From a8f33f7dbff1c3ad0cb01b7f9214b8bf49eaa992 Mon Sep 17 00:00:00 2001 From: Viet Dang Date: Thu, 28 Mar 2019 17:22:56 +0000 Subject: [PATCH 0001/1022] BidirectionalSequenceLSTM op: Fixes VTS test for merge_outputs Bug: 123644584 Test: VtsHalNeuralnetworksV1_xTargetTest Change-Id: I8829fd47094ca4af05e5d60da917499ce61acc5e --- neuralnetworks/1.2/vts/functional/ValidateModel.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp index 2988211e5a..a0b6d9aeac 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp @@ -508,9 +508,10 @@ static bool removeOperandSkip(size_t operand, const Model& model) { } } } - // BIDIRECTIONAL_SEQUENCE_RNN can have either on or two outputs - // depending on a mergeOutputs parameter - if (operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_RNN) { + // BIDIRECTIONAL_SEQUENCE_LSTM and BIDIRECTIONAL_SEQUENCE_RNN can have either one or two + // outputs depending on their mergeOutputs parameter. + if (operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_LSTM || + operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_RNN) { for (const size_t outOprand : operation.outputs) { if (operand == outOprand) { return true; From 8f685f9634d8129c8e8f8214e827b0b93bf38ee6 Mon Sep 17 00:00:00 2001 From: Andrew Chant Date: Thu, 4 Apr 2019 17:40:21 +0000 Subject: [PATCH 0002/1022] Revert "Mark layers with color transform client composition if not implemented." This reverts commit c53ea9f5f8e8d30ad79618d57b965a492962b546. Reason for revert: Breaks some display output Bug: 129945273 Bug: 115554640 Change-Id: If70a148ae6ad673b5dd03143b3f1ed73eaa1290f --- .../include/composer-passthrough/2.1/HwcHal.h | 28 +---- .../include/composer-passthrough/2.3/HwcHal.h | 101 +----------------- 2 files changed, 6 insertions(+), 123 deletions(-) diff --git a/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcHal.h b/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcHal.h index 5826b126bb..436e4612bb 100644 --- a/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcHal.h +++ b/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcHal.h @@ -162,7 +162,6 @@ class HwcHalImpl : public Hal { Error destroyLayer(Display display, Layer layer) override { int32_t err = mDispatch.destroyLayer(mDevice, display, layer); - onLayerDestroyed(display, layer); return static_cast(err); } @@ -328,7 +327,6 @@ class HwcHalImpl : public Hal { std::vector* outCompositionTypes, uint32_t* outDisplayRequestMask, std::vector* outRequestedLayers, std::vector* outRequestMasks) override { - onBeforeValidateDisplay(display); uint32_t typesCount = 0; uint32_t reqsCount = 0; int32_t err = mDispatch.validateDisplay(mDevice, display, &typesCount, &reqsCount); @@ -337,15 +335,17 @@ class HwcHalImpl : public Hal { return static_cast(err); } - err = getChangedCompositionTypes(display, &typesCount, nullptr, nullptr); + err = mDispatch.getChangedCompositionTypes(mDevice, display, &typesCount, nullptr, nullptr); if (err != HWC2_ERROR_NONE) { return static_cast(err); } std::vector changedLayers(typesCount); std::vector compositionTypes(typesCount); - err = getChangedCompositionTypes(display, &typesCount, changedLayers.data(), - compositionTypes.data()); + err = mDispatch.getChangedCompositionTypes( + mDevice, display, &typesCount, changedLayers.data(), + reinterpret_cast::type*>( + compositionTypes.data())); if (err != HWC2_ERROR_NONE) { return static_cast(err); } @@ -578,15 +578,6 @@ class HwcHalImpl : public Hal { return true; } - virtual int32_t getChangedCompositionTypes(Display display, uint32_t* outTypesCount, - Layer* outChangedLayers, - IComposerClient::Composition* outCompositionTypes) { - return getChangedCompositionTypesInternal(display, outTypesCount, outChangedLayers, - outCompositionTypes); - } - virtual void onLayerDestroyed(Display /* display */, Layer /* layer */) {} - virtual void onBeforeValidateDisplay(Display /* display */) {} - static void hotplugHook(hwc2_callback_data_t callbackData, hwc2_display_t display, int32_t connected) { auto hal = static_cast(callbackData); @@ -605,15 +596,6 @@ class HwcHalImpl : public Hal { hal->mEventCallback->onVsync(display, timestamp); } - int32_t getChangedCompositionTypesInternal(Display display, uint32_t* outTypesCount, - Layer* outChangedLayers, - IComposerClient::Composition* outCompositionTypes) { - return mDispatch.getChangedCompositionTypes( - mDevice, display, outTypesCount, outChangedLayers, - reinterpret_cast::type*>( - outCompositionTypes)); - } - hwc2_device_t* mDevice = nullptr; std::unordered_set mCapabilities; diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h index 9d67e0442d..070cf80e44 100644 --- a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h +++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h @@ -42,20 +42,6 @@ using common::V1_2::PixelFormat; using V2_1::Display; using V2_1::Error; -namespace { - -bool isIdentityMatrix(const float* matrix) { - if (matrix[0] == 1.0 && matrix[1] == 0.0 && matrix[2] == 0.0 && matrix[3] == 0.0 && - matrix[4] == 0.0 && matrix[5] == 1.0 && matrix[6] == 0.0 && matrix[7] == 0.0 && - matrix[8] == 0.0 && matrix[9] == 0.0 && matrix[10] == 1.0 && matrix[11] == 0.0 && - matrix[12] == 0.0 && matrix[13] == 0.0 && matrix[14] == 0.0 && matrix[15] == 1.0) { - return true; - } - return false; -} - -} // namespace - // HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2 template class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl { @@ -144,16 +130,6 @@ class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl { Error setLayerColorTransform(Display display, Layer layer, const float* matrix) override { if (!mDispatch.setLayerColorTransform) { - if (isIdentityMatrix(matrix)) { - // If an identity matrix is set, then we can remove the layer from client - // composition list. - mClientCompositionLayers[display].erase(layer); - return Error::UNSUPPORTED; - } - // if setLayerColorTransform is not implemented, per spec we want to make sure the - // layer marked as client composition, and thus we maintain a list, and mark all these - // layers as client composition later before validate the display. - mClientCompositionLayers[display].insert(layer); return Error::UNSUPPORTED; } int32_t err = mDispatch.setLayerColorTransform(mDevice, display, layer, matrix); @@ -318,79 +294,7 @@ class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl { return true; } - int32_t getChangedCompositionTypes(Display display, uint32_t* outTypesCount, - Layer* outChangedLayers, - IComposerClient::Composition* outCompositionTypes) override { - if (outChangedLayers == nullptr && outCompositionTypes == nullptr) { - uint32_t typesCount = 0; - int32_t error = BaseType2_1::getChangedCompositionTypesInternal(display, &typesCount, - nullptr, nullptr); - if (error != HWC2_ERROR_NONE) { - return error; - } - mChangedLayersCache[display].reserve(typesCount); - mCompositionTypesCache[display].reserve(typesCount); - error = BaseType2_1::getChangedCompositionTypesInternal( - display, &typesCount, mChangedLayersCache[display].data(), - mCompositionTypesCache[display].data()); - if (error != HWC2_ERROR_NONE) { - return error; - } - for (Layer layer : mClientCompositionLayers[display]) { - bool exist = false; - for (uint32_t i = 0; i < typesCount; ++i) { - if (mChangedLayersCache[display][i] == layer) { - exist = true; - break; - } - } - if (!exist) { - mChangedLayersCache[display].push_back(layer); - mCompositionTypesCache[display].push_back(IComposerClient::Composition::CLIENT); - } - } - *outTypesCount = mChangedLayersCache[display].size(); - return error; - } - for (uint32_t i = 0; i < *outTypesCount; ++i) { - if (outChangedLayers != nullptr) { - outChangedLayers[i] = mChangedLayersCache[display][i]; - } - if (outCompositionTypes != nullptr) { - outCompositionTypes[i] = mCompositionTypesCache[display][i]; - } - } - return HWC2_ERROR_NONE; - } - - void onLayerDestroyed(Display display, Layer layer) override { - if (mClientCompositionLayers.find(display) == mClientCompositionLayers.end()) { - return; - } - mClientCompositionLayers[display].erase(layer); - } - - void onBeforeValidateDisplay(Display display) override { - if (mClientCompositionLayers.find(display) == mClientCompositionLayers.end()) { - return; - } - - // clear the cache proactively so that we don't hold too much memory over time. - mChangedLayersCache[display].clear(); - mCompositionTypesCache[display].clear(); - - // SET_LAYER_COLOR_TRANSFORM is optional, and thus if it's not implemented, we need to - // follow the spec to make sure those layers marked as client composition before validate - // the display. - if (!mDispatch.setLayerColorTransform) { - for (Layer layer : mClientCompositionLayers[display]) { - BaseType2_1::setLayerCompositionType( - display, layer, static_cast(IComposerClient::Composition::CLIENT)); - } - } - } - - private: + private: struct { HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA getDisplayIdentificationData; HWC2_PFN_SET_LAYER_COLOR_TRANSFORM setLayerColorTransform; @@ -414,9 +318,6 @@ class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl { using BaseType2_2::getRenderIntents; using BaseType2_2::setColorMode_2_2; using BaseType2_2::setLayerPerFrameMetadata; - std::map> mClientCompositionLayers; - std::map> mChangedLayersCache; - std::map> mCompositionTypesCache; }; } // namespace detail From ccbd24f6336bf7141b9a6e463b89aa027b289bfe Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 4 Apr 2019 12:32:09 -0700 Subject: [PATCH 0003/1022] IMapper: change an error message Change the error message that prints when IMapper 3.0 isn't present. The old warning was causing unnecessary concerns. Bug: 128013727 Test: compile Change-Id: I197cd953d08a8e9f3bdee92cede973bf1b97dfe2 --- .../2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h index 1df496c065..18d184ecb4 100644 --- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h +++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h @@ -44,7 +44,7 @@ class ComposerHandleImporter { if (mMapper3) { return true; } - ALOGW_IF(!mMapper3, "failed to get mapper 3.0 service"); + ALOGD_IF(!mMapper3, "failed to get mapper 3.0 service, falling back to mapper 2.0"); mMapper2 = mapper::V2_0::IMapper::getService(); ALOGE_IF(!mMapper2, "failed to get mapper 2.0 service"); From 8c0edf6c84253afb4500a386b83c858e94331d32 Mon Sep 17 00:00:00 2001 From: Max Bires Date: Fri, 8 Feb 2019 12:29:58 -0800 Subject: [PATCH 0004/1022] Expanding VTS test coverage Keymaster VTS test coverage on 4.0 was incomplete. This significantly expands the coverage of the spec. The bugs listed are errors found that these tests will cover, but are not indicative of the complete set of things tested. Test: atest VtsHalKeymasterV4_0TargetTest Bug: 79953279 Bug: 119553313 Bug: 119541233 Bug: 119396995 Bug: 119542230 Bug: 119549128 Bug: 119549677 Bug: 122184852 Bug: 122261372 Change-Id: I42d78091b48398597bbebe1d9c91b806494ddf4c --- keymaster/4.0/support/attestation_record.cpp | 58 ++++ .../keymasterV4_0/attestation_record.h | 13 + .../4.0/vts/functional/KeymasterHidlTest.cpp | 42 +++ .../4.0/vts/functional/KeymasterHidlTest.h | 5 + .../functional/keymaster_hidl_hal_test.cpp | 291 +++++++++++++++++- 5 files changed, 399 insertions(+), 10 deletions(-) diff --git a/keymaster/4.0/support/attestation_record.cpp b/keymaster/4.0/support/attestation_record.cpp index 6de0c1c629..000d46e7db 100644 --- a/keymaster/4.0/support/attestation_record.cpp +++ b/keymaster/4.0/support/attestation_record.cpp @@ -16,6 +16,7 @@ #include +#include #include #include @@ -26,6 +27,8 @@ #include #include +#define AT __FILE__ ":" << __LINE__ + namespace android { namespace hardware { namespace keymaster { @@ -304,6 +307,61 @@ ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key return extract_auth_list(record->tee_enforced, tee_enforced); } +ErrorCode parse_root_of_trust(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len, + hidl_vec* verified_boot_key, + keymaster_verified_boot_t* verified_boot_state, bool* device_locked, + hidl_vec* verified_boot_hash) { + if (!verified_boot_key || !verified_boot_state || !device_locked || !verified_boot_hash) { + LOG(ERROR) << AT << "null pointer input(s)"; + return ErrorCode::INVALID_ARGUMENT; + } + const uint8_t* p = asn1_key_desc; + KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len)); + if (!record.get()) { + LOG(ERROR) << AT << "Failed record parsing"; + return ErrorCode::UNKNOWN_ERROR; + } + if (!record->tee_enforced) { + LOG(ERROR) << AT << "Failed hardware characteristic parsing"; + return ErrorCode::INVALID_ARGUMENT; + } + if (!record->tee_enforced->root_of_trust) { + LOG(ERROR) << AT << "Failed root of trust parsing"; + return ErrorCode::INVALID_ARGUMENT; + } + if (!record->tee_enforced->root_of_trust->verified_boot_key) { + LOG(ERROR) << AT << "Failed verified boot key parsing"; + return ErrorCode::INVALID_ARGUMENT; + } + KM_ROOT_OF_TRUST* root_of_trust = record->tee_enforced->root_of_trust; + + auto& vb_key = root_of_trust->verified_boot_key; + verified_boot_key->resize(vb_key->length); + memcpy(verified_boot_key->data(), vb_key->data, vb_key->length); + + *verified_boot_state = static_cast( + ASN1_ENUMERATED_get(root_of_trust->verified_boot_state)); + if (!verified_boot_state) { + LOG(ERROR) << AT << "Failed verified boot state parsing"; + return ErrorCode::INVALID_ARGUMENT; + } + + *device_locked = root_of_trust->device_locked; + if (!device_locked) { + LOG(ERROR) << AT << "Failed device locked parsing"; + return ErrorCode::INVALID_ARGUMENT; + } + + auto& vb_hash = root_of_trust->verified_boot_hash; + if (!vb_hash) { + LOG(ERROR) << AT << "Failed verified boot hash parsing"; + return ErrorCode::INVALID_ARGUMENT; + } + verified_boot_hash->resize(vb_hash->length); + memcpy(verified_boot_hash->data(), vb_hash->data, vb_hash->length); + return ErrorCode::OK; // KM_ERROR_OK; +} + } // namespace V4_0 } // namespace keymaster } // namespace hardware diff --git a/keymaster/4.0/support/include/keymasterV4_0/attestation_record.h b/keymaster/4.0/support/include/keymasterV4_0/attestation_record.h index fae403a7c5..eb95ceae13 100644 --- a/keymaster/4.0/support/include/keymasterV4_0/attestation_record.h +++ b/keymaster/4.0/support/include/keymasterV4_0/attestation_record.h @@ -42,6 +42,13 @@ class AuthorizationSet; */ static const char kAttestionRecordOid[] = "1.3.6.1.4.1.11129.2.1.17"; +enum keymaster_verified_boot_t { + KM_VERIFIED_BOOT_VERIFIED = 0, + KM_VERIFIED_BOOT_SELF_SIGNED = 1, + KM_VERIFIED_BOOT_UNVERIFIED = 2, + KM_VERIFIED_BOOT_FAILED = 3, +}; + ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len, uint32_t* attestation_version, // SecurityLevel* attestation_security_level, @@ -51,6 +58,12 @@ ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key AuthorizationSet* software_enforced, AuthorizationSet* tee_enforced, // hidl_vec* unique_id); + +ErrorCode parse_root_of_trust(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len, + hidl_vec* verified_boot_key, + keymaster_verified_boot_t* verified_boot_state, bool* device_locked, + hidl_vec* verified_boot_hash); + } // namespace V4_0 } // namespace keymaster } // namespace hardware diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp index 995ae4f45c..a7b6c981f4 100644 --- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp +++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp @@ -16,6 +16,7 @@ #include "KeymasterHidlTest.h" +#include #include #include @@ -206,6 +207,47 @@ void KeymasterHidlTest::CheckedDeleteKey() { CheckedDeleteKey(&key_blob_); } +void KeymasterHidlTest::CheckCreationDateTime( + const AuthorizationSet& sw_enforced, + std::chrono::time_point creation) { + for (int i = 0; i < sw_enforced.size(); i++) { + if (sw_enforced[i].tag == TAG_CREATION_DATETIME) { + std::chrono::time_point now = + std::chrono::system_clock::now(); + std::chrono::time_point reported_time{ + std::chrono::milliseconds(sw_enforced[i].f.dateTime)}; + // The test is flaky for EC keys, so a buffer time of 1 second will be added. + EXPECT_LE(creation - 1s, reported_time); + EXPECT_LE(reported_time, now + 1s); + } + } +} + +void KeymasterHidlTest::CheckGetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id, + const HidlBuf& app_data, + KeyCharacteristics* key_characteristics) { + HidlBuf empty_buf = {}; + EXPECT_EQ(ErrorCode::OK, + GetCharacteristics(key_blob, client_id, app_data, key_characteristics)); + EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0); + EXPECT_GT(key_characteristics->softwareEnforced.size(), 0); + + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + GetCharacteristics(key_blob, empty_buf, app_data, key_characteristics)); + EXPECT_EQ(key_characteristics->hardwareEnforced.size(), 0); + EXPECT_EQ(key_characteristics->softwareEnforced.size(), 0); + + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + GetCharacteristics(key_blob, client_id, empty_buf, key_characteristics)); + EXPECT_EQ(key_characteristics->hardwareEnforced.size(), 0); + EXPECT_EQ(key_characteristics->softwareEnforced.size(), 0); + + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + GetCharacteristics(key_blob, empty_buf, empty_buf, key_characteristics)); + EXPECT_EQ(key_characteristics->hardwareEnforced.size(), 0); + EXPECT_EQ(key_characteristics->softwareEnforced.size(), 0); +} + ErrorCode KeymasterHidlTest::GetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id, const HidlBuf& app_data, KeyCharacteristics* key_characteristics) { diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h index 4cd6a5b577..015fc43752 100644 --- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h +++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h @@ -131,6 +131,11 @@ class KeymasterHidlTest : public ::testing::VtsHalHidlTargetTestBase { void CheckedDeleteKey(HidlBuf* key_blob, bool keep_key_blob = false); void CheckedDeleteKey(); + static void CheckCreationDateTime(const AuthorizationSet& sw_enforced, + std::chrono::time_point creation); + + void CheckGetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id, + const HidlBuf& app_data, KeyCharacteristics* key_characteristics); ErrorCode GetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id, const HidlBuf& app_data, KeyCharacteristics* key_characteristics); ErrorCode GetCharacteristics(const HidlBuf& key_blob, KeyCharacteristics* key_characteristics); 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 a9c6f6ca93..2e76604027 100644 --- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp +++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp @@ -299,8 +299,9 @@ std::string make_string(const uint8_t (&a)[N]) { bool verify_attestation_record(const string& challenge, const string& app_id, AuthorizationSet expected_sw_enforced, - AuthorizationSet expected_tee_enforced, SecurityLevel security_level, - const hidl_vec& attestation_cert) { + AuthorizationSet expected_hw_enforced, SecurityLevel security_level, + const hidl_vec& attestation_cert, + std::chrono::time_point creation_time) { X509_Ptr cert(parse_cert_blob(attestation_cert)); EXPECT_TRUE(!!cert.get()); if (!cert.get()) return false; @@ -310,7 +311,7 @@ bool verify_attestation_record(const string& challenge, const string& app_id, if (!attest_rec) return false; AuthorizationSet att_sw_enforced; - AuthorizationSet att_tee_enforced; + AuthorizationSet att_hw_enforced; uint32_t att_attestation_version; uint32_t att_keymaster_version; SecurityLevel att_attestation_security_level; @@ -327,7 +328,7 @@ bool verify_attestation_record(const string& challenge, const string& app_id, &att_keymaster_security_level, // &att_challenge, // &att_sw_enforced, // - &att_tee_enforced, // + &att_hw_enforced, // &att_unique_id); EXPECT_EQ(ErrorCode::OK, error); if (error != ErrorCode::OK) return false; @@ -343,13 +344,105 @@ bool verify_attestation_record(const string& challenge, const string& app_id, EXPECT_EQ(challenge.length(), att_challenge.size()); EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length())); + char property_value[PROPERTY_VALUE_MAX] = {}; + for (int i = 0; i < att_hw_enforced.size(); i++) { + if (att_hw_enforced[i].tag == TAG_BOOT_PATCHLEVEL || + att_hw_enforced[i].tag == TAG_VENDOR_PATCHLEVEL) { + std::string date = std::to_string(att_hw_enforced[i].f.integer); + // strptime seems to require delimiters, but the tag value will be YYYYMMDD + date.insert(6, "-"); + date.insert(4, "-"); + EXPECT_EQ(date.size(), 10); + struct tm time; + strptime(date.c_str(), "%Y-%m-%d", &time); + + // Day of the month (0-31) + EXPECT_GT(time.tm_mday, 0); + EXPECT_LT(time.tm_mday, 32); + // Months since Jan (0-11) + EXPECT_GE(time.tm_mon, 0); + EXPECT_LT(time.tm_mon, 12); + // Years since 1900 + EXPECT_GT(time.tm_year, 110); + EXPECT_LT(time.tm_year, 200); + } + } + + // Check to make sure boolean values are properly encoded. Presence of a boolean tag indicates + // true. A provided boolean tag that can be pulled back out of the certificate indicates correct + // encoding. No need to check if it's in both lists, since the AuthorizationSet compare below + // will handle mismatches of tags. + EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED)); + + // Alternatively this checks the opposite - a false boolean tag (one that isn't provided in + // the authorization list during key generation) isn't being attested to in the certificate. + EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED)); + EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED)); + + KeymasterHidlTest::CheckCreationDateTime(att_sw_enforced, creation_time); + + if (att_hw_enforced.Contains(TAG_ALGORITHM, Algorithm::EC)) { + // For ECDSA keys, either an EC_CURVE or a KEY_SIZE can be specified, but one must be. + EXPECT_TRUE(att_hw_enforced.Contains(TAG_EC_CURVE) || + att_hw_enforced.Contains(TAG_KEY_SIZE)); + } + + // Test root of trust elements + HidlBuf verified_boot_key; + keymaster_verified_boot_t verified_boot_state; + bool device_locked; + HidlBuf verified_boot_hash; + error = parse_root_of_trust(attest_rec->data, attest_rec->length, &verified_boot_key, + &verified_boot_state, &device_locked, &verified_boot_hash); + EXPECT_EQ(ErrorCode::OK, error); + + property_get("ro.boot.vbmeta.digest", property_value, "nogood"); + EXPECT_NE(strcmp(property_value, "nogood"), 0); + string prop_string(property_value); + EXPECT_EQ(prop_string.size(), 64); + EXPECT_EQ(0, memcmp(verified_boot_hash.data(), prop_string.data(), verified_boot_hash.size())); + + property_get("ro.boot.vbmeta.device_state", property_value, "nogood"); + EXPECT_NE(property_value, "nogood"); + if (!strcmp(property_value, "unlocked")) { + EXPECT_FALSE(device_locked); + } else { + EXPECT_TRUE(device_locked); + } + + // Verified boot key should be all 0's if the boot state is not verified or self signed + std::string empty_boot_key(32, '\0'); + std::string verified_boot_key_str((const char*)verified_boot_key.data(), + verified_boot_key.size()); + property_get("ro.boot.verifiedbootstate", property_value, "nogood"); + EXPECT_NE(property_value, "nogood"); + if (!strcmp(property_value, "green")) { + EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_VERIFIED); + EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(), + verified_boot_key.size())); + } else if (!strcmp(property_value, "yellow")) { + EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_SELF_SIGNED); + EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(), + verified_boot_key.size())); + } else if (!strcmp(property_value, "orange")) { + EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_UNVERIFIED); + EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(), + verified_boot_key.size())); + } else if (!strcmp(property_value, "red")) { + EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_FAILED); + EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(), + verified_boot_key.size())); + } else { + EXPECT_TRUE(false); + } + att_sw_enforced.Sort(); expected_sw_enforced.Sort(); EXPECT_EQ(filter_tags(expected_sw_enforced), filter_tags(att_sw_enforced)); - att_tee_enforced.Sort(); - expected_tee_enforced.Sort(); - EXPECT_EQ(filter_tags(expected_tee_enforced), filter_tags(att_tee_enforced)); + att_hw_enforced.Sort(); + expected_hw_enforced.Sort(); + EXPECT_EQ(filter_tags(expected_hw_enforced), filter_tags(att_hw_enforced)); return true; } @@ -431,6 +524,24 @@ TEST_F(NewKeyGenerationTest, Rsa) { } } +/* + * NewKeyGenerationTest.RsaCheckCreationDateTime + * + * Verifies that creation date time is correct. + */ +TEST_F(NewKeyGenerationTest, RsaCheckCreationDateTime) { + KeyCharacteristics key_characteristics; + auto creation_time = std::chrono::system_clock::now(); + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(2048, 3) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE))); + GetCharacteristics(key_blob_, &key_characteristics); + AuthorizationSet sw_enforced = key_characteristics.softwareEnforced; + CheckCreationDateTime(sw_enforced, creation_time); +} + /* * NewKeyGenerationTest.NoInvalidRsaSizes * @@ -494,6 +605,23 @@ TEST_F(NewKeyGenerationTest, Ecdsa) { } } +/* + * NewKeyGenerationTest.EcCheckCreationDateTime + * + * Verifies that creation date time is correct. + */ +TEST_F(NewKeyGenerationTest, EcCheckCreationDateTime) { + KeyCharacteristics key_characteristics; + auto creation_time = std::chrono::system_clock::now(); + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(256) + .Digest(Digest::NONE))); + GetCharacteristics(key_blob_, &key_characteristics); + AuthorizationSet sw_enforced = key_characteristics.softwareEnforced; + CheckCreationDateTime(sw_enforced, creation_time); +} + /* * NewKeyGenerationTest.EcdsaDefaultSize * @@ -733,6 +861,69 @@ TEST_F(SigningOperationsTest, RsaSuccess) { message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)); } +/* + * SigningOperationsTest.RsaGetKeyCharacteristicsRequiresCorrectAppIdAppData + * + * Verifies that getting RSA key characteristics requires the correct app ID/data. + */ +TEST_F(SigningOperationsTest, RsaGetKeyCharacteristicsRequiresCorrectAppIdAppData) { + HidlBuf key_blob; + KeyCharacteristics key_characteristics; + ASSERT_EQ(ErrorCode::OK, + GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_APPLICATION_ID, HidlBuf("clientid")) + .Authorization(TAG_APPLICATION_DATA, HidlBuf("appdata")), + &key_blob, &key_characteristics)); + CheckGetCharacteristics(key_blob, HidlBuf("clientid"), HidlBuf("appdata"), + &key_characteristics); +} + +/* + * SigningOperationsTest.RsaUseRequiresCorrectAppIdAppData + * + * Verifies that using an RSA key requires the correct app ID/data. + */ +TEST_F(SigningOperationsTest, RsaUseRequiresCorrectAppIdAppData) { + ASSERT_EQ(ErrorCode::OK, + GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_APPLICATION_ID, HidlBuf("clientid")) + .Authorization(TAG_APPLICATION_DATA, HidlBuf("appdata")))); + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + Begin(KeyPurpose::SIGN, + AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE))); + AbortIfNeeded(); + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + Begin(KeyPurpose::SIGN, + AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_APPLICATION_ID, HidlBuf("clientid")))); + AbortIfNeeded(); + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + Begin(KeyPurpose::SIGN, + AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_APPLICATION_DATA, HidlBuf("appdata")))); + AbortIfNeeded(); + EXPECT_EQ(ErrorCode::OK, + Begin(KeyPurpose::SIGN, + AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_APPLICATION_DATA, HidlBuf("appdata")) + .Authorization(TAG_APPLICATION_ID, HidlBuf("clientid")))); + AbortIfNeeded(); +} + /* * SigningOperationsTest.RsaPssSha256Success * @@ -1109,6 +1300,63 @@ TEST_F(SigningOperationsTest, EcdsaNoDigestHugeData) { SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE)); } +/* + * SigningOperationsTest.EcGetKeyCharacteristicsRequiresCorrectAppIdAppData + * + * Verifies that getting EC key characteristics requires the correct app ID/data. + */ +TEST_F(SigningOperationsTest, EcGetKeyCharacteristicsRequiresCorrectAppIdAppData) { + HidlBuf key_blob; + KeyCharacteristics key_characteristics; + ASSERT_EQ(ErrorCode::OK, + GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(256) + .Digest(Digest::NONE) + .Authorization(TAG_APPLICATION_ID, HidlBuf("clientid")) + .Authorization(TAG_APPLICATION_DATA, HidlBuf("appdata")), + &key_blob, &key_characteristics)); + CheckGetCharacteristics(key_blob, HidlBuf("clientid"), HidlBuf("appdata"), + &key_characteristics); +} + +/* + * SigningOperationsTest.EcUseRequiresCorrectAppIdAppData + * + * Verifies that using an EC key requires the correct app ID/data. + */ +TEST_F(SigningOperationsTest, EcUseRequiresCorrectAppIdAppData) { + ASSERT_EQ(ErrorCode::OK, + GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(256) + .Digest(Digest::NONE) + .Authorization(TAG_APPLICATION_ID, HidlBuf("clientid")) + .Authorization(TAG_APPLICATION_DATA, HidlBuf("appdata")))); + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Digest(Digest::NONE))); + AbortIfNeeded(); + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + Begin(KeyPurpose::SIGN, + AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Authorization(TAG_APPLICATION_ID, HidlBuf("clientid")))); + AbortIfNeeded(); + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + Begin(KeyPurpose::SIGN, + AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Authorization(TAG_APPLICATION_DATA, HidlBuf("appdata")))); + AbortIfNeeded(); + EXPECT_EQ(ErrorCode::OK, + Begin(KeyPurpose::SIGN, + AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Authorization(TAG_APPLICATION_DATA, HidlBuf("appdata")) + .Authorization(TAG_APPLICATION_ID, HidlBuf("clientid")))); + AbortIfNeeded(); +} + /* * SigningOperationsTest.AesEcbSign * @@ -3858,6 +4106,7 @@ typedef KeymasterHidlTest AttestationTest; * Verifies that attesting to RSA keys works and generates the expected output. */ TEST_F(AttestationTest, RsaAttestation) { + auto creation_time = std::chrono::system_clock::now(); ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() .Authorization(TAG_NO_AUTH_REQUIRED) .RsaSigningKey(2048, 65537) @@ -3882,7 +4131,7 @@ TEST_F(AttestationTest, RsaAttestation) { EXPECT_TRUE(verify_attestation_record("challenge", "foo", // key_characteristics_.softwareEnforced, // key_characteristics_.hardwareEnforced, // - SecLevel(), cert_chain[0])); + SecLevel(), cert_chain[0], creation_time)); } /* @@ -3905,12 +4154,35 @@ TEST_F(AttestationTest, RsaAttestationRequiresAppId) { &cert_chain)); } +/* + * AttestationTest.RsaAttestationRequiresCorrectAppId + * + * Verifies that attesting to RSA requires the correct app ID. + */ +TEST_F(AttestationTest, RsaAttestationRequiresCorrectAppId) { + ASSERT_EQ(ErrorCode::OK, + GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_APPLICATION_ID, HidlBuf("lol")))); + + hidl_vec> cert_chain; + EXPECT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING, + AttestKey(AuthorizationSetBuilder() + .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge")) + .Authorization(TAG_APPLICATION_ID, HidlBuf("heh")), + &cert_chain)); +} + /* * AttestationTest.EcAttestation * * Verifies that attesting to EC keys works and generates the expected output. */ TEST_F(AttestationTest, EcAttestation) { + auto creation_time = std::chrono::system_clock::now(); ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() .Authorization(TAG_NO_AUTH_REQUIRED) .EcdsaSigningKey(EcCurve::P_256) @@ -3929,11 +4201,10 @@ TEST_F(AttestationTest, EcAttestation) { string signature = SignMessage(message, AuthorizationSetBuilder().Digest(Digest::SHA_2_256)); EXPECT_TRUE(verify_chain(cert_chain, message, signature)); - EXPECT_TRUE(verify_attestation_record("challenge", "foo", // key_characteristics_.softwareEnforced, // key_characteristics_.hardwareEnforced, // - SecLevel(), cert_chain[0])); + SecLevel(), cert_chain[0], creation_time)); } /* From f1ca6754a86549fb2d84bbca43822fb91bc1ada2 Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Tue, 16 Apr 2019 15:04:32 -0700 Subject: [PATCH 0005/1022] Fix IBurstCallback.hal typo Test: mma Bug: N/A Change-Id: If753c6618c31a11672c4449f798fb57aa4bb7831 --- current.txt | 2 +- neuralnetworks/1.2/IBurstCallback.hal | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/current.txt b/current.txt index 875be97f28..2ecd50a4a8 100644 --- a/current.txt +++ b/current.txt @@ -509,7 +509,7 @@ d36f747f9c9a8f2f21db2f8323c2d755dd08b34ce813932d7339979f7d490dab android.hardwar b9422a9aca84df1ff9623dc12c0562abce97716e28d63a965f2bfb88f9ad9607 android.hardware.media.c2@1.0::IInputSurface 0a786a19e6753f9774a7ca7781c2a2edfe5c0b5fa112355dfa0e50ebedeb08b9 android.hardware.media.c2@1.0::IInputSurfaceConnection 7d3c292ca75ec3e22a8fd4ae72d2edb0659d280257e763786e766f3429954dd1 android.hardware.media.c2@1.0::types -4880af120fc1640225abdc2c60bda6d79617d73484d5124913c7278af3b11e2d android.hardware.neuralnetworks@1.2::IBurstCallback +5f6b6b99ffd0d51a5713174a3030a2a69273bcd476fc1b5ce814491437685857 android.hardware.neuralnetworks@1.2::IBurstCallback 19877e466ad8c6ed42b38050b77bd010cf7800ff365fdc8574f45bbfda03a758 android.hardware.neuralnetworks@1.2::IBurstContext b83317b66721241887d2770b5ae95fd5af1e77c5daa7530ecb08fae8892f2b43 android.hardware.neuralnetworks@1.2::IDevice 92714960d1a53fc2ec557302b41c7cc93d2636d8364a44bd0f85be0c92927ff8 android.hardware.neuralnetworks@1.2::IExecutionCallback diff --git a/neuralnetworks/1.2/IBurstCallback.hal b/neuralnetworks/1.2/IBurstCallback.hal index 3f82e3152b..cc38d7a3a4 100644 --- a/neuralnetworks/1.2/IBurstCallback.hal +++ b/neuralnetworks/1.2/IBurstCallback.hal @@ -24,7 +24,7 @@ import @1.0::ErrorStatus; */ interface IBurstCallback { /** - * Get the memory regions that correspond to slot ids. The slot ids are are + * Get the memory regions that correspond to slot ids. The slot ids are * unique to the burst object. * * @param slots Values uniquely identifying memory regions within a Burst. From c03613d7697be20bff109cb601b90581f5ece0e1 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 19 Apr 2019 19:51:41 -0700 Subject: [PATCH 0006/1022] Add dep to ...broadcastradio@common-utils-2x-tests Required now because iterators use the base hidl_vec constructor. It's not expected this type of change would be needed in any places. This test originally came with the introduction of the constructor that created the hidl_vec. Bug: 130161842 Test: build only, links (note b/130918604) Change-Id: Ide3cb13b6afd79489c208af2396e7c02b7da436e --- broadcastradio/common/tests/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/broadcastradio/common/tests/Android.bp b/broadcastradio/common/tests/Android.bp index ef8733c290..0ace941ac1 100644 --- a/broadcastradio/common/tests/Android.bp +++ b/broadcastradio/common/tests/Android.bp @@ -58,6 +58,7 @@ cc_test { "android.hardware.broadcastradio@common-utils-2x-lib", ], shared_libs: [ + "libhidlbase", "android.hardware.broadcastradio@2.0", ], test_suites: ["general-tests"], From af09bfeed4f2f4bfc1bffeb6974e9010cbcf203e Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Fri, 29 Mar 2019 10:48:36 -0700 Subject: [PATCH 0007/1022] Add BGRA8888 format support. Bug: 129462449 Test: Build and run VTS on Hawk Change-Id: I9d162b3200b64fbbec802eb1b0a2b6862af6949b Signed-off-by: Changyeon Jo --- .../evs/1.0/vts/functional/FormatConvert.cpp | 59 +++++++++++++++---- .../evs/1.0/vts/functional/FormatConvert.h | 26 ++++++-- .../evs/1.0/vts/functional/FrameHandler.cpp | 37 ++++++++++-- 3 files changed, 98 insertions(+), 24 deletions(-) diff --git a/automotive/evs/1.0/vts/functional/FormatConvert.cpp b/automotive/evs/1.0/vts/functional/FormatConvert.cpp index 1e8929d6b7..3d82d32cac 100644 --- a/automotive/evs/1.0/vts/functional/FormatConvert.cpp +++ b/automotive/evs/1.0/vts/functional/FormatConvert.cpp @@ -38,7 +38,8 @@ static inline float clamp(float v, float min, float max) { } -static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin) { +static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin, + bool bgrxFormat = false) { // Don't use this if you want to see the best performance. :) // Better to do this in a pixel shader if we really have to, but on actual // embedded hardware we expect to be able to texture directly from the YUV data @@ -52,16 +53,24 @@ static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char G = (unsigned char)clamp(Gf, 0.0f, 255.0f); unsigned char B = (unsigned char)clamp(Bf, 0.0f, 255.0f); - return (R ) | - (G << 8) | - (B << 16) | - 0xFF000000; // Fill the alpha channel with ones + if (!bgrxFormat) { + return (R ) | + (G << 8) | + (B << 16) | + 0xFF000000; // Fill the alpha channel with ones + } else { + return (R << 16) | + (G << 8) | + (B ) | + 0xFF000000; // Fill the alpha channel with ones + } } void copyNV21toRGB32(unsigned width, unsigned height, uint8_t* src, - uint32_t* dst, unsigned dstStridePixels) + uint32_t* dst, unsigned dstStridePixels, + bool bgrxFormat) { // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved // U/V array. It assumes an even width and height for the overall image, and a horizontal @@ -84,7 +93,7 @@ void copyNV21toRGB32(unsigned width, unsigned height, for (unsigned c = 0; c < width; c++) { unsigned uCol = (c & ~1); // uCol is always even and repeats 1:2 with Y values unsigned vCol = uCol | 1; // vCol is always odd - rowDest[c] = yuvToRgbx(rowY[c], rowUV[uCol], rowUV[vCol]); + rowDest[c] = yuvToRgbx(rowY[c], rowUV[uCol], rowUV[vCol], bgrxFormat); } } } @@ -92,7 +101,8 @@ void copyNV21toRGB32(unsigned width, unsigned height, void copyYV12toRGB32(unsigned width, unsigned height, uint8_t* src, - uint32_t* dst, unsigned dstStridePixels) + uint32_t* dst, unsigned dstStridePixels, + bool bgrxFormat) { // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed // by another 1/2 x 1/2 V array. It assumes an even width and height for the overall image, @@ -118,7 +128,7 @@ void copyYV12toRGB32(unsigned width, unsigned height, uint32_t* rowDest = dst + r*dstStridePixels; for (unsigned c = 0; c < width; c++) { - rowDest[c] = yuvToRgbx(rowY[c], rowU[c], rowV[c]); + rowDest[c] = yuvToRgbx(rowY[c], rowU[c], rowV[c], bgrxFormat); } } } @@ -126,7 +136,8 @@ void copyYV12toRGB32(unsigned width, unsigned height, void copyYUYVtoRGB32(unsigned width, unsigned height, uint8_t* src, unsigned srcStridePixels, - uint32_t* dst, unsigned dstStridePixels) + uint32_t* dst, unsigned dstStridePixels, + bool bgrxFormat) { uint32_t* srcWords = (uint32_t*)src; @@ -144,8 +155,8 @@ void copyYUYVtoRGB32(unsigned width, unsigned height, uint8_t V = (srcPixel >> 24) & 0xFF; // On the RGB output, we're writing one pixel at a time - *(dst+0) = yuvToRgbx(Y1, U, V); - *(dst+1) = yuvToRgbx(Y2, U, V); + *(dst+0) = yuvToRgbx(Y1, U, V, bgrxFormat); + *(dst+1) = yuvToRgbx(Y2, U, V, bgrxFormat); dst += 2; } @@ -156,6 +167,30 @@ void copyYUYVtoRGB32(unsigned width, unsigned height, } +void copyNV21toBGR32(unsigned width, unsigned height, + uint8_t* src, + uint32_t* dst, unsigned dstStridePixels) +{ + return copyNV21toRGB32(width, height, src, dst, dstStridePixels, true); +} + + +void copyYV12toBGR32(unsigned width, unsigned height, + uint8_t* src, + uint32_t* dst, unsigned dstStridePixels) +{ + return copyYV12toRGB32(width, height, src, dst, dstStridePixels, true); +} + + +void copyYUYVtoBGR32(unsigned width, unsigned height, + uint8_t* src, unsigned srcStridePixels, + uint32_t* dst, unsigned dstStridePixels) +{ + return copyYUYVtoRGB32(width, height, src, srcStridePixels, dst, dstStridePixels, true); +} + + void copyMatchedInterleavedFormats(unsigned width, unsigned height, void* src, unsigned srcStridePixels, void* dst, unsigned dstStridePixels, diff --git a/automotive/evs/1.0/vts/functional/FormatConvert.h b/automotive/evs/1.0/vts/functional/FormatConvert.h index 3ff1eec12d..4a94f996d0 100644 --- a/automotive/evs/1.0/vts/functional/FormatConvert.h +++ b/automotive/evs/1.0/vts/functional/FormatConvert.h @@ -21,30 +21,44 @@ #include -// Given an image buffer in NV21 format (HAL_PIXEL_FORMAT_YCRCB_420_SP), output 32bit RGBx values. -// The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved +// Given an image buffer in NV21 format (HAL_PIXEL_FORMAT_YCRCB_420_SP), output 32bit RGBx/BGRx +// values. The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved // U/V array. It assumes an even width and height for the overall image, and a horizontal // stride that is an even multiple of 16 bytes for both the Y and UV arrays. void copyNV21toRGB32(unsigned width, unsigned height, + uint8_t* src, + uint32_t* dst, unsigned dstStridePixels, + bool bgrxFormat = false); + +void copyNV21toBGR32(unsigned width, unsigned height, uint8_t* src, uint32_t* dst, unsigned dstStridePixels); -// Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx values. +// Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx/BGRx values. // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed // by another 1/2 x 1/2 V array. It assumes an even width and height for the overall image, // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U, // and V arrays. void copyYV12toRGB32(unsigned width, unsigned height, + uint8_t* src, + uint32_t* dst, unsigned dstStridePixels, + bool bgrxFormat = false); + +void copyYV12toBGR32(unsigned width, unsigned height, uint8_t* src, uint32_t* dst, unsigned dstStridePixels); - -// Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx values. -// The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved +// Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx/BGRx +// values. The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved // U/V array. It assumes an even width and height for the overall image, and a horizontal // stride that is an even multiple of 16 bytes for both the Y and UV arrays. void copyYUYVtoRGB32(unsigned width, unsigned height, + uint8_t* src, unsigned srcStrideBytes, + uint32_t* dst, unsigned dstStrideBytes, + bool bgrxFormat = false); + +void copyYUYVtoBGR32(unsigned width, unsigned height, uint8_t* src, unsigned srcStrideBytes, uint32_t* dst, unsigned dstStrideBytes); diff --git a/automotive/evs/1.0/vts/functional/FrameHandler.cpp b/automotive/evs/1.0/vts/functional/FrameHandler.cpp index a69f72be49..d44ba41c5d 100644 --- a/automotive/evs/1.0/vts/functional/FrameHandler.cpp +++ b/automotive/evs/1.0/vts/functional/FrameHandler.cpp @@ -231,16 +231,12 @@ bool FrameHandler::copyBufferContents(const BufferDesc& tgtBuffer, uint8_t* srcPixels = nullptr; src->lock(GRALLOC_USAGE_SW_READ_OFTEN, (void**)&srcPixels); - // Lock our target buffer for writing (should be RGBA8888 format) + // Lock our target buffer for writing (should be either RGBA8888 or BGRA8888 format) uint32_t* tgtPixels = nullptr; tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels); if (srcPixels && tgtPixels) { - if (tgtBuffer.format != HAL_PIXEL_FORMAT_RGBA_8888) { - // We always expect 32 bit RGB for the display output for now. Is there a need for 565? - ALOGE("Diplay buffer is always expected to be 32bit RGBA"); - success = false; - } else { + if (tgtBuffer.format == HAL_PIXEL_FORMAT_RGBA_8888) { if (srcBuffer.format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21 copyNV21toRGB32(width, height, srcPixels, @@ -258,7 +254,36 @@ bool FrameHandler::copyBufferContents(const BufferDesc& tgtBuffer, srcPixels, srcBuffer.stride, tgtPixels, tgtBuffer.stride, tgtBuffer.pixelSize); + } else { + ALOGE("Camera buffer format is not supported"); + success = false; } + } else if (tgtBuffer.format == HAL_PIXEL_FORMAT_BGRA_8888) { + if (srcBuffer.format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21 + copyNV21toBGR32(width, height, + srcPixels, + tgtPixels, tgtBuffer.stride); + } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12 + copyYV12toBGR32(width, height, + srcPixels, + tgtPixels, tgtBuffer.stride); + } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV + copyYUYVtoBGR32(width, height, + srcPixels, srcBuffer.stride, + tgtPixels, tgtBuffer.stride); + } else if (srcBuffer.format == tgtBuffer.format) { // 32bit RGBA + copyMatchedInterleavedFormats(width, height, + srcPixels, srcBuffer.stride, + tgtPixels, tgtBuffer.stride, + tgtBuffer.pixelSize); + } else { + ALOGE("Camera buffer format is not supported"); + success = false; + } + } else { + // We always expect 32 bit RGB for the display output for now. Is there a need for 565? + ALOGE("Diplay buffer is always expected to be 32bit RGBA"); + success = false; } } else { ALOGE("Failed to lock buffer contents for contents transfer"); From 2b537f78527b98c76537ccaa8491d7877cae6305 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 24 Apr 2019 12:58:30 -0700 Subject: [PATCH 0008/1022] Zero hidl-generated structs (cas) Bug: 131356202 Test: boot Change-Id: I41de4b8de19a060e064ff8457b81b918c4ce887f --- cas/1.0/default/FactoryLoader.h | 33 ++++++++++++++++------------- cas/1.0/default/MediaCasService.cpp | 2 +- cas/1.1/default/FactoryLoader.h | 27 ++++++++++++++--------- cas/1.1/default/MediaCasService.cpp | 2 +- 4 files changed, 37 insertions(+), 27 deletions(-) diff --git a/cas/1.0/default/FactoryLoader.h b/cas/1.0/default/FactoryLoader.h index 18c2186dcb..943f761033 100644 --- a/cas/1.0/default/FactoryLoader.h +++ b/cas/1.0/default/FactoryLoader.h @@ -45,9 +45,9 @@ public: sp *library = NULL, T** factory = NULL); - bool enumeratePlugins(vector* results); + bool enumeratePlugins(hidl_vec* results); -private: + private: typedef T*(*CreateFactoryFunc)(); Mutex mMapLock; @@ -63,9 +63,7 @@ private: sp *library, T** factory); - bool queryPluginsFromPath( - const String8 &path, - vector* results); + bool queryPluginsFromPath(const String8& path, hidl_vec* results); bool openFactory(const String8 &path); void closeFactory(); @@ -121,12 +119,9 @@ bool FactoryLoader::findFactoryForScheme( } template -bool FactoryLoader::enumeratePlugins( - vector* results) { +bool FactoryLoader::enumeratePlugins(hidl_vec* results) { ALOGI("enumeratePlugins"); - results->clear(); - String8 dirPath("/vendor/lib/mediacas"); DIR* pDir = opendir(dirPath.string()); @@ -168,8 +163,8 @@ bool FactoryLoader::loadFactoryForSchemeFromPath( } template -bool FactoryLoader::queryPluginsFromPath( - const String8 &path, vector* results) { +bool FactoryLoader::queryPluginsFromPath(const String8& path, + hidl_vec* results) { closeFactory(); vector descriptors; @@ -178,11 +173,19 @@ bool FactoryLoader::queryPluginsFromPath( return false; } - for (auto it = descriptors.begin(); it != descriptors.end(); it++) { - results->push_back( HidlCasPluginDescriptor { - .caSystemId = it->CA_system_id, - .name = it->name.c_str()}); + results->resize(descriptors.size()); + + if (results->size() >= SIZE_MAX / sizeof(HidlCasPluginDescriptor)) { + return false; } + memset(results->data(), 0, results->size() * sizeof(HidlCasPluginDescriptor)); + + for (size_t i = 0; i < results->size(); i++) { + HidlCasPluginDescriptor& descriptor = (*results)[i]; + descriptor.caSystemId = descriptors[i].CA_system_id; + descriptor.name = descriptors[i].name.c_str(); + } + return true; } diff --git a/cas/1.0/default/MediaCasService.cpp b/cas/1.0/default/MediaCasService.cpp index dbdd0087db..b159f5b918 100644 --- a/cas/1.0/default/MediaCasService.cpp +++ b/cas/1.0/default/MediaCasService.cpp @@ -44,7 +44,7 @@ Return MediaCasService::enumeratePlugins(enumeratePlugins_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); - vector results; + hidl_vec results; mCasLoader.enumeratePlugins(&results); _hidl_cb(results); diff --git a/cas/1.1/default/FactoryLoader.h b/cas/1.1/default/FactoryLoader.h index c4a48e2852..862d5570e6 100644 --- a/cas/1.1/default/FactoryLoader.h +++ b/cas/1.1/default/FactoryLoader.h @@ -44,9 +44,9 @@ class FactoryLoader { bool findFactoryForScheme(int32_t CA_system_id, sp* library = NULL, T** factory = NULL); - bool enumeratePlugins(vector* results); + bool enumeratePlugins(hidl_vec* results); - private: + private: typedef T* (*CreateFactoryFunc)(); Mutex mMapLock; @@ -59,7 +59,7 @@ class FactoryLoader { bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id, sp* library, T** factory); - bool queryPluginsFromPath(const String8& path, vector* results); + bool queryPluginsFromPath(const String8& path, hidl_vec* results); bool openFactory(const String8& path); void closeFactory(); @@ -113,11 +113,9 @@ bool FactoryLoader::findFactoryForScheme(int32_t CA_system_id, sp -bool FactoryLoader::enumeratePlugins(vector* results) { +bool FactoryLoader::enumeratePlugins(hidl_vec* results) { ALOGI("enumeratePlugins"); - results->clear(); - String8 dirPath("/vendor/lib/mediacas"); DIR* pDir = opendir(dirPath.string()); @@ -159,7 +157,7 @@ bool FactoryLoader::loadFactoryForSchemeFromPath(const String8& path, int32_t template bool FactoryLoader::queryPluginsFromPath(const String8& path, - vector* results) { + hidl_vec* results) { closeFactory(); vector descriptors; @@ -168,10 +166,19 @@ bool FactoryLoader::queryPluginsFromPath(const String8& path, return false; } - for (auto it = descriptors.begin(); it != descriptors.end(); it++) { - results->push_back( - HidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()}); + results->resize(descriptors.size()); + + if (results->size() >= SIZE_MAX / sizeof(HidlCasPluginDescriptor)) { + return false; } + memset(results->data(), 0, results->size() * sizeof(HidlCasPluginDescriptor)); + + for (size_t i = 0; i < results->size(); i++) { + HidlCasPluginDescriptor& descriptor = (*results)[i]; + descriptor.caSystemId = descriptors[i].CA_system_id; + descriptor.name = descriptors[i].name.c_str(); + } + return true; } diff --git a/cas/1.1/default/MediaCasService.cpp b/cas/1.1/default/MediaCasService.cpp index eb3fa6b599..122c53f6fe 100644 --- a/cas/1.1/default/MediaCasService.cpp +++ b/cas/1.1/default/MediaCasService.cpp @@ -68,7 +68,7 @@ MediaCasService::~MediaCasService() {} Return MediaCasService::enumeratePlugins(enumeratePlugins_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); - vector results; + hidl_vec results; mCasLoader.enumeratePlugins(&results); _hidl_cb(results); From 9b2e504295fe9a9c02809c2ecd9b8a0ad46b4beb Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 1 May 2019 01:15:39 +0000 Subject: [PATCH 0009/1022] Revert "Zero hidl-generated structs (cas)" This reverts commit 2b537f78527b98c76537ccaa8491d7877cae6305. Reason for revert: Clearing all hidl_vec/array data instead. Change-Id: I7d51c5268e1b9020732e34c186e2e452cf044518 --- cas/1.0/default/FactoryLoader.h | 33 +++++++++++++---------------- cas/1.0/default/MediaCasService.cpp | 2 +- cas/1.1/default/FactoryLoader.h | 27 +++++++++-------------- cas/1.1/default/MediaCasService.cpp | 2 +- 4 files changed, 27 insertions(+), 37 deletions(-) diff --git a/cas/1.0/default/FactoryLoader.h b/cas/1.0/default/FactoryLoader.h index 943f761033..18c2186dcb 100644 --- a/cas/1.0/default/FactoryLoader.h +++ b/cas/1.0/default/FactoryLoader.h @@ -45,9 +45,9 @@ public: sp *library = NULL, T** factory = NULL); - bool enumeratePlugins(hidl_vec* results); + bool enumeratePlugins(vector* results); - private: +private: typedef T*(*CreateFactoryFunc)(); Mutex mMapLock; @@ -63,7 +63,9 @@ public: sp *library, T** factory); - bool queryPluginsFromPath(const String8& path, hidl_vec* results); + bool queryPluginsFromPath( + const String8 &path, + vector* results); bool openFactory(const String8 &path); void closeFactory(); @@ -119,9 +121,12 @@ bool FactoryLoader::findFactoryForScheme( } template -bool FactoryLoader::enumeratePlugins(hidl_vec* results) { +bool FactoryLoader::enumeratePlugins( + vector* results) { ALOGI("enumeratePlugins"); + results->clear(); + String8 dirPath("/vendor/lib/mediacas"); DIR* pDir = opendir(dirPath.string()); @@ -163,8 +168,8 @@ bool FactoryLoader::loadFactoryForSchemeFromPath( } template -bool FactoryLoader::queryPluginsFromPath(const String8& path, - hidl_vec* results) { +bool FactoryLoader::queryPluginsFromPath( + const String8 &path, vector* results) { closeFactory(); vector descriptors; @@ -173,19 +178,11 @@ bool FactoryLoader::queryPluginsFromPath(const String8& path, return false; } - results->resize(descriptors.size()); - - if (results->size() >= SIZE_MAX / sizeof(HidlCasPluginDescriptor)) { - return false; + for (auto it = descriptors.begin(); it != descriptors.end(); it++) { + results->push_back( HidlCasPluginDescriptor { + .caSystemId = it->CA_system_id, + .name = it->name.c_str()}); } - memset(results->data(), 0, results->size() * sizeof(HidlCasPluginDescriptor)); - - for (size_t i = 0; i < results->size(); i++) { - HidlCasPluginDescriptor& descriptor = (*results)[i]; - descriptor.caSystemId = descriptors[i].CA_system_id; - descriptor.name = descriptors[i].name.c_str(); - } - return true; } diff --git a/cas/1.0/default/MediaCasService.cpp b/cas/1.0/default/MediaCasService.cpp index b159f5b918..dbdd0087db 100644 --- a/cas/1.0/default/MediaCasService.cpp +++ b/cas/1.0/default/MediaCasService.cpp @@ -44,7 +44,7 @@ Return MediaCasService::enumeratePlugins(enumeratePlugins_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); - hidl_vec results; + vector results; mCasLoader.enumeratePlugins(&results); _hidl_cb(results); diff --git a/cas/1.1/default/FactoryLoader.h b/cas/1.1/default/FactoryLoader.h index 862d5570e6..c4a48e2852 100644 --- a/cas/1.1/default/FactoryLoader.h +++ b/cas/1.1/default/FactoryLoader.h @@ -44,9 +44,9 @@ class FactoryLoader { bool findFactoryForScheme(int32_t CA_system_id, sp* library = NULL, T** factory = NULL); - bool enumeratePlugins(hidl_vec* results); + bool enumeratePlugins(vector* results); - private: + private: typedef T* (*CreateFactoryFunc)(); Mutex mMapLock; @@ -59,7 +59,7 @@ class FactoryLoader { bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id, sp* library, T** factory); - bool queryPluginsFromPath(const String8& path, hidl_vec* results); + bool queryPluginsFromPath(const String8& path, vector* results); bool openFactory(const String8& path); void closeFactory(); @@ -113,9 +113,11 @@ bool FactoryLoader::findFactoryForScheme(int32_t CA_system_id, sp -bool FactoryLoader::enumeratePlugins(hidl_vec* results) { +bool FactoryLoader::enumeratePlugins(vector* results) { ALOGI("enumeratePlugins"); + results->clear(); + String8 dirPath("/vendor/lib/mediacas"); DIR* pDir = opendir(dirPath.string()); @@ -157,7 +159,7 @@ bool FactoryLoader::loadFactoryForSchemeFromPath(const String8& path, int32_t template bool FactoryLoader::queryPluginsFromPath(const String8& path, - hidl_vec* results) { + vector* results) { closeFactory(); vector descriptors; @@ -166,19 +168,10 @@ bool FactoryLoader::queryPluginsFromPath(const String8& path, return false; } - results->resize(descriptors.size()); - - if (results->size() >= SIZE_MAX / sizeof(HidlCasPluginDescriptor)) { - return false; + for (auto it = descriptors.begin(); it != descriptors.end(); it++) { + results->push_back( + HidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()}); } - memset(results->data(), 0, results->size() * sizeof(HidlCasPluginDescriptor)); - - for (size_t i = 0; i < results->size(); i++) { - HidlCasPluginDescriptor& descriptor = (*results)[i]; - descriptor.caSystemId = descriptors[i].CA_system_id; - descriptor.name = descriptors[i].name.c_str(); - } - return true; } diff --git a/cas/1.1/default/MediaCasService.cpp b/cas/1.1/default/MediaCasService.cpp index 122c53f6fe..eb3fa6b599 100644 --- a/cas/1.1/default/MediaCasService.cpp +++ b/cas/1.1/default/MediaCasService.cpp @@ -68,7 +68,7 @@ MediaCasService::~MediaCasService() {} Return MediaCasService::enumeratePlugins(enumeratePlugins_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); - hidl_vec results; + vector results; mCasLoader.enumeratePlugins(&results); _hidl_cb(results); From 1a18c080520837fea7caf2f0031a5d02931b5aee Mon Sep 17 00:00:00 2001 From: Slava Shklyaev Date: Fri, 10 May 2019 16:08:30 +0100 Subject: [PATCH 0010/1022] Ensure that drivers return an error if STRIDED_SLICE parameters are invalid We don't have a framework for handcrafting tests resulting in execution failure. To produce this test, I created strided_slice_invalid_output_dims.mod.py and used our VTS test generator to create the corresponding example.cpp and model.cpp files. I put those under the new directory neuralnetworks/1.2/vts/functional/generated to distinguish them from the streamlined generated tests. Bug: 79856511 Bug: 132155416 Test: VtsHalNeuralnetworksV1_2TargetTest Change-Id: Ib331778605c2e3828195e1e7d1651091873985a0 --- .../1.2/vts/functional/GeneratedTests.cpp | 15 ++ .../1.2/vts/functional/ValidateRequest.cpp | 16 ++ .../vts/functional/VtsHalNeuralnetworks.cpp | 14 ++ .../1.2/vts/functional/VtsHalNeuralnetworks.h | 3 + ...ided_slice_invalid_output_dims.example.cpp | 116 ++++++++++ ...trided_slice_invalid_output_dims.model.cpp | 216 ++++++++++++++++++ .../strided_slice_invalid_output_dims.mod.py | 43 ++++ 7 files changed, 423 insertions(+) create mode 100644 neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp create mode 100644 neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp create mode 100644 neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp index 2c3287ab35..5af3255f42 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp @@ -44,6 +44,21 @@ std::vector createRequests(const std::vector& exampl // in frameworks/ml/nn/runtime/tests/generated/ #include "all_generated_V1_2_vts_tests.cpp" +// Generated from spec/strided_slice_invalid_output_dims.mod.py. +// TODO(b/132155416): Make this part of all_generated_V1_2_vts_tests.cpp. +namespace strided_slice_invalid_output_dims { +#include "generated/strided_slice_invalid_output_dims.example.cpp" +#include "generated/strided_slice_invalid_output_dims.model.cpp" +} // namespace strided_slice_invalid_output_dims + +// TODO(b/132155416): Make this part of all_generated_V1_2_vts_tests.cpp. +TEST_F(ValidationTest, strided_slice_invalid_output_dims) { + const Model model = strided_slice_invalid_output_dims::createTestModel(); + const std::vector requests = + createRequests(strided_slice_invalid_output_dims::get_examples()); + validateFailure(model, requests); +} + } // namespace functional } // namespace vts } // namespace V1_2 diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp index 9703c2d765..e935aaa1fa 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp @@ -274,6 +274,22 @@ void ValidationTest::validateRequests(const sp& preparedModel, } } +void ValidationTest::validateRequestFailure(const sp& preparedModel, + const std::vector& requests) { + for (const Request& request : requests) { + SCOPED_TRACE("Expecting request to fail [executeSynchronously]"); + Return executeStatus = preparedModel->executeSynchronously( + request, MeasureTiming::NO, + [](ErrorStatus error, const hidl_vec& outputShapes, + const Timing& timing) { + ASSERT_NE(ErrorStatus::NONE, error); + EXPECT_EQ(outputShapes.size(), 0); + EXPECT_TRUE(badTiming(timing)); + }); + ASSERT_TRUE(executeStatus.isOk()); + } +} + } // namespace functional } // namespace vts } // namespace V1_2 diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp index 4ddefe8134..666f9b5b00 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp @@ -140,6 +140,20 @@ void ValidationTest::validateEverything(const Model& model, const std::vector& requests) { + // TODO: Should this always succeed? + // What if the invalid input is part of the model (i.e., a parameter). + validateModel(model); + + sp preparedModel; + ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel)); + if (preparedModel == nullptr) { + return; + } + + validateRequestFailure(preparedModel, requests); +} + sp getPreparedModel_1_2( const sp& callback) { sp preparedModelV1_0 = callback->getPreparedModel(); diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h index 8d1acbe03e..80e810a5f7 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h @@ -73,11 +73,14 @@ class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase { class ValidationTest : public NeuralnetworksHidlTest { protected: void validateEverything(const Model& model, const std::vector& requests); + void validateFailure(const Model& model, const std::vector& requests); private: void validateModel(const Model& model); void validateRequests(const sp& preparedModel, const std::vector& requests); + void validateRequestFailure(const sp& preparedModel, + const std::vector& requests); void validateBurst(const sp& preparedModel, const std::vector& requests); }; diff --git a/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp b/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp new file mode 100644 index 0000000000..064083340c --- /dev/null +++ b/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp @@ -0,0 +1,116 @@ +// clang-format off +// Generated file (from: strided_slice_invalid_output_dims.mod.py). Do not edit +std::vector& get_examples() { +static std::vector examples = { +// Begin of an example +{ +.operands = { +//Input(s) +{ // See tools/test_generator/include/TestHarness.h:MixedTyped + // int -> Dimensions map + .operandDimensions = {{0, {2, 3}}}, + // int -> FLOAT32 map + .float32Operands = {{0, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}}}, + // int -> INT32 map + .int32Operands = {}, + // int -> QUANT8_ASYMM map + .quant8AsymmOperands = {}, + // int -> QUANT16_SYMM map + .quant16SymmOperands = {}, + // int -> FLOAT16 map + .float16Operands = {}, + // int -> BOOL8 map + .bool8Operands = {}, + // int -> QUANT8_SYMM_PER_CHANNEL map + .quant8ChannelOperands = {}, + // int -> QUANT16_ASYMM map + .quant16AsymmOperands = {}, + // int -> QUANT8_SYMM map + .quant8SymmOperands = {}, +}, +//Output(s) +{ // See tools/test_generator/include/TestHarness.h:MixedTyped + // int -> Dimensions map + .operandDimensions = {{0, {3}}}, + // int -> FLOAT32 map + .float32Operands = {{0, {1.0f, 2.0f, 3.0f}}}, + // int -> INT32 map + .int32Operands = {}, + // int -> QUANT8_ASYMM map + .quant8AsymmOperands = {}, + // int -> QUANT16_SYMM map + .quant16SymmOperands = {}, + // int -> FLOAT16 map + .float16Operands = {}, + // int -> BOOL8 map + .bool8Operands = {}, + // int -> QUANT8_SYMM_PER_CHANNEL map + .quant8ChannelOperands = {}, + // int -> QUANT16_ASYMM map + .quant16AsymmOperands = {}, + // int -> QUANT8_SYMM map + .quant8SymmOperands = {}, +} +}, +}, // End of an example +}; +return examples; +}; + +std::vector& get_examples_dynamic_output_shape() { +static std::vector examples_dynamic_output_shape = { +// Begin of an example +{ +.operands = { +//Input(s) +{ // See tools/test_generator/include/TestHarness.h:MixedTyped + // int -> Dimensions map + .operandDimensions = {{0, {2, 3}}}, + // int -> FLOAT32 map + .float32Operands = {{0, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}}}, + // int -> INT32 map + .int32Operands = {}, + // int -> QUANT8_ASYMM map + .quant8AsymmOperands = {}, + // int -> QUANT16_SYMM map + .quant16SymmOperands = {}, + // int -> FLOAT16 map + .float16Operands = {}, + // int -> BOOL8 map + .bool8Operands = {}, + // int -> QUANT8_SYMM_PER_CHANNEL map + .quant8ChannelOperands = {}, + // int -> QUANT16_ASYMM map + .quant16AsymmOperands = {}, + // int -> QUANT8_SYMM map + .quant8SymmOperands = {}, +}, +//Output(s) +{ // See tools/test_generator/include/TestHarness.h:MixedTyped + // int -> Dimensions map + .operandDimensions = {{0, {3}}}, + // int -> FLOAT32 map + .float32Operands = {{0, {1.0f, 2.0f, 3.0f}}}, + // int -> INT32 map + .int32Operands = {}, + // int -> QUANT8_ASYMM map + .quant8AsymmOperands = {}, + // int -> QUANT16_SYMM map + .quant16SymmOperands = {}, + // int -> FLOAT16 map + .float16Operands = {}, + // int -> BOOL8 map + .bool8Operands = {}, + // int -> QUANT8_SYMM_PER_CHANNEL map + .quant8ChannelOperands = {}, + // int -> QUANT16_ASYMM map + .quant16AsymmOperands = {}, + // int -> QUANT8_SYMM map + .quant8SymmOperands = {}, +} +}, +}, // End of an example +}; +return examples_dynamic_output_shape; +}; + diff --git a/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp b/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp new file mode 100644 index 0000000000..106655aa30 --- /dev/null +++ b/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp @@ -0,0 +1,216 @@ +// clang-format off +// Generated file (from: strided_slice_invalid_output_dims.mod.py). Do not edit +// Create the model +Model createTestModel() { + const std::vector operands = { + { + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {2, 3}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + .type = OperandType::TENSOR_INT32, + .dimensions = {2}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::CONSTANT_COPY, + .location = {.poolIndex = 0, .offset = 0, .length = 8}, + }, + { + .type = OperandType::TENSOR_INT32, + .dimensions = {2}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::CONSTANT_COPY, + .location = {.poolIndex = 0, .offset = 8, .length = 8}, + }, + { + .type = OperandType::TENSOR_INT32, + .dimensions = {2}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::CONSTANT_COPY, + .location = {.poolIndex = 0, .offset = 16, .length = 8}, + }, + { + .type = OperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::CONSTANT_COPY, + .location = {.poolIndex = 0, .offset = 24, .length = 4}, + }, + { + .type = OperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::CONSTANT_COPY, + .location = {.poolIndex = 0, .offset = 28, .length = 4}, + }, + { + .type = OperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::CONSTANT_COPY, + .location = {.poolIndex = 0, .offset = 32, .length = 4}, + }, + { + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {3}, + .numberOfConsumers = 0, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_OUTPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + } + }; + + const std::vector operations = { + { + .type = OperationType::STRIDED_SLICE, + .inputs = {0, 1, 2, 3, 4, 5, 6}, + .outputs = {7}, + } + }; + + const std::vector inputIndexes = {0}; + const std::vector outputIndexes = {7}; + std::vector operandValues = { + 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 + }; + const std::vector pools = {}; + + return { + .operands = operands, + .operations = operations, + .inputIndexes = inputIndexes, + .outputIndexes = outputIndexes, + .operandValues = operandValues, + .pools = pools, + }; +} + +inline bool is_ignored(int i) { + static std::set ignore = {}; + return ignore.find(i) != ignore.end(); +} + +// Create the model +Model createTestModel_dynamic_output_shape() { + const std::vector operands = { + { + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {2, 3}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + .type = OperandType::TENSOR_INT32, + .dimensions = {2}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::CONSTANT_COPY, + .location = {.poolIndex = 0, .offset = 0, .length = 8}, + }, + { + .type = OperandType::TENSOR_INT32, + .dimensions = {2}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::CONSTANT_COPY, + .location = {.poolIndex = 0, .offset = 8, .length = 8}, + }, + { + .type = OperandType::TENSOR_INT32, + .dimensions = {2}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::CONSTANT_COPY, + .location = {.poolIndex = 0, .offset = 16, .length = 8}, + }, + { + .type = OperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::CONSTANT_COPY, + .location = {.poolIndex = 0, .offset = 24, .length = 4}, + }, + { + .type = OperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::CONSTANT_COPY, + .location = {.poolIndex = 0, .offset = 28, .length = 4}, + }, + { + .type = OperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::CONSTANT_COPY, + .location = {.poolIndex = 0, .offset = 32, .length = 4}, + }, + { + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {0}, + .numberOfConsumers = 0, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_OUTPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + } + }; + + const std::vector operations = { + { + .type = OperationType::STRIDED_SLICE, + .inputs = {0, 1, 2, 3, 4, 5, 6}, + .outputs = {7}, + } + }; + + const std::vector inputIndexes = {0}; + const std::vector outputIndexes = {7}; + std::vector operandValues = { + 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 + }; + const std::vector pools = {}; + + return { + .operands = operands, + .operations = operations, + .inputIndexes = inputIndexes, + .outputIndexes = outputIndexes, + .operandValues = operandValues, + .pools = pools, + }; +} + +inline bool is_ignored_dynamic_output_shape(int i) { + static std::set ignore = {}; + return ignore.find(i) != ignore.end(); +} + diff --git a/neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py b/neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py new file mode 100644 index 0000000000..e8d30f3fb2 --- /dev/null +++ b/neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py @@ -0,0 +1,43 @@ +# +# 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. +# + +# This test makes sure that executing STRIDED_SLICE results in a failure when +# the output dimensions do not match shrinkAxisMask. +# +# The test generator does not support generating tests resulting in execution +# failure, so the gTest part of this test has been written by hand. +# TODO(b/132155416): Move this under frameworks/ml/nn/runtime/test/specs/V1_2. +# +# Based on strided_slice_float_11.mod.py. + +model = Model() +i1 = Input("input", "TENSOR_FLOAT32", "{2, 3}") +begins = Parameter("begins", "TENSOR_INT32", "{2}", [0, 0]) +# The value "2" below makes the test invalid. See http://b/79856511#comment2. +ends = Parameter("ends", "TENSOR_INT32", "{2}", [2, 3]) +strides = Parameter("strides", "TENSOR_INT32", "{2}", [1, 1]) +beginMask = Int32Scalar("beginMask", 0) +endMask = Int32Scalar("endMask", 0) +shrinkAxisMask = Int32Scalar("shrinkAxisMask", 1) + +output = Output("output", "TENSOR_FLOAT32", "{3}") + +model = model.Operation("STRIDED_SLICE", i1, begins, ends, strides, beginMask, endMask, shrinkAxisMask).To(output) + +Example({ + i1: [1, 2, 3, 4, 5, 6], + output: [1, 2, 3], +}) From b28e69f37efe8d569db2a3fc9dd9c633c0ab8ba5 Mon Sep 17 00:00:00 2001 From: Max Bires Date: Wed, 22 May 2019 00:48:49 +0000 Subject: [PATCH 0011/1022] Removing an extraneous test Test: VTS passes Bug: 133316458 Change-Id: I98d73ff025515a89e2743ed20950c840aedb5114 --- .../functional/keymaster_hidl_hal_test.cpp | 22 ------------------- 1 file changed, 22 deletions(-) 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 2e76604027..4d93efabfe 100644 --- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp +++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp @@ -4154,28 +4154,6 @@ TEST_F(AttestationTest, RsaAttestationRequiresAppId) { &cert_chain)); } -/* - * AttestationTest.RsaAttestationRequiresCorrectAppId - * - * Verifies that attesting to RSA requires the correct app ID. - */ -TEST_F(AttestationTest, RsaAttestationRequiresCorrectAppId) { - ASSERT_EQ(ErrorCode::OK, - GenerateKey(AuthorizationSetBuilder() - .Authorization(TAG_NO_AUTH_REQUIRED) - .RsaSigningKey(2048, 65537) - .Digest(Digest::NONE) - .Padding(PaddingMode::NONE) - .Authorization(TAG_APPLICATION_ID, HidlBuf("lol")))); - - hidl_vec> cert_chain; - EXPECT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING, - AttestKey(AuthorizationSetBuilder() - .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge")) - .Authorization(TAG_APPLICATION_ID, HidlBuf("heh")), - &cert_chain)); -} - /* * AttestationTest.EcAttestation * From b019fd7a9a7389e60d96a1661fdac2f167d2f043 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Thu, 23 May 2019 12:50:12 -0700 Subject: [PATCH 0012/1022] Clean up Readback test Readback will be used in RenderEngine testing. Clean up test files and extract common classes Bug: 133411821 Test: build, boot, VtsHalGraphicsComposerV2_2TargetTest Change-Id: I45b4666348ae0137dd2a7825b5cfd627a1e1aa58 --- graphics/composer/2.2/utils/vts/Android.bp | 3 + .../composer/2.2/utils/vts/ReadbackVts.cpp | 247 ++++++++++ .../include/composer-vts/2.2/ReadbackVts.h | 175 +++++++ ...VtsHalGraphicsComposerV2_2ReadbackTest.cpp | 436 +++--------------- 4 files changed, 498 insertions(+), 363 deletions(-) create mode 100644 graphics/composer/2.2/utils/vts/ReadbackVts.cpp create mode 100644 graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp index c6b524d234..4016120143 100644 --- a/graphics/composer/2.2/utils/vts/Android.bp +++ b/graphics/composer/2.2/utils/vts/Android.bp @@ -19,12 +19,15 @@ cc_library_static { defaults: ["hidl_defaults"], srcs: [ "ComposerVts.cpp", + "ReadbackVts.cpp", ], static_libs: [ "VtsHalHidlTargetTestBase", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.1-vts", "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.mapper@2.1", + "android.hardware.graphics.mapper@2.1-vts", ], export_static_lib_headers: [ "android.hardware.graphics.composer@2.1-vts", diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp new file mode 100644 index 0000000000..8eabaef5e3 --- /dev/null +++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp @@ -0,0 +1,247 @@ +/* + * Copyright 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. + */ + +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_2 { +namespace vts { + +void TestLayer::write(const std::shared_ptr& writer) { + writer->selectLayer(mLayer); + writer->setLayerDisplayFrame(mDisplayFrame); + writer->setLayerSourceCrop(mSourceCrop); + writer->setLayerZOrder(mZOrder); + writer->setLayerSurfaceDamage(mSurfaceDamage); + writer->setLayerTransform(mTransform); + writer->setLayerPlaneAlpha(mAlpha); + writer->setLayerBlendMode(mBlendMode); +} + +int32_t ReadbackHelper::GetBytesPerPixel(PixelFormat pixelFormat) { + switch (pixelFormat) { + case PixelFormat::RGBA_8888: + return 4; + case PixelFormat::RGB_888: + return 3; + default: + return -1; + } +} + +void ReadbackHelper::fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData, + PixelFormat pixelFormat, + std::vector desiredPixelColors) { + ASSERT_TRUE(pixelFormat == PixelFormat::RGB_888 || pixelFormat == PixelFormat::RGBA_8888); + int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat); + ASSERT_NE(-1, bytesPerPixel); + for (int row = 0; row < height; row++) { + for (int col = 0; col < width; col++) { + int pixel = row * width + col; + IComposerClient::Color srcColor = desiredPixelColors[pixel]; + + int offset = (row * stride + col) * bytesPerPixel; + uint8_t* pixelColor = (uint8_t*)bufferData + offset; + pixelColor[0] = srcColor.r; + pixelColor[1] = srcColor.g; + pixelColor[2] = srcColor.b; + + if (bytesPerPixel == 4) { + pixelColor[3] = srcColor.a; + } + } + } +} + +void ReadbackHelper::clearColors(std::vector& expectedColors, int32_t width, + int32_t height, int32_t displayWidth) { + for (int row = 0; row < height; row++) { + for (int col = 0; col < width; col++) { + int pixel = row * displayWidth + col; + expectedColors[pixel] = BLACK; + } + } +} + +void ReadbackHelper::fillColorsArea(std::vector& expectedColors, + int32_t stride, IComposerClient::Rect area, + IComposerClient::Color color) { + for (int row = area.top; row < area.bottom; row++) { + for (int col = area.left; col < area.right; col++) { + int pixel = row * stride + col; + expectedColors[pixel] = color; + } + } +} + +bool ReadbackHelper::readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace, + const Error error) { + if (error != Error::NONE) { + return false; + } + // TODO: add support for RGBA_1010102 + if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) { + return false; + } + if (dataspace != Dataspace::V0_SRGB) { + return false; + } + return true; +} + +ReadbackBuffer::ReadbackBuffer(Display display, const std::shared_ptr& client, + const std::shared_ptr& gralloc, uint32_t width, + uint32_t height, PixelFormat pixelFormat, Dataspace dataspace) { + mDisplay = display; + + mComposerClient = client; + mGralloc = gralloc; + + mPixelFormat = pixelFormat; + mDataspace = dataspace; + + mInfo.width = width; + mInfo.height = height; + mInfo.layerCount = 1; + mInfo.format = mPixelFormat; + mInfo.usage = static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE); + + mAccessRegion.top = 0; + mAccessRegion.left = 0; + mAccessRegion.width = width; + mAccessRegion.height = height; +} + +ReadbackBuffer::~ReadbackBuffer() { + if (mBufferHandle != nullptr) { + mGralloc->freeBuffer(mBufferHandle); + } +} + +void ReadbackBuffer::setReadbackBuffer() { + if (mBufferHandle != nullptr) { + mGralloc->freeBuffer(mBufferHandle); + mBufferHandle = nullptr; + } + mBufferHandle = mGralloc->allocate(mInfo, /*import*/ true, &mStride); + ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mInfo, mStride)); + ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle, -1)); +} + +void ReadbackBuffer::checkReadbackBuffer(std::vector expectedColors) { + // lock buffer for reading + int32_t fenceHandle; + ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle)); + + void* bufData = mGralloc->lock(mBufferHandle, mInfo.usage, mAccessRegion, fenceHandle); + ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888); + int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(mPixelFormat); + ASSERT_NE(-1, bytesPerPixel); + for (int row = 0; row < mInfo.height; row++) { + for (int col = 0; col < mInfo.width; col++) { + int pixel = row * mInfo.width + col; + int offset = (row * mStride + col) * bytesPerPixel; + uint8_t* pixelColor = (uint8_t*)bufData + offset; + + ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]); + ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]); + ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]); + } + } + int32_t unlockFence = mGralloc->unlock(mBufferHandle); + if (unlockFence != -1) { + sync_wait(unlockFence, -1); + close(unlockFence); + } +} + +void TestColorLayer::write(const std::shared_ptr& writer) { + TestLayer::write(writer); + writer->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR); + writer->setLayerColor(mColor); +} + +TestBufferLayer::TestBufferLayer(const std::shared_ptr& client, + const std::shared_ptr& gralloc, Display display, + int32_t width, int32_t height, PixelFormat format, + IComposerClient::Composition composition) + : TestLayer{client, display} { + mGralloc = gralloc; + mComposition = composition; + mInfo.width = width; + mInfo.height = height; + mInfo.layerCount = 1; + mInfo.format = format; + mInfo.usage = static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY); + + mAccessRegion.top = 0; + mAccessRegion.left = 0; + mAccessRegion.width = width; + mAccessRegion.height = height; + + setSourceCrop({0, 0, (float)width, (float)height}); +} + +TestBufferLayer::~TestBufferLayer() { + if (mBufferHandle != nullptr) { + mGralloc->freeBuffer(mBufferHandle); + } +} + +void TestBufferLayer::write(const std::shared_ptr& writer) { + TestLayer::write(writer); + writer->setLayerCompositionType(mComposition); + writer->setLayerDataspace(Dataspace::UNKNOWN); + writer->setLayerVisibleRegion(std::vector(1, mDisplayFrame)); + if (mBufferHandle != nullptr) writer->setLayerBuffer(0, mBufferHandle, mFillFence); +} + +void TestBufferLayer::fillBuffer(std::vector expectedColors) { + void* bufData = mGralloc->lock(mBufferHandle, mInfo.usage, mAccessRegion, -1); + ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mInfo.width, mInfo.height, mStride, bufData, + mInfo.format, expectedColors)); + mFillFence = mGralloc->unlock(mBufferHandle); + if (mFillFence != -1) { + sync_wait(mFillFence, -1); + close(mFillFence); + } +} +void TestBufferLayer::setBuffer(std::vector colors) { + if (mBufferHandle != nullptr) { + mGralloc->freeBuffer(mBufferHandle); + mBufferHandle = nullptr; + } + mBufferHandle = mGralloc->allocate(mInfo, /*import*/ true, &mStride); + ASSERT_NE(nullptr, mBufferHandle); + ASSERT_NO_FATAL_FAILURE(fillBuffer(colors)); + ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mInfo, mStride)); +} + +void TestBufferLayer::setToClientComposition(const std::shared_ptr& writer) { + writer->selectLayer(mLayer); + writer->setLayerCompositionType(IComposerClient::Composition::CLIENT); +} + +} // namespace vts +} // namespace V2_2 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h new file mode 100644 index 0000000000..9ce4e39b51 --- /dev/null +++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h @@ -0,0 +1,175 @@ +/* + * Copyright 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_2 { +namespace vts { + +using android::hardware::hidl_handle; +using common::V1_1::BufferUsage; +using common::V1_1::Dataspace; +using common::V1_1::PixelFormat; +using mapper::V2_1::IMapper; +using mapper::V2_1::vts::Gralloc; +using V2_1::Display; +using V2_1::Layer; +using V2_1::vts::TestCommandReader; + +static const IComposerClient::Color BLACK = {0, 0, 0, 0xff}; +static const IComposerClient::Color RED = {0xff, 0, 0, 0xff}; +static const IComposerClient::Color TRANSLUCENT_RED = {0xff, 0, 0, 0x33}; +static const IComposerClient::Color GREEN = {0, 0xff, 0, 0xff}; +static const IComposerClient::Color BLUE = {0, 0, 0xff, 0xff}; + +class TestLayer { + public: + TestLayer(const std::shared_ptr& client, Display display) + : mLayer(client->createLayer(display, kBufferSlotCount)), mComposerClient(client) {} + + // ComposerClient will take care of destroying layers, no need to explicitly + // call destroyLayers here + virtual ~TestLayer(){}; + + virtual void write(const std::shared_ptr& writer); + + void setDisplayFrame(IComposerClient::Rect frame) { mDisplayFrame = frame; } + void setSourceCrop(IComposerClient::FRect crop) { mSourceCrop = crop; } + void setZOrder(uint32_t z) { mZOrder = z; } + + void setSurfaceDamage(std::vector surfaceDamage) { + mSurfaceDamage = surfaceDamage; + } + + void setTransform(Transform transform) { mTransform = transform; } + void setAlpha(float alpha) { mAlpha = alpha; } + void setBlendMode(IComposerClient::BlendMode blendMode) { mBlendMode = blendMode; } + + static constexpr uint32_t kBufferSlotCount = 64; + + IComposerClient::Rect mDisplayFrame = {0, 0, 0, 0}; + uint32_t mZOrder = 0; + std::vector mSurfaceDamage; + Transform mTransform = static_cast(0); + IComposerClient::FRect mSourceCrop = {0, 0, 0, 0}; + float mAlpha = 1.0; + IComposerClient::BlendMode mBlendMode = IComposerClient::BlendMode::NONE; + + protected: + Layer mLayer; + + private: + std::shared_ptr const mComposerClient; +}; + +class TestColorLayer : public TestLayer { + public: + TestColorLayer(const std::shared_ptr& client, Display display) + : TestLayer{client, display} {} + + void write(const std::shared_ptr& writer) override; + + void setColor(IComposerClient::Color color) { mColor = color; } + + private: + IComposerClient::Color mColor = {0xff, 0xff, 0xff, 0xff}; +}; + +class TestBufferLayer : public TestLayer { + public: + TestBufferLayer( + const std::shared_ptr& client, const std::shared_ptr& gralloc, + Display display, int32_t width, int32_t height, PixelFormat format, + IComposerClient::Composition composition = IComposerClient::Composition::DEVICE); + + ~TestBufferLayer(); + + void write(const std::shared_ptr& writer) override; + + void fillBuffer(std::vector expectedColors); + + void setBuffer(std::vector colors); + + void setToClientComposition(const std::shared_ptr& writer); + + IMapper::BufferDescriptorInfo mInfo; + IMapper::Rect mAccessRegion; + uint32_t mStride; + + protected: + IComposerClient::Composition mComposition; + std::shared_ptr mGralloc; + int32_t mFillFence; + const native_handle_t* mBufferHandle = nullptr; +}; + +class ReadbackHelper : public ::testing::VtsHalHidlTargetTestBase { + public: + static int32_t GetBytesPerPixel(PixelFormat pixelFormat); + + static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData, + PixelFormat pixelFormat, + std::vector desiredPixelColors); + + static void clearColors(std::vector& expectedColors, int32_t width, + int32_t height, int32_t displayWidth); + + static void fillColorsArea(std::vector& expectedColors, int32_t stride, + IComposerClient::Rect area, IComposerClient::Color color); + + static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace, + const Error error); +}; + +class ReadbackBuffer { + public: + ReadbackBuffer(Display display, const std::shared_ptr& client, + const std::shared_ptr& gralloc, uint32_t width, uint32_t height, + PixelFormat pixelFormat, Dataspace dataspace); + ~ReadbackBuffer(); + + void setReadbackBuffer(); + + void checkReadbackBuffer(std::vector expectedColors); + + protected: + IMapper::BufferDescriptorInfo mInfo; + IMapper::Rect mAccessRegion; + uint32_t mStride; + const native_handle_t* mBufferHandle = nullptr; + PixelFormat mPixelFormat; + Dataspace mDataspace; + Display mDisplay; + std::shared_ptr mGralloc; + std::shared_ptr mComposerClient; +}; + +} // namespace vts +} // namespace V2_2 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp index da8858e037..2534196522 100644 --- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp @@ -18,13 +18,10 @@ #include #include -#include -#include #include #include #include -#include -#include +#include namespace android { namespace hardware { @@ -44,12 +41,6 @@ using V2_1::Display; using V2_1::Layer; using V2_1::vts::TestCommandReader; -static const IComposerClient::Color BLACK = {0, 0, 0, 0xff}; -static const IComposerClient::Color RED = {0xff, 0, 0, 0xff}; -static const IComposerClient::Color TRANSLUCENT_RED = {0xff, 0, 0, 0x33}; -static const IComposerClient::Color GREEN = {0, 0xff, 0, 0xff}; -static const IComposerClient::Color BLUE = {0, 0, 0xff, 0xff}; - // Test environment for graphics.composer class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: @@ -65,92 +56,7 @@ class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEn GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment); }; -class TestLayer { - public: - TestLayer(const std::shared_ptr& client, Display display) - : mLayer(client->createLayer(display, kBufferSlotCount)), mComposerClient(client) {} - - // ComposerClient will take care of destroying layers, no need to explicitly - // call destroyLayers here - virtual ~TestLayer(){}; - - virtual void write(const std::shared_ptr& writer) { - writer->selectLayer(mLayer); - writer->setLayerDisplayFrame(mDisplayFrame); - writer->setLayerSourceCrop(mSourceCrop); - writer->setLayerZOrder(mZOrder); - writer->setLayerSurfaceDamage(mSurfaceDamage); - writer->setLayerTransform(mTransform); - writer->setLayerPlaneAlpha(mAlpha); - writer->setLayerBlendMode(mBlendMode); - } - - void setDisplayFrame(IComposerClient::Rect frame) { mDisplayFrame = frame; } - void setSourceCrop(IComposerClient::FRect crop) { mSourceCrop = crop; } - void setZOrder(uint32_t z) { mZOrder = z; } - - void setSurfaceDamage(std::vector surfaceDamage) { - mSurfaceDamage = surfaceDamage; - } - - void setTransform(Transform transform) { mTransform = transform; } - void setAlpha(float alpha) { mAlpha = alpha; } - void setBlendMode(IComposerClient::BlendMode blendMode) { mBlendMode = blendMode; } - - static constexpr uint32_t kBufferSlotCount = 64; - - IComposerClient::Rect mDisplayFrame = {0, 0, 0, 0}; - uint32_t mZOrder = 0; - std::vector mSurfaceDamage; - Transform mTransform = static_cast(0); - IComposerClient::FRect mSourceCrop = {0, 0, 0, 0}; - float mAlpha = 1.0; - IComposerClient::BlendMode mBlendMode = IComposerClient::BlendMode::NONE; - - protected: - Layer mLayer; - - private: - std::shared_ptr const mComposerClient; -}; - class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase { - public: - static int32_t GetBytesPerPixel(PixelFormat pixelFormat) { - switch (pixelFormat) { - case PixelFormat::RGBA_8888: - return 4; - case PixelFormat::RGB_888: - return 3; - default: - return -1; - } - } - - static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData, - PixelFormat pixelFormat, - std::vector desiredPixelColors) { - ASSERT_TRUE(pixelFormat == PixelFormat::RGB_888 || pixelFormat == PixelFormat::RGBA_8888); - int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat); - ASSERT_NE(-1, bytesPerPixel); - for (int row = 0; row < height; row++) { - for (int col = 0; col < width; col++) { - int pixel = row * width + col; - IComposerClient::Color srcColor = desiredPixelColors[pixel]; - - int offset = (row * stride + col) * bytesPerPixel; - uint8_t* pixelColor = (uint8_t*)bufferData + offset; - pixelColor[0] = srcColor.r; - pixelColor[1] = srcColor.g; - pixelColor[2] = srcColor.b; - - if (bytesPerPixel == 4) { - pixelColor[3] = srcColor.a; - } - } - } - } - protected: using PowerMode = V2_1::IComposerClient::PowerMode; void SetUp() override { @@ -183,12 +89,13 @@ class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase mGralloc = std::make_shared(); mComposerClient->getRaw()->getReadbackBufferAttributes( - mPrimaryDisplay, - [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { - mHasReadbackBuffer = readbackSupported(tmpPixelFormat, tmpDataspace, tmpError); - mPixelFormat = tmpPixelFormat; - mDataspace = tmpDataspace; - }); + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON)); } @@ -209,10 +116,6 @@ class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase mReader->mErrors.clear(); } - void execute() { - ASSERT_NO_FATAL_FAILURE(mComposerClient->execute(mReader.get(), mWriter.get())); - } - void writeLayers(const std::vector>& layers) { for (auto layer : layers) { layer->write(mWriter); @@ -220,42 +123,10 @@ class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase execute(); } - void clearColors(std::vector& expectedColors, int32_t width, - int32_t height) { - for (int row = 0; row < height; row++) { - for (int col = 0; col < width; col++) { - int pixel = row * mDisplayWidth + col; - expectedColors[pixel] = BLACK; - } - } + void execute() { + ASSERT_NO_FATAL_FAILURE(mComposerClient->execute(mReader.get(), mWriter.get())); } - void fillColorsArea(std::vector& expectedColors, int32_t stride, - IComposerClient::Rect area, IComposerClient::Color color) { - for (int row = area.top; row < area.bottom; row++) { - for (int col = area.left; col < area.right; col++) { - int pixel = row * stride + col; - expectedColors[pixel] = color; - } - } - } - - bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace, - const Error error) { - if (error != Error::NONE) { - return false; - } - // TODO: add support for RGBA_1010102 - if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) { - return false; - } - if (dataspace != Dataspace::V0_SRGB) { - return false; - } - return true; - } - - std::unique_ptr mComposer; std::shared_ptr mComposerClient; @@ -286,178 +157,6 @@ class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase } } }; -class ReadbackBuffer { - public: - ReadbackBuffer(Display display, const std::shared_ptr& client, - const std::shared_ptr& gralloc, uint32_t width, uint32_t height, - PixelFormat pixelFormat, Dataspace dataspace) { - mDisplay = display; - - mComposerClient = client; - mGralloc = gralloc; - - mPixelFormat = pixelFormat; - mDataspace = dataspace; - - mInfo.width = width; - mInfo.height = height; - mInfo.layerCount = 1; - mInfo.format = mPixelFormat; - mInfo.usage = static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE); - - mAccessRegion.top = 0; - mAccessRegion.left = 0; - mAccessRegion.width = width; - mAccessRegion.height = height; - }; - - ~ReadbackBuffer() { - if (mBufferHandle != nullptr) { - mGralloc->freeBuffer(mBufferHandle); - } - } - - void setReadbackBuffer() { - if (mBufferHandle != nullptr) { - mGralloc->freeBuffer(mBufferHandle); - mBufferHandle = nullptr; - } - mBufferHandle = mGralloc->allocate(mInfo, /*import*/ true, &mStride); - ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mInfo, mStride)); - ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle, -1)); - } - - void checkReadbackBuffer(std::vector expectedColors) { - // lock buffer for reading - int32_t fenceHandle; - ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle)); - - void* bufData = mGralloc->lock(mBufferHandle, mInfo.usage, mAccessRegion, fenceHandle); - ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888); - int32_t bytesPerPixel = GraphicsComposerReadbackTest::GetBytesPerPixel(mPixelFormat); - ASSERT_NE(-1, bytesPerPixel); - for (int row = 0; row < mInfo.height; row++) { - for (int col = 0; col < mInfo.width; col++) { - int pixel = row * mInfo.width + col; - int offset = (row * mStride + col) * bytesPerPixel; - uint8_t* pixelColor = (uint8_t*)bufData + offset; - - ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]); - ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]); - ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]); - } - } - int32_t unlockFence = mGralloc->unlock(mBufferHandle); - if (unlockFence != -1) { - sync_wait(unlockFence, -1); - close(unlockFence); - } - } - - protected: - IMapper::BufferDescriptorInfo mInfo; - IMapper::Rect mAccessRegion; - uint32_t mStride; - const native_handle_t* mBufferHandle = nullptr; - PixelFormat mPixelFormat; - Dataspace mDataspace; - Display mDisplay; - std::shared_ptr mGralloc; - std::shared_ptr mComposerClient; -}; - -class TestColorLayer : public TestLayer { - public: - TestColorLayer(const std::shared_ptr& client, Display display) - : TestLayer{client, display} {} - - void write(const std::shared_ptr& writer) override { - TestLayer::write(writer); - writer->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR); - writer->setLayerColor(mColor); - } - - void setColor(IComposerClient::Color color) { mColor = color; } - - private: - IComposerClient::Color mColor = {0xff, 0xff, 0xff, 0xff}; -}; - -class TestBufferLayer : public TestLayer { - public: - TestBufferLayer(const std::shared_ptr& client, - const std::shared_ptr& gralloc, Display display, int32_t width, - int32_t height, PixelFormat format, - IComposerClient::Composition composition = IComposerClient::Composition::DEVICE) - : TestLayer{client, display} { - mGralloc = gralloc; - mComposition = composition; - mInfo.width = width; - mInfo.height = height; - mInfo.layerCount = 1; - mInfo.format = format; - mInfo.usage = - static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | - BufferUsage::COMPOSER_OVERLAY); - - mAccessRegion.top = 0; - mAccessRegion.left = 0; - mAccessRegion.width = width; - mAccessRegion.height = height; - - setSourceCrop({0, 0, (float)width, (float)height}); - } - - ~TestBufferLayer() { - if (mBufferHandle != nullptr) { - mGralloc->freeBuffer(mBufferHandle); - } - } - - void write(const std::shared_ptr& writer) override { - TestLayer::write(writer); - writer->setLayerCompositionType(mComposition); - writer->setLayerDataspace(Dataspace::UNKNOWN); - writer->setLayerVisibleRegion(std::vector(1, mDisplayFrame)); - if (mBufferHandle != nullptr) writer->setLayerBuffer(0, mBufferHandle, mFillFence); - } - - void fillBuffer(std::vector expectedColors) { - void* bufData = mGralloc->lock(mBufferHandle, mInfo.usage, mAccessRegion, -1); - ASSERT_NO_FATAL_FAILURE(GraphicsComposerReadbackTest::fillBuffer( - mInfo.width, mInfo.height, mStride, bufData, mInfo.format, expectedColors)); - mFillFence = mGralloc->unlock(mBufferHandle); - if (mFillFence != -1) { - sync_wait(mFillFence, -1); - close(mFillFence); - } - } - void setBuffer(std::vector colors) { - if (mBufferHandle != nullptr) { - mGralloc->freeBuffer(mBufferHandle); - mBufferHandle = nullptr; - } - mBufferHandle = mGralloc->allocate(mInfo, /*import*/ true, &mStride); - ASSERT_NE(nullptr, mBufferHandle); - ASSERT_NO_FATAL_FAILURE(fillBuffer(colors)); - ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mInfo, mStride)); - } - - void setToClientComposition(const std::shared_ptr& writer) { - writer->selectLayer(mLayer); - writer->setLayerCompositionType(IComposerClient::Composition::CLIENT); - } - - IMapper::BufferDescriptorInfo mInfo; - IMapper::Rect mAccessRegion; - uint32_t mStride; - - protected: - IComposerClient::Composition mComposition; - std::shared_ptr mGralloc; - int32_t mFillFence; - const native_handle_t* mBufferHandle = nullptr; -}; TEST_F(GraphicsComposerReadbackTest, SingleSolidColorLayer) { if (!mHasReadbackBuffer) { @@ -478,7 +177,7 @@ TEST_F(GraphicsComposerReadbackTest, SingleSolidColorLayer) { // expected color for each pixel std::vector expectedColors(mDisplayWidth * mDisplayHeight); - fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE); ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); @@ -515,11 +214,13 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerBuffer) { mDisplayHeight, mPixelFormat, mDataspace); ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); std::vector expectedColors(mDisplayWidth * mDisplayHeight); - fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); - fillColorsArea(expectedColors, mDisplayWidth, - {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, GREEN); - fillColorsArea(expectedColors, mDisplayWidth, - {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, + GREEN); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE); auto layer = std::make_shared(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, @@ -580,7 +281,7 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerBufferNoEffect) { // expected color for each pixel std::vector expectedColors(mDisplayWidth * mDisplayHeight); - fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE); ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); @@ -611,11 +312,13 @@ TEST_F(GraphicsComposerReadbackTest, ClientComposition) { mWriter->selectDisplay(mPrimaryDisplay); std::vector expectedColors(mDisplayWidth * mDisplayHeight); - fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); - fillColorsArea(expectedColors, mDisplayWidth, - {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, GREEN); - fillColorsArea(expectedColors, mDisplayWidth, - {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, + GREEN); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE); auto layer = std::make_shared(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, @@ -657,8 +360,9 @@ TEST_F(GraphicsComposerReadbackTest, ClientComposition) { void* clientBufData = mGralloc->lock(clientBufferHandle, clientInfo.usage, layer->mAccessRegion, -1); - ASSERT_NO_FATAL_FAILURE(fillBuffer(clientInfo.width, clientInfo.height, clientStride, - clientBufData, clientInfo.format, expectedColors)); + ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(clientInfo.width, clientInfo.height, + clientStride, clientBufData, + clientInfo.format, expectedColors)); int clientFence = mGralloc->unlock(clientBufferHandle); if (clientFence != -1) { sync_wait(clientFence, -1); @@ -695,9 +399,10 @@ TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) { mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount)); std::vector expectedColors(mDisplayWidth * mDisplayHeight); - fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 2}, GREEN); - fillColorsArea(expectedColors, mDisplayWidth, - {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight / 2}, GREEN); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED); ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); @@ -708,10 +413,10 @@ TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) { mDisplayHeight / 2, PixelFormat::RGBA_8888); std::vector deviceColors(deviceLayer->mInfo.width * deviceLayer->mInfo.height); - fillColorsArea(deviceColors, deviceLayer->mInfo.width, - {0, 0, static_cast(deviceLayer->mInfo.width), - static_cast(deviceLayer->mInfo.height)}, - GREEN); + ReadbackHelper::fillColorsArea(deviceColors, deviceLayer->mInfo.width, + {0, 0, static_cast(deviceLayer->mInfo.width), + static_cast(deviceLayer->mInfo.height)}, + GREEN); deviceLayer->setDisplayFrame({0, 0, static_cast(deviceLayer->mInfo.width), static_cast(deviceLayer->mInfo.height)}); deviceLayer->setZOrder(10); @@ -749,9 +454,10 @@ TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) { clientAccessRegion.height = mDisplayHeight; void* clientData = mGralloc->lock(clientBufferHandle, clientInfo.usage, clientAccessRegion, -1); std::vector clientColors(clientInfo.width * clientInfo.height); - fillColorsArea(clientColors, clientInfo.width, clientFrame, RED); - ASSERT_NO_FATAL_FAILURE(fillBuffer(clientInfo.width, clientInfo.height, clientStride, - clientData, clientInfo.format, clientColors)); + ReadbackHelper::fillColorsArea(clientColors, clientInfo.width, clientFrame, RED); + ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(clientInfo.width, clientInfo.height, + clientStride, clientData, clientInfo.format, + clientColors)); int clientFence = mGralloc->unlock(clientBufferHandle); if (clientFence != -1) { sync_wait(clientFence, -1); @@ -787,7 +493,7 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerDamage) { IComposerClient::Rect redRect = {0, 0, mDisplayWidth / 4, mDisplayHeight / 4}; std::vector expectedColors(mDisplayWidth * mDisplayHeight); - fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); auto layer = std::make_shared(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, @@ -820,8 +526,8 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerDamage) { // update surface damage and recheck redRect = {mDisplayWidth / 4, mDisplayHeight / 4, mDisplayWidth / 2, mDisplayHeight / 2}; - clearColors(expectedColors, mDisplayWidth, mDisplayHeight); - fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors)); layer->setSurfaceDamage( @@ -895,9 +601,10 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerSourceCrop) { mWriter->selectDisplay(mPrimaryDisplay); std::vector expectedColors(mDisplayWidth * mDisplayHeight); - fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); - fillColorsArea(expectedColors, mDisplayWidth, - {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE); auto layer = std::make_shared(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, @@ -911,7 +618,8 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerSourceCrop) { std::vector> layers = {layer}; // update expected colors to match crop - fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight}, BLUE); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight}, BLUE); ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); @@ -959,8 +667,8 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerZOrder) { redLayer->setZOrder(10); // fill blue first so that red will overwrite on overlap - fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE); - fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); @@ -982,9 +690,9 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerZOrder) { ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); redLayer->setZOrder(1); - clearColors(expectedColors, mDisplayWidth, mDisplayHeight); - fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); - fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE); + ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE); ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); @@ -1019,8 +727,8 @@ class GraphicsComposerBlendModeReadbackTest : public GraphicsComposerReadbackTes void setUpLayers(IComposerClient::BlendMode blendMode) { mLayers.clear(); std::vector topLayerPixelColors(mDisplayWidth * mDisplayHeight); - fillColorsArea(topLayerPixelColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight}, - mTopLayerColor); + ReadbackHelper::fillColorsArea(topLayerPixelColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight}, mTopLayerColor); auto backgroundLayer = std::make_shared(mComposerClient, mPrimaryDisplay); backgroundLayer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); @@ -1043,7 +751,7 @@ class GraphicsComposerBlendModeReadbackTest : public GraphicsComposerReadbackTes void setExpectedColors(std::vector& expectedColors) { ASSERT_EQ(2, mLayers.size()); - clearColors(expectedColors, mDisplayWidth, mDisplayHeight); + ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth); auto layer = mLayers[1]; IComposerClient::BlendMode blendMode = layer->mBlendMode; @@ -1216,8 +924,8 @@ class GraphicsComposerTransformReadbackTest : public GraphicsComposerReadbackTes mLayer->setZOrder(10); std::vector baseColors(mSideLength * mSideLength); - fillColorsArea(baseColors, mSideLength, redRect, RED); - fillColorsArea(baseColors, mSideLength, blueRect, BLUE); + ReadbackHelper::fillColorsArea(baseColors, mSideLength, redRect, RED); + ReadbackHelper::fillColorsArea(baseColors, mSideLength, blueRect, BLUE); ASSERT_NO_FATAL_FAILURE(mLayer->setBuffer(baseColors)); mLayers = {backgroundLayer, mLayer}; @@ -1240,10 +948,10 @@ TEST_F(GraphicsComposerTransformReadbackTest, FLIP_H) { ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); mLayer->setTransform(Transform::FLIP_H); std::vector expectedColors(mDisplayWidth * mDisplayHeight); - fillColorsArea(expectedColors, mDisplayWidth, - {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED); - fillColorsArea(expectedColors, mDisplayWidth, - {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE); writeLayers(mLayers); ASSERT_EQ(0, mReader->mErrors.size()); @@ -1274,10 +982,10 @@ TEST_F(GraphicsComposerTransformReadbackTest, FLIP_V) { mLayer->setTransform(Transform::FLIP_V); std::vector expectedColors(mDisplayWidth * mDisplayHeight); - fillColorsArea(expectedColors, mDisplayWidth, - {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED); - fillColorsArea(expectedColors, mDisplayWidth, - {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE); writeLayers(mLayers); ASSERT_EQ(0, mReader->mErrors.size()); @@ -1307,9 +1015,11 @@ TEST_F(GraphicsComposerTransformReadbackTest, ROT_180) { mLayer->setTransform(Transform::ROT_180); std::vector expectedColors(mDisplayWidth * mDisplayHeight); - fillColorsArea(expectedColors, mDisplayWidth, - {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength}, RED); - fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mSideLength / 2, mSideLength / 2}, BLUE); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength}, + RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mSideLength / 2, mSideLength / 2}, BLUE); writeLayers(mLayers); ASSERT_EQ(0, mReader->mErrors.size()); From 1297854120b7079d2f0f8ea3886d7793f0670af2 Mon Sep 17 00:00:00 2001 From: Jordan Liu Date: Wed, 29 May 2019 11:06:16 -0700 Subject: [PATCH 0013/1022] Add radio config 1.2 VTS tests Bug: 122730535 Test: run vts -m VtsHalRadioConfigV1_2Target Change-Id: Ib4fc17ea9f76caaf0cb0d4a2914595b7cfb7b041 --- radio/config/1.2/vts/functional/Android.bp | 35 +++++ .../VtsHalRadioConfigV1_2TargetTest.cpp | 26 ++++ .../functional/radio_config_hidl_hal_api.cpp | 30 ++++ .../functional/radio_config_hidl_hal_test.cpp | 66 +++++++++ .../functional/radio_config_hidl_hal_utils.h | 140 ++++++++++++++++++ .../functional/radio_config_indication.cpp | 25 ++++ .../vts/functional/radio_config_response.cpp | 66 +++++++++ 7 files changed, 388 insertions(+) create mode 100644 radio/config/1.2/vts/functional/Android.bp create mode 100644 radio/config/1.2/vts/functional/VtsHalRadioConfigV1_2TargetTest.cpp create mode 100644 radio/config/1.2/vts/functional/radio_config_hidl_hal_api.cpp create mode 100644 radio/config/1.2/vts/functional/radio_config_hidl_hal_test.cpp create mode 100644 radio/config/1.2/vts/functional/radio_config_hidl_hal_utils.h create mode 100644 radio/config/1.2/vts/functional/radio_config_indication.cpp create mode 100644 radio/config/1.2/vts/functional/radio_config_response.cpp diff --git a/radio/config/1.2/vts/functional/Android.bp b/radio/config/1.2/vts/functional/Android.bp new file mode 100644 index 0000000000..0cafc24160 --- /dev/null +++ b/radio/config/1.2/vts/functional/Android.bp @@ -0,0 +1,35 @@ +// +// 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. +// + +cc_test { + name: "VtsHalRadioConfigV1_2TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "radio_config_hidl_hal_api.cpp", + "radio_config_hidl_hal_test.cpp", + "radio_config_response.cpp", + "radio_config_indication.cpp", + "VtsHalRadioConfigV1_2TargetTest.cpp", + ], + static_libs: [ + "RadioVtsTestUtilBase", + "android.hardware.radio.config@1.0", + "android.hardware.radio.config@1.1", + "android.hardware.radio.config@1.2", + ], + header_libs: ["radio.util.header@1.0"], + test_suites: ["general-tests"], +} diff --git a/radio/config/1.2/vts/functional/VtsHalRadioConfigV1_2TargetTest.cpp b/radio/config/1.2/vts/functional/VtsHalRadioConfigV1_2TargetTest.cpp new file mode 100644 index 0000000000..ec6544e659 --- /dev/null +++ b/radio/config/1.2/vts/functional/VtsHalRadioConfigV1_2TargetTest.cpp @@ -0,0 +1,26 @@ +/* + * 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. + */ + +#include + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(RadioConfigHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + RadioConfigHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} diff --git a/radio/config/1.2/vts/functional/radio_config_hidl_hal_api.cpp b/radio/config/1.2/vts/functional/radio_config_hidl_hal_api.cpp new file mode 100644 index 0000000000..a3729aca2f --- /dev/null +++ b/radio/config/1.2/vts/functional/radio_config_hidl_hal_api.cpp @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#include + +#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) + +/* + * Test IRadioConfig.getSimSlotsStatus() + */ +TEST_F(RadioConfigHidlTest, getSimSlotsStatus) { + const int serial = GetRandomSerialNumber(); + Return res = radioConfig->getSimSlotsStatus(serial); + ASSERT_OK(res); + ALOGI("getIccSlotsStatus, rspInfo.error = %s\n", + toString(radioConfigRsp->rspInfo.error).c_str()); +} diff --git a/radio/config/1.2/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.2/vts/functional/radio_config_hidl_hal_test.cpp new file mode 100644 index 0000000000..cd7a1726aa --- /dev/null +++ b/radio/config/1.2/vts/functional/radio_config_hidl_hal_test.cpp @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#include + +void RadioConfigHidlTest::SetUp() { + radioConfig = ::testing::VtsHalHidlTargetTestBase::getService( + RadioConfigHidlEnvironment::Instance()->getServiceName( + hidl_string(RADIO_SERVICE_NAME))); + if (radioConfig == NULL) { + sleep(60); + radioConfig = ::testing::VtsHalHidlTargetTestBase::getService( + RadioConfigHidlEnvironment::Instance()->getServiceName( + hidl_string(RADIO_SERVICE_NAME))); + } + ASSERT_NE(nullptr, radioConfig.get()); + + radioConfigRsp = new (std::nothrow) RadioConfigResponse(*this); + ASSERT_NE(nullptr, radioConfigRsp.get()); + + count_ = 0; + + radioConfig->setResponseFunctions(radioConfigRsp, nullptr); +} + +/* + * Notify that the response message is received. + */ +void RadioConfigHidlTest::notify(int receivedSerial) { + std::unique_lock lock(mtx_); + if (serial == receivedSerial) { + count_++; + cv_.notify_one(); + } +} + +/* + * Wait till the response message is notified or till TIMEOUT_PERIOD. + */ +std::cv_status RadioConfigHidlTest::wait() { + std::unique_lock lock(mtx_); + + std::cv_status status = std::cv_status::no_timeout; + auto now = std::chrono::system_clock::now(); + while (count_ == 0) { + status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD)); + if (status == std::cv_status::timeout) { + return status; + } + } + count_--; + return status; +} diff --git a/radio/config/1.2/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.2/vts/functional/radio_config_hidl_hal_utils.h new file mode 100644 index 0000000000..a876766b48 --- /dev/null +++ b/radio/config/1.2/vts/functional/radio_config_hidl_hal_utils.h @@ -0,0 +1,140 @@ +/* + * 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. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "vts_test_util.h" + +using namespace ::android::hardware::radio::config::V1_2; + +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::radio::config::V1_1::IRadioConfig; +using ::android::hardware::radio::config::V1_1::ModemsConfig; +using ::android::hardware::radio::config::V1_1::PhoneCapability; +using ::android::hardware::radio::config::V1_2::SimSlotStatus; +using ::android::hardware::radio::V1_0::RadioResponseInfo; +using ::android::hardware::radio::V1_0::RadioResponseType; + +#define TIMEOUT_PERIOD 75 +#define RADIO_SERVICE_NAME "slot1" + +class RadioConfigHidlTest; + +/* Callback class for radio config response */ +class RadioConfigResponse : public IRadioConfigResponse { + protected: + RadioConfigHidlTest& parent; + + public: + RadioResponseInfo rspInfo; + PhoneCapability phoneCap; + + RadioConfigResponse(RadioConfigHidlTest& parent); + virtual ~RadioConfigResponse() = default; + + Return getSimSlotsStatusResponse( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus); + + Return getSimSlotsStatusResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec& slotStatus); + + Return setSimSlotsMappingResponse(const RadioResponseInfo& info); + + Return getPhoneCapabilityResponse(const RadioResponseInfo& info, + const PhoneCapability& phoneCapability); + + Return setPreferredDataModemResponse(const RadioResponseInfo& info); + + Return getModemsConfigResponse(const RadioResponseInfo& info, + const ModemsConfig& mConfig); + + Return setModemsConfigResponse(const RadioResponseInfo& info); +}; + +/* Callback class for radio config indication */ +class RadioConfigIndication : public IRadioConfigIndication { + protected: + RadioConfigHidlTest& parent; + + public: + RadioConfigIndication(RadioConfigHidlTest& parent); + virtual ~RadioConfigIndication() = default; + + Return simSlotsStatusChanged_1_2( + ::android::hardware::radio::V1_0::RadioIndicationType type, + const ::android::hardware::hidl_vec& slotStatus); +}; + +// Test environment for Radio HIDL HAL. +class RadioConfigHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static RadioConfigHidlEnvironment* Instance() { + static RadioConfigHidlEnvironment* instance = new RadioConfigHidlEnvironment; + return instance; + } + virtual void registerTestServices() override { registerTestService(); } + + private: + RadioConfigHidlEnvironment() {} +}; + +// The main test class for Radio config HIDL. +class RadioConfigHidlTest : public ::testing::VtsHalHidlTargetTestBase { + protected: + std::mutex mtx_; + std::condition_variable cv_; + int count_; + + public: + virtual void SetUp() override; + + /* Used as a mechanism to inform the test about data/event callback */ + void notify(int receivedSerial); + + /* Test code calls this function to wait for response */ + std::cv_status wait(); + + void updateSimCardStatus(); + + /* Serial number for radio request */ + int serial; + + /* radio config service handle */ + sp radioConfig; + + /* radio config response handle */ + sp radioConfigRsp; +}; diff --git a/radio/config/1.2/vts/functional/radio_config_indication.cpp b/radio/config/1.2/vts/functional/radio_config_indication.cpp new file mode 100644 index 0000000000..0bacacb363 --- /dev/null +++ b/radio/config/1.2/vts/functional/radio_config_indication.cpp @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#include + +RadioConfigIndication::RadioConfigIndication(RadioConfigHidlTest& parent) : parent(parent) {} + +Return RadioConfigIndication::simSlotsStatusChanged_1_2( + ::android::hardware::radio::V1_0::RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec& /*slotStatus*/) { + return Void(); +} diff --git a/radio/config/1.2/vts/functional/radio_config_response.cpp b/radio/config/1.2/vts/functional/radio_config_response.cpp new file mode 100644 index 0000000000..ec0f88662a --- /dev/null +++ b/radio/config/1.2/vts/functional/radio_config_response.cpp @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#include + +using ::android::hardware::radio::V1_0::RadioResponseInfo; + +// SimSlotStatus slotStatus; + +RadioConfigResponse::RadioConfigResponse(RadioConfigHidlTest& parent) : parent(parent) {} + +Return RadioConfigResponse::getSimSlotsStatusResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& /* info */, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::config::V1_0::SimSlotStatus>& /* slotStatus */) { + return Void(); +} + +Return RadioConfigResponse::getSimSlotsStatusResponse_1_2( + const ::android::hardware::radio::V1_0::RadioResponseInfo& /* info */, + const ::android::hardware::hidl_vec& /* slotStatus */) { + return Void(); +} + +Return RadioConfigResponse::setSimSlotsMappingResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& /* info */) { + return Void(); +} + +Return RadioConfigResponse::getPhoneCapabilityResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& info, + const PhoneCapability& phoneCapability) { + rspInfo = info; + phoneCap = phoneCapability; + parent.notify(info.serial); + return Void(); +} + +Return RadioConfigResponse::setPreferredDataModemResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& /* info */) { + return Void(); +} + +Return RadioConfigResponse::getModemsConfigResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& /* info */, + const ModemsConfig& /* mConfig */) { + return Void(); +} + +Return RadioConfigResponse::setModemsConfigResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& /* info */) { + return Void(); +} From f9f366e5197c4a0d6ef8f3ea4a9a2f1384c7fdaa Mon Sep 17 00:00:00 2001 From: Janis Danisevskis Date: Tue, 4 Jun 2019 17:01:25 -0700 Subject: [PATCH 0014/1022] Added HIDL based software implementation of gatekeeper This patch adds a HIDL based software implementation of gatekeeper based on libgatekeeper. Also adds OWNER files to the vts test and default implementation directories. Test: Manually tested in emulator. Changing passwords and login worked. VtsHalGatekeeperV1_0TargetTest gatekeeper-software-device-unit-tests Change-Id: I632aeb6677640c133ec1b79e72568840adbc0550 --- gatekeeper/1.0/default/OWNERS | 2 + gatekeeper/1.0/software/Android.bp | 28 +++ gatekeeper/1.0/software/OWNERS | 2 + gatekeeper/1.0/software/SoftGateKeeper.h | 171 +++++++++++++++++ .../1.0/software/SoftGateKeeperDevice.cpp | 114 +++++++++++ .../1.0/software/SoftGateKeeperDevice.h | 80 ++++++++ ...ardware.gatekeeper@1.0-service.software.rc | 4 + ...rdware.gatekeeper@1.0-service.software.xml | 11 ++ gatekeeper/1.0/software/service.cpp | 39 ++++ gatekeeper/1.0/software/tests/Android.bp | 34 ++++ .../1.0/software/tests/gatekeeper_test.cpp | 178 ++++++++++++++++++ gatekeeper/1.0/vts/OWNERS | 3 + 12 files changed, 666 insertions(+) create mode 100644 gatekeeper/1.0/default/OWNERS create mode 100644 gatekeeper/1.0/software/Android.bp create mode 100644 gatekeeper/1.0/software/OWNERS create mode 100644 gatekeeper/1.0/software/SoftGateKeeper.h create mode 100644 gatekeeper/1.0/software/SoftGateKeeperDevice.cpp create mode 100644 gatekeeper/1.0/software/SoftGateKeeperDevice.h create mode 100644 gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.rc create mode 100644 gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.xml create mode 100644 gatekeeper/1.0/software/service.cpp create mode 100644 gatekeeper/1.0/software/tests/Android.bp create mode 100644 gatekeeper/1.0/software/tests/gatekeeper_test.cpp create mode 100644 gatekeeper/1.0/vts/OWNERS diff --git a/gatekeeper/1.0/default/OWNERS b/gatekeeper/1.0/default/OWNERS new file mode 100644 index 0000000000..335660da3b --- /dev/null +++ b/gatekeeper/1.0/default/OWNERS @@ -0,0 +1,2 @@ +jdanis@google.com +swillden@google.com diff --git a/gatekeeper/1.0/software/Android.bp b/gatekeeper/1.0/software/Android.bp new file mode 100644 index 0000000000..148c98938f --- /dev/null +++ b/gatekeeper/1.0/software/Android.bp @@ -0,0 +1,28 @@ +cc_binary { + name: "android.hardware.gatekeeper@1.0-service.software", + defaults: ["hidl_defaults"], + relative_install_path: "hw", + vendor: true, + init_rc: ["android.hardware.gatekeeper@1.0-service.software.rc"], + + srcs: [ + "service.cpp", + "SoftGateKeeperDevice.cpp", + ], + + shared_libs: [ + "android.hardware.gatekeeper@1.0", + "libbase", + "libhardware", + "libhidlbase", + "libhidltransport", + "libutils", + "liblog", + "libcrypto", + "libgatekeeper", + ], + + static_libs: ["libscrypt_static"], + + vintf_fragments: ["android.hardware.gatekeeper@1.0-service.software.xml"], +} diff --git a/gatekeeper/1.0/software/OWNERS b/gatekeeper/1.0/software/OWNERS new file mode 100644 index 0000000000..335660da3b --- /dev/null +++ b/gatekeeper/1.0/software/OWNERS @@ -0,0 +1,2 @@ +jdanis@google.com +swillden@google.com diff --git a/gatekeeper/1.0/software/SoftGateKeeper.h b/gatekeeper/1.0/software/SoftGateKeeper.h new file mode 100644 index 0000000000..3276d1ebbd --- /dev/null +++ b/gatekeeper/1.0/software/SoftGateKeeper.h @@ -0,0 +1,171 @@ +/* + * Copyright 2015 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 SOFT_GATEKEEPER_H_ +#define SOFT_GATEKEEPER_H_ + +extern "C" { +#include +#include + +#include +} + +#include +#include + +#include +#include +#include + +namespace gatekeeper { + +struct fast_hash_t { + uint64_t salt; + uint8_t digest[SHA256_DIGEST_LENGTH]; +}; + +class SoftGateKeeper : public GateKeeper { + public: + static const uint32_t SIGNATURE_LENGTH_BYTES = 32; + + // scrypt params + static const uint64_t N = 16384; + static const uint32_t r = 8; + static const uint32_t p = 1; + + static const int MAX_UINT_32_CHARS = 11; + + SoftGateKeeper() { + key_.reset(new uint8_t[SIGNATURE_LENGTH_BYTES]); + memset(key_.get(), 0, SIGNATURE_LENGTH_BYTES); + } + + virtual ~SoftGateKeeper() {} + + virtual bool GetAuthTokenKey(const uint8_t** auth_token_key, uint32_t* length) const { + if (auth_token_key == NULL || length == NULL) return false; + *auth_token_key = key_.get(); + *length = SIGNATURE_LENGTH_BYTES; + return true; + } + + virtual void GetPasswordKey(const uint8_t** password_key, uint32_t* length) { + if (password_key == NULL || length == NULL) return; + *password_key = key_.get(); + *length = SIGNATURE_LENGTH_BYTES; + } + + virtual void ComputePasswordSignature(uint8_t* signature, uint32_t signature_length, + const uint8_t*, uint32_t, const uint8_t* password, + uint32_t password_length, salt_t salt) const { + if (signature == NULL) return; + crypto_scrypt(password, password_length, reinterpret_cast(&salt), sizeof(salt), N, + r, p, signature, signature_length); + } + + virtual void GetRandom(void* random, uint32_t requested_length) const { + if (random == NULL) return; + RAND_pseudo_bytes((uint8_t*)random, requested_length); + } + + virtual void ComputeSignature(uint8_t* signature, uint32_t signature_length, const uint8_t*, + uint32_t, const uint8_t*, const uint32_t) const { + if (signature == NULL) return; + memset(signature, 0, signature_length); + } + + virtual uint64_t GetMillisecondsSinceBoot() const { + struct timespec time; + int res = clock_gettime(CLOCK_BOOTTIME, &time); + if (res < 0) return 0; + return (time.tv_sec * 1000) + (time.tv_nsec / 1000 / 1000); + } + + virtual bool IsHardwareBacked() const { return false; } + + virtual bool GetFailureRecord(uint32_t uid, secure_id_t user_id, failure_record_t* record, + bool /* secure */) { + failure_record_t* stored = &failure_map_[uid]; + if (user_id != stored->secure_user_id) { + stored->secure_user_id = user_id; + stored->last_checked_timestamp = 0; + stored->failure_counter = 0; + } + memcpy(record, stored, sizeof(*record)); + return true; + } + + virtual bool ClearFailureRecord(uint32_t uid, secure_id_t user_id, bool /* secure */) { + failure_record_t* stored = &failure_map_[uid]; + stored->secure_user_id = user_id; + stored->last_checked_timestamp = 0; + stored->failure_counter = 0; + return true; + } + + virtual bool WriteFailureRecord(uint32_t uid, failure_record_t* record, bool /* secure */) { + failure_map_[uid] = *record; + return true; + } + + fast_hash_t ComputeFastHash(const SizedBuffer& password, uint64_t salt) { + fast_hash_t fast_hash; + size_t digest_size = password.size() + sizeof(salt); + std::unique_ptr digest(new uint8_t[digest_size]); + memcpy(digest.get(), &salt, sizeof(salt)); + memcpy(digest.get() + sizeof(salt), password.Data(), password.size()); + + SHA256(digest.get(), digest_size, (uint8_t*)&fast_hash.digest); + + fast_hash.salt = salt; + return fast_hash; + } + + bool VerifyFast(const fast_hash_t& fast_hash, const SizedBuffer& password) { + fast_hash_t computed = ComputeFastHash(password, fast_hash.salt); + return memcmp(computed.digest, fast_hash.digest, SHA256_DIGEST_LENGTH) == 0; + } + + bool DoVerify(const password_handle_t* expected_handle, const SizedBuffer& password) { + uint64_t user_id = android::base::get_unaligned(&expected_handle->user_id); + FastHashMap::const_iterator it = fast_hash_map_.find(user_id); + if (it != fast_hash_map_.end() && VerifyFast(it->second, password)) { + return true; + } else { + if (GateKeeper::DoVerify(expected_handle, password)) { + uint64_t salt; + GetRandom(&salt, sizeof(salt)); + fast_hash_map_[user_id] = ComputeFastHash(password, salt); + return true; + } + } + + return false; + } + + private: + typedef std::unordered_map FailureRecordMap; + typedef std::unordered_map FastHashMap; + + std::unique_ptr key_; + FailureRecordMap failure_map_; + FastHashMap fast_hash_map_; +}; +} // namespace gatekeeper + +#endif // SOFT_GATEKEEPER_H_ diff --git a/gatekeeper/1.0/software/SoftGateKeeperDevice.cpp b/gatekeeper/1.0/software/SoftGateKeeperDevice.cpp new file mode 100644 index 0000000000..d7a0b46ee6 --- /dev/null +++ b/gatekeeper/1.0/software/SoftGateKeeperDevice.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2015 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 "SoftGateKeeperDevice.h" +#include "SoftGateKeeper.h" + +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::gatekeeper::V1_0::GatekeeperStatusCode; +using ::gatekeeper::EnrollRequest; +using ::gatekeeper::EnrollResponse; +using ::gatekeeper::ERROR_INVALID; +using ::gatekeeper::ERROR_MEMORY_ALLOCATION_FAILED; +using ::gatekeeper::ERROR_NONE; +using ::gatekeeper::ERROR_RETRY; +using ::gatekeeper::SizedBuffer; +using ::gatekeeper::VerifyRequest; +using ::gatekeeper::VerifyResponse; + +#include + +namespace android { + +inline SizedBuffer hidl_vec2sized_buffer(const hidl_vec& vec) { + if (vec.size() == 0 || vec.size() > std::numeric_limits::max()) return {}; + auto dummy = new uint8_t[vec.size()]; + std::copy(vec.begin(), vec.end(), dummy); + return {dummy, static_cast(vec.size())}; +} + +Return SoftGateKeeperDevice::enroll(uint32_t uid, + const hidl_vec& currentPasswordHandle, + const hidl_vec& currentPassword, + const hidl_vec& desiredPassword, + enroll_cb _hidl_cb) { + if (desiredPassword.size() == 0) { + _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}}); + return {}; + } + + EnrollRequest request(uid, hidl_vec2sized_buffer(currentPasswordHandle), + hidl_vec2sized_buffer(desiredPassword), + hidl_vec2sized_buffer(currentPassword)); + EnrollResponse response; + impl_->Enroll(request, &response); + + if (response.error == ERROR_RETRY) { + _hidl_cb({GatekeeperStatusCode::ERROR_RETRY_TIMEOUT, response.retry_timeout, {}}); + } else if (response.error != ERROR_NONE) { + _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}}); + } else { + hidl_vec new_handle(response.enrolled_password_handle.Data(), + response.enrolled_password_handle.Data() + + response.enrolled_password_handle.size()); + _hidl_cb({GatekeeperStatusCode::STATUS_OK, response.retry_timeout, new_handle}); + } + return {}; +} + +Return SoftGateKeeperDevice::verify( + uint32_t uid, uint64_t challenge, + const ::android::hardware::hidl_vec& enrolledPasswordHandle, + const ::android::hardware::hidl_vec& providedPassword, verify_cb _hidl_cb) { + if (enrolledPasswordHandle.size() == 0) { + _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}}); + return {}; + } + + VerifyRequest request(uid, challenge, hidl_vec2sized_buffer(enrolledPasswordHandle), + hidl_vec2sized_buffer(providedPassword)); + VerifyResponse response; + + impl_->Verify(request, &response); + + if (response.error == ERROR_RETRY) { + _hidl_cb({GatekeeperStatusCode::ERROR_RETRY_TIMEOUT, response.retry_timeout, {}}); + } else if (response.error != ERROR_NONE) { + _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}}); + } else { + hidl_vec auth_token( + response.auth_token.Data(), + response.auth_token.Data() + response.auth_token.size()); + + _hidl_cb({response.request_reenroll ? GatekeeperStatusCode::STATUS_REENROLL + : GatekeeperStatusCode::STATUS_OK, + response.retry_timeout, auth_token}); + } + return {}; +} + +Return SoftGateKeeperDevice::deleteUser(uint32_t /*uid*/, deleteUser_cb _hidl_cb) { + _hidl_cb({GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED, 0, {}}); + return {}; +} + +Return SoftGateKeeperDevice::deleteAllUsers(deleteAllUsers_cb _hidl_cb) { + _hidl_cb({GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED, 0, {}}); + return {}; +} + +} // namespace android diff --git a/gatekeeper/1.0/software/SoftGateKeeperDevice.h b/gatekeeper/1.0/software/SoftGateKeeperDevice.h new file mode 100644 index 0000000000..17b474e4aa --- /dev/null +++ b/gatekeeper/1.0/software/SoftGateKeeperDevice.h @@ -0,0 +1,80 @@ +/* + * Copyright 2015 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 SOFT_GATEKEEPER_DEVICE_H_ +#define SOFT_GATEKEEPER_DEVICE_H_ + +#include +#include + +#include +#include "SoftGateKeeper.h" + +namespace android { + +/** + * Software based GateKeeper implementation + */ +class SoftGateKeeperDevice : public ::android::hardware::gatekeeper::V1_0::IGatekeeper { + public: + SoftGateKeeperDevice() { impl_.reset(new ::gatekeeper::SoftGateKeeper()); } + + // Wrappers to translate the gatekeeper HAL API to the Kegyuard Messages API. + + /** + * Enrolls password_payload, which should be derived from a user selected pin or password, + * with the authentication factor private key used only for enrolling authentication + * factor data. + * + * Returns: 0 on success or an error code less than 0 on error. + * On error, enrolled_password_handle will not be allocated. + */ + ::android::hardware::Return enroll( + uint32_t uid, const ::android::hardware::hidl_vec& currentPasswordHandle, + const ::android::hardware::hidl_vec& currentPassword, + const ::android::hardware::hidl_vec& desiredPassword, + enroll_cb _hidl_cb) override; + + /** + * Verifies provided_password matches enrolled_password_handle. + * + * Implementations of this module may retain the result of this call + * to attest to the recency of authentication. + * + * On success, writes the address of a verification token to auth_token, + * usable to attest password verification to other trusted services. Clients + * may pass NULL for this value. + * + * Returns: 0 on success or an error code less than 0 on error + * On error, verification token will not be allocated + */ + ::android::hardware::Return verify( + uint32_t uid, uint64_t challenge, + const ::android::hardware::hidl_vec& enrolledPasswordHandle, + const ::android::hardware::hidl_vec& providedPassword, + verify_cb _hidl_cb) override; + + ::android::hardware::Return deleteUser(uint32_t uid, deleteUser_cb _hidl_cb) override; + + ::android::hardware::Return deleteAllUsers(deleteAllUsers_cb _hidl_cb) override; + + private: + std::unique_ptr<::gatekeeper::SoftGateKeeper> impl_; +}; + +} // namespace android + +#endif // SOFT_GATEKEEPER_DEVICE_H_ diff --git a/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.rc b/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.rc new file mode 100644 index 0000000000..60cb96c915 --- /dev/null +++ b/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.rc @@ -0,0 +1,4 @@ +service vendor.gatekeeper-1-0 /vendor/bin/hw/android.hardware.gatekeeper@1.0-service.software + class hal + user system + group system diff --git a/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.xml b/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.xml new file mode 100644 index 0000000000..19714a83b7 --- /dev/null +++ b/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.xml @@ -0,0 +1,11 @@ + + + android.hardware.gatekeeper + hwbinder + 1.0 + + IGatekeeper + default + + + diff --git a/gatekeeper/1.0/software/service.cpp b/gatekeeper/1.0/software/service.cpp new file mode 100644 index 0000000000..a48a964c08 --- /dev/null +++ b/gatekeeper/1.0/software/service.cpp @@ -0,0 +1,39 @@ +/* + * 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 "android.hardware.gatekeeper@1.0-service" + +#include +#include + +#include + +#include "SoftGateKeeperDevice.h" + +// Generated HIDL files +using android::SoftGateKeeperDevice; +using android::hardware::gatekeeper::V1_0::IGatekeeper; + +int main() { + ::android::hardware::configureRpcThreadpool(1, true /* willJoinThreadpool */); + android::sp gatekeeper(new SoftGateKeeperDevice()); + auto status = gatekeeper->registerAsService(); + if (status != android::OK) { + LOG(FATAL) << "Could not register service for Gatekeeper 1.0 (software) (" << status << ")"; + } + + android::hardware::joinRpcThreadpool(); + return -1; // Should never get here. +} diff --git a/gatekeeper/1.0/software/tests/Android.bp b/gatekeeper/1.0/software/tests/Android.bp new file mode 100644 index 0000000000..3f0300dc18 --- /dev/null +++ b/gatekeeper/1.0/software/tests/Android.bp @@ -0,0 +1,34 @@ +// +// Copyright (C) 2015 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. +// + +cc_test { + name: "gatekeeper-software-device-unit-tests", + + cflags: [ + "-g", + "-Wall", + "-Werror", + "-Wno-missing-field-initializers", + ], + shared_libs: [ + "libgatekeeper", + "libcrypto", + "libbase", + ], + static_libs: ["libscrypt_static"], + + srcs: ["gatekeeper_test.cpp"], +} diff --git a/gatekeeper/1.0/software/tests/gatekeeper_test.cpp b/gatekeeper/1.0/software/tests/gatekeeper_test.cpp new file mode 100644 index 0000000000..bf4a8bc5fa --- /dev/null +++ b/gatekeeper/1.0/software/tests/gatekeeper_test.cpp @@ -0,0 +1,178 @@ +/* + * Copyright 2015 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 + +#include +#include + +#include "../SoftGateKeeper.h" + +using ::gatekeeper::EnrollRequest; +using ::gatekeeper::EnrollResponse; +using ::gatekeeper::secure_id_t; +using ::gatekeeper::SizedBuffer; +using ::gatekeeper::SoftGateKeeper; +using ::gatekeeper::VerifyRequest; +using ::gatekeeper::VerifyResponse; +using ::testing::Test; + +static SizedBuffer makePasswordBuffer(int init = 0) { + constexpr const uint32_t pw_buffer_size = 16; + auto pw_buffer = new uint8_t[pw_buffer_size]; + memset(pw_buffer, init, pw_buffer_size); + + return {pw_buffer, pw_buffer_size}; +} + +static SizedBuffer makeAndInitializeSizedBuffer(const uint8_t* data, uint32_t size) { + auto buffer = new uint8_t[size]; + memcpy(buffer, data, size); + return {buffer, size}; +} + +static SizedBuffer copySizedBuffer(const SizedBuffer& rhs) { + return makeAndInitializeSizedBuffer(rhs.Data(), rhs.size()); +} + +static void do_enroll(SoftGateKeeper& gatekeeper, EnrollResponse* response) { + EnrollRequest request(0, {}, makePasswordBuffer(), {}); + + gatekeeper.Enroll(request, response); +} + +TEST(GateKeeperTest, EnrollSuccess) { + SoftGateKeeper gatekeeper; + EnrollResponse response; + do_enroll(gatekeeper, &response); + ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error); +} + +TEST(GateKeeperTest, EnrollBogusData) { + SoftGateKeeper gatekeeper; + EnrollResponse response; + + EnrollRequest request(0, {}, {}, {}); + + gatekeeper.Enroll(request, &response); + + ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_INVALID, response.error); +} + +TEST(GateKeeperTest, VerifySuccess) { + SoftGateKeeper gatekeeper; + EnrollResponse enroll_response; + + do_enroll(gatekeeper, &enroll_response); + ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error); + VerifyRequest request(0, 1, std::move(enroll_response.enrolled_password_handle), + makePasswordBuffer()); + VerifyResponse response; + + gatekeeper.Verify(request, &response); + + ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error); + + auto auth_token = response.auth_token.Data(); + + ASSERT_NE(nullptr, auth_token); + ASSERT_EQ((uint32_t)HW_AUTH_PASSWORD, ntohl(auth_token->authenticator_type)); + ASSERT_EQ((uint64_t)1, auth_token->challenge); + ASSERT_NE(~((uint32_t)0), auth_token->timestamp); + ASSERT_NE((uint64_t)0, auth_token->user_id); + ASSERT_NE((uint64_t)0, auth_token->authenticator_id); +} + +TEST(GateKeeperTest, TrustedReEnroll) { + SoftGateKeeper gatekeeper; + EnrollResponse enroll_response; + + // do_enroll enrolls an all 0 password + do_enroll(gatekeeper, &enroll_response); + ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error); + + // verify first password + VerifyRequest request(0, 0, copySizedBuffer(enroll_response.enrolled_password_handle), + makePasswordBuffer()); + VerifyResponse response; + gatekeeper.Verify(request, &response); + ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error); + auto auth_token = response.auth_token.Data(); + ASSERT_NE(nullptr, auth_token); + + secure_id_t secure_id = auth_token->user_id; + + // enroll new password + EnrollRequest enroll_request(0, std::move(enroll_response.enrolled_password_handle), + makePasswordBuffer(1) /* new password */, + makePasswordBuffer() /* old password */); + gatekeeper.Enroll(enroll_request, &enroll_response); + ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error); + + // verify new password + VerifyRequest new_request(0, 0, std::move(enroll_response.enrolled_password_handle), + makePasswordBuffer(1)); + gatekeeper.Verify(new_request, &response); + ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error); + ASSERT_NE(nullptr, response.auth_token.Data()); + ASSERT_EQ(secure_id, response.auth_token.Data()->user_id); +} + +TEST(GateKeeperTest, UntrustedReEnroll) { + SoftGateKeeper gatekeeper; + SizedBuffer provided_password; + EnrollResponse enroll_response; + + // do_enroll enrolls an all 0 password + provided_password = makePasswordBuffer(); + do_enroll(gatekeeper, &enroll_response); + ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error); + + // verify first password + VerifyRequest request(0, 0, std::move(enroll_response.enrolled_password_handle), + std::move(provided_password)); + VerifyResponse response; + gatekeeper.Verify(request, &response); + ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error); + auto auth_token = response.auth_token.Data(); + ASSERT_NE(nullptr, auth_token); + + secure_id_t secure_id = auth_token->user_id; + + EnrollRequest enroll_request(0, {}, makePasswordBuffer(1), {}); + gatekeeper.Enroll(enroll_request, &enroll_response); + ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error); + + // verify new password + VerifyRequest new_request(0, 0, std::move(enroll_response.enrolled_password_handle), + makePasswordBuffer(1)); + gatekeeper.Verify(new_request, &response); + ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error); + ASSERT_NE(nullptr, response.auth_token.Data()); + ASSERT_NE(secure_id, response.auth_token.Data()->user_id); +} + +TEST(GateKeeperTest, VerifyBogusData) { + SoftGateKeeper gatekeeper; + VerifyResponse response; + + VerifyRequest request(0, 0, {}, {}); + + gatekeeper.Verify(request, &response); + + ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_INVALID, response.error); +} diff --git a/gatekeeper/1.0/vts/OWNERS b/gatekeeper/1.0/vts/OWNERS new file mode 100644 index 0000000000..738c71025a --- /dev/null +++ b/gatekeeper/1.0/vts/OWNERS @@ -0,0 +1,3 @@ +jdanis@google.com +swillden@google.com +guangzhu@google.com From f69d8bc9c5f965b4c277c51992e4e9244b200871 Mon Sep 17 00:00:00 2001 From: Janis Danisevskis Date: Wed, 12 Jun 2019 13:30:03 -0700 Subject: [PATCH 0015/1022] Keymaster memory management is inconsistent Object derived from RefBase must be owned by sp rather then other smart pointer implementations. Bug: 79474587 Change-Id: I866f67e1cb091efb3026450d50a410b5985539b6 --- keymaster/4.0/support/Keymaster.cpp | 7 +++---- keymaster/4.0/support/include/keymasterV4_0/Keymaster.h | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/keymaster/4.0/support/Keymaster.cpp b/keymaster/4.0/support/Keymaster.cpp index 1eb9a68547..f20f9511fc 100644 --- a/keymaster/4.0/support/Keymaster.cpp +++ b/keymaster/4.0/support/Keymaster.cpp @@ -80,8 +80,7 @@ std::ostream& operator<<(std::ostream& os, const Keymaster& keymaster) { } template -std::vector> enumerateDevices( - const sp& serviceManager) { +Keymaster::KeymasterSet enumerateDevices(const sp& serviceManager) { Keymaster::KeymasterSet result; bool foundDefault = false; @@ -92,7 +91,7 @@ std::vector> enumerateDevices( auto device = Wrapper::WrappedIKeymasterDevice::getService(name); CHECK(device) << "Failed to get service for " << descriptor << " with interface name " << name; - result.push_back(std::unique_ptr(new Wrapper(device, name))); + result.push_back(new Wrapper(device, name)); } }); @@ -100,7 +99,7 @@ std::vector> enumerateDevices( // "default" wasn't provided by listManifestByInterface. Maybe there's a passthrough // implementation. auto device = Wrapper::WrappedIKeymasterDevice::getService("default"); - if (device) result.push_back(std::unique_ptr(new Wrapper(device, "default"))); + if (device) result.push_back(new Wrapper(device, "default")); } return result; diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h index 43a34b055b..ad83f17106 100644 --- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h +++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h @@ -39,8 +39,8 @@ namespace support { * while still having to use only the latest interface. */ class Keymaster : public IKeymasterDevice { - public: - using KeymasterSet = std::vector>; + public: + using KeymasterSet = std::vector>; Keymaster(const hidl_string& descriptor, const hidl_string& instanceName) : descriptor_(descriptor), instanceName_(instanceName) {} @@ -86,7 +86,7 @@ class Keymaster : public IKeymasterDevice { */ static void performHmacKeyAgreement(const KeymasterSet& keymasters); - private: + private: hidl_string descriptor_; hidl_string instanceName_; }; From c1dc31340e8f8d5e5f0eb49d0903dd6b380548d7 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Thu, 13 Jun 2019 09:49:44 -0700 Subject: [PATCH 0016/1022] Adding support for different Mapper versions in IComposer VTS tests Bug: 135139498 Test: build, boot, VtsHalGraphicsComposerV2_<1,2,3>TargetTest, Change-Id: I05e2832c64d4c06eb4afd64c3323d7edbd19a5f4 --- graphics/composer/2.1/utils/vts/Android.bp | 2 + .../composer/2.1/utils/vts/ComposerVts.cpp | 71 +++++++++++++++ .../include/composer-vts/2.1/ComposerVts.h | 36 ++++++++ .../composer/2.1/vts/functional/Android.bp | 3 + .../VtsHalGraphicsComposerV2_1TargetTest.cpp | 20 ++--- graphics/composer/2.2/utils/vts/Android.bp | 2 + .../composer/2.2/utils/vts/ComposerVts.cpp | 42 +++++++++ .../composer/2.2/utils/vts/ReadbackVts.cpp | 48 ++++++----- .../include/composer-vts/2.2/ComposerVts.h | 26 ++++++ .../include/composer-vts/2.2/ReadbackVts.h | 21 +++-- .../composer/2.2/vts/functional/Android.bp | 3 + ...VtsHalGraphicsComposerV2_2ReadbackTest.cpp | 75 +++++++--------- .../VtsHalGraphicsComposerV2_2TargetTest.cpp | 36 +++----- graphics/composer/2.3/utils/vts/Android.bp | 6 ++ .../composer/2.3/vts/functional/Android.bp | 4 + .../VtsHalGraphicsComposerV2_3TargetTest.cpp | 14 +-- graphics/mapper/2.1/utils/vts/MapperVts.cpp | 13 +-- .../vts/include/mapper-vts/2.1/MapperVts.h | 25 +++--- graphics/mapper/3.0/utils/vts/MapperVts.cpp | 19 +++- .../vts/include/mapper-vts/3.0/MapperVts.h | 86 ++++++++++--------- 20 files changed, 371 insertions(+), 181 deletions(-) diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp index 846cfdf355..fcb327f365 100644 --- a/graphics/composer/2.1/utils/vts/Android.bp +++ b/graphics/composer/2.1/utils/vts/Android.bp @@ -25,6 +25,8 @@ cc_library_static { static_libs: [ "VtsHalHidlTargetTestBase", "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.mapper@2.0-vts", + "android.hardware.graphics.mapper@3.0-vts", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp index 7ba67d45b5..c5d5823398 100644 --- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp @@ -315,6 +315,77 @@ void ComposerClient::execute(TestCommandReader* reader, CommandWriterBase* write writer->reset(); } +Gralloc::Gralloc() { + [this] { + ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared("default", "default", + /*errOnFailure=*/false)); + if (mGralloc3->getAllocator() == nullptr || mGralloc3->getMapper() == nullptr) { + mGralloc3 = nullptr; + ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared()); + } + }(); +} + +const native_handle_t* Gralloc::allocate(uint32_t width, uint32_t height, uint32_t layerCount, + PixelFormat format, uint64_t usage, bool import, + uint32_t* outStride) { + if (mGralloc3) { + IMapper3::BufferDescriptorInfo info{}; + info.width = width; + info.height = height; + info.layerCount = layerCount; + info.format = static_cast(format); + info.usage = usage; + return mGralloc3->allocate(info, import, outStride); + } else { + IMapper2::BufferDescriptorInfo info{}; + info.width = width; + info.height = height; + info.layerCount = layerCount; + info.format = format; + info.usage = usage; + return mGralloc2->allocate(info, import, outStride); + } +} + +void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, + const AccessRegion& accessRegionRect, int acquireFence) { + if (mGralloc3) { + IMapper3::Rect accessRegion; + accessRegion.left = accessRegionRect.left; + accessRegion.top = accessRegionRect.top; + accessRegion.width = accessRegionRect.width; + accessRegion.height = accessRegionRect.height; + int32_t bytesPerPixel; + int32_t bytesPerStride; + return mGralloc3->lock(bufferHandle, cpuUsage, accessRegion, acquireFence, &bytesPerPixel, + &bytesPerStride); + } else { + IMapper2::Rect accessRegion; + accessRegion.left = accessRegionRect.left; + accessRegion.top = accessRegionRect.top; + accessRegion.width = accessRegionRect.width; + accessRegion.height = accessRegionRect.height; + return mGralloc2->lock(bufferHandle, cpuUsage, accessRegion, acquireFence); + } +} + +int Gralloc::unlock(const native_handle_t* bufferHandle) { + if (mGralloc3) { + return mGralloc3->unlock(bufferHandle); + } else { + return mGralloc2->unlock(bufferHandle); + } +} + +void Gralloc::freeBuffer(const native_handle_t* bufferHandle) { + if (mGralloc3) { + mGralloc3->freeBuffer(bufferHandle); + } else { + mGralloc2->freeBuffer(bufferHandle); + } +} + } // namespace vts } // namespace V2_1 } // namespace composer diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h index c97be76d9a..7811048270 100644 --- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h +++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h @@ -25,8 +25,12 @@ #include #include #include +#include +#include #include +#include "gtest/gtest.h" + namespace android { namespace hardware { namespace graphics { @@ -38,6 +42,10 @@ using android::hardware::graphics::common::V1_0::ColorMode; using android::hardware::graphics::common::V1_0::Dataspace; using android::hardware::graphics::common::V1_0::Hdr; using android::hardware::graphics::common::V1_0::PixelFormat; +using IMapper2 = android::hardware::graphics::mapper::V2_0::IMapper; +using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper; +using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc; +using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc; class ComposerClient; @@ -119,6 +127,34 @@ class ComposerClient { const sp mClient; }; +class AccessRegion { + public: + int32_t left; + int32_t top; + int32_t width; + int32_t height; +}; + +class Gralloc { + public: + explicit Gralloc(); + + const native_handle_t* allocate(uint32_t width, uint32_t height, uint32_t layerCount, + PixelFormat format, uint64_t usage, bool import = true, + uint32_t* outStride = nullptr); + + void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, + const AccessRegion& accessRegionRect, int acquireFence); + + int unlock(const native_handle_t* bufferHandle); + + void freeBuffer(const native_handle_t* bufferHandle); + + protected: + std::shared_ptr mGralloc2 = nullptr; + std::shared_ptr mGralloc3 = nullptr; +}; + } // namespace vts } // namespace V2_1 } // namespace composer diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp index c98cc0deb8..d54da60f6d 100644 --- a/graphics/composer/2.1/vts/functional/Android.bp +++ b/graphics/composer/2.1/vts/functional/Android.bp @@ -26,10 +26,13 @@ cc_test { ], static_libs: [ "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.allocator@3.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@3.0", + "android.hardware.graphics.mapper@3.0-vts", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp index 3c408b7d7b..30b96949dc 100644 --- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp +++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -47,8 +48,6 @@ using android::hardware::graphics::common::V1_0::ColorTransform; using android::hardware::graphics::common::V1_0::Dataspace; using android::hardware::graphics::common::V1_0::PixelFormat; using android::hardware::graphics::common::V1_0::Transform; -using android::hardware::graphics::mapper::V2_0::IMapper; -using android::hardware::graphics::mapper::V2_0::vts::Gralloc; using GrallocError = android::hardware::graphics::mapper::V2_0::Error; // Test environment for graphics.composer @@ -669,7 +668,6 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp()); ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique()); - Config activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay); mDisplayWidth = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig, IComposerClient::Attribute::WIDTH); @@ -685,16 +683,10 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { } const native_handle_t* allocate() { - IMapper::BufferDescriptorInfo info{}; - info.width = mDisplayWidth; - info.height = mDisplayHeight; - info.layerCount = 1; - info.format = PixelFormat::RGBA_8888; - info.usage = - static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN | - BufferUsage::COMPOSER_OVERLAY); - - return mGralloc->allocate(info); + uint64_t usage = + static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN | + BufferUsage::COMPOSER_OVERLAY); + return mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, usage); } void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } @@ -705,7 +697,7 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { int32_t mDisplayHeight; private: - std::unique_ptr mGralloc; + std::unique_ptr mGralloc; }; /** diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp index 4016120143..56b12f5093 100644 --- a/graphics/composer/2.2/utils/vts/Android.bp +++ b/graphics/composer/2.2/utils/vts/Android.bp @@ -28,6 +28,8 @@ cc_library_static { "android.hardware.graphics.composer@2.2", "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", ], export_static_lib_headers: [ "android.hardware.graphics.composer@2.1-vts", diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp index da994606bb..a380fc040d 100644 --- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp @@ -180,6 +180,48 @@ std::array ComposerClient::getDataspaceSaturationMatrix(Dataspace dat return matrix; } +Gralloc::Gralloc() { + [this] { + ALOGD("Attempting to initialize gralloc3"); + ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared("default", "default", + /*errOnFailure=*/false)); + if (mGralloc3->getMapper() == nullptr || mGralloc3->getAllocator() == nullptr) { + mGralloc3 = nullptr; + ALOGD("Failed to initialize gralloc3, initializing gralloc2_1"); + mGralloc2_1 = std::make_shared(/*errOnFailure*/ false); + if (!mGralloc2_1->getMapper()) { + mGralloc2_1 = nullptr; + ALOGD("Failed to initialize gralloc2_1, initializing gralloc2"); + ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared()); + } + } + }(); +} + +bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle, uint32_t width, + uint32_t height, uint32_t layerCount, PixelFormat format, + uint64_t usage, uint32_t stride) { + if (mGralloc3) { + IMapper3::BufferDescriptorInfo info{}; + info.width = width; + info.height = height; + info.layerCount = layerCount; + info.format = static_cast(format); + info.usage = usage; + return mGralloc3->validateBufferSize(bufferHandle, info, stride); + } else if (mGralloc2_1) { + IMapper2_1::BufferDescriptorInfo info{}; + info.width = width; + info.height = height; + info.layerCount = layerCount; + info.format = static_cast(format); + info.usage = usage; + return mGralloc2_1->validateBufferSize(bufferHandle, info, stride); + } else { + return true; + } +} + } // namespace vts } // namespace V2_2 } // namespace composer diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp index 8eabaef5e3..81a6452948 100644 --- a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp +++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp @@ -116,11 +116,11 @@ ReadbackBuffer::ReadbackBuffer(Display display, const std::shared_ptr(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE); + mWidth = width; + mHeight = height; + mLayerCount = 1; + mFormat = mPixelFormat; + mUsage = static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE); mAccessRegion.top = 0; mAccessRegion.left = 0; @@ -139,8 +139,10 @@ void ReadbackBuffer::setReadbackBuffer() { mGralloc->freeBuffer(mBufferHandle); mBufferHandle = nullptr; } - mBufferHandle = mGralloc->allocate(mInfo, /*import*/ true, &mStride); - ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mInfo, mStride)); + mBufferHandle = mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage, + /*import*/ true, &mStride); + ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mWidth, mHeight, mLayerCount, + mFormat, mUsage, mStride)); ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle, -1)); } @@ -149,13 +151,13 @@ void ReadbackBuffer::checkReadbackBuffer(std::vector exp int32_t fenceHandle; ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle)); - void* bufData = mGralloc->lock(mBufferHandle, mInfo.usage, mAccessRegion, fenceHandle); + void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, fenceHandle); ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888); int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(mPixelFormat); ASSERT_NE(-1, bytesPerPixel); - for (int row = 0; row < mInfo.height; row++) { - for (int col = 0; col < mInfo.width; col++) { - int pixel = row * mInfo.width + col; + for (int row = 0; row < mHeight; row++) { + for (int col = 0; col < mWidth; col++) { + int pixel = row * mWidth + col; int offset = (row * mStride + col) * bytesPerPixel; uint8_t* pixelColor = (uint8_t*)bufData + offset; @@ -184,12 +186,12 @@ TestBufferLayer::TestBufferLayer(const std::shared_ptr& client, : TestLayer{client, display} { mGralloc = gralloc; mComposition = composition; - mInfo.width = width; - mInfo.height = height; - mInfo.layerCount = 1; - mInfo.format = format; - mInfo.usage = static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | - BufferUsage::COMPOSER_OVERLAY); + mWidth = width; + mHeight = height; + mLayerCount = 1; + mFormat = format; + mUsage = static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY); mAccessRegion.top = 0; mAccessRegion.left = 0; @@ -214,9 +216,9 @@ void TestBufferLayer::write(const std::shared_ptr& writer) { } void TestBufferLayer::fillBuffer(std::vector expectedColors) { - void* bufData = mGralloc->lock(mBufferHandle, mInfo.usage, mAccessRegion, -1); - ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mInfo.width, mInfo.height, mStride, bufData, - mInfo.format, expectedColors)); + void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, -1); + ASSERT_NO_FATAL_FAILURE( + ReadbackHelper::fillBuffer(mWidth, mHeight, mStride, bufData, mFormat, expectedColors)); mFillFence = mGralloc->unlock(mBufferHandle); if (mFillFence != -1) { sync_wait(mFillFence, -1); @@ -228,10 +230,12 @@ void TestBufferLayer::setBuffer(std::vector colors) { mGralloc->freeBuffer(mBufferHandle); mBufferHandle = nullptr; } - mBufferHandle = mGralloc->allocate(mInfo, /*import*/ true, &mStride); + mBufferHandle = mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage, + /*import*/ true, &mStride); ASSERT_NE(nullptr, mBufferHandle); ASSERT_NO_FATAL_FAILURE(fillBuffer(colors)); - ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mInfo, mStride)); + ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mWidth, mHeight, mLayerCount, + mFormat, mUsage, mStride)); } void TestBufferLayer::setToClientComposition(const std::shared_ptr& writer) { diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h index 263302124f..8fa9b7b3fe 100644 --- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h +++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h @@ -27,6 +27,7 @@ #include #include #include +#include #include namespace android { @@ -41,6 +42,11 @@ using common::V1_1::ColorMode; using common::V1_1::Dataspace; using common::V1_1::PixelFormat; using common::V1_1::RenderIntent; +using IMapper2_1 = android::hardware::graphics::mapper::V2_1::IMapper; +using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper; +using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc; +using Gralloc2_1 = android::hardware::graphics::mapper::V2_1::vts::Gralloc; +using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc; class ComposerClient; @@ -84,6 +90,26 @@ class ComposerClient : public V2_1::vts::ComposerClient { const sp mClient; }; +class Gralloc : public V2_1::vts::Gralloc { + public: + Gralloc(); + const native_handle_t* allocate(uint32_t width, uint32_t height, uint32_t layerCount, + PixelFormat format, uint64_t usage, bool import = true, + uint32_t* outStride = nullptr) { + return V2_1::vts::Gralloc::allocate( + width, height, layerCount, + static_cast(format), usage, + import, outStride); + } + + bool validateBufferSize(const native_handle_t* bufferHandle, uint32_t width, uint32_t height, + uint32_t layerCount, PixelFormat format, uint64_t usage, + uint32_t stride); + + protected: + std::shared_ptr mGralloc2_1 = nullptr; +}; + } // namespace vts } // namespace V2_2 } // namespace composer diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h index 9ce4e39b51..7e931676ff 100644 --- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h +++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h @@ -33,10 +33,11 @@ using android::hardware::hidl_handle; using common::V1_1::BufferUsage; using common::V1_1::Dataspace; using common::V1_1::PixelFormat; -using mapper::V2_1::IMapper; -using mapper::V2_1::vts::Gralloc; +using IMapper2_1 = mapper::V2_1::IMapper; +using Gralloc2_1 = mapper::V2_1::vts::Gralloc; using V2_1::Display; using V2_1::Layer; +using V2_1::vts::AccessRegion; using V2_1::vts::TestCommandReader; static const IComposerClient::Color BLACK = {0, 0, 0, 0xff}; @@ -115,8 +116,12 @@ class TestBufferLayer : public TestLayer { void setToClientComposition(const std::shared_ptr& writer); - IMapper::BufferDescriptorInfo mInfo; - IMapper::Rect mAccessRegion; + uint32_t mWidth; + uint32_t mHeight; + uint32_t mLayerCount; + PixelFormat mFormat; + uint64_t mUsage; + AccessRegion mAccessRegion; uint32_t mStride; protected: @@ -156,8 +161,12 @@ class ReadbackBuffer { void checkReadbackBuffer(std::vector expectedColors); protected: - IMapper::BufferDescriptorInfo mInfo; - IMapper::Rect mAccessRegion; + uint32_t mWidth; + uint32_t mHeight; + uint32_t mLayerCount; + PixelFormat mFormat; + uint64_t mUsage; + AccessRegion mAccessRegion; uint32_t mStride; const native_handle_t* mBufferHandle = nullptr; PixelFormat mPixelFormat; diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp index b62f3021b9..13e03c61d9 100644 --- a/graphics/composer/2.2/vts/functional/Android.bp +++ b/graphics/composer/2.2/vts/functional/Android.bp @@ -30,6 +30,7 @@ cc_test { ], static_libs: [ "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.allocator@3.0", "android.hardware.graphics.common@1.1", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.1-vts", @@ -39,6 +40,8 @@ cc_test { "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", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp index 2534196522..eef0433b42 100644 --- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp @@ -36,7 +36,6 @@ using common::V1_1::BufferUsage; using common::V1_1::Dataspace; using common::V1_1::PixelFormat; using mapper::V2_1::IMapper; -using mapper::V2_1::vts::Gralloc; using V2_1::Display; using V2_1::Layer; using V2_1::vts::TestCommandReader; @@ -269,14 +268,11 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerBufferNoEffect) { layer->write(mWriter); // This following buffer call should have no effect - IMapper::BufferDescriptorInfo bufferInfo{}; - bufferInfo.width = mDisplayWidth; - bufferInfo.height = mDisplayHeight; - bufferInfo.layerCount = 1; - bufferInfo.format = PixelFormat::RGBA_8888; - bufferInfo.usage = - static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN); - const native_handle_t* bufferHandle = mGralloc->allocate(bufferInfo); + PixelFormat format = PixelFormat::RGBA_8888; + uint64_t usage = + static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN); + const native_handle_t* bufferHandle = + mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, format, usage); mWriter->setLayerBuffer(0, bufferHandle, -1); // expected color for each pixel @@ -345,24 +341,21 @@ TEST_F(GraphicsComposerReadbackTest, ClientComposition) { // create client target buffer uint32_t clientStride; - IMapper::BufferDescriptorInfo clientInfo; - clientInfo.width = layer->mInfo.width; - clientInfo.height = layer->mInfo.height; - clientInfo.layerCount = layer->mInfo.layerCount; - clientInfo.format = PixelFormat::RGBA_8888; - clientInfo.usage = - static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | - BufferUsage::COMPOSER_CLIENT_TARGET); + PixelFormat clientFormat = PixelFormat::RGBA_8888; + uint64_t clientUsage = + static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_CLIENT_TARGET); const native_handle_t* clientBufferHandle = - mGralloc->allocate(clientInfo, /*import*/ true, &clientStride); + mGralloc->allocate(layer->mWidth, layer->mHeight, layer->mLayerCount, clientFormat, + clientUsage, /*import*/ true, &clientStride); ASSERT_NE(nullptr, clientBufferHandle); void* clientBufData = - mGralloc->lock(clientBufferHandle, clientInfo.usage, layer->mAccessRegion, -1); + mGralloc->lock(clientBufferHandle, clientUsage, layer->mAccessRegion, -1); - ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(clientInfo.width, clientInfo.height, + ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(layer->mWidth, layer->mHeight, clientStride, clientBufData, - clientInfo.format, expectedColors)); + clientFormat, expectedColors)); int clientFence = mGralloc->unlock(clientBufferHandle); if (clientFence != -1) { sync_wait(clientFence, -1); @@ -411,14 +404,13 @@ TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) { auto deviceLayer = std::make_shared(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, mDisplayHeight / 2, PixelFormat::RGBA_8888); - std::vector deviceColors(deviceLayer->mInfo.width * - deviceLayer->mInfo.height); - ReadbackHelper::fillColorsArea(deviceColors, deviceLayer->mInfo.width, - {0, 0, static_cast(deviceLayer->mInfo.width), - static_cast(deviceLayer->mInfo.height)}, + std::vector deviceColors(deviceLayer->mWidth * deviceLayer->mHeight); + ReadbackHelper::fillColorsArea(deviceColors, deviceLayer->mWidth, + {0, 0, static_cast(deviceLayer->mWidth), + static_cast(deviceLayer->mHeight)}, GREEN); - deviceLayer->setDisplayFrame({0, 0, static_cast(deviceLayer->mInfo.width), - static_cast(deviceLayer->mInfo.height)}); + deviceLayer->setDisplayFrame({0, 0, static_cast(deviceLayer->mWidth), + static_cast(deviceLayer->mHeight)}); deviceLayer->setZOrder(10); ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors)); deviceLayer->write(mWriter); @@ -433,30 +425,25 @@ TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) { execute(); ASSERT_EQ(0, mReader->mErrors.size()); - IMapper::BufferDescriptorInfo clientInfo; - clientInfo.width = mDisplayWidth; - clientInfo.height = mDisplayHeight; - clientInfo.layerCount = 1; - clientInfo.format = PixelFormat::RGBA_8888; - clientInfo.usage = - static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | - BufferUsage::COMPOSER_CLIENT_TARGET); - + uint64_t clientUsage = + static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_CLIENT_TARGET); uint32_t clientStride; const native_handle_t* clientBufferHandle = - mGralloc->allocate(clientInfo, /*import*/ true, &clientStride); + mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, + clientUsage, /*import*/ true, &clientStride); ASSERT_NE(nullptr, clientBufferHandle); - IMapper::Rect clientAccessRegion; + AccessRegion clientAccessRegion; clientAccessRegion.left = 0; clientAccessRegion.top = 0; clientAccessRegion.width = mDisplayWidth; clientAccessRegion.height = mDisplayHeight; - void* clientData = mGralloc->lock(clientBufferHandle, clientInfo.usage, clientAccessRegion, -1); - std::vector clientColors(clientInfo.width * clientInfo.height); - ReadbackHelper::fillColorsArea(clientColors, clientInfo.width, clientFrame, RED); - ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(clientInfo.width, clientInfo.height, - clientStride, clientData, clientInfo.format, + void* clientData = mGralloc->lock(clientBufferHandle, clientUsage, clientAccessRegion, -1); + std::vector clientColors(mDisplayWidth * mDisplayHeight); + ReadbackHelper::fillColorsArea(clientColors, mDisplayWidth, clientFrame, RED); + ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mDisplayWidth, mDisplayHeight, clientStride, + clientData, PixelFormat::RGBA_8888, clientColors)); int clientFence = mGralloc->unlock(clientBufferHandle); if (clientFence != -1) { diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp index 9c80f4da5e..51832f9f4c 100644 --- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp @@ -40,7 +40,6 @@ using common::V1_1::Dataspace; using common::V1_1::PixelFormat; using common::V1_1::RenderIntent; using mapper::V2_0::IMapper; -using mapper::V2_0::vts::Gralloc; // Test environment for graphics.composer class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { @@ -171,15 +170,10 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { } const native_handle_t* allocate() { - IMapper::BufferDescriptorInfo info{}; - info.width = 64; - info.height = 64; - info.layerCount = 1; - info.format = static_cast(PixelFormat::RGBA_8888); - info.usage = - static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); - - return mGralloc->allocate(info); + uint64_t usage = + static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); + return mGralloc->allocate(/*width*/ 64, /*height*/ 64, /*layerCount*/ 1, + PixelFormat::RGBA_8888, usage); } void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } @@ -456,18 +450,15 @@ TEST_F(GraphicsComposerHidlTest, SetReadbackBuffer) { return; } - IMapper::BufferDescriptorInfo info{}; - info.width = mDisplayWidth; - info.height = mDisplayHeight; - info.layerCount = 1; - info.format = static_cast(mReadbackPixelFormat); // BufferUsage::COMPOSER_OUTPUT is missing - info.usage = static_cast(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN); + uint64_t usage = + static_cast(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN); std::unique_ptr gralloc; const native_handle_t* buffer; ASSERT_NO_FATAL_FAILURE(gralloc = std::make_unique()); - ASSERT_NO_FATAL_FAILURE(buffer = gralloc->allocate(info)); + ASSERT_NO_FATAL_FAILURE(buffer = gralloc->allocate(mDisplayWidth, mDisplayHeight, 1, + mReadbackPixelFormat, usage)); mComposerClient->setReadbackBuffer(mPrimaryDisplay, buffer, -1); } @@ -483,17 +474,14 @@ TEST_F(GraphicsComposerHidlTest, SetReadbackBufferBadDisplay) { return; } - IMapper::BufferDescriptorInfo info{}; - info.width = mDisplayWidth; - info.height = mDisplayHeight; - info.layerCount = 1; - info.format = static_cast(mReadbackPixelFormat); - info.usage = static_cast(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN); + uint64_t usage = + static_cast(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN); std::unique_ptr gralloc; const native_handle_t* buffer; ASSERT_NO_FATAL_FAILURE(gralloc = std::make_unique()); - ASSERT_NO_FATAL_FAILURE(buffer = gralloc->allocate(info)); + ASSERT_NO_FATAL_FAILURE(buffer = gralloc->allocate(mDisplayWidth, mDisplayHeight, 1, + mReadbackPixelFormat, usage)); Error error = mComposerClient->getRaw()->setReadbackBuffer(mInvalidDisplayId, buffer, nullptr); ASSERT_EQ(Error::BAD_DISPLAY, error); diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp index 19438cbe26..036ef69cf3 100644 --- a/graphics/composer/2.3/utils/vts/Android.bp +++ b/graphics/composer/2.3/utils/vts/Android.bp @@ -27,6 +27,12 @@ cc_library_static { "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.2-vts", "android.hardware.graphics.composer@2.3", + "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", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp index 7548cb521e..2b2fc6d37e 100644 --- a/graphics/composer/2.3/vts/functional/Android.bp +++ b/graphics/composer/2.3/vts/functional/Android.bp @@ -27,6 +27,7 @@ cc_test { ], static_libs: [ "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.allocator@3.0", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.1-vts", "android.hardware.graphics.composer@2.2", @@ -36,6 +37,9 @@ cc_test { "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", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp index d51c30a307..dafe58786b 100644 --- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp +++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp @@ -41,7 +41,7 @@ using common::V1_2::ColorMode; using common::V1_2::Dataspace; using common::V1_2::PixelFormat; using mapper::V2_0::IMapper; -using mapper::V2_0::vts::Gralloc; +using V2_2::vts::Gralloc; // Test environment for graphics.composer class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { @@ -156,15 +156,9 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { } const native_handle_t* allocate() { - IMapper::BufferDescriptorInfo info{}; - info.width = 64; - info.height = 64; - info.layerCount = 1; - info.format = static_cast(PixelFormat::RGBA_8888); - info.usage = - static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); - - return mGralloc->allocate(info); + return mGralloc->allocate( + 64, 64, 1, static_cast(PixelFormat::RGBA_8888), + static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN)); } void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } diff --git a/graphics/mapper/2.1/utils/vts/MapperVts.cpp b/graphics/mapper/2.1/utils/vts/MapperVts.cpp index 078068e306..36f9cbbeb2 100644 --- a/graphics/mapper/2.1/utils/vts/MapperVts.cpp +++ b/graphics/mapper/2.1/utils/vts/MapperVts.cpp @@ -43,24 +43,25 @@ static_assert(sizeof(OldBufferDescriptorInfo) == sizeof(IMapper::BufferDescripto offsetof(IMapper::BufferDescriptorInfo, usage), ""); -Gralloc::Gralloc() : V2_0::vts::Gralloc() { +Gralloc::Gralloc(bool errOnFailure) : V2_0::vts::Gralloc() { if (::testing::Test::HasFatalFailure()) { return; } - init(); + init(errOnFailure); } -Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName) +Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName, + bool errOnFailure) : V2_0::vts::Gralloc(allocatorServiceName, mapperServiceName) { if (::testing::Test::HasFatalFailure()) { return; } - init(); + init(errOnFailure); } -void Gralloc::init() { +void Gralloc::init(bool errOnFailure) { mMapperV2_1 = IMapper::castFrom(V2_0::vts::Gralloc::getMapper()); - ASSERT_NE(nullptr, mMapperV2_1.get()) << "failed to get mapper 2.1 service"; + if (errOnFailure) ASSERT_NE(nullptr, mMapperV2_1.get()) << "failed to get mapper 2.1 service"; } sp Gralloc::getMapper() const { diff --git a/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h b/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h index 423d4b3c0d..bc683bb355 100644 --- a/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h +++ b/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h @@ -32,25 +32,26 @@ using V2_0::BufferDescriptor; // A wrapper to IAllocator and IMapper. class Gralloc : public V2_0::vts::Gralloc { public: - Gralloc(); - Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName); + Gralloc(bool errOnFailure = true); + Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName, + bool errOnFailure = true); - sp getMapper() const; + sp getMapper() const; - bool validateBufferSize(const native_handle_t* bufferHandle, - const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride); - void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds, - uint32_t* outNumInts); + bool validateBufferSize(const native_handle_t* bufferHandle, + const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride); + void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds, + uint32_t* outNumInts); - BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo); + BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo); - const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, - bool import = true, uint32_t* outStride = nullptr); + const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, + bool import = true, uint32_t* outStride = nullptr); protected: - void init(); + void init(bool errOnFailure = true); - sp mMapperV2_1; + sp mMapperV2_1; }; } // namespace vts diff --git a/graphics/mapper/3.0/utils/vts/MapperVts.cpp b/graphics/mapper/3.0/utils/vts/MapperVts.cpp index f2b7594b3f..c94e8db065 100644 --- a/graphics/mapper/3.0/utils/vts/MapperVts.cpp +++ b/graphics/mapper/3.0/utils/vts/MapperVts.cpp @@ -25,8 +25,13 @@ namespace mapper { namespace V3_0 { namespace vts { -Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName) { - init(allocatorServiceName, mapperServiceName); +Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName, + bool errOnFailure) { + if (errOnFailure) { + init(allocatorServiceName, mapperServiceName); + } else { + initNoErr(allocatorServiceName, mapperServiceName); + } } void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) { @@ -38,6 +43,16 @@ void Gralloc::init(const std::string& allocatorServiceName, const std::string& m ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode"; } +void Gralloc::initNoErr(const std::string& allocatorServiceName, + const std::string& mapperServiceName) { + mAllocator = ::testing::VtsHalHidlTargetTestBase::getService(allocatorServiceName); + + mMapper = ::testing::VtsHalHidlTargetTestBase::getService(mapperServiceName); + if (mMapper.get()) { + ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode"; + } +} + Gralloc::~Gralloc() { for (auto bufferHandle : mClonedBuffers) { auto buffer = const_cast(bufferHandle); diff --git a/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h b/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h index ba79ca42b7..1141a881e0 100644 --- a/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h +++ b/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h @@ -36,62 +36,66 @@ using android::hardware::graphics::allocator::V3_0::IAllocator; // A wrapper to IAllocator and IMapper. class Gralloc { public: - Gralloc(const std::string& allocatorServiceName = "default", - const std::string& mapperServiceName = "default"); - ~Gralloc(); + Gralloc(const std::string& allocatorServiceName = "default", + const std::string& mapperServiceName = "default", bool errOnFailure = true); + ~Gralloc(); - // IAllocator methods + // IAllocator methods - sp getAllocator() const; + sp getAllocator() const; - std::string dumpDebugInfo(); + std::string dumpDebugInfo(); - // When import is false, this simply calls IAllocator::allocate. When import - // is true, the returned buffers are also imported into the mapper. - // - // Either case, the returned buffers must be freed with freeBuffer. - std::vector allocate(const BufferDescriptor& descriptor, uint32_t count, - bool import = true, uint32_t* outStride = nullptr); - const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, - bool import = true, uint32_t* outStride = nullptr); + // When import is false, this simply calls IAllocator::allocate. When import + // is true, the returned buffers are also imported into the mapper. + // + // Either case, the returned buffers must be freed with freeBuffer. + std::vector allocate(const BufferDescriptor& descriptor, + uint32_t count, bool import = true, + uint32_t* outStride = nullptr); + const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, + bool import = true, uint32_t* outStride = nullptr); - // IMapper methods + // IMapper methods - sp getMapper() const; + sp getMapper() const; - BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo); + BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo); - const native_handle_t* importBuffer(const hidl_handle& rawHandle); - void freeBuffer(const native_handle_t* bufferHandle); + const native_handle_t* importBuffer(const hidl_handle& rawHandle); + void freeBuffer(const native_handle_t* bufferHandle); - // We use fd instead of hidl_handle in these functions to pass fences - // in and out of the mapper. The ownership of the fd is always transferred - // with each of these functions. - void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, - const IMapper::Rect& accessRegion, int acquireFence, int32_t* outBytesPerPixel, - int32_t* outBytesPerStride); - YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage, - const IMapper::Rect& accessRegion, int acquireFence); - int unlock(const native_handle_t* bufferHandle); + // We use fd instead of hidl_handle in these functions to pass fences + // in and out of the mapper. The ownership of the fd is always transferred + // with each of these functions. + void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, + const IMapper::Rect& accessRegion, int acquireFence, int32_t* outBytesPerPixel, + int32_t* outBytesPerStride); + YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage, + const IMapper::Rect& accessRegion, int acquireFence); + int unlock(const native_handle_t* bufferHandle); - bool validateBufferSize(const native_handle_t* bufferHandle, - const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride); - void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds, - uint32_t* outNumInts); + bool validateBufferSize(const native_handle_t* bufferHandle, + const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride); + void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds, + uint32_t* outNumInts); - bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo); + bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo); private: - void init(const std::string& allocatorServiceName, const std::string& mapperServiceName); - const native_handle_t* cloneBuffer(const hidl_handle& rawHandle); + void init(const std::string& allocatorServiceName, const std::string& mapperServiceName); - sp mAllocator; - sp mMapper; + // initialize without checking for failure to get service + void initNoErr(const std::string& allocatorServiceName, const std::string& mapperServiceName); + const native_handle_t* cloneBuffer(const hidl_handle& rawHandle); - // Keep track of all cloned and imported handles. When a test fails with - // ASSERT_*, the destructor will free the handles for the test. - std::unordered_set mClonedBuffers; - std::unordered_set mImportedBuffers; + sp mAllocator; + sp mMapper; + + // Keep track of all cloned and imported handles. When a test fails with + // ASSERT_*, the destructor will free the handles for the test. + std::unordered_set mClonedBuffers; + std::unordered_set mImportedBuffers; }; } // namespace vts From 337e0084df904ed8c74194fdd1651008fa7d41d3 Mon Sep 17 00:00:00 2001 From: Kevin Rocard Date: Mon, 17 Jun 2019 18:38:44 -0700 Subject: [PATCH 0017/1022] Version dependant target should included version in name As a V6.0 version needs to be created. Note that this target is not used anywhere explicitly. There seem to be some magic to "xsd_config", probably has to do with the package_name. Bug: 134940862 Test: build Change-Id: Id6935c5458294981cb778f3647ec01ee34a34e2f Signed-off-by: Kevin Rocard --- audio/effect/5.0/xml/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/audio/effect/5.0/xml/Android.bp b/audio/effect/5.0/xml/Android.bp index 967135ce51..eb2bcee8e7 100644 --- a/audio/effect/5.0/xml/Android.bp +++ b/audio/effect/5.0/xml/Android.bp @@ -1,6 +1,6 @@ xsd_config { - name: "audio_effects_conf", + name: "audio_effects_conf_V5_0", srcs: ["audio_effects_conf.xsd"], package_name: "audio.effects.V5_0", } From a559b823fb42855a21cd09e73f5f31ffde88b5ff Mon Sep 17 00:00:00 2001 From: Adam Bodnar Date: Tue, 25 Jun 2019 16:43:21 -0700 Subject: [PATCH 0018/1022] Explicate SRGB in Composer VTS 2.2 Readback Tests Bug: 136032929 Test: Build, boot, VtsHalGraphicsComposerV2_2TargetTest Change-Id: Ic842e574e47baf231a4a41803dd2ee178ad2f6a4 --- .../VtsHalGraphicsComposerV2_2ReadbackTest.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp index eef0433b42..6ae8446554 100644 --- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp @@ -87,6 +87,9 @@ class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase mReader = std::make_unique(); mGralloc = std::make_shared(); + ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB, + RenderIntent::COLORIMETRIC)); + mComposerClient->getRaw()->getReadbackBufferAttributes( mPrimaryDisplay, [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { @@ -163,8 +166,6 @@ TEST_F(GraphicsComposerReadbackTest, SingleSolidColorLayer) { return; } mWriter->selectDisplay(mPrimaryDisplay); - ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB, - RenderIntent::COLORIMETRIC)); auto layer = std::make_shared(mComposerClient, mPrimaryDisplay); IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight}); @@ -257,8 +258,6 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerBufferNoEffect) { } mWriter->selectDisplay(mPrimaryDisplay); - ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB, - RenderIntent::COLORIMETRIC)); auto layer = std::make_shared(mComposerClient, mPrimaryDisplay); IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight}); @@ -542,8 +541,6 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerPlaneAlpha) { } mWriter->selectDisplay(mPrimaryDisplay); - ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB, - RenderIntent::COLORIMETRIC)); auto layer = std::make_shared(mComposerClient, mPrimaryDisplay); layer->setColor(RED); @@ -633,8 +630,6 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerZOrder) { } mWriter->selectDisplay(mPrimaryDisplay); - ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB, - RenderIntent::COLORIMETRIC)); IComposerClient::Rect redRect = {0, 0, mDisplayWidth, mDisplayHeight / 2}; IComposerClient::Rect blueRect = {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight}; @@ -891,8 +886,6 @@ class GraphicsComposerTransformReadbackTest : public GraphicsComposerReadbackTes GraphicsComposerReadbackTest::SetUp(); mWriter->selectDisplay(mPrimaryDisplay); - ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB, - RenderIntent::COLORIMETRIC)); auto backgroundLayer = std::make_shared(mComposerClient, mPrimaryDisplay); backgroundLayer->setColor({0, 0, 0, 0}); From 7c8eb68002648118e2fda3b1ba09272daed05e0d Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Wed, 12 Jun 2019 14:24:27 -0700 Subject: [PATCH 0019/1022] Add support for different color modes for readback Bug: 135045017 Test: build, boot, VtsHalGraphicsComposerV2_2TargetTest Change-Id: I07868d95120068bee1d98432888109313da33119 --- .../composer/2.2/utils/vts/ReadbackVts.cpp | 28 +- .../include/composer-vts/2.2/ReadbackVts.h | 7 + ...VtsHalGraphicsComposerV2_2ReadbackTest.cpp | 1140 ++++++++++------- 3 files changed, 686 insertions(+), 489 deletions(-) diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp index 81a6452948..515dda3f7b 100644 --- a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp +++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp @@ -34,6 +34,32 @@ void TestLayer::write(const std::shared_ptr& writer) { writer->setLayerBlendMode(mBlendMode); } +const std::vector ReadbackHelper::colorModes = {ColorMode::SRGB, ColorMode::DISPLAY_P3}; +const std::vector ReadbackHelper::dataspaces = {Dataspace::V0_SRGB, + Dataspace::DISPLAY_P3}; + +std::string ReadbackHelper::getColorModeString(ColorMode mode) { + switch (mode) { + case ColorMode::SRGB: + return std::string("SRGB"); + case ColorMode::DISPLAY_P3: + return std::string("DISPLAY_P3"); + default: + return std::string("Unsupported color mode for readback"); + } +} + +std::string ReadbackHelper::getDataspaceString(Dataspace dataspace) { + switch (dataspace) { + case Dataspace::V0_SRGB: + return std::string("V0_SRGB"); + case Dataspace::DISPLAY_P3: + return std::string("DISPLAY_P3"); + default: + return std::string("Unsupported dataspace for readback"); + } +} + int32_t ReadbackHelper::GetBytesPerPixel(PixelFormat pixelFormat) { switch (pixelFormat) { case PixelFormat::RGBA_8888: @@ -99,7 +125,7 @@ bool ReadbackHelper::readbackSupported(const PixelFormat& pixelFormat, const Dat if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) { return false; } - if (dataspace != Dataspace::V0_SRGB) { + if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) { return false; } return true; diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h index 7e931676ff..d7c8c03296 100644 --- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h +++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h @@ -133,6 +133,10 @@ class TestBufferLayer : public TestLayer { class ReadbackHelper : public ::testing::VtsHalHidlTargetTestBase { public: + static std::string getColorModeString(ColorMode mode); + + static std::string getDataspaceString(Dataspace dataspace); + static int32_t GetBytesPerPixel(PixelFormat pixelFormat); static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData, @@ -147,6 +151,9 @@ class ReadbackHelper : public ::testing::VtsHalHidlTargetTestBase { static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace, const Error error); + + static const std::vector colorModes; + static const std::vector dataspaces; }; class ReadbackBuffer { diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp index 6ae8446554..6b30df7923 100644 --- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp @@ -78,6 +78,8 @@ class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase mDisplayHeight = mComposerClient->getDisplayAttribute( mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT)); + setTestColorModes(); + // explicitly disable vsync ASSERT_NO_FATAL_FAILURE(mComposerClient->setVsyncEnabled(mPrimaryDisplay, false)); mComposerCallback->setVsyncAllowed(false); @@ -87,17 +89,6 @@ class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase mReader = std::make_unique(); mGralloc = std::make_shared(); - ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB, - RenderIntent::COLORIMETRIC)); - - mComposerClient->getRaw()->getReadbackBufferAttributes( - mPrimaryDisplay, - [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { - mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, - tmpDataspace, tmpError); - mPixelFormat = tmpPixelFormat; - mDataspace = tmpDataspace; - }); ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON)); } @@ -137,6 +128,7 @@ class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase Display mPrimaryDisplay; int32_t mDisplayWidth; int32_t mDisplayHeight; + std::vector mTestColorModes; std::shared_ptr mWriter; std::unique_ptr mReader; std::shared_ptr mGralloc; @@ -158,186 +150,373 @@ class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase return displays[0]; } } + + void setTestColorModes() { + mTestColorModes.clear(); + mComposerClient->getRaw()->getColorModes_2_2(mPrimaryDisplay, [&](const auto& tmpError, + const auto& tmpModes) { + ASSERT_EQ(Error::NONE, tmpError); + for (ColorMode mode : tmpModes) { + if (std::find(ReadbackHelper::colorModes.begin(), ReadbackHelper::colorModes.end(), + mode) != ReadbackHelper::colorModes.end()) { + mTestColorModes.push_back(mode); + } + } + }); + } }; TEST_F(GraphicsComposerReadbackTest, SingleSolidColorLayer) { - if (!mHasReadbackBuffer) { - GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; - return; + for (ColorMode mode : mTestColorModes) { + std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" + << std::endl; + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); + + if (!mHasReadbackBuffer) { + std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + auto layer = std::make_shared(mComposerClient, mPrimaryDisplay); + IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setColor(BLUE); + layer->setDisplayFrame(coloredSquare); + layer->setZOrder(10); + + std::vector> layers = {layer}; + + // expected color for each pixel + std::vector expectedColors(mDisplayWidth * mDisplayHeight); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + // if hwc cannot handle and asks for composition change, + // just succeed the test + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } - mWriter->selectDisplay(mPrimaryDisplay); - - auto layer = std::make_shared(mComposerClient, mPrimaryDisplay); - IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight}); - layer->setColor(BLUE); - layer->setDisplayFrame(coloredSquare); - layer->setZOrder(10); - - std::vector> layers = {layer}; - - // expected color for each pixel - std::vector expectedColors(mDisplayWidth * mDisplayHeight); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE); - - ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, - mDisplayHeight, mPixelFormat, mDataspace); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - - writeLayers(layers); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - // if hwc cannot handle and asks for composition change, - // just succeed the test - if (mReader->mCompositionChanges.size() != 0) { - clearCommandReaderState(); - GTEST_SUCCEED(); - return; - } - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->presentDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } TEST_F(GraphicsComposerReadbackTest, SetLayerBuffer) { - if (!mHasReadbackBuffer) { - GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; - return; + for (ColorMode mode : mTestColorModes) { + std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" + << std::endl; + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); + + if (!mHasReadbackBuffer) { + std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + std::vector expectedColors(mDisplayWidth * mDisplayHeight); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, + GREEN); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, + BLUE); + + auto layer = std::make_shared(mComposerClient, mGralloc, mPrimaryDisplay, + mDisplayWidth, mDisplayHeight, + PixelFormat::RGBA_8888); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); + + std::vector> layers = {layer}; + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + + mWriter->presentDisplay(); + execute(); + + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } - - mWriter->selectDisplay(mPrimaryDisplay); - - ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, - mDisplayHeight, mPixelFormat, mDataspace); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - std::vector expectedColors(mDisplayWidth * mDisplayHeight); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, - GREEN); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE); - - auto layer = - std::make_shared(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, - mDisplayHeight, PixelFormat::RGBA_8888); - layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); - layer->setZOrder(10); - ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); - - std::vector> layers = {layer}; - - writeLayers(layers); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - - if (mReader->mCompositionChanges.size() != 0) { - clearCommandReaderState(); - GTEST_SUCCEED(); - return; - } - ASSERT_EQ(0, mReader->mErrors.size()); - - mWriter->presentDisplay(); - execute(); - - ASSERT_EQ(0, mReader->mErrors.size()); - - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } TEST_F(GraphicsComposerReadbackTest, SetLayerBufferNoEffect) { - if (!mHasReadbackBuffer) { - GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; - return; + for (ColorMode mode : mTestColorModes) { + std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" + << std::endl; + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); + + if (!mHasReadbackBuffer) { + std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + auto layer = std::make_shared(mComposerClient, mPrimaryDisplay); + IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setColor(BLUE); + layer->setDisplayFrame(coloredSquare); + layer->setZOrder(10); + layer->write(mWriter); + + // This following buffer call should have no effect + uint64_t usage = + static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN); + const native_handle_t* bufferHandle = + mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, usage); + mWriter->setLayerBuffer(0, bufferHandle, -1); + + // expected color for each pixel + std::vector expectedColors(mDisplayWidth * mDisplayHeight); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + mWriter->validateDisplay(); + execute(); + + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } - - mWriter->selectDisplay(mPrimaryDisplay); - - auto layer = std::make_shared(mComposerClient, mPrimaryDisplay); - IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight}); - layer->setColor(BLUE); - layer->setDisplayFrame(coloredSquare); - layer->setZOrder(10); - layer->write(mWriter); - - // This following buffer call should have no effect - PixelFormat format = PixelFormat::RGBA_8888; - uint64_t usage = - static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN); - const native_handle_t* bufferHandle = - mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, format, usage); - mWriter->setLayerBuffer(0, bufferHandle, -1); - - // expected color for each pixel - std::vector expectedColors(mDisplayWidth * mDisplayHeight); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE); - - ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, - mDisplayHeight, mPixelFormat, mDataspace); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - - mWriter->validateDisplay(); - execute(); - - if (mReader->mCompositionChanges.size() != 0) { - clearCommandReaderState(); - GTEST_SUCCEED(); - return; - } - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->presentDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } TEST_F(GraphicsComposerReadbackTest, ClientComposition) { - if (!mHasReadbackBuffer) { - GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; - return; - } - - mWriter->selectDisplay(mPrimaryDisplay); - - std::vector expectedColors(mDisplayWidth * mDisplayHeight); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, - GREEN); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE); - - auto layer = - std::make_shared(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, - mDisplayHeight, PixelFormat::RGBA_FP16); - layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); - layer->setZOrder(10); - - std::vector> layers = {layer}; - - ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, - mDisplayHeight, mPixelFormat, mDataspace); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - writeLayers(layers); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - - if (mReader->mCompositionChanges.size() != 0) { - ASSERT_EQ(1, mReader->mCompositionChanges.size()); - ASSERT_EQ(1, mReader->mCompositionChanges[0].second); - - ASSERT_NO_FATAL_FAILURE( + ASSERT_NO_FATAL_FAILURE( mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount)); + for (ColorMode mode : mTestColorModes) { + std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" + << std::endl; + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); + + if (!mHasReadbackBuffer) { + std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + std::vector expectedColors(mDisplayWidth * mDisplayHeight); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, + GREEN); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, + BLUE); + + auto layer = std::make_shared(mComposerClient, mGralloc, mPrimaryDisplay, + mDisplayWidth, mDisplayHeight, + PixelFormat::RGBA_FP16); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + + std::vector> layers = {layer}; + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + + if (mReader->mCompositionChanges.size() != 0) { + ASSERT_EQ(1, mReader->mCompositionChanges.size()); + ASSERT_EQ(1, mReader->mCompositionChanges[0].second); + + // create client target buffer + uint32_t clientStride; + PixelFormat clientFormat = PixelFormat::RGBA_8888; + uint64_t clientUsage = static_cast(BufferUsage::CPU_READ_OFTEN | + BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_CLIENT_TARGET); + const native_handle_t* clientBufferHandle = + mGralloc->allocate(layer->mWidth, layer->mHeight, layer->mLayerCount, + clientFormat, clientUsage, /*import*/ true, &clientStride); + ASSERT_NE(nullptr, clientBufferHandle); + + void* clientBufData = + mGralloc->lock(clientBufferHandle, clientUsage, layer->mAccessRegion, -1); + + ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(layer->mWidth, layer->mHeight, + clientStride, clientBufData, + clientFormat, expectedColors)); + int clientFence = mGralloc->unlock(clientBufferHandle); + if (clientFence != -1) { + sync_wait(clientFence, -1); + close(clientFence); + } + + IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight}; + mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN, + std::vector(1, damage)); + + layer->setToClientComposition(mWriter); + mWriter->validateDisplay(); + execute(); + ASSERT_EQ(0, mReader->mCompositionChanges.size()); + } + ASSERT_EQ(0, mReader->mErrors.size()); + + mWriter->presentDisplay(); + execute(); + + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + } +} + +TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) { + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount)); + + for (ColorMode mode : mTestColorModes) { + std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" + << std::endl; + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); + + if (!mHasReadbackBuffer) { + std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + std::vector expectedColors(mDisplayWidth * mDisplayHeight); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight / 2}, GREEN); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + auto deviceLayer = std::make_shared( + mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, mDisplayHeight / 2, + PixelFormat::RGBA_8888); + std::vector deviceColors(deviceLayer->mWidth * + deviceLayer->mHeight); + ReadbackHelper::fillColorsArea(deviceColors, deviceLayer->mWidth, + {0, 0, static_cast(deviceLayer->mWidth), + static_cast(deviceLayer->mHeight)}, + GREEN); + deviceLayer->setDisplayFrame({0, 0, static_cast(deviceLayer->mWidth), + static_cast(deviceLayer->mHeight)}); + deviceLayer->setZOrder(10); + ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors)); + deviceLayer->write(mWriter); + + auto clientLayer = std::make_shared( + mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, mDisplayHeight / 2, + PixelFormat::RGBA_8888, IComposerClient::Composition::CLIENT); + IComposerClient::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}; + clientLayer->setDisplayFrame(clientFrame); + clientLayer->setZOrder(0); + clientLayer->write(mWriter); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + // create client target buffer uint32_t clientStride; PixelFormat clientFormat = PixelFormat::RGBA_8888; @@ -345,350 +524,335 @@ TEST_F(GraphicsComposerReadbackTest, ClientComposition) { static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_CLIENT_TARGET); const native_handle_t* clientBufferHandle = - mGralloc->allocate(layer->mWidth, layer->mHeight, layer->mLayerCount, clientFormat, - clientUsage, /*import*/ true, &clientStride); + mGralloc->allocate(mDisplayWidth, mDisplayHeight, clientLayer->mLayerCount, + clientFormat, clientUsage, /*import*/ true, &clientStride); ASSERT_NE(nullptr, clientBufferHandle); - void* clientBufData = - mGralloc->lock(clientBufferHandle, clientUsage, layer->mAccessRegion, -1); + void* clientBufData = mGralloc->lock(clientBufferHandle, clientUsage, + {0, 0, mDisplayWidth, mDisplayHeight}, -1); - ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(layer->mWidth, layer->mHeight, + std::vector clientColors(mDisplayWidth * mDisplayHeight); + ReadbackHelper::fillColorsArea(clientColors, mDisplayWidth, clientFrame, RED); + ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mDisplayWidth, mDisplayHeight, clientStride, clientBufData, - clientFormat, expectedColors)); + clientFormat, clientColors)); int clientFence = mGralloc->unlock(clientBufferHandle); if (clientFence != -1) { sync_wait(clientFence, -1); close(clientFence); } - IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight}; mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN, - std::vector(1, damage)); - - layer->setToClientComposition(mWriter); + std::vector(1, clientFrame)); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); mWriter->validateDisplay(); execute(); - ASSERT_EQ(0, mReader->mCompositionChanges.size()); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + std::cout << "Composition change requested, skipping test" << std::endl; + GTEST_SUCCEED() << "Composition change requested, skipping test"; + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } - ASSERT_EQ(0, mReader->mErrors.size()); - - mWriter->presentDisplay(); - execute(); - - ASSERT_EQ(0, mReader->mErrors.size()); - - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); -} - -TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) { - if (!mHasReadbackBuffer) { - GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; - return; - } - - mWriter->selectDisplay(mPrimaryDisplay); - ASSERT_NO_FATAL_FAILURE( - mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount)); - - std::vector expectedColors(mDisplayWidth * mDisplayHeight); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {0, 0, mDisplayWidth, mDisplayHeight / 2}, GREEN); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED); - - ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, - mDisplayHeight, mPixelFormat, mDataspace); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - - auto deviceLayer = - std::make_shared(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, - mDisplayHeight / 2, PixelFormat::RGBA_8888); - std::vector deviceColors(deviceLayer->mWidth * deviceLayer->mHeight); - ReadbackHelper::fillColorsArea(deviceColors, deviceLayer->mWidth, - {0, 0, static_cast(deviceLayer->mWidth), - static_cast(deviceLayer->mHeight)}, - GREEN); - deviceLayer->setDisplayFrame({0, 0, static_cast(deviceLayer->mWidth), - static_cast(deviceLayer->mHeight)}); - deviceLayer->setZOrder(10); - ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors)); - deviceLayer->write(mWriter); - - auto clientLayer = std::make_shared( - mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, mDisplayHeight / 2, - PixelFormat::RGBA_8888, IComposerClient::Composition::CLIENT); - IComposerClient::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}; - clientLayer->setDisplayFrame(clientFrame); - clientLayer->setZOrder(0); - clientLayer->write(mWriter); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - - uint64_t clientUsage = - static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | - BufferUsage::COMPOSER_CLIENT_TARGET); - uint32_t clientStride; - const native_handle_t* clientBufferHandle = - mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, - clientUsage, /*import*/ true, &clientStride); - ASSERT_NE(nullptr, clientBufferHandle); - - AccessRegion clientAccessRegion; - clientAccessRegion.left = 0; - clientAccessRegion.top = 0; - clientAccessRegion.width = mDisplayWidth; - clientAccessRegion.height = mDisplayHeight; - void* clientData = mGralloc->lock(clientBufferHandle, clientUsage, clientAccessRegion, -1); - std::vector clientColors(mDisplayWidth * mDisplayHeight); - ReadbackHelper::fillColorsArea(clientColors, mDisplayWidth, clientFrame, RED); - ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mDisplayWidth, mDisplayHeight, clientStride, - clientData, PixelFormat::RGBA_8888, - clientColors)); - int clientFence = mGralloc->unlock(clientBufferHandle); - if (clientFence != -1) { - sync_wait(clientFence, -1); - close(clientFence); - } - - mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN, - std::vector(1, clientFrame)); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - if (mReader->mCompositionChanges.size() != 0) { - clearCommandReaderState(); - GTEST_SUCCEED(); - return; - } - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->presentDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } TEST_F(GraphicsComposerReadbackTest, SetLayerDamage) { - if (!mHasReadbackBuffer) { - GTEST_SUCCEED() << "Readback not supported or unsupported pixelformat/dataspace"; - return; + for (ColorMode mode : mTestColorModes) { + std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" + << std::endl; + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); + + if (!mHasReadbackBuffer) { + std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + IComposerClient::Rect redRect = {0, 0, mDisplayWidth / 4, mDisplayHeight / 4}; + + std::vector expectedColors(mDisplayWidth * mDisplayHeight); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + + auto layer = std::make_shared(mComposerClient, mGralloc, mPrimaryDisplay, + mDisplayWidth, mDisplayHeight, + PixelFormat::RGBA_8888); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); + + std::vector> layers = {layer}; + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + + // update surface damage and recheck + redRect = {mDisplayWidth / 4, mDisplayHeight / 4, mDisplayWidth / 2, mDisplayHeight / 2}; + ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + + ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors)); + layer->setSurfaceDamage(std::vector( + 1, {0, 0, mDisplayWidth / 2, mDisplayWidth / 2})); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_EQ(0, mReader->mCompositionChanges.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } - - mWriter->selectDisplay(mPrimaryDisplay); - - IComposerClient::Rect redRect = {0, 0, mDisplayWidth / 4, mDisplayHeight / 4}; - - std::vector expectedColors(mDisplayWidth * mDisplayHeight); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); - - auto layer = - std::make_shared(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, - mDisplayHeight, PixelFormat::RGBA_8888); - layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); - layer->setZOrder(10); - ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); - - std::vector> layers = {layer}; - - ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, - mDisplayHeight, mPixelFormat, mDataspace); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - - writeLayers(layers); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - if (mReader->mCompositionChanges.size() != 0) { - clearCommandReaderState(); - GTEST_SUCCEED(); - return; - } - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->presentDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); - - // update surface damage and recheck - redRect = {mDisplayWidth / 4, mDisplayHeight / 4, mDisplayWidth / 2, mDisplayHeight / 2}; - ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); - - ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors)); - layer->setSurfaceDamage( - std::vector(1, {0, 0, mDisplayWidth / 2, mDisplayWidth / 2})); - - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - - writeLayers(layers); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - ASSERT_EQ(0, mReader->mCompositionChanges.size()); - mWriter->presentDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } TEST_F(GraphicsComposerReadbackTest, SetLayerPlaneAlpha) { - if (!mHasReadbackBuffer) { - GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; - return; + for (ColorMode mode : mTestColorModes) { + std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" + << std::endl; + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); + + if (!mHasReadbackBuffer) { + std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + auto layer = std::make_shared(mComposerClient, mPrimaryDisplay); + layer->setColor(RED); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + layer->setAlpha(0); + layer->setBlendMode(IComposerClient::BlendMode::PREMULTIPLIED); + + std::vector> layers = {layer}; + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + std::vector expectedColors(mDisplayWidth * mDisplayHeight); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } - - mWriter->selectDisplay(mPrimaryDisplay); - - auto layer = std::make_shared(mComposerClient, mPrimaryDisplay); - layer->setColor(RED); - layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); - layer->setZOrder(10); - layer->setAlpha(0); - layer->setBlendMode(IComposerClient::BlendMode::PREMULTIPLIED); - - std::vector> layers = {layer}; - - ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, - mDisplayHeight, mPixelFormat, mDataspace); - - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - - writeLayers(layers); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - if (mReader->mCompositionChanges.size() != 0) { - clearCommandReaderState(); - GTEST_SUCCEED(); - return; - } - ASSERT_EQ(0, mReader->mErrors.size()); - - mWriter->presentDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - - std::vector expectedColors(mDisplayWidth * mDisplayHeight); - - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } TEST_F(GraphicsComposerReadbackTest, SetLayerSourceCrop) { - if (!mHasReadbackBuffer) { - GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; - return; + for (ColorMode mode : mTestColorModes) { + std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" + << std::endl; + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); + + if (!mHasReadbackBuffer) { + std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + std::vector expectedColors(mDisplayWidth * mDisplayHeight); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, + BLUE); + + auto layer = std::make_shared(mComposerClient, mGralloc, mPrimaryDisplay, + mDisplayWidth, mDisplayHeight, + PixelFormat::RGBA_8888); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + layer->setSourceCrop({0, static_cast(mDisplayHeight / 2), + static_cast(mDisplayWidth), + static_cast(mDisplayHeight)}); + ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); + + std::vector> layers = {layer}; + + // update expected colors to match crop + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight}, BLUE); + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } - - mWriter->selectDisplay(mPrimaryDisplay); - - std::vector expectedColors(mDisplayWidth * mDisplayHeight); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE); - - auto layer = - std::make_shared(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, - mDisplayHeight, PixelFormat::RGBA_8888); - layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); - layer->setZOrder(10); - layer->setSourceCrop({0, static_cast(mDisplayHeight / 2), - static_cast(mDisplayWidth), static_cast(mDisplayHeight)}); - ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); - - std::vector> layers = {layer}; - - // update expected colors to match crop - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {0, 0, mDisplayWidth, mDisplayHeight}, BLUE); - ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, - mDisplayHeight, mPixelFormat, mDataspace); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - writeLayers(layers); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - if (mReader->mCompositionChanges.size() != 0) { - clearCommandReaderState(); - GTEST_SUCCEED(); - return; - } - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->presentDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } TEST_F(GraphicsComposerReadbackTest, SetLayerZOrder) { - if (!mHasReadbackBuffer) { - GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; - return; + for (ColorMode mode : mTestColorModes) { + std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" + << std::endl; + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); + + if (!mHasReadbackBuffer) { + std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + IComposerClient::Rect redRect = {0, 0, mDisplayWidth, mDisplayHeight / 2}; + IComposerClient::Rect blueRect = {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight}; + auto redLayer = std::make_shared(mComposerClient, mPrimaryDisplay); + redLayer->setColor(RED); + redLayer->setDisplayFrame(redRect); + + auto blueLayer = std::make_shared(mComposerClient, mPrimaryDisplay); + blueLayer->setColor(BLUE); + blueLayer->setDisplayFrame(blueRect); + blueLayer->setZOrder(5); + + std::vector> layers = {redLayer, blueLayer}; + std::vector expectedColors(mDisplayWidth * mDisplayHeight); + + // red in front of blue + redLayer->setZOrder(10); + + // fill blue first so that red will overwrite on overlap + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + + redLayer->setZOrder(1); + ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + ASSERT_EQ(0, mReader->mCompositionChanges.size()); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } - - mWriter->selectDisplay(mPrimaryDisplay); - - IComposerClient::Rect redRect = {0, 0, mDisplayWidth, mDisplayHeight / 2}; - IComposerClient::Rect blueRect = {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight}; - auto redLayer = std::make_shared(mComposerClient, mPrimaryDisplay); - redLayer->setColor(RED); - redLayer->setDisplayFrame(redRect); - - auto blueLayer = std::make_shared(mComposerClient, mPrimaryDisplay); - blueLayer->setColor(BLUE); - blueLayer->setDisplayFrame(blueRect); - blueLayer->setZOrder(5); - - std::vector> layers = {redLayer, blueLayer}; - std::vector expectedColors(mDisplayWidth * mDisplayHeight); - - // red in front of blue - redLayer->setZOrder(10); - - // fill blue first so that red will overwrite on overlap - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); - - ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, - mDisplayHeight, mPixelFormat, mDataspace); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - - writeLayers(layers); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - if (mReader->mCompositionChanges.size() != 0) { - clearCommandReaderState(); - GTEST_SUCCEED(); - return; - } - mWriter->presentDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); - - redLayer->setZOrder(1); - ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE); - - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - - writeLayers(layers); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - ASSERT_EQ(0, mReader->mCompositionChanges.size()); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->presentDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } class GraphicsComposerBlendModeReadbackTest : public GraphicsComposerReadbackTest, From 1353468370d7aec662fa5811052c2160ef39c691 Mon Sep 17 00:00:00 2001 From: Brian Duddie Date: Wed, 19 Jun 2019 16:25:11 -0700 Subject: [PATCH 0020/1022] Avoid potential race condition in test setup Resize the event queue before starting the polling thread to avoid potential concurrent access. Test: run VtsHalSensorsV2_0TargetTest Change-Id: I71af46169e7731df4135639644665365b3714e1f --- sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp index 03fcc174ef..dc54f27bf3 100644 --- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp +++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp @@ -130,8 +130,8 @@ void SensorsHidlEnvironmentV2_0::HidlTearDown() { void SensorsHidlEnvironmentV2_0::startPollingThread() { mStopThread = false; - mPollThread = std::thread(pollingThread, this); mEvents.reserve(MAX_RECEIVE_BUFFER_EVENT_COUNT); + mPollThread = std::thread(pollingThread, this); } void SensorsHidlEnvironmentV2_0::readEvents() { From 5261dce877f7f20d5235fdb7b4763b35c9906392 Mon Sep 17 00:00:00 2001 From: Kevin Rocard Date: Tue, 18 Jun 2019 12:40:48 -0700 Subject: [PATCH 0021/1022] Audio service: Refactor register interface Remove all per interface version boilerplate. Adding a new version now requires only including the file and adding the version name to the list. Bug: 134940862 Test: adb shell lshal Change-Id: Ib6b99d7a2c2079d914970fbe804aaf3c78c143ce Signed-off-by: Kevin Rocard --- .../all-versions/default/service/service.cpp | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp index 8a7b2ea09d..2a6571b9e3 100644 --- a/audio/common/all-versions/default/service/service.cpp +++ b/audio/common/all-versions/default/service/service.cpp @@ -36,6 +36,15 @@ using namespace android::hardware; using android::OK; +/** Try to register the provided factories in the provided order. + * If any registers successfully, do not register any other and return true. + * If all fail, return false. + */ +template +bool registerPassthroughServiceImplementations() { + return ((registerPassthroughServiceImplementation() != OK) && ...); +} + int main(int /* argc */, char* /* argv */ []) { ::android::ProcessState::initWithDriver("/dev/vndbinder"); // start a threadpool for vndbinder interactions @@ -50,30 +59,30 @@ int main(int /* argc */, char* /* argv */ []) { } configureRpcThreadpool(16, true /*callerWillJoin*/); - bool fail = registerPassthroughServiceImplementation() != OK && - registerPassthroughServiceImplementation() != OK && - registerPassthroughServiceImplementation() != OK; - LOG_ALWAYS_FATAL_IF(fail, "Could not register audio core API 2, 4 nor 5"); + LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations()), + "Could not register audio core API"); - fail = registerPassthroughServiceImplementation() != OK && - registerPassthroughServiceImplementation() != OK && - registerPassthroughServiceImplementation() != OK, - LOG_ALWAYS_FATAL_IF(fail, "Could not register audio effect API 2, 4 nor 5"); + LOG_ALWAYS_FATAL_IF( + (registerPassthroughServiceImplementations()), + "Could not register audio effect API"); - fail = registerPassthroughServiceImplementation() != OK && - registerPassthroughServiceImplementation() != OK && - registerPassthroughServiceImplementation() != OK, - ALOGW_IF(fail, "Could not register soundtrigger API 2.0, 2.1 nor 2.2"); + ALOGW_IF((registerPassthroughServiceImplementations()), + "Could not register soundtrigger API"); - fail = registerPassthroughServiceImplementation< - bluetooth::audio::V2_0::IBluetoothAudioProvidersFactory>() != OK; - ALOGW_IF(fail, "Could not register Bluetooth Audio API 2.0"); + ALOGW_IF(registerPassthroughServiceImplementations< + bluetooth::audio::V2_0::IBluetoothAudioProvidersFactory>(), + "Could not register Bluetooth audio API"); // remove the old HIDL when Bluetooth Audio Hal V2 has offloading supported - fail = - registerPassthroughServiceImplementation() != - OK; - ALOGW_IF(fail, "Could not register Bluetooth audio offload 1.0"); + ALOGW_IF(registerPassthroughServiceImplementations< + bluetooth::a2dp::V1_0::IBluetoothAudioOffload>(), + "Could not register Bluetooth audio offload API"); joinRpcThreadpool(); } From 5bf9dc69ac92670fa941c6ba6d93475b01aba3c8 Mon Sep 17 00:00:00 2001 From: Adam Bodnar Date: Fri, 24 May 2019 09:20:04 -0700 Subject: [PATCH 0022/1022] Validate Render Engine output in composer VTS 2.2 Bug: 133411821 Test: build, boot, VtsHalGraphicsComposerV2_2TargetTest Change-Id: Ie95c197d702977738a75e29954c541fe1b7baa38 --- graphics/composer/2.2/utils/vts/Android.bp | 8 + .../composer/2.2/utils/vts/ReadbackVts.cpp | 87 +++++- .../2.2/utils/vts/RenderEngineVts.cpp | 85 ++++++ .../include/composer-vts/2.2/ReadbackVts.h | 13 + .../composer-vts/2.2/RenderEngineVts.h | 68 +++++ .../composer/2.2/vts/functional/Android.bp | 11 + ...sComposerV2_2CompositionComparisonTest.cpp | 262 ++++++++++++++++++ ...VtsHalGraphicsComposerV2_2ReadbackTest.cpp | 2 +- 8 files changed, 522 insertions(+), 14 deletions(-) create mode 100644 graphics/composer/2.2/utils/vts/RenderEngineVts.cpp create mode 100644 graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h create mode 100644 graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp index 56b12f5093..b813688f89 100644 --- a/graphics/composer/2.2/utils/vts/Android.bp +++ b/graphics/composer/2.2/utils/vts/Android.bp @@ -20,8 +20,16 @@ cc_library_static { srcs: [ "ComposerVts.cpp", "ReadbackVts.cpp", + "RenderEngineVts.cpp", + ], + shared_libs: [ + "libui", ], static_libs: [ + "librenderengine", + "libmath", + "libarect", + "libnativewindow", "VtsHalHidlTargetTestBase", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.1-vts", diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp index 515dda3f7b..91efc6ff07 100644 --- a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp +++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp @@ -60,6 +60,27 @@ std::string ReadbackHelper::getDataspaceString(Dataspace dataspace) { } } +LayerSettings TestLayer::toRenderEngineLayerSettings() { + LayerSettings layerSettings; + + layerSettings.alpha = half(mAlpha); + layerSettings.disableBlending = mBlendMode == IComposerClient::BlendMode::NONE; + layerSettings.geometry.boundaries = FloatRect( + static_cast(mDisplayFrame.left), static_cast(mDisplayFrame.top), + static_cast(mDisplayFrame.right), static_cast(mDisplayFrame.bottom)); + + const mat4 translation = mat4::translate(vec4( + (mTransform & Transform::FLIP_H ? -1.0f : 0.0f) * mDisplayFrame.right, + (mTransform & Transform::FLIP_V ? -1.0f : 0.0f) * mDisplayFrame.bottom, 0.0f, 1.0f)); + + const mat4 scale = mat4::scale(vec4(mTransform & Transform::FLIP_H ? -1.0f : 1.0f, + mTransform & Transform::FLIP_V ? -1.0f : 1.0f, 1.0f, 1.0f)); + + layerSettings.geometry.positionTransform = translation * scale; + + return layerSettings; +} + int32_t ReadbackHelper::GetBytesPerPixel(PixelFormat pixelFormat) { switch (pixelFormat) { case PixelFormat::RGBA_8888: @@ -131,6 +152,25 @@ bool ReadbackHelper::readbackSupported(const PixelFormat& pixelFormat, const Dat return true; } +void ReadbackHelper::compareColorBuffers(std::vector& expectedColors, + void* bufferData, const uint32_t stride, + const uint32_t width, const uint32_t height, + const PixelFormat pixelFormat) { + const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat); + ASSERT_NE(-1, bytesPerPixel); + for (int row = 0; row < height; row++) { + for (int col = 0; col < width; col++) { + int pixel = row * width + col; + int offset = (row * stride + col) * bytesPerPixel; + uint8_t* pixelColor = (uint8_t*)bufferData + offset; + + ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]); + ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]); + ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]); + } + } +} + ReadbackBuffer::ReadbackBuffer(Display display, const std::shared_ptr& client, const std::shared_ptr& gralloc, uint32_t width, uint32_t height, PixelFormat pixelFormat, Dataspace dataspace) { @@ -179,19 +219,8 @@ void ReadbackBuffer::checkReadbackBuffer(std::vector exp void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, fenceHandle); ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888); - int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(mPixelFormat); - ASSERT_NE(-1, bytesPerPixel); - for (int row = 0; row < mHeight; row++) { - for (int col = 0; col < mWidth; col++) { - int pixel = row * mWidth + col; - int offset = (row * mStride + col) * bytesPerPixel; - uint8_t* pixelColor = (uint8_t*)bufData + offset; - - ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]); - ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]); - ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]); - } - } + ReadbackHelper::compareColorBuffers(expectedColors, bufData, mStride, mWidth, mHeight, + mPixelFormat); int32_t unlockFence = mGralloc->unlock(mBufferHandle); if (unlockFence != -1) { sync_wait(unlockFence, -1); @@ -205,6 +234,16 @@ void TestColorLayer::write(const std::shared_ptr& writer) { writer->setLayerColor(mColor); } +LayerSettings TestColorLayer::toRenderEngineLayerSettings() { + LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings(); + + layerSettings.source.solidColor = + half3(static_cast(mColor.r) / 255.0, static_cast(mColor.g) / 255.0, + static_cast(mColor.b) / 255.0); + layerSettings.alpha = mAlpha * (static_cast(mColor.a) / 255.0); + return layerSettings; +} + TestBufferLayer::TestBufferLayer(const std::shared_ptr& client, const std::shared_ptr& gralloc, Display display, int32_t width, int32_t height, PixelFormat format, @@ -241,6 +280,27 @@ void TestBufferLayer::write(const std::shared_ptr& writer) { if (mBufferHandle != nullptr) writer->setLayerBuffer(0, mBufferHandle, mFillFence); } +LayerSettings TestBufferLayer::toRenderEngineLayerSettings() { + LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings(); + layerSettings.source.buffer.buffer = + new GraphicBuffer(mBufferHandle, GraphicBuffer::CLONE_HANDLE, mWidth, mHeight, + static_cast(mFormat), 1, mUsage, mStride); + // TODO(b/136483187): Why does this break the premultiply test + // layerSettings.source.buffer.usePremultipliedAlpha = + // mBlendMode == IComposerClient::BlendMode::PREMULTIPLIED; + + const float scaleX = (mSourceCrop.right - mSourceCrop.left) / (mWidth); + const float scaleY = (mSourceCrop.bottom - mSourceCrop.top) / (mHeight); + const float translateX = mSourceCrop.left / (mWidth); + const float translateY = mSourceCrop.top / (mHeight); + + layerSettings.source.buffer.textureTransform = + mat4::translate(vec4(translateX, translateY, 0, 1)) * + mat4::scale(vec4(scaleX, scaleY, 1.0, 1.0)); + + return layerSettings; +} + void TestBufferLayer::fillBuffer(std::vector expectedColors) { void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, -1); ASSERT_NO_FATAL_FAILURE( @@ -251,6 +311,7 @@ void TestBufferLayer::fillBuffer(std::vector expectedCol close(mFillFence); } } + void TestBufferLayer::setBuffer(std::vector colors) { if (mBufferHandle != nullptr) { mGralloc->freeBuffer(mBufferHandle); diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp new file mode 100644 index 0000000000..d910169bfb --- /dev/null +++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp @@ -0,0 +1,85 @@ +/* + * Copyright 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. + */ + +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_2 { +namespace vts { + +using mapper::V2_1::IMapper; +using renderengine::DisplaySettings; +using renderengine::LayerSettings; + +TestRenderEngine::TestRenderEngine(common::V1_1::PixelFormat hwcFormat, + uint32_t renderEngineFeatures) { + mFormat = hwcFormat; + mRenderEngine = renderengine::RenderEngine::create( + static_cast(mFormat), renderEngineFeatures, mMaxFrameBufferAcquireBuffers); +} + +void TestRenderEngine::setRenderLayers(std::vector> layers) { + sort(layers.begin(), layers.end(), + [](const std::shared_ptr& lhs, const std::shared_ptr& rhs) -> bool { + return lhs->mZOrder < rhs->mZOrder; + }); + + if (!mCompositionLayers.empty()) { + mCompositionLayers.clear(); + } + for (auto& layer : layers) { + LayerSettings settings = layer->toRenderEngineLayerSettings(); + mCompositionLayers.push_back(settings); + } +} + +void TestRenderEngine::initGraphicBuffer(uint32_t width, uint32_t height, uint32_t layerCount, + uint64_t usage) { + mGraphicBuffer = + new GraphicBuffer(width, height, static_cast(mFormat), layerCount, usage); +} + +void TestRenderEngine::drawLayers() { + base::unique_fd bufferFence; + base::unique_fd readyFence; + mRenderEngine->drawLayers(mDisplaySettings, mCompositionLayers, + mGraphicBuffer->getNativeBuffer(), true, std::move(bufferFence), + &readyFence); + int fd = readyFence.release(); + if (fd != -1) { + ASSERT_EQ(0, sync_wait(fd, -1)); + ASSERT_EQ(0, close(fd)); + } +} + +void TestRenderEngine::checkColorBuffer(std::vector& expectedColors) { + void* bufferData; + ASSERT_EQ(0, mGraphicBuffer->lock(mGraphicBuffer->getUsage(), &bufferData)); + ReadbackHelper::compareColorBuffers(expectedColors, bufferData, mGraphicBuffer->getStride(), + mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(), + mFormat); + ASSERT_EQ(0, mGraphicBuffer->unlock()); +} + +} // namespace vts +} // namespace V2_2 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h index d7c8c03296..5304cd4b23 100644 --- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h +++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h @@ -14,6 +14,8 @@ * limitations under the License. */ +#pragma once + #include #include #include @@ -21,6 +23,7 @@ #include #include #include +#include namespace android { namespace hardware { @@ -35,6 +38,7 @@ using common::V1_1::Dataspace; using common::V1_1::PixelFormat; using IMapper2_1 = mapper::V2_1::IMapper; using Gralloc2_1 = mapper::V2_1::vts::Gralloc; +using renderengine::LayerSettings; using V2_1::Display; using V2_1::Layer; using V2_1::vts::AccessRegion; @@ -56,6 +60,7 @@ class TestLayer { virtual ~TestLayer(){}; virtual void write(const std::shared_ptr& writer); + virtual LayerSettings toRenderEngineLayerSettings(); void setDisplayFrame(IComposerClient::Rect frame) { mDisplayFrame = frame; } void setSourceCrop(IComposerClient::FRect crop) { mSourceCrop = crop; } @@ -93,6 +98,8 @@ class TestColorLayer : public TestLayer { void write(const std::shared_ptr& writer) override; + LayerSettings toRenderEngineLayerSettings() override; + void setColor(IComposerClient::Color color) { mColor = color; } private: @@ -110,6 +117,8 @@ class TestBufferLayer : public TestLayer { void write(const std::shared_ptr& writer) override; + LayerSettings toRenderEngineLayerSettings() override; + void fillBuffer(std::vector expectedColors); void setBuffer(std::vector colors); @@ -154,6 +163,10 @@ class ReadbackHelper : public ::testing::VtsHalHidlTargetTestBase { static const std::vector colorModes; static const std::vector dataspaces; + + static void compareColorBuffers(std::vector& expectedColors, + void* bufferData, const uint32_t stride, const uint32_t width, + const uint32_t height, const PixelFormat pixelFormat); }; class ReadbackBuffer { diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h new file mode 100644 index 0000000000..0ac5a22683 --- /dev/null +++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h @@ -0,0 +1,68 @@ +/* + * Copyright 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_2 { +namespace vts { + +using mapper::V2_1::IMapper; +using renderengine::DisplaySettings; +using vts::Gralloc; + +class TestRenderEngine { + public: + TestRenderEngine(common::V1_1::PixelFormat hwcFormat, uint32_t renderEngineFeatures); + ~TestRenderEngine() = default; + + void setRenderLayers(std::vector> layers); + void initGraphicBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint64_t usage); + void setDisplaySettings(DisplaySettings& displaySettings) { + mDisplaySettings = displaySettings; + }; + void drawLayers(); + void checkColorBuffer(std::vector& expectedColors); + + private: + static constexpr uint32_t mMaxFrameBufferAcquireBuffers = 2; + common::V1_1::PixelFormat mFormat; + std::vector mCompositionLayers; + std::unique_ptr mRenderEngine; + std::vector mRenderLayers; + sp mGraphicBuffer; + DisplaySettings mDisplaySettings; +}; + +} // namespace vts +} // namespace V2_2 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp index 9f7e1cd22e..cc24774fff 100644 --- a/graphics/composer/2.2/vts/functional/Android.bp +++ b/graphics/composer/2.2/vts/functional/Android.bp @@ -20,6 +20,7 @@ cc_test { srcs: [ "VtsHalGraphicsComposerV2_2ReadbackTest.cpp", "VtsHalGraphicsComposerV2_2TargetTest.cpp", + "VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp", ], // TODO(b/64437680): Assume these libs are always available on the device. @@ -27,9 +28,19 @@ cc_test { "libfmq", "libhidlbase", "libhidltransport", + "libhwbinder", "libsync", + "libui", + "libgui", + "libEGL", + "libGLESv1_CM", + "libGLESv2", ], static_libs: [ + "librenderengine", + "libmath", + "libarect", + "libnativewindow", "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.allocator@3.0", "android.hardware.graphics.common@1.1", diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp new file mode 100644 index 0000000000..d694a5bab0 --- /dev/null +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp @@ -0,0 +1,262 @@ +/* + * Copyright 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 "graphics_composer_hidl_hal_readback_tests@2.2" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_2 { +namespace vts { +namespace { + +using android::GraphicBuffer; +using android::Rect; +using android::hardware::hidl_handle; +using common::V1_1::BufferUsage; +using common::V1_1::Dataspace; +using common::V1_1::PixelFormat; +using mapper::V2_1::IMapper; +using V2_1::Config; +using V2_1::Display; +using V2_1::vts::TestCommandReader; +using vts::Gralloc; + +// Test environment for graphics.composer +class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static GraphicsComposerHidlEnvironment* Instance() { + static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment; + return instance; + } + virtual void registerTestServices() override { registerTestService(); } + + private: + GraphicsComposerHidlEnvironment() {} + GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment); +}; + +class GraphicsCompositionComparisonTest : public ::testing::VtsHalHidlTargetTestBase { + protected: + using PowerMode = V2_1::IComposerClient::PowerMode; + void SetUp() override { + VtsHalHidlTargetTestBase::SetUp(); + ASSERT_NO_FATAL_FAILURE( + mComposer = std::make_unique( + GraphicsComposerHidlEnvironment::Instance()->getServiceName())); + ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); + mComposerCallback = new V2_1::vts::GraphicsComposerCallback; + mComposerClient->registerCallback(mComposerCallback); + + // assume the first display is primary and is never removed + mPrimaryDisplay = waitForFirstDisplay(); + Config activeConfig; + ASSERT_NO_FATAL_FAILURE(activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay)); + ASSERT_NO_FATAL_FAILURE( + mDisplayWidth = mComposerClient->getDisplayAttribute( + mPrimaryDisplay, activeConfig, IComposerClient::Attribute::WIDTH)); + ASSERT_NO_FATAL_FAILURE( + mDisplayHeight = mComposerClient->getDisplayAttribute( + mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT)); + + setTestColorModes(); + + // explicitly disable vsync + ASSERT_NO_FATAL_FAILURE(mComposerClient->setVsyncEnabled(mPrimaryDisplay, false)); + mComposerCallback->setVsyncAllowed(false); + + // set up command writer/reader and gralloc + mWriter = std::make_shared(1024); + mReader = std::make_unique(); + mGralloc = std::make_shared(); + + ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON)); + + ASSERT_NO_FATAL_FAILURE( + mTestRenderEngine = std::unique_ptr(new TestRenderEngine( + PixelFormat::RGBA_8888, + renderengine::RenderEngine::USE_COLOR_MANAGEMENT | + renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT))); + + renderengine::DisplaySettings clientCompositionDisplay; + clientCompositionDisplay.physicalDisplay = Rect(mDisplayWidth, mDisplayHeight); + clientCompositionDisplay.clip = clientCompositionDisplay.physicalDisplay; + clientCompositionDisplay.clearRegion = Region(clientCompositionDisplay.physicalDisplay); + + mTestRenderEngine->initGraphicBuffer( + static_cast(mDisplayWidth), static_cast(mDisplayHeight), 1, + static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN)); + mTestRenderEngine->setDisplaySettings(clientCompositionDisplay); + } + + void TearDown() override { + ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::OFF)); + EXPECT_EQ(0, mReader->mErrors.size()); + EXPECT_EQ(0, mReader->mCompositionChanges.size()); + if (mComposerCallback != nullptr) { + EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount()); + EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount()); + EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount()); + } + VtsHalHidlTargetTestBase::TearDown(); + } + + void clearCommandReaderState() { + mReader->mCompositionChanges.clear(); + mReader->mErrors.clear(); + } + + void writeLayers(const std::vector>& layers) { + for (auto layer : layers) { + layer->write(mWriter); + } + execute(); + } + + void execute() { + ASSERT_NO_FATAL_FAILURE(mComposerClient->execute(mReader.get(), mWriter.get())); + } + + std::unique_ptr mComposer; + std::shared_ptr mComposerClient; + + sp mComposerCallback; + // the first display and is assumed never to be removed + Display mPrimaryDisplay; + int32_t mDisplayWidth; + int32_t mDisplayHeight; + std::vector mTestColorModes; + std::shared_ptr mWriter; + std::unique_ptr mReader; + std::shared_ptr mGralloc; + std::unique_ptr mTestRenderEngine; + + bool mHasReadbackBuffer; + PixelFormat mPixelFormat; + Dataspace mDataspace; + + private: + Display waitForFirstDisplay() { + while (true) { + std::vector displays = mComposerCallback->getDisplays(); + if (displays.empty()) { + usleep(5 * 1000); + continue; + } + return displays[0]; + } + } + + void setTestColorModes() { + mTestColorModes.clear(); + mComposerClient->getRaw()->getColorModes_2_2(mPrimaryDisplay, [&](const auto& tmpError, + const auto& tmpModes) { + ASSERT_EQ(Error::NONE, tmpError); + for (ColorMode mode : tmpModes) { + if (std::find(ReadbackHelper::colorModes.begin(), ReadbackHelper::colorModes.end(), + mode) != ReadbackHelper::colorModes.end()) { + mTestColorModes.push_back(mode); + } + } + }); + } +}; + +TEST_F(GraphicsCompositionComparisonTest, SingleSolidColorLayer) { + for (ColorMode mode : mTestColorModes) { + std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" + << std::endl; + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); + + if (!mHasReadbackBuffer) { + std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + auto layer = std::make_shared(mComposerClient, mPrimaryDisplay); + IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setColor(BLUE); + layer->setDisplayFrame(coloredSquare); + layer->setZOrder(10); + + std::vector> layers = {layer}; + + // expected color for each pixel + std::vector expectedColors(mDisplayWidth * mDisplayHeight); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + // if hwc cannot handle and asks for composition change, + // just succeed the test + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(layers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); + } +} + +} // namespace +} // namespace vts +} // namespace V2_2 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp index 6b30df7923..72c9496056 100644 --- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2018 The Android Open Source Project + * Copyright 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. From 1b5692ea057591b4467469d6176c2fed06462fdc Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Tue, 2 Jul 2019 14:23:09 -0700 Subject: [PATCH 0023/1022] [Cleanup] Properly export lib headers. Properly export lib headers to avoid copying everything when upgrade composer version. Minor: Remove VTS team as OWNERS of non-VTS directory. BUG: 135929065 Test: build and boot Change-Id: I4c3544490fcf043ff6bda2312a00aed015d0d5fc --- graphics/composer/2.1/utils/vts/Android.bp | 9 +++++++++ graphics/composer/2.2/utils/OWNERS | 4 ---- .../2.2/utils/command-buffer/Android.bp | 7 ++++++- graphics/composer/2.2/utils/vts/Android.bp | 17 +++++++---------- graphics/composer/2.3/utils/OWNERS | 4 ---- .../2.3/utils/command-buffer/Android.bp | 9 ++++++--- graphics/composer/2.3/utils/vts/Android.bp | 19 +++++++------------ 7 files changed, 35 insertions(+), 34 deletions(-) diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp index fcb327f365..88b1a8b3d7 100644 --- a/graphics/composer/2.1/utils/vts/Android.bp +++ b/graphics/composer/2.1/utils/vts/Android.bp @@ -28,9 +28,18 @@ cc_library_static { "android.hardware.graphics.mapper@2.0-vts", "android.hardware.graphics.mapper@3.0-vts", ], + export_static_lib_headers: [ + "VtsHalHidlTargetTestBase", + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.mapper@2.0-vts", + "android.hardware.graphics.mapper@3.0-vts", + ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", ], + export_header_lib_headers: [ + "android.hardware.graphics.composer@2.1-command-buffer", + ], cflags: [ "-O0", "-g", diff --git a/graphics/composer/2.2/utils/OWNERS b/graphics/composer/2.2/utils/OWNERS index a17a50c1b9..3f1e82c85a 100644 --- a/graphics/composer/2.2/utils/OWNERS +++ b/graphics/composer/2.2/utils/OWNERS @@ -3,7 +3,3 @@ courtneygo@google.com lpy@google.com stoza@google.com vhau@google.com - -# VTS team -yim@google.com -zhuoyao@google.com diff --git a/graphics/composer/2.2/utils/command-buffer/Android.bp b/graphics/composer/2.2/utils/command-buffer/Android.bp index efaabd46f4..c4ceaabe9f 100644 --- a/graphics/composer/2.2/utils/command-buffer/Android.bp +++ b/graphics/composer/2.2/utils/command-buffer/Android.bp @@ -3,11 +3,16 @@ cc_library_headers { defaults: ["hidl_defaults"], vendor_available: true, shared_libs: [ - "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.composer@2.2", + ], + export_shared_lib_headers: [ "android.hardware.graphics.composer@2.2", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", ], + export_header_lib_headers: [ + "android.hardware.graphics.composer@2.1-command-buffer", + ], export_include_dirs: ["include"], } diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp index b813688f89..1754a43dbb 100644 --- a/graphics/composer/2.2/utils/vts/Android.bp +++ b/graphics/composer/2.2/utils/vts/Android.bp @@ -26,28 +26,25 @@ cc_library_static { "libui", ], static_libs: [ - "librenderengine", - "libmath", - "libarect", - "libnativewindow", "VtsHalHidlTargetTestBase", - "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.1-vts", "android.hardware.graphics.composer@2.2", - "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", + "libarect", + "libmath", + "libnativewindow", + "librenderengine", ], export_static_lib_headers: [ + "VtsHalHidlTargetTestBase", "android.hardware.graphics.composer@2.1-vts", + "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.mapper@2.1-vts", ], header_libs: [ - "android.hardware.graphics.composer@2.1-command-buffer", "android.hardware.graphics.composer@2.2-command-buffer", ], export_header_lib_headers: [ - "android.hardware.graphics.composer@2.1-command-buffer", "android.hardware.graphics.composer@2.2-command-buffer", ], cflags: [ diff --git a/graphics/composer/2.3/utils/OWNERS b/graphics/composer/2.3/utils/OWNERS index b3ea6bef7b..cc6d937cad 100644 --- a/graphics/composer/2.3/utils/OWNERS +++ b/graphics/composer/2.3/utils/OWNERS @@ -2,7 +2,3 @@ lpy@google.com stoza@google.com vhau@google.com - -# VTS team -yim@google.com -zhuoyao@google.com diff --git a/graphics/composer/2.3/utils/command-buffer/Android.bp b/graphics/composer/2.3/utils/command-buffer/Android.bp index c48fe7a53c..36ac297588 100644 --- a/graphics/composer/2.3/utils/command-buffer/Android.bp +++ b/graphics/composer/2.3/utils/command-buffer/Android.bp @@ -3,12 +3,15 @@ cc_library_headers { defaults: ["hidl_defaults"], vendor_available: true, shared_libs: [ - "android.hardware.graphics.composer@2.1", - "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.composer@2.3", + ], + export_shared_lib_headers: [ "android.hardware.graphics.composer@2.3", ], header_libs: [ - "android.hardware.graphics.composer@2.1-command-buffer", + "android.hardware.graphics.composer@2.2-command-buffer", + ], + export_header_lib_headers: [ "android.hardware.graphics.composer@2.2-command-buffer", ], export_include_dirs: ["include"], diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp index 036ef69cf3..f65a9c41ae 100644 --- a/graphics/composer/2.3/utils/vts/Android.bp +++ b/graphics/composer/2.3/utils/vts/Android.bp @@ -21,22 +21,17 @@ cc_library_static { "ComposerVts.cpp", ], static_libs: [ - "VtsHalHidlTargetTestBase", - "android.hardware.graphics.composer@2.1", - "android.hardware.graphics.composer@2.1-vts", - "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.2-vts", "android.hardware.graphics.composer@2.3", - "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", + ], + export_static_lib_headers: [ + "android.hardware.graphics.composer@2.2-vts", + "android.hardware.graphics.composer@2.3", ], header_libs: [ - "android.hardware.graphics.composer@2.1-command-buffer", - "android.hardware.graphics.composer@2.2-command-buffer", + "android.hardware.graphics.composer@2.3-command-buffer", + ], + export_header_lib_headers: [ "android.hardware.graphics.composer@2.3-command-buffer", ], cflags: [ From 1d6b4659972010b9999dc77fbe65892b8b69d6da Mon Sep 17 00:00:00 2001 From: Slava Shklyaev Date: Tue, 14 May 2019 14:15:14 +0100 Subject: [PATCH 0024/1022] Refactor NNAPI VTS to remove unreasonable dependence between versions To make it easier to create the next version of NNAPI, this change removes the following nonsensical dependence: - NNAPI 1.0 VTS depends on NNAPI 1.1 and 1.2 - NNAPI 1.1 VTS depends on NNAPI 1.2 In particular, I made the following changes: - split GeneratedTestHarness.cpp into three separate implementations, - created a restricted version of Callbacks.h for 1.0 and 1.1, - removed the dependency on frameworks/ml/nn/HalInterfaces.h, - refactored Android.bp files for more autonomy between 1.0, 1.1, and 1.2, - consolidated some common code into Utils.h, - created structure for sharing code between VTS versions (VtsHalNeuralNetworksV1_0_utils). Bug: 74827824 Bug: 124462414 Test: VtsHalNeuralnetworksV1_0TargetTest Test: VtsHalNeuralnetworksV1_1TargetTest Test: VtsHalNeuralnetworksV1_1CompatV1_0TargetTest Test: VtsHalNeuralnetworksV1_2TargetTest Test: VtsHalNeuralnetworksV1_2CompatV1_0TargetTest Test: VtsHalNeuralnetworksV1_2CompatV1_1TargetTest Change-Id: I4243d0b5e574255cef1070850f4d0a284f65f54e --- neuralnetworks/1.0/vts/functional/Android.bp | 23 +- .../1.0/vts/functional/Callbacks.cpp | 36 +- .../vts/functional/GeneratedTestHarness.cpp | 460 ++---------------- .../1.0/vts/functional/GeneratedTestHarness.h | 26 +- ...eratedTests.cpp => GeneratedTestsV1_0.cpp} | 18 +- neuralnetworks/1.0/vts/functional/Utils.cpp | 60 +++ .../1.0/vts/functional/ValidateModel.cpp | 6 +- .../1.0/vts/functional/ValidateRequest.cpp | 27 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 4 +- .../1.0/vts/functional/VtsHalNeuralnetworks.h | 6 +- .../vts/functional/include/1.0/Callbacks.h | 326 +++++++++++++ .../1.0/vts/functional/include/1.0/Utils.h | 56 +++ neuralnetworks/1.1/vts/functional/Android.bp | 41 +- .../vts/functional/GeneratedTestHarness.cpp | 232 +++++++++ .../1.1/vts/functional/GeneratedTestHarness.h | 40 ++ .../1.1/vts/functional/GeneratedTestsV1_0.cpp | 19 +- ...eratedTests.cpp => GeneratedTestsV1_1.cpp} | 19 +- .../1.1/vts/functional/ValidateModel.cpp | 95 ++-- .../1.1/vts/functional/ValidateRequest.cpp | 58 +-- .../vts/functional/VtsHalNeuralnetworks.cpp | 4 +- .../1.1/vts/functional/VtsHalNeuralnetworks.h | 6 +- neuralnetworks/1.2/vts/functional/Android.bp | 46 +- .../1.2/vts/functional/Callbacks.cpp | 173 +++++++ .../functional/CompilationCachingTests.cpp | 3 +- .../vts/functional/GeneratedTestHarness.cpp | 452 +++++++++++++++++ .../1.2/vts/functional/GeneratedTestHarness.h | 51 ++ .../1.2/vts/functional/GeneratedTestsV1_0.cpp | 14 +- .../1.2/vts/functional/GeneratedTestsV1_1.cpp | 14 +- ...eratedTests.cpp => GeneratedTestsV1_2.cpp} | 14 +- .../1.2/vts/functional/ValidateBurst.cpp | 2 +- .../1.2/vts/functional/ValidateModel.cpp | 71 +-- .../1.2/vts/functional/ValidateRequest.cpp | 49 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 2 +- .../1.2/vts/functional/VtsHalNeuralnetworks.h | 49 +- .../vts/functional/include/1.2}/Callbacks.h | 47 +- 35 files changed, 1761 insertions(+), 788 deletions(-) rename neuralnetworks/1.0/vts/functional/{GeneratedTests.cpp => GeneratedTestsV1_0.cpp} (86%) create mode 100644 neuralnetworks/1.0/vts/functional/Utils.cpp create mode 100644 neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h create mode 100644 neuralnetworks/1.0/vts/functional/include/1.0/Utils.h create mode 100644 neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp create mode 100644 neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h rename neuralnetworks/1.1/vts/functional/{GeneratedTests.cpp => GeneratedTestsV1_1.cpp} (83%) create mode 100644 neuralnetworks/1.2/vts/functional/Callbacks.cpp create mode 100644 neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp create mode 100644 neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h rename neuralnetworks/1.2/vts/functional/{GeneratedTests.cpp => GeneratedTestsV1_2.cpp} (97%) rename neuralnetworks/{1.0/vts/functional => 1.2/vts/functional/include/1.2}/Callbacks.h (94%) diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp index 0fb18f1a56..0d70816f31 100644 --- a/neuralnetworks/1.0/vts/functional/Android.bp +++ b/neuralnetworks/1.0/vts/functional/Android.bp @@ -15,21 +15,19 @@ // cc_library_static { - name: "VtsHalNeuralnetworksTest_utils", + name: "VtsHalNeuralNetworksV1_0_utils", srcs: [ "Callbacks.cpp", - "GeneratedTestHarness.cpp", + "Utils.cpp", ], defaults: ["VtsHalTargetTestDefaults"], - export_include_dirs: ["."], + export_include_dirs: ["include"], shared_libs: [ "libfmq", "libnativewindow", ], static_libs: [ "android.hardware.neuralnetworks@1.0", - "android.hardware.neuralnetworks@1.1", - "android.hardware.neuralnetworks@1.2", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "libgmock", @@ -44,12 +42,13 @@ cc_library_static { } cc_defaults { - name: "VtsHalNeuralNetworksTargetTestDefaults", + name: "VtsHalNeuralNetworksV1_0TargetTestDefaults", defaults: ["VtsHalTargetTestDefaults"], srcs: [ "ValidateModel.cpp", "ValidateRequest.cpp", "VtsHalNeuralnetworks.cpp", + "GeneratedTestHarness.cpp", ], shared_libs: [ "libfmq", @@ -57,14 +56,12 @@ cc_defaults { ], static_libs: [ "android.hardware.neuralnetworks@1.0", - "android.hardware.neuralnetworks@1.1", - "android.hardware.neuralnetworks@1.2", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "libgmock", "libhidlmemory", "libneuralnetworks_utils", - "VtsHalNeuralnetworksTest_utils", + "VtsHalNeuralNetworksV1_0_utils", ], header_libs: [ "libneuralnetworks_headers", @@ -76,19 +73,19 @@ cc_defaults { cc_test { name: "VtsHalNeuralnetworksV1_0TargetTest", - defaults: ["VtsHalNeuralNetworksTargetTestDefaults"], + defaults: ["VtsHalNeuralNetworksV1_0TargetTestDefaults"], srcs: [ "BasicTests.cpp", - "GeneratedTests.cpp", + "GeneratedTestsV1_0.cpp", ], } cc_test { name: "PresubmitHalNeuralnetworksV1_0TargetTest", - defaults: ["VtsHalNeuralNetworksTargetTestDefaults"], + defaults: ["VtsHalNeuralNetworksV1_0TargetTestDefaults"], srcs: [ "BasicTests.cpp", - "GeneratedTests.cpp", + "GeneratedTestsV1_0.cpp", ], cflags: [ "-DPRESUBMIT_NOT_VTS", diff --git a/neuralnetworks/1.0/vts/functional/Callbacks.cpp b/neuralnetworks/1.0/vts/functional/Callbacks.cpp index c30702cd99..2b5723dc3d 100644 --- a/neuralnetworks/1.0/vts/functional/Callbacks.cpp +++ b/neuralnetworks/1.0/vts/functional/Callbacks.cpp @@ -14,13 +14,13 @@ * limitations under the License. */ -#include "Callbacks.h" +#include "1.0/Callbacks.h" #include namespace android { namespace hardware { namespace neuralnetworks { -namespace V1_2 { +namespace V1_0 { namespace implementation { CallbackBase::CallbackBase() : mNotified(false) {} @@ -111,14 +111,6 @@ Return PreparedModelCallback::notify(ErrorStatus errorStatus, return Void(); } -Return PreparedModelCallback::notify_1_2(ErrorStatus errorStatus, - const sp& preparedModel) { - mErrorStatus = errorStatus; - mPreparedModel = preparedModel; - CallbackBase::notify(); - return Void(); -} - ErrorStatus PreparedModelCallback::getStatus() { wait(); return mErrorStatus; @@ -135,18 +127,6 @@ ExecutionCallback::~ExecutionCallback() {} Return ExecutionCallback::notify(ErrorStatus errorStatus) { mErrorStatus = errorStatus; - mOutputShapes = {}; - mTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; - CallbackBase::notify(); - return Void(); -} - -Return ExecutionCallback::notify_1_2(ErrorStatus errorStatus, - const hidl_vec& outputShapes, - const Timing& timing) { - mErrorStatus = errorStatus; - mOutputShapes = outputShapes; - mTiming = timing; CallbackBase::notify(); return Void(); } @@ -156,18 +136,8 @@ ErrorStatus ExecutionCallback::getStatus() { return mErrorStatus; } -const std::vector& ExecutionCallback::getOutputShapes() { - wait(); - return mOutputShapes; -} - -Timing ExecutionCallback::getTiming() { - wait(); - return mTiming; -} - } // namespace implementation -} // namespace V1_2 +} // namespace V1_0 } // namespace neuralnetworks } // namespace hardware } // namespace android diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp index c819b52b8f..603054dddf 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp @@ -15,129 +15,47 @@ */ #include "GeneratedTestHarness.h" -#include "Callbacks.h" -#include "ExecutionBurstController.h" +#include "1.0/Callbacks.h" +#include "1.0/Utils.h" +#include "MemoryUtils.h" #include "TestHarness.h" -#include "Utils.h" #include #include -#include #include -#include #include -#include -#include -#include -#include -#include #include #include #include + #include namespace android { namespace hardware { namespace neuralnetworks { - namespace generated_tests { -using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; -using ::test_helper::bool8; + +using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; +using ::android::hardware::neuralnetworks::V1_0::IDevice; +using ::android::hardware::neuralnetworks::V1_0::IPreparedModel; +using ::android::hardware::neuralnetworks::V1_0::Model; +using ::android::hardware::neuralnetworks::V1_0::Request; +using ::android::hardware::neuralnetworks::V1_0::RequestArgument; +using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; +using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; +using ::android::hidl::memory::V1_0::IMemory; using ::test_helper::compare; -using ::test_helper::expectMultinomialDistributionWithinTolerance; using ::test_helper::filter; using ::test_helper::for_all; -using ::test_helper::for_each; using ::test_helper::MixedTyped; using ::test_helper::MixedTypedExample; using ::test_helper::resize_accordingly; -using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; - -template -void copy_back_(std::map>* dst, const std::vector& ra, - char* src) { - for_each(*dst, [&ra, src](int index, std::vector& m) { - ASSERT_EQ(m.size(), ra[index].location.length / sizeof(T)); - char* begin = src + ra[index].location.offset; - memcpy(m.data(), begin, ra[index].location.length); - }); -} - -void copy_back(MixedTyped* dst, const std::vector& ra, char* src) { - copy_back_(&dst->float32Operands, ra, src); - copy_back_(&dst->int32Operands, ra, src); - copy_back_(&dst->quant8AsymmOperands, ra, src); - copy_back_(&dst->quant16SymmOperands, ra, src); - copy_back_(&dst->float16Operands, ra, src); - copy_back_(&dst->bool8Operands, ra, src); - copy_back_(&dst->quant8ChannelOperands, ra, src); - copy_back_(&dst->quant16AsymmOperands, ra, src); - copy_back_(&dst->quant8SymmOperands, ra, src); - static_assert(9 == MixedTyped::kNumTypes, - "Number of types in MixedTyped changed, but copy_back function wasn't updated"); -} - -static bool isZeroSized(const MixedTyped& example, uint32_t index) { - for (auto i : example.operandDimensions.at(index)) { - if (i == 0) return true; - } - return false; -} // Top level driver for models and examples generated by test_generator.py // Test driver for those generated from ml/nn/runtime/test/spec -static Return ExecutePreparedModel(sp& preparedModel, - const Request& request, MeasureTiming, - sp& callback) { - return preparedModel->execute(request, callback); -} -static Return ExecutePreparedModel(sp& preparedModel, - const Request& request, MeasureTiming measure, - sp& callback) { - return preparedModel->execute_1_2(request, measure, callback); -} -static Return ExecutePreparedModel(sp&, const Request&, - MeasureTiming, hidl_vec*, Timing*) { - ADD_FAILURE() << "asking for synchronous execution at V1_0"; - return ErrorStatus::GENERAL_FAILURE; -} -static Return ExecutePreparedModel(sp& preparedModel, - const Request& request, MeasureTiming measure, - hidl_vec* outputShapes, - Timing* timing) { - ErrorStatus result; - Return ret = preparedModel->executeSynchronously( - request, measure, - [&result, outputShapes, timing](ErrorStatus error, const hidl_vec& shapes, - const Timing& time) { - result = error; - *outputShapes = shapes; - *timing = time; - }); - if (!ret.isOk()) { - return ErrorStatus::GENERAL_FAILURE; - } - return result; -} -static std::unique_ptr<::android::nn::ExecutionBurstController> CreateBurst( - const sp&) { - ADD_FAILURE() << "asking for burst execution at V1_0"; - return nullptr; -} -static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst( - const sp& preparedModel) { - return ::android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true); -} -enum class Executor { ASYNC, SYNC, BURST }; -enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; -const float kDefaultAtol = 1e-5f; -const float kDefaultRtol = 1e-5f; -template -void EvaluatePreparedModel(sp& preparedModel, std::function is_ignored, - const std::vector& examples, - bool hasRelaxedFloat32Model, float fpAtol, float fpRtol, - Executor executor, MeasureTiming measure, OutputType outputType) { +void EvaluatePreparedModel(sp& preparedModel, std::function is_ignored, + const std::vector& examples, float fpAtol, + float fpRtol) { const uint32_t INPUT = 0; const uint32_t OUTPUT = 1; @@ -147,14 +65,7 @@ void EvaluatePreparedModel(sp& preparedModel, std::function inputs_info, outputs_info; uint32_t inputSize = 0, outputSize = 0; @@ -163,11 +74,13 @@ void EvaluatePreparedModel(sp& preparedModel, std::function(index)) inputs_info.resize(index + 1); RequestArgument arg = { - .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast(s)}, - .dimensions = {}, + .location = {.poolIndex = INPUT, + .offset = 0, + .length = static_cast(s)}, + .dimensions = {}, }; RequestArgument arg_empty = { - .hasNoValue = true, + .hasNoValue = true, }; inputs_info[index] = s ? arg : arg_empty; inputSize += s; @@ -185,31 +98,17 @@ void EvaluatePreparedModel(sp& preparedModel, std::function(index)) outputs_info.resize(index + 1); - if (index == 0) { - // On OutputType::INSUFFICIENT, set the output operand with index 0 with - // buffer size one byte less than needed. - if (outputType == OutputType::INSUFFICIENT) { - if (s > 1 && !isZeroSized(golden, index)) { - s -= 1; - } else { - sizeLargerThanOne = false; - } - } - } RequestArgument arg = { - .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast(s)}, - .dimensions = {}, + .location = {.poolIndex = OUTPUT, + .offset = 0, + .length = static_cast(s)}, + .dimensions = {}, }; outputs_info[index] = arg; outputSize += s; }); - // If output0 does not have size larger than one byte, - // we can not provide an insufficient buffer - if (!sizeLargerThanOne && outputType == OutputType::INSUFFICIENT) return; // Compute offset for outputs 1 and so on { size_t offset = 0; @@ -248,107 +147,17 @@ void EvaluatePreparedModel(sp& preparedModel, std::function outputShapes; - Timing timing; - switch (executor) { - case Executor::ASYNC: { - SCOPED_TRACE("asynchronous"); + // launch execution + sp executionCallback = new ExecutionCallback(); + ASSERT_NE(nullptr, executionCallback.get()); + Return executionLaunchStatus = + preparedModel->execute(request, executionCallback); + ASSERT_TRUE(executionLaunchStatus.isOk()); + EXPECT_EQ(ErrorStatus::NONE, static_cast(executionLaunchStatus)); - // launch execution - sp executionCallback = new ExecutionCallback(); - ASSERT_NE(nullptr, executionCallback.get()); - Return executionLaunchStatus = - ExecutePreparedModel(preparedModel, request, measure, executionCallback); - ASSERT_TRUE(executionLaunchStatus.isOk()); - EXPECT_EQ(ErrorStatus::NONE, static_cast(executionLaunchStatus)); - - // retrieve execution status - executionCallback->wait(); - executionStatus = executionCallback->getStatus(); - outputShapes = executionCallback->getOutputShapes(); - timing = executionCallback->getTiming(); - - break; - } - case Executor::SYNC: { - SCOPED_TRACE("synchronous"); - - // execute - Return executionReturnStatus = ExecutePreparedModel( - preparedModel, request, measure, &outputShapes, &timing); - ASSERT_TRUE(executionReturnStatus.isOk()); - executionStatus = static_cast(executionReturnStatus); - - break; - } - case Executor::BURST: { - SCOPED_TRACE("burst"); - - // create burst - const std::shared_ptr<::android::nn::ExecutionBurstController> controller = - CreateBurst(preparedModel); - ASSERT_NE(nullptr, controller.get()); - - // create memory keys - std::vector keys(request.pools.size()); - for (size_t i = 0; i < keys.size(); ++i) { - keys[i] = reinterpret_cast(&request.pools[i]); - } - - // execute burst - std::tie(executionStatus, outputShapes, timing) = - controller->compute(request, measure, keys); - - break; - } - } - - if (outputType != OutputType::FULLY_SPECIFIED && - executionStatus == ErrorStatus::GENERAL_FAILURE) { - LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " - "execute model that it does not support."; - std::cout << "[ ] Early termination of test because vendor service cannot " - "execute model that it does not support." - << std::endl; - GTEST_SKIP(); - } - if (measure == MeasureTiming::NO) { - EXPECT_EQ(UINT64_MAX, timing.timeOnDevice); - EXPECT_EQ(UINT64_MAX, timing.timeInDriver); - } else { - if (timing.timeOnDevice != UINT64_MAX && timing.timeInDriver != UINT64_MAX) { - EXPECT_LE(timing.timeOnDevice, timing.timeInDriver); - } - } - - switch (outputType) { - case OutputType::FULLY_SPECIFIED: - // If the model output operands are fully specified, outputShapes must be either - // either empty, or have the same number of elements as the number of outputs. - ASSERT_EQ(ErrorStatus::NONE, executionStatus); - ASSERT_TRUE(outputShapes.size() == 0 || - outputShapes.size() == test.operandDimensions.size()); - break; - case OutputType::UNSPECIFIED: - // If the model output operands are not fully specified, outputShapes must have - // the same number of elements as the number of outputs. - ASSERT_EQ(ErrorStatus::NONE, executionStatus); - ASSERT_EQ(outputShapes.size(), test.operandDimensions.size()); - break; - case OutputType::INSUFFICIENT: - ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus); - ASSERT_EQ(outputShapes.size(), test.operandDimensions.size()); - ASSERT_FALSE(outputShapes[0].isSufficient); - return; - } - // Go through all outputs, overwrite output dimensions with returned output shapes - if (outputShapes.size() > 0) { - for_each(test.operandDimensions, - [&outputShapes](int idx, std::vector& dim) { - dim = outputShapes[idx].dimensions; - }); - } + // retrieve execution status + executionCallback->wait(); + ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus()); // validate results outputMemory->read(); @@ -360,89 +169,22 @@ void EvaluatePreparedModel(sp& preparedModel, std::function 0) { - expectMultinomialDistributionWithinTolerance(test, example); - } - } -} -template -void EvaluatePreparedModel(sp& preparedModel, std::function is_ignored, - const std::vector& examples, - bool hasRelaxedFloat32Model, Executor executor, MeasureTiming measure, - OutputType outputType) { - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, kDefaultAtol, - kDefaultRtol, executor, measure, outputType); -} - -void EvaluatePreparedModel(sp& preparedModel, - std::function is_ignored, - const std::vector& examples, - bool hasRelaxedFloat32Model, bool testDynamicOutputShape) { - if (testDynamicOutputShape) { - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::ASYNC, MeasureTiming::NO, OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::SYNC, MeasureTiming::NO, OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::BURST, MeasureTiming::NO, OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::ASYNC, MeasureTiming::YES, OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::SYNC, MeasureTiming::YES, OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::BURST, MeasureTiming::YES, OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::ASYNC, MeasureTiming::NO, OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::SYNC, MeasureTiming::NO, OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::BURST, MeasureTiming::NO, OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::ASYNC, MeasureTiming::YES, OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::SYNC, MeasureTiming::YES, OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::BURST, MeasureTiming::YES, OutputType::INSUFFICIENT); - } else { - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::ASYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::SYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::BURST, MeasureTiming::NO, OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::ASYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::SYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::BURST, MeasureTiming::YES, OutputType::FULLY_SPECIFIED); } } -static void getPreparedModel(sp callback, - sp* preparedModel) { - *preparedModel = callback->getPreparedModel(); -} -static void getPreparedModel(sp callback, - sp* preparedModel) { - sp preparedModelV1_0 = callback->getPreparedModel(); - *preparedModel = V1_2::IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr); -} - -void Execute(const sp& device, std::function create_model, +void Execute(const sp& device, std::function create_model, std::function is_ignored, const std::vector& examples) { - V1_0::Model model = create_model(); + Model model = create_model(); // see if service can handle model bool fullySupportsModel = false; Return supportedCall = device->getSupportedOperations( - model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { - ASSERT_EQ(ErrorStatus::NONE, status); - ASSERT_NE(0ul, supported.size()); - fullySupportsModel = - std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; }); - }); + model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { + ASSERT_EQ(ErrorStatus::NONE, status); + ASSERT_NE(0ul, supported.size()); + fullySupportsModel = std::all_of(supported.begin(), supported.end(), + [](bool valid) { return valid; }); + }); ASSERT_TRUE(supportedCall.isOk()); // launch prepare model @@ -455,8 +197,7 @@ void Execute(const sp& device, std::function c // retrieve prepared model preparedModelCallback->wait(); ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); - sp preparedModel; - getPreparedModel(preparedModelCallback, &preparedModel); + sp preparedModel = preparedModelCallback->getPreparedModel(); // early termination if vendor service cannot fully prepare model if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { @@ -472,115 +213,10 @@ void Execute(const sp& device, std::function c ASSERT_NE(nullptr, preparedModel.get()); float fpAtol = 1e-5f, fpRtol = 5.0f * 1.1920928955078125e-7f; - EvaluatePreparedModel(preparedModel, is_ignored, examples, - /*hasRelaxedFloat32Model=*/false, fpAtol, fpRtol, Executor::ASYNC, - MeasureTiming::NO, OutputType::FULLY_SPECIFIED); -} - -void Execute(const sp& device, std::function create_model, - std::function is_ignored, const std::vector& examples) { - V1_1::Model model = create_model(); - - // see if service can handle model - bool fullySupportsModel = false; - Return supportedCall = device->getSupportedOperations_1_1( - model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { - ASSERT_EQ(ErrorStatus::NONE, status); - ASSERT_NE(0ul, supported.size()); - fullySupportsModel = - std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; }); - }); - ASSERT_TRUE(supportedCall.isOk()); - - // launch prepare model - sp preparedModelCallback = new PreparedModelCallback(); - ASSERT_NE(nullptr, preparedModelCallback.get()); - Return prepareLaunchStatus = device->prepareModel_1_1( - model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback); - ASSERT_TRUE(prepareLaunchStatus.isOk()); - ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); - - // retrieve prepared model - preparedModelCallback->wait(); - ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); - sp preparedModel; - getPreparedModel(preparedModelCallback, &preparedModel); - - // early termination if vendor service cannot fully prepare model - if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { - ASSERT_EQ(nullptr, preparedModel.get()); - LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " - "prepare model that it does not support."; - std::cout << "[ ] Early termination of test because vendor service cannot " - "prepare model that it does not support." - << std::endl; - GTEST_SKIP(); - } - EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); - ASSERT_NE(nullptr, preparedModel.get()); - - EvaluatePreparedModel(preparedModel, is_ignored, examples, - model.relaxComputationFloat32toFloat16, 1e-5f, 1e-5f, Executor::ASYNC, - MeasureTiming::NO, OutputType::FULLY_SPECIFIED); -} - -void PrepareModel(const sp& device, const V1_2::Model& model, - sp* preparedModel) { - // see if service can handle model - bool fullySupportsModel = false; - Return supportedCall = device->getSupportedOperations_1_2( - model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { - ASSERT_EQ(ErrorStatus::NONE, status); - ASSERT_NE(0ul, supported.size()); - fullySupportsModel = - std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; }); - }); - ASSERT_TRUE(supportedCall.isOk()); - - // launch prepare model - sp preparedModelCallback = new PreparedModelCallback(); - ASSERT_NE(nullptr, preparedModelCallback.get()); - Return prepareLaunchStatus = device->prepareModel_1_2( - model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec(), - hidl_vec(), HidlToken(), preparedModelCallback); - ASSERT_TRUE(prepareLaunchStatus.isOk()); - ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); - - // retrieve prepared model - preparedModelCallback->wait(); - ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); - getPreparedModel(preparedModelCallback, preparedModel); - - // early termination if vendor service cannot fully prepare model - if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { - ASSERT_EQ(nullptr, preparedModel->get()); - LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " - "prepare model that it does not support."; - std::cout << "[ ] Early termination of test because vendor service cannot " - "prepare model that it does not support." - << std::endl; - return; - } - EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); - ASSERT_NE(nullptr, preparedModel->get()); -} - -// TODO: Reduce code duplication. -void Execute(const sp& device, std::function create_model, - std::function is_ignored, const std::vector& examples, - bool testDynamicOutputShape) { - V1_2::Model model = create_model(); - sp preparedModel = nullptr; - PrepareModel(device, model, &preparedModel); - if (preparedModel == nullptr) { - GTEST_SKIP(); - } - EvaluatePreparedModel(preparedModel, is_ignored, examples, - model.relaxComputationFloat32toFloat16, testDynamicOutputShape); + EvaluatePreparedModel(preparedModel, is_ignored, examples, fpAtol, fpRtol); } } // namespace generated_tests - } // namespace neuralnetworks } // namespace hardware } // namespace android diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h index c7d23993f4..11950d91f0 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h @@ -14,14 +14,11 @@ * limitations under the License. */ -#ifndef VTS_HAL_NEURALNETWORKS_GENERATED_TEST_HARNESS_H -#define VTS_HAL_NEURALNETWORKS_GENERATED_TEST_HARNESS_H - -#include "TestHarness.h" +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_GENERATED_TEST_HARNESS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_GENERATED_TEST_HARNESS_H #include -#include -#include +#include "TestHarness.h" namespace android { namespace hardware { @@ -30,28 +27,13 @@ namespace neuralnetworks { namespace generated_tests { using ::test_helper::MixedTypedExample; -void PrepareModel(const sp& device, const V1_2::Model& model, - sp* preparedModel); - -void EvaluatePreparedModel(sp& preparedModel, - std::function is_ignored, - const std::vector& examples, - bool hasRelaxedFloat32Model, bool testDynamicOutputShape); - void Execute(const sp& device, std::function create_model, std::function is_ignored, const std::vector& examples); -void Execute(const sp& device, std::function create_model, - std::function is_ignored, const std::vector& examples); - -void Execute(const sp& device, std::function create_model, - std::function is_ignored, const std::vector& examples, - bool testDynamicOutputShape = false); - } // namespace generated_tests } // namespace neuralnetworks } // namespace hardware } // namespace android -#endif // VTS_HAL_NEURALNETWORKS_GENERATED_TEST_HARNESS_H +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_GENERATED_TEST_HARNESS_H diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestsV1_0.cpp similarity index 86% rename from neuralnetworks/1.0/vts/functional/GeneratedTests.cpp rename to neuralnetworks/1.0/vts/functional/GeneratedTestsV1_0.cpp index d1c7de322f..74946a5cae 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestsV1_0.cpp @@ -16,17 +16,16 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" -#include "VtsHalNeuralnetworks.h" - -#include "Callbacks.h" -#include "GeneratedTestHarness.h" -#include "TestHarness.h" -#include "Utils.h" - #include #include #include +#include "1.0/Callbacks.h" +#include "GeneratedTestHarness.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "VtsHalNeuralnetworks.h" + namespace android { namespace hardware { namespace neuralnetworks { @@ -34,8 +33,9 @@ namespace V1_0 { namespace vts { namespace functional { -using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; +using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; +using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; +using ::android::hidl::memory::V1_0::IMemory; using ::android::nn::allocateSharedMemory; using ::test_helper::MixedTypedExample; diff --git a/neuralnetworks/1.0/vts/functional/Utils.cpp b/neuralnetworks/1.0/vts/functional/Utils.cpp new file mode 100644 index 0000000000..521e524687 --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/Utils.cpp @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#include "GeneratedTestHarness.h" +#include "TestHarness.h" + +#include + +#include +#include +#include + +namespace android { +namespace hardware { +namespace neuralnetworks { + +using ::android::hardware::neuralnetworks::V1_0::RequestArgument; +using ::test_helper::for_each; +using ::test_helper::MixedTyped; + +template +void copy_back_(std::map>* dst, const std::vector& ra, + char* src) { + for_each(*dst, [&ra, src](int index, std::vector& m) { + ASSERT_EQ(m.size(), ra[index].location.length / sizeof(T)); + char* begin = src + ra[index].location.offset; + memcpy(m.data(), begin, ra[index].location.length); + }); +} + +void copy_back(MixedTyped* dst, const std::vector& ra, char* src) { + copy_back_(&dst->float32Operands, ra, src); + copy_back_(&dst->int32Operands, ra, src); + copy_back_(&dst->quant8AsymmOperands, ra, src); + copy_back_(&dst->quant16SymmOperands, ra, src); + copy_back_(&dst->float16Operands, ra, src); + copy_back_(&dst->bool8Operands, ra, src); + copy_back_(&dst->quant8ChannelOperands, ra, src); + copy_back_(&dst->quant16AsymmOperands, ra, src); + copy_back_(&dst->quant8SymmOperands, ra, src); + static_assert(9 == MixedTyped::kNumTypes, + "Number of types in MixedTyped changed, but copy_back function wasn't updated"); +} + +} // namespace neuralnetworks +} // namespace hardware +} // namespace android diff --git a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp index 5d24fb5bbc..72c4a2b229 100644 --- a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp @@ -18,7 +18,7 @@ #include "VtsHalNeuralnetworks.h" -#include "Callbacks.h" +#include "1.0/Callbacks.h" namespace android { namespace hardware { @@ -27,8 +27,8 @@ namespace V1_0 { namespace vts { namespace functional { -using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; +using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; +using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// diff --git a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp index f0c93b7b54..058eb25002 100644 --- a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp @@ -16,16 +16,15 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" -#include "VtsHalNeuralnetworks.h" - -#include "Callbacks.h" -#include "TestHarness.h" -#include "Utils.h" - #include #include #include +#include "1.0/Callbacks.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "VtsHalNeuralnetworks.h" + namespace android { namespace hardware { namespace neuralnetworks { @@ -33,7 +32,7 @@ namespace V1_0 { namespace vts { namespace functional { -using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; +using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; using ::android::hidl::memory::V1_0::IMemory; using test_helper::for_all; using test_helper::MixedTyped; @@ -121,11 +120,13 @@ std::vector createRequests(const std::vector& exampl for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) { if (inputs_info.size() <= static_cast(index)) inputs_info.resize(index + 1); RequestArgument arg = { - .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast(s)}, - .dimensions = {}, + .location = {.poolIndex = INPUT, + .offset = 0, + .length = static_cast(s)}, + .dimensions = {}, }; RequestArgument arg_empty = { - .hasNoValue = true, + .hasNoValue = true, }; inputs_info[index] = s ? arg : arg_empty; inputSize += s; @@ -143,8 +144,10 @@ std::vector createRequests(const std::vector& exampl for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) { if (outputs_info.size() <= static_cast(index)) outputs_info.resize(index + 1); RequestArgument arg = { - .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast(s)}, - .dimensions = {}, + .location = {.poolIndex = OUTPUT, + .offset = 0, + .length = static_cast(s)}, + .dimensions = {}, }; outputs_info[index] = arg; outputSize += s; diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp index aee2f8549b..95b7ad3e09 100644 --- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp @@ -20,7 +20,7 @@ #include -#include "Callbacks.h" +#include "1.0/Callbacks.h" namespace android { namespace hardware { @@ -29,7 +29,7 @@ namespace V1_0 { namespace vts { namespace functional { -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; +using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; static void createPreparedModel(const sp& device, const V1_0::Model& model, sp* preparedModel) { diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h index 22285be38e..c32a91dc34 100644 --- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H -#define VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_VTS_HAL_NEURALNETWORKS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_VTS_HAL_NEURALNETWORKS_H #include #include @@ -89,4 +89,4 @@ namespace android::hardware::neuralnetworks::V1_0 { } // namespace android::hardware::neuralnetworks::V1_0 -#endif // VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_VTS_HAL_NEURALNETWORKS_H diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h b/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h new file mode 100644 index 0000000000..36318ea2c2 --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2018 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_CALLBACKS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace neuralnetworks { +namespace V1_0 { +namespace implementation { + +/** + * The CallbackBase class is used internally by the NeuralNetworks runtime to + * synchronize between different threads. An asynchronous task is launched + * paired with a callback object. When a client thread requires the output being + * generated by the asynchronous task, the client thread can wait for the result + * and be blocked until it has completed or a timeout condition has been + * reached. Any wait* may safely be called concurrently, even on the same + * callback object. When the asynchronous task has finished its workload, it + * must immediately call "notify". If the asynchronous task has failed to launch, + * the function that tried to launch the asynchronous task must immediately call + * "notify". This "notify" call awakens any client threads waiting on the + * callback object. + * + * The CallbackBase class implements some of the base synchronization common to + * both PrepareModelCallback and ExecutionCallback. For consistency, any HIDL + * callback class must inherit from CallbackBase as well as the HIDL callback + * interface it implements. + * + * This class exists to enable synchronization across HIDL. When synchronization + * is only required in the same process, consider using std::future, std::mutex, + * std::condition_variable, or std::experimental::latch instead. + */ +class CallbackBase { + public: + CallbackBase(); + ~CallbackBase(); + + /** + * CallbackBase::wait blocks until notify has been called on the callback + * object. + */ + void wait(); + + /** + * CallbackBase::wait_for blocks until notify has been called on the + * callback object or the time duration from the time the wait_for function + * was called has expired, whichever comes first. + * + * @return Status std::cv_status::no_timeout if the callback was notified + * before the time duration expired, std::cv_status::timeout + * otherwise. + */ + template + std::cv_status wait_for(const std::chrono::duration& timeout_duration); + + /** + * CallbackBase::on_finish binds a function to the callback object. This + * bound function will be executed when CallbackBase::notify is called, + * before any calls to wait* return. (Note that CallbackBase::wait_for can + * return std::cv_status::timeout before CallbackBase::notify is called for + * the first time, and hence before the bound function is executed.) + * + * The bound function must not synchronize with or otherwise access the + * callback object it is bound to, as this could cause a deadlock. + * + * CallbackBase::on_finish can be called at most once on a given callback + * object, and the call to CallbackBase::on_finish must finish before + * CallbackBase::notify is called. + * + * @param post_work Function to be invoked the first time + * CallbackBase::notify is called. Must have a target -- + * i.e., must not compare equal to nullptr. post_work + * returns true if it successfully completes, false if it + * fails. + * @return bool True if the function was successfully bound, false if + * unsuccessful. + * + * TODO: Why does the return value of the callback matter? + */ + bool on_finish(std::function post_work); + + /** + * CallbackBase::bind_thread binds a thread to the event for later use by + * CallbackBase::join_thread. + * + * The thread must be passed using std::move. + * + * Once a thread is bound with CallbackBase::bind_thread, the client code + * should ensure that one of the following occurs before the event is + * destroyed: + * - CallbackBase::join_thread has been called. + * - CallbackBase::wait has been called. + * - CallbackBase::wait_for has been called and returned other than + * std::cv_status::no_timeout. + * + * The bound thread shall not call any CallbackBase method with the + * exception of CallbackBase::notify, which it must call when the thread has + * finished its computation. + * + * CallbackBase::bind_thread can be called at most once on a given callback + * object. + * + * @param asyncThread Thread to be bound to the callback object. The thread + * object must represent a thread of execution -- i.e., + * asyncThread.joinable() must be true. + * @return bool True if successful, false if thread was not properly bound. + */ + bool bind_thread(std::thread&& asyncThread); + + /** + * CallbackBase::join_thread ensures that the thread (if any) bound to this + * event with CallbackBase::bind_thread has fully finished and cleaned its + * resources. It is legal to call this function multiple times, concurrently + * or sequentially. + */ + void join_thread(); + + protected: + /** + * CallbackBase::notify enables all prior and future wait* calls on the + * callback object to proceed. The call to CallbackBase::notify happens + * before any wait* calls on this callback object return (except in the case + * of wait_for timing out). The asynchronous call the callback object is + * paired with must ensure that any update to state that should be visible + * to the caller of wait* happens before the call to CallbackBase::notify. + * + * CallbackBase::notify must be called exactly once on a given callback + * object. + */ + void notify(); + + private: + // Same as CallbackBase::join_thread but assumes we already hold a lock on + // mMutex. + void join_thread_locked(); + + bool mNotified; + std::mutex mMutex; + std::condition_variable mCondition; + std::function mPostWork; + std::thread mThread; +}; + +/** + * The PreparedModelCallback class is used to receive the error status of + * preparing a model as well as the prepared model from a task executing + * asynchronously with respect to the runtime. If a calling thread calls wait* + * or get* on a PreparedModelCallback object and the corresponding asynchronous + * task has not finished preparing the model, the calling thread will block + * until the asynchronous task has called notify. For more information on the + * synchronization behavior, refer to the CallbackBase class. + * + * This class inherits the basic blocking and signaling calls from + * CallbackBase, and implements the HIDL notify call from + * IPreparedModelCallback. This callback object is passed as an argument to + * IDevice::prepareModel. + */ +class PreparedModelCallback : public CallbackBase, public IPreparedModelCallback { + public: + PreparedModelCallback(); + ~PreparedModelCallback() override; + + /** + * IPreparedModelCallback::notify marks the callback object with the return + * status of the asynchronous model preparation along with the prepared + * model and calls CallbackBase::notify, enabling all prior and future + * wait* calls on the PreparedModelCallback object to proceed. + * For more information on the synchronization behavior, refer to the + * CallbackBase class. + * + * IPreparedModelCallback::notify must be called exactly once on a given + * PreparedModelCallback object. + * + * @param status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + * @param preparedModel Returned model that has been prepared for execution, + * nullptr if the model was unable to be prepared. + */ + Return notify(ErrorStatus status, const sp& preparedModel) override; + + /** + * Retrieves the error status returned from the asynchronous task launched + * by IDevice::prepareModel. If IDevice::prepareModel has not finished + * asynchronously preparing the model, this call will block until the + * asynchronous task notifies the object. + * + * @return status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + */ + ErrorStatus getStatus(); + + /** + * Retrieves the model that has been prepared for execution from the + * asynchronous task launched by IDevice::prepareModel. If + * IDevice::prepareModel has not finished asynchronously preparing the + * model, this call will block until the asynchronous task notifies the + * object. + * + * @return preparedModel Returned model that has been prepared for + * execution, nullptr if the model was unable to be + * prepared. + */ + sp getPreparedModel(); + + private: + ErrorStatus mErrorStatus; + sp mPreparedModel; +}; + +/** + * The ExecutionCallback class is used to receive the error status of the + * execution from a task executing asynchronously with respect to the runtime. + * If a calling thread calls wait* or get* on a PreparedModelCallback object and + * the corresponding asynchronous task has not finished the execution, the + * calling thread will block until the asynchronous task has called notify. + * For more information on the synchronization behavior, refer to the + * CallbackBase class. + * + * This class inherits the basic blocking and signaling calls from + * CallbackBase, and implements the HIDL notify call from IExecutionCallback. + * This callback object is passed as an argument to IPreparedModel::execute. + */ +class ExecutionCallback : public CallbackBase, public IExecutionCallback { + public: + ExecutionCallback(); + ~ExecutionCallback() override; + + /** + * IExecutionCallback::notify marks the callback object with the return + * status of the asynchronous execution that held this callback and enable + * all prior and future wait* calls on the ExecutionCallback object to + * proceed. For more information on the synchronization behavior, refer to + * the CallbackBase class. + * + * IExecutionCallback::notify must be called exactly once on a given + * ExecutionCallback object. + * + * @param status Error status returned from launching the asynchronous task + * (if the launch fails) or from the asynchronous task itself + * (if the launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is + * not large enough to store the resultant values + * - INVALID_ARGUMENT if the input request is invalid + */ + Return notify(ErrorStatus status) override; + + /** + * Retrieves the error status returned from the asynchronous task launched + * by IPreparedModel::execute. If IPreparedModel::execute has not finished + * asynchronously executing, this call will block until the asynchronous + * task notifies the object. + * + * @return status Error status returned from launching the asynchronous task + * (if the launch fails) or from the asynchronous task itself + * (if the launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the asynchronous task resulted in an + * unspecified error + * - OUTPUT_INSUFFICIENT_SIZE if at least one output + * operand buffer is not large enough to store the + * corresponding output + * - INVALID_ARGUMENT if one of the input arguments to + * prepareModel is invalid + */ + ErrorStatus getStatus(); + + private: + ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE; +}; + +// template function implementation(s) below this point + +template +std::cv_status CallbackBase::wait_for(const std::chrono::duration& timeout_duration) { + std::unique_lock lock(mMutex); + std::cv_status status = + mCondition.wait_for(lock, timeout_duration, [this] { return mNotified; }); + if (status != std::cv_status::timeout) { + join_thread_locked(); + } + return status; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace neuralnetworks +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h new file mode 100644 index 0000000000..b270c20450 --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H + +#include +#include +#include +#include "TestHarness.h" + +namespace android { +namespace hardware { +namespace neuralnetworks { + +void copy_back(::test_helper::MixedTyped* dst, const std::vector& ra, + char* src); + +// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation, +// so this is efficiently accomplished by moving the element to the end and +// resizing the hidl_vec to one less. +template +inline void hidl_vec_removeAt(hidl_vec* vec, uint32_t index) { + if (vec) { + std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end()); + vec->resize(vec->size() - 1); + } +} + +template +inline uint32_t hidl_vec_push_back(hidl_vec* vec, const Type& value) { + // assume vec is valid + const uint32_t index = vec->size(); + vec->resize(index + 1); + (*vec)[index] = value; + return index; +} + +} // namespace neuralnetworks +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp index 4fbeac978d..ee90ec6fe2 100644 --- a/neuralnetworks/1.1/vts/functional/Android.bp +++ b/neuralnetworks/1.1/vts/functional/Android.bp @@ -14,10 +14,41 @@ // limitations under the License. // +cc_defaults { + name: "VtsHalNeuralNetworksV1_1TargetTestDefaults", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "ValidateModel.cpp", + "ValidateRequest.cpp", + "VtsHalNeuralnetworks.cpp", + "GeneratedTestHarness.cpp", + ], + shared_libs: [ + "libfmq", + "libnativewindow", + ], + static_libs: [ + "android.hardware.neuralnetworks@1.0", + "android.hardware.neuralnetworks@1.1", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "libgmock", + "libhidlmemory", + "libneuralnetworks_utils", + "VtsHalNeuralNetworksV1_0_utils", + ], + header_libs: [ + "libneuralnetworks_headers", + "libneuralnetworks_generated_test_harness_headers", + "libneuralnetworks_generated_tests", + ], + test_suites: ["general-tests"], +} + // Tests for V1_0 models using the V1_1 HAL. cc_test { name: "VtsHalNeuralnetworksV1_1CompatV1_0TargetTest", - defaults: ["VtsHalNeuralNetworksTargetTestDefaults"], + defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"], srcs: [ "GeneratedTestsV1_0.cpp", ], @@ -26,19 +57,19 @@ cc_test { // Tests for V1_1 models. cc_test { name: "VtsHalNeuralnetworksV1_1TargetTest", - defaults: ["VtsHalNeuralNetworksTargetTestDefaults"], + defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"], srcs: [ "BasicTests.cpp", - "GeneratedTests.cpp", + "GeneratedTestsV1_1.cpp", ], } cc_test { name: "PresubmitHalNeuralnetworksV1_1TargetTest", - defaults: ["VtsHalNeuralNetworksTargetTestDefaults"], + defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"], srcs: [ "BasicTests.cpp", - "GeneratedTests.cpp", + "GeneratedTestsV1_1.cpp", ], cflags: [ "-DPRESUBMIT_NOT_VTS", diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp new file mode 100644 index 0000000000..d9f64fdb5b --- /dev/null +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2017 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 "GeneratedTestHarness.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "1.0/Callbacks.h" +#include "1.0/Utils.h" +#include "MemoryUtils.h" +#include "TestHarness.h" + +namespace android { +namespace hardware { +namespace neuralnetworks { +namespace generated_tests { + +using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; +using ::android::hardware::neuralnetworks::V1_0::IPreparedModel; +using ::android::hardware::neuralnetworks::V1_0::Request; +using ::android::hardware::neuralnetworks::V1_0::RequestArgument; +using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; +using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; +using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference; +using ::android::hardware::neuralnetworks::V1_1::IDevice; +using ::android::hardware::neuralnetworks::V1_1::Model; +using ::android::hidl::memory::V1_0::IMemory; +using ::test_helper::compare; +using ::test_helper::filter; +using ::test_helper::for_all; +using ::test_helper::MixedTyped; +using ::test_helper::MixedTypedExample; +using ::test_helper::resize_accordingly; + +// Top level driver for models and examples generated by test_generator.py +// Test driver for those generated from ml/nn/runtime/test/spec +void EvaluatePreparedModel(sp& preparedModel, std::function is_ignored, + const std::vector& examples, + bool hasRelaxedFloat32Model, float fpAtol, float fpRtol) { + const uint32_t INPUT = 0; + const uint32_t OUTPUT = 1; + + int example_no = 1; + for (auto& example : examples) { + SCOPED_TRACE(example_no++); + const MixedTyped& inputs = example.operands.first; + const MixedTyped& golden = example.operands.second; + + const bool hasFloat16Inputs = !inputs.float16Operands.empty(); + if (hasRelaxedFloat32Model || hasFloat16Inputs) { + // TODO: Adjust the error limit based on testing. + // If in relaxed mode, set the absolute tolerance to be 5ULP of FP16. + fpAtol = 5.0f * 0.0009765625f; + // Set the relative tolerance to be 5ULP of the corresponding FP precision. + fpRtol = 5.0f * 0.0009765625f; + } + + std::vector inputs_info, outputs_info; + uint32_t inputSize = 0, outputSize = 0; + // This function only partially specifies the metadata (vector of RequestArguments). + // The contents are copied over below. + for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) { + if (inputs_info.size() <= static_cast(index)) inputs_info.resize(index + 1); + RequestArgument arg = { + .location = {.poolIndex = INPUT, + .offset = 0, + .length = static_cast(s)}, + .dimensions = {}, + }; + RequestArgument arg_empty = { + .hasNoValue = true, + }; + inputs_info[index] = s ? arg : arg_empty; + inputSize += s; + }); + // Compute offset for inputs 1 and so on + { + size_t offset = 0; + for (auto& i : inputs_info) { + if (!i.hasNoValue) i.location.offset = offset; + offset += i.location.length; + } + } + + MixedTyped test; // holding test results + + // Go through all outputs, initialize RequestArgument descriptors + resize_accordingly(golden, test); + for_all(golden, [&outputs_info, &outputSize](int index, auto, auto s) { + if (outputs_info.size() <= static_cast(index)) outputs_info.resize(index + 1); + RequestArgument arg = { + .location = {.poolIndex = OUTPUT, + .offset = 0, + .length = static_cast(s)}, + .dimensions = {}, + }; + outputs_info[index] = arg; + outputSize += s; + }); + // Compute offset for outputs 1 and so on + { + size_t offset = 0; + for (auto& i : outputs_info) { + i.location.offset = offset; + offset += i.location.length; + } + } + std::vector pools = {nn::allocateSharedMemory(inputSize), + nn::allocateSharedMemory(outputSize)}; + ASSERT_NE(0ull, pools[INPUT].size()); + ASSERT_NE(0ull, pools[OUTPUT].size()); + + // load data + sp inputMemory = mapMemory(pools[INPUT]); + sp outputMemory = mapMemory(pools[OUTPUT]); + ASSERT_NE(nullptr, inputMemory.get()); + ASSERT_NE(nullptr, outputMemory.get()); + char* inputPtr = reinterpret_cast(static_cast(inputMemory->getPointer())); + char* outputPtr = reinterpret_cast(static_cast(outputMemory->getPointer())); + ASSERT_NE(nullptr, inputPtr); + ASSERT_NE(nullptr, outputPtr); + inputMemory->update(); + outputMemory->update(); + + // Go through all inputs, copy the values + for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) { + char* begin = (char*)p; + char* end = begin + s; + // TODO: handle more than one input + std::copy(begin, end, inputPtr + inputs_info[index].location.offset); + }); + + inputMemory->commit(); + outputMemory->commit(); + + const Request request = {.inputs = inputs_info, .outputs = outputs_info, .pools = pools}; + + // launch execution + sp executionCallback = new ExecutionCallback(); + ASSERT_NE(nullptr, executionCallback.get()); + Return executionLaunchStatus = + preparedModel->execute(request, executionCallback); + ASSERT_TRUE(executionLaunchStatus.isOk()); + EXPECT_EQ(ErrorStatus::NONE, static_cast(executionLaunchStatus)); + + // retrieve execution status + executionCallback->wait(); + ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus()); + + // validate results + outputMemory->read(); + copy_back(&test, outputs_info, outputPtr); + outputMemory->commit(); + // Filter out don't cares + MixedTyped filtered_golden = filter(golden, is_ignored); + MixedTyped filtered_test = filter(test, is_ignored); + + // We want "close-enough" results for float + compare(filtered_golden, filtered_test, fpAtol, fpRtol); + } +} + +void Execute(const sp& device, std::function create_model, + std::function is_ignored, const std::vector& examples) { + Model model = create_model(); + + // see if service can handle model + bool fullySupportsModel = false; + Return supportedCall = device->getSupportedOperations_1_1( + model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { + ASSERT_EQ(ErrorStatus::NONE, status); + ASSERT_NE(0ul, supported.size()); + fullySupportsModel = std::all_of(supported.begin(), supported.end(), + [](bool valid) { return valid; }); + }); + ASSERT_TRUE(supportedCall.isOk()); + + // launch prepare model + sp preparedModelCallback = new PreparedModelCallback(); + ASSERT_NE(nullptr, preparedModelCallback.get()); + Return prepareLaunchStatus = device->prepareModel_1_1( + model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); + + // retrieve prepared model + preparedModelCallback->wait(); + ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + sp preparedModel = preparedModelCallback->getPreparedModel(); + + // early termination if vendor service cannot fully prepare model + if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { + ASSERT_EQ(nullptr, preparedModel.get()); + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " + "prepare model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "prepare model that it does not support." + << std::endl; + GTEST_SKIP(); + } + EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); + ASSERT_NE(nullptr, preparedModel.get()); + + EvaluatePreparedModel(preparedModel, is_ignored, examples, + model.relaxComputationFloat32toFloat16, 1e-5f, 1e-5f); +} + +} // namespace generated_tests +} // namespace neuralnetworks +} // namespace hardware +} // namespace android diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h new file mode 100644 index 0000000000..ab71b2b87a --- /dev/null +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_1_GENERATED_TEST_HARNESS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_1_GENERATED_TEST_HARNESS_H + +#include +#include +#include +#include +#include "TestHarness.h" + +namespace android { +namespace hardware { +namespace neuralnetworks { +namespace generated_tests { + +void Execute(const sp& device, std::function create_model, + std::function is_ignored, + const std::vector<::test_helper::MixedTypedExample>& examples); + +} // namespace generated_tests +} // namespace neuralnetworks +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_1_GENERATED_TEST_HARNESS_H diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp index e67ef8ed98..10cf5a9e5a 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp @@ -16,17 +16,16 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" -#include "VtsHalNeuralnetworks.h" - -#include "Callbacks.h" -#include "GeneratedTestHarness.h" -#include "TestHarness.h" -#include "Utils.h" - #include #include #include +#include "1.0/Callbacks.h" +#include "GeneratedTestHarness.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "VtsHalNeuralnetworks.h" + namespace android { namespace hardware { namespace neuralnetworks { @@ -34,8 +33,10 @@ namespace V1_1 { namespace vts { namespace functional { -using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; +using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; +using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; +using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; +using ::android::hidl::memory::V1_0::IMemory; using ::android::nn::allocateSharedMemory; using ::test_helper::MixedTypedExample; diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_1.cpp similarity index 83% rename from neuralnetworks/1.1/vts/functional/GeneratedTests.cpp rename to neuralnetworks/1.1/vts/functional/GeneratedTestsV1_1.cpp index 4db12769a7..079c18c449 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_1.cpp @@ -16,17 +16,16 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" -#include "VtsHalNeuralnetworks.h" - -#include "Callbacks.h" -#include "GeneratedTestHarness.h" -#include "TestHarness.h" -#include "Utils.h" - #include #include #include +#include "1.0/Callbacks.h" +#include "GeneratedTestHarness.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "VtsHalNeuralnetworks.h" + namespace android { namespace hardware { namespace neuralnetworks { @@ -34,8 +33,10 @@ namespace V1_1 { namespace vts { namespace functional { -using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; +using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; +using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; +using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; +using ::android::hidl::memory::V1_0::IMemory; using ::android::nn::allocateSharedMemory; using ::test_helper::MixedTypedExample; diff --git a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp index b35a901ef8..fb80d1307a 100644 --- a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp @@ -16,25 +16,22 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" +#include "1.0/Callbacks.h" +#include "1.0/Utils.h" #include "VtsHalNeuralnetworks.h" -#include "Callbacks.h" - namespace android { namespace hardware { namespace neuralnetworks { namespace V1_1 { - -using V1_0::IPreparedModel; -using V1_0::Operand; -using V1_0::OperandLifeTime; -using V1_0::OperandType; - namespace vts { namespace functional { -using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; +using ::android::hardware::neuralnetworks::V1_0::IPreparedModel; +using ::android::hardware::neuralnetworks::V1_0::Operand; +using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; +using ::android::hardware::neuralnetworks::V1_0::OperandType; +using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// @@ -42,10 +39,10 @@ static void validateGetSupportedOperations(const sp& device, const std: const V1_1::Model& model) { SCOPED_TRACE(message + " [getSupportedOperations_1_1]"); - Return ret = - device->getSupportedOperations_1_1(model, [&](ErrorStatus status, const hidl_vec&) { - EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); - }); + Return ret = device->getSupportedOperations_1_1( + model, [&](ErrorStatus status, const hidl_vec&) { + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); + }); EXPECT_TRUE(ret.isOk()); } @@ -56,7 +53,7 @@ static void validatePrepareModel(const sp& device, const std::string& m sp preparedModelCallback = new PreparedModelCallback(); ASSERT_NE(nullptr, preparedModelCallback.get()); Return prepareLaunchStatus = - device->prepareModel_1_1(model, preference, preparedModelCallback); + device->prepareModel_1_1(model, preference, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(prepareLaunchStatus)); @@ -87,36 +84,16 @@ static void validate(const sp& device, const std::string& message, V1_1 validatePrepareModel(device, message, model, preference); } -// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation, -// so this is efficiently accomplished by moving the element to the end and -// resizing the hidl_vec to one less. -template -static void hidl_vec_removeAt(hidl_vec* vec, uint32_t index) { - if (vec) { - std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end()); - vec->resize(vec->size() - 1); - } -} - -template -static uint32_t hidl_vec_push_back(hidl_vec* vec, const Type& value) { - // assume vec is valid - const uint32_t index = vec->size(); - vec->resize(index + 1); - (*vec)[index] = value; - return index; -} - static uint32_t addOperand(Model* model) { return hidl_vec_push_back(&model->operands, { - .type = OperandType::INT32, - .dimensions = {}, - .numberOfConsumers = 0, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::MODEL_INPUT, - .location = {.poolIndex = 0, .offset = 0, .length = 0}, + .type = OperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 0, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, }); } @@ -130,10 +107,10 @@ static uint32_t addOperand(Model* model, OperandLifeTime lifetime) { ///////////////////////// VALIDATE MODEL OPERAND TYPE ///////////////////////// static const int32_t invalidOperandTypes[] = { - static_cast(OperandType::FLOAT32) - 1, // lower bound fundamental - static_cast(OperandType::TENSOR_QUANT8_ASYMM) + 1, // upper bound fundamental - static_cast(OperandType::OEM) - 1, // lower bound OEM - static_cast(OperandType::TENSOR_OEM_BYTE) + 1, // upper bound OEM + static_cast(OperandType::FLOAT32) - 1, // lower bound fundamental + static_cast(OperandType::TENSOR_QUANT8_ASYMM) + 1, // upper bound fundamental + static_cast(OperandType::OEM) - 1, // lower bound OEM + static_cast(OperandType::TENSOR_OEM_BYTE) + 1, // upper bound OEM }; static void mutateOperandTypeTest(const sp& device, const V1_1::Model& model) { @@ -226,7 +203,7 @@ static std::vector getInvalidZeroPoints(OperandType type) { static void mutateOperandZeroPointTest(const sp& device, const V1_1::Model& model) { for (size_t operand = 0; operand < model.operands.size(); ++operand) { const std::vector invalidZeroPoints = - getInvalidZeroPoints(model.operands[operand].type); + getInvalidZeroPoints(model.operands[operand].type); for (int32_t invalidZeroPoint : invalidZeroPoints) { const std::string message = "mutateOperandZeroPointTest: operand " + std::to_string(operand) + " has zero point of " + @@ -258,18 +235,18 @@ static void mutateOperand(Operand* operand, OperandType type) { break; case OperandType::TENSOR_FLOAT32: newOperand.dimensions = - operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); newOperand.scale = 0.0f; newOperand.zeroPoint = 0; break; case OperandType::TENSOR_INT32: newOperand.dimensions = - operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); newOperand.zeroPoint = 0; break; case OperandType::TENSOR_QUANT8_ASYMM: newOperand.dimensions = - operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f; break; case OperandType::OEM: @@ -319,10 +296,10 @@ static void mutateOperationOperandTypeTest(const sp& device, const V1_1 ///////////////////////// VALIDATE MODEL OPERATION TYPE ///////////////////////// static const int32_t invalidOperationTypes[] = { - static_cast(OperationType::ADD) - 1, // lower bound fundamental - static_cast(OperationType::TRANSPOSE) + 1, // upper bound fundamental - static_cast(OperationType::OEM_OPERATION) - 1, // lower bound OEM - static_cast(OperationType::OEM_OPERATION) + 1, // upper bound OEM + static_cast(OperationType::ADD) - 1, // lower bound fundamental + static_cast(OperationType::TRANSPOSE) + 1, // upper bound fundamental + static_cast(OperationType::OEM_OPERATION) - 1, // lower bound OEM + static_cast(OperationType::OEM_OPERATION) + 1, // upper bound OEM }; static void mutateOperationTypeTest(const sp& device, const V1_1::Model& model) { @@ -333,7 +310,7 @@ static void mutateOperationTypeTest(const sp& device, const V1_1::Model std::to_string(invalidOperationType); validate(device, message, model, [operation, invalidOperationType](Model* model) { model->operations[operation].type = - static_cast(invalidOperationType); + static_cast(invalidOperationType); }); } } @@ -486,7 +463,7 @@ static void addOperationInputTest(const sp& device, const V1_1::Model& static void addOperationOutputTest(const sp& device, const V1_1::Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { const std::string message = - "addOperationOutputTest: operation " + std::to_string(operation); + "addOperationOutputTest: operation " + std::to_string(operation); validate(device, message, model, [operation](Model* model) { uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT); hidl_vec_push_back(&model->operations[operation].outputs, index); @@ -498,14 +475,14 @@ static void addOperationOutputTest(const sp& device, const V1_1::Model& ///////////////////////// VALIDATE EXECUTION PREFERENCE ///////////////////////// static const int32_t invalidExecutionPreferences[] = { - static_cast(ExecutionPreference::LOW_POWER) - 1, // lower bound - static_cast(ExecutionPreference::SUSTAINED_SPEED) + 1, // upper bound + static_cast(ExecutionPreference::LOW_POWER) - 1, // lower bound + static_cast(ExecutionPreference::SUSTAINED_SPEED) + 1, // upper bound }; static void mutateExecutionPreferenceTest(const sp& device, const V1_1::Model& model) { for (int32_t preference : invalidExecutionPreferences) { const std::string message = - "mutateExecutionPreferenceTest: preference " + std::to_string(preference); + "mutateExecutionPreferenceTest: preference " + std::to_string(preference); validate(device, message, model, [](Model*) {}, static_cast(preference)); } diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp index f4adbabf93..c54972887e 100644 --- a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp @@ -16,16 +16,16 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" -#include "VtsHalNeuralnetworks.h" - -#include "Callbacks.h" -#include "TestHarness.h" -#include "Utils.h" - #include #include #include +#include "1.0/Callbacks.h" +#include "1.0/Utils.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "VtsHalNeuralnetworks.h" + namespace android { namespace hardware { namespace neuralnetworks { @@ -33,11 +33,15 @@ namespace V1_1 { namespace vts { namespace functional { -using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; +using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; +using ::android::hardware::neuralnetworks::V1_0::Request; +using ::android::hardware::neuralnetworks::V1_0::RequestArgument; +using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; +using ::android::hardware::neuralnetworks::V1_1::IPreparedModel; using ::android::hidl::memory::V1_0::IMemory; -using test_helper::for_all; -using test_helper::MixedTyped; -using test_helper::MixedTypedExample; +using ::test_helper::for_all; +using ::test_helper::MixedTyped; +using ::test_helper::MixedTypedExample; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// @@ -61,26 +65,6 @@ static void validate(const sp& preparedModel, const std::string& ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus); } -// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation, -// so this is efficiently accomplished by moving the element to the end and -// resizing the hidl_vec to one less. -template -static void hidl_vec_removeAt(hidl_vec* vec, uint32_t index) { - if (vec) { - std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end()); - vec->resize(vec->size() - 1); - } -} - -template -static uint32_t hidl_vec_push_back(hidl_vec* vec, const Type& value) { - // assume vec is valid - const uint32_t index = vec->size(); - vec->resize(index + 1); - (*vec)[index] = value; - return index; -} - ///////////////////////// REMOVE INPUT //////////////////////////////////// static void removeInputTest(const sp& preparedModel, const Request& request) { @@ -121,11 +105,13 @@ std::vector createRequests(const std::vector& exampl for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) { if (inputs_info.size() <= static_cast(index)) inputs_info.resize(index + 1); RequestArgument arg = { - .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast(s)}, - .dimensions = {}, + .location = {.poolIndex = INPUT, + .offset = 0, + .length = static_cast(s)}, + .dimensions = {}, }; RequestArgument arg_empty = { - .hasNoValue = true, + .hasNoValue = true, }; inputs_info[index] = s ? arg : arg_empty; inputSize += s; @@ -143,8 +129,10 @@ std::vector createRequests(const std::vector& exampl for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) { if (outputs_info.size() <= static_cast(index)) outputs_info.resize(index + 1); RequestArgument arg = { - .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast(s)}, - .dimensions = {}, + .location = {.poolIndex = OUTPUT, + .offset = 0, + .length = static_cast(s)}, + .dimensions = {}, }; outputs_info[index] = arg; outputSize += s; diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp index 08069f2e7a..12bdd3ffb6 100644 --- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp @@ -20,7 +20,7 @@ #include -#include "Callbacks.h" +#include "1.0/Callbacks.h" namespace android { namespace hardware { @@ -29,7 +29,7 @@ namespace V1_1 { namespace vts { namespace functional { -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; +using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; static void createPreparedModel(const sp& device, const V1_1::Model& model, sp* preparedModel) { diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h index f3f587b866..3156784fc5 100644 --- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef VTS_HAL_NEURALNETWORKS_V1_1_H -#define VTS_HAL_NEURALNETWORKS_V1_1_H +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_1_VTS_HAL_NEURALNETWORKS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_1_VTS_HAL_NEURALNETWORKS_H #include #include @@ -98,4 +98,4 @@ namespace android::hardware::neuralnetworks::V1_0 { } // namespace android::hardware::neuralnetworks::V1_0 -#endif // VTS_HAL_NEURALNETWORKS_V1_1_H +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_1_VTS_HAL_NEURALNETWORKS_H diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index 6c26820b27..b48646f6e2 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -14,10 +14,44 @@ // limitations under the License. // +cc_defaults { + name: "VtsHalNeuralNetworksV1_2TargetTestDefaults", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "ValidateModel.cpp", + "ValidateRequest.cpp", + "VtsHalNeuralnetworks.cpp", + "Callbacks.cpp", + "GeneratedTestHarness.cpp", + ], + local_include_dirs: ["include"], + shared_libs: [ + "libfmq", + "libnativewindow", + ], + static_libs: [ + "android.hardware.neuralnetworks@1.0", + "android.hardware.neuralnetworks@1.1", + "android.hardware.neuralnetworks@1.2", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "libgmock", + "libhidlmemory", + "libneuralnetworks_utils", + "VtsHalNeuralNetworksV1_0_utils", + ], + header_libs: [ + "libneuralnetworks_headers", + "libneuralnetworks_generated_test_harness_headers", + "libneuralnetworks_generated_tests", + ], + test_suites: ["general-tests"], +} + // Tests for V1_0 models using the V1_2 HAL. cc_test { name: "VtsHalNeuralnetworksV1_2CompatV1_0TargetTest", - defaults: ["VtsHalNeuralNetworksTargetTestDefaults"], + defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ "GeneratedTestsV1_0.cpp", "ValidateBurst.cpp", @@ -30,7 +64,7 @@ cc_test { // Tests for V1_1 models using the V1_2 HAL. cc_test { name: "VtsHalNeuralnetworksV1_2CompatV1_1TargetTest", - defaults: ["VtsHalNeuralNetworksTargetTestDefaults"], + defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ "GeneratedTestsV1_1.cpp", "ValidateBurst.cpp", @@ -43,11 +77,11 @@ cc_test { // Tests for V1_2 models. cc_test { name: "VtsHalNeuralnetworksV1_2TargetTest", - defaults: ["VtsHalNeuralNetworksTargetTestDefaults"], + defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ "BasicTests.cpp", "CompilationCachingTests.cpp", - "GeneratedTests.cpp", + "GeneratedTestsV1_2.cpp", "ValidateBurst.cpp", ], cflags: [ @@ -57,10 +91,10 @@ cc_test { cc_test { name: "PresubmitHalNeuralnetworksV1_2TargetTest", - defaults: ["VtsHalNeuralNetworksTargetTestDefaults"], + defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ "BasicTests.cpp", - "GeneratedTests.cpp", + "GeneratedTestsV1_2.cpp", "ValidateBurst.cpp", ], cflags: [ diff --git a/neuralnetworks/1.2/vts/functional/Callbacks.cpp b/neuralnetworks/1.2/vts/functional/Callbacks.cpp new file mode 100644 index 0000000000..cfaf91d433 --- /dev/null +++ b/neuralnetworks/1.2/vts/functional/Callbacks.cpp @@ -0,0 +1,173 @@ +/* + * 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. + */ + +#include "1.2/Callbacks.h" +#include + +namespace android { +namespace hardware { +namespace neuralnetworks { +namespace V1_2 { +namespace implementation { + +CallbackBase::CallbackBase() : mNotified(false) {} + +CallbackBase::~CallbackBase() { + // Note that we cannot call CallbackBase::join_thread from here: + // CallbackBase is intended to be reference counted, and it is possible that + // the reference count drops to zero in the bound thread, causing the + // bound thread to call this destructor. If a thread tries to join + // itself, it throws an exception, producing a message like the + // following: + // + // terminating with uncaught exception of type std::__1::system_error: + // thread::join failed: Resource deadlock would occur +} + +void CallbackBase::wait() { + std::unique_lock lock(mMutex); + mCondition.wait(lock, [this] { return mNotified; }); + join_thread_locked(); +} + +bool CallbackBase::on_finish(std::function post_work) { + std::lock_guard lock(mMutex); + if (mPostWork != nullptr) { + LOG(ERROR) << "CallbackBase::on_finish -- a post-work function has already been bound to " + "this callback object"; + return false; + } + if (post_work == nullptr) { + LOG(ERROR) << "CallbackBase::on_finish -- the new post-work function is invalid"; + return false; + } + mPostWork = std::move(post_work); + return true; +} + +bool CallbackBase::bind_thread(std::thread&& asyncThread) { + std::lock_guard lock(mMutex); + if (mThread.joinable()) { + LOG(ERROR) << "CallbackBase::bind_thread -- a thread has already been bound to this " + "callback object"; + return false; + } + if (!asyncThread.joinable()) { + LOG(ERROR) << "CallbackBase::bind_thread -- the new thread is not joinable"; + return false; + } + mThread = std::move(asyncThread); + return true; +} + +void CallbackBase::join_thread() { + std::lock_guard lock(mMutex); + join_thread_locked(); +} + +void CallbackBase::notify() { + { + std::lock_guard lock(mMutex); + mNotified = true; + if (mPostWork != nullptr) { + bool success = mPostWork(); + if (!success) { + LOG(ERROR) << "CallbackBase::notify -- post work failed"; + } + } + } + mCondition.notify_all(); +} + +void CallbackBase::join_thread_locked() { + if (mThread.joinable()) { + mThread.join(); + } +} + +PreparedModelCallback::PreparedModelCallback() + : mErrorStatus(ErrorStatus::GENERAL_FAILURE), mPreparedModel(nullptr) {} + +PreparedModelCallback::~PreparedModelCallback() {} + +Return PreparedModelCallback::notify(ErrorStatus errorStatus, + const sp& preparedModel) { + mErrorStatus = errorStatus; + mPreparedModel = preparedModel; + CallbackBase::notify(); + return Void(); +} + +Return PreparedModelCallback::notify_1_2(ErrorStatus errorStatus, + const sp& preparedModel) { + mErrorStatus = errorStatus; + mPreparedModel = preparedModel; + CallbackBase::notify(); + return Void(); +} + +ErrorStatus PreparedModelCallback::getStatus() { + wait(); + return mErrorStatus; +} + +sp PreparedModelCallback::getPreparedModel() { + wait(); + return mPreparedModel; +} + +ExecutionCallback::ExecutionCallback() : mErrorStatus(ErrorStatus::GENERAL_FAILURE) {} + +ExecutionCallback::~ExecutionCallback() {} + +Return ExecutionCallback::notify(ErrorStatus errorStatus) { + mErrorStatus = errorStatus; + mOutputShapes = {}; + mTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; + CallbackBase::notify(); + return Void(); +} + +Return ExecutionCallback::notify_1_2(ErrorStatus errorStatus, + const hidl_vec& outputShapes, + const Timing& timing) { + mErrorStatus = errorStatus; + mOutputShapes = outputShapes; + mTiming = timing; + CallbackBase::notify(); + return Void(); +} + +ErrorStatus ExecutionCallback::getStatus() { + wait(); + return mErrorStatus; +} + +const std::vector& ExecutionCallback::getOutputShapes() { + wait(); + return mOutputShapes; +} + +Timing ExecutionCallback::getTiming() { + wait(); + return mTiming; +} + +} // namespace implementation +} // namespace V1_2 +} // namespace neuralnetworks +} // namespace hardware +} // namespace android diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp index 4411b90097..9cabb7b04e 100644 --- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp @@ -27,8 +27,9 @@ #include #include -#include "Callbacks.h" +#include "1.2/Callbacks.h" #include "GeneratedTestHarness.h" +#include "MemoryUtils.h" #include "TestHarness.h" #include "Utils.h" #include "VtsHalNeuralnetworks.h" diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp new file mode 100644 index 0000000000..c3578cdca7 --- /dev/null +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp @@ -0,0 +1,452 @@ +/* + * 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. + */ + +#include "GeneratedTestHarness.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "1.0/Utils.h" +#include "1.2/Callbacks.h" +#include "ExecutionBurstController.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "Utils.h" + +namespace android { +namespace hardware { +namespace neuralnetworks { +namespace generated_tests { + +using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; +using ::android::hardware::neuralnetworks::V1_0::Request; +using ::android::hardware::neuralnetworks::V1_0::RequestArgument; +using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference; +using ::android::hardware::neuralnetworks::V1_2::IDevice; +using ::android::hardware::neuralnetworks::V1_2::IPreparedModel; +using ::android::hardware::neuralnetworks::V1_2::Model; +using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; +using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; +using ::android::hidl::memory::V1_0::IMemory; +using ::test_helper::compare; +using ::test_helper::expectMultinomialDistributionWithinTolerance; +using ::test_helper::filter; +using ::test_helper::for_all; +using ::test_helper::for_each; +using ::test_helper::MixedTyped; +using ::test_helper::MixedTypedExample; +using ::test_helper::resize_accordingly; +using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; + +static bool isZeroSized(const MixedTyped& example, uint32_t index) { + for (auto i : example.operandDimensions.at(index)) { + if (i == 0) return true; + } + return false; +} + +static Return ExecutePreparedModel(sp& preparedModel, + const Request& request, MeasureTiming measure, + sp& callback) { + return preparedModel->execute_1_2(request, measure, callback); +} +static Return ExecutePreparedModel(sp& preparedModel, + const Request& request, MeasureTiming measure, + hidl_vec* outputShapes, + Timing* timing) { + ErrorStatus result; + Return ret = preparedModel->executeSynchronously( + request, measure, + [&result, outputShapes, timing](ErrorStatus error, const hidl_vec& shapes, + const Timing& time) { + result = error; + *outputShapes = shapes; + *timing = time; + }); + if (!ret.isOk()) { + return ErrorStatus::GENERAL_FAILURE; + } + return result; +} +static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst( + const sp& preparedModel) { + return ::android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true); +} +enum class Executor { ASYNC, SYNC, BURST }; +enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; +const float kDefaultAtol = 1e-5f; +const float kDefaultRtol = 1e-5f; +void EvaluatePreparedModel(sp& preparedModel, std::function is_ignored, + const std::vector& examples, + bool hasRelaxedFloat32Model, float fpAtol, float fpRtol, + Executor executor, MeasureTiming measure, OutputType outputType) { + const uint32_t INPUT = 0; + const uint32_t OUTPUT = 1; + + int example_no = 1; + for (auto& example : examples) { + SCOPED_TRACE(example_no++); + const MixedTyped& inputs = example.operands.first; + const MixedTyped& golden = example.operands.second; + + const bool hasFloat16Inputs = !inputs.float16Operands.empty(); + if (hasRelaxedFloat32Model || hasFloat16Inputs) { + // TODO: Adjust the error limit based on testing. + // If in relaxed mode, set the absolute tolerance to be 5ULP of FP16. + fpAtol = 5.0f * 0.0009765625f; + // Set the relative tolerance to be 5ULP of the corresponding FP precision. + fpRtol = 5.0f * 0.0009765625f; + } + + std::vector inputs_info, outputs_info; + uint32_t inputSize = 0, outputSize = 0; + // This function only partially specifies the metadata (vector of RequestArguments). + // The contents are copied over below. + for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) { + if (inputs_info.size() <= static_cast(index)) inputs_info.resize(index + 1); + RequestArgument arg = { + .location = {.poolIndex = INPUT, + .offset = 0, + .length = static_cast(s)}, + .dimensions = {}, + }; + RequestArgument arg_empty = { + .hasNoValue = true, + }; + inputs_info[index] = s ? arg : arg_empty; + inputSize += s; + }); + // Compute offset for inputs 1 and so on + { + size_t offset = 0; + for (auto& i : inputs_info) { + if (!i.hasNoValue) i.location.offset = offset; + offset += i.location.length; + } + } + + MixedTyped test; // holding test results + + // Go through all outputs, initialize RequestArgument descriptors + resize_accordingly(golden, test); + bool sizeLargerThanOne = true; + for_all(golden, [&golden, &outputs_info, &outputSize, &outputType, &sizeLargerThanOne]( + int index, auto, auto s) { + if (outputs_info.size() <= static_cast(index)) outputs_info.resize(index + 1); + if (index == 0) { + // On OutputType::INSUFFICIENT, set the output operand with index 0 with + // buffer size one byte less than needed. + if (outputType == OutputType::INSUFFICIENT) { + if (s > 1 && !isZeroSized(golden, index)) { + s -= 1; + } else { + sizeLargerThanOne = false; + } + } + } + RequestArgument arg = { + .location = {.poolIndex = OUTPUT, + .offset = 0, + .length = static_cast(s)}, + .dimensions = {}, + }; + outputs_info[index] = arg; + outputSize += s; + }); + // If output0 does not have size larger than one byte, + // we can not provide an insufficient buffer + if (!sizeLargerThanOne && outputType == OutputType::INSUFFICIENT) return; + // Compute offset for outputs 1 and so on + { + size_t offset = 0; + for (auto& i : outputs_info) { + i.location.offset = offset; + offset += i.location.length; + } + } + std::vector pools = {nn::allocateSharedMemory(inputSize), + nn::allocateSharedMemory(outputSize)}; + ASSERT_NE(0ull, pools[INPUT].size()); + ASSERT_NE(0ull, pools[OUTPUT].size()); + + // load data + sp inputMemory = mapMemory(pools[INPUT]); + sp outputMemory = mapMemory(pools[OUTPUT]); + ASSERT_NE(nullptr, inputMemory.get()); + ASSERT_NE(nullptr, outputMemory.get()); + char* inputPtr = reinterpret_cast(static_cast(inputMemory->getPointer())); + char* outputPtr = reinterpret_cast(static_cast(outputMemory->getPointer())); + ASSERT_NE(nullptr, inputPtr); + ASSERT_NE(nullptr, outputPtr); + inputMemory->update(); + outputMemory->update(); + + // Go through all inputs, copy the values + for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) { + char* begin = (char*)p; + char* end = begin + s; + // TODO: handle more than one input + std::copy(begin, end, inputPtr + inputs_info[index].location.offset); + }); + + inputMemory->commit(); + outputMemory->commit(); + + const Request request = {.inputs = inputs_info, .outputs = outputs_info, .pools = pools}; + + ErrorStatus executionStatus; + hidl_vec outputShapes; + Timing timing; + switch (executor) { + case Executor::ASYNC: { + SCOPED_TRACE("asynchronous"); + + // launch execution + sp executionCallback = new ExecutionCallback(); + ASSERT_NE(nullptr, executionCallback.get()); + Return executionLaunchStatus = + ExecutePreparedModel(preparedModel, request, measure, executionCallback); + ASSERT_TRUE(executionLaunchStatus.isOk()); + EXPECT_EQ(ErrorStatus::NONE, static_cast(executionLaunchStatus)); + + // retrieve execution status + executionCallback->wait(); + executionStatus = executionCallback->getStatus(); + outputShapes = executionCallback->getOutputShapes(); + timing = executionCallback->getTiming(); + + break; + } + case Executor::SYNC: { + SCOPED_TRACE("synchronous"); + + // execute + Return executionReturnStatus = ExecutePreparedModel( + preparedModel, request, measure, &outputShapes, &timing); + ASSERT_TRUE(executionReturnStatus.isOk()); + executionStatus = static_cast(executionReturnStatus); + + break; + } + case Executor::BURST: { + SCOPED_TRACE("burst"); + + // create burst + const std::shared_ptr<::android::nn::ExecutionBurstController> controller = + CreateBurst(preparedModel); + ASSERT_NE(nullptr, controller.get()); + + // create memory keys + std::vector keys(request.pools.size()); + for (size_t i = 0; i < keys.size(); ++i) { + keys[i] = reinterpret_cast(&request.pools[i]); + } + + // execute burst + std::tie(executionStatus, outputShapes, timing) = + controller->compute(request, measure, keys); + + break; + } + } + + if (outputType != OutputType::FULLY_SPECIFIED && + executionStatus == ErrorStatus::GENERAL_FAILURE) { + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " + "execute model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "execute model that it does not support." + << std::endl; + GTEST_SKIP(); + } + if (measure == MeasureTiming::NO) { + EXPECT_EQ(UINT64_MAX, timing.timeOnDevice); + EXPECT_EQ(UINT64_MAX, timing.timeInDriver); + } else { + if (timing.timeOnDevice != UINT64_MAX && timing.timeInDriver != UINT64_MAX) { + EXPECT_LE(timing.timeOnDevice, timing.timeInDriver); + } + } + + switch (outputType) { + case OutputType::FULLY_SPECIFIED: + // If the model output operands are fully specified, outputShapes must be either + // either empty, or have the same number of elements as the number of outputs. + ASSERT_EQ(ErrorStatus::NONE, executionStatus); + ASSERT_TRUE(outputShapes.size() == 0 || + outputShapes.size() == test.operandDimensions.size()); + break; + case OutputType::UNSPECIFIED: + // If the model output operands are not fully specified, outputShapes must have + // the same number of elements as the number of outputs. + ASSERT_EQ(ErrorStatus::NONE, executionStatus); + ASSERT_EQ(outputShapes.size(), test.operandDimensions.size()); + break; + case OutputType::INSUFFICIENT: + ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus); + ASSERT_EQ(outputShapes.size(), test.operandDimensions.size()); + ASSERT_FALSE(outputShapes[0].isSufficient); + return; + } + // Go through all outputs, overwrite output dimensions with returned output shapes + if (outputShapes.size() > 0) { + for_each(test.operandDimensions, + [&outputShapes](int idx, std::vector& dim) { + dim = outputShapes[idx].dimensions; + }); + } + + // validate results + outputMemory->read(); + copy_back(&test, outputs_info, outputPtr); + outputMemory->commit(); + // Filter out don't cares + MixedTyped filtered_golden = filter(golden, is_ignored); + MixedTyped filtered_test = filter(test, is_ignored); + + // We want "close-enough" results for float + compare(filtered_golden, filtered_test, fpAtol, fpRtol); + + if (example.expectedMultinomialDistributionTolerance > 0) { + expectMultinomialDistributionWithinTolerance(test, example); + } + } +} +void EvaluatePreparedModel(sp& preparedModel, std::function is_ignored, + const std::vector& examples, + bool hasRelaxedFloat32Model, Executor executor, MeasureTiming measure, + OutputType outputType) { + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, kDefaultAtol, + kDefaultRtol, executor, measure, outputType); +} + +void EvaluatePreparedModel(sp& preparedModel, std::function is_ignored, + const std::vector& examples, + bool hasRelaxedFloat32Model, bool testDynamicOutputShape) { + if (testDynamicOutputShape) { + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::NO, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::NO, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::NO, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::YES, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::YES, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::YES, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::NO, OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::NO, OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::NO, OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::YES, OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::YES, OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::YES, OutputType::INSUFFICIENT); + } else { + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::NO, OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::YES, OutputType::FULLY_SPECIFIED); + } +} + +void PrepareModel(const sp& device, const Model& model, + sp* preparedModel) { + // see if service can handle model + bool fullySupportsModel = false; + Return supportedCall = device->getSupportedOperations_1_2( + model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { + ASSERT_EQ(ErrorStatus::NONE, status); + ASSERT_NE(0ul, supported.size()); + fullySupportsModel = std::all_of(supported.begin(), supported.end(), + [](bool valid) { return valid; }); + }); + ASSERT_TRUE(supportedCall.isOk()); + + // launch prepare model + sp preparedModelCallback = new PreparedModelCallback(); + ASSERT_NE(nullptr, preparedModelCallback.get()); + Return prepareLaunchStatus = device->prepareModel_1_2( + model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec(), + hidl_vec(), HidlToken(), preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); + + // retrieve prepared model + preparedModelCallback->wait(); + ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + sp preparedModelV1_0 = preparedModelCallback->getPreparedModel(); + *preparedModel = IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr); + + // early termination if vendor service cannot fully prepare model + if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { + ASSERT_EQ(nullptr, preparedModel->get()); + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " + "prepare model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "prepare model that it does not support." + << std::endl; + return; + } + EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); + ASSERT_NE(nullptr, preparedModel->get()); +} + +void Execute(const sp& device, std::function create_model, + std::function is_ignored, const std::vector& examples, + bool testDynamicOutputShape) { + Model model = create_model(); + sp preparedModel = nullptr; + PrepareModel(device, model, &preparedModel); + if (preparedModel == nullptr) { + GTEST_SKIP(); + } + EvaluatePreparedModel(preparedModel, is_ignored, examples, + model.relaxComputationFloat32toFloat16, testDynamicOutputShape); +} + +} // namespace generated_tests +} // namespace neuralnetworks +} // namespace hardware +} // namespace android diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h new file mode 100644 index 0000000000..30e5578b66 --- /dev/null +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H + +#include +#include +#include +#include +#include +#include "TestHarness.h" + +namespace android { +namespace hardware { +namespace neuralnetworks { +namespace generated_tests { + +using ::test_helper::MixedTypedExample; + +void PrepareModel(const sp& device, const V1_2::Model& model, + sp* preparedModel); + +void EvaluatePreparedModel(sp& preparedModel, + std::function is_ignored, + const std::vector& examples, + bool hasRelaxedFloat32Model, bool testDynamicOutputShape); + +void Execute(const sp& device, std::function create_model, + std::function is_ignored, const std::vector& examples, + bool testDynamicOutputShape = false); + +} // namespace generated_tests +} // namespace neuralnetworks +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp index 990cab9161..d48c73e331 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp @@ -16,17 +16,17 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" -#include "VtsHalNeuralnetworks.h" - -#include "Callbacks.h" -#include "GeneratedTestHarness.h" -#include "TestHarness.h" -#include "Utils.h" - #include #include #include +#include "1.2/Callbacks.h" +#include "GeneratedTestHarness.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "Utils.h" +#include "VtsHalNeuralnetworks.h" + namespace android { namespace hardware { namespace neuralnetworks { diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp index fa6d54d295..1adb3717e5 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp @@ -16,17 +16,17 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" -#include "VtsHalNeuralnetworks.h" - -#include "Callbacks.h" -#include "GeneratedTestHarness.h" -#include "TestHarness.h" -#include "Utils.h" - #include #include #include +#include "1.2/Callbacks.h" +#include "GeneratedTestHarness.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "Utils.h" +#include "VtsHalNeuralnetworks.h" + namespace android { namespace hardware { namespace neuralnetworks { diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp similarity index 97% rename from neuralnetworks/1.2/vts/functional/GeneratedTests.cpp rename to neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp index 5af3255f42..f9cecf8e28 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp @@ -16,17 +16,17 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" -#include "VtsHalNeuralnetworks.h" - -#include "Callbacks.h" -#include "GeneratedTestHarness.h" -#include "TestHarness.h" -#include "Utils.h" - #include #include #include +#include "1.2/Callbacks.h" +#include "GeneratedTestHarness.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "Utils.h" +#include "VtsHalNeuralnetworks.h" + namespace android { namespace hardware { namespace neuralnetworks { diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp index 8c6391e815..4d6bdbb7e6 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp @@ -18,7 +18,7 @@ #include "VtsHalNeuralnetworks.h" -#include "Callbacks.h" +#include "1.2/Callbacks.h" #include "ExecutionBurstController.h" #include "ExecutionBurstServer.h" #include "TestHarness.h" diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp index a0b6d9aeac..78bb194fb8 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp @@ -16,10 +16,10 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" +#include "1.0/Utils.h" +#include "1.2/Callbacks.h" #include "VtsHalNeuralnetworks.h" -#include "Callbacks.h" - namespace android { namespace hardware { namespace neuralnetworks { @@ -41,10 +41,10 @@ static void validateGetSupportedOperations(const sp& device, const std: const Model& model) { SCOPED_TRACE(message + " [getSupportedOperations_1_2]"); - Return ret = - device->getSupportedOperations_1_2(model, [&](ErrorStatus status, const hidl_vec&) { - EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); - }); + Return ret = device->getSupportedOperations_1_2( + model, [&](ErrorStatus status, const hidl_vec&) { + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); + }); EXPECT_TRUE(ret.isOk()); } @@ -87,36 +87,16 @@ static void validate(const sp& device, const std::string& message, Mode validatePrepareModel(device, message, model, preference); } -// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation, -// so this is efficiently accomplished by moving the element to the end and -// resizing the hidl_vec to one less. -template -static void hidl_vec_removeAt(hidl_vec* vec, uint32_t index) { - if (vec) { - std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end()); - vec->resize(vec->size() - 1); - } -} - -template -static uint32_t hidl_vec_push_back(hidl_vec* vec, const Type& value) { - // assume vec is valid - const uint32_t index = vec->size(); - vec->resize(index + 1); - (*vec)[index] = value; - return index; -} - static uint32_t addOperand(Model* model) { return hidl_vec_push_back(&model->operands, { - .type = OperandType::INT32, - .dimensions = {}, - .numberOfConsumers = 0, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::MODEL_INPUT, - .location = {.poolIndex = 0, .offset = 0, .length = 0}, + .type = OperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 0, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, }); } @@ -243,7 +223,7 @@ static std::vector getInvalidZeroPoints(OperandType type) { case OperandType::TENSOR_QUANT8_ASYMM: return {-1, 256}; case OperandType::TENSOR_QUANT8_SYMM: - return {-129, -1, 1, 128}; + return {-129, -1, 1, 128}; case OperandType::TENSOR_QUANT16_ASYMM: return {-1, 65536}; case OperandType::TENSOR_QUANT16_SYMM: @@ -256,7 +236,7 @@ static std::vector getInvalidZeroPoints(OperandType type) { static void mutateOperandZeroPointTest(const sp& device, const Model& model) { for (size_t operand = 0; operand < model.operands.size(); ++operand) { const std::vector invalidZeroPoints = - getInvalidZeroPoints(model.operands[operand].type); + getInvalidZeroPoints(model.operands[operand].type); for (int32_t invalidZeroPoint : invalidZeroPoints) { const std::string message = "mutateOperandZeroPointTest: operand " + std::to_string(operand) + " has zero point of " + @@ -292,13 +272,13 @@ static void mutateOperand(Operand* operand, OperandType type) { case OperandType::TENSOR_FLOAT16: case OperandType::TENSOR_FLOAT32: newOperand.dimensions = - operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); newOperand.scale = 0.0f; newOperand.zeroPoint = 0; break; case OperandType::TENSOR_INT32: newOperand.dimensions = - operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); newOperand.zeroPoint = 0; break; case OperandType::TENSOR_QUANT8_ASYMM: @@ -306,19 +286,20 @@ static void mutateOperand(Operand* operand, OperandType type) { case OperandType::TENSOR_QUANT16_ASYMM: case OperandType::TENSOR_QUANT16_SYMM: newOperand.dimensions = - operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f; break; case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: { newOperand.dimensions = - operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); newOperand.scale = 0.0f; newOperand.zeroPoint = 0; SymmPerChannelQuantParams channelQuant; channelQuant.channelDim = 0; channelQuant.scales = hidl_vec( - operand->dimensions.size() > 0 ? static_cast(operand->dimensions[0]) : 0); + operand->dimensions.size() > 0 ? static_cast(operand->dimensions[0]) + : 0); for (size_t i = 0; i < channelQuant.scales.size(); ++i) { channelQuant.scales[i] = 1.0f; } @@ -435,7 +416,7 @@ static void mutateOperationTypeTest(const sp& device, const Model& mode std::to_string(invalidOperationType); validate(device, message, model, [operation, invalidOperationType](Model* model) { model->operations[operation].type = - static_cast(invalidOperationType); + static_cast(invalidOperationType); }); } } @@ -690,7 +671,7 @@ static void addOperationInputTest(const sp& device, const Model& model) static void addOperationOutputTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { const std::string message = - "addOperationOutputTest: operation " + std::to_string(operation); + "addOperationOutputTest: operation " + std::to_string(operation); validate(device, message, model, [operation](Model* model) { uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT); hidl_vec_push_back(&model->operations[operation].outputs, index); @@ -702,14 +683,14 @@ static void addOperationOutputTest(const sp& device, const Model& model ///////////////////////// VALIDATE EXECUTION PREFERENCE ///////////////////////// static const int32_t invalidExecutionPreferences[] = { - static_cast(ExecutionPreference::LOW_POWER) - 1, // lower bound - static_cast(ExecutionPreference::SUSTAINED_SPEED) + 1, // upper bound + static_cast(ExecutionPreference::LOW_POWER) - 1, // lower bound + static_cast(ExecutionPreference::SUSTAINED_SPEED) + 1, // upper bound }; static void mutateExecutionPreferenceTest(const sp& device, const Model& model) { for (int32_t preference : invalidExecutionPreferences) { const std::string message = - "mutateExecutionPreferenceTest: preference " + std::to_string(preference); + "mutateExecutionPreferenceTest: preference " + std::to_string(preference); validate(device, message, model, [](Model*) {}, static_cast(preference)); } diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp index e935aaa1fa..a7e83289f1 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp @@ -16,17 +16,18 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" -#include "VtsHalNeuralnetworks.h" - -#include "Callbacks.h" -#include "ExecutionBurstController.h" -#include "TestHarness.h" -#include "Utils.h" - #include #include #include +#include "1.0/Utils.h" +#include "1.2/Callbacks.h" +#include "ExecutionBurstController.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "Utils.h" +#include "VtsHalNeuralnetworks.h" + namespace android { namespace hardware { namespace neuralnetworks { @@ -137,26 +138,6 @@ static void validate(const sp& preparedModel, const std::string& } } -// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation, -// so this is efficiently accomplished by moving the element to the end and -// resizing the hidl_vec to one less. -template -static void hidl_vec_removeAt(hidl_vec* vec, uint32_t index) { - if (vec) { - std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end()); - vec->resize(vec->size() - 1); - } -} - -template -static uint32_t hidl_vec_push_back(hidl_vec* vec, const Type& value) { - // assume vec is valid - const uint32_t index = vec->size(); - vec->resize(index + 1); - (*vec)[index] = value; - return index; -} - ///////////////////////// REMOVE INPUT //////////////////////////////////// static void removeInputTest(const sp& preparedModel, const Request& request) { @@ -197,11 +178,13 @@ std::vector createRequests(const std::vector& exampl for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) { if (inputs_info.size() <= static_cast(index)) inputs_info.resize(index + 1); RequestArgument arg = { - .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast(s)}, - .dimensions = {}, + .location = {.poolIndex = INPUT, + .offset = 0, + .length = static_cast(s)}, + .dimensions = {}, }; RequestArgument arg_empty = { - .hasNoValue = true, + .hasNoValue = true, }; inputs_info[index] = s ? arg : arg_empty; inputSize += s; @@ -219,8 +202,10 @@ std::vector createRequests(const std::vector& exampl for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) { if (outputs_info.size() <= static_cast(index)) outputs_info.resize(index + 1); RequestArgument arg = { - .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast(s)}, - .dimensions = {}, + .location = {.poolIndex = OUTPUT, + .offset = 0, + .length = static_cast(s)}, + .dimensions = {}, }; outputs_info[index] = arg; outputSize += s; diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp index 666f9b5b00..bd24edc249 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp @@ -20,7 +20,7 @@ #include -#include "Callbacks.h" +#include "1.2/Callbacks.h" namespace android { namespace hardware { diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h index 80e810a5f7..90dfe25312 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h @@ -14,24 +14,23 @@ * limitations under the License. */ -#ifndef VTS_HAL_NEURALNETWORKS_V1_2_H -#define VTS_HAL_NEURALNETWORKS_V1_2_H - -#include "Callbacks.h" +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H +#include +#include +#include #include #include #include #include - -#include -#include - -#include #include + #include #include +#include "1.2/Callbacks.h" + namespace android { namespace hardware { namespace neuralnetworks { @@ -50,7 +49,7 @@ class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvB NeuralnetworksHidlEnvironment(); ~NeuralnetworksHidlEnvironment() override; - public: + public: static NeuralnetworksHidlEnvironment* getInstance(); void registerTestServices() override; }; @@ -59,30 +58,30 @@ class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvB class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase { DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest); - public: + public: NeuralnetworksHidlTest(); ~NeuralnetworksHidlTest() override; void SetUp() override; void TearDown() override; - protected: + protected: sp device; }; // Tag for the validation tests class ValidationTest : public NeuralnetworksHidlTest { - protected: - void validateEverything(const Model& model, const std::vector& requests); - void validateFailure(const Model& model, const std::vector& requests); + protected: + void validateEverything(const Model& model, const std::vector& requests); + void validateFailure(const Model& model, const std::vector& requests); - private: - void validateModel(const Model& model); - void validateRequests(const sp& preparedModel, - const std::vector& requests); - void validateRequestFailure(const sp& preparedModel, - const std::vector& requests); - void validateBurst(const sp& preparedModel, - const std::vector& requests); + private: + void validateModel(const Model& model); + void validateRequests(const sp& preparedModel, + const std::vector& requests); + void validateRequestFailure(const sp& preparedModel, + const std::vector& requests); + void validateBurst(const sp& preparedModel, + const std::vector& requests); }; // Tag for the generated tests @@ -93,7 +92,7 @@ class DynamicOutputShapeTest : public NeuralnetworksHidlTest {}; // Utility function to get PreparedModel from callback and downcast to V1_2. sp getPreparedModel_1_2( - const sp& callback); + const sp& callback); } // namespace functional } // namespace vts @@ -110,4 +109,4 @@ namespace android::hardware::neuralnetworks::V1_0 { } // namespace android::hardware::neuralnetworks::V1_0 -#endif // VTS_HAL_NEURALNETWORKS_V1_2_H +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H diff --git a/neuralnetworks/1.0/vts/functional/Callbacks.h b/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h similarity index 94% rename from neuralnetworks/1.0/vts/functional/Callbacks.h rename to neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h index 4707d0a251..212a8875df 100644 --- a/neuralnetworks/1.0/vts/functional/Callbacks.h +++ b/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h @@ -14,14 +14,11 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H -#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H -#include -#include #include #include -#include #include #include #include @@ -60,7 +57,7 @@ using V1_0::ErrorStatus; * std::condition_variable, or std::experimental::latch instead. */ class CallbackBase { - public: + public: CallbackBase(); ~CallbackBase(); @@ -79,8 +76,8 @@ class CallbackBase { * before the time duration expired, std::cv_status::timeout * otherwise. */ - template - std::cv_status wait_for(const std::chrono::duration& timeout_duration); + template + std::cv_status wait_for(const std::chrono::duration& timeout_duration); /** * CallbackBase::on_finish binds a function to the callback object. This @@ -144,7 +141,7 @@ class CallbackBase { */ void join_thread(); - protected: + protected: /** * CallbackBase::notify enables all prior and future wait* calls on the * callback object to proceed. The call to CallbackBase::notify happens @@ -158,16 +155,16 @@ class CallbackBase { */ void notify(); - private: + private: // Same as CallbackBase::join_thread but assumes we already hold a lock on // mMutex. void join_thread_locked(); - bool mNotified; - std::mutex mMutex; - std::condition_variable mCondition; + bool mNotified; + std::mutex mMutex; + std::condition_variable mCondition; std::function mPostWork; - std::thread mThread; + std::thread mThread; }; /** @@ -185,7 +182,7 @@ class CallbackBase { * IDevice::prepareModel. */ class PreparedModelCallback : public CallbackBase, public IPreparedModelCallback { - public: + public: PreparedModelCallback(); ~PreparedModelCallback() override; @@ -241,8 +238,8 @@ class PreparedModelCallback : public CallbackBase, public IPreparedModelCallback */ sp getPreparedModel(); - private: - ErrorStatus mErrorStatus; + private: + ErrorStatus mErrorStatus; sp mPreparedModel; }; @@ -260,8 +257,8 @@ class PreparedModelCallback : public CallbackBase, public IPreparedModelCallback * IExecutionCallback. This callback object is passed as an argument to * IPreparedModel::execute. */ -class ExecutionCallback : public CallbackBase, public IExecutionCallback { - public: +class ExecutionCallback : public CallbackBase, public IExecutionCallback { + public: ExecutionCallback(); ~ExecutionCallback() override; @@ -376,19 +373,19 @@ class ExecutionCallback : public CallbackBase, public IExecutionCallback { */ Timing getTiming(); - private: + private: ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE; std::vector mOutputShapes = {}; Timing mTiming = {}; }; - // template function implementation(s) below this point -template -std::cv_status CallbackBase::wait_for(const std::chrono::duration& timeout_duration) { +template +std::cv_status CallbackBase::wait_for(const std::chrono::duration& timeout_duration) { std::unique_lock lock(mMutex); - std::cv_status status = mCondition.wait_for(lock, timeout_duration, [this]{return mNotified;}); + std::cv_status status = + mCondition.wait_for(lock, timeout_duration, [this] { return mNotified; }); if (status != std::cv_status::timeout) { join_thread_locked(); } @@ -401,4 +398,4 @@ std::cv_status CallbackBase::wait_for(const std::chrono::duration& t } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H From 822686148920215db6de7b33921be29bf76e5778 Mon Sep 17 00:00:00 2001 From: Slava Shklyaev Date: Wed, 29 May 2019 22:21:53 +0100 Subject: [PATCH 0025/1022] Update paths to NNAPI VTS models See change If3bfbdfa016cd32a39b8a63028481da7318d6e02 Bug: 124040454 Test: VtsHalNeuralnetworksV1_0TargetTest Test: VtsHalNeuralnetworksV1_1TargetTest Test: VtsHalNeuralnetworksV1_1CompatV1_0TargetTest Test: VtsHalNeuralnetworksV1_2TargetTest Test: VtsHalNeuralnetworksV1_2CompatV1_0TargetTest Test: VtsHalNeuralnetworksV1_2CompatV1_1TargetTest Change-Id: I17dd4377ee5110ac10ae8142fa7403329eda067c --- neuralnetworks/1.0/vts/functional/GeneratedTestsV1_0.cpp | 2 +- neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp | 2 +- neuralnetworks/1.1/vts/functional/GeneratedTestsV1_1.cpp | 2 +- neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp | 4 ++-- neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp | 2 +- neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp | 2 +- neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestsV1_0.cpp index 74946a5cae..32e9a7f4ce 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestsV1_0.cpp +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestsV1_0.cpp @@ -42,7 +42,7 @@ using ::test_helper::MixedTypedExample; std::vector createRequests(const std::vector& examples); // in frameworks/ml/nn/runtime/tests/generated/ -#include "all_generated_V1_0_vts_tests.cpp" +#include "vts/V1_0/all_generated_V1_0_vts_tests.cpp" } // namespace functional } // namespace vts diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp index 10cf5a9e5a..23e6534231 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp @@ -43,7 +43,7 @@ using ::test_helper::MixedTypedExample; std::vector createRequests(const std::vector& examples); // in frameworks/ml/nn/runtime/tests/generated/ -#include "all_generated_V1_0_vts_tests.cpp" +#include "vts/V1_1/all_generated_V1_0_vts_tests.cpp" } // namespace functional } // namespace vts diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_1.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_1.cpp index 079c18c449..680b93aaee 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_1.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_1.cpp @@ -43,7 +43,7 @@ using ::test_helper::MixedTypedExample; std::vector createRequests(const std::vector& examples); // in frameworks/ml/nn/runtime/tests/generated/ -#include "all_generated_V1_1_vts_tests.cpp" +#include "vts/V1_1/all_generated_V1_1_vts_tests.cpp" } // namespace functional } // namespace vts diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp index 9cabb7b04e..adbf224fee 100644 --- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp @@ -50,7 +50,7 @@ namespace float32_model { // In frameworks/ml/nn/runtime/test/generated/, creates a hidl model of float32 mobilenet. #include "examples/mobilenet_224_gender_basic_fixed.example.cpp" -#include "vts_models/mobilenet_224_gender_basic_fixed.model.cpp" +#include "vts/V1_2/models/mobilenet_224_gender_basic_fixed.model.cpp" // Prevent the compiler from complaining about an otherwise unused function. [[maybe_unused]] auto dummy_createTestModel = createTestModel_dynamic_output_shape; @@ -73,7 +73,7 @@ namespace quant8_model { // In frameworks/ml/nn/runtime/test/generated/, creates a hidl model of quant8 mobilenet. #include "examples/mobilenet_quantized.example.cpp" -#include "vts_models/mobilenet_quantized.model.cpp" +#include "vts/V1_2/models/mobilenet_quantized.model.cpp" // Prevent the compiler from complaining about an otherwise unused function. [[maybe_unused]] auto dummy_createTestModel = createTestModel_dynamic_output_shape; diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp index d48c73e331..b4e6696403 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp @@ -42,7 +42,7 @@ using ::test_helper::MixedTypedExample; std::vector createRequests(const std::vector& examples); // in frameworks/ml/nn/runtime/tests/generated/ -#include "all_generated_V1_0_vts_tests.cpp" +#include "vts/V1_2/all_generated_V1_0_vts_tests.cpp" } // namespace functional } // namespace vts diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp index 1adb3717e5..33212fb002 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp @@ -42,7 +42,7 @@ using ::test_helper::MixedTypedExample; std::vector createRequests(const std::vector& examples); // in frameworks/ml/nn/runtime/tests/generated/ -#include "all_generated_V1_1_vts_tests.cpp" +#include "vts/V1_2/all_generated_V1_1_vts_tests.cpp" } // namespace functional } // namespace vts diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp index f9cecf8e28..8481b4d7eb 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp @@ -42,7 +42,7 @@ using ::test_helper::MixedTypedExample; std::vector createRequests(const std::vector& examples); // in frameworks/ml/nn/runtime/tests/generated/ -#include "all_generated_V1_2_vts_tests.cpp" +#include "vts/V1_2/all_generated_V1_2_vts_tests.cpp" // Generated from spec/strided_slice_invalid_output_dims.mod.py. // TODO(b/132155416): Make this part of all_generated_V1_2_vts_tests.cpp. From 98f2715168f774b4051c9d7d09aba3b754e3121d Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Mon, 8 Jul 2019 15:26:34 -0700 Subject: [PATCH 0026/1022] Fix the name of the constant for device [dis]connect parameter During the transition to Treble, "device connect" / "disconnect" parameter was erroneously attributed to audio streams. This issue got fixed in Audio HAL V4.0, but AudioParameter file was still using incorrect name for the constant. Test: make Change-Id: I18e1e3fccad3d41372f3c5c046af4f6ffd83328b --- audio/core/all-versions/default/Device.cpp | 2 +- audio/core/all-versions/default/Stream.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp index bec22df6d5..1a9df217e1 100644 --- a/audio/core/all-versions/default/Device.cpp +++ b/audio/core/all-versions/default/Device.cpp @@ -378,7 +378,7 @@ Return Device::getMicrophones(getMicrophones_cb _hidl_cb) { } Return Device::setConnectedState(const DeviceAddress& address, bool connected) { - auto key = connected ? AudioParameter::keyStreamConnect : AudioParameter::keyStreamDisconnect; + auto key = connected ? AudioParameter::keyDeviceConnect : AudioParameter::keyDeviceDisconnect; return setParam(key, address); } #endif diff --git a/audio/core/all-versions/default/Stream.cpp b/audio/core/all-versions/default/Stream.cpp index b995657087..e62f6d3b0a 100644 --- a/audio/core/all-versions/default/Stream.cpp +++ b/audio/core/all-versions/default/Stream.cpp @@ -243,8 +243,8 @@ Return Stream::setParameters(const hidl_vec& parameters) Return Stream::setConnectedState(const DeviceAddress& address, bool connected) { return setParam( - connected ? AudioParameter::keyStreamConnect : AudioParameter::keyStreamDisconnect, - address); + connected ? AudioParameter::keyDeviceConnect : AudioParameter::keyDeviceDisconnect, + address); } #elif MAJOR_VERSION >= 4 Return Stream::getDevices(getDevices_cb _hidl_cb) { From d365e2b5ffd4236c9b85e6f00d48485187c65b9f Mon Sep 17 00:00:00 2001 From: Amy Date: Mon, 3 Dec 2018 18:18:50 -0800 Subject: [PATCH 0027/1022] Add an xsd file for Short Audio Descriptor xml config file. Please see platform/device/*/files/sadConfigSample.xml as a sample XML. Test: xmllint --noout --schema hardware/interfaces/tv/cec/1.0/config/sadConfig.xsd --xinclude device/harman/atom/files/sadConfig.xml Bug: 80297701 Change-Id: Ic69aff4f480a206f86ef0c345b6d3f7eb87e8c1f (cherry picked from commit 652af560cd420107b7eb5eac2307e3b53f4294a9) --- tv/cec/1.0/config/sadConfig.xsd | 86 +++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 tv/cec/1.0/config/sadConfig.xsd diff --git a/tv/cec/1.0/config/sadConfig.xsd b/tv/cec/1.0/config/sadConfig.xsd new file mode 100644 index 0000000000..7f99311151 --- /dev/null +++ b/tv/cec/1.0/config/sadConfig.xsd @@ -0,0 +1,86 @@ + + + + + + + + List the config versions supported by Short Audio Descriptor(SAD) config. + + + + + + + + + + + Device section: + There is a list of configurations in this SAD config for all the input audio + devices that the current Android device supports. + Each device has the following attributes: + "type": type of the audio device. + And the following element + : the supported format info of the device. There can be + multiple formats supported by one audio device. + + + + + + + + + + + SupportedFormat section: + The details of the short audio descriptor of a specific audio format + supported by the audio device. Attributes as follows: + "format": format enum of the current supported format. + "descriptor": three-byte short audio descriptor for the given format in hex. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 7763d5354524d625e3d2b81f17e8e6194e7adc16 Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Thu, 11 Jul 2019 09:07:49 -0700 Subject: [PATCH 0028/1022] Remove compiler flag for dynamic output shape tests. Having separate VTS models and tests for difference HAL version. This compiler flag is no longer needed. Bug: 122740334 Test: All VTS 1.x and 1.xCompat1.y Change-Id: Idbd96a954da9bd5a0e0e66afd9120d84a1efc784 --- neuralnetworks/1.2/vts/functional/Android.bp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index b48646f6e2..31b853242c 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -56,9 +56,6 @@ cc_test { "GeneratedTestsV1_0.cpp", "ValidateBurst.cpp", ], - cflags: [ - "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE" - ], } // Tests for V1_1 models using the V1_2 HAL. @@ -69,9 +66,6 @@ cc_test { "GeneratedTestsV1_1.cpp", "ValidateBurst.cpp", ], - cflags: [ - "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE" - ], } // Tests for V1_2 models. @@ -84,9 +78,6 @@ cc_test { "GeneratedTestsV1_2.cpp", "ValidateBurst.cpp", ], - cflags: [ - "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE" - ], } cc_test { @@ -98,7 +89,6 @@ cc_test { "ValidateBurst.cpp", ], cflags: [ - "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE", "-DPRESUBMIT_NOT_VTS", ], } From 0ce19b8fd95034e5de9f6a1f513fdb29ea814e7d Mon Sep 17 00:00:00 2001 From: Kai Date: Tue, 9 Jul 2019 15:56:16 -0700 Subject: [PATCH 0029/1022] Update properties' config Update defaultConfig according to types.hal Bug: 136215520 Test: 1. replace vhal to default vhal 2. run unit tests under vehicleHal_test Change-Id: Id0b58bc9e2cc18d68ea44387ce7634f053e51e1c --- .../default/impl/vhal_v2_0/DefaultConfig.h | 43 +++++-------------- 1 file changed, 11 insertions(+), 32 deletions(-) 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 a46de24b16..3e59584983 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 @@ -167,7 +167,6 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::STATIC, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.floatValues = {15000.0f}}}, @@ -177,14 +176,13 @@ const ConfigDeclaration kVehicleProperties[]{ .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::STATIC, }, - .initialValue = {.int32Values = {1}}}, + .initialValue = {.int32Values = {(int)FuelType::FUEL_TYPE_UNLEADED}}}, {.config = { .prop = toInt(VehicleProperty::INFO_EV_BATTERY_CAPACITY), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::STATIC, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.floatValues = {150000.0f}}}, @@ -194,14 +192,13 @@ const ConfigDeclaration kVehicleProperties[]{ .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::STATIC, }, - .initialValue = {.int32Values = {1}}}, + .initialValue = {.int32Values = {(int)EvConnectorType::IEC_TYPE_1_AC}}}, {.config = { .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::STATIC, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {SEAT_1_LEFT}}}, @@ -210,7 +207,6 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::INFO_FUEL_DOOR_LOCATION), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::STATIC, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {FUEL_DOOR_REAR_LEFT}}}, @@ -219,7 +215,6 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::INFO_EV_PORT_LOCATION), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::STATIC, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT}}}, @@ -234,7 +229,7 @@ const ConfigDeclaration kVehicleProperties[]{ { .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED), .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, .minSampleRate = 1.0f, .maxSampleRate = 10.0f, }, @@ -265,7 +260,7 @@ const ConfigDeclaration kVehicleProperties[]{ { .prop = toInt(VehicleProperty::PERF_ODOMETER), .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, }, .initialValue = {.floatValues = {0.0f}}}, @@ -285,8 +280,7 @@ const ConfigDeclaration kVehicleProperties[]{ { .prop = toInt(VehicleProperty::FUEL_LEVEL), .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, }, .initialValue = {.floatValues = {15000.0f}}}, @@ -295,7 +289,6 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::FUEL_DOOR_OPEN), .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {0}}}, @@ -303,8 +296,7 @@ const ConfigDeclaration kVehicleProperties[]{ { .prop = toInt(VehicleProperty::EV_BATTERY_LEVEL), .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, }, .initialValue = {.floatValues = {150000.0f}}}, @@ -313,7 +305,6 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::EV_CHARGE_PORT_OPEN), .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {0}}}, @@ -322,7 +313,6 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::EV_CHARGE_PORT_CONNECTED), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {0}}}, @@ -330,17 +320,15 @@ const ConfigDeclaration kVehicleProperties[]{ { .prop = toInt(VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE), .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, }, .initialValue = {.floatValues = {0.0f}}}, {.config = { .prop = toInt(VehicleProperty::RANGE_REMAINING), - .access = VehiclePropertyAccess::READ, + .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::CONTINUOUS, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, .minSampleRate = 1.0f, .maxSampleRate = 2.0f, }, @@ -365,7 +353,7 @@ const ConfigDeclaration kVehicleProperties[]{ VehicleAreaConfig{ .areaId = WHEEL_REAR_RIGHT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f, }}}, - .initialValue = {.floatValues = {200}}}, // units in kPa + .initialValue = {.floatValues = {200.0f}}}, // units in kPa {.config = { @@ -388,7 +376,6 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {0}}}, @@ -541,8 +528,8 @@ const ConfigDeclaration kVehicleProperties[]{ {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS), .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS}, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}}, + .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS} + }, .initialValue = {.int32Values = {(int)VehicleUnit::FAHRENHEIT}}}, {.config = @@ -713,7 +700,6 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::HEADLIGHTS_STATE), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {LIGHT_STATE_ON}}}, @@ -722,7 +708,6 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_STATE), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {LIGHT_STATE_ON}}}, @@ -731,7 +716,6 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::FOG_LIGHTS_STATE), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {LIGHT_STATE_ON}}}, @@ -740,7 +724,6 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::HAZARD_LIGHTS_STATE), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {LIGHT_STATE_ON}}}, @@ -749,7 +732,6 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::HEADLIGHTS_SWITCH), .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}}, @@ -758,7 +740,6 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_SWITCH), .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}}, @@ -767,7 +748,6 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::FOG_LIGHTS_SWITCH), .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}}, @@ -776,7 +756,6 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::HAZARD_LIGHTS_SWITCH), .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}}, From 37edd052ce2b30d6550efcbb5532011e7b0f4370 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Thu, 11 Jul 2019 15:48:38 -0700 Subject: [PATCH 0030/1022] Fixing client composition setup on non-SRGB color mode displays Fixing client composition behavior to match SF - dataspace of client composition is determined by the color mode of the display Bug: 135045017 Test: build, boot, VtsHalGraphicsComposerV2_2TargetTest Change-Id: I88371d173501875b59bf40092943cebff3d22b06 --- .../composer/2.2/utils/vts/ReadbackVts.cpp | 12 +++ .../include/composer-vts/2.2/ReadbackVts.h | 2 + ...VtsHalGraphicsComposerV2_2ReadbackTest.cpp | 84 +++++++++++++------ 3 files changed, 73 insertions(+), 25 deletions(-) diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp index 91efc6ff07..02ab49b0a8 100644 --- a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp +++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp @@ -55,11 +55,23 @@ std::string ReadbackHelper::getDataspaceString(Dataspace dataspace) { return std::string("V0_SRGB"); case Dataspace::DISPLAY_P3: return std::string("DISPLAY_P3"); + case Dataspace::UNKNOWN: + return std::string("UNKNOWN"); default: return std::string("Unsupported dataspace for readback"); } } +Dataspace ReadbackHelper::getDataspaceForColorMode(ColorMode mode) { + switch (mode) { + case ColorMode::DISPLAY_P3: + return Dataspace::DISPLAY_P3; + case ColorMode::SRGB: + default: + return Dataspace::UNKNOWN; + } +} + LayerSettings TestLayer::toRenderEngineLayerSettings() { LayerSettings layerSettings; diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h index 5304cd4b23..9fa1c3c699 100644 --- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h +++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h @@ -146,6 +146,8 @@ class ReadbackHelper : public ::testing::VtsHalHidlTargetTestBase { static std::string getDataspaceString(Dataspace dataspace); + static Dataspace getDataspaceForColorMode(ColorMode mode); + static int32_t GetBytesPerPixel(PixelFormat pixelFormat); static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData, diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp index 72c9496056..fd46e37052 100644 --- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp @@ -413,12 +413,28 @@ TEST_F(GraphicsComposerReadbackTest, ClientComposition) { ASSERT_EQ(1, mReader->mCompositionChanges.size()); ASSERT_EQ(1, mReader->mCompositionChanges[0].second); - // create client target buffer - uint32_t clientStride; PixelFormat clientFormat = PixelFormat::RGBA_8888; uint64_t clientUsage = static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_CLIENT_TARGET); + Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode); + IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight}; + + bool clientTargetSupported = mComposerClient->getClientTargetSupport_2_2( + mPrimaryDisplay, layer->mWidth, layer->mHeight, clientFormat, clientDataspace); + // if the client target format is not supported, skip this + // configuration + if (!clientTargetSupported) { + std::cout << "Client target configuration width: " << layer->mWidth + << " height: " << layer->mHeight + << " pixel format: PixelFormat::RGBA_8888 dataspace: " + << ReadbackHelper::getDataspaceString(clientDataspace) + << " unsupported for display" << std::endl; + continue; + } + + // create client target buffer + uint32_t clientStride; const native_handle_t* clientBufferHandle = mGralloc->allocate(layer->mWidth, layer->mHeight, layer->mLayerCount, clientFormat, clientUsage, /*import*/ true, &clientStride); @@ -436,8 +452,7 @@ TEST_F(GraphicsComposerReadbackTest, ClientComposition) { close(clientFence); } - IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight}; - mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN, + mWriter->setClientTarget(0, clientBufferHandle, clientFence, clientDataspace, std::vector(1, damage)); layer->setToClientComposition(mWriter); @@ -507,22 +522,46 @@ TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) { ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors)); deviceLayer->write(mWriter); - auto clientLayer = std::make_shared( - mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, mDisplayHeight / 2, - PixelFormat::RGBA_8888, IComposerClient::Composition::CLIENT); - IComposerClient::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}; - clientLayer->setDisplayFrame(clientFrame); - clientLayer->setZOrder(0); - clientLayer->write(mWriter); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - - // create client target buffer - uint32_t clientStride; PixelFormat clientFormat = PixelFormat::RGBA_8888; uint64_t clientUsage = static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_CLIENT_TARGET); + Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode); + int32_t clientWidth = mDisplayWidth; + int32_t clientHeight = mDisplayHeight / 2; + + bool clientTargetSupported = mComposerClient->getClientTargetSupport_2_2( + mPrimaryDisplay, clientWidth, clientHeight, clientFormat, clientDataspace); + // if the client target format is not supported, skip this + // configuration + if (!clientTargetSupported) { + std::cout << "Client target configuration width: " << clientWidth + << " height: " << clientHeight + << " pixel format: PixelFormat::RGBA_8888 dataspace: " + << ReadbackHelper::getDataspaceString(clientDataspace) + << " unsupported for display" << std::endl; + continue; + } + + auto clientLayer = std::make_shared( + mComposerClient, mGralloc, mPrimaryDisplay, clientWidth, clientHeight, + PixelFormat::RGBA_FP16, IComposerClient::Composition::DEVICE); + IComposerClient::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}; + clientLayer->setDisplayFrame(clientFrame); + clientLayer->setZOrder(0); + clientLayer->write(mWriter); + mWriter->validateDisplay(); + execute(); + + if (mReader->mCompositionChanges.size() != 1) { + std::cout << "HWC asked for none or more than 1 composition change, skipping" + << std::endl; + mReader->mCompositionChanges.clear(); + continue; + } + // create client target buffer + ASSERT_EQ(1, mReader->mCompositionChanges[0].second); + uint32_t clientStride; const native_handle_t* clientBufferHandle = mGralloc->allocate(mDisplayWidth, mDisplayHeight, clientLayer->mLayerCount, clientFormat, clientUsage, /*import*/ true, &clientStride); @@ -542,19 +581,14 @@ TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) { close(clientFence); } - mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN, + mWriter->setClientTarget(0, clientBufferHandle, clientFence, clientDataspace, std::vector(1, clientFrame)); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); + clientLayer->setToClientComposition(mWriter); mWriter->validateDisplay(); execute(); - if (mReader->mCompositionChanges.size() != 0) { - clearCommandReaderState(); - std::cout << "Composition change requested, skipping test" << std::endl; - GTEST_SUCCEED() << "Composition change requested, skipping test"; - return; - } + ASSERT_EQ(0, mReader->mCompositionChanges.size()); ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); execute(); ASSERT_EQ(0, mReader->mErrors.size()); From 6d1493018f0940c692e59f2b32f644e0af27e950 Mon Sep 17 00:00:00 2001 From: "jie.yuan" Date: Wed, 3 Jul 2019 11:01:06 +0800 Subject: [PATCH 0031/1022] VTS : fix vts fail [1/1] Problem: VtsHalGraphicsComposerV2_1Target#GraphicsComposerHidlCommandTest.PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES fail the testcase setcolormode SRGB without check if current device support SRGB Solution: change setColorMode from SRGB to NATIVE Verify: verify in on franklin Bug:135375302 Test: build, boot, VtsHalGraphicsComposerV2_1TargetTest Change-Id: I5eebe5f530e3b62037d669992cf2eca0849f10be --- .../2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp index 30b96949dc..fa5ace65b1 100644 --- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp +++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp @@ -790,7 +790,7 @@ TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY) { TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) { mWriter->selectDisplay(mPrimaryDisplay); mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::ON); - mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB); + mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::NATIVE); auto handle = allocate(); ASSERT_NE(nullptr, handle); From 23d0e562e0013469cc1aacec4c221db406ce8789 Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Tue, 16 Jul 2019 16:52:06 -0700 Subject: [PATCH 0032/1022] Update NN VTS callback objects The VTS Callback files are a subset of the Callback files in frameworks/ml/nn/runtime/Callbacks.*. This CL syncs the implementations, removing the functionality that is not needed in VTS. Fixes: 132322149 Test: mma Test: VtsHalNeuralnetworksV1_0TargetTest Test: VtsHalNeuralnetworksV1_1TargetTest Test: VtsHalNeuralnetworksV1_2TargetTest Change-Id: I114ce7f3b6c3d58de0196e9508209614d0a73e11 --- .../1.0/vts/functional/Callbacks.cpp | 150 ++---- .../vts/functional/include/1.0/Callbacks.h | 337 ++++-------- .../1.2/vts/functional/Callbacks.cpp | 188 +++---- .../functional/CompilationCachingTests.cpp | 1 + .../vts/functional/include/1.2/Callbacks.h | 489 ++++++++---------- 5 files changed, 442 insertions(+), 723 deletions(-) diff --git a/neuralnetworks/1.0/vts/functional/Callbacks.cpp b/neuralnetworks/1.0/vts/functional/Callbacks.cpp index 2b5723dc3d..37afcf0bd9 100644 --- a/neuralnetworks/1.0/vts/functional/Callbacks.cpp +++ b/neuralnetworks/1.0/vts/functional/Callbacks.cpp @@ -14,130 +14,78 @@ * limitations under the License. */ +#define LOG_TAG "Callbacks" + #include "1.0/Callbacks.h" + #include -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_0 { -namespace implementation { +namespace android::hardware::neuralnetworks::V1_0::implementation { -CallbackBase::CallbackBase() : mNotified(false) {} - -CallbackBase::~CallbackBase() { - // Note that we cannot call CallbackBase::join_thread from here: - // CallbackBase is intended to be reference counted, and it is possible that - // the reference count drops to zero in the bound thread, causing the - // bound thread to call this destructor. If a thread tries to join - // itself, it throws an exception, producing a message like the - // following: - // - // terminating with uncaught exception of type std::__1::system_error: - // thread::join failed: Resource deadlock would occur -} - -void CallbackBase::wait() { - std::unique_lock lock(mMutex); - mCondition.wait(lock, [this]{return mNotified;}); - join_thread_locked(); -} - -bool CallbackBase::on_finish(std::function post_work) { - std::lock_guard lock(mMutex); - if (mPostWork != nullptr) { - LOG(ERROR) << "CallbackBase::on_finish -- a post-work function has already been bound to " - "this callback object"; - return false; - } - if (post_work == nullptr) { - LOG(ERROR) << "CallbackBase::on_finish -- the new post-work function is invalid"; - return false; - } - mPostWork = std::move(post_work); - return true; -} - -bool CallbackBase::bind_thread(std::thread&& asyncThread) { - std::lock_guard lock(mMutex); - if (mThread.joinable()) { - LOG(ERROR) << "CallbackBase::bind_thread -- a thread has already been bound to this " - "callback object"; - return false; - } - if (!asyncThread.joinable()) { - LOG(ERROR) << "CallbackBase::bind_thread -- the new thread is not joinable"; - return false; - } - mThread = std::move(asyncThread); - return true; -} - -void CallbackBase::join_thread() { - std::lock_guard lock(mMutex); - join_thread_locked(); -} - -void CallbackBase::notify() { - { - std::lock_guard lock(mMutex); - mNotified = true; - if (mPostWork != nullptr) { - bool success = mPostWork(); - if (!success) { - LOG(ERROR) << "CallbackBase::notify -- post work failed"; - } - } - } - mCondition.notify_all(); -} - -void CallbackBase::join_thread_locked() { - if (mThread.joinable()) { - mThread.join(); - } -} - -PreparedModelCallback::PreparedModelCallback() : - mErrorStatus(ErrorStatus::GENERAL_FAILURE), mPreparedModel(nullptr) {} - -PreparedModelCallback::~PreparedModelCallback() {} +// PreparedModelCallback methods begin here Return PreparedModelCallback::notify(ErrorStatus errorStatus, - const sp& preparedModel) { - mErrorStatus = errorStatus; - mPreparedModel = preparedModel; - CallbackBase::notify(); + const sp& preparedModel) { + { + std::lock_guard hold(mMutex); + + // quick-return if object has already been notified + if (mNotified) { + return Void(); + } + + // store results and mark as notified + mErrorStatus = errorStatus; + mPreparedModel = preparedModel; + mNotified = true; + } + + mCondition.notify_all(); return Void(); } -ErrorStatus PreparedModelCallback::getStatus() { +void PreparedModelCallback::wait() const { + std::unique_lock lock(mMutex); + mCondition.wait(lock, [this] { return mNotified; }); +} + +ErrorStatus PreparedModelCallback::getStatus() const { wait(); return mErrorStatus; } -sp PreparedModelCallback::getPreparedModel() { +sp PreparedModelCallback::getPreparedModel() const { wait(); return mPreparedModel; } -ExecutionCallback::ExecutionCallback() : mErrorStatus(ErrorStatus::GENERAL_FAILURE) {} - -ExecutionCallback::~ExecutionCallback() {} +// ExecutionCallback methods begin here Return ExecutionCallback::notify(ErrorStatus errorStatus) { - mErrorStatus = errorStatus; - CallbackBase::notify(); + { + std::lock_guard hold(mMutex); + + // quick-return if object has already been notified + if (mNotified) { + return Void(); + } + + mErrorStatus = errorStatus; + mNotified = true; + } + mCondition.notify_all(); + return Void(); } -ErrorStatus ExecutionCallback::getStatus() { +void ExecutionCallback::wait() const { + std::unique_lock lock(mMutex); + mCondition.wait(lock, [this] { return mNotified; }); +} + +ErrorStatus ExecutionCallback::getStatus() const { wait(); return mErrorStatus; } -} // namespace implementation -} // namespace V1_0 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_0::implementation diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h b/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h index 36318ea2c2..820bb107f8 100644 --- a/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h +++ b/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h @@ -17,268 +17,160 @@ #ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H #define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H +#include #include #include #include -#include #include -#include #include -#include -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_0 { -namespace implementation { - -/** - * The CallbackBase class is used internally by the NeuralNetworks runtime to +/* + * The Callback classes are used internally by the NeuralNetworks runtime to * synchronize between different threads. An asynchronous task is launched * paired with a callback object. When a client thread requires the output being * generated by the asynchronous task, the client thread can wait for the result - * and be blocked until it has completed or a timeout condition has been - * reached. Any wait* may safely be called concurrently, even on the same - * callback object. When the asynchronous task has finished its workload, it - * must immediately call "notify". If the asynchronous task has failed to launch, - * the function that tried to launch the asynchronous task must immediately call - * "notify". This "notify" call awakens any client threads waiting on the - * callback object. + * and be blocked until it has completed. Any wait may safely be called + * concurrently, even on the same callback object. When the asynchronous task + * has finished its workload, it must immediately call "notify". If the + * asynchronous task has failed to launch, the function that tried to launch the + * asynchronous task must immediately call "notify". This "notify" call + * awakens any client threads waiting on the callback object. * - * The CallbackBase class implements some of the base synchronization common to - * both PrepareModelCallback and ExecutionCallback. For consistency, any HIDL - * callback class must inherit from CallbackBase as well as the HIDL callback - * interface it implements. - * - * This class exists to enable synchronization across HIDL. When synchronization - * is only required in the same process, consider using std::future, std::mutex, - * std::condition_variable, or std::experimental::latch instead. + * These classes exist to enable synchronization across HIDL. When + * synchronization is only required in the same process, consider using + * std::future, std::mutex, std::condition_variable, or std::experimental::latch + * instead. */ -class CallbackBase { - public: - CallbackBase(); - ~CallbackBase(); - /** - * CallbackBase::wait blocks until notify has been called on the callback - * object. - */ - void wait(); - - /** - * CallbackBase::wait_for blocks until notify has been called on the - * callback object or the time duration from the time the wait_for function - * was called has expired, whichever comes first. - * - * @return Status std::cv_status::no_timeout if the callback was notified - * before the time duration expired, std::cv_status::timeout - * otherwise. - */ - template - std::cv_status wait_for(const std::chrono::duration& timeout_duration); - - /** - * CallbackBase::on_finish binds a function to the callback object. This - * bound function will be executed when CallbackBase::notify is called, - * before any calls to wait* return. (Note that CallbackBase::wait_for can - * return std::cv_status::timeout before CallbackBase::notify is called for - * the first time, and hence before the bound function is executed.) - * - * The bound function must not synchronize with or otherwise access the - * callback object it is bound to, as this could cause a deadlock. - * - * CallbackBase::on_finish can be called at most once on a given callback - * object, and the call to CallbackBase::on_finish must finish before - * CallbackBase::notify is called. - * - * @param post_work Function to be invoked the first time - * CallbackBase::notify is called. Must have a target -- - * i.e., must not compare equal to nullptr. post_work - * returns true if it successfully completes, false if it - * fails. - * @return bool True if the function was successfully bound, false if - * unsuccessful. - * - * TODO: Why does the return value of the callback matter? - */ - bool on_finish(std::function post_work); - - /** - * CallbackBase::bind_thread binds a thread to the event for later use by - * CallbackBase::join_thread. - * - * The thread must be passed using std::move. - * - * Once a thread is bound with CallbackBase::bind_thread, the client code - * should ensure that one of the following occurs before the event is - * destroyed: - * - CallbackBase::join_thread has been called. - * - CallbackBase::wait has been called. - * - CallbackBase::wait_for has been called and returned other than - * std::cv_status::no_timeout. - * - * The bound thread shall not call any CallbackBase method with the - * exception of CallbackBase::notify, which it must call when the thread has - * finished its computation. - * - * CallbackBase::bind_thread can be called at most once on a given callback - * object. - * - * @param asyncThread Thread to be bound to the callback object. The thread - * object must represent a thread of execution -- i.e., - * asyncThread.joinable() must be true. - * @return bool True if successful, false if thread was not properly bound. - */ - bool bind_thread(std::thread&& asyncThread); - - /** - * CallbackBase::join_thread ensures that the thread (if any) bound to this - * event with CallbackBase::bind_thread has fully finished and cleaned its - * resources. It is legal to call this function multiple times, concurrently - * or sequentially. - */ - void join_thread(); - - protected: - /** - * CallbackBase::notify enables all prior and future wait* calls on the - * callback object to proceed. The call to CallbackBase::notify happens - * before any wait* calls on this callback object return (except in the case - * of wait_for timing out). The asynchronous call the callback object is - * paired with must ensure that any update to state that should be visible - * to the caller of wait* happens before the call to CallbackBase::notify. - * - * CallbackBase::notify must be called exactly once on a given callback - * object. - */ - void notify(); - - private: - // Same as CallbackBase::join_thread but assumes we already hold a lock on - // mMutex. - void join_thread_locked(); - - bool mNotified; - std::mutex mMutex; - std::condition_variable mCondition; - std::function mPostWork; - std::thread mThread; -}; +namespace android::hardware::neuralnetworks::V1_0::implementation { /** * The PreparedModelCallback class is used to receive the error status of * preparing a model as well as the prepared model from a task executing - * asynchronously with respect to the runtime. If a calling thread calls wait* + * asynchronously with respect to the runtime. If a calling thread calls wait * or get* on a PreparedModelCallback object and the corresponding asynchronous * task has not finished preparing the model, the calling thread will block - * until the asynchronous task has called notify. For more information on the - * synchronization behavior, refer to the CallbackBase class. + * until the asynchronous task has called notify. * - * This class inherits the basic blocking and signaling calls from - * CallbackBase, and implements the HIDL notify call from - * IPreparedModelCallback. This callback object is passed as an argument to - * IDevice::prepareModel. + * If the callback object is notified more than once, only the results of the + * first call to notify are used, and the results from subsequent calls are + * discarded. + * + * This callback object is passed as an argument to IDevice::prepareModel*. */ -class PreparedModelCallback : public CallbackBase, public IPreparedModelCallback { +class PreparedModelCallback : public IPreparedModelCallback { public: - PreparedModelCallback(); - ~PreparedModelCallback() override; - /** * IPreparedModelCallback::notify marks the callback object with the return * status of the asynchronous model preparation along with the prepared - * model and calls CallbackBase::notify, enabling all prior and future - * wait* calls on the PreparedModelCallback object to proceed. - * For more information on the synchronization behavior, refer to the - * CallbackBase class. + * model, and allows all prior and future wait calls on the + * PreparedModelCallback object to proceed. * - * IPreparedModelCallback::notify must be called exactly once on a given + * IPreparedModelCallback::notify must be called on a given * PreparedModelCallback object. * + * If the callback object is notified more than once, only the results of + * the first call to notify are used, and the results from subsequent calls + * are discarded. + * * @param status Error status returned from asynchronously preparing the - * model; will be: - * - NONE if the asynchronous preparation was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if there is an unspecified error - * - INVALID_ARGUMENT if the input model is invalid + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid * @param preparedModel Returned model that has been prepared for execution, - * nullptr if the model was unable to be prepared. + * nullptr if the model was unable to be prepared. */ - Return notify(ErrorStatus status, const sp& preparedModel) override; + Return notify(ErrorStatus status, const sp& preparedModel) override; + + /** + * PreparedModelCallback::wait blocks until notify has been called on the + * callback object. + */ + void wait() const; /** * Retrieves the error status returned from the asynchronous task launched - * by IDevice::prepareModel. If IDevice::prepareModel has not finished + * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished * asynchronously preparing the model, this call will block until the * asynchronous task notifies the object. * * @return status Error status returned from asynchronously preparing the - * model; will be: - * - NONE if the asynchronous preparation was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if there is an unspecified error - * - INVALID_ARGUMENT if the input model is invalid + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid */ - ErrorStatus getStatus(); + ErrorStatus getStatus() const; /** * Retrieves the model that has been prepared for execution from the - * asynchronous task launched by IDevice::prepareModel. If - * IDevice::prepareModel has not finished asynchronously preparing the + * asynchronous task launched by IDevice::prepareModel*. If + * IDevice::prepareModel* has not finished asynchronously preparing the * model, this call will block until the asynchronous task notifies the * object. * * @return preparedModel Returned model that has been prepared for - * execution, nullptr if the model was unable to be - * prepared. + * execution, nullptr if the model was unable to be prepared. */ - sp getPreparedModel(); + sp getPreparedModel() const; private: - ErrorStatus mErrorStatus; - sp mPreparedModel; + mutable std::mutex mMutex; + mutable std::condition_variable mCondition; + bool mNotified GUARDED_BY(mMutex) = false; + ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE; + sp mPreparedModel; }; /** - * The ExecutionCallback class is used to receive the error status of the - * execution from a task executing asynchronously with respect to the runtime. - * If a calling thread calls wait* or get* on a PreparedModelCallback object and - * the corresponding asynchronous task has not finished the execution, the - * calling thread will block until the asynchronous task has called notify. - * For more information on the synchronization behavior, refer to the - * CallbackBase class. + * The ExecutionCallback class is used to receive the results of the execution + * from a task executing asynchronously with respect to the runtime. If a + * calling thread calls wait or get* on a ExecutionCallback object and the + * corresponding asynchronous task has not finished the execution, the calling + * thread will block until the asynchronous task has called notify. * - * This class inherits the basic blocking and signaling calls from - * CallbackBase, and implements the HIDL notify call from IExecutionCallback. - * This callback object is passed as an argument to IPreparedModel::execute. + * If the callback object is notified more than once, only the results of the + * first call to notify are used, and the results from subsequent calls are + * discarded. + * + * This callback object is passed as an argument to IPreparedModel::execute*. */ -class ExecutionCallback : public CallbackBase, public IExecutionCallback { +class ExecutionCallback : public IExecutionCallback { public: - ExecutionCallback(); - ~ExecutionCallback() override; - /** * IExecutionCallback::notify marks the callback object with the return - * status of the asynchronous execution that held this callback and enable - * all prior and future wait* calls on the ExecutionCallback object to - * proceed. For more information on the synchronization behavior, refer to - * the CallbackBase class. + * status of the asynchronous execution that held this callback and enables + * all prior and future wait calls on the ExecutionCallback object to + * proceed. * - * IExecutionCallback::notify must be called exactly once on a given - * ExecutionCallback object. + * IExecutionCallback::notify must be called on a given ExecutionCallback + * object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify are used, and the results from subsequent calls + * are discarded. * * @param status Error status returned from launching the asynchronous task - * (if the launch fails) or from the asynchronous task itself - * (if the launch succeeds). Must be: - * - NONE if the asynchronous execution was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if there is an unspecified error - * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is - * not large enough to store the resultant values - * - INVALID_ARGUMENT if the input request is invalid + * (if the launch fails) or from the asynchronous task itself (if the + * launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large + * enough to store the resultant values + * - INVALID_ARGUMENT if the input request is invalid */ Return notify(ErrorStatus status) override; + /** + * ExecutionCallback::wait blocks until notify has been called on the + * callback object. + */ + void wait() const; + /** * Retrieves the error status returned from the asynchronous task launched * by IPreparedModel::execute. If IPreparedModel::execute has not finished @@ -286,41 +178,26 @@ class ExecutionCallback : public CallbackBase, public IExecutionCallback { * task notifies the object. * * @return status Error status returned from launching the asynchronous task - * (if the launch fails) or from the asynchronous task itself - * (if the launch succeeds). Must be: - * - NONE if the asynchronous execution was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if the asynchronous task resulted in an - * unspecified error - * - OUTPUT_INSUFFICIENT_SIZE if at least one output - * operand buffer is not large enough to store the - * corresponding output - * - INVALID_ARGUMENT if one of the input arguments to - * prepareModel is invalid + * (if the launch fails) or from the asynchronous task itself (if the + * launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified + * error + * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is + * not large enough to store the corresponding output + * - INVALID_ARGUMENT if one of the input arguments to prepareModel is + * invalid */ - ErrorStatus getStatus(); + ErrorStatus getStatus() const; private: + mutable std::mutex mMutex; + mutable std::condition_variable mCondition; + bool mNotified GUARDED_BY(mMutex) = false; ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE; }; -// template function implementation(s) below this point - -template -std::cv_status CallbackBase::wait_for(const std::chrono::duration& timeout_duration) { - std::unique_lock lock(mMutex); - std::cv_status status = - mCondition.wait_for(lock, timeout_duration, [this] { return mNotified; }); - if (status != std::cv_status::timeout) { - join_thread_locked(); - } - return status; -} - -} // namespace implementation -} // namespace V1_0 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_0::implementation #endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H diff --git a/neuralnetworks/1.2/vts/functional/Callbacks.cpp b/neuralnetworks/1.2/vts/functional/Callbacks.cpp index cfaf91d433..a607a083c0 100644 --- a/neuralnetworks/1.2/vts/functional/Callbacks.cpp +++ b/neuralnetworks/1.2/vts/functional/Callbacks.cpp @@ -14,160 +14,128 @@ * limitations under the License. */ +#define LOG_TAG "Callbacks" + #include "1.2/Callbacks.h" + #include -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_2 { -namespace implementation { +#include -CallbackBase::CallbackBase() : mNotified(false) {} +namespace android::hardware::neuralnetworks::V1_2::implementation { -CallbackBase::~CallbackBase() { - // Note that we cannot call CallbackBase::join_thread from here: - // CallbackBase is intended to be reference counted, and it is possible that - // the reference count drops to zero in the bound thread, causing the - // bound thread to call this destructor. If a thread tries to join - // itself, it throws an exception, producing a message like the - // following: - // - // terminating with uncaught exception of type std::__1::system_error: - // thread::join failed: Resource deadlock would occur -} +constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits::max(), + .timeInDriver = std::numeric_limits::max()}; -void CallbackBase::wait() { - std::unique_lock lock(mMutex); - mCondition.wait(lock, [this] { return mNotified; }); - join_thread_locked(); -} - -bool CallbackBase::on_finish(std::function post_work) { - std::lock_guard lock(mMutex); - if (mPostWork != nullptr) { - LOG(ERROR) << "CallbackBase::on_finish -- a post-work function has already been bound to " - "this callback object"; - return false; - } - if (post_work == nullptr) { - LOG(ERROR) << "CallbackBase::on_finish -- the new post-work function is invalid"; - return false; - } - mPostWork = std::move(post_work); - return true; -} - -bool CallbackBase::bind_thread(std::thread&& asyncThread) { - std::lock_guard lock(mMutex); - if (mThread.joinable()) { - LOG(ERROR) << "CallbackBase::bind_thread -- a thread has already been bound to this " - "callback object"; - return false; - } - if (!asyncThread.joinable()) { - LOG(ERROR) << "CallbackBase::bind_thread -- the new thread is not joinable"; - return false; - } - mThread = std::move(asyncThread); - return true; -} - -void CallbackBase::join_thread() { - std::lock_guard lock(mMutex); - join_thread_locked(); -} - -void CallbackBase::notify() { - { - std::lock_guard lock(mMutex); - mNotified = true; - if (mPostWork != nullptr) { - bool success = mPostWork(); - if (!success) { - LOG(ERROR) << "CallbackBase::notify -- post work failed"; - } - } - } - mCondition.notify_all(); -} - -void CallbackBase::join_thread_locked() { - if (mThread.joinable()) { - mThread.join(); - } -} - -PreparedModelCallback::PreparedModelCallback() - : mErrorStatus(ErrorStatus::GENERAL_FAILURE), mPreparedModel(nullptr) {} - -PreparedModelCallback::~PreparedModelCallback() {} +// PreparedModelCallback methods begin here Return PreparedModelCallback::notify(ErrorStatus errorStatus, const sp& preparedModel) { - mErrorStatus = errorStatus; - mPreparedModel = preparedModel; - CallbackBase::notify(); + { + std::lock_guard hold(mMutex); + + // quick-return if object has already been notified + if (mNotified) { + return Void(); + } + + // store results and mark as notified + mErrorStatus = errorStatus; + mPreparedModel = preparedModel; + mNotified = true; + } + + mCondition.notify_all(); return Void(); } Return PreparedModelCallback::notify_1_2(ErrorStatus errorStatus, const sp& preparedModel) { - mErrorStatus = errorStatus; - mPreparedModel = preparedModel; - CallbackBase::notify(); - return Void(); + return notify(errorStatus, preparedModel); } -ErrorStatus PreparedModelCallback::getStatus() { +void PreparedModelCallback::wait() const { + std::unique_lock lock(mMutex); + mCondition.wait(lock, [this] { return mNotified; }); +} + +ErrorStatus PreparedModelCallback::getStatus() const { wait(); return mErrorStatus; } -sp PreparedModelCallback::getPreparedModel() { +sp PreparedModelCallback::getPreparedModel() const { wait(); return mPreparedModel; } -ExecutionCallback::ExecutionCallback() : mErrorStatus(ErrorStatus::GENERAL_FAILURE) {} - -ExecutionCallback::~ExecutionCallback() {} +// ExecutionCallback methods begin here Return ExecutionCallback::notify(ErrorStatus errorStatus) { - mErrorStatus = errorStatus; - mOutputShapes = {}; - mTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; - CallbackBase::notify(); + notifyInternal(errorStatus, {}, kNoTiming); return Void(); } Return ExecutionCallback::notify_1_2(ErrorStatus errorStatus, const hidl_vec& outputShapes, const Timing& timing) { - mErrorStatus = errorStatus; - mOutputShapes = outputShapes; - mTiming = timing; - CallbackBase::notify(); + if (errorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { + // outputShapes must not be empty if OUTPUT_INSUFFICIENT_SIZE. + if (outputShapes.size() == 0) { + LOG(ERROR) << "Notified with empty output shape vector when OUTPUT_INSUFFICIENT_SIZE"; + notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + return Void(); + } + } else if (errorStatus != ErrorStatus::NONE) { + // outputShapes must be empty if errorStatus is neither NONE nor OUTPUT_INSUFFICIENT_SIZE. + if (outputShapes.size() != 0) { + LOG(ERROR) << "Notified with non-empty output shape vector when error status is " + "neither NONE nor OUTPUT_INSUFFICIENT_SIZE"; + notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + return Void(); + } + } + notifyInternal(errorStatus, outputShapes, timing); return Void(); } -ErrorStatus ExecutionCallback::getStatus() { +void ExecutionCallback::wait() const { + std::unique_lock lock(mMutex); + mCondition.wait(lock, [this] { return mNotified; }); +} + +ErrorStatus ExecutionCallback::getStatus() const { wait(); return mErrorStatus; } -const std::vector& ExecutionCallback::getOutputShapes() { +const std::vector& ExecutionCallback::getOutputShapes() const { wait(); return mOutputShapes; } -Timing ExecutionCallback::getTiming() { +Timing ExecutionCallback::getTiming() const { wait(); return mTiming; } -} // namespace implementation -} // namespace V1_2 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +void ExecutionCallback::notifyInternal(ErrorStatus errorStatus, + const hidl_vec& outputShapes, + const Timing& timing) { + { + std::lock_guard hold(mMutex); + + // quick-return if object has already been notified + if (mNotified) { + return; + } + + mErrorStatus = errorStatus; + mOutputShapes = outputShapes; + mTiming = timing; + mNotified = true; + } + mCondition.notify_all(); +} + +} // namespace android::hardware::neuralnetworks::V1_2::implementation diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp index adbf224fee..ac92a5b0a2 100644 --- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "1.2/Callbacks.h" #include "GeneratedTestHarness.h" diff --git a/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h b/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h index 212a8875df..2992c0cfe9 100644 --- a/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h +++ b/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h @@ -17,299 +17,218 @@ #ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H #define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H +#include +#include +#include #include #include #include -#include #include -#include #include -#include -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_2 { -namespace implementation { +/* + * The Callback classes are used internally by the NeuralNetworks runtime to + * synchronize between different threads. An asynchronous task is launched + * paired with a callback object. When a client thread requires the output being + * generated by the asynchronous task, the client thread can wait for the result + * and be blocked until it has completed. Any wait may safely be called + * concurrently, even on the same callback object. When the asynchronous task + * has finished its workload, it must immediately call "notify*". If the + * asynchronous task has failed to launch, the function that tried to launch the + * asynchronous task must immediately call "notify*". This "notify*" call + * awakens any client threads waiting on the callback object. + * + * These classes exist to enable synchronization across HIDL. When + * synchronization is only required in the same process, consider using + * std::future, std::mutex, std::condition_variable, or std::experimental::latch + * instead. + */ + +namespace android::hardware::neuralnetworks::V1_2::implementation { using V1_0::ErrorStatus; -/** - * The CallbackBase class is used internally by the NeuralNetworks runtime to - * synchronize between different threads. An asynchronous task is launched - * paired with a callback object. When a client thread requires the output being - * generated by the asynchronous task, the client thread can wait for the result - * and be blocked until it has completed or a timeout condition has been - * reached. Any wait* may safely be called concurrently, even on the same - * callback object. When the asynchronous task has finished its workload, it - * must immediately call "notify". If the asynchronous task has failed to launch, - * the function that tried to launch the asynchronous task must immediately call - * "notify". This "notify" call awakens any client threads waiting on the - * callback object. - * - * The CallbackBase class implements some of the base synchronization common to - * both PrepareModelCallback and ExecutionCallback. For consistency, any HIDL - * callback class must inherit from CallbackBase as well as the HIDL callback - * interface it implements. - * - * This class exists to enable synchronization across HIDL. When synchronization - * is only required in the same process, consider using std::future, std::mutex, - * std::condition_variable, or std::experimental::latch instead. - */ -class CallbackBase { - public: - CallbackBase(); - ~CallbackBase(); - - /** - * CallbackBase::wait blocks until notify has been called on the callback - * object. - */ - void wait(); - - /** - * CallbackBase::wait_for blocks until notify has been called on the - * callback object or the time duration from the time the wait_for function - * was called has expired, whichever comes first. - * - * @return Status std::cv_status::no_timeout if the callback was notified - * before the time duration expired, std::cv_status::timeout - * otherwise. - */ - template - std::cv_status wait_for(const std::chrono::duration& timeout_duration); - - /** - * CallbackBase::on_finish binds a function to the callback object. This - * bound function will be executed when CallbackBase::notify is called, - * before any calls to wait* return. (Note that CallbackBase::wait_for can - * return std::cv_status::timeout before CallbackBase::notify is called for - * the first time, and hence before the bound function is executed.) - * - * The bound function must not synchronize with or otherwise access the - * callback object it is bound to, as this could cause a deadlock. - * - * CallbackBase::on_finish can be called at most once on a given callback - * object, and the call to CallbackBase::on_finish must finish before - * CallbackBase::notify is called. - * - * @param post_work Function to be invoked the first time - * CallbackBase::notify is called. Must have a target -- - * i.e., must not compare equal to nullptr. post_work - * returns true if it successfully completes, false if it - * fails. - * @return bool True if the function was successfully bound, false if - * unsuccessful. - * - * TODO: Why does the return value of the callback matter? - */ - bool on_finish(std::function post_work); - - /** - * CallbackBase::bind_thread binds a thread to the event for later use by - * CallbackBase::join_thread. - * - * The thread must be passed using std::move. - * - * Once a thread is bound with CallbackBase::bind_thread, the client code - * should ensure that one of the following occurs before the event is - * destroyed: - * - CallbackBase::join_thread has been called. - * - CallbackBase::wait has been called. - * - CallbackBase::wait_for has been called and returned other than - * std::cv_status::no_timeout. - * - * The bound thread shall not call any CallbackBase method with the - * exception of CallbackBase::notify, which it must call when the thread has - * finished its computation. - * - * CallbackBase::bind_thread can be called at most once on a given callback - * object. - * - * @param asyncThread Thread to be bound to the callback object. The thread - * object must represent a thread of execution -- i.e., - * asyncThread.joinable() must be true. - * @return bool True if successful, false if thread was not properly bound. - */ - bool bind_thread(std::thread&& asyncThread); - - /** - * CallbackBase::join_thread ensures that the thread (if any) bound to this - * event with CallbackBase::bind_thread has fully finished and cleaned its - * resources. It is legal to call this function multiple times, concurrently - * or sequentially. - */ - void join_thread(); - - protected: - /** - * CallbackBase::notify enables all prior and future wait* calls on the - * callback object to proceed. The call to CallbackBase::notify happens - * before any wait* calls on this callback object return (except in the case - * of wait_for timing out). The asynchronous call the callback object is - * paired with must ensure that any update to state that should be visible - * to the caller of wait* happens before the call to CallbackBase::notify. - * - * CallbackBase::notify must be called exactly once on a given callback - * object. - */ - void notify(); - - private: - // Same as CallbackBase::join_thread but assumes we already hold a lock on - // mMutex. - void join_thread_locked(); - - bool mNotified; - std::mutex mMutex; - std::condition_variable mCondition; - std::function mPostWork; - std::thread mThread; -}; - /** * The PreparedModelCallback class is used to receive the error status of * preparing a model as well as the prepared model from a task executing - * asynchronously with respect to the runtime. If a calling thread calls wait* + * asynchronously with respect to the runtime. If a calling thread calls wait * or get* on a PreparedModelCallback object and the corresponding asynchronous * task has not finished preparing the model, the calling thread will block - * until the asynchronous task has either called notify or notify_1_2. For more - * information on the synchronization behavior, refer to the CallbackBase class. + * until the asynchronous task has either called notify or notify_1_2. * - * This class inherits the basic blocking and signaling calls from - * CallbackBase, and implements the HIDL notify and notify_1_2 calls from - * IPreparedModelCallback. This callback object is passed as an argument to - * IDevice::prepareModel. + * If the callback object is notified more than once, only the results of the + * first call to notify* are used, and the results from subsequent calls are + * discarded. + * + * This callback object is passed as an argument to IDevice::prepareModel*. */ -class PreparedModelCallback : public CallbackBase, public IPreparedModelCallback { +class PreparedModelCallback : public IPreparedModelCallback { public: - PreparedModelCallback(); - ~PreparedModelCallback() override; - /** - * IPreparedModelCallback::notify and IPreparedModelCallback::notify_1_2 - * mark the callback object with the return status of the asynchronous - * model preparation along with the prepared model, and call - * CallbackBase::notify, enabling all prior and future wait* calls on the - * PreparedModelCallback object to proceed. For more information on the - * synchronization behavior, refer to the CallbackBase class. + * IPreparedModelCallback::notify marks the callback object with the return + * status of the asynchronous model preparation along with the prepared + * model, and allows all prior and future wait calls on the + * PreparedModelCallback object to proceed. * - * Either IPreparedModelCallback::notify or IPreparedModelCallback::notify_1_2 - * must be called exactly once on a given PreparedModelCallback object. + * Either IPreparedModelCallback::notify or + * IPreparedModelCallback::notify_1_2 must be called on a given + * PreparedModelCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. * * @param status Error status returned from asynchronously preparing the - * model; will be: - * - NONE if the asynchronous preparation was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if there is an unspecified error - * - INVALID_ARGUMENT if the input model is invalid + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid * @param preparedModel Returned model that has been prepared for execution, - * nullptr if the model was unable to be prepared. + * nullptr if the model was unable to be prepared. */ Return notify(ErrorStatus status, const sp& preparedModel) override; + + /** + * IPreparedModelCallback::notify_1_2 marks the callback object with the + * return status of the asynchronous model preparation along with the + * prepared model, and allows all prior and future wait calls on the + * PreparedModelCallback object to proceed. + * + * Either IPreparedModelCallback::notify or + * IPreparedModelCallback::notify_1_2 must be called on a given + * PreparedModelCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + * @param preparedModel Returned model that has been prepared for execution, + * nullptr if the model was unable to be prepared. + */ Return notify_1_2(ErrorStatus status, const sp& preparedModel) override; + /** + * PreparedModelCallback::wait blocks until notify* has been called on the + * callback object. + */ + void wait() const; + /** * Retrieves the error status returned from the asynchronous task launched - * by IDevice::prepareModel. If IDevice::prepareModel has not finished + * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished * asynchronously preparing the model, this call will block until the * asynchronous task notifies the object. * * @return status Error status returned from asynchronously preparing the - * model; will be: - * - NONE if the asynchronous preparation was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if there is an unspecified error - * - INVALID_ARGUMENT if the input model is invalid + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid */ - ErrorStatus getStatus(); + ErrorStatus getStatus() const; /** * Retrieves the model that has been prepared for execution from the - * asynchronous task launched by IDevice::prepareModel. If - * IDevice::prepareModel has not finished asynchronously preparing the + * asynchronous task launched by IDevice::prepareModel*. If + * IDevice::prepareModel* has not finished asynchronously preparing the * model, this call will block until the asynchronous task notifies the * object. * * @return preparedModel Returned model that has been prepared for - * execution, nullptr if the model was unable to be - * prepared. + * execution, nullptr if the model was unable to be prepared. */ - sp getPreparedModel(); + sp getPreparedModel() const; private: - ErrorStatus mErrorStatus; + mutable std::mutex mMutex; + mutable std::condition_variable mCondition; + bool mNotified GUARDED_BY(mMutex) = false; + ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE; sp mPreparedModel; }; /** - * The ExecutionCallback class is used to receive the error status of the - * execution from a task executing asynchronously with respect to the runtime. - * If a calling thread calls wait* or get* on a PreparedModelCallback object and - * the corresponding asynchronous task has not finished the execution, the - * calling thread will block until the asynchronous task has either called notify - * or notify_1_2. For more information on the synchronization behavior, refer to - * the CallbackBase class. + * The ExecutionCallback class is used to receive the results of the execution + * from a task executing asynchronously with respect to the runtime. If a + * calling thread calls wait or get* on a ExecutionCallback object and the + * corresponding asynchronous task has not finished the execution, the calling + * thread will block until the asynchronous task has either called notify or + * notify_1_2. * - * This class inherits the basic blocking and signaling calls from - * CallbackBase, and implements the HIDL notify and notify_1_2 calls from - * IExecutionCallback. This callback object is passed as an argument to - * IPreparedModel::execute. + * If the callback object is notified more than once, only the results of the + * first call to notify* are used, and the results from subsequent calls are + * discarded. + * + * This callback object is passed as an argument to IPreparedModel::execute*. */ -class ExecutionCallback : public CallbackBase, public IExecutionCallback { +class ExecutionCallback : public IExecutionCallback { public: - ExecutionCallback(); - ~ExecutionCallback() override; - /** - * IExecutionCallback::notify and IExecutionCallback::notify_1_2 mark the - * callback object with the return status of the asynchronous execution that - * held this callback and enable all prior and future wait* calls on the - * ExecutionCallback object to proceed. For more information on the - * synchronization behavior, refer to the CallbackBase class. + * IExecutionCallback::notify marks the callback object with the return + * status of the asynchronous execution that held this callback and enables + * all prior and future wait calls on the ExecutionCallback object to + * proceed. * * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must - * be called exactly once on a given ExecutionCallback object. + * be called on a given ExecutionCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. * * @param status Error status returned from launching the asynchronous task - * (if the launch fails) or from the asynchronous task itself - * (if the launch succeeds). Must be: - * - NONE if the asynchronous execution was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if there is an unspecified error - * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is - * not large enough to store the resultant values - * - INVALID_ARGUMENT if the input request is invalid + * (if the launch fails) or from the asynchronous task itself (if the + * launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large + * enough to store the resultant values + * - INVALID_ARGUMENT if the input request is invalid */ Return notify(ErrorStatus status) override; /** - * Similar to IExecutionCallback::notify, but for V1_2::IPreparedModel to - * also notify output shapes along with error status. + * IExecutionCallback::notify_1_2 marks the callback object with the results + * (error status, dynamic output shapes, and timing information) of the + * asynchronous execution that held this callback and enables all prior and + * future wait calls on the ExecutionCallback object to proceed. + * + * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must + * be called on a given ExecutionCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. * * @param status Error status returned from launching the asynchronous task - * (if the launch fails) or from the asynchronous task itself - * (if the launch succeeds). Must be: - * - NONE if the asynchronous execution was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if the asynchronous task resulted in an - * unspecified error - * - OUTPUT_INSUFFICIENT_SIZE if at least one output - * operand buffer is not large enough to store the - * corresponding output - * - INVALID_ARGUMENT if one of the input arguments to - * prepareModel is invalid + * (if the launch fails) or from the asynchronous task itself (if the + * launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified + * error + * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is + * not large enough to store the corresponding output + * - INVALID_ARGUMENT if one of the input arguments to prepareModel is + * invalid * @param outputShapes A list of shape information of model output operands. - * The index into "outputShapes" corresponds to the index - * of the output operand in the Request outputs vector. - * outputShapes must be empty unless the status is either - * NONE or OUTPUT_INSUFFICIENT_SIZE. - * @return Timing Duration of execution. Unless MeasureTiming::YES was passed when - * launching the execution and status is NONE, all times must - * be reported as UINT64_MAX. A driver may choose to report - * any time as UINT64_MAX, indicating that particular measurement is - * not available. + * The index into "outputShapes" corresponds to the index of the output + * operand in the Request outputs vector. outputShapes must be empty + * unless the status is either NONE or OUTPUT_INSUFFICIENT_SIZE. + * @param Timing Duration of execution. Unless MeasureTiming::YES was passed + * when launching the execution and status is NONE, all times must be + * reported as UINT64_MAX. A driver may choose to report any time as + * UINT64_MAX, indicating that particular measurement is not available. */ Return notify_1_2(ErrorStatus status, const hidl_vec& outputShapes, const Timing& timing) override; @@ -320,82 +239,88 @@ class ExecutionCallback : public CallbackBase, public IExecutionCallback { return notify_1_2(status, outputShapes, timing); } + /** + * ExecutionCallback::wait blocks until notify* has been called on the + * callback object. + */ + void wait() const; + /** * Retrieves the error status returned from the asynchronous task launched * by either IPreparedModel::execute or IPreparedModel::execute_1_2. If * IPreparedModel::execute or IPreparedModel::execute_1_2 has not finished - * asynchronously executing, this call will block until the asynchronous task - * notifies the object. + * asynchronously executing, this call will block until the asynchronous + * task notifies the object. * * @return status Error status returned from launching the asynchronous task - * (if the launch fails) or from the asynchronous task itself - * (if the launch succeeds). Must be: - * - NONE if the asynchronous execution was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if the asynchronous task resulted in an - * unspecified error - * - OUTPUT_INSUFFICIENT_SIZE if at least one output - * operand buffer is not large enough to store the - * corresponding output - * - INVALID_ARGUMENT if one of the input arguments to - * prepareModel is invalid + * (if the launch fails) or from the asynchronous task itself (if the + * launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified + * error + * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is + * not large enough to store the corresponding output + * - INVALID_ARGUMENT if one of the input arguments to prepareModel is + * invalid */ - ErrorStatus getStatus(); + ErrorStatus getStatus() const; /** * Retrieves the output shapes returned from the asynchronous task launched - * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not finished - * asynchronously executing, this call will block until the asynchronous task - * notifies the object. + * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not + * finished asynchronously executing, this call will block until the + * asynchronous task notifies the object. * - * If the asynchronous task was launched by IPreparedModel::execute, an empty vector - * will be returned. + * If the asynchronous task was launched by IPreparedModel::execute, an + * empty vector will be returned. * - * @return outputShapes A list of shape information of model output operands. - * The index into "outputShapes" corresponds to the index - * of the output operand in the Request outputs vector. - * outputShapes must be empty unless the status is either - * NONE or OUTPUT_INSUFFICIENT_SIZE. + * @return outputShapes A list of shape information of model output + * operands. The index into "outputShapes" corresponds to the index of + * the output operand in the Request outputs vector. outputShapes must + * be empty unless the status is either NONE or + * OUTPUT_INSUFFICIENT_SIZE. outputShaps may be empty if the status is + * NONE and all model output operands are fully-specified at execution + * time. outputShapes must have the same number of elements as the + * number of model output operands if the status is + * OUTPUT_INSUFFICIENT_SIZE, or if the status is NONE and the model has + * at least one output operand that is not fully-specified. */ - const std::vector& getOutputShapes(); + const std::vector& getOutputShapes() const; /** - * Retrieves the duration of execution ofthe asynchronous task launched - * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not finished - * asynchronously executing, this call will block until the asynchronous task - * notifies the object. + * Retrieves the duration of execution of the asynchronous task launched by + * IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not + * finished asynchronously executing, this call will block until the + * asynchronous task notifies the object. * - * If the asynchronous task was launched by IPreparedModel::execute, every time - * must be UINT64_MAX. + * If the asynchronous task was launched by IPreparedModel::execute, every + * time must be UINT64_MAX. * - * @return timing Duration of the execution. Every time must be UINT64_MAX unless - * the status is NONE. + * @return timing Duration of the execution. Every time must be UINT64_MAX + * unless the status is NONE. */ - Timing getTiming(); + Timing getTiming() const; private: + /* + * ExecutionCallback::notifyInternal stores the results of the execution + * (status, output shapes, and timing information) in the ExecutionCallback + * object before any call to wait or get* return. It then enables all prior + * and future wait calls on the ExecutionCallback object to proceed. + */ + void notifyInternal(ErrorStatus errorStatus, const hidl_vec& outputShapes, + const Timing& timing); + + // members + mutable std::mutex mMutex; + mutable std::condition_variable mCondition; + bool mNotified GUARDED_BY(mMutex) = false; ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE; std::vector mOutputShapes = {}; Timing mTiming = {}; }; -// template function implementation(s) below this point - -template -std::cv_status CallbackBase::wait_for(const std::chrono::duration& timeout_duration) { - std::unique_lock lock(mMutex); - std::cv_status status = - mCondition.wait_for(lock, timeout_duration, [this] { return mNotified; }); - if (status != std::cv_status::timeout) { - join_thread_locked(); - } - return status; -} - -} // namespace implementation -} // namespace V1_2 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_2::implementation #endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H From 4745a3d96edcf43536ee0d39e1bef17c19a44262 Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Thu, 11 Jul 2019 15:43:22 -0700 Subject: [PATCH 0033/1022] NNAPI VTS fix from NNAPI CL: Cleanup HalInterfaces.h Prior to this CL, HalInterfaces.h polluted the global namespace through the "using" declarations. To fix b/72880287, those names were put in a new ::android::nn::hal namespace. This CL fixes the compilation errors that occur due to this cleanup. Bug: 72880287 Test: mma Change-Id: Idb228e37615af7c0343a09f9a51de378e63bdb5a --- neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp | 3 +++ neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp | 4 ++++ neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp | 2 ++ neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp | 2 ++ neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp | 2 ++ neuralnetworks/1.2/vts/functional/ValidateRequest.cpp | 1 + 6 files changed, 14 insertions(+) diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp index adbf224fee..b66dd64a52 100644 --- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp @@ -41,8 +41,11 @@ namespace V1_2 { namespace vts { namespace functional { +using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; +using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference; using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; +using ::android::hidl::memory::V1_0::IMemory; using ::android::nn::allocateSharedMemory; using ::test_helper::MixedTypedExample; diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp index c3578cdca7..495f3ecdb6 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp @@ -49,9 +49,13 @@ using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; using ::android::hardware::neuralnetworks::V1_0::Request; using ::android::hardware::neuralnetworks::V1_0::RequestArgument; using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference; +using ::android::hardware::neuralnetworks::V1_2::Constant; using ::android::hardware::neuralnetworks::V1_2::IDevice; using ::android::hardware::neuralnetworks::V1_2::IPreparedModel; +using ::android::hardware::neuralnetworks::V1_2::MeasureTiming; using ::android::hardware::neuralnetworks::V1_2::Model; +using ::android::hardware::neuralnetworks::V1_2::OutputShape; +using ::android::hardware::neuralnetworks::V1_2::Timing; using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; using ::android::hidl::memory::V1_0::IMemory; diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp index b4e6696403..6fbd1dc6a2 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp @@ -34,8 +34,10 @@ namespace V1_2 { namespace vts { namespace functional { +using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; +using ::android::hidl::memory::V1_0::IMemory; using ::android::nn::allocateSharedMemory; using ::test_helper::MixedTypedExample; diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp index 33212fb002..d824e4348c 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp @@ -34,8 +34,10 @@ namespace V1_2 { namespace vts { namespace functional { +using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; +using ::android::hidl::memory::V1_0::IMemory; using ::android::nn::allocateSharedMemory; using ::test_helper::MixedTypedExample; diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp index 8481b4d7eb..1928b8c03c 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp @@ -34,8 +34,10 @@ namespace V1_2 { namespace vts { namespace functional { +using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; +using ::android::hidl::memory::V1_0::IMemory; using ::android::nn::allocateSharedMemory; using ::test_helper::MixedTypedExample; diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp index a7e83289f1..cf5905f688 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp @@ -35,6 +35,7 @@ namespace V1_2 { namespace vts { namespace functional { +using ::android::hardware::neuralnetworks::V1_0::RequestArgument; using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; using ::android::hidl::memory::V1_0::IMemory; using test_helper::for_all; From 781d0bbe3b6555bda067443d7da74a4e0d485759 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Wed, 3 Jul 2019 10:57:02 -0700 Subject: [PATCH 0034/1022] [Composer] Create place holder for Composer 2.4. Create place holder for composer 2.4. Minor: Extend DisplayCapability to include protected contents. BUG: 135929065 Test: build Change-Id: I9dbdb21f4a69027bedd95cd54e9c3c652bbe9006 --- graphics/composer/2.4/Android.bp | 24 +++ graphics/composer/2.4/IComposer.hal | 34 +++ graphics/composer/2.4/IComposerClient.hal | 51 +++++ graphics/composer/2.4/default/Android.bp | 47 +++++ graphics/composer/2.4/default/OWNERS | 4 + ....hardware.graphics.composer@2.4-service.rc | 7 + graphics/composer/2.4/default/service.cpp | 55 +++++ graphics/composer/2.4/utils/OWNERS | 4 + .../2.4/utils/command-buffer/Android.bp | 18 ++ .../2.4/ComposerCommandBuffer.h | 58 ++++++ graphics/composer/2.4/utils/hal/Android.bp | 36 ++++ .../hal/include/composer-hal/2.4/Composer.h | 89 ++++++++ .../include/composer-hal/2.4/ComposerClient.h | 69 ++++++ .../include/composer-hal/2.4/ComposerHal.h | 48 +++++ .../composer/2.4/utils/passthrough/Android.bp | 30 +++ .../include/composer-passthrough/2.4/HwcHal.h | 88 ++++++++ .../composer-passthrough/2.4/HwcLoader.h | 79 +++++++ graphics/composer/2.4/utils/vts/Android.bp | 42 ++++ .../composer/2.4/utils/vts/ComposerVts.cpp | 69 ++++++ .../include/composer-vts/2.4/ComposerVts.h | 83 ++++++++ .../composer/2.4/vts/functional/Android.bp | 48 +++++ graphics/composer/2.4/vts/functional/OWNERS | 8 + .../VtsHalGraphicsComposerV2_4TargetTest.cpp | 197 ++++++++++++++++++ 23 files changed, 1188 insertions(+) create mode 100644 graphics/composer/2.4/Android.bp create mode 100644 graphics/composer/2.4/IComposer.hal create mode 100644 graphics/composer/2.4/IComposerClient.hal create mode 100644 graphics/composer/2.4/default/Android.bp create mode 100644 graphics/composer/2.4/default/OWNERS create mode 100644 graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc create mode 100644 graphics/composer/2.4/default/service.cpp create mode 100644 graphics/composer/2.4/utils/OWNERS create mode 100644 graphics/composer/2.4/utils/command-buffer/Android.bp create mode 100644 graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h create mode 100644 graphics/composer/2.4/utils/hal/Android.bp create mode 100644 graphics/composer/2.4/utils/hal/include/composer-hal/2.4/Composer.h create mode 100644 graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h create mode 100644 graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h create mode 100644 graphics/composer/2.4/utils/passthrough/Android.bp create mode 100644 graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h create mode 100644 graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcLoader.h create mode 100644 graphics/composer/2.4/utils/vts/Android.bp create mode 100644 graphics/composer/2.4/utils/vts/ComposerVts.cpp create mode 100644 graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h create mode 100644 graphics/composer/2.4/vts/functional/Android.bp create mode 100644 graphics/composer/2.4/vts/functional/OWNERS create mode 100644 graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp diff --git a/graphics/composer/2.4/Android.bp b/graphics/composer/2.4/Android.bp new file mode 100644 index 0000000000..4a92df2c5b --- /dev/null +++ b/graphics/composer/2.4/Android.bp @@ -0,0 +1,24 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.graphics.composer@2.4", + root: "android.hardware", + vndk: { + // TODO(b/135929065) enable once we are ready to use. + enabled: false, + }, + srcs: [ + "IComposer.hal", + "IComposerClient.hal", + ], + interfaces: [ + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.composer@2.3", + "android.hidl.base@1.0", + ], + gen_java: false, +} diff --git a/graphics/composer/2.4/IComposer.hal b/graphics/composer/2.4/IComposer.hal new file mode 100644 index 0000000000..34801daa27 --- /dev/null +++ b/graphics/composer/2.4/IComposer.hal @@ -0,0 +1,34 @@ +/* + * Copyright 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. + */ + +package android.hardware.graphics.composer@2.4; + +import IComposerClient; + +import @2.1::Error; +import @2.3::IComposer; + +interface IComposer extends @2.3::IComposer { + + /** + * Creates a v2.4 client of the composer. Supersedes @2.3::createClient. + * + * @return error is NONE upon success. Otherwise, + * NO_RESOURCES when the client could not be created. + * @return client is the newly created client. + */ + createClient_2_4() generates (Error error, IComposerClient client); +}; diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal new file mode 100644 index 0000000000..8fe0976781 --- /dev/null +++ b/graphics/composer/2.4/IComposerClient.hal @@ -0,0 +1,51 @@ +/* + * Copyright 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. + */ + +package android.hardware.graphics.composer@2.4; + +import @2.1::Display; +import @2.1::Error; +import @2.3::IComposerClient; + +interface IComposerClient extends @2.3::IComposerClient { + + /** + * Required capabilities which are supported by the display. The + * particular set of supported capabilities for a given display may be + * retrieved using getDisplayCapabilities. + */ + enum DisplayCapability : uint32_t { + /** + * Indicates that the display supports protected contents. + * When returned, hardware composer must be able to accept client target + * with protected buffers. + */ + PROTECTED_CONTENTS = 4, + }; + + /** + * Provides a list of supported capabilities (as described in the + * definition of DisplayCapability above). This list must not change after + * initialization. + * + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * @return capabilities is a list of supported capabilities. + */ + getDisplayCapabilities_2_4(Display display) + generates (Error error, + vec capabilities); +}; diff --git a/graphics/composer/2.4/default/Android.bp b/graphics/composer/2.4/default/Android.bp new file mode 100644 index 0000000000..1bf51e0250 --- /dev/null +++ b/graphics/composer/2.4/default/Android.bp @@ -0,0 +1,47 @@ +// +// Copyright 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. +// + +cc_binary { + name: "android.hardware.graphics.composer@2.4-service", + defaults: ["hidl_defaults"], + vendor: true, + relative_install_path: "hw", + srcs: ["service.cpp"], + init_rc: ["android.hardware.graphics.composer@2.4-service.rc"], + header_libs: [ + "android.hardware.graphics.composer@2.4-passthrough", + ], + shared_libs: [ + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.composer@2.3", + "android.hardware.graphics.composer@2.4", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", + "libbase", + "libbinder", + "libcutils", + "libfmq", + "libhardware", + "libhidlbase", + "libhidltransport", + "libhwc2on1adapter", + "libhwc2onfbadapter", + "liblog", + "libsync", + "libutils", + ], +} diff --git a/graphics/composer/2.4/default/OWNERS b/graphics/composer/2.4/default/OWNERS new file mode 100644 index 0000000000..cc6d937cad --- /dev/null +++ b/graphics/composer/2.4/default/OWNERS @@ -0,0 +1,4 @@ +# Graphics team +lpy@google.com +stoza@google.com +vhau@google.com diff --git a/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc b/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc new file mode 100644 index 0000000000..a296b0aace --- /dev/null +++ b/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc @@ -0,0 +1,7 @@ +service vendor.hwcomposer-2-4 /vendor/bin/hw/android.hardware.graphics.composer@2.4-service + class hal animation + user system + group graphics drmrpc + capabilities SYS_NICE + onrestart restart surfaceflinger + writepid /dev/cpuset/system-background/tasks diff --git a/graphics/composer/2.4/default/service.cpp b/graphics/composer/2.4/default/service.cpp new file mode 100644 index 0000000000..98dac3e258 --- /dev/null +++ b/graphics/composer/2.4/default/service.cpp @@ -0,0 +1,55 @@ +/* + * Copyright 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. + */ + +#include + +#include +#include +#include +#include + +using android::hardware::graphics::composer::V2_4::IComposer; +using android::hardware::graphics::composer::V2_4::passthrough::HwcLoader; + +int main() { + // the conventional HAL might start binder services + android::ProcessState::initWithDriver("/dev/vndbinder"); + android::ProcessState::self()->setThreadPoolMaxThreadCount(4); + android::ProcessState::self()->startThreadPool(); + + // same as SF main thread + struct sched_param param = {0}; + param.sched_priority = 2; + if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK, ¶m) != 0) { + ALOGE("Couldn't set SCHED_FIFO: %d", errno); + } + + android::hardware::configureRpcThreadpool(4, true /* will join */); + + android::sp composer = HwcLoader::load(); + if (composer == nullptr) { + return 1; + } + if (composer->registerAsService() != android::NO_ERROR) { + ALOGE("failed to register service"); + return 1; + } + + android::hardware::joinRpcThreadpool(); + + ALOGE("service is terminating"); + return 1; +} diff --git a/graphics/composer/2.4/utils/OWNERS b/graphics/composer/2.4/utils/OWNERS new file mode 100644 index 0000000000..cc6d937cad --- /dev/null +++ b/graphics/composer/2.4/utils/OWNERS @@ -0,0 +1,4 @@ +# Graphics team +lpy@google.com +stoza@google.com +vhau@google.com diff --git a/graphics/composer/2.4/utils/command-buffer/Android.bp b/graphics/composer/2.4/utils/command-buffer/Android.bp new file mode 100644 index 0000000000..8acf0e13ca --- /dev/null +++ b/graphics/composer/2.4/utils/command-buffer/Android.bp @@ -0,0 +1,18 @@ +cc_library_headers { + name: "android.hardware.graphics.composer@2.4-command-buffer", + defaults: ["hidl_defaults"], + vendor_available: true, + shared_libs: [ + "android.hardware.graphics.composer@2.4", + ], + export_shared_lib_headers: [ + "android.hardware.graphics.composer@2.4", + ], + header_libs: [ + "android.hardware.graphics.composer@2.3-command-buffer", + ], + export_header_lib_headers: [ + "android.hardware.graphics.composer@2.3-command-buffer", + ], + export_include_dirs: ["include"], +} diff --git a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h new file mode 100644 index 0000000000..6b64c163c0 --- /dev/null +++ b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h @@ -0,0 +1,58 @@ +/* + * Copyright 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. + */ + +#pragma once + +#ifndef LOG_TAG +#warn "ComposerCommandBuffer.h included without LOG_TAG" +#endif + +#undef LOG_NDEBUG +#define LOG_NDEBUG 0 + +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_4 { + +using android::hardware::MessageQueue; +using android::hardware::graphics::composer::V2_1::Error; +using android::hardware::graphics::composer::V2_4::IComposerClient; + +// This class helps build a command queue. Note that all sizes/lengths are in +// units of uint32_t's. +class CommandWriterBase : public V2_3::CommandWriterBase { + public: + CommandWriterBase(uint32_t initialMaxSize) : V2_3::CommandWriterBase(initialMaxSize) {} +}; + +// This class helps parse a command queue. Note that all sizes/lengths are in +// units of uint32_t's. +class CommandReaderBase : public V2_3::CommandReaderBase { + public: + CommandReaderBase() : V2_3::CommandReaderBase(){}; +}; + +} // namespace V2_4 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.4/utils/hal/Android.bp b/graphics/composer/2.4/utils/hal/Android.bp new file mode 100644 index 0000000000..3ee4e19a7d --- /dev/null +++ b/graphics/composer/2.4/utils/hal/Android.bp @@ -0,0 +1,36 @@ +// +// Copyright 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. +// + +cc_library_headers { + name: "android.hardware.graphics.composer@2.4-hal", + defaults: ["hidl_defaults"], + vendor_available: true, + shared_libs: [ + "android.hardware.graphics.composer@2.4", + ], + export_shared_lib_headers: [ + "android.hardware.graphics.composer@2.4", + ], + header_libs: [ + "android.hardware.graphics.composer@2.3-hal", + "android.hardware.graphics.composer@2.3-command-buffer", + ], + export_header_lib_headers: [ + "android.hardware.graphics.composer@2.3-hal", + "android.hardware.graphics.composer@2.3-command-buffer", + ], + export_include_dirs: ["include"], +} diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/Composer.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/Composer.h new file mode 100644 index 0000000000..129bae6eb9 --- /dev/null +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/Composer.h @@ -0,0 +1,89 @@ +/* + * Copyright 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. + */ + +#pragma once + +#ifndef LOG_TAG +#warning "Composer.h included without LOG_TAG" +#endif + +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_4 { +namespace hal { + +namespace detail { + +// ComposerImpl implements V2_*::IComposer on top of V2_*::ComposerHal +template +class ComposerImpl : public V2_3::hal::detail::ComposerImpl { + public: + static std::unique_ptr create(std::unique_ptr hal) { + return std::make_unique(std::move(hal)); + } + + explicit ComposerImpl(std::unique_ptr hal) : BaseType2_3(std::move(hal)) {} + + // IComposer 2.4 interface + + Return createClient_2_4(IComposer::createClient_2_4_cb hidl_cb) override { + std::unique_lock lock(mClientMutex); + if (!waitForClientDestroyedLocked(lock)) { + hidl_cb(Error::NO_RESOURCES, nullptr); + return Void(); + } + + sp client = ComposerClient::create(mHal.get()).release(); + if (!client) { + hidl_cb(Error::NO_RESOURCES, nullptr); + return Void(); + } + + auto clientDestroyed = [this]() { onClientDestroyed(); }; + client->setOnClientDestroyed(clientDestroyed); + + mClient = client; + hidl_cb(Error::NONE, client); + return Void(); + } + + private: + using BaseType2_3 = V2_3::hal::detail::ComposerImpl; + using BaseType2_1 = V2_1::hal::detail::ComposerImpl; + + using BaseType2_1::mClient; + using BaseType2_1::mClientMutex; + using BaseType2_1::mHal; + using BaseType2_1::onClientDestroyed; + using BaseType2_1::waitForClientDestroyedLocked; +}; + +} // namespace detail + +using Composer = detail::ComposerImpl; + +} // namespace hal +} // namespace V2_4 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h new file mode 100644 index 0000000000..7110c80db0 --- /dev/null +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h @@ -0,0 +1,69 @@ +/* + * Copyright 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. + */ + +#pragma once + +#ifndef LOG_TAG +#warning "ComposerClient.h included without LOG_TAG" +#endif + +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_4 { +namespace hal { + +namespace detail { + +// ComposerClientImpl implements V2_*::IComposerClient on top of V2_*::ComposerHal +template +class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImpl { + public: + ComposerClientImpl(Hal* hal) : BaseType2_3(hal) {} + + Return getDisplayCapabilities_2_4( + Display display, IComposerClient::getDisplayCapabilities_2_4_cb hidl_cb) override { + std::vector capabilities; + Error error = mHal->getDisplayCapabilities_2_4(display, &capabilities); + hidl_cb(error, capabilities); + return Void(); + } + + static std::unique_ptr create(Hal* hal) { + auto client = std::make_unique(hal); + return client->init() ? std::move(client) : nullptr; + } + + private: + using BaseType2_3 = V2_3::hal::detail::ComposerClientImpl; + using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl; + using BaseType2_1::mHal; +}; + +} // namespace detail + +using ComposerClient = detail::ComposerClientImpl; + +} // namespace hal +} // namespace V2_4 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h new file mode 100644 index 0000000000..0074808309 --- /dev/null +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h @@ -0,0 +1,48 @@ +/* + * Copyright 2018 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. + */ + +#pragma once + +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_4 { +namespace hal { + +using common::V1_1::RenderIntent; +using common::V1_2::ColorMode; +using common::V1_2::Dataspace; +using common::V1_2::Hdr; +using common::V1_2::PixelFormat; +using V2_1::Display; +using V2_1::Error; +using V2_1::Layer; + +class ComposerHal : public V2_3::hal::ComposerHal { + public: + virtual Error getDisplayCapabilities_2_4( + Display display, std::vector* outCapabilities) = 0; +}; + +} // namespace hal +} // namespace V2_4 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.4/utils/passthrough/Android.bp b/graphics/composer/2.4/utils/passthrough/Android.bp new file mode 100644 index 0000000000..43d9aaaa78 --- /dev/null +++ b/graphics/composer/2.4/utils/passthrough/Android.bp @@ -0,0 +1,30 @@ +// +// Copyright 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. +// + +cc_library_headers { + name: "android.hardware.graphics.composer@2.4-passthrough", + defaults: ["hidl_defaults"], + vendor: true, + header_libs: [ + "android.hardware.graphics.composer@2.3-passthrough", + "android.hardware.graphics.composer@2.4-hal", + ], + export_header_lib_headers: [ + "android.hardware.graphics.composer@2.3-passthrough", + "android.hardware.graphics.composer@2.4-hal", + ], + export_include_dirs: ["include"], +} diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h new file mode 100644 index 0000000000..65d47d781d --- /dev/null +++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h @@ -0,0 +1,88 @@ +/* + * Copyright 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. + */ + +#pragma once + +#ifndef LOG_TAG +#warning "HwcHal.h included without LOG_TAG" +#endif + +#include + +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_4 { +namespace passthrough { + +namespace detail { + +using common::V1_1::RenderIntent; +using common::V1_2::ColorMode; +using common::V1_2::Dataspace; +using common::V1_2::Hdr; +using common::V1_2::PixelFormat; +using V2_1::Display; +using V2_1::Error; + +// HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2 +template +class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { + public: + Error getDisplayCapabilities_2_4( + Display display, + std::vector* outCapabilities) override { + std::vector capabilities; + Error error = BaseType2_3::getDisplayCapabilities(display, &capabilities); + if (error != Error::NONE) { + return error; + } + outCapabilities->clear(); + outCapabilities->reserve(capabilities.size()); + for (auto capability : capabilities) { + outCapabilities->push_back(static_cast(capability)); + } + return Error::NONE; + } + + protected: + bool initDispatch() override { + if (!BaseType2_3::initDispatch()) { + return false; + } + return true; + } + + private: + using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl; + using BaseType2_3 = V2_3::passthrough::detail::HwcHalImpl; + using BaseType2_1::mDevice; +}; + +} // namespace detail + +using HwcHal = detail::HwcHalImpl; + +} // namespace passthrough +} // namespace V2_4 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcLoader.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcLoader.h new file mode 100644 index 0000000000..a7cc5886e0 --- /dev/null +++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcLoader.h @@ -0,0 +1,79 @@ +/* + * Copyright 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. + */ + +#pragma once + +#ifndef LOG_TAG +#warning "HwcLoader.h included without LOG_TAG" +#endif + +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_4 { +namespace passthrough { + +class HwcLoader : public V2_3::passthrough::HwcLoader { + public: + static IComposer* load() { + const hw_module_t* module = loadModule(); + if (!module) { + return nullptr; + } + + auto hal = createHalWithAdapter(module); + if (!hal) { + return nullptr; + } + + return createComposer(std::move(hal)).release(); + } + + // create a ComposerHal instance + static std::unique_ptr createHal(const hw_module_t* module) { + auto hal = std::make_unique(); + return hal->initWithModule(module) ? std::move(hal) : nullptr; + } + + // create a ComposerHal instance, insert an adapter if necessary + static std::unique_ptr createHalWithAdapter(const hw_module_t* module) { + bool adapted; + hwc2_device_t* device = openDeviceWithAdapter(module, &adapted); + if (!device) { + return nullptr; + } + auto hal = std::make_unique(); + return hal->initWithDevice(std::move(device), !adapted) ? std::move(hal) : nullptr; + } + + // create an IComposer instance + static std::unique_ptr createComposer(std::unique_ptr hal) { + return hal::Composer::create(std::move(hal)); + } +}; + +} // namespace passthrough +} // namespace V2_4 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp new file mode 100644 index 0000000000..b87a116865 --- /dev/null +++ b/graphics/composer/2.4/utils/vts/Android.bp @@ -0,0 +1,42 @@ +// +// Copyright 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. +// + +cc_library_static { + name: "android.hardware.graphics.composer@2.4-vts", + defaults: ["hidl_defaults"], + srcs: [ + "ComposerVts.cpp", + ], + static_libs: [ + "VtsHalHidlTargetTestBase", + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.composer@2.3-vts", + "android.hardware.graphics.composer@2.3", + "android.hardware.graphics.composer@2.4", + ], + header_libs: [ + "android.hardware.graphics.composer@2.1-command-buffer", + "android.hardware.graphics.composer@2.2-command-buffer", + "android.hardware.graphics.composer@2.3-command-buffer", + ], + cflags: [ + "-O0", + "-g", + "-DLOG_TAG=\"ComposerVts\"", + ], + export_include_dirs: ["include"], +} diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp new file mode 100644 index 0000000000..ee4f3a3959 --- /dev/null +++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 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. + */ + +#include + +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_4 { +namespace vts { + +using V2_1::Error; + +Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService()) {} + +Composer::Composer(const std::string& name) + : Composer(::testing::VtsHalHidlTargetTestBase::getService(name)) {} + +Composer::Composer(const sp& composer) + : V2_3::vts::Composer(composer), mComposer(composer) {} + +std::unique_ptr Composer::createClient() { + std::unique_ptr client; + mComposer->createClient_2_4([&client](const auto& tmpError, const auto& tmpClient) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to create client"; + client = std::make_unique(tmpClient); + }); + + return client; +} + +sp ComposerClient::getRaw() const { + return mClient; +} + +Error ComposerClient::getDisplayCapabilities( + Display display, std::vector* outCapabilities) { + std::vector capabilities; + Error error = Error::NONE; + mClient->getDisplayCapabilities_2_4(display, + [&](const auto& tmpError, const auto& tmpCapabilities) { + error = tmpError; + *outCapabilities = tmpCapabilities; + }); + return error; +} + +} // namespace vts +} // namespace V2_4 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h new file mode 100644 index 0000000000..0a301c6ca7 --- /dev/null +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h @@ -0,0 +1,83 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_4 { +namespace vts { + +using common::V1_1::RenderIntent; +using common::V1_2::ColorMode; +using common::V1_2::Dataspace; +using common::V1_2::Hdr; +using common::V1_2::PixelFormat; +using V2_1::Display; +using V2_1::Error; +using V2_4::IComposer; +using V2_4::IComposerClient; + +class ComposerClient; + +// A wrapper to IComposer. +class Composer : public V2_3::vts::Composer { + public: + Composer(); + explicit Composer(const std::string& name); + + std::unique_ptr createClient(); + + protected: + explicit Composer(const sp& composer); + + private: + const sp mComposer; +}; + +// A wrapper to IComposerClient. +class ComposerClient : public V2_3::vts::ComposerClient { + public: + explicit ComposerClient(const sp& client) + : V2_3::vts::ComposerClient(client), mClient(client) {} + + sp getRaw() const; + + Error getDisplayCapabilities( + Display display, + std::vector* outDisplayCapabilities); + + private: + const sp mClient; +}; + +} // namespace vts +} // namespace V2_4 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp new file mode 100644 index 0000000000..d437f2486e --- /dev/null +++ b/graphics/composer/2.4/vts/functional/Android.bp @@ -0,0 +1,48 @@ +// +// Copyright 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. +// + +cc_test { + name: "VtsHalGraphicsComposerV2_4TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalGraphicsComposerV2_4TargetTest.cpp"], + + // TODO(b/64437680): Assume these libs are always available on the device. + shared_libs: [ + "libfmq", + "libhidltransport", + "libsync", + ], + static_libs: [ + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.composer@2.1-vts", + "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.composer@2.2-vts", + "android.hardware.graphics.composer@2.3", + "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", + ], + header_libs: [ + "android.hardware.graphics.composer@2.1-command-buffer", + "android.hardware.graphics.composer@2.2-command-buffer", + "android.hardware.graphics.composer@2.3-command-buffer", + "android.hardware.graphics.composer@2.4-command-buffer", + ], +} diff --git a/graphics/composer/2.4/vts/functional/OWNERS b/graphics/composer/2.4/vts/functional/OWNERS new file mode 100644 index 0000000000..b3ea6bef7b --- /dev/null +++ b/graphics/composer/2.4/vts/functional/OWNERS @@ -0,0 +1,8 @@ +# Graphics team +lpy@google.com +stoza@google.com +vhau@google.com + +# VTS team +yim@google.com +zhuoyao@google.com diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp new file mode 100644 index 0000000000..0fccc58637 --- /dev/null +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -0,0 +1,197 @@ +/* + * Copyright 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 "graphics_composer_hidl_hal_test@2.4" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_4 { +namespace vts { +namespace { + +using common::V1_0::BufferUsage; +using common::V1_1::RenderIntent; +using common::V1_2::ColorMode; +using common::V1_2::Dataspace; +using common::V1_2::PixelFormat; +using mapper::V2_0::IMapper; +using mapper::V2_0::vts::Gralloc; + +// Test environment for graphics.composer +class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static GraphicsComposerHidlEnvironment* Instance() { + static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { registerTestService(); } + + private: + GraphicsComposerHidlEnvironment() {} + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment); +}; + +class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { + protected: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE( + mComposer = std::make_unique( + GraphicsComposerHidlEnvironment::Instance()->getServiceName())); + ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); + + mComposerCallback = new V2_1::vts::GraphicsComposerCallback; + mComposerClient->registerCallback(mComposerCallback); + + // assume the first display is primary and is never removed + mPrimaryDisplay = waitForFirstDisplay(); + + mInvalidDisplayId = GetInvalidDisplayId(); + + // explicitly disable vsync + mComposerClient->setVsyncEnabled(mPrimaryDisplay, false); + mComposerCallback->setVsyncAllowed(false); + + mWriter = std::make_unique(1024); + mReader = std::make_unique(); + } + + void TearDown() override { + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_EQ(0, mReader->mCompositionChanges.size()); + if (mComposerCallback != nullptr) { + EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount()); + EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount()); + EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount()); + } + } + + // returns an invalid display id (one that has not been registered to a + // display. Currently assuming that a device will never have close to + // std::numeric_limit::max() displays registered while running tests + Display GetInvalidDisplayId() { + std::vector validDisplays = mComposerCallback->getDisplays(); + uint64_t id = std::numeric_limits::max(); + while (id > 0) { + if (std::find(validDisplays.begin(), validDisplays.end(), id) == validDisplays.end()) { + return id; + } + id--; + } + + return 0; + } + + void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } + + std::unique_ptr mComposer; + std::unique_ptr mComposerClient; + sp mComposerCallback; + // the first display and is assumed never to be removed + Display mPrimaryDisplay; + Display mInvalidDisplayId; + std::unique_ptr mWriter; + std::unique_ptr mReader; + + private: + Display waitForFirstDisplay() { + while (true) { + std::vector displays = mComposerCallback->getDisplays(); + if (displays.empty()) { + usleep(5 * 1000); + continue; + } + + return displays[0]; + } + } +}; + +// Tests for IComposerClient::Command. +class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { + protected: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp()); + + ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique()); + + mWriter = std::make_unique(1024); + mReader = std::make_unique(); + } + + void TearDown() override { + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown()); + } + + const native_handle_t* allocate() { + IMapper::BufferDescriptorInfo info{}; + info.width = 64; + info.height = 64; + info.layerCount = 1; + info.format = static_cast(PixelFormat::RGBA_8888); + info.usage = + static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); + + return mGralloc->allocate(info); + } + + void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } + + std::unique_ptr mWriter; + std::unique_ptr mReader; + + private: + std::unique_ptr mGralloc; +}; + +TEST_F(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) { + std::vector capabilities; + const auto error = mComposerClient->getDisplayCapabilities(mInvalidDisplayId, &capabilities); + EXPECT_EQ(Error::BAD_DISPLAY, error); +} + +} // namespace +} // namespace vts +} // namespace V2_4 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android + +int main(int argc, char** argv) { + using android::hardware::graphics::composer::V2_4::vts::GraphicsComposerHidlEnvironment; + ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + return status; +} From e3a08d761ef093bbf767758c8d24e4c0e960eda6 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Wed, 17 Jul 2019 17:30:41 -0700 Subject: [PATCH 0035/1022] Enable VNDK for composer 2.4 BUG: 135929065 Test: build Change-Id: I7c55b48a84840d61d48c588e5c464a6f00fea7f0 --- graphics/composer/2.4/Android.bp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/graphics/composer/2.4/Android.bp b/graphics/composer/2.4/Android.bp index 4a92df2c5b..0e1bc0940a 100644 --- a/graphics/composer/2.4/Android.bp +++ b/graphics/composer/2.4/Android.bp @@ -4,8 +4,7 @@ hidl_interface { name: "android.hardware.graphics.composer@2.4", root: "android.hardware", vndk: { - // TODO(b/135929065) enable once we are ready to use. - enabled: false, + enabled: true, }, srcs: [ "IComposer.hal", From d6db130a2beb0f9f104e7551dc41b09abe255fe0 Mon Sep 17 00:00:00 2001 From: Inseob Kim Date: Thu, 18 Jul 2019 16:43:21 +0900 Subject: [PATCH 0036/1022] Use shared variant of VNDK libmedia_helper Vendor modules should use shared VNDK. Bug: 137178339 Test: m && boot blueline Change-Id: I56ad69125811ff768d8064af34acf5603b575b4b --- audio/core/all-versions/default/Android.bp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp index a1af3c4db5..97b4553361 100644 --- a/audio/core/all-versions/default/Android.bp +++ b/audio/core/all-versions/default/Android.bp @@ -26,6 +26,7 @@ cc_defaults { "libhidlbase", "libhidltransport", "liblog", + "libmedia_helper", "libutils", "android.hardware.audio.common-util", ], @@ -37,10 +38,6 @@ cc_defaults { "libhardware_headers", "libmedia_headers", ], - - whole_static_libs: [ - "libmedia_helper", - ], } cc_library_shared { From c99ced161c0ce2ccd746d6913455e3c42eb54bf5 Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Thu, 18 Jul 2019 13:31:04 -0700 Subject: [PATCH 0037/1022] Move strided_slice_invalid_output_dims to spec directory. Bug: 132155416 Test: 1.2 VTS Change-Id: I0479b8172c55e5e290f3fc8530a428ac5f54998f --- .../1.2/vts/functional/GeneratedTestsV1_2.cpp | 15 -- ...ided_slice_invalid_output_dims.example.cpp | 116 ---------- ...trided_slice_invalid_output_dims.model.cpp | 216 ------------------ .../strided_slice_invalid_output_dims.mod.py | 43 ---- 4 files changed, 390 deletions(-) delete mode 100644 neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp delete mode 100644 neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp delete mode 100644 neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp index 8481b4d7eb..872fc0b071 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp @@ -44,21 +44,6 @@ std::vector createRequests(const std::vector& exampl // in frameworks/ml/nn/runtime/tests/generated/ #include "vts/V1_2/all_generated_V1_2_vts_tests.cpp" -// Generated from spec/strided_slice_invalid_output_dims.mod.py. -// TODO(b/132155416): Make this part of all_generated_V1_2_vts_tests.cpp. -namespace strided_slice_invalid_output_dims { -#include "generated/strided_slice_invalid_output_dims.example.cpp" -#include "generated/strided_slice_invalid_output_dims.model.cpp" -} // namespace strided_slice_invalid_output_dims - -// TODO(b/132155416): Make this part of all_generated_V1_2_vts_tests.cpp. -TEST_F(ValidationTest, strided_slice_invalid_output_dims) { - const Model model = strided_slice_invalid_output_dims::createTestModel(); - const std::vector requests = - createRequests(strided_slice_invalid_output_dims::get_examples()); - validateFailure(model, requests); -} - } // namespace functional } // namespace vts } // namespace V1_2 diff --git a/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp b/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp deleted file mode 100644 index 064083340c..0000000000 --- a/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp +++ /dev/null @@ -1,116 +0,0 @@ -// clang-format off -// Generated file (from: strided_slice_invalid_output_dims.mod.py). Do not edit -std::vector& get_examples() { -static std::vector examples = { -// Begin of an example -{ -.operands = { -//Input(s) -{ // See tools/test_generator/include/TestHarness.h:MixedTyped - // int -> Dimensions map - .operandDimensions = {{0, {2, 3}}}, - // int -> FLOAT32 map - .float32Operands = {{0, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}}}, - // int -> INT32 map - .int32Operands = {}, - // int -> QUANT8_ASYMM map - .quant8AsymmOperands = {}, - // int -> QUANT16_SYMM map - .quant16SymmOperands = {}, - // int -> FLOAT16 map - .float16Operands = {}, - // int -> BOOL8 map - .bool8Operands = {}, - // int -> QUANT8_SYMM_PER_CHANNEL map - .quant8ChannelOperands = {}, - // int -> QUANT16_ASYMM map - .quant16AsymmOperands = {}, - // int -> QUANT8_SYMM map - .quant8SymmOperands = {}, -}, -//Output(s) -{ // See tools/test_generator/include/TestHarness.h:MixedTyped - // int -> Dimensions map - .operandDimensions = {{0, {3}}}, - // int -> FLOAT32 map - .float32Operands = {{0, {1.0f, 2.0f, 3.0f}}}, - // int -> INT32 map - .int32Operands = {}, - // int -> QUANT8_ASYMM map - .quant8AsymmOperands = {}, - // int -> QUANT16_SYMM map - .quant16SymmOperands = {}, - // int -> FLOAT16 map - .float16Operands = {}, - // int -> BOOL8 map - .bool8Operands = {}, - // int -> QUANT8_SYMM_PER_CHANNEL map - .quant8ChannelOperands = {}, - // int -> QUANT16_ASYMM map - .quant16AsymmOperands = {}, - // int -> QUANT8_SYMM map - .quant8SymmOperands = {}, -} -}, -}, // End of an example -}; -return examples; -}; - -std::vector& get_examples_dynamic_output_shape() { -static std::vector examples_dynamic_output_shape = { -// Begin of an example -{ -.operands = { -//Input(s) -{ // See tools/test_generator/include/TestHarness.h:MixedTyped - // int -> Dimensions map - .operandDimensions = {{0, {2, 3}}}, - // int -> FLOAT32 map - .float32Operands = {{0, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}}}, - // int -> INT32 map - .int32Operands = {}, - // int -> QUANT8_ASYMM map - .quant8AsymmOperands = {}, - // int -> QUANT16_SYMM map - .quant16SymmOperands = {}, - // int -> FLOAT16 map - .float16Operands = {}, - // int -> BOOL8 map - .bool8Operands = {}, - // int -> QUANT8_SYMM_PER_CHANNEL map - .quant8ChannelOperands = {}, - // int -> QUANT16_ASYMM map - .quant16AsymmOperands = {}, - // int -> QUANT8_SYMM map - .quant8SymmOperands = {}, -}, -//Output(s) -{ // See tools/test_generator/include/TestHarness.h:MixedTyped - // int -> Dimensions map - .operandDimensions = {{0, {3}}}, - // int -> FLOAT32 map - .float32Operands = {{0, {1.0f, 2.0f, 3.0f}}}, - // int -> INT32 map - .int32Operands = {}, - // int -> QUANT8_ASYMM map - .quant8AsymmOperands = {}, - // int -> QUANT16_SYMM map - .quant16SymmOperands = {}, - // int -> FLOAT16 map - .float16Operands = {}, - // int -> BOOL8 map - .bool8Operands = {}, - // int -> QUANT8_SYMM_PER_CHANNEL map - .quant8ChannelOperands = {}, - // int -> QUANT16_ASYMM map - .quant16AsymmOperands = {}, - // int -> QUANT8_SYMM map - .quant8SymmOperands = {}, -} -}, -}, // End of an example -}; -return examples_dynamic_output_shape; -}; - diff --git a/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp b/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp deleted file mode 100644 index 106655aa30..0000000000 --- a/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp +++ /dev/null @@ -1,216 +0,0 @@ -// clang-format off -// Generated file (from: strided_slice_invalid_output_dims.mod.py). Do not edit -// Create the model -Model createTestModel() { - const std::vector operands = { - { - .type = OperandType::TENSOR_FLOAT32, - .dimensions = {2, 3}, - .numberOfConsumers = 1, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::MODEL_INPUT, - .location = {.poolIndex = 0, .offset = 0, .length = 0}, - }, - { - .type = OperandType::TENSOR_INT32, - .dimensions = {2}, - .numberOfConsumers = 1, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::CONSTANT_COPY, - .location = {.poolIndex = 0, .offset = 0, .length = 8}, - }, - { - .type = OperandType::TENSOR_INT32, - .dimensions = {2}, - .numberOfConsumers = 1, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::CONSTANT_COPY, - .location = {.poolIndex = 0, .offset = 8, .length = 8}, - }, - { - .type = OperandType::TENSOR_INT32, - .dimensions = {2}, - .numberOfConsumers = 1, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::CONSTANT_COPY, - .location = {.poolIndex = 0, .offset = 16, .length = 8}, - }, - { - .type = OperandType::INT32, - .dimensions = {}, - .numberOfConsumers = 1, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::CONSTANT_COPY, - .location = {.poolIndex = 0, .offset = 24, .length = 4}, - }, - { - .type = OperandType::INT32, - .dimensions = {}, - .numberOfConsumers = 1, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::CONSTANT_COPY, - .location = {.poolIndex = 0, .offset = 28, .length = 4}, - }, - { - .type = OperandType::INT32, - .dimensions = {}, - .numberOfConsumers = 1, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::CONSTANT_COPY, - .location = {.poolIndex = 0, .offset = 32, .length = 4}, - }, - { - .type = OperandType::TENSOR_FLOAT32, - .dimensions = {3}, - .numberOfConsumers = 0, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::MODEL_OUTPUT, - .location = {.poolIndex = 0, .offset = 0, .length = 0}, - } - }; - - const std::vector operations = { - { - .type = OperationType::STRIDED_SLICE, - .inputs = {0, 1, 2, 3, 4, 5, 6}, - .outputs = {7}, - } - }; - - const std::vector inputIndexes = {0}; - const std::vector outputIndexes = {7}; - std::vector operandValues = { - 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 - }; - const std::vector pools = {}; - - return { - .operands = operands, - .operations = operations, - .inputIndexes = inputIndexes, - .outputIndexes = outputIndexes, - .operandValues = operandValues, - .pools = pools, - }; -} - -inline bool is_ignored(int i) { - static std::set ignore = {}; - return ignore.find(i) != ignore.end(); -} - -// Create the model -Model createTestModel_dynamic_output_shape() { - const std::vector operands = { - { - .type = OperandType::TENSOR_FLOAT32, - .dimensions = {2, 3}, - .numberOfConsumers = 1, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::MODEL_INPUT, - .location = {.poolIndex = 0, .offset = 0, .length = 0}, - }, - { - .type = OperandType::TENSOR_INT32, - .dimensions = {2}, - .numberOfConsumers = 1, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::CONSTANT_COPY, - .location = {.poolIndex = 0, .offset = 0, .length = 8}, - }, - { - .type = OperandType::TENSOR_INT32, - .dimensions = {2}, - .numberOfConsumers = 1, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::CONSTANT_COPY, - .location = {.poolIndex = 0, .offset = 8, .length = 8}, - }, - { - .type = OperandType::TENSOR_INT32, - .dimensions = {2}, - .numberOfConsumers = 1, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::CONSTANT_COPY, - .location = {.poolIndex = 0, .offset = 16, .length = 8}, - }, - { - .type = OperandType::INT32, - .dimensions = {}, - .numberOfConsumers = 1, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::CONSTANT_COPY, - .location = {.poolIndex = 0, .offset = 24, .length = 4}, - }, - { - .type = OperandType::INT32, - .dimensions = {}, - .numberOfConsumers = 1, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::CONSTANT_COPY, - .location = {.poolIndex = 0, .offset = 28, .length = 4}, - }, - { - .type = OperandType::INT32, - .dimensions = {}, - .numberOfConsumers = 1, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::CONSTANT_COPY, - .location = {.poolIndex = 0, .offset = 32, .length = 4}, - }, - { - .type = OperandType::TENSOR_FLOAT32, - .dimensions = {0}, - .numberOfConsumers = 0, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::MODEL_OUTPUT, - .location = {.poolIndex = 0, .offset = 0, .length = 0}, - } - }; - - const std::vector operations = { - { - .type = OperationType::STRIDED_SLICE, - .inputs = {0, 1, 2, 3, 4, 5, 6}, - .outputs = {7}, - } - }; - - const std::vector inputIndexes = {0}; - const std::vector outputIndexes = {7}; - std::vector operandValues = { - 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 - }; - const std::vector pools = {}; - - return { - .operands = operands, - .operations = operations, - .inputIndexes = inputIndexes, - .outputIndexes = outputIndexes, - .operandValues = operandValues, - .pools = pools, - }; -} - -inline bool is_ignored_dynamic_output_shape(int i) { - static std::set ignore = {}; - return ignore.find(i) != ignore.end(); -} - diff --git a/neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py b/neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py deleted file mode 100644 index e8d30f3fb2..0000000000 --- a/neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py +++ /dev/null @@ -1,43 +0,0 @@ -# -# 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. -# - -# This test makes sure that executing STRIDED_SLICE results in a failure when -# the output dimensions do not match shrinkAxisMask. -# -# The test generator does not support generating tests resulting in execution -# failure, so the gTest part of this test has been written by hand. -# TODO(b/132155416): Move this under frameworks/ml/nn/runtime/test/specs/V1_2. -# -# Based on strided_slice_float_11.mod.py. - -model = Model() -i1 = Input("input", "TENSOR_FLOAT32", "{2, 3}") -begins = Parameter("begins", "TENSOR_INT32", "{2}", [0, 0]) -# The value "2" below makes the test invalid. See http://b/79856511#comment2. -ends = Parameter("ends", "TENSOR_INT32", "{2}", [2, 3]) -strides = Parameter("strides", "TENSOR_INT32", "{2}", [1, 1]) -beginMask = Int32Scalar("beginMask", 0) -endMask = Int32Scalar("endMask", 0) -shrinkAxisMask = Int32Scalar("shrinkAxisMask", 1) - -output = Output("output", "TENSOR_FLOAT32", "{3}") - -model = model.Operation("STRIDED_SLICE", i1, begins, ends, strides, beginMask, endMask, shrinkAxisMask).To(output) - -Example({ - i1: [1, 2, 3, 4, 5, 6], - output: [1, 2, 3], -}) From 92d1226f9c89b9709c60bce222873a8f25562bbd Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Mon, 22 Jul 2019 10:18:34 -0700 Subject: [PATCH 0038/1022] Setting layer dataspace to match the color mode Bug: 135045017 Test: build, boot, VtsHalGraphicsComposerV2_2TargetTest Change-Id: I7188c53ca92895a98da062a248f6b781202671b8 --- .../composer/2.2/utils/vts/ReadbackVts.cpp | 7 +- .../include/composer-vts/2.2/ReadbackVts.h | 2 + ...VtsHalGraphicsComposerV2_2ReadbackTest.cpp | 474 +++++++++++------- 3 files changed, 304 insertions(+), 179 deletions(-) diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp index 02ab49b0a8..d479aa74ec 100644 --- a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp +++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp @@ -287,7 +287,6 @@ TestBufferLayer::~TestBufferLayer() { void TestBufferLayer::write(const std::shared_ptr& writer) { TestLayer::write(writer); writer->setLayerCompositionType(mComposition); - writer->setLayerDataspace(Dataspace::UNKNOWN); writer->setLayerVisibleRegion(std::vector(1, mDisplayFrame)); if (mBufferHandle != nullptr) writer->setLayerBuffer(0, mBufferHandle, mFillFence); } @@ -337,6 +336,12 @@ void TestBufferLayer::setBuffer(std::vector colors) { mFormat, mUsage, mStride)); } +void TestBufferLayer::setDataspace(Dataspace dataspace, + const std::shared_ptr& writer) { + writer->selectLayer(mLayer); + writer->setLayerDataspace(dataspace); +} + void TestBufferLayer::setToClientComposition(const std::shared_ptr& writer) { writer->selectLayer(mLayer); writer->setLayerCompositionType(IComposerClient::Composition::CLIENT); diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h index 9fa1c3c699..7519a64b4f 100644 --- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h +++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h @@ -123,6 +123,8 @@ class TestBufferLayer : public TestLayer { void setBuffer(std::vector colors); + void setDataspace(Dataspace dataspace, const std::shared_ptr& writer); + void setToClientComposition(const std::shared_ptr& writer); uint32_t mWidth; diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp index fd46e37052..92c03f0dbf 100644 --- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp @@ -268,6 +268,7 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerBuffer) { PixelFormat::RGBA_8888); layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); layer->setZOrder(10); + layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); std::vector> layers = {layer}; @@ -398,6 +399,7 @@ TEST_F(GraphicsComposerReadbackTest, ClientComposition) { PixelFormat::RGBA_FP16); layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); layer->setZOrder(10); + layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); std::vector> layers = {layer}; @@ -519,6 +521,7 @@ TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) { deviceLayer->setDisplayFrame({0, 0, static_cast(deviceLayer->mWidth), static_cast(deviceLayer->mHeight)}); deviceLayer->setZOrder(10); + deviceLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors)); deviceLayer->write(mWriter); @@ -631,6 +634,7 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerDamage) { PixelFormat::RGBA_8888); layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); layer->setZOrder(10); + layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); std::vector> layers = {layer}; @@ -775,6 +779,7 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerSourceCrop) { PixelFormat::RGBA_8888); layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); layer->setZOrder(10); + layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); layer->setSourceCrop({0, static_cast(mDisplayHeight / 2), static_cast(mDisplayWidth), static_cast(mDisplayHeight)}); @@ -894,6 +899,7 @@ class GraphicsComposerBlendModeReadbackTest : public GraphicsComposerReadbackTes public: void SetUp() override { GraphicsComposerReadbackTest::SetUp(); + mTestColorModes = {ColorMode::SRGB}; // TODO: add more color mode support mBackgroundColor = BLACK; mTopLayerColor = RED; } @@ -920,6 +926,7 @@ class GraphicsComposerBlendModeReadbackTest : public GraphicsComposerReadbackTes PixelFormat::RGBA_8888); layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); layer->setZOrder(10); + layer->setDataspace(Dataspace::UNKNOWN, mWriter); ASSERT_NO_FATAL_FAILURE(layer->setBuffer(topLayerPixelColors)); layer->setBlendMode(blendMode); @@ -970,109 +977,162 @@ class GraphicsComposerBlendModeReadbackTest : public GraphicsComposerReadbackTes }; TEST_P(GraphicsComposerBlendModeReadbackTest, None) { - if (!mHasReadbackBuffer) { - GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; - return; + for (ColorMode mode : mTestColorModes) { + std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" + << std::endl; + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); + + if (!mHasReadbackBuffer) { + std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + std::vector expectedColors(mDisplayWidth * mDisplayHeight); + + setBackgroundColor(BLACK); + setTopLayerColor(TRANSLUCENT_RED); + setUpLayers(IComposerClient::BlendMode::NONE); + setExpectedColors(expectedColors); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } - - mWriter->selectDisplay(mPrimaryDisplay); - - std::vector expectedColors(mDisplayWidth * mDisplayHeight); - - setBackgroundColor(BLACK); - setTopLayerColor(TRANSLUCENT_RED); - setUpLayers(IComposerClient::BlendMode::NONE); - setExpectedColors(expectedColors); - - ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, - mDisplayHeight, mPixelFormat, mDataspace); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - writeLayers(mLayers); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - if (mReader->mCompositionChanges.size() != 0) { - clearCommandReaderState(); - GTEST_SUCCEED(); - return; - } - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->presentDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } // TODO: bug 116865056: Readback returns (245, 0, 0) for layer plane // alpha of .2, expected 10.2 TEST_P(GraphicsComposerBlendModeReadbackTest, DISABLED_Coverage) { - if (!mHasReadbackBuffer) { - GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; - return; + for (ColorMode mode : mTestColorModes) { + std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" + << std::endl; + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); + + if (!mHasReadbackBuffer) { + std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + std::vector expectedColors(mDisplayWidth * mDisplayHeight); + + setBackgroundColor(BLACK); + setTopLayerColor(TRANSLUCENT_RED); + + setUpLayers(IComposerClient::BlendMode::COVERAGE); + setExpectedColors(expectedColors); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } - - mWriter->selectDisplay(mPrimaryDisplay); - - std::vector expectedColors(mDisplayWidth * mDisplayHeight); - - setBackgroundColor(BLACK); - setTopLayerColor(TRANSLUCENT_RED); - - setUpLayers(IComposerClient::BlendMode::COVERAGE); - setExpectedColors(expectedColors); - - ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, - mDisplayHeight, mPixelFormat, mDataspace); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - writeLayers(mLayers); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - if (mReader->mCompositionChanges.size() != 0) { - clearCommandReaderState(); - GTEST_SUCCEED(); - return; - } - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->presentDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } TEST_P(GraphicsComposerBlendModeReadbackTest, Premultiplied) { - if (!mHasReadbackBuffer) { - GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; - return; + for (ColorMode mode : mTestColorModes) { + std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" + << std::endl; + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); + + if (!mHasReadbackBuffer) { + std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + mWriter->selectDisplay(mPrimaryDisplay); + + std::vector expectedColors(mDisplayWidth * mDisplayHeight); + + setBackgroundColor(BLACK); + setTopLayerColor(TRANSLUCENT_RED); + setUpLayers(IComposerClient::BlendMode::PREMULTIPLIED); + setExpectedColors(expectedColors); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } - - mWriter->selectDisplay(mPrimaryDisplay); - - std::vector expectedColors(mDisplayWidth * mDisplayHeight); - - setBackgroundColor(BLACK); - setTopLayerColor(TRANSLUCENT_RED); - setUpLayers(IComposerClient::BlendMode::PREMULTIPLIED); - setExpectedColors(expectedColors); - - ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, - mDisplayHeight, mPixelFormat, mDataspace); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - writeLayers(mLayers); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - if (mReader->mCompositionChanges.size() != 0) { - clearCommandReaderState(); - GTEST_SUCCEED(); - return; - } - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->presentDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } INSTANTIATE_TEST_CASE_P(BlendModeTest, GraphicsComposerBlendModeReadbackTest, @@ -1117,102 +1177,160 @@ class GraphicsComposerTransformReadbackTest : public GraphicsComposerReadbackTes }; TEST_F(GraphicsComposerTransformReadbackTest, FLIP_H) { - if (!mHasReadbackBuffer) { - GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; - return; - } - ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, - mDisplayHeight, mPixelFormat, mDataspace); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - mLayer->setTransform(Transform::FLIP_H); - std::vector expectedColors(mDisplayWidth * mDisplayHeight); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE); + for (ColorMode mode : mTestColorModes) { + std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" + << std::endl; + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); - writeLayers(mLayers); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - if (mReader->mCompositionChanges.size() != 0) { - clearCommandReaderState(); - GTEST_SUCCEED(); - return; - } - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->presentDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + if (!mHasReadbackBuffer) { + std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + mLayer->setTransform(Transform::FLIP_H); + mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + + std::vector expectedColors(mDisplayWidth * mDisplayHeight); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE); + + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + } } TEST_F(GraphicsComposerTransformReadbackTest, FLIP_V) { - if (!mHasReadbackBuffer) { - GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; - return; + for (ColorMode mode : mTestColorModes) { + std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" + << std::endl; + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); + + if (!mHasReadbackBuffer) { + std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + mLayer->setTransform(Transform::FLIP_V); + mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + + std::vector expectedColors(mDisplayWidth * mDisplayHeight); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE); + + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } - ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, - mDisplayHeight, mPixelFormat, mDataspace); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - - mLayer->setTransform(Transform::FLIP_V); - - std::vector expectedColors(mDisplayWidth * mDisplayHeight); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE); - - writeLayers(mLayers); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - if (mReader->mCompositionChanges.size() != 0) { - clearCommandReaderState(); - GTEST_SUCCEED(); - return; - } - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->presentDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } TEST_F(GraphicsComposerTransformReadbackTest, ROT_180) { - if (!mHasReadbackBuffer) { - GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; - return; + for (ColorMode mode : mTestColorModes) { + std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" + << std::endl; + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, + tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); + + if (!mHasReadbackBuffer) { + std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + mLayer->setTransform(Transform::ROT_180); + mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + + std::vector expectedColors(mDisplayWidth * mDisplayHeight); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength}, + RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mSideLength / 2, mSideLength / 2}, BLUE); + + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } - ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, - mDisplayHeight, mPixelFormat, mDataspace); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - - mLayer->setTransform(Transform::ROT_180); - - std::vector expectedColors(mDisplayWidth * mDisplayHeight); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength}, - RED); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, - {0, 0, mSideLength / 2, mSideLength / 2}, BLUE); - - writeLayers(mLayers); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - if (mReader->mCompositionChanges.size() != 0) { - clearCommandReaderState(); - GTEST_SUCCEED(); - return; - } - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->presentDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); } } // anonymous namespace From 2bcfdc82a0172d42202d3b3bc4dab98d8cc0ff58 Mon Sep 17 00:00:00 2001 From: Slava Shklyaev Date: Wed, 17 Jul 2019 15:50:57 +0100 Subject: [PATCH 0039/1022] Refactor generated NNAPI tests See change I2c0366fb87c96851fa6e0f8fe9ceac012d8e3513 Bug: 136097638 Test: m VtsHalNeuralnetworksV1_0TargetTest Test: m VtsHalNeuralnetworksV1_1TargetTest Test: m VtsHalNeuralnetworksV1_2TargetTest Test: m VtsHalNeuralnetworksV1_2CompatV1_0TargetTest Change-Id: I6fdede028422145d313d46532b5d2154ef0d40bc --- neuralnetworks/1.0/vts/functional/Android.bp | 4 +- .../vts/functional/GeneratedTestHarness.cpp | 2 + .../1.0/vts/functional/GeneratedTestHarness.h | 5 +- .../1.0/vts/functional/GeneratedTests.h | 38 +++++++++++++ .../1.0/vts/functional/GeneratedTestsV1_0.cpp | 52 ------------------ neuralnetworks/1.1/vts/functional/Android.bp | 6 +-- .../vts/functional/GeneratedTestHarness.cpp | 2 + .../1.1/vts/functional/GeneratedTestHarness.h | 2 + .../1.1/vts/functional/GeneratedTests.h | 39 ++++++++++++++ .../1.1/vts/functional/GeneratedTestsV1_0.cpp | 53 ------------------ .../1.1/vts/functional/GeneratedTestsV1_1.cpp | 53 ------------------ neuralnetworks/1.2/vts/functional/Android.bp | 9 ++-- .../functional/CompilationCachingTests.cpp | 37 ++++++++----- .../vts/functional/GeneratedTestHarness.cpp | 2 + .../1.2/vts/functional/GeneratedTestHarness.h | 2 + .../1.2/vts/functional/GeneratedTests.h | 40 ++++++++++++++ .../1.2/vts/functional/GeneratedTestsV1_0.cpp | 54 ------------------- .../1.2/vts/functional/GeneratedTestsV1_1.cpp | 54 ------------------- .../1.2/vts/functional/GeneratedTestsV1_2.cpp | 54 ------------------- 19 files changed, 163 insertions(+), 345 deletions(-) create mode 100644 neuralnetworks/1.0/vts/functional/GeneratedTests.h delete mode 100644 neuralnetworks/1.0/vts/functional/GeneratedTestsV1_0.cpp create mode 100644 neuralnetworks/1.1/vts/functional/GeneratedTests.h delete mode 100644 neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp delete mode 100644 neuralnetworks/1.1/vts/functional/GeneratedTestsV1_1.cpp create mode 100644 neuralnetworks/1.2/vts/functional/GeneratedTests.h delete mode 100644 neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp delete mode 100644 neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp delete mode 100644 neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp index 0d70816f31..a8406de235 100644 --- a/neuralnetworks/1.0/vts/functional/Android.bp +++ b/neuralnetworks/1.0/vts/functional/Android.bp @@ -76,7 +76,7 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_0TargetTestDefaults"], srcs: [ "BasicTests.cpp", - "GeneratedTestsV1_0.cpp", + ":VtsHalNeuralNetworksV1_0_all_generated_V1_0_tests", ], } @@ -85,7 +85,7 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_0TargetTestDefaults"], srcs: [ "BasicTests.cpp", - "GeneratedTestsV1_0.cpp", + ":VtsHalNeuralNetworksV1_0_all_generated_V1_0_tests", ], cflags: [ "-DPRESUBMIT_NOT_VTS", diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp index 603054dddf..40d2f4ceb7 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp @@ -33,6 +33,7 @@ namespace android { namespace hardware { namespace neuralnetworks { +namespace V1_0 { namespace generated_tests { using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; @@ -217,6 +218,7 @@ void Execute(const sp& device, std::function create_model, } } // namespace generated_tests +} // namespace V1_0 } // namespace neuralnetworks } // namespace hardware } // namespace android diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h index 11950d91f0..337eb0f924 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h @@ -23,15 +23,16 @@ namespace android { namespace hardware { namespace neuralnetworks { - +namespace V1_0 { namespace generated_tests { + using ::test_helper::MixedTypedExample; void Execute(const sp& device, std::function create_model, std::function is_ignored, const std::vector& examples); } // namespace generated_tests - +} // namespace V1_0 } // namespace neuralnetworks } // namespace hardware } // namespace android diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTests.h b/neuralnetworks/1.0/vts/functional/GeneratedTests.h new file mode 100644 index 0000000000..11ee5e882a --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/GeneratedTests.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#include +#include + +#include "GeneratedTestHarness.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "VtsHalNeuralnetworks.h" + +namespace android::hardware::neuralnetworks::V1_0::vts::functional { + +std::vector createRequests(const std::vector<::test_helper::MixedTypedExample>& examples); + +} // namespace android::hardware::neuralnetworks::V1_0::vts::functional + +namespace android::hardware::neuralnetworks::V1_0::generated_tests { + +using namespace android::hardware::neuralnetworks::V1_0::vts::functional; + +using ::android::hardware::neuralnetworks::V1_0::Model; +using ::android::hardware::neuralnetworks::V1_0::Request; + +} // namespace android::hardware::neuralnetworks::V1_0::generated_tests diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestsV1_0.cpp deleted file mode 100644 index 32e9a7f4ce..0000000000 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestsV1_0.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test" - -#include -#include -#include - -#include "1.0/Callbacks.h" -#include "GeneratedTestHarness.h" -#include "MemoryUtils.h" -#include "TestHarness.h" -#include "VtsHalNeuralnetworks.h" - -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_0 { -namespace vts { -namespace functional { - -using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; -using ::android::hidl::memory::V1_0::IMemory; -using ::android::nn::allocateSharedMemory; -using ::test_helper::MixedTypedExample; - -std::vector createRequests(const std::vector& examples); - -// in frameworks/ml/nn/runtime/tests/generated/ -#include "vts/V1_0/all_generated_V1_0_vts_tests.cpp" - -} // namespace functional -} // namespace vts -} // namespace V1_0 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp index ee90ec6fe2..1b31008cbb 100644 --- a/neuralnetworks/1.1/vts/functional/Android.bp +++ b/neuralnetworks/1.1/vts/functional/Android.bp @@ -50,7 +50,7 @@ cc_test { name: "VtsHalNeuralnetworksV1_1CompatV1_0TargetTest", defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"], srcs: [ - "GeneratedTestsV1_0.cpp", + ":VtsHalNeuralNetworksV1_1_all_generated_V1_0_tests", ], } @@ -60,7 +60,7 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"], srcs: [ "BasicTests.cpp", - "GeneratedTestsV1_1.cpp", + ":VtsHalNeuralNetworksV1_1_all_generated_V1_1_tests", ], } @@ -69,7 +69,7 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"], srcs: [ "BasicTests.cpp", - "GeneratedTestsV1_1.cpp", + ":VtsHalNeuralNetworksV1_1_all_generated_V1_1_tests", ], cflags: [ "-DPRESUBMIT_NOT_VTS", diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp index d9f64fdb5b..e7d59eca91 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp @@ -34,6 +34,7 @@ namespace android { namespace hardware { namespace neuralnetworks { +namespace V1_1 { namespace generated_tests { using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; @@ -227,6 +228,7 @@ void Execute(const sp& device, std::function create_model, } } // namespace generated_tests +} // namespace V1_1 } // namespace neuralnetworks } // namespace hardware } // namespace android diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h index ab71b2b87a..64b88dd689 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h @@ -26,6 +26,7 @@ namespace android { namespace hardware { namespace neuralnetworks { +namespace V1_1 { namespace generated_tests { void Execute(const sp& device, std::function create_model, @@ -33,6 +34,7 @@ void Execute(const sp& device, std::function c const std::vector<::test_helper::MixedTypedExample>& examples); } // namespace generated_tests +} // namespace V1_1 } // namespace neuralnetworks } // namespace hardware } // namespace android diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTests.h b/neuralnetworks/1.1/vts/functional/GeneratedTests.h new file mode 100644 index 0000000000..2343a4f955 --- /dev/null +++ b/neuralnetworks/1.1/vts/functional/GeneratedTests.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#include +#include + +#include "GeneratedTestHarness.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "VtsHalNeuralnetworks.h" + +namespace android::hardware::neuralnetworks::V1_1::vts::functional { + +std::vector createRequests(const std::vector<::test_helper::MixedTypedExample>& examples); + +} // namespace android::hardware::neuralnetworks::V1_1::vts::functional + +namespace android::hardware::neuralnetworks::V1_1::generated_tests { + +using namespace android::hardware::neuralnetworks::V1_1::vts::functional; + +using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; +using ::android::hardware::neuralnetworks::V1_0::Request; +using ::android::hardware::neuralnetworks::V1_1::Model; + +} // namespace android::hardware::neuralnetworks::V1_1::generated_tests diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp deleted file mode 100644 index 23e6534231..0000000000 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test" - -#include -#include -#include - -#include "1.0/Callbacks.h" -#include "GeneratedTestHarness.h" -#include "MemoryUtils.h" -#include "TestHarness.h" -#include "VtsHalNeuralnetworks.h" - -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_1 { -namespace vts { -namespace functional { - -using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; -using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; -using ::android::hidl::memory::V1_0::IMemory; -using ::android::nn::allocateSharedMemory; -using ::test_helper::MixedTypedExample; - -std::vector createRequests(const std::vector& examples); - -// in frameworks/ml/nn/runtime/tests/generated/ -#include "vts/V1_1/all_generated_V1_0_vts_tests.cpp" - -} // namespace functional -} // namespace vts -} // namespace V1_1 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_1.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_1.cpp deleted file mode 100644 index 680b93aaee..0000000000 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_1.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test" - -#include -#include -#include - -#include "1.0/Callbacks.h" -#include "GeneratedTestHarness.h" -#include "MemoryUtils.h" -#include "TestHarness.h" -#include "VtsHalNeuralnetworks.h" - -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_1 { -namespace vts { -namespace functional { - -using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; -using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; -using ::android::hidl::memory::V1_0::IMemory; -using ::android::nn::allocateSharedMemory; -using ::test_helper::MixedTypedExample; - -std::vector createRequests(const std::vector& examples); - -// in frameworks/ml/nn/runtime/tests/generated/ -#include "vts/V1_1/all_generated_V1_1_vts_tests.cpp" - -} // namespace functional -} // namespace vts -} // namespace V1_1 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index 31b853242c..301ca5d065 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -53,7 +53,7 @@ cc_test { name: "VtsHalNeuralnetworksV1_2CompatV1_0TargetTest", defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ - "GeneratedTestsV1_0.cpp", + ":VtsHalNeuralNetworksV1_2_all_generated_V1_0_tests", "ValidateBurst.cpp", ], } @@ -63,7 +63,7 @@ cc_test { name: "VtsHalNeuralnetworksV1_2CompatV1_1TargetTest", defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ - "GeneratedTestsV1_1.cpp", + ":VtsHalNeuralNetworksV1_2_all_generated_V1_1_tests", "ValidateBurst.cpp", ], } @@ -74,8 +74,9 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ "BasicTests.cpp", + ":VtsHalNeuralNetworksV1_2_all_generated_V1_2_tests", "CompilationCachingTests.cpp", - "GeneratedTestsV1_2.cpp", + ":VtsHalNeuralNetworksV1_2_mobilenets", // CompilationCachingTests depend on MobileNets. "ValidateBurst.cpp", ], } @@ -85,7 +86,7 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ "BasicTests.cpp", - "GeneratedTestsV1_2.cpp", + ":VtsHalNeuralNetworksV1_2_all_generated_V1_2_tests", "ValidateBurst.cpp", ], cflags: [ diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp index 8711f479fe..082d7583a3 100644 --- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp @@ -35,6 +35,23 @@ #include "Utils.h" #include "VtsHalNeuralnetworks.h" +namespace android::hardware::neuralnetworks::V1_2::generated_tests:: + mobilenet_224_gender_basic_fixed { +Model createTestModel(); +} // namespace android::hardware::neuralnetworks::V1_2::generated_tests::mobilenet_224_gender_basic_fixed + +namespace generated_tests::mobilenet_224_gender_basic_fixed { +std::vector& get_examples(); +} // namespace generated_tests::mobilenet_224_gender_basic_fixed + +namespace android::hardware::neuralnetworks::V1_2::generated_tests::mobilenet_quantized { +Model createTestModel(); +} // namespace android::hardware::neuralnetworks::V1_2::generated_tests::mobilenet_quantized + +namespace generated_tests::mobilenet_quantized { +std::vector& get_examples(); +} // namespace generated_tests::mobilenet_quantized + namespace android { namespace hardware { namespace neuralnetworks { @@ -52,13 +69,9 @@ using ::test_helper::MixedTypedExample; namespace float32_model { -// In frameworks/ml/nn/runtime/test/generated/, creates a hidl model of float32 mobilenet. -#include "examples/mobilenet_224_gender_basic_fixed.example.cpp" -#include "vts/V1_2/models/mobilenet_224_gender_basic_fixed.model.cpp" - -// Prevent the compiler from complaining about an otherwise unused function. -[[maybe_unused]] auto dummy_createTestModel = createTestModel_dynamic_output_shape; -[[maybe_unused]] auto dummy_get_examples = get_examples_dynamic_output_shape; +constexpr auto createTestModel = ::android::hardware::neuralnetworks::V1_2::generated_tests:: + mobilenet_224_gender_basic_fixed::createTestModel; +constexpr auto get_examples = ::generated_tests::mobilenet_224_gender_basic_fixed::get_examples; // MixedTypedExample is defined in frameworks/ml/nn/tools/test_generator/include/TestHarness.h. // This function assumes the operation is always ADD. @@ -75,13 +88,9 @@ std::vector getLargeModelExamples(uint32_t len) { namespace quant8_model { -// In frameworks/ml/nn/runtime/test/generated/, creates a hidl model of quant8 mobilenet. -#include "examples/mobilenet_quantized.example.cpp" -#include "vts/V1_2/models/mobilenet_quantized.model.cpp" - -// Prevent the compiler from complaining about an otherwise unused function. -[[maybe_unused]] auto dummy_createTestModel = createTestModel_dynamic_output_shape; -[[maybe_unused]] auto dummy_get_examples = get_examples_dynamic_output_shape; +constexpr auto createTestModel = ::android::hardware::neuralnetworks::V1_2::generated_tests:: + mobilenet_quantized::createTestModel; +constexpr auto get_examples = ::generated_tests::mobilenet_quantized::get_examples; // MixedTypedExample is defined in frameworks/ml/nn/tools/test_generator/include/TestHarness.h. // This function assumes the operation is always ADD. diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp index 495f3ecdb6..82cc73db95 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp @@ -43,6 +43,7 @@ namespace android { namespace hardware { namespace neuralnetworks { +namespace V1_2 { namespace generated_tests { using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; @@ -451,6 +452,7 @@ void Execute(const sp& device, std::function create_model, } } // namespace generated_tests +} // namespace V1_2 } // namespace neuralnetworks } // namespace hardware } // namespace android diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h index 30e5578b66..0ecbe7e76a 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h @@ -27,6 +27,7 @@ namespace android { namespace hardware { namespace neuralnetworks { +namespace V1_2 { namespace generated_tests { using ::test_helper::MixedTypedExample; @@ -44,6 +45,7 @@ void Execute(const sp& device, std::function c bool testDynamicOutputShape = false); } // namespace generated_tests +} // namespace V1_2 } // namespace neuralnetworks } // namespace hardware } // namespace android diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTests.h b/neuralnetworks/1.2/vts/functional/GeneratedTests.h new file mode 100644 index 0000000000..f393eb2499 --- /dev/null +++ b/neuralnetworks/1.2/vts/functional/GeneratedTests.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#include +#include + +#include "GeneratedTestHarness.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "Utils.h" +#include "VtsHalNeuralnetworks.h" + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +std::vector createRequests(const std::vector<::test_helper::MixedTypedExample>& examples); + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional + +namespace android::hardware::neuralnetworks::V1_2::generated_tests { + +using namespace ::android::hardware::neuralnetworks::V1_2::vts::functional; + +using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; +using ::android::hardware::neuralnetworks::V1_0::Request; +using ::android::hardware::neuralnetworks::V1_2::Model; + +} // namespace android::hardware::neuralnetworks::V1_2::generated_tests diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp deleted file mode 100644 index 6fbd1dc6a2..0000000000 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test" - -#include -#include -#include - -#include "1.2/Callbacks.h" -#include "GeneratedTestHarness.h" -#include "MemoryUtils.h" -#include "TestHarness.h" -#include "Utils.h" -#include "VtsHalNeuralnetworks.h" - -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_2 { -namespace vts { -namespace functional { - -using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; -using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; -using ::android::hidl::memory::V1_0::IMemory; -using ::android::nn::allocateSharedMemory; -using ::test_helper::MixedTypedExample; - -std::vector createRequests(const std::vector& examples); - -// in frameworks/ml/nn/runtime/tests/generated/ -#include "vts/V1_2/all_generated_V1_0_vts_tests.cpp" - -} // namespace functional -} // namespace vts -} // namespace V1_2 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp deleted file mode 100644 index d824e4348c..0000000000 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test" - -#include -#include -#include - -#include "1.2/Callbacks.h" -#include "GeneratedTestHarness.h" -#include "MemoryUtils.h" -#include "TestHarness.h" -#include "Utils.h" -#include "VtsHalNeuralnetworks.h" - -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_2 { -namespace vts { -namespace functional { - -using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; -using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; -using ::android::hidl::memory::V1_0::IMemory; -using ::android::nn::allocateSharedMemory; -using ::test_helper::MixedTypedExample; - -std::vector createRequests(const std::vector& examples); - -// in frameworks/ml/nn/runtime/tests/generated/ -#include "vts/V1_2/all_generated_V1_1_vts_tests.cpp" - -} // namespace functional -} // namespace vts -} // namespace V1_2 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp deleted file mode 100644 index 6e03534394..0000000000 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test" - -#include -#include -#include - -#include "1.2/Callbacks.h" -#include "GeneratedTestHarness.h" -#include "MemoryUtils.h" -#include "TestHarness.h" -#include "Utils.h" -#include "VtsHalNeuralnetworks.h" - -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_2 { -namespace vts { -namespace functional { - -using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; -using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; -using ::android::hidl::memory::V1_0::IMemory; -using ::android::nn::allocateSharedMemory; -using ::test_helper::MixedTypedExample; - -std::vector createRequests(const std::vector& examples); - -// in frameworks/ml/nn/runtime/tests/generated/ -#include "vts/V1_2/all_generated_V1_2_vts_tests.cpp" - -} // namespace functional -} // namespace vts -} // namespace V1_2 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android From 6534164fd642d1670512c10fe1cd3eab69429983 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 20 Jun 2019 13:21:06 -0700 Subject: [PATCH 0040/1022] graphics: rev IAllocator/IMapper to 4.0 Rev the IAllocator/IMapper HIDL interfaces to 4.0. This patch is a copy paste from IAllocator/IMapper 3.0. Bug: 136016160 Test: Compiles and boots Change-Id: Ia7f159f97fe0f812b5f0e10a850715364090883c --- .../compatibility_matrix.current.xml | 4 +- graphics/allocator/4.0/Android.bp | 20 + graphics/allocator/4.0/IAllocator.hal | 55 ++ graphics/mapper/4.0/Android.bp | 21 + graphics/mapper/4.0/IMapper.hal | 304 +++++++++++ graphics/mapper/4.0/types.hal | 84 +++ graphics/mapper/4.0/utils/OWNERS | 3 + graphics/mapper/4.0/utils/vts/Android.bp | 34 ++ graphics/mapper/4.0/utils/vts/MapperVts.cpp | 304 +++++++++++ .../vts/include/mapper-vts/4.0/MapperVts.h | 105 ++++ graphics/mapper/4.0/vts/OWNERS | 3 + graphics/mapper/4.0/vts/functional/Android.bp | 30 ++ .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 494 ++++++++++++++++++ 13 files changed, 1459 insertions(+), 2 deletions(-) create mode 100644 graphics/allocator/4.0/Android.bp create mode 100644 graphics/allocator/4.0/IAllocator.hal create mode 100644 graphics/mapper/4.0/Android.bp create mode 100644 graphics/mapper/4.0/IMapper.hal create mode 100644 graphics/mapper/4.0/types.hal create mode 100644 graphics/mapper/4.0/utils/OWNERS create mode 100644 graphics/mapper/4.0/utils/vts/Android.bp create mode 100644 graphics/mapper/4.0/utils/vts/MapperVts.cpp create mode 100644 graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h create mode 100644 graphics/mapper/4.0/vts/OWNERS create mode 100644 graphics/mapper/4.0/vts/functional/Android.bp create mode 100644 graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 6e1bc8fa78..3e83cdca80 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -195,8 +195,8 @@ android.hardware.graphics.allocator - 2.0 3.0 + 4.0 IAllocator default @@ -212,8 +212,8 @@ android.hardware.graphics.mapper - 2.1 3.0 + 4.0 IMapper default diff --git a/graphics/allocator/4.0/Android.bp b/graphics/allocator/4.0/Android.bp new file mode 100644 index 0000000000..f5f94585a7 --- /dev/null +++ b/graphics/allocator/4.0/Android.bp @@ -0,0 +1,20 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.graphics.allocator@4.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "IAllocator.hal", + ], + interfaces: [ + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + "android.hardware.graphics.mapper@4.0", + "android.hidl.base@1.0", + ], + gen_java: false, +} diff --git a/graphics/allocator/4.0/IAllocator.hal b/graphics/allocator/4.0/IAllocator.hal new file mode 100644 index 0000000000..9931685abc --- /dev/null +++ b/graphics/allocator/4.0/IAllocator.hal @@ -0,0 +1,55 @@ +/* + * Copyright 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. + */ + +package android.hardware.graphics.allocator@4.0; + +import android.hardware.graphics.mapper@4.0; + +interface IAllocator { + /** + * Retrieves implementation-defined debug information, which will be + * displayed during, for example, `dumpsys SurfaceFlinger`. + * + * @return debugInfo is a string of debug information. + */ + dumpDebugInfo() generates (string debugInfo); + + /** + * Allocates buffers with the properties specified by the descriptor. + * + * Allocations should be optimized for usage bits provided in the + * descriptor. + * + * @param descriptor Properties of the buffers to allocate. This must be + * obtained from IMapper::createDescriptor(). + * @param count The number of buffers to allocate. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_DESCRIPTOR` if the descriptor is invalid. + * - `NO_RESOURCES` if the allocation cannot be fulfilled at this time. + * - `UNSUPPORTED` if any of the properties encoded in the descriptor + * are not supported. + * @return stride The number of pixels between two consecutive rows of + * an allocated buffer, when the concept of consecutive rows is defined. + * Otherwise, it has no meaning. + * @return buffers Array of raw handles to the allocated buffers. + */ + allocate(BufferDescriptor descriptor, uint32_t count) + generates (Error error, + uint32_t stride, + vec buffers); +}; + diff --git a/graphics/mapper/4.0/Android.bp b/graphics/mapper/4.0/Android.bp new file mode 100644 index 0000000000..42c4942e85 --- /dev/null +++ b/graphics/mapper/4.0/Android.bp @@ -0,0 +1,21 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.graphics.mapper@4.0", + root: "android.hardware", + vndk: { + enabled: true, + support_system_process: true, + }, + srcs: [ + "types.hal", + "IMapper.hal", + ], + interfaces: [ + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + "android.hidl.base@1.0", + ], + gen_java: false, +} diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal new file mode 100644 index 0000000000..f5df04b853 --- /dev/null +++ b/graphics/mapper/4.0/IMapper.hal @@ -0,0 +1,304 @@ +/* + * Copyright 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. + */ + +package android.hardware.graphics.mapper@4.0; + +import android.hardware.graphics.common@1.2::BufferUsage; +import android.hardware.graphics.common@1.2::PixelFormat; +import android.hardware.graphics.common@1.2::Rect; + +interface IMapper { + struct BufferDescriptorInfo { + /** + * The width specifies how many columns of pixels must be in the + * allocated buffer, but does not necessarily represent the offset in + * columns between the same column in adjacent rows. The rows may be + * padded. + */ + uint32_t width; + + /** + * The height specifies how many rows of pixels must be in the + * allocated buffer. + */ + uint32_t height; + + /** + * The number of image layers that must be in the allocated buffer. + */ + uint32_t layerCount; + + /** Buffer pixel format. */ + PixelFormat format; + + /** + * Buffer usage mask; valid flags can be found in the definition of + * BufferUsage. + */ + bitfield usage; + }; + + struct Rect { + int32_t left; + int32_t top; + int32_t width; + int32_t height; + }; + + /** + * Creates a buffer descriptor. The descriptor can be used with IAllocator + * to allocate buffers. + * + * Since the buffer descriptor fully describes a buffer, any device + * dependent or device independent checks must be performed here whenever + * possible. Specifically, when layered buffers are not supported, this + * function must return `UNSUPPORTED` if `description.layers` is great than + * 1. + * + * @param description Attributes of the descriptor. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_VALUE` if any of the specified attributes are invalid or + * inconsistent. + * - `NO_RESOURCES` if the creation cannot be fullfilled due to + * unavailability of resources. + * - `UNSUPPORTED` when any of the specified attributes are not + * supported. + * @return descriptor Newly created buffer descriptor. + */ + createDescriptor(BufferDescriptorInfo description) + generates (Error error, + BufferDescriptor descriptor); + + /** + * Imports a raw buffer handle to create an imported buffer handle for use + * with the rest of the mapper or with other in-process libraries. + * + * A buffer handle is considered raw when it is cloned (e.g., with + * `native_handle_clone()`) from another buffer handle locally, or when it + * is received from another HAL server/client or another process. A raw + * buffer handle must not be used to access the underlying graphic + * buffer. It must be imported to create an imported handle first. + * + * This function must at least validate the raw handle before creating the + * imported handle. It must also support importing the same raw handle + * multiple times to create multiple imported handles. The imported handle + * must be considered valid everywhere in the process, including in + * another instance of the mapper. + * + * Because of passthrough HALs, a raw buffer handle received from a HAL + * may actually have been imported in the process. importBuffer() must treat + * such a handle as if it is raw and must not return `BAD_BUFFER`. The + * returned handle is independent from the input handle as usual, and + * freeBuffer() must be called on it when it is no longer needed. + * + * @param rawHandle Raw buffer handle to import. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the raw handle is invalid. + * - `NO_RESOURCES` if the raw handle cannot be imported due to + * unavailability of resources. + * @return buffer Imported buffer handle that has the type + * `buffer_handle_t` which is a handle type. + */ + importBuffer(handle rawHandle) generates (Error error, pointer buffer); + + /** + * Frees a buffer handle. Buffer handles returned by importBuffer() must be + * freed with this function when no longer needed. + * + * This function must free up all resources allocated by importBuffer() for + * the imported handle. For example, if the imported handle was created + * with `native_handle_create()`, this function must call + * `native_handle_close()` and `native_handle_delete()`. + * + * @param buffer Imported buffer handle. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the buffer is invalid. + */ + freeBuffer(pointer buffer) generates (Error error); + + /** + * Validates that the buffer can be safely accessed by a caller who assumes + * the specified @p description and @p stride. This must at least validate + * that the buffer size is large enough. Validating the buffer against + * individual buffer attributes is optional. + * + * @param buffer Buffer to validate against. + * @param description Attributes of the buffer. + * @param stride Stride returned by IAllocator::allocate(). + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the buffer is invalid. + * - `BAD_VALUE` if the buffer cannot be safely accessed. + */ + validateBufferSize(pointer buffer, + BufferDescriptorInfo description, + uint32_t stride) + generates (Error error); + + /** + * Calculates the transport size of a buffer. An imported buffer handle is a + * raw buffer handle with the process-local runtime data appended. This + * function, for example, allows a caller to omit the process-local runtime + * data at the tail when serializing the imported buffer handle. + * + * Note that a client might or might not omit the process-local runtime data + * when sending an imported buffer handle. The mapper must support both + * cases on the receiving end. + * + * @param buffer Buffer to get the transport size from. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the buffer is invalid. + * @return numFds The number of file descriptors needed for transport. + * @return numInts The number of integers needed for transport. + */ + getTransportSize(pointer buffer) + generates (Error error, + uint32_t numFds, + uint32_t numInts); + + /** + * Locks the given buffer for the specified CPU usage. + * + * Locking the same buffer simultaneously from multiple threads is + * permitted, but if any of the threads attempt to lock the buffer for + * writing, the behavior is undefined, except that it must not cause + * process termination or block the client indefinitely. Leaving the + * buffer content in an indeterminate state or returning an error are both + * acceptable. + * + * 1D buffers (width = size in bytes, height = 1, pixel_format = BLOB) must + * "lock in place". The buffers must be directly accessible via mapping. + * + * The client must not modify the content of the buffer outside of + * @p accessRegion, and the device need not guarantee that content outside + * of @p accessRegion is valid for reading. The result of reading or writing + * outside of @p accessRegion is undefined, except that it must not cause + * process termination. + * + * On success, @p data must be filled with a pointer to the locked buffer + * memory. This address will represent the top-left corner of the entire + * buffer, even if @p accessRegion does not begin at the top-left corner. + * + * On success, bytesPerPixel must contain the number of bytes per pixel in + * the buffer. If the bytesPerPixel is unknown or variable, a value of -1 + * should be returned. bytesPerStride must contain the bytes per stride of + * the buffer. If the bytesPerStride is unknown or variable, a value of -1 + * should be returned. + * + * @param buffer Buffer to lock. + * @param cpuUsage CPU usage flags to request. See +ndk + * libnativewindow#AHardwareBuffer_UsageFlags for possible values. + * @param accessRegion Portion of the buffer that the client intends to + * access. + * @param acquireFence Handle containing a file descriptor referring to a + * sync fence object, which will be signaled when it is safe for the + * mapper to lock the buffer. @p acquireFence may be an empty fence if + * it is already safe to lock. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the buffer is invalid or is incompatible with this + * function. + * - `BAD_VALUE` if @p cpuUsage is 0, contains non-CPU usage flags, or + * is incompatible with the buffer. + * - `NO_RESOURCES` if the buffer cannot be locked at this time. Note + * that locking may succeed at a later time. + * @return data CPU-accessible pointer to the buffer data. + * @return bytesPerPixel the number of bytes per pixel in the buffer + * @return bytesPerStride the number of bytes per stride of the buffer + */ + lock(pointer buffer, + uint64_t cpuUsage, + Rect accessRegion, + handle acquireFence) + generates (Error error, + pointer data, + int32_t bytesPerPixel, + int32_t bytesPerStride); + + /** + * Locks a YCbCr buffer for the specified CPU usage. + * + * This is largely the same as lock(), except that instead of returning a + * pointer directly to the buffer data, it returns a `YCbCrLayout` struct + * describing how to access the data planes. + * + * This function must work on buffers with + * `AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_*` if supported by the device, as well + * as with any other formats requested by multimedia codecs when they are + * configured with a flexible-YUV-compatible color format. + * + * @param buffer Buffer to lock. + * @param cpuUsage CPU usage flags to request. See +ndk + * libnativewindow#AHardwareBuffer_UsageFlags for possible values. + * @param accessRegion Portion of the buffer that the client intends to + * access. + * @param acquireFence Handle containing a file descriptor referring to a + * sync fence object, which will be signaled when it is safe for the + * mapper to lock the buffer. @p acquireFence may be empty if it is + * already safe to lock. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the buffer is invalid or is incompatible with this + * function. + * - `BAD_VALUE` if @p cpuUsage is 0, contains non-CPU usage flags, or + * is incompatible with the buffer. + * - `NO_RESOURCES` if the buffer cannot be locked at this time. Note + * that locking may succeed at a later time. + * @return layout Data layout of the locked buffer. + */ + lockYCbCr(pointer buffer, + uint64_t cpuUsage, + Rect accessRegion, + handle acquireFence) + generates (Error error, + YCbCrLayout layout); + + /** + * Unlocks a buffer to indicate all CPU accesses to the buffer have + * completed. + * + * @param buffer Buffer to unlock. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the buffer is invalid or not locked. + * @return releaseFence Handle containing a file descriptor referring to a + * sync fence object. The sync fence object will be signaled when the + * mapper has completed any pending work. @p releaseFence may be an + * empty fence. + */ + unlock(pointer buffer) generates (Error error, handle releaseFence); + + /** + * Test whether the given BufferDescriptorInfo is allocatable. + * + * If this function returns true, it means that a buffer with the given + * description can be allocated on this implementation, unless resource + * exhaustion occurs. If this function returns false, it means that the + * allocation of the given description will never succeed. + * + * @param description the description of the buffer + * @return supported whether the description is supported + */ + isSupported(BufferDescriptorInfo description) + generates (Error error, + bool supported); + +}; + diff --git a/graphics/mapper/4.0/types.hal b/graphics/mapper/4.0/types.hal new file mode 100644 index 0000000000..603b243db6 --- /dev/null +++ b/graphics/mapper/4.0/types.hal @@ -0,0 +1,84 @@ +/* + * Copyright 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. + */ + +package android.hardware.graphics.mapper@4.0; + +/** + * Error values that may be returned by a method of IAllocator or IMapper. + */ +enum Error : int32_t { + /** + * No error. + */ + NONE = 0, + /** + * Invalid BufferDescriptor. + */ + BAD_DESCRIPTOR = 1, + /** + * Invalid buffer handle. + */ + BAD_BUFFER = 2, + /** + * Invalid HardwareBufferDescription. + */ + BAD_VALUE = 3, + /** + * Resource unavailable. + */ + NO_RESOURCES = 5, + /** + * Permanent failure. + */ + UNSUPPORTED = 7, +}; + +/** + * A buffer descriptor is an implementation-defined opaque data returned by + * createDescriptor(). It describes the properties of a buffer and is consumed + * by the allocator. + */ +typedef vec BufferDescriptor; + +/** + * Structure for describing YCbCr formats for consumption by applications. + * This is used with PixelFormat::YCBCR_*_888. + * + * Buffer chroma subsampling is defined in the format. + * e.g. PixelFormat::YCBCR_420_888 has subsampling 4:2:0. + * + * Buffers must have a 8 bit depth. + * + * y, cb, and cr point to the first byte of their respective planes. + * + * Stride describes the distance in bytes from the first value of one row of + * the image to the first value of the next row. It includes the width of the + * image plus padding. + * yStride is the stride of the luma plane. + * cStride is the stride of the chroma planes. + * + * chromaStep is the distance in bytes from one chroma pixel value to the + * next. This is 2 bytes for semiplanar (because chroma values are interleaved + * and each chroma value is one byte) and 1 for planar. + */ +struct YCbCrLayout { + pointer y; + pointer cb; + pointer cr; + uint32_t yStride; + uint32_t cStride; + uint32_t chromaStep; +}; diff --git a/graphics/mapper/4.0/utils/OWNERS b/graphics/mapper/4.0/utils/OWNERS new file mode 100644 index 0000000000..96f6d51573 --- /dev/null +++ b/graphics/mapper/4.0/utils/OWNERS @@ -0,0 +1,3 @@ +# Graphics team +marissaw@google.com +stoza@google.com diff --git a/graphics/mapper/4.0/utils/vts/Android.bp b/graphics/mapper/4.0/utils/vts/Android.bp new file mode 100644 index 0000000000..e451584958 --- /dev/null +++ b/graphics/mapper/4.0/utils/vts/Android.bp @@ -0,0 +1,34 @@ +// +// 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. +// + +cc_library_static { + name: "android.hardware.graphics.mapper@4.0-vts", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["MapperVts.cpp"], + cflags: [ + "-O0", + "-g", + ], + static_libs: [ + "android.hardware.graphics.allocator@4.0", + "android.hardware.graphics.mapper@4.0", + ], + export_static_lib_headers: [ + "android.hardware.graphics.allocator@4.0", + "android.hardware.graphics.mapper@4.0", + ], + export_include_dirs: ["include"], +} diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp new file mode 100644 index 0000000000..056b7c9da4 --- /dev/null +++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp @@ -0,0 +1,304 @@ +/* + * Copyright 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. + */ + +#include + +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace mapper { +namespace V4_0 { +namespace vts { + +Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName, + bool errOnFailure) { + if (errOnFailure) { + init(allocatorServiceName, mapperServiceName); + } else { + initNoErr(allocatorServiceName, mapperServiceName); + } +} + +void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) { + mAllocator = ::testing::VtsHalHidlTargetTestBase::getService(allocatorServiceName); + ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service"; + + mMapper = ::testing::VtsHalHidlTargetTestBase::getService(mapperServiceName); + ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service"; + ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode"; +} + +void Gralloc::initNoErr(const std::string& allocatorServiceName, + const std::string& mapperServiceName) { + mAllocator = ::testing::VtsHalHidlTargetTestBase::getService(allocatorServiceName); + + mMapper = ::testing::VtsHalHidlTargetTestBase::getService(mapperServiceName); + if (mMapper.get()) { + ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode"; + } +} + +Gralloc::~Gralloc() { + for (auto bufferHandle : mClonedBuffers) { + auto buffer = const_cast(bufferHandle); + native_handle_close(buffer); + native_handle_delete(buffer); + } + mClonedBuffers.clear(); + + for (auto bufferHandle : mImportedBuffers) { + auto buffer = const_cast(bufferHandle); + EXPECT_EQ(Error::NONE, mMapper->freeBuffer(buffer)) << "failed to free buffer " << buffer; + } + mImportedBuffers.clear(); +} + +sp Gralloc::getAllocator() const { + return mAllocator; +} + +std::string Gralloc::dumpDebugInfo() { + std::string debugInfo; + mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); }); + + return debugInfo; +} + +const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle) { + const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle()); + EXPECT_NE(nullptr, bufferHandle); + + if (bufferHandle) { + mClonedBuffers.insert(bufferHandle); + } + + return bufferHandle; +} + +std::vector Gralloc::allocate(const BufferDescriptor& descriptor, + uint32_t count, bool import, + uint32_t* outStride) { + std::vector bufferHandles; + bufferHandles.reserve(count); + mAllocator->allocate(descriptor, count, + [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers"; + ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array"; + + for (uint32_t i = 0; i < count; i++) { + if (import) { + ASSERT_NO_FATAL_FAILURE( + bufferHandles.push_back(importBuffer(tmpBuffers[i]))); + } else { + ASSERT_NO_FATAL_FAILURE( + bufferHandles.push_back(cloneBuffer(tmpBuffers[i]))); + } + } + + if (outStride) { + *outStride = tmpStride; + } + }); + + if (::testing::Test::HasFatalFailure()) { + bufferHandles.clear(); + } + + return bufferHandles; +} + +const native_handle_t* Gralloc::allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, + bool import, uint32_t* outStride) { + BufferDescriptor descriptor = createDescriptor(descriptorInfo); + if (::testing::Test::HasFatalFailure()) { + return nullptr; + } + + auto buffers = allocate(descriptor, 1, import, outStride); + if (::testing::Test::HasFatalFailure()) { + return nullptr; + } + + return buffers[0]; +} + +sp Gralloc::getMapper() const { + return mMapper; +} + +BufferDescriptor Gralloc::createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo) { + BufferDescriptor descriptor; + mMapper->createDescriptor(descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor"; + descriptor = tmpDescriptor; + }); + + return descriptor; +} + +const native_handle_t* Gralloc::importBuffer(const hidl_handle& rawHandle) { + const native_handle_t* bufferHandle = nullptr; + mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) { + ASSERT_EQ(Error::NONE, tmpError) + << "failed to import buffer %p" << rawHandle.getNativeHandle(); + bufferHandle = static_cast(tmpBuffer); + }); + + if (bufferHandle) { + mImportedBuffers.insert(bufferHandle); + } + + return bufferHandle; +} + +void Gralloc::freeBuffer(const native_handle_t* bufferHandle) { + auto buffer = const_cast(bufferHandle); + + if (mImportedBuffers.erase(bufferHandle)) { + Error error = mMapper->freeBuffer(buffer); + ASSERT_EQ(Error::NONE, error) << "failed to free buffer " << buffer; + } else { + mClonedBuffers.erase(bufferHandle); + native_handle_close(buffer); + native_handle_delete(buffer); + } +} + +void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, + const IMapper::Rect& accessRegion, int acquireFence, int32_t* outBytesPerPixel, + int32_t* outBytesPerStride) { + auto buffer = const_cast(bufferHandle); + + NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0); + hidl_handle acquireFenceHandle; + if (acquireFence >= 0) { + auto h = native_handle_init(acquireFenceStorage, 1, 0); + h->data[0] = acquireFence; + acquireFenceHandle = h; + } + + *outBytesPerPixel = -1; + *outBytesPerStride = -1; + + void* data = nullptr; + mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle, + [&](const auto& tmpError, const auto& tmpData, int32_t tmpBytesPerPixel, + int32_t tmpBytesPerStride) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to lock buffer " << buffer; + data = tmpData; + *outBytesPerPixel = tmpBytesPerPixel; + *outBytesPerStride = tmpBytesPerStride; + }); + + if (acquireFence >= 0) { + close(acquireFence); + } + + return data; +} + +YCbCrLayout Gralloc::lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage, + const IMapper::Rect& accessRegion, int acquireFence) { + auto buffer = const_cast(bufferHandle); + + NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0); + hidl_handle acquireFenceHandle; + if (acquireFence >= 0) { + auto h = native_handle_init(acquireFenceStorage, 1, 0); + h->data[0] = acquireFence; + acquireFenceHandle = h; + } + + YCbCrLayout layout = {}; + mMapper->lockYCbCr(buffer, cpuUsage, accessRegion, acquireFenceHandle, + [&](const auto& tmpError, const auto& tmpLayout) { + ASSERT_EQ(Error::NONE, tmpError) + << "failed to lockYCbCr buffer " << buffer; + layout = tmpLayout; + }); + + if (acquireFence >= 0) { + close(acquireFence); + } + + return layout; +} + +int Gralloc::unlock(const native_handle_t* bufferHandle) { + auto buffer = const_cast(bufferHandle); + + int releaseFence = -1; + mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to unlock buffer " << buffer; + + auto fenceHandle = tmpReleaseFence.getNativeHandle(); + if (fenceHandle) { + ASSERT_EQ(0, fenceHandle->numInts) << "invalid fence handle " << fenceHandle; + if (fenceHandle->numFds == 1) { + releaseFence = dup(fenceHandle->data[0]); + ASSERT_LT(0, releaseFence) << "failed to dup fence fd"; + } else { + ASSERT_EQ(0, fenceHandle->numFds) << " invalid fence handle " << fenceHandle; + } + } + }); + + return releaseFence; +} + +bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle, + const IMapper::BufferDescriptorInfo& descriptorInfo, + uint32_t stride) { + auto buffer = const_cast(bufferHandle); + + Error error = mMapper->validateBufferSize(buffer, descriptorInfo, stride); + return error == Error::NONE; +} + +void Gralloc::getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds, + uint32_t* outNumInts) { + auto buffer = const_cast(bufferHandle); + + *outNumFds = 0; + *outNumInts = 0; + mMapper->getTransportSize(buffer, [&](const auto& tmpError, const auto& tmpNumFds, + const auto& tmpNumInts) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to get transport size"; + ASSERT_GE(bufferHandle->numFds, int(tmpNumFds)) << "invalid numFds " << tmpNumFds; + ASSERT_GE(bufferHandle->numInts, int(tmpNumInts)) << "invalid numInts " << tmpNumInts; + + *outNumFds = tmpNumFds; + *outNumInts = tmpNumInts; + }); +} + +bool Gralloc::isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo) { + bool supported = false; + mMapper->isSupported(descriptorInfo, [&](const auto& tmpError, const auto& tmpSupported) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to check is supported"; + supported = tmpSupported; + }); + return supported; +} + +} // namespace vts +} // namespace V4_0 +} // namespace mapper +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h new file mode 100644 index 0000000000..03ce764d8b --- /dev/null +++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h @@ -0,0 +1,105 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace mapper { +namespace V4_0 { +namespace vts { + +using android::hardware::graphics::allocator::V4_0::IAllocator; + +// A wrapper to IAllocator and IMapper. +class Gralloc { + public: + Gralloc(const std::string& allocatorServiceName = "default", + const std::string& mapperServiceName = "default", bool errOnFailure = true); + ~Gralloc(); + + // IAllocator methods + + sp getAllocator() const; + + std::string dumpDebugInfo(); + + // When import is false, this simply calls IAllocator::allocate. When import + // is true, the returned buffers are also imported into the mapper. + // + // Either case, the returned buffers must be freed with freeBuffer. + std::vector allocate(const BufferDescriptor& descriptor, uint32_t count, + bool import = true, uint32_t* outStride = nullptr); + const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, + bool import = true, uint32_t* outStride = nullptr); + + // IMapper methods + + sp getMapper() const; + + BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo); + + const native_handle_t* importBuffer(const hidl_handle& rawHandle); + void freeBuffer(const native_handle_t* bufferHandle); + + // We use fd instead of hidl_handle in these functions to pass fences + // in and out of the mapper. The ownership of the fd is always transferred + // with each of these functions. + void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, + const IMapper::Rect& accessRegion, int acquireFence, int32_t* outBytesPerPixel, + int32_t* outBytesPerStride); + YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage, + const IMapper::Rect& accessRegion, int acquireFence); + int unlock(const native_handle_t* bufferHandle); + + bool validateBufferSize(const native_handle_t* bufferHandle, + const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride); + void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds, + uint32_t* outNumInts); + + bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo); + + private: + void init(const std::string& allocatorServiceName, const std::string& mapperServiceName); + + // initialize without checking for failure to get service + void initNoErr(const std::string& allocatorServiceName, const std::string& mapperServiceName); + const native_handle_t* cloneBuffer(const hidl_handle& rawHandle); + + sp mAllocator; + sp mMapper; + + // Keep track of all cloned and imported handles. When a test fails with + // ASSERT_*, the destructor will free the handles for the test. + std::unordered_set mClonedBuffers; + std::unordered_set mImportedBuffers; +}; + +} // namespace vts +} // namespace V4_0 +} // namespace mapper +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/mapper/4.0/vts/OWNERS b/graphics/mapper/4.0/vts/OWNERS new file mode 100644 index 0000000000..96f6d51573 --- /dev/null +++ b/graphics/mapper/4.0/vts/OWNERS @@ -0,0 +1,3 @@ +# Graphics team +marissaw@google.com +stoza@google.com diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp new file mode 100644 index 0000000000..a90ee0ca1c --- /dev/null +++ b/graphics/mapper/4.0/vts/functional/Android.bp @@ -0,0 +1,30 @@ +// +// Copyright 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. +// + +cc_test { + name: "VtsHalGraphicsMapperV4_0TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"], + static_libs: [ + "android.hardware.graphics.allocator@4.0", + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + "android.hardware.graphics.mapper@4.0", + "android.hardware.graphics.mapper@4.0-vts", + ], + test_suites: ["general-tests"], +} diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp new file mode 100644 index 0000000000..706c658f69 --- /dev/null +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -0,0 +1,494 @@ +/* + * Copyright 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 "VtsHalGraphicsMapperV4_0TargetTest" + +#include +#include +#include + +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace mapper { +namespace V4_0 { +namespace vts { +namespace { + +using android::hardware::graphics::common::V1_2::BufferUsage; +using android::hardware::graphics::common::V1_2::PixelFormat; + +// Test environment for graphics.mapper. +class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static GraphicsMapperHidlEnvironment* Instance() { + static GraphicsMapperHidlEnvironment* instance = new GraphicsMapperHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { + registerTestService(); + registerTestService(); + } +}; + +class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase { + protected: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE( + mGralloc = std::make_unique( + GraphicsMapperHidlEnvironment::Instance()->getServiceName(), + GraphicsMapperHidlEnvironment::Instance()->getServiceName())); + + mDummyDescriptorInfo.width = 64; + mDummyDescriptorInfo.height = 64; + mDummyDescriptorInfo.layerCount = 1; + mDummyDescriptorInfo.format = PixelFormat::RGBA_8888; + mDummyDescriptorInfo.usage = + static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); + } + + void TearDown() override {} + + std::unique_ptr mGralloc; + IMapper::BufferDescriptorInfo mDummyDescriptorInfo{}; +}; + +/** + * Test IAllocator::dumpDebugInfo by calling it. + */ +TEST_F(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) { + mGralloc->dumpDebugInfo(); +} + +/** + * Test IAllocator::allocate with valid buffer descriptors. + */ +TEST_F(GraphicsMapperHidlTest, AllocatorAllocate) { + BufferDescriptor descriptor; + ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo)); + + for (uint32_t count = 0; count < 5; count++) { + std::vector bufferHandles; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(bufferHandles = + mGralloc->allocate(descriptor, count, false, &stride)); + + if (count >= 1) { + EXPECT_LE(mDummyDescriptorInfo.width, stride) << "invalid buffer stride"; + } + + for (auto bufferHandle : bufferHandles) { + mGralloc->freeBuffer(bufferHandle); + } + } +} + +/** + * Test IAllocator::allocate with invalid buffer descriptors. + */ +TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNegative) { + // this assumes any valid descriptor is non-empty + BufferDescriptor descriptor; + mGralloc->getAllocator()->allocate(descriptor, 1, + [&](const auto& tmpError, const auto&, const auto&) { + EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError); + }); +} + +/** + * Test IAllocator::allocate does not leak. + */ +TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) { + auto info = mDummyDescriptorInfo; + info.width = 1024; + info.height = 1024; + + for (int i = 0; i < 2048; i++) { + auto bufferHandle = mGralloc->allocate(info, false); + mGralloc->freeBuffer(bufferHandle); + } +} + +/** + * Test that IAllocator::allocate is thread-safe. + */ +TEST_F(GraphicsMapperHidlTest, AllocatorAllocateThreaded) { + BufferDescriptor descriptor; + ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo)); + + std::atomic timeUp(false); + std::atomic allocationCount(0); + auto threadLoop = [&]() { + while (!timeUp) { + mGralloc->getAllocator()->allocate( + descriptor, 1, + [&](const auto&, const auto&, const auto&) { allocationCount++; }); + } + }; + + std::vector threads; + for (int i = 0; i < 8; i++) { + threads.push_back(std::thread(threadLoop)); + } + + std::this_thread::sleep_for(std::chrono::seconds(3)); + timeUp = true; + LOG(VERBOSE) << "Made " << allocationCount << " threaded allocations"; + + for (auto& thread : threads) { + thread.join(); + } +} + +/** + * Test IMapper::createDescriptor with valid descriptor info. + */ +TEST_F(GraphicsMapperHidlTest, CreateDescriptorBasic) { + ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo)); +} + +/** + * Test IMapper::createDescriptor with invalid descriptor info. + */ +TEST_F(GraphicsMapperHidlTest, CreateDescriptorNegative) { + auto info = mDummyDescriptorInfo; + info.width = 0; + mGralloc->getMapper()->createDescriptor(info, [&](const auto& tmpError, const auto&) { + EXPECT_EQ(Error::BAD_VALUE, tmpError) << "createDescriptor did not fail with BAD_VALUE"; + }); +} + +/** + * Test IMapper::importBuffer and IMapper::freeBuffer with allocated buffers. + */ +TEST_F(GraphicsMapperHidlTest, ImportFreeBufferBasic) { + const native_handle_t* bufferHandle; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); + ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle)); +} + +/** + * Test IMapper::importBuffer and IMapper::freeBuffer with cloned buffers. + */ +TEST_F(GraphicsMapperHidlTest, ImportFreeBufferClone) { + const native_handle_t* clonedBufferHandle; + ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false)); + + // A cloned handle is a raw handle. Check that we can import it multiple + // times. + const native_handle_t* importedBufferHandles[2]; + ASSERT_NO_FATAL_FAILURE(importedBufferHandles[0] = mGralloc->importBuffer(clonedBufferHandle)); + ASSERT_NO_FATAL_FAILURE(importedBufferHandles[1] = mGralloc->importBuffer(clonedBufferHandle)); + ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[0])); + ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[1])); + + ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(clonedBufferHandle)); +} + +/** + * Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances. + */ +TEST_F(GraphicsMapperHidlTest, ImportFreeBufferSingleton) { + const native_handle_t* rawHandle; + ASSERT_NO_FATAL_FAILURE(rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false)); + + native_handle_t* importedHandle = nullptr; + mGralloc->getMapper()->importBuffer(rawHandle, [&](const auto& tmpError, const auto& buffer) { + ASSERT_EQ(Error::NONE, tmpError); + importedHandle = static_cast(buffer); + }); + + // free the imported handle with another mapper + std::unique_ptr anotherGralloc; + ASSERT_NO_FATAL_FAILURE( + anotherGralloc = std::make_unique( + GraphicsMapperHidlEnvironment::Instance()->getServiceName(), + GraphicsMapperHidlEnvironment::Instance()->getServiceName())); + Error error = mGralloc->getMapper()->freeBuffer(importedHandle); + ASSERT_EQ(Error::NONE, error); + + ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(rawHandle)); +} + +/** + * Test IMapper::importBuffer and IMapper::freeBuffer do not leak. + */ +TEST_F(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) { + auto info = mDummyDescriptorInfo; + info.width = 1024; + info.height = 1024; + + for (int i = 0; i < 2048; i++) { + auto bufferHandle = mGralloc->allocate(info, true); + mGralloc->freeBuffer(bufferHandle); + } +} + +/** + * Test IMapper::importBuffer with invalid buffers. + */ +TEST_F(GraphicsMapperHidlTest, ImportBufferNegative) { + native_handle_t* invalidHandle = nullptr; + mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) { + EXPECT_EQ(Error::BAD_BUFFER, tmpError) + << "importBuffer with nullptr did not fail with BAD_BUFFER"; + }); + + invalidHandle = native_handle_create(0, 0); + mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) { + EXPECT_EQ(Error::BAD_BUFFER, tmpError) + << "importBuffer with invalid handle did not fail with BAD_BUFFER"; + }); + native_handle_delete(invalidHandle); +} + +/** + * Test IMapper::freeBuffer with invalid buffers. + */ +TEST_F(GraphicsMapperHidlTest, FreeBufferNegative) { + native_handle_t* invalidHandle = nullptr; + Error error = mGralloc->getMapper()->freeBuffer(invalidHandle); + EXPECT_EQ(Error::BAD_BUFFER, error) << "freeBuffer with nullptr did not fail with BAD_BUFFER"; + + invalidHandle = native_handle_create(0, 0); + error = mGralloc->getMapper()->freeBuffer(invalidHandle); + EXPECT_EQ(Error::BAD_BUFFER, error) + << "freeBuffer with invalid handle did not fail with BAD_BUFFER"; + native_handle_delete(invalidHandle); + + const native_handle_t* clonedBufferHandle; + ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false)); + error = mGralloc->getMapper()->freeBuffer(invalidHandle); + EXPECT_EQ(Error::BAD_BUFFER, error) + << "freeBuffer with un-imported handle did not fail with BAD_BUFFER"; + + mGralloc->freeBuffer(clonedBufferHandle); +} + +/** + * Test IMapper::lock and IMapper::unlock. + */ +TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) { + const auto& info = mDummyDescriptorInfo; + + const native_handle_t* bufferHandle; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, &stride)); + + // lock buffer for writing + const IMapper::Rect region{0, 0, static_cast(info.width), + static_cast(info.height)}; + int fence = -1; + uint8_t* data; + int32_t bytesPerPixel = -1; + int32_t bytesPerStride = -1; + ASSERT_NO_FATAL_FAILURE( + data = static_cast(mGralloc->lock(bufferHandle, info.usage, region, fence, + &bytesPerPixel, &bytesPerStride))); + + // Valid return values are -1 for unsupported or the number bytes for supported which is >=0 + EXPECT_GT(bytesPerPixel, -1); + EXPECT_GT(bytesPerStride, -1); + + // RGBA_8888 + size_t strideInBytes = stride * 4; + size_t writeInBytes = info.width * 4; + + for (uint32_t y = 0; y < info.height; y++) { + memset(data, y, writeInBytes); + data += strideInBytes; + } + + ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); + + bytesPerPixel = -1; + bytesPerStride = -1; + + // lock again for reading + ASSERT_NO_FATAL_FAILURE( + data = static_cast(mGralloc->lock(bufferHandle, info.usage, region, fence, + &bytesPerPixel, &bytesPerStride))); + for (uint32_t y = 0; y < info.height; y++) { + for (size_t i = 0; i < writeInBytes; i++) { + EXPECT_EQ(static_cast(y), data[i]); + } + data += strideInBytes; + } + + EXPECT_GT(bytesPerPixel, -1); + EXPECT_GT(bytesPerStride, -1); + + ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); + if (fence >= 0) { + close(fence); + } +} + +/** + * Test IMapper::lockYCbCr. This locks a YV12 buffer, and makes sure we can + * write to and read from it. + */ +TEST_F(GraphicsMapperHidlTest, LockYCbCrBasic) { + auto info = mDummyDescriptorInfo; + info.format = PixelFormat::YV12; + + const native_handle_t* bufferHandle; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, &stride)); + + // lock buffer for writing + const IMapper::Rect region{0, 0, static_cast(info.width), + static_cast(info.height)}; + int fence = -1; + YCbCrLayout layout; + ASSERT_NO_FATAL_FAILURE(layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence)); + + auto yData = static_cast(layout.y); + auto cbData = static_cast(layout.cb); + auto crData = static_cast(layout.cr); + for (uint32_t y = 0; y < info.height; y++) { + for (uint32_t x = 0; x < info.width; x++) { + auto val = static_cast(info.height * y + x); + + yData[layout.yStride * y + x] = val; + if (y % 2 == 0 && x % 2 == 0) { + cbData[layout.cStride * y / 2 + x / 2] = val; + crData[layout.cStride * y / 2 + x / 2] = val; + } + } + } + + ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); + + // lock again for reading + ASSERT_NO_FATAL_FAILURE(layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence)); + + yData = static_cast(layout.y); + cbData = static_cast(layout.cb); + crData = static_cast(layout.cr); + for (uint32_t y = 0; y < info.height; y++) { + for (uint32_t x = 0; x < info.width; x++) { + auto val = static_cast(info.height * y + x); + + EXPECT_EQ(val, yData[layout.yStride * y + x]); + if (y % 2 == 0 && x % 2 == 0) { + EXPECT_EQ(val, cbData[layout.cStride * y / 2 + x / 2]); + EXPECT_EQ(val, crData[layout.cStride * y / 2 + x / 2]); + } + } + } + + ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); + if (fence >= 0) { + close(fence); + } +} + +/** + * Test IMapper::unlock with invalid buffers. + */ +TEST_F(GraphicsMapperHidlTest, UnlockNegative) { + native_handle_t* invalidHandle = nullptr; + mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) { + EXPECT_EQ(Error::BAD_BUFFER, tmpError) + << "unlock with nullptr did not fail with BAD_BUFFER"; + }); + + invalidHandle = native_handle_create(0, 0); + mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) { + EXPECT_EQ(Error::BAD_BUFFER, tmpError) + << "unlock with invalid handle did not fail with BAD_BUFFER"; + }); + native_handle_delete(invalidHandle); + + ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast( + mGralloc->allocate(mDummyDescriptorInfo, false))); + mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) { + EXPECT_EQ(Error::BAD_BUFFER, tmpError) + << "unlock with un-imported handle did not fail with BAD_BUFFER"; + }); + mGralloc->freeBuffer(invalidHandle); + +// disabled as it fails on many existing drivers +#if 0 + ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast( + mGralloc->allocate(mDummyDescriptorInfo, true))); + mGralloc->getMapper()->unlock( + invalidHandle, [&](const auto& tmpError, const auto&) { + EXPECT_EQ(Error::BAD_BUFFER, tmpError) + << "unlock with unlocked handle did not fail with BAD_BUFFER"; + }); + mGralloc->freeBuffer(invalidHandle); +#endif +} + +/** + * Test IMapper::isSupported with required format RGBA_8888 + */ +TEST_F(GraphicsMapperHidlTest, IsSupportedRGBA8888) { + const auto& info = mDummyDescriptorInfo; + bool supported = false; + + ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info)); + ASSERT_TRUE(supported); +} + +/** + * Test IMapper::isSupported with required format YV12 + */ +TEST_F(GraphicsMapperHidlTest, IsSupportedYV12) { + auto info = mDummyDescriptorInfo; + info.format = PixelFormat::YV12; + bool supported = false; + + ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info)); + ASSERT_TRUE(supported); +} + +/** + * Test IMapper::isSupported with optional format Y16 + */ +TEST_F(GraphicsMapperHidlTest, IsSupportedY16) { + auto info = mDummyDescriptorInfo; + info.format = PixelFormat::Y16; + bool supported = false; + + ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info)); +} + +} // namespace +} // namespace vts +} // namespace V4_0 +} // namespace mapper +} // namespace graphics +} // namespace hardware +} // namespace android + +int main(int argc, char** argv) { + using android::hardware::graphics::mapper::V4_0::vts::GraphicsMapperHidlEnvironment; + ::testing::AddGlobalTestEnvironment(GraphicsMapperHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + GraphicsMapperHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} From 7dc09889baaa4f1db00ba0fa6400692b44d20721 Mon Sep 17 00:00:00 2001 From: Grace Cheng Date: Wed, 24 Jul 2019 21:04:57 -0700 Subject: [PATCH 0041/1022] Fixes vts failure. Formats code. Root cause: Default (without specification in implementation) minimum sample rate is 0.0f. VTS tests minimum sample rate should be larger than 0.0f. Adds minimum and maximum sample rate for continuous property. Bug: 136215520, 138316549 Test: vts-tradefed run vts-hal-auto -m VtsHalAutomotiveVehicleV2_0Host Change-Id: I324c3e05f4d8c6100d370031d0072e8231a43267 --- .../default/impl/vhal_v2_0/DefaultConfig.h | 1327 +++++++++-------- 1 file changed, 682 insertions(+), 645 deletions(-) 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 3e59584983..7bafd2c4ff 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 @@ -162,651 +162,688 @@ struct ConfigDeclaration { }; const ConfigDeclaration kVehicleProperties[]{ - {.config = - { - .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::STATIC, - }, - .initialValue = {.floatValues = {15000.0f}}}, - - {.config = - { - .prop = toInt(VehicleProperty::INFO_FUEL_TYPE), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::STATIC, - }, - .initialValue = {.int32Values = {(int)FuelType::FUEL_TYPE_UNLEADED}}}, - - {.config = - { - .prop = toInt(VehicleProperty::INFO_EV_BATTERY_CAPACITY), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::STATIC, - }, - .initialValue = {.floatValues = {150000.0f}}}, - - {.config = - { - .prop = toInt(VehicleProperty::INFO_EV_CONNECTOR_TYPE), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::STATIC, - }, - .initialValue = {.int32Values = {(int)EvConnectorType::IEC_TYPE_1_AC}}}, - - {.config = - { - .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::STATIC, - }, - .initialValue = {.int32Values = {SEAT_1_LEFT}}}, - - {.config = - { - .prop = toInt(VehicleProperty::INFO_FUEL_DOOR_LOCATION), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::STATIC, - }, - .initialValue = {.int32Values = {FUEL_DOOR_REAR_LEFT}}}, - - {.config = - { - .prop = toInt(VehicleProperty::INFO_EV_PORT_LOCATION), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::STATIC, - }, - .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT}}}, - - {.config = - { - .prop = toInt(VehicleProperty::INFO_MAKE), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::STATIC, - }, - .initialValue = {.stringValue = "Toy Vehicle"}}, - {.config = - { - .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::CONTINUOUS, - .minSampleRate = 1.0f, - .maxSampleRate = 10.0f, - }, - .initialValue = {.floatValues = {0.0f}}}, - - {.config = - { - .prop = toInt(VehicleProperty::VEHICLE_SPEED_DISPLAY_UNITS), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .configArray = {(int)VehicleUnit::METER_PER_SEC, - (int)VehicleUnit::MILES_PER_HOUR, - (int)VehicleUnit::KILOMETERS_PER_HOUR}, - }, - .initialValue = {.int32Values = {(int)VehicleUnit::KILOMETERS_PER_HOUR}}}, - - {.config = - { - .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::STATIC, - // this was a zoned property on an old vhal, but it is meant to be global - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, - }, - .initialValue = {.int32Values = {SEAT_1_LEFT}}}, - - {.config = - { - .prop = toInt(VehicleProperty::PERF_ODOMETER), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::CONTINUOUS, - }, - .initialValue = {.floatValues = {0.0f}}}, - - { - .config = - { - .prop = toInt(VehicleProperty::ENGINE_RPM), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::CONTINUOUS, - .minSampleRate = 1.0f, - .maxSampleRate = 10.0f, - }, - .initialValue = {.floatValues = {0.0f}}, - }, - - {.config = - { - .prop = toInt(VehicleProperty::FUEL_LEVEL), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::CONTINUOUS, - }, - .initialValue = {.floatValues = {15000.0f}}}, - - {.config = - { - .prop = toInt(VehicleProperty::FUEL_DOOR_OPEN), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {0}}}, - - {.config = - { - .prop = toInt(VehicleProperty::EV_BATTERY_LEVEL), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::CONTINUOUS, - }, - .initialValue = {.floatValues = {150000.0f}}}, - - {.config = - { - .prop = toInt(VehicleProperty::EV_CHARGE_PORT_OPEN), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {0}}}, - - {.config = - { - .prop = toInt(VehicleProperty::EV_CHARGE_PORT_CONNECTED), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {0}}}, - - {.config = - { - .prop = toInt(VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::CONTINUOUS, - }, - .initialValue = {.floatValues = {0.0f}}}, - - {.config = - { - .prop = toInt(VehicleProperty::RANGE_REMAINING), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::CONTINUOUS, - .minSampleRate = 1.0f, - .maxSampleRate = 2.0f, - }, - .initialValue = {.floatValues = {100.0f}}}, // units in meters - - {.config = - {.prop = toInt(VehicleProperty::TIRE_PRESSURE), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::CONTINUOUS, - .minSampleRate = 1.0f, - .maxSampleRate = 2.0f, - .areaConfigs = - {VehicleAreaConfig{ - .areaId = WHEEL_FRONT_LEFT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f, - }, - VehicleAreaConfig{ - .areaId = WHEEL_FRONT_RIGHT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f, - }, - VehicleAreaConfig{ - .areaId = WHEEL_REAR_LEFT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f, - }, - VehicleAreaConfig{ - .areaId = WHEEL_REAR_RIGHT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f, - }}}, - .initialValue = {.floatValues = {200.0f}}}, // units in kPa - - {.config = - { - .prop = toInt(VehicleProperty::CURRENT_GEAR), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}}, - - {.config = - { - .prop = toInt(VehicleProperty::PARKING_BRAKE_ON), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {1}}}, - - {.config = - { - .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {0}}}, - - {.config = - { - .prop = toInt(VehicleProperty::HW_KEY_INPUT), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {0, 0, 0}}}, - - {.config = {.prop = toInt(VehicleProperty::HVAC_POWER_ON), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}, - // TODO(bryaneyler): Ideally, this is generated dynamically from - // kHvacPowerProperties. - .configArray = {toInt(VehicleProperty::HVAC_FAN_SPEED), - toInt(VehicleProperty::HVAC_FAN_DIRECTION)}}, - .initialValue = {.int32Values = {1}}}, - - { - .config = {.prop = toInt(VehicleProperty::HVAC_DEFROSTER), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = - {VehicleAreaConfig{.areaId = toInt(VehicleAreaWindow::FRONT_WINDSHIELD)}, - VehicleAreaConfig{.areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}}, - .initialValue = {.int32Values = {0}} // Will be used for all areas. - }, - - {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_DEFROST_ON), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, - .initialValue = {.int32Values = {0}}}, - - {.config = {.prop = toInt(VehicleProperty::HVAC_RECIRC_ON), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, - .initialValue = {.int32Values = {1}}}, - - {.config = {.prop = toInt(VehicleProperty::HVAC_AUTO_RECIRC_ON), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, - .initialValue = {.int32Values = {0}}}, - - {.config = {.prop = toInt(VehicleProperty::HVAC_AC_ON), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, - .initialValue = {.int32Values = {1}}}, - - {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_AC_ON), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, - .initialValue = {.int32Values = {0}}}, - - {.config = {.prop = toInt(VehicleProperty::HVAC_AUTO_ON), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, - .initialValue = {.int32Values = {1}}}, - - {.config = {.prop = toInt(VehicleProperty::HVAC_DUAL_ON), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, - .initialValue = {.int32Values = {0}}}, - - {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_SPEED), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{ - .areaId = HVAC_ALL, .minInt32Value = 1, .maxInt32Value = 7}}}, - .initialValue = {.int32Values = {3}}}, - - {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, - .initialValue = {.int32Values = {toInt(VehicleHvacFanDirection::FACE)}}}, - - {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION_AVAILABLE), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::STATIC, - .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, - .initialValue = {.int32Values = {FAN_DIRECTION_FACE, FAN_DIRECTION_FLOOR, - FAN_DIRECTION_FACE | FAN_DIRECTION_FLOOR}}}, - - {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_VENTILATION), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{ - .areaId = SEAT_1_LEFT, .minInt32Value = 0, .maxInt32Value = 3, - }, - VehicleAreaConfig{ - .areaId = SEAT_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 3, - }}}, - .initialValue = {.int32Values = {0}}}, // 0 is off and +ve values indicate ventilation level. - - {.config = {.prop = toInt(VehicleProperty::HVAC_STEERING_WHEEL_HEAT), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{ - .areaId = (0), .minInt32Value = -2, .maxInt32Value = 2}}}, - .initialValue = {.int32Values = {0}}}, // +ve values for heating and -ve for cooling - - {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{ - .areaId = SEAT_1_LEFT, .minInt32Value = -2, .maxInt32Value = 2, - }, - VehicleAreaConfig{ - .areaId = SEAT_1_RIGHT, .minInt32Value = -2, .maxInt32Value = 2, - }}}, - .initialValue = {.int32Values = {0}}}, // +ve values for heating and -ve for cooling - - {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{ - .areaId = HVAC_LEFT, - .minFloatValue = 16, - .maxFloatValue = 32, - }, - VehicleAreaConfig{ - .areaId = HVAC_RIGHT, - .minFloatValue = 16, - .maxFloatValue = 32, - }}}, - .initialAreaValues = {{HVAC_LEFT, {.floatValues = {16}}}, - {HVAC_RIGHT, {.floatValues = {20}}}}}, - - {.config = - { - .prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE), - .access = VehiclePropertyAccess::READ, - // TODO(bryaneyler): Support ON_CHANGE as well. - .changeMode = VehiclePropertyChangeMode::CONTINUOUS, - .minSampleRate = 1.0f, - .maxSampleRate = 2.0f, - }, - .initialValue = {.floatValues = {25.0f}}}, - - {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS} - }, - .initialValue = {.int32Values = {(int)VehicleUnit::FAHRENHEIT}}}, - - {.config = - { - .prop = toInt(VehicleProperty::NIGHT_MODE), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {0}}}, - - {.config = - { - .prop = toInt(VehicleProperty::GEAR_SELECTION), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}}, - - {.config = - { - .prop = toInt(VehicleProperty::IGNITION_STATE), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {toInt(VehicleIgnitionState::ON)}}}, - - {.config = - { - .prop = toInt(VehicleProperty::ENGINE_OIL_LEVEL), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {toInt(VehicleOilLevel::NORMAL)}}}, - - {.config = - { - .prop = toInt(VehicleProperty::ENGINE_OIL_TEMP), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::CONTINUOUS, - .minSampleRate = 0.1, // 0.1 Hz, every 10 seconds - .maxSampleRate = 10, // 10 Hz, every 100 ms - }, - .initialValue = {.floatValues = {101.0f}}}, - - { - .config = - { - .prop = kGenerateFakeDataControllingProperty, - .access = VehiclePropertyAccess::WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - }, - - {.config = {.prop = toInt(VehicleProperty::DOOR_LOCK), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT}, - VehicleAreaConfig{.areaId = DOOR_1_RIGHT}, - VehicleAreaConfig{.areaId = DOOR_2_LEFT}, - VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}}, - .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}}, - {DOOR_1_RIGHT, {.int32Values = {1}}}, - {DOOR_2_LEFT, {.int32Values = {1}}}, - {DOOR_2_RIGHT, {.int32Values = {1}}}}}, - - {.config = - { - .prop = toInt(VehicleProperty::DOOR_POS), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = - {VehicleAreaConfig{.areaId = DOOR_1_LEFT, .minInt32Value = 0, .maxInt32Value = 1}, - VehicleAreaConfig{.areaId = DOOR_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 1}, - VehicleAreaConfig{.areaId = DOOR_2_LEFT, .minInt32Value = 0, .maxInt32Value = 1}, - VehicleAreaConfig{.areaId = DOOR_2_RIGHT, .minInt32Value = 0, .maxInt32Value = 1}, - VehicleAreaConfig{.areaId = DOOR_REAR, .minInt32Value = 0, .maxInt32Value = 1}}}, - .initialValue = {.int32Values = {0}}}, - - {.config = {.prop = toInt(VehicleProperty::WINDOW_LOCK), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = WINDOW_1_RIGHT | WINDOW_2_LEFT | - WINDOW_2_RIGHT}}}, - .initialAreaValues = {{WINDOW_1_RIGHT | WINDOW_2_LEFT | WINDOW_2_RIGHT, - {.int32Values = {0}}}}}, - - {.config = - {.prop = toInt(VehicleProperty::WINDOW_POS), - .access = - VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = - {VehicleAreaConfig{.areaId = WINDOW_1_LEFT, .minInt32Value = 0, .maxInt32Value = 10}, - VehicleAreaConfig{.areaId = WINDOW_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 10}, - VehicleAreaConfig{.areaId = WINDOW_2_LEFT, .minInt32Value = 0, .maxInt32Value = 10}, - VehicleAreaConfig{.areaId = WINDOW_2_RIGHT, .minInt32Value = 0, .maxInt32Value = 10}, - VehicleAreaConfig{ - .areaId = WINDOW_ROOF_TOP_1, .minInt32Value = -10, .maxInt32Value = 10}}}, - .initialValue = {.int32Values = {0}}}, - - {.config = - { - .prop = WHEEL_TICK, - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::CONTINUOUS, - .configArray = {ALL_WHEELS, 50000, 50000, 50000, 50000}, - .minSampleRate = 1.0f, - .maxSampleRate = 10.0f, - }, - .initialValue = {.int64Values = {0, 100000, 200000, 300000, 400000}}}, - - {.config = {.prop = ABS_ACTIVE, - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE}, - .initialValue = {.int32Values = {0}}}, - - {.config = {.prop = TRACTION_CONTROL_ACTIVE, - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE}, - .initialValue = {.int32Values = {0}}}, - - {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REQ), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .configArray = {3}}, - .initialValue = {.int32Values = {toInt(VehicleApPowerStateReq::ON), 0}}}, - - {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT), - .access = VehiclePropertyAccess::WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE}, - .initialValue = {.int32Values = {toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL), 0}}}, - - {.config = {.prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.minInt32Value = 0, .maxInt32Value = 100}}}, - .initialValue = {.int32Values = {100}}}, - - { - .config = {.prop = OBD2_LIVE_FRAME, - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .configArray = {0, 0}}, - }, - - { - .config = {.prop = OBD2_FREEZE_FRAME, - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .configArray = {0, 0}}, - }, - - { - .config = {.prop = OBD2_FREEZE_FRAME_INFO, - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE}, - }, - - { - .config = {.prop = OBD2_FREEZE_FRAME_CLEAR, - .access = VehiclePropertyAccess::WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .configArray = {1}}, - }, - - {.config = - { - .prop = toInt(VehicleProperty::HEADLIGHTS_STATE), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {LIGHT_STATE_ON}}}, - - {.config = - { - .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_STATE), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {LIGHT_STATE_ON}}}, - - {.config = - { - .prop = toInt(VehicleProperty::FOG_LIGHTS_STATE), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {LIGHT_STATE_ON}}}, - - {.config = - { - .prop = toInt(VehicleProperty::HAZARD_LIGHTS_STATE), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {LIGHT_STATE_ON}}}, - - {.config = - { - .prop = toInt(VehicleProperty::HEADLIGHTS_SWITCH), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}}, - - {.config = - { - .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_SWITCH), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}}, - - {.config = - { - .prop = toInt(VehicleProperty::FOG_LIGHTS_SWITCH), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}}, - - {.config = - { - .prop = toInt(VehicleProperty::HAZARD_LIGHTS_SWITCH), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}}, - - {.config = {.prop = VEHICLE_MAP_SERVICE, - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE}}, - - // Example Vendor Extension properties for testing - {.config = {.prop = VENDOR_EXTENSION_BOOLEAN_PROPERTY, - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT}, - VehicleAreaConfig{.areaId = DOOR_1_RIGHT}, - VehicleAreaConfig{.areaId = DOOR_2_LEFT}, - VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}}, - .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}}, - {DOOR_1_RIGHT, {.int32Values = {1}}}, - {DOOR_2_LEFT, {.int32Values = {0}}}, - {DOOR_2_RIGHT, {.int32Values = {0}}}}}, - - {.config = {.prop = VENDOR_EXTENSION_FLOAT_PROPERTY, - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{ - .areaId = HVAC_LEFT, .minFloatValue = -10, .maxFloatValue = 10}, - VehicleAreaConfig{.areaId = HVAC_RIGHT, - .minFloatValue = -10, - .maxFloatValue = 10}}}, - .initialAreaValues = {{HVAC_LEFT, {.floatValues = {1}}}, {HVAC_RIGHT, {.floatValues = {2}}}}}, - - {.config = {.prop = VENDOR_EXTENSION_INT_PROPERTY, - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .areaConfigs = {VehicleAreaConfig{ - .areaId = (int)VehicleAreaWindow::FRONT_WINDSHIELD, - .minInt32Value = -100, - .maxInt32Value = 100}, - VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::REAR_WINDSHIELD, - .minInt32Value = -100, - .maxInt32Value = 100}, - VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::ROOF_TOP_1, - .minInt32Value = -100, - .maxInt32Value = 100}}}, - .initialAreaValues = {{(int)VehicleAreaWindow::FRONT_WINDSHIELD, {.int32Values = {1}}}, - {(int)VehicleAreaWindow::REAR_WINDSHIELD, {.int32Values = {0}}}, - {(int)VehicleAreaWindow::ROOF_TOP_1, {.int32Values = {-1}}}}}, - - {.config = {.prop = VENDOR_EXTENSION_STRING_PROPERTY, - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE}, - .initialValue = {.stringValue = "Vendor String Property"}}, + {.config = + { + .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + }, + .initialValue = {.floatValues = {15000.0f}}}, + + {.config = + { + .prop = toInt(VehicleProperty::INFO_FUEL_TYPE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + }, + .initialValue = {.int32Values = {(int)FuelType::FUEL_TYPE_UNLEADED}}}, + + {.config = + { + .prop = toInt(VehicleProperty::INFO_EV_BATTERY_CAPACITY), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + }, + .initialValue = {.floatValues = {150000.0f}}}, + + {.config = + { + .prop = toInt(VehicleProperty::INFO_EV_CONNECTOR_TYPE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + }, + .initialValue = {.int32Values = {(int)EvConnectorType::IEC_TYPE_1_AC}}}, + + {.config = + { + .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + }, + .initialValue = {.int32Values = {SEAT_1_LEFT}}}, + + {.config = + { + .prop = toInt(VehicleProperty::INFO_FUEL_DOOR_LOCATION), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + }, + .initialValue = {.int32Values = {FUEL_DOOR_REAR_LEFT}}}, + + {.config = + { + .prop = toInt(VehicleProperty::INFO_EV_PORT_LOCATION), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + }, + .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT}}}, + + {.config = + { + .prop = toInt(VehicleProperty::INFO_MAKE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + }, + .initialValue = {.stringValue = "Toy Vehicle"}}, + {.config = + { + .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .minSampleRate = 1.0f, + .maxSampleRate = 10.0f, + }, + .initialValue = {.floatValues = {0.0f}}}, + + {.config = + { + .prop = toInt(VehicleProperty::VEHICLE_SPEED_DISPLAY_UNITS), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {(int)VehicleUnit::METER_PER_SEC, + (int)VehicleUnit::MILES_PER_HOUR, + (int)VehicleUnit::KILOMETERS_PER_HOUR}, + }, + .initialValue = {.int32Values = {(int)VehicleUnit::KILOMETERS_PER_HOUR}}}, + + {.config = + { + .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + // this was a zoned property on an old vhal, but it is meant to be global + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + }, + .initialValue = {.int32Values = {SEAT_1_LEFT}}}, + + {.config = + { + .prop = toInt(VehicleProperty::PERF_ODOMETER), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .minSampleRate = 0.0f, + .maxSampleRate = 10.0f, + }, + .initialValue = {.floatValues = {0.0f}}}, + + { + .config = + { + .prop = toInt(VehicleProperty::ENGINE_RPM), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .minSampleRate = 1.0f, + .maxSampleRate = 10.0f, + }, + .initialValue = {.floatValues = {0.0f}}, + }, + + {.config = + { + .prop = toInt(VehicleProperty::FUEL_LEVEL), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .minSampleRate = 0.0f, + .maxSampleRate = 100.0f, + }, + .initialValue = {.floatValues = {15000.0f}}}, + + {.config = + { + .prop = toInt(VehicleProperty::FUEL_DOOR_OPEN), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {0}}}, + + {.config = + { + .prop = toInt(VehicleProperty::EV_BATTERY_LEVEL), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .minSampleRate = 0.0f, + .maxSampleRate = 100.0f, + }, + .initialValue = {.floatValues = {150000.0f}}}, + + {.config = + { + .prop = toInt(VehicleProperty::EV_CHARGE_PORT_OPEN), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {0}}}, + + {.config = + { + .prop = toInt(VehicleProperty::EV_CHARGE_PORT_CONNECTED), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {0}}}, + + {.config = + { + .prop = toInt(VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .minSampleRate = 1.0f, + .maxSampleRate = 10.0f, + }, + .initialValue = {.floatValues = {0.0f}}}, + + {.config = + { + .prop = toInt(VehicleProperty::RANGE_REMAINING), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .minSampleRate = 1.0f, + .maxSampleRate = 2.0f, + }, + .initialValue = {.floatValues = {100.0f}}}, // units in meters + + {.config = {.prop = toInt(VehicleProperty::TIRE_PRESSURE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .minSampleRate = 1.0f, + .maxSampleRate = 2.0f, + .areaConfigs = {VehicleAreaConfig{ + .areaId = WHEEL_FRONT_LEFT, + .minFloatValue = 100.0f, + .maxFloatValue = 300.0f, + }, + VehicleAreaConfig{ + .areaId = WHEEL_FRONT_RIGHT, + .minFloatValue = 100.0f, + .maxFloatValue = 300.0f, + }, + VehicleAreaConfig{ + .areaId = WHEEL_REAR_LEFT, + .minFloatValue = 100.0f, + .maxFloatValue = 300.0f, + }, + VehicleAreaConfig{ + .areaId = WHEEL_REAR_RIGHT, + .minFloatValue = 100.0f, + .maxFloatValue = 300.0f, + }}}, + .initialValue = {.floatValues = {200.0f}}}, // units in kPa + + {.config = + { + .prop = toInt(VehicleProperty::CURRENT_GEAR), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}}, + + {.config = + { + .prop = toInt(VehicleProperty::PARKING_BRAKE_ON), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {1}}}, + + {.config = + { + .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {0}}}, + + {.config = + { + .prop = toInt(VehicleProperty::HW_KEY_INPUT), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {0, 0, 0}}}, + + {.config = {.prop = toInt(VehicleProperty::HVAC_POWER_ON), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}, + // TODO(bryaneyler): Ideally, this is generated dynamically from + // kHvacPowerProperties. + .configArray = {toInt(VehicleProperty::HVAC_FAN_SPEED), + toInt(VehicleProperty::HVAC_FAN_DIRECTION)}}, + .initialValue = {.int32Values = {1}}}, + + { + .config = {.prop = toInt(VehicleProperty::HVAC_DEFROSTER), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = + {VehicleAreaConfig{ + .areaId = toInt(VehicleAreaWindow::FRONT_WINDSHIELD)}, + VehicleAreaConfig{ + .areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}}, + .initialValue = {.int32Values = {0}} // Will be used for all areas. + }, + + {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_DEFROST_ON), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, + .initialValue = {.int32Values = {0}}}, + + {.config = {.prop = toInt(VehicleProperty::HVAC_RECIRC_ON), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, + .initialValue = {.int32Values = {1}}}, + + {.config = {.prop = toInt(VehicleProperty::HVAC_AUTO_RECIRC_ON), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, + .initialValue = {.int32Values = {0}}}, + + {.config = {.prop = toInt(VehicleProperty::HVAC_AC_ON), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, + .initialValue = {.int32Values = {1}}}, + + {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_AC_ON), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, + .initialValue = {.int32Values = {0}}}, + + {.config = {.prop = toInt(VehicleProperty::HVAC_AUTO_ON), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, + .initialValue = {.int32Values = {1}}}, + + {.config = {.prop = toInt(VehicleProperty::HVAC_DUAL_ON), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, + .initialValue = {.int32Values = {0}}}, + + {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_SPEED), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{ + .areaId = HVAC_ALL, .minInt32Value = 1, .maxInt32Value = 7}}}, + .initialValue = {.int32Values = {3}}}, + + {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, + .initialValue = {.int32Values = {toInt(VehicleHvacFanDirection::FACE)}}}, + + {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION_AVAILABLE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, + .initialValue = {.int32Values = {FAN_DIRECTION_FACE, FAN_DIRECTION_FLOOR, + FAN_DIRECTION_FACE | FAN_DIRECTION_FLOOR}}}, + + {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_VENTILATION), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{ + .areaId = SEAT_1_LEFT, + .minInt32Value = 0, + .maxInt32Value = 3, + }, + VehicleAreaConfig{ + .areaId = SEAT_1_RIGHT, + .minInt32Value = 0, + .maxInt32Value = 3, + }}}, + .initialValue = + {.int32Values = {0}}}, // 0 is off and +ve values indicate ventilation level. + + {.config = {.prop = toInt(VehicleProperty::HVAC_STEERING_WHEEL_HEAT), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{ + .areaId = (0), .minInt32Value = -2, .maxInt32Value = 2}}}, + .initialValue = {.int32Values = {0}}}, // +ve values for heating and -ve for cooling + + {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{ + .areaId = SEAT_1_LEFT, + .minInt32Value = -2, + .maxInt32Value = 2, + }, + VehicleAreaConfig{ + .areaId = SEAT_1_RIGHT, + .minInt32Value = -2, + .maxInt32Value = 2, + }}}, + .initialValue = {.int32Values = {0}}}, // +ve values for heating and -ve for cooling + + {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{ + .areaId = HVAC_LEFT, + .minFloatValue = 16, + .maxFloatValue = 32, + }, + VehicleAreaConfig{ + .areaId = HVAC_RIGHT, + .minFloatValue = 16, + .maxFloatValue = 32, + }}}, + .initialAreaValues = {{HVAC_LEFT, {.floatValues = {16}}}, + {HVAC_RIGHT, {.floatValues = {20}}}}}, + + {.config = + { + .prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE), + .access = VehiclePropertyAccess::READ, + // TODO(bryaneyler): Support ON_CHANGE as well. + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .minSampleRate = 1.0f, + .maxSampleRate = 2.0f, + }, + .initialValue = {.floatValues = {25.0f}}}, + + {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS}}, + .initialValue = {.int32Values = {(int)VehicleUnit::FAHRENHEIT}}}, + + {.config = + { + .prop = toInt(VehicleProperty::NIGHT_MODE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {0}}}, + + {.config = + { + .prop = toInt(VehicleProperty::GEAR_SELECTION), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}}, + + {.config = + { + .prop = toInt(VehicleProperty::IGNITION_STATE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {toInt(VehicleIgnitionState::ON)}}}, + + {.config = + { + .prop = toInt(VehicleProperty::ENGINE_OIL_LEVEL), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {toInt(VehicleOilLevel::NORMAL)}}}, + + {.config = + { + .prop = toInt(VehicleProperty::ENGINE_OIL_TEMP), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .minSampleRate = 0.1, // 0.1 Hz, every 10 seconds + .maxSampleRate = 10, // 10 Hz, every 100 ms + }, + .initialValue = {.floatValues = {101.0f}}}, + + { + .config = + { + .prop = kGenerateFakeDataControllingProperty, + .access = VehiclePropertyAccess::WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + }, + + {.config = {.prop = toInt(VehicleProperty::DOOR_LOCK), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT}, + VehicleAreaConfig{.areaId = DOOR_1_RIGHT}, + VehicleAreaConfig{.areaId = DOOR_2_LEFT}, + VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}}, + .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}}, + {DOOR_1_RIGHT, {.int32Values = {1}}}, + {DOOR_2_LEFT, {.int32Values = {1}}}, + {DOOR_2_RIGHT, {.int32Values = {1}}}}}, + + {.config = {.prop = toInt(VehicleProperty::DOOR_POS), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = + {VehicleAreaConfig{ + .areaId = DOOR_1_LEFT, .minInt32Value = 0, .maxInt32Value = 1}, + VehicleAreaConfig{.areaId = DOOR_1_RIGHT, + .minInt32Value = 0, + .maxInt32Value = 1}, + VehicleAreaConfig{ + .areaId = DOOR_2_LEFT, .minInt32Value = 0, .maxInt32Value = 1}, + VehicleAreaConfig{.areaId = DOOR_2_RIGHT, + .minInt32Value = 0, + .maxInt32Value = 1}, + VehicleAreaConfig{ + .areaId = DOOR_REAR, .minInt32Value = 0, .maxInt32Value = 1}}}, + .initialValue = {.int32Values = {0}}}, + + {.config = {.prop = toInt(VehicleProperty::WINDOW_LOCK), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = WINDOW_1_RIGHT | WINDOW_2_LEFT | + WINDOW_2_RIGHT}}}, + .initialAreaValues = {{WINDOW_1_RIGHT | WINDOW_2_LEFT | WINDOW_2_RIGHT, + {.int32Values = {0}}}}}, + + {.config = {.prop = toInt(VehicleProperty::WINDOW_POS), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = WINDOW_1_LEFT, + .minInt32Value = 0, + .maxInt32Value = 10}, + VehicleAreaConfig{.areaId = WINDOW_1_RIGHT, + .minInt32Value = 0, + .maxInt32Value = 10}, + VehicleAreaConfig{.areaId = WINDOW_2_LEFT, + .minInt32Value = 0, + .maxInt32Value = 10}, + VehicleAreaConfig{.areaId = WINDOW_2_RIGHT, + .minInt32Value = 0, + .maxInt32Value = 10}, + VehicleAreaConfig{.areaId = WINDOW_ROOF_TOP_1, + .minInt32Value = -10, + .maxInt32Value = 10}}}, + .initialValue = {.int32Values = {0}}}, + + {.config = + { + .prop = WHEEL_TICK, + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .configArray = {ALL_WHEELS, 50000, 50000, 50000, 50000}, + .minSampleRate = 1.0f, + .maxSampleRate = 10.0f, + }, + .initialValue = {.int64Values = {0, 100000, 200000, 300000, 400000}}}, + + {.config = {.prop = ABS_ACTIVE, + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE}, + .initialValue = {.int32Values = {0}}}, + + {.config = {.prop = TRACTION_CONTROL_ACTIVE, + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE}, + .initialValue = {.int32Values = {0}}}, + + {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REQ), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {3}}, + .initialValue = {.int32Values = {toInt(VehicleApPowerStateReq::ON), 0}}}, + + {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT), + .access = VehiclePropertyAccess::WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE}, + .initialValue = {.int32Values = {toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL), 0}}}, + + {.config = {.prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.minInt32Value = 0, .maxInt32Value = 100}}}, + .initialValue = {.int32Values = {100}}}, + + { + .config = {.prop = OBD2_LIVE_FRAME, + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {0, 0}}, + }, + + { + .config = {.prop = OBD2_FREEZE_FRAME, + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {0, 0}}, + }, + + { + .config = {.prop = OBD2_FREEZE_FRAME_INFO, + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE}, + }, + + { + .config = {.prop = OBD2_FREEZE_FRAME_CLEAR, + .access = VehiclePropertyAccess::WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {1}}, + }, + + {.config = + { + .prop = toInt(VehicleProperty::HEADLIGHTS_STATE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {LIGHT_STATE_ON}}}, + + {.config = + { + .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_STATE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {LIGHT_STATE_ON}}}, + + {.config = + { + .prop = toInt(VehicleProperty::FOG_LIGHTS_STATE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {LIGHT_STATE_ON}}}, + + {.config = + { + .prop = toInt(VehicleProperty::HAZARD_LIGHTS_STATE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {LIGHT_STATE_ON}}}, + + {.config = + { + .prop = toInt(VehicleProperty::HEADLIGHTS_SWITCH), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}}, + + {.config = + { + .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_SWITCH), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}}, + + {.config = + { + .prop = toInt(VehicleProperty::FOG_LIGHTS_SWITCH), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}}, + + {.config = + { + .prop = toInt(VehicleProperty::HAZARD_LIGHTS_SWITCH), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}}, + + {.config = {.prop = VEHICLE_MAP_SERVICE, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE}}, + + // Example Vendor Extension properties for testing + {.config = {.prop = VENDOR_EXTENSION_BOOLEAN_PROPERTY, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT}, + VehicleAreaConfig{.areaId = DOOR_1_RIGHT}, + VehicleAreaConfig{.areaId = DOOR_2_LEFT}, + VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}}, + .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}}, + {DOOR_1_RIGHT, {.int32Values = {1}}}, + {DOOR_2_LEFT, {.int32Values = {0}}}, + {DOOR_2_RIGHT, {.int32Values = {0}}}}}, + + {.config = {.prop = VENDOR_EXTENSION_FLOAT_PROPERTY, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_LEFT, + .minFloatValue = -10, + .maxFloatValue = 10}, + VehicleAreaConfig{.areaId = HVAC_RIGHT, + .minFloatValue = -10, + .maxFloatValue = 10}}}, + .initialAreaValues = {{HVAC_LEFT, {.floatValues = {1}}}, + {HVAC_RIGHT, {.floatValues = {2}}}}}, + + {.config = {.prop = VENDOR_EXTENSION_INT_PROPERTY, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = + {VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::FRONT_WINDSHIELD, + .minInt32Value = -100, + .maxInt32Value = 100}, + VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::REAR_WINDSHIELD, + .minInt32Value = -100, + .maxInt32Value = 100}, + VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::ROOF_TOP_1, + .minInt32Value = -100, + .maxInt32Value = 100}}}, + .initialAreaValues = {{(int)VehicleAreaWindow::FRONT_WINDSHIELD, {.int32Values = {1}}}, + {(int)VehicleAreaWindow::REAR_WINDSHIELD, {.int32Values = {0}}}, + {(int)VehicleAreaWindow::ROOF_TOP_1, {.int32Values = {-1}}}}}, + + {.config = {.prop = VENDOR_EXTENSION_STRING_PROPERTY, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE}, + .initialValue = {.stringValue = "Vendor String Property"}}, }; } // impl From c62d9b11011f24882503e0b9b48efb6254f4d610 Mon Sep 17 00:00:00 2001 From: Kai Date: Tue, 16 Jul 2019 16:30:08 -0700 Subject: [PATCH 0042/1022] Add electric defrosters and unknown in FanDiretion Add a new property stands for electric defrosters. Add a enum unknown in VehicleHvacFanDirection. Add the new property into Google VHAL config file. Bug: 126756367 Bug: 132187457 Test: build and flash Change-Id: I853666ebbb0f5286ce59faeb02f0f37259a88c54 --- .../default/impl/vhal_v2_0/DefaultConfig.h | 11 ++++++++ automotive/vehicle/2.0/types.hal | 27 ++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) 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 7bafd2c4ff..bc9b94d1da 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 @@ -422,6 +422,17 @@ const ConfigDeclaration kVehicleProperties[]{ .areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}}, .initialValue = {.int32Values = {0}} // Will be used for all areas. }, + { + .config = {.prop = toInt(VehicleProperty::HVAC_ELECTRIC_DEFROSTER_ON), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = + {VehicleAreaConfig{ + .areaId = toInt(VehicleAreaWindow::FRONT_WINDSHIELD)}, + VehicleAreaConfig{ + .areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}}, + .initialValue = {.int32Values = {0}} // Will be used for all areas. + }, {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_DEFROST_ON), .access = VehiclePropertyAccess::READ_WRITE, diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index f6ebcdd7d0..6232dd56da 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -799,7 +799,7 @@ enum VehicleProperty : int32_t { | VehicleArea:SEAT), /** - * On/off defrost for designated window + * Fan-based defrost for designated window. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE * @access VehiclePropertyAccess:READ_WRITE @@ -1076,6 +1076,7 @@ enum VehicleProperty : int32_t { * * @change_mode VehiclePropertyChangeMode:STATIC * @access VehiclePropertyAccess:READ + * @data_enum VehicleHvacFanDirection */ HVAC_FAN_DIRECTION_AVAILABLE = ( 0x0511 @@ -1118,6 +1119,18 @@ enum VehicleProperty : int32_t { | VehiclePropertyType:INT32 | VehicleArea:SEAT), + /** + * Electric defrosters' status + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + HVAC_ELECTRIC_DEFROSTER_ON = ( + 0x0514 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:WINDOW), + /** * Distance units for display * @@ -2458,9 +2471,19 @@ enum FuelType : int32_t { * Bit flags for fan direction */ enum VehicleHvacFanDirection : int32_t { + UNKNOWN = 0x0, + FACE = 0x1, FLOOR = 0x2, + /** + * FACE_AND_FLOOR = FACE | FLOOR + */ + FACE_AND_FLOOR = 0X3, DEFROST = 0x4, + /** + * DEFROST_AND_FLOOR = DEFROST | FLOOR + */ + DEFROST_AND_FLOOR = 0x06, }; enum VehicleOilLevel : int32_t { @@ -2723,6 +2746,8 @@ enum VehiclePropertyStatus : int32_t { * Various gears which can be selected by user and chosen in system. */ enum VehicleGear : int32_t { + GEAR_UNKNOWN = 0x0000, + GEAR_NEUTRAL = 0x0001, GEAR_REVERSE = 0x0002, GEAR_PARK = 0x0004, From cd995a8c18335f029eb654ee22ae5e580ef53b50 Mon Sep 17 00:00:00 2001 From: Kai Date: Mon, 29 Jul 2019 15:19:23 -0700 Subject: [PATCH 0043/1022] Add MIXED type property in google HAL Add kMixedTypePropertyForTest for E2E test Bug: 133334962 Test: change VHAL to google HAL and run vehiclehal_test Change-Id: Ib9a9708830c4357f9cfc3de6e29d951072e2d2aa --- .../2.0/default/impl/vhal_v2_0/DefaultConfig.h | 14 ++++++++++++++ automotive/vehicle/2.0/types.hal | 15 +++++++++++++++ 2 files changed, 29 insertions(+) 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 7bafd2c4ff..4e848b6425 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 @@ -84,6 +84,12 @@ constexpr int WHEEL_REAR_RIGHT = (int)VehicleAreaWheel::RIGHT_REAR; const int32_t kGenerateFakeDataControllingProperty = 0x0666 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED; +/** + * This property is used for test purpose. End to end tests use this property to test set and get + * method for MIXED type properties. + */ +const int32_t kMixedTypePropertyForTest = + 0x1111 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED; /** * FakeDataCommand enum defines the supported command type for kGenerateFakeDataControllingProperty. * All those commands can be send independently with each other. And each will override the one sent @@ -607,6 +613,14 @@ const ConfigDeclaration kVehicleProperties[]{ }, }, + {.config = {.prop = kMixedTypePropertyForTest, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {1, 1, 0, 2, 0, 0, 1, 0, 0}}, + .initialValue = {.stringValue = "MIXED property", + .int32Values = {1 /* indicate TRUE boolean value */, 2, 3}, + .floatValues = {4.5f}}}, + {.config = {.prop = toInt(VehicleProperty::DOOR_LOCK), .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index f6ebcdd7d0..13993f7f82 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -35,6 +35,21 @@ enum VehiclePropertyType : int32_t { /** * Any combination of scalar or vector types. The exact format must be * provided in the description of the property. + * + * For vendor MIXED type properties, configArray needs to be formatted in this + * structure. + * configArray[0], 1 indicates the property has a String value + * configArray[1], 1 indicates the property has a Boolean value . + * configArray[2], 1 indicates the property has an Integer value. + * configArray[3], the number indicates the size of Integer[] in the property. + * configArray[4], 1 indicates the property has a Long value. + * configArray[5], the number indicates the size of Long[] in the property. + * configArray[6], 1 indicates the property has a Float value. + * configArray[7], the number indicates the size of Float[] in the property. + * configArray[8], the number indicates the size of byte[] in the property. + * For example: + * {@code configArray = {1, 1, 1, 3, 0, 0, 0, 0, 0}} indicates the property has + * a String value, a Boolean value, an Integer value and an array with 3 integers. */ MIXED = 0x00e00000, From d3bef8732c90cc9a45695dc29a3d172c40b8ac43 Mon Sep 17 00:00:00 2001 From: Anil Admal Date: Tue, 30 Jul 2019 17:59:58 -0700 Subject: [PATCH 0044/1022] Address GNSS VTS code duplication (part 1) -Moved GNSS callback event queue class from VTS 2.0 code into common library that is shared with all GNSS VTS tests. -Modified VTS 1.1 code to reuse GNSS callback event queue in order to address potential issues noted in b/131869042 and also to later extract common code from VTS 1.1 and VTS 2.0 into common library. Bug: 136515339 Test: atest VtsHalGnssV2_0TargetTest atest VtsHalGnssV1_1TargetTest Change-Id: I9356e7653f9784a9149b2c2bd6307750e9cc56b3 --- gnss/1.1/vts/functional/gnss_hal_test.cpp | 98 +++++------- gnss/1.1/vts/functional/gnss_hal_test.h | 85 +++++------ .../vts/functional/gnss_hal_test_cases.cpp | 116 +++++++++------ gnss/2.0/vts/functional/gnss_hal_test.h | 124 ++-------------- .../vts/functional/gnss_hal_test_cases.cpp | 10 +- .../vts/include/GnssCallbackEventQueue.h | 140 ++++++++++++++++++ 6 files changed, 302 insertions(+), 271 deletions(-) create mode 100644 gnss/common/utils/vts/include/GnssCallbackEventQueue.h diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp index f3b376e6bd..61a2ce434d 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test.cpp +++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp @@ -28,18 +28,9 @@ using ::android::hardware::hidl_vec; using ::android::hardware::gnss::common::Utils; -// Implementations for the main test class for GNSS HAL -GnssHalTest::GnssHalTest() - : info_called_count_(0), - capabilities_called_count_(0), - location_called_count_(0), - name_called_count_(0), - notify_count_(0) {} - void GnssHalTest::SetUp() { gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService( GnssHidlEnvironment::Instance()->getServiceName()); - list_gnss_sv_status_.clear(); ASSERT_NE(gnss_hal_, nullptr); SetUpGnssCallback(); @@ -48,14 +39,15 @@ void GnssHalTest::SetUp() { void GnssHalTest::TearDown() { if (gnss_hal_ != nullptr) { gnss_hal_->cleanup(); + gnss_hal_ = nullptr; } - if (notify_count_ > 0) { - ALOGW("%d unprocessed callbacks discarded", notify_count_); - } + + // Set to nullptr to destruct the callback event queues and warn of any unprocessed events. + gnss_cb_ = nullptr; } void GnssHalTest::SetUpGnssCallback() { - gnss_cb_ = new GnssCallback(*this); + gnss_cb_ = new GnssCallback(); ASSERT_NE(gnss_cb_, nullptr); auto result = gnss_hal_->setCallback_1_1(gnss_cb_); @@ -69,13 +61,13 @@ void GnssHalTest::SetUpGnssCallback() { /* * All capabilities, name and systemInfo callbacks should trigger */ - EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC)); - EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC)); - EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC)); + EXPECT_TRUE(gnss_cb_->capabilities_cbq_.retrieve(gnss_cb_->last_capabilities_, TIMEOUT_SEC)); + EXPECT_TRUE(gnss_cb_->info_cbq_.retrieve(gnss_cb_->last_info_, TIMEOUT_SEC)); + EXPECT_TRUE(gnss_cb_->name_cbq_.retrieve(gnss_cb_->last_name_, TIMEOUT_SEC)); - EXPECT_EQ(capabilities_called_count_, 1); - EXPECT_EQ(info_called_count_, 1); - EXPECT_EQ(name_called_count_, 1); + EXPECT_EQ(gnss_cb_->capabilities_cbq_.calledCount(), 1); + EXPECT_EQ(gnss_cb_->info_cbq_.calledCount(), 1); + EXPECT_EQ(gnss_cb_->name_cbq_.calledCount(), 1); } void GnssHalTest::StopAndClearLocations() { @@ -89,9 +81,9 @@ void GnssHalTest::StopAndClearLocations() { * the last reply for final startup messages to arrive (esp. system * info.) */ - while (wait(TIMEOUT_SEC) == std::cv_status::no_timeout) { + while (gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, TIMEOUT_SEC)) { } - location_called_count_ = 0; + gnss_cb_->location_cbq_.reset(); } void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_power_mode) { @@ -118,19 +110,22 @@ bool GnssHalTest::StartAndCheckFirstLocation() { */ const int kFirstGnssLocationTimeoutSeconds = 75; - wait(kFirstGnssLocationTimeoutSeconds); - EXPECT_EQ(location_called_count_, 1); + EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, + kFirstGnssLocationTimeoutSeconds)); + int locationCalledCount = gnss_cb_->location_cbq_.calledCount(); + EXPECT_EQ(locationCalledCount, 1); - if (location_called_count_ > 0) { + if (locationCalledCount > 0) { // don't require speed on first fix - CheckLocation(last_location_, false); + CheckLocation(gnss_cb_->last_location_, false); return true; } return false; } void GnssHalTest::CheckLocation(GnssLocation& location, bool check_speed) { - bool check_more_accuracies = (info_called_count_ > 0 && last_info_.yearOfHw >= 2017); + const bool check_more_accuracies = + (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017); Utils::checkLocation(location, check_speed, check_more_accuracies); } @@ -145,12 +140,14 @@ void GnssHalTest::StartAndCheckLocations(int count) { EXPECT_TRUE(StartAndCheckFirstLocation()); for (int i = 1; i < count; i++) { - EXPECT_EQ(std::cv_status::no_timeout, wait(kLocationTimeoutSubsequentSec)); - EXPECT_EQ(location_called_count_, i + 1); + EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, + kLocationTimeoutSubsequentSec)); + int locationCalledCount = gnss_cb_->location_cbq_.calledCount(); + EXPECT_EQ(locationCalledCount, i + 1); // Don't cause confusion by checking details if no location yet - if (location_called_count_ > 0) { + if (locationCalledCount > 0) { // Should be more than 1 location by now, but if not, still don't check first fix speed - CheckLocation(last_location_, location_called_count_ > 1); + CheckLocation(gnss_cb_->last_location_, locationCalledCount > 1); } } } @@ -177,60 +174,41 @@ bool GnssHalTest::IsGnssHalVersion_1_1() const { return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0; } -void GnssHalTest::notify() { - std::unique_lock lock(mtx_); - notify_count_++; - cv_.notify_one(); -} - -std::cv_status GnssHalTest::wait(int timeout_seconds) { - std::unique_lock lock(mtx_); - - auto status = std::cv_status::no_timeout; - while (notify_count_ == 0) { - status = cv_.wait_for(lock, std::chrono::seconds(timeout_seconds)); - if (status == std::cv_status::timeout) return status; - } - notify_count_--; - return status; -} +GnssHalTest::GnssCallback::GnssCallback() + : info_cbq_("system_info"), + name_cbq_("name"), + capabilities_cbq_("capabilities"), + location_cbq_("location"), + sv_status_cbq_("sv_status") {} Return GnssHalTest::GnssCallback::gnssSetSystemInfoCb( const IGnssCallback::GnssSystemInfo& info) { ALOGI("Info received, year %d", info.yearOfHw); - parent_.info_called_count_++; - parent_.last_info_ = info; - parent_.notify(); + info_cbq_.store(info); return Void(); } Return GnssHalTest::GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) { ALOGI("Capabilities received %d", capabilities); - parent_.capabilities_called_count_++; - parent_.last_capabilities_ = capabilities; - parent_.notify(); + capabilities_cbq_.store(capabilities); return Void(); } Return GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) { ALOGI("Name received: %s", name.c_str()); - parent_.name_called_count_++; - parent_.last_name_ = name; - parent_.notify(); + name_cbq_.store(name); return Void(); } Return GnssHalTest::GnssCallback::gnssLocationCb(const GnssLocation& location) { ALOGI("Location received"); - parent_.location_called_count_++; - parent_.last_location_ = location; - parent_.notify(); + location_cbq_.store(location); return Void(); } Return GnssHalTest::GnssCallback::gnssSvStatusCb( const IGnssCallback::GnssSvStatus& svStatus) { ALOGI("GnssSvStatus received"); - parent_.list_gnss_sv_status_.emplace_back(svStatus); + sv_status_cbq_.store(svStatus); return Void(); } diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h index 84a9f846fc..e4325bf359 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test.h +++ b/gnss/1.1/vts/functional/gnss_hal_test.h @@ -21,19 +21,17 @@ #include #include - -#include -#include -#include +#include "GnssCallbackEventQueue.h" using android::hardware::Return; using android::hardware::Void; using android::hardware::gnss::V1_0::GnssLocation; +using android::hardware::gnss::common::GnssCallbackEventQueue; +using android::hardware::gnss::V1_0::GnssLocationFlags; using android::hardware::gnss::V1_1::IGnss; using android::hardware::gnss::V1_1::IGnssCallback; -using android::hardware::gnss::V1_0::GnssLocationFlags; using android::sp; @@ -57,8 +55,6 @@ class GnssHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { // The main test class for GNSS HAL. class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase { public: - GnssHalTest(); - virtual void SetUp() override; virtual void TearDown() override; @@ -72,32 +68,40 @@ class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase { /* Callback class for data & Event. */ class GnssCallback : public IGnssCallback { public: - GnssHalTest& parent_; + IGnssCallback::GnssSystemInfo last_info_; + android::hardware::hidl_string last_name_; + uint32_t last_capabilities_; + GnssLocation last_location_; - GnssCallback(GnssHalTest& parent) : parent_(parent){}; + GnssCallbackEventQueue info_cbq_; + GnssCallbackEventQueue name_cbq_; + GnssCallbackEventQueue capabilities_cbq_; + GnssCallbackEventQueue location_cbq_; + GnssCallbackEventQueue sv_status_cbq_; - virtual ~GnssCallback() = default; + GnssCallback(); + virtual ~GnssCallback() = default; - // Dummy callback handlers - Return gnssStatusCb(const IGnssCallback::GnssStatusValue /* status */) override { - return Void(); - } - Return gnssNmeaCb(int64_t /* timestamp */, - const android::hardware::hidl_string& /* nmea */) override { - return Void(); - } - Return gnssAcquireWakelockCb() override { return Void(); } - Return gnssReleaseWakelockCb() override { return Void(); } - Return gnssRequestLocationCb(bool /* independentFromGnss */) override { - return Void(); - } - Return gnssRequestTimeCb() override { return Void(); } - // Actual (test) callback handlers - Return gnssNameCb(const android::hardware::hidl_string& name) override; - Return gnssLocationCb(const GnssLocation& location) override; - Return gnssSetCapabilitesCb(uint32_t capabilities) override; - Return gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override; - Return gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override; + // Dummy callback handlers + Return gnssStatusCb(const IGnssCallback::GnssStatusValue /* status */) override { + return Void(); + } + Return gnssNmeaCb(int64_t /* timestamp */, + const android::hardware::hidl_string& /* nmea */) override { + return Void(); + } + Return gnssAcquireWakelockCb() override { return Void(); } + Return gnssReleaseWakelockCb() override { return Void(); } + Return gnssRequestLocationCb(bool /* independentFromGnss */) override { + return Void(); + } + Return gnssRequestTimeCb() override { return Void(); } + // Actual (test) callback handlers + Return gnssNameCb(const android::hardware::hidl_string& name) override; + Return gnssLocationCb(const GnssLocation& location) override; + Return gnssSetCapabilitesCb(uint32_t capabilities) override; + Return gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override; + Return gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override; }; /* @@ -152,26 +156,7 @@ class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase { bool IsGnssHalVersion_1_1() const; sp gnss_hal_; // GNSS HAL to call into - sp gnss_cb_; // Primary callback interface - - /* Count of calls to set the following items, and the latest item (used by - * test.) - */ - int info_called_count_; - IGnssCallback::GnssSystemInfo last_info_; - uint32_t last_capabilities_; - int capabilities_called_count_; - int location_called_count_; - GnssLocation last_location_; - list list_gnss_sv_status_; - - int name_called_count_; - android::hardware::hidl_string last_name_; - - private: - std::mutex mtx_; - std::condition_variable cv_; - int notify_count_; + sp gnss_cb_; // Primary callback interface }; #endif // GNSS_HAL_TEST_H_ diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp index ee236ba5d1..3294bcd1ad 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp @@ -50,7 +50,7 @@ TEST_F(GnssHalTest, TestGnssMeasurementCallback) { ASSERT_TRUE(gnssMeasurement_1_1.isOk()); auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement(); ASSERT_TRUE(gnssMeasurement_1_0.isOk()); - if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) { + if (gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) { sp iGnssMeas_1_1 = gnssMeasurement_1_1; sp iGnssMeas_1_0 = gnssMeasurement_1_0; // At least one interface must be non-null. @@ -78,8 +78,10 @@ TEST_F(GnssHalTest, GetLocationLowPower) { const bool kLowPowerMode = true; // Warmup period - VTS doesn't have AGPS access via GnssLocationProvider - StartAndCheckLocations(5); + gnss_cb_->location_cbq_.reset(); + StartAndCheckLocations(kLocationsToCheck); StopAndClearLocations(); + gnss_cb_->location_cbq_.reset(); // Start of Low Power Mode test SetPositionMode(kMinIntervalMsec, kLowPowerMode); @@ -93,24 +95,27 @@ TEST_F(GnssHalTest, GetLocationLowPower) { // Verify that kMinIntervalMsec is respected by waiting kNoLocationPeriodSec and // ensure that no location is received yet - wait(kNoLocationPeriodSec); + gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, kNoLocationPeriodSec); + const int location_called_count = gnss_cb_->location_cbq_.calledCount(); + // Tolerate (ignore) one extra location right after the first one // to handle startup edge case scheduling limitations in some implementations - if ((i == 1) && (location_called_count_ == 2)) { - CheckLocation(last_location_, true); + if ((i == 1) && (location_called_count == 2)) { + CheckLocation(gnss_cb_->last_location_, true); continue; // restart the quiet wait period after this too-fast location } - EXPECT_LE(location_called_count_, i); - if (location_called_count_ != i) { + EXPECT_LE(location_called_count, i); + if (location_called_count != i) { ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ", - location_called_count_, i); + location_called_count, i); } - if (std::cv_status::no_timeout != - wait(kLocationTimeoutSubsequentSec - kNoLocationPeriodSec)) { + if (!gnss_cb_->location_cbq_.retrieve( + gnss_cb_->last_location_, + kLocationTimeoutSubsequentSec - kNoLocationPeriodSec)) { ALOGW("GetLocationLowPower test - timeout awaiting location %d", i); } else { - CheckLocation(last_location_, true); + CheckLocation(gnss_cb_->last_location_, true); } } @@ -222,12 +227,15 @@ TEST_F(GnssHalTest, BlacklistIndividualSatellites) { const int kLocationsToAwait = 3; const int kRetriesToUnBlacklist = 10; + gnss_cb_->location_cbq_.reset(); StartAndCheckLocations(kLocationsToAwait); + int location_called_count = gnss_cb_->location_cbq_.calledCount(); // Tolerate 1 less sv status to handle edge cases in reporting. - EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait); - ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", - (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_); + int sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size(); + EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait); + ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", sv_status_cbq_size, + kLocationsToAwait, location_called_count); /* * Identify strongest SV seen at least kLocationsToAwait -1 times @@ -235,8 +243,14 @@ TEST_F(GnssHalTest, BlacklistIndividualSatellites) { * observability (one epoch RF null) */ + const int kGnssSvStatusTimeout = 2; + list sv_status_list; + int count = gnss_cb_->sv_status_cbq_.retrieve(sv_status_list, sv_status_cbq_size, + kGnssSvStatusTimeout); + ASSERT_EQ(count, sv_status_cbq_size); + IGnssConfiguration::BlacklistedSource source_to_blacklist = - FindStrongFrequentNonGpsSource(list_gnss_sv_status_, kLocationsToAwait - 1); + FindStrongFrequentNonGpsSource(sv_status_list, kLocationsToAwait - 1); if (source_to_blacklist.constellation == GnssConstellationType::UNKNOWN) { // Cannot find a non-GPS satellite. Let the test pass. @@ -260,21 +274,26 @@ TEST_F(GnssHalTest, BlacklistIndividualSatellites) { EXPECT_TRUE(result); // retry and ensure satellite not used - list_gnss_sv_status_.clear(); + gnss_cb_->sv_status_cbq_.reset(); + gnss_cb_->location_cbq_.reset(); StartAndCheckLocations(kLocationsToAwait); // early exit if test is being run with insufficient signal - if (location_called_count_ == 0) { + location_called_count = gnss_cb_->location_cbq_.calledCount(); + if (location_called_count == 0) { ALOGE("0 Gnss locations received - ensure sufficient signal and retry"); } - ASSERT_TRUE(location_called_count_ > 0); + ASSERT_TRUE(location_called_count > 0); // Tolerate 1 less sv status to handle edge cases in reporting. - EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait); - ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", - (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_); - for (const auto& gnss_sv_status : list_gnss_sv_status_) { + sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size(); + EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait); + ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", sv_status_cbq_size, + kLocationsToAwait, location_called_count); + for (int i = 0; i < sv_status_cbq_size; ++i) { + IGnssCallback::GnssSvStatus gnss_sv_status; + gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout); for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) { const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv]; EXPECT_FALSE((gnss_sv.svid == source_to_blacklist.svid) && @@ -295,24 +314,28 @@ TEST_F(GnssHalTest, BlacklistIndividualSatellites) { int unblacklist_loops_remaining = kRetriesToUnBlacklist; while (!strongest_sv_is_reobserved && (unblacklist_loops_remaining-- > 0)) { StopAndClearLocations(); - list_gnss_sv_status_.clear(); + gnss_cb_->sv_status_cbq_.reset(); + gnss_cb_->location_cbq_.reset(); StartAndCheckLocations(kLocationsToAwait); // early exit loop if test is being run with insufficient signal - if (location_called_count_ == 0) { + location_called_count = gnss_cb_->location_cbq_.calledCount(); + if (location_called_count == 0) { ALOGE("0 Gnss locations received - ensure sufficient signal and retry"); } - ASSERT_TRUE(location_called_count_ > 0); + ASSERT_TRUE(location_called_count > 0); // Tolerate 1 less sv status to handle edge cases in reporting. - EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait); - ALOGD( - "Clear blacklist, observed %d GnssSvStatus, while awaiting %d Locations" - ", tries remaining %d", - (int)list_gnss_sv_status_.size(), kLocationsToAwait, unblacklist_loops_remaining); + sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size(); + EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait); + ALOGD("Clear blacklist, observed %d GnssSvStatus, while awaiting %d Locations" + ", tries remaining %d", + sv_status_cbq_size, kLocationsToAwait, unblacklist_loops_remaining); - for (const auto& gnss_sv_status : list_gnss_sv_status_) { + for (int i = 0; i < sv_status_cbq_size; ++i) { + IGnssCallback::GnssSvStatus gnss_sv_status; + gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout); for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) { const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv]; if ((gnss_sv.svid == source_to_blacklist.svid) && @@ -347,16 +370,22 @@ TEST_F(GnssHalTest, BlacklistConstellation) { 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. - EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait); - ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", - (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_); + int sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size(); + EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait); + ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", sv_status_cbq_size, + kLocationsToAwait, location_called_count); // Find first non-GPS constellation to blacklist + const int kGnssSvStatusTimeout = 2; GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN; - for (const auto& gnss_sv_status : list_gnss_sv_status_) { + for (int i = 0; i < sv_status_cbq_size; ++i) { + IGnssCallback::GnssSvStatus gnss_sv_status; + gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout); for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) { const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv]; if ((gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) && @@ -395,16 +424,19 @@ TEST_F(GnssHalTest, BlacklistConstellation) { EXPECT_TRUE(result); // retry and ensure constellation not used - list_gnss_sv_status_.clear(); + gnss_cb_->sv_status_cbq_.reset(); - location_called_count_ = 0; + gnss_cb_->location_cbq_.reset(); StartAndCheckLocations(kLocationsToAwait); // Tolerate 1 less sv status to handle edge cases in reporting. - EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait); - ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(), + sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size(); + EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait); + ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_status_cbq_size, kLocationsToAwait); - for (const auto& gnss_sv_status : list_gnss_sv_status_) { + for (int i = 0; i < sv_status_cbq_size; ++i) { + IGnssCallback::GnssSvStatus gnss_sv_status; + gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout); for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) { const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv]; EXPECT_FALSE((gnss_sv.constellation == source_to_blacklist.constellation) && @@ -427,7 +459,7 @@ TEST_F(GnssHalTest, BlacklistConstellation) { */ TEST_F(GnssHalTest, InjectBestLocation) { StartAndCheckLocations(1); - GnssLocation gnssLocation = last_location_; + GnssLocation gnssLocation = gnss_cb_->last_location_; CheckLocation(gnssLocation, true); auto result = gnss_hal_->injectBestLocation(gnssLocation); @@ -447,7 +479,7 @@ TEST_F(GnssHalTest, InjectBestLocation) { TEST_F(GnssHalTest, GnssDebugValuesSanityTest) { auto gnssDebug = gnss_hal_->getExtensionGnssDebug(); ASSERT_TRUE(gnssDebug.isOk()); - if (info_called_count_ > 0 && last_info_.yearOfHw >= 2017) { + if (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017) { sp iGnssDebug = gnssDebug; EXPECT_NE(iGnssDebug, nullptr); diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h index 90a7866082..7d07c0f423 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test.h +++ b/gnss/2.0/vts/functional/gnss_hal_test.h @@ -17,19 +17,16 @@ #ifndef GNSS_HAL_TEST_H_ #define GNSS_HAL_TEST_H_ -#include #include #include - -#include -#include -#include -#include +#include +#include "GnssCallbackEventQueue.h" using android::hardware::hidl_vec; using android::hardware::Return; using android::hardware::Void; +using android::hardware::gnss::common::GnssCallbackEventQueue; using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback; using android::hardware::gnss::V1_0::GnssLocationFlags; using android::hardware::gnss::V2_0::IGnss; @@ -70,50 +67,6 @@ class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase { virtual void TearDown() override; - /* Producer/consumer queue for storing/retrieving callback events from GNSS HAL */ - template - class CallbackQueue { - public: - CallbackQueue(const std::string& name) : name_(name), called_count_(0){}; - ~CallbackQueue() { reset(); } - - /* Adds callback event to the end of the queue. */ - void store(const T& event); - - /* - * Removes the callack event at the front of the queue, stores it in event parameter - * and returns true. Returns false on timeout and event is not populated. - */ - bool retrieve(T& event, int timeout_seconds); - - /* - * Removes parameter count number of callack events at the front of the queue, stores - * them in event_list parameter and returns the number of events retrieved. Waits up to - * timeout_seconds to retrieve each event. If timeout occurs, it returns the number of - * items retrieved which will be less than count. - */ - int retrieve(list& event_list, int count, int timeout_seconds); - - /* Returns the number of events pending to be retrieved from the callback event queue. */ - int size() const; - - /* Returns the number of callback events received since last reset(). */ - int calledCount() const; - - /* Clears the callback event queue and resets the calledCount() to 0. */ - void reset(); - - private: - CallbackQueue(const CallbackQueue&) = delete; - CallbackQueue& operator=(const CallbackQueue&) = delete; - - std::string name_; - int called_count_; - mutable std::recursive_mutex mtx_; - std::condition_variable_any cv_; - std::deque events_; - }; - /* Callback class for data & Event. */ class GnssCallback : public IGnssCallback_2_0 { public: @@ -122,11 +75,11 @@ class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase { uint32_t last_capabilities_; GnssLocation_2_0 last_location_; - CallbackQueue info_cbq_; - CallbackQueue name_cbq_; - CallbackQueue capabilities_cbq_; - CallbackQueue location_cbq_; - CallbackQueue> sv_info_list_cbq_; + GnssCallbackEventQueue info_cbq_; + GnssCallbackEventQueue name_cbq_; + GnssCallbackEventQueue capabilities_cbq_; + GnssCallbackEventQueue location_cbq_; + GnssCallbackEventQueue> sv_info_list_cbq_; GnssCallback(); virtual ~GnssCallback() = default; @@ -169,7 +122,7 @@ class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase { /* Callback class for GnssMeasurement. */ class GnssMeasurementCallback : public IGnssMeasurementCallback_2_0 { public: - CallbackQueue measurement_cbq_; + GnssCallbackEventQueue measurement_cbq_; GnssMeasurementCallback() : measurement_cbq_("measurement"){}; virtual ~GnssMeasurementCallback() = default; @@ -192,7 +145,7 @@ class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase { class GnssMeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback { public: uint32_t last_capabilities_; - CallbackQueue capabilities_cbq_; + GnssCallbackEventQueue capabilities_cbq_; GnssMeasurementCorrectionsCallback() : capabilities_cbq_("capabilities"){}; virtual ~GnssMeasurementCorrectionsCallback() = default; @@ -252,61 +205,4 @@ class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase { sp gnss_cb_; // Primary callback interface }; -template -void GnssHalTest::CallbackQueue::store(const T& event) { - std::unique_lock lock(mtx_); - events_.push_back(event); - ++called_count_; - lock.unlock(); - cv_.notify_all(); -} - -template -bool GnssHalTest::CallbackQueue::retrieve(T& event, int timeout_seconds) { - std::unique_lock lock(mtx_); - cv_.wait_for(lock, std::chrono::seconds(timeout_seconds), [&] { return !events_.empty(); }); - if (events_.empty()) { - return false; - } - event = events_.front(); - events_.pop_front(); - return true; -} - -template -int GnssHalTest::CallbackQueue::retrieve(list& event_list, int count, int timeout_seconds) { - for (int i = 0; i < count; ++i) { - T event; - if (!retrieve(event, timeout_seconds)) { - return i; - } - event_list.push_back(event); - } - - return count; -} - -template -int GnssHalTest::CallbackQueue::size() const { - std::unique_lock lock(mtx_); - return events_.size(); -} - -template -int GnssHalTest::CallbackQueue::calledCount() const { - std::unique_lock lock(mtx_); - return called_count_; -} - -template -void GnssHalTest::CallbackQueue::reset() { - std::unique_lock lock(mtx_); - if (!events_.empty()) { - ALOGW("%u unprocessed events discarded in callback queue %s", (unsigned int)events_.size(), - name_.c_str()); - } - events_.clear(); - called_count_ = 0; -} - #endif // GNSS_HAL_TEST_H_ 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 39736cc250..ca3edc57d4 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp @@ -453,18 +453,18 @@ TEST_F(GnssHalTest, GetLocationLowPower) { // ensure that no location is received yet gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, kNoLocationPeriodSec); - const int locationCalledCount = gnss_cb_->location_cbq_.calledCount(); + const int location_called_count = gnss_cb_->location_cbq_.calledCount(); // Tolerate (ignore) one extra location right after the first one // to handle startup edge case scheduling limitations in some implementations - if ((i == 1) && (locationCalledCount == 2)) { + if ((i == 1) && (location_called_count == 2)) { CheckLocation(gnss_cb_->last_location_, true); continue; // restart the quiet wait period after this too-fast location } - EXPECT_LE(locationCalledCount, i); - if (locationCalledCount != i) { + EXPECT_LE(location_called_count, i); + if (location_called_count != i) { ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ", - locationCalledCount, i); + location_called_count, i); } if (!gnss_cb_->location_cbq_.retrieve( diff --git a/gnss/common/utils/vts/include/GnssCallbackEventQueue.h b/gnss/common/utils/vts/include/GnssCallbackEventQueue.h new file mode 100644 index 0000000000..b1d8ed4e36 --- /dev/null +++ b/gnss/common/utils/vts/include/GnssCallbackEventQueue.h @@ -0,0 +1,140 @@ +/* + * 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. + */ + +#ifndef android_hardware_gnss_common_vts_GnssCallbackEventQueue_H_ +#define android_hardware_gnss_common_vts_GnssCallbackEventQueue_H_ + +#include + +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +/* + * Producer/consumer queue for storing/retrieving callback events from GNSS HAL. + */ +template +class GnssCallbackEventQueue { + public: + GnssCallbackEventQueue(const std::string& name) : name_(name), called_count_(0){}; + ~GnssCallbackEventQueue() { reset(); } + + /* Adds callback event to the end of the queue. */ + void store(const T& event); + + /* + * Removes the callack event at the front of the queue, stores it in event parameter + * and returns true. Returns false on timeout and event is not populated. + */ + bool retrieve(T& event, int timeout_seconds); + + /* + * Removes parameter count number of callack events at the front of the queue, stores + * them in event_list parameter and returns the number of events retrieved. Waits up to + * timeout_seconds to retrieve each event. If timeout occurs, it returns the number of + * items retrieved which will be less than count. + */ + int retrieve(list& event_list, int count, int timeout_seconds); + + /* Returns the number of events pending to be retrieved from the callback event queue. */ + int size() const; + + /* Returns the number of callback events received since last reset(). */ + int calledCount() const; + + /* Clears the callback event queue and resets the calledCount() to 0. */ + void reset(); + + private: + GnssCallbackEventQueue(const GnssCallbackEventQueue&) = delete; + GnssCallbackEventQueue& operator=(const GnssCallbackEventQueue&) = delete; + + std::string name_; + int called_count_; + mutable std::recursive_mutex mtx_; + std::condition_variable_any cv_; + std::deque events_; +}; + +template +void GnssCallbackEventQueue::store(const T& event) { + std::unique_lock lock(mtx_); + events_.push_back(event); + ++called_count_; + lock.unlock(); + cv_.notify_all(); +} + +template +bool GnssCallbackEventQueue::retrieve(T& event, int timeout_seconds) { + std::unique_lock lock(mtx_); + cv_.wait_for(lock, std::chrono::seconds(timeout_seconds), [&] { return !events_.empty(); }); + if (events_.empty()) { + return false; + } + event = events_.front(); + events_.pop_front(); + return true; +} + +template +int GnssCallbackEventQueue::retrieve(list& event_list, int count, int timeout_seconds) { + for (int i = 0; i < count; ++i) { + T event; + if (!retrieve(event, timeout_seconds)) { + return i; + } + event_list.push_back(event); + } + + return count; +} + +template +int GnssCallbackEventQueue::size() const { + std::unique_lock lock(mtx_); + return events_.size(); +} + +template +int GnssCallbackEventQueue::calledCount() const { + std::unique_lock lock(mtx_); + return called_count_; +} + +template +void GnssCallbackEventQueue::reset() { + std::unique_lock lock(mtx_); + if (!events_.empty()) { + ALOGW("%u unprocessed events discarded in callback queue %s", (unsigned int)events_.size(), + name_.c_str()); + } + events_.clear(); + called_count_ = 0; +} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_vts_GnssCallbackEventQueue_H_ From 57800d71f6df98e1b15409319e0ad34e45e19997 Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Wed, 31 Jul 2019 09:46:06 -0400 Subject: [PATCH 0045/1022] Update OWNERS for sensors HAL Changes sensors team owners to reflect the current owners on the team. Test: N/A Change-Id: Ic5b957bc65688ffb2bce7d0eab256a5153b61efd --- sensors/1.0/default/OWNERS | 3 ++- sensors/1.0/vts/functional/OWNERS | 3 ++- sensors/2.0/default/OWNERS | 3 ++- sensors/2.0/vts/functional/OWNERS | 3 ++- sensors/common/vts/OWNERS | 3 ++- sensors/common/vts/utils/OWNERS | 3 ++- 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/sensors/1.0/default/OWNERS b/sensors/1.0/default/OWNERS index 2031d848cf..90c233030e 100644 --- a/sensors/1.0/default/OWNERS +++ b/sensors/1.0/default/OWNERS @@ -1,2 +1,3 @@ +arthuri@google.com bduddie@google.com -bstack@google.com +stange@google.com diff --git a/sensors/1.0/vts/functional/OWNERS b/sensors/1.0/vts/functional/OWNERS index 759d87b482..892da1548c 100644 --- a/sensors/1.0/vts/functional/OWNERS +++ b/sensors/1.0/vts/functional/OWNERS @@ -1,6 +1,7 @@ # Sensors team +arthuri@google.com bduddie@google.com -bstack@google.com +stange@google.com # VTS team trong@google.com diff --git a/sensors/2.0/default/OWNERS b/sensors/2.0/default/OWNERS index 2031d848cf..90c233030e 100644 --- a/sensors/2.0/default/OWNERS +++ b/sensors/2.0/default/OWNERS @@ -1,2 +1,3 @@ +arthuri@google.com bduddie@google.com -bstack@google.com +stange@google.com diff --git a/sensors/2.0/vts/functional/OWNERS b/sensors/2.0/vts/functional/OWNERS index 759d87b482..892da1548c 100644 --- a/sensors/2.0/vts/functional/OWNERS +++ b/sensors/2.0/vts/functional/OWNERS @@ -1,6 +1,7 @@ # Sensors team +arthuri@google.com bduddie@google.com -bstack@google.com +stange@google.com # VTS team trong@google.com diff --git a/sensors/common/vts/OWNERS b/sensors/common/vts/OWNERS index 759d87b482..892da1548c 100644 --- a/sensors/common/vts/OWNERS +++ b/sensors/common/vts/OWNERS @@ -1,6 +1,7 @@ # Sensors team +arthuri@google.com bduddie@google.com -bstack@google.com +stange@google.com # VTS team trong@google.com diff --git a/sensors/common/vts/utils/OWNERS b/sensors/common/vts/utils/OWNERS index 759d87b482..892da1548c 100644 --- a/sensors/common/vts/utils/OWNERS +++ b/sensors/common/vts/utils/OWNERS @@ -1,6 +1,7 @@ # Sensors team +arthuri@google.com bduddie@google.com -bstack@google.com +stange@google.com # VTS team trong@google.com From 1d0f024bd7b39cab38b78504d9c50dfd6c477d6a Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Thu, 18 Jul 2019 10:00:12 -0700 Subject: [PATCH 0046/1022] Update comments on EVS 1.0 interfaces This change fixes hidl-lint errors and warnings in EVS 1.0 interface definitions. Bug: 135472573 Change-Id: I4b6b5df792875a8dde2ee146f88fb401a4d5e860 Signed-off-by: Changyeon Jo --- automotive/evs/1.0/IEvsCamera.hal | 31 ++++++++--- automotive/evs/1.0/IEvsCameraStream.hal | 2 + automotive/evs/1.0/IEvsDisplay.hal | 21 ++++++-- automotive/evs/1.0/IEvsEnumerator.hal | 19 ++++--- automotive/evs/1.0/types.hal | 70 +++++++++++++++++++------ 5 files changed, 108 insertions(+), 35 deletions(-) diff --git a/automotive/evs/1.0/IEvsCamera.hal b/automotive/evs/1.0/IEvsCamera.hal index dbcaf9288c..464dafba75 100644 --- a/automotive/evs/1.0/IEvsCamera.hal +++ b/automotive/evs/1.0/IEvsCamera.hal @@ -16,7 +16,6 @@ package android.hardware.automotive.evs@1.0; -import types; import IEvsCameraStream; @@ -28,8 +27,8 @@ interface IEvsCamera { /** * Returns the ID of this camera. * - * Returns the description of this camera. This must be the same value as reported - * by EvsEnumerator::getCamerList(). + * @return info The description of this camera. This must be the same value as + * reported by EvsEnumerator::getCameraList(). */ getCameraInfo() generates (CameraDesc info); @@ -43,16 +42,20 @@ interface IEvsCamera { * in which case buffers should be added or removed from the chain as appropriate. * If no call is made to this entry point, the IEvsCamera must support at least one * frame by default. More is acceptable. - * BUFFER_NOT_AVAILABLE is returned if the implementation cannot support the - * requested number of concurrent frames. + * + * @param bufferCount Number of buffers the client of IEvsCamera may hold concurrently. + * @return result EvsResult::OK is returned if this call is successful. */ setMaxFramesInFlight(uint32_t bufferCount) generates (EvsResult result); /** - * Request delivery of EVS camera frames from this camera. + * Request to start EVS camera stream from this camera. * - * The IEvsCameraStream must begin receiving periodic calls with new image - * frames until stopVideoStream() is called. + * The IEvsCameraStream must begin receiving calls with various events + * including new image frame ready until stopVideoStream() is called. + * + * @param receiver IEvsCameraStream implementation. + * @return result EvsResult::OK is returned if this call is successful. */ startVideoStream(IEvsCameraStream receiver) generates (EvsResult result); @@ -64,6 +67,8 @@ interface IEvsCamera { * A small, finite number of buffers are available (possibly as small * as one), and if the supply is exhausted, no further frames may be * delivered until a buffer is returned. + * + * @param buffer A buffer to be returned. */ oneway doneWithFrame(BufferDesc buffer); @@ -83,6 +88,11 @@ interface IEvsCamera { * The values allowed for opaqueIdentifier are driver specific, * but no value passed in may crash the driver. The driver should * return 0 for any unrecognized opaqueIdentifier. + * + * @param opaqueIdentifier An unique identifier of the information to + * request. + * @return value Requested information. Zero is returned if the + * driver does not recognize a given identifier. */ getExtendedInfo(uint32_t opaqueIdentifier) generates (int32_t value); @@ -94,6 +104,11 @@ interface IEvsCamera { * in order to function in a default state. * INVALID_ARG is returned if the opaqueValue is not meaningful to * the driver implementation. + * + * @param opaqueIdentifier An unique identifier of the information to + * program. + * opaqueValue A value to program. + * @return result EvsResult::OK is returned if this call is successful. */ setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) generates (EvsResult result); }; diff --git a/automotive/evs/1.0/IEvsCameraStream.hal b/automotive/evs/1.0/IEvsCameraStream.hal index 4e743b2683..ec18f6a822 100644 --- a/automotive/evs/1.0/IEvsCameraStream.hal +++ b/automotive/evs/1.0/IEvsCameraStream.hal @@ -31,6 +31,8 @@ interface IEvsCameraStream { * When the last frame in the stream has been delivered, a NULL bufferHandle * must be delivered, signifying the end of the stream. No further frame * deliveries may happen thereafter. + * + * @param buffer a buffer descriptor of a delivered image frame. */ oneway deliverFrame(BufferDesc buffer); }; diff --git a/automotive/evs/1.0/IEvsDisplay.hal b/automotive/evs/1.0/IEvsDisplay.hal index 12541f3513..72f767e9c0 100644 --- a/automotive/evs/1.0/IEvsDisplay.hal +++ b/automotive/evs/1.0/IEvsDisplay.hal @@ -16,8 +16,6 @@ package android.hardware.automotive.evs@1.0; -import types; - /** * Represents a single camera and is the primary interface for capturing images. @@ -28,6 +26,9 @@ interface IEvsDisplay { * Returns basic information about the EVS display provided by the system. * * See the description of the DisplayDesc structure for details. + * + * @return info The description of this display. Please see the description + * of the DisplayDesc structure for details. */ getDisplayInfo() generates (DisplayDesc info); @@ -42,6 +43,9 @@ interface IEvsDisplay { * video. When the display is no longer required, the client is expected to request * the NOT_VISIBLE state after passing the last video frame. * Returns INVALID_ARG if the requested state is not a recognized value. + * + * @param state Desired new DisplayState. + * @return result EvsResult::OK is returned if this call is successful. */ setDisplayState(DisplayState state) generates (EvsResult result); @@ -54,6 +58,8 @@ interface IEvsDisplay { * the logic responsible for changing display states should generally live above * the device layer, making it undesirable for the HAL implementation to spontaneously * change display states. + * + * @return state Current DisplayState of this Display. */ getDisplayState() generates (DisplayState state); @@ -61,9 +67,11 @@ interface IEvsDisplay { /** * This call returns a handle to a frame buffer associated with the display. * - * The returned buffer may be locked and written to by software and/or GL. This buffer - * must be returned via a call to returnTargetBufferForDisplay() even if the - * display is no longer visible. + * @return buffer A handle to a frame buffer. The returned buffer may be + * locked and written to by software and/or GL. This buffer + * must be returned via a call to + * returnTargetBufferForDisplay() even if the display is no + * longer visible. */ getTargetBuffer() generates (BufferDesc buffer); @@ -75,6 +83,9 @@ interface IEvsDisplay { * There is no maximum time the caller may hold onto the buffer before making this * call. The buffer may be returned at any time and in any DisplayState, but all * buffers are expected to be returned before the IEvsDisplay interface is destroyed. + * + * @param buffer A buffer handle to the frame that is ready for display. + * @return result EvsResult::OK is returned if this call is successful. */ returnTargetBufferForDisplay(BufferDesc buffer) generates (EvsResult result); }; diff --git a/automotive/evs/1.0/IEvsEnumerator.hal b/automotive/evs/1.0/IEvsEnumerator.hal index ee51e7e994..e5633df973 100644 --- a/automotive/evs/1.0/IEvsEnumerator.hal +++ b/automotive/evs/1.0/IEvsEnumerator.hal @@ -16,7 +16,6 @@ package android.hardware.automotive.evs@1.0; -import types; import IEvsCamera; import IEvsDisplay; @@ -28,6 +27,8 @@ interface IEvsEnumerator { /** * Returns a list of all EVS cameras available to the system + * + * @return cameras A list of cameras availale for EVS service. */ getCameraList() generates (vec cameras); @@ -37,9 +38,9 @@ interface IEvsEnumerator { * Given a camera's unique cameraId from CameraDesc, returns the * IEvsCamera interface associated with the specified camera. When * done using the camera, the caller may release it by calling closeCamera(). - * Note: Reliance on the sp<> going out of scope is not recommended - * because the resources may not be released right away due to asynchronos - * behavior in the hardware binder (ref b/36122635). + * + * @param cameraId A unique identifier of the camera. + * @return carCamera EvsCamera object associated with a given cameraId. */ openCamera(string cameraId) generates (IEvsCamera carCamera); @@ -48,6 +49,8 @@ interface IEvsEnumerator { * * When the IEvsCamera object is no longer required, it must be released. * NOTE: Video streaming must be cleanly stopped before making this call. + * + * @param carCamera EvsCamera object to be closed. */ closeCamera(IEvsCamera carCamera); @@ -60,8 +63,8 @@ interface IEvsEnumerator { * the old instance shall be closed and give the new caller exclusive * access. * When done using the display, the caller may release it by calling closeDisplay(). - * TODO(b/36122635) Reliance on the sp<> going out of scope is not recommended because the - * resources may not be released right away due to asynchronos behavior in the hardware binder. + * + * @return display EvsDisplay object to be used. */ openDisplay() generates (IEvsDisplay display); @@ -70,6 +73,8 @@ interface IEvsEnumerator { * * When the IEvsDisplay object is no longer required, it must be released. * NOTE: All buffers must have been returned to the display before making this call. + * + * @param display EvsDisplay object to be closed. */ closeDisplay(IEvsDisplay display); @@ -80,6 +85,8 @@ interface IEvsEnumerator { * the actual state of the active display. This call is replicated on the IEvsEnumerator * interface in order to allow secondary clients to monitor the state of the EVS display * without acquiring exclusive ownership of the display. + * + * @return state Current DisplayState of this Display. */ getDisplayState() generates (DisplayState state); }; diff --git a/automotive/evs/1.0/types.hal b/automotive/evs/1.0/types.hal index 7cebf6d179..1efd5ebf3d 100644 --- a/automotive/evs/1.0/types.hal +++ b/automotive/evs/1.0/types.hal @@ -24,8 +24,15 @@ package android.hardware.automotive.evs@1.0; * EVS camera in the system. */ struct CameraDesc { + /* Unique identifier for camera devices. This may be a path to detected + * camera device; for example, "/dev/video0". + */ string cameraId; - uint32_t vendorFlags; // Opaque value from driver + + /* Opaque value from driver. Vendor may use this field to store additional + * information; for example, sensor and bridge chip id. + */ + uint32_t vendorFlags; }; @@ -38,8 +45,11 @@ struct CameraDesc { * presentation device. */ struct DisplayDesc { + /* Unique identifier for the display */ string displayId; - uint32_t vendorFlags; // Opaque value from driver + + /* Opaque value from driver */ + uint32_t vendorFlags; }; @@ -56,14 +66,31 @@ struct DisplayDesc { * Specifically consider if format and/or usage should become enumerated types. */ struct BufferDesc { - uint32_t width; // Units of pixels - uint32_t height; // Units of pixels - uint32_t stride; // Units of pixels to match gralloc - uint32_t pixelSize; // Units of bytes - uint32_t format; // May contain values from android_pixel_format_t - uint32_t usage; // May contain values from from Gralloc.h - uint32_t bufferId; // Opaque value from driver - handle memHandle; // gralloc memory buffer handle + /* A frame width in the units of pixels */ + uint32_t width; + + /* A frame height in the units of pixels */ + uint32_t height; + + /* A frame stride in the units of pixels, to match gralloc */ + uint32_t stride; + + /* The size of a pixel in the units of bytes */ + uint32_t pixelSize; + + /* The image format of the frame; may contain values from + * android_pixel_format_t + */ + uint32_t format; + + /* May contain values from Gralloc.h */ + uint32_t usage; + + /* Opaque value from driver */ + uint32_t bufferId; + + /* Gralloc memory buffer handle */ + handle memHandle; }; @@ -77,12 +104,23 @@ struct BufferDesc { * presentation device. */ enum DisplayState : uint32_t { - NOT_OPEN = 0, // Display has not been requested by any application - NOT_VISIBLE, // Display is inhibited - VISIBLE_ON_NEXT_FRAME, // Will become visible with next frame - VISIBLE, // Display is currently active - DEAD, // Driver is in an undefined state. Interface should be closed. - NUM_STATES // Must be last + /* Display has not been requested by any application yet */ + NOT_OPEN = 0, + + /* Display is inhibited */ + NOT_VISIBLE, + + /* Will become visible with next frame */ + VISIBLE_ON_NEXT_FRAME, + + /* Display is currently active */ + VISIBLE, + + /* Driver is in an undefined state. Interface should be closed. */ + DEAD, + + /* Must be the last */ + NUM_STATES }; From e472971e9644f45997eb77f01001a2ce27d75cce Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Mon, 29 Jul 2019 08:21:29 -0700 Subject: [PATCH 0047/1022] Move utility functions to a common library This change creates a library that contains utility functions commonly used in different EVS versions. Bug: 13542573 Test: VTS Change-Id: Ica8f5e6228d7d4b1426d8cc9cd2c570d6b584897 Signed-off-by: Changyeon Jo --- ...oid.hardware.automotive.evs@1.0-service.rc | 1 + automotive/evs/1.0/vts/functional/Android.bp | 6 +- .../evs/1.0/vts/functional/FormatConvert.h | 74 -------------- .../evs/1.0/vts/functional/FrameHandler.cpp | 53 +++++----- .../evs/common/utils/default/Android.bp | 31 ++++++ .../utils/default}/FormatConvert.cpp | 72 ++++++++------ .../utils/default/include/FormatConvert.h | 99 +++++++++++++++++++ 7 files changed, 205 insertions(+), 131 deletions(-) delete mode 100644 automotive/evs/1.0/vts/functional/FormatConvert.h create mode 100644 automotive/evs/common/utils/default/Android.bp rename automotive/evs/{1.0/vts/functional => common/utils/default}/FormatConvert.cpp (74%) create mode 100644 automotive/evs/common/utils/default/include/FormatConvert.h diff --git a/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc b/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc index 117c249a51..8dcd9694b0 100644 --- a/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc +++ b/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc @@ -2,3 +2,4 @@ service vendor.evs-hal-mock /vendor/bin/hw/android.hardware.automotive.evs@1.0-s class hal user automotive_evs group automotive_evs + disabled # do not start automatically diff --git a/automotive/evs/1.0/vts/functional/Android.bp b/automotive/evs/1.0/vts/functional/Android.bp index 2ef33fdd11..8988bfd8b1 100644 --- a/automotive/evs/1.0/vts/functional/Android.bp +++ b/automotive/evs/1.0/vts/functional/Android.bp @@ -19,13 +19,15 @@ cc_test { srcs: [ "VtsHalEvsV1_0TargetTest.cpp", "FrameHandler.cpp", - "FormatConvert.cpp" ], defaults: ["VtsHalTargetTestDefaults"], shared_libs: [ "libui", ], - static_libs: ["android.hardware.automotive.evs@1.0"], + static_libs: [ + "android.hardware.automotive.evs@1.0", + "android.hardware.automotive.evs@common-default-lib", + ], test_suites: ["general-tests"], cflags: [ "-O0", diff --git a/automotive/evs/1.0/vts/functional/FormatConvert.h b/automotive/evs/1.0/vts/functional/FormatConvert.h deleted file mode 100644 index 4a94f996d0..0000000000 --- a/automotive/evs/1.0/vts/functional/FormatConvert.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2017 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 EVS_VTS_FORMATCONVERT_H -#define EVS_VTS_FORMATCONVERT_H - -#include -#include - - -// Given an image buffer in NV21 format (HAL_PIXEL_FORMAT_YCRCB_420_SP), output 32bit RGBx/BGRx -// values. The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved -// U/V array. It assumes an even width and height for the overall image, and a horizontal -// stride that is an even multiple of 16 bytes for both the Y and UV arrays. -void copyNV21toRGB32(unsigned width, unsigned height, - uint8_t* src, - uint32_t* dst, unsigned dstStridePixels, - bool bgrxFormat = false); - -void copyNV21toBGR32(unsigned width, unsigned height, - uint8_t* src, - uint32_t* dst, unsigned dstStridePixels); - - -// Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx/BGRx values. -// The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed -// by another 1/2 x 1/2 V array. It assumes an even width and height for the overall image, -// and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U, -// and V arrays. -void copyYV12toRGB32(unsigned width, unsigned height, - uint8_t* src, - uint32_t* dst, unsigned dstStridePixels, - bool bgrxFormat = false); - -void copyYV12toBGR32(unsigned width, unsigned height, - uint8_t* src, - uint32_t* dst, unsigned dstStridePixels); - -// Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx/BGRx -// values. The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved -// U/V array. It assumes an even width and height for the overall image, and a horizontal -// stride that is an even multiple of 16 bytes for both the Y and UV arrays. -void copyYUYVtoRGB32(unsigned width, unsigned height, - uint8_t* src, unsigned srcStrideBytes, - uint32_t* dst, unsigned dstStrideBytes, - bool bgrxFormat = false); - -void copyYUYVtoBGR32(unsigned width, unsigned height, - uint8_t* src, unsigned srcStrideBytes, - uint32_t* dst, unsigned dstStrideBytes); - - -// Given an simple rectangular image buffer with an integer number of bytes per pixel, -// copy the pixel values into a new rectangular buffer (potentially with a different stride). -// This is typically used to copy RGBx data into an RGBx output buffer. -void copyMatchedInterleavedFormats(unsigned width, unsigned height, - void* src, unsigned srcStridePixels, - void* dst, unsigned dstStridePixels, - unsigned pixelSize); - -#endif // EVS_VTS_FORMATCONVERT_H diff --git a/automotive/evs/1.0/vts/functional/FrameHandler.cpp b/automotive/evs/1.0/vts/functional/FrameHandler.cpp index bc3790f385..6a01a44dfe 100644 --- a/automotive/evs/1.0/vts/functional/FrameHandler.cpp +++ b/automotive/evs/1.0/vts/functional/FrameHandler.cpp @@ -240,46 +240,47 @@ bool FrameHandler::copyBufferContents(const BufferDesc& tgtBuffer, tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels); if (srcPixels && tgtPixels) { + using namespace ::android::hardware::automotive::evs::common; if (tgtBuffer.format == HAL_PIXEL_FORMAT_RGBA_8888) { if (srcBuffer.format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21 - copyNV21toRGB32(width, height, - srcPixels, - tgtPixels, tgtBuffer.stride); + Utils::copyNV21toRGB32(width, height, + srcPixels, + tgtPixels, tgtBuffer.stride); } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12 - copyYV12toRGB32(width, height, - srcPixels, - tgtPixels, tgtBuffer.stride); + Utils::copyYV12toRGB32(width, height, + srcPixels, + tgtPixels, tgtBuffer.stride); } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV - copyYUYVtoRGB32(width, height, - srcPixels, srcBuffer.stride, - tgtPixels, tgtBuffer.stride); + Utils::copyYUYVtoRGB32(width, height, + srcPixels, srcBuffer.stride, + tgtPixels, tgtBuffer.stride); } else if (srcBuffer.format == tgtBuffer.format) { // 32bit RGBA - copyMatchedInterleavedFormats(width, height, - srcPixels, srcBuffer.stride, - tgtPixels, tgtBuffer.stride, - tgtBuffer.pixelSize); + Utils::copyMatchedInterleavedFormats(width, height, + srcPixels, srcBuffer.stride, + tgtPixels, tgtBuffer.stride, + tgtBuffer.pixelSize); } else { ALOGE("Camera buffer format is not supported"); success = false; } } else if (tgtBuffer.format == HAL_PIXEL_FORMAT_BGRA_8888) { if (srcBuffer.format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21 - copyNV21toBGR32(width, height, - srcPixels, - tgtPixels, tgtBuffer.stride); + Utils::copyNV21toBGR32(width, height, + srcPixels, + tgtPixels, tgtBuffer.stride); } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12 - copyYV12toBGR32(width, height, - srcPixels, - tgtPixels, tgtBuffer.stride); + Utils::copyYV12toBGR32(width, height, + srcPixels, + tgtPixels, tgtBuffer.stride); } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV - copyYUYVtoBGR32(width, height, - srcPixels, srcBuffer.stride, - tgtPixels, tgtBuffer.stride); + Utils::copyYUYVtoBGR32(width, height, + srcPixels, srcBuffer.stride, + tgtPixels, tgtBuffer.stride); } else if (srcBuffer.format == tgtBuffer.format) { // 32bit RGBA - copyMatchedInterleavedFormats(width, height, - srcPixels, srcBuffer.stride, - tgtPixels, tgtBuffer.stride, - tgtBuffer.pixelSize); + Utils::copyMatchedInterleavedFormats(width, height, + srcPixels, srcBuffer.stride, + tgtPixels, tgtBuffer.stride, + tgtBuffer.pixelSize); } else { ALOGE("Camera buffer format is not supported"); success = false; diff --git a/automotive/evs/common/utils/default/Android.bp b/automotive/evs/common/utils/default/Android.bp new file mode 100644 index 0000000000..7734f5c19e --- /dev/null +++ b/automotive/evs/common/utils/default/Android.bp @@ -0,0 +1,31 @@ +// +// 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. +// + +cc_library_static { + name: "android.hardware.automotive.evs@common-default-lib", + vendor_available: true, + relative_install_path: "hw", + cflags: [ + "-O0", + "-g", + ], + srcs: [ + "FormatConvert.cpp" + ], + export_include_dirs: ["include"], + shared_libs: [ + ], +} diff --git a/automotive/evs/1.0/vts/functional/FormatConvert.cpp b/automotive/evs/common/utils/default/FormatConvert.cpp similarity index 74% rename from automotive/evs/1.0/vts/functional/FormatConvert.cpp rename to automotive/evs/common/utils/default/FormatConvert.cpp index 3d82d32cac..d4c7da0363 100644 --- a/automotive/evs/1.0/vts/functional/FormatConvert.cpp +++ b/automotive/evs/common/utils/default/FormatConvert.cpp @@ -18,10 +18,15 @@ #include "FormatConvert.h" +namespace android { +namespace hardware { +namespace automotive { +namespace evs { +namespace common { // Round up to the nearest multiple of the given alignment value template -int align(int value) { +int Utils::align(int value) { static_assert((alignment && !(alignment & (alignment - 1))), "alignment must be a power of 2"); @@ -31,15 +36,17 @@ int align(int value) { // Limit the given value to the provided range. :) -static inline float clamp(float v, float min, float max) { +inline float Utils::clamp(float v, float min, float max) { if (v < min) return min; if (v > max) return max; return v; } -static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin, - bool bgrxFormat = false) { +uint32_t Utils::yuvToRgbx(const unsigned char Y, + const unsigned char Uin, + const unsigned char Vin, + bool bgrxFormat) { // Don't use this if you want to see the best performance. :) // Better to do this in a pixel shader if we really have to, but on actual // embedded hardware we expect to be able to texture directly from the YUV data @@ -67,10 +74,10 @@ static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const } -void copyNV21toRGB32(unsigned width, unsigned height, - uint8_t* src, - uint32_t* dst, unsigned dstStridePixels, - bool bgrxFormat) +void Utils::copyNV21toRGB32(unsigned width, unsigned height, + uint8_t* src, + uint32_t* dst, unsigned dstStridePixels, + bool bgrxFormat) { // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved // U/V array. It assumes an even width and height for the overall image, and a horizontal @@ -99,10 +106,10 @@ void copyNV21toRGB32(unsigned width, unsigned height, } -void copyYV12toRGB32(unsigned width, unsigned height, - uint8_t* src, - uint32_t* dst, unsigned dstStridePixels, - bool bgrxFormat) +void Utils::copyYV12toRGB32(unsigned width, unsigned height, + uint8_t* src, + uint32_t* dst, unsigned dstStridePixels, + bool bgrxFormat) { // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed // by another 1/2 x 1/2 V array. It assumes an even width and height for the overall image, @@ -134,10 +141,10 @@ void copyYV12toRGB32(unsigned width, unsigned height, } -void copyYUYVtoRGB32(unsigned width, unsigned height, - uint8_t* src, unsigned srcStridePixels, - uint32_t* dst, unsigned dstStridePixels, - bool bgrxFormat) +void Utils::copyYUYVtoRGB32(unsigned width, unsigned height, + uint8_t* src, unsigned srcStridePixels, + uint32_t* dst, unsigned dstStridePixels, + bool bgrxFormat) { uint32_t* srcWords = (uint32_t*)src; @@ -167,34 +174,34 @@ void copyYUYVtoRGB32(unsigned width, unsigned height, } -void copyNV21toBGR32(unsigned width, unsigned height, - uint8_t* src, - uint32_t* dst, unsigned dstStridePixels) +void Utils::copyNV21toBGR32(unsigned width, unsigned height, + uint8_t* src, + uint32_t* dst, unsigned dstStridePixels) { return copyNV21toRGB32(width, height, src, dst, dstStridePixels, true); } -void copyYV12toBGR32(unsigned width, unsigned height, - uint8_t* src, - uint32_t* dst, unsigned dstStridePixels) +void Utils::copyYV12toBGR32(unsigned width, unsigned height, + uint8_t* src, + uint32_t* dst, unsigned dstStridePixels) { return copyYV12toRGB32(width, height, src, dst, dstStridePixels, true); } -void copyYUYVtoBGR32(unsigned width, unsigned height, - uint8_t* src, unsigned srcStridePixels, - uint32_t* dst, unsigned dstStridePixels) +void Utils::copyYUYVtoBGR32(unsigned width, unsigned height, + uint8_t* src, unsigned srcStridePixels, + uint32_t* dst, unsigned dstStridePixels) { return copyYUYVtoRGB32(width, height, src, srcStridePixels, dst, dstStridePixels, true); } -void copyMatchedInterleavedFormats(unsigned width, unsigned height, - void* src, unsigned srcStridePixels, - void* dst, unsigned dstStridePixels, - unsigned pixelSize) { +void Utils::copyMatchedInterleavedFormats(unsigned width, unsigned height, + void* src, unsigned srcStridePixels, + void* dst, unsigned dstStridePixels, + unsigned pixelSize) { for (unsigned row = 0; row < height; row++) { // Copy the entire row of pixel data memcpy(dst, src, width * pixelSize); @@ -204,3 +211,10 @@ void copyMatchedInterleavedFormats(unsigned width, unsigned height, dst = (uint8_t*)dst + dstStridePixels * pixelSize; } } + +} // namespace common +} // namespace evs +} // namespace automotive +} // namespace hardware +} // namespace android + diff --git a/automotive/evs/common/utils/default/include/FormatConvert.h b/automotive/evs/common/utils/default/include/FormatConvert.h new file mode 100644 index 0000000000..2bb89554da --- /dev/null +++ b/automotive/evs/common/utils/default/include/FormatConvert.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2017 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 EVS_VTS_FORMATCONVERT_H +#define EVS_VTS_FORMATCONVERT_H + +#include +#include + + +namespace android { +namespace hardware { +namespace automotive { +namespace evs { +namespace common { + +class Utils { +public: + // Given an image buffer in NV21 format (HAL_PIXEL_FORMAT_YCRCB_420_SP), output 32bit RGBx/BGRx + // values. The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved + // U/V array. It assumes an even width and height for the overall image, and a horizontal + // stride that is an even multiple of 16 bytes for both the Y and UV arrays. + static void copyNV21toRGB32(unsigned width, unsigned height, + uint8_t* src, + uint32_t* dst, unsigned dstStridePixels, + bool bgrxFormat = false); + + static void copyNV21toBGR32(unsigned width, unsigned height, + uint8_t* src, + uint32_t* dst, unsigned dstStridePixels); + + + // Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx/BGRx values. + // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed + // by another 1/2 x 1/2 V array. It assumes an even width and height for the overall image, + // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U, + // and V arrays. + static void copyYV12toRGB32(unsigned width, unsigned height, + uint8_t* src, + uint32_t* dst, unsigned dstStridePixels, + bool bgrxFormat = false); + + static void copyYV12toBGR32(unsigned width, unsigned height, + uint8_t* src, + uint32_t* dst, unsigned dstStridePixels); + + // Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx/BGRx + // values. The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved + // U/V array. It assumes an even width and height for the overall image, and a horizontal + // stride that is an even multiple of 16 bytes for both the Y and UV arrays. + static void copyYUYVtoRGB32(unsigned width, unsigned height, + uint8_t* src, unsigned srcStrideBytes, + uint32_t* dst, unsigned dstStrideBytes, + bool bgrxFormat = false); + + static void copyYUYVtoBGR32(unsigned width, unsigned height, + uint8_t* src, unsigned srcStrideBytes, + uint32_t* dst, unsigned dstStrideBytes); + + + // Given an simple rectangular image buffer with an integer number of bytes per pixel, + // copy the pixel values into a new rectangular buffer (potentially with a different stride). + // This is typically used to copy RGBx data into an RGBx output buffer. + static void copyMatchedInterleavedFormats(unsigned width, unsigned height, + void* src, unsigned srcStridePixels, + void* dst, unsigned dstStridePixels, + unsigned pixelSize); + +private: + template + static int align(int value); + + static inline float clamp(float v, float min, float max); + static uint32_t yuvToRgbx(const unsigned char Y, + const unsigned char Uin, + const unsigned char Vin, + bool bgrxFormat = false); +}; + +} // namespace common +} // namespace evs +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // EVS_VTS_FORMATCONVERT_H From 2400b69b85e98fd7090b654ad02a301f831692e9 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Thu, 18 Jul 2019 21:32:48 -0700 Subject: [PATCH 0048/1022] Add EVS v1.1 interface Extends existing v1.0 interfaces to support more functionalities and adds corresponding test cases. Bug: 135472573 Test: VTS Change-Id: I5245238e6a18ddc2c0451aaa21a9cce55c6207eb Signed-off-by: Changyeon Jo --- automotive/evs/1.1/Android.bp | 22 + automotive/evs/1.1/IEvsCamera.hal | 57 ++ automotive/evs/1.1/IEvsCameraStream.hal | 31 + automotive/evs/1.1/default/Android.bp | 32 + automotive/evs/1.1/default/EvsCamera.cpp | 584 ++++++++++++++++++ automotive/evs/1.1/default/EvsCamera.h | 128 ++++ automotive/evs/1.1/default/EvsDisplay.cpp | 335 ++++++++++ automotive/evs/1.1/default/EvsDisplay.h | 72 +++ automotive/evs/1.1/default/EvsEnumerator.cpp | 217 +++++++ automotive/evs/1.1/default/EvsEnumerator.h | 81 +++ automotive/evs/1.1/default/ServiceNames.h | 17 + ...oid.hardware.automotive.evs@1.1-service.rc | 5 + automotive/evs/1.1/default/service.cpp | 63 ++ automotive/evs/1.1/types.hal | 84 +++ automotive/evs/1.1/vts/functional/Android.bp | 40 ++ .../evs/1.1/vts/functional/FrameHandler.cpp | 340 ++++++++++ .../evs/1.1/vts/functional/FrameHandler.h | 102 +++ .../functional/VtsHalEvsV1_1TargetTest.cpp | 526 ++++++++++++++++ 18 files changed, 2736 insertions(+) create mode 100644 automotive/evs/1.1/Android.bp create mode 100644 automotive/evs/1.1/IEvsCamera.hal create mode 100644 automotive/evs/1.1/IEvsCameraStream.hal create mode 100644 automotive/evs/1.1/default/Android.bp create mode 100644 automotive/evs/1.1/default/EvsCamera.cpp create mode 100644 automotive/evs/1.1/default/EvsCamera.h create mode 100644 automotive/evs/1.1/default/EvsDisplay.cpp create mode 100644 automotive/evs/1.1/default/EvsDisplay.h create mode 100644 automotive/evs/1.1/default/EvsEnumerator.cpp create mode 100644 automotive/evs/1.1/default/EvsEnumerator.h create mode 100644 automotive/evs/1.1/default/ServiceNames.h create mode 100644 automotive/evs/1.1/default/android.hardware.automotive.evs@1.1-service.rc create mode 100644 automotive/evs/1.1/default/service.cpp create mode 100644 automotive/evs/1.1/types.hal create mode 100644 automotive/evs/1.1/vts/functional/Android.bp create mode 100644 automotive/evs/1.1/vts/functional/FrameHandler.cpp create mode 100644 automotive/evs/1.1/vts/functional/FrameHandler.h create mode 100644 automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp diff --git a/automotive/evs/1.1/Android.bp b/automotive/evs/1.1/Android.bp new file mode 100644 index 0000000000..d2e85f1304 --- /dev/null +++ b/automotive/evs/1.1/Android.bp @@ -0,0 +1,22 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.automotive.evs@1.1", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IEvsCamera.hal", + "IEvsCameraStream.hal", + ], + interfaces: [ + "android.hardware.automotive.evs@1.0", + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal new file mode 100644 index 0000000000..e7f6bb7b5b --- /dev/null +++ b/automotive/evs/1.1/IEvsCamera.hal @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package android.hardware.automotive.evs@1.1; + +import @1.0::IEvsCamera; +import @1.0::EvsResult; +import IEvsCameraStream; + +/** + * Represents a single camera and is the primary interface for capturing images. + */ +interface IEvsCamera extends @1.0::IEvsCamera { + /** + * Requests to pause EVS camera stream events. + * + * Like stopVideoStream(), events may continue to arrive for some time + * after this call returns. Delivered frame buffers must be returned. + * + * @return result EvsResult::OK is returned if this call is successful. + */ + pauseVideoStream() generates (EvsResult result); + + /** + * Requests to resume EVS camera stream. + * + * @return result EvsResult::OK is returned if this call is successful. + */ + resumeVideoStream() generates (EvsResult result); + + /** + * Returns a frame that was delivered by to the IEvsCameraStream. + * + * When done consuming a frame delivered to the IEvsCameraStream + * interface, it must be returned to the IEvsCamera for reuse. + * A small, finite number of buffers are available (possibly as small + * as one), and if the supply is exhausted, no further frames may be + * delivered until a buffer is returned. + * + * @param buffer A buffer to be returned. + * @return result Return EvsResult::OK if this call is successful. + */ + doneWithFrame_1_1(BufferDesc buffer) generates (EvsResult result); +}; diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal new file mode 100644 index 0000000000..cd058a5540 --- /dev/null +++ b/automotive/evs/1.1/IEvsCameraStream.hal @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package android.hardware.automotive.evs@1.1; + +import @1.0::IEvsCameraStream; + +/** + * Implemented on client side to receive asynchronous video frame deliveries. + */ +interface IEvsCameraStream extends @1.0::IEvsCameraStream { + /** + * Receives calls from the HAL each time an event happens. + * + * @param event EVS event with possible event information. + */ + oneway notifyEvent(EvsEvent event); +}; diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp new file mode 100644 index 0000000000..411f0ff742 --- /dev/null +++ b/automotive/evs/1.1/default/Android.bp @@ -0,0 +1,32 @@ +cc_binary { + name: "android.hardware.automotive.evs@1.1-service", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: [ + "service.cpp", + "EvsCamera.cpp", + "EvsEnumerator.cpp", + "EvsDisplay.cpp" + ], + init_rc: ["android.hardware.automotive.evs@1.1-service.rc"], + + shared_libs: [ + "android.hardware.automotive.evs@1.0", + "android.hardware.automotive.evs@1.1", + "libbase", + "libbinder", + "libcutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libui", + "libutils", + ], + + cflags: [ + "-O0", + "-g", + ], +} diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp new file mode 100644 index 0000000000..62d9826f24 --- /dev/null +++ b/automotive/evs/1.1/default/EvsCamera.cpp @@ -0,0 +1,584 @@ +/* + * 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 "android.hardware.automotive.evs@1.1-service" + +#include "EvsCamera.h" +#include "EvsEnumerator.h" + +#include +#include + + +namespace android { +namespace hardware { +namespace automotive { +namespace evs { +namespace V1_1 { +namespace implementation { + + +// Special camera names for which we'll initialize alternate test data +const char EvsCamera::kCameraName_Backup[] = "backup"; + + +// Arbitrary limit on number of graphics buffers allowed to be allocated +// Safeguards against unreasonable resource consumption and provides a testable limit +const unsigned MAX_BUFFERS_IN_FLIGHT = 100; + + +EvsCamera::EvsCamera(const char *id) : + mFramesAllowed(0), + mFramesInUse(0), + mStreamState(STOPPED) { + + ALOGD("EvsCamera instantiated"); + + mDescription.cameraId = id; + + // Set up dummy data for testing + if (mDescription.cameraId == kCameraName_Backup) { + mWidth = 640; // full NTSC/VGA + mHeight = 480; // full NTSC/VGA + mDescription.vendorFlags = 0xFFFFFFFF; // Arbitrary value + } else { + mWidth = 320; // 1/2 NTSC/VGA + mHeight = 240; // 1/2 NTSC/VGA + } + + mFormat = HAL_PIXEL_FORMAT_RGBA_8888; + mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE | + GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY; +} + + +EvsCamera::~EvsCamera() { + ALOGD("EvsCamera being destroyed"); + forceShutdown(); +} + + +// +// This gets called if another caller "steals" ownership of the camera +// +void EvsCamera::forceShutdown() +{ + ALOGD("EvsCamera forceShutdown"); + + // Make sure our output stream is cleaned up + // (It really should be already) + stopVideoStream(); + + // Claim the lock while we work on internal state + std::lock_guard lock(mAccessLock); + + // Drop all the graphics buffers we've been using + if (mBuffers.size() > 0) { + GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); + for (auto&& rec : mBuffers) { + if (rec.inUse) { + ALOGE("Error - releasing buffer despite remote ownership"); + } + alloc.free(rec.handle); + rec.handle = nullptr; + } + mBuffers.clear(); + } + + // Put this object into an unrecoverable error state since somebody else + // is going to own the underlying camera now + mStreamState = DEAD; +} + + +// Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow. +Return EvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) { + ALOGD("getCameraInfo"); + + // Send back our self description + _hidl_cb(mDescription); + return Void(); +} + + +Return EvsCamera::setMaxFramesInFlight(uint32_t bufferCount) { + ALOGD("setMaxFramesInFlight"); + std::lock_guard lock(mAccessLock); + + // If we've been displaced by another owner of the camera, then we can't do anything else + if (mStreamState == DEAD) { + ALOGE("ignoring setMaxFramesInFlight call when camera has been lost."); + return EvsResult::OWNERSHIP_LOST; + } + + // We cannot function without at least one video buffer to send data + if (bufferCount < 1) { + ALOGE("Ignoring setMaxFramesInFlight with less than one buffer requested"); + return EvsResult::INVALID_ARG; + } + + // Update our internal state + if (setAvailableFrames_Locked(bufferCount)) { + return EvsResult::OK; + } else { + return EvsResult::BUFFER_NOT_AVAILABLE; + } +} + + +Return EvsCamera::startVideoStream(const ::android::sp& stream) { + ALOGD("startVideoStream"); + std::lock_guard lock(mAccessLock); + + // If we've been displaced by another owner of the camera, then we can't do anything else + if (mStreamState == DEAD) { + ALOGE("ignoring startVideoStream call when camera has been lost."); + return EvsResult::OWNERSHIP_LOST; + } + if (mStreamState != STOPPED) { + ALOGE("ignoring startVideoStream call when a stream is already running."); + return EvsResult::STREAM_ALREADY_RUNNING; + } + + // If the client never indicated otherwise, configure ourselves for a single streaming buffer + if (mFramesAllowed < 1) { + if (!setAvailableFrames_Locked(1)) { + ALOGE("Failed to start stream because we couldn't get a graphics buffer"); + return EvsResult::BUFFER_NOT_AVAILABLE; + } + } + + // Record the user's callback for use when we have a frame ready + mStream = IEvsCameraStream_1_1::castFrom(stream).withDefault(nullptr); + if (mStream == nullptr) { + ALOGE("Default implementation does not support v1.0 IEvsCameraStream"); + return EvsResult::INVALID_ARG; + } + + // Start the frame generation thread + mStreamState = RUNNING; + mCaptureThread = std::thread([this](){ generateFrames(); }); + + return EvsResult::OK; +} + + +Return EvsCamera::doneWithFrame(const BufferDesc_1_0& buffer) { + std::lock_guard lock(mAccessLock); + returnBuffer(buffer.bufferId, buffer.memHandle); + + return Void(); +} + + +Return EvsCamera::stopVideoStream() { + ALOGD("stopVideoStream"); + std::unique_lock lock(mAccessLock); + + if (mStreamState == RUNNING) { + // Tell the GenerateFrames loop we want it to stop + mStreamState = STOPPING; + + // Block outside the mutex until the "stop" flag has been acknowledged + // We won't send any more frames, but the client might still get some already in flight + ALOGD("Waiting for stream thread to end.."); + lock.unlock(); + mCaptureThread.join(); + lock.lock(); + + mStreamState = STOPPED; + mStream = nullptr; + ALOGD("Stream marked STOPPED."); + } + + return Void(); +} + + +Return EvsCamera::getExtendedInfo(uint32_t opaqueIdentifier) { + ALOGD("getExtendedInfo"); + std::lock_guard lock(mAccessLock); + + // For any single digit value, return the index itself as a test value + if (opaqueIdentifier <= 9) { + return opaqueIdentifier; + } + + // Return zero by default as required by the spec + return 0; +} + + +Return EvsCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/, int32_t /*opaqueValue*/) { + ALOGD("setExtendedInfo"); + std::lock_guard lock(mAccessLock); + + // If we've been displaced by another owner of the camera, then we can't do anything else + if (mStreamState == DEAD) { + ALOGE("ignoring setExtendedInfo call when camera has been lost."); + return EvsResult::OWNERSHIP_LOST; + } + + // We don't store any device specific information in this implementation + return EvsResult::INVALID_ARG; +} + + +// Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow. +Return EvsCamera::doneWithFrame_1_1(const BufferDesc_1_1& bufDesc) { + std::lock_guard lock(mAccessLock); + returnBuffer(bufDesc.bufferId, bufDesc.buffer.nativeHandle); + + return EvsResult::OK; +} + + +Return EvsCamera::pauseVideoStream() { + // Default implementation does not support this. + return EvsResult::UNDERLYING_SERVICE_ERROR; +} + + +Return EvsCamera::resumeVideoStream() { + // Default implementation does not support this. + return EvsResult::UNDERLYING_SERVICE_ERROR; +} + + +bool EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) { + if (bufferCount < 1) { + ALOGE("Ignoring request to set buffer count to zero"); + return false; + } + if (bufferCount > MAX_BUFFERS_IN_FLIGHT) { + ALOGE("Rejecting buffer request in excess of internal limit"); + return false; + } + + // Is an increase required? + if (mFramesAllowed < bufferCount) { + // An increase is required + unsigned needed = bufferCount - mFramesAllowed; + ALOGI("Allocating %d buffers for camera frames", needed); + + unsigned added = increaseAvailableFrames_Locked(needed); + if (added != needed) { + // If we didn't add all the frames we needed, then roll back to the previous state + ALOGE("Rolling back to previous frame queue size"); + decreaseAvailableFrames_Locked(added); + return false; + } + } else if (mFramesAllowed > bufferCount) { + // A decrease is required + unsigned framesToRelease = mFramesAllowed - bufferCount; + ALOGI("Returning %d camera frame buffers", framesToRelease); + + unsigned released = decreaseAvailableFrames_Locked(framesToRelease); + if (released != framesToRelease) { + // This shouldn't happen with a properly behaving client because the client + // should only make this call after returning sufficient outstanding buffers + // to allow a clean resize. + ALOGE("Buffer queue shrink failed -- too many buffers currently in use?"); + } + } + + return true; +} + + +unsigned EvsCamera::increaseAvailableFrames_Locked(unsigned numToAdd) { + // Acquire the graphics buffer allocator + GraphicBufferAllocator &alloc(GraphicBufferAllocator::get()); + + unsigned added = 0; + + while (added < numToAdd) { + buffer_handle_t memHandle = nullptr; + status_t result = alloc.allocate(mWidth, mHeight, mFormat, 1, mUsage, + &memHandle, &mStride, 0, "EvsCamera"); + if (result != NO_ERROR) { + ALOGE("Error %d allocating %d x %d graphics buffer", result, mWidth, mHeight); + break; + } + if (!memHandle) { + ALOGE("We didn't get a buffer handle back from the allocator"); + break; + } + + // Find a place to store the new buffer + bool stored = false; + for (auto&& rec : mBuffers) { + if (rec.handle == nullptr) { + // Use this existing entry + rec.handle = memHandle; + rec.inUse = false; + stored = true; + break; + } + } + if (!stored) { + // Add a BufferRecord wrapping this handle to our set of available buffers + mBuffers.emplace_back(memHandle); + } + + mFramesAllowed++; + added++; + } + + return added; +} + + +unsigned EvsCamera::decreaseAvailableFrames_Locked(unsigned numToRemove) { + // Acquire the graphics buffer allocator + GraphicBufferAllocator &alloc(GraphicBufferAllocator::get()); + + unsigned removed = 0; + + for (auto&& rec : mBuffers) { + // Is this record not in use, but holding a buffer that we can free? + if ((rec.inUse == false) && (rec.handle != nullptr)) { + // Release buffer and update the record so we can recognize it as "empty" + alloc.free(rec.handle); + rec.handle = nullptr; + + mFramesAllowed--; + removed++; + + if (removed == numToRemove) { + break; + } + } + } + + return removed; +} + + +// This is the asynchronous frame generation thread that runs in parallel with the +// main serving thread. There is one for each active camera instance. +void EvsCamera::generateFrames() { + ALOGD("Frame generation loop started"); + + unsigned idx; + + while (true) { + bool timeForFrame = false; + nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); + + // Lock scope for updating shared state + { + std::lock_guard lock(mAccessLock); + + if (mStreamState != RUNNING) { + // Break out of our main thread loop + break; + } + + // Are we allowed to issue another buffer? + if (mFramesInUse >= mFramesAllowed) { + // Can't do anything right now -- skip this frame + ALOGW("Skipped a frame because too many are in flight\n"); + } else { + // Identify an available buffer to fill + for (idx = 0; idx < mBuffers.size(); idx++) { + if (!mBuffers[idx].inUse) { + if (mBuffers[idx].handle != nullptr) { + // Found an available record, so stop looking + break; + } + } + } + if (idx >= mBuffers.size()) { + // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed + ALOGE("Failed to find an available buffer slot\n"); + } else { + // We're going to make the frame busy + mBuffers[idx].inUse = true; + mFramesInUse++; + timeForFrame = true; + } + } + } + + if (timeForFrame) { + // Assemble the buffer description we'll transmit below + BufferDesc_1_1 newBuffer = {}; + AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&newBuffer.buffer.description); + pDesc->width = mWidth; + pDesc->height = mHeight; + pDesc->layers = 1; + pDesc->format = mFormat; + pDesc->usage = mUsage; + pDesc->stride = mStride; + newBuffer.buffer.nativeHandle = mBuffers[idx].handle; + newBuffer.pixelSize = sizeof(uint32_t); + newBuffer.bufferId = idx; + + // Write test data into the image buffer + fillTestFrame(newBuffer); + + // Issue the (asynchronous) callback to the client -- can't be holding the lock + EvsEvent event; + event.buffer(newBuffer); + auto result = mStream->notifyEvent(event); + if (result.isOk()) { + ALOGD("Delivered %p as id %d", + newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId); + } else { + // This can happen if the client dies and is likely unrecoverable. + // To avoid consuming resources generating failing calls, we stop sending + // frames. Note, however, that the stream remains in the "STREAMING" state + // until cleaned up on the main thread. + ALOGE("Frame delivery call failed in the transport layer."); + + // Since we didn't actually deliver it, mark the frame as available + std::lock_guard lock(mAccessLock); + mBuffers[idx].inUse = false; + mFramesInUse--; + + break; + } + } + + // We arbitrarily choose to generate frames at 12 fps to ensure we pass the 10fps test requirement + static const int kTargetFrameRate = 12; + static const nsecs_t kTargetFrameTimeUs = 1000*1000 / kTargetFrameRate; + const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + const nsecs_t workTimeUs = (now - startTime) / 1000; + const nsecs_t sleepDurationUs = kTargetFrameTimeUs - workTimeUs; + if (sleepDurationUs > 0) { + usleep(sleepDurationUs); + } + } + + // If we've been asked to stop, send an event to signal the actual end of stream + EvsEvent event; + event.info(EvsEventType::STREAM_STOPPED); + auto result = mStream->notifyEvent(event); + if (!result.isOk()) { + ALOGE("Error delivering end of stream marker"); + } + + return; +} + + +void EvsCamera::fillTestFrame(const BufferDesc_1_1& buff) { + // Lock our output buffer for writing + uint32_t *pixels = nullptr; + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&buff.buffer.description); + GraphicBufferMapper &mapper = GraphicBufferMapper::get(); + mapper.lock(buff.buffer.nativeHandle, + GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER, + android::Rect(pDesc->width, pDesc->height), + (void **) &pixels); + + // If we failed to lock the pixel buffer, we're about to crash, but log it first + if (!pixels) { + ALOGE("Camera failed to gain access to image buffer for writing"); + } + + // Fill in the test pixels + for (unsigned row = 0; row < pDesc->height; row++) { + for (unsigned col = 0; col < pDesc->width; col++) { + // Index into the row to check the pixel at this column. + // We expect 0xFF in the LSB channel, a vertical gradient in the + // second channel, a horitzontal gradient in the third channel, and + // 0xFF in the MSB. + // The exception is the very first 32 bits which is used for the + // time varying frame signature to avoid getting fooled by a static image. + uint32_t expectedPixel = 0xFF0000FF | // MSB and LSB + ((row & 0xFF) << 8) | // vertical gradient + ((col & 0xFF) << 16); // horizontal gradient + if ((row | col) == 0) { + static uint32_t sFrameTicker = 0; + expectedPixel = (sFrameTicker) & 0xFF; + sFrameTicker++; + } + pixels[col] = expectedPixel; + } + // Point to the next row + // NOTE: stride retrieved from gralloc is in units of pixels + pixels = pixels + pDesc->stride; + } + + // Release our output buffer + mapper.unlock(buff.buffer.nativeHandle); +} + + +void EvsCamera::fillTestFrame(const BufferDesc_1_0& buff) { + BufferDesc_1_1 newBufDesc = {}; + AHardwareBuffer_Desc desc = { + buff.width, // width + buff.height, // height + 1, // layers, always 1 for EVS + buff.format, // One of AHardwareBuffer_Format + buff.usage, // Combination of AHardwareBuffer_UsageFlags + buff.stride, // Row stride in pixels + 0, // Reserved + 0 // Reserved + }; + memcpy(&desc, &newBufDesc.buffer.description, sizeof(desc)); + newBufDesc.buffer.nativeHandle = buff.memHandle; + newBufDesc.pixelSize = buff.pixelSize; + newBufDesc.bufferId = buff.bufferId; + + return fillTestFrame(newBufDesc); +} + + +void EvsCamera::returnBuffer(const uint32_t bufferId, const buffer_handle_t memHandle) { + std::lock_guard lock(mAccessLock); + + if (memHandle == nullptr) { + ALOGE("ignoring doneWithFrame called with null handle"); + } else if (bufferId >= mBuffers.size()) { + ALOGE("ignoring doneWithFrame called with invalid bufferId %d (max is %zu)", + bufferId, mBuffers.size()-1); + } else if (!mBuffers[bufferId].inUse) { + ALOGE("ignoring doneWithFrame called on frame %d which is already free", + bufferId); + } else { + // Mark the frame as available + mBuffers[bufferId].inUse = false; + mFramesInUse--; + + // If this frame's index is high in the array, try to move it down + // to improve locality after mFramesAllowed has been reduced. + if (bufferId >= mFramesAllowed) { + // Find an empty slot lower in the array (which should always exist in this case) + for (auto&& rec : mBuffers) { + if (rec.handle == nullptr) { + rec.handle = mBuffers[bufferId].handle; + mBuffers[bufferId].handle = nullptr; + break; + } + } + } + } +} + + +} // namespace implementation +} // namespace V1_0 +} // namespace evs +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h new file mode 100644 index 0000000000..0982464b59 --- /dev/null +++ b/automotive/evs/1.1/default/EvsCamera.h @@ -0,0 +1,128 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERA_H +#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERA_H + +#include +#include +#include +#include + +#include + +using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc; +using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc; +using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream; +using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream; +using ::android::hardware::automotive::evs::V1_0::EvsResult; +using ::android::hardware::automotive::evs::V1_0::CameraDesc; + + +namespace android { +namespace hardware { +namespace automotive { +namespace evs { +namespace V1_1 { +namespace implementation { + + +// From EvsEnumerator.h +class EvsEnumerator; + + +class EvsCamera : public IEvsCamera { +public: + // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow. + Return getCameraInfo(getCameraInfo_cb _hidl_cb) override; + Return setMaxFramesInFlight(uint32_t bufferCount) override; + Return startVideoStream(const ::android::sp& stream) override; + Return stopVideoStream() override; + Return doneWithFrame(const BufferDesc_1_0& buffer) override; + + Return getExtendedInfo(uint32_t opaqueIdentifier) override; + Return setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override; + + // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow. + Return pauseVideoStream() override; + Return resumeVideoStream() override; + Return doneWithFrame_1_1(const BufferDesc_1_1& buffer) override; + + // Implementation details + EvsCamera(const char *id); + virtual ~EvsCamera() override; + void forceShutdown(); // This gets called if another caller "steals" ownership of the camera + + const CameraDesc& getDesc() { return mDescription; }; + + static const char kCameraName_Backup[]; + +private: + // These three functions are expected to be called while mAccessLock is held + bool setAvailableFrames_Locked(unsigned bufferCount); + unsigned increaseAvailableFrames_Locked(unsigned numToAdd); + unsigned decreaseAvailableFrames_Locked(unsigned numToRemove); + + void generateFrames(); + void fillTestFrame(const BufferDesc_1_0& buff); + void fillTestFrame(const BufferDesc_1_1& buff); + void returnBuffer(const uint32_t bufferId, const buffer_handle_t memHandle); + + sp mEnumerator; // The enumerator object that created this camera + + CameraDesc mDescription = {}; // The properties of this camera + + std::thread mCaptureThread; // The thread we'll use to synthesize frames + + uint32_t mWidth = 0; // Horizontal pixel count in the buffers + uint32_t mHeight = 0; // Vertical pixel count in the buffers + uint32_t mFormat = 0; // Values from android_pixel_format_t + uint64_t mUsage = 0; // Values from from Gralloc.h + uint32_t mStride = 0; // Bytes per line in the buffers + + sp mStream = nullptr; // The callback used to deliver each frame + + struct BufferRecord { + buffer_handle_t handle; + bool inUse; + + explicit BufferRecord(buffer_handle_t h) : handle(h), inUse(false) {}; + }; + + std::vector mBuffers; // Graphics buffers to transfer images + unsigned mFramesAllowed; // How many buffers are we currently using + unsigned mFramesInUse; // How many buffers are currently outstanding + + enum StreamStateValues { + STOPPED, + RUNNING, + STOPPING, + DEAD, + }; + StreamStateValues mStreamState; + + // Synchronization necessary to deconflict mCaptureThread from the main service thread + std::mutex mAccessLock; +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace evs +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERA_H diff --git a/automotive/evs/1.1/default/EvsDisplay.cpp b/automotive/evs/1.1/default/EvsDisplay.cpp new file mode 100644 index 0000000000..74c099ac30 --- /dev/null +++ b/automotive/evs/1.1/default/EvsDisplay.cpp @@ -0,0 +1,335 @@ +/* + * 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 "android.hardware.automotive.evs@1.1-service" + +#include "EvsDisplay.h" + +#include +#include + + +namespace android { +namespace hardware { +namespace automotive { +namespace evs { +namespace V1_1 { +namespace implementation { + + +EvsDisplay::EvsDisplay() { + ALOGD("EvsDisplay instantiated"); + + // Set up our self description + // NOTE: These are arbitrary values chosen for testing + mInfo.displayId = "Mock Display"; + mInfo.vendorFlags = 3870; + + // Assemble the buffer description we'll use for our render target + mBuffer.width = 320; + mBuffer.height = 240; + mBuffer.format = HAL_PIXEL_FORMAT_RGBA_8888; + mBuffer.usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER; + mBuffer.bufferId = 0x3870; // Arbitrary magic number for self recognition + mBuffer.pixelSize = 4; +} + + +EvsDisplay::~EvsDisplay() { + ALOGD("EvsDisplay being destroyed"); + forceShutdown(); +} + + +/** + * This gets called if another caller "steals" ownership of the display + */ +void EvsDisplay::forceShutdown() +{ + ALOGD("EvsDisplay forceShutdown"); + std::lock_guard lock(mAccessLock); + + // If the buffer isn't being held by a remote client, release it now as an + // optimization to release the resources more quickly than the destructor might + // get called. + if (mBuffer.memHandle) { + // Report if we're going away while a buffer is outstanding + if (mFrameBusy) { + ALOGE("EvsDisplay going down while client is holding a buffer"); + } + + // Drop the graphics buffer we've been using + GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); + alloc.free(mBuffer.memHandle); + mBuffer.memHandle = nullptr; + } + + // Put this object into an unrecoverable error state since somebody else + // is going to own the display now. + mRequestedState = DisplayState::DEAD; +} + + +/** + * Returns basic information about the EVS display provided by the system. + * See the description of the DisplayDesc structure for details. + */ +Return EvsDisplay::getDisplayInfo(getDisplayInfo_cb _hidl_cb) { + ALOGD("getDisplayInfo"); + + // Send back our self description + _hidl_cb(mInfo); + return Void(); +} + + +/** + * Clients may set the display state to express their desired state. + * The HAL implementation must gracefully accept a request for any state + * while in any other state, although the response may be to ignore the request. + * The display is defined to start in the NOT_VISIBLE state upon initialization. + * The client is then expected to request the VISIBLE_ON_NEXT_FRAME state, and + * then begin providing video. When the display is no longer required, the client + * is expected to request the NOT_VISIBLE state after passing the last video frame. + */ +Return EvsDisplay::setDisplayState(DisplayState state) { + ALOGD("setDisplayState"); + std::lock_guard lock(mAccessLock); + + if (mRequestedState == DisplayState::DEAD) { + // This object no longer owns the display -- it's been superceeded! + return EvsResult::OWNERSHIP_LOST; + } + + // Ensure we recognize the requested state so we don't go off the rails + if (state < DisplayState::NUM_STATES) { + // Record the requested state + mRequestedState = state; + return EvsResult::OK; + } + else { + // Turn off the display if asked for an unrecognized state + mRequestedState = DisplayState::NOT_VISIBLE; + return EvsResult::INVALID_ARG; + } +} + + +/** + * The HAL implementation should report the actual current state, which might + * transiently differ from the most recently requested state. Note, however, that + * the logic responsible for changing display states should generally live above + * the device layer, making it undesirable for the HAL implementation to + * spontaneously change display states. + */ +Return EvsDisplay::getDisplayState() { + ALOGD("getDisplayState"); + std::lock_guard lock(mAccessLock); + + return mRequestedState; +} + + +/** + * This call returns a handle to a frame buffer associated with the display. + * This buffer may be locked and written to by software and/or GL. This buffer + * must be returned via a call to returnTargetBufferForDisplay() even if the + * display is no longer visible. + */ +// TODO: We need to know if/when our client dies so we can get the buffer back! (blocked b/31632518) +Return EvsDisplay::getTargetBuffer(getTargetBuffer_cb _hidl_cb) { + ALOGD("getTargetBuffer"); + std::lock_guard lock(mAccessLock); + + if (mRequestedState == DisplayState::DEAD) { + ALOGE("Rejecting buffer request from object that lost ownership of the display."); + BufferDesc_1_0 nullBuff = {}; + _hidl_cb(nullBuff); + return Void(); + } + + // If we don't already have a buffer, allocate one now + if (!mBuffer.memHandle) { + // Allocate the buffer that will hold our displayable image + buffer_handle_t handle = nullptr; + GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); + status_t result = alloc.allocate( + mBuffer.width, mBuffer.height, mBuffer.format, 1, mBuffer.usage, + &handle, &mBuffer.stride, 0, "EvsDisplay"); + if (result != NO_ERROR) { + ALOGE("Error %d allocating %d x %d graphics buffer", + result, mBuffer.width, mBuffer.height); + BufferDesc_1_0 nullBuff = {}; + _hidl_cb(nullBuff); + return Void(); + } + if (!handle) { + ALOGE("We didn't get a buffer handle back from the allocator"); + BufferDesc_1_0 nullBuff = {}; + _hidl_cb(nullBuff); + return Void(); + } + + mBuffer.memHandle = handle; + mFrameBusy = false; + ALOGD("Allocated new buffer %p with stride %u", + mBuffer.memHandle.getNativeHandle(), mBuffer.stride); + } + + // Do we have a frame available? + if (mFrameBusy) { + // This means either we have a 2nd client trying to compete for buffers + // (an unsupported mode of operation) or else the client hasn't returned + // a previously issued buffer yet (they're behaving badly). + // NOTE: We have to make the callback even if we have nothing to provide + ALOGE("getTargetBuffer called while no buffers available."); + BufferDesc_1_0 nullBuff = {}; + _hidl_cb(nullBuff); + return Void(); + } else { + // Mark our buffer as busy + mFrameBusy = true; + + // Send the buffer to the client + ALOGD("Providing display buffer handle %p as id %d", + mBuffer.memHandle.getNativeHandle(), mBuffer.bufferId); + _hidl_cb(mBuffer); + return Void(); + } +} + + +/** + * This call tells the display that the buffer is ready for display. + * The buffer is no longer valid for use by the client after this call. + */ +Return EvsDisplay::returnTargetBufferForDisplayImpl(const uint32_t bufferId, const buffer_handle_t memHandle) { + ALOGD("returnTargetBufferForDisplay %p", memHandle); + std::lock_guard lock(mAccessLock); + + // Nobody should call us with a null handle + if (!memHandle) { + ALOGE ("returnTargetBufferForDisplay called without a valid buffer handle.\n"); + return EvsResult::INVALID_ARG; + } + if (bufferId != mBuffer.bufferId) { + ALOGE ("Got an unrecognized frame returned.\n"); + return EvsResult::INVALID_ARG; + } + if (!mFrameBusy) { + ALOGE ("A frame was returned with no outstanding frames.\n"); + return EvsResult::BUFFER_NOT_AVAILABLE; + } + + mFrameBusy = false; + + // If we've been displaced by another owner of the display, then we can't do anything else + if (mRequestedState == DisplayState::DEAD) { + return EvsResult::OWNERSHIP_LOST; + } + + // If we were waiting for a new frame, this is it! + if (mRequestedState == DisplayState::VISIBLE_ON_NEXT_FRAME) { + mRequestedState = DisplayState::VISIBLE; + } + + // Validate we're in an expected state + if (mRequestedState != DisplayState::VISIBLE) { + // We shouldn't get frames back when we're not visible. + ALOGE ("Got an unexpected frame returned while not visible - ignoring.\n"); + } else { + // This is where the buffer would be made visible. + // For now we simply validate it has the data we expect in it by reading it back + + // Lock our display buffer for reading + uint32_t* pixels = nullptr; + GraphicBufferMapper &mapper = GraphicBufferMapper::get(); + mapper.lock(mBuffer.memHandle, + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, + android::Rect(mBuffer.width, mBuffer.height), + (void **)&pixels); + + // If we failed to lock the pixel buffer, we're about to crash, but log it first + if (!pixels) { + ALOGE("Display failed to gain access to image buffer for reading"); + } + + // Check the test pixels + bool frameLooksGood = true; + for (unsigned row = 0; row < mBuffer.height; row++) { + for (unsigned col = 0; col < mBuffer.width; col++) { + // Index into the row to check the pixel at this column. + // We expect 0xFF in the LSB channel, a vertical gradient in the + // second channel, a horitzontal gradient in the third channel, and + // 0xFF in the MSB. + // The exception is the very first 32 bits which is used for the + // time varying frame signature to avoid getting fooled by a static image. + uint32_t expectedPixel = 0xFF0000FF | // MSB and LSB + ((row & 0xFF) << 8) | // vertical gradient + ((col & 0xFF) << 16); // horizontal gradient + if ((row | col) == 0) { + // we'll check the "uniqueness" of the frame signature below + continue; + } + // Walk across this row (we'll step rows below) + uint32_t receivedPixel = pixels[col]; + if (receivedPixel != expectedPixel) { + ALOGE("Pixel check mismatch in frame buffer"); + frameLooksGood = false; + break; + } + } + + if (!frameLooksGood) { + break; + } + + // Point to the next row (NOTE: gralloc reports stride in units of pixels) + pixels = pixels + mBuffer.stride; + } + + // Ensure we don't see the same buffer twice without it being rewritten + static uint32_t prevSignature = ~0; + uint32_t signature = pixels[0] & 0xFF; + if (prevSignature == signature) { + frameLooksGood = false; + ALOGE("Duplicate, likely stale frame buffer detected"); + } + + + // Release our output buffer + mapper.unlock(mBuffer.memHandle); + + if (!frameLooksGood) { + return EvsResult::UNDERLYING_SERVICE_ERROR; + } + } + + return EvsResult::OK; +} + + +Return EvsDisplay::returnTargetBufferForDisplay(const BufferDesc_1_0& buffer) { + return returnTargetBufferForDisplayImpl(buffer.bufferId, buffer.memHandle); +} + + +} // namespace implementation +} // namespace V1_1 +} // namespace evs +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/evs/1.1/default/EvsDisplay.h b/automotive/evs/1.1/default/EvsDisplay.h new file mode 100644 index 0000000000..2a5653500f --- /dev/null +++ b/automotive/evs/1.1/default/EvsDisplay.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 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_AUTOMOTIVE_EVS_V1_1_EVSDISPLAY_H +#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSDISPLAY_H + +#include +#include + +using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; +using ::android::hardware::automotive::evs::V1_0::DisplayDesc; +using ::android::hardware::automotive::evs::V1_0::DisplayState; +using ::android::hardware::automotive::evs::V1_0::EvsResult; +using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc; + +namespace android { +namespace hardware { +namespace automotive { +namespace evs { +namespace V1_1 { +namespace implementation { + + +class EvsDisplay : public IEvsDisplay { +public: + // Methods from ::android::hardware::automotive::evs::V1_0::IEvsDisplay follow. + Return getDisplayInfo(getDisplayInfo_cb _hidl_cb) override; + Return setDisplayState(DisplayState state) override; + Return getDisplayState() override; + Return getTargetBuffer(getTargetBuffer_cb _hidl_cb) override; + Return returnTargetBufferForDisplay(const BufferDesc_1_0& buffer) override; + + + // Implementation details + EvsDisplay(); + virtual ~EvsDisplay() override; + + void forceShutdown(); // This gets called if another caller "steals" ownership of the display + Return returnTargetBufferForDisplayImpl(const uint32_t bufferId, + const buffer_handle_t memHandle); + +private: + DisplayDesc mInfo = {}; + BufferDesc_1_0 mBuffer = {}; // A graphics buffer into which we'll store images + + bool mFrameBusy = false; // A flag telling us our buffer is in use + DisplayState mRequestedState = DisplayState::NOT_VISIBLE; + + std::mutex mAccessLock; +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace evs +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSDISPLAY_H diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp new file mode 100644 index 0000000000..b3249071ae --- /dev/null +++ b/automotive/evs/1.1/default/EvsEnumerator.cpp @@ -0,0 +1,217 @@ +/* + * 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 "android.hardware.automotive.evs@1.1-service" + +#include "EvsEnumerator.h" +#include "EvsCamera.h" +#include "EvsDisplay.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace evs { +namespace V1_1 { +namespace implementation { + + +// NOTE: All members values are static so that all clients operate on the same state +// That is to say, this is effectively a singleton despite the fact that HIDL +// constructs a new instance for each client. +std::list EvsEnumerator::sCameraList; +wp EvsEnumerator::sActiveDisplay; + + +EvsEnumerator::EvsEnumerator() { + ALOGD("EvsEnumerator created"); + + // Add sample camera data to our list of cameras + // In a real driver, this would be expected to can the available hardware + sCameraList.emplace_back(EvsCamera::kCameraName_Backup); + sCameraList.emplace_back("LaneView"); + sCameraList.emplace_back("right turn"); +} + + +// Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow. +Return EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) { + ALOGD("getCameraList"); + + const unsigned numCameras = sCameraList.size(); + + // Build up a packed array of CameraDesc for return + // NOTE: Only has to live until the callback returns + std::vector descriptions; + descriptions.reserve(numCameras); + for (const auto& cam : sCameraList) { + descriptions.push_back( cam.desc ); + } + + // Encapsulate our camera descriptions in the HIDL vec type + hidl_vec hidlCameras(descriptions); + + // Send back the results + ALOGD("reporting %zu cameras available", hidlCameras.size()); + _hidl_cb(hidlCameras); + + // HIDL convention says we return Void if we sent our result back via callback + return Void(); +} + + +Return> EvsEnumerator::openCamera(const hidl_string& cameraId) { + ALOGD("openCamera"); + + // Find the named camera + CameraRecord *pRecord = nullptr; + for (auto &&cam : sCameraList) { + if (cam.desc.cameraId == cameraId) { + // Found a match! + pRecord = &cam; + break; + } + } + + // Is this a recognized camera id? + if (!pRecord) { + ALOGE("Requested camera %s not found", cameraId.c_str()); + return nullptr; + } + + // Has this camera already been instantiated by another caller? + sp pActiveCamera = pRecord->activeInstance.promote(); + if (pActiveCamera != nullptr) { + ALOGW("Killing previous camera because of new caller"); + closeCamera(pActiveCamera); + } + + // Construct a camera instance for the caller + pActiveCamera = new EvsCamera(cameraId.c_str()); + pRecord->activeInstance = pActiveCamera; + if (pActiveCamera == nullptr) { + ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str()); + } + + return pActiveCamera; +} + + +Return EvsEnumerator::closeCamera(const ::android::sp& pCamera) { + ALOGD("closeCamera"); + + auto pCamera_1_1 = IEvsCamera_1_1::castFrom(pCamera).withDefault(nullptr); + if (pCamera_1_1 == nullptr) { + ALOGE("Ignoring call to closeCamera with null camera ptr"); + return Void(); + } + + // Get the camera id so we can find it in our list + std::string cameraId; + pCamera_1_1->getCameraInfo([&cameraId](CameraDesc desc) { + cameraId = desc.cameraId; + } + ); + + // Find the named camera + CameraRecord *pRecord = nullptr; + for (auto &&cam : sCameraList) { + if (cam.desc.cameraId == cameraId) { + // Found a match! + pRecord = &cam; + break; + } + } + + // Is the display being destroyed actually the one we think is active? + if (!pRecord) { + ALOGE("Asked to close a camera who's name isn't recognized"); + } else { + sp pActiveCamera = pRecord->activeInstance.promote(); + + if (pActiveCamera == nullptr) { + ALOGE("Somehow a camera is being destroyed when the enumerator didn't know one existed"); + } else if (pActiveCamera != pCamera_1_1) { + // This can happen if the camera was aggressively reopened, orphaning this previous instance + ALOGW("Ignoring close of previously orphaned camera - why did a client steal?"); + } else { + // Drop the active camera + pActiveCamera->forceShutdown(); + pRecord->activeInstance = nullptr; + } + } + + return Void(); +} + + +Return> EvsEnumerator::openDisplay() { + ALOGD("openDisplay"); + + // If we already have a display active, then we need to shut it down so we can + // give exclusive access to the new caller. + sp pActiveDisplay = sActiveDisplay.promote(); + if (pActiveDisplay != nullptr) { + ALOGW("Killing previous display because of new caller"); + closeDisplay(pActiveDisplay); + } + + // Create a new display interface and return it + pActiveDisplay = new EvsDisplay(); + sActiveDisplay = pActiveDisplay; + + ALOGD("Returning new EvsDisplay object %p", pActiveDisplay.get()); + return pActiveDisplay; +} + + +Return EvsEnumerator::closeDisplay(const ::android::sp& pDisplay) { + ALOGD("closeDisplay"); + + // Do we still have a display object we think should be active? + sp pActiveDisplay = sActiveDisplay.promote(); + if (pActiveDisplay == nullptr) { + ALOGE("Somehow a display is being destroyed when the enumerator didn't know one existed"); + } else if (sActiveDisplay != pDisplay) { + ALOGW("Ignoring close of previously orphaned display - why did a client steal?"); + } else { + // Drop the active display + pActiveDisplay->forceShutdown(); + sActiveDisplay = nullptr; + } + + return Void(); +} + + +Return EvsEnumerator::getDisplayState() { + ALOGD("getDisplayState"); + + // Do we still have a display object we think should be active? + sp pActiveDisplay = sActiveDisplay.promote(); + if (pActiveDisplay != nullptr) { + return pActiveDisplay->getDisplayState(); + } else { + return DisplayState::NOT_OPEN; + } +} + + +} // namespace implementation +} // namespace V1_1 +} // namespace evs +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h new file mode 100644 index 0000000000..11c2170632 --- /dev/null +++ b/automotive/evs/1.1/default/EvsEnumerator.h @@ -0,0 +1,81 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H +#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H + +#include +#include + +#include + +using ::android::hardware::automotive::evs::V1_0::EvsResult; +using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; +using ::android::hardware::automotive::evs::V1_0::DisplayState; +using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator; +using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera; +using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera; +using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc; + + +namespace android { +namespace hardware { +namespace automotive { +namespace evs { +namespace V1_1 { +namespace implementation { + + +class EvsCamera; // from EvsCamera.h +class EvsDisplay; // from EvsDisplay.h + + +class EvsEnumerator : public IEvsEnumerator { +public: + // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow. + Return getCameraList(getCameraList_cb _hidl_cb) override; + Return> openCamera(const hidl_string& cameraId) override; + Return closeCamera(const ::android::sp& carCamera) override; + Return> openDisplay() override; + Return closeDisplay(const ::android::sp& display) override; + Return getDisplayState() override; + + // Implementation details + EvsEnumerator(); + +private: + // NOTE: All members values are static so that all clients operate on the same state + // That is to say, this is effectively a singleton despite the fact that HIDL + // constructs a new instance for each client. + struct CameraRecord { + CameraDesc_1_0 desc; + wp activeInstance; + + CameraRecord(const char *cameraId) : desc() { desc.cameraId = cameraId; } + }; + static std::list sCameraList; + + static wp sActiveDisplay; // Weak pointer. Object destructs if client dies. +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace evs +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H diff --git a/automotive/evs/1.1/default/ServiceNames.h b/automotive/evs/1.1/default/ServiceNames.h new file mode 100644 index 0000000000..1178da5a9c --- /dev/null +++ b/automotive/evs/1.1/default/ServiceNames.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2016 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. + */ + +const static char kEnumeratorServiceName[] = "EvsEnumeratorHw"; diff --git a/automotive/evs/1.1/default/android.hardware.automotive.evs@1.1-service.rc b/automotive/evs/1.1/default/android.hardware.automotive.evs@1.1-service.rc new file mode 100644 index 0000000000..284b3fda4e --- /dev/null +++ b/automotive/evs/1.1/default/android.hardware.automotive.evs@1.1-service.rc @@ -0,0 +1,5 @@ +service vendor.evs-hal-mock /vendor/bin/hw/android.hardware.automotive.evs@1.1-service + class hal + user automotive_evs + group automotive_evs + disabled diff --git a/automotive/evs/1.1/default/service.cpp b/automotive/evs/1.1/default/service.cpp new file mode 100644 index 0000000000..128a14aa30 --- /dev/null +++ b/automotive/evs/1.1/default/service.cpp @@ -0,0 +1,63 @@ +/* + * 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 "android.hardware.automotive.evs@1.1-service" + +#include + +#include +#include +#include +#include + +#include "ServiceNames.h" +#include "EvsEnumerator.h" +#include "EvsDisplay.h" + + +// libhidl: +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; + +// Generated HIDL files +using android::hardware::automotive::evs::V1_0::IEvsEnumerator; +using android::hardware::automotive::evs::V1_0::IEvsDisplay; + +// The namespace in which all our implementation code lives +using namespace android::hardware::automotive::evs::V1_1::implementation; +using namespace android; + + +int main() { + ALOGI("EVS Hardware Enumerator service is starting"); + android::sp service = new EvsEnumerator(); + + configureRpcThreadpool(1, true /* callerWillJoin */); + + // Register our service -- if somebody is already registered by our name, + // they will be killed (their thread pool will throw an exception). + status_t status = service->registerAsService(kEnumeratorServiceName); + if (status == OK) { + ALOGD("%s is ready.", kEnumeratorServiceName); + joinRpcThreadpool(); + } else { + ALOGE("Could not register service %s (%d).", kEnumeratorServiceName, status); + } + + // In normal operation, we don't expect the thread pool to exit + ALOGE("EVS Hardware Enumerator is shutting down"); + return 1; +} diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal new file mode 100644 index 0000000000..ff6ab4e785 --- /dev/null +++ b/automotive/evs/1.1/types.hal @@ -0,0 +1,84 @@ +/* + * 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. + */ + +package android.hardware.automotive.evs@1.1; + +import @1.0::CameraDesc; +import @1.0::DisplayDesc; +import @1.0::DisplayState; +import @1.0::EvsResult; +import android.hardware.graphics.common@1.2::HardwareBuffer; + +/** + * Structure representing an image buffer through our APIs + * + * In addition to the handle to the graphics memory, we need to retain + * the properties of the buffer for easy reference and reconstruction of + * an ANativeWindowBuffer object on the remote side of API calls. + * (Not least because OpenGL expect an ANativeWindowBuffer* for us as a + * texture via eglCreateImageKHR(). + */ +struct BufferDesc { + /** + * HIDL counterpart of `AHardwareBuffer_Desc`. Please see + * hardware/interfaces/graphics/common/1.2/types.hal for more details. + */ + HardwareBuffer buffer; + /** + * The size of a pixel in the units of bytes + */ + uint32_t pixelSize; + /** + * Opaque value from driver + */ + uint32_t bufferId; +}; + +/** + * EVS event types + */ +enum EvsEventType : uint32_t { + /** + * Video stream is started + */ + STREAM_STARTED = 0, + /** + * Video stream is stopped + */ + STREAM_STOPPED, + /** + * Video frame is dropped + */ + FRAME_DROPPED, + /** + * Timeout happens + */ + TIMEOUT, +}; + +/** + * EVS event definition + */ +safe_union EvsEvent { + /** + * A buffer descriptor of an image frame + */ + BufferDesc buffer; + /** + * General streaming events + */ + EvsEventType info; +}; diff --git a/automotive/evs/1.1/vts/functional/Android.bp b/automotive/evs/1.1/vts/functional/Android.bp new file mode 100644 index 0000000000..55c50a42b8 --- /dev/null +++ b/automotive/evs/1.1/vts/functional/Android.bp @@ -0,0 +1,40 @@ +// +// 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. +// + +cc_test { + name: "VtsHalEvsV1_1TargetTest", + srcs: [ + "FrameHandler.cpp", + "VtsHalEvsV1_1TargetTest.cpp", + ], + defaults: ["VtsHalTargetTestDefaults"], + shared_libs: [ + "libui", + ], + static_libs: [ + "android.hardware.automotive.evs@1.0", + "android.hardware.automotive.evs@1.1", + "android.hardware.automotive.evs@common-default-lib", + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + ], + test_suites: ["general-tests"], + cflags: [ + "-O0", + "-g", + ], +} diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp new file mode 100644 index 0000000000..b7c7f21c2d --- /dev/null +++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp @@ -0,0 +1,340 @@ +/* + * 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 "VtsHalEvsTest" + +#include "FrameHandler.h" +#include "FormatConvert.h" + +#include +#include + +#include +#include +#include + +FrameHandler::FrameHandler(android::sp pCamera, CameraDesc cameraInfo, + android::sp pDisplay, + BufferControlFlag mode) : + mCamera(pCamera), + mCameraInfo(cameraInfo), + mDisplay(pDisplay), + mReturnMode(mode) { + // Nothing but member initialization here... +} + + +void FrameHandler::shutdown() +{ + // Make sure we're not still streaming + blockingStopStream(); + + // At this point, the receiver thread is no longer running, so we can safely drop + // our remote object references so they can be freed + mCamera = nullptr; + mDisplay = nullptr; +} + + +bool FrameHandler::startStream() { + // Tell the camera to start streaming + Return result = mCamera->startVideoStream(this); + if (result != EvsResult::OK) { + return false; + } + + // Mark ourselves as running + mLock.lock(); + mRunning = true; + mLock.unlock(); + + return true; +} + + +void FrameHandler::asyncStopStream() { + // Tell the camera to stop streaming. + // This will result in a null frame being delivered when the stream actually stops. + mCamera->stopVideoStream(); +} + + +void FrameHandler::blockingStopStream() { + // Tell the stream to stop + asyncStopStream(); + + // Wait until the stream has actually stopped + std::unique_lock lock(mLock); + if (mRunning) { + mSignal.wait(lock, [this]() { return !mRunning; }); + } +} + + +bool FrameHandler::returnHeldBuffer() { + std::unique_lock lock(mLock); + + // Return the oldest buffer we're holding + if (mHeldBuffers.empty()) { + // No buffers are currently held + return false; + } + + BufferDesc_1_1 buffer = mHeldBuffers.front(); + mHeldBuffers.pop(); + mCamera->doneWithFrame_1_1(buffer); + + return true; +} + + +bool FrameHandler::isRunning() { + std::unique_lock lock(mLock); + return mRunning; +} + + +void FrameHandler::waitForFrameCount(unsigned frameCount) { + // Wait until we've seen at least the requested number of frames (could be more) + std::unique_lock lock(mLock); + mSignal.wait(lock, [this, frameCount](){ return mFramesReceived >= frameCount; }); +} + + +void FrameHandler::getFramesCounters(unsigned* received, unsigned* displayed) { + std::unique_lock lock(mLock); + + if (received) { + *received = mFramesReceived; + } + if (displayed) { + *displayed = mFramesDisplayed; + } +} + + +Return FrameHandler::deliverFrame(const BufferDesc_1_0& bufferArg) { + ALOGW("A frame delivered via v1.0 method is rejected."); + mCamera->doneWithFrame(bufferArg); + return Void(); +} + + +Return FrameHandler::notifyEvent(const EvsEvent& event) { + // Local flag we use to keep track of when the stream is stopping + bool timeToStop = false; + + auto type = event.getDiscriminator(); + if (type == EvsEvent::hidl_discriminator::info) { + if (event.info() == EvsEventType::STREAM_STOPPED) { + // Signal that the last frame has been received and the stream is stopped + timeToStop = true; + } else { + ALOGD("Received an event 0x%X", event.info()); + } + } else { + auto bufDesc = event.buffer(); + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&bufDesc.buffer.description); + ALOGD("Received a frame from the camera (%p)", + bufDesc.buffer.nativeHandle.getNativeHandle()); + + // Store a dimension of a received frame. + mFrameWidth = pDesc->width; + mFrameHeight = pDesc->height; + + // If we were given an opened display at construction time, then send the received + // image back down the camera. + if (mDisplay.get()) { + // Get the output buffer we'll use to display the imagery + BufferDesc_1_0 tgtBuffer = {}; + mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) { + tgtBuffer = buff; + } + ); + + if (tgtBuffer.memHandle == nullptr) { + printf("Didn't get target buffer - frame lost\n"); + ALOGE("Didn't get requested output buffer -- skipping this frame."); + } else { + // Copy the contents of the of buffer.memHandle into tgtBuffer + copyBufferContents(tgtBuffer, bufDesc); + + // Send the target buffer back for display + Return result = mDisplay->returnTargetBufferForDisplay(tgtBuffer); + if (!result.isOk()) { + printf("HIDL error on display buffer (%s)- frame lost\n", + result.description().c_str()); + ALOGE("Error making the remote function call. HIDL said %s", + result.description().c_str()); + } else if (result != EvsResult::OK) { + printf("Display reported error - frame lost\n"); + ALOGE("We encountered error %d when returning a buffer to the display!", + (EvsResult) result); + } else { + // Everything looks good! + // Keep track so tests or watch dogs can monitor progress + mLock.lock(); + mFramesDisplayed++; + mLock.unlock(); + } + } + } + + + switch (mReturnMode) { + case eAutoReturn: + // Send the camera buffer back now that the client has seen it + ALOGD("Calling doneWithFrame"); + // TODO: Why is it that we get a HIDL crash if we pass back the cloned buffer? + mCamera->doneWithFrame_1_1(bufDesc); + break; + case eNoAutoReturn: + // Hang onto the buffer handle for now -- the client will return it explicitly later + mHeldBuffers.push(bufDesc); + } + + + ALOGD("Frame handling complete"); + } + + + // Update our received frame count and notify anybody who cares that things have changed + mLock.lock(); + if (timeToStop) { + mRunning = false; + } else { + mFramesReceived++; + } + mLock.unlock(); + mSignal.notify_all(); + + return Void(); +} + + +bool FrameHandler::copyBufferContents(const BufferDesc_1_0& tgtBuffer, + const BufferDesc_1_1& srcBuffer) { + bool success = true; + const AHardwareBuffer_Desc* pSrcDesc = + reinterpret_cast(&srcBuffer.buffer.description); + + // Make sure we don't run off the end of either buffer + const unsigned width = std::min(tgtBuffer.width, + pSrcDesc->width); + const unsigned height = std::min(tgtBuffer.height, + pSrcDesc->height); + + sp tgt = new android::GraphicBuffer(tgtBuffer.memHandle, + android::GraphicBuffer::CLONE_HANDLE, + tgtBuffer.width, + tgtBuffer.height, + tgtBuffer.format, + 1, + tgtBuffer.usage, + tgtBuffer.stride); + sp src = new android::GraphicBuffer(srcBuffer.buffer.nativeHandle, + android::GraphicBuffer::CLONE_HANDLE, + pSrcDesc->width, + pSrcDesc->height, + pSrcDesc->format, + pSrcDesc->layers, + pSrcDesc->usage, + pSrcDesc->stride); + + // Lock our source buffer for reading (current expectation are for this to be NV21 format) + uint8_t* srcPixels = nullptr; + src->lock(GRALLOC_USAGE_SW_READ_OFTEN, (void**)&srcPixels); + + // Lock our target buffer for writing (should be either RGBA8888 or BGRA8888 format) + uint32_t* tgtPixels = nullptr; + tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels); + + if (srcPixels && tgtPixels) { + using namespace ::android::hardware::automotive::evs::common; + if (tgtBuffer.format == HAL_PIXEL_FORMAT_RGBA_8888) { + if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21 + Utils::copyNV21toRGB32(width, height, + srcPixels, + tgtPixels, tgtBuffer.stride); + } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12 + Utils::copyYV12toRGB32(width, height, + srcPixels, + tgtPixels, tgtBuffer.stride); + } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV + Utils::copyYUYVtoRGB32(width, height, + srcPixels, pSrcDesc->stride, + tgtPixels, tgtBuffer.stride); + } else if (pSrcDesc->format == tgtBuffer.format) { // 32bit RGBA + Utils::copyMatchedInterleavedFormats(width, height, + srcPixels, pSrcDesc->stride, + tgtPixels, tgtBuffer.stride, + tgtBuffer.pixelSize); + } else { + ALOGE("Camera buffer format is not supported"); + success = false; + } + } else if (tgtBuffer.format == HAL_PIXEL_FORMAT_BGRA_8888) { + if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21 + Utils::copyNV21toBGR32(width, height, + srcPixels, + tgtPixels, tgtBuffer.stride); + } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12 + Utils::copyYV12toBGR32(width, height, + srcPixels, + tgtPixels, tgtBuffer.stride); + } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV + Utils::copyYUYVtoBGR32(width, height, + srcPixels, pSrcDesc->stride, + tgtPixels, tgtBuffer.stride); + } else if (pSrcDesc->format == tgtBuffer.format) { // 32bit RGBA + Utils::copyMatchedInterleavedFormats(width, height, + srcPixels, pSrcDesc->stride, + tgtPixels, tgtBuffer.stride, + tgtBuffer.pixelSize); + } else { + ALOGE("Camera buffer format is not supported"); + success = false; + } + } else { + // We always expect 32 bit RGB for the display output for now. Is there a need for 565? + ALOGE("Diplay buffer is always expected to be 32bit RGBA"); + success = false; + } + } else { + ALOGE("Failed to lock buffer contents for contents transfer"); + success = false; + } + + if (srcPixels) { + src->unlock(); + } + if (tgtPixels) { + tgt->unlock(); + } + + return success; +} + +void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) { + if (width) { + *width = mFrameWidth; + } + + if (height) { + *height = mFrameHeight; + } +} diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h new file mode 100644 index 0000000000..49fa736435 --- /dev/null +++ b/automotive/evs/1.1/vts/functional/FrameHandler.h @@ -0,0 +1,102 @@ +/* + * 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. + */ + +#ifndef EVS_VTS_FRAMEHANDLER_H +#define EVS_VTS_FRAMEHANDLER_H + +#include + +#include + +#include +#include +#include + +using namespace ::android::hardware::automotive::evs::V1_1; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_handle; +using ::android::sp; +using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; +using ::android::hardware::automotive::evs::V1_0::EvsResult; +using ::android::hardware::automotive::evs::V1_0::CameraDesc; +using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc; +using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc; + + +/* + * FrameHandler: + * This class can be used to receive camera imagery from an IEvsCamera implementation. Given an + * IEvsDisplay instance at startup, it will forward the received imagery to the display, + * providing a trivial implementation of a rear vew camera type application. + * Note that the video frames are delivered on a background thread, while the control interface + * is actuated from the applications foreground thread. + */ +class FrameHandler : public IEvsCameraStream { +public: + enum BufferControlFlag { + eAutoReturn, + eNoAutoReturn, + }; + + FrameHandler(android::sp pCamera, CameraDesc cameraInfo, + android::sp pDisplay = nullptr, + BufferControlFlag mode = eAutoReturn); + void shutdown(); + + bool startStream(); + void asyncStopStream(); + void blockingStopStream(); + + bool returnHeldBuffer(); + + bool isRunning(); + + void waitForFrameCount(unsigned frameCount); + void getFramesCounters(unsigned* received, unsigned* displayed); + void getFrameDimension(unsigned* width, unsigned* height); + +private: + // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream + Return deliverFrame(const BufferDesc_1_0& buffer) override; + Return notifyEvent(const EvsEvent& event) override; + + // Local implementation details + bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer); + + // Values initialized as startup + android::sp mCamera; + CameraDesc mCameraInfo; + android::sp mDisplay; + BufferControlFlag mReturnMode; + + // Since we get frames delivered to us asynchronously via the IEvsCameraStream interface, + // we need to protect all member variables that may be modified while we're streaming + // (ie: those below) + std::mutex mLock; + std::condition_variable mSignal; + + std::queue mHeldBuffers; + bool mRunning = false; + unsigned mFramesReceived = 0; // Simple counter -- rolls over eventually! + unsigned mFramesDisplayed = 0; // Simple counter -- rolls over eventually! + unsigned mFrameWidth = 0; + unsigned mFrameHeight = 0; +}; + + +#endif //EVS_VTS_FRAMEHANDLER_H diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp new file mode 100644 index 0000000000..4f7082aa26 --- /dev/null +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -0,0 +1,526 @@ +/* + * 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 "VtsHalEvsTest" + + +// Note: We have't got a great way to indicate which target +// should be tested, so we'll leave the interface served by the +// default (mock) EVS driver here for easy reference. All +// actual EVS drivers should serve on the EvsEnumeratorHw name, +// however, so the code is checked in that way. +//const static char kEnumeratorName[] = "EvsEnumeratorHw-Mock"; +const static char kEnumeratorName[] = "EvsEnumeratorHw"; + + +// These values are called out in the EVS design doc (as of Mar 8, 2017) +static const int kMaxStreamStartMilliseconds = 500; +static const int kMinimumFramesPerSecond = 10; + +static const int kSecondsToMilliseconds = 1000; +static const int kMillisecondsToMicroseconds = 1000; +static const float kNanoToMilliseconds = 0.000001f; +static const float kNanoToSeconds = 0.000000001f; + + +#include "FrameHandler.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::android::hardware::automotive::evs::V1_1; + +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_string; +using ::android::sp; +using ::android::hardware::automotive::evs::V1_0::CameraDesc; +using ::android::hardware::automotive::evs::V1_0::DisplayDesc; +using ::android::hardware::automotive::evs::V1_0::DisplayState; +using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator; +using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera; +using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera; + +// Test environment for Evs HIDL HAL. +class EvsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static EvsHidlEnvironment* Instance() { + static EvsHidlEnvironment* instance = new EvsHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { registerTestService(); } + + private: + EvsHidlEnvironment() {} +}; + +// The main test class for EVS +class EvsHidlTest : public ::testing::VtsHalHidlTargetTestBase { +public: + virtual void SetUp() override { + // Make sure we can connect to the enumerator + string service_name = + EvsHidlEnvironment::Instance()->getServiceName(kEnumeratorName); + pEnumerator = getService(service_name); + ASSERT_NE(pEnumerator.get(), nullptr); + + mIsHwModule = !service_name.compare(kEnumeratorName); + } + + virtual void TearDown() override {} + +protected: + void loadCameraList() { + // SetUp() must run first! + assert(pEnumerator != nullptr); + + // Get the camera list + pEnumerator->getCameraList([this](hidl_vec cameraList) { + ALOGI("Camera list callback received %zu cameras", + cameraList.size()); + cameraInfo.reserve(cameraList.size()); + for (auto&& cam: cameraList) { + ALOGI("Found camera %s", cam.cameraId.c_str()); + cameraInfo.push_back(cam); + } + } + ); + + // We insist on at least one camera for EVS to pass any camera tests + ASSERT_GE(cameraInfo.size(), 1u); + } + + sp pEnumerator; // Every test needs access to the service + std::vector cameraInfo; // Empty unless/until loadCameraList() is called + bool mIsHwModule; // boolean to tell current module under testing + // is HW module implementation. +}; + + +// Test cases, their implementations, and corresponding requirements are +// documented at go/aae-evs-public-api-test. + +/* + * CameraOpenClean: + * Opens each camera reported by the enumerator and then explicitly closes it via a + * call to closeCamera. Then repeats the test to ensure all cameras can be reopened. + */ +TEST_F(EvsHidlTest, CameraOpenClean) { + ALOGI("Starting CameraOpenClean test"); + + // Get the camera list + loadCameraList(); + + // Open and close each camera twice + for (auto&& cam: cameraInfo) { + for (int pass = 0; pass < 2; pass++) { + sp pCam = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + .withDefault(nullptr); + ASSERT_NE(pCam, nullptr); + + // Verify that this camera self-identifies correctly + pCam->getCameraInfo([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.cameraId.c_str()); + EXPECT_EQ(cam.cameraId, desc.cameraId); + } + ); + + // Explicitly close the camera so resources are released right away + pEnumerator->closeCamera(pCam); + } + } +} + + +/* + * CameraOpenAggressive: + * Opens each camera reported by the enumerator twice in a row without an intervening closeCamera + * call. This ensures that the intended "aggressive open" behavior works. This is necessary for + * the system to be tolerant of shutdown/restart race conditions. + */ +TEST_F(EvsHidlTest, CameraOpenAggressive) { + ALOGI("Starting CameraOpenAggressive test"); + + // Get the camera list + loadCameraList(); + + // Open and close each camera twice + for (auto&& cam: cameraInfo) { + sp pCam = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + .withDefault(nullptr); + ASSERT_NE(pCam, nullptr); + + // Verify that this camera self-identifies correctly + pCam->getCameraInfo([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.cameraId.c_str()); + EXPECT_EQ(cam.cameraId, desc.cameraId); + } + ); + + sp pCam2 = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + .withDefault(nullptr); + ASSERT_NE(pCam, pCam2); + ASSERT_NE(pCam2, nullptr); + + Return result = pCam->setMaxFramesInFlight(2); + if (mIsHwModule) { + // Verify that the old camera rejects calls via HW module. + EXPECT_EQ(EvsResult::OWNERSHIP_LOST, EvsResult(result)); + } else { + // default implementation supports multiple clients. + EXPECT_EQ(EvsResult::OK, EvsResult(result)); + } + + // Close the superceded camera + pEnumerator->closeCamera(pCam); + + // Verify that the second camera instance self-identifies correctly + pCam2->getCameraInfo([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.cameraId.c_str()); + EXPECT_EQ(cam.cameraId, desc.cameraId); + } + ); + + // Close the second camera instance + pEnumerator->closeCamera(pCam2); + } + + // Sleep here to ensure the destructor cleanup has time to run so we don't break follow on tests + sleep(1); // I hate that this is an arbitrary time to wait. :( b/36122635 +} + + +/* + * CameraStreamPerformance: + * Measure and qualify the stream start up time and streaming frame rate of each reported camera + */ +TEST_F(EvsHidlTest, CameraStreamPerformance) { + ALOGI("Starting CameraStreamPerformance test"); + + // Get the camera list + loadCameraList(); + + // Test each reported camera + for (auto&& cam: cameraInfo) { + sp pCam = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + .withDefault(nullptr); + ASSERT_NE(pCam, nullptr); + + // Set up a frame receiver object which will fire up its own thread + sp frameHandler = new FrameHandler(pCam, cam, + nullptr, + FrameHandler::eAutoReturn); + + // Start the camera's video stream + nsecs_t start = systemTime(SYSTEM_TIME_MONOTONIC); + bool startResult = frameHandler->startStream(); + ASSERT_TRUE(startResult); + + // Ensure the first frame arrived within the expected time + frameHandler->waitForFrameCount(1); + nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t timeToFirstFrame = systemTime(SYSTEM_TIME_MONOTONIC) - start; + EXPECT_LE(nanoseconds_to_milliseconds(timeToFirstFrame), kMaxStreamStartMilliseconds); + printf("Measured time to first frame %0.2f ms\n", timeToFirstFrame * kNanoToMilliseconds); + ALOGI("Measured time to first frame %0.2f ms", timeToFirstFrame * kNanoToMilliseconds); + + // Check aspect ratio + unsigned width = 0, height = 0; + frameHandler->getFrameDimension(&width, &height); + EXPECT_GE(width, height); + + // Wait a bit, then ensure we get at least the required minimum number of frames + sleep(5); + nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC); + unsigned framesReceived = 0; + frameHandler->getFramesCounters(&framesReceived, nullptr); + framesReceived = framesReceived - 1; // Back out the first frame we already waited for + nsecs_t runTime = end - firstFrame; + float framesPerSecond = framesReceived / (runTime * kNanoToSeconds); + printf("Measured camera rate %3.2f fps\n", framesPerSecond); + ALOGI("Measured camera rate %3.2f fps", framesPerSecond); + EXPECT_GE(framesPerSecond, kMinimumFramesPerSecond); + + // Even when the camera pointer goes out of scope, the FrameHandler object will + // keep the stream alive unless we tell it to shutdown. + // Also note that the FrameHandle and the Camera have a mutual circular reference, so + // we have to break that cycle in order for either of them to get cleaned up. + frameHandler->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCam); + } +} + + +/* + * CameraStreamBuffering: + * Ensure the camera implementation behaves properly when the client holds onto buffers for more + * than one frame time. The camera must cleanly skip frames until the client is ready again. + */ +TEST_F(EvsHidlTest, CameraStreamBuffering) { + ALOGI("Starting CameraStreamBuffering test"); + + // Arbitrary constant (should be > 1 and less than crazy) + static const unsigned int kBuffersToHold = 6; + + // Get the camera list + loadCameraList(); + + // Test each reported camera + for (auto&& cam: cameraInfo) { + + sp pCam = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + .withDefault(nullptr); + ASSERT_NE(pCam, nullptr); + + // Ask for a crazy number of buffers in flight to ensure it errors correctly + Return badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF); + EXPECT_EQ(EvsResult::BUFFER_NOT_AVAILABLE, badResult); + + // Now ask for exactly two buffers in flight as we'll test behavior in that case + Return goodResult = pCam->setMaxFramesInFlight(kBuffersToHold); + EXPECT_EQ(EvsResult::OK, goodResult); + + + // Set up a frame receiver object which will fire up its own thread. + sp frameHandler = new FrameHandler(pCam, cam, + nullptr, + FrameHandler::eNoAutoReturn); + + // Start the camera's video stream + bool startResult = frameHandler->startStream(); + ASSERT_TRUE(startResult); + + // Check that the video stream stalls once we've gotten exactly the number of buffers + // we requested since we told the frameHandler not to return them. + sleep(2); // 1 second should be enough for at least 5 frames to be delivered worst case + unsigned framesReceived = 0; + frameHandler->getFramesCounters(&framesReceived, nullptr); + ASSERT_EQ(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit"; + + + // Give back one buffer + bool didReturnBuffer = frameHandler->returnHeldBuffer(); + EXPECT_TRUE(didReturnBuffer); + + // Once we return a buffer, it shouldn't take more than 1/10 second to get a new one + // filled since we require 10fps minimum -- but give a 10% allowance just in case. + usleep(110 * kMillisecondsToMicroseconds); + frameHandler->getFramesCounters(&framesReceived, nullptr); + EXPECT_EQ(kBuffersToHold+1, framesReceived) << "Stream should've resumed"; + + // Even when the camera pointer goes out of scope, the FrameHandler object will + // keep the stream alive unless we tell it to shutdown. + // Also note that the FrameHandle and the Camera have a mutual circular reference, so + // we have to break that cycle in order for either of them to get cleaned up. + frameHandler->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCam); + } +} + + +/* + * CameraToDisplayRoundTrip: + * End to end test of data flowing from the camera to the display. Each delivered frame of camera + * imagery is simply copied to the display buffer and presented on screen. This is the one test + * which a human could observe to see the operation of the system on the physical display. + */ +TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { + ALOGI("Starting CameraToDisplayRoundTrip test"); + + // Get the camera list + loadCameraList(); + + // Request exclusive access to the EVS display + sp pDisplay = pEnumerator->openDisplay(); + ASSERT_NE(pDisplay, nullptr); + + // Test each reported camera + for (auto&& cam: cameraInfo) { + sp pCam = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + .withDefault(nullptr); + ASSERT_NE(pCam, nullptr); + + // Set up a frame receiver object which will fire up its own thread. + sp frameHandler = new FrameHandler(pCam, cam, + pDisplay, + FrameHandler::eAutoReturn); + + + // Activate the display + pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME); + + // Start the camera's video stream + bool startResult = frameHandler->startStream(); + ASSERT_TRUE(startResult); + + // Wait a while to let the data flow + static const int kSecondsToWait = 5; + const int streamTimeMs = kSecondsToWait * kSecondsToMilliseconds - + kMaxStreamStartMilliseconds; + const unsigned minimumFramesExpected = streamTimeMs * kMinimumFramesPerSecond / + kSecondsToMilliseconds; + sleep(kSecondsToWait); + unsigned framesReceived = 0; + unsigned framesDisplayed = 0; + frameHandler->getFramesCounters(&framesReceived, &framesDisplayed); + EXPECT_EQ(framesReceived, framesDisplayed); + EXPECT_GE(framesDisplayed, minimumFramesExpected); + + // Turn off the display (yes, before the stream stops -- it should be handled) + pDisplay->setDisplayState(DisplayState::NOT_VISIBLE); + + // Shut down the streamer + frameHandler->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCam); + } + + // Explicitly release the display + pEnumerator->closeDisplay(pDisplay); +} + + +/* + * MultiCameraStream: + * Verify that each client can start and stop video streams on the same + * underlying camera. + */ +TEST_F(EvsHidlTest, MultiCameraStream) { + ALOGI("Starting MultiCameraStream test"); + + if (mIsHwModule) { + // This test is not for HW module implementation. + return; + } + + // Get the camera list + loadCameraList(); + + // Test each reported camera + for (auto&& cam: cameraInfo) { + // Create two camera clients. + sp pCam0 = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + .withDefault(nullptr); + ASSERT_NE(pCam0, nullptr); + + sp pCam1 = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + .withDefault(nullptr); + ASSERT_NE(pCam1, nullptr); + + // Set up per-client frame receiver objects which will fire up its own thread + sp frameHandler0 = new FrameHandler(pCam0, cam, + nullptr, + FrameHandler::eAutoReturn); + ASSERT_NE(frameHandler0, nullptr); + + sp frameHandler1 = new FrameHandler(pCam1, cam, + nullptr, + FrameHandler::eAutoReturn); + ASSERT_NE(frameHandler1, nullptr); + + // Start the camera's video stream via client 0 + bool startResult = false; + startResult = frameHandler0->startStream() && + frameHandler1->startStream(); + ASSERT_TRUE(startResult); + + // Ensure the stream starts + frameHandler0->waitForFrameCount(1); + frameHandler1->waitForFrameCount(1); + + nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC); + + // Wait a bit, then ensure both clients get at least the required minimum number of frames + sleep(5); + nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC); + unsigned framesReceived0 = 0, framesReceived1 = 0; + frameHandler0->getFramesCounters(&framesReceived0, nullptr); + frameHandler1->getFramesCounters(&framesReceived1, nullptr); + framesReceived0 = framesReceived0 - 1; // Back out the first frame we already waited for + framesReceived1 = framesReceived1 - 1; // Back out the first frame we already waited for + nsecs_t runTime = end - firstFrame; + float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds); + float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds); + printf("Measured camera rate %3.2f fps and %3.2f fps\n", framesPerSecond0, framesPerSecond1); + ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1); + EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond); + EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond); + + // Shutdown one client + frameHandler0->shutdown(); + + // Read frame counters again + frameHandler0->getFramesCounters(&framesReceived0, nullptr); + frameHandler1->getFramesCounters(&framesReceived1, nullptr); + + // Wait a bit again + sleep(5); + unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0; + frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr); + frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr); + EXPECT_EQ(framesReceived0, framesReceivedAfterStop0); + EXPECT_LT(framesReceived1, framesReceivedAfterStop1); + + // Shutdown another + frameHandler1->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCam0); + pEnumerator->closeCamera(pCam1); + } +} + + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + EvsHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +} From f76964bbd65a4c510c81faa69541934f097ba60c Mon Sep 17 00:00:00 2001 From: jiabin Date: Wed, 31 Jul 2019 12:54:19 -0700 Subject: [PATCH 0049/1022] Add libaudiofoundation. Some classes, e.g. AudioGain, in libaudiofoundation, which are used by libaudiopolicycomponent, will require libaudiofoundation as a shared library to avoid link error when building. Bug: 135621476 Test: make Change-Id: I8732bdab37d8afd866fe03a74db3dc564fea1ad2 --- audio/core/all-versions/vts/functional/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp index 88fdb5a1dd..5e17ade365 100644 --- a/audio/core/all-versions/vts/functional/Android.bp +++ b/audio/core/all-versions/vts/functional/Android.bp @@ -24,6 +24,7 @@ cc_defaults { "libxml2", ], shared_libs: [ + "libaudiofoundation", "libfmq", ], header_libs: [ From 2619443e0a8b5bb8ca19c6c5761c8f6a834e4936 Mon Sep 17 00:00:00 2001 From: Jordan Jozwiak Date: Thu, 1 Aug 2019 18:48:03 -0700 Subject: [PATCH 0050/1022] Add DISTANCE_DISPLAY_UNIT to google VHAL Bug: 138816759 Test: aae app vhal apply google & dump properties Change-Id: I6a4d571975d5fe7ba6419cd4c37b734f21162f41 --- .../vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h | 7 +++++++ 1 file changed, 7 insertions(+) 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 7bafd2c4ff..293cc72504 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 @@ -556,6 +556,13 @@ const ConfigDeclaration kVehicleProperties[]{ .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS}}, .initialValue = {.int32Values = {(int)VehicleUnit::FAHRENHEIT}}}, + {.config = {.prop = toInt(VehicleProperty::DISTANCE_DISPLAY_UNITS), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {(int)VehicleUnit::KILOMETER, (int)VehicleUnit::MILE}, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}}, + .initialValue = {.int32Values = {(int)VehicleUnit::MILE}}}, + {.config = { .prop = toInt(VehicleProperty::NIGHT_MODE), From a27d4e435a566aa616e5b5a2e9a03a45bccf8090 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 7 Jun 2019 15:21:02 -0700 Subject: [PATCH 0051/1022] Define CAN bus HAL. Bug: 135918744 Test: VTS (separate new change) Change-Id: Ia4de5ee441834c7870e33481e982960a1593de28 --- automotive/can/1.0/Android.bp | 20 +++ automotive/can/1.0/ICanBus.hal | 60 +++++++ automotive/can/1.0/ICanController.hal | 190 +++++++++++++++++++++ automotive/can/1.0/ICanMessageListener.hal | 40 +++++ automotive/can/1.0/ICloseHandle.hal | 33 ++++ automotive/can/1.0/types.hal | 112 ++++++++++++ 6 files changed, 455 insertions(+) create mode 100644 automotive/can/1.0/Android.bp create mode 100644 automotive/can/1.0/ICanBus.hal create mode 100644 automotive/can/1.0/ICanController.hal create mode 100644 automotive/can/1.0/ICanMessageListener.hal create mode 100644 automotive/can/1.0/ICloseHandle.hal create mode 100644 automotive/can/1.0/types.hal diff --git a/automotive/can/1.0/Android.bp b/automotive/can/1.0/Android.bp new file mode 100644 index 0000000000..fe2a2bed21 --- /dev/null +++ b/automotive/can/1.0/Android.bp @@ -0,0 +1,20 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.automotive.can@1.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "ICanBus.hal", + "ICanController.hal", + "ICanMessageListener.hal", + "ICloseHandle.hal", + ], + interfaces: [ + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/automotive/can/1.0/ICanBus.hal b/automotive/can/1.0/ICanBus.hal new file mode 100644 index 0000000000..6ed89f3b22 --- /dev/null +++ b/automotive/can/1.0/ICanBus.hal @@ -0,0 +1,60 @@ +/* + * 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. + */ +package android.hardware.automotive.can@1.0; + +import ICanMessageListener; +import ICloseHandle; + +/** + * Represents a CAN bus interface that's up and configured. + * + * Configuration part is done in ICanController. + */ +interface ICanBus { + /** + * Send CAN message. + * + * @param message CAN message to send out + * @return result OK in the case of success + * PAYLOAD_TOO_LONG if the payload is too long + * INTERFACE_DOWN if the bus is down + * TRANSMISSION_FAILURE in case of transmission failure + */ + send(CanMessage message) generates (Result result); + + /** + * Requests HAL implementation to listen for specific CAN messages. + * + * HAL is responsible for maintaining listener set and sending out messages + * to each listener that matches given filter against received message. + * + * Empty filter list means no filtering. If two or more listeners requested + * different filters, HAL server must merge these to fulfill the superset of + * these filters. HAL must not send out a message to a listener which filter + * doesn't match given message id. + * + * If filtering is not supported at the hardware level (what's strongly + * recommended), it must be covered in the HAL. + * + * @param filter The set of requested filters + * @param listener The interface to receive the messages on + * @return result OK in the case of success + * INTERFACE_DOWN if the bus is down + * @return close A handle to call in order to remove the listener + */ + listen(vec filter, ICanMessageListener listener) + generates (Result result, ICloseHandle close); +}; diff --git a/automotive/can/1.0/ICanController.hal b/automotive/can/1.0/ICanController.hal new file mode 100644 index 0000000000..2c7494a907 --- /dev/null +++ b/automotive/can/1.0/ICanController.hal @@ -0,0 +1,190 @@ +/* + * 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. + */ +package android.hardware.automotive.can@1.0; + +/** + * Represents a CAN controller that's capable of configuring CAN bus interfaces. + * + * The goal of this service is to configure CAN interfaces and bring up HIDL + * server instances of ICanBus for each one that's up. + * + * Providing an ICanController interface to configure CAN buses is optional. + * A system can elect to publish only ICanBus if the hardware is hardcoded + * for a specific application. + */ +interface ICanController { + /** + * Type of an interface, a mean to express the domain of device address. + */ + enum InterfaceType : uint8_t { + /** + * Virtual SocketCAN interface. + * + * The address is an interface name, such as vcan0. If the interface + * doesn't exist, HAL server must create it. + * + * Valid InterfaceIdentifier types: + * - address. + */ + VIRTUAL, + + /** + * Native SocketCAN interface. + * + * The address is an interface name, such as can0. + * + * Valid InterfaceIdentifier types: + * - address; + * - serialno. + */ + SOCKETCAN, + + /** + * Serial-based interface. + * + * The address is a patch to a device, such as /dev/ttyUSB0. + * + * Valid InterfaceIdentifier types: + * - address; + * - serialno. + */ + SLCAN, + + /** + * Proprietary interface, specific to the hardware system Android + * is running on. Instead of using address field, the interface is + * addressed with 0-based index. + * + * Valid InterfaceIdentifier types: + * - index + */ + INDEXED + }; + + enum Result : uint8_t { + OK, + + /** + * General error class, if others are not applicable. + */ + UNKNOWN_ERROR, + + /** + * Up request was called out of order (i.e. trying to up the + * interface twice). + */ + INVALID_STATE, + + /** Interface type is not supported. */ + NOT_SUPPORTED, + + /** + * Provided address (interface name, device path) doesn't exist or there + * is no device with a given serial no. + */ + BAD_ADDRESS, + + /** Provided baud rate is not supported by the hardware. */ + BAD_BAUDRATE, + }; + + /** + * Configuration of the (physical or virtual) CAN bus. + * + * ISO TP and CAN FD are currently not supported. + */ + struct BusConfiguration { + /** + * Name under which ICanBus HIDL service should be published. + * + * It must consist of only alphanumeric characters and underscore + * (a-z, A-Z, 0-9, '_'), at least 1 and at most 32 characters long. + */ + string name; + + /** + * Type of the hardware (or virtual) CAN interface. + */ + InterfaceType iftype; + + /** + * Identification of hardware interface to configure. + */ + safe_union InterfaceIdentifier { + /** + * Interface name or other mean of identification of the specific + * interface port. Syntax depends on {@see iftype}, for details + * {@see InterfaceType}. + */ + string address; + + /** + * Numerical identifier of interface, used for InterfaceType#INDEXED. + */ + uint8_t index; + + /** + * Alternatively to providing {@see address}, one may provide a list + * of interface serial number suffixes. If there happens to be + * a device (like USB2CAN) with a matching serial number suffix, + * it gets selected. + * + * Client may utilize this in two ways: by matching against the + * entire serial number, or the last few characters (usually one). + * The former is better for small-scale test deployments (with just + * a handful of vehicles), the latter is good for larger scale + * (where a small suffix list may support large test fleet). + */ + vec serialno; + } interfaceId; + + /** + * Baud rate for CAN communication. + * + * Typical baud rates are: 100000, 125000, 250000, 500000. + * + * For virtual interfaces this value is ignored. + */ + uint32_t baudrate; + }; + + /** + * Fetches the list of interface types supported by this HAL server. + * + * @return iftypes The list of supported interface types + */ + getSupportedInterfaceTypes() generates (vec iftypes); + + /** + * Bring up the CAN interface and publish ICanBus server instance. + * + * @param config Configuration of the CAN interface + * @return result OK if the operation succeeded; error code otherwise. + */ + upInterface(BusConfiguration config) generates (Result result); + + /** + * Unpublish ICanBus server instance and bring down the CAN interface. + * + * In case of failure, at least the ICanBus server instance must be + * unpublished and resources freed on best-effort basis. + * + * @param name Name of the interface (@see BusConfiguration#name} to + * bring down + * @return success true in case of success, false otherwise + */ + downInterface(string name) generates (bool success); +}; diff --git a/automotive/can/1.0/ICanMessageListener.hal b/automotive/can/1.0/ICanMessageListener.hal new file mode 100644 index 0000000000..992d1c77ff --- /dev/null +++ b/automotive/can/1.0/ICanMessageListener.hal @@ -0,0 +1,40 @@ +/* + * 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. + */ +package android.hardware.automotive.can@1.0; + +/** + * CAN message listener. + */ +interface ICanMessageListener { + /** + * Called on received CAN message. + * + * The timestamp field of message struct is set to time when the message + * was received by the hardware. If it's not possible to fetch exact + * hardware time, this field should be set as early as possible to decrease + * potential time delta. + * + * @param message Received CAN message + */ + onReceive(CanMessage message); + + /** + * Called on error event. + * + * @param error Error type + */ + onError(ErrorEvent error); +}; diff --git a/automotive/can/1.0/ICloseHandle.hal b/automotive/can/1.0/ICloseHandle.hal new file mode 100644 index 0000000000..924c58bfff --- /dev/null +++ b/automotive/can/1.0/ICloseHandle.hal @@ -0,0 +1,33 @@ +/* + * 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. + */ +package android.hardware.automotive.can@1.0; + +/** + * Represents a generic close handle to remove a callback that doesn't need + * active interface. + * + * When close() is called OR when the interface is released, the underlying + * resources must be freed. + */ +interface ICloseHandle { + /** + * Closes the handle. + * + * The call must not fail and must be issued by the client at most once. + * Otherwise, the server must ignore subsequent calls. + */ + close(); +}; diff --git a/automotive/can/1.0/types.hal b/automotive/can/1.0/types.hal new file mode 100644 index 0000000000..37877c6023 --- /dev/null +++ b/automotive/can/1.0/types.hal @@ -0,0 +1,112 @@ +/* + * 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. + */ +package android.hardware.automotive.can@1.0; + +/** + * CAN message ID. + * + * Does not include any flags like RTR nor ERR, only a plain 11-bit + * or 29-bit identifier, as defined in CAN 1.x/2.0x. + * + * Unused bits must be set to zero. + */ +typedef uint32_t CanMessageId; + +/** + * CAN message being sent or received. + */ +struct CanMessage { + CanMessageId id; + + /** + * CAN message payload, as defined in CAN 1.x and CAN 2.x standards. + * + * The length of the payload vector directly translates to the length + * of the data frame (i.e. includes any padding bytes), so it may be in + * a range of: + * - 0-8 bytes for standard CAN; + * - up to 64 bytes for CAN FD. + * ISO TP is not supported directly for now. + */ + vec payload; + + /** + * Time in nanoseconds since boot. + * + * Ignored for outgoing messages. + */ + uint64_t timestamp; + + /** + * A request to proactively pull certain data from other ECU in CAN network. + * + * For details please refer to CAN standard. + * + * If this flag is set, payload must be empty. + */ + bool remoteTransmissionRequest; +}; + +/** + * Single filter rule for CAN messages. + * + * A filter is satisfied if: + * ((receivedId & mask) == (id & mask)) == !inverted + * + * In order for set of filters to match, at least one non-inverted filters must match (if there is + * one) and all inverted filters must match. In other words: + * - a single matching non-inverted filter makes the whole set matching; + * - a single non-matching inverted filter makes the whole set non-matching. + */ +struct CanMessageFilter { + CanMessageId id; + uint32_t mask; + bool inverted; +}; + +enum Result : uint8_t { + OK, + UNKNOWN_ERROR, + PAYLOAD_TOO_LONG, + INTERFACE_DOWN, + TRANSMISSION_FAILURE, + INVALID_ARGUMENTS, +}; + +/** + * @see ICanMessageListener#onError + */ +enum ErrorEvent : uint8_t { + UNKNOWN_ERROR, + + /** A problem with CAN interface HW. */ + HARDWARE_ERROR, + + /** TX buffer overflow: client is sending too many packets. */ + TX_OVERFLOW, + + /** RX buffer overflow: client is not reading packets fast enough. */ + RX_OVERFLOW, + + /** Received malformed input. */ + MALFORMED_INPUT, + + /** Bus overload: there is too much traffic on the bus. */ + BUS_OVERLOAD, + + /** Bus error: shorted Hi/Lo line, bus off etc. */ + BUS_ERROR, +}; From 0cb0aed337d3e8818d7501946e11ec2d2411160b Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Thu, 4 Jul 2019 14:51:22 +0800 Subject: [PATCH 0052/1022] ocsp: add getOcsp and setOcsp methods to control ocsp behavior Bug: 136720092 Test: atest VtsHalWifiSupplicantV1_3TargetTest Change-Id: Ic4a4123cbf96a886e3403b7ff5b73aa6be8b0136 --- wifi/supplicant/1.3/Android.bp | 21 ++++++ wifi/supplicant/1.3/ISupplicant.hal | 30 ++++++++ wifi/supplicant/1.3/ISupplicantStaNetwork.hal | 50 +++++++++++++ wifi/supplicant/1.3/types.hal | 27 +++++++ wifi/supplicant/1.3/vts/OWNERS | 2 + wifi/supplicant/1.3/vts/functional/Android.bp | 67 +++++++++++++++++ .../VtsHalWifiSupplicantV1_3TargetTest.cpp | 62 ++++++++++++++++ .../supplicant_hidl_test_utils_1_3.cpp | 28 +++++++ .../supplicant_hidl_test_utils_1_3.h | 25 +++++++ .../supplicant_sta_network_hidl_test.cpp | 73 +++++++++++++++++++ 10 files changed, 385 insertions(+) create mode 100644 wifi/supplicant/1.3/Android.bp create mode 100644 wifi/supplicant/1.3/ISupplicant.hal create mode 100644 wifi/supplicant/1.3/ISupplicantStaNetwork.hal create mode 100644 wifi/supplicant/1.3/types.hal create mode 100644 wifi/supplicant/1.3/vts/OWNERS create mode 100644 wifi/supplicant/1.3/vts/functional/Android.bp create mode 100644 wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp create mode 100644 wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp create mode 100644 wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h create mode 100644 wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp diff --git a/wifi/supplicant/1.3/Android.bp b/wifi/supplicant/1.3/Android.bp new file mode 100644 index 0000000000..6633d9d1e3 --- /dev/null +++ b/wifi/supplicant/1.3/Android.bp @@ -0,0 +1,21 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.wifi.supplicant@1.3", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "ISupplicant.hal", + "ISupplicantStaNetwork.hal", + ], + interfaces: [ + "android.hardware.wifi.supplicant@1.0", + "android.hardware.wifi.supplicant@1.1", + "android.hardware.wifi.supplicant@1.2", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/wifi/supplicant/1.3/ISupplicant.hal b/wifi/supplicant/1.3/ISupplicant.hal new file mode 100644 index 0000000000..75b7e960ea --- /dev/null +++ b/wifi/supplicant/1.3/ISupplicant.hal @@ -0,0 +1,30 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi.supplicant@1.3; + +import @1.2::ISupplicant; + +/** + * Interface exposed by the supplicant HIDL service registered + * with the hardware service manager. + * This is the root level object for any the supplicant interactions. + * To use 1.3 features you must cast specific interfaces returned from the + * 1.2 HAL. For example V1_2::ISupplicant::addIface() adds V1_2::ISupplicantIface, + * which can be cast to V1_3::ISupplicantStaIface. + */ +interface ISupplicant extends @1.2::ISupplicant { +}; diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal new file mode 100644 index 0000000000..eb9de9a53e --- /dev/null +++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal @@ -0,0 +1,50 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi.supplicant@1.3; + +import @1.0::SupplicantStatus; +import @1.2::ISupplicantStaNetwork; + +/** + * Interface exposed by the supplicant for each station mode network + * configuration it controls. + */ +interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { + /** + * Set OCSP (Online Certificate Status Protocol) type for this network. + * + * @param ocspType value to set. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + setOcsp(OcspType ocspType) generates (SupplicantStatus status); + + /** + * Get OCSP (Online Certificate Status Protocol) type for this network. + * + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + * @return ocspType ocsp type. + */ + getOcsp() generates (SupplicantStatus status, OcspType ocspType); +}; diff --git a/wifi/supplicant/1.3/types.hal b/wifi/supplicant/1.3/types.hal new file mode 100644 index 0000000000..a782b49584 --- /dev/null +++ b/wifi/supplicant/1.3/types.hal @@ -0,0 +1,27 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi.supplicant@1.3; + +/** + * OcspType: The type of OCSP request. + */ +enum OcspType : uint32_t { + NONE, + REQUEST_CERT_STATUS, + REQUIRE_CERT_STATUS, + REQUIRE_ALL_CERTS_STATUS, +}; diff --git a/wifi/supplicant/1.3/vts/OWNERS b/wifi/supplicant/1.3/vts/OWNERS new file mode 100644 index 0000000000..8bfb14882c --- /dev/null +++ b/wifi/supplicant/1.3/vts/OWNERS @@ -0,0 +1,2 @@ +rpius@google.com +etancohen@google.com diff --git a/wifi/supplicant/1.3/vts/functional/Android.bp b/wifi/supplicant/1.3/vts/functional/Android.bp new file mode 100644 index 0000000000..6f58168c23 --- /dev/null +++ b/wifi/supplicant/1.3/vts/functional/Android.bp @@ -0,0 +1,67 @@ +// +// 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. +// + +cc_library_static { + name: "VtsHalWifiSupplicantV1_3TargetTestUtil", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["supplicant_hidl_test_utils_1_3.cpp"], + export_include_dirs: [ + "." + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "VtsHalWifiSupplicantV1_0TargetTestUtil", + "VtsHalWifiSupplicantV1_1TargetTestUtil", + "VtsHalWifiSupplicantV1_2TargetTestUtil", + "android.hardware.wifi.supplicant@1.0", + "android.hardware.wifi.supplicant@1.1", + "android.hardware.wifi.supplicant@1.2", + "android.hardware.wifi.supplicant@1.3", + "android.hardware.wifi@1.0", + "libcrypto", + "libgmock", + "libwifi-system", + "libwifi-system-iface", + ], +} + +cc_test { + name: "VtsHalWifiSupplicantV1_3TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "VtsHalWifiSupplicantV1_3TargetTest.cpp", + "supplicant_sta_network_hidl_test.cpp", + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "VtsHalWifiSupplicantV1_0TargetTestUtil", + "VtsHalWifiSupplicantV1_1TargetTestUtil", + "VtsHalWifiSupplicantV1_2TargetTestUtil", + "VtsHalWifiSupplicantV1_3TargetTestUtil", + "android.hardware.wifi.supplicant@1.0", + "android.hardware.wifi.supplicant@1.1", + "android.hardware.wifi.supplicant@1.2", + "android.hardware.wifi.supplicant@1.3", + "android.hardware.wifi@1.0", + "android.hardware.wifi@1.1", + "libcrypto", + "libgmock", + "libwifi-system", + "libwifi-system-iface", + ], + test_suites: ["general-tests"], +} + diff --git a/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp b/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp new file mode 100644 index 0000000000..4dbb64eeda --- /dev/null +++ b/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp @@ -0,0 +1,62 @@ +/* + * 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. + */ + +#include +#include +#include + +#include "supplicant_hidl_test_utils.h" +#include "wifi_hidl_test_utils.h" + +class WifiSupplicantHidlEnvironment_1_3 : public WifiSupplicantHidlEnvironment { + public: + // get the test environment singleton + static WifiSupplicantHidlEnvironment_1_3* Instance() { + static WifiSupplicantHidlEnvironment_1_3* instance = + new WifiSupplicantHidlEnvironment_1_3; + return instance; + } + virtual void registerTestServices() override { + registerTestService<::android::hardware::wifi::V1_0::IWifi>(); + registerTestService<::android::hardware::wifi::V1_1::IWifi>(); + registerTestService< + ::android::hardware::wifi::supplicant::V1_0::ISupplicant>(); + registerTestService< + ::android::hardware::wifi::supplicant::V1_1::ISupplicant>(); + registerTestService< + ::android::hardware::wifi::supplicant::V1_2::ISupplicant>(); + registerTestService< + ::android::hardware::wifi::supplicant::V1_3::ISupplicant>(); + } + + private: + WifiSupplicantHidlEnvironment_1_3() {} +}; + +WifiSupplicantHidlEnvironment* gEnv = + WifiSupplicantHidlEnvironment_1_3::Instance(); + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(gEnv); + ::testing::InitGoogleTest(&argc, argv); + gEnv->init(&argc, argv); + int status = gEnv->initFromOptions(argc, argv); + if (status == 0) { + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + } + return status; +} diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp new file mode 100644 index 0000000000..86959eba97 --- /dev/null +++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp @@ -0,0 +1,28 @@ +/* + * 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. + */ + +#include +#include + +#include "supplicant_hidl_test_utils.h" +#include "supplicant_hidl_test_utils_1_3.h" + +using ::android::sp; +using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork; + +sp createSupplicantStaNetwork_1_3() { + return ISupplicantStaNetwork::castFrom(createSupplicantStaNetwork()); +} diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h new file mode 100644 index 0000000000..8e64162d04 --- /dev/null +++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#ifndef SUPPLICANT_HIDL_TEST_UTILS_1_3_H +#define SUPPLICANT_HIDL_TEST_UTILS_1_3_H + +#include + +android::sp +createSupplicantStaNetwork_1_3(); + +#endif /* SUPPLICANT_HIDL_TEST_UTILS_1_3_H */ diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp new file mode 100644 index 0000000000..e5be0ccfef --- /dev/null +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp @@ -0,0 +1,73 @@ +/* + * 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. + */ + +#include + +#include +#include + +#include "supplicant_hidl_test_utils.h" +#include "supplicant_hidl_test_utils_1_3.h" + +using ::android::sp; +using ::android::hardware::hidl_vec; +using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus; +using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; +using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork; +using ::android::hardware::wifi::supplicant::V1_3::OcspType; +namespace { +constexpr OcspType kTestOcspType = OcspType::REQUEST_CERT_STATUS; +constexpr OcspType kTestInvalidOcspType = (OcspType)-1; +} // namespace + +class SupplicantStaNetworkHidlTest + : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + startSupplicantAndWaitForHidlService(); + EXPECT_TRUE(turnOnExcessiveLogging()); + sta_network_ = createSupplicantStaNetwork_1_3(); + ASSERT_NE(sta_network_.get(), nullptr); + } + + virtual void TearDown() override { stopSupplicant(); } + + protected: + // ISupplicantStaNetwork object used for all tests in this fixture. + sp sta_network_; +}; + +/* + * SetGetOcsp + */ +TEST_F(SupplicantStaNetworkHidlTest, SetGetOcsp) { + OcspType testOcspType = kTestOcspType; + + sta_network_->setOcsp(testOcspType, [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + sta_network_->setOcsp( + kTestInvalidOcspType, [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::FAILURE_ARGS_INVALID, status.code); + }); + + sta_network_->getOcsp( + [testOcspType](const SupplicantStatus &status, OcspType ocspType) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + EXPECT_EQ(testOcspType, ocspType); + }); +} From 3f48f4e9847332f2d268b38c32cadf4579426419 Mon Sep 17 00:00:00 2001 From: Hayden Gomes Date: Tue, 30 Jul 2019 10:53:40 -0700 Subject: [PATCH 0053/1022] Deprecate IAudioControl.getBusForContext Usage of this API has been replaced by car_audio_configuration.xml. Bug: 135625954 Test: Built and ran on device Change-Id: I09440446cbfeb2e5c321899767bee7bfdd29e129 --- automotive/audiocontrol/1.0/IAudioControl.hal | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/automotive/audiocontrol/1.0/IAudioControl.hal b/automotive/audiocontrol/1.0/IAudioControl.hal index 3c8b086bc6..2e7ef75380 100644 --- a/automotive/audiocontrol/1.0/IAudioControl.hal +++ b/automotive/audiocontrol/1.0/IAudioControl.hal @@ -29,6 +29,11 @@ interface IAudioControl { * * For every context, a valid bus number (0 - num busses-1) must be returned. If an * unrecognized contextNumber is encountered, then -1 shall be returned. + * + * Deprecated: usage of this API and car_volume_groups.xml has been replaced with + * car_audio_configuration.xml. If using car_audio_configuration.xml, then the framework + * will not call this method. If it doesn't, then it will load car_volume_groups.xml and + * call this method. */ getBusForContext(ContextNumber contextNumber) generates (int32_t busNumber); From 45a70ce00ebed824ce90133073aefef78a09ebba Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 5 Aug 2019 16:55:12 -0700 Subject: [PATCH 0054/1022] [VTS] Update RenderEngine dependencies. Upstream change adds a new RenderEngine dependency, adding the dependency here to fix compilation issue. Bug: 136806342 Bug: 137191934 Test: builds Change-Id: I8c097dd162afb79d36269741af00d0e69cf77c2a --- graphics/composer/2.2/vts/functional/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp index cc24774fff..13190350ec 100644 --- a/graphics/composer/2.2/vts/functional/Android.bp +++ b/graphics/composer/2.2/vts/functional/Android.bp @@ -29,6 +29,7 @@ cc_test { "libhidlbase", "libhidltransport", "libhwbinder", + "libprocessgroup", "libsync", "libui", "libgui", From 873296702f68d314593cdf8d49c1a3838c7bef48 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 12 Jul 2019 11:43:00 -0700 Subject: [PATCH 0055/1022] Default implementation for CAN bus HAL This implementation supports SocketCAN interfaces. Bug: 135918744 Test: VTS (separate new change) Change-Id: I12b93e37fa64e341bee2c64eaf130b39977fcef5 --- automotive/can/1.0/default/Android.bp | 55 ++++ automotive/can/1.0/default/CanBus.cpp | 249 ++++++++++++++++++ automotive/can/1.0/default/CanBus.h | 97 +++++++ automotive/can/1.0/default/CanBusNative.cpp | 57 ++++ automotive/can/1.0/default/CanBusNative.h | 43 +++ automotive/can/1.0/default/CanBusVirtual.cpp | 60 +++++ automotive/can/1.0/default/CanBusVirtual.h | 44 ++++ automotive/can/1.0/default/CanController.cpp | 133 ++++++++++ automotive/can/1.0/default/CanController.h | 47 ++++ automotive/can/1.0/default/CanSocket.cpp | 150 +++++++++++ automotive/can/1.0/default/CanSocket.h | 80 ++++++ automotive/can/1.0/default/CloseHandle.cpp | 45 ++++ automotive/can/1.0/default/CloseHandle.h | 59 +++++ ...oid.hardware.automotive.can@1.0-service.rc | 5 + .../can/1.0/default/libnetdevice/Android.bp | 30 +++ .../default/libnetdevice/NetlinkRequest.cpp | 58 ++++ .../1.0/default/libnetdevice/NetlinkRequest.h | 159 +++++++++++ .../default/libnetdevice/NetlinkSocket.cpp | 114 ++++++++ .../1.0/default/libnetdevice/NetlinkSocket.h | 68 +++++ .../can/1.0/default/libnetdevice/can.cpp | 91 +++++++ .../can/1.0/default/libnetdevice/common.cpp | 38 +++ .../can/1.0/default/libnetdevice/common.h | 36 +++ .../libnetdevice/include/libnetdevice/can.h | 42 +++ .../include/libnetdevice/libnetdevice.h | 75 ++++++ .../1.0/default/libnetdevice/libnetdevice.cpp | 100 +++++++ automotive/can/1.0/default/service.cpp | 55 ++++ 26 files changed, 1990 insertions(+) create mode 100644 automotive/can/1.0/default/Android.bp create mode 100644 automotive/can/1.0/default/CanBus.cpp create mode 100644 automotive/can/1.0/default/CanBus.h create mode 100644 automotive/can/1.0/default/CanBusNative.cpp create mode 100644 automotive/can/1.0/default/CanBusNative.h create mode 100644 automotive/can/1.0/default/CanBusVirtual.cpp create mode 100644 automotive/can/1.0/default/CanBusVirtual.h create mode 100644 automotive/can/1.0/default/CanController.cpp create mode 100644 automotive/can/1.0/default/CanController.h create mode 100644 automotive/can/1.0/default/CanSocket.cpp create mode 100644 automotive/can/1.0/default/CanSocket.h create mode 100644 automotive/can/1.0/default/CloseHandle.cpp create mode 100644 automotive/can/1.0/default/CloseHandle.h create mode 100644 automotive/can/1.0/default/android.hardware.automotive.can@1.0-service.rc create mode 100644 automotive/can/1.0/default/libnetdevice/Android.bp create mode 100644 automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp create mode 100644 automotive/can/1.0/default/libnetdevice/NetlinkRequest.h create mode 100644 automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp create mode 100644 automotive/can/1.0/default/libnetdevice/NetlinkSocket.h create mode 100644 automotive/can/1.0/default/libnetdevice/can.cpp create mode 100644 automotive/can/1.0/default/libnetdevice/common.cpp create mode 100644 automotive/can/1.0/default/libnetdevice/common.h create mode 100644 automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h create mode 100644 automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h create mode 100644 automotive/can/1.0/default/libnetdevice/libnetdevice.cpp create mode 100644 automotive/can/1.0/default/service.cpp diff --git a/automotive/can/1.0/default/Android.bp b/automotive/can/1.0/default/Android.bp new file mode 100644 index 0000000000..0a4afd6e37 --- /dev/null +++ b/automotive/can/1.0/default/Android.bp @@ -0,0 +1,55 @@ +// +// 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. +// + +cc_defaults { + name: "android.hardware.automotive.can@defaults", + cpp_std: "experimental", + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION=1", + ], + shared_libs: [ + "libbase", + "libutils", + ], +} + +cc_binary { + name: "android.hardware.automotive.can@1.0-service", + init_rc: ["android.hardware.automotive.can@1.0-service.rc"], + defaults: ["android.hardware.automotive.can@defaults"], + vendor: true, + relative_install_path: "hw", + srcs: [ + "CanBus.cpp", + "CanBusNative.cpp", + "CanBusVirtual.cpp", + "CanController.cpp", + "CanSocket.cpp", + "CloseHandle.cpp", + "service.cpp", + ], + shared_libs: [ + "android.hardware.automotive.can@1.0", + "libhidlbase", + "libhidltransport", + ], + static_libs: [ + "android.hardware.automotive.can@libnetdevice", + ], +} diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp new file mode 100644 index 0000000000..65da291b0b --- /dev/null +++ b/automotive/can/1.0/default/CanBus.cpp @@ -0,0 +1,249 @@ +/* + * 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. + */ + +#include "CanBus.h" + +#include "CloseHandle.h" + +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace implementation { + +/** + * Whether to log sent/received packets. + */ +static constexpr bool kSuperVerbose = false; + +Return CanBus::send(const CanMessage& message) { + std::lock_guard lck(mIsUpGuard); + if (!mIsUp) return Result::INTERFACE_DOWN; + + if (UNLIKELY(kSuperVerbose)) { + LOG(VERBOSE) << "Sending " << toString(message); + } + + if (message.payload.size() > CAN_MAX_DLEN) return Result::PAYLOAD_TOO_LONG; + + struct canfd_frame frame = {}; + frame.can_id = message.id; + frame.len = message.payload.size(); + memcpy(frame.data, message.payload.data(), message.payload.size()); + + if (!mSocket->send(frame)) return Result::TRANSMISSION_FAILURE; + + return Result::OK; +} + +Return CanBus::listen(const hidl_vec& filter, + const sp& listenerCb, listen_cb _hidl_cb) { + std::lock_guard lck(mIsUpGuard); + + if (listenerCb == nullptr) { + _hidl_cb(Result::INVALID_ARGUMENTS, nullptr); + return {}; + } + if (!mIsUp) { + _hidl_cb(Result::INTERFACE_DOWN, nullptr); + return {}; + } + + std::lock_guard lckListeners(mListenersGuard); + + sp closeHandle = new CloseHandle([this, listenerCb]() { + std::lock_guard lck(mListenersGuard); + std::erase_if(mListeners, [&](const auto& e) { return e.callback == listenerCb; }); + }); + mListeners.emplace_back(CanMessageListener{listenerCb, filter, closeHandle}); + auto& listener = mListeners.back(); + + // fix message IDs to have all zeros on bits not covered by mask + std::for_each(listener.filter.begin(), listener.filter.end(), + [](auto& rule) { rule.id &= rule.mask; }); + + _hidl_cb(Result::OK, closeHandle); + return {}; +} + +CanBus::CanBus(const std::string& ifname) : mIfname(ifname) {} + +CanBus::~CanBus() { + std::lock_guard lck(mIsUpGuard); + CHECK(!mIsUp) << "Interface is still up while being destroyed"; + + std::lock_guard lckListeners(mListenersGuard); + CHECK(mListeners.empty()) << "Listeners list is not empty while interface is being destroyed"; +} + +ICanController::Result CanBus::preUp() { + return ICanController::Result::OK; +} + +bool CanBus::postDown() { + return true; +} + +ICanController::Result CanBus::up() { + std::lock_guard lck(mIsUpGuard); + + if (mIsUp) { + LOG(WARNING) << "Interface is already up"; + return ICanController::Result::INVALID_STATE; + } + + const auto preResult = preUp(); + if (preResult != ICanController::Result::OK) return preResult; + + const auto isUp = netdevice::isUp(mIfname); + if (!isUp.has_value()) { + // preUp() should prepare the interface (either create or make sure it's there) + LOG(ERROR) << "Interface " << mIfname << " didn't get prepared"; + return ICanController::Result::BAD_ADDRESS; + } + mWasUpInitially = *isUp; + + if (!mWasUpInitially && !netdevice::up(mIfname)) { + LOG(ERROR) << "Can't bring " << mIfname << " up"; + return ICanController::Result::UNKNOWN_ERROR; + } + + using namespace std::placeholders; + CanSocket::ReadCallback rdcb = std::bind(&CanBus::onRead, this, _1, _2); + CanSocket::ErrorCallback errcb = std::bind(&CanBus::onError, this); + mSocket = CanSocket::open(mIfname, rdcb, errcb); + if (!mSocket) { + if (!mWasUpInitially) netdevice::down(mIfname); + return ICanController::Result::UNKNOWN_ERROR; + } + + mIsUp = true; + return ICanController::Result::OK; +} + +void CanBus::clearListeners() { + std::vector> listenersToClose; + { + std::lock_guard lck(mListenersGuard); + std::transform(mListeners.begin(), mListeners.end(), std::back_inserter(listenersToClose), + [](const auto& e) { return e.closeHandle; }); + } + + for (auto& weakListener : listenersToClose) { + /* Between populating listenersToClose and calling close method here, some listeners might + * have been already removed from the original mListeners list (resulting in a dangling weak + * pointer here). It's fine - we just want to clean them up. */ + auto listener = weakListener.promote(); + if (listener != nullptr) listener->close(); + } + + std::lock_guard lck(mListenersGuard); + CHECK(mListeners.empty()) << "Listeners list wasn't emptied"; +} + +bool CanBus::down() { + std::lock_guard lck(mIsUpGuard); + + if (!mIsUp) { + LOG(WARNING) << "Interface is already down"; + return false; + } + mIsUp = false; + + clearListeners(); + mSocket.reset(); + + bool success = true; + + if (!mWasUpInitially && !netdevice::down(mIfname)) { + LOG(ERROR) << "Can't bring " << mIfname << " down"; + // don't return yet, let's try to do best-effort cleanup + success = false; + } + + if (!postDown()) success = false; + + return success; +} + +/** + * Match the filter set against message id. + * + * For details on the filters syntax, please see CanMessageFilter at + * the HAL definition (types.hal). + * + * \param filter Filter to match against + * \param id Message id to filter + * \return true if the message id matches the filter, false otherwise + */ +static bool match(const hidl_vec& filter, CanMessageId id) { + if (filter.size() == 0) return true; + + bool anyNonInvertedPresent = false; + bool anyNonInvertedSatisfied = false; + for (auto& rule : filter) { + const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted; + if (rule.inverted) { + // Any inverted (blacklist) rule not being satisfied invalidates the whole filter set. + if (!satisfied) return false; + } else { + anyNonInvertedPresent = true; + if (satisfied) anyNonInvertedSatisfied = true; + } + } + return !anyNonInvertedPresent || anyNonInvertedSatisfied; +} + +void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp) { + CanMessage message = {}; + message.id = frame.can_id; + message.payload = hidl_vec(frame.data, frame.data + frame.len); + message.timestamp = timestamp.count(); + + if (UNLIKELY(kSuperVerbose)) { + LOG(VERBOSE) << "Got message " << toString(message); + } + + std::lock_guard lck(mListenersGuard); + for (auto& listener : mListeners) { + if (!match(listener.filter, message.id)) continue; + if (!listener.callback->onReceive(message).isOk()) { + LOG(WARNING) << "Failed to notify listener about message"; + } + } +} + +void CanBus::onError() { + std::lock_guard lck(mListenersGuard); + for (auto& listener : mListeners) { + if (!listener.callback->onError(ErrorEvent::HARDWARE_ERROR).isOk()) { + LOG(WARNING) << "Failed to notify listener about error"; + } + } +} + +} // namespace implementation +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/can/1.0/default/CanBus.h b/automotive/can/1.0/default/CanBus.h new file mode 100644 index 0000000000..81a83c82b8 --- /dev/null +++ b/automotive/can/1.0/default/CanBus.h @@ -0,0 +1,97 @@ +/* + * 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. + */ + +#pragma once + +#include "CanSocket.h" + +#include +#include +#include +#include + +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace implementation { + +struct CanBus : public ICanBus { + virtual ~CanBus(); + + Return send(const CanMessage& message) override; + Return listen(const hidl_vec& filter, + const sp& listener, listen_cb _hidl_cb) override; + + ICanController::Result up(); + bool down(); + + protected: + CanBus(const std::string& ifname); + + /** + * Prepare the SocketCAN interface. + * + * After calling this method, mIfname network interface is available and ready to be brought up. + */ + virtual ICanController::Result preUp(); + + /** + * Cleanup after bringing the interface down. + * + * This is a counterpart to preUp(). + */ + virtual bool postDown(); + + /** Network interface name. */ + const std::string mIfname; + + private: + struct CanMessageListener { + sp callback; + hidl_vec filter; + wp closeHandle; + }; + void clearListeners(); + + void onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp); + void onError(); + + std::mutex mListenersGuard; + std::vector mListeners GUARDED_BY(mListenersGuard); + + std::unique_ptr mSocket; + bool mWasUpInitially; + + /** + * Guard for up flag is required to be held for entire time when the interface is being used + * (i.e. message being sent), because we don't want the interface to be torn down while + * executing that operation. + */ + std::mutex mIsUpGuard; + bool mIsUp GUARDED_BY(mIsUpGuard) = false; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/can/1.0/default/CanBusNative.cpp b/automotive/can/1.0/default/CanBusNative.cpp new file mode 100644 index 0000000000..365b749cd7 --- /dev/null +++ b/automotive/can/1.0/default/CanBusNative.cpp @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#include "CanBusNative.h" + +#include +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace implementation { + +CanBusNative::CanBusNative(const std::string& ifname, uint32_t baudrate) + : CanBus(ifname), mBaudrate(baudrate) {} + +ICanController::Result CanBusNative::preUp() { + if (!netdevice::exists(mIfname)) { + LOG(ERROR) << "Interface " << mIfname << " doesn't exist"; + return ICanController::Result::BAD_ADDRESS; + } + + if (!netdevice::down(mIfname)) { + LOG(ERROR) << "Can't bring " << mIfname << " down (to configure it)"; + return ICanController::Result::UNKNOWN_ERROR; + } + + if (!netdevice::can::setBitrate(mIfname, mBaudrate)) { + LOG(ERROR) << "Can't set bitrate " << mBaudrate << " for " << mIfname; + return ICanController::Result::BAD_BAUDRATE; + } + + return ICanController::Result::OK; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/can/1.0/default/CanBusNative.h b/automotive/can/1.0/default/CanBusNative.h new file mode 100644 index 0000000000..126f1cb77c --- /dev/null +++ b/automotive/can/1.0/default/CanBusNative.h @@ -0,0 +1,43 @@ +/* + * 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. + */ + +#pragma once + +#include "CanBus.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace implementation { + +struct CanBusNative : public CanBus { + CanBusNative(const std::string& ifname, uint32_t baudrate); + + protected: + virtual ICanController::Result preUp() override; + + private: + const uint32_t mBaudrate; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/can/1.0/default/CanBusVirtual.cpp b/automotive/can/1.0/default/CanBusVirtual.cpp new file mode 100644 index 0000000000..cc59fa97b8 --- /dev/null +++ b/automotive/can/1.0/default/CanBusVirtual.cpp @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#include "CanBusVirtual.h" + +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace implementation { + +CanBusVirtual::CanBusVirtual(const std::string& ifname) : CanBus(ifname) {} + +ICanController::Result CanBusVirtual::preUp() { + if (netdevice::exists(mIfname)) return ICanController::Result::OK; + + LOG(DEBUG) << "Virtual interface " << mIfname << " doesn't exist, creating..."; + mWasCreated = true; + if (!netdevice::add(mIfname, "vcan")) { + LOG(ERROR) << "Can't create vcan interface " << mIfname; + return ICanController::Result::UNKNOWN_ERROR; + } + + return ICanController::Result::OK; +} + +bool CanBusVirtual::postDown() { + if (mWasCreated) { + mWasCreated = false; + if (!netdevice::del(mIfname)) { + LOG(ERROR) << "Couldn't remove vcan interface " << mIfname; + return false; + } + } + return true; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/can/1.0/default/CanBusVirtual.h b/automotive/can/1.0/default/CanBusVirtual.h new file mode 100644 index 0000000000..c2d5794502 --- /dev/null +++ b/automotive/can/1.0/default/CanBusVirtual.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#pragma once + +#include "CanBus.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace implementation { + +struct CanBusVirtual : public CanBus { + CanBusVirtual(const std::string& ifname); + + protected: + virtual ICanController::Result preUp() override; + virtual bool postDown() override; + + private: + bool mWasCreated = false; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp new file mode 100644 index 0000000000..20adbe120e --- /dev/null +++ b/automotive/can/1.0/default/CanController.cpp @@ -0,0 +1,133 @@ +/* + * 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. + */ + +#include "CanController.h" + +#include "CanBusNative.h" +#include "CanBusVirtual.h" + +#include +#include + +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace implementation { + +using IfaceIdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator; + +Return CanController::getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) { + _hidl_cb({ + ICanController::InterfaceType::VIRTUAL, + ICanController::InterfaceType::SOCKETCAN, + }); + return {}; +} + +static bool isValidName(const std::string& name) { + static const std::regex nameRE("^[a-zA-Z0-9_]{1,32}$"); + return std::regex_match(name, nameRE); +} + +Return CanController::upInterface( + const ICanController::BusConfiguration& config) { + LOG(VERBOSE) << "Attempting to bring interface up: " << toString(config); + + std::lock_guard lck(mCanBusesGuard); + + if (!isValidName(config.name)) { + LOG(ERROR) << "Bus name " << config.name << " is invalid"; + return ICanController::Result::UNKNOWN_ERROR; + } + + if (mCanBuses.find(config.name) != mCanBuses.end()) { + LOG(ERROR) << "Bus " << config.name << " is already up"; + return ICanController::Result::INVALID_STATE; + } + + sp busService; + + if (config.iftype == ICanController::InterfaceType::SOCKETCAN) { + // TODO(b/135918744): support serialno + if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) { + busService = new CanBusNative(config.interfaceId.address(), config.baudrate); + } else { + return ICanController::Result::BAD_ADDRESS; + } + } else if (config.iftype == ICanController::InterfaceType::VIRTUAL) { + if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) { + busService = new CanBusVirtual(config.interfaceId.address()); + } else { + return ICanController::Result::BAD_ADDRESS; + } + } else { + return ICanController::Result::NOT_SUPPORTED; + } + + const auto result = busService->up(); + if (result != ICanController::Result::OK) return result; + + if (busService->registerAsService(config.name) != OK) { + LOG(ERROR) << "Failed to register ICanBus/" << config.name; + if (!busService->down()) { + LOG(WARNING) << "Failed to bring down CAN bus that failed to register"; + } + return ICanController::Result::UNKNOWN_ERROR; + } + + mCanBuses[config.name] = busService; + + return ICanController::Result::OK; +} + +Return CanController::downInterface(const hidl_string& name) { + LOG(VERBOSE) << "Attempting to bring interface down: " << name; + + std::lock_guard lck(mCanBusesGuard); + + auto busEntry = mCanBuses.extract(name); + if (!busEntry) { + LOG(WARNING) << "Interface " << name << " is not up"; + return false; + } + + auto success = true; + + auto manager = hidl::manager::V1_2::IServiceManager::getService(); + if (!manager || !manager->tryUnregister(ICanBus::descriptor, name, busEntry.mapped())) { + LOG(ERROR) << "Couldn't unregister " << name; + // don't return yet, let's try to do best-effort cleanup + success = false; + } + + if (!busEntry.mapped()->down()) { + LOG(ERROR) << "Couldn't bring " << name << " down"; + success = false; + } + + return success; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/can/1.0/default/CanController.h b/automotive/can/1.0/default/CanController.h new file mode 100644 index 0000000000..0674d0edf7 --- /dev/null +++ b/automotive/can/1.0/default/CanController.h @@ -0,0 +1,47 @@ +/* + * 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. + */ + +#pragma once + +#include "CanBus.h" + +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace implementation { + +struct CanController : public ICanController { + Return getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) override; + + Return upInterface( + const ICanController::BusConfiguration& config) override; + Return downInterface(const hidl_string& name) override; + + private: + std::mutex mCanBusesGuard; + std::map> mCanBuses GUARDED_BY(mCanBusesGuard); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/can/1.0/default/CanSocket.cpp b/automotive/can/1.0/default/CanSocket.cpp new file mode 100644 index 0000000000..4d86de6a28 --- /dev/null +++ b/automotive/can/1.0/default/CanSocket.cpp @@ -0,0 +1,150 @@ +/* + * 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. + */ + +#include "CanSocket.h" + +#include +#include +#include +#include +#include + +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace implementation { + +using namespace std::chrono_literals; + +/** + * How frequently the read thread checks whether the interface was asked to be down. + * + * Note: This does *not* affect read timing or bandwidth, just CPU load vs time to + * down the interface. + */ +static constexpr auto kReadPooling = 100ms; + +std::unique_ptr CanSocket::open(const std::string& ifname, ReadCallback rdcb, + ErrorCallback errcb) { + auto sock = netdevice::can::socket(ifname); + if (!sock.ok()) { + LOG(ERROR) << "Can't open CAN socket on " << ifname; + return nullptr; + } + + // Can't use std::make_unique due to private CanSocket constructor. + return std::unique_ptr(new CanSocket(std::move(sock), rdcb, errcb)); +} + +CanSocket::CanSocket(base::unique_fd socket, ReadCallback rdcb, ErrorCallback errcb) + : mReadCallback(rdcb), + mErrorCallback(errcb), + mSocket(std::move(socket)), + mReaderThread(&CanSocket::readerThread, this) {} + +CanSocket::~CanSocket() { + mStopReaderThread = true; + mReaderThread.join(); +} + +bool CanSocket::send(const struct canfd_frame& frame) { + const auto res = write(mSocket.get(), &frame, CAN_MTU); + if (res < 0) { + LOG(DEBUG) << "CanSocket send failed: " << errno; + return false; + } + if (res != CAN_MTU) { + LOG(DEBUG) << "CanSocket sent wrong number of bytes: " << res; + return false; + } + return true; +} + +static struct timeval toTimeval(std::chrono::microseconds t) { + struct timeval tv; + tv.tv_sec = t / 1s; + tv.tv_usec = (t % 1s) / 1us; + return tv; +} + +static int selectRead(const base::unique_fd& fd, std::chrono::microseconds timeout) { + auto timeouttv = toTimeval(timeout); + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(fd.get(), &readfds); + return select(fd.get() + 1, &readfds, nullptr, nullptr, &timeouttv); +} + +void CanSocket::readerThread() { + LOG(VERBOSE) << "Reader thread started"; + + while (!mStopReaderThread) { + /* The ideal would be to have a blocking read(3) call and interrupt it with shutdown(3). + * This is unfortunately not supported for SocketCAN, so we need to rely on select(3). + */ + const auto sel = selectRead(mSocket, kReadPooling); + if (sel == 0) continue; // timeout + if (sel == -1) { + LOG(ERROR) << "Select failed: " << errno; + break; + } + + struct canfd_frame frame; + const auto nbytes = read(mSocket.get(), &frame, CAN_MTU); + + /* We could use SIOCGSTAMP to get a precise UNIX timestamp for a given packet, but what + * we really need is a time since boot. There is no direct way to convert between these + * clocks. We could implement a class to calculate the difference between the clocks + * (querying both several times and picking the smallest difference); apply the difference + * to a SIOCGSTAMP returned value; re-synchronize if the elapsed time is too much in the + * past (indicating the UNIX timestamp might have been adjusted). + * + * Apart from the added complexity, it's possible the added calculations and system calls + * would add so much time to the processing pipeline so the precision of the reported time + * was buried under the subsystem latency. Let's just use a local time since boot here and + * leave precise hardware timestamps for custom proprietary implementations (if needed). + */ + const std::chrono::nanoseconds ts(elapsedRealtimeNano()); + + if (nbytes != CAN_MTU) { + if (nbytes >= 0) { + LOG(ERROR) << "Failed to read CAN packet, got " << nbytes << " bytes"; + break; + } + if (errno == EAGAIN) continue; + + LOG(ERROR) << "Failed to read CAN packet: " << errno; + break; + } + + mReadCallback(frame, ts); + } + + if (!mStopReaderThread) mErrorCallback(); + + LOG(VERBOSE) << "Reader thread stopped"; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/can/1.0/default/CanSocket.h b/automotive/can/1.0/default/CanSocket.h new file mode 100644 index 0000000000..cd7162db75 --- /dev/null +++ b/automotive/can/1.0/default/CanSocket.h @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace implementation { + +/** + * Wrapper around SocketCAN socket. + */ +struct CanSocket { + using ReadCallback = std::function; + using ErrorCallback = std::function; + + /** + * Open and bind SocketCAN socket. + * + * \param ifname SocketCAN network interface name (such as can0) + * \param rdcb Callback on received messages + * \param errcb Callback on socket failure + * \return Socket instance, or nullptr if it wasn't possible to open one + */ + static std::unique_ptr open(const std::string& ifname, ReadCallback rdcb, + ErrorCallback errcb); + virtual ~CanSocket(); + + /** + * Send CAN frame. + * + * \param frame Frame to send + * \return true in case of success, false otherwise + */ + bool send(const struct canfd_frame& frame); + + private: + CanSocket(base::unique_fd socket, ReadCallback rdcb, ErrorCallback errcb); + void readerThread(); + + ReadCallback mReadCallback; + ErrorCallback mErrorCallback; + + const base::unique_fd mSocket; + std::thread mReaderThread; + std::atomic mStopReaderThread = false; + + DISALLOW_COPY_AND_ASSIGN(CanSocket); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/can/1.0/default/CloseHandle.cpp b/automotive/can/1.0/default/CloseHandle.cpp new file mode 100644 index 0000000000..13693d29e6 --- /dev/null +++ b/automotive/can/1.0/default/CloseHandle.cpp @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#include "CloseHandle.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace implementation { + +CloseHandle::CloseHandle(Callback callback) : mCallback(callback) {} + +CloseHandle::~CloseHandle() { + close(); +} + +Return CloseHandle::close() { + const auto wasClosed = mIsClosed.exchange(true); + if (wasClosed) return {}; + + mCallback(); + return {}; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/can/1.0/default/CloseHandle.h b/automotive/can/1.0/default/CloseHandle.h new file mode 100644 index 0000000000..94972e03b5 --- /dev/null +++ b/automotive/can/1.0/default/CloseHandle.h @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace implementation { + +/** + * Generic ICloseHandle implementation ignoring double-close events. + */ +struct CloseHandle : public ICloseHandle { + using Callback = std::function; + + /** + * Create a handle with a callback. + * + * The callback is guaranteed to be called exactly once. + * + * \param callback Called on the first close() call, or on destruction of the handle + */ + CloseHandle(Callback callback); + virtual ~CloseHandle(); + + Return close() override; + + private: + Callback mCallback; + std::atomic mIsClosed = false; + + DISALLOW_COPY_AND_ASSIGN(CloseHandle); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/can/1.0/default/android.hardware.automotive.can@1.0-service.rc b/automotive/can/1.0/default/android.hardware.automotive.can@1.0-service.rc new file mode 100644 index 0000000000..a629bdae00 --- /dev/null +++ b/automotive/can/1.0/default/android.hardware.automotive.can@1.0-service.rc @@ -0,0 +1,5 @@ +service can-hal-1.0-service /vendor/bin/hw/android.hardware.automotive.can@1.0-service + class hal + capabilities NET_ADMIN + user vehicle_network + group system inet diff --git a/automotive/can/1.0/default/libnetdevice/Android.bp b/automotive/can/1.0/default/libnetdevice/Android.bp new file mode 100644 index 0000000000..31e5ad0376 --- /dev/null +++ b/automotive/can/1.0/default/libnetdevice/Android.bp @@ -0,0 +1,30 @@ +// +// 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. +// + +cc_library_static { + name: "android.hardware.automotive.can@libnetdevice", + defaults: ["android.hardware.automotive.can@defaults"], + vendor_available: true, + relative_install_path: "hw", + srcs: [ + "NetlinkRequest.cpp", + "NetlinkSocket.cpp", + "can.cpp", + "common.cpp", + "libnetdevice.cpp", + ], + export_include_dirs: ["include"], +} diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp new file mode 100644 index 0000000000..9845bc7dd6 --- /dev/null +++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#include "NetlinkRequest.h" + +#include + +namespace android { +namespace netdevice { +namespace impl { + +static struct rtattr* nlmsg_tail(struct nlmsghdr* n) { + return reinterpret_cast( // + reinterpret_cast(n) + NLMSG_ALIGN(n->nlmsg_len)); +} + +struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data, + size_t dataLen) { + size_t newLen = NLMSG_ALIGN(n->nlmsg_len) + RTA_SPACE(dataLen); + if (newLen > maxLen) { + LOG(ERROR) << "addattr_l failed - exceeded maxLen: " << newLen << " > " << maxLen; + return nullptr; + } + + auto attr = nlmsg_tail(n); + attr->rta_len = RTA_SPACE(dataLen); + attr->rta_type = type; + if (dataLen > 0) memcpy(RTA_DATA(attr), data, dataLen); + + n->nlmsg_len = newLen; + return attr; +} + +struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type) { + return addattr_l(n, maxLen, type, nullptr, 0); +} + +void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest) { + size_t nestLen = reinterpret_cast(nlmsg_tail(n)) - reinterpret_cast(nest); + nest->rta_len = nestLen; +} + +} // namespace impl +} // namespace netdevice +} // namespace android diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h new file mode 100644 index 0000000000..21202e39bc --- /dev/null +++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h @@ -0,0 +1,159 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include + +namespace android { +namespace netdevice { + +typedef unsigned short rtattrtype_t; // as in rtnetlink.h +typedef __u16 nlmsgtype_t; // as in netlink.h + +/** + * Implementation details, do not use outside NetlinkRequest template. + */ +namespace impl { + +struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data, + size_t dataLen); +struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type); +void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest); + +} // namespace impl + +/** + * Wrapper around NETLINK_ROUTE messages, to build them in C++ style. + * + * \param T specific message header (such as struct ifinfomsg) + * \param BUFSIZE how much space to reserve for payload (not counting the header size) + */ +template +struct NetlinkRequest { + /** + * Create empty message. + * + * \param type Message type (such as RTM_NEWLINK) + * \param flags Message flags (such as NLM_F_REQUEST) + */ + NetlinkRequest(nlmsgtype_t type, uint16_t flags) { + mRequest.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(mRequest.data)); + mRequest.nlmsg.nlmsg_type = type; + mRequest.nlmsg.nlmsg_flags = flags; + } + + /** Returns pointer to raw netlink message header. */ + struct nlmsghdr* header() { + return &mRequest.nlmsg; + } + /** Reference to message-specific header. */ + T& data() { return mRequest.data; } + + /** + * Adds an attribute of a simple type. + * + * If this method fails (i.e. due to insufficient space), the message will be marked + * as bad (\see isGood). + * + * \param type attribute type (such as IFLA_IFNAME) + * \param attr attribute data + */ + template + void addattr(rtattrtype_t type, const A& attr) { + if (!mIsGood) return; + auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, &attr, sizeof(attr)); + if (ap == nullptr) mIsGood = false; + } + + template <> + void addattr(rtattrtype_t type, const std::string& s) { + if (!mIsGood) return; + auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, s.c_str(), s.size() + 1); + if (ap == nullptr) mIsGood = false; + } + + /** + * Guard class to frame nested attributes. See nest(int). + */ + struct Nest { + Nest(NetlinkRequest& req, rtattrtype_t type) : mReq(req), mAttr(req.nestStart(type)) {} + ~Nest() { mReq.nestEnd(mAttr); } + + private: + NetlinkRequest& mReq; + struct rtattr* mAttr; + + DISALLOW_COPY_AND_ASSIGN(Nest); + }; + + /** + * Add nested attribute. + * + * The returned object is a guard for auto-nesting children inside the argument attribute. + * When the Nest object goes out of scope, the nesting attribute is closed. + * + * Example usage nesting IFLA_CAN_BITTIMING inside IFLA_INFO_DATA, which is nested + * inside IFLA_LINKINFO: + * NetlinkRequest req(RTM_NEWLINK, NLM_F_REQUEST); + * { + * auto linkinfo = req.nest(IFLA_LINKINFO); + * req.addattr(IFLA_INFO_KIND, "can"); + * { + * auto infodata = req.nest(IFLA_INFO_DATA); + * req.addattr(IFLA_CAN_BITTIMING, bitTimingStruct); + * } + * } + * // use req + * + * \param type attribute type (such as IFLA_LINKINFO) + */ + Nest nest(int type) { return Nest(*this, type); } + + /** + * Indicates, whether the message is in a good state. + * + * The bad state is usually a result of payload buffer being too small. + * You can modify BUFSIZE template parameter to fix this. + */ + bool isGood() const { return mIsGood; } + + private: + bool mIsGood = true; + + struct { + struct nlmsghdr nlmsg; + T data; + char buf[BUFSIZE]; + } mRequest = {}; + + struct rtattr* nestStart(rtattrtype_t type) { + if (!mIsGood) return nullptr; + auto attr = impl::addattr_nest(&mRequest.nlmsg, sizeof(mRequest), type); + if (attr == nullptr) mIsGood = false; + return attr; + } + + void nestEnd(struct rtattr* nest) { + if (mIsGood && nest != nullptr) impl::addattr_nest_end(&mRequest.nlmsg, nest); + } +}; + +} // namespace netdevice +} // namespace android diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp new file mode 100644 index 0000000000..05147647e6 --- /dev/null +++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp @@ -0,0 +1,114 @@ +/* + * 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. + */ + +#include "NetlinkSocket.h" + +#include + +namespace android { +namespace netdevice { + +NetlinkSocket::NetlinkSocket(int protocol) { + mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol)); + if (!mFd.ok()) { + LOG(ERROR) << "Can't open Netlink socket: " << errno; + mFailed = true; + return; + } + + struct sockaddr_nl sa = {}; + sa.nl_family = AF_NETLINK; + + if (bind(mFd.get(), reinterpret_cast(&sa), sizeof(sa)) < 0) { + LOG(ERROR) << "Can't bind Netlink socket: " << errno; + mFd.reset(); + mFailed = true; + } +} + +bool NetlinkSocket::send(struct nlmsghdr* nlmsg) { + if (mFailed) return false; + + nlmsg->nlmsg_pid = 0; // kernel + nlmsg->nlmsg_seq = mSeq++; + nlmsg->nlmsg_flags |= NLM_F_ACK; + + struct iovec iov = {nlmsg, nlmsg->nlmsg_len}; + + struct sockaddr_nl sa = {}; + sa.nl_family = AF_NETLINK; + + struct msghdr msg = {}; + msg.msg_name = &sa; + msg.msg_namelen = sizeof(sa); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + if (sendmsg(mFd.get(), &msg, 0) < 0) { + LOG(ERROR) << "Can't send Netlink message: " << errno; + return false; + } + return true; +} + +bool NetlinkSocket::receiveAck() { + if (mFailed) return false; + + char buf[8192]; + + struct sockaddr_nl sa; + struct iovec iov = {buf, sizeof(buf)}; + + struct msghdr msg = {}; + msg.msg_name = &sa; + msg.msg_namelen = sizeof(sa); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + const ssize_t status = recvmsg(mFd.get(), &msg, 0); + if (status < 0) { + LOG(ERROR) << "Failed to receive Netlink message: " << errno; + return false; + } + size_t remainingLen = status; + + if (msg.msg_flags & MSG_TRUNC) { + LOG(ERROR) << "Failed to receive Netlink message: truncated"; + return false; + } + + for (auto nlmsg = reinterpret_cast(buf); NLMSG_OK(nlmsg, remainingLen); + nlmsg = NLMSG_NEXT(nlmsg, remainingLen)) { + // We're looking for error/ack message only, ignoring others. + if (nlmsg->nlmsg_type != NLMSG_ERROR) { + LOG(WARNING) << "Received unexpected Netlink message (ignored): " << nlmsg->nlmsg_type; + continue; + } + + // Found error/ack message, return status. + auto nlerr = reinterpret_cast(NLMSG_DATA(nlmsg)); + if (nlerr->error != 0) { + LOG(ERROR) << "Received Netlink error message: " << nlerr->error; + return false; + } + return true; + } + // Couldn't find any error/ack messages. + return false; +} + +} // namespace netdevice +} // namespace android diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h new file mode 100644 index 0000000000..81d6224e7f --- /dev/null +++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#pragma once + +#include "NetlinkRequest.h" + +#include +#include + +#include + +namespace android { +namespace netdevice { + +/** + * A wrapper around AF_NETLINK sockets. + * + * This class is not thread safe to use a single instance between multiple threads, but it's fine to + * use multiple instances over multiple threads. + */ +struct NetlinkSocket { + NetlinkSocket(int protocol); + + /** + * Send Netlink message to Kernel. + * + * @param msg Message to send, nlmsg_seq will be set to next sequence number + * @return true, if succeeded + */ + template + bool send(NetlinkRequest& req) { + if (!req.isGood()) return false; + return send(req.header()); + } + + /** + * Receive Netlink ACK message from Kernel. + * + * @return true if received ACK message, false in case of error + */ + bool receiveAck(); + + private: + uint32_t mSeq = 0; + base::unique_fd mFd; + bool mFailed = false; + + bool send(struct nlmsghdr* msg); + + DISALLOW_COPY_AND_ASSIGN(NetlinkSocket); +}; + +} // namespace netdevice +} // namespace android diff --git a/automotive/can/1.0/default/libnetdevice/can.cpp b/automotive/can/1.0/default/libnetdevice/can.cpp new file mode 100644 index 0000000000..87617dde74 --- /dev/null +++ b/automotive/can/1.0/default/libnetdevice/can.cpp @@ -0,0 +1,91 @@ +/* + * 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. + */ + +#include + +#include "NetlinkRequest.h" +#include "NetlinkSocket.h" +#include "common.h" + +#include +#include + +#include +#include + +namespace android { +namespace netdevice { +namespace can { + +base::unique_fd socket(const std::string& ifname) { + struct sockaddr_can addr = {}; + addr.can_family = AF_CAN; + addr.can_ifindex = nametoindex(ifname); + if (addr.can_ifindex == 0) { + LOG(ERROR) << "Interface " << ifname << " doesn't exists"; + return {}; + } + + base::unique_fd sock(::socket(PF_CAN, SOCK_RAW, CAN_RAW)); + if (!sock.ok()) { + LOG(ERROR) << "Failed to create CAN socket"; + return {}; + } + + if (0 != fcntl(sock.get(), F_SETFL, O_RDWR | O_NONBLOCK)) { + LOG(ERROR) << "Couldn't put CAN socket in non-blocking mode"; + return {}; + } + + if (0 != bind(sock.get(), reinterpret_cast(&addr), sizeof(addr))) { + LOG(ERROR) << "Can't bind to CAN interface " << ifname; + return {}; + } + + return sock; +} + +bool setBitrate(std::string ifname, uint32_t bitrate) { + struct can_bittiming bt = {}; + bt.bitrate = bitrate; + + NetlinkRequest req(RTM_NEWLINK, NLM_F_REQUEST); + + const auto ifidx = nametoindex(ifname); + if (ifidx == 0) { + LOG(ERROR) << "Can't find interface " << ifname; + return false; + } + req.data().ifi_index = ifidx; + + { + auto linkinfo = req.nest(IFLA_LINKINFO); + req.addattr(IFLA_INFO_KIND, "can"); + { + auto infodata = req.nest(IFLA_INFO_DATA); + /* For CAN FD, it would require to add IFLA_CAN_DATA_BITTIMING + * and IFLA_CAN_CTRLMODE as well. */ + req.addattr(IFLA_CAN_BITTIMING, bt); + } + } + + NetlinkSocket sock(NETLINK_ROUTE); + return sock.send(req) && sock.receiveAck(); +} + +} // namespace can +} // namespace netdevice +} // namespace android diff --git a/automotive/can/1.0/default/libnetdevice/common.cpp b/automotive/can/1.0/default/libnetdevice/common.cpp new file mode 100644 index 0000000000..3deac3e7ff --- /dev/null +++ b/automotive/can/1.0/default/libnetdevice/common.cpp @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#include "common.h" + +#include + +#include + +namespace android { +namespace netdevice { + +unsigned int nametoindex(const std::string& ifname) { + const auto ifidx = if_nametoindex(ifname.c_str()); + if (ifidx != 0) return ifidx; + + const auto err = errno; + if (err != ENODEV) { + LOG(ERROR) << "if_nametoindex(" << ifname << ") failed: " << err; + } + return 0; +} + +} // namespace netdevice +} // namespace android diff --git a/automotive/can/1.0/default/libnetdevice/common.h b/automotive/can/1.0/default/libnetdevice/common.h new file mode 100644 index 0000000000..9bdff4de21 --- /dev/null +++ b/automotive/can/1.0/default/libnetdevice/common.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace android { +namespace netdevice { + +/** + * Returns the index of a given network interface. + * + * If the syscall to check the index fails with other error than ENODEV, it gets logged and the + * return value indicates the interface doesn't exists. + * + * \param ifname Interface to check + * \return Interface index, or 0 if the interface doesn't exist + */ +unsigned int nametoindex(const std::string& ifname); + +} // namespace netdevice +} // namespace android diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h new file mode 100644 index 0000000000..ec3f96257a --- /dev/null +++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include + +namespace android { +namespace netdevice { +namespace can { + +/** + * Opens and binds SocketCAN socket. + * + * @param ifname Interface to open a socket against + * @return Socket's FD or -1 in case of failure + */ +base::unique_fd socket(const std::string& ifname); + +/** + * Sets CAN interface bitrate. + */ +bool setBitrate(std::string ifname, uint32_t bitrate); + +} // namespace can +} // namespace netdevice +} // namespace android diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h new file mode 100644 index 0000000000..33d5de5ef8 --- /dev/null +++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h @@ -0,0 +1,75 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +namespace android { +namespace netdevice { + +/** + * Checks, if the network interface exists. + * + * @param ifname Interface to check + * @return true if it exists, false otherwise + */ +bool exists(std::string ifname); + +/** + * Checks if network interface is up. + * + * @param ifname Interface to check + * @return true/false if the check succeeded, nullopt otherwise + */ +std::optional isUp(std::string ifname); + +/** + * Brings network interface up. + * + * @param ifname Interface to bring up + * @return true in case of success, false otherwise + */ +bool up(std::string ifname); + +/** + * Brings network interface down. + * + * @param ifname Interface to bring down + * @return true in case of success, false otherwise + */ +bool down(std::string ifname); + +/** + * Adds virtual link. + * + * @param dev the name of the new virtual device + * @param type the type of the new device + * @return true in case of success, false otherwise + */ +bool add(std::string dev, std::string type); + +/** + * Deletes virtual link. + * + * @param dev the name of the device to remove + * @return true in case of success, false otherwise + */ +bool del(std::string dev); + +} // namespace netdevice +} // namespace android diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp new file mode 100644 index 0000000000..fc2b193355 --- /dev/null +++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp @@ -0,0 +1,100 @@ +/* + * 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. + */ + +#include + +#include "NetlinkRequest.h" +#include "NetlinkSocket.h" +#include "common.h" + +#include + +#include +#include + +namespace android { +namespace netdevice { + +bool exists(std::string ifname) { + return nametoindex(ifname) != 0; +} + +static bool sendIfreq(unsigned long request, struct ifreq& ifr) { + /* For general interfaces it would be socket(AF_INET, SOCK_DGRAM, 0), + * but SEPolicy forces us to limit our flexibility here. */ + base::unique_fd sock(socket(PF_CAN, SOCK_RAW, CAN_RAW)); + if (!sock.ok()) { + LOG(ERROR) << "Can't create socket"; + return false; + } + + if (ioctl(sock.get(), request, &ifr) < 0) { + LOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed: " << errno; + return false; + } + + return true; +} + +static struct ifreq ifreqFromName(const std::string& ifname) { + struct ifreq ifr = {}; + strlcpy(ifr.ifr_name, ifname.c_str(), IF_NAMESIZE); + return ifr; +} + +std::optional isUp(std::string ifname) { + struct ifreq ifr = ifreqFromName(ifname); + if (!sendIfreq(SIOCGIFFLAGS, ifr)) return std::nullopt; + return ifr.ifr_flags & IFF_UP; +} + +bool up(std::string ifname) { + struct ifreq ifr = ifreqFromName(ifname); + if (!sendIfreq(SIOCGIFFLAGS, ifr)) return false; + ifr.ifr_flags |= IFF_UP; + return sendIfreq(SIOCSIFFLAGS, ifr); +} + +bool down(std::string ifname) { + struct ifreq ifr = ifreqFromName(ifname); + if (!sendIfreq(SIOCGIFFLAGS, ifr)) return false; + ifr.ifr_flags &= ~IFF_UP; + return sendIfreq(SIOCSIFFLAGS, ifr); +} + +bool add(std::string dev, std::string type) { + NetlinkRequest req(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL); + req.addattr(IFLA_IFNAME, dev); + + { + auto linkinfo = req.nest(IFLA_LINKINFO); + req.addattr(IFLA_INFO_KIND, type); + } + + NetlinkSocket sock(NETLINK_ROUTE); + return sock.send(req) && sock.receiveAck(); +} + +bool del(std::string dev) { + NetlinkRequest req(RTM_DELLINK, NLM_F_REQUEST); + req.addattr(IFLA_IFNAME, dev); + + NetlinkSocket sock(NETLINK_ROUTE); + return sock.send(req) && sock.receiveAck(); +} + +} // namespace netdevice +} // namespace android diff --git a/automotive/can/1.0/default/service.cpp b/automotive/can/1.0/default/service.cpp new file mode 100644 index 0000000000..7ef44fc297 --- /dev/null +++ b/automotive/can/1.0/default/service.cpp @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#include "CanController.h" + +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace implementation { + +static void canControllerService() { + base::SetDefaultTag("CanController"); + base::SetMinimumLogSeverity(android::base::VERBOSE); + configureRpcThreadpool(16, true); + LOG(DEBUG) << "CAN controller service starting..."; + + CanController canController; + if (canController.registerAsService("socketcan") != OK) { + LOG(FATAL) << "Failed to register CAN controller"; + return; + } + + LOG(INFO) << "CAN controller service ready"; + joinRpcThreadpool(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android + +int main() { + ::android::hardware::automotive::can::V1_0::implementation::canControllerService(); + return 1; // canBusService (joinRpcThreadpool) shouldn't exit +} From 1b2c6efe46279a3b287e3ce76ac82e6b10a74acd Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 19 Jul 2019 13:57:42 -0700 Subject: [PATCH 0056/1022] Implement CAN bus HAL tools These tools are for manual interaction with CAN bus HAL instances. Meant primarily for testing/debugging, not useful in user builds. Bug: 135918744 Test: adb shell Change-Id: I1dfbe94c0006f69954806c395cd888f3bf2a4249 --- automotive/can/1.0/hidl-utils/Android.bp | 20 ++ .../include/hidl-utils/hidl-utils.h | 67 +++++++ automotive/can/1.0/tools/Android.bp | 60 ++++++ automotive/can/1.0/tools/canhalctrl.cpp | 181 ++++++++++++++++++ automotive/can/1.0/tools/canhaldump.cpp | 136 +++++++++++++ automotive/can/1.0/tools/canhalsend.cpp | 136 +++++++++++++ 6 files changed, 600 insertions(+) create mode 100644 automotive/can/1.0/hidl-utils/Android.bp create mode 100644 automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h create mode 100644 automotive/can/1.0/tools/Android.bp create mode 100644 automotive/can/1.0/tools/canhalctrl.cpp create mode 100644 automotive/can/1.0/tools/canhaldump.cpp create mode 100644 automotive/can/1.0/tools/canhalsend.cpp diff --git a/automotive/can/1.0/hidl-utils/Android.bp b/automotive/can/1.0/hidl-utils/Android.bp new file mode 100644 index 0000000000..bc8ff136e5 --- /dev/null +++ b/automotive/can/1.0/hidl-utils/Android.bp @@ -0,0 +1,20 @@ +// +// 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. +// + +cc_library_headers { + name: "android.hardware.automotive.can@hidl-utils-lib", + export_include_dirs: ["include"], +} diff --git a/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h b/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h new file mode 100644 index 0000000000..039f971c35 --- /dev/null +++ b/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#pragma once + +namespace android { +namespace hardware { +namespace automotive { +namespace hidl_utils { + +/** + * Helper functor to fetch results from multi-return HIDL calls. + * It's meant to be used in place of _hidl_cb callbacks. + * + * Please note extracting these return variables outside of the callback scope requires making + * a copy of each return variable. This may be costly for frequently called HIDL methods with + * non-negligible return object size. Please be cautious about performance when using this. + * + * Example usage: + * Result result; + * sp iface; + * hidlObject->someMethod(arg1, arg2, hidl_utils::fill(&result, &iface)).assertOk(); + * // use result and iface + */ +template +struct fill : public std::function { + /** + * Create _hidl_cb functor that copies the call arguments to specified pointers. + * + * \param args... Targets to copy the call arguments to + */ + fill(T*... args) : mTargets(args...) {} + + void operator()(const T&... args) { copy<0, T...>(args...); } + + private: + std::tuple mTargets; + + template + inline void copy(const First& first) { + *std::get(mTargets) = first; + } + + template + inline void copy(const First& first, const Rest&... rest) { + *std::get(mTargets) = first; + copy(rest...); + } +}; + +} // namespace hidl_utils +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/can/1.0/tools/Android.bp b/automotive/can/1.0/tools/Android.bp new file mode 100644 index 0000000000..8c26985d51 --- /dev/null +++ b/automotive/can/1.0/tools/Android.bp @@ -0,0 +1,60 @@ +// +// 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. +// + +cc_binary { + name: "canhalctrl", + defaults: ["android.hardware.automotive.can@defaults"], + srcs: [ + "canhalctrl.cpp", + ], + shared_libs: [ + "android.hardware.automotive.can@1.0", + "libhidlbase", + "libhidltransport", + ], + header_libs: [ + "android.hardware.automotive.can@hidl-utils-lib", + ], +} + +cc_binary { + name: "canhaldump", + defaults: ["android.hardware.automotive.can@defaults"], + srcs: [ + "canhaldump.cpp", + ], + shared_libs: [ + "android.hardware.automotive.can@1.0", + "libhidlbase", + "libhidltransport", + ], + header_libs: [ + "android.hardware.automotive.can@hidl-utils-lib", + ], +} + +cc_binary { + name: "canhalsend", + defaults: ["android.hardware.automotive.can@defaults"], + srcs: [ + "canhalsend.cpp", + ], + shared_libs: [ + "android.hardware.automotive.can@1.0", + "libhidlbase", + "libhidltransport", + ], +} diff --git a/automotive/can/1.0/tools/canhalctrl.cpp b/automotive/can/1.0/tools/canhalctrl.cpp new file mode 100644 index 0000000000..fa1048d6ac --- /dev/null +++ b/automotive/can/1.0/tools/canhalctrl.cpp @@ -0,0 +1,181 @@ +/* + * 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. + */ + +#include +#include +#include +#include + +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { + +using ICanController = V1_0::ICanController; + +static void usage() { + std::cerr << "CAN bus HAL Control tool" << std::endl; + std::cerr << std::endl << "usage:" << std::endl << std::endl; + std::cerr << "canhalctrl up [baudrate]" << std::endl; + std::cerr << "where:" << std::endl; + std::cerr << " bus name - name under which ICanBus will be published" << std::endl; + std::cerr << " type - one of: virtual, socketcan, slcan, indexed" << std::endl; + std::cerr << " interface - hardware identifier (like can0, vcan0, /dev/ttyUSB0)" << std::endl; + std::cerr << " baudrate - such as 100000, 125000, 250000, 500000" << std::endl; + std::cerr << std::endl; + std::cerr << "canhalctrl down " << std::endl; + std::cerr << "where:" << std::endl; + std::cerr << " bus name - name under which ICanBus will be published" << std::endl; +} + +static hidl_vec getControlServices() { + auto manager = hidl::manager::V1_2::IServiceManager::getService(); + hidl_vec services; + manager->listManifestByInterface(ICanController::descriptor, hidl_utils::fill(&services)); + if (services.size() == 0) { + std::cerr << "No ICanController services registered (missing privileges?)" << std::endl; + exit(-1); + } + return services; +} + +static bool isSupported(sp ctrl, ICanController::InterfaceType iftype) { + hidl_vec supported; + if (!ctrl->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).isOk()) return false; + return supported.contains(iftype); +} + +static int up(const std::string& busName, ICanController::InterfaceType type, + const std::string& interface, uint32_t baudrate) { + bool anySupported = false; + for (auto&& service : getControlServices()) { + auto ctrl = ICanController::getService(service); + if (ctrl == nullptr) { + std::cerr << "Couldn't open ICanController/" << service; + continue; + } + + if (!isSupported(ctrl, type)) continue; + anySupported = true; + + ICanController::BusConfiguration config = {}; + config.name = busName; + config.iftype = type; + config.baudrate = baudrate; + + if (type == ICanController::InterfaceType::INDEXED) { + config.interfaceId.index(std::stol(interface)); + } else { + config.interfaceId.address(interface); + } + + const auto upresult = ctrl->upInterface(config); + if (upresult == ICanController::Result::OK) return 0; + std::cerr << "Failed to bring interface up: " << toString(upresult) << std::endl; + // Let's continue the loop to try other controllers. + } + + if (!anySupported) { + std::cerr << "No controller supports " << toString(type) << std::endl; + } + return -1; +} + +static int down(const std::string& busName) { + for (auto&& service : getControlServices()) { + auto ctrl = ICanController::getService(service); + if (ctrl == nullptr) continue; + + if (ctrl->downInterface(busName)) return 0; + } + + std::cerr << "Failed to bring interface " << busName << " down (maybe it's down already?)" + << std::endl; + return -1; +} + +static std::optional parseInterfaceType(const std::string& str) { + if (str == "virtual") return ICanController::InterfaceType::VIRTUAL; + if (str == "socketcan") return ICanController::InterfaceType::SOCKETCAN; + if (str == "slcan") return ICanController::InterfaceType::SLCAN; + if (str == "indexed") return ICanController::InterfaceType::INDEXED; + return std::nullopt; +} + +static int main(int argc, char* argv[]) { + base::SetDefaultTag("CanHalControl"); + base::SetMinimumLogSeverity(android::base::VERBOSE); + + if (argc == 0) { + usage(); + return 0; + } + + std::string cmd(argv[0]); + argv++; + argc--; + + if (cmd == "up") { + if (argc < 3 || argc > 4) { + std::cerr << "Invalid number of arguments to up command: " << argc << std::endl; + usage(); + return -1; + } + + const std::string busName(argv[0]); + const std::string typeStr(argv[1]); + const std::string interface(argv[2]); + + const auto type = parseInterfaceType(typeStr); + if (!type) { + std::cerr << "Invalid interface type: " << typeStr << std::endl; + usage(); + return -1; + } + + long long baudrate = 0; + if (argc == 4) { + baudrate = std::stoll(argv[3]); + } + + return up(busName, *type, interface, baudrate); + } else if (cmd == "down") { + if (argc != 1) { + std::cerr << "Invalid number of arguments to down command: " << argc << std::endl; + usage(); + return -1; + } + + return down(argv[0]); + } else { + std::cerr << "Invalid command: " << cmd << std::endl; + usage(); + return -1; + } +} + +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android + +int main(int argc, char* argv[]) { + if (argc < 1) return -1; + return ::android::hardware::automotive::can::main(--argc, ++argv); +} diff --git a/automotive/can/1.0/tools/canhaldump.cpp b/automotive/can/1.0/tools/canhaldump.cpp new file mode 100644 index 0000000000..5713d17e8d --- /dev/null +++ b/automotive/can/1.0/tools/canhaldump.cpp @@ -0,0 +1,136 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { + +using namespace std::chrono_literals; + +using ICanBus = V1_0::ICanBus; +using Result = V1_0::Result; + +struct CanMessageListener : public V1_0::ICanMessageListener { + const std::string name; + + CanMessageListener(std::string name) : name(name) {} + + virtual Return onReceive(const V1_0::CanMessage& message) { + std::cout << " " << name << " " << std::hex << std::uppercase << std::setw(3) + << std::setfill('0') << message.id << std::setw(0); + if (message.remoteTransmissionRequest) { + std::cout << " RTR"; + } else { + std::cout << " [" << message.payload.size() << "] "; + for (const auto byte : message.payload) { + std::cout << " " << unsigned(byte); + } + } + std::cout << std::nouppercase << std::dec << std::endl; + return {}; + } + + virtual Return onError(V1_0::ErrorEvent error) { + std::cout << " " << name << " " << toString(error) << std::endl; + return {}; + } +}; + +static void usage() { + std::cerr << "canhaldump - dump CAN bus traffic" << std::endl; + std::cerr << std::endl << "usage:" << std::endl << std::endl; + std::cerr << "canhaldump " << std::endl; + std::cerr << "where:" << std::endl; + std::cerr << " bus name - name under which ICanBus is be published" << std::endl; +} + +// TODO(b/135918744): extract to a new library +static sp tryOpen(const std::string& busname) { + auto bus = ICanBus::tryGetService(busname); + if (bus != nullptr) return bus; + + /* Fallback for interfaces not registered in manifest. For testing purposes only, + * one should not depend on this in production deployment. */ + auto manager = hidl::manager::V1_2::IServiceManager::getService(); + auto ret = manager->get(ICanBus::descriptor, busname).withDefault(nullptr); + if (ret == nullptr) return nullptr; + + std::cerr << "WARNING: bus " << busname << " is not registered in device manifest, " + << "trying to fetch it directly..." << std::endl; + + return ICanBus::castFrom(ret); +} + +static int candump(const std::string& busname) { + auto bus = tryOpen(busname); + if (bus == nullptr) { + std::cerr << "Bus " << busname << " is not available" << std::endl; + return -1; + } + + Result result; + sp chnd; + // TODO(b/135918744): extract to library + bus->listen({}, new CanMessageListener(busname), hidl_utils::fill(&result, &chnd)).assertOk(); + + if (result != Result::OK) { + std::cerr << "Listen call failed: " << toString(result) << std::endl; + return -1; + } + + while (true) std::this_thread::sleep_for(1h); +} + +static int main(int argc, char* argv[]) { + base::SetDefaultTag("CanHalDump"); + base::SetMinimumLogSeverity(android::base::VERBOSE); + + if (argc == 0) { + usage(); + return 0; + } + + if (argc != 1) { + std::cerr << "Invalid number of arguments" << std::endl; + usage(); + return -1; + } + + return candump(argv[0]); +} + +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android + +int main(int argc, char* argv[]) { + if (argc < 1) return -1; + return ::android::hardware::automotive::can::main(--argc, ++argv); +} diff --git a/automotive/can/1.0/tools/canhalsend.cpp b/automotive/can/1.0/tools/canhalsend.cpp new file mode 100644 index 0000000000..29330c9c75 --- /dev/null +++ b/automotive/can/1.0/tools/canhalsend.cpp @@ -0,0 +1,136 @@ +/* + * 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. + */ + +#include +#include +#include + +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { + +using ICanBus = V1_0::ICanBus; +using Result = V1_0::Result; + +static void usage() { + std::cerr << "cansend - simple command line tool to send raw CAN frames" << std::endl; + std::cerr << std::endl << "usage:" << std::endl << std::endl; + std::cerr << "canhalsend #" << std::endl; + std::cerr << "where:" << std::endl; + std::cerr << " bus name - name under which ICanBus is be published" << std::endl; + std::cerr << " can id - such as 1a5" << std::endl; + std::cerr << " data - such as deadbeef or 010203" << std::endl; +} + +// TODO(b/135918744): extract to a new library +static sp tryOpen(const std::string& busname) { + auto bus = ICanBus::tryGetService(busname); + if (bus != nullptr) return bus; + + /* Fallback for interfaces not registered in manifest. For testing purposes only, + * one should not depend on this in production deployment. */ + auto manager = hidl::manager::V1_2::IServiceManager::getService(); + auto ret = manager->get(ICanBus::descriptor, busname).withDefault(nullptr); + if (ret == nullptr) return nullptr; + + std::cerr << "WARNING: bus " << busname << " is not registered in device manifest, " + << "trying to fetch it directly..." << std::endl; + + return ICanBus::castFrom(ret); +} + +static int cansend(const std::string& busname, V1_0::CanMessageId msgid, + std::vector payload) { + auto bus = tryOpen(busname); + if (bus == nullptr) { + std::cerr << "Bus " << busname << " is not available" << std::endl; + return -1; + } + + V1_0::CanMessage msg = {}; + msg.id = msgid; + msg.payload = payload; + + const auto result = bus->send(msg); + if (result != Result::OK) { + std::cerr << "Send call failed: " << toString(result) << std::endl; + return -1; + } + return 0; +} + +static std::optional>> parseCanMessage( + const std::string& msg) { + const auto hashpos = msg.find("#"); + if (hashpos == std::string::npos) return std::nullopt; + + const std::string msgidStr = msg.substr(0, hashpos); + const std::string payloadStr = msg.substr(hashpos + 1); + + size_t idx = 0; + V1_0::CanMessageId msgid = std::stoi(msgidStr, &idx, 16); + if (msgidStr[idx] != '\0') return std::nullopt; + + std::vector payload; + if (payloadStr.size() % 2 != 0) return std::nullopt; + for (size_t i = 0; i < payloadStr.size(); i += 2) { + std::string byteStr(payloadStr, i, 2); + payload.emplace_back(std::stoi(byteStr, &idx, 16)); + if (byteStr[idx] != '\0') return std::nullopt; + } + + return {{msgid, payload}}; +} + +static int main(int argc, char* argv[]) { + base::SetDefaultTag("CanHalSend"); + base::SetMinimumLogSeverity(android::base::VERBOSE); + + if (argc == 0) { + usage(); + return 0; + } + + if (argc != 2) { + std::cerr << "Invalid number of arguments" << std::endl; + usage(); + return -1; + } + + std::string busname(argv[0]); + const auto canmsg = parseCanMessage(argv[1]); + if (!canmsg) { + std::cerr << "Failed to parse CAN message argument" << std::endl; + return -1; + } + const auto [msgid, payload] = *canmsg; + + return cansend(busname, msgid, payload); +} + +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android + +int main(int argc, char* argv[]) { + if (argc < 1) return -1; + return ::android::hardware::automotive::can::main(--argc, ++argv); +} From 0ec8d63d5d7f1895158d3e98ff5ea4f00b3dd026 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 12 Jul 2019 11:43:44 -0700 Subject: [PATCH 0057/1022] Test CAN bus HAL Bug: 135918744 Test: VTS Change-Id: I7b45a24b6a1142cf74c1d215658792835553d169 --- automotive/can/1.0/vts/functional/Android.bp | 47 +++ .../functional/VtsHalCanBusV1_0TargetTest.cpp | 168 +++++++++ .../VtsHalCanBusVirtualV1_0TargetTest.cpp | 322 ++++++++++++++++++ .../VtsHalCanControllerV1_0TargetTest.cpp | 260 ++++++++++++++ automotive/can/1.0/vts/utils/Android.bp | 20 ++ .../include/can-vts-utils/can-hal-printers.h | 55 +++ .../include/can-vts-utils/environment-utils.h | 72 ++++ 7 files changed, 944 insertions(+) create mode 100644 automotive/can/1.0/vts/functional/Android.bp create mode 100644 automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp create mode 100644 automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp create mode 100644 automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp create mode 100644 automotive/can/1.0/vts/utils/Android.bp create mode 100644 automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h create mode 100644 automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h diff --git a/automotive/can/1.0/vts/functional/Android.bp b/automotive/can/1.0/vts/functional/Android.bp new file mode 100644 index 0000000000..b4d91325ee --- /dev/null +++ b/automotive/can/1.0/vts/functional/Android.bp @@ -0,0 +1,47 @@ +// +// 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. +// + +cc_defaults { + name: "android.hardware.automotive.can@vts-defaults", + defaults: ["VtsHalTargetTestDefaults", "android.hardware.automotive.can@defaults"], + header_libs: [ + "android.hardware.automotive.can@hidl-utils-lib", + "android.hardware.automotive.can@vts-utils-lib", + ], + static_libs: [ + "android.hardware.automotive.can@1.0", + "libgmock", + ], + test_suites: ["general-tests"], +} + +cc_test { + name: "VtsHalCanControllerV1_0TargetTest", + defaults: ["android.hardware.automotive.can@vts-defaults"], + srcs: ["VtsHalCanControllerV1_0TargetTest.cpp"], +} + +cc_test { + name: "VtsHalCanBusV1_0TargetTest", + defaults: ["android.hardware.automotive.can@vts-defaults"], + srcs: ["VtsHalCanBusV1_0TargetTest.cpp"], +} + +cc_test { + name: "VtsHalCanBusVirtualV1_0TargetTest", + defaults: ["android.hardware.automotive.can@vts-defaults"], + srcs: ["VtsHalCanBusVirtualV1_0TargetTest.cpp"], +} diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp new file mode 100644 index 0000000000..215328e878 --- /dev/null +++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp @@ -0,0 +1,168 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace vts { + +using hardware::hidl_vec; + +static utils::SimpleHidlEnvironment* gEnv = nullptr; + +struct CanMessageListener : public can::V1_0::ICanMessageListener { + virtual Return onReceive(const can::V1_0::CanMessage&) { return {}; } + virtual Return onError(can::V1_0::ErrorEvent) { return {}; } +}; + +class CanBusHalTest : public ::testing::VtsHalHidlTargetTestBase { + protected: + virtual void SetUp() override; + virtual void TearDown() override; + + std::tuple> listen(const hidl_vec& filter, + const sp& listener); + + sp mCanBus; +}; + +void CanBusHalTest::SetUp() { + const auto serviceName = gEnv->getServiceName(); + mCanBus = getService(serviceName); + ASSERT_TRUE(mCanBus) << "Couldn't open CAN Bus: " << serviceName; +} + +void CanBusHalTest::TearDown() { + mCanBus.clear(); +} + +std::tuple> CanBusHalTest::listen( + const hidl_vec& filter, const sp& listener) { + Result halResult; + sp closeHandle; + mCanBus->listen(filter, listener, hidl_utils::fill(&halResult, &closeHandle)).assertOk(); + + return {halResult, closeHandle}; +} + +TEST_F(CanBusHalTest, SendNoPayload) { + CanMessage msg = {}; + msg.id = 0x123; + + const auto result = mCanBus->send(msg); + ASSERT_EQ(Result::OK, result); +} + +TEST_F(CanBusHalTest, Send8B) { + CanMessage msg = {}; + msg.id = 0x234; + msg.payload = {1, 2, 3, 4, 5, 6, 7, 8}; + + const auto result = mCanBus->send(msg); + ASSERT_EQ(Result::OK, result); +} + +TEST_F(CanBusHalTest, SendZeroId) { + CanMessage msg = {}; + msg.payload = {1, 2, 3}; + + const auto result = mCanBus->send(msg); + ASSERT_EQ(Result::OK, result); +} + +TEST_F(CanBusHalTest, SendTooLong) { + CanMessage msg = {}; + msg.id = 0x123; + msg.payload = hidl_vec(102400); // 100kiB + + const auto result = mCanBus->send(msg); + ASSERT_EQ(Result::PAYLOAD_TOO_LONG, result); +} + +TEST_F(CanBusHalTest, ListenNoFilter) { + const auto [result, closeHandle] = listen({}, new CanMessageListener()); + ASSERT_EQ(Result::OK, result); + + closeHandle->close().assertOk(); +} + +TEST_F(CanBusHalTest, ListenSomeFilter) { + hidl_vec filters = { + {0x123, 0x1FF, false}, + {0x001, 0x00F, true}, + {0x200, 0x100, false}, + }; + + const auto [result, closeHandle] = listen(filters, new CanMessageListener()); + ASSERT_EQ(Result::OK, result); + + closeHandle->close().assertOk(); +} + +TEST_F(CanBusHalTest, ListenNull) { + const auto [result, closeHandle] = listen({}, nullptr); + ASSERT_EQ(Result::INVALID_ARGUMENTS, result); +} + +TEST_F(CanBusHalTest, DoubleCloseListen) { + const auto [result, closeHandle] = listen({}, new CanMessageListener()); + ASSERT_EQ(Result::OK, result); + + closeHandle->close().assertOk(); + closeHandle->close().assertOk(); +} + +TEST_F(CanBusHalTest, DontCloseListen) { + const auto [result, closeHandle] = listen({}, new CanMessageListener()); + ASSERT_EQ(Result::OK, result); +} + +} // namespace vts +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android + +/** + * Example manual invocation: + * adb shell /data/nativetest64/VtsHalCanBusV1_0TargetTest/VtsHalCanBusV1_0TargetTest \ + * --hal_service_instance=android.hardware.automotive.can@1.0::ICanBus/test + */ +int main(int argc, char** argv) { + using android::hardware::automotive::can::V1_0::ICanBus; + using android::hardware::automotive::can::V1_0::vts::gEnv; + using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment; + android::base::SetDefaultTag("CanBusVts"); + android::base::SetMinimumLogSeverity(android::base::VERBOSE); + gEnv = new SimpleHidlEnvironment; + ::testing::AddGlobalTestEnvironment(gEnv); + ::testing::InitGoogleTest(&argc, argv); + gEnv->init(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp new file mode 100644 index 0000000000..699c1387a3 --- /dev/null +++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp @@ -0,0 +1,322 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace vts { + +using namespace std::chrono_literals; + +using hardware::hidl_vec; +using InterfaceType = ICanController::InterfaceType; + +static utils::SimpleHidlEnvironment* gEnv = nullptr; + +struct CanMessageListener : public can::V1_0::ICanMessageListener { + DISALLOW_COPY_AND_ASSIGN(CanMessageListener); + + CanMessageListener() {} + + virtual Return onReceive(const can::V1_0::CanMessage& msg) { + std::unique_lock lk(mMessagesGuard); + mMessages.push_back(msg); + mMessagesUpdated.notify_one(); + return {}; + } + + virtual Return onError(can::V1_0::ErrorEvent event) { + EXPECT_TRUE(false) << "Got error: " << event; + return {}; + } + + virtual ~CanMessageListener() { mCloseHandle->close(); } + + void assignCloseHandle(sp closeHandle) { + EXPECT_TRUE(closeHandle); + EXPECT_FALSE(mCloseHandle); + mCloseHandle = closeHandle; + } + + std::vector fetchMessages(std::chrono::milliseconds timeout, + unsigned atLeast = 1) { + std::unique_lock lk(mMessagesGuard); + mMessagesUpdated.wait_for(lk, timeout, [&] { return mMessages.size() >= atLeast; }); + const auto messages = mMessages; + mMessages.clear(); + return messages; + } + + private: + sp mCloseHandle; + + std::mutex mMessagesGuard; + std::condition_variable mMessagesUpdated GUARDED_BY(mMessagesGuard); + std::vector mMessages GUARDED_BY(mMessagesGuard); +}; + +struct Bus { + DISALLOW_COPY_AND_ASSIGN(Bus); + + Bus(sp controller, const ICanController::BusConfiguration& config) + : mIfname(config.name), mController(controller) { + const auto result = controller->upInterface(config); + EXPECT_EQ(ICanController::Result::OK, result); + + /* Not using ICanBus::getService here, since it ignores interfaces not in the manifest + * file -- this is a test, so we don't want to add dummy services to a device manifest. + */ + auto manager = hidl::manager::V1_2::IServiceManager::getService(); + auto service = manager->get(ICanBus::descriptor, config.name); + mBus = ICanBus::castFrom(service); + EXPECT_TRUE(mBus) << "ICanBus/" << config.name << " failed to register"; + } + + virtual ~Bus() { reset(); } + + void reset() { + mBus.clear(); + if (mController) { + const auto res = mController->downInterface(mIfname); + EXPECT_TRUE(res); + mController.clear(); + } + } + + ICanBus* operator->() const { return mBus.get(); } + sp get() { return mBus; } + + sp listen(const hidl_vec& filter) { + sp listener = new CanMessageListener(); + + Result result; + sp closeHandle; + mBus->listen(filter, listener, hidl_utils::fill(&result, &closeHandle)).assertOk(); + EXPECT_EQ(Result::OK, result); + listener->assignCloseHandle(closeHandle); + + return listener; + } + + void send(const CanMessage& msg) { + const auto result = mBus->send(msg); + EXPECT_EQ(Result::OK, result); + } + + private: + const std::string mIfname; + sp mController; + sp mBus; +}; + +class CanBusVirtualHalTest : public ::testing::VtsHalHidlTargetTestBase { + protected: + virtual void SetUp() override; + + static void SetUpTestCase(); + static void TearDownTestCase(); + + Bus makeBus(); + + private: + unsigned mLastIface = 0; + static sp mCanController; + static bool mVirtualSupported; +}; + +sp CanBusVirtualHalTest::mCanController = nullptr; +bool CanBusVirtualHalTest::mVirtualSupported; + +static CanMessage makeMessage(CanMessageId id) { + CanMessage msg = {}; + msg.id = id; + return msg; +} + +static void clearTimestamps(std::vector& messages) { + std::for_each(messages.begin(), messages.end(), [](auto& msg) { msg.timestamp = 0; }); +} + +void CanBusVirtualHalTest::SetUp() { + if (!mVirtualSupported) GTEST_SKIP(); +} + +void CanBusVirtualHalTest::SetUpTestCase() { + const auto serviceName = gEnv->getServiceName(); + mCanController = getService(serviceName); + ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << serviceName; + + hidl_vec supported; + mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).assertOk(); + mVirtualSupported = supported.contains(InterfaceType::VIRTUAL); +} + +void CanBusVirtualHalTest::TearDownTestCase() { + mCanController.clear(); +} + +Bus CanBusVirtualHalTest::makeBus() { + const auto idx = ++mLastIface; + + ICanController::BusConfiguration config = {}; + config.name = "test" + std::to_string(idx); + config.iftype = InterfaceType::VIRTUAL; + config.interfaceId.address("vcan50"); + + return Bus(mCanController, config); +} + +TEST_F(CanBusVirtualHalTest, Send) { + auto bus = makeBus(); + + CanMessage msg = {}; + msg.id = 0x123; + msg.payload = {1, 2, 3}; + + bus.send(msg); +} + +TEST_F(CanBusVirtualHalTest, SendAfterClose) { + auto bus = makeBus(); + auto zombie = bus.get(); + bus.reset(); + + const auto result = zombie->send({}); + ASSERT_EQ(Result::INTERFACE_DOWN, result); +} + +TEST_F(CanBusVirtualHalTest, SendAndRecv) { + auto bus1 = makeBus(); + auto bus2 = makeBus(); + + auto listener = bus2.listen({}); + + CanMessage msg = {}; + msg.id = 0x123; + msg.payload = {1, 2, 3}; + bus1.send(msg); + + auto messages = listener->fetchMessages(100ms); + ASSERT_EQ(1u, messages.size()); + ASSERT_NEAR(uint64_t(elapsedRealtimeNano()), messages[0].timestamp, + std::chrono::nanoseconds(100ms).count()); + clearTimestamps(messages); + ASSERT_EQ(msg, messages[0]); +} + +TEST_F(CanBusVirtualHalTest, DownOneOfTwo) { + auto bus1 = makeBus(); + auto bus2 = makeBus(); + + bus2.reset(); + + bus1.send({}); +} + +TEST_F(CanBusVirtualHalTest, Filter) { + auto bus1 = makeBus(); + auto bus2 = makeBus(); + + hidl_vec filterPositive = { + {0x101, 0x100, false}, + {0x010, 0x0F0, false}, + }; + auto listenerPositive = bus2.listen(filterPositive); + + hidl_vec filterNegative = { + {0x123, 0x0FF, true}, + {0x004, 0x00F, true}, + }; + auto listenerNegative = bus2.listen(filterNegative); + + bus1.send(makeMessage(0)); + bus1.send(makeMessage(0x1A0)); + bus1.send(makeMessage(0x1A1)); + bus1.send(makeMessage(0x2A0)); + bus1.send(makeMessage(0x3A0)); + bus1.send(makeMessage(0x010)); + bus1.send(makeMessage(0x123)); + bus1.send(makeMessage(0x023)); + bus1.send(makeMessage(0x124)); + + std::vector expectedPositive{ + makeMessage(0x1A0), // + makeMessage(0x1A1), // + makeMessage(0x3A0), // + makeMessage(0x010), // + makeMessage(0x123), // + makeMessage(0x124), // + }; + std::vector expectedNegative{ + makeMessage(0), // + makeMessage(0x1A0), // + makeMessage(0x1A1), // + makeMessage(0x2A0), // + makeMessage(0x3A0), // + makeMessage(0x010), // + }; + + auto messagesNegative = listenerNegative->fetchMessages(100ms, expectedNegative.size()); + auto messagesPositive = listenerPositive->fetchMessages(100ms, expectedPositive.size()); + clearTimestamps(messagesNegative); + clearTimestamps(messagesPositive); + ASSERT_EQ(expectedNegative, messagesNegative); + ASSERT_EQ(expectedPositive, messagesPositive); +} + +} // namespace vts +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android + +/** + * Example manual invocation: + * adb shell /data/nativetest64/VtsHalCanBusVirtualV1_0TargetTest/VtsHalCanBusVirtualV1_0TargetTest\ + * --hal_service_instance=android.hardware.automotive.can@1.0::ICanController/socketcan + */ +int main(int argc, char** argv) { + using android::hardware::automotive::can::V1_0::ICanController; + using android::hardware::automotive::can::V1_0::vts::gEnv; + using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment; + android::base::SetDefaultTag("CanBusVirtualVts"); + android::base::SetMinimumLogSeverity(android::base::VERBOSE); + gEnv = new SimpleHidlEnvironment; + ::testing::AddGlobalTestEnvironment(gEnv); + ::testing::InitGoogleTest(&argc, argv); + gEnv->init(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp new file mode 100644 index 0000000000..70f9fe44b5 --- /dev/null +++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp @@ -0,0 +1,260 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace vts { + +using hardware::hidl_vec; +using InterfaceType = ICanController::InterfaceType; + +static utils::SimpleHidlEnvironment* gEnv = nullptr; + +class CanControllerHalTest : public ::testing::VtsHalHidlTargetTestBase { + protected: + virtual void SetUp() override; + virtual void TearDown() override; + + hidl_vec getSupportedInterfaceTypes(); + bool isSupported(InterfaceType iftype); + + bool up(InterfaceType iftype, const std::string srvname, std::string ifname, + ICanController::Result expected); + void assertRegistered(const std::string srvname, bool expectRegistered); + + sp mCanController; +}; + +void CanControllerHalTest::SetUp() { + const auto serviceName = gEnv->getServiceName(); + mCanController = getService(serviceName); + ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << serviceName; +} + +void CanControllerHalTest::TearDown() { + mCanController.clear(); +} + +hidl_vec CanControllerHalTest::getSupportedInterfaceTypes() { + hidl_vec iftypesResult; + mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&iftypesResult)).assertOk(); + return iftypesResult; +} + +bool CanControllerHalTest::isSupported(InterfaceType iftype) { + const auto supported = getSupportedInterfaceTypes(); + return std::find(supported.begin(), supported.end(), iftype) != supported.end(); +} + +bool CanControllerHalTest::up(InterfaceType iftype, std::string srvname, std::string ifname, + ICanController::Result expected) { + ICanController::BusConfiguration config = {}; + config.name = srvname; + config.iftype = iftype; + config.interfaceId.address(ifname); + + const auto upresult = mCanController->upInterface(config); + + if (!isSupported(iftype)) { + LOG(INFO) << iftype << " interfaces not supported"; + EXPECT_EQ(ICanController::Result::NOT_SUPPORTED, upresult); + return false; + } + + EXPECT_EQ(expected, upresult); + return true; +} + +void CanControllerHalTest::assertRegistered(std::string srvname, bool expectRegistered) { + /* Not using ICanBus::tryGetService here, since it ignores interfaces not in the manifest + * file -- this is a test, so we don't want to add dummy services to a device manifest. + */ + auto manager = hidl::manager::V1_2::IServiceManager::getService(); + auto busService = manager->get(ICanBus::descriptor, srvname); + ASSERT_EQ(expectRegistered, busService.withDefault(nullptr) != nullptr) + << "ICanBus/" << srvname << (expectRegistered ? " is not " : " is ") << "registered" + << " (should be otherwise)"; +} + +TEST_F(CanControllerHalTest, SupportsSomething) { + const auto supported = getSupportedInterfaceTypes(); + ASSERT_GT(supported.size(), 0u); +} + +TEST_F(CanControllerHalTest, BringUpDown) { + const std::string name = "dummy"; + + assertRegistered(name, false); + if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::OK)) GTEST_SKIP(); + assertRegistered(name, true); + + const auto dnresult = mCanController->downInterface(name); + ASSERT_TRUE(dnresult); + + assertRegistered(name, false); +} + +TEST_F(CanControllerHalTest, DownDummy) { + const auto result = mCanController->downInterface("imnotup"); + ASSERT_FALSE(result); +} + +TEST_F(CanControllerHalTest, UpTwice) { + const std::string name = "dummy"; + + assertRegistered(name, false); + if (!up(InterfaceType::VIRTUAL, name, "vcan72", ICanController::Result::OK)) GTEST_SKIP(); + assertRegistered(name, true); + if (!up(InterfaceType::VIRTUAL, name, "vcan73", ICanController::Result::INVALID_STATE)) { + GTEST_SKIP(); + } + assertRegistered(name, true); + + const auto result = mCanController->downInterface(name); + ASSERT_TRUE(result); + assertRegistered(name, false); +} + +TEST_F(CanControllerHalTest, IdentifierCompatibility) { + using IdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator; + static const std::map> compatMatrix = { + {InterfaceType::VIRTUAL, {IdDisc::address}}, + {InterfaceType::SOCKETCAN, {IdDisc::address, IdDisc::serialno}}, + {InterfaceType::SLCAN, {IdDisc::address, IdDisc::serialno}}, + {InterfaceType::INDEXED, {IdDisc::index}}, + }; + static const std::vector allDisc = {IdDisc::address, IdDisc::index, IdDisc::serialno}; + + for (const auto [iftype, supported] : compatMatrix) { + for (const auto iddisc : allDisc) { + LOG(INFO) << "Compatibility testing: " << iftype << " / " << iddisc; + + ICanController::BusConfiguration config = {}; + config.name = "compattestsrv"; + config.iftype = iftype; + config.baudrate = 125000; + + // using random-ish addresses, which may not be valid - we can't test the success case + if (iddisc == IdDisc::address) { + config.interfaceId.address("can0"); + } else if (iddisc == IdDisc::index) { + config.interfaceId.index(0); + } else if (iddisc == IdDisc::serialno) { + config.interfaceId.serialno({"dummy", "dummier"}); + } + + const auto upresult = mCanController->upInterface(config); + + if (!isSupported(iftype)) { + ASSERT_EQ(ICanController::Result::NOT_SUPPORTED, upresult); + continue; + } + ASSERT_NE(ICanController::Result::NOT_SUPPORTED, upresult); + + bool isSupportedDisc = + std::find(supported.begin(), supported.end(), iddisc) != supported.end(); + if (!isSupportedDisc) { + ASSERT_EQ(ICanController::Result::BAD_ADDRESS, upresult); + continue; + } + + if (upresult == ICanController::Result::OK) { + const auto dnresult = mCanController->downInterface(config.name); + ASSERT_TRUE(dnresult); + continue; + } + } + } +} + +TEST_F(CanControllerHalTest, FailEmptyName) { + const std::string name = ""; + + assertRegistered(name, false); + if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::UNKNOWN_ERROR)) { + GTEST_SKIP(); + } + assertRegistered(name, false); +} + +TEST_F(CanControllerHalTest, FailBadName) { + // 33 characters (name can be at most 32 characters long) + const std::string name = "ab012345678901234567890123456789c"; + + assertRegistered(name, false); + if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::UNKNOWN_ERROR)) { + GTEST_SKIP(); + } + assertRegistered(name, false); +} + +TEST_F(CanControllerHalTest, FailBadVirtualAddress) { + const std::string name = "dummy"; + + assertRegistered(name, false); + if (!up(InterfaceType::VIRTUAL, name, "", ICanController::Result::BAD_ADDRESS)) GTEST_SKIP(); + assertRegistered(name, false); +} + +TEST_F(CanControllerHalTest, FailBadSocketcanAddress) { + const std::string name = "dummy"; + + assertRegistered(name, false); + if (!up(InterfaceType::SOCKETCAN, name, "can87", ICanController::Result::BAD_ADDRESS)) { + GTEST_SKIP(); + } + assertRegistered(name, false); +} + +} // namespace vts +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android + +/** + * Example manual invocation: + * adb shell /data/nativetest64/VtsHalCanControllerV1_0TargetTest/VtsHalCanControllerV1_0TargetTest\ + * --hal_service_instance=android.hardware.automotive.can@1.0::ICanController/socketcan + */ +int main(int argc, char** argv) { + using android::hardware::automotive::can::V1_0::ICanController; + using android::hardware::automotive::can::V1_0::vts::gEnv; + using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment; + android::base::SetDefaultTag("CanControllerVts"); + android::base::SetMinimumLogSeverity(android::base::VERBOSE); + gEnv = new SimpleHidlEnvironment; + ::testing::AddGlobalTestEnvironment(gEnv); + ::testing::InitGoogleTest(&argc, argv); + gEnv->init(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/automotive/can/1.0/vts/utils/Android.bp b/automotive/can/1.0/vts/utils/Android.bp new file mode 100644 index 0000000000..e925c8fe34 --- /dev/null +++ b/automotive/can/1.0/vts/utils/Android.bp @@ -0,0 +1,20 @@ +// +// 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. +// + +cc_library_headers { + name: "android.hardware.automotive.can@vts-utils-lib", + export_include_dirs: ["include"], +} diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h new file mode 100644 index 0000000000..09239989ef --- /dev/null +++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { + +/** + * Define gTest printer for a given HIDL type, but skip definition for Return. + */ +#define DEFINE_CAN_HAL_PRINTER_SIMPLE(T, converter) \ + std::ostream& operator<<(std::ostream& os, const T& v) { return os << converter(v); } + +/** + * Define gTest printer for a given HIDL type. + */ +#define DEFINE_CAN_HAL_PRINTER(T, converter) \ + DEFINE_CAN_HAL_PRINTER_SIMPLE(T, converter) \ + std::ostream& operator<<(std::ostream& os, const Return& v) { return os << converter(v); } + +DEFINE_CAN_HAL_PRINTER(CanMessage, toString) +DEFINE_CAN_HAL_PRINTER(ErrorEvent, toString) +DEFINE_CAN_HAL_PRINTER_SIMPLE( + ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator, int) +DEFINE_CAN_HAL_PRINTER(ICanController::InterfaceType, toString) +DEFINE_CAN_HAL_PRINTER(ICanController::Result, toString) +DEFINE_CAN_HAL_PRINTER(Result, toString) + +#undef DEFINE_CAN_HAL_PRINTER +#undef DEFINE_CAN_HAL_PRINTER_SIMPLE + +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h new file mode 100644 index 0000000000..a722dd0783 --- /dev/null +++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace vts { +namespace utils { + +/** + * Simple test environment. + * + * This is a helper class to instantiate a test environment without boilerplate code for cases where + * there is no need to pass more parameters than just HIDL service instance name. + * + * The class implements registerTestServices() by calling registerTestService() on every HIDL + * interface provided as parameter to this template. + * + * Example usage: + * static utils::SimpleHidlEnvironment* gEnv = nullptr; + * + * void CanBusHalTest::SetUp() { + * const auto serviceName = gEnv->getServiceName(); + * (...) + * } + * + * int main(int argc, char** argv) { + * gEnv = new SimpleHidlEnvironment; + * ::testing::AddGlobalTestEnvironment(gEnv); + * ::testing::InitGoogleTest(&argc, argv); + * gEnv->init(&argc, argv); + * return RUN_ALL_TESTS(); + * } + * + * \param T... HIDL interface names to register for a test service + */ +template +class SimpleHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + virtual void registerTestServices() override { + // Call registerTestService() for every HIDL interface using this template. + using expander = int[]; + (void)expander{0, (registerTestService(), 0)...}; + } +}; + +} // namespace utils +} // namespace vts +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android From bd5b290fbf7a89f16d553c5fb77de7406634caec Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Fri, 19 Jul 2019 09:53:35 -0700 Subject: [PATCH 0058/1022] camera/metadata/3.5 Add SYSTEM_CAMERA capability. Bug: 133508924 Bug: 138135081 Test: builds Change-Id: I67199769488b819f726d73a762f56980f9c94ca6 Signed-off-by: Jayant Chowdhary --- camera/metadata/3.5/Android.bp | 19 ++++++++++++++++ camera/metadata/3.5/types.hal | 41 ++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 camera/metadata/3.5/Android.bp create mode 100644 camera/metadata/3.5/types.hal diff --git a/camera/metadata/3.5/Android.bp b/camera/metadata/3.5/Android.bp new file mode 100644 index 0000000000..4ebd069d3a --- /dev/null +++ b/camera/metadata/3.5/Android.bp @@ -0,0 +1,19 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.camera.metadata@3.5", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + ], + interfaces: [ + "android.hardware.camera.metadata@3.2", + "android.hardware.camera.metadata@3.3", + "android.hardware.camera.metadata@3.4", + ], + gen_java: true, +} + diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal new file mode 100644 index 0000000000..0fec947b97 --- /dev/null +++ b/camera/metadata/3.5/types.hal @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2017 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. + */ + +/* + * Autogenerated from camera metadata definitions in + * /system/media/camera/docs/metadata_definitions.xml + * *** DO NOT EDIT BY HAND *** + */ + +package android.hardware.camera.metadata@3.5; + +import android.hardware.camera.metadata@3.2; +import android.hardware.camera.metadata@3.3; +import android.hardware.camera.metadata@3.4; + +// No new metadata sections added in this revision + +/* + * Enumeration definitions for the various entries that need them + */ + +/** android.request.availableCapabilities enumeration values added since v3.4 + * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES + */ +enum CameraMetadataEnumAndroidRequestAvailableCapabilities : + @3.4::CameraMetadataEnumAndroidRequestAvailableCapabilities { + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA, +}; From 1b38536a879c6f28f1e7a63910f3d17a3a8a986b Mon Sep 17 00:00:00 2001 From: jiabin Date: Wed, 24 Jul 2019 17:33:02 -0700 Subject: [PATCH 0059/1022] Use audio containers from libaudiofoundation. It is suggested to do so according to Vector.h and SortedVector.h. At framework side, there are audio containers such as FormatVector, ChannelMaskSet, SampleRateSet to replace the usage of Vector SortedVector for audio stuff. In default hal implementation, we can use these audio containers to replace Vector and SortedVector. Bug: 135621476 Test: play/record audio Change-Id: I4d985327fb76cd06afe241860d8b592abcbfe4f2 --- audio/core/all-versions/default/Android.bp | 1 + audio/core/all-versions/default/Stream.cpp | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp index 97b4553361..328322344e 100644 --- a/audio/core/all-versions/default/Android.bp +++ b/audio/core/all-versions/default/Android.bp @@ -19,6 +19,7 @@ cc_defaults { export_include_dirs: ["include"], shared_libs: [ + "libaudiofoundation", "libbase", "libcutils", "libfmq", diff --git a/audio/core/all-versions/default/Stream.cpp b/audio/core/all-versions/default/Stream.cpp index e62f6d3b0a..2a4ef6dc31 100644 --- a/audio/core/all-versions/default/Stream.cpp +++ b/audio/core/all-versions/default/Stream.cpp @@ -26,9 +26,8 @@ #include #include #include +#include #include -#include -#include namespace android { namespace hardware { @@ -100,11 +99,11 @@ Return Stream::getSupportedSampleRates(AudioFormat format, Result result = getParam(AudioParameter::keyStreamSupportedSamplingRates, &halListValue, context); hidl_vec sampleRates; - SortedVector halSampleRates; + SampleRateSet halSampleRates; if (result == Result::OK) { halSampleRates = samplingRatesFromString(halListValue.string(), AudioParameter::valueListSeparator); - sampleRates.setToExternal(halSampleRates.editArray(), halSampleRates.size()); + sampleRates = hidl_vec(halSampleRates.begin(), halSampleRates.end()); // Legacy get_parameter does not return a status_t, thus can not advertise of failure. // Note that this method must succeed (non empty list) if the format is supported. if (sampleRates.size() == 0) { @@ -126,13 +125,14 @@ Return Stream::getSupportedChannelMasks(AudioFormat format, String8 halListValue; Result result = getParam(AudioParameter::keyStreamSupportedChannels, &halListValue, context); hidl_vec channelMasks; - SortedVector halChannelMasks; + ChannelMaskSet halChannelMasks; if (result == Result::OK) { halChannelMasks = channelMasksFromString(halListValue.string(), AudioParameter::valueListSeparator); channelMasks.resize(halChannelMasks.size()); - for (size_t i = 0; i < halChannelMasks.size(); ++i) { - channelMasks[i] = AudioChannelBitfield(halChannelMasks[i]); + size_t i = 0; + for (auto channelMask : halChannelMasks) { + channelMasks[i++] = AudioChannelBitfield(channelMask); } // Legacy get_parameter does not return a status_t, thus can not advertise of failure. // Note that this method must succeed (non empty list) if the format is supported. @@ -168,7 +168,7 @@ Return Stream::getSupportedFormats(getSupportedFormats_cb _hidl_cb) { String8 halListValue; Result result = getParam(AudioParameter::keyStreamSupportedFormats, &halListValue); hidl_vec formats; - Vector halFormats; + FormatVector halFormats; if (result == Result::OK) { halFormats = formatsFromString(halListValue.string(), AudioParameter::valueListSeparator); formats.resize(halFormats.size()); From b355bf38e64bc395df63a791804dc323ee5e836d Mon Sep 17 00:00:00 2001 From: Grace Cheng Date: Thu, 8 Aug 2019 12:50:38 -0700 Subject: [PATCH 0060/1022] Fixes typo. Test: python vhal_const_generate.py Change-Id: I9b38313424a0e486698001a72a5c58162adfa35e --- automotive/vehicle/2.0/types.hal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index 6232dd56da..955283e598 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -2478,7 +2478,7 @@ enum VehicleHvacFanDirection : int32_t { /** * FACE_AND_FLOOR = FACE | FLOOR */ - FACE_AND_FLOOR = 0X3, + FACE_AND_FLOOR = 0x3, DEFROST = 0x4, /** * DEFROST_AND_FLOOR = DEFROST | FLOOR From b183194f78f84fc65f904617111d5aabdd71f368 Mon Sep 17 00:00:00 2001 From: Grace Cheng Date: Fri, 9 Aug 2019 15:56:19 -0700 Subject: [PATCH 0061/1022] Lacking TURN_SIGNAL_STATE implementation causes emulator GUI broken. Bug: b/136215520 Test: Runs emulator GUI. Change-Id: Id23407e1e80a4a87b933d4d4f74c74d1489c7b6e --- .../vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h | 8 ++++++++ 1 file changed, 8 insertions(+) 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 8a008d3b09..932f0d86a7 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 @@ -590,6 +590,14 @@ const ConfigDeclaration kVehicleProperties[]{ }, .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}}, + {.config = + { + .prop = toInt(VehicleProperty::TURN_SIGNAL_STATE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {toInt(VehicleTurnSignal::NONE)}}}, + {.config = { .prop = toInt(VehicleProperty::IGNITION_STATE), From a689f8a65b544cbad7ced2464ed6234d2540b7fe Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Tue, 30 Jul 2019 11:35:48 -0400 Subject: [PATCH 0062/1022] Add skeleton for multihal 2.0 Creates a basic set of structures needed to implement multihal 2.0. Descriptions of each are as follows: HalProxy - Main point of contact from the sensors framework. Implements the ISensors interface and will implement several callbacks passed to sub-HALs in the future SubHal - Contains interface that sub-HALs are expected to implement in order to be loaded properly by the HalProxy. Also contains definitions for various callbacks and classes that will be fully implemented by the HalProxy. service.cpp - contains the main function that is reponsible for initializing the HalProxy and starting the thread pool that will handle communication between the HalProxy and sensors framework. Bug: 136511617 Test: compile for now. Stubbed out sub-HAL to be added in a followup CL to facilitate testing before a vendor implements the subHAL interface. Change-Id: If663159d444d721a0a65ebe49dd92e8924bbb3a3 --- sensors/2.0/multihal/Android.bp | 38 ++++ sensors/2.0/multihal/HalProxy.cpp | 182 ++++++++++++++++ sensors/2.0/multihal/HalProxy.h | 120 +++++++++++ sensors/2.0/multihal/OWNERS | 3 + sensors/2.0/multihal/SubHal.h | 202 ++++++++++++++++++ .../android.hardware.sensors@2.0-multihal.xml | 11 + ...d.hardware.sensors@2.0-service-multihal.rc | 6 + sensors/2.0/multihal/service.cpp | 41 ++++ 8 files changed, 603 insertions(+) create mode 100644 sensors/2.0/multihal/Android.bp create mode 100644 sensors/2.0/multihal/HalProxy.cpp create mode 100644 sensors/2.0/multihal/HalProxy.h create mode 100644 sensors/2.0/multihal/OWNERS create mode 100644 sensors/2.0/multihal/SubHal.h create mode 100644 sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml create mode 100644 sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc create mode 100644 sensors/2.0/multihal/service.cpp diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp new file mode 100644 index 0000000000..4dec768abf --- /dev/null +++ b/sensors/2.0/multihal/Android.bp @@ -0,0 +1,38 @@ +// +// 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. + +cc_binary { + name: "android.hardware.sensors@2.0-service.multihal", + defaults: ["hidl_defaults"], + vendor: true, + relative_install_path: "hw", + srcs: [ + "service.cpp", + "HalProxy.cpp", + ], + init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"], + shared_libs: [ + "android.hardware.sensors@1.0", + "android.hardware.sensors@2.0", + "libcutils", + "libfmq", + "libhidlbase", + "libhidltransport", + "liblog", + "libpower", + "libutils", + ], + vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"], +} diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp new file mode 100644 index 0000000000..31f8a182b8 --- /dev/null +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -0,0 +1,182 @@ +/* + * 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. + */ + +#include "HalProxy.h" + +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace implementation { + +// TODO: Use this wake lock name as the prefix to all sensors HAL wake locks acquired. +// constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP"; + +// TODO: Use the following class as a starting point for implementing the full HalProxyCallback +// along with being inspiration for how to implement the ScopedWakelock class. +/** + * Callback class used to provide the HalProxy with the index of which subHal is invoking + */ +class SensorsCallbackProxy : public ISensorsCallback { + public: + SensorsCallbackProxy(wp& halProxy, int32_t subHalIndex) + : mHalProxy(halProxy), mSubHalIndex(subHalIndex) {} + + Return onDynamicSensorsConnected( + const hidl_vec& dynamicSensorsAdded) override { + sp halProxy(mHalProxy.promote()); + if (halProxy != nullptr) { + return halProxy->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex); + } + return Return(); + } + + Return onDynamicSensorsDisconnected( + const hidl_vec& dynamicSensorHandlesRemoved) override { + sp halProxy(mHalProxy.promote()); + if (halProxy != nullptr) { + return halProxy->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, + mSubHalIndex); + } + return Return(); + } + + private: + wp& mHalProxy; + int32_t mSubHalIndex; +}; + +HalProxy::HalProxy() { + // TODO: Initialize all sub-HALs and discover sensors. +} + +HalProxy::~HalProxy() { + // TODO: Join any running threads and clean up FMQs and any other allocated + // state. +} + +Return HalProxy::getSensorsList(getSensorsList_cb /* _hidl_cb */) { + // TODO: Output sensors list created as part of HalProxy(). + return Void(); +} + +Return HalProxy::setOperationMode(OperationMode /* mode */) { + // TODO: Proxy API call to all sub-HALs and return appropriate result. + return Result::INVALID_OPERATION; +} + +Return HalProxy::activate(int32_t /* sensorHandle */, bool /* enabled */) { + // TODO: Proxy API call to appropriate sub-HAL. + return Result::INVALID_OPERATION; +} + +Return HalProxy::initialize( + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) { + Result result = Result::OK; + + // TODO: clean up sensor requests, if not already done elsewhere through a death recipient, and + // clean up any other resources that exist (FMQs, flags, threads, etc.) + + mDynamicSensorsCallback = sensorsCallback; + + // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions. + mEventQueue = + std::make_unique(eventQueueDescriptor, true /* resetPointers */); + + // Create the EventFlag that is used to signal to the framework that sensor events have been + // written to the Event FMQ + if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) { + result = Result::BAD_VALUE; + } + + // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP + // events have been successfully read and handled by the framework. + mWakeLockQueue = + std::make_unique(wakeLockDescriptor, true /* resetPointers */); + + if (!mDynamicSensorsCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) { + result = Result::BAD_VALUE; + } + + // TODO: start threads to read wake locks and process events from sub HALs. + + return result; +} + +Return HalProxy::batch(int32_t /* sensorHandle */, int64_t /* samplingPeriodNs */, + int64_t /* maxReportLatencyNs */) { + // TODO: Proxy API call to appropriate sub-HAL. + return Result::INVALID_OPERATION; +} + +Return HalProxy::flush(int32_t /* sensorHandle */) { + // TODO: Proxy API call to appropriate sub-HAL. + return Result::INVALID_OPERATION; +} + +Return HalProxy::injectSensorData(const Event& /* event */) { + // TODO: Proxy API call to appropriate sub-HAL. + return Result::INVALID_OPERATION; +} + +Return HalProxy::registerDirectChannel(const SharedMemInfo& /* mem */, + registerDirectChannel_cb _hidl_cb) { + // TODO: During init, discover the first sub-HAL in the config that has sensors with direct + // channel support, if any, and proxy the API call there. + _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */); + return Return(); +} + +Return HalProxy::unregisterDirectChannel(int32_t /* channelHandle */) { + // TODO: During init, discover the first sub-HAL in the config that has sensors with direct + // channel support, if any, and proxy the API call there. + return Result::INVALID_OPERATION; +} + +Return HalProxy::configDirectReport(int32_t /* sensorHandle */, int32_t /* channelHandle */, + RateLevel /* rate */, configDirectReport_cb _hidl_cb) { + // TODO: During init, discover the first sub-HAL in the config that has sensors with direct + // channel support, if any, and proxy the API call there. + _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */); + return Return(); +} + +Return HalProxy::debug(const hidl_handle& /* fd */, const hidl_vec& /* args */) { + // TODO: output debug information + return Return(); +} + +Return HalProxy::onDynamicSensorsConnected( + const hidl_vec& /* dynamicSensorsAdded */, int32_t /* subHalIndex */) { + // TODO: Map the SensorInfo to the global list and then invoke the framework's callback. + return Return(); +} + +Return HalProxy::onDynamicSensorsDisconnected( + const hidl_vec& /* dynamicSensorHandlesRemoved */, int32_t /* subHalIndex */) { + // TODO: Unmap the SensorInfo from the global list and then invoke the framework's callback. + return Return(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android diff --git a/sensors/2.0/multihal/HalProxy.h b/sensors/2.0/multihal/HalProxy.h new file mode 100644 index 0000000000..b9855a6ac5 --- /dev/null +++ b/sensors/2.0/multihal/HalProxy.h @@ -0,0 +1,120 @@ +/* + * 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. + */ + +#pragma once + +#include "SubHal.h" + +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::EventFlag; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::MessageQueue; +using ::android::hardware::MQDescriptor; +using ::android::hardware::Return; +using ::android::hardware::Void; + +struct HalProxy : public ISensors { + using Event = ::android::hardware::sensors::V1_0::Event; + using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; + using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; + using Result = ::android::hardware::sensors::V1_0::Result; + using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; + + HalProxy(); + ~HalProxy(); + + // Methods from ::android::hardware::sensors::V2_0::ISensors follow. + Return getSensorsList(getSensorsList_cb _hidl_cb) override; + + Return setOperationMode(OperationMode mode) override; + + Return activate(int32_t sensorHandle, bool enabled) override; + + Return initialize( + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) override; + + Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) override; + + Return flush(int32_t sensorHandle) override; + + Return injectSensorData(const Event& event) override; + + Return registerDirectChannel(const SharedMemInfo& mem, + registerDirectChannel_cb _hidl_cb) override; + + Return unregisterDirectChannel(int32_t channelHandle) override; + + Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + configDirectReport_cb _hidl_cb) override; + + Return debug(const hidl_handle& fd, const hidl_vec& args) override; + + // Below methods from ::android::hardware::sensors::V2_0::ISensorsCaback with a minor change + // to pass in the sub-HAL index. While the above methods are invoked from the sensors framework + // via the binder, these methods are invoked from a callback provided to sub-HALs inside the + // same process as the HalProxy, but potentially running on different threads. + Return onDynamicSensorsConnected(const hidl_vec& dynamicSensorsAdded, + int32_t subHalIndex); + + Return onDynamicSensorsDisconnected(const hidl_vec& dynamicSensorHandlesRemoved, + int32_t subHalIndex); + + private: + using EventMessageQueue = MessageQueue; + using WakeLockMessageQueue = MessageQueue; + + /** + * The Event FMQ where sensor events are written + */ + std::unique_ptr mEventQueue; + + /** + * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events + */ + std::unique_ptr mWakeLockQueue; + + /** + * Event Flag to signal to the framework when sensor events are available to be read + */ + EventFlag* mEventQueueFlag; + + /** + * Callback to the sensors framework to inform it that new sensors have been added or removed. + */ + sp mDynamicSensorsCallback; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android diff --git a/sensors/2.0/multihal/OWNERS b/sensors/2.0/multihal/OWNERS new file mode 100644 index 0000000000..e9556700d6 --- /dev/null +++ b/sensors/2.0/multihal/OWNERS @@ -0,0 +1,3 @@ +arthuri@google.com +bduddie@google.com +stange@google.com \ No newline at end of file diff --git a/sensors/2.0/multihal/SubHal.h b/sensors/2.0/multihal/SubHal.h new file mode 100644 index 0000000000..152f91d96c --- /dev/null +++ b/sensors/2.0/multihal/SubHal.h @@ -0,0 +1,202 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include + +using ::android::hardware::sensors::V1_0::Event; +using ::android::hardware::sensors::V1_0::Result; +using ::android::hardware::sensors::V1_0::SensorInfo; + +// Indicates the current version of the multiHAL interface formatted as (HAL major version) << 24 | +// (HAL minor version) << 16 | (multiHAL version) +#define SUB_HAL_2_0_VERSION 0x02000000 + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace implementation { + +/** + * Wrapper around wake lock acquisition functions (acquire/release_wake_lock) that provides a + * RAII-style mechanism for keeping a wake lock held for the duration of a scoped block. + * When a ScopedWakelock is created, it increments the reference count stored in the HalProxy + * for the sub-HALs specific wake lock, acquiring the wake lock if necessary. When the object goes + * out of scope, the ref count is decremented, potentially releasing the wake lock if no other + * references to the wake lock exist. + * + * This class is allocated through the createScopedWakelock callback inside the IHalProxyCallback + * provided to sub-HALs during initialization and should be used for all wake lock acquisition + * inside of the sub-HAL to ensure wake locks are not held indefinitely. + * + * The most prevalent use case for this class will be for posting events to the framework through + * the postEvents HalProxy callback. The expectation is that sub-HALs will create this + * ScopedWakelock through the createScopedWakelock upon receiving a sensor events. The lock boolean + * provided to createScopedWakelock will be set the according to whether the sensor events are + * from wakeup sensors. Then, the sub-HAL will perform any processing necessary before invoking the + * postEvents callback passing in the previously created ScopedWakelock. At this point, ownership + * of the object will be passed to the HalProxy that will then be responsible for ensuring any + * wake locks continue to be held, if necessary. + */ +class ScopedWakelock { + public: + ScopedWakelock(ScopedWakelock&&) = default; + ScopedWakelock& operator=(ScopedWakelock&&) = default; + virtual ~ScopedWakelock() { mLocked = false; }; + + bool isLocked() const { return mLocked; } + + protected: + bool mLocked; + + private: + // TODO: Mark HalProxy's subclass of ScopedWakelock as a friend so that it can be initialized. + ScopedWakelock(); + ScopedWakelock(const ScopedWakelock&) = delete; + ScopedWakelock& operator=(const ScopedWakelock&) = delete; +}; + +/** + * Interface that contains several callbacks into the HalProxy class to communicate dynamic sensor + * changes and sensor events to the framework and acquire wake locks. The HalProxy will ensure + * callbacks occurring at the same time from multiple sub-HALs are synchronized in a safe, efficient + * manner. + */ +class IHalProxyCallback : public ISensorsCallback { + public: + /** + * Thread-safe callback used to post events to the HalProxy. Sub-HALs should invoke this + * whenever new sensor events need to be delivered to the sensors framework. Once invoked, the + * HalProxy will attempt to send events to the sensors framework using a blocking write with a + * 5 second timeout. This write may be done asynchronously if the queue used to communicate + * with the framework is full to avoid blocking sub-HALs for the length of the timeout. If the + * write fails, the events will be dropped and any wake locks held will be released. + * + * The provided ScopedWakelock must be locked if the events are from wakeup sensors. If it's + * not locked accordingly, the HalProxy will crash as this indicates the sub-HAL isn't compliant + * with the sensors HAL 2.0 specification. Additionally, since ScopedWakelock isn't copyable, + * the HalProxy will take ownership of the wake lock given when this method is invoked. Once the + * method returns, the HalProxy will handle holding the wake lock, if necessary, until the + * framework has successfully processed any wakeup events. + * + * No return type is used for this callback to avoid sub-HALs trying to resend events when + * writes fail. Writes should only fail when the framework is under inordinate stress which will + * likely result in a framework restart so retrying will likely only result in overloading the + * HalProxy. Sub-HALs should always assume that the write was a success and perform any + * necessary cleanup. Additionally, the HalProxy will ensure it logs any errors (through ADB and + * bug reports) it encounters during delivery to ensure it's obvious that a failure occurred. + * + * @param events the events that should be sent to the sensors framework + * @param wakelock ScopedWakelock that should be locked to send events from wake sensors and + * unlocked otherwise. + */ + virtual void postEvents(const std::vector& events, ScopedWakelock wakelock) = 0; + + /** + * Initializes a ScopedWakelock on the stack that, when locked, will increment the reference + * count for the sub-HAL's wake lock managed inside the HalProxy. See the ScopedWakelock class + * definition for how it should be used. + * + * @param lock whether the ScopedWakelock should be locked before it's returned. + * @return the created ScopedWakelock + */ + virtual ScopedWakelock createScopedWakelock(bool lock) = 0; +}; + +/** + * ISensorsSubHal is an interface that sub-HALs must implement in order to be compliant with + * multihal 2.0 and in order for the HalProxy to successfully load and communicate with the sub-HAL. + * + * Any vendor wishing to implement this interface and support multihal 2.0 will need to create a + * dynamic library that exposes sensorsHalGetSubHal (defined below). This library will be loaded by + * the HalProxy when the sensors HAL is initialized and then the HalProxy will retrieve the vendor's + * implementation of sensorsHalGetSubHal. + * + * With the exception of the initialize method, ISensorsSubHal will implement the ISensors.hal spec. + * Any sensor handles given to the HalProxy, either through getSensorsList() or the + * onDynamicSensors(Dis)Connected callbacks, will be translated to avoid clashing with other sub-HAL + * handles. To achieve this, the HalProxy will use the upper byte to store the sub-HAL index and + * sub-HALs can continue to use the lower 3 bytes of the handle. + */ +class ISensorsSubHal : public ISensors { + // The ISensors version of initialize isn't used for multihal. Instead, sub-HALs must implement + // the version below to allow communciation logic to centralized in the HalProxy + Return initialize( + const ::android::hardware::MQDescriptorSync& /* eventQueueDescriptor */, + const ::android::hardware::MQDescriptorSync& /* wakeLockDescriptor */, + const sp& /* sensorsCallback */) final { + return Result::INVALID_OPERATION; + } + + /** + * Method defined in ::android::hidl::base::V1_0::IBase. + * + * This method should write debug information to hidl_handle that is useful for debugging + * issues. Suggestions include: + * - Sensor info including handle values and any other state available in the SensorInfo class + * - List of active sensors and their current sampling period and reporting latency + * - Information about pending flush requests + * - Current operating mode + * - Currently registered direct channel info + * - A history of any of the above + */ + virtual Return debug(const hidl_handle& fd, const hidl_vec& args) = 0; + + /** + * @return A human-readable name for use in wake locks and logging. + */ + virtual const std::string& getName() = 0; + + /** + * First method invoked on the sub-HAL after it's allocated through sensorsHalGetSubHal() by the + * HalProxy. Sub-HALs should use this to initialize any state and retain the callback given in + * order to communicate with the HalProxy. + * + * @param halProxyCallback callback used to inform the HalProxy when a dynamic sensor's state + * changes, new sensor events should be sent to the framework, and when a new ScopedWakelock + * should be created. + * @return result OK on success + */ + virtual Return initialize(const sp& halProxyCallback) = 0; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android + +using ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal; + +/** + * Function that must be exported so the HalProxy class can invoke it on the sub-HAL dynamic + * library. This function will only be invoked once at initialization time. + * + * NOTE: The supported sensors HAL version must match SUB_HAL_2_0_VERSION exactly or the HalProxy + * will fail to initialize. + * + * @param uint32_t when this function returns, this parameter must contain the HAL version that + * this sub-HAL supports. To support this version of multi-HAL, this must be set to + * SUB_HAL_2_0_VERSION. + * @return A statically allocated, valid ISensorsSubHal implementation. + */ +__attribute__((visibility("default"))) extern "C" ISensorsSubHal* sensorsHalGetSubHal( + uint32_t* version); diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml b/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml new file mode 100644 index 0000000000..a771100ecc --- /dev/null +++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml @@ -0,0 +1,11 @@ + + + android.hardware.sensors + hwbinder + 2.0 + + ISensors + multihal + + + diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc new file mode 100644 index 0000000000..167168919a --- /dev/null +++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc @@ -0,0 +1,6 @@ +service vendor.sensors-hal-2-0-multihal /vendor/bin/hw/android.hardware.sensors@2.0-service.multihal + class hal + user system + group system + capabilities BLOCK_SUSPEND + rlimit rtprio 10 10 diff --git a/sensors/2.0/multihal/service.cpp b/sensors/2.0/multihal/service.cpp new file mode 100644 index 0000000000..995cf3cbe0 --- /dev/null +++ b/sensors/2.0/multihal/service.cpp @@ -0,0 +1,41 @@ +/* + * 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 "android.hardware.sensors@2.0-service" + +#include +#include +#include +#include +#include "HalProxy.h" + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::sensors::V2_0::ISensors; +using android::hardware::sensors::V2_0::implementation::HalProxy; + +int main(int /* argc */, char** /* argv */) { + configureRpcThreadpool(1, true); + + android::sp halProxy = new HalProxy(); + if (halProxy->registerAsService() != ::android::OK) { + ALOGE("Failed to register Sensors HAL instance"); + return -1; + } + + joinRpcThreadpool(); + return 1; // joinRpcThreadpool shouldn't exit +} From c34e6683b1ec0ccd09738f6d8a2206e75dd16e3a Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Fri, 9 Aug 2019 11:24:17 -0400 Subject: [PATCH 0063/1022] Add a sub-HAL implementation for testing multi-HAL Creates a fake sub-HAL using the default implementation for sensors HAL 2.0 with some small modifications to support the multi-HAL interface. This sub-HAL can be configured to support two different sets of sensors making it easier to build and load two different sub-HAL implementations onto device and verify the multihal implementation works. Bug: 136511617 Test: compile only. Once multihal can load in sub-HALs, then this can be accurately tested. Change-Id: I9b136506bdbc8a3b196fd363748bddfcdd564daf --- sensors/2.0/multihal/Android.bp | 9 + sensors/2.0/multihal/{ => include}/SubHal.h | 2 +- sensors/2.0/multihal/testing/Android.bp | 55 +++ sensors/2.0/multihal/testing/README | 19 + sensors/2.0/multihal/testing/Sensor.cpp | 372 ++++++++++++++++++ sensors/2.0/multihal/testing/Sensor.h | 146 +++++++ .../2.0/multihal/testing/SensorsSubHal.cpp | 179 +++++++++ sensors/2.0/multihal/testing/SensorsSubHal.h | 115 ++++++ 8 files changed, 896 insertions(+), 1 deletion(-) rename sensors/2.0/multihal/{ => include}/SubHal.h (99%) create mode 100644 sensors/2.0/multihal/testing/Android.bp create mode 100644 sensors/2.0/multihal/testing/README create mode 100644 sensors/2.0/multihal/testing/Sensor.cpp create mode 100644 sensors/2.0/multihal/testing/Sensor.h create mode 100644 sensors/2.0/multihal/testing/SensorsSubHal.cpp create mode 100644 sensors/2.0/multihal/testing/SensorsSubHal.h diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp index 4dec768abf..f0b33e42a1 100644 --- a/sensors/2.0/multihal/Android.bp +++ b/sensors/2.0/multihal/Android.bp @@ -23,6 +23,9 @@ cc_binary { "HalProxy.cpp", ], init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"], + header_libs: [ + "android.hardware.sensors@2.0-subhal.header", + ], shared_libs: [ "android.hardware.sensors@1.0", "android.hardware.sensors@2.0", @@ -36,3 +39,9 @@ cc_binary { ], vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"], } + +cc_library_headers { + name: "android.hardware.sensors@2.0-subhal.header", + vendor: true, + export_include_dirs: ["include"], +} \ No newline at end of file diff --git a/sensors/2.0/multihal/SubHal.h b/sensors/2.0/multihal/include/SubHal.h similarity index 99% rename from sensors/2.0/multihal/SubHal.h rename to sensors/2.0/multihal/include/SubHal.h index 152f91d96c..75e93a18b5 100644 --- a/sensors/2.0/multihal/SubHal.h +++ b/sensors/2.0/multihal/include/SubHal.h @@ -163,7 +163,7 @@ class ISensorsSubHal : public ISensors { /** * @return A human-readable name for use in wake locks and logging. */ - virtual const std::string& getName() = 0; + virtual const std::string getName() = 0; /** * First method invoked on the sub-HAL after it's allocated through sensorsHalGetSubHal() by the diff --git a/sensors/2.0/multihal/testing/Android.bp b/sensors/2.0/multihal/testing/Android.bp new file mode 100644 index 0000000000..3dedbd69cf --- /dev/null +++ b/sensors/2.0/multihal/testing/Android.bp @@ -0,0 +1,55 @@ +// +// 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. + +cc_defaults { + name: "android.hardware.sensors@2.0-fakesubhal-defaults", + vendor: true, + srcs: [ + "Sensor.cpp", + "SensorsSubHal.cpp", + ], + header_libs: [ + "android.hardware.sensors@2.0-subhal.header", + ], + shared_libs: [ + "android.hardware.sensors@1.0", + "android.hardware.sensors@2.0", + "libcutils", + "libfmq", + "libhidlbase", + "libhidltransport", + "liblog", + "libpower", + "libutils", + ], +} + +cc_library { + name: "android.hardware.sensors@2.0-fakesubhal-config1", + defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"], + cflags: [ + "-DSUPPORT_CONTINUOUS_SENSORS", + "-DSUB_HAL_NAME=\"FakeSubHal-Continuous\"", + ], +} + +cc_library { + name: "android.hardware.sensors@2.0-fakesubhal-config2", + defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"], + cflags: [ + "-DSUPPORT_ON_CHANGE_SENSORS", + "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"", + ], +} \ No newline at end of file diff --git a/sensors/2.0/multihal/testing/README b/sensors/2.0/multihal/testing/README new file mode 100644 index 0000000000..ddcc58452f --- /dev/null +++ b/sensors/2.0/multihal/testing/README @@ -0,0 +1,19 @@ +This directory contains a modified version of the default implementation +provided for sensors HAL 2.0 to support multi-HAL 2.0. It should be used as a +means to verify the multi-HAL 2.0 implementation can successfully load and +interact with sub-HALs. + +This sub-HAL implementation has two macros that can be used to configure support +for different sets of sensors. One "SUPPORT_CONTINUOUS_SENSORS", enables +support for continuous sensors like accel, and gyro whereas the other +"SUPPORT_ON_CHANGE_SENSORS" enables support for on change sensors like the +light and proximity sensor. A build target is defined for each of these macros, +but more targets could be added to support both in one sub-HAL or none at all, +if necessary. + +When built, the library will be written to +out/target/product//vendor/lib64/android.hardware.sensors@2.0-fakesubhal.so + +Take this .so and place it where the multi-HAL config will cause the HalProxy to +look and then restart the system server with adb shell stop / adb shell start +to cause the multi-HAL to restart and attempt to load in the sub-HAL. diff --git a/sensors/2.0/multihal/testing/Sensor.cpp b/sensors/2.0/multihal/testing/Sensor.cpp new file mode 100644 index 0000000000..e095efe0cf --- /dev/null +++ b/sensors/2.0/multihal/testing/Sensor.cpp @@ -0,0 +1,372 @@ +/* + * 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. + */ + +#include "Sensor.h" + +#include + +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace subhal { +namespace implementation { + +using ::android::hardware::sensors::V1_0::MetaDataEventType; +using ::android::hardware::sensors::V1_0::SensorFlagBits; +using ::android::hardware::sensors::V1_0::SensorStatus; + +static constexpr float kDefaultMaxDelayUs = 10 * 1000 * 1000; + +Sensor::Sensor(ISensorsEventCallback* callback) + : mIsEnabled(false), + mSamplingPeriodNs(0), + mLastSampleTimeNs(0), + mCallback(callback), + mMode(OperationMode::NORMAL) { + mRunThread = std::thread(startThread, this); +} + +Sensor::~Sensor() { + std::unique_lock lock(mRunMutex); + mStopThread = true; + mIsEnabled = false; + mWaitCV.notify_all(); + lock.release(); + mRunThread.join(); +} + +const SensorInfo& Sensor::getSensorInfo() const { + return mSensorInfo; +} + +void Sensor::batch(int32_t samplingPeriodNs) { + samplingPeriodNs = + std::clamp(samplingPeriodNs, mSensorInfo.minDelay * 1000, mSensorInfo.maxDelay * 1000); + + if (mSamplingPeriodNs != samplingPeriodNs) { + mSamplingPeriodNs = samplingPeriodNs; + // Wake up the 'run' thread to check if a new event should be generated now + mWaitCV.notify_all(); + } +} + +void Sensor::activate(bool enable) { + if (mIsEnabled != enable) { + std::unique_lock lock(mRunMutex); + mIsEnabled = enable; + mWaitCV.notify_all(); + } +} + +Result Sensor::flush() { + // Only generate a flush complete event if the sensor is enabled and if the sensor is not a + // one-shot sensor. + if (!mIsEnabled || (mSensorInfo.flags & static_cast(SensorFlagBits::ONE_SHOT_MODE))) { + return Result::BAD_VALUE; + } + + // Note: If a sensor supports batching, write all of the currently batched events for the sensor + // to the Event FMQ prior to writing the flush complete event. + Event ev; + ev.sensorHandle = mSensorInfo.sensorHandle; + ev.sensorType = SensorType::META_DATA; + ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE; + std::vector evs{ev}; + mCallback->postEvents(evs, isWakeUpSensor()); + + return Result::OK; +} + +void Sensor::startThread(Sensor* sensor) { + sensor->run(); +} + +void Sensor::run() { + std::unique_lock runLock(mRunMutex); + constexpr int64_t kNanosecondsInSeconds = 1000 * 1000 * 1000; + + while (!mStopThread) { + if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) { + mWaitCV.wait(runLock, [&] { + return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread); + }); + } else { + timespec curTime; + clock_gettime(CLOCK_REALTIME, &curTime); + int64_t now = (curTime.tv_sec * kNanosecondsInSeconds) + curTime.tv_nsec; + int64_t nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs; + + if (now >= nextSampleTime) { + mLastSampleTimeNs = now; + nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs; + mCallback->postEvents(readEvents(), isWakeUpSensor()); + } + + mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now)); + } + } +} + +bool Sensor::isWakeUpSensor() { + return mSensorInfo.flags & static_cast(SensorFlagBits::WAKE_UP); +} + +std::vector Sensor::readEvents() { + std::vector events; + Event event; + event.sensorHandle = mSensorInfo.sensorHandle; + event.sensorType = mSensorInfo.type; + event.timestamp = ::android::elapsedRealtimeNano(); + event.u.vec3.x = 0; + event.u.vec3.y = 0; + event.u.vec3.z = 0; + event.u.vec3.status = SensorStatus::ACCURACY_HIGH; + events.push_back(event); + return events; +} + +void Sensor::setOperationMode(OperationMode mode) { + if (mMode != mode) { + std::unique_lock lock(mRunMutex); + mMode = mode; + mWaitCV.notify_all(); + } +} + +bool Sensor::supportsDataInjection() const { + return mSensorInfo.flags & static_cast(SensorFlagBits::DATA_INJECTION); +} + +Result Sensor::injectEvent(const Event& event) { + Result result = Result::OK; + if (event.sensorType == SensorType::ADDITIONAL_INFO) { + // When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation + // environment data into the device. + } else if (!supportsDataInjection()) { + result = Result::INVALID_OPERATION; + } else if (mMode == OperationMode::DATA_INJECTION) { + mCallback->postEvents(std::vector{event}, isWakeUpSensor()); + } else { + result = Result::BAD_VALUE; + } + return result; +} + +OnChangeSensor::OnChangeSensor(ISensorsEventCallback* callback) + : Sensor(callback), mPreviousEventSet(false) {} + +void OnChangeSensor::activate(bool enable) { + Sensor::activate(enable); + if (!enable) { + mPreviousEventSet = false; + } +} + +std::vector OnChangeSensor::readEvents() { + std::vector events = Sensor::readEvents(); + std::vector outputEvents; + + for (auto iter = events.begin(); iter != events.end(); ++iter) { + Event ev = *iter; + if (ev.u.vec3 != mPreviousEvent.u.vec3 || !mPreviousEventSet) { + outputEvents.push_back(ev); + mPreviousEvent = ev; + mPreviousEventSet = true; + } + } + return outputEvents; +} + +AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Accel Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::ACCELEROMETER; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 78.4f; // +/- 8g + mSensorInfo.resolution = 1.52e-5; + mSensorInfo.power = 0.001f; // mA + mSensorInfo.minDelay = 20 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = static_cast(SensorFlagBits::DATA_INJECTION); +}; + +PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : Sensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Pressure Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::PRESSURE; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 1100.0f; // hPa + mSensorInfo.resolution = 0.005f; // hPa + mSensorInfo.power = 0.001f; // mA + mSensorInfo.minDelay = 100 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = 0; +}; + +MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : Sensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Magnetic Field Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::MAGNETIC_FIELD; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 1300.0f; + mSensorInfo.resolution = 0.01f; + mSensorInfo.power = 0.001f; // mA + mSensorInfo.minDelay = 20 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = 0; +}; + +LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : OnChangeSensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Light Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::LIGHT; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 43000.0f; + mSensorInfo.resolution = 10.0f; + mSensorInfo.power = 0.001f; // mA + mSensorInfo.minDelay = 200 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = static_cast(SensorFlagBits::ON_CHANGE_MODE); +}; + +ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : OnChangeSensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Proximity Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::PROXIMITY; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 5.0f; + mSensorInfo.resolution = 1.0f; + mSensorInfo.power = 0.012f; // mA + mSensorInfo.minDelay = 200 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = + static_cast(SensorFlagBits::ON_CHANGE_MODE | SensorFlagBits::WAKE_UP); +}; + +GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Gyro Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::GYROSCOPE; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f; + mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f); + mSensorInfo.power = 0.001f; + mSensorInfo.minDelay = 2.5f * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = 0; +}; + +AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : OnChangeSensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Ambient Temp Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 80.0f; + mSensorInfo.resolution = 0.01f; + mSensorInfo.power = 0.001f; + mSensorInfo.minDelay = 40 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = static_cast(SensorFlagBits::ON_CHANGE_MODE); +}; + +DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : OnChangeSensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Device Temp Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::TEMPERATURE; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 80.0f; + mSensorInfo.resolution = 0.01f; + mSensorInfo.power = 0.001f; + mSensorInfo.minDelay = 40 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = static_cast(SensorFlagBits::ON_CHANGE_MODE); +} + +RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle, + ISensorsEventCallback* callback) + : OnChangeSensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Relative Humidity Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::RELATIVE_HUMIDITY; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 100.0f; + mSensorInfo.resolution = 0.1f; + mSensorInfo.power = 0.001f; + mSensorInfo.minDelay = 40 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = static_cast(SensorFlagBits::ON_CHANGE_MODE); +} + +} // namespace implementation +} // namespace subhal +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android diff --git a/sensors/2.0/multihal/testing/Sensor.h b/sensors/2.0/multihal/testing/Sensor.h new file mode 100644 index 0000000000..980ea54559 --- /dev/null +++ b/sensors/2.0/multihal/testing/Sensor.h @@ -0,0 +1,146 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include + +using ::android::hardware::sensors::V1_0::Event; +using ::android::hardware::sensors::V1_0::OperationMode; +using ::android::hardware::sensors::V1_0::Result; +using ::android::hardware::sensors::V1_0::SensorInfo; +using ::android::hardware::sensors::V1_0::SensorType; + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace subhal { +namespace implementation { + +class ISensorsEventCallback { + public: + virtual ~ISensorsEventCallback(){}; + virtual void postEvents(const std::vector& events, bool wakeup) = 0; +}; + +class Sensor { + public: + Sensor(ISensorsEventCallback* callback); + virtual ~Sensor(); + + const SensorInfo& getSensorInfo() const; + void batch(int32_t samplingPeriodNs); + virtual void activate(bool enable); + Result flush(); + + void setOperationMode(OperationMode mode); + bool supportsDataInjection() const; + Result injectEvent(const Event& event); + + protected: + void run(); + virtual std::vector readEvents(); + static void startThread(Sensor* sensor); + + bool isWakeUpSensor(); + + bool mIsEnabled; + int64_t mSamplingPeriodNs; + int64_t mLastSampleTimeNs; + SensorInfo mSensorInfo; + + std::atomic_bool mStopThread; + std::condition_variable mWaitCV; + std::mutex mRunMutex; + std::thread mRunThread; + + ISensorsEventCallback* mCallback; + + OperationMode mMode; +}; + +class OnChangeSensor : public Sensor { + public: + OnChangeSensor(ISensorsEventCallback* callback); + + virtual void activate(bool enable) override; + + protected: + virtual std::vector readEvents() override; + + protected: + Event mPreviousEvent; + bool mPreviousEventSet; +}; + +class AccelSensor : public Sensor { + public: + AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class GyroSensor : public Sensor { + public: + GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class AmbientTempSensor : public OnChangeSensor { + public: + AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class DeviceTempSensor : public OnChangeSensor { + public: + DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class PressureSensor : public Sensor { + public: + PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class MagnetometerSensor : public Sensor { + public: + MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class LightSensor : public OnChangeSensor { + public: + LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class ProximitySensor : public OnChangeSensor { + public: + ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class RelativeHumiditySensor : public OnChangeSensor { + public: + RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +} // namespace implementation +} // namespace subhal +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android diff --git a/sensors/2.0/multihal/testing/SensorsSubHal.cpp b/sensors/2.0/multihal/testing/SensorsSubHal.cpp new file mode 100644 index 0000000000..8d459824dc --- /dev/null +++ b/sensors/2.0/multihal/testing/SensorsSubHal.cpp @@ -0,0 +1,179 @@ +/* + * 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. + */ + +#include "SensorsSubHal.h" + +#include +#include + +ISensorsSubHal* sensorsHalGetSubHal(uint32_t* version) { + static ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal subHal; + *version = SUB_HAL_2_0_VERSION; + return &subHal; +} + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace subhal { +namespace implementation { + +using ::android::hardware::Void; +using ::android::hardware::sensors::V1_0::Event; +using ::android::hardware::sensors::V1_0::OperationMode; +using ::android::hardware::sensors::V1_0::RateLevel; +using ::android::hardware::sensors::V1_0::Result; +using ::android::hardware::sensors::V1_0::SharedMemInfo; +using ::android::hardware::sensors::V2_0::SensorTimeout; +using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; +using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock; + +SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) { +#ifdef SUPPORT_CONTINUOUS_SENSORS + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); +#endif // SUPPORT_CONTINUOUS_SENSORS + +#ifdef SUPPORT_ON_CHANGE_SENSORS + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); +#endif // SUPPORT_ON_CHANGE_SENSORS +} + +// Methods from ::android::hardware::sensors::V2_0::ISensors follow. +Return SensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) { + std::vector sensors; + for (const auto& sensor : mSensors) { + sensors.push_back(sensor.second->getSensorInfo()); + } + + _hidl_cb(sensors); + return Void(); +} + +Return SensorsSubHal::setOperationMode(OperationMode mode) { + for (auto sensor : mSensors) { + sensor.second->setOperationMode(mode); + } + return Result::OK; +} + +Return SensorsSubHal::activate(int32_t sensorHandle, bool enabled) { + auto sensor = mSensors.find(sensorHandle); + if (sensor != mSensors.end()) { + sensor->second->activate(enabled); + return Result::OK; + } + return Result::BAD_VALUE; +} + +Return SensorsSubHal::batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t /* maxReportLatencyNs */) { + auto sensor = mSensors.find(sensorHandle); + if (sensor != mSensors.end()) { + sensor->second->batch(samplingPeriodNs); + return Result::OK; + } + return Result::BAD_VALUE; +} + +Return SensorsSubHal::flush(int32_t sensorHandle) { + auto sensor = mSensors.find(sensorHandle); + if (sensor != mSensors.end()) { + return sensor->second->flush(); + } + return Result::BAD_VALUE; +} + +Return SensorsSubHal::injectSensorData(const Event& event) { + auto sensor = mSensors.find(event.sensorHandle); + if (sensor != mSensors.end()) { + return sensor->second->injectEvent(event); + } + + return Result::BAD_VALUE; +} + +Return SensorsSubHal::registerDirectChannel(const SharedMemInfo& /* mem */, + registerDirectChannel_cb _hidl_cb) { + _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */); + return Return(); +} + +Return SensorsSubHal::unregisterDirectChannel(int32_t /* channelHandle */) { + return Result::INVALID_OPERATION; +} + +Return SensorsSubHal::configDirectReport(int32_t /* sensorHandle */, + int32_t /* channelHandle */, RateLevel /* rate */, + configDirectReport_cb _hidl_cb) { + _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */); + return Return(); +} + +Return SensorsSubHal::debug(const hidl_handle& fd, const hidl_vec& args) { + if (fd.getNativeHandle() == nullptr || fd->numFds < 1) { + ALOGE("%s: missing fd for writing", __FUNCTION__); + return Void(); + } + + FILE* out = fdopen(dup(fd->data[0]), "w"); + + if (args.size() != 0) { + fprintf(out, + "Note: sub-HAL %s currently does not support args. Input arguments are " + "ignored.\n", + getName().c_str()); + } + + std::ostringstream stream; + stream << "Available sensors:" << std::endl; + for (auto sensor : mSensors) { + SensorInfo info = sensor.second->getSensorInfo(); + stream << "Name: " << info.name << std::endl; + stream << "Min delay: " << info.minDelay << std::endl; + stream << "Flags: " << info.flags << std::endl; + } + stream << std::endl; + + fprintf(out, "%s", stream.str().c_str()); + + fclose(out); + return Return(); +} + +Return SensorsSubHal::initialize(const sp& halProxyCallback) { + mCallback = halProxyCallback; + return Result::OK; +} + +void SensorsSubHal::postEvents(const std::vector& events, bool wakeup) { + ScopedWakelock wakelock = mCallback->createScopedWakelock(wakeup); + mCallback->postEvents(events, std::move(wakelock)); +} + +} // namespace implementation +} // namespace subhal +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android diff --git a/sensors/2.0/multihal/testing/SensorsSubHal.h b/sensors/2.0/multihal/testing/SensorsSubHal.h new file mode 100644 index 0000000000..93009d5833 --- /dev/null +++ b/sensors/2.0/multihal/testing/SensorsSubHal.h @@ -0,0 +1,115 @@ +/* + * 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. + */ + +#pragma once + +#include "SubHal.h" + +#include "Sensor.h" + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace subhal { +namespace implementation { + +using ::android::hardware::sensors::V2_0::implementation::IHalProxyCallback; + +/** + * Implementation of a ISensorsSubHal that can be used to test the implementation of multihal 2.0. + * See the README file for more details on how this class can be used for testing. + */ +class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { + using Event = ::android::hardware::sensors::V1_0::Event; + using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; + using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; + using Result = ::android::hardware::sensors::V1_0::Result; + using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; + + public: + SensorsSubHal(); + + // Methods from ::android::hardware::sensors::V2_0::ISensors follow. + Return getSensorsList(getSensorsList_cb _hidl_cb) override; + + Return setOperationMode(OperationMode mode) override; + + Return activate(int32_t sensorHandle, bool enabled) override; + + Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) override; + + Return flush(int32_t sensorHandle) override; + + Return injectSensorData(const Event& event) override; + + Return registerDirectChannel(const SharedMemInfo& mem, + registerDirectChannel_cb _hidl_cb) override; + + Return unregisterDirectChannel(int32_t channelHandle) override; + + Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + configDirectReport_cb _hidl_cb) override; + + Return debug(const hidl_handle& fd, const hidl_vec& args) override; + + // Methods from ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal follow. + const std::string getName() override { +#ifdef SUB_HAL_NAME + return SUB_HAL_NAME; +#else // SUB_HAL_NAME + return "FakeSubHal"; +#endif // SUB_HAL_NAME + } + + Return initialize(const sp& halProxyCallback) override; + + // Method from ISensorsEventCallback. + void postEvents(const std::vector& events, bool wakeup) override; + + private: + template + void AddSensor() { + std::shared_ptr sensor = + std::make_shared(mNextHandle++ /* sensorHandle */, this /* callback */); + mSensors[sensor->getSensorInfo().sensorHandle] = sensor; + } + + /** + * Callback used to communicate to the HalProxy when dynamic sensors are connected / + * disconnected, sensor events need to be sent to the framework, and when a wakelock should be + * acquired. + */ + sp mCallback; + + /** + * A map of the available sensors + */ + std::map> mSensors; + + /** + * The next available sensor handle + */ + int32_t mNextHandle; +}; + +} // namespace implementation +} // namespace subhal +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android From a9bd7a4e4f96cb04b4945d61946e43f3c9af3ee4 Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Wed, 31 Jul 2019 12:09:58 -0700 Subject: [PATCH 0064/1022] Camera: Timing requirement between notify and processCaptureResult For physical sub-camera result error, require the notify() call is made before the final processCaptureResult. Test: Updated VTS test passes Bug: 138727686 Change-Id: Ifba247bc1aa35ecdba651ea888dd26902a31647e --- camera/device/3.5/types.hal | 3 +- .../VtsHalCameraProviderV2_4TargetTest.cpp | 123 +++++++++++++----- current.txt | 1 + 3 files changed, 97 insertions(+), 30 deletions(-) diff --git a/camera/device/3.5/types.hal b/camera/device/3.5/types.hal index 6d861e2e72..38493b4f72 100644 --- a/camera/device/3.5/types.hal +++ b/camera/device/3.5/types.hal @@ -23,7 +23,8 @@ import @3.2::CameraBlobId; /** * If the result metadata cannot be produced for a physical camera device part of a logical * multi-camera, then HAL must invoke the notification callback and pass a message with ERROR_RESULT - * code and errorStreamId that contains the stream id associated with that physical device. + * code and errorStreamId that contains the stream id associated with that physical device. Such + * callback must be made before the final processCaptureResult() call for the corresponding request. * The behavior during absent result metadata remains unchanged for a logical or a non-logical * camera device and the errorStreamId must be set to -1. */ diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index a5369e7b8d..e0d41bacf5 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -622,7 +622,7 @@ public: Return returnStreamBuffers(const hidl_vec& buffers) override; - void setCurrentStreamConfig(const hidl_vec& streams, + void setCurrentStreamConfig(const hidl_vec& streams, const hidl_vec& halStreams); void waitForBuffersReturned(); @@ -639,7 +639,7 @@ public: /* members for requestStreamBuffers() and returnStreamBuffers()*/ std::mutex mLock; // protecting members below bool mUseHalBufManager = false; - hidl_vec mStreams; + hidl_vec mStreams; hidl_vec mHalStreams; uint64_t mNextBufferId = 1; using OutstandingBuffers = std::unordered_map; @@ -865,6 +865,8 @@ protected: int32_t partialResultCount; // For buffer drop errors, the stream ID for the stream that lost a buffer. + // For physical sub-camera result errors, the Id of the physical stream + // for the physical sub-camera. // Otherwise -1. int32_t errorStreamId; @@ -878,6 +880,8 @@ protected: // return from HAL but framework. ::android::Vector resultOutputBuffers; + std::unordered_set expectedPhysicalResults; + InFlightRequest() : shutterTimestamp(0), errorCodeValid(false), @@ -907,6 +911,24 @@ protected: partialResultCount(0), errorStreamId(-1), hasInputBuffer(hasInput) {} + + InFlightRequest(ssize_t numBuffers, bool hasInput, + bool partialResults, uint32_t partialCount, + const std::unordered_set& extraPhysicalResult, + std::shared_ptr queue = nullptr) : + shutterTimestamp(0), + errorCodeValid(false), + errorCode(ErrorCode::ERROR_BUFFER), + usePartialResult(partialResults), + numPartialResults(partialCount), + resultQueue(queue), + haveResultMetadata(false), + numBuffersLeft(numBuffers), + frameNumber(0), + partialResultCount(0), + errorStreamId(-1), + hasInputBuffer(hasInput), + expectedPhysicalResults(extraPhysicalResult) {} }; // Map from frame number to the in-flight request state @@ -1124,6 +1146,13 @@ bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& r return notify; } + if (physicalCameraMetadata.size() != request->expectedPhysicalResults.size()) { + ALOGE("%s: Frame %d: Returned physical metadata count %zu " + "must be equal to expected count %zu", __func__, frameNumber, + physicalCameraMetadata.size(), request->expectedPhysicalResults.size()); + ADD_FAILURE(); + return notify; + } std::vector<::android::hardware::camera::device::V3_2::CameraMetadata> physResultMetadata; physResultMetadata.resize(physicalCameraMetadata.size()); for (size_t i = 0; i < physicalCameraMetadata.size(); i++) { @@ -1251,11 +1280,11 @@ bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& r } void CameraHidlTest::DeviceCb::setCurrentStreamConfig( - const hidl_vec& streams, const hidl_vec& halStreams) { + const hidl_vec& streams, const hidl_vec& halStreams) { ASSERT_EQ(streams.size(), halStreams.size()); ASSERT_NE(streams.size(), 0); for (size_t i = 0; i < streams.size(); i++) { - ASSERT_EQ(streams[i].id, halStreams[i].id); + ASSERT_EQ(streams[i].v3_2.id, halStreams[i].id); } std::lock_guard l(mLock); mUseHalBufManager = true; @@ -1293,16 +1322,6 @@ Return CameraHidlTest::DeviceCb::notify( std::lock_guard l(mParent->mLock); for (size_t i = 0; i < messages.size(); i++) { - ssize_t idx = mParent->mInflightMap.indexOfKey( - messages[i].msg.shutter.frameNumber); - if (::android::NAME_NOT_FOUND == idx) { - ALOGE("%s: Unexpected frame number! received: %u", - __func__, messages[i].msg.shutter.frameNumber); - ADD_FAILURE(); - break; - } - InFlightRequest *r = mParent->mInflightMap.editValueAt(idx); - switch(messages[i].type) { case MsgType::ERROR: if (ErrorCode::ERROR_DEVICE == messages[i].msg.error.errorCode) { @@ -1310,13 +1329,59 @@ Return CameraHidlTest::DeviceCb::notify( __func__); ADD_FAILURE(); } else { - r->errorCodeValid = true; - r->errorCode = messages[i].msg.error.errorCode; - r->errorStreamId = messages[i].msg.error.errorStreamId; + ssize_t idx = mParent->mInflightMap.indexOfKey( + messages[i].msg.error.frameNumber); + if (::android::NAME_NOT_FOUND == idx) { + ALOGE("%s: Unexpected error frame number! received: %u", + __func__, messages[i].msg.error.frameNumber); + ADD_FAILURE(); + break; + } + InFlightRequest *r = mParent->mInflightMap.editValueAt(idx); + + if (ErrorCode::ERROR_RESULT == messages[i].msg.error.errorCode && + messages[i].msg.error.errorStreamId != -1) { + if (r->haveResultMetadata) { + ALOGE("%s: Camera must report physical camera result error before " + "the final capture result!", __func__); + ADD_FAILURE(); + } else { + for (size_t j = 0; j < mStreams.size(); j++) { + if (mStreams[j].v3_2.id == messages[i].msg.error.errorStreamId) { + hidl_string physicalCameraId = mStreams[j].physicalCameraId; + bool idExpected = r->expectedPhysicalResults.find( + physicalCameraId) != r->expectedPhysicalResults.end(); + if (!idExpected) { + ALOGE("%s: ERROR_RESULT's error stream's physicalCameraId " + "%s must be expected", __func__, + physicalCameraId.c_str()); + ADD_FAILURE(); + } else { + r->expectedPhysicalResults.erase(physicalCameraId); + } + break; + } + } + } + } else { + r->errorCodeValid = true; + r->errorCode = messages[i].msg.error.errorCode; + r->errorStreamId = messages[i].msg.error.errorStreamId; + } } break; case MsgType::SHUTTER: + { + ssize_t idx = mParent->mInflightMap.indexOfKey(messages[i].msg.shutter.frameNumber); + if (::android::NAME_NOT_FOUND == idx) { + ALOGE("%s: Unexpected shutter frame number! received: %u", + __func__, messages[i].msg.shutter.frameNumber); + ADD_FAILURE(); + break; + } + InFlightRequest *r = mParent->mInflightMap.editValueAt(idx); r->shutterTimestamp = messages[i].msg.shutter.timestamp; + } break; default: ALOGE("%s: Unsupported notify message %d", __func__, @@ -1357,7 +1422,7 @@ Return CameraHidlTest::DeviceCb::requestStreamBuffers( for (size_t i = 0; i < bufReqs.size(); i++) { bool found = false; for (size_t idx = 0; idx < mStreams.size(); idx++) { - if (bufReqs[i].streamId == mStreams[idx].id) { + if (bufReqs[i].streamId == mStreams[idx].v3_2.id) { found = true; indexes[i] = idx; break; @@ -1381,7 +1446,7 @@ Return CameraHidlTest::DeviceCb::requestStreamBuffers( const auto& halStream = mHalStreams[idx]; const V3_5::BufferRequest& bufReq = bufReqs[i]; if (mOutstandingBufferIds[idx].size() + bufReq.numBuffersRequested > halStream.maxBuffers) { - bufRets[i].streamId = stream.id; + bufRets[i].streamId = stream.v3_2.id; bufRets[i].val.error(StreamBufferRequestError::MAX_BUFFER_EXCEEDED); allStreamOk = false; continue; @@ -1390,17 +1455,17 @@ Return CameraHidlTest::DeviceCb::requestStreamBuffers( hidl_vec tmpRetBuffers(bufReq.numBuffersRequested); for (size_t j = 0; j < bufReq.numBuffersRequested; j++) { hidl_handle buffer_handle; - mParent->allocateGraphicBuffer(stream.width, stream.height, + mParent->allocateGraphicBuffer(stream.v3_2.width, stream.v3_2.height, android_convertGralloc1To0Usage( halStream.producerUsage, halStream.consumerUsage), halStream.overrideFormat, &buffer_handle); - tmpRetBuffers[j] = {stream.id, mNextBufferId, buffer_handle, BufferStatus::OK, + tmpRetBuffers[j] = {stream.v3_2.id, mNextBufferId, buffer_handle, BufferStatus::OK, nullptr, nullptr}; mOutstandingBufferIds[idx].insert(std::make_pair(mNextBufferId++, buffer_handle)); } atLeastOneStreamOk = true; - bufRets[i].streamId = stream.id; + bufRets[i].streamId = stream.v3_2.id; bufRets[i].val.buffers(std::move(tmpRetBuffers)); } @@ -1430,7 +1495,7 @@ Return CameraHidlTest::DeviceCb::returnStreamBuffers( for (const auto& buf : buffers) { bool found = false; for (size_t idx = 0; idx < mOutstandingBufferIds.size(); idx++) { - if (mStreams[idx].id == buf.streamId && + if (mStreams[idx].v3_2.id == buf.streamId && mOutstandingBufferIds[idx].count(buf.bufferId) == 1) { mOutstandingBufferIds[idx].erase(buf.bufferId); // TODO: check do we need to close/delete native handle or assume we have enough @@ -4157,7 +4222,7 @@ TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) { ASSERT_TRUE(resultQueueRet.isOk()); InFlightRequest inflightReq = {static_cast (halStreamConfig.streams.size()), false, - supportsPartialResults, partialResultCount, resultQueue}; + supportsPartialResults, partialResultCount, physicalIds, resultQueue}; std::vector graphicBuffers; graphicBuffers.reserve(halStreamConfig.streams.size()); @@ -4236,7 +4301,7 @@ TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) { request.v3_2.outputBuffers[0].buffer = nullptr; mInflightMap.clear(); inflightReq = {static_cast (physicalIds.size()), false, - supportsPartialResults, partialResultCount, resultQueue}; + supportsPartialResults, partialResultCount, physicalIds, resultQueue}; mInflightMap.add(request.v3_2.frameNumber, &inflightReq); } @@ -5315,10 +5380,10 @@ void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t ASSERT_EQ(physicalIds.size(), halConfig.streams.size()); *halStreamConfig = halConfig; if (*useHalBufManager) { - hidl_vec streams(physicalIds.size()); + hidl_vec streams(physicalIds.size()); hidl_vec halStreams(physicalIds.size()); for (size_t i = 0; i < physicalIds.size(); i++) { - streams[i] = streams3_4[i].v3_2; + streams[i] = streams3_4[i]; halStreams[i] = halConfig.streams[i].v3_3.v3_2; } cb->setCurrentStreamConfig(streams, halStreams); @@ -5493,9 +5558,9 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t dev halStreamConfig->streams.resize(1); halStreamConfig->streams[0] = halConfig.streams[0].v3_3.v3_2; if (*useHalBufManager) { - hidl_vec streams(1); + hidl_vec streams(1); hidl_vec halStreams(1); - streams[0] = stream3_2; + streams[0] = config3_4.streams[0]; halStreams[0] = halConfig.streams[0].v3_3.v3_2; cb->setCurrentStreamConfig(streams, halStreams); } diff --git a/current.txt b/current.txt index fbb9752c04..c7b0d9e964 100644 --- a/current.txt +++ b/current.txt @@ -572,6 +572,7 @@ efbb061c969fa9553d243da6ee23b83fe5d4aa663a7b8896adc52e2b015bc2f3 android.hardwar cfa81f229b69f9011c58f48264fcb552447430fe68610eac514e811e65bc306a android.hardware.wifi.supplicant@1.2::types # ABI preserving changes to HALs during Android R +2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice ad431c8de51c07934a068e3043d8dd0537ac4d3158627706628b123f42df48dc android.hardware.neuralnetworks@1.0::IPreparedModel aafcc10cf04ab247e86d4582586c71c6b4c2b8c479241ffa7fe37deb659fc942 android.hardware.neuralnetworks@1.2::IPreparedModel From bca165e63a00ffd60fe25a787216e38950f50503 Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Thu, 1 Aug 2019 16:28:33 -0700 Subject: [PATCH 0065/1022] Tuner HAL for ATV Initialize Tuner HAL review from Tuner and Frontend Interface. Bug: 135709729 Test: Manual Change-Id: Ibfc18049ea471a1cfec6fb9f5b71f8a92cf89045 --- tv/tuner/1.0/Android.bp | 20 +++++ tv/tuner/1.0/IFrontend.hal | 82 +++++++++++++++++ tv/tuner/1.0/IFrontendCallback.hal | 37 ++++++++ tv/tuner/1.0/ITuner.hal | 52 +++++++++++ tv/tuner/1.0/types.hal | 139 +++++++++++++++++++++++++++++ 5 files changed, 330 insertions(+) create mode 100644 tv/tuner/1.0/Android.bp create mode 100644 tv/tuner/1.0/IFrontend.hal create mode 100644 tv/tuner/1.0/IFrontendCallback.hal create mode 100644 tv/tuner/1.0/ITuner.hal create mode 100644 tv/tuner/1.0/types.hal diff --git a/tv/tuner/1.0/Android.bp b/tv/tuner/1.0/Android.bp new file mode 100644 index 0000000000..b54413de6a --- /dev/null +++ b/tv/tuner/1.0/Android.bp @@ -0,0 +1,20 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.tv.tuner@1.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IFrontend.hal", + "IFrontendCallback.hal", + "ITuner.hal", + ], + interfaces: [ + "android.hidl.base@1.0", + ], + gen_java: false, + gen_java_constants: true, +} diff --git a/tv/tuner/1.0/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal new file mode 100644 index 0000000000..05cee910fd --- /dev/null +++ b/tv/tuner/1.0/IFrontend.hal @@ -0,0 +1,82 @@ +/* + * 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. + */ +package android.hardware.tv.tuner@1.0; + +import IFrontendCallback; + +/** + * A Tuner Frontend is used to tune to a frequency and lock signal. It provide + * live data feed to Tuner Demux interface. + */ +interface IFrontend { + /** + * Set the callback + * + * It is used by the client to receive events from the Frontend. + * Only one callback for one Frontend instance is supported. The callback + * will be replaced if it's set again. + * + * @param callback Callback object to pass Frontend events to the system. + * The previously registered callback must be replaced with this one. + * It can be null. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if callback can't be set at current stage, + * UNKNOWN_ERROR if callback setting failed for other reasons. + */ + setCallback(IFrontendCallback callback) generates (Result result); + + /** + * Tuning Frontend + * + * It is used by the client to lock a frequency by providing signal + * delivery information. If previous tuning isn't completed, this call must + * stop previous tuning, and start a new tuning. Tune is a async call. + * LOCKED or NO_SIGNAL eventi is sent back to caller through callback. + * + * @param settings Signal delivery information which frontend can use to + * search and lock the signal. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if tuning can't be applied at current stage, + * UNKNOWN_ERROR if tuning failed for other reasons. + */ + tune(FrontendSettings settings) generates (Result result); + + /** + * Stop the tuning + * + * It is used by the client to stop a previous tuning. + * + * @return result Result status of the operation. + * SUCCESS if successfully stop tuning. + * UNKNOWN_ERROR if failed for other reasons. + */ + stopTune() generates (Result result); + + /** + * Release the Frontend instance + * + * It is used by the client to release the frontend instance. HAL clear + * underneath resource. client mustn't access the instance any more. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + */ + close() generates (Result result); +}; diff --git a/tv/tuner/1.0/IFrontendCallback.hal b/tv/tuner/1.0/IFrontendCallback.hal new file mode 100644 index 0000000000..e9070495c3 --- /dev/null +++ b/tv/tuner/1.0/IFrontendCallback.hal @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package android.hardware.tv.tuner@1.0; + +interface IFrontendCallback { + /** + * Notify the client that a new event happened on the frontend. + * + * @param frontendEventType the event type. + */ + oneway onEvent(FrontendEventType frontendEventType); + + /** + * The callback function that must be called by HAL implementation to notify + * the client of new DiSEqC message. + * + * @param diseqcMessage a byte array of data for DiSEqC (Digital Satellite + * Equipment Control) message which is specified by EUTELSAT Bus Functional + * Specification Version 4.2. + */ + oneway onDiseqcMessage(vec diseqcMessage); +}; + diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal new file mode 100644 index 0000000000..5a5f547a75 --- /dev/null +++ b/tv/tuner/1.0/ITuner.hal @@ -0,0 +1,52 @@ +/* + * 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. + */ + +package android.hardware.tv.tuner@1.0; + +import IFrontend; + +/** + * Top level interface to manage Frontend, Demux and Decrambler hardware + * resouces which are needed for Android TV. + */ +interface ITuner { + /** + * Get Frontend IDs + * + * It is used by the client to get all available frontends' IDs. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if tuning failed for other reasons. + * @return frontendIds an array of FrontendId for the available frontends. + */ + getFrontendIds() generates (Result result, vec frontendIds); + + /** + * Create a new instance of Frontend given a frontendId. + * + * It is used by the client to create a frontend instance. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if creation failed for other reasons. + * @return frontend the newly created frontend interface. + */ + openFrontendById(FrontendId frontendId) + generates (Result result, IFrontend frontend); + +}; + diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal new file mode 100644 index 0000000000..1ca7fda4b7 --- /dev/null +++ b/tv/tuner/1.0/types.hal @@ -0,0 +1,139 @@ +/* + * 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. + */ + +package android.hardware.tv.tuner@1.0; + +import android.hidl.safe_union@1.0; + +@export +enum Result : int32_t { + SUCCESS, + UNAVAILABLE, + NOT_INITIALIZED, + INVALID_STATE, + INVALID_ARGUMENT, + OUT_OF_MEMORY, + UNKNOWN_ERROR, +}; + +/** + * Frontend ID. + */ +typedef uint32_t FrontendId; + +/** + * Frontend Types. + */ +@export +enum FrontendType : uint32_t { + UNDEFINED = 0, + ANALOG, + ATSC, + DVBC, + DVBS, + DVBT, + ISDBT, +}; + +/** + * Inner Forward Error Correction type as specified in ETSI EN 300 468 V1.15.1 + * It's a 4-bit field specifying the inner FEC scheme used according to the + * table 35 in the spec. + */ +@export +enum FrontendInnerFec : uint32_t { + /* Not defined */ + FEC_UNDEFINED = 0, + /* 1/2 conv. code rate */ + FEC_1_2 = 1 << 0, + /* 2/3 conv. code rate */ + FEC_2_3 = 1 << 1, + /* 3/4 conv. code rate */ + FEC_3_4 = 1 << 2, + /* 5/6 conv. code rate */ + FEC_5_6 = 1 << 3, + /* 7/8 conv. code rate */ + FEC_7_8 = 1 << 4, + /* 8/9 conv. code rate */ + FEC_8_9 = 1 << 5, + /* 3/5 conv. code rate */ + FEC_3_5 = 1 << 6, + /* 4/5 conv. code rate */ + FEC_4_5 = 1 << 7, + /* 9/10 conv. code rate */ + FEC_9_10 = 1 << 8, + /* hardware is able to detect and set FEC automatically */ + FEC_AUTO = 1 << 9, +}; + +/** + * Modulation Type for ATSC. + */ +@export +enum FrontendAtscModulation : uint32_t { + UNDEFINED = 0, + MOD_8VSB = 1 << 0, + MOD_16VSB = 1 << 1, +}; + +/** + * Signal Setting for ATSC Frontend. + */ +struct FrontendAtscSettings { + /** Signal frequencey in Herhz */ + uint32_t frequency; + FrontendAtscModulation modulation; +}; + +/** + * Signal Setting for DVBT Frontend. + */ +struct FrontendDvbtSettings { + /** Signal frequencey in Herhz */ + uint32_t frequency; + FrontendAtscModulation modulation; + FrontendInnerFec fec; +}; + +/** + * Modulation Type for ATSC. + */ +safe_union FrontendSettings { + FrontendAtscSettings atsc; + FrontendDvbtSettings dvbt; +}; + +/** + * Frontend Event Type. + */ +@export +enum FrontendEventType : uint32_t { + /** + * If frontend locked the signal which is specified by tune method, HAL sent + * Locked event. + */ + LOCKED, + /** + * If frontend can't locked the signal which is specified by tune method, + * HAL sent NO_SIGNAL event. + */ + NO_SIGNAL, + /** + * If frontend detect that the locked signal get lost, HAL sent LOST_LOCK + * event. + */ + LOST_LOCK, +}; From d0aef4dfe5ac80a1b51d5002a24c51d2ff56a15e Mon Sep 17 00:00:00 2001 From: Adam Bodnar Date: Thu, 11 Jul 2019 10:35:42 -0700 Subject: [PATCH 0066/1022] Add more HWC vs RenderEngine tests to composer vts Bug: 133411821 Test: build, boot, VtsHalGraphicsComposerV2_2TargetTest Change-Id: I19322f75b098813b1e4acf31cb6bae9e15fb8915 --- .../composer/2.2/utils/vts/ReadbackVts.cpp | 14 +- .../composer/2.2/vts/functional/Android.bp | 16 +- ...sComposerV2_2CompositionComparisonTest.cpp | 262 ------------------ ...VtsHalGraphicsComposerV2_2ReadbackTest.cpp | 111 ++++++-- 4 files changed, 97 insertions(+), 306 deletions(-) delete mode 100644 graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp index d479aa74ec..7bb9121cba 100644 --- a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp +++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp @@ -81,14 +81,14 @@ LayerSettings TestLayer::toRenderEngineLayerSettings() { static_cast(mDisplayFrame.left), static_cast(mDisplayFrame.top), static_cast(mDisplayFrame.right), static_cast(mDisplayFrame.bottom)); - const mat4 translation = mat4::translate(vec4( - (mTransform & Transform::FLIP_H ? -1.0f : 0.0f) * mDisplayFrame.right, - (mTransform & Transform::FLIP_V ? -1.0f : 0.0f) * mDisplayFrame.bottom, 0.0f, 1.0f)); + const mat4 translation = mat4::translate( + vec4((mTransform & Transform::FLIP_H ? -mDisplayFrame.right : 0.0f), + (mTransform & Transform::FLIP_V ? -mDisplayFrame.bottom : 0.0f), 0.0f, 1.0f)); const mat4 scale = mat4::scale(vec4(mTransform & Transform::FLIP_H ? -1.0f : 1.0f, mTransform & Transform::FLIP_V ? -1.0f : 1.0f, 1.0f, 1.0f)); - layerSettings.geometry.positionTransform = translation * scale; + layerSettings.geometry.positionTransform = scale * translation; return layerSettings; } @@ -296,9 +296,9 @@ LayerSettings TestBufferLayer::toRenderEngineLayerSettings() { layerSettings.source.buffer.buffer = new GraphicBuffer(mBufferHandle, GraphicBuffer::CLONE_HANDLE, mWidth, mHeight, static_cast(mFormat), 1, mUsage, mStride); - // TODO(b/136483187): Why does this break the premultiply test - // layerSettings.source.buffer.usePremultipliedAlpha = - // mBlendMode == IComposerClient::BlendMode::PREMULTIPLIED; + + layerSettings.source.buffer.usePremultipliedAlpha = + mBlendMode == IComposerClient::BlendMode::PREMULTIPLIED; const float scaleX = (mSourceCrop.right - mSourceCrop.left) / (mWidth); const float scaleY = (mSourceCrop.bottom - mSourceCrop.top) / (mHeight); diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp index 13190350ec..25b827e83b 100644 --- a/graphics/composer/2.2/vts/functional/Android.bp +++ b/graphics/composer/2.2/vts/functional/Android.bp @@ -19,29 +19,24 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: [ "VtsHalGraphicsComposerV2_2ReadbackTest.cpp", - "VtsHalGraphicsComposerV2_2TargetTest.cpp", - "VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp", + "VtsHalGraphicsComposerV2_2TargetTest.cpp" ], // TODO(b/64437680): Assume these libs are always available on the device. shared_libs: [ + "libEGL", + "libGLESv1_CM", + "libGLESv2", "libfmq", + "libgui", "libhidlbase", "libhidltransport", "libhwbinder", "libprocessgroup", "libsync", "libui", - "libgui", - "libEGL", - "libGLESv1_CM", - "libGLESv2", ], static_libs: [ - "librenderengine", - "libmath", - "libarect", - "libnativewindow", "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.allocator@3.0", "android.hardware.graphics.common@1.1", @@ -55,6 +50,7 @@ cc_test { "android.hardware.graphics.mapper@2.1-vts", "android.hardware.graphics.mapper@3.0", "android.hardware.graphics.mapper@3.0-vts", + "librenderengine" ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp deleted file mode 100644 index d694a5bab0..0000000000 --- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright 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 "graphics_composer_hidl_hal_readback_tests@2.2" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace android { -namespace hardware { -namespace graphics { -namespace composer { -namespace V2_2 { -namespace vts { -namespace { - -using android::GraphicBuffer; -using android::Rect; -using android::hardware::hidl_handle; -using common::V1_1::BufferUsage; -using common::V1_1::Dataspace; -using common::V1_1::PixelFormat; -using mapper::V2_1::IMapper; -using V2_1::Config; -using V2_1::Display; -using V2_1::vts::TestCommandReader; -using vts::Gralloc; - -// Test environment for graphics.composer -class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static GraphicsComposerHidlEnvironment* Instance() { - static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment; - return instance; - } - virtual void registerTestServices() override { registerTestService(); } - - private: - GraphicsComposerHidlEnvironment() {} - GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment); -}; - -class GraphicsCompositionComparisonTest : public ::testing::VtsHalHidlTargetTestBase { - protected: - using PowerMode = V2_1::IComposerClient::PowerMode; - void SetUp() override { - VtsHalHidlTargetTestBase::SetUp(); - ASSERT_NO_FATAL_FAILURE( - mComposer = std::make_unique( - GraphicsComposerHidlEnvironment::Instance()->getServiceName())); - ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); - mComposerCallback = new V2_1::vts::GraphicsComposerCallback; - mComposerClient->registerCallback(mComposerCallback); - - // assume the first display is primary and is never removed - mPrimaryDisplay = waitForFirstDisplay(); - Config activeConfig; - ASSERT_NO_FATAL_FAILURE(activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay)); - ASSERT_NO_FATAL_FAILURE( - mDisplayWidth = mComposerClient->getDisplayAttribute( - mPrimaryDisplay, activeConfig, IComposerClient::Attribute::WIDTH)); - ASSERT_NO_FATAL_FAILURE( - mDisplayHeight = mComposerClient->getDisplayAttribute( - mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT)); - - setTestColorModes(); - - // explicitly disable vsync - ASSERT_NO_FATAL_FAILURE(mComposerClient->setVsyncEnabled(mPrimaryDisplay, false)); - mComposerCallback->setVsyncAllowed(false); - - // set up command writer/reader and gralloc - mWriter = std::make_shared(1024); - mReader = std::make_unique(); - mGralloc = std::make_shared(); - - ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON)); - - ASSERT_NO_FATAL_FAILURE( - mTestRenderEngine = std::unique_ptr(new TestRenderEngine( - PixelFormat::RGBA_8888, - renderengine::RenderEngine::USE_COLOR_MANAGEMENT | - renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT))); - - renderengine::DisplaySettings clientCompositionDisplay; - clientCompositionDisplay.physicalDisplay = Rect(mDisplayWidth, mDisplayHeight); - clientCompositionDisplay.clip = clientCompositionDisplay.physicalDisplay; - clientCompositionDisplay.clearRegion = Region(clientCompositionDisplay.physicalDisplay); - - mTestRenderEngine->initGraphicBuffer( - static_cast(mDisplayWidth), static_cast(mDisplayHeight), 1, - static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN)); - mTestRenderEngine->setDisplaySettings(clientCompositionDisplay); - } - - void TearDown() override { - ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::OFF)); - EXPECT_EQ(0, mReader->mErrors.size()); - EXPECT_EQ(0, mReader->mCompositionChanges.size()); - if (mComposerCallback != nullptr) { - EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount()); - EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount()); - EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount()); - } - VtsHalHidlTargetTestBase::TearDown(); - } - - void clearCommandReaderState() { - mReader->mCompositionChanges.clear(); - mReader->mErrors.clear(); - } - - void writeLayers(const std::vector>& layers) { - for (auto layer : layers) { - layer->write(mWriter); - } - execute(); - } - - void execute() { - ASSERT_NO_FATAL_FAILURE(mComposerClient->execute(mReader.get(), mWriter.get())); - } - - std::unique_ptr mComposer; - std::shared_ptr mComposerClient; - - sp mComposerCallback; - // the first display and is assumed never to be removed - Display mPrimaryDisplay; - int32_t mDisplayWidth; - int32_t mDisplayHeight; - std::vector mTestColorModes; - std::shared_ptr mWriter; - std::unique_ptr mReader; - std::shared_ptr mGralloc; - std::unique_ptr mTestRenderEngine; - - bool mHasReadbackBuffer; - PixelFormat mPixelFormat; - Dataspace mDataspace; - - private: - Display waitForFirstDisplay() { - while (true) { - std::vector displays = mComposerCallback->getDisplays(); - if (displays.empty()) { - usleep(5 * 1000); - continue; - } - return displays[0]; - } - } - - void setTestColorModes() { - mTestColorModes.clear(); - mComposerClient->getRaw()->getColorModes_2_2(mPrimaryDisplay, [&](const auto& tmpError, - const auto& tmpModes) { - ASSERT_EQ(Error::NONE, tmpError); - for (ColorMode mode : tmpModes) { - if (std::find(ReadbackHelper::colorModes.begin(), ReadbackHelper::colorModes.end(), - mode) != ReadbackHelper::colorModes.end()) { - mTestColorModes.push_back(mode); - } - } - }); - } -}; - -TEST_F(GraphicsCompositionComparisonTest, SingleSolidColorLayer) { - for (ColorMode mode : mTestColorModes) { - std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" - << std::endl; - mWriter->selectDisplay(mPrimaryDisplay); - ASSERT_NO_FATAL_FAILURE( - mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); - - mComposerClient->getRaw()->getReadbackBufferAttributes( - mPrimaryDisplay, - [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { - mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat, - tmpDataspace, tmpError); - mPixelFormat = tmpPixelFormat; - mDataspace = tmpDataspace; - }); - - if (!mHasReadbackBuffer) { - std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl; - GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; - return; - } - - auto layer = std::make_shared(mComposerClient, mPrimaryDisplay); - IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight}); - layer->setColor(BLUE); - layer->setDisplayFrame(coloredSquare); - layer->setZOrder(10); - - std::vector> layers = {layer}; - - // expected color for each pixel - std::vector expectedColors(mDisplayWidth * mDisplayHeight); - ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE); - - ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, - mDisplayHeight, mPixelFormat, mDataspace); - ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); - - writeLayers(layers); - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->validateDisplay(); - execute(); - // if hwc cannot handle and asks for composition change, - // just succeed the test - if (mReader->mCompositionChanges.size() != 0) { - clearCommandReaderState(); - GTEST_SUCCEED(); - return; - } - ASSERT_EQ(0, mReader->mErrors.size()); - mWriter->presentDisplay(); - execute(); - ASSERT_EQ(0, mReader->mErrors.size()); - - ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); - mTestRenderEngine->setRenderLayers(layers); - ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); - ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); - } -} - -} // namespace -} // namespace vts -} // namespace V2_2 -} // namespace composer -} // namespace graphics -} // namespace hardware -} // namespace android diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp index 92c03f0dbf..ade7a38222 100644 --- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp @@ -21,7 +21,14 @@ #include #include #include +#include #include +#include +#include +#include +#include +#include +#include namespace android { namespace hardware { @@ -31,14 +38,17 @@ namespace V2_2 { namespace vts { namespace { +using android::GraphicBuffer; +using android::Rect; using android::hardware::hidl_handle; using common::V1_1::BufferUsage; using common::V1_1::Dataspace; using common::V1_1::PixelFormat; using mapper::V2_1::IMapper; +using V2_1::Config; using V2_1::Display; -using V2_1::Layer; using V2_1::vts::TestCommandReader; +using vts::Gralloc; // Test environment for graphics.composer class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { @@ -55,8 +65,8 @@ class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEn GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment); }; -class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase { - protected: +class GraphicsCompositionTest : public ::testing::VtsHalHidlTargetTestBase { + protected: using PowerMode = V2_1::IComposerClient::PowerMode; void SetUp() override { VtsHalHidlTargetTestBase::SetUp(); @@ -90,6 +100,22 @@ class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase mGralloc = std::make_shared(); ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON)); + + ASSERT_NO_FATAL_FAILURE( + mTestRenderEngine = std::unique_ptr(new TestRenderEngine( + PixelFormat::RGBA_8888, + renderengine::RenderEngine::USE_COLOR_MANAGEMENT | + renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT))); + + renderengine::DisplaySettings clientCompositionDisplay; + clientCompositionDisplay.physicalDisplay = Rect(mDisplayWidth, mDisplayHeight); + clientCompositionDisplay.clip = clientCompositionDisplay.physicalDisplay; + clientCompositionDisplay.clearRegion = Region(clientCompositionDisplay.physicalDisplay); + + mTestRenderEngine->initGraphicBuffer( + static_cast(mDisplayWidth), static_cast(mDisplayHeight), 1, + static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN)); + mTestRenderEngine->setDisplaySettings(clientCompositionDisplay); } void TearDown() override { @@ -132,6 +158,7 @@ class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase std::shared_ptr mWriter; std::unique_ptr mReader; std::shared_ptr mGralloc; + std::unique_ptr mTestRenderEngine; bool mHasReadbackBuffer; PixelFormat mPixelFormat; @@ -166,7 +193,7 @@ class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase } }; -TEST_F(GraphicsComposerReadbackTest, SingleSolidColorLayer) { +TEST_F(GraphicsCompositionTest, SingleSolidColorLayer) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -222,10 +249,13 @@ TEST_F(GraphicsComposerReadbackTest, SingleSolidColorLayer) { ASSERT_EQ(0, mReader->mErrors.size()); ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(layers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); } } -TEST_F(GraphicsComposerReadbackTest, SetLayerBuffer) { +TEST_F(GraphicsCompositionTest, SetLayerBuffer) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -291,10 +321,13 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerBuffer) { ASSERT_EQ(0, mReader->mErrors.size()); ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(layers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); } } -TEST_F(GraphicsComposerReadbackTest, SetLayerBufferNoEffect) { +TEST_F(GraphicsCompositionTest, SetLayerBufferNoEffect) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -356,7 +389,7 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerBufferNoEffect) { } } -TEST_F(GraphicsComposerReadbackTest, ClientComposition) { +TEST_F(GraphicsCompositionTest, ClientComposition) { ASSERT_NO_FATAL_FAILURE( mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount)); @@ -473,7 +506,7 @@ TEST_F(GraphicsComposerReadbackTest, ClientComposition) { } } -TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) { +TEST_F(GraphicsCompositionTest, DeviceAndClientComposition) { ASSERT_NO_FATAL_FAILURE( mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount)); @@ -599,7 +632,7 @@ TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) { } } -TEST_F(GraphicsComposerReadbackTest, SetLayerDamage) { +TEST_F(GraphicsCompositionTest, SetLayerDamage) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -684,7 +717,7 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerDamage) { } } -TEST_F(GraphicsComposerReadbackTest, SetLayerPlaneAlpha) { +TEST_F(GraphicsCompositionTest, SetLayerPlaneAlpha) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -739,10 +772,13 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerPlaneAlpha) { std::vector expectedColors(mDisplayWidth * mDisplayHeight); ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(layers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); } } -TEST_F(GraphicsComposerReadbackTest, SetLayerSourceCrop) { +TEST_F(GraphicsCompositionTest, SetLayerSourceCrop) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -807,10 +843,13 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerSourceCrop) { execute(); ASSERT_EQ(0, mReader->mErrors.size()); ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(layers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); } } -TEST_F(GraphicsComposerReadbackTest, SetLayerZOrder) { +TEST_F(GraphicsCompositionTest, SetLayerZOrder) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -891,20 +930,23 @@ TEST_F(GraphicsComposerReadbackTest, SetLayerZOrder) { ASSERT_EQ(0, mReader->mErrors.size()); ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(layers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); } } -class GraphicsComposerBlendModeReadbackTest : public GraphicsComposerReadbackTest, - public ::testing::WithParamInterface { - public: +class GraphicsBlendModeCompositionTest : public GraphicsCompositionTest, + public ::testing::WithParamInterface { + public: void SetUp() override { - GraphicsComposerReadbackTest::SetUp(); + GraphicsCompositionTest::SetUp(); mTestColorModes = {ColorMode::SRGB}; // TODO: add more color mode support mBackgroundColor = BLACK; mTopLayerColor = RED; } - void TearDown() override { GraphicsComposerReadbackTest::TearDown(); } + void TearDown() override { GraphicsCompositionTest::TearDown(); } void setBackgroundColor(IComposerClient::Color color) { mBackgroundColor = color; } @@ -976,7 +1018,7 @@ class GraphicsComposerBlendModeReadbackTest : public GraphicsComposerReadbackTes IComposerClient::Color mTopLayerColor; }; -TEST_P(GraphicsComposerBlendModeReadbackTest, None) { +TEST_P(GraphicsBlendModeCompositionTest, None) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -1026,12 +1068,15 @@ TEST_P(GraphicsComposerBlendModeReadbackTest, None) { ASSERT_EQ(0, mReader->mErrors.size()); ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(mLayers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); } } // TODO: bug 116865056: Readback returns (245, 0, 0) for layer plane // alpha of .2, expected 10.2 -TEST_P(GraphicsComposerBlendModeReadbackTest, DISABLED_Coverage) { +TEST_P(GraphicsBlendModeCompositionTest, DISABLED_Coverage) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -1084,7 +1129,7 @@ TEST_P(GraphicsComposerBlendModeReadbackTest, DISABLED_Coverage) { } } -TEST_P(GraphicsComposerBlendModeReadbackTest, Premultiplied) { +TEST_P(GraphicsBlendModeCompositionTest, Premultiplied) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -1132,16 +1177,19 @@ TEST_P(GraphicsComposerBlendModeReadbackTest, Premultiplied) { execute(); ASSERT_EQ(0, mReader->mErrors.size()); ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(mLayers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); } } -INSTANTIATE_TEST_CASE_P(BlendModeTest, GraphicsComposerBlendModeReadbackTest, +INSTANTIATE_TEST_CASE_P(BlendModeTest, GraphicsBlendModeCompositionTest, ::testing::Values(.2, 1.0)); -class GraphicsComposerTransformReadbackTest : public GraphicsComposerReadbackTest { - protected: +class GraphicsTransformCompositionTest : public GraphicsCompositionTest { + protected: void SetUp() override { - GraphicsComposerReadbackTest::SetUp(); + GraphicsCompositionTest::SetUp(); mWriter->selectDisplay(mPrimaryDisplay); @@ -1176,7 +1224,7 @@ class GraphicsComposerTransformReadbackTest : public GraphicsComposerReadbackTes int mSideLength; }; -TEST_F(GraphicsComposerTransformReadbackTest, FLIP_H) { +TEST_F(GraphicsTransformCompositionTest, FLIP_H) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -1225,10 +1273,13 @@ TEST_F(GraphicsComposerTransformReadbackTest, FLIP_H) { ASSERT_EQ(0, mReader->mErrors.size()); ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(mLayers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); } } -TEST_F(GraphicsComposerTransformReadbackTest, FLIP_V) { +TEST_F(GraphicsTransformCompositionTest, FLIP_V) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -1277,10 +1328,13 @@ TEST_F(GraphicsComposerTransformReadbackTest, FLIP_V) { execute(); ASSERT_EQ(0, mReader->mErrors.size()); ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(mLayers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); } } -TEST_F(GraphicsComposerTransformReadbackTest, ROT_180) { +TEST_F(GraphicsTransformCompositionTest, ROT_180) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -1330,6 +1384,9 @@ TEST_F(GraphicsComposerTransformReadbackTest, ROT_180) { execute(); ASSERT_EQ(0, mReader->mErrors.size()); ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(mLayers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); } } From 126ee9202317d98f1936339f254caa596cbfb5ee Mon Sep 17 00:00:00 2001 From: Amy Date: Fri, 9 Aug 2019 16:25:12 -0700 Subject: [PATCH 0067/1022] Tuner HAL default implementation for ATV for Tuner and Frontend Interface. Bug: 135709325 Test: Manual Change-Id: I5603e2c6dd71c46c9c5f3b0e25425c965e77ed0c --- tv/tuner/1.0/default/Android.bp | 43 +++++++++ tv/tuner/1.0/default/Frontend.cpp | 93 +++++++++++++++++++ tv/tuner/1.0/default/Frontend.h | 69 ++++++++++++++ tv/tuner/1.0/default/Tuner.cpp | 79 ++++++++++++++++ tv/tuner/1.0/default/Tuner.h | 55 +++++++++++ ...roid.hardware.tv.tuner@1.0-service-lazy.rc | 9 ++ ...oid.hardware.tv.tuner@1.0-service-lazy.xml | 11 +++ .../android.hardware.tv.tuner@1.0-service.rc | 6 ++ .../android.hardware.tv.tuner@1.0-service.xml | 11 +++ tv/tuner/1.0/default/service.cpp | 58 ++++++++++++ 10 files changed, 434 insertions(+) create mode 100644 tv/tuner/1.0/default/Android.bp create mode 100644 tv/tuner/1.0/default/Frontend.cpp create mode 100644 tv/tuner/1.0/default/Frontend.h create mode 100644 tv/tuner/1.0/default/Tuner.cpp create mode 100644 tv/tuner/1.0/default/Tuner.h create mode 100644 tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.rc create mode 100644 tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.xml create mode 100644 tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.rc create mode 100644 tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.xml create mode 100644 tv/tuner/1.0/default/service.cpp diff --git a/tv/tuner/1.0/default/Android.bp b/tv/tuner/1.0/default/Android.bp new file mode 100644 index 0000000000..cc8d1f50e6 --- /dev/null +++ b/tv/tuner/1.0/default/Android.bp @@ -0,0 +1,43 @@ +cc_defaults { + name: "tuner_service_defaults", + defaults: ["hidl_defaults"], + vendor: true, + relative_install_path: "hw", + srcs: [ + "Frontend.cpp", + "Tuner.cpp", + "service.cpp", + ], + + compile_multilib: "first", + + shared_libs: [ + "android.hardware.tv.tuner@1.0", + "android.hidl.memory@1.0", + "libhidlbase", + "libhidlmemory", + "libhidltransport", + "liblog", + "libstagefright_foundation", + "libutils", + ], + header_libs: [ + "media_plugin_headers", + ], +} + +cc_binary { + name: "android.hardware.tv.tuner@1.0-service", + vintf_fragments: ["android.hardware.tv.tuner@1.0-service.xml"], + defaults: ["tuner_service_defaults"], + init_rc: ["android.hardware.tv.tuner@1.0-service.rc"], +} + +cc_binary { + name: "android.hardware.tv.tuner@1.0-service-lazy", + vintf_fragments: ["android.hardware.tv.tuner@1.0-service-lazy.xml"], + overrides: ["android.hardware.tv.tuner@1.0-service"], + defaults: ["tuner_service_defaults"], + init_rc: ["android.hardware.tv.tuner@1.0-service-lazy.rc"], + cflags: ["-DLAZY_SERVICE"], +} diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp new file mode 100644 index 0000000000..3dcc2b1ebd --- /dev/null +++ b/tv/tuner/1.0/default/Frontend.cpp @@ -0,0 +1,93 @@ +/* + * 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 "android.hardware.tv.tuner@1.0-Frontend" + +#include "Frontend.h" +#include +#include + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +Frontend::Frontend() { + // Init callback to nullptr + mCallback = nullptr; +} + +Frontend::Frontend(FrontendType type, FrontendId id) { + mType = type; + mId = id; + // Init callback to nullptr + mCallback = nullptr; +} + +Frontend::~Frontend() {} + +Return Frontend::close() { + ALOGV("%s", __FUNCTION__); + // Reset callback + mCallback = nullptr; + + return Result::SUCCESS; +} + +Return Frontend::setCallback(const sp& callback) { + ALOGV("%s", __FUNCTION__); + if (callback == nullptr) { + ALOGW("[ WARN ] Set Frontend callback with nullptr"); + return Result::INVALID_ARGUMENT; + } + + mCallback = callback; + return Result::SUCCESS; +} + +Return Frontend::tune(const FrontendSettings& /* settings */) { + ALOGV("%s", __FUNCTION__); + if (mCallback == nullptr) { + ALOGW("[ WARN ] Frontend callback is not set when tune"); + return Result::INVALID_STATE; + } + + mCallback->onEvent(FrontendEventType::NO_SIGNAL); + return Result::SUCCESS; +} + +Return Frontend::stopTune() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +FrontendType Frontend::getFrontendType() { + return mType; +} + +FrontendId Frontend::getFrontendId() { + return mId; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h new file mode 100644 index 0000000000..f77a0d8894 --- /dev/null +++ b/tv/tuner/1.0/default/Frontend.h @@ -0,0 +1,69 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_FRONTEND_H_ +#define ANDROID_HARDWARE_TV_TUNER_V1_0_FRONTEND_H_ + +#include +#include + +using namespace std; + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::tv::tuner::V1_0::FrontendId; +using ::android::hardware::tv::tuner::V1_0::FrontendType; +using ::android::hardware::tv::tuner::V1_0::IFrontend; +using ::android::hardware::tv::tuner::V1_0::IFrontendCallback; +using ::android::hardware::tv::tuner::V1_0::Result; + +class Frontend : public IFrontend { + public: + Frontend(); + Frontend(FrontendType type, FrontendId id); + + virtual Return close() override; + + virtual Return setCallback(const sp& callback) override; + + virtual Return tune(const FrontendSettings& settings) override; + + virtual Return stopTune() override; + + FrontendType getFrontendType(); + + FrontendId getFrontendId(); + + private: + virtual ~Frontend(); + sp mCallback; + FrontendType mType = FrontendType::UNDEFINED; + FrontendId mId = 0; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_FRONTEND_H_ diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp new file mode 100644 index 0000000000..67ec754579 --- /dev/null +++ b/tv/tuner/1.0/default/Tuner.cpp @@ -0,0 +1,79 @@ +/* + * 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 "android.hardware.tv.tuner@1.0-Tuner" + +#include "Tuner.h" +#include +#include +#include "Frontend.h" + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +Tuner::Tuner() { + // Static Frontends array to maintain local frontends information + // Array index matches their FrontendId in the default impl + mFrontendSize = 8; + mFrontends.resize(mFrontendSize); + mFrontends[0] = new Frontend(); + mFrontends[1] = new Frontend(FrontendType::ATSC, 1); + mFrontends[2] = new Frontend(FrontendType::DVBC, 2); + mFrontends[3] = new Frontend(FrontendType::DVBS, 3); + mFrontends[4] = new Frontend(FrontendType::DVBT, 4); + mFrontends[5] = new Frontend(FrontendType::ISDBT, 5); + mFrontends[6] = new Frontend(FrontendType::ANALOG, 6); + mFrontends[7] = new Frontend(FrontendType::ATSC, 7); +} + +Tuner::~Tuner() {} + +Return Tuner::getFrontendIds(getFrontendIds_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + vector frontendIds; + frontendIds.resize(mFrontendSize); + for (int i = 0; i < mFrontendSize; i++) { + frontendIds[i] = mFrontends[i]->getFrontendId(); + } + + _hidl_cb(Result::SUCCESS, frontendIds); + return Void(); +} + +Return Tuner::openFrontendById(uint32_t frontendId, openFrontendById_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + if (frontendId >= mFrontendSize || frontendId < 0) { + ALOGW("[ WARN ] Frontend with id %d isn't available", frontendId); + _hidl_cb(Result::UNAVAILABLE, nullptr); + return Void(); + } + + _hidl_cb(Result::SUCCESS, mFrontends[frontendId]); + return Void(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h new file mode 100644 index 0000000000..2152c899c8 --- /dev/null +++ b/tv/tuner/1.0/default/Tuner.h @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_TUNER_H_ +#define ANDROID_HARDWARE_TV_TUNER_V1_0_TUNER_H_ + +#include +#include "Frontend.h" + +using namespace std; + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +class Tuner : public ITuner { + public: + Tuner(); + virtual Return getFrontendIds(getFrontendIds_cb _hidl_cb) override; + + virtual Return openFrontendById(uint32_t frontendId, + openFrontendById_cb _hidl_cb) override; + + private: + virtual ~Tuner(); + // Static mFrontends array to maintain local frontends information + vector> mFrontends; + // To maintain how many Frontends we have + int mFrontendSize; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_TUNER_H_ diff --git a/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.rc b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.rc new file mode 100644 index 0000000000..ad72fae706 --- /dev/null +++ b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.rc @@ -0,0 +1,9 @@ +service vendor.tuner-hal-1-0 /vendor/bin/hw/android.hardware.tv.tuner@1.0-service-lazy + interface android.hardware.tv.tuner@1.0::ITuner default + oneshot + disabled + class hal + user media + group mediadrm drmrpc + ioprio rt 4 + writepid /dev/cpuset/foreground/tasks \ No newline at end of file diff --git a/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.xml b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.xml new file mode 100644 index 0000000000..4bcfe10685 --- /dev/null +++ b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.xml @@ -0,0 +1,11 @@ + + + android.hardware.tv.tuner + hwbinder + 1.0 + + ITuner + default + + + \ No newline at end of file diff --git a/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.rc b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.rc new file mode 100644 index 0000000000..6d59ed75bb --- /dev/null +++ b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.rc @@ -0,0 +1,6 @@ +service vendor.tuner-hal-1-0 /vendor/bin/hw/android.hardware.tv.tuner@1.0-service + class hal + user media + group mediadrm drmrpc + ioprio rt 4 + writepid /dev/cpuset/foreground/tasks \ No newline at end of file diff --git a/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.xml b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.xml new file mode 100644 index 0000000000..4bcfe10685 --- /dev/null +++ b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.xml @@ -0,0 +1,11 @@ + + + android.hardware.tv.tuner + hwbinder + 1.0 + + ITuner + default + + + \ No newline at end of file diff --git a/tv/tuner/1.0/default/service.cpp b/tv/tuner/1.0/default/service.cpp new file mode 100644 index 0000000000..581d269b9e --- /dev/null +++ b/tv/tuner/1.0/default/service.cpp @@ -0,0 +1,58 @@ +/* + * Copyright 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_NDEBUG 0 +#ifdef LAZY_SERVICE +#define LOG_TAG "android.hardware.tv.tuner@1.0-service-lazy" +#else +#define LOG_TAG "android.hardware.tv.tuner@1.0-service" +#endif + +#include +#include +#include + +#include "Tuner.h" + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::LazyServiceRegistrar; +using android::hardware::tv::tuner::V1_0::ITuner; +using android::hardware::tv::tuner::V1_0::implementation::Tuner; + +#ifdef LAZY_SERVICE +const bool kLazyService = true; +#else +const bool kLazyService = false; +#endif + +int main() { + configureRpcThreadpool(8, true /* callerWillJoin */); + + // Setup hwbinder service + android::sp service = new Tuner(); + android::status_t status; + if (kLazyService) { + auto serviceRegistrar = std::make_shared(); + status = serviceRegistrar->registerService(service); + } else { + status = service->registerAsService(); + } + LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering tuner service: %d", status); + + joinRpcThreadpool(); + return 0; +} From 01f5eacdccd0a9cf602df9bce50829cdc566059d Mon Sep 17 00:00:00 2001 From: Amy Date: Fri, 9 Aug 2019 16:34:55 -0700 Subject: [PATCH 0068/1022] Tuner HAL VTS for Tuner and Frontend Interface. Bug: 135708935 Test: Manual Change-Id: I5be2206ffe606ccc5464635f9a26e2c281930a0b --- tv/tuner/1.0/vts/functional/Android.bp | 32 ++ .../VtsHalTvTunerV1_0TargetTest.cpp | 307 ++++++++++++++++++ 2 files changed, 339 insertions(+) create mode 100644 tv/tuner/1.0/vts/functional/Android.bp create mode 100644 tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp new file mode 100644 index 0000000000..faf566c847 --- /dev/null +++ b/tv/tuner/1.0/vts/functional/Android.bp @@ -0,0 +1,32 @@ +// +// 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. +// + +cc_test { + name: "VtsHalTvTunerV1_0TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalTvTunerV1_0TargetTest.cpp"], + static_libs: [ + "android.hardware.tv.tuner@1.0", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "libhidlallocatorutils", + "libhidlmemory", + ], + shared_libs: [ + "libbinder", + ], + test_suites: ["general-tests"], +} diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp new file mode 100644 index 0000000000..4840a02e25 --- /dev/null +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -0,0 +1,307 @@ +/* + * 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 "Tuner_hidl_hal_test" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WAIT_TIMEOUT 3000000000 + +using android::Condition; +using android::IMemory; +using android::IMemoryHeap; +using android::MemoryDealer; +using android::Mutex; +using android::sp; +using android::hardware::fromHeap; +using android::hardware::hidl_string; +using android::hardware::hidl_vec; +using android::hardware::HidlMemory; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::tv::tuner::V1_0::FrontendAtscModulation; +using android::hardware::tv::tuner::V1_0::FrontendAtscSettings; +using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings; +using android::hardware::tv::tuner::V1_0::FrontendEventType; +using android::hardware::tv::tuner::V1_0::FrontendId; +using android::hardware::tv::tuner::V1_0::FrontendInnerFec; +using android::hardware::tv::tuner::V1_0::FrontendSettings; +using android::hardware::tv::tuner::V1_0::IFrontend; +using android::hardware::tv::tuner::V1_0::IFrontendCallback; +using android::hardware::tv::tuner::V1_0::ITuner; +using android::hardware::tv::tuner::V1_0::Result; + +namespace { + +class FrontendCallback : public IFrontendCallback { + public: + virtual Return onEvent(FrontendEventType frontendEventType) override { + android::Mutex::Autolock autoLock(mMsgLock); + mEventReceived = true; + mEventType = frontendEventType; + mMsgCondition.signal(); + return Void(); + } + + virtual Return onDiseqcMessage(const hidl_vec& diseqcMessage) override { + android::Mutex::Autolock autoLock(mMsgLock); + mDiseqcMessageReceived = true; + mEventMessage = diseqcMessage; + mMsgCondition.signal(); + return Void(); + } + + void testOnEvent(sp& frontend, FrontendSettings settings); + void testOnDiseqcMessage(sp& frontend, FrontendSettings settings); + + private: + bool mEventReceived = false; + bool mDiseqcMessageReceived = false; + FrontendEventType mEventType; + hidl_vec mEventMessage; + android::Mutex mMsgLock; + android::Condition mMsgCondition; +}; + +void FrontendCallback::testOnEvent(sp& frontend, FrontendSettings settings) { + Result result = frontend->tune(settings); + + EXPECT_TRUE(result == Result::SUCCESS); + + android::Mutex::Autolock autoLock(mMsgLock); + while (!mEventReceived) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "event not received within timeout"; + return; + } + } +} + +void FrontendCallback::testOnDiseqcMessage(sp& frontend, FrontendSettings settings) { + Result result = frontend->tune(settings); + + EXPECT_TRUE(result == Result::SUCCESS); + + android::Mutex::Autolock autoLock(mMsgLock); + while (!mDiseqcMessageReceived) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "diseqc message not received within timeout"; + return; + } + } +} + +// Test environment for Tuner HIDL HAL. +class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static TunerHidlEnvironment* Instance() { + static TunerHidlEnvironment* instance = new TunerHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { registerTestService(); } +}; + +class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + mService = ::testing::VtsHalHidlTargetTestBase::getService( + TunerHidlEnvironment::Instance()->getServiceName()); + ASSERT_NE(mService, nullptr); + } + + sp mService; + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp mFrontend; + sp mFrontendCallback; + + ::testing::AssertionResult createFrontend(int32_t frontendId); + ::testing::AssertionResult tuneFrontend(int32_t frontendId); + ::testing::AssertionResult stopTuneFrontend(int32_t frontendId); + ::testing::AssertionResult closeFrontend(int32_t frontendId); +}; + +::testing::AssertionResult TunerHidlTest::createFrontend(int32_t frontendId) { + Result status; + + mService->openFrontendById(frontendId, [&](Result result, const sp& frontend) { + mFrontend = frontend; + status = result; + }); + if (status != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + + mFrontendCallback = new FrontendCallback(); + auto callbackStatus = mFrontend->setCallback(mFrontendCallback); + + return ::testing::AssertionResult(callbackStatus.isOk()); +} + +::testing::AssertionResult TunerHidlTest::tuneFrontend(int32_t frontendId) { + if (createFrontend(frontendId) == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + // Frontend Settings for testing + FrontendSettings frontendSettings; + FrontendAtscSettings frontendAtscSettings{ + .frequency = 0, + .modulation = FrontendAtscModulation::UNDEFINED, + }; + frontendSettings.atsc() = frontendAtscSettings; + mFrontendCallback->testOnEvent(mFrontend, frontendSettings); + + FrontendDvbtSettings frontendDvbtSettings{ + .frequency = 0, + .modulation = FrontendAtscModulation::UNDEFINED, + .fec = FrontendInnerFec::FEC_UNDEFINED, + }; + frontendSettings.dvbt(frontendDvbtSettings); + mFrontendCallback->testOnEvent(mFrontend, frontendSettings); + + return ::testing::AssertionResult(true); +} + +::testing::AssertionResult TunerHidlTest::stopTuneFrontend(int32_t frontendId) { + Result status; + if (createFrontend(frontendId) == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + status = mFrontend->stopTune(); + return ::testing::AssertionResult(status == Result::SUCCESS); +} + +::testing::AssertionResult TunerHidlTest::closeFrontend(int32_t frontendId) { + Result status; + if (createFrontend(frontendId) == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + status = mFrontend->close(); + return ::testing::AssertionResult(status == Result::SUCCESS); +} + +TEST_F(TunerHidlTest, CreateFrontend) { + Result status; + hidl_vec feIds; + + description("Create Frontends"); + mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { + status = result; + feIds = frontendIds; + }); + + if (feIds.size() == 0) { + ALOGW("[ WARN ] Frontend isn't available"); + return; + } + + for (size_t i = 0; i < feIds.size(); i++) { + ASSERT_TRUE(createFrontend(feIds[i])); + } +} + +TEST_F(TunerHidlTest, TuneFrontend) { + Result status; + hidl_vec feIds; + + description("Tune Frontends and check callback onEvent"); + mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { + status = result; + feIds = frontendIds; + }); + + if (feIds.size() == 0) { + ALOGW("[ WARN ] Frontend isn't available"); + return; + } + + for (size_t i = 0; i < feIds.size(); i++) { + ASSERT_TRUE(tuneFrontend(feIds[i])); + } +} + +TEST_F(TunerHidlTest, StopTuneFrontend) { + Result status; + hidl_vec feIds; + + description("stopTune Frontends"); + mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { + status = result; + feIds = frontendIds; + }); + + if (feIds.size() == 0) { + ALOGW("[ WARN ] Frontend isn't available"); + return; + } + + for (size_t i = 0; i < feIds.size(); i++) { + ASSERT_TRUE(stopTuneFrontend(feIds[i])); + } +} + +TEST_F(TunerHidlTest, CloseFrontend) { + Result status; + hidl_vec feIds; + + description("Close Frontends"); + mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { + status = result; + feIds = frontendIds; + }); + + if (feIds.size() == 0) { + ALOGW("[ WARN ] Frontend isn't available"); + return; + } + + for (size_t i = 0; i < feIds.size(); i++) { + ASSERT_TRUE(closeFrontend(feIds[i])); + } +} + +} // namespace + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(TunerHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + TunerHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} From d2a82466d82bdf5019ba86c3b8a6f0da2acef57e Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Tue, 30 Jul 2019 11:57:17 -0700 Subject: [PATCH 0069/1022] Add methods to get or set camera parameters This change adds new methods to set and get camera parameters. As the vendor may handle a parameter set request with invalid value, a set method returns an effective value with a status code. Bug: 138328396 Test: VTS Change-Id: I278dad6c285fb9b341be3517cde09359da14cda6 Signed-off-by: Changyeon Jo --- automotive/evs/1.1/IEvsCamera.hal | 55 +++ automotive/evs/1.1/IEvsCameraStream.hal | 2 +- automotive/evs/1.1/default/EvsCamera.cpp | 36 +- automotive/evs/1.1/default/EvsCamera.h | 5 + automotive/evs/1.1/types.hal | 94 +++++- .../evs/1.1/vts/functional/FrameHandler.cpp | 53 ++- .../evs/1.1/vts/functional/FrameHandler.h | 6 +- .../functional/VtsHalEvsV1_1TargetTest.cpp | 315 +++++++++++++++++- 8 files changed, 540 insertions(+), 26 deletions(-) diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal index e7f6bb7b5b..d4263b7e20 100644 --- a/automotive/evs/1.1/IEvsCamera.hal +++ b/automotive/evs/1.1/IEvsCamera.hal @@ -54,4 +54,59 @@ interface IEvsCamera extends @1.0::IEvsCamera { * @return result Return EvsResult::OK if this call is successful. */ doneWithFrame_1_1(BufferDesc buffer) generates (EvsResult result); + + /** + * Requests to be a master client. + * + * When multiple clients subscribe to a single camera hardware and one of + * them adjusts a camera parameter such as the contrast, it may disturb + * other clients' operations. Therefore, the client must call this method + * to be a master client. Once it becomes a master, it will be able to + * change camera parameters until either it dies or explicitly gives up the + * role. + * + * @return result EvsResult::OK if a master role is granted. + * EvsResult::OWNERSHIP_LOST if there is already a + * master client. + */ + setMaster() generates (EvsResult result); + + + /** + * Retires from a master client role. + * + * @return result EvsResult::OK if this call is successful. + * EvsResult::INVALID_ARG if the caller client is not a + * master client. + */ + unsetMaster() generates (EvsResult result); + + /** + * Requests to set a camera parameter. + * + * @param id The identifier of camera parameter, CameraParam enum. + * value A desired parameter value. + * @return result EvsResult::OK if it succeeds to set a parameter. + * EvsResult::INVALID_ARG if either the request is + * not made by a master client, or a requested + * parameter is not supported. + * EvsResult::UNDERLYING_SERVICE_ERROR if it fails to + * program a value by any other reason. + * effectiveValue A programmed parameter value. This may differ + * from what the client gives if, for example, the + * driver does not support a target parameter. + */ + setParameter(CameraParam id, int32_t value) + generates (EvsResult result, int32_t effectiveValue); + + /** + * Retrieves a value of given camera parameter. + * + * @param id The identifier of camera parameter, CameraParam enum. + * @return result EvsResult::OK if it succeeds to read a parameter. + * EvsResult::INVALID_ARG if either a requested parameter is + * not supported. + * value A value of requested camera parameter. + */ + getParameter(CameraParam id) generates(EvsResult result, int32_t value); }; diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal index cd058a5540..7c7f832103 100644 --- a/automotive/evs/1.1/IEvsCameraStream.hal +++ b/automotive/evs/1.1/IEvsCameraStream.hal @@ -19,7 +19,7 @@ package android.hardware.automotive.evs@1.1; import @1.0::IEvsCameraStream; /** - * Implemented on client side to receive asynchronous video frame deliveries. + * Implemented on client side to receive asynchronous streaming event deliveries. */ interface IEvsCameraStream extends @1.0::IEvsCameraStream { /** diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp index 62d9826f24..ae293b6ba0 100644 --- a/automotive/evs/1.1/default/EvsCamera.cpp +++ b/automotive/evs/1.1/default/EvsCamera.cpp @@ -258,6 +258,38 @@ Return EvsCamera::resumeVideoStream() { } +Return EvsCamera::setMaster() { + // Default implementation does not expect multiple subscribers and therefore + // return a success code always. + return EvsResult::OK; +} + + +Return EvsCamera::unsetMaster() { + // Default implementation does not expect multiple subscribers and therefore + // return a success code always. + return EvsResult::OK; +} + + +Return EvsCamera::setParameter(CameraParam id, int32_t value, + setParameter_cb _hidl_cb) { + // Default implementation does not support this. + (void)id; + (void)value; + _hidl_cb(EvsResult::INVALID_ARG, 0); + return Void(); +} + + +Return EvsCamera::getParameter(CameraParam id, getParameter_cb _hidl_cb) { + // Default implementation does not support this. + (void)id; + _hidl_cb(EvsResult::INVALID_ARG, 0); + return Void(); +} + + bool EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) { if (bufferCount < 1) { ALOGE("Ignoring request to set buffer count to zero"); @@ -468,7 +500,9 @@ void EvsCamera::generateFrames() { // If we've been asked to stop, send an event to signal the actual end of stream EvsEvent event; - event.info(EvsEventType::STREAM_STOPPED); + InfoEventDesc desc = {}; + desc.aType = InfoEventType::STREAM_STOPPED; + event.info(desc); auto result = mStream->notifyEvent(event); if (!result.isOk()) { ALOGE("Error delivering end of stream marker"); diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h index 0982464b59..6cb1cfbcff 100644 --- a/automotive/evs/1.1/default/EvsCamera.h +++ b/automotive/evs/1.1/default/EvsCamera.h @@ -60,6 +60,11 @@ public: Return pauseVideoStream() override; Return resumeVideoStream() override; Return doneWithFrame_1_1(const BufferDesc_1_1& buffer) override; + Return setMaster() override; + Return unsetMaster() override; + Return setParameter(CameraParam id, int32_t value, + setParameter_cb _hidl_cb) override; + Return getParameter(CameraParam id, getParameter_cb _hidl_cb) override; // Implementation details EvsCamera(const char *id); diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal index ff6ab4e785..2677018a40 100644 --- a/automotive/evs/1.1/types.hal +++ b/automotive/evs/1.1/types.hal @@ -48,9 +48,9 @@ struct BufferDesc { }; /** - * EVS event types + * Types of informative streaming events */ -enum EvsEventType : uint32_t { +enum InfoEventType : uint32_t { /** * Video stream is started */ @@ -67,6 +67,25 @@ enum EvsEventType : uint32_t { * Timeout happens */ TIMEOUT, + /** + * Camera parameter is changed; payload contains a changed parameter ID and + * its value + */ + PARAMETER_CHANGED, +}; + +/** + * Structure that describes informative events occurred during EVS is streaming + */ +struct InfoEventDesc { + /** + * Type of an informative event + */ + InfoEventType aType; + /** + * Possible additional information + */ + uint32_t[4] payload; }; /** @@ -80,5 +99,74 @@ safe_union EvsEvent { /** * General streaming events */ - EvsEventType info; + InfoEventDesc info; +}; + +/** + * EVS Camera Parameter + */ +enum CameraParam : uint32_t { + /** + * The brightness of image frames + */ + BRIGHTNESS, + /** + * The contrast of image frames + */ + CONTRAST, + /** + * Automatic gain/exposure control + */ + AUTOGAIN, + /** + * Gain control + */ + GAIN, + /** + * Mirror the image horizontally + */ + HFLIP, + /** + * Mirror the image vertically + */ + VFLIP, + /** + * Automatic Whitebalance + */ + AUTO_WHITE_BALANCE, + /** + * Manual white balance setting as a color temperature in Kelvin. + */ + WHITE_BALANCE_TEMPERATURE, + /** + * Image sharpness adjustment + */ + SHARPNESS, + /** + * Auto Exposure Control modes; auto, manual, shutter priority, or + * aperture priority. + */ + AUTO_EXPOSURE, + /** + * Manual exposure time of the camera + */ + ABSOLUTE_EXPOSURE, + /** + * When AEC is running in either auto or aperture priority, this parameter + * sets whether a frame rate varies. + */ + AUTO_EXPOSURE_PRIORITY, + /** + * Set the focal point of the camera to the specified position. This + * parameter may not be effective when auto focus is enabled. + */ + ABSOLUTE_FOCUS, + /** + * Enables continuous automatic focus adjustments. + */ + AUTO_FOCUS, + /** + * Specify the objective lens focal length as an absolute value. + */ + ABSOLUTE_ZOOM, }; diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp index b7c7f21c2d..a39346b845 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp +++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp @@ -79,7 +79,7 @@ void FrameHandler::blockingStopStream() { // Wait until the stream has actually stopped std::unique_lock lock(mLock); if (mRunning) { - mSignal.wait(lock, [this]() { return !mRunning; }); + mEventSignal.wait(lock, [this]() { return !mRunning; }); } } @@ -110,7 +110,9 @@ bool FrameHandler::isRunning() { void FrameHandler::waitForFrameCount(unsigned frameCount) { // Wait until we've seen at least the requested number of frames (could be more) std::unique_lock lock(mLock); - mSignal.wait(lock, [this, frameCount](){ return mFramesReceived >= frameCount; }); + mFrameSignal.wait(lock, [this, frameCount](){ + return mFramesReceived >= frameCount; + }); } @@ -135,16 +137,21 @@ Return FrameHandler::deliverFrame(const BufferDesc_1_0& bufferArg) { Return FrameHandler::notifyEvent(const EvsEvent& event) { // Local flag we use to keep track of when the stream is stopping - bool timeToStop = false; - auto type = event.getDiscriminator(); if (type == EvsEvent::hidl_discriminator::info) { - if (event.info() == EvsEventType::STREAM_STOPPED) { + mLock.lock(); + mLatestEventDesc = event.info(); + if (mLatestEventDesc.aType == InfoEventType::STREAM_STOPPED) { // Signal that the last frame has been received and the stream is stopped - timeToStop = true; + mRunning = false; + } else if (mLatestEventDesc.aType == InfoEventType::PARAMETER_CHANGED) { + ALOGD("Camera parameter 0x%X is changed to 0x%X", + mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]); } else { - ALOGD("Received an event 0x%X", event.info()); + ALOGD("Received an event 0x%X", mLatestEventDesc.aType); } + mLock.unlock(); + mEventSignal.notify_all(); } else { auto bufDesc = event.buffer(); const AHardwareBuffer_Desc* pDesc = @@ -207,21 +214,14 @@ Return FrameHandler::notifyEvent(const EvsEvent& event) { mHeldBuffers.push(bufDesc); } + mLock.lock(); + ++mFramesReceived; + mLock.unlock(); + mFrameSignal.notify_all(); ALOGD("Frame handling complete"); } - - // Update our received frame count and notify anybody who cares that things have changed - mLock.lock(); - if (timeToStop) { - mRunning = false; - } else { - mFramesReceived++; - } - mLock.unlock(); - mSignal.notify_all(); - return Void(); } @@ -338,3 +338,20 @@ void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) { *height = mFrameHeight; } } + +void FrameHandler::waitForEvent(const InfoEventType aTargetEvent, + InfoEventDesc &eventDesc) { + // Wait until we get an expected parameter change event. + std::unique_lock lock(mLock); + mEventSignal.wait(lock, [this, aTargetEvent, &eventDesc](){ + bool flag = mLatestEventDesc.aType == aTargetEvent; + if (flag) { + eventDesc.aType = mLatestEventDesc.aType; + eventDesc.payload[0] = mLatestEventDesc.payload[0]; + eventDesc.payload[1] = mLatestEventDesc.payload[1]; + } + + return flag; + }); +} + diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h index 49fa736435..c5faecde5f 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.h +++ b/automotive/evs/1.1/vts/functional/FrameHandler.h @@ -67,6 +67,8 @@ public: bool isRunning(); void waitForFrameCount(unsigned frameCount); + void waitForEvent(const InfoEventType aTargetEvent, + InfoEventDesc &eventDesc); void getFramesCounters(unsigned* received, unsigned* displayed); void getFrameDimension(unsigned* width, unsigned* height); @@ -88,7 +90,8 @@ private: // we need to protect all member variables that may be modified while we're streaming // (ie: those below) std::mutex mLock; - std::condition_variable mSignal; + std::condition_variable mEventSignal; + std::condition_variable mFrameSignal; std::queue mHeldBuffers; bool mRunning = false; @@ -96,6 +99,7 @@ private: unsigned mFramesDisplayed = 0; // Simple counter -- rolls over eventually! unsigned mFrameWidth = 0; unsigned mFrameHeight = 0; + InfoEventDesc mLatestEventDesc; }; diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index 4f7082aa26..09a1bd936e 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -124,8 +124,8 @@ protected: sp pEnumerator; // Every test needs access to the service std::vector cameraInfo; // Empty unless/until loadCameraList() is called - bool mIsHwModule; // boolean to tell current module under testing - // is HW module implementation. + bool mIsHwModule; // boolean to tell current module under testing + // is HW module implementation. }; @@ -516,6 +516,317 @@ TEST_F(EvsHidlTest, MultiCameraStream) { } +/* + * CameraParameter: + * Verify that a client can adjust a camera parameter. + */ +TEST_F(EvsHidlTest, CameraParameter) { + ALOGI("Starting CameraParameter test"); + + // Get the camera list + loadCameraList(); + + // Test each reported camera + for (auto&& cam: cameraInfo) { + // Create a camera client + sp pCam = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + .withDefault(nullptr); + ASSERT_NE(pCam, nullptr); + + // Set up per-client frame receiver objects which will fire up its own thread + sp frameHandler = new FrameHandler(pCam, cam, + nullptr, + FrameHandler::eAutoReturn); + ASSERT_NE(frameHandler, nullptr); + + // Start the camera's video stream + bool startResult = frameHandler->startStream(); + ASSERT_TRUE(startResult); + + // Ensure the stream starts + frameHandler->waitForFrameCount(1); + + // Try to program few parameters + EvsResult result = EvsResult::OK; + int32_t val0 = 100; + int32_t val1 = 0; + + result = pCam->setMaster(); + ASSERT_TRUE(result == EvsResult::OK); + + pCam->setParameter(CameraParam::BRIGHTNESS, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + + pCam->getParameter(CameraParam::BRIGHTNESS, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + ASSERT_EQ(val0, val1) << "Values are not matched."; + + val0 = 80; + val1 = 0; + pCam->setParameter(CameraParam::CONTRAST, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + + pCam->getParameter(CameraParam::CONTRAST, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + ASSERT_EQ(val0, val1) << "Values are not matched."; + + val0 = 300; + val1 = 0; + pCam->setParameter(CameraParam::ABSOLUTE_ZOOM, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + + pCam->getParameter(CameraParam::ABSOLUTE_ZOOM, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + ASSERT_EQ(val0, val1) << "Values are not matched."; + + result = pCam->unsetMaster(); + ASSERT_TRUE(result == EvsResult::OK); + + // Shutdown another + frameHandler->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCam); + } +} + + +/* + * MultiCameraParameter: + * Verify that master and non-master clients behave as expected when they try to adjust + * camera parameters. + */ +TEST_F(EvsHidlTest, MultiCameraParameter) { + ALOGI("Starting CameraParameter test"); + + if (mIsHwModule) { + // This test is not for HW module implementation. + return; + } + + // Get the camera list + loadCameraList(); + + // Test each reported camera + for (auto&& cam: cameraInfo) { + // Create two camera clients. + sp pCamMaster = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + .withDefault(nullptr); + ASSERT_NE(pCamMaster, nullptr); + sp pCamNonMaster = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + .withDefault(nullptr); + ASSERT_NE(pCamNonMaster, nullptr); + + // Set up per-client frame receiver objects which will fire up its own thread + sp frameHandlerMaster = + new FrameHandler(pCamMaster, cam, + nullptr, + FrameHandler::eAutoReturn); + ASSERT_NE(frameHandlerMaster, nullptr); + sp frameHandlerNonMaster = + new FrameHandler(pCamNonMaster, cam, + nullptr, + FrameHandler::eAutoReturn); + ASSERT_NE(frameHandlerNonMaster, nullptr); + + // Set one client as the master + EvsResult result = pCamMaster->setMaster(); + ASSERT_TRUE(result == EvsResult::OK); + + // Try to set another client as the master. + result = pCamNonMaster->setMaster(); + ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST); + + // Start the camera's video stream via a master client. + bool startResult = frameHandlerMaster->startStream(); + ASSERT_TRUE(startResult); + + // Ensure the stream starts + frameHandlerMaster->waitForFrameCount(1); + + // Start the camera's video stream via another client + startResult = frameHandlerNonMaster->startStream(); + ASSERT_TRUE(startResult); + + // Ensure the stream starts + frameHandlerNonMaster->waitForFrameCount(1); + + // Try to program CameraParam::BRIGHTNESS + int32_t val0 = 100; + int32_t val1 = 0; + + pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program + result == EvsResult::INVALID_ARG); // Camera parameter is not supported + + // Non-master client expects to receive a parameter change notification + // whenever a master client adjusts it. + InfoEventDesc aNotification = {}; + + pCamMaster->getParameter(CameraParam::BRIGHTNESS, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program + result == EvsResult::INVALID_ARG); // Camera parameter is not supported + if (result == EvsResult::OK) { + ASSERT_EQ(val0, val1) << "Values are not matched."; + + // Verify a change notification + frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); + ASSERT_EQ(InfoEventType::PARAMETER_CHANGED, + static_cast(aNotification.aType)); + ASSERT_EQ(CameraParam::BRIGHTNESS, + static_cast(aNotification.payload[0])); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); + } + + // Try to program CameraParam::CONTRAST + val0 = 80; + val1 = 0; + pCamMaster->setParameter(CameraParam::CONTRAST, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program + result == EvsResult::INVALID_ARG); // Camera parameter is not supported + + if (result == EvsResult::OK) { + pCamMaster->getParameter(CameraParam::CONTRAST, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(val0, val1) << "Values are not matched."; + + + // Verify a change notification + frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); + ASSERT_EQ(InfoEventType::PARAMETER_CHANGED, + static_cast(aNotification.aType)); + ASSERT_EQ(CameraParam::CONTRAST, + static_cast(aNotification.payload[0])); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); + } + + // Try to adjust a parameter via non-master client + pCamNonMaster->setParameter(CameraParam::CONTRAST, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::INVALID_ARG); + + // Non-master client attemps to be a master + result = pCamNonMaster->setMaster(); + ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST); + + // Master client retires from a master role + result = pCamMaster->unsetMaster(); + ASSERT_TRUE(result == EvsResult::OK); + + // Try to adjust a parameter after being retired + pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::INVALID_ARG); + + // Non-master client becomes a master + result = pCamNonMaster->setMaster(); + ASSERT_TRUE(result == EvsResult::OK); + + // Try to adjust a parameter via new master client + pCamNonMaster->setParameter(CameraParam::BRIGHTNESS, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program + result == EvsResult::INVALID_ARG); // Camera parameter is not supported + + // Wait a moment + sleep(1); + + // Verify a change notification + if (result == EvsResult::OK) { + frameHandlerMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); + ASSERT_EQ(static_cast(aNotification.aType), + InfoEventType::PARAMETER_CHANGED); + ASSERT_EQ(static_cast(aNotification.payload[0]), + CameraParam::BRIGHTNESS); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); + } + + // New master retires from a master role + result = pCamNonMaster->unsetMaster(); + ASSERT_TRUE(result == EvsResult::OK); + + // Shutdown + frameHandlerMaster->shutdown(); + frameHandlerNonMaster->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCamMaster); + pEnumerator->closeCamera(pCamNonMaster); + } +} + + int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance()); ::testing::InitGoogleTest(&argc, argv); From 5830754d35d8698ca246da77968634c1eede239b Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Thu, 15 Aug 2019 18:34:53 -0700 Subject: [PATCH 0070/1022] Add MASTER_RELEASED EVS event This change adds new event to notify that a master role becomes available and implements corresponding test cases. Bug: 138328396 Test: VTS Change-Id: Iddea2931a71fef2c7f5847eda12362e88cd52e5b Signed-off-by: Changyeon Jo --- automotive/evs/1.1/types.hal | 4 + .../functional/VtsHalEvsV1_1TargetTest.cpp | 172 ++++++++++++++---- 2 files changed, 144 insertions(+), 32 deletions(-) diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal index 2677018a40..2c6b2ed589 100644 --- a/automotive/evs/1.1/types.hal +++ b/automotive/evs/1.1/types.hal @@ -72,6 +72,10 @@ enum InfoEventType : uint32_t { * its value */ PARAMETER_CHANGED, + /** + * Master role has become available + */ + MASTER_RELEASED, }; /** diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index 09a1bd936e..0d88c07dd2 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -563,16 +563,18 @@ TEST_F(EvsHidlTest, CameraParameter) { ASSERT_TRUE(result == EvsResult::OK || result == EvsResult::INVALID_ARG); - pCam->getParameter(CameraParam::BRIGHTNESS, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - ASSERT_EQ(val0, val1) << "Values are not matched."; + if (result == EvsResult::OK) { + pCam->getParameter(CameraParam::BRIGHTNESS, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + ASSERT_EQ(val0, val1) << "Values are not matched."; + } val0 = 80; val1 = 0; @@ -584,16 +586,18 @@ TEST_F(EvsHidlTest, CameraParameter) { ASSERT_TRUE(result == EvsResult::OK || result == EvsResult::INVALID_ARG); - pCam->getParameter(CameraParam::CONTRAST, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - ASSERT_EQ(val0, val1) << "Values are not matched."; + if (result == EvsResult::OK) { + pCam->getParameter(CameraParam::CONTRAST, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + ASSERT_EQ(val0, val1) << "Values are not matched."; + } val0 = 300; val1 = 0; @@ -605,21 +609,23 @@ TEST_F(EvsHidlTest, CameraParameter) { ASSERT_TRUE(result == EvsResult::OK || result == EvsResult::INVALID_ARG); - pCam->getParameter(CameraParam::ABSOLUTE_ZOOM, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - ASSERT_EQ(val0, val1) << "Values are not matched."; + if (result == EvsResult::OK) { + pCam->getParameter(CameraParam::ABSOLUTE_ZOOM, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + ASSERT_EQ(val0, val1) << "Values are not matched."; + } result = pCam->unsetMaster(); ASSERT_TRUE(result == EvsResult::OK); - // Shutdown another + // Shutdown frameHandler->shutdown(); // Explicitly release the camera @@ -628,13 +634,115 @@ TEST_F(EvsHidlTest, CameraParameter) { } +/* + * CameraMasterRelease + * Verify that non-master client gets notified when the master client either + * terminates or releases a role. + */ +TEST_F(EvsHidlTest, CameraMasterRelease) { + ALOGI("Starting CameraMasterRelease test"); + + if (mIsHwModule) { + // This test is not for HW module implementation. + return; + } + + // Get the camera list + loadCameraList(); + + // Test each reported camera + for (auto&& cam: cameraInfo) { + // Create two camera clients. + sp pCamMaster = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + .withDefault(nullptr); + ASSERT_NE(pCamMaster, nullptr); + sp pCamNonMaster = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + .withDefault(nullptr); + ASSERT_NE(pCamNonMaster, nullptr); + + // Set up per-client frame receiver objects which will fire up its own thread + sp frameHandlerMaster = + new FrameHandler(pCamMaster, cam, + nullptr, + FrameHandler::eAutoReturn); + ASSERT_NE(frameHandlerMaster, nullptr); + sp frameHandlerNonMaster = + new FrameHandler(pCamNonMaster, cam, + nullptr, + FrameHandler::eAutoReturn); + ASSERT_NE(frameHandlerNonMaster, nullptr); + + // Set one client as the master + EvsResult result = pCamMaster->setMaster(); + ASSERT_TRUE(result == EvsResult::OK); + + // Try to set another client as the master. + result = pCamNonMaster->setMaster(); + ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST); + + // Start the camera's video stream via a master client. + bool startResult = frameHandlerMaster->startStream(); + ASSERT_TRUE(startResult); + + // Ensure the stream starts + frameHandlerMaster->waitForFrameCount(1); + + // Start the camera's video stream via another client + startResult = frameHandlerNonMaster->startStream(); + ASSERT_TRUE(startResult); + + // Ensure the stream starts + frameHandlerNonMaster->waitForFrameCount(1); + + // Non-master client expects to receive a master role relesed + // notification. + InfoEventDesc aNotification = {}; + + // Release a master role. + pCamMaster->unsetMaster(); + + // Verify a change notification. + frameHandlerNonMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(InfoEventType::MASTER_RELEASED, + static_cast(aNotification.aType)); + + // Non-master becomes a master. + result = pCamNonMaster->setMaster(); + ASSERT_TRUE(result == EvsResult::OK); + + // Previous master client fails to become a master. + result = pCamMaster->setMaster(); + ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST); + + // Closing current master client. + frameHandlerNonMaster->shutdown(); + + // Verify a change notification. + frameHandlerMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(InfoEventType::MASTER_RELEASED, + static_cast(aNotification.aType)); + + // Closing another stream. + frameHandlerMaster->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCamMaster); + pEnumerator->closeCamera(pCamNonMaster); + } + + +} + + /* * MultiCameraParameter: * Verify that master and non-master clients behave as expected when they try to adjust * camera parameters. */ TEST_F(EvsHidlTest, MultiCameraParameter) { - ALOGI("Starting CameraParameter test"); + ALOGI("Starting MultiCameraParameter test"); if (mIsHwModule) { // This test is not for HW module implementation. From a8c3130a34b3fd392fb2d2ae0fe45848f51f6c37 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 15 Aug 2019 14:42:50 -0700 Subject: [PATCH 0071/1022] composer: refactor ComposerResources into shared library composer@2.x-hal is a header library. Any of the shared libraries it depends on must also be included by anyone who includes composer@2.x-hal. This means when we add a new version of mapper, anyone who uses composer@2.x-hal must also include the new version of the mapper. Vendors that depend on composer@2.x-hal are broken every time we add a new mapper. This patch refactors ComposerResources into a seperate shared library. ComposerResources contains all of the mapper code. composer@2.x-hal will depend on the new composer@2.x-resource hal. Everyone downstream must also add the composer@2.x-resource file now. However, they will not be broken again when we add a new mapper version. Bug: 136016160 Test: Compiles and boots Change-Id: I208a954a941ed65938074cd3efb8a6893a2bc1eb --- graphics/composer/2.1/default/Android.bp | 3 +- graphics/composer/2.1/utils/hal/Android.bp | 6 +- .../include/composer-hal/2.1/ComposerClient.h | 2 +- .../composer-hal/2.1/ComposerCommandEngine.h | 10 +- .../composer-hal/2.1/ComposerResources.h | 592 ------------------ .../composer/2.1/utils/resources/Android.bp | 49 ++ .../2.1/utils/resources/ComposerResources.cpp | 485 ++++++++++++++ .../2.1/ComposerResources.h | 258 ++++++++ graphics/composer/2.2/default/Android.mk | 4 +- graphics/composer/2.2/utils/hal/Android.bp | 2 + .../include/composer-hal/2.2/ComposerClient.h | 4 +- .../composer-hal/2.2/ComposerCommandEngine.h | 2 +- .../composer/2.2/utils/resources/Android.bp | 29 + .../2.2/utils/resources/ComposerResources.cpp | 84 +++ .../2.2/ComposerResources.h | 16 +- graphics/composer/2.3/default/Android.bp | 4 +- .../include/composer-hal/2.3/ComposerClient.h | 2 +- .../composer-hal/2.3/ComposerCommandEngine.h | 2 +- graphics/composer/2.4/default/Android.bp | 4 +- 19 files changed, 935 insertions(+), 623 deletions(-) delete mode 100644 graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h create mode 100644 graphics/composer/2.1/utils/resources/Android.bp create mode 100644 graphics/composer/2.1/utils/resources/ComposerResources.cpp create mode 100644 graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h create mode 100644 graphics/composer/2.2/utils/resources/Android.bp create mode 100644 graphics/composer/2.2/utils/resources/ComposerResources.cpp rename graphics/composer/2.2/utils/{hal/include/composer-hal => resources/include/composer-resources}/2.2/ComposerResources.h (90%) diff --git a/graphics/composer/2.1/default/Android.bp b/graphics/composer/2.1/default/Android.bp index 63accffef7..c4feae553e 100644 --- a/graphics/composer/2.1/default/Android.bp +++ b/graphics/composer/2.1/default/Android.bp @@ -9,8 +9,7 @@ cc_library_shared { ], shared_libs: [ "android.hardware.graphics.composer@2.1", - "android.hardware.graphics.mapper@2.0", - "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.composer@2.1-resources", "libbase", "libcutils", "libfmq", diff --git a/graphics/composer/2.1/utils/hal/Android.bp b/graphics/composer/2.1/utils/hal/Android.bp index 7a501fcc88..ea3666dd28 100644 --- a/graphics/composer/2.1/utils/hal/Android.bp +++ b/graphics/composer/2.1/utils/hal/Android.bp @@ -19,14 +19,12 @@ cc_library_headers { vendor_available: true, shared_libs: [ "android.hardware.graphics.composer@2.1", - "android.hardware.graphics.mapper@2.0", - "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.composer@2.1-resources", "libhardware", // TODO remove hwcomposer2.h dependency ], export_shared_lib_headers: [ "android.hardware.graphics.composer@2.1", - "android.hardware.graphics.mapper@2.0", - "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.composer@2.1-resources", "libhardware", ], header_libs: [ diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h index 095189f91b..47ead41fb0 100644 --- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h +++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include namespace android { diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h index d87110a014..53b9202b97 100644 --- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h +++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h @@ -24,7 +24,7 @@ #include #include -#include +#include // TODO remove hwcomposer_defs.h dependency #include #include @@ -195,7 +195,7 @@ class ComposerCommandEngine : protected CommandReaderBase { bool closeFence = true; const native_handle_t* clientTarget; - ComposerResources::ReplacedBufferHandle replacedClientTarget; + ComposerResources::ReplacedHandle replacedClientTarget(true); auto err = mResources->getDisplayClientTarget(mCurrentDisplay, slot, useCache, rawHandle, &clientTarget, &replacedClientTarget); if (err == Error::NONE) { @@ -226,7 +226,7 @@ class ComposerCommandEngine : protected CommandReaderBase { bool closeFence = true; const native_handle_t* outputBuffer; - ComposerResources::ReplacedBufferHandle replacedOutputBuffer; + ComposerResources::ReplacedHandle replacedOutputBuffer(true); auto err = mResources->getDisplayOutputBuffer(mCurrentDisplay, slot, useCache, rawhandle, &outputBuffer, &replacedOutputBuffer); if (err == Error::NONE) { @@ -369,7 +369,7 @@ class ComposerCommandEngine : protected CommandReaderBase { bool closeFence = true; const native_handle_t* buffer; - ComposerResources::ReplacedBufferHandle replacedBuffer; + ComposerResources::ReplacedHandle replacedBuffer(true); auto err = mResources->getLayerBuffer(mCurrentDisplay, mCurrentLayer, slot, useCache, rawHandle, &buffer, &replacedBuffer); if (err == Error::NONE) { @@ -489,7 +489,7 @@ class ComposerCommandEngine : protected CommandReaderBase { auto rawHandle = readHandle(); const native_handle_t* stream; - ComposerResources::ReplacedStreamHandle replacedStream; + ComposerResources::ReplacedHandle replacedStream(false); auto err = mResources->getLayerSidebandStream(mCurrentDisplay, mCurrentLayer, rawHandle, &stream, &replacedStream); if (err == Error::NONE) { diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h deleted file mode 100644 index 18d184ecb4..0000000000 --- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h +++ /dev/null @@ -1,592 +0,0 @@ -/* - * Copyright 2018 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. - */ - -#pragma once - -#ifndef LOG_TAG -#warning "ComposerResources.h included without LOG_TAG" -#endif - -#include -#include -#include -#include - -#include -#include -#include - -namespace android { -namespace hardware { -namespace graphics { -namespace composer { -namespace V2_1 { -namespace hal { - -// wrapper for IMapper to import buffers and sideband streams -class ComposerHandleImporter { - public: - bool init() { - mMapper3 = mapper::V3_0::IMapper::getService(); - if (mMapper3) { - return true; - } - ALOGD_IF(!mMapper3, "failed to get mapper 3.0 service, falling back to mapper 2.0"); - - mMapper2 = mapper::V2_0::IMapper::getService(); - ALOGE_IF(!mMapper2, "failed to get mapper 2.0 service"); - - return mMapper2 != nullptr; - } - - Error importBuffer(const native_handle_t* rawHandle, const native_handle_t** outBufferHandle) { - if (!rawHandle || (!rawHandle->numFds && !rawHandle->numInts)) { - *outBufferHandle = nullptr; - return Error::NONE; - } - - const native_handle_t* bufferHandle; - if (mMapper2) { - mapper::V2_0::Error error; - mMapper2->importBuffer( - rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) { - error = tmpError; - bufferHandle = static_cast(tmpBufferHandle); - }); - if (error != mapper::V2_0::Error::NONE) { - return Error::NO_RESOURCES; - } - } - if (mMapper3) { - mapper::V3_0::Error error; - mMapper3->importBuffer( - rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) { - error = tmpError; - bufferHandle = static_cast(tmpBufferHandle); - }); - if (error != mapper::V3_0::Error::NONE) { - return Error::NO_RESOURCES; - } - } - - *outBufferHandle = bufferHandle; - return Error::NONE; - } - - void freeBuffer(const native_handle_t* bufferHandle) { - if (bufferHandle) { - if (mMapper2) { - mMapper2->freeBuffer( - static_cast(const_cast(bufferHandle))); - } else if (mMapper3) { - mMapper3->freeBuffer( - static_cast(const_cast(bufferHandle))); - } - } - } - - Error importStream(const native_handle_t* rawHandle, const native_handle_t** outStreamHandle) { - const native_handle_t* streamHandle = nullptr; - if (rawHandle) { - streamHandle = native_handle_clone(rawHandle); - if (!streamHandle) { - return Error::NO_RESOURCES; - } - } - - *outStreamHandle = streamHandle; - return Error::NONE; - } - - void freeStream(const native_handle_t* streamHandle) { - if (streamHandle) { - native_handle_close(streamHandle); - native_handle_delete(const_cast(streamHandle)); - } - } - - private: - sp mMapper2; - sp mMapper3; -}; - -class ComposerHandleCache { - public: - enum class HandleType { - INVALID, - BUFFER, - STREAM, - }; - - ComposerHandleCache(ComposerHandleImporter& importer, HandleType type, uint32_t cacheSize) - : mImporter(importer), mHandleType(type), mHandles(cacheSize, nullptr) {} - - // must be initialized later with initCache - ComposerHandleCache(ComposerHandleImporter& importer) : mImporter(importer) {} - - ~ComposerHandleCache() { - switch (mHandleType) { - case HandleType::BUFFER: - for (auto handle : mHandles) { - mImporter.freeBuffer(handle); - } - break; - case HandleType::STREAM: - for (auto handle : mHandles) { - mImporter.freeStream(handle); - } - break; - default: - break; - } - } - - ComposerHandleCache(const ComposerHandleCache&) = delete; - ComposerHandleCache& operator=(const ComposerHandleCache&) = delete; - - bool initCache(HandleType type, uint32_t cacheSize) { - // already initialized - if (mHandleType != HandleType::INVALID) { - return false; - } - - mHandleType = type; - mHandles.resize(cacheSize, nullptr); - - return true; - } - - Error lookupCache(uint32_t slot, const native_handle_t** outHandle) { - if (slot >= 0 && slot < mHandles.size()) { - *outHandle = mHandles[slot]; - return Error::NONE; - } else { - return Error::BAD_PARAMETER; - } - } - - Error updateCache(uint32_t slot, const native_handle_t* handle, - const native_handle** outReplacedHandle) { - if (slot >= 0 && slot < mHandles.size()) { - auto& cachedHandle = mHandles[slot]; - *outReplacedHandle = cachedHandle; - cachedHandle = handle; - return Error::NONE; - } else { - return Error::BAD_PARAMETER; - } - } - - // when fromCache is true, look up in the cache; otherwise, update the cache - Error getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle, - const native_handle_t** outHandle, const native_handle** outReplacedHandle) { - if (fromCache) { - *outReplacedHandle = nullptr; - return lookupCache(slot, outHandle); - } else { - *outHandle = inHandle; - return updateCache(slot, inHandle, outReplacedHandle); - } - } - - private: - ComposerHandleImporter& mImporter; - HandleType mHandleType = HandleType::INVALID; - std::vector mHandles; -}; - -// layer resource -class ComposerLayerResource { - public: - ComposerLayerResource(ComposerHandleImporter& importer, uint32_t bufferCacheSize) - : mBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, bufferCacheSize), - mSidebandStreamCache(importer, ComposerHandleCache::HandleType::STREAM, 1) {} - - virtual ~ComposerLayerResource() = default; - - Error getBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle, - const native_handle_t** outHandle, const native_handle** outReplacedHandle) { - return mBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle); - } - - Error getSidebandStream(uint32_t slot, bool fromCache, const native_handle_t* inHandle, - const native_handle_t** outHandle, - const native_handle** outReplacedHandle) { - return mSidebandStreamCache.getHandle(slot, fromCache, inHandle, outHandle, - outReplacedHandle); - } - - protected: - ComposerHandleCache mBufferCache; - ComposerHandleCache mSidebandStreamCache; -}; - -// display resource -class ComposerDisplayResource { - public: - enum class DisplayType { - PHYSICAL, - VIRTUAL, - }; - - virtual ~ComposerDisplayResource() = default; - - ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer, - uint32_t outputBufferCacheSize) - : mType(type), - mClientTargetCache(importer), - mOutputBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, - outputBufferCacheSize), - mMustValidate(true) {} - - bool initClientTargetCache(uint32_t cacheSize) { - return mClientTargetCache.initCache(ComposerHandleCache::HandleType::BUFFER, cacheSize); - } - - bool isVirtual() const { return mType == DisplayType::VIRTUAL; } - - Error getClientTarget(uint32_t slot, bool fromCache, const native_handle_t* inHandle, - const native_handle_t** outHandle, - const native_handle** outReplacedHandle) { - return mClientTargetCache.getHandle(slot, fromCache, inHandle, outHandle, - outReplacedHandle); - } - - Error getOutputBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle, - const native_handle_t** outHandle, - const native_handle** outReplacedHandle) { - return mOutputBufferCache.getHandle(slot, fromCache, inHandle, outHandle, - outReplacedHandle); - } - - bool addLayer(Layer layer, std::unique_ptr layerResource) { - auto result = mLayerResources.emplace(layer, std::move(layerResource)); - return result.second; - } - - bool removeLayer(Layer layer) { return mLayerResources.erase(layer) > 0; } - - ComposerLayerResource* findLayerResource(Layer layer) { - auto layerIter = mLayerResources.find(layer); - if (layerIter == mLayerResources.end()) { - return nullptr; - } - - return layerIter->second.get(); - } - - std::vector getLayers() const { - std::vector layers; - layers.reserve(mLayerResources.size()); - for (const auto& layerKey : mLayerResources) { - layers.push_back(layerKey.first); - } - return layers; - } - - void setMustValidateState(bool mustValidate) { mMustValidate = mustValidate; } - - bool mustValidate() const { return mMustValidate; } - - protected: - const DisplayType mType; - ComposerHandleCache mClientTargetCache; - ComposerHandleCache mOutputBufferCache; - bool mMustValidate; - - std::unordered_map> mLayerResources; -}; - -class ComposerResources { - private: - template - class ReplacedHandle; - - public: - static std::unique_ptr create() { - auto resources = std::make_unique(); - return resources->init() ? std::move(resources) : nullptr; - } - - ComposerResources() = default; - virtual ~ComposerResources() = default; - - bool init() { return mImporter.init(); } - - using RemoveDisplay = - std::function& layers)>; - void clear(RemoveDisplay removeDisplay) { - std::lock_guard lock(mDisplayResourcesMutex); - for (const auto& displayKey : mDisplayResources) { - Display display = displayKey.first; - const ComposerDisplayResource& displayResource = *displayKey.second; - removeDisplay(display, displayResource.isVirtual(), displayResource.getLayers()); - } - mDisplayResources.clear(); - } - - Error addPhysicalDisplay(Display display) { - auto displayResource = - createDisplayResource(ComposerDisplayResource::DisplayType::PHYSICAL, 0); - - std::lock_guard lock(mDisplayResourcesMutex); - auto result = mDisplayResources.emplace(display, std::move(displayResource)); - return result.second ? Error::NONE : Error::BAD_DISPLAY; - } - - Error addVirtualDisplay(Display display, uint32_t outputBufferCacheSize) { - auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::VIRTUAL, - outputBufferCacheSize); - - std::lock_guard lock(mDisplayResourcesMutex); - auto result = mDisplayResources.emplace(display, std::move(displayResource)); - return result.second ? Error::NONE : Error::BAD_DISPLAY; - } - - Error removeDisplay(Display display) { - std::lock_guard lock(mDisplayResourcesMutex); - return mDisplayResources.erase(display) > 0 ? Error::NONE : Error::BAD_DISPLAY; - } - - Error setDisplayClientTargetCacheSize(Display display, uint32_t clientTargetCacheSize) { - std::lock_guard lock(mDisplayResourcesMutex); - ComposerDisplayResource* displayResource = findDisplayResourceLocked(display); - if (!displayResource) { - return Error::BAD_DISPLAY; - } - - return displayResource->initClientTargetCache(clientTargetCacheSize) ? Error::NONE - : Error::BAD_PARAMETER; - } - - Error addLayer(Display display, Layer layer, uint32_t bufferCacheSize) { - auto layerResource = createLayerResource(bufferCacheSize); - - std::lock_guard lock(mDisplayResourcesMutex); - ComposerDisplayResource* displayResource = findDisplayResourceLocked(display); - if (!displayResource) { - return Error::BAD_DISPLAY; - } - - return displayResource->addLayer(layer, std::move(layerResource)) ? Error::NONE - : Error::BAD_LAYER; - } - - Error removeLayer(Display display, Layer layer) { - std::lock_guard lock(mDisplayResourcesMutex); - ComposerDisplayResource* displayResource = findDisplayResourceLocked(display); - if (!displayResource) { - return Error::BAD_DISPLAY; - } - - return displayResource->removeLayer(layer) ? Error::NONE : Error::BAD_LAYER; - } - - using ReplacedBufferHandle = ReplacedHandle; - using ReplacedStreamHandle = ReplacedHandle; - - Error getDisplayClientTarget(Display display, uint32_t slot, bool fromCache, - const native_handle_t* rawHandle, - const native_handle_t** outBufferHandle, - ReplacedBufferHandle* outReplacedBuffer) { - return getHandle(display, 0, slot, fromCache, rawHandle, - outBufferHandle, outReplacedBuffer); - } - - Error getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache, - const native_handle_t* rawHandle, - const native_handle_t** outBufferHandle, - ReplacedBufferHandle* outReplacedBuffer) { - return getHandle(display, 0, slot, fromCache, rawHandle, - outBufferHandle, outReplacedBuffer); - } - - Error getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache, - const native_handle_t* rawHandle, const native_handle_t** outBufferHandle, - ReplacedBufferHandle* outReplacedBuffer) { - return getHandle(display, layer, slot, fromCache, rawHandle, - outBufferHandle, outReplacedBuffer); - } - - Error getLayerSidebandStream(Display display, Layer layer, const native_handle_t* rawHandle, - const native_handle_t** outStreamHandle, - ReplacedStreamHandle* outReplacedStream) { - return getHandle(display, layer, 0, false, rawHandle, - outStreamHandle, outReplacedStream); - } - - void setDisplayMustValidateState(Display display, bool mustValidate) { - std::lock_guard lock(mDisplayResourcesMutex); - auto* displayResource = findDisplayResourceLocked(display); - if (displayResource) { - displayResource->setMustValidateState(mustValidate); - } - } - - bool mustValidateDisplay(Display display) { - std::lock_guard lock(mDisplayResourcesMutex); - auto* displayResource = findDisplayResourceLocked(display); - if (displayResource) { - return displayResource->mustValidate(); - } - return false; - } - - protected: - virtual std::unique_ptr createDisplayResource( - ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) { - return std::make_unique(type, mImporter, outputBufferCacheSize); - } - - virtual std::unique_ptr createLayerResource(uint32_t bufferCacheSize) { - return std::make_unique(mImporter, bufferCacheSize); - } - - ComposerDisplayResource* findDisplayResourceLocked(Display display) { - auto iter = mDisplayResources.find(display); - if (iter == mDisplayResources.end()) { - return nullptr; - } - return iter->second.get(); - } - - ComposerHandleImporter mImporter; - - std::mutex mDisplayResourcesMutex; - std::unordered_map> mDisplayResources; - - private: - enum class Cache { - CLIENT_TARGET, - OUTPUT_BUFFER, - LAYER_BUFFER, - LAYER_SIDEBAND_STREAM, - }; - - // When a buffer in the cache is replaced by a new one, we must keep it - // alive until it has been replaced in ComposerHal. - template - class ReplacedHandle { - public: - ReplacedHandle() = default; - ReplacedHandle(const ReplacedHandle&) = delete; - ReplacedHandle& operator=(const ReplacedHandle&) = delete; - - ~ReplacedHandle() { reset(); } - - void reset(ComposerHandleImporter* importer = nullptr, - const native_handle_t* handle = nullptr) { - if (mHandle) { - if (isBuffer) { - mImporter->freeBuffer(mHandle); - } else { - mImporter->freeStream(mHandle); - } - } - - mImporter = importer; - mHandle = handle; - } - - private: - ComposerHandleImporter* mImporter = nullptr; - const native_handle_t* mHandle = nullptr; - }; - - template - Error getHandle(Display display, Layer layer, uint32_t slot, bool fromCache, - const native_handle_t* rawHandle, const native_handle_t** outHandle, - ReplacedHandle* outReplacedHandle) { - Error error; - - // import the raw handle (or ignore raw handle when fromCache is true) - const native_handle_t* importedHandle = nullptr; - if (!fromCache) { - error = (isBuffer) ? mImporter.importBuffer(rawHandle, &importedHandle) - : mImporter.importStream(rawHandle, &importedHandle); - if (error != Error::NONE) { - return error; - } - } - - std::lock_guard lock(mDisplayResourcesMutex); - - // find display/layer resource - const bool needLayerResource = - (cache == Cache::LAYER_BUFFER || cache == Cache::LAYER_SIDEBAND_STREAM); - ComposerDisplayResource* displayResource = findDisplayResourceLocked(display); - ComposerLayerResource* layerResource = (displayResource && needLayerResource) - ? displayResource->findLayerResource(layer) - : nullptr; - - // lookup or update cache - const native_handle_t* replacedHandle = nullptr; - if (displayResource && (!needLayerResource || layerResource)) { - switch (cache) { - case Cache::CLIENT_TARGET: - error = displayResource->getClientTarget(slot, fromCache, importedHandle, - outHandle, &replacedHandle); - break; - case Cache::OUTPUT_BUFFER: - error = displayResource->getOutputBuffer(slot, fromCache, importedHandle, - outHandle, &replacedHandle); - break; - case Cache::LAYER_BUFFER: - error = layerResource->getBuffer(slot, fromCache, importedHandle, outHandle, - &replacedHandle); - break; - case Cache::LAYER_SIDEBAND_STREAM: - error = layerResource->getSidebandStream(slot, fromCache, importedHandle, - outHandle, &replacedHandle); - break; - default: - error = Error::BAD_PARAMETER; - break; - } - - if (error != Error::NONE) { - ALOGW("invalid cache %d slot %d", int(cache), int(slot)); - } - } else if (!displayResource) { - error = Error::BAD_DISPLAY; - } else { - error = Error::BAD_LAYER; - } - - // clean up on errors - if (error != Error::NONE) { - if (!fromCache) { - if (isBuffer) { - mImporter.freeBuffer(importedHandle); - } else { - mImporter.freeStream(importedHandle); - } - } - return error; - } - - outReplacedHandle->reset(&mImporter, replacedHandle); - - return Error::NONE; - } -}; - -} // namespace hal -} // namespace V2_1 -} // namespace composer -} // namespace graphics -} // namespace hardware -} // namespace android diff --git a/graphics/composer/2.1/utils/resources/Android.bp b/graphics/composer/2.1/utils/resources/Android.bp new file mode 100644 index 0000000000..e7ba458f9a --- /dev/null +++ b/graphics/composer/2.1/utils/resources/Android.bp @@ -0,0 +1,49 @@ +// +// 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. + +cc_library_shared { + name: "android.hardware.graphics.composer@2.1-resources", + defaults: ["hidl_defaults"], + vendor_available: true, + shared_libs: [ + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", + "libcutils", + "libhardware", // TODO remove hwcomposer2.h dependency + "libhidlbase", + "liblog", + "libutils", + ], + export_shared_lib_headers: [ + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", + "libhardware", + "libhidlbase", + "liblog", + "libutils", + ], + header_libs: [ + "android.hardware.graphics.composer@2.1-command-buffer", + ], + export_header_lib_headers: [ + "android.hardware.graphics.composer@2.1-command-buffer", + ], + export_include_dirs: ["include"], + srcs: [ + "ComposerResources.cpp", + ], +} diff --git a/graphics/composer/2.1/utils/resources/ComposerResources.cpp b/graphics/composer/2.1/utils/resources/ComposerResources.cpp new file mode 100644 index 0000000000..d28eedca1b --- /dev/null +++ b/graphics/composer/2.1/utils/resources/ComposerResources.cpp @@ -0,0 +1,485 @@ +/* + * Copyright 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 "ComposerResources" + +#include "composer-resources/2.1/ComposerResources.h" + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_1 { +namespace hal { + +bool ComposerHandleImporter::init() { + mMapper3 = mapper::V3_0::IMapper::getService(); + if (mMapper3) { + return true; + } + ALOGI_IF(!mMapper3, "failed to get mapper 3.0 service, falling back to mapper 2.0"); + + mMapper2 = mapper::V2_0::IMapper::getService(); + ALOGE_IF(!mMapper2, "failed to get mapper 2.0 service"); + + return mMapper2 != nullptr; +} + +Error ComposerHandleImporter::importBuffer(const native_handle_t* rawHandle, + const native_handle_t** outBufferHandle) { + if (!rawHandle || (!rawHandle->numFds && !rawHandle->numInts)) { + *outBufferHandle = nullptr; + return Error::NONE; + } + + const native_handle_t* bufferHandle; + if (mMapper2) { + mapper::V2_0::Error error; + mMapper2->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) { + error = tmpError; + bufferHandle = static_cast(tmpBufferHandle); + }); + if (error != mapper::V2_0::Error::NONE) { + return Error::NO_RESOURCES; + } + } + if (mMapper3) { + mapper::V3_0::Error error; + mMapper3->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) { + error = tmpError; + bufferHandle = static_cast(tmpBufferHandle); + }); + if (error != mapper::V3_0::Error::NONE) { + return Error::NO_RESOURCES; + } + } + + *outBufferHandle = bufferHandle; + return Error::NONE; +} + +void ComposerHandleImporter::freeBuffer(const native_handle_t* bufferHandle) { + if (bufferHandle) { + if (mMapper2) { + mMapper2->freeBuffer(static_cast(const_cast(bufferHandle))); + } else if (mMapper3) { + mMapper3->freeBuffer(static_cast(const_cast(bufferHandle))); + } + } +} + +Error ComposerHandleImporter::importStream(const native_handle_t* rawHandle, + const native_handle_t** outStreamHandle) { + const native_handle_t* streamHandle = nullptr; + if (rawHandle) { + streamHandle = native_handle_clone(rawHandle); + if (!streamHandle) { + return Error::NO_RESOURCES; + } + } + + *outStreamHandle = streamHandle; + return Error::NONE; +} + +void ComposerHandleImporter::freeStream(const native_handle_t* streamHandle) { + if (streamHandle) { + native_handle_close(streamHandle); + native_handle_delete(const_cast(streamHandle)); + } +} + +ComposerHandleCache::ComposerHandleCache(ComposerHandleImporter& importer, HandleType type, + uint32_t cacheSize) + : mImporter(importer), mHandleType(type), mHandles(cacheSize, nullptr) {} + +// must be initialized later with initCache +ComposerHandleCache::ComposerHandleCache(ComposerHandleImporter& importer) : mImporter(importer) {} + +ComposerHandleCache::~ComposerHandleCache() { + switch (mHandleType) { + case HandleType::BUFFER: + for (auto handle : mHandles) { + mImporter.freeBuffer(handle); + } + break; + case HandleType::STREAM: + for (auto handle : mHandles) { + mImporter.freeStream(handle); + } + break; + default: + break; + } +} + +bool ComposerHandleCache::initCache(HandleType type, uint32_t cacheSize) { + // already initialized + if (mHandleType != HandleType::INVALID) { + return false; + } + + mHandleType = type; + mHandles.resize(cacheSize, nullptr); + + return true; +} + +Error ComposerHandleCache::lookupCache(uint32_t slot, const native_handle_t** outHandle) { + if (slot >= 0 && slot < mHandles.size()) { + *outHandle = mHandles[slot]; + return Error::NONE; + } else { + return Error::BAD_PARAMETER; + } +} + +Error ComposerHandleCache::updateCache(uint32_t slot, const native_handle_t* handle, + const native_handle** outReplacedHandle) { + if (slot >= 0 && slot < mHandles.size()) { + auto& cachedHandle = mHandles[slot]; + *outReplacedHandle = cachedHandle; + cachedHandle = handle; + return Error::NONE; + } else { + return Error::BAD_PARAMETER; + } +} + +// when fromCache is true, look up in the cache; otherwise, update the cache +Error ComposerHandleCache::getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle, + const native_handle_t** outHandle, + const native_handle** outReplacedHandle) { + if (fromCache) { + *outReplacedHandle = nullptr; + return lookupCache(slot, outHandle); + } else { + *outHandle = inHandle; + return updateCache(slot, inHandle, outReplacedHandle); + } +} + +ComposerLayerResource::ComposerLayerResource(ComposerHandleImporter& importer, + uint32_t bufferCacheSize) + : mBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, bufferCacheSize), + mSidebandStreamCache(importer, ComposerHandleCache::HandleType::STREAM, 1) {} + +Error ComposerLayerResource::getBuffer(uint32_t slot, bool fromCache, + const native_handle_t* inHandle, + const native_handle_t** outHandle, + const native_handle** outReplacedHandle) { + return mBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle); +} + +Error ComposerLayerResource::getSidebandStream(uint32_t slot, bool fromCache, + const native_handle_t* inHandle, + const native_handle_t** outHandle, + const native_handle** outReplacedHandle) { + return mSidebandStreamCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle); +} + +ComposerDisplayResource::ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer, + uint32_t outputBufferCacheSize) + : mType(type), + mClientTargetCache(importer), + mOutputBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, outputBufferCacheSize), + mMustValidate(true) {} + +bool ComposerDisplayResource::initClientTargetCache(uint32_t cacheSize) { + return mClientTargetCache.initCache(ComposerHandleCache::HandleType::BUFFER, cacheSize); +} + +bool ComposerDisplayResource::isVirtual() const { + return mType == DisplayType::VIRTUAL; +} + +Error ComposerDisplayResource::getClientTarget(uint32_t slot, bool fromCache, + const native_handle_t* inHandle, + const native_handle_t** outHandle, + const native_handle** outReplacedHandle) { + return mClientTargetCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle); +} + +Error ComposerDisplayResource::getOutputBuffer(uint32_t slot, bool fromCache, + const native_handle_t* inHandle, + const native_handle_t** outHandle, + const native_handle** outReplacedHandle) { + return mOutputBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle); +} + +bool ComposerDisplayResource::addLayer(Layer layer, + std::unique_ptr layerResource) { + auto result = mLayerResources.emplace(layer, std::move(layerResource)); + return result.second; +} + +bool ComposerDisplayResource::removeLayer(Layer layer) { + return mLayerResources.erase(layer) > 0; +} + +ComposerLayerResource* ComposerDisplayResource::findLayerResource(Layer layer) { + auto layerIter = mLayerResources.find(layer); + if (layerIter == mLayerResources.end()) { + return nullptr; + } + + return layerIter->second.get(); +} + +std::vector ComposerDisplayResource::getLayers() const { + std::vector layers; + layers.reserve(mLayerResources.size()); + for (const auto& layerKey : mLayerResources) { + layers.push_back(layerKey.first); + } + return layers; +} + +void ComposerDisplayResource::setMustValidateState(bool mustValidate) { + mMustValidate = mustValidate; +} + +bool ComposerDisplayResource::mustValidate() const { + return mMustValidate; +} + +std::unique_ptr ComposerResources::create() { + auto resources = std::make_unique(); + return resources->init() ? std::move(resources) : nullptr; +} + +bool ComposerResources::init() { + return mImporter.init(); +} + +void ComposerResources::clear(RemoveDisplay removeDisplay) { + std::lock_guard lock(mDisplayResourcesMutex); + for (const auto& displayKey : mDisplayResources) { + Display display = displayKey.first; + const ComposerDisplayResource& displayResource = *displayKey.second; + removeDisplay(display, displayResource.isVirtual(), displayResource.getLayers()); + } + mDisplayResources.clear(); +} + +Error ComposerResources::addPhysicalDisplay(Display display) { + auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::PHYSICAL, 0); + + std::lock_guard lock(mDisplayResourcesMutex); + auto result = mDisplayResources.emplace(display, std::move(displayResource)); + return result.second ? Error::NONE : Error::BAD_DISPLAY; +} + +Error ComposerResources::addVirtualDisplay(Display display, uint32_t outputBufferCacheSize) { + auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::VIRTUAL, + outputBufferCacheSize); + + std::lock_guard lock(mDisplayResourcesMutex); + auto result = mDisplayResources.emplace(display, std::move(displayResource)); + return result.second ? Error::NONE : Error::BAD_DISPLAY; +} + +Error ComposerResources::removeDisplay(Display display) { + std::lock_guard lock(mDisplayResourcesMutex); + return mDisplayResources.erase(display) > 0 ? Error::NONE : Error::BAD_DISPLAY; +} + +Error ComposerResources::setDisplayClientTargetCacheSize(Display display, + uint32_t clientTargetCacheSize) { + std::lock_guard lock(mDisplayResourcesMutex); + ComposerDisplayResource* displayResource = findDisplayResourceLocked(display); + if (!displayResource) { + return Error::BAD_DISPLAY; + } + + return displayResource->initClientTargetCache(clientTargetCacheSize) ? Error::NONE + : Error::BAD_PARAMETER; +} + +Error ComposerResources::addLayer(Display display, Layer layer, uint32_t bufferCacheSize) { + auto layerResource = createLayerResource(bufferCacheSize); + + std::lock_guard lock(mDisplayResourcesMutex); + ComposerDisplayResource* displayResource = findDisplayResourceLocked(display); + if (!displayResource) { + return Error::BAD_DISPLAY; + } + + return displayResource->addLayer(layer, std::move(layerResource)) ? Error::NONE + : Error::BAD_LAYER; +} + +Error ComposerResources::removeLayer(Display display, Layer layer) { + std::lock_guard lock(mDisplayResourcesMutex); + ComposerDisplayResource* displayResource = findDisplayResourceLocked(display); + if (!displayResource) { + return Error::BAD_DISPLAY; + } + + return displayResource->removeLayer(layer) ? Error::NONE : Error::BAD_LAYER; +} + +Error ComposerResources::getDisplayClientTarget(Display display, uint32_t slot, bool fromCache, + const native_handle_t* rawHandle, + const native_handle_t** outBufferHandle, + ReplacedHandle* outReplacedBuffer) { + return getHandle(display, 0, slot, Cache::CLIENT_TARGET, fromCache, rawHandle, outBufferHandle, + outReplacedBuffer); +} + +Error ComposerResources::getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache, + const native_handle_t* rawHandle, + const native_handle_t** outBufferHandle, + ReplacedHandle* outReplacedBuffer) { + return getHandle(display, 0, slot, Cache::OUTPUT_BUFFER, fromCache, rawHandle, outBufferHandle, + outReplacedBuffer); +} + +Error ComposerResources::getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache, + const native_handle_t* rawHandle, + const native_handle_t** outBufferHandle, + ReplacedHandle* outReplacedBuffer) { + return getHandle(display, layer, slot, Cache::LAYER_BUFFER, fromCache, rawHandle, + outBufferHandle, outReplacedBuffer); +} + +Error ComposerResources::getLayerSidebandStream(Display display, Layer layer, + const native_handle_t* rawHandle, + const native_handle_t** outStreamHandle, + ReplacedHandle* outReplacedStream) { + return getHandle(display, layer, 0, Cache::LAYER_SIDEBAND_STREAM, false, rawHandle, + outStreamHandle, outReplacedStream); +} + +void ComposerResources::setDisplayMustValidateState(Display display, bool mustValidate) { + std::lock_guard lock(mDisplayResourcesMutex); + auto* displayResource = findDisplayResourceLocked(display); + if (displayResource) { + displayResource->setMustValidateState(mustValidate); + } +} + +bool ComposerResources::mustValidateDisplay(Display display) { + std::lock_guard lock(mDisplayResourcesMutex); + auto* displayResource = findDisplayResourceLocked(display); + if (displayResource) { + return displayResource->mustValidate(); + } + return false; +} + +std::unique_ptr ComposerResources::createDisplayResource( + ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) { + return std::make_unique(type, mImporter, outputBufferCacheSize); +} + +std::unique_ptr ComposerResources::createLayerResource( + uint32_t bufferCacheSize) { + return std::make_unique(mImporter, bufferCacheSize); +} + +ComposerDisplayResource* ComposerResources::findDisplayResourceLocked(Display display) { + auto iter = mDisplayResources.find(display); + if (iter == mDisplayResources.end()) { + return nullptr; + } + return iter->second.get(); +} + +Error ComposerResources::getHandle(Display display, Layer layer, uint32_t slot, Cache cache, + bool fromCache, const native_handle_t* rawHandle, + const native_handle_t** outHandle, + ReplacedHandle* outReplacedHandle) { + Error error; + + // import the raw handle (or ignore raw handle when fromCache is true) + const native_handle_t* importedHandle = nullptr; + if (!fromCache) { + error = (outReplacedHandle->isBuffer()) + ? mImporter.importBuffer(rawHandle, &importedHandle) + : mImporter.importStream(rawHandle, &importedHandle); + if (error != Error::NONE) { + return error; + } + } + + std::lock_guard lock(mDisplayResourcesMutex); + + // find display/layer resource + const bool needLayerResource = (cache == ComposerResources::Cache::LAYER_BUFFER || + cache == ComposerResources::Cache::LAYER_SIDEBAND_STREAM); + ComposerDisplayResource* displayResource = findDisplayResourceLocked(display); + ComposerLayerResource* layerResource = (displayResource && needLayerResource) + ? displayResource->findLayerResource(layer) + : nullptr; + + // lookup or update cache + const native_handle_t* replacedHandle = nullptr; + if (displayResource && (!needLayerResource || layerResource)) { + switch (cache) { + case ComposerResources::Cache::CLIENT_TARGET: + error = displayResource->getClientTarget(slot, fromCache, importedHandle, outHandle, + &replacedHandle); + break; + case ComposerResources::Cache::OUTPUT_BUFFER: + error = displayResource->getOutputBuffer(slot, fromCache, importedHandle, outHandle, + &replacedHandle); + break; + case ComposerResources::Cache::LAYER_BUFFER: + error = layerResource->getBuffer(slot, fromCache, importedHandle, outHandle, + &replacedHandle); + break; + case ComposerResources::Cache::LAYER_SIDEBAND_STREAM: + error = layerResource->getSidebandStream(slot, fromCache, importedHandle, outHandle, + &replacedHandle); + break; + default: + error = Error::BAD_PARAMETER; + break; + } + + if (error != Error::NONE) { + ALOGW("invalid cache %d slot %d", int(cache), int(slot)); + } + } else if (!displayResource) { + error = Error::BAD_DISPLAY; + } else { + error = Error::BAD_LAYER; + } + + // clean up on errors + if (error != Error::NONE) { + if (!fromCache) { + if (outReplacedHandle->isBuffer()) { + mImporter.freeBuffer(importedHandle); + } else { + mImporter.freeStream(importedHandle); + } + } + return error; + } + + outReplacedHandle->reset(&mImporter, replacedHandle); + + return Error::NONE; +} + +} // namespace hal +} // namespace V2_1 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h b/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h new file mode 100644 index 0000000000..b9b713824f --- /dev/null +++ b/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h @@ -0,0 +1,258 @@ +/* + * Copyright 2018 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. + */ + +#pragma once + +#ifndef LOG_TAG +#warning "ComposerResources.h included without LOG_TAG" +#endif + +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_1 { +namespace hal { + +// wrapper for IMapper to import buffers and sideband streams +class ComposerHandleImporter { + public: + bool init(); + + Error importBuffer(const native_handle_t* rawHandle, const native_handle_t** outBufferHandle); + void freeBuffer(const native_handle_t* bufferHandle); + Error importStream(const native_handle_t* rawHandle, const native_handle_t** outStreamHandle); + void freeStream(const native_handle_t* streamHandle); + + private: + sp mMapper2; + sp mMapper3; +}; + +class ComposerHandleCache { + public: + enum class HandleType { + INVALID, + BUFFER, + STREAM, + }; + + ComposerHandleCache(ComposerHandleImporter& importer, HandleType type, uint32_t cacheSize); + + // must be initialized later with initCache + ComposerHandleCache(ComposerHandleImporter& importer); + + ~ComposerHandleCache(); + + ComposerHandleCache(const ComposerHandleCache&) = delete; + ComposerHandleCache& operator=(const ComposerHandleCache&) = delete; + + bool initCache(HandleType type, uint32_t cacheSize); + Error lookupCache(uint32_t slot, const native_handle_t** outHandle); + Error updateCache(uint32_t slot, const native_handle_t* handle, + const native_handle** outReplacedHandle); + + // when fromCache is true, look up in the cache; otherwise, update the cache + Error getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle, + const native_handle_t** outHandle, const native_handle** outReplacedHandle); + + private: + ComposerHandleImporter& mImporter; + HandleType mHandleType = HandleType::INVALID; + std::vector mHandles; +}; + +// layer resource +class ComposerLayerResource { + public: + ComposerLayerResource(ComposerHandleImporter& importer, uint32_t bufferCacheSize); + + virtual ~ComposerLayerResource() = default; + + Error getBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle, + const native_handle_t** outHandle, const native_handle** outReplacedHandle); + Error getSidebandStream(uint32_t slot, bool fromCache, const native_handle_t* inHandle, + const native_handle_t** outHandle, + const native_handle** outReplacedHandle); + + protected: + ComposerHandleCache mBufferCache; + ComposerHandleCache mSidebandStreamCache; +}; + +// display resource +class ComposerDisplayResource { + public: + enum class DisplayType { + PHYSICAL, + VIRTUAL, + }; + + virtual ~ComposerDisplayResource() = default; + + ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer, + uint32_t outputBufferCacheSize); + + bool initClientTargetCache(uint32_t cacheSize); + + bool isVirtual() const; + + Error getClientTarget(uint32_t slot, bool fromCache, const native_handle_t* inHandle, + const native_handle_t** outHandle, + const native_handle** outReplacedHandle); + + Error getOutputBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle, + const native_handle_t** outHandle, + const native_handle** outReplacedHandle); + + bool addLayer(Layer layer, std::unique_ptr layerResource); + bool removeLayer(Layer layer); + ComposerLayerResource* findLayerResource(Layer layer); + std::vector getLayers() const; + + void setMustValidateState(bool mustValidate); + + bool mustValidate() const; + + protected: + const DisplayType mType; + ComposerHandleCache mClientTargetCache; + ComposerHandleCache mOutputBufferCache; + bool mMustValidate; + + std::unordered_map> mLayerResources; +}; + +class ComposerResources { + public: + static std::unique_ptr create(); + + ComposerResources() = default; + virtual ~ComposerResources() = default; + + bool init(); + + using RemoveDisplay = + std::function& layers)>; + void clear(RemoveDisplay removeDisplay); + + Error addPhysicalDisplay(Display display); + Error addVirtualDisplay(Display display, uint32_t outputBufferCacheSize); + + Error removeDisplay(Display display); + + Error setDisplayClientTargetCacheSize(Display display, uint32_t clientTargetCacheSize); + + Error addLayer(Display display, Layer layer, uint32_t bufferCacheSize); + Error removeLayer(Display display, Layer layer); + + void setDisplayMustValidateState(Display display, bool mustValidate); + + bool mustValidateDisplay(Display display); + + // When a buffer in the cache is replaced by a new one, we must keep it + // alive until it has been replaced in ComposerHal. + class ReplacedHandle { + public: + explicit ReplacedHandle(bool isBuffer) : mIsBuffer(isBuffer) {} + ReplacedHandle(const ReplacedHandle&) = delete; + ReplacedHandle& operator=(const ReplacedHandle&) = delete; + + ~ReplacedHandle() { reset(); } + + bool isBuffer() { return mIsBuffer; } + + void reset(ComposerHandleImporter* importer = nullptr, + const native_handle_t* handle = nullptr) { + if (mHandle) { + if (mIsBuffer) { + mImporter->freeBuffer(mHandle); + } else { + mImporter->freeStream(mHandle); + } + } + + mImporter = importer; + mHandle = handle; + } + + private: + bool mIsBuffer; + ComposerHandleImporter* mImporter = nullptr; + const native_handle_t* mHandle = nullptr; + }; + + Error getDisplayClientTarget(Display display, uint32_t slot, bool fromCache, + const native_handle_t* rawHandle, + const native_handle_t** outBufferHandle, + ReplacedHandle* outReplacedBuffer); + + Error getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache, + const native_handle_t* rawHandle, + const native_handle_t** outBufferHandle, + ReplacedHandle* outReplacedBuffer); + + Error getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache, + const native_handle_t* rawHandle, const native_handle_t** outBufferHandle, + ReplacedHandle* outReplacedBuffer); + + Error getLayerSidebandStream(Display display, Layer layer, const native_handle_t* rawHandle, + const native_handle_t** outStreamHandle, + ReplacedHandle* outReplacedStream); + + protected: + virtual std::unique_ptr createDisplayResource( + ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize); + + virtual std::unique_ptr createLayerResource(uint32_t bufferCacheSize); + + ComposerDisplayResource* findDisplayResourceLocked(Display display); + + ComposerHandleImporter mImporter; + + std::mutex mDisplayResourcesMutex; + std::unordered_map> mDisplayResources; + + private: + enum class Cache { + CLIENT_TARGET, + OUTPUT_BUFFER, + LAYER_BUFFER, + LAYER_SIDEBAND_STREAM, + }; + + Error getHandle(Display display, Layer layer, uint32_t slot, Cache cache, bool fromCache, + const native_handle_t* rawHandle, const native_handle_t** outHandle, + ReplacedHandle* outReplacedHandle); +}; + +} // namespace hal +} // namespace V2_1 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.2/default/Android.mk b/graphics/composer/2.2/default/Android.mk index 7dedf616b4..cb551c6c60 100644 --- a/graphics/composer/2.2/default/Android.mk +++ b/graphics/composer/2.2/default/Android.mk @@ -11,8 +11,8 @@ LOCAL_HEADER_LIBRARIES := android.hardware.graphics.composer@2.2-passthrough LOCAL_SHARED_LIBRARIES := \ android.hardware.graphics.composer@2.1 \ android.hardware.graphics.composer@2.2 \ - android.hardware.graphics.mapper@2.0 \ - android.hardware.graphics.mapper@3.0 \ + android.hardware.graphics.composer@2.1-resources \ + android.hardware.graphics.composer@2.2-resources \ libbase \ libbinder \ libcutils \ diff --git a/graphics/composer/2.2/utils/hal/Android.bp b/graphics/composer/2.2/utils/hal/Android.bp index 10dcae4dd7..f334a11c7c 100644 --- a/graphics/composer/2.2/utils/hal/Android.bp +++ b/graphics/composer/2.2/utils/hal/Android.bp @@ -19,9 +19,11 @@ cc_library_headers { vendor_available: true, shared_libs: [ "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.composer@2.2-resources", ], export_shared_lib_headers: [ "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.composer@2.2-resources", ], header_libs: [ "android.hardware.graphics.composer@2.2-command-buffer", diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h index c760d0a421..512d39d2b0 100644 --- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h +++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include namespace android { namespace hardware { @@ -89,7 +89,7 @@ class ComposerClientImpl : public V2_1::hal::detail::ComposerClientImpl(mResources.get()); const native_handle_t* readbackBuffer; - ComposerResources::ReplacedBufferHandle replacedReadbackBuffer; + ComposerResources::ReplacedHandle replacedReadbackBuffer(true); error = resources->getDisplayReadbackBuffer(display, buffer.getNativeHandle(), &readbackBuffer, &replacedReadbackBuffer); if (error != Error::NONE) { diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h index 97e3a9ece6..d9f6226ad9 100644 --- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h +++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h @@ -23,7 +23,7 @@ #include #include #include -#include +#include namespace android { namespace hardware { diff --git a/graphics/composer/2.2/utils/resources/Android.bp b/graphics/composer/2.2/utils/resources/Android.bp new file mode 100644 index 0000000000..752eb8170d --- /dev/null +++ b/graphics/composer/2.2/utils/resources/Android.bp @@ -0,0 +1,29 @@ +// +// 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. + +cc_library_shared { + name: "android.hardware.graphics.composer@2.2-resources", + defaults: ["hidl_defaults"], + vendor_available: true, + shared_libs: [ + "android.hardware.graphics.composer@2.1-resources", + "android.hardware.graphics.composer@2.2", + ], + export_shared_lib_headers: [ + "android.hardware.graphics.composer@2.1-resources", + "android.hardware.graphics.composer@2.2", + ], + export_include_dirs: ["include"], +} diff --git a/graphics/composer/2.2/utils/resources/ComposerResources.cpp b/graphics/composer/2.2/utils/resources/ComposerResources.cpp new file mode 100644 index 0000000000..a0610a3fda --- /dev/null +++ b/graphics/composer/2.2/utils/resources/ComposerResources.cpp @@ -0,0 +1,84 @@ +/* + * Copyright 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 "ComposerResources 2.2" + +#include "composer-resources/2.2/ComposerResources.h" + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_2 { +namespace hal { + +using V2_1::Display; +using V2_1::Error; +using V2_1::Layer; +using V2_1::hal::ComposerHandleCache; +using V2_1::hal::ComposerHandleImporter; + +Error ComposerDisplayResource::getReadbackBuffer(const native_handle_t* inHandle, + const native_handle_t** outHandle, + const native_handle** outReplacedHandle) { + const uint32_t slot = 0; + const bool fromCache = false; + return mReadbackBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle); +} + +std::unique_ptr ComposerResources::create() { + auto resources = std::make_unique(); + return resources->init() ? std::move(resources) : nullptr; +} + +Error ComposerResources::getDisplayReadbackBuffer(Display display, const native_handle_t* rawHandle, + const native_handle_t** outHandle, + ReplacedHandle* outReplacedHandle) { + // import buffer + const native_handle_t* importedHandle; + Error error = mImporter.importBuffer(rawHandle, &importedHandle); + if (error != Error::NONE) { + return error; + } + + std::lock_guard lock(mDisplayResourcesMutex); + + auto iter = mDisplayResources.find(display); + if (iter == mDisplayResources.end()) { + mImporter.freeBuffer(importedHandle); + return Error::BAD_DISPLAY; + } + ComposerDisplayResource& displayResource = + *static_cast(iter->second.get()); + + // update cache + const native_handle_t* replacedHandle; + error = displayResource.getReadbackBuffer(importedHandle, outHandle, &replacedHandle); + if (error != Error::NONE) { + mImporter.freeBuffer(importedHandle); + return error; + } + + outReplacedHandle->reset(&mImporter, replacedHandle); + return Error::NONE; +} + +} // namespace hal +} // namespace V2_2 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h b/graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h similarity index 90% rename from graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h rename to graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h index 85b665179c..33012e92c8 100644 --- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h +++ b/graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h @@ -20,7 +20,7 @@ #warning "ComposerResources.h included without LOG_TAG" #endif -#include +#include namespace android { namespace hardware { @@ -33,7 +33,7 @@ using V2_1::hal::ComposerHandleCache; using V2_1::hal::ComposerHandleImporter; class ComposerDisplayResource : public V2_1::hal::ComposerDisplayResource { - public: + public: ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer, uint32_t outputBufferCacheSize) : V2_1::hal::ComposerDisplayResource(type, importer, outputBufferCacheSize), @@ -47,12 +47,12 @@ class ComposerDisplayResource : public V2_1::hal::ComposerDisplayResource { outReplacedHandle); } - protected: + protected: ComposerHandleCache mReadbackBufferCache; }; class ComposerResources : public V2_1::hal::ComposerResources { - public: + public: static std::unique_ptr create() { auto resources = std::make_unique(); return resources->init() ? std::move(resources) : nullptr; @@ -60,7 +60,7 @@ class ComposerResources : public V2_1::hal::ComposerResources { Error getDisplayReadbackBuffer(Display display, const native_handle_t* rawHandle, const native_handle_t** outHandle, - ReplacedBufferHandle* outReplacedHandle) { + ReplacedHandle* outReplacedHandle) { // import buffer const native_handle_t* importedHandle; Error error = mImporter.importBuffer(rawHandle, &importedHandle); @@ -76,7 +76,7 @@ class ComposerResources : public V2_1::hal::ComposerResources { return Error::BAD_DISPLAY; } ComposerDisplayResource& displayResource = - *static_cast(iter->second.get()); + *static_cast(iter->second.get()); // update cache const native_handle_t* replacedHandle; @@ -90,9 +90,9 @@ class ComposerResources : public V2_1::hal::ComposerResources { return Error::NONE; } - protected: + protected: std::unique_ptr createDisplayResource( - ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) override { + ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) override { return std::make_unique(type, mImporter, outputBufferCacheSize); } }; diff --git a/graphics/composer/2.3/default/Android.bp b/graphics/composer/2.3/default/Android.bp index 07afd6c9a6..8103b89a39 100644 --- a/graphics/composer/2.3/default/Android.bp +++ b/graphics/composer/2.3/default/Android.bp @@ -28,8 +28,8 @@ cc_binary { "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", - "android.hardware.graphics.mapper@2.0", - "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.composer@2.1-resources", + "android.hardware.graphics.composer@2.2-resources", "libbase", "libbinder", "libcutils", diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h index b289b6a0f9..04530d328e 100644 --- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h +++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h @@ -21,9 +21,9 @@ #endif #include -#include #include #include +#include namespace android { namespace hardware { diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h index 1a40d962b8..329dbed51f 100644 --- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h +++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h @@ -23,8 +23,8 @@ #include #include #include -#include #include +#include namespace android { namespace hardware { diff --git a/graphics/composer/2.4/default/Android.bp b/graphics/composer/2.4/default/Android.bp index 1bf51e0250..a44e68794e 100644 --- a/graphics/composer/2.4/default/Android.bp +++ b/graphics/composer/2.4/default/Android.bp @@ -29,8 +29,8 @@ cc_binary { "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "android.hardware.graphics.composer@2.4", - "android.hardware.graphics.mapper@2.0", - "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.composer@2.1-resources", + "android.hardware.graphics.composer@2.2-resources", "libbase", "libbinder", "libcutils", From 7d6690e5330cbad85a466e596d0961d9d561a23a Mon Sep 17 00:00:00 2001 From: Nick Chalko Date: Fri, 16 Aug 2019 12:11:19 -0700 Subject: [PATCH 0072/1022] Improve IFrontend docstrings Change-Id: I9c8395a43807d05ccc4d78da169f7fd1b8ab88ac Test: m VtsHalTvTunerV1_0TargetTest --- tv/tuner/1.0/IFrontend.hal | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/tv/tuner/1.0/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal index 05cee910fd..f7237bae73 100644 --- a/tv/tuner/1.0/IFrontend.hal +++ b/tv/tuner/1.0/IFrontend.hal @@ -18,15 +18,16 @@ package android.hardware.tv.tuner@1.0; import IFrontendCallback; /** - * A Tuner Frontend is used to tune to a frequency and lock signal. It provide - * live data feed to Tuner Demux interface. + * A Tuner Frontend is used to tune to a frequency and lock signal. + * + * IFrontend provides a bit stream to the Tuner Demux interface. */ interface IFrontend { /** - * Set the callback + * Set the frontend callback. * - * It is used by the client to receive events from the Frontend. - * Only one callback for one Frontend instance is supported. The callback + * IFrontendCallback is used by the client to receive events from the Frontend. + * Only one callback per IFrontend instance is supported. The callback * will be replaced if it's set again. * * @param callback Callback object to pass Frontend events to the system. @@ -40,14 +41,14 @@ interface IFrontend { setCallback(IFrontendCallback callback) generates (Result result); /** - * Tuning Frontend + * Tunes the frontend to using the settings given. * - * It is used by the client to lock a frequency by providing signal - * delivery information. If previous tuning isn't completed, this call must - * stop previous tuning, and start a new tuning. Tune is a async call. - * LOCKED or NO_SIGNAL eventi is sent back to caller through callback. + * This locks the frontend to a frequency by providing signal + * delivery information. If previous tuning isn't completed, this call MUST + * stop previous tuning, and start a new tuning. + * Tune is an async call, with LOCKED or NO_SIGNAL events sent via callback. * - * @param settings Signal delivery information which frontend can use to + * @param settings Signal delivery information the frontend uses to * search and lock the signal. * * @return result Result status of the operation. @@ -58,9 +59,10 @@ interface IFrontend { tune(FrontendSettings settings) generates (Result result); /** - * Stop the tuning + * Stops a previous tuning. * - * It is used by the client to stop a previous tuning. + * If the method completes successfully the frontend is no longer tuned and no data + * will be sent to attached demuxes. * * @return result Result status of the operation. * SUCCESS if successfully stop tuning. @@ -69,10 +71,10 @@ interface IFrontend { stopTune() generates (Result result); /** - * Release the Frontend instance + * Releases the Frontend instance * - * It is used by the client to release the frontend instance. HAL clear - * underneath resource. client mustn't access the instance any more. + * Associated resources are released. close may be called more than once. + * Calls to any other method after this will return an error * * @return result Result status of the operation. * SUCCESS if successful, From b96c2eb1194bcb8496165c81eaf1d16de66409ce Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 20 Jun 2019 13:30:10 -0700 Subject: [PATCH 0073/1022] composer: support gralloc 4.0 Add support for gralloc 4.0 to composer. Bug: 136016160 Test: Compiles and boots Change-Id: I2609f20348f795a7c4e966d7420b36fa27daa054 --- .../composer/2.1/utils/resources/Android.bp | 2 ++ .../2.1/utils/resources/ComposerResources.cpp | 18 ++++++++++++++++++ .../composer-resources/2.1/ComposerResources.h | 2 ++ 3 files changed, 22 insertions(+) diff --git a/graphics/composer/2.1/utils/resources/Android.bp b/graphics/composer/2.1/utils/resources/Android.bp index e7ba458f9a..ed827feb66 100644 --- a/graphics/composer/2.1/utils/resources/Android.bp +++ b/graphics/composer/2.1/utils/resources/Android.bp @@ -21,6 +21,7 @@ cc_library_shared { "android.hardware.graphics.composer@2.1", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "libcutils", "libhardware", // TODO remove hwcomposer2.h dependency "libhidlbase", @@ -31,6 +32,7 @@ cc_library_shared { "android.hardware.graphics.composer@2.1", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "libhardware", "libhidlbase", "liblog", diff --git a/graphics/composer/2.1/utils/resources/ComposerResources.cpp b/graphics/composer/2.1/utils/resources/ComposerResources.cpp index d28eedca1b..21f60355f8 100644 --- a/graphics/composer/2.1/utils/resources/ComposerResources.cpp +++ b/graphics/composer/2.1/utils/resources/ComposerResources.cpp @@ -26,6 +26,12 @@ namespace V2_1 { namespace hal { bool ComposerHandleImporter::init() { + mMapper4 = mapper::V4_0::IMapper::getService(); + if (mMapper4) { + return true; + } + ALOGI_IF(!mMapper4, "failed to get mapper 4.0 service, falling back to mapper 3.0"); + mMapper3 = mapper::V3_0::IMapper::getService(); if (mMapper3) { return true; @@ -66,6 +72,16 @@ Error ComposerHandleImporter::importBuffer(const native_handle_t* rawHandle, return Error::NO_RESOURCES; } } + if (mMapper4) { + mapper::V4_0::Error error; + mMapper4->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) { + error = tmpError; + bufferHandle = static_cast(tmpBufferHandle); + }); + if (error != mapper::V4_0::Error::NONE) { + return Error::NO_RESOURCES; + } + } *outBufferHandle = bufferHandle; return Error::NONE; @@ -77,6 +93,8 @@ void ComposerHandleImporter::freeBuffer(const native_handle_t* bufferHandle) { mMapper2->freeBuffer(static_cast(const_cast(bufferHandle))); } else if (mMapper3) { mMapper3->freeBuffer(static_cast(const_cast(bufferHandle))); + } else if (mMapper4) { + mMapper4->freeBuffer(static_cast(const_cast(bufferHandle))); } } } diff --git a/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h b/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h index b9b713824f..3738278559 100644 --- a/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h +++ b/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h @@ -29,6 +29,7 @@ #include #include +#include #include namespace android { @@ -51,6 +52,7 @@ class ComposerHandleImporter { private: sp mMapper2; sp mMapper3; + sp mMapper4; }; class ComposerHandleCache { From 0d0228de5a96d720b562cfe66c29a9ee09de055e Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Sat, 17 Aug 2019 21:40:28 -0700 Subject: [PATCH 0074/1022] Add a method to override a master EVS considers the client, which owns the display, as the high priority client and allows it to steal a master role from existing master that does not own the display. Bug: 139536751 Test: VtsHalEvsV1_1Target Change-Id: Idecaeedd90f187de57de912a09f4782bfb81a996 Signed-off-by: Changyeon Jo --- automotive/evs/1.1/IEvsCamera.hal | 18 +++ automotive/evs/1.1/default/EvsCamera.cpp | 6 + automotive/evs/1.1/default/EvsCamera.h | 3 + .../evs/1.1/vts/functional/FrameHandler.cpp | 48 +++++-- .../evs/1.1/vts/functional/FrameHandler.h | 3 +- .../functional/VtsHalEvsV1_1TargetTest.cpp | 126 ++++++++++++++++++ 6 files changed, 192 insertions(+), 12 deletions(-) diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal index d4263b7e20..21ca79e91f 100644 --- a/automotive/evs/1.1/IEvsCamera.hal +++ b/automotive/evs/1.1/IEvsCamera.hal @@ -17,6 +17,7 @@ package android.hardware.automotive.evs@1.1; import @1.0::IEvsCamera; +import @1.0::IEvsDisplay; import @1.0::EvsResult; import IEvsCameraStream; @@ -71,6 +72,23 @@ interface IEvsCamera extends @1.0::IEvsCamera { */ setMaster() generates (EvsResult result); + /** + * Sets to be a master client forcibly. + * + * The client, which owns the display, has a high priority and can take over + * a master role from other clients without the display. + * + * @param display IEvsDisplay handle. If a given display is in either + * NOT_VISIBLE, VISIBLE_ON_NEXT_FRAME, or VISIBLE state, the + * calling client is considered as the high priority client + * and therefore allowed to take over a master role from + * existing master client. + * + * @return result EvsResult::OK if a master role is granted. + * EvsResult::INVALID_ARG if a given display handle is null + * or in valid states. + */ + forceMaster(IEvsDisplay display) generates (EvsResult result); /** * Retires from a master client role. diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp index ae293b6ba0..2d55566349 100644 --- a/automotive/evs/1.1/default/EvsCamera.cpp +++ b/automotive/evs/1.1/default/EvsCamera.cpp @@ -264,6 +264,12 @@ Return EvsCamera::setMaster() { return EvsResult::OK; } +Return EvsCamera::forceMaster(const sp& ) { + // Default implementation does not expect multiple subscribers and therefore + // return a success code always. + return EvsResult::OK; +} + Return EvsCamera::unsetMaster() { // Default implementation does not expect multiple subscribers and therefore diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h index 6cb1cfbcff..47a3164892 100644 --- a/automotive/evs/1.1/default/EvsCamera.h +++ b/automotive/evs/1.1/default/EvsCamera.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -30,6 +31,7 @@ using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCam using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream; using ::android::hardware::automotive::evs::V1_0::EvsResult; using ::android::hardware::automotive::evs::V1_0::CameraDesc; +using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; namespace android { @@ -61,6 +63,7 @@ public: Return resumeVideoStream() override; Return doneWithFrame_1_1(const BufferDesc_1_1& buffer) override; Return setMaster() override; + Return forceMaster(const sp& display) override; Return unsetMaster() override; Return setParameter(CameraParam id, int32_t value, setParameter_cb _hidl_cb) override; diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp index a39346b845..16276891f0 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp +++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp @@ -21,11 +21,14 @@ #include #include +#include #include #include #include +using namespace std::chrono_literals; + FrameHandler::FrameHandler(android::sp pCamera, CameraDesc cameraInfo, android::sp pDisplay, BufferControlFlag mode) : @@ -148,7 +151,7 @@ Return FrameHandler::notifyEvent(const EvsEvent& event) { ALOGD("Camera parameter 0x%X is changed to 0x%X", mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]); } else { - ALOGD("Received an event 0x%X", mLatestEventDesc.aType); + ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType)); } mLock.unlock(); mEventSignal.notify_all(); @@ -339,19 +342,42 @@ void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) { } } -void FrameHandler::waitForEvent(const InfoEventType aTargetEvent, +bool FrameHandler::waitForEvent(const InfoEventType aTargetEvent, InfoEventDesc &eventDesc) { // Wait until we get an expected parameter change event. std::unique_lock lock(mLock); - mEventSignal.wait(lock, [this, aTargetEvent, &eventDesc](){ - bool flag = mLatestEventDesc.aType == aTargetEvent; - if (flag) { - eventDesc.aType = mLatestEventDesc.aType; - eventDesc.payload[0] = mLatestEventDesc.payload[0]; - eventDesc.payload[1] = mLatestEventDesc.payload[1]; - } + auto now = std::chrono::system_clock::now(); + bool result = mEventSignal.wait_until(lock, now + 5s, + [this, aTargetEvent, &eventDesc](){ + bool flag = mLatestEventDesc.aType == aTargetEvent; + if (flag) { + eventDesc.aType = mLatestEventDesc.aType; + eventDesc.payload[0] = mLatestEventDesc.payload[0]; + eventDesc.payload[1] = mLatestEventDesc.payload[1]; + } - return flag; - }); + return flag; + } + ); + + return !result; } +const char *FrameHandler::eventToString(const InfoEventType aType) { + switch (aType) { + case InfoEventType::STREAM_STARTED: + return "STREAM_STARTED"; + case InfoEventType::STREAM_STOPPED: + return "STREAM_STOPPED"; + case InfoEventType::FRAME_DROPPED: + return "FRAME_DROPPED"; + case InfoEventType::TIMEOUT: + return "TIMEOUT"; + case InfoEventType::PARAMETER_CHANGED: + return "PARAMETER_CHANGED"; + case InfoEventType::MASTER_RELEASED: + return "MASTER_RELEASED"; + default: + return "Unknown"; + } +} diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h index c5faecde5f..7f87cb4409 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.h +++ b/automotive/evs/1.1/vts/functional/FrameHandler.h @@ -67,7 +67,7 @@ public: bool isRunning(); void waitForFrameCount(unsigned frameCount); - void waitForEvent(const InfoEventType aTargetEvent, + bool waitForEvent(const InfoEventType aTargetEvent, InfoEventDesc &eventDesc); void getFramesCounters(unsigned* received, unsigned* displayed); void getFrameDimension(unsigned* width, unsigned* height); @@ -79,6 +79,7 @@ private: // Local implementation details bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer); + const char *eventToString(const InfoEventType aType); // Values initialized as startup android::sp mCamera; diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index 0d88c07dd2..a6e4881d4d 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -935,6 +935,132 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { } +/* + * HighPriorityCameraClient: + * EVS client, which owns the display, is priortized and therefore can take over + * a master role from other EVS clients without the display. + */ +TEST_F(EvsHidlTest, HighPriorityCameraClient) { + ALOGI("Starting HighPriorityCameraClient test"); + + // Get the camera list + loadCameraList(); + + // Request exclusive access to the EVS display + sp pDisplay = pEnumerator->openDisplay(); + ASSERT_NE(pDisplay, nullptr); + + // Test each reported camera + for (auto&& cam: cameraInfo) { + // Create two clients + sp pCam0 = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + .withDefault(nullptr); + ASSERT_NE(pCam0, nullptr); + + sp pCam1 = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + .withDefault(nullptr); + ASSERT_NE(pCam1, nullptr); + + // Set up a frame receiver object which will fire up its own thread. + sp frameHandler0 = new FrameHandler(pCam0, cam, + pDisplay, + FrameHandler::eAutoReturn); + sp frameHandler1 = new FrameHandler(pCam1, cam, + nullptr, + FrameHandler::eAutoReturn); + + // Activate the display + pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME); + + // Start the camera's video stream + ASSERT_TRUE(frameHandler0->startStream()); + ASSERT_TRUE(frameHandler1->startStream()); + + // Ensure the stream starts + frameHandler0->waitForFrameCount(1); + frameHandler1->waitForFrameCount(1); + + // Client 1 becomes a master and programs a brightness. + EvsResult result = EvsResult::OK; + int32_t val0 = 100; + int32_t val1 = 0; + + result = pCam1->setMaster(); + ASSERT_TRUE(result == EvsResult::OK); + + pCam1->setParameter(CameraParam::BRIGHTNESS, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + + + // Verify a change notification + InfoEventDesc aNotification = {}; + if (result == EvsResult::OK) { + bool timeout = + frameHandler0->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); + ASSERT_FALSE(timeout) << "Expected event does not arrive"; + ASSERT_EQ(static_cast(aNotification.aType), + InfoEventType::PARAMETER_CHANGED); + ASSERT_EQ(static_cast(aNotification.payload[0]), + CameraParam::BRIGHTNESS); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); + } + + // Client 0 steals a master role + ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay)); + + frameHandler1->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(static_cast(aNotification.aType), + InfoEventType::MASTER_RELEASED); + + // Client 0 programs a brightness + val0 = 50; + val1 = 0; + pCam0->setParameter(CameraParam::BRIGHTNESS, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + + // Verify a change notification + if (result == EvsResult::OK) { + bool timeout = + frameHandler1->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); + ASSERT_FALSE(timeout) << "Expected event does not arrive"; + ASSERT_EQ(static_cast(aNotification.aType), + InfoEventType::PARAMETER_CHANGED); + ASSERT_EQ(static_cast(aNotification.payload[0]), + CameraParam::BRIGHTNESS); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); + } + + // Turn off the display (yes, before the stream stops -- it should be handled) + pDisplay->setDisplayState(DisplayState::NOT_VISIBLE); + + // Shut down the streamer + frameHandler0->shutdown(); + frameHandler1->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCam0); + pEnumerator->closeCamera(pCam1); + } + + // Explicitly release the display + pEnumerator->closeDisplay(pDisplay); +} + + int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance()); ::testing::InitGoogleTest(&argc, argv); From 53aff11b36b7f53b6d987e45d90ff6bd2de648d3 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 20 Jun 2019 13:49:21 -0700 Subject: [PATCH 0075/1022] composer-vts: support gralloc 4 Add support for gralloc 4.0 to composer-vts. Bug: 136016160 Test: Compiles and boots Change-Id: Ibfa802023ddeb3b4d09a7b69bbc796b67c4ee62d --- graphics/composer/2.1/utils/vts/Android.bp | 2 + .../composer/2.1/utils/vts/ComposerVts.cpp | 43 +++++++++++++++---- .../include/composer-vts/2.1/ComposerVts.h | 4 ++ .../composer/2.1/vts/functional/Android.bp | 5 +++ .../VtsHalGraphicsComposerV2_1TargetTest.cpp | 1 + graphics/composer/2.2/utils/vts/Android.bp | 4 ++ .../composer/2.2/utils/vts/ComposerVts.cpp | 36 +++++++++++----- .../include/composer-vts/2.2/ComposerVts.h | 2 + .../composer/2.2/vts/functional/Android.bp | 3 ++ .../composer/2.3/vts/functional/Android.bp | 3 ++ .../composer/2.4/vts/functional/Android.bp | 7 +++ 11 files changed, 91 insertions(+), 19 deletions(-) diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp index 88b1a8b3d7..cdc0f35a41 100644 --- a/graphics/composer/2.1/utils/vts/Android.bp +++ b/graphics/composer/2.1/utils/vts/Android.bp @@ -27,12 +27,14 @@ cc_library_static { "android.hardware.graphics.composer@2.1", "android.hardware.graphics.mapper@2.0-vts", "android.hardware.graphics.mapper@3.0-vts", + "android.hardware.graphics.mapper@4.0-vts", ], export_static_lib_headers: [ "VtsHalHidlTargetTestBase", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.mapper@2.0-vts", "android.hardware.graphics.mapper@3.0-vts", + "android.hardware.graphics.mapper@4.0-vts", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp index c5d5823398..a0745cef60 100644 --- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp @@ -317,11 +317,16 @@ void ComposerClient::execute(TestCommandReader* reader, CommandWriterBase* write Gralloc::Gralloc() { [this] { - ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared("default", "default", + ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared("default", "default", /*errOnFailure=*/false)); - if (mGralloc3->getAllocator() == nullptr || mGralloc3->getMapper() == nullptr) { - mGralloc3 = nullptr; - ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared()); + if (mGralloc4->getAllocator() == nullptr || mGralloc4->getMapper() == nullptr) { + mGralloc4 = nullptr; + ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared("default", "default", + /*errOnFailure=*/false)); + if (mGralloc3->getAllocator() == nullptr || mGralloc3->getMapper() == nullptr) { + mGralloc3 = nullptr; + ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared()); + } } }(); } @@ -329,7 +334,15 @@ Gralloc::Gralloc() { const native_handle_t* Gralloc::allocate(uint32_t width, uint32_t height, uint32_t layerCount, PixelFormat format, uint64_t usage, bool import, uint32_t* outStride) { - if (mGralloc3) { + if (mGralloc4) { + IMapper4::BufferDescriptorInfo info{}; + info.width = width; + info.height = height; + info.layerCount = layerCount; + info.format = static_cast(format); + info.usage = usage; + return mGralloc4->allocate(info, import, outStride); + } else if (mGralloc3) { IMapper3::BufferDescriptorInfo info{}; info.width = width; info.height = height; @@ -350,7 +363,17 @@ const native_handle_t* Gralloc::allocate(uint32_t width, uint32_t height, uint32 void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, const AccessRegion& accessRegionRect, int acquireFence) { - if (mGralloc3) { + if (mGralloc4) { + IMapper4::Rect accessRegion; + accessRegion.left = accessRegionRect.left; + accessRegion.top = accessRegionRect.top; + accessRegion.width = accessRegionRect.width; + accessRegion.height = accessRegionRect.height; + int32_t bytesPerPixel; + int32_t bytesPerStride; + return mGralloc4->lock(bufferHandle, cpuUsage, accessRegion, acquireFence, &bytesPerPixel, + &bytesPerStride); + } else if (mGralloc3) { IMapper3::Rect accessRegion; accessRegion.left = accessRegionRect.left; accessRegion.top = accessRegionRect.top; @@ -371,7 +394,9 @@ void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, } int Gralloc::unlock(const native_handle_t* bufferHandle) { - if (mGralloc3) { + if (mGralloc4) { + return mGralloc4->unlock(bufferHandle); + } else if (mGralloc3) { return mGralloc3->unlock(bufferHandle); } else { return mGralloc2->unlock(bufferHandle); @@ -379,7 +404,9 @@ int Gralloc::unlock(const native_handle_t* bufferHandle) { } void Gralloc::freeBuffer(const native_handle_t* bufferHandle) { - if (mGralloc3) { + if (mGralloc4) { + mGralloc4->freeBuffer(bufferHandle); + } else if (mGralloc3) { mGralloc3->freeBuffer(bufferHandle); } else { mGralloc2->freeBuffer(bufferHandle); diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h index 7811048270..429465779b 100644 --- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h +++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "gtest/gtest.h" @@ -44,8 +45,10 @@ using android::hardware::graphics::common::V1_0::Hdr; using android::hardware::graphics::common::V1_0::PixelFormat; using IMapper2 = android::hardware::graphics::mapper::V2_0::IMapper; using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper; +using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper; using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc; using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc; +using Gralloc4 = android::hardware::graphics::mapper::V4_0::vts::Gralloc; class ComposerClient; @@ -153,6 +156,7 @@ class Gralloc { protected: std::shared_ptr mGralloc2 = nullptr; std::shared_ptr mGralloc3 = nullptr; + std::shared_ptr mGralloc4 = nullptr; }; } // namespace vts diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp index d54da60f6d..799ca919b9 100644 --- a/graphics/composer/2.1/vts/functional/Android.bp +++ b/graphics/composer/2.1/vts/functional/Android.bp @@ -27,12 +27,17 @@ cc_test { static_libs: [ "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.allocator@3.0", + "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: [ "android.hardware.graphics.composer@2.1-command-buffer", diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp index fa5ace65b1..5d2f65deab 100644 --- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp +++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp index 1754a43dbb..5432882bea 100644 --- a/graphics/composer/2.2/utils/vts/Android.bp +++ b/graphics/composer/2.2/utils/vts/Android.bp @@ -34,6 +34,10 @@ cc_library_static { "libmath", "libnativewindow", "librenderengine", + "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", ], export_static_lib_headers: [ "VtsHalHidlTargetTestBase", diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp index a380fc040d..93b67f0fcc 100644 --- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp @@ -182,17 +182,23 @@ std::array ComposerClient::getDataspaceSaturationMatrix(Dataspace dat Gralloc::Gralloc() { [this] { - ALOGD("Attempting to initialize gralloc3"); - ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared("default", "default", + ALOGD("Attempting to initialize gralloc4"); + ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared("default", "default", /*errOnFailure=*/false)); - if (mGralloc3->getMapper() == nullptr || mGralloc3->getAllocator() == nullptr) { - mGralloc3 = nullptr; - ALOGD("Failed to initialize gralloc3, initializing gralloc2_1"); - mGralloc2_1 = std::make_shared(/*errOnFailure*/ false); - if (!mGralloc2_1->getMapper()) { - mGralloc2_1 = nullptr; - ALOGD("Failed to initialize gralloc2_1, initializing gralloc2"); - ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared()); + if (mGralloc4->getMapper() == nullptr || mGralloc4->getAllocator() == nullptr) { + mGralloc4 = nullptr; + ALOGD("Failed to initialize gralloc4, initializing gralloc3"); + ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared("default", "default", + /*errOnFailure=*/false)); + if (mGralloc3->getMapper() == nullptr || mGralloc3->getAllocator() == nullptr) { + mGralloc3 = nullptr; + ALOGD("Failed to initialize gralloc3, initializing gralloc2_1"); + mGralloc2_1 = std::make_shared(/*errOnFailure*/ false); + if (!mGralloc2_1->getMapper()) { + mGralloc2_1 = nullptr; + ALOGD("Failed to initialize gralloc2_1, initializing gralloc2"); + ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared()); + } } } }(); @@ -201,7 +207,15 @@ Gralloc::Gralloc() { bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle, uint32_t width, uint32_t height, uint32_t layerCount, PixelFormat format, uint64_t usage, uint32_t stride) { - if (mGralloc3) { + if (mGralloc4) { + IMapper4::BufferDescriptorInfo info{}; + info.width = width; + info.height = height; + info.layerCount = layerCount; + info.format = static_cast(format); + info.usage = usage; + return mGralloc4->validateBufferSize(bufferHandle, info, stride); + } else if (mGralloc3) { IMapper3::BufferDescriptorInfo info{}; info.width = width; info.height = height; diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h index 8fa9b7b3fe..5d22305020 100644 --- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h +++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h @@ -44,9 +44,11 @@ using common::V1_1::PixelFormat; using common::V1_1::RenderIntent; using IMapper2_1 = android::hardware::graphics::mapper::V2_1::IMapper; using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper; +using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper; using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc; using Gralloc2_1 = android::hardware::graphics::mapper::V2_1::vts::Gralloc; using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc; +using Gralloc4 = android::hardware::graphics::mapper::V4_0::vts::Gralloc; class ComposerClient; diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp index 25b827e83b..28728803e8 100644 --- a/graphics/composer/2.2/vts/functional/Android.bp +++ b/graphics/composer/2.2/vts/functional/Android.bp @@ -39,6 +39,7 @@ cc_test { static_libs: [ "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.allocator@3.0", + "android.hardware.graphics.allocator@4.0", "android.hardware.graphics.common@1.1", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.1-vts", @@ -50,6 +51,8 @@ cc_test { "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", "librenderengine" ], header_libs: [ diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp index 2766638754..965c8fe40b 100644 --- a/graphics/composer/2.3/vts/functional/Android.bp +++ b/graphics/composer/2.3/vts/functional/Android.bp @@ -29,6 +29,7 @@ cc_test { static_libs: [ "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.allocator@3.0", + "android.hardware.graphics.allocator@4.0", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.1-vts", "android.hardware.graphics.composer@2.2", @@ -41,6 +42,8 @@ cc_test { "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: [ "android.hardware.graphics.composer@2.1-command-buffer", diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp index d437f2486e..6ee78738cc 100644 --- a/graphics/composer/2.4/vts/functional/Android.bp +++ b/graphics/composer/2.4/vts/functional/Android.bp @@ -27,6 +27,8 @@ cc_test { ], static_libs: [ "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.allocator@3.0", + "android.hardware.graphics.allocator@4.0", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.1-vts", "android.hardware.graphics.composer@2.2", @@ -38,6 +40,11 @@ cc_test { "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: [ "android.hardware.graphics.composer@2.1-command-buffer", From 244e794ffe68ed2b22ccdb92f45e56eb6e6c535c Mon Sep 17 00:00:00 2001 From: Kai Date: Wed, 31 Jul 2019 16:12:35 -0700 Subject: [PATCH 0076/1022] Check timestamp before updating the value Check timestamp before updating property value. Use timestamp in generating fake property event. Bug: 134963097 Test: end to end test in VehcileHal_test Change-Id: I60f8c0eb3a19db2c165469bb45b3b80b39388b37 --- .../common/src/VehiclePropertyStore.cpp | 18 ++++++++++++------ .../impl/vhal_v2_0/EmulatedVehicleHal.cpp | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp index 94ace455cc..24b777c75f 100644 --- a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp +++ b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp @@ -50,12 +50,18 @@ bool VehiclePropertyStore::writeValue(const VehiclePropValue& propValue, VehiclePropValue* valueToUpdate = const_cast(getValueOrNullLocked(recId)); if (valueToUpdate == nullptr) { mPropertyValues.insert({ recId, propValue }); - } else { - valueToUpdate->timestamp = propValue.timestamp; - valueToUpdate->value = propValue.value; - if (updateStatus) { - valueToUpdate->status = propValue.status; - } + return true; + } + + // propValue is outdated and drops it. + if (valueToUpdate->timestamp > propValue.timestamp) { + return false; + } + // update the propertyValue. + valueToUpdate->timestamp = propValue.timestamp; + valueToUpdate->value = propValue.value; + if (updateStatus) { + valueToUpdate->status = propValue.status; } return true; } 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 ba81a521a0..b4f1f07323 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 @@ -455,7 +455,7 @@ void EmulatedVehicleHal::onFakeValueGenerated(const VehiclePropValue& value) { VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value); if (updatedPropValue) { - updatedPropValue->timestamp = elapsedRealtimeNano(); + updatedPropValue->timestamp = value.timestamp; updatedPropValue->status = VehiclePropertyStatus::AVAILABLE; mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus); auto changeMode = mPropStore->getConfigOrDie(value.prop)->changeMode; From 8e8b70c439409eb7205fad2e1e9b1c135ace5ab6 Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Fri, 9 Aug 2019 16:38:14 -0700 Subject: [PATCH 0077/1022] Modify 1.0 VTS tests to consume test struct directly. Implement converter utilities constructing HIDL model and request from TestModel. Bug: 123092187 Bug: 138718240 Test: All VTS Change-Id: I0b26b7f41d31d5e63ed083ab5f6f269a3620f034 --- neuralnetworks/1.0/vts/functional/Android.bp | 6 +- .../vts/functional/GeneratedTestHarness.cpp | 225 ++++++++---------- .../1.0/vts/functional/GeneratedTestHarness.h | 5 +- .../1.0/vts/functional/GeneratedTests.h | 11 +- neuralnetworks/1.0/vts/functional/Utils.cpp | 104 ++++++-- .../1.0/vts/functional/ValidateRequest.cpp | 111 +-------- .../vts/functional/VtsHalNeuralnetworks.cpp | 4 +- .../1.0/vts/functional/VtsHalNeuralnetworks.h | 5 +- .../1.0/vts/functional/include/1.0/Utils.h | 7 +- 9 files changed, 197 insertions(+), 281 deletions(-) diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp index a8406de235..abff213847 100644 --- a/neuralnetworks/1.0/vts/functional/Android.bp +++ b/neuralnetworks/1.0/vts/functional/Android.bp @@ -32,12 +32,11 @@ cc_library_static { "android.hidl.memory@1.0", "libgmock", "libhidlmemory", + "libneuralnetworks_generated_test_harness", "libneuralnetworks_utils", ], header_libs: [ "libneuralnetworks_headers", - "libneuralnetworks_generated_test_harness_headers", - "libneuralnetworks_generated_tests", ], } @@ -60,13 +59,12 @@ cc_defaults { "android.hidl.memory@1.0", "libgmock", "libhidlmemory", + "libneuralnetworks_generated_test_harness", "libneuralnetworks_utils", "VtsHalNeuralNetworksV1_0_utils", ], header_libs: [ "libneuralnetworks_headers", - "libneuralnetworks_generated_test_harness_headers", - "libneuralnetworks_generated_tests", ], test_suites: ["general-tests"], } diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp index 40d2f4ceb7..0fd9947ede 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp @@ -15,6 +15,7 @@ */ #include "GeneratedTestHarness.h" + #include "1.0/Callbacks.h" #include "1.0/Utils.h" #include "MemoryUtils.h" @@ -28,6 +29,7 @@ #include #include +#include #include namespace android { @@ -36,6 +38,7 @@ namespace neuralnetworks { namespace V1_0 { namespace generated_tests { +using namespace test_helper; using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; using ::android::hardware::neuralnetworks::V1_0::IDevice; using ::android::hardware::neuralnetworks::V1_0::IPreparedModel; @@ -45,137 +48,111 @@ using ::android::hardware::neuralnetworks::V1_0::RequestArgument; using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; using ::android::hidl::memory::V1_0::IMemory; -using ::test_helper::compare; -using ::test_helper::filter; -using ::test_helper::for_all; -using ::test_helper::MixedTyped; -using ::test_helper::MixedTypedExample; -using ::test_helper::resize_accordingly; + +Model createModel(const TestModel& testModel) { + // Model operands. + hidl_vec operands(testModel.operands.size()); + size_t constCopySize = 0, constRefSize = 0; + for (uint32_t i = 0; i < testModel.operands.size(); i++) { + const auto& op = testModel.operands[i]; + + DataLocation loc = {}; + if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { + loc = {.poolIndex = 0, + .offset = static_cast(constCopySize), + .length = static_cast(op.data.size())}; + constCopySize += op.data.alignedSize(); + } else if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) { + loc = {.poolIndex = 0, + .offset = static_cast(constRefSize), + .length = static_cast(op.data.size())}; + constRefSize += op.data.alignedSize(); + } + + operands[i] = {.type = static_cast(op.type), + .dimensions = op.dimensions, + .numberOfConsumers = op.numberOfConsumers, + .scale = op.scale, + .zeroPoint = op.zeroPoint, + .lifetime = static_cast(op.lifetime), + .location = loc}; + } + + // Model operations. + hidl_vec operations(testModel.operations.size()); + std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(), + [](const TestOperation& op) -> Operation { + return {.type = static_cast(op.type), + .inputs = op.inputs, + .outputs = op.outputs}; + }); + + // Constant copies. + hidl_vec operandValues(constCopySize); + for (uint32_t i = 0; i < testModel.operands.size(); i++) { + const auto& op = testModel.operands[i]; + if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { + const uint8_t* begin = op.data.get(); + const uint8_t* end = begin + op.data.size(); + std::copy(begin, end, operandValues.data() + operands[i].location.offset); + } + } + + // Shared memory. + hidl_vec pools; + if (constRefSize > 0) { + hidl_vec_push_back(&pools, nn::allocateSharedMemory(constRefSize)); + CHECK_NE(pools[0].size(), 0u); + + // load data + sp mappedMemory = mapMemory(pools[0]); + CHECK(mappedMemory.get() != nullptr); + uint8_t* mappedPtr = + reinterpret_cast(static_cast(mappedMemory->getPointer())); + CHECK(mappedPtr != nullptr); + + for (uint32_t i = 0; i < testModel.operands.size(); i++) { + const auto& op = testModel.operands[i]; + if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) { + const uint8_t* begin = op.data.get(); + const uint8_t* end = begin + op.data.size(); + std::copy(begin, end, mappedPtr + operands[i].location.offset); + } + } + } + + return {.operands = std::move(operands), + .operations = std::move(operations), + .inputIndexes = testModel.inputIndexes, + .outputIndexes = testModel.outputIndexes, + .operandValues = std::move(operandValues), + .pools = std::move(pools)}; +} // Top level driver for models and examples generated by test_generator.py // Test driver for those generated from ml/nn/runtime/test/spec -void EvaluatePreparedModel(sp& preparedModel, std::function is_ignored, - const std::vector& examples, float fpAtol, - float fpRtol) { - const uint32_t INPUT = 0; - const uint32_t OUTPUT = 1; +void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel) { + const Request request = createRequest(testModel); - int example_no = 1; - for (auto& example : examples) { - SCOPED_TRACE(example_no++); - const MixedTyped& inputs = example.operands.first; - const MixedTyped& golden = example.operands.second; + // Launch execution. + sp executionCallback = new ExecutionCallback(); + Return executionLaunchStatus = preparedModel->execute(request, executionCallback); + ASSERT_TRUE(executionLaunchStatus.isOk()); + EXPECT_EQ(ErrorStatus::NONE, static_cast(executionLaunchStatus)); - CHECK(inputs.float16Operands.empty()) << "float16 is not supported in 1.0"; + // Retrieve execution status. + executionCallback->wait(); + ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus()); - std::vector inputs_info, outputs_info; - uint32_t inputSize = 0, outputSize = 0; - // This function only partially specifies the metadata (vector of RequestArguments). - // The contents are copied over below. - for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) { - if (inputs_info.size() <= static_cast(index)) inputs_info.resize(index + 1); - RequestArgument arg = { - .location = {.poolIndex = INPUT, - .offset = 0, - .length = static_cast(s)}, - .dimensions = {}, - }; - RequestArgument arg_empty = { - .hasNoValue = true, - }; - inputs_info[index] = s ? arg : arg_empty; - inputSize += s; - }); - // Compute offset for inputs 1 and so on - { - size_t offset = 0; - for (auto& i : inputs_info) { - if (!i.hasNoValue) i.location.offset = offset; - offset += i.location.length; - } - } + // Retrieve execution results. + const std::vector outputs = getOutputBuffers(request); - MixedTyped test; // holding test results - - // Go through all outputs, initialize RequestArgument descriptors - resize_accordingly(golden, test); - for_all(golden, [&outputs_info, &outputSize](int index, auto, auto s) { - if (outputs_info.size() <= static_cast(index)) outputs_info.resize(index + 1); - RequestArgument arg = { - .location = {.poolIndex = OUTPUT, - .offset = 0, - .length = static_cast(s)}, - .dimensions = {}, - }; - outputs_info[index] = arg; - outputSize += s; - }); - // Compute offset for outputs 1 and so on - { - size_t offset = 0; - for (auto& i : outputs_info) { - i.location.offset = offset; - offset += i.location.length; - } - } - std::vector pools = {nn::allocateSharedMemory(inputSize), - nn::allocateSharedMemory(outputSize)}; - ASSERT_NE(0ull, pools[INPUT].size()); - ASSERT_NE(0ull, pools[OUTPUT].size()); - - // load data - sp inputMemory = mapMemory(pools[INPUT]); - sp outputMemory = mapMemory(pools[OUTPUT]); - ASSERT_NE(nullptr, inputMemory.get()); - ASSERT_NE(nullptr, outputMemory.get()); - char* inputPtr = reinterpret_cast(static_cast(inputMemory->getPointer())); - char* outputPtr = reinterpret_cast(static_cast(outputMemory->getPointer())); - ASSERT_NE(nullptr, inputPtr); - ASSERT_NE(nullptr, outputPtr); - inputMemory->update(); - outputMemory->update(); - - // Go through all inputs, copy the values - for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) { - char* begin = (char*)p; - char* end = begin + s; - // TODO: handle more than one input - std::copy(begin, end, inputPtr + inputs_info[index].location.offset); - }); - - inputMemory->commit(); - outputMemory->commit(); - - const Request request = {.inputs = inputs_info, .outputs = outputs_info, .pools = pools}; - - // launch execution - sp executionCallback = new ExecutionCallback(); - ASSERT_NE(nullptr, executionCallback.get()); - Return executionLaunchStatus = - preparedModel->execute(request, executionCallback); - ASSERT_TRUE(executionLaunchStatus.isOk()); - EXPECT_EQ(ErrorStatus::NONE, static_cast(executionLaunchStatus)); - - // retrieve execution status - executionCallback->wait(); - ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus()); - - // validate results - outputMemory->read(); - copy_back(&test, outputs_info, outputPtr); - outputMemory->commit(); - // Filter out don't cares - MixedTyped filtered_golden = filter(golden, is_ignored); - MixedTyped filtered_test = filter(test, is_ignored); - - // We want "close-enough" results for float - compare(filtered_golden, filtered_test, fpAtol, fpRtol); - } + // We want "close-enough" results. + checkResults(testModel, outputs); } -void Execute(const sp& device, std::function create_model, - std::function is_ignored, const std::vector& examples) { - Model model = create_model(); +void Execute(const sp& device, const TestModel& testModel) { + Model model = createModel(testModel); // see if service can handle model bool fullySupportsModel = false; @@ -190,7 +167,6 @@ void Execute(const sp& device, std::function create_model, // launch prepare model sp preparedModelCallback = new PreparedModelCallback(); - ASSERT_NE(nullptr, preparedModelCallback.get()); Return prepareLaunchStatus = device->prepareModel(model, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); @@ -213,8 +189,7 @@ void Execute(const sp& device, std::function create_model, EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); ASSERT_NE(nullptr, preparedModel.get()); - float fpAtol = 1e-5f, fpRtol = 5.0f * 1.1920928955078125e-7f; - EvaluatePreparedModel(preparedModel, is_ignored, examples, fpAtol, fpRtol); + EvaluatePreparedModel(preparedModel, testModel); } } // namespace generated_tests diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h index 337eb0f924..5d22158529 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h @@ -26,10 +26,9 @@ namespace neuralnetworks { namespace V1_0 { namespace generated_tests { -using ::test_helper::MixedTypedExample; +Model createModel(const ::test_helper::TestModel& testModel); -void Execute(const sp& device, std::function create_model, - std::function is_ignored, const std::vector& examples); +void Execute(const sp& device, const ::test_helper::TestModel& testModel); } // namespace generated_tests } // namespace V1_0 diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTests.h b/neuralnetworks/1.0/vts/functional/GeneratedTests.h index 5cabf68c1d..9528905d61 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTests.h +++ b/neuralnetworks/1.0/vts/functional/GeneratedTests.h @@ -14,20 +14,11 @@ * limitations under the License. */ -#include -#include - +#include "1.0/Utils.h" #include "GeneratedTestHarness.h" -#include "MemoryUtils.h" #include "TestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_0::vts::functional { - -std::vector createRequests(const std::vector<::test_helper::MixedTypedExample>& examples); - -} // namespace android::hardware::neuralnetworks::V1_0::vts::functional - namespace android::hardware::neuralnetworks::V1_0::generated_tests { using namespace android::hardware::neuralnetworks::V1_0::vts::functional; diff --git a/neuralnetworks/1.0/vts/functional/Utils.cpp b/neuralnetworks/1.0/vts/functional/Utils.cpp index 521e524687..94ba183ee8 100644 --- a/neuralnetworks/1.0/vts/functional/Utils.cpp +++ b/neuralnetworks/1.0/vts/functional/Utils.cpp @@ -14,45 +14,99 @@ * limitations under the License. */ -#include "GeneratedTestHarness.h" +#include "1.0/Utils.h" + +#include "MemoryUtils.h" #include "TestHarness.h" +#include #include +#include +#include +#include -#include -#include #include namespace android { namespace hardware { namespace neuralnetworks { +using namespace test_helper; +using ::android::hardware::neuralnetworks::V1_0::DataLocation; +using ::android::hardware::neuralnetworks::V1_0::Request; using ::android::hardware::neuralnetworks::V1_0::RequestArgument; -using ::test_helper::for_each; -using ::test_helper::MixedTyped; +using ::android::hidl::memory::V1_0::IMemory; -template -void copy_back_(std::map>* dst, const std::vector& ra, - char* src) { - for_each(*dst, [&ra, src](int index, std::vector& m) { - ASSERT_EQ(m.size(), ra[index].location.length / sizeof(T)); - char* begin = src + ra[index].location.offset; - memcpy(m.data(), begin, ra[index].location.length); - }); +constexpr uint32_t kInputPoolIndex = 0; +constexpr uint32_t kOutputPoolIndex = 1; + +Request createRequest(const TestModel& testModel) { + // Model inputs. + hidl_vec inputs(testModel.inputIndexes.size()); + size_t inputSize = 0; + for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) { + const auto& op = testModel.operands[testModel.inputIndexes[i]]; + if (op.data.size() == 0) { + // Omitted input. + inputs[i] = {.hasNoValue = true}; + } else { + DataLocation loc = {.poolIndex = kInputPoolIndex, + .offset = static_cast(inputSize), + .length = static_cast(op.data.size())}; + inputSize += op.data.alignedSize(); + inputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}}; + } + } + + // Model outputs. + hidl_vec outputs(testModel.outputIndexes.size()); + size_t outputSize = 0; + for (uint32_t i = 0; i < testModel.outputIndexes.size(); i++) { + const auto& op = testModel.operands[testModel.outputIndexes[i]]; + size_t dataSize = op.data.size(); + DataLocation loc = {.poolIndex = kOutputPoolIndex, + .offset = static_cast(outputSize), + .length = static_cast(dataSize)}; + outputSize += op.data.alignedSize(); + outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}}; + } + + // Allocate memory pools. + hidl_vec pools = {nn::allocateSharedMemory(inputSize), + nn::allocateSharedMemory(outputSize)}; + CHECK_NE(pools[kInputPoolIndex].size(), 0u); + CHECK_NE(pools[kOutputPoolIndex].size(), 0u); + sp inputMemory = mapMemory(pools[kInputPoolIndex]); + CHECK(inputMemory.get() != nullptr); + uint8_t* inputPtr = static_cast(static_cast(inputMemory->getPointer())); + CHECK(inputPtr != nullptr); + + // Copy input data to the memory pool. + for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) { + const auto& op = testModel.operands[testModel.inputIndexes[i]]; + if (op.data.size() > 0) { + const uint8_t* begin = op.data.get(); + const uint8_t* end = begin + op.data.size(); + std::copy(begin, end, inputPtr + inputs[i].location.offset); + } + } + + return {.inputs = std::move(inputs), .outputs = std::move(outputs), .pools = std::move(pools)}; } -void copy_back(MixedTyped* dst, const std::vector& ra, char* src) { - copy_back_(&dst->float32Operands, ra, src); - copy_back_(&dst->int32Operands, ra, src); - copy_back_(&dst->quant8AsymmOperands, ra, src); - copy_back_(&dst->quant16SymmOperands, ra, src); - copy_back_(&dst->float16Operands, ra, src); - copy_back_(&dst->bool8Operands, ra, src); - copy_back_(&dst->quant8ChannelOperands, ra, src); - copy_back_(&dst->quant16AsymmOperands, ra, src); - copy_back_(&dst->quant8SymmOperands, ra, src); - static_assert(9 == MixedTyped::kNumTypes, - "Number of types in MixedTyped changed, but copy_back function wasn't updated"); +std::vector getOutputBuffers(const Request& request) { + sp outputMemory = mapMemory(request.pools[kOutputPoolIndex]); + CHECK(outputMemory.get() != nullptr); + uint8_t* outputPtr = static_cast(static_cast(outputMemory->getPointer())); + CHECK(outputPtr != nullptr); + + // Copy out output results. + std::vector outputBuffers; + for (const auto& output : request.outputs) { + outputBuffers.emplace_back(output.location.length, outputPtr + output.location.offset); + } + + return outputBuffers; } } // namespace neuralnetworks diff --git a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp index 058eb25002..d62365cb6a 100644 --- a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp @@ -16,13 +16,7 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" -#include -#include -#include - #include "1.0/Callbacks.h" -#include "MemoryUtils.h" -#include "TestHarness.h" #include "VtsHalNeuralnetworks.h" namespace android { @@ -33,10 +27,6 @@ namespace vts { namespace functional { using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; -using ::android::hidl::memory::V1_0::IMemory; -using test_helper::for_all; -using test_helper::MixedTyped; -using test_helper::MixedTypedExample; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// @@ -102,103 +92,10 @@ static void removeOutputTest(const sp& preparedModel, const Requ ///////////////////////////// ENTRY POINT ////////////////////////////////// -std::vector createRequests(const std::vector& examples) { - const uint32_t INPUT = 0; - const uint32_t OUTPUT = 1; - - std::vector requests; - - for (const MixedTypedExample& example : examples) { - const MixedTyped& inputs = example.operands.first; - const MixedTyped& outputs = example.operands.second; - - std::vector inputs_info, outputs_info; - uint32_t inputSize = 0, outputSize = 0; - - // This function only partially specifies the metadata (vector of RequestArguments). - // The contents are copied over below. - for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) { - if (inputs_info.size() <= static_cast(index)) inputs_info.resize(index + 1); - RequestArgument arg = { - .location = {.poolIndex = INPUT, - .offset = 0, - .length = static_cast(s)}, - .dimensions = {}, - }; - RequestArgument arg_empty = { - .hasNoValue = true, - }; - inputs_info[index] = s ? arg : arg_empty; - inputSize += s; - }); - // Compute offset for inputs 1 and so on - { - size_t offset = 0; - for (auto& i : inputs_info) { - if (!i.hasNoValue) i.location.offset = offset; - offset += i.location.length; - } - } - - // Go through all outputs, initialize RequestArgument descriptors - for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) { - if (outputs_info.size() <= static_cast(index)) outputs_info.resize(index + 1); - RequestArgument arg = { - .location = {.poolIndex = OUTPUT, - .offset = 0, - .length = static_cast(s)}, - .dimensions = {}, - }; - outputs_info[index] = arg; - outputSize += s; - }); - // Compute offset for outputs 1 and so on - { - size_t offset = 0; - for (auto& i : outputs_info) { - i.location.offset = offset; - offset += i.location.length; - } - } - std::vector pools = {nn::allocateSharedMemory(inputSize), - nn::allocateSharedMemory(outputSize)}; - if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) { - return {}; - } - - // map pool - sp inputMemory = mapMemory(pools[INPUT]); - if (inputMemory == nullptr) { - return {}; - } - char* inputPtr = reinterpret_cast(static_cast(inputMemory->getPointer())); - if (inputPtr == nullptr) { - return {}; - } - - // initialize pool - inputMemory->update(); - for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) { - char* begin = (char*)p; - char* end = begin + s; - // TODO: handle more than one input - std::copy(begin, end, inputPtr + inputs_info[index].location.offset); - }); - inputMemory->commit(); - - requests.push_back({.inputs = inputs_info, .outputs = outputs_info, .pools = pools}); - } - - return requests; -} - -void ValidationTest::validateRequests(const sp& preparedModel, - const std::vector& requests) { - // validate each request - for (const Request& request : requests) { - removeInputTest(preparedModel, request); - removeOutputTest(preparedModel, request); - } +void ValidationTest::validateRequest(const sp& preparedModel, + const Request& request) { + removeInputTest(preparedModel, request); + removeOutputTest(preparedModel, request); } } // namespace functional diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp index 95b7ad3e09..626deac143 100644 --- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp @@ -121,7 +121,7 @@ void NeuralnetworksHidlTest::TearDown() { ::testing::VtsHalHidlTargetTestBase::TearDown(); } -void ValidationTest::validateEverything(const Model& model, const std::vector& requests) { +void ValidationTest::validateEverything(const Model& model, const Request& request) { validateModel(model); // create IPreparedModel @@ -131,7 +131,7 @@ void ValidationTest::validateEverything(const Model& model, const std::vector& request); + void validateEverything(const Model& model, const Request& request); private: void validateModel(const Model& model); - void validateRequests(const sp& preparedModel, - const std::vector& requests); + void validateRequest(const sp& preparedModel, const Request& request); }; // Tag for the generated tests diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h index b270c20450..2955b6e35c 100644 --- a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h +++ b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h @@ -26,8 +26,11 @@ namespace android { namespace hardware { namespace neuralnetworks { -void copy_back(::test_helper::MixedTyped* dst, const std::vector& ra, - char* src); +// Create HIDL Request from the TestModel struct. +V1_0::Request createRequest(const ::test_helper::TestModel& testModel); + +// After execution, copy out output results from the output memory pool. +std::vector<::test_helper::TestBuffer> getOutputBuffers(const V1_0::Request& request); // Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation, // so this is efficiently accomplished by moving the element to the end and From 6aad0402780ba007ca027bf40707c0dc14c5f5fc Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Fri, 9 Aug 2019 16:41:16 -0700 Subject: [PATCH 0078/1022] Modify 1.1 VTS tests to consume test struct directly. This CL is very similar to the 1.0 VTS CL. The only difference is that 1.1 Models have an additional field for relaxed model computation. Bug: 123092187 Bug: 138718240 Test: All VTS Change-Id: I9264e5b2468b9c6db47d86683d24f8c2c5ec46aa --- neuralnetworks/1.1/vts/functional/Android.bp | 3 +- .../vts/functional/GeneratedTestHarness.cpp | 236 ++++++++---------- .../1.1/vts/functional/GeneratedTestHarness.h | 9 +- .../1.1/vts/functional/GeneratedTests.h | 11 +- .../1.1/vts/functional/ValidateRequest.cpp | 112 +-------- .../vts/functional/VtsHalNeuralnetworks.cpp | 4 +- .../1.1/vts/functional/VtsHalNeuralnetworks.h | 5 +- 7 files changed, 117 insertions(+), 263 deletions(-) diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp index 1b31008cbb..86002d21aa 100644 --- a/neuralnetworks/1.1/vts/functional/Android.bp +++ b/neuralnetworks/1.1/vts/functional/Android.bp @@ -34,13 +34,12 @@ cc_defaults { "android.hidl.memory@1.0", "libgmock", "libhidlmemory", + "libneuralnetworks_generated_test_harness", "libneuralnetworks_utils", "VtsHalNeuralNetworksV1_0_utils", ], header_libs: [ "libneuralnetworks_headers", - "libneuralnetworks_generated_test_harness_headers", - "libneuralnetworks_generated_tests", ], test_suites: ["general-tests"], } diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp index e7d59eca91..73eeb93a47 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include "1.0/Callbacks.h" @@ -37,8 +38,13 @@ namespace neuralnetworks { namespace V1_1 { namespace generated_tests { +using namespace test_helper; +using ::android::hardware::neuralnetworks::V1_0::DataLocation; using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; using ::android::hardware::neuralnetworks::V1_0::IPreparedModel; +using ::android::hardware::neuralnetworks::V1_0::Operand; +using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; +using ::android::hardware::neuralnetworks::V1_0::OperandType; using ::android::hardware::neuralnetworks::V1_0::Request; using ::android::hardware::neuralnetworks::V1_0::RequestArgument; using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; @@ -47,144 +53,112 @@ using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference; using ::android::hardware::neuralnetworks::V1_1::IDevice; using ::android::hardware::neuralnetworks::V1_1::Model; using ::android::hidl::memory::V1_0::IMemory; -using ::test_helper::compare; -using ::test_helper::filter; -using ::test_helper::for_all; -using ::test_helper::MixedTyped; -using ::test_helper::MixedTypedExample; -using ::test_helper::resize_accordingly; + +Model createModel(const TestModel& testModel) { + // Model operands. + hidl_vec operands(testModel.operands.size()); + size_t constCopySize = 0, constRefSize = 0; + for (uint32_t i = 0; i < testModel.operands.size(); i++) { + const auto& op = testModel.operands[i]; + + DataLocation loc = {}; + if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { + loc = {.poolIndex = 0, + .offset = static_cast(constCopySize), + .length = static_cast(op.data.size())}; + constCopySize += op.data.alignedSize(); + } else if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) { + loc = {.poolIndex = 0, + .offset = static_cast(constRefSize), + .length = static_cast(op.data.size())}; + constRefSize += op.data.alignedSize(); + } + + operands[i] = {.type = static_cast(op.type), + .dimensions = op.dimensions, + .numberOfConsumers = op.numberOfConsumers, + .scale = op.scale, + .zeroPoint = op.zeroPoint, + .lifetime = static_cast(op.lifetime), + .location = loc}; + } + + // Model operations. + hidl_vec operations(testModel.operations.size()); + std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(), + [](const TestOperation& op) -> Operation { + return {.type = static_cast(op.type), + .inputs = op.inputs, + .outputs = op.outputs}; + }); + + // Constant copies. + hidl_vec operandValues(constCopySize); + for (uint32_t i = 0; i < testModel.operands.size(); i++) { + const auto& op = testModel.operands[i]; + if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { + const uint8_t* begin = op.data.get(); + const uint8_t* end = begin + op.data.size(); + std::copy(begin, end, operandValues.data() + operands[i].location.offset); + } + } + + // Shared memory. + hidl_vec pools; + if (constRefSize > 0) { + hidl_vec_push_back(&pools, nn::allocateSharedMemory(constRefSize)); + CHECK_NE(pools[0].size(), 0u); + + // load data + sp mappedMemory = mapMemory(pools[0]); + CHECK(mappedMemory.get() != nullptr); + uint8_t* mappedPtr = + reinterpret_cast(static_cast(mappedMemory->getPointer())); + CHECK(mappedPtr != nullptr); + + for (uint32_t i = 0; i < testModel.operands.size(); i++) { + const auto& op = testModel.operands[i]; + if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) { + const uint8_t* begin = op.data.get(); + const uint8_t* end = begin + op.data.size(); + std::copy(begin, end, mappedPtr + operands[i].location.offset); + } + } + } + + return {.operands = std::move(operands), + .operations = std::move(operations), + .inputIndexes = testModel.inputIndexes, + .outputIndexes = testModel.outputIndexes, + .operandValues = std::move(operandValues), + .pools = std::move(pools), + .relaxComputationFloat32toFloat16 = testModel.isRelaxed}; +} // Top level driver for models and examples generated by test_generator.py // Test driver for those generated from ml/nn/runtime/test/spec -void EvaluatePreparedModel(sp& preparedModel, std::function is_ignored, - const std::vector& examples, - bool hasRelaxedFloat32Model, float fpAtol, float fpRtol) { - const uint32_t INPUT = 0; - const uint32_t OUTPUT = 1; +void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel) { + const Request request = createRequest(testModel); - int example_no = 1; - for (auto& example : examples) { - SCOPED_TRACE(example_no++); - const MixedTyped& inputs = example.operands.first; - const MixedTyped& golden = example.operands.second; + // Launch execution. + sp executionCallback = new ExecutionCallback(); + Return executionLaunchStatus = preparedModel->execute(request, executionCallback); + ASSERT_TRUE(executionLaunchStatus.isOk()); + EXPECT_EQ(ErrorStatus::NONE, static_cast(executionLaunchStatus)); - const bool hasFloat16Inputs = !inputs.float16Operands.empty(); - if (hasRelaxedFloat32Model || hasFloat16Inputs) { - // TODO: Adjust the error limit based on testing. - // If in relaxed mode, set the absolute tolerance to be 5ULP of FP16. - fpAtol = 5.0f * 0.0009765625f; - // Set the relative tolerance to be 5ULP of the corresponding FP precision. - fpRtol = 5.0f * 0.0009765625f; - } + // Retrieve execution status. + executionCallback->wait(); + ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus()); - std::vector inputs_info, outputs_info; - uint32_t inputSize = 0, outputSize = 0; - // This function only partially specifies the metadata (vector of RequestArguments). - // The contents are copied over below. - for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) { - if (inputs_info.size() <= static_cast(index)) inputs_info.resize(index + 1); - RequestArgument arg = { - .location = {.poolIndex = INPUT, - .offset = 0, - .length = static_cast(s)}, - .dimensions = {}, - }; - RequestArgument arg_empty = { - .hasNoValue = true, - }; - inputs_info[index] = s ? arg : arg_empty; - inputSize += s; - }); - // Compute offset for inputs 1 and so on - { - size_t offset = 0; - for (auto& i : inputs_info) { - if (!i.hasNoValue) i.location.offset = offset; - offset += i.location.length; - } - } + // Retrieve execution results. + const std::vector outputs = getOutputBuffers(request); - MixedTyped test; // holding test results - - // Go through all outputs, initialize RequestArgument descriptors - resize_accordingly(golden, test); - for_all(golden, [&outputs_info, &outputSize](int index, auto, auto s) { - if (outputs_info.size() <= static_cast(index)) outputs_info.resize(index + 1); - RequestArgument arg = { - .location = {.poolIndex = OUTPUT, - .offset = 0, - .length = static_cast(s)}, - .dimensions = {}, - }; - outputs_info[index] = arg; - outputSize += s; - }); - // Compute offset for outputs 1 and so on - { - size_t offset = 0; - for (auto& i : outputs_info) { - i.location.offset = offset; - offset += i.location.length; - } - } - std::vector pools = {nn::allocateSharedMemory(inputSize), - nn::allocateSharedMemory(outputSize)}; - ASSERT_NE(0ull, pools[INPUT].size()); - ASSERT_NE(0ull, pools[OUTPUT].size()); - - // load data - sp inputMemory = mapMemory(pools[INPUT]); - sp outputMemory = mapMemory(pools[OUTPUT]); - ASSERT_NE(nullptr, inputMemory.get()); - ASSERT_NE(nullptr, outputMemory.get()); - char* inputPtr = reinterpret_cast(static_cast(inputMemory->getPointer())); - char* outputPtr = reinterpret_cast(static_cast(outputMemory->getPointer())); - ASSERT_NE(nullptr, inputPtr); - ASSERT_NE(nullptr, outputPtr); - inputMemory->update(); - outputMemory->update(); - - // Go through all inputs, copy the values - for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) { - char* begin = (char*)p; - char* end = begin + s; - // TODO: handle more than one input - std::copy(begin, end, inputPtr + inputs_info[index].location.offset); - }); - - inputMemory->commit(); - outputMemory->commit(); - - const Request request = {.inputs = inputs_info, .outputs = outputs_info, .pools = pools}; - - // launch execution - sp executionCallback = new ExecutionCallback(); - ASSERT_NE(nullptr, executionCallback.get()); - Return executionLaunchStatus = - preparedModel->execute(request, executionCallback); - ASSERT_TRUE(executionLaunchStatus.isOk()); - EXPECT_EQ(ErrorStatus::NONE, static_cast(executionLaunchStatus)); - - // retrieve execution status - executionCallback->wait(); - ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus()); - - // validate results - outputMemory->read(); - copy_back(&test, outputs_info, outputPtr); - outputMemory->commit(); - // Filter out don't cares - MixedTyped filtered_golden = filter(golden, is_ignored); - MixedTyped filtered_test = filter(test, is_ignored); - - // We want "close-enough" results for float - compare(filtered_golden, filtered_test, fpAtol, fpRtol); - } + // We want "close-enough" results. + checkResults(testModel, outputs); } -void Execute(const sp& device, std::function create_model, - std::function is_ignored, const std::vector& examples) { - Model model = create_model(); +void Execute(const sp& device, const TestModel& testModel) { + Model model = createModel(testModel); // see if service can handle model bool fullySupportsModel = false; @@ -199,7 +173,6 @@ void Execute(const sp& device, std::function create_model, // launch prepare model sp preparedModelCallback = new PreparedModelCallback(); - ASSERT_NE(nullptr, preparedModelCallback.get()); Return prepareLaunchStatus = device->prepareModel_1_1( model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); @@ -223,8 +196,7 @@ void Execute(const sp& device, std::function create_model, EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); ASSERT_NE(nullptr, preparedModel.get()); - EvaluatePreparedModel(preparedModel, is_ignored, examples, - model.relaxComputationFloat32toFloat16, 1e-5f, 1e-5f); + EvaluatePreparedModel(preparedModel, testModel); } } // namespace generated_tests diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h index 64b88dd689..56fc8257bd 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h @@ -18,9 +18,6 @@ #define ANDROID_HARDWARE_NEURALNETWORKS_V1_1_GENERATED_TEST_HARNESS_H #include -#include -#include -#include #include "TestHarness.h" namespace android { @@ -29,9 +26,9 @@ namespace neuralnetworks { namespace V1_1 { namespace generated_tests { -void Execute(const sp& device, std::function create_model, - std::function is_ignored, - const std::vector<::test_helper::MixedTypedExample>& examples); +Model createModel(const ::test_helper::TestModel& testModel); + +void Execute(const sp& device, const ::test_helper::TestModel& testModel); } // namespace generated_tests } // namespace V1_1 diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTests.h b/neuralnetworks/1.1/vts/functional/GeneratedTests.h index 80442bfece..a55213d2a6 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTests.h +++ b/neuralnetworks/1.1/vts/functional/GeneratedTests.h @@ -14,20 +14,11 @@ * limitations under the License. */ -#include -#include - +#include "1.0/Utils.h" #include "GeneratedTestHarness.h" -#include "MemoryUtils.h" #include "TestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_1::vts::functional { - -std::vector createRequests(const std::vector<::test_helper::MixedTypedExample>& examples); - -} // namespace android::hardware::neuralnetworks::V1_1::vts::functional - namespace android::hardware::neuralnetworks::V1_1::generated_tests { using namespace android::hardware::neuralnetworks::V1_1::vts::functional; diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp index c54972887e..757bee9711 100644 --- a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp @@ -16,14 +16,8 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" -#include -#include -#include - #include "1.0/Callbacks.h" #include "1.0/Utils.h" -#include "MemoryUtils.h" -#include "TestHarness.h" #include "VtsHalNeuralnetworks.h" namespace android { @@ -35,13 +29,8 @@ namespace functional { using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; using ::android::hardware::neuralnetworks::V1_0::Request; -using ::android::hardware::neuralnetworks::V1_0::RequestArgument; using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; using ::android::hardware::neuralnetworks::V1_1::IPreparedModel; -using ::android::hidl::memory::V1_0::IMemory; -using ::test_helper::for_all; -using ::test_helper::MixedTyped; -using ::test_helper::MixedTypedExample; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// @@ -87,103 +76,10 @@ static void removeOutputTest(const sp& preparedModel, const Requ ///////////////////////////// ENTRY POINT ////////////////////////////////// -std::vector createRequests(const std::vector& examples) { - const uint32_t INPUT = 0; - const uint32_t OUTPUT = 1; - - std::vector requests; - - for (auto& example : examples) { - const MixedTyped& inputs = example.operands.first; - const MixedTyped& outputs = example.operands.second; - - std::vector inputs_info, outputs_info; - uint32_t inputSize = 0, outputSize = 0; - - // This function only partially specifies the metadata (vector of RequestArguments). - // The contents are copied over below. - for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) { - if (inputs_info.size() <= static_cast(index)) inputs_info.resize(index + 1); - RequestArgument arg = { - .location = {.poolIndex = INPUT, - .offset = 0, - .length = static_cast(s)}, - .dimensions = {}, - }; - RequestArgument arg_empty = { - .hasNoValue = true, - }; - inputs_info[index] = s ? arg : arg_empty; - inputSize += s; - }); - // Compute offset for inputs 1 and so on - { - size_t offset = 0; - for (auto& i : inputs_info) { - if (!i.hasNoValue) i.location.offset = offset; - offset += i.location.length; - } - } - - // Go through all outputs, initialize RequestArgument descriptors - for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) { - if (outputs_info.size() <= static_cast(index)) outputs_info.resize(index + 1); - RequestArgument arg = { - .location = {.poolIndex = OUTPUT, - .offset = 0, - .length = static_cast(s)}, - .dimensions = {}, - }; - outputs_info[index] = arg; - outputSize += s; - }); - // Compute offset for outputs 1 and so on - { - size_t offset = 0; - for (auto& i : outputs_info) { - i.location.offset = offset; - offset += i.location.length; - } - } - std::vector pools = {nn::allocateSharedMemory(inputSize), - nn::allocateSharedMemory(outputSize)}; - if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) { - return {}; - } - - // map pool - sp inputMemory = mapMemory(pools[INPUT]); - if (inputMemory == nullptr) { - return {}; - } - char* inputPtr = reinterpret_cast(static_cast(inputMemory->getPointer())); - if (inputPtr == nullptr) { - return {}; - } - - // initialize pool - inputMemory->update(); - for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) { - char* begin = (char*)p; - char* end = begin + s; - // TODO: handle more than one input - std::copy(begin, end, inputPtr + inputs_info[index].location.offset); - }); - inputMemory->commit(); - - requests.push_back({.inputs = inputs_info, .outputs = outputs_info, .pools = pools}); - } - - return requests; -} - -void ValidationTest::validateRequests(const sp& preparedModel, - const std::vector& requests) { - // validate each request - for (const Request& request : requests) { - removeInputTest(preparedModel, request); - removeOutputTest(preparedModel, request); - } +void ValidationTest::validateRequest(const sp& preparedModel, + const Request& request) { + removeInputTest(preparedModel, request); + removeOutputTest(preparedModel, request); } } // namespace functional diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp index 12bdd3ffb6..b3b15fa8e5 100644 --- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp @@ -122,7 +122,7 @@ void NeuralnetworksHidlTest::TearDown() { ::testing::VtsHalHidlTargetTestBase::TearDown(); } -void ValidationTest::validateEverything(const Model& model, const std::vector& requests) { +void ValidationTest::validateEverything(const Model& model, const Request& request) { validateModel(model); // create IPreparedModel @@ -132,7 +132,7 @@ void ValidationTest::validateEverything(const Model& model, const std::vector& request); + void validateEverything(const Model& model, const Request& request); private: void validateModel(const Model& model); - void validateRequests(const sp& preparedModel, - const std::vector& requests); + void validateRequest(const sp& preparedModel, const Request& request); }; // Tag for the generated tests From a51eb93c51eba86075b1ba5492b667dd0e720e4c Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Fri, 21 Jun 2019 09:13:35 -0700 Subject: [PATCH 0079/1022] gralloc: add IAllocator/IMapper 4.0 to camera HIDL Add support for gralloc 4.0 to camera interface. Bug: 136016160 Test: VtsHalCameraProviderV2_4TargetTest on a pixel with a local rev'd version of gralloc 4.0. Change-Id: I7f2e14c291fbdafcb68c1e9c6e94fed87d810191 --- camera/common/1.0/default/Android.bp | 1 + camera/common/1.0/default/HandleImporter.cpp | 56 ++++++++++++++++--- .../1.0/default/include/HandleImporter.h | 4 +- camera/device/1.0/default/Android.bp | 1 + camera/device/3.2/default/Android.bp | 1 + camera/device/3.3/default/Android.bp | 1 + camera/device/3.4/default/Android.bp | 2 + camera/device/3.5/default/Android.bp | 4 +- camera/provider/2.4/default/Android.bp | 6 ++ camera/provider/2.4/vts/functional/Android.bp | 2 + .../VtsHalCameraProviderV2_4TargetTest.cpp | 35 +++++++++++- 11 files changed, 101 insertions(+), 12 deletions(-) diff --git a/camera/common/1.0/default/Android.bp b/camera/common/1.0/default/Android.bp index 3e5c6d7812..f4390b2e30 100644 --- a/camera/common/1.0/default/Android.bp +++ b/camera/common/1.0/default/Android.bp @@ -21,6 +21,7 @@ cc_library_static { "libcamera_metadata", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "libexif", ], include_dirs: ["system/media/private/camera/include"], diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp index b8c40e95b8..76f97789c0 100644 --- a/camera/common/1.0/default/HandleImporter.cpp +++ b/camera/common/1.0/default/HandleImporter.cpp @@ -27,7 +27,9 @@ namespace helper { using MapperErrorV2 = android::hardware::graphics::mapper::V2_0::Error; using MapperErrorV3 = android::hardware::graphics::mapper::V3_0::Error; +using MapperErrorV4 = android::hardware::graphics::mapper::V4_0::Error; using IMapperV3 = android::hardware::graphics::mapper::V3_0::IMapper; +using IMapperV4 = android::hardware::graphics::mapper::V4_0::IMapper; HandleImporter::HandleImporter() : mInitialized(false) {} @@ -36,6 +38,12 @@ void HandleImporter::initializeLocked() { return; } + mMapperV4 = IMapperV4::getService(); + if (mMapperV4 != nullptr) { + mInitialized = true; + return; + } + mMapperV3 = IMapperV3::getService(); if (mMapperV3 != nullptr) { mInitialized = true; @@ -53,6 +61,7 @@ void HandleImporter::initializeLocked() { } void HandleImporter::cleanup() { + mMapperV4.clear(); mMapperV3.clear(); mMapperV2.clear(); mInitialized = false; @@ -151,6 +160,10 @@ bool HandleImporter::importBuffer(buffer_handle_t& handle) { initializeLocked(); } + if (mMapperV4 != nullptr) { + return importBufferInternal(mMapperV4, handle); + } + if (mMapperV3 != nullptr) { return importBufferInternal(mMapperV3, handle); } @@ -159,7 +172,7 @@ bool HandleImporter::importBuffer(buffer_handle_t& handle) { return importBufferInternal(mMapperV2, handle); } - ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__); + ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__); return false; } @@ -169,12 +182,17 @@ void HandleImporter::freeBuffer(buffer_handle_t handle) { } Mutex::Autolock lock(mLock); - if (mMapperV3 == nullptr && mMapperV2 == nullptr) { - ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__); + if (mMapperV4 == nullptr && mMapperV3 == nullptr && mMapperV2 == nullptr) { + ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__); return; } - if (mMapperV3 != nullptr) { + if (mMapperV4 != nullptr) { + auto ret = mMapperV4->freeBuffer(const_cast(handle)); + if (!ret.isOk()) { + ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str()); + } + } else if (mMapperV3 != nullptr) { auto ret = mMapperV3->freeBuffer(const_cast(handle)); if (!ret.isOk()) { ALOGE("%s: mapper freeBuffer failed: %s", @@ -222,14 +240,27 @@ void* HandleImporter::lock( initializeLocked(); } - if (mMapperV3 == nullptr && mMapperV2 == nullptr) { - ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__); + if (mMapperV4 == nullptr && mMapperV3 == nullptr && mMapperV2 == nullptr) { + ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__); return ret; } hidl_handle acquireFenceHandle; auto buffer = const_cast(buf); - if (mMapperV3 != nullptr) { + if (mMapperV4 != nullptr) { + IMapperV4::Rect accessRegion{0, 0, static_cast(size), 1}; + // No need to use bytesPerPixel and bytesPerStride because we are using + // an 1-D buffer and accressRegion. + mMapperV4->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle, + [&](const auto& tmpError, const auto& tmpPtr, const auto& /*bytesPerPixel*/, + const auto& /*bytesPerStride*/) { + if (tmpError == MapperErrorV4::NONE) { + ret = tmpPtr; + } else { + ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError); + } + }); + } else if (mMapperV3 != nullptr) { IMapperV3::Rect accessRegion { 0, 0, static_cast(size), 1 }; // No need to use bytesPerPixel and bytesPerStride because we are using // an 1-D buffer and accressRegion. @@ -269,6 +300,10 @@ YCbCrLayout HandleImporter::lockYCbCr( initializeLocked(); } + if (mMapperV4 != nullptr) { + return lockYCbCrInternal(mMapperV4, buf, cpuUsage, accessRegion); + } + if (mMapperV3 != nullptr) { return lockYCbCrInternal( mMapperV3, buf, cpuUsage, accessRegion); @@ -279,11 +314,14 @@ YCbCrLayout HandleImporter::lockYCbCr( mMapperV2, buf, cpuUsage, accessRegion); } - ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__); + ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__); return {}; } int HandleImporter::unlock(buffer_handle_t& buf) { + if (mMapperV4 != nullptr) { + return unlockInternal(mMapperV4, buf); + } if (mMapperV3 != nullptr) { return unlockInternal(mMapperV3, buf); } @@ -291,7 +329,7 @@ int HandleImporter::unlock(buffer_handle_t& buf) { return unlockInternal(mMapperV2, buf); } - ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__); + ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__); return -1; } diff --git a/camera/common/1.0/default/include/HandleImporter.h b/camera/common/1.0/default/include/HandleImporter.h index a93d4554ad..fc2bbd1197 100644 --- a/camera/common/1.0/default/include/HandleImporter.h +++ b/camera/common/1.0/default/include/HandleImporter.h @@ -17,10 +17,11 @@ #ifndef CAMERA_COMMON_1_0_HANDLEIMPORTED_H #define CAMERA_COMMON_1_0_HANDLEIMPORTED_H -#include #include #include +#include #include +#include using android::hardware::graphics::mapper::V2_0::IMapper; using android::hardware::graphics::mapper::V2_0::YCbCrLayout; @@ -70,6 +71,7 @@ private: bool mInitialized; sp mMapperV2; sp mMapperV3; + sp mMapperV4; }; } // namespace helper diff --git a/camera/device/1.0/default/Android.bp b/camera/device/1.0/default/Android.bp index aa3b941c2e..c3518d3325 100644 --- a/camera/device/1.0/default/Android.bp +++ b/camera/device/1.0/default/Android.bp @@ -16,6 +16,7 @@ cc_library_shared { "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "android.hardware.graphics.common@1.0", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", diff --git a/camera/device/3.2/default/Android.bp b/camera/device/3.2/default/Android.bp index edb008ed62..edc2988fc6 100644 --- a/camera/device/3.2/default/Android.bp +++ b/camera/device/3.2/default/Android.bp @@ -14,6 +14,7 @@ cc_library_shared { "android.hardware.camera.provider@2.4", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "liblog", "libhardware", "libcamera_metadata", diff --git a/camera/device/3.3/default/Android.bp b/camera/device/3.3/default/Android.bp index 39d379d049..f3c2e0e414 100644 --- a/camera/device/3.3/default/Android.bp +++ b/camera/device/3.3/default/Android.bp @@ -16,6 +16,7 @@ cc_library_shared { "android.hardware.camera.provider@2.4", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "liblog", "libhardware", "libcamera_metadata", diff --git a/camera/device/3.4/default/Android.bp b/camera/device/3.4/default/Android.bp index c22b13c2c4..8e699d83d0 100644 --- a/camera/device/3.4/default/Android.bp +++ b/camera/device/3.4/default/Android.bp @@ -49,6 +49,7 @@ cc_library_shared { "android.hardware.camera.provider@2.4", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "liblog", "libhardware", "libcamera_metadata", @@ -86,6 +87,7 @@ cc_library_shared { "android.hardware.camera.provider@2.4", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "liblog", "libhardware", "libcamera_metadata", diff --git a/camera/device/3.5/default/Android.bp b/camera/device/3.5/default/Android.bp index 26b3b6734b..dde585eb6a 100644 --- a/camera/device/3.5/default/Android.bp +++ b/camera/device/3.5/default/Android.bp @@ -50,6 +50,7 @@ cc_library_shared { "android.hardware.camera.provider@2.4", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "liblog", "libhardware", "libcamera_metadata", @@ -83,7 +84,8 @@ cc_library_shared { "android.hardware.camera.device@3.5", "android.hardware.camera.provider@2.4", "android.hardware.graphics.mapper@2.0", - "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "liblog", "libhardware", "libcamera_metadata", diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp index cb78fcb859..313b29bf8d 100644 --- a/camera/provider/2.4/default/Android.bp +++ b/camera/provider/2.4/default/Android.bp @@ -13,6 +13,7 @@ cc_library_shared { "android.hardware.camera.provider@2.4", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "camera.device@1.0-impl", @@ -52,6 +53,7 @@ cc_library_shared { "android.hardware.camera.provider@2.4", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "camera.device@3.3-impl", @@ -95,6 +97,8 @@ cc_library_shared { "android.hardware.camera.provider@2.4-external", "android.hardware.camera.provider@2.4-legacy", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "camera.device@1.0-impl", @@ -140,6 +144,8 @@ cc_defaults { "android.hardware.camera.device@3.5", "android.hardware.camera.provider@2.4", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "libbinder", diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp index 2c3ed37a6a..5fe7b197d0 100644 --- a/camera/provider/2.4/vts/functional/Android.bp +++ b/camera/provider/2.4/vts/functional/Android.bp @@ -43,9 +43,11 @@ cc_test { "android.hardware.camera.provider@2.5", "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.allocator@3.0", + "android.hardware.graphics.allocator@4.0", "android.hardware.graphics.common@1.0", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "android.hidl.allocator@1.0", "libgrallocusage", "libhidlmemory", diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index a5369e7b8d..6f6479d18d 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -55,9 +55,11 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -6148,13 +6150,44 @@ void CameraHidlTest::allocateGraphicBuffer(uint32_t width, uint32_t height, uint android::hardware::graphics::allocator::V2_0::IAllocator::getService(); sp allocatorV3 = android::hardware::graphics::allocator::V3_0::IAllocator::getService(); + sp allocatorV4 = + android::hardware::graphics::allocator::V4_0::IAllocator::getService(); + sp mapperV4 = + android::hardware::graphics::mapper::V4_0::IMapper::getService(); sp mapperV3 = android::hardware::graphics::mapper::V3_0::IMapper::getService(); sp mapper = android::hardware::graphics::mapper::V2_0::IMapper::getService(); ::android::hardware::hidl_vec descriptor; - if (mapperV3 != nullptr && allocatorV3 != nullptr) { + if (mapperV4 != nullptr && allocatorV4 != nullptr) { + android::hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo descriptorInfo{}; + descriptorInfo.width = width; + descriptorInfo.height = height; + descriptorInfo.layerCount = 1; + descriptorInfo.format = + static_cast(format); + descriptorInfo.usage = usage; + + auto ret = mapperV4->createDescriptor( + descriptorInfo, [&descriptor](android::hardware::graphics::mapper::V4_0::Error err, + ::android::hardware::hidl_vec desc) { + ASSERT_EQ(err, android::hardware::graphics::mapper::V4_0::Error::NONE); + descriptor = desc; + }); + ASSERT_TRUE(ret.isOk()); + + ret = allocatorV4->allocate( + descriptor, 1u, + [&](android::hardware::graphics::mapper::V4_0::Error err, uint32_t /*stride*/, + const ::android::hardware::hidl_vec<::android::hardware::hidl_handle>& + buffers) { + ASSERT_EQ(android::hardware::graphics::mapper::V4_0::Error::NONE, err); + ASSERT_EQ(buffers.size(), 1u); + *buffer_handle = buffers[0]; + }); + ASSERT_TRUE(ret.isOk()); + } else if (mapperV3 != nullptr && allocatorV3 != nullptr) { android::hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo descriptorInfo {}; descriptorInfo.width = width; descriptorInfo.height = height; From 79e0167feacd3a50162406ab871771c6979ae74c Mon Sep 17 00:00:00 2001 From: Amy Date: Wed, 21 Aug 2019 13:54:39 -0700 Subject: [PATCH 0080/1022] Adding OWNER for the TunerHAL implementation Test: manual Change-Id: Ia716b7ddabe80203b19d80cf54efb7fb93df3e10 --- tv/tuner/1.0/default/OWNERS | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tv/tuner/1.0/default/OWNERS diff --git a/tv/tuner/1.0/default/OWNERS b/tv/tuner/1.0/default/OWNERS new file mode 100644 index 0000000000..1b3d095f9c --- /dev/null +++ b/tv/tuner/1.0/default/OWNERS @@ -0,0 +1,4 @@ +nchalko@google.com +amyjojo@google.com +shubang@google.com +quxiangfang@google.com From 491b0a89133b8519a68b5999cf3b227c750f6deb Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Fri, 9 Aug 2019 16:45:24 -0700 Subject: [PATCH 0081/1022] Modify 1.2 VTS tests to consume test struct directly. Comparing with v1.1, the converter for 1.2 HIDL model has additional support for extraParam, dynamic output shape, and zero-sized output. Modify CompilationCachingTests to use the new test struct. Bug: 123092187 Bug: 138718240 Test: All VTS Change-Id: I54ac97f62898e47a338b51cc6d895a0309ab001f --- neuralnetworks/1.0/vts/functional/Utils.cpp | 15 +- neuralnetworks/1.2/vts/functional/Android.bp | 5 +- .../functional/CompilationCachingTests.cpp | 339 +++++------ .../vts/functional/GeneratedTestHarness.cpp | 563 +++++++++--------- .../1.2/vts/functional/GeneratedTestHarness.h | 11 +- .../1.2/vts/functional/GeneratedTests.h | 12 +- .../1.2/vts/functional/ValidateBurst.cpp | 100 ++-- .../1.2/vts/functional/ValidateRequest.cpp | 134 +---- .../vts/functional/VtsHalNeuralnetworks.cpp | 10 +- .../1.2/vts/functional/VtsHalNeuralnetworks.h | 14 +- 10 files changed, 492 insertions(+), 711 deletions(-) diff --git a/neuralnetworks/1.0/vts/functional/Utils.cpp b/neuralnetworks/1.0/vts/functional/Utils.cpp index 94ba183ee8..5aa27516db 100644 --- a/neuralnetworks/1.0/vts/functional/Utils.cpp +++ b/neuralnetworks/1.0/vts/functional/Utils.cpp @@ -25,6 +25,7 @@ #include #include +#include #include namespace android { @@ -63,11 +64,19 @@ Request createRequest(const TestModel& testModel) { size_t outputSize = 0; for (uint32_t i = 0; i < testModel.outputIndexes.size(); i++) { const auto& op = testModel.operands[testModel.outputIndexes[i]]; - size_t dataSize = op.data.size(); + + // In the case of zero-sized output, we should at least provide a one-byte buffer. + // This is because zero-sized tensors are only supported internally to the driver, or + // reported in output shapes. It is illegal for the client to pre-specify a zero-sized + // tensor as model output. Otherwise, we will have two semantic conflicts: + // - "Zero dimension" conflicts with "unspecified dimension". + // - "Omitted operand buffer" conflicts with "zero-sized operand buffer". + size_t bufferSize = std::max(op.data.size(), 1); + DataLocation loc = {.poolIndex = kOutputPoolIndex, .offset = static_cast(outputSize), - .length = static_cast(dataSize)}; - outputSize += op.data.alignedSize(); + .length = static_cast(bufferSize)}; + outputSize += op.data.size() == 0 ? TestBuffer::kAlignment : op.data.alignedSize(); outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}}; } diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index 301ca5d065..e14430f45d 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -37,13 +37,12 @@ cc_defaults { "android.hidl.memory@1.0", "libgmock", "libhidlmemory", + "libneuralnetworks_generated_test_harness", "libneuralnetworks_utils", "VtsHalNeuralNetworksV1_0_utils", ], header_libs: [ "libneuralnetworks_headers", - "libneuralnetworks_generated_test_harness_headers", - "libneuralnetworks_generated_tests", ], test_suites: ["general-tests"], } @@ -75,8 +74,8 @@ cc_test { srcs: [ "BasicTests.cpp", ":VtsHalNeuralNetworksV1_2_all_generated_V1_2_tests", + ":VtsHalNeuralNetworksV1_2_mobilenets", "CompilationCachingTests.cpp", - ":VtsHalNeuralNetworksV1_2_mobilenets", // CompilationCachingTests depend on MobileNets. "ValidateBurst.cpp", ], } diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp index 590764635e..8747fb3bf5 100644 --- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp @@ -35,22 +35,14 @@ #include "Utils.h" #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_2 { +// Forward declaration of the mobilenet generated test models in +// frameworks/ml/nn/runtime/test/generated/. namespace generated_tests::mobilenet_224_gender_basic_fixed { -Model createTestModel(); +const ::test_helper::TestModel& get_test_model(); } // namespace generated_tests::mobilenet_224_gender_basic_fixed -} // namespace android::hardware::neuralnetworks::V1_2 - -namespace generated_tests::mobilenet_224_gender_basic_fixed { -std::vector& get_examples(); -} // namespace generated_tests::mobilenet_224_gender_basic_fixed - -namespace android::hardware::neuralnetworks::V1_2::generated_tests::mobilenet_quantized { -Model createTestModel(); -} // namespace android::hardware::neuralnetworks::V1_2::generated_tests::mobilenet_quantized namespace generated_tests::mobilenet_quantized { -std::vector& get_examples(); +const ::test_helper::TestModel& get_test_model(); } // namespace generated_tests::mobilenet_quantized namespace android { @@ -60,49 +52,23 @@ namespace V1_2 { namespace vts { namespace functional { +using namespace test_helper; using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference; using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; using ::android::hidl::memory::V1_0::IMemory; using ::android::nn::allocateSharedMemory; -using ::test_helper::MixedTypedExample; namespace float32_model { -constexpr auto createTestModel = ::android::hardware::neuralnetworks::V1_2::generated_tests:: - mobilenet_224_gender_basic_fixed::createTestModel; -constexpr auto get_examples = ::generated_tests::mobilenet_224_gender_basic_fixed::get_examples; - -// MixedTypedExample is defined in frameworks/ml/nn/tools/test_generator/include/TestHarness.h. -// This function assumes the operation is always ADD. -std::vector getLargeModelExamples(uint32_t len) { - float outputValue = 1.0f + static_cast(len); - return {{.operands = { - // Input - {.operandDimensions = {{0, {1}}}, .float32Operands = {{0, {1.0f}}}}, - // Output - {.operandDimensions = {{0, {1}}}, .float32Operands = {{0, {outputValue}}}}}}}; -} +constexpr auto get_test_model = ::generated_tests::mobilenet_224_gender_basic_fixed::get_test_model; } // namespace float32_model namespace quant8_model { -constexpr auto createTestModel = ::android::hardware::neuralnetworks::V1_2::generated_tests:: - mobilenet_quantized::createTestModel; -constexpr auto get_examples = ::generated_tests::mobilenet_quantized::get_examples; - -// MixedTypedExample is defined in frameworks/ml/nn/tools/test_generator/include/TestHarness.h. -// This function assumes the operation is always ADD. -std::vector getLargeModelExamples(uint32_t len) { - uint8_t outputValue = 1 + static_cast(len); - return {{.operands = {// Input - {.operandDimensions = {{0, {1}}}, .quant8AsymmOperands = {{0, {1}}}}, - // Output - {.operandDimensions = {{0, {1}}}, - .quant8AsymmOperands = {{0, {outputValue}}}}}}}; -} +constexpr auto get_test_model = ::generated_tests::mobilenet_quantized::get_test_model; } // namespace quant8_model @@ -155,39 +121,34 @@ void createCacheHandles(const std::vector>& fileGroups, // [1] [1] [1] [1] // // This function assumes the operation is either ADD or MUL. -template -Model createLargeTestModelImpl(OperationType op, uint32_t len) { - EXPECT_TRUE(op == OperationType::ADD || op == OperationType::MUL); +template +TestModel createLargeTestModelImpl(TestOperationType op, uint32_t len) { + EXPECT_TRUE(op == TestOperationType::ADD || op == TestOperationType::MUL); // Model operations and operands. - std::vector operations(len); - std::vector operands(len * 2 + 2); - - // The constant buffer pool. This contains the activation scalar, followed by the - // per-operation constant operands. - std::vector operandValues(sizeof(int32_t) + len * sizeof(CppType)); + std::vector operations(len); + std::vector operands(len * 2 + 2); // The activation scalar, value = 0. operands[0] = { - .type = OperandType::INT32, + .type = TestOperandType::INT32, .dimensions = {}, .numberOfConsumers = len, .scale = 0.0f, .zeroPoint = 0, - .lifetime = OperandLifeTime::CONSTANT_COPY, - .location = {.poolIndex = 0, .offset = 0, .length = sizeof(int32_t)}, + .lifetime = TestOperandLifeTime::CONSTANT_COPY, + .data = TestBuffer::createFromVector({0}), }; - memset(operandValues.data(), 0, sizeof(int32_t)); // The buffer value of the constant second operand. The logical value is always 1.0f. CppType bufferValue; // The scale of the first and second operand. float scale1, scale2; - if (operandType == OperandType::TENSOR_FLOAT32) { + if (operandType == TestOperandType::TENSOR_FLOAT32) { bufferValue = 1.0f; scale1 = 0.0f; scale2 = 0.0f; - } else if (op == OperationType::ADD) { + } else if (op == TestOperationType::ADD) { bufferValue = 1; scale1 = 1.0f; scale2 = 1.0f; @@ -211,9 +172,9 @@ Model createLargeTestModelImpl(OperationType op, uint32_t len) { .numberOfConsumers = 1, .scale = scale1, .zeroPoint = 0, - .lifetime = (i == 0 ? OperandLifeTime::MODEL_INPUT - : OperandLifeTime::TEMPORARY_VARIABLE), - .location = {}, + .lifetime = (i == 0 ? TestOperandLifeTime::MODEL_INPUT + : TestOperandLifeTime::TEMPORARY_VARIABLE), + .data = (i == 0 ? TestBuffer::createFromVector({1}) : TestBuffer()), }; // The second operation input, value = 1. @@ -223,13 +184,9 @@ Model createLargeTestModelImpl(OperationType op, uint32_t len) { .numberOfConsumers = 1, .scale = scale2, .zeroPoint = 0, - .lifetime = OperandLifeTime::CONSTANT_COPY, - .location = {.poolIndex = 0, - .offset = static_cast(i * sizeof(CppType) + sizeof(int32_t)), - .length = sizeof(CppType)}, + .lifetime = TestOperandLifeTime::CONSTANT_COPY, + .data = TestBuffer::createFromVector({bufferValue}), }; - memcpy(operandValues.data() + sizeof(int32_t) + i * sizeof(CppType), &bufferValue, - sizeof(CppType)); // The operation. All operations share the same activation scalar. // The output operand is created as an input in the next iteration of the loop, in the case @@ -242,6 +199,10 @@ Model createLargeTestModelImpl(OperationType op, uint32_t len) { }; } + // For TestOperationType::ADD, output = 1 + 1 * len = len + 1 + // For TestOperationType::MUL, output = 1 * 1 ^ len = 1 + CppType outputResult = static_cast(op == TestOperationType::ADD ? len + 1u : 1u); + // The model output. operands.back() = { .type = operandType, @@ -249,21 +210,16 @@ Model createLargeTestModelImpl(OperationType op, uint32_t len) { .numberOfConsumers = 0, .scale = scale1, .zeroPoint = 0, - .lifetime = OperandLifeTime::MODEL_OUTPUT, - .location = {}, + .lifetime = TestOperandLifeTime::MODEL_OUTPUT, + .data = TestBuffer::createFromVector({outputResult}), }; - const std::vector inputIndexes = {1}; - const std::vector outputIndexes = {len * 2 + 1}; - const std::vector pools = {}; - return { - .operands = operands, - .operations = operations, - .inputIndexes = inputIndexes, - .outputIndexes = outputIndexes, - .operandValues = operandValues, - .pools = pools, + .operands = std::move(operands), + .operations = std::move(operations), + .inputIndexes = {1}, + .outputIndexes = {len * 2 + 1}, + .isRelaxed = false, }; } @@ -332,35 +288,21 @@ class CompilationCachingTestBase : public NeuralnetworksHidlTest { // Model and examples creators. According to kOperandType, the following methods will return // either float32 model/examples or the quant8 variant. - Model createTestModel() { + TestModel createTestModel() { if (kOperandType == OperandType::TENSOR_FLOAT32) { - return float32_model::createTestModel(); + return float32_model::get_test_model(); } else { - return quant8_model::createTestModel(); + return quant8_model::get_test_model(); } } - std::vector get_examples() { + TestModel createLargeTestModel(OperationType op, uint32_t len) { if (kOperandType == OperandType::TENSOR_FLOAT32) { - return float32_model::get_examples(); + return createLargeTestModelImpl( + static_cast(op), len); } else { - return quant8_model::get_examples(); - } - } - - Model createLargeTestModel(OperationType op, uint32_t len) { - if (kOperandType == OperandType::TENSOR_FLOAT32) { - return createLargeTestModelImpl(op, len); - } else { - return createLargeTestModelImpl(op, len); - } - } - - std::vector getLargeModelExamples(uint32_t len) { - if (kOperandType == OperandType::TENSOR_FLOAT32) { - return float32_model::getLargeModelExamples(len); - } else { - return quant8_model::getLargeModelExamples(len); + return createLargeTestModelImpl( + static_cast(op), len); } } @@ -482,8 +424,9 @@ class CompilationCachingTest : public CompilationCachingTestBase, TEST_P(CompilationCachingTest, CacheSavingAndRetrieval) { // Create test HIDL model and compile. - const Model testModel = createTestModel(); - if (checkEarlyTermination(testModel)) return; + const TestModel& testModel = createTestModel(); + const Model model = generated_tests::createModel(testModel); + if (checkEarlyTermination(model)) return; sp preparedModel = nullptr; // Save the compilation to cache. @@ -491,7 +434,7 @@ TEST_P(CompilationCachingTest, CacheSavingAndRetrieval) { hidl_vec modelCache, dataCache; createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); - saveModelToCache(testModel, modelCache, dataCache); + saveModelToCache(model, modelCache, dataCache); } // Retrieve preparedModel from cache. @@ -516,15 +459,15 @@ TEST_P(CompilationCachingTest, CacheSavingAndRetrieval) { } // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(), - testModel.relaxComputationFloat32toFloat16, + generated_tests::EvaluatePreparedModel(preparedModel, testModel, /*testDynamicOutputShape=*/false); } TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) { // Create test HIDL model and compile. - const Model testModel = createTestModel(); - if (checkEarlyTermination(testModel)) return; + const TestModel& testModel = createTestModel(); + const Model model = generated_tests::createModel(testModel); + if (checkEarlyTermination(model)) return; sp preparedModel = nullptr; // Save the compilation to cache. @@ -545,7 +488,7 @@ TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) { write(dataCache[i].getNativeHandle()->data[0], &dummyBytes, sizeof(dummyBytes)), sizeof(dummyBytes)); } - saveModelToCache(testModel, modelCache, dataCache); + saveModelToCache(model, modelCache, dataCache); } // Retrieve preparedModel from cache. @@ -579,15 +522,15 @@ TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) { } // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(), - testModel.relaxComputationFloat32toFloat16, + generated_tests::EvaluatePreparedModel(preparedModel, testModel, /*testDynamicOutputShape=*/false); } TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { // Create test HIDL model and compile. - const Model testModel = createTestModel(); - if (checkEarlyTermination(testModel)) return; + const TestModel& testModel = createTestModel(); + const Model model = generated_tests::createModel(testModel); + if (checkEarlyTermination(model)) return; // Test with number of model cache files greater than mNumModelCache. { @@ -598,12 +541,10 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); mModelCache.pop_back(); sp preparedModel = nullptr; - saveModelToCache(testModel, modelCache, dataCache, &preparedModel); + saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, - get_examples(), - testModel.relaxComputationFloat32toFloat16, + generated_tests::EvaluatePreparedModel(preparedModel, testModel, /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; @@ -625,12 +566,10 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); mModelCache.push_back(tmp); sp preparedModel = nullptr; - saveModelToCache(testModel, modelCache, dataCache, &preparedModel); + saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, - get_examples(), - testModel.relaxComputationFloat32toFloat16, + generated_tests::EvaluatePreparedModel(preparedModel, testModel, /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; @@ -651,12 +590,10 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); mDataCache.pop_back(); sp preparedModel = nullptr; - saveModelToCache(testModel, modelCache, dataCache, &preparedModel); + saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, - get_examples(), - testModel.relaxComputationFloat32toFloat16, + generated_tests::EvaluatePreparedModel(preparedModel, testModel, /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; @@ -678,12 +615,10 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); mDataCache.push_back(tmp); sp preparedModel = nullptr; - saveModelToCache(testModel, modelCache, dataCache, &preparedModel); + saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, - get_examples(), - testModel.relaxComputationFloat32toFloat16, + generated_tests::EvaluatePreparedModel(preparedModel, testModel, /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; @@ -698,15 +633,16 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumCache) { // Create test HIDL model and compile. - const Model testModel = createTestModel(); - if (checkEarlyTermination(testModel)) return; + const TestModel& testModel = createTestModel(); + const Model model = generated_tests::createModel(testModel); + if (checkEarlyTermination(model)) return; // Save the compilation to cache. { hidl_vec modelCache, dataCache; createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); - saveModelToCache(testModel, modelCache, dataCache); + saveModelToCache(model, modelCache, dataCache); } // Test with number of model cache files greater than mNumModelCache. @@ -778,8 +714,9 @@ TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumCache) { TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { // Create test HIDL model and compile. - const Model testModel = createTestModel(); - if (checkEarlyTermination(testModel)) return; + const TestModel& testModel = createTestModel(); + const Model model = generated_tests::createModel(testModel); + if (checkEarlyTermination(model)) return; // Go through each handle in model cache, test with NumFd greater than 1. for (uint32_t i = 0; i < mNumModelCache; i++) { @@ -790,12 +727,10 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); mModelCache[i].pop_back(); sp preparedModel = nullptr; - saveModelToCache(testModel, modelCache, dataCache, &preparedModel); + saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, - get_examples(), - testModel.relaxComputationFloat32toFloat16, + generated_tests::EvaluatePreparedModel(preparedModel, testModel, /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; @@ -817,12 +752,10 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); mModelCache[i].push_back(tmp); sp preparedModel = nullptr; - saveModelToCache(testModel, modelCache, dataCache, &preparedModel); + saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, - get_examples(), - testModel.relaxComputationFloat32toFloat16, + generated_tests::EvaluatePreparedModel(preparedModel, testModel, /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; @@ -843,12 +776,10 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); mDataCache[i].pop_back(); sp preparedModel = nullptr; - saveModelToCache(testModel, modelCache, dataCache, &preparedModel); + saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, - get_examples(), - testModel.relaxComputationFloat32toFloat16, + generated_tests::EvaluatePreparedModel(preparedModel, testModel, /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; @@ -870,12 +801,10 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); mDataCache[i].push_back(tmp); sp preparedModel = nullptr; - saveModelToCache(testModel, modelCache, dataCache, &preparedModel); + saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, - get_examples(), - testModel.relaxComputationFloat32toFloat16, + generated_tests::EvaluatePreparedModel(preparedModel, testModel, /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; @@ -890,15 +819,16 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumFd) { // Create test HIDL model and compile. - const Model testModel = createTestModel(); - if (checkEarlyTermination(testModel)) return; + const TestModel& testModel = createTestModel(); + const Model model = generated_tests::createModel(testModel); + if (checkEarlyTermination(model)) return; // Save the compilation to cache. { hidl_vec modelCache, dataCache; createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); - saveModelToCache(testModel, modelCache, dataCache); + saveModelToCache(model, modelCache, dataCache); } // Go through each handle in model cache, test with NumFd greater than 1. @@ -970,8 +900,9 @@ TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumFd) { TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) { // Create test HIDL model and compile. - const Model testModel = createTestModel(); - if (checkEarlyTermination(testModel)) return; + const TestModel& testModel = createTestModel(); + const Model model = generated_tests::createModel(testModel); + if (checkEarlyTermination(model)) return; std::vector modelCacheMode(mNumModelCache, AccessMode::READ_WRITE); std::vector dataCacheMode(mNumDataCache, AccessMode::READ_WRITE); @@ -983,12 +914,10 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) { createCacheHandles(mDataCache, dataCacheMode, &dataCache); modelCacheMode[i] = AccessMode::READ_WRITE; sp preparedModel = nullptr; - saveModelToCache(testModel, modelCache, dataCache, &preparedModel); + saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, - get_examples(), - testModel.relaxComputationFloat32toFloat16, + generated_tests::EvaluatePreparedModel(preparedModel, testModel, /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; @@ -1008,12 +937,10 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) { createCacheHandles(mDataCache, dataCacheMode, &dataCache); dataCacheMode[i] = AccessMode::READ_WRITE; sp preparedModel = nullptr; - saveModelToCache(testModel, modelCache, dataCache, &preparedModel); + saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, - get_examples(), - testModel.relaxComputationFloat32toFloat16, + generated_tests::EvaluatePreparedModel(preparedModel, testModel, /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; @@ -1028,8 +955,9 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) { TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidAccessMode) { // Create test HIDL model and compile. - const Model testModel = createTestModel(); - if (checkEarlyTermination(testModel)) return; + const TestModel& testModel = createTestModel(); + const Model model = generated_tests::createModel(testModel); + if (checkEarlyTermination(model)) return; std::vector modelCacheMode(mNumModelCache, AccessMode::READ_WRITE); std::vector dataCacheMode(mNumDataCache, AccessMode::READ_WRITE); @@ -1038,7 +966,7 @@ TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidAccessMode) { hidl_vec modelCache, dataCache; createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); - saveModelToCache(testModel, modelCache, dataCache); + saveModelToCache(model, modelCache, dataCache); } // Go through each handle in model cache, test with invalid access mode. @@ -1106,12 +1034,14 @@ TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) { if (!mIsCachingSupported) return; // Create test models and check if fully supported by the service. - const Model testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize); - if (checkEarlyTermination(testModelMul)) return; - const Model testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize); - if (checkEarlyTermination(testModelAdd)) return; + const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize); + const Model modelMul = generated_tests::createModel(testModelMul); + if (checkEarlyTermination(modelMul)) return; + const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize); + const Model modelAdd = generated_tests::createModel(testModelAdd); + if (checkEarlyTermination(modelAdd)) return; - // Save the testModelMul compilation to cache. + // Save the modelMul compilation to cache. auto modelCacheMul = mModelCache; for (auto& cache : modelCacheMul) { cache[0].append("_mul"); @@ -1120,15 +1050,15 @@ TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) { hidl_vec modelCache, dataCache; createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache); createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); - saveModelToCache(testModelMul, modelCache, dataCache); + saveModelToCache(modelMul, modelCache, dataCache); } - // Use a different token for testModelAdd. + // Use a different token for modelAdd. mToken[0]++; // This test is probabilistic, so we run it multiple times. for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) { - // Save the testModelAdd compilation to cache. + // Save the modelAdd compilation to cache. { hidl_vec modelCache, dataCache; createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); @@ -1136,7 +1066,7 @@ TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) { // Spawn a thread to copy the cache content concurrently while saving to cache. std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache)); - saveModelToCache(testModelAdd, modelCache, dataCache); + saveModelToCache(modelAdd, modelCache, dataCache); thread.join(); } @@ -1155,11 +1085,8 @@ TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) { ASSERT_EQ(preparedModel, nullptr); } else { ASSERT_NE(preparedModel, nullptr); - generated_tests::EvaluatePreparedModel( - preparedModel, [](int) { return false; }, - getLargeModelExamples(kLargeModelSize), - testModelAdd.relaxComputationFloat32toFloat16, - /*testDynamicOutputShape=*/false); + generated_tests::EvaluatePreparedModel(preparedModel, testModelAdd, + /*testDynamicOutputShape=*/false); } } } @@ -1169,12 +1096,14 @@ TEST_P(CompilationCachingTest, PrepareFromCache_TOCTOU) { if (!mIsCachingSupported) return; // Create test models and check if fully supported by the service. - const Model testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize); - if (checkEarlyTermination(testModelMul)) return; - const Model testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize); - if (checkEarlyTermination(testModelAdd)) return; + const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize); + const Model modelMul = generated_tests::createModel(testModelMul); + if (checkEarlyTermination(modelMul)) return; + const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize); + const Model modelAdd = generated_tests::createModel(testModelAdd); + if (checkEarlyTermination(modelAdd)) return; - // Save the testModelMul compilation to cache. + // Save the modelMul compilation to cache. auto modelCacheMul = mModelCache; for (auto& cache : modelCacheMul) { cache[0].append("_mul"); @@ -1183,20 +1112,20 @@ TEST_P(CompilationCachingTest, PrepareFromCache_TOCTOU) { hidl_vec modelCache, dataCache; createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache); createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); - saveModelToCache(testModelMul, modelCache, dataCache); + saveModelToCache(modelMul, modelCache, dataCache); } - // Use a different token for testModelAdd. + // Use a different token for modelAdd. mToken[0]++; // This test is probabilistic, so we run it multiple times. for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) { - // Save the testModelAdd compilation to cache. + // Save the modelAdd compilation to cache. { hidl_vec modelCache, dataCache; createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); - saveModelToCache(testModelAdd, modelCache, dataCache); + saveModelToCache(modelAdd, modelCache, dataCache); } // Retrieve preparedModel from cache. @@ -1218,11 +1147,8 @@ TEST_P(CompilationCachingTest, PrepareFromCache_TOCTOU) { ASSERT_EQ(preparedModel, nullptr); } else { ASSERT_NE(preparedModel, nullptr); - generated_tests::EvaluatePreparedModel( - preparedModel, [](int) { return false; }, - getLargeModelExamples(kLargeModelSize), - testModelAdd.relaxComputationFloat32toFloat16, - /*testDynamicOutputShape=*/false); + generated_tests::EvaluatePreparedModel(preparedModel, testModelAdd, + /*testDynamicOutputShape=*/false); } } } @@ -1232,12 +1158,14 @@ TEST_P(CompilationCachingTest, ReplaceSecuritySensitiveCache) { if (!mIsCachingSupported) return; // Create test models and check if fully supported by the service. - const Model testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize); - if (checkEarlyTermination(testModelMul)) return; - const Model testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize); - if (checkEarlyTermination(testModelAdd)) return; + const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize); + const Model modelMul = generated_tests::createModel(testModelMul); + if (checkEarlyTermination(modelMul)) return; + const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize); + const Model modelAdd = generated_tests::createModel(testModelAdd); + if (checkEarlyTermination(modelAdd)) return; - // Save the testModelMul compilation to cache. + // Save the modelMul compilation to cache. auto modelCacheMul = mModelCache; for (auto& cache : modelCacheMul) { cache[0].append("_mul"); @@ -1246,21 +1174,21 @@ TEST_P(CompilationCachingTest, ReplaceSecuritySensitiveCache) { hidl_vec modelCache, dataCache; createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache); createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); - saveModelToCache(testModelMul, modelCache, dataCache); + saveModelToCache(modelMul, modelCache, dataCache); } - // Use a different token for testModelAdd. + // Use a different token for modelAdd. mToken[0]++; - // Save the testModelAdd compilation to cache. + // Save the modelAdd compilation to cache. { hidl_vec modelCache, dataCache; createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); - saveModelToCache(testModelAdd, modelCache, dataCache); + saveModelToCache(modelAdd, modelCache, dataCache); } - // Replace the model cache of testModelAdd with testModelMul. + // Replace the model cache of modelAdd with modelMul. copyCacheFiles(modelCacheMul, mModelCache); // Retrieve the preparedModel from cache, expect failure. @@ -1336,15 +1264,16 @@ class CompilationCachingSecurityTest // The modifier accepts one pointer argument "skip" as the returning value, indicating // whether the test should be skipped or not. void testCorruptedCache(ExpectedResult expected, std::function modifier) { - const Model testModel = createTestModel(); - if (checkEarlyTermination(testModel)) return; + const TestModel& testModel = createTestModel(); + const Model model = generated_tests::createModel(testModel); + if (checkEarlyTermination(model)) return; // Save the compilation to cache. { hidl_vec modelCache, dataCache; createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); - saveModelToCache(testModel, modelCache, dataCache); + saveModelToCache(model, modelCache, dataCache); } bool skip = false; diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp index 82cc73db95..1dcebbe39c 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp @@ -31,7 +31,10 @@ #include #include +#include +#include #include +#include #include "1.0/Utils.h" #include "1.2/Callbacks.h" @@ -46,7 +49,10 @@ namespace neuralnetworks { namespace V1_2 { namespace generated_tests { +using namespace test_helper; +using ::android::hardware::neuralnetworks::V1_0::DataLocation; using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; +using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; using ::android::hardware::neuralnetworks::V1_0::Request; using ::android::hardware::neuralnetworks::V1_0::RequestArgument; using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference; @@ -60,29 +66,122 @@ using ::android::hardware::neuralnetworks::V1_2::Timing; using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; using ::android::hidl::memory::V1_0::IMemory; -using ::test_helper::compare; -using ::test_helper::expectMultinomialDistributionWithinTolerance; -using ::test_helper::filter; -using ::test_helper::for_all; -using ::test_helper::for_each; -using ::test_helper::MixedTyped; -using ::test_helper::MixedTypedExample; -using ::test_helper::resize_accordingly; using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; -static bool isZeroSized(const MixedTyped& example, uint32_t index) { - for (auto i : example.operandDimensions.at(index)) { - if (i == 0) return true; +enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; + +Model createModel(const TestModel& testModel) { + // Model operands. + hidl_vec operands(testModel.operands.size()); + size_t constCopySize = 0, constRefSize = 0; + for (uint32_t i = 0; i < testModel.operands.size(); i++) { + const auto& op = testModel.operands[i]; + + DataLocation loc = {}; + if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { + loc = {.poolIndex = 0, + .offset = static_cast(constCopySize), + .length = static_cast(op.data.size())}; + constCopySize += op.data.alignedSize(); + } else if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) { + loc = {.poolIndex = 0, + .offset = static_cast(constRefSize), + .length = static_cast(op.data.size())}; + constRefSize += op.data.alignedSize(); + } + + Operand::ExtraParams extraParams; + if (op.type == TestOperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) { + extraParams.channelQuant(SymmPerChannelQuantParams{ + .scales = op.channelQuant.scales, .channelDim = op.channelQuant.channelDim}); + } + + operands[i] = {.type = static_cast(op.type), + .dimensions = op.dimensions, + .numberOfConsumers = op.numberOfConsumers, + .scale = op.scale, + .zeroPoint = op.zeroPoint, + .lifetime = static_cast(op.lifetime), + .location = loc, + .extraParams = std::move(extraParams)}; } - return false; + + // Model operations. + hidl_vec operations(testModel.operations.size()); + std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(), + [](const TestOperation& op) -> Operation { + return {.type = static_cast(op.type), + .inputs = op.inputs, + .outputs = op.outputs}; + }); + + // Constant copies. + hidl_vec operandValues(constCopySize); + for (uint32_t i = 0; i < testModel.operands.size(); i++) { + const auto& op = testModel.operands[i]; + if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { + const uint8_t* begin = op.data.get(); + const uint8_t* end = begin + op.data.size(); + std::copy(begin, end, operandValues.data() + operands[i].location.offset); + } + } + + // Shared memory. + hidl_vec pools = {}; + if (constRefSize > 0) { + hidl_vec_push_back(&pools, nn::allocateSharedMemory(constRefSize)); + CHECK_NE(pools[0].size(), 0u); + + // load data + sp mappedMemory = mapMemory(pools[0]); + CHECK(mappedMemory.get() != nullptr); + uint8_t* mappedPtr = + reinterpret_cast(static_cast(mappedMemory->getPointer())); + CHECK(mappedPtr != nullptr); + + for (uint32_t i = 0; i < testModel.operands.size(); i++) { + const auto& op = testModel.operands[i]; + if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) { + const uint8_t* begin = op.data.get(); + const uint8_t* end = begin + op.data.size(); + std::copy(begin, end, mappedPtr + operands[i].location.offset); + } + } + } + + return {.operands = std::move(operands), + .operations = std::move(operations), + .inputIndexes = testModel.inputIndexes, + .outputIndexes = testModel.outputIndexes, + .operandValues = std::move(operandValues), + .pools = std::move(pools), + .relaxComputationFloat32toFloat16 = testModel.isRelaxed}; } -static Return ExecutePreparedModel(sp& preparedModel, +static bool isOutputSizeGreaterThanOne(const TestModel& testModel, uint32_t index) { + const auto byteSize = testModel.operands[testModel.outputIndexes[index]].data.size(); + return byteSize > 1u; +} + +static void makeOutputInsufficientSize(uint32_t outputIndex, Request* request) { + auto& length = request->outputs[outputIndex].location.length; + ASSERT_GT(length, 1u); + length -= 1u; +} + +static void makeOutputDimensionsUnspecified(Model* model) { + for (auto i : model->outputIndexes) { + auto& dims = model->operands[i].dimensions; + std::fill(dims.begin(), dims.end(), 0); + } +} + +static Return ExecutePreparedModel(const sp& preparedModel, const Request& request, MeasureTiming measure, sp& callback) { return preparedModel->execute_1_2(request, measure, callback); } -static Return ExecutePreparedModel(sp& preparedModel, +static Return ExecutePreparedModel(const sp& preparedModel, const Request& request, MeasureTiming measure, hidl_vec* outputShapes, Timing* timing) { @@ -105,294 +204,168 @@ static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst( return ::android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true); } enum class Executor { ASYNC, SYNC, BURST }; -enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; -const float kDefaultAtol = 1e-5f; -const float kDefaultRtol = 1e-5f; -void EvaluatePreparedModel(sp& preparedModel, std::function is_ignored, - const std::vector& examples, - bool hasRelaxedFloat32Model, float fpAtol, float fpRtol, + +void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel, Executor executor, MeasureTiming measure, OutputType outputType) { - const uint32_t INPUT = 0; - const uint32_t OUTPUT = 1; + // If output0 does not have size larger than one byte, we can not test with insufficient buffer. + if (outputType == OutputType::INSUFFICIENT && !isOutputSizeGreaterThanOne(testModel, 0)) { + return; + } - int example_no = 1; - for (auto& example : examples) { - SCOPED_TRACE(example_no++); - const MixedTyped& inputs = example.operands.first; - const MixedTyped& golden = example.operands.second; + Request request = createRequest(testModel); + if (outputType == OutputType::INSUFFICIENT) { + makeOutputInsufficientSize(/*outputIndex=*/0, &request); + } - const bool hasFloat16Inputs = !inputs.float16Operands.empty(); - if (hasRelaxedFloat32Model || hasFloat16Inputs) { - // TODO: Adjust the error limit based on testing. - // If in relaxed mode, set the absolute tolerance to be 5ULP of FP16. - fpAtol = 5.0f * 0.0009765625f; - // Set the relative tolerance to be 5ULP of the corresponding FP precision. - fpRtol = 5.0f * 0.0009765625f; + ErrorStatus executionStatus; + hidl_vec outputShapes; + Timing timing; + switch (executor) { + case Executor::ASYNC: { + SCOPED_TRACE("asynchronous"); + + // launch execution + sp executionCallback = new ExecutionCallback(); + Return executionLaunchStatus = + ExecutePreparedModel(preparedModel, request, measure, executionCallback); + ASSERT_TRUE(executionLaunchStatus.isOk()); + EXPECT_EQ(ErrorStatus::NONE, static_cast(executionLaunchStatus)); + + // retrieve execution status + executionCallback->wait(); + executionStatus = executionCallback->getStatus(); + outputShapes = executionCallback->getOutputShapes(); + timing = executionCallback->getTiming(); + + break; } + case Executor::SYNC: { + SCOPED_TRACE("synchronous"); - std::vector inputs_info, outputs_info; - uint32_t inputSize = 0, outputSize = 0; - // This function only partially specifies the metadata (vector of RequestArguments). - // The contents are copied over below. - for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) { - if (inputs_info.size() <= static_cast(index)) inputs_info.resize(index + 1); - RequestArgument arg = { - .location = {.poolIndex = INPUT, - .offset = 0, - .length = static_cast(s)}, - .dimensions = {}, - }; - RequestArgument arg_empty = { - .hasNoValue = true, - }; - inputs_info[index] = s ? arg : arg_empty; - inputSize += s; - }); - // Compute offset for inputs 1 and so on - { - size_t offset = 0; - for (auto& i : inputs_info) { - if (!i.hasNoValue) i.location.offset = offset; - offset += i.location.length; + // execute + Return executionReturnStatus = + ExecutePreparedModel(preparedModel, request, measure, &outputShapes, &timing); + ASSERT_TRUE(executionReturnStatus.isOk()); + executionStatus = static_cast(executionReturnStatus); + + break; + } + case Executor::BURST: { + SCOPED_TRACE("burst"); + + // create burst + const std::shared_ptr<::android::nn::ExecutionBurstController> controller = + CreateBurst(preparedModel); + ASSERT_NE(nullptr, controller.get()); + + // create memory keys + std::vector keys(request.pools.size()); + for (size_t i = 0; i < keys.size(); ++i) { + keys[i] = reinterpret_cast(&request.pools[i]); } - } - MixedTyped test; // holding test results + // execute burst + std::tie(executionStatus, outputShapes, timing) = + controller->compute(request, measure, keys); - // Go through all outputs, initialize RequestArgument descriptors - resize_accordingly(golden, test); - bool sizeLargerThanOne = true; - for_all(golden, [&golden, &outputs_info, &outputSize, &outputType, &sizeLargerThanOne]( - int index, auto, auto s) { - if (outputs_info.size() <= static_cast(index)) outputs_info.resize(index + 1); - if (index == 0) { - // On OutputType::INSUFFICIENT, set the output operand with index 0 with - // buffer size one byte less than needed. - if (outputType == OutputType::INSUFFICIENT) { - if (s > 1 && !isZeroSized(golden, index)) { - s -= 1; - } else { - sizeLargerThanOne = false; - } - } - } - RequestArgument arg = { - .location = {.poolIndex = OUTPUT, - .offset = 0, - .length = static_cast(s)}, - .dimensions = {}, - }; - outputs_info[index] = arg; - outputSize += s; - }); - // If output0 does not have size larger than one byte, - // we can not provide an insufficient buffer - if (!sizeLargerThanOne && outputType == OutputType::INSUFFICIENT) return; - // Compute offset for outputs 1 and so on - { - size_t offset = 0; - for (auto& i : outputs_info) { - i.location.offset = offset; - offset += i.location.length; - } - } - std::vector pools = {nn::allocateSharedMemory(inputSize), - nn::allocateSharedMemory(outputSize)}; - ASSERT_NE(0ull, pools[INPUT].size()); - ASSERT_NE(0ull, pools[OUTPUT].size()); - - // load data - sp inputMemory = mapMemory(pools[INPUT]); - sp outputMemory = mapMemory(pools[OUTPUT]); - ASSERT_NE(nullptr, inputMemory.get()); - ASSERT_NE(nullptr, outputMemory.get()); - char* inputPtr = reinterpret_cast(static_cast(inputMemory->getPointer())); - char* outputPtr = reinterpret_cast(static_cast(outputMemory->getPointer())); - ASSERT_NE(nullptr, inputPtr); - ASSERT_NE(nullptr, outputPtr); - inputMemory->update(); - outputMemory->update(); - - // Go through all inputs, copy the values - for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) { - char* begin = (char*)p; - char* end = begin + s; - // TODO: handle more than one input - std::copy(begin, end, inputPtr + inputs_info[index].location.offset); - }); - - inputMemory->commit(); - outputMemory->commit(); - - const Request request = {.inputs = inputs_info, .outputs = outputs_info, .pools = pools}; - - ErrorStatus executionStatus; - hidl_vec outputShapes; - Timing timing; - switch (executor) { - case Executor::ASYNC: { - SCOPED_TRACE("asynchronous"); - - // launch execution - sp executionCallback = new ExecutionCallback(); - ASSERT_NE(nullptr, executionCallback.get()); - Return executionLaunchStatus = - ExecutePreparedModel(preparedModel, request, measure, executionCallback); - ASSERT_TRUE(executionLaunchStatus.isOk()); - EXPECT_EQ(ErrorStatus::NONE, static_cast(executionLaunchStatus)); - - // retrieve execution status - executionCallback->wait(); - executionStatus = executionCallback->getStatus(); - outputShapes = executionCallback->getOutputShapes(); - timing = executionCallback->getTiming(); - - break; - } - case Executor::SYNC: { - SCOPED_TRACE("synchronous"); - - // execute - Return executionReturnStatus = ExecutePreparedModel( - preparedModel, request, measure, &outputShapes, &timing); - ASSERT_TRUE(executionReturnStatus.isOk()); - executionStatus = static_cast(executionReturnStatus); - - break; - } - case Executor::BURST: { - SCOPED_TRACE("burst"); - - // create burst - const std::shared_ptr<::android::nn::ExecutionBurstController> controller = - CreateBurst(preparedModel); - ASSERT_NE(nullptr, controller.get()); - - // create memory keys - std::vector keys(request.pools.size()); - for (size_t i = 0; i < keys.size(); ++i) { - keys[i] = reinterpret_cast(&request.pools[i]); - } - - // execute burst - std::tie(executionStatus, outputShapes, timing) = - controller->compute(request, measure, keys); - - break; - } - } - - if (outputType != OutputType::FULLY_SPECIFIED && - executionStatus == ErrorStatus::GENERAL_FAILURE) { - LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " - "execute model that it does not support."; - std::cout << "[ ] Early termination of test because vendor service cannot " - "execute model that it does not support." - << std::endl; - GTEST_SKIP(); - } - if (measure == MeasureTiming::NO) { - EXPECT_EQ(UINT64_MAX, timing.timeOnDevice); - EXPECT_EQ(UINT64_MAX, timing.timeInDriver); - } else { - if (timing.timeOnDevice != UINT64_MAX && timing.timeInDriver != UINT64_MAX) { - EXPECT_LE(timing.timeOnDevice, timing.timeInDriver); - } - } - - switch (outputType) { - case OutputType::FULLY_SPECIFIED: - // If the model output operands are fully specified, outputShapes must be either - // either empty, or have the same number of elements as the number of outputs. - ASSERT_EQ(ErrorStatus::NONE, executionStatus); - ASSERT_TRUE(outputShapes.size() == 0 || - outputShapes.size() == test.operandDimensions.size()); - break; - case OutputType::UNSPECIFIED: - // If the model output operands are not fully specified, outputShapes must have - // the same number of elements as the number of outputs. - ASSERT_EQ(ErrorStatus::NONE, executionStatus); - ASSERT_EQ(outputShapes.size(), test.operandDimensions.size()); - break; - case OutputType::INSUFFICIENT: - ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus); - ASSERT_EQ(outputShapes.size(), test.operandDimensions.size()); - ASSERT_FALSE(outputShapes[0].isSufficient); - return; - } - // Go through all outputs, overwrite output dimensions with returned output shapes - if (outputShapes.size() > 0) { - for_each(test.operandDimensions, - [&outputShapes](int idx, std::vector& dim) { - dim = outputShapes[idx].dimensions; - }); - } - - // validate results - outputMemory->read(); - copy_back(&test, outputs_info, outputPtr); - outputMemory->commit(); - // Filter out don't cares - MixedTyped filtered_golden = filter(golden, is_ignored); - MixedTyped filtered_test = filter(test, is_ignored); - - // We want "close-enough" results for float - compare(filtered_golden, filtered_test, fpAtol, fpRtol); - - if (example.expectedMultinomialDistributionTolerance > 0) { - expectMultinomialDistributionWithinTolerance(test, example); + break; } } -} -void EvaluatePreparedModel(sp& preparedModel, std::function is_ignored, - const std::vector& examples, - bool hasRelaxedFloat32Model, Executor executor, MeasureTiming measure, - OutputType outputType) { - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, kDefaultAtol, - kDefaultRtol, executor, measure, outputType); + + if (outputType != OutputType::FULLY_SPECIFIED && + executionStatus == ErrorStatus::GENERAL_FAILURE) { + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " + "execute model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "execute model that it does not support." + << std::endl; + GTEST_SKIP(); + } + if (measure == MeasureTiming::NO) { + EXPECT_EQ(UINT64_MAX, timing.timeOnDevice); + EXPECT_EQ(UINT64_MAX, timing.timeInDriver); + } else { + if (timing.timeOnDevice != UINT64_MAX && timing.timeInDriver != UINT64_MAX) { + EXPECT_LE(timing.timeOnDevice, timing.timeInDriver); + } + } + + switch (outputType) { + case OutputType::FULLY_SPECIFIED: + // If the model output operands are fully specified, outputShapes must be either + // either empty, or have the same number of elements as the number of outputs. + ASSERT_EQ(ErrorStatus::NONE, executionStatus); + ASSERT_TRUE(outputShapes.size() == 0 || + outputShapes.size() == testModel.outputIndexes.size()); + break; + case OutputType::UNSPECIFIED: + // If the model output operands are not fully specified, outputShapes must have + // the same number of elements as the number of outputs. + ASSERT_EQ(ErrorStatus::NONE, executionStatus); + ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size()); + break; + case OutputType::INSUFFICIENT: + ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus); + ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size()); + ASSERT_FALSE(outputShapes[0].isSufficient); + return; + } + + // Go through all outputs, check returned output shapes. + for (uint32_t i = 0; i < outputShapes.size(); i++) { + EXPECT_TRUE(outputShapes[i].isSufficient); + const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions; + const std::vector actual = outputShapes[i].dimensions; + EXPECT_EQ(expect, actual); + } + + // Retrieve execution results. + const std::vector outputs = getOutputBuffers(request); + + // We want "close-enough" results. + checkResults(testModel, outputs); } -void EvaluatePreparedModel(sp& preparedModel, std::function is_ignored, - const std::vector& examples, - bool hasRelaxedFloat32Model, bool testDynamicOutputShape) { +void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel, + bool testDynamicOutputShape) { if (testDynamicOutputShape) { - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::ASYNC, MeasureTiming::NO, OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::SYNC, MeasureTiming::NO, OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::BURST, MeasureTiming::NO, OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::ASYNC, MeasureTiming::YES, OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::SYNC, MeasureTiming::YES, OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::BURST, MeasureTiming::YES, OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::ASYNC, MeasureTiming::NO, OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::SYNC, MeasureTiming::NO, OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::BURST, MeasureTiming::NO, OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::ASYNC, MeasureTiming::YES, OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::SYNC, MeasureTiming::YES, OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::BURST, MeasureTiming::YES, OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO, + OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO, + OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO, + OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES, + OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES, + OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES, + OutputType::INSUFFICIENT); } else { - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::ASYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::SYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::BURST, MeasureTiming::NO, OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::ASYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::SYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, - Executor::BURST, MeasureTiming::YES, OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO, + OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO, + OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO, + OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES, + OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES, + OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES, + OutputType::FULLY_SPECIFIED); } } @@ -411,7 +384,6 @@ void PrepareModel(const sp& device, const Model& model, // launch prepare model sp preparedModelCallback = new PreparedModelCallback(); - ASSERT_NE(nullptr, preparedModelCallback.get()); Return prepareLaunchStatus = device->prepareModel_1_2( model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec(), hidl_vec(), HidlToken(), preparedModelCallback); @@ -438,17 +410,18 @@ void PrepareModel(const sp& device, const Model& model, ASSERT_NE(nullptr, preparedModel->get()); } -void Execute(const sp& device, std::function create_model, - std::function is_ignored, const std::vector& examples, - bool testDynamicOutputShape) { - Model model = create_model(); +void Execute(const sp& device, const TestModel& testModel, bool testDynamicOutputShape) { + Model model = createModel(testModel); + if (testDynamicOutputShape) { + makeOutputDimensionsUnspecified(&model); + } + sp preparedModel = nullptr; PrepareModel(device, model, &preparedModel); if (preparedModel == nullptr) { GTEST_SKIP(); } - EvaluatePreparedModel(preparedModel, is_ignored, examples, - model.relaxComputationFloat32toFloat16, testDynamicOutputShape); + EvaluatePreparedModel(preparedModel, testModel, testDynamicOutputShape); } } // namespace generated_tests diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h index 0ecbe7e76a..de45242ac7 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h @@ -30,18 +30,15 @@ namespace neuralnetworks { namespace V1_2 { namespace generated_tests { -using ::test_helper::MixedTypedExample; +Model createModel(const ::test_helper::TestModel& testModel); void PrepareModel(const sp& device, const V1_2::Model& model, sp* preparedModel); -void EvaluatePreparedModel(sp& preparedModel, - std::function is_ignored, - const std::vector& examples, - bool hasRelaxedFloat32Model, bool testDynamicOutputShape); +void EvaluatePreparedModel(const sp& preparedModel, + const ::test_helper::TestModel& testModel, bool testDynamicOutputShape); -void Execute(const sp& device, std::function create_model, - std::function is_ignored, const std::vector& examples, +void Execute(const sp& device, const ::test_helper::TestModel& testModel, bool testDynamicOutputShape = false); } // namespace generated_tests diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTests.h b/neuralnetworks/1.2/vts/functional/GeneratedTests.h index 98420364b2..a72360941e 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTests.h +++ b/neuralnetworks/1.2/vts/functional/GeneratedTests.h @@ -14,21 +14,11 @@ * limitations under the License. */ -#include -#include - +#include "1.0/Utils.h" #include "GeneratedTestHarness.h" -#include "MemoryUtils.h" #include "TestHarness.h" -#include "Utils.h" #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_2::vts::functional { - -std::vector createRequests(const std::vector<::test_helper::MixedTypedExample>& examples); - -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional - namespace android::hardware::neuralnetworks::V1_2::generated_tests { using namespace ::android::hardware::neuralnetworks::V1_2::vts::functional; diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp index 4d6bdbb7e6..c4c92804d9 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp @@ -239,7 +239,7 @@ static void mutateDatumTest(RequestChannelSender* sender, ResultChannelReceiver* ///////////////////////// BURST VALIATION TESTS //////////////////////////////////// static void validateBurstSerialization(const sp& preparedModel, - const std::vector& requests) { + const Request& request) { // create burst std::unique_ptr sender; std::unique_ptr receiver; @@ -250,35 +250,32 @@ static void validateBurstSerialization(const sp& preparedModel, ASSERT_NE(nullptr, receiver.get()); ASSERT_NE(nullptr, context.get()); - // validate each request - for (const Request& request : requests) { - // load memory into callback slots - std::vector keys; - keys.reserve(request.pools.size()); - std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys), - [](const auto& pool) { return reinterpret_cast(&pool); }); - const std::vector slots = callback->getSlots(request.pools, keys); + // load memory into callback slots + std::vector keys; + keys.reserve(request.pools.size()); + std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys), + [](const auto& pool) { return reinterpret_cast(&pool); }); + const std::vector slots = callback->getSlots(request.pools, keys); - // ensure slot std::numeric_limits::max() doesn't exist (for - // subsequent slot validation testing) - ASSERT_TRUE(std::all_of(slots.begin(), slots.end(), [](int32_t slot) { - return slot != std::numeric_limits::max(); - })); + // ensure slot std::numeric_limits::max() doesn't exist (for + // subsequent slot validation testing) + ASSERT_TRUE(std::all_of(slots.begin(), slots.end(), [](int32_t slot) { + return slot != std::numeric_limits::max(); + })); - // serialize the request - const auto serialized = ::android::nn::serialize(request, MeasureTiming::YES, slots); + // serialize the request + const auto serialized = ::android::nn::serialize(request, MeasureTiming::YES, slots); - // validations - removeDatumTest(sender.get(), receiver.get(), serialized); - addDatumTest(sender.get(), receiver.get(), serialized); - mutateDatumTest(sender.get(), receiver.get(), serialized); - } + // validations + removeDatumTest(sender.get(), receiver.get(), serialized); + addDatumTest(sender.get(), receiver.get(), serialized); + mutateDatumTest(sender.get(), receiver.get(), serialized); } // This test validates that when the Result message size exceeds length of the // result FMQ, the service instance gracefully fails and returns an error. static void validateBurstFmqLength(const sp& preparedModel, - const std::vector& requests) { + const Request& request) { // create regular burst std::shared_ptr controllerRegular; ASSERT_NO_FATAL_FAILURE(createBurstWithResultChannelLength( @@ -291,35 +288,32 @@ static void validateBurstFmqLength(const sp& preparedModel, preparedModel, kExecutionBurstChannelSmallLength, &controllerSmall)); ASSERT_NE(nullptr, controllerSmall.get()); - // validate each request - for (const Request& request : requests) { - // load memory into callback slots - std::vector keys(request.pools.size()); - for (size_t i = 0; i < keys.size(); ++i) { - keys[i] = reinterpret_cast(&request.pools[i]); - } - - // collect serialized result by running regular burst - const auto [statusRegular, outputShapesRegular, timingRegular] = - controllerRegular->compute(request, MeasureTiming::NO, keys); - - // skip test if regular burst output isn't useful for testing a failure - // caused by having too small of a length for the result FMQ - const std::vector serialized = - ::android::nn::serialize(statusRegular, outputShapesRegular, timingRegular); - if (statusRegular != ErrorStatus::NONE || - serialized.size() <= kExecutionBurstChannelSmallLength) { - continue; - } - - // by this point, execution should fail because the result channel isn't - // large enough to return the serialized result - const auto [statusSmall, outputShapesSmall, timingSmall] = - controllerSmall->compute(request, MeasureTiming::NO, keys); - EXPECT_NE(ErrorStatus::NONE, statusSmall); - EXPECT_EQ(0u, outputShapesSmall.size()); - EXPECT_TRUE(badTiming(timingSmall)); + // load memory into callback slots + std::vector keys(request.pools.size()); + for (size_t i = 0; i < keys.size(); ++i) { + keys[i] = reinterpret_cast(&request.pools[i]); } + + // collect serialized result by running regular burst + const auto [statusRegular, outputShapesRegular, timingRegular] = + controllerRegular->compute(request, MeasureTiming::NO, keys); + + // skip test if regular burst output isn't useful for testing a failure + // caused by having too small of a length for the result FMQ + const std::vector serialized = + ::android::nn::serialize(statusRegular, outputShapesRegular, timingRegular); + if (statusRegular != ErrorStatus::NONE || + serialized.size() <= kExecutionBurstChannelSmallLength) { + return; + } + + // by this point, execution should fail because the result channel isn't + // large enough to return the serialized result + const auto [statusSmall, outputShapesSmall, timingSmall] = + controllerSmall->compute(request, MeasureTiming::NO, keys); + EXPECT_NE(ErrorStatus::NONE, statusSmall); + EXPECT_EQ(0u, outputShapesSmall.size()); + EXPECT_TRUE(badTiming(timingSmall)); } static bool isSanitized(const FmqResultDatum& datum) { @@ -403,9 +397,9 @@ static void validateBurstSanitized(const sp& preparedModel, ///////////////////////////// ENTRY POINT ////////////////////////////////// void ValidationTest::validateBurst(const sp& preparedModel, - const std::vector& requests) { - ASSERT_NO_FATAL_FAILURE(validateBurstSerialization(preparedModel, requests)); - ASSERT_NO_FATAL_FAILURE(validateBurstFmqLength(preparedModel, requests)); + const Request& request) { + ASSERT_NO_FATAL_FAILURE(validateBurstSerialization(preparedModel, request)); + ASSERT_NO_FATAL_FAILURE(validateBurstFmqLength(preparedModel, request)); ASSERT_NO_FATAL_FAILURE(validateBurstSanitized(preparedModel, requests)); } diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp index cf5905f688..13d45e4a1a 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp @@ -16,14 +16,9 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" -#include -#include -#include - #include "1.0/Utils.h" #include "1.2/Callbacks.h" #include "ExecutionBurstController.h" -#include "MemoryUtils.h" #include "TestHarness.h" #include "Utils.h" #include "VtsHalNeuralnetworks.h" @@ -35,12 +30,7 @@ namespace V1_2 { namespace vts { namespace functional { -using ::android::hardware::neuralnetworks::V1_0::RequestArgument; using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; -using ::android::hidl::memory::V1_0::IMemory; -using test_helper::for_all; -using test_helper::MixedTyped; -using test_helper::MixedTypedExample; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// @@ -161,119 +151,23 @@ static void removeOutputTest(const sp& preparedModel, const Requ ///////////////////////////// ENTRY POINT ////////////////////////////////// -std::vector createRequests(const std::vector& examples) { - const uint32_t INPUT = 0; - const uint32_t OUTPUT = 1; - - std::vector requests; - - for (auto& example : examples) { - const MixedTyped& inputs = example.operands.first; - const MixedTyped& outputs = example.operands.second; - - std::vector inputs_info, outputs_info; - uint32_t inputSize = 0, outputSize = 0; - - // This function only partially specifies the metadata (vector of RequestArguments). - // The contents are copied over below. - for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) { - if (inputs_info.size() <= static_cast(index)) inputs_info.resize(index + 1); - RequestArgument arg = { - .location = {.poolIndex = INPUT, - .offset = 0, - .length = static_cast(s)}, - .dimensions = {}, - }; - RequestArgument arg_empty = { - .hasNoValue = true, - }; - inputs_info[index] = s ? arg : arg_empty; - inputSize += s; - }); - // Compute offset for inputs 1 and so on - { - size_t offset = 0; - for (auto& i : inputs_info) { - if (!i.hasNoValue) i.location.offset = offset; - offset += i.location.length; - } - } - - // Go through all outputs, initialize RequestArgument descriptors - for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) { - if (outputs_info.size() <= static_cast(index)) outputs_info.resize(index + 1); - RequestArgument arg = { - .location = {.poolIndex = OUTPUT, - .offset = 0, - .length = static_cast(s)}, - .dimensions = {}, - }; - outputs_info[index] = arg; - outputSize += s; - }); - // Compute offset for outputs 1 and so on - { - size_t offset = 0; - for (auto& i : outputs_info) { - i.location.offset = offset; - offset += i.location.length; - } - } - std::vector pools = {nn::allocateSharedMemory(inputSize), - nn::allocateSharedMemory(outputSize)}; - if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) { - return {}; - } - - // map pool - sp inputMemory = mapMemory(pools[INPUT]); - if (inputMemory == nullptr) { - return {}; - } - char* inputPtr = reinterpret_cast(static_cast(inputMemory->getPointer())); - if (inputPtr == nullptr) { - return {}; - } - - // initialize pool - inputMemory->update(); - for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) { - char* begin = (char*)p; - char* end = begin + s; - // TODO: handle more than one input - std::copy(begin, end, inputPtr + inputs_info[index].location.offset); - }); - inputMemory->commit(); - - requests.push_back({.inputs = inputs_info, .outputs = outputs_info, .pools = pools}); - } - - return requests; -} - -void ValidationTest::validateRequests(const sp& preparedModel, - const std::vector& requests) { - // validate each request - for (const Request& request : requests) { - removeInputTest(preparedModel, request); - removeOutputTest(preparedModel, request); - } +void ValidationTest::validateRequest(const sp& preparedModel, + const Request& request) { + removeInputTest(preparedModel, request); + removeOutputTest(preparedModel, request); } void ValidationTest::validateRequestFailure(const sp& preparedModel, - const std::vector& requests) { - for (const Request& request : requests) { - SCOPED_TRACE("Expecting request to fail [executeSynchronously]"); - Return executeStatus = preparedModel->executeSynchronously( - request, MeasureTiming::NO, - [](ErrorStatus error, const hidl_vec& outputShapes, - const Timing& timing) { - ASSERT_NE(ErrorStatus::NONE, error); - EXPECT_EQ(outputShapes.size(), 0); - EXPECT_TRUE(badTiming(timing)); - }); - ASSERT_TRUE(executeStatus.isOk()); - } + const Request& request) { + SCOPED_TRACE("Expecting request to fail [executeSynchronously]"); + Return executeStatus = preparedModel->executeSynchronously( + request, MeasureTiming::NO, + [](ErrorStatus error, const hidl_vec& outputShapes, const Timing& timing) { + ASSERT_NE(ErrorStatus::NONE, error); + EXPECT_EQ(outputShapes.size(), 0); + EXPECT_TRUE(badTiming(timing)); + }); + ASSERT_TRUE(executeStatus.isOk()); } } // namespace functional diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp index bd24edc249..eb52110548 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp @@ -126,7 +126,7 @@ void NeuralnetworksHidlTest::TearDown() { ::testing::VtsHalHidlTargetTestBase::TearDown(); } -void ValidationTest::validateEverything(const Model& model, const std::vector& requests) { +void ValidationTest::validateEverything(const Model& model, const Request& request) { validateModel(model); // create IPreparedModel @@ -136,11 +136,11 @@ void ValidationTest::validateEverything(const Model& model, const std::vector& requests) { +void ValidationTest::validateFailure(const Model& model, const Request& request) { // TODO: Should this always succeed? // What if the invalid input is part of the model (i.e., a parameter). validateModel(model); @@ -151,7 +151,7 @@ void ValidationTest::validateFailure(const Model& model, const std::vector getPreparedModel_1_2( diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h index 90dfe25312..e76ad7bc64 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h @@ -68,20 +68,16 @@ class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase { sp device; }; -// Tag for the validation tests class ValidationTest : public NeuralnetworksHidlTest { protected: - void validateEverything(const Model& model, const std::vector& requests); - void validateFailure(const Model& model, const std::vector& requests); + void validateEverything(const Model& model, const Request& request); + void validateFailure(const Model& model, const Request& request); private: void validateModel(const Model& model); - void validateRequests(const sp& preparedModel, - const std::vector& requests); - void validateRequestFailure(const sp& preparedModel, - const std::vector& requests); - void validateBurst(const sp& preparedModel, - const std::vector& requests); + void validateRequest(const sp& preparedModel, const Request& request); + void validateRequestFailure(const sp& preparedModel, const Request& request); + void validateBurst(const sp& preparedModel, const Request& request); }; // Tag for the generated tests From 8fc4622bf128ceef28f2bc2465fd9faac689693d Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Mon, 19 Aug 2019 10:37:18 -0700 Subject: [PATCH 0082/1022] Modify validateBurstSanitized to take a single request. This CL is to modify validateBurstSanitized implementation in accordance with the new test generator and test harness change in the same topic. Bug: 123092187 Test: 1.2 VTS Change-Id: Iacfe0e3bba8b4b44b7aee023d1c8129cbd089d4a --- .../1.2/vts/functional/ValidateBurst.cpp | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp index c4c92804d9..94603fbcfd 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp @@ -361,7 +361,7 @@ static bool isSanitized(const FmqResultDatum& datum) { } static void validateBurstSanitized(const sp& preparedModel, - const std::vector& requests) { + const Request& request) { // create burst std::unique_ptr sender; std::unique_ptr receiver; @@ -372,26 +372,23 @@ static void validateBurstSanitized(const sp& preparedModel, ASSERT_NE(nullptr, receiver.get()); ASSERT_NE(nullptr, context.get()); - // validate each request - for (const Request& request : requests) { - // load memory into callback slots - std::vector keys; - keys.reserve(request.pools.size()); - std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys), - [](const auto& pool) { return reinterpret_cast(&pool); }); - const std::vector slots = callback->getSlots(request.pools, keys); + // load memory into callback slots + std::vector keys; + keys.reserve(request.pools.size()); + std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys), + [](const auto& pool) { return reinterpret_cast(&pool); }); + const std::vector slots = callback->getSlots(request.pools, keys); - // send valid request - ASSERT_TRUE(sender->send(request, MeasureTiming::YES, slots)); + // send valid request + ASSERT_TRUE(sender->send(request, MeasureTiming::YES, slots)); - // receive valid result - auto serialized = receiver->getPacketBlocking(); - ASSERT_TRUE(serialized.has_value()); + // receive valid result + auto serialized = receiver->getPacketBlocking(); + ASSERT_TRUE(serialized.has_value()); - // sanitize result - ASSERT_TRUE(std::all_of(serialized->begin(), serialized->end(), isSanitized)) - << "The result serialized data is not properly sanitized"; - } + // sanitize result + ASSERT_TRUE(std::all_of(serialized->begin(), serialized->end(), isSanitized)) + << "The result serialized data is not properly sanitized"; } ///////////////////////////// ENTRY POINT ////////////////////////////////// @@ -400,7 +397,7 @@ void ValidationTest::validateBurst(const sp& preparedModel, const Request& request) { ASSERT_NO_FATAL_FAILURE(validateBurstSerialization(preparedModel, request)); ASSERT_NO_FATAL_FAILURE(validateBurstFmqLength(preparedModel, request)); - ASSERT_NO_FATAL_FAILURE(validateBurstSanitized(preparedModel, requests)); + ASSERT_NO_FATAL_FAILURE(validateBurstSanitized(preparedModel, request)); } } // namespace functional From f3eec03f4272313e668d466abe43b2511875f253 Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Thu, 15 Aug 2019 18:57:08 -0700 Subject: [PATCH 0083/1022] Add Demux and Descrambler interface to Tuner HAL Test: Manual bug: 135709729 Change-Id: I78283acdd7c22a2d4a785fa050bedd5e7ccc593e --- tv/tuner/1.0/Android.bp | 3 ++ tv/tuner/1.0/IDemux.hal | 37 ++++++++++++++++++++++++ tv/tuner/1.0/IDemuxCallback.hal | 11 ++++++++ tv/tuner/1.0/IDescrambler.hal | 35 +++++++++++++++++++++++ tv/tuner/1.0/ITuner.hal | 29 ++++++++++++++++++- tv/tuner/1.0/default/Tuner.cpp | 21 ++++++++++++++ tv/tuner/1.0/default/Tuner.h | 4 +++ tv/tuner/1.0/types.hal | 50 +++++++++++++++++++++++++++++++++ 8 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 tv/tuner/1.0/IDemux.hal create mode 100644 tv/tuner/1.0/IDemuxCallback.hal create mode 100644 tv/tuner/1.0/IDescrambler.hal diff --git a/tv/tuner/1.0/Android.bp b/tv/tuner/1.0/Android.bp index b54413de6a..986518b327 100644 --- a/tv/tuner/1.0/Android.bp +++ b/tv/tuner/1.0/Android.bp @@ -8,6 +8,9 @@ hidl_interface { }, srcs: [ "types.hal", + "IDemux.hal", + "IDemuxCallback.hal", + "IDescrambler.hal", "IFrontend.hal", "IFrontendCallback.hal", "ITuner.hal", diff --git a/tv/tuner/1.0/IDemux.hal b/tv/tuner/1.0/IDemux.hal new file mode 100644 index 0000000000..938bc4456e --- /dev/null +++ b/tv/tuner/1.0/IDemux.hal @@ -0,0 +1,37 @@ +package android.hardware.tv.tuner@1.0; + +import IDemuxCallback; + +/** + * Demultiplexer(Demux) takes a single multiplexed input and splits it into + * one or more output. + * + */ +interface IDemux { + + /** + * Set a frontend resource as data input of the demux + * + * It is used by the client to specify a hardware frontend as data source of + * this demux instance. A demux instance can have only one data source. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + setFrontendDataSource(FrontendId frontendId) generates (Result result); + + /** + * Close the Demux instance + * + * It is used by the client to release the demux instance. HAL clear + * underneath resource. client mustn't access the instance any more. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + */ + close() generates (Result result); +}; + diff --git a/tv/tuner/1.0/IDemuxCallback.hal b/tv/tuner/1.0/IDemuxCallback.hal new file mode 100644 index 0000000000..c67c5f2aa6 --- /dev/null +++ b/tv/tuner/1.0/IDemuxCallback.hal @@ -0,0 +1,11 @@ +package android.hardware.tv.tuner@1.0; + +interface IDemuxCallback { + /** + * Notify the client that a new filter event happened. + * + * @param filterEvent a demux filter event. + */ + oneway onFilterEvent(DemuxFilterEvent filterEvent); +}; + diff --git a/tv/tuner/1.0/IDescrambler.hal b/tv/tuner/1.0/IDescrambler.hal new file mode 100644 index 0000000000..4d6cf3c7a1 --- /dev/null +++ b/tv/tuner/1.0/IDescrambler.hal @@ -0,0 +1,35 @@ +package android.hardware.tv.tuner@1.0; + +/** + * Descrambler is used to descramble input data. + * + */ +interface IDescrambler { + + /** + * Set a demux as source of the descrambler + * + * It is used by the client to specify a demux as source of this + * descrambler. A descrambler instance can have only one source, and + * this method can be only called once. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + setDemuxSource(DemuxId demuxId) generates (Result result); + + /** + * Release the descrambler instance + * + * It is used by the client to release the descrambler instance. HAL clear + * underneath resource. client mustn't access the instance any more. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + */ + close() generates (Result result); +}; + diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal index 5a5f547a75..61a9d63205 100644 --- a/tv/tuner/1.0/ITuner.hal +++ b/tv/tuner/1.0/ITuner.hal @@ -16,6 +16,8 @@ package android.hardware.tv.tuner@1.0; +import IDemux; +import IDescrambler; import IFrontend; /** @@ -48,5 +50,30 @@ interface ITuner { openFrontendById(FrontendId frontendId) generates (Result result, IFrontend frontend); -}; + /** + * Create a new instance of Demux. + * + * It is used by the client to create a Demux instance. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if creation failed for other reasons. + * @return demuxId newly created demux id. + * @return demux the newly created demux interface. + */ + openDemux() + generates (Result result, DemuxId demuxId, IDemux demux); + /** + * Create a new instance of Descrambler. + * + * It is used by the client to create a Descrambler instance. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if creation failed for other reasons. + * @return descrambler the newly created descrambler interface. + */ + openDescrambler() + generates (Result result, IDescrambler descrambler); +}; diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp index 67ec754579..6bb7aa9af8 100644 --- a/tv/tuner/1.0/default/Tuner.cpp +++ b/tv/tuner/1.0/default/Tuner.cpp @@ -28,6 +28,8 @@ namespace tuner { namespace V1_0 { namespace implementation { +using ::android::hardware::tv::tuner::V1_0::DemuxId; + Tuner::Tuner() { // Static Frontends array to maintain local frontends information // Array index matches their FrontendId in the default impl @@ -71,6 +73,25 @@ Return Tuner::openFrontendById(uint32_t frontendId, openFrontendById_cb _h return Void(); } +Return Tuner::openDemux(openDemux_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + sp demux; + DemuxId demuxId = 0; + + _hidl_cb(Result::SUCCESS, demuxId, demux); + return Void(); +} + +Return Tuner::openDescrambler(openDescrambler_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + sp descrambler; + + _hidl_cb(Result::SUCCESS, descrambler); + return Void(); +} + } // namespace implementation } // namespace V1_0 } // namespace tuner diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h index 2152c899c8..1ca7671f1f 100644 --- a/tv/tuner/1.0/default/Tuner.h +++ b/tv/tuner/1.0/default/Tuner.h @@ -37,6 +37,10 @@ class Tuner : public ITuner { virtual Return openFrontendById(uint32_t frontendId, openFrontendById_cb _hidl_cb) override; + virtual Return openDemux(openDemux_cb _hidl_cb) override; + + virtual Return openDescrambler(openDescrambler_cb _hidl_cb) override; + private: virtual ~Tuner(); // Static mFrontends array to maintain local frontends information diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index 1ca7fda4b7..3fa9641169 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -137,3 +137,53 @@ enum FrontendEventType : uint32_t { */ LOST_LOCK, }; + +/* Demux ID is used to associate with a hardware demux resource. */ +typedef uint32_t DemuxId; + +/* Filter ID is used to associate with a hardware filter resource. */ +typedef uint32_t DemuxFilterId; + +/** + * Filter Type according to ISO/IEC 13818-1 + */ +@export +enum DemuxFilterType : uint32_t { + /** + * A filter to filter section data out from input stream. + */ + SECTION, + /** + * A filter to filter PES data out from input stream. + */ + PES, + /** + * A filter to filter TS payload out from input stream. + */ + TS, + /** + * A filter to filter Audio Metadata out from input stream. + */ + AUDIO, + /** + * A filter to filter Vidoe Metadata out from input stream. + */ + VIDEO, + /** + * A filter to set PCR channel from input stream. + */ + PCR, + /** + * A filter to filter data directly to output buffer for record. + */ + RECORD, +}; + +/** + * Filter Event. + */ +struct DemuxFilterEvent { + DemuxFilterId filterId; + DemuxFilterType filterType; +}; + From fd4243a9515898de76b20e4440c934f6cee96582 Mon Sep 17 00:00:00 2001 From: Amy Date: Fri, 16 Aug 2019 16:01:27 -0700 Subject: [PATCH 0084/1022] Tuner HAL default implementation for Demux and Descrambler Interface. Bug: 135709325 Test: Manual Change-Id: I38a92abb761d2d39e8e6a495f2d93dee5f1c9d90 --- tv/tuner/1.0/default/Android.bp | 2 + tv/tuner/1.0/default/Demux.cpp | 55 ++++++++++++++++++++++++++ tv/tuner/1.0/default/Demux.h | 55 ++++++++++++++++++++++++++ tv/tuner/1.0/default/Descrambler.cpp | 59 ++++++++++++++++++++++++++++ tv/tuner/1.0/default/Descrambler.h | 56 ++++++++++++++++++++++++++ tv/tuner/1.0/default/Tuner.cpp | 9 +++-- tv/tuner/1.0/default/Tuner.h | 3 ++ 7 files changed, 236 insertions(+), 3 deletions(-) create mode 100644 tv/tuner/1.0/default/Demux.cpp create mode 100644 tv/tuner/1.0/default/Demux.h create mode 100644 tv/tuner/1.0/default/Descrambler.cpp create mode 100644 tv/tuner/1.0/default/Descrambler.h diff --git a/tv/tuner/1.0/default/Android.bp b/tv/tuner/1.0/default/Android.bp index cc8d1f50e6..21c9f1b6c2 100644 --- a/tv/tuner/1.0/default/Android.bp +++ b/tv/tuner/1.0/default/Android.bp @@ -5,6 +5,8 @@ cc_defaults { relative_install_path: "hw", srcs: [ "Frontend.cpp", + "Descrambler.cpp", + "Demux.cpp", "Tuner.cpp", "service.cpp", ], diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp new file mode 100644 index 0000000000..6f7c68bfb4 --- /dev/null +++ b/tv/tuner/1.0/default/Demux.cpp @@ -0,0 +1,55 @@ +/* + * 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 "android.hardware.tv.tuner@1.0-Demux" + +#include "Demux.h" +#include + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +Demux::Demux(uint32_t demuxId) { + mDemuxId = demuxId; +} + +Demux::~Demux() {} + +Return Demux::setFrontendDataSource(uint32_t frontendId) { + ALOGV("%s", __FUNCTION__); + + mSourceFrontendId = frontendId; + + return Result::SUCCESS; +} + +Return Demux::close() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; + ; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h new file mode 100644 index 0000000000..52f39336bd --- /dev/null +++ b/tv/tuner/1.0/default/Demux.h @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_DEMUX_H_ +#define ANDROID_HARDWARE_TV_TUNER_V1_0_DEMUX_H_ + +#include + +using namespace std; + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::tv::tuner::V1_0::IDemux; +using ::android::hardware::tv::tuner::V1_0::Result; + +class Demux : public IDemux { + public: + Demux(uint32_t demuxId); + + virtual Return setFrontendDataSource(uint32_t frontendId) override; + + virtual Return close() override; + + private: + virtual ~Demux(); + uint32_t mDemuxId; + uint32_t mSourceFrontendId; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_DEMUX_H_ diff --git a/tv/tuner/1.0/default/Descrambler.cpp b/tv/tuner/1.0/default/Descrambler.cpp new file mode 100644 index 0000000000..1af1a2c995 --- /dev/null +++ b/tv/tuner/1.0/default/Descrambler.cpp @@ -0,0 +1,59 @@ +/* + * 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 "android.hardware.tv.tuner@1.0-Descrambler" + +#include +#include + +#include "Descrambler.h" + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +Descrambler::Descrambler() {} + +Descrambler::~Descrambler() {} + +Return Descrambler::setDemuxSource(uint32_t demuxId) { + ALOGV("%s", __FUNCTION__); + if (mDemuxSet) { + ALOGW("[ WARN ] Descrambler has already been set with a demux id %d", mSourceDemuxId); + return Result::INVALID_STATE; + } + mDemuxSet = true; + mSourceDemuxId = demuxId; + + return Result::SUCCESS; +} + +Return Descrambler::close() { + ALOGV("%s", __FUNCTION__); + mDemuxSet = false; + + return Result::SUCCESS; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android diff --git a/tv/tuner/1.0/default/Descrambler.h b/tv/tuner/1.0/default/Descrambler.h new file mode 100644 index 0000000000..2ec8412a6d --- /dev/null +++ b/tv/tuner/1.0/default/Descrambler.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_DESCRAMBLER_H_ +#define ANDROID_HARDWARE_TV_TUNER_V1_0_DESCRAMBLER_H_ + +#include +#include + +using namespace std; + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::tv::tuner::V1_0::IDescrambler; +using ::android::hardware::tv::tuner::V1_0::Result; + +class Descrambler : public IDescrambler { + public: + Descrambler(); + + virtual Return setDemuxSource(uint32_t demuxId) override; + + virtual Return close() override; + + private: + virtual ~Descrambler(); + uint32_t mSourceDemuxId; + bool mDemuxSet = false; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TV_TUNER_V1_DESCRAMBLER_H_ diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp index 6bb7aa9af8..68b34368ee 100644 --- a/tv/tuner/1.0/default/Tuner.cpp +++ b/tv/tuner/1.0/default/Tuner.cpp @@ -19,6 +19,8 @@ #include "Tuner.h" #include #include +#include "Demux.h" +#include "Descrambler.h" #include "Frontend.h" namespace android { @@ -76,8 +78,9 @@ Return Tuner::openFrontendById(uint32_t frontendId, openFrontendById_cb _h Return Tuner::openDemux(openDemux_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); - sp demux; - DemuxId demuxId = 0; + DemuxId demuxId = mLastUsedId + 1; + mLastUsedId += 1; + sp demux = new Demux(demuxId); _hidl_cb(Result::SUCCESS, demuxId, demux); return Void(); @@ -86,7 +89,7 @@ Return Tuner::openDemux(openDemux_cb _hidl_cb) { Return Tuner::openDescrambler(openDescrambler_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); - sp descrambler; + sp descrambler = new Descrambler(); _hidl_cb(Result::SUCCESS, descrambler); return Void(); diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h index 1ca7671f1f..12e959406a 100644 --- a/tv/tuner/1.0/default/Tuner.h +++ b/tv/tuner/1.0/default/Tuner.h @@ -47,6 +47,9 @@ class Tuner : public ITuner { vector> mFrontends; // To maintain how many Frontends we have int mFrontendSize; + // The last used demux id. Initial value is -1. + // First used id will be 0. + int mLastUsedId = -1; }; } // namespace implementation From c247c884fa22ea2decc401328be899d8dd65c0b0 Mon Sep 17 00:00:00 2001 From: Amy Date: Mon, 19 Aug 2019 13:12:17 -0700 Subject: [PATCH 0085/1022] Tuner HAL VTS for Demux and Descrambler Interface. Bug: 135708935 Test: Manual Change-Id: I1f2c9bfe6036dc6070dbf88d9728645f2568dcde --- .../VtsHalTvTunerV1_0TargetTest.cpp | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 4840a02e25..c652944fee 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -52,6 +55,9 @@ using android::hardware::tv::tuner::V1_0::FrontendEventType; using android::hardware::tv::tuner::V1_0::FrontendId; using android::hardware::tv::tuner::V1_0::FrontendInnerFec; using android::hardware::tv::tuner::V1_0::FrontendSettings; +using android::hardware::tv::tuner::V1_0::IDemux; +using android::hardware::tv::tuner::V1_0::IDemuxCallback; +using android::hardware::tv::tuner::V1_0::IDescrambler; using android::hardware::tv::tuner::V1_0::IFrontend; using android::hardware::tv::tuner::V1_0::IFrontendCallback; using android::hardware::tv::tuner::V1_0::ITuner; @@ -146,11 +152,19 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { sp mFrontend; sp mFrontendCallback; + sp mDescrambler; + sp mDemux; + uint32_t mDemuxId; ::testing::AssertionResult createFrontend(int32_t frontendId); ::testing::AssertionResult tuneFrontend(int32_t frontendId); ::testing::AssertionResult stopTuneFrontend(int32_t frontendId); ::testing::AssertionResult closeFrontend(int32_t frontendId); + ::testing::AssertionResult createDemux(); + ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId); + ::testing::AssertionResult closeDemux(); + ::testing::AssertionResult createDescrambler(); + ::testing::AssertionResult closeDescrambler(); }; ::testing::AssertionResult TunerHidlTest::createFrontend(int32_t frontendId) { @@ -215,6 +229,78 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionResult(status == Result::SUCCESS); } +::testing::AssertionResult TunerHidlTest::createDemux() { + Result status; + + mService->openDemux([&](Result result, uint32_t demuxId, const sp& demux) { + mDemux = demux; + mDemuxId = demuxId; + status = result; + }); + return ::testing::AssertionResult(status == Result::SUCCESS); +} + +::testing::AssertionResult TunerHidlTest::createDemuxWithFrontend(int32_t frontendId) { + Result status; + + if (createDemux() == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + if (createFrontend(frontendId) == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + status = mDemux->setFrontendDataSource(frontendId); + + return ::testing::AssertionResult(status == Result::SUCCESS); +} + +::testing::AssertionResult TunerHidlTest::closeDemux() { + Result status; + if (createDemux() == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + status = mDemux->close(); + return ::testing::AssertionResult(status == Result::SUCCESS); +} + +::testing::AssertionResult TunerHidlTest::createDescrambler() { + Result status; + + mService->openDescrambler([&](Result result, const sp& descrambler) { + mDescrambler = descrambler; + status = result; + }); + if (status != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + + if (createDemux() == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + status = mDescrambler->setDemuxSource(mDemuxId); + if (status != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + + // Test if demux source can be set more than once. + status = mDescrambler->setDemuxSource(mDemuxId); + return ::testing::AssertionResult(status == Result::INVALID_STATE); +} + +::testing::AssertionResult TunerHidlTest::closeDescrambler() { + Result status; + if (createDescrambler() == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + status = mDescrambler->close(); + return ::testing::AssertionResult(status == Result::SUCCESS); +} + TEST_F(TunerHidlTest, CreateFrontend) { Result status; hidl_vec feIds; @@ -295,6 +381,50 @@ TEST_F(TunerHidlTest, CloseFrontend) { } } +TEST_F(TunerHidlTest, CreateDemux) { + description("Create Demux"); + + ASSERT_TRUE(createDemux()); +} + +TEST_F(TunerHidlTest, CreateDemuxWithFrontend) { + Result status; + hidl_vec feIds; + + description("Create Demux with Frontend"); + mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { + status = result; + feIds = frontendIds; + }); + + if (feIds.size() == 0) { + ALOGW("[ WARN ] Frontend isn't available"); + return; + } + + for (size_t i = 0; i < feIds.size(); i++) { + ASSERT_TRUE(createDemuxWithFrontend(feIds[i])); + } +} + +TEST_F(TunerHidlTest, CloseDemux) { + description("Close Demux"); + + ASSERT_TRUE(closeDemux()); +} + +TEST_F(TunerHidlTest, CreateDescrambler) { + description("Create Descrambler"); + + ASSERT_TRUE(createDescrambler()); +} + +TEST_F(TunerHidlTest, CloseDescrambler) { + description("Close Descrambler"); + + ASSERT_TRUE(closeDescrambler()); +} + } // namespace int main(int argc, char** argv) { From 600809eaab10804669956ba7d32d41ec918c50fc Mon Sep 17 00:00:00 2001 From: Peter Kalauskas Date: Wed, 14 Aug 2019 12:11:57 -0700 Subject: [PATCH 0086/1022] Convert LazyServiceRegistrar usage to singleton Test: lshal Bug: 139376253 Change-Id: I8a407d84f1a5b51309cf4306cf1beab4ed0c7df4 --- tv/tuner/1.0/default/service.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tv/tuner/1.0/default/service.cpp b/tv/tuner/1.0/default/service.cpp index 581d269b9e..c360fcf05c 100644 --- a/tv/tuner/1.0/default/service.cpp +++ b/tv/tuner/1.0/default/service.cpp @@ -46,8 +46,8 @@ int main() { android::sp service = new Tuner(); android::status_t status; if (kLazyService) { - auto serviceRegistrar = std::make_shared(); - status = serviceRegistrar->registerService(service); + auto serviceRegistrar = LazyServiceRegistrar::getInstance(); + status = serviceRegistrar.registerService(service); } else { status = service->registerAsService(); } From 615647f437dcbc862c0082eff2a5a736161d8f13 Mon Sep 17 00:00:00 2001 From: Nick Chalko Date: Fri, 23 Aug 2019 10:26:14 -0700 Subject: [PATCH 0087/1022] Fix spelling errors Change-Id: Ie8c8212d953ef74192e3b713975b813098a7485a Test: m VtsHalTvTunerV1_0TargetTest --- tv/tuner/1.0/types.hal | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index 3fa9641169..4ee03a0288 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -90,10 +90,10 @@ enum FrontendAtscModulation : uint32_t { }; /** - * Signal Setting for ATSC Frontend. + * Signal Settings for an ATSC Frontend. */ struct FrontendAtscSettings { - /** Signal frequencey in Herhz */ + /** Signal frequency in Hertz */ uint32_t frequency; FrontendAtscModulation modulation; }; @@ -102,7 +102,7 @@ struct FrontendAtscSettings { * Signal Setting for DVBT Frontend. */ struct FrontendDvbtSettings { - /** Signal frequencey in Herhz */ + /** Signal frequency in Hertz */ uint32_t frequency; FrontendAtscModulation modulation; FrontendInnerFec fec; From 2879067ddb8bb17db84d963e93f70a0992e27d5b Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Tue, 20 Aug 2019 14:32:15 -0700 Subject: [PATCH 0088/1022] Multihal 2.0 - Implement SubHal discovery Collect the SubHal pointers discovered from dynamic libs contained within the multi hal config file. Bug: 136511617 Test: Compiled with mma -j and observed loading of modules Change-Id: I148265722e70d4cd56671af9c6f1ff6dde355ae4 --- sensors/2.0/multihal/Android.bp | 2 +- sensors/2.0/multihal/HalProxy.cpp | 41 ++++++++++++++++++++++++++++++- sensors/2.0/multihal/HalProxy.h | 5 ++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp index f0b33e42a1..dff28abcf0 100644 --- a/sensors/2.0/multihal/Android.bp +++ b/sensors/2.0/multihal/Android.bp @@ -44,4 +44,4 @@ cc_library_headers { name: "android.hardware.sensors@2.0-subhal.header", vendor: true, export_include_dirs: ["include"], -} \ No newline at end of file +} diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index 31f8a182b8..41c35485b6 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -18,12 +18,19 @@ #include +#include + +#include +#include + namespace android { namespace hardware { namespace sensors { namespace V2_0 { namespace implementation { +typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*); + // TODO: Use this wake lock name as the prefix to all sensors HAL wake locks acquired. // constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP"; @@ -62,7 +69,39 @@ class SensorsCallbackProxy : public ISensorsCallback { }; HalProxy::HalProxy() { - // TODO: Initialize all sub-HALs and discover sensors. + const char* kMultiHalConfigFilePath = "/vendor/etc/sensors/hals.conf"; + std::ifstream subHalConfigStream(kMultiHalConfigFilePath); + if (!subHalConfigStream) { + LOG_FATAL("Failed to load subHal config file: %s", kMultiHalConfigFilePath); + } else { + std::string subHalLibraryFile; + while (subHalConfigStream >> subHalLibraryFile) { + void* handle = dlopen(subHalLibraryFile.c_str(), RTLD_NOW); + if (handle == nullptr) { + LOG_FATAL("dlopen failed for library: %s", subHalLibraryFile.c_str()); + } else { + SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr = + (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal"); + if (sensorsHalGetSubHalPtr == nullptr) { + LOG_FATAL("Failed to locate sensorsHalGetSubHal function for library: %s", + subHalLibraryFile.c_str()); + } else { + std::function sensorsHalGetSubHal = + *sensorsHalGetSubHalPtr; + uint32_t version; + ISensorsSubHal* subHal = sensorsHalGetSubHal(&version); + if (version != SUB_HAL_2_0_VERSION) { + LOG_FATAL("SubHal version was not 2.0 for library: %s", + subHalLibraryFile.c_str()); + } else { + ALOGI("Loaded SubHal from library: %s", subHalLibraryFile.c_str()); + mSubHalList.push_back(subHal); + } + } + } + } + } + // TODO: Discover sensors } HalProxy::~HalProxy() { diff --git a/sensors/2.0/multihal/HalProxy.h b/sensors/2.0/multihal/HalProxy.h index b9855a6ac5..e5799fdcd4 100644 --- a/sensors/2.0/multihal/HalProxy.h +++ b/sensors/2.0/multihal/HalProxy.h @@ -111,6 +111,11 @@ struct HalProxy : public ISensors { * Callback to the sensors framework to inform it that new sensors have been added or removed. */ sp mDynamicSensorsCallback; + + /** + * SubHal object pointers that have been saved from vendor dynamic libraries. + */ + std::vector mSubHalList; }; } // namespace implementation From 9e2b97b83cd3163750bebe55e6b55811ca8a6712 Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Fri, 23 Aug 2019 16:10:54 -0700 Subject: [PATCH 0089/1022] Update VTS tests with the new test harness. Bug: 120601396 Test: All VTS Change-Id: I539e75585b2cc01d153565814491361adfa048be --- neuralnetworks/1.0/vts/functional/Android.bp | 4 +- .../vts/functional/GeneratedTestHarness.cpp | 85 ++++++++++-------- .../1.0/vts/functional/GeneratedTestHarness.h | 38 +++++++- .../1.0/vts/functional/GeneratedTests.h | 26 ------ .../1.0/vts/functional/ValidateModel.cpp | 4 +- .../1.0/vts/functional/ValidateRequest.cpp | 1 + .../vts/functional/VtsHalNeuralnetworks.cpp | 15 +++- .../1.0/vts/functional/VtsHalNeuralnetworks.h | 15 +--- neuralnetworks/1.1/vts/functional/Android.bp | 6 +- .../vts/functional/GeneratedTestHarness.cpp | 86 +++++++++++-------- .../1.1/vts/functional/GeneratedTestHarness.h | 38 +++++++- .../1.1/vts/functional/GeneratedTests.h | 29 ------- .../1.1/vts/functional/ValidateModel.cpp | 1 + .../1.1/vts/functional/ValidateRequest.cpp | 1 + .../vts/functional/VtsHalNeuralnetworks.cpp | 15 +++- .../1.1/vts/functional/VtsHalNeuralnetworks.h | 15 +--- neuralnetworks/1.2/vts/functional/Android.bp | 8 +- .../functional/CompilationCachingTests.cpp | 86 +++++++++---------- .../vts/functional/GeneratedTestHarness.cpp | 48 ++++++++--- .../1.2/vts/functional/GeneratedTestHarness.h | 42 +++++++-- .../1.2/vts/functional/GeneratedTests.h | 29 ------- .../1.2/vts/functional/ValidateBurst.cpp | 1 + .../1.2/vts/functional/ValidateModel.cpp | 1 + .../1.2/vts/functional/ValidateRequest.cpp | 1 + .../vts/functional/VtsHalNeuralnetworks.cpp | 18 +++- .../1.2/vts/functional/VtsHalNeuralnetworks.h | 19 +--- 26 files changed, 348 insertions(+), 284 deletions(-) delete mode 100644 neuralnetworks/1.0/vts/functional/GeneratedTests.h delete mode 100644 neuralnetworks/1.1/vts/functional/GeneratedTests.h delete mode 100644 neuralnetworks/1.2/vts/functional/GeneratedTests.h diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp index abff213847..664436c8bc 100644 --- a/neuralnetworks/1.0/vts/functional/Android.bp +++ b/neuralnetworks/1.0/vts/functional/Android.bp @@ -74,7 +74,7 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_0TargetTestDefaults"], srcs: [ "BasicTests.cpp", - ":VtsHalNeuralNetworksV1_0_all_generated_V1_0_tests", + ":VtsHalNeuralNetworksV1_0_all_generated_tests", ], } @@ -83,7 +83,7 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_0TargetTestDefaults"], srcs: [ "BasicTests.cpp", - ":VtsHalNeuralNetworksV1_0_all_generated_V1_0_tests", + ":VtsHalNeuralNetworksV1_0_all_generated_tests", ], cflags: [ "-DPRESUBMIT_NOT_VTS", diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp index 0fd9947ede..5f96539fc4 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp @@ -20,6 +20,7 @@ #include "1.0/Utils.h" #include "MemoryUtils.h" #include "TestHarness.h" +#include "VtsHalNeuralnetworks.h" #include #include @@ -36,7 +37,8 @@ namespace android { namespace hardware { namespace neuralnetworks { namespace V1_0 { -namespace generated_tests { +namespace vts { +namespace functional { using namespace test_helper; using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; @@ -151,48 +153,61 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo checkResults(testModel, outputs); } -void Execute(const sp& device, const TestModel& testModel) { - Model model = createModel(testModel); +// Tag for the generated tests +class GeneratedTest : public GeneratedTestBase { + protected: + void Execute(const TestModel& testModel) { + Model model = createModel(testModel); - // see if service can handle model - bool fullySupportsModel = false; - Return supportedCall = device->getSupportedOperations( - model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { - ASSERT_EQ(ErrorStatus::NONE, status); - ASSERT_NE(0ul, supported.size()); - fullySupportsModel = std::all_of(supported.begin(), supported.end(), - [](bool valid) { return valid; }); - }); - ASSERT_TRUE(supportedCall.isOk()); + // see if service can handle model + bool fullySupportsModel = false; + Return supportedCall = device->getSupportedOperations( + model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { + ASSERT_EQ(ErrorStatus::NONE, status); + ASSERT_NE(0ul, supported.size()); + fullySupportsModel = std::all_of(supported.begin(), supported.end(), + [](bool valid) { return valid; }); + }); + ASSERT_TRUE(supportedCall.isOk()); - // launch prepare model - sp preparedModelCallback = new PreparedModelCallback(); - Return prepareLaunchStatus = device->prepareModel(model, preparedModelCallback); - ASSERT_TRUE(prepareLaunchStatus.isOk()); - ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); + // launch prepare model + sp preparedModelCallback = new PreparedModelCallback(); + Return prepareLaunchStatus = + device->prepareModel(model, preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); - // retrieve prepared model - preparedModelCallback->wait(); - ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); - sp preparedModel = preparedModelCallback->getPreparedModel(); + // retrieve prepared model + preparedModelCallback->wait(); + ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + sp preparedModel = preparedModelCallback->getPreparedModel(); - // early termination if vendor service cannot fully prepare model - if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { - ASSERT_EQ(nullptr, preparedModel.get()); - LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " - "prepare model that it does not support."; - std::cout << "[ ] Early termination of test because vendor service cannot " - "prepare model that it does not support." - << std::endl; - GTEST_SKIP(); + // early termination if vendor service cannot fully prepare model + if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { + ASSERT_EQ(nullptr, preparedModel.get()); + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " + "prepare model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "prepare model that it does not support." + << std::endl; + GTEST_SKIP(); + } + EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); + ASSERT_NE(nullptr, preparedModel.get()); + + EvaluatePreparedModel(preparedModel, testModel); } - EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); - ASSERT_NE(nullptr, preparedModel.get()); +}; - EvaluatePreparedModel(preparedModel, testModel); +TEST_P(GeneratedTest, Test) { + Execute(*mTestModel); } -} // namespace generated_tests +INSTANTIATE_GENERATED_TEST(GeneratedTest, + [](const TestModel& testModel) { return !testModel.expectFailure; }); + +} // namespace functional +} // namespace vts } // namespace V1_0 } // namespace neuralnetworks } // namespace hardware diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h index 5d22158529..f86e8b3e72 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h @@ -19,18 +19,48 @@ #include #include "TestHarness.h" +#include "VtsHalNeuralnetworks.h" namespace android { namespace hardware { namespace neuralnetworks { namespace V1_0 { -namespace generated_tests { +namespace vts { +namespace functional { + +class GeneratedTestBase + : public NeuralnetworksHidlTest, + public ::testing::WithParamInterface { + protected: + void SetUp() override { + NeuralnetworksHidlTest::SetUp(); + ASSERT_NE(mTestModel, nullptr); + } + + const test_helper::TestModel* mTestModel = GetParam().second; +}; + +#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ + INSTANTIATE_TEST_SUITE_P( \ + TestGenerated, TestSuite, \ + ::testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \ + [](const auto& info) { return info.param.first; }) + +// Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp. +// TODO: Clean up the hierarchy for ValidationTest. +class ValidationTest : public GeneratedTestBase { + protected: + void validateEverything(const Model& model, const Request& request); + + private: + void validateModel(const Model& model); + void validateRequest(const sp& preparedModel, const Request& request); +}; Model createModel(const ::test_helper::TestModel& testModel); -void Execute(const sp& device, const ::test_helper::TestModel& testModel); - -} // namespace generated_tests +} // namespace functional +} // namespace vts } // namespace V1_0 } // namespace neuralnetworks } // namespace hardware diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTests.h b/neuralnetworks/1.0/vts/functional/GeneratedTests.h deleted file mode 100644 index 9528905d61..0000000000 --- a/neuralnetworks/1.0/vts/functional/GeneratedTests.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ - -#include "1.0/Utils.h" -#include "GeneratedTestHarness.h" -#include "TestHarness.h" -#include "VtsHalNeuralnetworks.h" - -namespace android::hardware::neuralnetworks::V1_0::generated_tests { - -using namespace android::hardware::neuralnetworks::V1_0::vts::functional; - -} // namespace android::hardware::neuralnetworks::V1_0::generated_tests diff --git a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp index 72c4a2b229..5845aabe70 100644 --- a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp @@ -16,9 +16,9 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" -#include "VtsHalNeuralnetworks.h" - #include "1.0/Callbacks.h" +#include "GeneratedTestHarness.h" +#include "VtsHalNeuralnetworks.h" namespace android { namespace hardware { diff --git a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp index d62365cb6a..730e054757 100644 --- a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" #include "1.0/Callbacks.h" +#include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" namespace android { diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp index 626deac143..a51f71f8c6 100644 --- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp @@ -17,11 +17,13 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" #include "VtsHalNeuralnetworks.h" +#include "1.0/Callbacks.h" +#include "1.0/Utils.h" +#include "GeneratedTestHarness.h" +#include "TestHarness.h" #include -#include "1.0/Callbacks.h" - namespace android { namespace hardware { namespace neuralnetworks { @@ -134,6 +136,15 @@ void ValidationTest::validateEverything(const Model& model, const Request& reque validateRequest(preparedModel, request); } +TEST_P(ValidationTest, Test) { + const Model model = createModel(*mTestModel); + const Request request = createRequest(*mTestModel); + ASSERT_FALSE(mTestModel->expectFailure); + validateEverything(model, request); +} + +INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); + } // namespace functional } // namespace vts } // namespace V1_0 diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h index 3765314218..9638a0e667 100644 --- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h @@ -28,6 +28,8 @@ #include #include +#include "TestHarness.h" + namespace android { namespace hardware { namespace neuralnetworks { @@ -60,19 +62,6 @@ class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase { sp device; }; -// Tag for the validation tests -class ValidationTest : public NeuralnetworksHidlTest { - protected: - void validateEverything(const Model& model, const Request& request); - - private: - void validateModel(const Model& model); - void validateRequest(const sp& preparedModel, const Request& request); -}; - -// Tag for the generated tests -class GeneratedTest : public NeuralnetworksHidlTest {}; - } // namespace functional } // namespace vts } // namespace V1_0 diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp index 86002d21aa..05c7f6bfff 100644 --- a/neuralnetworks/1.1/vts/functional/Android.bp +++ b/neuralnetworks/1.1/vts/functional/Android.bp @@ -49,7 +49,7 @@ cc_test { name: "VtsHalNeuralnetworksV1_1CompatV1_0TargetTest", defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"], srcs: [ - ":VtsHalNeuralNetworksV1_1_all_generated_V1_0_tests", + ":VtsHalNeuralNetworksV1_0_all_generated_tests", ], } @@ -59,7 +59,7 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"], srcs: [ "BasicTests.cpp", - ":VtsHalNeuralNetworksV1_1_all_generated_V1_1_tests", + ":VtsHalNeuralNetworksV1_1_all_generated_tests", ], } @@ -68,7 +68,7 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"], srcs: [ "BasicTests.cpp", - ":VtsHalNeuralNetworksV1_1_all_generated_V1_1_tests", + ":VtsHalNeuralNetworksV1_1_all_generated_tests", ], cflags: [ "-DPRESUBMIT_NOT_VTS", diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp index 73eeb93a47..d8d1a31ac4 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp @@ -31,12 +31,14 @@ #include "1.0/Utils.h" #include "MemoryUtils.h" #include "TestHarness.h" +#include "VtsHalNeuralnetworks.h" namespace android { namespace hardware { namespace neuralnetworks { namespace V1_1 { -namespace generated_tests { +namespace vts { +namespace functional { using namespace test_helper; using ::android::hardware::neuralnetworks::V1_0::DataLocation; @@ -157,49 +159,61 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo checkResults(testModel, outputs); } -void Execute(const sp& device, const TestModel& testModel) { - Model model = createModel(testModel); +// Tag for the generated tests +class GeneratedTest : public GeneratedTestBase { + protected: + void Execute(const TestModel& testModel) { + Model model = createModel(testModel); - // see if service can handle model - bool fullySupportsModel = false; - Return supportedCall = device->getSupportedOperations_1_1( - model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { - ASSERT_EQ(ErrorStatus::NONE, status); - ASSERT_NE(0ul, supported.size()); - fullySupportsModel = std::all_of(supported.begin(), supported.end(), - [](bool valid) { return valid; }); - }); - ASSERT_TRUE(supportedCall.isOk()); + // see if service can handle model + bool fullySupportsModel = false; + Return supportedCall = device->getSupportedOperations_1_1( + model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { + ASSERT_EQ(ErrorStatus::NONE, status); + ASSERT_NE(0ul, supported.size()); + fullySupportsModel = std::all_of(supported.begin(), supported.end(), + [](bool valid) { return valid; }); + }); + ASSERT_TRUE(supportedCall.isOk()); - // launch prepare model - sp preparedModelCallback = new PreparedModelCallback(); - Return prepareLaunchStatus = device->prepareModel_1_1( - model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback); - ASSERT_TRUE(prepareLaunchStatus.isOk()); - ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); + // launch prepare model + sp preparedModelCallback = new PreparedModelCallback(); + Return prepareLaunchStatus = device->prepareModel_1_1( + model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); - // retrieve prepared model - preparedModelCallback->wait(); - ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); - sp preparedModel = preparedModelCallback->getPreparedModel(); + // retrieve prepared model + preparedModelCallback->wait(); + ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + sp preparedModel = preparedModelCallback->getPreparedModel(); - // early termination if vendor service cannot fully prepare model - if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { - ASSERT_EQ(nullptr, preparedModel.get()); - LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " - "prepare model that it does not support."; - std::cout << "[ ] Early termination of test because vendor service cannot " - "prepare model that it does not support." - << std::endl; - GTEST_SKIP(); + // early termination if vendor service cannot fully prepare model + if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { + ASSERT_EQ(nullptr, preparedModel.get()); + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " + "prepare model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "prepare model that it does not support." + << std::endl; + GTEST_SKIP(); + } + EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); + ASSERT_NE(nullptr, preparedModel.get()); + + EvaluatePreparedModel(preparedModel, testModel); } - EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); - ASSERT_NE(nullptr, preparedModel.get()); +}; - EvaluatePreparedModel(preparedModel, testModel); +TEST_P(GeneratedTest, Test) { + Execute(*mTestModel); } -} // namespace generated_tests +INSTANTIATE_GENERATED_TEST(GeneratedTest, + [](const TestModel& testModel) { return !testModel.expectFailure; }); + +} // namespace functional +} // namespace vts } // namespace V1_1 } // namespace neuralnetworks } // namespace hardware diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h index 56fc8257bd..82fc55148a 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h @@ -19,18 +19,48 @@ #include #include "TestHarness.h" +#include "VtsHalNeuralnetworks.h" namespace android { namespace hardware { namespace neuralnetworks { namespace V1_1 { -namespace generated_tests { +namespace vts { +namespace functional { + +class GeneratedTestBase + : public NeuralnetworksHidlTest, + public ::testing::WithParamInterface { + protected: + void SetUp() override { + NeuralnetworksHidlTest::SetUp(); + ASSERT_NE(mTestModel, nullptr); + } + + const test_helper::TestModel* mTestModel = GetParam().second; +}; + +#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ + INSTANTIATE_TEST_SUITE_P( \ + TestGenerated, TestSuite, \ + ::testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \ + [](const auto& info) { return info.param.first; }) + +// Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp. +// TODO: Clean up the hierarchy for ValidationTest. +class ValidationTest : public GeneratedTestBase { + protected: + void validateEverything(const Model& model, const Request& request); + + private: + void validateModel(const Model& model); + void validateRequest(const sp& preparedModel, const Request& request); +}; Model createModel(const ::test_helper::TestModel& testModel); -void Execute(const sp& device, const ::test_helper::TestModel& testModel); - -} // namespace generated_tests +} // namespace functional +} // namespace vts } // namespace V1_1 } // namespace neuralnetworks } // namespace hardware diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTests.h b/neuralnetworks/1.1/vts/functional/GeneratedTests.h deleted file mode 100644 index a55213d2a6..0000000000 --- a/neuralnetworks/1.1/vts/functional/GeneratedTests.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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. - */ - -#include "1.0/Utils.h" -#include "GeneratedTestHarness.h" -#include "TestHarness.h" -#include "VtsHalNeuralnetworks.h" - -namespace android::hardware::neuralnetworks::V1_1::generated_tests { - -using namespace android::hardware::neuralnetworks::V1_1::vts::functional; - -using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; -using ::android::hardware::neuralnetworks::V1_0::Request; - -} // namespace android::hardware::neuralnetworks::V1_1::generated_tests diff --git a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp index fb80d1307a..d20dcd0aeb 100644 --- a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp @@ -18,6 +18,7 @@ #include "1.0/Callbacks.h" #include "1.0/Utils.h" +#include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" namespace android { diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp index 757bee9711..e0710f119e 100644 --- a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp @@ -18,6 +18,7 @@ #include "1.0/Callbacks.h" #include "1.0/Utils.h" +#include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" namespace android { diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp index b3b15fa8e5..9a11b10b49 100644 --- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp @@ -17,11 +17,13 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" #include "VtsHalNeuralnetworks.h" +#include "1.0/Callbacks.h" +#include "1.0/Utils.h" +#include "GeneratedTestHarness.h" +#include "TestHarness.h" #include -#include "1.0/Callbacks.h" - namespace android { namespace hardware { namespace neuralnetworks { @@ -135,6 +137,15 @@ void ValidationTest::validateEverything(const Model& model, const Request& reque validateRequest(preparedModel, request); } +TEST_P(ValidationTest, Test) { + const Model model = createModel(*mTestModel); + const Request request = createRequest(*mTestModel); + ASSERT_FALSE(mTestModel->expectFailure); + validateEverything(model, request); +} + +INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); + } // namespace functional } // namespace vts } // namespace V1_1 diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h index 2d6a20cdbe..8d44deb21b 100644 --- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h @@ -29,6 +29,8 @@ #include #include +#include "TestHarness.h" + namespace android { namespace hardware { namespace neuralnetworks { @@ -69,19 +71,6 @@ class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase { sp device; }; -// Tag for the validation tests -class ValidationTest : public NeuralnetworksHidlTest { - protected: - void validateEverything(const Model& model, const Request& request); - - private: - void validateModel(const Model& model); - void validateRequest(const sp& preparedModel, const Request& request); -}; - -// Tag for the generated tests -class GeneratedTest : public NeuralnetworksHidlTest {}; - } // namespace functional } // namespace vts } // namespace V1_1 diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index e14430f45d..7f2e11098d 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -52,7 +52,7 @@ cc_test { name: "VtsHalNeuralnetworksV1_2CompatV1_0TargetTest", defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ - ":VtsHalNeuralNetworksV1_2_all_generated_V1_0_tests", + ":VtsHalNeuralNetworksV1_0_all_generated_tests", "ValidateBurst.cpp", ], } @@ -62,7 +62,7 @@ cc_test { name: "VtsHalNeuralnetworksV1_2CompatV1_1TargetTest", defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ - ":VtsHalNeuralNetworksV1_2_all_generated_V1_1_tests", + ":VtsHalNeuralNetworksV1_1_all_generated_tests", "ValidateBurst.cpp", ], } @@ -73,7 +73,7 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ "BasicTests.cpp", - ":VtsHalNeuralNetworksV1_2_all_generated_V1_2_tests", + ":VtsHalNeuralNetworksV1_2_all_generated_tests", ":VtsHalNeuralNetworksV1_2_mobilenets", "CompilationCachingTests.cpp", "ValidateBurst.cpp", @@ -85,7 +85,7 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ "BasicTests.cpp", - ":VtsHalNeuralNetworksV1_2_all_generated_V1_2_tests", + ":VtsHalNeuralNetworksV1_2_all_generated_tests", "ValidateBurst.cpp", ], cflags: [ diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp index 8747fb3bf5..bde700e079 100644 --- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp @@ -425,7 +425,7 @@ class CompilationCachingTest : public CompilationCachingTestBase, TEST_P(CompilationCachingTest, CacheSavingAndRetrieval) { // Create test HIDL model and compile. const TestModel& testModel = createTestModel(); - const Model model = generated_tests::createModel(testModel); + const Model model = createModel(testModel); if (checkEarlyTermination(model)) return; sp preparedModel = nullptr; @@ -459,14 +459,14 @@ TEST_P(CompilationCachingTest, CacheSavingAndRetrieval) { } // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); } TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) { // Create test HIDL model and compile. const TestModel& testModel = createTestModel(); - const Model model = generated_tests::createModel(testModel); + const Model model = createModel(testModel); if (checkEarlyTermination(model)) return; sp preparedModel = nullptr; @@ -522,14 +522,14 @@ TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) { } // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); } TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { // Create test HIDL model and compile. const TestModel& testModel = createTestModel(); - const Model model = generated_tests::createModel(testModel); + const Model model = createModel(testModel); if (checkEarlyTermination(model)) return; // Test with number of model cache files greater than mNumModelCache. @@ -544,8 +544,8 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -569,8 +569,8 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -593,8 +593,8 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -618,8 +618,8 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -634,7 +634,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumCache) { // Create test HIDL model and compile. const TestModel& testModel = createTestModel(); - const Model model = generated_tests::createModel(testModel); + const Model model = createModel(testModel); if (checkEarlyTermination(model)) return; // Save the compilation to cache. @@ -715,7 +715,7 @@ TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumCache) { TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { // Create test HIDL model and compile. const TestModel& testModel = createTestModel(); - const Model model = generated_tests::createModel(testModel); + const Model model = createModel(testModel); if (checkEarlyTermination(model)) return; // Go through each handle in model cache, test with NumFd greater than 1. @@ -730,8 +730,8 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -755,8 +755,8 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -779,8 +779,8 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -804,8 +804,8 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -820,7 +820,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumFd) { // Create test HIDL model and compile. const TestModel& testModel = createTestModel(); - const Model model = generated_tests::createModel(testModel); + const Model model = createModel(testModel); if (checkEarlyTermination(model)) return; // Save the compilation to cache. @@ -901,7 +901,7 @@ TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumFd) { TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) { // Create test HIDL model and compile. const TestModel& testModel = createTestModel(); - const Model model = generated_tests::createModel(testModel); + const Model model = createModel(testModel); if (checkEarlyTermination(model)) return; std::vector modelCacheMode(mNumModelCache, AccessMode::READ_WRITE); std::vector dataCacheMode(mNumDataCache, AccessMode::READ_WRITE); @@ -917,8 +917,8 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -940,8 +940,8 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - generated_tests::EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -956,7 +956,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) { TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidAccessMode) { // Create test HIDL model and compile. const TestModel& testModel = createTestModel(); - const Model model = generated_tests::createModel(testModel); + const Model model = createModel(testModel); if (checkEarlyTermination(model)) return; std::vector modelCacheMode(mNumModelCache, AccessMode::READ_WRITE); std::vector dataCacheMode(mNumDataCache, AccessMode::READ_WRITE); @@ -1035,10 +1035,10 @@ TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) { // Create test models and check if fully supported by the service. const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize); - const Model modelMul = generated_tests::createModel(testModelMul); + const Model modelMul = createModel(testModelMul); if (checkEarlyTermination(modelMul)) return; const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize); - const Model modelAdd = generated_tests::createModel(testModelAdd); + const Model modelAdd = createModel(testModelAdd); if (checkEarlyTermination(modelAdd)) return; // Save the modelMul compilation to cache. @@ -1085,8 +1085,8 @@ TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) { ASSERT_EQ(preparedModel, nullptr); } else { ASSERT_NE(preparedModel, nullptr); - generated_tests::EvaluatePreparedModel(preparedModel, testModelAdd, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModelAdd, + /*testDynamicOutputShape=*/false); } } } @@ -1097,10 +1097,10 @@ TEST_P(CompilationCachingTest, PrepareFromCache_TOCTOU) { // Create test models and check if fully supported by the service. const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize); - const Model modelMul = generated_tests::createModel(testModelMul); + const Model modelMul = createModel(testModelMul); if (checkEarlyTermination(modelMul)) return; const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize); - const Model modelAdd = generated_tests::createModel(testModelAdd); + const Model modelAdd = createModel(testModelAdd); if (checkEarlyTermination(modelAdd)) return; // Save the modelMul compilation to cache. @@ -1147,8 +1147,8 @@ TEST_P(CompilationCachingTest, PrepareFromCache_TOCTOU) { ASSERT_EQ(preparedModel, nullptr); } else { ASSERT_NE(preparedModel, nullptr); - generated_tests::EvaluatePreparedModel(preparedModel, testModelAdd, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModelAdd, + /*testDynamicOutputShape=*/false); } } } @@ -1159,10 +1159,10 @@ TEST_P(CompilationCachingTest, ReplaceSecuritySensitiveCache) { // Create test models and check if fully supported by the service. const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize); - const Model modelMul = generated_tests::createModel(testModelMul); + const Model modelMul = createModel(testModelMul); if (checkEarlyTermination(modelMul)) return; const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize); - const Model modelAdd = generated_tests::createModel(testModelAdd); + const Model modelAdd = createModel(testModelAdd); if (checkEarlyTermination(modelAdd)) return; // Save the modelMul compilation to cache. @@ -1265,7 +1265,7 @@ class CompilationCachingSecurityTest // whether the test should be skipped or not. void testCorruptedCache(ExpectedResult expected, std::function modifier) { const TestModel& testModel = createTestModel(); - const Model model = generated_tests::createModel(testModel); + const Model model = createModel(testModel); if (checkEarlyTermination(model)) return; // Save the compilation to cache. diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp index 1dcebbe39c..1d302e2f2c 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp @@ -42,12 +42,14 @@ #include "MemoryUtils.h" #include "TestHarness.h" #include "Utils.h" +#include "VtsHalNeuralnetworks.h" namespace android { namespace hardware { namespace neuralnetworks { namespace V1_2 { -namespace generated_tests { +namespace vts { +namespace functional { using namespace test_helper; using ::android::hardware::neuralnetworks::V1_0::DataLocation; @@ -410,21 +412,43 @@ void PrepareModel(const sp& device, const Model& model, ASSERT_NE(nullptr, preparedModel->get()); } -void Execute(const sp& device, const TestModel& testModel, bool testDynamicOutputShape) { - Model model = createModel(testModel); - if (testDynamicOutputShape) { - makeOutputDimensionsUnspecified(&model); - } +// Tag for the generated tests +class GeneratedTest : public GeneratedTestBase { + protected: + void Execute(const TestModel& testModel, bool testDynamicOutputShape) { + Model model = createModel(testModel); + if (testDynamicOutputShape) { + makeOutputDimensionsUnspecified(&model); + } - sp preparedModel = nullptr; - PrepareModel(device, model, &preparedModel); - if (preparedModel == nullptr) { - GTEST_SKIP(); + sp preparedModel = nullptr; + PrepareModel(device, model, &preparedModel); + if (preparedModel == nullptr) { + GTEST_SKIP(); + } + EvaluatePreparedModel(preparedModel, testModel, testDynamicOutputShape); } - EvaluatePreparedModel(preparedModel, testModel, testDynamicOutputShape); +}; + +// Tag for the dynamic output shape tests +class DynamicOutputShapeTest : public GeneratedTest {}; + +TEST_P(GeneratedTest, Test) { + Execute(*mTestModel, /*testDynamicOutputShape=*/false); } -} // namespace generated_tests +TEST_P(DynamicOutputShapeTest, Test) { + Execute(*mTestModel, /*testDynamicOutputShape=*/true); +} + +INSTANTIATE_GENERATED_TEST(GeneratedTest, + [](const TestModel& testModel) { return !testModel.expectFailure; }); + +INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, + [](const TestModel& testModel) { return !testModel.expectFailure; }); + +} // namespace functional +} // namespace vts } // namespace V1_2 } // namespace neuralnetworks } // namespace hardware diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h index de45242ac7..27208ce4b6 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h @@ -23,12 +23,46 @@ #include #include #include "TestHarness.h" +#include "VtsHalNeuralnetworks.h" namespace android { namespace hardware { namespace neuralnetworks { namespace V1_2 { -namespace generated_tests { +namespace vts { +namespace functional { + +class GeneratedTestBase + : public NeuralnetworksHidlTest, + public ::testing::WithParamInterface { + protected: + void SetUp() override { + NeuralnetworksHidlTest::SetUp(); + ASSERT_NE(mTestModel, nullptr); + } + + const test_helper::TestModel* mTestModel = GetParam().second; +}; + +#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ + INSTANTIATE_TEST_SUITE_P( \ + TestGenerated, TestSuite, \ + ::testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \ + [](const auto& info) { return info.param.first; }) + +// Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp. +// TODO: Clean up the hierarchy for ValidationTest. +class ValidationTest : public GeneratedTestBase { + protected: + void validateEverything(const Model& model, const Request& request); + void validateFailure(const Model& model, const Request& request); + + private: + void validateModel(const Model& model); + void validateRequest(const sp& preparedModel, const Request& request); + void validateRequestFailure(const sp& preparedModel, const Request& request); + void validateBurst(const sp& preparedModel, const Request& request); +}; Model createModel(const ::test_helper::TestModel& testModel); @@ -38,10 +72,8 @@ void PrepareModel(const sp& device, const V1_2::Model& model, void EvaluatePreparedModel(const sp& preparedModel, const ::test_helper::TestModel& testModel, bool testDynamicOutputShape); -void Execute(const sp& device, const ::test_helper::TestModel& testModel, - bool testDynamicOutputShape = false); - -} // namespace generated_tests +} // namespace functional +} // namespace vts } // namespace V1_2 } // namespace neuralnetworks } // namespace hardware diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTests.h b/neuralnetworks/1.2/vts/functional/GeneratedTests.h deleted file mode 100644 index a72360941e..0000000000 --- a/neuralnetworks/1.2/vts/functional/GeneratedTests.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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. - */ - -#include "1.0/Utils.h" -#include "GeneratedTestHarness.h" -#include "TestHarness.h" -#include "VtsHalNeuralnetworks.h" - -namespace android::hardware::neuralnetworks::V1_2::generated_tests { - -using namespace ::android::hardware::neuralnetworks::V1_2::vts::functional; - -using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; -using ::android::hardware::neuralnetworks::V1_0::Request; - -} // namespace android::hardware::neuralnetworks::V1_2::generated_tests diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp index 94603fbcfd..cb801eb4ad 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp @@ -21,6 +21,7 @@ #include "1.2/Callbacks.h" #include "ExecutionBurstController.h" #include "ExecutionBurstServer.h" +#include "GeneratedTestHarness.h" #include "TestHarness.h" #include "Utils.h" diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp index 78bb194fb8..7dfcff2d42 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp @@ -18,6 +18,7 @@ #include "1.0/Utils.h" #include "1.2/Callbacks.h" +#include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" namespace android { diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp index 13d45e4a1a..20c740e306 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp @@ -19,6 +19,7 @@ #include "1.0/Utils.h" #include "1.2/Callbacks.h" #include "ExecutionBurstController.h" +#include "GeneratedTestHarness.h" #include "TestHarness.h" #include "Utils.h" #include "VtsHalNeuralnetworks.h" diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp index eb52110548..b87384e6c7 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp @@ -17,11 +17,13 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" #include "VtsHalNeuralnetworks.h" +#include "1.0/Callbacks.h" +#include "1.0/Utils.h" +#include "GeneratedTestHarness.h" +#include "TestHarness.h" #include -#include "1.2/Callbacks.h" - namespace android { namespace hardware { namespace neuralnetworks { @@ -154,6 +156,18 @@ void ValidationTest::validateFailure(const Model& model, const Request& request) validateRequestFailure(preparedModel, request); } +TEST_P(ValidationTest, Test) { + const Model model = createModel(*mTestModel); + const Request request = createRequest(*mTestModel); + if (mTestModel->expectFailure) { + validateFailure(model, request); + } else { + validateEverything(model, request); + } +} + +INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); + sp getPreparedModel_1_2( const sp& callback) { sp preparedModelV1_0 = callback->getPreparedModel(); diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h index e76ad7bc64..8729a6f190 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h @@ -30,6 +30,7 @@ #include #include "1.2/Callbacks.h" +#include "TestHarness.h" namespace android { namespace hardware { @@ -68,24 +69,6 @@ class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase { sp device; }; -class ValidationTest : public NeuralnetworksHidlTest { - protected: - void validateEverything(const Model& model, const Request& request); - void validateFailure(const Model& model, const Request& request); - - private: - void validateModel(const Model& model); - void validateRequest(const sp& preparedModel, const Request& request); - void validateRequestFailure(const sp& preparedModel, const Request& request); - void validateBurst(const sp& preparedModel, const Request& request); -}; - -// Tag for the generated tests -class GeneratedTest : public NeuralnetworksHidlTest {}; - -// Tag for the dynamic output shape tests -class DynamicOutputShapeTest : public NeuralnetworksHidlTest {}; - // Utility function to get PreparedModel from callback and downcast to V1_2. sp getPreparedModel_1_2( const sp& callback); From cbfa6b998e0d88c74597facfbd4ab077f54e0b55 Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Thu, 22 Aug 2019 14:58:16 -0700 Subject: [PATCH 0090/1022] Statically check test enums against HIDL definitions. Fixes: 123092187 Test: mma all VTS Test: Attempt to modify test enum value, confirm that there is build error with proper error message. Change-Id: I0129378c87637b33bb145ec93307634273a9d2fd --- neuralnetworks/1.0/vts/functional/Android.bp | 1 + .../1.0/vts/functional/TestAssertions.cpp | 74 +++++++++ neuralnetworks/1.1/vts/functional/Android.bp | 1 + .../1.1/vts/functional/TestAssertions.cpp | 69 +++++++++ neuralnetworks/1.2/vts/functional/Android.bp | 1 + .../1.2/vts/functional/TestAssertions.cpp | 141 ++++++++++++++++++ 6 files changed, 287 insertions(+) create mode 100644 neuralnetworks/1.0/vts/functional/TestAssertions.cpp create mode 100644 neuralnetworks/1.1/vts/functional/TestAssertions.cpp create mode 100644 neuralnetworks/1.2/vts/functional/TestAssertions.cpp diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp index abff213847..b3f544f5b9 100644 --- a/neuralnetworks/1.0/vts/functional/Android.bp +++ b/neuralnetworks/1.0/vts/functional/Android.bp @@ -44,6 +44,7 @@ cc_defaults { name: "VtsHalNeuralNetworksV1_0TargetTestDefaults", defaults: ["VtsHalTargetTestDefaults"], srcs: [ + "TestAssertions.cpp", "ValidateModel.cpp", "ValidateRequest.cpp", "VtsHalNeuralnetworks.cpp", diff --git a/neuralnetworks/1.0/vts/functional/TestAssertions.cpp b/neuralnetworks/1.0/vts/functional/TestAssertions.cpp new file mode 100644 index 0000000000..8fdc98d4b9 --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/TestAssertions.cpp @@ -0,0 +1,74 @@ +/* + * 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. + */ + +#include +#include "TestHarness.h" + +namespace android::hardware::neuralnetworks::V1_0 { + +// Make sure that the HIDL enums are compatible with the values defined in +// frameworks/ml/nn/tools/test_generator/test_harness/include/TestHarness.h. +using namespace test_helper; +#define CHECK_TEST_ENUM(EnumType, enumValue) \ + static_assert(static_cast(Test##EnumType::enumValue) == EnumType::enumValue) + +CHECK_TEST_ENUM(OperandType, FLOAT32); +CHECK_TEST_ENUM(OperandType, INT32); +CHECK_TEST_ENUM(OperandType, UINT32); +CHECK_TEST_ENUM(OperandType, TENSOR_FLOAT32); +CHECK_TEST_ENUM(OperandType, TENSOR_INT32); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_ASYMM); + +CHECK_TEST_ENUM(OperandLifeTime, TEMPORARY_VARIABLE); +CHECK_TEST_ENUM(OperandLifeTime, MODEL_INPUT); +CHECK_TEST_ENUM(OperandLifeTime, MODEL_OUTPUT); +CHECK_TEST_ENUM(OperandLifeTime, CONSTANT_COPY); +CHECK_TEST_ENUM(OperandLifeTime, CONSTANT_REFERENCE); +CHECK_TEST_ENUM(OperandLifeTime, NO_VALUE); + +CHECK_TEST_ENUM(OperationType, ADD); +CHECK_TEST_ENUM(OperationType, AVERAGE_POOL_2D); +CHECK_TEST_ENUM(OperationType, CONCATENATION); +CHECK_TEST_ENUM(OperationType, CONV_2D); +CHECK_TEST_ENUM(OperationType, DEPTHWISE_CONV_2D); +CHECK_TEST_ENUM(OperationType, DEPTH_TO_SPACE); +CHECK_TEST_ENUM(OperationType, DEQUANTIZE); +CHECK_TEST_ENUM(OperationType, EMBEDDING_LOOKUP); +CHECK_TEST_ENUM(OperationType, FLOOR); +CHECK_TEST_ENUM(OperationType, FULLY_CONNECTED); +CHECK_TEST_ENUM(OperationType, HASHTABLE_LOOKUP); +CHECK_TEST_ENUM(OperationType, L2_NORMALIZATION); +CHECK_TEST_ENUM(OperationType, L2_POOL_2D); +CHECK_TEST_ENUM(OperationType, LOCAL_RESPONSE_NORMALIZATION); +CHECK_TEST_ENUM(OperationType, LOGISTIC); +CHECK_TEST_ENUM(OperationType, LSH_PROJECTION); +CHECK_TEST_ENUM(OperationType, LSTM); +CHECK_TEST_ENUM(OperationType, MAX_POOL_2D); +CHECK_TEST_ENUM(OperationType, MUL); +CHECK_TEST_ENUM(OperationType, RELU); +CHECK_TEST_ENUM(OperationType, RELU1); +CHECK_TEST_ENUM(OperationType, RELU6); +CHECK_TEST_ENUM(OperationType, RESHAPE); +CHECK_TEST_ENUM(OperationType, RESIZE_BILINEAR); +CHECK_TEST_ENUM(OperationType, RNN); +CHECK_TEST_ENUM(OperationType, SOFTMAX); +CHECK_TEST_ENUM(OperationType, SPACE_TO_DEPTH); +CHECK_TEST_ENUM(OperationType, SVDF); +CHECK_TEST_ENUM(OperationType, TANH); + +#undef CHECK_TEST_ENUM + +} // namespace android::hardware::neuralnetworks::V1_0 diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp index 86002d21aa..56e0fb26e3 100644 --- a/neuralnetworks/1.1/vts/functional/Android.bp +++ b/neuralnetworks/1.1/vts/functional/Android.bp @@ -18,6 +18,7 @@ cc_defaults { name: "VtsHalNeuralNetworksV1_1TargetTestDefaults", defaults: ["VtsHalTargetTestDefaults"], srcs: [ + "TestAssertions.cpp", "ValidateModel.cpp", "ValidateRequest.cpp", "VtsHalNeuralnetworks.cpp", diff --git a/neuralnetworks/1.1/vts/functional/TestAssertions.cpp b/neuralnetworks/1.1/vts/functional/TestAssertions.cpp new file mode 100644 index 0000000000..f4a49bcd91 --- /dev/null +++ b/neuralnetworks/1.1/vts/functional/TestAssertions.cpp @@ -0,0 +1,69 @@ +/* + * 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. + */ + +#include +#include "TestHarness.h" + +namespace android::hardware::neuralnetworks::V1_1 { + +// Make sure that the HIDL enums are compatible with the values defined in +// frameworks/ml/nn/tools/test_generator/test_harness/include/TestHarness.h. +using namespace test_helper; +#define CHECK_TEST_ENUM(EnumType, enumValue) \ + static_assert(static_cast(Test##EnumType::enumValue) == EnumType::enumValue) + +CHECK_TEST_ENUM(OperationType, ADD); +CHECK_TEST_ENUM(OperationType, AVERAGE_POOL_2D); +CHECK_TEST_ENUM(OperationType, CONCATENATION); +CHECK_TEST_ENUM(OperationType, CONV_2D); +CHECK_TEST_ENUM(OperationType, DEPTHWISE_CONV_2D); +CHECK_TEST_ENUM(OperationType, DEPTH_TO_SPACE); +CHECK_TEST_ENUM(OperationType, DEQUANTIZE); +CHECK_TEST_ENUM(OperationType, EMBEDDING_LOOKUP); +CHECK_TEST_ENUM(OperationType, FLOOR); +CHECK_TEST_ENUM(OperationType, FULLY_CONNECTED); +CHECK_TEST_ENUM(OperationType, HASHTABLE_LOOKUP); +CHECK_TEST_ENUM(OperationType, L2_NORMALIZATION); +CHECK_TEST_ENUM(OperationType, L2_POOL_2D); +CHECK_TEST_ENUM(OperationType, LOCAL_RESPONSE_NORMALIZATION); +CHECK_TEST_ENUM(OperationType, LOGISTIC); +CHECK_TEST_ENUM(OperationType, LSH_PROJECTION); +CHECK_TEST_ENUM(OperationType, LSTM); +CHECK_TEST_ENUM(OperationType, MAX_POOL_2D); +CHECK_TEST_ENUM(OperationType, MUL); +CHECK_TEST_ENUM(OperationType, RELU); +CHECK_TEST_ENUM(OperationType, RELU1); +CHECK_TEST_ENUM(OperationType, RELU6); +CHECK_TEST_ENUM(OperationType, RESHAPE); +CHECK_TEST_ENUM(OperationType, RESIZE_BILINEAR); +CHECK_TEST_ENUM(OperationType, RNN); +CHECK_TEST_ENUM(OperationType, SOFTMAX); +CHECK_TEST_ENUM(OperationType, SPACE_TO_DEPTH); +CHECK_TEST_ENUM(OperationType, SVDF); +CHECK_TEST_ENUM(OperationType, TANH); +CHECK_TEST_ENUM(OperationType, BATCH_TO_SPACE_ND); +CHECK_TEST_ENUM(OperationType, DIV); +CHECK_TEST_ENUM(OperationType, MEAN); +CHECK_TEST_ENUM(OperationType, PAD); +CHECK_TEST_ENUM(OperationType, SPACE_TO_BATCH_ND); +CHECK_TEST_ENUM(OperationType, SQUEEZE); +CHECK_TEST_ENUM(OperationType, STRIDED_SLICE); +CHECK_TEST_ENUM(OperationType, SUB); +CHECK_TEST_ENUM(OperationType, TRANSPOSE); + +#undef CHECK_TEST_ENUM + +} // namespace android::hardware::neuralnetworks::V1_1 diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index e14430f45d..6a86062cc2 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -18,6 +18,7 @@ cc_defaults { name: "VtsHalNeuralNetworksV1_2TargetTestDefaults", defaults: ["VtsHalTargetTestDefaults"], srcs: [ + "TestAssertions.cpp", "ValidateModel.cpp", "ValidateRequest.cpp", "VtsHalNeuralnetworks.cpp", diff --git a/neuralnetworks/1.2/vts/functional/TestAssertions.cpp b/neuralnetworks/1.2/vts/functional/TestAssertions.cpp new file mode 100644 index 0000000000..a0aa3c37d1 --- /dev/null +++ b/neuralnetworks/1.2/vts/functional/TestAssertions.cpp @@ -0,0 +1,141 @@ +/* + * 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. + */ + +#include +#include "TestHarness.h" + +namespace android::hardware::neuralnetworks::V1_2 { + +// Make sure that the HIDL enums are compatible with the values defined in +// frameworks/ml/nn/tools/test_generator/test_harness/include/TestHarness.h. +using namespace test_helper; +#define CHECK_TEST_ENUM(EnumType, enumValue) \ + static_assert(static_cast(Test##EnumType::enumValue) == EnumType::enumValue) + +CHECK_TEST_ENUM(OperandType, FLOAT32); +CHECK_TEST_ENUM(OperandType, INT32); +CHECK_TEST_ENUM(OperandType, UINT32); +CHECK_TEST_ENUM(OperandType, TENSOR_FLOAT32); +CHECK_TEST_ENUM(OperandType, TENSOR_INT32); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_ASYMM); +CHECK_TEST_ENUM(OperandType, BOOL); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT16_SYMM); +CHECK_TEST_ENUM(OperandType, TENSOR_FLOAT16); +CHECK_TEST_ENUM(OperandType, TENSOR_BOOL8); +CHECK_TEST_ENUM(OperandType, FLOAT16); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_SYMM_PER_CHANNEL); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT16_ASYMM); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_SYMM); + +CHECK_TEST_ENUM(OperationType, ADD); +CHECK_TEST_ENUM(OperationType, AVERAGE_POOL_2D); +CHECK_TEST_ENUM(OperationType, CONCATENATION); +CHECK_TEST_ENUM(OperationType, CONV_2D); +CHECK_TEST_ENUM(OperationType, DEPTHWISE_CONV_2D); +CHECK_TEST_ENUM(OperationType, DEPTH_TO_SPACE); +CHECK_TEST_ENUM(OperationType, DEQUANTIZE); +CHECK_TEST_ENUM(OperationType, EMBEDDING_LOOKUP); +CHECK_TEST_ENUM(OperationType, FLOOR); +CHECK_TEST_ENUM(OperationType, FULLY_CONNECTED); +CHECK_TEST_ENUM(OperationType, HASHTABLE_LOOKUP); +CHECK_TEST_ENUM(OperationType, L2_NORMALIZATION); +CHECK_TEST_ENUM(OperationType, L2_POOL_2D); +CHECK_TEST_ENUM(OperationType, LOCAL_RESPONSE_NORMALIZATION); +CHECK_TEST_ENUM(OperationType, LOGISTIC); +CHECK_TEST_ENUM(OperationType, LSH_PROJECTION); +CHECK_TEST_ENUM(OperationType, LSTM); +CHECK_TEST_ENUM(OperationType, MAX_POOL_2D); +CHECK_TEST_ENUM(OperationType, MUL); +CHECK_TEST_ENUM(OperationType, RELU); +CHECK_TEST_ENUM(OperationType, RELU1); +CHECK_TEST_ENUM(OperationType, RELU6); +CHECK_TEST_ENUM(OperationType, RESHAPE); +CHECK_TEST_ENUM(OperationType, RESIZE_BILINEAR); +CHECK_TEST_ENUM(OperationType, RNN); +CHECK_TEST_ENUM(OperationType, SOFTMAX); +CHECK_TEST_ENUM(OperationType, SPACE_TO_DEPTH); +CHECK_TEST_ENUM(OperationType, SVDF); +CHECK_TEST_ENUM(OperationType, TANH); +CHECK_TEST_ENUM(OperationType, BATCH_TO_SPACE_ND); +CHECK_TEST_ENUM(OperationType, DIV); +CHECK_TEST_ENUM(OperationType, MEAN); +CHECK_TEST_ENUM(OperationType, PAD); +CHECK_TEST_ENUM(OperationType, SPACE_TO_BATCH_ND); +CHECK_TEST_ENUM(OperationType, SQUEEZE); +CHECK_TEST_ENUM(OperationType, STRIDED_SLICE); +CHECK_TEST_ENUM(OperationType, SUB); +CHECK_TEST_ENUM(OperationType, TRANSPOSE); +CHECK_TEST_ENUM(OperationType, ABS); +CHECK_TEST_ENUM(OperationType, ARGMAX); +CHECK_TEST_ENUM(OperationType, ARGMIN); +CHECK_TEST_ENUM(OperationType, AXIS_ALIGNED_BBOX_TRANSFORM); +CHECK_TEST_ENUM(OperationType, BIDIRECTIONAL_SEQUENCE_LSTM); +CHECK_TEST_ENUM(OperationType, BIDIRECTIONAL_SEQUENCE_RNN); +CHECK_TEST_ENUM(OperationType, BOX_WITH_NMS_LIMIT); +CHECK_TEST_ENUM(OperationType, CAST); +CHECK_TEST_ENUM(OperationType, CHANNEL_SHUFFLE); +CHECK_TEST_ENUM(OperationType, DETECTION_POSTPROCESSING); +CHECK_TEST_ENUM(OperationType, EQUAL); +CHECK_TEST_ENUM(OperationType, EXP); +CHECK_TEST_ENUM(OperationType, EXPAND_DIMS); +CHECK_TEST_ENUM(OperationType, GATHER); +CHECK_TEST_ENUM(OperationType, GENERATE_PROPOSALS); +CHECK_TEST_ENUM(OperationType, GREATER); +CHECK_TEST_ENUM(OperationType, GREATER_EQUAL); +CHECK_TEST_ENUM(OperationType, GROUPED_CONV_2D); +CHECK_TEST_ENUM(OperationType, HEATMAP_MAX_KEYPOINT); +CHECK_TEST_ENUM(OperationType, INSTANCE_NORMALIZATION); +CHECK_TEST_ENUM(OperationType, LESS); +CHECK_TEST_ENUM(OperationType, LESS_EQUAL); +CHECK_TEST_ENUM(OperationType, LOG); +CHECK_TEST_ENUM(OperationType, LOGICAL_AND); +CHECK_TEST_ENUM(OperationType, LOGICAL_NOT); +CHECK_TEST_ENUM(OperationType, LOGICAL_OR); +CHECK_TEST_ENUM(OperationType, LOG_SOFTMAX); +CHECK_TEST_ENUM(OperationType, MAXIMUM); +CHECK_TEST_ENUM(OperationType, MINIMUM); +CHECK_TEST_ENUM(OperationType, NEG); +CHECK_TEST_ENUM(OperationType, NOT_EQUAL); +CHECK_TEST_ENUM(OperationType, PAD_V2); +CHECK_TEST_ENUM(OperationType, POW); +CHECK_TEST_ENUM(OperationType, PRELU); +CHECK_TEST_ENUM(OperationType, QUANTIZE); +CHECK_TEST_ENUM(OperationType, QUANTIZED_16BIT_LSTM); +CHECK_TEST_ENUM(OperationType, RANDOM_MULTINOMIAL); +CHECK_TEST_ENUM(OperationType, REDUCE_ALL); +CHECK_TEST_ENUM(OperationType, REDUCE_ANY); +CHECK_TEST_ENUM(OperationType, REDUCE_MAX); +CHECK_TEST_ENUM(OperationType, REDUCE_MIN); +CHECK_TEST_ENUM(OperationType, REDUCE_PROD); +CHECK_TEST_ENUM(OperationType, REDUCE_SUM); +CHECK_TEST_ENUM(OperationType, ROI_ALIGN); +CHECK_TEST_ENUM(OperationType, ROI_POOLING); +CHECK_TEST_ENUM(OperationType, RSQRT); +CHECK_TEST_ENUM(OperationType, SELECT); +CHECK_TEST_ENUM(OperationType, SIN); +CHECK_TEST_ENUM(OperationType, SLICE); +CHECK_TEST_ENUM(OperationType, SPLIT); +CHECK_TEST_ENUM(OperationType, SQRT); +CHECK_TEST_ENUM(OperationType, TILE); +CHECK_TEST_ENUM(OperationType, TOPK_V2); +CHECK_TEST_ENUM(OperationType, TRANSPOSE_CONV_2D); +CHECK_TEST_ENUM(OperationType, UNIDIRECTIONAL_SEQUENCE_LSTM); +CHECK_TEST_ENUM(OperationType, UNIDIRECTIONAL_SEQUENCE_RNN); +CHECK_TEST_ENUM(OperationType, RESIZE_NEAREST_NEIGHBOR); + +#undef CHECK_TEST_ENUM + +} // namespace android::hardware::neuralnetworks::V1_2 From 13d03d5174e460ab37539569183da82be68049ea Mon Sep 17 00:00:00 2001 From: mamik Date: Fri, 16 Aug 2019 13:40:37 -0700 Subject: [PATCH 0091/1022] Rev up vr_hwc to composer@2.3 Fix for issue: "[GSI XR] VrFlinger doesn't work on GSI/MTP845. Making member variables protected instead of private for the 2.3 interface, which is the behavior in the 2.1 interface. "vr_composer_client" needs to access the "mResources" and "mHal" class member to be able to create the ComposerCommandEngine. Bug: 137325030 Bug: 138938154 Bug: 137448042 Test: Built the firmware and ran the dvr_display-test, which passes now. Change-Id: I0f531d4dd6d60a3f2da793f19b4d3ea1eb53930e --- .../utils/hal/include/composer-hal/2.3/ComposerClient.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h index 04530d328e..041fbc80cc 100644 --- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h +++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h @@ -184,18 +184,18 @@ class ComposerClientImpl : public V2_2::hal::detail::ComposerClientImpl; + using BaseType2_1::mHal; + using BaseType2_1::mResources; std::unique_ptr createCommandEngine() override { return std::make_unique( mHal, static_cast(mResources.get())); } - private: + private: using BaseType2_2 = V2_2::hal::detail::ComposerClientImpl; - using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl; using BaseType2_1::mCommandEngine; using BaseType2_1::mCommandEngineMutex; - using BaseType2_1::mHal; - using BaseType2_1::mResources; }; } // namespace detail From c7cdd550a01191898bc11a7711bbcfc4caf7b241 Mon Sep 17 00:00:00 2001 From: David Gross Date: Tue, 27 Aug 2019 12:20:50 -0700 Subject: [PATCH 0092/1022] Fix V1_2::IDevice::getType documentation: was @param instead of @return Bug: 124346013 Test: $ cd neuralnetworks/1.2 ; mma Change-Id: I45d1320a9edae73cde7d9ccaca57b5b9519b0210 --- current.txt | 1 + neuralnetworks/1.2/IDevice.hal | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/current.txt b/current.txt index fbb9752c04..b7383ea18f 100644 --- a/current.txt +++ b/current.txt @@ -574,6 +574,7 @@ cfa81f229b69f9011c58f48264fcb552447430fe68610eac514e811e65bc306a android.hardwar # ABI preserving changes to HALs during Android R b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice ad431c8de51c07934a068e3043d8dd0537ac4d3158627706628b123f42df48dc android.hardware.neuralnetworks@1.0::IPreparedModel +fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice aafcc10cf04ab247e86d4582586c71c6b4c2b8c479241ffa7fe37deb659fc942 android.hardware.neuralnetworks@1.2::IPreparedModel 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface diff --git a/neuralnetworks/1.2/IDevice.hal b/neuralnetworks/1.2/IDevice.hal index d83f9e6758..ff20c12867 100644 --- a/neuralnetworks/1.2/IDevice.hal +++ b/neuralnetworks/1.2/IDevice.hal @@ -64,14 +64,14 @@ interface IDevice extends @1.1::IDevice { * results, the developer could choose an ACCELERATOR type device for ML * workloads, and reserve GPU for graphical rendering. * - * @param status Error status returned from querying the device type. Must be: - * - NONE if the query was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if the query resulted in an - * unspecified error - * @param type The DeviceType of the device. Please note, this is not a - * bitfield of DeviceTypes. Each device must only be of a - * single DeviceType. + * @return status Error status returned from querying the device type. Must be: + * - NONE if the query was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the query resulted in an + * unspecified error + * @return type The DeviceType of the device. Please note, this is not a + * bitfield of DeviceTypes. Each device must only be of a + * single DeviceType. */ getType() generates (ErrorStatus status, DeviceType type); From f7a8f03e3db0d3170a9e858f326c79c70c3ed44a Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Fri, 23 Aug 2019 16:17:01 -0700 Subject: [PATCH 0093/1022] Change NNAPI VTS to use static library This CL also adds Compilation Caching tests to the Presubmit tests, which were missing configuration files before. Bug: 139889855 Test: mma Test: VtsHalNeuralnetworksV1_*TargetTest (with sample-all) Test: VtsHalNeuralnetworksV1_*CompatV1_*TargetTest (with sample-all) Change-Id: I65274b5f72def815ff238a8d8df10c9d014afc44 --- neuralnetworks/1.0/vts/functional/Android.bp | 8 ++++++-- neuralnetworks/1.1/vts/functional/Android.bp | 12 ++++++++---- neuralnetworks/1.2/vts/functional/Android.bp | 18 ++++++++++++++---- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp index 664436c8bc..9e3d97bd34 100644 --- a/neuralnetworks/1.0/vts/functional/Android.bp +++ b/neuralnetworks/1.0/vts/functional/Android.bp @@ -74,7 +74,9 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_0TargetTestDefaults"], srcs: [ "BasicTests.cpp", - ":VtsHalNeuralNetworksV1_0_all_generated_tests", + ], + whole_static_libs: [ + "neuralnetworks_generated_V1_0_example", ], } @@ -83,7 +85,9 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_0TargetTestDefaults"], srcs: [ "BasicTests.cpp", - ":VtsHalNeuralNetworksV1_0_all_generated_tests", + ], + whole_static_libs: [ + "neuralnetworks_generated_V1_0_example", ], cflags: [ "-DPRESUBMIT_NOT_VTS", diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp index 05c7f6bfff..8603b4b1dd 100644 --- a/neuralnetworks/1.1/vts/functional/Android.bp +++ b/neuralnetworks/1.1/vts/functional/Android.bp @@ -48,8 +48,8 @@ cc_defaults { cc_test { name: "VtsHalNeuralnetworksV1_1CompatV1_0TargetTest", defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"], - srcs: [ - ":VtsHalNeuralNetworksV1_0_all_generated_tests", + whole_static_libs: [ + "neuralnetworks_generated_V1_0_example", ], } @@ -59,7 +59,9 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"], srcs: [ "BasicTests.cpp", - ":VtsHalNeuralNetworksV1_1_all_generated_tests", + ], + whole_static_libs: [ + "neuralnetworks_generated_V1_1_example", ], } @@ -68,7 +70,9 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"], srcs: [ "BasicTests.cpp", - ":VtsHalNeuralNetworksV1_1_all_generated_tests", + ], + whole_static_libs: [ + "neuralnetworks_generated_V1_1_example", ], cflags: [ "-DPRESUBMIT_NOT_VTS", diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index 7f2e11098d..acbd92d377 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -52,9 +52,11 @@ cc_test { name: "VtsHalNeuralnetworksV1_2CompatV1_0TargetTest", defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ - ":VtsHalNeuralNetworksV1_0_all_generated_tests", "ValidateBurst.cpp", ], + whole_static_libs: [ + "neuralnetworks_generated_V1_0_example", + ], } // Tests for V1_1 models using the V1_2 HAL. @@ -62,9 +64,11 @@ cc_test { name: "VtsHalNeuralnetworksV1_2CompatV1_1TargetTest", defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ - ":VtsHalNeuralNetworksV1_1_all_generated_tests", "ValidateBurst.cpp", ], + whole_static_libs: [ + "neuralnetworks_generated_V1_1_example", + ], } // Tests for V1_2 models. @@ -73,11 +77,13 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ "BasicTests.cpp", - ":VtsHalNeuralNetworksV1_2_all_generated_tests", ":VtsHalNeuralNetworksV1_2_mobilenets", "CompilationCachingTests.cpp", "ValidateBurst.cpp", ], + whole_static_libs: [ + "neuralnetworks_generated_V1_2_example", + ], } cc_test { @@ -85,9 +91,13 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ "BasicTests.cpp", - ":VtsHalNeuralNetworksV1_2_all_generated_tests", + ":VtsHalNeuralNetworksV1_2_mobilenets", + "CompilationCachingTests.cpp", "ValidateBurst.cpp", ], + whole_static_libs: [ + "neuralnetworks_generated_V1_2_example", + ], cflags: [ "-DPRESUBMIT_NOT_VTS", ], From 72227f3ef8b89625e137a24a6d1be8139eb1c049 Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Mon, 26 Aug 2019 22:25:40 -0700 Subject: [PATCH 0094/1022] NNAPI Combine Compatability test with VTS test Bug: 139889855 Fixes: 140120312 Test: mma Test: VtsHalNeuralnetworksV1_*TargetTest (with sample-all) Change-Id: Ib93d159dc657eaf292d16140ebdd9de3b0f5f1d3 --- neuralnetworks/1.1/vts/functional/Android.bp | 12 ++------ neuralnetworks/1.2/vts/functional/Android.bp | 31 +++----------------- 2 files changed, 6 insertions(+), 37 deletions(-) diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp index 23c47c831d..c197e6de66 100644 --- a/neuralnetworks/1.1/vts/functional/Android.bp +++ b/neuralnetworks/1.1/vts/functional/Android.bp @@ -45,16 +45,6 @@ cc_defaults { test_suites: ["general-tests"], } -// Tests for V1_0 models using the V1_1 HAL. -cc_test { - name: "VtsHalNeuralnetworksV1_1CompatV1_0TargetTest", - defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"], - whole_static_libs: [ - "neuralnetworks_generated_V1_0_example", - ], -} - -// Tests for V1_1 models. cc_test { name: "VtsHalNeuralnetworksV1_1TargetTest", defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"], @@ -62,6 +52,7 @@ cc_test { "BasicTests.cpp", ], whole_static_libs: [ + "neuralnetworks_generated_V1_0_example", "neuralnetworks_generated_V1_1_example", ], } @@ -73,6 +64,7 @@ cc_test { "BasicTests.cpp", ], whole_static_libs: [ + "neuralnetworks_generated_V1_0_example", "neuralnetworks_generated_V1_1_example", ], cflags: [ diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index 1c1b8051c3..40ca809612 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -48,41 +48,17 @@ cc_defaults { test_suites: ["general-tests"], } -// Tests for V1_0 models using the V1_2 HAL. -cc_test { - name: "VtsHalNeuralnetworksV1_2CompatV1_0TargetTest", - defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], - srcs: [ - "ValidateBurst.cpp", - ], - whole_static_libs: [ - "neuralnetworks_generated_V1_0_example", - ], -} - -// Tests for V1_1 models using the V1_2 HAL. -cc_test { - name: "VtsHalNeuralnetworksV1_2CompatV1_1TargetTest", - defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], - srcs: [ - "ValidateBurst.cpp", - ], - whole_static_libs: [ - "neuralnetworks_generated_V1_1_example", - ], -} - -// Tests for V1_2 models. cc_test { name: "VtsHalNeuralnetworksV1_2TargetTest", defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ "BasicTests.cpp", - ":VtsHalNeuralNetworksV1_2_mobilenets", "CompilationCachingTests.cpp", "ValidateBurst.cpp", ], whole_static_libs: [ + "neuralnetworks_generated_V1_0_example", + "neuralnetworks_generated_V1_1_example", "neuralnetworks_generated_V1_2_example", ], } @@ -92,11 +68,12 @@ cc_test { defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], srcs: [ "BasicTests.cpp", - ":VtsHalNeuralNetworksV1_2_mobilenets", "CompilationCachingTests.cpp", "ValidateBurst.cpp", ], whole_static_libs: [ + "neuralnetworks_generated_V1_0_example", + "neuralnetworks_generated_V1_1_example", "neuralnetworks_generated_V1_2_example", ], cflags: [ From bbe5dad26674e8fac9570f52814571f626f09a3b Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Mon, 26 Aug 2019 23:55:47 -0700 Subject: [PATCH 0095/1022] Cleanup NNAPI VTS tests This CL includes the following cleanups: * namespace compression * remove "using" from header files * remove no-op code, default no-op constructors * clang-formats the code Bug: N/A Test: mma Test: VtsHalNeuralnetworksV1_*TargetTest Change-Id: I023997d8686ca65223858eed3a0881f5444ed2d6 --- .../1.0/vts/functional/BasicTests.cpp | 28 +++----- .../vts/functional/GeneratedTestHarness.cpp | 26 ++------ .../1.0/vts/functional/GeneratedTestHarness.h | 14 +--- neuralnetworks/1.0/vts/functional/Utils.cpp | 16 ++--- .../1.0/vts/functional/ValidateModel.cpp | 66 ++++++++----------- .../1.0/vts/functional/ValidateRequest.cpp | 17 +---- .../vts/functional/VtsHalNeuralnetworks.cpp | 36 ++-------- .../1.0/vts/functional/VtsHalNeuralnetworks.h | 29 +++----- .../1.0/vts/functional/include/1.0/Utils.h | 18 ++--- .../1.1/vts/functional/BasicTests.cpp | 35 ++++------ .../vts/functional/GeneratedTestHarness.cpp | 38 ++++------- .../1.1/vts/functional/GeneratedTestHarness.h | 19 ++---- .../1.1/vts/functional/ValidateModel.cpp | 31 ++++----- .../1.1/vts/functional/ValidateRequest.cpp | 23 ++----- .../vts/functional/VtsHalNeuralnetworks.cpp | 33 ++-------- .../1.1/vts/functional/VtsHalNeuralnetworks.h | 37 +++-------- .../1.2/vts/functional/BasicTests.cpp | 16 ++--- .../1.2/vts/functional/Callbacks.cpp | 2 + .../functional/CompilationCachingTests.cpp | 39 ++++------- .../vts/functional/GeneratedTestHarness.cpp | 38 +++-------- .../1.2/vts/functional/GeneratedTestHarness.h | 30 +++------ .../1.2/vts/functional/ValidateBurst.cpp | 24 +++---- .../1.2/vts/functional/ValidateModel.cpp | 26 ++------ .../1.2/vts/functional/ValidateRequest.cpp | 19 ++---- .../vts/functional/VtsHalNeuralnetworks.cpp | 35 ++-------- .../1.2/vts/functional/VtsHalNeuralnetworks.h | 31 ++------- .../vts/functional/include/1.2/Callbacks.h | 23 ++++--- 27 files changed, 220 insertions(+), 529 deletions(-) diff --git a/neuralnetworks/1.0/vts/functional/BasicTests.cpp b/neuralnetworks/1.0/vts/functional/BasicTests.cpp index 945c4065e5..5727ca4034 100644 --- a/neuralnetworks/1.0/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.0/vts/functional/BasicTests.cpp @@ -18,12 +18,7 @@ #include "VtsHalNeuralnetworks.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_0 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_0::vts::functional { // create device test TEST_F(NeuralnetworksHidlTest, CreateDevice) {} @@ -38,19 +33,14 @@ TEST_F(NeuralnetworksHidlTest, StatusTest) { // initialization TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) { Return ret = - device->getCapabilities([](ErrorStatus status, const Capabilities& capabilities) { - EXPECT_EQ(ErrorStatus::NONE, status); - EXPECT_LT(0.0f, capabilities.float32Performance.execTime); - EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage); - EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime); - EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage); - }); + device->getCapabilities([](ErrorStatus status, const Capabilities& capabilities) { + EXPECT_EQ(ErrorStatus::NONE, status); + EXPECT_LT(0.0f, capabilities.float32Performance.execTime); + EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage); + EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime); + EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage); + }); EXPECT_TRUE(ret.isOk()); } -} // namespace functional -} // namespace vts -} // namespace V1_0 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_0::vts::functional diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp index 5f96539fc4..33a6fa5d6a 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp @@ -33,23 +33,12 @@ #include #include -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_0 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_0::vts::functional { using namespace test_helper; -using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; -using ::android::hardware::neuralnetworks::V1_0::IDevice; -using ::android::hardware::neuralnetworks::V1_0::IPreparedModel; -using ::android::hardware::neuralnetworks::V1_0::Model; -using ::android::hardware::neuralnetworks::V1_0::Request; -using ::android::hardware::neuralnetworks::V1_0::RequestArgument; -using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; -using ::android::hidl::memory::V1_0::IMemory; +using hidl::memory::V1_0::IMemory; +using implementation::ExecutionCallback; +using implementation::PreparedModelCallback; Model createModel(const TestModel& testModel) { // Model operands. @@ -206,9 +195,4 @@ TEST_P(GeneratedTest, Test) { INSTANTIATE_GENERATED_TEST(GeneratedTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); -} // namespace functional -} // namespace vts -} // namespace V1_0 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_0::vts::functional diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h index f86e8b3e72..a42f271cad 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h @@ -21,12 +21,7 @@ #include "TestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_0 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_0::vts::functional { class GeneratedTestBase : public NeuralnetworksHidlTest, @@ -59,11 +54,6 @@ class ValidationTest : public GeneratedTestBase { Model createModel(const ::test_helper::TestModel& testModel); -} // namespace functional -} // namespace vts -} // namespace V1_0 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_0::vts::functional #endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_GENERATED_TEST_HARNESS_H diff --git a/neuralnetworks/1.0/vts/functional/Utils.cpp b/neuralnetworks/1.0/vts/functional/Utils.cpp index 5aa27516db..5de99fd0b3 100644 --- a/neuralnetworks/1.0/vts/functional/Utils.cpp +++ b/neuralnetworks/1.0/vts/functional/Utils.cpp @@ -28,15 +28,13 @@ #include #include -namespace android { -namespace hardware { -namespace neuralnetworks { +namespace android::hardware::neuralnetworks { using namespace test_helper; -using ::android::hardware::neuralnetworks::V1_0::DataLocation; -using ::android::hardware::neuralnetworks::V1_0::Request; -using ::android::hardware::neuralnetworks::V1_0::RequestArgument; -using ::android::hidl::memory::V1_0::IMemory; +using hidl::memory::V1_0::IMemory; +using V1_0::DataLocation; +using V1_0::Request; +using V1_0::RequestArgument; constexpr uint32_t kInputPoolIndex = 0; constexpr uint32_t kOutputPoolIndex = 1; @@ -118,6 +116,4 @@ std::vector getOutputBuffers(const Request& request) { return outputBuffers; } -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks diff --git a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp index 5845aabe70..9854395084 100644 --- a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp @@ -20,15 +20,9 @@ #include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_0 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_0::vts::functional { -using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; +using implementation::PreparedModelCallback; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// @@ -37,9 +31,9 @@ static void validateGetSupportedOperations(const sp& device, const std: SCOPED_TRACE(message + " [getSupportedOperations]"); Return ret = - device->getSupportedOperations(model, [&](ErrorStatus status, const hidl_vec&) { - EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); - }); + device->getSupportedOperations(model, [&](ErrorStatus status, const hidl_vec&) { + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); + }); EXPECT_TRUE(ret.isOk()); } @@ -48,7 +42,6 @@ static void validatePrepareModel(const sp& device, const std::string& m SCOPED_TRACE(message + " [prepareModel]"); sp preparedModelCallback = new PreparedModelCallback(); - ASSERT_NE(nullptr, preparedModelCallback.get()); Return prepareLaunchStatus = device->prepareModel(model, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(prepareLaunchStatus)); @@ -94,13 +87,13 @@ static uint32_t hidl_vec_push_back(hidl_vec* vec, const Type& value) { static uint32_t addOperand(Model* model) { return hidl_vec_push_back(&model->operands, { - .type = OperandType::INT32, - .dimensions = {}, - .numberOfConsumers = 0, - .scale = 0.0f, - .zeroPoint = 0, - .lifetime = OperandLifeTime::MODEL_INPUT, - .location = {.poolIndex = 0, .offset = 0, .length = 0}, + .type = OperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 0, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, }); } @@ -114,10 +107,10 @@ static uint32_t addOperand(Model* model, OperandLifeTime lifetime) { ///////////////////////// VALIDATE MODEL OPERAND TYPE ///////////////////////// static const int32_t invalidOperandTypes[] = { - static_cast(OperandType::FLOAT32) - 1, // lower bound fundamental - static_cast(OperandType::TENSOR_QUANT8_ASYMM) + 1, // upper bound fundamental - static_cast(OperandType::OEM) - 1, // lower bound OEM - static_cast(OperandType::TENSOR_OEM_BYTE) + 1, // upper bound OEM + static_cast(OperandType::FLOAT32) - 1, // lower bound fundamental + static_cast(OperandType::TENSOR_QUANT8_ASYMM) + 1, // upper bound fundamental + static_cast(OperandType::OEM) - 1, // lower bound OEM + static_cast(OperandType::TENSOR_OEM_BYTE) + 1, // upper bound OEM }; static void mutateOperandTypeTest(const sp& device, const V1_0::Model& model) { @@ -210,7 +203,7 @@ static std::vector getInvalidZeroPoints(OperandType type) { static void mutateOperandZeroPointTest(const sp& device, const V1_0::Model& model) { for (size_t operand = 0; operand < model.operands.size(); ++operand) { const std::vector invalidZeroPoints = - getInvalidZeroPoints(model.operands[operand].type); + getInvalidZeroPoints(model.operands[operand].type); for (int32_t invalidZeroPoint : invalidZeroPoints) { const std::string message = "mutateOperandZeroPointTest: operand " + std::to_string(operand) + " has zero point of " + @@ -242,18 +235,18 @@ static void mutateOperand(Operand* operand, OperandType type) { break; case OperandType::TENSOR_FLOAT32: newOperand.dimensions = - operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); newOperand.scale = 0.0f; newOperand.zeroPoint = 0; break; case OperandType::TENSOR_INT32: newOperand.dimensions = - operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); newOperand.zeroPoint = 0; break; case OperandType::TENSOR_QUANT8_ASYMM: newOperand.dimensions = - operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f; break; case OperandType::OEM: @@ -303,10 +296,10 @@ static void mutateOperationOperandTypeTest(const sp& device, const V1_0 ///////////////////////// VALIDATE MODEL OPERATION TYPE ///////////////////////// static const int32_t invalidOperationTypes[] = { - static_cast(OperationType::ADD) - 1, // lower bound fundamental - static_cast(OperationType::TANH) + 1, // upper bound fundamental - static_cast(OperationType::OEM_OPERATION) - 1, // lower bound OEM - static_cast(OperationType::OEM_OPERATION) + 1, // upper bound OEM + static_cast(OperationType::ADD) - 1, // lower bound fundamental + static_cast(OperationType::TANH) + 1, // upper bound fundamental + static_cast(OperationType::OEM_OPERATION) - 1, // lower bound OEM + static_cast(OperationType::OEM_OPERATION) + 1, // upper bound OEM }; static void mutateOperationTypeTest(const sp& device, const V1_0::Model& model) { @@ -317,7 +310,7 @@ static void mutateOperationTypeTest(const sp& device, const V1_0::Model std::to_string(invalidOperationType); validate(device, message, model, [operation, invalidOperationType](Model* model) { model->operations[operation].type = - static_cast(invalidOperationType); + static_cast(invalidOperationType); }); } } @@ -470,7 +463,7 @@ static void addOperationInputTest(const sp& device, const V1_0::Model& static void addOperationOutputTest(const sp& device, const V1_0::Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { const std::string message = - "addOperationOutputTest: operation " + std::to_string(operation); + "addOperationOutputTest: operation " + std::to_string(operation); validate(device, message, model, [operation](Model* model) { uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT); hidl_vec_push_back(&model->operations[operation].outputs, index); @@ -498,9 +491,4 @@ void ValidationTest::validateModel(const V1_0::Model& model) { addOperationOutputTest(device, model); } -} // namespace functional -} // namespace vts -} // namespace V1_0 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_0::vts::functional diff --git a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp index 730e054757..d8f3e65e8c 100644 --- a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp @@ -20,14 +20,9 @@ #include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_0 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_0::vts::functional { -using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; +using implementation::ExecutionCallback; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// @@ -41,7 +36,6 @@ static void validate(const sp& preparedModel, const std::string& SCOPED_TRACE(message + " [execute]"); sp executionCallback = new ExecutionCallback(); - ASSERT_NE(nullptr, executionCallback.get()); Return executeLaunchStatus = preparedModel->execute(request, executionCallback); ASSERT_TRUE(executeLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(executeLaunchStatus)); @@ -99,9 +93,4 @@ void ValidationTest::validateRequest(const sp& preparedModel, removeOutputTest(preparedModel, request); } -} // namespace functional -} // namespace vts -} // namespace V1_0 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_0::vts::functional diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp index a51f71f8c6..9ee4e37cb0 100644 --- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp @@ -24,16 +24,11 @@ #include -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_0 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_0::vts::functional { -using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; +using implementation::PreparedModelCallback; -static void createPreparedModel(const sp& device, const V1_0::Model& model, +static void createPreparedModel(const sp& device, const Model& model, sp* preparedModel) { ASSERT_NE(nullptr, preparedModel); @@ -50,7 +45,6 @@ static void createPreparedModel(const sp& device, const V1_0::Model& mo // launch prepare model sp preparedModelCallback = new PreparedModelCallback(); - ASSERT_NE(nullptr, preparedModelCallback.get()); Return prepareLaunchStatus = device->prepareModel(model, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); @@ -81,10 +75,6 @@ static void createPreparedModel(const sp& device, const V1_0::Model& mo } // A class for test environment setup -NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {} - -NeuralnetworksHidlEnvironment::~NeuralnetworksHidlEnvironment() {} - NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() { // This has to return a "new" object because it is freed inside // ::testing::AddGlobalTestEnvironment when the gtest is being torn down @@ -97,14 +87,8 @@ void NeuralnetworksHidlEnvironment::registerTestServices() { } // The main test class for NEURALNETWORK HIDL HAL. -NeuralnetworksHidlTest::NeuralnetworksHidlTest() {} - -NeuralnetworksHidlTest::~NeuralnetworksHidlTest() {} - void NeuralnetworksHidlTest::SetUp() { ::testing::VtsHalHidlTargetTestBase::SetUp(); - device = ::testing::VtsHalHidlTargetTestBase::getService( - NeuralnetworksHidlEnvironment::getInstance()); #ifdef PRESUBMIT_NOT_VTS const std::string name = @@ -119,7 +103,6 @@ void NeuralnetworksHidlTest::SetUp() { } void NeuralnetworksHidlTest::TearDown() { - device = nullptr; ::testing::VtsHalHidlTargetTestBase::TearDown(); } @@ -128,10 +111,8 @@ void ValidationTest::validateEverything(const Model& model, const Request& reque // create IPreparedModel sp preparedModel; - ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel)); - if (preparedModel == nullptr) { - return; - } + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; validateRequest(preparedModel, request); } @@ -145,12 +126,7 @@ TEST_P(ValidationTest, Test) { INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); -} // namespace functional -} // namespace vts -} // namespace V1_0 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_0::vts::functional namespace android::hardware::neuralnetworks::V1_0 { diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h index 9638a0e667..fa9ad3b3c1 100644 --- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h @@ -30,20 +30,14 @@ #include "TestHarness.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_0 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_0::vts::functional { // A class for test environment setup class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment); - NeuralnetworksHidlEnvironment(); - ~NeuralnetworksHidlEnvironment() override; + NeuralnetworksHidlEnvironment() = default; - public: + public: static NeuralnetworksHidlEnvironment* getInstance(); void registerTestServices() override; }; @@ -52,22 +46,17 @@ class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvB class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase { DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest); - public: - NeuralnetworksHidlTest(); - ~NeuralnetworksHidlTest() override; + public: + NeuralnetworksHidlTest() = default; void SetUp() override; void TearDown() override; - protected: - sp device; + protected: + const sp device = ::testing::VtsHalHidlTargetTestBase::getService( + NeuralnetworksHidlEnvironment::getInstance()); }; -} // namespace functional -} // namespace vts -} // namespace V1_0 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_0::vts::functional namespace android::hardware::neuralnetworks::V1_0 { diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h index 2955b6e35c..274cb584ea 100644 --- a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h +++ b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h @@ -17,14 +17,13 @@ #ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H #define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H +#include #include #include #include #include "TestHarness.h" -namespace android { -namespace hardware { -namespace neuralnetworks { +namespace android::hardware::neuralnetworks { // Create HIDL Request from the TestModel struct. V1_0::Request createRequest(const ::test_helper::TestModel& testModel); @@ -37,23 +36,20 @@ std::vector<::test_helper::TestBuffer> getOutputBuffers(const V1_0::Request& req // resizing the hidl_vec to one less. template inline void hidl_vec_removeAt(hidl_vec* vec, uint32_t index) { - if (vec) { - std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end()); - vec->resize(vec->size() - 1); - } + CHECK(vec != nullptr); + std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end()); + vec->resize(vec->size() - 1); } template inline uint32_t hidl_vec_push_back(hidl_vec* vec, const Type& value) { - // assume vec is valid + CHECK(vec != nullptr); const uint32_t index = vec->size(); vec->resize(index + 1); (*vec)[index] = value; return index; } -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks #endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H diff --git a/neuralnetworks/1.1/vts/functional/BasicTests.cpp b/neuralnetworks/1.1/vts/functional/BasicTests.cpp index ed59a2dd8c..c239c510fd 100644 --- a/neuralnetworks/1.1/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.1/vts/functional/BasicTests.cpp @@ -18,12 +18,10 @@ #include "VtsHalNeuralnetworks.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_1 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_1::vts::functional { + +using V1_0::DeviceStatus; +using V1_0::ErrorStatus; // create device test TEST_F(NeuralnetworksHidlTest, CreateDevice) {} @@ -38,21 +36,16 @@ TEST_F(NeuralnetworksHidlTest, StatusTest) { // initialization TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) { Return ret = - device->getCapabilities_1_1([](ErrorStatus status, const Capabilities& capabilities) { - EXPECT_EQ(ErrorStatus::NONE, status); - EXPECT_LT(0.0f, capabilities.float32Performance.execTime); - EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage); - EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime); - EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage); - EXPECT_LT(0.0f, capabilities.relaxedFloat32toFloat16Performance.execTime); - EXPECT_LT(0.0f, capabilities.relaxedFloat32toFloat16Performance.powerUsage); - }); + device->getCapabilities_1_1([](ErrorStatus status, const Capabilities& capabilities) { + EXPECT_EQ(ErrorStatus::NONE, status); + EXPECT_LT(0.0f, capabilities.float32Performance.execTime); + EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage); + EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime); + EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage); + EXPECT_LT(0.0f, capabilities.relaxedFloat32toFloat16Performance.execTime); + EXPECT_LT(0.0f, capabilities.relaxedFloat32toFloat16Performance.powerUsage); + }); EXPECT_TRUE(ret.isOk()); } -} // namespace functional -} // namespace vts -} // namespace V1_1 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_1::vts::functional diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp index d8d1a31ac4..6ed5bc1274 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp @@ -33,28 +33,19 @@ #include "TestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_1 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_1::vts::functional { using namespace test_helper; -using ::android::hardware::neuralnetworks::V1_0::DataLocation; -using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; -using ::android::hardware::neuralnetworks::V1_0::IPreparedModel; -using ::android::hardware::neuralnetworks::V1_0::Operand; -using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; -using ::android::hardware::neuralnetworks::V1_0::OperandType; -using ::android::hardware::neuralnetworks::V1_0::Request; -using ::android::hardware::neuralnetworks::V1_0::RequestArgument; -using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; -using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference; -using ::android::hardware::neuralnetworks::V1_1::IDevice; -using ::android::hardware::neuralnetworks::V1_1::Model; -using ::android::hidl::memory::V1_0::IMemory; +using hidl::memory::V1_0::IMemory; +using V1_0::DataLocation; +using V1_0::ErrorStatus; +using V1_0::IPreparedModel; +using V1_0::Operand; +using V1_0::OperandLifeTime; +using V1_0::OperandType; +using V1_0::Request; +using V1_0::implementation::ExecutionCallback; +using V1_0::implementation::PreparedModelCallback; Model createModel(const TestModel& testModel) { // Model operands. @@ -212,9 +203,4 @@ TEST_P(GeneratedTest, Test) { INSTANTIATE_GENERATED_TEST(GeneratedTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); -} // namespace functional -} // namespace vts -} // namespace V1_1 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_1::vts::functional diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h index 82fc55148a..7cb9bdce2c 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h @@ -21,12 +21,7 @@ #include "TestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_1 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_1::vts::functional { class GeneratedTestBase : public NeuralnetworksHidlTest, @@ -50,20 +45,16 @@ class GeneratedTestBase // TODO: Clean up the hierarchy for ValidationTest. class ValidationTest : public GeneratedTestBase { protected: - void validateEverything(const Model& model, const Request& request); + void validateEverything(const Model& model, const V1_0::Request& request); private: void validateModel(const Model& model); - void validateRequest(const sp& preparedModel, const Request& request); + void validateRequest(const sp& preparedModel, + const V1_0::Request& request); }; Model createModel(const ::test_helper::TestModel& testModel); -} // namespace functional -} // namespace vts -} // namespace V1_1 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_1::vts::functional #endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_1_GENERATED_TEST_HARNESS_H diff --git a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp index d20dcd0aeb..e617219480 100644 --- a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp @@ -21,18 +21,14 @@ #include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_1 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_1::vts::functional { -using ::android::hardware::neuralnetworks::V1_0::IPreparedModel; -using ::android::hardware::neuralnetworks::V1_0::Operand; -using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; -using ::android::hardware::neuralnetworks::V1_0::OperandType; -using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; +using V1_0::ErrorStatus; +using V1_0::IPreparedModel; +using V1_0::Operand; +using V1_0::OperandLifeTime; +using V1_0::OperandType; +using V1_0::implementation::PreparedModelCallback; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// @@ -52,7 +48,6 @@ static void validatePrepareModel(const sp& device, const std::string& m SCOPED_TRACE(message + " [prepareModel_1_1]"); sp preparedModelCallback = new PreparedModelCallback(); - ASSERT_NE(nullptr, preparedModelCallback.get()); Return prepareLaunchStatus = device->prepareModel_1_1(model, preference, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); @@ -484,8 +479,9 @@ static void mutateExecutionPreferenceTest(const sp& device, const V1_1: for (int32_t preference : invalidExecutionPreferences) { const std::string message = "mutateExecutionPreferenceTest: preference " + std::to_string(preference); - validate(device, message, model, [](Model*) {}, - static_cast(preference)); + validate( + device, message, model, [](Model*) {}, + static_cast(preference)); } } @@ -509,9 +505,4 @@ void ValidationTest::validateModel(const V1_1::Model& model) { mutateExecutionPreferenceTest(device, model); } -} // namespace functional -} // namespace vts -} // namespace V1_1 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_1::vts::functional diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp index e0710f119e..a4e4ade84f 100644 --- a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp @@ -21,17 +21,12 @@ #include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_1 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_1::vts::functional { -using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; -using ::android::hardware::neuralnetworks::V1_0::Request; -using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_1::IPreparedModel; +using V1_0::ErrorStatus; +using V1_0::IPreparedModel; +using V1_0::Request; +using V1_0::implementation::ExecutionCallback; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// @@ -45,7 +40,6 @@ static void validate(const sp& preparedModel, const std::string& SCOPED_TRACE(message + " [execute]"); sp executionCallback = new ExecutionCallback(); - ASSERT_NE(nullptr, executionCallback.get()); Return executeLaunchStatus = preparedModel->execute(request, executionCallback); ASSERT_TRUE(executeLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(executeLaunchStatus)); @@ -83,9 +77,4 @@ void ValidationTest::validateRequest(const sp& preparedModel, removeOutputTest(preparedModel, request); } -} // namespace functional -} // namespace vts -} // namespace V1_1 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_1::vts::functional diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp index 9a11b10b49..2c1a839cc9 100644 --- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp @@ -24,16 +24,14 @@ #include -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_1 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_1::vts::functional { -using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; +using V1_0::ErrorStatus; +using V1_0::IPreparedModel; +using V1_0::Request; +using V1_0::implementation::PreparedModelCallback; -static void createPreparedModel(const sp& device, const V1_1::Model& model, +static void createPreparedModel(const sp& device, const Model& model, sp* preparedModel) { ASSERT_NE(nullptr, preparedModel); @@ -50,7 +48,6 @@ static void createPreparedModel(const sp& device, const V1_1::Model& mo // launch prepare model sp preparedModelCallback = new PreparedModelCallback(); - ASSERT_NE(nullptr, preparedModelCallback.get()); Return prepareLaunchStatus = device->prepareModel_1_1( model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); @@ -82,10 +79,6 @@ static void createPreparedModel(const sp& device, const V1_1::Model& mo } // A class for test environment setup -NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {} - -NeuralnetworksHidlEnvironment::~NeuralnetworksHidlEnvironment() {} - NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() { // This has to return a "new" object because it is freed inside // ::testing::AddGlobalTestEnvironment when the gtest is being torn down @@ -98,14 +91,8 @@ void NeuralnetworksHidlEnvironment::registerTestServices() { } // The main test class for NEURALNETWORK HIDL HAL. -NeuralnetworksHidlTest::NeuralnetworksHidlTest() {} - -NeuralnetworksHidlTest::~NeuralnetworksHidlTest() {} - void NeuralnetworksHidlTest::SetUp() { ::testing::VtsHalHidlTargetTestBase::SetUp(); - device = ::testing::VtsHalHidlTargetTestBase::getService( - NeuralnetworksHidlEnvironment::getInstance()); #ifdef PRESUBMIT_NOT_VTS const std::string name = @@ -120,7 +107,6 @@ void NeuralnetworksHidlTest::SetUp() { } void NeuralnetworksHidlTest::TearDown() { - device = nullptr; ::testing::VtsHalHidlTargetTestBase::TearDown(); } @@ -146,12 +132,7 @@ TEST_P(ValidationTest, Test) { INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); -} // namespace functional -} // namespace vts -} // namespace V1_1 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_1::vts::functional namespace android::hardware::neuralnetworks::V1_0 { diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h index 8d44deb21b..3d6f2eab6f 100644 --- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h @@ -31,28 +31,14 @@ #include "TestHarness.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_1 { - -using V1_0::DeviceStatus; -using V1_0::ErrorStatus; -using V1_0::IPreparedModel; -using V1_0::Operand; -using V1_0::OperandType; -using V1_0::Request; - -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_1::vts::functional { // A class for test environment setup class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment); - NeuralnetworksHidlEnvironment(); - ~NeuralnetworksHidlEnvironment() override; + NeuralnetworksHidlEnvironment() = default; - public: + public: static NeuralnetworksHidlEnvironment* getInstance(); void registerTestServices() override; }; @@ -61,22 +47,17 @@ class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvB class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase { DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest); - public: - NeuralnetworksHidlTest(); - ~NeuralnetworksHidlTest() override; + public: + NeuralnetworksHidlTest() = default; void SetUp() override; void TearDown() override; - protected: - sp device; + protected: + const sp device = ::testing::VtsHalHidlTargetTestBase::getService( + NeuralnetworksHidlEnvironment::getInstance()); }; -} // namespace functional -} // namespace vts -} // namespace V1_1 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_1::vts::functional namespace android::hardware::neuralnetworks::V1_0 { diff --git a/neuralnetworks/1.2/vts/functional/BasicTests.cpp b/neuralnetworks/1.2/vts/functional/BasicTests.cpp index 5c269df275..86849d566a 100644 --- a/neuralnetworks/1.2/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.2/vts/functional/BasicTests.cpp @@ -18,13 +18,10 @@ #include "VtsHalNeuralnetworks.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_2 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { +using V1_0::DeviceStatus; +using V1_0::ErrorStatus; using V1_0::PerformanceInfo; // create device test @@ -113,9 +110,4 @@ TEST_F(NeuralnetworksHidlTest, getNumberOfCacheFilesNeeded) { }); EXPECT_TRUE(ret.isOk()); } -} // namespace functional -} // namespace vts -} // namespace V1_2 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.2/vts/functional/Callbacks.cpp b/neuralnetworks/1.2/vts/functional/Callbacks.cpp index a607a083c0..3972ad6ff2 100644 --- a/neuralnetworks/1.2/vts/functional/Callbacks.cpp +++ b/neuralnetworks/1.2/vts/functional/Callbacks.cpp @@ -24,6 +24,8 @@ namespace android::hardware::neuralnetworks::V1_2::implementation { +using V1_0::ErrorStatus; + constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits::max(), .timeInDriver = std::numeric_limits::max()}; diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp index bde700e079..90872d4cc5 100644 --- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp @@ -17,7 +17,6 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" #include -#include #include #include #include @@ -45,20 +44,12 @@ namespace generated_tests::mobilenet_quantized { const ::test_helper::TestModel& get_test_model(); } // namespace generated_tests::mobilenet_quantized -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_2 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { using namespace test_helper; -using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; -using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference; -using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; -using ::android::hidl::memory::V1_0::IMemory; -using ::android::nn::allocateSharedMemory; +using implementation::PreparedModelCallback; +using V1_0::ErrorStatus; +using V1_1::ExecutionPreference; namespace float32_model { @@ -307,7 +298,7 @@ class CompilationCachingTestBase : public NeuralnetworksHidlTest { } // See if the service can handle the model. - bool isModelFullySupported(const V1_2::Model& model) { + bool isModelFullySupported(const Model& model) { bool fullySupportsModel = false; Return supportedCall = device->getSupportedOperations_1_2( model, @@ -321,14 +312,13 @@ class CompilationCachingTestBase : public NeuralnetworksHidlTest { return fullySupportsModel; } - void saveModelToCache(const V1_2::Model& model, const hidl_vec& modelCache, + void saveModelToCache(const Model& model, const hidl_vec& modelCache, const hidl_vec& dataCache, sp* preparedModel = nullptr) { if (preparedModel != nullptr) *preparedModel = nullptr; // Launch prepare model. sp preparedModelCallback = new PreparedModelCallback(); - ASSERT_NE(nullptr, preparedModelCallback.get()); hidl_array cacheToken(mToken); Return prepareLaunchStatus = device->prepareModel_1_2(model, ExecutionPreference::FAST_SINGLE_ANSWER, modelCache, @@ -340,9 +330,8 @@ class CompilationCachingTestBase : public NeuralnetworksHidlTest { preparedModelCallback->wait(); ASSERT_EQ(preparedModelCallback->getStatus(), ErrorStatus::NONE); if (preparedModel != nullptr) { - *preparedModel = - V1_2::IPreparedModel::castFrom(preparedModelCallback->getPreparedModel()) - .withDefault(nullptr); + *preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel()) + .withDefault(nullptr); } } @@ -358,7 +347,7 @@ class CompilationCachingTestBase : public NeuralnetworksHidlTest { return false; } - bool checkEarlyTermination(const V1_2::Model& model) { + bool checkEarlyTermination(const Model& model) { if (!isModelFullySupported(model)) { LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " "prepare model that it does not support."; @@ -375,7 +364,6 @@ class CompilationCachingTestBase : public NeuralnetworksHidlTest { sp* preparedModel, ErrorStatus* status) { // Launch prepare model from cache. sp preparedModelCallback = new PreparedModelCallback(); - ASSERT_NE(nullptr, preparedModelCallback.get()); hidl_array cacheToken(mToken); Return prepareLaunchStatus = device->prepareModelFromCache( modelCache, dataCache, cacheToken, preparedModelCallback); @@ -389,7 +377,7 @@ class CompilationCachingTestBase : public NeuralnetworksHidlTest { // Retrieve prepared model. preparedModelCallback->wait(); *status = preparedModelCallback->getStatus(); - *preparedModel = V1_2::IPreparedModel::castFrom(preparedModelCallback->getPreparedModel()) + *preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel()) .withDefault(nullptr); } @@ -1353,9 +1341,4 @@ TEST_P(CompilationCachingSecurityTest, WrongToken) { INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest, ::testing::Combine(kOperandTypeChoices, ::testing::Range(0U, 10U))); -} // namespace functional -} // namespace vts -} // namespace V1_2 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp index 1d302e2f2c..b8ca080e5a 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp @@ -44,30 +44,17 @@ #include "Utils.h" #include "VtsHalNeuralnetworks.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_2 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { using namespace test_helper; -using ::android::hardware::neuralnetworks::V1_0::DataLocation; -using ::android::hardware::neuralnetworks::V1_0::ErrorStatus; -using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime; -using ::android::hardware::neuralnetworks::V1_0::Request; -using ::android::hardware::neuralnetworks::V1_0::RequestArgument; -using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference; -using ::android::hardware::neuralnetworks::V1_2::Constant; -using ::android::hardware::neuralnetworks::V1_2::IDevice; -using ::android::hardware::neuralnetworks::V1_2::IPreparedModel; -using ::android::hardware::neuralnetworks::V1_2::MeasureTiming; -using ::android::hardware::neuralnetworks::V1_2::Model; -using ::android::hardware::neuralnetworks::V1_2::OutputShape; -using ::android::hardware::neuralnetworks::V1_2::Timing; -using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; -using ::android::hidl::memory::V1_0::IMemory; +using hidl::memory::V1_0::IMemory; +using implementation::ExecutionCallback; +using implementation::PreparedModelCallback; +using V1_0::DataLocation; +using V1_0::ErrorStatus; +using V1_0::OperandLifeTime; +using V1_0::Request; +using V1_1::ExecutionPreference; using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; @@ -447,9 +434,4 @@ INSTANTIATE_GENERATED_TEST(GeneratedTest, INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); -} // namespace functional -} // namespace vts -} // namespace V1_2 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h index 27208ce4b6..cb01b91cfd 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h @@ -25,12 +25,7 @@ #include "TestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_2 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { class GeneratedTestBase : public NeuralnetworksHidlTest, @@ -54,29 +49,24 @@ class GeneratedTestBase // TODO: Clean up the hierarchy for ValidationTest. class ValidationTest : public GeneratedTestBase { protected: - void validateEverything(const Model& model, const Request& request); - void validateFailure(const Model& model, const Request& request); + void validateEverything(const Model& model, const V1_0::Request& request); + void validateFailure(const Model& model, const V1_0::Request& request); private: void validateModel(const Model& model); - void validateRequest(const sp& preparedModel, const Request& request); - void validateRequestFailure(const sp& preparedModel, const Request& request); - void validateBurst(const sp& preparedModel, const Request& request); + void validateRequest(const sp& preparedModel, const V1_0::Request& request); + void validateRequestFailure(const sp& preparedModel, + const V1_0::Request& request); + void validateBurst(const sp& preparedModel, const V1_0::Request& request); }; Model createModel(const ::test_helper::TestModel& testModel); -void PrepareModel(const sp& device, const V1_2::Model& model, - sp* preparedModel); +void PrepareModel(const sp& device, const Model& model, sp* preparedModel); -void EvaluatePreparedModel(const sp& preparedModel, +void EvaluatePreparedModel(const sp& preparedModel, const ::test_helper::TestModel& testModel, bool testDynamicOutputShape); -} // namespace functional -} // namespace vts -} // namespace V1_2 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional #endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp index cb801eb4ad..844e87986d 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp @@ -28,17 +28,14 @@ #include #include -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_2 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { -using ::android::nn::ExecutionBurstController; -using ::android::nn::RequestChannelSender; -using ::android::nn::ResultChannelReceiver; -using ExecutionBurstCallback = ::android::nn::ExecutionBurstController::ExecutionBurstCallback; +using nn::ExecutionBurstController; +using nn::RequestChannelSender; +using nn::ResultChannelReceiver; +using V1_0::ErrorStatus; +using V1_0::Request; +using ExecutionBurstCallback = ExecutionBurstController::ExecutionBurstCallback; // This constant value represents the length of an FMQ that is large enough to // return a result from a burst execution for all of the generated test cases. @@ -401,9 +398,4 @@ void ValidationTest::validateBurst(const sp& preparedModel, ASSERT_NO_FATAL_FAILURE(validateBurstSanitized(preparedModel, request)); } -} // namespace functional -} // namespace vts -} // namespace V1_2 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp index 7dfcff2d42..74840a6790 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp @@ -21,19 +21,12 @@ #include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_2 { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { +using implementation::PreparedModelCallback; +using V1_0::ErrorStatus; using V1_0::OperandLifeTime; using V1_1::ExecutionPreference; - -namespace vts { -namespace functional { - -using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// @@ -54,7 +47,6 @@ static void validatePrepareModel(const sp& device, const std::string& m SCOPED_TRACE(message + " [prepareModel_1_2]"); sp preparedModelCallback = new PreparedModelCallback(); - ASSERT_NE(nullptr, preparedModelCallback.get()); Return prepareLaunchStatus = device->prepareModel_1_2(model, preference, hidl_vec(), hidl_vec(), HidlToken(), preparedModelCallback); @@ -692,8 +684,9 @@ static void mutateExecutionPreferenceTest(const sp& device, const Model for (int32_t preference : invalidExecutionPreferences) { const std::string message = "mutateExecutionPreferenceTest: preference " + std::to_string(preference); - validate(device, message, model, [](Model*) {}, - static_cast(preference)); + validate( + device, message, model, [](Model*) {}, + static_cast(preference)); } } @@ -717,9 +710,4 @@ void ValidationTest::validateModel(const Model& model) { mutateExecutionPreferenceTest(device, model); } -} // namespace functional -} // namespace vts -} // namespace V1_2 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp index 20c740e306..684b43366a 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp @@ -24,14 +24,11 @@ #include "Utils.h" #include "VtsHalNeuralnetworks.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_2 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { -using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; +using implementation::ExecutionCallback; +using V1_0::ErrorStatus; +using V1_0::Request; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// @@ -62,7 +59,6 @@ static void validate(const sp& preparedModel, const std::string& SCOPED_TRACE(message + " [execute_1_2]"); sp executionCallback = new ExecutionCallback(); - ASSERT_NE(nullptr, executionCallback.get()); Return executeLaunchStatus = preparedModel->execute_1_2(request, measure, executionCallback); ASSERT_TRUE(executeLaunchStatus.isOk()); @@ -171,9 +167,4 @@ void ValidationTest::validateRequestFailure(const sp& preparedMo ASSERT_TRUE(executeStatus.isOk()); } -} // namespace functional -} // namespace vts -} // namespace V1_2 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp index b87384e6c7..ea9d684be8 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp @@ -24,15 +24,12 @@ #include -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_2 { -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; +using implementation::PreparedModelCallback; using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; +using V1_0::ErrorStatus; +using V1_0::Request; using V1_1::ExecutionPreference; // internal helper function @@ -53,7 +50,6 @@ static void createPreparedModel(const sp& device, const Model& model, // launch prepare model sp preparedModelCallback = new PreparedModelCallback(); - ASSERT_NE(nullptr, preparedModelCallback.get()); Return prepareLaunchStatus = device->prepareModel_1_2( model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec(), hidl_vec(), HidlToken(), preparedModelCallback); @@ -86,10 +82,6 @@ static void createPreparedModel(const sp& device, const Model& model, } // A class for test environment setup -NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {} - -NeuralnetworksHidlEnvironment::~NeuralnetworksHidlEnvironment() {} - NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() { // This has to return a "new" object because it is freed inside // ::testing::AddGlobalTestEnvironment when the gtest is being torn down @@ -102,14 +94,8 @@ void NeuralnetworksHidlEnvironment::registerTestServices() { } // The main test class for NEURALNETWORK HIDL HAL. -NeuralnetworksHidlTest::NeuralnetworksHidlTest() {} - -NeuralnetworksHidlTest::~NeuralnetworksHidlTest() {} - void NeuralnetworksHidlTest::SetUp() { ::testing::VtsHalHidlTargetTestBase::SetUp(); - device = ::testing::VtsHalHidlTargetTestBase::getService( - NeuralnetworksHidlEnvironment::getInstance()); #ifdef PRESUBMIT_NOT_VTS const std::string name = @@ -124,7 +110,6 @@ void NeuralnetworksHidlTest::SetUp() { } void NeuralnetworksHidlTest::TearDown() { - device = nullptr; ::testing::VtsHalHidlTargetTestBase::TearDown(); } @@ -168,18 +153,12 @@ TEST_P(ValidationTest, Test) { INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); -sp getPreparedModel_1_2( - const sp& callback) { +sp getPreparedModel_1_2(const sp& callback) { sp preparedModelV1_0 = callback->getPreparedModel(); - return V1_2::IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr); + return IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr); } -} // namespace functional -} // namespace vts -} // namespace V1_2 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional namespace android::hardware::neuralnetworks::V1_0 { diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h index 8729a6f190..4a6d33bc6b 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h @@ -32,23 +32,12 @@ #include "1.2/Callbacks.h" #include "TestHarness.h" -namespace android { -namespace hardware { -namespace neuralnetworks { -namespace V1_2 { - -using V1_0::DeviceStatus; -using V1_0::ErrorStatus; -using V1_0::Request; - -namespace vts { -namespace functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { // A class for test environment setup class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment); - NeuralnetworksHidlEnvironment(); - ~NeuralnetworksHidlEnvironment() override; + NeuralnetworksHidlEnvironment() = default; public: static NeuralnetworksHidlEnvironment* getInstance(); @@ -60,25 +49,19 @@ class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase { DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest); public: - NeuralnetworksHidlTest(); - ~NeuralnetworksHidlTest() override; + NeuralnetworksHidlTest() = default; void SetUp() override; void TearDown() override; protected: - sp device; + const sp device = ::testing::VtsHalHidlTargetTestBase::getService( + NeuralnetworksHidlEnvironment::getInstance()); }; // Utility function to get PreparedModel from callback and downcast to V1_2. -sp getPreparedModel_1_2( - const sp& callback); +sp getPreparedModel_1_2(const sp& callback); -} // namespace functional -} // namespace vts -} // namespace V1_2 -} // namespace neuralnetworks -} // namespace hardware -} // namespace android +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional namespace android::hardware::neuralnetworks::V1_0 { diff --git a/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h b/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h index 2992c0cfe9..bf4792cc6b 100644 --- a/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h +++ b/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h @@ -46,8 +46,6 @@ namespace android::hardware::neuralnetworks::V1_2::implementation { -using V1_0::ErrorStatus; - /** * The PreparedModelCallback class is used to receive the error status of * preparing a model as well as the prepared model from a task executing @@ -87,7 +85,8 @@ class PreparedModelCallback : public IPreparedModelCallback { * @param preparedModel Returned model that has been prepared for execution, * nullptr if the model was unable to be prepared. */ - Return notify(ErrorStatus status, const sp& preparedModel) override; + Return notify(V1_0::ErrorStatus status, + const sp& preparedModel) override; /** * IPreparedModelCallback::notify_1_2 marks the callback object with the @@ -112,7 +111,7 @@ class PreparedModelCallback : public IPreparedModelCallback { * @param preparedModel Returned model that has been prepared for execution, * nullptr if the model was unable to be prepared. */ - Return notify_1_2(ErrorStatus status, + Return notify_1_2(V1_0::ErrorStatus status, const sp& preparedModel) override; /** @@ -134,7 +133,7 @@ class PreparedModelCallback : public IPreparedModelCallback { * - GENERAL_FAILURE if there is an unspecified error * - INVALID_ARGUMENT if the input model is invalid */ - ErrorStatus getStatus() const; + V1_0::ErrorStatus getStatus() const; /** * Retrieves the model that has been prepared for execution from the @@ -152,7 +151,7 @@ class PreparedModelCallback : public IPreparedModelCallback { mutable std::mutex mMutex; mutable std::condition_variable mCondition; bool mNotified GUARDED_BY(mMutex) = false; - ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE; + V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; sp mPreparedModel; }; @@ -195,7 +194,7 @@ class ExecutionCallback : public IExecutionCallback { * enough to store the resultant values * - INVALID_ARGUMENT if the input request is invalid */ - Return notify(ErrorStatus status) override; + Return notify(V1_0::ErrorStatus status) override; /** * IExecutionCallback::notify_1_2 marks the callback object with the results @@ -230,11 +229,11 @@ class ExecutionCallback : public IExecutionCallback { * reported as UINT64_MAX. A driver may choose to report any time as * UINT64_MAX, indicating that particular measurement is not available. */ - Return notify_1_2(ErrorStatus status, const hidl_vec& outputShapes, + Return notify_1_2(V1_0::ErrorStatus status, const hidl_vec& outputShapes, const Timing& timing) override; // An overload of the latest notify interface to hide the version from ExecutionBuilder. - Return notify(ErrorStatus status, const hidl_vec& outputShapes, + Return notify(V1_0::ErrorStatus status, const hidl_vec& outputShapes, const Timing& timing) { return notify_1_2(status, outputShapes, timing); } @@ -264,7 +263,7 @@ class ExecutionCallback : public IExecutionCallback { * - INVALID_ARGUMENT if one of the input arguments to prepareModel is * invalid */ - ErrorStatus getStatus() const; + V1_0::ErrorStatus getStatus() const; /** * Retrieves the output shapes returned from the asynchronous task launched @@ -309,14 +308,14 @@ class ExecutionCallback : public IExecutionCallback { * object before any call to wait or get* return. It then enables all prior * and future wait calls on the ExecutionCallback object to proceed. */ - void notifyInternal(ErrorStatus errorStatus, const hidl_vec& outputShapes, + void notifyInternal(V1_0::ErrorStatus errorStatus, const hidl_vec& outputShapes, const Timing& timing); // members mutable std::mutex mMutex; mutable std::condition_variable mCondition; bool mNotified GUARDED_BY(mMutex) = false; - ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE; + V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; std::vector mOutputShapes = {}; Timing mTiming = {}; }; From e16af0a44ba9b76667a598b10a085f808efb8c7c Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Thu, 29 Aug 2019 22:17:24 -0700 Subject: [PATCH 0096/1022] Consolidate NNAPI VTS utility code This CL does additional NNAPI VTS test cleanup, including consolidating duplicate functionality. Specifically, this CL: * consolidates the createPreparedModel function, removing the duplicate * consolidates the std::out ErrorStatus and DeviceStatus code into Utils * changes non-null constant pointers to constant references * removes redudant leading namespace specifiers (V1_0::, ::testing, etc.) * makes the Valdiation tests free functions * renames device to kDevice and mTestModel to kTestModel Bug: N/A Test: mma Test: VtsHalNeuralnetworksV1_*TargetTest (with sample-all) Change-Id: Ic401bb1f1760cc10384ac0d30c0c93409b63a9c7 --- .../1.0/vts/functional/BasicTests.cpp | 4 +- .../vts/functional/GeneratedTestHarness.cpp | 55 ++--------- .../1.0/vts/functional/GeneratedTestHarness.h | 26 ++---- neuralnetworks/1.0/vts/functional/Utils.cpp | 13 +++ .../1.0/vts/functional/ValidateModel.cpp | 44 +++++---- .../1.0/vts/functional/ValidateRequest.cpp | 3 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 71 +++++++------- .../1.0/vts/functional/VtsHalNeuralnetworks.h | 24 ++--- .../1.0/vts/functional/include/1.0/Utils.h | 9 ++ .../1.1/vts/functional/BasicTests.cpp | 4 +- .../vts/functional/GeneratedTestHarness.cpp | 55 ++--------- .../1.1/vts/functional/GeneratedTestHarness.h | 27 ++---- .../1.1/vts/functional/ValidateModel.cpp | 46 +++++---- .../1.1/vts/functional/ValidateRequest.cpp | 3 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 76 +++++++-------- .../1.1/vts/functional/VtsHalNeuralnetworks.h | 24 ++--- .../1.2/vts/functional/BasicTests.cpp | 21 +++-- .../functional/CompilationCachingTests.cpp | 22 ++--- .../vts/functional/GeneratedTestHarness.cpp | 69 +++----------- .../1.2/vts/functional/GeneratedTestHarness.h | 30 ++---- .../1.2/vts/functional/ValidateBurst.cpp | 3 +- .../1.2/vts/functional/ValidateModel.cpp | 2 +- .../1.2/vts/functional/ValidateRequest.cpp | 6 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 93 +++++++++---------- .../1.2/vts/functional/VtsHalNeuralnetworks.h | 24 ++--- 25 files changed, 278 insertions(+), 476 deletions(-) diff --git a/neuralnetworks/1.0/vts/functional/BasicTests.cpp b/neuralnetworks/1.0/vts/functional/BasicTests.cpp index 5727ca4034..551ea6788a 100644 --- a/neuralnetworks/1.0/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.0/vts/functional/BasicTests.cpp @@ -25,7 +25,7 @@ TEST_F(NeuralnetworksHidlTest, CreateDevice) {} // status test TEST_F(NeuralnetworksHidlTest, StatusTest) { - Return status = device->getStatus(); + Return status = kDevice->getStatus(); ASSERT_TRUE(status.isOk()); EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast(status)); } @@ -33,7 +33,7 @@ TEST_F(NeuralnetworksHidlTest, StatusTest) { // initialization TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) { Return ret = - device->getCapabilities([](ErrorStatus status, const Capabilities& capabilities) { + kDevice->getCapabilities([](ErrorStatus status, const Capabilities& capabilities) { EXPECT_EQ(ErrorStatus::NONE, status); EXPECT_LT(0.0f, capabilities.float32Performance.execTime); EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage); diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp index 33a6fa5d6a..1948c053a9 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp @@ -122,9 +122,15 @@ Model createModel(const TestModel& testModel) { // Top level driver for models and examples generated by test_generator.py // Test driver for those generated from ml/nn/runtime/test/spec -void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel) { +void Execute(const sp& device, const TestModel& testModel) { + const Model model = createModel(testModel); const Request request = createRequest(testModel); + // Create IPreparedModel. + sp preparedModel; + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; + // Launch execution. sp executionCallback = new ExecutionCallback(); Return executionLaunchStatus = preparedModel->execute(request, executionCallback); @@ -143,53 +149,10 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo } // Tag for the generated tests -class GeneratedTest : public GeneratedTestBase { - protected: - void Execute(const TestModel& testModel) { - Model model = createModel(testModel); - - // see if service can handle model - bool fullySupportsModel = false; - Return supportedCall = device->getSupportedOperations( - model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { - ASSERT_EQ(ErrorStatus::NONE, status); - ASSERT_NE(0ul, supported.size()); - fullySupportsModel = std::all_of(supported.begin(), supported.end(), - [](bool valid) { return valid; }); - }); - ASSERT_TRUE(supportedCall.isOk()); - - // launch prepare model - sp preparedModelCallback = new PreparedModelCallback(); - Return prepareLaunchStatus = - device->prepareModel(model, preparedModelCallback); - ASSERT_TRUE(prepareLaunchStatus.isOk()); - ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); - - // retrieve prepared model - preparedModelCallback->wait(); - ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); - sp preparedModel = preparedModelCallback->getPreparedModel(); - - // early termination if vendor service cannot fully prepare model - if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { - ASSERT_EQ(nullptr, preparedModel.get()); - LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " - "prepare model that it does not support."; - std::cout << "[ ] Early termination of test because vendor service cannot " - "prepare model that it does not support." - << std::endl; - GTEST_SKIP(); - } - EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); - ASSERT_NE(nullptr, preparedModel.get()); - - EvaluatePreparedModel(preparedModel, testModel); - } -}; +class GeneratedTest : public GeneratedTestBase {}; TEST_P(GeneratedTest, Test) { - Execute(*mTestModel); + Execute(kDevice, kTestModel); } INSTANTIATE_GENERATED_TEST(GeneratedTest, diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h index a42f271cad..10e46b7d2c 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h @@ -25,32 +25,20 @@ namespace android::hardware::neuralnetworks::V1_0::vts::functional { class GeneratedTestBase : public NeuralnetworksHidlTest, - public ::testing::WithParamInterface { + public testing::WithParamInterface { protected: - void SetUp() override { - NeuralnetworksHidlTest::SetUp(); - ASSERT_NE(mTestModel, nullptr); - } - - const test_helper::TestModel* mTestModel = GetParam().second; + const test_helper::TestModel& kTestModel = *GetParam().second; }; -#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ - INSTANTIATE_TEST_SUITE_P( \ - TestGenerated, TestSuite, \ - ::testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \ +#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ + INSTANTIATE_TEST_SUITE_P( \ + TestGenerated, TestSuite, \ + testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \ [](const auto& info) { return info.param.first; }) // Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp. // TODO: Clean up the hierarchy for ValidationTest. -class ValidationTest : public GeneratedTestBase { - protected: - void validateEverything(const Model& model, const Request& request); - - private: - void validateModel(const Model& model); - void validateRequest(const sp& preparedModel, const Request& request); -}; +class ValidationTest : public GeneratedTestBase {}; Model createModel(const ::test_helper::TestModel& testModel); diff --git a/neuralnetworks/1.0/vts/functional/Utils.cpp b/neuralnetworks/1.0/vts/functional/Utils.cpp index 5de99fd0b3..307003cf4a 100644 --- a/neuralnetworks/1.0/vts/functional/Utils.cpp +++ b/neuralnetworks/1.0/vts/functional/Utils.cpp @@ -26,6 +26,7 @@ #include #include +#include #include namespace android::hardware::neuralnetworks { @@ -117,3 +118,15 @@ std::vector getOutputBuffers(const Request& request) { } } // namespace android::hardware::neuralnetworks + +namespace android::hardware::neuralnetworks::V1_0 { + +::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus) { + return os << toString(errorStatus); +} + +::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus) { + return os << toString(deviceStatus); +} + +} // namespace android::hardware::neuralnetworks::V1_0 diff --git a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp index 9854395084..cc15263ae2 100644 --- a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp @@ -27,7 +27,7 @@ using implementation::PreparedModelCallback; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// static void validateGetSupportedOperations(const sp& device, const std::string& message, - const V1_0::Model& model) { + const Model& model) { SCOPED_TRACE(message + " [getSupportedOperations]"); Return ret = @@ -38,7 +38,7 @@ static void validateGetSupportedOperations(const sp& device, const std: } static void validatePrepareModel(const sp& device, const std::string& message, - const V1_0::Model& model) { + const Model& model) { SCOPED_TRACE(message + " [prepareModel]"); sp preparedModelCallback = new PreparedModelCallback(); @@ -57,7 +57,7 @@ static void validatePrepareModel(const sp& device, const std::string& m // mutation to it to invalidate the model, then pass it to interface calls that // use the model. Note that the model here is passed by value, and any mutation // to the model does not leave this function. -static void validate(const sp& device, const std::string& message, V1_0::Model model, +static void validate(const sp& device, const std::string& message, Model model, const std::function& mutation) { mutation(&model); validateGetSupportedOperations(device, message, model); @@ -113,7 +113,7 @@ static const int32_t invalidOperandTypes[] = { static_cast(OperandType::TENSOR_OEM_BYTE) + 1, // upper bound OEM }; -static void mutateOperandTypeTest(const sp& device, const V1_0::Model& model) { +static void mutateOperandTypeTest(const sp& device, const Model& model) { for (size_t operand = 0; operand < model.operands.size(); ++operand) { for (int32_t invalidOperandType : invalidOperandTypes) { const std::string message = "mutateOperandTypeTest: operand " + @@ -143,7 +143,7 @@ static uint32_t getInvalidRank(OperandType type) { } } -static void mutateOperandRankTest(const sp& device, const V1_0::Model& model) { +static void mutateOperandRankTest(const sp& device, const Model& model) { for (size_t operand = 0; operand < model.operands.size(); ++operand) { const uint32_t invalidRank = getInvalidRank(model.operands[operand].type); const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) + @@ -172,7 +172,7 @@ static float getInvalidScale(OperandType type) { } } -static void mutateOperandScaleTest(const sp& device, const V1_0::Model& model) { +static void mutateOperandScaleTest(const sp& device, const Model& model) { for (size_t operand = 0; operand < model.operands.size(); ++operand) { const float invalidScale = getInvalidScale(model.operands[operand].type); const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) + @@ -200,7 +200,7 @@ static std::vector getInvalidZeroPoints(OperandType type) { } } -static void mutateOperandZeroPointTest(const sp& device, const V1_0::Model& model) { +static void mutateOperandZeroPointTest(const sp& device, const Model& model) { for (size_t operand = 0; operand < model.operands.size(); ++operand) { const std::vector invalidZeroPoints = getInvalidZeroPoints(model.operands[operand].type); @@ -257,7 +257,7 @@ static void mutateOperand(Operand* operand, OperandType type) { *operand = newOperand; } -static bool mutateOperationOperandTypeSkip(size_t operand, const V1_0::Model& model) { +static bool mutateOperationOperandTypeSkip(size_t operand, const Model& model) { // LSH_PROJECTION's second argument is allowed to have any type. This is the // only operation that currently has a type that can be anything independent // from any other type. Changing the operand type to any other type will @@ -271,7 +271,7 @@ static bool mutateOperationOperandTypeSkip(size_t operand, const V1_0::Model& mo return false; } -static void mutateOperationOperandTypeTest(const sp& device, const V1_0::Model& model) { +static void mutateOperationOperandTypeTest(const sp& device, const Model& model) { for (size_t operand = 0; operand < model.operands.size(); ++operand) { if (mutateOperationOperandTypeSkip(operand, model)) { continue; @@ -302,7 +302,7 @@ static const int32_t invalidOperationTypes[] = { static_cast(OperationType::OEM_OPERATION) + 1, // upper bound OEM }; -static void mutateOperationTypeTest(const sp& device, const V1_0::Model& model) { +static void mutateOperationTypeTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { for (int32_t invalidOperationType : invalidOperationTypes) { const std::string message = "mutateOperationTypeTest: operation " + @@ -318,8 +318,7 @@ static void mutateOperationTypeTest(const sp& device, const V1_0::Model ///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX ///////////////////////// -static void mutateOperationInputOperandIndexTest(const sp& device, - const V1_0::Model& model) { +static void mutateOperationInputOperandIndexTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { const uint32_t invalidOperand = model.operands.size(); for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) { @@ -335,8 +334,7 @@ static void mutateOperationInputOperandIndexTest(const sp& device, ///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX ///////////////////////// -static void mutateOperationOutputOperandIndexTest(const sp& device, - const V1_0::Model& model) { +static void mutateOperationOutputOperandIndexTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { const uint32_t invalidOperand = model.operands.size(); for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) { @@ -374,7 +372,7 @@ static void removeOperand(Model* model, uint32_t index) { removeValueAndDecrementGreaterValues(&model->outputIndexes, index); } -static void removeOperandTest(const sp& device, const V1_0::Model& model) { +static void removeOperandTest(const sp& device, const Model& model) { for (size_t operand = 0; operand < model.operands.size(); ++operand) { const std::string message = "removeOperandTest: operand " + std::to_string(operand); validate(device, message, model, @@ -391,7 +389,7 @@ static void removeOperation(Model* model, uint32_t index) { hidl_vec_removeAt(&model->operations, index); } -static void removeOperationTest(const sp& device, const V1_0::Model& model) { +static void removeOperationTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { const std::string message = "removeOperationTest: operation " + std::to_string(operation); validate(device, message, model, @@ -401,14 +399,14 @@ static void removeOperationTest(const sp& device, const V1_0::Model& mo ///////////////////////// REMOVE OPERATION INPUT ///////////////////////// -static void removeOperationInputTest(const sp& device, const V1_0::Model& model) { +static void removeOperationInputTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) { - const V1_0::Operation& op = model.operations[operation]; + const Operation& op = model.operations[operation]; // CONCATENATION has at least 2 inputs, with the last element being // INT32. Skip this test if removing one of CONCATENATION's // inputs still produces a valid model. - if (op.type == V1_0::OperationType::CONCATENATION && op.inputs.size() > 2 && + if (op.type == OperationType::CONCATENATION && op.inputs.size() > 2 && input != op.inputs.size() - 1) { continue; } @@ -426,7 +424,7 @@ static void removeOperationInputTest(const sp& device, const V1_0::Mode ///////////////////////// REMOVE OPERATION OUTPUT ///////////////////////// -static void removeOperationOutputTest(const sp& device, const V1_0::Model& model) { +static void removeOperationOutputTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) { const std::string message = "removeOperationOutputTest: operation " + @@ -447,7 +445,7 @@ static void removeOperationOutputTest(const sp& device, const V1_0::Mod ///////////////////////// ADD OPERATION INPUT ///////////////////////// -static void addOperationInputTest(const sp& device, const V1_0::Model& model) { +static void addOperationInputTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { const std::string message = "addOperationInputTest: operation " + std::to_string(operation); validate(device, message, model, [operation](Model* model) { @@ -460,7 +458,7 @@ static void addOperationInputTest(const sp& device, const V1_0::Model& ///////////////////////// ADD OPERATION OUTPUT ///////////////////////// -static void addOperationOutputTest(const sp& device, const V1_0::Model& model) { +static void addOperationOutputTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { const std::string message = "addOperationOutputTest: operation " + std::to_string(operation); @@ -474,7 +472,7 @@ static void addOperationOutputTest(const sp& device, const V1_0::Model& ////////////////////////// ENTRY POINT ////////////////////////////// -void ValidationTest::validateModel(const V1_0::Model& model) { +void validateModel(const sp& device, const Model& model) { mutateOperandTypeTest(device, model); mutateOperandRankTest(device, model); mutateOperandScaleTest(device, model); diff --git a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp index d8f3e65e8c..05eefd13d8 100644 --- a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp @@ -87,8 +87,7 @@ static void removeOutputTest(const sp& preparedModel, const Requ ///////////////////////////// ENTRY POINT ////////////////////////////////// -void ValidationTest::validateRequest(const sp& preparedModel, - const Request& request) { +void validateRequest(const sp& preparedModel, const Request& request) { removeInputTest(preparedModel, request); removeOutputTest(preparedModel, request); } diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp index 9ee4e37cb0..20b4565a47 100644 --- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp @@ -28,30 +28,32 @@ namespace android::hardware::neuralnetworks::V1_0::vts::functional { using implementation::PreparedModelCallback; -static void createPreparedModel(const sp& device, const Model& model, - sp* preparedModel) { +void createPreparedModel(const sp& device, const Model& model, + sp* preparedModel) { ASSERT_NE(nullptr, preparedModel); + *preparedModel = nullptr; // see if service can handle model bool fullySupportsModel = false; - Return supportedOpsLaunchStatus = device->getSupportedOperations( + const Return supportedCall = device->getSupportedOperations( model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { ASSERT_EQ(ErrorStatus::NONE, status); ASSERT_NE(0ul, supported.size()); fullySupportsModel = std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; }); }); - ASSERT_TRUE(supportedOpsLaunchStatus.isOk()); + ASSERT_TRUE(supportedCall.isOk()); // launch prepare model - sp preparedModelCallback = new PreparedModelCallback(); - Return prepareLaunchStatus = device->prepareModel(model, preparedModelCallback); + const sp preparedModelCallback = new PreparedModelCallback(); + const Return prepareLaunchStatus = + device->prepareModel(model, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); // retrieve prepared model preparedModelCallback->wait(); - ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); *preparedModel = preparedModelCallback->getPreparedModel(); // The getSupportedOperations call returns a list of operations that are @@ -63,12 +65,12 @@ static void createPreparedModel(const sp& device, const Model& model, // can continue. if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { ASSERT_EQ(nullptr, preparedModel->get()); - LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot " - "prepare model that it does not support."; - std::cout << "[ ] Unable to test Request validation because vendor service " - "cannot prepare model that it does not support." + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot prepare " + "model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "prepare model that it does not support." << std::endl; - return; + GTEST_SKIP(); } ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus); ASSERT_NE(nullptr, preparedModel->get()); @@ -77,7 +79,7 @@ static void createPreparedModel(const sp& device, const Model& model, // A class for test environment setup NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() { // This has to return a "new" object because it is freed inside - // ::testing::AddGlobalTestEnvironment when the gtest is being torn down + // testing::AddGlobalTestEnvironment when the gtest is being torn down static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment(); return instance; } @@ -88,28 +90,29 @@ void NeuralnetworksHidlEnvironment::registerTestServices() { // The main test class for NEURALNETWORK HIDL HAL. void NeuralnetworksHidlTest::SetUp() { - ::testing::VtsHalHidlTargetTestBase::SetUp(); + testing::VtsHalHidlTargetTestBase::SetUp(); #ifdef PRESUBMIT_NOT_VTS const std::string name = NeuralnetworksHidlEnvironment::getInstance()->getServiceName(); const std::string sampleDriver = "sample-"; - if (device == nullptr && name.substr(0, sampleDriver.size()) == sampleDriver) { + if (kDevice == nullptr && name.substr(0, sampleDriver.size()) == sampleDriver) { GTEST_SKIP(); } #endif // PRESUBMIT_NOT_VTS - ASSERT_NE(nullptr, device.get()); + ASSERT_NE(nullptr, kDevice.get()); } -void NeuralnetworksHidlTest::TearDown() { - ::testing::VtsHalHidlTargetTestBase::TearDown(); -} +// Forward declaration from ValidateModel.cpp +void validateModel(const sp& device, const Model& model); +// Forward declaration from ValidateRequest.cpp +void validateRequest(const sp& preparedModel, const Request& request); -void ValidationTest::validateEverything(const Model& model, const Request& request) { - validateModel(model); +void validateEverything(const sp& device, const Model& model, const Request& request) { + validateModel(device, model); - // create IPreparedModel + // Create IPreparedModel. sp preparedModel; createPreparedModel(device, model, &preparedModel); if (preparedModel == nullptr) return; @@ -118,33 +121,21 @@ void ValidationTest::validateEverything(const Model& model, const Request& reque } TEST_P(ValidationTest, Test) { - const Model model = createModel(*mTestModel); - const Request request = createRequest(*mTestModel); - ASSERT_FALSE(mTestModel->expectFailure); - validateEverything(model, request); + const Model model = createModel(kTestModel); + const Request request = createRequest(kTestModel); + ASSERT_FALSE(kTestModel.expectFailure); + validateEverything(kDevice, model, request); } INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); } // namespace android::hardware::neuralnetworks::V1_0::vts::functional -namespace android::hardware::neuralnetworks::V1_0 { - -::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus) { - return os << toString(errorStatus); -} - -::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus) { - return os << toString(deviceStatus); -} - -} // namespace android::hardware::neuralnetworks::V1_0 - using android::hardware::neuralnetworks::V1_0::vts::functional::NeuralnetworksHidlEnvironment; int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance()); - ::testing::InitGoogleTest(&argc, argv); + testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance()); + testing::InitGoogleTest(&argc, argv); NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv); int status = RUN_ALL_TESTS(); diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h index fa9ad3b3c1..48dc23774f 100644 --- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h @@ -25,15 +25,11 @@ #include #include -#include -#include - -#include "TestHarness.h" namespace android::hardware::neuralnetworks::V1_0::vts::functional { // A class for test environment setup -class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { +class NeuralnetworksHidlEnvironment : public testing::VtsHalHidlTargetTestEnvBase { DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment); NeuralnetworksHidlEnvironment() = default; @@ -43,27 +39,23 @@ class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvB }; // The main test class for NEURALNETWORKS HIDL HAL. -class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class NeuralnetworksHidlTest : public testing::VtsHalHidlTargetTestBase { DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest); public: NeuralnetworksHidlTest() = default; void SetUp() override; - void TearDown() override; protected: - const sp device = ::testing::VtsHalHidlTargetTestBase::getService( + const sp kDevice = testing::VtsHalHidlTargetTestBase::getService( NeuralnetworksHidlEnvironment::getInstance()); }; +// Create an IPreparedModel object. If the model cannot be prepared, +// "preparedModel" will be nullptr instead. +void createPreparedModel(const sp& device, const Model& model, + sp* preparedModel); + } // namespace android::hardware::neuralnetworks::V1_0::vts::functional -namespace android::hardware::neuralnetworks::V1_0 { - -// pretty-print values for error messages -::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus); -::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus); - -} // namespace android::hardware::neuralnetworks::V1_0 - #endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_VTS_HAL_NEURALNETWORKS_H diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h index 274cb584ea..1ce751c54c 100644 --- a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h +++ b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "TestHarness.h" @@ -52,4 +53,12 @@ inline uint32_t hidl_vec_push_back(hidl_vec* vec, const Type& value) { } // namespace android::hardware::neuralnetworks +namespace android::hardware::neuralnetworks::V1_0 { + +// pretty-print values for error messages +::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus); +::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus); + +} // namespace android::hardware::neuralnetworks::V1_0 + #endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H diff --git a/neuralnetworks/1.1/vts/functional/BasicTests.cpp b/neuralnetworks/1.1/vts/functional/BasicTests.cpp index c239c510fd..2791e804c3 100644 --- a/neuralnetworks/1.1/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.1/vts/functional/BasicTests.cpp @@ -28,7 +28,7 @@ TEST_F(NeuralnetworksHidlTest, CreateDevice) {} // status test TEST_F(NeuralnetworksHidlTest, StatusTest) { - Return status = device->getStatus(); + Return status = kDevice->getStatus(); ASSERT_TRUE(status.isOk()); EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast(status)); } @@ -36,7 +36,7 @@ TEST_F(NeuralnetworksHidlTest, StatusTest) { // initialization TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) { Return ret = - device->getCapabilities_1_1([](ErrorStatus status, const Capabilities& capabilities) { + kDevice->getCapabilities_1_1([](ErrorStatus status, const Capabilities& capabilities) { EXPECT_EQ(ErrorStatus::NONE, status); EXPECT_LT(0.0f, capabilities.float32Performance.execTime); EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage); diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp index 6ed5bc1274..fddfc2bb28 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp @@ -130,9 +130,15 @@ Model createModel(const TestModel& testModel) { // Top level driver for models and examples generated by test_generator.py // Test driver for those generated from ml/nn/runtime/test/spec -void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel) { +void Execute(const sp& device, const TestModel& testModel) { + const Model model = createModel(testModel); const Request request = createRequest(testModel); + // Create IPreparedModel. + sp preparedModel; + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; + // Launch execution. sp executionCallback = new ExecutionCallback(); Return executionLaunchStatus = preparedModel->execute(request, executionCallback); @@ -151,53 +157,10 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo } // Tag for the generated tests -class GeneratedTest : public GeneratedTestBase { - protected: - void Execute(const TestModel& testModel) { - Model model = createModel(testModel); - - // see if service can handle model - bool fullySupportsModel = false; - Return supportedCall = device->getSupportedOperations_1_1( - model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { - ASSERT_EQ(ErrorStatus::NONE, status); - ASSERT_NE(0ul, supported.size()); - fullySupportsModel = std::all_of(supported.begin(), supported.end(), - [](bool valid) { return valid; }); - }); - ASSERT_TRUE(supportedCall.isOk()); - - // launch prepare model - sp preparedModelCallback = new PreparedModelCallback(); - Return prepareLaunchStatus = device->prepareModel_1_1( - model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback); - ASSERT_TRUE(prepareLaunchStatus.isOk()); - ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); - - // retrieve prepared model - preparedModelCallback->wait(); - ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); - sp preparedModel = preparedModelCallback->getPreparedModel(); - - // early termination if vendor service cannot fully prepare model - if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { - ASSERT_EQ(nullptr, preparedModel.get()); - LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " - "prepare model that it does not support."; - std::cout << "[ ] Early termination of test because vendor service cannot " - "prepare model that it does not support." - << std::endl; - GTEST_SKIP(); - } - EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); - ASSERT_NE(nullptr, preparedModel.get()); - - EvaluatePreparedModel(preparedModel, testModel); - } -}; +class GeneratedTest : public GeneratedTestBase {}; TEST_P(GeneratedTest, Test) { - Execute(*mTestModel); + Execute(kDevice, kTestModel); } INSTANTIATE_GENERATED_TEST(GeneratedTest, diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h index 7cb9bdce2c..273d1ec66a 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h @@ -25,33 +25,20 @@ namespace android::hardware::neuralnetworks::V1_1::vts::functional { class GeneratedTestBase : public NeuralnetworksHidlTest, - public ::testing::WithParamInterface { + public testing::WithParamInterface { protected: - void SetUp() override { - NeuralnetworksHidlTest::SetUp(); - ASSERT_NE(mTestModel, nullptr); - } - - const test_helper::TestModel* mTestModel = GetParam().second; + const test_helper::TestModel& kTestModel = *GetParam().second; }; -#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ - INSTANTIATE_TEST_SUITE_P( \ - TestGenerated, TestSuite, \ - ::testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \ +#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ + INSTANTIATE_TEST_SUITE_P( \ + TestGenerated, TestSuite, \ + testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \ [](const auto& info) { return info.param.first; }) // Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp. // TODO: Clean up the hierarchy for ValidationTest. -class ValidationTest : public GeneratedTestBase { - protected: - void validateEverything(const Model& model, const V1_0::Request& request); - - private: - void validateModel(const Model& model); - void validateRequest(const sp& preparedModel, - const V1_0::Request& request); -}; +class ValidationTest : public GeneratedTestBase {}; Model createModel(const ::test_helper::TestModel& testModel); diff --git a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp index e617219480..0629a1edf9 100644 --- a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp @@ -33,7 +33,7 @@ using V1_0::implementation::PreparedModelCallback; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// static void validateGetSupportedOperations(const sp& device, const std::string& message, - const V1_1::Model& model) { + const Model& model) { SCOPED_TRACE(message + " [getSupportedOperations_1_1]"); Return ret = device->getSupportedOperations_1_1( @@ -44,7 +44,7 @@ static void validateGetSupportedOperations(const sp& device, const std: } static void validatePrepareModel(const sp& device, const std::string& message, - const V1_1::Model& model, ExecutionPreference preference) { + const Model& model, ExecutionPreference preference) { SCOPED_TRACE(message + " [prepareModel_1_1]"); sp preparedModelCallback = new PreparedModelCallback(); @@ -70,7 +70,7 @@ static bool validExecutionPreference(ExecutionPreference preference) { // mutation to it to invalidate the model, then pass it to interface calls that // use the model. Note that the model here is passed by value, and any mutation // to the model does not leave this function. -static void validate(const sp& device, const std::string& message, V1_1::Model model, +static void validate(const sp& device, const std::string& message, Model model, const std::function& mutation, ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) { mutation(&model); @@ -109,7 +109,7 @@ static const int32_t invalidOperandTypes[] = { static_cast(OperandType::TENSOR_OEM_BYTE) + 1, // upper bound OEM }; -static void mutateOperandTypeTest(const sp& device, const V1_1::Model& model) { +static void mutateOperandTypeTest(const sp& device, const Model& model) { for (size_t operand = 0; operand < model.operands.size(); ++operand) { for (int32_t invalidOperandType : invalidOperandTypes) { const std::string message = "mutateOperandTypeTest: operand " + @@ -139,7 +139,7 @@ static uint32_t getInvalidRank(OperandType type) { } } -static void mutateOperandRankTest(const sp& device, const V1_1::Model& model) { +static void mutateOperandRankTest(const sp& device, const Model& model) { for (size_t operand = 0; operand < model.operands.size(); ++operand) { const uint32_t invalidRank = getInvalidRank(model.operands[operand].type); const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) + @@ -168,7 +168,7 @@ static float getInvalidScale(OperandType type) { } } -static void mutateOperandScaleTest(const sp& device, const V1_1::Model& model) { +static void mutateOperandScaleTest(const sp& device, const Model& model) { for (size_t operand = 0; operand < model.operands.size(); ++operand) { const float invalidScale = getInvalidScale(model.operands[operand].type); const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) + @@ -196,7 +196,7 @@ static std::vector getInvalidZeroPoints(OperandType type) { } } -static void mutateOperandZeroPointTest(const sp& device, const V1_1::Model& model) { +static void mutateOperandZeroPointTest(const sp& device, const Model& model) { for (size_t operand = 0; operand < model.operands.size(); ++operand) { const std::vector invalidZeroPoints = getInvalidZeroPoints(model.operands[operand].type); @@ -253,7 +253,7 @@ static void mutateOperand(Operand* operand, OperandType type) { *operand = newOperand; } -static bool mutateOperationOperandTypeSkip(size_t operand, const V1_1::Model& model) { +static bool mutateOperationOperandTypeSkip(size_t operand, const Model& model) { // LSH_PROJECTION's second argument is allowed to have any type. This is the // only operation that currently has a type that can be anything independent // from any other type. Changing the operand type to any other type will @@ -267,7 +267,7 @@ static bool mutateOperationOperandTypeSkip(size_t operand, const V1_1::Model& mo return false; } -static void mutateOperationOperandTypeTest(const sp& device, const V1_1::Model& model) { +static void mutateOperationOperandTypeTest(const sp& device, const Model& model) { for (size_t operand = 0; operand < model.operands.size(); ++operand) { if (mutateOperationOperandTypeSkip(operand, model)) { continue; @@ -298,7 +298,7 @@ static const int32_t invalidOperationTypes[] = { static_cast(OperationType::OEM_OPERATION) + 1, // upper bound OEM }; -static void mutateOperationTypeTest(const sp& device, const V1_1::Model& model) { +static void mutateOperationTypeTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { for (int32_t invalidOperationType : invalidOperationTypes) { const std::string message = "mutateOperationTypeTest: operation " + @@ -314,8 +314,7 @@ static void mutateOperationTypeTest(const sp& device, const V1_1::Model ///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX ///////////////////////// -static void mutateOperationInputOperandIndexTest(const sp& device, - const V1_1::Model& model) { +static void mutateOperationInputOperandIndexTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { const uint32_t invalidOperand = model.operands.size(); for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) { @@ -331,8 +330,7 @@ static void mutateOperationInputOperandIndexTest(const sp& device, ///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX ///////////////////////// -static void mutateOperationOutputOperandIndexTest(const sp& device, - const V1_1::Model& model) { +static void mutateOperationOutputOperandIndexTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { const uint32_t invalidOperand = model.operands.size(); for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) { @@ -370,7 +368,7 @@ static void removeOperand(Model* model, uint32_t index) { removeValueAndDecrementGreaterValues(&model->outputIndexes, index); } -static void removeOperandTest(const sp& device, const V1_1::Model& model) { +static void removeOperandTest(const sp& device, const Model& model) { for (size_t operand = 0; operand < model.operands.size(); ++operand) { const std::string message = "removeOperandTest: operand " + std::to_string(operand); validate(device, message, model, @@ -387,7 +385,7 @@ static void removeOperation(Model* model, uint32_t index) { hidl_vec_removeAt(&model->operations, index); } -static void removeOperationTest(const sp& device, const V1_1::Model& model) { +static void removeOperationTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { const std::string message = "removeOperationTest: operation " + std::to_string(operation); validate(device, message, model, @@ -397,14 +395,14 @@ static void removeOperationTest(const sp& device, const V1_1::Model& mo ///////////////////////// REMOVE OPERATION INPUT ///////////////////////// -static void removeOperationInputTest(const sp& device, const V1_1::Model& model) { +static void removeOperationInputTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) { - const V1_1::Operation& op = model.operations[operation]; + const Operation& op = model.operations[operation]; // CONCATENATION has at least 2 inputs, with the last element being // INT32. Skip this test if removing one of CONCATENATION's // inputs still produces a valid model. - if (op.type == V1_1::OperationType::CONCATENATION && op.inputs.size() > 2 && + if (op.type == OperationType::CONCATENATION && op.inputs.size() > 2 && input != op.inputs.size() - 1) { continue; } @@ -422,7 +420,7 @@ static void removeOperationInputTest(const sp& device, const V1_1::Mode ///////////////////////// REMOVE OPERATION OUTPUT ///////////////////////// -static void removeOperationOutputTest(const sp& device, const V1_1::Model& model) { +static void removeOperationOutputTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) { const std::string message = "removeOperationOutputTest: operation " + @@ -443,7 +441,7 @@ static void removeOperationOutputTest(const sp& device, const V1_1::Mod ///////////////////////// ADD OPERATION INPUT ///////////////////////// -static void addOperationInputTest(const sp& device, const V1_1::Model& model) { +static void addOperationInputTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { const std::string message = "addOperationInputTest: operation " + std::to_string(operation); validate(device, message, model, [operation](Model* model) { @@ -456,7 +454,7 @@ static void addOperationInputTest(const sp& device, const V1_1::Model& ///////////////////////// ADD OPERATION OUTPUT ///////////////////////// -static void addOperationOutputTest(const sp& device, const V1_1::Model& model) { +static void addOperationOutputTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { const std::string message = "addOperationOutputTest: operation " + std::to_string(operation); @@ -475,7 +473,7 @@ static const int32_t invalidExecutionPreferences[] = { static_cast(ExecutionPreference::SUSTAINED_SPEED) + 1, // upper bound }; -static void mutateExecutionPreferenceTest(const sp& device, const V1_1::Model& model) { +static void mutateExecutionPreferenceTest(const sp& device, const Model& model) { for (int32_t preference : invalidExecutionPreferences) { const std::string message = "mutateExecutionPreferenceTest: preference " + std::to_string(preference); @@ -487,7 +485,7 @@ static void mutateExecutionPreferenceTest(const sp& device, const V1_1: ////////////////////////// ENTRY POINT ////////////////////////////// -void ValidationTest::validateModel(const V1_1::Model& model) { +void validateModel(const sp& device, const Model& model) { mutateOperandTypeTest(device, model); mutateOperandRankTest(device, model); mutateOperandScaleTest(device, model); diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp index a4e4ade84f..9684eb2b30 100644 --- a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp @@ -71,8 +71,7 @@ static void removeOutputTest(const sp& preparedModel, const Requ ///////////////////////////// ENTRY POINT ////////////////////////////////// -void ValidationTest::validateRequest(const sp& preparedModel, - const Request& request) { +void validateRequest(const sp& preparedModel, const Request& request) { removeInputTest(preparedModel, request); removeOutputTest(preparedModel, request); } diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp index 2c1a839cc9..d53d43e0b6 100644 --- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp @@ -31,31 +31,32 @@ using V1_0::IPreparedModel; using V1_0::Request; using V1_0::implementation::PreparedModelCallback; -static void createPreparedModel(const sp& device, const Model& model, - sp* preparedModel) { +void createPreparedModel(const sp& device, const Model& model, + sp* preparedModel) { ASSERT_NE(nullptr, preparedModel); + *preparedModel = nullptr; // see if service can handle model bool fullySupportsModel = false; - Return supportedOpsLaunchStatus = device->getSupportedOperations_1_1( + const Return supportedCall = device->getSupportedOperations_1_1( model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { ASSERT_EQ(ErrorStatus::NONE, status); ASSERT_NE(0ul, supported.size()); fullySupportsModel = std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; }); }); - ASSERT_TRUE(supportedOpsLaunchStatus.isOk()); + ASSERT_TRUE(supportedCall.isOk()); // launch prepare model - sp preparedModelCallback = new PreparedModelCallback(); - Return prepareLaunchStatus = device->prepareModel_1_1( + const sp preparedModelCallback = new PreparedModelCallback(); + const Return prepareLaunchStatus = device->prepareModel_1_1( model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); // retrieve prepared model preparedModelCallback->wait(); - ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); *preparedModel = preparedModelCallback->getPreparedModel(); // The getSupportedOperations_1_1 call returns a list of operations that are @@ -67,12 +68,12 @@ static void createPreparedModel(const sp& device, const Model& model, // can continue. if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { ASSERT_EQ(nullptr, preparedModel->get()); - LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot " - "prepare model that it does not support."; - std::cout << "[ ] Unable to test Request validation because vendor service " - "cannot prepare model that it does not support." + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot prepare " + "model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "prepare model that it does not support." << std::endl; - return; + GTEST_SKIP(); } ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus); ASSERT_NE(nullptr, preparedModel->get()); @@ -81,7 +82,7 @@ static void createPreparedModel(const sp& device, const Model& model, // A class for test environment setup NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() { // This has to return a "new" object because it is freed inside - // ::testing::AddGlobalTestEnvironment when the gtest is being torn down + // testing::AddGlobalTestEnvironment when the gtest is being torn down static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment(); return instance; } @@ -92,65 +93,52 @@ void NeuralnetworksHidlEnvironment::registerTestServices() { // The main test class for NEURALNETWORK HIDL HAL. void NeuralnetworksHidlTest::SetUp() { - ::testing::VtsHalHidlTargetTestBase::SetUp(); + testing::VtsHalHidlTargetTestBase::SetUp(); #ifdef PRESUBMIT_NOT_VTS const std::string name = NeuralnetworksHidlEnvironment::getInstance()->getServiceName(); const std::string sampleDriver = "sample-"; - if (device == nullptr && name.substr(0, sampleDriver.size()) == sampleDriver) { + if (kDevice == nullptr && name.substr(0, sampleDriver.size()) == sampleDriver) { GTEST_SKIP(); } #endif // PRESUBMIT_NOT_VTS - ASSERT_NE(nullptr, device.get()); + ASSERT_NE(nullptr, kDevice.get()); } -void NeuralnetworksHidlTest::TearDown() { - ::testing::VtsHalHidlTargetTestBase::TearDown(); -} +// Forward declaration from ValidateModel.cpp +void validateModel(const sp& device, const Model& model); +// Forward declaration from ValidateRequest.cpp +void validateRequest(const sp& preparedModel, const V1_0::Request& request); -void ValidationTest::validateEverything(const Model& model, const Request& request) { - validateModel(model); +void validateEverything(const sp& device, const Model& model, const Request& request) { + validateModel(device, model); - // create IPreparedModel + // Create IPreparedModel. sp preparedModel; - ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel)); - if (preparedModel == nullptr) { - return; - } + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; validateRequest(preparedModel, request); } TEST_P(ValidationTest, Test) { - const Model model = createModel(*mTestModel); - const Request request = createRequest(*mTestModel); - ASSERT_FALSE(mTestModel->expectFailure); - validateEverything(model, request); + const Model model = createModel(kTestModel); + const Request request = createRequest(kTestModel); + ASSERT_FALSE(kTestModel.expectFailure); + validateEverything(kDevice, model, request); } INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); } // namespace android::hardware::neuralnetworks::V1_1::vts::functional -namespace android::hardware::neuralnetworks::V1_0 { - -::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus) { - return os << toString(errorStatus); -} - -::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus) { - return os << toString(deviceStatus); -} - -} // namespace android::hardware::neuralnetworks::V1_0 - using android::hardware::neuralnetworks::V1_1::vts::functional::NeuralnetworksHidlEnvironment; int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance()); - ::testing::InitGoogleTest(&argc, argv); + testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance()); + testing::InitGoogleTest(&argc, argv); NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv); int status = RUN_ALL_TESTS(); diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h index 3d6f2eab6f..9d6194a143 100644 --- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h @@ -26,15 +26,11 @@ #include #include -#include -#include - -#include "TestHarness.h" namespace android::hardware::neuralnetworks::V1_1::vts::functional { // A class for test environment setup -class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { +class NeuralnetworksHidlEnvironment : public testing::VtsHalHidlTargetTestEnvBase { DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment); NeuralnetworksHidlEnvironment() = default; @@ -44,27 +40,23 @@ class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvB }; // The main test class for NEURALNETWORKS HIDL HAL. -class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class NeuralnetworksHidlTest : public testing::VtsHalHidlTargetTestBase { DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest); public: NeuralnetworksHidlTest() = default; void SetUp() override; - void TearDown() override; protected: - const sp device = ::testing::VtsHalHidlTargetTestBase::getService( + const sp kDevice = testing::VtsHalHidlTargetTestBase::getService( NeuralnetworksHidlEnvironment::getInstance()); }; +// Create an IPreparedModel object. If the model cannot be prepared, +// "preparedModel" will be nullptr instead. +void createPreparedModel(const sp& device, const Model& model, + sp* preparedModel); + } // namespace android::hardware::neuralnetworks::V1_1::vts::functional -namespace android::hardware::neuralnetworks::V1_0 { - -// pretty-print values for error messages -::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus); -::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus); - -} // namespace android::hardware::neuralnetworks::V1_0 - #endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_1_VTS_HAL_NEURALNETWORKS_H diff --git a/neuralnetworks/1.2/vts/functional/BasicTests.cpp b/neuralnetworks/1.2/vts/functional/BasicTests.cpp index 86849d566a..8f95b96c52 100644 --- a/neuralnetworks/1.2/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.2/vts/functional/BasicTests.cpp @@ -29,7 +29,7 @@ TEST_F(NeuralnetworksHidlTest, CreateDevice) {} // status test TEST_F(NeuralnetworksHidlTest, StatusTest) { - Return status = device->getStatus(); + Return status = kDevice->getStatus(); ASSERT_TRUE(status.isOk()); EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast(status)); } @@ -37,8 +37,8 @@ TEST_F(NeuralnetworksHidlTest, StatusTest) { // initialization TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) { using OperandPerformance = Capabilities::OperandPerformance; - Return ret = device->getCapabilities_1_2([](ErrorStatus status, - const Capabilities& capabilities) { + Return ret = kDevice->getCapabilities_1_2([](ErrorStatus status, + const Capabilities& capabilities) { EXPECT_EQ(ErrorStatus::NONE, status); auto isPositive = [](const PerformanceInfo& perf) { @@ -61,16 +61,17 @@ TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) { // device version test TEST_F(NeuralnetworksHidlTest, GetDeviceVersionStringTest) { - Return ret = device->getVersionString([](ErrorStatus status, const hidl_string& version) { - EXPECT_EQ(ErrorStatus::NONE, status); - EXPECT_LT(0, version.size()); - }); + Return ret = + kDevice->getVersionString([](ErrorStatus status, const hidl_string& version) { + EXPECT_EQ(ErrorStatus::NONE, status); + EXPECT_LT(0, version.size()); + }); EXPECT_TRUE(ret.isOk()); } // device type test TEST_F(NeuralnetworksHidlTest, GetDeviceTypeTest) { - Return ret = device->getType([](ErrorStatus status, DeviceType type) { + Return ret = kDevice->getType([](ErrorStatus status, DeviceType type) { EXPECT_EQ(ErrorStatus::NONE, status); EXPECT_TRUE(type == DeviceType::OTHER || type == DeviceType::CPU || type == DeviceType::GPU || type == DeviceType::ACCELERATOR); @@ -80,7 +81,7 @@ TEST_F(NeuralnetworksHidlTest, GetDeviceTypeTest) { // device supported extensions test TEST_F(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) { - Return ret = device->getSupportedExtensions( + Return ret = kDevice->getSupportedExtensions( [](ErrorStatus status, const hidl_vec& extensions) { EXPECT_EQ(ErrorStatus::NONE, status); for (auto& extension : extensions) { @@ -101,7 +102,7 @@ TEST_F(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) { // getNumberOfCacheFilesNeeded test TEST_F(NeuralnetworksHidlTest, getNumberOfCacheFilesNeeded) { - Return ret = device->getNumberOfCacheFilesNeeded( + Return ret = kDevice->getNumberOfCacheFilesNeeded( [](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) { EXPECT_EQ(ErrorStatus::NONE, status); EXPECT_LE(numModelCache, diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp index 90872d4cc5..bb46e06d6f 100644 --- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp @@ -223,7 +223,7 @@ class CompilationCachingTestBase : public NeuralnetworksHidlTest { void SetUp() override { NeuralnetworksHidlTest::SetUp(); - ASSERT_NE(device.get(), nullptr); + ASSERT_NE(kDevice.get(), nullptr); // Create cache directory. The cache directory and a temporary cache file is always created // to test the behavior of prepareModelFromCache, even when caching is not supported. @@ -233,7 +233,7 @@ class CompilationCachingTestBase : public NeuralnetworksHidlTest { mCacheDir = cacheDir; mCacheDir.push_back('/'); - Return ret = device->getNumberOfCacheFilesNeeded( + Return ret = kDevice->getNumberOfCacheFilesNeeded( [this](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) { EXPECT_EQ(ErrorStatus::NONE, status); mNumModelCache = numModelCache; @@ -267,7 +267,7 @@ class CompilationCachingTestBase : public NeuralnetworksHidlTest { void TearDown() override { // If the test passes, remove the tmp directory. Otherwise, keep it for debugging purposes. - if (!::testing::Test::HasFailure()) { + if (!testing::Test::HasFailure()) { // Recursively remove the cache directory specified by mCacheDir. auto callback = [](const char* entry, const struct stat*, int, struct FTW*) { return remove(entry); @@ -300,7 +300,7 @@ class CompilationCachingTestBase : public NeuralnetworksHidlTest { // See if the service can handle the model. bool isModelFullySupported(const Model& model) { bool fullySupportsModel = false; - Return supportedCall = device->getSupportedOperations_1_2( + Return supportedCall = kDevice->getSupportedOperations_1_2( model, [&fullySupportsModel, &model](ErrorStatus status, const hidl_vec& supported) { ASSERT_EQ(ErrorStatus::NONE, status); @@ -321,8 +321,8 @@ class CompilationCachingTestBase : public NeuralnetworksHidlTest { sp preparedModelCallback = new PreparedModelCallback(); hidl_array cacheToken(mToken); Return prepareLaunchStatus = - device->prepareModel_1_2(model, ExecutionPreference::FAST_SINGLE_ANSWER, modelCache, - dataCache, cacheToken, preparedModelCallback); + kDevice->prepareModel_1_2(model, ExecutionPreference::FAST_SINGLE_ANSWER, + modelCache, dataCache, cacheToken, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(static_cast(prepareLaunchStatus), ErrorStatus::NONE); @@ -365,7 +365,7 @@ class CompilationCachingTestBase : public NeuralnetworksHidlTest { // Launch prepare model from cache. sp preparedModelCallback = new PreparedModelCallback(); hidl_array cacheToken(mToken); - Return prepareLaunchStatus = device->prepareModelFromCache( + Return prepareLaunchStatus = kDevice->prepareModelFromCache( modelCache, dataCache, cacheToken, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); if (static_cast(prepareLaunchStatus) != ErrorStatus::NONE) { @@ -405,7 +405,7 @@ class CompilationCachingTestBase : public NeuralnetworksHidlTest { // A parameterized fixture of CompilationCachingTestBase. Every test will run twice, with the first // pass running with float32 models and the second pass running with quant8 models. class CompilationCachingTest : public CompilationCachingTestBase, - public ::testing::WithParamInterface { + public testing::WithParamInterface { protected: CompilationCachingTest() : CompilationCachingTestBase(GetParam()) {} }; @@ -1193,13 +1193,13 @@ TEST_P(CompilationCachingTest, ReplaceSecuritySensitiveCache) { } static const auto kOperandTypeChoices = - ::testing::Values(OperandType::TENSOR_FLOAT32, OperandType::TENSOR_QUANT8_ASYMM); + testing::Values(OperandType::TENSOR_FLOAT32, OperandType::TENSOR_QUANT8_ASYMM); INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingTest, kOperandTypeChoices); class CompilationCachingSecurityTest : public CompilationCachingTestBase, - public ::testing::WithParamInterface> { + public testing::WithParamInterface> { protected: CompilationCachingSecurityTest() : CompilationCachingTestBase(std::get<0>(GetParam())) {} @@ -1339,6 +1339,6 @@ TEST_P(CompilationCachingSecurityTest, WrongToken) { } INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest, - ::testing::Combine(kOperandTypeChoices, ::testing::Range(0U, 10U))); + testing::Combine(kOperandTypeChoices, testing::Range(0U, 10U))); } // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp index b8ca080e5a..a2d37920d5 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp @@ -358,74 +358,31 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo } } -void PrepareModel(const sp& device, const Model& model, - sp* preparedModel) { - // see if service can handle model - bool fullySupportsModel = false; - Return supportedCall = device->getSupportedOperations_1_2( - model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { - ASSERT_EQ(ErrorStatus::NONE, status); - ASSERT_NE(0ul, supported.size()); - fullySupportsModel = std::all_of(supported.begin(), supported.end(), - [](bool valid) { return valid; }); - }); - ASSERT_TRUE(supportedCall.isOk()); - - // launch prepare model - sp preparedModelCallback = new PreparedModelCallback(); - Return prepareLaunchStatus = device->prepareModel_1_2( - model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec(), - hidl_vec(), HidlToken(), preparedModelCallback); - ASSERT_TRUE(prepareLaunchStatus.isOk()); - ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); - - // retrieve prepared model - preparedModelCallback->wait(); - ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); - sp preparedModelV1_0 = preparedModelCallback->getPreparedModel(); - *preparedModel = IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr); - - // early termination if vendor service cannot fully prepare model - if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { - ASSERT_EQ(nullptr, preparedModel->get()); - LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " - "prepare model that it does not support."; - std::cout << "[ ] Early termination of test because vendor service cannot " - "prepare model that it does not support." - << std::endl; - return; +void Execute(const sp& device, const TestModel& testModel, bool testDynamicOutputShape) { + Model model = createModel(testModel); + if (testDynamicOutputShape) { + makeOutputDimensionsUnspecified(&model); } - EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); - ASSERT_NE(nullptr, preparedModel->get()); + + sp preparedModel; + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; + + EvaluatePreparedModel(preparedModel, testModel, testDynamicOutputShape); } // Tag for the generated tests -class GeneratedTest : public GeneratedTestBase { - protected: - void Execute(const TestModel& testModel, bool testDynamicOutputShape) { - Model model = createModel(testModel); - if (testDynamicOutputShape) { - makeOutputDimensionsUnspecified(&model); - } - - sp preparedModel = nullptr; - PrepareModel(device, model, &preparedModel); - if (preparedModel == nullptr) { - GTEST_SKIP(); - } - EvaluatePreparedModel(preparedModel, testModel, testDynamicOutputShape); - } -}; +class GeneratedTest : public GeneratedTestBase {}; // Tag for the dynamic output shape tests class DynamicOutputShapeTest : public GeneratedTest {}; TEST_P(GeneratedTest, Test) { - Execute(*mTestModel, /*testDynamicOutputShape=*/false); + Execute(kDevice, kTestModel, /*testDynamicOutputShape=*/false); } TEST_P(DynamicOutputShapeTest, Test) { - Execute(*mTestModel, /*testDynamicOutputShape=*/true); + Execute(kDevice, kTestModel, /*testDynamicOutputShape=*/true); } INSTANTIATE_GENERATED_TEST(GeneratedTest, diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h index cb01b91cfd..0b8b917b0a 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h @@ -29,36 +29,20 @@ namespace android::hardware::neuralnetworks::V1_2::vts::functional { class GeneratedTestBase : public NeuralnetworksHidlTest, - public ::testing::WithParamInterface { + public testing::WithParamInterface { protected: - void SetUp() override { - NeuralnetworksHidlTest::SetUp(); - ASSERT_NE(mTestModel, nullptr); - } - - const test_helper::TestModel* mTestModel = GetParam().second; + const test_helper::TestModel& kTestModel = *GetParam().second; }; -#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ - INSTANTIATE_TEST_SUITE_P( \ - TestGenerated, TestSuite, \ - ::testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \ +#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ + INSTANTIATE_TEST_SUITE_P( \ + TestGenerated, TestSuite, \ + testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \ [](const auto& info) { return info.param.first; }) // Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp. // TODO: Clean up the hierarchy for ValidationTest. -class ValidationTest : public GeneratedTestBase { - protected: - void validateEverything(const Model& model, const V1_0::Request& request); - void validateFailure(const Model& model, const V1_0::Request& request); - - private: - void validateModel(const Model& model); - void validateRequest(const sp& preparedModel, const V1_0::Request& request); - void validateRequestFailure(const sp& preparedModel, - const V1_0::Request& request); - void validateBurst(const sp& preparedModel, const V1_0::Request& request); -}; +class ValidationTest : public GeneratedTestBase {}; Model createModel(const ::test_helper::TestModel& testModel); diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp index 844e87986d..c02d0206e2 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp @@ -391,8 +391,7 @@ static void validateBurstSanitized(const sp& preparedModel, ///////////////////////////// ENTRY POINT ////////////////////////////////// -void ValidationTest::validateBurst(const sp& preparedModel, - const Request& request) { +void validateBurst(const sp& preparedModel, const Request& request) { ASSERT_NO_FATAL_FAILURE(validateBurstSerialization(preparedModel, request)); ASSERT_NO_FATAL_FAILURE(validateBurstFmqLength(preparedModel, request)); ASSERT_NO_FATAL_FAILURE(validateBurstSanitized(preparedModel, request)); diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp index 74840a6790..30530beacc 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp @@ -692,7 +692,7 @@ static void mutateExecutionPreferenceTest(const sp& device, const Model ////////////////////////// ENTRY POINT ////////////////////////////// -void ValidationTest::validateModel(const Model& model) { +void validateModel(const sp& device, const Model& model) { mutateOperandTypeTest(device, model); mutateOperandRankTest(device, model); mutateOperandScaleTest(device, model); diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp index 684b43366a..5c52de5834 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp @@ -148,14 +148,12 @@ static void removeOutputTest(const sp& preparedModel, const Requ ///////////////////////////// ENTRY POINT ////////////////////////////////// -void ValidationTest::validateRequest(const sp& preparedModel, - const Request& request) { +void validateRequest(const sp& preparedModel, const Request& request) { removeInputTest(preparedModel, request); removeOutputTest(preparedModel, request); } -void ValidationTest::validateRequestFailure(const sp& preparedModel, - const Request& request) { +void validateRequestFailure(const sp& preparedModel, const Request& request) { SCOPED_TRACE("Expecting request to fail [executeSynchronously]"); Return executeStatus = preparedModel->executeSynchronously( request, MeasureTiming::NO, diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp index ea9d684be8..aa4f1f20b8 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp @@ -33,24 +33,25 @@ using V1_0::Request; using V1_1::ExecutionPreference; // internal helper function -static void createPreparedModel(const sp& device, const Model& model, - sp* preparedModel) { +void createPreparedModel(const sp& device, const Model& model, + sp* preparedModel) { ASSERT_NE(nullptr, preparedModel); + *preparedModel = nullptr; // see if service can handle model bool fullySupportsModel = false; - Return supportedOpsLaunchStatus = device->getSupportedOperations_1_2( + const Return supportedCall = device->getSupportedOperations_1_2( model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { ASSERT_EQ(ErrorStatus::NONE, status); ASSERT_NE(0ul, supported.size()); fullySupportsModel = std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; }); }); - ASSERT_TRUE(supportedOpsLaunchStatus.isOk()); + ASSERT_TRUE(supportedCall.isOk()); // launch prepare model - sp preparedModelCallback = new PreparedModelCallback(); - Return prepareLaunchStatus = device->prepareModel_1_2( + const sp preparedModelCallback = new PreparedModelCallback(); + const Return prepareLaunchStatus = device->prepareModel_1_2( model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec(), hidl_vec(), HidlToken(), preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); @@ -58,7 +59,7 @@ static void createPreparedModel(const sp& device, const Model& model, // retrieve prepared model preparedModelCallback->wait(); - ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); *preparedModel = getPreparedModel_1_2(preparedModelCallback); // The getSupportedOperations_1_2 call returns a list of operations that are @@ -70,12 +71,12 @@ static void createPreparedModel(const sp& device, const Model& model, // can continue. if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { ASSERT_EQ(nullptr, preparedModel->get()); - LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot " - "prepare model that it does not support."; - std::cout << "[ ] Unable to test Request validation because vendor service " - "cannot prepare model that it does not support." + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot prepare " + "model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "prepare model that it does not support." << std::endl; - return; + GTEST_SKIP(); } ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus); ASSERT_NE(nullptr, preparedModel->get()); @@ -84,7 +85,7 @@ static void createPreparedModel(const sp& device, const Model& model, // A class for test environment setup NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() { // This has to return a "new" object because it is freed inside - // ::testing::AddGlobalTestEnvironment when the gtest is being torn down + // testing::AddGlobalTestEnvironment when the gtest is being torn down static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment(); return instance; } @@ -95,59 +96,61 @@ void NeuralnetworksHidlEnvironment::registerTestServices() { // The main test class for NEURALNETWORK HIDL HAL. void NeuralnetworksHidlTest::SetUp() { - ::testing::VtsHalHidlTargetTestBase::SetUp(); + testing::VtsHalHidlTargetTestBase::SetUp(); #ifdef PRESUBMIT_NOT_VTS const std::string name = NeuralnetworksHidlEnvironment::getInstance()->getServiceName(); const std::string sampleDriver = "sample-"; - if (device == nullptr && name.substr(0, sampleDriver.size()) == sampleDriver) { + if (kDevice == nullptr && name.substr(0, sampleDriver.size()) == sampleDriver) { GTEST_SKIP(); } #endif // PRESUBMIT_NOT_VTS - ASSERT_NE(nullptr, device.get()); + ASSERT_NE(nullptr, kDevice.get()); } -void NeuralnetworksHidlTest::TearDown() { - ::testing::VtsHalHidlTargetTestBase::TearDown(); -} +// Forward declaration from ValidateModel.cpp +void validateModel(const sp& device, const Model& model); +// Forward declaration from ValidateRequest.cpp +void validateRequest(const sp& preparedModel, const V1_0::Request& request); +// Forward declaration from ValidateRequest.cpp +void validateRequestFailure(const sp& preparedModel, const V1_0::Request& request); +// Forward declaration from ValidateBurst.cpp +void validateBurst(const sp& preparedModel, const V1_0::Request& request); -void ValidationTest::validateEverything(const Model& model, const Request& request) { - validateModel(model); +void validateEverything(const sp& device, const Model& model, const Request& request) { + validateModel(device, model); - // create IPreparedModel + // Create IPreparedModel. sp preparedModel; - ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel)); - if (preparedModel == nullptr) { - return; - } + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; validateRequest(preparedModel, request); validateBurst(preparedModel, request); } -void ValidationTest::validateFailure(const Model& model, const Request& request) { +void validateFailure(const sp& device, const Model& model, const Request& request) { // TODO: Should this always succeed? // What if the invalid input is part of the model (i.e., a parameter). - validateModel(model); + validateModel(device, model); + // Create IPreparedModel. sp preparedModel; - ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel)); - if (preparedModel == nullptr) { - return; - } + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; validateRequestFailure(preparedModel, request); } TEST_P(ValidationTest, Test) { - const Model model = createModel(*mTestModel); - const Request request = createRequest(*mTestModel); - if (mTestModel->expectFailure) { - validateFailure(model, request); + const Model model = createModel(kTestModel); + const Request request = createRequest(kTestModel); + if (kTestModel.expectFailure) { + validateFailure(kDevice, model, request); } else { - validateEverything(model, request); + validateEverything(kDevice, model, request); } } @@ -160,23 +163,11 @@ sp getPreparedModel_1_2(const spinit(&argc, argv); int status = RUN_ALL_TESTS(); diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h index 4a6d33bc6b..9981696290 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h @@ -26,16 +26,12 @@ #include #include -#include -#include - #include "1.2/Callbacks.h" -#include "TestHarness.h" namespace android::hardware::neuralnetworks::V1_2::vts::functional { // A class for test environment setup -class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { +class NeuralnetworksHidlEnvironment : public testing::VtsHalHidlTargetTestEnvBase { DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment); NeuralnetworksHidlEnvironment() = default; @@ -45,30 +41,26 @@ class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvB }; // The main test class for NEURALNETWORKS HIDL HAL. -class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class NeuralnetworksHidlTest : public testing::VtsHalHidlTargetTestBase { DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest); public: NeuralnetworksHidlTest() = default; void SetUp() override; - void TearDown() override; protected: - const sp device = ::testing::VtsHalHidlTargetTestBase::getService( + const sp kDevice = testing::VtsHalHidlTargetTestBase::getService( NeuralnetworksHidlEnvironment::getInstance()); }; +// Create an IPreparedModel object. If the model cannot be prepared, +// "preparedModel" will be nullptr instead. +void createPreparedModel(const sp& device, const Model& model, + sp* preparedModel); + // Utility function to get PreparedModel from callback and downcast to V1_2. sp getPreparedModel_1_2(const sp& callback); } // namespace android::hardware::neuralnetworks::V1_2::vts::functional -namespace android::hardware::neuralnetworks::V1_0 { - -// pretty-print values for error messages -::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus); -::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus); - -} // namespace android::hardware::neuralnetworks::V1_0 - #endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H From aacbf948544a4dcc489bc59706e15ab4fc7f0d08 Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Fri, 30 Aug 2019 15:21:34 -0400 Subject: [PATCH 0097/1022] Set up shell to use for unit tests Sets up a unit test file that can be used to unit test the HalProxy. The unit tests will eventually end up containing code that injects the fake SensorsSubHal implementation into the HalProxy and verifies various parts of the implementation. This will likely require some modifications to the SensorsSubHal class to modify it during test execution, but it's better that the same implementation is shared between unit / manual integration testing. Test: Run atest android.hardware.sensors@2.0-halproxy-unit-tests Bug: 136511617 Change-Id: I7b6865564ea41ab3c58f77d3168366c95e3289e5 --- sensors/2.0/multihal/Android.bp | 46 +++++++++++++------ sensors/2.0/multihal/HalProxy.cpp | 4 ++ sensors/2.0/multihal/{ => include}/HalProxy.h | 6 ++- .../multihal/{testing => tests}/Android.bp | 42 +++++++++++++++-- sensors/2.0/multihal/tests/HalProxy_test.cpp | 39 ++++++++++++++++ .../{testing => tests/fake_subhal}/README | 0 .../{testing => tests/fake_subhal}/Sensor.cpp | 13 ++++-- .../{testing => tests/fake_subhal}/Sensor.h | 0 .../fake_subhal}/SensorsSubHal.cpp | 0 .../fake_subhal}/SensorsSubHal.h | 0 10 files changed, 126 insertions(+), 24 deletions(-) rename sensors/2.0/multihal/{ => include}/HalProxy.h (96%) rename sensors/2.0/multihal/{testing => tests}/Android.bp (59%) create mode 100644 sensors/2.0/multihal/tests/HalProxy_test.cpp rename sensors/2.0/multihal/{testing => tests/fake_subhal}/README (100%) rename sensors/2.0/multihal/{testing => tests/fake_subhal}/Sensor.cpp (98%) rename sensors/2.0/multihal/{testing => tests/fake_subhal}/Sensor.h (100%) rename sensors/2.0/multihal/{testing => tests/fake_subhal}/SensorsSubHal.cpp (100%) rename sensors/2.0/multihal/{testing => tests/fake_subhal}/SensorsSubHal.h (100%) diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp index dff28abcf0..44dddfd4e9 100644 --- a/sensors/2.0/multihal/Android.bp +++ b/sensors/2.0/multihal/Android.bp @@ -13,18 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -cc_binary { - name: "android.hardware.sensors@2.0-service.multihal", - defaults: ["hidl_defaults"], - vendor: true, - relative_install_path: "hw", - srcs: [ - "service.cpp", - "HalProxy.cpp", - ], - init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"], +cc_defaults { + name: "android.hardware.sensors@2.0-multihal-defaults", header_libs: [ - "android.hardware.sensors@2.0-subhal.header", + "android.hardware.sensors@2.0-multihal.header", ], shared_libs: [ "android.hardware.sensors@1.0", @@ -37,11 +29,39 @@ cc_binary { "libpower", "libutils", ], +} + +cc_binary { + name: "android.hardware.sensors@2.0-service.multihal", + defaults: [ + "hidl_defaults", + "android.hardware.sensors@2.0-multihal-defaults", + ], + vendor: true, + relative_install_path: "hw", + srcs: [ + "service.cpp", + "HalProxy.cpp", + ], + init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"], vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"], } cc_library_headers { - name: "android.hardware.sensors@2.0-subhal.header", - vendor: true, + name: "android.hardware.sensors@2.0-multihal.header", + vendor_available: true, export_include_dirs: ["include"], } + +// The below targets should only be used for testing. +cc_test_library { + name: "android.hardware.sensors@2.0-HalProxy", + defaults: ["android.hardware.sensors@2.0-multihal-defaults"], + vendor_available: true, + srcs: [ + "HalProxy.cpp", + ], + export_header_lib_headers: [ + "android.hardware.sensors@2.0-multihal.header", + ], +} diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index 41c35485b6..80d7296793 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -104,6 +104,10 @@ HalProxy::HalProxy() { // TODO: Discover sensors } +HalProxy::HalProxy(std::vector& subHalList) : mSubHalList(subHalList) { + // TODO: Perform the same steps as the empty constructor. +} + HalProxy::~HalProxy() { // TODO: Join any running threads and clean up FMQs and any other allocated // state. diff --git a/sensors/2.0/multihal/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h similarity index 96% rename from sensors/2.0/multihal/HalProxy.h rename to sensors/2.0/multihal/include/HalProxy.h index e5799fdcd4..9d5787c655 100644 --- a/sensors/2.0/multihal/HalProxy.h +++ b/sensors/2.0/multihal/include/HalProxy.h @@ -46,7 +46,9 @@ struct HalProxy : public ISensors { using Result = ::android::hardware::sensors::V1_0::Result; using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; - HalProxy(); + explicit HalProxy(); + // Test only constructor. + explicit HalProxy(std::vector& subHalList); ~HalProxy(); // Methods from ::android::hardware::sensors::V2_0::ISensors follow. @@ -78,7 +80,7 @@ struct HalProxy : public ISensors { Return debug(const hidl_handle& fd, const hidl_vec& args) override; - // Below methods from ::android::hardware::sensors::V2_0::ISensorsCaback with a minor change + // Below methods from ::android::hardware::sensors::V2_0::ISensorsCallback with a minor change // to pass in the sub-HAL index. While the above methods are invoked from the sensors framework // via the binder, these methods are invoked from a callback provided to sub-HALs inside the // same process as the HalProxy, but potentially running on different threads. diff --git a/sensors/2.0/multihal/testing/Android.bp b/sensors/2.0/multihal/tests/Android.bp similarity index 59% rename from sensors/2.0/multihal/testing/Android.bp rename to sensors/2.0/multihal/tests/Android.bp index 3dedbd69cf..13d80f7a6d 100644 --- a/sensors/2.0/multihal/testing/Android.bp +++ b/sensors/2.0/multihal/tests/Android.bp @@ -15,14 +15,13 @@ cc_defaults { name: "android.hardware.sensors@2.0-fakesubhal-defaults", - vendor: true, srcs: [ - "Sensor.cpp", - "SensorsSubHal.cpp", + "fake_subhal/*.cpp", ], header_libs: [ - "android.hardware.sensors@2.0-subhal.header", + "android.hardware.sensors@2.0-multihal.header", ], + export_include_dirs: ["fake_subhal"], shared_libs: [ "android.hardware.sensors@1.0", "android.hardware.sensors@2.0", @@ -38,6 +37,7 @@ cc_defaults { cc_library { name: "android.hardware.sensors@2.0-fakesubhal-config1", + vendor: true, defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"], cflags: [ "-DSUPPORT_CONTINUOUS_SENSORS", @@ -47,9 +47,43 @@ cc_library { cc_library { name: "android.hardware.sensors@2.0-fakesubhal-config2", + vendor: true, defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"], cflags: [ "-DSUPPORT_ON_CHANGE_SENSORS", "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"", ], +} + +cc_test_library { + name: "android.hardware.sensors@2.0-fakesubhal-unittest", + vendor_available: true, + defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"], + cflags: [ + "-DSUPPORT_ON_CHANGE_SENSORS", + "-DSUPPORT_CONTINUOUS_SENSORS", + "-DSUB_HAL_NAME=\"FakeSubHal-Test\"", + ], +} + +cc_test { + name: "android.hardware.sensors@2.0-halproxy-unit-tests", + srcs: ["HalProxy_test.cpp"], + vendor: true, + static_libs: [ + "android.hardware.sensors@2.0-HalProxy", + "android.hardware.sensors@2.0-fakesubhal-unittest", + ], + shared_libs: [ + "android.hardware.sensors@1.0", + "android.hardware.sensors@2.0", + "libcutils", + "libfmq", + "libhidlbase", + "libhidltransport", + "liblog", + "libpower", + "libutils", + ], + test_suites: ["device-tests"], } \ No newline at end of file diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp new file mode 100644 index 0000000000..9edc88a424 --- /dev/null +++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp @@ -0,0 +1,39 @@ +// +// 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. + +#include + +#include "HalProxy.h" +#include "SensorsSubHal.h" + +using ::android::hardware::sensors::V2_0::implementation::HalProxy; +using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal; + +// TODO: Add more interesting tests such as +// - verify setOperationMode invokes all subhals +// - verify if a subhal fails to change operation mode, that state is reset properly +// - Available sensors are obtained during initialization +// +// You can run this suite using "atest android.hardware.sensors@2.0-halproxy-unit-tests". +// +// See https://source.android.com/compatibility/tests/development/native-func-e2e.md for more info +// on how tests are set up and for information on the gtest framework itself. +TEST(HalProxyTest, ExampleTest) { + SensorsSubHal subHal; + std::vector fakeSubHals; + fakeSubHals.push_back(&subHal); + + HalProxy proxy(fakeSubHals); +} \ No newline at end of file diff --git a/sensors/2.0/multihal/testing/README b/sensors/2.0/multihal/tests/fake_subhal/README similarity index 100% rename from sensors/2.0/multihal/testing/README rename to sensors/2.0/multihal/tests/fake_subhal/README diff --git a/sensors/2.0/multihal/testing/Sensor.cpp b/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp similarity index 98% rename from sensors/2.0/multihal/testing/Sensor.cpp rename to sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp index e095efe0cf..4d536653a9 100644 --- a/sensors/2.0/multihal/testing/Sensor.cpp +++ b/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp @@ -43,11 +43,14 @@ Sensor::Sensor(ISensorsEventCallback* callback) } Sensor::~Sensor() { - std::unique_lock lock(mRunMutex); - mStopThread = true; - mIsEnabled = false; - mWaitCV.notify_all(); - lock.release(); + // Ensure that lock is unlocked before calling mRunThread.join() or a + // deadlock will occur. + { + std::unique_lock lock(mRunMutex); + mStopThread = true; + mIsEnabled = false; + mWaitCV.notify_all(); + } mRunThread.join(); } diff --git a/sensors/2.0/multihal/testing/Sensor.h b/sensors/2.0/multihal/tests/fake_subhal/Sensor.h similarity index 100% rename from sensors/2.0/multihal/testing/Sensor.h rename to sensors/2.0/multihal/tests/fake_subhal/Sensor.h diff --git a/sensors/2.0/multihal/testing/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp similarity index 100% rename from sensors/2.0/multihal/testing/SensorsSubHal.cpp rename to sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp diff --git a/sensors/2.0/multihal/testing/SensorsSubHal.h b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h similarity index 100% rename from sensors/2.0/multihal/testing/SensorsSubHal.h rename to sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h From 2dfa33790358c4efddde77690df28c23b92de449 Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Fri, 23 Aug 2019 10:31:21 -0700 Subject: [PATCH 0098/1022] Add filter function to Demux interface and Add program info to Descrambler bug: 135708935 Test: Manual Change-Id: Iacaebdac6a8ce08ca47ae272be13d51fbd502959 --- tv/tuner/1.0/IDemux.hal | 147 ++++++++++++++++ tv/tuner/1.0/IDemuxCallback.hal | 10 +- tv/tuner/1.0/IDescrambler.hal | 50 +++++- tv/tuner/1.0/ITuner.hal | 1 + tv/tuner/1.0/types.hal | 298 +++++++++++++++++++++++++++++++- 5 files changed, 499 insertions(+), 7 deletions(-) diff --git a/tv/tuner/1.0/IDemux.hal b/tv/tuner/1.0/IDemux.hal index 938bc4456e..2d7b2754ac 100644 --- a/tv/tuner/1.0/IDemux.hal +++ b/tv/tuner/1.0/IDemux.hal @@ -22,6 +22,153 @@ interface IDemux { */ setFrontendDataSource(FrontendId frontendId) generates (Result result); + /** + * Add a filter to the demux + * + * It is used by the client to add a filter to the demux. + * + * @param type the type of the filter to be added. + * @param bufferSize the buffer size of the filter to be added. It's used to + * create a FMQ(Fast Message Queue) to hold data output from the filter. + * @param cb the callback for the filter to be used to send notifications + * back to the client. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + * @return filterId the ID of the newly added filter. + */ + addFilter(DemuxFilterType type, uint32_t bufferSize, IDemuxCallback cb) + generates (Result result, DemuxFilterId filterId); + + /** + * Get the descriptor of the filter's FMQ + * + * It is used by the client to get the descriptor of the filter's Fast + * Message Queue. The data in FMQ is filtered out from MPEG transport + * stream. The data is origanized to data blocks which may have + * different length. The length's information of one or multiple data blocks + * is sent to client throught DemuxFilterEvent. + * + * @param filterId the ID of the filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_ARGUMENT if failed for wrong filter ID. + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + * @return queue the descriptor of the filter's FMQ + */ + getFilterQueueDesc(DemuxFilterId filterId) + generates (Result result, fmq_sync queue); + + /** + * Configure the filter. + * + * It is used by the client to configure the filter so that it can filter out + * intended data. + * + * @param filterId the ID of the filter. + * @param settings the settings of the filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_ARGUMENT if failed for wrong filter ID. + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + configureFilter(DemuxFilterId filterId, DemuxFilterSettings settings) + generates(Result result); + + /** + * Start the filter. + * + * It is used by the client to ask the filter to start filterring data. + * + * @param filterId the ID of the filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_ARGUMENT if failed for wrong filter ID. + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + startFilter(DemuxFilterId filterId) generates (Result result); + + /** + * Stop the filter. + * + * It is used by the client to ask the filter to stop filterring data. + * It won't discard the data already filtered out by the filter. The filter + * will be stopped and removed automatically if the demux is closed. + * + * @param filterId the ID of the filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_ARGUMENT if failed for wrong filter ID. + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + stopFilter(DemuxFilterId filterId) generates (Result result); + + /** + * Flush the filter. + * + * It is used by the client to ask the filter to flush the data which is + * already produced but not consumed yet. + * + * @param filterId the ID of the filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_ARGUMENT if failed for wrong filter ID. + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + flushFilter(DemuxFilterId filterId) generates (Result result); + + /** + * Remove a filter from the demux + * + * It is used by the client to remove a filter from the demux. + * + * @param filterId the ID of the removed filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_ARGUMENT if failed for wrong filter ID. + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + removeFilter(DemuxFilterId filterId) generates (Result result); + + /** + * Get hardware sync ID for audio and video. + * + * It is used by the client to get the hardware sync ID for audio and video. + * + * @param filterId the ID of the filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_ARGUMENT if failed for a wrong filter ID. + * UNKNOWN_ERROR if failed for other reasons. + * @return avSyncHwId the id of hardware A/V sync. + */ + getAvSyncHwId(DemuxFilterId filterId) + generates (Result result, AvSyncHwId avSyncHwId); + + /** + * Get current time stamp to use for A/V sync + * + * It is used by the client to get current time stamp for A/V sync. HW is + * supported to increment and maintain current time stamp. + * + * @param avSyncHwId the hardware id of A/V sync. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_ARGUMENT if failed for a wrong hardware ID of A/V sync. + * UNKNOWN_ERROR if failed for other reasons. + * @return time the current time stamp of hardware A/V sync. The time stamp + * based on 90KHz has the same format as PTS (Presentation Time Stamp). + */ + getAvSyncTime(AvSyncHwId avSyncHwId) + generates (Result result, uint64_t time); + /** * Close the Demux instance * diff --git a/tv/tuner/1.0/IDemuxCallback.hal b/tv/tuner/1.0/IDemuxCallback.hal index c67c5f2aa6..7efd2c3591 100644 --- a/tv/tuner/1.0/IDemuxCallback.hal +++ b/tv/tuner/1.0/IDemuxCallback.hal @@ -6,6 +6,14 @@ interface IDemuxCallback { * * @param filterEvent a demux filter event. */ - oneway onFilterEvent(DemuxFilterEvent filterEvent); + oneway onFilterEvent(DemuxFilterEvent filterEvent); + + /** + * Notify the client a new status of a demux filter. + * + * @param filterId the demux filter ID. + * @param status a new status of the demux filter. + */ + oneway onFilterStatus(DemuxFilterId filterId, DemuxFilterStatus status); }; diff --git a/tv/tuner/1.0/IDescrambler.hal b/tv/tuner/1.0/IDescrambler.hal index 4d6cf3c7a1..d078657d65 100644 --- a/tv/tuner/1.0/IDescrambler.hal +++ b/tv/tuner/1.0/IDescrambler.hal @@ -1,11 +1,9 @@ package android.hardware.tv.tuner@1.0; - /** * Descrambler is used to descramble input data. * */ interface IDescrambler { - /** * Set a demux as source of the descrambler * @@ -13,6 +11,7 @@ interface IDescrambler { * descrambler. A descrambler instance can have only one source, and * this method can be only called once. * + * @param demuxId the id of the demux to be used as descrambler's source. * @return result Result status of the operation. * SUCCESS if successful, * INVALID_STATE if failed for wrong state. @@ -20,6 +19,51 @@ interface IDescrambler { */ setDemuxSource(DemuxId demuxId) generates (Result result); + /** + * Set a key token to link descrambler to a key slot + * + * It is used by the client to link a hardware key slot to a descrambler. + * A descrambler instance can have only one key slot to link, but a key + * slot can hold a few keys for different purposes. + * + * @param keyToken the token to be used to link the key slot. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + setKeyToken(TunerKeyToken keyToken) generates (Result result); + + /** + * Add packets' PID to the descrambler for descrambling + * + * It is used by the client to specify Package ID (PID) of packets which the + * descrambler start to descramble. Multiple PIDs can be added into one + * descrambler instance because descambling can happen simultaneously on + * packets from different PIDs. + * + * @param pid the PID of packets to start to be descrambled. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + addPid(DemuxTpid pid) generates (Result result); + + /** + * Remove packets' PID from the descrambler + * + * It is used by the client to specify Package ID (PID) of packets which the + * descrambler stop to descramble. + * + * @param pid the PID of packets to stop to be descrambled. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + removePid(DemuxTpid pid) generates (Result result); + /** * Release the descrambler instance * @@ -30,6 +74,6 @@ interface IDescrambler { * SUCCESS if successful, * UNKNOWN_ERROR if failed for other reasons. */ - close() generates (Result result); + close() generates (Result result); }; diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal index 61a9d63205..a0f3e8e7d1 100644 --- a/tv/tuner/1.0/ITuner.hal +++ b/tv/tuner/1.0/ITuner.hal @@ -42,6 +42,7 @@ interface ITuner { * * It is used by the client to create a frontend instance. * + * @param frontendId the id of the frontend to be opened. * @return result Result status of the operation. * SUCCESS if successful, * UNKNOWN_ERROR if creation failed for other reasons. diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index 3fa9641169..4522db24d9 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -170,7 +170,7 @@ enum DemuxFilterType : uint32_t { */ VIDEO, /** - * A filter to set PCR channel from input stream. + * A filter to set PCR (Program Clock Reference) channel from input stream. */ PCR, /** @@ -179,11 +179,303 @@ enum DemuxFilterType : uint32_t { RECORD, }; +/* Packet ID is used to specify packets in transport stream. */ +typedef uint16_t DemuxTpid; + +@export +enum Constant : uint16_t { + /** + * An invalid packet ID in transport stream according to ISO/IEC 13818-1. + */ + INVALID_TPID = 0xFFFF, + /** + * An invalid Stream ID. + */ + INVALID_STREAM_ID = 0xFFFF, +}; + +/** + * A status of data in the filter's buffer. + */ +@export +enum DemuxFilterStatus : uint8_t { + /** + * The data in the filter buffer is ready to be read. + */ + DATA_READY = 1 << 0, + /** + * The available data amount in the filter buffer is at low level which is + * set to 25 percent by default. + */ + LOW_WATER = 1 << 1, + /** + * The available data amount in the filter buffer is at high level which is + * set to 75 percent by default. + */ + HIGH_WATER = 1 << 2, + /** + * The data in the filter buffer is full and newly filtered data is being + * discarded. + */ + OVERFLOW = 1 << 3, +}; + +/** + * Bits Setting for Section Filter. + */ +struct DemuxFilterSectionBits { + /* The bytes are configured for Section Filter */ + vec filter; + /* Active bits in the configured bytes to be used for filtering */ + vec mask; + /* + * Do positive match at the bit position of the configured bytes when the + * bit at same position of the mode is 0. + * Do negative match at the bit position of the configured bytes when the + * bit at same position of the mode is 1. + */ + vec mode; +}; + +/** + * Filter Settings for Section data according to ISO/IEC 13818-1. + */ +struct DemuxFilterSectionSettings { + DemuxTpid tpid; + DemuxFilterSectionBits bits; + /* Table ID for Section Filter */ + uint16_t tableId; + /* Version number for Section Filter */ + uint16_t version; + /* true if the filter checks CRC and discards data with wrong CRC */ + bool checkCrc; + /* true if the filter repeats the data with the same version */ + bool isRepeat; + /* true if the filter output raw data */ + bool isRaw; +}; + +/* Stream ID is used to specify one elementary stream */ +typedef uint16_t DemuxStreamId; + +/** + * Filter Settings for a PES Data. + */ +struct DemuxFilterPesDataSettings { + DemuxTpid tpid; + DemuxStreamId streamId; + /* true if the filter output raw data */ + bool bIsRaw; +}; + +/** + * Filter Settings for a TS Data. + */ +struct DemuxFilterTsSettings { + DemuxTpid tpid; +}; + +/** + * Filter Settings for a Audio. + */ +struct DemuxFilterAudioSettings { + DemuxTpid tpid; + /** + * true if the filter output goes to decoder directly in pass through mode. + */ + bool bPassthrough; +}; + +/** + * Filter Settings for a Video. + */ +struct DemuxFilterVideoSettings { + DemuxTpid tpid; + /** + * true if the filter output goes to decoder directly in pass through mode. + */ + bool bPassthrough; +}; + +/** + * Filter Settings for a PCR (Program Clock Reference). + */ +struct DemuxFilterPcrSettings { + DemuxTpid tpid; +}; + +/** + * Indexes can be tagged through TS (Transport Stream) header. + */ +@export +enum DemuxTsIndex : uint32_t { + FIRST_PACKET = 1 << 0, + PAYLOAD_UNIT_START_INDICATOR = 1 << 1, + CHANGE_TO_NOT_SCRAMBLED = 1 << 2, + CHANGE_TO_EVEN_SCRAMBLED = 1 << 3, + CHANGE_TO_ODD_SCRAMBLED = 1 << 4, + DISCONTINUITY_INDICATOR = 1 << 5, + RANDOM_ACCESS_INDICATOR = 1 << 6, + PRIORITY_INDICATOR = 1 << 7, + PCR_FLAG = 1 << 8, + OPCR_FLAG = 1 << 9, + SPLICING_POINT_FLAG = 1 << 10, + PRIVATE_DATA = 1 << 11, + ADAPTATION_EXTENSION_FLAG = 1 << 12, +}; + +/** + * A mask of TS indexes + * + * It's a combination of TS indexes. + */ +typedef bitfield DemuxTsIndexMask; + +/** + * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream) + * according to ISO/IEC 13818-1. + */ +@export +enum DemuxScIndex : uint32_t { + /* Start Code is for a new I Frame */ + I_FRAME = 1 << 0, + /* Start Code is for a new P Frame */ + P_FRAME = 1 << 1, + /* Start Code is for a new B Frame */ + B_FRAME = 1 << 2, + /* Start Code is for a new Sequence */ + SEQUENCE = 1 << 3, +}; + +/** + * A mask of Start Code Indexes + * + * It's a combination of Start Code Indexes. + */ +typedef bitfield DemuxScIndexMask; + +/* Index type to be used in the filter for record */ +@export +enum DemuxRecordIndexType : uint32_t { + /* Don't use index */ + NONE, + /* Use TS index */ + TS, + /* Use Start Code index */ + SC, +}; + +/** + * Filter Settings for Record data. + */ +struct DemuxFilterRecordSettings { + DemuxTpid tpid; + DemuxRecordIndexType indexType; + safe_union IndexMask { + DemuxTsIndexMask tsIndexMask; + DemuxScIndexMask scIndexMask; + } indexMask; +}; + +/** + * Filter Settings. + */ +safe_union DemuxFilterSettings { + DemuxFilterSectionSettings section; + DemuxFilterPesDataSettings pesData; + DemuxFilterTsSettings ts; + DemuxFilterAudioSettings audio; + DemuxFilterVideoSettings video; + DemuxFilterPcrSettings pcr; + DemuxFilterRecordSettings record; +}; + +/** + * The bits of EventFlag in FMQ (Fast message queue) are used by client to + * notify HAL the status change. + */ +@export +enum DemuxQueueNotifyBits : uint32_t { + /* client writes data and notify HAL the data is ready. */ + DATA_READY = 1 << 0, + /* client reads data and notify HAL the data is consumed. */ + DATA_CONSUMED = 1 << 1 +}; + +/** + * Filter Event for Section Filter. + */ +struct DemuxFilterSectionEvent { + /* Table ID of filtered data */ + uint16_t tableId; + /* Version number of filtered data */ + uint16_t version; + /* Section number of filtered data */ + uint16_t sectionNum; + /* Data size in bytes of filtered data */ + uint16_t dataLength; +}; + +/** + * Filter Event for Audio or Video Filter. + */ +struct DemuxFilterMediaEvent { + /* Presentation Time Stamp for audio or video frame. It based on 90KHz has + * the same format as PTS (Presentation Time Stamp). + */ + uint64_t pts; + /* Data size in bytes of audio or video frame */ + uint16_t dataLength; + /* A handle associated to the memory where audio or video data stays. */ + handle secureMemory; +}; + +/** + * Filter Event for PES data. + */ +struct DemuxFilterPesEvent { + DemuxStreamId streamId; + /* Data size in bytes of PES data */ + uint16_t dataLength; +}; + +/** + * Filter Event for Record data. + */ +struct DemuxFilterRecordEvent { + DemuxTpid tpid; + /* Indexes of record output */ + safe_union IndexMask { + DemuxTsIndexMask tsIndexMask; + DemuxScIndexMask scIndexMask; + } indexMask; + /* Packet number from beginning of the filter's output */ + uint64_t packetNum; +}; + /** * Filter Event. */ struct DemuxFilterEvent { - DemuxFilterId filterId; - DemuxFilterType filterType; + DemuxFilterId filterId; + DemuxFilterType filterType; + safe_union Event { + DemuxFilterSectionEvent section; + DemuxFilterMediaEvent media; + DemuxFilterPesEvent pes; + DemuxFilterRecordEvent ts; + }; + /* An array of events */ + vec events; }; +/** + * A hardware resource ID to be used for audio and video hardware sync. + */ +typedef uint32_t AvSyncHwId; + +/** + * A token to be used to link descrambler and key slot. It's opaque to + * framework and apps. + */ +typedef vec TunerKeyToken; From a609d5a0e2a0943f07e0a11243256fa521c3f32d Mon Sep 17 00:00:00 2001 From: Amy Date: Fri, 23 Aug 2019 14:38:31 -0700 Subject: [PATCH 0099/1022] Tuner HAL Filter APIs default implementation Bug: 135709325 Test: manual Change-Id: If10acac560d3130105079121602be576eb0b225a --- tv/tuner/1.0/default/Android.bp | 2 + tv/tuner/1.0/default/Demux.cpp | 352 ++++++++++++++++++++++++++- tv/tuner/1.0/default/Demux.h | 88 +++++++ tv/tuner/1.0/default/Descrambler.cpp | 18 ++ tv/tuner/1.0/default/Descrambler.h | 6 + 5 files changed, 465 insertions(+), 1 deletion(-) diff --git a/tv/tuner/1.0/default/Android.bp b/tv/tuner/1.0/default/Android.bp index 21c9f1b6c2..01bcbabc95 100644 --- a/tv/tuner/1.0/default/Android.bp +++ b/tv/tuner/1.0/default/Android.bp @@ -16,6 +16,8 @@ cc_defaults { shared_libs: [ "android.hardware.tv.tuner@1.0", "android.hidl.memory@1.0", + "libcutils", + "libfmq", "libhidlbase", "libhidlmemory", "libhidltransport", diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp index 6f7c68bfb4..4016c5a0e9 100644 --- a/tv/tuner/1.0/default/Demux.cpp +++ b/tv/tuner/1.0/default/Demux.cpp @@ -26,12 +26,81 @@ namespace tuner { namespace V1_0 { namespace implementation { +#define WAIT_TIMEOUT 3000000000 + +const std::vector fakeDataInputBuffer{ + 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb, + 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03, + 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06, + 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, + 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, + 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d, + 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63, + 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, + 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, + 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, + 0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d, + 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65, + 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31, + 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e, + 0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20, + 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, + 0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69, + 0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71, + 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, + 0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d, + 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, + 0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68, + 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f, + 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, + 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79, + 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, + 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20, + 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30, + 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20, + 0x73, 0x63, 0x65, 0x6e, 0x65, +}; + Demux::Demux(uint32_t demuxId) { mDemuxId = demuxId; } Demux::~Demux() {} +bool Demux::createAndSaveMQ(uint32_t bufferSize, uint32_t filterId) { + ALOGV("%s", __FUNCTION__); + + // Create a synchronized FMQ that supports blocking read/write + std::unique_ptr tmpFilterMQ = + std::unique_ptr(new (std::nothrow) FilterMQ(bufferSize, true)); + if (!tmpFilterMQ->isValid()) { + ALOGW("Failed to create FMQ of filter with id: %d", filterId); + return false; + } + + mFilterMQs.resize(filterId + 1); + mFilterMQs[filterId] = std::move(tmpFilterMQ); + + EventFlag* mFilterEventFlag; + if (EventFlag::createEventFlag(mFilterMQs[filterId]->getEventFlagWord(), &mFilterEventFlag) != + OK) { + return false; + } + mFilterEventFlags.resize(filterId + 1); + mFilterEventFlags[filterId] = mFilterEventFlag; + mFilterWriteCount.resize(filterId + 1); + mFilterWriteCount[filterId] = 0; + mThreadRunning.resize(filterId + 1); + + return true; +} + Return Demux::setFrontendDataSource(uint32_t frontendId) { ALOGV("%s", __FUNCTION__); @@ -40,11 +109,292 @@ Return Demux::setFrontendDataSource(uint32_t frontendId) { return Result::SUCCESS; } +Return Demux::addFilter(DemuxFilterType type, uint32_t bufferSize, + const sp& cb, addFilter_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + uint32_t filterId = mLastUsedFilterId + 1; + mLastUsedFilterId += 1; + + if ((type != DemuxFilterType::PCR || type != DemuxFilterType::TS) && cb == nullptr) { + ALOGW("callback can't be null"); + _hidl_cb(Result::INVALID_ARGUMENT, filterId); + return Void(); + } + // Add callback + mDemuxCallbacks.resize(filterId + 1); + mDemuxCallbacks[filterId] = cb; + + // Mapping from the filter ID to the filter type + mFilterTypes.resize(filterId + 1); + mFilterTypes[filterId] = type; + + if (!createAndSaveMQ(bufferSize, filterId)) { + _hidl_cb(Result::UNKNOWN_ERROR, -1); + return Void(); + } + + _hidl_cb(Result::SUCCESS, filterId); + return Void(); +} + +Return Demux::getFilterQueueDesc(uint32_t filterId, getFilterQueueDesc_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + if (filterId < 0 || filterId > mLastUsedFilterId) { + ALOGW("No filter with id: %d exists", filterId); + _hidl_cb(Result::INVALID_ARGUMENT, FilterMQ::Descriptor()); + return Void(); + } + + _hidl_cb(Result::SUCCESS, *mFilterMQs[filterId]->getDesc()); + return Void(); +} + +Return Demux::configureFilter(uint32_t /* filterId */, + const DemuxFilterSettings& /* settings */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Demux::startFilter(uint32_t filterId) { + ALOGV("%s", __FUNCTION__); + + if (filterId < 0 || filterId > mLastUsedFilterId) { + ALOGW("No filter with id: %d exists", filterId); + return Result::INVALID_ARGUMENT; + } + + DemuxFilterType filterType = mFilterTypes[filterId]; + Result result; + DemuxFilterEvent event{ + .filterId = filterId, + .filterType = filterType, + }; + + switch (filterType) { + case DemuxFilterType::SECTION: + result = startSectionFilterHandler(event); + break; + case DemuxFilterType::PES: + result = startPesFilterHandler(event); + break; + case DemuxFilterType::TS: + result = startTsFilterHandler(); + return Result::SUCCESS; + case DemuxFilterType::AUDIO: + case DemuxFilterType::VIDEO: + result = startMediaFilterHandler(event); + break; + case DemuxFilterType::RECORD: + result = startRecordFilterHandler(event); + break; + case DemuxFilterType::PCR: + result = startPcrFilterHandler(); + return Result::SUCCESS; + default: + return Result::UNKNOWN_ERROR; + } + + return result; +} + +Return Demux::stopFilter(uint32_t /* filterId */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Demux::flushFilter(uint32_t /* filterId */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Demux::removeFilter(uint32_t /* filterId */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Demux::getAvSyncHwId(uint32_t /* filterId */, getAvSyncHwId_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + AvSyncHwId avSyncHwId = 0; + + _hidl_cb(Result::SUCCESS, avSyncHwId); + return Void(); +} + +Return Demux::getAvSyncTime(AvSyncHwId /* avSyncHwId */, getAvSyncTime_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + uint64_t avSyncTime = 0; + + _hidl_cb(Result::SUCCESS, avSyncTime); + return Void(); +} + Return Demux::close() { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; - ; +} + +bool Demux::writeSectionsAndCreateEvent(DemuxFilterEvent& event, uint32_t sectionNum) { + event.events.resize(sectionNum); + for (int i = 0; i < sectionNum; i++) { + DemuxFilterSectionEvent secEvent; + secEvent = { + // temp dump meta data + .tableId = 0, + .version = 1, + .sectionNum = 1, + .dataLength = 530, + }; + event.events[i].section(secEvent); + if (!writeDataToFilterMQ(fakeDataInputBuffer, event.filterId)) { + return false; + } + } + return true; +} + +bool Demux::writeDataToFilterMQ(const std::vector& data, uint32_t filterId) { + std::lock_guard lock(mWriteLock); + if (mFilterMQs[filterId]->write(data.data(), data.size())) { + return true; + } + return false; +} + +Result Demux::startSectionFilterHandler(DemuxFilterEvent event) { + struct ThreadArgs* threadArgs = (struct ThreadArgs*)malloc(sizeof(struct ThreadArgs)); + threadArgs->user = this; + threadArgs->event = &event; + + pthread_create(&mThreadId, NULL, __threadLoop, (void*)threadArgs); + pthread_setname_np(mThreadId, "demux_filter_waiting_loop"); + + return Result::SUCCESS; +} + +Result Demux::startPesFilterHandler(DemuxFilterEvent& event) { + // TODO generate multiple events in one event callback + DemuxFilterPesEvent pesEvent; + pesEvent = { + // temp dump meta data + .streamId = 0, + .dataLength = 530, + }; + event.events.resize(1); + event.events[0].pes(pesEvent); + /*pthread_create(&mThreadId, NULL, __threadLoop, this); + pthread_setname_np(mThreadId, "demux_section_filter_waiting_loop");*/ + if (!writeDataToFilterMQ(fakeDataInputBuffer, event.filterId)) { + return Result::INVALID_STATE; + } + + if (mDemuxCallbacks[event.filterId] == nullptr) { + return Result::NOT_INITIALIZED; + } + + mDemuxCallbacks[event.filterId]->onFilterEvent(event); + return Result::SUCCESS; +} + +Result Demux::startTsFilterHandler() { + // TODO handle starting TS filter + return Result::SUCCESS; +} + +Result Demux::startMediaFilterHandler(DemuxFilterEvent& event) { + DemuxFilterMediaEvent mediaEvent; + mediaEvent = { + // temp dump meta data + .pts = 0, + .dataLength = 530, + .secureMemory = nullptr, + }; + event.events.resize(1); + event.events[0].media() = mediaEvent; + // TODO handle write FQM for media stream + return Result::SUCCESS; +} + +Result Demux::startRecordFilterHandler(DemuxFilterEvent& event) { + DemuxFilterRecordEvent recordEvent; + recordEvent = { + // temp dump meta data + .tpid = 0, + .packetNum = 0, + }; + recordEvent.indexMask.tsIndexMask() = 0x01; + event.events.resize(1); + event.events[0].ts() = recordEvent; + return Result::SUCCESS; +} + +Result Demux::startPcrFilterHandler() { + // TODO handle starting PCR filter + return Result::SUCCESS; +} + +void* Demux::__threadLoop(void* threadArg) { + Demux* const self = static_cast(((struct ThreadArgs*)threadArg)->user); + self->filterThreadLoop(((struct ThreadArgs*)threadArg)->event); + return 0; +} + +void Demux::filterThreadLoop(DemuxFilterEvent* event) { + uint32_t filterId = event->filterId; + ALOGD("[Demux] filter %d threadLoop start.", filterId); + mThreadRunning[filterId] = true; + + while (mThreadRunning[filterId]) { + uint32_t efState = 0; + // We do not wait for the last round of writen data to be read to finish the thread + // because the VTS can verify the reading itself. + for (int i = 0; i < SECTION_WRITE_COUNT; i++) { + DemuxFilterEvent filterEvent{ + .filterId = filterId, + .filterType = event->filterType, + }; + if (!writeSectionsAndCreateEvent(filterEvent, 2)) { + ALOGD("[Demux] filter %d fails to write into FMQ. Ending thread", filterId); + break; + } + mFilterWriteCount[filterId]++; + if (mDemuxCallbacks[filterId] == nullptr) { + ALOGD("[Demux] filter %d does not hava callback. Ending thread", filterId); + break; + } + // After successfully write, send a callback and wait for the read to be done + mDemuxCallbacks[filterId]->onFilterEvent(filterEvent); + // We do not wait for the last read to be done + // VTS can verify the read result itself. + if (i == SECTION_WRITE_COUNT - 1) { + ALOGD("[Demux] filter %d writing done. Ending thread", filterId); + break; + } + while (mThreadRunning[filterId]) { + status_t status = mFilterEventFlags[filterId]->wait( + static_cast(DemuxQueueNotifyBits::DATA_CONSUMED), &efState, + WAIT_TIMEOUT, true /* retry on spurious wake */); + if (status != OK) { + ALOGD("[Demux] wait for data consumed"); + continue; + } + break; + } + } + + mFilterWriteCount[filterId] = 0; + mThreadRunning[filterId] = false; + } + + ALOGD("[Demux] filter thread ended."); } } // namespace implementation diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h index 52f39336bd..8b002669dd 100644 --- a/tv/tuner/1.0/default/Demux.h +++ b/tv/tuner/1.0/default/Demux.h @@ -18,6 +18,7 @@ #define ANDROID_HARDWARE_TV_TUNER_V1_0_DEMUX_H_ #include +#include using namespace std; @@ -28,9 +29,16 @@ namespace tuner { namespace V1_0 { namespace implementation { +using ::android::hardware::EventFlag; +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; +using ::android::hardware::MQDescriptorSync; using ::android::hardware::tv::tuner::V1_0::IDemux; +using ::android::hardware::tv::tuner::V1_0::IDemuxCallback; using ::android::hardware::tv::tuner::V1_0::Result; +using FilterMQ = MessageQueue; + class Demux : public IDemux { public: Demux(uint32_t demuxId); @@ -39,10 +47,90 @@ class Demux : public IDemux { virtual Return close() override; + virtual Return addFilter(DemuxFilterType type, uint32_t bufferSize, + const sp& cb, addFilter_cb _hidl_cb) override; + + virtual Return getFilterQueueDesc(uint32_t filterId, + getFilterQueueDesc_cb _hidl_cb) override; + + virtual Return configureFilter(uint32_t filterId, + const DemuxFilterSettings& settings) override; + + virtual Return startFilter(uint32_t filterId) override; + + virtual Return stopFilter(uint32_t filterId) override; + + virtual Return flushFilter(uint32_t filterId) override; + + virtual Return removeFilter(uint32_t filterId) override; + + virtual Return getAvSyncHwId(uint32_t filterId, getAvSyncHwId_cb _hidl_cb) override; + + virtual Return getAvSyncTime(AvSyncHwId avSyncHwId, getAvSyncTime_cb _hidl_cb) override; + private: virtual ~Demux(); + /** + * To create a FilterMQ with the the next available Filter ID. + * Creating Event Flag at the same time. + * Add the successfully created/saved FilterMQ into the local list. + * + * Return false is any of the above processes fails. + */ + bool createAndSaveMQ(uint32_t bufferSize, uint32_t filterId); + void deleteEventFlag(); + bool writeDataToFilterMQ(const std::vector& data, uint32_t filterId); + Result startSectionFilterHandler(DemuxFilterEvent event); + Result startPesFilterHandler(DemuxFilterEvent& event); + Result startTsFilterHandler(); + Result startMediaFilterHandler(DemuxFilterEvent& event); + Result startRecordFilterHandler(DemuxFilterEvent& event); + Result startPcrFilterHandler(); + bool writeSectionsAndCreateEvent(DemuxFilterEvent& event, uint32_t sectionNum); + void filterThreadLoop(DemuxFilterEvent* event); + static void* __threadLoop(void* data); + uint32_t mDemuxId; uint32_t mSourceFrontendId; + /** + * Record the last used filer id. Initial value is -1. + * Filter Id starts with 0. + */ + uint32_t mLastUsedFilterId = -1; + /** + * A list of created FilterMQ ptrs. + * The array number is the filter ID. + */ + vector> mFilterMQs; + vector mFilterTypes; + vector mFilterEventFlags; + /** + * Demux callbacks used on filter events or IO buffer status + */ + vector> mDemuxCallbacks; + /** + * How many times a specific filter has written since started + */ + vector mFilterWriteCount; + pthread_t mThreadId = 0; + /** + * If a specific filter's writing loop is still running + */ + vector mThreadRunning; + /** + * Lock to protect writes to the FMQs + */ + std::mutex mWriteLock; + /** + * How many times a filter should write + * TODO make this dynamic/random/can take as a parameter + */ + const uint16_t SECTION_WRITE_COUNT = 10; + // A struct that passes the arguments to a newly created filter thread + struct ThreadArgs { + Demux* user; + DemuxFilterEvent* event; + }; }; } // namespace implementation diff --git a/tv/tuner/1.0/default/Descrambler.cpp b/tv/tuner/1.0/default/Descrambler.cpp index 1af1a2c995..085f2c8d54 100644 --- a/tv/tuner/1.0/default/Descrambler.cpp +++ b/tv/tuner/1.0/default/Descrambler.cpp @@ -44,6 +44,24 @@ Return Descrambler::setDemuxSource(uint32_t demuxId) { return Result::SUCCESS; } +Return Descrambler::setKeyToken(const hidl_vec& /* keyToken */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Descrambler::addPid(uint16_t /* pid */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Descrambler::removePid(uint16_t /* pid */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + Return Descrambler::close() { ALOGV("%s", __FUNCTION__); mDemuxSet = false; diff --git a/tv/tuner/1.0/default/Descrambler.h b/tv/tuner/1.0/default/Descrambler.h index 2ec8412a6d..436adcfc43 100644 --- a/tv/tuner/1.0/default/Descrambler.h +++ b/tv/tuner/1.0/default/Descrambler.h @@ -38,6 +38,12 @@ class Descrambler : public IDescrambler { virtual Return setDemuxSource(uint32_t demuxId) override; + virtual Return setKeyToken(const hidl_vec& keyToken) override; + + virtual Return addPid(uint16_t pid) override; + + virtual Return removePid(uint16_t pid) override; + virtual Return close() override; private: From 052275a924b34b8713ab5b627d02d793ef550276 Mon Sep 17 00:00:00 2001 From: Amy Date: Tue, 27 Aug 2019 15:22:40 -0700 Subject: [PATCH 0100/1022] Tuner HAL Demux Filter VTS Test: atest VtsHalTvTunerV1_0TargetTest Bug: 135708935 Change-Id: I2b6b7e904cb274e7ccd10e481b04dfd9394afe3e --- tv/tuner/1.0/vts/functional/Android.bp | 2 + .../VtsHalTvTunerV1_0TargetTest.cpp | 318 ++++++++++++++++++ 2 files changed, 320 insertions(+) diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp index faf566c847..7d6b990a7b 100644 --- a/tv/tuner/1.0/vts/functional/Android.bp +++ b/tv/tuner/1.0/vts/functional/Android.bp @@ -24,6 +24,8 @@ cc_test { "android.hidl.memory@1.0", "libhidlallocatorutils", "libhidlmemory", + "libcutils", + "libfmq", ], shared_libs: [ "libbinder", diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index c652944fee..66adb2a698 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -42,12 +43,22 @@ using android::IMemoryHeap; using android::MemoryDealer; using android::Mutex; using android::sp; +using android::hardware::EventFlag; using android::hardware::fromHeap; using android::hardware::hidl_string; using android::hardware::hidl_vec; using android::hardware::HidlMemory; +using android::hardware::kSynchronizedReadWrite; +using android::hardware::MessageQueue; +using android::hardware::MQDescriptorSync; using android::hardware::Return; using android::hardware::Void; +using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterStatus; +using android::hardware::tv::tuner::V1_0::DemuxFilterType; +using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; using android::hardware::tv::tuner::V1_0::FrontendAtscModulation; using android::hardware::tv::tuner::V1_0::FrontendAtscSettings; using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings; @@ -65,6 +76,53 @@ using android::hardware::tv::tuner::V1_0::Result; namespace { +using FilterMQ = MessageQueue; +using FilterMQDesc = MQDescriptorSync; + +const std::vector goldenDataInputBuffer{ + 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb, + 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03, + 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06, + 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, + 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, + 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d, + 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63, + 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, + 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, + 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, + 0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d, + 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65, + 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31, + 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e, + 0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20, + 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, + 0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69, + 0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71, + 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, + 0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d, + 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, + 0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68, + 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f, + 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, + 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79, + 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, + 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20, + 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30, + 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20, + 0x73, 0x63, 0x65, 0x6e, 0x65, +}; + +const uint16_t FMQ_SIZE_4K = 0x1000; +// Equal to SECTION_WRITE_COUNT on the HAL impl side +// The HAL impl will repeatedly write to the FMQ the count times +const uint16_t SECTION_READ_COUNT = 10; + class FrontendCallback : public IFrontendCallback { public: virtual Return onEvent(FrontendEventType frontendEventType) override { @@ -123,6 +181,134 @@ void FrontendCallback::testOnDiseqcMessage(sp& frontend, FrontendSett } } +class DemuxCallback : public IDemuxCallback { + public: + virtual Return onFilterEvent(const DemuxFilterEvent& filterEvent) override { + android::Mutex::Autolock autoLock(mMsgLock); + mFilterEventReceived = true; + mFilterEvent = filterEvent; + mMsgCondition.signal(); + return Void(); + } + + virtual Return onFilterStatus(uint32_t /*filterId*/, + const DemuxFilterStatus /*status*/) override { + return Void(); + } + + void testOnFilterEvent(uint32_t filterId); + void testOnSectionFilterEvent(sp& demux, uint32_t filterId, + FilterMQDesc& filterMQDescriptor); + void testOnPesFilterEvent(sp& demux, uint32_t filterId, + FilterMQDesc& filterMQDescriptor); + void readAndCompareSectionEventData(); + void readAndComparePesEventData(); + + private: + bool mFilterEventReceived = false; + std::vector mDataOutputBuffer; + std::unique_ptr mFilterMQ; + uint16_t mDataLength = 0; + DemuxFilterEvent mFilterEvent; + android::Mutex mMsgLock; + android::Mutex mReadLock; + android::Condition mMsgCondition; + EventFlag* mFilterMQEventFlag; +}; + +void DemuxCallback::testOnFilterEvent(uint32_t filterId) { + android::Mutex::Autolock autoLock(mMsgLock); + while (!mFilterEventReceived) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "filter event not received within timeout"; + return; + } + } + // Reset the filter event recieved flag + mFilterEventReceived = false; + // Check if filter id match + EXPECT_TRUE(filterId == mFilterEvent.filterId) << "filter id match"; +} + +void DemuxCallback::testOnSectionFilterEvent(sp& demux, uint32_t filterId, + FilterMQDesc& filterMQDescriptor) { + Result status; + // Create MQ to read the output into the local buffer + mFilterMQ = std::make_unique(filterMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(mFilterMQ); + // Create the EventFlag that is used to signal the HAL impl that data have been + // read the Filter FMQ + EXPECT_TRUE(EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag) == + android::OK); + // Start filter + status = demux->startFilter(filterId); + EXPECT_EQ(status, Result::SUCCESS); + // Test start filter and receive callback event + for (int i = 0; i < SECTION_READ_COUNT; i++) { + testOnFilterEvent(filterId); + // checksum of mDataOutputBuffer and Input golden input + readAndCompareSectionEventData(); + } +} + +void DemuxCallback::testOnPesFilterEvent(sp& demux, uint32_t filterId, + FilterMQDesc& filterMQDescriptor) { + Result status; + // Create MQ to read the output into the local buffer + mFilterMQ = std::make_unique(filterMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(mFilterMQ); + // Create the EventFlag that is used to signal the HAL impl that data have been + // read the Filter FMQ + EXPECT_TRUE(EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag) == + android::OK); + // Start filter + status = demux->startFilter(filterId); + EXPECT_EQ(status, Result::SUCCESS); + // Test start filter and receive callback event + testOnFilterEvent(filterId); + // checksum of mDataOutputBuffer and Input golden input + readAndComparePesEventData(); +} + +void DemuxCallback::readAndCompareSectionEventData() { + bool result = false; + for (int i = 0; i < mFilterEvent.events.size(); i++) { + DemuxFilterSectionEvent event = mFilterEvent.events[i].section(); + mDataLength = event.dataLength; + EXPECT_TRUE(mDataLength == goldenDataInputBuffer.size()) << "buffer size does not match"; + + mDataOutputBuffer.resize(mDataLength); + result = mFilterMQ->read(mDataOutputBuffer.data(), mDataLength); + EXPECT_TRUE(result) << "can't read from Filter MQ"; + + for (int i = 0; i < mDataLength; i++) { + EXPECT_TRUE(goldenDataInputBuffer[i] == mDataOutputBuffer[i]) << "data does not match"; + } + } + if (result) { + mFilterMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); + } +} + +void DemuxCallback::readAndComparePesEventData() { + // TODO handle multiple events in one filter callback event + DemuxFilterPesEvent event = mFilterEvent.events[0].pes(); + mDataLength = event.dataLength; + EXPECT_TRUE(mDataLength == goldenDataInputBuffer.size()) << "buffer size does not match"; + + mDataOutputBuffer.resize(mDataLength); + bool result = mFilterMQ->read(mDataOutputBuffer.data(), mDataLength); + EXPECT_TRUE(result) << "can't read from Filter MQ"; + + if (result) { + mFilterMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); + } + + for (int i = 0; i < mDataLength; i++) { + EXPECT_TRUE(goldenDataInputBuffer[i] == mDataOutputBuffer[i]) << "data does not match"; + } +} + // Test environment for Tuner HIDL HAL. class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: @@ -154,7 +340,10 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { sp mFrontendCallback; sp mDescrambler; sp mDemux; + sp mDemuxCallback; + FilterMQDesc mFilterMQDescriptor; uint32_t mDemuxId; + uint32_t mFilterId; ::testing::AssertionResult createFrontend(int32_t frontendId); ::testing::AssertionResult tuneFrontend(int32_t frontendId); @@ -162,6 +351,11 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { ::testing::AssertionResult closeFrontend(int32_t frontendId); ::testing::AssertionResult createDemux(); ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId); + ::testing::AssertionResult addSectionFilterToDemux(); + ::testing::AssertionResult addPesFilterToDemux(); + ::testing::AssertionResult getFilterMQDescriptor(sp& demux, const uint32_t filterId); + ::testing::AssertionResult readSectionFilterDataOutput(); + ::testing::AssertionResult readPesFilterDataOutput(); ::testing::AssertionResult closeDemux(); ::testing::AssertionResult createDescrambler(); ::testing::AssertionResult closeDescrambler(); @@ -256,6 +450,104 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionResult(status == Result::SUCCESS); } +::testing::AssertionResult TunerHidlTest::addSectionFilterToDemux() { + Result status; + + if (createDemux() == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + // Create demux callback + mDemuxCallback = new DemuxCallback(); + + // Add section filter to the local demux + mDemux->addFilter(DemuxFilterType::SECTION, FMQ_SIZE_4K, mDemuxCallback, + [&](Result result, uint32_t filterId) { + mFilterId = filterId; + status = result; + }); + + // Add another section filter to the local demux + mDemux->addFilter(DemuxFilterType::SECTION, FMQ_SIZE_4K, mDemuxCallback, + [&](Result result, uint32_t filterId) { + mFilterId = filterId; + status = result; + }); + + // TODO Test configure the filter + + return ::testing::AssertionResult(status == Result::SUCCESS); +} + +::testing::AssertionResult TunerHidlTest::addPesFilterToDemux() { + Result status; + + if (createDemux() == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + // Create demux callback + mDemuxCallback = new DemuxCallback(); + + // Add PES filter to the local demux + mDemux->addFilter(DemuxFilterType::PES, FMQ_SIZE_4K, mDemuxCallback, + [&](Result result, uint32_t filterId) { + mFilterId = filterId; + status = result; + }); + + // Add another PES filter to the local demux + mDemux->addFilter(DemuxFilterType::PES, FMQ_SIZE_4K, mDemuxCallback, + [&](Result result, uint32_t filterId) { + mFilterId = filterId; + status = result; + }); + + // TODO Test configure the filter + + return ::testing::AssertionResult(status == Result::SUCCESS); +} + +::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor(sp& demux, + const uint32_t filterId) { + Result status; + + if (!demux) { + return ::testing::AssertionFailure(); + } + + mDemux->getFilterQueueDesc(filterId, [&](Result result, const FilterMQDesc& filterMQDesc) { + mFilterMQDescriptor = filterMQDesc; + status = result; + }); + + return ::testing::AssertionResult(status == Result::SUCCESS); +} + +::testing::AssertionResult TunerHidlTest::readSectionFilterDataOutput() { + if (addSectionFilterToDemux() == ::testing::AssertionFailure() || + getFilterMQDescriptor(mDemux, mFilterId) == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + // Test start filter and read the output data + mDemuxCallback->testOnSectionFilterEvent(mDemux, mFilterId, mFilterMQDescriptor); + + return ::testing::AssertionResult(true); +} + +::testing::AssertionResult TunerHidlTest::readPesFilterDataOutput() { + if (addPesFilterToDemux() == ::testing::AssertionFailure() || + getFilterMQDescriptor(mDemux, mFilterId) == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + // Test start filter and read the output data + mDemuxCallback->testOnPesFilterEvent(mDemux, mFilterId, mFilterMQDescriptor); + + return ::testing::AssertionResult(true); +} + ::testing::AssertionResult TunerHidlTest::closeDemux() { Result status; if (createDemux() == ::testing::AssertionFailure()) { @@ -407,6 +699,32 @@ TEST_F(TunerHidlTest, CreateDemuxWithFrontend) { } } +TEST_F(TunerHidlTest, AddSectionFilterToDemux) { + description("Add a section filter to a created demux"); + ASSERT_TRUE(addSectionFilterToDemux()); +} + +TEST_F(TunerHidlTest, AddPesFilterToDemux) { + description("Add a pes filter to a created demux"); + ASSERT_TRUE(addPesFilterToDemux()); +} + +TEST_F(TunerHidlTest, GetFilterMQDescriptor) { + description("Get MQ Descriptor from a created filter"); + ASSERT_TRUE(addSectionFilterToDemux()); + ASSERT_TRUE(getFilterMQDescriptor(mDemux, mFilterId)); +} + +TEST_F(TunerHidlTest, ReadSectionFilterOutput) { + description("Read data output from FMQ of a Section Filter"); + ASSERT_TRUE(readSectionFilterDataOutput()); +} + +TEST_F(TunerHidlTest, ReadPesFilterOutput) { + description("Read data output from FMQ of a PES Filter"); + ASSERT_TRUE(readPesFilterDataOutput()); +} + TEST_F(TunerHidlTest, CloseDemux) { description("Close Demux"); From 2814d0417386c1cf74d299c614809642666d51e4 Mon Sep 17 00:00:00 2001 From: Amy Date: Wed, 4 Sep 2019 19:16:29 -0700 Subject: [PATCH 0101/1022] Add an OWNER file to the Tuner HAL 1.0 VTS Test: manual Change-Id: I2e5992a827dc430118cfbd68982c4ef08aa9b0e1 --- tv/tuner/1.0/vts/OWNERS | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tv/tuner/1.0/vts/OWNERS diff --git a/tv/tuner/1.0/vts/OWNERS b/tv/tuner/1.0/vts/OWNERS new file mode 100644 index 0000000000..1b3d095f9c --- /dev/null +++ b/tv/tuner/1.0/vts/OWNERS @@ -0,0 +1,4 @@ +nchalko@google.com +amyjojo@google.com +shubang@google.com +quxiangfang@google.com From a07870dd56138903ef54fe8de36f1a1ba73ff85c Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Thu, 5 Sep 2019 18:08:01 -0700 Subject: [PATCH 0102/1022] Check for the correct userId in callbacks Test: vts-tradefed run commandAndExit vts-hal -m VtsHalBiometricsFaceV1_0Target Change-Id: I0c9478d635f67c8ac5c4b47c022d76a6f91de230 --- .../VtsHalBiometricsFaceV1_0TargetTest.cpp | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp index d3d738798b..a4e95ed7b7 100644 --- a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp +++ b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp @@ -64,7 +64,7 @@ struct FaceCallbackArgs { // The error passed to the last onError() callback. FaceError error; - // The userId passed to the last onRemoved() callback. + // The userId passed to the last callback. int32_t userId; }; @@ -74,24 +74,32 @@ struct FaceCallbackArgs { class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase, public IBiometricsFaceClientCallback { public: - Return onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override { - NotifyFromCallback(kCallbackNameOnEnrollResult); + Return onEnrollResult(uint64_t, uint32_t, int32_t userId, uint32_t) override { + FaceCallbackArgs args = {}; + args.userId = userId; + NotifyFromCallback(kCallbackNameOnEnrollResult, args); return Void(); } - Return onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec&) override { - NotifyFromCallback(kCallbackNameOnAuthenticated); + Return onAuthenticated(uint64_t, uint32_t, int32_t userId, + const hidl_vec&) override { + FaceCallbackArgs args = {}; + args.userId = userId; + NotifyFromCallback(kCallbackNameOnAuthenticated, args); return Void(); } - Return onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override { - NotifyFromCallback(kCallbackNameOnAcquired); + Return onAcquired(uint64_t, int32_t userId, FaceAcquiredInfo, int32_t) override { + FaceCallbackArgs args = {}; + args.userId = userId; + NotifyFromCallback(kCallbackNameOnAcquired, args); return Void(); } - Return onError(uint64_t, int32_t, FaceError error, int32_t) override { + Return onError(uint64_t, int32_t userId, FaceError error, int32_t) override { FaceCallbackArgs args = {}; args.error = error; + args.userId = userId; NotifyFromCallback(kCallbackNameOnError, args); return Void(); } @@ -103,8 +111,10 @@ class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase onEnumerate(uint64_t, const hidl_vec&, int32_t) override { - NotifyFromCallback(kCallbackNameOnEnumerate); + Return onEnumerate(uint64_t, const hidl_vec&, int32_t userId) override { + FaceCallbackArgs args = {}; + args.userId = userId; + NotifyFromCallback(kCallbackNameOnEnumerate, args); return Void(); } @@ -185,6 +195,7 @@ TEST_F(FaceHidlTest, EnrollZeroHatTest) { // onError should be called with a meaningful (nonzero) error. auto res = mCallback->WaitForCallback(kCallbackNameOnError); EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kUserId, res.args->userId); EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error); } @@ -205,6 +216,7 @@ TEST_F(FaceHidlTest, EnrollGarbageHatTest) { // onError should be called with a meaningful (nonzero) error. auto res = mCallback->WaitForCallback(kCallbackNameOnError); EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kUserId, res.args->userId); EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error); } @@ -271,6 +283,7 @@ TEST_F(FaceHidlTest, EnumerateTest) { Return ret = mService->enumerate(); ASSERT_EQ(Status::OK, static_cast(ret)); auto res = mCallback->WaitForCallback(kCallbackNameOnEnumerate); + EXPECT_EQ(kUserId, res.args->userId); EXPECT_TRUE(res.no_timeout); } @@ -330,6 +343,7 @@ TEST_F(FaceHidlTest, CancelTest) { auto res = mCallback->WaitForCallback(kCallbackNameOnError); // make sure callback was invoked within kRevokeChallengeTimeout EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kUserId, res.args->userId); EXPECT_EQ(FaceError::CANCELED, res.args->error); } From 14fe1d9028130eb8e254335b7a6882fe781381a0 Mon Sep 17 00:00:00 2001 From: Kai Date: Thu, 5 Sep 2019 15:28:24 -0700 Subject: [PATCH 0103/1022] Add three vendor properties for e2e test Add three vendor properties for e2e test. By using those properties, it will mock the behavior of car's ECU. Bug: 140581574 Test: run test in VehcileHAL_test Change-Id: Ibf80419fb56532878fa8e6d4b4b105bcc6c41045 --- .../default/impl/vhal_v2_0/DefaultConfig.h | 53 +++++++++++++++++++ .../impl/vhal_v2_0/EmulatedVehicleHal.cpp | 45 ++++++++++++++-- 2 files changed, 94 insertions(+), 4 deletions(-) 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 4a42d79b0b..c8e11e3c30 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 @@ -84,6 +84,28 @@ constexpr int WHEEL_REAR_RIGHT = (int)VehicleAreaWheel::RIGHT_REAR; const int32_t kGenerateFakeDataControllingProperty = 0x0666 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED; +/** + * This property is used for test purpose to set properties' value from vehicle. + * For example: Mocking hard button press triggering a HVAC fan speed change. + * Android set kSetPropertyFromVehcileForTest with an array of integer {HVAC_FAN_SPEED, value of + * fan speed} and a long value indicates the timestamp of the events . + * It only works with integer type properties. + */ +const int32_t kSetIntPropertyFromVehcileForTest = + 0x1112 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED; +/** + * This property is used for test purpose to set properties' value from vehicle. + * It only works with float type properties. + */ +const int32_t kSetFloatPropertyFromVehcileForTest = + 0x1113 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED; +/** + * This property is used for test purpose to set properties' value from vehicle. + * It only works with boolean type properties. + */ +const int32_t kSetBooleanPropertyFromVehcileForTest = + 0x1114 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED; + /** * This property is used for test purpose. End to end tests use this property to test set and get * method for MIXED type properties. @@ -636,6 +658,37 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = kGenerateFakeDataControllingProperty, .access = VehiclePropertyAccess::WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {1, 0, 0, 2, 0, 0, 0, 0, 0}, + }, + }, + + { + .config = + { + .prop = kSetIntPropertyFromVehcileForTest, + .access = VehiclePropertyAccess::WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {0, 0, 0, 2, 1, 0, 0, 0, 0}, + }, + }, + + { + .config = + { + .prop = kSetFloatPropertyFromVehcileForTest, + .access = VehiclePropertyAccess::WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {0, 0, 1, 0, 1, 0, 1, 0, 0}, + }, + }, + + { + .config = + { + .prop = kSetBooleanPropertyFromVehcileForTest, + .access = VehiclePropertyAccess::WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {0, 1, 1, 0, 1, 0, 0, 0, 0}, }, }, 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 b4f1f07323..9d249be954 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 @@ -131,6 +131,36 @@ VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get( StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { static constexpr bool shouldUpdateStatus = false; + // set the value from vehcile side, used in end to end test. + if (propValue.prop == kSetIntPropertyFromVehcileForTest) { + auto mockValue = createVehiclePropValue(VehiclePropertyType::INT32, 1); + mockValue->prop = propValue.value.int32Values[0]; + mockValue->value.int32Values[0] = propValue.value.int32Values[1]; + mockValue->timestamp = propValue.value.int64Values[0]; + mockValue->areaId = propValue.areaId; + setPropertyFromVehicle(*mockValue); + return StatusCode::OK; + } + + if (propValue.prop == kSetFloatPropertyFromVehcileForTest) { + auto mockValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1); + mockValue->prop = propValue.value.int32Values[0]; + mockValue->value.floatValues[0] = propValue.value.floatValues[0]; + mockValue->timestamp = propValue.value.int64Values[0]; + mockValue->areaId = propValue.areaId; + setPropertyFromVehicle(*mockValue); + return StatusCode::OK; + } + if (propValue.prop == kSetBooleanPropertyFromVehcileForTest) { + auto mockValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1); + mockValue->prop = propValue.value.int32Values[1]; + mockValue->value.int32Values[0] = propValue.value.int32Values[0]; + mockValue->timestamp = propValue.value.int64Values[0]; + mockValue->areaId = propValue.areaId; + setPropertyFromVehicle(*mockValue); + return StatusCode::OK; + } + if (propValue.prop == kGenerateFakeDataControllingProperty) { StatusCode status = handleGenerateFakeDataRequest(propValue); if (status != StatusCode::OK) { @@ -198,12 +228,19 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { return StatusCode::NOT_AVAILABLE; } - if (!mPropStore->writeValue(propValue, shouldUpdateStatus)) { - return StatusCode::INVALID_ARG; + /** + * After checking all conditions, such as the property is available, a real vhal will + * sent the events to Car ECU to take actions. + * Google HAL will just add a timestamp for the value and triggle the callback to android. + */ + VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(propValue); + updatedPropValue->timestamp = elapsedRealtimeNano(); + if (!mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus)) { + return StatusCode::INTERNAL_ERROR; } - getEmulatorOrDie()->doSetValueFromClient(propValue); - doHalEvent(getValuePool()->obtain(propValue)); + getEmulatorOrDie()->doSetValueFromClient(*updatedPropValue); + doHalEvent(std::move(updatedPropValue)); return StatusCode::OK; } From 48544cc38a6499553672ca940fd6899af3d264b2 Mon Sep 17 00:00:00 2001 From: David Gross Date: Mon, 9 Sep 2019 14:32:09 -0700 Subject: [PATCH 0104/1022] "successful preparation means successful execution" guarantee neglects bad operation inputs Under certain circumstances, we guarantee that a prepared model can be executed successfully. In describing those circumstances, we neglected to specify that operation input operands must have legal values for the guarantee to hold. For example, the guarantee doesn't hold if an ADD operation has an activation input that is not one of the defined values; or if a RESHAPE operation has a shape input in which two or more components are -1. This change modifies the guarantee to apply only when operation input operands have legal values. It also documents this guarantee for burst execution. Note that if an operation has an input operand that can be proven to have an illegal value at preparation time (e.g., a constant value that is illegal), model preparation might (but is not required to) fail for that reason. Bug: 135933040 Test: $ cd neuralnetworks ; mma Change-Id: I8b421550dd89e4bbbdae899e7cb5e9e88a46d2fb --- current.txt | 4 ++-- neuralnetworks/1.0/IPreparedModel.hal | 13 ++++++++----- neuralnetworks/1.2/IPreparedModel.hal | 25 ++++++++++++++++++------- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/current.txt b/current.txt index 2aa9ef23b4..44eebf8a88 100644 --- a/current.txt +++ b/current.txt @@ -574,8 +574,8 @@ cfa81f229b69f9011c58f48264fcb552447430fe68610eac514e811e65bc306a android.hardwar # ABI preserving changes to HALs during Android R 2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice -ad431c8de51c07934a068e3043d8dd0537ac4d3158627706628b123f42df48dc android.hardware.neuralnetworks@1.0::IPreparedModel +eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice -aafcc10cf04ab247e86d4582586c71c6b4c2b8c479241ffa7fe37deb659fc942 android.hardware.neuralnetworks@1.2::IPreparedModel +6c5081dd131eeb7eb02efece2187cd4d7d554197800bb520c92ff874cc238fa6 android.hardware.neuralnetworks@1.2::IPreparedModel 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface diff --git a/neuralnetworks/1.0/IPreparedModel.hal b/neuralnetworks/1.0/IPreparedModel.hal index 53200506dd..3dc3202d7d 100644 --- a/neuralnetworks/1.0/IPreparedModel.hal +++ b/neuralnetworks/1.0/IPreparedModel.hal @@ -49,11 +49,14 @@ interface IPreparedModel { * must not change the content of any of the data objects corresponding to * 'request' inputs. * - * If the prepared model was prepared from a model wherein all - * tensor operands have fully specified dimensions, and the inputs - * to the function are valid, then the execution should launch - * and complete successfully (ErrorStatus::NONE). There must be - * no failure unless the device itself is in a bad state. + * If the prepared model was prepared from a model wherein all tensor + * operands have fully specified dimensions, and the inputs to the function + * are valid, then: + * - the execution should launch successfully (ErrorStatus::NONE): There + * must be no failure unless the device itself is in a bad state. + * - if at execution time every operation's input operands have legal + * values, the execution should complete successfully (ErrorStatus::NONE): + * There must be no failure unless the device itself is in a bad state. * * Multiple threads can call the execute function on the same IPreparedModel * object concurrently with different requests. diff --git a/neuralnetworks/1.2/IPreparedModel.hal b/neuralnetworks/1.2/IPreparedModel.hal index ba163342b8..f3508fede7 100644 --- a/neuralnetworks/1.2/IPreparedModel.hal +++ b/neuralnetworks/1.2/IPreparedModel.hal @@ -54,11 +54,14 @@ interface IPreparedModel extends @1.0::IPreparedModel { * must not change the content of any of the data objects corresponding to * 'request' inputs. * - * If the prepared model was prepared from a model wherein all - * tensor operands have fully specified dimensions, and the inputs - * to the function are valid, then the execution should launch - * and complete successfully (ErrorStatus::NONE). There must be - * no failure unless the device itself is in a bad state. + * If the prepared model was prepared from a model wherein all tensor + * operands have fully specified dimensions, and the inputs to the function + * are valid, then: + * - the execution should launch successfully (ErrorStatus::NONE): There + * must be no failure unless the device itself is in a bad state. + * - if at execution time every operation's input operands have legal + * values, the execution should complete successfully (ErrorStatus::NONE): + * There must be no failure unless the device itself is in a bad state. * * Any number of calls to the execute, execute_1_2, and executeSynchronously * functions, in any combination, may be made concurrently, even on the same @@ -105,8 +108,9 @@ interface IPreparedModel extends @1.0::IPreparedModel { * * If the prepared model was prepared from a model wherein all tensor * operands have fully specified dimensions, and the inputs to the function - * are valid, then the execution should complete successfully - * (ErrorStatus::NONE). There must be no failure unless the device itself is + * are valid, and at execution time every operation's input operands have + * legal values, then the execution should complete successfully + * (ErrorStatus::NONE): There must be no failure unless the device itself is * in a bad state. * * Any number of calls to the execute, execute_1_2, and executeSynchronously @@ -145,6 +149,13 @@ interface IPreparedModel extends @1.0::IPreparedModel { * Configure a Burst object used to execute multiple inferences on a * prepared model in rapid succession. * + * If the prepared model was prepared from a model wherein all tensor + * operands have fully specified dimensions, and a valid serialized Request + * is sent to the Burst for execution, and at execution time every + * operation's input operands have legal values, then the execution should + * complete successfully (ErrorStatus::NONE): There must be no failure + * unless the device itself is in a bad state. + * * @param callback A callback object used to retrieve memory resources * corresponding to a unique identifiers ("slots"). * @param requestChannel Used by the client to send a serialized Request to From d909580269eca0faee37bccc5823c002c3e0e829 Mon Sep 17 00:00:00 2001 From: Pete Bentley Date: Tue, 10 Sep 2019 17:21:04 +0100 Subject: [PATCH 0105/1022] Remove unused libcrypto dependency. libcrypto is unused, which causes problems when boringssl hash injection is turned on as the code is all stripped and there is nothing left to inject the hash into. See http://r.android.com/1117291 for the AOSP change to related modules. Bug: 137267623 Test: croot hardware/interfaces/wifi && mma Change-Id: I9d002c0b723cf9a04ee64641b5281e65912595c8 --- wifi/supplicant/1.3/vts/functional/Android.bp | 3 --- 1 file changed, 3 deletions(-) diff --git a/wifi/supplicant/1.3/vts/functional/Android.bp b/wifi/supplicant/1.3/vts/functional/Android.bp index 6f58168c23..67c73481f2 100644 --- a/wifi/supplicant/1.3/vts/functional/Android.bp +++ b/wifi/supplicant/1.3/vts/functional/Android.bp @@ -31,7 +31,6 @@ cc_library_static { "android.hardware.wifi.supplicant@1.2", "android.hardware.wifi.supplicant@1.3", "android.hardware.wifi@1.0", - "libcrypto", "libgmock", "libwifi-system", "libwifi-system-iface", @@ -57,11 +56,9 @@ cc_test { "android.hardware.wifi.supplicant@1.3", "android.hardware.wifi@1.0", "android.hardware.wifi@1.1", - "libcrypto", "libgmock", "libwifi-system", "libwifi-system-iface", ], test_suites: ["general-tests"], } - From 1638531dfbb242a48cd59441a8bab1b0b484f9b9 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Tue, 10 Sep 2019 14:54:36 -0700 Subject: [PATCH 0106/1022] MultiHal 2.0 - proxying api calls helper methods Create getSubHalForSensorHandle method which will get the proper subhal pointer by getting the subhal list index from the first byte of the sensor handle. Create the zeroOutFirstByte static helper method that will return a version of the sensor handle without the first byte when passed a handle. Test: Tested compilation. Bug: 136511617 Change-Id: I7d07003e1903aa1d8abaf904b778248c7b352653 --- sensors/2.0/multihal/HalProxy.cpp | 8 ++++++++ sensors/2.0/multihal/include/HalProxy.h | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index 80d7296793..964f5893aa 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -218,6 +218,14 @@ Return HalProxy::onDynamicSensorsDisconnected( return Return(); } +ISensorsSubHal* HalProxy::getSubHalForSensorHandle(uint32_t sensorHandle) { + return mSubHalList[static_cast(sensorHandle >> 24)]; +} + +uint32_t HalProxy::zeroOutFirstByte(uint32_t num) { + return num & 0x00FFFFFF; +} + } // namespace implementation } // namespace V2_0 } // namespace sensors diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h index 9d5787c655..809d07e98b 100644 --- a/sensors/2.0/multihal/include/HalProxy.h +++ b/sensors/2.0/multihal/include/HalProxy.h @@ -118,6 +118,24 @@ struct HalProxy : public ISensors { * SubHal object pointers that have been saved from vendor dynamic libraries. */ std::vector mSubHalList; + + /* + * Get the subhal pointer which can be found by indexing into the mSubHalList vector + * using the index from the first byte of sensorHandle. + * + * @param sensorHandle The handle used to identify a sensor in one of the subhals. + */ + ISensorsSubHal* getSubHalForSensorHandle(uint32_t sensorHandle); + + /* + * Zero out the first (most significant) byte in a number. Used in modifying the sensor handles + * before passing them to subhals. + * + * @param num The uint32_t number to work with. + * + * @return The modified version of num param. + */ + static uint32_t zeroOutFirstByte(uint32_t num); }; } // namespace implementation From 4b4c7b744db68a297c192be417d2ab4b1128e717 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Tue, 10 Sep 2019 15:07:59 -0700 Subject: [PATCH 0107/1022] MultiHal 2.0 - activate, batch, flush methods of HalProxy These three methods of HalProxy simply call the apropriate ISensors methods of the subhal pointed to by sensorHandle. Test: Loaded onto device and observed no crashing. Bug: 136511617 Change-Id: If90652554ea18c22b24aead0074ab9847eae0a4f --- sensors/2.0/multihal/HalProxy.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index 964f5893aa..dcdccac2be 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -123,9 +123,9 @@ Return HalProxy::setOperationMode(OperationMode /* mode */) { return Result::INVALID_OPERATION; } -Return HalProxy::activate(int32_t /* sensorHandle */, bool /* enabled */) { - // TODO: Proxy API call to appropriate sub-HAL. - return Result::INVALID_OPERATION; +Return HalProxy::activate(int32_t sensorHandle, bool enabled) { + return getSubHalForSensorHandle(sensorHandle) + ->activate(zeroOutFirstByte(sensorHandle), enabled); } Return HalProxy::initialize( @@ -163,15 +163,14 @@ Return HalProxy::initialize( return result; } -Return HalProxy::batch(int32_t /* sensorHandle */, int64_t /* samplingPeriodNs */, - int64_t /* maxReportLatencyNs */) { - // TODO: Proxy API call to appropriate sub-HAL. - return Result::INVALID_OPERATION; +Return HalProxy::batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) { + return getSubHalForSensorHandle(sensorHandle) + ->batch(zeroOutFirstByte(sensorHandle), samplingPeriodNs, maxReportLatencyNs); } -Return HalProxy::flush(int32_t /* sensorHandle */) { - // TODO: Proxy API call to appropriate sub-HAL. - return Result::INVALID_OPERATION; +Return HalProxy::flush(int32_t sensorHandle) { + return getSubHalForSensorHandle(sensorHandle)->flush(zeroOutFirstByte(sensorHandle)); } Return HalProxy::injectSensorData(const Event& /* event */) { From 6a05e9113ab93976fa1e7af9f41aa0af7832b56e Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Wed, 11 Sep 2019 14:17:09 -0700 Subject: [PATCH 0108/1022] Returning HWC2_CAPABILITY_SKIP_VALIDATE capability if device supports it For reasons unknown, HWC2_CAPABILITY_SKIP_VALIDATE was never added to the IComposer hal. However, we would like to tell the client that the device has this capability when it is returned during a getCapabilities query. We manually add it to the list of IComposer::Capability (static_cast should be ok since the IComposer::Capability has a fixed underlying type of int32_t, and HWC2_CAPABILITY_SKIP_VALIDATE = 4 is in this range). Checking that device has skip validate functionality in relevent test as well Bug: 140813883 Test: build, boot, VtsHalGraphicsComposerV2_1TargetTest Change-Id: I5f28268c4e6edeb2895502c5f4e009cebb566100 --- .../2.1/utils/hal/include/composer-hal/2.1/Composer.h | 8 ++++++++ .../functional/VtsHalGraphicsComposerV2_1TargetTest.cpp | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h index 62a163c91c..4b8c6bbf26 100644 --- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h +++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h @@ -67,6 +67,14 @@ class ComposerImpl : public Interface { } } + // we do not have HWC2_CAPABILITY_SKIP_VALIDATE defined in + // IComposer::Capability. However, this is defined in hwcomposer2.h, + // so if the device returns it, add it manually to be returned to the + // client + if (mHal->hasCapability(HWC2_CAPABILITY_SKIP_VALIDATE)) { + caps.push_back(static_cast(HWC2_CAPABILITY_SKIP_VALIDATE)); + } + hidl_vec caps_reply; caps_reply.setToExternal(caps.data(), caps.size()); hidl_cb(caps_reply); diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp index 5d2f65deab..9477ee665b 100644 --- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp +++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -789,6 +790,12 @@ TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY) { * surface damage have been set */ TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) { + if (!mComposer->hasCapability( + static_cast(HWC2_CAPABILITY_SKIP_VALIDATE))) { + std::cout << "Device does not have skip validate capability, skipping" << std::endl; + GTEST_SUCCEED(); + return; + } mWriter->selectDisplay(mPrimaryDisplay); mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::ON); mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::NATIVE); From dc7a8e7898a443b59beb0ee22bd387b1f53a0730 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Fri, 23 Aug 2019 12:35:40 -0700 Subject: [PATCH 0109/1022] MultiHal 2.0 - Get sensors list from subhals Implement SubHal constructors. The default ctor will get the SubHal object pointers from dynamic libraries. The test ctor will take a vector of SubHal objects. Implment the HalProxy getSensorsList method which will return all the sensors from the subhal objects. Create one unit test for getSensorsList as well. Bug: 136511617 Test: Flashed onto device and observed proper logs for both test subhals. Also, passed getSensorsList test. Change-Id: I6e8ca4883c50daabbd7b0955d3664f66b6cd74bf --- sensors/2.0/multihal/HalProxy.cpp | 94 ++++++++++++------- sensors/2.0/multihal/include/HalProxy.h | 24 ++++- sensors/2.0/multihal/include/SubHal.h | 1 + sensors/2.0/multihal/tests/Android.bp | 2 +- sensors/2.0/multihal/tests/HalProxy_test.cpp | 60 +++++++++++- .../tests/fake_subhal/SensorsSubHal.cpp | 53 +++++++---- .../tests/fake_subhal/SensorsSubHal.h | 23 ++++- 7 files changed, 199 insertions(+), 58 deletions(-) diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index dcdccac2be..d8bde8354c 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -70,42 +70,12 @@ class SensorsCallbackProxy : public ISensorsCallback { HalProxy::HalProxy() { const char* kMultiHalConfigFilePath = "/vendor/etc/sensors/hals.conf"; - std::ifstream subHalConfigStream(kMultiHalConfigFilePath); - if (!subHalConfigStream) { - LOG_FATAL("Failed to load subHal config file: %s", kMultiHalConfigFilePath); - } else { - std::string subHalLibraryFile; - while (subHalConfigStream >> subHalLibraryFile) { - void* handle = dlopen(subHalLibraryFile.c_str(), RTLD_NOW); - if (handle == nullptr) { - LOG_FATAL("dlopen failed for library: %s", subHalLibraryFile.c_str()); - } else { - SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr = - (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal"); - if (sensorsHalGetSubHalPtr == nullptr) { - LOG_FATAL("Failed to locate sensorsHalGetSubHal function for library: %s", - subHalLibraryFile.c_str()); - } else { - std::function sensorsHalGetSubHal = - *sensorsHalGetSubHalPtr; - uint32_t version; - ISensorsSubHal* subHal = sensorsHalGetSubHal(&version); - if (version != SUB_HAL_2_0_VERSION) { - LOG_FATAL("SubHal version was not 2.0 for library: %s", - subHalLibraryFile.c_str()); - } else { - ALOGI("Loaded SubHal from library: %s", subHalLibraryFile.c_str()); - mSubHalList.push_back(subHal); - } - } - } - } - } - // TODO: Discover sensors + initializeSubHalListFromConfigFile(kMultiHalConfigFilePath); + initializeSensorList(); } HalProxy::HalProxy(std::vector& subHalList) : mSubHalList(subHalList) { - // TODO: Perform the same steps as the empty constructor. + initializeSensorList(); } HalProxy::~HalProxy() { @@ -113,8 +83,8 @@ HalProxy::~HalProxy() { // state. } -Return HalProxy::getSensorsList(getSensorsList_cb /* _hidl_cb */) { - // TODO: Output sensors list created as part of HalProxy(). +Return HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) { + _hidl_cb(mSensorList); return Void(); } @@ -217,6 +187,60 @@ Return HalProxy::onDynamicSensorsDisconnected( return Return(); } +void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) { + std::ifstream subHalConfigStream(configFileName); + if (!subHalConfigStream) { + LOG_FATAL("Failed to load subHal config file: %s", configFileName); + } else { + std::string subHalLibraryFile; + while (subHalConfigStream >> subHalLibraryFile) { + void* handle = dlopen(subHalLibraryFile.c_str(), RTLD_NOW); + if (handle == nullptr) { + LOG_FATAL("dlopen failed for library: %s", subHalLibraryFile.c_str()); + } else { + SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr = + (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal"); + if (sensorsHalGetSubHalPtr == nullptr) { + LOG_FATAL("Failed to locate sensorsHalGetSubHal function for library: %s", + subHalLibraryFile.c_str()); + } else { + std::function sensorsHalGetSubHal = + *sensorsHalGetSubHalPtr; + uint32_t version; + ISensorsSubHal* subHal = sensorsHalGetSubHal(&version); + if (version != SUB_HAL_2_0_VERSION) { + LOG_FATAL("SubHal version was not 2.0 for library: %s", + subHalLibraryFile.c_str()); + } else { + ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str()); + mSubHalList.push_back(subHal); + } + } + } + } + } +} + +void HalProxy::initializeSensorList() { + for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) { + ISensorsSubHal* subHal = mSubHalList[subHalIndex]; + auto result = subHal->getSensorsList([&](const auto& list) { + for (SensorInfo sensor : list) { + if ((sensor.sensorHandle & 0xFF000000) != 0) { + ALOGE("SubHal sensorHandle's first byte was not 0"); + } else { + ALOGV("Loaded sensor: %s", sensor.name.c_str()); + sensor.sensorHandle |= (subHalIndex << 24); + mSensorList.push_back(sensor); + } + } + }); + if (!result.isOk()) { + ALOGE("getSensorsList call failed for SubHal: %s", subHal->getName().c_str()); + } + } +} + ISensorsSubHal* HalProxy::getSubHalForSensorHandle(uint32_t sensorHandle) { return mSubHalList[static_cast(sensorHandle >> 24)]; } diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h index 809d07e98b..b0261c8c7d 100644 --- a/sensors/2.0/multihal/include/HalProxy.h +++ b/sensors/2.0/multihal/include/HalProxy.h @@ -39,7 +39,8 @@ using ::android::hardware::MQDescriptor; using ::android::hardware::Return; using ::android::hardware::Void; -struct HalProxy : public ISensors { +class HalProxy : public ISensors { + public: using Event = ::android::hardware::sensors::V1_0::Event; using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; @@ -119,6 +120,27 @@ struct HalProxy : public ISensors { */ std::vector mSubHalList; + /** + * List of SensorInfo objects that contains the sensor info from subhals as + * well as the modified sensor handle for the framework. + * + * The subhal index is encoded in the first byte of the sensor handle and + * the remaining bytes are generated by the subhal. + */ + std::vector mSensorList; + + /** + * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries + * listed in a config file. + */ + void initializeSubHalListFromConfigFile(const char* configFileName); + + /** + * Initialize the list of SensorInfo objects in mSensorList by getting sensors from each + * subhal. + */ + void initializeSensorList(); + /* * Get the subhal pointer which can be found by indexing into the mSubHalList vector * using the index from the first byte of sensorHandle. diff --git a/sensors/2.0/multihal/include/SubHal.h b/sensors/2.0/multihal/include/SubHal.h index 75e93a18b5..e84cba50f6 100644 --- a/sensors/2.0/multihal/include/SubHal.h +++ b/sensors/2.0/multihal/include/SubHal.h @@ -137,6 +137,7 @@ class IHalProxyCallback : public ISensorsCallback { * sub-HALs can continue to use the lower 3 bytes of the handle. */ class ISensorsSubHal : public ISensors { + public: // The ISensors version of initialize isn't used for multihal. Instead, sub-HALs must implement // the version below to allow communciation logic to centralized in the HalProxy Return initialize( diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp index 13d80f7a6d..21ceb0c2d7 100644 --- a/sensors/2.0/multihal/tests/Android.bp +++ b/sensors/2.0/multihal/tests/Android.bp @@ -86,4 +86,4 @@ cc_test { "libutils", ], test_suites: ["device-tests"], -} \ No newline at end of file +} diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp index 9edc88a424..28004d0d32 100644 --- a/sensors/2.0/multihal/tests/HalProxy_test.cpp +++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp @@ -18,7 +18,14 @@ #include "HalProxy.h" #include "SensorsSubHal.h" +#include + +using ::android::hardware::sensors::V1_0::SensorInfo; +using ::android::hardware::sensors::V1_0::SensorType; using ::android::hardware::sensors::V2_0::implementation::HalProxy; +using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal; +using ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal; +using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal; // TODO: Add more interesting tests such as @@ -30,10 +37,55 @@ using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal; // // See https://source.android.com/compatibility/tests/development/native-func-e2e.md for more info // on how tests are set up and for information on the gtest framework itself. -TEST(HalProxyTest, ExampleTest) { - SensorsSubHal subHal; - std::vector fakeSubHals; - fakeSubHals.push_back(&subHal); +// Helper declarations follow +void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, + const std::vector& subHalSensorsList); + +// Tests follow +TEST(HalProxyTest, GetSensorsListOneSubHalTest) { + AllSensorsSubHal subHal; + std::vector fakeSubHals{&subHal}; HalProxy proxy(fakeSubHals); + + proxy.getSensorsList([&](const auto& proxySensorsList) { + subHal.getSensorsList([&](const auto& subHalSensorsList) { + testSensorsListFromProxyAndSubHal(proxySensorsList, subHalSensorsList); + }); + }); +} + +TEST(HalProxyTest, GetSensorsListTwoSubHalTest) { + ContinuousSensorsSubHal continuousSubHal; + OnChangeSensorsSubHal onChangeSubHal; + std::vector fakeSubHals; + fakeSubHals.push_back(&continuousSubHal); + fakeSubHals.push_back(&onChangeSubHal); + HalProxy proxy(fakeSubHals); + + std::vector proxySensorsList, combinedSubHalSensorsList; + + proxy.getSensorsList([&](const auto& list) { proxySensorsList = list; }); + continuousSubHal.getSensorsList([&](const auto& list) { + combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end()); + }); + onChangeSubHal.getSensorsList([&](const auto& list) { + combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end()); + }); + + testSensorsListFromProxyAndSubHal(proxySensorsList, combinedSubHalSensorsList); +} + +// Helper implementations follow +void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, + const std::vector& subHalSensorsList) { + EXPECT_EQ(proxySensorsList.size(), subHalSensorsList.size()); + + for (size_t i = 0; i < proxySensorsList.size(); i++) { + const SensorInfo& proxySensor = proxySensorsList[i]; + const SensorInfo& subHalSensor = subHalSensorsList[i]; + + EXPECT_EQ(proxySensor.type, subHalSensor.type); + EXPECT_EQ(proxySensor.sensorHandle & 0x00FFFFFF, subHalSensor.sensorHandle); + } } \ No newline at end of file diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp index 8d459824dc..fe471616c5 100644 --- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp +++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp @@ -20,7 +20,16 @@ #include ISensorsSubHal* sensorsHalGetSubHal(uint32_t* version) { +#if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS + static ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal subHal; +#elif defined SUPPORT_CONTINUOUS_SENSORS + static ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal + subHal; +#elif defined SUPPORT_ON_CHANGE_SENSORS + static ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal subHal; +#else static ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal subHal; +#endif // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS *version = SUB_HAL_2_0_VERSION; return &subHal; } @@ -42,22 +51,7 @@ using ::android::hardware::sensors::V2_0::SensorTimeout; using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock; -SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) { -#ifdef SUPPORT_CONTINUOUS_SENSORS - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); -#endif // SUPPORT_CONTINUOUS_SENSORS - -#ifdef SUPPORT_ON_CHANGE_SENSORS - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); -#endif // SUPPORT_ON_CHANGE_SENSORS -} +SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {} // Methods from ::android::hardware::sensors::V2_0::ISensors follow. Return SensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) { @@ -171,6 +165,33 @@ void SensorsSubHal::postEvents(const std::vector& events, bool wakeup) { mCallback->postEvents(events, std::move(wakelock)); } +ContinuousSensorsSubHal::ContinuousSensorsSubHal() { + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); +} + +OnChangeSensorsSubHal::OnChangeSensorsSubHal() { + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); +} + +AllSensorsSubHal::AllSensorsSubHal() { + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); +} + } // namespace implementation } // namespace subhal } // namespace V2_0 diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h index 93009d5833..d94d73d536 100644 --- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h +++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h @@ -20,6 +20,8 @@ #include "Sensor.h" +#include + namespace android { namespace hardware { namespace sensors { @@ -81,7 +83,7 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { // Method from ISensorsEventCallback. void postEvents(const std::vector& events, bool wakeup) override; - private: + protected: template void AddSensor() { std::shared_ptr sensor = @@ -89,6 +91,7 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { mSensors[sensor->getSensorInfo().sensorHandle] = sensor; } + private: /** * Callback used to communicate to the HalProxy when dynamic sensors are connected / * disconnected, sensor events need to be sent to the framework, and when a wakelock should be @@ -107,6 +110,24 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { int32_t mNextHandle; }; +// SubHal that has continuous sensors for testing purposes. +class ContinuousSensorsSubHal : public SensorsSubHal { + public: + ContinuousSensorsSubHal(); +}; + +// SubHal that has on-change sensors for testing purposes. +class OnChangeSensorsSubHal : public SensorsSubHal { + public: + OnChangeSensorsSubHal(); +}; + +// SubHal that has both continuous and on-change sensors for testing purposes. +class AllSensorsSubHal : public SensorsSubHal { + public: + AllSensorsSubHal(); +}; + } // namespace implementation } // namespace subhal } // namespace V2_0 From 7a7235461f19e4ce5a19e34271e4efd3c6d49a70 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Thu, 29 Aug 2019 15:47:50 -0700 Subject: [PATCH 0110/1022] MultiHal 2.0 - setOperationMode and init direct channel flags Implement setOperationMode method of HalProxy object and initialized the direct channel flag for the sensors list. Also create some unit tests to test both of these new additions in HalProxy_test.cpp. Bug: 136511617 Test: Tested using unit tests and tested on device with both fake subhals Change-Id: I4e39ca0e94b3e109706d628612d1db9c98aca053 --- sensors/2.0/multihal/Android.bp | 1 + sensors/2.0/multihal/HalProxy.cpp | 55 ++++++-- sensors/2.0/multihal/include/HalProxy.h | 19 ++- sensors/2.0/multihal/service.cpp | 2 - sensors/2.0/multihal/tests/HalProxy_test.cpp | 119 ++++++++++++++++-- .../tests/fake_subhal/SensorsSubHal.cpp | 29 +++++ .../tests/fake_subhal/SensorsSubHal.h | 41 ++++-- 7 files changed, 233 insertions(+), 33 deletions(-) diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp index 44dddfd4e9..697bf9e117 100644 --- a/sensors/2.0/multihal/Android.bp +++ b/sensors/2.0/multihal/Android.bp @@ -45,6 +45,7 @@ cc_binary { ], init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"], vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"], + cflags: ["-DLOG_TAG=\"SensorsMultiHal\""], } cc_library_headers { diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index d8bde8354c..28dae93ebd 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -69,8 +69,8 @@ class SensorsCallbackProxy : public ISensorsCallback { }; HalProxy::HalProxy() { - const char* kMultiHalConfigFilePath = "/vendor/etc/sensors/hals.conf"; - initializeSubHalListFromConfigFile(kMultiHalConfigFilePath); + const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf"; + initializeSubHalListFromConfigFile(kMultiHalConfigFile); initializeSensorList(); } @@ -88,9 +88,27 @@ Return HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) { return Void(); } -Return HalProxy::setOperationMode(OperationMode /* mode */) { - // TODO: Proxy API call to all sub-HALs and return appropriate result. - return Result::INVALID_OPERATION; +Return HalProxy::setOperationMode(OperationMode mode) { + Result result = Result::OK; + size_t subHalIndex; + for (subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) { + ISensorsSubHal* subHal = mSubHalList[subHalIndex]; + result = subHal->setOperationMode(mode); + if (result != Result::OK) { + ALOGE("setOperationMode failed for SubHal: %s", subHal->getName().c_str()); + break; + } + } + if (result != Result::OK) { + // Reset the subhal operation modes that have been flipped + for (size_t i = 0; i < subHalIndex; i++) { + ISensorsSubHal* subHal = mSubHalList[i]; + subHal->setOperationMode(mCurrentOperationMode); + } + } else { + mCurrentOperationMode = mode; + } + return result; } Return HalProxy::activate(int32_t sensorHandle, bool enabled) { @@ -190,27 +208,27 @@ Return HalProxy::onDynamicSensorsDisconnected( void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) { std::ifstream subHalConfigStream(configFileName); if (!subHalConfigStream) { - LOG_FATAL("Failed to load subHal config file: %s", configFileName); + ALOGE("Failed to load subHal config file: %s", configFileName); } else { std::string subHalLibraryFile; while (subHalConfigStream >> subHalLibraryFile) { void* handle = dlopen(subHalLibraryFile.c_str(), RTLD_NOW); if (handle == nullptr) { - LOG_FATAL("dlopen failed for library: %s", subHalLibraryFile.c_str()); + ALOGE("dlopen failed for library: %s", subHalLibraryFile.c_str()); } else { SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr = (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal"); if (sensorsHalGetSubHalPtr == nullptr) { - LOG_FATAL("Failed to locate sensorsHalGetSubHal function for library: %s", - subHalLibraryFile.c_str()); + ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s", + subHalLibraryFile.c_str()); } else { std::function sensorsHalGetSubHal = *sensorsHalGetSubHalPtr; uint32_t version; ISensorsSubHal* subHal = sensorsHalGetSubHal(&version); if (version != SUB_HAL_2_0_VERSION) { - LOG_FATAL("SubHal version was not 2.0 for library: %s", - subHalLibraryFile.c_str()); + ALOGE("SubHal version was not 2.0 for library: %s", + subHalLibraryFile.c_str()); } else { ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str()); mSubHalList.push_back(subHal); @@ -231,6 +249,7 @@ void HalProxy::initializeSensorList() { } else { ALOGV("Loaded sensor: %s", sensor.name.c_str()); sensor.sensorHandle |= (subHalIndex << 24); + setDirectChannelFlags(&sensor, subHal); mSensorList.push_back(sensor); } } @@ -241,6 +260,20 @@ void HalProxy::initializeSensorList() { } } +void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal) { + bool sensorSupportsDirectChannel = + (sensorInfo->flags & (V1_0::SensorFlagBits::MASK_DIRECT_REPORT | + V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL)) != 0; + if (mDirectChannelSubHal == nullptr && sensorSupportsDirectChannel) { + mDirectChannelSubHal = subHal; + } else if (mDirectChannelSubHal != nullptr && subHal != mDirectChannelSubHal) { + // disable direct channel capability for sensors in subHals that are not + // the only one we will enable + sensorInfo->flags &= ~(V1_0::SensorFlagBits::MASK_DIRECT_REPORT | + V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL); + } +} + ISensorsSubHal* HalProxy::getSubHalForSensorHandle(uint32_t sensorHandle) { return mSubHalList[static_cast(sensorHandle >> 24)]; } diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h index b0261c8c7d..24b5081591 100644 --- a/sensors/2.0/multihal/include/HalProxy.h +++ b/sensors/2.0/multihal/include/HalProxy.h @@ -125,10 +125,16 @@ class HalProxy : public ISensors { * well as the modified sensor handle for the framework. * * The subhal index is encoded in the first byte of the sensor handle and - * the remaining bytes are generated by the subhal. + * the remaining bytes are generated by the subhal to identify the sensor. */ std::vector mSensorList; + //! The current operation mode for all subhals. + OperationMode mCurrentOperationMode = OperationMode::NORMAL; + + //! The single subHal that supports directChannel reporting. + ISensorsSubHal* mDirectChannelSubHal = nullptr; + /** * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries * listed in a config file. @@ -141,6 +147,17 @@ class HalProxy : public ISensors { */ void initializeSensorList(); + /** + * Clear direct channel flags if the HalProxy has already chosen a subhal as its direct channel + * subhal. Set the directChannelSubHal pointer to the subHal passed in if this is the first + * direct channel enabled sensor seen. + * + * @param sensorInfo The SensorInfo object that may be altered to have direct channel support + * disabled. + * @param subHal The subhal pointer that the current sensorInfo object came from. + */ + void setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal); + /* * Get the subhal pointer which can be found by indexing into the mSubHalList vector * using the index from the first byte of sensorHandle. diff --git a/sensors/2.0/multihal/service.cpp b/sensors/2.0/multihal/service.cpp index 995cf3cbe0..ef77048020 100644 --- a/sensors/2.0/multihal/service.cpp +++ b/sensors/2.0/multihal/service.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#define LOG_TAG "android.hardware.sensors@2.0-service" - #include #include #include diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp index 28004d0d32..1e1f9e9e44 100644 --- a/sensors/2.0/multihal/tests/HalProxy_test.cpp +++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp @@ -15,33 +15,56 @@ #include +#include + #include "HalProxy.h" #include "SensorsSubHal.h" #include +namespace { + +using ::android::hardware::sensors::V1_0::SensorFlagBits; using ::android::hardware::sensors::V1_0::SensorInfo; using ::android::hardware::sensors::V1_0::SensorType; using ::android::hardware::sensors::V2_0::implementation::HalProxy; using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal; +using ::android::hardware::sensors::V2_0::subhal::implementation:: + AllSupportDirectChannelSensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal; +using ::android::hardware::sensors::V2_0::subhal::implementation:: + DoesNotSupportDirectChannelSensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal; -// TODO: Add more interesting tests such as -// - verify setOperationMode invokes all subhals -// - verify if a subhal fails to change operation mode, that state is reset properly -// - Available sensors are obtained during initialization -// -// You can run this suite using "atest android.hardware.sensors@2.0-halproxy-unit-tests". -// -// See https://source.android.com/compatibility/tests/development/native-func-e2e.md for more info -// on how tests are set up and for information on the gtest framework itself. +using ::android::hardware::sensors::V2_0::subhal::implementation:: + SetOperationModeFailingSensorsSubHal; // Helper declarations follow + +/** + * Tests that for each SensorInfo object from a proxy getSensorsList call each corresponding + * object from a subhal getSensorsList call has the same type and its last 3 bytes are the + * same for sensorHandle field. + * + * @param proxySensorsList The list of SensorInfo objects from the proxy.getSensorsList callback. + * @param subHalSenosrsList The list of SensorInfo objects from the subHal.getSensorsList callback. + */ void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, const std::vector& subHalSensorsList); +/** + * Tests that there is exactly one subhal that allows its sensors to have direct channel enabled. + * Therefore, all SensorInfo objects that are not from the enabled subhal should be disabled for + * direct channel. + * + * @param sensorsList The SensorInfo object list from proxy.getSensorsList call. + * @param enabledSubHalIndex The index of the subhal in the halproxy that is expected to be + * enabled. + */ +void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector& sensorsList, + size_t enabledSubHalIndex); + // Tests follow TEST(HalProxyTest, GetSensorsListOneSubHalTest) { AllSensorsSubHal subHal; @@ -76,6 +99,63 @@ TEST(HalProxyTest, GetSensorsListTwoSubHalTest) { testSensorsListFromProxyAndSubHal(proxySensorsList, combinedSubHalSensorsList); } +TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) { + ContinuousSensorsSubHal subHal1; + OnChangeSensorsSubHal subHal2; + + std::vector fakeSubHals{&subHal1, &subHal2}; + HalProxy proxy(fakeSubHals); + + EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL); + EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL); + + Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION); + + EXPECT_EQ(result, Result::OK); + EXPECT_EQ(subHal1.getOperationMode(), OperationMode::DATA_INJECTION); + EXPECT_EQ(subHal2.getOperationMode(), OperationMode::DATA_INJECTION); +} + +TEST(HalProxyTest, SetOperationModeTwoSubHalFailTest) { + AllSensorsSubHal subHal1; + SetOperationModeFailingSensorsSubHal subHal2; + + std::vector fakeSubHals{&subHal1, &subHal2}; + HalProxy proxy(fakeSubHals); + + EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL); + EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL); + + Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION); + + EXPECT_NE(result, Result::OK); + EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL); + EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL); +} + +TEST(HalProxyTest, InitDirectChannelTwoSubHalsUnitTest) { + AllSupportDirectChannelSensorsSubHal subHal1; + AllSupportDirectChannelSensorsSubHal subHal2; + + std::vector fakeSubHals{&subHal1, &subHal2}; + HalProxy proxy(fakeSubHals); + + proxy.getSensorsList([&](const auto& sensorsList) { + testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 0); + }); +} + +TEST(HalProxyTest, InitDirectChannelThreeSubHalsUnitTest) { + DoesNotSupportDirectChannelSensorsSubHal subHal1; + AllSupportDirectChannelSensorsSubHal subHal2, subHal3; + std::vector fakeSubHals{&subHal1, &subHal2, &subHal3}; + HalProxy proxy(fakeSubHals); + + proxy.getSensorsList([&](const auto& sensorsList) { + testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 1); + }); +} + // Helper implementations follow void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, const std::vector& subHalSensorsList) { @@ -88,4 +168,23 @@ void testSensorsListFromProxyAndSubHal(const std::vector& proxySenso EXPECT_EQ(proxySensor.type, subHalSensor.type); EXPECT_EQ(proxySensor.sensorHandle & 0x00FFFFFF, subHalSensor.sensorHandle); } -} \ No newline at end of file +} + +void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector& sensorsList, + size_t enabledSubHalIndex) { + for (const SensorInfo& sensor : sensorsList) { + size_t subHalIndex = static_cast(sensor.sensorHandle >> 24); + if (subHalIndex == enabledSubHalIndex) { + // First subhal should have been picked as the direct channel subhal + // and so have direct channel enabled on all of its sensors + EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0); + EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0); + } else { + // All other subhals should have direct channel disabled for all sensors + EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0); + EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0); + } + } +} + +} // namespace diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp index fe471616c5..d581c49a32 100644 --- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp +++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp @@ -68,6 +68,7 @@ Return SensorsSubHal::setOperationMode(OperationMode mode) { for (auto sensor : mSensors) { sensor.second->setOperationMode(mode); } + mCurrentOperationMode = mode; return Result::OK; } @@ -192,6 +193,34 @@ AllSensorsSubHal::AllSensorsSubHal() { AddSensor(); } +Return SetOperationModeFailingSensorsSubHal::setOperationMode(OperationMode /*mode*/) { + return Result::BAD_VALUE; +} + +Return AllSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) { + std::vector sensors; + for (const auto& sensor : mSensors) { + SensorInfo sensorInfo = sensor.second->getSensorInfo(); + sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL; + sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_REPORT; + sensors.push_back(sensorInfo); + } + _hidl_cb(sensors); + return Void(); +} + +Return DoesNotSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) { + std::vector sensors; + for (const auto& sensor : mSensors) { + SensorInfo sensorInfo = sensor.second->getSensorInfo(); + sensorInfo.flags &= ~static_cast(V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL); + sensorInfo.flags &= ~static_cast(V1_0::SensorFlagBits::MASK_DIRECT_REPORT); + sensors.push_back(sensorInfo); + } + _hidl_cb(sensors); + return Void(); +} + } // namespace implementation } // namespace subhal } // namespace V2_0 diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h index d94d73d536..61caa2c39e 100644 --- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h +++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h @@ -29,6 +29,8 @@ namespace V2_0 { namespace subhal { namespace implementation { +using ::android::hardware::sensors::V1_0::OperationMode; +using ::android::hardware::sensors::V1_0::Result; using ::android::hardware::sensors::V2_0::implementation::IHalProxyCallback; /** @@ -37,18 +39,18 @@ using ::android::hardware::sensors::V2_0::implementation::IHalProxyCallback; */ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { using Event = ::android::hardware::sensors::V1_0::Event; - using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; - using Result = ::android::hardware::sensors::V1_0::Result; using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; public: SensorsSubHal(); // Methods from ::android::hardware::sensors::V2_0::ISensors follow. - Return getSensorsList(getSensorsList_cb _hidl_cb) override; + virtual Return getSensorsList(getSensorsList_cb _hidl_cb) override; - Return setOperationMode(OperationMode mode) override; + virtual Return setOperationMode(OperationMode mode) override; + + OperationMode getOperationMode() const { return mCurrentOperationMode; } Return activate(int32_t sensorHandle, bool enabled) override; @@ -91,7 +93,18 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { mSensors[sensor->getSensorInfo().sensorHandle] = sensor; } + /** + * A map of the available sensors + */ + std::map> mSensors; + private: + /** + * The current operation mode of the multihal framework. Ensures that all subhals are set to + * the same operation mode. + */ + OperationMode mCurrentOperationMode = OperationMode::NORMAL; + /** * Callback used to communicate to the HalProxy when dynamic sensors are connected / * disconnected, sensor events need to be sent to the framework, and when a wakelock should be @@ -99,11 +112,6 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { */ sp mCallback; - /** - * A map of the available sensors - */ - std::map> mSensors; - /** * The next available sensor handle */ @@ -128,6 +136,21 @@ class AllSensorsSubHal : public SensorsSubHal { AllSensorsSubHal(); }; +class SetOperationModeFailingSensorsSubHal : public AllSensorsSubHal { + public: + Return setOperationMode(OperationMode mode) override; +}; + +class AllSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { + public: + Return getSensorsList(getSensorsList_cb _hidl_cb) override; +}; + +class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { + public: + Return getSensorsList(getSensorsList_cb _hidl_cb) override; +}; + } // namespace implementation } // namespace subhal } // namespace V2_0 From f99bffd08a3e4f212a306a67b97509a2335f6b87 Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Mon, 24 Jun 2019 10:57:02 -0700 Subject: [PATCH 0111/1022] Specify NNAPI Burst FMQ read/write requirements This CL additionally adds missing documentation for timing information when returning results on the resultChannel. Bug: 133773876 Test: mma Change-Id: I1eb1affbb4a912d5fdeab012e2be7e7005deb04d --- current.txt | 2 +- neuralnetworks/1.2/IPreparedModel.hal | 52 +++++++++++++++++++-------- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/current.txt b/current.txt index 44eebf8a88..83657b2d47 100644 --- a/current.txt +++ b/current.txt @@ -576,6 +576,6 @@ cfa81f229b69f9011c58f48264fcb552447430fe68610eac514e811e65bc306a android.hardwar b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice -6c5081dd131eeb7eb02efece2187cd4d7d554197800bb520c92ff874cc238fa6 android.hardware.neuralnetworks@1.2::IPreparedModel +40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface diff --git a/neuralnetworks/1.2/IPreparedModel.hal b/neuralnetworks/1.2/IPreparedModel.hal index f3508fede7..1445f18e4d 100644 --- a/neuralnetworks/1.2/IPreparedModel.hal +++ b/neuralnetworks/1.2/IPreparedModel.hal @@ -157,22 +157,44 @@ interface IPreparedModel extends @1.0::IPreparedModel { * unless the device itself is in a bad state. * * @param callback A callback object used to retrieve memory resources - * corresponding to a unique identifiers ("slots"). - * @param requestChannel Used by the client to send a serialized Request to - * the Burst for execution. The client must not change - * the content of any data object referenced by the - * Request (described by the {@link @1.0::DataLocation} - * of an {@link OperandInformation}) until a result - * has been received from resultChannel. Execution - * must not change the content of any of the data - * objects corresponding to Request inputs. requestChannel + * corresponding to unique identifiers ("slots"). + * @param requestChannel FMQ used by the client to send a serialized Request + * to the Burst for execution. The client must not + * change the content of any data object referenced by + * the Request (described by the + * {@link @1.0::DataLocation} of an + * {@link OperandInformation}) until a result has been + * received from resultChannel. Execution must not + * change the content of any of the data objects + * corresponding to Request inputs. requestChannel * must not be used to pass a second Request object - * until a result has been received from resultChannel. - * @param resultChannel Used by the service to return the results of an - * execution to the client: the status of the execution - * and OutputShape of all output tensors. resultChannel - * must be used to return the results if a Request was - * sent through the requestChannel. + * until a result has been received from + * resultChannel. The client must send the request + * messages to the consumer atomically by using + * MessageQueue::writeBlocking if the queue is + * blocking, or by using MessageQueue::write if the + * queue is non-blocking. When the service receives a + * packet, it must dequeue the entire packet from the + * requestChannel. The client must not send a request + * packet that exceeds the length of the FMQ. + * @param resultChannel FMQ used by the service to return the results of an + * execution to the client: the status of the + * execution, OutputShape of all output tensors, and + * timing information. resultChannel must be used to + * return the results if a Request was sent through the + * requestChannel. The service must send the result + * messages to the consumer atomically by using + * MessageQueue::writeBlocking if the queue is + * blocking, or by using MessageQueue::write if the + * queue is non-blocking. When the client receives a + * packet, it must dequeue the entire packet from the + * resultChannel. If the packet's length exceeds the + * size of the FMQ, the service must not send this + * result packet; instead, the service must send a + * packet consisting of the error code + * ErrorStatus::GENERAL_FAILURE, no information for the + * outputShapes, and an indication that timing + * information is unavailable. * @return status Error status of configuring the execution burst, must be: * - NONE if the burst is successfully configured * - DEVICE_UNAVAILABLE if driver is offline or busy From f97a3f3579e68d30328e751a0f85da7d3066e5c1 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Fri, 13 Sep 2019 09:58:47 -0700 Subject: [PATCH 0112/1022] Multihal 2.0 - Small tweaks to sensorHandle handling Add the sensor handle to subhal index bitmask as a constant. Change the name of zeroOutFirstByte method to clearSubHalIndex and use the constant there. Also use the constant in initSensorsList method. Bug: 136511617 Test: Tested compilation success. Change-Id: I3983850827697ff77c484e7b8d33e7722a7fb52a --- sensors/2.0/multihal/HalProxy.cpp | 12 ++++++------ sensors/2.0/multihal/include/HalProxy.h | 12 +++++++----- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index 28dae93ebd..b4d246690d 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -113,7 +113,7 @@ Return HalProxy::setOperationMode(OperationMode mode) { Return HalProxy::activate(int32_t sensorHandle, bool enabled) { return getSubHalForSensorHandle(sensorHandle) - ->activate(zeroOutFirstByte(sensorHandle), enabled); + ->activate(clearSubHalIndex(sensorHandle), enabled); } Return HalProxy::initialize( @@ -154,11 +154,11 @@ Return HalProxy::initialize( Return HalProxy::batch(int32_t sensorHandle, int64_t samplingPeriodNs, int64_t maxReportLatencyNs) { return getSubHalForSensorHandle(sensorHandle) - ->batch(zeroOutFirstByte(sensorHandle), samplingPeriodNs, maxReportLatencyNs); + ->batch(clearSubHalIndex(sensorHandle), samplingPeriodNs, maxReportLatencyNs); } Return HalProxy::flush(int32_t sensorHandle) { - return getSubHalForSensorHandle(sensorHandle)->flush(zeroOutFirstByte(sensorHandle)); + return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle)); } Return HalProxy::injectSensorData(const Event& /* event */) { @@ -244,7 +244,7 @@ void HalProxy::initializeSensorList() { ISensorsSubHal* subHal = mSubHalList[subHalIndex]; auto result = subHal->getSensorsList([&](const auto& list) { for (SensorInfo sensor : list) { - if ((sensor.sensorHandle & 0xFF000000) != 0) { + if ((sensor.sensorHandle & kSensorHandleSubHalIndexMask) != 0) { ALOGE("SubHal sensorHandle's first byte was not 0"); } else { ALOGV("Loaded sensor: %s", sensor.name.c_str()); @@ -278,8 +278,8 @@ ISensorsSubHal* HalProxy::getSubHalForSensorHandle(uint32_t sensorHandle) { return mSubHalList[static_cast(sensorHandle >> 24)]; } -uint32_t HalProxy::zeroOutFirstByte(uint32_t num) { - return num & 0x00FFFFFF; +uint32_t HalProxy::clearSubHalIndex(uint32_t sensorHandle) { + return sensorHandle & (~kSensorHandleSubHalIndexMask); } } // namespace implementation diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h index 24b5081591..4ecb58b5a5 100644 --- a/sensors/2.0/multihal/include/HalProxy.h +++ b/sensors/2.0/multihal/include/HalProxy.h @@ -135,6 +135,9 @@ class HalProxy : public ISensors { //! The single subHal that supports directChannel reporting. ISensorsSubHal* mDirectChannelSubHal = nullptr; + //! The bit mask used to get the subhal index from a sensor handle. + static constexpr uint32_t kSensorHandleSubHalIndexMask = 0xFF000000; + /** * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries * listed in a config file. @@ -167,14 +170,13 @@ class HalProxy : public ISensors { ISensorsSubHal* getSubHalForSensorHandle(uint32_t sensorHandle); /* - * Zero out the first (most significant) byte in a number. Used in modifying the sensor handles - * before passing them to subhals. + * Clear out the subhal index bytes from a sensorHandle. * - * @param num The uint32_t number to work with. + * @param sensorHandle The sensor handle to modify. * - * @return The modified version of num param. + * @return The modified version of the sensor handle. */ - static uint32_t zeroOutFirstByte(uint32_t num); + static uint32_t clearSubHalIndex(uint32_t sensorHandle); }; } // namespace implementation From 11107873aa5fecc0a76cbea97c10766bf80ad6f4 Mon Sep 17 00:00:00 2001 From: Ytai Ben-Tsvi Date: Mon, 9 Sep 2019 11:50:45 -0700 Subject: [PATCH 0113/1022] Improve visibility of IMemory security risks This change renames the IMemory raw pointer accessors to unsecure*() to make it apparent to coders and code reviewers that the returned buffer may potentially be shared with untrusted processes, who may, after the fact, attempt to read and/or modify the contents. This may lead to hard to find security bugs and hopefully the rename makes it harder to forget. The change also attempts to fix all the callsites to make everything build correctly, but in the processes, wherever the callsite code was not obviously secure, I added a TODO requesting the owners to either document why it's secure or to change the code. Apologies in advance to the owners if there are some false positives here - I don't have enough context to reason about all the different callsites. Test: Completely syntactic change. Made sure code still builds. Change-Id: Icfde96b17f8c763dcf304456c224127310c1c289 --- cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp | 4 ++-- cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp index 14b8bbdd5a..f0bba57137 100644 --- a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp +++ b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp @@ -325,7 +325,7 @@ class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionFailure(); } - uint8_t* ipBuffer = static_cast(static_cast(mem->pointer())); + uint8_t* ipBuffer = static_cast(static_cast(mem->unsecurePointer())); memcpy(ipBuffer, kInBinaryBuffer, sizeof(kInBinaryBuffer)); // hidlMemory is not to be passed out of scope! @@ -568,7 +568,7 @@ TEST_F(MediaCasHidlTest, TestClearKeyApis) { EXPECT_EQ(Status::OK, descrambleStatus); ASSERT_NE(nullptr, dataMemory.get()); - uint8_t* opBuffer = static_cast(static_cast(dataMemory->pointer())); + uint8_t* opBuffer = static_cast(static_cast(dataMemory->unsecurePointer())); int compareResult = memcmp(static_cast(opBuffer), static_cast(kOutRefBinaryBuffer), diff --git a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp index 88f1fb01d6..0264bddedd 100644 --- a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp +++ b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp @@ -366,7 +366,7 @@ class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionFailure(); } - uint8_t* ipBuffer = static_cast(static_cast(mem->pointer())); + uint8_t* ipBuffer = static_cast(static_cast(mem->unsecurePointer())); memcpy(ipBuffer, kInBinaryBuffer, sizeof(kInBinaryBuffer)); // hidlMemory is not to be passed out of scope! @@ -543,7 +543,7 @@ TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) { EXPECT_EQ(Status::OK, descrambleStatus); ASSERT_NE(nullptr, dataMemory.get()); - uint8_t* opBuffer = static_cast(static_cast(dataMemory->pointer())); + uint8_t* opBuffer = static_cast(static_cast(dataMemory->unsecurePointer())); int compareResult = memcmp(static_cast(opBuffer), From 7076f629b75aa24e9759d1efea874662744dd4bf Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Thu, 29 Aug 2019 11:08:25 -0700 Subject: [PATCH 0114/1022] Change NNAPI VTS to use TEST_P to iterate across all service instances This CL removes a dependency on the VTS test runner by dynamically discovering all NN HAL service instances in the gtest binary itself, and runs through all service instances with parameterized tests. This CL converts TEST_F cases to TEST_P cases, where the test parameter is the name of the service instance. For existing TEST_P cases (such as the generated test cases), the service instance name is made to be the first test parameter. This CL enables the NN VTS tests to be more portable, e.g., they can run directly as a presubmit test. Fixes: 124540002 Test: mma Test: VtsHalNeuralnetworksV1_*TargetTest (with sample-all) Test: cd $ANDROID_BUILD_TOP/hardware/interfaces/neuralnetworks && atest Change-Id: I1e301d7c9f9342bb8f35a267bef180f510944b19 --- neuralnetworks/1.0/vts/functional/Android.bp | 33 ++------- .../1.0/vts/functional/BasicTests.cpp | 6 +- .../vts/functional/GeneratedTestHarness.cpp | 14 ++++ .../1.0/vts/functional/GeneratedTestHarness.h | 29 +++++--- neuralnetworks/1.0/vts/functional/Utils.cpp | 7 ++ .../vts/functional/VtsHalNeuralnetworks.cpp | 70 +++++++++--------- .../1.0/vts/functional/VtsHalNeuralnetworks.h | 42 +++++------ .../1.0/vts/functional/include/1.0/Utils.h | 19 ++++- neuralnetworks/1.1/vts/functional/Android.bp | 36 ++-------- .../1.1/vts/functional/BasicTests.cpp | 6 +- .../vts/functional/GeneratedTestHarness.cpp | 14 ++++ .../1.1/vts/functional/GeneratedTestHarness.h | 29 +++++--- .../vts/functional/VtsHalNeuralnetworks.cpp | 72 +++++++++---------- .../1.1/vts/functional/VtsHalNeuralnetworks.h | 42 +++++------ neuralnetworks/1.2/vts/functional/Android.bp | 49 ++++--------- .../1.2/vts/functional/BasicTests.cpp | 14 ++-- .../functional/CompilationCachingTests.cpp | 60 ++++++++++++---- .../vts/functional/GeneratedTestHarness.cpp | 16 ++++- .../1.2/vts/functional/GeneratedTestHarness.h | 31 +++++--- .../1.2/vts/functional/ValidateBurst.cpp | 4 +- .../1.2/vts/functional/ValidateRequest.cpp | 2 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 72 +++++++++---------- .../1.2/vts/functional/VtsHalNeuralnetworks.h | 41 +++++------ neuralnetworks/TEST_MAPPING | 21 ++++-- 24 files changed, 379 insertions(+), 350 deletions(-) diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp index 0af7f79860..3e9d5f7e83 100644 --- a/neuralnetworks/1.0/vts/functional/Android.bp +++ b/neuralnetworks/1.0/vts/functional/Android.bp @@ -40,10 +40,11 @@ cc_library_static { ], } -cc_defaults { - name: "VtsHalNeuralNetworksV1_0TargetTestDefaults", +cc_test { + name: "VtsHalNeuralnetworksV1_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ + "BasicTests.cpp", "TestAssertions.cpp", "ValidateModel.cpp", "ValidateRequest.cpp", @@ -64,33 +65,11 @@ cc_defaults { "libneuralnetworks_utils", "VtsHalNeuralNetworksV1_0_utils", ], + whole_static_libs: [ + "neuralnetworks_generated_V1_0_example", + ], header_libs: [ "libneuralnetworks_headers", ], test_suites: ["general-tests"], } - -cc_test { - name: "VtsHalNeuralnetworksV1_0TargetTest", - defaults: ["VtsHalNeuralNetworksV1_0TargetTestDefaults"], - srcs: [ - "BasicTests.cpp", - ], - whole_static_libs: [ - "neuralnetworks_generated_V1_0_example", - ], -} - -cc_test { - name: "PresubmitHalNeuralnetworksV1_0TargetTest", - defaults: ["VtsHalNeuralNetworksV1_0TargetTestDefaults"], - srcs: [ - "BasicTests.cpp", - ], - whole_static_libs: [ - "neuralnetworks_generated_V1_0_example", - ], - cflags: [ - "-DPRESUBMIT_NOT_VTS", - ], -} diff --git a/neuralnetworks/1.0/vts/functional/BasicTests.cpp b/neuralnetworks/1.0/vts/functional/BasicTests.cpp index 551ea6788a..cc44c9efe1 100644 --- a/neuralnetworks/1.0/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.0/vts/functional/BasicTests.cpp @@ -21,17 +21,17 @@ namespace android::hardware::neuralnetworks::V1_0::vts::functional { // create device test -TEST_F(NeuralnetworksHidlTest, CreateDevice) {} +TEST_P(NeuralnetworksHidlTest, CreateDevice) {} // status test -TEST_F(NeuralnetworksHidlTest, StatusTest) { +TEST_P(NeuralnetworksHidlTest, StatusTest) { Return status = kDevice->getStatus(); ASSERT_TRUE(status.isOk()); EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast(status)); } // initialization -TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) { +TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) { Return ret = kDevice->getCapabilities([](ErrorStatus status, const Capabilities& capabilities) { EXPECT_EQ(ErrorStatus::NONE, status); diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp index 1948c053a9..595ad85633 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp @@ -148,6 +148,20 @@ void Execute(const sp& device, const TestModel& testModel) { checkResults(testModel, outputs); } +void GeneratedTestBase::SetUp() { + testing::TestWithParam::SetUp(); + ASSERT_NE(kDevice, nullptr); +} + +std::vector getNamedModels(const FilterFn& filter) { + return TestModelManager::get().getTestModels(filter); +} + +std::string printGeneratedTest(const testing::TestParamInfo& info) { + const auto& [namedDevice, namedModel] = info.param; + return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel)); +} + // Tag for the generated tests class GeneratedTest : public GeneratedTestBase {}; diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h index 10e46b7d2c..f230a028f3 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h @@ -18,29 +18,38 @@ #define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_GENERATED_TEST_HARNESS_H #include +#include #include "TestHarness.h" #include "VtsHalNeuralnetworks.h" namespace android::hardware::neuralnetworks::V1_0::vts::functional { -class GeneratedTestBase - : public NeuralnetworksHidlTest, - public testing::WithParamInterface { +using NamedModel = Named; +using GeneratedTestParam = std::tuple; + +class GeneratedTestBase : public testing::TestWithParam { protected: - const test_helper::TestModel& kTestModel = *GetParam().second; + void SetUp() override; + const sp kDevice = getData(std::get(GetParam())); + const test_helper::TestModel& kTestModel = *getData(std::get(GetParam())); }; -#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ - INSTANTIATE_TEST_SUITE_P( \ - TestGenerated, TestSuite, \ - testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \ - [](const auto& info) { return info.param.first; }) +using FilterFn = std::function; +std::vector getNamedModels(const FilterFn& filter); + +std::string printGeneratedTest(const testing::TestParamInfo& info); + +#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ + INSTANTIATE_TEST_SUITE_P(TestGenerated, TestSuite, \ + testing::Combine(testing::ValuesIn(getNamedDevices()), \ + testing::ValuesIn(getNamedModels(filter))), \ + printGeneratedTest) // Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp. // TODO: Clean up the hierarchy for ValidationTest. class ValidationTest : public GeneratedTestBase {}; -Model createModel(const ::test_helper::TestModel& testModel); +Model createModel(const test_helper::TestModel& testModel); } // namespace android::hardware::neuralnetworks::V1_0::vts::functional diff --git a/neuralnetworks/1.0/vts/functional/Utils.cpp b/neuralnetworks/1.0/vts/functional/Utils.cpp index 307003cf4a..5b630fd7a6 100644 --- a/neuralnetworks/1.0/vts/functional/Utils.cpp +++ b/neuralnetworks/1.0/vts/functional/Utils.cpp @@ -117,6 +117,13 @@ std::vector getOutputBuffers(const Request& request) { return outputBuffers; } +std::string gtestCompliantName(std::string name) { + // gtest test names must only contain alphanumeric characters + std::replace_if( + name.begin(), name.end(), [](char c) { return !std::isalnum(c); }, '_'); + return name; +} + } // namespace android::hardware::neuralnetworks namespace android::hardware::neuralnetworks::V1_0 { diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp index 20b4565a47..cb2225025b 100644 --- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp @@ -18,11 +18,13 @@ #include "VtsHalNeuralnetworks.h" #include "1.0/Callbacks.h" -#include "1.0/Utils.h" #include "GeneratedTestHarness.h" #include "TestHarness.h" #include +#include +#include +#include namespace android::hardware::neuralnetworks::V1_0::vts::functional { @@ -76,34 +78,39 @@ void createPreparedModel(const sp& device, const Model& model, ASSERT_NE(nullptr, preparedModel->get()); } -// A class for test environment setup -NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() { - // This has to return a "new" object because it is freed inside - // testing::AddGlobalTestEnvironment when the gtest is being torn down - static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment(); - return instance; -} - -void NeuralnetworksHidlEnvironment::registerTestServices() { - registerTestService(); -} - -// The main test class for NEURALNETWORK HIDL HAL. void NeuralnetworksHidlTest::SetUp() { - testing::VtsHalHidlTargetTestBase::SetUp(); - -#ifdef PRESUBMIT_NOT_VTS - const std::string name = - NeuralnetworksHidlEnvironment::getInstance()->getServiceName(); - const std::string sampleDriver = "sample-"; - if (kDevice == nullptr && name.substr(0, sampleDriver.size()) == sampleDriver) { - GTEST_SKIP(); - } -#endif // PRESUBMIT_NOT_VTS - - ASSERT_NE(nullptr, kDevice.get()); + testing::TestWithParam::SetUp(); + ASSERT_NE(kDevice, nullptr); } +static NamedDevice makeNamedDevice(const std::string& name) { + return {name, IDevice::getService(name)}; +} + +static std::vector getNamedDevicesImpl() { + // Retrieves the name of all service instances that implement IDevice, + // including any Lazy HAL instances. + const std::vector names = hardware::getAllHalInstanceNames(IDevice::descriptor); + + // Get a handle to each device and pair it with its name. + std::vector namedDevices; + namedDevices.reserve(names.size()); + std::transform(names.begin(), names.end(), std::back_inserter(namedDevices), makeNamedDevice); + return namedDevices; +} + +const std::vector& getNamedDevices() { + const static std::vector devices = getNamedDevicesImpl(); + return devices; +} + +std::string printNeuralnetworksHidlTest( + const testing::TestParamInfo& info) { + return gtestCompliantName(getName(info.param)); +} + +INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest); + // Forward declaration from ValidateModel.cpp void validateModel(const sp& device, const Model& model); // Forward declaration from ValidateRequest.cpp @@ -130,14 +137,3 @@ TEST_P(ValidationTest, Test) { INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); } // namespace android::hardware::neuralnetworks::V1_0::vts::functional - -using android::hardware::neuralnetworks::V1_0::vts::functional::NeuralnetworksHidlEnvironment; - -int main(int argc, char** argv) { - testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance()); - testing::InitGoogleTest(&argc, argv); - NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv); - - int status = RUN_ALL_TESTS(); - return status; -} diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h index 48dc23774f..17f4613ac6 100644 --- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h @@ -17,40 +17,34 @@ #ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_VTS_HAL_NEURALNETWORKS_H #define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_VTS_HAL_NEURALNETWORKS_H +#include "1.0/Utils.h" + #include #include - -#include -#include - -#include #include +#include + namespace android::hardware::neuralnetworks::V1_0::vts::functional { -// A class for test environment setup -class NeuralnetworksHidlEnvironment : public testing::VtsHalHidlTargetTestEnvBase { - DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment); - NeuralnetworksHidlEnvironment() = default; - - public: - static NeuralnetworksHidlEnvironment* getInstance(); - void registerTestServices() override; -}; - -// The main test class for NEURALNETWORKS HIDL HAL. -class NeuralnetworksHidlTest : public testing::VtsHalHidlTargetTestBase { - DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest); - - public: - NeuralnetworksHidlTest() = default; - void SetUp() override; +using NamedDevice = Named>; +using NeuralnetworksHidlTestParam = NamedDevice; +class NeuralnetworksHidlTest : public testing::TestWithParam { protected: - const sp kDevice = testing::VtsHalHidlTargetTestBase::getService( - NeuralnetworksHidlEnvironment::getInstance()); + void SetUp() override; + const sp kDevice = getData(GetParam()); }; +const std::vector& getNamedDevices(); + +std::string printNeuralnetworksHidlTest( + const testing::TestParamInfo& info); + +#define INSTANTIATE_DEVICE_TEST(TestSuite) \ + INSTANTIATE_TEST_SUITE_P(PerInstance, TestSuite, testing::ValuesIn(getNamedDevices()), \ + printNeuralnetworksHidlTest) + // Create an IPreparedModel object. If the model cannot be prepared, // "preparedModel" will be nullptr instead. void createPreparedModel(const sp& device, const Model& model, diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h index 1ce751c54c..6d4534cb4e 100644 --- a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h +++ b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h @@ -21,13 +21,15 @@ #include #include #include +#include +#include #include #include "TestHarness.h" namespace android::hardware::neuralnetworks { // Create HIDL Request from the TestModel struct. -V1_0::Request createRequest(const ::test_helper::TestModel& testModel); +V1_0::Request createRequest(const test_helper::TestModel& testModel); // After execution, copy out output results from the output memory pool. std::vector<::test_helper::TestBuffer> getOutputBuffers(const V1_0::Request& request); @@ -51,6 +53,21 @@ inline uint32_t hidl_vec_push_back(hidl_vec* vec, const Type& value) { return index; } +template +using Named = std::pair; + +template +const std::string& getName(const Named& namedData) { + return namedData.first; +} + +template +const Type& getData(const Named& namedData) { + return namedData.second; +} + +std::string gtestCompliantName(std::string name); + } // namespace android::hardware::neuralnetworks namespace android::hardware::neuralnetworks::V1_0 { diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp index c197e6de66..4e85355838 100644 --- a/neuralnetworks/1.1/vts/functional/Android.bp +++ b/neuralnetworks/1.1/vts/functional/Android.bp @@ -14,10 +14,11 @@ // limitations under the License. // -cc_defaults { - name: "VtsHalNeuralNetworksV1_1TargetTestDefaults", +cc_test { + name: "VtsHalNeuralnetworksV1_1TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ + "BasicTests.cpp", "TestAssertions.cpp", "ValidateModel.cpp", "ValidateRequest.cpp", @@ -39,35 +40,12 @@ cc_defaults { "libneuralnetworks_utils", "VtsHalNeuralNetworksV1_0_utils", ], + whole_static_libs: [ + "neuralnetworks_generated_V1_0_example", + "neuralnetworks_generated_V1_1_example", + ], header_libs: [ "libneuralnetworks_headers", ], test_suites: ["general-tests"], } - -cc_test { - name: "VtsHalNeuralnetworksV1_1TargetTest", - defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"], - srcs: [ - "BasicTests.cpp", - ], - whole_static_libs: [ - "neuralnetworks_generated_V1_0_example", - "neuralnetworks_generated_V1_1_example", - ], -} - -cc_test { - name: "PresubmitHalNeuralnetworksV1_1TargetTest", - defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"], - srcs: [ - "BasicTests.cpp", - ], - whole_static_libs: [ - "neuralnetworks_generated_V1_0_example", - "neuralnetworks_generated_V1_1_example", - ], - cflags: [ - "-DPRESUBMIT_NOT_VTS", - ], -} diff --git a/neuralnetworks/1.1/vts/functional/BasicTests.cpp b/neuralnetworks/1.1/vts/functional/BasicTests.cpp index 2791e804c3..44836f0c95 100644 --- a/neuralnetworks/1.1/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.1/vts/functional/BasicTests.cpp @@ -24,17 +24,17 @@ using V1_0::DeviceStatus; using V1_0::ErrorStatus; // create device test -TEST_F(NeuralnetworksHidlTest, CreateDevice) {} +TEST_P(NeuralnetworksHidlTest, CreateDevice) {} // status test -TEST_F(NeuralnetworksHidlTest, StatusTest) { +TEST_P(NeuralnetworksHidlTest, StatusTest) { Return status = kDevice->getStatus(); ASSERT_TRUE(status.isOk()); EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast(status)); } // initialization -TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) { +TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) { Return ret = kDevice->getCapabilities_1_1([](ErrorStatus status, const Capabilities& capabilities) { EXPECT_EQ(ErrorStatus::NONE, status); diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp index fddfc2bb28..7a929d6063 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp @@ -156,6 +156,20 @@ void Execute(const sp& device, const TestModel& testModel) { checkResults(testModel, outputs); } +void GeneratedTestBase::SetUp() { + testing::TestWithParam::SetUp(); + ASSERT_NE(kDevice, nullptr); +} + +std::vector getNamedModels(const FilterFn& filter) { + return TestModelManager::get().getTestModels(filter); +} + +std::string printGeneratedTest(const testing::TestParamInfo& info) { + const auto& [namedDevice, namedModel] = info.param; + return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel)); +} + // Tag for the generated tests class GeneratedTest : public GeneratedTestBase {}; diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h index 273d1ec66a..cf449ea42d 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h @@ -18,29 +18,38 @@ #define ANDROID_HARDWARE_NEURALNETWORKS_V1_1_GENERATED_TEST_HARNESS_H #include +#include "1.0/Utils.h" #include "TestHarness.h" #include "VtsHalNeuralnetworks.h" namespace android::hardware::neuralnetworks::V1_1::vts::functional { -class GeneratedTestBase - : public NeuralnetworksHidlTest, - public testing::WithParamInterface { +using NamedModel = Named; +using GeneratedTestParam = std::tuple; + +class GeneratedTestBase : public testing::TestWithParam { protected: - const test_helper::TestModel& kTestModel = *GetParam().second; + void SetUp() override; + const sp kDevice = getData(std::get(GetParam())); + const test_helper::TestModel& kTestModel = *getData(std::get(GetParam())); }; -#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ - INSTANTIATE_TEST_SUITE_P( \ - TestGenerated, TestSuite, \ - testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \ - [](const auto& info) { return info.param.first; }) +using FilterFn = std::function; +std::vector getNamedModels(const FilterFn& filter); + +std::string printGeneratedTest(const testing::TestParamInfo& info); + +#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ + INSTANTIATE_TEST_SUITE_P(TestGenerated, TestSuite, \ + testing::Combine(testing::ValuesIn(getNamedDevices()), \ + testing::ValuesIn(getNamedModels(filter))), \ + printGeneratedTest) // Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp. // TODO: Clean up the hierarchy for ValidationTest. class ValidationTest : public GeneratedTestBase {}; -Model createModel(const ::test_helper::TestModel& testModel); +Model createModel(const test_helper::TestModel& testModel); } // namespace android::hardware::neuralnetworks::V1_1::vts::functional diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp index d53d43e0b6..d56d40b2ba 100644 --- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp @@ -17,13 +17,15 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" #include "VtsHalNeuralnetworks.h" +#include +#include +#include +#include #include "1.0/Callbacks.h" #include "1.0/Utils.h" #include "GeneratedTestHarness.h" #include "TestHarness.h" -#include - namespace android::hardware::neuralnetworks::V1_1::vts::functional { using V1_0::ErrorStatus; @@ -79,34 +81,39 @@ void createPreparedModel(const sp& device, const Model& model, ASSERT_NE(nullptr, preparedModel->get()); } -// A class for test environment setup -NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() { - // This has to return a "new" object because it is freed inside - // testing::AddGlobalTestEnvironment when the gtest is being torn down - static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment(); - return instance; -} - -void NeuralnetworksHidlEnvironment::registerTestServices() { - registerTestService(); -} - -// The main test class for NEURALNETWORK HIDL HAL. void NeuralnetworksHidlTest::SetUp() { - testing::VtsHalHidlTargetTestBase::SetUp(); - -#ifdef PRESUBMIT_NOT_VTS - const std::string name = - NeuralnetworksHidlEnvironment::getInstance()->getServiceName(); - const std::string sampleDriver = "sample-"; - if (kDevice == nullptr && name.substr(0, sampleDriver.size()) == sampleDriver) { - GTEST_SKIP(); - } -#endif // PRESUBMIT_NOT_VTS - - ASSERT_NE(nullptr, kDevice.get()); + testing::TestWithParam::SetUp(); + ASSERT_NE(kDevice, nullptr); } +static NamedDevice makeNamedDevice(const std::string& name) { + return {name, IDevice::getService(name)}; +} + +static std::vector getNamedDevicesImpl() { + // Retrieves the name of all service instances that implement IDevice, + // including any Lazy HAL instances. + const std::vector names = hardware::getAllHalInstanceNames(IDevice::descriptor); + + // Get a handle to each device and pair it with its name. + std::vector namedDevices; + namedDevices.reserve(names.size()); + std::transform(names.begin(), names.end(), std::back_inserter(namedDevices), makeNamedDevice); + return namedDevices; +} + +const std::vector& getNamedDevices() { + const static std::vector devices = getNamedDevicesImpl(); + return devices; +} + +std::string printNeuralnetworksHidlTest( + const testing::TestParamInfo& info) { + return gtestCompliantName(getName(info.param)); +} + +INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest); + // Forward declaration from ValidateModel.cpp void validateModel(const sp& device, const Model& model); // Forward declaration from ValidateRequest.cpp @@ -133,14 +140,3 @@ TEST_P(ValidationTest, Test) { INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); } // namespace android::hardware::neuralnetworks::V1_1::vts::functional - -using android::hardware::neuralnetworks::V1_1::vts::functional::NeuralnetworksHidlEnvironment; - -int main(int argc, char** argv) { - testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance()); - testing::InitGoogleTest(&argc, argv); - NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv); - - int status = RUN_ALL_TESTS(); - return status; -} diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h index 9d6194a143..e879d843d2 100644 --- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h @@ -17,41 +17,33 @@ #ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_1_VTS_HAL_NEURALNETWORKS_H #define ANDROID_HARDWARE_NEURALNETWORKS_V1_1_VTS_HAL_NEURALNETWORKS_H -#include +#include #include #include - -#include -#include - -#include #include +#include +#include "1.0/Utils.h" namespace android::hardware::neuralnetworks::V1_1::vts::functional { -// A class for test environment setup -class NeuralnetworksHidlEnvironment : public testing::VtsHalHidlTargetTestEnvBase { - DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment); - NeuralnetworksHidlEnvironment() = default; - - public: - static NeuralnetworksHidlEnvironment* getInstance(); - void registerTestServices() override; -}; - -// The main test class for NEURALNETWORKS HIDL HAL. -class NeuralnetworksHidlTest : public testing::VtsHalHidlTargetTestBase { - DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest); - - public: - NeuralnetworksHidlTest() = default; - void SetUp() override; +using NamedDevice = Named>; +using NeuralnetworksHidlTestParam = NamedDevice; +class NeuralnetworksHidlTest : public testing::TestWithParam { protected: - const sp kDevice = testing::VtsHalHidlTargetTestBase::getService( - NeuralnetworksHidlEnvironment::getInstance()); + void SetUp() override; + const sp kDevice = getData(GetParam()); }; +const std::vector& getNamedDevices(); + +std::string printNeuralnetworksHidlTest( + const testing::TestParamInfo& info); + +#define INSTANTIATE_DEVICE_TEST(TestSuite) \ + INSTANTIATE_TEST_SUITE_P(PerInstance, TestSuite, testing::ValuesIn(getNamedDevices()), \ + printNeuralnetworksHidlTest) + // Create an IPreparedModel object. If the model cannot be prepared, // "preparedModel" will be nullptr instead. void createPreparedModel(const sp& device, const Model& model, diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index 40ca809612..3ba8879ae9 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -14,16 +14,19 @@ // limitations under the License. // -cc_defaults { - name: "VtsHalNeuralNetworksV1_2TargetTestDefaults", +cc_test { + name: "VtsHalNeuralnetworksV1_2TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ + "BasicTests.cpp", + "Callbacks.cpp", + "CompilationCachingTests.cpp", + "GeneratedTestHarness.cpp", "TestAssertions.cpp", "ValidateModel.cpp", "ValidateRequest.cpp", + "ValidateBurst.cpp", "VtsHalNeuralnetworks.cpp", - "Callbacks.cpp", - "GeneratedTestHarness.cpp", ], local_include_dirs: ["include"], shared_libs: [ @@ -42,41 +45,13 @@ cc_defaults { "libneuralnetworks_utils", "VtsHalNeuralNetworksV1_0_utils", ], + whole_static_libs: [ + "neuralnetworks_generated_V1_0_example", + "neuralnetworks_generated_V1_1_example", + "neuralnetworks_generated_V1_2_example", + ], header_libs: [ "libneuralnetworks_headers", ], test_suites: ["general-tests"], } - -cc_test { - name: "VtsHalNeuralnetworksV1_2TargetTest", - defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], - srcs: [ - "BasicTests.cpp", - "CompilationCachingTests.cpp", - "ValidateBurst.cpp", - ], - whole_static_libs: [ - "neuralnetworks_generated_V1_0_example", - "neuralnetworks_generated_V1_1_example", - "neuralnetworks_generated_V1_2_example", - ], -} - -cc_test { - name: "PresubmitHalNeuralnetworksV1_2TargetTest", - defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"], - srcs: [ - "BasicTests.cpp", - "CompilationCachingTests.cpp", - "ValidateBurst.cpp", - ], - whole_static_libs: [ - "neuralnetworks_generated_V1_0_example", - "neuralnetworks_generated_V1_1_example", - "neuralnetworks_generated_V1_2_example", - ], - cflags: [ - "-DPRESUBMIT_NOT_VTS", - ], -} diff --git a/neuralnetworks/1.2/vts/functional/BasicTests.cpp b/neuralnetworks/1.2/vts/functional/BasicTests.cpp index 8f95b96c52..8e82c5376e 100644 --- a/neuralnetworks/1.2/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.2/vts/functional/BasicTests.cpp @@ -25,17 +25,17 @@ using V1_0::ErrorStatus; using V1_0::PerformanceInfo; // create device test -TEST_F(NeuralnetworksHidlTest, CreateDevice) {} +TEST_P(NeuralnetworksHidlTest, CreateDevice) {} // status test -TEST_F(NeuralnetworksHidlTest, StatusTest) { +TEST_P(NeuralnetworksHidlTest, StatusTest) { Return status = kDevice->getStatus(); ASSERT_TRUE(status.isOk()); EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast(status)); } // initialization -TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) { +TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) { using OperandPerformance = Capabilities::OperandPerformance; Return ret = kDevice->getCapabilities_1_2([](ErrorStatus status, const Capabilities& capabilities) { @@ -60,7 +60,7 @@ TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) { } // device version test -TEST_F(NeuralnetworksHidlTest, GetDeviceVersionStringTest) { +TEST_P(NeuralnetworksHidlTest, GetDeviceVersionStringTest) { Return ret = kDevice->getVersionString([](ErrorStatus status, const hidl_string& version) { EXPECT_EQ(ErrorStatus::NONE, status); @@ -70,7 +70,7 @@ TEST_F(NeuralnetworksHidlTest, GetDeviceVersionStringTest) { } // device type test -TEST_F(NeuralnetworksHidlTest, GetDeviceTypeTest) { +TEST_P(NeuralnetworksHidlTest, GetDeviceTypeTest) { Return ret = kDevice->getType([](ErrorStatus status, DeviceType type) { EXPECT_EQ(ErrorStatus::NONE, status); EXPECT_TRUE(type == DeviceType::OTHER || type == DeviceType::CPU || @@ -80,7 +80,7 @@ TEST_F(NeuralnetworksHidlTest, GetDeviceTypeTest) { } // device supported extensions test -TEST_F(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) { +TEST_P(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) { Return ret = kDevice->getSupportedExtensions( [](ErrorStatus status, const hidl_vec& extensions) { EXPECT_EQ(ErrorStatus::NONE, status); @@ -101,7 +101,7 @@ TEST_F(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) { } // getNumberOfCacheFilesNeeded test -TEST_F(NeuralnetworksHidlTest, getNumberOfCacheFilesNeeded) { +TEST_P(NeuralnetworksHidlTest, getNumberOfCacheFilesNeeded) { Return ret = kDevice->getNumberOfCacheFilesNeeded( [](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) { EXPECT_EQ(ErrorStatus::NONE, status); diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp index bb46e06d6f..2130a76b75 100644 --- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" #include +#include #include #include #include @@ -37,11 +38,11 @@ // Forward declaration of the mobilenet generated test models in // frameworks/ml/nn/runtime/test/generated/. namespace generated_tests::mobilenet_224_gender_basic_fixed { -const ::test_helper::TestModel& get_test_model(); +const test_helper::TestModel& get_test_model(); } // namespace generated_tests::mobilenet_224_gender_basic_fixed namespace generated_tests::mobilenet_quantized { -const ::test_helper::TestModel& get_test_model(); +const test_helper::TestModel& get_test_model(); } // namespace generated_tests::mobilenet_quantized namespace android::hardware::neuralnetworks::V1_2::vts::functional { @@ -53,13 +54,13 @@ using V1_1::ExecutionPreference; namespace float32_model { -constexpr auto get_test_model = ::generated_tests::mobilenet_224_gender_basic_fixed::get_test_model; +constexpr auto get_test_model = generated_tests::mobilenet_224_gender_basic_fixed::get_test_model; } // namespace float32_model namespace quant8_model { -constexpr auto get_test_model = ::generated_tests::mobilenet_quantized::get_test_model; +constexpr auto get_test_model = generated_tests::mobilenet_quantized::get_test_model; } // namespace quant8_model @@ -217,12 +218,13 @@ TestModel createLargeTestModelImpl(TestOperationType op, uint32_t len) { } // namespace // Tag for the compilation caching tests. -class CompilationCachingTestBase : public NeuralnetworksHidlTest { +class CompilationCachingTestBase : public testing::Test { protected: - CompilationCachingTestBase(OperandType type) : kOperandType(type) {} + CompilationCachingTestBase(sp device, OperandType type) + : kDevice(std::move(device)), kOperandType(type) {} void SetUp() override { - NeuralnetworksHidlTest::SetUp(); + testing::Test::SetUp(); ASSERT_NE(kDevice.get(), nullptr); // Create cache directory. The cache directory and a temporary cache file is always created @@ -274,7 +276,7 @@ class CompilationCachingTestBase : public NeuralnetworksHidlTest { }; nftw(mCacheDir.c_str(), callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS); } - NeuralnetworksHidlTest::TearDown(); + testing::Test::TearDown(); } // Model and examples creators. According to kOperandType, the following methods will return @@ -398,16 +400,21 @@ class CompilationCachingTestBase : public NeuralnetworksHidlTest { uint32_t mNumDataCache; uint32_t mIsCachingSupported; + const sp kDevice; // The primary data type of the testModel. const OperandType kOperandType; }; +using CompilationCachingTestParam = std::tuple; + // A parameterized fixture of CompilationCachingTestBase. Every test will run twice, with the first // pass running with float32 models and the second pass running with quant8 models. class CompilationCachingTest : public CompilationCachingTestBase, - public testing::WithParamInterface { + public testing::WithParamInterface { protected: - CompilationCachingTest() : CompilationCachingTestBase(GetParam()) {} + CompilationCachingTest() + : CompilationCachingTestBase(getData(std::get(GetParam())), + std::get(GetParam())) {} }; TEST_P(CompilationCachingTest, CacheSavingAndRetrieval) { @@ -1192,16 +1199,30 @@ TEST_P(CompilationCachingTest, ReplaceSecuritySensitiveCache) { } } +static const auto kNamedDeviceChoices = testing::ValuesIn(getNamedDevices()); static const auto kOperandTypeChoices = testing::Values(OperandType::TENSOR_FLOAT32, OperandType::TENSOR_QUANT8_ASYMM); -INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingTest, kOperandTypeChoices); +std::string printCompilationCachingTest( + const testing::TestParamInfo& info) { + const auto& [namedDevice, operandType] = info.param; + const std::string type = (operandType == OperandType::TENSOR_FLOAT32 ? "float32" : "quant8"); + return gtestCompliantName(getName(namedDevice) + "_" + type); +} + +INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingTest, + testing::Combine(kNamedDeviceChoices, kOperandTypeChoices), + printCompilationCachingTest); + +using CompilationCachingSecurityTestParam = std::tuple; class CompilationCachingSecurityTest : public CompilationCachingTestBase, - public testing::WithParamInterface> { + public testing::WithParamInterface { protected: - CompilationCachingSecurityTest() : CompilationCachingTestBase(std::get<0>(GetParam())) {} + CompilationCachingSecurityTest() + : CompilationCachingTestBase(getData(std::get(GetParam())), + std::get(GetParam())) {} void SetUp() { CompilationCachingTestBase::SetUp(); @@ -1291,7 +1312,7 @@ class CompilationCachingSecurityTest } } - const uint32_t kSeed = std::get<1>(GetParam()); + const uint32_t kSeed = std::get(GetParam()); std::mt19937 generator; }; @@ -1338,7 +1359,16 @@ TEST_P(CompilationCachingSecurityTest, WrongToken) { }); } +std::string printCompilationCachingSecurityTest( + const testing::TestParamInfo& info) { + const auto& [namedDevice, operandType, seed] = info.param; + const std::string type = (operandType == OperandType::TENSOR_FLOAT32 ? "float32" : "quant8"); + return gtestCompliantName(getName(namedDevice) + "_" + type + "_" + std::to_string(seed)); +} + INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest, - testing::Combine(kOperandTypeChoices, testing::Range(0U, 10U))); + testing::Combine(kNamedDeviceChoices, kOperandTypeChoices, + testing::Range(0U, 10U)), + printCompilationCachingSecurityTest); } // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp index a2d37920d5..2beec983e0 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp @@ -190,7 +190,7 @@ static Return ExecutePreparedModel(const sp& prepar } static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst( const sp& preparedModel) { - return ::android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true); + return android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true); } enum class Executor { ASYNC, SYNC, BURST }; @@ -371,6 +371,20 @@ void Execute(const sp& device, const TestModel& testModel, bool testDyn EvaluatePreparedModel(preparedModel, testModel, testDynamicOutputShape); } +void GeneratedTestBase::SetUp() { + testing::TestWithParam::SetUp(); + ASSERT_NE(kDevice, nullptr); +} + +std::vector getNamedModels(const FilterFn& filter) { + return TestModelManager::get().getTestModels(filter); +} + +std::string printGeneratedTest(const testing::TestParamInfo& info) { + const auto& [namedDevice, namedModel] = info.param; + return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel)); +} + // Tag for the generated tests class GeneratedTest : public GeneratedTestBase {}; diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h index 0b8b917b0a..dfc980c169 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h @@ -22,34 +22,43 @@ #include #include #include +#include "1.0/Utils.h" #include "TestHarness.h" #include "VtsHalNeuralnetworks.h" namespace android::hardware::neuralnetworks::V1_2::vts::functional { -class GeneratedTestBase - : public NeuralnetworksHidlTest, - public testing::WithParamInterface { +using NamedModel = Named; +using GeneratedTestParam = std::tuple; + +class GeneratedTestBase : public testing::TestWithParam { protected: - const test_helper::TestModel& kTestModel = *GetParam().second; + void SetUp() override; + const sp kDevice = getData(std::get(GetParam())); + const test_helper::TestModel& kTestModel = *getData(std::get(GetParam())); }; -#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ - INSTANTIATE_TEST_SUITE_P( \ - TestGenerated, TestSuite, \ - testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \ - [](const auto& info) { return info.param.first; }) +using FilterFn = std::function; +std::vector getNamedModels(const FilterFn& filter); + +std::string printGeneratedTest(const testing::TestParamInfo& info); + +#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ + INSTANTIATE_TEST_SUITE_P(TestGenerated, TestSuite, \ + testing::Combine(testing::ValuesIn(getNamedDevices()), \ + testing::ValuesIn(getNamedModels(filter))), \ + printGeneratedTest) // Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp. // TODO: Clean up the hierarchy for ValidationTest. class ValidationTest : public GeneratedTestBase {}; -Model createModel(const ::test_helper::TestModel& testModel); +Model createModel(const test_helper::TestModel& testModel); void PrepareModel(const sp& device, const Model& model, sp* preparedModel); void EvaluatePreparedModel(const sp& preparedModel, - const ::test_helper::TestModel& testModel, bool testDynamicOutputShape); + const test_helper::TestModel& testModel, bool testDynamicOutputShape); } // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp index c02d0206e2..1d4493d208 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp @@ -262,7 +262,7 @@ static void validateBurstSerialization(const sp& preparedModel, })); // serialize the request - const auto serialized = ::android::nn::serialize(request, MeasureTiming::YES, slots); + const auto serialized = android::nn::serialize(request, MeasureTiming::YES, slots); // validations removeDatumTest(sender.get(), receiver.get(), serialized); @@ -299,7 +299,7 @@ static void validateBurstFmqLength(const sp& preparedModel, // skip test if regular burst output isn't useful for testing a failure // caused by having too small of a length for the result FMQ const std::vector serialized = - ::android::nn::serialize(statusRegular, outputShapesRegular, timingRegular); + android::nn::serialize(statusRegular, outputShapesRegular, timingRegular); if (statusRegular != ErrorStatus::NONE || serialized.size() <= kExecutionBurstChannelSmallLength) { return; diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp index 5c52de5834..f25ee62617 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp @@ -94,7 +94,7 @@ static void validate(const sp& preparedModel, const std::string& // create burst std::shared_ptr<::android::nn::ExecutionBurstController> burst = - ::android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true); + android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true); ASSERT_NE(nullptr, burst.get()); // create memory keys diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp index aa4f1f20b8..4fbd0e270f 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp @@ -17,13 +17,15 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" #include "VtsHalNeuralnetworks.h" +#include +#include +#include +#include #include "1.0/Callbacks.h" #include "1.0/Utils.h" #include "GeneratedTestHarness.h" #include "TestHarness.h" -#include - namespace android::hardware::neuralnetworks::V1_2::vts::functional { using implementation::PreparedModelCallback; @@ -82,34 +84,39 @@ void createPreparedModel(const sp& device, const Model& model, ASSERT_NE(nullptr, preparedModel->get()); } -// A class for test environment setup -NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() { - // This has to return a "new" object because it is freed inside - // testing::AddGlobalTestEnvironment when the gtest is being torn down - static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment(); - return instance; -} - -void NeuralnetworksHidlEnvironment::registerTestServices() { - registerTestService(); -} - -// The main test class for NEURALNETWORK HIDL HAL. void NeuralnetworksHidlTest::SetUp() { - testing::VtsHalHidlTargetTestBase::SetUp(); - -#ifdef PRESUBMIT_NOT_VTS - const std::string name = - NeuralnetworksHidlEnvironment::getInstance()->getServiceName(); - const std::string sampleDriver = "sample-"; - if (kDevice == nullptr && name.substr(0, sampleDriver.size()) == sampleDriver) { - GTEST_SKIP(); - } -#endif // PRESUBMIT_NOT_VTS - - ASSERT_NE(nullptr, kDevice.get()); + testing::TestWithParam::SetUp(); + ASSERT_NE(kDevice, nullptr); } +static NamedDevice makeNamedDevice(const std::string& name) { + return {name, IDevice::getService(name)}; +} + +static std::vector getNamedDevicesImpl() { + // Retrieves the name of all service instances that implement IDevice, + // including any Lazy HAL instances. + const std::vector names = hardware::getAllHalInstanceNames(IDevice::descriptor); + + // Get a handle to each device and pair it with its name. + std::vector namedDevices; + namedDevices.reserve(names.size()); + std::transform(names.begin(), names.end(), std::back_inserter(namedDevices), makeNamedDevice); + return namedDevices; +} + +const std::vector& getNamedDevices() { + const static std::vector devices = getNamedDevicesImpl(); + return devices; +} + +std::string printNeuralnetworksHidlTest( + const testing::TestParamInfo& info) { + return gtestCompliantName(getName(info.param)); +} + +INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest); + // Forward declaration from ValidateModel.cpp void validateModel(const sp& device, const Model& model); // Forward declaration from ValidateRequest.cpp @@ -162,14 +169,3 @@ sp getPreparedModel_1_2(const spinit(&argc, argv); - - int status = RUN_ALL_TESTS(); - return status; -} diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h index 9981696290..d01336eccd 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h @@ -17,42 +17,33 @@ #ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H #define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H -#include -#include -#include -#include -#include #include +#include #include #include - +#include "1.0/Utils.h" #include "1.2/Callbacks.h" namespace android::hardware::neuralnetworks::V1_2::vts::functional { -// A class for test environment setup -class NeuralnetworksHidlEnvironment : public testing::VtsHalHidlTargetTestEnvBase { - DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment); - NeuralnetworksHidlEnvironment() = default; - - public: - static NeuralnetworksHidlEnvironment* getInstance(); - void registerTestServices() override; -}; - -// The main test class for NEURALNETWORKS HIDL HAL. -class NeuralnetworksHidlTest : public testing::VtsHalHidlTargetTestBase { - DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest); - - public: - NeuralnetworksHidlTest() = default; - void SetUp() override; +using NamedDevice = Named>; +using NeuralnetworksHidlTestParam = NamedDevice; +class NeuralnetworksHidlTest : public testing::TestWithParam { protected: - const sp kDevice = testing::VtsHalHidlTargetTestBase::getService( - NeuralnetworksHidlEnvironment::getInstance()); + void SetUp() override; + const sp kDevice = getData(GetParam()); }; +const std::vector& getNamedDevices(); + +std::string printNeuralnetworksHidlTest( + const testing::TestParamInfo& info); + +#define INSTANTIATE_DEVICE_TEST(TestSuite) \ + INSTANTIATE_TEST_SUITE_P(PerInstance, TestSuite, testing::ValuesIn(getNamedDevices()), \ + printNeuralnetworksHidlTest) + // Create an IPreparedModel object. If the model cannot be prepared, // "preparedModel" will be nullptr instead. void createPreparedModel(const sp& device, const Model& model, diff --git a/neuralnetworks/TEST_MAPPING b/neuralnetworks/TEST_MAPPING index 50b6c19124..421922a25e 100644 --- a/neuralnetworks/TEST_MAPPING +++ b/neuralnetworks/TEST_MAPPING @@ -1,26 +1,35 @@ { "presubmit": [ { - "name": "PresubmitHalNeuralnetworksV1_0TargetTest", + "name": "VtsHalNeuralnetworksV1_0TargetTest", "options": [ { - "native-test-flag": "--hal_service_instance=android.hardware.neuralnetworks@1.0::IDevice/sample-all" + // Just use sample-all driver for presubmit tests for faster results. + // The other sample drivers (fast-float, quant, etc.) are subsets of + // sample-all. + "native-test-flag": "--gtest_filter=*sample_all*" } ] }, { - "name": "PresubmitHalNeuralnetworksV1_1TargetTest", + "name": "VtsHalNeuralnetworksV1_1TargetTest", "options": [ { - "native-test-flag": "--hal_service_instance=android.hardware.neuralnetworks@1.1::IDevice/sample-all" + // Just use sample-all driver for presubmit tests for faster results. + // The other sample drivers (fast-float, quant, etc.) are subsets of + // sample-all. + "native-test-flag": "--gtest_filter=*sample_all*" } ] }, { - "name": "PresubmitHalNeuralnetworksV1_2TargetTest", + "name": "VtsHalNeuralnetworksV1_2TargetTest", "options": [ { - "native-test-flag": "--hal_service_instance=android.hardware.neuralnetworks@1.2::IDevice/sample-all" + // Just use sample-all driver for presubmit tests for faster results. + // The other sample drivers (fast-float, quant, etc.) are subsets of + // sample-all. + "native-test-flag": "--gtest_filter=*sample_all*" } ] } From 2226b070fb5baf2fd1ade1f9307534c4a85403a3 Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Thu, 5 Sep 2019 14:56:48 -0700 Subject: [PATCH 0115/1022] Add record and playback to Tuner HAL bug: 135708935 Test: Manual Change-Id: Ibe8a51be31f455cc15b380748a0810e2706e5c1e --- tv/tuner/1.0/IDemux.hal | 217 +++++++++++++++++++++++++++++++- tv/tuner/1.0/IDemuxCallback.hal | 14 +++ tv/tuner/1.0/types.hal | 96 ++++++++++++++ 3 files changed, 326 insertions(+), 1 deletion(-) diff --git a/tv/tuner/1.0/IDemux.hal b/tv/tuner/1.0/IDemux.hal index 2d7b2754ac..e03095b2e3 100644 --- a/tv/tuner/1.0/IDemux.hal +++ b/tv/tuner/1.0/IDemux.hal @@ -180,5 +180,220 @@ interface IDemux { * UNKNOWN_ERROR if failed for other reasons. */ close() generates (Result result); -}; + /** + * Add output to the demux + * + * It is used by the client to record output data from selected filters. + * + * @param bufferSize the buffer size of the output to be added. It's used to + * create a FMQ(Fast Message Queue) to hold data from selected filters. + * @param cb the callback for the demux to be used to send notifications + * back to the client. + * @return result Result status of the operation. + * SUCCESS if successful, + * OUT_OF_MEMORY if failed for not enough memory. + * UNKNOWN_ERROR if failed for other reasons. + */ + addOutput(uint32_t bufferSize, IDemuxCallback cb) generates (Result result); + + /** + * Get the descriptor of the output's FMQ + * + * It is used by the client to get the descriptor of the output's Fast + * Message Queue. The data in FMQ is muxed packets output from selected + * filters. The packet's format is specifed by DemuxDataFormat in + * DemuxOutputSettings. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + * @return queue the descriptor of the output's FMQ + */ + getOutputQueueDesc() generates (Result result, fmq_sync queue); + + /** + * Configure the demux's output. + * + * It is used by the client to configure the demux's output for recording. + * + * @param settings the settings of the demux's output. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + configureOutput(DemuxOutputSettings settings) generates (Result result); + + /** + * Attach one filter to the demux's output. + * + * It is used by the client to mux one filter's output to demux's output. + * + * @param filterId the ID of the attached filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + attachOutputTsFilter(DemuxFilterId filterId) generates (Result result); + + /** + * Detach one filter from the demux's output. + * + * It is used by the client to remove one filter's output from demux's + * output. + * + * @param filterId the ID of the detached filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + detachOutputTsFilter(DemuxFilterId filterId) generates (Result result); + + /** + * Start to take data to the demux's output. + * + * It is used by the client to ask the output to start to take data from + * attached filters. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + startOutput() generates (Result result); + + /** + * Stop to take data to the demux's output. + * + * It is used by the client to ask the output to stop to take data from + * attached filters. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + stopOutput() generates (Result result); + + /** + * Flush unconsumed data in the demux's output. + * + * It is used by the client to ask the demux to flush the data which is + * already produced but not consumed yet in the demux's output. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + flushOutput() generates (Result result); + + /** + * Remove the demux's output. + * + * It is used by the client to remove the demux's output. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + removeOutput() generates (Result result); + + /** + * Add input to the demux + * + * It is used by the client to add the demux's input for playback content. + * + * @param bufferSize the buffer size of the demux's input to be added. + * It's used to create a FMQ(Fast Message Queue) to hold input data. + * @param cb the callback for the demux to be used to send notifications + * back to the client. + * @return result Result status of the operation. + * SUCCESS if successful, + * OUT_OF_MEMORY if failed for not enough memory. + * UNKNOWN_ERROR if failed for other reasons. + */ + addInput(uint32_t bufferSize, IDemuxCallback cb) generates (Result result); + + /** + * Get the descriptor of the input's FMQ + * + * It is used by the client to get the descriptor of the input's Fast + * Message Queue. The data in FMQ is fed by client. Data format is specifed + * by DemuxDataFormat in DemuxInputSettings. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + * @return queue the descriptor of the output's FMQ + */ + getInputQueueDesc() generates (Result result, fmq_sync queue); + + /** + * Configure the demux's input. + * + * It is used by the client to configure the demux's input for playback. + * + * @param settings the settings of the demux's input. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + configureInput(DemuxInputSettings settings) generates (Result result); + + /** + * Start to consume the data from the demux's input. + * + * It is used by the client to ask the demux to start to consume data from + * the demux's input. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + startInput() generates (Result result); + + /** + * Stop to consume the data from the demux's input. + * + * It is used by the client to ask the demux to stop to consume data from + * the demux's input. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + stopInput() generates (Result result); + + /** + * Flush unconsumed data in the demux's input. + * + * It is used by the client to ask the demux to flush the data which is + * already produced but not consumed yet in the demux's input. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + flushInput() generates (Result result); + + /** + * Remove the demux's input. + * + * It is used by the client to remove the demux's input. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + removeInput() generates (Result result); +}; diff --git a/tv/tuner/1.0/IDemuxCallback.hal b/tv/tuner/1.0/IDemuxCallback.hal index 7efd2c3591..55e84200ab 100644 --- a/tv/tuner/1.0/IDemuxCallback.hal +++ b/tv/tuner/1.0/IDemuxCallback.hal @@ -15,5 +15,19 @@ interface IDemuxCallback { * @param status a new status of the demux filter. */ oneway onFilterStatus(DemuxFilterId filterId, DemuxFilterStatus status); + + /** + * Notify the client a new status of the demux's output. + * + * @param status a new status of the demux's output. + */ + oneway onOutputStatus(DemuxOutputStatus status); + + /** + * Notify the client a new status of the demux's input. + * + * @param status a new status of the demux's input. + */ + oneway onInputStatus(DemuxInputStatus status); }; diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index 94e70f53e6..77f7eadb79 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -479,3 +479,99 @@ typedef uint32_t AvSyncHwId; * framework and apps. */ typedef vec TunerKeyToken; + +/** + * A data format in demux's output or input according to ISO/IEC 13818-1. + */ +@export +enum DemuxDataFormat : uint32_t { + /* Data is Transport Stream. */ + TS, + /* Data is Packetized Elementary Stream. */ + PES, + /* Data is Elementary Stream. */ + ES, +}; + +/** + * A status of the demux's output. + */ +typedef DemuxFilterStatus DemuxOutputStatus; + +/** + * The Settings for the demux's output. + */ +struct DemuxOutputSettings { + /** + * Register for interested status events so that the HAL can send these + * status events back to client. + */ + bitfield statusMask; + /** + * Unconsumed data size in bytes in the output. The HAL uses it to trigger + * DemuxOutputStatus::LOW_WATER. + */ + uint32_t lowThreshold; + /** + * Unconsumed data size in bytes in the output. The HAL uses it to trigger + * DemuxOutputStatus::High_WATER. + */ + uint32_t highThreshold; + /** + * The data format in the output. + */ + DemuxDataFormat dataFormat; + /** + * The packet size in bytes in the output. + */ + uint8_t packetSize; +}; + +/** + * A status of the demux's input. + */ +@export +enum DemuxInputStatus : uint32_t { + /** + * The space of the demux's input is empty. + */ + SPACE_EMPTY = 1 << 0, + /** + * The spece of the demux's input is almost empty. + */ + SPACE_ALMOST_EMPTY = 1 << 1, + /** + * The space of the demux's input is almost full. + */ + SPACE_ALMOST_FULL = 1 << 2, + /** + * The space of the demux's input is full. + */ + SPACE_FULL = 1 << 3, +}; + +struct DemuxInputSettings { + /** + * Register for interested status events so that the HAL can send these + * status events back to client. + */ + bitfield statusMask; + /** + * Unused space size in bytes in the input. The HAL uses it to trigger + * DemuxInputStatus::SPACE_ALMOST_EMPTY. + */ + uint32_t lowThreshold; + /** + * Unused space size in bytes in the input. The HAL uses it to trigger + * DemuxInputStatus::SPACE_ALMOST_FULL. + */ + uint32_t highThreshold; + /** + * The data format in the input. + */ + DemuxDataFormat dataFormat; + /** + * The packet size in bytes in the input. + */ + uint8_t packetSize; +}; From a4885299c2001001338ec535061b73e741c0e813 Mon Sep 17 00:00:00 2001 From: Amy Date: Fri, 6 Sep 2019 10:30:53 -0700 Subject: [PATCH 0116/1022] Tuner HAL Demux Playback interface implementation Test: manual Bug: 135709325 Change-Id: I0b673159b667c5bde47e9ed285cfa1bdc6c668c6 --- tv/tuner/1.0/default/Demux.cpp | 598 ++++++++++++++++++++++++--------- tv/tuner/1.0/default/Demux.h | 121 +++++-- 2 files changed, 529 insertions(+), 190 deletions(-) diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp index 4016c5a0e9..889e42ed06 100644 --- a/tv/tuner/1.0/default/Demux.cpp +++ b/tv/tuner/1.0/default/Demux.cpp @@ -73,34 +73,6 @@ Demux::Demux(uint32_t demuxId) { Demux::~Demux() {} -bool Demux::createAndSaveMQ(uint32_t bufferSize, uint32_t filterId) { - ALOGV("%s", __FUNCTION__); - - // Create a synchronized FMQ that supports blocking read/write - std::unique_ptr tmpFilterMQ = - std::unique_ptr(new (std::nothrow) FilterMQ(bufferSize, true)); - if (!tmpFilterMQ->isValid()) { - ALOGW("Failed to create FMQ of filter with id: %d", filterId); - return false; - } - - mFilterMQs.resize(filterId + 1); - mFilterMQs[filterId] = std::move(tmpFilterMQ); - - EventFlag* mFilterEventFlag; - if (EventFlag::createEventFlag(mFilterMQs[filterId]->getEventFlagWord(), &mFilterEventFlag) != - OK) { - return false; - } - mFilterEventFlags.resize(filterId + 1); - mFilterEventFlags[filterId] = mFilterEventFlag; - mFilterWriteCount.resize(filterId + 1); - mFilterWriteCount[filterId] = 0; - mThreadRunning.resize(filterId + 1); - - return true; -} - Return Demux::setFrontendDataSource(uint32_t frontendId) { ALOGV("%s", __FUNCTION__); @@ -113,23 +85,42 @@ Return Demux::addFilter(DemuxFilterType type, uint32_t bufferSize, const sp& cb, addFilter_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); - uint32_t filterId = mLastUsedFilterId + 1; - mLastUsedFilterId += 1; + uint32_t filterId; + + if (!mUnusedFilterIds.empty()) { + filterId = *mUnusedFilterIds.begin(); + + mUnusedFilterIds.erase(filterId); + } else { + filterId = ++mLastUsedFilterId; + + mDemuxCallbacks.resize(filterId + 1); + mFilterMQs.resize(filterId + 1); + mFilterEvents.resize(filterId + 1); + mFilterEventFlags.resize(filterId + 1); + mFilterThreadRunning.resize(filterId + 1); + mFilterThreads.resize(filterId + 1); + } + + mUsedFilterIds.insert(filterId); if ((type != DemuxFilterType::PCR || type != DemuxFilterType::TS) && cb == nullptr) { ALOGW("callback can't be null"); _hidl_cb(Result::INVALID_ARGUMENT, filterId); return Void(); } + // Add callback - mDemuxCallbacks.resize(filterId + 1); mDemuxCallbacks[filterId] = cb; - // Mapping from the filter ID to the filter type - mFilterTypes.resize(filterId + 1); - mFilterTypes[filterId] = type; + // Mapping from the filter ID to the filter event + DemuxFilterEvent event{ + .filterId = filterId, + .filterType = type, + }; + mFilterEvents[filterId] = event; - if (!createAndSaveMQ(bufferSize, filterId)) { + if (!createFilterMQ(bufferSize, filterId)) { _hidl_cb(Result::UNKNOWN_ERROR, -1); return Void(); } @@ -141,8 +132,8 @@ Return Demux::addFilter(DemuxFilterType type, uint32_t bufferSize, Return Demux::getFilterQueueDesc(uint32_t filterId, getFilterQueueDesc_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); - if (filterId < 0 || filterId > mLastUsedFilterId) { - ALOGW("No filter with id: %d exists", filterId); + if (mUsedFilterIds.find(filterId) == mUsedFilterIds.end()) { + ALOGW("No filter with id: %d exists to get desc", filterId); _hidl_cb(Result::INVALID_ARGUMENT, FilterMQ::Descriptor()); return Void(); } @@ -160,35 +151,29 @@ Return Demux::configureFilter(uint32_t /* filterId */, Return Demux::startFilter(uint32_t filterId) { ALOGV("%s", __FUNCTION__); + Result result; - if (filterId < 0 || filterId > mLastUsedFilterId) { - ALOGW("No filter with id: %d exists", filterId); + if (mUsedFilterIds.find(filterId) == mUsedFilterIds.end()) { + ALOGW("No filter with id: %d exists to start filter", filterId); return Result::INVALID_ARGUMENT; } - DemuxFilterType filterType = mFilterTypes[filterId]; - Result result; - DemuxFilterEvent event{ - .filterId = filterId, - .filterType = filterType, - }; - - switch (filterType) { + switch (mFilterEvents[filterId].filterType) { case DemuxFilterType::SECTION: - result = startSectionFilterHandler(event); + result = startFilterLoop(filterId); break; case DemuxFilterType::PES: - result = startPesFilterHandler(event); + result = startPesFilterHandler(filterId); break; case DemuxFilterType::TS: result = startTsFilterHandler(); return Result::SUCCESS; case DemuxFilterType::AUDIO: case DemuxFilterType::VIDEO: - result = startMediaFilterHandler(event); + result = startMediaFilterHandler(filterId); break; case DemuxFilterType::RECORD: - result = startRecordFilterHandler(event); + result = startRecordFilterHandler(filterId); break; case DemuxFilterType::PCR: result = startPcrFilterHandler(); @@ -212,9 +197,13 @@ Return Demux::flushFilter(uint32_t /* filterId */) { return Result::SUCCESS; } -Return Demux::removeFilter(uint32_t /* filterId */) { +Return Demux::removeFilter(uint32_t filterId) { ALOGV("%s", __FUNCTION__); + // resetFilterRecords(filterId); + mUsedFilterIds.erase(filterId); + mUnusedFilterIds.insert(filterId); + return Result::SUCCESS; } @@ -239,25 +228,291 @@ Return Demux::getAvSyncTime(AvSyncHwId /* avSyncHwId */, getAvSyncTime_cb Return Demux::close() { ALOGV("%s", __FUNCTION__); + set::iterator it; + mInputThread = 0; + mOutputThread = 0; + mFilterThreads.clear(); + mUnusedFilterIds.clear(); + mUsedFilterIds.clear(); + mDemuxCallbacks.clear(); + mFilterMQs.clear(); + mFilterEvents.clear(); + mFilterEventFlags.clear(); + mLastUsedFilterId = -1; + return Result::SUCCESS; } -bool Demux::writeSectionsAndCreateEvent(DemuxFilterEvent& event, uint32_t sectionNum) { - event.events.resize(sectionNum); - for (int i = 0; i < sectionNum; i++) { - DemuxFilterSectionEvent secEvent; - secEvent = { - // temp dump meta data - .tableId = 0, - .version = 1, - .sectionNum = 1, - .dataLength = 530, - }; - event.events[i].section(secEvent); - if (!writeDataToFilterMQ(fakeDataInputBuffer, event.filterId)) { - return false; - } +Return Demux::addOutput(uint32_t bufferSize, const sp& cb) { + ALOGV("%s", __FUNCTION__); + + // Create a synchronized FMQ that supports blocking read/write + std::unique_ptr tmpFilterMQ = + std::unique_ptr(new (std::nothrow) FilterMQ(bufferSize, true)); + if (!tmpFilterMQ->isValid()) { + ALOGW("Failed to create output FMQ"); + return Result::UNKNOWN_ERROR; } + + mOutputMQ = std::move(tmpFilterMQ); + + if (EventFlag::createEventFlag(mOutputMQ->getEventFlagWord(), &mOutputEventFlag) != OK) { + return Result::UNKNOWN_ERROR; + } + + mOutputCallback = cb; + + return Result::SUCCESS; +} + +Return Demux::getOutputQueueDesc(getOutputQueueDesc_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + if (!mOutputMQ) { + _hidl_cb(Result::NOT_INITIALIZED, FilterMQ::Descriptor()); + return Void(); + } + + _hidl_cb(Result::SUCCESS, *mOutputMQ->getDesc()); + return Void(); +} + +Return Demux::configureOutput(const DemuxOutputSettings& /* settings */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Demux::attachOutputTsFilter(uint32_t /*filterId*/) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Demux::detachOutputTsFilter(uint32_t /* filterId */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Demux::startOutput() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Demux::stopOutput() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Demux::flushOutput() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Demux::removeOutput() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Demux::addInput(uint32_t bufferSize, const sp& cb) { + ALOGV("%s", __FUNCTION__); + + // Create a synchronized FMQ that supports blocking read/write + std::unique_ptr tmpInputMQ = + std::unique_ptr(new (std::nothrow) FilterMQ(bufferSize, true)); + if (!tmpInputMQ->isValid()) { + ALOGW("Failed to create input FMQ"); + return Result::UNKNOWN_ERROR; + } + + mInputMQ = std::move(tmpInputMQ); + + if (EventFlag::createEventFlag(mInputMQ->getEventFlagWord(), &mInputEventFlag) != OK) { + return Result::UNKNOWN_ERROR; + } + + mInputCallback = cb; + + return Result::SUCCESS; +} + +Return Demux::getInputQueueDesc(getInputQueueDesc_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + if (!mInputMQ) { + _hidl_cb(Result::NOT_INITIALIZED, FilterMQ::Descriptor()); + return Void(); + } + + _hidl_cb(Result::SUCCESS, *mInputMQ->getDesc()); + return Void(); +} + +Return Demux::configureInput(const DemuxInputSettings& /* settings */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Demux::startInput() { + ALOGV("%s", __FUNCTION__); + + pthread_create(&mInputThread, NULL, __threadLoopInput, this); + pthread_setname_np(mInputThread, "demux_input_waiting_loop"); + + // TODO start another thread to send filter status callback to the framework + + return Result::SUCCESS; +} + +Return Demux::stopInput() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Demux::flushInput() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Demux::removeInput() { + ALOGV("%s", __FUNCTION__); + + mInputMQ = nullptr; + + return Result::SUCCESS; +} + +Result Demux::startFilterLoop(uint32_t filterId) { + struct ThreadArgs* threadArgs = (struct ThreadArgs*)malloc(sizeof(struct ThreadArgs)); + threadArgs->user = this; + threadArgs->filterId = filterId; + + pthread_t mFilterThread; + pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs); + mFilterThreads[filterId] = mFilterThread; + pthread_setname_np(mFilterThread, "demux_filter_waiting_loop"); + + return Result::SUCCESS; +} + +Result Demux::startSectionFilterHandler(uint32_t filterId, vector data) { + if (!writeSectionsAndCreateEvent(filterId, data)) { + ALOGD("[Demux] filter %d fails to write into FMQ. Ending thread", filterId); + return Result::UNKNOWN_ERROR; + } + + return Result::SUCCESS; +} + +Result Demux::startPesFilterHandler(uint32_t filterId) { + // TODO generate multiple events in one event callback + DemuxFilterPesEvent pesEvent; + pesEvent = { + // temp dump meta data + .streamId = 0, + .dataLength = 530, + }; + mFilterEvents[filterId].events.resize(1); + mFilterEvents[filterId].events[0].pes(pesEvent); + /*pthread_create(&mThreadId, NULL, __threadLoop, this); + pthread_setname_np(mThreadId, "demux_section_filter_waiting_loop");*/ + if (!writeDataToFilterMQ(fakeDataInputBuffer, filterId)) { + return Result::INVALID_STATE; + } + + if (mDemuxCallbacks[filterId] == nullptr) { + return Result::NOT_INITIALIZED; + } + + mDemuxCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]); + return Result::SUCCESS; +} + +Result Demux::startTsFilterHandler() { + // TODO handle starting TS filter + return Result::SUCCESS; +} + +Result Demux::startMediaFilterHandler(uint32_t filterId) { + DemuxFilterMediaEvent mediaEvent; + mediaEvent = { + // temp dump meta data + .pts = 0, + .dataLength = 530, + .secureMemory = nullptr, + }; + mFilterEvents[filterId].events.resize(1); + mFilterEvents[filterId].events[0].media() = mediaEvent; + // TODO handle write FQM for media stream + return Result::SUCCESS; +} + +Result Demux::startRecordFilterHandler(uint32_t filterId) { + DemuxFilterRecordEvent recordEvent; + recordEvent = { + // temp dump meta data + .tpid = 0, + .packetNum = 0, + }; + recordEvent.indexMask.tsIndexMask() = 0x01; + mFilterEvents[filterId].events.resize(1); + mFilterEvents[filterId].events[0].ts() = recordEvent; + return Result::SUCCESS; +} + +Result Demux::startPcrFilterHandler() { + // TODO handle starting PCR filter + return Result::SUCCESS; +} + +bool Demux::createFilterMQ(uint32_t bufferSize, uint32_t filterId) { + ALOGV("%s", __FUNCTION__); + + // Create a synchronized FMQ that supports blocking read/write + std::unique_ptr tmpFilterMQ = + std::unique_ptr(new (std::nothrow) FilterMQ(bufferSize, true)); + if (!tmpFilterMQ->isValid()) { + ALOGW("Failed to create FMQ of filter with id: %d", filterId); + return false; + } + + mFilterMQs[filterId] = std::move(tmpFilterMQ); + + EventFlag* filterEventFlag; + if (EventFlag::createEventFlag(mFilterMQs[filterId]->getEventFlagWord(), &filterEventFlag) != + OK) { + return false; + } + mFilterEventFlags[filterId] = filterEventFlag; + + return true; +} + +bool Demux::writeSectionsAndCreateEvent(uint32_t filterId, vector data) { + // TODO check how many sections has been read + std::lock_guard lock(mFilterEventLock); + int size = mFilterEvents[filterId].events.size(); + mFilterEvents[filterId].events.resize(size + 1); + if (!writeDataToFilterMQ(data, filterId)) { + return false; + } + DemuxFilterSectionEvent secEvent; + secEvent = { + // temp dump meta data + .tableId = 0, + .version = 1, + .sectionNum = 1, + .dataLength = 530, + }; + mFilterEvents[filterId].events[size].section(secEvent); return true; } @@ -269,116 +524,82 @@ bool Demux::writeDataToFilterMQ(const std::vector& data, uint32_t filte return false; } -Result Demux::startSectionFilterHandler(DemuxFilterEvent event) { - struct ThreadArgs* threadArgs = (struct ThreadArgs*)malloc(sizeof(struct ThreadArgs)); - threadArgs->user = this; - threadArgs->event = &event; +bool Demux::filterAndOutputData() { + ALOGD("[Demux] start to dispatch data to filters"); + // Read input data from the input FMQ + int size = mInputMQ->availableToRead(); + vector dataOutputBuffer; + dataOutputBuffer.resize(size); + mInputMQ->read(dataOutputBuffer.data(), size); - pthread_create(&mThreadId, NULL, __threadLoop, (void*)threadArgs); - pthread_setname_np(mThreadId, "demux_filter_waiting_loop"); - - return Result::SUCCESS; -} - -Result Demux::startPesFilterHandler(DemuxFilterEvent& event) { - // TODO generate multiple events in one event callback - DemuxFilterPesEvent pesEvent; - pesEvent = { - // temp dump meta data - .streamId = 0, - .dataLength = 530, - }; - event.events.resize(1); - event.events[0].pes(pesEvent); - /*pthread_create(&mThreadId, NULL, __threadLoop, this); - pthread_setname_np(mThreadId, "demux_section_filter_waiting_loop");*/ - if (!writeDataToFilterMQ(fakeDataInputBuffer, event.filterId)) { - return Result::INVALID_STATE; + Result result; + // Filter the data and feed the output to each filter + set::iterator it; + for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { + switch (mFilterEvents[*it].filterType) { + case DemuxFilterType::SECTION: + result = startSectionFilterHandler(*it, dataOutputBuffer); + break; + case DemuxFilterType::PES: + result = startPesFilterHandler(*it); + break; + case DemuxFilterType::TS: + result = startTsFilterHandler(); + break; + case DemuxFilterType::AUDIO: + case DemuxFilterType::VIDEO: + result = startMediaFilterHandler(*it); + break; + case DemuxFilterType::RECORD: + result = startRecordFilterHandler(*it); + break; + case DemuxFilterType::PCR: + result = startPcrFilterHandler(); + break; + default: + return false; + } } - if (mDemuxCallbacks[event.filterId] == nullptr) { - return Result::NOT_INITIALIZED; - } - - mDemuxCallbacks[event.filterId]->onFilterEvent(event); - return Result::SUCCESS; + return result == Result::SUCCESS; } -Result Demux::startTsFilterHandler() { - // TODO handle starting TS filter - return Result::SUCCESS; -} - -Result Demux::startMediaFilterHandler(DemuxFilterEvent& event) { - DemuxFilterMediaEvent mediaEvent; - mediaEvent = { - // temp dump meta data - .pts = 0, - .dataLength = 530, - .secureMemory = nullptr, - }; - event.events.resize(1); - event.events[0].media() = mediaEvent; - // TODO handle write FQM for media stream - return Result::SUCCESS; -} - -Result Demux::startRecordFilterHandler(DemuxFilterEvent& event) { - DemuxFilterRecordEvent recordEvent; - recordEvent = { - // temp dump meta data - .tpid = 0, - .packetNum = 0, - }; - recordEvent.indexMask.tsIndexMask() = 0x01; - event.events.resize(1); - event.events[0].ts() = recordEvent; - return Result::SUCCESS; -} - -Result Demux::startPcrFilterHandler() { - // TODO handle starting PCR filter - return Result::SUCCESS; -} - -void* Demux::__threadLoop(void* threadArg) { +void* Demux::__threadLoopFilter(void* threadArg) { Demux* const self = static_cast(((struct ThreadArgs*)threadArg)->user); - self->filterThreadLoop(((struct ThreadArgs*)threadArg)->event); + self->filterThreadLoop(((struct ThreadArgs*)threadArg)->filterId); return 0; } -void Demux::filterThreadLoop(DemuxFilterEvent* event) { - uint32_t filterId = event->filterId; - ALOGD("[Demux] filter %d threadLoop start.", filterId); - mThreadRunning[filterId] = true; +void* Demux::__threadLoopInput(void* user) { + Demux* const self = static_cast(user); + self->inputThreadLoop(); + return 0; +} - while (mThreadRunning[filterId]) { +void Demux::filterThreadLoop(uint32_t filterId) { + ALOGD("[Demux] filter %d threadLoop start.", filterId); + mFilterThreadRunning[filterId] = true; + + // For the first time of filter output, implementation needs to send the filter + // Event Callback without waiting for the DATA_CONSUMED to init the process. + while (mFilterThreadRunning[filterId]) { + if (mFilterEvents[filterId].events.size() == 0) { + ALOGD("[Demux] wait for filter data output."); + usleep(1000 * 1000); + continue; + } + // After successfully write, send a callback and wait for the read to be done + mDemuxCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]); + mFilterEvents[filterId].events.resize(0); + break; + } + + while (mFilterThreadRunning[filterId]) { uint32_t efState = 0; // We do not wait for the last round of writen data to be read to finish the thread // because the VTS can verify the reading itself. for (int i = 0; i < SECTION_WRITE_COUNT; i++) { - DemuxFilterEvent filterEvent{ - .filterId = filterId, - .filterType = event->filterType, - }; - if (!writeSectionsAndCreateEvent(filterEvent, 2)) { - ALOGD("[Demux] filter %d fails to write into FMQ. Ending thread", filterId); - break; - } - mFilterWriteCount[filterId]++; - if (mDemuxCallbacks[filterId] == nullptr) { - ALOGD("[Demux] filter %d does not hava callback. Ending thread", filterId); - break; - } - // After successfully write, send a callback and wait for the read to be done - mDemuxCallbacks[filterId]->onFilterEvent(filterEvent); - // We do not wait for the last read to be done - // VTS can verify the read result itself. - if (i == SECTION_WRITE_COUNT - 1) { - ALOGD("[Demux] filter %d writing done. Ending thread", filterId); - break; - } - while (mThreadRunning[filterId]) { + while (mFilterThreadRunning[filterId]) { status_t status = mFilterEventFlags[filterId]->wait( static_cast(DemuxQueueNotifyBits::DATA_CONSUMED), &efState, WAIT_TIMEOUT, true /* retry on spurious wake */); @@ -388,15 +609,60 @@ void Demux::filterThreadLoop(DemuxFilterEvent* event) { } break; } - } - mFilterWriteCount[filterId] = 0; - mThreadRunning[filterId] = false; + if (mDemuxCallbacks[filterId] == nullptr) { + ALOGD("[Demux] filter %d does not hava callback. Ending thread", filterId); + break; + } + + while (mFilterThreadRunning[filterId]) { + std::lock_guard lock(mFilterEventLock); + if (mFilterEvents[filterId].events.size() == 0) { + continue; + } + // After successfully write, send a callback and wait for the read to be done + mDemuxCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]); + mFilterEvents[filterId].events.resize(0); + break; + } + // We do not wait for the last read to be done + // VTS can verify the read result itself. + if (i == SECTION_WRITE_COUNT - 1) { + ALOGD("[Demux] filter %d writing done. Ending thread", filterId); + break; + } + } + mFilterThreadRunning[filterId] = false; } ALOGD("[Demux] filter thread ended."); } +void Demux::inputThreadLoop() { + ALOGD("[Demux] input threadLoop start."); + mInputThreadRunning = true; + + while (mInputThreadRunning) { + uint32_t efState = 0; + status_t status = + mInputEventFlag->wait(static_cast(DemuxQueueNotifyBits::DATA_READY), + &efState, WAIT_TIMEOUT, true /* retry on spurious wake */); + if (status != OK) { + ALOGD("[Demux] wait for data ready on the input FMQ"); + continue; + } + // Our current implementation filter the data and write it into the filter FMQ immedaitely + // after the DATA_READY from the VTS/framework + if (!filterAndOutputData()) { + ALOGD("[Demux] input data failed to be filtered. Ending thread"); + break; + } + } + + mInputThreadRunning = false; + ALOGD("[Demux] input thread ended."); +} + } // namespace implementation } // namespace V1_0 } // namespace tuner diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h index 8b002669dd..2fdde8dcf8 100644 --- a/tv/tuner/1.0/default/Demux.h +++ b/tv/tuner/1.0/default/Demux.h @@ -19,6 +19,7 @@ #include #include +#include using namespace std; @@ -43,6 +44,8 @@ class Demux : public IDemux { public: Demux(uint32_t demuxId); + ~Demux(); + virtual Return setFrontendDataSource(uint32_t frontendId) override; virtual Return close() override; @@ -68,8 +71,58 @@ class Demux : public IDemux { virtual Return getAvSyncTime(AvSyncHwId avSyncHwId, getAvSyncTime_cb _hidl_cb) override; + virtual Return addInput(uint32_t bufferSize, const sp& cb) override; + + virtual Return getInputQueueDesc(getInputQueueDesc_cb _hidl_cb) override; + + virtual Return configureInput(const DemuxInputSettings& settings) override; + + virtual Return startInput() override; + + virtual Return stopInput() override; + + virtual Return flushInput() override; + + virtual Return removeInput() override; + + virtual Return addOutput(uint32_t bufferSize, const sp& cb) override; + + virtual Return getOutputQueueDesc(getOutputQueueDesc_cb _hidl_cb) override; + + virtual Return configureOutput(const DemuxOutputSettings& settings) override; + + virtual Return attachOutputTsFilter(uint32_t filterId) override; + + virtual Return detachOutputTsFilter(uint32_t filterId) override; + + virtual Return startOutput() override; + + virtual Return stopOutput() override; + + virtual Return flushOutput() override; + + virtual Return removeOutput() override; + private: - virtual ~Demux(); + // A struct that passes the arguments to a newly created filter thread + struct ThreadArgs { + Demux* user; + uint32_t filterId; + }; + + /** + * Filter handlers to handle the data filtering. + * They are also responsible to write the filtered output into the filter FMQ + * and update the filterEvent bound with the same filterId. + */ + Result startSectionFilterHandler(uint32_t filterId, vector data); + Result startPesFilterHandler(uint32_t filterId); + Result startTsFilterHandler(); + Result startMediaFilterHandler(uint32_t filterId); + Result startRecordFilterHandler(uint32_t filterId); + Result startPcrFilterHandler(); + Result startFilterLoop(uint32_t filterId); + /** * To create a FilterMQ with the the next available Filter ID. * Creating Event Flag at the same time. @@ -77,60 +130,80 @@ class Demux : public IDemux { * * Return false is any of the above processes fails. */ - bool createAndSaveMQ(uint32_t bufferSize, uint32_t filterId); + bool createFilterMQ(uint32_t bufferSize, uint32_t filterId); + bool createMQ(FilterMQ* queue, EventFlag* eventFlag, uint32_t bufferSize); void deleteEventFlag(); bool writeDataToFilterMQ(const std::vector& data, uint32_t filterId); - Result startSectionFilterHandler(DemuxFilterEvent event); - Result startPesFilterHandler(DemuxFilterEvent& event); - Result startTsFilterHandler(); - Result startMediaFilterHandler(DemuxFilterEvent& event); - Result startRecordFilterHandler(DemuxFilterEvent& event); - Result startPcrFilterHandler(); - bool writeSectionsAndCreateEvent(DemuxFilterEvent& event, uint32_t sectionNum); - void filterThreadLoop(DemuxFilterEvent* event); - static void* __threadLoop(void* data); + bool readDataFromMQ(); + bool writeSectionsAndCreateEvent(uint32_t filterId, vector data); + /** + * A dispatcher to read and dispatch input data to all the started filters. + * Each filter handler handles the data filtering/output writing/filterEvent updating. + */ + bool filterAndOutputData(); + static void* __threadLoopFilter(void* data); + static void* __threadLoopInput(void* user); + void filterThreadLoop(uint32_t filterId); + void inputThreadLoop(); uint32_t mDemuxId; uint32_t mSourceFrontendId; /** - * Record the last used filer id. Initial value is -1. + * Record the last used filter id. Initial value is -1. * Filter Id starts with 0. */ uint32_t mLastUsedFilterId = -1; + /** + * Record all the used filter Ids. + * Any removed filter id should be removed from this set. + */ + set mUsedFilterIds; + /** + * Record all the unused filter Ids within mLastUsedFilterId. + * Removed filter Id should be added into this set. + * When this set is not empty, ids here should be allocated first + * and added into usedFilterIds. + */ + set mUnusedFilterIds; /** * A list of created FilterMQ ptrs. * The array number is the filter ID. */ vector> mFilterMQs; - vector mFilterTypes; vector mFilterEventFlags; + vector mFilterEvents; + unique_ptr mInputMQ; + unique_ptr mOutputMQ; + EventFlag* mInputEventFlag; + EventFlag* mOutputEventFlag; /** * Demux callbacks used on filter events or IO buffer status */ vector> mDemuxCallbacks; - /** - * How many times a specific filter has written since started - */ - vector mFilterWriteCount; - pthread_t mThreadId = 0; + sp mInputCallback; + sp mOutputCallback; + // Thread handlers + pthread_t mInputThread; + pthread_t mOutputThread; + vector mFilterThreads; /** * If a specific filter's writing loop is still running */ - vector mThreadRunning; + vector mFilterThreadRunning; + bool mInputThreadRunning; /** * Lock to protect writes to the FMQs */ std::mutex mWriteLock; + /** + * Lock to protect writes to the filter event + */ + std::mutex mFilterEventLock; /** * How many times a filter should write * TODO make this dynamic/random/can take as a parameter */ const uint16_t SECTION_WRITE_COUNT = 10; - // A struct that passes the arguments to a newly created filter thread - struct ThreadArgs { - Demux* user; - DemuxFilterEvent* event; - }; }; } // namespace implementation From 9db58dfa486b47e5b4974d28da31d74b75f73b11 Mon Sep 17 00:00:00 2001 From: Amy Date: Fri, 6 Sep 2019 10:30:53 -0700 Subject: [PATCH 0117/1022] Tuner HAL Demux Playback interface VTS Test: manual Bug: 135708935 Change-Id: Ifb93bbd5920f7998d9716a55cba983f8a5ace425 --- .../VtsHalTvTunerV1_0TargetTest.cpp | 546 ++++++++++++------ 1 file changed, 356 insertions(+), 190 deletions(-) diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 66adb2a698..d272d710f3 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -34,6 +34,8 @@ #include #include #include +#include +#include #define WAIT_TIMEOUT 3000000000 @@ -53,11 +55,16 @@ using android::hardware::MessageQueue; using android::hardware::MQDescriptorSync; using android::hardware::Return; using android::hardware::Void; +using android::hardware::tv::tuner::V1_0::DemuxDataFormat; using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent; using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterStatus; using android::hardware::tv::tuner::V1_0::DemuxFilterType; +using android::hardware::tv::tuner::V1_0::DemuxInputSettings; +using android::hardware::tv::tuner::V1_0::DemuxInputStatus; +using android::hardware::tv::tuner::V1_0::DemuxOutputStatus; using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; using android::hardware::tv::tuner::V1_0::FrontendAtscModulation; using android::hardware::tv::tuner::V1_0::FrontendAtscSettings; @@ -77,9 +84,9 @@ using android::hardware::tv::tuner::V1_0::Result; namespace { using FilterMQ = MessageQueue; -using FilterMQDesc = MQDescriptorSync; +using MQDesc = MQDescriptorSync; -const std::vector goldenDataInputBuffer{ +const std::vector goldenDataOutputBuffer{ 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb, 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03, 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06, @@ -119,10 +126,21 @@ const std::vector goldenDataInputBuffer{ }; const uint16_t FMQ_SIZE_4K = 0x1000; +const uint32_t FMQ_SIZE_1M = 0x100000; // Equal to SECTION_WRITE_COUNT on the HAL impl side // The HAL impl will repeatedly write to the FMQ the count times const uint16_t SECTION_READ_COUNT = 10; +struct FilterConf { + DemuxFilterType type; + DemuxFilterSettings setting; +}; + +struct InputConf { + string inputDataFile; + DemuxInputSettings setting; +}; + class FrontendCallback : public IFrontendCallback { public: virtual Return onEvent(FrontendEventType frontendEventType) override { @@ -184,8 +202,10 @@ void FrontendCallback::testOnDiseqcMessage(sp& frontend, FrontendSett class DemuxCallback : public IDemuxCallback { public: virtual Return onFilterEvent(const DemuxFilterEvent& filterEvent) override { + ALOGW("[VTS] FILTER EVENT %d", filterEvent.filterId); android::Mutex::Autolock autoLock(mMsgLock); mFilterEventReceived = true; + // maybe assemble here?? mFilterEvent = filterEvent; mMsgCondition.signal(); return Void(); @@ -196,24 +216,53 @@ class DemuxCallback : public IDemuxCallback { return Void(); } + virtual Return onOutputStatus(DemuxOutputStatus /*status*/) override { return Void(); } + + virtual Return onInputStatus(DemuxInputStatus status) override { + // android::Mutex::Autolock autoLock(mMsgLock); + switch (status) { + case DemuxInputStatus::SPACE_EMPTY: + case DemuxInputStatus::SPACE_ALMOST_EMPTY: + mKeepWritingInputFMQ = true; + break; + case DemuxInputStatus::SPACE_ALMOST_FULL: + case DemuxInputStatus::SPACE_FULL: + mKeepWritingInputFMQ = false; + break; + } + return Void(); + } + void testOnFilterEvent(uint32_t filterId); - void testOnSectionFilterEvent(sp& demux, uint32_t filterId, - FilterMQDesc& filterMQDescriptor); - void testOnPesFilterEvent(sp& demux, uint32_t filterId, - FilterMQDesc& filterMQDescriptor); - void readAndCompareSectionEventData(); - void readAndComparePesEventData(); + void testOnSectionFilterEvent(sp& demux, uint32_t filterId, MQDesc& filterMQDescriptor, + MQDesc& inputMQDescriptor); + void startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor); + bool readAndCompareSectionEventData(); + + static void* __threadLoopInput(void* threadArgs); + void inputThreadLoop(InputConf inputConf, bool* keepWritingInputFMQ, MQDesc& inputMQDescriptor); private: + struct InputThreadArgs { + DemuxCallback* user; + InputConf inputConf; + bool* keepWritingInputFMQ; + MQDesc& inputMQDesc; + }; bool mFilterEventReceived = false; std::vector mDataOutputBuffer; std::unique_ptr mFilterMQ; + std::unique_ptr mInputMQ; uint16_t mDataLength = 0; DemuxFilterEvent mFilterEvent; android::Mutex mMsgLock; android::Mutex mReadLock; android::Condition mMsgCondition; EventFlag* mFilterMQEventFlag; + EventFlag* mInputMQEventFlag; + bool mKeepWritingInputFMQ; + bool mInputThreadRunning; + pthread_t mInputThread; }; void DemuxCallback::testOnFilterEvent(uint32_t filterId) { @@ -230,83 +279,138 @@ void DemuxCallback::testOnFilterEvent(uint32_t filterId) { EXPECT_TRUE(filterId == mFilterEvent.filterId) << "filter id match"; } +void DemuxCallback::startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor) { + struct InputThreadArgs* threadArgs = + (struct InputThreadArgs*)malloc(sizeof(struct InputThreadArgs)); + threadArgs->user = this; + threadArgs->inputConf = inputConf; + threadArgs->keepWritingInputFMQ = &mKeepWritingInputFMQ; + threadArgs->inputMQDesc = inputMQDescriptor; + + pthread_create(&mInputThread, NULL, __threadLoopInput, (void*)threadArgs); + pthread_setname_np(mInputThread, "test_playback_input_loop"); +} + +/*void DemuxCallback::testPlaybackDataFlow(bool* keepWritingInputFMQ) { + // timeout logic here + + // assemble logic here + + +}*/ + void DemuxCallback::testOnSectionFilterEvent(sp& demux, uint32_t filterId, - FilterMQDesc& filterMQDescriptor) { + MQDesc& filterMQDescriptor, + MQDesc& inputMQDescriptor) { Result status; // Create MQ to read the output into the local buffer mFilterMQ = std::make_unique(filterMQDescriptor, true /* resetPointers */); EXPECT_TRUE(mFilterMQ); + // Get the MQ to write the input to the HAL + mInputMQ = std::make_unique(inputMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(mInputMQ); // Create the EventFlag that is used to signal the HAL impl that data have been // read the Filter FMQ EXPECT_TRUE(EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag) == android::OK); + // Create the EventFlag that is used to signal the HAL impl that data have been + // written into the Input FMQ + EXPECT_TRUE(EventFlag::createEventFlag(mInputMQ->getEventFlagWord(), &mInputMQEventFlag) == + android::OK); // Start filter status = demux->startFilter(filterId); + status = demux->startInput(); + EXPECT_EQ(status, Result::SUCCESS); // Test start filter and receive callback event for (int i = 0; i < SECTION_READ_COUNT; i++) { + // Write input FMQ and notify the Tuner Implementation + EXPECT_TRUE(mInputMQ->write(goldenDataOutputBuffer.data(), goldenDataOutputBuffer.size())); + mInputMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); testOnFilterEvent(filterId); // checksum of mDataOutputBuffer and Input golden input - readAndCompareSectionEventData(); + if (readAndCompareSectionEventData() && i < SECTION_READ_COUNT - 1) { + mFilterMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); + } } } -void DemuxCallback::testOnPesFilterEvent(sp& demux, uint32_t filterId, - FilterMQDesc& filterMQDescriptor) { - Result status; - // Create MQ to read the output into the local buffer - mFilterMQ = std::make_unique(filterMQDescriptor, true /* resetPointers */); - EXPECT_TRUE(mFilterMQ); - // Create the EventFlag that is used to signal the HAL impl that data have been - // read the Filter FMQ - EXPECT_TRUE(EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag) == - android::OK); - // Start filter - status = demux->startFilter(filterId); - EXPECT_EQ(status, Result::SUCCESS); - // Test start filter and receive callback event - testOnFilterEvent(filterId); - // checksum of mDataOutputBuffer and Input golden input - readAndComparePesEventData(); -} - -void DemuxCallback::readAndCompareSectionEventData() { +bool DemuxCallback::readAndCompareSectionEventData() { bool result = false; for (int i = 0; i < mFilterEvent.events.size(); i++) { DemuxFilterSectionEvent event = mFilterEvent.events[i].section(); mDataLength = event.dataLength; - EXPECT_TRUE(mDataLength == goldenDataInputBuffer.size()) << "buffer size does not match"; + EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not match"; mDataOutputBuffer.resize(mDataLength); result = mFilterMQ->read(mDataOutputBuffer.data(), mDataLength); EXPECT_TRUE(result) << "can't read from Filter MQ"; for (int i = 0; i < mDataLength; i++) { - EXPECT_TRUE(goldenDataInputBuffer[i] == mDataOutputBuffer[i]) << "data does not match"; + EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match"; } } - if (result) { - mFilterMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); - } + return result; } -void DemuxCallback::readAndComparePesEventData() { - // TODO handle multiple events in one filter callback event - DemuxFilterPesEvent event = mFilterEvent.events[0].pes(); - mDataLength = event.dataLength; - EXPECT_TRUE(mDataLength == goldenDataInputBuffer.size()) << "buffer size does not match"; +void* DemuxCallback::__threadLoopInput(void* threadArgs) { + DemuxCallback* const self = + static_cast(((struct InputThreadArgs*)threadArgs)->user); + self->inputThreadLoop(((struct InputThreadArgs*)threadArgs)->inputConf, + ((struct InputThreadArgs*)threadArgs)->keepWritingInputFMQ, + ((struct InputThreadArgs*)threadArgs)->inputMQDesc); + return 0; +} - mDataOutputBuffer.resize(mDataLength); - bool result = mFilterMQ->read(mDataOutputBuffer.data(), mDataLength); - EXPECT_TRUE(result) << "can't read from Filter MQ"; +void DemuxCallback::inputThreadLoop(InputConf inputConf, bool* keepWritingInputFMQ, + MQDesc& inputMQDescriptor) { + mInputThreadRunning = true; - if (result) { - mFilterMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); + std::unique_ptr inputMQ = + std::make_unique(inputMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(inputMQ); + + // Create the EventFlag that is used to signal the HAL impl that data have been + // written into the Input FMQ + EventFlag* inputMQEventFlag; + EXPECT_TRUE(EventFlag::createEventFlag(inputMQ->getEventFlagWord(), &inputMQEventFlag) == + android::OK); + + // open the stream and get its length + std::ifstream inputData(inputConf.inputDataFile /*"ts/test1.ts"*/, std::ifstream::binary); + int writeSize = inputConf.setting.packetSize * 6; + char* buffer = new char[writeSize]; + if (!inputData) { + // log + mInputThreadRunning = false; } - for (int i = 0; i < mDataLength; i++) { - EXPECT_TRUE(goldenDataInputBuffer[i] == mDataOutputBuffer[i]) << "data does not match"; + while (mInputThreadRunning) { + // move the stream pointer for packet size * 2k? every read until end + while (*keepWritingInputFMQ) { + inputData.read(buffer, writeSize); + if (!inputData) { + int leftSize = inputData.gcount(); + inputData.clear(); + inputData.read(buffer, leftSize); + // Write the left over of the input data and quit the thread + if (leftSize > 0) { + EXPECT_TRUE(inputMQ->write((unsigned char*)&buffer[0], + leftSize / inputConf.setting.packetSize)); + inputMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); + } + mInputThreadRunning = false; + break; + } + // Write input FMQ and notify the Tuner Implementation + EXPECT_TRUE(inputMQ->write((unsigned char*)&buffer[0], 6)); + inputMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); + inputData.seekg(writeSize, inputData.cur); + } } + + delete[] buffer; + inputData.close(); } // Test environment for Tuner HIDL HAL. @@ -341,24 +445,33 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { sp mDescrambler; sp mDemux; sp mDemuxCallback; - FilterMQDesc mFilterMQDescriptor; + MQDesc mFilterMQDescriptor; + MQDesc mInputMQDescriptor; + uint32_t mDemuxId; uint32_t mFilterId; + pthread_t mInputThread; + bool mInputThreadRunning; + ::testing::AssertionResult createFrontend(int32_t frontendId); ::testing::AssertionResult tuneFrontend(int32_t frontendId); ::testing::AssertionResult stopTuneFrontend(int32_t frontendId); ::testing::AssertionResult closeFrontend(int32_t frontendId); ::testing::AssertionResult createDemux(); ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId); + ::testing::AssertionResult getInputMQDescriptor(); + ::testing::AssertionResult addInputToDemux(DemuxInputSettings setting); ::testing::AssertionResult addSectionFilterToDemux(); - ::testing::AssertionResult addPesFilterToDemux(); - ::testing::AssertionResult getFilterMQDescriptor(sp& demux, const uint32_t filterId); - ::testing::AssertionResult readSectionFilterDataOutput(); - ::testing::AssertionResult readPesFilterDataOutput(); + ::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting); + ::testing::AssertionResult getFilterMQDescriptor(const uint32_t filterId); ::testing::AssertionResult closeDemux(); ::testing::AssertionResult createDescrambler(); ::testing::AssertionResult closeDescrambler(); + + ::testing::AssertionResult readSectionFilterDataOutput(); + ::testing::AssertionResult playbackDataFlowTest(vector filterConf, + InputConf inputConf, string goldenOutput); }; ::testing::AssertionResult TunerHidlTest::createFrontend(int32_t frontendId) { @@ -405,7 +518,7 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { ::testing::AssertionResult TunerHidlTest::stopTuneFrontend(int32_t frontendId) { Result status; - if (createFrontend(frontendId) == ::testing::AssertionFailure()) { + if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } @@ -415,11 +528,12 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { ::testing::AssertionResult TunerHidlTest::closeFrontend(int32_t frontendId) { Result status; - if (createFrontend(frontendId) == ::testing::AssertionFailure()) { + if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } status = mFrontend->close(); + mFrontend = nullptr; return ::testing::AssertionResult(status == Result::SUCCESS); } @@ -437,11 +551,11 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { ::testing::AssertionResult TunerHidlTest::createDemuxWithFrontend(int32_t frontendId) { Result status; - if (createDemux() == ::testing::AssertionFailure()) { + if (!mDemux && createDemux() == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } - if (createFrontend(frontendId) == ::testing::AssertionFailure()) { + if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } @@ -450,111 +564,14 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionResult(status == Result::SUCCESS); } -::testing::AssertionResult TunerHidlTest::addSectionFilterToDemux() { - Result status; - - if (createDemux() == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); - } - - // Create demux callback - mDemuxCallback = new DemuxCallback(); - - // Add section filter to the local demux - mDemux->addFilter(DemuxFilterType::SECTION, FMQ_SIZE_4K, mDemuxCallback, - [&](Result result, uint32_t filterId) { - mFilterId = filterId; - status = result; - }); - - // Add another section filter to the local demux - mDemux->addFilter(DemuxFilterType::SECTION, FMQ_SIZE_4K, mDemuxCallback, - [&](Result result, uint32_t filterId) { - mFilterId = filterId; - status = result; - }); - - // TODO Test configure the filter - - return ::testing::AssertionResult(status == Result::SUCCESS); -} - -::testing::AssertionResult TunerHidlTest::addPesFilterToDemux() { - Result status; - - if (createDemux() == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); - } - - // Create demux callback - mDemuxCallback = new DemuxCallback(); - - // Add PES filter to the local demux - mDemux->addFilter(DemuxFilterType::PES, FMQ_SIZE_4K, mDemuxCallback, - [&](Result result, uint32_t filterId) { - mFilterId = filterId; - status = result; - }); - - // Add another PES filter to the local demux - mDemux->addFilter(DemuxFilterType::PES, FMQ_SIZE_4K, mDemuxCallback, - [&](Result result, uint32_t filterId) { - mFilterId = filterId; - status = result; - }); - - // TODO Test configure the filter - - return ::testing::AssertionResult(status == Result::SUCCESS); -} - -::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor(sp& demux, - const uint32_t filterId) { - Result status; - - if (!demux) { - return ::testing::AssertionFailure(); - } - - mDemux->getFilterQueueDesc(filterId, [&](Result result, const FilterMQDesc& filterMQDesc) { - mFilterMQDescriptor = filterMQDesc; - status = result; - }); - - return ::testing::AssertionResult(status == Result::SUCCESS); -} - -::testing::AssertionResult TunerHidlTest::readSectionFilterDataOutput() { - if (addSectionFilterToDemux() == ::testing::AssertionFailure() || - getFilterMQDescriptor(mDemux, mFilterId) == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); - } - - // Test start filter and read the output data - mDemuxCallback->testOnSectionFilterEvent(mDemux, mFilterId, mFilterMQDescriptor); - - return ::testing::AssertionResult(true); -} - -::testing::AssertionResult TunerHidlTest::readPesFilterDataOutput() { - if (addPesFilterToDemux() == ::testing::AssertionFailure() || - getFilterMQDescriptor(mDemux, mFilterId) == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); - } - - // Test start filter and read the output data - mDemuxCallback->testOnPesFilterEvent(mDemux, mFilterId, mFilterMQDescriptor); - - return ::testing::AssertionResult(true); -} - ::testing::AssertionResult TunerHidlTest::closeDemux() { Result status; - if (createDemux() == ::testing::AssertionFailure()) { + if (!mDemux && createDemux() == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } status = mDemux->close(); + mDemux = nullptr; return ::testing::AssertionResult(status == Result::SUCCESS); } @@ -569,7 +586,7 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionFailure(); } - if (createDemux() == ::testing::AssertionFailure()) { + if (!mDemux && createDemux() == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } @@ -585,14 +602,185 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { ::testing::AssertionResult TunerHidlTest::closeDescrambler() { Result status; - if (createDescrambler() == ::testing::AssertionFailure()) { + if (!mDescrambler && createDescrambler() == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } status = mDescrambler->close(); + mDescrambler = nullptr; return ::testing::AssertionResult(status == Result::SUCCESS); } +::testing::AssertionResult TunerHidlTest::addInputToDemux(DemuxInputSettings setting) { + Result status; + + if (!mDemux && createDemux() == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + // Create demux callback + if (!mDemuxCallback) { + mDemuxCallback = new DemuxCallback(); + } + + // Add section filter to the local demux + status = mDemux->addInput(FMQ_SIZE_1M, mDemuxCallback); + + if (status != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + + status = mDemux->configureInput(setting); + + return ::testing::AssertionResult(status == Result::SUCCESS); +} + +::testing::AssertionResult TunerHidlTest::getInputMQDescriptor() { + Result status; + + if (!mDemux && createDemux() == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + mDemux->getInputQueueDesc([&](Result result, const MQDesc& inputMQDesc) { + mInputMQDescriptor = inputMQDesc; + status = result; + }); + + return ::testing::AssertionResult(status == Result::SUCCESS); +} + +::testing::AssertionResult TunerHidlTest::addSectionFilterToDemux() { + Result status; + + if (!mDemux && createDemux() == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + // Create demux callback + if (!mDemuxCallback) { + mDemuxCallback = new DemuxCallback(); + } + + // Add section filter to the local demux + mDemux->addFilter(DemuxFilterType::SECTION, FMQ_SIZE_4K, mDemuxCallback, + [&](Result result, uint32_t filterId) { + mFilterId = filterId; + status = result; + }); + + return ::testing::AssertionResult(status == Result::SUCCESS); +} + +::testing::AssertionResult TunerHidlTest::addFilterToDemux(DemuxFilterType type, + DemuxFilterSettings setting) { + Result status; + + if (!mDemux && createDemux() == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + // Create demux callback + if (!mDemuxCallback) { + mDemuxCallback = new DemuxCallback(); + } + + // Add filter to the local demux + mDemux->addFilter(type, FMQ_SIZE_4K, mDemuxCallback, [&](Result result, uint32_t filterId) { + // TODO use a map to save all the filter id and FMQ + mFilterId = filterId; + status = result; + }); + + if (status != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + + // Configure the filter + status = mDemux->configureFilter(mFilterId, setting); + + return ::testing::AssertionResult(status == Result::SUCCESS); +} + +::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor(const uint32_t filterId) { + Result status; + + if (!mDemux) { + return ::testing::AssertionFailure(); + } + + mDemux->getFilterQueueDesc(filterId, [&](Result result, const MQDesc& filterMQDesc) { + mFilterMQDescriptor = filterMQDesc; + status = result; + }); + + return ::testing::AssertionResult(status == Result::SUCCESS); +} + +::testing::AssertionResult TunerHidlTest::readSectionFilterDataOutput() { + // Filter Configuration Module + DemuxInputSettings setting{ + .statusMask = 0xf, + .lowThreshold = 0x1000, + .highThreshold = 0x100000, + .dataFormat = DemuxDataFormat::TS, + .packetSize = 188, + }; + if (addSectionFilterToDemux() == ::testing::AssertionFailure() || + getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure() || + addInputToDemux(setting) == ::testing::AssertionFailure() || + getInputMQDescriptor() == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + // Data Verify Module + // Test start filter and read the output data + mDemuxCallback->testOnSectionFilterEvent(mDemux, mFilterId, mFilterMQDescriptor, + mInputMQDescriptor); + + // Clean Up Module + return closeDemux(); //::testing::AssertionSuccess(); +} + +::testing::AssertionResult TunerHidlTest::playbackDataFlowTest(vector filterConf, + InputConf inputConf, + string /*goldenOutput*/) { + Result status; + // Filter Configuration Module + for (int i = 0; i < filterConf.size(); i++) { + if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) == + ::testing::AssertionFailure() || + // TODO use a map to save the FMQs/EvenFlags and pass to callback + getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + } + + // Playback Input Module + DemuxInputSettings inputSetting = inputConf.setting; + if (addInputToDemux(inputSetting) == ::testing::AssertionFailure() || + getInputMQDescriptor() == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + mDemuxCallback->startPlaybackInputThread(inputConf, mInputMQDescriptor); + status = mDemux->startInput(); + if (status != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + + // Data Verify Module + // golden output, created FMQ to read and EventFlags to DATA_CONSUMED + // Maintain each filter's real output (and how to assemble?????) + // mDemuxCallback->testPlaybackDataFlow(); + + // Clean Up Module + // TODO what about remove input, remove filters + return closeDemux(); +} + +/* + * API STATUS TESTS + */ TEST_F(TunerHidlTest, CreateFrontend) { Result status; hidl_vec feIds; @@ -673,12 +861,6 @@ TEST_F(TunerHidlTest, CloseFrontend) { } } -TEST_F(TunerHidlTest, CreateDemux) { - description("Create Demux"); - - ASSERT_TRUE(createDemux()); -} - TEST_F(TunerHidlTest, CreateDemuxWithFrontend) { Result status; hidl_vec feIds; @@ -699,50 +881,34 @@ TEST_F(TunerHidlTest, CreateDemuxWithFrontend) { } } -TEST_F(TunerHidlTest, AddSectionFilterToDemux) { - description("Add a section filter to a created demux"); - ASSERT_TRUE(addSectionFilterToDemux()); -} - -TEST_F(TunerHidlTest, AddPesFilterToDemux) { - description("Add a pes filter to a created demux"); - ASSERT_TRUE(addPesFilterToDemux()); -} - -TEST_F(TunerHidlTest, GetFilterMQDescriptor) { - description("Get MQ Descriptor from a created filter"); - ASSERT_TRUE(addSectionFilterToDemux()); - ASSERT_TRUE(getFilterMQDescriptor(mDemux, mFilterId)); -} - -TEST_F(TunerHidlTest, ReadSectionFilterOutput) { - description("Read data output from FMQ of a Section Filter"); - ASSERT_TRUE(readSectionFilterDataOutput()); -} - -TEST_F(TunerHidlTest, ReadPesFilterOutput) { - description("Read data output from FMQ of a PES Filter"); - ASSERT_TRUE(readPesFilterDataOutput()); +TEST_F(TunerHidlTest, CreateDemux) { + description("Create Demux"); + ASSERT_TRUE(createDemux()); } TEST_F(TunerHidlTest, CloseDemux) { description("Close Demux"); - ASSERT_TRUE(closeDemux()); } TEST_F(TunerHidlTest, CreateDescrambler) { description("Create Descrambler"); - ASSERT_TRUE(createDescrambler()); } TEST_F(TunerHidlTest, CloseDescrambler) { description("Close Descrambler"); - ASSERT_TRUE(closeDescrambler()); } +/* + * DATA FLOW TESTS + */ +TEST_F(TunerHidlTest, ReadSectionFilterOutput) { + description("Read data output from FMQ of a Section Filter"); + ASSERT_TRUE(readSectionFilterDataOutput()); +} + } // namespace int main(int argc, char** argv) { From f501a98aadcb068f4dd18a8227b0966a47e208d2 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Tue, 23 Jul 2019 15:02:22 -0700 Subject: [PATCH 0118/1022] Wifi: Uprev Wifi HAL to 1.4 Move Wifi HAL from 1.3 to 1.4 This commit also include adding the VINTF fragment definition for IWifi hal. Bug: 138243400 Test: Builds and wifi works Change-Id: I5ec9b21f8d6b7e1b5b5e47e26681dd4ed3ffcc2d --- .../compatibility_matrix.current.xml | 2 +- wifi/1.4/Android.bp | 20 +++++++++++++ wifi/1.4/IWifi.hal | 28 +++++++++++++++++++ wifi/{1.3 => 1.4}/default/Android.mk | 13 ++++++--- wifi/{1.3 => 1.4}/default/OWNERS | 0 wifi/{1.3 => 1.4}/default/THREADING.README | 0 .../android.hardware.wifi@1.0-service-lazy.rc | 0 .../android.hardware.wifi@1.0-service.rc | 0 .../android.hardware.wifi@1.0-service.xml | 11 ++++++++ .../{1.3 => 1.4}/default/hidl_callback_util.h | 4 +-- wifi/{1.3 => 1.4}/default/hidl_return_util.h | 4 +-- .../{1.3 => 1.4}/default/hidl_struct_util.cpp | 10 +++---- wifi/{1.3 => 1.4}/default/hidl_struct_util.h | 4 +-- wifi/{1.3 => 1.4}/default/hidl_sync_util.cpp | 4 +-- wifi/{1.3 => 1.4}/default/hidl_sync_util.h | 4 +-- wifi/{1.3 => 1.4}/default/ringbuffer.cpp | 4 +-- wifi/{1.3 => 1.4}/default/ringbuffer.h | 4 +-- wifi/{1.3 => 1.4}/default/service.cpp | 12 ++++---- .../tests/hidl_struct_util_unit_tests.cpp | 8 +++--- wifi/{1.3 => 1.4}/default/tests/main.cpp | 0 .../default/tests/mock_interface_tool.cpp | 0 .../default/tests/mock_interface_tool.h | 0 .../default/tests/mock_wifi_feature_flags.cpp | 4 +-- .../default/tests/mock_wifi_feature_flags.h | 4 +-- .../default/tests/mock_wifi_iface_util.cpp | 4 +-- .../default/tests/mock_wifi_iface_util.h | 4 +-- .../default/tests/mock_wifi_legacy_hal.cpp | 4 +-- .../default/tests/mock_wifi_legacy_hal.h | 8 +++--- .../tests/mock_wifi_mode_controller.cpp | 4 +-- .../default/tests/mock_wifi_mode_controller.h | 4 +-- .../default/tests/ringbuffer_unit_tests.cpp | 4 +-- wifi/{1.3 => 1.4}/default/tests/runtests.sh | 0 .../tests/wifi_ap_iface_unit_tests.cpp | 4 +-- .../default/tests/wifi_chip_unit_tests.cpp | 4 +-- .../tests/wifi_iface_util_unit_tests.cpp | 4 +-- .../tests/wifi_nan_iface_unit_tests.cpp | 4 +-- wifi/{1.3 => 1.4}/default/wifi.cpp | 4 +-- wifi/{1.3 => 1.4}/default/wifi.h | 8 +++--- wifi/{1.3 => 1.4}/default/wifi_ap_iface.cpp | 4 +-- wifi/{1.3 => 1.4}/default/wifi_ap_iface.h | 4 +-- wifi/{1.3 => 1.4}/default/wifi_chip.cpp | 4 +-- wifi/{1.3 => 1.4}/default/wifi_chip.h | 4 +-- .../default/wifi_feature_flags.cpp | 4 +-- .../{1.3 => 1.4}/default/wifi_feature_flags.h | 4 +-- wifi/{1.3 => 1.4}/default/wifi_iface_util.cpp | 4 +-- wifi/{1.3 => 1.4}/default/wifi_iface_util.h | 4 +-- wifi/{1.3 => 1.4}/default/wifi_legacy_hal.cpp | 4 +-- wifi/{1.3 => 1.4}/default/wifi_legacy_hal.h | 4 +-- .../default/wifi_legacy_hal_stubs.cpp | 4 +-- .../default/wifi_legacy_hal_stubs.h | 4 +-- .../default/wifi_mode_controller.cpp | 4 +-- .../default/wifi_mode_controller.h | 4 +-- wifi/{1.3 => 1.4}/default/wifi_nan_iface.cpp | 4 +-- wifi/{1.3 => 1.4}/default/wifi_nan_iface.h | 4 +-- wifi/{1.3 => 1.4}/default/wifi_p2p_iface.cpp | 4 +-- wifi/{1.3 => 1.4}/default/wifi_p2p_iface.h | 4 +-- .../default/wifi_rtt_controller.cpp | 4 +-- .../default/wifi_rtt_controller.h | 4 +-- wifi/{1.3 => 1.4}/default/wifi_sta_iface.cpp | 4 +-- wifi/{1.3 => 1.4}/default/wifi_sta_iface.h | 4 +-- .../{1.3 => 1.4}/default/wifi_status_util.cpp | 4 +-- wifi/{1.3 => 1.4}/default/wifi_status_util.h | 4 +-- 62 files changed, 180 insertions(+), 116 deletions(-) create mode 100644 wifi/1.4/Android.bp create mode 100644 wifi/1.4/IWifi.hal rename wifi/{1.3 => 1.4}/default/Android.mk (93%) rename wifi/{1.3 => 1.4}/default/OWNERS (100%) rename wifi/{1.3 => 1.4}/default/THREADING.README (100%) rename wifi/{1.3 => 1.4}/default/android.hardware.wifi@1.0-service-lazy.rc (100%) rename wifi/{1.3 => 1.4}/default/android.hardware.wifi@1.0-service.rc (100%) create mode 100644 wifi/1.4/default/android.hardware.wifi@1.0-service.xml rename wifi/{1.3 => 1.4}/default/hidl_callback_util.h (99%) rename wifi/{1.3 => 1.4}/default/hidl_return_util.h (99%) rename wifi/{1.3 => 1.4}/default/hidl_struct_util.cpp (99%) rename wifi/{1.3 => 1.4}/default/hidl_struct_util.h (99%) rename wifi/{1.3 => 1.4}/default/hidl_sync_util.cpp (96%) rename wifi/{1.3 => 1.4}/default/hidl_sync_util.h (96%) rename wifi/{1.3 => 1.4}/default/ringbuffer.cpp (97%) rename wifi/{1.3 => 1.4}/default/ringbuffer.h (97%) rename wifi/{1.3 => 1.4}/default/service.cpp (85%) rename wifi/{1.3 => 1.4}/default/tests/hidl_struct_util_unit_tests.cpp (98%) rename wifi/{1.3 => 1.4}/default/tests/main.cpp (100%) rename wifi/{1.3 => 1.4}/default/tests/mock_interface_tool.cpp (100%) rename wifi/{1.3 => 1.4}/default/tests/mock_interface_tool.h (100%) rename wifi/{1.3 => 1.4}/default/tests/mock_wifi_feature_flags.cpp (96%) rename wifi/{1.3 => 1.4}/default/tests/mock_wifi_feature_flags.h (97%) rename wifi/{1.3 => 1.4}/default/tests/mock_wifi_iface_util.cpp (96%) rename wifi/{1.3 => 1.4}/default/tests/mock_wifi_iface_util.h (97%) rename wifi/{1.3 => 1.4}/default/tests/mock_wifi_legacy_hal.cpp (96%) rename wifi/{1.3 => 1.4}/default/tests/mock_wifi_legacy_hal.h (92%) rename wifi/{1.3 => 1.4}/default/tests/mock_wifi_mode_controller.cpp (96%) rename wifi/{1.3 => 1.4}/default/tests/mock_wifi_mode_controller.h (97%) rename wifi/{1.3 => 1.4}/default/tests/ringbuffer_unit_tests.cpp (98%) rename wifi/{1.3 => 1.4}/default/tests/runtests.sh (100%) rename wifi/{1.3 => 1.4}/default/tests/wifi_ap_iface_unit_tests.cpp (98%) rename wifi/{1.3 => 1.4}/default/tests/wifi_chip_unit_tests.cpp (99%) rename wifi/{1.3 => 1.4}/default/tests/wifi_iface_util_unit_tests.cpp (98%) rename wifi/{1.3 => 1.4}/default/tests/wifi_nan_iface_unit_tests.cpp (99%) rename wifi/{1.3 => 1.4}/default/wifi.cpp (99%) rename wifi/{1.3 => 1.4}/default/wifi.h (96%) rename wifi/{1.3 => 1.4}/default/wifi_ap_iface.cpp (99%) rename wifi/{1.3 => 1.4}/default/wifi_ap_iface.h (98%) rename wifi/{1.3 => 1.4}/default/wifi_chip.cpp (99%) rename wifi/{1.3 => 1.4}/default/wifi_chip.h (99%) rename wifi/{1.3 => 1.4}/default/wifi_feature_flags.cpp (99%) rename wifi/{1.3 => 1.4}/default/wifi_feature_flags.h (97%) rename wifi/{1.3 => 1.4}/default/wifi_iface_util.cpp (99%) rename wifi/{1.3 => 1.4}/default/wifi_iface_util.h (98%) rename wifi/{1.3 => 1.4}/default/wifi_legacy_hal.cpp (99%) rename wifi/{1.3 => 1.4}/default/wifi_legacy_hal.h (99%) rename wifi/{1.3 => 1.4}/default/wifi_legacy_hal_stubs.cpp (99%) rename wifi/{1.3 => 1.4}/default/wifi_legacy_hal_stubs.h (96%) rename wifi/{1.3 => 1.4}/default/wifi_mode_controller.cpp (98%) rename wifi/{1.3 => 1.4}/default/wifi_mode_controller.h (98%) rename wifi/{1.3 => 1.4}/default/wifi_nan_iface.cpp (99%) rename wifi/{1.3 => 1.4}/default/wifi_nan_iface.h (99%) rename wifi/{1.3 => 1.4}/default/wifi_p2p_iface.cpp (98%) rename wifi/{1.3 => 1.4}/default/wifi_p2p_iface.h (98%) rename wifi/{1.3 => 1.4}/default/wifi_rtt_controller.cpp (99%) rename wifi/{1.3 => 1.4}/default/wifi_rtt_controller.h (99%) rename wifi/{1.3 => 1.4}/default/wifi_sta_iface.cpp (99%) rename wifi/{1.3 => 1.4}/default/wifi_sta_iface.h (99%) rename wifi/{1.3 => 1.4}/default/wifi_status_util.cpp (99%) rename wifi/{1.3 => 1.4}/default/wifi_status_util.h (97%) diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index d4f53cd19a..ef1cd75cd1 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -491,7 +491,7 @@ android.hardware.wifi - 1.0-3 + 1.0-4 IWifi default diff --git a/wifi/1.4/Android.bp b/wifi/1.4/Android.bp new file mode 100644 index 0000000000..a6ac020cbc --- /dev/null +++ b/wifi/1.4/Android.bp @@ -0,0 +1,20 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.wifi@1.4", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "IWifi.hal", + ], + interfaces: [ + "android.hardware.wifi@1.0", + "android.hardware.wifi@1.1", + "android.hardware.wifi@1.2", + "android.hardware.wifi@1.3", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/wifi/1.4/IWifi.hal b/wifi/1.4/IWifi.hal new file mode 100644 index 0000000000..f4bc618f10 --- /dev/null +++ b/wifi/1.4/IWifi.hal @@ -0,0 +1,28 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi@1.4; + +import @1.3::IWifi; + +/** + * This is the root of the HAL module and is the interface returned when + * loading an implementation of the Wi-Fi HAL. There must be at most one + * module loaded in the system. + * IWifi.getChip() must return @1.2::IWifiChip + */ +interface IWifi extends @1.3::IWifi { +}; diff --git a/wifi/1.3/default/Android.mk b/wifi/1.4/default/Android.mk similarity index 93% rename from wifi/1.3/default/Android.mk rename to wifi/1.4/default/Android.mk index 29f1c4256f..7ba5e36d9c 100644 --- a/wifi/1.3/default/Android.mk +++ b/wifi/1.4/default/Android.mk @@ -18,6 +18,7 @@ LOCAL_PATH := $(call my-dir) ### include $(CLEAR_VARS) LOCAL_MODULE := android.hardware.wifi@1.0-service-lib +LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_PROPRIETARY_MODULE := true LOCAL_CPPFLAGS := -Wall -Werror -Wextra @@ -67,7 +68,8 @@ LOCAL_SHARED_LIBRARIES := \ android.hardware.wifi@1.0 \ android.hardware.wifi@1.1 \ android.hardware.wifi@1.2 \ - android.hardware.wifi@1.3 + android.hardware.wifi@1.3 \ + android.hardware.wifi@1.4 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) include $(BUILD_STATIC_LIBRARY) @@ -93,7 +95,8 @@ LOCAL_SHARED_LIBRARIES := \ android.hardware.wifi@1.0 \ android.hardware.wifi@1.1 \ android.hardware.wifi@1.2 \ - android.hardware.wifi@1.3 + android.hardware.wifi@1.3 \ + android.hardware.wifi@1.4 LOCAL_STATIC_LIBRARIES := \ android.hardware.wifi@1.0-service-lib LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc @@ -123,7 +126,8 @@ LOCAL_SHARED_LIBRARIES := \ android.hardware.wifi@1.0 \ android.hardware.wifi@1.1 \ android.hardware.wifi@1.2 \ - android.hardware.wifi@1.3 + android.hardware.wifi@1.3 \ + android.hardware.wifi@1.4 LOCAL_STATIC_LIBRARIES := \ android.hardware.wifi@1.0-service-lib LOCAL_INIT_RC := android.hardware.wifi@1.0-service-lazy.rc @@ -165,5 +169,6 @@ LOCAL_SHARED_LIBRARIES := \ android.hardware.wifi@1.0 \ android.hardware.wifi@1.1 \ android.hardware.wifi@1.2 \ - android.hardware.wifi@1.3 + android.hardware.wifi@1.3 \ + android.hardware.wifi@1.4 include $(BUILD_NATIVE_TEST) diff --git a/wifi/1.3/default/OWNERS b/wifi/1.4/default/OWNERS similarity index 100% rename from wifi/1.3/default/OWNERS rename to wifi/1.4/default/OWNERS diff --git a/wifi/1.3/default/THREADING.README b/wifi/1.4/default/THREADING.README similarity index 100% rename from wifi/1.3/default/THREADING.README rename to wifi/1.4/default/THREADING.README diff --git a/wifi/1.3/default/android.hardware.wifi@1.0-service-lazy.rc b/wifi/1.4/default/android.hardware.wifi@1.0-service-lazy.rc similarity index 100% rename from wifi/1.3/default/android.hardware.wifi@1.0-service-lazy.rc rename to wifi/1.4/default/android.hardware.wifi@1.0-service-lazy.rc diff --git a/wifi/1.3/default/android.hardware.wifi@1.0-service.rc b/wifi/1.4/default/android.hardware.wifi@1.0-service.rc similarity index 100% rename from wifi/1.3/default/android.hardware.wifi@1.0-service.rc rename to wifi/1.4/default/android.hardware.wifi@1.0-service.rc diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml b/wifi/1.4/default/android.hardware.wifi@1.0-service.xml new file mode 100644 index 0000000000..b5d25cd140 --- /dev/null +++ b/wifi/1.4/default/android.hardware.wifi@1.0-service.xml @@ -0,0 +1,11 @@ + + + android.hardware.wifi + hwbinder + 1.4 + + IWifi + default + + + diff --git a/wifi/1.3/default/hidl_callback_util.h b/wifi/1.4/default/hidl_callback_util.h similarity index 99% rename from wifi/1.3/default/hidl_callback_util.h rename to wifi/1.4/default/hidl_callback_util.h index a44af79fe3..fc601b804a 100644 --- a/wifi/1.3/default/hidl_callback_util.h +++ b/wifi/1.4/default/hidl_callback_util.h @@ -52,7 +52,7 @@ class HidlDeathHandler : public android::hardware::hidl_death_recipient { namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace hidl_callback_util { template @@ -117,7 +117,7 @@ class HidlCallbackHandler { } // namespace hidl_callback_util } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/hidl_return_util.h b/wifi/1.4/default/hidl_return_util.h similarity index 99% rename from wifi/1.3/default/hidl_return_util.h rename to wifi/1.4/default/hidl_return_util.h index 9707444fe6..99c70928b7 100644 --- a/wifi/1.3/default/hidl_return_util.h +++ b/wifi/1.4/default/hidl_return_util.h @@ -23,7 +23,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace hidl_return_util { using namespace android::hardware::wifi::V1_0; @@ -113,7 +113,7 @@ Return validateAndCall( } // namespace hidl_return_util } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp similarity index 99% rename from wifi/1.3/default/hidl_struct_util.cpp rename to wifi/1.4/default/hidl_struct_util.cpp index 2e4db70480..47713cde22 100644 --- a/wifi/1.3/default/hidl_struct_util.cpp +++ b/wifi/1.4/default/hidl_struct_util.cpp @@ -22,7 +22,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace hidl_struct_util { @@ -302,11 +302,11 @@ legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2( } legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy( - IWifiChip::LatencyMode hidl_latency_mode) { + V1_3::IWifiChip::LatencyMode hidl_latency_mode) { switch (hidl_latency_mode) { - case IWifiChip::LatencyMode::NORMAL: + case V1_3::IWifiChip::LatencyMode::NORMAL: return legacy_hal::WIFI_LATENCY_MODE_NORMAL; - case IWifiChip::LatencyMode::LOW: + case V1_3::IWifiChip::LatencyMode::LOW: return legacy_hal::WIFI_LATENCY_MODE_LOW; } CHECK(false); @@ -2683,7 +2683,7 @@ bool convertLegacyVectorOfRttResultToHidl( } } // namespace hidl_struct_util } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h similarity index 99% rename from wifi/1.3/default/hidl_struct_util.h rename to wifi/1.4/default/hidl_struct_util.h index 3eefd9592b..c9f1c262d5 100644 --- a/wifi/1.3/default/hidl_struct_util.h +++ b/wifi/1.4/default/hidl_struct_util.h @@ -37,7 +37,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace hidl_struct_util { using namespace android::hardware::wifi::V1_0; @@ -188,7 +188,7 @@ bool convertLegacyVectorOfRttResultToHidl( std::vector* hidl_results); } // namespace hidl_struct_util } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/hidl_sync_util.cpp b/wifi/1.4/default/hidl_sync_util.cpp similarity index 96% rename from wifi/1.3/default/hidl_sync_util.cpp rename to wifi/1.4/default/hidl_sync_util.cpp index 160727f609..593a3bc5be 100644 --- a/wifi/1.3/default/hidl_sync_util.cpp +++ b/wifi/1.4/default/hidl_sync_util.cpp @@ -23,7 +23,7 @@ std::recursive_mutex g_mutex; namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace hidl_sync_util { @@ -33,7 +33,7 @@ std::unique_lock acquireGlobalLock() { } // namespace hidl_sync_util } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/hidl_sync_util.h b/wifi/1.4/default/hidl_sync_util.h similarity index 96% rename from wifi/1.3/default/hidl_sync_util.h rename to wifi/1.4/default/hidl_sync_util.h index ebfb05144b..02444219e9 100644 --- a/wifi/1.3/default/hidl_sync_util.h +++ b/wifi/1.4/default/hidl_sync_util.h @@ -24,13 +24,13 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace hidl_sync_util { std::unique_lock acquireGlobalLock(); } // namespace hidl_sync_util } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/ringbuffer.cpp b/wifi/1.4/default/ringbuffer.cpp similarity index 97% rename from wifi/1.3/default/ringbuffer.cpp rename to wifi/1.4/default/ringbuffer.cpp index 1294c52982..0fe8ef45aa 100644 --- a/wifi/1.3/default/ringbuffer.cpp +++ b/wifi/1.4/default/ringbuffer.cpp @@ -21,7 +21,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {} @@ -48,7 +48,7 @@ const std::list>& Ringbuffer::getData() const { } } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/ringbuffer.h b/wifi/1.4/default/ringbuffer.h similarity index 97% rename from wifi/1.3/default/ringbuffer.h rename to wifi/1.4/default/ringbuffer.h index d9f8df685d..ddce648949 100644 --- a/wifi/1.3/default/ringbuffer.h +++ b/wifi/1.4/default/ringbuffer.h @@ -23,7 +23,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { /** @@ -45,7 +45,7 @@ class Ringbuffer { }; } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/service.cpp b/wifi/1.4/default/service.cpp similarity index 85% rename from wifi/1.3/default/service.cpp rename to wifi/1.4/default/service.cpp index 0b41d28da9..3f7f6094fd 100644 --- a/wifi/1.3/default/service.cpp +++ b/wifi/1.4/default/service.cpp @@ -28,11 +28,11 @@ using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; using android::hardware::LazyServiceRegistrar; -using android::hardware::wifi::V1_3::implementation::feature_flags:: +using android::hardware::wifi::V1_4::implementation::feature_flags:: WifiFeatureFlags; -using android::hardware::wifi::V1_3::implementation::iface_util::WifiIfaceUtil; -using android::hardware::wifi::V1_3::implementation::legacy_hal::WifiLegacyHal; -using android::hardware::wifi::V1_3::implementation::mode_controller:: +using android::hardware::wifi::V1_4::implementation::iface_util::WifiIfaceUtil; +using android::hardware::wifi::V1_4::implementation::legacy_hal::WifiLegacyHal; +using android::hardware::wifi::V1_4::implementation::mode_controller:: WifiModeController; #ifdef LAZY_SERVICE @@ -51,8 +51,8 @@ int main(int /*argc*/, char** argv) { const auto iface_tool = std::make_shared(); // Setup hwbinder service - android::sp service = - new android::hardware::wifi::V1_3::implementation::Wifi( + android::sp service = + new android::hardware::wifi::V1_4::implementation::Wifi( iface_tool, std::make_shared(iface_tool), std::make_shared(), std::make_shared(iface_tool), diff --git a/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp similarity index 98% rename from wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp rename to wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp index dbf7bd6113..fde1df0383 100644 --- a/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp +++ b/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp @@ -34,7 +34,7 @@ constexpr char kIfaceName2[] = "wlan1"; namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { using namespace android::hardware::wifi::V1_0; using ::android::hardware::wifi::V1_0::WifiChannelWidthInMhz; @@ -275,9 +275,9 @@ TEST_F(HidlStructUtilTest, CanConvertLegacyFeaturesToHidl) { uint32_t hidle_caps; uint32_t legacy_feature_set = - WIFI_FEATURE_D2D_RTT | WIFI_FEATURE_SET_LATENCY_MODE; + WIFI_FEATURE_D2D_RTT | WIFI_FEATURE_SET_LATENCY_MODE; uint32_t legacy_logger_feature_set = - legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED; + legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED; ASSERT_TRUE(hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities( legacy_feature_set, legacy_logger_feature_set, &hidle_caps)); @@ -290,7 +290,7 @@ TEST_F(HidlStructUtilTest, CanConvertLegacyFeaturesToHidl) { hidle_caps); } } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/tests/main.cpp b/wifi/1.4/default/tests/main.cpp similarity index 100% rename from wifi/1.3/default/tests/main.cpp rename to wifi/1.4/default/tests/main.cpp diff --git a/wifi/1.3/default/tests/mock_interface_tool.cpp b/wifi/1.4/default/tests/mock_interface_tool.cpp similarity index 100% rename from wifi/1.3/default/tests/mock_interface_tool.cpp rename to wifi/1.4/default/tests/mock_interface_tool.cpp diff --git a/wifi/1.3/default/tests/mock_interface_tool.h b/wifi/1.4/default/tests/mock_interface_tool.h similarity index 100% rename from wifi/1.3/default/tests/mock_interface_tool.h rename to wifi/1.4/default/tests/mock_interface_tool.h diff --git a/wifi/1.3/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.4/default/tests/mock_wifi_feature_flags.cpp similarity index 96% rename from wifi/1.3/default/tests/mock_wifi_feature_flags.cpp rename to wifi/1.4/default/tests/mock_wifi_feature_flags.cpp index a393fdc539..b1fa432ca3 100644 --- a/wifi/1.3/default/tests/mock_wifi_feature_flags.cpp +++ b/wifi/1.4/default/tests/mock_wifi_feature_flags.cpp @@ -21,7 +21,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace feature_flags { @@ -29,7 +29,7 @@ MockWifiFeatureFlags::MockWifiFeatureFlags() {} } // namespace feature_flags } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/tests/mock_wifi_feature_flags.h b/wifi/1.4/default/tests/mock_wifi_feature_flags.h similarity index 97% rename from wifi/1.3/default/tests/mock_wifi_feature_flags.h rename to wifi/1.4/default/tests/mock_wifi_feature_flags.h index ee12b54c78..72d23045b0 100644 --- a/wifi/1.3/default/tests/mock_wifi_feature_flags.h +++ b/wifi/1.4/default/tests/mock_wifi_feature_flags.h @@ -25,7 +25,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace feature_flags { @@ -39,7 +39,7 @@ class MockWifiFeatureFlags : public WifiFeatureFlags { } // namespace feature_flags } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/tests/mock_wifi_iface_util.cpp b/wifi/1.4/default/tests/mock_wifi_iface_util.cpp similarity index 96% rename from wifi/1.3/default/tests/mock_wifi_iface_util.cpp rename to wifi/1.4/default/tests/mock_wifi_iface_util.cpp index 3d877c0cbf..0968569c56 100644 --- a/wifi/1.3/default/tests/mock_wifi_iface_util.cpp +++ b/wifi/1.4/default/tests/mock_wifi_iface_util.cpp @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace iface_util { @@ -33,7 +33,7 @@ MockWifiIfaceUtil::MockWifiIfaceUtil( : WifiIfaceUtil(iface_tool) {} } // namespace iface_util } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/tests/mock_wifi_iface_util.h b/wifi/1.4/default/tests/mock_wifi_iface_util.h similarity index 97% rename from wifi/1.3/default/tests/mock_wifi_iface_util.h rename to wifi/1.4/default/tests/mock_wifi_iface_util.h index 8ec93eb471..6cc81e4083 100644 --- a/wifi/1.3/default/tests/mock_wifi_iface_util.h +++ b/wifi/1.4/default/tests/mock_wifi_iface_util.h @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace iface_util { @@ -43,7 +43,7 @@ class MockWifiIfaceUtil : public WifiIfaceUtil { }; } // namespace iface_util } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp similarity index 96% rename from wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp rename to wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp index 0a202c42d2..8d65c59e25 100644 --- a/wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp +++ b/wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace legacy_hal { @@ -33,7 +33,7 @@ MockWifiLegacyHal::MockWifiLegacyHal( : WifiLegacyHal(iface_tool) {} } // namespace legacy_hal } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/tests/mock_wifi_legacy_hal.h b/wifi/1.4/default/tests/mock_wifi_legacy_hal.h similarity index 92% rename from wifi/1.3/default/tests/mock_wifi_legacy_hal.h rename to wifi/1.4/default/tests/mock_wifi_legacy_hal.h index 81cb1ded86..6942c1e4e3 100644 --- a/wifi/1.3/default/tests/mock_wifi_legacy_hal.h +++ b/wifi/1.4/default/tests/mock_wifi_legacy_hal.h @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace legacy_hal { @@ -41,9 +41,9 @@ class MockWifiLegacyHal : public WifiLegacyHal { wifi_error(const std::string&, const on_radio_mode_change_callback&)); MOCK_METHOD1(getFirmwareVersion, std::pair( - const std::string& iface_name)); + const std::string& iface_name)); MOCK_METHOD1(getDriverVersion, std::pair( - const std::string& iface_name)); + const std::string& iface_name)); MOCK_METHOD2(selectTxPowerScenario, wifi_error(const std::string& iface_name, @@ -60,7 +60,7 @@ class MockWifiLegacyHal : public WifiLegacyHal { }; } // namespace legacy_hal } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.4/default/tests/mock_wifi_mode_controller.cpp similarity index 96% rename from wifi/1.3/default/tests/mock_wifi_mode_controller.cpp rename to wifi/1.4/default/tests/mock_wifi_mode_controller.cpp index 2b0ea366f3..ee09029820 100644 --- a/wifi/1.3/default/tests/mock_wifi_mode_controller.cpp +++ b/wifi/1.4/default/tests/mock_wifi_mode_controller.cpp @@ -24,14 +24,14 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace mode_controller { MockWifiModeController::MockWifiModeController() : WifiModeController() {} } // namespace mode_controller } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/tests/mock_wifi_mode_controller.h b/wifi/1.4/default/tests/mock_wifi_mode_controller.h similarity index 97% rename from wifi/1.3/default/tests/mock_wifi_mode_controller.h rename to wifi/1.4/default/tests/mock_wifi_mode_controller.h index c204059e67..1e1ce696f0 100644 --- a/wifi/1.3/default/tests/mock_wifi_mode_controller.h +++ b/wifi/1.4/default/tests/mock_wifi_mode_controller.h @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace mode_controller { @@ -38,7 +38,7 @@ class MockWifiModeController : public WifiModeController { }; } // namespace mode_controller } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/tests/ringbuffer_unit_tests.cpp b/wifi/1.4/default/tests/ringbuffer_unit_tests.cpp similarity index 98% rename from wifi/1.3/default/tests/ringbuffer_unit_tests.cpp rename to wifi/1.4/default/tests/ringbuffer_unit_tests.cpp index 0cf1e4f256..a65347f7ac 100644 --- a/wifi/1.3/default/tests/ringbuffer_unit_tests.cpp +++ b/wifi/1.4/default/tests/ringbuffer_unit_tests.cpp @@ -24,7 +24,7 @@ using testing::Test; namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { class RingbufferTest : public Test { @@ -91,7 +91,7 @@ TEST_F(RingbufferTest, OversizedAppendDoesNotDropExistingData) { EXPECT_EQ(input, buffer_.getData().front()); } } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/tests/runtests.sh b/wifi/1.4/default/tests/runtests.sh similarity index 100% rename from wifi/1.3/default/tests/runtests.sh rename to wifi/1.4/default/tests/runtests.sh diff --git a/wifi/1.3/default/tests/wifi_ap_iface_unit_tests.cpp b/wifi/1.4/default/tests/wifi_ap_iface_unit_tests.cpp similarity index 98% rename from wifi/1.3/default/tests/wifi_ap_iface_unit_tests.cpp rename to wifi/1.4/default/tests/wifi_ap_iface_unit_tests.cpp index 680f534c41..230edd2ee3 100644 --- a/wifi/1.3/default/tests/wifi_ap_iface_unit_tests.cpp +++ b/wifi/1.4/default/tests/wifi_ap_iface_unit_tests.cpp @@ -38,7 +38,7 @@ constexpr char kIfaceName[] = "mockWlan0"; namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { class WifiApIfaceTest : public Test { @@ -73,7 +73,7 @@ TEST_F(WifiApIfaceTest, DontSetRandomMacAddressIfFeatureDisabled) { new WifiApIface(kIfaceName, legacy_hal_, iface_util_, feature_flags_); } } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp similarity index 99% rename from wifi/1.3/default/tests/wifi_chip_unit_tests.cpp rename to wifi/1.4/default/tests/wifi_chip_unit_tests.cpp index d8ce2785b7..2ad093ae69 100644 --- a/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp +++ b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp @@ -41,7 +41,7 @@ constexpr ChipId kFakeChipId = 5; namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { class WifiChipTest : public Test { @@ -865,7 +865,7 @@ TEST_F(WifiChip_MultiIfaceTest, CreateApStartsWithIdx1) { ASSERT_EQ(createIface(IfaceType::STA), "wlan3"); } } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/tests/wifi_iface_util_unit_tests.cpp b/wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp similarity index 98% rename from wifi/1.3/default/tests/wifi_iface_util_unit_tests.cpp rename to wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp index 28d23ffa71..03394bc209 100644 --- a/wifi/1.3/default/tests/wifi_iface_util_unit_tests.cpp +++ b/wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp @@ -41,7 +41,7 @@ bool isValidUnicastLocallyAssignedMacAddress( namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace iface_util { class WifiIfaceUtilTest : public Test { @@ -90,7 +90,7 @@ TEST_F(WifiIfaceUtilTest, IfaceEventHandlers_SetMacAddress) { } } // namespace iface_util } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp similarity index 99% rename from wifi/1.3/default/tests/wifi_nan_iface_unit_tests.cpp rename to wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp index eb6c61065d..8aefa92412 100644 --- a/wifi/1.3/default/tests/wifi_nan_iface_unit_tests.cpp +++ b/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp @@ -38,7 +38,7 @@ constexpr char kIfaceName[] = "mockWlan0"; namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { bool CaptureIfaceEventHandlers( @@ -142,7 +142,7 @@ TEST_F(WifiNanIfaceTest, IfacEventHandlers_OnStateToggleOffOn) { captured_iface_event_handlers.on_state_toggle_off_on(kIfaceName); } } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi.cpp b/wifi/1.4/default/wifi.cpp similarity index 99% rename from wifi/1.3/default/wifi.cpp rename to wifi/1.4/default/wifi.cpp index 2f21819dbc..4f48d7e7a6 100644 --- a/wifi/1.3/default/wifi.cpp +++ b/wifi/1.4/default/wifi.cpp @@ -28,7 +28,7 @@ static constexpr android::hardware::wifi::V1_0::ChipId kChipId = 0; namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { using hidl_return_util::validateAndCall; using hidl_return_util::validateAndCallWithLock; @@ -210,7 +210,7 @@ WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController( return createWifiStatus(WifiStatusCode::SUCCESS); } } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi.h b/wifi/1.4/default/wifi.h similarity index 96% rename from wifi/1.3/default/wifi.h rename to wifi/1.4/default/wifi.h index 1c2a15409e..087d6f71e8 100644 --- a/wifi/1.3/default/wifi.h +++ b/wifi/1.4/default/wifi.h @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include "hidl_callback_util.h" @@ -32,13 +32,13 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { /** * Root HIDL interface object used to control the Wifi HAL. */ -class Wifi : public V1_3::IWifi { +class Wifi : public V1_4::IWifi { public: Wifi(const std::shared_ptr iface_tool, const std::shared_ptr legacy_hal, @@ -92,7 +92,7 @@ class Wifi : public V1_3::IWifi { }; } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_ap_iface.cpp b/wifi/1.4/default/wifi_ap_iface.cpp similarity index 99% rename from wifi/1.3/default/wifi_ap_iface.cpp rename to wifi/1.4/default/wifi_ap_iface.cpp index 9a8681afed..13ce2dddcb 100644 --- a/wifi/1.3/default/wifi_ap_iface.cpp +++ b/wifi/1.4/default/wifi_ap_iface.cpp @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { using hidl_return_util::validateAndCall; @@ -112,7 +112,7 @@ WifiApIface::getValidFrequenciesForBandInternal(WifiBand band) { return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies}; } } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_ap_iface.h b/wifi/1.4/default/wifi_ap_iface.h similarity index 98% rename from wifi/1.3/default/wifi_ap_iface.h rename to wifi/1.4/default/wifi_ap_iface.h index 98c5c9c376..179acacdaa 100644 --- a/wifi/1.3/default/wifi_ap_iface.h +++ b/wifi/1.4/default/wifi_ap_iface.h @@ -27,7 +27,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { using namespace android::hardware::wifi::V1_0; @@ -72,7 +72,7 @@ class WifiApIface : public V1_0::IWifiApIface { }; } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp similarity index 99% rename from wifi/1.3/default/wifi_chip.cpp rename to wifi/1.4/default/wifi_chip.cpp index e9991dceec..5a14b01c37 100644 --- a/wifi/1.3/default/wifi_chip.cpp +++ b/wifi/1.4/default/wifi_chip.cpp @@ -307,7 +307,7 @@ std::vector makeCharVec(const std::string& str) { namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { using hidl_return_util::validateAndCall; using hidl_return_util::validateAndCallWithLock; @@ -1539,7 +1539,7 @@ bool WifiChip::writeRingbufferFilesInternal() { } } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_chip.h b/wifi/1.4/default/wifi_chip.h similarity index 99% rename from wifi/1.3/default/wifi_chip.h rename to wifi/1.4/default/wifi_chip.h index 153ca6a62d..ae9af9099c 100644 --- a/wifi/1.3/default/wifi_chip.h +++ b/wifi/1.4/default/wifi_chip.h @@ -37,7 +37,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { using namespace android::hardware::wifi::V1_0; @@ -273,7 +273,7 @@ class WifiChip : public V1_3::IWifiChip { }; } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_feature_flags.cpp b/wifi/1.4/default/wifi_feature_flags.cpp similarity index 99% rename from wifi/1.3/default/wifi_feature_flags.cpp rename to wifi/1.4/default/wifi_feature_flags.cpp index 7212cfac3c..f9746eb076 100644 --- a/wifi/1.3/default/wifi_feature_flags.cpp +++ b/wifi/1.4/default/wifi_feature_flags.cpp @@ -19,7 +19,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace feature_flags { @@ -162,7 +162,7 @@ bool WifiFeatureFlags::isApMacRandomizationDisabled() { } // namespace feature_flags } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_feature_flags.h b/wifi/1.4/default/wifi_feature_flags.h similarity index 97% rename from wifi/1.3/default/wifi_feature_flags.h rename to wifi/1.4/default/wifi_feature_flags.h index 3ae6920907..4e146cdfc6 100644 --- a/wifi/1.3/default/wifi_feature_flags.h +++ b/wifi/1.4/default/wifi_feature_flags.h @@ -22,7 +22,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace feature_flags { @@ -48,7 +48,7 @@ class WifiFeatureFlags { } // namespace feature_flags } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_iface_util.cpp b/wifi/1.4/default/wifi_iface_util.cpp similarity index 99% rename from wifi/1.3/default/wifi_iface_util.cpp rename to wifi/1.4/default/wifi_iface_util.cpp index 34bc02d3f9..2883b4627b 100644 --- a/wifi/1.3/default/wifi_iface_util.cpp +++ b/wifi/1.4/default/wifi_iface_util.cpp @@ -35,7 +35,7 @@ constexpr uint8_t kMacAddressLocallyAssignedMask = 0x02; namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace iface_util { @@ -112,7 +112,7 @@ std::array WifiIfaceUtil::createRandomMacAddress() { } } // namespace iface_util } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_iface_util.h b/wifi/1.4/default/wifi_iface_util.h similarity index 98% rename from wifi/1.3/default/wifi_iface_util.h rename to wifi/1.4/default/wifi_iface_util.h index 98073e0763..35edff68bd 100644 --- a/wifi/1.3/default/wifi_iface_util.h +++ b/wifi/1.4/default/wifi_iface_util.h @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace iface_util { @@ -67,7 +67,7 @@ class WifiIfaceUtil { } // namespace iface_util } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp similarity index 99% rename from wifi/1.3/default/wifi_legacy_hal.cpp rename to wifi/1.4/default/wifi_legacy_hal.cpp index 485bd16634..8139253272 100644 --- a/wifi/1.3/default/wifi_legacy_hal.cpp +++ b/wifi/1.4/default/wifi_legacy_hal.cpp @@ -50,7 +50,7 @@ std::vector makeCharVec(const std::string& str) { namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace legacy_hal { // Legacy HAL functions accept "C" style function pointers, so use global @@ -1449,7 +1449,7 @@ void WifiLegacyHal::invalidate() { } // namespace legacy_hal } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h similarity index 99% rename from wifi/1.3/default/wifi_legacy_hal.h rename to wifi/1.4/default/wifi_legacy_hal.h index 9cfa172402..7f16c30628 100644 --- a/wifi/1.3/default/wifi_legacy_hal.h +++ b/wifi/1.4/default/wifi_legacy_hal.h @@ -35,7 +35,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { // This is in a separate namespace to prevent typename conflicts between // the legacy HAL types and the HIDL interface types. @@ -396,7 +396,7 @@ class WifiLegacyHal { } // namespace legacy_hal } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_legacy_hal_stubs.cpp b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp similarity index 99% rename from wifi/1.3/default/wifi_legacy_hal_stubs.cpp rename to wifi/1.4/default/wifi_legacy_hal_stubs.cpp index dedd2d4819..27afa1ff06 100644 --- a/wifi/1.3/default/wifi_legacy_hal_stubs.cpp +++ b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp @@ -20,7 +20,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace legacy_hal { template @@ -142,7 +142,7 @@ bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) { } } // namespace legacy_hal } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_legacy_hal_stubs.h b/wifi/1.4/default/wifi_legacy_hal_stubs.h similarity index 96% rename from wifi/1.3/default/wifi_legacy_hal_stubs.h rename to wifi/1.4/default/wifi_legacy_hal_stubs.h index 64854e00f6..577a545b1d 100644 --- a/wifi/1.3/default/wifi_legacy_hal_stubs.h +++ b/wifi/1.4/default/wifi_legacy_hal_stubs.h @@ -20,7 +20,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace legacy_hal { #include @@ -28,7 +28,7 @@ namespace legacy_hal { bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn); } // namespace legacy_hal } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_mode_controller.cpp b/wifi/1.4/default/wifi_mode_controller.cpp similarity index 98% rename from wifi/1.3/default/wifi_mode_controller.cpp rename to wifi/1.4/default/wifi_mode_controller.cpp index c392486f84..252121a5b4 100644 --- a/wifi/1.3/default/wifi_mode_controller.cpp +++ b/wifi/1.4/default/wifi_mode_controller.cpp @@ -48,7 +48,7 @@ int convertIfaceTypeToFirmwareMode(IfaceType type) { namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace mode_controller { @@ -85,7 +85,7 @@ bool WifiModeController::deinitialize() { } } // namespace mode_controller } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_mode_controller.h b/wifi/1.4/default/wifi_mode_controller.h similarity index 98% rename from wifi/1.3/default/wifi_mode_controller.h rename to wifi/1.4/default/wifi_mode_controller.h index ace5a52839..45fa999b2a 100644 --- a/wifi/1.3/default/wifi_mode_controller.h +++ b/wifi/1.4/default/wifi_mode_controller.h @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { namespace mode_controller { using namespace android::hardware::wifi::V1_0; @@ -55,7 +55,7 @@ class WifiModeController { } // namespace mode_controller } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_nan_iface.cpp b/wifi/1.4/default/wifi_nan_iface.cpp similarity index 99% rename from wifi/1.3/default/wifi_nan_iface.cpp rename to wifi/1.4/default/wifi_nan_iface.cpp index ff9f4224df..981acb282c 100644 --- a/wifi/1.3/default/wifi_nan_iface.cpp +++ b/wifi/1.4/default/wifi_nan_iface.cpp @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { using hidl_return_util::validateAndCall; @@ -881,7 +881,7 @@ WifiStatus WifiNanIface::configRequest_1_2Internal( } } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_nan_iface.h b/wifi/1.4/default/wifi_nan_iface.h similarity index 99% rename from wifi/1.3/default/wifi_nan_iface.h rename to wifi/1.4/default/wifi_nan_iface.h index 737be93217..e3a5c34cd3 100644 --- a/wifi/1.3/default/wifi_nan_iface.h +++ b/wifi/1.4/default/wifi_nan_iface.h @@ -28,7 +28,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { using namespace android::hardware::wifi::V1_0; @@ -160,7 +160,7 @@ class WifiNanIface : public V1_2::IWifiNanIface { }; } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_p2p_iface.cpp b/wifi/1.4/default/wifi_p2p_iface.cpp similarity index 98% rename from wifi/1.3/default/wifi_p2p_iface.cpp rename to wifi/1.4/default/wifi_p2p_iface.cpp index b5d5886f68..9e7341f248 100644 --- a/wifi/1.3/default/wifi_p2p_iface.cpp +++ b/wifi/1.4/default/wifi_p2p_iface.cpp @@ -23,7 +23,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { using hidl_return_util::validateAndCall; @@ -60,7 +60,7 @@ std::pair WifiP2pIface::getTypeInternal() { } } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_p2p_iface.h b/wifi/1.4/default/wifi_p2p_iface.h similarity index 98% rename from wifi/1.3/default/wifi_p2p_iface.h rename to wifi/1.4/default/wifi_p2p_iface.h index 8a7207a412..a6fc59d04b 100644 --- a/wifi/1.3/default/wifi_p2p_iface.h +++ b/wifi/1.4/default/wifi_p2p_iface.h @@ -25,7 +25,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { using namespace android::hardware::wifi::V1_0; @@ -58,7 +58,7 @@ class WifiP2pIface : public V1_0::IWifiP2pIface { }; } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_rtt_controller.cpp b/wifi/1.4/default/wifi_rtt_controller.cpp similarity index 99% rename from wifi/1.3/default/wifi_rtt_controller.cpp rename to wifi/1.4/default/wifi_rtt_controller.cpp index 3dcbee687b..d50c7cf68a 100644 --- a/wifi/1.3/default/wifi_rtt_controller.cpp +++ b/wifi/1.4/default/wifi_rtt_controller.cpp @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { using hidl_return_util::validateAndCall; @@ -271,7 +271,7 @@ WifiStatus WifiRttController::disableResponderInternal(uint32_t cmd_id) { return createWifiStatusFromLegacyError(legacy_status); } } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_rtt_controller.h b/wifi/1.4/default/wifi_rtt_controller.h similarity index 99% rename from wifi/1.3/default/wifi_rtt_controller.h rename to wifi/1.4/default/wifi_rtt_controller.h index eedd22aeef..1415ff7ce6 100644 --- a/wifi/1.3/default/wifi_rtt_controller.h +++ b/wifi/1.4/default/wifi_rtt_controller.h @@ -27,7 +27,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { /** @@ -98,7 +98,7 @@ class WifiRttController : public V1_0::IWifiRttController { }; } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_sta_iface.cpp b/wifi/1.4/default/wifi_sta_iface.cpp similarity index 99% rename from wifi/1.3/default/wifi_sta_iface.cpp rename to wifi/1.4/default/wifi_sta_iface.cpp index a6539e5d90..3e0127ed2a 100644 --- a/wifi/1.3/default/wifi_sta_iface.cpp +++ b/wifi/1.4/default/wifi_sta_iface.cpp @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { using hidl_return_util::validateAndCall; @@ -641,7 +641,7 @@ WifiStaIface::getFactoryMacAddressInternal() { } } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_sta_iface.h b/wifi/1.4/default/wifi_sta_iface.h similarity index 99% rename from wifi/1.3/default/wifi_sta_iface.h rename to wifi/1.4/default/wifi_sta_iface.h index 92249394bf..d8f7a01ade 100644 --- a/wifi/1.3/default/wifi_sta_iface.h +++ b/wifi/1.4/default/wifi_sta_iface.h @@ -28,7 +28,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { using namespace android::hardware::wifi::V1_0; @@ -171,7 +171,7 @@ class WifiStaIface : public V1_3::IWifiStaIface { }; } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_status_util.cpp b/wifi/1.4/default/wifi_status_util.cpp similarity index 99% rename from wifi/1.3/default/wifi_status_util.cpp rename to wifi/1.4/default/wifi_status_util.cpp index 0a5bb13d4f..597c04b609 100644 --- a/wifi/1.3/default/wifi_status_util.cpp +++ b/wifi/1.4/default/wifi_status_util.cpp @@ -19,7 +19,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { std::string legacyErrorToString(legacy_hal::wifi_error error) { @@ -100,7 +100,7 @@ WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error) { } } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_status_util.h b/wifi/1.4/default/wifi_status_util.h similarity index 97% rename from wifi/1.3/default/wifi_status_util.h rename to wifi/1.4/default/wifi_status_util.h index bc8baa9fe7..41bcfaf741 100644 --- a/wifi/1.3/default/wifi_status_util.h +++ b/wifi/1.4/default/wifi_status_util.h @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_3 { +namespace V1_4 { namespace implementation { using namespace android::hardware::wifi::V1_0; @@ -37,7 +37,7 @@ WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error, WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error); } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace wifi } // namespace hardware } // namespace android From 537c0274b86c980a81b56f02c219f3f64802d274 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Fri, 13 Sep 2019 10:36:07 -0700 Subject: [PATCH 0119/1022] MH2 | Add rough proxy callback postEvents method Add post events method to HalProxyCallback without fully implementing the wakeup events handling and pending blocking writes. Also change mSensorList of the halProxy to mSensors which is a map from sensorHandle to sensorInfo so that getNumWakeupEvents method of callback can find sensorinfo info from sensorhandle of event type. Instantiate halproxycallback vector in HalProxy for each subhal in the ctor as well. Add very simple test for the postEvents method of callback. Bug: 136511617 Test: New unit test passes. Change-Id: I39c861cff286f24992bfcfcaa6bb468b4544b0e0 --- sensors/2.0/multihal/HalProxy.cpp | 141 +++++++++++++----- sensors/2.0/multihal/include/HalProxy.h | 87 ++++++++++- sensors/2.0/multihal/include/SubHal.h | 14 +- sensors/2.0/multihal/tests/HalProxy_test.cpp | 147 ++++++++++++++++++- 4 files changed, 338 insertions(+), 51 deletions(-) diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index b4d246690d..5a45a44ad5 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -16,12 +16,15 @@ #include "HalProxy.h" +#include "SubHal.h" + #include #include #include #include +#include namespace android { namespace hardware { @@ -29,53 +32,22 @@ namespace sensors { namespace V2_0 { namespace implementation { +using ::android::hardware::sensors::V2_0::EventQueueFlagBits; + typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*); -// TODO: Use this wake lock name as the prefix to all sensors HAL wake locks acquired. -// constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP"; - -// TODO: Use the following class as a starting point for implementing the full HalProxyCallback -// along with being inspiration for how to implement the ScopedWakelock class. -/** - * Callback class used to provide the HalProxy with the index of which subHal is invoking - */ -class SensorsCallbackProxy : public ISensorsCallback { - public: - SensorsCallbackProxy(wp& halProxy, int32_t subHalIndex) - : mHalProxy(halProxy), mSubHalIndex(subHalIndex) {} - - Return onDynamicSensorsConnected( - const hidl_vec& dynamicSensorsAdded) override { - sp halProxy(mHalProxy.promote()); - if (halProxy != nullptr) { - return halProxy->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex); - } - return Return(); - } - - Return onDynamicSensorsDisconnected( - const hidl_vec& dynamicSensorHandlesRemoved) override { - sp halProxy(mHalProxy.promote()); - if (halProxy != nullptr) { - return halProxy->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, - mSubHalIndex); - } - return Return(); - } - - private: - wp& mHalProxy; - int32_t mSubHalIndex; -}; +ScopedWakelock::ScopedWakelock() { + // TODO: Implement +} HalProxy::HalProxy() { const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf"; initializeSubHalListFromConfigFile(kMultiHalConfigFile); - initializeSensorList(); + initializeSubHalCallbacksAndSensorList(); } HalProxy::HalProxy(std::vector& subHalList) : mSubHalList(subHalList) { - initializeSensorList(); + initializeSubHalCallbacksAndSensorList(); } HalProxy::~HalProxy() { @@ -84,7 +56,11 @@ HalProxy::~HalProxy() { } Return HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) { - _hidl_cb(mSensorList); + std::vector sensors; + for (const auto& iter : mSensors) { + sensors.push_back(iter.second); + } + _hidl_cb(sensors); return Void(); } @@ -148,6 +124,17 @@ Return HalProxy::initialize( // TODO: start threads to read wake locks and process events from sub HALs. + for (size_t i = 0; i < mSubHalList.size(); i++) { + auto subHal = mSubHalList[i]; + const auto& subHalCallback = mSubHalCallbacks[i]; + Result currRes = subHal->initialize(subHalCallback); + if (currRes != Result::OK) { + result = currRes; + ALOGE("Subhal '%s' failed to initialize.", subHal->getName().c_str()); + break; + } + } + return result; } @@ -239,6 +226,13 @@ void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) { } } +void HalProxy::initializeSubHalCallbacks() { + for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) { + sp callback = new HalProxyCallback(this, subHalIndex); + mSubHalCallbacks.push_back(callback); + } +} + void HalProxy::initializeSensorList() { for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) { ISensorsSubHal* subHal = mSubHalList[subHalIndex]; @@ -250,7 +244,7 @@ void HalProxy::initializeSensorList() { ALOGV("Loaded sensor: %s", sensor.name.c_str()); sensor.sensorHandle |= (subHalIndex << 24); setDirectChannelFlags(&sensor, subHal); - mSensorList.push_back(sensor); + mSensors[sensor.sensorHandle] = sensor; } } }); @@ -260,6 +254,29 @@ void HalProxy::initializeSensorList() { } } +void HalProxy::initializeSubHalCallbacksAndSensorList() { + initializeSubHalCallbacks(); + initializeSensorList(); +} + +void HalProxy::postEventsToMessageQueue(const std::vector& events) { + std::lock_guard lock(mEventQueueMutex); + size_t numToWrite = std::min(events.size(), mEventQueue->availableToWrite()); + if (numToWrite > 0) { + if (mEventQueue->write(events.data(), numToWrite)) { + // TODO: While loop if mEventQueue->avaiableToWrite > 0 to possibly fit in more writes + // immediately + mEventQueueFlag->wake(static_cast(EventQueueFlagBits::READ_AND_PROCESS)); + } else { + numToWrite = 0; + } + } + if (numToWrite < events.size()) { + // TODO: Post from events[numToWrite -> end] to background events queue + // Signal background thread + } +} + void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal) { bool sensorSupportsDirectChannel = (sensorInfo->flags & (V1_0::SensorFlagBits::MASK_DIRECT_REPORT | @@ -282,6 +299,50 @@ uint32_t HalProxy::clearSubHalIndex(uint32_t sensorHandle) { return sensorHandle & (~kSensorHandleSubHalIndexMask); } +void HalProxyCallback::postEvents(const std::vector& events, ScopedWakelock wakelock) { + (void)wakelock; + size_t numWakeupEvents; + std::vector processedEvents = processEvents(events, &numWakeupEvents); + if (numWakeupEvents > 0) { + ALOG_ASSERT(wakelock.isLocked(), + "Wakeup events posted while wakelock unlocked for subhal" + " w/ index %zu.", + mSubHalIndex); + } else { + ALOG_ASSERT(!wakelock.isLocked(), + "No Wakeup events posted but wakelock locked for subhal" + " w/ index %zu.", + mSubHalIndex); + } + + mHalProxy->postEventsToMessageQueue(processedEvents); +} + +ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) { + ScopedWakelock wakelock; + wakelock.mLocked = lock; + return wakelock; +} + +std::vector HalProxyCallback::processEvents(const std::vector& events, + size_t* numWakeupEvents) const { + std::vector eventsOut; + *numWakeupEvents = 0; + for (Event event : events) { + event.sensorHandle = setSubHalIndex(event.sensorHandle); + eventsOut.push_back(event); + if ((mHalProxy->getSensorInfo(event.sensorHandle).flags & V1_0::SensorFlagBits::WAKE_UP) != + 0) { + (*numWakeupEvents)++; + } + } + return eventsOut; +} + +uint32_t HalProxyCallback::setSubHalIndex(uint32_t sensorHandle) const { + return sensorHandle | mSubHalIndex << 24; +} + } // namespace implementation } // namespace V2_0 } // namespace sensors diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h index 4ecb58b5a5..6c50eef8f4 100644 --- a/sensors/2.0/multihal/include/HalProxy.h +++ b/sensors/2.0/multihal/include/HalProxy.h @@ -24,6 +24,8 @@ #include #include +#include + namespace android { namespace hardware { namespace sensors { @@ -45,7 +47,9 @@ class HalProxy : public ISensors { using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; using Result = ::android::hardware::sensors::V1_0::Result; + using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo; using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; + using ISensorsSubHal = ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal; explicit HalProxy(); // Test only constructor. @@ -91,6 +95,27 @@ class HalProxy : public ISensors { Return onDynamicSensorsDisconnected(const hidl_vec& dynamicSensorHandlesRemoved, int32_t subHalIndex); + // Below methods are for HalProxyCallback + + /** + * Post events to the event message queue if there is room to write them. Otherwise post the + * remaining events to a background thread for a blocking write with a 5 second timeout. + * + * @param events The list of events to post to the message queue. + */ + void postEventsToMessageQueue(const std::vector& events); + + /** + * Get the SensorInfo object associated with the sensorHandle. + * + * @param sensorHandle The sensorHandle for the sensor. + * + * @return The sensor info for the sensor. + */ + const SensorInfo& getSensorInfo(uint32_t sensorHandle) const { + return mSensors.at(sensorHandle); + } + private: using EventMessageQueue = MessageQueue; using WakeLockMessageQueue = MessageQueue; @@ -120,14 +145,16 @@ class HalProxy : public ISensors { */ std::vector mSubHalList; + std::vector> mSubHalCallbacks; + /** - * List of SensorInfo objects that contains the sensor info from subhals as + * Map of sensor handles to SensorInfo objects that contains the sensor info from subhals as * well as the modified sensor handle for the framework. * - * The subhal index is encoded in the first byte of the sensor handle and - * the remaining bytes are generated by the subhal to identify the sensor. + * The subhal index is encoded in the first byte of the sensor handle and the remaining + * bytes are generated by the subhal to identify the sensor. */ - std::vector mSensorList; + std::map mSensors; //! The current operation mode for all subhals. OperationMode mCurrentOperationMode = OperationMode::NORMAL; @@ -135,6 +162,9 @@ class HalProxy : public ISensors { //! The single subHal that supports directChannel reporting. ISensorsSubHal* mDirectChannelSubHal = nullptr; + //! The mutex for the event queue. + std::mutex mEventQueueMutex; + //! The bit mask used to get the subhal index from a sensor handle. static constexpr uint32_t kSensorHandleSubHalIndexMask = 0xFF000000; @@ -144,12 +174,22 @@ class HalProxy : public ISensors { */ void initializeSubHalListFromConfigFile(const char* configFileName); + /** + * Initialize the HalProxyCallback vector using the list of subhals. + */ + void initializeSubHalCallbacks(); + /** * Initialize the list of SensorInfo objects in mSensorList by getting sensors from each * subhal. */ void initializeSensorList(); + /** + * Calls the above two helper methods which are shared in both ctors. + */ + void initializeSubHalCallbacksAndSensorList(); + /** * Clear direct channel flags if the HalProxy has already chosen a subhal as its direct channel * subhal. Set the directChannelSubHal pointer to the subHal passed in if this is the first @@ -179,6 +219,45 @@ class HalProxy : public ISensors { static uint32_t clearSubHalIndex(uint32_t sensorHandle); }; +// TODO: Use this wake lock name as the prefix to all sensors HAL wake locks acquired. +// constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP"; + +// TODO: Use the following class as a starting point for implementing the full HalProxyCallback +// along with being inspiration for how to implement the ScopedWakelock class. +/** + * Callback class used to provide the HalProxy with the index of which subHal is invoking + */ +class HalProxyCallback : public IHalProxyCallback { + using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo; + + public: + HalProxyCallback(HalProxy* halProxy, int32_t subHalIndex) + : mHalProxy(halProxy), mSubHalIndex(subHalIndex) {} + + Return onDynamicSensorsConnected( + const hidl_vec& dynamicSensorsAdded) override { + return mHalProxy->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex); + } + + Return onDynamicSensorsDisconnected( + const hidl_vec& dynamicSensorHandlesRemoved) override { + return mHalProxy->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex); + } + + void postEvents(const std::vector& events, ScopedWakelock wakelock); + + ScopedWakelock createScopedWakelock(bool lock); + + private: + HalProxy* mHalProxy; + int32_t mSubHalIndex; + + std::vector processEvents(const std::vector& events, + size_t* numWakeupEvents) const; + + uint32_t setSubHalIndex(uint32_t sensorHandle) const; +}; + } // namespace implementation } // namespace V2_0 } // namespace sensors diff --git a/sensors/2.0/multihal/include/SubHal.h b/sensors/2.0/multihal/include/SubHal.h index e84cba50f6..6181e0bb25 100644 --- a/sensors/2.0/multihal/include/SubHal.h +++ b/sensors/2.0/multihal/include/SubHal.h @@ -21,10 +21,6 @@ #include -using ::android::hardware::sensors::V1_0::Event; -using ::android::hardware::sensors::V1_0::Result; -using ::android::hardware::sensors::V1_0::SensorInfo; - // Indicates the current version of the multiHAL interface formatted as (HAL major version) << 24 | // (HAL minor version) << 16 | (multiHAL version) #define SUB_HAL_2_0_VERSION 0x02000000 @@ -35,6 +31,10 @@ namespace sensors { namespace V2_0 { namespace implementation { +using ::android::hardware::sensors::V1_0::Event; +using ::android::hardware::sensors::V1_0::Result; +using ::android::hardware::sensors::V1_0::SensorInfo; + /** * Wrapper around wake lock acquisition functions (acquire/release_wake_lock) that provides a * RAII-style mechanism for keeping a wake lock held for the duration of a scoped block. @@ -68,7 +68,7 @@ class ScopedWakelock { bool mLocked; private: - // TODO: Mark HalProxy's subclass of ScopedWakelock as a friend so that it can be initialized. + friend class HalProxyCallback; ScopedWakelock(); ScopedWakelock(const ScopedWakelock&) = delete; ScopedWakelock& operator=(const ScopedWakelock&) = delete; @@ -169,7 +169,9 @@ class ISensorsSubHal : public ISensors { /** * First method invoked on the sub-HAL after it's allocated through sensorsHalGetSubHal() by the * HalProxy. Sub-HALs should use this to initialize any state and retain the callback given in - * order to communicate with the HalProxy. + * order to communicate with the HalProxy. Method will be called anytime the sensors framework + * restarts. Therefore, this method will be responsible for reseting the state of the subhal and + * cleaning up and reallocating any previously allocated data. * * @param halProxyCallback callback used to inform the HalProxy when a dynamic sensor's state * changes, new sensor events should be sent to the framework, and when a new ScopedWakelock diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp index 1e1f9e9e44..a93230f568 100644 --- a/sensors/2.0/multihal/tests/HalProxy_test.cpp +++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp @@ -16,18 +16,29 @@ #include #include +#include #include "HalProxy.h" #include "SensorsSubHal.h" +#include "SubHal.h" #include +#undef LOG_TAG +#define LOG_TAG "HalProxy_test" + namespace { +using ::android::hardware::hidl_vec; +using ::android::hardware::MessageQueue; +using ::android::hardware::Return; +using ::android::hardware::sensors::V1_0::EventPayload; using ::android::hardware::sensors::V1_0::SensorFlagBits; using ::android::hardware::sensors::V1_0::SensorInfo; using ::android::hardware::sensors::V1_0::SensorType; +using ::android::hardware::sensors::V2_0::ISensorsCallback; using ::android::hardware::sensors::V2_0::implementation::HalProxy; +using ::android::hardware::sensors::V2_0::implementation::HalProxyCallback; using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation:: AllSupportDirectChannelSensorsSubHal; @@ -36,10 +47,28 @@ using ::android::hardware::sensors::V2_0::subhal::implementation:: DoesNotSupportDirectChannelSensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal; - using ::android::hardware::sensors::V2_0::subhal::implementation:: SetOperationModeFailingSensorsSubHal; +using EventMessageQueue = MessageQueue; +using WakeupMessageQueue = MessageQueue; + +// The barebones sensors callback class passed into halproxy initialize calls +class SensorsCallback : public ISensorsCallback { + public: + Return onDynamicSensorsConnected( + const hidl_vec& /*dynamicSensorsAdded*/) override { + // Nothing yet + return Return(); + } + + Return onDynamicSensorsDisconnected( + const hidl_vec& /*dynamicSensorHandlesRemoved*/) override { + // Nothing yet + return Return(); + } +}; + // Helper declarations follow /** @@ -65,6 +94,22 @@ void testSensorsListFromProxyAndSubHal(const std::vector& proxySenso void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector& sensorsList, size_t enabledSubHalIndex); +/** + * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor + * which is a wakeup type sensor. + * + * @ return A proximity event. + */ +Event makeProximityEvent(); + +/** + * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor + * which is a wakeup type sensor. + * + * @ return A proximity event. + */ +Event makeAccelerometerEvent(); + // Tests follow TEST(HalProxyTest, GetSensorsListOneSubHalTest) { AllSensorsSubHal subHal; @@ -156,6 +201,86 @@ TEST(HalProxyTest, InitDirectChannelThreeSubHalsUnitTest) { }); } +TEST(HalProxyTest, PostSingleNonWakeupEvent) { + constexpr size_t kQueueSize = 5; + AllSensorsSubHal subHal; + std::vector subHals{&subHal}; + HalProxy proxy(subHals); + std::unique_ptr eventQueue = + std::make_unique(kQueueSize, true); + std::unique_ptr wakeLockQueue = + std::make_unique(kQueueSize, true); + ::android::sp callback = new SensorsCallback(); + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + + std::vector events{makeAccelerometerEvent()}; + subHal.postEvents(events, false /* wakeup */); + + EXPECT_EQ(eventQueue->availableToRead(), 1); +} + +TEST(HalProxyTest, PostMultipleNonWakeupEvent) { + constexpr size_t kQueueSize = 5; + constexpr size_t kNumEvents = 3; + AllSensorsSubHal subHal; + std::vector subHals{&subHal}; + HalProxy proxy(subHals); + std::unique_ptr eventQueue = + std::make_unique(kQueueSize, true); + std::unique_ptr wakeLockQueue = + std::make_unique(kQueueSize, true); + ::android::sp callback = new SensorsCallback(); + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + + std::vector events; + for (size_t i = 0; i < kNumEvents; i++) { + events.push_back(makeAccelerometerEvent()); + } + subHal.postEvents(events, false /* wakeup */); + + EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); +} + +TEST(HalProxyTest, PostSingleWakeupEvent) { + constexpr size_t kQueueSize = 5; + AllSensorsSubHal subHal; + std::vector subHals{&subHal}; + HalProxy proxy(subHals); + std::unique_ptr eventQueue = + std::make_unique(kQueueSize, true); + std::unique_ptr wakeLockQueue = + std::make_unique(kQueueSize, true); + ::android::sp callback = new SensorsCallback(); + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + + std::vector events{makeProximityEvent()}; + subHal.postEvents(events, true /* wakeup */); + + EXPECT_EQ(eventQueue->availableToRead(), 1); +} + +TEST(HalProxyTest, PostMultipleWakeupEvents) { + constexpr size_t kQueueSize = 5; + constexpr size_t kNumEvents = 3; + AllSensorsSubHal subHal; + std::vector subHals{&subHal}; + HalProxy proxy(subHals); + std::unique_ptr eventQueue = + std::make_unique(kQueueSize, true); + std::unique_ptr wakeLockQueue = + std::make_unique(kQueueSize, true); + ::android::sp callback = new SensorsCallback(); + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + + std::vector events; + for (size_t i = 0; i < kNumEvents; i++) { + events.push_back(makeProximityEvent()); + } + subHal.postEvents(events, true /* wakeup */); + + EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); +} + // Helper implementations follow void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, const std::vector& subHalSensorsList) { @@ -187,4 +312,24 @@ void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector Date: Tue, 17 Sep 2019 15:52:51 -0700 Subject: [PATCH 0120/1022] MH2 | Implement ScopeWakelock ctor and dtor Put the ScopedWakelock class into its own header and its implementation into its own cpp. Implement the refcounting of the wakelocks. However, do not incorporate the wakelock handling into post events in halproxy yet. Bug: 136511617 Test: No new tests yet. Will add more in a later patchset once more fleshed out and integrated with postEvents. Change-Id: I0815c6a6659ec5933b799294956595b11e7bf1b3 --- sensors/2.0/multihal/Android.bp | 2 + sensors/2.0/multihal/HalProxy.cpp | 28 +++++-- sensors/2.0/multihal/ScopedWakelock.cpp | 44 +++++++++++ sensors/2.0/multihal/include/HalProxy.h | 27 +++++-- sensors/2.0/multihal/include/ScopedWakelock.h | 77 +++++++++++++++++++ sensors/2.0/multihal/include/SubHal.h | 41 +--------- sensors/2.0/multihal/tests/Android.bp | 3 + sensors/2.0/multihal/tests/HalProxy_test.cpp | 2 +- 8 files changed, 172 insertions(+), 52 deletions(-) create mode 100644 sensors/2.0/multihal/ScopedWakelock.cpp create mode 100644 sensors/2.0/multihal/include/ScopedWakelock.h diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp index 697bf9e117..216cc209a2 100644 --- a/sensors/2.0/multihal/Android.bp +++ b/sensors/2.0/multihal/Android.bp @@ -42,6 +42,7 @@ cc_binary { srcs: [ "service.cpp", "HalProxy.cpp", + "ScopedWakelock.cpp", ], init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"], vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"], @@ -61,6 +62,7 @@ cc_test_library { vendor_available: true, srcs: [ "HalProxy.cpp", + "ScopedWakelock.cpp", ], export_header_lib_headers: [ "android.hardware.sensors@2.0-multihal.header", diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index 5a45a44ad5..81d1b64af8 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -20,6 +20,8 @@ #include +#include "hardware_legacy/power.h" + #include #include @@ -36,10 +38,6 @@ using ::android::hardware::sensors::V2_0::EventQueueFlagBits; typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*); -ScopedWakelock::ScopedWakelock() { - // TODO: Implement -} - HalProxy::HalProxy() { const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf"; initializeSubHalListFromConfigFile(kMultiHalConfigFile); @@ -277,6 +275,25 @@ void HalProxy::postEventsToMessageQueue(const std::vector& events) { } } +// TODO: Implement the wakelock timeout in these next two methods. Also pass in the subhal +// index for better tracking. + +void HalProxy::incrementRefCountAndMaybeAcquireWakelock() { + std::lock_guard lockGuard(mWakelockRefCountMutex); + if (mWakelockRefCount == 0) { + acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLockName); + } + mWakelockRefCount++; +} + +void HalProxy::decrementRefCountAndMaybeReleaseWakelock() { + std::lock_guard lockGuard(mWakelockRefCountMutex); + mWakelockRefCount--; + if (mWakelockRefCount == 0) { + release_wake_lock(kWakeLockName); + } +} + void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal) { bool sensorSupportsDirectChannel = (sensorInfo->flags & (V1_0::SensorFlagBits::MASK_DIRECT_REPORT | @@ -319,8 +336,7 @@ void HalProxyCallback::postEvents(const std::vector& events, ScopedWakelo } ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) { - ScopedWakelock wakelock; - wakelock.mLocked = lock; + ScopedWakelock wakelock(mHalProxy, lock); return wakelock; } diff --git a/sensors/2.0/multihal/ScopedWakelock.cpp b/sensors/2.0/multihal/ScopedWakelock.cpp new file mode 100644 index 0000000000..0430fa393e --- /dev/null +++ b/sensors/2.0/multihal/ScopedWakelock.cpp @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#include "ScopedWakelock.h" + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace implementation { + +ScopedWakelock::ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked) + : mRefCounter(refCounter), mLocked(locked) { + // TODO: Move this implementation into HalProxy object instead + if (mLocked) { + mRefCounter->incrementRefCountAndMaybeAcquireWakelock(); + } +} + +ScopedWakelock::~ScopedWakelock() { + // TODO: Move this implementation into HalProxy object instead + if (mLocked) { + mRefCounter->decrementRefCountAndMaybeReleaseWakelock(); + } +} + +} // namespace implementation +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h index 6c50eef8f4..bdcc1ff7c1 100644 --- a/sensors/2.0/multihal/include/HalProxy.h +++ b/sensors/2.0/multihal/include/HalProxy.h @@ -41,7 +41,7 @@ using ::android::hardware::MQDescriptor; using ::android::hardware::Return; using ::android::hardware::Void; -class HalProxy : public ISensors { +class HalProxy : public ISensors, public IScopedWakelockRefCounter { public: using Event = ::android::hardware::sensors::V1_0::Event; using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; @@ -95,6 +95,18 @@ class HalProxy : public ISensors { Return onDynamicSensorsDisconnected(const hidl_vec& dynamicSensorHandlesRemoved, int32_t subHalIndex); + // Below methods follow IScopedWakelockRefCounter + + /** + * Increment ref count and maybe acquire wakelock. + */ + void incrementRefCountAndMaybeAcquireWakelock() override; + + /** + * Decrement ref count and maybe release wakelock. + */ + void decrementRefCountAndMaybeReleaseWakelock() override; + // Below methods are for HalProxyCallback /** @@ -120,6 +132,8 @@ class HalProxy : public ISensors { using EventMessageQueue = MessageQueue; using WakeLockMessageQueue = MessageQueue; + const char* kWakeLockName = "SensorsHAL_WAKEUP"; + /** * The Event FMQ where sensor events are written */ @@ -165,6 +179,12 @@ class HalProxy : public ISensors { //! The mutex for the event queue. std::mutex mEventQueueMutex; + //! The scoped wakelock ref count. + size_t mWakelockRefCount = 0; + + //! The mutex guarding the mWakelockRefCount variable + std::mutex mWakelockRefCountMutex; + //! The bit mask used to get the subhal index from a sensor handle. static constexpr uint32_t kSensorHandleSubHalIndexMask = 0xFF000000; @@ -219,11 +239,6 @@ class HalProxy : public ISensors { static uint32_t clearSubHalIndex(uint32_t sensorHandle); }; -// TODO: Use this wake lock name as the prefix to all sensors HAL wake locks acquired. -// constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP"; - -// TODO: Use the following class as a starting point for implementing the full HalProxyCallback -// along with being inspiration for how to implement the ScopedWakelock class. /** * Callback class used to provide the HalProxy with the index of which subHal is invoking */ diff --git a/sensors/2.0/multihal/include/ScopedWakelock.h b/sensors/2.0/multihal/include/ScopedWakelock.h new file mode 100644 index 0000000000..a151f1566f --- /dev/null +++ b/sensors/2.0/multihal/include/ScopedWakelock.h @@ -0,0 +1,77 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace implementation { + +class IScopedWakelockRefCounter { + public: + virtual void incrementRefCountAndMaybeAcquireWakelock() = 0; + virtual void decrementRefCountAndMaybeReleaseWakelock() = 0; + // Virtual dtor needed for compilation success + virtual ~IScopedWakelockRefCounter(){}; +}; + +/** + * Wrapper around wake lock acquisition functions (acquire/release_wake_lock) that provides a + * RAII-style mechanism for keeping a wake lock held for the duration of a scoped block. + * When a ScopedWakelock is created, it increments the reference count stored in the HalProxy + * for the sub-HALs specific wake lock, acquiring the wake lock if necessary. When the object goes + * out of scope, the ref count is decremented, potentially releasing the wake lock if no other + * references to the wake lock exist. + * + * This class is allocated through the createScopedWakelock callback inside the IHalProxyCallback + * provided to sub-HALs during initialization and should be used for all wake lock acquisition + * inside of the sub-HAL to ensure wake locks are not held indefinitely. + * + * The most prevalent use case for this class will be for posting events to the framework through + * the postEvents HalProxy callback. The expectation is that sub-HALs will create this + * ScopedWakelock through the createScopedWakelock upon receiving a sensor events. The lock boolean + * provided to createScopedWakelock will be set the according to whether the sensor events are + * from wakeup sensors. Then, the sub-HAL will perform any processing necessary before invoking the + * postEvents callback passing in the previously created ScopedWakelock. At this point, ownership + * of the object will be passed to the HalProxy that will then be responsible for ensuring any + * wake locks continue to be held, if necessary. + */ +class ScopedWakelock { + public: + ScopedWakelock(ScopedWakelock&&) = default; + ScopedWakelock& operator=(ScopedWakelock&&) = default; + virtual ~ScopedWakelock(); + + bool isLocked() const { return mLocked; } + + private: + friend class HalProxyCallback; + IScopedWakelockRefCounter* mRefCounter; + bool mLocked; + ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked); + ScopedWakelock(const ScopedWakelock&) = delete; + ScopedWakelock& operator=(const ScopedWakelock&) = delete; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/sensors/2.0/multihal/include/SubHal.h b/sensors/2.0/multihal/include/SubHal.h index 6181e0bb25..e7eedaa3ea 100644 --- a/sensors/2.0/multihal/include/SubHal.h +++ b/sensors/2.0/multihal/include/SubHal.h @@ -16,6 +16,8 @@ #pragma once +#include "ScopedWakelock.h" + #include #include @@ -35,45 +37,6 @@ using ::android::hardware::sensors::V1_0::Event; using ::android::hardware::sensors::V1_0::Result; using ::android::hardware::sensors::V1_0::SensorInfo; -/** - * Wrapper around wake lock acquisition functions (acquire/release_wake_lock) that provides a - * RAII-style mechanism for keeping a wake lock held for the duration of a scoped block. - * When a ScopedWakelock is created, it increments the reference count stored in the HalProxy - * for the sub-HALs specific wake lock, acquiring the wake lock if necessary. When the object goes - * out of scope, the ref count is decremented, potentially releasing the wake lock if no other - * references to the wake lock exist. - * - * This class is allocated through the createScopedWakelock callback inside the IHalProxyCallback - * provided to sub-HALs during initialization and should be used for all wake lock acquisition - * inside of the sub-HAL to ensure wake locks are not held indefinitely. - * - * The most prevalent use case for this class will be for posting events to the framework through - * the postEvents HalProxy callback. The expectation is that sub-HALs will create this - * ScopedWakelock through the createScopedWakelock upon receiving a sensor events. The lock boolean - * provided to createScopedWakelock will be set the according to whether the sensor events are - * from wakeup sensors. Then, the sub-HAL will perform any processing necessary before invoking the - * postEvents callback passing in the previously created ScopedWakelock. At this point, ownership - * of the object will be passed to the HalProxy that will then be responsible for ensuring any - * wake locks continue to be held, if necessary. - */ -class ScopedWakelock { - public: - ScopedWakelock(ScopedWakelock&&) = default; - ScopedWakelock& operator=(ScopedWakelock&&) = default; - virtual ~ScopedWakelock() { mLocked = false; }; - - bool isLocked() const { return mLocked; } - - protected: - bool mLocked; - - private: - friend class HalProxyCallback; - ScopedWakelock(); - ScopedWakelock(const ScopedWakelock&) = delete; - ScopedWakelock& operator=(const ScopedWakelock&) = delete; -}; - /** * Interface that contains several callbacks into the HalProxy class to communicate dynamic sensor * changes and sensor events to the framework and acquire wake locks. The HalProxy will ensure diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp index 21ceb0c2d7..ab260a47dc 100644 --- a/sensors/2.0/multihal/tests/Android.bp +++ b/sensors/2.0/multihal/tests/Android.bp @@ -33,6 +33,9 @@ cc_defaults { "libpower", "libutils", ], + static_libs: [ + "android.hardware.sensors@2.0-HalProxy", + ], } cc_library { diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp index a93230f568..4b1a15efaa 100644 --- a/sensors/2.0/multihal/tests/HalProxy_test.cpp +++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp @@ -19,8 +19,8 @@ #include #include "HalProxy.h" +#include "ScopedWakelock.h" #include "SensorsSubHal.h" -#include "SubHal.h" #include From d6887ca8cce8d1184fab2997de053f7e7df4435e Mon Sep 17 00:00:00 2001 From: Dongwon Kang Date: Mon, 23 Sep 2019 14:21:57 -0700 Subject: [PATCH 0121/1022] Remove unnecessary include in service.cpp Test: build. Bug: 139201422 Change-Id: I13fcd1223eacc999c66c514b549c51a96e4efda6 --- tv/tuner/1.0/default/service.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tv/tuner/1.0/default/service.cpp b/tv/tuner/1.0/default/service.cpp index c360fcf05c..7bbc09e45c 100644 --- a/tv/tuner/1.0/default/service.cpp +++ b/tv/tuner/1.0/default/service.cpp @@ -21,7 +21,6 @@ #define LOG_TAG "android.hardware.tv.tuner@1.0-service" #endif -#include #include #include From 0d653ad82c147cee7c02c7869980421344751f26 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Mon, 23 Sep 2019 16:40:50 -0700 Subject: [PATCH 0122/1022] Wifi: Move LOCAL_VINTF_FRAGMENTS to executables Current codebase has the LOCAL_VINTF_FRAGMENTS defined in the static library definition in Android.mk. This line is skipped and does not take effect, and hence the Wifi hal service does not start. Moving the definition to the executable definitions, so it takes effect. Bug: 141447327 Test: Verify that wifi starts at boot Change-Id: I9e01483eec4017444689509ea90f761305ae471b --- wifi/1.4/default/Android.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wifi/1.4/default/Android.mk b/wifi/1.4/default/Android.mk index 7ba5e36d9c..943beccc68 100644 --- a/wifi/1.4/default/Android.mk +++ b/wifi/1.4/default/Android.mk @@ -18,7 +18,6 @@ LOCAL_PATH := $(call my-dir) ### include $(CLEAR_VARS) LOCAL_MODULE := android.hardware.wifi@1.0-service-lib -LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_PROPRIETARY_MODULE := true LOCAL_CPPFLAGS := -Wall -Werror -Wextra @@ -78,6 +77,7 @@ include $(BUILD_STATIC_LIBRARY) ### include $(CLEAR_VARS) LOCAL_MODULE := android.hardware.wifi@1.0-service +LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_PROPRIETARY_MODULE := true LOCAL_CPPFLAGS := -Wall -Werror -Wextra @@ -107,6 +107,7 @@ include $(BUILD_EXECUTABLE) ### include $(CLEAR_VARS) LOCAL_MODULE := android.hardware.wifi@1.0-service-lazy +LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml LOCAL_OVERRIDES_MODULES := android.hardware.wifi@1.0-service LOCAL_CFLAGS := -DLAZY_SERVICE LOCAL_MODULE_RELATIVE_PATH := hw From 1ab2fac7dee5f1bac811995bac1d1e5ecc6afc9f Mon Sep 17 00:00:00 2001 From: Jim Tang Date: Tue, 24 Sep 2019 07:19:12 +0000 Subject: [PATCH 0123/1022] Revert "Wifi: Move LOCAL_VINTF_FRAGMENTS to executables" This reverts commit 0d653ad82c147cee7c02c7869980421344751f26. Reason for revert: cannot be added: HAL "android.hardware.wifi" has a conflict. Change-Id: I33780dcca99015cb97b4f2240d1dfc6c3ebf9638 --- wifi/1.4/default/Android.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wifi/1.4/default/Android.mk b/wifi/1.4/default/Android.mk index 943beccc68..7ba5e36d9c 100644 --- a/wifi/1.4/default/Android.mk +++ b/wifi/1.4/default/Android.mk @@ -18,6 +18,7 @@ LOCAL_PATH := $(call my-dir) ### include $(CLEAR_VARS) LOCAL_MODULE := android.hardware.wifi@1.0-service-lib +LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_PROPRIETARY_MODULE := true LOCAL_CPPFLAGS := -Wall -Werror -Wextra @@ -77,7 +78,6 @@ include $(BUILD_STATIC_LIBRARY) ### include $(CLEAR_VARS) LOCAL_MODULE := android.hardware.wifi@1.0-service -LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_PROPRIETARY_MODULE := true LOCAL_CPPFLAGS := -Wall -Werror -Wextra @@ -107,7 +107,6 @@ include $(BUILD_EXECUTABLE) ### include $(CLEAR_VARS) LOCAL_MODULE := android.hardware.wifi@1.0-service-lazy -LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml LOCAL_OVERRIDES_MODULES := android.hardware.wifi@1.0-service LOCAL_CFLAGS := -DLAZY_SERVICE LOCAL_MODULE_RELATIVE_PATH := hw From e2f447ae08496ba763b16811ad2345d4a063a321 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Tue, 24 Sep 2019 15:33:43 +0000 Subject: [PATCH 0124/1022] Revert "Revert "Wifi: Move LOCAL_VINTF_FRAGMENTS to executables"" This reverts commit 1ab2fac7dee5f1bac811995bac1d1e5ecc6afc9f. Reason for revert: I fixed the cause for the build breakage, so no need to revert this change any more. Change-Id: I8c174116b3a9fcfbf4944b531f957a7ae72b4025 --- wifi/1.4/default/Android.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wifi/1.4/default/Android.mk b/wifi/1.4/default/Android.mk index 7ba5e36d9c..943beccc68 100644 --- a/wifi/1.4/default/Android.mk +++ b/wifi/1.4/default/Android.mk @@ -18,7 +18,6 @@ LOCAL_PATH := $(call my-dir) ### include $(CLEAR_VARS) LOCAL_MODULE := android.hardware.wifi@1.0-service-lib -LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_PROPRIETARY_MODULE := true LOCAL_CPPFLAGS := -Wall -Werror -Wextra @@ -78,6 +77,7 @@ include $(BUILD_STATIC_LIBRARY) ### include $(CLEAR_VARS) LOCAL_MODULE := android.hardware.wifi@1.0-service +LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_PROPRIETARY_MODULE := true LOCAL_CPPFLAGS := -Wall -Werror -Wextra @@ -107,6 +107,7 @@ include $(BUILD_EXECUTABLE) ### include $(CLEAR_VARS) LOCAL_MODULE := android.hardware.wifi@1.0-service-lazy +LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml LOCAL_OVERRIDES_MODULES := android.hardware.wifi@1.0-service LOCAL_CFLAGS := -DLAZY_SERVICE LOCAL_MODULE_RELATIVE_PATH := hw From 83e4370aec53f211c9078673c282737bfaad2c69 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Tue, 24 Sep 2019 10:16:08 -0700 Subject: [PATCH 0125/1022] MH2 | Implement injectSensorData method of HalProxy Bug: 136511617 Test: Compiles. No unit tests needed right now for such simple change. Change-Id: Iaaf74579c26393ef8854ae717f01bb7a451de496 --- sensors/2.0/multihal/HalProxy.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index 81d1b64af8..f051a11a2c 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -146,9 +146,20 @@ Return HalProxy::flush(int32_t sensorHandle) { return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle)); } -Return HalProxy::injectSensorData(const Event& /* event */) { - // TODO: Proxy API call to appropriate sub-HAL. - return Result::INVALID_OPERATION; +Return HalProxy::injectSensorData(const Event& event) { + Result result = Result::OK; + if (mCurrentOperationMode == OperationMode::NORMAL && + event.sensorType != V1_0::SensorType::ADDITIONAL_INFO) { + ALOGE("An event with type != ADDITIONAL_INFO passed to injectSensorData while operation" + " mode was NORMAL."); + result = Result::BAD_VALUE; + } + if (result == Result::OK) { + Event subHalEvent = event; + subHalEvent.sensorHandle = clearSubHalIndex(event.sensorHandle); + result = getSubHalForSensorHandle(event.sensorHandle)->injectSensorData(subHalEvent); + } + return result; } Return HalProxy::registerDirectChannel(const SharedMemInfo& /* mem */, From 0d5c8da3388df3d260a940534578eb3d664d0641 Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Mon, 16 Sep 2019 13:19:53 -0700 Subject: [PATCH 0126/1022] Add DVBC/DVBS/ISDBT/ISDBS/ISDBS3/ATSC3 support bug: 135708935 Test: Manual Change-Id: I667afbe8f4455ba1c70ae3113a2cd6819aa28156 --- tv/tuner/1.0/Android.bp | 1 + tv/tuner/1.0/IFrontend.hal | 95 +++ tv/tuner/1.0/IFrontendCallback.hal | 10 +- tv/tuner/1.0/ILnb.hal | 68 ++ tv/tuner/1.0/ITuner.hal | 48 +- tv/tuner/1.0/types.hal | 1042 +++++++++++++++++++++++++++- 6 files changed, 1232 insertions(+), 32 deletions(-) create mode 100644 tv/tuner/1.0/ILnb.hal diff --git a/tv/tuner/1.0/Android.bp b/tv/tuner/1.0/Android.bp index 986518b327..09265f7fce 100644 --- a/tv/tuner/1.0/Android.bp +++ b/tv/tuner/1.0/Android.bp @@ -13,6 +13,7 @@ hidl_interface { "IDescrambler.hal", "IFrontend.hal", "IFrontendCallback.hal", + "ILnb.hal", "ITuner.hal", ], interfaces: [ diff --git a/tv/tuner/1.0/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal index f7237bae73..8788643344 100644 --- a/tv/tuner/1.0/IFrontend.hal +++ b/tv/tuner/1.0/IFrontend.hal @@ -16,6 +16,7 @@ package android.hardware.tv.tuner@1.0; import IFrontendCallback; +import ILnb; /** * A Tuner Frontend is used to tune to a frequency and lock signal. @@ -81,4 +82,98 @@ interface IFrontend { * UNKNOWN_ERROR if failed for other reasons. */ close() generates (Result result); + + /** + * Scan the frontend to use the settings given. + * + * This uses the frontend to start a scan from signal delivery information. + * If previous scan isn't completed, this call MUST stop previous scan, + * and start a new scan. + * Scan is an async call, with FrontendScanMessage sent via callback. + * + * @param settings Signal delivery information which the frontend uses to + * scan the signal. + * @param type the type which the frontend uses to scan the signal. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if tuning can't be applied at current stage, + * UNKNOWN_ERROR if tuning failed for other reasons. + */ + scan(FrontendSettings settings, FrontendScanType type) generates (Result result); + + /** + * Stops a previous scanning. + * + * If the method completes successfully, the frontend stop previous + * scanning. + * + * @return result Result status of the operation. + * SUCCESS if successfully stop tuning. + * UNKNOWN_ERROR if failed for other reasons. + */ + stopScan() generates (Result result); + + /** + * Gets the statuses of the frontend. + * + * This retrieve the statuses of the frontend for given status types. + * + * @param statusTypes an array of status type which the caller request. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if tuning can't be applied at current stage, + * UNKNOWN_ERROR if tuning failed for other reasons. + * @return statuses an array of statuses which response the caller's + * request. + */ + getStatus(vec statusTypes) generates (Result result, vec statuses); + + /** + * Sets Low-Noise Block downconverter (LNB) for satellite frontend. + * + * This assigns a hardware LNB resource to the satellite frontend. It can be + * called multiple times to update LNB assignment. The LNB resource must be + * released when the frontend is closed. + * + * @param lnbId the Id of assigned LNB resource. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if the frontend can't be set with a LNB, such as + * cable frontend. + * UNKNOWN_ERROR if failed for other reasons. + */ + setLnb(ILnb lnb) generates (Result result); + + /** + * Enble or Disable Low Noise Amplifier (LNA). + * + * @param bEnable true if activate LNA module; false if deactivate LNA + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if the frontend doesn't support LNA. + * UNKNOWN_ERROR if failed for other reasons. + */ + setLna(bool bEnable) generates (Result result); + + /** + * Sends DiSEqC (Digital Satellite Equipment Control) message. + * + * Client sends DiSeqc message to DiSEqc compatible device through the + * frontend. The response message from the device comes back to the client + * through frontend's callback onDiseqcMessage. + * + * @param diseqcMessage a byte array of data for DiSEqC message which is + * specified by EUTELSAT Bus Functional Specification Version 4.2. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if the frontend can't send DiSEqc Message, such as + * cable frontend. + * UNKNOWN_ERROR if failed for other reasons. + */ + sendDiseqcMessage(vec diseqcMessage) generates (Result result); }; diff --git a/tv/tuner/1.0/IFrontendCallback.hal b/tv/tuner/1.0/IFrontendCallback.hal index e9070495c3..8896a09b62 100644 --- a/tv/tuner/1.0/IFrontendCallback.hal +++ b/tv/tuner/1.0/IFrontendCallback.hal @@ -33,5 +33,13 @@ interface IFrontendCallback { * Specification Version 4.2. */ oneway onDiseqcMessage(vec diseqcMessage); -}; + /** + * The callback function that must be called by HAL implementation to notify + * the client of scan messages. + * + * @param type the type of scan message. + * @param message the scan message sent by HAL to the client. + */ + oneway onScanMessage(FrontendScanMessageType type, FrontendScanMessage message); +}; diff --git a/tv/tuner/1.0/ILnb.hal b/tv/tuner/1.0/ILnb.hal new file mode 100644 index 0000000000..49fc3b44d8 --- /dev/null +++ b/tv/tuner/1.0/ILnb.hal @@ -0,0 +1,68 @@ +/* + * 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. + */ +package android.hardware.tv.tuner@1.0; + +/** + * A Tuner LNB (low-noise block downconverter) is used by satellite frontend + * to receive the microwave signal from the satellite, amplify it, and + * downconvert the frequency to a lower frequency. + */ +interface ILnb { + /** + * Set the lnb's power voltage. + * + * @param voltage the power's voltage the Lnb to use. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_ARGUMENT if the selected voltage isn't allowed, + * UNKNOWN_ERROR if failed for other reasons. + */ + setVoltage(FrontendLnbVoltage voltage) generates (Result result); + + /** + * Set the lnb's tone mode. + * + * @param tone the tone mode the Lnb to use. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_ARGUMENT if the selected tone mode isn't allowed, + * UNKNOWN_ERROR if failed for other reasons. + */ + setTone(FrontendLnbTone tone) generates (Result result); + + /** + * Select the lnb's position. + * + * @param position the position the Lnb to use. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_ARGUMENT if the selected position isn't allowed, + * UNKNOWN_ERROR if failed for other reasons. + */ + setSatellitePosition(FrontendLnbPosition position) generates (Result result); + + /** + * Releases the LNB instance + * + * Associated resources are released. close may be called more than once. + * Calls to any other method after this will return an error + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + */ + close() generates (Result result); +}; diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal index a0f3e8e7d1..f1a8617261 100644 --- a/tv/tuner/1.0/ITuner.hal +++ b/tv/tuner/1.0/ITuner.hal @@ -19,6 +19,7 @@ package android.hardware.tv.tuner@1.0; import IDemux; import IDescrambler; import IFrontend; +import ILnb; /** * Top level interface to manage Frontend, Demux and Decrambler hardware @@ -45,6 +46,7 @@ interface ITuner { * @param frontendId the id of the frontend to be opened. * @return result Result status of the operation. * SUCCESS if successful, + * UNAVAILABLE if no resource. * UNKNOWN_ERROR if creation failed for other reasons. * @return frontend the newly created frontend interface. */ @@ -62,7 +64,7 @@ interface ITuner { * @return demuxId newly created demux id. * @return demux the newly created demux interface. */ - openDemux() + openDemux() generates (Result result, DemuxId demuxId, IDemux demux); /** @@ -75,6 +77,48 @@ interface ITuner { * UNKNOWN_ERROR if creation failed for other reasons. * @return descrambler the newly created descrambler interface. */ - openDescrambler() + openDescrambler() generates (Result result, IDescrambler descrambler); + + /** + * Create a new instance of Descrambler. + * + * It is used by the client to create a Descrambler instance. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if creation failed for other reasons. + * @return descrambler the newly created descrambler interface. + */ + getFrontendInfo(FrontendId frontendId) + generates (Result result, FrontendInfo info); + + /** + * Get low-noise block downconverter (LNB) IDs. + * + * It is used by the client to get all available LNBs' IDs. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if tuning failed for other reasons. + * @return frontendIds an array of LnbId for the available LNBs. + */ + getLnbIds() generates (Result result, vec lnbIds); + + /** + * Create a new instance of Lnb given a lnbId. + * + * It is used by the client to create a Lnb instance for satellite Frontend. + * + * @param lnbId the id of the LNB to be opened. + * @return result Result status of the operation. + * SUCCESS if successful, + * UNAVAILABLE if no resource. + * UNKNOWN_ERROR if creation failed for other reasons. + * @return lnb the newly created Lnb interface. + */ + openLnbById(LnbId lnbId) + generates (Result result, ILnb lnb); + }; + diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index 77f7eadb79..d37f63a6ef 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -41,42 +41,121 @@ typedef uint32_t FrontendId; enum FrontendType : uint32_t { UNDEFINED = 0, ANALOG, + /* Advanced Television Systems Committee (ATSC) Standard A/72. */ ATSC, + /* Advanced Television Systems Committee (ATSC 3.0) Standard A/330. */ + ATSC3, + /** + * Digital Video Broadcasting - Cable + * DVB Cable Frontend Standard ETSI EN 300 468 V1.15.1. + */ DVBC, + /** + * Digital Video Broadcasting - Satellite + * DVB Satellite Frontend Standard ETSI EN 300 468 V1.15.1 and + * ETSI EN 302 307-2 V1.1.1. + */ DVBS, + /** + * Digital Video Broadcasting - Terrestrial + * DVB Terresttrial Frontend Standard ETSI EN 300 468 V1.15.1 and + * ETSI EN 302 755 V1.4.1. + */ DVBT, + /* Integrated Services Digital Broadcasting-Satellite (ISDB-S) + * ARIB SDT-B20 is technical document of ISDB-S. + */ + ISDBS, + /* Integrated Services Digital Broadcasting-Satellite (ISDB-S) + * ARIB TR-B15 is technical document of ISDB-S3. + */ + ISDBS3, + /* Integrated Services Digital Broadcasting-Terrestrial (ISDB-T or SBTVD) + * ABNT NBR 15603 is technical document of ISDB-T. + */ ISDBT, }; /** * Inner Forward Error Correction type as specified in ETSI EN 300 468 V1.15.1 - * It's a 4-bit field specifying the inner FEC scheme used according to the - * table 35 in the spec. + * and ETSI EN 302 307-2 V1.1.1. */ @export -enum FrontendInnerFec : uint32_t { +enum FrontendInnerFec : uint64_t { /* Not defined */ FEC_UNDEFINED = 0, - /* 1/2 conv. code rate */ - FEC_1_2 = 1 << 0, - /* 2/3 conv. code rate */ - FEC_2_3 = 1 << 1, - /* 3/4 conv. code rate */ - FEC_3_4 = 1 << 2, - /* 5/6 conv. code rate */ - FEC_5_6 = 1 << 3, - /* 7/8 conv. code rate */ - FEC_7_8 = 1 << 4, - /* 8/9 conv. code rate */ - FEC_8_9 = 1 << 5, - /* 3/5 conv. code rate */ - FEC_3_5 = 1 << 6, - /* 4/5 conv. code rate */ - FEC_4_5 = 1 << 7, - /* 9/10 conv. code rate */ - FEC_9_10 = 1 << 8, /* hardware is able to detect and set FEC automatically */ - FEC_AUTO = 1 << 9, + AUTO = 1 << 0, + /* 1/2 conv. code rate */ + FEC_1_2 = 1 << 1, + /* 1/3 conv. code rate */ + FEC_1_3 = 1 << 2, + /* 1/4 conv. code rate */ + FEC_1_4 = 1 << 3, + /* 1/5 conv. code rate */ + FEC_1_5 = 1 << 4, + /* 2/3 conv. code rate */ + FEC_2_3 = 1 << 5, + /* 2/5 conv. code rate */ + FEC_2_5 = 1 << 6, + /* 2/9 conv. code rate */ + FEC_2_9 = 1 << 7, + /* 3/4 conv. code rate */ + FEC_3_4 = 1 << 8, + /* 3/5 conv. code rate */ + FEC_3_5 = 1 << 9, + /* 4/5 conv. code rate */ + FEC_4_5 = 1 << 10, + /* 4/15 conv. code rate */ + FEC_4_15 = 1 << 11, + /* 5/6 conv. code rate */ + FEC_5_6 = 1 << 12, + /* 5/9 conv. code rate */ + FEC_5_9 = 1 << 13, + /* 6/7 conv. code rate */ + FEC_6_7 = 1 << 14, + /* 7/8 conv. code rate */ + FEC_7_8 = 1 << 15, + /* 7/9 conv. code rate */ + FEC_7_9 = 1 << 16, + /* 7/15 conv. code rate */ + FEC_7_15 = 1 << 17, + /* 8/9 conv. code rate */ + FEC_8_9 = 1 << 18, + /* 8/15 conv. code rate */ + FEC_8_15 = 1 << 19, + /* 9/10 conv. code rate */ + FEC_9_10 = 1 << 20, + /* 9/20 conv. code rate */ + FEC_9_20 = 1 << 21, + /* 11/15 conv. code rate */ + FEC_11_15 = 1 << 22, + /* 11/20 conv. code rate */ + FEC_11_20 = 1 << 23, + /* 11/45 conv. code rate */ + FEC_11_45 = 1 << 24, + /* 13/18 conv. code rate */ + FEC_13_18 = 1 << 25, + /* 13/45 conv. code rate */ + FEC_13_45 = 1 << 26, + /* 14/45 conv. code rate */ + FEC_14_45 = 1 << 27, + /* 23/36 conv. code rate */ + FEC_23_36 = 1 << 28, + /* 25/36 conv. code rate */ + FEC_25_36 = 1 << 29, + /* 26/45 conv. code rate */ + FEC_26_45 = 1 << 30, + /* 28/45 conv. code rate */ + FEC_28_45 = 1 << 31, + /* 29/45 conv. code rate */ + FEC_29_45 = 1 << 32, + /* 31/45 conv. code rate */ + FEC_31_45 = 1 << 33, + /* 32/45 conv. code rate */ + FEC_32_45 = 1 << 34, + /* 77/90 conv. code rate */ + FEC_77_90 = 1 << 35, }; /** @@ -98,22 +177,761 @@ struct FrontendAtscSettings { FrontendAtscModulation modulation; }; +/** + * Capabilities for ATSC Frontend. + */ +struct FrontendAtscCapabilities { + /** Modulation capability */ + bitfield modulationCap; +}; + +/** + * Modulation Type for ATSC3. + */ +@export +enum FrontendAtsc3Modulation : uint32_t { + UNDEFINED = 0, + MOD_QPSK = 1 << 0, + MOD_16QAM = 1 << 1, + MOD_64QAM = 1 << 2, + MOD_256QAM = 1 << 3, + MOD_1024QAM = 1 << 4, + MOD_4096QAM = 1 << 5, +}; + +/** + * Bandwidth for ATSC3. + */ +@export +enum FrontendAtsc3Bandwidth : uint32_t { + UNDEFINED = 0, + BANDWIDTH_8MHZ = 1 << 0, + BANDWIDTH_7MHZ = 1 << 1, + BANDWIDTH_6MHZ = 1 << 2, +}; + +/** + * Time Interleave Mode for ATSC3. + */ +@export +enum FrontendAtsc3TimeInterleaveMode : uint32_t { + UNDEFINED, + CTI, + HTI, +}; + +/** + * Code Rate for ATSC3. + */ +@export +enum FrontendAtsc3CodeRate : uint32_t { + UNDEFINED = 0, + /** hardware is able to detect and set Coderate automatically */ + AUTO = 1 << 0, + CODERATE_2_15 = 1 << 1, + CODERATE_3_15 = 1 << 2, + CODERATE_4_15 = 1 << 3, + CODERATE_5_15 = 1 << 4, + CODERATE_6_15 = 1 << 5, + CODERATE_7_15 = 1 << 6, + CODERATE_8_15 = 1 << 7, + CODERATE_9_15 = 1 << 8, + CODERATE_10_15 = 1 << 9, + CODERATE_11_15 = 1 << 10, + CODERATE_12_15 = 1 << 11, + CODERATE_13_15 = 1 << 12, +}; + +/** + * Forward Error Correction (FEC) for ATSC3. + */ +@export +enum FrontendAtsc3Fec : uint32_t { + UNDEFINED, + BCH_LDPC_16K, + BCH_LDPC_64K, + CRC_LDPC_16K, + CRC_LDPC_64K, + LDPC_16K, + LDPC_64K, +}; + +/** + * Signal Settings for an ATSC3 Frontend. + */ +struct FrontendAtsc3Settings { + /** Signal frequency in Hertz */ + uint32_t frequency; + FrontendAtsc3Bandwidth bandwidth; + FrontendAtsc3TimeInterleaveMode interleaveMode; + FrontendAtsc3CodeRate codeRate; + FrontendAtsc3Fec fec; + vec plpIdList; +}; + +/** + * Capabilities for ATSC3 Frontend. + */ +struct FrontendAtsc3Capabilities { + /** Modulation capability */ + bitfield modulationCap; + /** Bandwidth capability */ + bitfield bandwidthCap; +}; + +/** + * Modulation Type for DVBS. + */ +@export +enum FrontendDvbsModulation : int32_t { + UNDEFINED = 0, + /** hardware is able to detect and set Modulation automatically */ + AUTO = 1 << 0, + MOD_QPSK = 1 << 1, + MOD_8PSK = 1 << 2, + MOD_16QAM = 1 << 3, + MOD_16PSK = 1 << 4, + MOD_32PSK = 1 << 5, + MOD_ACM = 1 << 6, + MOD_8APSK = 1 << 7, + MOD_16APSK = 1 << 8, + MOD_32APSK = 1 << 9, + MOD_64APSK = 1 << 10, + MOD_128APSK = 1 << 11, + MOD_256APSK = 1 << 12, + /** Reserved for Proprietary modulation */ + MOD_RESERVED = 1 << 13, +}; + +/** + * Roll Off value for DVBS. + */ +@export +enum FrontendDvbsRolloff : uint32_t { + UNDEFINED, + ROLLOFF_0_35, + ROLLOFF_0_25, + ROLLOFF_0_20, + ROLLOFF_0_15, + ROLLOFF_0_10, + ROLLOFF_0_5, +}; + +/** + * Pilot mode for DVBS. + */ +@export +enum FrontendDvbsPilot : uint32_t { + UNDEFINED, + ON, + OFF, + AUTO, +}; + +/** + * Code Rate for DVBS. + */ +struct FrontendDvbsCodeRate { + FrontendInnerFec fec; + bool isLinear; + /* true if enable short frame */ + bool isShortFrames; + /* bits number in 1000 symbol. 0 if use the default. */ + uint32_t bitsPer1000Symbol; +}; + +/** + * Sub standards in DVBS. + */ +@export +enum FrontendDvbsStandard : uint8_t { + AUTO = 1 << 0, + S = 1 << 1, + S2 = 1 << 2, + S2X = 1 << 3, +}; + +/** + * Signal Settings for an DVBS Frontend. + */ +struct FrontendDvbsSettings { + /** Signal frequency in Hertz */ + uint32_t frequency; + FrontendDvbsModulation modulation; + FrontendDvbsCodeRate coderate; + /** Symbols per second */ + uint32_t symbolRate; + FrontendDvbsRolloff rolloff; + FrontendDvbsPilot pilot; + uint32_t inputStreamId; + FrontendDvbsStandard standard; +}; + +/** + * Capabilities for DVBS Frontend. + */ +struct FrontendDvbsCapabilities { + bitfield modulationCap; + bitfield innerfecCap; + bitfield standard; +}; + +/** + * Modulation Type for DVBC. + */ +@export +enum FrontendDvbcModulation : uint32_t { + UNDEFINED = 0, + /** hardware is able to detect and set Modulation automatically */ + AUTO = 1 << 0, + MOD_16QAM = 1 << 1, + MOD_32QAM = 1 << 2, + MOD_64QAM = 1 << 3, + MOD_128QAM = 1 << 4, + MOD_256QAM = 1 << 5, +}; + +/** + * Outer Forward Error Correction (FEC) Type for DVBC. + */ +@export +enum FrontendDvbcOuterFec : uint32_t { + UNDEFINED = 0, + OUTER_FEC_NONE, + OUTER_FEC_RS, +}; + +/** + * Annex Type for DVBC. + */ +@export +enum FrontendDvbcAnnex : uint8_t { + UNDEFINED = 0, + A = 1 << 0, + B = 1 << 1, + C = 1 << 2, +}; + +/** + * Spectral Inversion Type for DVBC. + */ +@export +enum FrontendDvbcSpectralInversion : uint32_t { + UNDEFINED, + NORMAL, + INVERTED, +}; + +/** + * Signal Settings for an DVBC Frontend. + */ +struct FrontendDvbcSettings { + /** Signal frequency in Hertz */ + uint32_t frequency; + FrontendDvbcModulation modulation; + FrontendInnerFec fec; + /** Symbols per second */ + uint32_t symbolRate; + FrontendDvbcOuterFec outerFec; + FrontendDvbcAnnex annex; + FrontendDvbcSpectralInversion spectralInversion; +}; + +/** + * Capabilities for DVBC Frontend. + */ +struct FrontendDvbcCapabilities { + bitfield modulationCap; + bitfield fecCap; + bitfield annexCap; +}; + +/** + * Bandwidth Type for DVBT. + */ +@export +enum FrontendDvbtBandwidth : uint32_t { + UNDEFINED = 0, + /** hardware is able to detect and set Bandwidth automatically */ + AUTO = 1 << 0, + BANDWIDTH_8MHZ = 1 << 1, + BANDWIDTH_7MHZ = 1 << 2, + BANDWIDTH_6MHZ = 1 << 3, + BANDWIDTH_5MHZ = 1 << 4, + BANDWIDTH_1_7MHZ = 1 << 5, + BANDWIDTH_10MHZ = 1 << 6, +}; + +/** + * Constellation Type for DVBT. + */ +@export +enum FrontendDvbtConstellation : uint32_t { + UNDEFINED = 0, + /** hardware is able to detect and set Constellation automatically */ + AUTO = 1 << 0, + CONSTELLATION_QPSK = 1 << 1, + CONSTELLATION_16QAM = 1 << 2, + CONSTELLATION_64QAM = 1 << 3, + CONSTELLATION_256QAM = 1 << 4, +}; + +/** + * Hierarchy Type for DVBT. + */ +@export +enum FrontendDvbtHierarchy : uint32_t { + UNDEFINED = 0, + /** hardware is able to detect and set Hierarchy automatically */ + AUTO = 1 << 0, + HIERARCHY_NON_NATIVE = 1 << 1, + HIERARCHY_1_NATIVE = 1 << 2, + HIERARCHY_2_NATIVE = 1 << 3, + HIERARCHY_4_NATIVE = 1 << 4, + HIERARCHY_NON_INDEPTH = 1 << 5, + HIERARCHY_1_INDEPTH = 1 << 6, + HIERARCHY_2_INDEPTH = 1 << 7, + HIERARCHY_4_INDEPTH = 1 << 8, +}; + +/** + * Hierarchy Type for DVBT. + */ +@export +enum FrontendDvbtCoderate : uint32_t { + UNDEFINED = 0, + /** hardware is able to detect and set Hierarchy automatically */ + AUTO = 1 << 0, + CODERATE_1_2 = 1 << 1, + CODERATE_2_3 = 1 << 2, + CODERATE_3_4 = 1 << 3, + CODERATE_5_6 = 1 << 4, + CODERATE_7_8 = 1 << 5, + CODERATE_3_5 = 1 << 6, + CODERATE_4_5 = 1 << 7, + CODERATE_6_7 = 1 << 8, + CODERATE_8_9 = 1 << 9, +}; + +/** + * Guard Interval Type for DVBT. + */ +@export +enum FrontendDvbtGuardInterval : uint32_t { + UNDEFINED = 0, + /** hardware is able to detect and set Guard Interval automatically */ + AUTO = 1 << 0, + INTERVAL_1_32 = 1 << 1, + INTERVAL_1_16 = 1 << 2, + INTERVAL_1_8 = 1 << 3, + INTERVAL_1_4 = 1 << 4, + INTERVAL_1_128 = 1 << 5, + INTERVAL_19_128 = 1 << 6, + INTERVAL_19_256 = 1 << 7, +}; + +/** + * Transmission Mode for DVBT. + */ +@export +enum FrontendDvbtTransmissionMode : uint32_t { + UNDEFINED = 0, + /** hardware is able to detect and set Transmission Mode automatically */ + AUTO = 1 << 0, + MODE_2K = 1 << 1, + MODE_8K = 1 << 2, + MODE_4K = 1 << 3, + MODE_1K = 1 << 4, + MODE_16K = 1 << 5, + MODE_32K = 1 << 6, +}; + +/** + * Physical Layer Pipe (PLP) Mode for DVBT. + */ +enum FrontendDvbtPlpMode : uint32_t { + UNDEFINED, + AUTO, + MANUAL, +}; + +/** + * Sub standards in DVBT. + */ +@export +enum FrontendDvbtStandard : uint8_t { + AUTO = 1 << 0, + T = 1 << 1, + T2 = 1 << 2, +}; + /** * Signal Setting for DVBT Frontend. */ struct FrontendDvbtSettings { /** Signal frequency in Hertz */ uint32_t frequency; - FrontendAtscModulation modulation; - FrontendInnerFec fec; + FrontendDvbtTransmissionMode transmissionMode; + FrontendDvbtBandwidth bandwidth; + FrontendDvbtConstellation constellation; + FrontendDvbtHierarchy hierarchy; + /** Code Rate for High Priority level */ + FrontendDvbtCoderate hpCoderate; + /** Code Rate for Low Priority level */ + FrontendDvbtCoderate lpCoderate; + FrontendDvbtGuardInterval guardInterval; + bool isHighPriority; + FrontendDvbtStandard standard; + bool isMiso; + FrontendDvbtPlpMode plpMode; + /** Physical Layer Pipe (PLP) Id */ + uint8_t plpId; + /** Group Id for Physical Layer Pipe (PLP) */ + uint8_t plpGroupId; }; /** - * Modulation Type for ATSC. + * Capabilities for DVBT Frontend. + */ +struct FrontendDvbtCapabilities { + bitfield transmissionModeCap; + bitfield bandwidthCap; + bitfield constellationCap; + bitfield coderateCap; + bitfield hierarchyCap; + bitfield guardIntervalCap; + bool isT2Supported; + bool isMisoSupported; +}; + +/** + * Roll Off Type for ISDBS. + */ +@export +enum FrontendIsdbsRolloff : uint32_t { + UNDEFINED, + ROLLOFF_0_35, +}; + +/** + * Modulaltion Type for ISDBS. + */ +@export +enum FrontendIsdbsModulation : uint32_t { + UNDEFINED = 0, + /** hardware is able to detect and set Modulation automatically */ + AUTO = 1 << 0, + MOD_BPSK = 1 << 1, + MOD_QPSK = 1 << 2, + MOD_TC8PSK = 1 << 3, +}; + +/** + * Code Rate Type for ISDBS. + */ +@export +enum FrontendIsdbsCoderate : uint32_t { + UNDEFINED = 0, + /** hardware is able to detect and set Code Rate automatically */ + AUTO = 1 << 0, + CODERATE_1_2 = 1 << 1, + CODERATE_2_3 = 1 << 2, + CODERATE_3_4 = 1 << 3, + CODERATE_5_6 = 1 << 4, + CODERATE_7_8 = 1 << 5, +}; + +/** + * Stream Id Type for ISDBS. + */ +@export +enum FrontendIsdbsStreamIdType : uint32_t { + STREAM_ID, + RELATIVE_STREAM_ID, +}; + +/** + * Signal Setting for ISDBS Frontend. + */ +struct FrontendIsdbsSettings { + /** Signal frequency in Hertz */ + uint32_t frequency; + uint16_t streamId; + FrontendIsdbsStreamIdType streamIdType; + FrontendIsdbsModulation modulation; + FrontendIsdbsCoderate coderate; + /** Symbols per second */ + uint32_t symbolRate; + FrontendIsdbsRolloff rolloff; +}; + +/** + * Capabilities for ISDBS Frontend. + */ +struct FrontendIsdbsCapabilities { + bitfield modulationCap; + bitfield coderateCap; +}; + +/** + * Roll of Type for ISDBS3. + */ +@export +enum FrontendIsdbs3Rolloff : uint32_t { + UNDEFINED, + ROLLOFF_0_03, +}; + +/** + * Modulaltion Type for ISDBS3. + */ +@export +enum FrontendIsdbs3Modulation : uint32_t { + UNDEFINED = 0, + /** hardware is able to detect and set Modulation automatically */ + AUTO = 1 << 5, + MOD_BPSK = 1 << 1, + MOD_QPSK = 1 << 2, + MOD_8PSK = 1 << 3, + MOD_16APSK = 1 << 4, + MOD_32APSK = 1 << 5, +}; + +/** + * Code Rate Type for ISDBS3. + */ +@export +enum FrontendIsdbs3Coderate : uint32_t { + UNDEFINED = 0, + /** hardware is able to detect and set Code Rate automatically */ + AUTO = 1 << 0, + CODERATE_1_3 = 1 << 1, + CODERATE_2_5 = 1 << 2, + CODERATE_1_2 = 1 << 3, + CODERATE_3_5 = 1 << 4, + CODERATE_2_3 = 1 << 5, + CODERATE_3_4 = 1 << 6, + CODERATE_7_9 = 1 << 7, + CODERATE_4_5 = 1 << 8, + CODERATE_5_6 = 1 << 9, + CODERATE_7_8 = 1 << 10, + CODERATE_9_10 = 1 << 11, +}; + +/** + * Signal Setting for ISDBS3 Frontend. + */ +struct FrontendIsdbs3Settings { + /** Signal frequency in Hertz */ + uint32_t frequency; + uint16_t streamId; + FrontendIsdbsStreamIdType streamIdType; + FrontendIsdbs3Modulation modulation; + FrontendIsdbs3Coderate coderate; + /** Symbols per second */ + uint32_t symbolRate; + FrontendIsdbs3Rolloff rolloff; +}; + +/** + * Capabilities for ISDBS3 Frontend. + */ +struct FrontendIsdbs3Capabilities { + bitfield modulationCap; + bitfield coderateCap; +}; + +/** + * Mode for ISDBT. + */ +@export +enum FrontendIsdbtMode : uint32_t { + UNDEFINED = 0, + /** hardware is able to detect and set Mode automatically */ + AUTO = 1 << 0, + MODE_1 = 1 << 1, + MODE_2 = 1 << 2, + MODE_3 = 1 << 3, +}; + +/** + * Bandwidth for ISDBT. + */ +@export +enum FrontendIsdbtBandwidth : uint32_t { + UNDEFINED = 0, + /** hardware is able to detect and set Bandwidth automatically */ + AUTO = 1 << 0, + BANDWIDTH_8MHZ = 1 << 1, + BANDWIDTH_7MHZ = 1 << 2, + BANDWIDTH_6MHZ = 1 << 3, +}; + +/** + * Modulation for ISDBT. + */ +@export +enum FrontendIsdbtModulation : uint32_t { + UNDEFINED = 0, + /** hardware is able to detect and set Modulation automatically */ + AUTO = 1 << 0, + MOD_DQPSK = 1 << 1, + MOD_QPSK = 1 << 2, + MOD_16QAM = 1 << 3, + MOD_64QAM = 1 << 4, +}; + +/** Code Rate for ISDBT. */ +typedef FrontendDvbtCoderate FrontendIsdbtCoderate; + +/** Guard Interval for ISDBT. */ +typedef FrontendDvbtGuardInterval FrontendIsdbtGuardInterval; + +/** + * Signal Setting for ISDBT Frontend. + */ +struct FrontendIsdbtSettings { + /** Signal frequency in Hertz */ + uint32_t frequency; + FrontendIsdbtModulation modulation; + FrontendIsdbtBandwidth bandwidth; + FrontendIsdbtMode mode; + FrontendIsdbtCoderate coderate; + FrontendIsdbtGuardInterval guardInterval; + uint32_t serviceAreaId; +}; + +/** + * Capabilities for ISDBT Frontend. + */ +struct FrontendIsdbtCapabilities { + bitfield modeCap; + bitfield bandwidthCap; + bitfield constellationCap; + bitfield coderateCap; + bitfield guardIntervalCap; +}; + +/** + * Signal Type for Analog Frontend. + */ +@export +enum FrontendAnalogType : uint32_t { + UNDEFINED = 0, + PAL = 1 << 0, + SECAM = 1 << 1, + NTSC = 1 << 2, +}; + +/** + * Standard Interchange Format (SIF) for Analog Frontend. + */ +@export +enum FrontendAnalogSifStandard : uint32_t { + UNDEFINED = 0, + BG = 1 << 0, + BG_A2 = 1 << 1, + BG_NICAM = 1 << 2, + I = 1 << 3, + DK = 1 << 4, + DK1 = 1 << 5, + DK2 = 1 << 6, + DK3 = 1 << 7, + DK_NICAM = 1 << 8, + L = 1 << 9, + M = 1 << 10, + M_BTSC = 1 << 11, + M_A2 = 1 << 12, + M_EIA_J = 1 << 13, + I_NICAM = 1 << 14, + L_NICAM = 1 << 15, +}; + +/** + * Signal Setting for Analog Frontend. + */ +struct FrontendAnalogSettings { + /** Signal frequency in Hertz */ + uint32_t frequency; + FrontendAnalogType type; + FrontendAnalogSifStandard sifStandard; +}; + +/** + * Capabilities for Analog Frontend. + */ +struct FrontendAnalogCapabilities { + bitfield typeCap; + bitfield sifStandardCap; +}; + +/** + * Signal Setting for Frontend. */ safe_union FrontendSettings { + FrontendAnalogSettings analog; FrontendAtscSettings atsc; + FrontendAtsc3Settings atsc3; + FrontendDvbsSettings dvbs; + FrontendDvbcSettings dvbc; FrontendDvbtSettings dvbt; + FrontendIsdbsSettings isdbs; + FrontendIsdbs3Settings isdbs3; + FrontendIsdbtSettings isdbt; +}; + +/** + * Scan type for Frontend. + */ +enum FrontendScanType : uint32_t { + SCAN_UNDEFINED = 0, + SCAN_AUTO = 1 << 0, + SCAN_BLIND = 1 << 1, +}; + +/** + * Scan Message Type for Frontend. + */ +enum FrontendScanMessageType : uint32_t { + /** Scan locked the signal. */ + LOCKED, + /** Scan stopped. */ + END, + /** Scan progress report. */ + PROGRESS_PERCENT, + /** Locked frequency report. */ + FREQUENCY, + /** Locked symbol rate. */ + SYMBOL_RATE, + /** Locked Plp Ids for DVBT2 frontend. */ + PLP_IDS, + /** Locked group Ids for DVBT2 frontend. */ + GROUP_IDS, + /** Locked the number of the Plps. */ + INPUT_STREAM_IDS, + /** Locked signal stardard. */ + STANDARD, +}; + +/** + * Scan Message for Frontend. + */ +safe_union FrontendScanMessage { + bool islocked; + bool isEnd; + /** scan progress percent (0..100) */ + uint8_t progressPercent; + /** Signal frequency in Hertz */ + uint32_t frequency; + /** Symbols per second */ + uint32_t symbolRate; + vec plpIds; + vec groupIds; + vec inputStreamIds; + safe_union standard { + FrontendDvbsStandard sStd; + FrontendDvbtStandard tStd; + } std; }; /** @@ -136,8 +954,174 @@ enum FrontendEventType : uint32_t { * event. */ LOST_LOCK, + /** + * If frontend detect that incoming Diseqc message is overflow. + */ + DISEQC_RX_OVERFLOW, + /** + * If frontend detect that outgoing Diseqc message isn't delivered on time. + */ + DISEQC_RX_TIMEOUT, + /** + * If frontend detect that the incoming Diseqc message has parity error. + */ + DISEQC_RX_PARITY_ERROR, + /** + * If frontend detect that the LNB is overload. + */ + LNB_OVERLOAD, }; +/** + * Frontend Status Type. + */ +@export +enum FrontendStatusType : uint32_t { + /** Lock status for RF or Demod. */ + LOCK, + /** Signal to Noise Ratio. */ + SNR, + /** Bit Error Ratio. */ + BER, + /** Packages Error Ratio. */ + PER, + /** Bit Error Ratio befor FEC. */ + PRE_BER, + /* + * Signal Quality (0..100). Good data over total data in percent can be + * used as a way to present Signal Quality. + */ + SIGNAL_QUALITY, + /** Signal Strength. */ + SIGGAL_STRENGTH, + /** Symbol Rate. */ + SYMBOL_RATE, + /** Forward Error Correction Type. */ + FEC, + /** Modulation Type. */ + MODULATION, + /** Spectral Inversion Type. */ + SPECTRAL, + /** LNB Voltage. */ + LNB_VOLTAGE, + /** Physical Layer Pipe ID. */ + PLP_ID, + /** Status for Emergency Warning Broadcasting System. */ + EWBS, +}; + +/** + * Modulation Type for Frontend's status. + */ +safe_union FrontendModulationStatus { + FrontendDvbsModulation dvbs; + FrontendAtsc3Modulation atsc3; +}; + +/** + * The status for Frontend. + */ +safe_union FrontendStatus { + bool isLocked; + /** SNR value measured by 0.001 dB. */ + int32_t snr; + /** The number of error bit per 1 billion bits. */ + uint32_t ber; + /** The number of error package per 1 billion packages. */ + uint32_t per; + /** The number of error bit per 1 billion bits before FEC. */ + uint32_t preBer; + /** Signal Quality in percent. */ + uint32_t signalQuality; + /** Signal Strength measured by 0.001 dBm. */ + int32_t signalStrength; + /** Symbols per second */ + uint32_t symbolRate; + FrontendInnerFec innerFec; + FrontendModulationStatus modulation; + FrontendDvbcSpectralInversion inversion; + FrontendLnbVoltage lnbVoltage; + uint8_t plpId; + bool isEWBS; +}; + +/** + * Information for the Frontend. + */ +struct FrontendInfo { + FrontendType type; + /** Frequency in Hertz */ + uint32_t minFrequency; + /** Frequency in Hertz */ + uint32_t maxFrequency; + /** Minimum symbols per second */ + uint32_t minSymbolRate; + /** Maximum symbols per second */ + uint32_t maxSymbolRate; + /** Range in Hertz */ + uint32_t acquireRange; + /* + * Frontends are assigned with the same exclusiveGroupId if they can't + * function at same time. For instance, they share same hardware module. + */ + uint32_t exclusiveGroupId; + /** A list of supported status types which client can inquiry */ + vec statusCaps; + safe_union FrontendCapabilities { + FrontendAnalogCapabilities analogCaps; + FrontendAtscCapabilities atscCaps; + FrontendAtsc3Capabilities atsc3Caps; + FrontendDvbsCapabilities dvbsCaps; + FrontendDvbcCapabilities dvbcCaps; + FrontendDvbtCapabilities dvbtCaps; + FrontendIsdbsCapabilities isdbsCaps; + FrontendIsdbs3Capabilities isdbs3Caps; + FrontendIsdbtCapabilities isdbtCaps; + } frontendCaps; +}; + +/* + * Low-Noise Block downconverter (LNB) ID is used to associate with a hardware + * LNB module. + */ +typedef uint32_t LnbId; + +/** + * Power Voltage Type for LNB. + */ +@export +enum FrontendLnbVoltage : uint32_t { + NONE, + VOLTAGE_5V, + VOLTAGE_11V, + VOLTAGE_12V, + VOLTAGE_13V, + VOLTAGE_14V, + VOLTAGE_15V, + VOLTAGE_18V, + VOLTAGE_19V, +}; + +/** + * Tone Type for LNB. + */ +@export +enum FrontendLnbTone : int32_t { + NONE, + CONTINUOUS, +}; + +/** + * The Position of LNB. + */ +@export +enum FrontendLnbPosition : int32_t { + UNDEFINED, + POSITION_A, + POSITION_B, +}; + + /* Demux ID is used to associate with a hardware demux resource. */ typedef uint32_t DemuxId; @@ -248,7 +1232,7 @@ struct DemuxFilterSectionSettings { /* Version number for Section Filter */ uint16_t version; /* true if the filter checks CRC and discards data with wrong CRC */ - bool checkCrc; + bool isCheckCrc; /* true if the filter repeats the data with the same version */ bool isRepeat; /* true if the filter output raw data */ @@ -265,7 +1249,7 @@ struct DemuxFilterPesDataSettings { DemuxTpid tpid; DemuxStreamId streamId; /* true if the filter output raw data */ - bool bIsRaw; + bool isRaw; }; /** @@ -283,7 +1267,7 @@ struct DemuxFilterAudioSettings { /** * true if the filter output goes to decoder directly in pass through mode. */ - bool bPassthrough; + bool isPassthrough; }; /** @@ -294,7 +1278,7 @@ struct DemuxFilterVideoSettings { /** * true if the filter output goes to decoder directly in pass through mode. */ - bool bPassthrough; + bool isPassthrough; }; /** From 016b73119c3ad04e39f57e44af7b3b6033609815 Mon Sep 17 00:00:00 2001 From: Amy Date: Mon, 16 Sep 2019 15:51:28 -0700 Subject: [PATCH 0127/1022] Add DVBC/DVBS/ISDBT/ISDBS/ISDBS3/ATSC3 support default implementation Test: manual Bug: 135709325 Change-Id: I846c8d1f50ad636e9718cf792a29c8b076246c54 --- tv/tuner/1.0/default/Android.bp | 1 + tv/tuner/1.0/default/Frontend.cpp | 40 ++++++++++++++++++++ tv/tuner/1.0/default/Frontend.h | 14 +++++++ tv/tuner/1.0/default/Lnb.cpp | 62 +++++++++++++++++++++++++++++++ tv/tuner/1.0/default/Lnb.h | 60 ++++++++++++++++++++++++++++++ tv/tuner/1.0/default/Tuner.cpp | 28 ++++++++++++++ tv/tuner/1.0/default/Tuner.h | 7 ++++ 7 files changed, 212 insertions(+) create mode 100644 tv/tuner/1.0/default/Lnb.cpp create mode 100644 tv/tuner/1.0/default/Lnb.h diff --git a/tv/tuner/1.0/default/Android.bp b/tv/tuner/1.0/default/Android.bp index b211dd249f..0ae8bcdac8 100644 --- a/tv/tuner/1.0/default/Android.bp +++ b/tv/tuner/1.0/default/Android.bp @@ -8,6 +8,7 @@ cc_defaults { "Descrambler.cpp", "Demux.cpp", "Tuner.cpp", + "Lnb.cpp", "service.cpp", ], diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp index 3dcc2b1ebd..0609d05121 100644 --- a/tv/tuner/1.0/default/Frontend.cpp +++ b/tv/tuner/1.0/default/Frontend.cpp @@ -77,6 +77,46 @@ Return Frontend::stopTune() { return Result::SUCCESS; } +Return Frontend::scan(const FrontendSettings& /* settings */, FrontendScanType /* type */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Frontend::stopScan() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Frontend::getStatus(const hidl_vec& /* statusTypes */, + getStatus_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + vector statuses; + _hidl_cb(Result::SUCCESS, statuses); + + return Void(); +} + +Return Frontend::setLna(bool /* bEnable */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Frontend::setLnb(const sp& /* lnb */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Frontend::sendDiseqcMessage(const hidl_vec& /* diseqcMessage */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + FrontendType Frontend::getFrontendType() { return mType; } diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h index f77a0d8894..fc586b5174 100644 --- a/tv/tuner/1.0/default/Frontend.h +++ b/tv/tuner/1.0/default/Frontend.h @@ -38,6 +38,7 @@ using ::android::hardware::tv::tuner::V1_0::Result; class Frontend : public IFrontend { public: Frontend(); + Frontend(FrontendType type, FrontendId id); virtual Return close() override; @@ -48,6 +49,19 @@ class Frontend : public IFrontend { virtual Return stopTune() override; + virtual Return scan(const FrontendSettings& settings, FrontendScanType type) override; + + virtual Return stopScan() override; + + virtual Return getStatus(const hidl_vec& statusTypes, + getStatus_cb _hidl_cb) override; + + virtual Return sendDiseqcMessage(const hidl_vec& diseqcMessage) override; + + virtual Return setLna(bool bEnable) override; + + virtual Return setLnb(const sp& lnb) override; + FrontendType getFrontendType(); FrontendId getFrontendId(); diff --git a/tv/tuner/1.0/default/Lnb.cpp b/tv/tuner/1.0/default/Lnb.cpp new file mode 100644 index 0000000000..b81bb1508b --- /dev/null +++ b/tv/tuner/1.0/default/Lnb.cpp @@ -0,0 +1,62 @@ +/* + * 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 "android.hardware.tv.tuner@1.0-Lnb" + +#include "Lnb.h" +#include + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +Lnb::Lnb() {} + +Lnb::~Lnb() {} + +Return Lnb::setVoltage(FrontendLnbVoltage /* voltage */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Lnb::setTone(FrontendLnbTone /* tone */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Lnb::setSatellitePosition(FrontendLnbPosition /* position */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Lnb::close() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/tv/tuner/1.0/default/Lnb.h b/tv/tuner/1.0/default/Lnb.h new file mode 100644 index 0000000000..df7e0fe2b3 --- /dev/null +++ b/tv/tuner/1.0/default/Lnb.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_LNB_H_ +#define ANDROID_HARDWARE_TV_TUNER_V1_0_LNB_H_ + +#include +#include + +using namespace std; + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::tv::tuner::V1_0::FrontendLnbPosition; +using ::android::hardware::tv::tuner::V1_0::FrontendLnbTone; +using ::android::hardware::tv::tuner::V1_0::FrontendLnbVoltage; +using ::android::hardware::tv::tuner::V1_0::Result; + +class Lnb : public ILnb { + public: + Lnb(); + + virtual Return setVoltage(FrontendLnbVoltage voltage); + + virtual Return setTone(FrontendLnbTone tone) override; + + virtual Return setSatellitePosition(FrontendLnbPosition position) override; + + virtual Return close() override; + + private: + virtual ~Lnb(); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_LNB_H_ \ No newline at end of file diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp index 68b34368ee..00831aea30 100644 --- a/tv/tuner/1.0/default/Tuner.cpp +++ b/tv/tuner/1.0/default/Tuner.cpp @@ -22,6 +22,7 @@ #include "Demux.h" #include "Descrambler.h" #include "Frontend.h" +#include "Lnb.h" namespace android { namespace hardware { @@ -95,6 +96,33 @@ Return Tuner::openDescrambler(openDescrambler_cb _hidl_cb) { return Void(); } +Return Tuner::getFrontendInfo(FrontendId /* frontendId */, getFrontendInfo_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + FrontendInfo info; + + _hidl_cb(Result::SUCCESS, info); + return Void(); +} + +Return Tuner::getLnbIds(getLnbIds_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + vector lnbIds; + + _hidl_cb(Result::SUCCESS, lnbIds); + return Void(); +} + +Return Tuner::openLnbById(LnbId /* lnbId */, openLnbById_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + sp lnb = new Lnb(); + + _hidl_cb(Result::SUCCESS, lnb); + return Void(); +} + } // namespace implementation } // namespace V1_0 } // namespace tuner diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h index 12e959406a..62227eefcd 100644 --- a/tv/tuner/1.0/default/Tuner.h +++ b/tv/tuner/1.0/default/Tuner.h @@ -41,6 +41,13 @@ class Tuner : public ITuner { virtual Return openDescrambler(openDescrambler_cb _hidl_cb) override; + virtual Return getFrontendInfo(FrontendId frontendId, + getFrontendInfo_cb _hidl_cb) override; + + virtual Return getLnbIds(getLnbIds_cb _hidl_cb) override; + + virtual Return openLnbById(LnbId lnbId, openLnbById_cb _hidl_cb) override; + private: virtual ~Tuner(); // Static mFrontends array to maintain local frontends information From db23aa825bad61eee3d53f261feb44151b70e84b Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Tue, 24 Sep 2019 11:08:27 -0700 Subject: [PATCH 0128/1022] MH2 | Implement direct channel and direct report methods Implement registerDirectChannel, unregisterDirectChannel, and configDirectReport methods of HalProxy. Bug: 136511617 Test: Compiles successfully. Simple enough change to ignore unit tests for now. Change-Id: I7e1e6a4da6ba2fc070836084210c83bd9b53aabe --- sensors/2.0/multihal/HalProxy.cpp | 35 +++++++++++++++++++------------ 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index f051a11a2c..7264e15c9f 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -162,25 +162,34 @@ Return HalProxy::injectSensorData(const Event& event) { return result; } -Return HalProxy::registerDirectChannel(const SharedMemInfo& /* mem */, +Return HalProxy::registerDirectChannel(const SharedMemInfo& mem, registerDirectChannel_cb _hidl_cb) { - // TODO: During init, discover the first sub-HAL in the config that has sensors with direct - // channel support, if any, and proxy the API call there. - _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */); + if (mDirectChannelSubHal == nullptr) { + _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */); + } else { + mDirectChannelSubHal->registerDirectChannel(mem, _hidl_cb); + } return Return(); } -Return HalProxy::unregisterDirectChannel(int32_t /* channelHandle */) { - // TODO: During init, discover the first sub-HAL in the config that has sensors with direct - // channel support, if any, and proxy the API call there. - return Result::INVALID_OPERATION; +Return HalProxy::unregisterDirectChannel(int32_t channelHandle) { + Result result; + if (mDirectChannelSubHal == nullptr) { + result = Result::INVALID_OPERATION; + } else { + result = mDirectChannelSubHal->unregisterDirectChannel(channelHandle); + } + return result; } -Return HalProxy::configDirectReport(int32_t /* sensorHandle */, int32_t /* channelHandle */, - RateLevel /* rate */, configDirectReport_cb _hidl_cb) { - // TODO: During init, discover the first sub-HAL in the config that has sensors with direct - // channel support, if any, and proxy the API call there. - _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */); +Return HalProxy::configDirectReport(int32_t sensorHandle, int32_t channelHandle, + RateLevel rate, configDirectReport_cb _hidl_cb) { + if (mDirectChannelSubHal == nullptr) { + _hidl_cb(Result::INVALID_OPERATION, -1 /* reportToken */); + } else { + mDirectChannelSubHal->configDirectReport(clearSubHalIndex(sensorHandle), channelHandle, + rate, _hidl_cb); + } return Return(); } From fda9224f14da57afd51be1af0e36333b413c9b1c Mon Sep 17 00:00:00 2001 From: Amy Date: Thu, 19 Sep 2019 12:42:50 -0700 Subject: [PATCH 0129/1022] Playback VTS modulization Test: manual Bug: 135708935 Change-Id: I07c03223703290196a20b0b3f689637063bac202 --- .../VtsHalTvTunerV1_0TargetTest.cpp | 165 +++++++++++++----- 1 file changed, 126 insertions(+), 39 deletions(-) diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index d272d710f3..7256cc4478 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #define WAIT_TIMEOUT 3000000000 @@ -72,6 +73,8 @@ using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings; using android::hardware::tv::tuner::V1_0::FrontendEventType; using android::hardware::tv::tuner::V1_0::FrontendId; using android::hardware::tv::tuner::V1_0::FrontendInnerFec; +using android::hardware::tv::tuner::V1_0::FrontendScanMessage; +using android::hardware::tv::tuner::V1_0::FrontendScanMessageType; using android::hardware::tv::tuner::V1_0::FrontendSettings; using android::hardware::tv::tuner::V1_0::IDemux; using android::hardware::tv::tuner::V1_0::IDemuxCallback; @@ -159,12 +162,21 @@ class FrontendCallback : public IFrontendCallback { return Void(); } + virtual Return onScanMessage(FrontendScanMessageType /* type */, + const FrontendScanMessage& /* message */) override { + android::Mutex::Autolock autoLock(mMsgLock); + mScanMessageReceived = true; + mMsgCondition.signal(); + return Void(); + }; + void testOnEvent(sp& frontend, FrontendSettings settings); void testOnDiseqcMessage(sp& frontend, FrontendSettings settings); private: bool mEventReceived = false; bool mDiseqcMessageReceived = false; + bool mScanMessageReceived = false; FrontendEventType mEventType; hidl_vec mEventMessage; android::Mutex mMsgLock; @@ -205,8 +217,8 @@ class DemuxCallback : public IDemuxCallback { ALOGW("[VTS] FILTER EVENT %d", filterEvent.filterId); android::Mutex::Autolock autoLock(mMsgLock); mFilterEventReceived = true; - // maybe assemble here?? - mFilterEvent = filterEvent; + mFilterIdToEvent[filterEvent.filterId] = filterEvent; + startFilterEventThread(filterEvent); mMsgCondition.signal(); return Void(); } @@ -236,11 +248,19 @@ class DemuxCallback : public IDemuxCallback { void testOnFilterEvent(uint32_t filterId); void testOnSectionFilterEvent(sp& demux, uint32_t filterId, MQDesc& filterMQDescriptor, MQDesc& inputMQDescriptor); - void startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor); - bool readAndCompareSectionEventData(); + void testFilterDataOutput(); + // Legacy + bool readAndCompareSectionEventData(uint32_t filterId); + void startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor); + void startFilterEventThread(DemuxFilterEvent event); static void* __threadLoopInput(void* threadArgs); + static void* __threadLoopFilter(void* threadArgs); void inputThreadLoop(InputConf inputConf, bool* keepWritingInputFMQ, MQDesc& inputMQDescriptor); + void filterThreadLoop(DemuxFilterEvent& event); + + void updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor); + void updateGoldenOutputMap(uint32_t filterId, string goldenOutputFile); private: struct InputThreadArgs { @@ -249,22 +269,34 @@ class DemuxCallback : public IDemuxCallback { bool* keepWritingInputFMQ; MQDesc& inputMQDesc; }; - bool mFilterEventReceived = false; - std::vector mDataOutputBuffer; - std::unique_ptr mFilterMQ; - std::unique_ptr mInputMQ; + struct FilterThreadArgs { + DemuxCallback* user; + DemuxFilterEvent& event; + }; uint16_t mDataLength = 0; - DemuxFilterEvent mFilterEvent; - android::Mutex mMsgLock; - android::Mutex mReadLock; - android::Condition mMsgCondition; - EventFlag* mFilterMQEventFlag; + std::vector mDataOutputBuffer; + + bool mFilterEventReceived; + std::map mFilterIdToGoldenOutput; + std::map mFilterIdToEvent; + + std::map> mFilterIdToMQ; + std::unique_ptr mInputMQ; + std::map mFilterIdToMQEventFlag; EventFlag* mInputMQEventFlag; + + android::Mutex mMsgLock; + android::Mutex mFilterOutputLock; + android::Condition mMsgCondition; + android::Condition mFilterOutputCondition; + bool mKeepWritingInputFMQ; bool mInputThreadRunning; pthread_t mInputThread; + pthread_t mFilterThread; }; +// Legacy void DemuxCallback::testOnFilterEvent(uint32_t filterId) { android::Mutex::Autolock autoLock(mMsgLock); while (!mFilterEventReceived) { @@ -276,7 +308,7 @@ void DemuxCallback::testOnFilterEvent(uint32_t filterId) { // Reset the filter event recieved flag mFilterEventReceived = false; // Check if filter id match - EXPECT_TRUE(filterId == mFilterEvent.filterId) << "filter id match"; + EXPECT_TRUE(filterId == mFilterIdToEvent[filterId].filterId) << "filter id match"; } void DemuxCallback::startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor) { @@ -291,28 +323,42 @@ void DemuxCallback::startPlaybackInputThread(InputConf inputConf, MQDesc& inputM pthread_setname_np(mInputThread, "test_playback_input_loop"); } -/*void DemuxCallback::testPlaybackDataFlow(bool* keepWritingInputFMQ) { - // timeout logic here +void DemuxCallback::startFilterEventThread(DemuxFilterEvent event) { + struct FilterThreadArgs* threadArgs = + (struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs)); + threadArgs->user = this; + threadArgs->event = event; - // assemble logic here + pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs); + pthread_setname_np(mFilterThread, "test_playback_input_loop"); +} +void DemuxCallback::testFilterDataOutput() { + android::Mutex::Autolock autoLock(mFilterOutputLock); + while (!mFilterIdToMQ.empty()) { + if (-ETIMEDOUT == mFilterOutputCondition.waitRelative(mFilterOutputLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "filter output does not match golden output within timeout"; + return; + } + } +} -}*/ - +// Legacy void DemuxCallback::testOnSectionFilterEvent(sp& demux, uint32_t filterId, MQDesc& filterMQDescriptor, MQDesc& inputMQDescriptor) { Result status; // Create MQ to read the output into the local buffer - mFilterMQ = std::make_unique(filterMQDescriptor, true /* resetPointers */); - EXPECT_TRUE(mFilterMQ); + mFilterIdToMQ[filterId] = + std::make_unique(filterMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(mFilterIdToMQ[filterId]); // Get the MQ to write the input to the HAL mInputMQ = std::make_unique(inputMQDescriptor, true /* resetPointers */); EXPECT_TRUE(mInputMQ); // Create the EventFlag that is used to signal the HAL impl that data have been // read the Filter FMQ - EXPECT_TRUE(EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag) == - android::OK); + EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ[filterId]->getEventFlagWord(), + &mFilterIdToMQEventFlag[filterId]) == android::OK); // Create the EventFlag that is used to signal the HAL impl that data have been // written into the Input FMQ EXPECT_TRUE(EventFlag::createEventFlag(mInputMQ->getEventFlagWord(), &mInputMQEventFlag) == @@ -329,21 +375,24 @@ void DemuxCallback::testOnSectionFilterEvent(sp& demux, uint32_t filterI mInputMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); testOnFilterEvent(filterId); // checksum of mDataOutputBuffer and Input golden input - if (readAndCompareSectionEventData() && i < SECTION_READ_COUNT - 1) { - mFilterMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); + if (readAndCompareSectionEventData(filterId) && i < SECTION_READ_COUNT - 1) { + mFilterIdToMQEventFlag[filterId]->wake( + static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); } } } -bool DemuxCallback::readAndCompareSectionEventData() { +// Legacy +bool DemuxCallback::readAndCompareSectionEventData(uint32_t filterId) { bool result = false; - for (int i = 0; i < mFilterEvent.events.size(); i++) { - DemuxFilterSectionEvent event = mFilterEvent.events[i].section(); + DemuxFilterEvent filterEvent = mFilterIdToEvent[filterId]; + for (int i = 0; i < filterEvent.events.size(); i++) { + DemuxFilterSectionEvent event = filterEvent.events[i].section(); mDataLength = event.dataLength; EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not match"; mDataOutputBuffer.resize(mDataLength); - result = mFilterMQ->read(mDataOutputBuffer.data(), mDataLength); + result = mFilterIdToMQ[filterId]->read(mDataOutputBuffer.data(), mDataLength); EXPECT_TRUE(result) << "can't read from Filter MQ"; for (int i = 0; i < mDataLength; i++) { @@ -353,6 +402,18 @@ bool DemuxCallback::readAndCompareSectionEventData() { return result; } +void DemuxCallback::updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor) { + mFilterIdToMQ[filterId] = + std::make_unique(filterMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(mFilterIdToMQ[filterId]); + EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ[filterId]->getEventFlagWord(), + &mFilterIdToMQEventFlag[filterId]) == android::OK); +} + +void DemuxCallback::updateGoldenOutputMap(uint32_t filterId, string goldenOutputFile) { + mFilterIdToGoldenOutput[filterId] = goldenOutputFile; +} + void* DemuxCallback::__threadLoopInput(void* threadArgs) { DemuxCallback* const self = static_cast(((struct InputThreadArgs*)threadArgs)->user); @@ -413,6 +474,26 @@ void DemuxCallback::inputThreadLoop(InputConf inputConf, bool* keepWritingInputF inputData.close(); } +void* DemuxCallback::__threadLoopFilter(void* threadArgs) { + DemuxCallback* const self = + static_cast(((struct FilterThreadArgs*)threadArgs)->user); + self->filterThreadLoop(((struct FilterThreadArgs*)threadArgs)->event); + return 0; +} + +void DemuxCallback::filterThreadLoop(DemuxFilterEvent& /*event*/) { + android::Mutex::Autolock autoLock(mFilterOutputLock); + // Read from MQ[event.filterId] per event and filter type + + // Assemble to filterOutput[filterId] + + // check if filterOutput[filterId] matches goldenOutput[filterId] + + // If match, remove filterId entry from MQ map + + // end thread +} + // Test environment for Tuner HIDL HAL. class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: @@ -462,16 +543,19 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId); ::testing::AssertionResult getInputMQDescriptor(); ::testing::AssertionResult addInputToDemux(DemuxInputSettings setting); - ::testing::AssertionResult addSectionFilterToDemux(); ::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting); ::testing::AssertionResult getFilterMQDescriptor(const uint32_t filterId); ::testing::AssertionResult closeDemux(); ::testing::AssertionResult createDescrambler(); ::testing::AssertionResult closeDescrambler(); - ::testing::AssertionResult readSectionFilterDataOutput(); ::testing::AssertionResult playbackDataFlowTest(vector filterConf, - InputConf inputConf, string goldenOutput); + InputConf inputConf, + vector goldenOutputFiles); + + // Legacy + ::testing::AssertionResult addSectionFilterToDemux(); + ::testing::AssertionResult readSectionFilterDataOutput(); }; ::testing::AssertionResult TunerHidlTest::createFrontend(int32_t frontendId) { @@ -507,8 +591,6 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { FrontendDvbtSettings frontendDvbtSettings{ .frequency = 0, - .modulation = FrontendAtscModulation::UNDEFINED, - .fec = FrontendInnerFec::FEC_UNDEFINED, }; frontendSettings.dvbt(frontendDvbtSettings); mFrontendCallback->testOnEvent(mFrontend, frontendSettings); @@ -650,6 +732,7 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionResult(status == Result::SUCCESS); } +// Legacy ::testing::AssertionResult TunerHidlTest::addSectionFilterToDemux() { Result status; @@ -717,6 +800,7 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionResult(status == Result::SUCCESS); } +// Legacy ::testing::AssertionResult TunerHidlTest::readSectionFilterDataOutput() { // Filter Configuration Module DemuxInputSettings setting{ @@ -744,7 +828,7 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { ::testing::AssertionResult TunerHidlTest::playbackDataFlowTest(vector filterConf, InputConf inputConf, - string /*goldenOutput*/) { + vector goldenOutputFiles) { Result status; // Filter Configuration Module for (int i = 0; i < filterConf.size(); i++) { @@ -754,6 +838,12 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } + mDemuxCallback->updateFilterMQ(mFilterId, mFilterMQDescriptor); + mDemuxCallback->updateGoldenOutputMap(mFilterId, goldenOutputFiles[i]); + status = mDemux->startFilter(mFilterId); + if (status != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } } // Playback Input Module @@ -769,12 +859,9 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { } // Data Verify Module - // golden output, created FMQ to read and EventFlags to DATA_CONSUMED - // Maintain each filter's real output (and how to assemble?????) - // mDemuxCallback->testPlaybackDataFlow(); + mDemuxCallback->testFilterDataOutput(); // Clean Up Module - // TODO what about remove input, remove filters return closeDemux(); } From 1eb823636d1b09347e6c0b5a0530f67e1294d988 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Wed, 28 Aug 2019 17:54:29 +0800 Subject: [PATCH 0130/1022] wifi: add pmk cache interface Bug: 36505680 Test: atest VtsHalWifiSupplicantV1_3TargetTest Test: connect EAP access point and verify PMK cache works correctly. Change-Id: Iab3a8a69b5fd23bda209c4fa8cf1518c9a1602db --- .../compatibility_matrix.current.xml | 2 +- wifi/supplicant/1.3/Android.bp | 2 + wifi/supplicant/1.3/ISupplicantStaIface.hal | 46 +++++ .../1.3/ISupplicantStaIfaceCallback.hal | 38 ++++ wifi/supplicant/1.3/ISupplicantStaNetwork.hal | 15 ++ wifi/supplicant/1.3/vts/functional/Android.bp | 1 + .../supplicant_hidl_test_utils_1_3.cpp | 5 + .../supplicant_hidl_test_utils_1_3.h | 3 + .../supplicant_sta_iface_hidl_test.cpp | 181 ++++++++++++++++++ .../supplicant_sta_network_hidl_test.cpp | 13 ++ 10 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 wifi/supplicant/1.3/ISupplicantStaIface.hal create mode 100644 wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal create mode 100644 wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index ef1cd75cd1..69766f2a51 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -507,7 +507,7 @@ android.hardware.wifi.supplicant - 1.0-2 + 1.0-3 ISupplicant default diff --git a/wifi/supplicant/1.3/Android.bp b/wifi/supplicant/1.3/Android.bp index 6633d9d1e3..3f2053132b 100644 --- a/wifi/supplicant/1.3/Android.bp +++ b/wifi/supplicant/1.3/Android.bp @@ -9,6 +9,8 @@ hidl_interface { srcs: [ "types.hal", "ISupplicant.hal", + "ISupplicantStaIface.hal", + "ISupplicantStaIfaceCallback.hal", "ISupplicantStaNetwork.hal", ], interfaces: [ diff --git a/wifi/supplicant/1.3/ISupplicantStaIface.hal b/wifi/supplicant/1.3/ISupplicantStaIface.hal new file mode 100644 index 0000000000..62b40333e9 --- /dev/null +++ b/wifi/supplicant/1.3/ISupplicantStaIface.hal @@ -0,0 +1,46 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi.supplicant@1.3; + +import @1.0::SupplicantStatus; +import @1.2::ISupplicantStaIface; +import @1.3::ISupplicantStaIfaceCallback; + +/** + * Interface exposed by the supplicant for each station mode network + * interface (e.g wlan0) it controls. + */ +interface ISupplicantStaIface extends @1.2::ISupplicantStaIface { + /** + * Register for callbacks from this interface. + * + * These callbacks are invoked for events that are specific to this interface. + * Registration of multiple callback objects is supported. These objects must + * be automatically deleted when the corresponding client process is dead or + * if this interface is removed. + * + * @param callback An instance of the |ISupplicantStaIfaceCallback| HIDL + * interface object. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_IFACE_INVALID| + */ + registerCallback_1_3(ISupplicantStaIfaceCallback callback) + generates (SupplicantStatus status); +}; diff --git a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal new file mode 100644 index 0000000000..107e0fc0f6 --- /dev/null +++ b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal @@ -0,0 +1,38 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi.supplicant@1.3; + +import @1.2::ISupplicantStaIfaceCallback; + +/** + * Callback Interface exposed by the supplicant service + * for each station mode interface (ISupplicantStaIface). + * + * Clients need to host an instance of this HIDL interface object and + * pass a reference of the object to the supplicant via the + * corresponding |ISupplicantStaIface.registerCallback_1_3| method. + */ +interface ISupplicantStaIfaceCallback extends @1.2::ISupplicantStaIfaceCallback { + /** + * Indicates PMK cache added event. + * + * @param expirationTimeInSec expiration time in seconds + * @param serializedEntry is serialized PMK cache entry, the content is + * opaque for the framework and depends on the native implementation. + */ + oneway onPmkCacheAdded(int64_t expirationTimeInSec, vec serializedEntry); +}; diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal index eb9de9a53e..5e265c6257 100644 --- a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal +++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal @@ -47,4 +47,19 @@ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { * @return ocspType ocsp type. */ getOcsp() generates (SupplicantStatus status, OcspType ocspType); + + /** + * Add a PMK into supplicant PMK cache. + * + * @param serializedEntry is serialized PMK cache entry, the content is + * opaque for the framework and depends on the native implementation. + * @return status Status of the operation + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + setPmkCache(vec serializedEntry) + generates (SupplicantStatus status); }; diff --git a/wifi/supplicant/1.3/vts/functional/Android.bp b/wifi/supplicant/1.3/vts/functional/Android.bp index 67c73481f2..abb86008b5 100644 --- a/wifi/supplicant/1.3/vts/functional/Android.bp +++ b/wifi/supplicant/1.3/vts/functional/Android.bp @@ -42,6 +42,7 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: [ "VtsHalWifiSupplicantV1_3TargetTest.cpp", + "supplicant_sta_iface_hidl_test.cpp", "supplicant_sta_network_hidl_test.cpp", ], static_libs: [ diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp index 86959eba97..308808deff 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp @@ -21,8 +21,13 @@ #include "supplicant_hidl_test_utils_1_3.h" using ::android::sp; +using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork; +sp getSupplicantStaIface_1_3() { + return ISupplicantStaIface::castFrom(getSupplicantStaIface()); +} + sp createSupplicantStaNetwork_1_3() { return ISupplicantStaNetwork::castFrom(createSupplicantStaNetwork()); } diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h index 8e64162d04..39dbb8fc96 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h +++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h @@ -17,8 +17,11 @@ #ifndef SUPPLICANT_HIDL_TEST_UTILS_1_3_H #define SUPPLICANT_HIDL_TEST_UTILS_1_3_H +#include #include +android::sp +getSupplicantStaIface_1_3(); android::sp createSupplicantStaNetwork_1_3(); diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp new file mode 100644 index 0000000000..9b68a4708d --- /dev/null +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp @@ -0,0 +1,181 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "supplicant_hidl_test_utils.h" +#include "supplicant_hidl_test_utils_1_3.h" + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus; +using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; +using ::android::hardware::wifi::supplicant::V1_2::DppAkm; +using ::android::hardware::wifi::supplicant::V1_2::DppFailureCode; +using ::android::hardware::wifi::supplicant::V1_2::DppProgressCode; +using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface; +using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIfaceCallback; +using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork; + +class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + startSupplicantAndWaitForHidlService(); + EXPECT_TRUE(turnOnExcessiveLogging()); + sta_iface_ = getSupplicantStaIface_1_3(); + ASSERT_NE(sta_iface_.get(), nullptr); + } + + virtual void TearDown() override { stopSupplicant(); } + + int64_t pmkCacheExpirationTimeInSec; + std::vector serializedPmkCacheEntry; + + protected: + // ISupplicantStaIface object used for all tests in this fixture. + sp sta_iface_; +}; + +class IfaceCallback : public ISupplicantStaIfaceCallback { + Return onNetworkAdded(uint32_t /* id */) override { return Void(); } + Return onNetworkRemoved(uint32_t /* id */) override { return Void(); } + Return onStateChanged( + ISupplicantStaIfaceCallback::State /* newState */, + const hidl_array& /*bssid */, uint32_t /* id */, + const hidl_vec& /* ssid */) override { + return Void(); + } + Return onAnqpQueryDone( + const hidl_array& /* bssid */, + const ISupplicantStaIfaceCallback::AnqpData& /* data */, + const ISupplicantStaIfaceCallback::Hs20AnqpData& /* hs20Data */) + override { + return Void(); + } + virtual Return onHs20IconQueryDone( + const hidl_array& /* bssid */, + const hidl_string& /* fileName */, + const hidl_vec& /* data */) override { + return Void(); + } + virtual Return onHs20SubscriptionRemediation( + const hidl_array& /* bssid */, + ISupplicantStaIfaceCallback::OsuMethod /* osuMethod */, + const hidl_string& /* url*/) override { + return Void(); + } + Return onHs20DeauthImminentNotice( + const hidl_array& /* bssid */, uint32_t /* reasonCode */, + uint32_t /* reAuthDelayInSec */, + const hidl_string& /* url */) override { + return Void(); + } + Return onDisconnected(const hidl_array& /* bssid */, + bool /* locallyGenerated */, + ISupplicantStaIfaceCallback::ReasonCode + /* reasonCode */) override { + return Void(); + } + Return onAssociationRejected( + const hidl_array& /* bssid */, + ISupplicantStaIfaceCallback::StatusCode /* statusCode */, + bool /*timedOut */) override { + return Void(); + } + Return onAuthenticationTimeout( + const hidl_array& /* bssid */) override { + return Void(); + } + Return onBssidChanged( + ISupplicantStaIfaceCallback::BssidChangeReason /* reason */, + const hidl_array& /* bssid */) override { + return Void(); + } + Return onEapFailure() override { return Void(); } + Return onEapFailure_1_1( + ISupplicantStaIfaceCallback::EapErrorCode /* eapErrorCode */) override { + return Void(); + } + Return onWpsEventSuccess() override { return Void(); } + Return onWpsEventFail( + const hidl_array& /* bssid */, + ISupplicantStaIfaceCallback::WpsConfigError /* configError */, + ISupplicantStaIfaceCallback::WpsErrorIndication /* errorInd */) + override { + return Void(); + } + Return onWpsEventPbcOverlap() override { return Void(); } + Return onExtRadioWorkStart(uint32_t /* id */) override { + return Void(); + } + Return onExtRadioWorkTimeout(uint32_t /* id*/) override { + return Void(); + } + Return onDppSuccessConfigReceived( + const hidl_vec& /* ssid */, const hidl_string& /* password */, + const hidl_array& /* psk */, + DppAkm /* securityAkm */) override { + return Void(); + } + Return onDppSuccessConfigSent() override { return Void(); } + Return onDppProgress(DppProgressCode /* code */) override { + return Void(); + } + Return onDppFailure(DppFailureCode /* code */) override { + return Void(); + } + Return onPmkCacheAdded( + int64_t /* expirationTimeInSec */, + const hidl_vec& /* serializedEntry */) override { + return Void(); + } +}; + +class IfacePmkCacheCallback : public IfaceCallback { + SupplicantStaIfaceHidlTest& parent_; + Return onPmkCacheAdded( + int64_t expirationTimeInSec, + const hidl_vec& serializedEntry) override { + parent_.pmkCacheExpirationTimeInSec = expirationTimeInSec; + parent_.serializedPmkCacheEntry = serializedEntry; + return Void(); + } + + public: + IfacePmkCacheCallback(SupplicantStaIfaceHidlTest& parent) + : parent_(parent) {} +}; + +/* + * RegisterCallback_1_3 + */ +TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback_1_3) { + sta_iface_->registerCallback_1_3( + new IfaceCallback(), [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); +} diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp index e5be0ccfef..07bc9d8103 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp @@ -71,3 +71,16 @@ TEST_F(SupplicantStaNetworkHidlTest, SetGetOcsp) { EXPECT_EQ(testOcspType, ocspType); }); } + +/* + * SetPmkCacheEntry + */ +TEST_F(SupplicantStaNetworkHidlTest, SetPmkCache) { + uint8_t bytes[128] = {0}; + std::vector serializedEntry(bytes, bytes + sizeof(bytes)); + + sta_network_->setPmkCache( + serializedEntry, [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); +} From 5971426925420a48cc49b481b323368fa02a918c Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Fri, 20 Sep 2019 10:55:30 -0700 Subject: [PATCH 0131/1022] MH2 | Implement pending writes thread Spin up a background thread inside the hal proxy that is responsible for writing events to the event fmq if a previous write failed on the normal postEvents thread. Create several new unit tests that help test the new functionality. Bug: 136511617 Test: Unit tests passing. Change-Id: Ic35c9736fc0402297ab50072c195f66c9feb887d --- sensors/2.0/multihal/HalProxy.cpp | 81 ++++++++-- sensors/2.0/multihal/include/HalProxy.h | 34 ++++ sensors/2.0/multihal/tests/HalProxy_test.cpp | 157 +++++++++++++++++-- 3 files changed, 245 insertions(+), 27 deletions(-) diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index 81d1b64af8..ccd6e6647e 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -49,8 +49,15 @@ HalProxy::HalProxy(std::vector& subHalList) : mSubHalList(subHa } HalProxy::~HalProxy() { - // TODO: Join any running threads and clean up FMQs and any other allocated - // state. + { + std::lock_guard lockGuard(mEventQueueWriteMutex); + mPendingWritesRun = false; + mEventQueueWriteCV.notify_one(); + } + if (mPendingWritesThread.joinable()) { + mPendingWritesThread.join(); + } + // TODO: Cleanup wakeup thread once it is implemented } Return HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) { @@ -120,7 +127,8 @@ Return HalProxy::initialize( result = Result::BAD_VALUE; } - // TODO: start threads to read wake locks and process events from sub HALs. + mPendingWritesThread = std::thread(startPendingWritesThread, this); + // TODO: start threads to read wake locks. for (size_t i = 0; i < mSubHalList.size(); i++) { auto subHal = mSubHalList[i]; @@ -257,21 +265,66 @@ void HalProxy::initializeSubHalCallbacksAndSensorList() { initializeSensorList(); } +void HalProxy::startPendingWritesThread(HalProxy* halProxy) { + halProxy->handlePendingWrites(); +} + +void HalProxy::handlePendingWrites() { + // TODO: Find a way to optimize locking strategy maybe using two mutexes instead of one. + std::unique_lock lock(mEventQueueWriteMutex); + while (mPendingWritesRun) { + mEventQueueWriteCV.wait( + lock, [&] { return !mPendingWriteEventsQueue.empty() || !mPendingWritesRun; }); + if (!mPendingWriteEventsQueue.empty() && mPendingWritesRun) { + std::vector& pendingWriteEvents = mPendingWriteEventsQueue.front(); + size_t eventQueueSize = mEventQueue->getQuantumCount(); + size_t numToWrite = std::min(pendingWriteEvents.size(), eventQueueSize); + lock.unlock(); + // TODO: Find a way to interrup writeBlocking if the thread should exit + // so we don't have to wait for timeout on framework restarts. + if (!mEventQueue->writeBlocking( + pendingWriteEvents.data(), numToWrite, + static_cast(EventQueueFlagBits::EVENTS_READ), + static_cast(EventQueueFlagBits::READ_AND_PROCESS), + kWakelockTimeoutNs, mEventQueueFlag)) { + ALOGE("Dropping %zu events after blockingWrite failed.", numToWrite); + } else { + mEventQueueFlag->wake(static_cast(EventQueueFlagBits::READ_AND_PROCESS)); + } + lock.lock(); + if (pendingWriteEvents.size() > eventQueueSize) { + // TODO: Check if this erase operation is too inefficient. It will copy all the + // events ahead of it down to fill gap off array at front after the erase. + pendingWriteEvents.erase(pendingWriteEvents.begin(), + pendingWriteEvents.begin() + eventQueueSize); + } else { + mPendingWriteEventsQueue.pop(); + } + } + } +} + void HalProxy::postEventsToMessageQueue(const std::vector& events) { - std::lock_guard lock(mEventQueueMutex); - size_t numToWrite = std::min(events.size(), mEventQueue->availableToWrite()); - if (numToWrite > 0) { - if (mEventQueue->write(events.data(), numToWrite)) { - // TODO: While loop if mEventQueue->avaiableToWrite > 0 to possibly fit in more writes - // immediately - mEventQueueFlag->wake(static_cast(EventQueueFlagBits::READ_AND_PROCESS)); - } else { - numToWrite = 0; + size_t numToWrite = 0; + std::lock_guard lock(mEventQueueWriteMutex); + if (mPendingWriteEventsQueue.empty()) { + numToWrite = std::min(events.size(), mEventQueue->availableToWrite()); + if (numToWrite > 0) { + if (mEventQueue->write(events.data(), numToWrite)) { + // TODO: While loop if mEventQueue->avaiableToWrite > 0 to possibly fit in more + // writes immediately + mEventQueueFlag->wake(static_cast(EventQueueFlagBits::READ_AND_PROCESS)); + } else { + numToWrite = 0; + } } } if (numToWrite < events.size()) { - // TODO: Post from events[numToWrite -> end] to background events queue - // Signal background thread + // TODO: Bound the mPendingWriteEventsQueue so that we do not trigger OOMs if framework + // stalls + mPendingWriteEventsQueue.push( + std::vector(events.begin() + numToWrite, events.end())); + mEventQueueWriteCV.notify_one(); } } diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h index bdcc1ff7c1..ae4b2c53c6 100644 --- a/sensors/2.0/multihal/include/HalProxy.h +++ b/sensors/2.0/multihal/include/HalProxy.h @@ -24,7 +24,12 @@ #include #include +#include +#include #include +#include +#include +#include namespace android { namespace hardware { @@ -159,6 +164,7 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { */ std::vector mSubHalList; + //! The list of subhal callbacks for each subhal where the indices correlate with mSubHalList std::vector> mSubHalCallbacks; /** @@ -179,6 +185,9 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { //! The mutex for the event queue. std::mutex mEventQueueMutex; + //! The timeout for each pending write on background thread for events. + static const int64_t kWakelockTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */; + //! The scoped wakelock ref count. size_t mWakelockRefCount = 0; @@ -188,6 +197,21 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { //! The bit mask used to get the subhal index from a sensor handle. static constexpr uint32_t kSensorHandleSubHalIndexMask = 0xFF000000; + //! The events that were not able to be written to fmq right away + std::queue> mPendingWriteEventsQueue; + + //! The mutex protecting writing to the fmq and the pending events queue + std::mutex mEventQueueWriteMutex; + + //! The condition variable waiting on pending write events to stack up + std::condition_variable mEventQueueWriteCV; + + //! The thread object ptr that handles pending writes + std::thread mPendingWritesThread; + + //! The bool indicating whether to end the pending writes background thread or not + bool mPendingWritesRun = true; + /** * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries * listed in a config file. @@ -210,6 +234,16 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { */ void initializeSubHalCallbacksAndSensorList(); + /** + * Starts the thread that handles pending writes to event fmq. + * + * @param halProxy The HalProxy object pointer. + */ + static void startPendingWritesThread(HalProxy* halProxy); + + //! Handles the pending writes on events to eventqueue. + void handlePendingWrites(); + /** * Clear direct channel flags if the HalProxy has already chosen a subhal as its direct channel * subhal. Set the directChannelSubHal pointer to the subHal passed in if this is the first diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp index 4b1a15efaa..61fb14c38f 100644 --- a/sensors/2.0/multihal/tests/HalProxy_test.cpp +++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp @@ -22,11 +22,10 @@ #include "ScopedWakelock.h" #include "SensorsSubHal.h" +#include +#include #include -#undef LOG_TAG -#define LOG_TAG "HalProxy_test" - namespace { using ::android::hardware::hidl_vec; @@ -98,7 +97,7 @@ void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector makeMultipleProximityEvents(size_t numEvents); + +/** + * Make a certain number of accelerometer type events with the sensorHandle field set to + * the proper number for AllSensorsSubHal subhal type. + * + * @param numEvents The number of events to make. + * + * @return The created list of events. + */ +std::vector makeMultipleAccelerometerEvents(size_t numEvents); + // Tests follow TEST(HalProxyTest, GetSensorsListOneSubHalTest) { AllSensorsSubHal subHal; @@ -232,10 +251,7 @@ TEST(HalProxyTest, PostMultipleNonWakeupEvent) { ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events; - for (size_t i = 0; i < kNumEvents; i++) { - events.push_back(makeAccelerometerEvent()); - } + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); subHal.postEvents(events, false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); @@ -272,15 +288,114 @@ TEST(HalProxyTest, PostMultipleWakeupEvents) { ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events; - for (size_t i = 0; i < kNumEvents; i++) { - events.push_back(makeProximityEvent()); - } + std::vector events = makeMultipleProximityEvents(kNumEvents); subHal.postEvents(events, true /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); } +TEST(HalProxyTest, PostEventsMultipleSubhals) { + constexpr size_t kQueueSize = 5; + constexpr size_t kNumEvents = 2; + AllSensorsSubHal subHal1, subHal2; + std::vector subHals{&subHal1, &subHal2}; + HalProxy proxy(subHals); + std::unique_ptr eventQueue = + std::make_unique(kQueueSize, true); + std::unique_ptr wakeLockQueue = + std::make_unique(kQueueSize, true); + ::android::sp callback = new SensorsCallback(); + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal1.postEvents(events, false /* wakeup */); + + EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); + + subHal2.postEvents(events, false /* wakeup */); + + EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2); +} + +TEST(HalProxyTest, PostEventsDelayedWrite) { + constexpr size_t kQueueSize = 5; + constexpr size_t kNumEvents = 6; + AllSensorsSubHal subHal1, subHal2; + std::vector subHals{&subHal1, &subHal2}; + HalProxy proxy(subHals); + std::unique_ptr eventQueue = + std::make_unique(kQueueSize, true); + std::unique_ptr wakeLockQueue = + std::make_unique(kQueueSize, true); + ::android::sp callback = new SensorsCallback(); + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal1.postEvents(events, false /* wakeup */); + + EXPECT_EQ(eventQueue->availableToRead(), kQueueSize); + + Event eventOut; + // writeblock 1 event out of queue, timeout for half a second + EXPECT_TRUE(eventQueue->readBlocking(&eventOut, 1, 500000000)); + + // Sleep for a half second so that blocking write has time complete in background thread + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + + // proxy background thread should have wrote last event when it saw space + EXPECT_EQ(eventQueue->availableToRead(), kQueueSize); +} + +TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) { + constexpr size_t kQueueSize = 5; + constexpr size_t kNumEvents = 2; + AllSensorsSubHal subHal1, subHal2; + std::vector subHals{&subHal1, &subHal2}; + HalProxy proxy(subHals); + std::unique_ptr eventQueue = + std::make_unique(kQueueSize, true); + std::unique_ptr wakeLockQueue = + std::make_unique(kQueueSize, true); + ::android::sp callback = new SensorsCallback(); + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + + std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, events, false); + std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, events, false); + + t1.join(); + t2.join(); + + EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2); +} + +TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThreadTest) { + constexpr size_t kQueueSize = 5; + constexpr size_t kNumEvents = 6; + AllSensorsSubHal subHal; + std::vector subHals{&subHal}; + + std::unique_ptr eventQueue = + std::make_unique(kQueueSize, true); + std::unique_ptr wakeLockQueue = + std::make_unique(kQueueSize, true); + ::android::sp callback = new SensorsCallback(); + HalProxy proxy(subHals); + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal.postEvents(events, false /* wakeup */); + + // Sleep for a half second so that background thread has time to attempt it's blocking write + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + + // Should see a 5 second wait for blocking write timeout here + + // Should be one events left on pending writes queue here and proxy will destruct + // If this TEST completes then it was a success, if it hangs we will see a crash +} + // Helper implementations follow void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, const std::vector& subHalSensorsList) { @@ -332,4 +447,20 @@ Event makeAccelerometerEvent() { return event; } +std::vector makeMultipleProximityEvents(size_t numEvents) { + std::vector events; + for (size_t i = 0; i < numEvents; i++) { + events.push_back(makeProximityEvent()); + } + return events; +} + +std::vector makeMultipleAccelerometerEvents(size_t numEvents) { + std::vector events; + for (size_t i = 0; i < numEvents; i++) { + events.push_back(makeAccelerometerEvent()); + } + return events; +} + } // namespace From bde28187e481a156fd10901aaacf715949af4287 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 26 Sep 2019 09:14:31 -0700 Subject: [PATCH 0132/1022] Freeze wifi 1.4 HAL For R release, so that the tree is in a shippable state. If further changes to it are needed in R, this hash can be updated. Bug: 141025272 Test: build (verifies hash) Change-Id: I74c28087f3721e4ef98320efe854e598af6699f9 --- current.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/current.txt b/current.txt index 83657b2d47..3352f8ad27 100644 --- a/current.txt +++ b/current.txt @@ -579,3 +579,6 @@ fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardwar 40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface + +# HALs released in Android R +04395b26be33db17747c3d3b0e8066d323f891ff4f9f3b3ddb490b2f3f844a18 android.hardware.wifi@1.4::IWifi From 44d525b68bb6e087d0fbe0b122c735a0fa9be8f7 Mon Sep 17 00:00:00 2001 From: Jim Kaye Date: Fri, 27 Sep 2019 12:21:36 -0700 Subject: [PATCH 0133/1022] Change AP_POWER_STATE_REPORT's access property. Change AP_POWER_STATE_REPORT's access property from WRITE to READ_WRITE. In Vehicle environment some hals communicate with external ecu, so they must know the boot reason. (Not only on, but DEEP_SLEEP_EXIT, ON, CANCELED) To handle this, AOSP provide CarPowerManager, but it use AIDL. But, in treble, vendor process must communicate with system process via hidl. So, vendor processes(almost hal), can't use CarPowerManager. (Beside, CarPowerManager use /dev/binder but vendor process use /dev/vndbinder). If hals subscribe AP_POWER_STATE_REPORT via vehicle hal, they can handle the power state. Bug: 140370318 Test: Verified on Hawk Change-Id: Ic4c7f1d66a4fdee1cfb8b9da42cf76bc7aed5948 --- automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h | 2 +- automotive/vehicle/2.0/types.hal | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 c8e11e3c30..094a37253e 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 @@ -786,7 +786,7 @@ const ConfigDeclaration kVehicleProperties[]{ .initialValue = {.int32Values = {toInt(VehicleApPowerStateReq::ON), 0}}}, {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT), - .access = VehiclePropertyAccess::WRITE, + .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE}, .initialValue = {.int32Values = {toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL), 0}}}, diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index 8c84c0a17e..9dfd558f79 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -1310,7 +1310,7 @@ enum VehicleProperty : int32_t { * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ AP_POWER_STATE_REPORT = ( 0x0A01 From 93347e2f44371d7c6c39cabd533769b93c281bcb Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 30 Sep 2019 10:20:26 -0700 Subject: [PATCH 0134/1022] Freeze wifi supplicant 1.3 HAL For R release, so that the tree is in a shippable state. If further changes to it are needed in R, this hash can be updated. Bug: 141764710 Test: build (checks hashes) Change-Id: Ibaedbd20807f880a6df52b46f4157e7ab4dac94f --- current.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/current.txt b/current.txt index 3352f8ad27..0718b16a42 100644 --- a/current.txt +++ b/current.txt @@ -582,3 +582,8 @@ fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardwar # HALs released in Android R 04395b26be33db17747c3d3b0e8066d323f891ff4f9f3b3ddb490b2f3f844a18 android.hardware.wifi@1.4::IWifi +270f0eb670dfd9bc5cd718e09711f2534fa8425f54d06c1a46523ca156b509e2 android.hardware.wifi.supplicant@1.3::ISupplicant +dd4b7cfbb6e1c6ff011c33920762ad89dd02240c63a4d3a3d5037f154eae3e3b android.hardware.wifi.supplicant@1.3::ISupplicantStaIface +619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback +6fe09b18e913608579638594788198ec45bb2369e567d7df661db46c4f0e5f08 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork +91931b05bd70ea6bdffbe075086183f803379571788564e28854207620eb75cf android.hardware.wifi.supplicant@1.3::types From 38e79e6905f82a78fce67fd937a5674176dec047 Mon Sep 17 00:00:00 2001 From: Keun young Park Date: Mon, 30 Sep 2019 13:41:40 -0700 Subject: [PATCH 0135/1022] Update OWNERS bug: 141876695 Test: none Change-Id: I653304479634e7cc71b22705ff3384d04a3577dc --- automotive/OWNERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/automotive/OWNERS b/automotive/OWNERS index 3cf4489e9a..83ee63c397 100644 --- a/automotive/OWNERS +++ b/automotive/OWNERS @@ -1,4 +1,5 @@ -randolphs@google.com pirozzoj@google.com twasilczyk@google.com pfg@google.com +gurunagarajan@google.com +keunyoung@google.com From 9f290826b8548d855237c4e9b17a78f426696571 Mon Sep 17 00:00:00 2001 From: "Harpreet \"Eli\" Sangha" Date: Mon, 22 Jul 2019 16:15:16 +0900 Subject: [PATCH 0136/1022] vibrator: Support Async Callback APIs Bug: 136220871 Test: Manually via 'cmd vibrator' Change-Id: I4201538e4b2e663ac0215c1deb1047658f4d602e --- .../compatibility_matrix.current.xml | 2 +- vibrator/1.4/Android.bp | 22 +++++++ vibrator/1.4/IVibrator.hal | 57 +++++++++++++++++++ vibrator/1.4/IVibratorCallback.hal | 21 +++++++ vibrator/1.4/types.hal | 22 +++++++ 5 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 vibrator/1.4/Android.bp create mode 100644 vibrator/1.4/IVibrator.hal create mode 100644 vibrator/1.4/IVibratorCallback.hal create mode 100644 vibrator/1.4/types.hal diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 69766f2a51..76d1697c5f 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -467,7 +467,7 @@ android.hardware.vibrator - 1.0-3 + 1.0-4 IVibrator default diff --git a/vibrator/1.4/Android.bp b/vibrator/1.4/Android.bp new file mode 100644 index 0000000000..cf31fcdab5 --- /dev/null +++ b/vibrator/1.4/Android.bp @@ -0,0 +1,22 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.vibrator@1.4", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IVibrator.hal", + "IVibratorCallback.hal", + ], + interfaces: [ + "android.hardware.vibrator@1.0", + "android.hardware.vibrator@1.1", + "android.hardware.vibrator@1.2", + "android.hardware.vibrator@1.3", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/vibrator/1.4/IVibrator.hal b/vibrator/1.4/IVibrator.hal new file mode 100644 index 0000000000..913abe3ed1 --- /dev/null +++ b/vibrator/1.4/IVibrator.hal @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package android.hardware.vibrator@1.4; + +import @1.0::EffectStrength; +import @1.3::Effect; +import @1.0::Status; +import @1.3::IVibrator; +import IVibratorCallback; + +interface IVibrator extends @1.3::IVibrator { + /** + * Determine capabilities of the vibrator HAL. + */ + getCapabilities() generates (bitfield capabilities); + + /** + * Turn on vibrator + * + * This function must only be called after the previous timeout has expired or + * was canceled (through off()). + * @param timeoutMs number of milliseconds to vibrate. + * @param callback A callback used to inform Frameworks of state change, if supported. + * @return vibratorOnRet whether vibrator command was successful or not. + */ + on_1_4(uint32_t timeoutMs, IVibratorCallback callback) generates (Status vibratorOnRet); + + /** + * Fire off a predefined haptic event. + * + * @param effect The type of haptic event to trigger. + * @param strength The intensity of haptic event to trigger. + * @param callback A callback used to inform Frameworks of state change, if supported. + * @return status Whether the effect was successfully performed or not. Must + * return Status::UNSUPPORTED_OPERATION if the effect is not supported. + * @return lengthMs The length of time the event is expected to take in + * milliseconds. This doesn't need to be perfectly accurate, but should be a reasonable + * approximation. Should be a positive, non-zero value if the returned status is Status::OK, + * and set to 0 otherwise. + */ + perform_1_4(Effect effect, EffectStrength strength, IVibratorCallback callback) + generates (Status status, uint32_t lengthMs); +}; diff --git a/vibrator/1.4/IVibratorCallback.hal b/vibrator/1.4/IVibratorCallback.hal new file mode 100644 index 0000000000..76281bc589 --- /dev/null +++ b/vibrator/1.4/IVibratorCallback.hal @@ -0,0 +1,21 @@ +/* + * 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. + */ + +package android.hardware.vibrator@1.4; + +interface IVibratorCallback { + oneway onComplete(); +}; diff --git a/vibrator/1.4/types.hal b/vibrator/1.4/types.hal new file mode 100644 index 0000000000..acc49b15c0 --- /dev/null +++ b/vibrator/1.4/types.hal @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package android.hardware.vibrator@1.4; + +enum Capabilities : uint32_t { + ON_COMPLETION_CALLBACK = 1 << 0, + PERFORM_COMPLETION_CALLBACK = 1 << 1, +}; From 5a7b67ab8fafd171f07d0ba99338f85c42993e0f Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Thu, 8 Aug 2019 14:08:31 +0100 Subject: [PATCH 0137/1022] Create NNAPI HAL v1.3 and add TENSOR_QUANT8_ASYMM_SIGNED OperandType Bug: 137828494 Bug: 139120468 Bug: 136735770 Test: mma Change-Id: I1f615047d1c0c208a90082ffb6ffc43f252f77b4 --- current.txt | 2 + neuralnetworks/1.2/vts/functional/Android.bp | 1 + neuralnetworks/1.3/Android.bp | 21 ++ neuralnetworks/1.3/IDevice.hal | 171 +++++++++ neuralnetworks/1.3/types.hal | 361 +++++++++++++++++++ 5 files changed, 556 insertions(+) create mode 100644 neuralnetworks/1.3/Android.bp create mode 100644 neuralnetworks/1.3/IDevice.hal create mode 100644 neuralnetworks/1.3/types.hal diff --git a/current.txt b/current.txt index 0718b16a42..8b488ea71f 100644 --- a/current.txt +++ b/current.txt @@ -581,6 +581,8 @@ fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardwar fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface # HALs released in Android R +34515afa2bb792d3c6d8495a5f5d907d179c8507ca5e55c10050d02ae1d516ef android.hardware.neuralnetworks@1.3::IDevice +e2d20d4eb24f40b44a3766d05f77052581cb3f4df35fb48c0cc5d9cdcf5c872e android.hardware.neuralnetworks@1.3::types 04395b26be33db17747c3d3b0e8066d323f891ff4f9f3b3ddb490b2f3f844a18 android.hardware.wifi@1.4::IWifi 270f0eb670dfd9bc5cd718e09711f2534fa8425f54d06c1a46523ca156b509e2 android.hardware.wifi.supplicant@1.3::ISupplicant dd4b7cfbb6e1c6ff011c33920762ad89dd02240c63a4d3a3d5037f154eae3e3b android.hardware.wifi.supplicant@1.3::ISupplicantStaIface diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index 3ba8879ae9..bfb871986b 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -37,6 +37,7 @@ cc_test { "android.hardware.neuralnetworks@1.0", "android.hardware.neuralnetworks@1.1", "android.hardware.neuralnetworks@1.2", + "android.hardware.neuralnetworks@1.3", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "libgmock", diff --git a/neuralnetworks/1.3/Android.bp b/neuralnetworks/1.3/Android.bp new file mode 100644 index 0000000000..0615ec67dd --- /dev/null +++ b/neuralnetworks/1.3/Android.bp @@ -0,0 +1,21 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.neuralnetworks@1.3", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IDevice.hal", + ], + interfaces: [ + "android.hardware.neuralnetworks@1.0", + "android.hardware.neuralnetworks@1.1", + "android.hardware.neuralnetworks@1.2", + "android.hidl.base@1.0", + "android.hidl.safe_union@1.0", + ], + gen_java: false, +} diff --git a/neuralnetworks/1.3/IDevice.hal b/neuralnetworks/1.3/IDevice.hal new file mode 100644 index 0000000000..ee36fb4e51 --- /dev/null +++ b/neuralnetworks/1.3/IDevice.hal @@ -0,0 +1,171 @@ +/* + * 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. + */ + +package android.hardware.neuralnetworks@1.3; + +import @1.0::ErrorStatus; +import @1.1::ExecutionPreference; +import @1.2::Constant; +import @1.2::DeviceType; +import @1.2::Extension; +import @1.2::IDevice; +import @1.2::IPreparedModelCallback; + +/** + * This interface represents a device driver. + */ +interface IDevice extends @1.2::IDevice { + /** + * Gets the capabilities of a driver. + * + * @return status Error status of the call, must be: + * - NONE if successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * @return capabilities Capabilities of the driver. + */ + getCapabilities_1_3() generates (ErrorStatus status, Capabilities capabilities); + + /** + * Gets the supported operations in a model. + * + * getSupportedOperations indicates which operations of a model are fully + * supported by the vendor driver. If an operation may not be supported for + * any reason, getSupportedOperations must return false for that operation. + * + * @param model A model whose operations--and their corresponding operands-- + * are to be verified by the driver. + * @return status Error status of the call, must be: + * - NONE if successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if provided model is invalid + * @return supportedOperations A list of supported operations, where true + * indicates the operation is supported and false indicates the + * operation is not supported. The index of "supported" corresponds with + * the index of the operation it is describing. + */ + getSupportedOperations_1_3(Model model) + generates (ErrorStatus status, vec supportedOperations); + + /** + * Asynchronously creates a prepared model for execution and optionally + * saves it into cache files. + * + * prepareModel is used to make any necessary transformations to or + * alternative representations to a model for execution, possibly including + * transformations on the constant data, optimization on the model's graph, + * or compilation into the device's native binary format. The model itself + * is not changed. + * + * Optionally, caching information may be provided for the driver to save + * the prepared model to cache files for faster model compilation time when + * the same model preparation is requested in the future. There are two + * types of cache file handles provided to the driver: model cache and data + * cache. For more information on the two types of cache handles, refer to + * getNumberOfCacheFilesNeeded. + * + * The file descriptors must be opened with read and write permission. A + * file may have any size, and the corresponding file descriptor may have + * any offset. The driver must truncate a file to zero size before writing + * to that file. The file descriptors may be closed by the client once the + * asynchronous preparation has finished. The driver must dup a file + * descriptor if it wants to get access to the cache file later. + * + * The model is prepared asynchronously with respect to the caller. The + * prepareModel function must verify the inputs to the preparedModel + * function related to preparing the model (as opposed to saving the + * prepared model to cache) are correct. If there is an error, prepareModel + * must immediately invoke the callback with the appropriate ErrorStatus + * value and nullptr for the IPreparedModel, then return with the same + * ErrorStatus. If the inputs to the prepareModel function that are related + * to preparing the model are valid and there is no error, prepareModel must + * launch an asynchronous task to prepare the model in the background, and + * immediately return from prepareModel with ErrorStatus::NONE. If the + * asynchronous task fails to launch, prepareModel must immediately invoke + * the callback with ErrorStatus::GENERAL_FAILURE and nullptr for the + * IPreparedModel, then return with ErrorStatus::GENERAL_FAILURE. + * + * When the asynchronous task has finished preparing the model, it must + * immediately invoke the callback function provided as an input to + * prepareModel. If the model was prepared successfully, the callback object + * must be invoked with an error status of ErrorStatus::NONE and the + * produced IPreparedModel object. If an error occurred preparing the model, + * the callback object must be invoked with the appropriate ErrorStatus + * value and nullptr for the IPreparedModel. + * + * Optionally, the driver may save the prepared model to cache during the + * asynchronous preparation. Any error that occurs when saving to cache must + * not affect the status of preparing the model. Even if the input arguments + * related to the cache may be invalid, or the driver may fail to save to + * cache, the prepareModel function must finish preparing the model. The + * driver may choose not to save to cache even if the caching information is + * provided and valid. + * + * The only information that may be unknown to the model at this stage is + * the shape of the tensors, which may only be known at execution time. As + * such, some driver services may return partially prepared models, where + * the prepared model may only be finished when it is paired with a set of + * inputs to the model. Note that the same prepared model object may be used + * with different shapes of inputs on different (possibly concurrent) + * executions. + * + * Multiple threads may call prepareModel on the same model concurrently. + * + * @param model The model to be prepared for execution. + * @param preference Indicates the intended execution behavior of a prepared + * model. + * @param modelCache A vector of handles with each entry holding exactly one + * cache file descriptor for the security-sensitive cache. The length of + * the vector must either be 0 indicating that caching information is + * not provided, or match the numModelCache returned from + * getNumberOfCacheFilesNeeded. The cache handles will be provided in + * the same order when retrieving the preparedModel from cache files + * with prepareModelFromCache. + * @param dataCache A vector of handles with each entry holding exactly one + * cache file descriptor for the constants' cache. The length of the + * vector must either be 0 indicating that caching information is not + * provided, or match the numDataCache returned from + * getNumberOfCacheFilesNeeded. The cache handles will be provided in + * the same order when retrieving the preparedModel from cache files + * with prepareModelFromCache. + * @param token A caching token of length Constant::BYTE_SIZE_OF_CACHE_TOKEN + * identifying the prepared model. The same token will be provided when + * retrieving the prepared model from the cache files with + * prepareModelFromCache. Tokens should be chosen to have a low rate of + * collision for a particular application. The driver cannot detect a + * collision; a collision will result in a failed execution or in a + * successful execution that produces incorrect output values. If both + * modelCache and dataCache are empty indicating that caching + * information is not provided, this token must be ignored. + * @param callback A callback object used to return the error status of + * preparing the model for execution and the prepared model if + * successful, nullptr otherwise. The callback object's notify function + * must be called exactly once, even if the model could not be prepared. + * @return status Error status of launching a task which prepares the model + * in the background; must be: + * - NONE if preparation task is successfully launched + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if one of the input arguments related to preparing + * the model is invalid + */ + prepareModel_1_3(Model model, ExecutionPreference preference, + vec modelCache, vec dataCache, + uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token, + IPreparedModelCallback callback) + generates (ErrorStatus status); +}; diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal new file mode 100644 index 0000000000..db5dd51017 --- /dev/null +++ b/neuralnetworks/1.3/types.hal @@ -0,0 +1,361 @@ +/* + * 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. + */ + +package android.hardware.neuralnetworks@1.3; + +import @1.0::DataLocation; +import @1.0::OperandLifeTime; +import @1.0::PerformanceInfo; +import @1.2::OperandType; +import @1.2::OperationType; +import @1.2::SymmPerChannelQuantParams; + +import android.hidl.safe_union@1.0::Monostate; + +/** + * NOTE: Since NNAPI 1.2, OEM operation and data type are deprecated. Extensions + * are the preferred alternative. + * + * NOTE: Adding a new fundamental type requires updating the value of + * OperandTypeRange::FUNDAMENTAL_MAX. + */ +enum OperandType : @1.2::OperandType { + /** + * A tensor of 8 bit signed integers that represent real numbers. + * + * Attached to this tensor are two numbers that can be used to convert the + * 8 bit integer to the real value and vice versa. These two numbers are: + * - scale: a 32 bit floating point value greater than zero. + * - zeroPoint: a 32 bit integer, in range [-128, 127]. + * + * The formula is: + * real_value = (integer_value - zeroPoint) * scale. + * + * Available since API level 30. + */ + TENSOR_QUANT8_ASYMM_SIGNED = 14, +}; + +/** + * The range of operand values in the OperandType enum. + */ +enum OperandTypeRange : uint32_t { + BASE_MIN = 0, + FUNDAMENTAL_MIN = 0, + FUNDAMENTAL_MAX = 14, + OEM_MIN = 10000, + OEM_MAX = 10001, + BASE_MAX = 0xFFFF, +}; + + +/** + * The capabilities of a driver. + * + * Performance of an operation comes from the type of its first operand. + * This represents performance for non extension operand types. + */ +struct Capabilities { + /** + * Driver performance when operating on float32 data but performing + * calculations with range and/or precision as low as that of the IEEE + * 754 16-bit floating-point format. + */ + PerformanceInfo relaxedFloat32toFloat16PerformanceScalar; + PerformanceInfo relaxedFloat32toFloat16PerformanceTensor; + + /** + * Driver performance when operating on a particular data type. + * In the case of float32 data, this is used when the calculations + * are not relaxed. + */ + struct OperandPerformance { + OperandType type; + PerformanceInfo info; + }; + + /** + * Performance by operand type. Must be sorted by OperandType. + * If a particular OperandType is not present in operandPerformance, + * its performance is treated as + * { .execTime = FLT_MAX, .powerUsage = FLT_MAX }. + */ + vec operandPerformance; +}; + +/** + * Describes one operand of the model's graph. + */ +struct Operand { + /** + * The data type. + * + * Besides the values listed in {@link OperandType}, any value above + * {@link OperandTypeRange::BASE_MAX} is possible and should be interpreted + * as an extension type according to {@link Model::extensionNameToPrefix}. + */ + OperandType type; + + /** + * Dimensions of the operand. + * + * For a scalar operand, dimensions.size() must be 0. + * + * A tensor operand with all dimensions specified has "fully + * specified" dimensions. Whenever possible (i.e., whenever the + * dimensions are known at model construction time), a tensor + * operand should have (but is not required to have) fully + * specified dimensions, in order to enable the best possible + * performance. + * + * 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. + * + * In the following situations, a tensor operand's dimensions must + * be fully specified: + * + * . The operand has lifetime CONSTANT_COPY or + * CONSTANT_REFERENCE. + * + * . The operand has lifetime MODEL_INPUT. 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 + * (by setting the hasNoValue field of the corresponding + * RequestArgument to true) then it need not have fully + * specified dimensions. + * + * A tensor operand with some number of unspecified dimensions is + * represented by setting each unspecified dimension to 0. + * + * A tensor operand with unspecified rank is represented by providing + * an empty dimensions vector. + */ + vec dimensions; + + /** + * The number of times this operand appears as an operation input. + * + * (For example, if this operand appears once in one operation's + * input list, and three times in another operation's input list, + * then numberOfConsumers = 4.) + */ + uint32_t numberOfConsumers; + + /** + * Quantized scale of the operand. + * + * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM or + * TENSOR_INT32. + */ + float scale; + + /** + * Quantized zero-point offset of the operand. + * + * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM. + */ + int32_t zeroPoint; + + /** + * How the operand is used. + */ + OperandLifeTime lifetime; + + /** + * Where to find the data for this operand. + * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or + * NO_VALUE: + * - All the fields must be 0. + * If the lifetime is CONSTANT_COPY: + * - location.poolIndex is 0. + * - location.offset is the offset in bytes into Model.operandValues. + * - location.length is set. + * If the lifetime is CONSTANT_REFERENCE: + * - location.poolIndex is set. + * - location.offset is the offset in bytes into the specified pool. + * - location.length is set. + */ + DataLocation location; + + /** + * Additional parameters specific to a particular operand type. + */ + safe_union ExtraParams { + /** + * No additional parameters. + */ + Monostate none; + + /** + * Symmetric per-channel quantization parameters. + * + * Only applicable to operands of type TENSOR_QUANT8_SYMM_PER_CHANNEL. + */ + SymmPerChannelQuantParams channelQuant; + + /** + * Extension operand parameters. + * + * The framework treats this as an opaque data blob. + * The format is up to individual extensions. + */ + vec extension; + } extraParams; +}; + +/** + * Describes one operation of the model's graph. + */ +struct Operation { + /** + * The operation type. + */ + OperationType type; + + /** + * Describes the table that contains the indexes of the inputs of the + * operation. The offset is the index in the operandIndexes table. + */ + vec inputs; + + /** + * Describes the table that contains the indexes of the outputs of the + * operation. The offset is the index in the operandIndexes table. + */ + vec outputs; +}; + +/** + * A Neural Network Model. + * + * This includes not only the execution graph, but also constant data such as + * weights or scalars added at construction time. The only information that + * may not be known is the shape of the input tensors. + */ +struct Model { + /** + * All operands included in the model. + */ + vec operands; + + /** + * All operations included in the model. + * + * The operations are sorted into execution order. Every operand + * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be + * written before it is read. + */ + vec operations; + + /** + * Input indexes of the model. There must be at least one. + * + * Each value corresponds to the index of the operand in "operands". + */ + vec inputIndexes; + + /** + * Output indexes of the model. There must be at least one. + * + * Each value corresponds to the index of the operand in "operands". + */ + vec outputIndexes; + + /** + * A byte buffer containing operand data that were copied into the model. + * + * An operand's value must be located here if and only if Operand::lifetime + * equals OperandLifeTime::CONSTANT_COPY. + */ + vec operandValues; + + /** + * A collection of shared memory pools containing operand values. + * + * An operand's value must be located here if and only if Operand::lifetime + * equals OperandLifeTime::CONSTANT_REFERENCE. + */ + vec pools; + + /** + * 'true' indicates TENSOR_FLOAT32 may be calculated with range and/or + * precision as low as that of the IEEE 754 16-bit floating-point format. + * 'false' indicates TENSOR_FLOAT32 must be calculated using at least the + * range and precision of the IEEE 754 32-bit floating-point format. + */ + bool relaxComputationFloat32toFloat16; + + /** + * The mapping between extension names and prefixes of operand and + * operation type values. + * + * An operand or operation whose numeric type value is above + * {@link OperandTypeRange::BASE_MAX} or + * {@link OperationTypeRange::BASE_MAX} respectively should be interpreted + * as an extension operand. The low + * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value + * correspond to the type ID within the extension and the high + * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode + * the "prefix", which maps uniquely to the extension name. + * + * For example, if a model contains an operation whose value is + * 0xAAAABBBB and extensionNameToPrefix contains an entry with + * prefix=0xAAAA and name="vendor.test.test_extension", then + * the operation should be interpreted as the operation 0xBBBB + * of the extension named vendor.test.test_extension. + * + * This is a one-to-one correspondence. That is, there must be at most one + * prefix corresponding to each extension name and at most one extension + * name corresponding to each prefix. + */ + vec extensionNameToPrefix; + + /** + * A correspondence between an extension name and a prefix of operand and + * operation type values. + */ + struct ExtensionNameAndPrefix { + /** + * The extension name. + * + * See {@link Extension::name} for the format specification. + */ + string name; + + /** + * The unique extension identifier within the model. + * + * See {@link Model::extensionNameToPrefix}. + */ + uint16_t prefix; + }; + + /** + * Numeric values of extension operand and operation types have the + * following structure: + * - 16 high bits represent the "prefix", which corresponds uniquely to the + * extension name. + * - 16 low bits represent the type ID within the extension. + */ + enum ExtensionTypeEncoding : uint8_t { + HIGH_BITS_PREFIX = 16, + LOW_BITS_TYPE = 16, + }; +}; From 3b13b55ac1532647ee6f261489d23ca4269c1440 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Fri, 30 Aug 2019 11:35:34 +0100 Subject: [PATCH 0138/1022] Copy VTS tests from v1.2 to v1.3 So that it's easier to see what actually has changed in VTS tests for version 1.3 Bug: 139120468 Test: m Change-Id: Ief294d21349ca6531595612a16fa3ae3382f83ac --- neuralnetworks/1.3/vts/OWNERS | 16 + .../1.3/vts/functional/BasicTests.cpp | 114 ++ .../1.3/vts/functional/Callbacks.cpp | 143 ++ .../functional/CompilationCachingTests.cpp | 1374 +++++++++++++++++ .../vts/functional/GeneratedTestHarness.cpp | 408 +++++ .../1.3/vts/functional/GeneratedTestHarness.h | 65 + .../1.3/vts/functional/TestAssertions.cpp | 141 ++ .../1.3/vts/functional/ValidateBurst.cpp | 400 +++++ .../1.3/vts/functional/ValidateModel.cpp | 713 +++++++++ .../1.3/vts/functional/ValidateRequest.cpp | 168 ++ .../vts/functional/VtsHalNeuralnetworks.cpp | 171 ++ .../1.3/vts/functional/VtsHalNeuralnetworks.h | 57 + .../vts/functional/include/1.2/Callbacks.h | 325 ++++ 13 files changed, 4095 insertions(+) create mode 100644 neuralnetworks/1.3/vts/OWNERS create mode 100644 neuralnetworks/1.3/vts/functional/BasicTests.cpp create mode 100644 neuralnetworks/1.3/vts/functional/Callbacks.cpp create mode 100644 neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp create mode 100644 neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp create mode 100644 neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h create mode 100644 neuralnetworks/1.3/vts/functional/TestAssertions.cpp create mode 100644 neuralnetworks/1.3/vts/functional/ValidateBurst.cpp create mode 100644 neuralnetworks/1.3/vts/functional/ValidateModel.cpp create mode 100644 neuralnetworks/1.3/vts/functional/ValidateRequest.cpp create mode 100644 neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp create mode 100644 neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h create mode 100644 neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h diff --git a/neuralnetworks/1.3/vts/OWNERS b/neuralnetworks/1.3/vts/OWNERS new file mode 100644 index 0000000000..b5a8e1f473 --- /dev/null +++ b/neuralnetworks/1.3/vts/OWNERS @@ -0,0 +1,16 @@ +# Neuralnetworks team +butlermichael@google.com +dgross@google.com +jeanluc@google.com +levp@google.com +miaowang@google.com +mikie@google.com +mks@google.com +pszczepaniak@google.com +slavash@google.com +vddang@google.com +xusongw@google.com + +# VTS team +yim@google.com +yuexima@google.com diff --git a/neuralnetworks/1.3/vts/functional/BasicTests.cpp b/neuralnetworks/1.3/vts/functional/BasicTests.cpp new file mode 100644 index 0000000000..8e82c5376e --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/BasicTests.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test" + +#include "VtsHalNeuralnetworks.h" + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using V1_0::DeviceStatus; +using V1_0::ErrorStatus; +using V1_0::PerformanceInfo; + +// create device test +TEST_P(NeuralnetworksHidlTest, CreateDevice) {} + +// status test +TEST_P(NeuralnetworksHidlTest, StatusTest) { + Return status = kDevice->getStatus(); + ASSERT_TRUE(status.isOk()); + EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast(status)); +} + +// initialization +TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) { + using OperandPerformance = Capabilities::OperandPerformance; + Return ret = kDevice->getCapabilities_1_2([](ErrorStatus status, + const Capabilities& capabilities) { + EXPECT_EQ(ErrorStatus::NONE, status); + + auto isPositive = [](const PerformanceInfo& perf) { + return perf.execTime > 0.0f && perf.powerUsage > 0.0f; + }; + + EXPECT_TRUE(isPositive(capabilities.relaxedFloat32toFloat16PerformanceScalar)); + EXPECT_TRUE(isPositive(capabilities.relaxedFloat32toFloat16PerformanceTensor)); + const auto& opPerf = capabilities.operandPerformance; + EXPECT_TRUE(std::all_of( + opPerf.begin(), opPerf.end(), + [isPositive](const OperandPerformance& a) { return isPositive(a.info); })); + EXPECT_TRUE(std::is_sorted(opPerf.begin(), opPerf.end(), + [](const OperandPerformance& a, const OperandPerformance& b) { + return a.type < b.type; + })); + }); + EXPECT_TRUE(ret.isOk()); +} + +// device version test +TEST_P(NeuralnetworksHidlTest, GetDeviceVersionStringTest) { + Return ret = + kDevice->getVersionString([](ErrorStatus status, const hidl_string& version) { + EXPECT_EQ(ErrorStatus::NONE, status); + EXPECT_LT(0, version.size()); + }); + EXPECT_TRUE(ret.isOk()); +} + +// device type test +TEST_P(NeuralnetworksHidlTest, GetDeviceTypeTest) { + Return ret = kDevice->getType([](ErrorStatus status, DeviceType type) { + EXPECT_EQ(ErrorStatus::NONE, status); + EXPECT_TRUE(type == DeviceType::OTHER || type == DeviceType::CPU || + type == DeviceType::GPU || type == DeviceType::ACCELERATOR); + }); + EXPECT_TRUE(ret.isOk()); +} + +// device supported extensions test +TEST_P(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) { + Return ret = kDevice->getSupportedExtensions( + [](ErrorStatus status, const hidl_vec& extensions) { + EXPECT_EQ(ErrorStatus::NONE, status); + for (auto& extension : extensions) { + std::string extensionName = extension.name; + EXPECT_FALSE(extensionName.empty()); + for (char c : extensionName) { + EXPECT_TRUE(('a' <= c && c <= 'z') || ('0' <= c && c <= '9') || c == '_' || + c == '.') + << "Extension name contains an illegal character: " << c; + } + EXPECT_NE(extensionName.find('.'), std::string::npos) + << "Extension name must start with the reverse domain name of the " + "vendor"; + } + }); + EXPECT_TRUE(ret.isOk()); +} + +// getNumberOfCacheFilesNeeded test +TEST_P(NeuralnetworksHidlTest, getNumberOfCacheFilesNeeded) { + Return ret = kDevice->getNumberOfCacheFilesNeeded( + [](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) { + EXPECT_EQ(ErrorStatus::NONE, status); + EXPECT_LE(numModelCache, + static_cast(Constant::MAX_NUMBER_OF_CACHE_FILES)); + EXPECT_LE(numDataCache, static_cast(Constant::MAX_NUMBER_OF_CACHE_FILES)); + }); + EXPECT_TRUE(ret.isOk()); +} +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/Callbacks.cpp b/neuralnetworks/1.3/vts/functional/Callbacks.cpp new file mode 100644 index 0000000000..3972ad6ff2 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/Callbacks.cpp @@ -0,0 +1,143 @@ +/* + * 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 "Callbacks" + +#include "1.2/Callbacks.h" + +#include + +#include + +namespace android::hardware::neuralnetworks::V1_2::implementation { + +using V1_0::ErrorStatus; + +constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits::max(), + .timeInDriver = std::numeric_limits::max()}; + +// PreparedModelCallback methods begin here + +Return PreparedModelCallback::notify(ErrorStatus errorStatus, + const sp& preparedModel) { + { + std::lock_guard hold(mMutex); + + // quick-return if object has already been notified + if (mNotified) { + return Void(); + } + + // store results and mark as notified + mErrorStatus = errorStatus; + mPreparedModel = preparedModel; + mNotified = true; + } + + mCondition.notify_all(); + return Void(); +} + +Return PreparedModelCallback::notify_1_2(ErrorStatus errorStatus, + const sp& preparedModel) { + return notify(errorStatus, preparedModel); +} + +void PreparedModelCallback::wait() const { + std::unique_lock lock(mMutex); + mCondition.wait(lock, [this] { return mNotified; }); +} + +ErrorStatus PreparedModelCallback::getStatus() const { + wait(); + return mErrorStatus; +} + +sp PreparedModelCallback::getPreparedModel() const { + wait(); + return mPreparedModel; +} + +// ExecutionCallback methods begin here + +Return ExecutionCallback::notify(ErrorStatus errorStatus) { + notifyInternal(errorStatus, {}, kNoTiming); + return Void(); +} + +Return ExecutionCallback::notify_1_2(ErrorStatus errorStatus, + const hidl_vec& outputShapes, + const Timing& timing) { + if (errorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { + // outputShapes must not be empty if OUTPUT_INSUFFICIENT_SIZE. + if (outputShapes.size() == 0) { + LOG(ERROR) << "Notified with empty output shape vector when OUTPUT_INSUFFICIENT_SIZE"; + notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + return Void(); + } + } else if (errorStatus != ErrorStatus::NONE) { + // outputShapes must be empty if errorStatus is neither NONE nor OUTPUT_INSUFFICIENT_SIZE. + if (outputShapes.size() != 0) { + LOG(ERROR) << "Notified with non-empty output shape vector when error status is " + "neither NONE nor OUTPUT_INSUFFICIENT_SIZE"; + notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + return Void(); + } + } + notifyInternal(errorStatus, outputShapes, timing); + return Void(); +} + +void ExecutionCallback::wait() const { + std::unique_lock lock(mMutex); + mCondition.wait(lock, [this] { return mNotified; }); +} + +ErrorStatus ExecutionCallback::getStatus() const { + wait(); + return mErrorStatus; +} + +const std::vector& ExecutionCallback::getOutputShapes() const { + wait(); + return mOutputShapes; +} + +Timing ExecutionCallback::getTiming() const { + wait(); + return mTiming; +} + +void ExecutionCallback::notifyInternal(ErrorStatus errorStatus, + const hidl_vec& outputShapes, + const Timing& timing) { + { + std::lock_guard hold(mMutex); + + // quick-return if object has already been notified + if (mNotified) { + return; + } + + mErrorStatus = errorStatus; + mOutputShapes = outputShapes; + mTiming = timing; + mNotified = true; + } + mCondition.notify_all(); +} + +} // namespace android::hardware::neuralnetworks::V1_2::implementation diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp new file mode 100644 index 0000000000..2130a76b75 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp @@ -0,0 +1,1374 @@ +/* + * 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 "neuralnetworks_hidl_hal_test" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "1.2/Callbacks.h" +#include "GeneratedTestHarness.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "Utils.h" +#include "VtsHalNeuralnetworks.h" + +// Forward declaration of the mobilenet generated test models in +// frameworks/ml/nn/runtime/test/generated/. +namespace generated_tests::mobilenet_224_gender_basic_fixed { +const test_helper::TestModel& get_test_model(); +} // namespace generated_tests::mobilenet_224_gender_basic_fixed + +namespace generated_tests::mobilenet_quantized { +const test_helper::TestModel& get_test_model(); +} // namespace generated_tests::mobilenet_quantized + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using namespace test_helper; +using implementation::PreparedModelCallback; +using V1_0::ErrorStatus; +using V1_1::ExecutionPreference; + +namespace float32_model { + +constexpr auto get_test_model = generated_tests::mobilenet_224_gender_basic_fixed::get_test_model; + +} // namespace float32_model + +namespace quant8_model { + +constexpr auto get_test_model = generated_tests::mobilenet_quantized::get_test_model; + +} // namespace quant8_model + +namespace { + +enum class AccessMode { READ_WRITE, READ_ONLY, WRITE_ONLY }; + +// Creates cache handles based on provided file groups. +// The outer vector corresponds to handles and the inner vector is for fds held by each handle. +void createCacheHandles(const std::vector>& fileGroups, + const std::vector& mode, hidl_vec* handles) { + handles->resize(fileGroups.size()); + for (uint32_t i = 0; i < fileGroups.size(); i++) { + std::vector fds; + for (const auto& file : fileGroups[i]) { + int fd; + if (mode[i] == AccessMode::READ_ONLY) { + fd = open(file.c_str(), O_RDONLY); + } else if (mode[i] == AccessMode::WRITE_ONLY) { + fd = open(file.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + } else if (mode[i] == AccessMode::READ_WRITE) { + fd = open(file.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + } else { + FAIL(); + } + ASSERT_GE(fd, 0); + fds.push_back(fd); + } + native_handle_t* cacheNativeHandle = native_handle_create(fds.size(), 0); + ASSERT_NE(cacheNativeHandle, nullptr); + std::copy(fds.begin(), fds.end(), &cacheNativeHandle->data[0]); + (*handles)[i].setTo(cacheNativeHandle, /*shouldOwn=*/true); + } +} + +void createCacheHandles(const std::vector>& fileGroups, AccessMode mode, + hidl_vec* handles) { + createCacheHandles(fileGroups, std::vector(fileGroups.size(), mode), handles); +} + +// Create a chain of broadcast operations. The second operand is always constant tensor [1]. +// For simplicity, activation scalar is shared. The second operand is not shared +// in the model to let driver maintain a non-trivial size of constant data and the corresponding +// data locations in cache. +// +// --------- activation -------- +// ↓ ↓ ↓ ↓ +// E.g. input -> ADD -> ADD -> ADD -> ... -> ADD -> output +// ↑ ↑ ↑ ↑ +// [1] [1] [1] [1] +// +// This function assumes the operation is either ADD or MUL. +template +TestModel createLargeTestModelImpl(TestOperationType op, uint32_t len) { + EXPECT_TRUE(op == TestOperationType::ADD || op == TestOperationType::MUL); + + // Model operations and operands. + std::vector operations(len); + std::vector operands(len * 2 + 2); + + // The activation scalar, value = 0. + operands[0] = { + .type = TestOperandType::INT32, + .dimensions = {}, + .numberOfConsumers = len, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = TestOperandLifeTime::CONSTANT_COPY, + .data = TestBuffer::createFromVector({0}), + }; + + // The buffer value of the constant second operand. The logical value is always 1.0f. + CppType bufferValue; + // The scale of the first and second operand. + float scale1, scale2; + if (operandType == TestOperandType::TENSOR_FLOAT32) { + bufferValue = 1.0f; + scale1 = 0.0f; + scale2 = 0.0f; + } else if (op == TestOperationType::ADD) { + bufferValue = 1; + scale1 = 1.0f; + scale2 = 1.0f; + } else { + // To satisfy the constraint on quant8 MUL: input0.scale * input1.scale < output.scale, + // set input1 to have scale = 0.5f and bufferValue = 2, i.e. 1.0f in floating point. + bufferValue = 2; + scale1 = 1.0f; + scale2 = 0.5f; + } + + for (uint32_t i = 0; i < len; i++) { + const uint32_t firstInputIndex = i * 2 + 1; + const uint32_t secondInputIndex = firstInputIndex + 1; + const uint32_t outputIndex = secondInputIndex + 1; + + // The first operation input. + operands[firstInputIndex] = { + .type = operandType, + .dimensions = {1}, + .numberOfConsumers = 1, + .scale = scale1, + .zeroPoint = 0, + .lifetime = (i == 0 ? TestOperandLifeTime::MODEL_INPUT + : TestOperandLifeTime::TEMPORARY_VARIABLE), + .data = (i == 0 ? TestBuffer::createFromVector({1}) : TestBuffer()), + }; + + // The second operation input, value = 1. + operands[secondInputIndex] = { + .type = operandType, + .dimensions = {1}, + .numberOfConsumers = 1, + .scale = scale2, + .zeroPoint = 0, + .lifetime = TestOperandLifeTime::CONSTANT_COPY, + .data = TestBuffer::createFromVector({bufferValue}), + }; + + // The operation. All operations share the same activation scalar. + // The output operand is created as an input in the next iteration of the loop, in the case + // of all but the last member of the chain; and after the loop as a model output, in the + // case of the last member of the chain. + operations[i] = { + .type = op, + .inputs = {firstInputIndex, secondInputIndex, /*activation scalar*/ 0}, + .outputs = {outputIndex}, + }; + } + + // For TestOperationType::ADD, output = 1 + 1 * len = len + 1 + // For TestOperationType::MUL, output = 1 * 1 ^ len = 1 + CppType outputResult = static_cast(op == TestOperationType::ADD ? len + 1u : 1u); + + // The model output. + operands.back() = { + .type = operandType, + .dimensions = {1}, + .numberOfConsumers = 0, + .scale = scale1, + .zeroPoint = 0, + .lifetime = TestOperandLifeTime::MODEL_OUTPUT, + .data = TestBuffer::createFromVector({outputResult}), + }; + + return { + .operands = std::move(operands), + .operations = std::move(operations), + .inputIndexes = {1}, + .outputIndexes = {len * 2 + 1}, + .isRelaxed = false, + }; +} + +} // namespace + +// Tag for the compilation caching tests. +class CompilationCachingTestBase : public testing::Test { + protected: + CompilationCachingTestBase(sp device, OperandType type) + : kDevice(std::move(device)), kOperandType(type) {} + + void SetUp() override { + testing::Test::SetUp(); + ASSERT_NE(kDevice.get(), nullptr); + + // Create cache directory. The cache directory and a temporary cache file is always created + // to test the behavior of prepareModelFromCache, even when caching is not supported. + char cacheDirTemp[] = "/data/local/tmp/TestCompilationCachingXXXXXX"; + char* cacheDir = mkdtemp(cacheDirTemp); + ASSERT_NE(cacheDir, nullptr); + mCacheDir = cacheDir; + mCacheDir.push_back('/'); + + Return ret = kDevice->getNumberOfCacheFilesNeeded( + [this](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) { + EXPECT_EQ(ErrorStatus::NONE, status); + mNumModelCache = numModelCache; + mNumDataCache = numDataCache; + }); + EXPECT_TRUE(ret.isOk()); + mIsCachingSupported = mNumModelCache > 0 || mNumDataCache > 0; + + // Create empty cache files. + mTmpCache = mCacheDir + "tmp"; + for (uint32_t i = 0; i < mNumModelCache; i++) { + mModelCache.push_back({mCacheDir + "model" + std::to_string(i)}); + } + for (uint32_t i = 0; i < mNumDataCache; i++) { + mDataCache.push_back({mCacheDir + "data" + std::to_string(i)}); + } + // Dummy handles, use AccessMode::WRITE_ONLY for createCacheHandles to create files. + hidl_vec modelHandle, dataHandle, tmpHandle; + createCacheHandles(mModelCache, AccessMode::WRITE_ONLY, &modelHandle); + createCacheHandles(mDataCache, AccessMode::WRITE_ONLY, &dataHandle); + createCacheHandles({{mTmpCache}}, AccessMode::WRITE_ONLY, &tmpHandle); + + if (!mIsCachingSupported) { + LOG(INFO) << "NN VTS: Early termination of test because vendor service does not " + "support compilation caching."; + std::cout << "[ ] Early termination of test because vendor service does not " + "support compilation caching." + << std::endl; + } + } + + void TearDown() override { + // If the test passes, remove the tmp directory. Otherwise, keep it for debugging purposes. + if (!testing::Test::HasFailure()) { + // Recursively remove the cache directory specified by mCacheDir. + auto callback = [](const char* entry, const struct stat*, int, struct FTW*) { + return remove(entry); + }; + nftw(mCacheDir.c_str(), callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS); + } + testing::Test::TearDown(); + } + + // Model and examples creators. According to kOperandType, the following methods will return + // either float32 model/examples or the quant8 variant. + TestModel createTestModel() { + if (kOperandType == OperandType::TENSOR_FLOAT32) { + return float32_model::get_test_model(); + } else { + return quant8_model::get_test_model(); + } + } + + TestModel createLargeTestModel(OperationType op, uint32_t len) { + if (kOperandType == OperandType::TENSOR_FLOAT32) { + return createLargeTestModelImpl( + static_cast(op), len); + } else { + return createLargeTestModelImpl( + static_cast(op), len); + } + } + + // See if the service can handle the model. + bool isModelFullySupported(const Model& model) { + bool fullySupportsModel = false; + Return supportedCall = kDevice->getSupportedOperations_1_2( + model, + [&fullySupportsModel, &model](ErrorStatus status, const hidl_vec& supported) { + ASSERT_EQ(ErrorStatus::NONE, status); + ASSERT_EQ(supported.size(), model.operations.size()); + fullySupportsModel = std::all_of(supported.begin(), supported.end(), + [](bool valid) { return valid; }); + }); + EXPECT_TRUE(supportedCall.isOk()); + return fullySupportsModel; + } + + void saveModelToCache(const Model& model, const hidl_vec& modelCache, + const hidl_vec& dataCache, + sp* preparedModel = nullptr) { + if (preparedModel != nullptr) *preparedModel = nullptr; + + // Launch prepare model. + sp preparedModelCallback = new PreparedModelCallback(); + hidl_array cacheToken(mToken); + Return prepareLaunchStatus = + kDevice->prepareModel_1_2(model, ExecutionPreference::FAST_SINGLE_ANSWER, + modelCache, dataCache, cacheToken, preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + ASSERT_EQ(static_cast(prepareLaunchStatus), ErrorStatus::NONE); + + // Retrieve prepared model. + preparedModelCallback->wait(); + ASSERT_EQ(preparedModelCallback->getStatus(), ErrorStatus::NONE); + if (preparedModel != nullptr) { + *preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel()) + .withDefault(nullptr); + } + } + + bool checkEarlyTermination(ErrorStatus status) { + if (status == ErrorStatus::GENERAL_FAILURE) { + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " + "save the prepared model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "save the prepared model that it does not support." + << std::endl; + return true; + } + return false; + } + + bool checkEarlyTermination(const Model& model) { + if (!isModelFullySupported(model)) { + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " + "prepare model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "prepare model that it does not support." + << std::endl; + return true; + } + return false; + } + + void prepareModelFromCache(const hidl_vec& modelCache, + const hidl_vec& dataCache, + sp* preparedModel, ErrorStatus* status) { + // Launch prepare model from cache. + sp preparedModelCallback = new PreparedModelCallback(); + hidl_array cacheToken(mToken); + Return prepareLaunchStatus = kDevice->prepareModelFromCache( + modelCache, dataCache, cacheToken, preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + if (static_cast(prepareLaunchStatus) != ErrorStatus::NONE) { + *preparedModel = nullptr; + *status = static_cast(prepareLaunchStatus); + return; + } + + // Retrieve prepared model. + preparedModelCallback->wait(); + *status = preparedModelCallback->getStatus(); + *preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel()) + .withDefault(nullptr); + } + + // Absolute path to the temporary cache directory. + std::string mCacheDir; + + // Groups of file paths for model and data cache in the tmp cache directory, initialized with + // outer_size = mNum{Model|Data}Cache, inner_size = 1. The outer vector corresponds to handles + // and the inner vector is for fds held by each handle. + std::vector> mModelCache; + std::vector> mDataCache; + + // A separate temporary file path in the tmp cache directory. + std::string mTmpCache; + + uint8_t mToken[static_cast(Constant::BYTE_SIZE_OF_CACHE_TOKEN)] = {}; + uint32_t mNumModelCache; + uint32_t mNumDataCache; + uint32_t mIsCachingSupported; + + const sp kDevice; + // The primary data type of the testModel. + const OperandType kOperandType; +}; + +using CompilationCachingTestParam = std::tuple; + +// A parameterized fixture of CompilationCachingTestBase. Every test will run twice, with the first +// pass running with float32 models and the second pass running with quant8 models. +class CompilationCachingTest : public CompilationCachingTestBase, + public testing::WithParamInterface { + protected: + CompilationCachingTest() + : CompilationCachingTestBase(getData(std::get(GetParam())), + std::get(GetParam())) {} +}; + +TEST_P(CompilationCachingTest, CacheSavingAndRetrieval) { + // Create test HIDL model and compile. + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + sp preparedModel = nullptr; + + // Save the compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(model, modelCache, dataCache); + } + + // Retrieve preparedModel from cache. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (!mIsCachingSupported) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + return; + } else if (checkEarlyTermination(status)) { + ASSERT_EQ(preparedModel, nullptr); + return; + } else { + ASSERT_EQ(status, ErrorStatus::NONE); + ASSERT_NE(preparedModel, nullptr); + } + } + + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); +} + +TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) { + // Create test HIDL model and compile. + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + sp preparedModel = nullptr; + + // Save the compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + uint8_t dummyBytes[] = {0, 0}; + // Write a dummy integer to the cache. + // The driver should be able to handle non-empty cache and non-zero fd offset. + for (uint32_t i = 0; i < modelCache.size(); i++) { + ASSERT_EQ(write(modelCache[i].getNativeHandle()->data[0], &dummyBytes, + sizeof(dummyBytes)), + sizeof(dummyBytes)); + } + for (uint32_t i = 0; i < dataCache.size(); i++) { + ASSERT_EQ( + write(dataCache[i].getNativeHandle()->data[0], &dummyBytes, sizeof(dummyBytes)), + sizeof(dummyBytes)); + } + saveModelToCache(model, modelCache, dataCache); + } + + // Retrieve preparedModel from cache. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + uint8_t dummyByte = 0; + // Advance the offset of each handle by one byte. + // The driver should be able to handle non-zero fd offset. + for (uint32_t i = 0; i < modelCache.size(); i++) { + ASSERT_GE(read(modelCache[i].getNativeHandle()->data[0], &dummyByte, 1), 0); + } + for (uint32_t i = 0; i < dataCache.size(); i++) { + ASSERT_GE(read(dataCache[i].getNativeHandle()->data[0], &dummyByte, 1), 0); + } + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (!mIsCachingSupported) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + return; + } else if (checkEarlyTermination(status)) { + ASSERT_EQ(preparedModel, nullptr); + return; + } else { + ASSERT_EQ(status, ErrorStatus::NONE); + ASSERT_NE(preparedModel, nullptr); + } + } + + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); +} + +TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { + // Create test HIDL model and compile. + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + + // Test with number of model cache files greater than mNumModelCache. + { + hidl_vec modelCache, dataCache; + // Pass an additional cache file for model cache. + mModelCache.push_back({mTmpCache}); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mModelCache.pop_back(); + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Test with number of model cache files smaller than mNumModelCache. + if (mModelCache.size() > 0) { + hidl_vec modelCache, dataCache; + // Pop out the last cache file. + auto tmp = mModelCache.back(); + mModelCache.pop_back(); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mModelCache.push_back(tmp); + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Test with number of data cache files greater than mNumDataCache. + { + hidl_vec modelCache, dataCache; + // Pass an additional cache file for data cache. + mDataCache.push_back({mTmpCache}); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mDataCache.pop_back(); + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Test with number of data cache files smaller than mNumDataCache. + if (mDataCache.size() > 0) { + hidl_vec modelCache, dataCache; + // Pop out the last cache file. + auto tmp = mDataCache.back(); + mDataCache.pop_back(); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mDataCache.push_back(tmp); + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } +} + +TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumCache) { + // Create test HIDL model and compile. + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + + // Save the compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(model, modelCache, dataCache); + } + + // Test with number of model cache files greater than mNumModelCache. + { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + mModelCache.push_back({mTmpCache}); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mModelCache.pop_back(); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Test with number of model cache files smaller than mNumModelCache. + if (mModelCache.size() > 0) { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + auto tmp = mModelCache.back(); + mModelCache.pop_back(); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mModelCache.push_back(tmp); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Test with number of data cache files greater than mNumDataCache. + { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + mDataCache.push_back({mTmpCache}); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mDataCache.pop_back(); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Test with number of data cache files smaller than mNumDataCache. + if (mDataCache.size() > 0) { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + auto tmp = mDataCache.back(); + mDataCache.pop_back(); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mDataCache.push_back(tmp); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + ASSERT_EQ(preparedModel, nullptr); + } +} + +TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { + // Create test HIDL model and compile. + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + + // Go through each handle in model cache, test with NumFd greater than 1. + for (uint32_t i = 0; i < mNumModelCache; i++) { + hidl_vec modelCache, dataCache; + // Pass an invalid number of fds for handle i. + mModelCache[i].push_back(mTmpCache); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mModelCache[i].pop_back(); + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Go through each handle in model cache, test with NumFd equal to 0. + for (uint32_t i = 0; i < mNumModelCache; i++) { + hidl_vec modelCache, dataCache; + // Pass an invalid number of fds for handle i. + auto tmp = mModelCache[i].back(); + mModelCache[i].pop_back(); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mModelCache[i].push_back(tmp); + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Go through each handle in data cache, test with NumFd greater than 1. + for (uint32_t i = 0; i < mNumDataCache; i++) { + hidl_vec modelCache, dataCache; + // Pass an invalid number of fds for handle i. + mDataCache[i].push_back(mTmpCache); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mDataCache[i].pop_back(); + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Go through each handle in data cache, test with NumFd equal to 0. + for (uint32_t i = 0; i < mNumDataCache; i++) { + hidl_vec modelCache, dataCache; + // Pass an invalid number of fds for handle i. + auto tmp = mDataCache[i].back(); + mDataCache[i].pop_back(); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mDataCache[i].push_back(tmp); + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } +} + +TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumFd) { + // Create test HIDL model and compile. + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + + // Save the compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(model, modelCache, dataCache); + } + + // Go through each handle in model cache, test with NumFd greater than 1. + for (uint32_t i = 0; i < mNumModelCache; i++) { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + mModelCache[i].push_back(mTmpCache); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mModelCache[i].pop_back(); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Go through each handle in model cache, test with NumFd equal to 0. + for (uint32_t i = 0; i < mNumModelCache; i++) { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + auto tmp = mModelCache[i].back(); + mModelCache[i].pop_back(); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mModelCache[i].push_back(tmp); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Go through each handle in data cache, test with NumFd greater than 1. + for (uint32_t i = 0; i < mNumDataCache; i++) { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + mDataCache[i].push_back(mTmpCache); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mDataCache[i].pop_back(); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Go through each handle in data cache, test with NumFd equal to 0. + for (uint32_t i = 0; i < mNumDataCache; i++) { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + auto tmp = mDataCache[i].back(); + mDataCache[i].pop_back(); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mDataCache[i].push_back(tmp); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + ASSERT_EQ(preparedModel, nullptr); + } +} + +TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) { + // Create test HIDL model and compile. + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + std::vector modelCacheMode(mNumModelCache, AccessMode::READ_WRITE); + std::vector dataCacheMode(mNumDataCache, AccessMode::READ_WRITE); + + // Go through each handle in model cache, test with invalid access mode. + for (uint32_t i = 0; i < mNumModelCache; i++) { + hidl_vec modelCache, dataCache; + modelCacheMode[i] = AccessMode::READ_ONLY; + createCacheHandles(mModelCache, modelCacheMode, &modelCache); + createCacheHandles(mDataCache, dataCacheMode, &dataCache); + modelCacheMode[i] = AccessMode::READ_WRITE; + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Go through each handle in data cache, test with invalid access mode. + for (uint32_t i = 0; i < mNumDataCache; i++) { + hidl_vec modelCache, dataCache; + dataCacheMode[i] = AccessMode::READ_ONLY; + createCacheHandles(mModelCache, modelCacheMode, &modelCache); + createCacheHandles(mDataCache, dataCacheMode, &dataCache); + dataCacheMode[i] = AccessMode::READ_WRITE; + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } +} + +TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidAccessMode) { + // Create test HIDL model and compile. + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + std::vector modelCacheMode(mNumModelCache, AccessMode::READ_WRITE); + std::vector dataCacheMode(mNumDataCache, AccessMode::READ_WRITE); + + // Save the compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(model, modelCache, dataCache); + } + + // Go through each handle in model cache, test with invalid access mode. + for (uint32_t i = 0; i < mNumModelCache; i++) { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + modelCacheMode[i] = AccessMode::WRITE_ONLY; + createCacheHandles(mModelCache, modelCacheMode, &modelCache); + createCacheHandles(mDataCache, dataCacheMode, &dataCache); + modelCacheMode[i] = AccessMode::READ_WRITE; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + } + + // Go through each handle in data cache, test with invalid access mode. + for (uint32_t i = 0; i < mNumDataCache; i++) { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + dataCacheMode[i] = AccessMode::WRITE_ONLY; + createCacheHandles(mModelCache, modelCacheMode, &modelCache); + createCacheHandles(mDataCache, dataCacheMode, &dataCache); + dataCacheMode[i] = AccessMode::READ_WRITE; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + } +} + +// Copy file contents between file groups. +// The outer vector corresponds to handles and the inner vector is for fds held by each handle. +// The outer vector sizes must match and the inner vectors must have size = 1. +static void copyCacheFiles(const std::vector>& from, + const std::vector>& to) { + constexpr size_t kBufferSize = 1000000; + uint8_t buffer[kBufferSize]; + + ASSERT_EQ(from.size(), to.size()); + for (uint32_t i = 0; i < from.size(); i++) { + ASSERT_EQ(from[i].size(), 1u); + ASSERT_EQ(to[i].size(), 1u); + int fromFd = open(from[i][0].c_str(), O_RDONLY); + int toFd = open(to[i][0].c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + ASSERT_GE(fromFd, 0); + ASSERT_GE(toFd, 0); + + ssize_t readBytes; + while ((readBytes = read(fromFd, &buffer, kBufferSize)) > 0) { + ASSERT_EQ(write(toFd, &buffer, readBytes), readBytes); + } + ASSERT_GE(readBytes, 0); + + close(fromFd); + close(toFd); + } +} + +// Number of operations in the large test model. +constexpr uint32_t kLargeModelSize = 100; +constexpr uint32_t kNumIterationsTOCTOU = 100; + +TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) { + if (!mIsCachingSupported) return; + + // Create test models and check if fully supported by the service. + const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize); + const Model modelMul = createModel(testModelMul); + if (checkEarlyTermination(modelMul)) return; + const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize); + const Model modelAdd = createModel(testModelAdd); + if (checkEarlyTermination(modelAdd)) return; + + // Save the modelMul compilation to cache. + auto modelCacheMul = mModelCache; + for (auto& cache : modelCacheMul) { + cache[0].append("_mul"); + } + { + hidl_vec modelCache, dataCache; + createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(modelMul, modelCache, dataCache); + } + + // Use a different token for modelAdd. + mToken[0]++; + + // This test is probabilistic, so we run it multiple times. + for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) { + // Save the modelAdd compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + + // Spawn a thread to copy the cache content concurrently while saving to cache. + std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache)); + saveModelToCache(modelAdd, modelCache, dataCache); + thread.join(); + } + + // Retrieve preparedModel from cache. + { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + + // The preparation may fail or succeed, but must not crash. If the preparation succeeds, + // the prepared model must be executed with the correct result and not crash. + if (status != ErrorStatus::NONE) { + ASSERT_EQ(preparedModel, nullptr); + } else { + ASSERT_NE(preparedModel, nullptr); + EvaluatePreparedModel(preparedModel, testModelAdd, + /*testDynamicOutputShape=*/false); + } + } + } +} + +TEST_P(CompilationCachingTest, PrepareFromCache_TOCTOU) { + if (!mIsCachingSupported) return; + + // Create test models and check if fully supported by the service. + const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize); + const Model modelMul = createModel(testModelMul); + if (checkEarlyTermination(modelMul)) return; + const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize); + const Model modelAdd = createModel(testModelAdd); + if (checkEarlyTermination(modelAdd)) return; + + // Save the modelMul compilation to cache. + auto modelCacheMul = mModelCache; + for (auto& cache : modelCacheMul) { + cache[0].append("_mul"); + } + { + hidl_vec modelCache, dataCache; + createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(modelMul, modelCache, dataCache); + } + + // Use a different token for modelAdd. + mToken[0]++; + + // This test is probabilistic, so we run it multiple times. + for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) { + // Save the modelAdd compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(modelAdd, modelCache, dataCache); + } + + // Retrieve preparedModel from cache. + { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + + // Spawn a thread to copy the cache content concurrently while preparing from cache. + std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache)); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + thread.join(); + + // The preparation may fail or succeed, but must not crash. If the preparation succeeds, + // the prepared model must be executed with the correct result and not crash. + if (status != ErrorStatus::NONE) { + ASSERT_EQ(preparedModel, nullptr); + } else { + ASSERT_NE(preparedModel, nullptr); + EvaluatePreparedModel(preparedModel, testModelAdd, + /*testDynamicOutputShape=*/false); + } + } + } +} + +TEST_P(CompilationCachingTest, ReplaceSecuritySensitiveCache) { + if (!mIsCachingSupported) return; + + // Create test models and check if fully supported by the service. + const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize); + const Model modelMul = createModel(testModelMul); + if (checkEarlyTermination(modelMul)) return; + const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize); + const Model modelAdd = createModel(testModelAdd); + if (checkEarlyTermination(modelAdd)) return; + + // Save the modelMul compilation to cache. + auto modelCacheMul = mModelCache; + for (auto& cache : modelCacheMul) { + cache[0].append("_mul"); + } + { + hidl_vec modelCache, dataCache; + createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(modelMul, modelCache, dataCache); + } + + // Use a different token for modelAdd. + mToken[0]++; + + // Save the modelAdd compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(modelAdd, modelCache, dataCache); + } + + // Replace the model cache of modelAdd with modelMul. + copyCacheFiles(modelCacheMul, mModelCache); + + // Retrieve the preparedModel from cache, expect failure. + { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + } +} + +static const auto kNamedDeviceChoices = testing::ValuesIn(getNamedDevices()); +static const auto kOperandTypeChoices = + testing::Values(OperandType::TENSOR_FLOAT32, OperandType::TENSOR_QUANT8_ASYMM); + +std::string printCompilationCachingTest( + const testing::TestParamInfo& info) { + const auto& [namedDevice, operandType] = info.param; + const std::string type = (operandType == OperandType::TENSOR_FLOAT32 ? "float32" : "quant8"); + return gtestCompliantName(getName(namedDevice) + "_" + type); +} + +INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingTest, + testing::Combine(kNamedDeviceChoices, kOperandTypeChoices), + printCompilationCachingTest); + +using CompilationCachingSecurityTestParam = std::tuple; + +class CompilationCachingSecurityTest + : public CompilationCachingTestBase, + public testing::WithParamInterface { + protected: + CompilationCachingSecurityTest() + : CompilationCachingTestBase(getData(std::get(GetParam())), + std::get(GetParam())) {} + + void SetUp() { + CompilationCachingTestBase::SetUp(); + generator.seed(kSeed); + } + + // Get a random integer within a closed range [lower, upper]. + template + T getRandomInt(T lower, T upper) { + std::uniform_int_distribution dis(lower, upper); + return dis(generator); + } + + // Randomly flip one single bit of the cache entry. + void flipOneBitOfCache(const std::string& filename, bool* skip) { + FILE* pFile = fopen(filename.c_str(), "r+"); + ASSERT_EQ(fseek(pFile, 0, SEEK_END), 0); + long int fileSize = ftell(pFile); + if (fileSize == 0) { + fclose(pFile); + *skip = true; + return; + } + ASSERT_EQ(fseek(pFile, getRandomInt(0l, fileSize - 1), SEEK_SET), 0); + int readByte = fgetc(pFile); + ASSERT_NE(readByte, EOF); + ASSERT_EQ(fseek(pFile, -1, SEEK_CUR), 0); + ASSERT_NE(fputc(static_cast(readByte) ^ (1U << getRandomInt(0, 7)), pFile), EOF); + fclose(pFile); + *skip = false; + } + + // Randomly append bytes to the cache entry. + void appendBytesToCache(const std::string& filename, bool* skip) { + FILE* pFile = fopen(filename.c_str(), "a"); + uint32_t appendLength = getRandomInt(1, 256); + for (uint32_t i = 0; i < appendLength; i++) { + ASSERT_NE(fputc(getRandomInt(0, 255), pFile), EOF); + } + fclose(pFile); + *skip = false; + } + + enum class ExpectedResult { GENERAL_FAILURE, NOT_CRASH }; + + // Test if the driver behaves as expected when given corrupted cache or token. + // The modifier will be invoked after save to cache but before prepare from cache. + // The modifier accepts one pointer argument "skip" as the returning value, indicating + // whether the test should be skipped or not. + void testCorruptedCache(ExpectedResult expected, std::function modifier) { + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + + // Save the compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(model, modelCache, dataCache); + } + + bool skip = false; + modifier(&skip); + if (skip) return; + + // Retrieve preparedModel from cache. + { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + + switch (expected) { + case ExpectedResult::GENERAL_FAILURE: + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + break; + case ExpectedResult::NOT_CRASH: + ASSERT_EQ(preparedModel == nullptr, status != ErrorStatus::NONE); + break; + default: + FAIL(); + } + } + } + + const uint32_t kSeed = std::get(GetParam()); + std::mt19937 generator; +}; + +TEST_P(CompilationCachingSecurityTest, CorruptedModelCache) { + if (!mIsCachingSupported) return; + for (uint32_t i = 0; i < mNumModelCache; i++) { + testCorruptedCache(ExpectedResult::GENERAL_FAILURE, + [this, i](bool* skip) { flipOneBitOfCache(mModelCache[i][0], skip); }); + } +} + +TEST_P(CompilationCachingSecurityTest, WrongLengthModelCache) { + if (!mIsCachingSupported) return; + for (uint32_t i = 0; i < mNumModelCache; i++) { + testCorruptedCache(ExpectedResult::GENERAL_FAILURE, + [this, i](bool* skip) { appendBytesToCache(mModelCache[i][0], skip); }); + } +} + +TEST_P(CompilationCachingSecurityTest, CorruptedDataCache) { + if (!mIsCachingSupported) return; + for (uint32_t i = 0; i < mNumDataCache; i++) { + testCorruptedCache(ExpectedResult::NOT_CRASH, + [this, i](bool* skip) { flipOneBitOfCache(mDataCache[i][0], skip); }); + } +} + +TEST_P(CompilationCachingSecurityTest, WrongLengthDataCache) { + if (!mIsCachingSupported) return; + for (uint32_t i = 0; i < mNumDataCache; i++) { + testCorruptedCache(ExpectedResult::NOT_CRASH, + [this, i](bool* skip) { appendBytesToCache(mDataCache[i][0], skip); }); + } +} + +TEST_P(CompilationCachingSecurityTest, WrongToken) { + if (!mIsCachingSupported) return; + testCorruptedCache(ExpectedResult::GENERAL_FAILURE, [this](bool* skip) { + // Randomly flip one single bit in mToken. + uint32_t ind = + getRandomInt(0u, static_cast(Constant::BYTE_SIZE_OF_CACHE_TOKEN) - 1); + mToken[ind] ^= (1U << getRandomInt(0, 7)); + *skip = false; + }); +} + +std::string printCompilationCachingSecurityTest( + const testing::TestParamInfo& info) { + const auto& [namedDevice, operandType, seed] = info.param; + const std::string type = (operandType == OperandType::TENSOR_FLOAT32 ? "float32" : "quant8"); + return gtestCompliantName(getName(namedDevice) + "_" + type + "_" + std::to_string(seed)); +} + +INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest, + testing::Combine(kNamedDeviceChoices, kOperandTypeChoices, + testing::Range(0U, 10U)), + printCompilationCachingSecurityTest); + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp new file mode 100644 index 0000000000..2beec983e0 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -0,0 +1,408 @@ +/* + * 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. + */ + +#include "GeneratedTestHarness.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "1.0/Utils.h" +#include "1.2/Callbacks.h" +#include "ExecutionBurstController.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "Utils.h" +#include "VtsHalNeuralnetworks.h" + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using namespace test_helper; +using hidl::memory::V1_0::IMemory; +using implementation::ExecutionCallback; +using implementation::PreparedModelCallback; +using V1_0::DataLocation; +using V1_0::ErrorStatus; +using V1_0::OperandLifeTime; +using V1_0::Request; +using V1_1::ExecutionPreference; +using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; + +enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; + +Model createModel(const TestModel& testModel) { + // Model operands. + hidl_vec operands(testModel.operands.size()); + size_t constCopySize = 0, constRefSize = 0; + for (uint32_t i = 0; i < testModel.operands.size(); i++) { + const auto& op = testModel.operands[i]; + + DataLocation loc = {}; + if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { + loc = {.poolIndex = 0, + .offset = static_cast(constCopySize), + .length = static_cast(op.data.size())}; + constCopySize += op.data.alignedSize(); + } else if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) { + loc = {.poolIndex = 0, + .offset = static_cast(constRefSize), + .length = static_cast(op.data.size())}; + constRefSize += op.data.alignedSize(); + } + + Operand::ExtraParams extraParams; + if (op.type == TestOperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) { + extraParams.channelQuant(SymmPerChannelQuantParams{ + .scales = op.channelQuant.scales, .channelDim = op.channelQuant.channelDim}); + } + + operands[i] = {.type = static_cast(op.type), + .dimensions = op.dimensions, + .numberOfConsumers = op.numberOfConsumers, + .scale = op.scale, + .zeroPoint = op.zeroPoint, + .lifetime = static_cast(op.lifetime), + .location = loc, + .extraParams = std::move(extraParams)}; + } + + // Model operations. + hidl_vec operations(testModel.operations.size()); + std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(), + [](const TestOperation& op) -> Operation { + return {.type = static_cast(op.type), + .inputs = op.inputs, + .outputs = op.outputs}; + }); + + // Constant copies. + hidl_vec operandValues(constCopySize); + for (uint32_t i = 0; i < testModel.operands.size(); i++) { + const auto& op = testModel.operands[i]; + if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { + const uint8_t* begin = op.data.get(); + const uint8_t* end = begin + op.data.size(); + std::copy(begin, end, operandValues.data() + operands[i].location.offset); + } + } + + // Shared memory. + hidl_vec pools = {}; + if (constRefSize > 0) { + hidl_vec_push_back(&pools, nn::allocateSharedMemory(constRefSize)); + CHECK_NE(pools[0].size(), 0u); + + // load data + sp mappedMemory = mapMemory(pools[0]); + CHECK(mappedMemory.get() != nullptr); + uint8_t* mappedPtr = + reinterpret_cast(static_cast(mappedMemory->getPointer())); + CHECK(mappedPtr != nullptr); + + for (uint32_t i = 0; i < testModel.operands.size(); i++) { + const auto& op = testModel.operands[i]; + if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) { + const uint8_t* begin = op.data.get(); + const uint8_t* end = begin + op.data.size(); + std::copy(begin, end, mappedPtr + operands[i].location.offset); + } + } + } + + return {.operands = std::move(operands), + .operations = std::move(operations), + .inputIndexes = testModel.inputIndexes, + .outputIndexes = testModel.outputIndexes, + .operandValues = std::move(operandValues), + .pools = std::move(pools), + .relaxComputationFloat32toFloat16 = testModel.isRelaxed}; +} + +static bool isOutputSizeGreaterThanOne(const TestModel& testModel, uint32_t index) { + const auto byteSize = testModel.operands[testModel.outputIndexes[index]].data.size(); + return byteSize > 1u; +} + +static void makeOutputInsufficientSize(uint32_t outputIndex, Request* request) { + auto& length = request->outputs[outputIndex].location.length; + ASSERT_GT(length, 1u); + length -= 1u; +} + +static void makeOutputDimensionsUnspecified(Model* model) { + for (auto i : model->outputIndexes) { + auto& dims = model->operands[i].dimensions; + std::fill(dims.begin(), dims.end(), 0); + } +} + +static Return ExecutePreparedModel(const sp& preparedModel, + const Request& request, MeasureTiming measure, + sp& callback) { + return preparedModel->execute_1_2(request, measure, callback); +} +static Return ExecutePreparedModel(const sp& preparedModel, + const Request& request, MeasureTiming measure, + hidl_vec* outputShapes, + Timing* timing) { + ErrorStatus result; + Return ret = preparedModel->executeSynchronously( + request, measure, + [&result, outputShapes, timing](ErrorStatus error, const hidl_vec& shapes, + const Timing& time) { + result = error; + *outputShapes = shapes; + *timing = time; + }); + if (!ret.isOk()) { + return ErrorStatus::GENERAL_FAILURE; + } + return result; +} +static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst( + const sp& preparedModel) { + return android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true); +} +enum class Executor { ASYNC, SYNC, BURST }; + +void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel, + Executor executor, MeasureTiming measure, OutputType outputType) { + // If output0 does not have size larger than one byte, we can not test with insufficient buffer. + if (outputType == OutputType::INSUFFICIENT && !isOutputSizeGreaterThanOne(testModel, 0)) { + return; + } + + Request request = createRequest(testModel); + if (outputType == OutputType::INSUFFICIENT) { + makeOutputInsufficientSize(/*outputIndex=*/0, &request); + } + + ErrorStatus executionStatus; + hidl_vec outputShapes; + Timing timing; + switch (executor) { + case Executor::ASYNC: { + SCOPED_TRACE("asynchronous"); + + // launch execution + sp executionCallback = new ExecutionCallback(); + Return executionLaunchStatus = + ExecutePreparedModel(preparedModel, request, measure, executionCallback); + ASSERT_TRUE(executionLaunchStatus.isOk()); + EXPECT_EQ(ErrorStatus::NONE, static_cast(executionLaunchStatus)); + + // retrieve execution status + executionCallback->wait(); + executionStatus = executionCallback->getStatus(); + outputShapes = executionCallback->getOutputShapes(); + timing = executionCallback->getTiming(); + + break; + } + case Executor::SYNC: { + SCOPED_TRACE("synchronous"); + + // execute + Return executionReturnStatus = + ExecutePreparedModel(preparedModel, request, measure, &outputShapes, &timing); + ASSERT_TRUE(executionReturnStatus.isOk()); + executionStatus = static_cast(executionReturnStatus); + + break; + } + case Executor::BURST: { + SCOPED_TRACE("burst"); + + // create burst + const std::shared_ptr<::android::nn::ExecutionBurstController> controller = + CreateBurst(preparedModel); + ASSERT_NE(nullptr, controller.get()); + + // create memory keys + std::vector keys(request.pools.size()); + for (size_t i = 0; i < keys.size(); ++i) { + keys[i] = reinterpret_cast(&request.pools[i]); + } + + // execute burst + std::tie(executionStatus, outputShapes, timing) = + controller->compute(request, measure, keys); + + break; + } + } + + if (outputType != OutputType::FULLY_SPECIFIED && + executionStatus == ErrorStatus::GENERAL_FAILURE) { + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " + "execute model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "execute model that it does not support." + << std::endl; + GTEST_SKIP(); + } + if (measure == MeasureTiming::NO) { + EXPECT_EQ(UINT64_MAX, timing.timeOnDevice); + EXPECT_EQ(UINT64_MAX, timing.timeInDriver); + } else { + if (timing.timeOnDevice != UINT64_MAX && timing.timeInDriver != UINT64_MAX) { + EXPECT_LE(timing.timeOnDevice, timing.timeInDriver); + } + } + + switch (outputType) { + case OutputType::FULLY_SPECIFIED: + // If the model output operands are fully specified, outputShapes must be either + // either empty, or have the same number of elements as the number of outputs. + ASSERT_EQ(ErrorStatus::NONE, executionStatus); + ASSERT_TRUE(outputShapes.size() == 0 || + outputShapes.size() == testModel.outputIndexes.size()); + break; + case OutputType::UNSPECIFIED: + // If the model output operands are not fully specified, outputShapes must have + // the same number of elements as the number of outputs. + ASSERT_EQ(ErrorStatus::NONE, executionStatus); + ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size()); + break; + case OutputType::INSUFFICIENT: + ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus); + ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size()); + ASSERT_FALSE(outputShapes[0].isSufficient); + return; + } + + // Go through all outputs, check returned output shapes. + for (uint32_t i = 0; i < outputShapes.size(); i++) { + EXPECT_TRUE(outputShapes[i].isSufficient); + const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions; + const std::vector actual = outputShapes[i].dimensions; + EXPECT_EQ(expect, actual); + } + + // Retrieve execution results. + const std::vector outputs = getOutputBuffers(request); + + // We want "close-enough" results. + checkResults(testModel, outputs); +} + +void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel, + bool testDynamicOutputShape) { + if (testDynamicOutputShape) { + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO, + OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO, + OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO, + OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES, + OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES, + OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES, + OutputType::INSUFFICIENT); + } else { + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO, + OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO, + OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO, + OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES, + OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES, + OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES, + OutputType::FULLY_SPECIFIED); + } +} + +void Execute(const sp& device, const TestModel& testModel, bool testDynamicOutputShape) { + Model model = createModel(testModel); + if (testDynamicOutputShape) { + makeOutputDimensionsUnspecified(&model); + } + + sp preparedModel; + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; + + EvaluatePreparedModel(preparedModel, testModel, testDynamicOutputShape); +} + +void GeneratedTestBase::SetUp() { + testing::TestWithParam::SetUp(); + ASSERT_NE(kDevice, nullptr); +} + +std::vector getNamedModels(const FilterFn& filter) { + return TestModelManager::get().getTestModels(filter); +} + +std::string printGeneratedTest(const testing::TestParamInfo& info) { + const auto& [namedDevice, namedModel] = info.param; + return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel)); +} + +// Tag for the generated tests +class GeneratedTest : public GeneratedTestBase {}; + +// Tag for the dynamic output shape tests +class DynamicOutputShapeTest : public GeneratedTest {}; + +TEST_P(GeneratedTest, Test) { + Execute(kDevice, kTestModel, /*testDynamicOutputShape=*/false); +} + +TEST_P(DynamicOutputShapeTest, Test) { + Execute(kDevice, kTestModel, /*testDynamicOutputShape=*/true); +} + +INSTANTIATE_GENERATED_TEST(GeneratedTest, + [](const TestModel& testModel) { return !testModel.expectFailure; }); + +INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, + [](const TestModel& testModel) { return !testModel.expectFailure; }); + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h new file mode 100644 index 0000000000..dfc980c169 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H + +#include +#include +#include +#include +#include +#include "1.0/Utils.h" +#include "TestHarness.h" +#include "VtsHalNeuralnetworks.h" + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using NamedModel = Named; +using GeneratedTestParam = std::tuple; + +class GeneratedTestBase : public testing::TestWithParam { + protected: + void SetUp() override; + const sp kDevice = getData(std::get(GetParam())); + const test_helper::TestModel& kTestModel = *getData(std::get(GetParam())); +}; + +using FilterFn = std::function; +std::vector getNamedModels(const FilterFn& filter); + +std::string printGeneratedTest(const testing::TestParamInfo& info); + +#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ + INSTANTIATE_TEST_SUITE_P(TestGenerated, TestSuite, \ + testing::Combine(testing::ValuesIn(getNamedDevices()), \ + testing::ValuesIn(getNamedModels(filter))), \ + printGeneratedTest) + +// Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp. +// TODO: Clean up the hierarchy for ValidationTest. +class ValidationTest : public GeneratedTestBase {}; + +Model createModel(const test_helper::TestModel& testModel); + +void PrepareModel(const sp& device, const Model& model, sp* preparedModel); + +void EvaluatePreparedModel(const sp& preparedModel, + const test_helper::TestModel& testModel, bool testDynamicOutputShape); + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional + +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H diff --git a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp new file mode 100644 index 0000000000..a0aa3c37d1 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp @@ -0,0 +1,141 @@ +/* + * 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. + */ + +#include +#include "TestHarness.h" + +namespace android::hardware::neuralnetworks::V1_2 { + +// Make sure that the HIDL enums are compatible with the values defined in +// frameworks/ml/nn/tools/test_generator/test_harness/include/TestHarness.h. +using namespace test_helper; +#define CHECK_TEST_ENUM(EnumType, enumValue) \ + static_assert(static_cast(Test##EnumType::enumValue) == EnumType::enumValue) + +CHECK_TEST_ENUM(OperandType, FLOAT32); +CHECK_TEST_ENUM(OperandType, INT32); +CHECK_TEST_ENUM(OperandType, UINT32); +CHECK_TEST_ENUM(OperandType, TENSOR_FLOAT32); +CHECK_TEST_ENUM(OperandType, TENSOR_INT32); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_ASYMM); +CHECK_TEST_ENUM(OperandType, BOOL); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT16_SYMM); +CHECK_TEST_ENUM(OperandType, TENSOR_FLOAT16); +CHECK_TEST_ENUM(OperandType, TENSOR_BOOL8); +CHECK_TEST_ENUM(OperandType, FLOAT16); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_SYMM_PER_CHANNEL); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT16_ASYMM); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_SYMM); + +CHECK_TEST_ENUM(OperationType, ADD); +CHECK_TEST_ENUM(OperationType, AVERAGE_POOL_2D); +CHECK_TEST_ENUM(OperationType, CONCATENATION); +CHECK_TEST_ENUM(OperationType, CONV_2D); +CHECK_TEST_ENUM(OperationType, DEPTHWISE_CONV_2D); +CHECK_TEST_ENUM(OperationType, DEPTH_TO_SPACE); +CHECK_TEST_ENUM(OperationType, DEQUANTIZE); +CHECK_TEST_ENUM(OperationType, EMBEDDING_LOOKUP); +CHECK_TEST_ENUM(OperationType, FLOOR); +CHECK_TEST_ENUM(OperationType, FULLY_CONNECTED); +CHECK_TEST_ENUM(OperationType, HASHTABLE_LOOKUP); +CHECK_TEST_ENUM(OperationType, L2_NORMALIZATION); +CHECK_TEST_ENUM(OperationType, L2_POOL_2D); +CHECK_TEST_ENUM(OperationType, LOCAL_RESPONSE_NORMALIZATION); +CHECK_TEST_ENUM(OperationType, LOGISTIC); +CHECK_TEST_ENUM(OperationType, LSH_PROJECTION); +CHECK_TEST_ENUM(OperationType, LSTM); +CHECK_TEST_ENUM(OperationType, MAX_POOL_2D); +CHECK_TEST_ENUM(OperationType, MUL); +CHECK_TEST_ENUM(OperationType, RELU); +CHECK_TEST_ENUM(OperationType, RELU1); +CHECK_TEST_ENUM(OperationType, RELU6); +CHECK_TEST_ENUM(OperationType, RESHAPE); +CHECK_TEST_ENUM(OperationType, RESIZE_BILINEAR); +CHECK_TEST_ENUM(OperationType, RNN); +CHECK_TEST_ENUM(OperationType, SOFTMAX); +CHECK_TEST_ENUM(OperationType, SPACE_TO_DEPTH); +CHECK_TEST_ENUM(OperationType, SVDF); +CHECK_TEST_ENUM(OperationType, TANH); +CHECK_TEST_ENUM(OperationType, BATCH_TO_SPACE_ND); +CHECK_TEST_ENUM(OperationType, DIV); +CHECK_TEST_ENUM(OperationType, MEAN); +CHECK_TEST_ENUM(OperationType, PAD); +CHECK_TEST_ENUM(OperationType, SPACE_TO_BATCH_ND); +CHECK_TEST_ENUM(OperationType, SQUEEZE); +CHECK_TEST_ENUM(OperationType, STRIDED_SLICE); +CHECK_TEST_ENUM(OperationType, SUB); +CHECK_TEST_ENUM(OperationType, TRANSPOSE); +CHECK_TEST_ENUM(OperationType, ABS); +CHECK_TEST_ENUM(OperationType, ARGMAX); +CHECK_TEST_ENUM(OperationType, ARGMIN); +CHECK_TEST_ENUM(OperationType, AXIS_ALIGNED_BBOX_TRANSFORM); +CHECK_TEST_ENUM(OperationType, BIDIRECTIONAL_SEQUENCE_LSTM); +CHECK_TEST_ENUM(OperationType, BIDIRECTIONAL_SEQUENCE_RNN); +CHECK_TEST_ENUM(OperationType, BOX_WITH_NMS_LIMIT); +CHECK_TEST_ENUM(OperationType, CAST); +CHECK_TEST_ENUM(OperationType, CHANNEL_SHUFFLE); +CHECK_TEST_ENUM(OperationType, DETECTION_POSTPROCESSING); +CHECK_TEST_ENUM(OperationType, EQUAL); +CHECK_TEST_ENUM(OperationType, EXP); +CHECK_TEST_ENUM(OperationType, EXPAND_DIMS); +CHECK_TEST_ENUM(OperationType, GATHER); +CHECK_TEST_ENUM(OperationType, GENERATE_PROPOSALS); +CHECK_TEST_ENUM(OperationType, GREATER); +CHECK_TEST_ENUM(OperationType, GREATER_EQUAL); +CHECK_TEST_ENUM(OperationType, GROUPED_CONV_2D); +CHECK_TEST_ENUM(OperationType, HEATMAP_MAX_KEYPOINT); +CHECK_TEST_ENUM(OperationType, INSTANCE_NORMALIZATION); +CHECK_TEST_ENUM(OperationType, LESS); +CHECK_TEST_ENUM(OperationType, LESS_EQUAL); +CHECK_TEST_ENUM(OperationType, LOG); +CHECK_TEST_ENUM(OperationType, LOGICAL_AND); +CHECK_TEST_ENUM(OperationType, LOGICAL_NOT); +CHECK_TEST_ENUM(OperationType, LOGICAL_OR); +CHECK_TEST_ENUM(OperationType, LOG_SOFTMAX); +CHECK_TEST_ENUM(OperationType, MAXIMUM); +CHECK_TEST_ENUM(OperationType, MINIMUM); +CHECK_TEST_ENUM(OperationType, NEG); +CHECK_TEST_ENUM(OperationType, NOT_EQUAL); +CHECK_TEST_ENUM(OperationType, PAD_V2); +CHECK_TEST_ENUM(OperationType, POW); +CHECK_TEST_ENUM(OperationType, PRELU); +CHECK_TEST_ENUM(OperationType, QUANTIZE); +CHECK_TEST_ENUM(OperationType, QUANTIZED_16BIT_LSTM); +CHECK_TEST_ENUM(OperationType, RANDOM_MULTINOMIAL); +CHECK_TEST_ENUM(OperationType, REDUCE_ALL); +CHECK_TEST_ENUM(OperationType, REDUCE_ANY); +CHECK_TEST_ENUM(OperationType, REDUCE_MAX); +CHECK_TEST_ENUM(OperationType, REDUCE_MIN); +CHECK_TEST_ENUM(OperationType, REDUCE_PROD); +CHECK_TEST_ENUM(OperationType, REDUCE_SUM); +CHECK_TEST_ENUM(OperationType, ROI_ALIGN); +CHECK_TEST_ENUM(OperationType, ROI_POOLING); +CHECK_TEST_ENUM(OperationType, RSQRT); +CHECK_TEST_ENUM(OperationType, SELECT); +CHECK_TEST_ENUM(OperationType, SIN); +CHECK_TEST_ENUM(OperationType, SLICE); +CHECK_TEST_ENUM(OperationType, SPLIT); +CHECK_TEST_ENUM(OperationType, SQRT); +CHECK_TEST_ENUM(OperationType, TILE); +CHECK_TEST_ENUM(OperationType, TOPK_V2); +CHECK_TEST_ENUM(OperationType, TRANSPOSE_CONV_2D); +CHECK_TEST_ENUM(OperationType, UNIDIRECTIONAL_SEQUENCE_LSTM); +CHECK_TEST_ENUM(OperationType, UNIDIRECTIONAL_SEQUENCE_RNN); +CHECK_TEST_ENUM(OperationType, RESIZE_NEAREST_NEIGHBOR); + +#undef CHECK_TEST_ENUM + +} // namespace android::hardware::neuralnetworks::V1_2 diff --git a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp new file mode 100644 index 0000000000..1d4493d208 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp @@ -0,0 +1,400 @@ +/* + * 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 "neuralnetworks_hidl_hal_test" + +#include "VtsHalNeuralnetworks.h" + +#include "1.2/Callbacks.h" +#include "ExecutionBurstController.h" +#include "ExecutionBurstServer.h" +#include "GeneratedTestHarness.h" +#include "TestHarness.h" +#include "Utils.h" + +#include +#include + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using nn::ExecutionBurstController; +using nn::RequestChannelSender; +using nn::ResultChannelReceiver; +using V1_0::ErrorStatus; +using V1_0::Request; +using ExecutionBurstCallback = ExecutionBurstController::ExecutionBurstCallback; + +// This constant value represents the length of an FMQ that is large enough to +// return a result from a burst execution for all of the generated test cases. +constexpr size_t kExecutionBurstChannelLength = 1024; + +// This constant value represents a length of an FMQ that is not large enough +// to return a result from a burst execution for some of the generated test +// cases. +constexpr size_t kExecutionBurstChannelSmallLength = 8; + +///////////////////////// UTILITY FUNCTIONS ///////////////////////// + +static bool badTiming(Timing timing) { + return timing.timeOnDevice == UINT64_MAX && timing.timeInDriver == UINT64_MAX; +} + +static void createBurst(const sp& preparedModel, const sp& callback, + std::unique_ptr* sender, + std::unique_ptr* receiver, + sp* context, + size_t resultChannelLength = kExecutionBurstChannelLength) { + ASSERT_NE(nullptr, preparedModel.get()); + ASSERT_NE(nullptr, sender); + ASSERT_NE(nullptr, receiver); + ASSERT_NE(nullptr, context); + + // create FMQ objects + auto [fmqRequestChannel, fmqRequestDescriptor] = + RequestChannelSender::create(kExecutionBurstChannelLength, /*blocking=*/true); + auto [fmqResultChannel, fmqResultDescriptor] = + ResultChannelReceiver::create(resultChannelLength, /*blocking=*/true); + ASSERT_NE(nullptr, fmqRequestChannel.get()); + ASSERT_NE(nullptr, fmqResultChannel.get()); + ASSERT_NE(nullptr, fmqRequestDescriptor); + ASSERT_NE(nullptr, fmqResultDescriptor); + + // configure burst + ErrorStatus errorStatus; + sp burstContext; + const Return ret = preparedModel->configureExecutionBurst( + callback, *fmqRequestDescriptor, *fmqResultDescriptor, + [&errorStatus, &burstContext](ErrorStatus status, const sp& context) { + errorStatus = status; + burstContext = context; + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(ErrorStatus::NONE, errorStatus); + ASSERT_NE(nullptr, burstContext.get()); + + // return values + *sender = std::move(fmqRequestChannel); + *receiver = std::move(fmqResultChannel); + *context = burstContext; +} + +static void createBurstWithResultChannelLength( + const sp& preparedModel, size_t resultChannelLength, + std::shared_ptr* controller) { + ASSERT_NE(nullptr, preparedModel.get()); + ASSERT_NE(nullptr, controller); + + // create FMQ objects + std::unique_ptr sender; + std::unique_ptr receiver; + sp callback = new ExecutionBurstCallback(); + sp context; + ASSERT_NO_FATAL_FAILURE(createBurst(preparedModel, callback, &sender, &receiver, &context, + resultChannelLength)); + ASSERT_NE(nullptr, sender.get()); + ASSERT_NE(nullptr, receiver.get()); + ASSERT_NE(nullptr, context.get()); + + // return values + *controller = std::make_shared(std::move(sender), std::move(receiver), + context, callback); +} + +// Primary validation function. This function will take a valid serialized +// request, apply a mutation to it to invalidate the serialized request, then +// pass it to interface calls that use the serialized request. Note that the +// serialized request here is passed by value, and any mutation to the +// serialized request does not leave this function. +static void validate(RequestChannelSender* sender, ResultChannelReceiver* receiver, + const std::string& message, std::vector serialized, + const std::function*)>& mutation) { + mutation(&serialized); + + // skip if packet is too large to send + if (serialized.size() > kExecutionBurstChannelLength) { + return; + } + + SCOPED_TRACE(message); + + // send invalid packet + ASSERT_TRUE(sender->sendPacket(serialized)); + + // receive error + auto results = receiver->getBlocking(); + ASSERT_TRUE(results.has_value()); + const auto [status, outputShapes, timing] = std::move(*results); + EXPECT_NE(ErrorStatus::NONE, status); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_TRUE(badTiming(timing)); +} + +// For validation, valid packet entries are mutated to invalid packet entries, +// or invalid packet entries are inserted into valid packets. This function +// creates pre-set invalid packet entries for convenience. +static std::vector createBadRequestPacketEntries() { + const FmqRequestDatum::PacketInformation packetInformation = { + /*.packetSize=*/10, /*.numberOfInputOperands=*/10, /*.numberOfOutputOperands=*/10, + /*.numberOfPools=*/10}; + const FmqRequestDatum::OperandInformation operandInformation = { + /*.hasNoValue=*/false, /*.location=*/{}, /*.numberOfDimensions=*/10}; + const int32_t invalidPoolIdentifier = std::numeric_limits::max(); + std::vector bad(7); + bad[0].packetInformation(packetInformation); + bad[1].inputOperandInformation(operandInformation); + bad[2].inputOperandDimensionValue(0); + bad[3].outputOperandInformation(operandInformation); + bad[4].outputOperandDimensionValue(0); + bad[5].poolIdentifier(invalidPoolIdentifier); + bad[6].measureTiming(MeasureTiming::YES); + return bad; +} + +// For validation, valid packet entries are mutated to invalid packet entries, +// or invalid packet entries are inserted into valid packets. This function +// retrieves pre-set invalid packet entries for convenience. This function +// caches these data so they can be reused on subsequent validation checks. +static const std::vector& getBadRequestPacketEntries() { + static const std::vector bad = createBadRequestPacketEntries(); + return bad; +} + +///////////////////////// REMOVE DATUM //////////////////////////////////// + +static void removeDatumTest(RequestChannelSender* sender, ResultChannelReceiver* receiver, + const std::vector& serialized) { + for (size_t index = 0; index < serialized.size(); ++index) { + const std::string message = "removeDatum: removed datum at index " + std::to_string(index); + validate(sender, receiver, message, serialized, + [index](std::vector* serialized) { + serialized->erase(serialized->begin() + index); + }); + } +} + +///////////////////////// ADD DATUM //////////////////////////////////// + +static void addDatumTest(RequestChannelSender* sender, ResultChannelReceiver* receiver, + const std::vector& serialized) { + const std::vector& extra = getBadRequestPacketEntries(); + for (size_t index = 0; index <= serialized.size(); ++index) { + for (size_t type = 0; type < extra.size(); ++type) { + const std::string message = "addDatum: added datum type " + std::to_string(type) + + " at index " + std::to_string(index); + validate(sender, receiver, message, serialized, + [index, type, &extra](std::vector* serialized) { + serialized->insert(serialized->begin() + index, extra[type]); + }); + } + } +} + +///////////////////////// MUTATE DATUM //////////////////////////////////// + +static bool interestingCase(const FmqRequestDatum& lhs, const FmqRequestDatum& rhs) { + using Discriminator = FmqRequestDatum::hidl_discriminator; + + const bool differentValues = (lhs != rhs); + const bool sameDiscriminator = (lhs.getDiscriminator() == rhs.getDiscriminator()); + const auto discriminator = rhs.getDiscriminator(); + const bool isDimensionValue = (discriminator == Discriminator::inputOperandDimensionValue || + discriminator == Discriminator::outputOperandDimensionValue); + + return differentValues && !(sameDiscriminator && isDimensionValue); +} + +static void mutateDatumTest(RequestChannelSender* sender, ResultChannelReceiver* receiver, + const std::vector& serialized) { + const std::vector& change = getBadRequestPacketEntries(); + for (size_t index = 0; index < serialized.size(); ++index) { + for (size_t type = 0; type < change.size(); ++type) { + if (interestingCase(serialized[index], change[type])) { + const std::string message = "mutateDatum: changed datum at index " + + std::to_string(index) + " to datum type " + + std::to_string(type); + validate(sender, receiver, message, serialized, + [index, type, &change](std::vector* serialized) { + (*serialized)[index] = change[type]; + }); + } + } + } +} + +///////////////////////// BURST VALIATION TESTS //////////////////////////////////// + +static void validateBurstSerialization(const sp& preparedModel, + const Request& request) { + // create burst + std::unique_ptr sender; + std::unique_ptr receiver; + sp callback = new ExecutionBurstCallback(); + sp context; + ASSERT_NO_FATAL_FAILURE(createBurst(preparedModel, callback, &sender, &receiver, &context)); + ASSERT_NE(nullptr, sender.get()); + ASSERT_NE(nullptr, receiver.get()); + ASSERT_NE(nullptr, context.get()); + + // load memory into callback slots + std::vector keys; + keys.reserve(request.pools.size()); + std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys), + [](const auto& pool) { return reinterpret_cast(&pool); }); + const std::vector slots = callback->getSlots(request.pools, keys); + + // ensure slot std::numeric_limits::max() doesn't exist (for + // subsequent slot validation testing) + ASSERT_TRUE(std::all_of(slots.begin(), slots.end(), [](int32_t slot) { + return slot != std::numeric_limits::max(); + })); + + // serialize the request + const auto serialized = android::nn::serialize(request, MeasureTiming::YES, slots); + + // validations + removeDatumTest(sender.get(), receiver.get(), serialized); + addDatumTest(sender.get(), receiver.get(), serialized); + mutateDatumTest(sender.get(), receiver.get(), serialized); +} + +// This test validates that when the Result message size exceeds length of the +// result FMQ, the service instance gracefully fails and returns an error. +static void validateBurstFmqLength(const sp& preparedModel, + const Request& request) { + // create regular burst + std::shared_ptr controllerRegular; + ASSERT_NO_FATAL_FAILURE(createBurstWithResultChannelLength( + preparedModel, kExecutionBurstChannelLength, &controllerRegular)); + ASSERT_NE(nullptr, controllerRegular.get()); + + // create burst with small output channel + std::shared_ptr controllerSmall; + ASSERT_NO_FATAL_FAILURE(createBurstWithResultChannelLength( + preparedModel, kExecutionBurstChannelSmallLength, &controllerSmall)); + ASSERT_NE(nullptr, controllerSmall.get()); + + // load memory into callback slots + std::vector keys(request.pools.size()); + for (size_t i = 0; i < keys.size(); ++i) { + keys[i] = reinterpret_cast(&request.pools[i]); + } + + // collect serialized result by running regular burst + const auto [statusRegular, outputShapesRegular, timingRegular] = + controllerRegular->compute(request, MeasureTiming::NO, keys); + + // skip test if regular burst output isn't useful for testing a failure + // caused by having too small of a length for the result FMQ + const std::vector serialized = + android::nn::serialize(statusRegular, outputShapesRegular, timingRegular); + if (statusRegular != ErrorStatus::NONE || + serialized.size() <= kExecutionBurstChannelSmallLength) { + return; + } + + // by this point, execution should fail because the result channel isn't + // large enough to return the serialized result + const auto [statusSmall, outputShapesSmall, timingSmall] = + controllerSmall->compute(request, MeasureTiming::NO, keys); + EXPECT_NE(ErrorStatus::NONE, statusSmall); + EXPECT_EQ(0u, outputShapesSmall.size()); + EXPECT_TRUE(badTiming(timingSmall)); +} + +static bool isSanitized(const FmqResultDatum& datum) { + using Discriminator = FmqResultDatum::hidl_discriminator; + + // check to ensure the padding values in the returned + // FmqResultDatum::OperandInformation are initialized to 0 + if (datum.getDiscriminator() == Discriminator::operandInformation) { + static_assert( + offsetof(FmqResultDatum::OperandInformation, isSufficient) == 0, + "unexpected value for offset of FmqResultDatum::OperandInformation::isSufficient"); + static_assert( + sizeof(FmqResultDatum::OperandInformation::isSufficient) == 1, + "unexpected value for size of FmqResultDatum::OperandInformation::isSufficient"); + static_assert(offsetof(FmqResultDatum::OperandInformation, numberOfDimensions) == 4, + "unexpected value for offset of " + "FmqResultDatum::OperandInformation::numberOfDimensions"); + static_assert(sizeof(FmqResultDatum::OperandInformation::numberOfDimensions) == 4, + "unexpected value for size of " + "FmqResultDatum::OperandInformation::numberOfDimensions"); + static_assert(sizeof(FmqResultDatum::OperandInformation) == 8, + "unexpected value for size of " + "FmqResultDatum::OperandInformation"); + + constexpr size_t paddingOffset = + offsetof(FmqResultDatum::OperandInformation, isSufficient) + + sizeof(FmqResultDatum::OperandInformation::isSufficient); + constexpr size_t paddingSize = + offsetof(FmqResultDatum::OperandInformation, numberOfDimensions) - paddingOffset; + + FmqResultDatum::OperandInformation initialized{}; + std::memset(&initialized, 0, sizeof(initialized)); + + const char* initializedPaddingStart = + reinterpret_cast(&initialized) + paddingOffset; + const char* datumPaddingStart = + reinterpret_cast(&datum.operandInformation()) + paddingOffset; + + return std::memcmp(datumPaddingStart, initializedPaddingStart, paddingSize) == 0; + } + + // there are no other padding initialization checks required, so return true + // for any sum-type that isn't FmqResultDatum::OperandInformation + return true; +} + +static void validateBurstSanitized(const sp& preparedModel, + const Request& request) { + // create burst + std::unique_ptr sender; + std::unique_ptr receiver; + sp callback = new ExecutionBurstCallback(); + sp context; + ASSERT_NO_FATAL_FAILURE(createBurst(preparedModel, callback, &sender, &receiver, &context)); + ASSERT_NE(nullptr, sender.get()); + ASSERT_NE(nullptr, receiver.get()); + ASSERT_NE(nullptr, context.get()); + + // load memory into callback slots + std::vector keys; + keys.reserve(request.pools.size()); + std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys), + [](const auto& pool) { return reinterpret_cast(&pool); }); + const std::vector slots = callback->getSlots(request.pools, keys); + + // send valid request + ASSERT_TRUE(sender->send(request, MeasureTiming::YES, slots)); + + // receive valid result + auto serialized = receiver->getPacketBlocking(); + ASSERT_TRUE(serialized.has_value()); + + // sanitize result + ASSERT_TRUE(std::all_of(serialized->begin(), serialized->end(), isSanitized)) + << "The result serialized data is not properly sanitized"; +} + +///////////////////////////// ENTRY POINT ////////////////////////////////// + +void validateBurst(const sp& preparedModel, const Request& request) { + ASSERT_NO_FATAL_FAILURE(validateBurstSerialization(preparedModel, request)); + ASSERT_NO_FATAL_FAILURE(validateBurstFmqLength(preparedModel, request)); + ASSERT_NO_FATAL_FAILURE(validateBurstSanitized(preparedModel, request)); +} + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp new file mode 100644 index 0000000000..30530beacc --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -0,0 +1,713 @@ +/* + * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test" + +#include "1.0/Utils.h" +#include "1.2/Callbacks.h" +#include "GeneratedTestHarness.h" +#include "VtsHalNeuralnetworks.h" + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using implementation::PreparedModelCallback; +using V1_0::ErrorStatus; +using V1_0::OperandLifeTime; +using V1_1::ExecutionPreference; +using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; + +///////////////////////// UTILITY FUNCTIONS ///////////////////////// + +static void validateGetSupportedOperations(const sp& device, const std::string& message, + const Model& model) { + SCOPED_TRACE(message + " [getSupportedOperations_1_2]"); + + Return ret = device->getSupportedOperations_1_2( + model, [&](ErrorStatus status, const hidl_vec&) { + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); + }); + EXPECT_TRUE(ret.isOk()); +} + +static void validatePrepareModel(const sp& device, const std::string& message, + const Model& model, ExecutionPreference preference) { + SCOPED_TRACE(message + " [prepareModel_1_2]"); + + sp preparedModelCallback = new PreparedModelCallback(); + Return prepareLaunchStatus = + device->prepareModel_1_2(model, preference, hidl_vec(), + hidl_vec(), HidlToken(), preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(prepareLaunchStatus)); + + preparedModelCallback->wait(); + ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus); + sp preparedModel = getPreparedModel_1_2(preparedModelCallback); + ASSERT_EQ(nullptr, preparedModel.get()); +} + +static bool validExecutionPreference(ExecutionPreference preference) { + return preference == ExecutionPreference::LOW_POWER || + preference == ExecutionPreference::FAST_SINGLE_ANSWER || + preference == ExecutionPreference::SUSTAINED_SPEED; +} + +// Primary validation function. This function will take a valid model, apply a +// mutation to it to invalidate the model, then pass it to interface calls that +// use the model. Note that the model here is passed by value, and any mutation +// to the model does not leave this function. +static void validate(const sp& device, const std::string& message, Model model, + const std::function& mutation, + ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) { + mutation(&model); + if (validExecutionPreference(preference)) { + validateGetSupportedOperations(device, message, model); + } + validatePrepareModel(device, message, model, preference); +} + +static uint32_t addOperand(Model* model) { + return hidl_vec_push_back(&model->operands, + { + .type = OperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 0, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }); +} + +static uint32_t addOperand(Model* model, OperandLifeTime lifetime) { + uint32_t index = addOperand(model); + model->operands[index].numberOfConsumers = 1; + model->operands[index].lifetime = lifetime; + return index; +} + +///////////////////////// VALIDATE MODEL OPERAND TYPE ///////////////////////// + +static const uint32_t invalidOperandTypes[] = { + static_cast(OperandTypeRange::FUNDAMENTAL_MIN) - 1, + static_cast(OperandTypeRange::FUNDAMENTAL_MAX) + 1, + static_cast(OperandTypeRange::OEM_MIN) - 1, + static_cast(OperandTypeRange::OEM_MAX) + 1, +}; + +static void mutateOperandTypeTest(const sp& device, const Model& model) { + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + for (uint32_t invalidOperandType : invalidOperandTypes) { + const std::string message = "mutateOperandTypeTest: operand " + + std::to_string(operand) + " set to value " + + std::to_string(invalidOperandType); + validate(device, message, model, [operand, invalidOperandType](Model* model) { + model->operands[operand].type = static_cast(invalidOperandType); + }); + } + } +} + +///////////////////////// VALIDATE OPERAND RANK ///////////////////////// + +static uint32_t getInvalidRank(OperandType type) { + switch (type) { + case OperandType::FLOAT16: + case OperandType::FLOAT32: + case OperandType::INT32: + case OperandType::UINT32: + case OperandType::BOOL: + return 1; + case OperandType::TENSOR_BOOL8: + case OperandType::TENSOR_FLOAT16: + case OperandType::TENSOR_FLOAT32: + case OperandType::TENSOR_INT32: + case OperandType::TENSOR_QUANT8_ASYMM: + case OperandType::TENSOR_QUANT8_SYMM: + case OperandType::TENSOR_QUANT16_ASYMM: + case OperandType::TENSOR_QUANT16_SYMM: + case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: + return 0; + default: + return 0; + } +} + +static void mutateOperandRankTest(const sp& device, const Model& model) { + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + const uint32_t invalidRank = getInvalidRank(model.operands[operand].type); + if (invalidRank == 0) { + continue; + } + const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) + + " has rank of " + std::to_string(invalidRank); + validate(device, message, model, [operand, invalidRank](Model* model) { + model->operands[operand].dimensions = std::vector(invalidRank, 0); + }); + } +} + +///////////////////////// VALIDATE OPERAND SCALE ///////////////////////// + +static float getInvalidScale(OperandType type) { + switch (type) { + case OperandType::FLOAT16: + case OperandType::FLOAT32: + case OperandType::INT32: + case OperandType::UINT32: + case OperandType::BOOL: + case OperandType::TENSOR_BOOL8: + case OperandType::TENSOR_FLOAT16: + case OperandType::TENSOR_FLOAT32: + case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: + return 1.0f; + case OperandType::TENSOR_INT32: + return -1.0f; + case OperandType::TENSOR_QUANT8_SYMM: + case OperandType::TENSOR_QUANT8_ASYMM: + case OperandType::TENSOR_QUANT16_ASYMM: + case OperandType::TENSOR_QUANT16_SYMM: + return 0.0f; + default: + return 0.0f; + } +} + +static void mutateOperandScaleTest(const sp& device, const Model& model) { + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + const float invalidScale = getInvalidScale(model.operands[operand].type); + const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) + + " has scale of " + std::to_string(invalidScale); + validate(device, message, model, [operand, invalidScale](Model* model) { + model->operands[operand].scale = invalidScale; + }); + } +} + +///////////////////////// VALIDATE OPERAND ZERO POINT ///////////////////////// + +static std::vector getInvalidZeroPoints(OperandType type) { + switch (type) { + case OperandType::FLOAT16: + case OperandType::FLOAT32: + case OperandType::INT32: + case OperandType::UINT32: + case OperandType::BOOL: + case OperandType::TENSOR_BOOL8: + case OperandType::TENSOR_FLOAT16: + case OperandType::TENSOR_FLOAT32: + case OperandType::TENSOR_INT32: + case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: + return {1}; + case OperandType::TENSOR_QUANT8_ASYMM: + return {-1, 256}; + case OperandType::TENSOR_QUANT8_SYMM: + return {-129, -1, 1, 128}; + case OperandType::TENSOR_QUANT16_ASYMM: + return {-1, 65536}; + case OperandType::TENSOR_QUANT16_SYMM: + return {-32769, -1, 1, 32768}; + default: + return {}; + } +} + +static void mutateOperandZeroPointTest(const sp& device, const Model& model) { + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + const std::vector invalidZeroPoints = + getInvalidZeroPoints(model.operands[operand].type); + for (int32_t invalidZeroPoint : invalidZeroPoints) { + const std::string message = "mutateOperandZeroPointTest: operand " + + std::to_string(operand) + " has zero point of " + + std::to_string(invalidZeroPoint); + validate(device, message, model, [operand, invalidZeroPoint](Model* model) { + model->operands[operand].zeroPoint = invalidZeroPoint; + }); + } + } +} + +///////////////////////// VALIDATE EXTRA ??? ///////////////////////// + +// TODO: Operand::lifetime +// TODO: Operand::location + +///////////////////////// VALIDATE OPERATION OPERAND TYPE ///////////////////////// + +static void mutateOperand(Operand* operand, OperandType type) { + Operand newOperand = *operand; + newOperand.type = type; + switch (type) { + case OperandType::FLOAT16: + case OperandType::FLOAT32: + case OperandType::INT32: + case OperandType::UINT32: + case OperandType::BOOL: + newOperand.dimensions = hidl_vec(); + newOperand.scale = 0.0f; + newOperand.zeroPoint = 0; + break; + case OperandType::TENSOR_BOOL8: + case OperandType::TENSOR_FLOAT16: + case OperandType::TENSOR_FLOAT32: + newOperand.dimensions = + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + newOperand.scale = 0.0f; + newOperand.zeroPoint = 0; + break; + case OperandType::TENSOR_INT32: + newOperand.dimensions = + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + newOperand.zeroPoint = 0; + break; + case OperandType::TENSOR_QUANT8_ASYMM: + case OperandType::TENSOR_QUANT8_SYMM: + case OperandType::TENSOR_QUANT16_ASYMM: + case OperandType::TENSOR_QUANT16_SYMM: + newOperand.dimensions = + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f; + break; + case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: { + newOperand.dimensions = + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + newOperand.scale = 0.0f; + newOperand.zeroPoint = 0; + + SymmPerChannelQuantParams channelQuant; + channelQuant.channelDim = 0; + channelQuant.scales = hidl_vec( + operand->dimensions.size() > 0 ? static_cast(operand->dimensions[0]) + : 0); + for (size_t i = 0; i < channelQuant.scales.size(); ++i) { + channelQuant.scales[i] = 1.0f; + } + newOperand.extraParams.channelQuant(std::move(channelQuant)); + } break; + case OperandType::OEM: + case OperandType::TENSOR_OEM_BYTE: + default: + break; + } + *operand = newOperand; +} + +static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, const Model& model) { + // Do not test OEM types + if (type == model.operands[operand].type || type == OperandType::OEM || + type == OperandType::TENSOR_OEM_BYTE) { + return true; + } + for (const Operation& operation : model.operations) { + // Skip mutateOperationOperandTypeTest for the following operations. + // - LSH_PROJECTION's second argument is allowed to have any type. + // - ARGMIN and ARGMAX's first argument can be any of + // TENSOR_(FLOAT16|FLOAT32|INT32|QUANT8_ASYMM). + // - CAST's argument can be any of TENSOR_(FLOAT16|FLOAT32|INT32|QUANT8_ASYMM). + // - RANDOM_MULTINOMIAL's argument can be either TENSOR_FLOAT16 or TENSOR_FLOAT32. + // - DEQUANTIZE input can be any of + // TENSOR_(QUANT8_ASYMM|QUANT8_SYMM|QUANT8_SYMM_PER_CHANNEL), output can + // be of either TENSOR_FLOAT16 or TENSOR_FLOAT32. + // - QUANTIZE input can be either TENSOR_FLOAT16 or TENSOR_FLOAT32 + // - CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL + // - DEPTHWISE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL + // - GROUPED_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL + // - TRANSPOSE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL + switch (operation.type) { + case OperationType::LSH_PROJECTION: { + if (operand == operation.inputs[1]) { + return true; + } + } break; + case OperationType::CAST: + case OperationType::ARGMAX: + case OperationType::ARGMIN: { + if (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32 || + type == OperandType::TENSOR_INT32 || type == OperandType::TENSOR_QUANT8_ASYMM) { + return true; + } + } break; + case OperationType::QUANTIZE: + case OperationType::RANDOM_MULTINOMIAL: { + if (operand == operation.inputs[0] && + (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32)) { + return true; + } + } break; + case OperationType::DEQUANTIZE: { + if (operand == operation.inputs[0] && + (type == OperandType::TENSOR_QUANT8_ASYMM || + type == OperandType::TENSOR_QUANT8_SYMM || + type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL)) { + return true; + } + if (operand == operation.outputs[0] && + (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32)) { + return true; + } + } break; + case OperationType::TRANSPOSE_CONV_2D: + case OperationType::GROUPED_CONV_2D: + case OperationType::DEPTHWISE_CONV_2D: + case OperationType::CONV_2D: { + if (operand == operation.inputs[1] && + (type == OperandType::TENSOR_QUANT8_ASYMM || + type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL)) { + return true; + } + } break; + default: + break; + } + } + return false; +} + +static void mutateOperationOperandTypeTest(const sp& device, const Model& model) { + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + for (OperandType invalidOperandType : hidl_enum_range{}) { + if (mutateOperationOperandTypeSkip(operand, invalidOperandType, model)) { + continue; + } + const std::string message = "mutateOperationOperandTypeTest: operand " + + std::to_string(operand) + " set to type " + + toString(invalidOperandType); + validate(device, message, model, [operand, invalidOperandType](Model* model) { + mutateOperand(&model->operands[operand], invalidOperandType); + }); + } + } +} + +///////////////////////// VALIDATE MODEL OPERATION TYPE ///////////////////////// + +static const uint32_t invalidOperationTypes[] = { + static_cast(OperationTypeRange::FUNDAMENTAL_MAX) + 1, + static_cast(OperationTypeRange::OEM_MIN) - 1, + static_cast(OperationTypeRange::OEM_MAX) + 1, +}; + +static void mutateOperationTypeTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + for (uint32_t invalidOperationType : invalidOperationTypes) { + const std::string message = "mutateOperationTypeTest: operation " + + std::to_string(operation) + " set to value " + + std::to_string(invalidOperationType); + validate(device, message, model, [operation, invalidOperationType](Model* model) { + model->operations[operation].type = + static_cast(invalidOperationType); + }); + } + } +} + +///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX ///////////////////////// + +static void mutateOperationInputOperandIndexTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + const uint32_t invalidOperand = model.operands.size(); + for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) { + const std::string message = "mutateOperationInputOperandIndexTest: operation " + + std::to_string(operation) + " input " + + std::to_string(input); + validate(device, message, model, [operation, input, invalidOperand](Model* model) { + model->operations[operation].inputs[input] = invalidOperand; + }); + } + } +} + +///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX ///////////////////////// + +static void mutateOperationOutputOperandIndexTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + const uint32_t invalidOperand = model.operands.size(); + for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) { + const std::string message = "mutateOperationOutputOperandIndexTest: operation " + + std::to_string(operation) + " output " + + std::to_string(output); + validate(device, message, model, [operation, output, invalidOperand](Model* model) { + model->operations[operation].outputs[output] = invalidOperand; + }); + } + } +} + +///////////////////////// REMOVE OPERAND FROM EVERYTHING ///////////////////////// + +static void removeValueAndDecrementGreaterValues(hidl_vec* vec, uint32_t value) { + if (vec) { + // remove elements matching "value" + auto last = std::remove(vec->begin(), vec->end(), value); + vec->resize(std::distance(vec->begin(), last)); + + // decrement elements exceeding "value" + std::transform(vec->begin(), vec->end(), vec->begin(), + [value](uint32_t v) { return v > value ? v-- : v; }); + } +} + +static void removeOperand(Model* model, uint32_t index) { + hidl_vec_removeAt(&model->operands, index); + for (Operation& operation : model->operations) { + removeValueAndDecrementGreaterValues(&operation.inputs, index); + removeValueAndDecrementGreaterValues(&operation.outputs, index); + } + removeValueAndDecrementGreaterValues(&model->inputIndexes, index); + removeValueAndDecrementGreaterValues(&model->outputIndexes, index); +} + +static bool removeOperandSkip(size_t operand, const Model& model) { + for (const Operation& operation : model.operations) { + // Skip removeOperandTest for the following operations. + // - SPLIT's outputs are not checked during prepareModel. + if (operation.type == OperationType::SPLIT) { + for (const size_t outOprand : operation.outputs) { + if (operand == outOprand) { + return true; + } + } + } + // BIDIRECTIONAL_SEQUENCE_LSTM and BIDIRECTIONAL_SEQUENCE_RNN can have either one or two + // outputs depending on their mergeOutputs parameter. + if (operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_LSTM || + operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_RNN) { + for (const size_t outOprand : operation.outputs) { + if (operand == outOprand) { + return true; + } + } + } + } + return false; +} + +static void removeOperandTest(const sp& device, const Model& model) { + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + if (removeOperandSkip(operand, model)) { + continue; + } + const std::string message = "removeOperandTest: operand " + std::to_string(operand); + validate(device, message, model, + [operand](Model* model) { removeOperand(model, operand); }); + } +} + +///////////////////////// REMOVE OPERATION ///////////////////////// + +static void removeOperation(Model* model, uint32_t index) { + for (uint32_t operand : model->operations[index].inputs) { + model->operands[operand].numberOfConsumers--; + } + hidl_vec_removeAt(&model->operations, index); +} + +static void removeOperationTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + const std::string message = "removeOperationTest: operation " + std::to_string(operation); + validate(device, message, model, + [operation](Model* model) { removeOperation(model, operation); }); + } +} + +///////////////////////// REMOVE OPERATION INPUT ///////////////////////// + +static bool removeOperationInputSkip(const Operation& op, size_t input) { + // Skip removeOperationInputTest for the following operations. + // - CONCATENATION has at least 2 inputs, with the last element being INT32. + // - CONV_2D, DEPTHWISE_CONV_2D, MAX_POOL_2D, AVERAGE_POOL_2D, L2_POOL_2D, RESIZE_BILINEAR, + // SPACE_TO_DEPTH, SPACE_TO_DEPTH, SPACE_TO_BATCH_ND, BATCH_TO_SPACE_ND can have an optional + // layout parameter. + // - L2_NORMALIZATION, LOCAL_RESPONSE_NORMALIZATION, SOFTMAX can have an optional axis + // parameter. + switch (op.type) { + case OperationType::CONCATENATION: { + if (op.inputs.size() > 2 && input != op.inputs.size() - 1) { + return true; + } + } break; + case OperationType::DEPTHWISE_CONV_2D: { + if ((op.inputs.size() == 12 && input == 11) || (op.inputs.size() == 9 && input == 8)) { + return true; + } + } break; + case OperationType::CONV_2D: + case OperationType::AVERAGE_POOL_2D: + case OperationType::MAX_POOL_2D: + case OperationType::L2_POOL_2D: { + if ((op.inputs.size() == 11 && input == 10) || (op.inputs.size() == 8 && input == 7)) { + return true; + } + } break; + case OperationType::RESIZE_BILINEAR: { + if (op.inputs.size() == 4 && input == 3) { + return true; + } + } break; + case OperationType::SPACE_TO_DEPTH: + case OperationType::DEPTH_TO_SPACE: + case OperationType::BATCH_TO_SPACE_ND: { + if (op.inputs.size() == 3 && input == 2) { + return true; + } + } break; + case OperationType::SPACE_TO_BATCH_ND: { + if (op.inputs.size() == 4 && input == 3) { + return true; + } + } break; + case OperationType::L2_NORMALIZATION: { + if (op.inputs.size() == 2 && input == 1) { + return true; + } + } break; + case OperationType::LOCAL_RESPONSE_NORMALIZATION: { + if (op.inputs.size() == 6 && input == 5) { + return true; + } + } break; + case OperationType::SOFTMAX: { + if (op.inputs.size() == 3 && input == 2) { + return true; + } + } break; + default: + break; + } + return false; +} + +static void removeOperationInputTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) { + const Operation& op = model.operations[operation]; + if (removeOperationInputSkip(op, input)) { + continue; + } + const std::string message = "removeOperationInputTest: operation " + + std::to_string(operation) + ", input " + + std::to_string(input); + validate(device, message, model, [operation, input](Model* model) { + uint32_t operand = model->operations[operation].inputs[input]; + model->operands[operand].numberOfConsumers--; + hidl_vec_removeAt(&model->operations[operation].inputs, input); + }); + } + } +} + +///////////////////////// REMOVE OPERATION OUTPUT ///////////////////////// + +static void removeOperationOutputTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) { + const std::string message = "removeOperationOutputTest: operation " + + std::to_string(operation) + ", output " + + std::to_string(output); + validate(device, message, model, [operation, output](Model* model) { + hidl_vec_removeAt(&model->operations[operation].outputs, output); + }); + } + } +} + +///////////////////////// MODEL VALIDATION ///////////////////////// + +// TODO: remove model input +// TODO: remove model output +// TODO: add unused operation + +///////////////////////// ADD OPERATION INPUT ///////////////////////// + +static bool addOperationInputSkip(const Operation& op) { + // Skip addOperationInputTest for the following operations. + // - L2_NORMALIZATION, LOCAL_RESPONSE_NORMALIZATION, SOFTMAX can have an optional INT32 axis + // parameter. + if ((op.type == OperationType::L2_NORMALIZATION && op.inputs.size() == 1) || + (op.type == OperationType::LOCAL_RESPONSE_NORMALIZATION && op.inputs.size() == 5) || + (op.type == OperationType::SOFTMAX && op.inputs.size() == 2)) { + return true; + } + return false; +} + +static void addOperationInputTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + if (addOperationInputSkip(model.operations[operation])) { + continue; + } + const std::string message = "addOperationInputTest: operation " + std::to_string(operation); + validate(device, message, model, [operation](Model* model) { + uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT); + hidl_vec_push_back(&model->operations[operation].inputs, index); + hidl_vec_push_back(&model->inputIndexes, index); + }); + } +} + +///////////////////////// ADD OPERATION OUTPUT ///////////////////////// + +static void addOperationOutputTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + const std::string message = + "addOperationOutputTest: operation " + std::to_string(operation); + validate(device, message, model, [operation](Model* model) { + uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT); + hidl_vec_push_back(&model->operations[operation].outputs, index); + hidl_vec_push_back(&model->outputIndexes, index); + }); + } +} + +///////////////////////// VALIDATE EXECUTION PREFERENCE ///////////////////////// + +static const int32_t invalidExecutionPreferences[] = { + static_cast(ExecutionPreference::LOW_POWER) - 1, // lower bound + static_cast(ExecutionPreference::SUSTAINED_SPEED) + 1, // upper bound +}; + +static void mutateExecutionPreferenceTest(const sp& device, const Model& model) { + for (int32_t preference : invalidExecutionPreferences) { + const std::string message = + "mutateExecutionPreferenceTest: preference " + std::to_string(preference); + validate( + device, message, model, [](Model*) {}, + static_cast(preference)); + } +} + +////////////////////////// ENTRY POINT ////////////////////////////// + +void validateModel(const sp& device, const Model& model) { + mutateOperandTypeTest(device, model); + mutateOperandRankTest(device, model); + mutateOperandScaleTest(device, model); + mutateOperandZeroPointTest(device, model); + mutateOperationOperandTypeTest(device, model); + mutateOperationTypeTest(device, model); + mutateOperationInputOperandIndexTest(device, model); + mutateOperationOutputOperandIndexTest(device, model); + removeOperandTest(device, model); + removeOperationTest(device, model); + removeOperationInputTest(device, model); + removeOperationOutputTest(device, model); + addOperationInputTest(device, model); + addOperationOutputTest(device, model); + mutateExecutionPreferenceTest(device, model); +} + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp new file mode 100644 index 0000000000..f25ee62617 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test" + +#include "1.0/Utils.h" +#include "1.2/Callbacks.h" +#include "ExecutionBurstController.h" +#include "GeneratedTestHarness.h" +#include "TestHarness.h" +#include "Utils.h" +#include "VtsHalNeuralnetworks.h" + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using implementation::ExecutionCallback; +using V1_0::ErrorStatus; +using V1_0::Request; + +///////////////////////// UTILITY FUNCTIONS ///////////////////////// + +static bool badTiming(Timing timing) { + return timing.timeOnDevice == UINT64_MAX && timing.timeInDriver == UINT64_MAX; +} + +// Primary validation function. This function will take a valid request, apply a +// mutation to it to invalidate the request, then pass it to interface calls +// that use the request. Note that the request here is passed by value, and any +// mutation to the request does not leave this function. +static void validate(const sp& preparedModel, const std::string& message, + Request request, const std::function& mutation) { + mutation(&request); + + // We'd like to test both with timing requested and without timing + // requested. Rather than running each test both ways, we'll decide whether + // to request timing by hashing the message. We do not use std::hash because + // it is not guaranteed stable across executions. + char hash = 0; + for (auto c : message) { + hash ^= c; + }; + MeasureTiming measure = (hash & 1) ? MeasureTiming::YES : MeasureTiming::NO; + + // asynchronous + { + SCOPED_TRACE(message + " [execute_1_2]"); + + sp executionCallback = new ExecutionCallback(); + Return executeLaunchStatus = + preparedModel->execute_1_2(request, measure, executionCallback); + ASSERT_TRUE(executeLaunchStatus.isOk()); + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(executeLaunchStatus)); + + executionCallback->wait(); + ErrorStatus executionReturnStatus = executionCallback->getStatus(); + const auto& outputShapes = executionCallback->getOutputShapes(); + Timing timing = executionCallback->getTiming(); + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus); + ASSERT_EQ(outputShapes.size(), 0); + ASSERT_TRUE(badTiming(timing)); + } + + // synchronous + { + SCOPED_TRACE(message + " [executeSynchronously]"); + + Return executeStatus = preparedModel->executeSynchronously( + request, measure, + [](ErrorStatus error, const hidl_vec& outputShapes, + const Timing& timing) { + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); + EXPECT_EQ(outputShapes.size(), 0); + EXPECT_TRUE(badTiming(timing)); + }); + ASSERT_TRUE(executeStatus.isOk()); + } + + // burst + { + SCOPED_TRACE(message + " [burst]"); + + // create burst + std::shared_ptr<::android::nn::ExecutionBurstController> burst = + android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true); + ASSERT_NE(nullptr, burst.get()); + + // create memory keys + std::vector keys(request.pools.size()); + for (size_t i = 0; i < keys.size(); ++i) { + keys[i] = reinterpret_cast(&request.pools[i]); + } + + // execute and verify + ErrorStatus error; + std::vector outputShapes; + Timing timing; + std::tie(error, outputShapes, timing) = burst->compute(request, measure, keys); + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, error); + EXPECT_EQ(outputShapes.size(), 0); + EXPECT_TRUE(badTiming(timing)); + + // additional burst testing + if (request.pools.size() > 0) { + // valid free + burst->freeMemory(keys.front()); + + // negative test: invalid free of unknown (blank) memory + burst->freeMemory(intptr_t{}); + + // negative test: double free of memory + burst->freeMemory(keys.front()); + } + } +} + +///////////////////////// REMOVE INPUT //////////////////////////////////// + +static void removeInputTest(const sp& preparedModel, const Request& request) { + for (size_t input = 0; input < request.inputs.size(); ++input) { + const std::string message = "removeInput: removed input " + std::to_string(input); + validate(preparedModel, message, request, + [input](Request* request) { hidl_vec_removeAt(&request->inputs, input); }); + } +} + +///////////////////////// REMOVE OUTPUT //////////////////////////////////// + +static void removeOutputTest(const sp& preparedModel, const Request& request) { + for (size_t output = 0; output < request.outputs.size(); ++output) { + const std::string message = "removeOutput: removed Output " + std::to_string(output); + validate(preparedModel, message, request, + [output](Request* request) { hidl_vec_removeAt(&request->outputs, output); }); + } +} + +///////////////////////////// ENTRY POINT ////////////////////////////////// + +void validateRequest(const sp& preparedModel, const Request& request) { + removeInputTest(preparedModel, request); + removeOutputTest(preparedModel, request); +} + +void validateRequestFailure(const sp& preparedModel, const Request& request) { + SCOPED_TRACE("Expecting request to fail [executeSynchronously]"); + Return executeStatus = preparedModel->executeSynchronously( + request, MeasureTiming::NO, + [](ErrorStatus error, const hidl_vec& outputShapes, const Timing& timing) { + ASSERT_NE(ErrorStatus::NONE, error); + EXPECT_EQ(outputShapes.size(), 0); + EXPECT_TRUE(badTiming(timing)); + }); + ASSERT_TRUE(executeStatus.isOk()); +} + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp new file mode 100644 index 0000000000..4fbd0e270f --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test" + +#include "VtsHalNeuralnetworks.h" +#include +#include +#include +#include +#include "1.0/Callbacks.h" +#include "1.0/Utils.h" +#include "GeneratedTestHarness.h" +#include "TestHarness.h" + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using implementation::PreparedModelCallback; +using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; +using V1_0::ErrorStatus; +using V1_0::Request; +using V1_1::ExecutionPreference; + +// internal helper function +void createPreparedModel(const sp& device, const Model& model, + sp* preparedModel) { + ASSERT_NE(nullptr, preparedModel); + *preparedModel = nullptr; + + // see if service can handle model + bool fullySupportsModel = false; + const Return supportedCall = device->getSupportedOperations_1_2( + model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { + ASSERT_EQ(ErrorStatus::NONE, status); + ASSERT_NE(0ul, supported.size()); + fullySupportsModel = std::all_of(supported.begin(), supported.end(), + [](bool valid) { return valid; }); + }); + ASSERT_TRUE(supportedCall.isOk()); + + // launch prepare model + const sp preparedModelCallback = new PreparedModelCallback(); + const Return prepareLaunchStatus = device->prepareModel_1_2( + model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec(), + hidl_vec(), HidlToken(), preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); + + // retrieve prepared model + preparedModelCallback->wait(); + const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + *preparedModel = getPreparedModel_1_2(preparedModelCallback); + + // The getSupportedOperations_1_2 call returns a list of operations that are + // guaranteed not to fail if prepareModel_1_2 is called, and + // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed. + // If a driver has any doubt that it can prepare an operation, it must + // return false. So here, if a driver isn't sure if it can support an + // operation, but reports that it successfully prepared the model, the test + // can continue. + if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { + ASSERT_EQ(nullptr, preparedModel->get()); + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot prepare " + "model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "prepare model that it does not support." + << std::endl; + GTEST_SKIP(); + } + ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus); + ASSERT_NE(nullptr, preparedModel->get()); +} + +void NeuralnetworksHidlTest::SetUp() { + testing::TestWithParam::SetUp(); + ASSERT_NE(kDevice, nullptr); +} + +static NamedDevice makeNamedDevice(const std::string& name) { + return {name, IDevice::getService(name)}; +} + +static std::vector getNamedDevicesImpl() { + // Retrieves the name of all service instances that implement IDevice, + // including any Lazy HAL instances. + const std::vector names = hardware::getAllHalInstanceNames(IDevice::descriptor); + + // Get a handle to each device and pair it with its name. + std::vector namedDevices; + namedDevices.reserve(names.size()); + std::transform(names.begin(), names.end(), std::back_inserter(namedDevices), makeNamedDevice); + return namedDevices; +} + +const std::vector& getNamedDevices() { + const static std::vector devices = getNamedDevicesImpl(); + return devices; +} + +std::string printNeuralnetworksHidlTest( + const testing::TestParamInfo& info) { + return gtestCompliantName(getName(info.param)); +} + +INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest); + +// Forward declaration from ValidateModel.cpp +void validateModel(const sp& device, const Model& model); +// Forward declaration from ValidateRequest.cpp +void validateRequest(const sp& preparedModel, const V1_0::Request& request); +// Forward declaration from ValidateRequest.cpp +void validateRequestFailure(const sp& preparedModel, const V1_0::Request& request); +// Forward declaration from ValidateBurst.cpp +void validateBurst(const sp& preparedModel, const V1_0::Request& request); + +void validateEverything(const sp& device, const Model& model, const Request& request) { + validateModel(device, model); + + // Create IPreparedModel. + sp preparedModel; + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; + + validateRequest(preparedModel, request); + validateBurst(preparedModel, request); +} + +void validateFailure(const sp& device, const Model& model, const Request& request) { + // TODO: Should this always succeed? + // What if the invalid input is part of the model (i.e., a parameter). + validateModel(device, model); + + // Create IPreparedModel. + sp preparedModel; + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; + + validateRequestFailure(preparedModel, request); +} + +TEST_P(ValidationTest, Test) { + const Model model = createModel(kTestModel); + const Request request = createRequest(kTestModel); + if (kTestModel.expectFailure) { + validateFailure(kDevice, model, request); + } else { + validateEverything(kDevice, model, request); + } +} + +INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); + +sp getPreparedModel_1_2(const sp& callback) { + sp preparedModelV1_0 = callback->getPreparedModel(); + return IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr); +} + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h new file mode 100644 index 0000000000..d01336eccd --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2018 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_2_VTS_HAL_NEURALNETWORKS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H + +#include +#include +#include +#include +#include "1.0/Utils.h" +#include "1.2/Callbacks.h" + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using NamedDevice = Named>; +using NeuralnetworksHidlTestParam = NamedDevice; + +class NeuralnetworksHidlTest : public testing::TestWithParam { + protected: + void SetUp() override; + const sp kDevice = getData(GetParam()); +}; + +const std::vector& getNamedDevices(); + +std::string printNeuralnetworksHidlTest( + const testing::TestParamInfo& info); + +#define INSTANTIATE_DEVICE_TEST(TestSuite) \ + INSTANTIATE_TEST_SUITE_P(PerInstance, TestSuite, testing::ValuesIn(getNamedDevices()), \ + printNeuralnetworksHidlTest) + +// Create an IPreparedModel object. If the model cannot be prepared, +// "preparedModel" will be nullptr instead. +void createPreparedModel(const sp& device, const Model& model, + sp* preparedModel); + +// Utility function to get PreparedModel from callback and downcast to V1_2. +sp getPreparedModel_1_2(const sp& callback); + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional + +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H diff --git a/neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h b/neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h new file mode 100644 index 0000000000..bf4792cc6b --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2018 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_2_CALLBACKS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The Callback classes are used internally by the NeuralNetworks runtime to + * synchronize between different threads. An asynchronous task is launched + * paired with a callback object. When a client thread requires the output being + * generated by the asynchronous task, the client thread can wait for the result + * and be blocked until it has completed. Any wait may safely be called + * concurrently, even on the same callback object. When the asynchronous task + * has finished its workload, it must immediately call "notify*". If the + * asynchronous task has failed to launch, the function that tried to launch the + * asynchronous task must immediately call "notify*". This "notify*" call + * awakens any client threads waiting on the callback object. + * + * These classes exist to enable synchronization across HIDL. When + * synchronization is only required in the same process, consider using + * std::future, std::mutex, std::condition_variable, or std::experimental::latch + * instead. + */ + +namespace android::hardware::neuralnetworks::V1_2::implementation { + +/** + * The PreparedModelCallback class is used to receive the error status of + * preparing a model as well as the prepared model from a task executing + * asynchronously with respect to the runtime. If a calling thread calls wait + * or get* on a PreparedModelCallback object and the corresponding asynchronous + * task has not finished preparing the model, the calling thread will block + * until the asynchronous task has either called notify or notify_1_2. + * + * If the callback object is notified more than once, only the results of the + * first call to notify* are used, and the results from subsequent calls are + * discarded. + * + * This callback object is passed as an argument to IDevice::prepareModel*. + */ +class PreparedModelCallback : public IPreparedModelCallback { + public: + /** + * IPreparedModelCallback::notify marks the callback object with the return + * status of the asynchronous model preparation along with the prepared + * model, and allows all prior and future wait calls on the + * PreparedModelCallback object to proceed. + * + * Either IPreparedModelCallback::notify or + * IPreparedModelCallback::notify_1_2 must be called on a given + * PreparedModelCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + * @param preparedModel Returned model that has been prepared for execution, + * nullptr if the model was unable to be prepared. + */ + Return notify(V1_0::ErrorStatus status, + const sp& preparedModel) override; + + /** + * IPreparedModelCallback::notify_1_2 marks the callback object with the + * return status of the asynchronous model preparation along with the + * prepared model, and allows all prior and future wait calls on the + * PreparedModelCallback object to proceed. + * + * Either IPreparedModelCallback::notify or + * IPreparedModelCallback::notify_1_2 must be called on a given + * PreparedModelCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + * @param preparedModel Returned model that has been prepared for execution, + * nullptr if the model was unable to be prepared. + */ + Return notify_1_2(V1_0::ErrorStatus status, + const sp& preparedModel) override; + + /** + * PreparedModelCallback::wait blocks until notify* has been called on the + * callback object. + */ + void wait() const; + + /** + * Retrieves the error status returned from the asynchronous task launched + * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished + * asynchronously preparing the model, this call will block until the + * asynchronous task notifies the object. + * + * @return status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + */ + V1_0::ErrorStatus getStatus() const; + + /** + * Retrieves the model that has been prepared for execution from the + * asynchronous task launched by IDevice::prepareModel*. If + * IDevice::prepareModel* has not finished asynchronously preparing the + * model, this call will block until the asynchronous task notifies the + * object. + * + * @return preparedModel Returned model that has been prepared for + * execution, nullptr if the model was unable to be prepared. + */ + sp getPreparedModel() const; + + private: + mutable std::mutex mMutex; + mutable std::condition_variable mCondition; + bool mNotified GUARDED_BY(mMutex) = false; + V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; + sp mPreparedModel; +}; + +/** + * The ExecutionCallback class is used to receive the results of the execution + * from a task executing asynchronously with respect to the runtime. If a + * calling thread calls wait or get* on a ExecutionCallback object and the + * corresponding asynchronous task has not finished the execution, the calling + * thread will block until the asynchronous task has either called notify or + * notify_1_2. + * + * If the callback object is notified more than once, only the results of the + * first call to notify* are used, and the results from subsequent calls are + * discarded. + * + * This callback object is passed as an argument to IPreparedModel::execute*. + */ +class ExecutionCallback : public IExecutionCallback { + public: + /** + * IExecutionCallback::notify marks the callback object with the return + * status of the asynchronous execution that held this callback and enables + * all prior and future wait calls on the ExecutionCallback object to + * proceed. + * + * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must + * be called on a given ExecutionCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from launching the asynchronous task + * (if the launch fails) or from the asynchronous task itself (if the + * launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large + * enough to store the resultant values + * - INVALID_ARGUMENT if the input request is invalid + */ + Return notify(V1_0::ErrorStatus status) override; + + /** + * IExecutionCallback::notify_1_2 marks the callback object with the results + * (error status, dynamic output shapes, and timing information) of the + * asynchronous execution that held this callback and enables all prior and + * future wait calls on the ExecutionCallback object to proceed. + * + * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must + * be called on a given ExecutionCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from launching the asynchronous task + * (if the launch fails) or from the asynchronous task itself (if the + * launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified + * error + * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is + * not large enough to store the corresponding output + * - INVALID_ARGUMENT if one of the input arguments to prepareModel is + * invalid + * @param outputShapes A list of shape information of model output operands. + * The index into "outputShapes" corresponds to the index of the output + * operand in the Request outputs vector. outputShapes must be empty + * unless the status is either NONE or OUTPUT_INSUFFICIENT_SIZE. + * @param Timing Duration of execution. Unless MeasureTiming::YES was passed + * when launching the execution and status is NONE, all times must be + * reported as UINT64_MAX. A driver may choose to report any time as + * UINT64_MAX, indicating that particular measurement is not available. + */ + Return notify_1_2(V1_0::ErrorStatus status, const hidl_vec& outputShapes, + const Timing& timing) override; + + // An overload of the latest notify interface to hide the version from ExecutionBuilder. + Return notify(V1_0::ErrorStatus status, const hidl_vec& outputShapes, + const Timing& timing) { + return notify_1_2(status, outputShapes, timing); + } + + /** + * ExecutionCallback::wait blocks until notify* has been called on the + * callback object. + */ + void wait() const; + + /** + * Retrieves the error status returned from the asynchronous task launched + * by either IPreparedModel::execute or IPreparedModel::execute_1_2. If + * IPreparedModel::execute or IPreparedModel::execute_1_2 has not finished + * asynchronously executing, this call will block until the asynchronous + * task notifies the object. + * + * @return status Error status returned from launching the asynchronous task + * (if the launch fails) or from the asynchronous task itself (if the + * launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified + * error + * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is + * not large enough to store the corresponding output + * - INVALID_ARGUMENT if one of the input arguments to prepareModel is + * invalid + */ + V1_0::ErrorStatus getStatus() const; + + /** + * Retrieves the output shapes returned from the asynchronous task launched + * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not + * finished asynchronously executing, this call will block until the + * asynchronous task notifies the object. + * + * If the asynchronous task was launched by IPreparedModel::execute, an + * empty vector will be returned. + * + * @return outputShapes A list of shape information of model output + * operands. The index into "outputShapes" corresponds to the index of + * the output operand in the Request outputs vector. outputShapes must + * be empty unless the status is either NONE or + * OUTPUT_INSUFFICIENT_SIZE. outputShaps may be empty if the status is + * NONE and all model output operands are fully-specified at execution + * time. outputShapes must have the same number of elements as the + * number of model output operands if the status is + * OUTPUT_INSUFFICIENT_SIZE, or if the status is NONE and the model has + * at least one output operand that is not fully-specified. + */ + const std::vector& getOutputShapes() const; + + /** + * Retrieves the duration of execution of the asynchronous task launched by + * IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not + * finished asynchronously executing, this call will block until the + * asynchronous task notifies the object. + * + * If the asynchronous task was launched by IPreparedModel::execute, every + * time must be UINT64_MAX. + * + * @return timing Duration of the execution. Every time must be UINT64_MAX + * unless the status is NONE. + */ + Timing getTiming() const; + + private: + /* + * ExecutionCallback::notifyInternal stores the results of the execution + * (status, output shapes, and timing information) in the ExecutionCallback + * object before any call to wait or get* return. It then enables all prior + * and future wait calls on the ExecutionCallback object to proceed. + */ + void notifyInternal(V1_0::ErrorStatus errorStatus, const hidl_vec& outputShapes, + const Timing& timing); + + // members + mutable std::mutex mMutex; + mutable std::condition_variable mCondition; + bool mNotified GUARDED_BY(mMutex) = false; + V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; + std::vector mOutputShapes = {}; + Timing mTiming = {}; +}; + +} // namespace android::hardware::neuralnetworks::V1_2::implementation + +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H From b49dadfb64d585b768b5bcf4f4a61bd3b93e87d1 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Fri, 30 Aug 2019 11:57:18 +0100 Subject: [PATCH 0139/1022] Modify NNAPI VTS tests to run on version 1.3 Bug: 139120468 Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: Id9e4d99852da8a3d5167ab7464c0e71885250501 --- neuralnetworks/1.2/vts/functional/Android.bp | 19 +- neuralnetworks/1.3/vts/functional/Android.bp | 58 ++++ .../1.3/vts/functional/BasicTests.cpp | 62 +--- .../1.3/vts/functional/Callbacks.cpp | 143 -------- .../functional/CompilationCachingTests.cpp | 13 +- .../vts/functional/GeneratedTestHarness.cpp | 18 +- .../1.3/vts/functional/GeneratedTestHarness.h | 19 +- .../1.3/vts/functional/TestAssertions.cpp | 9 +- .../1.3/vts/functional/ValidateBurst.cpp | 11 +- .../1.3/vts/functional/ValidateModel.cpp | 21 +- .../1.3/vts/functional/ValidateRequest.cpp | 10 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 20 +- .../1.3/vts/functional/VtsHalNeuralnetworks.h | 19 +- .../vts/functional/include/1.2/Callbacks.h | 325 ------------------ 14 files changed, 170 insertions(+), 577 deletions(-) create mode 100644 neuralnetworks/1.3/vts/functional/Android.bp delete mode 100644 neuralnetworks/1.3/vts/functional/Callbacks.cpp delete mode 100644 neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index bfb871986b..fc727b74f4 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -14,12 +14,28 @@ // limitations under the License. // +cc_library_static { + name: "VtsHalNeuralNetworksV1_2Callbacks", + defaults: ["VtsHalTargetTestDefaults"], + export_include_dirs: ["include"], + srcs: [ + "Callbacks.cpp", + ], + static_libs: [ + "android.hardware.neuralnetworks@1.0", + "android.hardware.neuralnetworks@1.1", + "android.hardware.neuralnetworks@1.2", + ], + header_libs: [ + "libbase_headers", + ] +} + cc_test { name: "VtsHalNeuralnetworksV1_2TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ "BasicTests.cpp", - "Callbacks.cpp", "CompilationCachingTests.cpp", "GeneratedTestHarness.cpp", "TestAssertions.cpp", @@ -45,6 +61,7 @@ cc_test { "libneuralnetworks_generated_test_harness", "libneuralnetworks_utils", "VtsHalNeuralNetworksV1_0_utils", + "VtsHalNeuralNetworksV1_2Callbacks", ], whole_static_libs: [ "neuralnetworks_generated_V1_0_example", diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp new file mode 100644 index 0000000000..90ce852e3e --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/Android.bp @@ -0,0 +1,58 @@ +// +// 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. +// + +cc_test { + name: "VtsHalNeuralNetworksV1_3TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "BasicTests.cpp", + "CompilationCachingTests.cpp", + "GeneratedTestHarness.cpp", + "TestAssertions.cpp", + "ValidateBurst.cpp", + "ValidateModel.cpp", + "ValidateRequest.cpp", + "VtsHalNeuralnetworks.cpp", + ], + shared_libs: [ + "libfmq", + "libnativewindow", + ], + static_libs: [ + "android.hardware.neuralnetworks@1.0", + "android.hardware.neuralnetworks@1.1", + "android.hardware.neuralnetworks@1.2", + "android.hardware.neuralnetworks@1.3", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "libgmock", + "libhidlmemory", + "libneuralnetworks_generated_test_harness", + "libneuralnetworks_utils", + "VtsHalNeuralNetworksV1_0_utils", + "VtsHalNeuralNetworksV1_2Callbacks", + ], + whole_static_libs: [ + "neuralnetworks_generated_V1_0_example", + "neuralnetworks_generated_V1_1_example", + "neuralnetworks_generated_V1_2_example", + "neuralnetworks_generated_V1_3_example", + ], + header_libs: [ + "libneuralnetworks_headers", + ], + test_suites: ["general-tests"], +} diff --git a/neuralnetworks/1.3/vts/functional/BasicTests.cpp b/neuralnetworks/1.3/vts/functional/BasicTests.cpp index 8e82c5376e..b64dc2f61b 100644 --- a/neuralnetworks/1.3/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.3/vts/functional/BasicTests.cpp @@ -18,11 +18,14 @@ #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { using V1_0::DeviceStatus; using V1_0::ErrorStatus; using V1_0::PerformanceInfo; +using V1_2::Constant; +using V1_2::DeviceType; +using V1_2::Extension; // create device test TEST_P(NeuralnetworksHidlTest, CreateDevice) {} @@ -37,7 +40,7 @@ TEST_P(NeuralnetworksHidlTest, StatusTest) { // initialization TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) { using OperandPerformance = Capabilities::OperandPerformance; - Return ret = kDevice->getCapabilities_1_2([](ErrorStatus status, + Return ret = kDevice->getCapabilities_1_3([](ErrorStatus status, const Capabilities& capabilities) { EXPECT_EQ(ErrorStatus::NONE, status); @@ -58,57 +61,4 @@ TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) { }); EXPECT_TRUE(ret.isOk()); } - -// device version test -TEST_P(NeuralnetworksHidlTest, GetDeviceVersionStringTest) { - Return ret = - kDevice->getVersionString([](ErrorStatus status, const hidl_string& version) { - EXPECT_EQ(ErrorStatus::NONE, status); - EXPECT_LT(0, version.size()); - }); - EXPECT_TRUE(ret.isOk()); -} - -// device type test -TEST_P(NeuralnetworksHidlTest, GetDeviceTypeTest) { - Return ret = kDevice->getType([](ErrorStatus status, DeviceType type) { - EXPECT_EQ(ErrorStatus::NONE, status); - EXPECT_TRUE(type == DeviceType::OTHER || type == DeviceType::CPU || - type == DeviceType::GPU || type == DeviceType::ACCELERATOR); - }); - EXPECT_TRUE(ret.isOk()); -} - -// device supported extensions test -TEST_P(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) { - Return ret = kDevice->getSupportedExtensions( - [](ErrorStatus status, const hidl_vec& extensions) { - EXPECT_EQ(ErrorStatus::NONE, status); - for (auto& extension : extensions) { - std::string extensionName = extension.name; - EXPECT_FALSE(extensionName.empty()); - for (char c : extensionName) { - EXPECT_TRUE(('a' <= c && c <= 'z') || ('0' <= c && c <= '9') || c == '_' || - c == '.') - << "Extension name contains an illegal character: " << c; - } - EXPECT_NE(extensionName.find('.'), std::string::npos) - << "Extension name must start with the reverse domain name of the " - "vendor"; - } - }); - EXPECT_TRUE(ret.isOk()); -} - -// getNumberOfCacheFilesNeeded test -TEST_P(NeuralnetworksHidlTest, getNumberOfCacheFilesNeeded) { - Return ret = kDevice->getNumberOfCacheFilesNeeded( - [](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) { - EXPECT_EQ(ErrorStatus::NONE, status); - EXPECT_LE(numModelCache, - static_cast(Constant::MAX_NUMBER_OF_CACHE_FILES)); - EXPECT_LE(numDataCache, static_cast(Constant::MAX_NUMBER_OF_CACHE_FILES)); - }); - EXPECT_TRUE(ret.isOk()); -} -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/Callbacks.cpp b/neuralnetworks/1.3/vts/functional/Callbacks.cpp deleted file mode 100644 index 3972ad6ff2..0000000000 --- a/neuralnetworks/1.3/vts/functional/Callbacks.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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 "Callbacks" - -#include "1.2/Callbacks.h" - -#include - -#include - -namespace android::hardware::neuralnetworks::V1_2::implementation { - -using V1_0::ErrorStatus; - -constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits::max(), - .timeInDriver = std::numeric_limits::max()}; - -// PreparedModelCallback methods begin here - -Return PreparedModelCallback::notify(ErrorStatus errorStatus, - const sp& preparedModel) { - { - std::lock_guard hold(mMutex); - - // quick-return if object has already been notified - if (mNotified) { - return Void(); - } - - // store results and mark as notified - mErrorStatus = errorStatus; - mPreparedModel = preparedModel; - mNotified = true; - } - - mCondition.notify_all(); - return Void(); -} - -Return PreparedModelCallback::notify_1_2(ErrorStatus errorStatus, - const sp& preparedModel) { - return notify(errorStatus, preparedModel); -} - -void PreparedModelCallback::wait() const { - std::unique_lock lock(mMutex); - mCondition.wait(lock, [this] { return mNotified; }); -} - -ErrorStatus PreparedModelCallback::getStatus() const { - wait(); - return mErrorStatus; -} - -sp PreparedModelCallback::getPreparedModel() const { - wait(); - return mPreparedModel; -} - -// ExecutionCallback methods begin here - -Return ExecutionCallback::notify(ErrorStatus errorStatus) { - notifyInternal(errorStatus, {}, kNoTiming); - return Void(); -} - -Return ExecutionCallback::notify_1_2(ErrorStatus errorStatus, - const hidl_vec& outputShapes, - const Timing& timing) { - if (errorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { - // outputShapes must not be empty if OUTPUT_INSUFFICIENT_SIZE. - if (outputShapes.size() == 0) { - LOG(ERROR) << "Notified with empty output shape vector when OUTPUT_INSUFFICIENT_SIZE"; - notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); - return Void(); - } - } else if (errorStatus != ErrorStatus::NONE) { - // outputShapes must be empty if errorStatus is neither NONE nor OUTPUT_INSUFFICIENT_SIZE. - if (outputShapes.size() != 0) { - LOG(ERROR) << "Notified with non-empty output shape vector when error status is " - "neither NONE nor OUTPUT_INSUFFICIENT_SIZE"; - notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); - return Void(); - } - } - notifyInternal(errorStatus, outputShapes, timing); - return Void(); -} - -void ExecutionCallback::wait() const { - std::unique_lock lock(mMutex); - mCondition.wait(lock, [this] { return mNotified; }); -} - -ErrorStatus ExecutionCallback::getStatus() const { - wait(); - return mErrorStatus; -} - -const std::vector& ExecutionCallback::getOutputShapes() const { - wait(); - return mOutputShapes; -} - -Timing ExecutionCallback::getTiming() const { - wait(); - return mTiming; -} - -void ExecutionCallback::notifyInternal(ErrorStatus errorStatus, - const hidl_vec& outputShapes, - const Timing& timing) { - { - std::lock_guard hold(mMutex); - - // quick-return if object has already been notified - if (mNotified) { - return; - } - - mErrorStatus = errorStatus; - mOutputShapes = outputShapes; - mTiming = timing; - mNotified = true; - } - mCondition.notify_all(); -} - -} // namespace android::hardware::neuralnetworks::V1_2::implementation diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp index 2130a76b75..0ac4738fff 100644 --- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp @@ -45,12 +45,15 @@ namespace generated_tests::mobilenet_quantized { const test_helper::TestModel& get_test_model(); } // namespace generated_tests::mobilenet_quantized -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { using namespace test_helper; -using implementation::PreparedModelCallback; using V1_0::ErrorStatus; using V1_1::ExecutionPreference; +using V1_2::Constant; +using V1_2::IPreparedModel; +using V1_2::OperationType; +using V1_2::implementation::PreparedModelCallback; namespace float32_model { @@ -302,7 +305,7 @@ class CompilationCachingTestBase : public testing::Test { // See if the service can handle the model. bool isModelFullySupported(const Model& model) { bool fullySupportsModel = false; - Return supportedCall = kDevice->getSupportedOperations_1_2( + Return supportedCall = kDevice->getSupportedOperations_1_3( model, [&fullySupportsModel, &model](ErrorStatus status, const hidl_vec& supported) { ASSERT_EQ(ErrorStatus::NONE, status); @@ -323,7 +326,7 @@ class CompilationCachingTestBase : public testing::Test { sp preparedModelCallback = new PreparedModelCallback(); hidl_array cacheToken(mToken); Return prepareLaunchStatus = - kDevice->prepareModel_1_2(model, ExecutionPreference::FAST_SINGLE_ANSWER, + kDevice->prepareModel_1_3(model, ExecutionPreference::FAST_SINGLE_ANSWER, modelCache, dataCache, cacheToken, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(static_cast(prepareLaunchStatus), ErrorStatus::NONE); @@ -1371,4 +1374,4 @@ INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest, testing::Range(0U, 10U)), printCompilationCachingSecurityTest); -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 2beec983e0..16a7d70fb5 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -27,6 +27,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -44,17 +47,24 @@ #include "Utils.h" #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { using namespace test_helper; using hidl::memory::V1_0::IMemory; -using implementation::ExecutionCallback; -using implementation::PreparedModelCallback; using V1_0::DataLocation; using V1_0::ErrorStatus; using V1_0::OperandLifeTime; using V1_0::Request; using V1_1::ExecutionPreference; +using V1_2::Constant; +using V1_2::IPreparedModel; +using V1_2::MeasureTiming; +using V1_2::OperationType; +using V1_2::OutputShape; +using V1_2::SymmPerChannelQuantParams; +using V1_2::Timing; +using V1_2::implementation::ExecutionCallback; +using V1_2::implementation::PreparedModelCallback; using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; @@ -405,4 +415,4 @@ INSTANTIATE_GENERATED_TEST(GeneratedTest, INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h index dfc980c169..b9277cfd4a 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h @@ -14,19 +14,19 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H -#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H -#include #include -#include +#include +#include #include #include #include "1.0/Utils.h" #include "TestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { using NamedModel = Named; using GeneratedTestParam = std::tuple; @@ -55,11 +55,12 @@ class ValidationTest : public GeneratedTestBase {}; Model createModel(const test_helper::TestModel& testModel); -void PrepareModel(const sp& device, const Model& model, sp* preparedModel); +void PrepareModel(const sp& device, const Model& model, + sp* preparedModel); -void EvaluatePreparedModel(const sp& preparedModel, +void EvaluatePreparedModel(const sp& preparedModel, const test_helper::TestModel& testModel, bool testDynamicOutputShape); -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional -#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H diff --git a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp index a0aa3c37d1..7361078eca 100644 --- a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp +++ b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp @@ -14,10 +14,10 @@ * limitations under the License. */ -#include +#include #include "TestHarness.h" -namespace android::hardware::neuralnetworks::V1_2 { +namespace android::hardware::neuralnetworks::V1_3 { // Make sure that the HIDL enums are compatible with the values defined in // frameworks/ml/nn/tools/test_generator/test_harness/include/TestHarness.h. @@ -25,6 +25,8 @@ using namespace test_helper; #define CHECK_TEST_ENUM(EnumType, enumValue) \ static_assert(static_cast(Test##EnumType::enumValue) == EnumType::enumValue) +using V1_2::OperationType; + CHECK_TEST_ENUM(OperandType, FLOAT32); CHECK_TEST_ENUM(OperandType, INT32); CHECK_TEST_ENUM(OperandType, UINT32); @@ -39,6 +41,7 @@ CHECK_TEST_ENUM(OperandType, FLOAT16); CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_SYMM_PER_CHANNEL); CHECK_TEST_ENUM(OperandType, TENSOR_QUANT16_ASYMM); CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_SYMM); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_ASYMM_SIGNED); CHECK_TEST_ENUM(OperationType, ADD); CHECK_TEST_ENUM(OperationType, AVERAGE_POOL_2D); @@ -138,4 +141,4 @@ CHECK_TEST_ENUM(OperationType, RESIZE_NEAREST_NEIGHBOR); #undef CHECK_TEST_ENUM -} // namespace android::hardware::neuralnetworks::V1_2 +} // namespace android::hardware::neuralnetworks::V1_3 diff --git a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp index 1d4493d208..95f9f427b2 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp @@ -28,13 +28,20 @@ #include #include -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { using nn::ExecutionBurstController; using nn::RequestChannelSender; using nn::ResultChannelReceiver; using V1_0::ErrorStatus; using V1_0::Request; +using V1_2::FmqRequestDatum; +using V1_2::FmqResultDatum; +using V1_2::IBurstCallback; +using V1_2::IBurstContext; +using V1_2::IPreparedModel; +using V1_2::MeasureTiming; +using V1_2::Timing; using ExecutionBurstCallback = ExecutionBurstController::ExecutionBurstCallback; // This constant value represents the length of an FMQ that is large enough to @@ -397,4 +404,4 @@ void validateBurst(const sp& preparedModel, const Request& reque ASSERT_NO_FATAL_FAILURE(validateBurstSanitized(preparedModel, request)); } -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 30530beacc..44b32a9fec 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -21,21 +21,26 @@ #include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { -using implementation::PreparedModelCallback; using V1_0::ErrorStatus; using V1_0::OperandLifeTime; using V1_1::ExecutionPreference; -using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; +using V1_2::IPreparedModel; +using V1_2::OperationType; +using V1_2::OperationTypeRange; +using V1_2::SymmPerChannelQuantParams; +using V1_2::implementation::PreparedModelCallback; +using HidlToken = + hidl_array(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// static void validateGetSupportedOperations(const sp& device, const std::string& message, const Model& model) { - SCOPED_TRACE(message + " [getSupportedOperations_1_2]"); + SCOPED_TRACE(message + " [getSupportedOperations_1_3]"); - Return ret = device->getSupportedOperations_1_2( + Return ret = device->getSupportedOperations_1_3( model, [&](ErrorStatus status, const hidl_vec&) { EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); }); @@ -44,11 +49,11 @@ static void validateGetSupportedOperations(const sp& device, const std: static void validatePrepareModel(const sp& device, const std::string& message, const Model& model, ExecutionPreference preference) { - SCOPED_TRACE(message + " [prepareModel_1_2]"); + SCOPED_TRACE(message + " [prepareModel_1_3]"); sp preparedModelCallback = new PreparedModelCallback(); Return prepareLaunchStatus = - device->prepareModel_1_2(model, preference, hidl_vec(), + device->prepareModel_1_3(model, preference, hidl_vec(), hidl_vec(), HidlToken(), preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(prepareLaunchStatus)); @@ -710,4 +715,4 @@ void validateModel(const sp& device, const Model& model) { mutateExecutionPreferenceTest(device, model); } -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index f25ee62617..612212382c 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -24,11 +24,15 @@ #include "Utils.h" #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { -using implementation::ExecutionCallback; using V1_0::ErrorStatus; using V1_0::Request; +using V1_2::IPreparedModel; +using V1_2::MeasureTiming; +using V1_2::OutputShape; +using V1_2::Timing; +using V1_2::implementation::ExecutionCallback; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// @@ -165,4 +169,4 @@ void validateRequestFailure(const sp& preparedModel, const Reque ASSERT_TRUE(executeStatus.isOk()); } -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index 4fbd0e270f..4f0e150b32 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -26,13 +26,15 @@ #include "GeneratedTestHarness.h" #include "TestHarness.h" -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { -using implementation::PreparedModelCallback; -using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; +using HidlToken = + hidl_array(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; using V1_0::ErrorStatus; using V1_0::Request; using V1_1::ExecutionPreference; +using V1_2::IPreparedModel; +using V1_2::implementation::PreparedModelCallback; // internal helper function void createPreparedModel(const sp& device, const Model& model, @@ -42,7 +44,7 @@ void createPreparedModel(const sp& device, const Model& model, // see if service can handle model bool fullySupportsModel = false; - const Return supportedCall = device->getSupportedOperations_1_2( + const Return supportedCall = device->getSupportedOperations_1_3( model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { ASSERT_EQ(ErrorStatus::NONE, status); ASSERT_NE(0ul, supported.size()); @@ -53,7 +55,7 @@ void createPreparedModel(const sp& device, const Model& model, // launch prepare model const sp preparedModelCallback = new PreparedModelCallback(); - const Return prepareLaunchStatus = device->prepareModel_1_2( + const Return prepareLaunchStatus = device->prepareModel_1_3( model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec(), hidl_vec(), HidlToken(), preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); @@ -64,8 +66,8 @@ void createPreparedModel(const sp& device, const Model& model, const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); *preparedModel = getPreparedModel_1_2(preparedModelCallback); - // The getSupportedOperations_1_2 call returns a list of operations that are - // guaranteed not to fail if prepareModel_1_2 is called, and + // The getSupportedOperations_1_3 call returns a list of operations that are + // guaranteed not to fail if prepareModel_1_3 is called, and // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed. // If a driver has any doubt that it can prepare an operation, it must // return false. So here, if a driver isn't sure if it can support an @@ -163,9 +165,9 @@ TEST_P(ValidationTest, Test) { INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); -sp getPreparedModel_1_2(const sp& callback) { +sp getPreparedModel_1_2(const sp& callback) { sp preparedModelV1_0 = callback->getPreparedModel(); return IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr); } -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h index d01336eccd..fc654ce8f0 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h @@ -14,17 +14,17 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H -#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H -#include #include -#include +#include +#include #include #include "1.0/Utils.h" #include "1.2/Callbacks.h" -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { using NamedDevice = Named>; using NeuralnetworksHidlTestParam = NamedDevice; @@ -47,11 +47,12 @@ std::string printNeuralnetworksHidlTest( // Create an IPreparedModel object. If the model cannot be prepared, // "preparedModel" will be nullptr instead. void createPreparedModel(const sp& device, const Model& model, - sp* preparedModel); + sp* preparedModel); // Utility function to get PreparedModel from callback and downcast to V1_2. -sp getPreparedModel_1_2(const sp& callback); +sp getPreparedModel_1_2( + const sp& callback); -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional -#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H diff --git a/neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h b/neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h deleted file mode 100644 index bf4792cc6b..0000000000 --- a/neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (C) 2018 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_2_CALLBACKS_H -#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * The Callback classes are used internally by the NeuralNetworks runtime to - * synchronize between different threads. An asynchronous task is launched - * paired with a callback object. When a client thread requires the output being - * generated by the asynchronous task, the client thread can wait for the result - * and be blocked until it has completed. Any wait may safely be called - * concurrently, even on the same callback object. When the asynchronous task - * has finished its workload, it must immediately call "notify*". If the - * asynchronous task has failed to launch, the function that tried to launch the - * asynchronous task must immediately call "notify*". This "notify*" call - * awakens any client threads waiting on the callback object. - * - * These classes exist to enable synchronization across HIDL. When - * synchronization is only required in the same process, consider using - * std::future, std::mutex, std::condition_variable, or std::experimental::latch - * instead. - */ - -namespace android::hardware::neuralnetworks::V1_2::implementation { - -/** - * The PreparedModelCallback class is used to receive the error status of - * preparing a model as well as the prepared model from a task executing - * asynchronously with respect to the runtime. If a calling thread calls wait - * or get* on a PreparedModelCallback object and the corresponding asynchronous - * task has not finished preparing the model, the calling thread will block - * until the asynchronous task has either called notify or notify_1_2. - * - * If the callback object is notified more than once, only the results of the - * first call to notify* are used, and the results from subsequent calls are - * discarded. - * - * This callback object is passed as an argument to IDevice::prepareModel*. - */ -class PreparedModelCallback : public IPreparedModelCallback { - public: - /** - * IPreparedModelCallback::notify marks the callback object with the return - * status of the asynchronous model preparation along with the prepared - * model, and allows all prior and future wait calls on the - * PreparedModelCallback object to proceed. - * - * Either IPreparedModelCallback::notify or - * IPreparedModelCallback::notify_1_2 must be called on a given - * PreparedModelCallback object. - * - * If the callback object is notified more than once, only the results of - * the first call to notify* are used, and the results from subsequent calls - * are discarded. - * - * @param status Error status returned from asynchronously preparing the - * model; will be: - * - NONE if the asynchronous preparation was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if there is an unspecified error - * - INVALID_ARGUMENT if the input model is invalid - * @param preparedModel Returned model that has been prepared for execution, - * nullptr if the model was unable to be prepared. - */ - Return notify(V1_0::ErrorStatus status, - const sp& preparedModel) override; - - /** - * IPreparedModelCallback::notify_1_2 marks the callback object with the - * return status of the asynchronous model preparation along with the - * prepared model, and allows all prior and future wait calls on the - * PreparedModelCallback object to proceed. - * - * Either IPreparedModelCallback::notify or - * IPreparedModelCallback::notify_1_2 must be called on a given - * PreparedModelCallback object. - * - * If the callback object is notified more than once, only the results of - * the first call to notify* are used, and the results from subsequent calls - * are discarded. - * - * @param status Error status returned from asynchronously preparing the - * model; will be: - * - NONE if the asynchronous preparation was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if there is an unspecified error - * - INVALID_ARGUMENT if the input model is invalid - * @param preparedModel Returned model that has been prepared for execution, - * nullptr if the model was unable to be prepared. - */ - Return notify_1_2(V1_0::ErrorStatus status, - const sp& preparedModel) override; - - /** - * PreparedModelCallback::wait blocks until notify* has been called on the - * callback object. - */ - void wait() const; - - /** - * Retrieves the error status returned from the asynchronous task launched - * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished - * asynchronously preparing the model, this call will block until the - * asynchronous task notifies the object. - * - * @return status Error status returned from asynchronously preparing the - * model; will be: - * - NONE if the asynchronous preparation was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if there is an unspecified error - * - INVALID_ARGUMENT if the input model is invalid - */ - V1_0::ErrorStatus getStatus() const; - - /** - * Retrieves the model that has been prepared for execution from the - * asynchronous task launched by IDevice::prepareModel*. If - * IDevice::prepareModel* has not finished asynchronously preparing the - * model, this call will block until the asynchronous task notifies the - * object. - * - * @return preparedModel Returned model that has been prepared for - * execution, nullptr if the model was unable to be prepared. - */ - sp getPreparedModel() const; - - private: - mutable std::mutex mMutex; - mutable std::condition_variable mCondition; - bool mNotified GUARDED_BY(mMutex) = false; - V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; - sp mPreparedModel; -}; - -/** - * The ExecutionCallback class is used to receive the results of the execution - * from a task executing asynchronously with respect to the runtime. If a - * calling thread calls wait or get* on a ExecutionCallback object and the - * corresponding asynchronous task has not finished the execution, the calling - * thread will block until the asynchronous task has either called notify or - * notify_1_2. - * - * If the callback object is notified more than once, only the results of the - * first call to notify* are used, and the results from subsequent calls are - * discarded. - * - * This callback object is passed as an argument to IPreparedModel::execute*. - */ -class ExecutionCallback : public IExecutionCallback { - public: - /** - * IExecutionCallback::notify marks the callback object with the return - * status of the asynchronous execution that held this callback and enables - * all prior and future wait calls on the ExecutionCallback object to - * proceed. - * - * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must - * be called on a given ExecutionCallback object. - * - * If the callback object is notified more than once, only the results of - * the first call to notify* are used, and the results from subsequent calls - * are discarded. - * - * @param status Error status returned from launching the asynchronous task - * (if the launch fails) or from the asynchronous task itself (if the - * launch succeeds). Must be: - * - NONE if the asynchronous execution was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if there is an unspecified error - * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large - * enough to store the resultant values - * - INVALID_ARGUMENT if the input request is invalid - */ - Return notify(V1_0::ErrorStatus status) override; - - /** - * IExecutionCallback::notify_1_2 marks the callback object with the results - * (error status, dynamic output shapes, and timing information) of the - * asynchronous execution that held this callback and enables all prior and - * future wait calls on the ExecutionCallback object to proceed. - * - * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must - * be called on a given ExecutionCallback object. - * - * If the callback object is notified more than once, only the results of - * the first call to notify* are used, and the results from subsequent calls - * are discarded. - * - * @param status Error status returned from launching the asynchronous task - * (if the launch fails) or from the asynchronous task itself (if the - * launch succeeds). Must be: - * - NONE if the asynchronous execution was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified - * error - * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is - * not large enough to store the corresponding output - * - INVALID_ARGUMENT if one of the input arguments to prepareModel is - * invalid - * @param outputShapes A list of shape information of model output operands. - * The index into "outputShapes" corresponds to the index of the output - * operand in the Request outputs vector. outputShapes must be empty - * unless the status is either NONE or OUTPUT_INSUFFICIENT_SIZE. - * @param Timing Duration of execution. Unless MeasureTiming::YES was passed - * when launching the execution and status is NONE, all times must be - * reported as UINT64_MAX. A driver may choose to report any time as - * UINT64_MAX, indicating that particular measurement is not available. - */ - Return notify_1_2(V1_0::ErrorStatus status, const hidl_vec& outputShapes, - const Timing& timing) override; - - // An overload of the latest notify interface to hide the version from ExecutionBuilder. - Return notify(V1_0::ErrorStatus status, const hidl_vec& outputShapes, - const Timing& timing) { - return notify_1_2(status, outputShapes, timing); - } - - /** - * ExecutionCallback::wait blocks until notify* has been called on the - * callback object. - */ - void wait() const; - - /** - * Retrieves the error status returned from the asynchronous task launched - * by either IPreparedModel::execute or IPreparedModel::execute_1_2. If - * IPreparedModel::execute or IPreparedModel::execute_1_2 has not finished - * asynchronously executing, this call will block until the asynchronous - * task notifies the object. - * - * @return status Error status returned from launching the asynchronous task - * (if the launch fails) or from the asynchronous task itself (if the - * launch succeeds). Must be: - * - NONE if the asynchronous execution was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified - * error - * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is - * not large enough to store the corresponding output - * - INVALID_ARGUMENT if one of the input arguments to prepareModel is - * invalid - */ - V1_0::ErrorStatus getStatus() const; - - /** - * Retrieves the output shapes returned from the asynchronous task launched - * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not - * finished asynchronously executing, this call will block until the - * asynchronous task notifies the object. - * - * If the asynchronous task was launched by IPreparedModel::execute, an - * empty vector will be returned. - * - * @return outputShapes A list of shape information of model output - * operands. The index into "outputShapes" corresponds to the index of - * the output operand in the Request outputs vector. outputShapes must - * be empty unless the status is either NONE or - * OUTPUT_INSUFFICIENT_SIZE. outputShaps may be empty if the status is - * NONE and all model output operands are fully-specified at execution - * time. outputShapes must have the same number of elements as the - * number of model output operands if the status is - * OUTPUT_INSUFFICIENT_SIZE, or if the status is NONE and the model has - * at least one output operand that is not fully-specified. - */ - const std::vector& getOutputShapes() const; - - /** - * Retrieves the duration of execution of the asynchronous task launched by - * IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not - * finished asynchronously executing, this call will block until the - * asynchronous task notifies the object. - * - * If the asynchronous task was launched by IPreparedModel::execute, every - * time must be UINT64_MAX. - * - * @return timing Duration of the execution. Every time must be UINT64_MAX - * unless the status is NONE. - */ - Timing getTiming() const; - - private: - /* - * ExecutionCallback::notifyInternal stores the results of the execution - * (status, output shapes, and timing information) in the ExecutionCallback - * object before any call to wait or get* return. It then enables all prior - * and future wait calls on the ExecutionCallback object to proceed. - */ - void notifyInternal(V1_0::ErrorStatus errorStatus, const hidl_vec& outputShapes, - const Timing& timing); - - // members - mutable std::mutex mMutex; - mutable std::condition_variable mCondition; - bool mNotified GUARDED_BY(mMutex) = false; - V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; - std::vector mOutputShapes = {}; - Timing mTiming = {}; -}; - -} // namespace android::hardware::neuralnetworks::V1_2::implementation - -#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H From 809249059c7a21ca1d4b3bb2331746be541aa0c8 Mon Sep 17 00:00:00 2001 From: Patrik Fimml Date: Tue, 1 Oct 2019 14:14:23 +0200 Subject: [PATCH 0140/1022] Wifi 1.3: Fix STA getFactoryMacAddress test. It's valid for individual bytes in a MAC address to be zero as long as they're not all zero. Bug: 132705022 Bug: 141916952 Test: m -j32 vts && vts-tradefed run vts-hal --skip-preconditions --module VtsHalWifiV1_3Target Change-Id: Ic33a3b80cce90eb4b031aca33aa66bf2a375dc16 --- wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp index 71e90acb93..d382f30e0f 100644 --- a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp +++ b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp @@ -27,6 +27,8 @@ #include "wifi_hidl_test_utils.h" using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::wifi::V1_0::WifiStatus; using ::android::hardware::wifi::V1_0::WifiStatusCode; using ::android::hardware::wifi::V1_3::IWifiStaIface; @@ -59,14 +61,11 @@ class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { * and return a success status code. */ TEST_F(WifiStaIfaceHidlTest, GetFactoryMacAddress) { - const auto& status_and_mac = + std::pair > status_and_mac = HIDL_INVOKE(wifi_sta_iface_, getFactoryMacAddress); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mac.first.code); - const int num_elements = sizeof(status_and_mac.second) / sizeof(uint8_t); - EXPECT_EQ(6, num_elements); - for (int i = 0; i < num_elements; i++) { - EXPECT_NE(0, status_and_mac.second[i]); - } + hidl_array all_zero{}; + EXPECT_NE(all_zero, status_and_mac.second); } /* From 82b84148c7249952386f32d89871baf4ced96b34 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 2 Oct 2019 12:50:29 -0700 Subject: [PATCH 0141/1022] Remove libhwbinder/libhidltransport deps Since these were combined into libhidlbase. Bug: 135686713 Test: build only (libhwbinder/libhidltransport are empty) Change-Id: I878a4d04e65ef13f3a0ebaf64177f673958d213c --- automotive/can/1.0/default/Android.bp | 1 - automotive/can/1.0/tools/Android.bp | 3 --- automotive/evs/1.1/default/Android.bp | 1 - graphics/composer/2.2/vts/functional/Android.bp | 2 -- graphics/composer/2.4/default/Android.bp | 1 - graphics/composer/2.4/vts/functional/Android.bp | 1 - sensors/2.0/multihal/Android.bp | 1 - sensors/2.0/multihal/tests/Android.bp | 2 -- 8 files changed, 12 deletions(-) diff --git a/automotive/can/1.0/default/Android.bp b/automotive/can/1.0/default/Android.bp index 0a4afd6e37..8aa1d6bff7 100644 --- a/automotive/can/1.0/default/Android.bp +++ b/automotive/can/1.0/default/Android.bp @@ -47,7 +47,6 @@ cc_binary { shared_libs: [ "android.hardware.automotive.can@1.0", "libhidlbase", - "libhidltransport", ], static_libs: [ "android.hardware.automotive.can@libnetdevice", diff --git a/automotive/can/1.0/tools/Android.bp b/automotive/can/1.0/tools/Android.bp index 8c26985d51..21f364b629 100644 --- a/automotive/can/1.0/tools/Android.bp +++ b/automotive/can/1.0/tools/Android.bp @@ -23,7 +23,6 @@ cc_binary { shared_libs: [ "android.hardware.automotive.can@1.0", "libhidlbase", - "libhidltransport", ], header_libs: [ "android.hardware.automotive.can@hidl-utils-lib", @@ -39,7 +38,6 @@ cc_binary { shared_libs: [ "android.hardware.automotive.can@1.0", "libhidlbase", - "libhidltransport", ], header_libs: [ "android.hardware.automotive.can@hidl-utils-lib", @@ -55,6 +53,5 @@ cc_binary { shared_libs: [ "android.hardware.automotive.can@1.0", "libhidlbase", - "libhidltransport", ], } diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp index 411f0ff742..a46347102f 100644 --- a/automotive/evs/1.1/default/Android.bp +++ b/automotive/evs/1.1/default/Android.bp @@ -19,7 +19,6 @@ cc_binary { "libcutils", "libhardware", "libhidlbase", - "libhidltransport", "liblog", "libui", "libutils", diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp index 28728803e8..21ba9f3d7d 100644 --- a/graphics/composer/2.2/vts/functional/Android.bp +++ b/graphics/composer/2.2/vts/functional/Android.bp @@ -30,8 +30,6 @@ cc_test { "libfmq", "libgui", "libhidlbase", - "libhidltransport", - "libhwbinder", "libprocessgroup", "libsync", "libui", diff --git a/graphics/composer/2.4/default/Android.bp b/graphics/composer/2.4/default/Android.bp index a44e68794e..a30609b1a2 100644 --- a/graphics/composer/2.4/default/Android.bp +++ b/graphics/composer/2.4/default/Android.bp @@ -37,7 +37,6 @@ cc_binary { "libfmq", "libhardware", "libhidlbase", - "libhidltransport", "libhwc2on1adapter", "libhwc2onfbadapter", "liblog", diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp index 6ee78738cc..921c42155f 100644 --- a/graphics/composer/2.4/vts/functional/Android.bp +++ b/graphics/composer/2.4/vts/functional/Android.bp @@ -22,7 +22,6 @@ cc_test { // TODO(b/64437680): Assume these libs are always available on the device. shared_libs: [ "libfmq", - "libhidltransport", "libsync", ], static_libs: [ diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp index 216cc209a2..710835f84d 100644 --- a/sensors/2.0/multihal/Android.bp +++ b/sensors/2.0/multihal/Android.bp @@ -24,7 +24,6 @@ cc_defaults { "libcutils", "libfmq", "libhidlbase", - "libhidltransport", "liblog", "libpower", "libutils", diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp index ab260a47dc..aa44687590 100644 --- a/sensors/2.0/multihal/tests/Android.bp +++ b/sensors/2.0/multihal/tests/Android.bp @@ -28,7 +28,6 @@ cc_defaults { "libcutils", "libfmq", "libhidlbase", - "libhidltransport", "liblog", "libpower", "libutils", @@ -83,7 +82,6 @@ cc_test { "libcutils", "libfmq", "libhidlbase", - "libhidltransport", "liblog", "libpower", "libutils", From ce44a4b36396590aea8ef0f87b83e2613f3ebe19 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Thu, 19 Sep 2019 15:50:09 -0700 Subject: [PATCH 0142/1022] composer: Add getDisplayConnectionType Distinguish between internal and external displays, to obviate assuming that the first display is internal and subsequent displays are external. Note that connector types (e.g. DSI, HDMI, DisplayPort) are not enumerated, since that information is irrelevant for internal connections, and can be extracted from the EDID for external connections in the few cases where it matters, e.g. gating features like daisy chaining and content protection. Bug: 134771872 Test: Build Change-Id: I8a27e4ef569626620711910fcbaed5a7e12e6870 --- .../compatibility_matrix.current.xml | 2 +- graphics/composer/2.4/IComposer.hal | 2 -- graphics/composer/2.4/IComposerClient.hal | 29 ++++++++++++++++--- .../include/composer-hal/2.4/ComposerClient.h | 8 +++++ .../include/composer-hal/2.4/ComposerHal.h | 2 ++ .../include/composer-passthrough/2.4/HwcHal.h | 19 ++++++++++++ .../composer/2.4/utils/vts/ComposerVts.cpp | 11 ++++++- .../include/composer-vts/2.4/ComposerVts.h | 3 ++ .../VtsHalGraphicsComposerV2_4TargetTest.cpp | 10 +++++++ 9 files changed, 78 insertions(+), 8 deletions(-) diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 69766f2a51..e73eeb0247 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -204,7 +204,7 @@ android.hardware.graphics.composer - 2.1-3 + 2.1-4 IComposer default diff --git a/graphics/composer/2.4/IComposer.hal b/graphics/composer/2.4/IComposer.hal index 34801daa27..d3b3cb60a7 100644 --- a/graphics/composer/2.4/IComposer.hal +++ b/graphics/composer/2.4/IComposer.hal @@ -17,12 +17,10 @@ package android.hardware.graphics.composer@2.4; import IComposerClient; - import @2.1::Error; import @2.3::IComposer; interface IComposer extends @2.3::IComposer { - /** * Creates a v2.4 client of the composer. Supersedes @2.3::createClient. * diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal index 8fe0976781..60445f5327 100644 --- a/graphics/composer/2.4/IComposerClient.hal +++ b/graphics/composer/2.4/IComposerClient.hal @@ -21,13 +21,12 @@ import @2.1::Error; import @2.3::IComposerClient; interface IComposerClient extends @2.3::IComposerClient { - /** * Required capabilities which are supported by the display. The * particular set of supported capabilities for a given display may be * retrieved using getDisplayCapabilities. */ - enum DisplayCapability : uint32_t { + enum DisplayCapability : @2.3::IComposerClient.DisplayCapability { /** * Indicates that the display supports protected contents. * When returned, hardware composer must be able to accept client target @@ -36,6 +35,20 @@ interface IComposerClient extends @2.3::IComposerClient { PROTECTED_CONTENTS = 4, }; + /** + * Supersedes {@link @2.1::IComposerClient.DisplayType}. + */ + enum DisplayConnectionType : uint32_t { + /** + * Display is connected through internal port, e.g. DSI, eDP. + */ + INTERNAL = 0, + /** + * Display is connected through external port, e.g. HDMI, DisplayPort. + */ + EXTERNAL = 1, + }; + /** * Provides a list of supported capabilities (as described in the * definition of DisplayCapability above). This list must not change after @@ -46,6 +59,14 @@ interface IComposerClient extends @2.3::IComposerClient { * @return capabilities is a list of supported capabilities. */ getDisplayCapabilities_2_4(Display display) - generates (Error error, - vec capabilities); + generates (Error error, vec capabilities); + + /** + * Returns whether the given physical display is internal or external. + * + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when the given display is invalid or virtual. + * @return type is the connection type of the display. + */ + getDisplayConnectionType(Display display) generates (Error error, DisplayConnectionType type); }; diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h index 7110c80db0..c810186665 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h @@ -46,6 +46,14 @@ class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImpl getDisplayConnectionType( + Display display, IComposerClient::getDisplayConnectionType_cb hidl_cb) override { + IComposerClient::DisplayConnectionType type; + Error error = mHal->getDisplayConnectionType(display, &type); + hidl_cb(error, type); + return Void(); + } + static std::unique_ptr create(Hal* hal) { auto client = std::make_unique(hal); return client->init() ? std::move(client) : nullptr; diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h index 0074808309..c3bb535360 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h @@ -38,6 +38,8 @@ class ComposerHal : public V2_3::hal::ComposerHal { public: virtual Error getDisplayCapabilities_2_4( Display display, std::vector* outCapabilities) = 0; + virtual Error getDisplayConnectionType(Display display, + IComposerClient::DisplayConnectionType* outType) = 0; }; } // namespace hal diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h index 65d47d781d..fd05f6630b 100644 --- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h +++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h @@ -62,15 +62,34 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { return Error::NONE; } + Error getDisplayConnectionType(Display display, + IComposerClient::DisplayConnectionType* outType) override { + if (!mDispatch.getDisplayConnectionType) { + return Error::UNSUPPORTED; + } + + uint32_t type = HWC2_DISPLAY_CONNECTION_TYPE_INTERNAL; + int32_t error = mDispatch.getDisplayConnectionType(mDevice, display, &type); + *outType = static_cast(type); + return static_cast(error); + } + protected: bool initDispatch() override { if (!BaseType2_3::initDispatch()) { return false; } + + this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_CONNECTION_TYPE, + &mDispatch.getDisplayConnectionType); return true; } private: + struct { + HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE getDisplayConnectionType; + } mDispatch = {}; + using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl; using BaseType2_3 = V2_3::passthrough::detail::HwcHalImpl; using BaseType2_1::mDevice; diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp index ee4f3a3959..937b50efb4 100644 --- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp @@ -51,7 +51,6 @@ sp ComposerClient::getRaw() const { Error ComposerClient::getDisplayCapabilities( Display display, std::vector* outCapabilities) { - std::vector capabilities; Error error = Error::NONE; mClient->getDisplayCapabilities_2_4(display, [&](const auto& tmpError, const auto& tmpCapabilities) { @@ -61,6 +60,16 @@ Error ComposerClient::getDisplayCapabilities( return error; } +Error ComposerClient::getDisplayConnectionType(Display display, + IComposerClient::DisplayConnectionType* outType) { + Error error = Error::NONE; + mClient->getDisplayConnectionType(display, [&](const auto& tmpError, const auto& tmpType) { + error = tmpError; + *outType = tmpType; + }); + return error; +} + } // namespace vts } // namespace V2_4 } // namespace composer diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h index 0a301c6ca7..a7d7f8644f 100644 --- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h @@ -71,6 +71,9 @@ class ComposerClient : public V2_3::vts::ComposerClient { Display display, std::vector* outDisplayCapabilities); + Error getDisplayConnectionType(Display display, + IComposerClient::DisplayConnectionType* outType); + private: const sp mClient; }; diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index 0fccc58637..76c0039cf2 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -179,6 +179,16 @@ TEST_F(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) { EXPECT_EQ(Error::BAD_DISPLAY, error); } +TEST_F(GraphicsComposerHidlTest, getDisplayConnectionType) { + IComposerClient::DisplayConnectionType type; + EXPECT_EQ(Error::BAD_DISPLAY, + mComposerClient->getDisplayConnectionType(mInvalidDisplayId, &type)); + + for (Display display : mComposerCallback->getDisplays()) { + EXPECT_EQ(Error::NONE, mComposerClient->getDisplayConnectionType(display, &type)); + } +} + } // namespace } // namespace vts } // namespace V2_4 From 9bc4e8696e57419c63d9be57cb7568cc55516104 Mon Sep 17 00:00:00 2001 From: Edwin Wong Date: Mon, 30 Sep 2019 17:49:54 -0700 Subject: [PATCH 0143/1022] Add CTS/GTS tests for TH presumbit. Define CTS/GTS filters in TEST_MAPPING. Test: time atest bug: 138259722 Change-Id: Ib7f27dc5eb8699260cf6b79b03d45de6390aa6f7 --- drm/TEST_MAPPING | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 drm/TEST_MAPPING diff --git a/drm/TEST_MAPPING b/drm/TEST_MAPPING new file mode 100644 index 0000000000..cff681917f --- /dev/null +++ b/drm/TEST_MAPPING @@ -0,0 +1,8 @@ +{ + "imports": [ + // gts and cts filters + { + "path": "frameworks/av/drm/libmediadrm" + } + ] +} From 67e91107c6829b7fd96ca631e68b19809d964394 Mon Sep 17 00:00:00 2001 From: "Harpreet \\\"Eli\\\" Sangha" Date: Fri, 27 Sep 2019 19:00:46 +0900 Subject: [PATCH 0144/1022] vibrator: Async Callback API VTS Tests Bug: 136220871 Test: VTS Tests Change-Id: Icd8f794df76542c9f74e3ea762117da703db47d4 Signed-off-by: Harpreet \"Eli\" Sangha --- vibrator/1.4/vts/functional/Android.bp | 30 ++++ .../VtsHalVibratorV1_4TargetTest.cpp | 170 ++++++++++++++++++ 2 files changed, 200 insertions(+) create mode 100644 vibrator/1.4/vts/functional/Android.bp create mode 100644 vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp diff --git a/vibrator/1.4/vts/functional/Android.bp b/vibrator/1.4/vts/functional/Android.bp new file mode 100644 index 0000000000..4cdf3b66a7 --- /dev/null +++ b/vibrator/1.4/vts/functional/Android.bp @@ -0,0 +1,30 @@ +// +// 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. +// + +cc_test { + name: "VtsHalVibratorV1_4TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalVibratorV1_4TargetTest.cpp"], + static_libs: [ + "android.hardware.vibrator@1.0", + "android.hardware.vibrator@1.1", + "android.hardware.vibrator@1.2", + "android.hardware.vibrator@1.3", + "android.hardware.vibrator@1.4", + ], + test_suites: ["general-tests"], +} + diff --git a/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp b/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp new file mode 100644 index 0000000000..b51cc96942 --- /dev/null +++ b/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp @@ -0,0 +1,170 @@ +/* + * 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 "vibrator_hidl_hal_test" + +#include +#include +#include +#include +#include +#include +#include + +#include + +using ::android::sp; +using ::android::hardware::hidl_bitfield; +using ::android::hardware::hidl_enum_range; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::vibrator::V1_0::EffectStrength; +using ::android::hardware::vibrator::V1_0::Status; +using ::android::hardware::vibrator::V1_3::Effect; +using ::android::hardware::vibrator::V1_4::Capabilities; +using ::android::hardware::vibrator::V1_4::IVibrator; +using ::android::hardware::vibrator::V1_4::IVibratorCallback; + +#define EXPECT_OK(ret) ASSERT_TRUE((ret).isOk()) + +class CompletionCallback : public IVibratorCallback { + public: + CompletionCallback(std::function callback) : mCallback(callback) {} + Return onComplete() override { + mCallback(); + return Void(); + } + + private: + std::function mCallback; +}; + +class VibratorHidlTest_1_4 : public testing::TestWithParam { + public: + virtual void SetUp() override { + vibrator = IVibrator::getService(GetParam()); + ASSERT_NE(vibrator, nullptr); + capabilities = vibrator->getCapabilities(); + } + + virtual void TearDown() override {} + + sp vibrator; + hidl_bitfield capabilities; +}; + +TEST_P(VibratorHidlTest_1_4, OnWithCallback) { + if (capabilities & Capabilities::ON_COMPLETION_CALLBACK) { + std::promise completionPromise; + std::future completionFuture{completionPromise.get_future()}; + sp callback = + new CompletionCallback([&completionPromise] { completionPromise.set_value(); }); + uint32_t duration = 250; + std::chrono::milliseconds timeout{duration * 2}; + EXPECT_EQ(Status::OK, vibrator->on_1_4(duration, callback)); + EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready); + vibrator->off(); + } +} + +static void validatePerformEffectUnsupportedOperation(Status status, uint32_t lengthMs) { + ASSERT_EQ(Status::UNSUPPORTED_OPERATION, status); + ASSERT_EQ(static_cast(0), lengthMs) + << "Effects that return UNSUPPORTED_OPERATION must have a duration of zero"; +} + +static void validatePerformEffect(Status status, uint32_t lengthMs) { + ASSERT_TRUE(status == Status::OK || status == Status::UNSUPPORTED_OPERATION); + if (status == Status::OK) { + ASSERT_LT(static_cast(0), lengthMs) + << "Effects that return OK must return a positive duration"; + } else { + validatePerformEffectUnsupportedOperation(status, lengthMs); + } +} + +/* + * Test to make sure effects within the valid range return are either supported and return OK with + * a valid duration, or are unsupported and return UNSUPPORTED_OPERATION with a duration of 0. + */ +TEST_P(VibratorHidlTest_1_4, PerformEffect_1_4) { + Status performStatus; + uint32_t performLength; + auto validateWrapper = [&](Status status, uint32_t lengthMs) { + performStatus = status; + performLength = lengthMs; + validatePerformEffect(status, lengthMs); + }; + for (const auto& effect : hidl_enum_range()) { + for (const auto& strength : hidl_enum_range()) { + std::promise completionPromise; + std::future completionFuture{completionPromise.get_future()}; + sp callback = + new CompletionCallback([&completionPromise] { completionPromise.set_value(); }); + EXPECT_OK(vibrator->perform_1_4(effect, strength, callback, validateWrapper)); + if (performStatus == Status::OK && + (capabilities & Capabilities::PERFORM_COMPLETION_CALLBACK)) { + std::chrono::milliseconds timeout{performLength * 2}; + EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready); + } + } + } +} + +/* + * Test to make sure effect values above the valid range are rejected. + */ +TEST_P(VibratorHidlTest_1_4, PerformEffect_1_4_BadEffects_AboveValidRange) { + Effect effect = *std::prev(hidl_enum_range().end()); + Effect badEffect = static_cast(static_cast(effect) + 1); + EXPECT_OK(vibrator->perform_1_4(badEffect, EffectStrength::LIGHT, nullptr, + validatePerformEffectUnsupportedOperation)); +} + +/* + * Test to make sure effect values below the valid range are rejected. + */ +TEST_P(VibratorHidlTest_1_4, PerformEffect_1_4_BadEffects_BelowValidRange) { + Effect effect = *hidl_enum_range().begin(); + Effect badEffect = static_cast(static_cast(effect) - 1); + EXPECT_OK(vibrator->perform_1_4(badEffect, EffectStrength::LIGHT, nullptr, + validatePerformEffectUnsupportedOperation)); +} + +/* + * Test to make sure strength values above the valid range are rejected. + */ +TEST_P(VibratorHidlTest_1_4, PerformEffect_1_4_BadStrength_AboveValidRange) { + EffectStrength strength = *std::prev(hidl_enum_range().end()); + EffectStrength badStrength = static_cast(static_cast(strength) + 1); + EXPECT_OK(vibrator->perform_1_4(Effect::THUD, badStrength, nullptr, + validatePerformEffectUnsupportedOperation)); +} + +/* + * Test to make sure strength values below the valid range are rejected. + */ +TEST_P(VibratorHidlTest_1_4, PerformEffect_1_4_BadStrength_BelowValidRange) { + EffectStrength strength = *hidl_enum_range().begin(); + EffectStrength badStrength = static_cast(static_cast(strength) - 1); + EXPECT_OK(vibrator->perform_1_4(Effect::THUD, badStrength, nullptr, + validatePerformEffectUnsupportedOperation)); +} + +INSTANTIATE_TEST_SUITE_P( + PerInstance, VibratorHidlTest_1_4, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVibrator::descriptor)), + android::hardware::PrintInstanceNameToString); From 2cae5c8b01605923044099dcf02ad4bb4566a5b4 Mon Sep 17 00:00:00 2001 From: David Gross Date: Tue, 1 Oct 2019 11:59:34 -0700 Subject: [PATCH 0145/1022] Replace sync_enums_to_hal.py with generate_api.{py,sh} and regenerate */types.hal There are certain pieces of NeuralNetworks.h and of our various *.hal files that ought to be kept in sync -- most notably the operand type and operation type definitions and descriptions in our NeuralNetworks.h and types.hal files. To avoid having to do this manually, a tool can be employed. The old solution to this problem is sync_enums_to_hal.py, which parses the existing NeuralNetworks.h and types.hal files, and then rewrites the types.hal files: It identifies the operand type and operation type portions of the files, and in the types.hal files replaces them with transformed versions of the portions from NeuralNetworks.h. This approach is brittle -- it is very sensitive to the structure of the files, as was recognized when this tool was created. Changes to those files since the script was last updated essentially broke the script, as noted in http://b/140132458. The new solution employs a new tool generate_api.py to combine a single "specification file" with one "template file" per API file (NeuralNetworks.h or types.hal) to produce that API file. The script generate_api.sh invokes generate_api.py once per API file, passing appropriate arguments. See frameworks/ml/nn/tools/api/README.md for more details. In the process of combining information from NeuralNetworks.h and */types.hal, some formatting, syntactic, and semantic changes have been made to those files. For example: - types.hal files no longer refer to API levels or (similarly) to HAL versions other than earlier HAL versions Bug: 130169064 Bug: 140132458 Test: cd neuralnetworks ; mma Change-Id: Iceb38effc2c7e6c32344e49225b85256144c0945 --- current.txt | 3 + neuralnetworks/1.0/types.hal | 467 +++++++++++---------- neuralnetworks/1.0/types.t | 431 ++++++++++++++++++++ neuralnetworks/1.1/types.hal | 47 +-- neuralnetworks/1.1/types.t | 158 ++++++++ neuralnetworks/1.2/types.hal | 761 ++++++++++++++++------------------- neuralnetworks/1.2/types.t | 745 ++++++++++++++++++++++++++++++++++ 7 files changed, 1922 insertions(+), 690 deletions(-) create mode 100644 neuralnetworks/1.0/types.t create mode 100644 neuralnetworks/1.1/types.t create mode 100644 neuralnetworks/1.2/types.t diff --git a/current.txt b/current.txt index 544abada5e..c2c8eaf711 100644 --- a/current.txt +++ b/current.txt @@ -575,8 +575,11 @@ cfa81f229b69f9011c58f48264fcb552447430fe68610eac514e811e65bc306a android.hardwar 2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel +f1109cbb10297b7429a11fab42afa912710b303c9bf20bd5cdb8bd57b9c84186 android.hardware.neuralnetworks@1.0::types +9d8ee57c490ffeaa28f702eaea8d198cb510e4bbfb99e6cb5f63e73341057c7c android.hardware.neuralnetworks@1.1::types fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice 40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel +71c0f7127335e5b74d1615d5e7f129831b43ffbae5318ad0924d7d8d8910a859 android.hardware.neuralnetworks@1.2::types a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface diff --git a/neuralnetworks/1.0/types.hal b/neuralnetworks/1.0/types.hal index 02db063e18..ba9d068e34 100644 --- a/neuralnetworks/1.0/types.hal +++ b/neuralnetworks/1.0/types.hal @@ -25,25 +25,24 @@ package android.hardware.neuralnetworks@1.0; * with at least one dimension). Types not prefaced by TENSOR_* represent * scalar values and must have no dimensions. * - * Although many types are defined, most operators accept just a few + * Although we define many types, most operators accept just a few * types. Most used are {@link OperandType::TENSOR_FLOAT32}, * {@link OperandType::TENSOR_QUANT8_ASYMM}, * and {@link OperandType::INT32}. */ enum OperandType : int32_t { /** A 32 bit floating point scalar value. */ - FLOAT32 = 0, + FLOAT32 = 0, /** A signed 32 bit integer scalar value. */ - INT32 = 1, + INT32 = 1, /** An unsigned 32 bit integer scalar value. */ - UINT32 = 2, - + UINT32 = 2, /** A tensor of 32 bit floating point values. */ - TENSOR_FLOAT32 = 3, + TENSOR_FLOAT32 = 3, /** A tensor of 32 bit integer values. */ - TENSOR_INT32 = 4, + TENSOR_INT32 = 4, /** - * A tensor of 8 bit integers that represent real numbers. + * A tensor of 8 bit unsigned integers that represent real numbers. * * Attached to this tensor are two numbers that can be used to convert the * 8 bit integer to the real value and vice versa. These two numbers are: @@ -51,21 +50,21 @@ enum OperandType : int32_t { * - zeroPoint: a 32 bit integer, in range [0, 255]. * * The formula is: - * real_value = (integer_value - zeroPoint) * scale. + * real_value = (integer_value - zeroPoint) * scale. */ TENSOR_QUANT8_ASYMM = 5, /** - * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to - * OEM operation and data types. + * DEPRECATED. Since HAL version 1.2, extensions are the preferred + * alternative to OEM operation and data types. * * OEM specific scalar value. */ OEM = 10000, /** - * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to - * OEM operation and data types. + * DEPRECATED. Since HAL version 1.2, extensions are the preferred + * alternative to OEM operation and data types. * * A tensor of OEM specific values. */ @@ -78,7 +77,6 @@ enum OperandType : int32_t { * The type of an operation in a model. */ enum OperationType : int32_t { - /** * Adds two tensors, element-wise. * @@ -110,14 +108,16 @@ enum OperationType : int32_t { * * 0: A tensor. * * 1: A tensor of the same {@link OperandType}, and compatible dimensions * as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scales and zeroPoint can be different from input0 scale and zeroPoint. * * 2: An {@link OperandType::INT32} scalar, and has to be one of the * {@link FusedActivationFunc} values. Specifies the activation to * invoke on the result. * * Outputs: * * 0: The sum, a tensor of the same {@link OperandType} as input0. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from inputs' scale and zeroPoint. */ ADD = 0, @@ -187,8 +187,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, out_height, out_width, depth]. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ AVERAGE_POOL_2D = 1, @@ -206,22 +206,23 @@ enum OperationType : int32_t { * * Inputs: * * 0 ~ n-1: The list of n input tensors, of shape - * [D0, D1, ..., Daxis(i), ..., Dm]. For inputs of - * {@link OperandType::TENSOR_QUANT8_ASYMM}, all input tensors - * must have the same scale and zeroPoint. + * [D0, D1, ..., Daxis(i), ..., Dm]. + * All input tensors of + * {@link OperandType::TENSOR_QUANT8_ASYMM} + * must have the same scale and zeroPoint as the output tensor. * * n: An {@link OperandType::INT32} scalar, specifying the * concatenation axis. * * Outputs: * * 0: The output, a tensor of the same {@link OperandType} as the input * tensors. The output shape is [D0, D1, ..., sum(Daxis(i)), ..., Dm]. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, the scale and zeroPoint + * values must be the same as the input tensors'. */ CONCATENATION = 2, /** - * Performs an 2-D convolution operation. + * Performs a 2-D convolution operation. * * The CONV_2D op sweeps a 2-D filter that can mix channels together over a * batch of images, applying the filter to each window of each image of the @@ -238,11 +239,17 @@ enum OperationType : int32_t { * filter[channel, di, dj, k] * ) + bias[channel] * - * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT32} - * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor {@link OperandType} configurations: + * * 32 bit floating point: + * * * {@link OperandType::TENSOR_FLOAT32} for input, filter, output, and bias. * - * Supported tensor rank: 4, with "NHWC" data layout. + * * Quantized: + * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, filter, and output. + * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to + * * * input.scale * filter.scale). + * + * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width, + * and Channels) data layout. * * Both explicit padding and implicit padding are supported. * @@ -252,12 +259,12 @@ enum OperationType : int32_t { * * 1: A 4-D tensor, of shape * [depth_out, filter_height, filter_width, depth_in], specifying the * filter. - * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. - * For input tensor of {@link OperandType::TENSOR_FLOAT32}, the bias - * should also be of {@link OperandType::TENSOR_FLOAT32}. For input - * tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias - * should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of - * 0 and bias_scale == input_scale * filter_scale. + * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input + * tensor of type {@link OperandType::TENSOR_FLOAT32} + * the bias must be of the same + * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint + * of 0 and bias_scale == input_scale * filter_scale. * * 3: An {@link OperandType::INT32} scalar, specifying the padding on * the left, in the ‘width’ dimension. * * 4: An {@link OperandType::INT32} scalar, specifying the padding on @@ -281,11 +288,11 @@ enum OperationType : int32_t { * [depth_out, filter_height, filter_width, depth_in], specifying the * filter. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input - * tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should - * also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor - * of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be - * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and - * bias_scale == input_scale * filter_scale. + * tensor of type {@link OperandType::TENSOR_FLOAT32} + * the bias must be of the same + * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint + * of 0 and bias_scale == input_scale * filter_scale. * * 3: An {@link OperandType::INT32} scalar, specifying the implicit * padding scheme, has to be one of the * following values: {0 (NONE), 1 (SAME), 2 (VALID)}. @@ -299,11 +306,9 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output 4-D tensor, of shape - * [batches, out_height, out_width, depth_out]. For output tensor of - * {@link OperandType::TENSOR_QUANT8_ASYMM}, the following condition - * must be satisfied: output_scale > input_scale * filter_scale. - * - * Available since API level 27. + * [batches, out_height, out_width, depth_out]. + * For output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the following condition must be satisfied: output_scale > input_scale * filter_scale */ CONV_2D = 3, @@ -329,11 +334,17 @@ enum OperationType : int32_t { * filter[1, di, dj, k * channel_multiplier + q] * ) + bias[k * channel_multiplier + q] * - * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT32} - * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor {@link OperandType} configurations: + * * 32 bit floating point: + * * * {@link OperandType::TENSOR_FLOAT32} for input, filter, output, and bias. * - * Supported tensor rank: 4, with "NHWC" data layout. + * * Quantized: + * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, filter, and output. + * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to + * * * input.scale * filter.scale). + * + * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width, + * and Channels) data layout. * * Both explicit padding and implicit padding are supported. * @@ -343,11 +354,11 @@ enum OperationType : int32_t { * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out], * specifying the filter. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input - * tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should - * also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor - * of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be - * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and - * bias_scale == input_scale * filter_scale. + * tensor of type {@link OperandType::TENSOR_FLOAT32} + * the bias must be of the same + * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint + * of 0 and bias_scale == input_scale * filter_scale. * * 3: An {@link OperandType::INT32} scalar, specifying the padding on * the left, in the ‘width’ dimension. * * 4: An {@link OperandType::INT32} scalar, specifying the padding on @@ -372,11 +383,11 @@ enum OperationType : int32_t { * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out], * specifying the filter. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input - * tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should - * also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor - * of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be - * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and - * bias_scale == input_scale * filter_scale. + * tensor of type {@link OperandType::TENSOR_FLOAT32} + * the bias must be of the same + * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint + * of 0 and bias_scale == input_scale * filter_scale. * * 3: An {@link OperandType::INT32} scalar, specifying the implicit * padding scheme, has to be one of the * following values: {0 (NONE), 1 (SAME), 2 (VALID)}. @@ -392,11 +403,10 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output 4-D tensor, of shape - * [batches, out_height, out_width, depth_out]. For output tensor of - * {@link OperandType::TENSOR_QUANT8_ASYMM}, the following condition - * must be satisfied: output_scale > input_scale * filter_scale. - * - * Available since API level 27. + * [batches, out_height, out_width, depth_out]. For + * output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the following condition must be satisfied: + * output_scale > input_scale * filter_scale */ DEPTHWISE_CONV_2D = 4, @@ -419,7 +429,8 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * - * Supported tensor rank: 4, with "NHWC" data layout. + * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width, + * and Channels) data layout. * * Inputs: * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], @@ -431,8 +442,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape [batch, height*block_size, * width*block_size, depth/(block_size*block_size)]. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ DEPTH_TO_SPACE = 5, @@ -443,19 +454,19 @@ enum OperationType : int32_t { * * output = (input - zeroPoint) * scale. * - * Supported tensor {@link OperandType}: + * Supported input tensor {@link OperandType}: * * {@link OperandType::TENSOR_QUANT8_ASYMM} * + * Supported output tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT32}. + * * Supported tensor rank: up to 4 * * Inputs: - * * 0: A tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}. + * * 0: A tensor. * * Outputs: - * * 0: The output tensor of same shape as input0, but with - * {@link OperandType::TENSOR_FLOAT32}. - * - * Available since API level 27. + * * 0: A tensor with the same shape as input0. */ DEQUANTIZE = 6, @@ -479,6 +490,13 @@ enum OperationType : int32_t { * If a value in Lookups is out of bounds, the operation must fail * and an error must be reported. * + * Supported value tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported value tensor rank: from 2 + * * Inputs: * * 0: Lookups. A 1-D tensor of {@link OperandType::TENSOR_INT32}. * The values are indices into the first dimension of Values. @@ -489,8 +507,8 @@ enum OperationType : int32_t { * * 0: A n-D tensor with the same rank and shape as the Values * tensor, except for the first dimension which has the same size * as Lookups' only dimension. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input1. */ EMBEDDING_LOOKUP = 7, @@ -508,8 +526,6 @@ enum OperationType : int32_t { * Outputs: * * 0: The output tensor, of the same {@link OperandType} and dimensions as * the input tensor. - * - * Available since API level 27. */ FLOOR = 8, @@ -549,12 +565,9 @@ enum OperationType : int32_t { * invoke on the result. * * Outputs: - * * 0: The output tensor, of shape [batch_size, num_units]. For output - * tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the following - * condition must be satisfied: - * output_scale > input_scale * filter_scale. - * - * Available since API level 27. + * * 0: The output tensor, of shape [batch_size, num_units]. For + * output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the following + * condition must be satisfied: output_scale > input_scale * filter_scale. */ FULLY_CONNECTED = 9, @@ -585,6 +598,13 @@ enum OperationType : int32_t { * must be selected. If no entry in Keys has 123456, a slice of zeroes * must be concatenated. * + * Supported value tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported value tensor rank: from 2 + * * Inputs: * * 0: Lookups. A 1-D {@link OperandType::TENSOR_INT32} tensor with * shape [ k ]. @@ -598,13 +618,13 @@ enum OperationType : int32_t { * * Outputs: * * 0: Output. A tensor with shape [ k …]. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input2. * * 1: Hits. A boolean tensor with shape [ k ] indicates whether the lookup * hits (True) or not (False). * Stored as {@link OperandType::TENSOR_QUANT8_ASYMM} with offset 0 * and scale 1.0f. * A non-zero byte represents True, a hit. A zero indicates otherwise. - * - * Available since API level 27. */ HASHTABLE_LOOKUP = 10, @@ -617,9 +637,6 @@ enum OperationType : int32_t { * input[batch, row, col, channel] / * sqrt(sum_{c} pow(input[batch, row, col, c], 2)) * - * For input tensor with more dimensions, independently normalizes each 1-D - * slice along dimension dim. - * * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT32} * @@ -627,13 +644,10 @@ enum OperationType : int32_t { * Height, Width, and Channels). * * Inputs: - * * 0: A 4-D tensor, of shape [batches, height, width, depth]. + * * 0: A 4-D tensor, specifying the tensor to be normalized. * * Outputs: - * * 0: The output 4-D tensor, of the same shape as input - * [batches, height, width, depth]. - * - * Available since API level 27. + * * 0: A tensor of the same {@link OperandType} and same shape as input0. */ L2_NORMALIZATION = 11, @@ -652,7 +666,8 @@ enum OperationType : int32_t { * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT32} * - * Supported tensor rank: 4, with "NHWC" data layout. + * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width, + * and Channels) data layout. * * Both explicit padding and implicit padding are supported. * @@ -700,8 +715,6 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, out_height, out_width, depth]. - * - * Available since API level 27. */ L2_POOL_2D = 12, @@ -729,17 +742,18 @@ enum OperationType : int32_t { * the input. * * 1: An {@link OperandType::INT32} scalar, specifying the radius of * the normalization window. - * * 2: An {@link OperandType::FLOAT32} scalar, specifying the bias, must - * not be zero. - * * 3: An {@link OperandType::FLOAT32} scalar, specifying the scale - * factor, alpha. - * * 4: An {@link OperandType::FLOAT32} scalar, specifying the exponent, - * beta. + * * 2: A scalar, specifying the bias, must not be zero. + * For input tensor of {@link OperandType::TENSOR_FLOAT32}, the bias + * value must be of {@link OperandType::FLOAT32}. + * * 3: A scalar, specifying the scale factor, alpha. + * For input tensor of {@link OperandType::TENSOR_FLOAT32}, the + * alpha value must be of {@link OperandType::FLOAT32}. + * * 4: A scalar, specifying the exponent, beta. + * For input tensor of {@link OperandType::TENSOR_FLOAT32}, the beta + * value must be of {@link OperandType::FLOAT32}. * * Outputs: * * 0: The output tensor of same shape as input0. - * - * Available since API level 27. */ LOCAL_RESPONSE_NORMALIZATION = 13, @@ -763,45 +777,53 @@ enum OperationType : int32_t { * * 0: The output tensor of same shape as input0. * For {@link OperandType::TENSOR_QUANT8_ASYMM}, * the scale must be 1.f / 256 and the zeroPoint must be 0. - * - * Available since API level 27. */ LOGISTIC = 14, /** * Projects an input to a bit vector via locality senstive hashing. * + * Supported input tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported input tensor rank: from 1 + * * Inputs: * * 0: Hash functions. Dim.size == 2, DataType: Float. - * Tensor[0].Dim[0]: Number of hash functions. - * Tensor[0].Dim[1]: Number of seeds per hash functions. - * Tensor[0].Dim[1] <= 32 in sparse case. + * Tensor[0].Dim[0]: Number of hash functions. + * Tensor[0].Dim[1]: Number of projected output bits generated by each + * hash function. + * If the projection type is Sparse: + * Tensor[0].Dim[1] + ceil(log2(Tensor[0].Dim[0])) <= 32 * * * 1: Input. Dim.size >= 1, no restriction on DataType. * * 2: Weight. Optional. Dim.size == 1, DataType: Float. - * If not set, each input element is considered to have the same weight - * of 1.0. - * Tensor[1].Dim[0] == Tensor[2].Dim[0] + * If not set, each input element is considered to have the same weight + * of 1.0. + * Tensor[1].Dim[0] == Tensor[2].Dim[0] * * 3: Type: - * Sparse: Value LSHProjectionType_SPARSE(=1). + * Sparse: + * Value LSHProjectionType_SPARSE(=1). * Computed bit vector is considered to be sparse. * Each output element is an int32 made up of multiple bits * computed from hash functions. * - * Dense: Value LSHProjectionType_DENSE(=2). + * Dense: + * Value LSHProjectionType_DENSE(=2). * Computed bit vector is considered to be dense. Each output * element represents a bit and can take the value of either * 0 or 1. * * Outputs: - * * 0: If the projection type is sparse: - * Output.Dim == { Tensor[0].Dim[0] } - * A tensor of int32 that represents hash signatures. - * If the projection type is Dense: - * Output.Dim == { Tensor[0].Dim[0] * Tensor[0].Dim[1] } - * A flattened tensor that represents projected bit vectors. + * * 0: If the projection type is Sparse: + * Output.Dim == { Tensor[0].Dim[0] } + * A tensor of int32 that represents hash signatures. * - * Available since API level 27. + * If the projection type is Dense: + * Output.Dim == { Tensor[0].Dim[0] * Tensor[0].Dim[1] } + * A flattened tensor that represents projected bit vectors. */ LSH_PROJECTION = 15, @@ -901,71 +923,54 @@ enum OperationType : int32_t { * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT32} * + * All input and output tensors must be of the same type. + * * Inputs: * * 0: The input (\f$x_t\f$). - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [batch_size, input_size], where “batch_size” corresponds to the - * batching dimension, and “input_size” is the size of the input. + * A 2-D tensor of shape [batch_size, input_size], where “batch_size” + * corresponds to the batching dimension, and “input_size” is the size + * of the input. * * 1: The input-to-input weights (\f$W_{xi}\f$). Optional. - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units, input_size], where “num_units” corresponds to the - * number of cell units. + * A 2-D tensor of shape [num_units, input_size], where “num_units” + * corresponds to the number of cell units. * * 2: The input-to-forget weights (\f$W_{xf}\f$). - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units, input_size]. + * A 2-D tensor of shape [num_units, input_size]. * * 3: The input-to-cell weights (\f$W_{xc}\f$). - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units, input_size]. + * A 2-D tensor of shape [num_units, input_size]. * * 4: The input-to-output weights (\f$W_{xo}\f$). - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units, input_size]. + * A 2-D tensor of shape [num_units, input_size]. * * 5: The recurrent-to-input weights (\f$W_{hi}\f$). Optional. - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units, output_size], where “output_size” corresponds to either - * the number of cell units (i.e., “num_units”), or the second - * dimension of the “projection_weights”, if defined. + * A 2-D tensor of shape [num_units, output_size], where “output_size” + * corresponds to either the number of cell units (i.e., “num_units”), + * or the second dimension of the “projection_weights”, if defined. * * 6: The recurrent-to-forget weights (\f$W_{hf}\f$). - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units, output_size]. + * A 2-D tensor of shape [num_units, output_size]. * * 7: The recurrent-to-cell weights (\f$W_{hc}\f$). - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units, output_size]. + * A 2-D tensor of shape [num_units, output_size]. * * 8: The recurrent-to-output weights (\f$W_{ho}\f$). - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units, output_size]. + * A 2-D tensor of shape [num_units, output_size]. * * 9: The cell-to-input weights (\f$W_{ci}\f$). Optional. - * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units]. + * A 1-D tensor of shape [num_units]. * * 10:The cell-to-forget weights (\f$W_{cf}\f$). Optional. - * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units]. + * A 1-D tensor of shape [num_units]. * * 11:The cell-to-output weights (\f$W_{co}\f$). Optional. - * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units]. + * A 1-D tensor of shape [num_units]. * * 12:The input gate bias (\f$b_i\f$). Optional. - * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units]. + * A 1-D tensor of shape [num_units]. * * 13:The forget gate bias (\f$b_f\f$). - * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units]. + * A 1-D tensor of shape [num_units]. * * 14:The cell bias (\f$b_c\f$). - * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units]. + * A 1-D tensor of shape [num_units]. * * 15:The output gate bias (\f$b_o\f$). - * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units]. + * A 1-D tensor of shape [num_units]. * * 16:The projection weights (\f$W_{proj}\f$). Optional. - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [output_size, num_units]. + * A 2-D tensor of shape [output_size, num_units]. * * 17:The projection bias (\f$b_{proj}\f$). Optional. - * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [output_size]. + * A 1-D tensor of shape [output_size]. * * 18:The output state (in) (\f$h_{t-1}\f$). - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [batch_size, output_size]. + * A 2-D tensor of shape [batch_size, output_size]. * * 19:The cell state (in) (\f$C_{t-1}\f$). - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [batch_size, num_units]. + * A 2-D tensor of shape [batch_size, num_units]. * * 20:The activation function (\f$g\f$). * A value indicating the activation function: *
    @@ -984,21 +989,15 @@ enum OperationType : int32_t { * * Outputs: * * 0: The scratch buffer. - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [batch_size, num_units * 3] with CIFG, or + * A 2-D tensor of shape [batch_size, num_units * 3] with CIFG, or * [batch_size, num_units * 4] without CIFG. * * 1: The output state (out) (\f$h_t\f$). - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [batch_size, output_size]. + * A 2-D tensor of shape [batch_size, output_size]. * * 2: The cell state (out) (\f$C_t\f$). - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [batch_size, num_units]. + * A 2-D tensor of shape [batch_size, num_units]. * * 3: The output (\f$o_t\f$). - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [batch_size, output_size]. This is effectively the same as the - * current “output state (out)” value. - * - * Available since API level 27. + * A 2-D tensor of shape [batch_size, output_size]. This is effectively + * the same as the current “output state (out)” value. */ LSTM = 16, @@ -1019,7 +1018,8 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * - * Supported tensor rank: 4, with "NHWC" data layout. + * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width, + * and Channels) data layout. * * Both explicit padding and implicit padding are supported. * @@ -1067,8 +1067,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, out_height, out_width, depth]. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ MAX_POOL_2D = 17, @@ -1106,8 +1106,6 @@ enum OperationType : int32_t { * For output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the following condition must be satisfied: * output_scale > input1_scale * input2_scale. - * - * Available since API level 27. */ MUL = 18, @@ -1129,8 +1127,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of same shape as input0. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ RELU = 19, @@ -1151,9 +1149,9 @@ enum OperationType : int32_t { * * 0: A tensor, specifying the input. * * Outputs: - * * 0: The output tensor of same shape as input0. - * - * Available since API level 27. + * * 0: The output tensor of the same shape as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ RELU1 = 20, @@ -1175,8 +1173,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of same shape as input0. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ RELU6 = 21, @@ -1205,8 +1203,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor, of shape specified by the input shape. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ RESHAPE = 22, @@ -1220,9 +1218,10 @@ enum OperationType : int32_t { * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT32} * - * Supported tensor rank: 4, with "NHWC" data layout. + * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width, + * and Channels) data layout. * - * Inputs: + * Inputs (resizing by shape): * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying * the input. * * 1: An {@link OperandType::INT32} scalar, specifying the output @@ -1233,8 +1232,6 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, new_height, new_width, depth]. - * - * Available since API level 27. */ RESIZE_BILINEAR = 23, @@ -1257,25 +1254,23 @@ enum OperationType : int32_t { * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT32} * + * The input tensors must all be the same type. + * * Inputs: * * 0: input. - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32} of shape - * [batch_size, input_size], where “batch_size” corresponds to the - * batching dimension, and “input_size” is the size of the input. + * A 2-D tensor of shape [batch_size, input_size], where “batch_size” + * corresponds to the batching dimension, and “input_size” is the size + * of the input. * * 1: weights. - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units, input_size], where “num_units” corresponds to the - * number of units. + * A 2-D tensor of shape [num_units, input_size], where “num_units” + * corresponds to the number of units. * * 2: recurrent_weights. - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units, num_units], with columns corresponding to the weights - * from each unit. + * A 2-D tensor of shape [num_units, num_units], with columns + * corresponding to the weights from each unit. * * 3: bias. - * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units]. + * A 1-D tensor of shape [num_units]. * * 4: hidden state (in). - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [batch_size, num_units]. + * A 2-D tensor of shape [batch_size, num_units]. * * 5: fused_activation_function. * An optional {@link FusedActivationFunc} value indicating the * activation function. If “NONE” is specified then it results in a @@ -1283,15 +1278,11 @@ enum OperationType : int32_t { * * Outputs: * * 0: hidden state (out). - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [batch_size, num_units]. + * A 2-D tensor of shape [batch_size, num_units]. * * * 1: output. - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [batch_size, num_units]. This is effectively the same as the - * current state value. - * - * Available since API level 27. + * A 2-D tensor of shape [batch_size, num_units]. This is effectively + * the same as the current state value. */ RNN = 24, @@ -1306,6 +1297,9 @@ enum OperationType : int32_t { * exp((input[batch, i] - max(input[batch, :])) * beta) / * sum_{k}{exp((input[batch, k] - max(input[batch, :])) * beta)} * + * For input tensor with rank other than 2, the activation will be applied + * independently on each 1-D slice along specified dimension. + * * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} @@ -1314,15 +1308,15 @@ enum OperationType : int32_t { * * Inputs: * * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped. - * * 1: An {@link OperandType::FLOAT32} scalar, specifying the positive - * scaling factor for the exponent, beta. + * * 1: A scalar, specifying the positive scaling factor for the exponent, + * beta. If input0 is of {@link OperandType::TENSOR_FLOAT32} or + * {@link OperandType::TENSOR_QUANT8_ASYMM}, the scalar must be of + * {@link OperandType::FLOAT32}. * * Outputs: * * 0: The output tensor of same shape as input0. * For {@link OperandType::TENSOR_QUANT8_ASYMM}, * the scale must be 1.f / 256 and the zeroPoint must be 0. - * - * Available since API level 27. */ SOFTMAX = 25, @@ -1344,7 +1338,8 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * - * Supported tensor rank: 4, with "NHWC" data layout. + * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width, + * and Channels) data layout. * * Inputs: * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], @@ -1356,8 +1351,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape [batches, height/block_size, * width/block_size, depth_in*block_size*block_size]. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ SPACE_TO_DEPTH = 26, @@ -1403,25 +1398,23 @@ enum OperationType : int32_t { * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT32} * + * All input tensors must be the same type. + * * Inputs: * * 0: input. - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [batch_size, input_size], where “batch_size” corresponds to the - * batching dimension, and “input_size” is the size of the input. + * A 2-D tensor of shape [batch_size, input_size], where “batch_size” + * corresponds to the batching dimension, and “input_size” is the size + * of the input. * * 1: weights_feature. - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units, input_size], where “num_units” corresponds to the - * number of units. + * A 2-D tensor of shape [num_units, input_size], where “num_units” + * corresponds to the number of units. * * 2: weights_time. - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [num_units, memory_size], where “memory_size” corresponds to the - * fixed-size of the memory. + * A 2-D tensor of shape [num_units, memory_size], where “memory_size” + * corresponds to the fixed-size of the memory. * * 3: bias. - * An optional 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, - * of shape [num_units]. + * An optional 1-D tensor of shape [num_units]. * * 4: state (in). - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape - * [batch_size, (memory_size - 1) * num_units * rank]. + * A 2-D tensor of shape [batch_size, (memory_size - 1) * num_units * rank]. * * 5: rank. * The rank of the SVD approximation. * * 6: fused_activation_function. @@ -1431,13 +1424,11 @@ enum OperationType : int32_t { * * Outputs: * * 0: state (out). - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape + * A 2-D tensor of the same {@link OperandType} as the inputs, with shape * [batch_size, (memory_size - 1) * num_units * rank]. * * 1: output. - * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape + * A 2-D tensor of the same {@link OperandType} as the inputs, with shape * [batch_size, num_units]. - * - * Available since API level 27. */ SVDF = 27, @@ -1458,8 +1449,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of same shape as input0. - * - * Available since API level 27. */ TANH = 28, diff --git a/neuralnetworks/1.0/types.t b/neuralnetworks/1.0/types.t new file mode 100644 index 0000000000..d7b26aab35 --- /dev/null +++ b/neuralnetworks/1.0/types.t @@ -0,0 +1,431 @@ +%% template file for generating types.hal. +%% see frameworks/ml/nn/tools/api/README.md. +/* + * Copyright (C) 2017 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. + */ + +package android.hardware.neuralnetworks@1.0; + +%insert Operand_1.0_Comment +enum OperandType : int32_t { +%insert Operand_1.0 + + /** + * DEPRECATED. Since HAL version 1.2, extensions are the preferred + * alternative to OEM operation and data types. + * + * OEM specific scalar value. + */ + OEM = 10000, + + /** + * DEPRECATED. Since HAL version 1.2, extensions are the preferred + * alternative to OEM operation and data types. + * + * A tensor of OEM specific values. + */ + TENSOR_OEM_BYTE = 10001, +}; + +%insert Operation_1.0_Comment +enum OperationType : int32_t { +%insert Operation_1.0 + + /** + * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to + * OEM operation and data types. + * + * This operation is OEM specific. It should only be used for OEM + * applications. + */ + OEM_OPERATION = 10000, +}; + +/** + * Fused activation function types. + */ +enum FusedActivationFunc : int32_t { + NONE = 0, + RELU = 1, + RELU1 = 2, + RELU6 = 3, +}; + +/** + * How an operand is used. + */ +enum OperandLifeTime : int32_t { + /** + * The operand is internal to the model. It's created by an operation and + * consumed by other operations. It must be an output operand of + * exactly one operation. + */ + TEMPORARY_VARIABLE, + + /** + * The operand is an input of the model. It must not be an output + * operand of any operation. + * + * An operand can't be both input and output of a model. + */ + MODEL_INPUT, + + /** + * The operand is an output of the model. It must be an output + * operand of exactly one operation. + * + * An operand can't be both input and output of a model. + */ + MODEL_OUTPUT, + + /** + * The operand is a constant found in Model.operandValues. It must + * not be an output operand of any operation. + */ + CONSTANT_COPY, + + /** + * The operand is a constant that was specified via a Memory + * object. It must not be an output operand of any operation. + */ + CONSTANT_REFERENCE, + + /** + * The operand does not have a value. This is valid only for optional + * arguments of operations. + */ + NO_VALUE, +}; + +/** + * Status of a device. + */ +enum DeviceStatus : int32_t { + AVAILABLE, + BUSY, + OFFLINE, + UNKNOWN, +}; + +/** + * Performance information for the reference workload. + * + * Used by a driver to report its performance characteristics. + */ +struct PerformanceInfo { + /** + * Ratio of the time taken by the driver to execute the + * workload compared to the time the CPU would take for the + * same workload. A lower number is better. + */ + float execTime; + + /** + * Ratio of the energy used by the driver compared to what + * the CPU would use for doing the same workload. A lower number + * is better. + */ + float powerUsage; +}; + +/** + * The capabilities of a driver. + */ +struct Capabilities { + /** + * Driver performance when operating on float32 data. + */ + PerformanceInfo float32Performance; + + /** + * Driver performance when operating on asymmetric 8-bit quantized data. + */ + PerformanceInfo quantized8Performance; +}; + +/** + * Describes the location of a data object. + */ +struct DataLocation { + /** + * The index of the memory pool where this location is found. + */ + uint32_t poolIndex; + + /** + * Offset in bytes from the start of the pool. + */ + uint32_t offset; + + /** + * The length of the data in bytes. + */ + uint32_t length; +}; + +/** + * Describes one operand of the model's graph. + */ +struct Operand { + /** + * Data type of the operand. + */ + OperandType type; + + /** + * Dimensions of the operand. + * + * For a scalar operand, dimensions.size() must be 0. + * + * For a tensor operand, dimensions.size() must be at least 1; + * however, any of the dimensions may be unspecified. + * + * A tensor operand with all dimensions specified has "fully + * specified" dimensions. Whenever possible (i.e., whenever the + * dimensions are known at model construction time), a tensor + * operand should have (but is not required to have) fully + * specified dimensions, in order to enable the best possible + * performance. + * + * 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. + * + * In the following situations, a tensor operand's dimensions must + * be fully specified: + * + * . The operand has lifetime CONSTANT_COPY or + * CONSTANT_REFERENCE. + * + * . The operand has lifetime MODEL_INPUT or MODEL_OUTPUT. Fully + * specified dimensions must either be present in the + * Operand or they must be provided in the corresponding + * RequestArgument. + * EXCEPTION: If the input or output is optional and omitted + * (by setting the hasNoValue field of the corresponding + * RequestArgument to true) then it need not have fully + * specified dimensions. + * + * A tensor operand with some number of unspecified dimensions is + * represented by setting each unspecified dimension to 0. + */ + vec dimensions; + + /** + * The number of times this operand appears as an operation input. + * + * (For example, if this operand appears once in one operation's + * input list, and three times in another operation's input list, + * then numberOfConsumers = 4.) + */ + uint32_t numberOfConsumers; + + /** + * Quantized scale of the operand. + * + * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM or + * TENSOR_INT32. + */ + float scale; + + /** + * Quantized zero-point offset of the operand. + * + * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM. + */ + int32_t zeroPoint; + + /** + * How the operand is used. + */ + OperandLifeTime lifetime; + + /** + * Where to find the data for this operand. + * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or + * NO_VALUE: + * - All the fields must be 0. + * If the lifetime is CONSTANT_COPY: + * - location.poolIndex is 0. + * - location.offset is the offset in bytes into Model.operandValues. + * - location.length is set. + * If the lifetime is CONSTANT_REFERENCE: + * - location.poolIndex is set. + * - location.offset is the offset in bytes into the specified pool. + * - location.length is set. + */ + DataLocation location; +}; + +/** + * Describes one operation of the model's graph. + */ +struct Operation { + /** + * The operation type. + */ + OperationType type; + + /** + * Describes the table that contains the indexes of the inputs of the + * operation. The offset is the index in the operandIndexes table. + */ + vec inputs; + + /** + * Describes the table that contains the indexes of the outputs of the + * operation. The offset is the index in the operandIndexes table. + */ + vec outputs; +}; + +/** + * A Neural Network Model. + * + * This includes not only the execution graph, but also constant data such as + * weights or scalars added at construction time. The only information that + * might not be known is the shape of the input tensors. + */ +struct Model { + /** + * All operands included in the model. + */ + vec operands; + + /** + * All operations included in the model. + * + * The operations are sorted into execution order. Every operand + * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be + * written before it is read. + */ + vec operations; + + /** + * Input indexes of the model. There must be at least one. + * + * Each value corresponds to the index of the operand in "operands". + */ + vec inputIndexes; + + /** + * Output indexes of the model. There must be at least one. + * + * Each value corresponds to the index of the operand in "operands". + */ + vec outputIndexes; + + /** + * A byte buffer containing operand data that were copied into the model. + * + * An operand's value must be located here if and only if Operand::lifetime + * equals OperandLifeTime::CONSTANT_COPY. + */ + vec operandValues; + + /** + * A collection of shared memory pools containing operand values. + * + * An operand's value must be located here if and only if Operand::lifetime + * equals OperandLifeTime::CONSTANT_REFERENCE. + */ + vec pools; +}; + +/** + * Metadata information specifying the location of the input or output data and + * any updates to the input or output operand. + */ +struct RequestArgument { + /** + * If true, the argument does not have a value. This can be used for + * operations that take optional arguments. If true, the fields of location + * are set to 0 and the dimensions vector is left empty. + */ + bool hasNoValue; + + /** + * The location within one of the memory pools passed in the Request. + */ + DataLocation location; + + /** + * Updated dimension information. + * + * If dimensions.size() > 0, dimension information was provided + * along with the argument. This can be the case for models that + * accept inputs of varying size. This can't change the rank, just + * the value of the dimensions that were unspecified in the + * model. If dimensions.size() > 0, then all dimensions must be + * specified here; and any dimension that was specified in the + * model must have the same value here. + * + * If the dimensions in the model are not fully specified, then + * they must be fully specified here, unless hasNoValue is set to + * true. If the dimensions in the model are fully specified, then + * either dimensions.size() may be 0, or the dimensions in the + * model must be identical to the dimensions here. + */ + vec dimensions; +}; + +/** + * Inputs to be sent to and outputs to be retrieved from a prepared model. + * + * A Request serves two primary tasks: + * 1) Provides the input and output data to be used when executing the model. + * 2) Specifies any updates to the input operand metadata that were left + * unspecified at model preparation time. + * + * An output must not overlap with any other output, with an input, or + * with an operand of lifetime CONSTANT_REFERENCE. + */ +struct Request { + /** + * Input data and information to be used in the execution of a prepared + * model. + * + * The index of the input corresponds to the index in Model.inputIndexes. + * E.g., input[i] corresponds to Model.inputIndexes[i]. + */ + vec inputs; + + /** + * Output data and information to be used in the execution of a prepared + * model. + * + * The index of the output corresponds to the index in Model.outputIndexes. + * E.g., output[i] corresponds to Model.outputIndexes[i]. + */ + vec outputs; + + /** + * A collection of shared memory pools containing operand data for both the + * inputs and the outputs to a model. + */ + vec pools; +}; + +/** + * Return status of a function. + */ +enum ErrorStatus : int32_t { + NONE, + DEVICE_UNAVAILABLE, + GENERAL_FAILURE, + OUTPUT_INSUFFICIENT_SIZE, + INVALID_ARGUMENT, +}; diff --git a/neuralnetworks/1.1/types.hal b/neuralnetworks/1.1/types.hal index 73705bb56d..3d78fb654d 100644 --- a/neuralnetworks/1.1/types.hal +++ b/neuralnetworks/1.1/types.hal @@ -26,7 +26,6 @@ import @1.0::PerformanceInfo; * The type of an operation in a model. */ enum OperationType : @1.0::OperationType { - /** * BatchToSpace for N-dimensional tensors. * @@ -41,7 +40,8 @@ enum OperationType : @1.0::OperationType { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * - * Supported tensor rank: 4 + * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width, + * and Channels) data layout. * * Inputs: * * 0: An n-D tensor, specifying the tensor to be reshaped @@ -51,8 +51,8 @@ enum OperationType : @1.0::OperationType { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 28. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ BATCH_TO_SPACE_ND = 29, @@ -91,8 +91,6 @@ enum OperationType : @1.0::OperationType { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 28. */ DIV = 30, @@ -126,8 +124,8 @@ enum OperationType : @1.0::OperationType { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 28. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be same as input0. */ MEAN = 31, @@ -138,7 +136,8 @@ enum OperationType : @1.0::OperationType { * * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT32} - * * {@link OperandType::TENSOR_QUANT8_ASYMM} (the pad value is undefined) + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * (the pad value is undefined) * * Supported tensor rank: up to 4 * @@ -160,11 +159,8 @@ enum OperationType : @1.0::OperationType { * of the padding: * output0.dimension[i] = * padding[i, 0] + input0.dimension[i] + padding[i, 1] - * - * NOTE: The pad value for {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} - * is undefined. - * - * Available since API level 28. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ PAD = 32, @@ -182,8 +178,10 @@ enum OperationType : @1.0::OperationType { * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * (the pad value is undefined) * - * Supported tensor rank: 4 + * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width, + * and Channels) data layout. * * Inputs: * * 0: An n-D tensor, specifying the input. @@ -201,8 +199,8 @@ enum OperationType : @1.0::OperationType { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 28. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ SPACE_TO_BATCH_ND = 33, @@ -232,8 +230,8 @@ enum OperationType : @1.0::OperationType { * * 0: A tensor of the same {@link OperandType} as input0. Contains the * same data as input, but has one or more dimensions of size 1 * removed. - * - * Available since API level 28. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ SQUEEZE = 34, @@ -278,8 +276,8 @@ enum OperationType : @1.0::OperationType { * Outputs: * * 0: A tensor of the same {@link OperandType} as input0 and rank (n - k), * where k is the number of bits set in shrink_axis_mask. - * - * Available since API level 28. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ STRIDED_SLICE = 35, @@ -318,8 +316,6 @@ enum OperationType : @1.0::OperationType { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 28. */ SUB = 36, @@ -345,11 +341,10 @@ enum OperationType : @1.0::OperationType { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 28. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ TRANSPOSE = 37, - }; /** diff --git a/neuralnetworks/1.1/types.t b/neuralnetworks/1.1/types.t new file mode 100644 index 0000000000..75ac2e7be8 --- /dev/null +++ b/neuralnetworks/1.1/types.t @@ -0,0 +1,158 @@ +%% template file for generating types.hal. +%% see frameworks/ml/nn/tools/api/README.md. +/* + * Copyright (C) 2018 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. + */ + +package android.hardware.neuralnetworks@1.1; + +import @1.0::Operand; +import @1.0::OperationType; +import @1.0::PerformanceInfo; + +/** + * Operation types. + * + * The type of an operation in a model. + */ +enum OperationType : @1.0::OperationType { +%insert Operation_1.1 +}; + +/** + * The capabilities of a driver. + */ +struct Capabilities { + /** + * Driver performance when operating on float32 data. + */ + PerformanceInfo float32Performance; + + /** + * Driver performance when operating on asymmetric 8-bit quantized data. + */ + PerformanceInfo quantized8Performance; + + /** + * Driver performance when operating on float32 data but performing + * calculations with range and/or precision as low as that of the IEEE + * 754 16-bit floating-point format. + */ + PerformanceInfo relaxedFloat32toFloat16Performance; +}; + +/** + * Describes one operation of the model's graph. + */ +struct Operation { + /** + * The operation type. + */ + OperationType type; + + /** + * Describes the table that contains the indexes of the inputs of the + * operation. The offset is the index in the operandIndexes table. + */ + vec inputs; + + /** + * Describes the table that contains the indexes of the outputs of the + * operation. The offset is the index in the operandIndexes table. + */ + vec outputs; +}; + +/** + * A Neural Network Model. + * + * This includes not only the execution graph, but also constant data such as + * weights or scalars added at construction time. The only information that + * may not be known is the shape of the input tensors. + */ +struct Model { + /** + * All operands included in the model. + */ + vec operands; + + /** + * All operations included in the model. + * + * The operations are sorted into execution order. Every operand + * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be + * written before it is read. + */ + vec operations; + + /** + * Input indexes of the model. There must be at least one. + * + * Each value corresponds to the index of the operand in "operands". + */ + vec inputIndexes; + + /** + * Output indexes of the model. There must be at least one. + * + * Each value corresponds to the index of the operand in "operands". + */ + vec outputIndexes; + + /** + * A byte buffer containing operand data that were copied into the model. + * + * An operand's value must be located here if and only if Operand::lifetime + * equals OperandLifeTime::CONSTANT_COPY. + */ + vec operandValues; + + /** + * A collection of shared memory pools containing operand values. + * + * An operand's value must be located here if and only if Operand::lifetime + * equals OperandLifeTime::CONSTANT_REFERENCE. + */ + vec pools; + + /** + * 'true' indicates TENSOR_FLOAT32 may be calculated with range and/or + * precision as low as that of the IEEE 754 16-bit floating-point format. + * 'false' indicates TENSOR_FLOAT32 must be calculated using at least the + * range and precision of the IEEE 754 32-bit floating-point format. + */ + bool relaxComputationFloat32toFloat16; +}; + +/** + * Execution preferences. + */ +enum ExecutionPreference : int32_t { + /** + * Prefer executing in a way that minimizes battery drain. + * This is desirable for compilations that will be executed often. + */ + LOW_POWER = 0, + /** + * Prefer returning a single answer as fast as possible, even if this causes + * more power consumption. + */ + FAST_SINGLE_ANSWER = 1, + /** + * Prefer maximizing the throughput of successive frames, for example when + * processing successive frames coming from the camera. + */ + SUSTAINED_SPEED = 2, +}; diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal index f368ce2cea..837ced5b48 100644 --- a/neuralnetworks/1.2/types.hal +++ b/neuralnetworks/1.2/types.hal @@ -43,8 +43,6 @@ enum OperandType : @1.0::OperandType { * * Values of this operand type are either true or false. A zero value * represents false; any other value represents true. - * - * Available since API level 29. */ BOOL = 6, /** @@ -55,14 +53,10 @@ enum OperandType : @1.0::OperandType { * realValue = integerValue * scale. * * scale is a 32 bit floating point with value greater than zero. - * - * Available since API level 29. */ TENSOR_QUANT16_SYMM = 7, /** * A tensor of IEEE 754 16 bit floating point values. - * - * Available since API level 29. */ TENSOR_FLOAT16 = 8, /** @@ -70,14 +64,10 @@ enum OperandType : @1.0::OperandType { * * Values of this operand type are either true or false. A zero value * represents false; any other value represents true. - * - * Available since API level 29. */ TENSOR_BOOL8 = 9, /** * An IEEE 754 16 bit floating point scalar value. - * - * Available since API level 29. */ FLOAT16 = 10, /** @@ -90,14 +80,13 @@ enum OperandType : @1.0::OperandType { * - scales: an array of positive 32 bit floating point values. * The size of the scales array must be equal to dimensions[channelDim]. * + *{@link SymmPerChannelQuantParams} must hold the parameters for an Operand of this type. * The channel dimension of this tensor must not be unknown (dimensions[channelDim] != 0). * * The formula is: * realValue[..., C, ...] = * integerValue[..., C, ...] * scales[C] * where C is an index in the Channel dimension. - * - * Available since API level 29. */ TENSOR_QUANT8_SYMM_PER_CHANNEL = 11, /** @@ -110,8 +99,6 @@ enum OperandType : @1.0::OperandType { * * The formula is: * real_value = (integer_value - zeroPoint) * scale. - * - * Available since API level 29. */ TENSOR_QUANT16_ASYMM = 12, /** @@ -122,20 +109,19 @@ enum OperandType : @1.0::OperandType { * realValue = integerValue * scale. * * scale is a 32 bit floating point with value greater than zero. - * - * Available since API level 29. */ TENSOR_QUANT8_SYMM = 13, + /* - * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to - * OEM operation and data types. + * DEPRECATED. Since HAL version 1.2, extensions are the preferred + * alternative to OEM operation and data types. * * OEM specific scalar value. * OEM = 10000, */ /* - * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to - * OEM operation and data types. + * DEPRECATED. Since HAL version 1.2, extensions are the preferred + * alternative to OEM operation and data types. * * A tensor of OEM specific values. * TENSOR_OEM_BYTE = 10001, @@ -166,6 +152,7 @@ enum OperandTypeRange : uint32_t { * The type of an operation in a model. */ enum OperationType : int32_t { + /** * Adds two tensors, element-wise. * @@ -187,12 +174,12 @@ enum OperationType : int32_t { * input2.dimension = {5, 4, 3, 1} * output.dimension = {5, 4, 3, 2} * - * Since API level 29, generic zero-sized input tensor is supported. Zero + * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero * dimension is only compatible with 0 or 1. The size of the output * dimension is zero if either of corresponding input dimension is zero. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * @@ -202,14 +189,16 @@ enum OperationType : int32_t { * * 0: A tensor. * * 1: A tensor of the same {@link OperandType}, and compatible dimensions * as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scales and zeroPoint can be different from input0 scale and zeroPoint. * * 2: An {@link OperandType::INT32} scalar, and has to be one of the * {@link FusedActivationFunc} values. Specifies the activation to * invoke on the result. * * Outputs: * * 0: The sum, a tensor of the same {@link OperandType} as input0. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from inputs' scale and zeroPoint. */ ADD = @1.1::OperationType:ADD, @@ -227,7 +216,7 @@ enum OperationType : int32_t { * ) / sum(1) * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * @@ -235,13 +224,14 @@ enum OperationType : int32_t { * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. * * Both explicit padding and implicit padding are supported. * * Inputs (explicit padding): * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying - * the input. Since API level 29, zero batches is supported for this - * tensor. + * the input. + * Since HAL version 1.2, zero batches is supported for this tensor. * * 1: An {@link OperandType::INT32} scalar, specifying the padding on * the left, in the ‘width’ dimension. * * 2: An {@link OperandType::INT32} scalar, specifying the padding on @@ -263,12 +253,12 @@ enum OperationType : int32_t { * invoke on the result. * * 10: An optional {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. - * Available since API level 29. + * Available since HAL version 1.2. * * Inputs (implicit padding): * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying - * the input. Since API level 29, zero batches is supported for this - * tensor. + * the input. + * Since HAL version 1.2, zero batches is supported for this tensor. * * 1: An {@link OperandType::INT32} scalar, specifying the implicit * padding scheme, has to be one of the * following values: {0 (NONE), 1 (SAME), 2 (VALID)}. @@ -285,13 +275,13 @@ enum OperationType : int32_t { * invoke on the result. * * 7: An optional {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. - * Available since API level 29. + * Available since HAL version 1.2. * * Outputs: * * 0: The output 4-D tensor, of shape * [batches, out_height, out_width, depth]. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ AVERAGE_POOL_2D = @1.1::OperationType:AVERAGE_POOL_2D, @@ -302,33 +292,34 @@ enum OperationType : int32_t { * dimensions except the dimension along the concatenation axis. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} - * * {@link OperandType::TENSOR_QUANT8_ASYMM} (full support since API - * level 29, see the input section) + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * (full support since HAL version 1.2, see the input section) * * Supported tensor rank: up to 4 * * Inputs: * * 0 ~ n-1: The list of n input tensors, of shape * [D0, D1, ..., Daxis(i), ..., Dm]. - * Before API level 29, all input tensors of + * Before HAL version 1.2, all input tensors of * {@link OperandType::TENSOR_QUANT8_ASYMM} * must have the same scale and zeroPoint as the output tensor. - * Since API level 29, zero-sized tensors are supported. + * Since HAL version 1.2, zero-sized tensors are supported. * * n: An {@link OperandType::INT32} scalar, specifying the * concatenation axis. * * Outputs: * * 0: The output, a tensor of the same {@link OperandType} as the input * tensors. The output shape is [D0, D1, ..., sum(Daxis(i)), ..., Dm]. - * - * Available since API level 27. + * Since HAL version 1.2, for a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint values can be different from + * input tensors. Before HAL version 1.2 they have to be the same as for the input tensors. */ CONCATENATION = @1.1::OperationType:CONCATENATION, /** - * Performs an 2-D convolution operation. + * Performs a 2-D convolution operation. * * The CONV_2D op sweeps a 2-D filter that can mix channels together over a * batch of images, applying the filter to each window of each image of the @@ -354,7 +345,7 @@ enum OperationType : int32_t { * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to * * * input.scale * filter.scale). * - * Available since API level 29: + * Available since HAL version 1.2: * * 16 bit floating point: * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias. * @@ -368,27 +359,29 @@ enum OperationType : int32_t { * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. * * Both explicit padding and implicit padding are supported. * * Inputs (explicit padding): * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], - * specifying the input. Since API level 29, zero batches is supported - * for this tensor. + * specifying the input. + * Since HAL version 1.2, zero batches is supported for this tensor. * * 1: A 4-D tensor, of shape * [depth_out, filter_height, filter_width, depth_in], specifying the - * filter. For tensor of type - * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel - * dimension (extraParams.channelQuant.channelDim) must be set to 0. + * filter. + * For tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} + * the channel dimension (SymmPerChannelQuantParams::channelDim) + * must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input - * tensor of type {@link OperandType::TENSOR_FLOAT32} or - * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same + * tensor of type {@link OperandType::TENSOR_FLOAT32} + * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint - * of 0 and bias_scale == input_scale * filter_scale. For filter tensor - * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias - * should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of - * 0 and bias_scale of 0. The actual scale of each value 'i' is equal to + * of 0 and bias_scale == input_scale * filter_scale. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 + * and bias_scale of 0. The actual scale of each value 'i' is equal to * bias_scale[i] = input_scale * filter_scale[i]. * * 3: An {@link OperandType::INT32} scalar, specifying the padding on * the left, in the ‘width’ dimension. @@ -407,36 +400,37 @@ enum OperationType : int32_t { * invoke on the result. * * 10: An optional {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. - * Available since API level 29. + * Available since HAL version 1.2. * * 11: An optional {@link OperandType::INT32} scalar, specifying the dilation * factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped * cells between each filter element on width dimension. If this input is set, * input 12 (dilation factor for height) must be specified as well. - * Available since API level 29. + * Available since HAL version 1.2. * * 12: An optional {@link OperandType::INT32} scalar, specifying the dilation * factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped * cells between each filter element on height dimension. If this input is set, * input 11 (dilation factor for width) must be specified as well. - * Available since API level 29. + * Available since HAL version 1.2. * * Inputs (implicit padding): * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], - * specifying the input. Since API level 29, zero batches is supported - * for this tensor. + * specifying the input. + * Since HAL version 1.2, zero batches is supported for this tensor. * * 1: A 4-D tensor, of shape * [depth_out, filter_height, filter_width, depth_in], specifying the - * filter. For tensor of type - * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel - * dimension (extraParams.channelQuant.channelDim) must be set to 0. + * filter. + * For tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} + * the channel dimension (SymmPerChannelQuantParams::channelDim) + * must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input - * tensor of type {@link OperandType::TENSOR_FLOAT32} or - * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same + * tensor of type {@link OperandType::TENSOR_FLOAT32} + * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint - * of 0 and bias_scale == input_scale * filter_scale. For filter tensor - * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias - * should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of - * 0 and bias_scale of 0. The actual scale of each value 'i' is equal to + * of 0 and bias_scale == input_scale * filter_scale. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 + * and bias_scale of 0. The actual scale of each value 'i' is equal to * bias_scale[i] = input_scale * filter_scale[i]. * * 3: An {@link OperandType::INT32} scalar, specifying the implicit * padding scheme, has to be one of the @@ -450,26 +444,23 @@ enum OperationType : int32_t { * invoke on the result. * * 7: An optional {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. - * Available since API level 29. + * Available since HAL version 1.2. * * 8: An optional {@link OperandType::INT32} scalar, specifying the dilation * factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped * cells between each filter element on width dimension. If this input is set, * input 9 (dilation factor for height) must be specified as well. - * Available since API level 29. + * Available since HAL version 1.2. * * 9: An optional {@link OperandType::INT32} scalar, specifying the dilation * factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped * cells between each filter element on height dimension. If this input is set, * input 8 (dilation factor for width) must be specified as well. - * Available since API level 29. + * Available since HAL version 1.2. * * Outputs: * * 0: The output 4-D tensor, of shape - * [batches, out_height, out_width, depth_out]. Before API level 29, - * for output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the - * following condition must be satisfied: - * output_scale > input_scale * filter_scale - * - * Available since API level 27. + * [batches, out_height, out_width, depth_out]. + * Before HAL version 1.2, for output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the following condition must be satisfied: output_scale > input_scale * filter_scale */ CONV_2D = @1.1::OperationType:CONV_2D, @@ -504,7 +495,7 @@ enum OperationType : int32_t { * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to * * * input.scale * filter.scale). * - * Available since API level 29: + * Available since HAL version 1.2: * * 16 bit floating point: * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias. * @@ -518,6 +509,7 @@ enum OperationType : int32_t { * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. * * Both explicit padding and implicit padding are supported. * @@ -525,18 +517,19 @@ enum OperationType : int32_t { * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], * specifying the input. * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out], - * specifying the filter. For tensor of type - * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel - * dimension (extraParams.channelQuant.channelDim) must be set to 3. + * specifying the filter. + * For tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} + * the channel dimension (SymmPerChannelQuantParams::channelDim) + * must be set to 3. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input - * tensor of type {@link OperandType::TENSOR_FLOAT32} or - * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same + * tensor of type {@link OperandType::TENSOR_FLOAT32} + * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint - * of 0 and bias_scale == input_scale * filter_scale. For filter tensor - * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias - * should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of - * 0 and bias_scale of 0. The actual scale of each value 'i' is equal to + * of 0 and bias_scale == input_scale * filter_scale. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 + * and bias_scale of 0. The actual scale of each value 'i' is equal to * bias_scale[i] = input_scale * filter_scale[i]. * * 3: An {@link OperandType::INT32} scalar, specifying the padding on * the left, in the ‘width’ dimension. @@ -557,17 +550,17 @@ enum OperationType : int32_t { * invoke on the result. * * 11: An optional {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. - * Available since API level 29. + * Available since HAL version 1.2. * * 12: An optional {@link OperandType::INT32} scalar, specifying the dilation * factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped * cells between each filter element on width dimension. If this input is set, * input 13 (dilation factor for height) must be specified as well. - * Available since API level 29. + * Available since HAL version 1.2. * * 13: An optional {@link OperandType::INT32} scalar, specifying the dilation * factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped * cells between each filter element on height dimension. If this input is set, * input 12 (dilation factor for width) must be specified as well. - * Available since API level 29. + * Available since HAL version 1.2. * * Inputs (implicit padding): * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], @@ -575,14 +568,14 @@ enum OperationType : int32_t { * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out], * specifying the filter. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input - * tensor of type {@link OperandType::TENSOR_FLOAT32} or - * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same + * tensor of type {@link OperandType::TENSOR_FLOAT32} + * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint - * of 0 and bias_scale == input_scale * filter_scale. For filter tensor - * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias - * should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of - * 0 and bias_scale of 0. The actual scale of each value 'i' is equal to + * of 0 and bias_scale == input_scale * filter_scale. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 + * and bias_scale of 0. The actual scale of each value 'i' is equal to * bias_scale[i] = input_scale * filter_scale[i]. * * 3: An {@link OperandType::INT32} scalar, specifying the implicit * padding scheme, has to be one of the @@ -598,27 +591,24 @@ enum OperationType : int32_t { * invoke on the result. * * 8: An optional {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. - * Available since API level 29. + * Available since HAL version 1.2. * * 9: An optional {@link OperandType::INT32} scalar, specifying the dilation * factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped * cells between each filter element on width dimension. If this input is set, * input 10 (dilation factor for height) must be specified as well. - * Available since API level 29. + * Available since HAL version 1.2. * * 10: An optional {@link OperandType::INT32} scalar, specifying the dilation * factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped * cells between each filter element on height dimension. If this input is set, * input 9 (dilation factor for width) must be specified as well. - * Available since API level 29. - + * Available since HAL version 1.2. * * Outputs: * * 0: The output 4-D tensor, of shape - * [batches, out_height, out_width, depth_out]. Before API level 29, - * for output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the - * following condition must be satisfied: + * [batches, out_height, out_width, depth_out]. Before HAL version 1.2, for + * output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the following condition must be satisfied: * output_scale > input_scale * filter_scale - * - * Available since API level 27. */ DEPTHWISE_CONV_2D = @1.1::OperationType:DEPTHWISE_CONV_2D, @@ -638,7 +628,7 @@ enum OperationType : int32_t { * be divisible by block_size * block_size * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * @@ -646,6 +636,7 @@ enum OperationType : int32_t { * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. * * Inputs: * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], @@ -655,13 +646,13 @@ enum OperationType : int32_t { * of the input depth. * * 2: An optional {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. - * Available since API level 29. + * Available since HAL version 1.2. * * Outputs: * * 0: The output 4-D tensor, of shape [batch, height*block_size, * width*block_size, depth/(block_size*block_size)]. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ DEPTH_TO_SPACE = @1.1::OperationType:DEPTH_TO_SPACE, @@ -674,22 +665,21 @@ enum OperationType : int32_t { * * Supported input tensor {@link OperandType}: * * {@link OperandType::TENSOR_QUANT8_ASYMM} - * * {@link OperandType::TENSOR_QUANT8_SYMM} (since API level 29) - * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} (since API level 29) + * * {@link OperandType::TENSOR_QUANT8_SYMM} (since HAL version 1.2) + * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} (since HAL version 1.2) * * Supported output tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32}. * * Supported tensor rank: up to 4 * * Inputs: - * * 0: A tensor. Since API level 29, this tensor may be zero-sized. + * * 0: A tensor. + * Since HAL version 1.2, this tensor may be zero-sized. * * Outputs: * * 0: A tensor with the same shape as input0. - * - * Available since API level 27. */ DEQUANTIZE = @1.1::OperationType:DEQUANTIZE, @@ -730,8 +720,8 @@ enum OperationType : int32_t { * * 0: A n-D tensor with the same rank and shape as the Values * tensor, except for the first dimension which has the same size * as Lookups' only dimension. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input1. */ EMBEDDING_LOOKUP = @1.1::OperationType:EMBEDDING_LOOKUP, @@ -739,7 +729,7 @@ enum OperationType : int32_t { * Computes element-wise floor() on the input tensor. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * Supported tensor rank: up to 4 @@ -750,8 +740,6 @@ enum OperationType : int32_t { * Outputs: * * 0: The output tensor, of the same {@link OperandType} and dimensions as * the input tensor. - * - * Available since API level 27. */ FLOOR = @1.1::OperationType:FLOOR, @@ -764,7 +752,7 @@ enum OperationType : int32_t { * outputs = activation(inputs * weights’ + bias) * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * @@ -777,8 +765,8 @@ enum OperationType : int32_t { * [batch_size, input_size], where "input_size" corresponds to the * number of inputs to the layer, matching the second dimension of * weights, and "batch_size" is calculated by dividing the number of - * elements by "input_size". Since API level 29, zero batch_size is - * supported for this tensor. + * elements by "input_size". + * Since HAL version 1.2, zero batch_size is supported for this tensor. * * 1: A 2-D tensor, specifying the weights, of shape * [num_units, input_size], where "num_units" corresponds to the number * of output nodes. @@ -793,12 +781,9 @@ enum OperationType : int32_t { * invoke on the result. * * Outputs: - * * 0: The output tensor, of shape [batch_size, num_units]. Before API - * level 29, For output tensor of {@link - * OperandType::TENSOR_QUANT8_ASYMM}, the following condition must be - * satisfied: output_scale > input_scale * filter_scale. - * - * Available since API level 27. + * * 0: The output tensor, of shape [batch_size, num_units]. Before HAL version 1.2, for + * output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the following + * condition must be satisfied: output_scale > input_scale * filter_scale. */ FULLY_CONNECTED = @1.1::OperationType:FULLY_CONNECTED, @@ -849,13 +834,13 @@ enum OperationType : int32_t { * * Outputs: * * 0: Output. A tensor with shape [ k …]. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input2. * * 1: Hits. A boolean tensor with shape [ k ] indicates whether the lookup * hits (True) or not (False). * Stored as {@link OperandType::TENSOR_QUANT8_ASYMM} with offset 0 * and scale 1.0f. * A non-zero byte represents True, a hit. A zero indicates otherwise. - * - * Available since API level 27. */ HASHTABLE_LOOKUP = @1.1::OperationType:HASHTABLE_LOOKUP, @@ -872,12 +857,12 @@ enum OperationType : int32_t { * 1-D slice along dimension dim. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} - * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since API level 29) + * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) * * Supported tensor rank: up to 4 - * Tensors with rank less than 4 are only supported since API level 29. + * Tensors with rank less than 4 are only supported since HAL version 1.2. * * Inputs: * * 0: An n-D tensor, specifying the tensor to be normalized. @@ -885,14 +870,12 @@ enum OperationType : int32_t { * specifying the dimension normalization would be performed on. * Negative index is used to specify axis from the end (e.g. -1 for * the last axis). Must be in the range [-n, n). - * Available since API level 29. + * Available since HAL version 1.2. * * Outputs: * * 0: A tensor of the same {@link OperandType} and same shape as input0. * For {@link OperandType::TENSOR_QUANT8_ASYMM}, * the scale must be 1.f / 128 and the zeroPoint must be 128. - * - * Available since API level 27. */ L2_NORMALIZATION = @1.1::OperationType:L2_NORMALIZATION, @@ -909,20 +892,21 @@ enum OperationType : int32_t { * sum(1)) * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. * * Both explicit padding and implicit padding are supported. * * Inputs (explicit padding): * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying - * the input. Since API level 29, zero batches is supported for this - * tensor. + * the input. + * Since HAL version 1.2, zero batches is supported for this tensor. * * 1: An {@link OperandType::INT32} scalar, specifying the padding on * the left, in the ‘width’ dimension. * * 2: An {@link OperandType::INT32} scalar, specifying the padding on @@ -944,12 +928,12 @@ enum OperationType : int32_t { * invoke on the result. * * 10: An optional {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. - * Available since API level 29. + * Available since HAL version 1.2. * * Inputs (implicit padding): * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying - * the input. Since API level 29, zero batches is supported for this - * tensor. + * the input. + * Since HAL version 1.2, zero batches is supported for this tensor. * * 1: An {@link OperandType::INT32} scalar, specifying the implicit * padding scheme, has to be one of the * following values: {0 (NONE), 1 (SAME), 2 (VALID)}. @@ -966,13 +950,11 @@ enum OperationType : int32_t { * invoke on the result. * * 7: An optional {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. - * Available since API level 29. + * Available since HAL version 1.2. * * Outputs: * * 0: The output 4-D tensor, of shape * [batches, out_height, out_width, depth]. - * - * Available since API level 27. */ L2_POOL_2D = @1.1::OperationType:L2_POOL_2D, @@ -994,11 +976,11 @@ enum OperationType : int32_t { * 1-D slice along specified dimension. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * Supported tensor rank: up to 4 - * Tensors with rank less than 4 are only supported since API level 29. + * Tensors with rank less than 4 are only supported since HAL version 1.2. * * Inputs: * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying @@ -1011,10 +993,10 @@ enum OperationType : int32_t { * For input tensor of {@link OperandType::TENSOR_FLOAT32}, the bias * value must be of {@link OperandType::FLOAT32}. * * 3: A scalar, specifying the scale factor, alpha. - * For input tensor of {@link OperandType::TENSOR_FLOAT16}, the alpha - * value must be of {@link OperandType::FLOAT16}. - * For input tensor of {@link OperandType::TENSOR_FLOAT32}, the alpha - * value must be of {@link OperandType::FLOAT32}. + * For input tensor of {@link OperandType::TENSOR_FLOAT16}, the + * alpha value must be of {@link OperandType::FLOAT16}. + * For input tensor of {@link OperandType::TENSOR_FLOAT32}, the + * alpha value must be of {@link OperandType::FLOAT32}. * * 4: A scalar, specifying the exponent, beta. * For input tensor of {@link OperandType::TENSOR_FLOAT16}, the beta * value must be of {@link OperandType::FLOAT16}. @@ -1024,12 +1006,10 @@ enum OperationType : int32_t { * specifying the dimension normalization would be performed on. * Negative index is used to specify axis from the end (e.g. -1 for * the last axis). Must be in the range [-n, n). - * Available since API level 29. + * Available since HAL version 1.2. * * Outputs: * * 0: The output tensor of same shape as input0. - * - * Available since API level 27. */ LOCAL_RESPONSE_NORMALIZATION = @1.1::OperationType:LOCAL_RESPONSE_NORMALIZATION, @@ -1041,22 +1021,20 @@ enum OperationType : int32_t { * output = 1 / (1 + exp(-input)) * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * * Supported tensor rank: up to 4. * * Inputs: - * * 0: A tensor, specifying the input. Since API level 29, this tensor may - * be zero-sized. + * * 0: A tensor, specifying the input. + * Since HAL version 1.2, this tensor may be zero-sized. * * Outputs: * * 0: The output tensor of same shape as input0. * For {@link OperandType::TENSOR_QUANT8_ASYMM}, * the scale must be 1.f / 256 and the zeroPoint must be 0. - * - * Available since API level 27. */ LOGISTIC = @1.1::OperationType:LOGISTIC, @@ -1064,7 +1042,7 @@ enum OperationType : int32_t { * Projects an input to a bit vector via locality senstive hashing. * * Supported input tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} @@ -1086,7 +1064,7 @@ enum OperationType : int32_t { * Tensor[1].Dim[0] == Tensor[2].Dim[0] * * 3: Type: * Sparse: - * Value LSHProjectionType_SPARSE(=3) (since API level 29). + * Value LSHProjectionType_SPARSE(=3) (since HAL version 1.2). * Computed bit vector is considered to be sparse. * Each output element is an int32 made up of multiple bits * computed from hash functions. @@ -1107,14 +1085,12 @@ enum OperationType : int32_t { * Outputs: * * 0: If the projection type is Sparse: * Output.Dim == { Tensor[0].Dim[0] } - * A tensor of int32 that represents hash signatures, + * A tensor of int32 that represents hash signatures. * * If the projection type is Dense: * Output.Dim == { Tensor[0].Dim[0] * Tensor[0].Dim[1] } * A flattened tensor that represents projected bit vectors. - * - * Available since API level 27. - * The offset value for sparse projections was added in API level 29. + * The offset value for sparse projections was added in HAL version 1.2. */ LSH_PROJECTION = @1.1::OperationType:LSH_PROJECTION, @@ -1170,7 +1146,7 @@ enum OperationType : int32_t { * matrix, each element of which is the product of the corresponding * elements of the input matrices. * - * Since API level 29 LSTM supports layer normalization. + * Since HAL version 1.2 LSTM supports layer normalization. * In case layer normalization is used, the inputs to internal activation * functions (sigmoid and \f$g\f$) are normalized, rescaled and recentered * following an approach from section 3.1 from @@ -1197,7 +1173,7 @@ enum OperationType : int32_t { * * The projection bias (\f$b_{proj}\f$) may (but not required to) have a * value if the recurrent projection layer exists, and should otherwise * have no value. - * * (API level >= 29) The four layer normalization weights either all have + * * (HAL version 1.2 or later) The four layer normalization weights either all have * values or none of them have values. Additionally, if CIFG is used, * input layer normalization weights tensor is omitted and the other layer * normalization weights either all have values or none of them have @@ -1228,7 +1204,7 @@ enum OperationType : int32_t { * Jimmy Ba et al. "Layer Normalization" * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * All input and output tensors must be of the same type. @@ -1291,24 +1267,24 @@ enum OperationType : int32_t { * * 21:The clipping threshold (\f$t_{cell}\f$) for the cell state, such * that values are bound within [-cell_clip, cell_clip]. If set to 0.0 * then clipping is disabled. - * Until API level 29 this scalar must be of type {@link - * FLOAT32}. Since API level 29, if all the input + * Until HAL version 1.2 this scalar must be of type {@link + * OperandType::FLOAT32}. Since HAL version 1.2, if all the input * tensors have type {@link OperandType::TENSOR_FLOAT32}, this * scalar must be of the type {@link OperandType::FLOAT32}, * otherwise if all the input tensors have the type {@link - * TENSOR_FLOAT16}, this scalar must be of type {@link - * FLOAT16}. + * OperandType::TENSOR_FLOAT16}, this scalar must be of type {@link + * OperandType::FLOAT16}. * * 22:The clipping threshold (\f$t_{proj}\f$) for the output from the * projection layer, such that values are bound within * [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled. - * Until API level 29 this scalar must be of type {@link - * FLOAT32}. Since API level 29, if all the input + * Until HAL version 1.2 this scalar must be of type {@link + * OperandType::FLOAT32}. Since HAL version 1.2, if all the input * tensors have type {@link OperandType::TENSOR_FLOAT32}, this * scalar must be of the type {@link OperandType::FLOAT32}, * otherwise if all the input tensors have the type {@link - * TENSOR_FLOAT16}, this scalar must be of type {@link - * FLOAT16}. - * Since API level 29 there are additional inputs to this op: + * OperandType::TENSOR_FLOAT16}, this scalar must be of type {@link + * OperandType::FLOAT16}. + * Since HAL version 1.2 there are additional inputs to this op: * * 23:The input layer normalization weights. * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs * to activation at input gate. @@ -1333,8 +1309,6 @@ enum OperationType : int32_t { * * 3: The output (\f$o_t\f$). * A 2-D tensor of shape [batch_size, output_size]. This is effectively * the same as the current “output state (out)” value. - * - * Available since API level 27. */ LSTM = @1.1::OperationType:LSTM, @@ -1352,7 +1326,7 @@ enum OperationType : int32_t { * ) * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * @@ -1360,13 +1334,14 @@ enum OperationType : int32_t { * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. * * Both explicit padding and implicit padding are supported. * * Inputs (explicit padding): * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying - * the input. Since API level 29, zero batches is supported for this - * tensor. + * the input. + * Since HAL version 1.2, zero batches is supported for this tensor. * * 1: An {@link OperandType::INT32} scalar, specifying the padding on * the left, in the ‘width’ dimension. * * 2: An {@link OperandType::INT32} scalar, specifying the padding on @@ -1388,12 +1363,12 @@ enum OperationType : int32_t { * invoke on the result. * * 10: An optional {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. - * Available since API level 29. + * Available since HAL version 1.2. * * Inputs (implicit padding): * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying - * the input. Since API level 29, zero batches is supported for this - * tensor. + * the input. + * Since HAL version 1.2, zero batches is supported for this tensor. * * 1: An {@link OperandType::INT32} scalar, specifying the implicit * padding scheme, has to be one of the * following values: {0 (NONE), 1 (SAME), 2 (VALID)}. @@ -1410,13 +1385,13 @@ enum OperationType : int32_t { * invoke on the result. * * 7: An optional {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. - * Available since API level 29. + * Available since HAL version 1.2. * * Outputs: * * 0: The output 4-D tensor, of shape * [batches, out_height, out_width, depth]. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ MAX_POOL_2D = @1.1::OperationType:MAX_POOL_2D, @@ -1435,15 +1410,15 @@ enum OperationType : int32_t { * of the input operands. It starts with the trailing dimensions, and works * its way forward. * - * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) - * * {@link OperandType::TENSOR_FLOAT32} - * * {@link OperandType::TENSOR_QUANT8_ASYMM} - * - * Since API level 29, generic zero-sized input tensor is supported. Zero + * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero * dimension is only compatible with 0 or 1. The size of the output * dimension is zero if either of corresponding input dimension is zero. * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * Supported tensor rank: up to 4 * * Inputs: @@ -1459,8 +1434,6 @@ enum OperationType : int32_t { * For output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the following condition must be satisfied: * output_scale > input1_scale * input2_scale. - * - * Available since API level 27. */ MUL = @1.1::OperationType:MUL, @@ -1472,20 +1445,20 @@ enum OperationType : int32_t { * output = max(0, input) * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * * Supported tensor rank: up to 4. * * Inputs: - * * 0: A tensor, specifying the input. Since API level 29, this tensor may - * be zero-sized. + * * 0: A tensor, specifying the input. + * Since HAL version 1.2, this tensor may be zero-sized. * * Outputs: * * 0: The output tensor of same shape as input0. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ RELU = @1.1::OperationType:RELU, @@ -1497,20 +1470,20 @@ enum OperationType : int32_t { * output = min(1.f, max(-1.f, input)) * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * * Supported tensor rank: up to 4. * * Inputs: - * * 0: A tensor, specifying the input. Since API level 29, this tensor may - * be zero-sized. + * * 0: A tensor, specifying the input. + * Since HAL version 1.2, this tensor may be zero-sized. * * Outputs: - * * 0: The output tensor of same shape as input0. - * - * Available since API level 27. + * * 0: The output tensor of the same shape as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ RELU1 = @1.1::OperationType:RELU1, @@ -1522,20 +1495,20 @@ enum OperationType : int32_t { * output = min(6, max(0, input)) * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * * Supported tensor rank: up to 4. * * Inputs: - * * 0: A tensor, specifying the input. Since API level 29, this tensor may - * be zero-sized. + * * 0: A tensor, specifying the input. + * Since HAL version 1.2, this tensor may be zero-sized. * * Outputs: * * 0: The output tensor of same shape as input0. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ RELU6 = @1.1::OperationType:RELU6, @@ -1546,7 +1519,7 @@ enum OperationType : int32_t { * tensor, but with a newly specified shape. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * @@ -1565,8 +1538,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor, of shape specified by the input shape. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ RESHAPE = @1.1::OperationType:RESHAPE, @@ -1578,30 +1551,31 @@ enum OperationType : int32_t { * same as corner pixels of input. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} - * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since API level 29) + * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. * * Both resizing by shape and resizing by scale are supported. * * Inputs (resizing by shape): * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying - * the input. Since API level 29, zero batches is supported for this - * tensor. + * the input. + * Since HAL version 1.2, zero batches is supported for this tensor. * * 1: An {@link OperandType::INT32} scalar, specifying the output * width of the output tensor. * * 2: An {@link OperandType::INT32} scalar, specifying the output * height of the output tensor. * * 3: An optional {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. - * Available since API level 29. + * Available since HAL version 1.2. * - * Inputs (resizing by scale, since API level 29): + * Inputs (resizing by scale, since HAL version 1.2): * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying * the input. Zero batches is supported for this tensor. * * 1: A scalar, specifying width_scale, the scaling factor of the width @@ -1622,8 +1596,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, new_height, new_width, depth]. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ RESIZE_BILINEAR = @1.1::OperationType:RESIZE_BILINEAR, @@ -1644,7 +1618,7 @@ enum OperationType : int32_t { * argument (if not “NONE”). * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * The input tensors must all be the same type. @@ -1676,8 +1650,6 @@ enum OperationType : int32_t { * * 1: output. * A 2-D tensor of shape [batch_size, num_units]. This is effectively * the same as the current state value. - * - * Available since API level 27. */ RNN = @1.1::OperationType:RNN, @@ -1696,34 +1668,32 @@ enum OperationType : int32_t { * independently on each 1-D slice along specified dimension. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * * Supported tensor rank: up to 4. - * Tensors with rank other than 2 or 4 are only supported since API level 29. + * Tensors with rank other than 2 or 4 are only supported since HAL version 1.2. * * Inputs: - * * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped. Since - * API level 29, this tensor may be zero-sized. + * * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped. + * Since HAL version 1.2, this tensor may be zero-sized. * * 1: A scalar, specifying the positive scaling factor for the exponent, * beta. If input0 is of {@link OperandType::TENSOR_FLOAT32} or * {@link OperandType::TENSOR_QUANT8_ASYMM}, the scalar must be of - * {@link OperandType::FLOAT32}. If input0 is of {@link - * OperandType::TENSOR_FLOAT16}, then the scalar must be of {@link - * OperandType::FLOAT16}. + * {@link OperandType::FLOAT32}. + * If input0 is of {@link OperandType::TENSOR_FLOAT16}, then the + * scalar must be of {@link OperandType::FLOAT16}. * * 2: An optional {@link OperandType::INT32} scalar, default to -1, * specifying the dimension the activation would be performed on. * Negative index is used to specify axis from the end (e.g. -1 for * the last axis). Must be in the range [-n, n). - * Available since API level 29. + * Available since HAL version 1.2. * * Outputs: * * 0: The output tensor of same shape as input0. * For {@link OperandType::TENSOR_QUANT8_ASYMM}, * the scale must be 1.f / 256 and the zeroPoint must be 0. - * - * Available since API level 27. */ SOFTMAX = @1.1::OperationType:SOFTMAX, @@ -1742,7 +1712,7 @@ enum OperationType : int32_t { * The input tensor's height and width must be divisible by block_size. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * @@ -1750,6 +1720,7 @@ enum OperationType : int32_t { * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. * * Inputs: * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], @@ -1759,13 +1730,13 @@ enum OperationType : int32_t { * input height and width. * * 2: An optional {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. - * Available since API level 29. + * Available since HAL version 1.2. * * Outputs: * * 0: The output 4-D tensor, of shape [batches, height/block_size, * width/block_size, depth_in*block_size*block_size]. - * - * Available since API level 27. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ SPACE_TO_DEPTH = @1.1::OperationType:SPACE_TO_DEPTH, @@ -1809,7 +1780,7 @@ enum OperationType : int32_t { * the filters. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * All input tensors must be the same type. @@ -1843,8 +1814,6 @@ enum OperationType : int32_t { * * 1: output. * A 2-D tensor of the same {@link OperandType} as the inputs, with shape * [batch_size, num_units]. - * - * Available since API level 27. */ SVDF = @1.1::OperationType:SVDF, @@ -1856,22 +1825,20 @@ enum OperationType : int32_t { * output = tanh(input) * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} - * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since API level 29) + * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) * * Supported tensor rank: up to 4. * * Inputs: - * * 0: A tensor, specifying the input. Since API level 29, this tensor may - * be zero-sized. + * * 0: A tensor, specifying the input. + * Since HAL version 1.2, this tensor may be zero-sized. * * Outputs: * * 0: The output tensor of same shape as input0. * For {@link OperandType::TENSOR_QUANT8_ASYMM}, * the scale must be 1.f / 128 and the zeroPoint must be 128. - * - * Available since API level 27. */ TANH = @1.1::OperationType:TANH, @@ -1886,7 +1853,7 @@ enum OperationType : int32_t { * This is the reverse of SpaceToBatch. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * @@ -1894,6 +1861,7 @@ enum OperationType : int32_t { * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. * * Inputs: * * 0: An n-D tensor, specifying the tensor to be reshaped @@ -1906,8 +1874,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 28. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ BATCH_TO_SPACE_ND = @1.1::OperationType:BATCH_TO_SPACE_ND, @@ -1931,12 +1899,12 @@ enum OperationType : int32_t { * input2.dimension = {5, 4, 3, 1} * output.dimension = {5, 4, 3, 2} * - * Since API level 29, generic zero-sized input tensor is supported. Zero + * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero * dimension is only compatible with 0 or 1. The size of the output * dimension is zero if either of corresponding input dimension is zero. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * Supported tensor rank: up to 4 @@ -1951,8 +1919,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 28. */ DIV = @1.1::OperationType:DIV, @@ -1965,7 +1931,7 @@ enum OperationType : int32_t { * length 1. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * @@ -1987,21 +1953,21 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 28. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be same as input0. */ MEAN = @1.1::OperationType:MEAN, /** - * Pads a tensor with zeros. + * Pads a tensor. * * This operation pads a tensor according to the specified paddings. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} - * * {@link OperandType::TENSOR_QUANT8_ASYMM} (full support since API - * level 29, see the output section) + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * (full support since HAL version 1.2, see the output section) * * Supported tensor rank: up to 4 * @@ -2023,12 +1989,12 @@ enum OperationType : int32_t { * of the padding: * output0.dimension[i] = * padding[i, 0] + input0.dimension[i] + padding[i, 1] + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. * - * NOTE: Before API level 29, the pad value for - * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} is undefined. - * Since API level 29, the pad value is always the logical zero. - * - * Available since API level 28. + * NOTE: Before HAL version 1.2, the pad value for + * {@link OperandType::TENSOR_QUANT8_ASYMM} is undefined. + * Since HAL version 1.2, the pad value is always the logical zero. */ PAD = @1.1::OperationType:PAD, @@ -2044,14 +2010,16 @@ enum OperationType : int32_t { * dimensions of the input are optionally zero padded according to paddings. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * (full support since HAL version 1.2, see the output section) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. * * Inputs: * * 0: An n-D tensor, specifying the input. @@ -2068,12 +2036,16 @@ enum OperationType : int32_t { * end of dimension i. * * 3: An optional {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. - * Available since API level 29. + * Available since HAL version 1.2. * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. * - * Available since API level 28. + * NOTE: Before HAL version 1.2, the pad value for + * {@link OperandType::TENSOR_QUANT8_ASYMM} is undefined. + * Since HAL version 1.2, the pad value is always the logical zero. */ SPACE_TO_BATCH_ND = @1.1::OperationType:SPACE_TO_BATCH_ND, @@ -2086,7 +2058,7 @@ enum OperationType : int32_t { * dimensions by specifying the axes (input1). * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * @@ -2104,8 +2076,8 @@ enum OperationType : int32_t { * * 0: A tensor of the same {@link OperandType} as input0. Contains the * same data as input, but has one or more dimensions of size 1 * removed. - * - * Available since API level 28. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ SQUEEZE = @1.1::OperationType:SQUEEZE, @@ -2119,7 +2091,7 @@ enum OperationType : int32_t { * reverse slice. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * @@ -2151,8 +2123,8 @@ enum OperationType : int32_t { * Outputs: * * 0: A tensor of the same {@link OperandType} as input0 and rank (n - k), * where k is the number of bits set in shrink_axis_mask. - * - * Available since API level 28. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ STRIDED_SLICE = @1.1::OperationType:STRIDED_SLICE, @@ -2176,14 +2148,14 @@ enum OperationType : int32_t { * input2.dimension = {5, 4, 3, 1} * output.dimension = {5, 4, 3, 2} * - * Since API level 29, generic zero-sized input tensor is supported. Zero + * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero * dimension is only compatible with 0 or 1. The size of the output * dimension is zero if either of corresponding input dimension is zero. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} - * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since API level 29) + * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) * * Supported tensor rank: up to 4 * @@ -2197,8 +2169,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 28. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from inputs' scale and zeroPoint. */ SUB = @1.1::OperationType:SUB, @@ -2212,7 +2184,7 @@ enum OperationType : int32_t { * regular matrix transpose on 2-D input Tensors. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * @@ -2220,14 +2192,14 @@ enum OperationType : int32_t { * * Inputs: * * 0: An n-D tensor, specifying the tensor to be transposed. - * Since API level 29, this tensor may be zero-sized. + * Since HAL version 1.2, this tensor may be zero-sized. * * 1: An optional 1-D Tensor of {@link OperandType::TENSOR_INT32}, * the permutation of the dimensions of the input tensor. * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 28. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ TRANSPOSE = @1.1::OperationType:TRANSPOSE, @@ -2245,8 +2217,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of same shape as input0. - * - * Available since API level 29. */ ABS = 38, @@ -2269,8 +2239,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: An (n - 1)-D {@link OperandType::TENSOR_INT32} tensor. - * - * Available since API level 29. */ // There is no underscore in ARG_MAX to avoid name conflict with // the macro defined in libc/kernel/uapi/linux/limits.h. @@ -2295,8 +2263,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: An (n - 1)-D {@link OperandType::TENSOR_INT32} tensor. - * - * Available since API level 29. */ ARGMIN = 40, // See ARGMAX for naming discussion. @@ -2341,8 +2307,8 @@ enum OperationType : int32_t { * * 0: A tensor of the same {@link OperandType} as input0, with shape * [num_rois, num_classes * 4], specifying the coordinates of each * output bounding box for each class, with format [x1, y1, x2, y2]. - * - * Available since API level 29. + * For type of {@link OperandType::TENSOR_QUANT16_ASYMM}, the + * scale must be 0.125 and the zero point must be 0. */ AXIS_ALIGNED_BBOX_TRANSFORM = 41, @@ -2482,17 +2448,15 @@ enum OperationType : int32_t { * then clipping is disabled. * If all the input tensors have type {@link OperandType::TENSOR_FLOAT32}, * this scalar must be of the type {@link OperandType::FLOAT32}, - * otherwise if all the input tensors have the type {@link - * TENSOR_FLOAT16}, this scalar must be of type {@link - * FLOAT16}. + * otherwise if all the input tensors have the type {@link OperandType::TENSOR_FLOAT16}, + * this scalar must be of type {@link OperandType::FLOAT16}. * * 50: The clipping threshold for the output from the * projection layer, such that values are bound within * [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled. * If all the input tensors have type {@link OperandType::TENSOR_FLOAT32}, * this scalar must be of the type {@link OperandType::FLOAT32}, - * otherwise if all the input tensors have the type {@link - * TENSOR_FLOAT16}, this scalar must be of type {@link - * FLOAT16}. + * otherwise if all the input tensors have the type {@link OperandType::TENSOR_FLOAT16}, + * this scalar must be of type {@link OperandType::FLOAT16}. * * 51: merge_outputs * An {@link OperandType::BOOL} scalar specifying if the outputs * from forward and backward cells should be merged. @@ -2539,8 +2503,6 @@ enum OperationType : int32_t { * A 3-D tensor of shape: * If time-major: [max_time, batch_size, bw_output_size] * If batch-major: [batch_size, max_time, bw_output_size] - * - * Available since API level 29. */ BIDIRECTIONAL_SEQUENCE_LSTM = 42, @@ -2658,8 +2620,6 @@ enum OperationType : int32_t { * (timeMajor). If it is set to true, then the shape is set to * [maxTime, batchSize, bwNumUnits], otherwise the shape is set to * [batchSize, maxTime, bwNumUnits]. - * - * Available since API level 29. */ BIDIRECTIONAL_SEQUENCE_RNN = 43, @@ -2737,8 +2697,6 @@ enum OperationType : int32_t { * * 3: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape * [num_output_rois], specifying the batch index of each box. Boxes * with the same batch index are grouped together. - * - * Available since API level 29. */ BOX_WITH_NMS_LIMIT = 44, @@ -2762,8 +2720,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor with the same shape as input0. - * - * Available since API level 29. */ CAST = 45, @@ -2800,8 +2756,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} and same shape as input0. - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ CHANNEL_SHUFFLE = 46, @@ -2856,14 +2812,14 @@ enum OperationType : int32_t { * * 11: A scalar, score_threshold. Boxes with scores lower than the * threshold are filtered before sending to the NMS algorithm. The * scalar must be of {@link OperandType::FLOAT16} if input0 is of - * {@link OperandType::TENSOR_FLOAT16} and of {@link - * OperandType::FLOAT32} if input0 is of {@link - * OperandType::TENSOR_FLOAT32}. + * {@link OperandType::TENSOR_FLOAT16} and of + * {@link OperandType::FLOAT32} if input0 is of + * {@link OperandType::TENSOR_FLOAT32}. * * 12: A scalar, specifying the IoU threshold for hard NMS. The scalar - * must be of {@link OperandType::FLOAT16} if input0 is of {@link - * OperandType::TENSOR_FLOAT16} and of {@link - * OperandType::FLOAT32} if input0 is of {@link - * OperandType::TENSOR_FLOAT32}. + * must be of {@link OperandType::FLOAT16} if input0 is of + * {@link OperandType::TENSOR_FLOAT16} and of + * {@link OperandType::FLOAT32} if input0 is of + * {@link OperandType::TENSOR_FLOAT32}. * * 13: An {@link OperandType::BOOL} scalar, set to true to include * background class in the list of label map for the output, set * to false to not include the background. When the background @@ -2882,8 +2838,6 @@ enum OperationType : int32_t { * output detection. * * 3: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape [batches], * specifying the number of valid output detections for each batch. - * - * Available since API level 29. */ DETECTION_POSTPROCESSING = 47, @@ -2908,8 +2862,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. - * - * Available since API level 29. */ EQUAL = 48, @@ -2927,8 +2879,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of same shape as input0. - * - * Available since API level 29. */ EXP = 49, @@ -2956,8 +2906,8 @@ enum OperationType : int32_t { * Outputs: * * 0: An (n + 1)-D tensor with the same {@link OperandType} and data as * input0. - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ EXPAND_DIMS = 50, @@ -2994,8 +2944,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: An (n + k - 1)-D tensor with the same {@link OperandType} as input0. - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ GATHER = 51, @@ -3074,8 +3024,6 @@ enum OperationType : int32_t { * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape * [num_output_rois], specifying the batch index of each box. Boxes * with the same batch index are grouped together. - * - * Available since API level 29. */ GENERATE_PROPOSALS = 52, @@ -3100,8 +3048,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. - * - * Available since API level 29. */ GREATER = 53, /** @@ -3125,8 +3071,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. - * - * Available since API level 29. */ GREATER_EQUAL = 54, @@ -3191,7 +3135,8 @@ enum OperationType : int32_t { * [depth_out, filter_height, filter_width, depth_group], specifying * the filter, where depth_out must be divisible by num_groups. For * tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} - * the channel dimension must be set to 0. + * the channel dimension (channelDim at + * {@link SymmPerChannelQuantParams}) must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same @@ -3229,7 +3174,8 @@ enum OperationType : int32_t { * [depth_out, filter_height, filter_width, depth_group], specifying * the filter, where depth_out must be divisible by num_groups. For * tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} - * the channel dimension must be set to 0. + * the channel dimension (SymmPerChannelQuantParams::channelDim) + * must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same @@ -3258,8 +3204,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, out_height, out_width, depth_out]. - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from inputs' scale and zeroPoint. */ GROUPED_CONV_2D = 55, @@ -3300,12 +3246,14 @@ enum OperationType : int32_t { * Outputs: * * 0: A tensor of the same {@link OperandType} as input0, with shape * [num_boxes, num_keypoints], specifying score of the keypoints. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from input0 scale and zeroPoint. * * 1: A tensor of the same {@link OperandType} as input1, with shape * [num_boxes, num_keypoints, 2], specifying the location of * the keypoints, the second dimension is organized as * [keypoint_x, keypoint_y]. - * - * Available since API level 29. + * For type of {@link OperandType::TENSOR_QUANT16_ASYMM}, the + * scale must be 0.125 and the zero point must be 0. */ HEATMAP_MAX_KEYPOINT = 56, @@ -3339,26 +3287,24 @@ enum OperationType : int32_t { * * 0: An n-D tensor, specifying the tensor to be normalized. * * 1: A scalar, specifying gamma, the scale applied to the normalized * tensor. The scalar must be of {@link OperandType::FLOAT16} if - * input0 is of {@link OperandType::TENSOR_FLOAT16} and of {@link - * OperandType::FLOAT32} if input0 is of {@link - * OperandType::TENSOR_FLOAT32}. + * input0 is of {@link OperandType::TENSOR_FLOAT16} and of + * {@link OperandType::FLOAT32} if input0 is of + * {@link OperandType::TENSOR_FLOAT32}. * * 2: A scalar, specifying beta, the offset applied to the normalized * tensor. The scalar must be of {@link OperandType::FLOAT16} if - * input0 is of {@link OperandType::TENSOR_FLOAT16} and of {@link - * OperandType::FLOAT32} if input0 is of {@link - * OperandType::TENSOR_FLOAT32}. + * input0 is of {@link OperandType::TENSOR_FLOAT16} and of + * {@link OperandType::FLOAT32} if input0 is of + * {@link OperandType::TENSOR_FLOAT32}. * * 3: A scalar, specifying epsilon, the small value added to variance to * avoid dividing by zero. The scalar must be of {@link OperandType::FLOAT16} if - * input0 is of {@link OperandType::TENSOR_FLOAT16} and of {@link - * OperandType::FLOAT32} if input0 is of {@link - * OperandType::TENSOR_FLOAT32}. + * input0 is of {@link OperandType::TENSOR_FLOAT16} and of + * {@link OperandType::FLOAT32} if input0 is of + * {@link OperandType::TENSOR_FLOAT32}. * * 4: An {@link OperandType::BOOL} scalar, set to true to specify * NCHW data layout for input0 and output0. Set to false for NHWC. * * Outputs: * * 0: A tensor of the same {@link OperandType} and same shape as input0. - * - * Available since API level 29. */ INSTANCE_NORMALIZATION = 57, @@ -3383,8 +3329,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. - * - * Available since API level 29. */ LESS = 58, @@ -3409,8 +3353,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. - * - * Available since API level 29. */ LESS_EQUAL = 59, @@ -3428,8 +3370,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of same shape as input0. - * - * Available since API level 29. */ LOG = 60, @@ -3450,8 +3390,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. - * - * Available since API level 29. */ LOGICAL_AND = 61, @@ -3468,8 +3406,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of same shape as input0. - * - * Available since API level 29. */ LOGICAL_NOT = 62, @@ -3490,8 +3426,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. - * - * Available since API level 29. */ LOGICAL_OR = 63, @@ -3523,8 +3457,6 @@ enum OperationType : int32_t { * Outputs: * * 0: The output tensor of the same {@link OperandType} and shape as * input0. - * - * Available since API level 29. */ LOG_SOFTMAX = 64, @@ -3543,11 +3475,13 @@ enum OperationType : int32_t { * * 0: A tensor. * * 1: A tensor of the same {@link OperandType} and compatible dimensions * with input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scales and zeroPoint can be different from input0 scale and zeroPoint. * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from inputs' scale and zeroPoint. */ MAXIMUM = 65, @@ -3566,11 +3500,13 @@ enum OperationType : int32_t { * * 0: A tensor. * * 1: A tensor of the same {@link OperandType} and compatible dimensions * with input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scales and zeroPoint can be different from input0 scale and zeroPoint. * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from inputs' scale and zeroPoint. */ MINIMUM = 66, @@ -3589,8 +3525,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of same shape as input0. - * - * Available since API level 29. */ NEG = 67, @@ -3615,8 +3549,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. - * - * Available since API level 29. */ NOT_EQUAL = 68, @@ -3657,8 +3589,8 @@ enum OperationType : int32_t { * of the padding: * output0.dimension[i] = * padding[i, 0] + input0.dimension[i] + padding[i, 1] - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ PAD_V2 = 69, @@ -3689,8 +3621,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: An output tensor. - * - * Available since API level 29. */ POW = 70, @@ -3728,8 +3658,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be diffent from the input0 scale and zeroPoint. */ PRELU = 71, @@ -3752,8 +3682,6 @@ enum OperationType : int32_t { * Outputs: * * 0: The output tensor of same shape as input0, but with * {@link OperandType::TENSOR_QUANT8_ASYMM}. - * - * Available since API level 29. */ QUANTIZE = 72, @@ -3879,8 +3807,6 @@ enum OperationType : int32_t { * Outputs: * * 0: A 2-D {@link OperandType::TENSOR_INT32} tensor with shape * [batches, samples], containing the drawn samples. - * - * Available since API level 29. */ RANDOM_MULTINOMIAL = 74, @@ -3906,8 +3832,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 29. */ REDUCE_ALL = 75, @@ -3933,8 +3857,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 29. */ REDUCE_ANY = 76, @@ -3962,8 +3884,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ REDUCE_MAX = 77, @@ -3991,8 +3913,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ REDUCE_MIN = 78, @@ -4018,8 +3940,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 29. */ REDUCE_PROD = 79, @@ -4045,8 +3965,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * - * Available since API level 29. */ REDUCE_SUM = 80, @@ -4064,7 +3982,7 @@ enum OperationType : int32_t { * interpolation. * * Supported tensor {@link OperandType}: - * * {@link OperandType::TENSOR_FLOAT16} (since API level 29) + * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * @@ -4105,8 +4023,8 @@ enum OperationType : int32_t { * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. The output * shape is [num_rois, out_height, out_width, depth]. - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from the input0 scale and zeroPoint. */ ROI_ALIGN = 81, @@ -4156,8 +4074,8 @@ enum OperationType : int32_t { * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. The output * shape is [num_rois, out_height, out_width, depth]. - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ ROI_POOLING = 82, @@ -4175,8 +4093,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of same shape as input0. - * - * Available since API level 29. */ RSQRT = 83, @@ -4201,9 +4117,13 @@ enum OperationType : int32_t { * true) or input2 (if false). * * 1: An input tensor of the same shape as input0. * * 2: An input tensor of the same shape and type as input1. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scales and zeroPoint can be different from input1 scale and zeroPoint. * * Outputs: * * 0: A tensor of the same type and shape as input1 and input2. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from inputs' scale and zeroPoint. * */ SELECT = 84, @@ -4222,8 +4142,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of same shape as input0. - * - * Available since API level 29. */ SIN = 85, @@ -4235,7 +4153,6 @@ enum OperationType : int32_t { * for each dimension. The size is specified as a 1-D tensor containing * either size of a slice along corresponding dimension or -1. In the latter * case, all the remaining elements in dimension are included in the slice. - * Slice size in each dimension cannot be zero. * * A sum of begin offset and a size of a slice must not exceed size of a * corresponding dimension. @@ -4257,8 +4174,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: An n-D tensor of the same type as the input containing the slice. - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * its scale and zeroPoint has to be same as the input0 scale and zeroPoint. */ SLICE = 86, @@ -4282,8 +4199,8 @@ enum OperationType : int32_t { * * Outputs: * * 0 ~ (num_splits - 1): Resulting subtensors. - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ SPLIT = 87, @@ -4301,8 +4218,6 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of same shape as input0. - * - * Available since API level 29. */ SQRT = 88, @@ -4330,8 +4245,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tiled tensor of the same {@link OperandType} and rank as `input`. - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ TILE = 89, @@ -4357,10 +4272,10 @@ enum OperationType : int32_t { * Outputs: * * 0: An n-D tensor of the same type as the input, containing the k * largest elements along each last dimensional slice. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. * * 1: An n-D tensor of type {@link OperandType::TENSOR_INT32} * containing the indices of values within the last dimension of input. - * - * Available since API level 29. */ TOPK_V2 = 90, @@ -4374,7 +4289,7 @@ enum OperationType : int32_t { * The output dimensions are functions of the filter dimensions, stride, and * padding. * - * Supported tensor {@link OperandCode} configurations: + * Supported tensor {@link OperandType} configurations: * * 16 bit floating point: * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias. * @@ -4406,7 +4321,7 @@ enum OperationType : int32_t { * [depth_out, filter_height, filter_width, depth_in], specifying the * filter. For tensor of type * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel - * dimension (extraParams.channelQuant.channelDim) must be set to 0. + * dimension (SymmPerChannelQuantParams::channelDim) must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or * {@link OperandType::TENSOR_FLOAT16}, the bias should be of the @@ -4443,7 +4358,7 @@ enum OperationType : int32_t { * [depth_out, filter_height, filter_width, depth_in], specifying the * filter. For tensor of type * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel - * dimension (extraParams.channelQuant.channelDim) must be set to 0. + * dimension (SymmPerChannelQuantParams::channelDim) must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or * {@link OperandType::TENSOR_FLOAT16}, the bias should be of the @@ -4473,8 +4388,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, out_height, out_width, depth_out]. - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from inputs' scale and zeroPoint. */ TRANSPOSE_CONV_2D = 91, @@ -4584,8 +4499,6 @@ enum OperationType : int32_t { * A 3-D tensor of shape: * If time-major: [max_time, batch_size, output_size] * If batch-major: [batch_size, max_time, output_size] - * - * Available since API level 29. */ UNIDIRECTIONAL_SEQUENCE_LSTM = 92, @@ -4641,8 +4554,6 @@ enum OperationType : int32_t { * it is set to 1, then the output has a shape [maxTime, batchSize, * numUnits], otherwise the output has a shape [batchSize, maxTime, * numUnits]. - * - * Available since API level 29. */ UNIDIRECTIONAL_SEQUENCE_RNN = 93, @@ -4696,8 +4607,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, new_height, new_width, depth]. - * - * Available since API level 29. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. */ RESIZE_NEAREST_NEIGHBOR = 94, diff --git a/neuralnetworks/1.2/types.t b/neuralnetworks/1.2/types.t new file mode 100644 index 0000000000..cab330d454 --- /dev/null +++ b/neuralnetworks/1.2/types.t @@ -0,0 +1,745 @@ +%% template file for generating types.hal. +%% see frameworks/ml/nn/tools/api/README.md. +/* + * Copyright (C) 2018 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. + */ + +package android.hardware.neuralnetworks@1.2; + +import @1.0::DataLocation; +import @1.0::ErrorStatus; +import @1.0::OperandLifeTime; +import @1.0::OperandType; +import @1.0::PerformanceInfo; +import @1.1::OperationType; + +import android.hidl.safe_union@1.0::Monostate; + +enum Constant : uint32_t { + /** + * The byte size of the cache token. + */ + BYTE_SIZE_OF_CACHE_TOKEN = 32, + + /** + * The maximum number of files for each type of cache in compilation caching. + */ + MAX_NUMBER_OF_CACHE_FILES = 32, +}; + +enum OperandType : @1.0::OperandType { +%insert Operand_1.2 + + /* + * DEPRECATED. Since HAL version 1.2, extensions are the preferred + * alternative to OEM operation and data types. + * + * OEM specific scalar value. + * OEM = 10000, + */ + /* + * DEPRECATED. Since HAL version 1.2, extensions are the preferred + * alternative to OEM operation and data types. + * + * A tensor of OEM specific values. + * TENSOR_OEM_BYTE = 10001, + */ + /* ADDING A NEW FUNDAMENTAL TYPE REQUIRES UPDATING THE VALUE OF + * OperandTypeRange::FUNDAMENTAL_MAX. + */ + /* ADDING A NEW OEM TYPE REQUIRES UPDATING THE VALUE OF + * OperandTypeRange::OEM_MAX. + */ +}; + +/** + * The range of operand values in the OperandType enum. + */ +enum OperandTypeRange : uint32_t { + BASE_MIN = 0, + FUNDAMENTAL_MIN = 0, +%insert Operand_1.2_MAX + OEM_MIN = 10000, + OEM_MAX = 10001, + BASE_MAX = 0xFFFF, +}; + +/** + * Operation types. + * + * The type of an operation in a model. + */ +enum OperationType : int32_t { + +%insert Operation_1.0 + +%insert Operation_1.1 + +%insert Operation_1.2 + + /** + * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to + * OEM operation and data types. + * + * This operation is OEM specific. It should only be used for OEM + * applications. + */ + OEM_OPERATION = @1.1::OperationType:OEM_OPERATION, + /* ADDING A NEW FUNDAMENTAL OPERATION REQUIRES UPDATING THE VALUE OF + * OperationTypeRange::FUNDAMENTAL_MAX. + */ + /* ADDING A NEW OEM OPERATION REQUIRES UPDATING THE VALUE OF + * OperationTypeRange::OEM_MAX. + */ +}; + +/** + * The range of values in the OperationType enum. + */ +enum OperationTypeRange : uint32_t { + BASE_MIN = 0, + FUNDAMENTAL_MIN = 0, +%insert Operation_1.2_MAX + OEM_MIN = 10000, + OEM_MAX = 10000, + BASE_MAX = 0xFFFF, +}; + +/** + * Device types. + * + * The type of NNAPI device. + */ +enum DeviceType : int32_t { + // Leaving 0 unused as it means unknown type in NDK NNAPI. There is no + // HAL equivalent of unknown type and a 1.2 HAL implementation must belong + // to one of the categories below. + /** The device does not fall into any category below. */ + OTHER = 1, + /** The device runs NNAPI models on single or multi-core CPU. */ + CPU = 2, + /** The device can run NNAPI models and also accelerate graphics APIs such + * as OpenGL ES and Vulkan. */ + GPU = 3, + /** Dedicated accelerator for Machine Learning workloads. */ + ACCELERATOR = 4, +}; + +/** + * The capabilities of a driver. + * + * Performance of an operation comes from the type of its first operand. + * This represents performance for non extension operand types. + */ +struct Capabilities { + /** + * Driver performance when operating on float32 data but performing + * calculations with range and/or precision as low as that of the IEEE + * 754 16-bit floating-point format. + */ + PerformanceInfo relaxedFloat32toFloat16PerformanceScalar; + PerformanceInfo relaxedFloat32toFloat16PerformanceTensor; + + /** + * Driver performance when operating on a particular data type. + * In the case of float32 data, this is used when the calculations + * are not relaxed. + */ + struct OperandPerformance { + OperandType type; + PerformanceInfo info; + }; + + /** + * Performance by operand type. Must be sorted by OperandType. + * If a particular OperandType is not present in operandPerformance, + * its performance is treated as { .execTime = FLT_MAX, .powerUsage = FLT_MAX }. + */ + vec operandPerformance; +}; + +/** + * Describes one operation of the model's graph. + */ +struct Operation { + /** + * The operation type. + * + * Besides the values listed in {@link OperationType}, any value above + * {@link OperationTypeRange::BASE_MAX} is possible and should be interpreted + * as an extension type according to {@link Model::extensionNameToPrefix}. + */ + OperationType type; + + /** + * Describes the table that contains the indexes of the inputs of the + * operation. The offset is the index in the operandIndexes table. + */ + vec inputs; + + /** + * Describes the table that contains the indexes of the outputs of the + * operation. The offset is the index in the operandIndexes table. + */ + vec outputs; +}; + +/** + * Parameters for TENSOR_QUANT8_SYMM_PER_CHANNEL operand. + */ +struct SymmPerChannelQuantParams { + /** Array of scaling values for each channel. Each value must be greater than zero. */ + vec scales; + /** Index of the channel dimension */ + uint32_t channelDim; +}; + +/** + * Describes one operand of the model's graph. + */ +struct Operand { + /** + * The data type. + * + * Besides the values listed in {@link OperandType}, any value above + * {@link OperandTypeRange::BASE_MAX} is possible and should be interpreted + * as an extension type according to {@link Model::extensionNameToPrefix}. + */ + OperandType type; + + /** + * Dimensions of the operand. + * + * For a scalar operand, dimensions.size() must be 0. + * + * A tensor operand with all dimensions specified has "fully + * specified" dimensions. Whenever possible (i.e., whenever the + * dimensions are known at model construction time), a tensor + * operand should have (but is not required to have) fully + * specified dimensions, in order to enable the best possible + * performance. + * + * 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. + * + * In the following situations, a tensor operand's dimensions must + * be fully specified: + * + * . The operand has lifetime CONSTANT_COPY or + * CONSTANT_REFERENCE. + * + * . The operand has lifetime MODEL_INPUT. 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 + * (by setting the hasNoValue field of the corresponding + * RequestArgument to true) then it need not have fully + * specified dimensions. + * + * A tensor operand with some number of unspecified dimensions is + * represented by setting each unspecified dimension to 0. + * + * A tensor operand with unspecified rank is represented by providing + * an empty dimensions vector. + */ + vec dimensions; + + /** + * The number of times this operand appears as an operation input. + * + * (For example, if this operand appears once in one operation's + * input list, and three times in another operation's input list, + * then numberOfConsumers = 4.) + */ + uint32_t numberOfConsumers; + + /** + * Quantized scale of the operand. + * + * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM or + * TENSOR_INT32. + */ + float scale; + + /** + * Quantized zero-point offset of the operand. + * + * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM. + */ + int32_t zeroPoint; + + /** + * How the operand is used. + */ + OperandLifeTime lifetime; + + /** + * Where to find the data for this operand. + * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or + * NO_VALUE: + * - All the fields must be 0. + * If the lifetime is CONSTANT_COPY: + * - location.poolIndex is 0. + * - location.offset is the offset in bytes into Model.operandValues. + * - location.length is set. + * If the lifetime is CONSTANT_REFERENCE: + * - location.poolIndex is set. + * - location.offset is the offset in bytes into the specified pool. + * - location.length is set. + */ + DataLocation location; + + /** + * Additional parameters specific to a particular operand type. + */ + safe_union ExtraParams { + /** + * No additional parameters. + */ + Monostate none; + + /** + * Symmetric per-channel quantization parameters. + * + * Only applicable to operands of type TENSOR_QUANT8_SYMM_PER_CHANNEL. + */ + SymmPerChannelQuantParams channelQuant; + + /** + * Extension operand parameters. + * + * The framework treats this as an opaque data blob. + * The format is up to individual extensions. + */ + vec extension; + } extraParams; +}; + +/** + * A Neural Network Model. + * + * This includes not only the execution graph, but also constant data such as + * weights or scalars added at construction time. The only information that + * may not be known is the shape of the input tensors. + */ +struct Model { + /** + * All operands included in the model. + */ + vec operands; + + /** + * All operations included in the model. + * + * The operations are sorted into execution order. Every operand + * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be + * written before it is read. + */ + vec operations; + + /** + * Input indexes of the model. There must be at least one. + * + * Each value corresponds to the index of the operand in "operands". + */ + vec inputIndexes; + + /** + * Output indexes of the model. There must be at least one. + * + * Each value corresponds to the index of the operand in "operands". + */ + vec outputIndexes; + + /** + * A byte buffer containing operand data that were copied into the model. + * + * An operand's value must be located here if and only if Operand::lifetime + * equals OperandLifeTime::CONSTANT_COPY. + */ + vec operandValues; + + /** + * A collection of shared memory pools containing operand values. + * + * An operand's value must be located here if and only if Operand::lifetime + * equals OperandLifeTime::CONSTANT_REFERENCE. + */ + vec pools; + + /** + * 'true' indicates TENSOR_FLOAT32 may be calculated with range and/or + * precision as low as that of the IEEE 754 16-bit floating-point format. + * 'false' indicates TENSOR_FLOAT32 must be calculated using at least the + * range and precision of the IEEE 754 32-bit floating-point format. + */ + bool relaxComputationFloat32toFloat16; + + /** + * The mapping between extension names and prefixes of operand and + * operation type values. + * + * An operand or operation whose numeric type value is above + * {@link OperandTypeRange::BASE_MAX} or + * {@link OperationTypeRange::BASE_MAX} respectively should be interpreted + * as an extension operand. The low + * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value + * correspond to the type ID within the extension and the high + * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode + * the "prefix", which maps uniquely to the extension name. + * + * For example, if a model contains an operation whose value is + * 0xAAAABBBB and extensionNameToPrefix contains an entry with + * prefix=0xAAAA and name="vendor.test.test_extension", then + * the operation should be interpreted as the operation 0xBBBB + * of the extension named vendor.test.test_extension. + * + * This is a one-to-one correspondence. That is, there must be at most one + * prefix corresponding to each extension name and at most one extension + * name corresponding to each prefix. + */ + vec extensionNameToPrefix; + + /** + * A correspondence between an extension name and a prefix of operand and + * operation type values. + */ + struct ExtensionNameAndPrefix { + /** + * The extension name. + * + * See {@link Extension::name} for the format specification. + */ + string name; + + /** + * The unique extension identifier within the model. + * + * See {@link Model::extensionNameToPrefix}. + */ + uint16_t prefix; + }; + + /** + * Numeric values of extension operand and operation types have the + * following structure: + * - 16 high bits represent the "prefix", which corresponds uniquely to the + * extension name. + * - 16 low bits represent the type ID within the extension. + */ + enum ExtensionTypeEncoding : uint8_t { + HIGH_BITS_PREFIX = 16, + LOW_BITS_TYPE = 16, + }; +}; + +/** + * Describes the shape information of an output operand after execution. + */ +struct OutputShape { + /** + * Dimensions of the operand. + */ + vec dimensions; + + /** + * Whether the provided buffer size is sufficient for the output. + */ + bool isSufficient; +}; + +/** + * Specifies whether or not to measure timing information during execution. + */ +enum MeasureTiming : int32_t { + NO = 0, + YES = 1, +}; + +/** + + * Timing information measured during execution. Each time is a duration from + * the beginning of some task to the end of that task, including time when that + * task is not active (for example, preempted by some other task, or + * waiting for some resource to become available). + * + * Times are measured in microseconds. + * When a time is not available, it must be reported as UINT64_MAX. + */ +struct Timing { + /** Execution time on device (not driver, which runs on host processor). */ + uint64_t timeOnDevice; + /** Execution time in driver (including time on device). */ + uint64_t timeInDriver; +}; + +/** + * FmqRequestDatum is a single element of a serialized representation of an + * execution request (a {@link @1.0::Request} object and a {@link MeasureTiming} + * value) which is sent across FastMessageQueue. + * + * The serialized representation for a particular execution is referred to later + * in these descriptions as a 'packet'. + * + * FastMessageQueue can only pass HIDL-defined types that do not involve nested + * buffers, handles, or interfaces. + * + * The request is serialized as follows: + * 1) 'packetInformation' + * 2) For each input operand: + * 2.1) 'inputOperandInformation' + * 2.2) For each dimension element of the operand: + * 2.2.1) 'inputOperandDimensionValue' + * 3) For each output operand: + * 3.1) 'outputOperandInformation' + * 3.2) For each dimension element of the operand: + * 3.2.1) 'outputOperandDimensionValue' + * 4) For each pool: + * 4.1) 'poolIdentifier' + * 5) 'measureTiming' + */ +safe_union FmqRequestDatum { + /** + * Type to describe the high-level layout of the packet. + */ + struct PacketInformation { + /** + * How many elements the packet contains, including the + * "packetInformation" datum. + */ + uint32_t packetSize; + + /** + * Number of input operands. + */ + uint32_t numberOfInputOperands; + + /** + * Number of output operands. + */ + uint32_t numberOfOutputOperands; + + /** + * Number of pool identifiers. + */ + uint32_t numberOfPools; + }; + + /** + * Type representing the information for each operand. + */ + struct OperandInformation { + /** + * If true, the argument does not have a value. This can be used for + * operations that take optional arguments. If true, the fields of + * 'location' are set to 0, 'numberOfDimensions' is set to 0, and the + * dimensions information is omitted from the serialization. + */ + bool hasNoValue; + + /** + * The location within one of the memory pools passed in the Request. + */ + DataLocation location; + + /** + * Number of subsequent elements that belong to the dimensions vector. + */ + uint32_t numberOfDimensions; + }; + + /** + * packetInformation is the first element of the packet and describes the + * remainder of the packet. + */ + PacketInformation packetInformation; + + /** + * Information for each input operand. + */ + OperandInformation inputOperandInformation; + + /** + * Element of the dimensions vector. + */ + uint32_t inputOperandDimensionValue; + + /** + * Information for each output operand. + */ + OperandInformation outputOperandInformation; + + /** + * Element of the dimensions vector. + */ + uint32_t outputOperandDimensionValue; + + /** + * Unique identifier for a pool. + * + * A {@link @1.0::Request} passes across one or more pools of shared memory + * for the inputs and outputs of an execution. However, these memory pools + * are not able to be sent across FastMessageQueue directly. Instead, the + * producing side of the FMQ represents each different pool with a unique + * identifier, and sends this identifier across the FMQ. Whenever the + * consuming side of the FMQ needs the memory corresponding to this unique + * identifier, it can pass the identifier to + * {@link IBurstCallback::getMemories} to retreive the memory. Although this + * HIDL Binder call is expensive compared to communication across FMQ, it is + * only needed in the cases when the consumer does not recognize the unique + * identifier. + */ + int32_t poolIdentifier; + + /** + * Specifies whether or not to measure duration of the execution. The + * duration runs from the time the driver dequeues the request from a + * FastMessageQueue to the time the driver enqueues results to a + * FastMessageQueue. + */ + MeasureTiming measureTiming; +}; + +/** + * FmqResultDatum is a single element of a serialized representation of the + * values returned from an execution ({@link @1.0::ErrorStatus}, + * vec<{@link OutputShape}>, and {@link Timing}) which is returned via + * FastMessageQueue. + * + * The serialized representation for a particular execution is referred to later + * in these descriptions as a 'packet'. + * + * FastMessageQueue can only pass HIDL-defined types that do not involve nested + * buffers, handles, or interfaces. + * + * The execution return values ({@link @1.0::ErrorStatus} and + * vec<{@link OutputShape}>) are serialized as follows: + * 1) 'packetInformation' + * 2) For each returned operand: + * 2.1) 'operandInformation' + * 2.2) For each dimension element of the operand: + * 2.2.1) 'operandDimensionValue' + * 3) 'executionTiming' + */ +safe_union FmqResultDatum { + /** + * Type to describe the high-level layout of the packet. + */ + struct PacketInformation { + /** + * How many elements the packet contains, including the + * "packetInformation" datum. + */ + uint32_t packetSize; + + /** + * Status of the execution. + */ + ErrorStatus errorStatus; + + /** + * Number of returned operands. + */ + uint32_t numberOfOperands; + }; + + /** + * Type representing the information for each operand. + */ + struct OperandInformation { + /** + * Indicates whether the operand's output buffer is large enough to + * store the operand's result data. + */ + bool isSufficient; + + /** + * Number of subsequent elements that belong to the dimensions vector. + */ + uint32_t numberOfDimensions; + }; + + /** + * packetInformation is the first element of the packet and describes the + * remainder of the packet. It additionally includes the status of the + * execution. + */ + PacketInformation packetInformation; + + /** + * Information for each returned operand. + */ + OperandInformation operandInformation; + + /** + * Element of the dimensions vector. + */ + uint32_t operandDimensionValue; + + /** + * Duration of execution. Unless measurement was requested and execution + * succeeds, all times must be reported as UINT64_MAX. A driver may choose + * to report any time as UINT64_MAX, indicating that measurement is not + * available. + */ + Timing executionTiming; +}; + +/** + * Information about an extension. + */ +struct Extension { + /** + * The extension name. + * + * The name must consist of lowercase latin letters, numbers, periods, and + * underscore signs. The name must contain at least one period. + * + * The name must start with the reverse domain name of the vendor. + * + * Example: com.google.test_extension + */ + string name; + + /** + * Information about an extension operand type. + */ + struct OperandTypeInformation { + /** + * The extension operand type. + */ + uint16_t type; + + /** + * Indicates whether the extension operand type represents a tensor or + * a scalar. + */ + bool isTensor; + + /** + * The byte size of the operand (if scalar) or of a single element (if + * tensor). + */ + uint32_t byteSize; + }; + + /** + * Information about operand types defined by the extension. + */ + vec operandTypes; +}; From a0cbe5804e6cee2850da923eedf2b2a3f9e44b8f Mon Sep 17 00:00:00 2001 From: Enrico Granata Date: Fri, 4 Oct 2019 11:14:50 -0700 Subject: [PATCH 0146/1022] Edit a comment to reflect an actual enum type name There is nothing named enum_vehicle_ap_power_state_shutdown_param_type in the Vehicle HAL source tree. The right greppable type name is VehicleApPowerStateShutdownParam. Test: git diff Change-Id: Ib6c8be491df9aa6cb3143b28a12b70bd4b8c29cc --- automotive/vehicle/2.0/types.hal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index 9dfd558f79..1355d9feab 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -2537,7 +2537,7 @@ enum VehicleApPowerStateReq : int32_t { * power controller must change power state to this state to shutdown * system. * - * int32Values[1] : one of enum_vehicle_ap_power_state_shutdown_param_type + * int32Values[1] : one of VehicleApPowerStateShutdownParam * * SHUTDOWN_PRPARE may be requested from either WAIT_FOR_VHAL or ON states. */ From 7259f3ab24a5f61c99e74c5cbf7ffa8fb3a9e163 Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Fri, 4 Oct 2019 14:32:51 -0700 Subject: [PATCH 0147/1022] Increase neuralnetworks compatibility to 1.3 Bug: 139120468 Test: mma Change-Id: Ic41febe005dfefe834587ec67fdda52e112c37cb --- compatibility_matrices/compatibility_matrix.current.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index c9206749a3..409c5a289e 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -307,7 +307,7 @@ android.hardware.neuralnetworks - 1.0-2 + 1.0-3 IDevice .* From de7d06babb5e1dd29390d4f0c63714794bdb697f Mon Sep 17 00:00:00 2001 From: Kevin Rocard Date: Tue, 18 Jun 2019 16:38:16 -0700 Subject: [PATCH 0148/1022] Convert audio HAL service mk to bp and rename the service The service supports multiple versions and its name should not be version dependant. For backward compatibility, keep the target name android.hardware.audio@2.0-service (32bit only), existing PRODUCT_PACKAGES do not have to be updated. New products should depend on android.hardware.audio.service:32. Additionally migrate to Android.bp, dropping support for AUDIOSERVER_MULTILIB. Previously the HAL service architecture (32 vs 64) would be the same as the audio server. This in not wanted as all android audio HAL are 32 bits. Bug: 121208203 Test: # Compare following commands before and after patch: find $ANDROID_PRODUCT_OUT/vendor -name 'android.hardware.audio*'|xargs file adb shell reboot # check device boots to UI and # check the HAL restarts after the audioserver is killed adb shell ps |grep audio; adb shell killall audioserver; adb shell ps Change-Id: I25f41735175a6687a051ca1e5a7fee670eb8115e Signed-off-by: Kevin Rocard --- CleanSpec.mk | 1 + .../all-versions/default/service/Android.bp | 48 ++++++++++++++ .../all-versions/default/service/Android.mk | 63 ------------------- ...e.rc => android.hardware.audio.service.rc} | 2 +- 4 files changed, 50 insertions(+), 64 deletions(-) create mode 100644 audio/common/all-versions/default/service/Android.bp delete mode 100644 audio/common/all-versions/default/service/Android.mk rename audio/common/all-versions/default/service/{android.hardware.audio@2.0-service.rc => android.hardware.audio.service.rc} (81%) diff --git a/CleanSpec.mk b/CleanSpec.mk index edde1cbd33..da2635e0d2 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -80,3 +80,4 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/vndk-Q/android.hardwar $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/android.hardware.configstore@1.2.so) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/vndk-Q/android.hardware.configstore@1.2.so) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/android.hardware.configstore@1.2.so) +$(call add-clean-step, rm -f $(PRODUCT_OUT)/etc/init/android.hardware.audio@2.0-service.rc $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.audio@2.0-service) diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp new file mode 100644 index 0000000000..f5a6f42df5 --- /dev/null +++ b/audio/common/all-versions/default/service/Android.bp @@ -0,0 +1,48 @@ +cc_binary { + name: "android.hardware.audio.service", + + init_rc: ["android.hardware.audio.service.rc"], + relative_install_path: "hw", + vendor: true, + // Only support 32 bit as the binary must always be installed at the same + // location for init to start it and the build system does not support + // having two binaries installable to the same location even if they are + // not installed in the same build. + compile_multilib: "32", + srcs: ["service.cpp"], + + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], + + shared_libs: [ + "libcutils", + "libbinder", + "libhidlbase", + "liblog", + "libutils", + "libhardware", + "android.hardware.audio@2.0", + "android.hardware.audio@4.0", + "android.hardware.audio@5.0", + "android.hardware.audio.common@2.0", + "android.hardware.audio.common@4.0", + "android.hardware.audio.common@5.0", + "android.hardware.audio.effect@2.0", + "android.hardware.audio.effect@4.0", + "android.hardware.audio.effect@5.0", + "android.hardware.bluetooth.a2dp@1.0", + "android.hardware.bluetooth.audio@2.0", + "android.hardware.soundtrigger@2.0", + "android.hardware.soundtrigger@2.1", + "android.hardware.soundtrigger@2.2", + ], +} + +// Legacy service name, use android.hardware.audio.service instead +phony { + name: "android.hardware.audio@2.0-service", + required: ["android.hardware.audio.service"], +} diff --git a/audio/common/all-versions/default/service/Android.mk b/audio/common/all-versions/default/service/Android.mk deleted file mode 100644 index 236f1fd3d6..0000000000 --- a/audio/common/all-versions/default/service/Android.mk +++ /dev/null @@ -1,63 +0,0 @@ -# -# Copyright (C) 2016 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. - - -LOCAL_PATH := $(call my-dir) - -# -# Service -# - -include $(CLEAR_VARS) -LOCAL_MODULE := android.hardware.audio@2.0-service -LOCAL_INIT_RC := android.hardware.audio@2.0-service.rc -LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_PROPRIETARY_MODULE := true -LOCAL_SRC_FILES := \ - service.cpp - -LOCAL_CFLAGS := -Wall -Werror - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libbinder \ - libhidlbase \ - liblog \ - libutils \ - libhardware \ - android.hardware.audio@2.0 \ - android.hardware.audio@4.0 \ - android.hardware.audio@5.0 \ - android.hardware.audio.common@2.0 \ - android.hardware.audio.common@4.0 \ - android.hardware.audio.common@5.0 \ - android.hardware.audio.effect@2.0 \ - android.hardware.audio.effect@4.0 \ - android.hardware.audio.effect@5.0 \ - android.hardware.bluetooth.a2dp@1.0 \ - android.hardware.bluetooth.audio@2.0 \ - android.hardware.soundtrigger@2.0 \ - android.hardware.soundtrigger@2.1 \ - android.hardware.soundtrigger@2.2 - -# Can not switch to Android.bp until AUDIOSERVER_MULTILIB -# is deprecated as build config variable are not supported -ifeq ($(strip $(AUDIOSERVER_MULTILIB)),) -LOCAL_MULTILIB := 32 -else -LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB) -endif - -include $(BUILD_EXECUTABLE) diff --git a/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc b/audio/common/all-versions/default/service/android.hardware.audio.service.rc similarity index 81% rename from audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc rename to audio/common/all-versions/default/service/android.hardware.audio.service.rc index 72b4d197dd..63d2542498 100644 --- a/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc +++ b/audio/common/all-versions/default/service/android.hardware.audio.service.rc @@ -1,4 +1,4 @@ -service vendor.audio-hal-2-0 /vendor/bin/hw/android.hardware.audio@2.0-service +service vendor.audio-hal /vendor/bin/hw/android.hardware.audio.service class hal user audioserver # media gid needed for /dev/fm (radio) and for /data/misc/media (tee) From c69e3e997f75ab6c485c4bbc934156e1bc9ef2a5 Mon Sep 17 00:00:00 2001 From: Kevin Rocard Date: Tue, 18 Jun 2019 15:39:17 -0700 Subject: [PATCH 0149/1022] Change some formatting for better script parsing Test: Compile Bug: 134940862 Change-Id: Ibbafdcaa6e0bfa8fd2b80f4a6c9ac6ac95058f93 Signed-off-by: Kevin Rocard --- audio/common/all-versions/default/Android.bp | 3 --- .../all-versions/default/service/service.cpp | 20 +++++++++++-------- audio/core/all-versions/default/Android.bp | 5 ----- audio/effect/all-versions/default/Android.bp | 3 --- 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/audio/common/all-versions/default/Android.bp b/audio/common/all-versions/default/Android.bp index c0bd34c45f..e630d93b80 100644 --- a/audio/common/all-versions/default/Android.bp +++ b/audio/common/all-versions/default/Android.bp @@ -69,7 +69,6 @@ cc_defaults { cc_library_shared { name: "android.hardware.audio.common@2.0-util", defaults: ["android.hardware.audio.common-util_default"], - shared_libs: [ "android.hardware.audio.common@2.0", ], @@ -83,7 +82,6 @@ cc_library_shared { cc_library_shared { name: "android.hardware.audio.common@4.0-util", defaults: ["android.hardware.audio.common-util_default"], - shared_libs: [ "android.hardware.audio.common@4.0", ], @@ -97,7 +95,6 @@ cc_library_shared { cc_library_shared { name: "android.hardware.audio.common@5.0-util", defaults: ["android.hardware.audio.common-util_default"], - shared_libs: [ "android.hardware.audio.common@5.0", ], diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp index 2a6571b9e3..e8a9e23f02 100644 --- a/audio/common/all-versions/default/service/service.cpp +++ b/audio/common/all-versions/default/service/service.cpp @@ -59,16 +59,20 @@ int main(int /* argc */, char* /* argv */ []) { } configureRpcThreadpool(16, true /*callerWillJoin*/); - LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations()), + // Keep versions on a separate line for easier parsing + // clang-format off + LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations< + audio::V5_0::IDevicesFactory, + audio::V4_0::IDevicesFactory, + audio::V2_0::IDevicesFactory>()), "Could not register audio core API"); - LOG_ALWAYS_FATAL_IF( - (registerPassthroughServiceImplementations()), - "Could not register audio effect API"); + LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations< + audio::effect::V5_0::IEffectsFactory, + audio::effect::V4_0::IEffectsFactory, + audio::effect::V2_0::IEffectsFactory>()), + "Could not register audio effect API"); + // clang-format on ALOGW_IF((registerPassthroughServiceImplementations Date: Mon, 7 Oct 2019 12:28:18 -0700 Subject: [PATCH 0150/1022] Introduce IBootControl 1.1. libsnapshot needs to communicate to the bootloader that a merge is in progress. This can be used to prevent factory data resets, prevent flashing or wiping userdata/metadata, and warning when the active slot changes. Bug: 138861550 Test: builds Change-Id: I577877696b5ec6920b9520d518374931ce9ddfaa --- boot/1.1/Android.bp | 18 +++++ boot/1.1/IBootControl.hal | 66 +++++++++++++++++++ boot/1.1/types.hal | 44 +++++++++++++ .../compatibility_matrix.current.xml | 2 +- current.txt | 2 + 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 boot/1.1/Android.bp create mode 100644 boot/1.1/IBootControl.hal create mode 100644 boot/1.1/types.hal diff --git a/boot/1.1/Android.bp b/boot/1.1/Android.bp new file mode 100644 index 0000000000..6a8d57aa8c --- /dev/null +++ b/boot/1.1/Android.bp @@ -0,0 +1,18 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.boot@1.1", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IBootControl.hal", + ], + interfaces: [ + "android.hardware.boot@1.0", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/boot/1.1/IBootControl.hal b/boot/1.1/IBootControl.hal new file mode 100644 index 0000000000..939dfb3d74 --- /dev/null +++ b/boot/1.1/IBootControl.hal @@ -0,0 +1,66 @@ +/* + * Copyright 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. + */ + +package android.hardware.boot@1.1; + +import @1.0::IBootControl; + +interface IBootControl extends @1.0::IBootControl { + /** + * Sets whether a snapshot-merge of any dynamic partition is in progress. + * + * After the merge status is set to a given value, subsequent calls to + * getSnapshotMergeStatus must return the set value. + * + * The merge status must be persistent across reboots. That is, getSnapshotMergeStatus + * must return the same value after a reboot if the merge status is not altered in any way + * (e.g. set by setSnapshotMergeStatus or set to CANCELLED by bootloader). + * + * Read/write access to the merge status must be atomic. When the HAL is processing a + * setSnapshotMergeStatus call, all subsequent calls to getSnapshotMergeStatus must block until + * setSnapshotMergeStatus has returned. + * + * A MERGING state indicates that dynamic partitions are partially comprised by blocks in the + * userdata partition. + * + * When the merge status is set to MERGING, the following operations must be prohibited from the + * bootloader: + * - Flashing or erasing "userdata" or "metadata". + * + * The following operations may be prohibited when the status is set to MERGING. If not + * prohibited, it is recommended that the user receive a warning. + * - Changing the active slot (e.g. via "fastboot set_active") + * + * @param status Merge status. + * + * @return success True on success, false otherwise. + */ + setSnapshotMergeStatus(MergeStatus status) generates (bool success); + + /** + * Returns whether a snapshot-merge of any dynamic partition is in progress. + * + * This function must return the merge status set by the last setSnapshotMergeStatus call and + * recorded by the bootloader with one exception. If the partitions are being flashed from the + * bootloader such that the pending merge must be canceled (for example, if the super partition + * is being flashed), this function must return CANCELLED. + * + * @return success True if the merge status is read successfully, false otherwise. + * @return status Merge status. + */ + getSnapshotMergeStatus() generates (MergeStatus status); +}; + diff --git a/boot/1.1/types.hal b/boot/1.1/types.hal new file mode 100644 index 0000000000..6346078c81 --- /dev/null +++ b/boot/1.1/types.hal @@ -0,0 +1,44 @@ +/* + * Copyright 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. + */ + +package android.hardware.boot@1.1; + +enum MergeStatus : int32_t { + /** + * No snapshot or merge is in progress. + */ + NONE = 0, + + /** + * The merge status could not be determined. + */ + UNKNOWN, + + /** + * Partitions are being snapshotted, but no merge has been started. + */ + SNAPSHOTTED, + + /** + * At least one partition has merge is in progress. + */ + MERGING, + + /** + * A merge was in progress, but it was canceled by the bootloader. + */ + CANCELLED, +}; diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 409c5a289e..a40965098c 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -89,7 +89,7 @@ android.hardware.boot - 1.0 + 1.1 IBootControl default diff --git a/current.txt b/current.txt index e164a3fb5b..8f4c1815b4 100644 --- a/current.txt +++ b/current.txt @@ -585,6 +585,8 @@ a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardwar fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface # HALs released in Android R +07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl +74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types 34515afa2bb792d3c6d8495a5f5d907d179c8507ca5e55c10050d02ae1d516ef android.hardware.neuralnetworks@1.3::IDevice e2d20d4eb24f40b44a3766d05f77052581cb3f4df35fb48c0cc5d9cdcf5c872e android.hardware.neuralnetworks@1.3::types 04395b26be33db17747c3d3b0e8066d323f891ff4f9f3b3ddb490b2f3f844a18 android.hardware.wifi@1.4::IWifi From 5bc18d65382022fd24d807ce5a6c903443a524f7 Mon Sep 17 00:00:00 2001 From: Kevin Rocard Date: Tue, 18 Jun 2019 15:39:17 -0700 Subject: [PATCH 0151/1022] Script to generate new audio HAL version Mostly automated script to generate a new Audio HAL major version. Test: push V6 to device and check audio works fine Bug: 134940862 Change-Id: I0da621e747eb48e75901a2a10cfc224f33864c3b Signed-off-by: Kevin Rocard --- audio/common/all-versions/copyHAL.sh | 204 +++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100755 audio/common/all-versions/copyHAL.sh diff --git a/audio/common/all-versions/copyHAL.sh b/audio/common/all-versions/copyHAL.sh new file mode 100755 index 0000000000..d07012fe04 --- /dev/null +++ b/audio/common/all-versions/copyHAL.sh @@ -0,0 +1,204 @@ +#/usr/bin/env bash + +set -euo pipefail + +if (echo "$@" |grep -qe -h); then + echo "This script will generate a new HAL version identical to an other one." + echo "This helps creating the boilerplate for a new version." + echo + echo "USAGE: $0 [BASE_VERSION] [NEW_VERSION]" + echo " BASE_VERSION default value is the highest version currently existing" + echo " NEW_VERSION default value is BASE_VERSION + 1" + echo + echo "Example: to generate a V6.0 by copying V5, do: $0 5.0 6.0" + exit +fi +readonly HAL_DIRECTORY=hardware/interfaces/audio +readonly HAL_VTS_DIRECTORY=core/all-versions/vts/functional +readonly HAL_VTS_FILE=AudioPrimaryHidlHalTest.cpp +readonly HAL_SERVICE_DIRECTORY=common/all-versions/default/service/ +readonly HAL_SERVICE_CPP=service.cpp + +readonly FWK_DIRECTORY=frameworks/av/media/libaudiohal +readonly IMPL_DIRECTORY=impl +readonly IMPL_FACTORYHAL=$IMPL_DIRECTORY/include/libaudiohal/FactoryHalHidl.h + +readonly VTS_DIRECTORY=test/vts-testcase/hal/audio +readonly VTS_LIST=test/vts/tools/build/tasks/list/vts_test_lib_hidl_package_list.mk +readonly WATCHDOG=frameworks/base/services/core/java/com/android/server/Watchdog.cpp +readonly GSI_CURRENT=build/make/target/product/gsi/current.txt + +readonly BASE_VERSION=${1:-$(ls $ANDROID_BUILD_TOP/$HAL_DIRECTORY | grep -E '[0-9]+\.[0-9]+' | + sort -n |tail -n1)} +readonly BASE_MAJOR_VERSION=${BASE_VERSION%.*} +readonly BASE_MINOR_VERSION=${BASE_VERSION##*.} + +readonly NEW_VERSION="${2:-$((${BASE_MAJOR_VERSION} + 1)).0}" +readonly NEW_MAJOR_VERSION=${NEW_VERSION%.*} +readonly NEW_MINOR_VERSION=${NEW_VERSION##*.} + + +readonly BASE_VERSION_REGEX="${BASE_MAJOR_VERSION}[._]${BASE_MINOR_VERSION}" +readonly NEW_VERSION_REGEX="${NEW_MAJOR_VERSION}[._]${NEW_MINOR_VERSION}" + +readonly BASE_VERSION_ESCAPE="${BASE_MAJOR_VERSION}\.${BASE_MINOR_VERSION}" +readonly BASE_VERSION_UNDERSCORE="${BASE_MAJOR_VERSION}_${BASE_MINOR_VERSION}" +readonly NEW_VERSION_UNDERSCORE="${NEW_MAJOR_VERSION}_${NEW_MINOR_VERSION}" +updateVersion() { + if [ $1 == "-e" ]; then + local -r REGEX="$2"; shift 2 + else + local -r REGEX="$BASE_VERSION_REGEX" + fi + awk -i inplace -e "{if (!/$REGEX/) print; else { + if (original_before) print + if (original_after) original_line=\$0; + + gsub(/$BASE_VERSION_ESCAPE/,\"$NEW_VERSION\"); + gsub(/$BASE_VERSION_UNDERSCORE/,\"$NEW_VERSION_UNDERSCORE\"); + gsub(/MAJOR_VERSION=$BASE_MAJOR_VERSION/, + \"MAJOR_VERSION=$NEW_MAJOR_VERSION\"); + gsub(/MINOR_VERSION=$BASE_MINOR_VERSION/, + \"MINOR_VERSION=$NEW_MINOR_VERSION\"); + + print + if (original_after) print original_line + }}" "$@" +} + +updateAudioVersion() { + updateVersion -e "audio.*$BASE_VERSION_REGEX" "$@" +} + +updateLicenceDates() { + # Update date on the 2 first lines + sed -i "1,2 s/20[0-9][0-9]/$(date +"%Y")/g" "$@" +} + +echo "Creating new audio HAL V$NEW_VERSION based on V$BASE_VERSION" +echo "Press Ctrl-C to cancel, Enter to continue" +read + +MODIFIED= +runIfNeeded() { + local -r TARGET=$1; shift + cd $ANDROID_BUILD_TOP/$TARGET + if grep -q -r "audio.*$NEW_VERSION_REGEX"; then + echo " Skipping $TARGET as already up to date" + else + echo " Updating $PWD" + MODIFIED+=$'\n - '$TARGET + "$@" + fi +} + +createHALVersion() { + local -r DIRS=". common effect" + local COPY= + echo "Copy $BASE_VERSION to $NEW_VERSION in $DIRS" + for DIR in $DIRS; do + cp -Tar $DIR/$BASE_VERSION $DIR/$NEW_VERSION + COPY+=" $DIR/$NEW_VERSION" + done + + echo "Replacing $BASE_VERSION by $NEW_VERSION in the copied files" + updateVersion $(find $COPY -type f) + updateLicenceDates $(find $COPY -type f) + + echo "Update implementation and VTS generic code" + local -r FILES="*/all-versions/default/Android.bp */all-versions/vts/functional/Android.bp" + updateVersion -v original_before=1 -v RS= -v ORS='\n\n' $FILES + sed -i '${/^$/d}' $FILES # Remove \n at the end of the files + + updateVersion -v original_before=1 $HAL_SERVICE_DIRECTORY/Android.bp + + updateVersion -e "audio::.*$BASE_VERSION_REGEX" -v original_after=1 \ + $HAL_SERVICE_DIRECTORY/$HAL_SERVICE_CPP + updateVersion -e "audio\/.*$BASE_VERSION_REGEX" -v original_before=1 \ + $HAL_SERVICE_DIRECTORY/$HAL_SERVICE_CPP + + local -r HAL_VTS_PATH=$HAL_VTS_DIRECTORY/$NEW_VERSION/$HAL_VTS_FILE + mkdir -p $(dirname $HAL_VTS_PATH) + cat > $HAL_VTS_PATH < Date: Mon, 30 Sep 2019 19:53:00 +0100 Subject: [PATCH 0152/1022] Introduce Audio V6 Generate with ./newHal.sh 5.0 + some typo fix in the .hal + some clang-tidy run This new HAL is an exact copy of the V5. It will be modified in following patches while R is developed. Test: push V6 to device and check audio works fine Bug: 134940862 Change-Id: Ic25d30175032e76e0d3208fb876451de9ae6b7b4 Signed-off-by: Kevin Rocard --- audio/6.0/Android.bp | 27 + audio/6.0/IDevice.hal | 282 +++++ audio/6.0/IDevicesFactory.hal | 70 ++ audio/6.0/IPrimaryDevice.hal | 195 ++++ audio/6.0/IStream.hal | 310 +++++ audio/6.0/IStreamIn.hal | 199 ++++ audio/6.0/IStreamOut.hal | 279 +++++ audio/6.0/IStreamOutCallback.hal | 37 + audio/6.0/config/Android.bp | 7 + audio/6.0/config/api/current.txt | 422 +++++++ audio/6.0/config/api/last_current.txt | 0 audio/6.0/config/api/last_removed.txt | 0 audio/6.0/config/api/removed.txt | 1 + .../6.0/config/audio_policy_configuration.xsd | 624 ++++++++++ audio/6.0/types.hal | 249 ++++ audio/common/6.0/Android.bp | 17 + audio/common/6.0/types.hal | 1032 +++++++++++++++++ audio/common/all-versions/default/Android.bp | 13 + .../all-versions/default/service/Android.bp | 3 + .../all-versions/default/service/service.cpp | 4 + audio/core/all-versions/default/Android.bp | 15 + .../6.0/AudioPrimaryHidlHalTest.cpp | 18 + .../all-versions/vts/functional/Android.bp | 17 + audio/effect/6.0/Android.bp | 33 + .../6.0/IAcousticEchoCancelerEffect.hal | 32 + .../6.0/IAutomaticGainControlEffect.hal | 68 ++ audio/effect/6.0/IBassBoostEffect.hal | 48 + audio/effect/6.0/IDownmixEffect.hal | 37 + audio/effect/6.0/IEffect.hal | 418 +++++++ .../6.0/IEffectBufferProviderCallback.hal | 38 + audio/effect/6.0/IEffectsFactory.hal | 58 + .../effect/6.0/IEnvironmentalReverbEffect.hal | 178 +++ audio/effect/6.0/IEqualizerEffect.hal | 93 ++ audio/effect/6.0/ILoudnessEnhancerEffect.hal | 32 + audio/effect/6.0/INoiseSuppressionEffect.hal | 68 ++ audio/effect/6.0/IPresetReverbEffect.hal | 43 + audio/effect/6.0/IVirtualizerEffect.hal | 77 ++ audio/effect/6.0/IVisualizerEffect.hal | 110 ++ audio/effect/6.0/types.hal | 301 +++++ audio/effect/6.0/xml/Android.bp | 6 + audio/effect/6.0/xml/api/current.txt | 132 +++ audio/effect/6.0/xml/api/last_current.txt | 0 audio/effect/6.0/xml/api/last_removed.txt | 0 audio/effect/6.0/xml/api/removed.txt | 1 + audio/effect/6.0/xml/audio_effects_conf.xsd | 1 + audio/effect/all-versions/default/Android.bp | 15 + .../all-versions/vts/functional/Android.bp | 13 + 47 files changed, 5623 insertions(+) create mode 100644 audio/6.0/Android.bp create mode 100644 audio/6.0/IDevice.hal create mode 100644 audio/6.0/IDevicesFactory.hal create mode 100644 audio/6.0/IPrimaryDevice.hal create mode 100644 audio/6.0/IStream.hal create mode 100644 audio/6.0/IStreamIn.hal create mode 100644 audio/6.0/IStreamOut.hal create mode 100644 audio/6.0/IStreamOutCallback.hal create mode 100644 audio/6.0/config/Android.bp create mode 100644 audio/6.0/config/api/current.txt create mode 100644 audio/6.0/config/api/last_current.txt create mode 100644 audio/6.0/config/api/last_removed.txt create mode 100644 audio/6.0/config/api/removed.txt create mode 100644 audio/6.0/config/audio_policy_configuration.xsd create mode 100644 audio/6.0/types.hal create mode 100644 audio/common/6.0/Android.bp create mode 100644 audio/common/6.0/types.hal create mode 100644 audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp create mode 100644 audio/effect/6.0/Android.bp create mode 100644 audio/effect/6.0/IAcousticEchoCancelerEffect.hal create mode 100644 audio/effect/6.0/IAutomaticGainControlEffect.hal create mode 100644 audio/effect/6.0/IBassBoostEffect.hal create mode 100644 audio/effect/6.0/IDownmixEffect.hal create mode 100644 audio/effect/6.0/IEffect.hal create mode 100644 audio/effect/6.0/IEffectBufferProviderCallback.hal create mode 100644 audio/effect/6.0/IEffectsFactory.hal create mode 100644 audio/effect/6.0/IEnvironmentalReverbEffect.hal create mode 100644 audio/effect/6.0/IEqualizerEffect.hal create mode 100644 audio/effect/6.0/ILoudnessEnhancerEffect.hal create mode 100644 audio/effect/6.0/INoiseSuppressionEffect.hal create mode 100644 audio/effect/6.0/IPresetReverbEffect.hal create mode 100644 audio/effect/6.0/IVirtualizerEffect.hal create mode 100644 audio/effect/6.0/IVisualizerEffect.hal create mode 100644 audio/effect/6.0/types.hal create mode 100644 audio/effect/6.0/xml/Android.bp create mode 100644 audio/effect/6.0/xml/api/current.txt create mode 100644 audio/effect/6.0/xml/api/last_current.txt create mode 100644 audio/effect/6.0/xml/api/last_removed.txt create mode 100644 audio/effect/6.0/xml/api/removed.txt create mode 120000 audio/effect/6.0/xml/audio_effects_conf.xsd diff --git a/audio/6.0/Android.bp b/audio/6.0/Android.bp new file mode 100644 index 0000000000..dc6bb98a53 --- /dev/null +++ b/audio/6.0/Android.bp @@ -0,0 +1,27 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.audio@6.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IDevice.hal", + "IDevicesFactory.hal", + "IPrimaryDevice.hal", + "IStream.hal", + "IStreamIn.hal", + "IStreamOut.hal", + "IStreamOutCallback.hal", + ], + interfaces: [ + "android.hardware.audio.common@6.0", + "android.hardware.audio.effect@6.0", + "android.hidl.base@1.0", + "android.hidl.safe_union@1.0", + ], + gen_java: false, + gen_java_constants: true, +} diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal new file mode 100644 index 0000000000..42a545b0be --- /dev/null +++ b/audio/6.0/IDevice.hal @@ -0,0 +1,282 @@ +/* + * 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. + */ + +package android.hardware.audio@6.0; + +import android.hardware.audio.common@6.0; +import IStreamIn; +import IStreamOut; + +interface IDevice { + /** + * Returns whether the audio hardware interface has been initialized. + * + * @return retval OK on success, NOT_INITIALIZED on failure. + */ + initCheck() generates (Result retval); + + /** + * Sets the audio volume for all audio activities other than voice call. If + * NOT_SUPPORTED is returned, the software mixer will emulate this + * capability. + * + * @param volume 1.0f means unity, 0.0f is zero. + * @return retval operation completion status. + */ + setMasterVolume(float volume) generates (Result retval); + + /** + * Get the current master volume value for the HAL, if the HAL supports + * master volume control. For example, AudioFlinger will query this value + * from the primary audio HAL when the service starts and use the value for + * setting the initial master volume across all HALs. HALs which do not + * support this method must return NOT_SUPPORTED in 'retval'. + * + * @return retval operation completion status. + * @return volume 1.0f means unity, 0.0f is zero. + */ + getMasterVolume() generates (Result retval, float volume); + + /** + * Sets microphone muting state. + * + * @param mute whether microphone is muted. + * @return retval operation completion status. + */ + setMicMute(bool mute) generates (Result retval); + + /** + * Gets whether microphone is muted. + * + * @return retval operation completion status. + * @return mute whether microphone is muted. + */ + getMicMute() generates (Result retval, bool mute); + + /** + * Set the audio mute status for all audio activities. If the return value + * is NOT_SUPPORTED, the software mixer will emulate this capability. + * + * @param mute whether audio is muted. + * @return retval operation completion status. + */ + setMasterMute(bool mute) generates (Result retval); + + /** + * Get the current master mute status for the HAL, if the HAL supports + * master mute control. AudioFlinger will query this value from the primary + * audio HAL when the service starts and use the value for setting the + * initial master mute across all HALs. HAL must indicate that the feature + * is not supported by returning NOT_SUPPORTED status. + * + * @return retval operation completion status. + * @return mute whether audio is muted. + */ + getMasterMute() generates (Result retval, bool mute); + + /** + * Returns audio input buffer size according to parameters passed or + * INVALID_ARGUMENTS if one of the parameters is not supported. + * + * @param config audio configuration. + * @return retval operation completion status. + * @return bufferSize input buffer size in bytes. + */ + getInputBufferSize(AudioConfig config) + generates (Result retval, uint64_t bufferSize); + + /** + * This method creates and opens the audio hardware output stream. + * If the stream can not be opened with the proposed audio config, + * HAL must provide suggested values for the audio config. + * + * @param ioHandle handle assigned by AudioFlinger. + * @param device device type and (if needed) address. + * @param config stream configuration. + * @param flags additional flags. + * @param sourceMetadata Description of the audio that will be played. + May be used by implementations to configure hardware effects. + * @return retval operation completion status. + * @return outStream created output stream. + * @return suggestedConfig in case of invalid parameters, suggested config. + */ + openOutputStream( + AudioIoHandle ioHandle, + DeviceAddress device, + AudioConfig config, + bitfield flags, + SourceMetadata sourceMetadata) generates ( + Result retval, + IStreamOut outStream, + AudioConfig suggestedConfig); + + /** + * This method creates and opens the audio hardware input stream. + * If the stream can not be opened with the proposed audio config, + * HAL must provide suggested values for the audio config. + * + * @param ioHandle handle assigned by AudioFlinger. + * @param device device type and (if needed) address. + * @param config stream configuration. + * @param flags additional flags. + * @param sinkMetadata Description of the audio that is suggested by the client. + * May be used by implementations to configure processing effects. + * @return retval operation completion status. + * @return inStream in case of success, created input stream. + * @return suggestedConfig in case of invalid parameters, suggested config. + */ + openInputStream( + AudioIoHandle ioHandle, + DeviceAddress device, + AudioConfig config, + bitfield flags, + SinkMetadata sinkMetadata) generates ( + Result retval, + IStreamIn inStream, + AudioConfig suggestedConfig); + + /** + * Returns whether HAL supports audio patches. + * + * @return supports true if audio patches are supported. + */ + supportsAudioPatches() generates (bool supports); + + /** + * Creates an audio patch between several source and sink ports. The handle + * is allocated by the HAL and must be unique for this audio HAL module. + * + * @param sources patch sources. + * @param sinks patch sinks. + * @return retval operation completion status. + * @return patch created patch handle. + */ + createAudioPatch(vec sources, vec sinks) + generates (Result retval, AudioPatchHandle patch); + + /** + * Release an audio patch. + * + * @param patch patch handle. + * @return retval operation completion status. + */ + releaseAudioPatch(AudioPatchHandle patch) generates (Result retval); + + /** + * Returns the list of supported attributes for a given audio port. + * + * As input, 'port' contains the information (type, role, address etc...) + * needed by the HAL to identify the port. + * + * As output, 'resultPort' contains possible attributes (sampling rates, + * formats, channel masks, gain controllers...) for this port. + * + * @param port port identifier. + * @return retval operation completion status. + * @return resultPort port descriptor with all parameters filled up. + */ + getAudioPort(AudioPort port) + generates (Result retval, AudioPort resultPort); + + /** + * Set audio port configuration. + * + * @param config audio port configuration. + * @return retval operation completion status. + */ + setAudioPortConfig(AudioPortConfig config) generates (Result retval); + + /** + * Gets the HW synchronization source of the device. Calling this method is + * equivalent to getting AUDIO_PARAMETER_HW_AV_SYNC on the legacy HAL. + * Optional method + * + * @return retval operation completion status: OK or NOT_SUPPORTED. + * @return hwAvSync HW synchronization source + */ + getHwAvSync() generates (Result retval, AudioHwSync hwAvSync); + + /** + * Sets whether the screen is on. Calling this method is equivalent to + * setting AUDIO_PARAMETER_KEY_SCREEN_STATE on the legacy HAL. + * Optional method + * + * @param turnedOn whether the screen is turned on. + * @return retval operation completion status. + */ + setScreenState(bool turnedOn) generates (Result retval); + + /** + * Generic method for retrieving vendor-specific parameter values. + * The framework does not interpret the parameters, they are passed + * in an opaque manner between a vendor application and HAL. + * + * Multiple parameters can be retrieved at the same time. + * The implementation should return as many requested parameters + * as possible, even if one or more is not supported + * + * @param context provides more information about the request + * @param keys keys of the requested parameters + * @return retval operation completion status. + * OK must be returned if keys is empty. + * NOT_SUPPORTED must be returned if at least one key is unknown. + * @return parameters parameter key value pairs. + * Must contain the value of all requested keys if retval == OK + */ + getParameters(vec context, vec keys) + generates (Result retval, vec parameters); + + /** + * Generic method for setting vendor-specific parameter values. + * The framework does not interpret the parameters, they are passed + * in an opaque manner between a vendor application and HAL. + * + * Multiple parameters can be set at the same time though this is + * discouraged as it make failure analysis harder. + * + * If possible, a failed setParameters should not impact the platform state. + * + * @param context provides more information about the request + * @param parameters parameter key value pairs. + * @return retval operation completion status. + * All parameters must be successfully set for OK to be returned + */ + setParameters(vec context, vec parameters) + generates (Result retval); + + /** + * Returns an array with available microphones in device. + * + * @return retval INVALID_STATE if the call is not successful, + * OK otherwise. + * + * @return microphones array with microphones info + */ + getMicrophones() + generates(Result retval, vec microphones); + + /** + * Notifies the device module about the connection state of an input/output + * device attached to it. Calling this method is equivalent to setting + * AUDIO_PARAMETER_DEVICE_[DIS]CONNECT on the legacy HAL. + * + * @param address audio device specification. + * @param connected whether the device is connected. + * @return retval operation completion status. + */ + setConnectedState(DeviceAddress address, bool connected) + generates (Result retval); +}; diff --git a/audio/6.0/IDevicesFactory.hal b/audio/6.0/IDevicesFactory.hal new file mode 100644 index 0000000000..04834734f1 --- /dev/null +++ b/audio/6.0/IDevicesFactory.hal @@ -0,0 +1,70 @@ +/* + * 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. + */ + +package android.hardware.audio@6.0; + +import android.hardware.audio.common@6.0; +import IDevice; +import IPrimaryDevice; + +/** This factory allows a HAL implementation to be split in multiple independent + * devices (called module in the pre-treble API). + * Note that this division is arbitrary and implementation are free + * to only have a Primary. + * The framework will query the devices according to audio_policy_configuration.xml + * + * Each device name is arbitrary, provided by the vendor's audio_policy_configuration.xml + * and only used to identify a device in this factory. + * The framework must not interpret the name, treating it as a vendor opaque data + * with the following exception: + * - the "r_submix" device that must be present to support policyMixes (Eg: Android projected). + * Note that this Device is included by default in a build derived from AOSP. + * + * Note that on AOSP Oreo (including MR1) the "a2dp" module is not using this API + * but is loaded directly from the system partition using the legacy API + * due to limitations with the Bluetooth framework. + */ +interface IDevicesFactory { + + /** + * Opens an audio device. To close the device, it is necessary to release + * references to the returned device object. + * + * @param device device name. + * @return retval operation completion status. Returns INVALID_ARGUMENTS + * if there is no corresponding hardware module found, + * NOT_INITIALIZED if an error occurred while opening the hardware + * module. + * @return result the interface for the created device. + */ + openDevice(string device) generates (Result retval, IDevice result); + + /** + * Opens the Primary audio device that must be present. + * This function is not optional and must return successfully the primary device. + * + * This device must have the name "primary". + * + * The telephony stack uses this device to control the audio during a voice call. + * + * @return retval operation completion status. Must be SUCCESS. + * For debugging, return INVALID_ARGUMENTS if there is no corresponding + * hardware module found, NOT_INITIALIZED if an error occurred + * while opening the hardware module. + * @return result the interface for the created device. + */ + openPrimaryDevice() generates (Result retval, IPrimaryDevice result); +}; diff --git a/audio/6.0/IPrimaryDevice.hal b/audio/6.0/IPrimaryDevice.hal new file mode 100644 index 0000000000..78cfc650b4 --- /dev/null +++ b/audio/6.0/IPrimaryDevice.hal @@ -0,0 +1,195 @@ +/* + * 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. + */ + +package android.hardware.audio@6.0; + +import android.hardware.audio.common@6.0; +import IDevice; + +interface IPrimaryDevice extends IDevice { + /** + * Sets the audio volume of a voice call. + * + * @param volume 1.0f means unity, 0.0f is zero. + * @return retval operation completion status. + */ + setVoiceVolume(float volume) generates (Result retval); + + /** + * This method is used to notify the HAL about audio mode changes. + * + * @param mode new mode. + * @return retval operation completion status. + */ + setMode(AudioMode mode) generates (Result retval); + + /** + * Sets the name of the current BT SCO headset. Calling this method + * is equivalent to setting legacy "bt_headset_name" parameter. + * The BT SCO headset name must only be used for debugging purposes. + * Optional method + * + * @param name the name of the current BT SCO headset (can be empty). + * @return retval operation completion status. + */ + setBtScoHeadsetDebugName(string name) generates (Result retval); + + /** + * Gets whether BT SCO Noise Reduction and Echo Cancellation are enabled. + * Calling this method is equivalent to getting AUDIO_PARAMETER_KEY_BT_NREC + * on the legacy HAL. + * + * @return retval operation completion status. + * @return enabled whether BT SCO NR + EC are enabled. + */ + getBtScoNrecEnabled() generates (Result retval, bool enabled); + + /** + * Sets whether BT SCO Noise Reduction and Echo Cancellation are enabled. + * Calling this method is equivalent to setting AUDIO_PARAMETER_KEY_BT_NREC + * on the legacy HAL. + * Optional method + * + * @param enabled whether BT SCO NR + EC are enabled. + * @return retval operation completion status. + */ + setBtScoNrecEnabled(bool enabled) generates (Result retval); + + /** + * Gets whether BT SCO Wideband mode is enabled. Calling this method is + * equivalent to getting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL. + * + * @return retval operation completion status. + * @return enabled whether BT Wideband is enabled. + */ + getBtScoWidebandEnabled() generates (Result retval, bool enabled); + + /** + * Sets whether BT SCO Wideband mode is enabled. Calling this method is + * equivalent to setting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL. + * Optional method + * + * @param enabled whether BT Wideband is enabled. + * @return retval operation completion status. + */ + setBtScoWidebandEnabled(bool enabled) generates (Result retval); + + /** + * Gets whether BT HFP (Hands-Free Profile) is enabled. Calling this method + * is equivalent to getting "hfp_enable" parameter value on the legacy HAL. + * + * @return retval operation completion status. + * @return enabled whether BT HFP is enabled. + */ + getBtHfpEnabled() generates (Result retval, bool enabled); + + /** + * Sets whether BT HFP (Hands-Free Profile) is enabled. Calling this method + * is equivalent to setting "hfp_enable" parameter on the legacy HAL. + * Optional method + * + * @param enabled whether BT HFP is enabled. + * @return retval operation completion status. + */ + setBtHfpEnabled(bool enabled) generates (Result retval); + + /** + * Sets the sampling rate of BT HFP (Hands-Free Profile). Calling this + * method is equivalent to setting "hfp_set_sampling_rate" parameter + * on the legacy HAL. + * Optional method + * + * @param sampleRateHz sample rate in Hz. + * @return retval operation completion status. + */ + setBtHfpSampleRate(uint32_t sampleRateHz) generates (Result retval); + + /** + * Sets the current output volume Hz for BT HFP (Hands-Free Profile). + * Calling this method is equivalent to setting "hfp_volume" parameter value + * on the legacy HAL (except that legacy HAL implementations expect + * an integer value in the range from 0 to 15.) + * Optional method + * + * @param volume 1.0f means unity, 0.0f is zero. + * @return retval operation completion status. + */ + setBtHfpVolume(float volume) generates (Result retval); + + enum TtyMode : int32_t { + OFF, + VCO, + HCO, + FULL + }; + + /** + * Gets current TTY mode selection. Calling this method is equivalent to + * getting AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL. + * + * @return retval operation completion status. + * @return mode TTY mode. + */ + getTtyMode() generates (Result retval, TtyMode mode); + + /** + * Sets current TTY mode. Calling this method is equivalent to setting + * AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL. + * + * @param mode TTY mode. + * @return retval operation completion status. + */ + setTtyMode(TtyMode mode) generates (Result retval); + + /** + * Gets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is + * enabled. Calling this method is equivalent to getting + * AUDIO_PARAMETER_KEY_HAC on the legacy HAL. + * + * @return retval operation completion status. + * @return enabled whether HAC mode is enabled. + */ + getHacEnabled() generates (Result retval, bool enabled); + + /** + * Sets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is + * enabled. Calling this method is equivalent to setting + * AUDIO_PARAMETER_KEY_HAC on the legacy HAL. + * Optional method + * + * @param enabled whether HAC mode is enabled. + * @return retval operation completion status. + */ + setHacEnabled(bool enabled) generates (Result retval); + + enum Rotation : int32_t { + DEG_0, + DEG_90, + DEG_180, + DEG_270 + }; + + /** + * Updates HAL on the current rotation of the device relative to natural + * orientation. Calling this method is equivalent to setting legacy + * parameter "rotation". + * + * @param rotation rotation in degrees relative to natural device + * orientation. + * @return retval operation completion status. + */ + updateRotation(Rotation rotation) generates (Result retval); +}; diff --git a/audio/6.0/IStream.hal b/audio/6.0/IStream.hal new file mode 100644 index 0000000000..f4c91f826d --- /dev/null +++ b/audio/6.0/IStream.hal @@ -0,0 +1,310 @@ +/* + * 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. + */ + +package android.hardware.audio@6.0; + +import android.hardware.audio.common@6.0; +import android.hardware.audio.effect@6.0::IEffect; + +interface IStream { + /** + * Return the frame size (number of bytes per sample). + * + * @return frameSize frame size in bytes. + */ + getFrameSize() generates (uint64_t frameSize); + + /** + * Return the frame count of the buffer. Calling this method is equivalent + * to getting AUDIO_PARAMETER_STREAM_FRAME_COUNT on the legacy HAL. + * + * @return count frame count. + */ + getFrameCount() generates (uint64_t count); + + /** + * Return the size of input/output buffer in bytes for this stream. + * It must be a multiple of the frame size. + * + * @return buffer buffer size in bytes. + */ + getBufferSize() generates (uint64_t bufferSize); + + /** + * Return the sampling rate in Hz. + * + * @return sampleRateHz sample rate in Hz. + */ + getSampleRate() generates (uint32_t sampleRateHz); + + /** + * Return supported native sampling rates of the stream for a given format. + * A supported native sample rate is a sample rate that can be efficiently + * played by the hardware (typically without sample-rate conversions). + * + * This function is only called for dynamic profile. If called for + * non-dynamic profile is should return NOT_SUPPORTED or the same list + * as in audio_policy_configuration.xml. + * + * Calling this method is equivalent to getting + * AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES on the legacy HAL. + * + * + * @param format audio format for which the sample rates are supported. + * @return retval operation completion status. + * Must be OK if the format is supported. + * @return sampleRateHz supported sample rates. + */ + getSupportedSampleRates(AudioFormat format) + generates (Result retval, vec sampleRates); + + /** + * Sets the sampling rate of the stream. Calling this method is equivalent + * to setting AUDIO_PARAMETER_STREAM_SAMPLING_RATE on the legacy HAL. + * Optional method. If implemented, only called on a stopped stream. + * + * @param sampleRateHz sample rate in Hz. + * @return retval operation completion status. + */ + setSampleRate(uint32_t sampleRateHz) generates (Result retval); + + /** + * Return the channel mask of the stream. + * + * @return mask channel mask. + */ + getChannelMask() generates (bitfield mask); + + /** + * Return supported channel masks of the stream. Calling this method is + * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_CHANNELS on the legacy + * HAL. + * + * @param format audio format for which the channel masks are supported. + * @return retval operation completion status. + * Must be OK if the format is supported. + * @return masks supported audio masks. + */ + getSupportedChannelMasks(AudioFormat format) + generates (Result retval, vec> masks); + + /** + * Sets the channel mask of the stream. Calling this method is equivalent to + * setting AUDIO_PARAMETER_STREAM_CHANNELS on the legacy HAL. + * Optional method + * + * @param format audio format. + * @return retval operation completion status. + */ + setChannelMask(bitfield mask) generates (Result retval); + + /** + * Return the audio format of the stream. + * + * @return format audio format. + */ + getFormat() generates (AudioFormat format); + + /** + * Return supported audio formats of the stream. Calling this method is + * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_FORMATS on the legacy + * HAL. + * + * @return formats supported audio formats. + */ + getSupportedFormats() generates (vec formats); + + /** + * Sets the audio format of the stream. Calling this method is equivalent to + * setting AUDIO_PARAMETER_STREAM_FORMAT on the legacy HAL. + * Optional method + * + * @param format audio format. + * @return retval operation completion status. + */ + setFormat(AudioFormat format) generates (Result retval); + + /** + * Convenience method for retrieving several stream parameters in + * one transaction. + * + * @return sampleRateHz sample rate in Hz. + * @return mask channel mask. + * @return format audio format. + */ + getAudioProperties() generates ( + uint32_t sampleRateHz, bitfield mask, AudioFormat format); + + /** + * Applies audio effect to the stream. + * + * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of + * the effect to apply. + * @return retval operation completion status. + */ + addEffect(uint64_t effectId) generates (Result retval); + + /** + * Stops application of the effect to the stream. + * + * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of + * the effect to remove. + * @return retval operation completion status. + */ + removeEffect(uint64_t effectId) generates (Result retval); + + /** + * Put the audio hardware input/output into standby mode. + * Driver must exit from standby mode at the next I/O operation. + * + * @return retval operation completion status. + */ + standby() generates (Result retval); + + /** + * Return the set of devices which this stream is connected to. + * Optional method + * + * @return retval operation completion status: OK or NOT_SUPPORTED. + * @return device set of devices which this stream is connected to. + */ + getDevices() generates (Result retval, vec devices); + + /** + * Connects the stream to one or multiple devices. + * + * This method must only be used for HALs that do not support + * 'IDevice.createAudioPatch' method. Calling this method is + * equivalent to setting AUDIO_PARAMETER_STREAM_ROUTING preceded + * with a device address in the legacy HAL interface. + * + * @param address device to connect the stream to. + * @return retval operation completion status. + */ + setDevices(vec devices) generates (Result retval); + + /** + * Sets the HW synchronization source. Calling this method is equivalent to + * setting AUDIO_PARAMETER_STREAM_HW_AV_SYNC on the legacy HAL. + * Optional method + * + * @param hwAvSync HW synchronization source + * @return retval operation completion status. + */ + setHwAvSync(AudioHwSync hwAvSync) generates (Result retval); + + /** + * Generic method for retrieving vendor-specific parameter values. + * The framework does not interpret the parameters, they are passed + * in an opaque manner between a vendor application and HAL. + * + * Multiple parameters can be retrieved at the same time. + * The implementation should return as many requested parameters + * as possible, even if one or more is not supported + * + * @param context provides more information about the request + * @param keys keys of the requested parameters + * @return retval operation completion status. + * OK must be returned if keys is empty. + * NOT_SUPPORTED must be returned if at least one key is unknown. + * @return parameters parameter key value pairs. + * Must contain the value of all requested keys if retval == OK + */ + getParameters(vec context, vec keys) + generates (Result retval, vec parameters); + + /** + * Generic method for setting vendor-specific parameter values. + * The framework does not interpret the parameters, they are passed + * in an opaque manner between a vendor application and HAL. + * + * Multiple parameters can be set at the same time though this is + * discouraged as it make failure analysis harder. + * + * If possible, a failed setParameters should not impact the platform state. + * + * @param context provides more information about the request + * @param parameters parameter key value pairs. + * @return retval operation completion status. + * All parameters must be successfully set for OK to be returned + */ + setParameters(vec context, vec parameters) + generates (Result retval); + + /** + * Called by the framework to start a stream operating in mmap mode. + * createMmapBuffer() must be called before calling start(). + * Function only implemented by streams operating in mmap mode. + * + * @return retval OK in case the success. + * NOT_SUPPORTED on non mmap mode streams + * INVALID_STATE if called out of sequence + */ + start() generates (Result retval); + + /** + * Called by the framework to stop a stream operating in mmap mode. + * Function only implemented by streams operating in mmap mode. + * + * @return retval OK in case the success. + * NOT_SUPPORTED on non mmap mode streams + * INVALID_STATE if called out of sequence + */ + stop() generates (Result retval) ; + + /** + * Called by the framework to retrieve information on the mmap buffer used for audio + * samples transfer. + * Function only implemented by streams operating in mmap mode. + * + * @param minSizeFrames minimum buffer size requested. The actual buffer + * size returned in struct MmapBufferInfo can be larger. + * @return retval OK in case the success. + * NOT_SUPPORTED on non mmap mode streams + * NOT_INITIALIZED in case of memory allocation error + * INVALID_ARGUMENTS if the requested buffer size is too large + * INVALID_STATE if called out of sequence + * @return info a MmapBufferInfo struct containing information on the MMMAP buffer created. + */ + createMmapBuffer(int32_t minSizeFrames) + generates (Result retval, MmapBufferInfo info); + + /** + * Called by the framework to read current read/write position in the mmap buffer + * with associated time stamp. + * Function only implemented by streams operating in mmap mode. + * + * @return retval OK in case the success. + * NOT_SUPPORTED on non mmap mode streams + * INVALID_STATE if called out of sequence + * @return position a MmapPosition struct containing current HW read/write position in frames + * with associated time stamp. + */ + getMmapPosition() + generates (Result retval, MmapPosition position); + + /** + * Called by the framework to deinitialize the stream and free up + * all the currently allocated resources. It is recommended to close + * the stream on the client side as soon as it is becomes unused. + * + * @return retval OK in case the success. + * NOT_SUPPORTED if called on IStream instead of input or + * output stream interface. + * INVALID_STATE if the stream was already closed. + */ + close() generates (Result retval); +}; diff --git a/audio/6.0/IStreamIn.hal b/audio/6.0/IStreamIn.hal new file mode 100644 index 0000000000..aadc3700d5 --- /dev/null +++ b/audio/6.0/IStreamIn.hal @@ -0,0 +1,199 @@ +/* + * 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. + */ + +package android.hardware.audio@6.0; + +import android.hardware.audio.common@6.0; +import IStream; + +interface IStreamIn extends IStream { + /** + * Returns the source descriptor of the input stream. Calling this method is + * equivalent to getting AUDIO_PARAMETER_STREAM_INPUT_SOURCE on the legacy + * HAL. + * Optional method + * + * @return retval operation completion status. + * @return source audio source. + */ + getAudioSource() generates (Result retval, AudioSource source); + + /** + * Set the input gain for the audio driver. + * Optional method + * + * @param gain 1.0f is unity, 0.0f is zero. + * @result retval operation completion status. + */ + setGain(float gain) generates (Result retval); + + /** + * Commands that can be executed on the driver reader thread. + */ + enum ReadCommand : int32_t { + READ, + GET_CAPTURE_POSITION + }; + + /** + * Data structure passed to the driver for executing commands + * on the driver reader thread. + */ + struct ReadParameters { + ReadCommand command; // discriminator + union Params { + uint64_t read; // READ command, amount of bytes to read, >= 0. + // No parameters for GET_CAPTURE_POSITION. + } params; + }; + + /** + * Data structure passed back to the client via status message queue + * of 'read' operation. + * + * Possible values of 'retval' field: + * - OK, read operation was successful; + * - INVALID_ARGUMENTS, stream was not configured properly; + * - INVALID_STATE, stream is in a state that doesn't allow reads. + */ + struct ReadStatus { + Result retval; + ReadCommand replyTo; // discriminator + union Reply { + uint64_t read; // READ command, amount of bytes read, >= 0. + struct CapturePosition { // same as generated by getCapturePosition. + uint64_t frames; + uint64_t time; + } capturePosition; + } reply; + }; + + /** + * Called when the metadata of the stream's sink has been changed. + * @param sinkMetadata Description of the audio that is suggested by the clients. + */ + updateSinkMetadata(SinkMetadata sinkMetadata); + + /** + * Set up required transports for receiving audio buffers from the driver. + * + * The transport consists of three message queues: + * -- command queue is used to instruct the reader thread what operation + * to perform; + * -- data queue is used for passing audio data from the driver + * to the client; + * -- status queue is used for reporting operation status + * (e.g. amount of bytes actually read or error code). + * + * The driver operates on a dedicated thread. The client must ensure that + * the thread is given an appropriate priority and assigned to correct + * scheduler and cgroup. For this purpose, the method returns identifiers + * of the driver thread. + * + * @param frameSize the size of a single frame, in bytes. + * @param framesCount the number of frames in a buffer. + * @param threadPriority priority of the driver thread. + * @return retval OK if both message queues were created successfully. + * INVALID_STATE if the method was already called. + * INVALID_ARGUMENTS if there was a problem setting up + * the queues. + * @return commandMQ a message queue used for passing commands. + * @return dataMQ a message queue used for passing audio data in the format + * specified at the stream opening. + * @return statusMQ a message queue used for passing status from the driver + * using ReadStatus structures. + * @return threadInfo identifiers of the driver's dedicated thread. + */ + prepareForReading(uint32_t frameSize, uint32_t framesCount) + generates ( + Result retval, + fmq_sync commandMQ, + fmq_sync dataMQ, + fmq_sync statusMQ, + ThreadInfo threadInfo); + + /** + * Return the amount of input frames lost in the audio driver since the last + * call of this function. + * + * Audio driver is expected to reset the value to 0 and restart counting + * upon returning the current value by this function call. Such loss + * typically occurs when the user space process is blocked longer than the + * capacity of audio driver buffers. + * + * @return framesLost the number of input audio frames lost. + */ + getInputFramesLost() generates (uint32_t framesLost); + + /** + * Return a recent count of the number of audio frames received and the + * clock time associated with that frame count. + * + * @return retval INVALID_STATE if the device is not ready/available, + * NOT_SUPPORTED if the command is not supported, + * OK otherwise. + * @return frames the total frame count received. This must be as early in + * the capture pipeline as possible. In general, frames + * must be non-negative and must not go "backwards". + * @return time is the clock monotonic time when frames was measured. In + * general, time must be a positive quantity and must not + * go "backwards". + */ + getCapturePosition() + generates (Result retval, uint64_t frames, uint64_t time); + + /** + * Returns an array with active microphones in the stream. + * + * @return retval INVALID_STATE if the call is not successful, + * OK otherwise. + * + * @return microphones array with microphones info + */ + getActiveMicrophones() + generates(Result retval, vec microphones); + + /** + * Specifies the logical microphone (for processing). + * + * If the feature is not supported an error should be returned + * If multiple microphones are present, this should be treated as a preference + * for their combined direction. + * + * Optional method + * + * @param Direction constant + * @return retval OK if the call is successful, an error code otherwise. + */ + setMicrophoneDirection(MicrophoneDirection direction) + generates(Result retval); + + /** + * Specifies the zoom factor for the selected microphone (for processing). + * + * If the feature is not supported an error should be returned + * If multiple microphones are present, this should be treated as a preference + * for their combined field dimension. + * + * Optional method + * + * @param the desired field dimension of microphone capture. Range is from -1 (wide angle), + * though 0 (no zoom) to 1 (maximum zoom). + * + * @return retval OK if the call is not successful, an error code otherwise. + */ + setMicrophoneFieldDimension(float zoom) generates(Result retval); +}; diff --git a/audio/6.0/IStreamOut.hal b/audio/6.0/IStreamOut.hal new file mode 100644 index 0000000000..941ba61006 --- /dev/null +++ b/audio/6.0/IStreamOut.hal @@ -0,0 +1,279 @@ +/* + * 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. + */ + +package android.hardware.audio@6.0; + +import android.hardware.audio.common@6.0; +import IStream; +import IStreamOutCallback; + +interface IStreamOut extends IStream { + /** + * Return the audio hardware driver estimated latency in milliseconds. + * + * @return latencyMs latency in milliseconds. + */ + getLatency() generates (uint32_t latencyMs); + + /** + * This method is used in situations where audio mixing is done in the + * hardware. This method serves as a direct interface with hardware, + * allowing to directly set the volume as apposed to via the framework. + * This method might produce multiple PCM outputs or hardware accelerated + * codecs, such as MP3 or AAC. + * Optional method + * + * @param left left channel attenuation, 1.0f is unity, 0.0f is zero. + * @param right right channel attenuation, 1.0f is unity, 0.0f is zero. + * @return retval operation completion status. + * If a volume is outside [0,1], return INVALID_ARGUMENTS + */ + setVolume(float left, float right) generates (Result retval); + + /** + * Commands that can be executed on the driver writer thread. + */ + enum WriteCommand : int32_t { + WRITE, + GET_PRESENTATION_POSITION, + GET_LATENCY + }; + + /** + * Data structure passed back to the client via status message queue + * of 'write' operation. + * + * Possible values of 'retval' field: + * - OK, write operation was successful; + * - INVALID_ARGUMENTS, stream was not configured properly; + * - INVALID_STATE, stream is in a state that doesn't allow writes; + * - INVALID_OPERATION, retrieving presentation position isn't supported. + */ + struct WriteStatus { + Result retval; + WriteCommand replyTo; // discriminator + union Reply { + uint64_t written; // WRITE command, amount of bytes written, >= 0. + struct PresentationPosition { // same as generated by + uint64_t frames; // getPresentationPosition. + TimeSpec timeStamp; + } presentationPosition; + uint32_t latencyMs; // Same as generated by getLatency. + } reply; + }; + + /** + * Called when the metadata of the stream's source has been changed. + * @param sourceMetadata Description of the audio that is played by the clients. + */ + updateSourceMetadata(SourceMetadata sourceMetadata); + + /** + * Set up required transports for passing audio buffers to the driver. + * + * The transport consists of three message queues: + * -- command queue is used to instruct the writer thread what operation + * to perform; + * -- data queue is used for passing audio data from the client + * to the driver; + * -- status queue is used for reporting operation status + * (e.g. amount of bytes actually written or error code). + * + * The driver operates on a dedicated thread. The client must ensure that + * the thread is given an appropriate priority and assigned to correct + * scheduler and cgroup. For this purpose, the method returns identifiers + * of the driver thread. + * + * @param frameSize the size of a single frame, in bytes. + * @param framesCount the number of frames in a buffer. + * @return retval OK if both message queues were created successfully. + * INVALID_STATE if the method was already called. + * INVALID_ARGUMENTS if there was a problem setting up + * the queues. + * @return commandMQ a message queue used for passing commands. + * @return dataMQ a message queue used for passing audio data in the format + * specified at the stream opening. + * @return statusMQ a message queue used for passing status from the driver + * using WriteStatus structures. + * @return threadInfo identifiers of the driver's dedicated thread. + */ + prepareForWriting(uint32_t frameSize, uint32_t framesCount) + generates ( + Result retval, + fmq_sync commandMQ, + fmq_sync dataMQ, + fmq_sync statusMQ, + ThreadInfo threadInfo); + + /** + * Return the number of audio frames written by the audio DSP to DAC since + * the output has exited standby. + * Optional method + * + * @return retval operation completion status. + * @return dspFrames number of audio frames written. + */ + getRenderPosition() generates (Result retval, uint32_t dspFrames); + + /** + * Get the local time at which the next write to the audio driver will be + * presented. The units are microseconds, where the epoch is decided by the + * local audio HAL. + * Optional method + * + * @return retval operation completion status. + * @return timestampUs time of the next write. + */ + getNextWriteTimestamp() generates (Result retval, int64_t timestampUs); + + /** + * Set the callback interface for notifying completion of non-blocking + * write and drain. + * + * Calling this function implies that all future 'write' and 'drain' + * must be non-blocking and use the callback to signal completion. + * + * 'clearCallback' method needs to be called in order to release the local + * callback proxy on the server side and thus dereference the callback + * implementation on the client side. + * + * @return retval operation completion status. + */ + setCallback(IStreamOutCallback callback) generates (Result retval); + + /** + * Clears the callback previously set via 'setCallback' method. + * + * Warning: failure to call this method results in callback implementation + * on the client side being held until the HAL server termination. + * + * If no callback was previously set, the method should be a no-op + * and return OK. + * + * @return retval operation completion status: OK or NOT_SUPPORTED. + */ + clearCallback() generates (Result retval); + + /** + * Returns whether HAL supports pausing and resuming of streams. + * + * @return supportsPause true if pausing is supported. + * @return supportsResume true if resume is supported. + */ + supportsPauseAndResume() + generates (bool supportsPause, bool supportsResume); + + /** + * Notifies to the audio driver to stop playback however the queued buffers + * are retained by the hardware. Useful for implementing pause/resume. Empty + * implementation if not supported however must be implemented for hardware + * with non-trivial latency. In the pause state, some audio hardware may + * still be using power. Client code may consider calling 'suspend' after a + * timeout to prevent that excess power usage. + * + * Implementation of this function is mandatory for offloaded playback. + * + * @return retval operation completion status. + */ + pause() generates (Result retval); + + /** + * Notifies to the audio driver to resume playback following a pause. + * Returns error INVALID_STATE if called without matching pause. + * + * Implementation of this function is mandatory for offloaded playback. + * + * @return retval operation completion status. + */ + resume() generates (Result retval); + + /** + * Returns whether HAL supports draining of streams. + * + * @return supports true if draining is supported. + */ + supportsDrain() generates (bool supports); + + /** + * Requests notification when data buffered by the driver/hardware has been + * played. If 'setCallback' has previously been called to enable + * non-blocking mode, then 'drain' must not block, instead it must return + * quickly and completion of the drain is notified through the callback. If + * 'setCallback' has not been called, then 'drain' must block until + * completion. + * + * If 'type' is 'ALL', the drain completes when all previously written data + * has been played. + * + * If 'type' is 'EARLY_NOTIFY', the drain completes shortly before all data + * for the current track has played to allow time for the framework to + * perform a gapless track switch. + * + * Drain must return immediately on 'stop' and 'flush' calls. + * + * Implementation of this function is mandatory for offloaded playback. + * + * @param type type of drain. + * @return retval operation completion status. + */ + drain(AudioDrain type) generates (Result retval); + + /** + * Notifies to the audio driver to flush the queued data. Stream must + * already be paused before calling 'flush'. + * Optional method + * + * Implementation of this function is mandatory for offloaded playback. + * + * @return retval operation completion status. + */ + flush() generates (Result retval); + + /** + * Return a recent count of the number of audio frames presented to an + * external observer. This excludes frames which have been written but are + * still in the pipeline. The count is not reset to zero when output enters + * standby. Also returns the value of CLOCK_MONOTONIC as of this + * presentation count. The returned count is expected to be 'recent', but + * does not need to be the most recent possible value. However, the + * associated time must correspond to whatever count is returned. + * + * Example: assume that N+M frames have been presented, where M is a 'small' + * number. Then it is permissible to return N instead of N+M, and the + * timestamp must correspond to N rather than N+M. The terms 'recent' and + * 'small' are not defined. They reflect the quality of the implementation. + * + * Optional method + * + * @return retval operation completion status. + * @return frames count of presented audio frames. + * @return timeStamp associated clock time. + */ + getPresentationPosition() + generates (Result retval, uint64_t frames, TimeSpec timeStamp); + + /** + * Selects a presentation for decoding from a next generation media stream + * (as defined per ETSI TS 103 190-2) and a program within the presentation. + * Optional method + * + * @param presentationId selected audio presentation. + * @param programId refinement for the presentation. + * @return retval operation completion status. + */ + selectPresentation(int32_t presentationId, int32_t programId) + generates (Result retval); +}; diff --git a/audio/6.0/IStreamOutCallback.hal b/audio/6.0/IStreamOutCallback.hal new file mode 100644 index 0000000000..e393d9a7d5 --- /dev/null +++ b/audio/6.0/IStreamOutCallback.hal @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package android.hardware.audio@6.0; + +/** + * Asynchronous write callback interface. + */ +interface IStreamOutCallback { + /** + * Non blocking write completed. + */ + oneway onWriteReady(); + + /** + * Drain completed. + */ + oneway onDrainReady(); + + /** + * Stream hit an error. + */ + oneway onError(); +}; diff --git a/audio/6.0/config/Android.bp b/audio/6.0/config/Android.bp new file mode 100644 index 0000000000..182dfcc9b5 --- /dev/null +++ b/audio/6.0/config/Android.bp @@ -0,0 +1,7 @@ + +xsd_config { + name: "audio_policy_configuration_V6_0", + srcs: ["audio_policy_configuration.xsd"], + package_name: "audio.policy.configuration.V6_0", +} + diff --git a/audio/6.0/config/api/current.txt b/audio/6.0/config/api/current.txt new file mode 100644 index 0000000000..7aa147cbb5 --- /dev/null +++ b/audio/6.0/config/api/current.txt @@ -0,0 +1,422 @@ +// Signature format: 2.0 +package audio.policy.configuration.V6_0 { + + public class AttachedDevices { + ctor public AttachedDevices(); + method public java.util.List getItem(); + } + + public enum AudioDevice { + method public String getRawName(); + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_AMBIENT; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_AUX_DIGITAL; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BACK_MIC; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_A2DP; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_BLE; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BUILTIN_MIC; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BUS; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_COMMUNICATION; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_DEFAULT; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_ECHO_REFERENCE; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_FM_TUNER; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_HDMI; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_HDMI_ARC; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_IP; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_LINE; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_LOOPBACK; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_PROXY; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_REMOTE_SUBMIX; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_SPDIF; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_STUB; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_TELEPHONY_RX; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_TV_TUNER; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_USB_ACCESSORY; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_USB_DEVICE; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_USB_HEADSET; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_VOICE_CALL; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_WIRED_HEADSET; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_NONE; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_AUX_DIGITAL; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_AUX_LINE; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BUS; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_DEFAULT; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_EARPIECE; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_ECHO_CANCELLER; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_FM; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_HDMI; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_HDMI_ARC; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_HEARING_AID; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_IP; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_LINE; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_PROXY; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_REMOTE_SUBMIX; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_SPDIF; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_SPEAKER; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_SPEAKER_SAFE; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_STUB; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_TELEPHONY_TX; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_USB_ACCESSORY; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_USB_DEVICE; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_USB_HEADSET; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADPHONE; + enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADSET; + } + + public enum AudioFormat { + method public String getRawName(); + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADIF; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_ELD; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_ERLC; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V1; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V2; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LC; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LD; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LTP; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_MAIN; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_SCALABLE; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_SSR; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_XHE; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ELD; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ERLC; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_HE_V1; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_HE_V2; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V1; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V2; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM_LC; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LC; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LD; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LTP; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_MAIN; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_SCALABLE; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_SSR; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_XHE; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AC3; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AC4; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_ALAC; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AMR_NB; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AMR_WB; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AMR_WB_PLUS; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APE; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_HD; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_TWSP; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_CELT; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DOLBY_TRUEHD; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DSD; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DTS; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DTS_HD; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRC; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRCB; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRCNW; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRCWB; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_E_AC3; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_E_AC3_JOC; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_FLAC; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_HE_AAC_V1; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_HE_AAC_V2; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_IEC61937; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_LDAC; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_LHDC; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_LHDC_LL; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MAT_1_0; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MAT_2_0; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MAT_2_1; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MP2; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MP3; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_OPUS; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_16_BIT; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_24_BIT_PACKED; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_32_BIT; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_8_24_BIT; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_8_BIT; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_FLOAT; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_QCELP; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_SBC; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_VORBIS; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_WMA; + enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_WMA_PRO; + } + + public class AudioPolicyConfiguration { + ctor public AudioPolicyConfiguration(); + method public audio.policy.configuration.V6_0.GlobalConfiguration getGlobalConfiguration(); + method public java.util.List getModules(); + method public audio.policy.configuration.V6_0.SurroundSound getSurroundSound(); + method public audio.policy.configuration.V6_0.Version getVersion(); + method public java.util.List getVolumes(); + method public void setGlobalConfiguration(audio.policy.configuration.V6_0.GlobalConfiguration); + method public void setSurroundSound(audio.policy.configuration.V6_0.SurroundSound); + method public void setVersion(audio.policy.configuration.V6_0.Version); + } + + public enum AudioUsage { + method public String getRawName(); + enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ALARM; + enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY; + enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE; + enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANCE_SONIFICATION; + enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANT; + enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_GAME; + enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_MEDIA; + enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_NOTIFICATION; + enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE; + enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_UNKNOWN; + enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_VIRTUAL_SOURCE; + enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION; + enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING; + } + + public enum DeviceCategory { + method public String getRawName(); + enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_EARPIECE; + enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_EXT_MEDIA; + enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_HEADSET; + enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_HEARING_AID; + enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_SPEAKER; + } + + public class DevicePorts { + ctor public DevicePorts(); + method public java.util.List getDevicePort(); + } + + public static class DevicePorts.DevicePort { + ctor public DevicePorts.DevicePort(); + method public String getAddress(); + method public java.util.List getEncodedFormats(); + method public audio.policy.configuration.V6_0.Gains getGains(); + method public java.util.List getProfile(); + method public audio.policy.configuration.V6_0.Role getRole(); + method public String getTagName(); + method public String getType(); + method public boolean get_default(); + method public void setAddress(String); + method public void setEncodedFormats(java.util.List); + method public void setGains(audio.policy.configuration.V6_0.Gains); + method public void setRole(audio.policy.configuration.V6_0.Role); + method public void setTagName(String); + method public void setType(String); + method public void set_default(boolean); + } + + public enum GainMode { + method public String getRawName(); + enum_constant public static final audio.policy.configuration.V6_0.GainMode AUDIO_GAIN_MODE_CHANNELS; + enum_constant public static final audio.policy.configuration.V6_0.GainMode AUDIO_GAIN_MODE_JOINT; + enum_constant public static final audio.policy.configuration.V6_0.GainMode AUDIO_GAIN_MODE_RAMP; + } + + public class Gains { + ctor public Gains(); + method public java.util.List getGain(); + } + + public static class Gains.Gain { + ctor public Gains.Gain(); + method public String getChannel_mask(); + method public int getDefaultValueMB(); + method public int getMaxRampMs(); + method public int getMaxValueMB(); + method public int getMinRampMs(); + method public int getMinValueMB(); + method public audio.policy.configuration.V6_0.GainMode getMode(); + method public String getName(); + method public int getStepValueMB(); + method public void setChannel_mask(String); + method public void setDefaultValueMB(int); + method public void setMaxRampMs(int); + method public void setMaxValueMB(int); + method public void setMinRampMs(int); + method public void setMinValueMB(int); + method public void setMode(audio.policy.configuration.V6_0.GainMode); + method public void setName(String); + method public void setStepValueMB(int); + } + + public class GlobalConfiguration { + ctor public GlobalConfiguration(); + method public boolean getSpeaker_drc_enabled(); + method public void setSpeaker_drc_enabled(boolean); + } + + public enum HalVersion { + method public String getRawName(); + enum_constant public static final audio.policy.configuration.V6_0.HalVersion _2_0; + enum_constant public static final audio.policy.configuration.V6_0.HalVersion _3_0; + } + + public class MixPorts { + ctor public MixPorts(); + method public java.util.List getMixPort(); + } + + public static class MixPorts.MixPort { + ctor public MixPorts.MixPort(); + method public String getFlags(); + method public audio.policy.configuration.V6_0.Gains getGains(); + method public long getMaxActiveCount(); + method public long getMaxOpenCount(); + method public String getName(); + method public java.util.List getPreferredUsage(); + method public java.util.List getProfile(); + method public audio.policy.configuration.V6_0.Role getRole(); + method public void setFlags(String); + method public void setGains(audio.policy.configuration.V6_0.Gains); + method public void setMaxActiveCount(long); + method public void setMaxOpenCount(long); + method public void setName(String); + method public void setPreferredUsage(java.util.List); + method public void setRole(audio.policy.configuration.V6_0.Role); + } + + public enum MixType { + method public String getRawName(); + enum_constant public static final audio.policy.configuration.V6_0.MixType mix; + enum_constant public static final audio.policy.configuration.V6_0.MixType mux; + } + + public class Modules { + ctor public Modules(); + method public java.util.List getModule(); + } + + public static class Modules.Module { + ctor public Modules.Module(); + method public audio.policy.configuration.V6_0.AttachedDevices getAttachedDevices(); + method public String getDefaultOutputDevice(); + method public audio.policy.configuration.V6_0.DevicePorts getDevicePorts(); + method public audio.policy.configuration.V6_0.HalVersion getHalVersion(); + method public audio.policy.configuration.V6_0.MixPorts getMixPorts(); + method public String getName(); + method public audio.policy.configuration.V6_0.Routes getRoutes(); + method public void setAttachedDevices(audio.policy.configuration.V6_0.AttachedDevices); + method public void setDefaultOutputDevice(String); + method public void setDevicePorts(audio.policy.configuration.V6_0.DevicePorts); + method public void setHalVersion(audio.policy.configuration.V6_0.HalVersion); + method public void setMixPorts(audio.policy.configuration.V6_0.MixPorts); + method public void setName(String); + method public void setRoutes(audio.policy.configuration.V6_0.Routes); + } + + public class Profile { + ctor public Profile(); + method public String getChannelMasks(); + method public String getFormat(); + method public String getName(); + method public String getSamplingRates(); + method public void setChannelMasks(String); + method public void setFormat(String); + method public void setName(String); + method public void setSamplingRates(String); + } + + public class Reference { + ctor public Reference(); + method public String getName(); + method public java.util.List getPoint(); + method public void setName(String); + } + + public enum Role { + method public String getRawName(); + enum_constant public static final audio.policy.configuration.V6_0.Role sink; + enum_constant public static final audio.policy.configuration.V6_0.Role source; + } + + public class Routes { + ctor public Routes(); + method public java.util.List getRoute(); + } + + public static class Routes.Route { + ctor public Routes.Route(); + method public String getSink(); + method public String getSources(); + method public audio.policy.configuration.V6_0.MixType getType(); + method public void setSink(String); + method public void setSources(String); + method public void setType(audio.policy.configuration.V6_0.MixType); + } + + public enum Stream { + method public String getRawName(); + enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ACCESSIBILITY; + enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ALARM; + enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_BLUETOOTH_SCO; + enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_DTMF; + enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ENFORCED_AUDIBLE; + enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_MUSIC; + enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_NOTIFICATION; + enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_PATCH; + enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_REROUTING; + enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_RING; + enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_SYSTEM; + enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_TTS; + enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_VOICE_CALL; + } + + public class SurroundFormats { + ctor public SurroundFormats(); + method public java.util.List getFormat(); + } + + public static class SurroundFormats.Format { + ctor public SurroundFormats.Format(); + method public audio.policy.configuration.V6_0.AudioFormat getName(); + method public java.util.List getSubformats(); + method public void setName(audio.policy.configuration.V6_0.AudioFormat); + method public void setSubformats(java.util.List); + } + + public class SurroundSound { + ctor public SurroundSound(); + method public audio.policy.configuration.V6_0.SurroundFormats getFormats(); + method public void setFormats(audio.policy.configuration.V6_0.SurroundFormats); + } + + public enum Version { + method public String getRawName(); + enum_constant public static final audio.policy.configuration.V6_0.Version _1_0; + } + + public class Volume { + ctor public Volume(); + method public audio.policy.configuration.V6_0.DeviceCategory getDeviceCategory(); + method public java.util.List getPoint(); + method public String getRef(); + method public audio.policy.configuration.V6_0.Stream getStream(); + method public void setDeviceCategory(audio.policy.configuration.V6_0.DeviceCategory); + method public void setRef(String); + method public void setStream(audio.policy.configuration.V6_0.Stream); + } + + public class Volumes { + ctor public Volumes(); + method public java.util.List getReference(); + method public java.util.List getVolume(); + } + + public class XmlParser { + ctor public XmlParser(); + method public static audio.policy.configuration.V6_0.AudioPolicyConfiguration read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + } + +} + diff --git a/audio/6.0/config/api/last_current.txt b/audio/6.0/config/api/last_current.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/audio/6.0/config/api/last_removed.txt b/audio/6.0/config/api/last_removed.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/audio/6.0/config/api/removed.txt b/audio/6.0/config/api/removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/audio/6.0/config/api/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/audio/6.0/config/audio_policy_configuration.xsd b/audio/6.0/config/audio_policy_configuration.xsd new file mode 100644 index 0000000000..0dc89bb1a7 --- /dev/null +++ b/audio/6.0/config/audio_policy_configuration.xsd @@ -0,0 +1,624 @@ + + + + + + + + + + + + + + Version of the interface the hal implements. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + There should be one section per audio HW module present on the platform. + Each contains two mandatory tags: “halVersion” and “name”. + The module "name" is the same as in previous .conf file. + Each module must contain the following sections: + - : a list of device descriptors for all + input and output devices accessible via this module. + This contains both permanently attached devices and removable devices. + - : listing all output and input streams exposed by the audio HAL + - : list of possible connections between input + and output devices or between stream and devices. + A is defined by a set of 3 attributes: + -"type": mux|mix means all sources are mutual exclusive (mux) or can be mixed (mix) + -"sink": the sink involved in this route + -"sources": all the sources than can be connected to the sink via this route + - : permanently attached devices. + The attachedDevices section is a list of devices names. + Their names correspond to device names defined in "devicePorts" section. + - is the device to be used when no policy rule applies + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "|" separated list of audio_output_flags_t or audio_input_flags_t. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + When choosing the mixPort of an audio track, the audioPolicy + first considers the mixPorts with a preferredUsage including + the track AudioUsage preferred . + If non support the track format, the other mixPorts are considered. + Eg: a will receive + the audio of all apps playing with a MEDIA usage. + It may receive audio from ALARM if there are no audio compatible + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Comma (",") separated list of channel flags + from audio_channel_mask_t. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The default device will be used if multiple have the same type + and no explicit route request exists for a specific device of + that type. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + List all available sources for a given sink. + + + + + + + + + + + + + + + + + + + + + + Comma separated pair of number. + The fist one is the framework level (between 0 and 100). + The second one is the volume to send to the HAL. + The framework will interpolate volumes not specified. + Their MUST be at least 2 points specified. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Volume section defines a volume curve for a given use case and device category. + It contains a list of points of this curve expressing the attenuation in Millibels + for a given volume index from 0 to 100. + + 0,-9600 + 100,0 + + + It may also reference a reference/@name to avoid duplicating curves. + + + 0,-9600 + 100,0 + + + + + + + + + + + + + + + + + + + + Surround Sound section provides configuration related to handling of + multi-channel formats. + + + + + + + + + + + + + + + + + + + + diff --git a/audio/6.0/types.hal b/audio/6.0/types.hal new file mode 100644 index 0000000000..1a704f8b32 --- /dev/null +++ b/audio/6.0/types.hal @@ -0,0 +1,249 @@ +/* + * 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. + */ + +package android.hardware.audio@6.0; + +import android.hardware.audio.common@6.0; + +enum Result : int32_t { + OK, + NOT_INITIALIZED, + INVALID_ARGUMENTS, + INVALID_STATE, + /** + * Methods marked as "Optional method" must return this result value + * if the operation is not supported by HAL. + */ + NOT_SUPPORTED +}; + +@export(name="audio_drain_type_t", value_prefix="AUDIO_DRAIN_") +enum AudioDrain : int32_t { + /** drain() returns when all data has been played. */ + ALL, + /** + * drain() returns a short time before all data from the current track has + * been played to give time for gapless track switch. + */ + EARLY_NOTIFY +}; + +/** + * A substitute for POSIX timespec. + */ +struct TimeSpec { + uint64_t tvSec; // seconds + uint64_t tvNSec; // nanoseconds +}; + +struct ParameterValue { + string key; + string value; +}; + +enum MmapBufferFlag : uint32_t { + NONE = 0x0, + /** + * If the buffer can be securely shared to untrusted applications + * through the AAudio exclusive mode. + * Only set this flag if applications are restricted from accessing the + * memory surrounding the audio data buffer by a kernel mechanism. + * See Linux kernel's dma_buf. + */ + APPLICATION_SHAREABLE = 0x1, +}; + +/** + * Mmap buffer descriptor returned by IStream.createMmapBuffer(). + * Used by streams opened in mmap mode. + */ +struct MmapBufferInfo { + /** Mmap memory buffer */ + memory sharedMemory; + /** Total buffer size in frames */ + uint32_t bufferSizeFrames; + /** Transfer size granularity in frames */ + uint32_t burstSizeFrames; + /** Attributes describing the buffer. */ + bitfield flags; +}; + +/** + * Mmap buffer read/write position returned by IStream.getMmapPosition(). + * Used by streams opened in mmap mode. + */ +struct MmapPosition { + int64_t timeNanoseconds; // time stamp in ns, CLOCK_MONOTONIC + int32_t positionFrames; // increasing 32 bit frame count reset when IStream.stop() is called +}; + +/** + * The message queue flags used to synchronize reads and writes from + * message queues used by StreamIn and StreamOut. + */ +enum MessageQueueFlagBits : uint32_t { + NOT_EMPTY = 1 << 0, + NOT_FULL = 1 << 1 +}; + +/* + * Microphone information + * + */ + +/** + * A 3D point used to represent position or orientation of a microphone. + * + * Position: Coordinates of the microphone's capsule, in meters, from the + * bottom-left-back corner of the bounding box of android device in natural + * orientation (PORTRAIT for phones, LANDSCAPE for tablets, tvs, etc). + * The orientation musth match the reported by the api Display.getRotation(). + * + * Orientation: Normalized vector to signal the main orientation of the + * microphone's capsule. Magnitude = sqrt(x^2 + y^2 + z^2) = 1 + */ +struct AudioMicrophoneCoordinate { + float x; + float y; + float z; +}; + +/** + * Enum to identify the type of channel mapping for active microphones. + * Used channels further identify if the microphone has any significative + * process (e.g. High Pass Filtering, dynamic compression) + * Simple processing as constant gain adjustment must be DIRECT. + */ +enum AudioMicrophoneChannelMapping : uint32_t { + UNUSED = 0, /* Channel not used */ + DIRECT = 1, /* Channel used and signal not processed */ + PROCESSED = 2, /* Channel used and signal has some process */ +}; + +/** + * Enum to identify locations of microphones in regards to the body of the + * android device. + */ +enum AudioMicrophoneLocation : uint32_t { + UNKNOWN = 0, + MAINBODY = 1, + MAINBODY_MOVABLE = 2, + PERIPHERAL = 3, +}; + +/** + * Identifier to help group related microphones together + * e.g. microphone arrays should belong to the same group + */ +typedef int32_t AudioMicrophoneGroup; + +/** + * Enum with standard polar patterns of microphones + */ +enum AudioMicrophoneDirectionality : uint32_t { + UNKNOWN = 0, + OMNI = 1, + BI_DIRECTIONAL = 2, + CARDIOID = 3, + HYPER_CARDIOID = 4, + SUPER_CARDIOID = 5, +}; + +/** + * A (frequency, level) pair. Used to represent frequency response. + */ +struct AudioFrequencyResponsePoint { + /** In Hz */ + float frequency; + /** In dB */ + float level; +}; + +/** + * Structure used by the HAL to describe microphone's characteristics + * Used by StreamIn and Device + */ +struct MicrophoneInfo { + /** Unique alphanumeric id for microphone. Guaranteed to be the same + * even after rebooting. + */ + string deviceId; + /** + * Device specific information + */ + DeviceAddress deviceAddress; + /** Each element of the vector must describe the channel with the same + * index. + */ + vec channelMapping; + /** Location of the microphone in regard to the body of the device */ + AudioMicrophoneLocation location; + /** Identifier to help group related microphones together + * e.g. microphone arrays should belong to the same group + */ + AudioMicrophoneGroup group; + /** Index of this microphone within the group. + * (group, index) must be unique within the same device. + */ + uint32_t indexInTheGroup; + /** Level in dBFS produced by a 1000 Hz tone at 94 dB SPL */ + float sensitivity; + /** Level in dB of the max SPL supported at 1000 Hz */ + float maxSpl; + /** Level in dB of the min SPL supported at 1000 Hz */ + float minSpl; + /** Standard polar pattern of the microphone */ + AudioMicrophoneDirectionality directionality; + /** Vector with ordered frequency responses (from low to high frequencies) + * with the frequency response of the microphone. + * Levels are in dB, relative to level at 1000 Hz + */ + vec frequencyResponse; + /** Position of the microphone's capsule in meters, from the + * bottom-left-back corner of the bounding box of device. + */ + AudioMicrophoneCoordinate position; + /** Normalized point to signal the main orientation of the microphone's + * capsule. sqrt(x^2 + y^2 + z^2) = 1 + */ + AudioMicrophoneCoordinate orientation; +}; + +/** + * Constants used by the HAL to determine how to select microphones and process those inputs in + * order to optimize for capture in the specified direction. + * + * MicrophoneDirection Constants are defined in MicrophoneDirection.java. + */ +@export(name="audio_microphone_direction_t", value_prefix="MIC_DIRECTION_") +enum MicrophoneDirection : int32_t { + /** + * Don't do any directionality processing of the activated microphone(s). + */ + UNSPECIFIED = 0, + /** + * Optimize capture for audio coming from the screen-side of the device. + */ + FRONT = 1, + /** + * Optimize capture for audio coming from the side of the device opposite the screen. + */ + BACK = 2, + /** + * Optimize capture for audio coming from an off-device microphone. + */ + EXTERNAL = 3, +}; diff --git a/audio/common/6.0/Android.bp b/audio/common/6.0/Android.bp new file mode 100644 index 0000000000..1a4e0548ea --- /dev/null +++ b/audio/common/6.0/Android.bp @@ -0,0 +1,17 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.audio.common@6.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + ], + interfaces: [ + "android.hidl.safe_union@1.0", + ], + gen_java: false, + gen_java_constants: true, +} diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal new file mode 100644 index 0000000000..132f86dc4e --- /dev/null +++ b/audio/common/6.0/types.hal @@ -0,0 +1,1032 @@ +/* + * 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. + */ + +package android.hardware.audio.common@6.0; + +import android.hidl.safe_union@1.0; + +/* + * + * IDs and Handles + * + */ + +/** + * Handle type for identifying audio sources and sinks. + */ +typedef int32_t AudioIoHandle; + +/** + * Audio hw module handle functions or structures referencing a module. + */ +typedef int32_t AudioModuleHandle; + +/** + * Each port has a unique ID or handle allocated by policy manager. + */ +typedef int32_t AudioPortHandle; + +/** + * Each patch is identified by a handle at the interface used to create that + * patch. For instance, when a patch is created by the audio HAL, the HAL + * allocates and returns a handle. This handle is unique to a given audio HAL + * hardware module. But the same patch receives another system wide unique + * handle allocated by the framework. This unique handle is used for all + * transactions inside the framework. + */ +typedef int32_t AudioPatchHandle; + +/** + * A HW synchronization source returned by the audio HAL. + */ +typedef uint32_t AudioHwSync; + +/** + * Each port has a unique ID or handle allocated by policy manager. + */ +@export(name="") +enum AudioHandleConsts : int32_t { + AUDIO_IO_HANDLE_NONE = 0, + AUDIO_MODULE_HANDLE_NONE = 0, + AUDIO_PORT_HANDLE_NONE = 0, + AUDIO_PATCH_HANDLE_NONE = 0, +}; + +/** + * Commonly used structure for passing unique identifieds (UUID). + * For the definition of UUID, refer to ITU-T X.667 spec. + */ +struct Uuid { + uint32_t timeLow; + uint16_t timeMid; + uint16_t versionAndTimeHigh; + uint16_t variantAndClockSeqHigh; + uint8_t[6] node; +}; + + +/* + * + * Audio streams + * + */ + +/** + * Audio stream type describing the intended use case of a stream. + */ +@export(name="audio_stream_type_t", value_prefix="AUDIO_STREAM_") +enum AudioStreamType : int32_t { + // These values must kept in sync with + // frameworks/base/media/java/android/media/AudioSystem.java + DEFAULT = -1, + MIN = 0, + VOICE_CALL = 0, + SYSTEM = 1, + RING = 2, + MUSIC = 3, + ALARM = 4, + NOTIFICATION = 5, + BLUETOOTH_SCO = 6, + ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be + // routed to speaker + DTMF = 8, + TTS = 9, // Transmitted Through Speaker. Plays over speaker + // only, silent on other devices + ACCESSIBILITY = 10, // For accessibility talk back prompts +}; + +@export(name="audio_source_t", value_prefix="AUDIO_SOURCE_") +enum AudioSource : int32_t { + // These values must kept in sync with + // frameworks/base/media/java/android/media/MediaRecorder.java, + // frameworks/av/services/audiopolicy/AudioPolicyService.cpp, + // system/media/audio_effects/include/audio_effects/audio_effects_conf.h + DEFAULT = 0, + MIC = 1, + VOICE_UPLINK = 2, + VOICE_DOWNLINK = 3, + VOICE_CALL = 4, + CAMCORDER = 5, + VOICE_RECOGNITION = 6, + VOICE_COMMUNICATION = 7, + /** + * Source for the mix to be presented remotely. An example of remote + * presentation is Wifi Display where a dongle attached to a TV can be used + * to play the mix captured by this audio source. + */ + REMOTE_SUBMIX = 8, + /** + * Source for unprocessed sound. Usage examples include level measurement + * and raw signal analysis. + */ + UNPROCESSED = 9, + /** + * Source for capturing audio meant to be processed in real time and played back for live + * performance (e.g karaoke). The capture path will minimize latency and coupling with + * playback path. + */ + VOICE_PERFORMANCE = 10, + /** + * Source for an echo canceller to capture the reference signal to be cancelled. + * The echo reference signal will be captured as close as possible to the DAC in order + * to include all post processing applied to the playback path. + */ + ECHO_REFERENCE = 1997, + FM_TUNER = 1998, + HOTWORD = 1999, +}; + +typedef int32_t AudioSession; +/** + * Special audio session values. + */ +@export(name="audio_session_t", value_prefix="AUDIO_SESSION_") +enum AudioSessionConsts : int32_t { + /** + * Session for effects attached to a particular output stream + * (value must be less than 0) + */ + OUTPUT_STAGE = -1, + /** + * Session for effects applied to output mix. These effects can + * be moved by audio policy manager to another output stream + * (value must be 0) + */ + OUTPUT_MIX = 0, + /** + * Application does not specify an explicit session ID to be used, and + * requests a new session ID to be allocated. Corresponds to + * AudioManager.AUDIO_SESSION_ID_GENERATE and + * AudioSystem.AUDIO_SESSION_ALLOCATE. + */ + ALLOCATE = 0, + /** + * For use with AudioRecord::start(), this indicates no trigger session. + * It is also used with output tracks and patch tracks, which never have a + * session. + */ + NONE = 0 +}; + +/** + * Audio format is a 32-bit word that consists of: + * main format field (upper 8 bits) + * sub format field (lower 24 bits). + * + * The main format indicates the main codec type. The sub format field indicates + * options and parameters for each format. The sub format is mainly used for + * record to indicate for instance the requested bitrate or profile. It can + * also be used for certain formats to give informations not present in the + * encoded audio stream (e.g. octet alignement for AMR). + */ +@export(name="audio_format_t", value_prefix="AUDIO_FORMAT_") +enum AudioFormat : uint32_t { + INVALID = 0xFFFFFFFFUL, + DEFAULT = 0, + PCM = 0x00000000UL, + MP3 = 0x01000000UL, + AMR_NB = 0x02000000UL, + AMR_WB = 0x03000000UL, + AAC = 0x04000000UL, + /** Deprecated, Use AAC_HE_V1 */ + HE_AAC_V1 = 0x05000000UL, + /** Deprecated, Use AAC_HE_V2 */ + HE_AAC_V2 = 0x06000000UL, + VORBIS = 0x07000000UL, + OPUS = 0x08000000UL, + AC3 = 0x09000000UL, + E_AC3 = 0x0A000000UL, + DTS = 0x0B000000UL, + DTS_HD = 0x0C000000UL, + /** IEC61937 is encoded audio wrapped in 16-bit PCM. */ + IEC61937 = 0x0D000000UL, + DOLBY_TRUEHD = 0x0E000000UL, + EVRC = 0x10000000UL, + EVRCB = 0x11000000UL, + EVRCWB = 0x12000000UL, + EVRCNW = 0x13000000UL, + AAC_ADIF = 0x14000000UL, + WMA = 0x15000000UL, + WMA_PRO = 0x16000000UL, + AMR_WB_PLUS = 0x17000000UL, + MP2 = 0x18000000UL, + QCELP = 0x19000000UL, + DSD = 0x1A000000UL, + FLAC = 0x1B000000UL, + ALAC = 0x1C000000UL, + APE = 0x1D000000UL, + AAC_ADTS = 0x1E000000UL, + SBC = 0x1F000000UL, + APTX = 0x20000000UL, + APTX_HD = 0x21000000UL, + AC4 = 0x22000000UL, + LDAC = 0x23000000UL, + /** Dolby Metadata-enhanced Audio Transmission */ + MAT = 0x24000000UL, + AAC_LATM = 0x25000000UL, + CELT = 0x26000000UL, + APTX_ADAPTIVE = 0x27000000UL, + LHDC = 0x28000000UL, + LHDC_LL = 0x29000000UL, + APTX_TWSP = 0x2A000000UL, + + /** Deprecated */ + MAIN_MASK = 0xFF000000UL, + SUB_MASK = 0x00FFFFFFUL, + + /* Subformats */ + PCM_SUB_16_BIT = 0x1, // PCM signed 16 bits + PCM_SUB_8_BIT = 0x2, // PCM unsigned 8 bits + PCM_SUB_32_BIT = 0x3, // PCM signed .31 fixed point + PCM_SUB_8_24_BIT = 0x4, // PCM signed 8.23 fixed point + PCM_SUB_FLOAT = 0x5, // PCM single-precision float pt + PCM_SUB_24_BIT_PACKED = 0x6, // PCM signed .23 fix pt (3 bytes) + + MP3_SUB_NONE = 0x0, + + AMR_SUB_NONE = 0x0, + + AAC_SUB_MAIN = 0x1, + AAC_SUB_LC = 0x2, + AAC_SUB_SSR = 0x4, + AAC_SUB_LTP = 0x8, + AAC_SUB_HE_V1 = 0x10, + AAC_SUB_SCALABLE = 0x20, + AAC_SUB_ERLC = 0x40, + AAC_SUB_LD = 0x80, + AAC_SUB_HE_V2 = 0x100, + AAC_SUB_ELD = 0x200, + AAC_SUB_XHE = 0x300, + + VORBIS_SUB_NONE = 0x0, + + E_AC3_SUB_JOC = 0x1, + + MAT_SUB_1_0 = 0x1, + MAT_SUB_2_0 = 0x2, + MAT_SUB_2_1 = 0x3, + + /* Aliases */ + /** note != AudioFormat.ENCODING_PCM_16BIT */ + PCM_16_BIT = (PCM | PCM_SUB_16_BIT), + /** note != AudioFormat.ENCODING_PCM_8BIT */ + PCM_8_BIT = (PCM | PCM_SUB_8_BIT), + PCM_32_BIT = (PCM | PCM_SUB_32_BIT), + PCM_8_24_BIT = (PCM | PCM_SUB_8_24_BIT), + PCM_FLOAT = (PCM | PCM_SUB_FLOAT), + PCM_24_BIT_PACKED = (PCM | PCM_SUB_24_BIT_PACKED), + AAC_MAIN = (AAC | AAC_SUB_MAIN), + AAC_LC = (AAC | AAC_SUB_LC), + AAC_SSR = (AAC | AAC_SUB_SSR), + AAC_LTP = (AAC | AAC_SUB_LTP), + AAC_HE_V1 = (AAC | AAC_SUB_HE_V1), + AAC_SCALABLE = (AAC | AAC_SUB_SCALABLE), + AAC_ERLC = (AAC | AAC_SUB_ERLC), + AAC_LD = (AAC | AAC_SUB_LD), + AAC_HE_V2 = (AAC | AAC_SUB_HE_V2), + AAC_ELD = (AAC | AAC_SUB_ELD), + AAC_XHE = (AAC | AAC_SUB_XHE), + AAC_ADTS_MAIN = (AAC_ADTS | AAC_SUB_MAIN), + AAC_ADTS_LC = (AAC_ADTS | AAC_SUB_LC), + AAC_ADTS_SSR = (AAC_ADTS | AAC_SUB_SSR), + AAC_ADTS_LTP = (AAC_ADTS | AAC_SUB_LTP), + AAC_ADTS_HE_V1 = (AAC_ADTS | AAC_SUB_HE_V1), + AAC_ADTS_SCALABLE = (AAC_ADTS | AAC_SUB_SCALABLE), + AAC_ADTS_ERLC = (AAC_ADTS | AAC_SUB_ERLC), + AAC_ADTS_LD = (AAC_ADTS | AAC_SUB_LD), + AAC_ADTS_HE_V2 = (AAC_ADTS | AAC_SUB_HE_V2), + AAC_ADTS_ELD = (AAC_ADTS | AAC_SUB_ELD), + AAC_ADTS_XHE = (AAC_ADTS | AAC_SUB_XHE), + E_AC3_JOC = (E_AC3 | E_AC3_SUB_JOC), + MAT_1_0 = (MAT | MAT_SUB_1_0), + MAT_2_0 = (MAT | MAT_SUB_2_0), + MAT_2_1 = (MAT | MAT_SUB_2_1), + AAC_LATM_LC = (AAC_LATM | AAC_SUB_LC), + AAC_LATM_HE_V1 = (AAC_LATM | AAC_SUB_HE_V1), + AAC_LATM_HE_V2 = (AAC_LATM | AAC_SUB_HE_V2), +}; + +/** + * Usage of these values highlights places in the code that use 2- or 8- channel + * assumptions. + */ +@export(name="") +enum FixedChannelCount : int32_t { + FCC_2 = 2, // This is typically due to legacy implementation of stereo I/O + FCC_8 = 8 // This is typically due to audio mixer and resampler limitations +}; + +/** + * A channel mask per se only defines the presence or absence of a channel, not + * the order. + * + * The channel order convention is that channels are interleaved in order from + * least significant channel mask bit to most significant channel mask bit, + * with unused bits skipped. For example for stereo, LEFT would be first, + * followed by RIGHT. + * Any exceptions to this convention are noted at the appropriate API. + * + * AudioChannelMask is an opaque type and its internal layout should not be + * assumed as it may change in the future. Instead, always use functions + * to examine it. + * + * These are the current representations: + * + * REPRESENTATION_POSITION + * is a channel mask representation for position assignment. Each low-order + * bit corresponds to the spatial position of a transducer (output), or + * interpretation of channel (input). The user of a channel mask needs to + * know the context of whether it is for output or input. The constants + * OUT_* or IN_* apply to the bits portion. It is not permitted for no bits + * to be set. + * + * REPRESENTATION_INDEX + * is a channel mask representation for index assignment. Each low-order + * bit corresponds to a selected channel. There is no platform + * interpretation of the various bits. There is no concept of output or + * input. It is not permitted for no bits to be set. + * + * All other representations are reserved for future use. + * + * Warning: current representation distinguishes between input and output, but + * this will not the be case in future revisions of the platform. Wherever there + * is an ambiguity between input and output that is currently resolved by + * checking the channel mask, the implementer should look for ways to fix it + * with additional information outside of the mask. + */ +@export(name="", value_prefix="AUDIO_CHANNEL_") +enum AudioChannelMask : uint32_t { + /** must be 0 for compatibility */ + REPRESENTATION_POSITION = 0, + /** 1 is reserved for future use */ + REPRESENTATION_INDEX = 2, + /* 3 is reserved for future use */ + + /** These can be a complete value of AudioChannelMask */ + NONE = 0x0, + INVALID = 0xC0000000, + + /* + * These can be the bits portion of an AudioChannelMask + * with representation REPRESENTATION_POSITION. + */ + + /** output channels */ + OUT_FRONT_LEFT = 0x1, + OUT_FRONT_RIGHT = 0x2, + OUT_FRONT_CENTER = 0x4, + OUT_LOW_FREQUENCY = 0x8, + OUT_BACK_LEFT = 0x10, + OUT_BACK_RIGHT = 0x20, + OUT_FRONT_LEFT_OF_CENTER = 0x40, + OUT_FRONT_RIGHT_OF_CENTER = 0x80, + OUT_BACK_CENTER = 0x100, + OUT_SIDE_LEFT = 0x200, + OUT_SIDE_RIGHT = 0x400, + OUT_TOP_CENTER = 0x800, + OUT_TOP_FRONT_LEFT = 0x1000, + OUT_TOP_FRONT_CENTER = 0x2000, + OUT_TOP_FRONT_RIGHT = 0x4000, + OUT_TOP_BACK_LEFT = 0x8000, + OUT_TOP_BACK_CENTER = 0x10000, + OUT_TOP_BACK_RIGHT = 0x20000, + OUT_TOP_SIDE_LEFT = 0x40000, + OUT_TOP_SIDE_RIGHT = 0x80000, + + /** + * Haptic channel characteristics are specific to a device and + * only used to play device specific resources (eg: ringtones). + * The HAL can freely map A and B to haptic controllers, the + * framework shall not interpret those values and forward them + * from the device audio assets. + */ + OUT_HAPTIC_A = 0x20000000, + OUT_HAPTIC_B = 0x10000000, + + OUT_MONO = OUT_FRONT_LEFT, + OUT_STEREO = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT), + OUT_2POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY), + OUT_2POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT), + OUT_2POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT | + OUT_LOW_FREQUENCY), + OUT_3POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | + OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT), + OUT_3POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | + OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT | + OUT_LOW_FREQUENCY), + OUT_QUAD = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_BACK_LEFT | OUT_BACK_RIGHT), + OUT_QUAD_BACK = OUT_QUAD, + /** like OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */ + OUT_QUAD_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_SIDE_LEFT | OUT_SIDE_RIGHT), + OUT_SURROUND = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_FRONT_CENTER | OUT_BACK_CENTER), + OUT_PENTA = (OUT_QUAD | OUT_FRONT_CENTER), + OUT_5POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | + OUT_BACK_LEFT | OUT_BACK_RIGHT), + OUT_5POINT1_BACK = OUT_5POINT1, + /** like OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_* */ + OUT_5POINT1_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | + OUT_SIDE_LEFT | OUT_SIDE_RIGHT), + OUT_5POINT1POINT2 = (OUT_5POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT), + OUT_5POINT1POINT4 = (OUT_5POINT1 | + OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT | + OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT), + OUT_6POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | + OUT_BACK_LEFT | OUT_BACK_RIGHT | + OUT_BACK_CENTER), + /** matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND */ + OUT_7POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | + OUT_BACK_LEFT | OUT_BACK_RIGHT | + OUT_SIDE_LEFT | OUT_SIDE_RIGHT), + OUT_7POINT1POINT2 = (OUT_7POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT), + OUT_7POINT1POINT4 = (OUT_7POINT1 | + OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT | + OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT), + OUT_MONO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_HAPTIC_A), + OUT_STEREO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_HAPTIC_A), + OUT_HAPTIC_AB = (OUT_HAPTIC_A | OUT_HAPTIC_B), + OUT_MONO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_HAPTIC_A | OUT_HAPTIC_B), + OUT_STEREO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_HAPTIC_A | OUT_HAPTIC_B), + // Note that the 2.0 OUT_ALL* have been moved to helper functions + + /* These are bits only, not complete values */ + + /** input channels */ + IN_LEFT = 0x4, + IN_RIGHT = 0x8, + IN_FRONT = 0x10, + IN_BACK = 0x20, + IN_LEFT_PROCESSED = 0x40, + IN_RIGHT_PROCESSED = 0x80, + IN_FRONT_PROCESSED = 0x100, + IN_BACK_PROCESSED = 0x200, + IN_PRESSURE = 0x400, + IN_X_AXIS = 0x800, + IN_Y_AXIS = 0x1000, + IN_Z_AXIS = 0x2000, + IN_BACK_LEFT = 0x10000, + IN_BACK_RIGHT = 0x20000, + IN_CENTER = 0x40000, + IN_LOW_FREQUENCY = 0x100000, + IN_TOP_LEFT = 0x200000, + IN_TOP_RIGHT = 0x400000, + + IN_VOICE_UPLINK = 0x4000, + IN_VOICE_DNLINK = 0x8000, + + IN_MONO = IN_FRONT, + IN_STEREO = (IN_LEFT | IN_RIGHT), + IN_FRONT_BACK = (IN_FRONT | IN_BACK), + IN_6 = (IN_LEFT | IN_RIGHT | + IN_FRONT | IN_BACK | + IN_LEFT_PROCESSED | IN_RIGHT_PROCESSED), + IN_2POINT0POINT2 = (IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT), + IN_2POINT1POINT2 = (IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT | + IN_LOW_FREQUENCY), + IN_3POINT0POINT2 = (IN_LEFT | IN_CENTER | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT), + IN_3POINT1POINT2 = (IN_LEFT | IN_CENTER | IN_RIGHT | + IN_TOP_LEFT | IN_TOP_RIGHT | IN_LOW_FREQUENCY), + IN_5POINT1 = (IN_LEFT | IN_CENTER | IN_RIGHT | + IN_BACK_LEFT | IN_BACK_RIGHT | IN_LOW_FREQUENCY), + IN_VOICE_UPLINK_MONO = (IN_VOICE_UPLINK | IN_MONO), + IN_VOICE_DNLINK_MONO = (IN_VOICE_DNLINK | IN_MONO), + IN_VOICE_CALL_MONO = (IN_VOICE_UPLINK_MONO | + IN_VOICE_DNLINK_MONO), + // Note that the 2.0 IN_ALL* have been moved to helper functions + + COUNT_MAX = 30, + INDEX_HDR = REPRESENTATION_INDEX << COUNT_MAX, + INDEX_MASK_1 = INDEX_HDR | ((1 << 1) - 1), + INDEX_MASK_2 = INDEX_HDR | ((1 << 2) - 1), + INDEX_MASK_3 = INDEX_HDR | ((1 << 3) - 1), + INDEX_MASK_4 = INDEX_HDR | ((1 << 4) - 1), + INDEX_MASK_5 = INDEX_HDR | ((1 << 5) - 1), + INDEX_MASK_6 = INDEX_HDR | ((1 << 6) - 1), + INDEX_MASK_7 = INDEX_HDR | ((1 << 7) - 1), + INDEX_MASK_8 = INDEX_HDR | ((1 << 8) - 1), + INDEX_MASK_9 = INDEX_HDR | ((1 << 9) - 1), + INDEX_MASK_10 = INDEX_HDR | ((1 << 10) - 1), + INDEX_MASK_11 = INDEX_HDR | ((1 << 11) - 1), + INDEX_MASK_12 = INDEX_HDR | ((1 << 12) - 1), + INDEX_MASK_13 = INDEX_HDR | ((1 << 13) - 1), + INDEX_MASK_14 = INDEX_HDR | ((1 << 14) - 1), + INDEX_MASK_15 = INDEX_HDR | ((1 << 15) - 1), + INDEX_MASK_16 = INDEX_HDR | ((1 << 16) - 1), + INDEX_MASK_17 = INDEX_HDR | ((1 << 17) - 1), + INDEX_MASK_18 = INDEX_HDR | ((1 << 18) - 1), + INDEX_MASK_19 = INDEX_HDR | ((1 << 19) - 1), + INDEX_MASK_20 = INDEX_HDR | ((1 << 20) - 1), + INDEX_MASK_21 = INDEX_HDR | ((1 << 21) - 1), + INDEX_MASK_22 = INDEX_HDR | ((1 << 22) - 1), + INDEX_MASK_23 = INDEX_HDR | ((1 << 23) - 1), + INDEX_MASK_24 = INDEX_HDR | ((1 << 24) - 1), +}; + +/** + * Major modes for a mobile device. The current mode setting affects audio + * routing. + */ +@export(name="audio_mode_t", value_prefix="AUDIO_MODE_") +enum AudioMode : int32_t { + NORMAL = 0, + RINGTONE = 1, + /** Calls handled by the telephony stack (Eg: PSTN). */ + IN_CALL = 2, + /** Calls handled by apps (Eg: Hangout). */ + IN_COMMUNICATION = 3, +}; + +@export(name="", value_prefix="AUDIO_DEVICE_") +enum AudioDevice : uint32_t { + NONE = 0x0, + /** reserved bits */ + BIT_IN = 0x80000000, + BIT_DEFAULT = 0x40000000, + /** output devices */ + OUT_EARPIECE = 0x1, + OUT_SPEAKER = 0x2, + OUT_WIRED_HEADSET = 0x4, + OUT_WIRED_HEADPHONE = 0x8, + OUT_BLUETOOTH_SCO = 0x10, + OUT_BLUETOOTH_SCO_HEADSET = 0x20, + OUT_BLUETOOTH_SCO_CARKIT = 0x40, + OUT_BLUETOOTH_A2DP = 0x80, + OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100, + OUT_BLUETOOTH_A2DP_SPEAKER = 0x200, + OUT_AUX_DIGITAL = 0x400, + OUT_HDMI = OUT_AUX_DIGITAL, + /** uses an analog connection (multiplexed over the USB pins for instance) */ + OUT_ANLG_DOCK_HEADSET = 0x800, + OUT_DGTL_DOCK_HEADSET = 0x1000, + /** USB accessory mode: Android device is USB device and dock is USB host */ + OUT_USB_ACCESSORY = 0x2000, + /** USB host mode: Android device is USB host and dock is USB device */ + OUT_USB_DEVICE = 0x4000, + OUT_REMOTE_SUBMIX = 0x8000, + /** Telephony voice TX path */ + OUT_TELEPHONY_TX = 0x10000, + /** Analog jack with line impedance detected */ + OUT_LINE = 0x20000, + /** HDMI Audio Return Channel */ + OUT_HDMI_ARC = 0x40000, + /** S/PDIF out */ + OUT_SPDIF = 0x80000, + /** FM transmitter out */ + OUT_FM = 0x100000, + /** Line out for av devices */ + OUT_AUX_LINE = 0x200000, + /** limited-output speaker device for acoustic safety */ + OUT_SPEAKER_SAFE = 0x400000, + OUT_IP = 0x800000, + /** audio bus implemented by the audio system (e.g an MOST stereo channel) */ + OUT_BUS = 0x1000000, + OUT_PROXY = 0x2000000, + OUT_USB_HEADSET = 0x4000000, + OUT_HEARING_AID = 0x8000000, + OUT_ECHO_CANCELLER = 0x10000000, + OUT_DEFAULT = BIT_DEFAULT, + // Note that the 2.0 OUT_ALL* have been moved to helper functions + + /** input devices */ + IN_COMMUNICATION = BIT_IN | 0x1, + IN_AMBIENT = BIT_IN | 0x2, + IN_BUILTIN_MIC = BIT_IN | 0x4, + IN_BLUETOOTH_SCO_HEADSET = BIT_IN | 0x8, + IN_WIRED_HEADSET = BIT_IN | 0x10, + IN_AUX_DIGITAL = BIT_IN | 0x20, + IN_HDMI = IN_AUX_DIGITAL, + /** Telephony voice RX path */ + IN_VOICE_CALL = BIT_IN | 0x40, + IN_TELEPHONY_RX = IN_VOICE_CALL, + IN_BACK_MIC = BIT_IN | 0x80, + IN_REMOTE_SUBMIX = BIT_IN | 0x100, + IN_ANLG_DOCK_HEADSET = BIT_IN | 0x200, + IN_DGTL_DOCK_HEADSET = BIT_IN | 0x400, + IN_USB_ACCESSORY = BIT_IN | 0x800, + IN_USB_DEVICE = BIT_IN | 0x1000, + /** FM tuner input */ + IN_FM_TUNER = BIT_IN | 0x2000, + /** TV tuner input */ + IN_TV_TUNER = BIT_IN | 0x4000, + /** Analog jack with line impedance detected */ + IN_LINE = BIT_IN | 0x8000, + /** S/PDIF in */ + IN_SPDIF = BIT_IN | 0x10000, + IN_BLUETOOTH_A2DP = BIT_IN | 0x20000, + IN_LOOPBACK = BIT_IN | 0x40000, + IN_IP = BIT_IN | 0x80000, + /** audio bus implemented by the audio system (e.g an MOST stereo channel) */ + IN_BUS = BIT_IN | 0x100000, + IN_PROXY = BIT_IN | 0x1000000, + IN_USB_HEADSET = BIT_IN | 0x2000000, + IN_BLUETOOTH_BLE = BIT_IN | 0x4000000, + IN_ECHO_REFERENCE = BIT_IN | 0x10000000, + IN_DEFAULT = BIT_IN | BIT_DEFAULT, + + // Note that the 2.0 IN_ALL* have been moved to helper functions +}; + +/** + * IEEE 802 MAC address. + */ +typedef uint8_t[6] MacAddress; + +/** + * Specifies a device address in case when several devices of the same type + * can be connected (e.g. BT A2DP, USB). + */ +struct DeviceAddress { + AudioDevice device; // discriminator + union Address { + MacAddress mac; // used for BLUETOOTH_A2DP_* + uint8_t[4] ipv4; // used for IP + struct Alsa { + int32_t card; + int32_t device; + } alsa; // used for USB_* + } address; + /** Arbitrary BUS device unique address. Should not be interpreted by the framework. */ + string busAddress; + /** Arbitrary REMOTE_SUBMIX device unique address. Should not be interpreted by the HAL. */ + string rSubmixAddress; +}; + +/** + * The audio output flags serve two purposes: + * + * - when an AudioTrack is created they indicate a "wish" to be connected to an + * output stream with attributes corresponding to the specified flags; + * + * - when present in an output profile descriptor listed for a particular audio + * hardware module, they indicate that an output stream can be opened that + * supports the attributes indicated by the flags. + * + * The audio policy manager will try to match the flags in the request + * (when getOuput() is called) to an available output stream. + */ +@export(name="audio_output_flags_t", value_prefix="AUDIO_OUTPUT_FLAG_") +enum AudioOutputFlag : int32_t { + NONE = 0x0, // no attributes + DIRECT = 0x1, // this output directly connects a track + // to one output stream: no software mixer + PRIMARY = 0x2, // this output is the primary output of the device. It is + // unique and must be present. It is opened by default and + // receives routing, audio mode and volume controls related + // to voice calls. + FAST = 0x4, // output supports "fast tracks", defined elsewhere + DEEP_BUFFER = 0x8, // use deep audio buffers + COMPRESS_OFFLOAD = 0x10, // offload playback of compressed streams to + // hardware codec + NON_BLOCKING = 0x20, // use non-blocking write + HW_AV_SYNC = 0x40, // output uses a hardware A/V sync + TTS = 0x80, // output for streams transmitted through speaker at a + // sample rate high enough to accommodate lower-range + // ultrasonic p/b + RAW = 0x100, // minimize signal processing + SYNC = 0x200, // synchronize I/O streams + IEC958_NONAUDIO = 0x400, // Audio stream contains compressed audio in SPDIF + // data bursts, not PCM. + DIRECT_PCM = 0x2000, // Audio stream containing PCM data that needs + // to pass through compress path for DSP post proc. + MMAP_NOIRQ = 0x4000, // output operates in MMAP no IRQ mode. + VOIP_RX = 0x8000, // preferred output for VoIP calls. + /** preferred output for call music */ + INCALL_MUSIC = 0x10000, +}; + +/** + * The audio input flags are analogous to audio output flags. + * Currently they are used only when an AudioRecord is created, + * to indicate a preference to be connected to an input stream with + * attributes corresponding to the specified flags. + */ +@export(name="audio_input_flags_t", value_prefix="AUDIO_INPUT_FLAG_") +enum AudioInputFlag : int32_t { + NONE = 0x0, // no attributes + FAST = 0x1, // prefer an input that supports "fast tracks" + HW_HOTWORD = 0x2, // prefer an input that captures from hw hotword source + RAW = 0x4, // minimize signal processing + SYNC = 0x8, // synchronize I/O streams + MMAP_NOIRQ = 0x10, // input operates in MMAP no IRQ mode. + VOIP_TX = 0x20, // preferred input for VoIP calls. + HW_AV_SYNC = 0x40, // input connected to an output that uses a hardware A/V sync +}; + +@export(name="audio_usage_t", value_prefix="AUDIO_USAGE_") +enum AudioUsage : int32_t { + // These values must kept in sync with + // frameworks/base/media/java/android/media/AudioAttributes.java + // Note that not all framework values are exposed + UNKNOWN = 0, + MEDIA = 1, + VOICE_COMMUNICATION = 2, + VOICE_COMMUNICATION_SIGNALLING = 3, + ALARM = 4, + NOTIFICATION = 5, + NOTIFICATION_TELEPHONY_RINGTONE = 6, + ASSISTANCE_ACCESSIBILITY = 11, + ASSISTANCE_NAVIGATION_GUIDANCE = 12, + ASSISTANCE_SONIFICATION = 13, + GAME = 14, + VIRTUAL_SOURCE = 15, + ASSISTANT = 16, +}; + +/** Type of audio generated by an application. */ +@export(name="audio_content_type_t", value_prefix="AUDIO_CONTENT_TYPE_") +enum AudioContentType : uint32_t { + // Do not change these values without updating their counterparts + // in frameworks/base/media/java/android/media/AudioAttributes.java + UNKNOWN = 0, + SPEECH = 1, + MUSIC = 2, + MOVIE = 3, + SONIFICATION = 4, +}; + +/** + * Additional information about the stream passed to hardware decoders. + */ +struct AudioOffloadInfo { + uint32_t sampleRateHz; + bitfield channelMask; + AudioFormat format; + AudioStreamType streamType; + uint32_t bitRatePerSecond; + int64_t durationMicroseconds; // -1 if unknown + bool hasVideo; + bool isStreaming; + uint32_t bitWidth; + uint32_t bufferSize; + AudioUsage usage; +}; + +/** + * Commonly used audio stream configuration parameters. + */ +struct AudioConfig { + uint32_t sampleRateHz; + bitfield channelMask; + AudioFormat format; + AudioOffloadInfo offloadInfo; + uint64_t frameCount; +}; + +/** Metadata of a playback track for a StreamOut. */ +struct PlaybackTrackMetadata { + AudioUsage usage; + AudioContentType contentType; + /** + * Positive linear gain applied to the track samples. 0 being muted and 1 is no attenuation, + * 2 means double amplification... + * Must not be negative. + */ + float gain; +}; + +/** Metadatas of the source of a StreamOut. */ +struct SourceMetadata { + vec tracks; +}; + +/** Metadata of a record track for a StreamIn. */ +struct RecordTrackMetadata { + AudioSource source; + /** + * Positive linear gain applied to the track samples. 0 being muted and 1 is no attenuation, + * 2 means double amplification... + * Must not be negative. + */ + float gain; + /** + * Indicates the destination of an input stream, can be left unspecified. + */ + safe_union Destination { + Monostate unspecified; + DeviceAddress device; + }; + Destination destination; +}; + +/** Metadatas of the sink of a StreamIn. */ +struct SinkMetadata { + vec tracks; +}; + + +/* + * + * Volume control + * + */ + +/** + * Type of gain control exposed by an audio port. + */ +@export(name="", value_prefix="AUDIO_GAIN_MODE_") +enum AudioGainMode : uint32_t { + JOINT = 0x1, // supports joint channel gain control + CHANNELS = 0x2, // supports separate channel gain control + RAMP = 0x4 // supports gain ramps +}; + +/** + * An audio_gain struct is a representation of a gain stage. + * A gain stage is always attached to an audio port. + */ +struct AudioGain { + bitfield mode; + bitfield channelMask; // channels which gain an be controlled + int32_t minValue; // minimum gain value in millibels + int32_t maxValue; // maximum gain value in millibels + int32_t defaultValue; // default gain value in millibels + uint32_t stepValue; // gain step in millibels + uint32_t minRampMs; // minimum ramp duration in ms + uint32_t maxRampMs; // maximum ramp duration in ms +}; + +/** + * The gain configuration structure is used to get or set the gain values of a + * given port. + */ +struct AudioGainConfig { + int32_t index; // index of the corresponding AudioGain in AudioPort.gains + AudioGainMode mode; + AudioChannelMask channelMask; // channels which gain value follows + /** + * 4 = sizeof(AudioChannelMask), + * 8 is not "FCC_8", so it won't need to be changed for > 8 channels. + * Gain values in millibels for each channel ordered from LSb to MSb in + * channel mask. The number of values is 1 in joint mode or + * popcount(channel_mask). + */ + int32_t[4 * 8] values; + uint32_t rampDurationMs; // ramp duration in ms +}; + + +/* + * + * Routing control + * + */ + +/* + * Types defined here are used to describe an audio source or sink at internal + * framework interfaces (audio policy, patch panel) or at the audio HAL. + * Sink and sources are grouped in a concept of “audio port” representing an + * audio end point at the edge of the system managed by the module exposing + * the interface. + */ + +/** Audio port role: either source or sink */ +@export(name="audio_port_role_t", value_prefix="AUDIO_PORT_ROLE_") +enum AudioPortRole : int32_t { + NONE, + SOURCE, + SINK, +}; + +/** + * Audio port type indicates if it is a session (e.g AudioTrack), a mix (e.g + * PlaybackThread output) or a physical device (e.g OUT_SPEAKER) + */ +@export(name="audio_port_type_t", value_prefix="AUDIO_PORT_TYPE_") +enum AudioPortType : int32_t { + NONE, + DEVICE, + MIX, + SESSION, +}; + +/** + * Extension for audio port configuration structure when the audio port is a + * hardware device. + */ +struct AudioPortConfigDeviceExt { + AudioModuleHandle hwModule; // module the device is attached to + AudioDevice type; // device type (e.g OUT_SPEAKER) + uint8_t[32] address; // device address. "" if N/A +}; + +/** + * Extension for audio port configuration structure when the audio port is an + * audio session. + */ +struct AudioPortConfigSessionExt { + AudioSession session; +}; + +/** + * Flags indicating which fields are to be considered in AudioPortConfig. + */ +@export(name="", value_prefix="AUDIO_PORT_CONFIG_") +enum AudioPortConfigMask : uint32_t { + SAMPLE_RATE = 0x1, + CHANNEL_MASK = 0x2, + FORMAT = 0x4, + GAIN = 0x8, +}; + +/** + * Audio port configuration structure used to specify a particular configuration + * of an audio port. + */ +struct AudioPortConfig { + AudioPortHandle id; + bitfield configMask; + uint32_t sampleRateHz; + bitfield channelMask; + AudioFormat format; + AudioGainConfig gain; + AudioPortType type; // type is used as a discriminator for Ext union + AudioPortRole role; // role is used as a discriminator for UseCase union + union Ext { + AudioPortConfigDeviceExt device; + struct AudioPortConfigMixExt { + AudioModuleHandle hwModule; // module the stream is attached to + AudioIoHandle ioHandle; // I/O handle of the input/output stream + union UseCase { + AudioStreamType stream; + AudioSource source; + } useCase; + } mix; + AudioPortConfigSessionExt session; + } ext; +}; + +/** + * Extension for audio port structure when the audio port is a hardware device. + */ +struct AudioPortDeviceExt { + AudioModuleHandle hwModule; // module the device is attached to + AudioDevice type; + /** 32 byte string identifying the port. */ + uint8_t[32] address; +}; + +/** + * Latency class of the audio mix. + */ +@export(name="audio_mix_latency_class_t", value_prefix="AUDIO_LATENCY_") +enum AudioMixLatencyClass : int32_t { + LOW, + NORMAL +}; + +struct AudioPortMixExt { + AudioModuleHandle hwModule; // module the stream is attached to + AudioIoHandle ioHandle; // I/O handle of the stream + AudioMixLatencyClass latencyClass; +}; + +/** + * Extension for audio port structure when the audio port is an audio session. + */ +struct AudioPortSessionExt { + AudioSession session; +}; + +struct AudioPort { + AudioPortHandle id; + AudioPortRole role; + string name; + vec sampleRates; + vec> channelMasks; + vec formats; + vec gains; + AudioPortConfig activeConfig; // current audio port configuration + AudioPortType type; // type is used as a discriminator + union Ext { + AudioPortDeviceExt device; + AudioPortMixExt mix; + AudioPortSessionExt session; + } ext; +}; + +struct ThreadInfo { + int64_t pid; + int64_t tid; +}; diff --git a/audio/common/all-versions/default/Android.bp b/audio/common/all-versions/default/Android.bp index e630d93b80..0eb4a71348 100644 --- a/audio/common/all-versions/default/Android.bp +++ b/audio/common/all-versions/default/Android.bp @@ -104,3 +104,16 @@ cc_library_shared { "-include common/all-versions/VersionMacro.h", ] } + +cc_library_shared { + name: "android.hardware.audio.common@6.0-util", + defaults: ["android.hardware.audio.common-util_default"], + shared_libs: [ + "android.hardware.audio.common@6.0", + ], + cflags: [ + "-DMAJOR_VERSION=6", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp index f5a6f42df5..45657305d5 100644 --- a/audio/common/all-versions/default/service/Android.bp +++ b/audio/common/all-versions/default/service/Android.bp @@ -27,12 +27,15 @@ cc_binary { "android.hardware.audio@2.0", "android.hardware.audio@4.0", "android.hardware.audio@5.0", + "android.hardware.audio@6.0", "android.hardware.audio.common@2.0", "android.hardware.audio.common@4.0", "android.hardware.audio.common@5.0", + "android.hardware.audio.common@6.0", "android.hardware.audio.effect@2.0", "android.hardware.audio.effect@4.0", "android.hardware.audio.effect@5.0", + "android.hardware.audio.effect@6.0", "android.hardware.bluetooth.a2dp@1.0", "android.hardware.bluetooth.audio@2.0", "android.hardware.soundtrigger@2.0", diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp index e8a9e23f02..2730f3b1bb 100644 --- a/audio/common/all-versions/default/service/service.cpp +++ b/audio/common/all-versions/default/service/service.cpp @@ -19,9 +19,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -62,12 +64,14 @@ int main(int /* argc */, char* /* argv */ []) { // Keep versions on a separate line for easier parsing // clang-format off LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations< + audio::V6_0::IDevicesFactory, audio::V5_0::IDevicesFactory, audio::V4_0::IDevicesFactory, audio::V2_0::IDevicesFactory>()), "Could not register audio core API"); LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations< + audio::effect::V6_0::IEffectsFactory, audio::effect::V5_0::IEffectsFactory, audio::effect::V4_0::IEffectsFactory, audio::effect::V2_0::IEffectsFactory>()), diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp index 423395e4f3..b8b7feeed0 100644 --- a/audio/core/all-versions/default/Android.bp +++ b/audio/core/all-versions/default/Android.bp @@ -85,3 +85,18 @@ cc_library_shared { "-include common/all-versions/VersionMacro.h", ] } + +cc_library_shared { + name: "android.hardware.audio@6.0-impl", + defaults: ["android.hardware.audio-impl_default"], + shared_libs: [ + "android.hardware.audio@6.0", + "android.hardware.audio.common@6.0", + "android.hardware.audio.common@6.0-util", + ], + cflags: [ + "-DMAJOR_VERSION=6", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp new file mode 100644 index 0000000000..6314ea72ec --- /dev/null +++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp @@ -0,0 +1,18 @@ +/* + * 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. + */ + +// pull in all the <= 5.0 tests +#include "5.0/AudioPrimaryHidlHalTest.cpp" diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp index 5e17ade365..73af7f471e 100644 --- a/audio/core/all-versions/vts/functional/Android.bp +++ b/audio/core/all-versions/vts/functional/Android.bp @@ -83,3 +83,20 @@ cc_test { "-include common/all-versions/VersionMacro.h", ] } + +cc_test { + name: "VtsHalAudioV6_0TargetTest", + defaults: ["VtsHalAudioTargetTest_defaults"], + srcs: [ + "6.0/AudioPrimaryHidlHalTest.cpp", + ], + static_libs: [ + "android.hardware.audio@6.0", + "android.hardware.audio.common@6.0", + ], + cflags: [ + "-DMAJOR_VERSION=6", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} diff --git a/audio/effect/6.0/Android.bp b/audio/effect/6.0/Android.bp new file mode 100644 index 0000000000..b6184f3a58 --- /dev/null +++ b/audio/effect/6.0/Android.bp @@ -0,0 +1,33 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.audio.effect@6.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IAcousticEchoCancelerEffect.hal", + "IAutomaticGainControlEffect.hal", + "IBassBoostEffect.hal", + "IDownmixEffect.hal", + "IEffect.hal", + "IEffectBufferProviderCallback.hal", + "IEffectsFactory.hal", + "IEnvironmentalReverbEffect.hal", + "IEqualizerEffect.hal", + "ILoudnessEnhancerEffect.hal", + "INoiseSuppressionEffect.hal", + "IPresetReverbEffect.hal", + "IVirtualizerEffect.hal", + "IVisualizerEffect.hal", + ], + interfaces: [ + "android.hardware.audio.common@6.0", + "android.hidl.base@1.0", + "android.hidl.safe_union@1.0", + ], + gen_java: false, + gen_java_constants: true, +} diff --git a/audio/effect/6.0/IAcousticEchoCancelerEffect.hal b/audio/effect/6.0/IAcousticEchoCancelerEffect.hal new file mode 100644 index 0000000000..f7d769fc50 --- /dev/null +++ b/audio/effect/6.0/IAcousticEchoCancelerEffect.hal @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package android.hardware.audio.effect@6.0; + +import android.hardware.audio.common@6.0; +import IEffect; + +interface IAcousticEchoCancelerEffect extends IEffect { + /** + * Sets echo delay value in milliseconds. + */ + setEchoDelay(uint32_t echoDelayMs) generates (Result retval); + + /** + * Gets echo delay value in milliseconds. + */ + getEchoDelay() generates (Result retval, uint32_t echoDelayMs); +}; diff --git a/audio/effect/6.0/IAutomaticGainControlEffect.hal b/audio/effect/6.0/IAutomaticGainControlEffect.hal new file mode 100644 index 0000000000..d264cd4911 --- /dev/null +++ b/audio/effect/6.0/IAutomaticGainControlEffect.hal @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package android.hardware.audio.effect@6.0; + +import android.hardware.audio.common@6.0; +import IEffect; + +interface IAutomaticGainControlEffect extends IEffect { + /** + * Sets target level in millibels. + */ + setTargetLevel(int16_t targetLevelMb) generates (Result retval); + + /** + * Gets target level. + */ + getTargetLevel() generates (Result retval, int16_t targetLevelMb); + + /** + * Sets gain in the compression range in millibels. + */ + setCompGain(int16_t compGainMb) generates (Result retval); + + /** + * Gets gain in the compression range. + */ + getCompGain() generates (Result retval, int16_t compGainMb); + + /** + * Enables or disables limiter. + */ + setLimiterEnabled(bool enabled) generates (Result retval); + + /** + * Returns whether limiter is enabled. + */ + isLimiterEnabled() generates (Result retval, bool enabled); + + struct AllProperties { + int16_t targetLevelMb; + int16_t compGainMb; + bool limiterEnabled; + }; + + /** + * Sets all properties at once. + */ + setAllProperties(AllProperties properties) generates (Result retval); + + /** + * Gets all properties at once. + */ + getAllProperties() generates (Result retval, AllProperties properties); +}; diff --git a/audio/effect/6.0/IBassBoostEffect.hal b/audio/effect/6.0/IBassBoostEffect.hal new file mode 100644 index 0000000000..91c409249f --- /dev/null +++ b/audio/effect/6.0/IBassBoostEffect.hal @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package android.hardware.audio.effect@6.0; + +import android.hardware.audio.common@6.0; +import IEffect; + +interface IBassBoostEffect extends IEffect { + /** + * Returns whether setting bass boost strength is supported. + */ + isStrengthSupported() generates (Result retval, bool strengthSupported); + + enum StrengthRange : uint16_t { + MIN = 0, + MAX = 1000 + }; + + /** + * Sets bass boost strength. + * + * @param strength strength of the effect. The valid range for strength + * strength is [0, 1000], where 0 per mille designates the + * mildest effect and 1000 per mille designates the + * strongest. + * @return retval operation completion status. + */ + setStrength(uint16_t strength) generates (Result retval); + + /** + * Gets virtualization strength. + */ + getStrength() generates (Result retval, uint16_t strength); +}; diff --git a/audio/effect/6.0/IDownmixEffect.hal b/audio/effect/6.0/IDownmixEffect.hal new file mode 100644 index 0000000000..e3a38e25aa --- /dev/null +++ b/audio/effect/6.0/IDownmixEffect.hal @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package android.hardware.audio.effect@6.0; + +import android.hardware.audio.common@6.0; +import IEffect; + +interface IDownmixEffect extends IEffect { + enum Type : int32_t { + STRIP, // throw away the extra channels + FOLD // mix the extra channels with FL/FR + }; + + /** + * Sets the current downmix preset. + */ + setType(Type preset) generates (Result retval); + + /** + * Gets the current downmix preset. + */ + getType() generates (Result retval, Type preset); +}; diff --git a/audio/effect/6.0/IEffect.hal b/audio/effect/6.0/IEffect.hal new file mode 100644 index 0000000000..b35afee260 --- /dev/null +++ b/audio/effect/6.0/IEffect.hal @@ -0,0 +1,418 @@ +/* + * 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. + */ + +package android.hardware.audio.effect@6.0; + +import android.hardware.audio.common@6.0; +import IEffectBufferProviderCallback; + +interface IEffect { + /** + * Initialize effect engine--all configurations return to default. + * + * @return retval operation completion status. + */ + @entry + init() generates (Result retval); + + /** + * Apply new audio parameters configurations for input and output buffers. + * The provider callbacks may be empty, but in this case the buffer + * must be provided in the EffectConfig structure. + * + * @param config configuration descriptor. + * @param inputBufferProvider optional buffer provider reference. + * @param outputBufferProvider optional buffer provider reference. + * @return retval operation completion status. + */ + setConfig(EffectConfig config, + IEffectBufferProviderCallback inputBufferProvider, + IEffectBufferProviderCallback outputBufferProvider) + generates (Result retval); + + /** + * Reset the effect engine. Keep configuration but resets state and buffer + * content. + * + * @return retval operation completion status. + */ + reset() generates (Result retval); + + /** + * Enable processing. + * + * @return retval operation completion status. + */ + @callflow(next={"prepareForProcessing"}) + enable() generates (Result retval); + + /** + * Disable processing. + * + * @return retval operation completion status. + */ + @callflow(next={"close"}) + disable() generates (Result retval); + + /** + * Set the rendering device the audio output path is connected to. The + * effect implementation must set EFFECT_FLAG_DEVICE_IND flag in its + * descriptor to receive this command when the device changes. + * + * Note: this method is only supported for effects inserted into + * the output chain. + * + * @param device output device specification. + * @return retval operation completion status. + */ + setDevice(bitfield device) generates (Result retval); + + /** + * Set and get volume. Used by audio framework to delegate volume control to + * effect engine. The effect implementation must set EFFECT_FLAG_VOLUME_CTRL + * flag in its descriptor to receive this command. The effect engine must + * return the volume that should be applied before the effect is + * processed. The overall volume (the volume actually applied by the effect + * engine multiplied by the returned value) should match the value indicated + * in the command. + * + * @param volumes vector containing volume for each channel defined in + * EffectConfig for output buffer expressed in 8.24 fixed + * point format. + * @return result updated volume values. + * @return retval operation completion status. + */ + setAndGetVolume(vec volumes) + generates (Result retval, vec result); + + /** + * Notify the effect of the volume change. The effect implementation must + * set EFFECT_FLAG_VOLUME_IND flag in its descriptor to receive this + * command. + * + * @param volumes vector containing volume for each channel defined in + * EffectConfig for output buffer expressed in 8.24 fixed + * point format. + * @return retval operation completion status. + */ + volumeChangeNotification(vec volumes) + generates (Result retval); + + /** + * Set the audio mode. The effect implementation must set + * EFFECT_FLAG_AUDIO_MODE_IND flag in its descriptor to receive this command + * when the audio mode changes. + * + * @param mode desired audio mode. + * @return retval operation completion status. + */ + setAudioMode(AudioMode mode) generates (Result retval); + + /** + * Apply new audio parameters configurations for input and output buffers of + * reverse stream. An example of reverse stream is the echo reference + * supplied to an Acoustic Echo Canceler. + * + * @param config configuration descriptor. + * @param inputBufferProvider optional buffer provider reference. + * @param outputBufferProvider optional buffer provider reference. + * @return retval operation completion status. + */ + setConfigReverse(EffectConfig config, + IEffectBufferProviderCallback inputBufferProvider, + IEffectBufferProviderCallback outputBufferProvider) + generates (Result retval); + + /** + * Set the capture device the audio input path is connected to. The effect + * implementation must set EFFECT_FLAG_DEVICE_IND flag in its descriptor to + * receive this command when the device changes. + * + * Note: this method is only supported for effects inserted into + * the input chain. + * + * @param device input device specification. + * @return retval operation completion status. + */ + setInputDevice(bitfield device) generates (Result retval); + + /** + * Read audio parameters configurations for input and output buffers. + * + * @return retval operation completion status. + * @return config configuration descriptor. + */ + getConfig() generates (Result retval, EffectConfig config); + + /** + * Read audio parameters configurations for input and output buffers of + * reverse stream. + * + * @return retval operation completion status. + * @return config configuration descriptor. + */ + getConfigReverse() generates (Result retval, EffectConfig config); + + /** + * Queries for supported combinations of main and auxiliary channels + * (e.g. for a multi-microphone noise suppressor). + * + * @param maxConfigs maximum number of the combinations to return. + * @return retval absence of the feature support is indicated using + * NOT_SUPPORTED code. RESULT_TOO_BIG is returned if + * the number of supported combinations exceeds 'maxConfigs'. + * @return result list of configuration descriptors. + */ + getSupportedAuxChannelsConfigs(uint32_t maxConfigs) + generates (Result retval, vec result); + + /** + * Retrieves the current configuration of main and auxiliary channels. + * + * @return retval absence of the feature support is indicated using + * NOT_SUPPORTED code. + * @return result configuration descriptor. + */ + getAuxChannelsConfig() + generates (Result retval, EffectAuxChannelsConfig result); + + /** + * Sets the current configuration of main and auxiliary channels. + * + * @return retval operation completion status; absence of the feature + * support is indicated using NOT_SUPPORTED code. + */ + setAuxChannelsConfig(EffectAuxChannelsConfig config) + generates (Result retval); + + /** + * Set the audio source the capture path is configured for (Camcorder, voice + * recognition...). + * + * Note: this method is only supported for effects inserted into + * the input chain. + * + * @param source source descriptor. + * @return retval operation completion status. + */ + setAudioSource(AudioSource source) generates (Result retval); + + /** + * This command indicates if the playback thread the effect is attached to + * is offloaded or not, and updates the I/O handle of the playback thread + * the effect is attached to. + * + * @param param effect offload descriptor. + * @return retval operation completion status. + */ + offload(EffectOffloadParameter param) generates (Result retval); + + /** + * Returns the effect descriptor. + * + * @return retval operation completion status. + * @return descriptor effect descriptor. + */ + getDescriptor() generates (Result retval, EffectDescriptor descriptor); + + /** + * Set up required transports for passing audio buffers to the effect. + * + * The transport consists of shared memory and a message queue for reporting + * effect processing operation status. The shared memory is set up + * separately using 'setProcessBuffers' method. + * + * Processing is requested by setting 'REQUEST_PROCESS' or + * 'REQUEST_PROCESS_REVERSE' EventFlags associated with the status message + * queue. The result of processing may be one of the following: + * OK if there were no errors during processing; + * INVALID_ARGUMENTS if audio buffers are invalid; + * INVALID_STATE if the engine has finished the disable phase; + * NOT_INITIALIZED if the audio buffers were not set; + * NOT_SUPPORTED if the requested processing type is not supported by + * the effect. + * + * @return retval OK if both message queues were created successfully. + * INVALID_STATE if the method was already called. + * INVALID_ARGUMENTS if there was a problem setting up + * the queue. + * @return statusMQ a message queue used for passing status from the effect. + */ + @callflow(next={"setProcessBuffers"}) + prepareForProcessing() generates (Result retval, fmq_sync statusMQ); + + /** + * Set up input and output buffers for processing audio data. The effect + * may modify both the input and the output buffer during the operation. + * Buffers may be set multiple times during effect lifetime. + * + * The input and the output buffer may be reused between different effects, + * and the input buffer may be used as an output buffer. Buffers are + * distinguished using 'AudioBuffer.id' field. + * + * @param inBuffer input audio buffer. + * @param outBuffer output audio buffer. + * @return retval OK if both buffers were mapped successfully. + * INVALID_ARGUMENTS if there was a problem with mapping + * any of the buffers. + */ + setProcessBuffers(AudioBuffer inBuffer, AudioBuffer outBuffer) + generates (Result retval); + + /** + * Execute a vendor specific command on the effect. The command code + * and data, as well as result data are not interpreted by Android + * Framework and are passed as-is between the application and the effect. + * + * The effect must use standard POSIX.1-2001 error codes for the operation + * completion status. + * + * Use this method only if the effect is provided by a third party, and + * there is no interface defined for it. This method only works for effects + * implemented in software. + * + * @param commandId the ID of the command. + * @param data command data. + * @param resultMaxSize maximum size in bytes of the result; can be 0. + * @return status command completion status. + * @return result result data. + */ + command(uint32_t commandId, vec data, uint32_t resultMaxSize) + generates (int32_t status, vec result); + + /** + * Set a vendor-specific parameter and apply it immediately. The parameter + * code and data are not interpreted by Android Framework and are passed + * as-is between the application and the effect. + * + * The effect must use INVALID_ARGUMENTS return code if the parameter ID is + * unknown or if provided parameter data is invalid. If the effect does not + * support setting vendor-specific parameters, it must return NOT_SUPPORTED. + * + * Use this method only if the effect is provided by a third party, and + * there is no interface defined for it. This method only works for effects + * implemented in software. + * + * @param parameter identifying data of the parameter. + * @param value the value of the parameter. + * @return retval operation completion status. + */ + setParameter(vec parameter, vec value) + generates (Result retval); + + /** + * Get a vendor-specific parameter value. The parameter code and returned + * data are not interpreted by Android Framework and are passed as-is + * between the application and the effect. + * + * The effect must use INVALID_ARGUMENTS return code if the parameter ID is + * unknown. If the effect does not support setting vendor-specific + * parameters, it must return NOT_SUPPORTED. + * + * Use this method only if the effect is provided by a third party, and + * there is no interface defined for it. This method only works for effects + * implemented in software. + * + * @param parameter identifying data of the parameter. + * @param valueMaxSize maximum size in bytes of the value. + * @return retval operation completion status. + * @return result the value of the parameter. + */ + getParameter(vec parameter, uint32_t valueMaxSize) + generates (Result retval, vec value); + + /** + * Get supported configs for a vendor-specific feature. The configs returned + * are not interpreted by Android Framework and are passed as-is between the + * application and the effect. + * + * The effect must use INVALID_ARGUMENTS return code if the feature ID is + * unknown. If the effect does not support getting vendor-specific feature + * configs, it must return NOT_SUPPORTED. If the feature is supported but + * the total number of supported configurations exceeds the maximum number + * indicated by the caller, the method must return RESULT_TOO_BIG. + * + * Use this method only if the effect is provided by a third party, and + * there is no interface defined for it. This method only works for effects + * implemented in software. + * + * @param featureId feature identifier. + * @param maxConfigs maximum number of configs to return. + * @param configSize size of each config in bytes. + * @return retval operation completion status. + * @return configsCount number of configs returned. + * @return configsData data for all the configs returned. + */ + getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize) generates ( + Result retval, + uint32_t configsCount, + vec configsData); + + /** + * Get the current config for a vendor-specific feature. The config returned + * is not interpreted by Android Framework and is passed as-is between the + * application and the effect. + * + * The effect must use INVALID_ARGUMENTS return code if the feature ID is + * unknown. If the effect does not support getting vendor-specific + * feature configs, it must return NOT_SUPPORTED. + * + * Use this method only if the effect is provided by a third party, and + * there is no interface defined for it. This method only works for effects + * implemented in software. + * + * @param featureId feature identifier. + * @param configSize size of the config in bytes. + * @return retval operation completion status. + * @return configData config data. + */ + getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize) + generates (Result retval, vec configData); + + /** + * Set the current config for a vendor-specific feature. The config data + * is not interpreted by Android Framework and is passed as-is between the + * application and the effect. + * + * The effect must use INVALID_ARGUMENTS return code if the feature ID is + * unknown. If the effect does not support getting vendor-specific + * feature configs, it must return NOT_SUPPORTED. + * + * Use this method only if the effect is provided by a third party, and + * there is no interface defined for it. This method only works for effects + * implemented in software. + * + * @param featureId feature identifier. + * @param configData config data. + * @return retval operation completion status. + */ + setCurrentConfigForFeature(uint32_t featureId, vec configData) + generates (Result retval); + + /** + * Called by the framework to deinitialize the effect and free up + * all the currently allocated resources. It is recommended to close + * the effect on the client side as soon as it is becomes unused. + * + * @return retval OK in case the success. + * INVALID_STATE if the effect was already closed. + */ + @exit + close() generates (Result retval); +}; diff --git a/audio/effect/6.0/IEffectBufferProviderCallback.hal b/audio/effect/6.0/IEffectBufferProviderCallback.hal new file mode 100644 index 0000000000..097528de41 --- /dev/null +++ b/audio/effect/6.0/IEffectBufferProviderCallback.hal @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package android.hardware.audio.effect@6.0; + +/** + * This callback interface contains functions that can be used by the effect + * engine 'process' function to exchange input and output audio buffers. + */ +interface IEffectBufferProviderCallback { + /** + * Called to retrieve a buffer where data should read from by 'process' + * function. + * + * @return buffer audio buffer for processing + */ + getBuffer() generates (AudioBuffer buffer); + + /** + * Called to provide a buffer with the data written by 'process' function. + * + * @param buffer audio buffer for processing + */ + putBuffer(AudioBuffer buffer); +}; diff --git a/audio/effect/6.0/IEffectsFactory.hal b/audio/effect/6.0/IEffectsFactory.hal new file mode 100644 index 0000000000..e08b2deb4b --- /dev/null +++ b/audio/effect/6.0/IEffectsFactory.hal @@ -0,0 +1,58 @@ +/* + * 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. + */ + +package android.hardware.audio.effect@6.0; + +import android.hardware.audio.common@6.0; +import IEffect; + +interface IEffectsFactory { + /** + * Returns descriptors of different effects in all loaded libraries. + * + * @return retval operation completion status. + * @return result list of effect descriptors. + */ + getAllDescriptors() generates(Result retval, vec result); + + /** + * Returns a descriptor of a particular effect. + * + * @return retval operation completion status. + * @return result effect descriptor. + */ + getDescriptor(Uuid uid) generates(Result retval, EffectDescriptor result); + + /** + * Creates an effect engine of the specified type. To release the effect + * engine, it is necessary to release references to the returned effect + * object. + * + * @param uid effect uuid. + * @param session audio session to which this effect instance will be + * attached. All effects created with the same session ID + * are connected in series and process the same signal + * stream. + * @param ioHandle identifies the output or input stream this effect is + * directed to in audio HAL. + * @return retval operation completion status. + * @return result the interface for the created effect. + * @return effectId the unique ID of the effect to be used with + * IStream::addEffect and IStream::removeEffect methods. + */ + createEffect(Uuid uid, AudioSession session, AudioIoHandle ioHandle) + generates (Result retval, IEffect result, uint64_t effectId); +}; diff --git a/audio/effect/6.0/IEnvironmentalReverbEffect.hal b/audio/effect/6.0/IEnvironmentalReverbEffect.hal new file mode 100644 index 0000000000..8887533478 --- /dev/null +++ b/audio/effect/6.0/IEnvironmentalReverbEffect.hal @@ -0,0 +1,178 @@ +/* + * 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. + */ + +package android.hardware.audio.effect@6.0; + +import android.hardware.audio.common@6.0; +import IEffect; + +interface IEnvironmentalReverbEffect extends IEffect { + /** + * Sets whether the effect should be bypassed. + */ + setBypass(bool bypass) generates (Result retval); + + /** + * Gets whether the effect should be bypassed. + */ + getBypass() generates (Result retval, bool bypass); + + enum ParamRange : int16_t { + ROOM_LEVEL_MIN = -6000, + ROOM_LEVEL_MAX = 0, + ROOM_HF_LEVEL_MIN = -4000, + ROOM_HF_LEVEL_MAX = 0, + DECAY_TIME_MIN = 100, + DECAY_TIME_MAX = 20000, + DECAY_HF_RATIO_MIN = 100, + DECAY_HF_RATIO_MAX = 1000, + REFLECTIONS_LEVEL_MIN = -6000, + REFLECTIONS_LEVEL_MAX = 0, + REFLECTIONS_DELAY_MIN = 0, + REFLECTIONS_DELAY_MAX = 65, + REVERB_LEVEL_MIN = -6000, + REVERB_LEVEL_MAX = 0, + REVERB_DELAY_MIN = 0, + REVERB_DELAY_MAX = 65, + DIFFUSION_MIN = 0, + DIFFUSION_MAX = 1000, + DENSITY_MIN = 0, + DENSITY_MAX = 1000 + }; + + /** + * Sets the room level. + */ + setRoomLevel(int16_t roomLevel) generates (Result retval); + + /** + * Gets the room level. + */ + getRoomLevel() generates (Result retval, int16_t roomLevel); + + /** + * Sets the room high frequencies level. + */ + setRoomHfLevel(int16_t roomHfLevel) generates (Result retval); + + /** + * Gets the room high frequencies level. + */ + getRoomHfLevel() generates (Result retval, int16_t roomHfLevel); + + /** + * Sets the room decay time. + */ + setDecayTime(uint32_t decayTime) generates (Result retval); + + /** + * Gets the room decay time. + */ + getDecayTime() generates (Result retval, uint32_t decayTime); + + /** + * Sets the ratio of high frequencies decay. + */ + setDecayHfRatio(int16_t decayHfRatio) generates (Result retval); + + /** + * Gets the ratio of high frequencies decay. + */ + getDecayHfRatio() generates (Result retval, int16_t decayHfRatio); + + /** + * Sets the level of reflections in the room. + */ + setReflectionsLevel(int16_t reflectionsLevel) generates (Result retval); + + /** + * Gets the level of reflections in the room. + */ + getReflectionsLevel() generates (Result retval, int16_t reflectionsLevel); + + /** + * Sets the reflections delay in the room. + */ + setReflectionsDelay(uint32_t reflectionsDelay) generates (Result retval); + + /** + * Gets the reflections delay in the room. + */ + getReflectionsDelay() generates (Result retval, uint32_t reflectionsDelay); + + /** + * Sets the reverb level of the room. + */ + setReverbLevel(int16_t reverbLevel) generates (Result retval); + + /** + * Gets the reverb level of the room. + */ + getReverbLevel() generates (Result retval, int16_t reverbLevel); + + /** + * Sets the reverb delay of the room. + */ + setReverbDelay(uint32_t reverDelay) generates (Result retval); + + /** + * Gets the reverb delay of the room. + */ + getReverbDelay() generates (Result retval, uint32_t reverbDelay); + + /** + * Sets room diffusion. + */ + setDiffusion(int16_t diffusion) generates (Result retval); + + /** + * Gets room diffusion. + */ + getDiffusion() generates (Result retval, int16_t diffusion); + + /** + * Sets room wall density. + */ + setDensity(int16_t density) generates (Result retval); + + /** + * Gets room wall density. + */ + getDensity() generates (Result retval, int16_t density); + + struct AllProperties { + int16_t roomLevel; // in millibels, range -6000 to 0 + int16_t roomHfLevel; // in millibels, range -4000 to 0 + uint32_t decayTime; // in milliseconds, range 100 to 20000 + int16_t decayHfRatio; // in permilles, range 100 to 1000 + int16_t reflectionsLevel; // in millibels, range -6000 to 0 + uint32_t reflectionsDelay; // in milliseconds, range 0 to 65 + int16_t reverbLevel; // in millibels, range -6000 to 0 + uint32_t reverbDelay; // in milliseconds, range 0 to 65 + int16_t diffusion; // in permilles, range 0 to 1000 + int16_t density; // in permilles, range 0 to 1000 + }; + + /** + * Sets all properties at once. + */ + setAllProperties(AllProperties properties) generates (Result retval); + + /** + * Gets all properties at once. + */ + getAllProperties() generates (Result retval, AllProperties properties); +}; diff --git a/audio/effect/6.0/IEqualizerEffect.hal b/audio/effect/6.0/IEqualizerEffect.hal new file mode 100644 index 0000000000..962d518e4d --- /dev/null +++ b/audio/effect/6.0/IEqualizerEffect.hal @@ -0,0 +1,93 @@ +/* + * 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. + */ + +package android.hardware.audio.effect@6.0; + +import android.hardware.audio.common@6.0; +import IEffect; + +interface IEqualizerEffect extends IEffect { + /** + * Gets the number of frequency bands that the equalizer supports. + */ + getNumBands() generates (Result retval, uint16_t numBands); + + /** + * Returns the minimum and maximum band levels supported. + */ + getLevelRange() + generates (Result retval, int16_t minLevel, int16_t maxLevel); + + /** + * Sets the gain for the given equalizer band. + */ + setBandLevel(uint16_t band, int16_t level) generates (Result retval); + + /** + * Gets the gain for the given equalizer band. + */ + getBandLevel(uint16_t band) generates (Result retval, int16_t level); + + /** + * Gets the center frequency of the given band, in milliHertz. + */ + getBandCenterFrequency(uint16_t band) + generates (Result retval, uint32_t centerFreqmHz); + + /** + * Gets the frequency range of the given frequency band, in milliHertz. + */ + getBandFrequencyRange(uint16_t band) + generates (Result retval, uint32_t minFreqmHz, uint32_t maxFreqmHz); + + /** + * Gets the band that has the most effect on the given frequency + * in milliHertz. + */ + getBandForFrequency(uint32_t freqmHz) + generates (Result retval, uint16_t band); + + /** + * Gets the names of all presets the equalizer supports. + */ + getPresetNames() generates (Result retval, vec names); + + /** + * Sets the current preset using the index of the preset in the names + * vector returned via 'getPresetNames'. + */ + setCurrentPreset(uint16_t preset) generates (Result retval); + + /** + * Gets the current preset. + */ + getCurrentPreset() generates (Result retval, uint16_t preset); + + struct AllProperties { + uint16_t curPreset; + vec bandLevels; + }; + + /** + * Sets all properties at once. + */ + setAllProperties(AllProperties properties) generates (Result retval); + + /** + * Gets all properties at once. + */ + getAllProperties() generates (Result retval, AllProperties properties); +}; diff --git a/audio/effect/6.0/ILoudnessEnhancerEffect.hal b/audio/effect/6.0/ILoudnessEnhancerEffect.hal new file mode 100644 index 0000000000..73dc818909 --- /dev/null +++ b/audio/effect/6.0/ILoudnessEnhancerEffect.hal @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package android.hardware.audio.effect@6.0; + +import android.hardware.audio.common@6.0; +import IEffect; + +interface ILoudnessEnhancerEffect extends IEffect { + /** + * Sets target gain expressed in millibels. + */ + setTargetGain(int32_t targetGainMb) generates (Result retval); + + /** + * Gets target gain expressed in millibels. + */ + getTargetGain() generates (Result retval, int32_t targetGainMb); +}; diff --git a/audio/effect/6.0/INoiseSuppressionEffect.hal b/audio/effect/6.0/INoiseSuppressionEffect.hal new file mode 100644 index 0000000000..16dee57397 --- /dev/null +++ b/audio/effect/6.0/INoiseSuppressionEffect.hal @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package android.hardware.audio.effect@6.0; + +import android.hardware.audio.common@6.0; +import IEffect; + +interface INoiseSuppressionEffect extends IEffect { + enum Level : int32_t { + LOW, + MEDIUM, + HIGH + }; + + /** + * Sets suppression level. + */ + setSuppressionLevel(Level level) generates (Result retval); + + /** + * Gets suppression level. + */ + getSuppressionLevel() generates (Result retval, Level level); + + enum Type : int32_t { + SINGLE_CHANNEL, + MULTI_CHANNEL + }; + + /** + * Set suppression type. + */ + setSuppressionType(Type type) generates (Result retval); + + /** + * Get suppression type. + */ + getSuppressionType() generates (Result retval, Type type); + + struct AllProperties { + Level level; + Type type; + }; + + /** + * Sets all properties at once. + */ + setAllProperties(AllProperties properties) generates (Result retval); + + /** + * Gets all properties at once. + */ + getAllProperties() generates (Result retval, AllProperties properties); +}; diff --git a/audio/effect/6.0/IPresetReverbEffect.hal b/audio/effect/6.0/IPresetReverbEffect.hal new file mode 100644 index 0000000000..d00c8af00a --- /dev/null +++ b/audio/effect/6.0/IPresetReverbEffect.hal @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package android.hardware.audio.effect@6.0; + +import android.hardware.audio.common@6.0; +import IEffect; + +interface IPresetReverbEffect extends IEffect { + enum Preset : int32_t { + NONE, // no reverb or reflections + SMALLROOM, // a small room less than five meters in length + MEDIUMROOM, // a medium room with a length of ten meters or less + LARGEROOM, // a large-sized room suitable for live performances + MEDIUMHALL, // a medium-sized hall + LARGEHALL, // a large-sized hall suitable for a full orchestra + PLATE, // synthesis of the traditional plate reverb + LAST = PLATE + }; + + /** + * Sets the current preset. + */ + setPreset(Preset preset) generates (Result retval); + + /** + * Gets the current preset. + */ + getPreset() generates (Result retval, Preset preset); +}; diff --git a/audio/effect/6.0/IVirtualizerEffect.hal b/audio/effect/6.0/IVirtualizerEffect.hal new file mode 100644 index 0000000000..5967b33db2 --- /dev/null +++ b/audio/effect/6.0/IVirtualizerEffect.hal @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package android.hardware.audio.effect@6.0; + +import android.hardware.audio.common@6.0; +import IEffect; + +interface IVirtualizerEffect extends IEffect { + /** + * Returns whether setting virtualization strength is supported. + */ + isStrengthSupported() generates (bool strengthSupported); + + enum StrengthRange : uint16_t { + MIN = 0, + MAX = 1000 + }; + + /** + * Sets virtualization strength. + * + * @param strength strength of the effect. The valid range for strength + * strength is [0, 1000], where 0 per mille designates the + * mildest effect and 1000 per mille designates the + * strongest. + * @return retval operation completion status. + */ + setStrength(uint16_t strength) generates (Result retval); + + /** + * Gets virtualization strength. + */ + getStrength() generates (Result retval, uint16_t strength); + + struct SpeakerAngle { + /** Speaker channel mask */ + bitfield mask; + // all angles are expressed in degrees and + // are relative to the listener. + int16_t azimuth; // 0 is the direction the listener faces + // 180 is behind the listener + // -90 is to their left + int16_t elevation; // 0 is the horizontal plane + // +90 is above the listener, -90 is below + }; + /** + * Retrieves virtual speaker angles for the given channel mask on the + * specified device. + */ + getVirtualSpeakerAngles(bitfield mask, AudioDevice device) + generates (Result retval, vec speakerAngles); + + /** + * Forces the virtualizer effect for the given output device. + */ + forceVirtualizationMode(AudioDevice device) generates (Result retval); + + /** + * Returns audio device reflecting the current virtualization mode, + * AUDIO_DEVICE_NONE when not virtualizing. + */ + getVirtualizationMode() generates (Result retval, AudioDevice device); +}; diff --git a/audio/effect/6.0/IVisualizerEffect.hal b/audio/effect/6.0/IVisualizerEffect.hal new file mode 100644 index 0000000000..3df3e6f491 --- /dev/null +++ b/audio/effect/6.0/IVisualizerEffect.hal @@ -0,0 +1,110 @@ +/* + * 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. + */ + +package android.hardware.audio.effect@6.0; + +import android.hardware.audio.common@6.0; +import IEffect; + +interface IVisualizerEffect extends IEffect { + enum CaptureSizeRange : int32_t { + MAX = 1024, // maximum capture size in samples + MIN = 128 // minimum capture size in samples + }; + + /** + * Sets the number PCM samples in the capture. + */ + setCaptureSize(uint16_t captureSize) generates (Result retval); + + /** + * Gets the number PCM samples in the capture. + */ + getCaptureSize() generates (Result retval, uint16_t captureSize); + + enum ScalingMode : int32_t { + // Keep in sync with SCALING_MODE_... in + // frameworks/base/media/java/android/media/audiofx/Visualizer.java + NORMALIZED = 0, + AS_PLAYED = 1 + }; + + /** + * Specifies the way the captured data is scaled. + */ + setScalingMode(ScalingMode scalingMode) generates (Result retval); + + /** + * Retrieves the way the captured data is scaled. + */ + getScalingMode() generates (Result retval, ScalingMode scalingMode); + + /** + * Informs the visualizer about the downstream latency. + */ + setLatency(uint32_t latencyMs) generates (Result retval); + + /** + * Gets the downstream latency. + */ + getLatency() generates (Result retval, uint32_t latencyMs); + + enum MeasurementMode : int32_t { + // Keep in sync with MEASUREMENT_MODE_... in + // frameworks/base/media/java/android/media/audiofx/Visualizer.java + NONE = 0x0, + PEAK_RMS = 0x1 + }; + + /** + * Specifies which measurements are to be made. + */ + setMeasurementMode(MeasurementMode measurementMode) + generates (Result retval); + + /** + * Retrieves which measurements are to be made. + */ + getMeasurementMode() generates ( + Result retval, MeasurementMode measurementMode); + + /** + * Retrieves the latest PCM snapshot captured by the visualizer engine. The + * number of samples to capture is specified by 'setCaptureSize' parameter. + * + * @return retval operation completion status. + * @return samples samples in 8 bit unsigned format (0 = 0x80) + */ + capture() generates (Result retval, vec samples); + + struct Measurement { + MeasurementMode mode; // discriminator + union Values { + struct PeakAndRms { + int32_t peakMb; // millibels + int32_t rmsMb; // millibels + } peakAndRms; + } value; + }; + /** + * Retrieves the latest measurements. The measurements to be made + * are specified by 'setMeasurementMode' parameter. + * + * @return retval operation completion status. + * @return result measurement. + */ + measure() generates (Result retval, Measurement result); +}; diff --git a/audio/effect/6.0/types.hal b/audio/effect/6.0/types.hal new file mode 100644 index 0000000000..dd5a4ad5ab --- /dev/null +++ b/audio/effect/6.0/types.hal @@ -0,0 +1,301 @@ +/* + * 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. + */ + +package android.hardware.audio.effect@6.0; + +import android.hardware.audio.common@6.0; + +enum Result : int32_t { + OK, + NOT_INITIALIZED, + INVALID_ARGUMENTS, + INVALID_STATE, + NOT_SUPPORTED, + RESULT_TOO_BIG +}; + +/** + * Effect engine capabilities/requirements flags. + * + * Definitions for flags field of effect descriptor. + * + * +----------------+--------+-------------------------------------------------- + * | description | bits | values + * +----------------+--------+-------------------------------------------------- + * | connection | 0..2 | 0 insert: after track process + * | mode | | 1 auxiliary: connect to track auxiliary + * | | | output and use send level + * | | | 2 replace: replaces track process function; + * | | | must implement SRC, volume and mono to stereo. + * | | | 3 pre processing: applied below audio HAL on in + * | | | 4 post processing: applied below audio HAL on out + * | | | 5 - 7 reserved + * +----------------+--------+-------------------------------------------------- + * | insertion | 3..5 | 0 none + * | preference | | 1 first of the chain + * | | | 2 last of the chain + * | | | 3 exclusive (only effect in the insert chain) + * | | | 4..7 reserved + * +----------------+--------+-------------------------------------------------- + * | Volume | 6..8 | 0 none + * | management | | 1 implements volume control + * | | | 2 requires volume indication + * | | | 3 monitors requested volume + * | | | 4 reserved + * +----------------+--------+-------------------------------------------------- + * | Device | 9..11 | 0 none + * | indication | | 1 requires device updates + * | | | 2, 4 reserved + * +----------------+--------+-------------------------------------------------- + * | Sample input | 12..13 | 1 direct: process() function or + * | mode | | EFFECT_CMD_SET_CONFIG command must specify + * | | | a buffer descriptor + * | | | 2 provider: process() function uses the + * | | | bufferProvider indicated by the + * | | | EFFECT_CMD_SET_CONFIG command to request input. + * | | | buffers. + * | | | 3 both: both input modes are supported + * +----------------+--------+-------------------------------------------------- + * | Sample output | 14..15 | 1 direct: process() function or + * | mode | | EFFECT_CMD_SET_CONFIG command must specify + * | | | a buffer descriptor + * | | | 2 provider: process() function uses the + * | | | bufferProvider indicated by the + * | | | EFFECT_CMD_SET_CONFIG command to request output + * | | | buffers. + * | | | 3 both: both output modes are supported + * +----------------+--------+-------------------------------------------------- + * | Hardware | 16..17 | 0 No hardware acceleration + * | acceleration | | 1 non tunneled hw acceleration: the process() + * | | | function reads the samples, send them to HW + * | | | accelerated effect processor, reads back + * | | | the processed samples and returns them + * | | | to the output buffer. + * | | | 2 tunneled hw acceleration: the process() + * | | | function is transparent. The effect interface + * | | | is only used to control the effect engine. + * | | | This mode is relevant for global effects + * | | | actually applied by the audio hardware on + * | | | the output stream. + * +----------------+--------+-------------------------------------------------- + * | Audio Mode | 18..19 | 0 none + * | indication | | 1 requires audio mode updates + * | | | 2..3 reserved + * +----------------+--------+-------------------------------------------------- + * | Audio source | 20..21 | 0 none + * | indication | | 1 requires audio source updates + * | | | 2..3 reserved + * +----------------+--------+-------------------------------------------------- + * | Effect offload | 22 | 0 The effect cannot be offloaded to an audio DSP + * | supported | | 1 The effect can be offloaded to an audio DSP + * +----------------+--------+-------------------------------------------------- + * | Process | 23 | 0 The effect implements a process function. + * | function | | 1 The effect does not implement a process + * | not | | function: enabling the effect has no impact + * | implemented | | on latency or CPU load. + * | | | Effect implementations setting this flag do not + * | | | have to implement a process function. + * +----------------+--------+-------------------------------------------------- + */ +@export(name="", value_prefix="EFFECT_FLAG_") +enum EffectFlags : int32_t { + // Insert mode + TYPE_SHIFT = 0, + TYPE_SIZE = 3, + TYPE_MASK = ((1 << TYPE_SIZE) -1) << TYPE_SHIFT, + TYPE_INSERT = 0 << TYPE_SHIFT, + TYPE_AUXILIARY = 1 << TYPE_SHIFT, + TYPE_REPLACE = 2 << TYPE_SHIFT, + TYPE_PRE_PROC = 3 << TYPE_SHIFT, + TYPE_POST_PROC = 4 << TYPE_SHIFT, + + // Insert preference + INSERT_SHIFT = TYPE_SHIFT + TYPE_SIZE, + INSERT_SIZE = 3, + INSERT_MASK = ((1 << INSERT_SIZE) -1) << INSERT_SHIFT, + INSERT_ANY = 0 << INSERT_SHIFT, + INSERT_FIRST = 1 << INSERT_SHIFT, + INSERT_LAST = 2 << INSERT_SHIFT, + INSERT_EXCLUSIVE = 3 << INSERT_SHIFT, + + // Volume control + VOLUME_SHIFT = INSERT_SHIFT + INSERT_SIZE, + VOLUME_SIZE = 3, + VOLUME_MASK = ((1 << VOLUME_SIZE) -1) << VOLUME_SHIFT, + VOLUME_CTRL = 1 << VOLUME_SHIFT, + VOLUME_IND = 2 << VOLUME_SHIFT, + VOLUME_MONITOR = 3 << VOLUME_SHIFT, + VOLUME_NONE = 0 << VOLUME_SHIFT, + + // Device indication + DEVICE_SHIFT = VOLUME_SHIFT + VOLUME_SIZE, + DEVICE_SIZE = 3, + DEVICE_MASK = ((1 << DEVICE_SIZE) -1) << DEVICE_SHIFT, + DEVICE_IND = 1 << DEVICE_SHIFT, + DEVICE_NONE = 0 << DEVICE_SHIFT, + + // Sample input modes + INPUT_SHIFT = DEVICE_SHIFT + DEVICE_SIZE, + INPUT_SIZE = 2, + INPUT_MASK = ((1 << INPUT_SIZE) -1) << INPUT_SHIFT, + INPUT_DIRECT = 1 << INPUT_SHIFT, + INPUT_PROVIDER = 2 << INPUT_SHIFT, + INPUT_BOTH = 3 << INPUT_SHIFT, + + // Sample output modes + OUTPUT_SHIFT = INPUT_SHIFT + INPUT_SIZE, + OUTPUT_SIZE = 2, + OUTPUT_MASK = ((1 << OUTPUT_SIZE) -1) << OUTPUT_SHIFT, + OUTPUT_DIRECT = 1 << OUTPUT_SHIFT, + OUTPUT_PROVIDER = 2 << OUTPUT_SHIFT, + OUTPUT_BOTH = 3 << OUTPUT_SHIFT, + + // Hardware acceleration mode + HW_ACC_SHIFT = OUTPUT_SHIFT + OUTPUT_SIZE, + HW_ACC_SIZE = 2, + HW_ACC_MASK = ((1 << HW_ACC_SIZE) -1) << HW_ACC_SHIFT, + HW_ACC_SIMPLE = 1 << HW_ACC_SHIFT, + HW_ACC_TUNNEL = 2 << HW_ACC_SHIFT, + + // Audio mode indication + AUDIO_MODE_SHIFT = HW_ACC_SHIFT + HW_ACC_SIZE, + AUDIO_MODE_SIZE = 2, + AUDIO_MODE_MASK = ((1 << AUDIO_MODE_SIZE) -1) << AUDIO_MODE_SHIFT, + AUDIO_MODE_IND = 1 << AUDIO_MODE_SHIFT, + AUDIO_MODE_NONE = 0 << AUDIO_MODE_SHIFT, + + // Audio source indication + AUDIO_SOURCE_SHIFT = AUDIO_MODE_SHIFT + AUDIO_MODE_SIZE, + AUDIO_SOURCE_SIZE = 2, + AUDIO_SOURCE_MASK = ((1 << AUDIO_SOURCE_SIZE) -1) << AUDIO_SOURCE_SHIFT, + AUDIO_SOURCE_IND = 1 << AUDIO_SOURCE_SHIFT, + AUDIO_SOURCE_NONE = 0 << AUDIO_SOURCE_SHIFT, + + // Effect offload indication + OFFLOAD_SHIFT = AUDIO_SOURCE_SHIFT + AUDIO_SOURCE_SIZE, + OFFLOAD_SIZE = 1, + OFFLOAD_MASK = ((1 << OFFLOAD_SIZE) -1) << OFFLOAD_SHIFT, + OFFLOAD_SUPPORTED = 1 << OFFLOAD_SHIFT, + + // Effect has no process indication + NO_PROCESS_SHIFT = OFFLOAD_SHIFT + OFFLOAD_SIZE, + NO_PROCESS_SIZE = 1, + NO_PROCESS_MASK = ((1 << NO_PROCESS_SIZE) -1) << NO_PROCESS_SHIFT, + NO_PROCESS = 1 << NO_PROCESS_SHIFT +}; + +/** + * The effect descriptor contains necessary information to facilitate the + * enumeration of the effect engines present in a library. + */ +struct EffectDescriptor { + Uuid type; // UUID of to the OpenSL ES interface implemented + // by this effect + Uuid uuid; // UUID for this particular implementation + bitfield flags; // effect engine capabilities/requirements flags + uint16_t cpuLoad; // CPU load indication expressed in 0.1 MIPS units + // as estimated on an ARM9E core (ARMv5TE) with 0 WS + uint16_t memoryUsage; // data memory usage expressed in KB and includes + // only dynamically allocated memory + uint8_t[64] name; // human readable effect name + uint8_t[64] implementor; // human readable effect implementor name +}; + +/** + * A buffer is a chunk of audio data for processing. Multi-channel audio is + * always interleaved. The channel order is from LSB to MSB with regard to the + * channel mask definition in audio.h, audio_channel_mask_t, e.g.: + * Stereo: L, R; 5.1: FL, FR, FC, LFE, BL, BR. + * + * The buffer size is expressed in frame count, a frame being composed of + * samples for all channels at a given time. Frame size for unspecified format + * (AUDIO_FORMAT_OTHER) is 8 bit by definition. + */ +struct AudioBuffer { + uint64_t id; + uint32_t frameCount; + memory data; +}; + +@export(name="effect_buffer_access_e", value_prefix="EFFECT_BUFFER_") +enum EffectBufferAccess : int32_t { + ACCESS_WRITE, + ACCESS_READ, + ACCESS_ACCUMULATE +}; + +/** + * Determines what fields of EffectBufferConfig need to be considered. + */ +@export(name="", value_prefix="EFFECT_CONFIG_") +enum EffectConfigParameters : int32_t { + BUFFER = 0x0001, // buffer field + SMP_RATE = 0x0002, // samplingRate + CHANNELS = 0x0004, // channels + FORMAT = 0x0008, // format + ACC_MODE = 0x0010, // accessMode + // Note that the 2.0 ALL have been moved to an helper function +}; + +/** + * The buffer config structure specifies the input or output audio format + * to be used by the effect engine. + */ +struct EffectBufferConfig { + AudioBuffer buffer; + uint32_t samplingRateHz; + bitfield channels; + AudioFormat format; + EffectBufferAccess accessMode; + bitfield mask; +}; + +struct EffectConfig { + EffectBufferConfig inputCfg; + EffectBufferConfig outputCfg; +}; + +@export(name="effect_feature_e", value_prefix="EFFECT_FEATURE_") +enum EffectFeature : int32_t { + AUX_CHANNELS, // supports auxiliary channels + // (e.g. dual mic noise suppressor) + CNT +}; + +struct EffectAuxChannelsConfig { + bitfield mainChannels; // channel mask for main channels + bitfield auxChannels; // channel mask for auxiliary channels +}; + +struct EffectOffloadParameter { + bool isOffload; // true if the playback thread the effect + // is attached to is offloaded + AudioIoHandle ioHandle; // io handle of the playback thread + // the effect is attached to +}; + +/** + * The message queue flags used to synchronize reads and writes from + * the status message queue used by effects. + */ +enum MessageQueueFlagBits : uint32_t { + DONE_PROCESSING = 1 << 0, + REQUEST_PROCESS = 1 << 1, + REQUEST_PROCESS_REVERSE = 1 << 2, + REQUEST_QUIT = 1 << 3, + REQUEST_PROCESS_ALL = + REQUEST_PROCESS | REQUEST_PROCESS_REVERSE | REQUEST_QUIT +}; diff --git a/audio/effect/6.0/xml/Android.bp b/audio/effect/6.0/xml/Android.bp new file mode 100644 index 0000000000..353686bd32 --- /dev/null +++ b/audio/effect/6.0/xml/Android.bp @@ -0,0 +1,6 @@ + +xsd_config { + name: "audio_effects_conf_V6_0", + srcs: ["audio_effects_conf.xsd"], + package_name: "audio.effects.V6_0", +} diff --git a/audio/effect/6.0/xml/api/current.txt b/audio/effect/6.0/xml/api/current.txt new file mode 100644 index 0000000000..2021639630 --- /dev/null +++ b/audio/effect/6.0/xml/api/current.txt @@ -0,0 +1,132 @@ +// Signature format: 2.0 +package audio.effects.V6_0 { + + public class AudioEffectsConf { + ctor public AudioEffectsConf(); + method public audio.effects.V6_0.EffectsType getEffects(); + method public audio.effects.V6_0.LibrariesType getLibraries(); + method public audio.effects.V6_0.AudioEffectsConf.Postprocess getPostprocess(); + method public audio.effects.V6_0.AudioEffectsConf.Preprocess getPreprocess(); + method public audio.effects.V6_0.VersionType getVersion(); + method public void setEffects(audio.effects.V6_0.EffectsType); + method public void setLibraries(audio.effects.V6_0.LibrariesType); + method public void setPostprocess(audio.effects.V6_0.AudioEffectsConf.Postprocess); + method public void setPreprocess(audio.effects.V6_0.AudioEffectsConf.Preprocess); + method public void setVersion(audio.effects.V6_0.VersionType); + } + + public static class AudioEffectsConf.Postprocess { + ctor public AudioEffectsConf.Postprocess(); + method public java.util.List getStream(); + } + + public static class AudioEffectsConf.Preprocess { + ctor public AudioEffectsConf.Preprocess(); + method public java.util.List getStream(); + } + + public class EffectImplType { + ctor public EffectImplType(); + method public String getLibrary(); + method public String getUuid(); + method public void setLibrary(String); + method public void setUuid(String); + } + + public class EffectProxyType extends audio.effects.V6_0.EffectType { + ctor public EffectProxyType(); + method public audio.effects.V6_0.EffectImplType getLibhw(); + method public audio.effects.V6_0.EffectImplType getLibsw(); + method public void setLibhw(audio.effects.V6_0.EffectImplType); + method public void setLibsw(audio.effects.V6_0.EffectImplType); + } + + public class EffectType extends audio.effects.V6_0.EffectImplType { + ctor public EffectType(); + method public String getName(); + method public void setName(String); + } + + public class EffectsType { + ctor public EffectsType(); + method public java.util.List getEffectProxy_optional(); + method public java.util.List getEffect_optional(); + } + + public class LibrariesType { + ctor public LibrariesType(); + method public java.util.List getLibrary(); + } + + public static class LibrariesType.Library { + ctor public LibrariesType.Library(); + method public String getName(); + method public String getPath(); + method public void setName(String); + method public void setPath(String); + } + + public enum StreamInputType { + method public String getRawName(); + enum_constant public static final audio.effects.V6_0.StreamInputType camcorder; + enum_constant public static final audio.effects.V6_0.StreamInputType mic; + enum_constant public static final audio.effects.V6_0.StreamInputType unprocessed; + enum_constant public static final audio.effects.V6_0.StreamInputType voice_call; + enum_constant public static final audio.effects.V6_0.StreamInputType voice_communication; + enum_constant public static final audio.effects.V6_0.StreamInputType voice_downlink; + enum_constant public static final audio.effects.V6_0.StreamInputType voice_performance; + enum_constant public static final audio.effects.V6_0.StreamInputType voice_recognition; + enum_constant public static final audio.effects.V6_0.StreamInputType voice_uplink; + } + + public enum StreamOutputType { + method public String getRawName(); + enum_constant public static final audio.effects.V6_0.StreamOutputType alarm; + enum_constant public static final audio.effects.V6_0.StreamOutputType bluetooth_sco; + enum_constant public static final audio.effects.V6_0.StreamOutputType dtmf; + enum_constant public static final audio.effects.V6_0.StreamOutputType enforced_audible; + enum_constant public static final audio.effects.V6_0.StreamOutputType music; + enum_constant public static final audio.effects.V6_0.StreamOutputType notification; + enum_constant public static final audio.effects.V6_0.StreamOutputType ring; + enum_constant public static final audio.effects.V6_0.StreamOutputType system; + enum_constant public static final audio.effects.V6_0.StreamOutputType tts; + enum_constant public static final audio.effects.V6_0.StreamOutputType voice_call; + } + + public class StreamPostprocessType extends audio.effects.V6_0.StreamProcessingType { + ctor public StreamPostprocessType(); + method public audio.effects.V6_0.StreamOutputType getType(); + method public void setType(audio.effects.V6_0.StreamOutputType); + } + + public class StreamPreprocessType extends audio.effects.V6_0.StreamProcessingType { + ctor public StreamPreprocessType(); + method public audio.effects.V6_0.StreamInputType getType(); + method public void setType(audio.effects.V6_0.StreamInputType); + } + + public class StreamProcessingType { + ctor public StreamProcessingType(); + method public java.util.List getApply(); + } + + public static class StreamProcessingType.Apply { + ctor public StreamProcessingType.Apply(); + method public String getEffect(); + method public void setEffect(String); + } + + public enum VersionType { + method public String getRawName(); + enum_constant public static final audio.effects.V6_0.VersionType _2_0; + } + + public class XmlParser { + ctor public XmlParser(); + method public static audio.effects.V6_0.AudioEffectsConf read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + } + +} + diff --git a/audio/effect/6.0/xml/api/last_current.txt b/audio/effect/6.0/xml/api/last_current.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/audio/effect/6.0/xml/api/last_removed.txt b/audio/effect/6.0/xml/api/last_removed.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/audio/effect/6.0/xml/api/removed.txt b/audio/effect/6.0/xml/api/removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/audio/effect/6.0/xml/api/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/audio/effect/6.0/xml/audio_effects_conf.xsd b/audio/effect/6.0/xml/audio_effects_conf.xsd new file mode 120000 index 0000000000..9d85fa7c68 --- /dev/null +++ b/audio/effect/6.0/xml/audio_effects_conf.xsd @@ -0,0 +1 @@ +../../2.0/xml/audio_effects_conf.xsd \ No newline at end of file diff --git a/audio/effect/all-versions/default/Android.bp b/audio/effect/all-versions/default/Android.bp index fdb12c1cf5..d9bb78b700 100644 --- a/audio/effect/all-versions/default/Android.bp +++ b/audio/effect/all-versions/default/Android.bp @@ -88,3 +88,18 @@ cc_library_shared { "-include common/all-versions/VersionMacro.h", ] } + +cc_library_shared { + name: "android.hardware.audio.effect@6.0-impl", + defaults: ["android.hardware.audio.effect-impl_default"], + shared_libs: [ + "android.hardware.audio.common@6.0", + "android.hardware.audio.common@6.0-util", + "android.hardware.audio.effect@6.0", + ], + cflags: [ + "-DMAJOR_VERSION=6", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} diff --git a/audio/effect/all-versions/vts/functional/Android.bp b/audio/effect/all-versions/vts/functional/Android.bp index cccb5c86aa..edc9076905 100644 --- a/audio/effect/all-versions/vts/functional/Android.bp +++ b/audio/effect/all-versions/vts/functional/Android.bp @@ -76,3 +76,16 @@ cc_test { ] } +cc_test { + name: "VtsHalAudioEffectV6_0TargetTest", + defaults: ["VtsHalAudioEffectTargetTest_default"], + static_libs: [ + "android.hardware.audio.common@6.0", + "android.hardware.audio.effect@6.0", + ], + cflags: [ + "-DMAJOR_VERSION=6", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} From e2fd183d62a5bdf7386151a3eeabf3a0828d58de Mon Sep 17 00:00:00 2001 From: Kevin Rocard Date: Thu, 3 Oct 2019 18:26:26 +0100 Subject: [PATCH 0153/1022] Allow device to have use Audio HAL V6 This HAL is optional for now as breaking changed are planned. It might get required for new device before R release. Test: push V6 to device and check audio works fine Bug: 134940862 Change-Id: Ib4a906da1c1d3d489003a6642bfc55b142424155 Signed-off-by: Kevin Rocard --- compatibility_matrices/compatibility_matrix.current.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index d4f53cd19a..d708b571db 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -10,6 +10,7 @@ android.hardware.audio 5.0 + 6.0 IDevicesFactory default @@ -18,6 +19,7 @@ android.hardware.audio.effect 5.0 + 6.0 IEffectsFactory default From 130bf68ccac8188ab91935ebbc6ca944436b5efd Mon Sep 17 00:00:00 2001 From: Kevin Rocard Date: Tue, 8 Oct 2019 11:09:46 +0100 Subject: [PATCH 0154/1022] Update README Bug: 134940862 Test: n/a Change-Id: I68e4f503147a236933e97bb96d777c6038282f46 Signed-off-by: Kevin Rocard --- audio/README | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/audio/README b/audio/README index abe979c0fa..afafbe32d2 100644 --- a/audio/README +++ b/audio/README @@ -1,5 +1,8 @@ Directory structure of the audio HIDL related code. +Run `common/all-versions/copyHAL.sh` to create a new version of the audio HAL +based on an existing one. + audio |-- 2.0 <== core 2.0 HIDL API. .hal can not be moved into the core directory | because that would change its namespace and include path @@ -11,13 +14,13 @@ audio | |-- 2.0 <== HIDL API of V2 | |-- 4.0 | |-- ... -| `-- all_versions <== code common to all version of both core and effect API +| `-- all-versions <== code common to all version of both core and effect API | |-- default <== implementation shared code between core and effect impl | |-- test <== utilities used by tests | `-- util <== utilities used by both implementation and tests | |-- core <== VTS and default implementation of the core API (not HIDL, see /audio/2.0)) -| `-- all_versions <== Code is version independent through #if and separate files +| `-- all-versions <== Code is version independent through #if and separate files | |-- default <== code that wraps the legacy API | `-- vts <== vts of core API | |-- 2.0 <== 2.0 specific tests and helpers @@ -28,6 +31,6 @@ audio |-- 2.0 |-- 4.0 |-- ... - `-- all_versions + `-- all-versions |-- default `-- vts From c919f9657eaaab19a050cf96a7b23e45a502fc89 Mon Sep 17 00:00:00 2001 From: Patrik Fimml Date: Wed, 11 Sep 2019 14:31:56 +0200 Subject: [PATCH 0155/1022] Add IWifiApIface@1.4 (configurable MAC address) Mirrors the methods and tests introduced in IWifiStaIface@1.2 and @1.3. Android.bp generated with $ hidl-gen -o . -Landroidbp -randroid.hardware:hardware/interfaces android.hardware.wifi@1.4 Bug: 132705022 Test: make vts && vts-tradefed run vts-host --skip-preconditions --primary-abi-only --module VtsHalWifiV1_4Host Change-Id: Iddacd2770c59522001673d10daafd3bbed3844f6 --- wifi/1.4/Android.bp | 1 + wifi/1.4/IWifiApIface.hal | 53 +++++++++++++ .../default/tests/wifi_chip_unit_tests.cpp | 5 +- wifi/1.4/default/wifi_ap_iface.cpp | 34 +++++++++ wifi/1.4/default/wifi_ap_iface.h | 11 ++- wifi/1.4/vts/OWNERS | 2 + wifi/1.4/vts/functional/Android.bp | 32 ++++++++ .../functional/VtsHalWifiV1_4TargetTest.cpp | 53 +++++++++++++ .../functional/wifi_ap_iface_hidl_test.cpp | 76 +++++++++++++++++++ 9 files changed, 263 insertions(+), 4 deletions(-) create mode 100644 wifi/1.4/IWifiApIface.hal create mode 100644 wifi/1.4/vts/OWNERS create mode 100644 wifi/1.4/vts/functional/Android.bp create mode 100644 wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp create mode 100644 wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp diff --git a/wifi/1.4/Android.bp b/wifi/1.4/Android.bp index a6ac020cbc..aba8b4443a 100644 --- a/wifi/1.4/Android.bp +++ b/wifi/1.4/Android.bp @@ -8,6 +8,7 @@ hidl_interface { }, srcs: [ "IWifi.hal", + "IWifiApIface.hal", ], interfaces: [ "android.hardware.wifi@1.0", diff --git a/wifi/1.4/IWifiApIface.hal b/wifi/1.4/IWifiApIface.hal new file mode 100644 index 0000000000..af88afbea0 --- /dev/null +++ b/wifi/1.4/IWifiApIface.hal @@ -0,0 +1,53 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi@1.4; + +import @1.0::IWifiApIface; +import @1.0::MacAddress; +import @1.0::WifiStatus; + +/** + * Represents a network interface in AP mode. + * + * This can be obtained through @1.0::IWifiChip.getApIface() and casting + * IWifiApIface up to 1.4. + */ +interface IWifiApIface extends @1.0::IWifiApIface { + /** + * Changes the MAC address of the interface to the given MAC address. + * + * @param mac MAC address to change to. + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|, + * |WifiStatusCode.ERROR_UNKNOWN| + */ + setMacAddress(MacAddress mac) generates (WifiStatus status); + + /** + * Gets the factory MAC address of the interface. + * + * @return status WifiStatus of the operation + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|, + * |WifiStatusCode.ERROR_UNKNOWN| + * @return mac factory MAC address of the interface + */ + getFactoryMacAddress() generates (WifiStatus status, MacAddress mac); +}; diff --git a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp index 2ad093ae69..b0357ba980 100644 --- a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp +++ b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp @@ -173,8 +173,9 @@ class WifiChipTest : public Test { std::string createIface(const IfaceType& type) { std::string iface_name; if (type == IfaceType::AP) { - chip_->createApIface([&iface_name](const WifiStatus& status, - const sp& iface) { + chip_->createApIface([&iface_name]( + const WifiStatus& status, + const sp& iface) { if (WifiStatusCode::SUCCESS == status.code) { ASSERT_NE(iface.get(), nullptr); iface->getName([&iface_name](const WifiStatus& status, diff --git a/wifi/1.4/default/wifi_ap_iface.cpp b/wifi/1.4/default/wifi_ap_iface.cpp index 13ce2dddcb..b8609106b6 100644 --- a/wifi/1.4/default/wifi_ap_iface.cpp +++ b/wifi/1.4/default/wifi_ap_iface.cpp @@ -85,6 +85,20 @@ Return WifiApIface::getValidFrequenciesForBand( hidl_status_cb, band); } +Return WifiApIface::setMacAddress(const hidl_array& mac, + setMacAddress_cb hidl_status_cb) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiApIface::setMacAddressInternal, hidl_status_cb, + mac); +} + +Return WifiApIface::getFactoryMacAddress( + getFactoryMacAddress_cb hidl_status_cb) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiApIface::getFactoryMacAddressInternal, + hidl_status_cb); +} + std::pair WifiApIface::getNameInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_}; } @@ -111,6 +125,26 @@ WifiApIface::getValidFrequenciesForBandInternal(WifiBand band) { ifname_, hidl_struct_util::convertHidlWifiBandToLegacy(band)); return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies}; } + +WifiStatus WifiApIface::setMacAddressInternal( + const std::array& mac) { + bool status = iface_util_.lock()->setMacAddress(ifname_, mac); + if (!status) { + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } + return createWifiStatus(WifiStatusCode::SUCCESS); +} + +std::pair> +WifiApIface::getFactoryMacAddressInternal() { + std::array mac = + iface_util_.lock()->getFactoryMacAddress(ifname_); + if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && + mac[4] == 0 && mac[5] == 0) { + return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), mac}; + } + return {createWifiStatus(WifiStatusCode::SUCCESS), mac}; +} } // namespace implementation } // namespace V1_4 } // namespace wifi diff --git a/wifi/1.4/default/wifi_ap_iface.h b/wifi/1.4/default/wifi_ap_iface.h index 179acacdaa..cb3ed3d29b 100644 --- a/wifi/1.4/default/wifi_ap_iface.h +++ b/wifi/1.4/default/wifi_ap_iface.h @@ -18,7 +18,7 @@ #define WIFI_AP_IFACE_H_ #include -#include +#include #include "wifi_feature_flags.h" #include "wifi_iface_util.h" @@ -34,7 +34,7 @@ using namespace android::hardware::wifi::V1_0; /** * HIDL interface object used to control a AP Iface instance. */ -class WifiApIface : public V1_0::IWifiApIface { +class WifiApIface : public V1_4::IWifiApIface { public: WifiApIface( const std::string& ifname, @@ -53,6 +53,10 @@ class WifiApIface : public V1_0::IWifiApIface { setCountryCode_cb hidl_status_cb) override; Return getValidFrequenciesForBand( WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) override; + Return setMacAddress(const hidl_array& mac, + setMacAddress_cb hidl_status_cb) override; + Return getFactoryMacAddress( + getFactoryMacAddress_cb hidl_status_cb) override; private: // Corresponding worker functions for the HIDL methods. @@ -61,6 +65,9 @@ class WifiApIface : public V1_0::IWifiApIface { WifiStatus setCountryCodeInternal(const std::array& code); std::pair> getValidFrequenciesForBandInternal(WifiBand band); + WifiStatus setMacAddressInternal(const std::array& mac); + std::pair> + getFactoryMacAddressInternal(); std::string ifname_; std::weak_ptr legacy_hal_; diff --git a/wifi/1.4/vts/OWNERS b/wifi/1.4/vts/OWNERS new file mode 100644 index 0000000000..8bfb14882c --- /dev/null +++ b/wifi/1.4/vts/OWNERS @@ -0,0 +1,2 @@ +rpius@google.com +etancohen@google.com diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp new file mode 100644 index 0000000000..859be89ee5 --- /dev/null +++ b/wifi/1.4/vts/functional/Android.bp @@ -0,0 +1,32 @@ +// +// 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. +// + +cc_test { + name: "VtsHalWifiV1_4TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "VtsHalWifiV1_4TargetTest.cpp", + "wifi_ap_iface_hidl_test.cpp", + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "android.hardware.wifi@1.0", + "android.hardware.wifi@1.1", + "android.hardware.wifi@1.2", + "android.hardware.wifi@1.3", + "android.hardware.wifi@1.4", + ], +} diff --git a/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp b/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp new file mode 100644 index 0000000000..26b93a6f08 --- /dev/null +++ b/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#include +#include + +#include "wifi_hidl_test_utils.h" + +using ::android::hardware::wifi::V1_4::IWifi; + +// Test environment for Wifi HIDL HAL. +class WifiHidlEnvironment_1_4 : public WifiHidlEnvironment { + public: + // get the test environment singleton + static WifiHidlEnvironment_1_4* Instance() { + static WifiHidlEnvironment_1_4* instance = new WifiHidlEnvironment_1_4; + return instance; + } + + virtual void registerTestServices() override { + registerTestService(); + } + + private: + WifiHidlEnvironment_1_4() {} +}; + +WifiHidlEnvironment_1_4* gEnv = WifiHidlEnvironment_1_4::Instance(); + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(gEnv); + ::testing::InitGoogleTest(&argc, argv); + gEnv->init(&argc, argv); + int status = gEnv->initFromOptions(argc, argv); + if (status == 0) { + status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + } + return status; +} diff --git a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp new file mode 100644 index 0000000000..c2c13941ea --- /dev/null +++ b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Staache 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 + +#include "wifi_hidl_call_util.h" +#include "wifi_hidl_test_utils.h" + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::wifi::V1_0::WifiStatus; +using ::android::hardware::wifi::V1_0::WifiStatusCode; +using ::android::hardware::wifi::V1_4::IWifiApIface; + +extern WifiHidlEnvironment* gEnv; + +/** + * Fixture to use for all STA Iface HIDL interface tests. + */ +class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + if (!gEnv->isSoftApOn) return; + wifi_ap_iface_ = IWifiApIface::castFrom(getWifiApIface()); + ASSERT_NE(nullptr, wifi_ap_iface_.get()); + } + + virtual void TearDown() override { + if (!gEnv->isSoftApOn) return; + stopWifi(); + } + + protected: + sp wifi_ap_iface_; +}; + +/* + * SetMacAddress: + * Ensures that calls to set MAC address will return a success status + * code. + */ +TEST_F(WifiApIfaceHidlTest, SetMacAddress) { + if (!gEnv->isSoftApOn) return; + const hidl_array kMac{{0x12, 0x22, 0x33, 0x52, 0x10, 0x41}}; + EXPECT_EQ(WifiStatusCode::SUCCESS, + HIDL_INVOKE(wifi_ap_iface_, setMacAddress, kMac).code); +} + +/* + * GetFactoryMacAddress: + * Ensures that calls to get factory MAC address will retrieve a non-zero MAC + * and return a success status code. + */ +TEST_F(WifiApIfaceHidlTest, GetFactoryMacAddress) { + if (!gEnv->isSoftApOn) return; + std::pair > status_and_mac = + HIDL_INVOKE(wifi_ap_iface_, getFactoryMacAddress); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mac.first.code); + hidl_array all_zero{}; + EXPECT_NE(all_zero, status_and_mac.second); +} From 859ec12b8d371a5f45377b5320504bb5511db5f4 Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Wed, 2 Oct 2019 18:42:57 -0700 Subject: [PATCH 0156/1022] Tuner HAL : patch comments and ATSC3 bug: 135708935 Test: Manual Change-Id: I2ccd19cba6e9a5fa6f9c61ca9a7ef13b7ab834e3 --- tv/tuner/1.0/IDemux.hal | 20 ++- tv/tuner/1.0/IDemuxCallback.hal | 16 +++ tv/tuner/1.0/IDescrambler.hal | 16 +++ tv/tuner/1.0/IFrontend.hal | 20 +-- tv/tuner/1.0/ILnb.hal | 18 +++ tv/tuner/1.0/ITuner.hal | 20 ++- tv/tuner/1.0/types.hal | 236 ++++++++++++++++++++++++++------ 7 files changed, 274 insertions(+), 72 deletions(-) diff --git a/tv/tuner/1.0/IDemux.hal b/tv/tuner/1.0/IDemux.hal index e03095b2e3..7ead34b00e 100644 --- a/tv/tuner/1.0/IDemux.hal +++ b/tv/tuner/1.0/IDemux.hal @@ -1,3 +1,19 @@ +/* + * 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. + */ + package android.hardware.tv.tuner@1.0; import IDemuxCallback; @@ -236,7 +252,7 @@ interface IDemux { * INVALID_STATE if failed for wrong state. * UNKNOWN_ERROR if failed for other reasons. */ - attachOutputTsFilter(DemuxFilterId filterId) generates (Result result); + attachOutputFilter(DemuxFilterId filterId) generates (Result result); /** * Detach one filter from the demux's output. @@ -250,7 +266,7 @@ interface IDemux { * INVALID_STATE if failed for wrong state. * UNKNOWN_ERROR if failed for other reasons. */ - detachOutputTsFilter(DemuxFilterId filterId) generates (Result result); + detachOutputFilter(DemuxFilterId filterId) generates (Result result); /** * Start to take data to the demux's output. diff --git a/tv/tuner/1.0/IDemuxCallback.hal b/tv/tuner/1.0/IDemuxCallback.hal index 55e84200ab..7bce9efeb1 100644 --- a/tv/tuner/1.0/IDemuxCallback.hal +++ b/tv/tuner/1.0/IDemuxCallback.hal @@ -1,3 +1,19 @@ +/* + * 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. + */ + package android.hardware.tv.tuner@1.0; interface IDemuxCallback { diff --git a/tv/tuner/1.0/IDescrambler.hal b/tv/tuner/1.0/IDescrambler.hal index d078657d65..61ff1df4bd 100644 --- a/tv/tuner/1.0/IDescrambler.hal +++ b/tv/tuner/1.0/IDescrambler.hal @@ -1,3 +1,19 @@ +/* + * 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. + */ + package android.hardware.tv.tuner@1.0; /** * Descrambler is used to descramble input data. diff --git a/tv/tuner/1.0/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal index 8788643344..d337ac1b81 100644 --- a/tv/tuner/1.0/IFrontend.hal +++ b/tv/tuner/1.0/IFrontend.hal @@ -145,7 +145,7 @@ interface IFrontend { * cable frontend. * UNKNOWN_ERROR if failed for other reasons. */ - setLnb(ILnb lnb) generates (Result result); + setLnb(LnbId lnbId) generates (Result result); /** * Enble or Disable Low Noise Amplifier (LNA). @@ -158,22 +158,4 @@ interface IFrontend { * UNKNOWN_ERROR if failed for other reasons. */ setLna(bool bEnable) generates (Result result); - - /** - * Sends DiSEqC (Digital Satellite Equipment Control) message. - * - * Client sends DiSeqc message to DiSEqc compatible device through the - * frontend. The response message from the device comes back to the client - * through frontend's callback onDiseqcMessage. - * - * @param diseqcMessage a byte array of data for DiSEqC message which is - * specified by EUTELSAT Bus Functional Specification Version 4.2. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if the frontend can't send DiSEqc Message, such as - * cable frontend. - * UNKNOWN_ERROR if failed for other reasons. - */ - sendDiseqcMessage(vec diseqcMessage) generates (Result result); }; diff --git a/tv/tuner/1.0/ILnb.hal b/tv/tuner/1.0/ILnb.hal index 49fc3b44d8..6b7119e046 100644 --- a/tv/tuner/1.0/ILnb.hal +++ b/tv/tuner/1.0/ILnb.hal @@ -54,6 +54,24 @@ interface ILnb { */ setSatellitePosition(FrontendLnbPosition position) generates (Result result); + /** + * Sends DiSEqC (Digital Satellite Equipment Control) message. + * + * Client sends DiSeqc message to DiSEqc to LNB. The response message from + * the device comes back to the client through frontend's callback + * onDiseqcMessage. + * + * @param diseqcMessage a byte array of data for DiSEqC message which is + * specified by EUTELSAT Bus Functional Specification Version 4.2. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if the frontend can't send DiSEqc Message, such as + * cable frontend. + * UNKNOWN_ERROR if failed for other reasons. + */ + sendDiseqcMessage(vec diseqcMessage) generates (Result result); + /** * Releases the LNB instance * diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal index f1a8617261..0d63442d07 100644 --- a/tv/tuner/1.0/ITuner.hal +++ b/tv/tuner/1.0/ITuner.hal @@ -67,6 +67,16 @@ interface ITuner { openDemux() generates (Result result, DemuxId demuxId, IDemux demux); + /** + * Retrieve the Demux's Capabilities. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if the inquiry failed for other reasons. + * @return caps the Demux's Capabilities. + */ + getDemuxCaps() generates (Result result, DemuxCapabilities caps); + /** * Create a new instance of Descrambler. * @@ -81,14 +91,13 @@ interface ITuner { generates (Result result, IDescrambler descrambler); /** - * Create a new instance of Descrambler. - * - * It is used by the client to create a Descrambler instance. + * Retrieve the frontend's information. * + * @param frontendId the id of the frontend to be inquiried. * @return result Result status of the operation. * SUCCESS if successful, - * UNKNOWN_ERROR if creation failed for other reasons. - * @return descrambler the newly created descrambler interface. + * UNKNOWN_ERROR if the inquiry failed for other reasons. + * @return info the frontend's information. */ getFrontendInfo(FrontendId frontendId) generates (Result result, FrontendInfo info); @@ -119,6 +128,5 @@ interface ITuner { */ openLnbById(LnbId lnbId) generates (Result result, ILnb lnb); - }; diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index d37f63a6ef..b6f11ee3c2 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -43,7 +43,7 @@ enum FrontendType : uint32_t { ANALOG, /* Advanced Television Systems Committee (ATSC) Standard A/72. */ ATSC, - /* Advanced Television Systems Committee (ATSC 3.0) Standard A/330. */ + /* Advanced Television Systems Committee (ATSC 3.0) Standard A/300. */ ATSC3, /** * Digital Video Broadcasting - Cable @@ -63,11 +63,11 @@ enum FrontendType : uint32_t { */ DVBT, /* Integrated Services Digital Broadcasting-Satellite (ISDB-S) - * ARIB SDT-B20 is technical document of ISDB-S. + * ARIB STD-B20 is technical document of ISDB-S. */ ISDBS, /* Integrated Services Digital Broadcasting-Satellite (ISDB-S) - * ARIB TR-B15 is technical document of ISDB-S3. + * ARIB STD-B44 is technical document of ISDB-S3. */ ISDBS3, /* Integrated Services Digital Broadcasting-Terrestrial (ISDB-T or SBTVD) @@ -164,8 +164,10 @@ enum FrontendInnerFec : uint64_t { @export enum FrontendAtscModulation : uint32_t { UNDEFINED = 0, - MOD_8VSB = 1 << 0, - MOD_16VSB = 1 << 1, + /** hardware is able to detect and set modulation automatically */ + AUTO = 1 << 0, + MOD_8VSB = 1 << 2, + MOD_16VSB = 1 << 3, }; /** @@ -191,12 +193,14 @@ struct FrontendAtscCapabilities { @export enum FrontendAtsc3Modulation : uint32_t { UNDEFINED = 0, - MOD_QPSK = 1 << 0, - MOD_16QAM = 1 << 1, - MOD_64QAM = 1 << 2, - MOD_256QAM = 1 << 3, - MOD_1024QAM = 1 << 4, - MOD_4096QAM = 1 << 5, + /** hardware is able to detect and set modulation automatically */ + AUTO = 1 << 0, + MOD_QPSK = 1 << 1, + MOD_16QAM = 1 << 2, + MOD_64QAM = 1 << 3, + MOD_256QAM = 1 << 4, + MOD_1024QAM = 1 << 5, + MOD_4096QAM = 1 << 6, }; /** @@ -205,9 +209,11 @@ enum FrontendAtsc3Modulation : uint32_t { @export enum FrontendAtsc3Bandwidth : uint32_t { UNDEFINED = 0, - BANDWIDTH_8MHZ = 1 << 0, - BANDWIDTH_7MHZ = 1 << 1, - BANDWIDTH_6MHZ = 1 << 2, + /** hardware is able to detect and set bandwidth automatically */ + AUTO = 1 << 0, + BANDWIDTH_6MHZ = 1 << 1, + BANDWIDTH_7MHZ = 1 << 2, + BANDWIDTH_8MHZ = 1 << 3, }; /** @@ -215,9 +221,11 @@ enum FrontendAtsc3Bandwidth : uint32_t { */ @export enum FrontendAtsc3TimeInterleaveMode : uint32_t { - UNDEFINED, - CTI, - HTI, + UNDEFINED = 0, + /** hardware is able to detect and set TimeInterleaveMode automatically */ + AUTO = 1 << 0, + CTI = 1 << 1, + HTI = 1 << 2, }; /** @@ -247,13 +255,39 @@ enum FrontendAtsc3CodeRate : uint32_t { */ @export enum FrontendAtsc3Fec : uint32_t { - UNDEFINED, - BCH_LDPC_16K, - BCH_LDPC_64K, - CRC_LDPC_16K, - CRC_LDPC_64K, - LDPC_16K, - LDPC_64K, + UNDEFINED = 0, + /** hardware is able to detect and set FEC automatically */ + AUTO = 1 << 0, + BCH_LDPC_16K = 1 << 1, + BCH_LDPC_64K = 1 << 2, + CRC_LDPC_16K = 1 << 3, + CRC_LDPC_64K = 1 << 4, + LDPC_16K = 1 << 5, + LDPC_64K = 1 << 6, +}; + +/** + * Demodulator Output Format for an ATSC3 Frontend. + */ +@export +enum FrontendAtsc3DemodOutputFormat : uint8_t { + /** Dummy. Scan uses this. */ + UNDEFINED = 0, + /** ALP format. Typically used in US region. */ + ATSC3_LINKLAYER_PACKET = 1 << 0, + /** BaseBand packet format. Typically used in Korea region. */ + BASEBAND_PACKET = 1 << 1, +}; + +/** + * PLP basis Signal Settings for an ATSC3 Frontend. + */ +struct FrontendAtsc3PlpSettings { + uint8_t plpId; + FrontendAtsc3Modulation modulation; + FrontendAtsc3TimeInterleaveMode interleaveMode; + FrontendAtsc3CodeRate codeRate; + FrontendAtsc3Fec fec; }; /** @@ -262,21 +296,28 @@ enum FrontendAtsc3Fec : uint32_t { struct FrontendAtsc3Settings { /** Signal frequency in Hertz */ uint32_t frequency; + /** Bandwidth of tuning band. */ FrontendAtsc3Bandwidth bandwidth; - FrontendAtsc3TimeInterleaveMode interleaveMode; - FrontendAtsc3CodeRate codeRate; - FrontendAtsc3Fec fec; - vec plpIdList; + FrontendAtsc3DemodOutputFormat demodOutputFormat; + vec plpSettings; }; /** * Capabilities for ATSC3 Frontend. */ struct FrontendAtsc3Capabilities { - /** Modulation capability */ - bitfield modulationCap; /** Bandwidth capability */ bitfield bandwidthCap; + /** Modulation capability */ + bitfield modulationCap; + /** TimeInterleaveMode capability */ + bitfield timeInterleaveModeCap; + /** CodeRate capability */ + bitfield codeRateCap; + /** FEC capability */ + bitfield fecCap; + /** Demodulator Output Format capability */ + bitfield demodOutputFormatCap; }; /** @@ -647,7 +688,7 @@ enum FrontendIsdbsCoderate : uint32_t { @export enum FrontendIsdbsStreamIdType : uint32_t { STREAM_ID, - RELATIVE_STREAM_ID, + RELATIVE_STREAM_NUMBER, }; /** @@ -845,6 +886,7 @@ enum FrontendAnalogSifStandard : uint32_t { M_EIA_J = 1 << 13, I_NICAM = 1 << 14, L_NICAM = 1 << 15, + L_PRIME = 1 << 16, }; /** @@ -907,10 +949,20 @@ enum FrontendScanMessageType : uint32_t { PLP_IDS, /** Locked group Ids for DVBT2 frontend. */ GROUP_IDS, - /** Locked the number of the Plps. */ - INPUT_STREAM_IDS, + /** Stream Ids. */ + INPUT_STREAM_IDS, /** Locked signal stardard. */ STANDARD, + /** PLP status in a tuned frequency band for ATSC3 frontend. */ + ATSC3_PLP_INFO, +}; + +/** + * ATSC3.0 PLP information for scan + */ +struct FrontendScanAtsc3PlpInfo { + uint8_t plpId; + bool bLlsFlag; }; /** @@ -927,11 +979,13 @@ safe_union FrontendScanMessage { uint32_t symbolRate; vec plpIds; vec groupIds; - vec inputStreamIds; + vec inputStreamIds; safe_union standard { FrontendDvbsStandard sStd; FrontendDvbtStandard tStd; } std; + /** A list of PLP status in a tuned frequency band for ATSC3 frontend. */ + vec atsc3PlpInfos; }; /** @@ -940,17 +994,17 @@ safe_union FrontendScanMessage { @export enum FrontendEventType : uint32_t { /** - * If frontend locked the signal which is specified by tune method, HAL sent + * If frontend locked the signal which is specified by tune method, HAL sends * Locked event. */ LOCKED, /** * If frontend can't locked the signal which is specified by tune method, - * HAL sent NO_SIGNAL event. + * HAL sends NO_SIGNAL event. */ NO_SIGNAL, /** - * If frontend detect that the locked signal get lost, HAL sent LOST_LOCK + * If frontend detect that the locked signal get lost, HAL sends LOST_LOCK * event. */ LOST_LOCK, @@ -977,15 +1031,15 @@ enum FrontendEventType : uint32_t { */ @export enum FrontendStatusType : uint32_t { - /** Lock status for RF or Demod. */ - LOCK, + /** Lock status for Demod. */ + DEMOD_LOCK, /** Signal to Noise Ratio. */ SNR, /** Bit Error Ratio. */ BER, /** Packages Error Ratio. */ PER, - /** Bit Error Ratio befor FEC. */ + /** Bit Error Ratio before FEC. */ PRE_BER, /* * Signal Quality (0..100). Good data over total data in percent can be @@ -993,7 +1047,7 @@ enum FrontendStatusType : uint32_t { */ SIGNAL_QUALITY, /** Signal Strength. */ - SIGGAL_STRENGTH, + SIGNAL_STRENGTH, /** Symbol Rate. */ SYMBOL_RATE, /** Forward Error Correction Type. */ @@ -1008,21 +1062,62 @@ enum FrontendStatusType : uint32_t { PLP_ID, /** Status for Emergency Warning Broadcasting System. */ EWBS, + /** Automatic Gain Control. */ + AGC, + /** Low Noise Amplifier. */ + LNA, + /** Lock status for stream. */ + STREAM_LOCK, + /** Error status by layer. */ + LAYER_ERROR, + /** CN value by VBER. */ + VBER_CN, + /** CN value by LBER. */ + LBER_CN, + /** CN value by XER. */ + XER_CN, + /** Moduration Error Ratio. */ + MER, + /** Difference between tuning frequency and actual locked frequency. */ + FREQ_OFFSET, + /* Hierarchy for DVBT. */ + HIERARCHY, + /** Lock status for RF. */ + RF_LOCK, + /** PLP information in a frequency band for ATSC3.0 frontend. */ + ATSC3_PLP_INFO, }; +/** + * Status for each tuning PLPs + */ +struct FrontendStatusAtsc3PlpInfo { + /** PLP Id value. */ + uint8_t plpId; + /** Demod Lock/Unlock status of this particular PLP. */ + bool isLocked; + /** Uncorrectable Error Counts (UEC) of this particular PLP since last tune operation. */ + uint32_t uec; +}; + + /** * Modulation Type for Frontend's status. */ safe_union FrontendModulationStatus { + FrontendDvbcModulation dvbc; FrontendDvbsModulation dvbs; - FrontendAtsc3Modulation atsc3; + FrontendIsdbsModulation isdbs; + FrontendIsdbs3Modulation isdbs3; + FrontendIsdbtModulation isdbt; }; /** * The status for Frontend. */ safe_union FrontendStatus { - bool isLocked; + /** Lock status for Demod in True/False. */ + bool isDemodLocked; /** SNR value measured by 0.001 dB. */ int32_t snr; /** The number of error bit per 1 billion bits. */ @@ -1043,6 +1138,25 @@ safe_union FrontendStatus { FrontendLnbVoltage lnbVoltage; uint8_t plpId; bool isEWBS; + /** AGC value is normalized from 0 to 255. */ + uint8_t agc; + bool isLnaOn; + bool isStreamLock; + vec isLayerError; + /** CN value by VBER measured by 0.001 dB */ + int32_t vberCn; + /** CN value by LBER measured by 0.001 dB */ + int32_t lberCn; + /** CN value by XER measured by 0.001 dB */ + int32_t xerCn; + /** MER value measured by 0.001 dB */ + int32_t mer; + /** Frequency difference in Hertz. */ + int32_t freqOffset; + FrontendDvbtHierarchy hierarchy; + bool isRfLocked; + /** A list of PLP status for tuned PLPs for ATSC3 frontend. */ + vec plpInfo; }; /** @@ -1121,7 +1235,6 @@ enum FrontendLnbPosition : int32_t { POSITION_B, }; - /* Demux ID is used to associate with a hardware demux resource. */ typedef uint32_t DemuxId; @@ -1150,7 +1263,7 @@ enum DemuxFilterType : uint32_t { */ AUDIO, /** - * A filter to filter Vidoe Metadata out from input stream. + * A filter to filter Video Metadata out from input stream. */ VIDEO, /** @@ -1475,6 +1588,8 @@ enum DemuxDataFormat : uint32_t { PES, /* Data is Elementary Stream. */ ES, + /* Data is TLV (type-length-value) Stream for JP SHV */ + SHV_TLV, }; /** @@ -1534,6 +1649,10 @@ enum DemuxInputStatus : uint32_t { SPACE_FULL = 1 << 3, }; +/** + * The Settings for the demux's input. + */ +@export struct DemuxInputSettings { /** * Register for interested status events so that the HAL can send these @@ -1559,3 +1678,30 @@ struct DemuxInputSettings { */ uint8_t packetSize; }; + +/** + * Capabilities for Demux. + */ +@export +struct DemuxCapabilities { + /* The number of Demux to be supported. */ + uint32_t numDemux; + /* The number of Input to be supported. */ + uint32_t numInput; + /* The number of Output to be supported. */ + uint32_t numOutput; + /* The number of TS Filter to be supported. */ + uint32_t numTsFilter; + /* The number of Section Filter to be supported. */ + uint32_t numSectionFilter; + /* The number of Audio Filter to be supported. */ + uint32_t numAudioFilter; + /* The number of Video Filter to be supported. */ + uint32_t numVideoFilter; + /* The number of PES Filter to be supported. */ + uint32_t numPesFilter; + /* The number of PCR Filter to be supported. */ + uint32_t numPcrFilter; + /* The maximum number of bytes is supported in the mask of Section Filter. */ + uint32_t numBytesInSectionFilter; +}; From 42a5b4b87fa9ea962be02dbdc73d16a17f9bc815 Mon Sep 17 00:00:00 2001 From: Amy Date: Thu, 3 Oct 2019 16:49:48 -0700 Subject: [PATCH 0157/1022] Adding a TS filter functionality into the Demux default impl Test: atest Bug: 135709325 Change-Id: I149104fd4c7d1ce413036b147365a49973455e72 --- tv/tuner/1.0/default/Demux.cpp | 192 ++++++++++++++++++++---------- tv/tuner/1.0/default/Demux.h | 24 +++- tv/tuner/1.0/default/Frontend.cpp | 8 +- tv/tuner/1.0/default/Frontend.h | 4 +- tv/tuner/1.0/default/Lnb.cpp | 6 + tv/tuner/1.0/default/Lnb.h | 4 +- tv/tuner/1.0/default/Tuner.cpp | 9 ++ tv/tuner/1.0/default/Tuner.h | 2 + 8 files changed, 175 insertions(+), 74 deletions(-) diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp index 889e42ed06..080116c4a9 100644 --- a/tv/tuner/1.0/default/Demux.cpp +++ b/tv/tuner/1.0/default/Demux.cpp @@ -100,6 +100,8 @@ Return Demux::addFilter(DemuxFilterType type, uint32_t bufferSize, mFilterEventFlags.resize(filterId + 1); mFilterThreadRunning.resize(filterId + 1); mFilterThreads.resize(filterId + 1); + mFilterPids.resize(filterId + 1); + mFilterOutputs.resize(filterId + 1); } mUsedFilterIds.insert(filterId); @@ -142,10 +144,34 @@ Return Demux::getFilterQueueDesc(uint32_t filterId, getFilterQueueDesc_cb return Void(); } -Return Demux::configureFilter(uint32_t /* filterId */, - const DemuxFilterSettings& /* settings */) { +Return Demux::configureFilter(uint32_t filterId, const DemuxFilterSettings& settings) { ALOGV("%s", __FUNCTION__); + switch (mFilterEvents[filterId].filterType) { + case DemuxFilterType::SECTION: + mFilterPids[filterId] = settings.section().tpid; + break; + case DemuxFilterType::PES: + mFilterPids[filterId] = settings.pesData().tpid; + break; + case DemuxFilterType::TS: + mFilterPids[filterId] = settings.ts().tpid; + break; + case DemuxFilterType::AUDIO: + mFilterPids[filterId] = settings.audio().tpid; + break; + case DemuxFilterType::VIDEO: + mFilterPids[filterId] = settings.video().tpid; + break; + case DemuxFilterType::RECORD: + mFilterPids[filterId] = settings.record().tpid; + break; + case DemuxFilterType::PCR: + mFilterPids[filterId] = settings.pcr().tpid; + break; + default: + return Result::UNKNOWN_ERROR; + } return Result::SUCCESS; } @@ -158,36 +184,16 @@ Return Demux::startFilter(uint32_t filterId) { return Result::INVALID_ARGUMENT; } - switch (mFilterEvents[filterId].filterType) { - case DemuxFilterType::SECTION: - result = startFilterLoop(filterId); - break; - case DemuxFilterType::PES: - result = startPesFilterHandler(filterId); - break; - case DemuxFilterType::TS: - result = startTsFilterHandler(); - return Result::SUCCESS; - case DemuxFilterType::AUDIO: - case DemuxFilterType::VIDEO: - result = startMediaFilterHandler(filterId); - break; - case DemuxFilterType::RECORD: - result = startRecordFilterHandler(filterId); - break; - case DemuxFilterType::PCR: - result = startPcrFilterHandler(); - return Result::SUCCESS; - default: - return Result::UNKNOWN_ERROR; - } + result = startFilterLoop(filterId); return result; } -Return Demux::stopFilter(uint32_t /* filterId */) { +Return Demux::stopFilter(uint32_t filterId) { ALOGV("%s", __FUNCTION__); + mFilterThreadRunning[filterId] = false; + return Result::SUCCESS; } @@ -238,6 +244,8 @@ Return Demux::close() { mFilterMQs.clear(); mFilterEvents.clear(); mFilterEventFlags.clear(); + mFilterOutputs.clear(); + mFilterPids.clear(); mLastUsedFilterId = -1; return Result::SUCCESS; @@ -277,19 +285,21 @@ Return Demux::getOutputQueueDesc(getOutputQueueDesc_cb _hidl_cb) { return Void(); } -Return Demux::configureOutput(const DemuxOutputSettings& /* settings */) { +Return Demux::configureOutput(const DemuxOutputSettings& settings) { + ALOGV("%s", __FUNCTION__); + + mOutputConfigured = true; + mOutputSettings = settings; + return Result::SUCCESS; +} + +Return Demux::attachOutputFilter(uint32_t /*filterId*/) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; } -Return Demux::attachOutputTsFilter(uint32_t /*filterId*/) { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Demux::detachOutputTsFilter(uint32_t /* filterId */) { +Return Demux::detachOutputFilter(uint32_t /* filterId */) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; @@ -353,15 +363,26 @@ Return Demux::getInputQueueDesc(getInputQueueDesc_cb _hidl_cb) { return Void(); } -Return Demux::configureInput(const DemuxInputSettings& /* settings */) { +Return Demux::configureInput(const DemuxInputSettings& settings) { ALOGV("%s", __FUNCTION__); + mInputConfigured = true; + mInputSettings = settings; + return Result::SUCCESS; } Return Demux::startInput() { ALOGV("%s", __FUNCTION__); + if (!mInputCallback) { + return Result::NOT_INITIALIZED; + } + + if (!mInputConfigured) { + return Result::INVALID_STATE; + } + pthread_create(&mInputThread, NULL, __threadLoopInput, this); pthread_setname_np(mInputThread, "demux_input_waiting_loop"); @@ -373,6 +394,8 @@ Return Demux::startInput() { Return Demux::stopInput() { ALOGV("%s", __FUNCTION__); + mInputThreadRunning = false; + return Result::SUCCESS; } @@ -403,36 +426,43 @@ Result Demux::startFilterLoop(uint32_t filterId) { return Result::SUCCESS; } -Result Demux::startSectionFilterHandler(uint32_t filterId, vector data) { - if (!writeSectionsAndCreateEvent(filterId, data)) { +Result Demux::startSectionFilterHandler(uint32_t filterId) { + if (mFilterOutputs[filterId].empty()) { + return Result::SUCCESS; + } + if (!writeSectionsAndCreateEvent(filterId, mFilterOutputs[filterId])) { ALOGD("[Demux] filter %d fails to write into FMQ. Ending thread", filterId); return Result::UNKNOWN_ERROR; } + mFilterOutputs[filterId].clear(); + return Result::SUCCESS; } Result Demux::startPesFilterHandler(uint32_t filterId) { - // TODO generate multiple events in one event callback + std::lock_guard lock(mFilterEventLock); DemuxFilterPesEvent pesEvent; + if (mFilterOutputs[filterId].empty()) { + return Result::SUCCESS; + } + + // TODO extract PES from TS + if (!writeDataToFilterMQ(mFilterOutputs[filterId], filterId)) { + mFilterOutputs[filterId].clear(); + return Result::INVALID_STATE; + } pesEvent = { // temp dump meta data .streamId = 0, - .dataLength = 530, + .dataLength = static_cast(mFilterOutputs[filterId].size()), }; - mFilterEvents[filterId].events.resize(1); - mFilterEvents[filterId].events[0].pes(pesEvent); - /*pthread_create(&mThreadId, NULL, __threadLoop, this); - pthread_setname_np(mThreadId, "demux_section_filter_waiting_loop");*/ - if (!writeDataToFilterMQ(fakeDataInputBuffer, filterId)) { - return Result::INVALID_STATE; - } + int size = mFilterEvents[filterId].events.size(); + mFilterEvents[filterId].events.resize(size + 1); + mFilterEvents[filterId].events[size].pes(pesEvent); - if (mDemuxCallbacks[filterId] == nullptr) { - return Result::NOT_INITIALIZED; - } + mFilterOutputs[filterId].clear(); - mDemuxCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]); return Result::SUCCESS; } @@ -499,18 +529,18 @@ bool Demux::createFilterMQ(uint32_t bufferSize, uint32_t filterId) { bool Demux::writeSectionsAndCreateEvent(uint32_t filterId, vector data) { // TODO check how many sections has been read std::lock_guard lock(mFilterEventLock); - int size = mFilterEvents[filterId].events.size(); - mFilterEvents[filterId].events.resize(size + 1); if (!writeDataToFilterMQ(data, filterId)) { return false; } + int size = mFilterEvents[filterId].events.size(); + mFilterEvents[filterId].events.resize(size + 1); DemuxFilterSectionEvent secEvent; secEvent = { // temp dump meta data .tableId = 0, .version = 1, .sectionNum = 1, - .dataLength = 530, + .dataLength = static_cast(data.size()), }; mFilterEvents[filterId].events[size].section(secEvent); return true; @@ -525,20 +555,32 @@ bool Demux::writeDataToFilterMQ(const std::vector& data, uint32_t filte } bool Demux::filterAndOutputData() { - ALOGD("[Demux] start to dispatch data to filters"); + Result result; + set::iterator it; + // Read input data from the input FMQ int size = mInputMQ->availableToRead(); + int inputPacketSize = mInputSettings.packetSize; vector dataOutputBuffer; - dataOutputBuffer.resize(size); - mInputMQ->read(dataOutputBuffer.data(), size); + dataOutputBuffer.resize(inputPacketSize); - Result result; - // Filter the data and feed the output to each filter - set::iterator it; + // Dispatch the packet to the PID matching filter output buffer + for (int i = 0; i < size / inputPacketSize; i++) { + mInputMQ->read(dataOutputBuffer.data(), inputPacketSize); + for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { + uint16_t pid = ((dataOutputBuffer[1] & 0x1f) << 8) | ((dataOutputBuffer[2] & 0xff)); + if (pid == mFilterPids[*it]) { + mFilterOutputs[*it].insert(mFilterOutputs[*it].end(), dataOutputBuffer.begin(), + dataOutputBuffer.end()); + } + } + } + + // Handle the output data per filter type for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { switch (mFilterEvents[*it].filterType) { case DemuxFilterType::SECTION: - result = startSectionFilterHandler(*it, dataOutputBuffer); + result = startSectionFilterHandler(*it); break; case DemuxFilterType::PES: result = startPesFilterHandler(*it); @@ -657,12 +699,42 @@ void Demux::inputThreadLoop() { ALOGD("[Demux] input data failed to be filtered. Ending thread"); break; } + + maySendInputStatusCallback(); } mInputThreadRunning = false; ALOGD("[Demux] input thread ended."); } +void Demux::maySendInputStatusCallback() { + std::lock_guard lock(mInputStatusLock); + int availableToRead = mInputMQ->availableToRead(); + int availableToWrite = mInputMQ->availableToWrite(); + + DemuxInputStatus newStatus = + checkStatusChange(availableToWrite, availableToRead, mInputSettings.highThreshold, + mInputSettings.lowThreshold); + if (mIntputStatus != newStatus) { + mInputCallback->onInputStatus(newStatus); + mIntputStatus = newStatus; + } +} + +DemuxInputStatus Demux::checkStatusChange(uint32_t availableToWrite, uint32_t availableToRead, + uint32_t highThreshold, uint32_t lowThreshold) { + if (availableToWrite == 0) { + return DemuxInputStatus::SPACE_FULL; + } else if (availableToRead > highThreshold) { + return DemuxInputStatus::SPACE_ALMOST_FULL; + } else if (availableToRead < lowThreshold) { + return DemuxInputStatus::SPACE_ALMOST_EMPTY; + } else if (availableToRead == 0) { + return DemuxInputStatus::SPACE_EMPTY; + } + return mIntputStatus; +} + } // namespace implementation } // namespace V1_0 } // namespace tuner diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h index 2fdde8dcf8..eaf6ac3ed9 100644 --- a/tv/tuner/1.0/default/Demux.h +++ b/tv/tuner/1.0/default/Demux.h @@ -91,9 +91,9 @@ class Demux : public IDemux { virtual Return configureOutput(const DemuxOutputSettings& settings) override; - virtual Return attachOutputTsFilter(uint32_t filterId) override; + virtual Return attachOutputFilter(uint32_t filterId) override; - virtual Return detachOutputTsFilter(uint32_t filterId) override; + virtual Return detachOutputFilter(uint32_t filterId) override; virtual Return startOutput() override; @@ -115,7 +115,7 @@ class Demux : public IDemux { * They are also responsible to write the filtered output into the filter FMQ * and update the filterEvent bound with the same filterId. */ - Result startSectionFilterHandler(uint32_t filterId, vector data); + Result startSectionFilterHandler(uint32_t filterId); Result startPesFilterHandler(uint32_t filterId); Result startTsFilterHandler(); Result startMediaFilterHandler(uint32_t filterId); @@ -136,6 +136,9 @@ class Demux : public IDemux { bool writeDataToFilterMQ(const std::vector& data, uint32_t filterId); bool readDataFromMQ(); bool writeSectionsAndCreateEvent(uint32_t filterId, vector data); + void maySendInputStatusCallback(); + DemuxInputStatus checkStatusChange(uint32_t availableToWrite, uint32_t availableToRead, + uint32_t highThreshold, uint32_t lowThreshold); /** * A dispatcher to read and dispatch input data to all the started filters. * Each filter handler handles the data filtering/output writing/filterEvent updating. @@ -169,6 +172,8 @@ class Demux : public IDemux { * A list of created FilterMQ ptrs. * The array number is the filter ID. */ + vector mFilterPids; + vector> mFilterOutputs; vector> mFilterMQs; vector mFilterEventFlags; vector mFilterEvents; @@ -182,10 +187,18 @@ class Demux : public IDemux { vector> mDemuxCallbacks; sp mInputCallback; sp mOutputCallback; + bool mInputConfigured = false; + bool mOutputConfigured = false; + DemuxInputSettings mInputSettings; + DemuxOutputSettings mOutputSettings; + // Thread handlers pthread_t mInputThread; pthread_t mOutputThread; vector mFilterThreads; + + // FMQ status local records + DemuxInputStatus mIntputStatus; /** * If a specific filter's writing loop is still running */ @@ -198,7 +211,12 @@ class Demux : public IDemux { /** * Lock to protect writes to the filter event */ + // TODO make each filter separate event lock std::mutex mFilterEventLock; + /** + * Lock to protect writes to the input status + */ + std::mutex mInputStatusLock; /** * How many times a filter should write * TODO make this dynamic/random/can take as a parameter diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp index 0609d05121..6f87d1b8b3 100644 --- a/tv/tuner/1.0/default/Frontend.cpp +++ b/tv/tuner/1.0/default/Frontend.cpp @@ -105,13 +105,7 @@ Return Frontend::setLna(bool /* bEnable */) { return Result::SUCCESS; } -Return Frontend::setLnb(const sp& /* lnb */) { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Frontend::sendDiseqcMessage(const hidl_vec& /* diseqcMessage */) { +Return Frontend::setLnb(uint32_t /* lnb */) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h index fc586b5174..f881e8b641 100644 --- a/tv/tuner/1.0/default/Frontend.h +++ b/tv/tuner/1.0/default/Frontend.h @@ -56,11 +56,9 @@ class Frontend : public IFrontend { virtual Return getStatus(const hidl_vec& statusTypes, getStatus_cb _hidl_cb) override; - virtual Return sendDiseqcMessage(const hidl_vec& diseqcMessage) override; - virtual Return setLna(bool bEnable) override; - virtual Return setLnb(const sp& lnb) override; + virtual Return setLnb(uint32_t lnb) override; FrontendType getFrontendType(); diff --git a/tv/tuner/1.0/default/Lnb.cpp b/tv/tuner/1.0/default/Lnb.cpp index b81bb1508b..1446f7f344 100644 --- a/tv/tuner/1.0/default/Lnb.cpp +++ b/tv/tuner/1.0/default/Lnb.cpp @@ -48,6 +48,12 @@ Return Lnb::setSatellitePosition(FrontendLnbPosition /* position */) { return Result::SUCCESS; } +Return Lnb::sendDiseqcMessage(const hidl_vec& /* diseqcMessage */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + Return Lnb::close() { ALOGV("%s", __FUNCTION__); diff --git a/tv/tuner/1.0/default/Lnb.h b/tv/tuner/1.0/default/Lnb.h index df7e0fe2b3..4c251f7591 100644 --- a/tv/tuner/1.0/default/Lnb.h +++ b/tv/tuner/1.0/default/Lnb.h @@ -38,12 +38,14 @@ class Lnb : public ILnb { public: Lnb(); - virtual Return setVoltage(FrontendLnbVoltage voltage); + virtual Return setVoltage(FrontendLnbVoltage voltage) override; virtual Return setTone(FrontendLnbTone tone) override; virtual Return setSatellitePosition(FrontendLnbPosition position) override; + virtual Return sendDiseqcMessage(const hidl_vec& diseqcMessage) override; + virtual Return close() override; private: diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp index 00831aea30..a4a8ca5043 100644 --- a/tv/tuner/1.0/default/Tuner.cpp +++ b/tv/tuner/1.0/default/Tuner.cpp @@ -87,6 +87,15 @@ Return Tuner::openDemux(openDemux_cb _hidl_cb) { return Void(); } +Return Tuner::getDemuxCaps(getDemuxCaps_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + DemuxCapabilities caps; + + _hidl_cb(Result::SUCCESS, caps); + return Void(); +} + Return Tuner::openDescrambler(openDescrambler_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h index 62227eefcd..c089864d32 100644 --- a/tv/tuner/1.0/default/Tuner.h +++ b/tv/tuner/1.0/default/Tuner.h @@ -39,6 +39,8 @@ class Tuner : public ITuner { virtual Return openDemux(openDemux_cb _hidl_cb) override; + virtual Return getDemuxCaps(getDemuxCaps_cb _hidl_cb) override; + virtual Return openDescrambler(openDescrambler_cb _hidl_cb) override; virtual Return getFrontendInfo(FrontendId frontendId, From 22cd1cbf8c24658128e5a40232ac474c78604955 Mon Sep 17 00:00:00 2001 From: Amy Date: Thu, 3 Oct 2019 17:01:52 -0700 Subject: [PATCH 0158/1022] Adding filter configuration and pes filter test based on PID test Test: atest Bug: 135708935 Change-Id: I61d6dab9124190b05a030f0ea36dcc15c00b7ac3 --- .../VtsHalTvTunerV1_0TargetTest.cpp | 303 ++++++++---------- 1 file changed, 127 insertions(+), 176 deletions(-) diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 7256cc4478..30fe08a188 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -39,6 +39,7 @@ #include #define WAIT_TIMEOUT 3000000000 +#define WAIT_TIMEOUT_data_ready 3000000000 * 4 using android::Condition; using android::IMemory; @@ -58,8 +59,10 @@ using android::hardware::Return; using android::hardware::Void; using android::hardware::tv::tuner::V1_0::DemuxDataFormat; using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent; using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterStatus; using android::hardware::tv::tuner::V1_0::DemuxFilterType; @@ -130,9 +133,6 @@ const std::vector goldenDataOutputBuffer{ const uint16_t FMQ_SIZE_4K = 0x1000; const uint32_t FMQ_SIZE_1M = 0x100000; -// Equal to SECTION_WRITE_COUNT on the HAL impl side -// The HAL impl will repeatedly write to the FMQ the count times -const uint16_t SECTION_READ_COUNT = 10; struct FilterConf { DemuxFilterType type; @@ -214,11 +214,15 @@ void FrontendCallback::testOnDiseqcMessage(sp& frontend, FrontendSett class DemuxCallback : public IDemuxCallback { public: virtual Return onFilterEvent(const DemuxFilterEvent& filterEvent) override { - ALOGW("[VTS] FILTER EVENT %d", filterEvent.filterId); android::Mutex::Autolock autoLock(mMsgLock); - mFilterEventReceived = true; + // Temprarily we treat the first coming back filter data on the matching pid a success + // once all of the MQ are cleared, means we got all the expected output mFilterIdToEvent[filterEvent.filterId] = filterEvent; - startFilterEventThread(filterEvent); + readFilterEventData(filterEvent.filterId); + mPidFilterOutputCount++; + // mFilterIdToMQ.erase(filterEvent.filterId); + + // startFilterEventThread(filterEvent); mMsgCondition.signal(); return Void(); } @@ -232,13 +236,16 @@ class DemuxCallback : public IDemuxCallback { virtual Return onInputStatus(DemuxInputStatus status) override { // android::Mutex::Autolock autoLock(mMsgLock); + ALOGW("[vts] input status %d", status); switch (status) { case DemuxInputStatus::SPACE_EMPTY: case DemuxInputStatus::SPACE_ALMOST_EMPTY: + ALOGW("[vts] keep inputing %d", status); mKeepWritingInputFMQ = true; break; case DemuxInputStatus::SPACE_ALMOST_FULL: case DemuxInputStatus::SPACE_FULL: + ALOGW("[vts] stop inputing %d", status); mKeepWritingInputFMQ = false; break; } @@ -246,43 +253,39 @@ class DemuxCallback : public IDemuxCallback { } void testOnFilterEvent(uint32_t filterId); - void testOnSectionFilterEvent(sp& demux, uint32_t filterId, MQDesc& filterMQDescriptor, - MQDesc& inputMQDescriptor); void testFilterDataOutput(); - // Legacy - bool readAndCompareSectionEventData(uint32_t filterId); void startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor); void startFilterEventThread(DemuxFilterEvent event); static void* __threadLoopInput(void* threadArgs); static void* __threadLoopFilter(void* threadArgs); - void inputThreadLoop(InputConf inputConf, bool* keepWritingInputFMQ, MQDesc& inputMQDescriptor); + void inputThreadLoop(InputConf* inputConf, bool* keepWritingInputFMQ); void filterThreadLoop(DemuxFilterEvent& event); void updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor); void updateGoldenOutputMap(uint32_t filterId, string goldenOutputFile); + bool readFilterEventData(uint32_t filterId); private: struct InputThreadArgs { DemuxCallback* user; - InputConf inputConf; + InputConf* inputConf; bool* keepWritingInputFMQ; - MQDesc& inputMQDesc; }; struct FilterThreadArgs { DemuxCallback* user; - DemuxFilterEvent& event; + DemuxFilterEvent event; }; uint16_t mDataLength = 0; std::vector mDataOutputBuffer; bool mFilterEventReceived; std::map mFilterIdToGoldenOutput; - std::map mFilterIdToEvent; std::map> mFilterIdToMQ; std::unique_ptr mInputMQ; std::map mFilterIdToMQEventFlag; + std::map mFilterIdToEvent; EventFlag* mInputMQEventFlag; android::Mutex mMsgLock; @@ -290,34 +293,22 @@ class DemuxCallback : public IDemuxCallback { android::Condition mMsgCondition; android::Condition mFilterOutputCondition; - bool mKeepWritingInputFMQ; + bool mKeepWritingInputFMQ = true; bool mInputThreadRunning; pthread_t mInputThread; pthread_t mFilterThread; + + int mPidFilterOutputCount = 0; }; -// Legacy -void DemuxCallback::testOnFilterEvent(uint32_t filterId) { - android::Mutex::Autolock autoLock(mMsgLock); - while (!mFilterEventReceived) { - if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { - EXPECT_TRUE(false) << "filter event not received within timeout"; - return; - } - } - // Reset the filter event recieved flag - mFilterEventReceived = false; - // Check if filter id match - EXPECT_TRUE(filterId == mFilterIdToEvent[filterId].filterId) << "filter id match"; -} - void DemuxCallback::startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor) { + mInputMQ = std::make_unique(inputMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(mInputMQ); struct InputThreadArgs* threadArgs = (struct InputThreadArgs*)malloc(sizeof(struct InputThreadArgs)); threadArgs->user = this; - threadArgs->inputConf = inputConf; + threadArgs->inputConf = &inputConf; threadArgs->keepWritingInputFMQ = &mKeepWritingInputFMQ; - threadArgs->inputMQDesc = inputMQDescriptor; pthread_create(&mInputThread, NULL, __threadLoopInput, (void*)threadArgs); pthread_setname_np(mInputThread, "test_playback_input_loop"); @@ -334,72 +325,16 @@ void DemuxCallback::startFilterEventThread(DemuxFilterEvent event) { } void DemuxCallback::testFilterDataOutput() { - android::Mutex::Autolock autoLock(mFilterOutputLock); - while (!mFilterIdToMQ.empty()) { - if (-ETIMEDOUT == mFilterOutputCondition.waitRelative(mFilterOutputLock, WAIT_TIMEOUT)) { - EXPECT_TRUE(false) << "filter output does not match golden output within timeout"; + android::Mutex::Autolock autoLock(mMsgLock); + while (mPidFilterOutputCount < 3) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "filter output matching pid does not output within timeout"; return; } } -} - -// Legacy -void DemuxCallback::testOnSectionFilterEvent(sp& demux, uint32_t filterId, - MQDesc& filterMQDescriptor, - MQDesc& inputMQDescriptor) { - Result status; - // Create MQ to read the output into the local buffer - mFilterIdToMQ[filterId] = - std::make_unique(filterMQDescriptor, true /* resetPointers */); - EXPECT_TRUE(mFilterIdToMQ[filterId]); - // Get the MQ to write the input to the HAL - mInputMQ = std::make_unique(inputMQDescriptor, true /* resetPointers */); - EXPECT_TRUE(mInputMQ); - // Create the EventFlag that is used to signal the HAL impl that data have been - // read the Filter FMQ - EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ[filterId]->getEventFlagWord(), - &mFilterIdToMQEventFlag[filterId]) == android::OK); - // Create the EventFlag that is used to signal the HAL impl that data have been - // written into the Input FMQ - EXPECT_TRUE(EventFlag::createEventFlag(mInputMQ->getEventFlagWord(), &mInputMQEventFlag) == - android::OK); - // Start filter - status = demux->startFilter(filterId); - status = demux->startInput(); - - EXPECT_EQ(status, Result::SUCCESS); - // Test start filter and receive callback event - for (int i = 0; i < SECTION_READ_COUNT; i++) { - // Write input FMQ and notify the Tuner Implementation - EXPECT_TRUE(mInputMQ->write(goldenDataOutputBuffer.data(), goldenDataOutputBuffer.size())); - mInputMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); - testOnFilterEvent(filterId); - // checksum of mDataOutputBuffer and Input golden input - if (readAndCompareSectionEventData(filterId) && i < SECTION_READ_COUNT - 1) { - mFilterIdToMQEventFlag[filterId]->wake( - static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); - } - } -} - -// Legacy -bool DemuxCallback::readAndCompareSectionEventData(uint32_t filterId) { - bool result = false; - DemuxFilterEvent filterEvent = mFilterIdToEvent[filterId]; - for (int i = 0; i < filterEvent.events.size(); i++) { - DemuxFilterSectionEvent event = filterEvent.events[i].section(); - mDataLength = event.dataLength; - EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not match"; - - mDataOutputBuffer.resize(mDataLength); - result = mFilterIdToMQ[filterId]->read(mDataOutputBuffer.data(), mDataLength); - EXPECT_TRUE(result) << "can't read from Filter MQ"; - - for (int i = 0; i < mDataLength; i++) { - EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match"; - } - } - return result; + ALOGW("[vts] pass and stop"); + mInputThreadRunning = false; + mKeepWritingInputFMQ = false; } void DemuxCallback::updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor) { @@ -418,58 +353,60 @@ void* DemuxCallback::__threadLoopInput(void* threadArgs) { DemuxCallback* const self = static_cast(((struct InputThreadArgs*)threadArgs)->user); self->inputThreadLoop(((struct InputThreadArgs*)threadArgs)->inputConf, - ((struct InputThreadArgs*)threadArgs)->keepWritingInputFMQ, - ((struct InputThreadArgs*)threadArgs)->inputMQDesc); + ((struct InputThreadArgs*)threadArgs)->keepWritingInputFMQ); return 0; } -void DemuxCallback::inputThreadLoop(InputConf inputConf, bool* keepWritingInputFMQ, - MQDesc& inputMQDescriptor) { +void DemuxCallback::inputThreadLoop(InputConf* inputConf, bool* keepWritingInputFMQ) { mInputThreadRunning = true; - std::unique_ptr inputMQ = - std::make_unique(inputMQDescriptor, true /* resetPointers */); - EXPECT_TRUE(inputMQ); - // Create the EventFlag that is used to signal the HAL impl that data have been // written into the Input FMQ EventFlag* inputMQEventFlag; - EXPECT_TRUE(EventFlag::createEventFlag(inputMQ->getEventFlagWord(), &inputMQEventFlag) == + EXPECT_TRUE(EventFlag::createEventFlag(mInputMQ->getEventFlagWord(), &inputMQEventFlag) == android::OK); // open the stream and get its length - std::ifstream inputData(inputConf.inputDataFile /*"ts/test1.ts"*/, std::ifstream::binary); - int writeSize = inputConf.setting.packetSize * 6; + std::ifstream inputData(inputConf->inputDataFile, std::ifstream::binary); + int writeSize = inputConf->setting.packetSize * 6; char* buffer = new char[writeSize]; - if (!inputData) { + ALOGW("[vts] input thread loop start %s", inputConf->inputDataFile.c_str()); + if (!inputData.is_open()) { // log mInputThreadRunning = false; + ALOGW("[vts] Error %s", strerror(errno)); } while (mInputThreadRunning) { - // move the stream pointer for packet size * 2k? every read until end + // move the stream pointer for packet size * 100 every read until the end while (*keepWritingInputFMQ) { inputData.read(buffer, writeSize); if (!inputData) { int leftSize = inputData.gcount(); + if (leftSize == 0) { + mInputThreadRunning = false; + break; + } inputData.clear(); inputData.read(buffer, leftSize); // Write the left over of the input data and quit the thread if (leftSize > 0) { - EXPECT_TRUE(inputMQ->write((unsigned char*)&buffer[0], - leftSize / inputConf.setting.packetSize)); + EXPECT_TRUE(mInputMQ->write((unsigned char*)&buffer[0], leftSize)); inputMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); } mInputThreadRunning = false; break; } // Write input FMQ and notify the Tuner Implementation - EXPECT_TRUE(inputMQ->write((unsigned char*)&buffer[0], 6)); + EXPECT_TRUE(mInputMQ->write((unsigned char*)&buffer[0], writeSize)); inputMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); inputData.seekg(writeSize, inputData.cur); + sleep(1); } } + ALOGW("[vts] Input thread end."); + delete[] buffer; inputData.close(); } @@ -481,9 +418,9 @@ void* DemuxCallback::__threadLoopFilter(void* threadArgs) { return 0; } -void DemuxCallback::filterThreadLoop(DemuxFilterEvent& /*event*/) { +void DemuxCallback::filterThreadLoop(DemuxFilterEvent& /* event */) { android::Mutex::Autolock autoLock(mFilterOutputLock); - // Read from MQ[event.filterId] per event and filter type + // Read from mFilterIdToMQ[event.filterId] per event and filter type // Assemble to filterOutput[filterId] @@ -494,6 +431,30 @@ void DemuxCallback::filterThreadLoop(DemuxFilterEvent& /*event*/) { // end thread } +bool DemuxCallback::readFilterEventData(uint32_t filterId) { + bool result = false; + DemuxFilterEvent filterEvent = mFilterIdToEvent[filterId]; + ALOGW("[vts] reading from filter FMQ %d", filterId); + // todo separate filter handlers + for (int i = 0; i < filterEvent.events.size(); i++) { + DemuxFilterPesEvent event = filterEvent.events[i].pes(); + mDataLength = event.dataLength; + // EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not + // match"; + + mDataOutputBuffer.resize(mDataLength); + result = mFilterIdToMQ[filterId]->read(mDataOutputBuffer.data(), mDataLength); + EXPECT_TRUE(result) << "can't read from Filter MQ"; + + /*for (int i = 0; i < mDataLength; i++) { + EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match"; + }*/ + } + mFilterIdToMQEventFlag[filterId]->wake( + static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); + return result; +} + // Test environment for Tuner HIDL HAL. class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: @@ -528,6 +489,7 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { sp mDemuxCallback; MQDesc mFilterMQDescriptor; MQDesc mInputMQDescriptor; + vector mUsedFilterIds; uint32_t mDemuxId; uint32_t mFilterId; @@ -552,10 +514,6 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { ::testing::AssertionResult playbackDataFlowTest(vector filterConf, InputConf inputConf, vector goldenOutputFiles); - - // Legacy - ::testing::AssertionResult addSectionFilterToDemux(); - ::testing::AssertionResult readSectionFilterDataOutput(); }; ::testing::AssertionResult TunerHidlTest::createFrontend(int32_t frontendId) { @@ -586,7 +544,7 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { .frequency = 0, .modulation = FrontendAtscModulation::UNDEFINED, }; - frontendSettings.atsc() = frontendAtscSettings; + frontendSettings.atsc(frontendAtscSettings); mFrontendCallback->testOnEvent(mFrontend, frontendSettings); FrontendDvbtSettings frontendDvbtSettings{ @@ -705,7 +663,7 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { mDemuxCallback = new DemuxCallback(); } - // Add section filter to the local demux + // Add playback input to the local demux status = mDemux->addInput(FMQ_SIZE_1M, mDemuxCallback); if (status != Result::SUCCESS) { @@ -732,29 +690,6 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionResult(status == Result::SUCCESS); } -// Legacy -::testing::AssertionResult TunerHidlTest::addSectionFilterToDemux() { - Result status; - - if (!mDemux && createDemux() == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); - } - - // Create demux callback - if (!mDemuxCallback) { - mDemuxCallback = new DemuxCallback(); - } - - // Add section filter to the local demux - mDemux->addFilter(DemuxFilterType::SECTION, FMQ_SIZE_4K, mDemuxCallback, - [&](Result result, uint32_t filterId) { - mFilterId = filterId; - status = result; - }); - - return ::testing::AssertionResult(status == Result::SUCCESS); -} - ::testing::AssertionResult TunerHidlTest::addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting) { Result status; @@ -800,36 +735,10 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionResult(status == Result::SUCCESS); } -// Legacy -::testing::AssertionResult TunerHidlTest::readSectionFilterDataOutput() { - // Filter Configuration Module - DemuxInputSettings setting{ - .statusMask = 0xf, - .lowThreshold = 0x1000, - .highThreshold = 0x100000, - .dataFormat = DemuxDataFormat::TS, - .packetSize = 188, - }; - if (addSectionFilterToDemux() == ::testing::AssertionFailure() || - getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure() || - addInputToDemux(setting) == ::testing::AssertionFailure() || - getInputMQDescriptor() == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); - } - - // Data Verify Module - // Test start filter and read the output data - mDemuxCallback->testOnSectionFilterEvent(mDemux, mFilterId, mFilterMQDescriptor, - mInputMQDescriptor); - - // Clean Up Module - return closeDemux(); //::testing::AssertionSuccess(); -} - -::testing::AssertionResult TunerHidlTest::playbackDataFlowTest(vector filterConf, - InputConf inputConf, - vector goldenOutputFiles) { +::testing::AssertionResult TunerHidlTest::playbackDataFlowTest( + vector filterConf, InputConf inputConf, vector /*goldenOutputFiles*/) { Result status; + int filterIdsSize; // Filter Configuration Module for (int i = 0; i < filterConf.size(); i++) { if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) == @@ -838,8 +747,11 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } + filterIdsSize = mUsedFilterIds.size(); + mUsedFilterIds.resize(filterIdsSize + 1); + mUsedFilterIds[filterIdsSize] = mFilterId; mDemuxCallback->updateFilterMQ(mFilterId, mFilterMQDescriptor); - mDemuxCallback->updateGoldenOutputMap(mFilterId, goldenOutputFiles[i]); + // mDemuxCallback->updateGoldenOutputMap(mFilterId, goldenOutputFiles[i]); status = mDemux->startFilter(mFilterId); if (status != Result::SUCCESS) { return ::testing::AssertionFailure(); @@ -862,6 +774,14 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { mDemuxCallback->testFilterDataOutput(); // Clean Up Module + for (int i = 0; i <= filterIdsSize; i++) { + if (mDemux->stopFilter(mUsedFilterIds[i]) != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + } + if (mDemux->stopInput() != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } return closeDemux(); } @@ -991,9 +911,40 @@ TEST_F(TunerHidlTest, CloseDescrambler) { /* * DATA FLOW TESTS */ -TEST_F(TunerHidlTest, ReadSectionFilterOutput) { - description("Read data output from FMQ of a Section Filter"); - ASSERT_TRUE(readSectionFilterDataOutput()); +TEST_F(TunerHidlTest, PlaybackDataFlowWithPesFilterTest) { + description("Feed ts data from playback and configure pes filter to get output"); + + // todo modulize the filter conf parser + vector filterConf; + filterConf.resize(1); + + DemuxFilterSettings filterSetting; + DemuxFilterPesDataSettings pesFilterSetting{ + .tpid = 4720, + }; + filterSetting.pesData(pesFilterSetting); + FilterConf pesFilterConf{ + .type = DemuxFilterType::PES, + .setting = filterSetting, + }; + filterConf[0] = pesFilterConf; + + DemuxInputSettings inputSetting{ + .statusMask = 0xf, + .lowThreshold = 0x1000, + .highThreshold = 0x07fff, + .dataFormat = DemuxDataFormat::TS, + .packetSize = 188, + }; + + InputConf inputConf{ + .inputDataFile = "/vendor/etc/test1.ts", + .setting = inputSetting, + }; + + vector goldenOutputFiles; + + ASSERT_TRUE(playbackDataFlowTest(filterConf, inputConf, goldenOutputFiles)); } } // namespace From 5094ae172d058bbcedb04348b322ec09152e64f7 Mon Sep 17 00:00:00 2001 From: Amy Date: Fri, 4 Oct 2019 18:43:21 -0700 Subject: [PATCH 0159/1022] Adding the mocking frontend tuning functionality to take specific ts file as source of a Demux. Test: atest Bug: 135709325 Change-Id: I69849db58d68a7496f929940a74a63e7a9e6c6be --- tv/tuner/1.0/default/Demux.cpp | 160 +++++++++++++++++++++++++----- tv/tuner/1.0/default/Demux.h | 31 +++++- tv/tuner/1.0/default/Frontend.cpp | 19 ++-- tv/tuner/1.0/default/Frontend.h | 17 +++- tv/tuner/1.0/default/Tuner.cpp | 38 +++++-- tv/tuner/1.0/default/Tuner.h | 13 +++ 6 files changed, 228 insertions(+), 50 deletions(-) diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp index 080116c4a9..04382b0f99 100644 --- a/tv/tuner/1.0/default/Demux.cpp +++ b/tv/tuner/1.0/default/Demux.cpp @@ -67,8 +67,9 @@ const std::vector fakeDataInputBuffer{ 0x73, 0x63, 0x65, 0x6e, 0x65, }; -Demux::Demux(uint32_t demuxId) { +Demux::Demux(uint32_t demuxId, sp tuner) { mDemuxId = demuxId; + mTunerService = tuner; } Demux::~Demux() {} @@ -76,9 +77,20 @@ Demux::~Demux() {} Return Demux::setFrontendDataSource(uint32_t frontendId) { ALOGV("%s", __FUNCTION__); - mSourceFrontendId = frontendId; + if (mTunerService == nullptr) { + return Result::NOT_INITIALIZED; + } - return Result::SUCCESS; + mFrontend = mTunerService->getFrontendById(frontendId); + + if (mFrontend == nullptr) { + return Result::INVALID_STATE; + } + + mFrontendSourceFile = mFrontend->getSourceFile(); + + mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId); + return startBroadcastInputLoop(); } Return Demux::addFilter(DemuxFilterType type, uint32_t bufferSize, @@ -194,6 +206,8 @@ Return Demux::stopFilter(uint32_t filterId) { mFilterThreadRunning[filterId] = false; + std::lock_guard lock(mFilterThreadLock); + return Result::SUCCESS; } @@ -396,6 +410,8 @@ Return Demux::stopInput() { mInputThreadRunning = false; + std::lock_guard lock(mInputThreadLock); + return Result::SUCCESS; } @@ -447,19 +463,28 @@ Result Demux::startPesFilterHandler(uint32_t filterId) { return Result::SUCCESS; } - // TODO extract PES from TS - if (!writeDataToFilterMQ(mFilterOutputs[filterId], filterId)) { - mFilterOutputs[filterId].clear(); - return Result::INVALID_STATE; + for (int i = 0; i < mFilterOutputs[filterId].size(); i += 188) { + uint8_t pusi = mFilterOutputs[filterId][i + 1] & 0x40; + uint8_t adaptFieldControl = (mFilterOutputs[filterId][i + 3] & 0x30) >> 4; + ALOGD("[Demux] pusi %d, adaptFieldControl %d", pusi, adaptFieldControl); + if (pusi && (adaptFieldControl == 0x01)) { + vector::const_iterator first = mFilterOutputs[filterId].begin() + i + 4; + vector::const_iterator last = mFilterOutputs[filterId].begin() + i + 187; + vector filterOutData(first, last); + if (!writeDataToFilterMQ(filterOutData, filterId)) { + mFilterOutputs[filterId].clear(); + return Result::INVALID_STATE; + } + pesEvent = { + // temp dump meta data + .streamId = filterOutData[3], + .dataLength = static_cast(filterOutData.size()), + }; + int size = mFilterEvents[filterId].events.size(); + mFilterEvents[filterId].events.resize(size + 1); + mFilterEvents[filterId].events[size].pes(pesEvent); + } } - pesEvent = { - // temp dump meta data - .streamId = 0, - .dataLength = static_cast(mFilterOutputs[filterId].size()), - }; - int size = mFilterEvents[filterId].events.size(); - mFilterEvents[filterId].events.resize(size + 1); - mFilterEvents[filterId].events[size].pes(pesEvent); mFilterOutputs[filterId].clear(); @@ -481,6 +506,8 @@ Result Demux::startMediaFilterHandler(uint32_t filterId) { }; mFilterEvents[filterId].events.resize(1); mFilterEvents[filterId].events[0].media() = mediaEvent; + + mFilterOutputs[filterId].clear(); // TODO handle write FQM for media stream return Result::SUCCESS; } @@ -495,6 +522,8 @@ Result Demux::startRecordFilterHandler(uint32_t filterId) { recordEvent.indexMask.tsIndexMask() = 0x01; mFilterEvents[filterId].events.resize(1); mFilterEvents[filterId].events[0].ts() = recordEvent; + + mFilterOutputs[filterId].clear(); return Result::SUCCESS; } @@ -554,10 +583,7 @@ bool Demux::writeDataToFilterMQ(const std::vector& data, uint32_t filte return false; } -bool Demux::filterAndOutputData() { - Result result; - set::iterator it; - +bool Demux::readInputFMQ() { // Read input data from the input FMQ int size = mInputMQ->availableToRead(); int inputPacketSize = mInputSettings.packetSize; @@ -566,15 +592,29 @@ bool Demux::filterAndOutputData() { // Dispatch the packet to the PID matching filter output buffer for (int i = 0; i < size / inputPacketSize; i++) { - mInputMQ->read(dataOutputBuffer.data(), inputPacketSize); - for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { - uint16_t pid = ((dataOutputBuffer[1] & 0x1f) << 8) | ((dataOutputBuffer[2] & 0xff)); - if (pid == mFilterPids[*it]) { - mFilterOutputs[*it].insert(mFilterOutputs[*it].end(), dataOutputBuffer.begin(), - dataOutputBuffer.end()); - } + if (!mInputMQ->read(dataOutputBuffer.data(), inputPacketSize)) { + return false; + } + startTsFilter(dataOutputBuffer); + } + + return true; +} + +void Demux::startTsFilter(vector data) { + set::iterator it; + for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { + uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff)); + ALOGW("start ts filter pid: %d", pid); + if (pid == mFilterPids[*it]) { + mFilterOutputs[*it].insert(mFilterOutputs[*it].end(), data.begin(), data.end()); } } +} + +bool Demux::startFilterDispatcher() { + Result result; + set::iterator it; // Handle the output data per filter type for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { @@ -620,6 +660,7 @@ void* Demux::__threadLoopInput(void* user) { void Demux::filterThreadLoop(uint32_t filterId) { ALOGD("[Demux] filter %d threadLoop start.", filterId); + std::lock_guard lock(mFilterThreadLock); mFilterThreadRunning[filterId] = true; // For the first time of filter output, implementation needs to send the filter @@ -682,6 +723,7 @@ void Demux::filterThreadLoop(uint32_t filterId) { void Demux::inputThreadLoop() { ALOGD("[Demux] input threadLoop start."); + std::lock_guard lock(mInputThreadLock); mInputThreadRunning = true; while (mInputThreadRunning) { @@ -695,7 +737,7 @@ void Demux::inputThreadLoop() { } // Our current implementation filter the data and write it into the filter FMQ immedaitely // after the DATA_READY from the VTS/framework - if (!filterAndOutputData()) { + if (!readInputFMQ() || !startFilterDispatcher()) { ALOGD("[Demux] input data failed to be filtered. Ending thread"); break; } @@ -735,6 +777,70 @@ DemuxInputStatus Demux::checkStatusChange(uint32_t availableToWrite, uint32_t av return mIntputStatus; } +Result Demux::startBroadcastInputLoop() { + pthread_create(&mBroadcastInputThread, NULL, __threadLoopBroadcast, this); + pthread_setname_np(mBroadcastInputThread, "broadcast_input_thread"); + + return Result::SUCCESS; +} + +void* Demux::__threadLoopBroadcast(void* user) { + Demux* const self = static_cast(user); + self->broadcastInputThreadLoop(); + return 0; +} + +void Demux::broadcastInputThreadLoop() { + std::lock_guard lock(mBroadcastInputThreadLock); + mBroadcastInputThreadRunning = true; + mKeepFetchingDataFromFrontend = true; + + // open the stream and get its length + std::ifstream inputData(mFrontendSourceFile, std::ifstream::binary); + // TODO take the packet size from the frontend setting + int packetSize = 188; + int writePacketAmount = 6; + char* buffer = new char[packetSize]; + ALOGW("[Demux] broadcast input thread loop start %s", mFrontendSourceFile.c_str()); + if (!inputData.is_open()) { + mBroadcastInputThreadRunning = false; + ALOGW("[Demux] Error %s", strerror(errno)); + } + + while (mBroadcastInputThreadRunning) { + // move the stream pointer for packet size * 6 every read until the end + while (mKeepFetchingDataFromFrontend) { + for (int i = 0; i < writePacketAmount; i++) { + inputData.read(buffer, packetSize); + if (!inputData) { + mBroadcastInputThreadRunning = false; + break; + } + // filter and dispatch filter output + vector byteBuffer; + byteBuffer.resize(sizeof(buffer)); + for (int index = 0; index < byteBuffer.size(); index++) { + byteBuffer[index] = static_cast(buffer[index]); + } + startTsFilter(byteBuffer); + inputData.seekg(packetSize, inputData.cur); + } + startFilterDispatcher(); + sleep(1); + } + } + + ALOGW("[Demux] Broadcast Input thread end."); + delete[] buffer; + inputData.close(); +} + +void Demux::stopBroadcastInput() { + mKeepFetchingDataFromFrontend = false; + mBroadcastInputThreadRunning = false; + std::lock_guard lock(mBroadcastInputThreadLock); +} + } // namespace implementation } // namespace V1_0 } // namespace tuner diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h index eaf6ac3ed9..e4a4e2bdae 100644 --- a/tv/tuner/1.0/default/Demux.h +++ b/tv/tuner/1.0/default/Demux.h @@ -20,6 +20,8 @@ #include #include #include +#include "Frontend.h" +#include "Tuner.h" using namespace std; @@ -40,9 +42,12 @@ using ::android::hardware::tv::tuner::V1_0::Result; using FilterMQ = MessageQueue; +class Tuner; +class Frontend; + class Demux : public IDemux { public: - Demux(uint32_t demuxId); + Demux(uint32_t demuxId, sp tuner); ~Demux(); @@ -103,7 +108,17 @@ class Demux : public IDemux { virtual Return removeOutput() override; + // Functions interacts with Tuner Service + void stopBroadcastInput(); + private: + // Tuner service + sp mTunerService; + + // Frontend source + sp mFrontend; + string mFrontendSourceFile; + // A struct that passes the arguments to a newly created filter thread struct ThreadArgs { Demux* user; @@ -122,6 +137,7 @@ class Demux : public IDemux { Result startRecordFilterHandler(uint32_t filterId); Result startPcrFilterHandler(); Result startFilterLoop(uint32_t filterId); + Result startBroadcastInputLoop(); /** * To create a FilterMQ with the the next available Filter ID. @@ -143,14 +159,17 @@ class Demux : public IDemux { * A dispatcher to read and dispatch input data to all the started filters. * Each filter handler handles the data filtering/output writing/filterEvent updating. */ - bool filterAndOutputData(); + bool readInputFMQ(); + void startTsFilter(vector data); + bool startFilterDispatcher(); static void* __threadLoopFilter(void* data); static void* __threadLoopInput(void* user); + static void* __threadLoopBroadcast(void* user); void filterThreadLoop(uint32_t filterId); void inputThreadLoop(); + void broadcastInputThreadLoop(); uint32_t mDemuxId; - uint32_t mSourceFrontendId; /** * Record the last used filter id. Initial value is -1. * Filter Id starts with 0. @@ -195,6 +214,7 @@ class Demux : public IDemux { // Thread handlers pthread_t mInputThread; pthread_t mOutputThread; + pthread_t mBroadcastInputThread; vector mFilterThreads; // FMQ status local records @@ -204,6 +224,8 @@ class Demux : public IDemux { */ vector mFilterThreadRunning; bool mInputThreadRunning; + bool mBroadcastInputThreadRunning; + bool mKeepFetchingDataFromFrontend; /** * Lock to protect writes to the FMQs */ @@ -217,6 +239,9 @@ class Demux : public IDemux { * Lock to protect writes to the input status */ std::mutex mInputStatusLock; + std::mutex mBroadcastInputThreadLock; + std::mutex mFilterThreadLock; + std::mutex mInputThreadLock; /** * How many times a filter should write * TODO make this dynamic/random/can take as a parameter diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp index 6f87d1b8b3..1e07eddbfe 100644 --- a/tv/tuner/1.0/default/Frontend.cpp +++ b/tv/tuner/1.0/default/Frontend.cpp @@ -27,14 +27,10 @@ namespace tuner { namespace V1_0 { namespace implementation { -Frontend::Frontend() { - // Init callback to nullptr - mCallback = nullptr; -} - -Frontend::Frontend(FrontendType type, FrontendId id) { +Frontend::Frontend(FrontendType type, FrontendId id, sp tuner) { mType = type; mId = id; + mTunerService = tuner; // Init callback to nullptr mCallback = nullptr; } @@ -67,13 +63,18 @@ Return Frontend::tune(const FrontendSettings& /* settings */) { return Result::INVALID_STATE; } - mCallback->onEvent(FrontendEventType::NO_SIGNAL); + // TODO dynamically allocate file to the source file + mSourceStreamFile = FRONTEND_STREAM_FILE; + + mCallback->onEvent(FrontendEventType::LOCKED); return Result::SUCCESS; } Return Frontend::stopTune() { ALOGV("%s", __FUNCTION__); + mTunerService->frontendStopTune(mId); + return Result::SUCCESS; } @@ -119,6 +120,10 @@ FrontendId Frontend::getFrontendId() { return mId; } +string Frontend::getSourceFile() { + return mSourceStreamFile; +} + } // namespace implementation } // namespace V1_0 } // namespace tuner diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h index f881e8b641..07fa7b93ab 100644 --- a/tv/tuner/1.0/default/Frontend.h +++ b/tv/tuner/1.0/default/Frontend.h @@ -18,7 +18,9 @@ #define ANDROID_HARDWARE_TV_TUNER_V1_0_FRONTEND_H_ #include -#include +#include +#include +#include "Tuner.h" using namespace std; @@ -35,11 +37,11 @@ using ::android::hardware::tv::tuner::V1_0::IFrontend; using ::android::hardware::tv::tuner::V1_0::IFrontendCallback; using ::android::hardware::tv::tuner::V1_0::Result; +class Tuner; + class Frontend : public IFrontend { public: - Frontend(); - - Frontend(FrontendType type, FrontendId id); + Frontend(FrontendType type, FrontendId id, sp tuner); virtual Return close() override; @@ -64,11 +66,18 @@ class Frontend : public IFrontend { FrontendId getFrontendId(); + string getSourceFile(); + private: virtual ~Frontend(); sp mCallback; + sp mTunerService; FrontendType mType = FrontendType::UNDEFINED; FrontendId mId = 0; + + const string FRONTEND_STREAM_FILE = "/vendor/etc/test1.ts"; + string mSourceStreamFile; + std::ifstream mFrontendData; }; } // namespace implementation diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp index a4a8ca5043..f86b28d3c6 100644 --- a/tv/tuner/1.0/default/Tuner.cpp +++ b/tv/tuner/1.0/default/Tuner.cpp @@ -38,14 +38,14 @@ Tuner::Tuner() { // Array index matches their FrontendId in the default impl mFrontendSize = 8; mFrontends.resize(mFrontendSize); - mFrontends[0] = new Frontend(); - mFrontends[1] = new Frontend(FrontendType::ATSC, 1); - mFrontends[2] = new Frontend(FrontendType::DVBC, 2); - mFrontends[3] = new Frontend(FrontendType::DVBS, 3); - mFrontends[4] = new Frontend(FrontendType::DVBT, 4); - mFrontends[5] = new Frontend(FrontendType::ISDBT, 5); - mFrontends[6] = new Frontend(FrontendType::ANALOG, 6); - mFrontends[7] = new Frontend(FrontendType::ATSC, 7); + mFrontends[0] = new Frontend(FrontendType::DVBT, 0, this); + mFrontends[1] = new Frontend(FrontendType::ATSC, 1, this); + mFrontends[2] = new Frontend(FrontendType::DVBC, 2, this); + mFrontends[3] = new Frontend(FrontendType::DVBS, 3, this); + mFrontends[4] = new Frontend(FrontendType::DVBT, 4, this); + mFrontends[5] = new Frontend(FrontendType::ISDBT, 5, this); + mFrontends[6] = new Frontend(FrontendType::ANALOG, 6, this); + mFrontends[7] = new Frontend(FrontendType::ATSC, 7, this); } Tuner::~Tuner() {} @@ -81,7 +81,8 @@ Return Tuner::openDemux(openDemux_cb _hidl_cb) { DemuxId demuxId = mLastUsedId + 1; mLastUsedId += 1; - sp demux = new Demux(demuxId); + sp demux = new Demux(demuxId, this); + mDemuxes[demuxId] = demux; _hidl_cb(Result::SUCCESS, demuxId, demux); return Void(); @@ -132,6 +133,25 @@ Return Tuner::openLnbById(LnbId /* lnbId */, openLnbById_cb _hidl_cb) { return Void(); } +sp Tuner::getFrontendById(uint32_t frontendId) { + ALOGV("%s", __FUNCTION__); + + return mFrontends[frontendId]; +} + +void Tuner::setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId) { + mFrontendToDemux[frontendId] = demuxId; +} + +void Tuner::frontendStopTune(uint32_t frontendId) { + map::iterator it = mFrontendToDemux.find(frontendId); + uint32_t demuxId; + if (it != mFrontendToDemux.end()) { + demuxId = it->second; + mDemuxes[demuxId]->stopBroadcastInput(); + } +} + } // namespace implementation } // namespace V1_0 } // namespace tuner diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h index c089864d32..96da257b0a 100644 --- a/tv/tuner/1.0/default/Tuner.h +++ b/tv/tuner/1.0/default/Tuner.h @@ -18,6 +18,8 @@ #define ANDROID_HARDWARE_TV_TUNER_V1_0_TUNER_H_ #include +#include +#include "Demux.h" #include "Frontend.h" using namespace std; @@ -29,6 +31,9 @@ namespace tuner { namespace V1_0 { namespace implementation { +class Frontend; +class Demux; + class Tuner : public ITuner { public: Tuner(); @@ -50,10 +55,18 @@ class Tuner : public ITuner { virtual Return openLnbById(LnbId lnbId, openLnbById_cb _hidl_cb) override; + sp getFrontendById(uint32_t frontendId); + + void setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId); + + void frontendStopTune(uint32_t frontendId); + private: virtual ~Tuner(); // Static mFrontends array to maintain local frontends information vector> mFrontends; + std::map mFrontendToDemux; + std::map> mDemuxes; // To maintain how many Frontends we have int mFrontendSize; // The last used demux id. Initial value is -1. From 4bad0f9840dd1fcf4e57fe736af07af09240a263 Mon Sep 17 00:00:00 2001 From: Amy Date: Mon, 7 Oct 2019 17:28:23 -0700 Subject: [PATCH 0160/1022] Adding a Broadcast data flow test with a PES filter Test: atest Bug: 135708935 Change-Id: I64166ae5113a7c0bfd834a85c722a860c1d16694 --- .../VtsHalTvTunerV1_0TargetTest.cpp | 122 ++++++++++++++++-- 1 file changed, 113 insertions(+), 9 deletions(-) diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 30fe08a188..7936185af5 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -254,6 +254,7 @@ class DemuxCallback : public IDemuxCallback { void testOnFilterEvent(uint32_t filterId); void testFilterDataOutput(); + void stopInputThread(); void startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor); void startFilterEventThread(DemuxFilterEvent event); @@ -290,6 +291,7 @@ class DemuxCallback : public IDemuxCallback { android::Mutex mMsgLock; android::Mutex mFilterOutputLock; + android::Mutex mInputThreadLock; android::Condition mMsgCondition; android::Condition mFilterOutputCondition; @@ -326,15 +328,21 @@ void DemuxCallback::startFilterEventThread(DemuxFilterEvent event) { void DemuxCallback::testFilterDataOutput() { android::Mutex::Autolock autoLock(mMsgLock); - while (mPidFilterOutputCount < 3) { + while (mPidFilterOutputCount < 1) { if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { EXPECT_TRUE(false) << "filter output matching pid does not output within timeout"; return; } } + mPidFilterOutputCount = 0; ALOGW("[vts] pass and stop"); +} + +void DemuxCallback::stopInputThread() { mInputThreadRunning = false; mKeepWritingInputFMQ = false; + + android::Mutex::Autolock autoLock(mInputThreadLock); } void DemuxCallback::updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor) { @@ -358,6 +366,7 @@ void* DemuxCallback::__threadLoopInput(void* threadArgs) { } void DemuxCallback::inputThreadLoop(InputConf* inputConf, bool* keepWritingInputFMQ) { + android::Mutex::Autolock autoLock(mInputThreadLock); mInputThreadRunning = true; // Create the EventFlag that is used to signal the HAL impl that data have been @@ -372,13 +381,12 @@ void DemuxCallback::inputThreadLoop(InputConf* inputConf, bool* keepWritingInput char* buffer = new char[writeSize]; ALOGW("[vts] input thread loop start %s", inputConf->inputDataFile.c_str()); if (!inputData.is_open()) { - // log mInputThreadRunning = false; ALOGW("[vts] Error %s", strerror(errno)); } while (mInputThreadRunning) { - // move the stream pointer for packet size * 100 every read until the end + // move the stream pointer for packet size * 6 every read until the end while (*keepWritingInputFMQ) { inputData.read(buffer, writeSize); if (!inputData) { @@ -502,7 +510,8 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { ::testing::AssertionResult stopTuneFrontend(int32_t frontendId); ::testing::AssertionResult closeFrontend(int32_t frontendId); ::testing::AssertionResult createDemux(); - ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId); + ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId, + FrontendSettings settings); ::testing::AssertionResult getInputMQDescriptor(); ::testing::AssertionResult addInputToDemux(DemuxInputSettings setting); ::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting); @@ -514,6 +523,8 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { ::testing::AssertionResult playbackDataFlowTest(vector filterConf, InputConf inputConf, vector goldenOutputFiles); + ::testing::AssertionResult broadcastDataFlowTest(vector filterConf, + vector goldenOutputFiles); }; ::testing::AssertionResult TunerHidlTest::createFrontend(int32_t frontendId) { @@ -588,7 +599,8 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionResult(status == Result::SUCCESS); } -::testing::AssertionResult TunerHidlTest::createDemuxWithFrontend(int32_t frontendId) { +::testing::AssertionResult TunerHidlTest::createDemuxWithFrontend(int32_t frontendId, + FrontendSettings settings) { Result status; if (!mDemux && createDemux() == ::testing::AssertionFailure()) { @@ -599,6 +611,8 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionFailure(); } + mFrontendCallback->testOnEvent(mFrontend, settings); + status = mDemux->setFrontendDataSource(frontendId); return ::testing::AssertionResult(status == Result::SUCCESS); @@ -772,6 +786,7 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { // Data Verify Module mDemuxCallback->testFilterDataOutput(); + mDemuxCallback->stopInputThread(); // Clean Up Module for (int i = 0; i <= filterIdsSize; i++) { @@ -785,6 +800,65 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return closeDemux(); } +::testing::AssertionResult TunerHidlTest::broadcastDataFlowTest( + vector filterConf, vector /*goldenOutputFiles*/) { + Result status; + hidl_vec feIds; + + mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { + status = result; + feIds = frontendIds; + }); + + if (feIds.size() == 0) { + ALOGW("[ WARN ] Frontend isn't available"); + return ::testing::AssertionFailure(); + } + + FrontendDvbtSettings dvbt{ + .frequency = 1000, + }; + FrontendSettings settings; + settings.dvbt(dvbt); + + if (createDemuxWithFrontend(feIds[0], settings) != ::testing::AssertionSuccess()) { + return ::testing::AssertionFailure(); + } + + int filterIdsSize; + // Filter Configuration Module + for (int i = 0; i < filterConf.size(); i++) { + if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) == + ::testing::AssertionFailure() || + // TODO use a map to save the FMQs/EvenFlags and pass to callback + getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + filterIdsSize = mUsedFilterIds.size(); + mUsedFilterIds.resize(filterIdsSize + 1); + mUsedFilterIds[filterIdsSize] = mFilterId; + mDemuxCallback->updateFilterMQ(mFilterId, mFilterMQDescriptor); + status = mDemux->startFilter(mFilterId); + if (status != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + } + + // Data Verify Module + mDemuxCallback->testFilterDataOutput(); + + // Clean Up Module + for (int i = 0; i <= filterIdsSize; i++) { + if (mDemux->stopFilter(mUsedFilterIds[i]) != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + } + if (mFrontend->stopTune() != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + return closeDemux(); +} + /* * API STATUS TESTS */ @@ -868,7 +942,7 @@ TEST_F(TunerHidlTest, CloseFrontend) { } } -TEST_F(TunerHidlTest, CreateDemuxWithFrontend) { +/*TEST_F(TunerHidlTest, CreateDemuxWithFrontend) { Result status; hidl_vec feIds; @@ -883,10 +957,17 @@ TEST_F(TunerHidlTest, CreateDemuxWithFrontend) { return; } + FrontendDvbtSettings dvbt{ + .frequency = 1000, + }; + FrontendSettings settings; + settings.dvbt(dvbt); + for (size_t i = 0; i < feIds.size(); i++) { - ASSERT_TRUE(createDemuxWithFrontend(feIds[i])); + ASSERT_TRUE(createDemuxWithFrontend(feIds[i], settings)); + mFrontend->stopTune(); } -} +}*/ TEST_F(TunerHidlTest, CreateDemux) { description("Create Demux"); @@ -920,7 +1001,7 @@ TEST_F(TunerHidlTest, PlaybackDataFlowWithPesFilterTest) { DemuxFilterSettings filterSetting; DemuxFilterPesDataSettings pesFilterSetting{ - .tpid = 4720, + .tpid = 18, }; filterSetting.pesData(pesFilterSetting); FilterConf pesFilterConf{ @@ -947,6 +1028,29 @@ TEST_F(TunerHidlTest, PlaybackDataFlowWithPesFilterTest) { ASSERT_TRUE(playbackDataFlowTest(filterConf, inputConf, goldenOutputFiles)); } +TEST_F(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) { + description("Feed ts data from frontend and test with PES filter"); + + // todo modulize the filter conf parser + vector filterConf; + filterConf.resize(1); + + DemuxFilterSettings filterSetting; + DemuxFilterPesDataSettings pesFilterSetting{ + .tpid = 18, + }; + filterSetting.pesData(pesFilterSetting); + FilterConf pesFilterConf{ + .type = DemuxFilterType::PES, + .setting = filterSetting, + }; + filterConf[0] = pesFilterConf; + + vector goldenOutputFiles; + + ASSERT_TRUE(broadcastDataFlowTest(filterConf, goldenOutputFiles)); +} + } // namespace int main(int argc, char** argv) { From e36b09b4c9fec6a6ab5b1f2fca335ba94addb47f Mon Sep 17 00:00:00 2001 From: Nick Chalko Date: Fri, 4 Oct 2019 17:06:40 -0700 Subject: [PATCH 0161/1022] Fix some spelling errors Test: m android.hardware.tv.tuner@1.0 Change-Id: I2f1551106a2d18efe0819bea62cd0f9a0679c636 --- tv/tuner/1.0/IDemux.hal | 8 ++++---- tv/tuner/1.0/IFrontend.hal | 2 +- tv/tuner/1.0/ITuner.hal | 2 +- tv/tuner/1.0/default/Demux.cpp | 2 +- tv/tuner/1.0/types.hal | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tv/tuner/1.0/IDemux.hal b/tv/tuner/1.0/IDemux.hal index 7ead34b00e..7fd7e265bc 100644 --- a/tv/tuner/1.0/IDemux.hal +++ b/tv/tuner/1.0/IDemux.hal @@ -62,9 +62,9 @@ interface IDemux { * * It is used by the client to get the descriptor of the filter's Fast * Message Queue. The data in FMQ is filtered out from MPEG transport - * stream. The data is origanized to data blocks which may have + * stream. The data is organized to data blocks which may have * different length. The length's information of one or multiple data blocks - * is sent to client throught DemuxFilterEvent. + * is sent to client through DemuxFilterEvent. * * @param filterId the ID of the filter. * @return result Result status of the operation. @@ -97,7 +97,7 @@ interface IDemux { /** * Start the filter. * - * It is used by the client to ask the filter to start filterring data. + * It is used by the client to ask the filter to start filtering data. * * @param filterId the ID of the filter. * @return result Result status of the operation. @@ -218,7 +218,7 @@ interface IDemux { * * It is used by the client to get the descriptor of the output's Fast * Message Queue. The data in FMQ is muxed packets output from selected - * filters. The packet's format is specifed by DemuxDataFormat in + * filters. The packet's format is specified by DemuxDataFormat in * DemuxOutputSettings. * * @return result Result status of the operation. diff --git a/tv/tuner/1.0/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal index d337ac1b81..83e390ddcf 100644 --- a/tv/tuner/1.0/IFrontend.hal +++ b/tv/tuner/1.0/IFrontend.hal @@ -148,7 +148,7 @@ interface IFrontend { setLnb(LnbId lnbId) generates (Result result); /** - * Enble or Disable Low Noise Amplifier (LNA). + * Enable or Disable Low Noise Amplifier (LNA). * * @param bEnable true if activate LNA module; false if deactivate LNA * diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal index 0d63442d07..1cf0e387b6 100644 --- a/tv/tuner/1.0/ITuner.hal +++ b/tv/tuner/1.0/ITuner.hal @@ -23,7 +23,7 @@ import ILnb; /** * Top level interface to manage Frontend, Demux and Decrambler hardware - * resouces which are needed for Android TV. + * resources which are needed for Android TV. */ interface ITuner { /** diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp index 04382b0f99..d65df594a6 100644 --- a/tv/tuner/1.0/default/Demux.cpp +++ b/tv/tuner/1.0/default/Demux.cpp @@ -735,7 +735,7 @@ void Demux::inputThreadLoop() { ALOGD("[Demux] wait for data ready on the input FMQ"); continue; } - // Our current implementation filter the data and write it into the filter FMQ immedaitely + // Our current implementation filter the data and write it into the filter FMQ immediately // after the DATA_READY from the VTS/framework if (!readInputFMQ() || !startFilterDispatcher()) { ALOGD("[Demux] input data failed to be filtered. Ending thread"); diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index b6f11ee3c2..890c1edd01 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -58,7 +58,7 @@ enum FrontendType : uint32_t { DVBS, /** * Digital Video Broadcasting - Terrestrial - * DVB Terresttrial Frontend Standard ETSI EN 300 468 V1.15.1 and + * DVB Terrestrial Frontend Standard ETSI EN 300 468 V1.15.1 and * ETSI EN 302 755 V1.4.1. */ DVBT, @@ -655,7 +655,7 @@ enum FrontendIsdbsRolloff : uint32_t { }; /** - * Modulaltion Type for ISDBS. + * Modulation Type for ISDBS. */ @export enum FrontendIsdbsModulation : uint32_t { @@ -951,7 +951,7 @@ enum FrontendScanMessageType : uint32_t { GROUP_IDS, /** Stream Ids. */ INPUT_STREAM_IDS, - /** Locked signal stardard. */ + /** Locked signal standard. */ STANDARD, /** PLP status in a tuned frequency band for ATSC3 frontend. */ ATSC3_PLP_INFO, @@ -969,7 +969,7 @@ struct FrontendScanAtsc3PlpInfo { * Scan Message for Frontend. */ safe_union FrontendScanMessage { - bool islocked; + bool isLocked; bool isEnd; /** scan progress percent (0..100) */ uint8_t progressPercent; From 2d724a3251c81d5f0142babb7076423cf0650920 Mon Sep 17 00:00:00 2001 From: Nick Chalko Date: Tue, 8 Oct 2019 11:24:50 -0700 Subject: [PATCH 0162/1022] Add a README for tuner HAL. Test: viewed on gtiles. Change-Id: Ib03bd9ffecd0c67a504a129db7b1cf16181f7b1f --- tv/tuner/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tv/tuner/README.md diff --git a/tv/tuner/README.md b/tv/tuner/README.md new file mode 100644 index 0000000000..a833c8740c --- /dev/null +++ b/tv/tuner/README.md @@ -0,0 +1,12 @@ +# Tuner HALs + +## Overview + +TV specific tuners. + +Sett 1.0/ITuner.hal for an overview. + +*** note +**Warning:** The HALs are not (yet) frozen, as the HAL definition is +expected to evolve between Android releases. +*** From e98e6793be04416ead2c56c73baa25cdccd767e9 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Fri, 4 Oct 2019 15:19:52 +0100 Subject: [PATCH 0163/1022] Add template for 1.3 types.hal and regenerate it After this update, types.hal v1.3 no longer refers to API level 30. Test: none needed Bug: 140132458 Change-Id: If707dfbcade6be1a0885fc21f6ddf47f3c27b244 --- current.txt | 2 +- neuralnetworks/1.2/types.t | 22 +-- neuralnetworks/1.3/types.hal | 30 ++- neuralnetworks/1.3/types.t | 344 +++++++++++++++++++++++++++++++++++ 4 files changed, 367 insertions(+), 31 deletions(-) create mode 100644 neuralnetworks/1.3/types.t diff --git a/current.txt b/current.txt index e164a3fb5b..5c7539c6f4 100644 --- a/current.txt +++ b/current.txt @@ -586,7 +586,7 @@ fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardwar # HALs released in Android R 34515afa2bb792d3c6d8495a5f5d907d179c8507ca5e55c10050d02ae1d516ef android.hardware.neuralnetworks@1.3::IDevice -e2d20d4eb24f40b44a3766d05f77052581cb3f4df35fb48c0cc5d9cdcf5c872e android.hardware.neuralnetworks@1.3::types +b74fe72cfe438f50e772e6a307657ff449d5bde83c15dd1f140ff2edbe73499c android.hardware.neuralnetworks@1.3::types 04395b26be33db17747c3d3b0e8066d323f891ff4f9f3b3ddb490b2f3f844a18 android.hardware.wifi@1.4::IWifi 270f0eb670dfd9bc5cd718e09711f2534fa8425f54d06c1a46523ca156b509e2 android.hardware.wifi.supplicant@1.3::ISupplicant dd4b7cfbb6e1c6ff011c33920762ad89dd02240c63a4d3a3d5037f154eae3e3b android.hardware.wifi.supplicant@1.3::ISupplicantStaIface diff --git a/neuralnetworks/1.2/types.t b/neuralnetworks/1.2/types.t index cab330d454..d197f6b541 100644 --- a/neuralnetworks/1.2/types.t +++ b/neuralnetworks/1.2/types.t @@ -41,27 +41,7 @@ enum Constant : uint32_t { enum OperandType : @1.0::OperandType { %insert Operand_1.2 - - /* - * DEPRECATED. Since HAL version 1.2, extensions are the preferred - * alternative to OEM operation and data types. - * - * OEM specific scalar value. - * OEM = 10000, - */ - /* - * DEPRECATED. Since HAL version 1.2, extensions are the preferred - * alternative to OEM operation and data types. - * - * A tensor of OEM specific values. - * TENSOR_OEM_BYTE = 10001, - */ - /* ADDING A NEW FUNDAMENTAL TYPE REQUIRES UPDATING THE VALUE OF - * OperandTypeRange::FUNDAMENTAL_MAX. - */ - /* ADDING A NEW OEM TYPE REQUIRES UPDATING THE VALUE OF - * OperandTypeRange::OEM_MAX. - */ +%insert OEMDeprecationAndOperandTypeRangeMaxComment }; /** diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index db5dd51017..86ab287067 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -25,13 +25,6 @@ import @1.2::SymmPerChannelQuantParams; import android.hidl.safe_union@1.0::Monostate; -/** - * NOTE: Since NNAPI 1.2, OEM operation and data type are deprecated. Extensions - * are the preferred alternative. - * - * NOTE: Adding a new fundamental type requires updating the value of - * OperandTypeRange::FUNDAMENTAL_MAX. - */ enum OperandType : @1.2::OperandType { /** * A tensor of 8 bit signed integers that represent real numbers. @@ -43,10 +36,29 @@ enum OperandType : @1.2::OperandType { * * The formula is: * real_value = (integer_value - zeroPoint) * scale. - * - * Available since API level 30. */ TENSOR_QUANT8_ASYMM_SIGNED = 14, + + /* + * DEPRECATED. Since HAL version 1.2, extensions are the preferred + * alternative to OEM operation and data types. + * + * OEM specific scalar value. + * OEM = 10000, + */ + /* + * DEPRECATED. Since HAL version 1.2, extensions are the preferred + * alternative to OEM operation and data types. + * + * A tensor of OEM specific values. + * TENSOR_OEM_BYTE = 10001, + */ + /* ADDING A NEW FUNDAMENTAL TYPE REQUIRES UPDATING THE VALUE OF + * OperandTypeRange::FUNDAMENTAL_MAX. + */ + /* ADDING A NEW OEM TYPE REQUIRES UPDATING THE VALUE OF + * OperandTypeRange::OEM_MAX. + */ }; /** diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t new file mode 100644 index 0000000000..d41cfd2c92 --- /dev/null +++ b/neuralnetworks/1.3/types.t @@ -0,0 +1,344 @@ +%% template file for generating types.hal. +%% see frameworks/ml/nn/tools/api/README.md. +/* + * 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. + */ + +package android.hardware.neuralnetworks@1.3; + +import @1.0::DataLocation; +import @1.0::OperandLifeTime; +import @1.0::PerformanceInfo; +import @1.2::OperandType; +import @1.2::OperationType; +import @1.2::SymmPerChannelQuantParams; + +import android.hidl.safe_union@1.0::Monostate; + +enum OperandType : @1.2::OperandType { +%insert Operand_1.3 +%insert OEMDeprecationAndOperandTypeRangeMaxComment +}; + +/** + * The range of operand values in the OperandType enum. + */ +enum OperandTypeRange : uint32_t { + BASE_MIN = 0, + FUNDAMENTAL_MIN = 0, +%insert Operand_1.3_MAX + OEM_MIN = 10000, + OEM_MAX = 10001, + BASE_MAX = 0xFFFF, +}; + + +/** + * The capabilities of a driver. + * + * Performance of an operation comes from the type of its first operand. + * This represents performance for non extension operand types. + */ +struct Capabilities { + /** + * Driver performance when operating on float32 data but performing + * calculations with range and/or precision as low as that of the IEEE + * 754 16-bit floating-point format. + */ + PerformanceInfo relaxedFloat32toFloat16PerformanceScalar; + PerformanceInfo relaxedFloat32toFloat16PerformanceTensor; + + /** + * Driver performance when operating on a particular data type. + * In the case of float32 data, this is used when the calculations + * are not relaxed. + */ + struct OperandPerformance { + OperandType type; + PerformanceInfo info; + }; + + /** + * Performance by operand type. Must be sorted by OperandType. + * If a particular OperandType is not present in operandPerformance, + * its performance is treated as + * { .execTime = FLT_MAX, .powerUsage = FLT_MAX }. + */ + vec operandPerformance; +}; + +/** + * Describes one operand of the model's graph. + */ +struct Operand { + /** + * The data type. + * + * Besides the values listed in {@link OperandType}, any value above + * {@link OperandTypeRange::BASE_MAX} is possible and should be interpreted + * as an extension type according to {@link Model::extensionNameToPrefix}. + */ + OperandType type; + + /** + * Dimensions of the operand. + * + * For a scalar operand, dimensions.size() must be 0. + * + * A tensor operand with all dimensions specified has "fully + * specified" dimensions. Whenever possible (i.e., whenever the + * dimensions are known at model construction time), a tensor + * operand should have (but is not required to have) fully + * specified dimensions, in order to enable the best possible + * performance. + * + * 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. + * + * In the following situations, a tensor operand's dimensions must + * be fully specified: + * + * . The operand has lifetime CONSTANT_COPY or + * CONSTANT_REFERENCE. + * + * . The operand has lifetime MODEL_INPUT. 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 + * (by setting the hasNoValue field of the corresponding + * RequestArgument to true) then it need not have fully + * specified dimensions. + * + * A tensor operand with some number of unspecified dimensions is + * represented by setting each unspecified dimension to 0. + * + * A tensor operand with unspecified rank is represented by providing + * an empty dimensions vector. + */ + vec dimensions; + + /** + * The number of times this operand appears as an operation input. + * + * (For example, if this operand appears once in one operation's + * input list, and three times in another operation's input list, + * then numberOfConsumers = 4.) + */ + uint32_t numberOfConsumers; + + /** + * Quantized scale of the operand. + * + * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM or + * TENSOR_INT32. + */ + float scale; + + /** + * Quantized zero-point offset of the operand. + * + * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM. + */ + int32_t zeroPoint; + + /** + * How the operand is used. + */ + OperandLifeTime lifetime; + + /** + * Where to find the data for this operand. + * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or + * NO_VALUE: + * - All the fields must be 0. + * If the lifetime is CONSTANT_COPY: + * - location.poolIndex is 0. + * - location.offset is the offset in bytes into Model.operandValues. + * - location.length is set. + * If the lifetime is CONSTANT_REFERENCE: + * - location.poolIndex is set. + * - location.offset is the offset in bytes into the specified pool. + * - location.length is set. + */ + DataLocation location; + + /** + * Additional parameters specific to a particular operand type. + */ + safe_union ExtraParams { + /** + * No additional parameters. + */ + Monostate none; + + /** + * Symmetric per-channel quantization parameters. + * + * Only applicable to operands of type TENSOR_QUANT8_SYMM_PER_CHANNEL. + */ + SymmPerChannelQuantParams channelQuant; + + /** + * Extension operand parameters. + * + * The framework treats this as an opaque data blob. + * The format is up to individual extensions. + */ + vec extension; + } extraParams; +}; + +/** + * Describes one operation of the model's graph. + */ +struct Operation { + /** + * The operation type. + */ + OperationType type; + + /** + * Describes the table that contains the indexes of the inputs of the + * operation. The offset is the index in the operandIndexes table. + */ + vec inputs; + + /** + * Describes the table that contains the indexes of the outputs of the + * operation. The offset is the index in the operandIndexes table. + */ + vec outputs; +}; + +/** + * A Neural Network Model. + * + * This includes not only the execution graph, but also constant data such as + * weights or scalars added at construction time. The only information that + * may not be known is the shape of the input tensors. + */ +struct Model { + /** + * All operands included in the model. + */ + vec operands; + + /** + * All operations included in the model. + * + * The operations are sorted into execution order. Every operand + * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be + * written before it is read. + */ + vec operations; + + /** + * Input indexes of the model. There must be at least one. + * + * Each value corresponds to the index of the operand in "operands". + */ + vec inputIndexes; + + /** + * Output indexes of the model. There must be at least one. + * + * Each value corresponds to the index of the operand in "operands". + */ + vec outputIndexes; + + /** + * A byte buffer containing operand data that were copied into the model. + * + * An operand's value must be located here if and only if Operand::lifetime + * equals OperandLifeTime::CONSTANT_COPY. + */ + vec operandValues; + + /** + * A collection of shared memory pools containing operand values. + * + * An operand's value must be located here if and only if Operand::lifetime + * equals OperandLifeTime::CONSTANT_REFERENCE. + */ + vec pools; + + /** + * 'true' indicates TENSOR_FLOAT32 may be calculated with range and/or + * precision as low as that of the IEEE 754 16-bit floating-point format. + * 'false' indicates TENSOR_FLOAT32 must be calculated using at least the + * range and precision of the IEEE 754 32-bit floating-point format. + */ + bool relaxComputationFloat32toFloat16; + + /** + * The mapping between extension names and prefixes of operand and + * operation type values. + * + * An operand or operation whose numeric type value is above + * {@link OperandTypeRange::BASE_MAX} or + * {@link OperationTypeRange::BASE_MAX} respectively should be interpreted + * as an extension operand. The low + * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value + * correspond to the type ID within the extension and the high + * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode + * the "prefix", which maps uniquely to the extension name. + * + * For example, if a model contains an operation whose value is + * 0xAAAABBBB and extensionNameToPrefix contains an entry with + * prefix=0xAAAA and name="vendor.test.test_extension", then + * the operation should be interpreted as the operation 0xBBBB + * of the extension named vendor.test.test_extension. + * + * This is a one-to-one correspondence. That is, there must be at most one + * prefix corresponding to each extension name and at most one extension + * name corresponding to each prefix. + */ + vec extensionNameToPrefix; + + /** + * A correspondence between an extension name and a prefix of operand and + * operation type values. + */ + struct ExtensionNameAndPrefix { + /** + * The extension name. + * + * See {@link Extension::name} for the format specification. + */ + string name; + + /** + * The unique extension identifier within the model. + * + * See {@link Model::extensionNameToPrefix}. + */ + uint16_t prefix; + }; + + /** + * Numeric values of extension operand and operation types have the + * following structure: + * - 16 high bits represent the "prefix", which corresponds uniquely to the + * extension name. + * - 16 low bits represent the type ID within the extension. + */ + enum ExtensionTypeEncoding : uint8_t { + HIGH_BITS_PREFIX = 16, + LOW_BITS_TYPE = 16, + }; +}; From 5756887a7ba72d33edc9093b5bd80211584de3ff Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Thu, 25 Jul 2019 17:22:11 -0700 Subject: [PATCH 0164/1022] NNAPI VTS update in response to utility function change The frameworks/ml/nn CL "Improve performance of Burst executions" changed the signature of a utility function used by NNAPI's VTS tests. This CL modifies the test accordingly. Bug: 132073143 Test: mma Test: VtsHalNeuralnetworksV1_2TargetTest (with sample-all) Test: VtsHalNeuralnetworksV1_3TargetTest (with sample-all) Change-Id: I56c3b04e6fec11d526e2a1ff5b896f31cb12eb5f --- .../1.2/vts/functional/GeneratedTestHarness.cpp | 8 ++++++-- neuralnetworks/1.2/vts/functional/ValidateBurst.cpp | 13 +++++++++---- .../1.2/vts/functional/ValidateRequest.cpp | 13 +++++++------ .../1.3/vts/functional/GeneratedTestHarness.cpp | 8 ++++++-- neuralnetworks/1.3/vts/functional/ValidateBurst.cpp | 13 +++++++++---- .../1.3/vts/functional/ValidateRequest.cpp | 13 +++++++------ 6 files changed, 44 insertions(+), 24 deletions(-) diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp index 2beec983e0..aacb38500b 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -190,7 +191,8 @@ static Return ExecutePreparedModel(const sp& prepar } static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst( const sp& preparedModel) { - return android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true); + return android::nn::ExecutionBurstController::create(preparedModel, + std::chrono::microseconds{0}); } enum class Executor { ASYNC, SYNC, BURST }; @@ -254,8 +256,10 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo } // execute burst - std::tie(executionStatus, outputShapes, timing) = + int n; + std::tie(n, outputShapes, timing, std::ignore) = controller->compute(request, measure, keys); + executionStatus = nn::convertResultCodeToErrorStatus(n); break; } diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp index 1d4493d208..416744f902 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp @@ -26,6 +26,7 @@ #include "Utils.h" #include +#include #include namespace android::hardware::neuralnetworks::V1_2::vts::functional { @@ -64,9 +65,9 @@ static void createBurst(const sp& preparedModel, const sp& preparedModel, } // collect serialized result by running regular burst - const auto [statusRegular, outputShapesRegular, timingRegular] = + const auto [nRegular, outputShapesRegular, timingRegular, fallbackRegular] = controllerRegular->compute(request, MeasureTiming::NO, keys); + const ErrorStatus statusRegular = nn::convertResultCodeToErrorStatus(nRegular); + EXPECT_FALSE(fallbackRegular); // skip test if regular burst output isn't useful for testing a failure // caused by having too small of a length for the result FMQ @@ -307,11 +310,13 @@ static void validateBurstFmqLength(const sp& preparedModel, // by this point, execution should fail because the result channel isn't // large enough to return the serialized result - const auto [statusSmall, outputShapesSmall, timingSmall] = + const auto [nSmall, outputShapesSmall, timingSmall, fallbackSmall] = controllerSmall->compute(request, MeasureTiming::NO, keys); + const ErrorStatus statusSmall = nn::convertResultCodeToErrorStatus(nSmall); EXPECT_NE(ErrorStatus::NONE, statusSmall); EXPECT_EQ(0u, outputShapesSmall.size()); EXPECT_TRUE(badTiming(timingSmall)); + EXPECT_FALSE(fallbackSmall); } static bool isSanitized(const FmqResultDatum& datum) { diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp index f25ee62617..2d83b8186c 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" +#include #include "1.0/Utils.h" #include "1.2/Callbacks.h" #include "ExecutionBurstController.h" @@ -94,7 +95,8 @@ static void validate(const sp& preparedModel, const std::string& // create burst std::shared_ptr<::android::nn::ExecutionBurstController> burst = - android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true); + android::nn::ExecutionBurstController::create(preparedModel, + std::chrono::microseconds{0}); ASSERT_NE(nullptr, burst.get()); // create memory keys @@ -104,13 +106,12 @@ static void validate(const sp& preparedModel, const std::string& } // execute and verify - ErrorStatus error; - std::vector outputShapes; - Timing timing; - std::tie(error, outputShapes, timing) = burst->compute(request, measure, keys); - EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, error); + const auto [n, outputShapes, timing, fallback] = burst->compute(request, measure, keys); + const ErrorStatus status = nn::convertResultCodeToErrorStatus(n); + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); EXPECT_EQ(outputShapes.size(), 0); EXPECT_TRUE(badTiming(timing)); + EXPECT_FALSE(fallback); // additional burst testing if (request.pools.size() > 0) { diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 16a7d70fb5..8a7ed24c9d 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -200,7 +201,8 @@ static Return ExecutePreparedModel(const sp& prepar } static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst( const sp& preparedModel) { - return android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true); + return android::nn::ExecutionBurstController::create(preparedModel, + std::chrono::microseconds{0}); } enum class Executor { ASYNC, SYNC, BURST }; @@ -264,8 +266,10 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo } // execute burst - std::tie(executionStatus, outputShapes, timing) = + int n; + std::tie(n, outputShapes, timing, std::ignore) = controller->compute(request, measure, keys); + executionStatus = nn::convertResultCodeToErrorStatus(n); break; } diff --git a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp index 95f9f427b2..2c97294fad 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp @@ -26,6 +26,7 @@ #include "Utils.h" #include +#include #include namespace android::hardware::neuralnetworks::V1_3::vts::functional { @@ -71,9 +72,9 @@ static void createBurst(const sp& preparedModel, const sp& preparedModel, } // collect serialized result by running regular burst - const auto [statusRegular, outputShapesRegular, timingRegular] = + const auto [nRegular, outputShapesRegular, timingRegular, fallbackRegular] = controllerRegular->compute(request, MeasureTiming::NO, keys); + const ErrorStatus statusRegular = nn::convertResultCodeToErrorStatus(nRegular); + EXPECT_FALSE(fallbackRegular); // skip test if regular burst output isn't useful for testing a failure // caused by having too small of a length for the result FMQ @@ -314,11 +317,13 @@ static void validateBurstFmqLength(const sp& preparedModel, // by this point, execution should fail because the result channel isn't // large enough to return the serialized result - const auto [statusSmall, outputShapesSmall, timingSmall] = + const auto [nSmall, outputShapesSmall, timingSmall, fallbackSmall] = controllerSmall->compute(request, MeasureTiming::NO, keys); + const ErrorStatus statusSmall = nn::convertResultCodeToErrorStatus(nSmall); EXPECT_NE(ErrorStatus::NONE, statusSmall); EXPECT_EQ(0u, outputShapesSmall.size()); EXPECT_TRUE(badTiming(timingSmall)); + EXPECT_FALSE(fallbackSmall); } static bool isSanitized(const FmqResultDatum& datum) { diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index 612212382c..c00512c4d3 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" +#include #include "1.0/Utils.h" #include "1.2/Callbacks.h" #include "ExecutionBurstController.h" @@ -98,7 +99,8 @@ static void validate(const sp& preparedModel, const std::string& // create burst std::shared_ptr<::android::nn::ExecutionBurstController> burst = - android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true); + android::nn::ExecutionBurstController::create(preparedModel, + std::chrono::microseconds{0}); ASSERT_NE(nullptr, burst.get()); // create memory keys @@ -108,13 +110,12 @@ static void validate(const sp& preparedModel, const std::string& } // execute and verify - ErrorStatus error; - std::vector outputShapes; - Timing timing; - std::tie(error, outputShapes, timing) = burst->compute(request, measure, keys); - EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, error); + const auto [n, outputShapes, timing, fallback] = burst->compute(request, measure, keys); + const ErrorStatus status = nn::convertResultCodeToErrorStatus(n); + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); EXPECT_EQ(outputShapes.size(), 0); EXPECT_TRUE(badTiming(timing)); + EXPECT_FALSE(fallback); // additional burst testing if (request.pools.size() > 0) { From c37306ea65a5ae77d8baf31497cb28eb20a029a6 Mon Sep 17 00:00:00 2001 From: Patrik Fimml Date: Tue, 8 Oct 2019 14:07:57 +0200 Subject: [PATCH 0165/1022] Wifi VTS: use VTS-native feature detection Previously, VTS would run VtsHalWifiV1_0HostTest, a python script on the host that tries identify whether SoftAP and NAN should be supported by the device. This is complex, prevents migration to pure gtests without custom runners, and duplicates logic that has become available in VTS. This switches to equivalent methods natively available in VTS: - NAN: We can use "precondition-feature" to check for the "android.hardware.wifi.aware" feature. - SoftAP: We can use "precondition-lshal" to check whether the "android.hardware.wifi.hostapd" HAL is declared in the device manifest (should have the same semantics as the previous python check). This splits out NAN- and SoftAP-dependent parts of IWifiChip tests so that they can use this method, so some tests moved between these targets: - VtsHalWifiV1_0TargetTest - VtsHalWifiApV1_0TargetTest - VtsHalWifiNanV1_0TargetTest Bug: 142304083 Test: vts-tradefed run vts --primary-abi-only --skip-device-info -l DEBUG --include-filter VtsHalWifiV1_0Target --include-filter VtsHalWifiApV1_0Target --include-filter VtsHalWifiNanV1_0Target --include-filter VtsHalWifiV1_1Target --include-filter VtsHalWifiV1_2Target --include-filter VtsHalWifiV1_3Target --include-filter VtsHalWifiApV1_4Target Change-Id: Ica0b58811a0aa152c1a6c3c9a35d577d6ae70160 --- wifi/1.0/vts/functional/Android.bp | 25 +- .../functional/VtsHalWifiV1_0TargetTest.cpp | 7 +- .../functional/wifi_ap_iface_hidl_test.cpp | 8 - .../vts/functional/wifi_chip_hidl_ap_test.cpp | 168 +++++++++++++ .../functional/wifi_chip_hidl_nan_test.cpp | 169 +++++++++++++ .../vts/functional/wifi_chip_hidl_test.cpp | 222 +----------------- .../1.0/vts/functional/wifi_hidl_test_utils.h | 44 ---- .../functional/VtsHalWifiV1_1TargetTest.cpp | 7 +- wifi/1.4/vts/functional/Android.bp | 3 +- .../functional/VtsHalWifiV1_4TargetTest.cpp | 7 +- .../functional/wifi_ap_iface_hidl_test.cpp | 4 - 11 files changed, 372 insertions(+), 292 deletions(-) create mode 100644 wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp create mode 100644 wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp index 397ad179af..6fa6e7ed6d 100644 --- a/wifi/1.0/vts/functional/Android.bp +++ b/wifi/1.0/vts/functional/Android.bp @@ -28,7 +28,9 @@ cc_library_static { shared_libs: [ "libnativehelper", ], - static_libs: ["android.hardware.wifi@1.0"], + static_libs: [ + "android.hardware.wifi@1.0", + ], } cc_test { @@ -36,7 +38,6 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: [ "VtsHalWifiV1_0TargetTest.cpp", - "wifi_ap_iface_hidl_test.cpp", "wifi_chip_hidl_test.cpp", "wifi_p2p_iface_hidl_test.cpp", "wifi_rtt_controller_hidl_test.cpp", @@ -52,11 +53,14 @@ cc_test { test_suites: ["general-tests"], } +// These tests are split out so that they can be conditioned on presence of the +// "android.hardware.wifi.aware" feature. cc_test { name: "VtsHalWifiNanV1_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ "VtsHalWifiV1_0TargetTest.cpp", + "wifi_chip_hidl_nan_test.cpp", "wifi_nan_iface_hidl_test.cpp", ], static_libs: [ @@ -65,3 +69,20 @@ cc_test { ], test_suites: ["general-tests"], } + +// These tests are split out so that they can be conditioned on presence of +// the hostapd HAL, which indicates SoftAP support. +cc_test { + name: "VtsHalWifiApV1_0TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "VtsHalWifiV1_0TargetTest.cpp", + "wifi_ap_iface_hidl_test.cpp", + "wifi_chip_hidl_ap_test.cpp", + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "android.hardware.wifi@1.0", + ], + test_suites: ["general-tests"], +} diff --git a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp index e7b85938cf..9d25014229 100644 --- a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp +++ b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp @@ -41,10 +41,7 @@ int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(gEnv); ::testing::InitGoogleTest(&argc, argv); gEnv->init(&argc, argv); - int status = gEnv->initFromOptions(argc, argv); - if (status == 0) { - status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - } + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; return status; } diff --git a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp index e5762f28f0..c55221d105 100644 --- a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp @@ -29,21 +29,17 @@ using ::android::hardware::wifi::V1_0::WifiBand; using ::android::hardware::wifi::V1_0::WifiStatusCode; using ::android::sp; -extern WifiHidlEnvironment* gEnv; - /** * Fixture to use for all AP Iface HIDL interface tests. */ class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { public: virtual void SetUp() override { - if (!gEnv->isSoftApOn) return; wifi_ap_iface_ = getWifiApIface(); ASSERT_NE(nullptr, wifi_ap_iface_.get()); } virtual void TearDown() override { - if (!gEnv->isSoftApOn) return; stopWifi(); } @@ -57,7 +53,6 @@ class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { * successfully created. */ TEST(WifiApIfaceHidlTestNoFixture, Create) { - if (!gEnv->isSoftApOn) return; EXPECT_NE(nullptr, getWifiApIface().get()); stopWifi(); } @@ -67,7 +62,6 @@ TEST(WifiApIfaceHidlTestNoFixture, Create) { * Ensures that the correct interface type is returned for AP interface. */ TEST_F(WifiApIfaceHidlTest, GetType) { - if (!gEnv->isSoftApOn) return; const auto& status_and_type = HIDL_INVOKE(wifi_ap_iface_, getType); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_type.first.code); EXPECT_EQ(IfaceType::AP, status_and_type.second); @@ -79,7 +73,6 @@ TEST_F(WifiApIfaceHidlTest, GetType) { * status code. */ TEST_F(WifiApIfaceHidlTest, SetCountryCode) { - if (!gEnv->isSoftApOn) return; const android::hardware::hidl_array kCountryCode{ std::array{{0x55, 0x53}}}; EXPECT_EQ(WifiStatusCode::SUCCESS, @@ -91,7 +84,6 @@ TEST_F(WifiApIfaceHidlTest, SetCountryCode) { * Ensures that we can retrieve valid frequencies for 2.4 GHz band. */ TEST_F(WifiApIfaceHidlTest, GetValidFrequenciesForBand) { - if (!gEnv->isSoftApOn) return; const auto& status_and_freqs = HIDL_INVOKE( wifi_ap_iface_, getValidFrequenciesForBand, WifiBand::BAND_24GHZ); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_freqs.first.code); diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp new file mode 100644 index 0000000000..232ffdd58b --- /dev/null +++ b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp @@ -0,0 +1,168 @@ +/* + * 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. + */ + +#include + +#include + +#include + +#include "wifi_hidl_call_util.h" +#include "wifi_hidl_test_utils.h" + +using ::android::sp; +using ::android::hardware::wifi::V1_0::ChipModeId; +using ::android::hardware::wifi::V1_0::IfaceType; +using ::android::hardware::wifi::V1_0::IWifiApIface; +using ::android::hardware::wifi::V1_0::IWifiChip; +using ::android::hardware::wifi::V1_0::IWifiIface; +using ::android::hardware::wifi::V1_0::WifiStatus; +using ::android::hardware::wifi::V1_0::WifiStatusCode; + +/** + * Fixture for IWifiChip tests that are conditioned on SoftAP support. + */ +class WifiChipHidlApTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + wifi_chip_ = getWifiChip(); + ASSERT_NE(nullptr, wifi_chip_.get()); + } + + virtual void TearDown() override { stopWifi(); } + + protected: + // Helper function to configure the Chip in one of the supported modes. + // Most of the non-mode-configuration-related methods require chip + // to be first configured. + ChipModeId configureChipForIfaceType(IfaceType type, bool expectSuccess) { + ChipModeId mode_id; + EXPECT_EQ(expectSuccess, + configureChipToSupportIfaceType(wifi_chip_, type, &mode_id)); + return mode_id; + } + + std::string getIfaceName(const sp& iface) { + const auto& status_and_name = HIDL_INVOKE(iface, getName); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_name.first.code); + return status_and_name.second; + } + + WifiStatusCode createApIface(sp* ap_iface) { + const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createApIface); + *ap_iface = status_and_iface.second; + return status_and_iface.first.code; + } + + WifiStatusCode removeApIface(const std::string& name) { + return HIDL_INVOKE(wifi_chip_, removeApIface, name).code; + } + + sp wifi_chip_; +}; + +/* + * CreateApIface + * Configures the chip in AP mode and ensures that at least 1 iface creation + * succeeds. + */ +TEST_F(WifiChipHidlApTest, CreateApIface) { + configureChipForIfaceType(IfaceType::AP, true); + + sp iface; + EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface)); + EXPECT_NE(nullptr, iface.get()); +} + +/* + * GetApIfaceNames + * Configures the chip in AP mode and ensures that the iface list is empty + * before creating the iface. Then, create the iface and ensure that + * iface name is returned via the list. + */ +TEST_F(WifiChipHidlApTest, GetApIfaceNames) { + configureChipForIfaceType(IfaceType::AP, true); + + const auto& status_and_iface_names1 = + HIDL_INVOKE(wifi_chip_, getApIfaceNames); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names1.first.code); + EXPECT_EQ(0u, status_and_iface_names1.second.size()); + + sp iface; + EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface)); + EXPECT_NE(nullptr, iface.get()); + + std::string iface_name = getIfaceName(iface); + const auto& status_and_iface_names2 = + HIDL_INVOKE(wifi_chip_, getApIfaceNames); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names2.first.code); + EXPECT_EQ(1u, status_and_iface_names2.second.size()); + EXPECT_EQ(iface_name, status_and_iface_names2.second[0]); + + EXPECT_EQ(WifiStatusCode::SUCCESS, removeApIface(iface_name)); + const auto& status_and_iface_names3 = + HIDL_INVOKE(wifi_chip_, getApIfaceNames); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names3.first.code); + EXPECT_EQ(0u, status_and_iface_names3.second.size()); +} + +/* + * GetApIface + * Configures the chip in AP mode and create an iface. Then, retrieve + * the iface object using the correct name and ensure any other name + * doesn't retrieve an iface object. + */ +TEST_F(WifiChipHidlApTest, GetApIface) { + configureChipForIfaceType(IfaceType::AP, true); + + sp ap_iface; + EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&ap_iface)); + EXPECT_NE(nullptr, ap_iface.get()); + + std::string iface_name = getIfaceName(ap_iface); + const auto& status_and_iface1 = + HIDL_INVOKE(wifi_chip_, getApIface, iface_name); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface1.first.code); + EXPECT_NE(nullptr, status_and_iface1.second.get()); + + std::string invalid_name = iface_name + "0"; + const auto& status_and_iface2 = + HIDL_INVOKE(wifi_chip_, getApIface, invalid_name); + EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, status_and_iface2.first.code); + EXPECT_EQ(nullptr, status_and_iface2.second.get()); +} + +/* + * RemoveApIface + * Configures the chip in AP mode and create an iface. Then, remove + * the iface object using the correct name and ensure any other name + * doesn't remove the iface. + */ +TEST_F(WifiChipHidlApTest, RemoveApIface) { + configureChipForIfaceType(IfaceType::AP, true); + + sp ap_iface; + EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&ap_iface)); + EXPECT_NE(nullptr, ap_iface.get()); + + std::string iface_name = getIfaceName(ap_iface); + std::string invalid_name = iface_name + "0"; + EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(invalid_name)); + EXPECT_EQ(WifiStatusCode::SUCCESS, removeApIface(iface_name)); + + // No such iface exists now. So, this should return failure. + EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(iface_name)); +} diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp new file mode 100644 index 0000000000..595f23a109 --- /dev/null +++ b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp @@ -0,0 +1,169 @@ +/* + * 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. + */ + +#include + +#include + +#include + +#include "wifi_hidl_call_util.h" +#include "wifi_hidl_test_utils.h" + +using ::android::sp; +using ::android::hardware::wifi::V1_0::ChipModeId; +using ::android::hardware::wifi::V1_0::IfaceType; +using ::android::hardware::wifi::V1_0::IWifiChip; +using ::android::hardware::wifi::V1_0::IWifiIface; +using ::android::hardware::wifi::V1_0::IWifiNanIface; +using ::android::hardware::wifi::V1_0::WifiStatus; +using ::android::hardware::wifi::V1_0::WifiStatusCode; + +/** + * Fixture for IWifiChip tests that are conditioned on NAN support. + */ +class WifiChipHidlNanTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + wifi_chip_ = getWifiChip(); + ASSERT_NE(nullptr, wifi_chip_.get()); + } + + virtual void TearDown() override { stopWifi(); } + + protected: + // Helper function to configure the Chip in one of the supported modes. + // Most of the non-mode-configuration-related methods require chip + // to be first configured. + ChipModeId configureChipForIfaceType(IfaceType type, bool expectSuccess) { + ChipModeId mode_id; + EXPECT_EQ(expectSuccess, + configureChipToSupportIfaceType(wifi_chip_, type, &mode_id)); + return mode_id; + } + + std::string getIfaceName(const sp& iface) { + const auto& status_and_name = HIDL_INVOKE(iface, getName); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_name.first.code); + return status_and_name.second; + } + + WifiStatusCode createNanIface(sp* nan_iface) { + const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createNanIface); + *nan_iface = status_and_iface.second; + return status_and_iface.first.code; + } + + WifiStatusCode removeNanIface(const std::string& name) { + return HIDL_INVOKE(wifi_chip_, removeNanIface, name).code; + } + + sp wifi_chip_; +}; + +/* + * CreateNanIface + * Configures the chip in NAN mode and ensures that at least 1 iface creation + * succeeds. + */ +TEST_F(WifiChipHidlNanTest, CreateNanIface) { + configureChipForIfaceType(IfaceType::NAN, true); + + sp iface; + ASSERT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface)); + EXPECT_NE(nullptr, iface.get()); +} + +/* + * GetNanIfaceNames + * Configures the chip in NAN mode and ensures that the iface list is empty + * before creating the iface. Then, create the iface and ensure that + * iface name is returned via the list. + */ +TEST_F(WifiChipHidlNanTest, GetNanIfaceNames) { + configureChipForIfaceType(IfaceType::NAN, true); + + const auto& status_and_iface_names1 = + HIDL_INVOKE(wifi_chip_, getNanIfaceNames); + ASSERT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names1.first.code); + EXPECT_EQ(0u, status_and_iface_names1.second.size()); + + sp iface; + EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface)); + EXPECT_NE(nullptr, iface.get()); + + std::string iface_name = getIfaceName(iface); + const auto& status_and_iface_names2 = + HIDL_INVOKE(wifi_chip_, getNanIfaceNames); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names2.first.code); + EXPECT_EQ(1u, status_and_iface_names2.second.size()); + EXPECT_EQ(iface_name, status_and_iface_names2.second[0]); + + EXPECT_EQ(WifiStatusCode::SUCCESS, removeNanIface(iface_name)); + const auto& status_and_iface_names3 = + HIDL_INVOKE(wifi_chip_, getNanIfaceNames); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names3.first.code); + EXPECT_EQ(0u, status_and_iface_names3.second.size()); +} + +/* + * GetNanIface + * Configures the chip in NAN mode and create an iface. Then, retrieve + * the iface object using the correct name and ensure any other name + * doesn't retrieve an iface object. + */ +TEST_F(WifiChipHidlNanTest, GetNanIface) { + configureChipForIfaceType(IfaceType::NAN, true); + + sp nan_iface; + EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&nan_iface)); + EXPECT_NE(nullptr, nan_iface.get()); + + std::string iface_name = getIfaceName(nan_iface); + const auto& status_and_iface1 = + HIDL_INVOKE(wifi_chip_, getNanIface, iface_name); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface1.first.code); + EXPECT_NE(nullptr, status_and_iface1.second.get()); + + std::string invalid_name = iface_name + "0"; + const auto& status_and_iface2 = + HIDL_INVOKE(wifi_chip_, getNanIface, invalid_name); + EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, status_and_iface2.first.code); + EXPECT_EQ(nullptr, status_and_iface2.second.get()); +} + +/* + * RemoveNanIface + * Configures the chip in NAN mode and create an iface. Then, remove + * the iface object using the correct name and ensure any other name + * doesn't remove the iface. + */ +TEST_F(WifiChipHidlNanTest, RemoveNanIface) { + configureChipForIfaceType(IfaceType::NAN, true); + + sp nan_iface; + EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&nan_iface)); + EXPECT_NE(nullptr, nan_iface.get()); + + std::string iface_name = getIfaceName(nan_iface); + std::string invalid_name = iface_name + "0"; + EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(invalid_name)); + + EXPECT_EQ(WifiStatusCode::SUCCESS, removeNanIface(iface_name)); + + // No such iface exists now. So, this should return failure. + EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(iface_name)); +} diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp index 1b7e821906..2601b78743 100644 --- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp @@ -36,9 +36,7 @@ using ::android::hardware::wifi::V1_0::WifiDebugHostWakeReasonStats; using ::android::hardware::wifi::V1_0::WifiStatus; using ::android::hardware::wifi::V1_0::WifiStatusCode; using ::android::hardware::wifi::V1_0::IWifiChip; -using ::android::hardware::wifi::V1_0::IWifiApIface; using ::android::hardware::wifi::V1_0::IWifiIface; -using ::android::hardware::wifi::V1_0::IWifiNanIface; using ::android::hardware::wifi::V1_0::IWifiP2pIface; using ::android::hardware::wifi::V1_0::IWifiRttController; using ::android::hardware::wifi::V1_0::IWifiStaIface; @@ -64,7 +62,10 @@ bool hasAnyRingBufferCapabilities(uint32_t caps) { } // namespace /** - * Fixture to use for all Wifi chip HIDL interface tests. + * Fixture for IWifiChip tests. + * + * Tests that require SoftAP or NAN support should go into WifiChipHidlApTest or + * WifiChipHidlNanTest respectively. */ class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { public: @@ -114,26 +115,6 @@ class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { return status_and_name.second; } - WifiStatusCode createApIface(sp* ap_iface) { - const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createApIface); - *ap_iface = status_and_iface.second; - return status_and_iface.first.code; - } - - WifiStatusCode removeApIface(const std::string& name) { - return HIDL_INVOKE(wifi_chip_, removeApIface, name).code; - } - - WifiStatusCode createNanIface(sp* nan_iface) { - const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createNanIface); - *nan_iface = status_and_iface.second; - return status_and_iface.first.code; - } - - WifiStatusCode removeNanIface(const std::string& name) { - return HIDL_INVOKE(wifi_chip_, removeNanIface, name).code; - } - WifiStatusCode createP2pIface(sp* p2p_iface) { const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createP2pIface); *p2p_iface = status_and_iface.second; @@ -359,201 +340,6 @@ TEST_F(WifiChipHidlTest, GetDebugHostWakeReasonStats) { } } -/* - * CreateApIface - * Configures the chip in AP mode and ensures that at least 1 iface creation - * succeeds. - */ -TEST_F(WifiChipHidlTest, CreateApIface) { - if (!gEnv->isSoftApOn) return; - configureChipForIfaceType(IfaceType::AP, true); - - sp iface; - EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface)); - EXPECT_NE(nullptr, iface.get()); -} - -/* - * GetApIfaceNames - * Configures the chip in AP mode and ensures that the iface list is empty - * before creating the iface. Then, create the iface and ensure that - * iface name is returned via the list. - */ -TEST_F(WifiChipHidlTest, GetApIfaceNames) { - if (!gEnv->isSoftApOn) return; - configureChipForIfaceType(IfaceType::AP, true); - - const auto& status_and_iface_names1 = - HIDL_INVOKE(wifi_chip_, getApIfaceNames); - EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names1.first.code); - EXPECT_EQ(0u, status_and_iface_names1.second.size()); - - sp iface; - EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface)); - EXPECT_NE(nullptr, iface.get()); - - std::string iface_name = getIfaceName(iface); - const auto& status_and_iface_names2 = - HIDL_INVOKE(wifi_chip_, getApIfaceNames); - EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names2.first.code); - EXPECT_EQ(1u, status_and_iface_names2.second.size()); - EXPECT_EQ(iface_name, status_and_iface_names2.second[0]); - - EXPECT_EQ(WifiStatusCode::SUCCESS, removeApIface(iface_name)); - const auto& status_and_iface_names3 = - HIDL_INVOKE(wifi_chip_, getApIfaceNames); - EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names3.first.code); - EXPECT_EQ(0u, status_and_iface_names3.second.size()); -} - -/* - * GetApIface - * Configures the chip in AP mode and create an iface. Then, retrieve - * the iface object using the correct name and ensure any other name - * doesn't retrieve an iface object. - */ -TEST_F(WifiChipHidlTest, GetApIface) { - if (!gEnv->isSoftApOn) return; - configureChipForIfaceType(IfaceType::AP, true); - - sp ap_iface; - EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&ap_iface)); - EXPECT_NE(nullptr, ap_iface.get()); - - std::string iface_name = getIfaceName(ap_iface); - const auto& status_and_iface1 = - HIDL_INVOKE(wifi_chip_, getApIface, iface_name); - EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface1.first.code); - EXPECT_NE(nullptr, status_and_iface1.second.get()); - - std::string invalid_name = iface_name + "0"; - const auto& status_and_iface2 = - HIDL_INVOKE(wifi_chip_, getApIface, invalid_name); - EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, status_and_iface2.first.code); - EXPECT_EQ(nullptr, status_and_iface2.second.get()); -} - -/* - * RemoveApIface - * Configures the chip in AP mode and create an iface. Then, remove - * the iface object using the correct name and ensure any other name - * doesn't remove the iface. - */ -TEST_F(WifiChipHidlTest, RemoveApIface) { - if (!gEnv->isSoftApOn) return; - configureChipForIfaceType(IfaceType::AP, true); - - sp ap_iface; - EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&ap_iface)); - EXPECT_NE(nullptr, ap_iface.get()); - - std::string iface_name = getIfaceName(ap_iface); - std::string invalid_name = iface_name + "0"; - EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(invalid_name)); - EXPECT_EQ(WifiStatusCode::SUCCESS, removeApIface(iface_name)); - - // No such iface exists now. So, this should return failure. - EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(iface_name)); -} - -/* - * CreateNanIface - * Configures the chip in NAN mode and ensures that at least 1 iface creation - * succeeds. - */ -TEST_F(WifiChipHidlTest, CreateNanIface) { - if (!gEnv->isNanOn) return; - configureChipForIfaceType(IfaceType::NAN, gEnv->isNanOn); - - sp iface; - ASSERT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface)); - EXPECT_NE(nullptr, iface.get()); -} - -/* - * GetNanIfaceNames - * Configures the chip in NAN mode and ensures that the iface list is empty - * before creating the iface. Then, create the iface and ensure that - * iface name is returned via the list. - */ -TEST_F(WifiChipHidlTest, GetNanIfaceNames) { - if (!gEnv->isNanOn) return; - configureChipForIfaceType(IfaceType::NAN, gEnv->isNanOn); - - const auto& status_and_iface_names1 = - HIDL_INVOKE(wifi_chip_, getNanIfaceNames); - ASSERT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names1.first.code); - EXPECT_EQ(0u, status_and_iface_names1.second.size()); - - sp iface; - EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface)); - EXPECT_NE(nullptr, iface.get()); - - std::string iface_name = getIfaceName(iface); - const auto& status_and_iface_names2 = - HIDL_INVOKE(wifi_chip_, getNanIfaceNames); - EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names2.first.code); - EXPECT_EQ(1u, status_and_iface_names2.second.size()); - EXPECT_EQ(iface_name, status_and_iface_names2.second[0]); - - EXPECT_EQ(WifiStatusCode::SUCCESS, removeNanIface(iface_name)); - const auto& status_and_iface_names3 = - HIDL_INVOKE(wifi_chip_, getNanIfaceNames); - EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names3.first.code); - EXPECT_EQ(0u, status_and_iface_names3.second.size()); -} - -/* - * GetNanIface - * Configures the chip in NAN mode and create an iface. Then, retrieve - * the iface object using the correct name and ensure any other name - * doesn't retrieve an iface object. - */ -TEST_F(WifiChipHidlTest, GetNanIface) { - if (!gEnv->isNanOn) return; - configureChipForIfaceType(IfaceType::NAN, gEnv->isNanOn); - - sp nan_iface; - EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&nan_iface)); - EXPECT_NE(nullptr, nan_iface.get()); - - std::string iface_name = getIfaceName(nan_iface); - const auto& status_and_iface1 = - HIDL_INVOKE(wifi_chip_, getNanIface, iface_name); - EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface1.first.code); - EXPECT_NE(nullptr, status_and_iface1.second.get()); - - std::string invalid_name = iface_name + "0"; - const auto& status_and_iface2 = - HIDL_INVOKE(wifi_chip_, getNanIface, invalid_name); - EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, status_and_iface2.first.code); - EXPECT_EQ(nullptr, status_and_iface2.second.get()); -} - -/* - * RemoveNanIface - * Configures the chip in NAN mode and create an iface. Then, remove - * the iface object using the correct name and ensure any other name - * doesn't remove the iface. - */ -TEST_F(WifiChipHidlTest, RemoveNanIface) { - if (!gEnv->isNanOn) return; - configureChipForIfaceType(IfaceType::NAN, gEnv->isNanOn); - - sp nan_iface; - EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&nan_iface)); - EXPECT_NE(nullptr, nan_iface.get()); - - std::string iface_name = getIfaceName(nan_iface); - std::string invalid_name = iface_name + "0"; - EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(invalid_name)); - - EXPECT_EQ(WifiStatusCode::SUCCESS, removeNanIface(iface_name)); - - // No such iface exists now. So, this should return failure. - EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(iface_name)); -} - /* * CreateP2pIface * Configures the chip in P2P mode and ensures that at least 1 iface creation diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h index d430ce0bea..7dacaf15a6 100644 --- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h +++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h @@ -54,48 +54,4 @@ class WifiHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { stopWifi(); sleep(5); } - - public: - // Whether NaN feature is supported on the device. - bool isNanOn = false; - // Whether SoftAp feature is supported on the device. - bool isSoftApOn = false; - - void usage(char* me, char* arg) { - fprintf(stderr, - "unrecognized option: %s\n\n" - "usage: %s \n\n" - "test options are:\n\n" - "-N, --nan_on: Whether NAN feature is supported\n" - "-S, --softap_on: Whether SOFTAP feature is supported\n", - arg, me); - } - - int initFromOptions(int argc, char** argv) { - static struct option options[] = {{"nan_on", no_argument, 0, 'N'}, - {"softap_on", no_argument, 0, 'S'}, - {0, 0, 0, 0}}; - - int c; - while ((c = getopt_long(argc, argv, "NS", options, NULL)) >= 0) { - switch (c) { - case 'N': - isNanOn = true; - break; - case 'S': - isSoftApOn = true; - break; - default: - usage(argv[0], argv[optind]); - return 2; - } - } - - if (optind < argc) { - usage(argv[0], argv[optind]); - return 2; - } - - return 0; - } }; diff --git a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp index a0f97f81e8..673fed3675 100644 --- a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp +++ b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp @@ -41,10 +41,7 @@ int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(gEnv); ::testing::InitGoogleTest(&argc, argv); gEnv->init(&argc, argv); - int status = gEnv->initFromOptions(argc, argv); - if (status == 0) { - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - } + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; return status; } diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp index 859be89ee5..42c60f2f0e 100644 --- a/wifi/1.4/vts/functional/Android.bp +++ b/wifi/1.4/vts/functional/Android.bp @@ -14,8 +14,9 @@ // limitations under the License. // +// SoftAP-specific tests, similar to VtsHalWifiApV1_0TargetTest. cc_test { - name: "VtsHalWifiV1_4TargetTest", + name: "VtsHalWifiApV1_4TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ "VtsHalWifiV1_4TargetTest.cpp", diff --git a/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp b/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp index 26b93a6f08..deac0fa0cf 100644 --- a/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp +++ b/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp @@ -44,10 +44,7 @@ int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(gEnv); ::testing::InitGoogleTest(&argc, argv); gEnv->init(&argc, argv); - int status = gEnv->initFromOptions(argc, argv); - if (status == 0) { - status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - } + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; return status; } diff --git a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp index c2c13941ea..68e9bbbde2 100644 --- a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp +++ b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp @@ -35,13 +35,11 @@ extern WifiHidlEnvironment* gEnv; class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { public: virtual void SetUp() override { - if (!gEnv->isSoftApOn) return; wifi_ap_iface_ = IWifiApIface::castFrom(getWifiApIface()); ASSERT_NE(nullptr, wifi_ap_iface_.get()); } virtual void TearDown() override { - if (!gEnv->isSoftApOn) return; stopWifi(); } @@ -55,7 +53,6 @@ class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { * code. */ TEST_F(WifiApIfaceHidlTest, SetMacAddress) { - if (!gEnv->isSoftApOn) return; const hidl_array kMac{{0x12, 0x22, 0x33, 0x52, 0x10, 0x41}}; EXPECT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(wifi_ap_iface_, setMacAddress, kMac).code); @@ -67,7 +64,6 @@ TEST_F(WifiApIfaceHidlTest, SetMacAddress) { * and return a success status code. */ TEST_F(WifiApIfaceHidlTest, GetFactoryMacAddress) { - if (!gEnv->isSoftApOn) return; std::pair > status_and_mac = HIDL_INVOKE(wifi_ap_iface_, getFactoryMacAddress); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mac.first.code); From bcc123b2dff3e33d85b7cdcf011dd366ba7c8855 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 10 Oct 2019 22:58:19 +0000 Subject: [PATCH 0166/1022] Revert "Merge "Revert "Increase neuralnetworks compatibility to 1.3"" am: c805505344 am: 5b33b3e129 am: 9c0273b979" This reverts commit af3e3516aa0643447701a56ce5e96432fbff5f8b. Reason for revert: revert of a cherry-pick broke master Change-Id: I66247588f8e42ebd85cc95b844f2d352adc81462 --- compatibility_matrices/compatibility_matrix.current.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index a69c9e56b4..a40965098c 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -307,7 +307,7 @@ android.hardware.neuralnetworks - 1.0-2 + 1.0-3 IDevice .* From b098d21e0cdaca087ad5bff73bcf90351dad055c Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 10 Oct 2019 22:58:36 +0000 Subject: [PATCH 0167/1022] Revert "Revert "Copy VTS tests from v1.2 to v1.3" am: 9613b4649b am: 432f6d1609 am: fe2cd91115" This reverts commit 1ea542bd1a93994ebca9896258b6819e94ecee70. Reason for revert: revert of a cherry-pick broke master Change-Id: I09797f5f3898501a008186a22dd411b00e9e2c67 --- neuralnetworks/1.3/vts/OWNERS | 16 + .../1.3/vts/functional/BasicTests.cpp | 114 ++ .../1.3/vts/functional/Callbacks.cpp | 143 ++ .../functional/CompilationCachingTests.cpp | 1374 +++++++++++++++++ .../vts/functional/GeneratedTestHarness.cpp | 408 +++++ .../1.3/vts/functional/GeneratedTestHarness.h | 65 + .../1.3/vts/functional/TestAssertions.cpp | 141 ++ .../1.3/vts/functional/ValidateBurst.cpp | 400 +++++ .../1.3/vts/functional/ValidateModel.cpp | 713 +++++++++ .../1.3/vts/functional/ValidateRequest.cpp | 168 ++ .../vts/functional/VtsHalNeuralnetworks.cpp | 171 ++ .../1.3/vts/functional/VtsHalNeuralnetworks.h | 57 + .../vts/functional/include/1.2/Callbacks.h | 325 ++++ 13 files changed, 4095 insertions(+) create mode 100644 neuralnetworks/1.3/vts/OWNERS create mode 100644 neuralnetworks/1.3/vts/functional/BasicTests.cpp create mode 100644 neuralnetworks/1.3/vts/functional/Callbacks.cpp create mode 100644 neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp create mode 100644 neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp create mode 100644 neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h create mode 100644 neuralnetworks/1.3/vts/functional/TestAssertions.cpp create mode 100644 neuralnetworks/1.3/vts/functional/ValidateBurst.cpp create mode 100644 neuralnetworks/1.3/vts/functional/ValidateModel.cpp create mode 100644 neuralnetworks/1.3/vts/functional/ValidateRequest.cpp create mode 100644 neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp create mode 100644 neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h create mode 100644 neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h diff --git a/neuralnetworks/1.3/vts/OWNERS b/neuralnetworks/1.3/vts/OWNERS new file mode 100644 index 0000000000..b5a8e1f473 --- /dev/null +++ b/neuralnetworks/1.3/vts/OWNERS @@ -0,0 +1,16 @@ +# Neuralnetworks team +butlermichael@google.com +dgross@google.com +jeanluc@google.com +levp@google.com +miaowang@google.com +mikie@google.com +mks@google.com +pszczepaniak@google.com +slavash@google.com +vddang@google.com +xusongw@google.com + +# VTS team +yim@google.com +yuexima@google.com diff --git a/neuralnetworks/1.3/vts/functional/BasicTests.cpp b/neuralnetworks/1.3/vts/functional/BasicTests.cpp new file mode 100644 index 0000000000..8e82c5376e --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/BasicTests.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test" + +#include "VtsHalNeuralnetworks.h" + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using V1_0::DeviceStatus; +using V1_0::ErrorStatus; +using V1_0::PerformanceInfo; + +// create device test +TEST_P(NeuralnetworksHidlTest, CreateDevice) {} + +// status test +TEST_P(NeuralnetworksHidlTest, StatusTest) { + Return status = kDevice->getStatus(); + ASSERT_TRUE(status.isOk()); + EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast(status)); +} + +// initialization +TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) { + using OperandPerformance = Capabilities::OperandPerformance; + Return ret = kDevice->getCapabilities_1_2([](ErrorStatus status, + const Capabilities& capabilities) { + EXPECT_EQ(ErrorStatus::NONE, status); + + auto isPositive = [](const PerformanceInfo& perf) { + return perf.execTime > 0.0f && perf.powerUsage > 0.0f; + }; + + EXPECT_TRUE(isPositive(capabilities.relaxedFloat32toFloat16PerformanceScalar)); + EXPECT_TRUE(isPositive(capabilities.relaxedFloat32toFloat16PerformanceTensor)); + const auto& opPerf = capabilities.operandPerformance; + EXPECT_TRUE(std::all_of( + opPerf.begin(), opPerf.end(), + [isPositive](const OperandPerformance& a) { return isPositive(a.info); })); + EXPECT_TRUE(std::is_sorted(opPerf.begin(), opPerf.end(), + [](const OperandPerformance& a, const OperandPerformance& b) { + return a.type < b.type; + })); + }); + EXPECT_TRUE(ret.isOk()); +} + +// device version test +TEST_P(NeuralnetworksHidlTest, GetDeviceVersionStringTest) { + Return ret = + kDevice->getVersionString([](ErrorStatus status, const hidl_string& version) { + EXPECT_EQ(ErrorStatus::NONE, status); + EXPECT_LT(0, version.size()); + }); + EXPECT_TRUE(ret.isOk()); +} + +// device type test +TEST_P(NeuralnetworksHidlTest, GetDeviceTypeTest) { + Return ret = kDevice->getType([](ErrorStatus status, DeviceType type) { + EXPECT_EQ(ErrorStatus::NONE, status); + EXPECT_TRUE(type == DeviceType::OTHER || type == DeviceType::CPU || + type == DeviceType::GPU || type == DeviceType::ACCELERATOR); + }); + EXPECT_TRUE(ret.isOk()); +} + +// device supported extensions test +TEST_P(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) { + Return ret = kDevice->getSupportedExtensions( + [](ErrorStatus status, const hidl_vec& extensions) { + EXPECT_EQ(ErrorStatus::NONE, status); + for (auto& extension : extensions) { + std::string extensionName = extension.name; + EXPECT_FALSE(extensionName.empty()); + for (char c : extensionName) { + EXPECT_TRUE(('a' <= c && c <= 'z') || ('0' <= c && c <= '9') || c == '_' || + c == '.') + << "Extension name contains an illegal character: " << c; + } + EXPECT_NE(extensionName.find('.'), std::string::npos) + << "Extension name must start with the reverse domain name of the " + "vendor"; + } + }); + EXPECT_TRUE(ret.isOk()); +} + +// getNumberOfCacheFilesNeeded test +TEST_P(NeuralnetworksHidlTest, getNumberOfCacheFilesNeeded) { + Return ret = kDevice->getNumberOfCacheFilesNeeded( + [](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) { + EXPECT_EQ(ErrorStatus::NONE, status); + EXPECT_LE(numModelCache, + static_cast(Constant::MAX_NUMBER_OF_CACHE_FILES)); + EXPECT_LE(numDataCache, static_cast(Constant::MAX_NUMBER_OF_CACHE_FILES)); + }); + EXPECT_TRUE(ret.isOk()); +} +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/Callbacks.cpp b/neuralnetworks/1.3/vts/functional/Callbacks.cpp new file mode 100644 index 0000000000..3972ad6ff2 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/Callbacks.cpp @@ -0,0 +1,143 @@ +/* + * 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 "Callbacks" + +#include "1.2/Callbacks.h" + +#include + +#include + +namespace android::hardware::neuralnetworks::V1_2::implementation { + +using V1_0::ErrorStatus; + +constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits::max(), + .timeInDriver = std::numeric_limits::max()}; + +// PreparedModelCallback methods begin here + +Return PreparedModelCallback::notify(ErrorStatus errorStatus, + const sp& preparedModel) { + { + std::lock_guard hold(mMutex); + + // quick-return if object has already been notified + if (mNotified) { + return Void(); + } + + // store results and mark as notified + mErrorStatus = errorStatus; + mPreparedModel = preparedModel; + mNotified = true; + } + + mCondition.notify_all(); + return Void(); +} + +Return PreparedModelCallback::notify_1_2(ErrorStatus errorStatus, + const sp& preparedModel) { + return notify(errorStatus, preparedModel); +} + +void PreparedModelCallback::wait() const { + std::unique_lock lock(mMutex); + mCondition.wait(lock, [this] { return mNotified; }); +} + +ErrorStatus PreparedModelCallback::getStatus() const { + wait(); + return mErrorStatus; +} + +sp PreparedModelCallback::getPreparedModel() const { + wait(); + return mPreparedModel; +} + +// ExecutionCallback methods begin here + +Return ExecutionCallback::notify(ErrorStatus errorStatus) { + notifyInternal(errorStatus, {}, kNoTiming); + return Void(); +} + +Return ExecutionCallback::notify_1_2(ErrorStatus errorStatus, + const hidl_vec& outputShapes, + const Timing& timing) { + if (errorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { + // outputShapes must not be empty if OUTPUT_INSUFFICIENT_SIZE. + if (outputShapes.size() == 0) { + LOG(ERROR) << "Notified with empty output shape vector when OUTPUT_INSUFFICIENT_SIZE"; + notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + return Void(); + } + } else if (errorStatus != ErrorStatus::NONE) { + // outputShapes must be empty if errorStatus is neither NONE nor OUTPUT_INSUFFICIENT_SIZE. + if (outputShapes.size() != 0) { + LOG(ERROR) << "Notified with non-empty output shape vector when error status is " + "neither NONE nor OUTPUT_INSUFFICIENT_SIZE"; + notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + return Void(); + } + } + notifyInternal(errorStatus, outputShapes, timing); + return Void(); +} + +void ExecutionCallback::wait() const { + std::unique_lock lock(mMutex); + mCondition.wait(lock, [this] { return mNotified; }); +} + +ErrorStatus ExecutionCallback::getStatus() const { + wait(); + return mErrorStatus; +} + +const std::vector& ExecutionCallback::getOutputShapes() const { + wait(); + return mOutputShapes; +} + +Timing ExecutionCallback::getTiming() const { + wait(); + return mTiming; +} + +void ExecutionCallback::notifyInternal(ErrorStatus errorStatus, + const hidl_vec& outputShapes, + const Timing& timing) { + { + std::lock_guard hold(mMutex); + + // quick-return if object has already been notified + if (mNotified) { + return; + } + + mErrorStatus = errorStatus; + mOutputShapes = outputShapes; + mTiming = timing; + mNotified = true; + } + mCondition.notify_all(); +} + +} // namespace android::hardware::neuralnetworks::V1_2::implementation diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp new file mode 100644 index 0000000000..2130a76b75 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp @@ -0,0 +1,1374 @@ +/* + * 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 "neuralnetworks_hidl_hal_test" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "1.2/Callbacks.h" +#include "GeneratedTestHarness.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "Utils.h" +#include "VtsHalNeuralnetworks.h" + +// Forward declaration of the mobilenet generated test models in +// frameworks/ml/nn/runtime/test/generated/. +namespace generated_tests::mobilenet_224_gender_basic_fixed { +const test_helper::TestModel& get_test_model(); +} // namespace generated_tests::mobilenet_224_gender_basic_fixed + +namespace generated_tests::mobilenet_quantized { +const test_helper::TestModel& get_test_model(); +} // namespace generated_tests::mobilenet_quantized + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using namespace test_helper; +using implementation::PreparedModelCallback; +using V1_0::ErrorStatus; +using V1_1::ExecutionPreference; + +namespace float32_model { + +constexpr auto get_test_model = generated_tests::mobilenet_224_gender_basic_fixed::get_test_model; + +} // namespace float32_model + +namespace quant8_model { + +constexpr auto get_test_model = generated_tests::mobilenet_quantized::get_test_model; + +} // namespace quant8_model + +namespace { + +enum class AccessMode { READ_WRITE, READ_ONLY, WRITE_ONLY }; + +// Creates cache handles based on provided file groups. +// The outer vector corresponds to handles and the inner vector is for fds held by each handle. +void createCacheHandles(const std::vector>& fileGroups, + const std::vector& mode, hidl_vec* handles) { + handles->resize(fileGroups.size()); + for (uint32_t i = 0; i < fileGroups.size(); i++) { + std::vector fds; + for (const auto& file : fileGroups[i]) { + int fd; + if (mode[i] == AccessMode::READ_ONLY) { + fd = open(file.c_str(), O_RDONLY); + } else if (mode[i] == AccessMode::WRITE_ONLY) { + fd = open(file.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + } else if (mode[i] == AccessMode::READ_WRITE) { + fd = open(file.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + } else { + FAIL(); + } + ASSERT_GE(fd, 0); + fds.push_back(fd); + } + native_handle_t* cacheNativeHandle = native_handle_create(fds.size(), 0); + ASSERT_NE(cacheNativeHandle, nullptr); + std::copy(fds.begin(), fds.end(), &cacheNativeHandle->data[0]); + (*handles)[i].setTo(cacheNativeHandle, /*shouldOwn=*/true); + } +} + +void createCacheHandles(const std::vector>& fileGroups, AccessMode mode, + hidl_vec* handles) { + createCacheHandles(fileGroups, std::vector(fileGroups.size(), mode), handles); +} + +// Create a chain of broadcast operations. The second operand is always constant tensor [1]. +// For simplicity, activation scalar is shared. The second operand is not shared +// in the model to let driver maintain a non-trivial size of constant data and the corresponding +// data locations in cache. +// +// --------- activation -------- +// ↓ ↓ ↓ ↓ +// E.g. input -> ADD -> ADD -> ADD -> ... -> ADD -> output +// ↑ ↑ ↑ ↑ +// [1] [1] [1] [1] +// +// This function assumes the operation is either ADD or MUL. +template +TestModel createLargeTestModelImpl(TestOperationType op, uint32_t len) { + EXPECT_TRUE(op == TestOperationType::ADD || op == TestOperationType::MUL); + + // Model operations and operands. + std::vector operations(len); + std::vector operands(len * 2 + 2); + + // The activation scalar, value = 0. + operands[0] = { + .type = TestOperandType::INT32, + .dimensions = {}, + .numberOfConsumers = len, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = TestOperandLifeTime::CONSTANT_COPY, + .data = TestBuffer::createFromVector({0}), + }; + + // The buffer value of the constant second operand. The logical value is always 1.0f. + CppType bufferValue; + // The scale of the first and second operand. + float scale1, scale2; + if (operandType == TestOperandType::TENSOR_FLOAT32) { + bufferValue = 1.0f; + scale1 = 0.0f; + scale2 = 0.0f; + } else if (op == TestOperationType::ADD) { + bufferValue = 1; + scale1 = 1.0f; + scale2 = 1.0f; + } else { + // To satisfy the constraint on quant8 MUL: input0.scale * input1.scale < output.scale, + // set input1 to have scale = 0.5f and bufferValue = 2, i.e. 1.0f in floating point. + bufferValue = 2; + scale1 = 1.0f; + scale2 = 0.5f; + } + + for (uint32_t i = 0; i < len; i++) { + const uint32_t firstInputIndex = i * 2 + 1; + const uint32_t secondInputIndex = firstInputIndex + 1; + const uint32_t outputIndex = secondInputIndex + 1; + + // The first operation input. + operands[firstInputIndex] = { + .type = operandType, + .dimensions = {1}, + .numberOfConsumers = 1, + .scale = scale1, + .zeroPoint = 0, + .lifetime = (i == 0 ? TestOperandLifeTime::MODEL_INPUT + : TestOperandLifeTime::TEMPORARY_VARIABLE), + .data = (i == 0 ? TestBuffer::createFromVector({1}) : TestBuffer()), + }; + + // The second operation input, value = 1. + operands[secondInputIndex] = { + .type = operandType, + .dimensions = {1}, + .numberOfConsumers = 1, + .scale = scale2, + .zeroPoint = 0, + .lifetime = TestOperandLifeTime::CONSTANT_COPY, + .data = TestBuffer::createFromVector({bufferValue}), + }; + + // The operation. All operations share the same activation scalar. + // The output operand is created as an input in the next iteration of the loop, in the case + // of all but the last member of the chain; and after the loop as a model output, in the + // case of the last member of the chain. + operations[i] = { + .type = op, + .inputs = {firstInputIndex, secondInputIndex, /*activation scalar*/ 0}, + .outputs = {outputIndex}, + }; + } + + // For TestOperationType::ADD, output = 1 + 1 * len = len + 1 + // For TestOperationType::MUL, output = 1 * 1 ^ len = 1 + CppType outputResult = static_cast(op == TestOperationType::ADD ? len + 1u : 1u); + + // The model output. + operands.back() = { + .type = operandType, + .dimensions = {1}, + .numberOfConsumers = 0, + .scale = scale1, + .zeroPoint = 0, + .lifetime = TestOperandLifeTime::MODEL_OUTPUT, + .data = TestBuffer::createFromVector({outputResult}), + }; + + return { + .operands = std::move(operands), + .operations = std::move(operations), + .inputIndexes = {1}, + .outputIndexes = {len * 2 + 1}, + .isRelaxed = false, + }; +} + +} // namespace + +// Tag for the compilation caching tests. +class CompilationCachingTestBase : public testing::Test { + protected: + CompilationCachingTestBase(sp device, OperandType type) + : kDevice(std::move(device)), kOperandType(type) {} + + void SetUp() override { + testing::Test::SetUp(); + ASSERT_NE(kDevice.get(), nullptr); + + // Create cache directory. The cache directory and a temporary cache file is always created + // to test the behavior of prepareModelFromCache, even when caching is not supported. + char cacheDirTemp[] = "/data/local/tmp/TestCompilationCachingXXXXXX"; + char* cacheDir = mkdtemp(cacheDirTemp); + ASSERT_NE(cacheDir, nullptr); + mCacheDir = cacheDir; + mCacheDir.push_back('/'); + + Return ret = kDevice->getNumberOfCacheFilesNeeded( + [this](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) { + EXPECT_EQ(ErrorStatus::NONE, status); + mNumModelCache = numModelCache; + mNumDataCache = numDataCache; + }); + EXPECT_TRUE(ret.isOk()); + mIsCachingSupported = mNumModelCache > 0 || mNumDataCache > 0; + + // Create empty cache files. + mTmpCache = mCacheDir + "tmp"; + for (uint32_t i = 0; i < mNumModelCache; i++) { + mModelCache.push_back({mCacheDir + "model" + std::to_string(i)}); + } + for (uint32_t i = 0; i < mNumDataCache; i++) { + mDataCache.push_back({mCacheDir + "data" + std::to_string(i)}); + } + // Dummy handles, use AccessMode::WRITE_ONLY for createCacheHandles to create files. + hidl_vec modelHandle, dataHandle, tmpHandle; + createCacheHandles(mModelCache, AccessMode::WRITE_ONLY, &modelHandle); + createCacheHandles(mDataCache, AccessMode::WRITE_ONLY, &dataHandle); + createCacheHandles({{mTmpCache}}, AccessMode::WRITE_ONLY, &tmpHandle); + + if (!mIsCachingSupported) { + LOG(INFO) << "NN VTS: Early termination of test because vendor service does not " + "support compilation caching."; + std::cout << "[ ] Early termination of test because vendor service does not " + "support compilation caching." + << std::endl; + } + } + + void TearDown() override { + // If the test passes, remove the tmp directory. Otherwise, keep it for debugging purposes. + if (!testing::Test::HasFailure()) { + // Recursively remove the cache directory specified by mCacheDir. + auto callback = [](const char* entry, const struct stat*, int, struct FTW*) { + return remove(entry); + }; + nftw(mCacheDir.c_str(), callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS); + } + testing::Test::TearDown(); + } + + // Model and examples creators. According to kOperandType, the following methods will return + // either float32 model/examples or the quant8 variant. + TestModel createTestModel() { + if (kOperandType == OperandType::TENSOR_FLOAT32) { + return float32_model::get_test_model(); + } else { + return quant8_model::get_test_model(); + } + } + + TestModel createLargeTestModel(OperationType op, uint32_t len) { + if (kOperandType == OperandType::TENSOR_FLOAT32) { + return createLargeTestModelImpl( + static_cast(op), len); + } else { + return createLargeTestModelImpl( + static_cast(op), len); + } + } + + // See if the service can handle the model. + bool isModelFullySupported(const Model& model) { + bool fullySupportsModel = false; + Return supportedCall = kDevice->getSupportedOperations_1_2( + model, + [&fullySupportsModel, &model](ErrorStatus status, const hidl_vec& supported) { + ASSERT_EQ(ErrorStatus::NONE, status); + ASSERT_EQ(supported.size(), model.operations.size()); + fullySupportsModel = std::all_of(supported.begin(), supported.end(), + [](bool valid) { return valid; }); + }); + EXPECT_TRUE(supportedCall.isOk()); + return fullySupportsModel; + } + + void saveModelToCache(const Model& model, const hidl_vec& modelCache, + const hidl_vec& dataCache, + sp* preparedModel = nullptr) { + if (preparedModel != nullptr) *preparedModel = nullptr; + + // Launch prepare model. + sp preparedModelCallback = new PreparedModelCallback(); + hidl_array cacheToken(mToken); + Return prepareLaunchStatus = + kDevice->prepareModel_1_2(model, ExecutionPreference::FAST_SINGLE_ANSWER, + modelCache, dataCache, cacheToken, preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + ASSERT_EQ(static_cast(prepareLaunchStatus), ErrorStatus::NONE); + + // Retrieve prepared model. + preparedModelCallback->wait(); + ASSERT_EQ(preparedModelCallback->getStatus(), ErrorStatus::NONE); + if (preparedModel != nullptr) { + *preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel()) + .withDefault(nullptr); + } + } + + bool checkEarlyTermination(ErrorStatus status) { + if (status == ErrorStatus::GENERAL_FAILURE) { + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " + "save the prepared model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "save the prepared model that it does not support." + << std::endl; + return true; + } + return false; + } + + bool checkEarlyTermination(const Model& model) { + if (!isModelFullySupported(model)) { + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " + "prepare model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "prepare model that it does not support." + << std::endl; + return true; + } + return false; + } + + void prepareModelFromCache(const hidl_vec& modelCache, + const hidl_vec& dataCache, + sp* preparedModel, ErrorStatus* status) { + // Launch prepare model from cache. + sp preparedModelCallback = new PreparedModelCallback(); + hidl_array cacheToken(mToken); + Return prepareLaunchStatus = kDevice->prepareModelFromCache( + modelCache, dataCache, cacheToken, preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + if (static_cast(prepareLaunchStatus) != ErrorStatus::NONE) { + *preparedModel = nullptr; + *status = static_cast(prepareLaunchStatus); + return; + } + + // Retrieve prepared model. + preparedModelCallback->wait(); + *status = preparedModelCallback->getStatus(); + *preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel()) + .withDefault(nullptr); + } + + // Absolute path to the temporary cache directory. + std::string mCacheDir; + + // Groups of file paths for model and data cache in the tmp cache directory, initialized with + // outer_size = mNum{Model|Data}Cache, inner_size = 1. The outer vector corresponds to handles + // and the inner vector is for fds held by each handle. + std::vector> mModelCache; + std::vector> mDataCache; + + // A separate temporary file path in the tmp cache directory. + std::string mTmpCache; + + uint8_t mToken[static_cast(Constant::BYTE_SIZE_OF_CACHE_TOKEN)] = {}; + uint32_t mNumModelCache; + uint32_t mNumDataCache; + uint32_t mIsCachingSupported; + + const sp kDevice; + // The primary data type of the testModel. + const OperandType kOperandType; +}; + +using CompilationCachingTestParam = std::tuple; + +// A parameterized fixture of CompilationCachingTestBase. Every test will run twice, with the first +// pass running with float32 models and the second pass running with quant8 models. +class CompilationCachingTest : public CompilationCachingTestBase, + public testing::WithParamInterface { + protected: + CompilationCachingTest() + : CompilationCachingTestBase(getData(std::get(GetParam())), + std::get(GetParam())) {} +}; + +TEST_P(CompilationCachingTest, CacheSavingAndRetrieval) { + // Create test HIDL model and compile. + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + sp preparedModel = nullptr; + + // Save the compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(model, modelCache, dataCache); + } + + // Retrieve preparedModel from cache. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (!mIsCachingSupported) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + return; + } else if (checkEarlyTermination(status)) { + ASSERT_EQ(preparedModel, nullptr); + return; + } else { + ASSERT_EQ(status, ErrorStatus::NONE); + ASSERT_NE(preparedModel, nullptr); + } + } + + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); +} + +TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) { + // Create test HIDL model and compile. + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + sp preparedModel = nullptr; + + // Save the compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + uint8_t dummyBytes[] = {0, 0}; + // Write a dummy integer to the cache. + // The driver should be able to handle non-empty cache and non-zero fd offset. + for (uint32_t i = 0; i < modelCache.size(); i++) { + ASSERT_EQ(write(modelCache[i].getNativeHandle()->data[0], &dummyBytes, + sizeof(dummyBytes)), + sizeof(dummyBytes)); + } + for (uint32_t i = 0; i < dataCache.size(); i++) { + ASSERT_EQ( + write(dataCache[i].getNativeHandle()->data[0], &dummyBytes, sizeof(dummyBytes)), + sizeof(dummyBytes)); + } + saveModelToCache(model, modelCache, dataCache); + } + + // Retrieve preparedModel from cache. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + uint8_t dummyByte = 0; + // Advance the offset of each handle by one byte. + // The driver should be able to handle non-zero fd offset. + for (uint32_t i = 0; i < modelCache.size(); i++) { + ASSERT_GE(read(modelCache[i].getNativeHandle()->data[0], &dummyByte, 1), 0); + } + for (uint32_t i = 0; i < dataCache.size(); i++) { + ASSERT_GE(read(dataCache[i].getNativeHandle()->data[0], &dummyByte, 1), 0); + } + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (!mIsCachingSupported) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + return; + } else if (checkEarlyTermination(status)) { + ASSERT_EQ(preparedModel, nullptr); + return; + } else { + ASSERT_EQ(status, ErrorStatus::NONE); + ASSERT_NE(preparedModel, nullptr); + } + } + + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); +} + +TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { + // Create test HIDL model and compile. + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + + // Test with number of model cache files greater than mNumModelCache. + { + hidl_vec modelCache, dataCache; + // Pass an additional cache file for model cache. + mModelCache.push_back({mTmpCache}); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mModelCache.pop_back(); + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Test with number of model cache files smaller than mNumModelCache. + if (mModelCache.size() > 0) { + hidl_vec modelCache, dataCache; + // Pop out the last cache file. + auto tmp = mModelCache.back(); + mModelCache.pop_back(); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mModelCache.push_back(tmp); + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Test with number of data cache files greater than mNumDataCache. + { + hidl_vec modelCache, dataCache; + // Pass an additional cache file for data cache. + mDataCache.push_back({mTmpCache}); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mDataCache.pop_back(); + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Test with number of data cache files smaller than mNumDataCache. + if (mDataCache.size() > 0) { + hidl_vec modelCache, dataCache; + // Pop out the last cache file. + auto tmp = mDataCache.back(); + mDataCache.pop_back(); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mDataCache.push_back(tmp); + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } +} + +TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumCache) { + // Create test HIDL model and compile. + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + + // Save the compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(model, modelCache, dataCache); + } + + // Test with number of model cache files greater than mNumModelCache. + { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + mModelCache.push_back({mTmpCache}); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mModelCache.pop_back(); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Test with number of model cache files smaller than mNumModelCache. + if (mModelCache.size() > 0) { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + auto tmp = mModelCache.back(); + mModelCache.pop_back(); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mModelCache.push_back(tmp); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Test with number of data cache files greater than mNumDataCache. + { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + mDataCache.push_back({mTmpCache}); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mDataCache.pop_back(); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Test with number of data cache files smaller than mNumDataCache. + if (mDataCache.size() > 0) { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + auto tmp = mDataCache.back(); + mDataCache.pop_back(); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mDataCache.push_back(tmp); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + ASSERT_EQ(preparedModel, nullptr); + } +} + +TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { + // Create test HIDL model and compile. + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + + // Go through each handle in model cache, test with NumFd greater than 1. + for (uint32_t i = 0; i < mNumModelCache; i++) { + hidl_vec modelCache, dataCache; + // Pass an invalid number of fds for handle i. + mModelCache[i].push_back(mTmpCache); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mModelCache[i].pop_back(); + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Go through each handle in model cache, test with NumFd equal to 0. + for (uint32_t i = 0; i < mNumModelCache; i++) { + hidl_vec modelCache, dataCache; + // Pass an invalid number of fds for handle i. + auto tmp = mModelCache[i].back(); + mModelCache[i].pop_back(); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mModelCache[i].push_back(tmp); + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Go through each handle in data cache, test with NumFd greater than 1. + for (uint32_t i = 0; i < mNumDataCache; i++) { + hidl_vec modelCache, dataCache; + // Pass an invalid number of fds for handle i. + mDataCache[i].push_back(mTmpCache); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mDataCache[i].pop_back(); + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Go through each handle in data cache, test with NumFd equal to 0. + for (uint32_t i = 0; i < mNumDataCache; i++) { + hidl_vec modelCache, dataCache; + // Pass an invalid number of fds for handle i. + auto tmp = mDataCache[i].back(); + mDataCache[i].pop_back(); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mDataCache[i].push_back(tmp); + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } +} + +TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumFd) { + // Create test HIDL model and compile. + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + + // Save the compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(model, modelCache, dataCache); + } + + // Go through each handle in model cache, test with NumFd greater than 1. + for (uint32_t i = 0; i < mNumModelCache; i++) { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + mModelCache[i].push_back(mTmpCache); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mModelCache[i].pop_back(); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Go through each handle in model cache, test with NumFd equal to 0. + for (uint32_t i = 0; i < mNumModelCache; i++) { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + auto tmp = mModelCache[i].back(); + mModelCache[i].pop_back(); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mModelCache[i].push_back(tmp); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Go through each handle in data cache, test with NumFd greater than 1. + for (uint32_t i = 0; i < mNumDataCache; i++) { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + mDataCache[i].push_back(mTmpCache); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mDataCache[i].pop_back(); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Go through each handle in data cache, test with NumFd equal to 0. + for (uint32_t i = 0; i < mNumDataCache; i++) { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + auto tmp = mDataCache[i].back(); + mDataCache[i].pop_back(); + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + mDataCache[i].push_back(tmp); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + ASSERT_EQ(preparedModel, nullptr); + } +} + +TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) { + // Create test HIDL model and compile. + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + std::vector modelCacheMode(mNumModelCache, AccessMode::READ_WRITE); + std::vector dataCacheMode(mNumDataCache, AccessMode::READ_WRITE); + + // Go through each handle in model cache, test with invalid access mode. + for (uint32_t i = 0; i < mNumModelCache; i++) { + hidl_vec modelCache, dataCache; + modelCacheMode[i] = AccessMode::READ_ONLY; + createCacheHandles(mModelCache, modelCacheMode, &modelCache); + createCacheHandles(mDataCache, dataCacheMode, &dataCache); + modelCacheMode[i] = AccessMode::READ_WRITE; + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } + + // Go through each handle in data cache, test with invalid access mode. + for (uint32_t i = 0; i < mNumDataCache; i++) { + hidl_vec modelCache, dataCache; + dataCacheMode[i] = AccessMode::READ_ONLY; + createCacheHandles(mModelCache, modelCacheMode, &modelCache); + createCacheHandles(mDataCache, dataCacheMode, &dataCache); + dataCacheMode[i] = AccessMode::READ_WRITE; + sp preparedModel = nullptr; + saveModelToCache(model, modelCache, dataCache, &preparedModel); + ASSERT_NE(preparedModel, nullptr); + // Execute and verify results. + EvaluatePreparedModel(preparedModel, testModel, + /*testDynamicOutputShape=*/false); + // Check if prepareModelFromCache fails. + preparedModel = nullptr; + ErrorStatus status; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + if (status != ErrorStatus::INVALID_ARGUMENT) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + ASSERT_EQ(preparedModel, nullptr); + } +} + +TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidAccessMode) { + // Create test HIDL model and compile. + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + std::vector modelCacheMode(mNumModelCache, AccessMode::READ_WRITE); + std::vector dataCacheMode(mNumDataCache, AccessMode::READ_WRITE); + + // Save the compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(model, modelCache, dataCache); + } + + // Go through each handle in model cache, test with invalid access mode. + for (uint32_t i = 0; i < mNumModelCache; i++) { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + modelCacheMode[i] = AccessMode::WRITE_ONLY; + createCacheHandles(mModelCache, modelCacheMode, &modelCache); + createCacheHandles(mDataCache, dataCacheMode, &dataCache); + modelCacheMode[i] = AccessMode::READ_WRITE; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + } + + // Go through each handle in data cache, test with invalid access mode. + for (uint32_t i = 0; i < mNumDataCache; i++) { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + dataCacheMode[i] = AccessMode::WRITE_ONLY; + createCacheHandles(mModelCache, modelCacheMode, &modelCache); + createCacheHandles(mDataCache, dataCacheMode, &dataCache); + dataCacheMode[i] = AccessMode::READ_WRITE; + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + } +} + +// Copy file contents between file groups. +// The outer vector corresponds to handles and the inner vector is for fds held by each handle. +// The outer vector sizes must match and the inner vectors must have size = 1. +static void copyCacheFiles(const std::vector>& from, + const std::vector>& to) { + constexpr size_t kBufferSize = 1000000; + uint8_t buffer[kBufferSize]; + + ASSERT_EQ(from.size(), to.size()); + for (uint32_t i = 0; i < from.size(); i++) { + ASSERT_EQ(from[i].size(), 1u); + ASSERT_EQ(to[i].size(), 1u); + int fromFd = open(from[i][0].c_str(), O_RDONLY); + int toFd = open(to[i][0].c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + ASSERT_GE(fromFd, 0); + ASSERT_GE(toFd, 0); + + ssize_t readBytes; + while ((readBytes = read(fromFd, &buffer, kBufferSize)) > 0) { + ASSERT_EQ(write(toFd, &buffer, readBytes), readBytes); + } + ASSERT_GE(readBytes, 0); + + close(fromFd); + close(toFd); + } +} + +// Number of operations in the large test model. +constexpr uint32_t kLargeModelSize = 100; +constexpr uint32_t kNumIterationsTOCTOU = 100; + +TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) { + if (!mIsCachingSupported) return; + + // Create test models and check if fully supported by the service. + const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize); + const Model modelMul = createModel(testModelMul); + if (checkEarlyTermination(modelMul)) return; + const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize); + const Model modelAdd = createModel(testModelAdd); + if (checkEarlyTermination(modelAdd)) return; + + // Save the modelMul compilation to cache. + auto modelCacheMul = mModelCache; + for (auto& cache : modelCacheMul) { + cache[0].append("_mul"); + } + { + hidl_vec modelCache, dataCache; + createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(modelMul, modelCache, dataCache); + } + + // Use a different token for modelAdd. + mToken[0]++; + + // This test is probabilistic, so we run it multiple times. + for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) { + // Save the modelAdd compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + + // Spawn a thread to copy the cache content concurrently while saving to cache. + std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache)); + saveModelToCache(modelAdd, modelCache, dataCache); + thread.join(); + } + + // Retrieve preparedModel from cache. + { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + + // The preparation may fail or succeed, but must not crash. If the preparation succeeds, + // the prepared model must be executed with the correct result and not crash. + if (status != ErrorStatus::NONE) { + ASSERT_EQ(preparedModel, nullptr); + } else { + ASSERT_NE(preparedModel, nullptr); + EvaluatePreparedModel(preparedModel, testModelAdd, + /*testDynamicOutputShape=*/false); + } + } + } +} + +TEST_P(CompilationCachingTest, PrepareFromCache_TOCTOU) { + if (!mIsCachingSupported) return; + + // Create test models and check if fully supported by the service. + const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize); + const Model modelMul = createModel(testModelMul); + if (checkEarlyTermination(modelMul)) return; + const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize); + const Model modelAdd = createModel(testModelAdd); + if (checkEarlyTermination(modelAdd)) return; + + // Save the modelMul compilation to cache. + auto modelCacheMul = mModelCache; + for (auto& cache : modelCacheMul) { + cache[0].append("_mul"); + } + { + hidl_vec modelCache, dataCache; + createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(modelMul, modelCache, dataCache); + } + + // Use a different token for modelAdd. + mToken[0]++; + + // This test is probabilistic, so we run it multiple times. + for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) { + // Save the modelAdd compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(modelAdd, modelCache, dataCache); + } + + // Retrieve preparedModel from cache. + { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + + // Spawn a thread to copy the cache content concurrently while preparing from cache. + std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache)); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + thread.join(); + + // The preparation may fail or succeed, but must not crash. If the preparation succeeds, + // the prepared model must be executed with the correct result and not crash. + if (status != ErrorStatus::NONE) { + ASSERT_EQ(preparedModel, nullptr); + } else { + ASSERT_NE(preparedModel, nullptr); + EvaluatePreparedModel(preparedModel, testModelAdd, + /*testDynamicOutputShape=*/false); + } + } + } +} + +TEST_P(CompilationCachingTest, ReplaceSecuritySensitiveCache) { + if (!mIsCachingSupported) return; + + // Create test models and check if fully supported by the service. + const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize); + const Model modelMul = createModel(testModelMul); + if (checkEarlyTermination(modelMul)) return; + const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize); + const Model modelAdd = createModel(testModelAdd); + if (checkEarlyTermination(modelAdd)) return; + + // Save the modelMul compilation to cache. + auto modelCacheMul = mModelCache; + for (auto& cache : modelCacheMul) { + cache[0].append("_mul"); + } + { + hidl_vec modelCache, dataCache; + createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(modelMul, modelCache, dataCache); + } + + // Use a different token for modelAdd. + mToken[0]++; + + // Save the modelAdd compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(modelAdd, modelCache, dataCache); + } + + // Replace the model cache of modelAdd with modelMul. + copyCacheFiles(modelCacheMul, mModelCache); + + // Retrieve the preparedModel from cache, expect failure. + { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + } +} + +static const auto kNamedDeviceChoices = testing::ValuesIn(getNamedDevices()); +static const auto kOperandTypeChoices = + testing::Values(OperandType::TENSOR_FLOAT32, OperandType::TENSOR_QUANT8_ASYMM); + +std::string printCompilationCachingTest( + const testing::TestParamInfo& info) { + const auto& [namedDevice, operandType] = info.param; + const std::string type = (operandType == OperandType::TENSOR_FLOAT32 ? "float32" : "quant8"); + return gtestCompliantName(getName(namedDevice) + "_" + type); +} + +INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingTest, + testing::Combine(kNamedDeviceChoices, kOperandTypeChoices), + printCompilationCachingTest); + +using CompilationCachingSecurityTestParam = std::tuple; + +class CompilationCachingSecurityTest + : public CompilationCachingTestBase, + public testing::WithParamInterface { + protected: + CompilationCachingSecurityTest() + : CompilationCachingTestBase(getData(std::get(GetParam())), + std::get(GetParam())) {} + + void SetUp() { + CompilationCachingTestBase::SetUp(); + generator.seed(kSeed); + } + + // Get a random integer within a closed range [lower, upper]. + template + T getRandomInt(T lower, T upper) { + std::uniform_int_distribution dis(lower, upper); + return dis(generator); + } + + // Randomly flip one single bit of the cache entry. + void flipOneBitOfCache(const std::string& filename, bool* skip) { + FILE* pFile = fopen(filename.c_str(), "r+"); + ASSERT_EQ(fseek(pFile, 0, SEEK_END), 0); + long int fileSize = ftell(pFile); + if (fileSize == 0) { + fclose(pFile); + *skip = true; + return; + } + ASSERT_EQ(fseek(pFile, getRandomInt(0l, fileSize - 1), SEEK_SET), 0); + int readByte = fgetc(pFile); + ASSERT_NE(readByte, EOF); + ASSERT_EQ(fseek(pFile, -1, SEEK_CUR), 0); + ASSERT_NE(fputc(static_cast(readByte) ^ (1U << getRandomInt(0, 7)), pFile), EOF); + fclose(pFile); + *skip = false; + } + + // Randomly append bytes to the cache entry. + void appendBytesToCache(const std::string& filename, bool* skip) { + FILE* pFile = fopen(filename.c_str(), "a"); + uint32_t appendLength = getRandomInt(1, 256); + for (uint32_t i = 0; i < appendLength; i++) { + ASSERT_NE(fputc(getRandomInt(0, 255), pFile), EOF); + } + fclose(pFile); + *skip = false; + } + + enum class ExpectedResult { GENERAL_FAILURE, NOT_CRASH }; + + // Test if the driver behaves as expected when given corrupted cache or token. + // The modifier will be invoked after save to cache but before prepare from cache. + // The modifier accepts one pointer argument "skip" as the returning value, indicating + // whether the test should be skipped or not. + void testCorruptedCache(ExpectedResult expected, std::function modifier) { + const TestModel& testModel = createTestModel(); + const Model model = createModel(testModel); + if (checkEarlyTermination(model)) return; + + // Save the compilation to cache. + { + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + saveModelToCache(model, modelCache, dataCache); + } + + bool skip = false; + modifier(&skip); + if (skip) return; + + // Retrieve preparedModel from cache. + { + sp preparedModel = nullptr; + ErrorStatus status; + hidl_vec modelCache, dataCache; + createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache); + createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache); + prepareModelFromCache(modelCache, dataCache, &preparedModel, &status); + + switch (expected) { + case ExpectedResult::GENERAL_FAILURE: + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + break; + case ExpectedResult::NOT_CRASH: + ASSERT_EQ(preparedModel == nullptr, status != ErrorStatus::NONE); + break; + default: + FAIL(); + } + } + } + + const uint32_t kSeed = std::get(GetParam()); + std::mt19937 generator; +}; + +TEST_P(CompilationCachingSecurityTest, CorruptedModelCache) { + if (!mIsCachingSupported) return; + for (uint32_t i = 0; i < mNumModelCache; i++) { + testCorruptedCache(ExpectedResult::GENERAL_FAILURE, + [this, i](bool* skip) { flipOneBitOfCache(mModelCache[i][0], skip); }); + } +} + +TEST_P(CompilationCachingSecurityTest, WrongLengthModelCache) { + if (!mIsCachingSupported) return; + for (uint32_t i = 0; i < mNumModelCache; i++) { + testCorruptedCache(ExpectedResult::GENERAL_FAILURE, + [this, i](bool* skip) { appendBytesToCache(mModelCache[i][0], skip); }); + } +} + +TEST_P(CompilationCachingSecurityTest, CorruptedDataCache) { + if (!mIsCachingSupported) return; + for (uint32_t i = 0; i < mNumDataCache; i++) { + testCorruptedCache(ExpectedResult::NOT_CRASH, + [this, i](bool* skip) { flipOneBitOfCache(mDataCache[i][0], skip); }); + } +} + +TEST_P(CompilationCachingSecurityTest, WrongLengthDataCache) { + if (!mIsCachingSupported) return; + for (uint32_t i = 0; i < mNumDataCache; i++) { + testCorruptedCache(ExpectedResult::NOT_CRASH, + [this, i](bool* skip) { appendBytesToCache(mDataCache[i][0], skip); }); + } +} + +TEST_P(CompilationCachingSecurityTest, WrongToken) { + if (!mIsCachingSupported) return; + testCorruptedCache(ExpectedResult::GENERAL_FAILURE, [this](bool* skip) { + // Randomly flip one single bit in mToken. + uint32_t ind = + getRandomInt(0u, static_cast(Constant::BYTE_SIZE_OF_CACHE_TOKEN) - 1); + mToken[ind] ^= (1U << getRandomInt(0, 7)); + *skip = false; + }); +} + +std::string printCompilationCachingSecurityTest( + const testing::TestParamInfo& info) { + const auto& [namedDevice, operandType, seed] = info.param; + const std::string type = (operandType == OperandType::TENSOR_FLOAT32 ? "float32" : "quant8"); + return gtestCompliantName(getName(namedDevice) + "_" + type + "_" + std::to_string(seed)); +} + +INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest, + testing::Combine(kNamedDeviceChoices, kOperandTypeChoices, + testing::Range(0U, 10U)), + printCompilationCachingSecurityTest); + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp new file mode 100644 index 0000000000..2beec983e0 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -0,0 +1,408 @@ +/* + * 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. + */ + +#include "GeneratedTestHarness.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "1.0/Utils.h" +#include "1.2/Callbacks.h" +#include "ExecutionBurstController.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "Utils.h" +#include "VtsHalNeuralnetworks.h" + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using namespace test_helper; +using hidl::memory::V1_0::IMemory; +using implementation::ExecutionCallback; +using implementation::PreparedModelCallback; +using V1_0::DataLocation; +using V1_0::ErrorStatus; +using V1_0::OperandLifeTime; +using V1_0::Request; +using V1_1::ExecutionPreference; +using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; + +enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; + +Model createModel(const TestModel& testModel) { + // Model operands. + hidl_vec operands(testModel.operands.size()); + size_t constCopySize = 0, constRefSize = 0; + for (uint32_t i = 0; i < testModel.operands.size(); i++) { + const auto& op = testModel.operands[i]; + + DataLocation loc = {}; + if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { + loc = {.poolIndex = 0, + .offset = static_cast(constCopySize), + .length = static_cast(op.data.size())}; + constCopySize += op.data.alignedSize(); + } else if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) { + loc = {.poolIndex = 0, + .offset = static_cast(constRefSize), + .length = static_cast(op.data.size())}; + constRefSize += op.data.alignedSize(); + } + + Operand::ExtraParams extraParams; + if (op.type == TestOperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) { + extraParams.channelQuant(SymmPerChannelQuantParams{ + .scales = op.channelQuant.scales, .channelDim = op.channelQuant.channelDim}); + } + + operands[i] = {.type = static_cast(op.type), + .dimensions = op.dimensions, + .numberOfConsumers = op.numberOfConsumers, + .scale = op.scale, + .zeroPoint = op.zeroPoint, + .lifetime = static_cast(op.lifetime), + .location = loc, + .extraParams = std::move(extraParams)}; + } + + // Model operations. + hidl_vec operations(testModel.operations.size()); + std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(), + [](const TestOperation& op) -> Operation { + return {.type = static_cast(op.type), + .inputs = op.inputs, + .outputs = op.outputs}; + }); + + // Constant copies. + hidl_vec operandValues(constCopySize); + for (uint32_t i = 0; i < testModel.operands.size(); i++) { + const auto& op = testModel.operands[i]; + if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { + const uint8_t* begin = op.data.get(); + const uint8_t* end = begin + op.data.size(); + std::copy(begin, end, operandValues.data() + operands[i].location.offset); + } + } + + // Shared memory. + hidl_vec pools = {}; + if (constRefSize > 0) { + hidl_vec_push_back(&pools, nn::allocateSharedMemory(constRefSize)); + CHECK_NE(pools[0].size(), 0u); + + // load data + sp mappedMemory = mapMemory(pools[0]); + CHECK(mappedMemory.get() != nullptr); + uint8_t* mappedPtr = + reinterpret_cast(static_cast(mappedMemory->getPointer())); + CHECK(mappedPtr != nullptr); + + for (uint32_t i = 0; i < testModel.operands.size(); i++) { + const auto& op = testModel.operands[i]; + if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) { + const uint8_t* begin = op.data.get(); + const uint8_t* end = begin + op.data.size(); + std::copy(begin, end, mappedPtr + operands[i].location.offset); + } + } + } + + return {.operands = std::move(operands), + .operations = std::move(operations), + .inputIndexes = testModel.inputIndexes, + .outputIndexes = testModel.outputIndexes, + .operandValues = std::move(operandValues), + .pools = std::move(pools), + .relaxComputationFloat32toFloat16 = testModel.isRelaxed}; +} + +static bool isOutputSizeGreaterThanOne(const TestModel& testModel, uint32_t index) { + const auto byteSize = testModel.operands[testModel.outputIndexes[index]].data.size(); + return byteSize > 1u; +} + +static void makeOutputInsufficientSize(uint32_t outputIndex, Request* request) { + auto& length = request->outputs[outputIndex].location.length; + ASSERT_GT(length, 1u); + length -= 1u; +} + +static void makeOutputDimensionsUnspecified(Model* model) { + for (auto i : model->outputIndexes) { + auto& dims = model->operands[i].dimensions; + std::fill(dims.begin(), dims.end(), 0); + } +} + +static Return ExecutePreparedModel(const sp& preparedModel, + const Request& request, MeasureTiming measure, + sp& callback) { + return preparedModel->execute_1_2(request, measure, callback); +} +static Return ExecutePreparedModel(const sp& preparedModel, + const Request& request, MeasureTiming measure, + hidl_vec* outputShapes, + Timing* timing) { + ErrorStatus result; + Return ret = preparedModel->executeSynchronously( + request, measure, + [&result, outputShapes, timing](ErrorStatus error, const hidl_vec& shapes, + const Timing& time) { + result = error; + *outputShapes = shapes; + *timing = time; + }); + if (!ret.isOk()) { + return ErrorStatus::GENERAL_FAILURE; + } + return result; +} +static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst( + const sp& preparedModel) { + return android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true); +} +enum class Executor { ASYNC, SYNC, BURST }; + +void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel, + Executor executor, MeasureTiming measure, OutputType outputType) { + // If output0 does not have size larger than one byte, we can not test with insufficient buffer. + if (outputType == OutputType::INSUFFICIENT && !isOutputSizeGreaterThanOne(testModel, 0)) { + return; + } + + Request request = createRequest(testModel); + if (outputType == OutputType::INSUFFICIENT) { + makeOutputInsufficientSize(/*outputIndex=*/0, &request); + } + + ErrorStatus executionStatus; + hidl_vec outputShapes; + Timing timing; + switch (executor) { + case Executor::ASYNC: { + SCOPED_TRACE("asynchronous"); + + // launch execution + sp executionCallback = new ExecutionCallback(); + Return executionLaunchStatus = + ExecutePreparedModel(preparedModel, request, measure, executionCallback); + ASSERT_TRUE(executionLaunchStatus.isOk()); + EXPECT_EQ(ErrorStatus::NONE, static_cast(executionLaunchStatus)); + + // retrieve execution status + executionCallback->wait(); + executionStatus = executionCallback->getStatus(); + outputShapes = executionCallback->getOutputShapes(); + timing = executionCallback->getTiming(); + + break; + } + case Executor::SYNC: { + SCOPED_TRACE("synchronous"); + + // execute + Return executionReturnStatus = + ExecutePreparedModel(preparedModel, request, measure, &outputShapes, &timing); + ASSERT_TRUE(executionReturnStatus.isOk()); + executionStatus = static_cast(executionReturnStatus); + + break; + } + case Executor::BURST: { + SCOPED_TRACE("burst"); + + // create burst + const std::shared_ptr<::android::nn::ExecutionBurstController> controller = + CreateBurst(preparedModel); + ASSERT_NE(nullptr, controller.get()); + + // create memory keys + std::vector keys(request.pools.size()); + for (size_t i = 0; i < keys.size(); ++i) { + keys[i] = reinterpret_cast(&request.pools[i]); + } + + // execute burst + std::tie(executionStatus, outputShapes, timing) = + controller->compute(request, measure, keys); + + break; + } + } + + if (outputType != OutputType::FULLY_SPECIFIED && + executionStatus == ErrorStatus::GENERAL_FAILURE) { + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " + "execute model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "execute model that it does not support." + << std::endl; + GTEST_SKIP(); + } + if (measure == MeasureTiming::NO) { + EXPECT_EQ(UINT64_MAX, timing.timeOnDevice); + EXPECT_EQ(UINT64_MAX, timing.timeInDriver); + } else { + if (timing.timeOnDevice != UINT64_MAX && timing.timeInDriver != UINT64_MAX) { + EXPECT_LE(timing.timeOnDevice, timing.timeInDriver); + } + } + + switch (outputType) { + case OutputType::FULLY_SPECIFIED: + // If the model output operands are fully specified, outputShapes must be either + // either empty, or have the same number of elements as the number of outputs. + ASSERT_EQ(ErrorStatus::NONE, executionStatus); + ASSERT_TRUE(outputShapes.size() == 0 || + outputShapes.size() == testModel.outputIndexes.size()); + break; + case OutputType::UNSPECIFIED: + // If the model output operands are not fully specified, outputShapes must have + // the same number of elements as the number of outputs. + ASSERT_EQ(ErrorStatus::NONE, executionStatus); + ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size()); + break; + case OutputType::INSUFFICIENT: + ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus); + ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size()); + ASSERT_FALSE(outputShapes[0].isSufficient); + return; + } + + // Go through all outputs, check returned output shapes. + for (uint32_t i = 0; i < outputShapes.size(); i++) { + EXPECT_TRUE(outputShapes[i].isSufficient); + const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions; + const std::vector actual = outputShapes[i].dimensions; + EXPECT_EQ(expect, actual); + } + + // Retrieve execution results. + const std::vector outputs = getOutputBuffers(request); + + // We want "close-enough" results. + checkResults(testModel, outputs); +} + +void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel, + bool testDynamicOutputShape) { + if (testDynamicOutputShape) { + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES, + OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO, + OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO, + OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO, + OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES, + OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES, + OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES, + OutputType::INSUFFICIENT); + } else { + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO, + OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO, + OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO, + OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES, + OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES, + OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES, + OutputType::FULLY_SPECIFIED); + } +} + +void Execute(const sp& device, const TestModel& testModel, bool testDynamicOutputShape) { + Model model = createModel(testModel); + if (testDynamicOutputShape) { + makeOutputDimensionsUnspecified(&model); + } + + sp preparedModel; + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; + + EvaluatePreparedModel(preparedModel, testModel, testDynamicOutputShape); +} + +void GeneratedTestBase::SetUp() { + testing::TestWithParam::SetUp(); + ASSERT_NE(kDevice, nullptr); +} + +std::vector getNamedModels(const FilterFn& filter) { + return TestModelManager::get().getTestModels(filter); +} + +std::string printGeneratedTest(const testing::TestParamInfo& info) { + const auto& [namedDevice, namedModel] = info.param; + return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel)); +} + +// Tag for the generated tests +class GeneratedTest : public GeneratedTestBase {}; + +// Tag for the dynamic output shape tests +class DynamicOutputShapeTest : public GeneratedTest {}; + +TEST_P(GeneratedTest, Test) { + Execute(kDevice, kTestModel, /*testDynamicOutputShape=*/false); +} + +TEST_P(DynamicOutputShapeTest, Test) { + Execute(kDevice, kTestModel, /*testDynamicOutputShape=*/true); +} + +INSTANTIATE_GENERATED_TEST(GeneratedTest, + [](const TestModel& testModel) { return !testModel.expectFailure; }); + +INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, + [](const TestModel& testModel) { return !testModel.expectFailure; }); + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h new file mode 100644 index 0000000000..dfc980c169 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H + +#include +#include +#include +#include +#include +#include "1.0/Utils.h" +#include "TestHarness.h" +#include "VtsHalNeuralnetworks.h" + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using NamedModel = Named; +using GeneratedTestParam = std::tuple; + +class GeneratedTestBase : public testing::TestWithParam { + protected: + void SetUp() override; + const sp kDevice = getData(std::get(GetParam())); + const test_helper::TestModel& kTestModel = *getData(std::get(GetParam())); +}; + +using FilterFn = std::function; +std::vector getNamedModels(const FilterFn& filter); + +std::string printGeneratedTest(const testing::TestParamInfo& info); + +#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ + INSTANTIATE_TEST_SUITE_P(TestGenerated, TestSuite, \ + testing::Combine(testing::ValuesIn(getNamedDevices()), \ + testing::ValuesIn(getNamedModels(filter))), \ + printGeneratedTest) + +// Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp. +// TODO: Clean up the hierarchy for ValidationTest. +class ValidationTest : public GeneratedTestBase {}; + +Model createModel(const test_helper::TestModel& testModel); + +void PrepareModel(const sp& device, const Model& model, sp* preparedModel); + +void EvaluatePreparedModel(const sp& preparedModel, + const test_helper::TestModel& testModel, bool testDynamicOutputShape); + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional + +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H diff --git a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp new file mode 100644 index 0000000000..a0aa3c37d1 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp @@ -0,0 +1,141 @@ +/* + * 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. + */ + +#include +#include "TestHarness.h" + +namespace android::hardware::neuralnetworks::V1_2 { + +// Make sure that the HIDL enums are compatible with the values defined in +// frameworks/ml/nn/tools/test_generator/test_harness/include/TestHarness.h. +using namespace test_helper; +#define CHECK_TEST_ENUM(EnumType, enumValue) \ + static_assert(static_cast(Test##EnumType::enumValue) == EnumType::enumValue) + +CHECK_TEST_ENUM(OperandType, FLOAT32); +CHECK_TEST_ENUM(OperandType, INT32); +CHECK_TEST_ENUM(OperandType, UINT32); +CHECK_TEST_ENUM(OperandType, TENSOR_FLOAT32); +CHECK_TEST_ENUM(OperandType, TENSOR_INT32); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_ASYMM); +CHECK_TEST_ENUM(OperandType, BOOL); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT16_SYMM); +CHECK_TEST_ENUM(OperandType, TENSOR_FLOAT16); +CHECK_TEST_ENUM(OperandType, TENSOR_BOOL8); +CHECK_TEST_ENUM(OperandType, FLOAT16); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_SYMM_PER_CHANNEL); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT16_ASYMM); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_SYMM); + +CHECK_TEST_ENUM(OperationType, ADD); +CHECK_TEST_ENUM(OperationType, AVERAGE_POOL_2D); +CHECK_TEST_ENUM(OperationType, CONCATENATION); +CHECK_TEST_ENUM(OperationType, CONV_2D); +CHECK_TEST_ENUM(OperationType, DEPTHWISE_CONV_2D); +CHECK_TEST_ENUM(OperationType, DEPTH_TO_SPACE); +CHECK_TEST_ENUM(OperationType, DEQUANTIZE); +CHECK_TEST_ENUM(OperationType, EMBEDDING_LOOKUP); +CHECK_TEST_ENUM(OperationType, FLOOR); +CHECK_TEST_ENUM(OperationType, FULLY_CONNECTED); +CHECK_TEST_ENUM(OperationType, HASHTABLE_LOOKUP); +CHECK_TEST_ENUM(OperationType, L2_NORMALIZATION); +CHECK_TEST_ENUM(OperationType, L2_POOL_2D); +CHECK_TEST_ENUM(OperationType, LOCAL_RESPONSE_NORMALIZATION); +CHECK_TEST_ENUM(OperationType, LOGISTIC); +CHECK_TEST_ENUM(OperationType, LSH_PROJECTION); +CHECK_TEST_ENUM(OperationType, LSTM); +CHECK_TEST_ENUM(OperationType, MAX_POOL_2D); +CHECK_TEST_ENUM(OperationType, MUL); +CHECK_TEST_ENUM(OperationType, RELU); +CHECK_TEST_ENUM(OperationType, RELU1); +CHECK_TEST_ENUM(OperationType, RELU6); +CHECK_TEST_ENUM(OperationType, RESHAPE); +CHECK_TEST_ENUM(OperationType, RESIZE_BILINEAR); +CHECK_TEST_ENUM(OperationType, RNN); +CHECK_TEST_ENUM(OperationType, SOFTMAX); +CHECK_TEST_ENUM(OperationType, SPACE_TO_DEPTH); +CHECK_TEST_ENUM(OperationType, SVDF); +CHECK_TEST_ENUM(OperationType, TANH); +CHECK_TEST_ENUM(OperationType, BATCH_TO_SPACE_ND); +CHECK_TEST_ENUM(OperationType, DIV); +CHECK_TEST_ENUM(OperationType, MEAN); +CHECK_TEST_ENUM(OperationType, PAD); +CHECK_TEST_ENUM(OperationType, SPACE_TO_BATCH_ND); +CHECK_TEST_ENUM(OperationType, SQUEEZE); +CHECK_TEST_ENUM(OperationType, STRIDED_SLICE); +CHECK_TEST_ENUM(OperationType, SUB); +CHECK_TEST_ENUM(OperationType, TRANSPOSE); +CHECK_TEST_ENUM(OperationType, ABS); +CHECK_TEST_ENUM(OperationType, ARGMAX); +CHECK_TEST_ENUM(OperationType, ARGMIN); +CHECK_TEST_ENUM(OperationType, AXIS_ALIGNED_BBOX_TRANSFORM); +CHECK_TEST_ENUM(OperationType, BIDIRECTIONAL_SEQUENCE_LSTM); +CHECK_TEST_ENUM(OperationType, BIDIRECTIONAL_SEQUENCE_RNN); +CHECK_TEST_ENUM(OperationType, BOX_WITH_NMS_LIMIT); +CHECK_TEST_ENUM(OperationType, CAST); +CHECK_TEST_ENUM(OperationType, CHANNEL_SHUFFLE); +CHECK_TEST_ENUM(OperationType, DETECTION_POSTPROCESSING); +CHECK_TEST_ENUM(OperationType, EQUAL); +CHECK_TEST_ENUM(OperationType, EXP); +CHECK_TEST_ENUM(OperationType, EXPAND_DIMS); +CHECK_TEST_ENUM(OperationType, GATHER); +CHECK_TEST_ENUM(OperationType, GENERATE_PROPOSALS); +CHECK_TEST_ENUM(OperationType, GREATER); +CHECK_TEST_ENUM(OperationType, GREATER_EQUAL); +CHECK_TEST_ENUM(OperationType, GROUPED_CONV_2D); +CHECK_TEST_ENUM(OperationType, HEATMAP_MAX_KEYPOINT); +CHECK_TEST_ENUM(OperationType, INSTANCE_NORMALIZATION); +CHECK_TEST_ENUM(OperationType, LESS); +CHECK_TEST_ENUM(OperationType, LESS_EQUAL); +CHECK_TEST_ENUM(OperationType, LOG); +CHECK_TEST_ENUM(OperationType, LOGICAL_AND); +CHECK_TEST_ENUM(OperationType, LOGICAL_NOT); +CHECK_TEST_ENUM(OperationType, LOGICAL_OR); +CHECK_TEST_ENUM(OperationType, LOG_SOFTMAX); +CHECK_TEST_ENUM(OperationType, MAXIMUM); +CHECK_TEST_ENUM(OperationType, MINIMUM); +CHECK_TEST_ENUM(OperationType, NEG); +CHECK_TEST_ENUM(OperationType, NOT_EQUAL); +CHECK_TEST_ENUM(OperationType, PAD_V2); +CHECK_TEST_ENUM(OperationType, POW); +CHECK_TEST_ENUM(OperationType, PRELU); +CHECK_TEST_ENUM(OperationType, QUANTIZE); +CHECK_TEST_ENUM(OperationType, QUANTIZED_16BIT_LSTM); +CHECK_TEST_ENUM(OperationType, RANDOM_MULTINOMIAL); +CHECK_TEST_ENUM(OperationType, REDUCE_ALL); +CHECK_TEST_ENUM(OperationType, REDUCE_ANY); +CHECK_TEST_ENUM(OperationType, REDUCE_MAX); +CHECK_TEST_ENUM(OperationType, REDUCE_MIN); +CHECK_TEST_ENUM(OperationType, REDUCE_PROD); +CHECK_TEST_ENUM(OperationType, REDUCE_SUM); +CHECK_TEST_ENUM(OperationType, ROI_ALIGN); +CHECK_TEST_ENUM(OperationType, ROI_POOLING); +CHECK_TEST_ENUM(OperationType, RSQRT); +CHECK_TEST_ENUM(OperationType, SELECT); +CHECK_TEST_ENUM(OperationType, SIN); +CHECK_TEST_ENUM(OperationType, SLICE); +CHECK_TEST_ENUM(OperationType, SPLIT); +CHECK_TEST_ENUM(OperationType, SQRT); +CHECK_TEST_ENUM(OperationType, TILE); +CHECK_TEST_ENUM(OperationType, TOPK_V2); +CHECK_TEST_ENUM(OperationType, TRANSPOSE_CONV_2D); +CHECK_TEST_ENUM(OperationType, UNIDIRECTIONAL_SEQUENCE_LSTM); +CHECK_TEST_ENUM(OperationType, UNIDIRECTIONAL_SEQUENCE_RNN); +CHECK_TEST_ENUM(OperationType, RESIZE_NEAREST_NEIGHBOR); + +#undef CHECK_TEST_ENUM + +} // namespace android::hardware::neuralnetworks::V1_2 diff --git a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp new file mode 100644 index 0000000000..1d4493d208 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp @@ -0,0 +1,400 @@ +/* + * 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 "neuralnetworks_hidl_hal_test" + +#include "VtsHalNeuralnetworks.h" + +#include "1.2/Callbacks.h" +#include "ExecutionBurstController.h" +#include "ExecutionBurstServer.h" +#include "GeneratedTestHarness.h" +#include "TestHarness.h" +#include "Utils.h" + +#include +#include + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using nn::ExecutionBurstController; +using nn::RequestChannelSender; +using nn::ResultChannelReceiver; +using V1_0::ErrorStatus; +using V1_0::Request; +using ExecutionBurstCallback = ExecutionBurstController::ExecutionBurstCallback; + +// This constant value represents the length of an FMQ that is large enough to +// return a result from a burst execution for all of the generated test cases. +constexpr size_t kExecutionBurstChannelLength = 1024; + +// This constant value represents a length of an FMQ that is not large enough +// to return a result from a burst execution for some of the generated test +// cases. +constexpr size_t kExecutionBurstChannelSmallLength = 8; + +///////////////////////// UTILITY FUNCTIONS ///////////////////////// + +static bool badTiming(Timing timing) { + return timing.timeOnDevice == UINT64_MAX && timing.timeInDriver == UINT64_MAX; +} + +static void createBurst(const sp& preparedModel, const sp& callback, + std::unique_ptr* sender, + std::unique_ptr* receiver, + sp* context, + size_t resultChannelLength = kExecutionBurstChannelLength) { + ASSERT_NE(nullptr, preparedModel.get()); + ASSERT_NE(nullptr, sender); + ASSERT_NE(nullptr, receiver); + ASSERT_NE(nullptr, context); + + // create FMQ objects + auto [fmqRequestChannel, fmqRequestDescriptor] = + RequestChannelSender::create(kExecutionBurstChannelLength, /*blocking=*/true); + auto [fmqResultChannel, fmqResultDescriptor] = + ResultChannelReceiver::create(resultChannelLength, /*blocking=*/true); + ASSERT_NE(nullptr, fmqRequestChannel.get()); + ASSERT_NE(nullptr, fmqResultChannel.get()); + ASSERT_NE(nullptr, fmqRequestDescriptor); + ASSERT_NE(nullptr, fmqResultDescriptor); + + // configure burst + ErrorStatus errorStatus; + sp burstContext; + const Return ret = preparedModel->configureExecutionBurst( + callback, *fmqRequestDescriptor, *fmqResultDescriptor, + [&errorStatus, &burstContext](ErrorStatus status, const sp& context) { + errorStatus = status; + burstContext = context; + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(ErrorStatus::NONE, errorStatus); + ASSERT_NE(nullptr, burstContext.get()); + + // return values + *sender = std::move(fmqRequestChannel); + *receiver = std::move(fmqResultChannel); + *context = burstContext; +} + +static void createBurstWithResultChannelLength( + const sp& preparedModel, size_t resultChannelLength, + std::shared_ptr* controller) { + ASSERT_NE(nullptr, preparedModel.get()); + ASSERT_NE(nullptr, controller); + + // create FMQ objects + std::unique_ptr sender; + std::unique_ptr receiver; + sp callback = new ExecutionBurstCallback(); + sp context; + ASSERT_NO_FATAL_FAILURE(createBurst(preparedModel, callback, &sender, &receiver, &context, + resultChannelLength)); + ASSERT_NE(nullptr, sender.get()); + ASSERT_NE(nullptr, receiver.get()); + ASSERT_NE(nullptr, context.get()); + + // return values + *controller = std::make_shared(std::move(sender), std::move(receiver), + context, callback); +} + +// Primary validation function. This function will take a valid serialized +// request, apply a mutation to it to invalidate the serialized request, then +// pass it to interface calls that use the serialized request. Note that the +// serialized request here is passed by value, and any mutation to the +// serialized request does not leave this function. +static void validate(RequestChannelSender* sender, ResultChannelReceiver* receiver, + const std::string& message, std::vector serialized, + const std::function*)>& mutation) { + mutation(&serialized); + + // skip if packet is too large to send + if (serialized.size() > kExecutionBurstChannelLength) { + return; + } + + SCOPED_TRACE(message); + + // send invalid packet + ASSERT_TRUE(sender->sendPacket(serialized)); + + // receive error + auto results = receiver->getBlocking(); + ASSERT_TRUE(results.has_value()); + const auto [status, outputShapes, timing] = std::move(*results); + EXPECT_NE(ErrorStatus::NONE, status); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_TRUE(badTiming(timing)); +} + +// For validation, valid packet entries are mutated to invalid packet entries, +// or invalid packet entries are inserted into valid packets. This function +// creates pre-set invalid packet entries for convenience. +static std::vector createBadRequestPacketEntries() { + const FmqRequestDatum::PacketInformation packetInformation = { + /*.packetSize=*/10, /*.numberOfInputOperands=*/10, /*.numberOfOutputOperands=*/10, + /*.numberOfPools=*/10}; + const FmqRequestDatum::OperandInformation operandInformation = { + /*.hasNoValue=*/false, /*.location=*/{}, /*.numberOfDimensions=*/10}; + const int32_t invalidPoolIdentifier = std::numeric_limits::max(); + std::vector bad(7); + bad[0].packetInformation(packetInformation); + bad[1].inputOperandInformation(operandInformation); + bad[2].inputOperandDimensionValue(0); + bad[3].outputOperandInformation(operandInformation); + bad[4].outputOperandDimensionValue(0); + bad[5].poolIdentifier(invalidPoolIdentifier); + bad[6].measureTiming(MeasureTiming::YES); + return bad; +} + +// For validation, valid packet entries are mutated to invalid packet entries, +// or invalid packet entries are inserted into valid packets. This function +// retrieves pre-set invalid packet entries for convenience. This function +// caches these data so they can be reused on subsequent validation checks. +static const std::vector& getBadRequestPacketEntries() { + static const std::vector bad = createBadRequestPacketEntries(); + return bad; +} + +///////////////////////// REMOVE DATUM //////////////////////////////////// + +static void removeDatumTest(RequestChannelSender* sender, ResultChannelReceiver* receiver, + const std::vector& serialized) { + for (size_t index = 0; index < serialized.size(); ++index) { + const std::string message = "removeDatum: removed datum at index " + std::to_string(index); + validate(sender, receiver, message, serialized, + [index](std::vector* serialized) { + serialized->erase(serialized->begin() + index); + }); + } +} + +///////////////////////// ADD DATUM //////////////////////////////////// + +static void addDatumTest(RequestChannelSender* sender, ResultChannelReceiver* receiver, + const std::vector& serialized) { + const std::vector& extra = getBadRequestPacketEntries(); + for (size_t index = 0; index <= serialized.size(); ++index) { + for (size_t type = 0; type < extra.size(); ++type) { + const std::string message = "addDatum: added datum type " + std::to_string(type) + + " at index " + std::to_string(index); + validate(sender, receiver, message, serialized, + [index, type, &extra](std::vector* serialized) { + serialized->insert(serialized->begin() + index, extra[type]); + }); + } + } +} + +///////////////////////// MUTATE DATUM //////////////////////////////////// + +static bool interestingCase(const FmqRequestDatum& lhs, const FmqRequestDatum& rhs) { + using Discriminator = FmqRequestDatum::hidl_discriminator; + + const bool differentValues = (lhs != rhs); + const bool sameDiscriminator = (lhs.getDiscriminator() == rhs.getDiscriminator()); + const auto discriminator = rhs.getDiscriminator(); + const bool isDimensionValue = (discriminator == Discriminator::inputOperandDimensionValue || + discriminator == Discriminator::outputOperandDimensionValue); + + return differentValues && !(sameDiscriminator && isDimensionValue); +} + +static void mutateDatumTest(RequestChannelSender* sender, ResultChannelReceiver* receiver, + const std::vector& serialized) { + const std::vector& change = getBadRequestPacketEntries(); + for (size_t index = 0; index < serialized.size(); ++index) { + for (size_t type = 0; type < change.size(); ++type) { + if (interestingCase(serialized[index], change[type])) { + const std::string message = "mutateDatum: changed datum at index " + + std::to_string(index) + " to datum type " + + std::to_string(type); + validate(sender, receiver, message, serialized, + [index, type, &change](std::vector* serialized) { + (*serialized)[index] = change[type]; + }); + } + } + } +} + +///////////////////////// BURST VALIATION TESTS //////////////////////////////////// + +static void validateBurstSerialization(const sp& preparedModel, + const Request& request) { + // create burst + std::unique_ptr sender; + std::unique_ptr receiver; + sp callback = new ExecutionBurstCallback(); + sp context; + ASSERT_NO_FATAL_FAILURE(createBurst(preparedModel, callback, &sender, &receiver, &context)); + ASSERT_NE(nullptr, sender.get()); + ASSERT_NE(nullptr, receiver.get()); + ASSERT_NE(nullptr, context.get()); + + // load memory into callback slots + std::vector keys; + keys.reserve(request.pools.size()); + std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys), + [](const auto& pool) { return reinterpret_cast(&pool); }); + const std::vector slots = callback->getSlots(request.pools, keys); + + // ensure slot std::numeric_limits::max() doesn't exist (for + // subsequent slot validation testing) + ASSERT_TRUE(std::all_of(slots.begin(), slots.end(), [](int32_t slot) { + return slot != std::numeric_limits::max(); + })); + + // serialize the request + const auto serialized = android::nn::serialize(request, MeasureTiming::YES, slots); + + // validations + removeDatumTest(sender.get(), receiver.get(), serialized); + addDatumTest(sender.get(), receiver.get(), serialized); + mutateDatumTest(sender.get(), receiver.get(), serialized); +} + +// This test validates that when the Result message size exceeds length of the +// result FMQ, the service instance gracefully fails and returns an error. +static void validateBurstFmqLength(const sp& preparedModel, + const Request& request) { + // create regular burst + std::shared_ptr controllerRegular; + ASSERT_NO_FATAL_FAILURE(createBurstWithResultChannelLength( + preparedModel, kExecutionBurstChannelLength, &controllerRegular)); + ASSERT_NE(nullptr, controllerRegular.get()); + + // create burst with small output channel + std::shared_ptr controllerSmall; + ASSERT_NO_FATAL_FAILURE(createBurstWithResultChannelLength( + preparedModel, kExecutionBurstChannelSmallLength, &controllerSmall)); + ASSERT_NE(nullptr, controllerSmall.get()); + + // load memory into callback slots + std::vector keys(request.pools.size()); + for (size_t i = 0; i < keys.size(); ++i) { + keys[i] = reinterpret_cast(&request.pools[i]); + } + + // collect serialized result by running regular burst + const auto [statusRegular, outputShapesRegular, timingRegular] = + controllerRegular->compute(request, MeasureTiming::NO, keys); + + // skip test if regular burst output isn't useful for testing a failure + // caused by having too small of a length for the result FMQ + const std::vector serialized = + android::nn::serialize(statusRegular, outputShapesRegular, timingRegular); + if (statusRegular != ErrorStatus::NONE || + serialized.size() <= kExecutionBurstChannelSmallLength) { + return; + } + + // by this point, execution should fail because the result channel isn't + // large enough to return the serialized result + const auto [statusSmall, outputShapesSmall, timingSmall] = + controllerSmall->compute(request, MeasureTiming::NO, keys); + EXPECT_NE(ErrorStatus::NONE, statusSmall); + EXPECT_EQ(0u, outputShapesSmall.size()); + EXPECT_TRUE(badTiming(timingSmall)); +} + +static bool isSanitized(const FmqResultDatum& datum) { + using Discriminator = FmqResultDatum::hidl_discriminator; + + // check to ensure the padding values in the returned + // FmqResultDatum::OperandInformation are initialized to 0 + if (datum.getDiscriminator() == Discriminator::operandInformation) { + static_assert( + offsetof(FmqResultDatum::OperandInformation, isSufficient) == 0, + "unexpected value for offset of FmqResultDatum::OperandInformation::isSufficient"); + static_assert( + sizeof(FmqResultDatum::OperandInformation::isSufficient) == 1, + "unexpected value for size of FmqResultDatum::OperandInformation::isSufficient"); + static_assert(offsetof(FmqResultDatum::OperandInformation, numberOfDimensions) == 4, + "unexpected value for offset of " + "FmqResultDatum::OperandInformation::numberOfDimensions"); + static_assert(sizeof(FmqResultDatum::OperandInformation::numberOfDimensions) == 4, + "unexpected value for size of " + "FmqResultDatum::OperandInformation::numberOfDimensions"); + static_assert(sizeof(FmqResultDatum::OperandInformation) == 8, + "unexpected value for size of " + "FmqResultDatum::OperandInformation"); + + constexpr size_t paddingOffset = + offsetof(FmqResultDatum::OperandInformation, isSufficient) + + sizeof(FmqResultDatum::OperandInformation::isSufficient); + constexpr size_t paddingSize = + offsetof(FmqResultDatum::OperandInformation, numberOfDimensions) - paddingOffset; + + FmqResultDatum::OperandInformation initialized{}; + std::memset(&initialized, 0, sizeof(initialized)); + + const char* initializedPaddingStart = + reinterpret_cast(&initialized) + paddingOffset; + const char* datumPaddingStart = + reinterpret_cast(&datum.operandInformation()) + paddingOffset; + + return std::memcmp(datumPaddingStart, initializedPaddingStart, paddingSize) == 0; + } + + // there are no other padding initialization checks required, so return true + // for any sum-type that isn't FmqResultDatum::OperandInformation + return true; +} + +static void validateBurstSanitized(const sp& preparedModel, + const Request& request) { + // create burst + std::unique_ptr sender; + std::unique_ptr receiver; + sp callback = new ExecutionBurstCallback(); + sp context; + ASSERT_NO_FATAL_FAILURE(createBurst(preparedModel, callback, &sender, &receiver, &context)); + ASSERT_NE(nullptr, sender.get()); + ASSERT_NE(nullptr, receiver.get()); + ASSERT_NE(nullptr, context.get()); + + // load memory into callback slots + std::vector keys; + keys.reserve(request.pools.size()); + std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys), + [](const auto& pool) { return reinterpret_cast(&pool); }); + const std::vector slots = callback->getSlots(request.pools, keys); + + // send valid request + ASSERT_TRUE(sender->send(request, MeasureTiming::YES, slots)); + + // receive valid result + auto serialized = receiver->getPacketBlocking(); + ASSERT_TRUE(serialized.has_value()); + + // sanitize result + ASSERT_TRUE(std::all_of(serialized->begin(), serialized->end(), isSanitized)) + << "The result serialized data is not properly sanitized"; +} + +///////////////////////////// ENTRY POINT ////////////////////////////////// + +void validateBurst(const sp& preparedModel, const Request& request) { + ASSERT_NO_FATAL_FAILURE(validateBurstSerialization(preparedModel, request)); + ASSERT_NO_FATAL_FAILURE(validateBurstFmqLength(preparedModel, request)); + ASSERT_NO_FATAL_FAILURE(validateBurstSanitized(preparedModel, request)); +} + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp new file mode 100644 index 0000000000..30530beacc --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -0,0 +1,713 @@ +/* + * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test" + +#include "1.0/Utils.h" +#include "1.2/Callbacks.h" +#include "GeneratedTestHarness.h" +#include "VtsHalNeuralnetworks.h" + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using implementation::PreparedModelCallback; +using V1_0::ErrorStatus; +using V1_0::OperandLifeTime; +using V1_1::ExecutionPreference; +using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; + +///////////////////////// UTILITY FUNCTIONS ///////////////////////// + +static void validateGetSupportedOperations(const sp& device, const std::string& message, + const Model& model) { + SCOPED_TRACE(message + " [getSupportedOperations_1_2]"); + + Return ret = device->getSupportedOperations_1_2( + model, [&](ErrorStatus status, const hidl_vec&) { + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); + }); + EXPECT_TRUE(ret.isOk()); +} + +static void validatePrepareModel(const sp& device, const std::string& message, + const Model& model, ExecutionPreference preference) { + SCOPED_TRACE(message + " [prepareModel_1_2]"); + + sp preparedModelCallback = new PreparedModelCallback(); + Return prepareLaunchStatus = + device->prepareModel_1_2(model, preference, hidl_vec(), + hidl_vec(), HidlToken(), preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(prepareLaunchStatus)); + + preparedModelCallback->wait(); + ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus); + sp preparedModel = getPreparedModel_1_2(preparedModelCallback); + ASSERT_EQ(nullptr, preparedModel.get()); +} + +static bool validExecutionPreference(ExecutionPreference preference) { + return preference == ExecutionPreference::LOW_POWER || + preference == ExecutionPreference::FAST_SINGLE_ANSWER || + preference == ExecutionPreference::SUSTAINED_SPEED; +} + +// Primary validation function. This function will take a valid model, apply a +// mutation to it to invalidate the model, then pass it to interface calls that +// use the model. Note that the model here is passed by value, and any mutation +// to the model does not leave this function. +static void validate(const sp& device, const std::string& message, Model model, + const std::function& mutation, + ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) { + mutation(&model); + if (validExecutionPreference(preference)) { + validateGetSupportedOperations(device, message, model); + } + validatePrepareModel(device, message, model, preference); +} + +static uint32_t addOperand(Model* model) { + return hidl_vec_push_back(&model->operands, + { + .type = OperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 0, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }); +} + +static uint32_t addOperand(Model* model, OperandLifeTime lifetime) { + uint32_t index = addOperand(model); + model->operands[index].numberOfConsumers = 1; + model->operands[index].lifetime = lifetime; + return index; +} + +///////////////////////// VALIDATE MODEL OPERAND TYPE ///////////////////////// + +static const uint32_t invalidOperandTypes[] = { + static_cast(OperandTypeRange::FUNDAMENTAL_MIN) - 1, + static_cast(OperandTypeRange::FUNDAMENTAL_MAX) + 1, + static_cast(OperandTypeRange::OEM_MIN) - 1, + static_cast(OperandTypeRange::OEM_MAX) + 1, +}; + +static void mutateOperandTypeTest(const sp& device, const Model& model) { + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + for (uint32_t invalidOperandType : invalidOperandTypes) { + const std::string message = "mutateOperandTypeTest: operand " + + std::to_string(operand) + " set to value " + + std::to_string(invalidOperandType); + validate(device, message, model, [operand, invalidOperandType](Model* model) { + model->operands[operand].type = static_cast(invalidOperandType); + }); + } + } +} + +///////////////////////// VALIDATE OPERAND RANK ///////////////////////// + +static uint32_t getInvalidRank(OperandType type) { + switch (type) { + case OperandType::FLOAT16: + case OperandType::FLOAT32: + case OperandType::INT32: + case OperandType::UINT32: + case OperandType::BOOL: + return 1; + case OperandType::TENSOR_BOOL8: + case OperandType::TENSOR_FLOAT16: + case OperandType::TENSOR_FLOAT32: + case OperandType::TENSOR_INT32: + case OperandType::TENSOR_QUANT8_ASYMM: + case OperandType::TENSOR_QUANT8_SYMM: + case OperandType::TENSOR_QUANT16_ASYMM: + case OperandType::TENSOR_QUANT16_SYMM: + case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: + return 0; + default: + return 0; + } +} + +static void mutateOperandRankTest(const sp& device, const Model& model) { + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + const uint32_t invalidRank = getInvalidRank(model.operands[operand].type); + if (invalidRank == 0) { + continue; + } + const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) + + " has rank of " + std::to_string(invalidRank); + validate(device, message, model, [operand, invalidRank](Model* model) { + model->operands[operand].dimensions = std::vector(invalidRank, 0); + }); + } +} + +///////////////////////// VALIDATE OPERAND SCALE ///////////////////////// + +static float getInvalidScale(OperandType type) { + switch (type) { + case OperandType::FLOAT16: + case OperandType::FLOAT32: + case OperandType::INT32: + case OperandType::UINT32: + case OperandType::BOOL: + case OperandType::TENSOR_BOOL8: + case OperandType::TENSOR_FLOAT16: + case OperandType::TENSOR_FLOAT32: + case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: + return 1.0f; + case OperandType::TENSOR_INT32: + return -1.0f; + case OperandType::TENSOR_QUANT8_SYMM: + case OperandType::TENSOR_QUANT8_ASYMM: + case OperandType::TENSOR_QUANT16_ASYMM: + case OperandType::TENSOR_QUANT16_SYMM: + return 0.0f; + default: + return 0.0f; + } +} + +static void mutateOperandScaleTest(const sp& device, const Model& model) { + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + const float invalidScale = getInvalidScale(model.operands[operand].type); + const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) + + " has scale of " + std::to_string(invalidScale); + validate(device, message, model, [operand, invalidScale](Model* model) { + model->operands[operand].scale = invalidScale; + }); + } +} + +///////////////////////// VALIDATE OPERAND ZERO POINT ///////////////////////// + +static std::vector getInvalidZeroPoints(OperandType type) { + switch (type) { + case OperandType::FLOAT16: + case OperandType::FLOAT32: + case OperandType::INT32: + case OperandType::UINT32: + case OperandType::BOOL: + case OperandType::TENSOR_BOOL8: + case OperandType::TENSOR_FLOAT16: + case OperandType::TENSOR_FLOAT32: + case OperandType::TENSOR_INT32: + case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: + return {1}; + case OperandType::TENSOR_QUANT8_ASYMM: + return {-1, 256}; + case OperandType::TENSOR_QUANT8_SYMM: + return {-129, -1, 1, 128}; + case OperandType::TENSOR_QUANT16_ASYMM: + return {-1, 65536}; + case OperandType::TENSOR_QUANT16_SYMM: + return {-32769, -1, 1, 32768}; + default: + return {}; + } +} + +static void mutateOperandZeroPointTest(const sp& device, const Model& model) { + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + const std::vector invalidZeroPoints = + getInvalidZeroPoints(model.operands[operand].type); + for (int32_t invalidZeroPoint : invalidZeroPoints) { + const std::string message = "mutateOperandZeroPointTest: operand " + + std::to_string(operand) + " has zero point of " + + std::to_string(invalidZeroPoint); + validate(device, message, model, [operand, invalidZeroPoint](Model* model) { + model->operands[operand].zeroPoint = invalidZeroPoint; + }); + } + } +} + +///////////////////////// VALIDATE EXTRA ??? ///////////////////////// + +// TODO: Operand::lifetime +// TODO: Operand::location + +///////////////////////// VALIDATE OPERATION OPERAND TYPE ///////////////////////// + +static void mutateOperand(Operand* operand, OperandType type) { + Operand newOperand = *operand; + newOperand.type = type; + switch (type) { + case OperandType::FLOAT16: + case OperandType::FLOAT32: + case OperandType::INT32: + case OperandType::UINT32: + case OperandType::BOOL: + newOperand.dimensions = hidl_vec(); + newOperand.scale = 0.0f; + newOperand.zeroPoint = 0; + break; + case OperandType::TENSOR_BOOL8: + case OperandType::TENSOR_FLOAT16: + case OperandType::TENSOR_FLOAT32: + newOperand.dimensions = + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + newOperand.scale = 0.0f; + newOperand.zeroPoint = 0; + break; + case OperandType::TENSOR_INT32: + newOperand.dimensions = + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + newOperand.zeroPoint = 0; + break; + case OperandType::TENSOR_QUANT8_ASYMM: + case OperandType::TENSOR_QUANT8_SYMM: + case OperandType::TENSOR_QUANT16_ASYMM: + case OperandType::TENSOR_QUANT16_SYMM: + newOperand.dimensions = + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f; + break; + case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: { + newOperand.dimensions = + operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec({1}); + newOperand.scale = 0.0f; + newOperand.zeroPoint = 0; + + SymmPerChannelQuantParams channelQuant; + channelQuant.channelDim = 0; + channelQuant.scales = hidl_vec( + operand->dimensions.size() > 0 ? static_cast(operand->dimensions[0]) + : 0); + for (size_t i = 0; i < channelQuant.scales.size(); ++i) { + channelQuant.scales[i] = 1.0f; + } + newOperand.extraParams.channelQuant(std::move(channelQuant)); + } break; + case OperandType::OEM: + case OperandType::TENSOR_OEM_BYTE: + default: + break; + } + *operand = newOperand; +} + +static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, const Model& model) { + // Do not test OEM types + if (type == model.operands[operand].type || type == OperandType::OEM || + type == OperandType::TENSOR_OEM_BYTE) { + return true; + } + for (const Operation& operation : model.operations) { + // Skip mutateOperationOperandTypeTest for the following operations. + // - LSH_PROJECTION's second argument is allowed to have any type. + // - ARGMIN and ARGMAX's first argument can be any of + // TENSOR_(FLOAT16|FLOAT32|INT32|QUANT8_ASYMM). + // - CAST's argument can be any of TENSOR_(FLOAT16|FLOAT32|INT32|QUANT8_ASYMM). + // - RANDOM_MULTINOMIAL's argument can be either TENSOR_FLOAT16 or TENSOR_FLOAT32. + // - DEQUANTIZE input can be any of + // TENSOR_(QUANT8_ASYMM|QUANT8_SYMM|QUANT8_SYMM_PER_CHANNEL), output can + // be of either TENSOR_FLOAT16 or TENSOR_FLOAT32. + // - QUANTIZE input can be either TENSOR_FLOAT16 or TENSOR_FLOAT32 + // - CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL + // - DEPTHWISE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL + // - GROUPED_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL + // - TRANSPOSE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL + switch (operation.type) { + case OperationType::LSH_PROJECTION: { + if (operand == operation.inputs[1]) { + return true; + } + } break; + case OperationType::CAST: + case OperationType::ARGMAX: + case OperationType::ARGMIN: { + if (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32 || + type == OperandType::TENSOR_INT32 || type == OperandType::TENSOR_QUANT8_ASYMM) { + return true; + } + } break; + case OperationType::QUANTIZE: + case OperationType::RANDOM_MULTINOMIAL: { + if (operand == operation.inputs[0] && + (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32)) { + return true; + } + } break; + case OperationType::DEQUANTIZE: { + if (operand == operation.inputs[0] && + (type == OperandType::TENSOR_QUANT8_ASYMM || + type == OperandType::TENSOR_QUANT8_SYMM || + type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL)) { + return true; + } + if (operand == operation.outputs[0] && + (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32)) { + return true; + } + } break; + case OperationType::TRANSPOSE_CONV_2D: + case OperationType::GROUPED_CONV_2D: + case OperationType::DEPTHWISE_CONV_2D: + case OperationType::CONV_2D: { + if (operand == operation.inputs[1] && + (type == OperandType::TENSOR_QUANT8_ASYMM || + type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL)) { + return true; + } + } break; + default: + break; + } + } + return false; +} + +static void mutateOperationOperandTypeTest(const sp& device, const Model& model) { + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + for (OperandType invalidOperandType : hidl_enum_range{}) { + if (mutateOperationOperandTypeSkip(operand, invalidOperandType, model)) { + continue; + } + const std::string message = "mutateOperationOperandTypeTest: operand " + + std::to_string(operand) + " set to type " + + toString(invalidOperandType); + validate(device, message, model, [operand, invalidOperandType](Model* model) { + mutateOperand(&model->operands[operand], invalidOperandType); + }); + } + } +} + +///////////////////////// VALIDATE MODEL OPERATION TYPE ///////////////////////// + +static const uint32_t invalidOperationTypes[] = { + static_cast(OperationTypeRange::FUNDAMENTAL_MAX) + 1, + static_cast(OperationTypeRange::OEM_MIN) - 1, + static_cast(OperationTypeRange::OEM_MAX) + 1, +}; + +static void mutateOperationTypeTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + for (uint32_t invalidOperationType : invalidOperationTypes) { + const std::string message = "mutateOperationTypeTest: operation " + + std::to_string(operation) + " set to value " + + std::to_string(invalidOperationType); + validate(device, message, model, [operation, invalidOperationType](Model* model) { + model->operations[operation].type = + static_cast(invalidOperationType); + }); + } + } +} + +///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX ///////////////////////// + +static void mutateOperationInputOperandIndexTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + const uint32_t invalidOperand = model.operands.size(); + for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) { + const std::string message = "mutateOperationInputOperandIndexTest: operation " + + std::to_string(operation) + " input " + + std::to_string(input); + validate(device, message, model, [operation, input, invalidOperand](Model* model) { + model->operations[operation].inputs[input] = invalidOperand; + }); + } + } +} + +///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX ///////////////////////// + +static void mutateOperationOutputOperandIndexTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + const uint32_t invalidOperand = model.operands.size(); + for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) { + const std::string message = "mutateOperationOutputOperandIndexTest: operation " + + std::to_string(operation) + " output " + + std::to_string(output); + validate(device, message, model, [operation, output, invalidOperand](Model* model) { + model->operations[operation].outputs[output] = invalidOperand; + }); + } + } +} + +///////////////////////// REMOVE OPERAND FROM EVERYTHING ///////////////////////// + +static void removeValueAndDecrementGreaterValues(hidl_vec* vec, uint32_t value) { + if (vec) { + // remove elements matching "value" + auto last = std::remove(vec->begin(), vec->end(), value); + vec->resize(std::distance(vec->begin(), last)); + + // decrement elements exceeding "value" + std::transform(vec->begin(), vec->end(), vec->begin(), + [value](uint32_t v) { return v > value ? v-- : v; }); + } +} + +static void removeOperand(Model* model, uint32_t index) { + hidl_vec_removeAt(&model->operands, index); + for (Operation& operation : model->operations) { + removeValueAndDecrementGreaterValues(&operation.inputs, index); + removeValueAndDecrementGreaterValues(&operation.outputs, index); + } + removeValueAndDecrementGreaterValues(&model->inputIndexes, index); + removeValueAndDecrementGreaterValues(&model->outputIndexes, index); +} + +static bool removeOperandSkip(size_t operand, const Model& model) { + for (const Operation& operation : model.operations) { + // Skip removeOperandTest for the following operations. + // - SPLIT's outputs are not checked during prepareModel. + if (operation.type == OperationType::SPLIT) { + for (const size_t outOprand : operation.outputs) { + if (operand == outOprand) { + return true; + } + } + } + // BIDIRECTIONAL_SEQUENCE_LSTM and BIDIRECTIONAL_SEQUENCE_RNN can have either one or two + // outputs depending on their mergeOutputs parameter. + if (operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_LSTM || + operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_RNN) { + for (const size_t outOprand : operation.outputs) { + if (operand == outOprand) { + return true; + } + } + } + } + return false; +} + +static void removeOperandTest(const sp& device, const Model& model) { + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + if (removeOperandSkip(operand, model)) { + continue; + } + const std::string message = "removeOperandTest: operand " + std::to_string(operand); + validate(device, message, model, + [operand](Model* model) { removeOperand(model, operand); }); + } +} + +///////////////////////// REMOVE OPERATION ///////////////////////// + +static void removeOperation(Model* model, uint32_t index) { + for (uint32_t operand : model->operations[index].inputs) { + model->operands[operand].numberOfConsumers--; + } + hidl_vec_removeAt(&model->operations, index); +} + +static void removeOperationTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + const std::string message = "removeOperationTest: operation " + std::to_string(operation); + validate(device, message, model, + [operation](Model* model) { removeOperation(model, operation); }); + } +} + +///////////////////////// REMOVE OPERATION INPUT ///////////////////////// + +static bool removeOperationInputSkip(const Operation& op, size_t input) { + // Skip removeOperationInputTest for the following operations. + // - CONCATENATION has at least 2 inputs, with the last element being INT32. + // - CONV_2D, DEPTHWISE_CONV_2D, MAX_POOL_2D, AVERAGE_POOL_2D, L2_POOL_2D, RESIZE_BILINEAR, + // SPACE_TO_DEPTH, SPACE_TO_DEPTH, SPACE_TO_BATCH_ND, BATCH_TO_SPACE_ND can have an optional + // layout parameter. + // - L2_NORMALIZATION, LOCAL_RESPONSE_NORMALIZATION, SOFTMAX can have an optional axis + // parameter. + switch (op.type) { + case OperationType::CONCATENATION: { + if (op.inputs.size() > 2 && input != op.inputs.size() - 1) { + return true; + } + } break; + case OperationType::DEPTHWISE_CONV_2D: { + if ((op.inputs.size() == 12 && input == 11) || (op.inputs.size() == 9 && input == 8)) { + return true; + } + } break; + case OperationType::CONV_2D: + case OperationType::AVERAGE_POOL_2D: + case OperationType::MAX_POOL_2D: + case OperationType::L2_POOL_2D: { + if ((op.inputs.size() == 11 && input == 10) || (op.inputs.size() == 8 && input == 7)) { + return true; + } + } break; + case OperationType::RESIZE_BILINEAR: { + if (op.inputs.size() == 4 && input == 3) { + return true; + } + } break; + case OperationType::SPACE_TO_DEPTH: + case OperationType::DEPTH_TO_SPACE: + case OperationType::BATCH_TO_SPACE_ND: { + if (op.inputs.size() == 3 && input == 2) { + return true; + } + } break; + case OperationType::SPACE_TO_BATCH_ND: { + if (op.inputs.size() == 4 && input == 3) { + return true; + } + } break; + case OperationType::L2_NORMALIZATION: { + if (op.inputs.size() == 2 && input == 1) { + return true; + } + } break; + case OperationType::LOCAL_RESPONSE_NORMALIZATION: { + if (op.inputs.size() == 6 && input == 5) { + return true; + } + } break; + case OperationType::SOFTMAX: { + if (op.inputs.size() == 3 && input == 2) { + return true; + } + } break; + default: + break; + } + return false; +} + +static void removeOperationInputTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) { + const Operation& op = model.operations[operation]; + if (removeOperationInputSkip(op, input)) { + continue; + } + const std::string message = "removeOperationInputTest: operation " + + std::to_string(operation) + ", input " + + std::to_string(input); + validate(device, message, model, [operation, input](Model* model) { + uint32_t operand = model->operations[operation].inputs[input]; + model->operands[operand].numberOfConsumers--; + hidl_vec_removeAt(&model->operations[operation].inputs, input); + }); + } + } +} + +///////////////////////// REMOVE OPERATION OUTPUT ///////////////////////// + +static void removeOperationOutputTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) { + const std::string message = "removeOperationOutputTest: operation " + + std::to_string(operation) + ", output " + + std::to_string(output); + validate(device, message, model, [operation, output](Model* model) { + hidl_vec_removeAt(&model->operations[operation].outputs, output); + }); + } + } +} + +///////////////////////// MODEL VALIDATION ///////////////////////// + +// TODO: remove model input +// TODO: remove model output +// TODO: add unused operation + +///////////////////////// ADD OPERATION INPUT ///////////////////////// + +static bool addOperationInputSkip(const Operation& op) { + // Skip addOperationInputTest for the following operations. + // - L2_NORMALIZATION, LOCAL_RESPONSE_NORMALIZATION, SOFTMAX can have an optional INT32 axis + // parameter. + if ((op.type == OperationType::L2_NORMALIZATION && op.inputs.size() == 1) || + (op.type == OperationType::LOCAL_RESPONSE_NORMALIZATION && op.inputs.size() == 5) || + (op.type == OperationType::SOFTMAX && op.inputs.size() == 2)) { + return true; + } + return false; +} + +static void addOperationInputTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + if (addOperationInputSkip(model.operations[operation])) { + continue; + } + const std::string message = "addOperationInputTest: operation " + std::to_string(operation); + validate(device, message, model, [operation](Model* model) { + uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT); + hidl_vec_push_back(&model->operations[operation].inputs, index); + hidl_vec_push_back(&model->inputIndexes, index); + }); + } +} + +///////////////////////// ADD OPERATION OUTPUT ///////////////////////// + +static void addOperationOutputTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + const std::string message = + "addOperationOutputTest: operation " + std::to_string(operation); + validate(device, message, model, [operation](Model* model) { + uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT); + hidl_vec_push_back(&model->operations[operation].outputs, index); + hidl_vec_push_back(&model->outputIndexes, index); + }); + } +} + +///////////////////////// VALIDATE EXECUTION PREFERENCE ///////////////////////// + +static const int32_t invalidExecutionPreferences[] = { + static_cast(ExecutionPreference::LOW_POWER) - 1, // lower bound + static_cast(ExecutionPreference::SUSTAINED_SPEED) + 1, // upper bound +}; + +static void mutateExecutionPreferenceTest(const sp& device, const Model& model) { + for (int32_t preference : invalidExecutionPreferences) { + const std::string message = + "mutateExecutionPreferenceTest: preference " + std::to_string(preference); + validate( + device, message, model, [](Model*) {}, + static_cast(preference)); + } +} + +////////////////////////// ENTRY POINT ////////////////////////////// + +void validateModel(const sp& device, const Model& model) { + mutateOperandTypeTest(device, model); + mutateOperandRankTest(device, model); + mutateOperandScaleTest(device, model); + mutateOperandZeroPointTest(device, model); + mutateOperationOperandTypeTest(device, model); + mutateOperationTypeTest(device, model); + mutateOperationInputOperandIndexTest(device, model); + mutateOperationOutputOperandIndexTest(device, model); + removeOperandTest(device, model); + removeOperationTest(device, model); + removeOperationInputTest(device, model); + removeOperationOutputTest(device, model); + addOperationInputTest(device, model); + addOperationOutputTest(device, model); + mutateExecutionPreferenceTest(device, model); +} + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp new file mode 100644 index 0000000000..f25ee62617 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test" + +#include "1.0/Utils.h" +#include "1.2/Callbacks.h" +#include "ExecutionBurstController.h" +#include "GeneratedTestHarness.h" +#include "TestHarness.h" +#include "Utils.h" +#include "VtsHalNeuralnetworks.h" + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using implementation::ExecutionCallback; +using V1_0::ErrorStatus; +using V1_0::Request; + +///////////////////////// UTILITY FUNCTIONS ///////////////////////// + +static bool badTiming(Timing timing) { + return timing.timeOnDevice == UINT64_MAX && timing.timeInDriver == UINT64_MAX; +} + +// Primary validation function. This function will take a valid request, apply a +// mutation to it to invalidate the request, then pass it to interface calls +// that use the request. Note that the request here is passed by value, and any +// mutation to the request does not leave this function. +static void validate(const sp& preparedModel, const std::string& message, + Request request, const std::function& mutation) { + mutation(&request); + + // We'd like to test both with timing requested and without timing + // requested. Rather than running each test both ways, we'll decide whether + // to request timing by hashing the message. We do not use std::hash because + // it is not guaranteed stable across executions. + char hash = 0; + for (auto c : message) { + hash ^= c; + }; + MeasureTiming measure = (hash & 1) ? MeasureTiming::YES : MeasureTiming::NO; + + // asynchronous + { + SCOPED_TRACE(message + " [execute_1_2]"); + + sp executionCallback = new ExecutionCallback(); + Return executeLaunchStatus = + preparedModel->execute_1_2(request, measure, executionCallback); + ASSERT_TRUE(executeLaunchStatus.isOk()); + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(executeLaunchStatus)); + + executionCallback->wait(); + ErrorStatus executionReturnStatus = executionCallback->getStatus(); + const auto& outputShapes = executionCallback->getOutputShapes(); + Timing timing = executionCallback->getTiming(); + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus); + ASSERT_EQ(outputShapes.size(), 0); + ASSERT_TRUE(badTiming(timing)); + } + + // synchronous + { + SCOPED_TRACE(message + " [executeSynchronously]"); + + Return executeStatus = preparedModel->executeSynchronously( + request, measure, + [](ErrorStatus error, const hidl_vec& outputShapes, + const Timing& timing) { + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); + EXPECT_EQ(outputShapes.size(), 0); + EXPECT_TRUE(badTiming(timing)); + }); + ASSERT_TRUE(executeStatus.isOk()); + } + + // burst + { + SCOPED_TRACE(message + " [burst]"); + + // create burst + std::shared_ptr<::android::nn::ExecutionBurstController> burst = + android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true); + ASSERT_NE(nullptr, burst.get()); + + // create memory keys + std::vector keys(request.pools.size()); + for (size_t i = 0; i < keys.size(); ++i) { + keys[i] = reinterpret_cast(&request.pools[i]); + } + + // execute and verify + ErrorStatus error; + std::vector outputShapes; + Timing timing; + std::tie(error, outputShapes, timing) = burst->compute(request, measure, keys); + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, error); + EXPECT_EQ(outputShapes.size(), 0); + EXPECT_TRUE(badTiming(timing)); + + // additional burst testing + if (request.pools.size() > 0) { + // valid free + burst->freeMemory(keys.front()); + + // negative test: invalid free of unknown (blank) memory + burst->freeMemory(intptr_t{}); + + // negative test: double free of memory + burst->freeMemory(keys.front()); + } + } +} + +///////////////////////// REMOVE INPUT //////////////////////////////////// + +static void removeInputTest(const sp& preparedModel, const Request& request) { + for (size_t input = 0; input < request.inputs.size(); ++input) { + const std::string message = "removeInput: removed input " + std::to_string(input); + validate(preparedModel, message, request, + [input](Request* request) { hidl_vec_removeAt(&request->inputs, input); }); + } +} + +///////////////////////// REMOVE OUTPUT //////////////////////////////////// + +static void removeOutputTest(const sp& preparedModel, const Request& request) { + for (size_t output = 0; output < request.outputs.size(); ++output) { + const std::string message = "removeOutput: removed Output " + std::to_string(output); + validate(preparedModel, message, request, + [output](Request* request) { hidl_vec_removeAt(&request->outputs, output); }); + } +} + +///////////////////////////// ENTRY POINT ////////////////////////////////// + +void validateRequest(const sp& preparedModel, const Request& request) { + removeInputTest(preparedModel, request); + removeOutputTest(preparedModel, request); +} + +void validateRequestFailure(const sp& preparedModel, const Request& request) { + SCOPED_TRACE("Expecting request to fail [executeSynchronously]"); + Return executeStatus = preparedModel->executeSynchronously( + request, MeasureTiming::NO, + [](ErrorStatus error, const hidl_vec& outputShapes, const Timing& timing) { + ASSERT_NE(ErrorStatus::NONE, error); + EXPECT_EQ(outputShapes.size(), 0); + EXPECT_TRUE(badTiming(timing)); + }); + ASSERT_TRUE(executeStatus.isOk()); +} + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp new file mode 100644 index 0000000000..4fbd0e270f --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test" + +#include "VtsHalNeuralnetworks.h" +#include +#include +#include +#include +#include "1.0/Callbacks.h" +#include "1.0/Utils.h" +#include "GeneratedTestHarness.h" +#include "TestHarness.h" + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using implementation::PreparedModelCallback; +using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; +using V1_0::ErrorStatus; +using V1_0::Request; +using V1_1::ExecutionPreference; + +// internal helper function +void createPreparedModel(const sp& device, const Model& model, + sp* preparedModel) { + ASSERT_NE(nullptr, preparedModel); + *preparedModel = nullptr; + + // see if service can handle model + bool fullySupportsModel = false; + const Return supportedCall = device->getSupportedOperations_1_2( + model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { + ASSERT_EQ(ErrorStatus::NONE, status); + ASSERT_NE(0ul, supported.size()); + fullySupportsModel = std::all_of(supported.begin(), supported.end(), + [](bool valid) { return valid; }); + }); + ASSERT_TRUE(supportedCall.isOk()); + + // launch prepare model + const sp preparedModelCallback = new PreparedModelCallback(); + const Return prepareLaunchStatus = device->prepareModel_1_2( + model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec(), + hidl_vec(), HidlToken(), preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); + + // retrieve prepared model + preparedModelCallback->wait(); + const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + *preparedModel = getPreparedModel_1_2(preparedModelCallback); + + // The getSupportedOperations_1_2 call returns a list of operations that are + // guaranteed not to fail if prepareModel_1_2 is called, and + // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed. + // If a driver has any doubt that it can prepare an operation, it must + // return false. So here, if a driver isn't sure if it can support an + // operation, but reports that it successfully prepared the model, the test + // can continue. + if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { + ASSERT_EQ(nullptr, preparedModel->get()); + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot prepare " + "model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "prepare model that it does not support." + << std::endl; + GTEST_SKIP(); + } + ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus); + ASSERT_NE(nullptr, preparedModel->get()); +} + +void NeuralnetworksHidlTest::SetUp() { + testing::TestWithParam::SetUp(); + ASSERT_NE(kDevice, nullptr); +} + +static NamedDevice makeNamedDevice(const std::string& name) { + return {name, IDevice::getService(name)}; +} + +static std::vector getNamedDevicesImpl() { + // Retrieves the name of all service instances that implement IDevice, + // including any Lazy HAL instances. + const std::vector names = hardware::getAllHalInstanceNames(IDevice::descriptor); + + // Get a handle to each device and pair it with its name. + std::vector namedDevices; + namedDevices.reserve(names.size()); + std::transform(names.begin(), names.end(), std::back_inserter(namedDevices), makeNamedDevice); + return namedDevices; +} + +const std::vector& getNamedDevices() { + const static std::vector devices = getNamedDevicesImpl(); + return devices; +} + +std::string printNeuralnetworksHidlTest( + const testing::TestParamInfo& info) { + return gtestCompliantName(getName(info.param)); +} + +INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest); + +// Forward declaration from ValidateModel.cpp +void validateModel(const sp& device, const Model& model); +// Forward declaration from ValidateRequest.cpp +void validateRequest(const sp& preparedModel, const V1_0::Request& request); +// Forward declaration from ValidateRequest.cpp +void validateRequestFailure(const sp& preparedModel, const V1_0::Request& request); +// Forward declaration from ValidateBurst.cpp +void validateBurst(const sp& preparedModel, const V1_0::Request& request); + +void validateEverything(const sp& device, const Model& model, const Request& request) { + validateModel(device, model); + + // Create IPreparedModel. + sp preparedModel; + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; + + validateRequest(preparedModel, request); + validateBurst(preparedModel, request); +} + +void validateFailure(const sp& device, const Model& model, const Request& request) { + // TODO: Should this always succeed? + // What if the invalid input is part of the model (i.e., a parameter). + validateModel(device, model); + + // Create IPreparedModel. + sp preparedModel; + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; + + validateRequestFailure(preparedModel, request); +} + +TEST_P(ValidationTest, Test) { + const Model model = createModel(kTestModel); + const Request request = createRequest(kTestModel); + if (kTestModel.expectFailure) { + validateFailure(kDevice, model, request); + } else { + validateEverything(kDevice, model, request); + } +} + +INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); + +sp getPreparedModel_1_2(const sp& callback) { + sp preparedModelV1_0 = callback->getPreparedModel(); + return IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr); +} + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h new file mode 100644 index 0000000000..d01336eccd --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2018 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_2_VTS_HAL_NEURALNETWORKS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H + +#include +#include +#include +#include +#include "1.0/Utils.h" +#include "1.2/Callbacks.h" + +namespace android::hardware::neuralnetworks::V1_2::vts::functional { + +using NamedDevice = Named>; +using NeuralnetworksHidlTestParam = NamedDevice; + +class NeuralnetworksHidlTest : public testing::TestWithParam { + protected: + void SetUp() override; + const sp kDevice = getData(GetParam()); +}; + +const std::vector& getNamedDevices(); + +std::string printNeuralnetworksHidlTest( + const testing::TestParamInfo& info); + +#define INSTANTIATE_DEVICE_TEST(TestSuite) \ + INSTANTIATE_TEST_SUITE_P(PerInstance, TestSuite, testing::ValuesIn(getNamedDevices()), \ + printNeuralnetworksHidlTest) + +// Create an IPreparedModel object. If the model cannot be prepared, +// "preparedModel" will be nullptr instead. +void createPreparedModel(const sp& device, const Model& model, + sp* preparedModel); + +// Utility function to get PreparedModel from callback and downcast to V1_2. +sp getPreparedModel_1_2(const sp& callback); + +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional + +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H diff --git a/neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h b/neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h new file mode 100644 index 0000000000..bf4792cc6b --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2018 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_2_CALLBACKS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The Callback classes are used internally by the NeuralNetworks runtime to + * synchronize between different threads. An asynchronous task is launched + * paired with a callback object. When a client thread requires the output being + * generated by the asynchronous task, the client thread can wait for the result + * and be blocked until it has completed. Any wait may safely be called + * concurrently, even on the same callback object. When the asynchronous task + * has finished its workload, it must immediately call "notify*". If the + * asynchronous task has failed to launch, the function that tried to launch the + * asynchronous task must immediately call "notify*". This "notify*" call + * awakens any client threads waiting on the callback object. + * + * These classes exist to enable synchronization across HIDL. When + * synchronization is only required in the same process, consider using + * std::future, std::mutex, std::condition_variable, or std::experimental::latch + * instead. + */ + +namespace android::hardware::neuralnetworks::V1_2::implementation { + +/** + * The PreparedModelCallback class is used to receive the error status of + * preparing a model as well as the prepared model from a task executing + * asynchronously with respect to the runtime. If a calling thread calls wait + * or get* on a PreparedModelCallback object and the corresponding asynchronous + * task has not finished preparing the model, the calling thread will block + * until the asynchronous task has either called notify or notify_1_2. + * + * If the callback object is notified more than once, only the results of the + * first call to notify* are used, and the results from subsequent calls are + * discarded. + * + * This callback object is passed as an argument to IDevice::prepareModel*. + */ +class PreparedModelCallback : public IPreparedModelCallback { + public: + /** + * IPreparedModelCallback::notify marks the callback object with the return + * status of the asynchronous model preparation along with the prepared + * model, and allows all prior and future wait calls on the + * PreparedModelCallback object to proceed. + * + * Either IPreparedModelCallback::notify or + * IPreparedModelCallback::notify_1_2 must be called on a given + * PreparedModelCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + * @param preparedModel Returned model that has been prepared for execution, + * nullptr if the model was unable to be prepared. + */ + Return notify(V1_0::ErrorStatus status, + const sp& preparedModel) override; + + /** + * IPreparedModelCallback::notify_1_2 marks the callback object with the + * return status of the asynchronous model preparation along with the + * prepared model, and allows all prior and future wait calls on the + * PreparedModelCallback object to proceed. + * + * Either IPreparedModelCallback::notify or + * IPreparedModelCallback::notify_1_2 must be called on a given + * PreparedModelCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + * @param preparedModel Returned model that has been prepared for execution, + * nullptr if the model was unable to be prepared. + */ + Return notify_1_2(V1_0::ErrorStatus status, + const sp& preparedModel) override; + + /** + * PreparedModelCallback::wait blocks until notify* has been called on the + * callback object. + */ + void wait() const; + + /** + * Retrieves the error status returned from the asynchronous task launched + * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished + * asynchronously preparing the model, this call will block until the + * asynchronous task notifies the object. + * + * @return status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + */ + V1_0::ErrorStatus getStatus() const; + + /** + * Retrieves the model that has been prepared for execution from the + * asynchronous task launched by IDevice::prepareModel*. If + * IDevice::prepareModel* has not finished asynchronously preparing the + * model, this call will block until the asynchronous task notifies the + * object. + * + * @return preparedModel Returned model that has been prepared for + * execution, nullptr if the model was unable to be prepared. + */ + sp getPreparedModel() const; + + private: + mutable std::mutex mMutex; + mutable std::condition_variable mCondition; + bool mNotified GUARDED_BY(mMutex) = false; + V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; + sp mPreparedModel; +}; + +/** + * The ExecutionCallback class is used to receive the results of the execution + * from a task executing asynchronously with respect to the runtime. If a + * calling thread calls wait or get* on a ExecutionCallback object and the + * corresponding asynchronous task has not finished the execution, the calling + * thread will block until the asynchronous task has either called notify or + * notify_1_2. + * + * If the callback object is notified more than once, only the results of the + * first call to notify* are used, and the results from subsequent calls are + * discarded. + * + * This callback object is passed as an argument to IPreparedModel::execute*. + */ +class ExecutionCallback : public IExecutionCallback { + public: + /** + * IExecutionCallback::notify marks the callback object with the return + * status of the asynchronous execution that held this callback and enables + * all prior and future wait calls on the ExecutionCallback object to + * proceed. + * + * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must + * be called on a given ExecutionCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from launching the asynchronous task + * (if the launch fails) or from the asynchronous task itself (if the + * launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large + * enough to store the resultant values + * - INVALID_ARGUMENT if the input request is invalid + */ + Return notify(V1_0::ErrorStatus status) override; + + /** + * IExecutionCallback::notify_1_2 marks the callback object with the results + * (error status, dynamic output shapes, and timing information) of the + * asynchronous execution that held this callback and enables all prior and + * future wait calls on the ExecutionCallback object to proceed. + * + * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must + * be called on a given ExecutionCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from launching the asynchronous task + * (if the launch fails) or from the asynchronous task itself (if the + * launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified + * error + * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is + * not large enough to store the corresponding output + * - INVALID_ARGUMENT if one of the input arguments to prepareModel is + * invalid + * @param outputShapes A list of shape information of model output operands. + * The index into "outputShapes" corresponds to the index of the output + * operand in the Request outputs vector. outputShapes must be empty + * unless the status is either NONE or OUTPUT_INSUFFICIENT_SIZE. + * @param Timing Duration of execution. Unless MeasureTiming::YES was passed + * when launching the execution and status is NONE, all times must be + * reported as UINT64_MAX. A driver may choose to report any time as + * UINT64_MAX, indicating that particular measurement is not available. + */ + Return notify_1_2(V1_0::ErrorStatus status, const hidl_vec& outputShapes, + const Timing& timing) override; + + // An overload of the latest notify interface to hide the version from ExecutionBuilder. + Return notify(V1_0::ErrorStatus status, const hidl_vec& outputShapes, + const Timing& timing) { + return notify_1_2(status, outputShapes, timing); + } + + /** + * ExecutionCallback::wait blocks until notify* has been called on the + * callback object. + */ + void wait() const; + + /** + * Retrieves the error status returned from the asynchronous task launched + * by either IPreparedModel::execute or IPreparedModel::execute_1_2. If + * IPreparedModel::execute or IPreparedModel::execute_1_2 has not finished + * asynchronously executing, this call will block until the asynchronous + * task notifies the object. + * + * @return status Error status returned from launching the asynchronous task + * (if the launch fails) or from the asynchronous task itself (if the + * launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified + * error + * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is + * not large enough to store the corresponding output + * - INVALID_ARGUMENT if one of the input arguments to prepareModel is + * invalid + */ + V1_0::ErrorStatus getStatus() const; + + /** + * Retrieves the output shapes returned from the asynchronous task launched + * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not + * finished asynchronously executing, this call will block until the + * asynchronous task notifies the object. + * + * If the asynchronous task was launched by IPreparedModel::execute, an + * empty vector will be returned. + * + * @return outputShapes A list of shape information of model output + * operands. The index into "outputShapes" corresponds to the index of + * the output operand in the Request outputs vector. outputShapes must + * be empty unless the status is either NONE or + * OUTPUT_INSUFFICIENT_SIZE. outputShaps may be empty if the status is + * NONE and all model output operands are fully-specified at execution + * time. outputShapes must have the same number of elements as the + * number of model output operands if the status is + * OUTPUT_INSUFFICIENT_SIZE, or if the status is NONE and the model has + * at least one output operand that is not fully-specified. + */ + const std::vector& getOutputShapes() const; + + /** + * Retrieves the duration of execution of the asynchronous task launched by + * IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not + * finished asynchronously executing, this call will block until the + * asynchronous task notifies the object. + * + * If the asynchronous task was launched by IPreparedModel::execute, every + * time must be UINT64_MAX. + * + * @return timing Duration of the execution. Every time must be UINT64_MAX + * unless the status is NONE. + */ + Timing getTiming() const; + + private: + /* + * ExecutionCallback::notifyInternal stores the results of the execution + * (status, output shapes, and timing information) in the ExecutionCallback + * object before any call to wait or get* return. It then enables all prior + * and future wait calls on the ExecutionCallback object to proceed. + */ + void notifyInternal(V1_0::ErrorStatus errorStatus, const hidl_vec& outputShapes, + const Timing& timing); + + // members + mutable std::mutex mMutex; + mutable std::condition_variable mCondition; + bool mNotified GUARDED_BY(mMutex) = false; + V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; + std::vector mOutputShapes = {}; + Timing mTiming = {}; +}; + +} // namespace android::hardware::neuralnetworks::V1_2::implementation + +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H From 552c7a66ea651027f996f1d2939428b5e3aaffcf Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 10 Oct 2019 22:58:41 +0000 Subject: [PATCH 0168/1022] Revert "Revert "Modify NNAPI VTS tests to run on version 1.3" am: 64f9eb4bd5 am: 7973d7dec5 am: 8bde98b027" This reverts commit 496320b1ec72f861ebd59d3f9ad4615ce9c80564. Reason for revert: revert of a cherry-pick broke master Change-Id: I4654dc75c17f8801103015dc1da91663dfa28d52 --- neuralnetworks/1.2/vts/functional/Android.bp | 19 +- neuralnetworks/1.3/vts/functional/Android.bp | 58 ++++ .../1.3/vts/functional/BasicTests.cpp | 62 +--- .../1.3/vts/functional/Callbacks.cpp | 143 -------- .../functional/CompilationCachingTests.cpp | 13 +- .../vts/functional/GeneratedTestHarness.cpp | 18 +- .../1.3/vts/functional/GeneratedTestHarness.h | 19 +- .../1.3/vts/functional/TestAssertions.cpp | 9 +- .../1.3/vts/functional/ValidateBurst.cpp | 11 +- .../1.3/vts/functional/ValidateModel.cpp | 21 +- .../1.3/vts/functional/ValidateRequest.cpp | 10 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 20 +- .../1.3/vts/functional/VtsHalNeuralnetworks.h | 19 +- .../vts/functional/include/1.2/Callbacks.h | 325 ------------------ 14 files changed, 170 insertions(+), 577 deletions(-) create mode 100644 neuralnetworks/1.3/vts/functional/Android.bp delete mode 100644 neuralnetworks/1.3/vts/functional/Callbacks.cpp delete mode 100644 neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index bfb871986b..fc727b74f4 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -14,12 +14,28 @@ // limitations under the License. // +cc_library_static { + name: "VtsHalNeuralNetworksV1_2Callbacks", + defaults: ["VtsHalTargetTestDefaults"], + export_include_dirs: ["include"], + srcs: [ + "Callbacks.cpp", + ], + static_libs: [ + "android.hardware.neuralnetworks@1.0", + "android.hardware.neuralnetworks@1.1", + "android.hardware.neuralnetworks@1.2", + ], + header_libs: [ + "libbase_headers", + ] +} + cc_test { name: "VtsHalNeuralnetworksV1_2TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ "BasicTests.cpp", - "Callbacks.cpp", "CompilationCachingTests.cpp", "GeneratedTestHarness.cpp", "TestAssertions.cpp", @@ -45,6 +61,7 @@ cc_test { "libneuralnetworks_generated_test_harness", "libneuralnetworks_utils", "VtsHalNeuralNetworksV1_0_utils", + "VtsHalNeuralNetworksV1_2Callbacks", ], whole_static_libs: [ "neuralnetworks_generated_V1_0_example", diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp new file mode 100644 index 0000000000..90ce852e3e --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/Android.bp @@ -0,0 +1,58 @@ +// +// 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. +// + +cc_test { + name: "VtsHalNeuralNetworksV1_3TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "BasicTests.cpp", + "CompilationCachingTests.cpp", + "GeneratedTestHarness.cpp", + "TestAssertions.cpp", + "ValidateBurst.cpp", + "ValidateModel.cpp", + "ValidateRequest.cpp", + "VtsHalNeuralnetworks.cpp", + ], + shared_libs: [ + "libfmq", + "libnativewindow", + ], + static_libs: [ + "android.hardware.neuralnetworks@1.0", + "android.hardware.neuralnetworks@1.1", + "android.hardware.neuralnetworks@1.2", + "android.hardware.neuralnetworks@1.3", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "libgmock", + "libhidlmemory", + "libneuralnetworks_generated_test_harness", + "libneuralnetworks_utils", + "VtsHalNeuralNetworksV1_0_utils", + "VtsHalNeuralNetworksV1_2Callbacks", + ], + whole_static_libs: [ + "neuralnetworks_generated_V1_0_example", + "neuralnetworks_generated_V1_1_example", + "neuralnetworks_generated_V1_2_example", + "neuralnetworks_generated_V1_3_example", + ], + header_libs: [ + "libneuralnetworks_headers", + ], + test_suites: ["general-tests"], +} diff --git a/neuralnetworks/1.3/vts/functional/BasicTests.cpp b/neuralnetworks/1.3/vts/functional/BasicTests.cpp index 8e82c5376e..b64dc2f61b 100644 --- a/neuralnetworks/1.3/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.3/vts/functional/BasicTests.cpp @@ -18,11 +18,14 @@ #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { using V1_0::DeviceStatus; using V1_0::ErrorStatus; using V1_0::PerformanceInfo; +using V1_2::Constant; +using V1_2::DeviceType; +using V1_2::Extension; // create device test TEST_P(NeuralnetworksHidlTest, CreateDevice) {} @@ -37,7 +40,7 @@ TEST_P(NeuralnetworksHidlTest, StatusTest) { // initialization TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) { using OperandPerformance = Capabilities::OperandPerformance; - Return ret = kDevice->getCapabilities_1_2([](ErrorStatus status, + Return ret = kDevice->getCapabilities_1_3([](ErrorStatus status, const Capabilities& capabilities) { EXPECT_EQ(ErrorStatus::NONE, status); @@ -58,57 +61,4 @@ TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) { }); EXPECT_TRUE(ret.isOk()); } - -// device version test -TEST_P(NeuralnetworksHidlTest, GetDeviceVersionStringTest) { - Return ret = - kDevice->getVersionString([](ErrorStatus status, const hidl_string& version) { - EXPECT_EQ(ErrorStatus::NONE, status); - EXPECT_LT(0, version.size()); - }); - EXPECT_TRUE(ret.isOk()); -} - -// device type test -TEST_P(NeuralnetworksHidlTest, GetDeviceTypeTest) { - Return ret = kDevice->getType([](ErrorStatus status, DeviceType type) { - EXPECT_EQ(ErrorStatus::NONE, status); - EXPECT_TRUE(type == DeviceType::OTHER || type == DeviceType::CPU || - type == DeviceType::GPU || type == DeviceType::ACCELERATOR); - }); - EXPECT_TRUE(ret.isOk()); -} - -// device supported extensions test -TEST_P(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) { - Return ret = kDevice->getSupportedExtensions( - [](ErrorStatus status, const hidl_vec& extensions) { - EXPECT_EQ(ErrorStatus::NONE, status); - for (auto& extension : extensions) { - std::string extensionName = extension.name; - EXPECT_FALSE(extensionName.empty()); - for (char c : extensionName) { - EXPECT_TRUE(('a' <= c && c <= 'z') || ('0' <= c && c <= '9') || c == '_' || - c == '.') - << "Extension name contains an illegal character: " << c; - } - EXPECT_NE(extensionName.find('.'), std::string::npos) - << "Extension name must start with the reverse domain name of the " - "vendor"; - } - }); - EXPECT_TRUE(ret.isOk()); -} - -// getNumberOfCacheFilesNeeded test -TEST_P(NeuralnetworksHidlTest, getNumberOfCacheFilesNeeded) { - Return ret = kDevice->getNumberOfCacheFilesNeeded( - [](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) { - EXPECT_EQ(ErrorStatus::NONE, status); - EXPECT_LE(numModelCache, - static_cast(Constant::MAX_NUMBER_OF_CACHE_FILES)); - EXPECT_LE(numDataCache, static_cast(Constant::MAX_NUMBER_OF_CACHE_FILES)); - }); - EXPECT_TRUE(ret.isOk()); -} -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/Callbacks.cpp b/neuralnetworks/1.3/vts/functional/Callbacks.cpp deleted file mode 100644 index 3972ad6ff2..0000000000 --- a/neuralnetworks/1.3/vts/functional/Callbacks.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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 "Callbacks" - -#include "1.2/Callbacks.h" - -#include - -#include - -namespace android::hardware::neuralnetworks::V1_2::implementation { - -using V1_0::ErrorStatus; - -constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits::max(), - .timeInDriver = std::numeric_limits::max()}; - -// PreparedModelCallback methods begin here - -Return PreparedModelCallback::notify(ErrorStatus errorStatus, - const sp& preparedModel) { - { - std::lock_guard hold(mMutex); - - // quick-return if object has already been notified - if (mNotified) { - return Void(); - } - - // store results and mark as notified - mErrorStatus = errorStatus; - mPreparedModel = preparedModel; - mNotified = true; - } - - mCondition.notify_all(); - return Void(); -} - -Return PreparedModelCallback::notify_1_2(ErrorStatus errorStatus, - const sp& preparedModel) { - return notify(errorStatus, preparedModel); -} - -void PreparedModelCallback::wait() const { - std::unique_lock lock(mMutex); - mCondition.wait(lock, [this] { return mNotified; }); -} - -ErrorStatus PreparedModelCallback::getStatus() const { - wait(); - return mErrorStatus; -} - -sp PreparedModelCallback::getPreparedModel() const { - wait(); - return mPreparedModel; -} - -// ExecutionCallback methods begin here - -Return ExecutionCallback::notify(ErrorStatus errorStatus) { - notifyInternal(errorStatus, {}, kNoTiming); - return Void(); -} - -Return ExecutionCallback::notify_1_2(ErrorStatus errorStatus, - const hidl_vec& outputShapes, - const Timing& timing) { - if (errorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { - // outputShapes must not be empty if OUTPUT_INSUFFICIENT_SIZE. - if (outputShapes.size() == 0) { - LOG(ERROR) << "Notified with empty output shape vector when OUTPUT_INSUFFICIENT_SIZE"; - notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); - return Void(); - } - } else if (errorStatus != ErrorStatus::NONE) { - // outputShapes must be empty if errorStatus is neither NONE nor OUTPUT_INSUFFICIENT_SIZE. - if (outputShapes.size() != 0) { - LOG(ERROR) << "Notified with non-empty output shape vector when error status is " - "neither NONE nor OUTPUT_INSUFFICIENT_SIZE"; - notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); - return Void(); - } - } - notifyInternal(errorStatus, outputShapes, timing); - return Void(); -} - -void ExecutionCallback::wait() const { - std::unique_lock lock(mMutex); - mCondition.wait(lock, [this] { return mNotified; }); -} - -ErrorStatus ExecutionCallback::getStatus() const { - wait(); - return mErrorStatus; -} - -const std::vector& ExecutionCallback::getOutputShapes() const { - wait(); - return mOutputShapes; -} - -Timing ExecutionCallback::getTiming() const { - wait(); - return mTiming; -} - -void ExecutionCallback::notifyInternal(ErrorStatus errorStatus, - const hidl_vec& outputShapes, - const Timing& timing) { - { - std::lock_guard hold(mMutex); - - // quick-return if object has already been notified - if (mNotified) { - return; - } - - mErrorStatus = errorStatus; - mOutputShapes = outputShapes; - mTiming = timing; - mNotified = true; - } - mCondition.notify_all(); -} - -} // namespace android::hardware::neuralnetworks::V1_2::implementation diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp index 2130a76b75..0ac4738fff 100644 --- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp @@ -45,12 +45,15 @@ namespace generated_tests::mobilenet_quantized { const test_helper::TestModel& get_test_model(); } // namespace generated_tests::mobilenet_quantized -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { using namespace test_helper; -using implementation::PreparedModelCallback; using V1_0::ErrorStatus; using V1_1::ExecutionPreference; +using V1_2::Constant; +using V1_2::IPreparedModel; +using V1_2::OperationType; +using V1_2::implementation::PreparedModelCallback; namespace float32_model { @@ -302,7 +305,7 @@ class CompilationCachingTestBase : public testing::Test { // See if the service can handle the model. bool isModelFullySupported(const Model& model) { bool fullySupportsModel = false; - Return supportedCall = kDevice->getSupportedOperations_1_2( + Return supportedCall = kDevice->getSupportedOperations_1_3( model, [&fullySupportsModel, &model](ErrorStatus status, const hidl_vec& supported) { ASSERT_EQ(ErrorStatus::NONE, status); @@ -323,7 +326,7 @@ class CompilationCachingTestBase : public testing::Test { sp preparedModelCallback = new PreparedModelCallback(); hidl_array cacheToken(mToken); Return prepareLaunchStatus = - kDevice->prepareModel_1_2(model, ExecutionPreference::FAST_SINGLE_ANSWER, + kDevice->prepareModel_1_3(model, ExecutionPreference::FAST_SINGLE_ANSWER, modelCache, dataCache, cacheToken, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(static_cast(prepareLaunchStatus), ErrorStatus::NONE); @@ -1371,4 +1374,4 @@ INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest, testing::Range(0U, 10U)), printCompilationCachingSecurityTest); -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 2beec983e0..16a7d70fb5 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -27,6 +27,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -44,17 +47,24 @@ #include "Utils.h" #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { using namespace test_helper; using hidl::memory::V1_0::IMemory; -using implementation::ExecutionCallback; -using implementation::PreparedModelCallback; using V1_0::DataLocation; using V1_0::ErrorStatus; using V1_0::OperandLifeTime; using V1_0::Request; using V1_1::ExecutionPreference; +using V1_2::Constant; +using V1_2::IPreparedModel; +using V1_2::MeasureTiming; +using V1_2::OperationType; +using V1_2::OutputShape; +using V1_2::SymmPerChannelQuantParams; +using V1_2::Timing; +using V1_2::implementation::ExecutionCallback; +using V1_2::implementation::PreparedModelCallback; using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; @@ -405,4 +415,4 @@ INSTANTIATE_GENERATED_TEST(GeneratedTest, INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h index dfc980c169..b9277cfd4a 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h @@ -14,19 +14,19 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H -#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H -#include #include -#include +#include +#include #include #include #include "1.0/Utils.h" #include "TestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { using NamedModel = Named; using GeneratedTestParam = std::tuple; @@ -55,11 +55,12 @@ class ValidationTest : public GeneratedTestBase {}; Model createModel(const test_helper::TestModel& testModel); -void PrepareModel(const sp& device, const Model& model, sp* preparedModel); +void PrepareModel(const sp& device, const Model& model, + sp* preparedModel); -void EvaluatePreparedModel(const sp& preparedModel, +void EvaluatePreparedModel(const sp& preparedModel, const test_helper::TestModel& testModel, bool testDynamicOutputShape); -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional -#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H diff --git a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp index a0aa3c37d1..7361078eca 100644 --- a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp +++ b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp @@ -14,10 +14,10 @@ * limitations under the License. */ -#include +#include #include "TestHarness.h" -namespace android::hardware::neuralnetworks::V1_2 { +namespace android::hardware::neuralnetworks::V1_3 { // Make sure that the HIDL enums are compatible with the values defined in // frameworks/ml/nn/tools/test_generator/test_harness/include/TestHarness.h. @@ -25,6 +25,8 @@ using namespace test_helper; #define CHECK_TEST_ENUM(EnumType, enumValue) \ static_assert(static_cast(Test##EnumType::enumValue) == EnumType::enumValue) +using V1_2::OperationType; + CHECK_TEST_ENUM(OperandType, FLOAT32); CHECK_TEST_ENUM(OperandType, INT32); CHECK_TEST_ENUM(OperandType, UINT32); @@ -39,6 +41,7 @@ CHECK_TEST_ENUM(OperandType, FLOAT16); CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_SYMM_PER_CHANNEL); CHECK_TEST_ENUM(OperandType, TENSOR_QUANT16_ASYMM); CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_SYMM); +CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_ASYMM_SIGNED); CHECK_TEST_ENUM(OperationType, ADD); CHECK_TEST_ENUM(OperationType, AVERAGE_POOL_2D); @@ -138,4 +141,4 @@ CHECK_TEST_ENUM(OperationType, RESIZE_NEAREST_NEIGHBOR); #undef CHECK_TEST_ENUM -} // namespace android::hardware::neuralnetworks::V1_2 +} // namespace android::hardware::neuralnetworks::V1_3 diff --git a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp index 1d4493d208..95f9f427b2 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp @@ -28,13 +28,20 @@ #include #include -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { using nn::ExecutionBurstController; using nn::RequestChannelSender; using nn::ResultChannelReceiver; using V1_0::ErrorStatus; using V1_0::Request; +using V1_2::FmqRequestDatum; +using V1_2::FmqResultDatum; +using V1_2::IBurstCallback; +using V1_2::IBurstContext; +using V1_2::IPreparedModel; +using V1_2::MeasureTiming; +using V1_2::Timing; using ExecutionBurstCallback = ExecutionBurstController::ExecutionBurstCallback; // This constant value represents the length of an FMQ that is large enough to @@ -397,4 +404,4 @@ void validateBurst(const sp& preparedModel, const Request& reque ASSERT_NO_FATAL_FAILURE(validateBurstSanitized(preparedModel, request)); } -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 30530beacc..44b32a9fec 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -21,21 +21,26 @@ #include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { -using implementation::PreparedModelCallback; using V1_0::ErrorStatus; using V1_0::OperandLifeTime; using V1_1::ExecutionPreference; -using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; +using V1_2::IPreparedModel; +using V1_2::OperationType; +using V1_2::OperationTypeRange; +using V1_2::SymmPerChannelQuantParams; +using V1_2::implementation::PreparedModelCallback; +using HidlToken = + hidl_array(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// static void validateGetSupportedOperations(const sp& device, const std::string& message, const Model& model) { - SCOPED_TRACE(message + " [getSupportedOperations_1_2]"); + SCOPED_TRACE(message + " [getSupportedOperations_1_3]"); - Return ret = device->getSupportedOperations_1_2( + Return ret = device->getSupportedOperations_1_3( model, [&](ErrorStatus status, const hidl_vec&) { EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); }); @@ -44,11 +49,11 @@ static void validateGetSupportedOperations(const sp& device, const std: static void validatePrepareModel(const sp& device, const std::string& message, const Model& model, ExecutionPreference preference) { - SCOPED_TRACE(message + " [prepareModel_1_2]"); + SCOPED_TRACE(message + " [prepareModel_1_3]"); sp preparedModelCallback = new PreparedModelCallback(); Return prepareLaunchStatus = - device->prepareModel_1_2(model, preference, hidl_vec(), + device->prepareModel_1_3(model, preference, hidl_vec(), hidl_vec(), HidlToken(), preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(prepareLaunchStatus)); @@ -710,4 +715,4 @@ void validateModel(const sp& device, const Model& model) { mutateExecutionPreferenceTest(device, model); } -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index f25ee62617..612212382c 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -24,11 +24,15 @@ #include "Utils.h" #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { -using implementation::ExecutionCallback; using V1_0::ErrorStatus; using V1_0::Request; +using V1_2::IPreparedModel; +using V1_2::MeasureTiming; +using V1_2::OutputShape; +using V1_2::Timing; +using V1_2::implementation::ExecutionCallback; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// @@ -165,4 +169,4 @@ void validateRequestFailure(const sp& preparedModel, const Reque ASSERT_TRUE(executeStatus.isOk()); } -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index 4fbd0e270f..4f0e150b32 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -26,13 +26,15 @@ #include "GeneratedTestHarness.h" #include "TestHarness.h" -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { -using implementation::PreparedModelCallback; -using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; +using HidlToken = + hidl_array(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; using V1_0::ErrorStatus; using V1_0::Request; using V1_1::ExecutionPreference; +using V1_2::IPreparedModel; +using V1_2::implementation::PreparedModelCallback; // internal helper function void createPreparedModel(const sp& device, const Model& model, @@ -42,7 +44,7 @@ void createPreparedModel(const sp& device, const Model& model, // see if service can handle model bool fullySupportsModel = false; - const Return supportedCall = device->getSupportedOperations_1_2( + const Return supportedCall = device->getSupportedOperations_1_3( model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { ASSERT_EQ(ErrorStatus::NONE, status); ASSERT_NE(0ul, supported.size()); @@ -53,7 +55,7 @@ void createPreparedModel(const sp& device, const Model& model, // launch prepare model const sp preparedModelCallback = new PreparedModelCallback(); - const Return prepareLaunchStatus = device->prepareModel_1_2( + const Return prepareLaunchStatus = device->prepareModel_1_3( model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec(), hidl_vec(), HidlToken(), preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); @@ -64,8 +66,8 @@ void createPreparedModel(const sp& device, const Model& model, const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); *preparedModel = getPreparedModel_1_2(preparedModelCallback); - // The getSupportedOperations_1_2 call returns a list of operations that are - // guaranteed not to fail if prepareModel_1_2 is called, and + // The getSupportedOperations_1_3 call returns a list of operations that are + // guaranteed not to fail if prepareModel_1_3 is called, and // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed. // If a driver has any doubt that it can prepare an operation, it must // return false. So here, if a driver isn't sure if it can support an @@ -163,9 +165,9 @@ TEST_P(ValidationTest, Test) { INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); -sp getPreparedModel_1_2(const sp& callback) { +sp getPreparedModel_1_2(const sp& callback) { sp preparedModelV1_0 = callback->getPreparedModel(); return IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr); } -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h index d01336eccd..fc654ce8f0 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h @@ -14,17 +14,17 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H -#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H -#include #include -#include +#include +#include #include #include "1.0/Utils.h" #include "1.2/Callbacks.h" -namespace android::hardware::neuralnetworks::V1_2::vts::functional { +namespace android::hardware::neuralnetworks::V1_3::vts::functional { using NamedDevice = Named>; using NeuralnetworksHidlTestParam = NamedDevice; @@ -47,11 +47,12 @@ std::string printNeuralnetworksHidlTest( // Create an IPreparedModel object. If the model cannot be prepared, // "preparedModel" will be nullptr instead. void createPreparedModel(const sp& device, const Model& model, - sp* preparedModel); + sp* preparedModel); // Utility function to get PreparedModel from callback and downcast to V1_2. -sp getPreparedModel_1_2(const sp& callback); +sp getPreparedModel_1_2( + const sp& callback); -} // namespace android::hardware::neuralnetworks::V1_2::vts::functional +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional -#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H diff --git a/neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h b/neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h deleted file mode 100644 index bf4792cc6b..0000000000 --- a/neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (C) 2018 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_2_CALLBACKS_H -#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * The Callback classes are used internally by the NeuralNetworks runtime to - * synchronize between different threads. An asynchronous task is launched - * paired with a callback object. When a client thread requires the output being - * generated by the asynchronous task, the client thread can wait for the result - * and be blocked until it has completed. Any wait may safely be called - * concurrently, even on the same callback object. When the asynchronous task - * has finished its workload, it must immediately call "notify*". If the - * asynchronous task has failed to launch, the function that tried to launch the - * asynchronous task must immediately call "notify*". This "notify*" call - * awakens any client threads waiting on the callback object. - * - * These classes exist to enable synchronization across HIDL. When - * synchronization is only required in the same process, consider using - * std::future, std::mutex, std::condition_variable, or std::experimental::latch - * instead. - */ - -namespace android::hardware::neuralnetworks::V1_2::implementation { - -/** - * The PreparedModelCallback class is used to receive the error status of - * preparing a model as well as the prepared model from a task executing - * asynchronously with respect to the runtime. If a calling thread calls wait - * or get* on a PreparedModelCallback object and the corresponding asynchronous - * task has not finished preparing the model, the calling thread will block - * until the asynchronous task has either called notify or notify_1_2. - * - * If the callback object is notified more than once, only the results of the - * first call to notify* are used, and the results from subsequent calls are - * discarded. - * - * This callback object is passed as an argument to IDevice::prepareModel*. - */ -class PreparedModelCallback : public IPreparedModelCallback { - public: - /** - * IPreparedModelCallback::notify marks the callback object with the return - * status of the asynchronous model preparation along with the prepared - * model, and allows all prior and future wait calls on the - * PreparedModelCallback object to proceed. - * - * Either IPreparedModelCallback::notify or - * IPreparedModelCallback::notify_1_2 must be called on a given - * PreparedModelCallback object. - * - * If the callback object is notified more than once, only the results of - * the first call to notify* are used, and the results from subsequent calls - * are discarded. - * - * @param status Error status returned from asynchronously preparing the - * model; will be: - * - NONE if the asynchronous preparation was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if there is an unspecified error - * - INVALID_ARGUMENT if the input model is invalid - * @param preparedModel Returned model that has been prepared for execution, - * nullptr if the model was unable to be prepared. - */ - Return notify(V1_0::ErrorStatus status, - const sp& preparedModel) override; - - /** - * IPreparedModelCallback::notify_1_2 marks the callback object with the - * return status of the asynchronous model preparation along with the - * prepared model, and allows all prior and future wait calls on the - * PreparedModelCallback object to proceed. - * - * Either IPreparedModelCallback::notify or - * IPreparedModelCallback::notify_1_2 must be called on a given - * PreparedModelCallback object. - * - * If the callback object is notified more than once, only the results of - * the first call to notify* are used, and the results from subsequent calls - * are discarded. - * - * @param status Error status returned from asynchronously preparing the - * model; will be: - * - NONE if the asynchronous preparation was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if there is an unspecified error - * - INVALID_ARGUMENT if the input model is invalid - * @param preparedModel Returned model that has been prepared for execution, - * nullptr if the model was unable to be prepared. - */ - Return notify_1_2(V1_0::ErrorStatus status, - const sp& preparedModel) override; - - /** - * PreparedModelCallback::wait blocks until notify* has been called on the - * callback object. - */ - void wait() const; - - /** - * Retrieves the error status returned from the asynchronous task launched - * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished - * asynchronously preparing the model, this call will block until the - * asynchronous task notifies the object. - * - * @return status Error status returned from asynchronously preparing the - * model; will be: - * - NONE if the asynchronous preparation was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if there is an unspecified error - * - INVALID_ARGUMENT if the input model is invalid - */ - V1_0::ErrorStatus getStatus() const; - - /** - * Retrieves the model that has been prepared for execution from the - * asynchronous task launched by IDevice::prepareModel*. If - * IDevice::prepareModel* has not finished asynchronously preparing the - * model, this call will block until the asynchronous task notifies the - * object. - * - * @return preparedModel Returned model that has been prepared for - * execution, nullptr if the model was unable to be prepared. - */ - sp getPreparedModel() const; - - private: - mutable std::mutex mMutex; - mutable std::condition_variable mCondition; - bool mNotified GUARDED_BY(mMutex) = false; - V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; - sp mPreparedModel; -}; - -/** - * The ExecutionCallback class is used to receive the results of the execution - * from a task executing asynchronously with respect to the runtime. If a - * calling thread calls wait or get* on a ExecutionCallback object and the - * corresponding asynchronous task has not finished the execution, the calling - * thread will block until the asynchronous task has either called notify or - * notify_1_2. - * - * If the callback object is notified more than once, only the results of the - * first call to notify* are used, and the results from subsequent calls are - * discarded. - * - * This callback object is passed as an argument to IPreparedModel::execute*. - */ -class ExecutionCallback : public IExecutionCallback { - public: - /** - * IExecutionCallback::notify marks the callback object with the return - * status of the asynchronous execution that held this callback and enables - * all prior and future wait calls on the ExecutionCallback object to - * proceed. - * - * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must - * be called on a given ExecutionCallback object. - * - * If the callback object is notified more than once, only the results of - * the first call to notify* are used, and the results from subsequent calls - * are discarded. - * - * @param status Error status returned from launching the asynchronous task - * (if the launch fails) or from the asynchronous task itself (if the - * launch succeeds). Must be: - * - NONE if the asynchronous execution was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if there is an unspecified error - * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large - * enough to store the resultant values - * - INVALID_ARGUMENT if the input request is invalid - */ - Return notify(V1_0::ErrorStatus status) override; - - /** - * IExecutionCallback::notify_1_2 marks the callback object with the results - * (error status, dynamic output shapes, and timing information) of the - * asynchronous execution that held this callback and enables all prior and - * future wait calls on the ExecutionCallback object to proceed. - * - * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must - * be called on a given ExecutionCallback object. - * - * If the callback object is notified more than once, only the results of - * the first call to notify* are used, and the results from subsequent calls - * are discarded. - * - * @param status Error status returned from launching the asynchronous task - * (if the launch fails) or from the asynchronous task itself (if the - * launch succeeds). Must be: - * - NONE if the asynchronous execution was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified - * error - * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is - * not large enough to store the corresponding output - * - INVALID_ARGUMENT if one of the input arguments to prepareModel is - * invalid - * @param outputShapes A list of shape information of model output operands. - * The index into "outputShapes" corresponds to the index of the output - * operand in the Request outputs vector. outputShapes must be empty - * unless the status is either NONE or OUTPUT_INSUFFICIENT_SIZE. - * @param Timing Duration of execution. Unless MeasureTiming::YES was passed - * when launching the execution and status is NONE, all times must be - * reported as UINT64_MAX. A driver may choose to report any time as - * UINT64_MAX, indicating that particular measurement is not available. - */ - Return notify_1_2(V1_0::ErrorStatus status, const hidl_vec& outputShapes, - const Timing& timing) override; - - // An overload of the latest notify interface to hide the version from ExecutionBuilder. - Return notify(V1_0::ErrorStatus status, const hidl_vec& outputShapes, - const Timing& timing) { - return notify_1_2(status, outputShapes, timing); - } - - /** - * ExecutionCallback::wait blocks until notify* has been called on the - * callback object. - */ - void wait() const; - - /** - * Retrieves the error status returned from the asynchronous task launched - * by either IPreparedModel::execute or IPreparedModel::execute_1_2. If - * IPreparedModel::execute or IPreparedModel::execute_1_2 has not finished - * asynchronously executing, this call will block until the asynchronous - * task notifies the object. - * - * @return status Error status returned from launching the asynchronous task - * (if the launch fails) or from the asynchronous task itself (if the - * launch succeeds). Must be: - * - NONE if the asynchronous execution was successful - * - DEVICE_UNAVAILABLE if driver is offline or busy - * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified - * error - * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is - * not large enough to store the corresponding output - * - INVALID_ARGUMENT if one of the input arguments to prepareModel is - * invalid - */ - V1_0::ErrorStatus getStatus() const; - - /** - * Retrieves the output shapes returned from the asynchronous task launched - * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not - * finished asynchronously executing, this call will block until the - * asynchronous task notifies the object. - * - * If the asynchronous task was launched by IPreparedModel::execute, an - * empty vector will be returned. - * - * @return outputShapes A list of shape information of model output - * operands. The index into "outputShapes" corresponds to the index of - * the output operand in the Request outputs vector. outputShapes must - * be empty unless the status is either NONE or - * OUTPUT_INSUFFICIENT_SIZE. outputShaps may be empty if the status is - * NONE and all model output operands are fully-specified at execution - * time. outputShapes must have the same number of elements as the - * number of model output operands if the status is - * OUTPUT_INSUFFICIENT_SIZE, or if the status is NONE and the model has - * at least one output operand that is not fully-specified. - */ - const std::vector& getOutputShapes() const; - - /** - * Retrieves the duration of execution of the asynchronous task launched by - * IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not - * finished asynchronously executing, this call will block until the - * asynchronous task notifies the object. - * - * If the asynchronous task was launched by IPreparedModel::execute, every - * time must be UINT64_MAX. - * - * @return timing Duration of the execution. Every time must be UINT64_MAX - * unless the status is NONE. - */ - Timing getTiming() const; - - private: - /* - * ExecutionCallback::notifyInternal stores the results of the execution - * (status, output shapes, and timing information) in the ExecutionCallback - * object before any call to wait or get* return. It then enables all prior - * and future wait calls on the ExecutionCallback object to proceed. - */ - void notifyInternal(V1_0::ErrorStatus errorStatus, const hidl_vec& outputShapes, - const Timing& timing); - - // members - mutable std::mutex mMutex; - mutable std::condition_variable mCondition; - bool mNotified GUARDED_BY(mMutex) = false; - V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; - std::vector mOutputShapes = {}; - Timing mTiming = {}; -}; - -} // namespace android::hardware::neuralnetworks::V1_2::implementation - -#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H From e93fdf9a4a8b42133882e59adece8a8fe6086a0b Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Tue, 24 Sep 2019 11:58:51 -0700 Subject: [PATCH 0169/1022] MH2 | Implement dynamic sensors callbacks on HalProxy Additionally, have HalProxyCallback::processEvents use HalProxy::setSubHalIndex static method instead of its own helper. Add unit tests to test the dynamic sensor methods. Bug: 136511617 Test: New unit tests are passing. Change-Id: Ib903291a83df2fafa480082f9305c594bd325f79 --- sensors/2.0/multihal/HalProxy.cpp | 64 +++++++-- sensors/2.0/multihal/include/HalProxy.h | 15 +- sensors/2.0/multihal/tests/HalProxy_test.cpp | 135 ++++++++++++++++++ .../tests/fake_subhal/SensorsSubHal.cpp | 10 ++ .../tests/fake_subhal/SensorsSubHal.h | 20 ++- 5 files changed, 224 insertions(+), 20 deletions(-) diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index 1fbc787157..5aa3b3d22b 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -38,6 +38,18 @@ using ::android::hardware::sensors::V2_0::EventQueueFlagBits; typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*); +/** + * Set the subhal index as first byte of sensor handle and return this modified version. + * + * @param sensorHandle The sensor handle to modify. + * @param subHalIndex The index in the hal proxy of the sub hal this sensor belongs to. + * + * @return The modified sensor handle. + */ +uint32_t setSubHalIndex(uint32_t sensorHandle, size_t subHalIndex) { + return sensorHandle | (subHalIndex << 24); +} + HalProxy::HalProxy() { const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf"; initializeSubHalListFromConfigFile(kMultiHalConfigFile); @@ -206,15 +218,45 @@ Return HalProxy::debug(const hidl_handle& /* fd */, const hidl_vec(); } -Return HalProxy::onDynamicSensorsConnected( - const hidl_vec& /* dynamicSensorsAdded */, int32_t /* subHalIndex */) { - // TODO: Map the SensorInfo to the global list and then invoke the framework's callback. +Return HalProxy::onDynamicSensorsConnected(const hidl_vec& dynamicSensorsAdded, + int32_t subHalIndex) { + std::vector sensors; + { + std::lock_guard lock(mDynamicSensorsMutex); + for (SensorInfo sensor : dynamicSensorsAdded) { + if (!subHalIndexIsClear(sensor.sensorHandle)) { + ALOGE("Dynamic sensor added %s had sensorHandle with first byte not 0.", + sensor.name.c_str()); + } else { + sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex); + mDynamicSensors[sensor.sensorHandle] = sensor; + sensors.push_back(sensor); + } + } + } + mDynamicSensorsCallback->onDynamicSensorsConnected(sensors); return Return(); } Return HalProxy::onDynamicSensorsDisconnected( - const hidl_vec& /* dynamicSensorHandlesRemoved */, int32_t /* subHalIndex */) { - // TODO: Unmap the SensorInfo from the global list and then invoke the framework's callback. + const hidl_vec& dynamicSensorHandlesRemoved, int32_t subHalIndex) { + // TODO: Block this call until all pending events are flushed from queue + std::vector sensorHandles; + { + std::lock_guard lock(mDynamicSensorsMutex); + for (int32_t sensorHandle : dynamicSensorHandlesRemoved) { + if (!subHalIndexIsClear(sensorHandle)) { + ALOGE("Dynamic sensorHandle removed had first byte not 0."); + } else { + sensorHandle = setSubHalIndex(sensorHandle, subHalIndex); + if (mDynamicSensors.find(sensorHandle) != mDynamicSensors.end()) { + mDynamicSensors.erase(sensorHandle); + sensorHandles.push_back(sensorHandle); + } + } + } + } + mDynamicSensorsCallback->onDynamicSensorsDisconnected(sensorHandles); return Return(); } @@ -264,7 +306,7 @@ void HalProxy::initializeSensorList() { ISensorsSubHal* subHal = mSubHalList[subHalIndex]; auto result = subHal->getSensorsList([&](const auto& list) { for (SensorInfo sensor : list) { - if ((sensor.sensorHandle & kSensorHandleSubHalIndexMask) != 0) { + if (!subHalIndexIsClear(sensor.sensorHandle)) { ALOGE("SubHal sensorHandle's first byte was not 0"); } else { ALOGV("Loaded sensor: %s", sensor.name.c_str()); @@ -389,6 +431,10 @@ uint32_t HalProxy::clearSubHalIndex(uint32_t sensorHandle) { return sensorHandle & (~kSensorHandleSubHalIndexMask); } +bool HalProxy::subHalIndexIsClear(uint32_t sensorHandle) { + return (sensorHandle & kSensorHandleSubHalIndexMask) == 0; +} + void HalProxyCallback::postEvents(const std::vector& events, ScopedWakelock wakelock) { (void)wakelock; size_t numWakeupEvents; @@ -418,7 +464,7 @@ std::vector HalProxyCallback::processEvents(const std::vector& eve std::vector eventsOut; *numWakeupEvents = 0; for (Event event : events) { - event.sensorHandle = setSubHalIndex(event.sensorHandle); + event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex); eventsOut.push_back(event); if ((mHalProxy->getSensorInfo(event.sensorHandle).flags & V1_0::SensorFlagBits::WAKE_UP) != 0) { @@ -428,10 +474,6 @@ std::vector HalProxyCallback::processEvents(const std::vector& eve return eventsOut; } -uint32_t HalProxyCallback::setSubHalIndex(uint32_t sensorHandle) const { - return sensorHandle | mSubHalIndex << 24; -} - } // namespace implementation } // namespace V2_0 } // namespace sensors diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h index ae4b2c53c6..47571a6368 100644 --- a/sensors/2.0/multihal/include/HalProxy.h +++ b/sensors/2.0/multihal/include/HalProxy.h @@ -176,6 +176,9 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { */ std::map mSensors; + //! Map of the dynamic sensors that have been added to halproxy. + std::map mDynamicSensors; + //! The current operation mode for all subhals. OperationMode mCurrentOperationMode = OperationMode::NORMAL; @@ -212,6 +215,9 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { //! The bool indicating whether to end the pending writes background thread or not bool mPendingWritesRun = true; + //! The mutex protecting access to the dynamic sensors added and removed methods. + std::mutex mDynamicSensorsMutex; + /** * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries * listed in a config file. @@ -271,6 +277,13 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { * @return The modified version of the sensor handle. */ static uint32_t clearSubHalIndex(uint32_t sensorHandle); + + /** + * @param sensorHandle The sensor handle to modify. + * + * @return true if subHalIndex byte of sensorHandle is zeroed. + */ + static bool subHalIndexIsClear(uint32_t sensorHandle); }; /** @@ -303,8 +316,6 @@ class HalProxyCallback : public IHalProxyCallback { std::vector processEvents(const std::vector& events, size_t* numWakeupEvents) const; - - uint32_t setSubHalIndex(uint32_t sensorHandle) const; }; } // namespace implementation diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp index 61fb14c38f..c8fbb730f6 100644 --- a/sensors/2.0/multihal/tests/HalProxy_test.cpp +++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp @@ -23,6 +23,7 @@ #include "SensorsSubHal.h" #include +#include #include #include @@ -38,6 +39,7 @@ using ::android::hardware::sensors::V1_0::SensorType; using ::android::hardware::sensors::V2_0::ISensorsCallback; using ::android::hardware::sensors::V2_0::implementation::HalProxy; using ::android::hardware::sensors::V2_0::implementation::HalProxyCallback; +using ::android::hardware::sensors::V2_0::subhal::implementation::AddAndRemoveDynamicSensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation:: AllSupportDirectChannelSensorsSubHal; @@ -68,6 +70,34 @@ class SensorsCallback : public ISensorsCallback { } }; +// The sensors callback that expects a variable list of sensors to be added +class TestSensorsCallback : public ISensorsCallback { + public: + Return onDynamicSensorsConnected( + const hidl_vec& dynamicSensorsAdded) override { + mSensorsConnected.insert(mSensorsConnected.end(), dynamicSensorsAdded.begin(), + dynamicSensorsAdded.end()); + return Return(); + } + + Return onDynamicSensorsDisconnected( + const hidl_vec& dynamicSensorHandlesRemoved) override { + mSensorHandlesDisconnected.insert(mSensorHandlesDisconnected.end(), + dynamicSensorHandlesRemoved.begin(), + dynamicSensorHandlesRemoved.end()); + return Return(); + } + + const std::vector& getSensorsConnected() const { return mSensorsConnected; } + const std::vector& getSensorHandlesDisconnected() const { + return mSensorHandlesDisconnected; + } + + private: + std::vector mSensorsConnected; + std::vector mSensorHandlesDisconnected; +}; + // Helper declarations follow /** @@ -129,6 +159,20 @@ std::vector makeMultipleProximityEvents(size_t numEvents); */ std::vector makeMultipleAccelerometerEvents(size_t numEvents); +/** + * Given a SensorInfo vector and a sensor handles vector populate 'sensors' with SensorInfo + * objects that have the sensorHandle property set to int32_ts from start to start + size + * (exclusive) and push those sensorHandles also onto 'sensorHandles'. + * + * @param start The starting sensorHandle value. + * @param size The ending (not included) sensorHandle value. + * @param sensors The SensorInfo object vector reference to push_back to. + * @param sensorHandles The sensor handles int32_t vector reference to push_back to. + */ +void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size, + std::vector& sensors, + std::vector& sensorHandles); + // Tests follow TEST(HalProxyTest, GetSensorsListOneSubHalTest) { AllSensorsSubHal subHal; @@ -396,6 +440,83 @@ TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThreadTest) { // If this TEST completes then it was a success, if it hangs we will see a crash } +TEST(HalProxyTest, DynamicSensorsConnectedTest) { + constexpr size_t kNumSensors = 3; + AddAndRemoveDynamicSensorsSubHal subHal; + std::vector subHals{&subHal}; + HalProxy proxy(subHals); + std::unique_ptr eventQueue = std::make_unique(0, true); + std::unique_ptr wakeLockQueue = + std::make_unique(0, true); + + std::vector sensorsToConnect; + std::vector sensorHandlesToExpect; + makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect, + sensorHandlesToExpect); + + TestSensorsCallback* callback = new TestSensorsCallback(); + ::android::sp callbackPtr = callback; + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); + subHal.addDynamicSensors(sensorsToConnect); + + std::vector sensorsSeen = callback->getSensorsConnected(); + EXPECT_EQ(kNumSensors, sensorsSeen.size()); + for (size_t i = 0; i < kNumSensors; i++) { + auto sensorHandleSeen = sensorsSeen[i].sensorHandle; + // Note since only one subhal we do not need to change first byte for expected + auto sensorHandleExpected = sensorHandlesToExpect[i]; + EXPECT_EQ(sensorHandleSeen, sensorHandleExpected); + } +} + +TEST(HalProxyTest, DynamicSensorsDisconnectedTest) { + constexpr size_t kNumSensors = 3; + AddAndRemoveDynamicSensorsSubHal subHal; + std::vector subHals{&subHal}; + HalProxy proxy(subHals); + std::unique_ptr eventQueue = std::make_unique(0, true); + std::unique_ptr wakeLockQueue = + std::make_unique(0, true); + + std::vector sensorsToConnect; + std::vector sensorHandlesToExpect; + makeSensorsAndSensorHandlesStartingAndOfSize(20, kNumSensors, sensorsToConnect, + sensorHandlesToExpect); + + std::vector nonDynamicSensorHandles; + for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) { + nonDynamicSensorHandles.push_back(sensorHandle); + } + + std::set nonDynamicSensorHandlesSet(nonDynamicSensorHandles.begin(), + nonDynamicSensorHandles.end()); + + std::vector sensorHandlesToAttemptToRemove; + sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(), + sensorHandlesToExpect.begin(), + sensorHandlesToExpect.end()); + sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(), + nonDynamicSensorHandles.begin(), + nonDynamicSensorHandles.end()); + + TestSensorsCallback* callback = new TestSensorsCallback(); + ::android::sp callbackPtr = callback; + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); + subHal.addDynamicSensors(sensorsToConnect); + subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove); + + std::vector sensorHandlesSeen = callback->getSensorHandlesDisconnected(); + EXPECT_EQ(kNumSensors, sensorHandlesSeen.size()); + for (size_t i = 0; i < kNumSensors; i++) { + auto sensorHandleSeen = sensorHandlesSeen[i]; + // Note since only one subhal we do not need to change first byte for expected + auto sensorHandleExpected = sensorHandlesToExpect[i]; + EXPECT_EQ(sensorHandleSeen, sensorHandleExpected); + EXPECT_TRUE(nonDynamicSensorHandlesSet.find(sensorHandleSeen) == + nonDynamicSensorHandlesSet.end()); + } +} + // Helper implementations follow void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, const std::vector& subHalSensorsList) { @@ -463,4 +584,18 @@ std::vector makeMultipleAccelerometerEvents(size_t numEvents) { return events; } +void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size, + std::vector& sensors, + std::vector& sensorHandles) { + for (int32_t sensorHandle = start; sensorHandle < start + static_cast(size); + sensorHandle++) { + SensorInfo sensor; + // Just set the sensorHandle field to the correct value so as to not have + // to compare every field + sensor.sensorHandle = sensorHandle; + sensors.push_back(sensor); + sensorHandles.push_back(sensorHandle); + } +} + } // namespace diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp index d581c49a32..cf3ae7560d 100644 --- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp +++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp @@ -221,6 +221,16 @@ Return DoesNotSupportDirectChannelSensorsSubHal::getSensorsList(getSensors return Void(); } +void AddAndRemoveDynamicSensorsSubHal::addDynamicSensors( + const std::vector& sensorsAdded) { + mCallback->onDynamicSensorsConnected(sensorsAdded); +} + +void AddAndRemoveDynamicSensorsSubHal::removeDynamicSensors( + const std::vector& sensorHandlesRemoved) { + mCallback->onDynamicSensorsDisconnected(sensorHandlesRemoved); +} + } // namespace implementation } // namespace subhal } // namespace V2_0 diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h index 61caa2c39e..c1e36472cf 100644 --- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h +++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h @@ -98,13 +98,6 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { */ std::map> mSensors; - private: - /** - * The current operation mode of the multihal framework. Ensures that all subhals are set to - * the same operation mode. - */ - OperationMode mCurrentOperationMode = OperationMode::NORMAL; - /** * Callback used to communicate to the HalProxy when dynamic sensors are connected / * disconnected, sensor events need to be sent to the framework, and when a wakelock should be @@ -112,6 +105,13 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { */ sp mCallback; + private: + /** + * The current operation mode of the multihal framework. Ensures that all subhals are set to + * the same operation mode. + */ + OperationMode mCurrentOperationMode = OperationMode::NORMAL; + /** * The next available sensor handle */ @@ -151,6 +151,12 @@ class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { Return getSensorsList(getSensorsList_cb _hidl_cb) override; }; +class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal { + public: + void addDynamicSensors(const std::vector& sensorsAdded); + void removeDynamicSensors(const std::vector& sensorHandlesAdded); +}; + } // namespace implementation } // namespace subhal } // namespace V2_0 From eabbe5d1bb35980d2075788633ac4a8bda2e47a7 Mon Sep 17 00:00:00 2001 From: "Harpreet \\\"Eli\\\" Sangha" Date: Fri, 27 Sep 2019 19:00:46 +0900 Subject: [PATCH 0170/1022] vibrator: Limit Length of Async Callback Tests Don't wait for callbacks for long effects, as determined by a command-line option. Bug: 136220871 Test: VTS Tests Change-Id: Ibaf3072a38b32b159d7b48a40860a25928c5d6f1 Signed-off-by: Harpreet \"Eli\" Sangha --- .../VtsHalVibratorV1_4TargetTest.cpp | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp b/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp index b51cc96942..1b6abe9e52 100644 --- a/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp +++ b/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp @@ -22,6 +22,8 @@ #include #include #include + +#include #include #include @@ -38,6 +40,8 @@ using ::android::hardware::vibrator::V1_4::Capabilities; using ::android::hardware::vibrator::V1_4::IVibrator; using ::android::hardware::vibrator::V1_4::IVibratorCallback; +static uint32_t sCompletionLimitMs = UINT32_MAX; + #define EXPECT_OK(ret) ASSERT_TRUE((ret).isOk()) class CompletionCallback : public IVibratorCallback { @@ -115,7 +119,7 @@ TEST_P(VibratorHidlTest_1_4, PerformEffect_1_4) { sp callback = new CompletionCallback([&completionPromise] { completionPromise.set_value(); }); EXPECT_OK(vibrator->perform_1_4(effect, strength, callback, validateWrapper)); - if (performStatus == Status::OK && + if (performStatus == Status::OK && performLength < sCompletionLimitMs && (capabilities & Capabilities::PERFORM_COMPLETION_CALLBACK)) { std::chrono::milliseconds timeout{performLength * 2}; EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready); @@ -168,3 +172,32 @@ INSTANTIATE_TEST_SUITE_P( PerInstance, VibratorHidlTest_1_4, testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVibrator::descriptor)), android::hardware::PrintInstanceNameToString); + +enum { + OPTION_COMPLETION_LIMIT_MS, +}; + +int main(int argc, char** argv) { + struct option options[] = { + {"completion-limit-ms", required_argument, 0, OPTION_COMPLETION_LIMIT_MS}, {}}; + + printf("Running main() from %s\n", __FILE__); + testing::InitGoogleTest(&argc, argv); + + while (true) { + int opt = getopt_long(argc, argv, "", options, nullptr); + if (opt == -1) { + break; + } + switch (opt) { + case OPTION_COMPLETION_LIMIT_MS: + std::istringstream(optarg) >> sCompletionLimitMs; + break; + default: + printf("Unrecognized option\n"); + return -EINVAL; + } + } + + return RUN_ALL_TESTS(); +} From 79125020539458a027fb50bb9af086c9530dca34 Mon Sep 17 00:00:00 2001 From: Amy Date: Thu, 10 Oct 2019 15:30:17 -0700 Subject: [PATCH 0171/1022] Adding filter status tracking logic into Demux default impl Test: manual Bug: 135709325 Change-Id: I2d473c250dc4d87263d5e7004095d144da684223 --- tv/tuner/1.0/default/Demux.cpp | 65 +++++++++++++++++++++++++++------- tv/tuner/1.0/default/Demux.h | 13 +++++-- 2 files changed, 63 insertions(+), 15 deletions(-) diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp index d65df594a6..b998468d26 100644 --- a/tv/tuner/1.0/default/Demux.cpp +++ b/tv/tuner/1.0/default/Demux.cpp @@ -106,7 +106,7 @@ Return Demux::addFilter(DemuxFilterType type, uint32_t bufferSize, } else { filterId = ++mLastUsedFilterId; - mDemuxCallbacks.resize(filterId + 1); + mFilterCallbacks.resize(filterId + 1); mFilterMQs.resize(filterId + 1); mFilterEvents.resize(filterId + 1); mFilterEventFlags.resize(filterId + 1); @@ -114,6 +114,7 @@ Return Demux::addFilter(DemuxFilterType type, uint32_t bufferSize, mFilterThreads.resize(filterId + 1); mFilterPids.resize(filterId + 1); mFilterOutputs.resize(filterId + 1); + mFilterStatus.resize(filterId + 1); } mUsedFilterIds.insert(filterId); @@ -125,7 +126,7 @@ Return Demux::addFilter(DemuxFilterType type, uint32_t bufferSize, } // Add callback - mDemuxCallbacks[filterId] = cb; + mFilterCallbacks[filterId] = cb; // Mapping from the filter ID to the filter event DemuxFilterEvent event{ @@ -211,9 +212,16 @@ Return Demux::stopFilter(uint32_t filterId) { return Result::SUCCESS; } -Return Demux::flushFilter(uint32_t /* filterId */) { +Return Demux::flushFilter(uint32_t filterId) { ALOGV("%s", __FUNCTION__); + // temp implementation to flush the FMQ + int size = mFilterMQs[filterId]->availableToRead(); + char* buffer = new char[size]; + mOutputMQ->read((unsigned char*)&buffer[0], size); + delete[] buffer; + mFilterStatus[filterId] = DemuxFilterStatus::DATA_READY; + return Result::SUCCESS; } @@ -254,7 +262,7 @@ Return Demux::close() { mFilterThreads.clear(); mUnusedFilterIds.clear(); mUsedFilterIds.clear(); - mDemuxCallbacks.clear(); + mFilterCallbacks.clear(); mFilterMQs.clear(); mFilterEvents.clear(); mFilterEventFlags.clear(); @@ -475,6 +483,7 @@ Result Demux::startPesFilterHandler(uint32_t filterId) { mFilterOutputs[filterId].clear(); return Result::INVALID_STATE; } + maySendFilterStatusCallback(filterId); pesEvent = { // temp dump meta data .streamId = filterOutData[3], @@ -672,8 +681,10 @@ void Demux::filterThreadLoop(uint32_t filterId) { continue; } // After successfully write, send a callback and wait for the read to be done - mDemuxCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]); + mFilterCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]); mFilterEvents[filterId].events.resize(0); + mFilterStatus[filterId] = DemuxFilterStatus::DATA_READY; + mFilterCallbacks[filterId]->onFilterStatus(filterId, mFilterStatus[filterId]); break; } @@ -693,18 +704,20 @@ void Demux::filterThreadLoop(uint32_t filterId) { break; } - if (mDemuxCallbacks[filterId] == nullptr) { + if (mFilterCallbacks[filterId] == nullptr) { ALOGD("[Demux] filter %d does not hava callback. Ending thread", filterId); break; } + maySendFilterStatusCallback(filterId); + while (mFilterThreadRunning[filterId]) { std::lock_guard lock(mFilterEventLock); if (mFilterEvents[filterId].events.size() == 0) { continue; } // After successfully write, send a callback and wait for the read to be done - mDemuxCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]); + mFilterCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]); mFilterEvents[filterId].events.resize(0); break; } @@ -755,16 +768,31 @@ void Demux::maySendInputStatusCallback() { int availableToWrite = mInputMQ->availableToWrite(); DemuxInputStatus newStatus = - checkStatusChange(availableToWrite, availableToRead, mInputSettings.highThreshold, - mInputSettings.lowThreshold); + checkInputStatusChange(availableToWrite, availableToRead, mInputSettings.highThreshold, + mInputSettings.lowThreshold); if (mIntputStatus != newStatus) { mInputCallback->onInputStatus(newStatus); mIntputStatus = newStatus; } } -DemuxInputStatus Demux::checkStatusChange(uint32_t availableToWrite, uint32_t availableToRead, - uint32_t highThreshold, uint32_t lowThreshold) { +void Demux::maySendFilterStatusCallback(uint32_t filterId) { + std::lock_guard lock(mFilterStatusLock); + int availableToRead = mFilterMQs[filterId]->availableToRead(); + int availableToWrite = mInputMQ->availableToWrite(); + int fmqSize = mFilterMQs[filterId]->getQuantumCount(); + + DemuxFilterStatus newStatus = + checkFilterStatusChange(filterId, availableToWrite, availableToRead, + ceil(fmqSize * 0.75), ceil(fmqSize * 0.25)); + if (mFilterStatus[filterId] != newStatus) { + mFilterCallbacks[filterId]->onFilterStatus(filterId, newStatus); + mFilterStatus[filterId] = newStatus; + } +} + +DemuxInputStatus Demux::checkInputStatusChange(uint32_t availableToWrite, uint32_t availableToRead, + uint32_t highThreshold, uint32_t lowThreshold) { if (availableToWrite == 0) { return DemuxInputStatus::SPACE_FULL; } else if (availableToRead > highThreshold) { @@ -777,6 +805,19 @@ DemuxInputStatus Demux::checkStatusChange(uint32_t availableToWrite, uint32_t av return mIntputStatus; } +DemuxFilterStatus Demux::checkFilterStatusChange(uint32_t filterId, uint32_t availableToWrite, + uint32_t availableToRead, uint32_t highThreshold, + uint32_t lowThreshold) { + if (availableToWrite == 0) { + return DemuxFilterStatus::OVERFLOW; + } else if (availableToRead > highThreshold) { + return DemuxFilterStatus::HIGH_WATER; + } else if (availableToRead < lowThreshold) { + return DemuxFilterStatus::LOW_WATER; + } + return mFilterStatus[filterId]; +} + Result Demux::startBroadcastInputLoop() { pthread_create(&mBroadcastInputThread, NULL, __threadLoopBroadcast, this); pthread_setname_np(mBroadcastInputThread, "broadcast_input_thread"); @@ -818,7 +859,7 @@ void Demux::broadcastInputThreadLoop() { } // filter and dispatch filter output vector byteBuffer; - byteBuffer.resize(sizeof(buffer)); + byteBuffer.resize(packetSize); for (int index = 0; index < byteBuffer.size(); index++) { byteBuffer[index] = static_cast(buffer[index]); } diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h index e4a4e2bdae..5a89e92eeb 100644 --- a/tv/tuner/1.0/default/Demux.h +++ b/tv/tuner/1.0/default/Demux.h @@ -19,6 +19,7 @@ #include #include +#include #include #include "Frontend.h" #include "Tuner.h" @@ -153,8 +154,12 @@ class Demux : public IDemux { bool readDataFromMQ(); bool writeSectionsAndCreateEvent(uint32_t filterId, vector data); void maySendInputStatusCallback(); - DemuxInputStatus checkStatusChange(uint32_t availableToWrite, uint32_t availableToRead, - uint32_t highThreshold, uint32_t lowThreshold); + void maySendFilterStatusCallback(uint32_t filterId); + DemuxInputStatus checkInputStatusChange(uint32_t availableToWrite, uint32_t availableToRead, + uint32_t highThreshold, uint32_t lowThreshold); + DemuxFilterStatus checkFilterStatusChange(uint32_t filterId, uint32_t availableToWrite, + uint32_t availableToRead, uint32_t highThreshold, + uint32_t lowThreshold); /** * A dispatcher to read and dispatch input data to all the started filters. * Each filter handler handles the data filtering/output writing/filterEvent updating. @@ -203,7 +208,7 @@ class Demux : public IDemux { /** * Demux callbacks used on filter events or IO buffer status */ - vector> mDemuxCallbacks; + vector> mFilterCallbacks; sp mInputCallback; sp mOutputCallback; bool mInputConfigured = false; @@ -219,6 +224,7 @@ class Demux : public IDemux { // FMQ status local records DemuxInputStatus mIntputStatus; + vector mFilterStatus; /** * If a specific filter's writing loop is still running */ @@ -239,6 +245,7 @@ class Demux : public IDemux { * Lock to protect writes to the input status */ std::mutex mInputStatusLock; + std::mutex mFilterStatusLock; std::mutex mBroadcastInputThreadLock; std::mutex mFilterThreadLock; std::mutex mInputThreadLock; From 1109e9fee22d5c24e6004f8a9d249f505856237e Mon Sep 17 00:00:00 2001 From: Amy Date: Thu, 10 Oct 2019 18:30:28 -0700 Subject: [PATCH 0172/1022] Adding PES filter functionality to assemble PES data Test: manual Bug: 135709325 Change-Id: I9bbbae88918004201e6d7d5389473b4fd3a0a969 --- tv/tuner/1.0/default/Demux.cpp | 61 +++++++++++++++++++++++----------- tv/tuner/1.0/default/Demux.h | 5 +++ 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp index b998468d26..b18d4df9e6 100644 --- a/tv/tuner/1.0/default/Demux.cpp +++ b/tv/tuner/1.0/default/Demux.cpp @@ -466,33 +466,54 @@ Result Demux::startSectionFilterHandler(uint32_t filterId) { Result Demux::startPesFilterHandler(uint32_t filterId) { std::lock_guard lock(mFilterEventLock); - DemuxFilterPesEvent pesEvent; if (mFilterOutputs[filterId].empty()) { return Result::SUCCESS; } for (int i = 0; i < mFilterOutputs[filterId].size(); i += 188) { - uint8_t pusi = mFilterOutputs[filterId][i + 1] & 0x40; - uint8_t adaptFieldControl = (mFilterOutputs[filterId][i + 3] & 0x30) >> 4; - ALOGD("[Demux] pusi %d, adaptFieldControl %d", pusi, adaptFieldControl); - if (pusi && (adaptFieldControl == 0x01)) { - vector::const_iterator first = mFilterOutputs[filterId].begin() + i + 4; - vector::const_iterator last = mFilterOutputs[filterId].begin() + i + 187; - vector filterOutData(first, last); - if (!writeDataToFilterMQ(filterOutData, filterId)) { - mFilterOutputs[filterId].clear(); - return Result::INVALID_STATE; + if (mPesSizeLeft == 0) { + uint32_t prefix = (mFilterOutputs[filterId][i + 4] << 16) | + (mFilterOutputs[filterId][i + 5] << 8) | + mFilterOutputs[filterId][i + 6]; + ALOGD("[Demux] prefix %d", prefix); + if (prefix == 0x000001) { + // TODO handle mulptiple Pes filters + mPesSizeLeft = + (mFilterOutputs[filterId][i + 7] << 8) | mFilterOutputs[filterId][i + 8]; + ALOGD("[Demux] pes data length %d", mPesSizeLeft); + } else { + continue; } - maySendFilterStatusCallback(filterId); - pesEvent = { - // temp dump meta data - .streamId = filterOutData[3], - .dataLength = static_cast(filterOutData.size()), - }; - int size = mFilterEvents[filterId].events.size(); - mFilterEvents[filterId].events.resize(size + 1); - mFilterEvents[filterId].events[size].pes(pesEvent); } + + int endPoint = min(184, mPesSizeLeft); + // append data and check size + vector::const_iterator first = mFilterOutputs[filterId].begin() + i + 4; + vector::const_iterator last = mFilterOutputs[filterId].begin() + i + 3 + endPoint; + mPesOutput.insert(mPesOutput.end(), first, last); + // size does not match then continue + mPesSizeLeft -= endPoint; + if (mPesSizeLeft > 0) { + continue; + } + // size match then create event + if (!writeDataToFilterMQ(mPesOutput, filterId)) { + mFilterOutputs[filterId].clear(); + return Result::INVALID_STATE; + } + maySendFilterStatusCallback(filterId); + DemuxFilterPesEvent pesEvent; + pesEvent = { + // temp dump meta data + .streamId = mPesOutput[3], + .dataLength = static_cast(mPesOutput.size()), + }; + ALOGD("[Demux] assembled pes data length %d", pesEvent.dataLength); + + int size = mFilterEvents[filterId].events.size(); + mFilterEvents[filterId].events.resize(size + 1); + mFilterEvents[filterId].events[size].pes(pesEvent); + mPesOutput.clear(); } mFilterOutputs[filterId].clear(); diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h index 5a89e92eeb..ba0b9b099a 100644 --- a/tv/tuner/1.0/default/Demux.h +++ b/tv/tuner/1.0/default/Demux.h @@ -254,6 +254,11 @@ class Demux : public IDemux { * TODO make this dynamic/random/can take as a parameter */ const uint16_t SECTION_WRITE_COUNT = 10; + + // temp handle single PES filter + // TODO handle mulptiple Pes filters + int mPesSizeLeft = 0; + vector mPesOutput; }; } // namespace implementation From b003105ef9e9782b2745fe78b5ccb417ee8921d5 Mon Sep 17 00:00:00 2001 From: "Harpreet \\\"Eli\\\" Sangha" Date: Fri, 11 Oct 2019 09:55:16 +0900 Subject: [PATCH 0173/1022] Add Vibrator 1.4 Hashes to current.txt Test: Build Change-Id: I3cf9bcca7e6aab7125b7666c82ac493ee44eec8c Signed-off-by: Harpreet \"Eli\" Sangha --- current.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/current.txt b/current.txt index 87498a10d7..4e0d0e0bab 100644 --- a/current.txt +++ b/current.txt @@ -595,3 +595,6 @@ dd4b7cfbb6e1c6ff011c33920762ad89dd02240c63a4d3a3d5037f154eae3e3b android.hardwar 619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback 6fe09b18e913608579638594788198ec45bb2369e567d7df661db46c4f0e5f08 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 91931b05bd70ea6bdffbe075086183f803379571788564e28854207620eb75cf android.hardware.wifi.supplicant@1.3::types +033eae03c09ebc75e82db37bc39995dfaa9086745577b44d9e14e9ccb48bd8cc android.hardware.vibrator@1.4::types +544049dcda3f943ad67d83d5277f06681a3782982a9af5a78b5d4e8d295d061a android.hardware.vibrator@1.4::IVibrator +5e1c12efbbba89c9143d10b1b90eceff8bc79aa079f5106215b528e104fef101 android.hardware.vibrator@1.4::IVibratorCallback From 95ac05d731e04cae4dbc3fb77f79ef89771999f1 Mon Sep 17 00:00:00 2001 From: "Harpreet \\\"Eli\\\" Sangha" Date: Fri, 27 Sep 2019 19:01:25 +0900 Subject: [PATCH 0174/1022] vibrator: Async Callback API Example Bug: 136220871 Test: VTS Tests Change-Id: I338f16d72cd7b1ba60ddf812e4cb87a6011de752 Signed-off-by: Harpreet \"Eli\" Sangha --- ...d.hardware.vibrator@1.3-service.example.rc | 4 --- vibrator/{1.3 => 1.x}/example/Android.bp | 7 ++-- vibrator/{1.3 => 1.x}/example/OWNERS | 0 vibrator/{1.3 => 1.x}/example/Vibrator.cpp | 32 +++++++++++++++++-- vibrator/{1.3 => 1.x}/example/Vibrator.h | 23 +++++++++---- ...d.hardware.vibrator@1.x-service.example.rc | 4 +++ ...hardware.vibrator@1.x-service.example.xml} | 2 +- vibrator/{1.3 => 1.x}/example/service.cpp | 8 ++--- 8 files changed, 58 insertions(+), 22 deletions(-) delete mode 100644 vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.rc rename vibrator/{1.3 => 1.x}/example/Android.bp (81%) rename vibrator/{1.3 => 1.x}/example/OWNERS (100%) rename vibrator/{1.3 => 1.x}/example/Vibrator.cpp (86%) rename vibrator/{1.3 => 1.x}/example/Vibrator.h (75%) create mode 100644 vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.rc rename vibrator/{1.3/example/android.hardware.vibrator@1.3-service.example.xml => 1.x/example/android.hardware.vibrator@1.x-service.example.xml} (90%) rename vibrator/{1.3 => 1.x}/example/service.cpp (82%) diff --git a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.rc b/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.rc deleted file mode 100644 index ed7a562cfc..0000000000 --- a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.rc +++ /dev/null @@ -1,4 +0,0 @@ -service vendor.vibrator-1-3 /vendor/bin/hw/android.hardware.vibrator@1.3-service.example - class hal - user system - group system diff --git a/vibrator/1.3/example/Android.bp b/vibrator/1.x/example/Android.bp similarity index 81% rename from vibrator/1.3/example/Android.bp rename to vibrator/1.x/example/Android.bp index 07f1c26db3..afbbb759ac 100644 --- a/vibrator/1.3/example/Android.bp +++ b/vibrator/1.x/example/Android.bp @@ -14,11 +14,11 @@ // limitations under the License. cc_binary { - name: "android.hardware.vibrator@1.3-service.example", + name: "android.hardware.vibrator@1.x-service.example", vendor: true, relative_install_path: "hw", - init_rc: ["android.hardware.vibrator@1.3-service.example.rc"], - vintf_fragments: ["android.hardware.vibrator@1.3-service.example.xml"], + init_rc: ["android.hardware.vibrator@1.x-service.example.rc"], + vintf_fragments: ["android.hardware.vibrator@1.x-service.example.xml"], srcs: ["service.cpp", "Vibrator.cpp"], cflags: ["-Wall", "-Werror"], shared_libs: [ @@ -29,5 +29,6 @@ cc_binary { "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.2", "android.hardware.vibrator@1.3", + "android.hardware.vibrator@1.4", ], } diff --git a/vibrator/1.3/example/OWNERS b/vibrator/1.x/example/OWNERS similarity index 100% rename from vibrator/1.3/example/OWNERS rename to vibrator/1.x/example/OWNERS diff --git a/vibrator/1.3/example/Vibrator.cpp b/vibrator/1.x/example/Vibrator.cpp similarity index 86% rename from vibrator/1.3/example/Vibrator.cpp rename to vibrator/1.x/example/Vibrator.cpp index b529437108..4dd1cb90b6 100644 --- a/vibrator/1.3/example/Vibrator.cpp +++ b/vibrator/1.x/example/Vibrator.cpp @@ -23,7 +23,7 @@ namespace android { namespace hardware { namespace vibrator { -namespace V1_3 { +namespace V1_4 { namespace implementation { static constexpr uint32_t MS_PER_S = 1000; @@ -100,7 +100,25 @@ Return Vibrator::setExternalControl(bool enabled) { } } -Return Vibrator::perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) { +Return Vibrator::perform_1_3(V1_3::Effect effect, EffectStrength strength, + perform_cb _hidl_cb) { + return perform(effect, strength, _hidl_cb); +} + +// Methods from ::android::hardware::vibrator::V1_4::IVibrator follow. + +Return> Vibrator::getCapabilities() { + return Capabilities::ON_COMPLETION_CALLBACK | Capabilities::PERFORM_COMPLETION_CALLBACK; +} + +Return Vibrator::on_1_4(uint32_t timeoutMs, const sp& callback) { + mCallback = callback; + return on(timeoutMs); +} + +Return Vibrator::perform_1_4(V1_3::Effect effect, EffectStrength strength, + const sp& callback, perform_cb _hidl_cb) { + mCallback = callback; return perform(effect, strength, _hidl_cb); } @@ -148,6 +166,14 @@ Status Vibrator::enable(bool enabled) { return Status::UNSUPPORTED_OPERATION; } else { ALOGI("Enabled: %s -> %s\n", mEnabled ? "true" : "false", enabled ? "true" : "false"); + if (mEnabled && !enabled) { + if (auto callback = mCallback) { + mCallback = nullptr; + if (auto ret = callback->onComplete(); !ret.isOk()) { + ALOGE("Failed completion callback: %s", ret.description().c_str()); + } + } + } mEnabled = enabled; return Status::OK; } @@ -271,7 +297,7 @@ uint8_t Vibrator::strengthToAmplitude(EffectStrength strength, Status* status) { } } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace vibrator } // namespace hardware } // namespace android diff --git a/vibrator/1.3/example/Vibrator.h b/vibrator/1.x/example/Vibrator.h similarity index 75% rename from vibrator/1.3/example/Vibrator.h rename to vibrator/1.x/example/Vibrator.h index 5180774552..ff634315ec 100644 --- a/vibrator/1.3/example/Vibrator.h +++ b/vibrator/1.x/example/Vibrator.h @@ -13,20 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H -#define ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H +#ifndef ANDROID_HARDWARE_VIBRATOR_V1_x_VIBRATOR_H +#define ANDROID_HARDWARE_VIBRATOR_V1_x_VIBRATOR_H -#include +#include #include namespace android { namespace hardware { namespace vibrator { -namespace V1_3 { +namespace V1_4 { namespace implementation { using android::hardware::vibrator::V1_0::EffectStrength; using android::hardware::vibrator::V1_0::Status; +using android::hardware::vibrator::V1_3::Effect; class Vibrator : public IVibrator { public: @@ -51,7 +52,14 @@ class Vibrator : public IVibrator { // Methods from ::android::hardware::vibrator::V1_3::IVibrator follow. Return supportsExternalControl() override; Return setExternalControl(bool enabled) override; - Return perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) override; + Return perform_1_3(V1_3::Effect effect, EffectStrength strength, + perform_cb _hidl_cb) override; + + // Methods from ::android::hardware::vibrator::V1_4::IVibrator follow. + Return> getCapabilities() override; + Return on_1_4(uint32_t timeoutMs, const sp& callback) override; + Return perform_1_4(V1_3::Effect effect, EffectStrength strength, + const sp& callback, perform_cb _hidl_cb) override; private: Return perform(Effect effect, EffectStrength strength, perform_cb _hidl_cb); @@ -72,11 +80,12 @@ class Vibrator : public IVibrator { bool mExternalControl{false}; std::mutex mMutex; timer_t mTimer{nullptr}; + sp mCallback{nullptr}; }; } // namespace implementation -} // namespace V1_3 +} // namespace V1_4 } // namespace vibrator } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H +#endif // ANDROID_HARDWARE_VIBRATOR_V1_x_VIBRATOR_H diff --git a/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.rc b/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.rc new file mode 100644 index 0000000000..4893db6b90 --- /dev/null +++ b/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.rc @@ -0,0 +1,4 @@ +service vendor.vibrator-1-x /vendor/bin/hw/android.hardware.vibrator@1.x-service.example + class hal + user system + group system diff --git a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml b/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.xml similarity index 90% rename from vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml rename to vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.xml index 172aa2178c..ebc8c4bcb8 100644 --- a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml +++ b/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.xml @@ -2,7 +2,7 @@ android.hardware.vibrator hwbinder - 1.3 + 1.4 IVibrator default diff --git a/vibrator/1.3/example/service.cpp b/vibrator/1.x/example/service.cpp similarity index 82% rename from vibrator/1.3/example/service.cpp rename to vibrator/1.x/example/service.cpp index 449996e280..13c66912e8 100644 --- a/vibrator/1.3/example/service.cpp +++ b/vibrator/1.x/example/service.cpp @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define LOG_TAG "android.hardware.vibrator@1.3-service.example" +#define LOG_TAG "android.hardware.vibrator@1.x-service.example" -#include +#include #include #include "Vibrator.h" using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; -using android::hardware::vibrator::V1_3::IVibrator; -using android::hardware::vibrator::V1_3::implementation::Vibrator; +using android::hardware::vibrator::V1_4::IVibrator; +using android::hardware::vibrator::V1_4::implementation::Vibrator; using namespace android; status_t registerVibratorService() { From e6976fce80a9a0951c6bc6f668b2de032ccc4d34 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Tue, 30 Jul 2019 17:48:26 -0700 Subject: [PATCH 0175/1022] Extend EVS interfaces and data types This change extends the definition of CameraDesc with the additional camera metadata field that various camera module informaiton will be stored. IEvsEnumerator is extended with three new methods: - getCameraList_1_1() returns a list of new camera descriptors - openCamera_1_1() tries to open a camera device with a given stream configuration. IEvsCameraStream has below changes: - deliverFrame_1_1() method is added to handle a frame in new BufferDesc. - Rename notifyEvent() as notify(). IEvsCamera also has below new methods: - getCameraInfo_1_1() returns a new camera descriptor. - getParameterList() returns a list of camera control parameters supported by the camera device. - getIntParameterRange() returns a valid range of parameter values. - Parameter setter and getter methods are renamed. VTS test cases are updated to use new methods and below test cases are added to validate their behaviors: - CameraUseStreamConfigToDisplay verifies end-to-end video stream with a stream configuration it finds from CameraDesc's metadata. - MultiCameraStreamUseConfig verifies two clients can start and stop video streams on the same underlying camera with same stream configuration. Bug: 128851019 Test: VtsHalEvsV1_1Target Change-Id: Ia6b0b94aff869129cb400d0a4c4df91e72682784 Signed-off-by: Changyeon Jo --- automotive/evs/1.1/Android.bp | 4 +- automotive/evs/1.1/IEvsCamera.hal | 34 +- automotive/evs/1.1/IEvsCameraStream.hal | 19 +- automotive/evs/1.1/IEvsEnumerator.hal | 50 + automotive/evs/1.1/default/Android.bp | 20 +- automotive/evs/1.1/default/ConfigManager.cpp | 487 ++++++++++ automotive/evs/1.1/default/ConfigManager.h | 336 +++++++ .../evs/1.1/default/ConfigManagerUtil.cpp | 131 +++ .../evs/1.1/default/ConfigManagerUtil.h | 61 ++ automotive/evs/1.1/default/EvsCamera.cpp | 108 ++- automotive/evs/1.1/default/EvsCamera.h | 28 +- automotive/evs/1.1/default/EvsEnumerator.cpp | 109 ++- automotive/evs/1.1/default/EvsEnumerator.h | 25 +- .../resources/evs_default_configuration.xml | 68 ++ automotive/evs/1.1/default/service.cpp | 2 +- automotive/evs/1.1/types.hal | 49 +- automotive/evs/1.1/vts/functional/Android.bp | 2 + .../evs/1.1/vts/functional/FrameHandler.cpp | 187 ++-- .../evs/1.1/vts/functional/FrameHandler.h | 23 +- .../functional/VtsHalEvsV1_1TargetTest.cpp | 901 +++++++++++++----- 20 files changed, 2230 insertions(+), 414 deletions(-) create mode 100644 automotive/evs/1.1/IEvsEnumerator.hal create mode 100644 automotive/evs/1.1/default/ConfigManager.cpp create mode 100644 automotive/evs/1.1/default/ConfigManager.h create mode 100644 automotive/evs/1.1/default/ConfigManagerUtil.cpp create mode 100644 automotive/evs/1.1/default/ConfigManagerUtil.h create mode 100644 automotive/evs/1.1/default/resources/evs_default_configuration.xml diff --git a/automotive/evs/1.1/Android.bp b/automotive/evs/1.1/Android.bp index d2e85f1304..c850c91b21 100644 --- a/automotive/evs/1.1/Android.bp +++ b/automotive/evs/1.1/Android.bp @@ -10,13 +10,15 @@ hidl_interface { "types.hal", "IEvsCamera.hal", "IEvsCameraStream.hal", + "IEvsEnumerator.hal", ], interfaces: [ "android.hardware.automotive.evs@1.0", + "android.hardware.camera.device@3.2", "android.hardware.graphics.common@1.0", "android.hardware.graphics.common@1.1", "android.hardware.graphics.common@1.2", "android.hidl.base@1.0", ], - gen_java: true, + gen_java: false, } diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal index 21ca79e91f..975b6c6cae 100644 --- a/automotive/evs/1.1/IEvsCamera.hal +++ b/automotive/evs/1.1/IEvsCamera.hal @@ -25,6 +25,14 @@ import IEvsCameraStream; * Represents a single camera and is the primary interface for capturing images. */ interface IEvsCamera extends @1.0::IEvsCamera { + /** + * Returns the description of this camera. + * + * @return info The description of this camera. This must be the same value as + * reported by EvsEnumerator::getCameraList_1_1(). + */ + getCameraInfo_1_1() generates (CameraDesc info); + /** * Requests to pause EVS camera stream events. * @@ -100,7 +108,27 @@ interface IEvsCamera extends @1.0::IEvsCamera { unsetMaster() generates (EvsResult result); /** - * Requests to set a camera parameter. + * Retrieves a list of parameters this camera supports. + * + * @return params A list of CameraParam that this camera supports. + */ + getParameterList() generates (vec params); + + /** + * Requests a valid value range of a camera parameter + * + * @param id The identifier of camera parameter, CameraParam enum. + * + * @return min The lower bound of valid parameter value range. + * @return max The upper bound of valid parameter value range. + * @return step The resolution of values in valid range. + */ + getIntParameterRange(CameraParam id) + generates (int32_t min, int32_t max, int32_t step); + + /** + * Requests to set a camera parameter. Only a request from the master + * client will be processed successfully. * * @param id The identifier of camera parameter, CameraParam enum. * value A desired parameter value. @@ -114,7 +142,7 @@ interface IEvsCamera extends @1.0::IEvsCamera { * from what the client gives if, for example, the * driver does not support a target parameter. */ - setParameter(CameraParam id, int32_t value) + setIntParameter(CameraParam id, int32_t value) generates (EvsResult result, int32_t effectiveValue); /** @@ -126,5 +154,5 @@ interface IEvsCamera extends @1.0::IEvsCamera { * not supported. * value A value of requested camera parameter. */ - getParameter(CameraParam id) generates(EvsResult result, int32_t value); + getIntParameter(CameraParam id) generates(EvsResult result, int32_t value); }; diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal index 7c7f832103..9e4ea19f1d 100644 --- a/automotive/evs/1.1/IEvsCameraStream.hal +++ b/automotive/evs/1.1/IEvsCameraStream.hal @@ -17,15 +17,32 @@ package android.hardware.automotive.evs@1.1; import @1.0::IEvsCameraStream; +import @1.1::BufferDesc; +import @1.1::EvsEvent; /** * Implemented on client side to receive asynchronous streaming event deliveries. */ interface IEvsCameraStream extends @1.0::IEvsCameraStream { + + /** + * Receives calls from the HAL each time a video frame is ready for inspection. + * Buffer handles received by this method must be returned via calls to + * IEvsCamera::doneWithFrame_1_1(). When the video stream is stopped via a call + * to IEvsCamera::stopVideoStream(), this callback may continue to happen for + * some time as the pipeline drains. Each frame must still be returned. + * When the last frame in the stream has been delivered, STREAM_STOPPED + * event must be delivered. No further frame deliveries may happen + * thereafter. + * + * @param buffer a buffer descriptor of a delivered image frame. + */ + oneway deliverFrame_1_1(BufferDesc buffer); + /** * Receives calls from the HAL each time an event happens. * * @param event EVS event with possible event information. */ - oneway notifyEvent(EvsEvent event); + oneway notify(EvsEvent event); }; diff --git a/automotive/evs/1.1/IEvsEnumerator.hal b/automotive/evs/1.1/IEvsEnumerator.hal new file mode 100644 index 0000000000..1695821baa --- /dev/null +++ b/automotive/evs/1.1/IEvsEnumerator.hal @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package android.hardware.automotive.evs@1.1; + +import IEvsCamera; +import @1.0::IEvsEnumerator; +import @1.0::EvsResult; +import android.hardware.camera.device@3.2::Stream; + +/** + * Provides the mechanism for EVS camera discovery + */ +interface IEvsEnumerator extends @1.0::IEvsEnumerator { + /** + * Returns a list of all EVS cameras available to the system + * + * @return cameras A list of cameras availale for EVS service. + */ + getCameraList_1_1() generates (vec cameras); + + /** + * Gets the IEvsCamera associated with a cameraId from a CameraDesc + * + * Given a camera's unique cameraId from CameraDesc, returns the + * IEvsCamera interface associated with the specified camera. When + * done using the camera, the caller may release it by calling closeCamera(). + * + * @param cameraId A unique identifier of the camera. + * @param streamCfg A stream configuration the client wants to use. + * @return evsCamera EvsCamera object associated with a given cameraId. + * Returned object would be null if a camera device does + * not support a given stream configuration or is already + * configured differently by another client. + */ + openCamera_1_1(string cameraId, Stream streamCfg) generates (IEvsCamera evsCamera); +}; diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp index a46347102f..41cb4265e5 100644 --- a/automotive/evs/1.1/default/Android.bp +++ b/automotive/evs/1.1/default/Android.bp @@ -7,25 +7,41 @@ cc_binary { "service.cpp", "EvsCamera.cpp", "EvsEnumerator.cpp", - "EvsDisplay.cpp" + "EvsDisplay.cpp", + "ConfigManager.cpp", + "ConfigManagerUtil.cpp", ], init_rc: ["android.hardware.automotive.evs@1.1-service.rc"], shared_libs: [ "android.hardware.automotive.evs@1.0", "android.hardware.automotive.evs@1.1", + "android.hardware.camera.device@3.2", "libbase", "libbinder", - "libcutils", + "liblog", "libhardware", "libhidlbase", "liblog", "libui", "libutils", + "libcamera_metadata", + "libtinyxml2", ], cflags: [ "-O0", "-g", ], + + required: [ + "evs_default_configuration.xml", + ], +} + +prebuilt_etc { + name: "evs_default_configuration.xml", + + src: "resources/evs_default_configuration.xml", + sub_dir: "automotive/evs", } diff --git a/automotive/evs/1.1/default/ConfigManager.cpp b/automotive/evs/1.1/default/ConfigManager.cpp new file mode 100644 index 0000000000..4f46f9dbca --- /dev/null +++ b/automotive/evs/1.1/default/ConfigManager.cpp @@ -0,0 +1,487 @@ +/* + * 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. + */ + +#include +#include +#include + +#include +#include +#include + +#include "ConfigManager.h" + +using ::android::hardware::camera::device::V3_2::StreamRotation; + + +ConfigManager::~ConfigManager() { + /* Nothing to do */ +} + + +void ConfigManager::readCameraInfo(const XMLElement * const aCameraElem) { + if (aCameraElem == nullptr) { + ALOGW("XML file does not have required camera element"); + return; + } + + const XMLElement *curElem = aCameraElem->FirstChildElement(); + while (curElem != nullptr) { + if (!strcmp(curElem->Name(), "group")) { + /* camera group identifier */ + const char *group_id = curElem->FindAttribute("group_id")->Value(); + + /* create CameraGroup */ + unique_ptr aCameraGroup(new ConfigManager::CameraGroup()); + + /* add a camera device to its group */ + addCameraDevices(curElem->FindAttribute("device_id")->Value(), aCameraGroup); + + /* a list of camera stream configurations */ + const XMLElement *childElem = + curElem->FirstChildElement("caps")->FirstChildElement("stream"); + while (childElem != nullptr) { + /* read 5 attributes */ + const XMLAttribute *idAttr = childElem->FindAttribute("id"); + const XMLAttribute *widthAttr = childElem->FindAttribute("width"); + const XMLAttribute *heightAttr = childElem->FindAttribute("height"); + const XMLAttribute *fmtAttr = childElem->FindAttribute("format"); + const XMLAttribute *fpsAttr = childElem->FindAttribute("framerate"); + + const int32_t id = stoi(idAttr->Value()); + int32_t framerate = 0; + if (fpsAttr != nullptr) { + framerate = stoi(fpsAttr->Value()); + } + + int32_t pixFormat; + if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), + pixFormat)) { + RawStreamConfiguration cfg = { + id, + stoi(widthAttr->Value()), + stoi(heightAttr->Value()), + pixFormat, + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, + framerate + }; + aCameraGroup->streamConfigurations[id] = cfg; + } + + childElem = childElem->NextSiblingElement("stream"); + } + + /* camera group synchronization */ + const char *sync = curElem->FindAttribute("synchronized")->Value(); + aCameraGroup->synchronized = + static_cast(strcmp(sync, "false")); + + /* add a group to hash map */ + mCameraGroups[group_id] = std::move(aCameraGroup); + } else if (!strcmp(curElem->Name(), "device")) { + /* camera unique identifier */ + const char *id = curElem->FindAttribute("id")->Value(); + + /* camera mount location */ + const char *pos = curElem->FindAttribute("position")->Value(); + + /* store read camera module information */ + mCameraInfo[id] = readCameraDeviceInfo(curElem); + + /* assign a camera device to a position group */ + mCameraPosition[pos].emplace(id); + } else { + /* ignore other device types */ + ALOGD("Unknown element %s is ignored", curElem->Name()); + } + + curElem = curElem->NextSiblingElement(); + } +} + + +unique_ptr +ConfigManager::readCameraDeviceInfo(const XMLElement *aDeviceElem) { + if (aDeviceElem == nullptr) { + return nullptr; + } + + /* create a CameraInfo to be filled */ + unique_ptr aCamera(new ConfigManager::CameraInfo()); + + /* size information to allocate camera_metadata_t */ + size_t totalEntries = 0; + size_t totalDataSize = 0; + + /* read device capabilities */ + totalEntries += + readCameraCapabilities(aDeviceElem->FirstChildElement("caps"), + aCamera, + totalDataSize); + + + /* read camera metadata */ + totalEntries += + readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"), + aCamera, + totalDataSize); + + /* construct camera_metadata_t */ + if (!constructCameraMetadata(aCamera, totalEntries, totalDataSize)) { + ALOGW("Either failed to allocate memory or " + "allocated memory was not large enough"); + } + + return aCamera; +} + + +size_t ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem, + unique_ptr &aCamera, + size_t &dataSize) { + if (aCapElem == nullptr) { + return 0; + } + + string token; + const XMLElement *curElem = nullptr; + + /* a list of supported camera parameters/controls */ + curElem = aCapElem->FirstChildElement("supported_controls"); + if (curElem != nullptr) { + const XMLElement *ctrlElem = curElem->FirstChildElement("control"); + while (ctrlElem != nullptr) { + const char *nameAttr = ctrlElem->FindAttribute("name")->Value();; + const int32_t minVal = stoi(ctrlElem->FindAttribute("min")->Value()); + const int32_t maxVal = stoi(ctrlElem->FindAttribute("max")->Value()); + + int32_t stepVal = 1; + const XMLAttribute *stepAttr = ctrlElem->FindAttribute("step"); + if (stepAttr != nullptr) { + stepVal = stoi(stepAttr->Value()); + } + + CameraParam aParam; + if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr, + aParam)) { + aCamera->controls.emplace( + aParam, + make_tuple(minVal, maxVal, stepVal) + ); + } + + ctrlElem = ctrlElem->NextSiblingElement("control"); + } + } + + /* a list of camera stream configurations */ + curElem = aCapElem->FirstChildElement("stream"); + while (curElem != nullptr) { + /* read 5 attributes */ + const XMLAttribute *idAttr = curElem->FindAttribute("id"); + const XMLAttribute *widthAttr = curElem->FindAttribute("width"); + const XMLAttribute *heightAttr = curElem->FindAttribute("height"); + const XMLAttribute *fmtAttr = curElem->FindAttribute("format"); + const XMLAttribute *fpsAttr = curElem->FindAttribute("framerate"); + + const int32_t id = stoi(idAttr->Value()); + int32_t framerate = 0; + if (fpsAttr != nullptr) { + framerate = stoi(fpsAttr->Value()); + } + + int32_t pixFormat; + if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), + pixFormat)) { + RawStreamConfiguration cfg = { + id, + stoi(widthAttr->Value()), + stoi(heightAttr->Value()), + pixFormat, + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, + framerate + }; + aCamera->streamConfigurations[id] = cfg; + } + + curElem = curElem->NextSiblingElement("stream"); + } + + dataSize = calculate_camera_metadata_entry_data_size( + get_camera_metadata_tag_type( + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS + ), + aCamera->streamConfigurations.size() * kStreamCfgSz + ); + + /* a single camera metadata entry contains multiple stream configurations */ + return dataSize > 0 ? 1 : 0; +} + + +size_t ConfigManager::readCameraMetadata(const XMLElement * const aParamElem, + unique_ptr &aCamera, + size_t &dataSize) { + if (aParamElem == nullptr) { + return 0; + } + + const XMLElement *curElem = aParamElem->FirstChildElement("parameter"); + size_t numEntries = 0; + camera_metadata_tag_t tag; + while (curElem != nullptr) { + if (!ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(), + tag)) { + switch(tag) { + case ANDROID_LENS_DISTORTION: + case ANDROID_LENS_POSE_ROTATION: + case ANDROID_LENS_POSE_TRANSLATION: + case ANDROID_LENS_INTRINSIC_CALIBRATION: { + /* float[] */ + size_t count = 0; + void *data = ConfigManagerUtil::convertFloatArray( + curElem->FindAttribute("size")->Value(), + curElem->FindAttribute("value")->Value(), + count + ); + + aCamera->cameraMetadata[tag] = + make_pair(make_unique(data), count); + + ++numEntries; + dataSize += calculate_camera_metadata_entry_data_size( + get_camera_metadata_tag_type(tag), count + ); + + break; + } + + default: + ALOGW("Parameter %s is not supported", + curElem->FindAttribute("name")->Value()); + break; + } + } + + curElem = curElem->NextSiblingElement("parameter"); + } + + return numEntries; +} + + +bool ConfigManager::constructCameraMetadata(unique_ptr &aCamera, + const size_t totalEntries, + const size_t totalDataSize) { + if (!aCamera->allocate(totalEntries, totalDataSize)) { + ALOGE("Failed to allocate memory for camera metadata"); + return false; + } + + const size_t numStreamConfigs = aCamera->streamConfigurations.size(); + unique_ptr data(new int32_t[kStreamCfgSz * numStreamConfigs]); + int32_t *ptr = data.get(); + for (auto &cfg : aCamera->streamConfigurations) { + for (auto i = 0; i < kStreamCfgSz; ++i) { + *ptr++ = cfg.second[i]; + } + } + int32_t err = add_camera_metadata_entry(aCamera->characteristics, + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, + data.get(), + numStreamConfigs * kStreamCfgSz); + + if (err) { + ALOGE("Failed to add stream configurations to metadata, ignored"); + return false; + } + + bool success = true; + for (auto &[tag, entry] : aCamera->cameraMetadata) { + /* try to add new camera metadata entry */ + int32_t err = add_camera_metadata_entry(aCamera->characteristics, + tag, + entry.first.get(), + entry.second); + if (err) { + ALOGE("Failed to add an entry with a tag 0x%X", tag); + + /* may exceed preallocated capacity */ + ALOGE("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled", + get_camera_metadata_entry_count(aCamera->characteristics), + get_camera_metadata_entry_capacity(aCamera->characteristics), + get_camera_metadata_data_count(aCamera->characteristics), + get_camera_metadata_data_capacity(aCamera->characteristics)); + ALOGE("\tCurrent metadata entry requires %ld bytes", + calculate_camera_metadata_entry_data_size(tag, entry.second)); + + success = false; + } + } + + ALOGV("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled", + get_camera_metadata_entry_count(aCamera->characteristics), + get_camera_metadata_entry_capacity(aCamera->characteristics), + get_camera_metadata_data_count(aCamera->characteristics), + get_camera_metadata_data_capacity(aCamera->characteristics)); + + return success; +} + + +void ConfigManager::readSystemInfo(const XMLElement * const aSysElem) { + if (aSysElem == nullptr) { + return; + } + + /* + * Please note that this function assumes that a given system XML element + * and its child elements follow DTD. If it does not, it will cause a + * segmentation fault due to the failure of finding expected attributes. + */ + + /* read number of cameras available in the system */ + const XMLElement *xmlElem = aSysElem->FirstChildElement("num_cameras"); + if (xmlElem != nullptr) { + mSystemInfo.numCameras = + stoi(xmlElem->FindAttribute("value")->Value()); + } +} + + +void ConfigManager::readDisplayInfo(const XMLElement * const aDisplayElem) { + if (aDisplayElem == nullptr) { + ALOGW("XML file does not have required camera element"); + return; + } + + const XMLElement *curDev = aDisplayElem->FirstChildElement("device"); + while (curDev != nullptr) { + const char *id = curDev->FindAttribute("id")->Value(); + //const char *pos = curDev->FirstAttribute("position")->Value(); + + unique_ptr dpy(new DisplayInfo()); + if (dpy == nullptr) { + ALOGE("Failed to allocate memory for DisplayInfo"); + return; + } + + const XMLElement *cap = curDev->FirstChildElement("caps"); + if (cap != nullptr) { + const XMLElement *curStream = cap->FirstChildElement("stream"); + while (curStream != nullptr) { + /* read 4 attributes */ + const XMLAttribute *idAttr = curStream->FindAttribute("id"); + const XMLAttribute *widthAttr = curStream->FindAttribute("width"); + const XMLAttribute *heightAttr = curStream->FindAttribute("height"); + const XMLAttribute *fmtAttr = curStream->FindAttribute("format"); + + const int32_t id = stoi(idAttr->Value()); + int32_t pixFormat; + if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), + pixFormat)) { + RawStreamConfiguration cfg = { + id, + stoi(widthAttr->Value()), + stoi(heightAttr->Value()), + pixFormat, + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT, + 0 // unused + }; + dpy->streamConfigurations[id] = cfg; + } + + curStream = curStream->NextSiblingElement("stream"); + } + } + + mDisplayInfo[id] = std::move(dpy); + curDev = curDev->NextSiblingElement("device"); + } + + return; +} + + +bool ConfigManager::readConfigDataFromXML() noexcept { + XMLDocument xmlDoc; + + const int64_t parsingStart = android::elapsedRealtimeNano(); + + /* load and parse a configuration file */ + xmlDoc.LoadFile(mConfigFilePath); + if (xmlDoc.ErrorID() != XML_SUCCESS) { + ALOGE("Failed to load and/or parse a configuration file, %s", xmlDoc.ErrorStr()); + return false; + } + + /* retrieve the root element */ + const XMLElement *rootElem = xmlDoc.RootElement(); + if (strcmp(rootElem->Name(), "configuration")) { + ALOGE("A configuration file is not in the required format. " + "See /etc/automotive/evs/evs_configuration.dtd"); + return false; + } + + /* + * parse camera information; this needs to be done before reading system + * information + */ + readCameraInfo(rootElem->FirstChildElement("camera")); + + /* parse system information */ + readSystemInfo(rootElem->FirstChildElement("system")); + + /* parse display information */ + readDisplayInfo(rootElem->FirstChildElement("display")); + + const int64_t parsingEnd = android::elapsedRealtimeNano(); + ALOGI("Parsing configuration file takes %lf (ms)", + (double)(parsingEnd - parsingStart) / 1000000.0); + + + return true; +} + + +void ConfigManager::addCameraDevices(const char *devices, + unique_ptr &aGroup) { + stringstream device_list(devices); + string token; + while (getline(device_list, token, ',')) { + aGroup->devices.emplace(token); + } +} + + +std::unique_ptr ConfigManager::Create(const char *path) { + unique_ptr cfgMgr(new ConfigManager(path)); + + /* + * Read a configuration from XML file + * + * If this is too slow, ConfigManager::readConfigDataFromBinary() and + * ConfigManager::writeConfigDataToBinary()can serialize CameraInfo object + * to the filesystem and construct CameraInfo instead; this was + * evaluated as 10x faster. + */ + if (!cfgMgr->readConfigDataFromXML()) { + return nullptr; + } else { + return cfgMgr; + } +} + diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h new file mode 100644 index 0000000000..0275f904e5 --- /dev/null +++ b/automotive/evs/1.1/default/ConfigManager.h @@ -0,0 +1,336 @@ +/* + * 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. + */ +#ifndef CONFIG_MANAGER_H +#define CONFIG_MANAGER_H + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "ConfigManagerUtil.h" + +using namespace std; +using namespace tinyxml2; + +using ::android::hardware::hidl_vec; +using ::android::hardware::camera::device::V3_2::Stream; +using ::android::hardware::automotive::evs::V1_1::CameraParam; + +/* + * Plese note that this is different from what is defined in + * libhardware/modules/camera/3_4/metadata/types.h; this has one additional + * field to store a framerate. + */ +const size_t kStreamCfgSz = 6; +typedef std::array RawStreamConfiguration; + +class ConfigManager { +public: + static std::unique_ptr Create(const char *path = ""); + ConfigManager(const ConfigManager&) = delete; + ConfigManager& operator=(const ConfigManager&) = delete; + + virtual ~ConfigManager(); + + /* Camera device's capabilities and metadata */ + class CameraInfo { + public: + CameraInfo() : + characteristics(nullptr) { + /* Nothing to do */ + } + + virtual ~CameraInfo() { + free_camera_metadata(characteristics); + } + + /* Allocate memory for camera_metadata_t */ + bool allocate(size_t entry_cap, size_t data_cap) { + if (characteristics != nullptr) { + ALOGE("Camera metadata is already allocated"); + return false; + } + + characteristics = allocate_camera_metadata(entry_cap, data_cap); + return characteristics != nullptr; + } + + /* + * List of supported controls that the master client can program. + * Paraemters are stored with its valid range + */ + unordered_map> controls; + + /* List of supported frame rates */ + unordered_set frameRates; + + /* + * List of supported output stream configurations; each array stores + * format, width, height, and direction values in the order. + */ + unordered_map streamConfigurations; + + /* + * Internal storage for camera metadata. Each entry holds a pointer to + * data and number of elements + */ + unordered_map, size_t>> cameraMetadata; + + /* Camera module characteristics */ + camera_metadata_t *characteristics; + }; + + class CameraGroup { + public: + CameraGroup() {} + + /* ID of member camera devices */ + unordered_set devices; + + /* The capture operation of member camera devices are synchronized */ + bool synchronized = false; + + /* + * List of stream configurations that are supposed by all camera devices + * in this group. + */ + unordered_map streamConfigurations; + }; + + class SystemInfo { + public: + /* number of available cameras */ + int32_t numCameras = 0; + }; + + class DisplayInfo { + public: + /* + * List of supported input stream configurations; each array stores + * format, width, height, and direction values in the order. + */ + unordered_map streamConfigurations; + }; + + /* + * Return system information + * + * @return SystemInfo + * Constant reference of SystemInfo. + */ + const SystemInfo &getSystemInfo() { + return mSystemInfo; + } + + /* + * Return a list of cameras + * + * This function assumes that it is not being called frequently. + * + * @return vector + * A vector that contains unique camera device identifiers. + */ + vector getCameraList() { + vector aList; + for (auto &v : mCameraInfo) { + aList.emplace_back(v.first); + } + + return aList; + } + + + /* + * Return a list of cameras + * + * @return CameraGroup + * A pointer to a camera group identified by a given id. + */ + unique_ptr& getCameraGroup(const string& gid) { + return mCameraGroups[gid]; + } + + + /* + * Return a camera metadata + * + * @param cameraId + * Unique camera node identifier in string + * + * @return unique_ptr + * A pointer to CameraInfo that is associated with a given camera + * ID. This returns a null pointer if this does not recognize a + * given camera identifier. + */ + unique_ptr& getCameraInfo(const string cameraId) noexcept { + return mCameraInfo[cameraId]; + } + +private: + /* Constructors */ + ConfigManager(const char *xmlPath) : + mConfigFilePath(xmlPath) { + } + + /* System configuration */ + SystemInfo mSystemInfo; + + /* Internal data structure for camera device information */ + unordered_map> mCameraInfo; + + /* Internal data structure for camera device information */ + unordered_map> mDisplayInfo; + + /* Camera groups are stored in hash map */ + unordered_map> mCameraGroups; + + /* + * Camera positions are stored in hash map. + * The position must be one of front, rear, left, and right. + */ + unordered_map> mCameraPosition; + + /* A path to XML configuration file */ + const char *mConfigFilePath; + + /* + * Parse a given EVS configuration file and store the information + * internally. + * + * @return bool + * True if it completes parsing a file successfully. + */ + bool readConfigDataFromXML() noexcept; + + /* + * read the information of the vehicle + * + * @param aSysElem + * A pointer to "system" XML element. + */ + void readSystemInfo(const XMLElement * const aSysElem); + + /* + * read the information of camera devices + * + * @param aCameraElem + * A pointer to "camera" XML element that may contain multiple + * "device" elements. + */ + void readCameraInfo(const XMLElement * const aCameraElem); + + /* + * read display device information + * + * @param aDisplayElem + * A pointer to "display" XML element that may contain multiple + * "device" elements. + */ + void readDisplayInfo(const XMLElement * const aDisplayElem); + + /* + * read camera device information + * + * @param aDeviceElem + * A pointer to "device" XML element that contains camera module + * capability info and its characteristics. + * + * @return unique_ptr + * A pointer to CameraInfo class that contains camera module + * capability and characteristics. Please note that this transfers + * the ownership of created CameraInfo to the caller. + */ + unique_ptr readCameraDeviceInfo(const XMLElement *aDeviceElem); + + /* + * read camera metadata + * + * @param aCapElem + * A pointer to "cap" XML element. + * @param aCamera + * A pointer to CameraInfo that is being filled by this method. + * @param dataSize + * Required size of memory to store camera metadata found in this + * method. This is calculated in this method and returned to the + * caller for camera_metadata allocation. + * + * @return size_t + * Number of camera metadata entries + */ + size_t readCameraCapabilities(const XMLElement * const aCapElem, + unique_ptr &aCamera, + size_t &dataSize); + + /* + * read camera metadata + * + * @param aParamElem + * A pointer to "characteristics" XML element. + * @param aCamera + * A pointer to CameraInfo that is being filled by this method. + * @param dataSize + * Required size of memory to store camera metadata found in this + * method. + * + * @return size_t + * Number of camera metadata entries + */ + size_t readCameraMetadata(const XMLElement * const aParamElem, + unique_ptr &aCamera, + size_t &dataSize); + + /* + * construct camera_metadata_t from camera capabilities and metadata + * + * @param aCamera + * A pointer to CameraInfo that is being filled by this method. + * @param totalEntries + * Number of camera metadata entries to be added. + * @param totalDataSize + * Sum of sizes of camera metadata entries to be added. + * + * @return bool + * False if either it fails to allocate memory for camera metadata + * or its size is not large enough to add all found camera metadata + * entries. + */ + bool constructCameraMetadata(unique_ptr &aCamera, + const size_t totalEntries, + const size_t totalDataSize); + + /* + * parse a comma-separated list of camera devices and add them to + * CameraGroup. + * + * @param devices + * A comma-separated list of camera device identifiers. + * @param aGroup + * Camera group which cameras will be added to. + */ + void addCameraDevices(const char *devices, + unique_ptr &aGroup); +}; +#endif // CONFIG_MANAGER_H + diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.cpp b/automotive/evs/1.1/default/ConfigManagerUtil.cpp new file mode 100644 index 0000000000..8206daa6d7 --- /dev/null +++ b/automotive/evs/1.1/default/ConfigManagerUtil.cpp @@ -0,0 +1,131 @@ +/* + * 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. + */ + +#include "ConfigManagerUtil.h" + +#include +#include +#include + +#include +#include + + +bool ConfigManagerUtil::convertToEvsCameraParam(const string &id, + CameraParam &camParam) { + string trimmed = ConfigManagerUtil::trimString(id); + bool success = true; + + if (!trimmed.compare("BRIGHTNESS")) { + camParam = CameraParam::BRIGHTNESS; + } else if (!trimmed.compare("CONTRAST")) { + camParam = CameraParam::CONTRAST; + } else if (!trimmed.compare("AUTOGAIN")) { + camParam = CameraParam::AUTOGAIN; + } else if (!trimmed.compare("GAIN")) { + camParam = CameraParam::GAIN; + } else if (!trimmed.compare("AUTO_WHITE_BALANCE")) { + camParam = CameraParam::AUTO_WHITE_BALANCE; + } else if (!trimmed.compare("WHITE_BALANCE_TEMPERATURE")) { + camParam = CameraParam::WHITE_BALANCE_TEMPERATURE; + } else if (!trimmed.compare("SHARPNESS")) { + camParam = CameraParam::SHARPNESS; + } else if (!trimmed.compare("AUTO_EXPOSURE")) { + camParam = CameraParam::AUTO_EXPOSURE; + } else if (!trimmed.compare("ABSOLUTE_EXPOSURE")) { + camParam = CameraParam::ABSOLUTE_EXPOSURE; + } else if (!trimmed.compare("ABSOLUTE_FOCUS")) { + camParam = CameraParam::ABSOLUTE_FOCUS; + } else if (!trimmed.compare("AUTO_FOCUS")) { + camParam = CameraParam::AUTO_FOCUS; + } else if (!trimmed.compare("ABSOLUTE_ZOOM")) { + camParam = CameraParam::ABSOLUTE_ZOOM; + } else { + success = false; + } + + return success; +} + + +bool ConfigManagerUtil::convertToPixelFormat(const string &format, + int32_t &pixFormat) { + string trimmed = ConfigManagerUtil::trimString(format); + bool success = true; + + if (!trimmed.compare("RGBA_8888")) { + pixFormat = HAL_PIXEL_FORMAT_RGBA_8888; + } else if (!trimmed.compare("YCRCB_420_SP")) { + pixFormat = HAL_PIXEL_FORMAT_YCRCB_420_SP; + } else if (!trimmed.compare("YCBCR_422_I")) { + pixFormat = HAL_PIXEL_FORMAT_YCBCR_422_I; + } else { + success = false; + } + + return success; +} + + +bool ConfigManagerUtil::convertToMetadataTag(const char *name, + camera_metadata_tag &aTag) { + if (!strcmp(name, "LENS_DISTORTION")) { + aTag = ANDROID_LENS_DISTORTION; + } else if (!strcmp(name, "LENS_INTRINSIC_CALIBRATION")) { + aTag = ANDROID_LENS_INTRINSIC_CALIBRATION; + } else if (!strcmp(name, "LENS_POSE_ROTATION")) { + aTag = ANDROID_LENS_POSE_ROTATION; + } else if (!strcmp(name, "LENS_POSE_TRANSLATION")) { + aTag = ANDROID_LENS_POSE_TRANSLATION; + } else { + return false; + } + + return true; +} + + +float *ConfigManagerUtil::convertFloatArray(const char *sz, const char *vals, + size_t &count, const char delimiter) { + string size_string(sz); + string value_string(vals); + + count = stoi(size_string); + float *result = new float[count]; + stringstream values(value_string); + + int32_t idx = 0; + string token; + while (getline(values, token, delimiter)) { + result[idx++] = stof(token); + } + + return result; +} + + +string ConfigManagerUtil::trimString(const string &src, const string &ws) { + const auto s = src.find_first_not_of(ws); + if (s == string::npos) { + return ""; + } + + const auto e = src.find_last_not_of(ws); + const auto r = e - s + 1; + + return src.substr(s, r); +} + diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.h b/automotive/evs/1.1/default/ConfigManagerUtil.h new file mode 100644 index 0000000000..8c89ae7745 --- /dev/null +++ b/automotive/evs/1.1/default/ConfigManagerUtil.h @@ -0,0 +1,61 @@ +/* + * 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. + */ +#ifndef CONFIG_MANAGER_UTIL_H +#define CONFIG_MANAGER_UTIL_H + +#include +#include +#include +#include + +using namespace std; +using ::android::hardware::automotive::evs::V1_1::CameraParam; + + +class ConfigManagerUtil { +public: + /** + * Convert a given string into V4L2_CID_* + */ + static bool convertToEvsCameraParam(const string &id, + CameraParam &camParam); + /** + * Convert a given string into android.hardware.graphics.common.PixelFormat + */ + static bool convertToPixelFormat(const string &format, + int32_t &pixelFormat); + /** + * Convert a given string into corresponding camera metadata data tag defined in + * system/media/camera/include/system/camera_metadta_tags.h + */ + static bool convertToMetadataTag(const char *name, + camera_metadata_tag &aTag); + /** + * Convert a given string into a floating value array + */ + static float *convertFloatArray(const char *sz, + const char *vals, + size_t &count, + const char delimiter = ','); + /** + * Trim a string + */ + static string trimString(const string &src, + const string &ws = " \n\r\t\f\v"); +}; + +#endif // CONFIG_MANAGER_UTIL_H + diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp index 2d55566349..5ba753da2e 100644 --- a/automotive/evs/1.1/default/EvsCamera.cpp +++ b/automotive/evs/1.1/default/EvsCamera.cpp @@ -40,28 +40,21 @@ const char EvsCamera::kCameraName_Backup[] = "backup"; const unsigned MAX_BUFFERS_IN_FLIGHT = 100; -EvsCamera::EvsCamera(const char *id) : +EvsCamera::EvsCamera(const char *id, + unique_ptr &camInfo) : mFramesAllowed(0), mFramesInUse(0), - mStreamState(STOPPED) { + mStreamState(STOPPED), + mCameraInfo(camInfo) { ALOGD("EvsCamera instantiated"); - mDescription.cameraId = id; + /* set a camera id */ + mDescription.v1.cameraId = id; - // Set up dummy data for testing - if (mDescription.cameraId == kCameraName_Backup) { - mWidth = 640; // full NTSC/VGA - mHeight = 480; // full NTSC/VGA - mDescription.vendorFlags = 0xFFFFFFFF; // Arbitrary value - } else { - mWidth = 320; // 1/2 NTSC/VGA - mHeight = 240; // 1/2 NTSC/VGA - } - - mFormat = HAL_PIXEL_FORMAT_RGBA_8888; - mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE | - GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY; + /* set camera metadata */ + mDescription.metadata.setToExternal((uint8_t *)camInfo->characteristics, + get_camera_metadata_size(camInfo->characteristics)); } @@ -109,7 +102,7 @@ Return EvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) { ALOGD("getCameraInfo"); // Send back our self description - _hidl_cb(mDescription); + _hidl_cb(mDescription.v1); return Void(); } @@ -194,7 +187,7 @@ Return EvsCamera::stopVideoStream() { // Block outside the mutex until the "stop" flag has been acknowledged // We won't send any more frames, but the client might still get some already in flight - ALOGD("Waiting for stream thread to end.."); + ALOGD("Waiting for stream thread to end..."); lock.unlock(); mCaptureThread.join(); lock.lock(); @@ -238,6 +231,15 @@ Return EvsCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/, int3 // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow. +Return EvsCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) { + ALOGD("getCameraInfo_1_1"); + + // Send back our self description + _hidl_cb(mDescription); + return Void(); +} + + Return EvsCamera::doneWithFrame_1_1(const BufferDesc_1_1& bufDesc) { std::lock_guard lock(mAccessLock); returnBuffer(bufDesc.bufferId, bufDesc.buffer.nativeHandle); @@ -278,8 +280,29 @@ Return EvsCamera::unsetMaster() { } -Return EvsCamera::setParameter(CameraParam id, int32_t value, - setParameter_cb _hidl_cb) { +Return EvsCamera::getParameterList(getParameterList_cb _hidl_cb) { + hidl_vec hidlCtrls; + hidlCtrls.resize(mCameraInfo->controls.size()); + unsigned idx = 0; + for (auto& [cid, cfg] : mCameraInfo->controls) { + hidlCtrls[idx++] = cid; + } + + _hidl_cb(hidlCtrls); + return Void(); +} + + +Return EvsCamera::getIntParameterRange(CameraParam id, + getIntParameterRange_cb _hidl_cb) { + auto range = mCameraInfo->controls[id]; + _hidl_cb(get<0>(range), get<1>(range), get<2>(range)); + return Void(); +} + + +Return EvsCamera::setIntParameter(CameraParam id, int32_t value, + setIntParameter_cb _hidl_cb) { // Default implementation does not support this. (void)id; (void)value; @@ -288,7 +311,8 @@ Return EvsCamera::setParameter(CameraParam id, int32_t value, } -Return EvsCamera::getParameter(CameraParam id, getParameter_cb _hidl_cb) { +Return EvsCamera::getIntParameter(CameraParam id, + getIntParameter_cb _hidl_cb) { // Default implementation does not support this. (void)id; _hidl_cb(EvsResult::INVALID_ARG, 0); @@ -471,9 +495,7 @@ void EvsCamera::generateFrames() { fillTestFrame(newBuffer); // Issue the (asynchronous) callback to the client -- can't be holding the lock - EvsEvent event; - event.buffer(newBuffer); - auto result = mStream->notifyEvent(event); + auto result = mStream->deliverFrame_1_1(newBuffer); if (result.isOk()) { ALOGD("Delivered %p as id %d", newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId); @@ -506,10 +528,8 @@ void EvsCamera::generateFrames() { // If we've been asked to stop, send an event to signal the actual end of stream EvsEvent event; - InfoEventDesc desc = {}; - desc.aType = InfoEventType::STREAM_STOPPED; - event.info(desc); - auto result = mStream->notifyEvent(event); + event.aType = EvsEventType::STREAM_STOPPED; + auto result = mStream->notify(event); if (!result.isOk()) { ALOGE("Error delivering end of stream marker"); } @@ -616,6 +636,38 @@ void EvsCamera::returnBuffer(const uint32_t bufferId, const buffer_handle_t memH } +sp EvsCamera::Create(const char *deviceName) { + unique_ptr nullCamInfo = nullptr; + + return Create(deviceName, nullCamInfo); +} + + +sp EvsCamera::Create(const char *deviceName, + unique_ptr &camInfo, + const Stream *streamCfg) { + sp evsCamera = new EvsCamera(deviceName, camInfo); + if (evsCamera == nullptr) { + return nullptr; + } + + /* default implementation does not use a given configuration */ + (void)streamCfg; + + /* Use the first resolution from the list for the testing */ + auto it = camInfo->streamConfigurations.begin(); + evsCamera->mWidth = it->second[1]; + evsCamera->mHeight = it->second[2]; + evsCamera->mDescription.v1.vendorFlags = 0xFFFFFFFF; // Arbitrary test value + + evsCamera->mFormat = HAL_PIXEL_FORMAT_RGBA_8888; + evsCamera->mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE | + GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY; + + return evsCamera; +} + + } // namespace implementation } // namespace V1_0 } // namespace evs diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h index 47a3164892..c15b4b117b 100644 --- a/automotive/evs/1.1/default/EvsCamera.h +++ b/automotive/evs/1.1/default/EvsCamera.h @@ -25,6 +25,8 @@ #include +#include "ConfigManager.h" + using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc; using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc; using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream; @@ -59,18 +61,28 @@ public: Return setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override; // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow. + Return getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) override; Return pauseVideoStream() override; Return resumeVideoStream() override; Return doneWithFrame_1_1(const BufferDesc_1_1& buffer) override; Return setMaster() override; Return forceMaster(const sp& display) override; Return unsetMaster() override; - Return setParameter(CameraParam id, int32_t value, - setParameter_cb _hidl_cb) override; - Return getParameter(CameraParam id, getParameter_cb _hidl_cb) override; + Return getParameterList(getParameterList_cb _hidl_cb) override; + Return getIntParameterRange(CameraParam id, + getIntParameterRange_cb _hidl_cb) override; + Return setIntParameter(CameraParam id, int32_t value, + setIntParameter_cb _hidl_cb) override; + Return getIntParameter(CameraParam id, + getIntParameter_cb _hidl_cb) override; + + static sp Create(const char *deviceName); + static sp Create(const char *deviceName, + unique_ptr &camInfo, + const Stream *streamCfg = nullptr); + EvsCamera(const EvsCamera&) = delete; + EvsCamera& operator=(const EvsCamera&) = delete; - // Implementation details - EvsCamera(const char *id); virtual ~EvsCamera() override; void forceShutdown(); // This gets called if another caller "steals" ownership of the camera @@ -79,7 +91,10 @@ public: static const char kCameraName_Backup[]; private: + EvsCamera(const char *id, + unique_ptr &camInfo); // These three functions are expected to be called while mAccessLock is held + // bool setAvailableFrames_Locked(unsigned bufferCount); unsigned increaseAvailableFrames_Locked(unsigned numToAdd); unsigned decreaseAvailableFrames_Locked(unsigned numToRemove); @@ -124,6 +139,9 @@ private: // Synchronization necessary to deconflict mCaptureThread from the main service thread std::mutex mAccessLock; + + // Static camera module information + unique_ptr &mCameraInfo; }; } // namespace implementation diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp index b3249071ae..a010729ce6 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.cpp +++ b/automotive/evs/1.1/default/EvsEnumerator.cpp @@ -33,6 +33,7 @@ namespace implementation { // constructs a new instance for each client. std::list EvsEnumerator::sCameraList; wp EvsEnumerator::sActiveDisplay; +unique_ptr EvsEnumerator::sConfigManager; EvsEnumerator::EvsEnumerator() { @@ -40,9 +41,11 @@ EvsEnumerator::EvsEnumerator() { // Add sample camera data to our list of cameras // In a real driver, this would be expected to can the available hardware - sCameraList.emplace_back(EvsCamera::kCameraName_Backup); - sCameraList.emplace_back("LaneView"); - sCameraList.emplace_back("right turn"); + sConfigManager = + ConfigManager::Create("/etc/automotive/evs/evs_sample_configuration.xml"); + for (auto v : sConfigManager->getCameraList()) { + sCameraList.emplace_back(v.c_str()); + } } @@ -57,7 +60,7 @@ Return EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) { std::vector descriptions; descriptions.reserve(numCameras); for (const auto& cam : sCameraList) { - descriptions.push_back( cam.desc ); + descriptions.push_back( cam.desc.v1 ); } // Encapsulate our camera descriptions in the HIDL vec type @@ -78,7 +81,7 @@ Return> EvsEnumerator::openCamera(const hidl_string& cameraId // Find the named camera CameraRecord *pRecord = nullptr; for (auto &&cam : sCameraList) { - if (cam.desc.cameraId == cameraId) { + if (cam.desc.v1.cameraId == cameraId) { // Found a match! pRecord = &cam; break; @@ -99,7 +102,12 @@ Return> EvsEnumerator::openCamera(const hidl_string& cameraId } // Construct a camera instance for the caller - pActiveCamera = new EvsCamera(cameraId.c_str()); + if (sConfigManager == nullptr) { + pActiveCamera = EvsCamera::Create(cameraId.c_str()); + } else { + pActiveCamera = EvsCamera::Create(cameraId.c_str(), + sConfigManager->getCameraInfo(cameraId)); + } pRecord->activeInstance = pActiveCamera; if (pActiveCamera == nullptr) { ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str()); @@ -120,15 +128,15 @@ Return EvsEnumerator::closeCamera(const ::android::sp& pCa // Get the camera id so we can find it in our list std::string cameraId; - pCamera_1_1->getCameraInfo([&cameraId](CameraDesc desc) { - cameraId = desc.cameraId; + pCamera_1_1->getCameraInfo_1_1([&cameraId](CameraDesc desc) { + cameraId = desc.v1.cameraId; } ); // Find the named camera CameraRecord *pRecord = nullptr; for (auto &&cam : sCameraList) { - if (cam.desc.cameraId == cameraId) { + if (cam.desc.v1.cameraId == cameraId) { // Found a match! pRecord = &cam; break; @@ -209,6 +217,89 @@ Return EvsEnumerator::getDisplayState() { } +// Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow. +Return EvsEnumerator::getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) { + ALOGD("getCameraList"); + + const unsigned numCameras = sCameraList.size(); + + // Build up a packed array of CameraDesc for return + // NOTE: Only has to live until the callback returns + std::vector descriptions; + descriptions.reserve(numCameras); + for (const auto& cam : sCameraList) { + descriptions.push_back( cam.desc ); + } + + // Encapsulate our camera descriptions in the HIDL vec type + hidl_vec hidlCameras(descriptions); + + // Send back the results + ALOGD("reporting %zu cameras available", hidlCameras.size()); + _hidl_cb(hidlCameras); + + // HIDL convention says we return Void if we sent our result back via callback + return Void(); +} + +Return> +EvsEnumerator::openCamera_1_1(const hidl_string& cameraId, + const Stream& streamCfg) { + // Find the named camera + CameraRecord *pRecord = nullptr; + for (auto &&cam : sCameraList) { + if (cam.desc.v1.cameraId == cameraId) { + // Found a match! + pRecord = &cam; + break; + } + } + + // Is this a recognized camera id? + if (!pRecord) { + ALOGE("Requested camera %s not found", cameraId.c_str()); + return nullptr; + } + + // Has this camera already been instantiated by another caller? + sp pActiveCamera = pRecord->activeInstance.promote(); + if (pActiveCamera != nullptr) { + ALOGW("Killing previous camera because of new caller"); + closeCamera(pActiveCamera); + } + + // Construct a camera instance for the caller + if (sConfigManager == nullptr) { + pActiveCamera = EvsCamera::Create(cameraId.c_str()); + } else { + pActiveCamera = EvsCamera::Create(cameraId.c_str(), + sConfigManager->getCameraInfo(cameraId), + &streamCfg); + } + + pRecord->activeInstance = pActiveCamera; + if (pActiveCamera == nullptr) { + ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str()); + } + + return pActiveCamera; +} + + +EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& cameraId) { + // Find the named camera + CameraRecord *pRecord = nullptr; + for (auto &&cam : sCameraList) { + if (cam.desc.v1.cameraId == cameraId) { + // Found a match! + pRecord = &cam; + break; + } + } + + return pRecord; +} + } // namespace implementation } // namespace V1_1 } // namespace evs diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h index 11c2170632..475ec76b93 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.h +++ b/automotive/evs/1.1/default/EvsEnumerator.h @@ -17,18 +17,20 @@ #ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H #define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H -#include +#include #include #include +#include "ConfigManager.h" + using ::android::hardware::automotive::evs::V1_0::EvsResult; using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; using ::android::hardware::automotive::evs::V1_0::DisplayState; -using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator; using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera; using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera; using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc; +using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc; namespace android { @@ -53,6 +55,11 @@ public: Return closeDisplay(const ::android::sp& display) override; Return getDisplayState() override; + // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow. + Return getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) override; + Return> openCamera_1_1(const hidl_string& cameraId, + const Stream& streamCfg) override; + // Implementation details EvsEnumerator(); @@ -61,14 +68,20 @@ private: // That is to say, this is effectively a singleton despite the fact that HIDL // constructs a new instance for each client. struct CameraRecord { - CameraDesc_1_0 desc; + CameraDesc_1_1 desc; wp activeInstance; - CameraRecord(const char *cameraId) : desc() { desc.cameraId = cameraId; } + CameraRecord(const char *cameraId) : desc() { desc.v1.cameraId = cameraId; } }; - static std::list sCameraList; - static wp sActiveDisplay; // Weak pointer. Object destructs if client dies. + static CameraRecord* findCameraById(const std::string& cameraId); + + static std::list sCameraList; + + // Weak pointer. Object destructs if client dies. + static wp sActiveDisplay; + + static unique_ptr sConfigManager; }; } // namespace implementation diff --git a/automotive/evs/1.1/default/resources/evs_default_configuration.xml b/automotive/evs/1.1/default/resources/evs_default_configuration.xml new file mode 100644 index 0000000000..692102ed38 --- /dev/null +++ b/automotive/evs/1.1/default/resources/evs_default_configuration.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/automotive/evs/1.1/default/service.cpp b/automotive/evs/1.1/default/service.cpp index 128a14aa30..5135864e88 100644 --- a/automotive/evs/1.1/default/service.cpp +++ b/automotive/evs/1.1/default/service.cpp @@ -33,7 +33,7 @@ using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; // Generated HIDL files -using android::hardware::automotive::evs::V1_0::IEvsEnumerator; +using android::hardware::automotive::evs::V1_1::IEvsEnumerator; using android::hardware::automotive::evs::V1_0::IEvsDisplay; // The namespace in which all our implementation code lives diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal index 2c6b2ed589..dcb2abb0e9 100644 --- a/automotive/evs/1.1/types.hal +++ b/automotive/evs/1.1/types.hal @@ -21,6 +21,22 @@ import @1.0::DisplayDesc; import @1.0::DisplayState; import @1.0::EvsResult; import android.hardware.graphics.common@1.2::HardwareBuffer; +import android.hardware.camera.device@3.2::CameraMetadata; + +/** + * Structure describing the basic properties of an EVS camera, extended from its + * v1.0 declaration. + * + * The HAL is responsible for filling out this structure for each + * EVS camera in the system. + */ +struct CameraDesc { + @1.0::CameraDesc v1; + /** + * Store camera metadata such as lens characteristics. + */ + CameraMetadata metadata; +}; /** * Structure representing an image buffer through our APIs @@ -50,7 +66,7 @@ struct BufferDesc { /** * Types of informative streaming events */ -enum InfoEventType : uint32_t { +enum EvsEventType : uint32_t { /** * Video stream is started */ @@ -81,31 +97,17 @@ enum InfoEventType : uint32_t { /** * Structure that describes informative events occurred during EVS is streaming */ -struct InfoEventDesc { +struct EvsEvent { /** * Type of an informative event */ - InfoEventType aType; + EvsEventType aType; /** * Possible additional information */ uint32_t[4] payload; }; -/** - * EVS event definition - */ -safe_union EvsEvent { - /** - * A buffer descriptor of an image frame - */ - BufferDesc buffer; - /** - * General streaming events - */ - InfoEventDesc info; -}; - /** * EVS Camera Parameter */ @@ -126,14 +128,6 @@ enum CameraParam : uint32_t { * Gain control */ GAIN, - /** - * Mirror the image horizontally - */ - HFLIP, - /** - * Mirror the image vertically - */ - VFLIP, /** * Automatic Whitebalance */ @@ -155,11 +149,6 @@ enum CameraParam : uint32_t { * Manual exposure time of the camera */ ABSOLUTE_EXPOSURE, - /** - * When AEC is running in either auto or aperture priority, this parameter - * sets whether a frame rate varies. - */ - AUTO_EXPOSURE_PRIORITY, /** * Set the focal point of the camera to the specified position. This * parameter may not be effective when auto focus is enabled. diff --git a/automotive/evs/1.1/vts/functional/Android.bp b/automotive/evs/1.1/vts/functional/Android.bp index 55c50a42b8..4753933f7f 100644 --- a/automotive/evs/1.1/vts/functional/Android.bp +++ b/automotive/evs/1.1/vts/functional/Android.bp @@ -23,6 +23,7 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], shared_libs: [ "libui", + "libcamera_metadata", ], static_libs: [ "android.hardware.automotive.evs@1.0", @@ -31,6 +32,7 @@ cc_test { "android.hardware.graphics.common@1.0", "android.hardware.graphics.common@1.1", "android.hardware.graphics.common@1.2", + "android.hardware.camera.device@3.2", ], test_suites: ["general-tests"], cflags: [ diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp index 16276891f0..6d53652f86 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp +++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp @@ -138,93 +138,93 @@ Return FrameHandler::deliverFrame(const BufferDesc_1_0& bufferArg) { } -Return FrameHandler::notifyEvent(const EvsEvent& event) { - // Local flag we use to keep track of when the stream is stopping - auto type = event.getDiscriminator(); - if (type == EvsEvent::hidl_discriminator::info) { - mLock.lock(); - mLatestEventDesc = event.info(); - if (mLatestEventDesc.aType == InfoEventType::STREAM_STOPPED) { - // Signal that the last frame has been received and the stream is stopped - mRunning = false; - } else if (mLatestEventDesc.aType == InfoEventType::PARAMETER_CHANGED) { - ALOGD("Camera parameter 0x%X is changed to 0x%X", - mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]); +Return FrameHandler::deliverFrame_1_1(const BufferDesc_1_1& bufDesc) { + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&bufDesc.buffer.description); + ALOGD("Received a frame from the camera (%p)", + bufDesc.buffer.nativeHandle.getNativeHandle()); + + // Store a dimension of a received frame. + mFrameWidth = pDesc->width; + mFrameHeight = pDesc->height; + + // If we were given an opened display at construction time, then send the received + // image back down the camera. + if (mDisplay.get()) { + // Get the output buffer we'll use to display the imagery + BufferDesc_1_0 tgtBuffer = {}; + mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) { + tgtBuffer = buff; + } + ); + + if (tgtBuffer.memHandle == nullptr) { + printf("Didn't get target buffer - frame lost\n"); + ALOGE("Didn't get requested output buffer -- skipping this frame."); } else { - ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType)); - } - mLock.unlock(); - mEventSignal.notify_all(); - } else { - auto bufDesc = event.buffer(); - const AHardwareBuffer_Desc* pDesc = - reinterpret_cast(&bufDesc.buffer.description); - ALOGD("Received a frame from the camera (%p)", - bufDesc.buffer.nativeHandle.getNativeHandle()); + // Copy the contents of the of buffer.memHandle into tgtBuffer + copyBufferContents(tgtBuffer, bufDesc); - // Store a dimension of a received frame. - mFrameWidth = pDesc->width; - mFrameHeight = pDesc->height; - - // If we were given an opened display at construction time, then send the received - // image back down the camera. - if (mDisplay.get()) { - // Get the output buffer we'll use to display the imagery - BufferDesc_1_0 tgtBuffer = {}; - mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) { - tgtBuffer = buff; - } - ); - - if (tgtBuffer.memHandle == nullptr) { - printf("Didn't get target buffer - frame lost\n"); - ALOGE("Didn't get requested output buffer -- skipping this frame."); + // Send the target buffer back for display + Return result = mDisplay->returnTargetBufferForDisplay(tgtBuffer); + if (!result.isOk()) { + printf("HIDL error on display buffer (%s)- frame lost\n", + result.description().c_str()); + ALOGE("Error making the remote function call. HIDL said %s", + result.description().c_str()); + } else if (result != EvsResult::OK) { + printf("Display reported error - frame lost\n"); + ALOGE("We encountered error %d when returning a buffer to the display!", + (EvsResult) result); } else { - // Copy the contents of the of buffer.memHandle into tgtBuffer - copyBufferContents(tgtBuffer, bufDesc); - - // Send the target buffer back for display - Return result = mDisplay->returnTargetBufferForDisplay(tgtBuffer); - if (!result.isOk()) { - printf("HIDL error on display buffer (%s)- frame lost\n", - result.description().c_str()); - ALOGE("Error making the remote function call. HIDL said %s", - result.description().c_str()); - } else if (result != EvsResult::OK) { - printf("Display reported error - frame lost\n"); - ALOGE("We encountered error %d when returning a buffer to the display!", - (EvsResult) result); - } else { - // Everything looks good! - // Keep track so tests or watch dogs can monitor progress - mLock.lock(); - mFramesDisplayed++; - mLock.unlock(); - } + // Everything looks good! + // Keep track so tests or watch dogs can monitor progress + mLock.lock(); + mFramesDisplayed++; + mLock.unlock(); } } - - - switch (mReturnMode) { - case eAutoReturn: - // Send the camera buffer back now that the client has seen it - ALOGD("Calling doneWithFrame"); - // TODO: Why is it that we get a HIDL crash if we pass back the cloned buffer? - mCamera->doneWithFrame_1_1(bufDesc); - break; - case eNoAutoReturn: - // Hang onto the buffer handle for now -- the client will return it explicitly later - mHeldBuffers.push(bufDesc); - } - - mLock.lock(); - ++mFramesReceived; - mLock.unlock(); - mFrameSignal.notify_all(); - - ALOGD("Frame handling complete"); } + + switch (mReturnMode) { + case eAutoReturn: + // Send the camera buffer back now that the client has seen it + ALOGD("Calling doneWithFrame"); + mCamera->doneWithFrame_1_1(bufDesc); + break; + case eNoAutoReturn: + // Hang onto the buffer handle for now -- the client will return it explicitly later + mHeldBuffers.push(bufDesc); + } + + mLock.lock(); + ++mFramesReceived; + mLock.unlock(); + mFrameSignal.notify_all(); + + ALOGD("Frame handling complete"); + + return Void(); +} + + +Return FrameHandler::notify(const EvsEvent& event) { + // Local flag we use to keep track of when the stream is stopping + mLock.lock(); + mLatestEventDesc = event; + if (mLatestEventDesc.aType == EvsEventType::STREAM_STOPPED) { + // Signal that the last frame has been received and the stream is stopped + mRunning = false; + } else if (mLatestEventDesc.aType == EvsEventType::PARAMETER_CHANGED) { + ALOGD("Camera parameter 0x%X is changed to 0x%X", + mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]); + } else { + ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType)); + } + mLock.unlock(); + mEventSignal.notify_all(); + return Void(); } @@ -342,18 +342,18 @@ void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) { } } -bool FrameHandler::waitForEvent(const InfoEventType aTargetEvent, - InfoEventDesc &eventDesc) { +bool FrameHandler::waitForEvent(const EvsEventType aTargetEvent, + EvsEvent &event) { // Wait until we get an expected parameter change event. std::unique_lock lock(mLock); auto now = std::chrono::system_clock::now(); bool result = mEventSignal.wait_until(lock, now + 5s, - [this, aTargetEvent, &eventDesc](){ + [this, aTargetEvent, &event](){ bool flag = mLatestEventDesc.aType == aTargetEvent; if (flag) { - eventDesc.aType = mLatestEventDesc.aType; - eventDesc.payload[0] = mLatestEventDesc.payload[0]; - eventDesc.payload[1] = mLatestEventDesc.payload[1]; + event.aType = mLatestEventDesc.aType; + event.payload[0] = mLatestEventDesc.payload[0]; + event.payload[1] = mLatestEventDesc.payload[1]; } return flag; @@ -363,21 +363,22 @@ bool FrameHandler::waitForEvent(const InfoEventType aTargetEvent, return !result; } -const char *FrameHandler::eventToString(const InfoEventType aType) { +const char *FrameHandler::eventToString(const EvsEventType aType) { switch (aType) { - case InfoEventType::STREAM_STARTED: + case EvsEventType::STREAM_STARTED: return "STREAM_STARTED"; - case InfoEventType::STREAM_STOPPED: + case EvsEventType::STREAM_STOPPED: return "STREAM_STOPPED"; - case InfoEventType::FRAME_DROPPED: + case EvsEventType::FRAME_DROPPED: return "FRAME_DROPPED"; - case InfoEventType::TIMEOUT: + case EvsEventType::TIMEOUT: return "TIMEOUT"; - case InfoEventType::PARAMETER_CHANGED: + case EvsEventType::PARAMETER_CHANGED: return "PARAMETER_CHANGED"; - case InfoEventType::MASTER_RELEASED: + case EvsEventType::MASTER_RELEASED: return "MASTER_RELEASED"; default: return "Unknown"; } } + diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h index 7f87cb4409..e5f1b8f112 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.h +++ b/automotive/evs/1.1/vts/functional/FrameHandler.h @@ -33,7 +33,6 @@ using ::android::hardware::hidl_handle; using ::android::sp; using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; using ::android::hardware::automotive::evs::V1_0::EvsResult; -using ::android::hardware::automotive::evs::V1_0::CameraDesc; using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc; using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc; @@ -56,6 +55,13 @@ public: FrameHandler(android::sp pCamera, CameraDesc cameraInfo, android::sp pDisplay = nullptr, BufferControlFlag mode = eAutoReturn); + virtual ~FrameHandler() { + if (mCamera != nullptr) { + /* shutdown a camera explicitly */ + shutdown(); + } + } + void shutdown(); bool startStream(); @@ -67,19 +73,22 @@ public: bool isRunning(); void waitForFrameCount(unsigned frameCount); - bool waitForEvent(const InfoEventType aTargetEvent, - InfoEventDesc &eventDesc); + bool waitForEvent(const EvsEventType aTargetEvent, + EvsEvent &eventDesc); void getFramesCounters(unsigned* received, unsigned* displayed); void getFrameDimension(unsigned* width, unsigned* height); private: - // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream + // Implementation for ::android::hardware::automotive::evs::V1_0::IEvsCameraStream Return deliverFrame(const BufferDesc_1_0& buffer) override; - Return notifyEvent(const EvsEvent& event) override; + + // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream + Return deliverFrame_1_1(const BufferDesc_1_1& buffer) override; + Return notify(const EvsEvent& event) override; // Local implementation details bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer); - const char *eventToString(const InfoEventType aType); + const char *eventToString(const EvsEventType aType); // Values initialized as startup android::sp mCamera; @@ -100,7 +109,7 @@ private: unsigned mFramesDisplayed = 0; // Simple counter -- rolls over eventually! unsigned mFrameWidth = 0; unsigned mFrameHeight = 0; - InfoEventDesc mLatestEventDesc; + EvsEvent mLatestEventDesc; }; diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index a6e4881d4d..1d3fd87356 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -38,8 +38,9 @@ static const float kNanoToSeconds = 0.000000001f; #include "FrameHandler.h" -#include -#include +#include +#include +#include #include #include @@ -50,8 +51,10 @@ static const float kNanoToSeconds = 0.000000001f; #include #include #include -#include +#include #include +#include +#include #include #include @@ -64,13 +67,28 @@ using ::android::hardware::hidl_vec; using ::android::hardware::hidl_handle; using ::android::hardware::hidl_string; using ::android::sp; -using ::android::hardware::automotive::evs::V1_0::CameraDesc; +using ::android::hardware::camera::device::V3_2::Stream; using ::android::hardware::automotive::evs::V1_0::DisplayDesc; using ::android::hardware::automotive::evs::V1_0::DisplayState; -using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator; +using ::android::hardware::graphics::common::V1_0::PixelFormat; using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera; using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera; +/* + * Plese note that this is different from what is defined in + * libhardware/modules/camera/3_4/metadata/types.h; this has one additional + * field to store a framerate. + */ +const size_t kStreamCfgSz = 5; +typedef struct { + int32_t width; + int32_t height; + int32_t format; + int32_t direction; + int32_t framerate; +} RawStreamConfig; + + // Test environment for Evs HIDL HAL. class EvsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: @@ -107,15 +125,16 @@ protected: assert(pEnumerator != nullptr); // Get the camera list - pEnumerator->getCameraList([this](hidl_vec cameraList) { - ALOGI("Camera list callback received %zu cameras", - cameraList.size()); - cameraInfo.reserve(cameraList.size()); - for (auto&& cam: cameraList) { - ALOGI("Found camera %s", cam.cameraId.c_str()); - cameraInfo.push_back(cam); - } - } + pEnumerator->getCameraList_1_1( + [this](hidl_vec cameraList) { + ALOGI("Camera list callback received %zu cameras", + cameraList.size()); + cameraInfo.reserve(cameraList.size()); + for (auto&& cam: cameraList) { + ALOGI("Found camera %s", cam.v1.cameraId.c_str()); + cameraInfo.push_back(cam); + } + } ); // We insist on at least one camera for EVS to pass any camera tests @@ -143,19 +162,23 @@ TEST_F(EvsHidlTest, CameraOpenClean) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Open and close each camera twice for (auto&& cam: cameraInfo) { for (int pass = 0; pass < 2; pass++) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); // Verify that this camera self-identifies correctly - pCam->getCameraInfo([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.cameraId.c_str()); - EXPECT_EQ(cam.cameraId, desc.cameraId); - } + pCam->getCameraInfo_1_1([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.v1.cameraId.c_str()); + EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); + } ); // Explicitly close the camera so resources are released right away @@ -177,22 +200,26 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Open and close each camera twice for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); // Verify that this camera self-identifies correctly - pCam->getCameraInfo([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.cameraId.c_str()); - EXPECT_EQ(cam.cameraId, desc.cameraId); - } + pCam->getCameraInfo_1_1([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.v1.cameraId.c_str()); + EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); + } ); sp pCam2 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, pCam2); ASSERT_NE(pCam2, nullptr); @@ -210,10 +237,10 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { pEnumerator->closeCamera(pCam); // Verify that the second camera instance self-identifies correctly - pCam2->getCameraInfo([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.cameraId.c_str()); - EXPECT_EQ(cam.cameraId, desc.cameraId); - } + pCam2->getCameraInfo_1_1([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.v1.cameraId.c_str()); + EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); + } ); // Close the second camera instance @@ -235,10 +262,14 @@ TEST_F(EvsHidlTest, CameraStreamPerformance) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); @@ -303,11 +334,15 @@ TEST_F(EvsHidlTest, CameraStreamBuffering) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); @@ -371,6 +406,10 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Request exclusive access to the EVS display sp pDisplay = pEnumerator->openDisplay(); ASSERT_NE(pDisplay, nullptr); @@ -378,7 +417,7 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { // Test each reported camera for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); @@ -439,16 +478,20 @@ TEST_F(EvsHidlTest, MultiCameraStream) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera for (auto&& cam: cameraInfo) { // Create two camera clients. sp pCam0 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam0, nullptr); sp pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam1, nullptr); @@ -486,7 +529,6 @@ TEST_F(EvsHidlTest, MultiCameraStream) { nsecs_t runTime = end - firstFrame; float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds); float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds); - printf("Measured camera rate %3.2f fps and %3.2f fps\n", framesPerSecond0, framesPerSecond1); ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1); EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond); EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond); @@ -526,14 +568,33 @@ TEST_F(EvsHidlTest, CameraParameter) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera + Return result = EvsResult::OK; for (auto&& cam: cameraInfo) { // Create a camera client sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); + // Get the parameter list + std::vector cmds; + pCam->getParameterList([&cmds](hidl_vec cmdList) { + cmds.reserve(cmdList.size()); + for (auto &&cmd : cmdList) { + cmds.push_back(cmd); + } + } + ); + + if (cmds.size() < 1) { + continue; + } + // Set up per-client frame receiver objects which will fire up its own thread sp frameHandler = new FrameHandler(pCam, cam, nullptr, @@ -547,83 +608,70 @@ TEST_F(EvsHidlTest, CameraParameter) { // Ensure the stream starts frameHandler->waitForFrameCount(1); - // Try to program few parameters - EvsResult result = EvsResult::OK; - int32_t val0 = 100; - int32_t val1 = 0; - result = pCam->setMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); - pCam->setParameter(CameraParam::BRIGHTNESS, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); + for (auto &cmd : cmds) { + // Get a valid parameter value range + int32_t minVal, maxVal, step; + pCam->getIntParameterRange( + cmd, + [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { + minVal = val0; + maxVal = val1; + step = val2; + } + ); - if (result == EvsResult::OK) { - pCam->getParameter(CameraParam::BRIGHTNESS, + EvsResult result = EvsResult::OK; + if (cmd == CameraParam::ABSOLUTE_FOCUS) { + // Try to turn off auto-focus + int32_t val1 = 0; + pCam->getIntParameter(CameraParam::AUTO_FOCUS, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + if (val1 != 0) { + pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val1, 0); + } + } + + // Try to program a parameter with a random value [minVal, maxVal] + int32_t val0 = minVal + (std::rand() % (maxVal - minVal)); + int32_t val1 = 0; + + // Rounding down + val0 = val0 - (val0 % step); + pCam->setIntParameter(cmd, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + + ASSERT_EQ(EvsResult::OK, result); + + pCam->getIntParameter(cmd, [&result, &val1](auto status, auto value) { result = status; if (status == EvsResult::OK) { val1 = value; } }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - ASSERT_EQ(val0, val1) << "Values are not matched."; - } - - val0 = 80; - val1 = 0; - pCam->setParameter(CameraParam::CONTRAST, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - - if (result == EvsResult::OK) { - pCam->getParameter(CameraParam::CONTRAST, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - ASSERT_EQ(val0, val1) << "Values are not matched."; - } - - val0 = 300; - val1 = 0; - pCam->setParameter(CameraParam::ABSOLUTE_ZOOM, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - - if (result == EvsResult::OK) { - pCam->getParameter(CameraParam::ABSOLUTE_ZOOM, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); + ASSERT_EQ(EvsResult::OK, result); ASSERT_EQ(val0, val1) << "Values are not matched."; } result = pCam->unsetMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); // Shutdown frameHandler->shutdown(); @@ -650,15 +698,19 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera for (auto&& cam: cameraInfo) { // Create two camera clients. sp pCamMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCamMaster, nullptr); sp pCamNonMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCamNonMaster, nullptr); @@ -698,15 +750,15 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { // Non-master client expects to receive a master role relesed // notification. - InfoEventDesc aNotification = {}; + EvsEvent aNotification = {}; // Release a master role. pCamMaster->unsetMaster(); // Verify a change notification. - frameHandlerNonMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); - ASSERT_EQ(InfoEventType::MASTER_RELEASED, - static_cast(aNotification.aType)); + frameHandlerNonMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(EvsEventType::MASTER_RELEASED, + static_cast(aNotification.aType)); // Non-master becomes a master. result = pCamNonMaster->setMaster(); @@ -720,9 +772,9 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { frameHandlerNonMaster->shutdown(); // Verify a change notification. - frameHandlerMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); - ASSERT_EQ(InfoEventType::MASTER_RELEASED, - static_cast(aNotification.aType)); + frameHandlerMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(EvsEventType::MASTER_RELEASED, + static_cast(aNotification.aType)); // Closing another stream. frameHandlerMaster->shutdown(); @@ -752,18 +804,46 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera for (auto&& cam: cameraInfo) { // Create two camera clients. sp pCamMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCamMaster, nullptr); sp pCamNonMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCamNonMaster, nullptr); + // Get the parameter list + std::vector camMasterCmds, camNonMasterCmds; + pCamMaster->getParameterList([&camMasterCmds](hidl_vec cmdList) { + camMasterCmds.reserve(cmdList.size()); + for (auto &&cmd : cmdList) { + camMasterCmds.push_back(cmd); + } + } + ); + + pCamNonMaster->getParameterList([&camNonMasterCmds](hidl_vec cmdList) { + camNonMasterCmds.reserve(cmdList.size()); + for (auto &&cmd : cmdList) { + camNonMasterCmds.push_back(cmd); + } + } + ); + + if (camMasterCmds.size() < 1 || + camNonMasterCmds.size() < 1) { + // Skip a camera device if it does not support any parameter. + continue; + } + // Set up per-client frame receiver objects which will fire up its own thread sp frameHandlerMaster = new FrameHandler(pCamMaster, cam, @@ -778,11 +858,11 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Set one client as the master EvsResult result = pCamMaster->setMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); // Try to set another client as the master. result = pCamNonMaster->setMaster(); - ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST); + ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result); // Start the camera's video stream via a master client. bool startResult = frameHandlerMaster->startStream(); @@ -798,131 +878,168 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Ensure the stream starts frameHandlerNonMaster->waitForFrameCount(1); - // Try to program CameraParam::BRIGHTNESS - int32_t val0 = 100; + int32_t val0 = 0; int32_t val1 = 0; + for (auto &cmd : camMasterCmds) { + // Get a valid parameter value range + int32_t minVal, maxVal, step; + pCamMaster->getIntParameterRange( + cmd, + [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { + minVal = val0; + maxVal = val1; + step = val2; + } + ); - pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program - result == EvsResult::INVALID_ARG); // Camera parameter is not supported + EvsResult result = EvsResult::OK; + if (cmd == CameraParam::ABSOLUTE_FOCUS) { + // Try to turn off auto-focus + int32_t val1 = 1; + pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val1, 0); + } - // Non-master client expects to receive a parameter change notification - // whenever a master client adjusts it. - InfoEventDesc aNotification = {}; + // Try to program a parameter + val0 = minVal + (std::rand() % (maxVal - minVal)); - pCamMaster->getParameter(CameraParam::BRIGHTNESS, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program - result == EvsResult::INVALID_ARG); // Camera parameter is not supported - if (result == EvsResult::OK) { - ASSERT_EQ(val0, val1) << "Values are not matched."; + // Rounding down + val0 = val0 - (val0 % step); + pCamMaster->setIntParameter(cmd, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); - // Verify a change notification - frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); - ASSERT_EQ(InfoEventType::PARAMETER_CHANGED, - static_cast(aNotification.aType)); - ASSERT_EQ(CameraParam::BRIGHTNESS, - static_cast(aNotification.payload[0])); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); - } + // Wait a moment + sleep(1); - // Try to program CameraParam::CONTRAST - val0 = 80; - val1 = 0; - pCamMaster->setParameter(CameraParam::CONTRAST, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program - result == EvsResult::INVALID_ARG); // Camera parameter is not supported + // Non-master client expects to receive a parameter change notification + // whenever a master client adjusts it. + EvsEvent aNotification = {}; - if (result == EvsResult::OK) { - pCamMaster->getParameter(CameraParam::CONTRAST, + pCamMaster->getIntParameter(cmd, [&result, &val1](auto status, auto value) { result = status; if (status == EvsResult::OK) { val1 = value; } }); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); ASSERT_EQ(val0, val1) << "Values are not matched."; - // Verify a change notification - frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); - ASSERT_EQ(InfoEventType::PARAMETER_CHANGED, - static_cast(aNotification.aType)); - ASSERT_EQ(CameraParam::CONTRAST, + frameHandlerNonMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); + ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, + static_cast(aNotification.aType)); + ASSERT_EQ(cmd, static_cast(aNotification.payload[0])); ASSERT_EQ(val1, static_cast(aNotification.payload[1])); } // Try to adjust a parameter via non-master client - pCamNonMaster->setParameter(CameraParam::CONTRAST, val0, + pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_TRUE(result == EvsResult::INVALID_ARG); + ASSERT_EQ(EvsResult::INVALID_ARG, result); // Non-master client attemps to be a master result = pCamNonMaster->setMaster(); - ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST); + ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result); // Master client retires from a master role result = pCamMaster->unsetMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); // Try to adjust a parameter after being retired - pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0, + pCamMaster->setIntParameter(camMasterCmds[0], val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_TRUE(result == EvsResult::INVALID_ARG); + ASSERT_EQ(EvsResult::INVALID_ARG, result); // Non-master client becomes a master result = pCamNonMaster->setMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); // Try to adjust a parameter via new master client - pCamNonMaster->setParameter(CameraParam::BRIGHTNESS, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program - result == EvsResult::INVALID_ARG); // Camera parameter is not supported + for (auto &cmd : camNonMasterCmds) { + // Get a valid parameter value range + int32_t minVal, maxVal, step; + pCamNonMaster->getIntParameterRange( + cmd, + [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { + minVal = val0; + maxVal = val1; + step = val2; + } + ); - // Wait a moment - sleep(1); + EvsResult result = EvsResult::OK; + if (cmd == CameraParam::ABSOLUTE_FOCUS) { + // Try to turn off auto-focus + int32_t val1 = 1; + pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val1, 0); + } - // Verify a change notification - if (result == EvsResult::OK) { - frameHandlerMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); - ASSERT_EQ(static_cast(aNotification.aType), - InfoEventType::PARAMETER_CHANGED); - ASSERT_EQ(static_cast(aNotification.payload[0]), - CameraParam::BRIGHTNESS); + // Try to program a parameter + val0 = minVal + (std::rand() % (maxVal - minVal)); + + // Rounding down + val0 = val0 - (val0 % step); + pCamNonMaster->setIntParameter(cmd, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + + // Wait a moment + sleep(1); + + // Non-master client expects to receive a parameter change notification + // whenever a master client adjusts it. + EvsEvent aNotification = {}; + + pCamNonMaster->getIntParameter(cmd, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val0, val1) << "Values are not matched."; + + // Verify a change notification + frameHandlerMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); + ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, + static_cast(aNotification.aType)); + ASSERT_EQ(cmd, + static_cast(aNotification.payload[0])); ASSERT_EQ(val1, static_cast(aNotification.payload[1])); } // New master retires from a master role result = pCamNonMaster->unsetMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); // Shutdown frameHandlerMaster->shutdown(); @@ -943,9 +1060,18 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { TEST_F(EvsHidlTest, HighPriorityCameraClient) { ALOGI("Starting HighPriorityCameraClient test"); + if (mIsHwModule) { + // This test is not for HW module implementation. + return; + } + // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Request exclusive access to the EVS display sp pDisplay = pEnumerator->openDisplay(); ASSERT_NE(pDisplay, nullptr); @@ -954,15 +1080,38 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { for (auto&& cam: cameraInfo) { // Create two clients sp pCam0 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam0, nullptr); sp pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam1, nullptr); + // Get the parameter list; this test will use the first command in both + // lists. + std::vector cam0Cmds, cam1Cmds; + pCam0->getParameterList([&cam0Cmds](hidl_vec cmdList) { + cam0Cmds.reserve(cmdList.size()); + for (auto &&cmd : cmdList) { + cam0Cmds.push_back(cmd); + } + } + ); + + pCam1->getParameterList([&cam1Cmds](hidl_vec cmdList) { + cam1Cmds.reserve(cmdList.size()); + for (auto &&cmd : cmdList) { + cam1Cmds.push_back(cmd); + } + } + ); + if (cam0Cmds.size() < 1 || cam1Cmds.size() < 1) { + // Cannot execute this test. + return; + } + // Set up a frame receiver object which will fire up its own thread. sp frameHandler0 = new FrameHandler(pCam0, cam, pDisplay, @@ -982,67 +1131,121 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { frameHandler0->waitForFrameCount(1); frameHandler1->waitForFrameCount(1); - // Client 1 becomes a master and programs a brightness. + // Client 1 becomes a master and programs a parameter. EvsResult result = EvsResult::OK; - int32_t val0 = 100; + // Get a valid parameter value range + int32_t minVal, maxVal, step; + pCam1->getIntParameterRange( + cam1Cmds[0], + [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { + minVal = val0; + maxVal = val1; + step = val2; + } + ); + + if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) { + // Try to turn off auto-focus + int32_t val1 = 0; + pCam1->getIntParameter(CameraParam::AUTO_FOCUS, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + if (val1 != 0) { + pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val1, 0); + } + } + + // Try to program a parameter with a random value [minVal, maxVal] + int32_t val0 = minVal + (std::rand() % (maxVal - minVal)); int32_t val1 = 0; - result = pCam1->setMaster(); - ASSERT_TRUE(result == EvsResult::OK); + // Rounding down + val0 = val0 - (val0 % step); - pCam1->setParameter(CameraParam::BRIGHTNESS, val0, + result = pCam1->setMaster(); + ASSERT_EQ(EvsResult::OK, result); + + pCam1->setIntParameter(cam1Cmds[0], val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - + ASSERT_EQ(EvsResult::OK, result); // Verify a change notification - InfoEventDesc aNotification = {}; - if (result == EvsResult::OK) { - bool timeout = - frameHandler0->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); - ASSERT_FALSE(timeout) << "Expected event does not arrive"; - ASSERT_EQ(static_cast(aNotification.aType), - InfoEventType::PARAMETER_CHANGED); - ASSERT_EQ(static_cast(aNotification.payload[0]), - CameraParam::BRIGHTNESS); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); - } + EvsEvent aNotification = {}; + bool timeout = + frameHandler0->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); + ASSERT_FALSE(timeout) << "Expected event does not arrive"; + ASSERT_EQ(static_cast(aNotification.aType), + EvsEventType::PARAMETER_CHANGED); + ASSERT_EQ(static_cast(aNotification.payload[0]), + cam1Cmds[0]); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); // Client 0 steals a master role ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay)); - frameHandler1->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); - ASSERT_EQ(static_cast(aNotification.aType), - InfoEventType::MASTER_RELEASED); + frameHandler1->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(static_cast(aNotification.aType), + EvsEventType::MASTER_RELEASED); - // Client 0 programs a brightness - val0 = 50; + // Client 0 programs a parameter + val0 = minVal + (std::rand() % (maxVal - minVal)); val1 = 0; - pCam0->setParameter(CameraParam::BRIGHTNESS, val0, + + // Rounding down + val0 = val0 - (val0 % step); + + if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) { + // Try to turn off auto-focus + int32_t val1 = 0; + pCam0->getIntParameter(CameraParam::AUTO_FOCUS, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + if (val1 != 0) { + pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val1, 0); + } + } + + pCam0->setIntParameter(cam0Cmds[0], val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); + ASSERT_EQ(EvsResult::OK, result); // Verify a change notification - if (result == EvsResult::OK) { - bool timeout = - frameHandler1->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); - ASSERT_FALSE(timeout) << "Expected event does not arrive"; - ASSERT_EQ(static_cast(aNotification.aType), - InfoEventType::PARAMETER_CHANGED); - ASSERT_EQ(static_cast(aNotification.payload[0]), - CameraParam::BRIGHTNESS); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); - } + timeout = + frameHandler1->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); + ASSERT_FALSE(timeout) << "Expected event does not arrive"; + ASSERT_EQ(static_cast(aNotification.aType), + EvsEventType::PARAMETER_CHANGED); + ASSERT_EQ(static_cast(aNotification.payload[0]), + cam0Cmds[0]); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); // Turn off the display (yes, before the stream stops -- it should be handled) pDisplay->setDisplayState(DisplayState::NOT_VISIBLE); @@ -1061,6 +1264,248 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { } +/* + * CameraUseStreamConfigToDisplay: + * End to end test of data flowing from the camera to the display. Similar to + * CameraToDisplayRoundTrip test case but this case retrieves available stream + * configurations from EVS and uses one of them to start a video stream. + */ +TEST_F(EvsHidlTest, CameraUseStreamConfigToDisplay) { + ALOGI("Starting CameraUseStreamConfigToDisplay test"); + + // Get the camera list + loadCameraList(); + + // Request exclusive access to the EVS display + sp pDisplay = pEnumerator->openDisplay(); + ASSERT_NE(pDisplay, nullptr); + + // Test each reported camera + for (auto&& cam: cameraInfo) { + // choose a configuration that has a frame rate faster than minReqFps. + Stream targetCfg = {}; + const int32_t minReqFps = 15; + int32_t maxArea = 0; + camera_metadata_entry_t streamCfgs; + bool foundCfg = false; + if (!find_camera_metadata_entry( + reinterpret_cast(cam.metadata.data()), + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, + &streamCfgs)) { + // Stream configurations are found in metadata + RawStreamConfig *ptr = reinterpret_cast(streamCfgs.data.i32); + for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) { + if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && + ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) { + + if (ptr->width * ptr->height > maxArea && + ptr->framerate >= minReqFps) { + targetCfg.width = ptr->width; + targetCfg.height = ptr->height; + + maxArea = ptr->width * ptr->height; + foundCfg = true; + } + } + ++ptr; + } + } + targetCfg.format = + static_cast(HAL_PIXEL_FORMAT_RGBA_8888); + + if (!foundCfg) { + // Current EVS camera does not provide stream configurations in the + // metadata. + continue; + } + + sp pCam = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) + .withDefault(nullptr); + ASSERT_NE(pCam, nullptr); + + // Set up a frame receiver object which will fire up its own thread. + sp frameHandler = new FrameHandler(pCam, cam, + pDisplay, + FrameHandler::eAutoReturn); + + + // Activate the display + pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME); + + // Start the camera's video stream + bool startResult = frameHandler->startStream(); + ASSERT_TRUE(startResult); + + // Wait a while to let the data flow + static const int kSecondsToWait = 5; + const int streamTimeMs = kSecondsToWait * kSecondsToMilliseconds - + kMaxStreamStartMilliseconds; + const unsigned minimumFramesExpected = streamTimeMs * kMinimumFramesPerSecond / + kSecondsToMilliseconds; + sleep(kSecondsToWait); + unsigned framesReceived = 0; + unsigned framesDisplayed = 0; + frameHandler->getFramesCounters(&framesReceived, &framesDisplayed); + EXPECT_EQ(framesReceived, framesDisplayed); + EXPECT_GE(framesDisplayed, minimumFramesExpected); + + // Turn off the display (yes, before the stream stops -- it should be handled) + pDisplay->setDisplayState(DisplayState::NOT_VISIBLE); + + // Shut down the streamer + frameHandler->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCam); + } + + // Explicitly release the display + pEnumerator->closeDisplay(pDisplay); +} + + +/* + * MultiCameraStreamUseConfig: + * Verify that each client can start and stop video streams on the same + * underlying camera with same configuration. + */ +TEST_F(EvsHidlTest, MultiCameraStreamUseConfig) { + ALOGI("Starting MultiCameraStream test"); + + if (mIsHwModule) { + // This test is not for HW module implementation. + return; + } + + // Get the camera list + loadCameraList(); + + // Test each reported camera + for (auto&& cam: cameraInfo) { + // choose a configuration that has a frame rate faster than minReqFps. + Stream targetCfg = {}; + const int32_t minReqFps = 15; + int32_t maxArea = 0; + camera_metadata_entry_t streamCfgs; + bool foundCfg = false; + if (!find_camera_metadata_entry( + reinterpret_cast(cam.metadata.data()), + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, + &streamCfgs)) { + // Stream configurations are found in metadata + RawStreamConfig *ptr = reinterpret_cast(streamCfgs.data.i32); + for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) { + if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && + ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) { + + if (ptr->width * ptr->height > maxArea && + ptr->framerate >= minReqFps) { + targetCfg.width = ptr->width; + targetCfg.height = ptr->height; + + maxArea = ptr->width * ptr->height; + foundCfg = true; + } + } + ++ptr; + } + } + targetCfg.format = + static_cast(HAL_PIXEL_FORMAT_RGBA_8888); + + if (!foundCfg) { + ALOGI("Device %s does not provide a list of supported stream configurations, skipped", + cam.v1.cameraId.c_str()); + + continue; + } + + // Create the first camera client with a selected stream configuration. + sp pCam0 = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) + .withDefault(nullptr); + ASSERT_NE(pCam0, nullptr); + + // Try to create the second camera client with different stream + // configuration. + int32_t id = targetCfg.id; + targetCfg.id += 1; // EVS manager sees only the stream id. + sp pCam1 = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) + .withDefault(nullptr); + ASSERT_EQ(pCam1, nullptr); + + // Try again with same stream configuration. + targetCfg.id = id; + pCam1 = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) + .withDefault(nullptr); + ASSERT_NE(pCam1, nullptr); + + // Set up per-client frame receiver objects which will fire up its own thread + sp frameHandler0 = new FrameHandler(pCam0, cam, + nullptr, + FrameHandler::eAutoReturn); + ASSERT_NE(frameHandler0, nullptr); + + sp frameHandler1 = new FrameHandler(pCam1, cam, + nullptr, + FrameHandler::eAutoReturn); + ASSERT_NE(frameHandler1, nullptr); + + // Start the camera's video stream via client 0 + bool startResult = false; + startResult = frameHandler0->startStream() && + frameHandler1->startStream(); + ASSERT_TRUE(startResult); + + // Ensure the stream starts + frameHandler0->waitForFrameCount(1); + frameHandler1->waitForFrameCount(1); + + nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC); + + // Wait a bit, then ensure both clients get at least the required minimum number of frames + sleep(5); + nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC); + unsigned framesReceived0 = 0, framesReceived1 = 0; + frameHandler0->getFramesCounters(&framesReceived0, nullptr); + frameHandler1->getFramesCounters(&framesReceived1, nullptr); + framesReceived0 = framesReceived0 - 1; // Back out the first frame we already waited for + framesReceived1 = framesReceived1 - 1; // Back out the first frame we already waited for + nsecs_t runTime = end - firstFrame; + float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds); + float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds); + ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1); + EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond); + EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond); + + // Shutdown one client + frameHandler0->shutdown(); + + // Read frame counters again + frameHandler0->getFramesCounters(&framesReceived0, nullptr); + frameHandler1->getFramesCounters(&framesReceived1, nullptr); + + // Wait a bit again + sleep(5); + unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0; + frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr); + frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr); + EXPECT_EQ(framesReceived0, framesReceivedAfterStop0); + EXPECT_LT(framesReceived1, framesReceivedAfterStop1); + + // Shutdown another + frameHandler1->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCam0); + pEnumerator->closeCamera(pCam1); + } +} + + int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance()); ::testing::InitGoogleTest(&argc, argv); From 1b73d28c04d250b581860dde082cf92c366371dc Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Fri, 11 Oct 2019 10:13:38 -0700 Subject: [PATCH 0176/1022] Revert "Extend EVS interfaces and data types" This reverts commit e6976fce80a9a0951c6bc6f668b2de032ccc4d34. --- automotive/evs/1.1/Android.bp | 4 +- automotive/evs/1.1/IEvsCamera.hal | 34 +- automotive/evs/1.1/IEvsCameraStream.hal | 19 +- automotive/evs/1.1/IEvsEnumerator.hal | 50 - automotive/evs/1.1/default/Android.bp | 20 +- automotive/evs/1.1/default/ConfigManager.cpp | 487 ---------- automotive/evs/1.1/default/ConfigManager.h | 336 ------- .../evs/1.1/default/ConfigManagerUtil.cpp | 131 --- .../evs/1.1/default/ConfigManagerUtil.h | 61 -- automotive/evs/1.1/default/EvsCamera.cpp | 108 +-- automotive/evs/1.1/default/EvsCamera.h | 28 +- automotive/evs/1.1/default/EvsEnumerator.cpp | 109 +-- automotive/evs/1.1/default/EvsEnumerator.h | 25 +- .../resources/evs_default_configuration.xml | 68 -- automotive/evs/1.1/default/service.cpp | 2 +- automotive/evs/1.1/types.hal | 49 +- automotive/evs/1.1/vts/functional/Android.bp | 2 - .../evs/1.1/vts/functional/FrameHandler.cpp | 187 ++-- .../evs/1.1/vts/functional/FrameHandler.h | 23 +- .../functional/VtsHalEvsV1_1TargetTest.cpp | 899 +++++------------- 20 files changed, 413 insertions(+), 2229 deletions(-) delete mode 100644 automotive/evs/1.1/IEvsEnumerator.hal delete mode 100644 automotive/evs/1.1/default/ConfigManager.cpp delete mode 100644 automotive/evs/1.1/default/ConfigManager.h delete mode 100644 automotive/evs/1.1/default/ConfigManagerUtil.cpp delete mode 100644 automotive/evs/1.1/default/ConfigManagerUtil.h delete mode 100644 automotive/evs/1.1/default/resources/evs_default_configuration.xml diff --git a/automotive/evs/1.1/Android.bp b/automotive/evs/1.1/Android.bp index c850c91b21..d2e85f1304 100644 --- a/automotive/evs/1.1/Android.bp +++ b/automotive/evs/1.1/Android.bp @@ -10,15 +10,13 @@ hidl_interface { "types.hal", "IEvsCamera.hal", "IEvsCameraStream.hal", - "IEvsEnumerator.hal", ], interfaces: [ "android.hardware.automotive.evs@1.0", - "android.hardware.camera.device@3.2", "android.hardware.graphics.common@1.0", "android.hardware.graphics.common@1.1", "android.hardware.graphics.common@1.2", "android.hidl.base@1.0", ], - gen_java: false, + gen_java: true, } diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal index 975b6c6cae..21ca79e91f 100644 --- a/automotive/evs/1.1/IEvsCamera.hal +++ b/automotive/evs/1.1/IEvsCamera.hal @@ -25,14 +25,6 @@ import IEvsCameraStream; * Represents a single camera and is the primary interface for capturing images. */ interface IEvsCamera extends @1.0::IEvsCamera { - /** - * Returns the description of this camera. - * - * @return info The description of this camera. This must be the same value as - * reported by EvsEnumerator::getCameraList_1_1(). - */ - getCameraInfo_1_1() generates (CameraDesc info); - /** * Requests to pause EVS camera stream events. * @@ -108,27 +100,7 @@ interface IEvsCamera extends @1.0::IEvsCamera { unsetMaster() generates (EvsResult result); /** - * Retrieves a list of parameters this camera supports. - * - * @return params A list of CameraParam that this camera supports. - */ - getParameterList() generates (vec params); - - /** - * Requests a valid value range of a camera parameter - * - * @param id The identifier of camera parameter, CameraParam enum. - * - * @return min The lower bound of valid parameter value range. - * @return max The upper bound of valid parameter value range. - * @return step The resolution of values in valid range. - */ - getIntParameterRange(CameraParam id) - generates (int32_t min, int32_t max, int32_t step); - - /** - * Requests to set a camera parameter. Only a request from the master - * client will be processed successfully. + * Requests to set a camera parameter. * * @param id The identifier of camera parameter, CameraParam enum. * value A desired parameter value. @@ -142,7 +114,7 @@ interface IEvsCamera extends @1.0::IEvsCamera { * from what the client gives if, for example, the * driver does not support a target parameter. */ - setIntParameter(CameraParam id, int32_t value) + setParameter(CameraParam id, int32_t value) generates (EvsResult result, int32_t effectiveValue); /** @@ -154,5 +126,5 @@ interface IEvsCamera extends @1.0::IEvsCamera { * not supported. * value A value of requested camera parameter. */ - getIntParameter(CameraParam id) generates(EvsResult result, int32_t value); + getParameter(CameraParam id) generates(EvsResult result, int32_t value); }; diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal index 9e4ea19f1d..7c7f832103 100644 --- a/automotive/evs/1.1/IEvsCameraStream.hal +++ b/automotive/evs/1.1/IEvsCameraStream.hal @@ -17,32 +17,15 @@ package android.hardware.automotive.evs@1.1; import @1.0::IEvsCameraStream; -import @1.1::BufferDesc; -import @1.1::EvsEvent; /** * Implemented on client side to receive asynchronous streaming event deliveries. */ interface IEvsCameraStream extends @1.0::IEvsCameraStream { - - /** - * Receives calls from the HAL each time a video frame is ready for inspection. - * Buffer handles received by this method must be returned via calls to - * IEvsCamera::doneWithFrame_1_1(). When the video stream is stopped via a call - * to IEvsCamera::stopVideoStream(), this callback may continue to happen for - * some time as the pipeline drains. Each frame must still be returned. - * When the last frame in the stream has been delivered, STREAM_STOPPED - * event must be delivered. No further frame deliveries may happen - * thereafter. - * - * @param buffer a buffer descriptor of a delivered image frame. - */ - oneway deliverFrame_1_1(BufferDesc buffer); - /** * Receives calls from the HAL each time an event happens. * * @param event EVS event with possible event information. */ - oneway notify(EvsEvent event); + oneway notifyEvent(EvsEvent event); }; diff --git a/automotive/evs/1.1/IEvsEnumerator.hal b/automotive/evs/1.1/IEvsEnumerator.hal deleted file mode 100644 index 1695821baa..0000000000 --- a/automotive/evs/1.1/IEvsEnumerator.hal +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - */ - -package android.hardware.automotive.evs@1.1; - -import IEvsCamera; -import @1.0::IEvsEnumerator; -import @1.0::EvsResult; -import android.hardware.camera.device@3.2::Stream; - -/** - * Provides the mechanism for EVS camera discovery - */ -interface IEvsEnumerator extends @1.0::IEvsEnumerator { - /** - * Returns a list of all EVS cameras available to the system - * - * @return cameras A list of cameras availale for EVS service. - */ - getCameraList_1_1() generates (vec cameras); - - /** - * Gets the IEvsCamera associated with a cameraId from a CameraDesc - * - * Given a camera's unique cameraId from CameraDesc, returns the - * IEvsCamera interface associated with the specified camera. When - * done using the camera, the caller may release it by calling closeCamera(). - * - * @param cameraId A unique identifier of the camera. - * @param streamCfg A stream configuration the client wants to use. - * @return evsCamera EvsCamera object associated with a given cameraId. - * Returned object would be null if a camera device does - * not support a given stream configuration or is already - * configured differently by another client. - */ - openCamera_1_1(string cameraId, Stream streamCfg) generates (IEvsCamera evsCamera); -}; diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp index 41cb4265e5..a46347102f 100644 --- a/automotive/evs/1.1/default/Android.bp +++ b/automotive/evs/1.1/default/Android.bp @@ -7,41 +7,25 @@ cc_binary { "service.cpp", "EvsCamera.cpp", "EvsEnumerator.cpp", - "EvsDisplay.cpp", - "ConfigManager.cpp", - "ConfigManagerUtil.cpp", + "EvsDisplay.cpp" ], init_rc: ["android.hardware.automotive.evs@1.1-service.rc"], shared_libs: [ "android.hardware.automotive.evs@1.0", "android.hardware.automotive.evs@1.1", - "android.hardware.camera.device@3.2", "libbase", "libbinder", - "liblog", + "libcutils", "libhardware", "libhidlbase", "liblog", "libui", "libutils", - "libcamera_metadata", - "libtinyxml2", ], cflags: [ "-O0", "-g", ], - - required: [ - "evs_default_configuration.xml", - ], -} - -prebuilt_etc { - name: "evs_default_configuration.xml", - - src: "resources/evs_default_configuration.xml", - sub_dir: "automotive/evs", } diff --git a/automotive/evs/1.1/default/ConfigManager.cpp b/automotive/evs/1.1/default/ConfigManager.cpp deleted file mode 100644 index 4f46f9dbca..0000000000 --- a/automotive/evs/1.1/default/ConfigManager.cpp +++ /dev/null @@ -1,487 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include - -#include -#include -#include - -#include "ConfigManager.h" - -using ::android::hardware::camera::device::V3_2::StreamRotation; - - -ConfigManager::~ConfigManager() { - /* Nothing to do */ -} - - -void ConfigManager::readCameraInfo(const XMLElement * const aCameraElem) { - if (aCameraElem == nullptr) { - ALOGW("XML file does not have required camera element"); - return; - } - - const XMLElement *curElem = aCameraElem->FirstChildElement(); - while (curElem != nullptr) { - if (!strcmp(curElem->Name(), "group")) { - /* camera group identifier */ - const char *group_id = curElem->FindAttribute("group_id")->Value(); - - /* create CameraGroup */ - unique_ptr aCameraGroup(new ConfigManager::CameraGroup()); - - /* add a camera device to its group */ - addCameraDevices(curElem->FindAttribute("device_id")->Value(), aCameraGroup); - - /* a list of camera stream configurations */ - const XMLElement *childElem = - curElem->FirstChildElement("caps")->FirstChildElement("stream"); - while (childElem != nullptr) { - /* read 5 attributes */ - const XMLAttribute *idAttr = childElem->FindAttribute("id"); - const XMLAttribute *widthAttr = childElem->FindAttribute("width"); - const XMLAttribute *heightAttr = childElem->FindAttribute("height"); - const XMLAttribute *fmtAttr = childElem->FindAttribute("format"); - const XMLAttribute *fpsAttr = childElem->FindAttribute("framerate"); - - const int32_t id = stoi(idAttr->Value()); - int32_t framerate = 0; - if (fpsAttr != nullptr) { - framerate = stoi(fpsAttr->Value()); - } - - int32_t pixFormat; - if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), - pixFormat)) { - RawStreamConfiguration cfg = { - id, - stoi(widthAttr->Value()), - stoi(heightAttr->Value()), - pixFormat, - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, - framerate - }; - aCameraGroup->streamConfigurations[id] = cfg; - } - - childElem = childElem->NextSiblingElement("stream"); - } - - /* camera group synchronization */ - const char *sync = curElem->FindAttribute("synchronized")->Value(); - aCameraGroup->synchronized = - static_cast(strcmp(sync, "false")); - - /* add a group to hash map */ - mCameraGroups[group_id] = std::move(aCameraGroup); - } else if (!strcmp(curElem->Name(), "device")) { - /* camera unique identifier */ - const char *id = curElem->FindAttribute("id")->Value(); - - /* camera mount location */ - const char *pos = curElem->FindAttribute("position")->Value(); - - /* store read camera module information */ - mCameraInfo[id] = readCameraDeviceInfo(curElem); - - /* assign a camera device to a position group */ - mCameraPosition[pos].emplace(id); - } else { - /* ignore other device types */ - ALOGD("Unknown element %s is ignored", curElem->Name()); - } - - curElem = curElem->NextSiblingElement(); - } -} - - -unique_ptr -ConfigManager::readCameraDeviceInfo(const XMLElement *aDeviceElem) { - if (aDeviceElem == nullptr) { - return nullptr; - } - - /* create a CameraInfo to be filled */ - unique_ptr aCamera(new ConfigManager::CameraInfo()); - - /* size information to allocate camera_metadata_t */ - size_t totalEntries = 0; - size_t totalDataSize = 0; - - /* read device capabilities */ - totalEntries += - readCameraCapabilities(aDeviceElem->FirstChildElement("caps"), - aCamera, - totalDataSize); - - - /* read camera metadata */ - totalEntries += - readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"), - aCamera, - totalDataSize); - - /* construct camera_metadata_t */ - if (!constructCameraMetadata(aCamera, totalEntries, totalDataSize)) { - ALOGW("Either failed to allocate memory or " - "allocated memory was not large enough"); - } - - return aCamera; -} - - -size_t ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem, - unique_ptr &aCamera, - size_t &dataSize) { - if (aCapElem == nullptr) { - return 0; - } - - string token; - const XMLElement *curElem = nullptr; - - /* a list of supported camera parameters/controls */ - curElem = aCapElem->FirstChildElement("supported_controls"); - if (curElem != nullptr) { - const XMLElement *ctrlElem = curElem->FirstChildElement("control"); - while (ctrlElem != nullptr) { - const char *nameAttr = ctrlElem->FindAttribute("name")->Value();; - const int32_t minVal = stoi(ctrlElem->FindAttribute("min")->Value()); - const int32_t maxVal = stoi(ctrlElem->FindAttribute("max")->Value()); - - int32_t stepVal = 1; - const XMLAttribute *stepAttr = ctrlElem->FindAttribute("step"); - if (stepAttr != nullptr) { - stepVal = stoi(stepAttr->Value()); - } - - CameraParam aParam; - if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr, - aParam)) { - aCamera->controls.emplace( - aParam, - make_tuple(minVal, maxVal, stepVal) - ); - } - - ctrlElem = ctrlElem->NextSiblingElement("control"); - } - } - - /* a list of camera stream configurations */ - curElem = aCapElem->FirstChildElement("stream"); - while (curElem != nullptr) { - /* read 5 attributes */ - const XMLAttribute *idAttr = curElem->FindAttribute("id"); - const XMLAttribute *widthAttr = curElem->FindAttribute("width"); - const XMLAttribute *heightAttr = curElem->FindAttribute("height"); - const XMLAttribute *fmtAttr = curElem->FindAttribute("format"); - const XMLAttribute *fpsAttr = curElem->FindAttribute("framerate"); - - const int32_t id = stoi(idAttr->Value()); - int32_t framerate = 0; - if (fpsAttr != nullptr) { - framerate = stoi(fpsAttr->Value()); - } - - int32_t pixFormat; - if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), - pixFormat)) { - RawStreamConfiguration cfg = { - id, - stoi(widthAttr->Value()), - stoi(heightAttr->Value()), - pixFormat, - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, - framerate - }; - aCamera->streamConfigurations[id] = cfg; - } - - curElem = curElem->NextSiblingElement("stream"); - } - - dataSize = calculate_camera_metadata_entry_data_size( - get_camera_metadata_tag_type( - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS - ), - aCamera->streamConfigurations.size() * kStreamCfgSz - ); - - /* a single camera metadata entry contains multiple stream configurations */ - return dataSize > 0 ? 1 : 0; -} - - -size_t ConfigManager::readCameraMetadata(const XMLElement * const aParamElem, - unique_ptr &aCamera, - size_t &dataSize) { - if (aParamElem == nullptr) { - return 0; - } - - const XMLElement *curElem = aParamElem->FirstChildElement("parameter"); - size_t numEntries = 0; - camera_metadata_tag_t tag; - while (curElem != nullptr) { - if (!ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(), - tag)) { - switch(tag) { - case ANDROID_LENS_DISTORTION: - case ANDROID_LENS_POSE_ROTATION: - case ANDROID_LENS_POSE_TRANSLATION: - case ANDROID_LENS_INTRINSIC_CALIBRATION: { - /* float[] */ - size_t count = 0; - void *data = ConfigManagerUtil::convertFloatArray( - curElem->FindAttribute("size")->Value(), - curElem->FindAttribute("value")->Value(), - count - ); - - aCamera->cameraMetadata[tag] = - make_pair(make_unique(data), count); - - ++numEntries; - dataSize += calculate_camera_metadata_entry_data_size( - get_camera_metadata_tag_type(tag), count - ); - - break; - } - - default: - ALOGW("Parameter %s is not supported", - curElem->FindAttribute("name")->Value()); - break; - } - } - - curElem = curElem->NextSiblingElement("parameter"); - } - - return numEntries; -} - - -bool ConfigManager::constructCameraMetadata(unique_ptr &aCamera, - const size_t totalEntries, - const size_t totalDataSize) { - if (!aCamera->allocate(totalEntries, totalDataSize)) { - ALOGE("Failed to allocate memory for camera metadata"); - return false; - } - - const size_t numStreamConfigs = aCamera->streamConfigurations.size(); - unique_ptr data(new int32_t[kStreamCfgSz * numStreamConfigs]); - int32_t *ptr = data.get(); - for (auto &cfg : aCamera->streamConfigurations) { - for (auto i = 0; i < kStreamCfgSz; ++i) { - *ptr++ = cfg.second[i]; - } - } - int32_t err = add_camera_metadata_entry(aCamera->characteristics, - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, - data.get(), - numStreamConfigs * kStreamCfgSz); - - if (err) { - ALOGE("Failed to add stream configurations to metadata, ignored"); - return false; - } - - bool success = true; - for (auto &[tag, entry] : aCamera->cameraMetadata) { - /* try to add new camera metadata entry */ - int32_t err = add_camera_metadata_entry(aCamera->characteristics, - tag, - entry.first.get(), - entry.second); - if (err) { - ALOGE("Failed to add an entry with a tag 0x%X", tag); - - /* may exceed preallocated capacity */ - ALOGE("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled", - get_camera_metadata_entry_count(aCamera->characteristics), - get_camera_metadata_entry_capacity(aCamera->characteristics), - get_camera_metadata_data_count(aCamera->characteristics), - get_camera_metadata_data_capacity(aCamera->characteristics)); - ALOGE("\tCurrent metadata entry requires %ld bytes", - calculate_camera_metadata_entry_data_size(tag, entry.second)); - - success = false; - } - } - - ALOGV("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled", - get_camera_metadata_entry_count(aCamera->characteristics), - get_camera_metadata_entry_capacity(aCamera->characteristics), - get_camera_metadata_data_count(aCamera->characteristics), - get_camera_metadata_data_capacity(aCamera->characteristics)); - - return success; -} - - -void ConfigManager::readSystemInfo(const XMLElement * const aSysElem) { - if (aSysElem == nullptr) { - return; - } - - /* - * Please note that this function assumes that a given system XML element - * and its child elements follow DTD. If it does not, it will cause a - * segmentation fault due to the failure of finding expected attributes. - */ - - /* read number of cameras available in the system */ - const XMLElement *xmlElem = aSysElem->FirstChildElement("num_cameras"); - if (xmlElem != nullptr) { - mSystemInfo.numCameras = - stoi(xmlElem->FindAttribute("value")->Value()); - } -} - - -void ConfigManager::readDisplayInfo(const XMLElement * const aDisplayElem) { - if (aDisplayElem == nullptr) { - ALOGW("XML file does not have required camera element"); - return; - } - - const XMLElement *curDev = aDisplayElem->FirstChildElement("device"); - while (curDev != nullptr) { - const char *id = curDev->FindAttribute("id")->Value(); - //const char *pos = curDev->FirstAttribute("position")->Value(); - - unique_ptr dpy(new DisplayInfo()); - if (dpy == nullptr) { - ALOGE("Failed to allocate memory for DisplayInfo"); - return; - } - - const XMLElement *cap = curDev->FirstChildElement("caps"); - if (cap != nullptr) { - const XMLElement *curStream = cap->FirstChildElement("stream"); - while (curStream != nullptr) { - /* read 4 attributes */ - const XMLAttribute *idAttr = curStream->FindAttribute("id"); - const XMLAttribute *widthAttr = curStream->FindAttribute("width"); - const XMLAttribute *heightAttr = curStream->FindAttribute("height"); - const XMLAttribute *fmtAttr = curStream->FindAttribute("format"); - - const int32_t id = stoi(idAttr->Value()); - int32_t pixFormat; - if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), - pixFormat)) { - RawStreamConfiguration cfg = { - id, - stoi(widthAttr->Value()), - stoi(heightAttr->Value()), - pixFormat, - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT, - 0 // unused - }; - dpy->streamConfigurations[id] = cfg; - } - - curStream = curStream->NextSiblingElement("stream"); - } - } - - mDisplayInfo[id] = std::move(dpy); - curDev = curDev->NextSiblingElement("device"); - } - - return; -} - - -bool ConfigManager::readConfigDataFromXML() noexcept { - XMLDocument xmlDoc; - - const int64_t parsingStart = android::elapsedRealtimeNano(); - - /* load and parse a configuration file */ - xmlDoc.LoadFile(mConfigFilePath); - if (xmlDoc.ErrorID() != XML_SUCCESS) { - ALOGE("Failed to load and/or parse a configuration file, %s", xmlDoc.ErrorStr()); - return false; - } - - /* retrieve the root element */ - const XMLElement *rootElem = xmlDoc.RootElement(); - if (strcmp(rootElem->Name(), "configuration")) { - ALOGE("A configuration file is not in the required format. " - "See /etc/automotive/evs/evs_configuration.dtd"); - return false; - } - - /* - * parse camera information; this needs to be done before reading system - * information - */ - readCameraInfo(rootElem->FirstChildElement("camera")); - - /* parse system information */ - readSystemInfo(rootElem->FirstChildElement("system")); - - /* parse display information */ - readDisplayInfo(rootElem->FirstChildElement("display")); - - const int64_t parsingEnd = android::elapsedRealtimeNano(); - ALOGI("Parsing configuration file takes %lf (ms)", - (double)(parsingEnd - parsingStart) / 1000000.0); - - - return true; -} - - -void ConfigManager::addCameraDevices(const char *devices, - unique_ptr &aGroup) { - stringstream device_list(devices); - string token; - while (getline(device_list, token, ',')) { - aGroup->devices.emplace(token); - } -} - - -std::unique_ptr ConfigManager::Create(const char *path) { - unique_ptr cfgMgr(new ConfigManager(path)); - - /* - * Read a configuration from XML file - * - * If this is too slow, ConfigManager::readConfigDataFromBinary() and - * ConfigManager::writeConfigDataToBinary()can serialize CameraInfo object - * to the filesystem and construct CameraInfo instead; this was - * evaluated as 10x faster. - */ - if (!cfgMgr->readConfigDataFromXML()) { - return nullptr; - } else { - return cfgMgr; - } -} - diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h deleted file mode 100644 index 0275f904e5..0000000000 --- a/automotive/evs/1.1/default/ConfigManager.h +++ /dev/null @@ -1,336 +0,0 @@ -/* - * 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. - */ -#ifndef CONFIG_MANAGER_H -#define CONFIG_MANAGER_H - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "ConfigManagerUtil.h" - -using namespace std; -using namespace tinyxml2; - -using ::android::hardware::hidl_vec; -using ::android::hardware::camera::device::V3_2::Stream; -using ::android::hardware::automotive::evs::V1_1::CameraParam; - -/* - * Plese note that this is different from what is defined in - * libhardware/modules/camera/3_4/metadata/types.h; this has one additional - * field to store a framerate. - */ -const size_t kStreamCfgSz = 6; -typedef std::array RawStreamConfiguration; - -class ConfigManager { -public: - static std::unique_ptr Create(const char *path = ""); - ConfigManager(const ConfigManager&) = delete; - ConfigManager& operator=(const ConfigManager&) = delete; - - virtual ~ConfigManager(); - - /* Camera device's capabilities and metadata */ - class CameraInfo { - public: - CameraInfo() : - characteristics(nullptr) { - /* Nothing to do */ - } - - virtual ~CameraInfo() { - free_camera_metadata(characteristics); - } - - /* Allocate memory for camera_metadata_t */ - bool allocate(size_t entry_cap, size_t data_cap) { - if (characteristics != nullptr) { - ALOGE("Camera metadata is already allocated"); - return false; - } - - characteristics = allocate_camera_metadata(entry_cap, data_cap); - return characteristics != nullptr; - } - - /* - * List of supported controls that the master client can program. - * Paraemters are stored with its valid range - */ - unordered_map> controls; - - /* List of supported frame rates */ - unordered_set frameRates; - - /* - * List of supported output stream configurations; each array stores - * format, width, height, and direction values in the order. - */ - unordered_map streamConfigurations; - - /* - * Internal storage for camera metadata. Each entry holds a pointer to - * data and number of elements - */ - unordered_map, size_t>> cameraMetadata; - - /* Camera module characteristics */ - camera_metadata_t *characteristics; - }; - - class CameraGroup { - public: - CameraGroup() {} - - /* ID of member camera devices */ - unordered_set devices; - - /* The capture operation of member camera devices are synchronized */ - bool synchronized = false; - - /* - * List of stream configurations that are supposed by all camera devices - * in this group. - */ - unordered_map streamConfigurations; - }; - - class SystemInfo { - public: - /* number of available cameras */ - int32_t numCameras = 0; - }; - - class DisplayInfo { - public: - /* - * List of supported input stream configurations; each array stores - * format, width, height, and direction values in the order. - */ - unordered_map streamConfigurations; - }; - - /* - * Return system information - * - * @return SystemInfo - * Constant reference of SystemInfo. - */ - const SystemInfo &getSystemInfo() { - return mSystemInfo; - } - - /* - * Return a list of cameras - * - * This function assumes that it is not being called frequently. - * - * @return vector - * A vector that contains unique camera device identifiers. - */ - vector getCameraList() { - vector aList; - for (auto &v : mCameraInfo) { - aList.emplace_back(v.first); - } - - return aList; - } - - - /* - * Return a list of cameras - * - * @return CameraGroup - * A pointer to a camera group identified by a given id. - */ - unique_ptr& getCameraGroup(const string& gid) { - return mCameraGroups[gid]; - } - - - /* - * Return a camera metadata - * - * @param cameraId - * Unique camera node identifier in string - * - * @return unique_ptr - * A pointer to CameraInfo that is associated with a given camera - * ID. This returns a null pointer if this does not recognize a - * given camera identifier. - */ - unique_ptr& getCameraInfo(const string cameraId) noexcept { - return mCameraInfo[cameraId]; - } - -private: - /* Constructors */ - ConfigManager(const char *xmlPath) : - mConfigFilePath(xmlPath) { - } - - /* System configuration */ - SystemInfo mSystemInfo; - - /* Internal data structure for camera device information */ - unordered_map> mCameraInfo; - - /* Internal data structure for camera device information */ - unordered_map> mDisplayInfo; - - /* Camera groups are stored in hash map */ - unordered_map> mCameraGroups; - - /* - * Camera positions are stored in hash map. - * The position must be one of front, rear, left, and right. - */ - unordered_map> mCameraPosition; - - /* A path to XML configuration file */ - const char *mConfigFilePath; - - /* - * Parse a given EVS configuration file and store the information - * internally. - * - * @return bool - * True if it completes parsing a file successfully. - */ - bool readConfigDataFromXML() noexcept; - - /* - * read the information of the vehicle - * - * @param aSysElem - * A pointer to "system" XML element. - */ - void readSystemInfo(const XMLElement * const aSysElem); - - /* - * read the information of camera devices - * - * @param aCameraElem - * A pointer to "camera" XML element that may contain multiple - * "device" elements. - */ - void readCameraInfo(const XMLElement * const aCameraElem); - - /* - * read display device information - * - * @param aDisplayElem - * A pointer to "display" XML element that may contain multiple - * "device" elements. - */ - void readDisplayInfo(const XMLElement * const aDisplayElem); - - /* - * read camera device information - * - * @param aDeviceElem - * A pointer to "device" XML element that contains camera module - * capability info and its characteristics. - * - * @return unique_ptr - * A pointer to CameraInfo class that contains camera module - * capability and characteristics. Please note that this transfers - * the ownership of created CameraInfo to the caller. - */ - unique_ptr readCameraDeviceInfo(const XMLElement *aDeviceElem); - - /* - * read camera metadata - * - * @param aCapElem - * A pointer to "cap" XML element. - * @param aCamera - * A pointer to CameraInfo that is being filled by this method. - * @param dataSize - * Required size of memory to store camera metadata found in this - * method. This is calculated in this method and returned to the - * caller for camera_metadata allocation. - * - * @return size_t - * Number of camera metadata entries - */ - size_t readCameraCapabilities(const XMLElement * const aCapElem, - unique_ptr &aCamera, - size_t &dataSize); - - /* - * read camera metadata - * - * @param aParamElem - * A pointer to "characteristics" XML element. - * @param aCamera - * A pointer to CameraInfo that is being filled by this method. - * @param dataSize - * Required size of memory to store camera metadata found in this - * method. - * - * @return size_t - * Number of camera metadata entries - */ - size_t readCameraMetadata(const XMLElement * const aParamElem, - unique_ptr &aCamera, - size_t &dataSize); - - /* - * construct camera_metadata_t from camera capabilities and metadata - * - * @param aCamera - * A pointer to CameraInfo that is being filled by this method. - * @param totalEntries - * Number of camera metadata entries to be added. - * @param totalDataSize - * Sum of sizes of camera metadata entries to be added. - * - * @return bool - * False if either it fails to allocate memory for camera metadata - * or its size is not large enough to add all found camera metadata - * entries. - */ - bool constructCameraMetadata(unique_ptr &aCamera, - const size_t totalEntries, - const size_t totalDataSize); - - /* - * parse a comma-separated list of camera devices and add them to - * CameraGroup. - * - * @param devices - * A comma-separated list of camera device identifiers. - * @param aGroup - * Camera group which cameras will be added to. - */ - void addCameraDevices(const char *devices, - unique_ptr &aGroup); -}; -#endif // CONFIG_MANAGER_H - diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.cpp b/automotive/evs/1.1/default/ConfigManagerUtil.cpp deleted file mode 100644 index 8206daa6d7..0000000000 --- a/automotive/evs/1.1/default/ConfigManagerUtil.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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. - */ - -#include "ConfigManagerUtil.h" - -#include -#include -#include - -#include -#include - - -bool ConfigManagerUtil::convertToEvsCameraParam(const string &id, - CameraParam &camParam) { - string trimmed = ConfigManagerUtil::trimString(id); - bool success = true; - - if (!trimmed.compare("BRIGHTNESS")) { - camParam = CameraParam::BRIGHTNESS; - } else if (!trimmed.compare("CONTRAST")) { - camParam = CameraParam::CONTRAST; - } else if (!trimmed.compare("AUTOGAIN")) { - camParam = CameraParam::AUTOGAIN; - } else if (!trimmed.compare("GAIN")) { - camParam = CameraParam::GAIN; - } else if (!trimmed.compare("AUTO_WHITE_BALANCE")) { - camParam = CameraParam::AUTO_WHITE_BALANCE; - } else if (!trimmed.compare("WHITE_BALANCE_TEMPERATURE")) { - camParam = CameraParam::WHITE_BALANCE_TEMPERATURE; - } else if (!trimmed.compare("SHARPNESS")) { - camParam = CameraParam::SHARPNESS; - } else if (!trimmed.compare("AUTO_EXPOSURE")) { - camParam = CameraParam::AUTO_EXPOSURE; - } else if (!trimmed.compare("ABSOLUTE_EXPOSURE")) { - camParam = CameraParam::ABSOLUTE_EXPOSURE; - } else if (!trimmed.compare("ABSOLUTE_FOCUS")) { - camParam = CameraParam::ABSOLUTE_FOCUS; - } else if (!trimmed.compare("AUTO_FOCUS")) { - camParam = CameraParam::AUTO_FOCUS; - } else if (!trimmed.compare("ABSOLUTE_ZOOM")) { - camParam = CameraParam::ABSOLUTE_ZOOM; - } else { - success = false; - } - - return success; -} - - -bool ConfigManagerUtil::convertToPixelFormat(const string &format, - int32_t &pixFormat) { - string trimmed = ConfigManagerUtil::trimString(format); - bool success = true; - - if (!trimmed.compare("RGBA_8888")) { - pixFormat = HAL_PIXEL_FORMAT_RGBA_8888; - } else if (!trimmed.compare("YCRCB_420_SP")) { - pixFormat = HAL_PIXEL_FORMAT_YCRCB_420_SP; - } else if (!trimmed.compare("YCBCR_422_I")) { - pixFormat = HAL_PIXEL_FORMAT_YCBCR_422_I; - } else { - success = false; - } - - return success; -} - - -bool ConfigManagerUtil::convertToMetadataTag(const char *name, - camera_metadata_tag &aTag) { - if (!strcmp(name, "LENS_DISTORTION")) { - aTag = ANDROID_LENS_DISTORTION; - } else if (!strcmp(name, "LENS_INTRINSIC_CALIBRATION")) { - aTag = ANDROID_LENS_INTRINSIC_CALIBRATION; - } else if (!strcmp(name, "LENS_POSE_ROTATION")) { - aTag = ANDROID_LENS_POSE_ROTATION; - } else if (!strcmp(name, "LENS_POSE_TRANSLATION")) { - aTag = ANDROID_LENS_POSE_TRANSLATION; - } else { - return false; - } - - return true; -} - - -float *ConfigManagerUtil::convertFloatArray(const char *sz, const char *vals, - size_t &count, const char delimiter) { - string size_string(sz); - string value_string(vals); - - count = stoi(size_string); - float *result = new float[count]; - stringstream values(value_string); - - int32_t idx = 0; - string token; - while (getline(values, token, delimiter)) { - result[idx++] = stof(token); - } - - return result; -} - - -string ConfigManagerUtil::trimString(const string &src, const string &ws) { - const auto s = src.find_first_not_of(ws); - if (s == string::npos) { - return ""; - } - - const auto e = src.find_last_not_of(ws); - const auto r = e - s + 1; - - return src.substr(s, r); -} - diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.h b/automotive/evs/1.1/default/ConfigManagerUtil.h deleted file mode 100644 index 8c89ae7745..0000000000 --- a/automotive/evs/1.1/default/ConfigManagerUtil.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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. - */ -#ifndef CONFIG_MANAGER_UTIL_H -#define CONFIG_MANAGER_UTIL_H - -#include -#include -#include -#include - -using namespace std; -using ::android::hardware::automotive::evs::V1_1::CameraParam; - - -class ConfigManagerUtil { -public: - /** - * Convert a given string into V4L2_CID_* - */ - static bool convertToEvsCameraParam(const string &id, - CameraParam &camParam); - /** - * Convert a given string into android.hardware.graphics.common.PixelFormat - */ - static bool convertToPixelFormat(const string &format, - int32_t &pixelFormat); - /** - * Convert a given string into corresponding camera metadata data tag defined in - * system/media/camera/include/system/camera_metadta_tags.h - */ - static bool convertToMetadataTag(const char *name, - camera_metadata_tag &aTag); - /** - * Convert a given string into a floating value array - */ - static float *convertFloatArray(const char *sz, - const char *vals, - size_t &count, - const char delimiter = ','); - /** - * Trim a string - */ - static string trimString(const string &src, - const string &ws = " \n\r\t\f\v"); -}; - -#endif // CONFIG_MANAGER_UTIL_H - diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp index 5ba753da2e..2d55566349 100644 --- a/automotive/evs/1.1/default/EvsCamera.cpp +++ b/automotive/evs/1.1/default/EvsCamera.cpp @@ -40,21 +40,28 @@ const char EvsCamera::kCameraName_Backup[] = "backup"; const unsigned MAX_BUFFERS_IN_FLIGHT = 100; -EvsCamera::EvsCamera(const char *id, - unique_ptr &camInfo) : +EvsCamera::EvsCamera(const char *id) : mFramesAllowed(0), mFramesInUse(0), - mStreamState(STOPPED), - mCameraInfo(camInfo) { + mStreamState(STOPPED) { ALOGD("EvsCamera instantiated"); - /* set a camera id */ - mDescription.v1.cameraId = id; + mDescription.cameraId = id; - /* set camera metadata */ - mDescription.metadata.setToExternal((uint8_t *)camInfo->characteristics, - get_camera_metadata_size(camInfo->characteristics)); + // Set up dummy data for testing + if (mDescription.cameraId == kCameraName_Backup) { + mWidth = 640; // full NTSC/VGA + mHeight = 480; // full NTSC/VGA + mDescription.vendorFlags = 0xFFFFFFFF; // Arbitrary value + } else { + mWidth = 320; // 1/2 NTSC/VGA + mHeight = 240; // 1/2 NTSC/VGA + } + + mFormat = HAL_PIXEL_FORMAT_RGBA_8888; + mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE | + GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY; } @@ -102,7 +109,7 @@ Return EvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) { ALOGD("getCameraInfo"); // Send back our self description - _hidl_cb(mDescription.v1); + _hidl_cb(mDescription); return Void(); } @@ -187,7 +194,7 @@ Return EvsCamera::stopVideoStream() { // Block outside the mutex until the "stop" flag has been acknowledged // We won't send any more frames, but the client might still get some already in flight - ALOGD("Waiting for stream thread to end..."); + ALOGD("Waiting for stream thread to end.."); lock.unlock(); mCaptureThread.join(); lock.lock(); @@ -231,15 +238,6 @@ Return EvsCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/, int3 // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow. -Return EvsCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) { - ALOGD("getCameraInfo_1_1"); - - // Send back our self description - _hidl_cb(mDescription); - return Void(); -} - - Return EvsCamera::doneWithFrame_1_1(const BufferDesc_1_1& bufDesc) { std::lock_guard lock(mAccessLock); returnBuffer(bufDesc.bufferId, bufDesc.buffer.nativeHandle); @@ -280,29 +278,8 @@ Return EvsCamera::unsetMaster() { } -Return EvsCamera::getParameterList(getParameterList_cb _hidl_cb) { - hidl_vec hidlCtrls; - hidlCtrls.resize(mCameraInfo->controls.size()); - unsigned idx = 0; - for (auto& [cid, cfg] : mCameraInfo->controls) { - hidlCtrls[idx++] = cid; - } - - _hidl_cb(hidlCtrls); - return Void(); -} - - -Return EvsCamera::getIntParameterRange(CameraParam id, - getIntParameterRange_cb _hidl_cb) { - auto range = mCameraInfo->controls[id]; - _hidl_cb(get<0>(range), get<1>(range), get<2>(range)); - return Void(); -} - - -Return EvsCamera::setIntParameter(CameraParam id, int32_t value, - setIntParameter_cb _hidl_cb) { +Return EvsCamera::setParameter(CameraParam id, int32_t value, + setParameter_cb _hidl_cb) { // Default implementation does not support this. (void)id; (void)value; @@ -311,8 +288,7 @@ Return EvsCamera::setIntParameter(CameraParam id, int32_t value, } -Return EvsCamera::getIntParameter(CameraParam id, - getIntParameter_cb _hidl_cb) { +Return EvsCamera::getParameter(CameraParam id, getParameter_cb _hidl_cb) { // Default implementation does not support this. (void)id; _hidl_cb(EvsResult::INVALID_ARG, 0); @@ -495,7 +471,9 @@ void EvsCamera::generateFrames() { fillTestFrame(newBuffer); // Issue the (asynchronous) callback to the client -- can't be holding the lock - auto result = mStream->deliverFrame_1_1(newBuffer); + EvsEvent event; + event.buffer(newBuffer); + auto result = mStream->notifyEvent(event); if (result.isOk()) { ALOGD("Delivered %p as id %d", newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId); @@ -528,8 +506,10 @@ void EvsCamera::generateFrames() { // If we've been asked to stop, send an event to signal the actual end of stream EvsEvent event; - event.aType = EvsEventType::STREAM_STOPPED; - auto result = mStream->notify(event); + InfoEventDesc desc = {}; + desc.aType = InfoEventType::STREAM_STOPPED; + event.info(desc); + auto result = mStream->notifyEvent(event); if (!result.isOk()) { ALOGE("Error delivering end of stream marker"); } @@ -636,38 +616,6 @@ void EvsCamera::returnBuffer(const uint32_t bufferId, const buffer_handle_t memH } -sp EvsCamera::Create(const char *deviceName) { - unique_ptr nullCamInfo = nullptr; - - return Create(deviceName, nullCamInfo); -} - - -sp EvsCamera::Create(const char *deviceName, - unique_ptr &camInfo, - const Stream *streamCfg) { - sp evsCamera = new EvsCamera(deviceName, camInfo); - if (evsCamera == nullptr) { - return nullptr; - } - - /* default implementation does not use a given configuration */ - (void)streamCfg; - - /* Use the first resolution from the list for the testing */ - auto it = camInfo->streamConfigurations.begin(); - evsCamera->mWidth = it->second[1]; - evsCamera->mHeight = it->second[2]; - evsCamera->mDescription.v1.vendorFlags = 0xFFFFFFFF; // Arbitrary test value - - evsCamera->mFormat = HAL_PIXEL_FORMAT_RGBA_8888; - evsCamera->mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE | - GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY; - - return evsCamera; -} - - } // namespace implementation } // namespace V1_0 } // namespace evs diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h index c15b4b117b..47a3164892 100644 --- a/automotive/evs/1.1/default/EvsCamera.h +++ b/automotive/evs/1.1/default/EvsCamera.h @@ -25,8 +25,6 @@ #include -#include "ConfigManager.h" - using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc; using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc; using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream; @@ -61,28 +59,18 @@ public: Return setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override; // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow. - Return getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) override; Return pauseVideoStream() override; Return resumeVideoStream() override; Return doneWithFrame_1_1(const BufferDesc_1_1& buffer) override; Return setMaster() override; Return forceMaster(const sp& display) override; Return unsetMaster() override; - Return getParameterList(getParameterList_cb _hidl_cb) override; - Return getIntParameterRange(CameraParam id, - getIntParameterRange_cb _hidl_cb) override; - Return setIntParameter(CameraParam id, int32_t value, - setIntParameter_cb _hidl_cb) override; - Return getIntParameter(CameraParam id, - getIntParameter_cb _hidl_cb) override; - - static sp Create(const char *deviceName); - static sp Create(const char *deviceName, - unique_ptr &camInfo, - const Stream *streamCfg = nullptr); - EvsCamera(const EvsCamera&) = delete; - EvsCamera& operator=(const EvsCamera&) = delete; + Return setParameter(CameraParam id, int32_t value, + setParameter_cb _hidl_cb) override; + Return getParameter(CameraParam id, getParameter_cb _hidl_cb) override; + // Implementation details + EvsCamera(const char *id); virtual ~EvsCamera() override; void forceShutdown(); // This gets called if another caller "steals" ownership of the camera @@ -91,10 +79,7 @@ public: static const char kCameraName_Backup[]; private: - EvsCamera(const char *id, - unique_ptr &camInfo); // These three functions are expected to be called while mAccessLock is held - // bool setAvailableFrames_Locked(unsigned bufferCount); unsigned increaseAvailableFrames_Locked(unsigned numToAdd); unsigned decreaseAvailableFrames_Locked(unsigned numToRemove); @@ -139,9 +124,6 @@ private: // Synchronization necessary to deconflict mCaptureThread from the main service thread std::mutex mAccessLock; - - // Static camera module information - unique_ptr &mCameraInfo; }; } // namespace implementation diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp index a010729ce6..b3249071ae 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.cpp +++ b/automotive/evs/1.1/default/EvsEnumerator.cpp @@ -33,7 +33,6 @@ namespace implementation { // constructs a new instance for each client. std::list EvsEnumerator::sCameraList; wp EvsEnumerator::sActiveDisplay; -unique_ptr EvsEnumerator::sConfigManager; EvsEnumerator::EvsEnumerator() { @@ -41,11 +40,9 @@ EvsEnumerator::EvsEnumerator() { // Add sample camera data to our list of cameras // In a real driver, this would be expected to can the available hardware - sConfigManager = - ConfigManager::Create("/etc/automotive/evs/evs_sample_configuration.xml"); - for (auto v : sConfigManager->getCameraList()) { - sCameraList.emplace_back(v.c_str()); - } + sCameraList.emplace_back(EvsCamera::kCameraName_Backup); + sCameraList.emplace_back("LaneView"); + sCameraList.emplace_back("right turn"); } @@ -60,7 +57,7 @@ Return EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) { std::vector descriptions; descriptions.reserve(numCameras); for (const auto& cam : sCameraList) { - descriptions.push_back( cam.desc.v1 ); + descriptions.push_back( cam.desc ); } // Encapsulate our camera descriptions in the HIDL vec type @@ -81,7 +78,7 @@ Return> EvsEnumerator::openCamera(const hidl_string& cameraId // Find the named camera CameraRecord *pRecord = nullptr; for (auto &&cam : sCameraList) { - if (cam.desc.v1.cameraId == cameraId) { + if (cam.desc.cameraId == cameraId) { // Found a match! pRecord = &cam; break; @@ -102,12 +99,7 @@ Return> EvsEnumerator::openCamera(const hidl_string& cameraId } // Construct a camera instance for the caller - if (sConfigManager == nullptr) { - pActiveCamera = EvsCamera::Create(cameraId.c_str()); - } else { - pActiveCamera = EvsCamera::Create(cameraId.c_str(), - sConfigManager->getCameraInfo(cameraId)); - } + pActiveCamera = new EvsCamera(cameraId.c_str()); pRecord->activeInstance = pActiveCamera; if (pActiveCamera == nullptr) { ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str()); @@ -128,15 +120,15 @@ Return EvsEnumerator::closeCamera(const ::android::sp& pCa // Get the camera id so we can find it in our list std::string cameraId; - pCamera_1_1->getCameraInfo_1_1([&cameraId](CameraDesc desc) { - cameraId = desc.v1.cameraId; + pCamera_1_1->getCameraInfo([&cameraId](CameraDesc desc) { + cameraId = desc.cameraId; } ); // Find the named camera CameraRecord *pRecord = nullptr; for (auto &&cam : sCameraList) { - if (cam.desc.v1.cameraId == cameraId) { + if (cam.desc.cameraId == cameraId) { // Found a match! pRecord = &cam; break; @@ -217,89 +209,6 @@ Return EvsEnumerator::getDisplayState() { } -// Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow. -Return EvsEnumerator::getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) { - ALOGD("getCameraList"); - - const unsigned numCameras = sCameraList.size(); - - // Build up a packed array of CameraDesc for return - // NOTE: Only has to live until the callback returns - std::vector descriptions; - descriptions.reserve(numCameras); - for (const auto& cam : sCameraList) { - descriptions.push_back( cam.desc ); - } - - // Encapsulate our camera descriptions in the HIDL vec type - hidl_vec hidlCameras(descriptions); - - // Send back the results - ALOGD("reporting %zu cameras available", hidlCameras.size()); - _hidl_cb(hidlCameras); - - // HIDL convention says we return Void if we sent our result back via callback - return Void(); -} - -Return> -EvsEnumerator::openCamera_1_1(const hidl_string& cameraId, - const Stream& streamCfg) { - // Find the named camera - CameraRecord *pRecord = nullptr; - for (auto &&cam : sCameraList) { - if (cam.desc.v1.cameraId == cameraId) { - // Found a match! - pRecord = &cam; - break; - } - } - - // Is this a recognized camera id? - if (!pRecord) { - ALOGE("Requested camera %s not found", cameraId.c_str()); - return nullptr; - } - - // Has this camera already been instantiated by another caller? - sp pActiveCamera = pRecord->activeInstance.promote(); - if (pActiveCamera != nullptr) { - ALOGW("Killing previous camera because of new caller"); - closeCamera(pActiveCamera); - } - - // Construct a camera instance for the caller - if (sConfigManager == nullptr) { - pActiveCamera = EvsCamera::Create(cameraId.c_str()); - } else { - pActiveCamera = EvsCamera::Create(cameraId.c_str(), - sConfigManager->getCameraInfo(cameraId), - &streamCfg); - } - - pRecord->activeInstance = pActiveCamera; - if (pActiveCamera == nullptr) { - ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str()); - } - - return pActiveCamera; -} - - -EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& cameraId) { - // Find the named camera - CameraRecord *pRecord = nullptr; - for (auto &&cam : sCameraList) { - if (cam.desc.v1.cameraId == cameraId) { - // Found a match! - pRecord = &cam; - break; - } - } - - return pRecord; -} - } // namespace implementation } // namespace V1_1 } // namespace evs diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h index 475ec76b93..11c2170632 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.h +++ b/automotive/evs/1.1/default/EvsEnumerator.h @@ -17,20 +17,18 @@ #ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H #define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H -#include +#include #include #include -#include "ConfigManager.h" - using ::android::hardware::automotive::evs::V1_0::EvsResult; using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; using ::android::hardware::automotive::evs::V1_0::DisplayState; +using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator; using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera; using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera; using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc; -using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc; namespace android { @@ -55,11 +53,6 @@ public: Return closeDisplay(const ::android::sp& display) override; Return getDisplayState() override; - // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow. - Return getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) override; - Return> openCamera_1_1(const hidl_string& cameraId, - const Stream& streamCfg) override; - // Implementation details EvsEnumerator(); @@ -68,20 +61,14 @@ private: // That is to say, this is effectively a singleton despite the fact that HIDL // constructs a new instance for each client. struct CameraRecord { - CameraDesc_1_1 desc; + CameraDesc_1_0 desc; wp activeInstance; - CameraRecord(const char *cameraId) : desc() { desc.v1.cameraId = cameraId; } + CameraRecord(const char *cameraId) : desc() { desc.cameraId = cameraId; } }; + static std::list sCameraList; - static CameraRecord* findCameraById(const std::string& cameraId); - - static std::list sCameraList; - - // Weak pointer. Object destructs if client dies. - static wp sActiveDisplay; - - static unique_ptr sConfigManager; + static wp sActiveDisplay; // Weak pointer. Object destructs if client dies. }; } // namespace implementation diff --git a/automotive/evs/1.1/default/resources/evs_default_configuration.xml b/automotive/evs/1.1/default/resources/evs_default_configuration.xml deleted file mode 100644 index 692102ed38..0000000000 --- a/automotive/evs/1.1/default/resources/evs_default_configuration.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/automotive/evs/1.1/default/service.cpp b/automotive/evs/1.1/default/service.cpp index 5135864e88..128a14aa30 100644 --- a/automotive/evs/1.1/default/service.cpp +++ b/automotive/evs/1.1/default/service.cpp @@ -33,7 +33,7 @@ using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; // Generated HIDL files -using android::hardware::automotive::evs::V1_1::IEvsEnumerator; +using android::hardware::automotive::evs::V1_0::IEvsEnumerator; using android::hardware::automotive::evs::V1_0::IEvsDisplay; // The namespace in which all our implementation code lives diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal index dcb2abb0e9..2c6b2ed589 100644 --- a/automotive/evs/1.1/types.hal +++ b/automotive/evs/1.1/types.hal @@ -21,22 +21,6 @@ import @1.0::DisplayDesc; import @1.0::DisplayState; import @1.0::EvsResult; import android.hardware.graphics.common@1.2::HardwareBuffer; -import android.hardware.camera.device@3.2::CameraMetadata; - -/** - * Structure describing the basic properties of an EVS camera, extended from its - * v1.0 declaration. - * - * The HAL is responsible for filling out this structure for each - * EVS camera in the system. - */ -struct CameraDesc { - @1.0::CameraDesc v1; - /** - * Store camera metadata such as lens characteristics. - */ - CameraMetadata metadata; -}; /** * Structure representing an image buffer through our APIs @@ -66,7 +50,7 @@ struct BufferDesc { /** * Types of informative streaming events */ -enum EvsEventType : uint32_t { +enum InfoEventType : uint32_t { /** * Video stream is started */ @@ -97,17 +81,31 @@ enum EvsEventType : uint32_t { /** * Structure that describes informative events occurred during EVS is streaming */ -struct EvsEvent { +struct InfoEventDesc { /** * Type of an informative event */ - EvsEventType aType; + InfoEventType aType; /** * Possible additional information */ uint32_t[4] payload; }; +/** + * EVS event definition + */ +safe_union EvsEvent { + /** + * A buffer descriptor of an image frame + */ + BufferDesc buffer; + /** + * General streaming events + */ + InfoEventDesc info; +}; + /** * EVS Camera Parameter */ @@ -128,6 +126,14 @@ enum CameraParam : uint32_t { * Gain control */ GAIN, + /** + * Mirror the image horizontally + */ + HFLIP, + /** + * Mirror the image vertically + */ + VFLIP, /** * Automatic Whitebalance */ @@ -149,6 +155,11 @@ enum CameraParam : uint32_t { * Manual exposure time of the camera */ ABSOLUTE_EXPOSURE, + /** + * When AEC is running in either auto or aperture priority, this parameter + * sets whether a frame rate varies. + */ + AUTO_EXPOSURE_PRIORITY, /** * Set the focal point of the camera to the specified position. This * parameter may not be effective when auto focus is enabled. diff --git a/automotive/evs/1.1/vts/functional/Android.bp b/automotive/evs/1.1/vts/functional/Android.bp index 4753933f7f..55c50a42b8 100644 --- a/automotive/evs/1.1/vts/functional/Android.bp +++ b/automotive/evs/1.1/vts/functional/Android.bp @@ -23,7 +23,6 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], shared_libs: [ "libui", - "libcamera_metadata", ], static_libs: [ "android.hardware.automotive.evs@1.0", @@ -32,7 +31,6 @@ cc_test { "android.hardware.graphics.common@1.0", "android.hardware.graphics.common@1.1", "android.hardware.graphics.common@1.2", - "android.hardware.camera.device@3.2", ], test_suites: ["general-tests"], cflags: [ diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp index 6d53652f86..16276891f0 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp +++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp @@ -138,93 +138,93 @@ Return FrameHandler::deliverFrame(const BufferDesc_1_0& bufferArg) { } -Return FrameHandler::deliverFrame_1_1(const BufferDesc_1_1& bufDesc) { - const AHardwareBuffer_Desc* pDesc = - reinterpret_cast(&bufDesc.buffer.description); - ALOGD("Received a frame from the camera (%p)", - bufDesc.buffer.nativeHandle.getNativeHandle()); - - // Store a dimension of a received frame. - mFrameWidth = pDesc->width; - mFrameHeight = pDesc->height; - - // If we were given an opened display at construction time, then send the received - // image back down the camera. - if (mDisplay.get()) { - // Get the output buffer we'll use to display the imagery - BufferDesc_1_0 tgtBuffer = {}; - mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) { - tgtBuffer = buff; - } - ); - - if (tgtBuffer.memHandle == nullptr) { - printf("Didn't get target buffer - frame lost\n"); - ALOGE("Didn't get requested output buffer -- skipping this frame."); +Return FrameHandler::notifyEvent(const EvsEvent& event) { + // Local flag we use to keep track of when the stream is stopping + auto type = event.getDiscriminator(); + if (type == EvsEvent::hidl_discriminator::info) { + mLock.lock(); + mLatestEventDesc = event.info(); + if (mLatestEventDesc.aType == InfoEventType::STREAM_STOPPED) { + // Signal that the last frame has been received and the stream is stopped + mRunning = false; + } else if (mLatestEventDesc.aType == InfoEventType::PARAMETER_CHANGED) { + ALOGD("Camera parameter 0x%X is changed to 0x%X", + mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]); } else { - // Copy the contents of the of buffer.memHandle into tgtBuffer - copyBufferContents(tgtBuffer, bufDesc); + ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType)); + } + mLock.unlock(); + mEventSignal.notify_all(); + } else { + auto bufDesc = event.buffer(); + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&bufDesc.buffer.description); + ALOGD("Received a frame from the camera (%p)", + bufDesc.buffer.nativeHandle.getNativeHandle()); - // Send the target buffer back for display - Return result = mDisplay->returnTargetBufferForDisplay(tgtBuffer); - if (!result.isOk()) { - printf("HIDL error on display buffer (%s)- frame lost\n", - result.description().c_str()); - ALOGE("Error making the remote function call. HIDL said %s", - result.description().c_str()); - } else if (result != EvsResult::OK) { - printf("Display reported error - frame lost\n"); - ALOGE("We encountered error %d when returning a buffer to the display!", - (EvsResult) result); + // Store a dimension of a received frame. + mFrameWidth = pDesc->width; + mFrameHeight = pDesc->height; + + // If we were given an opened display at construction time, then send the received + // image back down the camera. + if (mDisplay.get()) { + // Get the output buffer we'll use to display the imagery + BufferDesc_1_0 tgtBuffer = {}; + mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) { + tgtBuffer = buff; + } + ); + + if (tgtBuffer.memHandle == nullptr) { + printf("Didn't get target buffer - frame lost\n"); + ALOGE("Didn't get requested output buffer -- skipping this frame."); } else { - // Everything looks good! - // Keep track so tests or watch dogs can monitor progress - mLock.lock(); - mFramesDisplayed++; - mLock.unlock(); + // Copy the contents of the of buffer.memHandle into tgtBuffer + copyBufferContents(tgtBuffer, bufDesc); + + // Send the target buffer back for display + Return result = mDisplay->returnTargetBufferForDisplay(tgtBuffer); + if (!result.isOk()) { + printf("HIDL error on display buffer (%s)- frame lost\n", + result.description().c_str()); + ALOGE("Error making the remote function call. HIDL said %s", + result.description().c_str()); + } else if (result != EvsResult::OK) { + printf("Display reported error - frame lost\n"); + ALOGE("We encountered error %d when returning a buffer to the display!", + (EvsResult) result); + } else { + // Everything looks good! + // Keep track so tests or watch dogs can monitor progress + mLock.lock(); + mFramesDisplayed++; + mLock.unlock(); + } } } + + + switch (mReturnMode) { + case eAutoReturn: + // Send the camera buffer back now that the client has seen it + ALOGD("Calling doneWithFrame"); + // TODO: Why is it that we get a HIDL crash if we pass back the cloned buffer? + mCamera->doneWithFrame_1_1(bufDesc); + break; + case eNoAutoReturn: + // Hang onto the buffer handle for now -- the client will return it explicitly later + mHeldBuffers.push(bufDesc); + } + + mLock.lock(); + ++mFramesReceived; + mLock.unlock(); + mFrameSignal.notify_all(); + + ALOGD("Frame handling complete"); } - - switch (mReturnMode) { - case eAutoReturn: - // Send the camera buffer back now that the client has seen it - ALOGD("Calling doneWithFrame"); - mCamera->doneWithFrame_1_1(bufDesc); - break; - case eNoAutoReturn: - // Hang onto the buffer handle for now -- the client will return it explicitly later - mHeldBuffers.push(bufDesc); - } - - mLock.lock(); - ++mFramesReceived; - mLock.unlock(); - mFrameSignal.notify_all(); - - ALOGD("Frame handling complete"); - - return Void(); -} - - -Return FrameHandler::notify(const EvsEvent& event) { - // Local flag we use to keep track of when the stream is stopping - mLock.lock(); - mLatestEventDesc = event; - if (mLatestEventDesc.aType == EvsEventType::STREAM_STOPPED) { - // Signal that the last frame has been received and the stream is stopped - mRunning = false; - } else if (mLatestEventDesc.aType == EvsEventType::PARAMETER_CHANGED) { - ALOGD("Camera parameter 0x%X is changed to 0x%X", - mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]); - } else { - ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType)); - } - mLock.unlock(); - mEventSignal.notify_all(); - return Void(); } @@ -342,18 +342,18 @@ void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) { } } -bool FrameHandler::waitForEvent(const EvsEventType aTargetEvent, - EvsEvent &event) { +bool FrameHandler::waitForEvent(const InfoEventType aTargetEvent, + InfoEventDesc &eventDesc) { // Wait until we get an expected parameter change event. std::unique_lock lock(mLock); auto now = std::chrono::system_clock::now(); bool result = mEventSignal.wait_until(lock, now + 5s, - [this, aTargetEvent, &event](){ + [this, aTargetEvent, &eventDesc](){ bool flag = mLatestEventDesc.aType == aTargetEvent; if (flag) { - event.aType = mLatestEventDesc.aType; - event.payload[0] = mLatestEventDesc.payload[0]; - event.payload[1] = mLatestEventDesc.payload[1]; + eventDesc.aType = mLatestEventDesc.aType; + eventDesc.payload[0] = mLatestEventDesc.payload[0]; + eventDesc.payload[1] = mLatestEventDesc.payload[1]; } return flag; @@ -363,22 +363,21 @@ bool FrameHandler::waitForEvent(const EvsEventType aTargetEvent, return !result; } -const char *FrameHandler::eventToString(const EvsEventType aType) { +const char *FrameHandler::eventToString(const InfoEventType aType) { switch (aType) { - case EvsEventType::STREAM_STARTED: + case InfoEventType::STREAM_STARTED: return "STREAM_STARTED"; - case EvsEventType::STREAM_STOPPED: + case InfoEventType::STREAM_STOPPED: return "STREAM_STOPPED"; - case EvsEventType::FRAME_DROPPED: + case InfoEventType::FRAME_DROPPED: return "FRAME_DROPPED"; - case EvsEventType::TIMEOUT: + case InfoEventType::TIMEOUT: return "TIMEOUT"; - case EvsEventType::PARAMETER_CHANGED: + case InfoEventType::PARAMETER_CHANGED: return "PARAMETER_CHANGED"; - case EvsEventType::MASTER_RELEASED: + case InfoEventType::MASTER_RELEASED: return "MASTER_RELEASED"; default: return "Unknown"; } } - diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h index e5f1b8f112..7f87cb4409 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.h +++ b/automotive/evs/1.1/vts/functional/FrameHandler.h @@ -33,6 +33,7 @@ using ::android::hardware::hidl_handle; using ::android::sp; using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; using ::android::hardware::automotive::evs::V1_0::EvsResult; +using ::android::hardware::automotive::evs::V1_0::CameraDesc; using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc; using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc; @@ -55,13 +56,6 @@ public: FrameHandler(android::sp pCamera, CameraDesc cameraInfo, android::sp pDisplay = nullptr, BufferControlFlag mode = eAutoReturn); - virtual ~FrameHandler() { - if (mCamera != nullptr) { - /* shutdown a camera explicitly */ - shutdown(); - } - } - void shutdown(); bool startStream(); @@ -73,22 +67,19 @@ public: bool isRunning(); void waitForFrameCount(unsigned frameCount); - bool waitForEvent(const EvsEventType aTargetEvent, - EvsEvent &eventDesc); + bool waitForEvent(const InfoEventType aTargetEvent, + InfoEventDesc &eventDesc); void getFramesCounters(unsigned* received, unsigned* displayed); void getFrameDimension(unsigned* width, unsigned* height); private: - // Implementation for ::android::hardware::automotive::evs::V1_0::IEvsCameraStream - Return deliverFrame(const BufferDesc_1_0& buffer) override; - // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream - Return deliverFrame_1_1(const BufferDesc_1_1& buffer) override; - Return notify(const EvsEvent& event) override; + Return deliverFrame(const BufferDesc_1_0& buffer) override; + Return notifyEvent(const EvsEvent& event) override; // Local implementation details bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer); - const char *eventToString(const EvsEventType aType); + const char *eventToString(const InfoEventType aType); // Values initialized as startup android::sp mCamera; @@ -109,7 +100,7 @@ private: unsigned mFramesDisplayed = 0; // Simple counter -- rolls over eventually! unsigned mFrameWidth = 0; unsigned mFrameHeight = 0; - EvsEvent mLatestEventDesc; + InfoEventDesc mLatestEventDesc; }; diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index 1d3fd87356..a6e4881d4d 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -38,9 +38,8 @@ static const float kNanoToSeconds = 0.000000001f; #include "FrameHandler.h" -#include -#include -#include +#include +#include #include #include @@ -51,10 +50,8 @@ static const float kNanoToSeconds = 0.000000001f; #include #include #include -#include +#include #include -#include -#include #include #include @@ -67,28 +64,13 @@ using ::android::hardware::hidl_vec; using ::android::hardware::hidl_handle; using ::android::hardware::hidl_string; using ::android::sp; -using ::android::hardware::camera::device::V3_2::Stream; +using ::android::hardware::automotive::evs::V1_0::CameraDesc; using ::android::hardware::automotive::evs::V1_0::DisplayDesc; using ::android::hardware::automotive::evs::V1_0::DisplayState; -using ::android::hardware::graphics::common::V1_0::PixelFormat; +using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator; using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera; using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera; -/* - * Plese note that this is different from what is defined in - * libhardware/modules/camera/3_4/metadata/types.h; this has one additional - * field to store a framerate. - */ -const size_t kStreamCfgSz = 5; -typedef struct { - int32_t width; - int32_t height; - int32_t format; - int32_t direction; - int32_t framerate; -} RawStreamConfig; - - // Test environment for Evs HIDL HAL. class EvsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: @@ -125,16 +107,15 @@ protected: assert(pEnumerator != nullptr); // Get the camera list - pEnumerator->getCameraList_1_1( - [this](hidl_vec cameraList) { - ALOGI("Camera list callback received %zu cameras", - cameraList.size()); - cameraInfo.reserve(cameraList.size()); - for (auto&& cam: cameraList) { - ALOGI("Found camera %s", cam.v1.cameraId.c_str()); - cameraInfo.push_back(cam); - } - } + pEnumerator->getCameraList([this](hidl_vec cameraList) { + ALOGI("Camera list callback received %zu cameras", + cameraList.size()); + cameraInfo.reserve(cameraList.size()); + for (auto&& cam: cameraList) { + ALOGI("Found camera %s", cam.cameraId.c_str()); + cameraInfo.push_back(cam); + } + } ); // We insist on at least one camera for EVS to pass any camera tests @@ -162,23 +143,19 @@ TEST_F(EvsHidlTest, CameraOpenClean) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Open and close each camera twice for (auto&& cam: cameraInfo) { for (int pass = 0; pass < 2; pass++) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); // Verify that this camera self-identifies correctly - pCam->getCameraInfo_1_1([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.v1.cameraId.c_str()); - EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); - } + pCam->getCameraInfo([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.cameraId.c_str()); + EXPECT_EQ(cam.cameraId, desc.cameraId); + } ); // Explicitly close the camera so resources are released right away @@ -200,26 +177,22 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Open and close each camera twice for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); // Verify that this camera self-identifies correctly - pCam->getCameraInfo_1_1([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.v1.cameraId.c_str()); - EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); - } + pCam->getCameraInfo([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.cameraId.c_str()); + EXPECT_EQ(cam.cameraId, desc.cameraId); + } ); sp pCam2 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam, pCam2); ASSERT_NE(pCam2, nullptr); @@ -237,10 +210,10 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { pEnumerator->closeCamera(pCam); // Verify that the second camera instance self-identifies correctly - pCam2->getCameraInfo_1_1([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.v1.cameraId.c_str()); - EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); - } + pCam2->getCameraInfo([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.cameraId.c_str()); + EXPECT_EQ(cam.cameraId, desc.cameraId); + } ); // Close the second camera instance @@ -262,14 +235,10 @@ TEST_F(EvsHidlTest, CameraStreamPerformance) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); @@ -334,15 +303,11 @@ TEST_F(EvsHidlTest, CameraStreamBuffering) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); @@ -406,10 +371,6 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Request exclusive access to the EVS display sp pDisplay = pEnumerator->openDisplay(); ASSERT_NE(pDisplay, nullptr); @@ -417,7 +378,7 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { // Test each reported camera for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); @@ -478,20 +439,16 @@ TEST_F(EvsHidlTest, MultiCameraStream) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera for (auto&& cam: cameraInfo) { // Create two camera clients. sp pCam0 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam0, nullptr); sp pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam1, nullptr); @@ -529,6 +486,7 @@ TEST_F(EvsHidlTest, MultiCameraStream) { nsecs_t runTime = end - firstFrame; float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds); float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds); + printf("Measured camera rate %3.2f fps and %3.2f fps\n", framesPerSecond0, framesPerSecond1); ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1); EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond); EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond); @@ -568,33 +526,14 @@ TEST_F(EvsHidlTest, CameraParameter) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera - Return result = EvsResult::OK; for (auto&& cam: cameraInfo) { // Create a camera client sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); - // Get the parameter list - std::vector cmds; - pCam->getParameterList([&cmds](hidl_vec cmdList) { - cmds.reserve(cmdList.size()); - for (auto &&cmd : cmdList) { - cmds.push_back(cmd); - } - } - ); - - if (cmds.size() < 1) { - continue; - } - // Set up per-client frame receiver objects which will fire up its own thread sp frameHandler = new FrameHandler(pCam, cam, nullptr, @@ -608,70 +547,83 @@ TEST_F(EvsHidlTest, CameraParameter) { // Ensure the stream starts frameHandler->waitForFrameCount(1); + // Try to program few parameters + EvsResult result = EvsResult::OK; + int32_t val0 = 100; + int32_t val1 = 0; + result = pCam->setMaster(); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK); - for (auto &cmd : cmds) { - // Get a valid parameter value range - int32_t minVal, maxVal, step; - pCam->getIntParameterRange( - cmd, - [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { - minVal = val0; - maxVal = val1; - step = val2; - } - ); + pCam->setParameter(CameraParam::BRIGHTNESS, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); - EvsResult result = EvsResult::OK; - if (cmd == CameraParam::ABSOLUTE_FOCUS) { - // Try to turn off auto-focus - int32_t val1 = 0; - pCam->getIntParameter(CameraParam::AUTO_FOCUS, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - if (val1 != 0) { - pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val1, 0); - } - } - - // Try to program a parameter with a random value [minVal, maxVal] - int32_t val0 = minVal + (std::rand() % (maxVal - minVal)); - int32_t val1 = 0; - - // Rounding down - val0 = val0 - (val0 % step); - pCam->setIntParameter(cmd, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - - ASSERT_EQ(EvsResult::OK, result); - - pCam->getIntParameter(cmd, + if (result == EvsResult::OK) { + pCam->getParameter(CameraParam::BRIGHTNESS, [&result, &val1](auto status, auto value) { result = status; if (status == EvsResult::OK) { val1 = value; } }); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + ASSERT_EQ(val0, val1) << "Values are not matched."; + } + + val0 = 80; + val1 = 0; + pCam->setParameter(CameraParam::CONTRAST, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + + if (result == EvsResult::OK) { + pCam->getParameter(CameraParam::CONTRAST, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + ASSERT_EQ(val0, val1) << "Values are not matched."; + } + + val0 = 300; + val1 = 0; + pCam->setParameter(CameraParam::ABSOLUTE_ZOOM, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + + if (result == EvsResult::OK) { + pCam->getParameter(CameraParam::ABSOLUTE_ZOOM, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); ASSERT_EQ(val0, val1) << "Values are not matched."; } result = pCam->unsetMaster(); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK); // Shutdown frameHandler->shutdown(); @@ -698,19 +650,15 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera for (auto&& cam: cameraInfo) { // Create two camera clients. sp pCamMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCamMaster, nullptr); sp pCamNonMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCamNonMaster, nullptr); @@ -750,15 +698,15 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { // Non-master client expects to receive a master role relesed // notification. - EvsEvent aNotification = {}; + InfoEventDesc aNotification = {}; // Release a master role. pCamMaster->unsetMaster(); // Verify a change notification. - frameHandlerNonMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); - ASSERT_EQ(EvsEventType::MASTER_RELEASED, - static_cast(aNotification.aType)); + frameHandlerNonMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(InfoEventType::MASTER_RELEASED, + static_cast(aNotification.aType)); // Non-master becomes a master. result = pCamNonMaster->setMaster(); @@ -772,9 +720,9 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { frameHandlerNonMaster->shutdown(); // Verify a change notification. - frameHandlerMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); - ASSERT_EQ(EvsEventType::MASTER_RELEASED, - static_cast(aNotification.aType)); + frameHandlerMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(InfoEventType::MASTER_RELEASED, + static_cast(aNotification.aType)); // Closing another stream. frameHandlerMaster->shutdown(); @@ -804,46 +752,18 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera for (auto&& cam: cameraInfo) { // Create two camera clients. sp pCamMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCamMaster, nullptr); sp pCamNonMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCamNonMaster, nullptr); - // Get the parameter list - std::vector camMasterCmds, camNonMasterCmds; - pCamMaster->getParameterList([&camMasterCmds](hidl_vec cmdList) { - camMasterCmds.reserve(cmdList.size()); - for (auto &&cmd : cmdList) { - camMasterCmds.push_back(cmd); - } - } - ); - - pCamNonMaster->getParameterList([&camNonMasterCmds](hidl_vec cmdList) { - camNonMasterCmds.reserve(cmdList.size()); - for (auto &&cmd : cmdList) { - camNonMasterCmds.push_back(cmd); - } - } - ); - - if (camMasterCmds.size() < 1 || - camNonMasterCmds.size() < 1) { - // Skip a camera device if it does not support any parameter. - continue; - } - // Set up per-client frame receiver objects which will fire up its own thread sp frameHandlerMaster = new FrameHandler(pCamMaster, cam, @@ -858,11 +778,11 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Set one client as the master EvsResult result = pCamMaster->setMaster(); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK); // Try to set another client as the master. result = pCamNonMaster->setMaster(); - ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result); + ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST); // Start the camera's video stream via a master client. bool startResult = frameHandlerMaster->startStream(); @@ -878,168 +798,131 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Ensure the stream starts frameHandlerNonMaster->waitForFrameCount(1); - int32_t val0 = 0; + // Try to program CameraParam::BRIGHTNESS + int32_t val0 = 100; int32_t val1 = 0; - for (auto &cmd : camMasterCmds) { - // Get a valid parameter value range - int32_t minVal, maxVal, step; - pCamMaster->getIntParameterRange( - cmd, - [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { - minVal = val0; - maxVal = val1; - step = val2; - } - ); - EvsResult result = EvsResult::OK; - if (cmd == CameraParam::ABSOLUTE_FOCUS) { - // Try to turn off auto-focus - int32_t val1 = 1; - pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val1, 0); - } + pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program + result == EvsResult::INVALID_ARG); // Camera parameter is not supported - // Try to program a parameter - val0 = minVal + (std::rand() % (maxVal - minVal)); + // Non-master client expects to receive a parameter change notification + // whenever a master client adjusts it. + InfoEventDesc aNotification = {}; - // Rounding down - val0 = val0 - (val0 % step); - pCamMaster->setIntParameter(cmd, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); + pCamMaster->getParameter(CameraParam::BRIGHTNESS, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program + result == EvsResult::INVALID_ARG); // Camera parameter is not supported + if (result == EvsResult::OK) { + ASSERT_EQ(val0, val1) << "Values are not matched."; - // Wait a moment - sleep(1); + // Verify a change notification + frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); + ASSERT_EQ(InfoEventType::PARAMETER_CHANGED, + static_cast(aNotification.aType)); + ASSERT_EQ(CameraParam::BRIGHTNESS, + static_cast(aNotification.payload[0])); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); + } - // Non-master client expects to receive a parameter change notification - // whenever a master client adjusts it. - EvsEvent aNotification = {}; + // Try to program CameraParam::CONTRAST + val0 = 80; + val1 = 0; + pCamMaster->setParameter(CameraParam::CONTRAST, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program + result == EvsResult::INVALID_ARG); // Camera parameter is not supported - pCamMaster->getIntParameter(cmd, + if (result == EvsResult::OK) { + pCamMaster->getParameter(CameraParam::CONTRAST, [&result, &val1](auto status, auto value) { result = status; if (status == EvsResult::OK) { val1 = value; } }); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK); ASSERT_EQ(val0, val1) << "Values are not matched."; + // Verify a change notification - frameHandlerNonMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); - ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, - static_cast(aNotification.aType)); - ASSERT_EQ(cmd, + frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); + ASSERT_EQ(InfoEventType::PARAMETER_CHANGED, + static_cast(aNotification.aType)); + ASSERT_EQ(CameraParam::CONTRAST, static_cast(aNotification.payload[0])); ASSERT_EQ(val1, static_cast(aNotification.payload[1])); } // Try to adjust a parameter via non-master client - pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0, + pCamNonMaster->setParameter(CameraParam::CONTRAST, val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_EQ(EvsResult::INVALID_ARG, result); + ASSERT_TRUE(result == EvsResult::INVALID_ARG); // Non-master client attemps to be a master result = pCamNonMaster->setMaster(); - ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result); + ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST); // Master client retires from a master role result = pCamMaster->unsetMaster(); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK); // Try to adjust a parameter after being retired - pCamMaster->setIntParameter(camMasterCmds[0], val0, + pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_EQ(EvsResult::INVALID_ARG, result); + ASSERT_TRUE(result == EvsResult::INVALID_ARG); // Non-master client becomes a master result = pCamNonMaster->setMaster(); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK); // Try to adjust a parameter via new master client - for (auto &cmd : camNonMasterCmds) { - // Get a valid parameter value range - int32_t minVal, maxVal, step; - pCamNonMaster->getIntParameterRange( - cmd, - [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { - minVal = val0; - maxVal = val1; - step = val2; - } - ); + pCamNonMaster->setParameter(CameraParam::BRIGHTNESS, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program + result == EvsResult::INVALID_ARG); // Camera parameter is not supported - EvsResult result = EvsResult::OK; - if (cmd == CameraParam::ABSOLUTE_FOCUS) { - // Try to turn off auto-focus - int32_t val1 = 1; - pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val1, 0); - } + // Wait a moment + sleep(1); - // Try to program a parameter - val0 = minVal + (std::rand() % (maxVal - minVal)); - - // Rounding down - val0 = val0 - (val0 % step); - pCamNonMaster->setIntParameter(cmd, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - - // Wait a moment - sleep(1); - - // Non-master client expects to receive a parameter change notification - // whenever a master client adjusts it. - EvsEvent aNotification = {}; - - pCamNonMaster->getIntParameter(cmd, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val0, val1) << "Values are not matched."; - - // Verify a change notification - frameHandlerMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); - ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, - static_cast(aNotification.aType)); - ASSERT_EQ(cmd, - static_cast(aNotification.payload[0])); + // Verify a change notification + if (result == EvsResult::OK) { + frameHandlerMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); + ASSERT_EQ(static_cast(aNotification.aType), + InfoEventType::PARAMETER_CHANGED); + ASSERT_EQ(static_cast(aNotification.payload[0]), + CameraParam::BRIGHTNESS); ASSERT_EQ(val1, static_cast(aNotification.payload[1])); } // New master retires from a master role result = pCamNonMaster->unsetMaster(); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK); // Shutdown frameHandlerMaster->shutdown(); @@ -1060,18 +943,9 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { TEST_F(EvsHidlTest, HighPriorityCameraClient) { ALOGI("Starting HighPriorityCameraClient test"); - if (mIsHwModule) { - // This test is not for HW module implementation. - return; - } - // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Request exclusive access to the EVS display sp pDisplay = pEnumerator->openDisplay(); ASSERT_NE(pDisplay, nullptr); @@ -1080,38 +954,15 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { for (auto&& cam: cameraInfo) { // Create two clients sp pCam0 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam0, nullptr); sp pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam1, nullptr); - // Get the parameter list; this test will use the first command in both - // lists. - std::vector cam0Cmds, cam1Cmds; - pCam0->getParameterList([&cam0Cmds](hidl_vec cmdList) { - cam0Cmds.reserve(cmdList.size()); - for (auto &&cmd : cmdList) { - cam0Cmds.push_back(cmd); - } - } - ); - - pCam1->getParameterList([&cam1Cmds](hidl_vec cmdList) { - cam1Cmds.reserve(cmdList.size()); - for (auto &&cmd : cmdList) { - cam1Cmds.push_back(cmd); - } - } - ); - if (cam0Cmds.size() < 1 || cam1Cmds.size() < 1) { - // Cannot execute this test. - return; - } - // Set up a frame receiver object which will fire up its own thread. sp frameHandler0 = new FrameHandler(pCam0, cam, pDisplay, @@ -1131,121 +982,67 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { frameHandler0->waitForFrameCount(1); frameHandler1->waitForFrameCount(1); - // Client 1 becomes a master and programs a parameter. + // Client 1 becomes a master and programs a brightness. EvsResult result = EvsResult::OK; - // Get a valid parameter value range - int32_t minVal, maxVal, step; - pCam1->getIntParameterRange( - cam1Cmds[0], - [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { - minVal = val0; - maxVal = val1; - step = val2; - } - ); - - if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) { - // Try to turn off auto-focus - int32_t val1 = 0; - pCam1->getIntParameter(CameraParam::AUTO_FOCUS, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - if (val1 != 0) { - pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val1, 0); - } - } - - // Try to program a parameter with a random value [minVal, maxVal] - int32_t val0 = minVal + (std::rand() % (maxVal - minVal)); + int32_t val0 = 100; int32_t val1 = 0; - // Rounding down - val0 = val0 - (val0 % step); - result = pCam1->setMaster(); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK); - pCam1->setIntParameter(cam1Cmds[0], val0, + pCam1->setParameter(CameraParam::BRIGHTNESS, val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + // Verify a change notification - EvsEvent aNotification = {}; - bool timeout = - frameHandler0->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); - ASSERT_FALSE(timeout) << "Expected event does not arrive"; - ASSERT_EQ(static_cast(aNotification.aType), - EvsEventType::PARAMETER_CHANGED); - ASSERT_EQ(static_cast(aNotification.payload[0]), - cam1Cmds[0]); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); + InfoEventDesc aNotification = {}; + if (result == EvsResult::OK) { + bool timeout = + frameHandler0->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); + ASSERT_FALSE(timeout) << "Expected event does not arrive"; + ASSERT_EQ(static_cast(aNotification.aType), + InfoEventType::PARAMETER_CHANGED); + ASSERT_EQ(static_cast(aNotification.payload[0]), + CameraParam::BRIGHTNESS); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); + } // Client 0 steals a master role ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay)); - frameHandler1->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); - ASSERT_EQ(static_cast(aNotification.aType), - EvsEventType::MASTER_RELEASED); + frameHandler1->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(static_cast(aNotification.aType), + InfoEventType::MASTER_RELEASED); - // Client 0 programs a parameter - val0 = minVal + (std::rand() % (maxVal - minVal)); + // Client 0 programs a brightness + val0 = 50; val1 = 0; - - // Rounding down - val0 = val0 - (val0 % step); - - if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) { - // Try to turn off auto-focus - int32_t val1 = 0; - pCam0->getIntParameter(CameraParam::AUTO_FOCUS, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - if (val1 != 0) { - pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val1, 0); - } - } - - pCam0->setIntParameter(cam0Cmds[0], val0, + pCam0->setParameter(CameraParam::BRIGHTNESS, val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); // Verify a change notification - timeout = - frameHandler1->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); - ASSERT_FALSE(timeout) << "Expected event does not arrive"; - ASSERT_EQ(static_cast(aNotification.aType), - EvsEventType::PARAMETER_CHANGED); - ASSERT_EQ(static_cast(aNotification.payload[0]), - cam0Cmds[0]); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); + if (result == EvsResult::OK) { + bool timeout = + frameHandler1->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); + ASSERT_FALSE(timeout) << "Expected event does not arrive"; + ASSERT_EQ(static_cast(aNotification.aType), + InfoEventType::PARAMETER_CHANGED); + ASSERT_EQ(static_cast(aNotification.payload[0]), + CameraParam::BRIGHTNESS); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); + } // Turn off the display (yes, before the stream stops -- it should be handled) pDisplay->setDisplayState(DisplayState::NOT_VISIBLE); @@ -1264,248 +1061,6 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { } -/* - * CameraUseStreamConfigToDisplay: - * End to end test of data flowing from the camera to the display. Similar to - * CameraToDisplayRoundTrip test case but this case retrieves available stream - * configurations from EVS and uses one of them to start a video stream. - */ -TEST_F(EvsHidlTest, CameraUseStreamConfigToDisplay) { - ALOGI("Starting CameraUseStreamConfigToDisplay test"); - - // Get the camera list - loadCameraList(); - - // Request exclusive access to the EVS display - sp pDisplay = pEnumerator->openDisplay(); - ASSERT_NE(pDisplay, nullptr); - - // Test each reported camera - for (auto&& cam: cameraInfo) { - // choose a configuration that has a frame rate faster than minReqFps. - Stream targetCfg = {}; - const int32_t minReqFps = 15; - int32_t maxArea = 0; - camera_metadata_entry_t streamCfgs; - bool foundCfg = false; - if (!find_camera_metadata_entry( - reinterpret_cast(cam.metadata.data()), - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, - &streamCfgs)) { - // Stream configurations are found in metadata - RawStreamConfig *ptr = reinterpret_cast(streamCfgs.data.i32); - for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) { - if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && - ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) { - - if (ptr->width * ptr->height > maxArea && - ptr->framerate >= minReqFps) { - targetCfg.width = ptr->width; - targetCfg.height = ptr->height; - - maxArea = ptr->width * ptr->height; - foundCfg = true; - } - } - ++ptr; - } - } - targetCfg.format = - static_cast(HAL_PIXEL_FORMAT_RGBA_8888); - - if (!foundCfg) { - // Current EVS camera does not provide stream configurations in the - // metadata. - continue; - } - - sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) - .withDefault(nullptr); - ASSERT_NE(pCam, nullptr); - - // Set up a frame receiver object which will fire up its own thread. - sp frameHandler = new FrameHandler(pCam, cam, - pDisplay, - FrameHandler::eAutoReturn); - - - // Activate the display - pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME); - - // Start the camera's video stream - bool startResult = frameHandler->startStream(); - ASSERT_TRUE(startResult); - - // Wait a while to let the data flow - static const int kSecondsToWait = 5; - const int streamTimeMs = kSecondsToWait * kSecondsToMilliseconds - - kMaxStreamStartMilliseconds; - const unsigned minimumFramesExpected = streamTimeMs * kMinimumFramesPerSecond / - kSecondsToMilliseconds; - sleep(kSecondsToWait); - unsigned framesReceived = 0; - unsigned framesDisplayed = 0; - frameHandler->getFramesCounters(&framesReceived, &framesDisplayed); - EXPECT_EQ(framesReceived, framesDisplayed); - EXPECT_GE(framesDisplayed, minimumFramesExpected); - - // Turn off the display (yes, before the stream stops -- it should be handled) - pDisplay->setDisplayState(DisplayState::NOT_VISIBLE); - - // Shut down the streamer - frameHandler->shutdown(); - - // Explicitly release the camera - pEnumerator->closeCamera(pCam); - } - - // Explicitly release the display - pEnumerator->closeDisplay(pDisplay); -} - - -/* - * MultiCameraStreamUseConfig: - * Verify that each client can start and stop video streams on the same - * underlying camera with same configuration. - */ -TEST_F(EvsHidlTest, MultiCameraStreamUseConfig) { - ALOGI("Starting MultiCameraStream test"); - - if (mIsHwModule) { - // This test is not for HW module implementation. - return; - } - - // Get the camera list - loadCameraList(); - - // Test each reported camera - for (auto&& cam: cameraInfo) { - // choose a configuration that has a frame rate faster than minReqFps. - Stream targetCfg = {}; - const int32_t minReqFps = 15; - int32_t maxArea = 0; - camera_metadata_entry_t streamCfgs; - bool foundCfg = false; - if (!find_camera_metadata_entry( - reinterpret_cast(cam.metadata.data()), - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, - &streamCfgs)) { - // Stream configurations are found in metadata - RawStreamConfig *ptr = reinterpret_cast(streamCfgs.data.i32); - for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) { - if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && - ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) { - - if (ptr->width * ptr->height > maxArea && - ptr->framerate >= minReqFps) { - targetCfg.width = ptr->width; - targetCfg.height = ptr->height; - - maxArea = ptr->width * ptr->height; - foundCfg = true; - } - } - ++ptr; - } - } - targetCfg.format = - static_cast(HAL_PIXEL_FORMAT_RGBA_8888); - - if (!foundCfg) { - ALOGI("Device %s does not provide a list of supported stream configurations, skipped", - cam.v1.cameraId.c_str()); - - continue; - } - - // Create the first camera client with a selected stream configuration. - sp pCam0 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) - .withDefault(nullptr); - ASSERT_NE(pCam0, nullptr); - - // Try to create the second camera client with different stream - // configuration. - int32_t id = targetCfg.id; - targetCfg.id += 1; // EVS manager sees only the stream id. - sp pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) - .withDefault(nullptr); - ASSERT_EQ(pCam1, nullptr); - - // Try again with same stream configuration. - targetCfg.id = id; - pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) - .withDefault(nullptr); - ASSERT_NE(pCam1, nullptr); - - // Set up per-client frame receiver objects which will fire up its own thread - sp frameHandler0 = new FrameHandler(pCam0, cam, - nullptr, - FrameHandler::eAutoReturn); - ASSERT_NE(frameHandler0, nullptr); - - sp frameHandler1 = new FrameHandler(pCam1, cam, - nullptr, - FrameHandler::eAutoReturn); - ASSERT_NE(frameHandler1, nullptr); - - // Start the camera's video stream via client 0 - bool startResult = false; - startResult = frameHandler0->startStream() && - frameHandler1->startStream(); - ASSERT_TRUE(startResult); - - // Ensure the stream starts - frameHandler0->waitForFrameCount(1); - frameHandler1->waitForFrameCount(1); - - nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC); - - // Wait a bit, then ensure both clients get at least the required minimum number of frames - sleep(5); - nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC); - unsigned framesReceived0 = 0, framesReceived1 = 0; - frameHandler0->getFramesCounters(&framesReceived0, nullptr); - frameHandler1->getFramesCounters(&framesReceived1, nullptr); - framesReceived0 = framesReceived0 - 1; // Back out the first frame we already waited for - framesReceived1 = framesReceived1 - 1; // Back out the first frame we already waited for - nsecs_t runTime = end - firstFrame; - float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds); - float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds); - ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1); - EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond); - EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond); - - // Shutdown one client - frameHandler0->shutdown(); - - // Read frame counters again - frameHandler0->getFramesCounters(&framesReceived0, nullptr); - frameHandler1->getFramesCounters(&framesReceived1, nullptr); - - // Wait a bit again - sleep(5); - unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0; - frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr); - frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr); - EXPECT_EQ(framesReceived0, framesReceivedAfterStop0); - EXPECT_LT(framesReceived1, framesReceivedAfterStop1); - - // Shutdown another - frameHandler1->shutdown(); - - // Explicitly release the camera - pEnumerator->closeCamera(pCam0); - pEnumerator->closeCamera(pCam1); - } -} - - int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance()); ::testing::InitGoogleTest(&argc, argv); From 47b45af32cdea1788a1fd3e316f97d89aeddac2b Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Fri, 11 Oct 2019 10:17:33 -0700 Subject: [PATCH 0177/1022] Revert "Revert "Extend EVS interfaces and data types"" This reverts commit 1b73d28c04d250b581860dde082cf92c366371dc. --- automotive/evs/1.1/Android.bp | 4 +- automotive/evs/1.1/IEvsCamera.hal | 34 +- automotive/evs/1.1/IEvsCameraStream.hal | 19 +- automotive/evs/1.1/IEvsEnumerator.hal | 50 + automotive/evs/1.1/default/Android.bp | 20 +- automotive/evs/1.1/default/ConfigManager.cpp | 487 ++++++++++ automotive/evs/1.1/default/ConfigManager.h | 336 +++++++ .../evs/1.1/default/ConfigManagerUtil.cpp | 131 +++ .../evs/1.1/default/ConfigManagerUtil.h | 61 ++ automotive/evs/1.1/default/EvsCamera.cpp | 108 ++- automotive/evs/1.1/default/EvsCamera.h | 28 +- automotive/evs/1.1/default/EvsEnumerator.cpp | 109 ++- automotive/evs/1.1/default/EvsEnumerator.h | 25 +- .../resources/evs_default_configuration.xml | 68 ++ automotive/evs/1.1/default/service.cpp | 2 +- automotive/evs/1.1/types.hal | 49 +- automotive/evs/1.1/vts/functional/Android.bp | 2 + .../evs/1.1/vts/functional/FrameHandler.cpp | 187 ++-- .../evs/1.1/vts/functional/FrameHandler.h | 23 +- .../functional/VtsHalEvsV1_1TargetTest.cpp | 901 +++++++++++++----- 20 files changed, 2230 insertions(+), 414 deletions(-) create mode 100644 automotive/evs/1.1/IEvsEnumerator.hal create mode 100644 automotive/evs/1.1/default/ConfigManager.cpp create mode 100644 automotive/evs/1.1/default/ConfigManager.h create mode 100644 automotive/evs/1.1/default/ConfigManagerUtil.cpp create mode 100644 automotive/evs/1.1/default/ConfigManagerUtil.h create mode 100644 automotive/evs/1.1/default/resources/evs_default_configuration.xml diff --git a/automotive/evs/1.1/Android.bp b/automotive/evs/1.1/Android.bp index d2e85f1304..c850c91b21 100644 --- a/automotive/evs/1.1/Android.bp +++ b/automotive/evs/1.1/Android.bp @@ -10,13 +10,15 @@ hidl_interface { "types.hal", "IEvsCamera.hal", "IEvsCameraStream.hal", + "IEvsEnumerator.hal", ], interfaces: [ "android.hardware.automotive.evs@1.0", + "android.hardware.camera.device@3.2", "android.hardware.graphics.common@1.0", "android.hardware.graphics.common@1.1", "android.hardware.graphics.common@1.2", "android.hidl.base@1.0", ], - gen_java: true, + gen_java: false, } diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal index 21ca79e91f..975b6c6cae 100644 --- a/automotive/evs/1.1/IEvsCamera.hal +++ b/automotive/evs/1.1/IEvsCamera.hal @@ -25,6 +25,14 @@ import IEvsCameraStream; * Represents a single camera and is the primary interface for capturing images. */ interface IEvsCamera extends @1.0::IEvsCamera { + /** + * Returns the description of this camera. + * + * @return info The description of this camera. This must be the same value as + * reported by EvsEnumerator::getCameraList_1_1(). + */ + getCameraInfo_1_1() generates (CameraDesc info); + /** * Requests to pause EVS camera stream events. * @@ -100,7 +108,27 @@ interface IEvsCamera extends @1.0::IEvsCamera { unsetMaster() generates (EvsResult result); /** - * Requests to set a camera parameter. + * Retrieves a list of parameters this camera supports. + * + * @return params A list of CameraParam that this camera supports. + */ + getParameterList() generates (vec params); + + /** + * Requests a valid value range of a camera parameter + * + * @param id The identifier of camera parameter, CameraParam enum. + * + * @return min The lower bound of valid parameter value range. + * @return max The upper bound of valid parameter value range. + * @return step The resolution of values in valid range. + */ + getIntParameterRange(CameraParam id) + generates (int32_t min, int32_t max, int32_t step); + + /** + * Requests to set a camera parameter. Only a request from the master + * client will be processed successfully. * * @param id The identifier of camera parameter, CameraParam enum. * value A desired parameter value. @@ -114,7 +142,7 @@ interface IEvsCamera extends @1.0::IEvsCamera { * from what the client gives if, for example, the * driver does not support a target parameter. */ - setParameter(CameraParam id, int32_t value) + setIntParameter(CameraParam id, int32_t value) generates (EvsResult result, int32_t effectiveValue); /** @@ -126,5 +154,5 @@ interface IEvsCamera extends @1.0::IEvsCamera { * not supported. * value A value of requested camera parameter. */ - getParameter(CameraParam id) generates(EvsResult result, int32_t value); + getIntParameter(CameraParam id) generates(EvsResult result, int32_t value); }; diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal index 7c7f832103..9e4ea19f1d 100644 --- a/automotive/evs/1.1/IEvsCameraStream.hal +++ b/automotive/evs/1.1/IEvsCameraStream.hal @@ -17,15 +17,32 @@ package android.hardware.automotive.evs@1.1; import @1.0::IEvsCameraStream; +import @1.1::BufferDesc; +import @1.1::EvsEvent; /** * Implemented on client side to receive asynchronous streaming event deliveries. */ interface IEvsCameraStream extends @1.0::IEvsCameraStream { + + /** + * Receives calls from the HAL each time a video frame is ready for inspection. + * Buffer handles received by this method must be returned via calls to + * IEvsCamera::doneWithFrame_1_1(). When the video stream is stopped via a call + * to IEvsCamera::stopVideoStream(), this callback may continue to happen for + * some time as the pipeline drains. Each frame must still be returned. + * When the last frame in the stream has been delivered, STREAM_STOPPED + * event must be delivered. No further frame deliveries may happen + * thereafter. + * + * @param buffer a buffer descriptor of a delivered image frame. + */ + oneway deliverFrame_1_1(BufferDesc buffer); + /** * Receives calls from the HAL each time an event happens. * * @param event EVS event with possible event information. */ - oneway notifyEvent(EvsEvent event); + oneway notify(EvsEvent event); }; diff --git a/automotive/evs/1.1/IEvsEnumerator.hal b/automotive/evs/1.1/IEvsEnumerator.hal new file mode 100644 index 0000000000..1695821baa --- /dev/null +++ b/automotive/evs/1.1/IEvsEnumerator.hal @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package android.hardware.automotive.evs@1.1; + +import IEvsCamera; +import @1.0::IEvsEnumerator; +import @1.0::EvsResult; +import android.hardware.camera.device@3.2::Stream; + +/** + * Provides the mechanism for EVS camera discovery + */ +interface IEvsEnumerator extends @1.0::IEvsEnumerator { + /** + * Returns a list of all EVS cameras available to the system + * + * @return cameras A list of cameras availale for EVS service. + */ + getCameraList_1_1() generates (vec cameras); + + /** + * Gets the IEvsCamera associated with a cameraId from a CameraDesc + * + * Given a camera's unique cameraId from CameraDesc, returns the + * IEvsCamera interface associated with the specified camera. When + * done using the camera, the caller may release it by calling closeCamera(). + * + * @param cameraId A unique identifier of the camera. + * @param streamCfg A stream configuration the client wants to use. + * @return evsCamera EvsCamera object associated with a given cameraId. + * Returned object would be null if a camera device does + * not support a given stream configuration or is already + * configured differently by another client. + */ + openCamera_1_1(string cameraId, Stream streamCfg) generates (IEvsCamera evsCamera); +}; diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp index a46347102f..41cb4265e5 100644 --- a/automotive/evs/1.1/default/Android.bp +++ b/automotive/evs/1.1/default/Android.bp @@ -7,25 +7,41 @@ cc_binary { "service.cpp", "EvsCamera.cpp", "EvsEnumerator.cpp", - "EvsDisplay.cpp" + "EvsDisplay.cpp", + "ConfigManager.cpp", + "ConfigManagerUtil.cpp", ], init_rc: ["android.hardware.automotive.evs@1.1-service.rc"], shared_libs: [ "android.hardware.automotive.evs@1.0", "android.hardware.automotive.evs@1.1", + "android.hardware.camera.device@3.2", "libbase", "libbinder", - "libcutils", + "liblog", "libhardware", "libhidlbase", "liblog", "libui", "libutils", + "libcamera_metadata", + "libtinyxml2", ], cflags: [ "-O0", "-g", ], + + required: [ + "evs_default_configuration.xml", + ], +} + +prebuilt_etc { + name: "evs_default_configuration.xml", + + src: "resources/evs_default_configuration.xml", + sub_dir: "automotive/evs", } diff --git a/automotive/evs/1.1/default/ConfigManager.cpp b/automotive/evs/1.1/default/ConfigManager.cpp new file mode 100644 index 0000000000..4f46f9dbca --- /dev/null +++ b/automotive/evs/1.1/default/ConfigManager.cpp @@ -0,0 +1,487 @@ +/* + * 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. + */ + +#include +#include +#include + +#include +#include +#include + +#include "ConfigManager.h" + +using ::android::hardware::camera::device::V3_2::StreamRotation; + + +ConfigManager::~ConfigManager() { + /* Nothing to do */ +} + + +void ConfigManager::readCameraInfo(const XMLElement * const aCameraElem) { + if (aCameraElem == nullptr) { + ALOGW("XML file does not have required camera element"); + return; + } + + const XMLElement *curElem = aCameraElem->FirstChildElement(); + while (curElem != nullptr) { + if (!strcmp(curElem->Name(), "group")) { + /* camera group identifier */ + const char *group_id = curElem->FindAttribute("group_id")->Value(); + + /* create CameraGroup */ + unique_ptr aCameraGroup(new ConfigManager::CameraGroup()); + + /* add a camera device to its group */ + addCameraDevices(curElem->FindAttribute("device_id")->Value(), aCameraGroup); + + /* a list of camera stream configurations */ + const XMLElement *childElem = + curElem->FirstChildElement("caps")->FirstChildElement("stream"); + while (childElem != nullptr) { + /* read 5 attributes */ + const XMLAttribute *idAttr = childElem->FindAttribute("id"); + const XMLAttribute *widthAttr = childElem->FindAttribute("width"); + const XMLAttribute *heightAttr = childElem->FindAttribute("height"); + const XMLAttribute *fmtAttr = childElem->FindAttribute("format"); + const XMLAttribute *fpsAttr = childElem->FindAttribute("framerate"); + + const int32_t id = stoi(idAttr->Value()); + int32_t framerate = 0; + if (fpsAttr != nullptr) { + framerate = stoi(fpsAttr->Value()); + } + + int32_t pixFormat; + if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), + pixFormat)) { + RawStreamConfiguration cfg = { + id, + stoi(widthAttr->Value()), + stoi(heightAttr->Value()), + pixFormat, + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, + framerate + }; + aCameraGroup->streamConfigurations[id] = cfg; + } + + childElem = childElem->NextSiblingElement("stream"); + } + + /* camera group synchronization */ + const char *sync = curElem->FindAttribute("synchronized")->Value(); + aCameraGroup->synchronized = + static_cast(strcmp(sync, "false")); + + /* add a group to hash map */ + mCameraGroups[group_id] = std::move(aCameraGroup); + } else if (!strcmp(curElem->Name(), "device")) { + /* camera unique identifier */ + const char *id = curElem->FindAttribute("id")->Value(); + + /* camera mount location */ + const char *pos = curElem->FindAttribute("position")->Value(); + + /* store read camera module information */ + mCameraInfo[id] = readCameraDeviceInfo(curElem); + + /* assign a camera device to a position group */ + mCameraPosition[pos].emplace(id); + } else { + /* ignore other device types */ + ALOGD("Unknown element %s is ignored", curElem->Name()); + } + + curElem = curElem->NextSiblingElement(); + } +} + + +unique_ptr +ConfigManager::readCameraDeviceInfo(const XMLElement *aDeviceElem) { + if (aDeviceElem == nullptr) { + return nullptr; + } + + /* create a CameraInfo to be filled */ + unique_ptr aCamera(new ConfigManager::CameraInfo()); + + /* size information to allocate camera_metadata_t */ + size_t totalEntries = 0; + size_t totalDataSize = 0; + + /* read device capabilities */ + totalEntries += + readCameraCapabilities(aDeviceElem->FirstChildElement("caps"), + aCamera, + totalDataSize); + + + /* read camera metadata */ + totalEntries += + readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"), + aCamera, + totalDataSize); + + /* construct camera_metadata_t */ + if (!constructCameraMetadata(aCamera, totalEntries, totalDataSize)) { + ALOGW("Either failed to allocate memory or " + "allocated memory was not large enough"); + } + + return aCamera; +} + + +size_t ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem, + unique_ptr &aCamera, + size_t &dataSize) { + if (aCapElem == nullptr) { + return 0; + } + + string token; + const XMLElement *curElem = nullptr; + + /* a list of supported camera parameters/controls */ + curElem = aCapElem->FirstChildElement("supported_controls"); + if (curElem != nullptr) { + const XMLElement *ctrlElem = curElem->FirstChildElement("control"); + while (ctrlElem != nullptr) { + const char *nameAttr = ctrlElem->FindAttribute("name")->Value();; + const int32_t minVal = stoi(ctrlElem->FindAttribute("min")->Value()); + const int32_t maxVal = stoi(ctrlElem->FindAttribute("max")->Value()); + + int32_t stepVal = 1; + const XMLAttribute *stepAttr = ctrlElem->FindAttribute("step"); + if (stepAttr != nullptr) { + stepVal = stoi(stepAttr->Value()); + } + + CameraParam aParam; + if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr, + aParam)) { + aCamera->controls.emplace( + aParam, + make_tuple(minVal, maxVal, stepVal) + ); + } + + ctrlElem = ctrlElem->NextSiblingElement("control"); + } + } + + /* a list of camera stream configurations */ + curElem = aCapElem->FirstChildElement("stream"); + while (curElem != nullptr) { + /* read 5 attributes */ + const XMLAttribute *idAttr = curElem->FindAttribute("id"); + const XMLAttribute *widthAttr = curElem->FindAttribute("width"); + const XMLAttribute *heightAttr = curElem->FindAttribute("height"); + const XMLAttribute *fmtAttr = curElem->FindAttribute("format"); + const XMLAttribute *fpsAttr = curElem->FindAttribute("framerate"); + + const int32_t id = stoi(idAttr->Value()); + int32_t framerate = 0; + if (fpsAttr != nullptr) { + framerate = stoi(fpsAttr->Value()); + } + + int32_t pixFormat; + if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), + pixFormat)) { + RawStreamConfiguration cfg = { + id, + stoi(widthAttr->Value()), + stoi(heightAttr->Value()), + pixFormat, + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, + framerate + }; + aCamera->streamConfigurations[id] = cfg; + } + + curElem = curElem->NextSiblingElement("stream"); + } + + dataSize = calculate_camera_metadata_entry_data_size( + get_camera_metadata_tag_type( + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS + ), + aCamera->streamConfigurations.size() * kStreamCfgSz + ); + + /* a single camera metadata entry contains multiple stream configurations */ + return dataSize > 0 ? 1 : 0; +} + + +size_t ConfigManager::readCameraMetadata(const XMLElement * const aParamElem, + unique_ptr &aCamera, + size_t &dataSize) { + if (aParamElem == nullptr) { + return 0; + } + + const XMLElement *curElem = aParamElem->FirstChildElement("parameter"); + size_t numEntries = 0; + camera_metadata_tag_t tag; + while (curElem != nullptr) { + if (!ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(), + tag)) { + switch(tag) { + case ANDROID_LENS_DISTORTION: + case ANDROID_LENS_POSE_ROTATION: + case ANDROID_LENS_POSE_TRANSLATION: + case ANDROID_LENS_INTRINSIC_CALIBRATION: { + /* float[] */ + size_t count = 0; + void *data = ConfigManagerUtil::convertFloatArray( + curElem->FindAttribute("size")->Value(), + curElem->FindAttribute("value")->Value(), + count + ); + + aCamera->cameraMetadata[tag] = + make_pair(make_unique(data), count); + + ++numEntries; + dataSize += calculate_camera_metadata_entry_data_size( + get_camera_metadata_tag_type(tag), count + ); + + break; + } + + default: + ALOGW("Parameter %s is not supported", + curElem->FindAttribute("name")->Value()); + break; + } + } + + curElem = curElem->NextSiblingElement("parameter"); + } + + return numEntries; +} + + +bool ConfigManager::constructCameraMetadata(unique_ptr &aCamera, + const size_t totalEntries, + const size_t totalDataSize) { + if (!aCamera->allocate(totalEntries, totalDataSize)) { + ALOGE("Failed to allocate memory for camera metadata"); + return false; + } + + const size_t numStreamConfigs = aCamera->streamConfigurations.size(); + unique_ptr data(new int32_t[kStreamCfgSz * numStreamConfigs]); + int32_t *ptr = data.get(); + for (auto &cfg : aCamera->streamConfigurations) { + for (auto i = 0; i < kStreamCfgSz; ++i) { + *ptr++ = cfg.second[i]; + } + } + int32_t err = add_camera_metadata_entry(aCamera->characteristics, + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, + data.get(), + numStreamConfigs * kStreamCfgSz); + + if (err) { + ALOGE("Failed to add stream configurations to metadata, ignored"); + return false; + } + + bool success = true; + for (auto &[tag, entry] : aCamera->cameraMetadata) { + /* try to add new camera metadata entry */ + int32_t err = add_camera_metadata_entry(aCamera->characteristics, + tag, + entry.first.get(), + entry.second); + if (err) { + ALOGE("Failed to add an entry with a tag 0x%X", tag); + + /* may exceed preallocated capacity */ + ALOGE("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled", + get_camera_metadata_entry_count(aCamera->characteristics), + get_camera_metadata_entry_capacity(aCamera->characteristics), + get_camera_metadata_data_count(aCamera->characteristics), + get_camera_metadata_data_capacity(aCamera->characteristics)); + ALOGE("\tCurrent metadata entry requires %ld bytes", + calculate_camera_metadata_entry_data_size(tag, entry.second)); + + success = false; + } + } + + ALOGV("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled", + get_camera_metadata_entry_count(aCamera->characteristics), + get_camera_metadata_entry_capacity(aCamera->characteristics), + get_camera_metadata_data_count(aCamera->characteristics), + get_camera_metadata_data_capacity(aCamera->characteristics)); + + return success; +} + + +void ConfigManager::readSystemInfo(const XMLElement * const aSysElem) { + if (aSysElem == nullptr) { + return; + } + + /* + * Please note that this function assumes that a given system XML element + * and its child elements follow DTD. If it does not, it will cause a + * segmentation fault due to the failure of finding expected attributes. + */ + + /* read number of cameras available in the system */ + const XMLElement *xmlElem = aSysElem->FirstChildElement("num_cameras"); + if (xmlElem != nullptr) { + mSystemInfo.numCameras = + stoi(xmlElem->FindAttribute("value")->Value()); + } +} + + +void ConfigManager::readDisplayInfo(const XMLElement * const aDisplayElem) { + if (aDisplayElem == nullptr) { + ALOGW("XML file does not have required camera element"); + return; + } + + const XMLElement *curDev = aDisplayElem->FirstChildElement("device"); + while (curDev != nullptr) { + const char *id = curDev->FindAttribute("id")->Value(); + //const char *pos = curDev->FirstAttribute("position")->Value(); + + unique_ptr dpy(new DisplayInfo()); + if (dpy == nullptr) { + ALOGE("Failed to allocate memory for DisplayInfo"); + return; + } + + const XMLElement *cap = curDev->FirstChildElement("caps"); + if (cap != nullptr) { + const XMLElement *curStream = cap->FirstChildElement("stream"); + while (curStream != nullptr) { + /* read 4 attributes */ + const XMLAttribute *idAttr = curStream->FindAttribute("id"); + const XMLAttribute *widthAttr = curStream->FindAttribute("width"); + const XMLAttribute *heightAttr = curStream->FindAttribute("height"); + const XMLAttribute *fmtAttr = curStream->FindAttribute("format"); + + const int32_t id = stoi(idAttr->Value()); + int32_t pixFormat; + if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), + pixFormat)) { + RawStreamConfiguration cfg = { + id, + stoi(widthAttr->Value()), + stoi(heightAttr->Value()), + pixFormat, + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT, + 0 // unused + }; + dpy->streamConfigurations[id] = cfg; + } + + curStream = curStream->NextSiblingElement("stream"); + } + } + + mDisplayInfo[id] = std::move(dpy); + curDev = curDev->NextSiblingElement("device"); + } + + return; +} + + +bool ConfigManager::readConfigDataFromXML() noexcept { + XMLDocument xmlDoc; + + const int64_t parsingStart = android::elapsedRealtimeNano(); + + /* load and parse a configuration file */ + xmlDoc.LoadFile(mConfigFilePath); + if (xmlDoc.ErrorID() != XML_SUCCESS) { + ALOGE("Failed to load and/or parse a configuration file, %s", xmlDoc.ErrorStr()); + return false; + } + + /* retrieve the root element */ + const XMLElement *rootElem = xmlDoc.RootElement(); + if (strcmp(rootElem->Name(), "configuration")) { + ALOGE("A configuration file is not in the required format. " + "See /etc/automotive/evs/evs_configuration.dtd"); + return false; + } + + /* + * parse camera information; this needs to be done before reading system + * information + */ + readCameraInfo(rootElem->FirstChildElement("camera")); + + /* parse system information */ + readSystemInfo(rootElem->FirstChildElement("system")); + + /* parse display information */ + readDisplayInfo(rootElem->FirstChildElement("display")); + + const int64_t parsingEnd = android::elapsedRealtimeNano(); + ALOGI("Parsing configuration file takes %lf (ms)", + (double)(parsingEnd - parsingStart) / 1000000.0); + + + return true; +} + + +void ConfigManager::addCameraDevices(const char *devices, + unique_ptr &aGroup) { + stringstream device_list(devices); + string token; + while (getline(device_list, token, ',')) { + aGroup->devices.emplace(token); + } +} + + +std::unique_ptr ConfigManager::Create(const char *path) { + unique_ptr cfgMgr(new ConfigManager(path)); + + /* + * Read a configuration from XML file + * + * If this is too slow, ConfigManager::readConfigDataFromBinary() and + * ConfigManager::writeConfigDataToBinary()can serialize CameraInfo object + * to the filesystem and construct CameraInfo instead; this was + * evaluated as 10x faster. + */ + if (!cfgMgr->readConfigDataFromXML()) { + return nullptr; + } else { + return cfgMgr; + } +} + diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h new file mode 100644 index 0000000000..0275f904e5 --- /dev/null +++ b/automotive/evs/1.1/default/ConfigManager.h @@ -0,0 +1,336 @@ +/* + * 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. + */ +#ifndef CONFIG_MANAGER_H +#define CONFIG_MANAGER_H + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "ConfigManagerUtil.h" + +using namespace std; +using namespace tinyxml2; + +using ::android::hardware::hidl_vec; +using ::android::hardware::camera::device::V3_2::Stream; +using ::android::hardware::automotive::evs::V1_1::CameraParam; + +/* + * Plese note that this is different from what is defined in + * libhardware/modules/camera/3_4/metadata/types.h; this has one additional + * field to store a framerate. + */ +const size_t kStreamCfgSz = 6; +typedef std::array RawStreamConfiguration; + +class ConfigManager { +public: + static std::unique_ptr Create(const char *path = ""); + ConfigManager(const ConfigManager&) = delete; + ConfigManager& operator=(const ConfigManager&) = delete; + + virtual ~ConfigManager(); + + /* Camera device's capabilities and metadata */ + class CameraInfo { + public: + CameraInfo() : + characteristics(nullptr) { + /* Nothing to do */ + } + + virtual ~CameraInfo() { + free_camera_metadata(characteristics); + } + + /* Allocate memory for camera_metadata_t */ + bool allocate(size_t entry_cap, size_t data_cap) { + if (characteristics != nullptr) { + ALOGE("Camera metadata is already allocated"); + return false; + } + + characteristics = allocate_camera_metadata(entry_cap, data_cap); + return characteristics != nullptr; + } + + /* + * List of supported controls that the master client can program. + * Paraemters are stored with its valid range + */ + unordered_map> controls; + + /* List of supported frame rates */ + unordered_set frameRates; + + /* + * List of supported output stream configurations; each array stores + * format, width, height, and direction values in the order. + */ + unordered_map streamConfigurations; + + /* + * Internal storage for camera metadata. Each entry holds a pointer to + * data and number of elements + */ + unordered_map, size_t>> cameraMetadata; + + /* Camera module characteristics */ + camera_metadata_t *characteristics; + }; + + class CameraGroup { + public: + CameraGroup() {} + + /* ID of member camera devices */ + unordered_set devices; + + /* The capture operation of member camera devices are synchronized */ + bool synchronized = false; + + /* + * List of stream configurations that are supposed by all camera devices + * in this group. + */ + unordered_map streamConfigurations; + }; + + class SystemInfo { + public: + /* number of available cameras */ + int32_t numCameras = 0; + }; + + class DisplayInfo { + public: + /* + * List of supported input stream configurations; each array stores + * format, width, height, and direction values in the order. + */ + unordered_map streamConfigurations; + }; + + /* + * Return system information + * + * @return SystemInfo + * Constant reference of SystemInfo. + */ + const SystemInfo &getSystemInfo() { + return mSystemInfo; + } + + /* + * Return a list of cameras + * + * This function assumes that it is not being called frequently. + * + * @return vector + * A vector that contains unique camera device identifiers. + */ + vector getCameraList() { + vector aList; + for (auto &v : mCameraInfo) { + aList.emplace_back(v.first); + } + + return aList; + } + + + /* + * Return a list of cameras + * + * @return CameraGroup + * A pointer to a camera group identified by a given id. + */ + unique_ptr& getCameraGroup(const string& gid) { + return mCameraGroups[gid]; + } + + + /* + * Return a camera metadata + * + * @param cameraId + * Unique camera node identifier in string + * + * @return unique_ptr + * A pointer to CameraInfo that is associated with a given camera + * ID. This returns a null pointer if this does not recognize a + * given camera identifier. + */ + unique_ptr& getCameraInfo(const string cameraId) noexcept { + return mCameraInfo[cameraId]; + } + +private: + /* Constructors */ + ConfigManager(const char *xmlPath) : + mConfigFilePath(xmlPath) { + } + + /* System configuration */ + SystemInfo mSystemInfo; + + /* Internal data structure for camera device information */ + unordered_map> mCameraInfo; + + /* Internal data structure for camera device information */ + unordered_map> mDisplayInfo; + + /* Camera groups are stored in hash map */ + unordered_map> mCameraGroups; + + /* + * Camera positions are stored in hash map. + * The position must be one of front, rear, left, and right. + */ + unordered_map> mCameraPosition; + + /* A path to XML configuration file */ + const char *mConfigFilePath; + + /* + * Parse a given EVS configuration file and store the information + * internally. + * + * @return bool + * True if it completes parsing a file successfully. + */ + bool readConfigDataFromXML() noexcept; + + /* + * read the information of the vehicle + * + * @param aSysElem + * A pointer to "system" XML element. + */ + void readSystemInfo(const XMLElement * const aSysElem); + + /* + * read the information of camera devices + * + * @param aCameraElem + * A pointer to "camera" XML element that may contain multiple + * "device" elements. + */ + void readCameraInfo(const XMLElement * const aCameraElem); + + /* + * read display device information + * + * @param aDisplayElem + * A pointer to "display" XML element that may contain multiple + * "device" elements. + */ + void readDisplayInfo(const XMLElement * const aDisplayElem); + + /* + * read camera device information + * + * @param aDeviceElem + * A pointer to "device" XML element that contains camera module + * capability info and its characteristics. + * + * @return unique_ptr + * A pointer to CameraInfo class that contains camera module + * capability and characteristics. Please note that this transfers + * the ownership of created CameraInfo to the caller. + */ + unique_ptr readCameraDeviceInfo(const XMLElement *aDeviceElem); + + /* + * read camera metadata + * + * @param aCapElem + * A pointer to "cap" XML element. + * @param aCamera + * A pointer to CameraInfo that is being filled by this method. + * @param dataSize + * Required size of memory to store camera metadata found in this + * method. This is calculated in this method and returned to the + * caller for camera_metadata allocation. + * + * @return size_t + * Number of camera metadata entries + */ + size_t readCameraCapabilities(const XMLElement * const aCapElem, + unique_ptr &aCamera, + size_t &dataSize); + + /* + * read camera metadata + * + * @param aParamElem + * A pointer to "characteristics" XML element. + * @param aCamera + * A pointer to CameraInfo that is being filled by this method. + * @param dataSize + * Required size of memory to store camera metadata found in this + * method. + * + * @return size_t + * Number of camera metadata entries + */ + size_t readCameraMetadata(const XMLElement * const aParamElem, + unique_ptr &aCamera, + size_t &dataSize); + + /* + * construct camera_metadata_t from camera capabilities and metadata + * + * @param aCamera + * A pointer to CameraInfo that is being filled by this method. + * @param totalEntries + * Number of camera metadata entries to be added. + * @param totalDataSize + * Sum of sizes of camera metadata entries to be added. + * + * @return bool + * False if either it fails to allocate memory for camera metadata + * or its size is not large enough to add all found camera metadata + * entries. + */ + bool constructCameraMetadata(unique_ptr &aCamera, + const size_t totalEntries, + const size_t totalDataSize); + + /* + * parse a comma-separated list of camera devices and add them to + * CameraGroup. + * + * @param devices + * A comma-separated list of camera device identifiers. + * @param aGroup + * Camera group which cameras will be added to. + */ + void addCameraDevices(const char *devices, + unique_ptr &aGroup); +}; +#endif // CONFIG_MANAGER_H + diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.cpp b/automotive/evs/1.1/default/ConfigManagerUtil.cpp new file mode 100644 index 0000000000..8206daa6d7 --- /dev/null +++ b/automotive/evs/1.1/default/ConfigManagerUtil.cpp @@ -0,0 +1,131 @@ +/* + * 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. + */ + +#include "ConfigManagerUtil.h" + +#include +#include +#include + +#include +#include + + +bool ConfigManagerUtil::convertToEvsCameraParam(const string &id, + CameraParam &camParam) { + string trimmed = ConfigManagerUtil::trimString(id); + bool success = true; + + if (!trimmed.compare("BRIGHTNESS")) { + camParam = CameraParam::BRIGHTNESS; + } else if (!trimmed.compare("CONTRAST")) { + camParam = CameraParam::CONTRAST; + } else if (!trimmed.compare("AUTOGAIN")) { + camParam = CameraParam::AUTOGAIN; + } else if (!trimmed.compare("GAIN")) { + camParam = CameraParam::GAIN; + } else if (!trimmed.compare("AUTO_WHITE_BALANCE")) { + camParam = CameraParam::AUTO_WHITE_BALANCE; + } else if (!trimmed.compare("WHITE_BALANCE_TEMPERATURE")) { + camParam = CameraParam::WHITE_BALANCE_TEMPERATURE; + } else if (!trimmed.compare("SHARPNESS")) { + camParam = CameraParam::SHARPNESS; + } else if (!trimmed.compare("AUTO_EXPOSURE")) { + camParam = CameraParam::AUTO_EXPOSURE; + } else if (!trimmed.compare("ABSOLUTE_EXPOSURE")) { + camParam = CameraParam::ABSOLUTE_EXPOSURE; + } else if (!trimmed.compare("ABSOLUTE_FOCUS")) { + camParam = CameraParam::ABSOLUTE_FOCUS; + } else if (!trimmed.compare("AUTO_FOCUS")) { + camParam = CameraParam::AUTO_FOCUS; + } else if (!trimmed.compare("ABSOLUTE_ZOOM")) { + camParam = CameraParam::ABSOLUTE_ZOOM; + } else { + success = false; + } + + return success; +} + + +bool ConfigManagerUtil::convertToPixelFormat(const string &format, + int32_t &pixFormat) { + string trimmed = ConfigManagerUtil::trimString(format); + bool success = true; + + if (!trimmed.compare("RGBA_8888")) { + pixFormat = HAL_PIXEL_FORMAT_RGBA_8888; + } else if (!trimmed.compare("YCRCB_420_SP")) { + pixFormat = HAL_PIXEL_FORMAT_YCRCB_420_SP; + } else if (!trimmed.compare("YCBCR_422_I")) { + pixFormat = HAL_PIXEL_FORMAT_YCBCR_422_I; + } else { + success = false; + } + + return success; +} + + +bool ConfigManagerUtil::convertToMetadataTag(const char *name, + camera_metadata_tag &aTag) { + if (!strcmp(name, "LENS_DISTORTION")) { + aTag = ANDROID_LENS_DISTORTION; + } else if (!strcmp(name, "LENS_INTRINSIC_CALIBRATION")) { + aTag = ANDROID_LENS_INTRINSIC_CALIBRATION; + } else if (!strcmp(name, "LENS_POSE_ROTATION")) { + aTag = ANDROID_LENS_POSE_ROTATION; + } else if (!strcmp(name, "LENS_POSE_TRANSLATION")) { + aTag = ANDROID_LENS_POSE_TRANSLATION; + } else { + return false; + } + + return true; +} + + +float *ConfigManagerUtil::convertFloatArray(const char *sz, const char *vals, + size_t &count, const char delimiter) { + string size_string(sz); + string value_string(vals); + + count = stoi(size_string); + float *result = new float[count]; + stringstream values(value_string); + + int32_t idx = 0; + string token; + while (getline(values, token, delimiter)) { + result[idx++] = stof(token); + } + + return result; +} + + +string ConfigManagerUtil::trimString(const string &src, const string &ws) { + const auto s = src.find_first_not_of(ws); + if (s == string::npos) { + return ""; + } + + const auto e = src.find_last_not_of(ws); + const auto r = e - s + 1; + + return src.substr(s, r); +} + diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.h b/automotive/evs/1.1/default/ConfigManagerUtil.h new file mode 100644 index 0000000000..8c89ae7745 --- /dev/null +++ b/automotive/evs/1.1/default/ConfigManagerUtil.h @@ -0,0 +1,61 @@ +/* + * 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. + */ +#ifndef CONFIG_MANAGER_UTIL_H +#define CONFIG_MANAGER_UTIL_H + +#include +#include +#include +#include + +using namespace std; +using ::android::hardware::automotive::evs::V1_1::CameraParam; + + +class ConfigManagerUtil { +public: + /** + * Convert a given string into V4L2_CID_* + */ + static bool convertToEvsCameraParam(const string &id, + CameraParam &camParam); + /** + * Convert a given string into android.hardware.graphics.common.PixelFormat + */ + static bool convertToPixelFormat(const string &format, + int32_t &pixelFormat); + /** + * Convert a given string into corresponding camera metadata data tag defined in + * system/media/camera/include/system/camera_metadta_tags.h + */ + static bool convertToMetadataTag(const char *name, + camera_metadata_tag &aTag); + /** + * Convert a given string into a floating value array + */ + static float *convertFloatArray(const char *sz, + const char *vals, + size_t &count, + const char delimiter = ','); + /** + * Trim a string + */ + static string trimString(const string &src, + const string &ws = " \n\r\t\f\v"); +}; + +#endif // CONFIG_MANAGER_UTIL_H + diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp index 2d55566349..5ba753da2e 100644 --- a/automotive/evs/1.1/default/EvsCamera.cpp +++ b/automotive/evs/1.1/default/EvsCamera.cpp @@ -40,28 +40,21 @@ const char EvsCamera::kCameraName_Backup[] = "backup"; const unsigned MAX_BUFFERS_IN_FLIGHT = 100; -EvsCamera::EvsCamera(const char *id) : +EvsCamera::EvsCamera(const char *id, + unique_ptr &camInfo) : mFramesAllowed(0), mFramesInUse(0), - mStreamState(STOPPED) { + mStreamState(STOPPED), + mCameraInfo(camInfo) { ALOGD("EvsCamera instantiated"); - mDescription.cameraId = id; + /* set a camera id */ + mDescription.v1.cameraId = id; - // Set up dummy data for testing - if (mDescription.cameraId == kCameraName_Backup) { - mWidth = 640; // full NTSC/VGA - mHeight = 480; // full NTSC/VGA - mDescription.vendorFlags = 0xFFFFFFFF; // Arbitrary value - } else { - mWidth = 320; // 1/2 NTSC/VGA - mHeight = 240; // 1/2 NTSC/VGA - } - - mFormat = HAL_PIXEL_FORMAT_RGBA_8888; - mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE | - GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY; + /* set camera metadata */ + mDescription.metadata.setToExternal((uint8_t *)camInfo->characteristics, + get_camera_metadata_size(camInfo->characteristics)); } @@ -109,7 +102,7 @@ Return EvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) { ALOGD("getCameraInfo"); // Send back our self description - _hidl_cb(mDescription); + _hidl_cb(mDescription.v1); return Void(); } @@ -194,7 +187,7 @@ Return EvsCamera::stopVideoStream() { // Block outside the mutex until the "stop" flag has been acknowledged // We won't send any more frames, but the client might still get some already in flight - ALOGD("Waiting for stream thread to end.."); + ALOGD("Waiting for stream thread to end..."); lock.unlock(); mCaptureThread.join(); lock.lock(); @@ -238,6 +231,15 @@ Return EvsCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/, int3 // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow. +Return EvsCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) { + ALOGD("getCameraInfo_1_1"); + + // Send back our self description + _hidl_cb(mDescription); + return Void(); +} + + Return EvsCamera::doneWithFrame_1_1(const BufferDesc_1_1& bufDesc) { std::lock_guard lock(mAccessLock); returnBuffer(bufDesc.bufferId, bufDesc.buffer.nativeHandle); @@ -278,8 +280,29 @@ Return EvsCamera::unsetMaster() { } -Return EvsCamera::setParameter(CameraParam id, int32_t value, - setParameter_cb _hidl_cb) { +Return EvsCamera::getParameterList(getParameterList_cb _hidl_cb) { + hidl_vec hidlCtrls; + hidlCtrls.resize(mCameraInfo->controls.size()); + unsigned idx = 0; + for (auto& [cid, cfg] : mCameraInfo->controls) { + hidlCtrls[idx++] = cid; + } + + _hidl_cb(hidlCtrls); + return Void(); +} + + +Return EvsCamera::getIntParameterRange(CameraParam id, + getIntParameterRange_cb _hidl_cb) { + auto range = mCameraInfo->controls[id]; + _hidl_cb(get<0>(range), get<1>(range), get<2>(range)); + return Void(); +} + + +Return EvsCamera::setIntParameter(CameraParam id, int32_t value, + setIntParameter_cb _hidl_cb) { // Default implementation does not support this. (void)id; (void)value; @@ -288,7 +311,8 @@ Return EvsCamera::setParameter(CameraParam id, int32_t value, } -Return EvsCamera::getParameter(CameraParam id, getParameter_cb _hidl_cb) { +Return EvsCamera::getIntParameter(CameraParam id, + getIntParameter_cb _hidl_cb) { // Default implementation does not support this. (void)id; _hidl_cb(EvsResult::INVALID_ARG, 0); @@ -471,9 +495,7 @@ void EvsCamera::generateFrames() { fillTestFrame(newBuffer); // Issue the (asynchronous) callback to the client -- can't be holding the lock - EvsEvent event; - event.buffer(newBuffer); - auto result = mStream->notifyEvent(event); + auto result = mStream->deliverFrame_1_1(newBuffer); if (result.isOk()) { ALOGD("Delivered %p as id %d", newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId); @@ -506,10 +528,8 @@ void EvsCamera::generateFrames() { // If we've been asked to stop, send an event to signal the actual end of stream EvsEvent event; - InfoEventDesc desc = {}; - desc.aType = InfoEventType::STREAM_STOPPED; - event.info(desc); - auto result = mStream->notifyEvent(event); + event.aType = EvsEventType::STREAM_STOPPED; + auto result = mStream->notify(event); if (!result.isOk()) { ALOGE("Error delivering end of stream marker"); } @@ -616,6 +636,38 @@ void EvsCamera::returnBuffer(const uint32_t bufferId, const buffer_handle_t memH } +sp EvsCamera::Create(const char *deviceName) { + unique_ptr nullCamInfo = nullptr; + + return Create(deviceName, nullCamInfo); +} + + +sp EvsCamera::Create(const char *deviceName, + unique_ptr &camInfo, + const Stream *streamCfg) { + sp evsCamera = new EvsCamera(deviceName, camInfo); + if (evsCamera == nullptr) { + return nullptr; + } + + /* default implementation does not use a given configuration */ + (void)streamCfg; + + /* Use the first resolution from the list for the testing */ + auto it = camInfo->streamConfigurations.begin(); + evsCamera->mWidth = it->second[1]; + evsCamera->mHeight = it->second[2]; + evsCamera->mDescription.v1.vendorFlags = 0xFFFFFFFF; // Arbitrary test value + + evsCamera->mFormat = HAL_PIXEL_FORMAT_RGBA_8888; + evsCamera->mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE | + GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY; + + return evsCamera; +} + + } // namespace implementation } // namespace V1_0 } // namespace evs diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h index 47a3164892..c15b4b117b 100644 --- a/automotive/evs/1.1/default/EvsCamera.h +++ b/automotive/evs/1.1/default/EvsCamera.h @@ -25,6 +25,8 @@ #include +#include "ConfigManager.h" + using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc; using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc; using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream; @@ -59,18 +61,28 @@ public: Return setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override; // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow. + Return getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) override; Return pauseVideoStream() override; Return resumeVideoStream() override; Return doneWithFrame_1_1(const BufferDesc_1_1& buffer) override; Return setMaster() override; Return forceMaster(const sp& display) override; Return unsetMaster() override; - Return setParameter(CameraParam id, int32_t value, - setParameter_cb _hidl_cb) override; - Return getParameter(CameraParam id, getParameter_cb _hidl_cb) override; + Return getParameterList(getParameterList_cb _hidl_cb) override; + Return getIntParameterRange(CameraParam id, + getIntParameterRange_cb _hidl_cb) override; + Return setIntParameter(CameraParam id, int32_t value, + setIntParameter_cb _hidl_cb) override; + Return getIntParameter(CameraParam id, + getIntParameter_cb _hidl_cb) override; + + static sp Create(const char *deviceName); + static sp Create(const char *deviceName, + unique_ptr &camInfo, + const Stream *streamCfg = nullptr); + EvsCamera(const EvsCamera&) = delete; + EvsCamera& operator=(const EvsCamera&) = delete; - // Implementation details - EvsCamera(const char *id); virtual ~EvsCamera() override; void forceShutdown(); // This gets called if another caller "steals" ownership of the camera @@ -79,7 +91,10 @@ public: static const char kCameraName_Backup[]; private: + EvsCamera(const char *id, + unique_ptr &camInfo); // These three functions are expected to be called while mAccessLock is held + // bool setAvailableFrames_Locked(unsigned bufferCount); unsigned increaseAvailableFrames_Locked(unsigned numToAdd); unsigned decreaseAvailableFrames_Locked(unsigned numToRemove); @@ -124,6 +139,9 @@ private: // Synchronization necessary to deconflict mCaptureThread from the main service thread std::mutex mAccessLock; + + // Static camera module information + unique_ptr &mCameraInfo; }; } // namespace implementation diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp index b3249071ae..a010729ce6 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.cpp +++ b/automotive/evs/1.1/default/EvsEnumerator.cpp @@ -33,6 +33,7 @@ namespace implementation { // constructs a new instance for each client. std::list EvsEnumerator::sCameraList; wp EvsEnumerator::sActiveDisplay; +unique_ptr EvsEnumerator::sConfigManager; EvsEnumerator::EvsEnumerator() { @@ -40,9 +41,11 @@ EvsEnumerator::EvsEnumerator() { // Add sample camera data to our list of cameras // In a real driver, this would be expected to can the available hardware - sCameraList.emplace_back(EvsCamera::kCameraName_Backup); - sCameraList.emplace_back("LaneView"); - sCameraList.emplace_back("right turn"); + sConfigManager = + ConfigManager::Create("/etc/automotive/evs/evs_sample_configuration.xml"); + for (auto v : sConfigManager->getCameraList()) { + sCameraList.emplace_back(v.c_str()); + } } @@ -57,7 +60,7 @@ Return EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) { std::vector descriptions; descriptions.reserve(numCameras); for (const auto& cam : sCameraList) { - descriptions.push_back( cam.desc ); + descriptions.push_back( cam.desc.v1 ); } // Encapsulate our camera descriptions in the HIDL vec type @@ -78,7 +81,7 @@ Return> EvsEnumerator::openCamera(const hidl_string& cameraId // Find the named camera CameraRecord *pRecord = nullptr; for (auto &&cam : sCameraList) { - if (cam.desc.cameraId == cameraId) { + if (cam.desc.v1.cameraId == cameraId) { // Found a match! pRecord = &cam; break; @@ -99,7 +102,12 @@ Return> EvsEnumerator::openCamera(const hidl_string& cameraId } // Construct a camera instance for the caller - pActiveCamera = new EvsCamera(cameraId.c_str()); + if (sConfigManager == nullptr) { + pActiveCamera = EvsCamera::Create(cameraId.c_str()); + } else { + pActiveCamera = EvsCamera::Create(cameraId.c_str(), + sConfigManager->getCameraInfo(cameraId)); + } pRecord->activeInstance = pActiveCamera; if (pActiveCamera == nullptr) { ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str()); @@ -120,15 +128,15 @@ Return EvsEnumerator::closeCamera(const ::android::sp& pCa // Get the camera id so we can find it in our list std::string cameraId; - pCamera_1_1->getCameraInfo([&cameraId](CameraDesc desc) { - cameraId = desc.cameraId; + pCamera_1_1->getCameraInfo_1_1([&cameraId](CameraDesc desc) { + cameraId = desc.v1.cameraId; } ); // Find the named camera CameraRecord *pRecord = nullptr; for (auto &&cam : sCameraList) { - if (cam.desc.cameraId == cameraId) { + if (cam.desc.v1.cameraId == cameraId) { // Found a match! pRecord = &cam; break; @@ -209,6 +217,89 @@ Return EvsEnumerator::getDisplayState() { } +// Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow. +Return EvsEnumerator::getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) { + ALOGD("getCameraList"); + + const unsigned numCameras = sCameraList.size(); + + // Build up a packed array of CameraDesc for return + // NOTE: Only has to live until the callback returns + std::vector descriptions; + descriptions.reserve(numCameras); + for (const auto& cam : sCameraList) { + descriptions.push_back( cam.desc ); + } + + // Encapsulate our camera descriptions in the HIDL vec type + hidl_vec hidlCameras(descriptions); + + // Send back the results + ALOGD("reporting %zu cameras available", hidlCameras.size()); + _hidl_cb(hidlCameras); + + // HIDL convention says we return Void if we sent our result back via callback + return Void(); +} + +Return> +EvsEnumerator::openCamera_1_1(const hidl_string& cameraId, + const Stream& streamCfg) { + // Find the named camera + CameraRecord *pRecord = nullptr; + for (auto &&cam : sCameraList) { + if (cam.desc.v1.cameraId == cameraId) { + // Found a match! + pRecord = &cam; + break; + } + } + + // Is this a recognized camera id? + if (!pRecord) { + ALOGE("Requested camera %s not found", cameraId.c_str()); + return nullptr; + } + + // Has this camera already been instantiated by another caller? + sp pActiveCamera = pRecord->activeInstance.promote(); + if (pActiveCamera != nullptr) { + ALOGW("Killing previous camera because of new caller"); + closeCamera(pActiveCamera); + } + + // Construct a camera instance for the caller + if (sConfigManager == nullptr) { + pActiveCamera = EvsCamera::Create(cameraId.c_str()); + } else { + pActiveCamera = EvsCamera::Create(cameraId.c_str(), + sConfigManager->getCameraInfo(cameraId), + &streamCfg); + } + + pRecord->activeInstance = pActiveCamera; + if (pActiveCamera == nullptr) { + ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str()); + } + + return pActiveCamera; +} + + +EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& cameraId) { + // Find the named camera + CameraRecord *pRecord = nullptr; + for (auto &&cam : sCameraList) { + if (cam.desc.v1.cameraId == cameraId) { + // Found a match! + pRecord = &cam; + break; + } + } + + return pRecord; +} + } // namespace implementation } // namespace V1_1 } // namespace evs diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h index 11c2170632..475ec76b93 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.h +++ b/automotive/evs/1.1/default/EvsEnumerator.h @@ -17,18 +17,20 @@ #ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H #define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H -#include +#include #include #include +#include "ConfigManager.h" + using ::android::hardware::automotive::evs::V1_0::EvsResult; using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; using ::android::hardware::automotive::evs::V1_0::DisplayState; -using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator; using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera; using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera; using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc; +using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc; namespace android { @@ -53,6 +55,11 @@ public: Return closeDisplay(const ::android::sp& display) override; Return getDisplayState() override; + // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow. + Return getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) override; + Return> openCamera_1_1(const hidl_string& cameraId, + const Stream& streamCfg) override; + // Implementation details EvsEnumerator(); @@ -61,14 +68,20 @@ private: // That is to say, this is effectively a singleton despite the fact that HIDL // constructs a new instance for each client. struct CameraRecord { - CameraDesc_1_0 desc; + CameraDesc_1_1 desc; wp activeInstance; - CameraRecord(const char *cameraId) : desc() { desc.cameraId = cameraId; } + CameraRecord(const char *cameraId) : desc() { desc.v1.cameraId = cameraId; } }; - static std::list sCameraList; - static wp sActiveDisplay; // Weak pointer. Object destructs if client dies. + static CameraRecord* findCameraById(const std::string& cameraId); + + static std::list sCameraList; + + // Weak pointer. Object destructs if client dies. + static wp sActiveDisplay; + + static unique_ptr sConfigManager; }; } // namespace implementation diff --git a/automotive/evs/1.1/default/resources/evs_default_configuration.xml b/automotive/evs/1.1/default/resources/evs_default_configuration.xml new file mode 100644 index 0000000000..692102ed38 --- /dev/null +++ b/automotive/evs/1.1/default/resources/evs_default_configuration.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/automotive/evs/1.1/default/service.cpp b/automotive/evs/1.1/default/service.cpp index 128a14aa30..5135864e88 100644 --- a/automotive/evs/1.1/default/service.cpp +++ b/automotive/evs/1.1/default/service.cpp @@ -33,7 +33,7 @@ using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; // Generated HIDL files -using android::hardware::automotive::evs::V1_0::IEvsEnumerator; +using android::hardware::automotive::evs::V1_1::IEvsEnumerator; using android::hardware::automotive::evs::V1_0::IEvsDisplay; // The namespace in which all our implementation code lives diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal index 2c6b2ed589..dcb2abb0e9 100644 --- a/automotive/evs/1.1/types.hal +++ b/automotive/evs/1.1/types.hal @@ -21,6 +21,22 @@ import @1.0::DisplayDesc; import @1.0::DisplayState; import @1.0::EvsResult; import android.hardware.graphics.common@1.2::HardwareBuffer; +import android.hardware.camera.device@3.2::CameraMetadata; + +/** + * Structure describing the basic properties of an EVS camera, extended from its + * v1.0 declaration. + * + * The HAL is responsible for filling out this structure for each + * EVS camera in the system. + */ +struct CameraDesc { + @1.0::CameraDesc v1; + /** + * Store camera metadata such as lens characteristics. + */ + CameraMetadata metadata; +}; /** * Structure representing an image buffer through our APIs @@ -50,7 +66,7 @@ struct BufferDesc { /** * Types of informative streaming events */ -enum InfoEventType : uint32_t { +enum EvsEventType : uint32_t { /** * Video stream is started */ @@ -81,31 +97,17 @@ enum InfoEventType : uint32_t { /** * Structure that describes informative events occurred during EVS is streaming */ -struct InfoEventDesc { +struct EvsEvent { /** * Type of an informative event */ - InfoEventType aType; + EvsEventType aType; /** * Possible additional information */ uint32_t[4] payload; }; -/** - * EVS event definition - */ -safe_union EvsEvent { - /** - * A buffer descriptor of an image frame - */ - BufferDesc buffer; - /** - * General streaming events - */ - InfoEventDesc info; -}; - /** * EVS Camera Parameter */ @@ -126,14 +128,6 @@ enum CameraParam : uint32_t { * Gain control */ GAIN, - /** - * Mirror the image horizontally - */ - HFLIP, - /** - * Mirror the image vertically - */ - VFLIP, /** * Automatic Whitebalance */ @@ -155,11 +149,6 @@ enum CameraParam : uint32_t { * Manual exposure time of the camera */ ABSOLUTE_EXPOSURE, - /** - * When AEC is running in either auto or aperture priority, this parameter - * sets whether a frame rate varies. - */ - AUTO_EXPOSURE_PRIORITY, /** * Set the focal point of the camera to the specified position. This * parameter may not be effective when auto focus is enabled. diff --git a/automotive/evs/1.1/vts/functional/Android.bp b/automotive/evs/1.1/vts/functional/Android.bp index 55c50a42b8..4753933f7f 100644 --- a/automotive/evs/1.1/vts/functional/Android.bp +++ b/automotive/evs/1.1/vts/functional/Android.bp @@ -23,6 +23,7 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], shared_libs: [ "libui", + "libcamera_metadata", ], static_libs: [ "android.hardware.automotive.evs@1.0", @@ -31,6 +32,7 @@ cc_test { "android.hardware.graphics.common@1.0", "android.hardware.graphics.common@1.1", "android.hardware.graphics.common@1.2", + "android.hardware.camera.device@3.2", ], test_suites: ["general-tests"], cflags: [ diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp index 16276891f0..6d53652f86 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp +++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp @@ -138,93 +138,93 @@ Return FrameHandler::deliverFrame(const BufferDesc_1_0& bufferArg) { } -Return FrameHandler::notifyEvent(const EvsEvent& event) { - // Local flag we use to keep track of when the stream is stopping - auto type = event.getDiscriminator(); - if (type == EvsEvent::hidl_discriminator::info) { - mLock.lock(); - mLatestEventDesc = event.info(); - if (mLatestEventDesc.aType == InfoEventType::STREAM_STOPPED) { - // Signal that the last frame has been received and the stream is stopped - mRunning = false; - } else if (mLatestEventDesc.aType == InfoEventType::PARAMETER_CHANGED) { - ALOGD("Camera parameter 0x%X is changed to 0x%X", - mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]); +Return FrameHandler::deliverFrame_1_1(const BufferDesc_1_1& bufDesc) { + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&bufDesc.buffer.description); + ALOGD("Received a frame from the camera (%p)", + bufDesc.buffer.nativeHandle.getNativeHandle()); + + // Store a dimension of a received frame. + mFrameWidth = pDesc->width; + mFrameHeight = pDesc->height; + + // If we were given an opened display at construction time, then send the received + // image back down the camera. + if (mDisplay.get()) { + // Get the output buffer we'll use to display the imagery + BufferDesc_1_0 tgtBuffer = {}; + mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) { + tgtBuffer = buff; + } + ); + + if (tgtBuffer.memHandle == nullptr) { + printf("Didn't get target buffer - frame lost\n"); + ALOGE("Didn't get requested output buffer -- skipping this frame."); } else { - ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType)); - } - mLock.unlock(); - mEventSignal.notify_all(); - } else { - auto bufDesc = event.buffer(); - const AHardwareBuffer_Desc* pDesc = - reinterpret_cast(&bufDesc.buffer.description); - ALOGD("Received a frame from the camera (%p)", - bufDesc.buffer.nativeHandle.getNativeHandle()); + // Copy the contents of the of buffer.memHandle into tgtBuffer + copyBufferContents(tgtBuffer, bufDesc); - // Store a dimension of a received frame. - mFrameWidth = pDesc->width; - mFrameHeight = pDesc->height; - - // If we were given an opened display at construction time, then send the received - // image back down the camera. - if (mDisplay.get()) { - // Get the output buffer we'll use to display the imagery - BufferDesc_1_0 tgtBuffer = {}; - mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) { - tgtBuffer = buff; - } - ); - - if (tgtBuffer.memHandle == nullptr) { - printf("Didn't get target buffer - frame lost\n"); - ALOGE("Didn't get requested output buffer -- skipping this frame."); + // Send the target buffer back for display + Return result = mDisplay->returnTargetBufferForDisplay(tgtBuffer); + if (!result.isOk()) { + printf("HIDL error on display buffer (%s)- frame lost\n", + result.description().c_str()); + ALOGE("Error making the remote function call. HIDL said %s", + result.description().c_str()); + } else if (result != EvsResult::OK) { + printf("Display reported error - frame lost\n"); + ALOGE("We encountered error %d when returning a buffer to the display!", + (EvsResult) result); } else { - // Copy the contents of the of buffer.memHandle into tgtBuffer - copyBufferContents(tgtBuffer, bufDesc); - - // Send the target buffer back for display - Return result = mDisplay->returnTargetBufferForDisplay(tgtBuffer); - if (!result.isOk()) { - printf("HIDL error on display buffer (%s)- frame lost\n", - result.description().c_str()); - ALOGE("Error making the remote function call. HIDL said %s", - result.description().c_str()); - } else if (result != EvsResult::OK) { - printf("Display reported error - frame lost\n"); - ALOGE("We encountered error %d when returning a buffer to the display!", - (EvsResult) result); - } else { - // Everything looks good! - // Keep track so tests or watch dogs can monitor progress - mLock.lock(); - mFramesDisplayed++; - mLock.unlock(); - } + // Everything looks good! + // Keep track so tests or watch dogs can monitor progress + mLock.lock(); + mFramesDisplayed++; + mLock.unlock(); } } - - - switch (mReturnMode) { - case eAutoReturn: - // Send the camera buffer back now that the client has seen it - ALOGD("Calling doneWithFrame"); - // TODO: Why is it that we get a HIDL crash if we pass back the cloned buffer? - mCamera->doneWithFrame_1_1(bufDesc); - break; - case eNoAutoReturn: - // Hang onto the buffer handle for now -- the client will return it explicitly later - mHeldBuffers.push(bufDesc); - } - - mLock.lock(); - ++mFramesReceived; - mLock.unlock(); - mFrameSignal.notify_all(); - - ALOGD("Frame handling complete"); } + + switch (mReturnMode) { + case eAutoReturn: + // Send the camera buffer back now that the client has seen it + ALOGD("Calling doneWithFrame"); + mCamera->doneWithFrame_1_1(bufDesc); + break; + case eNoAutoReturn: + // Hang onto the buffer handle for now -- the client will return it explicitly later + mHeldBuffers.push(bufDesc); + } + + mLock.lock(); + ++mFramesReceived; + mLock.unlock(); + mFrameSignal.notify_all(); + + ALOGD("Frame handling complete"); + + return Void(); +} + + +Return FrameHandler::notify(const EvsEvent& event) { + // Local flag we use to keep track of when the stream is stopping + mLock.lock(); + mLatestEventDesc = event; + if (mLatestEventDesc.aType == EvsEventType::STREAM_STOPPED) { + // Signal that the last frame has been received and the stream is stopped + mRunning = false; + } else if (mLatestEventDesc.aType == EvsEventType::PARAMETER_CHANGED) { + ALOGD("Camera parameter 0x%X is changed to 0x%X", + mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]); + } else { + ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType)); + } + mLock.unlock(); + mEventSignal.notify_all(); + return Void(); } @@ -342,18 +342,18 @@ void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) { } } -bool FrameHandler::waitForEvent(const InfoEventType aTargetEvent, - InfoEventDesc &eventDesc) { +bool FrameHandler::waitForEvent(const EvsEventType aTargetEvent, + EvsEvent &event) { // Wait until we get an expected parameter change event. std::unique_lock lock(mLock); auto now = std::chrono::system_clock::now(); bool result = mEventSignal.wait_until(lock, now + 5s, - [this, aTargetEvent, &eventDesc](){ + [this, aTargetEvent, &event](){ bool flag = mLatestEventDesc.aType == aTargetEvent; if (flag) { - eventDesc.aType = mLatestEventDesc.aType; - eventDesc.payload[0] = mLatestEventDesc.payload[0]; - eventDesc.payload[1] = mLatestEventDesc.payload[1]; + event.aType = mLatestEventDesc.aType; + event.payload[0] = mLatestEventDesc.payload[0]; + event.payload[1] = mLatestEventDesc.payload[1]; } return flag; @@ -363,21 +363,22 @@ bool FrameHandler::waitForEvent(const InfoEventType aTargetEvent, return !result; } -const char *FrameHandler::eventToString(const InfoEventType aType) { +const char *FrameHandler::eventToString(const EvsEventType aType) { switch (aType) { - case InfoEventType::STREAM_STARTED: + case EvsEventType::STREAM_STARTED: return "STREAM_STARTED"; - case InfoEventType::STREAM_STOPPED: + case EvsEventType::STREAM_STOPPED: return "STREAM_STOPPED"; - case InfoEventType::FRAME_DROPPED: + case EvsEventType::FRAME_DROPPED: return "FRAME_DROPPED"; - case InfoEventType::TIMEOUT: + case EvsEventType::TIMEOUT: return "TIMEOUT"; - case InfoEventType::PARAMETER_CHANGED: + case EvsEventType::PARAMETER_CHANGED: return "PARAMETER_CHANGED"; - case InfoEventType::MASTER_RELEASED: + case EvsEventType::MASTER_RELEASED: return "MASTER_RELEASED"; default: return "Unknown"; } } + diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h index 7f87cb4409..e5f1b8f112 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.h +++ b/automotive/evs/1.1/vts/functional/FrameHandler.h @@ -33,7 +33,6 @@ using ::android::hardware::hidl_handle; using ::android::sp; using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; using ::android::hardware::automotive::evs::V1_0::EvsResult; -using ::android::hardware::automotive::evs::V1_0::CameraDesc; using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc; using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc; @@ -56,6 +55,13 @@ public: FrameHandler(android::sp pCamera, CameraDesc cameraInfo, android::sp pDisplay = nullptr, BufferControlFlag mode = eAutoReturn); + virtual ~FrameHandler() { + if (mCamera != nullptr) { + /* shutdown a camera explicitly */ + shutdown(); + } + } + void shutdown(); bool startStream(); @@ -67,19 +73,22 @@ public: bool isRunning(); void waitForFrameCount(unsigned frameCount); - bool waitForEvent(const InfoEventType aTargetEvent, - InfoEventDesc &eventDesc); + bool waitForEvent(const EvsEventType aTargetEvent, + EvsEvent &eventDesc); void getFramesCounters(unsigned* received, unsigned* displayed); void getFrameDimension(unsigned* width, unsigned* height); private: - // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream + // Implementation for ::android::hardware::automotive::evs::V1_0::IEvsCameraStream Return deliverFrame(const BufferDesc_1_0& buffer) override; - Return notifyEvent(const EvsEvent& event) override; + + // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream + Return deliverFrame_1_1(const BufferDesc_1_1& buffer) override; + Return notify(const EvsEvent& event) override; // Local implementation details bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer); - const char *eventToString(const InfoEventType aType); + const char *eventToString(const EvsEventType aType); // Values initialized as startup android::sp mCamera; @@ -100,7 +109,7 @@ private: unsigned mFramesDisplayed = 0; // Simple counter -- rolls over eventually! unsigned mFrameWidth = 0; unsigned mFrameHeight = 0; - InfoEventDesc mLatestEventDesc; + EvsEvent mLatestEventDesc; }; diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index a6e4881d4d..1d3fd87356 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -38,8 +38,9 @@ static const float kNanoToSeconds = 0.000000001f; #include "FrameHandler.h" -#include -#include +#include +#include +#include #include #include @@ -50,8 +51,10 @@ static const float kNanoToSeconds = 0.000000001f; #include #include #include -#include +#include #include +#include +#include #include #include @@ -64,13 +67,28 @@ using ::android::hardware::hidl_vec; using ::android::hardware::hidl_handle; using ::android::hardware::hidl_string; using ::android::sp; -using ::android::hardware::automotive::evs::V1_0::CameraDesc; +using ::android::hardware::camera::device::V3_2::Stream; using ::android::hardware::automotive::evs::V1_0::DisplayDesc; using ::android::hardware::automotive::evs::V1_0::DisplayState; -using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator; +using ::android::hardware::graphics::common::V1_0::PixelFormat; using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera; using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera; +/* + * Plese note that this is different from what is defined in + * libhardware/modules/camera/3_4/metadata/types.h; this has one additional + * field to store a framerate. + */ +const size_t kStreamCfgSz = 5; +typedef struct { + int32_t width; + int32_t height; + int32_t format; + int32_t direction; + int32_t framerate; +} RawStreamConfig; + + // Test environment for Evs HIDL HAL. class EvsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: @@ -107,15 +125,16 @@ protected: assert(pEnumerator != nullptr); // Get the camera list - pEnumerator->getCameraList([this](hidl_vec cameraList) { - ALOGI("Camera list callback received %zu cameras", - cameraList.size()); - cameraInfo.reserve(cameraList.size()); - for (auto&& cam: cameraList) { - ALOGI("Found camera %s", cam.cameraId.c_str()); - cameraInfo.push_back(cam); - } - } + pEnumerator->getCameraList_1_1( + [this](hidl_vec cameraList) { + ALOGI("Camera list callback received %zu cameras", + cameraList.size()); + cameraInfo.reserve(cameraList.size()); + for (auto&& cam: cameraList) { + ALOGI("Found camera %s", cam.v1.cameraId.c_str()); + cameraInfo.push_back(cam); + } + } ); // We insist on at least one camera for EVS to pass any camera tests @@ -143,19 +162,23 @@ TEST_F(EvsHidlTest, CameraOpenClean) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Open and close each camera twice for (auto&& cam: cameraInfo) { for (int pass = 0; pass < 2; pass++) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); // Verify that this camera self-identifies correctly - pCam->getCameraInfo([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.cameraId.c_str()); - EXPECT_EQ(cam.cameraId, desc.cameraId); - } + pCam->getCameraInfo_1_1([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.v1.cameraId.c_str()); + EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); + } ); // Explicitly close the camera so resources are released right away @@ -177,22 +200,26 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Open and close each camera twice for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); // Verify that this camera self-identifies correctly - pCam->getCameraInfo([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.cameraId.c_str()); - EXPECT_EQ(cam.cameraId, desc.cameraId); - } + pCam->getCameraInfo_1_1([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.v1.cameraId.c_str()); + EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); + } ); sp pCam2 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, pCam2); ASSERT_NE(pCam2, nullptr); @@ -210,10 +237,10 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { pEnumerator->closeCamera(pCam); // Verify that the second camera instance self-identifies correctly - pCam2->getCameraInfo([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.cameraId.c_str()); - EXPECT_EQ(cam.cameraId, desc.cameraId); - } + pCam2->getCameraInfo_1_1([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.v1.cameraId.c_str()); + EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); + } ); // Close the second camera instance @@ -235,10 +262,14 @@ TEST_F(EvsHidlTest, CameraStreamPerformance) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); @@ -303,11 +334,15 @@ TEST_F(EvsHidlTest, CameraStreamBuffering) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); @@ -371,6 +406,10 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Request exclusive access to the EVS display sp pDisplay = pEnumerator->openDisplay(); ASSERT_NE(pDisplay, nullptr); @@ -378,7 +417,7 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { // Test each reported camera for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); @@ -439,16 +478,20 @@ TEST_F(EvsHidlTest, MultiCameraStream) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera for (auto&& cam: cameraInfo) { // Create two camera clients. sp pCam0 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam0, nullptr); sp pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam1, nullptr); @@ -486,7 +529,6 @@ TEST_F(EvsHidlTest, MultiCameraStream) { nsecs_t runTime = end - firstFrame; float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds); float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds); - printf("Measured camera rate %3.2f fps and %3.2f fps\n", framesPerSecond0, framesPerSecond1); ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1); EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond); EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond); @@ -526,14 +568,33 @@ TEST_F(EvsHidlTest, CameraParameter) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera + Return result = EvsResult::OK; for (auto&& cam: cameraInfo) { // Create a camera client sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); + // Get the parameter list + std::vector cmds; + pCam->getParameterList([&cmds](hidl_vec cmdList) { + cmds.reserve(cmdList.size()); + for (auto &&cmd : cmdList) { + cmds.push_back(cmd); + } + } + ); + + if (cmds.size() < 1) { + continue; + } + // Set up per-client frame receiver objects which will fire up its own thread sp frameHandler = new FrameHandler(pCam, cam, nullptr, @@ -547,83 +608,70 @@ TEST_F(EvsHidlTest, CameraParameter) { // Ensure the stream starts frameHandler->waitForFrameCount(1); - // Try to program few parameters - EvsResult result = EvsResult::OK; - int32_t val0 = 100; - int32_t val1 = 0; - result = pCam->setMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); - pCam->setParameter(CameraParam::BRIGHTNESS, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); + for (auto &cmd : cmds) { + // Get a valid parameter value range + int32_t minVal, maxVal, step; + pCam->getIntParameterRange( + cmd, + [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { + minVal = val0; + maxVal = val1; + step = val2; + } + ); - if (result == EvsResult::OK) { - pCam->getParameter(CameraParam::BRIGHTNESS, + EvsResult result = EvsResult::OK; + if (cmd == CameraParam::ABSOLUTE_FOCUS) { + // Try to turn off auto-focus + int32_t val1 = 0; + pCam->getIntParameter(CameraParam::AUTO_FOCUS, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + if (val1 != 0) { + pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val1, 0); + } + } + + // Try to program a parameter with a random value [minVal, maxVal] + int32_t val0 = minVal + (std::rand() % (maxVal - minVal)); + int32_t val1 = 0; + + // Rounding down + val0 = val0 - (val0 % step); + pCam->setIntParameter(cmd, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + + ASSERT_EQ(EvsResult::OK, result); + + pCam->getIntParameter(cmd, [&result, &val1](auto status, auto value) { result = status; if (status == EvsResult::OK) { val1 = value; } }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - ASSERT_EQ(val0, val1) << "Values are not matched."; - } - - val0 = 80; - val1 = 0; - pCam->setParameter(CameraParam::CONTRAST, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - - if (result == EvsResult::OK) { - pCam->getParameter(CameraParam::CONTRAST, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - ASSERT_EQ(val0, val1) << "Values are not matched."; - } - - val0 = 300; - val1 = 0; - pCam->setParameter(CameraParam::ABSOLUTE_ZOOM, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - - if (result == EvsResult::OK) { - pCam->getParameter(CameraParam::ABSOLUTE_ZOOM, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); + ASSERT_EQ(EvsResult::OK, result); ASSERT_EQ(val0, val1) << "Values are not matched."; } result = pCam->unsetMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); // Shutdown frameHandler->shutdown(); @@ -650,15 +698,19 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera for (auto&& cam: cameraInfo) { // Create two camera clients. sp pCamMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCamMaster, nullptr); sp pCamNonMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCamNonMaster, nullptr); @@ -698,15 +750,15 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { // Non-master client expects to receive a master role relesed // notification. - InfoEventDesc aNotification = {}; + EvsEvent aNotification = {}; // Release a master role. pCamMaster->unsetMaster(); // Verify a change notification. - frameHandlerNonMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); - ASSERT_EQ(InfoEventType::MASTER_RELEASED, - static_cast(aNotification.aType)); + frameHandlerNonMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(EvsEventType::MASTER_RELEASED, + static_cast(aNotification.aType)); // Non-master becomes a master. result = pCamNonMaster->setMaster(); @@ -720,9 +772,9 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { frameHandlerNonMaster->shutdown(); // Verify a change notification. - frameHandlerMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); - ASSERT_EQ(InfoEventType::MASTER_RELEASED, - static_cast(aNotification.aType)); + frameHandlerMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(EvsEventType::MASTER_RELEASED, + static_cast(aNotification.aType)); // Closing another stream. frameHandlerMaster->shutdown(); @@ -752,18 +804,46 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera for (auto&& cam: cameraInfo) { // Create two camera clients. sp pCamMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCamMaster, nullptr); sp pCamNonMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCamNonMaster, nullptr); + // Get the parameter list + std::vector camMasterCmds, camNonMasterCmds; + pCamMaster->getParameterList([&camMasterCmds](hidl_vec cmdList) { + camMasterCmds.reserve(cmdList.size()); + for (auto &&cmd : cmdList) { + camMasterCmds.push_back(cmd); + } + } + ); + + pCamNonMaster->getParameterList([&camNonMasterCmds](hidl_vec cmdList) { + camNonMasterCmds.reserve(cmdList.size()); + for (auto &&cmd : cmdList) { + camNonMasterCmds.push_back(cmd); + } + } + ); + + if (camMasterCmds.size() < 1 || + camNonMasterCmds.size() < 1) { + // Skip a camera device if it does not support any parameter. + continue; + } + // Set up per-client frame receiver objects which will fire up its own thread sp frameHandlerMaster = new FrameHandler(pCamMaster, cam, @@ -778,11 +858,11 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Set one client as the master EvsResult result = pCamMaster->setMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); // Try to set another client as the master. result = pCamNonMaster->setMaster(); - ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST); + ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result); // Start the camera's video stream via a master client. bool startResult = frameHandlerMaster->startStream(); @@ -798,131 +878,168 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Ensure the stream starts frameHandlerNonMaster->waitForFrameCount(1); - // Try to program CameraParam::BRIGHTNESS - int32_t val0 = 100; + int32_t val0 = 0; int32_t val1 = 0; + for (auto &cmd : camMasterCmds) { + // Get a valid parameter value range + int32_t minVal, maxVal, step; + pCamMaster->getIntParameterRange( + cmd, + [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { + minVal = val0; + maxVal = val1; + step = val2; + } + ); - pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program - result == EvsResult::INVALID_ARG); // Camera parameter is not supported + EvsResult result = EvsResult::OK; + if (cmd == CameraParam::ABSOLUTE_FOCUS) { + // Try to turn off auto-focus + int32_t val1 = 1; + pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val1, 0); + } - // Non-master client expects to receive a parameter change notification - // whenever a master client adjusts it. - InfoEventDesc aNotification = {}; + // Try to program a parameter + val0 = minVal + (std::rand() % (maxVal - minVal)); - pCamMaster->getParameter(CameraParam::BRIGHTNESS, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program - result == EvsResult::INVALID_ARG); // Camera parameter is not supported - if (result == EvsResult::OK) { - ASSERT_EQ(val0, val1) << "Values are not matched."; + // Rounding down + val0 = val0 - (val0 % step); + pCamMaster->setIntParameter(cmd, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); - // Verify a change notification - frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); - ASSERT_EQ(InfoEventType::PARAMETER_CHANGED, - static_cast(aNotification.aType)); - ASSERT_EQ(CameraParam::BRIGHTNESS, - static_cast(aNotification.payload[0])); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); - } + // Wait a moment + sleep(1); - // Try to program CameraParam::CONTRAST - val0 = 80; - val1 = 0; - pCamMaster->setParameter(CameraParam::CONTRAST, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program - result == EvsResult::INVALID_ARG); // Camera parameter is not supported + // Non-master client expects to receive a parameter change notification + // whenever a master client adjusts it. + EvsEvent aNotification = {}; - if (result == EvsResult::OK) { - pCamMaster->getParameter(CameraParam::CONTRAST, + pCamMaster->getIntParameter(cmd, [&result, &val1](auto status, auto value) { result = status; if (status == EvsResult::OK) { val1 = value; } }); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); ASSERT_EQ(val0, val1) << "Values are not matched."; - // Verify a change notification - frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); - ASSERT_EQ(InfoEventType::PARAMETER_CHANGED, - static_cast(aNotification.aType)); - ASSERT_EQ(CameraParam::CONTRAST, + frameHandlerNonMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); + ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, + static_cast(aNotification.aType)); + ASSERT_EQ(cmd, static_cast(aNotification.payload[0])); ASSERT_EQ(val1, static_cast(aNotification.payload[1])); } // Try to adjust a parameter via non-master client - pCamNonMaster->setParameter(CameraParam::CONTRAST, val0, + pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_TRUE(result == EvsResult::INVALID_ARG); + ASSERT_EQ(EvsResult::INVALID_ARG, result); // Non-master client attemps to be a master result = pCamNonMaster->setMaster(); - ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST); + ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result); // Master client retires from a master role result = pCamMaster->unsetMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); // Try to adjust a parameter after being retired - pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0, + pCamMaster->setIntParameter(camMasterCmds[0], val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_TRUE(result == EvsResult::INVALID_ARG); + ASSERT_EQ(EvsResult::INVALID_ARG, result); // Non-master client becomes a master result = pCamNonMaster->setMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); // Try to adjust a parameter via new master client - pCamNonMaster->setParameter(CameraParam::BRIGHTNESS, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program - result == EvsResult::INVALID_ARG); // Camera parameter is not supported + for (auto &cmd : camNonMasterCmds) { + // Get a valid parameter value range + int32_t minVal, maxVal, step; + pCamNonMaster->getIntParameterRange( + cmd, + [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { + minVal = val0; + maxVal = val1; + step = val2; + } + ); - // Wait a moment - sleep(1); + EvsResult result = EvsResult::OK; + if (cmd == CameraParam::ABSOLUTE_FOCUS) { + // Try to turn off auto-focus + int32_t val1 = 1; + pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val1, 0); + } - // Verify a change notification - if (result == EvsResult::OK) { - frameHandlerMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); - ASSERT_EQ(static_cast(aNotification.aType), - InfoEventType::PARAMETER_CHANGED); - ASSERT_EQ(static_cast(aNotification.payload[0]), - CameraParam::BRIGHTNESS); + // Try to program a parameter + val0 = minVal + (std::rand() % (maxVal - minVal)); + + // Rounding down + val0 = val0 - (val0 % step); + pCamNonMaster->setIntParameter(cmd, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + + // Wait a moment + sleep(1); + + // Non-master client expects to receive a parameter change notification + // whenever a master client adjusts it. + EvsEvent aNotification = {}; + + pCamNonMaster->getIntParameter(cmd, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val0, val1) << "Values are not matched."; + + // Verify a change notification + frameHandlerMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); + ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, + static_cast(aNotification.aType)); + ASSERT_EQ(cmd, + static_cast(aNotification.payload[0])); ASSERT_EQ(val1, static_cast(aNotification.payload[1])); } // New master retires from a master role result = pCamNonMaster->unsetMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); // Shutdown frameHandlerMaster->shutdown(); @@ -943,9 +1060,18 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { TEST_F(EvsHidlTest, HighPriorityCameraClient) { ALOGI("Starting HighPriorityCameraClient test"); + if (mIsHwModule) { + // This test is not for HW module implementation. + return; + } + // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Request exclusive access to the EVS display sp pDisplay = pEnumerator->openDisplay(); ASSERT_NE(pDisplay, nullptr); @@ -954,15 +1080,38 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { for (auto&& cam: cameraInfo) { // Create two clients sp pCam0 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam0, nullptr); sp pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam1, nullptr); + // Get the parameter list; this test will use the first command in both + // lists. + std::vector cam0Cmds, cam1Cmds; + pCam0->getParameterList([&cam0Cmds](hidl_vec cmdList) { + cam0Cmds.reserve(cmdList.size()); + for (auto &&cmd : cmdList) { + cam0Cmds.push_back(cmd); + } + } + ); + + pCam1->getParameterList([&cam1Cmds](hidl_vec cmdList) { + cam1Cmds.reserve(cmdList.size()); + for (auto &&cmd : cmdList) { + cam1Cmds.push_back(cmd); + } + } + ); + if (cam0Cmds.size() < 1 || cam1Cmds.size() < 1) { + // Cannot execute this test. + return; + } + // Set up a frame receiver object which will fire up its own thread. sp frameHandler0 = new FrameHandler(pCam0, cam, pDisplay, @@ -982,67 +1131,121 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { frameHandler0->waitForFrameCount(1); frameHandler1->waitForFrameCount(1); - // Client 1 becomes a master and programs a brightness. + // Client 1 becomes a master and programs a parameter. EvsResult result = EvsResult::OK; - int32_t val0 = 100; + // Get a valid parameter value range + int32_t minVal, maxVal, step; + pCam1->getIntParameterRange( + cam1Cmds[0], + [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { + minVal = val0; + maxVal = val1; + step = val2; + } + ); + + if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) { + // Try to turn off auto-focus + int32_t val1 = 0; + pCam1->getIntParameter(CameraParam::AUTO_FOCUS, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + if (val1 != 0) { + pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val1, 0); + } + } + + // Try to program a parameter with a random value [minVal, maxVal] + int32_t val0 = minVal + (std::rand() % (maxVal - minVal)); int32_t val1 = 0; - result = pCam1->setMaster(); - ASSERT_TRUE(result == EvsResult::OK); + // Rounding down + val0 = val0 - (val0 % step); - pCam1->setParameter(CameraParam::BRIGHTNESS, val0, + result = pCam1->setMaster(); + ASSERT_EQ(EvsResult::OK, result); + + pCam1->setIntParameter(cam1Cmds[0], val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - + ASSERT_EQ(EvsResult::OK, result); // Verify a change notification - InfoEventDesc aNotification = {}; - if (result == EvsResult::OK) { - bool timeout = - frameHandler0->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); - ASSERT_FALSE(timeout) << "Expected event does not arrive"; - ASSERT_EQ(static_cast(aNotification.aType), - InfoEventType::PARAMETER_CHANGED); - ASSERT_EQ(static_cast(aNotification.payload[0]), - CameraParam::BRIGHTNESS); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); - } + EvsEvent aNotification = {}; + bool timeout = + frameHandler0->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); + ASSERT_FALSE(timeout) << "Expected event does not arrive"; + ASSERT_EQ(static_cast(aNotification.aType), + EvsEventType::PARAMETER_CHANGED); + ASSERT_EQ(static_cast(aNotification.payload[0]), + cam1Cmds[0]); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); // Client 0 steals a master role ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay)); - frameHandler1->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); - ASSERT_EQ(static_cast(aNotification.aType), - InfoEventType::MASTER_RELEASED); + frameHandler1->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(static_cast(aNotification.aType), + EvsEventType::MASTER_RELEASED); - // Client 0 programs a brightness - val0 = 50; + // Client 0 programs a parameter + val0 = minVal + (std::rand() % (maxVal - minVal)); val1 = 0; - pCam0->setParameter(CameraParam::BRIGHTNESS, val0, + + // Rounding down + val0 = val0 - (val0 % step); + + if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) { + // Try to turn off auto-focus + int32_t val1 = 0; + pCam0->getIntParameter(CameraParam::AUTO_FOCUS, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + if (val1 != 0) { + pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val1, 0); + } + } + + pCam0->setIntParameter(cam0Cmds[0], val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); + ASSERT_EQ(EvsResult::OK, result); // Verify a change notification - if (result == EvsResult::OK) { - bool timeout = - frameHandler1->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); - ASSERT_FALSE(timeout) << "Expected event does not arrive"; - ASSERT_EQ(static_cast(aNotification.aType), - InfoEventType::PARAMETER_CHANGED); - ASSERT_EQ(static_cast(aNotification.payload[0]), - CameraParam::BRIGHTNESS); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); - } + timeout = + frameHandler1->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); + ASSERT_FALSE(timeout) << "Expected event does not arrive"; + ASSERT_EQ(static_cast(aNotification.aType), + EvsEventType::PARAMETER_CHANGED); + ASSERT_EQ(static_cast(aNotification.payload[0]), + cam0Cmds[0]); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); // Turn off the display (yes, before the stream stops -- it should be handled) pDisplay->setDisplayState(DisplayState::NOT_VISIBLE); @@ -1061,6 +1264,248 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { } +/* + * CameraUseStreamConfigToDisplay: + * End to end test of data flowing from the camera to the display. Similar to + * CameraToDisplayRoundTrip test case but this case retrieves available stream + * configurations from EVS and uses one of them to start a video stream. + */ +TEST_F(EvsHidlTest, CameraUseStreamConfigToDisplay) { + ALOGI("Starting CameraUseStreamConfigToDisplay test"); + + // Get the camera list + loadCameraList(); + + // Request exclusive access to the EVS display + sp pDisplay = pEnumerator->openDisplay(); + ASSERT_NE(pDisplay, nullptr); + + // Test each reported camera + for (auto&& cam: cameraInfo) { + // choose a configuration that has a frame rate faster than minReqFps. + Stream targetCfg = {}; + const int32_t minReqFps = 15; + int32_t maxArea = 0; + camera_metadata_entry_t streamCfgs; + bool foundCfg = false; + if (!find_camera_metadata_entry( + reinterpret_cast(cam.metadata.data()), + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, + &streamCfgs)) { + // Stream configurations are found in metadata + RawStreamConfig *ptr = reinterpret_cast(streamCfgs.data.i32); + for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) { + if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && + ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) { + + if (ptr->width * ptr->height > maxArea && + ptr->framerate >= minReqFps) { + targetCfg.width = ptr->width; + targetCfg.height = ptr->height; + + maxArea = ptr->width * ptr->height; + foundCfg = true; + } + } + ++ptr; + } + } + targetCfg.format = + static_cast(HAL_PIXEL_FORMAT_RGBA_8888); + + if (!foundCfg) { + // Current EVS camera does not provide stream configurations in the + // metadata. + continue; + } + + sp pCam = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) + .withDefault(nullptr); + ASSERT_NE(pCam, nullptr); + + // Set up a frame receiver object which will fire up its own thread. + sp frameHandler = new FrameHandler(pCam, cam, + pDisplay, + FrameHandler::eAutoReturn); + + + // Activate the display + pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME); + + // Start the camera's video stream + bool startResult = frameHandler->startStream(); + ASSERT_TRUE(startResult); + + // Wait a while to let the data flow + static const int kSecondsToWait = 5; + const int streamTimeMs = kSecondsToWait * kSecondsToMilliseconds - + kMaxStreamStartMilliseconds; + const unsigned minimumFramesExpected = streamTimeMs * kMinimumFramesPerSecond / + kSecondsToMilliseconds; + sleep(kSecondsToWait); + unsigned framesReceived = 0; + unsigned framesDisplayed = 0; + frameHandler->getFramesCounters(&framesReceived, &framesDisplayed); + EXPECT_EQ(framesReceived, framesDisplayed); + EXPECT_GE(framesDisplayed, minimumFramesExpected); + + // Turn off the display (yes, before the stream stops -- it should be handled) + pDisplay->setDisplayState(DisplayState::NOT_VISIBLE); + + // Shut down the streamer + frameHandler->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCam); + } + + // Explicitly release the display + pEnumerator->closeDisplay(pDisplay); +} + + +/* + * MultiCameraStreamUseConfig: + * Verify that each client can start and stop video streams on the same + * underlying camera with same configuration. + */ +TEST_F(EvsHidlTest, MultiCameraStreamUseConfig) { + ALOGI("Starting MultiCameraStream test"); + + if (mIsHwModule) { + // This test is not for HW module implementation. + return; + } + + // Get the camera list + loadCameraList(); + + // Test each reported camera + for (auto&& cam: cameraInfo) { + // choose a configuration that has a frame rate faster than minReqFps. + Stream targetCfg = {}; + const int32_t minReqFps = 15; + int32_t maxArea = 0; + camera_metadata_entry_t streamCfgs; + bool foundCfg = false; + if (!find_camera_metadata_entry( + reinterpret_cast(cam.metadata.data()), + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, + &streamCfgs)) { + // Stream configurations are found in metadata + RawStreamConfig *ptr = reinterpret_cast(streamCfgs.data.i32); + for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) { + if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && + ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) { + + if (ptr->width * ptr->height > maxArea && + ptr->framerate >= minReqFps) { + targetCfg.width = ptr->width; + targetCfg.height = ptr->height; + + maxArea = ptr->width * ptr->height; + foundCfg = true; + } + } + ++ptr; + } + } + targetCfg.format = + static_cast(HAL_PIXEL_FORMAT_RGBA_8888); + + if (!foundCfg) { + ALOGI("Device %s does not provide a list of supported stream configurations, skipped", + cam.v1.cameraId.c_str()); + + continue; + } + + // Create the first camera client with a selected stream configuration. + sp pCam0 = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) + .withDefault(nullptr); + ASSERT_NE(pCam0, nullptr); + + // Try to create the second camera client with different stream + // configuration. + int32_t id = targetCfg.id; + targetCfg.id += 1; // EVS manager sees only the stream id. + sp pCam1 = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) + .withDefault(nullptr); + ASSERT_EQ(pCam1, nullptr); + + // Try again with same stream configuration. + targetCfg.id = id; + pCam1 = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) + .withDefault(nullptr); + ASSERT_NE(pCam1, nullptr); + + // Set up per-client frame receiver objects which will fire up its own thread + sp frameHandler0 = new FrameHandler(pCam0, cam, + nullptr, + FrameHandler::eAutoReturn); + ASSERT_NE(frameHandler0, nullptr); + + sp frameHandler1 = new FrameHandler(pCam1, cam, + nullptr, + FrameHandler::eAutoReturn); + ASSERT_NE(frameHandler1, nullptr); + + // Start the camera's video stream via client 0 + bool startResult = false; + startResult = frameHandler0->startStream() && + frameHandler1->startStream(); + ASSERT_TRUE(startResult); + + // Ensure the stream starts + frameHandler0->waitForFrameCount(1); + frameHandler1->waitForFrameCount(1); + + nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC); + + // Wait a bit, then ensure both clients get at least the required minimum number of frames + sleep(5); + nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC); + unsigned framesReceived0 = 0, framesReceived1 = 0; + frameHandler0->getFramesCounters(&framesReceived0, nullptr); + frameHandler1->getFramesCounters(&framesReceived1, nullptr); + framesReceived0 = framesReceived0 - 1; // Back out the first frame we already waited for + framesReceived1 = framesReceived1 - 1; // Back out the first frame we already waited for + nsecs_t runTime = end - firstFrame; + float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds); + float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds); + ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1); + EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond); + EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond); + + // Shutdown one client + frameHandler0->shutdown(); + + // Read frame counters again + frameHandler0->getFramesCounters(&framesReceived0, nullptr); + frameHandler1->getFramesCounters(&framesReceived1, nullptr); + + // Wait a bit again + sleep(5); + unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0; + frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr); + frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr); + EXPECT_EQ(framesReceived0, framesReceivedAfterStop0); + EXPECT_LT(framesReceived1, framesReceivedAfterStop1); + + // Shutdown another + frameHandler1->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCam0); + pEnumerator->closeCamera(pCam1); + } +} + + int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance()); ::testing::InitGoogleTest(&argc, argv); From 468cc1d476ae4a78787e0730cac8cf53e1806ed1 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Sat, 12 Oct 2019 05:18:16 -0700 Subject: [PATCH 0178/1022] Revert "Revert "Revert "Extend EVS interfaces and data types""" This reverts commit 47b45af32cdea1788a1fd3e316f97d89aeddac2b. --- automotive/evs/1.1/Android.bp | 4 +- automotive/evs/1.1/IEvsCamera.hal | 34 +- automotive/evs/1.1/IEvsCameraStream.hal | 19 +- automotive/evs/1.1/IEvsEnumerator.hal | 50 - automotive/evs/1.1/default/Android.bp | 20 +- automotive/evs/1.1/default/ConfigManager.cpp | 487 ---------- automotive/evs/1.1/default/ConfigManager.h | 336 ------- .../evs/1.1/default/ConfigManagerUtil.cpp | 131 --- .../evs/1.1/default/ConfigManagerUtil.h | 61 -- automotive/evs/1.1/default/EvsCamera.cpp | 108 +-- automotive/evs/1.1/default/EvsCamera.h | 28 +- automotive/evs/1.1/default/EvsEnumerator.cpp | 109 +-- automotive/evs/1.1/default/EvsEnumerator.h | 25 +- .../resources/evs_default_configuration.xml | 68 -- automotive/evs/1.1/default/service.cpp | 2 +- automotive/evs/1.1/types.hal | 49 +- automotive/evs/1.1/vts/functional/Android.bp | 2 - .../evs/1.1/vts/functional/FrameHandler.cpp | 187 ++-- .../evs/1.1/vts/functional/FrameHandler.h | 23 +- .../functional/VtsHalEvsV1_1TargetTest.cpp | 899 +++++------------- 20 files changed, 413 insertions(+), 2229 deletions(-) delete mode 100644 automotive/evs/1.1/IEvsEnumerator.hal delete mode 100644 automotive/evs/1.1/default/ConfigManager.cpp delete mode 100644 automotive/evs/1.1/default/ConfigManager.h delete mode 100644 automotive/evs/1.1/default/ConfigManagerUtil.cpp delete mode 100644 automotive/evs/1.1/default/ConfigManagerUtil.h delete mode 100644 automotive/evs/1.1/default/resources/evs_default_configuration.xml diff --git a/automotive/evs/1.1/Android.bp b/automotive/evs/1.1/Android.bp index c850c91b21..d2e85f1304 100644 --- a/automotive/evs/1.1/Android.bp +++ b/automotive/evs/1.1/Android.bp @@ -10,15 +10,13 @@ hidl_interface { "types.hal", "IEvsCamera.hal", "IEvsCameraStream.hal", - "IEvsEnumerator.hal", ], interfaces: [ "android.hardware.automotive.evs@1.0", - "android.hardware.camera.device@3.2", "android.hardware.graphics.common@1.0", "android.hardware.graphics.common@1.1", "android.hardware.graphics.common@1.2", "android.hidl.base@1.0", ], - gen_java: false, + gen_java: true, } diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal index 975b6c6cae..21ca79e91f 100644 --- a/automotive/evs/1.1/IEvsCamera.hal +++ b/automotive/evs/1.1/IEvsCamera.hal @@ -25,14 +25,6 @@ import IEvsCameraStream; * Represents a single camera and is the primary interface for capturing images. */ interface IEvsCamera extends @1.0::IEvsCamera { - /** - * Returns the description of this camera. - * - * @return info The description of this camera. This must be the same value as - * reported by EvsEnumerator::getCameraList_1_1(). - */ - getCameraInfo_1_1() generates (CameraDesc info); - /** * Requests to pause EVS camera stream events. * @@ -108,27 +100,7 @@ interface IEvsCamera extends @1.0::IEvsCamera { unsetMaster() generates (EvsResult result); /** - * Retrieves a list of parameters this camera supports. - * - * @return params A list of CameraParam that this camera supports. - */ - getParameterList() generates (vec params); - - /** - * Requests a valid value range of a camera parameter - * - * @param id The identifier of camera parameter, CameraParam enum. - * - * @return min The lower bound of valid parameter value range. - * @return max The upper bound of valid parameter value range. - * @return step The resolution of values in valid range. - */ - getIntParameterRange(CameraParam id) - generates (int32_t min, int32_t max, int32_t step); - - /** - * Requests to set a camera parameter. Only a request from the master - * client will be processed successfully. + * Requests to set a camera parameter. * * @param id The identifier of camera parameter, CameraParam enum. * value A desired parameter value. @@ -142,7 +114,7 @@ interface IEvsCamera extends @1.0::IEvsCamera { * from what the client gives if, for example, the * driver does not support a target parameter. */ - setIntParameter(CameraParam id, int32_t value) + setParameter(CameraParam id, int32_t value) generates (EvsResult result, int32_t effectiveValue); /** @@ -154,5 +126,5 @@ interface IEvsCamera extends @1.0::IEvsCamera { * not supported. * value A value of requested camera parameter. */ - getIntParameter(CameraParam id) generates(EvsResult result, int32_t value); + getParameter(CameraParam id) generates(EvsResult result, int32_t value); }; diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal index 9e4ea19f1d..7c7f832103 100644 --- a/automotive/evs/1.1/IEvsCameraStream.hal +++ b/automotive/evs/1.1/IEvsCameraStream.hal @@ -17,32 +17,15 @@ package android.hardware.automotive.evs@1.1; import @1.0::IEvsCameraStream; -import @1.1::BufferDesc; -import @1.1::EvsEvent; /** * Implemented on client side to receive asynchronous streaming event deliveries. */ interface IEvsCameraStream extends @1.0::IEvsCameraStream { - - /** - * Receives calls from the HAL each time a video frame is ready for inspection. - * Buffer handles received by this method must be returned via calls to - * IEvsCamera::doneWithFrame_1_1(). When the video stream is stopped via a call - * to IEvsCamera::stopVideoStream(), this callback may continue to happen for - * some time as the pipeline drains. Each frame must still be returned. - * When the last frame in the stream has been delivered, STREAM_STOPPED - * event must be delivered. No further frame deliveries may happen - * thereafter. - * - * @param buffer a buffer descriptor of a delivered image frame. - */ - oneway deliverFrame_1_1(BufferDesc buffer); - /** * Receives calls from the HAL each time an event happens. * * @param event EVS event with possible event information. */ - oneway notify(EvsEvent event); + oneway notifyEvent(EvsEvent event); }; diff --git a/automotive/evs/1.1/IEvsEnumerator.hal b/automotive/evs/1.1/IEvsEnumerator.hal deleted file mode 100644 index 1695821baa..0000000000 --- a/automotive/evs/1.1/IEvsEnumerator.hal +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - */ - -package android.hardware.automotive.evs@1.1; - -import IEvsCamera; -import @1.0::IEvsEnumerator; -import @1.0::EvsResult; -import android.hardware.camera.device@3.2::Stream; - -/** - * Provides the mechanism for EVS camera discovery - */ -interface IEvsEnumerator extends @1.0::IEvsEnumerator { - /** - * Returns a list of all EVS cameras available to the system - * - * @return cameras A list of cameras availale for EVS service. - */ - getCameraList_1_1() generates (vec cameras); - - /** - * Gets the IEvsCamera associated with a cameraId from a CameraDesc - * - * Given a camera's unique cameraId from CameraDesc, returns the - * IEvsCamera interface associated with the specified camera. When - * done using the camera, the caller may release it by calling closeCamera(). - * - * @param cameraId A unique identifier of the camera. - * @param streamCfg A stream configuration the client wants to use. - * @return evsCamera EvsCamera object associated with a given cameraId. - * Returned object would be null if a camera device does - * not support a given stream configuration or is already - * configured differently by another client. - */ - openCamera_1_1(string cameraId, Stream streamCfg) generates (IEvsCamera evsCamera); -}; diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp index 41cb4265e5..a46347102f 100644 --- a/automotive/evs/1.1/default/Android.bp +++ b/automotive/evs/1.1/default/Android.bp @@ -7,41 +7,25 @@ cc_binary { "service.cpp", "EvsCamera.cpp", "EvsEnumerator.cpp", - "EvsDisplay.cpp", - "ConfigManager.cpp", - "ConfigManagerUtil.cpp", + "EvsDisplay.cpp" ], init_rc: ["android.hardware.automotive.evs@1.1-service.rc"], shared_libs: [ "android.hardware.automotive.evs@1.0", "android.hardware.automotive.evs@1.1", - "android.hardware.camera.device@3.2", "libbase", "libbinder", - "liblog", + "libcutils", "libhardware", "libhidlbase", "liblog", "libui", "libutils", - "libcamera_metadata", - "libtinyxml2", ], cflags: [ "-O0", "-g", ], - - required: [ - "evs_default_configuration.xml", - ], -} - -prebuilt_etc { - name: "evs_default_configuration.xml", - - src: "resources/evs_default_configuration.xml", - sub_dir: "automotive/evs", } diff --git a/automotive/evs/1.1/default/ConfigManager.cpp b/automotive/evs/1.1/default/ConfigManager.cpp deleted file mode 100644 index 4f46f9dbca..0000000000 --- a/automotive/evs/1.1/default/ConfigManager.cpp +++ /dev/null @@ -1,487 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include - -#include -#include -#include - -#include "ConfigManager.h" - -using ::android::hardware::camera::device::V3_2::StreamRotation; - - -ConfigManager::~ConfigManager() { - /* Nothing to do */ -} - - -void ConfigManager::readCameraInfo(const XMLElement * const aCameraElem) { - if (aCameraElem == nullptr) { - ALOGW("XML file does not have required camera element"); - return; - } - - const XMLElement *curElem = aCameraElem->FirstChildElement(); - while (curElem != nullptr) { - if (!strcmp(curElem->Name(), "group")) { - /* camera group identifier */ - const char *group_id = curElem->FindAttribute("group_id")->Value(); - - /* create CameraGroup */ - unique_ptr aCameraGroup(new ConfigManager::CameraGroup()); - - /* add a camera device to its group */ - addCameraDevices(curElem->FindAttribute("device_id")->Value(), aCameraGroup); - - /* a list of camera stream configurations */ - const XMLElement *childElem = - curElem->FirstChildElement("caps")->FirstChildElement("stream"); - while (childElem != nullptr) { - /* read 5 attributes */ - const XMLAttribute *idAttr = childElem->FindAttribute("id"); - const XMLAttribute *widthAttr = childElem->FindAttribute("width"); - const XMLAttribute *heightAttr = childElem->FindAttribute("height"); - const XMLAttribute *fmtAttr = childElem->FindAttribute("format"); - const XMLAttribute *fpsAttr = childElem->FindAttribute("framerate"); - - const int32_t id = stoi(idAttr->Value()); - int32_t framerate = 0; - if (fpsAttr != nullptr) { - framerate = stoi(fpsAttr->Value()); - } - - int32_t pixFormat; - if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), - pixFormat)) { - RawStreamConfiguration cfg = { - id, - stoi(widthAttr->Value()), - stoi(heightAttr->Value()), - pixFormat, - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, - framerate - }; - aCameraGroup->streamConfigurations[id] = cfg; - } - - childElem = childElem->NextSiblingElement("stream"); - } - - /* camera group synchronization */ - const char *sync = curElem->FindAttribute("synchronized")->Value(); - aCameraGroup->synchronized = - static_cast(strcmp(sync, "false")); - - /* add a group to hash map */ - mCameraGroups[group_id] = std::move(aCameraGroup); - } else if (!strcmp(curElem->Name(), "device")) { - /* camera unique identifier */ - const char *id = curElem->FindAttribute("id")->Value(); - - /* camera mount location */ - const char *pos = curElem->FindAttribute("position")->Value(); - - /* store read camera module information */ - mCameraInfo[id] = readCameraDeviceInfo(curElem); - - /* assign a camera device to a position group */ - mCameraPosition[pos].emplace(id); - } else { - /* ignore other device types */ - ALOGD("Unknown element %s is ignored", curElem->Name()); - } - - curElem = curElem->NextSiblingElement(); - } -} - - -unique_ptr -ConfigManager::readCameraDeviceInfo(const XMLElement *aDeviceElem) { - if (aDeviceElem == nullptr) { - return nullptr; - } - - /* create a CameraInfo to be filled */ - unique_ptr aCamera(new ConfigManager::CameraInfo()); - - /* size information to allocate camera_metadata_t */ - size_t totalEntries = 0; - size_t totalDataSize = 0; - - /* read device capabilities */ - totalEntries += - readCameraCapabilities(aDeviceElem->FirstChildElement("caps"), - aCamera, - totalDataSize); - - - /* read camera metadata */ - totalEntries += - readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"), - aCamera, - totalDataSize); - - /* construct camera_metadata_t */ - if (!constructCameraMetadata(aCamera, totalEntries, totalDataSize)) { - ALOGW("Either failed to allocate memory or " - "allocated memory was not large enough"); - } - - return aCamera; -} - - -size_t ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem, - unique_ptr &aCamera, - size_t &dataSize) { - if (aCapElem == nullptr) { - return 0; - } - - string token; - const XMLElement *curElem = nullptr; - - /* a list of supported camera parameters/controls */ - curElem = aCapElem->FirstChildElement("supported_controls"); - if (curElem != nullptr) { - const XMLElement *ctrlElem = curElem->FirstChildElement("control"); - while (ctrlElem != nullptr) { - const char *nameAttr = ctrlElem->FindAttribute("name")->Value();; - const int32_t minVal = stoi(ctrlElem->FindAttribute("min")->Value()); - const int32_t maxVal = stoi(ctrlElem->FindAttribute("max")->Value()); - - int32_t stepVal = 1; - const XMLAttribute *stepAttr = ctrlElem->FindAttribute("step"); - if (stepAttr != nullptr) { - stepVal = stoi(stepAttr->Value()); - } - - CameraParam aParam; - if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr, - aParam)) { - aCamera->controls.emplace( - aParam, - make_tuple(minVal, maxVal, stepVal) - ); - } - - ctrlElem = ctrlElem->NextSiblingElement("control"); - } - } - - /* a list of camera stream configurations */ - curElem = aCapElem->FirstChildElement("stream"); - while (curElem != nullptr) { - /* read 5 attributes */ - const XMLAttribute *idAttr = curElem->FindAttribute("id"); - const XMLAttribute *widthAttr = curElem->FindAttribute("width"); - const XMLAttribute *heightAttr = curElem->FindAttribute("height"); - const XMLAttribute *fmtAttr = curElem->FindAttribute("format"); - const XMLAttribute *fpsAttr = curElem->FindAttribute("framerate"); - - const int32_t id = stoi(idAttr->Value()); - int32_t framerate = 0; - if (fpsAttr != nullptr) { - framerate = stoi(fpsAttr->Value()); - } - - int32_t pixFormat; - if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), - pixFormat)) { - RawStreamConfiguration cfg = { - id, - stoi(widthAttr->Value()), - stoi(heightAttr->Value()), - pixFormat, - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, - framerate - }; - aCamera->streamConfigurations[id] = cfg; - } - - curElem = curElem->NextSiblingElement("stream"); - } - - dataSize = calculate_camera_metadata_entry_data_size( - get_camera_metadata_tag_type( - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS - ), - aCamera->streamConfigurations.size() * kStreamCfgSz - ); - - /* a single camera metadata entry contains multiple stream configurations */ - return dataSize > 0 ? 1 : 0; -} - - -size_t ConfigManager::readCameraMetadata(const XMLElement * const aParamElem, - unique_ptr &aCamera, - size_t &dataSize) { - if (aParamElem == nullptr) { - return 0; - } - - const XMLElement *curElem = aParamElem->FirstChildElement("parameter"); - size_t numEntries = 0; - camera_metadata_tag_t tag; - while (curElem != nullptr) { - if (!ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(), - tag)) { - switch(tag) { - case ANDROID_LENS_DISTORTION: - case ANDROID_LENS_POSE_ROTATION: - case ANDROID_LENS_POSE_TRANSLATION: - case ANDROID_LENS_INTRINSIC_CALIBRATION: { - /* float[] */ - size_t count = 0; - void *data = ConfigManagerUtil::convertFloatArray( - curElem->FindAttribute("size")->Value(), - curElem->FindAttribute("value")->Value(), - count - ); - - aCamera->cameraMetadata[tag] = - make_pair(make_unique(data), count); - - ++numEntries; - dataSize += calculate_camera_metadata_entry_data_size( - get_camera_metadata_tag_type(tag), count - ); - - break; - } - - default: - ALOGW("Parameter %s is not supported", - curElem->FindAttribute("name")->Value()); - break; - } - } - - curElem = curElem->NextSiblingElement("parameter"); - } - - return numEntries; -} - - -bool ConfigManager::constructCameraMetadata(unique_ptr &aCamera, - const size_t totalEntries, - const size_t totalDataSize) { - if (!aCamera->allocate(totalEntries, totalDataSize)) { - ALOGE("Failed to allocate memory for camera metadata"); - return false; - } - - const size_t numStreamConfigs = aCamera->streamConfigurations.size(); - unique_ptr data(new int32_t[kStreamCfgSz * numStreamConfigs]); - int32_t *ptr = data.get(); - for (auto &cfg : aCamera->streamConfigurations) { - for (auto i = 0; i < kStreamCfgSz; ++i) { - *ptr++ = cfg.second[i]; - } - } - int32_t err = add_camera_metadata_entry(aCamera->characteristics, - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, - data.get(), - numStreamConfigs * kStreamCfgSz); - - if (err) { - ALOGE("Failed to add stream configurations to metadata, ignored"); - return false; - } - - bool success = true; - for (auto &[tag, entry] : aCamera->cameraMetadata) { - /* try to add new camera metadata entry */ - int32_t err = add_camera_metadata_entry(aCamera->characteristics, - tag, - entry.first.get(), - entry.second); - if (err) { - ALOGE("Failed to add an entry with a tag 0x%X", tag); - - /* may exceed preallocated capacity */ - ALOGE("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled", - get_camera_metadata_entry_count(aCamera->characteristics), - get_camera_metadata_entry_capacity(aCamera->characteristics), - get_camera_metadata_data_count(aCamera->characteristics), - get_camera_metadata_data_capacity(aCamera->characteristics)); - ALOGE("\tCurrent metadata entry requires %ld bytes", - calculate_camera_metadata_entry_data_size(tag, entry.second)); - - success = false; - } - } - - ALOGV("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled", - get_camera_metadata_entry_count(aCamera->characteristics), - get_camera_metadata_entry_capacity(aCamera->characteristics), - get_camera_metadata_data_count(aCamera->characteristics), - get_camera_metadata_data_capacity(aCamera->characteristics)); - - return success; -} - - -void ConfigManager::readSystemInfo(const XMLElement * const aSysElem) { - if (aSysElem == nullptr) { - return; - } - - /* - * Please note that this function assumes that a given system XML element - * and its child elements follow DTD. If it does not, it will cause a - * segmentation fault due to the failure of finding expected attributes. - */ - - /* read number of cameras available in the system */ - const XMLElement *xmlElem = aSysElem->FirstChildElement("num_cameras"); - if (xmlElem != nullptr) { - mSystemInfo.numCameras = - stoi(xmlElem->FindAttribute("value")->Value()); - } -} - - -void ConfigManager::readDisplayInfo(const XMLElement * const aDisplayElem) { - if (aDisplayElem == nullptr) { - ALOGW("XML file does not have required camera element"); - return; - } - - const XMLElement *curDev = aDisplayElem->FirstChildElement("device"); - while (curDev != nullptr) { - const char *id = curDev->FindAttribute("id")->Value(); - //const char *pos = curDev->FirstAttribute("position")->Value(); - - unique_ptr dpy(new DisplayInfo()); - if (dpy == nullptr) { - ALOGE("Failed to allocate memory for DisplayInfo"); - return; - } - - const XMLElement *cap = curDev->FirstChildElement("caps"); - if (cap != nullptr) { - const XMLElement *curStream = cap->FirstChildElement("stream"); - while (curStream != nullptr) { - /* read 4 attributes */ - const XMLAttribute *idAttr = curStream->FindAttribute("id"); - const XMLAttribute *widthAttr = curStream->FindAttribute("width"); - const XMLAttribute *heightAttr = curStream->FindAttribute("height"); - const XMLAttribute *fmtAttr = curStream->FindAttribute("format"); - - const int32_t id = stoi(idAttr->Value()); - int32_t pixFormat; - if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), - pixFormat)) { - RawStreamConfiguration cfg = { - id, - stoi(widthAttr->Value()), - stoi(heightAttr->Value()), - pixFormat, - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT, - 0 // unused - }; - dpy->streamConfigurations[id] = cfg; - } - - curStream = curStream->NextSiblingElement("stream"); - } - } - - mDisplayInfo[id] = std::move(dpy); - curDev = curDev->NextSiblingElement("device"); - } - - return; -} - - -bool ConfigManager::readConfigDataFromXML() noexcept { - XMLDocument xmlDoc; - - const int64_t parsingStart = android::elapsedRealtimeNano(); - - /* load and parse a configuration file */ - xmlDoc.LoadFile(mConfigFilePath); - if (xmlDoc.ErrorID() != XML_SUCCESS) { - ALOGE("Failed to load and/or parse a configuration file, %s", xmlDoc.ErrorStr()); - return false; - } - - /* retrieve the root element */ - const XMLElement *rootElem = xmlDoc.RootElement(); - if (strcmp(rootElem->Name(), "configuration")) { - ALOGE("A configuration file is not in the required format. " - "See /etc/automotive/evs/evs_configuration.dtd"); - return false; - } - - /* - * parse camera information; this needs to be done before reading system - * information - */ - readCameraInfo(rootElem->FirstChildElement("camera")); - - /* parse system information */ - readSystemInfo(rootElem->FirstChildElement("system")); - - /* parse display information */ - readDisplayInfo(rootElem->FirstChildElement("display")); - - const int64_t parsingEnd = android::elapsedRealtimeNano(); - ALOGI("Parsing configuration file takes %lf (ms)", - (double)(parsingEnd - parsingStart) / 1000000.0); - - - return true; -} - - -void ConfigManager::addCameraDevices(const char *devices, - unique_ptr &aGroup) { - stringstream device_list(devices); - string token; - while (getline(device_list, token, ',')) { - aGroup->devices.emplace(token); - } -} - - -std::unique_ptr ConfigManager::Create(const char *path) { - unique_ptr cfgMgr(new ConfigManager(path)); - - /* - * Read a configuration from XML file - * - * If this is too slow, ConfigManager::readConfigDataFromBinary() and - * ConfigManager::writeConfigDataToBinary()can serialize CameraInfo object - * to the filesystem and construct CameraInfo instead; this was - * evaluated as 10x faster. - */ - if (!cfgMgr->readConfigDataFromXML()) { - return nullptr; - } else { - return cfgMgr; - } -} - diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h deleted file mode 100644 index 0275f904e5..0000000000 --- a/automotive/evs/1.1/default/ConfigManager.h +++ /dev/null @@ -1,336 +0,0 @@ -/* - * 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. - */ -#ifndef CONFIG_MANAGER_H -#define CONFIG_MANAGER_H - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "ConfigManagerUtil.h" - -using namespace std; -using namespace tinyxml2; - -using ::android::hardware::hidl_vec; -using ::android::hardware::camera::device::V3_2::Stream; -using ::android::hardware::automotive::evs::V1_1::CameraParam; - -/* - * Plese note that this is different from what is defined in - * libhardware/modules/camera/3_4/metadata/types.h; this has one additional - * field to store a framerate. - */ -const size_t kStreamCfgSz = 6; -typedef std::array RawStreamConfiguration; - -class ConfigManager { -public: - static std::unique_ptr Create(const char *path = ""); - ConfigManager(const ConfigManager&) = delete; - ConfigManager& operator=(const ConfigManager&) = delete; - - virtual ~ConfigManager(); - - /* Camera device's capabilities and metadata */ - class CameraInfo { - public: - CameraInfo() : - characteristics(nullptr) { - /* Nothing to do */ - } - - virtual ~CameraInfo() { - free_camera_metadata(characteristics); - } - - /* Allocate memory for camera_metadata_t */ - bool allocate(size_t entry_cap, size_t data_cap) { - if (characteristics != nullptr) { - ALOGE("Camera metadata is already allocated"); - return false; - } - - characteristics = allocate_camera_metadata(entry_cap, data_cap); - return characteristics != nullptr; - } - - /* - * List of supported controls that the master client can program. - * Paraemters are stored with its valid range - */ - unordered_map> controls; - - /* List of supported frame rates */ - unordered_set frameRates; - - /* - * List of supported output stream configurations; each array stores - * format, width, height, and direction values in the order. - */ - unordered_map streamConfigurations; - - /* - * Internal storage for camera metadata. Each entry holds a pointer to - * data and number of elements - */ - unordered_map, size_t>> cameraMetadata; - - /* Camera module characteristics */ - camera_metadata_t *characteristics; - }; - - class CameraGroup { - public: - CameraGroup() {} - - /* ID of member camera devices */ - unordered_set devices; - - /* The capture operation of member camera devices are synchronized */ - bool synchronized = false; - - /* - * List of stream configurations that are supposed by all camera devices - * in this group. - */ - unordered_map streamConfigurations; - }; - - class SystemInfo { - public: - /* number of available cameras */ - int32_t numCameras = 0; - }; - - class DisplayInfo { - public: - /* - * List of supported input stream configurations; each array stores - * format, width, height, and direction values in the order. - */ - unordered_map streamConfigurations; - }; - - /* - * Return system information - * - * @return SystemInfo - * Constant reference of SystemInfo. - */ - const SystemInfo &getSystemInfo() { - return mSystemInfo; - } - - /* - * Return a list of cameras - * - * This function assumes that it is not being called frequently. - * - * @return vector - * A vector that contains unique camera device identifiers. - */ - vector getCameraList() { - vector aList; - for (auto &v : mCameraInfo) { - aList.emplace_back(v.first); - } - - return aList; - } - - - /* - * Return a list of cameras - * - * @return CameraGroup - * A pointer to a camera group identified by a given id. - */ - unique_ptr& getCameraGroup(const string& gid) { - return mCameraGroups[gid]; - } - - - /* - * Return a camera metadata - * - * @param cameraId - * Unique camera node identifier in string - * - * @return unique_ptr - * A pointer to CameraInfo that is associated with a given camera - * ID. This returns a null pointer if this does not recognize a - * given camera identifier. - */ - unique_ptr& getCameraInfo(const string cameraId) noexcept { - return mCameraInfo[cameraId]; - } - -private: - /* Constructors */ - ConfigManager(const char *xmlPath) : - mConfigFilePath(xmlPath) { - } - - /* System configuration */ - SystemInfo mSystemInfo; - - /* Internal data structure for camera device information */ - unordered_map> mCameraInfo; - - /* Internal data structure for camera device information */ - unordered_map> mDisplayInfo; - - /* Camera groups are stored in hash map */ - unordered_map> mCameraGroups; - - /* - * Camera positions are stored in hash map. - * The position must be one of front, rear, left, and right. - */ - unordered_map> mCameraPosition; - - /* A path to XML configuration file */ - const char *mConfigFilePath; - - /* - * Parse a given EVS configuration file and store the information - * internally. - * - * @return bool - * True if it completes parsing a file successfully. - */ - bool readConfigDataFromXML() noexcept; - - /* - * read the information of the vehicle - * - * @param aSysElem - * A pointer to "system" XML element. - */ - void readSystemInfo(const XMLElement * const aSysElem); - - /* - * read the information of camera devices - * - * @param aCameraElem - * A pointer to "camera" XML element that may contain multiple - * "device" elements. - */ - void readCameraInfo(const XMLElement * const aCameraElem); - - /* - * read display device information - * - * @param aDisplayElem - * A pointer to "display" XML element that may contain multiple - * "device" elements. - */ - void readDisplayInfo(const XMLElement * const aDisplayElem); - - /* - * read camera device information - * - * @param aDeviceElem - * A pointer to "device" XML element that contains camera module - * capability info and its characteristics. - * - * @return unique_ptr - * A pointer to CameraInfo class that contains camera module - * capability and characteristics. Please note that this transfers - * the ownership of created CameraInfo to the caller. - */ - unique_ptr readCameraDeviceInfo(const XMLElement *aDeviceElem); - - /* - * read camera metadata - * - * @param aCapElem - * A pointer to "cap" XML element. - * @param aCamera - * A pointer to CameraInfo that is being filled by this method. - * @param dataSize - * Required size of memory to store camera metadata found in this - * method. This is calculated in this method and returned to the - * caller for camera_metadata allocation. - * - * @return size_t - * Number of camera metadata entries - */ - size_t readCameraCapabilities(const XMLElement * const aCapElem, - unique_ptr &aCamera, - size_t &dataSize); - - /* - * read camera metadata - * - * @param aParamElem - * A pointer to "characteristics" XML element. - * @param aCamera - * A pointer to CameraInfo that is being filled by this method. - * @param dataSize - * Required size of memory to store camera metadata found in this - * method. - * - * @return size_t - * Number of camera metadata entries - */ - size_t readCameraMetadata(const XMLElement * const aParamElem, - unique_ptr &aCamera, - size_t &dataSize); - - /* - * construct camera_metadata_t from camera capabilities and metadata - * - * @param aCamera - * A pointer to CameraInfo that is being filled by this method. - * @param totalEntries - * Number of camera metadata entries to be added. - * @param totalDataSize - * Sum of sizes of camera metadata entries to be added. - * - * @return bool - * False if either it fails to allocate memory for camera metadata - * or its size is not large enough to add all found camera metadata - * entries. - */ - bool constructCameraMetadata(unique_ptr &aCamera, - const size_t totalEntries, - const size_t totalDataSize); - - /* - * parse a comma-separated list of camera devices and add them to - * CameraGroup. - * - * @param devices - * A comma-separated list of camera device identifiers. - * @param aGroup - * Camera group which cameras will be added to. - */ - void addCameraDevices(const char *devices, - unique_ptr &aGroup); -}; -#endif // CONFIG_MANAGER_H - diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.cpp b/automotive/evs/1.1/default/ConfigManagerUtil.cpp deleted file mode 100644 index 8206daa6d7..0000000000 --- a/automotive/evs/1.1/default/ConfigManagerUtil.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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. - */ - -#include "ConfigManagerUtil.h" - -#include -#include -#include - -#include -#include - - -bool ConfigManagerUtil::convertToEvsCameraParam(const string &id, - CameraParam &camParam) { - string trimmed = ConfigManagerUtil::trimString(id); - bool success = true; - - if (!trimmed.compare("BRIGHTNESS")) { - camParam = CameraParam::BRIGHTNESS; - } else if (!trimmed.compare("CONTRAST")) { - camParam = CameraParam::CONTRAST; - } else if (!trimmed.compare("AUTOGAIN")) { - camParam = CameraParam::AUTOGAIN; - } else if (!trimmed.compare("GAIN")) { - camParam = CameraParam::GAIN; - } else if (!trimmed.compare("AUTO_WHITE_BALANCE")) { - camParam = CameraParam::AUTO_WHITE_BALANCE; - } else if (!trimmed.compare("WHITE_BALANCE_TEMPERATURE")) { - camParam = CameraParam::WHITE_BALANCE_TEMPERATURE; - } else if (!trimmed.compare("SHARPNESS")) { - camParam = CameraParam::SHARPNESS; - } else if (!trimmed.compare("AUTO_EXPOSURE")) { - camParam = CameraParam::AUTO_EXPOSURE; - } else if (!trimmed.compare("ABSOLUTE_EXPOSURE")) { - camParam = CameraParam::ABSOLUTE_EXPOSURE; - } else if (!trimmed.compare("ABSOLUTE_FOCUS")) { - camParam = CameraParam::ABSOLUTE_FOCUS; - } else if (!trimmed.compare("AUTO_FOCUS")) { - camParam = CameraParam::AUTO_FOCUS; - } else if (!trimmed.compare("ABSOLUTE_ZOOM")) { - camParam = CameraParam::ABSOLUTE_ZOOM; - } else { - success = false; - } - - return success; -} - - -bool ConfigManagerUtil::convertToPixelFormat(const string &format, - int32_t &pixFormat) { - string trimmed = ConfigManagerUtil::trimString(format); - bool success = true; - - if (!trimmed.compare("RGBA_8888")) { - pixFormat = HAL_PIXEL_FORMAT_RGBA_8888; - } else if (!trimmed.compare("YCRCB_420_SP")) { - pixFormat = HAL_PIXEL_FORMAT_YCRCB_420_SP; - } else if (!trimmed.compare("YCBCR_422_I")) { - pixFormat = HAL_PIXEL_FORMAT_YCBCR_422_I; - } else { - success = false; - } - - return success; -} - - -bool ConfigManagerUtil::convertToMetadataTag(const char *name, - camera_metadata_tag &aTag) { - if (!strcmp(name, "LENS_DISTORTION")) { - aTag = ANDROID_LENS_DISTORTION; - } else if (!strcmp(name, "LENS_INTRINSIC_CALIBRATION")) { - aTag = ANDROID_LENS_INTRINSIC_CALIBRATION; - } else if (!strcmp(name, "LENS_POSE_ROTATION")) { - aTag = ANDROID_LENS_POSE_ROTATION; - } else if (!strcmp(name, "LENS_POSE_TRANSLATION")) { - aTag = ANDROID_LENS_POSE_TRANSLATION; - } else { - return false; - } - - return true; -} - - -float *ConfigManagerUtil::convertFloatArray(const char *sz, const char *vals, - size_t &count, const char delimiter) { - string size_string(sz); - string value_string(vals); - - count = stoi(size_string); - float *result = new float[count]; - stringstream values(value_string); - - int32_t idx = 0; - string token; - while (getline(values, token, delimiter)) { - result[idx++] = stof(token); - } - - return result; -} - - -string ConfigManagerUtil::trimString(const string &src, const string &ws) { - const auto s = src.find_first_not_of(ws); - if (s == string::npos) { - return ""; - } - - const auto e = src.find_last_not_of(ws); - const auto r = e - s + 1; - - return src.substr(s, r); -} - diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.h b/automotive/evs/1.1/default/ConfigManagerUtil.h deleted file mode 100644 index 8c89ae7745..0000000000 --- a/automotive/evs/1.1/default/ConfigManagerUtil.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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. - */ -#ifndef CONFIG_MANAGER_UTIL_H -#define CONFIG_MANAGER_UTIL_H - -#include -#include -#include -#include - -using namespace std; -using ::android::hardware::automotive::evs::V1_1::CameraParam; - - -class ConfigManagerUtil { -public: - /** - * Convert a given string into V4L2_CID_* - */ - static bool convertToEvsCameraParam(const string &id, - CameraParam &camParam); - /** - * Convert a given string into android.hardware.graphics.common.PixelFormat - */ - static bool convertToPixelFormat(const string &format, - int32_t &pixelFormat); - /** - * Convert a given string into corresponding camera metadata data tag defined in - * system/media/camera/include/system/camera_metadta_tags.h - */ - static bool convertToMetadataTag(const char *name, - camera_metadata_tag &aTag); - /** - * Convert a given string into a floating value array - */ - static float *convertFloatArray(const char *sz, - const char *vals, - size_t &count, - const char delimiter = ','); - /** - * Trim a string - */ - static string trimString(const string &src, - const string &ws = " \n\r\t\f\v"); -}; - -#endif // CONFIG_MANAGER_UTIL_H - diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp index 5ba753da2e..2d55566349 100644 --- a/automotive/evs/1.1/default/EvsCamera.cpp +++ b/automotive/evs/1.1/default/EvsCamera.cpp @@ -40,21 +40,28 @@ const char EvsCamera::kCameraName_Backup[] = "backup"; const unsigned MAX_BUFFERS_IN_FLIGHT = 100; -EvsCamera::EvsCamera(const char *id, - unique_ptr &camInfo) : +EvsCamera::EvsCamera(const char *id) : mFramesAllowed(0), mFramesInUse(0), - mStreamState(STOPPED), - mCameraInfo(camInfo) { + mStreamState(STOPPED) { ALOGD("EvsCamera instantiated"); - /* set a camera id */ - mDescription.v1.cameraId = id; + mDescription.cameraId = id; - /* set camera metadata */ - mDescription.metadata.setToExternal((uint8_t *)camInfo->characteristics, - get_camera_metadata_size(camInfo->characteristics)); + // Set up dummy data for testing + if (mDescription.cameraId == kCameraName_Backup) { + mWidth = 640; // full NTSC/VGA + mHeight = 480; // full NTSC/VGA + mDescription.vendorFlags = 0xFFFFFFFF; // Arbitrary value + } else { + mWidth = 320; // 1/2 NTSC/VGA + mHeight = 240; // 1/2 NTSC/VGA + } + + mFormat = HAL_PIXEL_FORMAT_RGBA_8888; + mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE | + GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY; } @@ -102,7 +109,7 @@ Return EvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) { ALOGD("getCameraInfo"); // Send back our self description - _hidl_cb(mDescription.v1); + _hidl_cb(mDescription); return Void(); } @@ -187,7 +194,7 @@ Return EvsCamera::stopVideoStream() { // Block outside the mutex until the "stop" flag has been acknowledged // We won't send any more frames, but the client might still get some already in flight - ALOGD("Waiting for stream thread to end..."); + ALOGD("Waiting for stream thread to end.."); lock.unlock(); mCaptureThread.join(); lock.lock(); @@ -231,15 +238,6 @@ Return EvsCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/, int3 // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow. -Return EvsCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) { - ALOGD("getCameraInfo_1_1"); - - // Send back our self description - _hidl_cb(mDescription); - return Void(); -} - - Return EvsCamera::doneWithFrame_1_1(const BufferDesc_1_1& bufDesc) { std::lock_guard lock(mAccessLock); returnBuffer(bufDesc.bufferId, bufDesc.buffer.nativeHandle); @@ -280,29 +278,8 @@ Return EvsCamera::unsetMaster() { } -Return EvsCamera::getParameterList(getParameterList_cb _hidl_cb) { - hidl_vec hidlCtrls; - hidlCtrls.resize(mCameraInfo->controls.size()); - unsigned idx = 0; - for (auto& [cid, cfg] : mCameraInfo->controls) { - hidlCtrls[idx++] = cid; - } - - _hidl_cb(hidlCtrls); - return Void(); -} - - -Return EvsCamera::getIntParameterRange(CameraParam id, - getIntParameterRange_cb _hidl_cb) { - auto range = mCameraInfo->controls[id]; - _hidl_cb(get<0>(range), get<1>(range), get<2>(range)); - return Void(); -} - - -Return EvsCamera::setIntParameter(CameraParam id, int32_t value, - setIntParameter_cb _hidl_cb) { +Return EvsCamera::setParameter(CameraParam id, int32_t value, + setParameter_cb _hidl_cb) { // Default implementation does not support this. (void)id; (void)value; @@ -311,8 +288,7 @@ Return EvsCamera::setIntParameter(CameraParam id, int32_t value, } -Return EvsCamera::getIntParameter(CameraParam id, - getIntParameter_cb _hidl_cb) { +Return EvsCamera::getParameter(CameraParam id, getParameter_cb _hidl_cb) { // Default implementation does not support this. (void)id; _hidl_cb(EvsResult::INVALID_ARG, 0); @@ -495,7 +471,9 @@ void EvsCamera::generateFrames() { fillTestFrame(newBuffer); // Issue the (asynchronous) callback to the client -- can't be holding the lock - auto result = mStream->deliverFrame_1_1(newBuffer); + EvsEvent event; + event.buffer(newBuffer); + auto result = mStream->notifyEvent(event); if (result.isOk()) { ALOGD("Delivered %p as id %d", newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId); @@ -528,8 +506,10 @@ void EvsCamera::generateFrames() { // If we've been asked to stop, send an event to signal the actual end of stream EvsEvent event; - event.aType = EvsEventType::STREAM_STOPPED; - auto result = mStream->notify(event); + InfoEventDesc desc = {}; + desc.aType = InfoEventType::STREAM_STOPPED; + event.info(desc); + auto result = mStream->notifyEvent(event); if (!result.isOk()) { ALOGE("Error delivering end of stream marker"); } @@ -636,38 +616,6 @@ void EvsCamera::returnBuffer(const uint32_t bufferId, const buffer_handle_t memH } -sp EvsCamera::Create(const char *deviceName) { - unique_ptr nullCamInfo = nullptr; - - return Create(deviceName, nullCamInfo); -} - - -sp EvsCamera::Create(const char *deviceName, - unique_ptr &camInfo, - const Stream *streamCfg) { - sp evsCamera = new EvsCamera(deviceName, camInfo); - if (evsCamera == nullptr) { - return nullptr; - } - - /* default implementation does not use a given configuration */ - (void)streamCfg; - - /* Use the first resolution from the list for the testing */ - auto it = camInfo->streamConfigurations.begin(); - evsCamera->mWidth = it->second[1]; - evsCamera->mHeight = it->second[2]; - evsCamera->mDescription.v1.vendorFlags = 0xFFFFFFFF; // Arbitrary test value - - evsCamera->mFormat = HAL_PIXEL_FORMAT_RGBA_8888; - evsCamera->mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE | - GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY; - - return evsCamera; -} - - } // namespace implementation } // namespace V1_0 } // namespace evs diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h index c15b4b117b..47a3164892 100644 --- a/automotive/evs/1.1/default/EvsCamera.h +++ b/automotive/evs/1.1/default/EvsCamera.h @@ -25,8 +25,6 @@ #include -#include "ConfigManager.h" - using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc; using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc; using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream; @@ -61,28 +59,18 @@ public: Return setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override; // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow. - Return getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) override; Return pauseVideoStream() override; Return resumeVideoStream() override; Return doneWithFrame_1_1(const BufferDesc_1_1& buffer) override; Return setMaster() override; Return forceMaster(const sp& display) override; Return unsetMaster() override; - Return getParameterList(getParameterList_cb _hidl_cb) override; - Return getIntParameterRange(CameraParam id, - getIntParameterRange_cb _hidl_cb) override; - Return setIntParameter(CameraParam id, int32_t value, - setIntParameter_cb _hidl_cb) override; - Return getIntParameter(CameraParam id, - getIntParameter_cb _hidl_cb) override; - - static sp Create(const char *deviceName); - static sp Create(const char *deviceName, - unique_ptr &camInfo, - const Stream *streamCfg = nullptr); - EvsCamera(const EvsCamera&) = delete; - EvsCamera& operator=(const EvsCamera&) = delete; + Return setParameter(CameraParam id, int32_t value, + setParameter_cb _hidl_cb) override; + Return getParameter(CameraParam id, getParameter_cb _hidl_cb) override; + // Implementation details + EvsCamera(const char *id); virtual ~EvsCamera() override; void forceShutdown(); // This gets called if another caller "steals" ownership of the camera @@ -91,10 +79,7 @@ public: static const char kCameraName_Backup[]; private: - EvsCamera(const char *id, - unique_ptr &camInfo); // These three functions are expected to be called while mAccessLock is held - // bool setAvailableFrames_Locked(unsigned bufferCount); unsigned increaseAvailableFrames_Locked(unsigned numToAdd); unsigned decreaseAvailableFrames_Locked(unsigned numToRemove); @@ -139,9 +124,6 @@ private: // Synchronization necessary to deconflict mCaptureThread from the main service thread std::mutex mAccessLock; - - // Static camera module information - unique_ptr &mCameraInfo; }; } // namespace implementation diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp index a010729ce6..b3249071ae 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.cpp +++ b/automotive/evs/1.1/default/EvsEnumerator.cpp @@ -33,7 +33,6 @@ namespace implementation { // constructs a new instance for each client. std::list EvsEnumerator::sCameraList; wp EvsEnumerator::sActiveDisplay; -unique_ptr EvsEnumerator::sConfigManager; EvsEnumerator::EvsEnumerator() { @@ -41,11 +40,9 @@ EvsEnumerator::EvsEnumerator() { // Add sample camera data to our list of cameras // In a real driver, this would be expected to can the available hardware - sConfigManager = - ConfigManager::Create("/etc/automotive/evs/evs_sample_configuration.xml"); - for (auto v : sConfigManager->getCameraList()) { - sCameraList.emplace_back(v.c_str()); - } + sCameraList.emplace_back(EvsCamera::kCameraName_Backup); + sCameraList.emplace_back("LaneView"); + sCameraList.emplace_back("right turn"); } @@ -60,7 +57,7 @@ Return EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) { std::vector descriptions; descriptions.reserve(numCameras); for (const auto& cam : sCameraList) { - descriptions.push_back( cam.desc.v1 ); + descriptions.push_back( cam.desc ); } // Encapsulate our camera descriptions in the HIDL vec type @@ -81,7 +78,7 @@ Return> EvsEnumerator::openCamera(const hidl_string& cameraId // Find the named camera CameraRecord *pRecord = nullptr; for (auto &&cam : sCameraList) { - if (cam.desc.v1.cameraId == cameraId) { + if (cam.desc.cameraId == cameraId) { // Found a match! pRecord = &cam; break; @@ -102,12 +99,7 @@ Return> EvsEnumerator::openCamera(const hidl_string& cameraId } // Construct a camera instance for the caller - if (sConfigManager == nullptr) { - pActiveCamera = EvsCamera::Create(cameraId.c_str()); - } else { - pActiveCamera = EvsCamera::Create(cameraId.c_str(), - sConfigManager->getCameraInfo(cameraId)); - } + pActiveCamera = new EvsCamera(cameraId.c_str()); pRecord->activeInstance = pActiveCamera; if (pActiveCamera == nullptr) { ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str()); @@ -128,15 +120,15 @@ Return EvsEnumerator::closeCamera(const ::android::sp& pCa // Get the camera id so we can find it in our list std::string cameraId; - pCamera_1_1->getCameraInfo_1_1([&cameraId](CameraDesc desc) { - cameraId = desc.v1.cameraId; + pCamera_1_1->getCameraInfo([&cameraId](CameraDesc desc) { + cameraId = desc.cameraId; } ); // Find the named camera CameraRecord *pRecord = nullptr; for (auto &&cam : sCameraList) { - if (cam.desc.v1.cameraId == cameraId) { + if (cam.desc.cameraId == cameraId) { // Found a match! pRecord = &cam; break; @@ -217,89 +209,6 @@ Return EvsEnumerator::getDisplayState() { } -// Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow. -Return EvsEnumerator::getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) { - ALOGD("getCameraList"); - - const unsigned numCameras = sCameraList.size(); - - // Build up a packed array of CameraDesc for return - // NOTE: Only has to live until the callback returns - std::vector descriptions; - descriptions.reserve(numCameras); - for (const auto& cam : sCameraList) { - descriptions.push_back( cam.desc ); - } - - // Encapsulate our camera descriptions in the HIDL vec type - hidl_vec hidlCameras(descriptions); - - // Send back the results - ALOGD("reporting %zu cameras available", hidlCameras.size()); - _hidl_cb(hidlCameras); - - // HIDL convention says we return Void if we sent our result back via callback - return Void(); -} - -Return> -EvsEnumerator::openCamera_1_1(const hidl_string& cameraId, - const Stream& streamCfg) { - // Find the named camera - CameraRecord *pRecord = nullptr; - for (auto &&cam : sCameraList) { - if (cam.desc.v1.cameraId == cameraId) { - // Found a match! - pRecord = &cam; - break; - } - } - - // Is this a recognized camera id? - if (!pRecord) { - ALOGE("Requested camera %s not found", cameraId.c_str()); - return nullptr; - } - - // Has this camera already been instantiated by another caller? - sp pActiveCamera = pRecord->activeInstance.promote(); - if (pActiveCamera != nullptr) { - ALOGW("Killing previous camera because of new caller"); - closeCamera(pActiveCamera); - } - - // Construct a camera instance for the caller - if (sConfigManager == nullptr) { - pActiveCamera = EvsCamera::Create(cameraId.c_str()); - } else { - pActiveCamera = EvsCamera::Create(cameraId.c_str(), - sConfigManager->getCameraInfo(cameraId), - &streamCfg); - } - - pRecord->activeInstance = pActiveCamera; - if (pActiveCamera == nullptr) { - ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str()); - } - - return pActiveCamera; -} - - -EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& cameraId) { - // Find the named camera - CameraRecord *pRecord = nullptr; - for (auto &&cam : sCameraList) { - if (cam.desc.v1.cameraId == cameraId) { - // Found a match! - pRecord = &cam; - break; - } - } - - return pRecord; -} - } // namespace implementation } // namespace V1_1 } // namespace evs diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h index 475ec76b93..11c2170632 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.h +++ b/automotive/evs/1.1/default/EvsEnumerator.h @@ -17,20 +17,18 @@ #ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H #define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H -#include +#include #include #include -#include "ConfigManager.h" - using ::android::hardware::automotive::evs::V1_0::EvsResult; using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; using ::android::hardware::automotive::evs::V1_0::DisplayState; +using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator; using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera; using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera; using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc; -using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc; namespace android { @@ -55,11 +53,6 @@ public: Return closeDisplay(const ::android::sp& display) override; Return getDisplayState() override; - // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow. - Return getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) override; - Return> openCamera_1_1(const hidl_string& cameraId, - const Stream& streamCfg) override; - // Implementation details EvsEnumerator(); @@ -68,20 +61,14 @@ private: // That is to say, this is effectively a singleton despite the fact that HIDL // constructs a new instance for each client. struct CameraRecord { - CameraDesc_1_1 desc; + CameraDesc_1_0 desc; wp activeInstance; - CameraRecord(const char *cameraId) : desc() { desc.v1.cameraId = cameraId; } + CameraRecord(const char *cameraId) : desc() { desc.cameraId = cameraId; } }; + static std::list sCameraList; - static CameraRecord* findCameraById(const std::string& cameraId); - - static std::list sCameraList; - - // Weak pointer. Object destructs if client dies. - static wp sActiveDisplay; - - static unique_ptr sConfigManager; + static wp sActiveDisplay; // Weak pointer. Object destructs if client dies. }; } // namespace implementation diff --git a/automotive/evs/1.1/default/resources/evs_default_configuration.xml b/automotive/evs/1.1/default/resources/evs_default_configuration.xml deleted file mode 100644 index 692102ed38..0000000000 --- a/automotive/evs/1.1/default/resources/evs_default_configuration.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/automotive/evs/1.1/default/service.cpp b/automotive/evs/1.1/default/service.cpp index 5135864e88..128a14aa30 100644 --- a/automotive/evs/1.1/default/service.cpp +++ b/automotive/evs/1.1/default/service.cpp @@ -33,7 +33,7 @@ using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; // Generated HIDL files -using android::hardware::automotive::evs::V1_1::IEvsEnumerator; +using android::hardware::automotive::evs::V1_0::IEvsEnumerator; using android::hardware::automotive::evs::V1_0::IEvsDisplay; // The namespace in which all our implementation code lives diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal index dcb2abb0e9..2c6b2ed589 100644 --- a/automotive/evs/1.1/types.hal +++ b/automotive/evs/1.1/types.hal @@ -21,22 +21,6 @@ import @1.0::DisplayDesc; import @1.0::DisplayState; import @1.0::EvsResult; import android.hardware.graphics.common@1.2::HardwareBuffer; -import android.hardware.camera.device@3.2::CameraMetadata; - -/** - * Structure describing the basic properties of an EVS camera, extended from its - * v1.0 declaration. - * - * The HAL is responsible for filling out this structure for each - * EVS camera in the system. - */ -struct CameraDesc { - @1.0::CameraDesc v1; - /** - * Store camera metadata such as lens characteristics. - */ - CameraMetadata metadata; -}; /** * Structure representing an image buffer through our APIs @@ -66,7 +50,7 @@ struct BufferDesc { /** * Types of informative streaming events */ -enum EvsEventType : uint32_t { +enum InfoEventType : uint32_t { /** * Video stream is started */ @@ -97,17 +81,31 @@ enum EvsEventType : uint32_t { /** * Structure that describes informative events occurred during EVS is streaming */ -struct EvsEvent { +struct InfoEventDesc { /** * Type of an informative event */ - EvsEventType aType; + InfoEventType aType; /** * Possible additional information */ uint32_t[4] payload; }; +/** + * EVS event definition + */ +safe_union EvsEvent { + /** + * A buffer descriptor of an image frame + */ + BufferDesc buffer; + /** + * General streaming events + */ + InfoEventDesc info; +}; + /** * EVS Camera Parameter */ @@ -128,6 +126,14 @@ enum CameraParam : uint32_t { * Gain control */ GAIN, + /** + * Mirror the image horizontally + */ + HFLIP, + /** + * Mirror the image vertically + */ + VFLIP, /** * Automatic Whitebalance */ @@ -149,6 +155,11 @@ enum CameraParam : uint32_t { * Manual exposure time of the camera */ ABSOLUTE_EXPOSURE, + /** + * When AEC is running in either auto or aperture priority, this parameter + * sets whether a frame rate varies. + */ + AUTO_EXPOSURE_PRIORITY, /** * Set the focal point of the camera to the specified position. This * parameter may not be effective when auto focus is enabled. diff --git a/automotive/evs/1.1/vts/functional/Android.bp b/automotive/evs/1.1/vts/functional/Android.bp index 4753933f7f..55c50a42b8 100644 --- a/automotive/evs/1.1/vts/functional/Android.bp +++ b/automotive/evs/1.1/vts/functional/Android.bp @@ -23,7 +23,6 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], shared_libs: [ "libui", - "libcamera_metadata", ], static_libs: [ "android.hardware.automotive.evs@1.0", @@ -32,7 +31,6 @@ cc_test { "android.hardware.graphics.common@1.0", "android.hardware.graphics.common@1.1", "android.hardware.graphics.common@1.2", - "android.hardware.camera.device@3.2", ], test_suites: ["general-tests"], cflags: [ diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp index 6d53652f86..16276891f0 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp +++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp @@ -138,93 +138,93 @@ Return FrameHandler::deliverFrame(const BufferDesc_1_0& bufferArg) { } -Return FrameHandler::deliverFrame_1_1(const BufferDesc_1_1& bufDesc) { - const AHardwareBuffer_Desc* pDesc = - reinterpret_cast(&bufDesc.buffer.description); - ALOGD("Received a frame from the camera (%p)", - bufDesc.buffer.nativeHandle.getNativeHandle()); - - // Store a dimension of a received frame. - mFrameWidth = pDesc->width; - mFrameHeight = pDesc->height; - - // If we were given an opened display at construction time, then send the received - // image back down the camera. - if (mDisplay.get()) { - // Get the output buffer we'll use to display the imagery - BufferDesc_1_0 tgtBuffer = {}; - mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) { - tgtBuffer = buff; - } - ); - - if (tgtBuffer.memHandle == nullptr) { - printf("Didn't get target buffer - frame lost\n"); - ALOGE("Didn't get requested output buffer -- skipping this frame."); +Return FrameHandler::notifyEvent(const EvsEvent& event) { + // Local flag we use to keep track of when the stream is stopping + auto type = event.getDiscriminator(); + if (type == EvsEvent::hidl_discriminator::info) { + mLock.lock(); + mLatestEventDesc = event.info(); + if (mLatestEventDesc.aType == InfoEventType::STREAM_STOPPED) { + // Signal that the last frame has been received and the stream is stopped + mRunning = false; + } else if (mLatestEventDesc.aType == InfoEventType::PARAMETER_CHANGED) { + ALOGD("Camera parameter 0x%X is changed to 0x%X", + mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]); } else { - // Copy the contents of the of buffer.memHandle into tgtBuffer - copyBufferContents(tgtBuffer, bufDesc); + ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType)); + } + mLock.unlock(); + mEventSignal.notify_all(); + } else { + auto bufDesc = event.buffer(); + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&bufDesc.buffer.description); + ALOGD("Received a frame from the camera (%p)", + bufDesc.buffer.nativeHandle.getNativeHandle()); - // Send the target buffer back for display - Return result = mDisplay->returnTargetBufferForDisplay(tgtBuffer); - if (!result.isOk()) { - printf("HIDL error on display buffer (%s)- frame lost\n", - result.description().c_str()); - ALOGE("Error making the remote function call. HIDL said %s", - result.description().c_str()); - } else if (result != EvsResult::OK) { - printf("Display reported error - frame lost\n"); - ALOGE("We encountered error %d when returning a buffer to the display!", - (EvsResult) result); + // Store a dimension of a received frame. + mFrameWidth = pDesc->width; + mFrameHeight = pDesc->height; + + // If we were given an opened display at construction time, then send the received + // image back down the camera. + if (mDisplay.get()) { + // Get the output buffer we'll use to display the imagery + BufferDesc_1_0 tgtBuffer = {}; + mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) { + tgtBuffer = buff; + } + ); + + if (tgtBuffer.memHandle == nullptr) { + printf("Didn't get target buffer - frame lost\n"); + ALOGE("Didn't get requested output buffer -- skipping this frame."); } else { - // Everything looks good! - // Keep track so tests or watch dogs can monitor progress - mLock.lock(); - mFramesDisplayed++; - mLock.unlock(); + // Copy the contents of the of buffer.memHandle into tgtBuffer + copyBufferContents(tgtBuffer, bufDesc); + + // Send the target buffer back for display + Return result = mDisplay->returnTargetBufferForDisplay(tgtBuffer); + if (!result.isOk()) { + printf("HIDL error on display buffer (%s)- frame lost\n", + result.description().c_str()); + ALOGE("Error making the remote function call. HIDL said %s", + result.description().c_str()); + } else if (result != EvsResult::OK) { + printf("Display reported error - frame lost\n"); + ALOGE("We encountered error %d when returning a buffer to the display!", + (EvsResult) result); + } else { + // Everything looks good! + // Keep track so tests or watch dogs can monitor progress + mLock.lock(); + mFramesDisplayed++; + mLock.unlock(); + } } } + + + switch (mReturnMode) { + case eAutoReturn: + // Send the camera buffer back now that the client has seen it + ALOGD("Calling doneWithFrame"); + // TODO: Why is it that we get a HIDL crash if we pass back the cloned buffer? + mCamera->doneWithFrame_1_1(bufDesc); + break; + case eNoAutoReturn: + // Hang onto the buffer handle for now -- the client will return it explicitly later + mHeldBuffers.push(bufDesc); + } + + mLock.lock(); + ++mFramesReceived; + mLock.unlock(); + mFrameSignal.notify_all(); + + ALOGD("Frame handling complete"); } - - switch (mReturnMode) { - case eAutoReturn: - // Send the camera buffer back now that the client has seen it - ALOGD("Calling doneWithFrame"); - mCamera->doneWithFrame_1_1(bufDesc); - break; - case eNoAutoReturn: - // Hang onto the buffer handle for now -- the client will return it explicitly later - mHeldBuffers.push(bufDesc); - } - - mLock.lock(); - ++mFramesReceived; - mLock.unlock(); - mFrameSignal.notify_all(); - - ALOGD("Frame handling complete"); - - return Void(); -} - - -Return FrameHandler::notify(const EvsEvent& event) { - // Local flag we use to keep track of when the stream is stopping - mLock.lock(); - mLatestEventDesc = event; - if (mLatestEventDesc.aType == EvsEventType::STREAM_STOPPED) { - // Signal that the last frame has been received and the stream is stopped - mRunning = false; - } else if (mLatestEventDesc.aType == EvsEventType::PARAMETER_CHANGED) { - ALOGD("Camera parameter 0x%X is changed to 0x%X", - mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]); - } else { - ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType)); - } - mLock.unlock(); - mEventSignal.notify_all(); - return Void(); } @@ -342,18 +342,18 @@ void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) { } } -bool FrameHandler::waitForEvent(const EvsEventType aTargetEvent, - EvsEvent &event) { +bool FrameHandler::waitForEvent(const InfoEventType aTargetEvent, + InfoEventDesc &eventDesc) { // Wait until we get an expected parameter change event. std::unique_lock lock(mLock); auto now = std::chrono::system_clock::now(); bool result = mEventSignal.wait_until(lock, now + 5s, - [this, aTargetEvent, &event](){ + [this, aTargetEvent, &eventDesc](){ bool flag = mLatestEventDesc.aType == aTargetEvent; if (flag) { - event.aType = mLatestEventDesc.aType; - event.payload[0] = mLatestEventDesc.payload[0]; - event.payload[1] = mLatestEventDesc.payload[1]; + eventDesc.aType = mLatestEventDesc.aType; + eventDesc.payload[0] = mLatestEventDesc.payload[0]; + eventDesc.payload[1] = mLatestEventDesc.payload[1]; } return flag; @@ -363,22 +363,21 @@ bool FrameHandler::waitForEvent(const EvsEventType aTargetEvent, return !result; } -const char *FrameHandler::eventToString(const EvsEventType aType) { +const char *FrameHandler::eventToString(const InfoEventType aType) { switch (aType) { - case EvsEventType::STREAM_STARTED: + case InfoEventType::STREAM_STARTED: return "STREAM_STARTED"; - case EvsEventType::STREAM_STOPPED: + case InfoEventType::STREAM_STOPPED: return "STREAM_STOPPED"; - case EvsEventType::FRAME_DROPPED: + case InfoEventType::FRAME_DROPPED: return "FRAME_DROPPED"; - case EvsEventType::TIMEOUT: + case InfoEventType::TIMEOUT: return "TIMEOUT"; - case EvsEventType::PARAMETER_CHANGED: + case InfoEventType::PARAMETER_CHANGED: return "PARAMETER_CHANGED"; - case EvsEventType::MASTER_RELEASED: + case InfoEventType::MASTER_RELEASED: return "MASTER_RELEASED"; default: return "Unknown"; } } - diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h index e5f1b8f112..7f87cb4409 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.h +++ b/automotive/evs/1.1/vts/functional/FrameHandler.h @@ -33,6 +33,7 @@ using ::android::hardware::hidl_handle; using ::android::sp; using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; using ::android::hardware::automotive::evs::V1_0::EvsResult; +using ::android::hardware::automotive::evs::V1_0::CameraDesc; using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc; using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc; @@ -55,13 +56,6 @@ public: FrameHandler(android::sp pCamera, CameraDesc cameraInfo, android::sp pDisplay = nullptr, BufferControlFlag mode = eAutoReturn); - virtual ~FrameHandler() { - if (mCamera != nullptr) { - /* shutdown a camera explicitly */ - shutdown(); - } - } - void shutdown(); bool startStream(); @@ -73,22 +67,19 @@ public: bool isRunning(); void waitForFrameCount(unsigned frameCount); - bool waitForEvent(const EvsEventType aTargetEvent, - EvsEvent &eventDesc); + bool waitForEvent(const InfoEventType aTargetEvent, + InfoEventDesc &eventDesc); void getFramesCounters(unsigned* received, unsigned* displayed); void getFrameDimension(unsigned* width, unsigned* height); private: - // Implementation for ::android::hardware::automotive::evs::V1_0::IEvsCameraStream - Return deliverFrame(const BufferDesc_1_0& buffer) override; - // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream - Return deliverFrame_1_1(const BufferDesc_1_1& buffer) override; - Return notify(const EvsEvent& event) override; + Return deliverFrame(const BufferDesc_1_0& buffer) override; + Return notifyEvent(const EvsEvent& event) override; // Local implementation details bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer); - const char *eventToString(const EvsEventType aType); + const char *eventToString(const InfoEventType aType); // Values initialized as startup android::sp mCamera; @@ -109,7 +100,7 @@ private: unsigned mFramesDisplayed = 0; // Simple counter -- rolls over eventually! unsigned mFrameWidth = 0; unsigned mFrameHeight = 0; - EvsEvent mLatestEventDesc; + InfoEventDesc mLatestEventDesc; }; diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index 1d3fd87356..a6e4881d4d 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -38,9 +38,8 @@ static const float kNanoToSeconds = 0.000000001f; #include "FrameHandler.h" -#include -#include -#include +#include +#include #include #include @@ -51,10 +50,8 @@ static const float kNanoToSeconds = 0.000000001f; #include #include #include -#include +#include #include -#include -#include #include #include @@ -67,28 +64,13 @@ using ::android::hardware::hidl_vec; using ::android::hardware::hidl_handle; using ::android::hardware::hidl_string; using ::android::sp; -using ::android::hardware::camera::device::V3_2::Stream; +using ::android::hardware::automotive::evs::V1_0::CameraDesc; using ::android::hardware::automotive::evs::V1_0::DisplayDesc; using ::android::hardware::automotive::evs::V1_0::DisplayState; -using ::android::hardware::graphics::common::V1_0::PixelFormat; +using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator; using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera; using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera; -/* - * Plese note that this is different from what is defined in - * libhardware/modules/camera/3_4/metadata/types.h; this has one additional - * field to store a framerate. - */ -const size_t kStreamCfgSz = 5; -typedef struct { - int32_t width; - int32_t height; - int32_t format; - int32_t direction; - int32_t framerate; -} RawStreamConfig; - - // Test environment for Evs HIDL HAL. class EvsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: @@ -125,16 +107,15 @@ protected: assert(pEnumerator != nullptr); // Get the camera list - pEnumerator->getCameraList_1_1( - [this](hidl_vec cameraList) { - ALOGI("Camera list callback received %zu cameras", - cameraList.size()); - cameraInfo.reserve(cameraList.size()); - for (auto&& cam: cameraList) { - ALOGI("Found camera %s", cam.v1.cameraId.c_str()); - cameraInfo.push_back(cam); - } - } + pEnumerator->getCameraList([this](hidl_vec cameraList) { + ALOGI("Camera list callback received %zu cameras", + cameraList.size()); + cameraInfo.reserve(cameraList.size()); + for (auto&& cam: cameraList) { + ALOGI("Found camera %s", cam.cameraId.c_str()); + cameraInfo.push_back(cam); + } + } ); // We insist on at least one camera for EVS to pass any camera tests @@ -162,23 +143,19 @@ TEST_F(EvsHidlTest, CameraOpenClean) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Open and close each camera twice for (auto&& cam: cameraInfo) { for (int pass = 0; pass < 2; pass++) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); // Verify that this camera self-identifies correctly - pCam->getCameraInfo_1_1([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.v1.cameraId.c_str()); - EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); - } + pCam->getCameraInfo([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.cameraId.c_str()); + EXPECT_EQ(cam.cameraId, desc.cameraId); + } ); // Explicitly close the camera so resources are released right away @@ -200,26 +177,22 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Open and close each camera twice for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); // Verify that this camera self-identifies correctly - pCam->getCameraInfo_1_1([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.v1.cameraId.c_str()); - EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); - } + pCam->getCameraInfo([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.cameraId.c_str()); + EXPECT_EQ(cam.cameraId, desc.cameraId); + } ); sp pCam2 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam, pCam2); ASSERT_NE(pCam2, nullptr); @@ -237,10 +210,10 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { pEnumerator->closeCamera(pCam); // Verify that the second camera instance self-identifies correctly - pCam2->getCameraInfo_1_1([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.v1.cameraId.c_str()); - EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); - } + pCam2->getCameraInfo([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.cameraId.c_str()); + EXPECT_EQ(cam.cameraId, desc.cameraId); + } ); // Close the second camera instance @@ -262,14 +235,10 @@ TEST_F(EvsHidlTest, CameraStreamPerformance) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); @@ -334,15 +303,11 @@ TEST_F(EvsHidlTest, CameraStreamBuffering) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); @@ -406,10 +371,6 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Request exclusive access to the EVS display sp pDisplay = pEnumerator->openDisplay(); ASSERT_NE(pDisplay, nullptr); @@ -417,7 +378,7 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { // Test each reported camera for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); @@ -478,20 +439,16 @@ TEST_F(EvsHidlTest, MultiCameraStream) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera for (auto&& cam: cameraInfo) { // Create two camera clients. sp pCam0 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam0, nullptr); sp pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam1, nullptr); @@ -529,6 +486,7 @@ TEST_F(EvsHidlTest, MultiCameraStream) { nsecs_t runTime = end - firstFrame; float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds); float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds); + printf("Measured camera rate %3.2f fps and %3.2f fps\n", framesPerSecond0, framesPerSecond1); ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1); EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond); EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond); @@ -568,33 +526,14 @@ TEST_F(EvsHidlTest, CameraParameter) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera - Return result = EvsResult::OK; for (auto&& cam: cameraInfo) { // Create a camera client sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); - // Get the parameter list - std::vector cmds; - pCam->getParameterList([&cmds](hidl_vec cmdList) { - cmds.reserve(cmdList.size()); - for (auto &&cmd : cmdList) { - cmds.push_back(cmd); - } - } - ); - - if (cmds.size() < 1) { - continue; - } - // Set up per-client frame receiver objects which will fire up its own thread sp frameHandler = new FrameHandler(pCam, cam, nullptr, @@ -608,70 +547,83 @@ TEST_F(EvsHidlTest, CameraParameter) { // Ensure the stream starts frameHandler->waitForFrameCount(1); + // Try to program few parameters + EvsResult result = EvsResult::OK; + int32_t val0 = 100; + int32_t val1 = 0; + result = pCam->setMaster(); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK); - for (auto &cmd : cmds) { - // Get a valid parameter value range - int32_t minVal, maxVal, step; - pCam->getIntParameterRange( - cmd, - [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { - minVal = val0; - maxVal = val1; - step = val2; - } - ); + pCam->setParameter(CameraParam::BRIGHTNESS, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); - EvsResult result = EvsResult::OK; - if (cmd == CameraParam::ABSOLUTE_FOCUS) { - // Try to turn off auto-focus - int32_t val1 = 0; - pCam->getIntParameter(CameraParam::AUTO_FOCUS, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - if (val1 != 0) { - pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val1, 0); - } - } - - // Try to program a parameter with a random value [minVal, maxVal] - int32_t val0 = minVal + (std::rand() % (maxVal - minVal)); - int32_t val1 = 0; - - // Rounding down - val0 = val0 - (val0 % step); - pCam->setIntParameter(cmd, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - - ASSERT_EQ(EvsResult::OK, result); - - pCam->getIntParameter(cmd, + if (result == EvsResult::OK) { + pCam->getParameter(CameraParam::BRIGHTNESS, [&result, &val1](auto status, auto value) { result = status; if (status == EvsResult::OK) { val1 = value; } }); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + ASSERT_EQ(val0, val1) << "Values are not matched."; + } + + val0 = 80; + val1 = 0; + pCam->setParameter(CameraParam::CONTRAST, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + + if (result == EvsResult::OK) { + pCam->getParameter(CameraParam::CONTRAST, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + ASSERT_EQ(val0, val1) << "Values are not matched."; + } + + val0 = 300; + val1 = 0; + pCam->setParameter(CameraParam::ABSOLUTE_ZOOM, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + + if (result == EvsResult::OK) { + pCam->getParameter(CameraParam::ABSOLUTE_ZOOM, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); ASSERT_EQ(val0, val1) << "Values are not matched."; } result = pCam->unsetMaster(); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK); // Shutdown frameHandler->shutdown(); @@ -698,19 +650,15 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera for (auto&& cam: cameraInfo) { // Create two camera clients. sp pCamMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCamMaster, nullptr); sp pCamNonMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCamNonMaster, nullptr); @@ -750,15 +698,15 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { // Non-master client expects to receive a master role relesed // notification. - EvsEvent aNotification = {}; + InfoEventDesc aNotification = {}; // Release a master role. pCamMaster->unsetMaster(); // Verify a change notification. - frameHandlerNonMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); - ASSERT_EQ(EvsEventType::MASTER_RELEASED, - static_cast(aNotification.aType)); + frameHandlerNonMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(InfoEventType::MASTER_RELEASED, + static_cast(aNotification.aType)); // Non-master becomes a master. result = pCamNonMaster->setMaster(); @@ -772,9 +720,9 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { frameHandlerNonMaster->shutdown(); // Verify a change notification. - frameHandlerMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); - ASSERT_EQ(EvsEventType::MASTER_RELEASED, - static_cast(aNotification.aType)); + frameHandlerMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(InfoEventType::MASTER_RELEASED, + static_cast(aNotification.aType)); // Closing another stream. frameHandlerMaster->shutdown(); @@ -804,46 +752,18 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera for (auto&& cam: cameraInfo) { // Create two camera clients. sp pCamMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCamMaster, nullptr); sp pCamNonMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCamNonMaster, nullptr); - // Get the parameter list - std::vector camMasterCmds, camNonMasterCmds; - pCamMaster->getParameterList([&camMasterCmds](hidl_vec cmdList) { - camMasterCmds.reserve(cmdList.size()); - for (auto &&cmd : cmdList) { - camMasterCmds.push_back(cmd); - } - } - ); - - pCamNonMaster->getParameterList([&camNonMasterCmds](hidl_vec cmdList) { - camNonMasterCmds.reserve(cmdList.size()); - for (auto &&cmd : cmdList) { - camNonMasterCmds.push_back(cmd); - } - } - ); - - if (camMasterCmds.size() < 1 || - camNonMasterCmds.size() < 1) { - // Skip a camera device if it does not support any parameter. - continue; - } - // Set up per-client frame receiver objects which will fire up its own thread sp frameHandlerMaster = new FrameHandler(pCamMaster, cam, @@ -858,11 +778,11 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Set one client as the master EvsResult result = pCamMaster->setMaster(); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK); // Try to set another client as the master. result = pCamNonMaster->setMaster(); - ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result); + ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST); // Start the camera's video stream via a master client. bool startResult = frameHandlerMaster->startStream(); @@ -878,168 +798,131 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Ensure the stream starts frameHandlerNonMaster->waitForFrameCount(1); - int32_t val0 = 0; + // Try to program CameraParam::BRIGHTNESS + int32_t val0 = 100; int32_t val1 = 0; - for (auto &cmd : camMasterCmds) { - // Get a valid parameter value range - int32_t minVal, maxVal, step; - pCamMaster->getIntParameterRange( - cmd, - [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { - minVal = val0; - maxVal = val1; - step = val2; - } - ); - EvsResult result = EvsResult::OK; - if (cmd == CameraParam::ABSOLUTE_FOCUS) { - // Try to turn off auto-focus - int32_t val1 = 1; - pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val1, 0); - } + pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program + result == EvsResult::INVALID_ARG); // Camera parameter is not supported - // Try to program a parameter - val0 = minVal + (std::rand() % (maxVal - minVal)); + // Non-master client expects to receive a parameter change notification + // whenever a master client adjusts it. + InfoEventDesc aNotification = {}; - // Rounding down - val0 = val0 - (val0 % step); - pCamMaster->setIntParameter(cmd, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); + pCamMaster->getParameter(CameraParam::BRIGHTNESS, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program + result == EvsResult::INVALID_ARG); // Camera parameter is not supported + if (result == EvsResult::OK) { + ASSERT_EQ(val0, val1) << "Values are not matched."; - // Wait a moment - sleep(1); + // Verify a change notification + frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); + ASSERT_EQ(InfoEventType::PARAMETER_CHANGED, + static_cast(aNotification.aType)); + ASSERT_EQ(CameraParam::BRIGHTNESS, + static_cast(aNotification.payload[0])); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); + } - // Non-master client expects to receive a parameter change notification - // whenever a master client adjusts it. - EvsEvent aNotification = {}; + // Try to program CameraParam::CONTRAST + val0 = 80; + val1 = 0; + pCamMaster->setParameter(CameraParam::CONTRAST, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program + result == EvsResult::INVALID_ARG); // Camera parameter is not supported - pCamMaster->getIntParameter(cmd, + if (result == EvsResult::OK) { + pCamMaster->getParameter(CameraParam::CONTRAST, [&result, &val1](auto status, auto value) { result = status; if (status == EvsResult::OK) { val1 = value; } }); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK); ASSERT_EQ(val0, val1) << "Values are not matched."; + // Verify a change notification - frameHandlerNonMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); - ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, - static_cast(aNotification.aType)); - ASSERT_EQ(cmd, + frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); + ASSERT_EQ(InfoEventType::PARAMETER_CHANGED, + static_cast(aNotification.aType)); + ASSERT_EQ(CameraParam::CONTRAST, static_cast(aNotification.payload[0])); ASSERT_EQ(val1, static_cast(aNotification.payload[1])); } // Try to adjust a parameter via non-master client - pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0, + pCamNonMaster->setParameter(CameraParam::CONTRAST, val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_EQ(EvsResult::INVALID_ARG, result); + ASSERT_TRUE(result == EvsResult::INVALID_ARG); // Non-master client attemps to be a master result = pCamNonMaster->setMaster(); - ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result); + ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST); // Master client retires from a master role result = pCamMaster->unsetMaster(); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK); // Try to adjust a parameter after being retired - pCamMaster->setIntParameter(camMasterCmds[0], val0, + pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_EQ(EvsResult::INVALID_ARG, result); + ASSERT_TRUE(result == EvsResult::INVALID_ARG); // Non-master client becomes a master result = pCamNonMaster->setMaster(); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK); // Try to adjust a parameter via new master client - for (auto &cmd : camNonMasterCmds) { - // Get a valid parameter value range - int32_t minVal, maxVal, step; - pCamNonMaster->getIntParameterRange( - cmd, - [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { - minVal = val0; - maxVal = val1; - step = val2; - } - ); + pCamNonMaster->setParameter(CameraParam::BRIGHTNESS, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program + result == EvsResult::INVALID_ARG); // Camera parameter is not supported - EvsResult result = EvsResult::OK; - if (cmd == CameraParam::ABSOLUTE_FOCUS) { - // Try to turn off auto-focus - int32_t val1 = 1; - pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val1, 0); - } + // Wait a moment + sleep(1); - // Try to program a parameter - val0 = minVal + (std::rand() % (maxVal - minVal)); - - // Rounding down - val0 = val0 - (val0 % step); - pCamNonMaster->setIntParameter(cmd, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - - // Wait a moment - sleep(1); - - // Non-master client expects to receive a parameter change notification - // whenever a master client adjusts it. - EvsEvent aNotification = {}; - - pCamNonMaster->getIntParameter(cmd, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val0, val1) << "Values are not matched."; - - // Verify a change notification - frameHandlerMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); - ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, - static_cast(aNotification.aType)); - ASSERT_EQ(cmd, - static_cast(aNotification.payload[0])); + // Verify a change notification + if (result == EvsResult::OK) { + frameHandlerMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); + ASSERT_EQ(static_cast(aNotification.aType), + InfoEventType::PARAMETER_CHANGED); + ASSERT_EQ(static_cast(aNotification.payload[0]), + CameraParam::BRIGHTNESS); ASSERT_EQ(val1, static_cast(aNotification.payload[1])); } // New master retires from a master role result = pCamNonMaster->unsetMaster(); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK); // Shutdown frameHandlerMaster->shutdown(); @@ -1060,18 +943,9 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { TEST_F(EvsHidlTest, HighPriorityCameraClient) { ALOGI("Starting HighPriorityCameraClient test"); - if (mIsHwModule) { - // This test is not for HW module implementation. - return; - } - // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Request exclusive access to the EVS display sp pDisplay = pEnumerator->openDisplay(); ASSERT_NE(pDisplay, nullptr); @@ -1080,38 +954,15 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { for (auto&& cam: cameraInfo) { // Create two clients sp pCam0 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam0, nullptr); sp pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) .withDefault(nullptr); ASSERT_NE(pCam1, nullptr); - // Get the parameter list; this test will use the first command in both - // lists. - std::vector cam0Cmds, cam1Cmds; - pCam0->getParameterList([&cam0Cmds](hidl_vec cmdList) { - cam0Cmds.reserve(cmdList.size()); - for (auto &&cmd : cmdList) { - cam0Cmds.push_back(cmd); - } - } - ); - - pCam1->getParameterList([&cam1Cmds](hidl_vec cmdList) { - cam1Cmds.reserve(cmdList.size()); - for (auto &&cmd : cmdList) { - cam1Cmds.push_back(cmd); - } - } - ); - if (cam0Cmds.size() < 1 || cam1Cmds.size() < 1) { - // Cannot execute this test. - return; - } - // Set up a frame receiver object which will fire up its own thread. sp frameHandler0 = new FrameHandler(pCam0, cam, pDisplay, @@ -1131,121 +982,67 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { frameHandler0->waitForFrameCount(1); frameHandler1->waitForFrameCount(1); - // Client 1 becomes a master and programs a parameter. + // Client 1 becomes a master and programs a brightness. EvsResult result = EvsResult::OK; - // Get a valid parameter value range - int32_t minVal, maxVal, step; - pCam1->getIntParameterRange( - cam1Cmds[0], - [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { - minVal = val0; - maxVal = val1; - step = val2; - } - ); - - if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) { - // Try to turn off auto-focus - int32_t val1 = 0; - pCam1->getIntParameter(CameraParam::AUTO_FOCUS, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - if (val1 != 0) { - pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val1, 0); - } - } - - // Try to program a parameter with a random value [minVal, maxVal] - int32_t val0 = minVal + (std::rand() % (maxVal - minVal)); + int32_t val0 = 100; int32_t val1 = 0; - // Rounding down - val0 = val0 - (val0 % step); - result = pCam1->setMaster(); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK); - pCam1->setIntParameter(cam1Cmds[0], val0, + pCam1->setParameter(CameraParam::BRIGHTNESS, val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); + // Verify a change notification - EvsEvent aNotification = {}; - bool timeout = - frameHandler0->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); - ASSERT_FALSE(timeout) << "Expected event does not arrive"; - ASSERT_EQ(static_cast(aNotification.aType), - EvsEventType::PARAMETER_CHANGED); - ASSERT_EQ(static_cast(aNotification.payload[0]), - cam1Cmds[0]); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); + InfoEventDesc aNotification = {}; + if (result == EvsResult::OK) { + bool timeout = + frameHandler0->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); + ASSERT_FALSE(timeout) << "Expected event does not arrive"; + ASSERT_EQ(static_cast(aNotification.aType), + InfoEventType::PARAMETER_CHANGED); + ASSERT_EQ(static_cast(aNotification.payload[0]), + CameraParam::BRIGHTNESS); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); + } // Client 0 steals a master role ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay)); - frameHandler1->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); - ASSERT_EQ(static_cast(aNotification.aType), - EvsEventType::MASTER_RELEASED); + frameHandler1->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(static_cast(aNotification.aType), + InfoEventType::MASTER_RELEASED); - // Client 0 programs a parameter - val0 = minVal + (std::rand() % (maxVal - minVal)); + // Client 0 programs a brightness + val0 = 50; val1 = 0; - - // Rounding down - val0 = val0 - (val0 % step); - - if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) { - // Try to turn off auto-focus - int32_t val1 = 0; - pCam0->getIntParameter(CameraParam::AUTO_FOCUS, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - if (val1 != 0) { - pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val1, 0); - } - } - - pCam0->setIntParameter(cam0Cmds[0], val0, + pCam0->setParameter(CameraParam::BRIGHTNESS, val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_EQ(EvsResult::OK, result); + ASSERT_TRUE(result == EvsResult::OK || + result == EvsResult::INVALID_ARG); // Verify a change notification - timeout = - frameHandler1->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); - ASSERT_FALSE(timeout) << "Expected event does not arrive"; - ASSERT_EQ(static_cast(aNotification.aType), - EvsEventType::PARAMETER_CHANGED); - ASSERT_EQ(static_cast(aNotification.payload[0]), - cam0Cmds[0]); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); + if (result == EvsResult::OK) { + bool timeout = + frameHandler1->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); + ASSERT_FALSE(timeout) << "Expected event does not arrive"; + ASSERT_EQ(static_cast(aNotification.aType), + InfoEventType::PARAMETER_CHANGED); + ASSERT_EQ(static_cast(aNotification.payload[0]), + CameraParam::BRIGHTNESS); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); + } // Turn off the display (yes, before the stream stops -- it should be handled) pDisplay->setDisplayState(DisplayState::NOT_VISIBLE); @@ -1264,248 +1061,6 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { } -/* - * CameraUseStreamConfigToDisplay: - * End to end test of data flowing from the camera to the display. Similar to - * CameraToDisplayRoundTrip test case but this case retrieves available stream - * configurations from EVS and uses one of them to start a video stream. - */ -TEST_F(EvsHidlTest, CameraUseStreamConfigToDisplay) { - ALOGI("Starting CameraUseStreamConfigToDisplay test"); - - // Get the camera list - loadCameraList(); - - // Request exclusive access to the EVS display - sp pDisplay = pEnumerator->openDisplay(); - ASSERT_NE(pDisplay, nullptr); - - // Test each reported camera - for (auto&& cam: cameraInfo) { - // choose a configuration that has a frame rate faster than minReqFps. - Stream targetCfg = {}; - const int32_t minReqFps = 15; - int32_t maxArea = 0; - camera_metadata_entry_t streamCfgs; - bool foundCfg = false; - if (!find_camera_metadata_entry( - reinterpret_cast(cam.metadata.data()), - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, - &streamCfgs)) { - // Stream configurations are found in metadata - RawStreamConfig *ptr = reinterpret_cast(streamCfgs.data.i32); - for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) { - if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && - ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) { - - if (ptr->width * ptr->height > maxArea && - ptr->framerate >= minReqFps) { - targetCfg.width = ptr->width; - targetCfg.height = ptr->height; - - maxArea = ptr->width * ptr->height; - foundCfg = true; - } - } - ++ptr; - } - } - targetCfg.format = - static_cast(HAL_PIXEL_FORMAT_RGBA_8888); - - if (!foundCfg) { - // Current EVS camera does not provide stream configurations in the - // metadata. - continue; - } - - sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) - .withDefault(nullptr); - ASSERT_NE(pCam, nullptr); - - // Set up a frame receiver object which will fire up its own thread. - sp frameHandler = new FrameHandler(pCam, cam, - pDisplay, - FrameHandler::eAutoReturn); - - - // Activate the display - pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME); - - // Start the camera's video stream - bool startResult = frameHandler->startStream(); - ASSERT_TRUE(startResult); - - // Wait a while to let the data flow - static const int kSecondsToWait = 5; - const int streamTimeMs = kSecondsToWait * kSecondsToMilliseconds - - kMaxStreamStartMilliseconds; - const unsigned minimumFramesExpected = streamTimeMs * kMinimumFramesPerSecond / - kSecondsToMilliseconds; - sleep(kSecondsToWait); - unsigned framesReceived = 0; - unsigned framesDisplayed = 0; - frameHandler->getFramesCounters(&framesReceived, &framesDisplayed); - EXPECT_EQ(framesReceived, framesDisplayed); - EXPECT_GE(framesDisplayed, minimumFramesExpected); - - // Turn off the display (yes, before the stream stops -- it should be handled) - pDisplay->setDisplayState(DisplayState::NOT_VISIBLE); - - // Shut down the streamer - frameHandler->shutdown(); - - // Explicitly release the camera - pEnumerator->closeCamera(pCam); - } - - // Explicitly release the display - pEnumerator->closeDisplay(pDisplay); -} - - -/* - * MultiCameraStreamUseConfig: - * Verify that each client can start and stop video streams on the same - * underlying camera with same configuration. - */ -TEST_F(EvsHidlTest, MultiCameraStreamUseConfig) { - ALOGI("Starting MultiCameraStream test"); - - if (mIsHwModule) { - // This test is not for HW module implementation. - return; - } - - // Get the camera list - loadCameraList(); - - // Test each reported camera - for (auto&& cam: cameraInfo) { - // choose a configuration that has a frame rate faster than minReqFps. - Stream targetCfg = {}; - const int32_t minReqFps = 15; - int32_t maxArea = 0; - camera_metadata_entry_t streamCfgs; - bool foundCfg = false; - if (!find_camera_metadata_entry( - reinterpret_cast(cam.metadata.data()), - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, - &streamCfgs)) { - // Stream configurations are found in metadata - RawStreamConfig *ptr = reinterpret_cast(streamCfgs.data.i32); - for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) { - if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && - ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) { - - if (ptr->width * ptr->height > maxArea && - ptr->framerate >= minReqFps) { - targetCfg.width = ptr->width; - targetCfg.height = ptr->height; - - maxArea = ptr->width * ptr->height; - foundCfg = true; - } - } - ++ptr; - } - } - targetCfg.format = - static_cast(HAL_PIXEL_FORMAT_RGBA_8888); - - if (!foundCfg) { - ALOGI("Device %s does not provide a list of supported stream configurations, skipped", - cam.v1.cameraId.c_str()); - - continue; - } - - // Create the first camera client with a selected stream configuration. - sp pCam0 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) - .withDefault(nullptr); - ASSERT_NE(pCam0, nullptr); - - // Try to create the second camera client with different stream - // configuration. - int32_t id = targetCfg.id; - targetCfg.id += 1; // EVS manager sees only the stream id. - sp pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) - .withDefault(nullptr); - ASSERT_EQ(pCam1, nullptr); - - // Try again with same stream configuration. - targetCfg.id = id; - pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) - .withDefault(nullptr); - ASSERT_NE(pCam1, nullptr); - - // Set up per-client frame receiver objects which will fire up its own thread - sp frameHandler0 = new FrameHandler(pCam0, cam, - nullptr, - FrameHandler::eAutoReturn); - ASSERT_NE(frameHandler0, nullptr); - - sp frameHandler1 = new FrameHandler(pCam1, cam, - nullptr, - FrameHandler::eAutoReturn); - ASSERT_NE(frameHandler1, nullptr); - - // Start the camera's video stream via client 0 - bool startResult = false; - startResult = frameHandler0->startStream() && - frameHandler1->startStream(); - ASSERT_TRUE(startResult); - - // Ensure the stream starts - frameHandler0->waitForFrameCount(1); - frameHandler1->waitForFrameCount(1); - - nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC); - - // Wait a bit, then ensure both clients get at least the required minimum number of frames - sleep(5); - nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC); - unsigned framesReceived0 = 0, framesReceived1 = 0; - frameHandler0->getFramesCounters(&framesReceived0, nullptr); - frameHandler1->getFramesCounters(&framesReceived1, nullptr); - framesReceived0 = framesReceived0 - 1; // Back out the first frame we already waited for - framesReceived1 = framesReceived1 - 1; // Back out the first frame we already waited for - nsecs_t runTime = end - firstFrame; - float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds); - float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds); - ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1); - EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond); - EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond); - - // Shutdown one client - frameHandler0->shutdown(); - - // Read frame counters again - frameHandler0->getFramesCounters(&framesReceived0, nullptr); - frameHandler1->getFramesCounters(&framesReceived1, nullptr); - - // Wait a bit again - sleep(5); - unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0; - frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr); - frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr); - EXPECT_EQ(framesReceived0, framesReceivedAfterStop0); - EXPECT_LT(framesReceived1, framesReceivedAfterStop1); - - // Shutdown another - frameHandler1->shutdown(); - - // Explicitly release the camera - pEnumerator->closeCamera(pCam0); - pEnumerator->closeCamera(pCam1); - } -} - - int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance()); ::testing::InitGoogleTest(&argc, argv); From c6fa0abf516f32cd12af20e6d61a9266d589bde6 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Sat, 12 Oct 2019 05:25:44 -0700 Subject: [PATCH 0179/1022] Revert "Revert "Revert "Revert "Extend EVS interfaces and data types"""" This reverts commit 468cc1d476ae4a78787e0730cac8cf53e1806ed1. Change-Id: If7e80111213ba02bf2c49f17f9880cd9cd14429e --- automotive/evs/1.1/Android.bp | 4 +- automotive/evs/1.1/IEvsCamera.hal | 34 +- automotive/evs/1.1/IEvsCameraStream.hal | 19 +- automotive/evs/1.1/IEvsEnumerator.hal | 50 + automotive/evs/1.1/default/Android.bp | 20 +- automotive/evs/1.1/default/ConfigManager.cpp | 487 ++++++++++ automotive/evs/1.1/default/ConfigManager.h | 336 +++++++ .../evs/1.1/default/ConfigManagerUtil.cpp | 131 +++ .../evs/1.1/default/ConfigManagerUtil.h | 61 ++ automotive/evs/1.1/default/EvsCamera.cpp | 108 ++- automotive/evs/1.1/default/EvsCamera.h | 28 +- automotive/evs/1.1/default/EvsEnumerator.cpp | 109 ++- automotive/evs/1.1/default/EvsEnumerator.h | 25 +- .../resources/evs_default_configuration.xml | 68 ++ automotive/evs/1.1/default/service.cpp | 2 +- automotive/evs/1.1/types.hal | 49 +- automotive/evs/1.1/vts/functional/Android.bp | 2 + .../evs/1.1/vts/functional/FrameHandler.cpp | 187 ++-- .../evs/1.1/vts/functional/FrameHandler.h | 23 +- .../functional/VtsHalEvsV1_1TargetTest.cpp | 901 +++++++++++++----- 20 files changed, 2230 insertions(+), 414 deletions(-) create mode 100644 automotive/evs/1.1/IEvsEnumerator.hal create mode 100644 automotive/evs/1.1/default/ConfigManager.cpp create mode 100644 automotive/evs/1.1/default/ConfigManager.h create mode 100644 automotive/evs/1.1/default/ConfigManagerUtil.cpp create mode 100644 automotive/evs/1.1/default/ConfigManagerUtil.h create mode 100644 automotive/evs/1.1/default/resources/evs_default_configuration.xml diff --git a/automotive/evs/1.1/Android.bp b/automotive/evs/1.1/Android.bp index d2e85f1304..c850c91b21 100644 --- a/automotive/evs/1.1/Android.bp +++ b/automotive/evs/1.1/Android.bp @@ -10,13 +10,15 @@ hidl_interface { "types.hal", "IEvsCamera.hal", "IEvsCameraStream.hal", + "IEvsEnumerator.hal", ], interfaces: [ "android.hardware.automotive.evs@1.0", + "android.hardware.camera.device@3.2", "android.hardware.graphics.common@1.0", "android.hardware.graphics.common@1.1", "android.hardware.graphics.common@1.2", "android.hidl.base@1.0", ], - gen_java: true, + gen_java: false, } diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal index 21ca79e91f..975b6c6cae 100644 --- a/automotive/evs/1.1/IEvsCamera.hal +++ b/automotive/evs/1.1/IEvsCamera.hal @@ -25,6 +25,14 @@ import IEvsCameraStream; * Represents a single camera and is the primary interface for capturing images. */ interface IEvsCamera extends @1.0::IEvsCamera { + /** + * Returns the description of this camera. + * + * @return info The description of this camera. This must be the same value as + * reported by EvsEnumerator::getCameraList_1_1(). + */ + getCameraInfo_1_1() generates (CameraDesc info); + /** * Requests to pause EVS camera stream events. * @@ -100,7 +108,27 @@ interface IEvsCamera extends @1.0::IEvsCamera { unsetMaster() generates (EvsResult result); /** - * Requests to set a camera parameter. + * Retrieves a list of parameters this camera supports. + * + * @return params A list of CameraParam that this camera supports. + */ + getParameterList() generates (vec params); + + /** + * Requests a valid value range of a camera parameter + * + * @param id The identifier of camera parameter, CameraParam enum. + * + * @return min The lower bound of valid parameter value range. + * @return max The upper bound of valid parameter value range. + * @return step The resolution of values in valid range. + */ + getIntParameterRange(CameraParam id) + generates (int32_t min, int32_t max, int32_t step); + + /** + * Requests to set a camera parameter. Only a request from the master + * client will be processed successfully. * * @param id The identifier of camera parameter, CameraParam enum. * value A desired parameter value. @@ -114,7 +142,7 @@ interface IEvsCamera extends @1.0::IEvsCamera { * from what the client gives if, for example, the * driver does not support a target parameter. */ - setParameter(CameraParam id, int32_t value) + setIntParameter(CameraParam id, int32_t value) generates (EvsResult result, int32_t effectiveValue); /** @@ -126,5 +154,5 @@ interface IEvsCamera extends @1.0::IEvsCamera { * not supported. * value A value of requested camera parameter. */ - getParameter(CameraParam id) generates(EvsResult result, int32_t value); + getIntParameter(CameraParam id) generates(EvsResult result, int32_t value); }; diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal index 7c7f832103..9e4ea19f1d 100644 --- a/automotive/evs/1.1/IEvsCameraStream.hal +++ b/automotive/evs/1.1/IEvsCameraStream.hal @@ -17,15 +17,32 @@ package android.hardware.automotive.evs@1.1; import @1.0::IEvsCameraStream; +import @1.1::BufferDesc; +import @1.1::EvsEvent; /** * Implemented on client side to receive asynchronous streaming event deliveries. */ interface IEvsCameraStream extends @1.0::IEvsCameraStream { + + /** + * Receives calls from the HAL each time a video frame is ready for inspection. + * Buffer handles received by this method must be returned via calls to + * IEvsCamera::doneWithFrame_1_1(). When the video stream is stopped via a call + * to IEvsCamera::stopVideoStream(), this callback may continue to happen for + * some time as the pipeline drains. Each frame must still be returned. + * When the last frame in the stream has been delivered, STREAM_STOPPED + * event must be delivered. No further frame deliveries may happen + * thereafter. + * + * @param buffer a buffer descriptor of a delivered image frame. + */ + oneway deliverFrame_1_1(BufferDesc buffer); + /** * Receives calls from the HAL each time an event happens. * * @param event EVS event with possible event information. */ - oneway notifyEvent(EvsEvent event); + oneway notify(EvsEvent event); }; diff --git a/automotive/evs/1.1/IEvsEnumerator.hal b/automotive/evs/1.1/IEvsEnumerator.hal new file mode 100644 index 0000000000..1695821baa --- /dev/null +++ b/automotive/evs/1.1/IEvsEnumerator.hal @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package android.hardware.automotive.evs@1.1; + +import IEvsCamera; +import @1.0::IEvsEnumerator; +import @1.0::EvsResult; +import android.hardware.camera.device@3.2::Stream; + +/** + * Provides the mechanism for EVS camera discovery + */ +interface IEvsEnumerator extends @1.0::IEvsEnumerator { + /** + * Returns a list of all EVS cameras available to the system + * + * @return cameras A list of cameras availale for EVS service. + */ + getCameraList_1_1() generates (vec cameras); + + /** + * Gets the IEvsCamera associated with a cameraId from a CameraDesc + * + * Given a camera's unique cameraId from CameraDesc, returns the + * IEvsCamera interface associated with the specified camera. When + * done using the camera, the caller may release it by calling closeCamera(). + * + * @param cameraId A unique identifier of the camera. + * @param streamCfg A stream configuration the client wants to use. + * @return evsCamera EvsCamera object associated with a given cameraId. + * Returned object would be null if a camera device does + * not support a given stream configuration or is already + * configured differently by another client. + */ + openCamera_1_1(string cameraId, Stream streamCfg) generates (IEvsCamera evsCamera); +}; diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp index a46347102f..41cb4265e5 100644 --- a/automotive/evs/1.1/default/Android.bp +++ b/automotive/evs/1.1/default/Android.bp @@ -7,25 +7,41 @@ cc_binary { "service.cpp", "EvsCamera.cpp", "EvsEnumerator.cpp", - "EvsDisplay.cpp" + "EvsDisplay.cpp", + "ConfigManager.cpp", + "ConfigManagerUtil.cpp", ], init_rc: ["android.hardware.automotive.evs@1.1-service.rc"], shared_libs: [ "android.hardware.automotive.evs@1.0", "android.hardware.automotive.evs@1.1", + "android.hardware.camera.device@3.2", "libbase", "libbinder", - "libcutils", + "liblog", "libhardware", "libhidlbase", "liblog", "libui", "libutils", + "libcamera_metadata", + "libtinyxml2", ], cflags: [ "-O0", "-g", ], + + required: [ + "evs_default_configuration.xml", + ], +} + +prebuilt_etc { + name: "evs_default_configuration.xml", + + src: "resources/evs_default_configuration.xml", + sub_dir: "automotive/evs", } diff --git a/automotive/evs/1.1/default/ConfigManager.cpp b/automotive/evs/1.1/default/ConfigManager.cpp new file mode 100644 index 0000000000..4f46f9dbca --- /dev/null +++ b/automotive/evs/1.1/default/ConfigManager.cpp @@ -0,0 +1,487 @@ +/* + * 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. + */ + +#include +#include +#include + +#include +#include +#include + +#include "ConfigManager.h" + +using ::android::hardware::camera::device::V3_2::StreamRotation; + + +ConfigManager::~ConfigManager() { + /* Nothing to do */ +} + + +void ConfigManager::readCameraInfo(const XMLElement * const aCameraElem) { + if (aCameraElem == nullptr) { + ALOGW("XML file does not have required camera element"); + return; + } + + const XMLElement *curElem = aCameraElem->FirstChildElement(); + while (curElem != nullptr) { + if (!strcmp(curElem->Name(), "group")) { + /* camera group identifier */ + const char *group_id = curElem->FindAttribute("group_id")->Value(); + + /* create CameraGroup */ + unique_ptr aCameraGroup(new ConfigManager::CameraGroup()); + + /* add a camera device to its group */ + addCameraDevices(curElem->FindAttribute("device_id")->Value(), aCameraGroup); + + /* a list of camera stream configurations */ + const XMLElement *childElem = + curElem->FirstChildElement("caps")->FirstChildElement("stream"); + while (childElem != nullptr) { + /* read 5 attributes */ + const XMLAttribute *idAttr = childElem->FindAttribute("id"); + const XMLAttribute *widthAttr = childElem->FindAttribute("width"); + const XMLAttribute *heightAttr = childElem->FindAttribute("height"); + const XMLAttribute *fmtAttr = childElem->FindAttribute("format"); + const XMLAttribute *fpsAttr = childElem->FindAttribute("framerate"); + + const int32_t id = stoi(idAttr->Value()); + int32_t framerate = 0; + if (fpsAttr != nullptr) { + framerate = stoi(fpsAttr->Value()); + } + + int32_t pixFormat; + if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), + pixFormat)) { + RawStreamConfiguration cfg = { + id, + stoi(widthAttr->Value()), + stoi(heightAttr->Value()), + pixFormat, + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, + framerate + }; + aCameraGroup->streamConfigurations[id] = cfg; + } + + childElem = childElem->NextSiblingElement("stream"); + } + + /* camera group synchronization */ + const char *sync = curElem->FindAttribute("synchronized")->Value(); + aCameraGroup->synchronized = + static_cast(strcmp(sync, "false")); + + /* add a group to hash map */ + mCameraGroups[group_id] = std::move(aCameraGroup); + } else if (!strcmp(curElem->Name(), "device")) { + /* camera unique identifier */ + const char *id = curElem->FindAttribute("id")->Value(); + + /* camera mount location */ + const char *pos = curElem->FindAttribute("position")->Value(); + + /* store read camera module information */ + mCameraInfo[id] = readCameraDeviceInfo(curElem); + + /* assign a camera device to a position group */ + mCameraPosition[pos].emplace(id); + } else { + /* ignore other device types */ + ALOGD("Unknown element %s is ignored", curElem->Name()); + } + + curElem = curElem->NextSiblingElement(); + } +} + + +unique_ptr +ConfigManager::readCameraDeviceInfo(const XMLElement *aDeviceElem) { + if (aDeviceElem == nullptr) { + return nullptr; + } + + /* create a CameraInfo to be filled */ + unique_ptr aCamera(new ConfigManager::CameraInfo()); + + /* size information to allocate camera_metadata_t */ + size_t totalEntries = 0; + size_t totalDataSize = 0; + + /* read device capabilities */ + totalEntries += + readCameraCapabilities(aDeviceElem->FirstChildElement("caps"), + aCamera, + totalDataSize); + + + /* read camera metadata */ + totalEntries += + readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"), + aCamera, + totalDataSize); + + /* construct camera_metadata_t */ + if (!constructCameraMetadata(aCamera, totalEntries, totalDataSize)) { + ALOGW("Either failed to allocate memory or " + "allocated memory was not large enough"); + } + + return aCamera; +} + + +size_t ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem, + unique_ptr &aCamera, + size_t &dataSize) { + if (aCapElem == nullptr) { + return 0; + } + + string token; + const XMLElement *curElem = nullptr; + + /* a list of supported camera parameters/controls */ + curElem = aCapElem->FirstChildElement("supported_controls"); + if (curElem != nullptr) { + const XMLElement *ctrlElem = curElem->FirstChildElement("control"); + while (ctrlElem != nullptr) { + const char *nameAttr = ctrlElem->FindAttribute("name")->Value();; + const int32_t minVal = stoi(ctrlElem->FindAttribute("min")->Value()); + const int32_t maxVal = stoi(ctrlElem->FindAttribute("max")->Value()); + + int32_t stepVal = 1; + const XMLAttribute *stepAttr = ctrlElem->FindAttribute("step"); + if (stepAttr != nullptr) { + stepVal = stoi(stepAttr->Value()); + } + + CameraParam aParam; + if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr, + aParam)) { + aCamera->controls.emplace( + aParam, + make_tuple(minVal, maxVal, stepVal) + ); + } + + ctrlElem = ctrlElem->NextSiblingElement("control"); + } + } + + /* a list of camera stream configurations */ + curElem = aCapElem->FirstChildElement("stream"); + while (curElem != nullptr) { + /* read 5 attributes */ + const XMLAttribute *idAttr = curElem->FindAttribute("id"); + const XMLAttribute *widthAttr = curElem->FindAttribute("width"); + const XMLAttribute *heightAttr = curElem->FindAttribute("height"); + const XMLAttribute *fmtAttr = curElem->FindAttribute("format"); + const XMLAttribute *fpsAttr = curElem->FindAttribute("framerate"); + + const int32_t id = stoi(idAttr->Value()); + int32_t framerate = 0; + if (fpsAttr != nullptr) { + framerate = stoi(fpsAttr->Value()); + } + + int32_t pixFormat; + if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), + pixFormat)) { + RawStreamConfiguration cfg = { + id, + stoi(widthAttr->Value()), + stoi(heightAttr->Value()), + pixFormat, + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, + framerate + }; + aCamera->streamConfigurations[id] = cfg; + } + + curElem = curElem->NextSiblingElement("stream"); + } + + dataSize = calculate_camera_metadata_entry_data_size( + get_camera_metadata_tag_type( + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS + ), + aCamera->streamConfigurations.size() * kStreamCfgSz + ); + + /* a single camera metadata entry contains multiple stream configurations */ + return dataSize > 0 ? 1 : 0; +} + + +size_t ConfigManager::readCameraMetadata(const XMLElement * const aParamElem, + unique_ptr &aCamera, + size_t &dataSize) { + if (aParamElem == nullptr) { + return 0; + } + + const XMLElement *curElem = aParamElem->FirstChildElement("parameter"); + size_t numEntries = 0; + camera_metadata_tag_t tag; + while (curElem != nullptr) { + if (!ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(), + tag)) { + switch(tag) { + case ANDROID_LENS_DISTORTION: + case ANDROID_LENS_POSE_ROTATION: + case ANDROID_LENS_POSE_TRANSLATION: + case ANDROID_LENS_INTRINSIC_CALIBRATION: { + /* float[] */ + size_t count = 0; + void *data = ConfigManagerUtil::convertFloatArray( + curElem->FindAttribute("size")->Value(), + curElem->FindAttribute("value")->Value(), + count + ); + + aCamera->cameraMetadata[tag] = + make_pair(make_unique(data), count); + + ++numEntries; + dataSize += calculate_camera_metadata_entry_data_size( + get_camera_metadata_tag_type(tag), count + ); + + break; + } + + default: + ALOGW("Parameter %s is not supported", + curElem->FindAttribute("name")->Value()); + break; + } + } + + curElem = curElem->NextSiblingElement("parameter"); + } + + return numEntries; +} + + +bool ConfigManager::constructCameraMetadata(unique_ptr &aCamera, + const size_t totalEntries, + const size_t totalDataSize) { + if (!aCamera->allocate(totalEntries, totalDataSize)) { + ALOGE("Failed to allocate memory for camera metadata"); + return false; + } + + const size_t numStreamConfigs = aCamera->streamConfigurations.size(); + unique_ptr data(new int32_t[kStreamCfgSz * numStreamConfigs]); + int32_t *ptr = data.get(); + for (auto &cfg : aCamera->streamConfigurations) { + for (auto i = 0; i < kStreamCfgSz; ++i) { + *ptr++ = cfg.second[i]; + } + } + int32_t err = add_camera_metadata_entry(aCamera->characteristics, + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, + data.get(), + numStreamConfigs * kStreamCfgSz); + + if (err) { + ALOGE("Failed to add stream configurations to metadata, ignored"); + return false; + } + + bool success = true; + for (auto &[tag, entry] : aCamera->cameraMetadata) { + /* try to add new camera metadata entry */ + int32_t err = add_camera_metadata_entry(aCamera->characteristics, + tag, + entry.first.get(), + entry.second); + if (err) { + ALOGE("Failed to add an entry with a tag 0x%X", tag); + + /* may exceed preallocated capacity */ + ALOGE("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled", + get_camera_metadata_entry_count(aCamera->characteristics), + get_camera_metadata_entry_capacity(aCamera->characteristics), + get_camera_metadata_data_count(aCamera->characteristics), + get_camera_metadata_data_capacity(aCamera->characteristics)); + ALOGE("\tCurrent metadata entry requires %ld bytes", + calculate_camera_metadata_entry_data_size(tag, entry.second)); + + success = false; + } + } + + ALOGV("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled", + get_camera_metadata_entry_count(aCamera->characteristics), + get_camera_metadata_entry_capacity(aCamera->characteristics), + get_camera_metadata_data_count(aCamera->characteristics), + get_camera_metadata_data_capacity(aCamera->characteristics)); + + return success; +} + + +void ConfigManager::readSystemInfo(const XMLElement * const aSysElem) { + if (aSysElem == nullptr) { + return; + } + + /* + * Please note that this function assumes that a given system XML element + * and its child elements follow DTD. If it does not, it will cause a + * segmentation fault due to the failure of finding expected attributes. + */ + + /* read number of cameras available in the system */ + const XMLElement *xmlElem = aSysElem->FirstChildElement("num_cameras"); + if (xmlElem != nullptr) { + mSystemInfo.numCameras = + stoi(xmlElem->FindAttribute("value")->Value()); + } +} + + +void ConfigManager::readDisplayInfo(const XMLElement * const aDisplayElem) { + if (aDisplayElem == nullptr) { + ALOGW("XML file does not have required camera element"); + return; + } + + const XMLElement *curDev = aDisplayElem->FirstChildElement("device"); + while (curDev != nullptr) { + const char *id = curDev->FindAttribute("id")->Value(); + //const char *pos = curDev->FirstAttribute("position")->Value(); + + unique_ptr dpy(new DisplayInfo()); + if (dpy == nullptr) { + ALOGE("Failed to allocate memory for DisplayInfo"); + return; + } + + const XMLElement *cap = curDev->FirstChildElement("caps"); + if (cap != nullptr) { + const XMLElement *curStream = cap->FirstChildElement("stream"); + while (curStream != nullptr) { + /* read 4 attributes */ + const XMLAttribute *idAttr = curStream->FindAttribute("id"); + const XMLAttribute *widthAttr = curStream->FindAttribute("width"); + const XMLAttribute *heightAttr = curStream->FindAttribute("height"); + const XMLAttribute *fmtAttr = curStream->FindAttribute("format"); + + const int32_t id = stoi(idAttr->Value()); + int32_t pixFormat; + if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), + pixFormat)) { + RawStreamConfiguration cfg = { + id, + stoi(widthAttr->Value()), + stoi(heightAttr->Value()), + pixFormat, + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT, + 0 // unused + }; + dpy->streamConfigurations[id] = cfg; + } + + curStream = curStream->NextSiblingElement("stream"); + } + } + + mDisplayInfo[id] = std::move(dpy); + curDev = curDev->NextSiblingElement("device"); + } + + return; +} + + +bool ConfigManager::readConfigDataFromXML() noexcept { + XMLDocument xmlDoc; + + const int64_t parsingStart = android::elapsedRealtimeNano(); + + /* load and parse a configuration file */ + xmlDoc.LoadFile(mConfigFilePath); + if (xmlDoc.ErrorID() != XML_SUCCESS) { + ALOGE("Failed to load and/or parse a configuration file, %s", xmlDoc.ErrorStr()); + return false; + } + + /* retrieve the root element */ + const XMLElement *rootElem = xmlDoc.RootElement(); + if (strcmp(rootElem->Name(), "configuration")) { + ALOGE("A configuration file is not in the required format. " + "See /etc/automotive/evs/evs_configuration.dtd"); + return false; + } + + /* + * parse camera information; this needs to be done before reading system + * information + */ + readCameraInfo(rootElem->FirstChildElement("camera")); + + /* parse system information */ + readSystemInfo(rootElem->FirstChildElement("system")); + + /* parse display information */ + readDisplayInfo(rootElem->FirstChildElement("display")); + + const int64_t parsingEnd = android::elapsedRealtimeNano(); + ALOGI("Parsing configuration file takes %lf (ms)", + (double)(parsingEnd - parsingStart) / 1000000.0); + + + return true; +} + + +void ConfigManager::addCameraDevices(const char *devices, + unique_ptr &aGroup) { + stringstream device_list(devices); + string token; + while (getline(device_list, token, ',')) { + aGroup->devices.emplace(token); + } +} + + +std::unique_ptr ConfigManager::Create(const char *path) { + unique_ptr cfgMgr(new ConfigManager(path)); + + /* + * Read a configuration from XML file + * + * If this is too slow, ConfigManager::readConfigDataFromBinary() and + * ConfigManager::writeConfigDataToBinary()can serialize CameraInfo object + * to the filesystem and construct CameraInfo instead; this was + * evaluated as 10x faster. + */ + if (!cfgMgr->readConfigDataFromXML()) { + return nullptr; + } else { + return cfgMgr; + } +} + diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h new file mode 100644 index 0000000000..0275f904e5 --- /dev/null +++ b/automotive/evs/1.1/default/ConfigManager.h @@ -0,0 +1,336 @@ +/* + * 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. + */ +#ifndef CONFIG_MANAGER_H +#define CONFIG_MANAGER_H + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "ConfigManagerUtil.h" + +using namespace std; +using namespace tinyxml2; + +using ::android::hardware::hidl_vec; +using ::android::hardware::camera::device::V3_2::Stream; +using ::android::hardware::automotive::evs::V1_1::CameraParam; + +/* + * Plese note that this is different from what is defined in + * libhardware/modules/camera/3_4/metadata/types.h; this has one additional + * field to store a framerate. + */ +const size_t kStreamCfgSz = 6; +typedef std::array RawStreamConfiguration; + +class ConfigManager { +public: + static std::unique_ptr Create(const char *path = ""); + ConfigManager(const ConfigManager&) = delete; + ConfigManager& operator=(const ConfigManager&) = delete; + + virtual ~ConfigManager(); + + /* Camera device's capabilities and metadata */ + class CameraInfo { + public: + CameraInfo() : + characteristics(nullptr) { + /* Nothing to do */ + } + + virtual ~CameraInfo() { + free_camera_metadata(characteristics); + } + + /* Allocate memory for camera_metadata_t */ + bool allocate(size_t entry_cap, size_t data_cap) { + if (characteristics != nullptr) { + ALOGE("Camera metadata is already allocated"); + return false; + } + + characteristics = allocate_camera_metadata(entry_cap, data_cap); + return characteristics != nullptr; + } + + /* + * List of supported controls that the master client can program. + * Paraemters are stored with its valid range + */ + unordered_map> controls; + + /* List of supported frame rates */ + unordered_set frameRates; + + /* + * List of supported output stream configurations; each array stores + * format, width, height, and direction values in the order. + */ + unordered_map streamConfigurations; + + /* + * Internal storage for camera metadata. Each entry holds a pointer to + * data and number of elements + */ + unordered_map, size_t>> cameraMetadata; + + /* Camera module characteristics */ + camera_metadata_t *characteristics; + }; + + class CameraGroup { + public: + CameraGroup() {} + + /* ID of member camera devices */ + unordered_set devices; + + /* The capture operation of member camera devices are synchronized */ + bool synchronized = false; + + /* + * List of stream configurations that are supposed by all camera devices + * in this group. + */ + unordered_map streamConfigurations; + }; + + class SystemInfo { + public: + /* number of available cameras */ + int32_t numCameras = 0; + }; + + class DisplayInfo { + public: + /* + * List of supported input stream configurations; each array stores + * format, width, height, and direction values in the order. + */ + unordered_map streamConfigurations; + }; + + /* + * Return system information + * + * @return SystemInfo + * Constant reference of SystemInfo. + */ + const SystemInfo &getSystemInfo() { + return mSystemInfo; + } + + /* + * Return a list of cameras + * + * This function assumes that it is not being called frequently. + * + * @return vector + * A vector that contains unique camera device identifiers. + */ + vector getCameraList() { + vector aList; + for (auto &v : mCameraInfo) { + aList.emplace_back(v.first); + } + + return aList; + } + + + /* + * Return a list of cameras + * + * @return CameraGroup + * A pointer to a camera group identified by a given id. + */ + unique_ptr& getCameraGroup(const string& gid) { + return mCameraGroups[gid]; + } + + + /* + * Return a camera metadata + * + * @param cameraId + * Unique camera node identifier in string + * + * @return unique_ptr + * A pointer to CameraInfo that is associated with a given camera + * ID. This returns a null pointer if this does not recognize a + * given camera identifier. + */ + unique_ptr& getCameraInfo(const string cameraId) noexcept { + return mCameraInfo[cameraId]; + } + +private: + /* Constructors */ + ConfigManager(const char *xmlPath) : + mConfigFilePath(xmlPath) { + } + + /* System configuration */ + SystemInfo mSystemInfo; + + /* Internal data structure for camera device information */ + unordered_map> mCameraInfo; + + /* Internal data structure for camera device information */ + unordered_map> mDisplayInfo; + + /* Camera groups are stored in hash map */ + unordered_map> mCameraGroups; + + /* + * Camera positions are stored in hash map. + * The position must be one of front, rear, left, and right. + */ + unordered_map> mCameraPosition; + + /* A path to XML configuration file */ + const char *mConfigFilePath; + + /* + * Parse a given EVS configuration file and store the information + * internally. + * + * @return bool + * True if it completes parsing a file successfully. + */ + bool readConfigDataFromXML() noexcept; + + /* + * read the information of the vehicle + * + * @param aSysElem + * A pointer to "system" XML element. + */ + void readSystemInfo(const XMLElement * const aSysElem); + + /* + * read the information of camera devices + * + * @param aCameraElem + * A pointer to "camera" XML element that may contain multiple + * "device" elements. + */ + void readCameraInfo(const XMLElement * const aCameraElem); + + /* + * read display device information + * + * @param aDisplayElem + * A pointer to "display" XML element that may contain multiple + * "device" elements. + */ + void readDisplayInfo(const XMLElement * const aDisplayElem); + + /* + * read camera device information + * + * @param aDeviceElem + * A pointer to "device" XML element that contains camera module + * capability info and its characteristics. + * + * @return unique_ptr + * A pointer to CameraInfo class that contains camera module + * capability and characteristics. Please note that this transfers + * the ownership of created CameraInfo to the caller. + */ + unique_ptr readCameraDeviceInfo(const XMLElement *aDeviceElem); + + /* + * read camera metadata + * + * @param aCapElem + * A pointer to "cap" XML element. + * @param aCamera + * A pointer to CameraInfo that is being filled by this method. + * @param dataSize + * Required size of memory to store camera metadata found in this + * method. This is calculated in this method and returned to the + * caller for camera_metadata allocation. + * + * @return size_t + * Number of camera metadata entries + */ + size_t readCameraCapabilities(const XMLElement * const aCapElem, + unique_ptr &aCamera, + size_t &dataSize); + + /* + * read camera metadata + * + * @param aParamElem + * A pointer to "characteristics" XML element. + * @param aCamera + * A pointer to CameraInfo that is being filled by this method. + * @param dataSize + * Required size of memory to store camera metadata found in this + * method. + * + * @return size_t + * Number of camera metadata entries + */ + size_t readCameraMetadata(const XMLElement * const aParamElem, + unique_ptr &aCamera, + size_t &dataSize); + + /* + * construct camera_metadata_t from camera capabilities and metadata + * + * @param aCamera + * A pointer to CameraInfo that is being filled by this method. + * @param totalEntries + * Number of camera metadata entries to be added. + * @param totalDataSize + * Sum of sizes of camera metadata entries to be added. + * + * @return bool + * False if either it fails to allocate memory for camera metadata + * or its size is not large enough to add all found camera metadata + * entries. + */ + bool constructCameraMetadata(unique_ptr &aCamera, + const size_t totalEntries, + const size_t totalDataSize); + + /* + * parse a comma-separated list of camera devices and add them to + * CameraGroup. + * + * @param devices + * A comma-separated list of camera device identifiers. + * @param aGroup + * Camera group which cameras will be added to. + */ + void addCameraDevices(const char *devices, + unique_ptr &aGroup); +}; +#endif // CONFIG_MANAGER_H + diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.cpp b/automotive/evs/1.1/default/ConfigManagerUtil.cpp new file mode 100644 index 0000000000..8206daa6d7 --- /dev/null +++ b/automotive/evs/1.1/default/ConfigManagerUtil.cpp @@ -0,0 +1,131 @@ +/* + * 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. + */ + +#include "ConfigManagerUtil.h" + +#include +#include +#include + +#include +#include + + +bool ConfigManagerUtil::convertToEvsCameraParam(const string &id, + CameraParam &camParam) { + string trimmed = ConfigManagerUtil::trimString(id); + bool success = true; + + if (!trimmed.compare("BRIGHTNESS")) { + camParam = CameraParam::BRIGHTNESS; + } else if (!trimmed.compare("CONTRAST")) { + camParam = CameraParam::CONTRAST; + } else if (!trimmed.compare("AUTOGAIN")) { + camParam = CameraParam::AUTOGAIN; + } else if (!trimmed.compare("GAIN")) { + camParam = CameraParam::GAIN; + } else if (!trimmed.compare("AUTO_WHITE_BALANCE")) { + camParam = CameraParam::AUTO_WHITE_BALANCE; + } else if (!trimmed.compare("WHITE_BALANCE_TEMPERATURE")) { + camParam = CameraParam::WHITE_BALANCE_TEMPERATURE; + } else if (!trimmed.compare("SHARPNESS")) { + camParam = CameraParam::SHARPNESS; + } else if (!trimmed.compare("AUTO_EXPOSURE")) { + camParam = CameraParam::AUTO_EXPOSURE; + } else if (!trimmed.compare("ABSOLUTE_EXPOSURE")) { + camParam = CameraParam::ABSOLUTE_EXPOSURE; + } else if (!trimmed.compare("ABSOLUTE_FOCUS")) { + camParam = CameraParam::ABSOLUTE_FOCUS; + } else if (!trimmed.compare("AUTO_FOCUS")) { + camParam = CameraParam::AUTO_FOCUS; + } else if (!trimmed.compare("ABSOLUTE_ZOOM")) { + camParam = CameraParam::ABSOLUTE_ZOOM; + } else { + success = false; + } + + return success; +} + + +bool ConfigManagerUtil::convertToPixelFormat(const string &format, + int32_t &pixFormat) { + string trimmed = ConfigManagerUtil::trimString(format); + bool success = true; + + if (!trimmed.compare("RGBA_8888")) { + pixFormat = HAL_PIXEL_FORMAT_RGBA_8888; + } else if (!trimmed.compare("YCRCB_420_SP")) { + pixFormat = HAL_PIXEL_FORMAT_YCRCB_420_SP; + } else if (!trimmed.compare("YCBCR_422_I")) { + pixFormat = HAL_PIXEL_FORMAT_YCBCR_422_I; + } else { + success = false; + } + + return success; +} + + +bool ConfigManagerUtil::convertToMetadataTag(const char *name, + camera_metadata_tag &aTag) { + if (!strcmp(name, "LENS_DISTORTION")) { + aTag = ANDROID_LENS_DISTORTION; + } else if (!strcmp(name, "LENS_INTRINSIC_CALIBRATION")) { + aTag = ANDROID_LENS_INTRINSIC_CALIBRATION; + } else if (!strcmp(name, "LENS_POSE_ROTATION")) { + aTag = ANDROID_LENS_POSE_ROTATION; + } else if (!strcmp(name, "LENS_POSE_TRANSLATION")) { + aTag = ANDROID_LENS_POSE_TRANSLATION; + } else { + return false; + } + + return true; +} + + +float *ConfigManagerUtil::convertFloatArray(const char *sz, const char *vals, + size_t &count, const char delimiter) { + string size_string(sz); + string value_string(vals); + + count = stoi(size_string); + float *result = new float[count]; + stringstream values(value_string); + + int32_t idx = 0; + string token; + while (getline(values, token, delimiter)) { + result[idx++] = stof(token); + } + + return result; +} + + +string ConfigManagerUtil::trimString(const string &src, const string &ws) { + const auto s = src.find_first_not_of(ws); + if (s == string::npos) { + return ""; + } + + const auto e = src.find_last_not_of(ws); + const auto r = e - s + 1; + + return src.substr(s, r); +} + diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.h b/automotive/evs/1.1/default/ConfigManagerUtil.h new file mode 100644 index 0000000000..8c89ae7745 --- /dev/null +++ b/automotive/evs/1.1/default/ConfigManagerUtil.h @@ -0,0 +1,61 @@ +/* + * 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. + */ +#ifndef CONFIG_MANAGER_UTIL_H +#define CONFIG_MANAGER_UTIL_H + +#include +#include +#include +#include + +using namespace std; +using ::android::hardware::automotive::evs::V1_1::CameraParam; + + +class ConfigManagerUtil { +public: + /** + * Convert a given string into V4L2_CID_* + */ + static bool convertToEvsCameraParam(const string &id, + CameraParam &camParam); + /** + * Convert a given string into android.hardware.graphics.common.PixelFormat + */ + static bool convertToPixelFormat(const string &format, + int32_t &pixelFormat); + /** + * Convert a given string into corresponding camera metadata data tag defined in + * system/media/camera/include/system/camera_metadta_tags.h + */ + static bool convertToMetadataTag(const char *name, + camera_metadata_tag &aTag); + /** + * Convert a given string into a floating value array + */ + static float *convertFloatArray(const char *sz, + const char *vals, + size_t &count, + const char delimiter = ','); + /** + * Trim a string + */ + static string trimString(const string &src, + const string &ws = " \n\r\t\f\v"); +}; + +#endif // CONFIG_MANAGER_UTIL_H + diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp index 2d55566349..5ba753da2e 100644 --- a/automotive/evs/1.1/default/EvsCamera.cpp +++ b/automotive/evs/1.1/default/EvsCamera.cpp @@ -40,28 +40,21 @@ const char EvsCamera::kCameraName_Backup[] = "backup"; const unsigned MAX_BUFFERS_IN_FLIGHT = 100; -EvsCamera::EvsCamera(const char *id) : +EvsCamera::EvsCamera(const char *id, + unique_ptr &camInfo) : mFramesAllowed(0), mFramesInUse(0), - mStreamState(STOPPED) { + mStreamState(STOPPED), + mCameraInfo(camInfo) { ALOGD("EvsCamera instantiated"); - mDescription.cameraId = id; + /* set a camera id */ + mDescription.v1.cameraId = id; - // Set up dummy data for testing - if (mDescription.cameraId == kCameraName_Backup) { - mWidth = 640; // full NTSC/VGA - mHeight = 480; // full NTSC/VGA - mDescription.vendorFlags = 0xFFFFFFFF; // Arbitrary value - } else { - mWidth = 320; // 1/2 NTSC/VGA - mHeight = 240; // 1/2 NTSC/VGA - } - - mFormat = HAL_PIXEL_FORMAT_RGBA_8888; - mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE | - GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY; + /* set camera metadata */ + mDescription.metadata.setToExternal((uint8_t *)camInfo->characteristics, + get_camera_metadata_size(camInfo->characteristics)); } @@ -109,7 +102,7 @@ Return EvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) { ALOGD("getCameraInfo"); // Send back our self description - _hidl_cb(mDescription); + _hidl_cb(mDescription.v1); return Void(); } @@ -194,7 +187,7 @@ Return EvsCamera::stopVideoStream() { // Block outside the mutex until the "stop" flag has been acknowledged // We won't send any more frames, but the client might still get some already in flight - ALOGD("Waiting for stream thread to end.."); + ALOGD("Waiting for stream thread to end..."); lock.unlock(); mCaptureThread.join(); lock.lock(); @@ -238,6 +231,15 @@ Return EvsCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/, int3 // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow. +Return EvsCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) { + ALOGD("getCameraInfo_1_1"); + + // Send back our self description + _hidl_cb(mDescription); + return Void(); +} + + Return EvsCamera::doneWithFrame_1_1(const BufferDesc_1_1& bufDesc) { std::lock_guard lock(mAccessLock); returnBuffer(bufDesc.bufferId, bufDesc.buffer.nativeHandle); @@ -278,8 +280,29 @@ Return EvsCamera::unsetMaster() { } -Return EvsCamera::setParameter(CameraParam id, int32_t value, - setParameter_cb _hidl_cb) { +Return EvsCamera::getParameterList(getParameterList_cb _hidl_cb) { + hidl_vec hidlCtrls; + hidlCtrls.resize(mCameraInfo->controls.size()); + unsigned idx = 0; + for (auto& [cid, cfg] : mCameraInfo->controls) { + hidlCtrls[idx++] = cid; + } + + _hidl_cb(hidlCtrls); + return Void(); +} + + +Return EvsCamera::getIntParameterRange(CameraParam id, + getIntParameterRange_cb _hidl_cb) { + auto range = mCameraInfo->controls[id]; + _hidl_cb(get<0>(range), get<1>(range), get<2>(range)); + return Void(); +} + + +Return EvsCamera::setIntParameter(CameraParam id, int32_t value, + setIntParameter_cb _hidl_cb) { // Default implementation does not support this. (void)id; (void)value; @@ -288,7 +311,8 @@ Return EvsCamera::setParameter(CameraParam id, int32_t value, } -Return EvsCamera::getParameter(CameraParam id, getParameter_cb _hidl_cb) { +Return EvsCamera::getIntParameter(CameraParam id, + getIntParameter_cb _hidl_cb) { // Default implementation does not support this. (void)id; _hidl_cb(EvsResult::INVALID_ARG, 0); @@ -471,9 +495,7 @@ void EvsCamera::generateFrames() { fillTestFrame(newBuffer); // Issue the (asynchronous) callback to the client -- can't be holding the lock - EvsEvent event; - event.buffer(newBuffer); - auto result = mStream->notifyEvent(event); + auto result = mStream->deliverFrame_1_1(newBuffer); if (result.isOk()) { ALOGD("Delivered %p as id %d", newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId); @@ -506,10 +528,8 @@ void EvsCamera::generateFrames() { // If we've been asked to stop, send an event to signal the actual end of stream EvsEvent event; - InfoEventDesc desc = {}; - desc.aType = InfoEventType::STREAM_STOPPED; - event.info(desc); - auto result = mStream->notifyEvent(event); + event.aType = EvsEventType::STREAM_STOPPED; + auto result = mStream->notify(event); if (!result.isOk()) { ALOGE("Error delivering end of stream marker"); } @@ -616,6 +636,38 @@ void EvsCamera::returnBuffer(const uint32_t bufferId, const buffer_handle_t memH } +sp EvsCamera::Create(const char *deviceName) { + unique_ptr nullCamInfo = nullptr; + + return Create(deviceName, nullCamInfo); +} + + +sp EvsCamera::Create(const char *deviceName, + unique_ptr &camInfo, + const Stream *streamCfg) { + sp evsCamera = new EvsCamera(deviceName, camInfo); + if (evsCamera == nullptr) { + return nullptr; + } + + /* default implementation does not use a given configuration */ + (void)streamCfg; + + /* Use the first resolution from the list for the testing */ + auto it = camInfo->streamConfigurations.begin(); + evsCamera->mWidth = it->second[1]; + evsCamera->mHeight = it->second[2]; + evsCamera->mDescription.v1.vendorFlags = 0xFFFFFFFF; // Arbitrary test value + + evsCamera->mFormat = HAL_PIXEL_FORMAT_RGBA_8888; + evsCamera->mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE | + GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY; + + return evsCamera; +} + + } // namespace implementation } // namespace V1_0 } // namespace evs diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h index 47a3164892..c15b4b117b 100644 --- a/automotive/evs/1.1/default/EvsCamera.h +++ b/automotive/evs/1.1/default/EvsCamera.h @@ -25,6 +25,8 @@ #include +#include "ConfigManager.h" + using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc; using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc; using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream; @@ -59,18 +61,28 @@ public: Return setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override; // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow. + Return getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) override; Return pauseVideoStream() override; Return resumeVideoStream() override; Return doneWithFrame_1_1(const BufferDesc_1_1& buffer) override; Return setMaster() override; Return forceMaster(const sp& display) override; Return unsetMaster() override; - Return setParameter(CameraParam id, int32_t value, - setParameter_cb _hidl_cb) override; - Return getParameter(CameraParam id, getParameter_cb _hidl_cb) override; + Return getParameterList(getParameterList_cb _hidl_cb) override; + Return getIntParameterRange(CameraParam id, + getIntParameterRange_cb _hidl_cb) override; + Return setIntParameter(CameraParam id, int32_t value, + setIntParameter_cb _hidl_cb) override; + Return getIntParameter(CameraParam id, + getIntParameter_cb _hidl_cb) override; + + static sp Create(const char *deviceName); + static sp Create(const char *deviceName, + unique_ptr &camInfo, + const Stream *streamCfg = nullptr); + EvsCamera(const EvsCamera&) = delete; + EvsCamera& operator=(const EvsCamera&) = delete; - // Implementation details - EvsCamera(const char *id); virtual ~EvsCamera() override; void forceShutdown(); // This gets called if another caller "steals" ownership of the camera @@ -79,7 +91,10 @@ public: static const char kCameraName_Backup[]; private: + EvsCamera(const char *id, + unique_ptr &camInfo); // These three functions are expected to be called while mAccessLock is held + // bool setAvailableFrames_Locked(unsigned bufferCount); unsigned increaseAvailableFrames_Locked(unsigned numToAdd); unsigned decreaseAvailableFrames_Locked(unsigned numToRemove); @@ -124,6 +139,9 @@ private: // Synchronization necessary to deconflict mCaptureThread from the main service thread std::mutex mAccessLock; + + // Static camera module information + unique_ptr &mCameraInfo; }; } // namespace implementation diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp index b3249071ae..a010729ce6 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.cpp +++ b/automotive/evs/1.1/default/EvsEnumerator.cpp @@ -33,6 +33,7 @@ namespace implementation { // constructs a new instance for each client. std::list EvsEnumerator::sCameraList; wp EvsEnumerator::sActiveDisplay; +unique_ptr EvsEnumerator::sConfigManager; EvsEnumerator::EvsEnumerator() { @@ -40,9 +41,11 @@ EvsEnumerator::EvsEnumerator() { // Add sample camera data to our list of cameras // In a real driver, this would be expected to can the available hardware - sCameraList.emplace_back(EvsCamera::kCameraName_Backup); - sCameraList.emplace_back("LaneView"); - sCameraList.emplace_back("right turn"); + sConfigManager = + ConfigManager::Create("/etc/automotive/evs/evs_sample_configuration.xml"); + for (auto v : sConfigManager->getCameraList()) { + sCameraList.emplace_back(v.c_str()); + } } @@ -57,7 +60,7 @@ Return EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) { std::vector descriptions; descriptions.reserve(numCameras); for (const auto& cam : sCameraList) { - descriptions.push_back( cam.desc ); + descriptions.push_back( cam.desc.v1 ); } // Encapsulate our camera descriptions in the HIDL vec type @@ -78,7 +81,7 @@ Return> EvsEnumerator::openCamera(const hidl_string& cameraId // Find the named camera CameraRecord *pRecord = nullptr; for (auto &&cam : sCameraList) { - if (cam.desc.cameraId == cameraId) { + if (cam.desc.v1.cameraId == cameraId) { // Found a match! pRecord = &cam; break; @@ -99,7 +102,12 @@ Return> EvsEnumerator::openCamera(const hidl_string& cameraId } // Construct a camera instance for the caller - pActiveCamera = new EvsCamera(cameraId.c_str()); + if (sConfigManager == nullptr) { + pActiveCamera = EvsCamera::Create(cameraId.c_str()); + } else { + pActiveCamera = EvsCamera::Create(cameraId.c_str(), + sConfigManager->getCameraInfo(cameraId)); + } pRecord->activeInstance = pActiveCamera; if (pActiveCamera == nullptr) { ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str()); @@ -120,15 +128,15 @@ Return EvsEnumerator::closeCamera(const ::android::sp& pCa // Get the camera id so we can find it in our list std::string cameraId; - pCamera_1_1->getCameraInfo([&cameraId](CameraDesc desc) { - cameraId = desc.cameraId; + pCamera_1_1->getCameraInfo_1_1([&cameraId](CameraDesc desc) { + cameraId = desc.v1.cameraId; } ); // Find the named camera CameraRecord *pRecord = nullptr; for (auto &&cam : sCameraList) { - if (cam.desc.cameraId == cameraId) { + if (cam.desc.v1.cameraId == cameraId) { // Found a match! pRecord = &cam; break; @@ -209,6 +217,89 @@ Return EvsEnumerator::getDisplayState() { } +// Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow. +Return EvsEnumerator::getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) { + ALOGD("getCameraList"); + + const unsigned numCameras = sCameraList.size(); + + // Build up a packed array of CameraDesc for return + // NOTE: Only has to live until the callback returns + std::vector descriptions; + descriptions.reserve(numCameras); + for (const auto& cam : sCameraList) { + descriptions.push_back( cam.desc ); + } + + // Encapsulate our camera descriptions in the HIDL vec type + hidl_vec hidlCameras(descriptions); + + // Send back the results + ALOGD("reporting %zu cameras available", hidlCameras.size()); + _hidl_cb(hidlCameras); + + // HIDL convention says we return Void if we sent our result back via callback + return Void(); +} + +Return> +EvsEnumerator::openCamera_1_1(const hidl_string& cameraId, + const Stream& streamCfg) { + // Find the named camera + CameraRecord *pRecord = nullptr; + for (auto &&cam : sCameraList) { + if (cam.desc.v1.cameraId == cameraId) { + // Found a match! + pRecord = &cam; + break; + } + } + + // Is this a recognized camera id? + if (!pRecord) { + ALOGE("Requested camera %s not found", cameraId.c_str()); + return nullptr; + } + + // Has this camera already been instantiated by another caller? + sp pActiveCamera = pRecord->activeInstance.promote(); + if (pActiveCamera != nullptr) { + ALOGW("Killing previous camera because of new caller"); + closeCamera(pActiveCamera); + } + + // Construct a camera instance for the caller + if (sConfigManager == nullptr) { + pActiveCamera = EvsCamera::Create(cameraId.c_str()); + } else { + pActiveCamera = EvsCamera::Create(cameraId.c_str(), + sConfigManager->getCameraInfo(cameraId), + &streamCfg); + } + + pRecord->activeInstance = pActiveCamera; + if (pActiveCamera == nullptr) { + ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str()); + } + + return pActiveCamera; +} + + +EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& cameraId) { + // Find the named camera + CameraRecord *pRecord = nullptr; + for (auto &&cam : sCameraList) { + if (cam.desc.v1.cameraId == cameraId) { + // Found a match! + pRecord = &cam; + break; + } + } + + return pRecord; +} + } // namespace implementation } // namespace V1_1 } // namespace evs diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h index 11c2170632..475ec76b93 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.h +++ b/automotive/evs/1.1/default/EvsEnumerator.h @@ -17,18 +17,20 @@ #ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H #define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H -#include +#include #include #include +#include "ConfigManager.h" + using ::android::hardware::automotive::evs::V1_0::EvsResult; using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; using ::android::hardware::automotive::evs::V1_0::DisplayState; -using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator; using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera; using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera; using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc; +using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc; namespace android { @@ -53,6 +55,11 @@ public: Return closeDisplay(const ::android::sp& display) override; Return getDisplayState() override; + // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow. + Return getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) override; + Return> openCamera_1_1(const hidl_string& cameraId, + const Stream& streamCfg) override; + // Implementation details EvsEnumerator(); @@ -61,14 +68,20 @@ private: // That is to say, this is effectively a singleton despite the fact that HIDL // constructs a new instance for each client. struct CameraRecord { - CameraDesc_1_0 desc; + CameraDesc_1_1 desc; wp activeInstance; - CameraRecord(const char *cameraId) : desc() { desc.cameraId = cameraId; } + CameraRecord(const char *cameraId) : desc() { desc.v1.cameraId = cameraId; } }; - static std::list sCameraList; - static wp sActiveDisplay; // Weak pointer. Object destructs if client dies. + static CameraRecord* findCameraById(const std::string& cameraId); + + static std::list sCameraList; + + // Weak pointer. Object destructs if client dies. + static wp sActiveDisplay; + + static unique_ptr sConfigManager; }; } // namespace implementation diff --git a/automotive/evs/1.1/default/resources/evs_default_configuration.xml b/automotive/evs/1.1/default/resources/evs_default_configuration.xml new file mode 100644 index 0000000000..692102ed38 --- /dev/null +++ b/automotive/evs/1.1/default/resources/evs_default_configuration.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/automotive/evs/1.1/default/service.cpp b/automotive/evs/1.1/default/service.cpp index 128a14aa30..5135864e88 100644 --- a/automotive/evs/1.1/default/service.cpp +++ b/automotive/evs/1.1/default/service.cpp @@ -33,7 +33,7 @@ using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; // Generated HIDL files -using android::hardware::automotive::evs::V1_0::IEvsEnumerator; +using android::hardware::automotive::evs::V1_1::IEvsEnumerator; using android::hardware::automotive::evs::V1_0::IEvsDisplay; // The namespace in which all our implementation code lives diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal index 2c6b2ed589..dcb2abb0e9 100644 --- a/automotive/evs/1.1/types.hal +++ b/automotive/evs/1.1/types.hal @@ -21,6 +21,22 @@ import @1.0::DisplayDesc; import @1.0::DisplayState; import @1.0::EvsResult; import android.hardware.graphics.common@1.2::HardwareBuffer; +import android.hardware.camera.device@3.2::CameraMetadata; + +/** + * Structure describing the basic properties of an EVS camera, extended from its + * v1.0 declaration. + * + * The HAL is responsible for filling out this structure for each + * EVS camera in the system. + */ +struct CameraDesc { + @1.0::CameraDesc v1; + /** + * Store camera metadata such as lens characteristics. + */ + CameraMetadata metadata; +}; /** * Structure representing an image buffer through our APIs @@ -50,7 +66,7 @@ struct BufferDesc { /** * Types of informative streaming events */ -enum InfoEventType : uint32_t { +enum EvsEventType : uint32_t { /** * Video stream is started */ @@ -81,31 +97,17 @@ enum InfoEventType : uint32_t { /** * Structure that describes informative events occurred during EVS is streaming */ -struct InfoEventDesc { +struct EvsEvent { /** * Type of an informative event */ - InfoEventType aType; + EvsEventType aType; /** * Possible additional information */ uint32_t[4] payload; }; -/** - * EVS event definition - */ -safe_union EvsEvent { - /** - * A buffer descriptor of an image frame - */ - BufferDesc buffer; - /** - * General streaming events - */ - InfoEventDesc info; -}; - /** * EVS Camera Parameter */ @@ -126,14 +128,6 @@ enum CameraParam : uint32_t { * Gain control */ GAIN, - /** - * Mirror the image horizontally - */ - HFLIP, - /** - * Mirror the image vertically - */ - VFLIP, /** * Automatic Whitebalance */ @@ -155,11 +149,6 @@ enum CameraParam : uint32_t { * Manual exposure time of the camera */ ABSOLUTE_EXPOSURE, - /** - * When AEC is running in either auto or aperture priority, this parameter - * sets whether a frame rate varies. - */ - AUTO_EXPOSURE_PRIORITY, /** * Set the focal point of the camera to the specified position. This * parameter may not be effective when auto focus is enabled. diff --git a/automotive/evs/1.1/vts/functional/Android.bp b/automotive/evs/1.1/vts/functional/Android.bp index 55c50a42b8..4753933f7f 100644 --- a/automotive/evs/1.1/vts/functional/Android.bp +++ b/automotive/evs/1.1/vts/functional/Android.bp @@ -23,6 +23,7 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], shared_libs: [ "libui", + "libcamera_metadata", ], static_libs: [ "android.hardware.automotive.evs@1.0", @@ -31,6 +32,7 @@ cc_test { "android.hardware.graphics.common@1.0", "android.hardware.graphics.common@1.1", "android.hardware.graphics.common@1.2", + "android.hardware.camera.device@3.2", ], test_suites: ["general-tests"], cflags: [ diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp index 16276891f0..6d53652f86 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp +++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp @@ -138,93 +138,93 @@ Return FrameHandler::deliverFrame(const BufferDesc_1_0& bufferArg) { } -Return FrameHandler::notifyEvent(const EvsEvent& event) { - // Local flag we use to keep track of when the stream is stopping - auto type = event.getDiscriminator(); - if (type == EvsEvent::hidl_discriminator::info) { - mLock.lock(); - mLatestEventDesc = event.info(); - if (mLatestEventDesc.aType == InfoEventType::STREAM_STOPPED) { - // Signal that the last frame has been received and the stream is stopped - mRunning = false; - } else if (mLatestEventDesc.aType == InfoEventType::PARAMETER_CHANGED) { - ALOGD("Camera parameter 0x%X is changed to 0x%X", - mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]); +Return FrameHandler::deliverFrame_1_1(const BufferDesc_1_1& bufDesc) { + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&bufDesc.buffer.description); + ALOGD("Received a frame from the camera (%p)", + bufDesc.buffer.nativeHandle.getNativeHandle()); + + // Store a dimension of a received frame. + mFrameWidth = pDesc->width; + mFrameHeight = pDesc->height; + + // If we were given an opened display at construction time, then send the received + // image back down the camera. + if (mDisplay.get()) { + // Get the output buffer we'll use to display the imagery + BufferDesc_1_0 tgtBuffer = {}; + mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) { + tgtBuffer = buff; + } + ); + + if (tgtBuffer.memHandle == nullptr) { + printf("Didn't get target buffer - frame lost\n"); + ALOGE("Didn't get requested output buffer -- skipping this frame."); } else { - ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType)); - } - mLock.unlock(); - mEventSignal.notify_all(); - } else { - auto bufDesc = event.buffer(); - const AHardwareBuffer_Desc* pDesc = - reinterpret_cast(&bufDesc.buffer.description); - ALOGD("Received a frame from the camera (%p)", - bufDesc.buffer.nativeHandle.getNativeHandle()); + // Copy the contents of the of buffer.memHandle into tgtBuffer + copyBufferContents(tgtBuffer, bufDesc); - // Store a dimension of a received frame. - mFrameWidth = pDesc->width; - mFrameHeight = pDesc->height; - - // If we were given an opened display at construction time, then send the received - // image back down the camera. - if (mDisplay.get()) { - // Get the output buffer we'll use to display the imagery - BufferDesc_1_0 tgtBuffer = {}; - mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) { - tgtBuffer = buff; - } - ); - - if (tgtBuffer.memHandle == nullptr) { - printf("Didn't get target buffer - frame lost\n"); - ALOGE("Didn't get requested output buffer -- skipping this frame."); + // Send the target buffer back for display + Return result = mDisplay->returnTargetBufferForDisplay(tgtBuffer); + if (!result.isOk()) { + printf("HIDL error on display buffer (%s)- frame lost\n", + result.description().c_str()); + ALOGE("Error making the remote function call. HIDL said %s", + result.description().c_str()); + } else if (result != EvsResult::OK) { + printf("Display reported error - frame lost\n"); + ALOGE("We encountered error %d when returning a buffer to the display!", + (EvsResult) result); } else { - // Copy the contents of the of buffer.memHandle into tgtBuffer - copyBufferContents(tgtBuffer, bufDesc); - - // Send the target buffer back for display - Return result = mDisplay->returnTargetBufferForDisplay(tgtBuffer); - if (!result.isOk()) { - printf("HIDL error on display buffer (%s)- frame lost\n", - result.description().c_str()); - ALOGE("Error making the remote function call. HIDL said %s", - result.description().c_str()); - } else if (result != EvsResult::OK) { - printf("Display reported error - frame lost\n"); - ALOGE("We encountered error %d when returning a buffer to the display!", - (EvsResult) result); - } else { - // Everything looks good! - // Keep track so tests or watch dogs can monitor progress - mLock.lock(); - mFramesDisplayed++; - mLock.unlock(); - } + // Everything looks good! + // Keep track so tests or watch dogs can monitor progress + mLock.lock(); + mFramesDisplayed++; + mLock.unlock(); } } - - - switch (mReturnMode) { - case eAutoReturn: - // Send the camera buffer back now that the client has seen it - ALOGD("Calling doneWithFrame"); - // TODO: Why is it that we get a HIDL crash if we pass back the cloned buffer? - mCamera->doneWithFrame_1_1(bufDesc); - break; - case eNoAutoReturn: - // Hang onto the buffer handle for now -- the client will return it explicitly later - mHeldBuffers.push(bufDesc); - } - - mLock.lock(); - ++mFramesReceived; - mLock.unlock(); - mFrameSignal.notify_all(); - - ALOGD("Frame handling complete"); } + + switch (mReturnMode) { + case eAutoReturn: + // Send the camera buffer back now that the client has seen it + ALOGD("Calling doneWithFrame"); + mCamera->doneWithFrame_1_1(bufDesc); + break; + case eNoAutoReturn: + // Hang onto the buffer handle for now -- the client will return it explicitly later + mHeldBuffers.push(bufDesc); + } + + mLock.lock(); + ++mFramesReceived; + mLock.unlock(); + mFrameSignal.notify_all(); + + ALOGD("Frame handling complete"); + + return Void(); +} + + +Return FrameHandler::notify(const EvsEvent& event) { + // Local flag we use to keep track of when the stream is stopping + mLock.lock(); + mLatestEventDesc = event; + if (mLatestEventDesc.aType == EvsEventType::STREAM_STOPPED) { + // Signal that the last frame has been received and the stream is stopped + mRunning = false; + } else if (mLatestEventDesc.aType == EvsEventType::PARAMETER_CHANGED) { + ALOGD("Camera parameter 0x%X is changed to 0x%X", + mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]); + } else { + ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType)); + } + mLock.unlock(); + mEventSignal.notify_all(); + return Void(); } @@ -342,18 +342,18 @@ void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) { } } -bool FrameHandler::waitForEvent(const InfoEventType aTargetEvent, - InfoEventDesc &eventDesc) { +bool FrameHandler::waitForEvent(const EvsEventType aTargetEvent, + EvsEvent &event) { // Wait until we get an expected parameter change event. std::unique_lock lock(mLock); auto now = std::chrono::system_clock::now(); bool result = mEventSignal.wait_until(lock, now + 5s, - [this, aTargetEvent, &eventDesc](){ + [this, aTargetEvent, &event](){ bool flag = mLatestEventDesc.aType == aTargetEvent; if (flag) { - eventDesc.aType = mLatestEventDesc.aType; - eventDesc.payload[0] = mLatestEventDesc.payload[0]; - eventDesc.payload[1] = mLatestEventDesc.payload[1]; + event.aType = mLatestEventDesc.aType; + event.payload[0] = mLatestEventDesc.payload[0]; + event.payload[1] = mLatestEventDesc.payload[1]; } return flag; @@ -363,21 +363,22 @@ bool FrameHandler::waitForEvent(const InfoEventType aTargetEvent, return !result; } -const char *FrameHandler::eventToString(const InfoEventType aType) { +const char *FrameHandler::eventToString(const EvsEventType aType) { switch (aType) { - case InfoEventType::STREAM_STARTED: + case EvsEventType::STREAM_STARTED: return "STREAM_STARTED"; - case InfoEventType::STREAM_STOPPED: + case EvsEventType::STREAM_STOPPED: return "STREAM_STOPPED"; - case InfoEventType::FRAME_DROPPED: + case EvsEventType::FRAME_DROPPED: return "FRAME_DROPPED"; - case InfoEventType::TIMEOUT: + case EvsEventType::TIMEOUT: return "TIMEOUT"; - case InfoEventType::PARAMETER_CHANGED: + case EvsEventType::PARAMETER_CHANGED: return "PARAMETER_CHANGED"; - case InfoEventType::MASTER_RELEASED: + case EvsEventType::MASTER_RELEASED: return "MASTER_RELEASED"; default: return "Unknown"; } } + diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h index 7f87cb4409..e5f1b8f112 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.h +++ b/automotive/evs/1.1/vts/functional/FrameHandler.h @@ -33,7 +33,6 @@ using ::android::hardware::hidl_handle; using ::android::sp; using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; using ::android::hardware::automotive::evs::V1_0::EvsResult; -using ::android::hardware::automotive::evs::V1_0::CameraDesc; using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc; using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc; @@ -56,6 +55,13 @@ public: FrameHandler(android::sp pCamera, CameraDesc cameraInfo, android::sp pDisplay = nullptr, BufferControlFlag mode = eAutoReturn); + virtual ~FrameHandler() { + if (mCamera != nullptr) { + /* shutdown a camera explicitly */ + shutdown(); + } + } + void shutdown(); bool startStream(); @@ -67,19 +73,22 @@ public: bool isRunning(); void waitForFrameCount(unsigned frameCount); - bool waitForEvent(const InfoEventType aTargetEvent, - InfoEventDesc &eventDesc); + bool waitForEvent(const EvsEventType aTargetEvent, + EvsEvent &eventDesc); void getFramesCounters(unsigned* received, unsigned* displayed); void getFrameDimension(unsigned* width, unsigned* height); private: - // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream + // Implementation for ::android::hardware::automotive::evs::V1_0::IEvsCameraStream Return deliverFrame(const BufferDesc_1_0& buffer) override; - Return notifyEvent(const EvsEvent& event) override; + + // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream + Return deliverFrame_1_1(const BufferDesc_1_1& buffer) override; + Return notify(const EvsEvent& event) override; // Local implementation details bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer); - const char *eventToString(const InfoEventType aType); + const char *eventToString(const EvsEventType aType); // Values initialized as startup android::sp mCamera; @@ -100,7 +109,7 @@ private: unsigned mFramesDisplayed = 0; // Simple counter -- rolls over eventually! unsigned mFrameWidth = 0; unsigned mFrameHeight = 0; - InfoEventDesc mLatestEventDesc; + EvsEvent mLatestEventDesc; }; diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index a6e4881d4d..1d3fd87356 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -38,8 +38,9 @@ static const float kNanoToSeconds = 0.000000001f; #include "FrameHandler.h" -#include -#include +#include +#include +#include #include #include @@ -50,8 +51,10 @@ static const float kNanoToSeconds = 0.000000001f; #include #include #include -#include +#include #include +#include +#include #include #include @@ -64,13 +67,28 @@ using ::android::hardware::hidl_vec; using ::android::hardware::hidl_handle; using ::android::hardware::hidl_string; using ::android::sp; -using ::android::hardware::automotive::evs::V1_0::CameraDesc; +using ::android::hardware::camera::device::V3_2::Stream; using ::android::hardware::automotive::evs::V1_0::DisplayDesc; using ::android::hardware::automotive::evs::V1_0::DisplayState; -using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator; +using ::android::hardware::graphics::common::V1_0::PixelFormat; using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera; using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera; +/* + * Plese note that this is different from what is defined in + * libhardware/modules/camera/3_4/metadata/types.h; this has one additional + * field to store a framerate. + */ +const size_t kStreamCfgSz = 5; +typedef struct { + int32_t width; + int32_t height; + int32_t format; + int32_t direction; + int32_t framerate; +} RawStreamConfig; + + // Test environment for Evs HIDL HAL. class EvsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: @@ -107,15 +125,16 @@ protected: assert(pEnumerator != nullptr); // Get the camera list - pEnumerator->getCameraList([this](hidl_vec cameraList) { - ALOGI("Camera list callback received %zu cameras", - cameraList.size()); - cameraInfo.reserve(cameraList.size()); - for (auto&& cam: cameraList) { - ALOGI("Found camera %s", cam.cameraId.c_str()); - cameraInfo.push_back(cam); - } - } + pEnumerator->getCameraList_1_1( + [this](hidl_vec cameraList) { + ALOGI("Camera list callback received %zu cameras", + cameraList.size()); + cameraInfo.reserve(cameraList.size()); + for (auto&& cam: cameraList) { + ALOGI("Found camera %s", cam.v1.cameraId.c_str()); + cameraInfo.push_back(cam); + } + } ); // We insist on at least one camera for EVS to pass any camera tests @@ -143,19 +162,23 @@ TEST_F(EvsHidlTest, CameraOpenClean) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Open and close each camera twice for (auto&& cam: cameraInfo) { for (int pass = 0; pass < 2; pass++) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); // Verify that this camera self-identifies correctly - pCam->getCameraInfo([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.cameraId.c_str()); - EXPECT_EQ(cam.cameraId, desc.cameraId); - } + pCam->getCameraInfo_1_1([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.v1.cameraId.c_str()); + EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); + } ); // Explicitly close the camera so resources are released right away @@ -177,22 +200,26 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Open and close each camera twice for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); // Verify that this camera self-identifies correctly - pCam->getCameraInfo([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.cameraId.c_str()); - EXPECT_EQ(cam.cameraId, desc.cameraId); - } + pCam->getCameraInfo_1_1([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.v1.cameraId.c_str()); + EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); + } ); sp pCam2 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, pCam2); ASSERT_NE(pCam2, nullptr); @@ -210,10 +237,10 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { pEnumerator->closeCamera(pCam); // Verify that the second camera instance self-identifies correctly - pCam2->getCameraInfo([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.cameraId.c_str()); - EXPECT_EQ(cam.cameraId, desc.cameraId); - } + pCam2->getCameraInfo_1_1([&cam](CameraDesc desc) { + ALOGD("Found camera %s", desc.v1.cameraId.c_str()); + EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); + } ); // Close the second camera instance @@ -235,10 +262,14 @@ TEST_F(EvsHidlTest, CameraStreamPerformance) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); @@ -303,11 +334,15 @@ TEST_F(EvsHidlTest, CameraStreamBuffering) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); @@ -371,6 +406,10 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Request exclusive access to the EVS display sp pDisplay = pEnumerator->openDisplay(); ASSERT_NE(pDisplay, nullptr); @@ -378,7 +417,7 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { // Test each reported camera for (auto&& cam: cameraInfo) { sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); @@ -439,16 +478,20 @@ TEST_F(EvsHidlTest, MultiCameraStream) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera for (auto&& cam: cameraInfo) { // Create two camera clients. sp pCam0 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam0, nullptr); sp pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam1, nullptr); @@ -486,7 +529,6 @@ TEST_F(EvsHidlTest, MultiCameraStream) { nsecs_t runTime = end - firstFrame; float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds); float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds); - printf("Measured camera rate %3.2f fps and %3.2f fps\n", framesPerSecond0, framesPerSecond1); ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1); EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond); EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond); @@ -526,14 +568,33 @@ TEST_F(EvsHidlTest, CameraParameter) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera + Return result = EvsResult::OK; for (auto&& cam: cameraInfo) { // Create a camera client sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); + // Get the parameter list + std::vector cmds; + pCam->getParameterList([&cmds](hidl_vec cmdList) { + cmds.reserve(cmdList.size()); + for (auto &&cmd : cmdList) { + cmds.push_back(cmd); + } + } + ); + + if (cmds.size() < 1) { + continue; + } + // Set up per-client frame receiver objects which will fire up its own thread sp frameHandler = new FrameHandler(pCam, cam, nullptr, @@ -547,83 +608,70 @@ TEST_F(EvsHidlTest, CameraParameter) { // Ensure the stream starts frameHandler->waitForFrameCount(1); - // Try to program few parameters - EvsResult result = EvsResult::OK; - int32_t val0 = 100; - int32_t val1 = 0; - result = pCam->setMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); - pCam->setParameter(CameraParam::BRIGHTNESS, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); + for (auto &cmd : cmds) { + // Get a valid parameter value range + int32_t minVal, maxVal, step; + pCam->getIntParameterRange( + cmd, + [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { + minVal = val0; + maxVal = val1; + step = val2; + } + ); - if (result == EvsResult::OK) { - pCam->getParameter(CameraParam::BRIGHTNESS, + EvsResult result = EvsResult::OK; + if (cmd == CameraParam::ABSOLUTE_FOCUS) { + // Try to turn off auto-focus + int32_t val1 = 0; + pCam->getIntParameter(CameraParam::AUTO_FOCUS, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + if (val1 != 0) { + pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val1, 0); + } + } + + // Try to program a parameter with a random value [minVal, maxVal] + int32_t val0 = minVal + (std::rand() % (maxVal - minVal)); + int32_t val1 = 0; + + // Rounding down + val0 = val0 - (val0 % step); + pCam->setIntParameter(cmd, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + + ASSERT_EQ(EvsResult::OK, result); + + pCam->getIntParameter(cmd, [&result, &val1](auto status, auto value) { result = status; if (status == EvsResult::OK) { val1 = value; } }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - ASSERT_EQ(val0, val1) << "Values are not matched."; - } - - val0 = 80; - val1 = 0; - pCam->setParameter(CameraParam::CONTRAST, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - - if (result == EvsResult::OK) { - pCam->getParameter(CameraParam::CONTRAST, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - ASSERT_EQ(val0, val1) << "Values are not matched."; - } - - val0 = 300; - val1 = 0; - pCam->setParameter(CameraParam::ABSOLUTE_ZOOM, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - - if (result == EvsResult::OK) { - pCam->getParameter(CameraParam::ABSOLUTE_ZOOM, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); + ASSERT_EQ(EvsResult::OK, result); ASSERT_EQ(val0, val1) << "Values are not matched."; } result = pCam->unsetMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); // Shutdown frameHandler->shutdown(); @@ -650,15 +698,19 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera for (auto&& cam: cameraInfo) { // Create two camera clients. sp pCamMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCamMaster, nullptr); sp pCamNonMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCamNonMaster, nullptr); @@ -698,15 +750,15 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { // Non-master client expects to receive a master role relesed // notification. - InfoEventDesc aNotification = {}; + EvsEvent aNotification = {}; // Release a master role. pCamMaster->unsetMaster(); // Verify a change notification. - frameHandlerNonMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); - ASSERT_EQ(InfoEventType::MASTER_RELEASED, - static_cast(aNotification.aType)); + frameHandlerNonMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(EvsEventType::MASTER_RELEASED, + static_cast(aNotification.aType)); // Non-master becomes a master. result = pCamNonMaster->setMaster(); @@ -720,9 +772,9 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { frameHandlerNonMaster->shutdown(); // Verify a change notification. - frameHandlerMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); - ASSERT_EQ(InfoEventType::MASTER_RELEASED, - static_cast(aNotification.aType)); + frameHandlerMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(EvsEventType::MASTER_RELEASED, + static_cast(aNotification.aType)); // Closing another stream. frameHandlerMaster->shutdown(); @@ -752,18 +804,46 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Test each reported camera for (auto&& cam: cameraInfo) { // Create two camera clients. sp pCamMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCamMaster, nullptr); sp pCamNonMaster = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCamNonMaster, nullptr); + // Get the parameter list + std::vector camMasterCmds, camNonMasterCmds; + pCamMaster->getParameterList([&camMasterCmds](hidl_vec cmdList) { + camMasterCmds.reserve(cmdList.size()); + for (auto &&cmd : cmdList) { + camMasterCmds.push_back(cmd); + } + } + ); + + pCamNonMaster->getParameterList([&camNonMasterCmds](hidl_vec cmdList) { + camNonMasterCmds.reserve(cmdList.size()); + for (auto &&cmd : cmdList) { + camNonMasterCmds.push_back(cmd); + } + } + ); + + if (camMasterCmds.size() < 1 || + camNonMasterCmds.size() < 1) { + // Skip a camera device if it does not support any parameter. + continue; + } + // Set up per-client frame receiver objects which will fire up its own thread sp frameHandlerMaster = new FrameHandler(pCamMaster, cam, @@ -778,11 +858,11 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Set one client as the master EvsResult result = pCamMaster->setMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); // Try to set another client as the master. result = pCamNonMaster->setMaster(); - ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST); + ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result); // Start the camera's video stream via a master client. bool startResult = frameHandlerMaster->startStream(); @@ -798,131 +878,168 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Ensure the stream starts frameHandlerNonMaster->waitForFrameCount(1); - // Try to program CameraParam::BRIGHTNESS - int32_t val0 = 100; + int32_t val0 = 0; int32_t val1 = 0; + for (auto &cmd : camMasterCmds) { + // Get a valid parameter value range + int32_t minVal, maxVal, step; + pCamMaster->getIntParameterRange( + cmd, + [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { + minVal = val0; + maxVal = val1; + step = val2; + } + ); - pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program - result == EvsResult::INVALID_ARG); // Camera parameter is not supported + EvsResult result = EvsResult::OK; + if (cmd == CameraParam::ABSOLUTE_FOCUS) { + // Try to turn off auto-focus + int32_t val1 = 1; + pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val1, 0); + } - // Non-master client expects to receive a parameter change notification - // whenever a master client adjusts it. - InfoEventDesc aNotification = {}; + // Try to program a parameter + val0 = minVal + (std::rand() % (maxVal - minVal)); - pCamMaster->getParameter(CameraParam::BRIGHTNESS, - [&result, &val1](auto status, auto value) { - result = status; - if (status == EvsResult::OK) { - val1 = value; - } - }); - ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program - result == EvsResult::INVALID_ARG); // Camera parameter is not supported - if (result == EvsResult::OK) { - ASSERT_EQ(val0, val1) << "Values are not matched."; + // Rounding down + val0 = val0 - (val0 % step); + pCamMaster->setIntParameter(cmd, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); - // Verify a change notification - frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); - ASSERT_EQ(InfoEventType::PARAMETER_CHANGED, - static_cast(aNotification.aType)); - ASSERT_EQ(CameraParam::BRIGHTNESS, - static_cast(aNotification.payload[0])); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); - } + // Wait a moment + sleep(1); - // Try to program CameraParam::CONTRAST - val0 = 80; - val1 = 0; - pCamMaster->setParameter(CameraParam::CONTRAST, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program - result == EvsResult::INVALID_ARG); // Camera parameter is not supported + // Non-master client expects to receive a parameter change notification + // whenever a master client adjusts it. + EvsEvent aNotification = {}; - if (result == EvsResult::OK) { - pCamMaster->getParameter(CameraParam::CONTRAST, + pCamMaster->getIntParameter(cmd, [&result, &val1](auto status, auto value) { result = status; if (status == EvsResult::OK) { val1 = value; } }); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); ASSERT_EQ(val0, val1) << "Values are not matched."; - // Verify a change notification - frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); - ASSERT_EQ(InfoEventType::PARAMETER_CHANGED, - static_cast(aNotification.aType)); - ASSERT_EQ(CameraParam::CONTRAST, + frameHandlerNonMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); + ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, + static_cast(aNotification.aType)); + ASSERT_EQ(cmd, static_cast(aNotification.payload[0])); ASSERT_EQ(val1, static_cast(aNotification.payload[1])); } // Try to adjust a parameter via non-master client - pCamNonMaster->setParameter(CameraParam::CONTRAST, val0, + pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_TRUE(result == EvsResult::INVALID_ARG); + ASSERT_EQ(EvsResult::INVALID_ARG, result); // Non-master client attemps to be a master result = pCamNonMaster->setMaster(); - ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST); + ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result); // Master client retires from a master role result = pCamMaster->unsetMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); // Try to adjust a parameter after being retired - pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0, + pCamMaster->setIntParameter(camMasterCmds[0], val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_TRUE(result == EvsResult::INVALID_ARG); + ASSERT_EQ(EvsResult::INVALID_ARG, result); // Non-master client becomes a master result = pCamNonMaster->setMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); // Try to adjust a parameter via new master client - pCamNonMaster->setParameter(CameraParam::BRIGHTNESS, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program - result == EvsResult::INVALID_ARG); // Camera parameter is not supported + for (auto &cmd : camNonMasterCmds) { + // Get a valid parameter value range + int32_t minVal, maxVal, step; + pCamNonMaster->getIntParameterRange( + cmd, + [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { + minVal = val0; + maxVal = val1; + step = val2; + } + ); - // Wait a moment - sleep(1); + EvsResult result = EvsResult::OK; + if (cmd == CameraParam::ABSOLUTE_FOCUS) { + // Try to turn off auto-focus + int32_t val1 = 1; + pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val1, 0); + } - // Verify a change notification - if (result == EvsResult::OK) { - frameHandlerMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); - ASSERT_EQ(static_cast(aNotification.aType), - InfoEventType::PARAMETER_CHANGED); - ASSERT_EQ(static_cast(aNotification.payload[0]), - CameraParam::BRIGHTNESS); + // Try to program a parameter + val0 = minVal + (std::rand() % (maxVal - minVal)); + + // Rounding down + val0 = val0 - (val0 % step); + pCamNonMaster->setIntParameter(cmd, val0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + + // Wait a moment + sleep(1); + + // Non-master client expects to receive a parameter change notification + // whenever a master client adjusts it. + EvsEvent aNotification = {}; + + pCamNonMaster->getIntParameter(cmd, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val0, val1) << "Values are not matched."; + + // Verify a change notification + frameHandlerMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); + ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, + static_cast(aNotification.aType)); + ASSERT_EQ(cmd, + static_cast(aNotification.payload[0])); ASSERT_EQ(val1, static_cast(aNotification.payload[1])); } // New master retires from a master role result = pCamNonMaster->unsetMaster(); - ASSERT_TRUE(result == EvsResult::OK); + ASSERT_EQ(EvsResult::OK, result); // Shutdown frameHandlerMaster->shutdown(); @@ -943,9 +1060,18 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { TEST_F(EvsHidlTest, HighPriorityCameraClient) { ALOGI("Starting HighPriorityCameraClient test"); + if (mIsHwModule) { + // This test is not for HW module implementation. + return; + } + // Get the camera list loadCameraList(); + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + // Request exclusive access to the EVS display sp pDisplay = pEnumerator->openDisplay(); ASSERT_NE(pDisplay, nullptr); @@ -954,15 +1080,38 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { for (auto&& cam: cameraInfo) { // Create two clients sp pCam0 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam0, nullptr); sp pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId)) + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam1, nullptr); + // Get the parameter list; this test will use the first command in both + // lists. + std::vector cam0Cmds, cam1Cmds; + pCam0->getParameterList([&cam0Cmds](hidl_vec cmdList) { + cam0Cmds.reserve(cmdList.size()); + for (auto &&cmd : cmdList) { + cam0Cmds.push_back(cmd); + } + } + ); + + pCam1->getParameterList([&cam1Cmds](hidl_vec cmdList) { + cam1Cmds.reserve(cmdList.size()); + for (auto &&cmd : cmdList) { + cam1Cmds.push_back(cmd); + } + } + ); + if (cam0Cmds.size() < 1 || cam1Cmds.size() < 1) { + // Cannot execute this test. + return; + } + // Set up a frame receiver object which will fire up its own thread. sp frameHandler0 = new FrameHandler(pCam0, cam, pDisplay, @@ -982,67 +1131,121 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { frameHandler0->waitForFrameCount(1); frameHandler1->waitForFrameCount(1); - // Client 1 becomes a master and programs a brightness. + // Client 1 becomes a master and programs a parameter. EvsResult result = EvsResult::OK; - int32_t val0 = 100; + // Get a valid parameter value range + int32_t minVal, maxVal, step; + pCam1->getIntParameterRange( + cam1Cmds[0], + [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) { + minVal = val0; + maxVal = val1; + step = val2; + } + ); + + if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) { + // Try to turn off auto-focus + int32_t val1 = 0; + pCam1->getIntParameter(CameraParam::AUTO_FOCUS, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + if (val1 != 0) { + pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val1, 0); + } + } + + // Try to program a parameter with a random value [minVal, maxVal] + int32_t val0 = minVal + (std::rand() % (maxVal - minVal)); int32_t val1 = 0; - result = pCam1->setMaster(); - ASSERT_TRUE(result == EvsResult::OK); + // Rounding down + val0 = val0 - (val0 % step); - pCam1->setParameter(CameraParam::BRIGHTNESS, val0, + result = pCam1->setMaster(); + ASSERT_EQ(EvsResult::OK, result); + + pCam1->setIntParameter(cam1Cmds[0], val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); - + ASSERT_EQ(EvsResult::OK, result); // Verify a change notification - InfoEventDesc aNotification = {}; - if (result == EvsResult::OK) { - bool timeout = - frameHandler0->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); - ASSERT_FALSE(timeout) << "Expected event does not arrive"; - ASSERT_EQ(static_cast(aNotification.aType), - InfoEventType::PARAMETER_CHANGED); - ASSERT_EQ(static_cast(aNotification.payload[0]), - CameraParam::BRIGHTNESS); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); - } + EvsEvent aNotification = {}; + bool timeout = + frameHandler0->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); + ASSERT_FALSE(timeout) << "Expected event does not arrive"; + ASSERT_EQ(static_cast(aNotification.aType), + EvsEventType::PARAMETER_CHANGED); + ASSERT_EQ(static_cast(aNotification.payload[0]), + cam1Cmds[0]); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); // Client 0 steals a master role ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay)); - frameHandler1->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification); - ASSERT_EQ(static_cast(aNotification.aType), - InfoEventType::MASTER_RELEASED); + frameHandler1->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); + ASSERT_EQ(static_cast(aNotification.aType), + EvsEventType::MASTER_RELEASED); - // Client 0 programs a brightness - val0 = 50; + // Client 0 programs a parameter + val0 = minVal + (std::rand() % (maxVal - minVal)); val1 = 0; - pCam0->setParameter(CameraParam::BRIGHTNESS, val0, + + // Rounding down + val0 = val0 - (val0 % step); + + if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) { + // Try to turn off auto-focus + int32_t val1 = 0; + pCam0->getIntParameter(CameraParam::AUTO_FOCUS, + [&result, &val1](auto status, auto value) { + result = status; + if (status == EvsResult::OK) { + val1 = value; + } + }); + if (val1 != 0) { + pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &val1](auto status, auto effectiveValue) { + result = status; + val1 = effectiveValue; + }); + ASSERT_EQ(EvsResult::OK, result); + ASSERT_EQ(val1, 0); + } + } + + pCam0->setIntParameter(cam0Cmds[0], val0, [&result, &val1](auto status, auto effectiveValue) { result = status; val1 = effectiveValue; }); - ASSERT_TRUE(result == EvsResult::OK || - result == EvsResult::INVALID_ARG); + ASSERT_EQ(EvsResult::OK, result); // Verify a change notification - if (result == EvsResult::OK) { - bool timeout = - frameHandler1->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification); - ASSERT_FALSE(timeout) << "Expected event does not arrive"; - ASSERT_EQ(static_cast(aNotification.aType), - InfoEventType::PARAMETER_CHANGED); - ASSERT_EQ(static_cast(aNotification.payload[0]), - CameraParam::BRIGHTNESS); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); - } + timeout = + frameHandler1->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); + ASSERT_FALSE(timeout) << "Expected event does not arrive"; + ASSERT_EQ(static_cast(aNotification.aType), + EvsEventType::PARAMETER_CHANGED); + ASSERT_EQ(static_cast(aNotification.payload[0]), + cam0Cmds[0]); + ASSERT_EQ(val1, + static_cast(aNotification.payload[1])); // Turn off the display (yes, before the stream stops -- it should be handled) pDisplay->setDisplayState(DisplayState::NOT_VISIBLE); @@ -1061,6 +1264,248 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { } +/* + * CameraUseStreamConfigToDisplay: + * End to end test of data flowing from the camera to the display. Similar to + * CameraToDisplayRoundTrip test case but this case retrieves available stream + * configurations from EVS and uses one of them to start a video stream. + */ +TEST_F(EvsHidlTest, CameraUseStreamConfigToDisplay) { + ALOGI("Starting CameraUseStreamConfigToDisplay test"); + + // Get the camera list + loadCameraList(); + + // Request exclusive access to the EVS display + sp pDisplay = pEnumerator->openDisplay(); + ASSERT_NE(pDisplay, nullptr); + + // Test each reported camera + for (auto&& cam: cameraInfo) { + // choose a configuration that has a frame rate faster than minReqFps. + Stream targetCfg = {}; + const int32_t minReqFps = 15; + int32_t maxArea = 0; + camera_metadata_entry_t streamCfgs; + bool foundCfg = false; + if (!find_camera_metadata_entry( + reinterpret_cast(cam.metadata.data()), + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, + &streamCfgs)) { + // Stream configurations are found in metadata + RawStreamConfig *ptr = reinterpret_cast(streamCfgs.data.i32); + for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) { + if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && + ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) { + + if (ptr->width * ptr->height > maxArea && + ptr->framerate >= minReqFps) { + targetCfg.width = ptr->width; + targetCfg.height = ptr->height; + + maxArea = ptr->width * ptr->height; + foundCfg = true; + } + } + ++ptr; + } + } + targetCfg.format = + static_cast(HAL_PIXEL_FORMAT_RGBA_8888); + + if (!foundCfg) { + // Current EVS camera does not provide stream configurations in the + // metadata. + continue; + } + + sp pCam = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) + .withDefault(nullptr); + ASSERT_NE(pCam, nullptr); + + // Set up a frame receiver object which will fire up its own thread. + sp frameHandler = new FrameHandler(pCam, cam, + pDisplay, + FrameHandler::eAutoReturn); + + + // Activate the display + pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME); + + // Start the camera's video stream + bool startResult = frameHandler->startStream(); + ASSERT_TRUE(startResult); + + // Wait a while to let the data flow + static const int kSecondsToWait = 5; + const int streamTimeMs = kSecondsToWait * kSecondsToMilliseconds - + kMaxStreamStartMilliseconds; + const unsigned minimumFramesExpected = streamTimeMs * kMinimumFramesPerSecond / + kSecondsToMilliseconds; + sleep(kSecondsToWait); + unsigned framesReceived = 0; + unsigned framesDisplayed = 0; + frameHandler->getFramesCounters(&framesReceived, &framesDisplayed); + EXPECT_EQ(framesReceived, framesDisplayed); + EXPECT_GE(framesDisplayed, minimumFramesExpected); + + // Turn off the display (yes, before the stream stops -- it should be handled) + pDisplay->setDisplayState(DisplayState::NOT_VISIBLE); + + // Shut down the streamer + frameHandler->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCam); + } + + // Explicitly release the display + pEnumerator->closeDisplay(pDisplay); +} + + +/* + * MultiCameraStreamUseConfig: + * Verify that each client can start and stop video streams on the same + * underlying camera with same configuration. + */ +TEST_F(EvsHidlTest, MultiCameraStreamUseConfig) { + ALOGI("Starting MultiCameraStream test"); + + if (mIsHwModule) { + // This test is not for HW module implementation. + return; + } + + // Get the camera list + loadCameraList(); + + // Test each reported camera + for (auto&& cam: cameraInfo) { + // choose a configuration that has a frame rate faster than minReqFps. + Stream targetCfg = {}; + const int32_t minReqFps = 15; + int32_t maxArea = 0; + camera_metadata_entry_t streamCfgs; + bool foundCfg = false; + if (!find_camera_metadata_entry( + reinterpret_cast(cam.metadata.data()), + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, + &streamCfgs)) { + // Stream configurations are found in metadata + RawStreamConfig *ptr = reinterpret_cast(streamCfgs.data.i32); + for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) { + if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && + ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) { + + if (ptr->width * ptr->height > maxArea && + ptr->framerate >= minReqFps) { + targetCfg.width = ptr->width; + targetCfg.height = ptr->height; + + maxArea = ptr->width * ptr->height; + foundCfg = true; + } + } + ++ptr; + } + } + targetCfg.format = + static_cast(HAL_PIXEL_FORMAT_RGBA_8888); + + if (!foundCfg) { + ALOGI("Device %s does not provide a list of supported stream configurations, skipped", + cam.v1.cameraId.c_str()); + + continue; + } + + // Create the first camera client with a selected stream configuration. + sp pCam0 = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) + .withDefault(nullptr); + ASSERT_NE(pCam0, nullptr); + + // Try to create the second camera client with different stream + // configuration. + int32_t id = targetCfg.id; + targetCfg.id += 1; // EVS manager sees only the stream id. + sp pCam1 = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) + .withDefault(nullptr); + ASSERT_EQ(pCam1, nullptr); + + // Try again with same stream configuration. + targetCfg.id = id; + pCam1 = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) + .withDefault(nullptr); + ASSERT_NE(pCam1, nullptr); + + // Set up per-client frame receiver objects which will fire up its own thread + sp frameHandler0 = new FrameHandler(pCam0, cam, + nullptr, + FrameHandler::eAutoReturn); + ASSERT_NE(frameHandler0, nullptr); + + sp frameHandler1 = new FrameHandler(pCam1, cam, + nullptr, + FrameHandler::eAutoReturn); + ASSERT_NE(frameHandler1, nullptr); + + // Start the camera's video stream via client 0 + bool startResult = false; + startResult = frameHandler0->startStream() && + frameHandler1->startStream(); + ASSERT_TRUE(startResult); + + // Ensure the stream starts + frameHandler0->waitForFrameCount(1); + frameHandler1->waitForFrameCount(1); + + nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC); + + // Wait a bit, then ensure both clients get at least the required minimum number of frames + sleep(5); + nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC); + unsigned framesReceived0 = 0, framesReceived1 = 0; + frameHandler0->getFramesCounters(&framesReceived0, nullptr); + frameHandler1->getFramesCounters(&framesReceived1, nullptr); + framesReceived0 = framesReceived0 - 1; // Back out the first frame we already waited for + framesReceived1 = framesReceived1 - 1; // Back out the first frame we already waited for + nsecs_t runTime = end - firstFrame; + float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds); + float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds); + ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1); + EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond); + EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond); + + // Shutdown one client + frameHandler0->shutdown(); + + // Read frame counters again + frameHandler0->getFramesCounters(&framesReceived0, nullptr); + frameHandler1->getFramesCounters(&framesReceived1, nullptr); + + // Wait a bit again + sleep(5); + unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0; + frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr); + frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr); + EXPECT_EQ(framesReceived0, framesReceivedAfterStop0); + EXPECT_LT(framesReceived1, framesReceivedAfterStop1); + + // Shutdown another + frameHandler1->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCam0); + pEnumerator->closeCamera(pCam1); + } +} + + int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance()); ::testing::InitGoogleTest(&argc, argv); From 63cddfc13f74d8c3ddb217f2149ee1fbba18f4f1 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Sat, 12 Oct 2019 05:27:34 -0700 Subject: [PATCH 0180/1022] Explictly cast size_t into a long data type This change explictly casts size_t type variables to long data type in ALOG*, to avoid any build error due to inconsistent size_t type declarations between different build targets. Bug: 142545867 Change-Id: I587c7006a6ab69970b3a507a6160b3decd4bfd5a Signed-off-by: Changyeon Jo --- automotive/evs/1.1/default/ConfigManager.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/automotive/evs/1.1/default/ConfigManager.cpp b/automotive/evs/1.1/default/ConfigManager.cpp index 4f46f9dbca..96a2f98576 100644 --- a/automotive/evs/1.1/default/ConfigManager.cpp +++ b/automotive/evs/1.1/default/ConfigManager.cpp @@ -321,22 +321,22 @@ bool ConfigManager::constructCameraMetadata(unique_ptr &aCamera, /* may exceed preallocated capacity */ ALOGE("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled", - get_camera_metadata_entry_count(aCamera->characteristics), - get_camera_metadata_entry_capacity(aCamera->characteristics), - get_camera_metadata_data_count(aCamera->characteristics), - get_camera_metadata_data_capacity(aCamera->characteristics)); + (long)get_camera_metadata_entry_count(aCamera->characteristics), + (long)get_camera_metadata_entry_capacity(aCamera->characteristics), + (long)get_camera_metadata_data_count(aCamera->characteristics), + (long)get_camera_metadata_data_capacity(aCamera->characteristics)); ALOGE("\tCurrent metadata entry requires %ld bytes", - calculate_camera_metadata_entry_data_size(tag, entry.second)); + (long)calculate_camera_metadata_entry_data_size(tag, entry.second)); success = false; } } ALOGV("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled", - get_camera_metadata_entry_count(aCamera->characteristics), - get_camera_metadata_entry_capacity(aCamera->characteristics), - get_camera_metadata_data_count(aCamera->characteristics), - get_camera_metadata_data_capacity(aCamera->characteristics)); + (long)get_camera_metadata_entry_count(aCamera->characteristics), + (long)get_camera_metadata_entry_capacity(aCamera->characteristics), + (long)get_camera_metadata_data_count(aCamera->characteristics), + (long)get_camera_metadata_data_capacity(aCamera->characteristics)); return success; } From 6d72a8110f5812c50ce07480a72d2e73d9590129 Mon Sep 17 00:00:00 2001 From: "Harpreet \\\"Eli\\\" Sangha" Date: Tue, 15 Oct 2019 02:24:56 +0900 Subject: [PATCH 0181/1022] Fix Vibrator 1.4 Hashes Ordering in current.txt Test: Build Change-Id: I7821d73d247a7ff8c60cfb579f357f4ddfb693c2 Signed-off-by: Harpreet \"Eli\" Sangha --- current.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/current.txt b/current.txt index 4e0d0e0bab..87649d2bd9 100644 --- a/current.txt +++ b/current.txt @@ -595,6 +595,6 @@ dd4b7cfbb6e1c6ff011c33920762ad89dd02240c63a4d3a3d5037f154eae3e3b android.hardwar 619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback 6fe09b18e913608579638594788198ec45bb2369e567d7df661db46c4f0e5f08 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 91931b05bd70ea6bdffbe075086183f803379571788564e28854207620eb75cf android.hardware.wifi.supplicant@1.3::types -033eae03c09ebc75e82db37bc39995dfaa9086745577b44d9e14e9ccb48bd8cc android.hardware.vibrator@1.4::types 544049dcda3f943ad67d83d5277f06681a3782982a9af5a78b5d4e8d295d061a android.hardware.vibrator@1.4::IVibrator 5e1c12efbbba89c9143d10b1b90eceff8bc79aa079f5106215b528e104fef101 android.hardware.vibrator@1.4::IVibratorCallback +033eae03c09ebc75e82db37bc39995dfaa9086745577b44d9e14e9ccb48bd8cc android.hardware.vibrator@1.4::types From 0ede089f5ba5277fef28fe0e7a43da81f0cefde7 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 12 Oct 2019 15:19:53 -0700 Subject: [PATCH 0182/1022] Fix requests for IBootControl 1.0 when using the 1.1 HAL. Bug: 138861550 Test: cuttlefish boots Change-Id: I10587a70dca716366a5cf48c8bc8c1bc4fb9f93a --- boot/1.1/default/Android.bp | 5 +++++ boot/1.1/default/android.hardware.boot@1.1.xml | 7 +++++++ boot/1.1/default/service.cpp | 4 ++-- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 boot/1.1/default/android.hardware.boot@1.1.xml diff --git a/boot/1.1/default/Android.bp b/boot/1.1/default/Android.bp index dca5c2635a..abf1bf9530 100644 --- a/boot/1.1/default/Android.bp +++ b/boot/1.1/default/Android.bp @@ -1,5 +1,6 @@ cc_library_shared { name: "android.hardware.boot@1.1-impl", + stem: "android.hardware.boot@1.0-impl-1.1", defaults: [ "hidl_defaults", "libboot_control_defaults", @@ -31,6 +32,10 @@ cc_binary { init_rc: ["android.hardware.boot@1.1-service.rc"], srcs: ["service.cpp"], + vintf_fragments: [ + "android.hardware.boot@1.1.xml", + ], + shared_libs: [ "liblog", "libhardware", diff --git a/boot/1.1/default/android.hardware.boot@1.1.xml b/boot/1.1/default/android.hardware.boot@1.1.xml new file mode 100644 index 0000000000..83d5d2e8de --- /dev/null +++ b/boot/1.1/default/android.hardware.boot@1.1.xml @@ -0,0 +1,7 @@ + + + android.hardware.boot + hwbinder + @1.1::IBootControl/default + + diff --git a/boot/1.1/default/service.cpp b/boot/1.1/default/service.cpp index b24b46456a..93eaedab8d 100644 --- a/boot/1.1/default/service.cpp +++ b/boot/1.1/default/service.cpp @@ -15,11 +15,11 @@ */ #define LOG_TAG "android.hardware.boot@1.1-service" -#include +#include #include using android::hardware::defaultPassthroughServiceImplementation; -using ::android::hardware::boot::V1_1::IBootControl; +using ::android::hardware::boot::V1_0::IBootControl; int main(int /* argc */, char* /* argv */[]) { return defaultPassthroughServiceImplementation(); From 54a3b0b46874a5d5d3e0a4d049b7e38a57236f03 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Tue, 15 Oct 2019 15:22:45 -0700 Subject: [PATCH 0183/1022] Convert VtsHalCasV1_0/1_1TargetTest to be parameterized test Bug: 142397658 Test: atest VtsHalCasV1_1TargetTest atest VtsHalCasV1_1Target atest VtsHalCasV1_0TargetTest atest VtsHalCasV1_0Target Change-Id: Ie3708d9fcd78f7d1200124d4d50b74b88a038075 --- cas/1.0/vts/functional/Android.bp | 2 +- .../functional/VtsHalCasV1_0TargetTest.cpp | 54 +++++++------------ cas/1.1/vts/functional/Android.bp | 2 +- .../functional/VtsHalCasV1_1TargetTest.cpp | 36 ++++--------- 4 files changed, 32 insertions(+), 62 deletions(-) diff --git a/cas/1.0/vts/functional/Android.bp b/cas/1.0/vts/functional/Android.bp index 622baa5988..ab39c0e93b 100644 --- a/cas/1.0/vts/functional/Android.bp +++ b/cas/1.0/vts/functional/Android.bp @@ -29,6 +29,6 @@ cc_test { shared_libs: [ "libbinder", ], - test_suites: ["general-tests"], + test_suites: ["general-tests", "vts-core"], } diff --git a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp index f0bba57137..0f16de5e90 100644 --- a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp +++ b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp @@ -16,8 +16,6 @@ #define LOG_TAG "mediacas_hidl_hal_test" -#include -#include #include #include #include @@ -27,8 +25,11 @@ #include #include #include +#include +#include #include #include +#include #include #include #include @@ -208,29 +209,16 @@ void MediaCasListener::testEventEcho(sp& mediaCas, int32_t& event, int32_t EXPECT_TRUE(mEventData == eventData); } -// Test environment for Cas HIDL HAL. -class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static CasHidlEnvironment* Instance() { - static CasHidlEnvironment* instance = new CasHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { registerTestService(); } -}; - -class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase { - public: +class MediaCasHidlTest : public testing::TestWithParam { + public: virtual void SetUp() override { - mService = ::testing::VtsHalHidlTargetTestBase::getService( - CasHidlEnvironment::Instance()->getServiceName()); + mService = IMediaCasService::getService(GetParam()); ASSERT_NE(mService, nullptr); } - sp mService; + sp mService = nullptr; - protected: + protected: static void description(const std::string& description) { RecordProperty("description", description); } @@ -419,7 +407,7 @@ class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionResult(returnVoid.isOk()); } -TEST_F(MediaCasHidlTest, EnumeratePlugins) { +TEST_P(MediaCasHidlTest, EnumeratePlugins) { description("Test enumerate plugins"); hidl_vec descriptors; EXPECT_TRUE(mService @@ -440,7 +428,7 @@ TEST_F(MediaCasHidlTest, EnumeratePlugins) { } } -TEST_F(MediaCasHidlTest, TestInvalidSystemIdFails) { +TEST_P(MediaCasHidlTest, TestInvalidSystemIdFails) { description("Test failure for invalid system ID"); sp casListener = new MediaCasListener(); @@ -458,7 +446,7 @@ TEST_F(MediaCasHidlTest, TestInvalidSystemIdFails) { EXPECT_EQ(descramblerBase, nullptr); } -TEST_F(MediaCasHidlTest, TestClearKeyPluginInstalled) { +TEST_P(MediaCasHidlTest, TestClearKeyPluginInstalled) { description("Test if ClearKey plugin is installed"); hidl_vec descriptors; EXPECT_TRUE(mService @@ -480,7 +468,7 @@ TEST_F(MediaCasHidlTest, TestClearKeyPluginInstalled) { ASSERT_TRUE(false) << "ClearKey plugin not installed"; } -TEST_F(MediaCasHidlTest, TestClearKeyApis) { +TEST_P(MediaCasHidlTest, TestClearKeyApis) { description("Test that valid call sequences succeed"); ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID)); @@ -584,7 +572,7 @@ TEST_F(MediaCasHidlTest, TestClearKeyApis) { EXPECT_EQ(Status::OK, returnStatus); } -TEST_F(MediaCasHidlTest, TestClearKeySessionClosedAfterRelease) { +TEST_P(MediaCasHidlTest, TestClearKeySessionClosedAfterRelease) { description("Test that all sessions are closed after a MediaCas object is released"); ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID)); @@ -611,7 +599,7 @@ TEST_F(MediaCasHidlTest, TestClearKeySessionClosedAfterRelease) { EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus); } -TEST_F(MediaCasHidlTest, TestClearKeyErrors) { +TEST_P(MediaCasHidlTest, TestClearKeyErrors) { description("Test that invalid call sequences fail with expected error codes"); ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID)); @@ -700,7 +688,7 @@ TEST_F(MediaCasHidlTest, TestClearKeyErrors) { EXPECT_FALSE(mDescramblerBase->requiresSecureDecoderComponent("bad")); } -TEST_F(MediaCasHidlTest, TestClearKeyOobFails) { +TEST_P(MediaCasHidlTest, TestClearKeyOobFails) { description("Test that oob descramble request fails with expected error"); ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID)); @@ -849,11 +837,7 @@ TEST_F(MediaCasHidlTest, TestClearKeyOobFails) { } // anonymous namespace -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - CasHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; -} +INSTANTIATE_TEST_SUITE_P( + PerInstance, MediaCasHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/cas/1.1/vts/functional/Android.bp b/cas/1.1/vts/functional/Android.bp index 8afd19abda..9e8eb52efe 100644 --- a/cas/1.1/vts/functional/Android.bp +++ b/cas/1.1/vts/functional/Android.bp @@ -30,6 +30,6 @@ cc_test { shared_libs: [ "libbinder", ], - test_suites: ["general-tests"], + test_suites: ["general-tests", "vts-core"], } diff --git a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp index 0264bddedd..7e5a61a6ff 100644 --- a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp +++ b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp @@ -27,8 +27,11 @@ #include #include #include +#include +#include #include #include +#include #include #include #include @@ -251,27 +254,14 @@ void MediaCasListener::testSessionEventEcho(sp& mediaCas, const hidl_vec(); } -}; - -class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class MediaCasHidlTest : public testing::TestWithParam { public: virtual void SetUp() override { - mService = ::testing::VtsHalHidlTargetTestBase::getService( - CasHidlEnvironment::Instance()->getServiceName()); + mService = IMediaCasService::getService(GetParam()); ASSERT_NE(mService, nullptr); } - sp mService; + sp mService = nullptr; protected: static void description(const std::string& description) { @@ -453,7 +443,7 @@ class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionResult(returnVoid.isOk()); } -TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) { +TEST_P(MediaCasHidlTest, TestClearKeyApisWithSession) { description("Test that valid call sequences with SessionEvent send and receive"); ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID)); @@ -561,11 +551,7 @@ TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) { } // anonymous namespace -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - CasHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; -} +INSTANTIATE_TEST_SUITE_P( + PerInstance, MediaCasHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)), + android::hardware::PrintInstanceNameToString); From b25ffb297b052a4e5cfc484ee821a749e6906979 Mon Sep 17 00:00:00 2001 From: Nick Chalko Date: Tue, 15 Oct 2019 15:53:07 -0700 Subject: [PATCH 0184/1022] Fix spelling error. Test: n/a Change-Id: Ia0be33f6295dcdc1606c3f0c619ff4b1a372ff22 --- tv/tuner/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tv/tuner/README.md b/tv/tuner/README.md index a833c8740c..aa1f62d422 100644 --- a/tv/tuner/README.md +++ b/tv/tuner/README.md @@ -4,7 +4,7 @@ TV specific tuners. -Sett 1.0/ITuner.hal for an overview. +See 1.0/ITuner.hal for an overview. *** note **Warning:** The HALs are not (yet) frozen, as the HAL definition is From 9a1e5aa93a17037bfef8cf8d8e156042ca2c814e Mon Sep 17 00:00:00 2001 From: shubang Date: Tue, 15 Oct 2019 22:18:11 -0700 Subject: [PATCH 0185/1022] Fix minor issues in dmux default impl Test: mannual Change-Id: If74df110cd9eda2dadb87a8d659d83233ad75d88 --- tv/tuner/1.0/default/Demux.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp index b18d4df9e6..8bb79f9702 100644 --- a/tv/tuner/1.0/default/Demux.cpp +++ b/tv/tuner/1.0/default/Demux.cpp @@ -479,7 +479,8 @@ Result Demux::startPesFilterHandler(uint32_t filterId) { if (prefix == 0x000001) { // TODO handle mulptiple Pes filters mPesSizeLeft = - (mFilterOutputs[filterId][i + 7] << 8) | mFilterOutputs[filterId][i + 8]; + (mFilterOutputs[filterId][i + 8] << 8) | mFilterOutputs[filterId][i + 9]; + mPesSizeLeft += 6; ALOGD("[Demux] pes data length %d", mPesSizeLeft); } else { continue; @@ -489,7 +490,7 @@ Result Demux::startPesFilterHandler(uint32_t filterId) { int endPoint = min(184, mPesSizeLeft); // append data and check size vector::const_iterator first = mFilterOutputs[filterId].begin() + i + 4; - vector::const_iterator last = mFilterOutputs[filterId].begin() + i + 3 + endPoint; + vector::const_iterator last = mFilterOutputs[filterId].begin() + i + 4 + endPoint; mPesOutput.insert(mPesOutput.end(), first, last); // size does not match then continue mPesSizeLeft -= endPoint; @@ -800,7 +801,7 @@ void Demux::maySendInputStatusCallback() { void Demux::maySendFilterStatusCallback(uint32_t filterId) { std::lock_guard lock(mFilterStatusLock); int availableToRead = mFilterMQs[filterId]->availableToRead(); - int availableToWrite = mInputMQ->availableToWrite(); + int availableToWrite = mFilterMQs[filterId]->availableToWrite(); int fmqSize = mFilterMQs[filterId]->getQuantumCount(); DemuxFilterStatus newStatus = @@ -885,7 +886,6 @@ void Demux::broadcastInputThreadLoop() { byteBuffer[index] = static_cast(buffer[index]); } startTsFilter(byteBuffer); - inputData.seekg(packetSize, inputData.cur); } startFilterDispatcher(); sleep(1); From 6beae321c645c559cb64dde0c15f954aaeef3c27 Mon Sep 17 00:00:00 2001 From: Patrik Fimml Date: Wed, 9 Oct 2019 17:34:01 +0200 Subject: [PATCH 0186/1022] Wifi AP: Remove HAL-level MAC randomization Randomization will be handled by framework code instead. This also means WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION is replaced with a framework config option (config_wifi_ap_mac_randomization_supported), which can be set from device overlays. Bug: 142387520 Test: atest android.hardware.wifi@1.0-service-tests; adb shell LD_LIBRARY_PATH=:/system/lib64/vndk-R /data/local/tmp/android.hardware.wifi@1.0-service-tests/x86_64/android.hardware.wifi@1.0-service-tests Test: vts-tradefed run vts --primary-abi-only --skip-device-info -l DEBUG --include-filter VtsHalWifiApV1_4Target Test: lunch hawk-userdebug; m (uses DISABLE_AP_MAC_RANDOMIZATION) Change-Id: I2dbf1158368ce3c39980501f892c6de1ffb3f748 --- wifi/1.4/default/Android.mk | 1 - .../tests/wifi_ap_iface_unit_tests.cpp | 79 ------------------- wifi/1.4/default/wifi_ap_iface.cpp | 19 +---- wifi/1.4/default/wifi_ap_iface.h | 10 +-- wifi/1.4/default/wifi_chip.cpp | 4 +- wifi/1.4/default/wifi_chip.h | 1 - wifi/1.4/default/wifi_feature_flags.cpp | 14 ++-- wifi/1.4/default/wifi_feature_flags.h | 1 - 8 files changed, 12 insertions(+), 117 deletions(-) delete mode 100644 wifi/1.4/default/tests/wifi_ap_iface_unit_tests.cpp diff --git a/wifi/1.4/default/Android.mk b/wifi/1.4/default/Android.mk index 943beccc68..ab76ff66e2 100644 --- a/wifi/1.4/default/Android.mk +++ b/wifi/1.4/default/Android.mk @@ -150,7 +150,6 @@ LOCAL_SRC_FILES := \ tests/mock_wifi_legacy_hal.cpp \ tests/mock_wifi_mode_controller.cpp \ tests/ringbuffer_unit_tests.cpp \ - tests/wifi_ap_iface_unit_tests.cpp \ tests/wifi_nan_iface_unit_tests.cpp \ tests/wifi_chip_unit_tests.cpp \ tests/wifi_iface_util_unit_tests.cpp diff --git a/wifi/1.4/default/tests/wifi_ap_iface_unit_tests.cpp b/wifi/1.4/default/tests/wifi_ap_iface_unit_tests.cpp deleted file mode 100644 index 230edd2ee3..0000000000 --- a/wifi/1.4/default/tests/wifi_ap_iface_unit_tests.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include - -#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38 -#include "wifi_ap_iface.h" - -#include "mock_interface_tool.h" -#include "mock_wifi_feature_flags.h" -#include "mock_wifi_iface_util.h" -#include "mock_wifi_legacy_hal.h" - -using testing::NiceMock; -using testing::Return; -using testing::Test; - -namespace { -constexpr char kIfaceName[] = "mockWlan0"; -} // namespace - -namespace android { -namespace hardware { -namespace wifi { -namespace V1_4 { -namespace implementation { - -class WifiApIfaceTest : public Test { - protected: - std::shared_ptr> iface_tool_{ - new NiceMock}; - std::shared_ptr> legacy_hal_{ - new NiceMock(iface_tool_)}; - std::shared_ptr> iface_util_{ - new NiceMock(iface_tool_)}; - std::shared_ptr> - feature_flags_{new NiceMock}; -}; - -TEST_F(WifiApIfaceTest, SetRandomMacAddressIfFeatureEnabled) { - EXPECT_CALL(*feature_flags_, isApMacRandomizationDisabled()) - .WillOnce(testing::Return(false)); - EXPECT_CALL(*iface_util_, getOrCreateRandomMacAddress()) - .WillOnce(testing::Return(std::array{0, 0, 0, 0, 0, 0})); - EXPECT_CALL(*iface_util_, setMacAddress(testing::_, testing::_)) - .WillOnce(testing::Return(true)); - sp ap_iface = - new WifiApIface(kIfaceName, legacy_hal_, iface_util_, feature_flags_); -} - -TEST_F(WifiApIfaceTest, DontSetRandomMacAddressIfFeatureDisabled) { - EXPECT_CALL(*feature_flags_, isApMacRandomizationDisabled()) - .WillOnce(testing::Return(true)); - EXPECT_CALL(*iface_util_, getOrCreateRandomMacAddress()).Times(0); - EXPECT_CALL(*iface_util_, setMacAddress(testing::_, testing::_)).Times(0); - sp ap_iface = - new WifiApIface(kIfaceName, legacy_hal_, iface_util_, feature_flags_); -} -} // namespace implementation -} // namespace V1_4 -} // namespace wifi -} // namespace hardware -} // namespace android diff --git a/wifi/1.4/default/wifi_ap_iface.cpp b/wifi/1.4/default/wifi_ap_iface.cpp index b8609106b6..e677f197b8 100644 --- a/wifi/1.4/default/wifi_ap_iface.cpp +++ b/wifi/1.4/default/wifi_ap_iface.cpp @@ -31,26 +31,11 @@ using hidl_return_util::validateAndCall; WifiApIface::WifiApIface( const std::string& ifname, const std::weak_ptr legacy_hal, - const std::weak_ptr iface_util, - const std::weak_ptr feature_flags) + const std::weak_ptr iface_util) : ifname_(ifname), legacy_hal_(legacy_hal), iface_util_(iface_util), - feature_flags_(feature_flags), - is_valid_(true) { - if (feature_flags_.lock()->isApMacRandomizationDisabled()) { - LOG(INFO) << "AP MAC randomization disabled"; - return; - } - LOG(INFO) << "AP MAC randomization enabled"; - // Set random MAC address - std::array randomized_mac = - iface_util_.lock()->getOrCreateRandomMacAddress(); - bool status = iface_util_.lock()->setMacAddress(ifname_, randomized_mac); - if (!status) { - LOG(ERROR) << "Failed to set random mac address"; - } -} + is_valid_(true) {} void WifiApIface::invalidate() { legacy_hal_.reset(); diff --git a/wifi/1.4/default/wifi_ap_iface.h b/wifi/1.4/default/wifi_ap_iface.h index cb3ed3d29b..4f3438c298 100644 --- a/wifi/1.4/default/wifi_ap_iface.h +++ b/wifi/1.4/default/wifi_ap_iface.h @@ -20,7 +20,6 @@ #include #include -#include "wifi_feature_flags.h" #include "wifi_iface_util.h" #include "wifi_legacy_hal.h" @@ -36,11 +35,9 @@ using namespace android::hardware::wifi::V1_0; */ class WifiApIface : public V1_4::IWifiApIface { public: - WifiApIface( - const std::string& ifname, - const std::weak_ptr legacy_hal, - const std::weak_ptr iface_util, - const std::weak_ptr feature_flags); + WifiApIface(const std::string& ifname, + const std::weak_ptr legacy_hal, + const std::weak_ptr iface_util); // Refer to |WifiChip::invalidate()|. void invalidate(); bool isValid(); @@ -72,7 +69,6 @@ class WifiApIface : public V1_4::IWifiApIface { std::string ifname_; std::weak_ptr legacy_hal_; std::weak_ptr iface_util_; - std::weak_ptr feature_flags_; bool is_valid_; DISALLOW_COPY_AND_ASSIGN(WifiApIface); diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp index 5a14b01c37..408096fdc0 100644 --- a/wifi/1.4/default/wifi_chip.cpp +++ b/wifi/1.4/default/wifi_chip.cpp @@ -321,7 +321,6 @@ WifiChip::WifiChip( legacy_hal_(legacy_hal), mode_controller_(mode_controller), iface_util_(iface_util), - feature_flags_(feature_flags), is_valid_(true), current_mode_id_(feature_flags::chip_mode_ids::kInvalid), modes_(feature_flags.lock()->getChipModes()), @@ -806,8 +805,7 @@ std::pair> WifiChip::createApIfaceInternal() { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } std::string ifname = allocateApIfaceName(); - sp iface = - new WifiApIface(ifname, legacy_hal_, iface_util_, feature_flags_); + sp iface = new WifiApIface(ifname, legacy_hal_, iface_util_); ap_ifaces_.push_back(iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) { diff --git a/wifi/1.4/default/wifi_chip.h b/wifi/1.4/default/wifi_chip.h index ae9af9099c..0d7061c0e3 100644 --- a/wifi/1.4/default/wifi_chip.h +++ b/wifi/1.4/default/wifi_chip.h @@ -251,7 +251,6 @@ class WifiChip : public V1_3::IWifiChip { std::weak_ptr legacy_hal_; std::weak_ptr mode_controller_; std::weak_ptr iface_util_; - std::weak_ptr feature_flags_; std::vector> ap_ifaces_; std::vector> nan_ifaces_; std::vector> p2p_ifaces_; diff --git a/wifi/1.4/default/wifi_feature_flags.cpp b/wifi/1.4/default/wifi_feature_flags.cpp index f9746eb076..195b460dfe 100644 --- a/wifi/1.4/default/wifi_feature_flags.cpp +++ b/wifi/1.4/default/wifi_feature_flags.cpp @@ -145,10 +145,12 @@ static const std::vector kChipModes{ #undef NAN #ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION -static const bool wifiHidlFeatureDisableApMacRandomization = true; -#else -static const bool wifiHidlFeatureDisableApMacRandomization = false; -#endif // WIFI_HIDL_FEATURE_DISABLE_AP +#pragma message \ + "WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION is deprecated; override " \ + "'config_wifi_ap_randomization_supported' in " \ + "frameworks/base/core/res/res/values/config.xml in the device overlay " \ + "instead" +#endif // WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION WifiFeatureFlags::WifiFeatureFlags() {} @@ -156,10 +158,6 @@ std::vector WifiFeatureFlags::getChipModes() { return kChipModes; } -bool WifiFeatureFlags::isApMacRandomizationDisabled() { - return wifiHidlFeatureDisableApMacRandomization; -} - } // namespace feature_flags } // namespace implementation } // namespace V1_4 diff --git a/wifi/1.4/default/wifi_feature_flags.h b/wifi/1.4/default/wifi_feature_flags.h index 4e146cdfc6..292dedfe19 100644 --- a/wifi/1.4/default/wifi_feature_flags.h +++ b/wifi/1.4/default/wifi_feature_flags.h @@ -43,7 +43,6 @@ class WifiFeatureFlags { virtual ~WifiFeatureFlags() = default; virtual std::vector getChipModes(); - virtual bool isApMacRandomizationDisabled(); }; } // namespace feature_flags From 75cc7bf2fee72bf6a00ef990cc6d10acd5b4c7b3 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Thu, 26 Sep 2019 13:17:01 -0700 Subject: [PATCH 0187/1022] MH2 | Implement wakelock processing thread Bug: 136511617 Test: Unit tests cannot be written for this change. Integration testing will be performed later. Change-Id: I651b5fde77c6017b3270413de896a947d95ff5f8 --- sensors/2.0/multihal/Android.bp | 5 +- sensors/2.0/multihal/HalProxy.cpp | 155 +++++++++++++----- sensors/2.0/multihal/ScopedWakelock.cpp | 12 +- sensors/2.0/multihal/include/HalProxy.h | 124 +++++++++----- sensors/2.0/multihal/include/ScopedWakelock.h | 35 +++- sensors/2.0/multihal/tests/Android.bp | 6 + sensors/2.0/multihal/tests/HalProxy_test.cpp | 59 ++++++- 7 files changed, 305 insertions(+), 91 deletions(-) diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp index 710835f84d..5c6767671e 100644 --- a/sensors/2.0/multihal/Android.bp +++ b/sensors/2.0/multihal/Android.bp @@ -28,6 +28,7 @@ cc_defaults { "libpower", "libutils", ], + cflags: ["-DLOG_TAG=\"SensorsMultiHal\""], } cc_binary { @@ -45,7 +46,6 @@ cc_binary { ], init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"], vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"], - cflags: ["-DLOG_TAG=\"SensorsMultiHal\""], } cc_library_headers { @@ -66,4 +66,7 @@ cc_test_library { export_header_lib_headers: [ "android.hardware.sensors@2.0-multihal.header", ], + shared_libs: [ + "libutils", + ], } diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index 5aa3b3d22b..d66721866c 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -24,6 +24,7 @@ #include +#include #include #include #include @@ -35,6 +36,9 @@ namespace V2_0 { namespace implementation { using ::android::hardware::sensors::V2_0::EventQueueFlagBits; +using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; +using ::android::hardware::sensors::V2_0::implementation::getTimeNow; +using ::android::hardware::sensors::V2_0::implementation::kWakelockTimeoutNs; typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*); @@ -53,23 +57,23 @@ uint32_t setSubHalIndex(uint32_t sensorHandle, size_t subHalIndex) { HalProxy::HalProxy() { const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf"; initializeSubHalListFromConfigFile(kMultiHalConfigFile); - initializeSubHalCallbacksAndSensorList(); + init(); } HalProxy::HalProxy(std::vector& subHalList) : mSubHalList(subHalList) { - initializeSubHalCallbacksAndSensorList(); + init(); } HalProxy::~HalProxy() { - { - std::lock_guard lockGuard(mEventQueueWriteMutex); - mPendingWritesRun = false; - mEventQueueWriteCV.notify_one(); - } + mThreadsRun.store(false); + mWakelockCV.notify_one(); + mEventQueueWriteCV.notify_one(); if (mPendingWritesThread.joinable()) { mPendingWritesThread.join(); } - // TODO: Cleanup wakeup thread once it is implemented + if (mWakelockThread.joinable()) { + mWakelockThread.join(); + } } Return HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) { @@ -140,7 +144,7 @@ Return HalProxy::initialize( } mPendingWritesThread = std::thread(startPendingWritesThread, this); - // TODO: start threads to read wake locks. + mWakelockThread = std::thread(startWakelockThread, this); for (size_t i = 0; i < mSubHalList.size(); i++) { auto subHal = mSubHalList[i]; @@ -322,7 +326,7 @@ void HalProxy::initializeSensorList() { } } -void HalProxy::initializeSubHalCallbacksAndSensorList() { +void HalProxy::init() { initializeSubHalCallbacks(); initializeSensorList(); } @@ -334,11 +338,12 @@ void HalProxy::startPendingWritesThread(HalProxy* halProxy) { void HalProxy::handlePendingWrites() { // TODO: Find a way to optimize locking strategy maybe using two mutexes instead of one. std::unique_lock lock(mEventQueueWriteMutex); - while (mPendingWritesRun) { + while (mThreadsRun.load()) { mEventQueueWriteCV.wait( - lock, [&] { return !mPendingWriteEventsQueue.empty() || !mPendingWritesRun; }); - if (!mPendingWriteEventsQueue.empty() && mPendingWritesRun) { - std::vector& pendingWriteEvents = mPendingWriteEventsQueue.front(); + lock, [&] { return !mPendingWriteEventsQueue.empty() || !mThreadsRun.load(); }); + if (mThreadsRun.load()) { + std::vector& pendingWriteEvents = mPendingWriteEventsQueue.front().first; + size_t numWakeupEvents = mPendingWriteEventsQueue.front().second; size_t eventQueueSize = mEventQueue->getQuantumCount(); size_t numToWrite = std::min(pendingWriteEvents.size(), eventQueueSize); lock.unlock(); @@ -348,10 +353,16 @@ void HalProxy::handlePendingWrites() { pendingWriteEvents.data(), numToWrite, static_cast(EventQueueFlagBits::EVENTS_READ), static_cast(EventQueueFlagBits::READ_AND_PROCESS), - kWakelockTimeoutNs, mEventQueueFlag)) { + kPendingWriteTimeoutNs, mEventQueueFlag)) { ALOGE("Dropping %zu events after blockingWrite failed.", numToWrite); - } else { - mEventQueueFlag->wake(static_cast(EventQueueFlagBits::READ_AND_PROCESS)); + if (numWakeupEvents > 0) { + if (pendingWriteEvents.size() > eventQueueSize) { + decrementRefCountAndMaybeReleaseWakelock( + countNumWakeupEvents(pendingWriteEvents, eventQueueSize)); + } else { + decrementRefCountAndMaybeReleaseWakelock(numWakeupEvents); + } + } } lock.lock(); if (pendingWriteEvents.size() > eventQueueSize) { @@ -366,9 +377,60 @@ void HalProxy::handlePendingWrites() { } } -void HalProxy::postEventsToMessageQueue(const std::vector& events) { +void HalProxy::startWakelockThread(HalProxy* halProxy) { + halProxy->handleWakelocks(); +} + +void HalProxy::handleWakelocks() { + std::unique_lock lock(mWakelockMutex); + while (mThreadsRun.load()) { + mWakelockCV.wait(lock, [&] { return mWakelockRefCount > 0 || !mThreadsRun.load(); }); + if (mThreadsRun.load()) { + int64_t timeLeft; + if (sharedWakelockDidTimeout(&timeLeft)) { + resetSharedWakelock(); + } else { + uint32_t numWakeLocksProcessed; + lock.unlock(); + bool success = mWakeLockQueue->readBlocking( + &numWakeLocksProcessed, 1, 0, + static_cast(WakeLockQueueFlagBits::DATA_WRITTEN), timeLeft); + lock.lock(); + if (success) { + decrementRefCountAndMaybeReleaseWakelock( + static_cast(numWakeLocksProcessed)); + } + } + } + } + resetSharedWakelock(); +} + +bool HalProxy::sharedWakelockDidTimeout(int64_t* timeLeft) { + bool didTimeout; + int64_t duration = getTimeNow() - mWakelockTimeoutStartTime; + if (duration > kWakelockTimeoutNs) { + didTimeout = true; + } else { + didTimeout = false; + *timeLeft = kWakelockTimeoutNs - duration; + } + return didTimeout; +} + +void HalProxy::resetSharedWakelock() { + std::lock_guard lockGuard(mWakelockMutex); + decrementRefCountAndMaybeReleaseWakelock(mWakelockRefCount); + mWakelockTimeoutResetTime = getTimeNow(); +} + +void HalProxy::postEventsToMessageQueue(const std::vector& events, size_t numWakeupEvents, + ScopedWakelock wakelock) { size_t numToWrite = 0; std::lock_guard lock(mEventQueueWriteMutex); + if (wakelock.isLocked()) { + incrementRefCountAndMaybeAcquireWakelock(numWakeupEvents); + } if (mPendingWriteEventsQueue.empty()) { numToWrite = std::min(events.size(), mEventQueue->availableToWrite()); if (numToWrite > 0) { @@ -384,28 +446,37 @@ void HalProxy::postEventsToMessageQueue(const std::vector& events) { if (numToWrite < events.size()) { // TODO: Bound the mPendingWriteEventsQueue so that we do not trigger OOMs if framework // stalls - mPendingWriteEventsQueue.push( - std::vector(events.begin() + numToWrite, events.end())); + std::vector eventsLeft(events.begin() + numToWrite, events.end()); + mPendingWriteEventsQueue.push({eventsLeft, numWakeupEvents}); mEventQueueWriteCV.notify_one(); } } -// TODO: Implement the wakelock timeout in these next two methods. Also pass in the subhal -// index for better tracking. - -void HalProxy::incrementRefCountAndMaybeAcquireWakelock() { - std::lock_guard lockGuard(mWakelockRefCountMutex); +bool HalProxy::incrementRefCountAndMaybeAcquireWakelock(size_t delta, + int64_t* timeoutStart /* = nullptr */) { + if (!mThreadsRun.load()) return false; + std::lock_guard lockGuard(mWakelockMutex); if (mWakelockRefCount == 0) { - acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLockName); + acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakelockName); + mWakelockCV.notify_one(); } - mWakelockRefCount++; + mWakelockTimeoutStartTime = getTimeNow(); + mWakelockRefCount += delta; + if (timeoutStart != nullptr) { + *timeoutStart = mWakelockTimeoutStartTime; + } + return true; } -void HalProxy::decrementRefCountAndMaybeReleaseWakelock() { - std::lock_guard lockGuard(mWakelockRefCountMutex); - mWakelockRefCount--; +void HalProxy::decrementRefCountAndMaybeReleaseWakelock(size_t delta, + int64_t timeoutStart /* = -1 */) { + if (!mThreadsRun.load()) return; + std::lock_guard lockGuard(mWakelockMutex); + if (timeoutStart == -1) timeoutStart = mWakelockTimeoutResetTime; + if (mWakelockRefCount == 0 || timeoutStart < mWakelockTimeoutResetTime) return; + mWakelockRefCount -= std::min(mWakelockRefCount, delta); if (mWakelockRefCount == 0) { - release_wake_lock(kWakeLockName); + release_wake_lock(kWakelockName); } } @@ -427,6 +498,17 @@ ISensorsSubHal* HalProxy::getSubHalForSensorHandle(uint32_t sensorHandle) { return mSubHalList[static_cast(sensorHandle >> 24)]; } +size_t HalProxy::countNumWakeupEvents(const std::vector& events, size_t n) { + size_t numWakeupEvents = 0; + for (size_t i = 0; i < n; i++) { + int32_t sensorHandle = events[i].sensorHandle; + if (mSensors[sensorHandle].flags & static_cast(V1_0::SensorFlagBits::WAKE_UP)) { + numWakeupEvents++; + } + } + return numWakeupEvents; +} + uint32_t HalProxy::clearSubHalIndex(uint32_t sensorHandle) { return sensorHandle & (~kSensorHandleSubHalIndexMask); } @@ -436,7 +518,7 @@ bool HalProxy::subHalIndexIsClear(uint32_t sensorHandle) { } void HalProxyCallback::postEvents(const std::vector& events, ScopedWakelock wakelock) { - (void)wakelock; + if (events.empty() || !mHalProxy->areThreadsRunning()) return; size_t numWakeupEvents; std::vector processedEvents = processEvents(events, &numWakeupEvents); if (numWakeupEvents > 0) { @@ -450,8 +532,7 @@ void HalProxyCallback::postEvents(const std::vector& events, ScopedWakelo " w/ index %zu.", mSubHalIndex); } - - mHalProxy->postEventsToMessageQueue(processedEvents); + mHalProxy->postEventsToMessageQueue(events, numWakeupEvents, std::move(wakelock)); } ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) { @@ -461,13 +542,13 @@ ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) { std::vector HalProxyCallback::processEvents(const std::vector& events, size_t* numWakeupEvents) const { - std::vector eventsOut; *numWakeupEvents = 0; + std::vector eventsOut; for (Event event : events) { event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex); eventsOut.push_back(event); - if ((mHalProxy->getSensorInfo(event.sensorHandle).flags & V1_0::SensorFlagBits::WAKE_UP) != - 0) { + const SensorInfo& sensor = mHalProxy->getSensorInfo(event.sensorHandle); + if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) { (*numWakeupEvents)++; } } diff --git a/sensors/2.0/multihal/ScopedWakelock.cpp b/sensors/2.0/multihal/ScopedWakelock.cpp index 0430fa393e..d85d4a7891 100644 --- a/sensors/2.0/multihal/ScopedWakelock.cpp +++ b/sensors/2.0/multihal/ScopedWakelock.cpp @@ -22,18 +22,22 @@ namespace sensors { namespace V2_0 { namespace implementation { +int64_t getTimeNow() { + return std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); +} + ScopedWakelock::ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked) : mRefCounter(refCounter), mLocked(locked) { - // TODO: Move this implementation into HalProxy object instead if (mLocked) { - mRefCounter->incrementRefCountAndMaybeAcquireWakelock(); + mLocked = mRefCounter->incrementRefCountAndMaybeAcquireWakelock(1, &mCreatedAtTimeNs); } } ScopedWakelock::~ScopedWakelock() { - // TODO: Move this implementation into HalProxy object instead if (mLocked) { - mRefCounter->decrementRefCountAndMaybeReleaseWakelock(); + mRefCounter->decrementRefCountAndMaybeReleaseWakelock(1, mCreatedAtTimeNs); } } diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h index 47571a6368..6592afef96 100644 --- a/sensors/2.0/multihal/include/HalProxy.h +++ b/sensors/2.0/multihal/include/HalProxy.h @@ -16,9 +16,11 @@ #pragma once +#include "ScopedWakelock.h" #include "SubHal.h" #include +#include #include #include #include @@ -30,6 +32,7 @@ #include #include #include +#include namespace android { namespace hardware { @@ -100,45 +103,41 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { Return onDynamicSensorsDisconnected(const hidl_vec& dynamicSensorHandlesRemoved, int32_t subHalIndex); - // Below methods follow IScopedWakelockRefCounter - - /** - * Increment ref count and maybe acquire wakelock. - */ - void incrementRefCountAndMaybeAcquireWakelock() override; - - /** - * Decrement ref count and maybe release wakelock. - */ - void decrementRefCountAndMaybeReleaseWakelock() override; - // Below methods are for HalProxyCallback /** * Post events to the event message queue if there is room to write them. Otherwise post the - * remaining events to a background thread for a blocking write with a 5 second timeout. + * remaining events to a background thread for a blocking write with a kPendingWriteTimeoutNs + * timeout. * * @param events The list of events to post to the message queue. + * @param numWakeupEvents The number of wakeup events in events. + * @param wakelock The wakelock associated with this post of events. */ - void postEventsToMessageQueue(const std::vector& events); + void postEventsToMessageQueue(const std::vector& events, size_t numWakeupEvents, + ScopedWakelock wakelock); /** - * Get the SensorInfo object associated with the sensorHandle. + * Get the sensor info associated with that sensorHandle. * - * @param sensorHandle The sensorHandle for the sensor. + * @param sensorHandle The sensor handle. * - * @return The sensor info for the sensor. + * @return The sensor info object in the mapping. */ - const SensorInfo& getSensorInfo(uint32_t sensorHandle) const { - return mSensors.at(sensorHandle); - } + const SensorInfo& getSensorInfo(uint32_t sensorHandle) { return mSensors[sensorHandle]; } + + bool areThreadsRunning() { return mThreadsRun.load(); } + + // Below methods are from IScopedWakelockRefCounter interface + bool incrementRefCountAndMaybeAcquireWakelock(size_t delta, + int64_t* timeoutStart = nullptr) override; + + void decrementRefCountAndMaybeReleaseWakelock(size_t delta, int64_t timeoutStart = -1) override; private: using EventMessageQueue = MessageQueue; using WakeLockMessageQueue = MessageQueue; - const char* kWakeLockName = "SensorsHAL_WAKEUP"; - /** * The Event FMQ where sensor events are written */ @@ -185,23 +184,17 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { //! The single subHal that supports directChannel reporting. ISensorsSubHal* mDirectChannelSubHal = nullptr; - //! The mutex for the event queue. - std::mutex mEventQueueMutex; - //! The timeout for each pending write on background thread for events. - static const int64_t kWakelockTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */; - - //! The scoped wakelock ref count. - size_t mWakelockRefCount = 0; - - //! The mutex guarding the mWakelockRefCount variable - std::mutex mWakelockRefCountMutex; + static const int64_t kPendingWriteTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */; //! The bit mask used to get the subhal index from a sensor handle. static constexpr uint32_t kSensorHandleSubHalIndexMask = 0xFF000000; - //! The events that were not able to be written to fmq right away - std::queue> mPendingWriteEventsQueue; + /** + * A FIFO queue of pairs of vector of events and the number of wakeup events in that vector + * which are waiting to be written to the events fmq in the background thread. + */ + std::queue, size_t>> mPendingWriteEventsQueue; //! The mutex protecting writing to the fmq and the pending events queue std::mutex mEventQueueWriteMutex; @@ -212,12 +205,32 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { //! The thread object ptr that handles pending writes std::thread mPendingWritesThread; - //! The bool indicating whether to end the pending writes background thread or not - bool mPendingWritesRun = true; + //! The thread object that handles wakelocks + std::thread mWakelockThread; + + //! The bool indicating whether to end the threads started in initialize + std::atomic_bool mThreadsRun = true; //! The mutex protecting access to the dynamic sensors added and removed methods. std::mutex mDynamicSensorsMutex; + // WakelockRefCount membar vars below + + //! The mutex protecting the wakelock refcount and subsequent wakelock releases and + //! acquisitions + std::recursive_mutex mWakelockMutex; + + std::condition_variable_any mWakelockCV; + + //! The refcount of how many ScopedWakelocks and pending wakeup events are active + size_t mWakelockRefCount = 0; + + int64_t mWakelockTimeoutStartTime = getTimeNow(); + + int64_t mWakelockTimeoutResetTime = getTimeNow(); + + const char* kWakelockName = "SensorsMultiHal"; + /** * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries * listed in a config file. @@ -236,9 +249,9 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { void initializeSensorList(); /** - * Calls the above two helper methods which are shared in both ctors. + * Calls the helper methods that all ctors use. */ - void initializeSubHalCallbacksAndSensorList(); + void init(); /** * Starts the thread that handles pending writes to event fmq. @@ -250,6 +263,31 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { //! Handles the pending writes on events to eventqueue. void handlePendingWrites(); + /** + * Starts the thread that handles decrementing the ref count on wakeup events processed by the + * framework and timing out wakelocks. + * + * @param halProxy The HalProxy object pointer. + */ + static void startWakelockThread(HalProxy* halProxy); + + //! Handles the wakelocks. + void handleWakelocks(); + + /** + * @param timeLeft The variable that should be set to the timeleft before timeout will occur or + * unmodified if timeout occurred. + * + * @return true if the shared wakelock has been held passed the timeout and should be released + */ + bool sharedWakelockDidTimeout(int64_t* timeLeft); + + /** + * Reset all the member variables associated with the wakelock ref count and maybe release + * the shared wakelock. + */ + void resetSharedWakelock(); + /** * Clear direct channel flags if the HalProxy has already chosen a subhal as its direct channel * subhal. Set the directChannelSubHal pointer to the subHal passed in if this is the first @@ -269,6 +307,16 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { */ ISensorsSubHal* getSubHalForSensorHandle(uint32_t sensorHandle); + /** + * Count the number of wakeup events in the first n events of the vector. + * + * @param events The vector of Event objects. + * @param n The end index not inclusive of events to consider. + * + * @return The number of wakeup events of the considered events. + */ + size_t countNumWakeupEvents(const std::vector& events, size_t n); + /* * Clear out the subhal index bytes from a sensorHandle. * diff --git a/sensors/2.0/multihal/include/ScopedWakelock.h b/sensors/2.0/multihal/include/ScopedWakelock.h index a151f1566f..aa6d9db3d4 100644 --- a/sensors/2.0/multihal/include/ScopedWakelock.h +++ b/sensors/2.0/multihal/include/ScopedWakelock.h @@ -16,7 +16,7 @@ #pragma once -#include +#include namespace android { namespace hardware { @@ -24,10 +24,36 @@ namespace sensors { namespace V2_0 { namespace implementation { -class IScopedWakelockRefCounter { +using ::android::hardware::sensors::V2_0::SensorTimeout; + +const int64_t kWakelockTimeoutNs = + static_cast(SensorTimeout::WAKE_LOCK_SECONDS) * INT64_C(1000000000); + +int64_t getTimeNow(); + +class IScopedWakelockRefCounter : public RefBase { public: - virtual void incrementRefCountAndMaybeAcquireWakelock() = 0; - virtual void decrementRefCountAndMaybeReleaseWakelock() = 0; + /** + * Increment the wakelock ref count and maybe acquire the shared wakelock if incrementing + * from 0 then return the time of incrementing back to caller. + * + * @param delta The amount to change ref count by. + * @param timeoutStart The ptr to the timestamp in ns that the increment occurred which will be + * set in the function or nullptr if not specified. + * + * @return true if successfully incremented the wakelock ref count. + */ + virtual bool incrementRefCountAndMaybeAcquireWakelock(size_t delta, + int64_t* timeoutStart = nullptr) = 0; + /** + * Decrement the wakelock ref count and maybe release wakelock if ref count ends up 0. + * + * @param delta The amount to change ref count by. + * @param timeoutStart The timestamp in ns that the calling context kept track of when + * incrementing the ref count or -1 by default + */ + virtual void decrementRefCountAndMaybeReleaseWakelock(size_t delta, + int64_t timeoutStart = -1) = 0; // Virtual dtor needed for compilation success virtual ~IScopedWakelockRefCounter(){}; }; @@ -64,6 +90,7 @@ class ScopedWakelock { private: friend class HalProxyCallback; IScopedWakelockRefCounter* mRefCounter; + int64_t mCreatedAtTimeNs; bool mLocked; ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked); ScopedWakelock(const ScopedWakelock&) = delete; diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp index aa44687590..e3a4af1e5a 100644 --- a/sensors/2.0/multihal/tests/Android.bp +++ b/sensors/2.0/multihal/tests/Android.bp @@ -35,6 +35,9 @@ cc_defaults { static_libs: [ "android.hardware.sensors@2.0-HalProxy", ], + cflags: [ + "-DLOG_TAG=\"FakeSubHal\"" + ], } cc_library { @@ -87,4 +90,7 @@ cc_test { "libutils", ], test_suites: ["device-tests"], + cflags: [ + "-DLOG_TAG=\"HalProxyUnitTests\"", + ], } diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp index c8fbb730f6..ad1b96fc78 100644 --- a/sensors/2.0/multihal/tests/HalProxy_test.cpp +++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp @@ -29,6 +29,7 @@ namespace { +using ::android::hardware::EventFlag; using ::android::hardware::hidl_vec; using ::android::hardware::MessageQueue; using ::android::hardware::Return; @@ -36,7 +37,9 @@ using ::android::hardware::sensors::V1_0::EventPayload; using ::android::hardware::sensors::V1_0::SensorFlagBits; using ::android::hardware::sensors::V1_0::SensorInfo; using ::android::hardware::sensors::V1_0::SensorType; +using ::android::hardware::sensors::V2_0::EventQueueFlagBits; using ::android::hardware::sensors::V2_0::ISensorsCallback; +using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; using ::android::hardware::sensors::V2_0::implementation::HalProxy; using ::android::hardware::sensors::V2_0::implementation::HalProxyCallback; using ::android::hardware::sensors::V2_0::subhal::implementation::AddAndRemoveDynamicSensorsSubHal; @@ -123,6 +126,12 @@ void testSensorsListFromProxyAndSubHal(const std::vector& proxySenso void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector& sensorsList, size_t enabledSubHalIndex); +void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr& wakelockQueue, + EventFlag* wakelockQueueFlag); + +bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& eventQueue, + EventFlag* eventQueueFlag); + /** * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor * which is a wakeup type sensor. @@ -313,10 +322,19 @@ TEST(HalProxyTest, PostSingleWakeupEvent) { ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + EventFlag* eventQueueFlag; + EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag); + + EventFlag* wakelockQueueFlag; + EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag); + std::vector events{makeProximityEvent()}; subHal.postEvents(events, true /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), 1); + + readEventsOutOfQueue(1, eventQueue, eventQueueFlag); + ackWakeupEventsToHalProxy(1, wakeLockQueue, wakelockQueueFlag); } TEST(HalProxyTest, PostMultipleWakeupEvents) { @@ -332,10 +350,19 @@ TEST(HalProxyTest, PostMultipleWakeupEvents) { ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + EventFlag* eventQueueFlag; + EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag); + + EventFlag* wakelockQueueFlag; + EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag); + std::vector events = makeMultipleProximityEvents(kNumEvents); subHal.postEvents(events, true /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); + + readEventsOutOfQueue(kNumEvents, eventQueue, eventQueueFlag); + ackWakeupEventsToHalProxy(kNumEvents, wakeLockQueue, wakelockQueueFlag); } TEST(HalProxyTest, PostEventsMultipleSubhals) { @@ -374,20 +401,21 @@ TEST(HalProxyTest, PostEventsDelayedWrite) { ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + EventFlag* eventQueueFlag; + EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); subHal1.postEvents(events, false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kQueueSize); - Event eventOut; - // writeblock 1 event out of queue, timeout for half a second - EXPECT_TRUE(eventQueue->readBlocking(&eventOut, 1, 500000000)); + // readblock a full queue size worth of events out of queue, timeout for half a second + EXPECT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag)); - // Sleep for a half second so that blocking write has time complete in background thread - std::this_thread::sleep_for(std::chrono::milliseconds(500)); + // proxy background thread should have wrote remaining events when it saw space + EXPECT_TRUE(readEventsOutOfQueue(kNumEvents - kQueueSize, eventQueue, eventQueueFlag)); - // proxy background thread should have wrote last event when it saw space - EXPECT_EQ(eventQueue->availableToRead(), kQueueSize); + EXPECT_EQ(eventQueue->availableToRead(), 0); } TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) { @@ -548,6 +576,23 @@ void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector& wakelockQueue, + EventFlag* wakelockQueueFlag) { + uint32_t numEventsUInt32 = static_cast(numEvents); + wakelockQueue->write(&numEventsUInt32); + wakelockQueueFlag->wake(static_cast(WakeLockQueueFlagBits::DATA_WRITTEN)); +} + +bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& eventQueue, + EventFlag* eventQueueFlag) { + constexpr int64_t kReadBlockingTimeout = INT64_C(500000000); + std::vector events(numEvents); + return eventQueue->readBlocking(events.data(), numEvents, + static_cast(EventQueueFlagBits::EVENTS_READ), + static_cast(EventQueueFlagBits::READ_AND_PROCESS), + kReadBlockingTimeout, eventQueueFlag); +} + Event makeProximityEvent() { Event event; event.timestamp = 0xFF00FF00; From f09465d1119f58e293671ba7dc760f1edec50477 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Wed, 2 Oct 2019 11:07:16 -0700 Subject: [PATCH 0188/1022] MH2 | Add makeFMQ helpers to HalProxy_test Bug: 136511617 Test: Ran the tests with success. Change-Id: Ide35e39529193696f3fb8d5898e9a3daf15b1630 --- sensors/2.0/multihal/tests/HalProxy_test.cpp | 70 +++++++++----------- 1 file changed, 32 insertions(+), 38 deletions(-) diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp index ad1b96fc78..fa527c9209 100644 --- a/sensors/2.0/multihal/tests/HalProxy_test.cpp +++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp @@ -132,6 +132,10 @@ void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr& eventQueue, EventFlag* eventQueueFlag); +std::unique_ptr makeEventFMQ(size_t size); + +std::unique_ptr makeWakelockFMQ(size_t size); + /** * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor * which is a wakeup type sensor. @@ -278,10 +282,8 @@ TEST(HalProxyTest, PostSingleNonWakeupEvent) { AllSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = - std::make_unique(kQueueSize, true); - std::unique_ptr wakeLockQueue = - std::make_unique(kQueueSize, true); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); @@ -297,10 +299,8 @@ TEST(HalProxyTest, PostMultipleNonWakeupEvent) { AllSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = - std::make_unique(kQueueSize, true); - std::unique_ptr wakeLockQueue = - std::make_unique(kQueueSize, true); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); @@ -315,10 +315,8 @@ TEST(HalProxyTest, PostSingleWakeupEvent) { AllSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = - std::make_unique(kQueueSize, true); - std::unique_ptr wakeLockQueue = - std::make_unique(kQueueSize, true); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); @@ -343,10 +341,8 @@ TEST(HalProxyTest, PostMultipleWakeupEvents) { AllSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = - std::make_unique(kQueueSize, true); - std::unique_ptr wakeLockQueue = - std::make_unique(kQueueSize, true); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); @@ -371,10 +367,8 @@ TEST(HalProxyTest, PostEventsMultipleSubhals) { AllSensorsSubHal subHal1, subHal2; std::vector subHals{&subHal1, &subHal2}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = - std::make_unique(kQueueSize, true); - std::unique_ptr wakeLockQueue = - std::make_unique(kQueueSize, true); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); @@ -394,10 +388,8 @@ TEST(HalProxyTest, PostEventsDelayedWrite) { AllSensorsSubHal subHal1, subHal2; std::vector subHals{&subHal1, &subHal2}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = - std::make_unique(kQueueSize, true); - std::unique_ptr wakeLockQueue = - std::make_unique(kQueueSize, true); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); @@ -424,10 +416,8 @@ TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) { AllSensorsSubHal subHal1, subHal2; std::vector subHals{&subHal1, &subHal2}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = - std::make_unique(kQueueSize, true); - std::unique_ptr wakeLockQueue = - std::make_unique(kQueueSize, true); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); @@ -448,10 +438,8 @@ TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThreadTest) { AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = - std::make_unique(kQueueSize, true); - std::unique_ptr wakeLockQueue = - std::make_unique(kQueueSize, true); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); @@ -473,9 +461,8 @@ TEST(HalProxyTest, DynamicSensorsConnectedTest) { AddAndRemoveDynamicSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = std::make_unique(0, true); - std::unique_ptr wakeLockQueue = - std::make_unique(0, true); + std::unique_ptr eventQueue = makeEventFMQ(0); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(0); std::vector sensorsToConnect; std::vector sensorHandlesToExpect; @@ -502,9 +489,8 @@ TEST(HalProxyTest, DynamicSensorsDisconnectedTest) { AddAndRemoveDynamicSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = std::make_unique(0, true); - std::unique_ptr wakeLockQueue = - std::make_unique(0, true); + std::unique_ptr eventQueue = makeEventFMQ(0); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(0); std::vector sensorsToConnect; std::vector sensorHandlesToExpect; @@ -593,6 +579,14 @@ bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& kReadBlockingTimeout, eventQueueFlag); } +std::unique_ptr makeEventFMQ(size_t size) { + return std::make_unique(size, true); +} + +std::unique_ptr makeWakelockFMQ(size_t size) { + return std::make_unique(size, true); +} + Event makeProximityEvent() { Event event; event.timestamp = 0xFF00FF00; From 731d7125bf431ee11bb6704db473de405a54c5bd Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Thu, 10 Oct 2019 17:06:33 -0700 Subject: [PATCH 0189/1022] MH2 | Change rc file to more appropriate settings Bug: 136511617 Test: N/A Change-Id: I23db5a299e5419156c3cb59fad9ea086ac2f393d --- .../multihal/android.hardware.sensors@2.0-service-multihal.rc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc index 167168919a..a4da3b084b 100644 --- a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc +++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc @@ -1,6 +1,7 @@ service vendor.sensors-hal-2-0-multihal /vendor/bin/hw/android.hardware.sensors@2.0-service.multihal class hal user system - group system + group system wakelock + writepid /dev/cpuset/system-background/tasks capabilities BLOCK_SUSPEND rlimit rtprio 10 10 From aa181aec49a78a40b56fa644ccd22c8f19d64b00 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Mon, 14 Oct 2019 13:17:17 -0700 Subject: [PATCH 0190/1022] gralloc: require locked buffers follow format Clarify that buffers that are locked (mapped) to the CPU must be in the format requested in their BufferDescriptorInfo. The buffers should not be compressed/swizzled/tiled/etc. Bug: 141631415 Test: This is already assumed by the tests. Change-Id: Ie674117418aaefc3f99ac2bc89c3da4072e236ec --- graphics/mapper/4.0/IMapper.hal | 3 +++ 1 file changed, 3 insertions(+) diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal index f5df04b853..85c7c81e85 100644 --- a/graphics/mapper/4.0/IMapper.hal +++ b/graphics/mapper/4.0/IMapper.hal @@ -202,6 +202,9 @@ interface IMapper { * the buffer. If the bytesPerStride is unknown or variable, a value of -1 * should be returned. * + * The locked buffer must adhere to the format requested at allocation time + * in the BufferDescriptorInfo. + * * @param buffer Buffer to lock. * @param cpuUsage CPU usage flags to request. See +ndk * libnativewindow#AHardwareBuffer_UsageFlags for possible values. From dc1146d90396b640f94ea6c1e4e1520e30c587b7 Mon Sep 17 00:00:00 2001 From: jiabin Date: Wed, 16 Oct 2019 11:31:08 -0700 Subject: [PATCH 0191/1022] Use static libaudiofoundation in VTS. As libaudiofoundation is not part of VNDK, it may break VTS. Using it as a static library can help solve the problem. Test: make, atest VtsHalAudioV5_0Target Bug: 142683018 Change-Id: Id540c354c90bd95681e2506abe47588311c94b67 --- audio/core/all-versions/vts/functional/Android.bp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp index 5e17ade365..c73970fb6b 100644 --- a/audio/core/all-versions/vts/functional/Android.bp +++ b/audio/core/all-versions/vts/functional/Android.bp @@ -19,12 +19,13 @@ cc_defaults { defaults: ["VtsHalTargetTestDefaults"], static_libs: [ "android.hardware.audio.common.test.utility", + "libaudiofoundation", "libaudiopolicycomponents", "libmedia_helper", "libxml2", ], shared_libs: [ - "libaudiofoundation", + "libbinder", "libfmq", ], header_libs: [ From 4652a0e565cdd80a26ca93342924d886669c91cf Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Tue, 15 Oct 2019 10:37:00 -0700 Subject: [PATCH 0192/1022] Convert VtsHalGnssV1_1TargetTest to be parameterized test Bug: 142397658 Test: atest VtsHalGnssV1_1TargetTest atest VtsHalGnssV1_1Target Change-Id: I575630c8cbbf8bbd341425c5bbe04ca49c2c1758 --- Android.bp | 1 + gnss/1.1/vts/functional/Android.bp | 2 +- .../functional/VtsHalGnssV1_1TargetTest.cpp | 18 +++++++-------- gnss/1.1/vts/functional/gnss_hal_test.cpp | 5 ++-- gnss/1.1/vts/functional/gnss_hal_test.h | 22 +++--------------- .../vts/functional/gnss_hal_test_cases.cpp | 23 +++++++++---------- .../vts/include/GnssCallbackEventQueue.h | 4 ++-- 7 files changed, 30 insertions(+), 45 deletions(-) diff --git a/Android.bp b/Android.bp index dd8473744e..70e0574f3d 100644 --- a/Android.bp +++ b/Android.bp @@ -45,4 +45,5 @@ cc_defaults { "-g", ], + require_root: true, } diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp index cc34290fa8..bdd02d2e6e 100644 --- a/gnss/1.1/vts/functional/Android.bp +++ b/gnss/1.1/vts/functional/Android.bp @@ -30,5 +30,5 @@ cc_test { shared_libs: [ "android.hardware.gnss.measurement_corrections@1.0", ], - test_suites: ["general-tests"], + test_suites: ["general-tests", "vts-core"], } diff --git a/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp index ca9eef4822..4a0a7f9ffa 100644 --- a/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp +++ b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp @@ -15,15 +15,15 @@ */ #define LOG_TAG "VtsHalGnssV1_1TargetTest" -#include +#include +#include +#include #include "gnss_hal_test.h" -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - GnssHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); - return status; -} +using android::hardware::gnss::V1_1::IGnss; + +INSTANTIATE_TEST_SUITE_P( + PerInstance, GnssHalTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp index 61a2ce434d..2c8a7b1399 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test.cpp +++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp @@ -17,6 +17,8 @@ #define LOG_TAG "GnssHalTest" #include +#include +#include #include #include @@ -29,8 +31,7 @@ using ::android::hardware::hidl_vec; using ::android::hardware::gnss::common::Utils; void GnssHalTest::SetUp() { - gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService( - GnssHidlEnvironment::Instance()->getServiceName()); + gnss_hal_ = IGnss::getService(GetParam()); ASSERT_NE(gnss_hal_, nullptr); SetUpGnssCallback(); diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h index e4325bf359..169cd62c59 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test.h +++ b/gnss/1.1/vts/functional/gnss_hal_test.h @@ -19,8 +19,7 @@ #include -#include -#include +#include #include "GnssCallbackEventQueue.h" using android::hardware::Return; @@ -37,24 +36,9 @@ using android::sp; #define TIMEOUT_SEC 2 // for basic commands/responses -// Test environment for GNSS HIDL HAL. -class GnssHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static GnssHidlEnvironment* Instance() { - static GnssHidlEnvironment* instance = new GnssHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { registerTestService(); } - - private: - GnssHidlEnvironment() {} -}; - // The main test class for GNSS HAL. -class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase { - public: +class GnssHalTest : public testing::TestWithParam { + public: virtual void SetUp() override; virtual void TearDown() override; diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp index 3294bcd1ad..79da84ac10 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp @@ -18,9 +18,8 @@ #include -#include - #include +#include using android::hardware::hidl_vec; @@ -39,13 +38,13 @@ using android::hardware::gnss::V1_1::IGnssMeasurement; * * Empty test fixture to verify basic Setup & Teardown */ -TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {} +TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {} /* * TestGnssMeasurementCallback: * Gets the GnssMeasurementExtension and verify that it returns an actual extension. */ -TEST_F(GnssHalTest, TestGnssMeasurementCallback) { +TEST_P(GnssHalTest, TestGnssMeasurementCallback) { auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1(); ASSERT_TRUE(gnssMeasurement_1_1.isOk()); auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement(); @@ -65,7 +64,7 @@ TEST_F(GnssHalTest, TestGnssMeasurementCallback) { * NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on * each received location. */ -TEST_F(GnssHalTest, GetLocationLowPower) { +TEST_P(GnssHalTest, GetLocationLowPower) { if (!IsGnssHalVersion_1_1()) { ALOGI("Test GetLocationLowPower skipped. GNSS HAL version is greater than 1.1."); return; @@ -97,7 +96,6 @@ TEST_F(GnssHalTest, GetLocationLowPower) { gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, kNoLocationPeriodSec); const int location_called_count = gnss_cb_->location_cbq_.calledCount(); - // Tolerate (ignore) one extra location right after the first one // to handle startup edge case scheduling limitations in some implementations if ((i == 1) && (location_called_count == 2)) { @@ -132,7 +130,8 @@ TEST_F(GnssHalTest, GetLocationLowPower) { */ IGnssConfiguration::BlacklistedSource FindStrongFrequentNonGpsSource( - const list list_gnss_sv_status, const int min_observations) { + const std::list list_gnss_sv_status, + const int min_observations) { struct ComparableBlacklistedSource { IGnssConfiguration::BlacklistedSource id; @@ -218,7 +217,7 @@ IGnssConfiguration::BlacklistedSource FindStrongFrequentNonGpsSource( * 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the * formerly strongest satellite */ -TEST_F(GnssHalTest, BlacklistIndividualSatellites) { +TEST_P(GnssHalTest, BlacklistIndividualSatellites) { if (!IsGnssHalVersion_1_1()) { ALOGI("Test BlacklistIndividualSatellites skipped. GNSS HAL version is greater than 1.1."); return; @@ -244,7 +243,7 @@ TEST_F(GnssHalTest, BlacklistIndividualSatellites) { */ const int kGnssSvStatusTimeout = 2; - list sv_status_list; + std::list sv_status_list; int count = gnss_cb_->sv_status_cbq_.retrieve(sv_status_list, sv_status_cbq_size, kGnssSvStatusTimeout); ASSERT_EQ(count, sv_status_cbq_size); @@ -362,7 +361,7 @@ TEST_F(GnssHalTest, BlacklistIndividualSatellites) { * GnssStatus does not use any constellation but GPS. * 4a & b) Clean up by turning off location, and send in empty blacklist. */ -TEST_F(GnssHalTest, BlacklistConstellation) { +TEST_P(GnssHalTest, BlacklistConstellation) { if (!IsGnssHalVersion_1_1()) { ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1."); return; @@ -457,7 +456,7 @@ TEST_F(GnssHalTest, BlacklistConstellation) { * * Ensure successfully injecting a location. */ -TEST_F(GnssHalTest, InjectBestLocation) { +TEST_P(GnssHalTest, InjectBestLocation) { StartAndCheckLocations(1); GnssLocation gnssLocation = gnss_cb_->last_location_; CheckLocation(gnssLocation, true); @@ -476,7 +475,7 @@ TEST_F(GnssHalTest, InjectBestLocation) { * GnssDebugValuesSanityTest: * Ensures that GnssDebug values make sense. */ -TEST_F(GnssHalTest, GnssDebugValuesSanityTest) { +TEST_P(GnssHalTest, GnssDebugValuesSanityTest) { auto gnssDebug = gnss_hal_->getExtensionGnssDebug(); ASSERT_TRUE(gnssDebug.isOk()); if (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017) { diff --git a/gnss/common/utils/vts/include/GnssCallbackEventQueue.h b/gnss/common/utils/vts/include/GnssCallbackEventQueue.h index b1d8ed4e36..3dc429b05e 100644 --- a/gnss/common/utils/vts/include/GnssCallbackEventQueue.h +++ b/gnss/common/utils/vts/include/GnssCallbackEventQueue.h @@ -53,7 +53,7 @@ class GnssCallbackEventQueue { * timeout_seconds to retrieve each event. If timeout occurs, it returns the number of * items retrieved which will be less than count. */ - int retrieve(list& event_list, int count, int timeout_seconds); + int retrieve(std::list& event_list, int count, int timeout_seconds); /* Returns the number of events pending to be retrieved from the callback event queue. */ int size() const; @@ -97,7 +97,7 @@ bool GnssCallbackEventQueue::retrieve(T& event, int timeout_seconds) { } template -int GnssCallbackEventQueue::retrieve(list& event_list, int count, int timeout_seconds) { +int GnssCallbackEventQueue::retrieve(std::list& event_list, int count, int timeout_seconds) { for (int i = 0; i < count; ++i) { T event; if (!retrieve(event, timeout_seconds)) { From 89af69eb05fde34496367c78082e25bfc24492af Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Tue, 15 Oct 2019 13:32:02 -0700 Subject: [PATCH 0193/1022] Convert VtsHalGnssV2_0TargetTest to be parameterized test Bug: 142397658 Test: atest VtsHalGnssV2_0TargetTest atest VtsHalGnssV2_0Target Change-Id: I0402e62265f71b4e2c141624ce12b627d965c8ee --- gnss/2.0/vts/functional/Android.bp | 1 + .../functional/VtsHalGnssV2_0TargetTest.cpp | 18 +++---- gnss/2.0/vts/functional/gnss_hal_test.cpp | 5 +- gnss/2.0/vts/functional/gnss_hal_test.h | 23 ++------- .../vts/functional/gnss_hal_test_cases.cpp | 47 ++++++++++--------- 5 files changed, 41 insertions(+), 53 deletions(-) diff --git a/gnss/2.0/vts/functional/Android.bp b/gnss/2.0/vts/functional/Android.bp index 278d87b117..9aa13349b0 100644 --- a/gnss/2.0/vts/functional/Android.bp +++ b/gnss/2.0/vts/functional/Android.bp @@ -30,4 +30,5 @@ cc_test { "android.hardware.gnss@2.0", "android.hardware.gnss@common-vts-lib", ], + test_suites: ["general-tests", "vts-core"], } diff --git a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp index ae36c50689..2c74fa37be 100644 --- a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp +++ b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp @@ -15,15 +15,15 @@ */ #define LOG_TAG "VtsHalGnssV2_0TargetTest" -#include +#include +#include +#include #include "gnss_hal_test.h" -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - GnssHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); - return status; -} +using android::hardware::gnss::V2_0::IGnss; + +INSTANTIATE_TEST_SUITE_P( + PerInstance, GnssHalTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp index 14ae43ce26..8ca3f684a3 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test.cpp +++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp @@ -20,12 +20,13 @@ #include #include "Utils.h" +#include + using ::android::hardware::gnss::common::Utils; // Implementations for the main test class for GNSS HAL void GnssHalTest::SetUp() { - gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService( - GnssHidlEnvironment::Instance()->getServiceName()); + gnss_hal_ = IGnss::getService(GetParam()); ASSERT_NE(gnss_hal_, nullptr); SetUpGnssCallback(); diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h index 7d07c0f423..4f7b87a485 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test.h +++ b/gnss/2.0/vts/functional/gnss_hal_test.h @@ -17,11 +17,11 @@ #ifndef GNSS_HAL_TEST_H_ #define GNSS_HAL_TEST_H_ -#include -#include #include #include "GnssCallbackEventQueue.h" +#include + using android::hardware::hidl_vec; using android::hardware::Return; using android::hardware::Void; @@ -45,24 +45,9 @@ using android::sp; #define TIMEOUT_SEC 2 // for basic commands/responses -// Test environment for GNSS HIDL HAL. -class GnssHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static GnssHidlEnvironment* Instance() { - static GnssHidlEnvironment* instance = new GnssHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { registerTestService(); } - - private: - GnssHidlEnvironment() {} -}; - // The main test class for GNSS HAL. -class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase { - public: +class GnssHalTest : public testing::TestWithParam { + public: virtual void SetUp() override; virtual void TearDown() override; 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 ca3edc57d4..c442cc6bf8 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp @@ -16,10 +16,11 @@ #define LOG_TAG "GnssHalTestCases" -#include #include #include "Utils.h" +#include + using android::hardware::hidl_string; using android::hardware::hidl_vec; @@ -51,13 +52,13 @@ using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl; * * Empty test fixture to verify basic Setup & Teardown */ -TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {} +TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {} /* * TestGnssMeasurementExtension: * Gets the GnssMeasurementExtension and verifies that it returns an actual extension. */ -TEST_F(GnssHalTest, TestGnssMeasurementExtension) { +TEST_P(GnssHalTest, TestGnssMeasurementExtension) { auto gnssMeasurement_2_0 = gnss_hal_->getExtensionGnssMeasurement_2_0(); auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1(); auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement(); @@ -80,7 +81,7 @@ TEST_F(GnssHalTest, TestGnssMeasurementExtension) { * The GNSS HAL 2.0 implementation must support @2.0::IGnssConfiguration interface due to * the deprecation of some methods in @1.0::IGnssConfiguration interface. */ -TEST_F(GnssHalTest, TestGnssConfigurationExtension) { +TEST_P(GnssHalTest, TestGnssConfigurationExtension) { auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0(); ASSERT_TRUE(gnssConfiguration.isOk()); sp iGnssConfiguration = gnssConfiguration; @@ -96,7 +97,7 @@ TEST_F(GnssHalTest, TestGnssConfigurationExtension) { * TestGnssConfiguration_setSuplEs_Deprecation: * Calls setSuplEs and verifies that it returns false. */ -TEST_F(GnssHalTest, TestGnssConfiguration_setSuplEs_Deprecation) { +TEST_P(GnssHalTest, TestGnssConfiguration_setSuplEs_Deprecation) { auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0(); ASSERT_TRUE(gnssConfiguration.isOk()); sp iGnssConfiguration = gnssConfiguration; @@ -111,7 +112,7 @@ TEST_F(GnssHalTest, TestGnssConfiguration_setSuplEs_Deprecation) { * TestGnssConfiguration_setGpsLock_Deprecation: * Calls setGpsLock and verifies that it returns false. */ -TEST_F(GnssHalTest, TestGnssConfiguration_setGpsLock_Deprecation) { +TEST_P(GnssHalTest, TestGnssConfiguration_setGpsLock_Deprecation) { auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0(); ASSERT_TRUE(gnssConfiguration.isOk()); sp iGnssConfiguration = gnssConfiguration; @@ -130,7 +131,7 @@ TEST_F(GnssHalTest, TestGnssConfiguration_setGpsLock_Deprecation) { * @2.0::IAGnssRil interface due to the deprecation of framework network API methods needed * to support the @1.0::IAGnssRil interface. */ -TEST_F(GnssHalTest, TestAGnssRilExtension) { +TEST_P(GnssHalTest, TestAGnssRilExtension) { auto agnssRil_2_0 = gnss_hal_->getExtensionAGnssRil_2_0(); ASSERT_TRUE(agnssRil_2_0.isOk()); sp iAGnssRil_2_0 = agnssRil_2_0; @@ -148,7 +149,7 @@ TEST_F(GnssHalTest, TestAGnssRilExtension) { * 1. Updates GNSS HAL that a network has connected. * 2. Updates GNSS HAL that network has disconnected. */ -TEST_F(GnssHalTest, TestAGnssRil_UpdateNetworkState_2_0) { +TEST_P(GnssHalTest, TestAGnssRil_UpdateNetworkState_2_0) { auto agnssRil = gnss_hal_->getExtensionAGnssRil_2_0(); ASSERT_TRUE(agnssRil.isOk()); sp iAGnssRil = agnssRil; @@ -180,7 +181,7 @@ TEST_F(GnssHalTest, TestAGnssRil_UpdateNetworkState_2_0) { * 2. constellation is valid. * 3. state is valid. */ -TEST_F(GnssHalTest, TestGnssMeasurementFields) { +TEST_P(GnssHalTest, TestGnssMeasurementFields) { const int kFirstGnssMeasurementTimeoutSeconds = 10; auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0(); @@ -234,7 +235,7 @@ TEST_F(GnssHalTest, TestGnssMeasurementFields) { * @2.0::IAGnss interface due to the deprecation of framework network API methods needed * to support the @1.0::IAGnss interface. */ -TEST_F(GnssHalTest, TestAGnssExtension) { +TEST_P(GnssHalTest, TestAGnssExtension) { auto agnss_2_0 = gnss_hal_->getExtensionAGnss_2_0(); ASSERT_TRUE(agnss_2_0.isOk()); sp iAGnss_2_0 = agnss_2_0; @@ -258,7 +259,7 @@ TEST_F(GnssHalTest, TestAGnssExtension) { * TestGnssNiExtension_Deprecation: * Gets the @1.0::IGnssNi extension and verifies that it is a nullptr. */ -TEST_F(GnssHalTest, TestGnssNiExtension_Deprecation) { +TEST_P(GnssHalTest, TestGnssNiExtension_Deprecation) { // Verify IGnssNi 1.0 is not supported. auto gnssNi = gnss_hal_->getExtensionGnssNi(); ASSERT_TRUE(!gnssNi.isOk() || ((sp)gnssNi) == nullptr); @@ -269,7 +270,7 @@ TEST_F(GnssHalTest, TestGnssNiExtension_Deprecation) { * Gets the GnssVisibilityControlExtension and if it is not null, verifies that it supports * the gnss.visibility_control@1.0::IGnssVisibilityControl interface by invoking a method. */ -TEST_F(GnssHalTest, TestGnssVisibilityControlExtension) { +TEST_P(GnssHalTest, TestGnssVisibilityControlExtension) { auto gnssVisibilityControl = gnss_hal_->getExtensionVisibilityControl(); ASSERT_TRUE(gnssVisibilityControl.isOk()); sp iGnssVisibilityControl = gnssVisibilityControl; @@ -290,7 +291,7 @@ TEST_F(GnssHalTest, TestGnssVisibilityControlExtension) { * capabilities are reported and the mandatory LOS_SATS or the EXCESS_PATH_LENGTH * capability flag is set. */ -TEST_F(GnssHalTest, TestGnssMeasurementCorrectionsCapabilities) { +TEST_P(GnssHalTest, TestGnssMeasurementCorrectionsCapabilities) { if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) { return; } @@ -318,7 +319,7 @@ TEST_F(GnssHalTest, TestGnssMeasurementCorrectionsCapabilities) { * If measurement corrections capability is supported, verifies that it supports the * gnss.measurement_corrections@1.0::IMeasurementCorrections interface by invoking a method. */ -TEST_F(GnssHalTest, TestGnssMeasurementCorrections) { +TEST_P(GnssHalTest, TestGnssMeasurementCorrections) { if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) { return; } @@ -348,7 +349,7 @@ TEST_F(GnssHalTest, TestGnssMeasurementCorrections) { * Sets a GnssMeasurementCallback, waits for a GnssData object, and verifies the flags in member * elapsedRealitme are valid. */ -TEST_F(GnssHalTest, TestGnssDataElapsedRealtimeFlags) { +TEST_P(GnssHalTest, TestGnssDataElapsedRealtimeFlags) { const int kFirstGnssMeasurementTimeoutSeconds = 10; auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0(); @@ -383,7 +384,7 @@ TEST_F(GnssHalTest, TestGnssDataElapsedRealtimeFlags) { iGnssMeasurement->close(); } -TEST_F(GnssHalTest, TestGnssLocationElapsedRealtime) { +TEST_P(GnssHalTest, TestGnssLocationElapsedRealtime) { StartAndCheckFirstLocation(); ASSERT_TRUE((int)gnss_cb_->last_location_.elapsedRealtime.flags <= @@ -399,7 +400,7 @@ TEST_F(GnssHalTest, TestGnssLocationElapsedRealtime) { } // This test only verify that injectBestLocation_2_0 does not crash. -TEST_F(GnssHalTest, TestInjectBestLocation_2_0) { +TEST_P(GnssHalTest, TestInjectBestLocation_2_0) { StartAndCheckFirstLocation(); gnss_hal_->injectBestLocation_2_0(gnss_cb_->last_location_); StopAndClearLocations(); @@ -410,7 +411,7 @@ TEST_F(GnssHalTest, TestInjectBestLocation_2_0) { * Gets the @2.0::IGnssBatching extension and verifies that it doesn't return an error. Support * for this interface is optional. */ -TEST_F(GnssHalTest, TestGnssBatchingExtension) { +TEST_P(GnssHalTest, TestGnssBatchingExtension) { auto gnssBatching_2_0 = gnss_hal_->getExtensionGnssBatching_2_0(); ASSERT_TRUE(gnssBatching_2_0.isOk()); } @@ -422,7 +423,7 @@ TEST_F(GnssHalTest, TestGnssBatchingExtension) { * NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on * each received location. */ -TEST_F(GnssHalTest, GetLocationLowPower) { +TEST_P(GnssHalTest, GetLocationLowPower) { if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::LOW_POWER_MODE)) { ALOGI("Test GetLocationLowPower skipped. LOW_POWER_MODE capability not supported."); return; @@ -513,7 +514,7 @@ GnssConstellationType_1_0 MapConstellationType(GnssConstellationType_2_0 constel * or a source with constellation == UNKNOWN if none are found sufficient times */ IGnssConfiguration_1_1::BlacklistedSource FindStrongFrequentNonGpsSource( - const list>& sv_info_lists, + const std::list>& sv_info_lists, const int min_observations) { struct ComparableBlacklistedSource { IGnssConfiguration_1_1::BlacklistedSource id; @@ -599,7 +600,7 @@ IGnssConfiguration_1_1::BlacklistedSource FindStrongFrequentNonGpsSource( * 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the * formerly strongest satellite */ -TEST_F(GnssHalTest, BlacklistIndividualSatellites) { +TEST_P(GnssHalTest, BlacklistIndividualSatellites) { if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) { ALOGI("Test BlacklistIndividualSatellites skipped. SATELLITE_BLACKLIST capability" " not supported."); @@ -626,7 +627,7 @@ TEST_F(GnssHalTest, BlacklistIndividualSatellites) { */ const int kGnssSvStatusTimeout = 2; - list> sv_info_lists; + std::list> sv_info_lists; int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_lists, sv_info_list_cbq_size, kGnssSvStatusTimeout); ASSERT_EQ(count, sv_info_list_cbq_size); @@ -744,7 +745,7 @@ TEST_F(GnssHalTest, BlacklistIndividualSatellites) { * GnssStatus does not use any constellation but GPS. * 4a & b) Clean up by turning off location, and send in empty blacklist. */ -TEST_F(GnssHalTest, BlacklistConstellation) { +TEST_P(GnssHalTest, BlacklistConstellation) { if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) { ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported."); return; From f210a8ca97c3d513decf693b4305f42d33947d9d Mon Sep 17 00:00:00 2001 From: Jim Kaye Date: Fri, 11 Oct 2019 13:37:37 -0700 Subject: [PATCH 0194/1022] [AAE Power Mgt] Allow Suspend to RAM without triggering Garage Mode The Vehicle HAL can tell us to shut down immediately, but it cannot tell us to suspend immediately. Add that capability. This capability will be needed when the VHAL initiates a Silent Boot and then asks for suspension. In this case, we do not want to postpone the suspension by entering Garage Mode. Bug: 134521909 Test: Added CarPowerManagementTest.testSleepImmediateEntry() Test: Added CarPowerManagementServiceTest.testSleepImmediately() Change-Id: I8190d16cb6faa15672ec3d61f126f6d283d1189e --- automotive/vehicle/2.0/types.hal | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index 1355d9feab..bc0b4d3d9e 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -2569,6 +2569,11 @@ enum VehicleApPowerStateShutdownParam : int32_t { /** AP can only shutdown with postponing allowed. */ SHUTDOWN_ONLY = 3, + + /** + * AP may enter deep sleep, but must either sleep or shut down immediately. + * Postponing is not allowed. */ + SLEEP_IMMEDIATELY = 4, }; enum VehicleApPowerStateReport : int32_t { @@ -3581,4 +3586,3 @@ enum VmsAvailabilityStateIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex { enum VmsPublisherInformationIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex { PUBLISHER_ID = 1, }; - From 0e2911ebe002f0747569b90a40e42e130f21026f Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Thu, 17 Oct 2019 11:10:38 -0700 Subject: [PATCH 0195/1022] [hardware][interfaces][sensors] fix -Wreorder-init-list C++20 will require members in a designated initializer to be in order unlike C99. Bug: 139945549 Test: mm Change-Id: I78d64ea2b7df3f2bd3b8503aa553a0523b20d711 Signed-off-by: Nick Desaulniers --- sensors/1.0/default/convert.cpp | 6 +++--- sensors/common/vts/utils/GrallocWrapper.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sensors/1.0/default/convert.cpp b/sensors/1.0/default/convert.cpp index 52f5e4f5a0..53ceb0d92f 100644 --- a/sensors/1.0/default/convert.cpp +++ b/sensors/1.0/default/convert.cpp @@ -68,9 +68,9 @@ void convertFromSensorEvent(const sensors_event_t &src, Event *dst) { typedef ::android::hardware::sensors::V1_0::MetaDataEventType MetaDataEventType; *dst = { - .sensorHandle = src.sensor, - .sensorType = (SensorType)src.type, - .timestamp = src.timestamp + .timestamp = src.timestamp, + .sensorHandle = src.sensor, + .sensorType = (SensorType)src.type, }; switch (dst->sensorType) { diff --git a/sensors/common/vts/utils/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp index 1cad9135b7..e63faa2e1c 100644 --- a/sensors/common/vts/utils/GrallocWrapper.cpp +++ b/sensors/common/vts/utils/GrallocWrapper.cpp @@ -147,8 +147,8 @@ BufferDescriptor GrallocHalWrapper::getDescriptor(uint32_t .width = size, .height = 1, .layerCount = 1, - .usage = kBufferUsage, .format = static_cast(PixelFormat::BLOB), + .usage = kBufferUsage, }; BufferDescriptor descriptor; From 38b298946128026a75ad7bcf2ae20fbc63b2bb6b Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Thu, 17 Oct 2019 12:34:07 -0700 Subject: [PATCH 0196/1022] [hardware][interfaces][automotive] fix -Wreorder-init-list C++20 will require members in a designated initializer to be in order unlike C99. Bug: 139945549 Test: mm Change-Id: I17d1d262d71eefa0aa5b89da7acc659bc2f97bbd Signed-off-by: Nick Desaulniers --- .../default/impl/vhal_v2_0/DefaultConfig.h | 85 +++++++++++-------- .../impl/vhal_v2_0/EmulatedVehicleHal.cpp | 4 +- .../impl/vhal_v2_0/JsonFakeValueGenerator.cpp | 8 +- .../impl/vhal_v2_0/VehicleEmulator.cpp | 13 +-- 4 files changed, 63 insertions(+), 47 deletions(-) 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 094a37253e..f41b33c910 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 @@ -370,31 +370,34 @@ const ConfigDeclaration kVehicleProperties[]{ }, .initialValue = {.floatValues = {100.0f}}}, // units in meters - {.config = {.prop = toInt(VehicleProperty::TIRE_PRESSURE), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::CONTINUOUS, - .minSampleRate = 1.0f, - .maxSampleRate = 2.0f, - .areaConfigs = {VehicleAreaConfig{ - .areaId = WHEEL_FRONT_LEFT, - .minFloatValue = 100.0f, - .maxFloatValue = 300.0f, - }, - VehicleAreaConfig{ - .areaId = WHEEL_FRONT_RIGHT, - .minFloatValue = 100.0f, - .maxFloatValue = 300.0f, - }, - VehicleAreaConfig{ - .areaId = WHEEL_REAR_LEFT, - .minFloatValue = 100.0f, - .maxFloatValue = 300.0f, - }, - VehicleAreaConfig{ - .areaId = WHEEL_REAR_RIGHT, - .minFloatValue = 100.0f, - .maxFloatValue = 300.0f, - }}}, + {.config = + { + .prop = toInt(VehicleProperty::TIRE_PRESSURE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .areaConfigs = {VehicleAreaConfig{ + .areaId = WHEEL_FRONT_LEFT, + .minFloatValue = 100.0f, + .maxFloatValue = 300.0f, + }, + VehicleAreaConfig{ + .areaId = WHEEL_FRONT_RIGHT, + .minFloatValue = 100.0f, + .maxFloatValue = 300.0f, + }, + VehicleAreaConfig{ + .areaId = WHEEL_REAR_LEFT, + .minFloatValue = 100.0f, + .maxFloatValue = 300.0f, + }, + VehicleAreaConfig{ + .areaId = WHEEL_REAR_RIGHT, + .minFloatValue = 100.0f, + .maxFloatValue = 300.0f, + }}, + .minSampleRate = 1.0f, + .maxSampleRate = 2.0f, + }, .initialValue = {.floatValues = {200.0f}}}, // units in kPa {.config = @@ -595,11 +598,14 @@ const ConfigDeclaration kVehicleProperties[]{ .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS}}, .initialValue = {.int32Values = {(int)VehicleUnit::FAHRENHEIT}}}, - {.config = {.prop = toInt(VehicleProperty::DISTANCE_DISPLAY_UNITS), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .configArray = {(int)VehicleUnit::KILOMETER, (int)VehicleUnit::MILE}, - .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}}, + {.config = + { + .prop = toInt(VehicleProperty::DISTANCE_DISPLAY_UNITS), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + .configArray = {(int)VehicleUnit::KILOMETER, (int)VehicleUnit::MILE}, + }, .initialValue = {.int32Values = {(int)VehicleUnit::MILE}}}, {.config = @@ -692,13 +698,18 @@ const ConfigDeclaration kVehicleProperties[]{ }, }, - {.config = {.prop = kMixedTypePropertyForTest, - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - .configArray = {1, 1, 0, 2, 0, 0, 1, 0, 0}}, - .initialValue = {.stringValue = "MIXED property", - .int32Values = {1 /* indicate TRUE boolean value */, 2, 3}, - .floatValues = {4.5f}}}, + { + .config = {.prop = kMixedTypePropertyForTest, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {1, 1, 0, 2, 0, 0, 1, 0, 0}}, + .initialValue = + { + .int32Values = {1 /* indicate TRUE boolean value */, 2, 3}, + .floatValues = {4.5f}, + .stringValue = "MIXED property", + }, + }, {.config = {.prop = toInt(VehicleProperty::DOOR_LOCK), .access = VehiclePropertyAccess::READ_WRITE, 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 9d249be954..dc051d8e53 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 @@ -286,8 +286,8 @@ void EmulatedVehicleHal::onCreate() { // Create a separate instance for each individual zone VehiclePropValue prop = { - .prop = cfg.prop, - .areaId = curArea, + .areaId = curArea, + .prop = cfg.prop, }; if (it.initialAreaValues.size() > 0) { diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp index b8fd2babee..8677f837f5 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp @@ -101,9 +101,11 @@ std::vector JsonFakeValueGenerator::parseFakeValueJson(std::is rawEvent.toStyledString().c_str()); continue; } - VehiclePropValue event = {.prop = rawEvent["prop"].asInt(), - .areaId = rawEvent["areaId"].asInt(), - .timestamp = rawEvent["timestamp"].asInt64()}; + VehiclePropValue event = { + .timestamp = rawEvent["timestamp"].asInt64(), + .areaId = rawEvent["areaId"].asInt(), + .prop = rawEvent["prop"].asInt(), + }; Json::Value rawEventValue = rawEvent["value"]; auto& value = event.value; diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp index 356a6b9568..9dc70859c9 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp @@ -120,7 +120,10 @@ void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage const& rxMs } { - VehiclePropValue request = { .prop = propId, .areaId = areaId }; + VehiclePropValue request = { + .areaId = areaId, + .prop = propId, + }; StatusCode halStatus; auto val = mHal->get(request, &halStatus); if (val != nullptr) { @@ -150,10 +153,10 @@ void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage const& rxMs VehicleEmulator::EmulatorMessage& respMsg) { emulator::VehiclePropValue protoVal = rxMsg.value(0); VehiclePropValue val = { - .prop = protoVal.prop(), - .areaId = protoVal.area_id(), - .status = (VehiclePropertyStatus)protoVal.status(), - .timestamp = elapsedRealtimeNano(), + .timestamp = elapsedRealtimeNano(), + .areaId = protoVal.area_id(), + .prop = protoVal.prop(), + .status = (VehiclePropertyStatus)protoVal.status(), }; respMsg.set_msg_type(emulator::SET_PROPERTY_RESP); From 336c1c71e25293f750e174790b286e8fbcc2033d Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Mon, 14 Oct 2019 15:30:57 -0700 Subject: [PATCH 0197/1022] MH2 | Add restart logic in HalProxy::initialize method. Bug: 136511617 Test: None yet Change-Id: I389a7243d3612586aae4e8a802afda92af8dcc6d --- sensors/2.0/multihal/HalProxy.cpp | 83 +++++++--- sensors/2.0/multihal/include/HalProxy.h | 18 ++- sensors/2.0/multihal/include/SubHal.h | 12 +- sensors/2.0/multihal/tests/HalProxy_test.cpp | 144 +++++++++++++++++- .../tests/fake_subhal/SensorsSubHal.cpp | 1 + 5 files changed, 226 insertions(+), 32 deletions(-) diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index d66721866c..fe2b98b21a 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -65,15 +65,7 @@ HalProxy::HalProxy(std::vector& subHalList) : mSubHalList(subHa } HalProxy::~HalProxy() { - mThreadsRun.store(false); - mWakelockCV.notify_one(); - mEventQueueWriteCV.notify_one(); - if (mPendingWritesThread.joinable()) { - mPendingWritesThread.join(); - } - if (mWakelockThread.joinable()) { - mWakelockThread.join(); - } + stopThreads(); } Return HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) { @@ -119,8 +111,18 @@ Return HalProxy::initialize( const sp& sensorsCallback) { Result result = Result::OK; - // TODO: clean up sensor requests, if not already done elsewhere through a death recipient, and - // clean up any other resources that exist (FMQs, flags, threads, etc.) + stopThreads(); + resetSharedWakelock(); + + // So that the pending write events queue can be cleared safely and when we start threads + // again we do not get new events until after initialize resets the subhals. + disableAllSensors(); + + // Clears the queue if any events were pending write before. + mPendingWriteEventsQueue = std::queue, size_t>>(); + + // Clears previously connected dynamic sensors + mDynamicSensors.clear(); mDynamicSensorsCallback = sensorsCallback; @@ -128,21 +130,29 @@ Return HalProxy::initialize( mEventQueue = std::make_unique(eventQueueDescriptor, true /* resetPointers */); - // Create the EventFlag that is used to signal to the framework that sensor events have been - // written to the Event FMQ - if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) { - result = Result::BAD_VALUE; - } - // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP // events have been successfully read and handled by the framework. mWakeLockQueue = std::make_unique(wakeLockDescriptor, true /* resetPointers */); + if (mEventQueueFlag != nullptr) { + EventFlag::deleteEventFlag(&mEventQueueFlag); + } + if (mWakelockQueueFlag != nullptr) { + EventFlag::deleteEventFlag(&mWakelockQueueFlag); + } + if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) { + result = Result::BAD_VALUE; + } + if (EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakelockQueueFlag) != OK) { + result = Result::BAD_VALUE; + } if (!mDynamicSensorsCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) { result = Result::BAD_VALUE; } + mThreadsRun.store(true); + mPendingWritesThread = std::thread(startPendingWritesThread, this); mWakelockThread = std::thread(startWakelockThread, this); @@ -157,6 +167,8 @@ Return HalProxy::initialize( } } + mCurrentOperationMode = OperationMode::NORMAL; + return result; } @@ -331,6 +343,41 @@ void HalProxy::init() { initializeSensorList(); } +void HalProxy::stopThreads() { + mThreadsRun.store(false); + if (mEventQueueFlag != nullptr && mEventQueue != nullptr) { + size_t numToRead = mEventQueue->availableToRead(); + std::vector events(numToRead); + mEventQueue->read(events.data(), numToRead); + mEventQueueFlag->wake(static_cast(EventQueueFlagBits::EVENTS_READ)); + } + if (mWakelockQueueFlag != nullptr && mWakeLockQueue != nullptr) { + uint32_t kZero = 0; + mWakeLockQueue->write(&kZero); + mWakelockQueueFlag->wake(static_cast(WakeLockQueueFlagBits::DATA_WRITTEN)); + } + mWakelockCV.notify_one(); + mEventQueueWriteCV.notify_one(); + if (mPendingWritesThread.joinable()) { + mPendingWritesThread.join(); + } + if (mWakelockThread.joinable()) { + mWakelockThread.join(); + } +} + +void HalProxy::disableAllSensors() { + for (const auto& sensorEntry : mSensors) { + int32_t sensorHandle = sensorEntry.first; + activate(sensorHandle, false /* enabled */); + } + std::lock_guard dynamicSensorsLock(mDynamicSensorsMutex); + for (const auto& sensorEntry : mDynamicSensors) { + int32_t sensorHandle = sensorEntry.first; + activate(sensorHandle, false /* enabled */); + } +} + void HalProxy::startPendingWritesThread(HalProxy* halProxy) { halProxy->handlePendingWrites(); } @@ -347,8 +394,6 @@ void HalProxy::handlePendingWrites() { size_t eventQueueSize = mEventQueue->getQuantumCount(); size_t numToWrite = std::min(pendingWriteEvents.size(), eventQueueSize); lock.unlock(); - // TODO: Find a way to interrup writeBlocking if the thread should exit - // so we don't have to wait for timeout on framework restarts. if (!mEventQueue->writeBlocking( pendingWriteEvents.data(), numToWrite, static_cast(EventQueueFlagBits::EVENTS_READ), diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h index 6592afef96..26bc6447a0 100644 --- a/sensors/2.0/multihal/include/HalProxy.h +++ b/sensors/2.0/multihal/include/HalProxy.h @@ -149,9 +149,13 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { std::unique_ptr mWakeLockQueue; /** - * Event Flag to signal to the framework when sensor events are available to be read + * Event Flag to signal to the framework when sensor events are available to be read and to + * interrupt event queue blocking write. */ - EventFlag* mEventQueueFlag; + EventFlag* mEventQueueFlag = nullptr; + + //! Event Flag to signal internally that the wakelock queue should stop its blocking read. + EventFlag* mWakelockQueueFlag = nullptr; /** * Callback to the sensors framework to inform it that new sensors have been added or removed. @@ -253,6 +257,16 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { */ void init(); + /** + * Stops all threads by setting the threads running flag to false and joining to them. + */ + void stopThreads(); + + /** + * Disable all the sensors observed by the HalProxy. + */ + void disableAllSensors(); + /** * Starts the thread that handles pending writes to event fmq. * diff --git a/sensors/2.0/multihal/include/SubHal.h b/sensors/2.0/multihal/include/SubHal.h index e7eedaa3ea..92ae3a61df 100644 --- a/sensors/2.0/multihal/include/SubHal.h +++ b/sensors/2.0/multihal/include/SubHal.h @@ -130,11 +130,13 @@ class ISensorsSubHal : public ISensors { virtual const std::string getName() = 0; /** - * First method invoked on the sub-HAL after it's allocated through sensorsHalGetSubHal() by the - * HalProxy. Sub-HALs should use this to initialize any state and retain the callback given in - * order to communicate with the HalProxy. Method will be called anytime the sensors framework - * restarts. Therefore, this method will be responsible for reseting the state of the subhal and - * cleaning up and reallocating any previously allocated data. + * This is the first method invoked on the sub-HAL after it's allocated through + * sensorsHalGetSubHal() by the HalProxy. Sub-HALs should use this to initialize any state and + * retain the callback given in order to communicate with the HalProxy. Method will be called + * anytime the sensors framework restarts. Therefore, this method will be responsible for + * reseting the state of the subhal and cleaning up and reallocating any previously allocated + * data. Initialize should ensure that the subhal has reset its operation mode to NORMAL state + * as well. * * @param halProxyCallback callback used to inform the HalProxy when a dynamic sensor's state * changes, new sensor events should be sent to the framework, and when a new ScopedWakelock diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp index fa527c9209..040e8c2ca4 100644 --- a/sensors/2.0/multihal/tests/HalProxy_test.cpp +++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp @@ -432,7 +432,7 @@ TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) { EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2); } -TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThreadTest) { +TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThread) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 6; AllSensorsSubHal subHal; @@ -447,13 +447,145 @@ TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThreadTest) { std::vector events = makeMultipleAccelerometerEvents(kNumEvents); subHal.postEvents(events, false /* wakeup */); - // Sleep for a half second so that background thread has time to attempt it's blocking write - std::this_thread::sleep_for(std::chrono::milliseconds(500)); + // Destructing HalProxy object with events on the background thread +} - // Should see a 5 second wait for blocking write timeout here +TEST(HalProxyTest, DestructingWithUnackedWakeupEventsPosted) { + constexpr size_t kQueueSize = 5; + AllSensorsSubHal subHal; + std::vector subHals{&subHal}; - // Should be one events left on pending writes queue here and proxy will destruct - // If this TEST completes then it was a success, if it hangs we will see a crash + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); + ::android::sp callback = new SensorsCallback(); + HalProxy proxy(subHals); + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + + std::vector events{makeProximityEvent()}; + subHal.postEvents(events, true /* wakeup */); + + // Not sending any acks back through wakeLockQueue + + // Destructing HalProxy object with unacked wakeup events posted +} + +TEST(HalProxyTest, ReinitializeWithEventsPendingOnBackgroundThread) { + constexpr size_t kQueueSize = 5; + constexpr size_t kNumEvents = 10; + AllSensorsSubHal subHal; + std::vector subHals{&subHal}; + + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); + ::android::sp callback = new SensorsCallback(); + HalProxy proxy(subHals); + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal.postEvents(events, false /* wakeup */); + + eventQueue = makeEventFMQ(kQueueSize); + wakeLockQueue = makeWakelockFMQ(kQueueSize); + + Result secondInitResult = + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + EXPECT_EQ(secondInitResult, Result::OK); + // Small sleep so that pending writes thread has a change to hit writeBlocking call. + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + Event eventOut; + EXPECT_FALSE(eventQueue->read(&eventOut)); +} + +TEST(HalProxyTest, ReinitializingWithUnackedWakeupEventsPosted) { + constexpr size_t kQueueSize = 5; + AllSensorsSubHal subHal; + std::vector subHals{&subHal}; + + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); + ::android::sp callback = new SensorsCallback(); + HalProxy proxy(subHals); + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + + std::vector events{makeProximityEvent()}; + subHal.postEvents(events, true /* wakeup */); + + // Not sending any acks back through wakeLockQueue + + eventQueue = makeEventFMQ(kQueueSize); + wakeLockQueue = makeWakelockFMQ(kQueueSize); + + Result secondInitResult = + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + EXPECT_EQ(secondInitResult, Result::OK); +} + +TEST(HalProxyTest, InitializeManyTimesInARow) { + constexpr size_t kQueueSize = 5; + constexpr size_t kNumTimesToInit = 100; + AllSensorsSubHal subHal; + std::vector subHals{&subHal}; + + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); + ::android::sp callback = new SensorsCallback(); + HalProxy proxy(subHals); + + for (size_t i = 0; i < kNumTimesToInit; i++) { + Result secondInitResult = + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + EXPECT_EQ(secondInitResult, Result::OK); + } +} + +TEST(HalProxyTest, OperationModeResetOnInitialize) { + constexpr size_t kQueueSize = 5; + AllSensorsSubHal subHal; + std::vector subHals{&subHal}; + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); + ::android::sp callback = new SensorsCallback(); + HalProxy proxy(subHals); + proxy.setOperationMode(OperationMode::DATA_INJECTION); + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + Event event = makeAccelerometerEvent(); + // Should not be able to inject a non AdditionInfo type event because operation mode should + // have been reset to NORMAL + EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE); +} + +TEST(HalProxyTest, DynamicSensorsDiscardedOnInitialize) { + constexpr size_t kQueueSize = 5; + constexpr size_t kNumSensors = 5; + AddAndRemoveDynamicSensorsSubHal subHal; + std::vector subHals{&subHal}; + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); + HalProxy proxy(subHals); + + std::vector sensorsToConnect; + std::vector sensorHandlesToAttemptToRemove; + makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect, + sensorHandlesToAttemptToRemove); + + std::vector nonDynamicSensorHandles; + for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) { + nonDynamicSensorHandles.push_back(sensorHandle); + } + + TestSensorsCallback* callback = new TestSensorsCallback(); + ::android::sp callbackPtr = callback; + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); + subHal.addDynamicSensors(sensorsToConnect); + + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); + subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove); + + std::vector sensorHandlesActuallyRemoved = callback->getSensorHandlesDisconnected(); + + // Should not have received the sensorHandles for any dynamic sensors that were removed since + // all of them should have been removed in the second initialize call. + EXPECT_TRUE(sensorHandlesActuallyRemoved.empty()); } TEST(HalProxyTest, DynamicSensorsConnectedTest) { diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp index cf3ae7560d..0da424622f 100644 --- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp +++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp @@ -158,6 +158,7 @@ Return SensorsSubHal::debug(const hidl_handle& fd, const hidl_vec SensorsSubHal::initialize(const sp& halProxyCallback) { mCallback = halProxyCallback; + setOperationMode(OperationMode::NORMAL); return Result::OK; } From e0721534748f45daf0e41c24c368494c10fb787d Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Thu, 17 Oct 2019 11:58:02 -0700 Subject: [PATCH 0198/1022] MH2 | Check that subhal index is in range For each HalProxy method that takes in a sensorHandle, the code now checks that the subhal index byte (first byte) of the handle is the range of subhals in list before indexing into mSubHalList so that are crash does not occur and returns Result::BAD_VALUE if that is the case. Add unit tests to assert that error is returned. Also change the methods that accept sensorHandles to int32_t type since that is the actual type defined in the HAL spec. Bug: 136511617 Test: Passing new unit tests. Change-Id: I5489e999bc5eaef1a21698bdbc0a0341bc88194c --- sensors/2.0/multihal/HalProxy.cpp | 43 ++++++++++++++++---- sensors/2.0/multihal/include/HalProxy.h | 23 +++++++---- sensors/2.0/multihal/tests/HalProxy_test.cpp | 29 +++++++++++++ 3 files changed, 81 insertions(+), 14 deletions(-) diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index fe2b98b21a..38a627fbec 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -42,6 +42,8 @@ using ::android::hardware::sensors::V2_0::implementation::kWakelockTimeoutNs; typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*); +static constexpr int32_t kBitsAfterSubHalIndex = 24; + /** * Set the subhal index as first byte of sensor handle and return this modified version. * @@ -50,8 +52,19 @@ typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*); * * @return The modified sensor handle. */ -uint32_t setSubHalIndex(uint32_t sensorHandle, size_t subHalIndex) { - return sensorHandle | (subHalIndex << 24); +int32_t setSubHalIndex(int32_t sensorHandle, size_t subHalIndex) { + return sensorHandle | (static_cast(subHalIndex) << kBitsAfterSubHalIndex); +} + +/** + * Extract the subHalIndex from sensorHandle. + * + * @param sensorHandle The sensorHandle to extract from. + * + * @return The subhal index. + */ +size_t extractSubHalIndex(int32_t sensorHandle) { + return static_cast(sensorHandle >> kBitsAfterSubHalIndex); } HalProxy::HalProxy() { @@ -101,6 +114,9 @@ Return HalProxy::setOperationMode(OperationMode mode) { } Return HalProxy::activate(int32_t sensorHandle, bool enabled) { + if (!isSubHalIndexValid(sensorHandle)) { + return Result::BAD_VALUE; + } return getSubHalForSensorHandle(sensorHandle) ->activate(clearSubHalIndex(sensorHandle), enabled); } @@ -174,11 +190,17 @@ Return HalProxy::initialize( Return HalProxy::batch(int32_t sensorHandle, int64_t samplingPeriodNs, int64_t maxReportLatencyNs) { + if (!isSubHalIndexValid(sensorHandle)) { + return Result::BAD_VALUE; + } return getSubHalForSensorHandle(sensorHandle) ->batch(clearSubHalIndex(sensorHandle), samplingPeriodNs, maxReportLatencyNs); } Return HalProxy::flush(int32_t sensorHandle) { + if (!isSubHalIndexValid(sensorHandle)) { + return Result::BAD_VALUE; + } return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle)); } @@ -192,6 +214,9 @@ Return HalProxy::injectSensorData(const Event& event) { } if (result == Result::OK) { Event subHalEvent = event; + if (!isSubHalIndexValid(event.sensorHandle)) { + return Result::BAD_VALUE; + } subHalEvent.sensorHandle = clearSubHalIndex(event.sensorHandle); result = getSubHalForSensorHandle(event.sensorHandle)->injectSensorData(subHalEvent); } @@ -326,7 +351,7 @@ void HalProxy::initializeSensorList() { ALOGE("SubHal sensorHandle's first byte was not 0"); } else { ALOGV("Loaded sensor: %s", sensor.name.c_str()); - sensor.sensorHandle |= (subHalIndex << 24); + sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex); setDirectChannelFlags(&sensor, subHal); mSensors[sensor.sensorHandle] = sensor; } @@ -539,8 +564,12 @@ void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* sub } } -ISensorsSubHal* HalProxy::getSubHalForSensorHandle(uint32_t sensorHandle) { - return mSubHalList[static_cast(sensorHandle >> 24)]; +ISensorsSubHal* HalProxy::getSubHalForSensorHandle(int32_t sensorHandle) { + return mSubHalList[extractSubHalIndex(sensorHandle)]; +} + +bool HalProxy::isSubHalIndexValid(int32_t sensorHandle) { + return extractSubHalIndex(sensorHandle) < mSubHalList.size(); } size_t HalProxy::countNumWakeupEvents(const std::vector& events, size_t n) { @@ -554,11 +583,11 @@ size_t HalProxy::countNumWakeupEvents(const std::vector& events, size_t n return numWakeupEvents; } -uint32_t HalProxy::clearSubHalIndex(uint32_t sensorHandle) { +int32_t HalProxy::clearSubHalIndex(int32_t sensorHandle) { return sensorHandle & (~kSensorHandleSubHalIndexMask); } -bool HalProxy::subHalIndexIsClear(uint32_t sensorHandle) { +bool HalProxy::subHalIndexIsClear(int32_t sensorHandle) { return (sensorHandle & kSensorHandleSubHalIndexMask) == 0; } diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h index 26bc6447a0..10fce43ebb 100644 --- a/sensors/2.0/multihal/include/HalProxy.h +++ b/sensors/2.0/multihal/include/HalProxy.h @@ -124,7 +124,7 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { * * @return The sensor info object in the mapping. */ - const SensorInfo& getSensorInfo(uint32_t sensorHandle) { return mSensors[sensorHandle]; } + const SensorInfo& getSensorInfo(int32_t sensorHandle) { return mSensors[sensorHandle]; } bool areThreadsRunning() { return mThreadsRun.load(); } @@ -177,10 +177,10 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { * The subhal index is encoded in the first byte of the sensor handle and the remaining * bytes are generated by the subhal to identify the sensor. */ - std::map mSensors; + std::map mSensors; //! Map of the dynamic sensors that have been added to halproxy. - std::map mDynamicSensors; + std::map mDynamicSensors; //! The current operation mode for all subhals. OperationMode mCurrentOperationMode = OperationMode::NORMAL; @@ -192,7 +192,7 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { static const int64_t kPendingWriteTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */; //! The bit mask used to get the subhal index from a sensor handle. - static constexpr uint32_t kSensorHandleSubHalIndexMask = 0xFF000000; + static constexpr int32_t kSensorHandleSubHalIndexMask = 0xFF000000; /** * A FIFO queue of pairs of vector of events and the number of wakeup events in that vector @@ -319,7 +319,16 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { * * @param sensorHandle The handle used to identify a sensor in one of the subhals. */ - ISensorsSubHal* getSubHalForSensorHandle(uint32_t sensorHandle); + ISensorsSubHal* getSubHalForSensorHandle(int32_t sensorHandle); + + /** + * Checks that sensorHandle's subhal index byte is within bounds of mSubHalList. + * + * @param sensorHandle The sensor handle to check. + * + * @return true if sensorHandles's subhal index byte is valid. + */ + bool isSubHalIndexValid(int32_t sensorHandle); /** * Count the number of wakeup events in the first n events of the vector. @@ -338,14 +347,14 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { * * @return The modified version of the sensor handle. */ - static uint32_t clearSubHalIndex(uint32_t sensorHandle); + static int32_t clearSubHalIndex(int32_t sensorHandle); /** * @param sensorHandle The sensor handle to modify. * * @return true if subHalIndex byte of sensorHandle is zeroed. */ - static bool subHalIndexIsClear(uint32_t sensorHandle); + static bool subHalIndexIsClear(int32_t sensorHandle); }; /** diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp index 040e8c2ca4..75a4c22d11 100644 --- a/sensors/2.0/multihal/tests/HalProxy_test.cpp +++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp @@ -663,6 +663,35 @@ TEST(HalProxyTest, DynamicSensorsDisconnectedTest) { } } +TEST(HalProxyTest, InvalidSensorHandleSubHalIndexProxyCalls) { + constexpr size_t kNumSubHals = 3; + constexpr size_t kQueueSize = 5; + int32_t kNumSubHalsInt32 = static_cast(kNumSubHals); + std::vector subHalObjs(kNumSubHals); + std::vector subHals; + for (const auto& subHal : subHalObjs) { + subHals.push_back((ISensorsSubHal*)(&subHal)); + } + + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); + ::android::sp callback = new SensorsCallback(); + HalProxy proxy(subHals); + // Initialize for the injectSensorData call so callback postEvents is valid + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + + // For testing proxy.injectSensorData properly + proxy.setOperationMode(OperationMode::DATA_INJECTION); + + // kNumSubHalsInt32 index is one off the end of mSubHalList in proxy object + EXPECT_EQ(proxy.activate(0x00000001 | (kNumSubHalsInt32 << 24), true), Result::BAD_VALUE); + EXPECT_EQ(proxy.batch(0x00000001 | (kNumSubHalsInt32 << 24), 0, 0), Result::BAD_VALUE); + EXPECT_EQ(proxy.flush(0x00000001 | (kNumSubHalsInt32 << 24)), Result::BAD_VALUE); + Event event; + event.sensorHandle = 0x00000001 | (kNumSubHalsInt32 << 24); + EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE); +} + // Helper implementations follow void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, const std::vector& subHalSensorsList) { From e56767d5611a59a0a3bfe4b4b31f347589b86124 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Mon, 30 Sep 2019 09:35:03 -0700 Subject: [PATCH 0199/1022] Wifi: Add getConnectionCapabilities API This commit adds the API for getConnectionCapabilities() in ISupplicantStaIface HAL. This is used to return the Wifi support for the connection on this STA interface. Bug: 138634524 Bug: 140168755 Test: Manual Test: VTS test Change-Id: I24ff3c16434067e41491298e41041bdfdf06452a --- current.txt | 12 +++---- wifi/1.4/IWifi.hal | 3 +- wifi/supplicant/1.3/ISupplicant.hal | 3 +- wifi/supplicant/1.3/ISupplicantStaIface.hal | 13 +++++++- wifi/supplicant/1.3/ISupplicantStaNetwork.hal | 3 +- wifi/supplicant/1.3/types.hal | 33 +++++++++++++++++++ .../supplicant_sta_iface_hidl_test.cpp | 12 +++++++ 7 files changed, 66 insertions(+), 13 deletions(-) diff --git a/current.txt b/current.txt index 87649d2bd9..9ab1967f66 100644 --- a/current.txt +++ b/current.txt @@ -589,12 +589,12 @@ fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardwar 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types 34515afa2bb792d3c6d8495a5f5d907d179c8507ca5e55c10050d02ae1d516ef android.hardware.neuralnetworks@1.3::IDevice b74fe72cfe438f50e772e6a307657ff449d5bde83c15dd1f140ff2edbe73499c android.hardware.neuralnetworks@1.3::types -04395b26be33db17747c3d3b0e8066d323f891ff4f9f3b3ddb490b2f3f844a18 android.hardware.wifi@1.4::IWifi -270f0eb670dfd9bc5cd718e09711f2534fa8425f54d06c1a46523ca156b509e2 android.hardware.wifi.supplicant@1.3::ISupplicant -dd4b7cfbb6e1c6ff011c33920762ad89dd02240c63a4d3a3d5037f154eae3e3b android.hardware.wifi.supplicant@1.3::ISupplicantStaIface -619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback -6fe09b18e913608579638594788198ec45bb2369e567d7df661db46c4f0e5f08 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork -91931b05bd70ea6bdffbe075086183f803379571788564e28854207620eb75cf android.hardware.wifi.supplicant@1.3::types 544049dcda3f943ad67d83d5277f06681a3782982a9af5a78b5d4e8d295d061a android.hardware.vibrator@1.4::IVibrator 5e1c12efbbba89c9143d10b1b90eceff8bc79aa079f5106215b528e104fef101 android.hardware.vibrator@1.4::IVibratorCallback 033eae03c09ebc75e82db37bc39995dfaa9086745577b44d9e14e9ccb48bd8cc android.hardware.vibrator@1.4::types +3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi +a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant +0a7ff83fd0326b82232e1609da98f34960be11335df72fc407ad238d7bd0e081 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface +619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback +c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork +b0f8c9cd61a45a8c1b4a8e40913ecaea0921011cbe2305a6fa5a2feaa0d36c30 android.hardware.wifi.supplicant@1.3::types diff --git a/wifi/1.4/IWifi.hal b/wifi/1.4/IWifi.hal index f4bc618f10..765e09d16a 100644 --- a/wifi/1.4/IWifi.hal +++ b/wifi/1.4/IWifi.hal @@ -24,5 +24,4 @@ import @1.3::IWifi; * module loaded in the system. * IWifi.getChip() must return @1.2::IWifiChip */ -interface IWifi extends @1.3::IWifi { -}; +interface IWifi extends @1.3::IWifi {}; diff --git a/wifi/supplicant/1.3/ISupplicant.hal b/wifi/supplicant/1.3/ISupplicant.hal index 75b7e960ea..246ce1fec3 100644 --- a/wifi/supplicant/1.3/ISupplicant.hal +++ b/wifi/supplicant/1.3/ISupplicant.hal @@ -26,5 +26,4 @@ import @1.2::ISupplicant; * 1.2 HAL. For example V1_2::ISupplicant::addIface() adds V1_2::ISupplicantIface, * which can be cast to V1_3::ISupplicantStaIface. */ -interface ISupplicant extends @1.2::ISupplicant { -}; +interface ISupplicant extends @1.2::ISupplicant {}; diff --git a/wifi/supplicant/1.3/ISupplicantStaIface.hal b/wifi/supplicant/1.3/ISupplicantStaIface.hal index 62b40333e9..cb207d836e 100644 --- a/wifi/supplicant/1.3/ISupplicantStaIface.hal +++ b/wifi/supplicant/1.3/ISupplicantStaIface.hal @@ -18,7 +18,7 @@ package android.hardware.wifi.supplicant@1.3; import @1.0::SupplicantStatus; import @1.2::ISupplicantStaIface; -import @1.3::ISupplicantStaIfaceCallback; +import ISupplicantStaIfaceCallback; /** * Interface exposed by the supplicant for each station mode network @@ -43,4 +43,15 @@ interface ISupplicantStaIface extends @1.2::ISupplicantStaIface { */ registerCallback_1_3(ISupplicantStaIfaceCallback callback) generates (SupplicantStatus status); + + /** + * Get Connection capabilities + * + * @return status Status of the operation, and connection capabilities. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + */ + getConnectionCapabilities() + generates (SupplicantStatus status, ConnectionCapabilities capabilities); }; diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal index 5e265c6257..ab08cff9c5 100644 --- a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal +++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal @@ -60,6 +60,5 @@ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { * |SupplicantStatusCode.FAILURE_UNKNOWN|, * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| */ - setPmkCache(vec serializedEntry) - generates (SupplicantStatus status); + setPmkCache(vec serializedEntry) generates (SupplicantStatus status); }; diff --git a/wifi/supplicant/1.3/types.hal b/wifi/supplicant/1.3/types.hal index a782b49584..787439984b 100644 --- a/wifi/supplicant/1.3/types.hal +++ b/wifi/supplicant/1.3/types.hal @@ -25,3 +25,36 @@ enum OcspType : uint32_t { REQUIRE_CERT_STATUS, REQUIRE_ALL_CERTS_STATUS, }; + +/** + * Wifi Technologies + */ +enum WifiTechnology : uint32_t { + UNKNOWN = 0, + /** + * For 802.11a/b/g + */ + LEGACY = 1, + /** + * For 802.11n + */ + HT = 2, + /** + * For 802.11ac + */ + VHT = 3, + /** + * For 802.11ax + */ + HE = 4, +}; + +/** + * Connection Capabilities. + */ +struct ConnectionCapabilities { + /** + * Wifi Technology + */ + WifiTechnology technology; +}; diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp index 9b68a4708d..62f3228c40 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp @@ -37,6 +37,7 @@ using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; using ::android::hardware::wifi::supplicant::V1_2::DppAkm; using ::android::hardware::wifi::supplicant::V1_2::DppFailureCode; using ::android::hardware::wifi::supplicant::V1_2::DppProgressCode; +using ::android::hardware::wifi::supplicant::V1_3::ConnectionCapabilities; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIfaceCallback; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork; @@ -179,3 +180,14 @@ TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback_1_3) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); }); } + +/* + * getConnectionCapabilities + */ +TEST_F(SupplicantStaIfaceHidlTest, GetConnectionCapabilities) { + sta_iface_->getConnectionCapabilities( + [&](const SupplicantStatus& status, + ConnectionCapabilities /* capabilities */) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); +} From 1de5bb334c7eece01bec0fa16b1b0a6d5305c09f Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Fri, 18 Oct 2019 14:21:58 -0700 Subject: [PATCH 0200/1022] MH2 | Fix wakelock name Name is supposed to be "SensorsHAL_WAKEUP". Bug: 142505817 Test: N/A Change-Id: I79f01509bffba499678fa519d038db37e2a9efbd --- sensors/2.0/multihal/include/HalProxy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h index 26bc6447a0..aee63b1f23 100644 --- a/sensors/2.0/multihal/include/HalProxy.h +++ b/sensors/2.0/multihal/include/HalProxy.h @@ -233,7 +233,7 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { int64_t mWakelockTimeoutResetTime = getTimeNow(); - const char* kWakelockName = "SensorsMultiHal"; + const char* kWakelockName = "SensorsHAL_WAKEUP"; /** * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries From bf46132fe532a533c8dcb5aeb3301be579d6198a Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Thu, 17 Oct 2019 13:40:35 -0700 Subject: [PATCH 0201/1022] MH2 | Implement debug method of HalProxy Bug: 9569382 Test: Observed debug output from $ adb shell lshal debug android.hardware.sensors@2.0::ISensors/default Change-Id: I9f2627a05d37bd8407a22e263b7557834a9677b8 --- sensors/2.0/multihal/Android.bp | 1 + sensors/2.0/multihal/HalProxy.cpp | 53 ++++++++++++++++++++++++++- sensors/2.0/multihal/tests/Android.bp | 1 + 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp index 5c6767671e..c13eaf2e92 100644 --- a/sensors/2.0/multihal/Android.bp +++ b/sensors/2.0/multihal/Android.bp @@ -21,6 +21,7 @@ cc_defaults { shared_libs: [ "android.hardware.sensors@1.0", "android.hardware.sensors@2.0", + "libbase", "libcutils", "libfmq", "libhidlbase", diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index fe2b98b21a..43e3af658c 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -20,11 +20,13 @@ #include +#include #include "hardware_legacy/power.h" #include #include +#include #include #include #include @@ -54,6 +56,18 @@ uint32_t setSubHalIndex(uint32_t sensorHandle, size_t subHalIndex) { return sensorHandle | (subHalIndex << 24); } +/** + * Convert nanoseconds to milliseconds. + * + * @param nanos The nanoseconds input. + * + * @return The milliseconds count. + */ +int64_t msFromNs(int64_t nanos) { + constexpr int64_t nanosecondsInAMillsecond = 1000000; + return nanos / nanosecondsInAMillsecond; +} + HalProxy::HalProxy() { const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf"; initializeSubHalListFromConfigFile(kMultiHalConfigFile); @@ -229,8 +243,43 @@ Return HalProxy::configDirectReport(int32_t sensorHandle, int32_t channelH return Return(); } -Return HalProxy::debug(const hidl_handle& /* fd */, const hidl_vec& /* args */) { - // TODO: output debug information +Return HalProxy::debug(const hidl_handle& fd, const hidl_vec& /*args*/) { + if (fd.getNativeHandle() == nullptr || fd->numFds < 1) { + ALOGE("%s: missing fd for writing", __FUNCTION__); + return Void(); + } + + android::base::borrowed_fd writeFd = dup(fd->data[0]); + + std::ostringstream stream; + stream << "===HalProxy===" << std::endl; + stream << "Internal values:" << std::endl; + stream << " Threads are running: " << (mThreadsRun.load() ? "true" : "false") << std::endl; + int64_t now = getTimeNow(); + stream << " Wakelock timeout start time: " << msFromNs(now - mWakelockTimeoutStartTime) + << " ms ago" << std::endl; + stream << " Wakelock timeout reset time: " << msFromNs(now - mWakelockTimeoutResetTime) + << " ms ago" << std::endl; + // TODO(b/142969448): Add logging for history of wakelock acquisition per subhal. + stream << " Wakelock ref count: " << mWakelockRefCount << std::endl; + stream << " Size of pending write events queue: " << mPendingWriteEventsQueue.size() + << std::endl; + if (!mPendingWriteEventsQueue.empty()) { + stream << " Size of events list on front of pending writes queue: " + << mPendingWriteEventsQueue.front().first.size() << std::endl; + } + stream << " # of non-dynamic sensors across all subhals: " << mSensors.size() << std::endl; + stream << " # of dynamic sensors across all subhals: " << mDynamicSensors.size() << std::endl; + stream << "SubHals (" << mSubHalList.size() << "):" << std::endl; + for (ISensorsSubHal* subHal : mSubHalList) { + stream << " Name: " << subHal->getName() << std::endl; + stream << " Debug dump: " << std::endl; + android::base::WriteStringToFd(stream.str(), writeFd); + subHal->debug(fd, {}); + stream.str(""); + stream << std::endl; + } + android::base::WriteStringToFd(stream.str(), writeFd); return Return(); } diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp index e3a4af1e5a..50a55f946e 100644 --- a/sensors/2.0/multihal/tests/Android.bp +++ b/sensors/2.0/multihal/tests/Android.bp @@ -82,6 +82,7 @@ cc_test { shared_libs: [ "android.hardware.sensors@1.0", "android.hardware.sensors@2.0", + "libbase", "libcutils", "libfmq", "libhidlbase", From 86e1aebad122c283c5d9c7278c9c339cb0491dcc Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 22 Oct 2019 15:49:46 -0700 Subject: [PATCH 0202/1022] [RenderEngine] Fix test build for RenderEngine refactor Fix build after refactor of creation flags. BUG: 142331374 Test: build, flash and boot Change-Id: I59c2858f8e35426e2eb08c91e8797efd738a3922 --- graphics/composer/2.2/utils/vts/RenderEngineVts.cpp | 9 ++++----- .../vts/include/composer-vts/2.2/RenderEngineVts.h | 6 ++++-- .../VtsHalGraphicsComposerV2_2ReadbackTest.cpp | 11 ++++++++--- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp index d910169bfb..e2f267012f 100644 --- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp +++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp @@ -26,12 +26,11 @@ namespace vts { using mapper::V2_1::IMapper; using renderengine::DisplaySettings; using renderengine::LayerSettings; +using renderengine::RenderEngineCreationArgs; -TestRenderEngine::TestRenderEngine(common::V1_1::PixelFormat hwcFormat, - uint32_t renderEngineFeatures) { - mFormat = hwcFormat; - mRenderEngine = renderengine::RenderEngine::create( - static_cast(mFormat), renderEngineFeatures, mMaxFrameBufferAcquireBuffers); +TestRenderEngine::TestRenderEngine(const RenderEngineCreationArgs& args) { + mFormat = static_cast(args.pixelFormat); + mRenderEngine = renderengine::RenderEngine::create(args); } void TestRenderEngine::setRenderLayers(std::vector> layers) { diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h index 0ac5a22683..b936cabb1e 100644 --- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h +++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h @@ -35,11 +35,14 @@ namespace vts { using mapper::V2_1::IMapper; using renderengine::DisplaySettings; +using renderengine::RenderEngineCreationArgs; using vts::Gralloc; class TestRenderEngine { public: - TestRenderEngine(common::V1_1::PixelFormat hwcFormat, uint32_t renderEngineFeatures); + static constexpr uint32_t sMaxFrameBufferAcquireBuffers = 2; + + TestRenderEngine(const RenderEngineCreationArgs& args); ~TestRenderEngine() = default; void setRenderLayers(std::vector> layers); @@ -51,7 +54,6 @@ class TestRenderEngine { void checkColorBuffer(std::vector& expectedColors); private: - static constexpr uint32_t mMaxFrameBufferAcquireBuffers = 2; common::V1_1::PixelFormat mFormat; std::vector mCompositionLayers; std::unique_ptr mRenderEngine; diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp index ade7a38222..6a6f7de6ac 100644 --- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp @@ -103,9 +103,14 @@ class GraphicsCompositionTest : public ::testing::VtsHalHidlTargetTestBase { ASSERT_NO_FATAL_FAILURE( mTestRenderEngine = std::unique_ptr(new TestRenderEngine( - PixelFormat::RGBA_8888, - renderengine::RenderEngine::USE_COLOR_MANAGEMENT | - renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT))); + renderengine::RenderEngineCreationArgs::Builder() + .setPixelFormat(static_cast(ui::PixelFormat::RGBA_8888)) + .setImageCacheSize(TestRenderEngine::sMaxFrameBufferAcquireBuffers) + .setUseColorManagerment(true) + .setEnableProtectedContext(false) + .setPrecacheToneMapperShaderOnly(false) + .setContextPriority(renderengine::RenderEngine::ContextPriority::HIGH) + .build()))); renderengine::DisplaySettings clientCompositionDisplay; clientCompositionDisplay.physicalDisplay = Rect(mDisplayWidth, mDisplayHeight); From d861e2be96ccf99af31ab0ea886b7d898999b24d Mon Sep 17 00:00:00 2001 From: Malcolm Chen Date: Wed, 2 Oct 2019 11:38:13 -0700 Subject: [PATCH 0203/1022] Create IRadio 1.5 folder and empty files. So that later people can add APIs and type definitions as needed. Bug: 141995149 Test: build Change-Id: Ib18f75fd391b94ffbd65d7feb4589ff82b3ac1d4 --- current.txt | 5 +++++ radio/1.5/Android.bp | 25 +++++++++++++++++++++++++ radio/1.5/IRadio.hal | 30 ++++++++++++++++++++++++++++++ radio/1.5/IRadioIndication.hal | 26 ++++++++++++++++++++++++++ radio/1.5/IRadioResponse.hal | 26 ++++++++++++++++++++++++++ radio/1.5/types.hal | 17 +++++++++++++++++ 6 files changed, 129 insertions(+) create mode 100644 radio/1.5/Android.bp create mode 100644 radio/1.5/IRadio.hal create mode 100644 radio/1.5/IRadioIndication.hal create mode 100644 radio/1.5/IRadioResponse.hal create mode 100644 radio/1.5/types.hal diff --git a/current.txt b/current.txt index 9ab1967f66..3ccc531b71 100644 --- a/current.txt +++ b/current.txt @@ -598,3 +598,8 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar 619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork b0f8c9cd61a45a8c1b4a8e40913ecaea0921011cbe2305a6fa5a2feaa0d36c30 android.hardware.wifi.supplicant@1.3::types +41c602462ccd1b19cfd645994be4de4c07fc197ff58a54e84476b31908e61e21 android.hardware.radio@1.5::types +a8691c71747c3f14f7a043598e856425077f755e55990507a9132ad62f8ab3f7 android.hardware.radio@1.5::IRadio +a62a93faf173b14a6175b683ebf61ffa568dc61f81e369d2dce7b1265e86cf2f android.hardware.radio@1.5::IRadioIndication +15daf260aaf6781b911450bc94e1a164901f9c0fe0bda68f8434f0a903f66e05 android.hardware.radio@1.5::IRadioResponse + diff --git a/radio/1.5/Android.bp b/radio/1.5/Android.bp new file mode 100644 index 0000000000..06a2a6ecf3 --- /dev/null +++ b/radio/1.5/Android.bp @@ -0,0 +1,25 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.radio@1.5", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IRadio.hal", + "IRadioIndication.hal", + "IRadioResponse.hal", + ], + interfaces: [ + "android.hardware.radio@1.0", + "android.hardware.radio@1.1", + "android.hardware.radio@1.2", + "android.hardware.radio@1.3", + "android.hardware.radio@1.4", + "android.hidl.base@1.0", + "android.hidl.safe_union@1.0", + ], + gen_java: true, +} diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal new file mode 100644 index 0000000000..de20dd08fd --- /dev/null +++ b/radio/1.5/IRadio.hal @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package android.hardware.radio@1.5; + +import @1.4::IRadio; + +/** + * This interface is used by telephony and telecom to talk to cellular radio. + * All the functions have minimum one parameter: + * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the + * duration of a method call. If clients provide colliding serials (including passing the same + * serial to different methods), multiple responses (one for each method call) must still be served. + * setResponseFunctions must work with @1.5::IRadioResponse and @1.5::IRadioIndication. + */ +interface IRadio extends @1.4::IRadio { +}; diff --git a/radio/1.5/IRadioIndication.hal b/radio/1.5/IRadioIndication.hal new file mode 100644 index 0000000000..d4884041c5 --- /dev/null +++ b/radio/1.5/IRadioIndication.hal @@ -0,0 +1,26 @@ +/* + * 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. + */ + +package android.hardware.radio@1.5; + +import @1.0::RadioIndicationType; +import @1.4::IRadioIndication; + +/** + * Interface declaring unsolicited radio indications. + */ +interface IRadioIndication extends @1.4::IRadioIndication { +}; diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal new file mode 100644 index 0000000000..d4c4f766af --- /dev/null +++ b/radio/1.5/IRadioResponse.hal @@ -0,0 +1,26 @@ +/* + * 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. + */ + +package android.hardware.radio@1.5; + +import @1.0::RadioResponseInfo; +import @1.4::IRadioResponse; + +/** + * Interface declaring response functions to solicited radio requests. + */ +interface IRadioResponse extends @1.4::IRadioResponse { +}; diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal new file mode 100644 index 0000000000..a639a8d1d9 --- /dev/null +++ b/radio/1.5/types.hal @@ -0,0 +1,17 @@ +/* + * 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. + */ + +package android.hardware.radio@1.5; From 7f9a0157b1842f05501d5fc75621dd0c3083808d Mon Sep 17 00:00:00 2001 From: Malcolm Chen Date: Tue, 8 Oct 2019 18:31:04 -0700 Subject: [PATCH 0204/1022] Creating IRadio 1.5 vts framework. Bug: 141995149 Test: build Change-Id: I260dfa2e57f1b8c7df5273e2d0b39cbc1d6a4571 --- radio/1.5/vts/OWNERS | 10 + radio/1.5/vts/functional/Android.bp | 40 + .../functional/VtsHalRadioV1_5TargetTest.cpp | 26 + .../1.5/vts/functional/radio_hidl_hal_api.cpp | 19 + .../vts/functional/radio_hidl_hal_test.cpp | 94 ++ .../functional/radio_hidl_hal_utils_v1_5.h | 760 +++++++++++++++ radio/1.5/vts/functional/radio_indication.cpp | 330 +++++++ radio/1.5/vts/functional/radio_response.cpp | 887 ++++++++++++++++++ 8 files changed, 2166 insertions(+) create mode 100644 radio/1.5/vts/OWNERS create mode 100644 radio/1.5/vts/functional/Android.bp create mode 100644 radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp create mode 100644 radio/1.5/vts/functional/radio_hidl_hal_api.cpp create mode 100644 radio/1.5/vts/functional/radio_hidl_hal_test.cpp create mode 100644 radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h create mode 100644 radio/1.5/vts/functional/radio_indication.cpp create mode 100644 radio/1.5/vts/functional/radio_response.cpp diff --git a/radio/1.5/vts/OWNERS b/radio/1.5/vts/OWNERS new file mode 100644 index 0000000000..3629a6c1f4 --- /dev/null +++ b/radio/1.5/vts/OWNERS @@ -0,0 +1,10 @@ +# Telephony team +refuhoo@google.com +amitmahajan@google.com +jackyu@google.com +fionaxu@google.com +# more to add + +# VTS team +yuexima@google.com +dshi@google.com \ No newline at end of file diff --git a/radio/1.5/vts/functional/Android.bp b/radio/1.5/vts/functional/Android.bp new file mode 100644 index 0000000000..85c4f99db4 --- /dev/null +++ b/radio/1.5/vts/functional/Android.bp @@ -0,0 +1,40 @@ +// +// 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. +// + +cc_test { + name: "VtsHalRadioV1_5TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "radio_hidl_hal_api.cpp", + "radio_hidl_hal_test.cpp", + "radio_response.cpp", + "radio_indication.cpp", + "VtsHalRadioV1_5TargetTest.cpp", + ], + static_libs: [ + "RadioVtsTestUtilBase", + "android.hardware.radio@1.5", + "android.hardware.radio@1.4", + "android.hardware.radio@1.3", + "android.hardware.radio@1.2", + "android.hardware.radio@1.1", + "android.hardware.radio@1.0", + "android.hardware.radio.config@1.0", + "android.hardware.radio.config@1.1", + ], + header_libs: ["radio.util.header@1.0"], + test_suites: ["general-tests"] +} diff --git a/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp b/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp new file mode 100644 index 0000000000..b72febddf0 --- /dev/null +++ b/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2018 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 + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(RadioHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + RadioHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} \ No newline at end of file diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp new file mode 100644 index 0000000000..b86fa5f59b --- /dev/null +++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp @@ -0,0 +1,19 @@ +/* + * 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. + */ + +#include + +#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) diff --git a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp new file mode 100644 index 0000000000..a5d236d47f --- /dev/null +++ b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp @@ -0,0 +1,94 @@ +/* + * 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. + */ + +#include + +void RadioHidlTest_v1_5::SetUp() { + radio_v1_5 = ::testing::VtsHalHidlTargetTestBase::getService< + ::android::hardware::radio::V1_5::IRadio>( + RadioHidlEnvironment::Instance() + ->getServiceName<::android::hardware::radio::V1_5::IRadio>( + hidl_string(RADIO_SERVICE_NAME))); + if (radio_v1_5 == NULL) { + sleep(60); + radio_v1_5 = ::testing::VtsHalHidlTargetTestBase::getService< + ::android::hardware::radio::V1_5::IRadio>( + RadioHidlEnvironment::Instance() + ->getServiceName<::android::hardware::radio::V1_5::IRadio>( + hidl_string(RADIO_SERVICE_NAME))); + } + ASSERT_NE(nullptr, radio_v1_5.get()); + + radioRsp_v1_5 = new (std::nothrow) RadioResponse_v1_5(*this); + ASSERT_NE(nullptr, radioRsp_v1_5.get()); + + count_ = 0; + + radioInd_v1_5 = new (std::nothrow) RadioIndication_v1_5(*this); + ASSERT_NE(nullptr, radioInd_v1_5.get()); + + radio_v1_5->setResponseFunctions(radioRsp_v1_5, radioInd_v1_5); + + updateSimCardStatus(); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); + + sp<::android::hardware::radio::config::V1_1::IRadioConfig> radioConfig = + ::testing::VtsHalHidlTargetTestBase::getService< + ::android::hardware::radio::config::V1_1::IRadioConfig>(); + + /* Enforce Vts tesing with RadioConfig is existed. */ + ASSERT_NE(nullptr, radioConfig.get()); + + /* Enforce Vts Testing with Sim Status Present only. */ + EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.cardState); +} + +/* + * Notify that the response message is received. + */ +void RadioHidlTest_v1_5::notify(int receivedSerial) { + std::unique_lock lock(mtx_); + if (serial == receivedSerial) { + count_++; + cv_.notify_one(); + } +} + +/* + * Wait till the response message is notified or till TIMEOUT_PERIOD. + */ +std::cv_status RadioHidlTest_v1_5::wait() { + std::unique_lock lock(mtx_); + + std::cv_status status = std::cv_status::no_timeout; + auto now = std::chrono::system_clock::now(); + while (count_ == 0) { + status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD)); + if (status == std::cv_status::timeout) { + return status; + } + } + count_--; + return status; +} + +void RadioHidlTest_v1_5::updateSimCardStatus() { + serial = GetRandomSerialNumber(); + radio_v1_5->getIccCardStatus(serial); + EXPECT_EQ(std::cv_status::no_timeout, wait()); +} diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h new file mode 100644 index 0000000000..799702b9a1 --- /dev/null +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -0,0 +1,760 @@ +/* + * 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. + */ + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "vts_test_util.h" + +using namespace ::android::hardware::radio::V1_5; +using namespace ::android::hardware::radio::V1_4; +using namespace ::android::hardware::radio::V1_3; +using namespace ::android::hardware::radio::V1_2; +using namespace ::android::hardware::radio::V1_1; +using namespace ::android::hardware::radio::V1_0; + +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +#define TIMEOUT_PERIOD 75 +#define MODEM_EMERGENCY_CALL_ESTABLISH_TIME 3 +#define MODEM_EMERGENCY_CALL_DISCONNECT_TIME 3 + +#define RADIO_SERVICE_NAME "slot1" + +class RadioHidlTest_v1_5; +extern ::android::hardware::radio::V1_4::CardStatus cardStatus; + +/* Callback class for radio respons v1_5 */ +class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioResponse { + protected: + RadioHidlTest_v1_5& parent_v1_5; + + public: + hidl_vec radioBandModes; + + RadioResponseInfo rspInfo; + + // Call + hidl_vec<::android::hardware::radio::V1_2::Call> currentCalls; + + // Modem + bool isModemEnabled; + bool enableModemResponseToggle; + + ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_4::RadioAccessFamily> + networkTypeBitmapResponse; + + // Data + ::android::hardware::radio::V1_4::DataRegStateResult dataRegResp; + + // SimLock status + ::android::hardware::radio::V1_4::CarrierRestrictionsWithPriority carrierRestrictionsResp; + ::android::hardware::radio::V1_4::SimLockMultiSimPolicy multiSimPolicyResp; + + RadioResponse_v1_5(RadioHidlTest_v1_5& parent_v1_5); + virtual ~RadioResponse_v1_5() = default; + + Return getIccCardStatusResponse( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_0::CardStatus& cardStatus); + + Return supplyIccPinForAppResponse(const RadioResponseInfo& info, + int32_t remainingRetries); + + Return supplyIccPukForAppResponse(const RadioResponseInfo& info, + int32_t remainingRetries); + + Return supplyIccPin2ForAppResponse(const RadioResponseInfo& info, + int32_t remainingRetries); + + Return supplyIccPuk2ForAppResponse(const RadioResponseInfo& info, + int32_t remainingRetries); + + Return changeIccPinForAppResponse(const RadioResponseInfo& info, + int32_t remainingRetries); + + Return changeIccPin2ForAppResponse(const RadioResponseInfo& info, + int32_t remainingRetries); + + Return supplyNetworkDepersonalizationResponse(const RadioResponseInfo& info, + int32_t remainingRetries); + + Return getCurrentCallsResponse( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& calls); + + Return dialResponse(const RadioResponseInfo& info); + + Return getIMSIForAppResponse(const RadioResponseInfo& info, + const ::android::hardware::hidl_string& imsi); + + Return hangupConnectionResponse(const RadioResponseInfo& info); + + Return hangupWaitingOrBackgroundResponse(const RadioResponseInfo& info); + + Return hangupForegroundResumeBackgroundResponse(const RadioResponseInfo& info); + + Return switchWaitingOrHoldingAndActiveResponse(const RadioResponseInfo& info); + + Return conferenceResponse(const RadioResponseInfo& info); + + Return rejectCallResponse(const RadioResponseInfo& info); + + Return getLastCallFailCauseResponse(const RadioResponseInfo& info, + const LastCallFailCauseInfo& failCauseInfo); + + Return getSignalStrengthResponse( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_0::SignalStrength& sigStrength); + + Return getVoiceRegistrationStateResponse( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_0::VoiceRegStateResult& voiceRegResponse); + + Return getDataRegistrationStateResponse( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_0::DataRegStateResult& dataRegResponse); + + Return getOperatorResponse(const RadioResponseInfo& info, + const ::android::hardware::hidl_string& longName, + const ::android::hardware::hidl_string& shortName, + const ::android::hardware::hidl_string& numeric); + + Return setRadioPowerResponse(const RadioResponseInfo& info); + + Return sendDtmfResponse(const RadioResponseInfo& info); + + Return sendSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms); + + Return sendSMSExpectMoreResponse(const RadioResponseInfo& info, const SendSmsResult& sms); + + Return setupDataCallResponse( + const RadioResponseInfo& info, + const android::hardware::radio::V1_0::SetupDataCallResult& dcResponse); + + Return iccIOForAppResponse(const RadioResponseInfo& info, const IccIoResult& iccIo); + + Return sendUssdResponse(const RadioResponseInfo& info); + + Return cancelPendingUssdResponse(const RadioResponseInfo& info); + + Return getClirResponse(const RadioResponseInfo& info, int32_t n, int32_t m); + + Return setClirResponse(const RadioResponseInfo& info); + + Return getCallForwardStatusResponse( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec& call_forwardInfos); + + Return setCallForwardResponse(const RadioResponseInfo& info); + + Return getCallWaitingResponse(const RadioResponseInfo& info, bool enable, + int32_t serviceClass); + + Return setCallWaitingResponse(const RadioResponseInfo& info); + + Return acknowledgeLastIncomingGsmSmsResponse(const RadioResponseInfo& info); + + Return acceptCallResponse(const RadioResponseInfo& info); + + Return deactivateDataCallResponse(const RadioResponseInfo& info); + + Return getFacilityLockForAppResponse(const RadioResponseInfo& info, int32_t response); + + Return setFacilityLockForAppResponse(const RadioResponseInfo& info, int32_t retry); + + Return setBarringPasswordResponse(const RadioResponseInfo& info); + + Return getNetworkSelectionModeResponse(const RadioResponseInfo& info, bool manual); + + Return setNetworkSelectionModeAutomaticResponse(const RadioResponseInfo& info); + + Return setNetworkSelectionModeManualResponse(const RadioResponseInfo& info); + + Return getAvailableNetworksResponse( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec& networkInfos); + + Return startDtmfResponse(const RadioResponseInfo& info); + + Return stopDtmfResponse(const RadioResponseInfo& info); + + Return getBasebandVersionResponse(const RadioResponseInfo& info, + const ::android::hardware::hidl_string& version); + + Return separateConnectionResponse(const RadioResponseInfo& info); + + Return setMuteResponse(const RadioResponseInfo& info); + + Return getMuteResponse(const RadioResponseInfo& info, bool enable); + + Return getClipResponse(const RadioResponseInfo& info, ClipStatus status); + + Return getDataCallListResponse( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec< + android::hardware::radio::V1_0::SetupDataCallResult>& dcResponse); + + Return sendOemRilRequestRawResponse(const RadioResponseInfo& info, + const ::android::hardware::hidl_vec& data); + + Return sendOemRilRequestStringsResponse( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& data); + + Return setSuppServiceNotificationsResponse(const RadioResponseInfo& info); + + Return writeSmsToSimResponse(const RadioResponseInfo& info, int32_t index); + + Return deleteSmsOnSimResponse(const RadioResponseInfo& info); + + Return setBandModeResponse(const RadioResponseInfo& info); + + Return getAvailableBandModesResponse( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec& bandModes); + + Return sendEnvelopeResponse(const RadioResponseInfo& info, + const ::android::hardware::hidl_string& commandResponse); + + Return sendTerminalResponseToSimResponse(const RadioResponseInfo& info); + + Return handleStkCallSetupRequestFromSimResponse(const RadioResponseInfo& info); + + Return explicitCallTransferResponse(const RadioResponseInfo& info); + + Return setPreferredNetworkTypeResponse(const RadioResponseInfo& info); + + Return getPreferredNetworkTypeResponse(const RadioResponseInfo& info, + PreferredNetworkType nwType); + + Return getNeighboringCidsResponse( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec& cells); + + Return setLocationUpdatesResponse(const RadioResponseInfo& info); + + Return setCdmaSubscriptionSourceResponse(const RadioResponseInfo& info); + + Return setCdmaRoamingPreferenceResponse(const RadioResponseInfo& info); + + Return getCdmaRoamingPreferenceResponse(const RadioResponseInfo& info, + CdmaRoamingType type); + + Return setTTYModeResponse(const RadioResponseInfo& info); + + Return getTTYModeResponse(const RadioResponseInfo& info, TtyMode mode); + + Return setPreferredVoicePrivacyResponse(const RadioResponseInfo& info); + + Return getPreferredVoicePrivacyResponse(const RadioResponseInfo& info, bool enable); + + Return sendCDMAFeatureCodeResponse(const RadioResponseInfo& info); + + Return sendBurstDtmfResponse(const RadioResponseInfo& info); + + Return sendCdmaSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms); + + Return acknowledgeLastIncomingCdmaSmsResponse(const RadioResponseInfo& info); + + Return getGsmBroadcastConfigResponse( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec& configs); + + Return setGsmBroadcastConfigResponse(const RadioResponseInfo& info); + + Return setGsmBroadcastActivationResponse(const RadioResponseInfo& info); + + Return getCdmaBroadcastConfigResponse( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec& configs); + + Return setCdmaBroadcastConfigResponse(const RadioResponseInfo& info); + + Return setCdmaBroadcastActivationResponse(const RadioResponseInfo& info); + + Return getCDMASubscriptionResponse(const RadioResponseInfo& info, + const ::android::hardware::hidl_string& mdn, + const ::android::hardware::hidl_string& hSid, + const ::android::hardware::hidl_string& hNid, + const ::android::hardware::hidl_string& min, + const ::android::hardware::hidl_string& prl); + + Return writeSmsToRuimResponse(const RadioResponseInfo& info, uint32_t index); + + Return deleteSmsOnRuimResponse(const RadioResponseInfo& info); + + Return getDeviceIdentityResponse(const RadioResponseInfo& info, + const ::android::hardware::hidl_string& imei, + const ::android::hardware::hidl_string& imeisv, + const ::android::hardware::hidl_string& esn, + const ::android::hardware::hidl_string& meid); + + Return exitEmergencyCallbackModeResponse(const RadioResponseInfo& info); + + Return getSmscAddressResponse(const RadioResponseInfo& info, + const ::android::hardware::hidl_string& smsc); + + Return setSmscAddressResponse(const RadioResponseInfo& info); + + Return reportSmsMemoryStatusResponse(const RadioResponseInfo& info); + + Return reportStkServiceIsRunningResponse(const RadioResponseInfo& info); + + Return getCdmaSubscriptionSourceResponse(const RadioResponseInfo& info, + CdmaSubscriptionSource source); + + Return requestIsimAuthenticationResponse( + const RadioResponseInfo& info, const ::android::hardware::hidl_string& response); + + Return acknowledgeIncomingGsmSmsWithPduResponse(const RadioResponseInfo& info); + + Return sendEnvelopeWithStatusResponse(const RadioResponseInfo& info, + const IccIoResult& iccIo); + + Return getVoiceRadioTechnologyResponse( + const RadioResponseInfo& info, ::android::hardware::radio::V1_0::RadioTechnology rat); + + Return getCellInfoListResponse( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::CellInfo>& + cellInfo); + + Return setCellInfoListRateResponse(const RadioResponseInfo& info); + + Return setInitialAttachApnResponse(const RadioResponseInfo& info); + + Return getImsRegistrationStateResponse(const RadioResponseInfo& info, bool isRegistered, + RadioTechnologyFamily ratFamily); + + Return sendImsSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms); + + Return iccTransmitApduBasicChannelResponse(const RadioResponseInfo& info, + const IccIoResult& result); + + Return iccOpenLogicalChannelResponse( + const RadioResponseInfo& info, int32_t channelId, + const ::android::hardware::hidl_vec& selectResponse); + + Return iccCloseLogicalChannelResponse(const RadioResponseInfo& info); + + Return iccTransmitApduLogicalChannelResponse(const RadioResponseInfo& info, + const IccIoResult& result); + + Return nvReadItemResponse(const RadioResponseInfo& info, + const ::android::hardware::hidl_string& result); + + Return nvWriteItemResponse(const RadioResponseInfo& info); + + Return nvWriteCdmaPrlResponse(const RadioResponseInfo& info); + + Return nvResetConfigResponse(const RadioResponseInfo& info); + + Return setUiccSubscriptionResponse(const RadioResponseInfo& info); + + Return setDataAllowedResponse(const RadioResponseInfo& info); + + Return getHardwareConfigResponse( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec& config); + + Return requestIccSimAuthenticationResponse(const RadioResponseInfo& info, + const IccIoResult& result); + + Return setDataProfileResponse(const RadioResponseInfo& info); + + Return requestShutdownResponse(const RadioResponseInfo& info); + + Return getRadioCapabilityResponse( + const RadioResponseInfo& info, + const android::hardware::radio::V1_0::RadioCapability& rc); + + Return setRadioCapabilityResponse( + const RadioResponseInfo& info, + const android::hardware::radio::V1_0::RadioCapability& rc); + + Return startLceServiceResponse(const RadioResponseInfo& info, + const LceStatusInfo& statusInfo); + + Return stopLceServiceResponse(const RadioResponseInfo& info, + const LceStatusInfo& statusInfo); + + Return pullLceDataResponse(const RadioResponseInfo& info, const LceDataInfo& lceInfo); + + Return getModemActivityInfoResponse(const RadioResponseInfo& info, + const ActivityStatsInfo& activityInfo); + + Return setAllowedCarriersResponse(const RadioResponseInfo& info, int32_t numAllowed); + + Return getAllowedCarriersResponse(const RadioResponseInfo& info, bool allAllowed, + const CarrierRestrictions& carriers); + + Return sendDeviceStateResponse(const RadioResponseInfo& info); + + Return setIndicationFilterResponse(const RadioResponseInfo& info); + + Return setSimCardPowerResponse(const RadioResponseInfo& info); + + Return acknowledgeRequest(int32_t serial); + + /* 1.1 Api */ + Return setCarrierInfoForImsiEncryptionResponse(const RadioResponseInfo& info); + + Return setSimCardPowerResponse_1_1(const RadioResponseInfo& info); + + Return startNetworkScanResponse(const RadioResponseInfo& info); + + Return stopNetworkScanResponse(const RadioResponseInfo& info); + + Return startKeepaliveResponse(const RadioResponseInfo& info, + const KeepaliveStatus& status); + + Return stopKeepaliveResponse(const RadioResponseInfo& info); + + /* 1.2 Api */ + Return setSignalStrengthReportingCriteriaResponse(const RadioResponseInfo& info); + + Return setLinkCapacityReportingCriteriaResponse(const RadioResponseInfo& info); + + Return getIccCardStatusResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_2::CardStatus& card_status); + + Return getCurrentCallsResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& calls); + + Return getSignalStrengthResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_2::SignalStrength& sig_strength); + + Return getSignalStrengthResponse_1_4( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_4::SignalStrength& sig_strength); + + Return getCellInfoListResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::CellInfo>& + cellInfo); + + Return getVoiceRegistrationStateResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_2::VoiceRegStateResult& voiceRegResponse); + + Return getDataRegistrationStateResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_2::DataRegStateResult& dataRegResponse); + + /* 1.3 Api */ + Return setSystemSelectionChannelsResponse(const RadioResponseInfo& info); + + Return enableModemResponse(const RadioResponseInfo& info); + + Return getModemStackStatusResponse(const RadioResponseInfo& info, const bool enabled); + + /* 1.4 Api */ + Return emergencyDialResponse(const RadioResponseInfo& info); + + Return startNetworkScanResponse_1_4(const RadioResponseInfo& info); + + Return getCellInfoListResponse_1_4( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::CellInfo>& + cellInfo); + + Return getDataRegistrationStateResponse_1_4( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_4::DataRegStateResult& dataRegResponse); + + Return getIccCardStatusResponse_1_4( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_4::CardStatus& card_status); + + Return getPreferredNetworkTypeBitmapResponse( + const RadioResponseInfo& info, + const ::android::hardware::hidl_bitfield< + ::android::hardware::radio::V1_4::RadioAccessFamily> + networkTypeBitmap); + + Return setPreferredNetworkTypeBitmapResponse(const RadioResponseInfo& info); + + Return getDataCallListResponse_1_4( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_4::SetupDataCallResult>& dcResponse); + + Return setupDataCallResponse_1_4( + const RadioResponseInfo& info, + const android::hardware::radio::V1_4::SetupDataCallResult& dcResponse); + + Return setAllowedCarriersResponse_1_4(const RadioResponseInfo& info); + + Return getAllowedCarriersResponse_1_4(const RadioResponseInfo& info, + const CarrierRestrictionsWithPriority& carriers, + SimLockMultiSimPolicy multiSimPolicy); +}; + +/* Callback class for radio indication */ +class RadioIndication_v1_5 : public ::android::hardware::radio::V1_5::IRadioIndication { + protected: + RadioHidlTest_v1_5& parent_v1_5; + + public: + RadioIndication_v1_5(RadioHidlTest_v1_5& parent_v1_5); + virtual ~RadioIndication_v1_5() = default; + + /* 1.4 Api */ + Return currentEmergencyNumberList( + RadioIndicationType type, + const ::android::hardware::hidl_vec& emergencyNumberList); + + Return cellInfoList_1_4( + RadioIndicationType type, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::CellInfo>& + records); + + Return networkScanResult_1_4( + RadioIndicationType type, + const ::android::hardware::radio::V1_4::NetworkScanResult& result); + + Return currentPhysicalChannelConfigs_1_4( + RadioIndicationType type, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_4::PhysicalChannelConfig>& configs); + + Return dataCallListChanged_1_4( + RadioIndicationType type, + const ::android::hardware::hidl_vec< + android::hardware::radio::V1_4::SetupDataCallResult>& dcList); + + /* 1.2 Api */ + Return networkScanResult_1_2( + RadioIndicationType type, + const ::android::hardware::radio::V1_2::NetworkScanResult& result); + + Return cellInfoList_1_2( + RadioIndicationType type, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::CellInfo>& + records); + + Return currentLinkCapacityEstimate( + RadioIndicationType type, + const ::android::hardware::radio::V1_2::LinkCapacityEstimate& lce); + + Return currentPhysicalChannelConfigs( + RadioIndicationType type, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_2::PhysicalChannelConfig>& configs); + + Return currentSignalStrength_1_2( + RadioIndicationType type, + const ::android::hardware::radio::V1_2::SignalStrength& signalStrength); + + Return currentSignalStrength_1_4( + RadioIndicationType type, + const ::android::hardware::radio::V1_4::SignalStrength& signalStrength); + + /* 1.1 Api */ + Return carrierInfoForImsiEncryption(RadioIndicationType info); + + Return networkScanResult( + RadioIndicationType type, + const ::android::hardware::radio::V1_1::NetworkScanResult& result); + + Return keepaliveStatus(RadioIndicationType type, const KeepaliveStatus& status); + + /* 1.0 Api */ + Return radioStateChanged(RadioIndicationType type, RadioState radioState); + + Return callStateChanged(RadioIndicationType type); + + Return networkStateChanged(RadioIndicationType type); + + Return newSms(RadioIndicationType type, + const ::android::hardware::hidl_vec& pdu); + + Return newSmsStatusReport(RadioIndicationType type, + const ::android::hardware::hidl_vec& pdu); + + Return newSmsOnSim(RadioIndicationType type, int32_t recordNumber); + + Return onUssd(RadioIndicationType type, UssdModeType modeType, + const ::android::hardware::hidl_string& msg); + + Return nitzTimeReceived(RadioIndicationType type, + const ::android::hardware::hidl_string& nitzTime, + uint64_t receivedTime); + + Return currentSignalStrength( + RadioIndicationType type, + const ::android::hardware::radio::V1_0::SignalStrength& signalStrength); + + Return dataCallListChanged( + RadioIndicationType type, + const ::android::hardware::hidl_vec< + android::hardware::radio::V1_0::SetupDataCallResult>& dcList); + + Return suppSvcNotify(RadioIndicationType type, const SuppSvcNotification& suppSvc); + + Return stkSessionEnd(RadioIndicationType type); + + Return stkProactiveCommand(RadioIndicationType type, + const ::android::hardware::hidl_string& cmd); + + Return stkEventNotify(RadioIndicationType type, + const ::android::hardware::hidl_string& cmd); + + Return stkCallSetup(RadioIndicationType type, int64_t timeout); + + Return simSmsStorageFull(RadioIndicationType type); + + Return simRefresh(RadioIndicationType type, const SimRefreshResult& refreshResult); + + Return callRing(RadioIndicationType type, bool isGsm, const CdmaSignalInfoRecord& record); + + Return simStatusChanged(RadioIndicationType type); + + Return cdmaNewSms(RadioIndicationType type, const CdmaSmsMessage& msg); + + Return newBroadcastSms(RadioIndicationType type, + const ::android::hardware::hidl_vec& data); + + Return cdmaRuimSmsStorageFull(RadioIndicationType type); + + Return restrictedStateChanged(RadioIndicationType type, PhoneRestrictedState state); + + Return enterEmergencyCallbackMode(RadioIndicationType type); + + Return cdmaCallWaiting(RadioIndicationType type, + const CdmaCallWaiting& callWaitingRecord); + + Return cdmaOtaProvisionStatus(RadioIndicationType type, CdmaOtaProvisionStatus status); + + Return cdmaInfoRec(RadioIndicationType type, const CdmaInformationRecords& records); + + Return indicateRingbackTone(RadioIndicationType type, bool start); + + Return resendIncallMute(RadioIndicationType type); + + Return cdmaSubscriptionSourceChanged(RadioIndicationType type, + CdmaSubscriptionSource cdmaSource); + + Return cdmaPrlChanged(RadioIndicationType type, int32_t version); + + Return exitEmergencyCallbackMode(RadioIndicationType type); + + Return rilConnected(RadioIndicationType type); + + Return voiceRadioTechChanged(RadioIndicationType type, + ::android::hardware::radio::V1_0::RadioTechnology rat); + + Return cellInfoList( + RadioIndicationType type, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::CellInfo>& + records); + + Return imsNetworkStateChanged(RadioIndicationType type); + + Return subscriptionStatusChanged(RadioIndicationType type, bool activate); + + Return srvccStateNotify(RadioIndicationType type, SrvccState state); + + Return hardwareConfigChanged( + RadioIndicationType type, const ::android::hardware::hidl_vec& configs); + + Return radioCapabilityIndication( + RadioIndicationType type, const android::hardware::radio::V1_0::RadioCapability& rc); + + Return onSupplementaryServiceIndication(RadioIndicationType type, + const StkCcUnsolSsResult& ss); + + Return stkCallControlAlphaNotify(RadioIndicationType type, + const ::android::hardware::hidl_string& alpha); + + Return lceData(RadioIndicationType type, const LceDataInfo& lce); + + Return pcoData(RadioIndicationType type, const PcoDataInfo& pco); + + Return modemReset(RadioIndicationType type, + const ::android::hardware::hidl_string& reason); +}; + +// Test environment for Radio HIDL HAL. +class RadioHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static RadioHidlEnvironment* Instance() { + static RadioHidlEnvironment* instance = new RadioHidlEnvironment; + return instance; + } + virtual void registerTestServices() override { + registerTestService<::android::hardware::radio::V1_5::IRadio>(); + } + + private: + RadioHidlEnvironment() {} +}; + +// The main test class for Radio HIDL. +class RadioHidlTest_v1_5 : public ::testing::VtsHalHidlTargetTestBase { + protected: + std::mutex mtx_; + std::condition_variable cv_; + int count_; + + /* Serial number for radio request */ + int serial; + + /* Clear Potential Established Calls */ + void clearPotentialEstablishedCalls(); + + /* Update Sim Card Status */ + void updateSimCardStatus(); + + public: + virtual void SetUp() override; + + /* Used as a mechanism to inform the test about data/event callback */ + void notify(int receivedSerial); + + /* Test code calls this function to wait for response */ + std::cv_status wait(); + + /* radio service handle */ + sp<::android::hardware::radio::V1_5::IRadio> radio_v1_5; + + /* radio response handle */ + sp radioRsp_v1_5; + + /* radio indication handle */ + sp radioInd_v1_5; +}; diff --git a/radio/1.5/vts/functional/radio_indication.cpp b/radio/1.5/vts/functional/radio_indication.cpp new file mode 100644 index 0000000000..b63b74571e --- /dev/null +++ b/radio/1.5/vts/functional/radio_indication.cpp @@ -0,0 +1,330 @@ +/* + * 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. + */ + +#include + +RadioIndication_v1_5::RadioIndication_v1_5(RadioHidlTest_v1_5& parent) : parent_v1_5(parent) {} + +/* 1.4 Apis */ +Return RadioIndication_v1_5::currentPhysicalChannelConfigs_1_4( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_4::PhysicalChannelConfig>& /*configs*/) { + return Void(); +} + +Return RadioIndication_v1_5::networkScanResult_1_4( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_4::NetworkScanResult& /*result*/) { + return Void(); +} + +Return RadioIndication_v1_5::cellInfoList_1_4( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_4::CellInfo>& /*records*/) { + return Void(); +} + +Return RadioIndication_v1_5::currentEmergencyNumberList( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec& /*emergencyNumberList*/) { + return Void(); +} + +Return RadioIndication_v1_5::dataCallListChanged_1_4( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec& + /*dcList*/) { + return Void(); +} + +/* 1.2 Apis */ +Return RadioIndication_v1_5::networkScanResult_1_2( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_2::NetworkScanResult& /*result*/) { + return Void(); +} + +Return RadioIndication_v1_5::cellInfoList_1_2( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_2::CellInfo>& /*records*/) { + return Void(); +} + +Return RadioIndication_v1_5::currentLinkCapacityEstimate( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_2::LinkCapacityEstimate& /*lce*/) { + return Void(); +} + +Return RadioIndication_v1_5::currentPhysicalChannelConfigs( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_2::PhysicalChannelConfig>& /*configs*/) { + return Void(); +} + +Return RadioIndication_v1_5::currentSignalStrength_1_2( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_2::SignalStrength& /*signalStrength*/) { + return Void(); +} + +Return RadioIndication_v1_5::currentSignalStrength_1_4( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_4::SignalStrength& /*signalStrength*/) { + return Void(); +} + +/* 1.1 Apis */ +Return RadioIndication_v1_5::carrierInfoForImsiEncryption(RadioIndicationType /*info*/) { + return Void(); +} + +Return RadioIndication_v1_5::networkScanResult( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_1::NetworkScanResult& /*result*/) { + return Void(); +} + +Return RadioIndication_v1_5::keepaliveStatus(RadioIndicationType /*type*/, + const KeepaliveStatus& /*status*/) { + return Void(); +} + +/* 1.0 Apis */ +Return RadioIndication_v1_5::radioStateChanged(RadioIndicationType /*type*/, + RadioState /*radioState*/) { + return Void(); +} + +Return RadioIndication_v1_5::callStateChanged(RadioIndicationType /*type*/) { + return Void(); +} + +Return RadioIndication_v1_5::networkStateChanged(RadioIndicationType /*type*/) { + return Void(); +} + +Return RadioIndication_v1_5::newSms(RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec& /*pdu*/) { + return Void(); +} + +Return RadioIndication_v1_5::newSmsStatusReport( + RadioIndicationType /*type*/, const ::android::hardware::hidl_vec& /*pdu*/) { + return Void(); +} + +Return RadioIndication_v1_5::newSmsOnSim(RadioIndicationType /*type*/, + int32_t /*recordNumber*/) { + return Void(); +} + +Return RadioIndication_v1_5::onUssd(RadioIndicationType /*type*/, UssdModeType /*modeType*/, + const ::android::hardware::hidl_string& /*msg*/) { + return Void(); +} + +Return RadioIndication_v1_5::nitzTimeReceived( + RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*nitzTime*/, + uint64_t /*receivedTime*/) { + return Void(); +} + +Return RadioIndication_v1_5::currentSignalStrength( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_0::SignalStrength& /*signalStrength*/) { + return Void(); +} + +Return RadioIndication_v1_5::dataCallListChanged( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec& + /*dcList*/) { + return Void(); +} + +Return RadioIndication_v1_5::suppSvcNotify(RadioIndicationType /*type*/, + const SuppSvcNotification& /*suppSvc*/) { + return Void(); +} + +Return RadioIndication_v1_5::stkSessionEnd(RadioIndicationType /*type*/) { + return Void(); +} + +Return RadioIndication_v1_5::stkProactiveCommand( + RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*cmd*/) { + return Void(); +} + +Return RadioIndication_v1_5::stkEventNotify(RadioIndicationType /*type*/, + const ::android::hardware::hidl_string& /*cmd*/) { + return Void(); +} + +Return RadioIndication_v1_5::stkCallSetup(RadioIndicationType /*type*/, int64_t /*timeout*/) { + return Void(); +} + +Return RadioIndication_v1_5::simSmsStorageFull(RadioIndicationType /*type*/) { + return Void(); +} + +Return RadioIndication_v1_5::simRefresh(RadioIndicationType /*type*/, + const SimRefreshResult& /*refreshResult*/) { + return Void(); +} + +Return RadioIndication_v1_5::callRing(RadioIndicationType /*type*/, bool /*isGsm*/, + const CdmaSignalInfoRecord& /*record*/) { + return Void(); +} + +Return RadioIndication_v1_5::simStatusChanged(RadioIndicationType /*type*/) { + return Void(); +} + +Return RadioIndication_v1_5::cdmaNewSms(RadioIndicationType /*type*/, + const CdmaSmsMessage& /*msg*/) { + return Void(); +} + +Return RadioIndication_v1_5::newBroadcastSms( + RadioIndicationType /*type*/, const ::android::hardware::hidl_vec& /*data*/) { + return Void(); +} + +Return RadioIndication_v1_5::cdmaRuimSmsStorageFull(RadioIndicationType /*type*/) { + return Void(); +} + +Return RadioIndication_v1_5::restrictedStateChanged(RadioIndicationType /*type*/, + PhoneRestrictedState /*state*/) { + return Void(); +} + +Return RadioIndication_v1_5::enterEmergencyCallbackMode(RadioIndicationType /*type*/) { + return Void(); +} + +Return RadioIndication_v1_5::cdmaCallWaiting(RadioIndicationType /*type*/, + const CdmaCallWaiting& /*callWaitingRecord*/) { + return Void(); +} + +Return RadioIndication_v1_5::cdmaOtaProvisionStatus(RadioIndicationType /*type*/, + CdmaOtaProvisionStatus /*status*/) { + return Void(); +} + +Return RadioIndication_v1_5::cdmaInfoRec(RadioIndicationType /*type*/, + const CdmaInformationRecords& /*records*/) { + return Void(); +} + +Return RadioIndication_v1_5::indicateRingbackTone(RadioIndicationType /*type*/, + bool /*start*/) { + return Void(); +} + +Return RadioIndication_v1_5::resendIncallMute(RadioIndicationType /*type*/) { + return Void(); +} + +Return RadioIndication_v1_5::cdmaSubscriptionSourceChanged( + RadioIndicationType /*type*/, CdmaSubscriptionSource /*cdmaSource*/) { + return Void(); +} + +Return RadioIndication_v1_5::cdmaPrlChanged(RadioIndicationType /*type*/, + int32_t /*version*/) { + return Void(); +} + +Return RadioIndication_v1_5::exitEmergencyCallbackMode(RadioIndicationType /*type*/) { + return Void(); +} + +Return RadioIndication_v1_5::rilConnected(RadioIndicationType /*type*/) { + return Void(); +} + +Return RadioIndication_v1_5::voiceRadioTechChanged( + RadioIndicationType /*type*/, ::android::hardware::radio::V1_0::RadioTechnology /*rat*/) { + return Void(); +} + +Return RadioIndication_v1_5::cellInfoList( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_0::CellInfo>& /*records*/) { + return Void(); +} + +Return RadioIndication_v1_5::imsNetworkStateChanged(RadioIndicationType /*type*/) { + return Void(); +} + +Return RadioIndication_v1_5::subscriptionStatusChanged(RadioIndicationType /*type*/, + bool /*activate*/) { + return Void(); +} + +Return RadioIndication_v1_5::srvccStateNotify(RadioIndicationType /*type*/, + SrvccState /*state*/) { + return Void(); +} + +Return RadioIndication_v1_5::hardwareConfigChanged( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec& /*configs*/) { + return Void(); +} + +Return RadioIndication_v1_5::radioCapabilityIndication( + RadioIndicationType /*type*/, + const android::hardware::radio::V1_0::RadioCapability& /*rc*/) { + return Void(); +} + +Return RadioIndication_v1_5::onSupplementaryServiceIndication( + RadioIndicationType /*type*/, const StkCcUnsolSsResult& /*ss*/) { + return Void(); +} + +Return RadioIndication_v1_5::stkCallControlAlphaNotify( + RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*alpha*/) { + return Void(); +} + +Return RadioIndication_v1_5::lceData(RadioIndicationType /*type*/, + const LceDataInfo& /*lce*/) { + return Void(); +} + +Return RadioIndication_v1_5::pcoData(RadioIndicationType /*type*/, + const PcoDataInfo& /*pco*/) { + return Void(); +} + +Return RadioIndication_v1_5::modemReset(RadioIndicationType /*type*/, + const ::android::hardware::hidl_string& /*reason*/) { + return Void(); +} diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp new file mode 100644 index 0000000000..1e5cc4775b --- /dev/null +++ b/radio/1.5/vts/functional/radio_response.cpp @@ -0,0 +1,887 @@ +/* + * 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. + */ + +#include + +::android::hardware::radio::V1_4::CardStatus cardStatus; + +RadioResponse_v1_5::RadioResponse_v1_5(RadioHidlTest_v1_5& parent) : parent_v1_5(parent) {} + +/* 1.0 Apis */ +Return RadioResponse_v1_5::getIccCardStatusResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::radio::V1_0::CardStatus& /*card_status*/) { + return Void(); +} + +Return RadioResponse_v1_5::supplyIccPinForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return RadioResponse_v1_5::supplyIccPukForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return RadioResponse_v1_5::supplyIccPin2ForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return RadioResponse_v1_5::supplyIccPuk2ForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return RadioResponse_v1_5::changeIccPinForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return RadioResponse_v1_5::changeIccPin2ForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return RadioResponse_v1_5::supplyNetworkDepersonalizationResponse( + const RadioResponseInfo& /*info*/, int32_t /*remainingRetries*/) { + return Void(); +} + +Return RadioResponse_v1_5::getCurrentCallsResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& /*calls*/) { + return Void(); +} + +Return RadioResponse_v1_5::dialResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getIMSIForAppResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*imsi*/) { + return Void(); +} + +Return RadioResponse_v1_5::hangupConnectionResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::hangupWaitingOrBackgroundResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::hangupForegroundResumeBackgroundResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::switchWaitingOrHoldingAndActiveResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::conferenceResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::rejectCallResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getLastCallFailCauseResponse( + const RadioResponseInfo& /*info*/, const LastCallFailCauseInfo& /*failCauseInfo*/) { + return Void(); +} + +Return RadioResponse_v1_5::getSignalStrengthResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::radio::V1_0::SignalStrength& /*sig_strength*/) { + return Void(); +} + +Return RadioResponse_v1_5::getVoiceRegistrationStateResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::radio::V1_0::VoiceRegStateResult& /*voiceRegResponse*/) { + return Void(); +} + +Return RadioResponse_v1_5::getDataRegistrationStateResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::radio::V1_0::DataRegStateResult& /*dataRegResponse*/) { + return Void(); +} + +Return RadioResponse_v1_5::getOperatorResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*longName*/, + const ::android::hardware::hidl_string& /*shortName*/, + const ::android::hardware::hidl_string& /*numeric*/) { + return Void(); +} + +Return RadioResponse_v1_5::setRadioPowerResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::sendDtmfResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::sendSmsResponse(const RadioResponseInfo& /*info*/, + const SendSmsResult& /*sms*/) { + return Void(); +} + +Return RadioResponse_v1_5::sendSMSExpectMoreResponse(const RadioResponseInfo& /*info*/, + const SendSmsResult& /*sms*/) { + return Void(); +} + +Return RadioResponse_v1_5::setupDataCallResponse( + const RadioResponseInfo& /*info*/, + const android::hardware::radio::V1_0::SetupDataCallResult& /*dcResponse*/) { + return Void(); +} + +Return RadioResponse_v1_5::iccIOForAppResponse(const RadioResponseInfo& /*info*/, + const IccIoResult& /*iccIo*/) { + return Void(); +} + +Return RadioResponse_v1_5::sendUssdResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::cancelPendingUssdResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getClirResponse(const RadioResponseInfo& /*info*/, int32_t /*n*/, + int32_t /*m*/) { + return Void(); +} + +Return RadioResponse_v1_5::setClirResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getCallForwardStatusResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec& + /*callForwardInfos*/) { + return Void(); +} + +Return RadioResponse_v1_5::setCallForwardResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getCallWaitingResponse(const RadioResponseInfo& /*info*/, + bool /*enable*/, int32_t /*serviceClass*/) { + return Void(); +} + +Return RadioResponse_v1_5::setCallWaitingResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::acknowledgeLastIncomingGsmSmsResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::acceptCallResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::deactivateDataCallResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::getFacilityLockForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*response*/) { + return Void(); +} + +Return RadioResponse_v1_5::setFacilityLockForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*retry*/) { + return Void(); +} + +Return RadioResponse_v1_5::setBarringPasswordResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getNetworkSelectionModeResponse(const RadioResponseInfo& /*info*/, + bool /*manual*/) { + return Void(); +} + +Return RadioResponse_v1_5::setNetworkSelectionModeAutomaticResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::setNetworkSelectionModeManualResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getAvailableNetworksResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec& /*networkInfos*/) { + return Void(); +} + +Return RadioResponse_v1_5::startDtmfResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::stopDtmfResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getBasebandVersionResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*version*/) { + return Void(); +} + +Return RadioResponse_v1_5::separateConnectionResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::setMuteResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getMuteResponse(const RadioResponseInfo& /*info*/, + bool /*enable*/) { + return Void(); +} + +Return RadioResponse_v1_5::getClipResponse(const RadioResponseInfo& /*info*/, + ClipStatus /*status*/) { + return Void(); +} + +Return RadioResponse_v1_5::getDataCallListResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec& + /*dcResponse*/) { + return Void(); +} + +Return RadioResponse_v1_5::sendOemRilRequestRawResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec& /*data*/) { + return Void(); +} + +Return RadioResponse_v1_5::sendOemRilRequestStringsResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& /*data*/) { + return Void(); +} + +Return RadioResponse_v1_5::setSuppServiceNotificationsResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::writeSmsToSimResponse(const RadioResponseInfo& /*info*/, + int32_t /*index*/) { + return Void(); +} + +Return RadioResponse_v1_5::deleteSmsOnSimResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::setBandModeResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getAvailableBandModesResponse( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec& bandModes) { + rspInfo = info; + radioBandModes = bandModes; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::sendEnvelopeResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_string& /*commandResponse*/) { + return Void(); +} + +Return RadioResponse_v1_5::sendTerminalResponseToSimResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::handleStkCallSetupRequestFromSimResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::explicitCallTransferResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::setPreferredNetworkTypeResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getPreferredNetworkTypeResponse(const RadioResponseInfo& /*info*/, + PreferredNetworkType /*nw_type*/) { + return Void(); +} + +Return RadioResponse_v1_5::getNeighboringCidsResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec& /*cells*/) { + return Void(); +} + +Return RadioResponse_v1_5::setLocationUpdatesResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::setCdmaSubscriptionSourceResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::setCdmaRoamingPreferenceResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getCdmaRoamingPreferenceResponse(const RadioResponseInfo& /*info*/, + CdmaRoamingType /*type*/) { + return Void(); +} + +Return RadioResponse_v1_5::setTTYModeResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getTTYModeResponse(const RadioResponseInfo& /*info*/, + TtyMode /*mode*/) { + return Void(); +} + +Return RadioResponse_v1_5::setPreferredVoicePrivacyResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getPreferredVoicePrivacyResponse(const RadioResponseInfo& /*info*/, + bool /*enable*/) { + return Void(); +} + +Return RadioResponse_v1_5::sendCDMAFeatureCodeResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::sendBurstDtmfResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::sendCdmaSmsResponse(const RadioResponseInfo& /*info*/, + const SendSmsResult& /*sms*/) { + return Void(); +} + +Return RadioResponse_v1_5::acknowledgeLastIncomingCdmaSmsResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getGsmBroadcastConfigResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec& /*configs*/) { + return Void(); +} + +Return RadioResponse_v1_5::setGsmBroadcastConfigResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::setGsmBroadcastActivationResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getCdmaBroadcastConfigResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec& /*configs*/) { + return Void(); +} + +Return RadioResponse_v1_5::setCdmaBroadcastConfigResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::setCdmaBroadcastActivationResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getCDMASubscriptionResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*mdn*/, + const ::android::hardware::hidl_string& /*hSid*/, + const ::android::hardware::hidl_string& /*hNid*/, + const ::android::hardware::hidl_string& /*min*/, + const ::android::hardware::hidl_string& /*prl*/) { + return Void(); +} + +Return RadioResponse_v1_5::writeSmsToRuimResponse(const RadioResponseInfo& /*info*/, + uint32_t /*index*/) { + return Void(); +} + +Return RadioResponse_v1_5::deleteSmsOnRuimResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getDeviceIdentityResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*imei*/, + const ::android::hardware::hidl_string& /*imeisv*/, + const ::android::hardware::hidl_string& /*esn*/, + const ::android::hardware::hidl_string& /*meid*/) { + return Void(); +} + +Return RadioResponse_v1_5::exitEmergencyCallbackModeResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getSmscAddressResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*smsc*/) { + return Void(); +} + +Return RadioResponse_v1_5::setSmscAddressResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::reportSmsMemoryStatusResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::reportStkServiceIsRunningResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getCdmaSubscriptionSourceResponse( + const RadioResponseInfo& /*info*/, CdmaSubscriptionSource /*source*/) { + return Void(); +} + +Return RadioResponse_v1_5::requestIsimAuthenticationResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*response*/) { + return Void(); +} + +Return RadioResponse_v1_5::acknowledgeIncomingGsmSmsWithPduResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::sendEnvelopeWithStatusResponse(const RadioResponseInfo& /*info*/, + const IccIoResult& /*iccIo*/) { + return Void(); +} + +Return RadioResponse_v1_5::getVoiceRadioTechnologyResponse( + const RadioResponseInfo& /*info*/, + ::android::hardware::radio::V1_0::RadioTechnology /*rat*/) { + return Void(); +} + +Return RadioResponse_v1_5::getCellInfoListResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_0::CellInfo>& /*cellInfo*/) { + return Void(); +} + +Return RadioResponse_v1_5::setCellInfoListRateResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::setInitialAttachApnResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::getImsRegistrationStateResponse( + const RadioResponseInfo& /*info*/, bool /*isRegistered*/, + RadioTechnologyFamily /*ratFamily*/) { + return Void(); +} + +Return RadioResponse_v1_5::sendImsSmsResponse(const RadioResponseInfo& /*info*/, + const SendSmsResult& /*sms*/) { + return Void(); +} + +Return RadioResponse_v1_5::iccTransmitApduBasicChannelResponse( + const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) { + return Void(); +} + +Return RadioResponse_v1_5::iccOpenLogicalChannelResponse( + const RadioResponseInfo& /*info*/, int32_t /*channelId*/, + const ::android::hardware::hidl_vec& /*selectResponse*/) { + return Void(); +} + +Return RadioResponse_v1_5::iccCloseLogicalChannelResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::iccTransmitApduLogicalChannelResponse( + const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) { + return Void(); +} + +Return RadioResponse_v1_5::nvReadItemResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*result*/) { + return Void(); +} + +Return RadioResponse_v1_5::nvWriteItemResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::nvWriteCdmaPrlResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::nvResetConfigResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::setUiccSubscriptionResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::setDataAllowedResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getHardwareConfigResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec& /*config*/) { + return Void(); +} + +Return RadioResponse_v1_5::requestIccSimAuthenticationResponse( + const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) { + return Void(); +} + +Return RadioResponse_v1_5::setDataProfileResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::requestShutdownResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::getRadioCapabilityResponse( + const RadioResponseInfo& /*info*/, + const android::hardware::radio::V1_0::RadioCapability& /*rc*/) { + return Void(); +} + +Return RadioResponse_v1_5::setRadioCapabilityResponse( + const RadioResponseInfo& /*info*/, + const android::hardware::radio::V1_0::RadioCapability& /*rc*/) { + return Void(); +} + +Return RadioResponse_v1_5::startLceServiceResponse(const RadioResponseInfo& /*info*/, + const LceStatusInfo& /*statusInfo*/) { + return Void(); +} + +Return RadioResponse_v1_5::stopLceServiceResponse(const RadioResponseInfo& /*info*/, + const LceStatusInfo& /*statusInfo*/) { + return Void(); +} + +Return RadioResponse_v1_5::pullLceDataResponse(const RadioResponseInfo& /*info*/, + const LceDataInfo& /*lceInfo*/) { + return Void(); +} + +Return RadioResponse_v1_5::getModemActivityInfoResponse( + const RadioResponseInfo& /*info*/, const ActivityStatsInfo& /*activityInfo*/) { + return Void(); +} + +Return RadioResponse_v1_5::setAllowedCarriersResponse(const RadioResponseInfo& /*info*/, + int32_t /*numAllowed*/) { + return Void(); +} + +Return RadioResponse_v1_5::getAllowedCarriersResponse( + const RadioResponseInfo& /*info*/, bool /*allAllowed*/, + const CarrierRestrictions& /*carriers*/) { + return Void(); +} + +Return RadioResponse_v1_5::sendDeviceStateResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::setIndicationFilterResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::setSimCardPowerResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::acknowledgeRequest(int32_t /*serial*/) { + return Void(); +} + +/* 1.1 Apis */ +Return RadioResponse_v1_5::setCarrierInfoForImsiEncryptionResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::setSimCardPowerResponse_1_1(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::startNetworkScanResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return RadioResponse_v1_5::stopNetworkScanResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::startKeepaliveResponse(const RadioResponseInfo& /*info*/, + const KeepaliveStatus& /*status*/) { + return Void(); +} + +Return RadioResponse_v1_5::stopKeepaliveResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +/* 1.2 Apis */ +Return RadioResponse_v1_5::setSignalStrengthReportingCriteriaResponse( + const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::setLinkCapacityReportingCriteriaResponse( + const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::getIccCardStatusResponse_1_2( + const RadioResponseInfo& /*info*/, + const ::android::hardware::radio::V1_2::CardStatus& /*card_status*/) { + return Void(); +} + +Return RadioResponse_v1_5::getCurrentCallsResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& calls) { + rspInfo = info; + currentCalls = calls; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::getSignalStrengthResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_2::SignalStrength& /*sig_strength*/) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::getSignalStrengthResponse_1_4( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_4::SignalStrength& /*sig_strength*/) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::getCellInfoListResponse_1_2( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_2::CellInfo>& /*cellInfo*/) { + return Void(); +} + +Return RadioResponse_v1_5::getVoiceRegistrationStateResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_2::VoiceRegStateResult& /*voiceRegResponse*/) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::getDataRegistrationStateResponse_1_2( + const RadioResponseInfo& /*info*/, + const ::android::hardware::radio::V1_2::DataRegStateResult& /*dataRegResponse*/) { + return Void(); +} + +/* 1.3 Apis */ +Return RadioResponse_v1_5::setSystemSelectionChannelsResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::enableModemResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::getModemStackStatusResponse(const RadioResponseInfo& info, + const bool enabled) { + rspInfo = info; + isModemEnabled = enabled; + parent_v1_5.notify(info.serial); + return Void(); +} + +/* 1.4 Apis */ +Return RadioResponse_v1_5::emergencyDialResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::startNetworkScanResponse_1_4(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::getDataRegistrationStateResponse_1_4( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_4::DataRegStateResult& dataRegResponse) { + rspInfo = info; + dataRegResp = dataRegResponse; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::getCellInfoListResponse_1_4( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_4::CellInfo>& /*cellInfo*/) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::getIccCardStatusResponse_1_4( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_4::CardStatus& card_status) { + rspInfo = info; + cardStatus = card_status; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::getPreferredNetworkTypeBitmapResponse( + const RadioResponseInfo& info, const ::android::hardware::hidl_bitfield< + ::android::hardware::radio::V1_4::RadioAccessFamily> + networkTypeBitmap) { + rspInfo = info; + networkTypeBitmapResponse = networkTypeBitmap; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::setPreferredNetworkTypeBitmapResponse( + const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::getDataCallListResponse_1_4( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::SetupDataCallResult>& + /*dcResponse*/) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::setupDataCallResponse_1_4( + const RadioResponseInfo& info, + const android::hardware::radio::V1_4::SetupDataCallResult& /*dcResponse*/) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::setAllowedCarriersResponse_1_4(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::getAllowedCarriersResponse_1_4( + const RadioResponseInfo& info, const CarrierRestrictionsWithPriority& carriers, + SimLockMultiSimPolicy multiSimPolicy) { + rspInfo = info; + carrierRestrictionsResp = carriers; + multiSimPolicyResp = multiSimPolicy; + parent_v1_5.notify(info.serial); + return Void(); +} From d306cccd0bcf6dd5bc57c664af9f59b2692a7f05 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 11 Oct 2019 17:50:52 -0700 Subject: [PATCH 0205/1022] audio: Extract utility functions Move common code out of the test source. Test: atest VtsHalAudioV5_0TargetTest Change-Id: I86cf399029a0a5f3f08c7e82713ae62df03dee3f --- .../test/utility/include/utility/AssertOk.h | 21 ++++++++++ .../vts/functional/AudioPrimaryHidlHalTest.h | 40 ++----------------- 2 files changed, 25 insertions(+), 36 deletions(-) diff --git a/audio/common/all-versions/test/utility/include/utility/AssertOk.h b/audio/common/all-versions/test/utility/include/utility/AssertOk.h index 5ac2fdc936..03a6305b10 100644 --- a/audio/common/all-versions/test/utility/include/utility/AssertOk.h +++ b/audio/common/all-versions/test/utility/include/utility/AssertOk.h @@ -114,6 +114,27 @@ inline ::testing::AssertionResult assertOk(const char* expr, const Return +static R extract(const Return& ret) { + if (!ret.isOk()) { + EXPECT_IS_OK(ret); + return R{}; + } + return ret; +} + +template +static void expectValueOrFailure(Result res, Value expectedValue, Value actualValue, + Result expectedFailure) { + if (res == Result::OK) { + ASSERT_EQ(expectedValue, actualValue); + } else { + ASSERT_EQ(expectedFailure, res) << "Unexpected result " << toString(res); + } +} + } // namespace utility } // namespace test } // namespace common diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h index 0778720bb0..6c51c1ba7f 100644 --- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -408,11 +408,7 @@ TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) { class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest { protected: - bool areAudioPatchesSupported() { - auto result = device->supportsAudioPatches(); - EXPECT_IS_OK(result); - return result; - } + bool areAudioPatchesSupported() { return extract(device->supportsAudioPatches()); } }; TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) { @@ -829,17 +825,6 @@ INSTANTIATE_TEST_CASE_P( ////////////////////////////// IStream getters /////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -/** Unpack the provided result. - * If the result is not OK, register a failure and return an undefined value. */ -template -static R extract(Return ret) { - if (!ret.isOk()) { - EXPECT_IS_OK(ret); - return R{}; - } - return ret; -} - /* Could not find a way to write a test for two parametrized class fixure * thus use this macro do duplicate tests for Input and Output stream */ #define TEST_IO_STREAM(test_name, documentation, code) \ @@ -1189,11 +1174,7 @@ TEST_P(OutputStreamTest, PrepareForWritingCheckOverflow) { struct Capability { Capability(IStreamOut* stream) { EXPECT_OK(stream->supportsPauseAndResume(returnIn(pause, resume))); - auto ret = stream->supportsDrain(); - EXPECT_IS_OK(ret); - if (ret.isOk()) { - drain = ret; - } + drain = extract(stream->supportsDrain()); } bool pause = false; bool resume = false; @@ -1205,19 +1186,6 @@ TEST_P(OutputStreamTest, SupportsPauseAndResumeAndDrain) { Capability(stream.get()); } -template -static void checkInvalidStateOr0(Result res, Value value) { - switch (res) { - case Result::INVALID_STATE: - break; - case Result::OK: - ASSERT_EQ(0U, value); - break; - default: - FAIL() << "Unexpected result " << toString(res); - } -} - TEST_P(OutputStreamTest, GetRenderPosition) { doc::test("A new stream render position should be 0 or INVALID_STATE"); uint32_t dspFrames; @@ -1226,7 +1194,7 @@ TEST_P(OutputStreamTest, GetRenderPosition) { doc::partialTest("getRenderPosition is not supported"); return; } - checkInvalidStateOr0(res, dspFrames); + expectValueOrFailure(res, 0U, dspFrames, Result::INVALID_STATE); } TEST_P(OutputStreamTest, GetNextWriteTimestamp) { @@ -1237,7 +1205,7 @@ TEST_P(OutputStreamTest, GetNextWriteTimestamp) { doc::partialTest("getNextWriteTimestamp is not supported"); return; } - checkInvalidStateOr0(res, timestampUs); + expectValueOrFailure(res, uint64_t{0}, timestampUs, Result::INVALID_STATE); } /** Stub implementation of out stream callback. */ From bc1d5aa08e997e80acf3f107f774acfea9106e59 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Wed, 23 Oct 2019 16:46:54 -0700 Subject: [PATCH 0206/1022] audio: Parametrize effect VTS tests for V6.0 Parametrize tests to accept IEffectsFactory instance name. Discover the instances in the test. Bug: 141847510 Bug: 141989952 Test: atest VtsHalAudioEffectV5_0TargetTest atest VtsHalAudioEffectV6_0TargetTest Change-Id: Iaf19109fc77a93b211cc3da85c21c0584d4f2b88 --- .../VtsHalAudioEffectTargetTest.cpp | 121 ++++++++++++------ 1 file changed, 83 insertions(+), 38 deletions(-) diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp index c4c7f7ccc4..3c712b5ca3 100644 --- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp +++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp @@ -28,8 +28,14 @@ #include +#if MAJOR_VERSION <= 5 #include #include +#elif MAJOR_VERSION >= 6 +#include +#include +#include +#endif using ::android::sp; using ::android::hardware::hidl_handle; @@ -49,6 +55,11 @@ using namespace ::android::hardware::audio::effect::CPP_VERSION; #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) #endif +#if MAJOR_VERSION <= 5 +// For HAL versions 2..5 Vts Environment and Test base classes are used. +// The tests are non-parametrized. +#define EFFECT_TEST TEST_F + // Test environment for Audio Effects Factory HIDL HAL. class AudioEffectsFactoryHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: @@ -71,6 +82,18 @@ class AudioEffectsFactoryHidlTest : public ::testing::VtsHalHidlTargetTestBase { ASSERT_NE(effectsFactory, nullptr); } +#elif MAJOR_VERSION >= 6 +// For HAL version 6 and above, standard GTest Environment and Test base classes are used. +// The tests are parametrized by the IEffectsFactory instance name. +#define EFFECT_TEST TEST_P + +class AudioEffectsFactoryHidlTest : public ::testing::TestWithParam { + public: + void SetUp() override { + effectsFactory = IEffectsFactory::getService(GetParam()); + ASSERT_NE(effectsFactory, nullptr); + } +#endif // The rest of the AudioEffectsFactoryHidlTest class definition is the same. void TearDown() override { effectsFactory.clear(); } protected: @@ -81,7 +104,7 @@ class AudioEffectsFactoryHidlTest : public ::testing::VtsHalHidlTargetTestBase { sp effectsFactory; }; -TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) { +EFFECT_TEST(AudioEffectsFactoryHidlTest, EnumerateEffects) { description("Verify that EnumerateEffects returns at least one effect"); Result retval = Result::NOT_INITIALIZED; size_t effectCount = 0; @@ -95,7 +118,7 @@ TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) { EXPECT_GT(effectCount, 0u); } -TEST_F(AudioEffectsFactoryHidlTest, CreateEffect) { +EFFECT_TEST(AudioEffectsFactoryHidlTest, CreateEffect) { description("Verify that an effect can be created via CreateEffect"); bool gotEffect = false; Uuid effectUuid; @@ -123,7 +146,7 @@ TEST_F(AudioEffectsFactoryHidlTest, CreateEffect) { EXPECT_NE(nullptr, effect.get()); } -TEST_F(AudioEffectsFactoryHidlTest, GetDescriptor) { +EFFECT_TEST(AudioEffectsFactoryHidlTest, GetDescriptor) { description( "Verify that effects factory can provide an effect descriptor via " "GetDescriptor"); @@ -146,7 +169,7 @@ TEST_F(AudioEffectsFactoryHidlTest, GetDescriptor) { EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectsFactoryHidlTest, DebugDumpInvalidArgument) { +EFFECT_TEST(AudioEffectsFactoryHidlTest, DebugDumpInvalidArgument) { description("Verify that debugDump doesn't crash on invalid arguments"); #if MAJOR_VERSION == 2 Return ret = effectsFactory->debugDump(hidl_handle()); @@ -168,10 +191,17 @@ static const Uuid LOUDNESS_ENHANCER_EFFECT_TYPE = { std::array{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}}; // The main test class for Audio Effect HIDL HAL. +#if MAJOR_VERSION <= 5 class AudioEffectHidlTest : public ::testing::VtsHalHidlTargetTestBase { public: void SetUp() override { effectsFactory = ::testing::VtsHalHidlTargetTestBase::getService(); +#elif MAJOR_VERSION >= 6 +class AudioEffectHidlTest : public ::testing::TestWithParam { + public: + void SetUp() override { + effectsFactory = IEffectsFactory::getService(GetParam()); +#endif ASSERT_NE(nullptr, effectsFactory.get()); findAndCreateEffect(getEffectType()); @@ -250,14 +280,14 @@ void AudioEffectHidlTest::getChannelCount(uint32_t* channelCount) { static_cast(currentConfig.outputCfg.channels)); } -TEST_F(AudioEffectHidlTest, Close) { +EFFECT_TEST(AudioEffectHidlTest, Close) { description("Verify that an effect can be closed"); Return ret = effect->close(); EXPECT_TRUE(ret.isOk()); EXPECT_EQ(Result::OK, ret); } -TEST_F(AudioEffectHidlTest, GetDescriptor) { +EFFECT_TEST(AudioEffectHidlTest, GetDescriptor) { description("Verify that an effect can return its own descriptor via GetDescriptor"); Result retval = Result::NOT_INITIALIZED; Uuid actualType; @@ -272,7 +302,7 @@ TEST_F(AudioEffectHidlTest, GetDescriptor) { EXPECT_EQ(getEffectType(), actualType); } -TEST_F(AudioEffectHidlTest, GetSetConfig) { +EFFECT_TEST(AudioEffectHidlTest, GetSetConfig) { description( "Verify that it is possible to manipulate effect config via Get / " "SetConfig"); @@ -291,26 +321,26 @@ TEST_F(AudioEffectHidlTest, GetSetConfig) { EXPECT_EQ(Result::OK, ret2); } -TEST_F(AudioEffectHidlTest, GetConfigReverse) { +EFFECT_TEST(AudioEffectHidlTest, GetConfigReverse) { description("Verify that GetConfigReverse does not crash"); Return ret = effect->getConfigReverse([&](Result, const EffectConfig&) {}); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) { +EFFECT_TEST(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) { description("Verify that GetSupportedAuxChannelsConfigs does not crash"); Return ret = effect->getSupportedAuxChannelsConfigs( 0, [&](Result, const hidl_vec&) {}); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, GetAuxChannelsConfig) { +EFFECT_TEST(AudioEffectHidlTest, GetAuxChannelsConfig) { description("Verify that GetAuxChannelsConfig does not crash"); Return ret = effect->getAuxChannelsConfig([&](Result, const EffectAuxChannelsConfig&) {}); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, SetAuxChannelsConfig) { +EFFECT_TEST(AudioEffectHidlTest, SetAuxChannelsConfig) { description("Verify that SetAuxChannelsConfig does not crash"); Return ret = effect->setAuxChannelsConfig(EffectAuxChannelsConfig()); EXPECT_TRUE(ret.isOk()); @@ -349,7 +379,7 @@ inline bool operator==(const EffectConfig& lhs, const EffectConfig& rhs) { } // namespace hardware } // namespace android -TEST_F(AudioEffectHidlTest, Reset) { +EFFECT_TEST(AudioEffectHidlTest, Reset) { description("Verify that Reset preserves effect configuration"); Result retval = Result::NOT_INITIALIZED; EffectConfig originalConfig; @@ -374,7 +404,7 @@ TEST_F(AudioEffectHidlTest, Reset) { EXPECT_EQ(originalConfig, configAfterReset); } -TEST_F(AudioEffectHidlTest, DisableEnableDisable) { +EFFECT_TEST(AudioEffectHidlTest, DisableEnableDisable) { description("Verify Disable -> Enable -> Disable sequence for an effect"); Return ret = effect->disable(); EXPECT_TRUE(ret.isOk()); @@ -387,14 +417,14 @@ TEST_F(AudioEffectHidlTest, DisableEnableDisable) { EXPECT_EQ(Result::OK, ret); } -TEST_F(AudioEffectHidlTest, SetDevice) { +EFFECT_TEST(AudioEffectHidlTest, SetDevice) { description("Verify that SetDevice works for an output chain effect"); Return ret = effect->setDevice(mkEnumBitfield(AudioDevice::OUT_SPEAKER)); EXPECT_TRUE(ret.isOk()); EXPECT_EQ(Result::OK, ret); } -TEST_F(AudioEffectHidlTest, SetAndGetVolume) { +EFFECT_TEST(AudioEffectHidlTest, SetAndGetVolume) { description("Verify that SetAndGetVolume method works for an effect"); uint32_t channelCount; getChannelCount(&channelCount); @@ -410,7 +440,7 @@ TEST_F(AudioEffectHidlTest, SetAndGetVolume) { EXPECT_EQ(Result::OK, retval); } -TEST_F(AudioEffectHidlTest, VolumeChangeNotification) { +EFFECT_TEST(AudioEffectHidlTest, VolumeChangeNotification) { description("Verify that effect accepts VolumeChangeNotification"); uint32_t channelCount; getChannelCount(&channelCount); @@ -424,32 +454,32 @@ TEST_F(AudioEffectHidlTest, VolumeChangeNotification) { EXPECT_EQ(Result::OK, ret); } -TEST_F(AudioEffectHidlTest, SetAudioMode) { +EFFECT_TEST(AudioEffectHidlTest, SetAudioMode) { description("Verify that SetAudioMode works for an effect"); Return ret = effect->setAudioMode(AudioMode::NORMAL); EXPECT_TRUE(ret.isOk()); EXPECT_EQ(Result::OK, ret); } -TEST_F(AudioEffectHidlTest, SetConfigReverse) { +EFFECT_TEST(AudioEffectHidlTest, SetConfigReverse) { description("Verify that SetConfigReverse does not crash"); Return ret = effect->setConfigReverse(EffectConfig(), nullptr, nullptr); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, SetInputDevice) { +EFFECT_TEST(AudioEffectHidlTest, SetInputDevice) { description("Verify that SetInputDevice does not crash"); Return ret = effect->setInputDevice(mkEnumBitfield(AudioDevice::IN_BUILTIN_MIC)); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, SetAudioSource) { +EFFECT_TEST(AudioEffectHidlTest, SetAudioSource) { description("Verify that SetAudioSource does not crash"); Return ret = effect->setAudioSource(AudioSource::MIC); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, Offload) { +EFFECT_TEST(AudioEffectHidlTest, Offload) { description("Verify that calling Offload method does not crash"); EffectOffloadParameter offloadParam; offloadParam.isOffload = false; @@ -458,7 +488,7 @@ TEST_F(AudioEffectHidlTest, Offload) { EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, PrepareForProcessing) { +EFFECT_TEST(AudioEffectHidlTest, PrepareForProcessing) { description("Verify that PrepareForProcessing method works for an effect"); Result retval = Result::NOT_INITIALIZED; Return ret = effect->prepareForProcessing( @@ -467,7 +497,7 @@ TEST_F(AudioEffectHidlTest, PrepareForProcessing) { EXPECT_EQ(Result::OK, retval); } -TEST_F(AudioEffectHidlTest, SetProcessBuffers) { +EFFECT_TEST(AudioEffectHidlTest, SetProcessBuffers) { description("Verify that SetProcessBuffers works for an effect"); sp ashmem = IAllocator::getService("ashmem"); ASSERT_NE(nullptr, ashmem.get()); @@ -486,41 +516,41 @@ TEST_F(AudioEffectHidlTest, SetProcessBuffers) { EXPECT_EQ(Result::OK, ret2); } -TEST_F(AudioEffectHidlTest, Command) { +EFFECT_TEST(AudioEffectHidlTest, Command) { description("Verify that Command does not crash"); Return ret = effect->command(0, hidl_vec(), 0, [&](int32_t, const hidl_vec&) {}); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, SetParameter) { +EFFECT_TEST(AudioEffectHidlTest, SetParameter) { description("Verify that SetParameter does not crash"); Return ret = effect->setParameter(hidl_vec(), hidl_vec()); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, GetParameter) { +EFFECT_TEST(AudioEffectHidlTest, GetParameter) { description("Verify that GetParameter does not crash"); Return ret = effect->getParameter(hidl_vec(), 0, [&](Result, const hidl_vec&) {}); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, GetSupportedConfigsForFeature) { +EFFECT_TEST(AudioEffectHidlTest, GetSupportedConfigsForFeature) { description("Verify that GetSupportedConfigsForFeature does not crash"); Return ret = effect->getSupportedConfigsForFeature( 0, 0, 0, [&](Result, uint32_t, const hidl_vec&) {}); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, GetCurrentConfigForFeature) { +EFFECT_TEST(AudioEffectHidlTest, GetCurrentConfigForFeature) { description("Verify that GetCurrentConfigForFeature does not crash"); Return ret = effect->getCurrentConfigForFeature(0, 0, [&](Result, const hidl_vec&) {}); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, SetCurrentConfigForFeature) { +EFFECT_TEST(AudioEffectHidlTest, SetCurrentConfigForFeature) { description("Verify that SetCurrentConfigForFeature does not crash"); Return ret = effect->setCurrentConfigForFeature(0, hidl_vec()); EXPECT_TRUE(ret.isOk()); @@ -606,21 +636,21 @@ void EqualizerAudioEffectHidlTest::getPresetCount(size_t* count) { ASSERT_EQ(Result::OK, retval); } -TEST_F(EqualizerAudioEffectHidlTest, GetNumBands) { +EFFECT_TEST(EqualizerAudioEffectHidlTest, GetNumBands) { description("Verify that Equalizer effect reports at least one band"); uint16_t numBands = 0; getNumBands(&numBands); EXPECT_GT(numBands, 0); } -TEST_F(EqualizerAudioEffectHidlTest, GetLevelRange) { +EFFECT_TEST(EqualizerAudioEffectHidlTest, GetLevelRange) { description("Verify that Equalizer effect reports adequate band level range"); int16_t minLevel = 0x7fff, maxLevel = 0; getLevelRange(&minLevel, &maxLevel); EXPECT_GT(maxLevel, minLevel); } -TEST_F(EqualizerAudioEffectHidlTest, GetSetBandLevel) { +EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetBandLevel) { description("Verify that manipulating band levels works for Equalizer effect"); uint16_t numBands = 0; getNumBands(&numBands); @@ -649,7 +679,7 @@ TEST_F(EqualizerAudioEffectHidlTest, GetSetBandLevel) { } } -TEST_F(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) { +EFFECT_TEST(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) { description("Verify that Equalizer effect reports adequate band frequency range"); uint16_t numBands = 0; getNumBands(&numBands); @@ -664,7 +694,7 @@ TEST_F(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) { } } -TEST_F(EqualizerAudioEffectHidlTest, GetBandForFrequency) { +EFFECT_TEST(EqualizerAudioEffectHidlTest, GetBandForFrequency) { description("Verify that Equalizer effect supports GetBandForFrequency correctly"); uint16_t numBands = 0; getNumBands(&numBands); @@ -693,14 +723,14 @@ TEST_F(EqualizerAudioEffectHidlTest, GetBandForFrequency) { } } -TEST_F(EqualizerAudioEffectHidlTest, GetPresetNames) { +EFFECT_TEST(EqualizerAudioEffectHidlTest, GetPresetNames) { description("Verify that Equalizer effect reports at least one preset"); size_t presetCount; getPresetCount(&presetCount); EXPECT_GT(presetCount, 0u); } -TEST_F(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) { +EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) { description("Verify that manipulating the current preset for Equalizer effect"); size_t presetCount; getPresetCount(&presetCount); @@ -723,7 +753,7 @@ TEST_F(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) { } } -TEST_F(EqualizerAudioEffectHidlTest, GetSetAllProperties) { +EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetAllProperties) { description( "Verify that setting band levels and presets works via Get / " "SetAllProperties for Equalizer effect"); @@ -787,7 +817,7 @@ class LoudnessEnhancerAudioEffectHidlTest : public AudioEffectHidlTest { sp enhancer; }; -TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) { +EFFECT_TEST(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) { description( "Verify that manipulating the target gain works for Loudness Enhancer " "effect"); @@ -808,6 +838,7 @@ TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) { EXPECT_EQ(gain, actualGain); } +#if MAJOR_VERSION <= 5 int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(AudioEffectsFactoryHidlEnvironment::Instance()); ::testing::InitGoogleTest(&argc, argv); @@ -816,3 +847,17 @@ int main(int argc, char** argv) { LOG(INFO) << "Test result = " << status; return status; } +#elif MAJOR_VERSION >= 6 +INSTANTIATE_TEST_SUITE_P( + EffectsFactory, AudioEffectsFactoryHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)), + android::hardware::PrintInstanceNameToString); +INSTANTIATE_TEST_SUITE_P( + Equalizer, EqualizerAudioEffectHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)), + android::hardware::PrintInstanceNameToString); +INSTANTIATE_TEST_SUITE_P( + LoudnessEnhancer, LoudnessEnhancerAudioEffectHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)), + android::hardware::PrintInstanceNameToString); +#endif From 9bed3dc4fa3a06ca0c05843959f2e8133277ad50 Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Fri, 11 Oct 2019 17:30:15 -0700 Subject: [PATCH 0207/1022] Update cas@1.1 hal to cas@1.2. Test: Manual bug: 141783130 Change-Id: I0c3e9041a2057ce721a608cf3a9f0a9bb15a2305 --- CleanSpec.mk | 3 + cas/1.2/Android.bp | 21 + cas/1.2/ICas.hal | 43 ++ cas/1.2/ICasListener.hal | 37 ++ cas/1.2/IMediaCasService.hal | 35 + cas/1.2/default/Android.bp | 49 ++ cas/1.2/default/CasImpl.cpp | 271 ++++++++ cas/1.2/default/CasImpl.h | 111 ++++ cas/1.2/default/DescramblerImpl.cpp | 195 ++++++ cas/1.2/default/DescramblerImpl.h | 67 ++ cas/1.2/default/FactoryLoader.h | 217 ++++++ cas/1.2/default/MediaCasService.cpp | 153 +++++ cas/1.2/default/MediaCasService.h | 67 ++ cas/1.2/default/SharedLibrary.cpp | 65 ++ cas/1.2/default/SharedLibrary.h | 50 ++ cas/1.2/default/TypeConvert.cpp | 121 ++++ cas/1.2/default/TypeConvert.h | 46 ++ .../android.hardware.cas@1.2-service-lazy.rc | 11 + .../android.hardware.cas@1.2-service-lazy.xml | 11 + .../android.hardware.cas@1.2-service.rc | 6 + .../android.hardware.cas@1.2-service.xml | 11 + cas/1.2/default/service.cpp | 58 ++ cas/1.2/types.hal | 149 +++++ cas/1.2/vts/functional/Android.bp | 36 + cas/1.2/vts/functional/OWNERS | 3 + .../functional/VtsHalCasV1_2TargetTest.cpp | 619 ++++++++++++++++++ 26 files changed, 2455 insertions(+) create mode 100644 cas/1.2/Android.bp create mode 100644 cas/1.2/ICas.hal create mode 100644 cas/1.2/ICasListener.hal create mode 100644 cas/1.2/IMediaCasService.hal create mode 100644 cas/1.2/default/Android.bp create mode 100644 cas/1.2/default/CasImpl.cpp create mode 100644 cas/1.2/default/CasImpl.h create mode 100644 cas/1.2/default/DescramblerImpl.cpp create mode 100644 cas/1.2/default/DescramblerImpl.h create mode 100644 cas/1.2/default/FactoryLoader.h create mode 100644 cas/1.2/default/MediaCasService.cpp create mode 100644 cas/1.2/default/MediaCasService.h create mode 100644 cas/1.2/default/SharedLibrary.cpp create mode 100644 cas/1.2/default/SharedLibrary.h create mode 100644 cas/1.2/default/TypeConvert.cpp create mode 100644 cas/1.2/default/TypeConvert.h create mode 100644 cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc create mode 100644 cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml create mode 100644 cas/1.2/default/android.hardware.cas@1.2-service.rc create mode 100644 cas/1.2/default/android.hardware.cas@1.2-service.xml create mode 100644 cas/1.2/default/service.cpp create mode 100644 cas/1.2/types.hal create mode 100644 cas/1.2/vts/functional/Android.bp create mode 100644 cas/1.2/vts/functional/OWNERS create mode 100644 cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp diff --git a/CleanSpec.mk b/CleanSpec.mk index da2635e0d2..76594fb448 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -81,3 +81,6 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/android.hardware.confi $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/vndk-Q/android.hardware.configstore@1.2.so) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/android.hardware.configstore@1.2.so) $(call add-clean-step, rm -f $(PRODUCT_OUT)/etc/init/android.hardware.audio@2.0-service.rc $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.audio@2.0-service) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.cas@1.1*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.cas@1.1*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/vintf/manifest/android.hardware.cas@1.1*) diff --git a/cas/1.2/Android.bp b/cas/1.2/Android.bp new file mode 100644 index 0000000000..af98b2e44e --- /dev/null +++ b/cas/1.2/Android.bp @@ -0,0 +1,21 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.cas@1.2", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "ICas.hal", + "ICasListener.hal", + "IMediaCasService.hal", + "types.hal", + ], + interfaces: [ + "android.hardware.cas@1.0", + "android.hardware.cas@1.1", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/cas/1.2/ICas.hal b/cas/1.2/ICas.hal new file mode 100644 index 0000000000..23edc50f59 --- /dev/null +++ b/cas/1.2/ICas.hal @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package android.hardware.cas@1.2; + +import @1.0::HidlCasSessionId; +import @1.1::ICas; +import ScramblingMode; +import SessionIntent; +import Status; + +/** + * ICas is the API to control the cas system and is accessible from both + * Java and native level. It is used to manage sessions, provision/refresh + * the cas system, and process the EMM/ECM messages. It also allows bi-directional, + * scheme-specific communications between the client and the cas system. + */ +interface ICas extends @1.1::ICas { + /** + * Open a session to descramble one or more streams by specifying intention + * and scrambling mode. + * + * @param intent the intention of the session to be opened. + * @param mode the scrambling mode the session will use. + * @return status the status of the call. + * @return sessionId the id of the newly opened session. + */ + openSession_1_2(SessionIntent intent, ScramblingMode mode) + generates (Status status, HidlCasSessionId sessionId); +}; diff --git a/cas/1.2/ICasListener.hal b/cas/1.2/ICasListener.hal new file mode 100644 index 0000000000..9a8be203a2 --- /dev/null +++ b/cas/1.2/ICasListener.hal @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package android.hardware.cas@1.2; + +import @1.1::ICasListener; +import StatusEvent; + +interface ICasListener extends @1.1::ICasListener { + /** + * Notify the listener that the status of CAS system has changed. + * + * @param event the event type of status change. + * @param number value for status event. + * For PLUGIN_PHYSICAL_MODULE_CHANGED event: + * the positive number presents how many plugins are inserted; + * the negative number presents how many plugins are removed. + * Client must enumerate plugins after receive the event. + * For PLUGIN_SESSION_NUMBER_CHANGED event: + * the number presents how many sessions are supported + * in the plugin. + */ + onStatusUpdate(StatusEvent event, int32_t number); +}; diff --git a/cas/1.2/IMediaCasService.hal b/cas/1.2/IMediaCasService.hal new file mode 100644 index 0000000000..a0bec7e5b4 --- /dev/null +++ b/cas/1.2/IMediaCasService.hal @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package android.hardware.cas@1.2; + +import ICas; +import ICasListener; +import @1.1::IMediaCasService; + +/** + * IMediaCasService is the main entry point for interacting with a vendor's + * cas HAL to create cas and descrambler plugin instances. A cas plugin instance + * opens cas sessions which are used to obtain keys for a descrambler session, + * which can in turn be used to descramble protected video content. + * + * The 1.2 must always create 1.2 ICas interfaces, which are + * returned via the 1.1 createPluginExt method. + * + * To use 1.2 features the caller must cast the returned interface to a + * 1.2 HAL, using V1_2::ICas::castFrom(). + */ +interface IMediaCasService extends @1.1::IMediaCasService {}; diff --git a/cas/1.2/default/Android.bp b/cas/1.2/default/Android.bp new file mode 100644 index 0000000000..9e5314874f --- /dev/null +++ b/cas/1.2/default/Android.bp @@ -0,0 +1,49 @@ +cc_defaults { + name: "cas_service_defaults@1.2", + defaults: ["hidl_defaults"], + vendor: true, + relative_install_path: "hw", + srcs: [ + "CasImpl.cpp", + "DescramblerImpl.cpp", + "MediaCasService.cpp", + "service.cpp", + "SharedLibrary.cpp", + "TypeConvert.cpp", + ], + + compile_multilib: "32", + + shared_libs: [ + "android.hardware.cas@1.0", + "android.hardware.cas@1.1", + "android.hardware.cas@1.2", + "android.hardware.cas.native@1.0", + "android.hidl.memory@1.0", + "libbinder", + "libhidlbase", + "libhidlmemory", + "liblog", + "libutils", + ], + header_libs: [ + "libstagefright_foundation_headers", + "media_plugin_headers", + ], +} + +cc_binary { + name: "android.hardware.cas@1.2-service", + vintf_fragments: ["android.hardware.cas@1.2-service.xml"], + defaults: ["cas_service_defaults@1.2"], + init_rc: ["android.hardware.cas@1.2-service.rc"], +} + +cc_binary { + name: "android.hardware.cas@1.2-service-lazy", + vintf_fragments: ["android.hardware.cas@1.2-service-lazy.xml"], + overrides: ["android.hardware.cas@1.2-service"], + defaults: ["cas_service_defaults@1.2"], + init_rc: ["android.hardware.cas@1.2-service-lazy.rc"], + cflags: ["-DLAZY_SERVICE"], +} diff --git a/cas/1.2/default/CasImpl.cpp b/cas/1.2/default/CasImpl.cpp new file mode 100644 index 0000000000..46dd25195e --- /dev/null +++ b/cas/1.2/default/CasImpl.cpp @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + icensed 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_NDEBUG 0 +#define LOG_TAG "android.hardware.cas@1.1-CasImpl" + +#include +#include +#include +#include + +#include "CasImpl.h" +#include "SharedLibrary.h" +#include "TypeConvert.h" + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +CasImpl::CasImpl(const sp& listener) : mListener(listener) { + ALOGV("CTOR"); +} + +CasImpl::~CasImpl() { + ALOGV("DTOR"); + release(); +} + +// static +void CasImpl::OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size) { + if (appData == NULL) { + ALOGE("Invalid appData!"); + return; + } + CasImpl* casImpl = static_cast(appData); + casImpl->onEvent(event, arg, data, size); +} + +// static +void CasImpl::CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size, + const CasSessionId* sessionId) { + if (appData == NULL) { + ALOGE("Invalid appData!"); + return; + } + CasImpl* casImpl = static_cast(appData); + casImpl->onEvent(sessionId, event, arg, data, size); +} + +// static +void CasImpl::StatusUpdate(void* appData, int32_t event, int32_t arg) { + if (appData == NULL) { + ALOGE("Invalid appData!"); + return; + } + CasImpl* casImpl = static_cast(appData); + casImpl->onStatusUpdate(event, arg); +} + +void CasImpl::init(const sp& library, CasPlugin* plugin) { + mLibrary = library; + std::shared_ptr holder(plugin); + std::atomic_store(&mPluginHolder, holder); +} + +void CasImpl::onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size) { + if (mListener == NULL) { + return; + } + + HidlCasData eventData; + if (data != NULL) { + eventData.setToExternal(data, size); + } + + mListener->onEvent(event, arg, eventData); +} + +void CasImpl::onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data, + size_t size) { + if (mListener == NULL) { + return; + } + + HidlCasData eventData; + if (data != NULL) { + eventData.setToExternal(data, size); + } + + if (sessionId != NULL) { + mListener->onSessionEvent(*sessionId, event, arg, eventData); + } else { + mListener->onEvent(event, arg, eventData); + } +} + +void CasImpl::onStatusUpdate(int32_t event, int32_t arg) { + if (mListener == NULL) { + return; + } + sp listenerV1_2 = V1_2::ICasListener::castFrom(mListener); + + if (listenerV1_2 != NULL) { + listenerV1_2->onStatusUpdate(static_cast(event), arg); + } +} + +Return CasImpl::setPluginStatusUpdateCallback() { + ALOGV("%s", __FUNCTION__); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + return toStatus(holder->setStatusCallback(&CasImpl::StatusUpdate)); +} + +Return CasImpl::setPrivateData(const HidlCasData& pvtData) { + ALOGV("%s", __FUNCTION__); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + return toStatus(holder->setPrivateData(pvtData)); +} + +Return CasImpl::openSession(openSession_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + CasSessionId sessionId; + + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + status_t err = INVALID_OPERATION; + if (holder.get() != nullptr) { + err = holder->openSession(&sessionId); + holder.reset(); + } + + _hidl_cb(toStatus(err), sessionId); + + return Void(); +} + +Return CasImpl::openSession_1_2(const SessionIntent intent, const ScramblingMode mode, + openSession_1_2_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + CasSessionId sessionId; + + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + status_t err = INVALID_OPERATION; + if (holder.get() != nullptr) { + err = holder->openSession(static_cast(intent), static_cast(mode), + &sessionId); + holder.reset(); + } + + _hidl_cb(toStatus_1_2(err), sessionId); + + return Void(); +} + +Return CasImpl::setSessionPrivateData(const HidlCasSessionId& sessionId, + const HidlCasData& pvtData) { + ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string()); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + return toStatus(holder->setSessionPrivateData(sessionId, pvtData)); +} + +Return CasImpl::closeSession(const HidlCasSessionId& sessionId) { + ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string()); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + return toStatus(holder->closeSession(sessionId)); +} + +Return CasImpl::processEcm(const HidlCasSessionId& sessionId, const HidlCasData& ecm) { + ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string()); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->processEcm(sessionId, ecm)); +} + +Return CasImpl::processEmm(const HidlCasData& emm) { + ALOGV("%s", __FUNCTION__); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->processEmm(emm)); +} + +Return CasImpl::sendEvent(int32_t event, int32_t arg, const HidlCasData& eventData) { + ALOGV("%s", __FUNCTION__); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + status_t err = holder->sendEvent(event, arg, eventData); + return toStatus(err); +} + +Return CasImpl::sendSessionEvent(const HidlCasSessionId& sessionId, int32_t event, + int32_t arg, const HidlCasData& eventData) { + ALOGV("%s", __FUNCTION__); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + status_t err = holder->sendSessionEvent(sessionId, event, arg, eventData); + return toStatus(err); +} + +Return CasImpl::provision(const hidl_string& provisionString) { + ALOGV("%s: provisionString=%s", __FUNCTION__, provisionString.c_str()); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->provision(String8(provisionString.c_str()))); +} + +Return CasImpl::refreshEntitlements(int32_t refreshType, const HidlCasData& refreshData) { + ALOGV("%s", __FUNCTION__); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + status_t err = holder->refreshEntitlements(refreshType, refreshData); + return toStatus(err); +} + +Return CasImpl::release() { + ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get()); + + std::shared_ptr holder(nullptr); + std::atomic_store(&mPluginHolder, holder); + + return Status::OK; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.2/default/CasImpl.h b/cas/1.2/default/CasImpl.h new file mode 100644 index 0000000000..4325c20313 --- /dev/null +++ b/cas/1.2/default/CasImpl.h @@ -0,0 +1,111 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_ +#define ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_ + +#include +#include +#include + +namespace android { +struct CasPlugin; + +namespace hardware { +namespace cas { +namespace V1_1 { +struct ICasListener; +namespace implementation { + +using ::android::hardware::cas::V1_0::HidlCasData; +using ::android::hardware::cas::V1_0::HidlCasSessionId; +using ::android::hardware::cas::V1_0::Status; +using ::android::hardware::cas::V1_2::ScramblingMode; +using ::android::hardware::cas::V1_2::SessionIntent; +using ::android::hardware::cas::V1_2::StatusEvent; + +class SharedLibrary; + +class CasImpl : public V1_2::ICas { + public: + CasImpl(const sp& listener); + virtual ~CasImpl(); + + static void OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size); + + static void CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size, + const CasSessionId* sessionId); + + static void StatusUpdate(void* appData, int32_t event, int32_t arg); + + void init(const sp& library, CasPlugin* plugin); + void onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size); + + void onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data, + size_t size); + + void onStatusUpdate(int32_t event, int32_t arg); + + // ICas inherits + + Return setPluginStatusUpdateCallback(); + + virtual Return setPrivateData(const HidlCasData& pvtData) override; + + virtual Return openSession(openSession_cb _hidl_cb) override; + + virtual Return openSession_1_2(const SessionIntent intent, const ScramblingMode mode, + openSession_1_2_cb _hidl_cb) override; + + virtual Return closeSession(const HidlCasSessionId& sessionId) override; + + virtual Return setSessionPrivateData(const HidlCasSessionId& sessionId, + const HidlCasData& pvtData) override; + + virtual Return processEcm(const HidlCasSessionId& sessionId, + const HidlCasData& ecm) override; + + virtual Return processEmm(const HidlCasData& emm) override; + + virtual Return sendEvent(int32_t event, int32_t arg, + const HidlCasData& eventData) override; + + virtual Return sendSessionEvent(const HidlCasSessionId& sessionId, int32_t event, + int32_t arg, const HidlCasData& eventData) override; + + virtual Return provision(const hidl_string& provisionString) override; + + virtual Return refreshEntitlements(int32_t refreshType, + const HidlCasData& refreshData) override; + + virtual Return release() override; + + private: + struct PluginHolder; + sp mLibrary; + std::shared_ptr mPluginHolder; + sp mListener; + + DISALLOW_EVIL_CONSTRUCTORS(CasImpl); +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_ diff --git a/cas/1.2/default/DescramblerImpl.cpp b/cas/1.2/default/DescramblerImpl.cpp new file mode 100644 index 0000000000..36dc1a51d0 --- /dev/null +++ b/cas/1.2/default/DescramblerImpl.cpp @@ -0,0 +1,195 @@ +/* + * 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_NDEBUG 0 +#define LOG_TAG "android.hardware.cas@1.1-DescramblerImpl" + +#include +#include +#include +#include +#include + +#include "DescramblerImpl.h" +#include "SharedLibrary.h" +#include "TypeConvert.h" + +namespace android { +using hidl::memory::V1_0::IMemory; + +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +#define CHECK_SUBSAMPLE_DEF(type) \ + static_assert(sizeof(SubSample) == sizeof(type::SubSample), "SubSample: size doesn't match"); \ + static_assert(offsetof(SubSample, numBytesOfClearData) == \ + offsetof(type::SubSample, mNumBytesOfClearData), \ + "SubSample: numBytesOfClearData offset doesn't match"); \ + static_assert(offsetof(SubSample, numBytesOfEncryptedData) == \ + offsetof(type::SubSample, mNumBytesOfEncryptedData), \ + "SubSample: numBytesOfEncryptedData offset doesn't match") + +CHECK_SUBSAMPLE_DEF(DescramblerPlugin); +CHECK_SUBSAMPLE_DEF(CryptoPlugin); + +DescramblerImpl::DescramblerImpl(const sp& library, DescramblerPlugin* plugin) + : mLibrary(library), mPluginHolder(plugin) { + ALOGV("CTOR: plugin=%p", mPluginHolder.get()); +} + +DescramblerImpl::~DescramblerImpl() { + ALOGV("DTOR: plugin=%p", mPluginHolder.get()); + release(); +} + +Return DescramblerImpl::setMediaCasSession(const HidlCasSessionId& sessionId) { + ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string()); + + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->setMediaCasSession(sessionId)); +} + +Return DescramblerImpl::requiresSecureDecoderComponent(const hidl_string& mime) { + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return false; + } + + return holder->requiresSecureDecoderComponent(String8(mime.c_str())); +} + +static inline bool validateRangeForSize(uint64_t offset, uint64_t length, uint64_t size) { + return isInRange(0, size, offset, length); +} + +Return DescramblerImpl::descramble(ScramblingControl scramblingControl, + const hidl_vec& subSamples, + const SharedBuffer& srcBuffer, uint64_t srcOffset, + const DestinationBuffer& dstBuffer, uint64_t dstOffset, + descramble_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + // hidl_memory's size is stored in uint64_t, but mapMemory's mmap will map + // size in size_t. If size is over SIZE_MAX, mapMemory mapMemory could succeed + // but the mapped memory's actual size will be smaller than the reported size. + if (srcBuffer.heapBase.size() > SIZE_MAX) { + ALOGE("Invalid hidl_memory size: %llu", srcBuffer.heapBase.size()); + android_errorWriteLog(0x534e4554, "79376389"); + _hidl_cb(toStatus(BAD_VALUE), 0, NULL); + return Void(); + } + + sp srcMem = mapMemory(srcBuffer.heapBase); + + // Validate if the offset and size in the SharedBuffer is consistent with the + // mapped ashmem, since the offset and size is controlled by client. + if (srcMem == NULL) { + ALOGE("Failed to map src buffer."); + _hidl_cb(toStatus(BAD_VALUE), 0, NULL); + return Void(); + } + if (!validateRangeForSize(srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize())) { + ALOGE("Invalid src buffer range: offset %llu, size %llu, srcMem size %llu", + srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize()); + android_errorWriteLog(0x534e4554, "67962232"); + _hidl_cb(toStatus(BAD_VALUE), 0, NULL); + return Void(); + } + + // use 64-bit here to catch bad subsample size that might be overflowing. + uint64_t totalBytesInSubSamples = 0; + for (size_t i = 0; i < subSamples.size(); i++) { + totalBytesInSubSamples += + (uint64_t)subSamples[i].numBytesOfClearData + subSamples[i].numBytesOfEncryptedData; + } + // Further validate if the specified srcOffset and requested total subsample size + // is consistent with the source shared buffer size. + if (!validateRangeForSize(srcOffset, totalBytesInSubSamples, srcBuffer.size)) { + ALOGE("Invalid srcOffset and subsample size: " + "srcOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu", + srcOffset, totalBytesInSubSamples, srcBuffer.size); + android_errorWriteLog(0x534e4554, "67962232"); + _hidl_cb(toStatus(BAD_VALUE), 0, NULL); + return Void(); + } + + void* srcPtr = (uint8_t*)(void*)srcMem->getPointer() + srcBuffer.offset; + void* dstPtr = NULL; + if (dstBuffer.type == BufferType::SHARED_MEMORY) { + // When using shared memory, src buffer is also used as dst, + // we don't map it again here. + dstPtr = srcPtr; + + // In this case the dst and src would be the same buffer, need to validate + // dstOffset against the buffer size too. + if (!validateRangeForSize(dstOffset, totalBytesInSubSamples, srcBuffer.size)) { + ALOGE("Invalid dstOffset and subsample size: " + "dstOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu", + dstOffset, totalBytesInSubSamples, srcBuffer.size); + android_errorWriteLog(0x534e4554, "67962232"); + _hidl_cb(toStatus(BAD_VALUE), 0, NULL); + return Void(); + } + } else { + native_handle_t* handle = + const_cast(dstBuffer.secureMemory.getNativeHandle()); + dstPtr = static_cast(handle); + } + + // Get a local copy of the shared_ptr for the plugin. Note that before + // calling the HIDL callback, this shared_ptr must be manually reset, + // since the client side could proceed as soon as the callback is called + // without waiting for this method to go out of scope. + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + _hidl_cb(toStatus(INVALID_OPERATION), 0, NULL); + return Void(); + } + + // Casting hidl SubSample to DescramblerPlugin::SubSample, but need + // to ensure structs are actually idential + + int32_t result = + holder->descramble(dstBuffer.type != BufferType::SHARED_MEMORY, + (DescramblerPlugin::ScramblingControl)scramblingControl, + subSamples.size(), (DescramblerPlugin::SubSample*)subSamples.data(), + srcPtr, srcOffset, dstPtr, dstOffset, NULL); + + holder.reset(); + _hidl_cb(toStatus(result >= 0 ? OK : result), result, NULL); + return Void(); +} + +Return DescramblerImpl::release() { + ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get()); + + std::shared_ptr holder(nullptr); + std::atomic_store(&mPluginHolder, holder); + + return Status::OK; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.2/default/DescramblerImpl.h b/cas/1.2/default/DescramblerImpl.h new file mode 100644 index 0000000000..011eace82f --- /dev/null +++ b/cas/1.2/default/DescramblerImpl.h @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_ +#define ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_ + +#include +#include + +namespace android { +struct DescramblerPlugin; +using namespace hardware::cas::native::V1_0; + +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +using ::android::hardware::cas::V1_0::HidlCasSessionId; +using ::android::hardware::cas::V1_0::Status; + +class SharedLibrary; + +class DescramblerImpl : public IDescrambler { + public: + DescramblerImpl(const sp& library, DescramblerPlugin* plugin); + virtual ~DescramblerImpl(); + + virtual Return setMediaCasSession(const HidlCasSessionId& sessionId) override; + + virtual Return requiresSecureDecoderComponent(const hidl_string& mime) override; + + virtual Return descramble(ScramblingControl scramblingControl, + const hidl_vec& subSamples, + const SharedBuffer& srcBuffer, uint64_t srcOffset, + const DestinationBuffer& dstBuffer, uint64_t dstOffset, + descramble_cb _hidl_cb) override; + + virtual Return release() override; + + private: + sp mLibrary; + std::shared_ptr mPluginHolder; + + DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl); +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_ diff --git a/cas/1.2/default/FactoryLoader.h b/cas/1.2/default/FactoryLoader.h new file mode 100644 index 0000000000..7403f86ac9 --- /dev/null +++ b/cas/1.2/default/FactoryLoader.h @@ -0,0 +1,217 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_ +#define ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_ + +#include +#include +#include +#include +#include +#include "SharedLibrary.h" + +using namespace std; + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor; + +template +class FactoryLoader { + public: + FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {} + + virtual ~FactoryLoader() { closeFactory(); } + + bool findFactoryForScheme(int32_t CA_system_id, sp* library = NULL, + T** factory = NULL); + + bool enumeratePlugins(vector* results); + + private: + typedef T* (*CreateFactoryFunc)(); + + Mutex mMapLock; + T* mFactory; + const char* mCreateFactoryFuncName; + sp mLibrary; + KeyedVector mCASystemIdToLibraryPathMap; + KeyedVector> mLibraryPathToOpenLibraryMap; + + bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id, + sp* library, T** factory); + + bool queryPluginsFromPath(const String8& path, vector* results); + + bool openFactory(const String8& path); + void closeFactory(); +}; + +template +bool FactoryLoader::findFactoryForScheme(int32_t CA_system_id, sp* library, + T** factory) { + if (library != NULL) { + library->clear(); + } + if (factory != NULL) { + *factory = NULL; + } + + Mutex::Autolock autoLock(mMapLock); + + // first check cache + ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id); + if (index >= 0) { + return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id, + library, factory); + } + + // no luck, have to search + String8 dirPath("/vendor/lib/mediacas"); + DIR* pDir = opendir(dirPath.string()); + + if (pDir == NULL) { + ALOGE("Failed to open plugin directory %s", dirPath.string()); + return false; + } + + struct dirent* pEntry; + while ((pEntry = readdir(pDir))) { + String8 pluginPath = dirPath + "/" + pEntry->d_name; + if (pluginPath.getPathExtension() == ".so") { + if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) { + mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath); + closedir(pDir); + + return true; + } + } + } + + closedir(pDir); + + ALOGE("Failed to find plugin"); + return false; +} + +template +bool FactoryLoader::enumeratePlugins(vector* results) { + ALOGI("enumeratePlugins"); + + results->clear(); + + String8 dirPath("/vendor/lib/mediacas"); + DIR* pDir = opendir(dirPath.string()); + + if (pDir == NULL) { + ALOGE("Failed to open plugin directory %s", dirPath.string()); + return false; + } + + Mutex::Autolock autoLock(mMapLock); + + struct dirent* pEntry; + while ((pEntry = readdir(pDir))) { + String8 pluginPath = dirPath + "/" + pEntry->d_name; + if (pluginPath.getPathExtension() == ".so") { + queryPluginsFromPath(pluginPath, results); + } + } + return true; +} + +template +bool FactoryLoader::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id, + sp* library, T** factory) { + closeFactory(); + + if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) { + closeFactory(); + return false; + } + + if (library != NULL) { + *library = mLibrary; + } + if (factory != NULL) { + *factory = mFactory; + } + return true; +} + +template +bool FactoryLoader::queryPluginsFromPath(const String8& path, + vector* results) { + closeFactory(); + + vector descriptors; + if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) { + closeFactory(); + return false; + } + + for (auto it = descriptors.begin(); it != descriptors.end(); it++) { + results->push_back( + HidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()}); + } + return true; +} + +template +bool FactoryLoader::openFactory(const String8& path) { + // get strong pointer to open shared library + ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path); + if (index >= 0) { + mLibrary = mLibraryPathToOpenLibraryMap[index].promote(); + } else { + index = mLibraryPathToOpenLibraryMap.add(path, NULL); + } + + if (!mLibrary.get()) { + mLibrary = new SharedLibrary(path); + if (!*mLibrary) { + return false; + } + + mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary); + } + + CreateFactoryFunc createFactory = (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName); + if (createFactory == NULL || (mFactory = createFactory()) == NULL) { + return false; + } + return true; +} + +template +void FactoryLoader::closeFactory() { + delete mFactory; + mFactory = NULL; + mLibrary.clear(); +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_ diff --git a/cas/1.2/default/MediaCasService.cpp b/cas/1.2/default/MediaCasService.cpp new file mode 100644 index 0000000000..4ecd52bd83 --- /dev/null +++ b/cas/1.2/default/MediaCasService.cpp @@ -0,0 +1,153 @@ +/* + * 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_NDEBUG 0 +#define LOG_TAG "android.hardware.cas@1.1-MediaCasService" + +#include +#include +#include +#include +#include + +#include "CasImpl.h" +#include "DescramblerImpl.h" +#include "MediaCasService.h" + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +class Wrapper : public V1_1::ICasListener { + public: + static sp wrap(sp impl) { + sp cast = V1_1::ICasListener::castFrom(impl); + if (cast == NULL) { + cast = new Wrapper(impl); + } + return cast; + } + + virtual Return onEvent(int32_t event, int32_t arg, + const hidl_vec& data) override { + mImpl->onEvent(event, arg, data); + return Void(); + } + + virtual Return onSessionEvent(const hidl_vec& /* sessionId */, + int32_t /* event */, int32_t /* arg */, + const hidl_vec& /*data*/) override { + ALOGV("Do nothing on Session Event for cas@1.0 client in cas@1.1"); + return Void(); + } + + private: + Wrapper(sp impl) : mImpl(impl){}; + sp mImpl; +}; + +MediaCasService::MediaCasService() + : mCasLoader("createCasFactory"), mDescramblerLoader("createDescramblerFactory") {} + +MediaCasService::~MediaCasService() {} + +Return MediaCasService::enumeratePlugins(enumeratePlugins_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + vector results; + mCasLoader.enumeratePlugins(&results); + + _hidl_cb(results); + return Void(); +} + +Return MediaCasService::isSystemIdSupported(int32_t CA_system_id) { + ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id); + + return mCasLoader.findFactoryForScheme(CA_system_id); +} + +Return> MediaCasService::createPlugin(int32_t CA_system_id, + const sp& listener) { + ALOGV("%s:Use createPluginExt to create plugin in cas@1.1", __FUNCTION__); + + sp result; + + sp listenerV1_1 = Wrapper::wrap(listener); + + result = createPluginExt(CA_system_id, listenerV1_1); + + return result; +} + +Return> MediaCasService::createPluginExt(int32_t CA_system_id, + const sp& listener) { + ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id); + if (listener == NULL) ALOGV("%s: Listener is NULL", __FUNCTION__); + + sp result; + + CasFactory* factory; + sp library; + if (mCasLoader.findFactoryForScheme(CA_system_id, &library, &factory)) { + CasPlugin* plugin = NULL; + sp casImpl = new CasImpl(listener); + if (factory->createPlugin(CA_system_id, casImpl.get(), &CasImpl::CallBackExt, &plugin) == + OK && + plugin != NULL) { + casImpl->init(library, plugin); + result = casImpl; + + sp listenerV1_2 = V1_2::ICasListener::castFrom(listener); + if (listenerV1_2 != NULL) { + casImpl->setPluginStatusUpdateCallback(); + } + } + } + + return result; +} + +Return MediaCasService::isDescramblerSupported(int32_t CA_system_id) { + ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id); + + return mDescramblerLoader.findFactoryForScheme(CA_system_id); +} + +Return> MediaCasService::createDescrambler(int32_t CA_system_id) { + ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id); + + sp result; + + DescramblerFactory* factory; + sp library; + if (mDescramblerLoader.findFactoryForScheme(CA_system_id, &library, &factory)) { + DescramblerPlugin* plugin = NULL; + if (factory->createPlugin(CA_system_id, &plugin) == OK && plugin != NULL) { + result = new DescramblerImpl(library, plugin); + } + } + + return result; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.2/default/MediaCasService.h b/cas/1.2/default/MediaCasService.h new file mode 100644 index 0000000000..01e11db4ea --- /dev/null +++ b/cas/1.2/default/MediaCasService.h @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_ +#define ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_ + +#include +#include + +#include "FactoryLoader.h" + +namespace android { +struct CasFactory; +struct DescramblerFactory; +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor; +using ::android::hardware::cas::V1_0::IDescramblerBase; + +class MediaCasService : public V1_2::IMediaCasService { + public: + MediaCasService(); + + virtual Return enumeratePlugins(enumeratePlugins_cb _hidl_cb) override; + + virtual Return isSystemIdSupported(int32_t CA_system_id) override; + + virtual Return> createPlugin(int32_t CA_system_id, + const sp& listener) override; + + virtual Return> createPluginExt(int32_t CA_system_id, + const sp& listener) override; + + virtual Return isDescramblerSupported(int32_t CA_system_id) override; + + virtual Return> createDescrambler(int32_t CA_system_id) override; + + private: + FactoryLoader mCasLoader; + FactoryLoader mDescramblerLoader; + + virtual ~MediaCasService(); +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_ diff --git a/cas/1.2/default/SharedLibrary.cpp b/cas/1.2/default/SharedLibrary.cpp new file mode 100644 index 0000000000..ffe4bb977a --- /dev/null +++ b/cas/1.2/default/SharedLibrary.cpp @@ -0,0 +1,65 @@ +/* + * 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_NDEBUG 0 +#define LOG_TAG "android.hardware.cas@1.1-SharedLibrary" + +#include "SharedLibrary.h" +#include +#include +#include + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +SharedLibrary::SharedLibrary(const String8& path) { + mLibHandle = dlopen(path.string(), RTLD_NOW); +} + +SharedLibrary::~SharedLibrary() { + if (mLibHandle != NULL) { + dlclose(mLibHandle); + mLibHandle = NULL; + } +} + +bool SharedLibrary::operator!() const { + return mLibHandle == NULL; +} + +void* SharedLibrary::lookup(const char* symbol) const { + if (!mLibHandle) { + return NULL; + } + // Clear last error before we load the symbol again, + // in case the caller didn't retrieve it. + (void)dlerror(); + return dlsym(mLibHandle, symbol); +} + +const char* SharedLibrary::lastError() const { + const char* error = dlerror(); + return error ? error : "No errors or unknown error"; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.2/default/SharedLibrary.h b/cas/1.2/default/SharedLibrary.h new file mode 100644 index 0000000000..b85f557ab4 --- /dev/null +++ b/cas/1.2/default/SharedLibrary.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_ +#define ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_ + +#include +#include +#include + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +class SharedLibrary : public RefBase { + public: + explicit SharedLibrary(const String8& path); + ~SharedLibrary(); + + bool operator!() const; + void* lookup(const char* symbol) const; + const char* lastError() const; + + private: + void* mLibHandle; + DISALLOW_EVIL_CONSTRUCTORS(SharedLibrary); +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_ diff --git a/cas/1.2/default/TypeConvert.cpp b/cas/1.2/default/TypeConvert.cpp new file mode 100644 index 0000000000..c4bd0dded5 --- /dev/null +++ b/cas/1.2/default/TypeConvert.cpp @@ -0,0 +1,121 @@ +/* + * 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_NDEBUG 0 +#define LOG_TAG "android.hardware.cas@1.1-TypeConvert" + +#include "TypeConvert.h" +#include + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +Status toStatus(status_t legacyStatus) { + Status status; + switch (legacyStatus) { + case android::OK: + status = Status::OK; + break; + case android::ERROR_CAS_NO_LICENSE: + status = Status::ERROR_CAS_NO_LICENSE; + break; + case android::ERROR_CAS_LICENSE_EXPIRED: + status = Status::ERROR_CAS_LICENSE_EXPIRED; + break; + case android::ERROR_CAS_SESSION_NOT_OPENED: + status = Status::ERROR_CAS_SESSION_NOT_OPENED; + break; + case android::ERROR_CAS_CANNOT_HANDLE: + status = Status::ERROR_CAS_CANNOT_HANDLE; + break; + case android::ERROR_CAS_TAMPER_DETECTED: + status = Status::ERROR_CAS_INVALID_STATE; + break; + case android::BAD_VALUE: + status = Status::BAD_VALUE; + break; + case android::ERROR_CAS_NOT_PROVISIONED: + status = Status::ERROR_CAS_NOT_PROVISIONED; + break; + case android::ERROR_CAS_RESOURCE_BUSY: + status = Status::ERROR_CAS_RESOURCE_BUSY; + break; + case android::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION: + status = Status::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION; + break; + case android::ERROR_CAS_DEVICE_REVOKED: + status = Status::ERROR_CAS_DEVICE_REVOKED; + break; + case android::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED: + status = Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED; + break; + case android::ERROR_CAS_DECRYPT: + status = Status::ERROR_CAS_DECRYPT; + break; + default: + ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN", legacyStatus); + status = Status::ERROR_CAS_UNKNOWN; + break; + } + return status; +} + +V1_2::Status toStatus_1_2(status_t legacyStatus) { + V1_2::Status status = static_cast(toStatus(legacyStatus)); + if (status == V1_2::Status::ERROR_CAS_UNKNOWN) { + switch (legacyStatus) { + case android::ERROR_CAS_NEED_ACTIVATION: + status = V1_2::Status::ERROR_CAS_NEED_ACTIVATION; + break; + case android::ERROR_CAS_NEED_PAIRING: + status = V1_2::Status::ERROR_CAS_NEED_PAIRING; + break; + case android::ERROR_CAS_NO_CARD: + status = V1_2::Status::ERROR_CAS_NO_CARD; + break; + case android::ERROR_CAS_CARD_MUTE: + status = V1_2::Status::ERROR_CAS_CARD_MUTE; + break; + case android::ERROR_CAS_CARD_INVALID: + status = V1_2::Status::ERROR_CAS_CARD_INVALID; + break; + case android::ERROR_CAS_BLACKOUT: + status = V1_2::Status::ERROR_CAS_BLACKOUT; + break; + } + } + return status; +} + +String8 sessionIdToString(const CasSessionId& sessionId) { + String8 result; + for (size_t i = 0; i < sessionId.size(); i++) { + result.appendFormat("%02x ", sessionId[i]); + } + if (result.isEmpty()) { + result.append("(null)"); + } + return result; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.2/default/TypeConvert.h b/cas/1.2/default/TypeConvert.h new file mode 100644 index 0000000000..018f310f2c --- /dev/null +++ b/cas/1.2/default/TypeConvert.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H +#define ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H + +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +using ::android::hardware::cas::V1_0::Status; + +Status toStatus(status_t legacyStatus); + +V1_2::Status toStatus_1_2(status_t legacyStatus); + +String8 sessionIdToString(const CasSessionId& sessionId); + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H diff --git a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc new file mode 100644 index 0000000000..1c7510030b --- /dev/null +++ b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc @@ -0,0 +1,11 @@ +service vendor.cas-hal-1-2 /vendor/bin/hw/android.hardware.cas@1.2-service-lazy + interface android.hardware.cas@1.0::IMediaCasService default + interface android.hardware.cas@1.1::IMediaCasService default + interface android.hardware.cas@1.2::IMediaCasService default + oneshot + disabled + class hal + user media + group mediadrm drmrpc + ioprio rt 4 + writepid /dev/cpuset/foreground/tasks diff --git a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml new file mode 100644 index 0000000000..9b36406055 --- /dev/null +++ b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml @@ -0,0 +1,11 @@ + + + android.hardware.cas + hwbinder + 1.2 + + IMediaCasService + default + + + diff --git a/cas/1.2/default/android.hardware.cas@1.2-service.rc b/cas/1.2/default/android.hardware.cas@1.2-service.rc new file mode 100644 index 0000000000..d1c853e40f --- /dev/null +++ b/cas/1.2/default/android.hardware.cas@1.2-service.rc @@ -0,0 +1,6 @@ +service vendor.cas-hal-1-2 /vendor/bin/hw/android.hardware.cas@1.2-service + class hal + user media + group mediadrm drmrpc + ioprio rt 4 + writepid /dev/cpuset/foreground/tasks diff --git a/cas/1.2/default/android.hardware.cas@1.2-service.xml b/cas/1.2/default/android.hardware.cas@1.2-service.xml new file mode 100644 index 0000000000..9b36406055 --- /dev/null +++ b/cas/1.2/default/android.hardware.cas@1.2-service.xml @@ -0,0 +1,11 @@ + + + android.hardware.cas + hwbinder + 1.2 + + IMediaCasService + default + + + diff --git a/cas/1.2/default/service.cpp b/cas/1.2/default/service.cpp new file mode 100644 index 0000000000..a623447b88 --- /dev/null +++ b/cas/1.2/default/service.cpp @@ -0,0 +1,58 @@ +/* + * Copyright 2017 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_NDEBUG 0 +#ifdef LAZY_SERVICE +#define LOG_TAG "android.hardware.cas@1.1-service-lazy" +#else +#define LOG_TAG "android.hardware.cas@1.1-service" +#endif + +#include +#include +#include + +#include "MediaCasService.h" + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::LazyServiceRegistrar; +using android::hardware::cas::V1_1::implementation::MediaCasService; +using android::hardware::cas::V1_2::IMediaCasService; + +#ifdef LAZY_SERVICE +const bool kLazyService = true; +#else +const bool kLazyService = false; +#endif + +int main() { + configureRpcThreadpool(8, true /* callerWillJoin */); + + // Setup hwbinder service + android::sp service = new MediaCasService(); + android::status_t status; + if (kLazyService) { + auto serviceRegistrar = LazyServiceRegistrar::getInstance(); + status = serviceRegistrar.registerService(service); + } else { + status = service->registerAsService(); + } + LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering cas service: %d", status); + + joinRpcThreadpool(); + return 0; +} diff --git a/cas/1.2/types.hal b/cas/1.2/types.hal new file mode 100644 index 0000000000..40c06cf1c7 --- /dev/null +++ b/cas/1.2/types.hal @@ -0,0 +1,149 @@ +/* + * 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. + */ + +package android.hardware.cas@1.2; + +import android.hardware.cas@1.0; +import android.hardware.cas@1.1; + +enum Status : @1.0::Status { + /** + * ERROR_CAS_NEED_ACTIVATION is used to trigger device activation process. + */ + ERROR_CAS_NEED_ACTIVATION, + /** + * ERROR_CAS_NEED_PAIRING is used to trigger pairing process. + */ + ERROR_CAS_NEED_PAIRING, + /** + * ERROR_CAS_NO_CARD is used to report no smart card for descrambling. + */ + ERROR_CAS_NO_CARD, + /** + * ERROR_CAS_CARD_MUTE is used to report smart card is muted for + * descrambling. + */ + ERROR_CAS_CARD_MUTE, + /** + * ERROR_CAS_CARD_INVALID is used to report smart card isn't valid. + */ + ERROR_CAS_CARD_INVALID, + /** + * ERROR_CAS_BLACKOUT is used to report geographical blackout. + */ + ERROR_CAS_BLACKOUT, +}; + +/** + * The intented usage for the session. + */ +enum SessionIntent : uint32_t { + /** + * Live Stream. + */ + LIVE, + /** + * Playback Recorded Stream. + */ + PLAYBACK, + /** + * Record Live Stream. + */ + RECORD, + /** + * View the content with Time Shift capability + */ + TIMESHIFT, +}; + +/** + * The Scrambling Mode. + */ +enum ScramblingMode : uint32_t { + RESERVED = 0, + /** + * DVB (Digital Video Broadcasting) CSA1 (Common Scrambling Algorithm 1) is + * the default mode and shall be used when the scrambling descriptor + * is not present in the program map section. DVB scrambling mode is + * specified in ETSI EN 300 468 specification. + */ + DVB_CSA1, + DVB_CSA2, + /** + * DVB-CSA3 in standard mode. + */ + DVB_CSA3_STANDARD, + /** + * DVB-CSA3 in minimally enhanced mode. + */ + DVB_CSA3_MINIMAL, + /** + * DVB-CSA3 in fully enhanced mode. + */ + DVB_CSA3_ENHANCE, + /** + * DVB-CISSA version 1. + */ + DVB_CISSA_V1, + /** + * ATIS-0800006 IIF Default Scrambling Algorithm (IDSA). + */ + DVB_IDSA, + /** + * a symmetric key algorithm. + */ + MULTI2, + /** + * Advanced Encryption System (AES) 128-bit Encryption mode. + */ + AES128, + /** + * Advanced Encryption System (AES) Electronic Code Book (ECB) mode. + */ + AES_ECB, + /** + * Advanced Encryption System (AES) Society of Cable Telecommunications + * Engineers (SCTE) 52 mode. + */ + AES_SCTE52, + /** + * Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode. + */ + TDES_ECB, + /** + * Triple Data Encryption Algorithm (TDES) Society of Cable Telecommunications + * Engineers (SCTE) 52 mode. + */ + TDES_SCTE52, + }; + +/** + * The Event Type for status change. + */ +enum StatusEvent : uint8_t { + /** + * The status of CAS plugin was changed due to physical module insertion or + * removal. Client must call enumeratePlugins to update plugins' status. + */ + PLUGIN_PHYSICAL_MODULE_CHANGED, + /** + * The status of supported session number was changed due to physical module + * insertion or removal. Client must update session resource according to + * latest StatusMessage from the StatusEvent. The plugin supports unlimited + * sesssion by default. + */ + PLUGIN_SESSION_NUMBER_CHANGED, +}; diff --git a/cas/1.2/vts/functional/Android.bp b/cas/1.2/vts/functional/Android.bp new file mode 100644 index 0000000000..9bc372c3a7 --- /dev/null +++ b/cas/1.2/vts/functional/Android.bp @@ -0,0 +1,36 @@ +// +// 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. +// + +cc_test { + name: "VtsHalCasV1_2TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalCasV1_2TargetTest.cpp"], + static_libs: [ + "android.hardware.cas@1.0", + "android.hardware.cas@1.1", + "android.hardware.cas@1.2", + "android.hardware.cas.native@1.0", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "libhidlallocatorutils", + "libhidlmemory", + ], + shared_libs: [ + "libbinder", + ], + test_suites: ["general-tests"], +} + diff --git a/cas/1.2/vts/functional/OWNERS b/cas/1.2/vts/functional/OWNERS new file mode 100644 index 0000000000..29246edc81 --- /dev/null +++ b/cas/1.2/vts/functional/OWNERS @@ -0,0 +1,3 @@ +nchalko@google.com +chz@google.com +quxiangfang@google.com diff --git a/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp new file mode 100644 index 0000000000..8439ceb6fa --- /dev/null +++ b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp @@ -0,0 +1,619 @@ +/* + * 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 "mediacas_hidl_hal_test" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CLEAR_KEY_SYSTEM_ID 0xF6D8 +#define INVALID_SYSTEM_ID 0 +#define WAIT_TIMEOUT 3000000000 + +#define PROVISION_STR \ + "{ " \ + " \"id\": 21140844, " \ + " \"name\": \"Test Title\", " \ + " \"lowercase_organization_name\": \"Android\", " \ + " \"asset_key\": { " \ + " \"encryption_key\": \"nezAr3CHFrmBR9R8Tedotw==\" " \ + " }, " \ + " \"cas_type\": 1, " \ + " \"track_types\": [ ] " \ + "} " + +using android::Condition; +using android::IMemory; +using android::IMemoryHeap; +using android::MemoryDealer; +using android::Mutex; +using android::sp; +using android::hardware::fromHeap; +using android::hardware::hidl_string; +using android::hardware::hidl_vec; +using android::hardware::HidlMemory; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::cas::native::V1_0::BufferType; +using android::hardware::cas::native::V1_0::DestinationBuffer; +using android::hardware::cas::native::V1_0::IDescrambler; +using android::hardware::cas::native::V1_0::ScramblingControl; +using android::hardware::cas::native::V1_0::SharedBuffer; +using android::hardware::cas::native::V1_0::SubSample; +using android::hardware::cas::V1_0::HidlCasPluginDescriptor; +using android::hardware::cas::V1_0::IDescramblerBase; +using android::hardware::cas::V1_0::Status; +using android::hardware::cas::V1_2::ICas; +using android::hardware::cas::V1_2::ICasListener; +using android::hardware::cas::V1_2::IMediaCasService; +using android::hardware::cas::V1_2::ScramblingMode; +using android::hardware::cas::V1_2::SessionIntent; +using android::hardware::cas::V1_2::StatusEvent; + +namespace { + +const uint8_t kEcmBinaryBuffer[] = { + 0x00, 0x00, 0x01, 0xf0, 0x00, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x46, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x27, 0x10, 0x02, 0x00, + 0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0x0e, 0xe3, 0x91, 0xbc, 0xfd, 0x05, 0xb1, 0x60, 0x4f, + 0x17, 0x82, 0xa4, 0x86, 0x9b, 0x23, 0x56, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x27, 0x10, 0x02, 0x00, 0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0xd7, 0x43, 0x62, 0xf8, 0x1c, + 0x62, 0x19, 0x05, 0xc7, 0x3a, 0x42, 0xcd, 0xfd, 0xd9, 0x13, 0x48, +}; + +const SubSample kSubSamples[] = {{162, 0}, {0, 184}, {0, 184}}; + +const uint8_t kInBinaryBuffer[] = { + 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb, + 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03, + 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06, + 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, + 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, + 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d, + 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63, + 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, + 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, + 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x6e, 0x45, 0x21, + 0x82, 0x38, 0xf0, 0x9d, 0x7d, 0x96, 0xe6, 0x94, 0xae, 0xe2, 0x87, 0x8f, 0x04, 0x49, 0xe5, + 0xf6, 0x8c, 0x8b, 0x9a, 0x10, 0x18, 0xba, 0x94, 0xe9, 0x22, 0x31, 0x04, 0x7e, 0x60, 0x5b, + 0xc4, 0x24, 0x00, 0x90, 0x62, 0x0d, 0xdc, 0x85, 0x74, 0x75, 0x78, 0xd0, 0x14, 0x08, 0xcb, + 0x02, 0x1d, 0x7d, 0x9d, 0x34, 0xe8, 0x81, 0xb9, 0xf7, 0x09, 0x28, 0x79, 0x29, 0x8d, 0xe3, + 0x14, 0xed, 0x5f, 0xca, 0xaf, 0xf4, 0x1c, 0x49, 0x15, 0xe1, 0x80, 0x29, 0x61, 0x76, 0x80, + 0x43, 0xf8, 0x58, 0x53, 0x40, 0xd7, 0x31, 0x6d, 0x61, 0x81, 0x41, 0xe9, 0x77, 0x9f, 0x9c, + 0xe1, 0x6d, 0xf2, 0xee, 0xd9, 0xc8, 0x67, 0xd2, 0x5f, 0x48, 0x73, 0xe3, 0x5c, 0xcd, 0xa7, + 0x45, 0x58, 0xbb, 0xdd, 0x28, 0x1d, 0x68, 0xfc, 0xb4, 0xc6, 0xf6, 0x92, 0xf6, 0x30, 0x03, + 0xaa, 0xe4, 0x32, 0xf6, 0x34, 0x51, 0x4b, 0x0f, 0x8c, 0xf9, 0xac, 0x98, 0x22, 0xfb, 0x49, + 0xc8, 0xbf, 0xca, 0x8c, 0x80, 0x86, 0x5d, 0xd7, 0xa4, 0x52, 0xb1, 0xd9, 0xa6, 0x04, 0x4e, + 0xb3, 0x2d, 0x1f, 0xb8, 0x35, 0xcc, 0x45, 0x6d, 0x9c, 0x20, 0xa7, 0xa4, 0x34, 0x59, 0x72, + 0xe3, 0xae, 0xba, 0x49, 0xde, 0xd1, 0xaa, 0xee, 0x3d, 0x77, 0xfc, 0x5d, 0xc6, 0x1f, 0x9d, + 0xac, 0xc2, 0x15, 0x66, 0xb8, 0xe1, 0x54, 0x4e, 0x74, 0x93, 0xdb, 0x9a, 0x24, 0x15, 0x6e, + 0x20, 0xa3, 0x67, 0x3e, 0x5a, 0x24, 0x41, 0x5e, 0xb0, 0xe6, 0x35, 0x87, 0x1b, 0xc8, 0x7a, + 0xf9, 0x77, 0x65, 0xe0, 0x01, 0xf2, 0x4c, 0xe4, 0x2b, 0xa9, 0x64, 0x96, 0x96, 0x0b, 0x46, + 0xca, 0xea, 0x79, 0x0e, 0x78, 0xa3, 0x5f, 0x43, 0xfc, 0x47, 0x6a, 0x12, 0xfa, 0xc4, 0x33, + 0x0e, 0x88, 0x1c, 0x19, 0x3a, 0x00, 0xc3, 0x4e, 0xb5, 0xd8, 0xfa, 0x8e, 0xf1, 0xbc, 0x3d, + 0xb2, 0x7e, 0x50, 0x8d, 0x67, 0xc3, 0x6b, 0xed, 0xe2, 0xea, 0xa6, 0x1f, 0x25, 0x24, 0x7c, + 0x94, 0x74, 0x50, 0x49, 0xe3, 0xc6, 0x58, 0x2e, 0xfd, 0x28, 0xb4, 0xc6, 0x73, 0xb1, 0x53, + 0x74, 0x27, 0x94, 0x5c, 0xdf, 0x69, 0xb7, 0xa1, 0xd7, 0xf5, 0xd3, 0x8a, 0x2c, 0x2d, 0xb4, + 0x5e, 0x8a, 0x16, 0x14, 0x54, 0x64, 0x6e, 0x00, 0x6b, 0x11, 0x59, 0x8a, 0x63, 0x38, 0x80, + 0x76, 0xc3, 0xd5, 0x59, 0xf7, 0x3f, 0xd2, 0xfa, 0xa5, 0xca, 0x82, 0xff, 0x4a, 0x62, 0xf0, + 0xe3, 0x42, 0xf9, 0x3b, 0x38, 0x27, 0x8a, 0x89, 0xaa, 0x50, 0x55, 0x4b, 0x29, 0xf1, 0x46, + 0x7c, 0x75, 0xef, 0x65, 0xaf, 0x9b, 0x0d, 0x6d, 0xda, 0x25, 0x94, 0x14, 0xc1, 0x1b, 0xf0, + 0xc5, 0x4c, 0x24, 0x0e, 0x65, +}; + +const uint8_t kOutRefBinaryBuffer[] = { + 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb, + 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03, + 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06, + 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, + 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, + 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d, + 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63, + 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, + 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, + 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, + 0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d, + 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65, + 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31, + 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e, + 0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20, + 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, + 0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69, + 0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71, + 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, + 0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d, + 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, + 0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68, + 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f, + 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, + 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79, + 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, + 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20, + 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30, + 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20, + 0x73, 0x63, 0x65, 0x6e, 0x65, +}; + +class MediaCasListener : public ICasListener { + public: + virtual Return onEvent(int32_t event, int32_t arg, + const hidl_vec& data) override { + android::Mutex::Autolock autoLock(mMsgLock); + mEvent = event; + mEventArg = arg; + mEventData = data; + + mEventReceived = true; + mMsgCondition.signal(); + return Void(); + } + + virtual Return onSessionEvent(const hidl_vec& sessionId, int32_t event, + int32_t arg, const hidl_vec& data) override { + android::Mutex::Autolock autoLock(mMsgLock); + mSessionId = sessionId; + mEvent = event; + mEventArg = arg; + mEventData = data; + + mEventReceived = true; + mMsgCondition.signal(); + return Void(); + } + + virtual Return onStatusUpdate(StatusEvent event, int32_t arg) override { + android::Mutex::Autolock autoLock(mMsgLock); + mStatusEvent = event; + mEventArg = arg; + + mEventReceived = true; + mMsgCondition.signal(); + return Void(); + } + + void testEventEcho(sp& mediaCas, int32_t& event, int32_t& eventArg, + hidl_vec& eventData); + + void testSessionEventEcho(sp& mediaCas, const hidl_vec& sessionId, + int32_t& event, int32_t& eventArg, hidl_vec& eventData); + + void testStatusUpdate(sp& mediaCas, std::vector* sessionId, SessionIntent intent, + ScramblingMode mode); + + private: + int32_t mEvent = -1; + int32_t mEventArg = -1; + StatusEvent mStatusEvent; + bool mEventReceived = false; + hidl_vec mEventData; + hidl_vec mSessionId; + android::Mutex mMsgLock; + android::Condition mMsgCondition; +}; + +void MediaCasListener::testEventEcho(sp& mediaCas, int32_t& event, int32_t& eventArg, + hidl_vec& eventData) { + mEventReceived = false; + auto returnStatus = mediaCas->sendEvent(event, eventArg, eventData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + android::Mutex::Autolock autoLock(mMsgLock); + while (!mEventReceived) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "event not received within timeout"; + return; + } + } + + EXPECT_EQ(mEvent, event); + EXPECT_EQ(mEventArg, eventArg); + EXPECT_TRUE(mEventData == eventData); +} + +void MediaCasListener::testSessionEventEcho(sp& mediaCas, const hidl_vec& sessionId, + int32_t& event, int32_t& eventArg, + hidl_vec& eventData) { + mEventReceived = false; + auto returnStatus = mediaCas->sendSessionEvent(sessionId, event, eventArg, eventData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + android::Mutex::Autolock autoLock(mMsgLock); + while (!mEventReceived) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "event not received within timeout"; + return; + } + } + + EXPECT_TRUE(mSessionId == sessionId); + EXPECT_EQ(mEvent, event); + EXPECT_EQ(mEventArg, eventArg); + EXPECT_TRUE(mEventData == eventData); +} + +void MediaCasListener::testStatusUpdate(sp& mediaCas, std::vector* sessionId, + SessionIntent intent, ScramblingMode mode) { + mEventReceived = false; + android::hardware::cas::V1_2::Status sessionStatus; + auto returnVoid = mediaCas->openSession_1_2( + intent, mode, + [&](android::hardware::cas::V1_2::Status status, const hidl_vec& id) { + sessionStatus = status; + *sessionId = id; + }); + EXPECT_TRUE(returnVoid.isOk()); + EXPECT_EQ(android::hardware::cas::V1_2::Status::OK, sessionStatus); + + android::Mutex::Autolock autoLock(mMsgLock); + while (!mEventReceived) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "event not received within timeout"; + return; + } + } + EXPECT_EQ(mStatusEvent, static_cast(intent)); + EXPECT_EQ(mEventArg, static_cast(mode)); +} + +// Test environment for Cas HIDL HAL. +class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static CasHidlEnvironment* Instance() { + static CasHidlEnvironment* instance = new CasHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { registerTestService(); } +}; + +class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + mService = ::testing::VtsHalHidlTargetTestBase::getService( + CasHidlEnvironment::Instance()->getServiceName()); + ASSERT_NE(mService, nullptr); + } + + sp mService; + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp mMediaCas; + sp mDescramblerBase; + sp mCasListener; + typedef struct _OobInputTestParams { + const SubSample* subSamples; + uint32_t numSubSamples; + size_t imemSizeActual; + uint64_t imemOffset; + uint64_t imemSize; + uint64_t srcOffset; + uint64_t dstOffset; + } OobInputTestParams; + + ::testing::AssertionResult createCasPlugin(int32_t caSystemId); + ::testing::AssertionResult openCasSession(std::vector* sessionId); + ::testing::AssertionResult openCasSession_1_2(std::vector* sessionId, + SessionIntent intent, ScramblingMode mode); + ::testing::AssertionResult descrambleTestInputBuffer(const sp& descrambler, + Status* descrambleStatus, + sp* hidlInMemory); + ::testing::AssertionResult descrambleTestOobInput(const sp& descrambler, + Status* descrambleStatus, + const OobInputTestParams& params); +}; + +::testing::AssertionResult MediaCasHidlTest::createCasPlugin(int32_t caSystemId) { + auto status = mService->isSystemIdSupported(caSystemId); + if (!status.isOk() || !status) { + return ::testing::AssertionFailure(); + } + status = mService->isDescramblerSupported(caSystemId); + if (!status.isOk() || !status) { + return ::testing::AssertionFailure(); + } + + mCasListener = new MediaCasListener(); + auto pluginStatus = mService->createPluginExt(caSystemId, mCasListener); + if (!pluginStatus.isOk()) { + return ::testing::AssertionFailure(); + } + mMediaCas = ICas::castFrom(pluginStatus); + if (mMediaCas == nullptr) { + return ::testing::AssertionFailure(); + } + + auto descramblerStatus = mService->createDescrambler(caSystemId); + if (!descramblerStatus.isOk()) { + return ::testing::AssertionFailure(); + } + mDescramblerBase = descramblerStatus; + return ::testing::AssertionResult(mDescramblerBase != nullptr); +} + +::testing::AssertionResult MediaCasHidlTest::openCasSession(std::vector* sessionId) { + Status sessionStatus; + auto returnVoid = mMediaCas->openSession([&](Status status, const hidl_vec& id) { + sessionStatus = status; + *sessionId = id; + }); + return ::testing::AssertionResult(returnVoid.isOk() && (Status::OK == sessionStatus)); +} + +::testing::AssertionResult MediaCasHidlTest::descrambleTestInputBuffer( + const sp& descrambler, Status* descrambleStatus, sp* inMemory) { + hidl_vec hidlSubSamples; + hidlSubSamples.setToExternal(const_cast(kSubSamples), + (sizeof(kSubSamples) / sizeof(SubSample)), false /*own*/); + + sp dealer = new MemoryDealer(sizeof(kInBinaryBuffer), "vts-cas"); + if (nullptr == dealer.get()) { + ALOGE("couldn't get MemoryDealer!"); + return ::testing::AssertionFailure(); + } + + sp mem = dealer->allocate(sizeof(kInBinaryBuffer)); + if (nullptr == mem.get()) { + ALOGE("couldn't allocate IMemory!"); + return ::testing::AssertionFailure(); + } + *inMemory = mem; + + // build HidlMemory from memory heap + ssize_t offset; + size_t size; + sp heap = mem->getMemory(&offset, &size); + if (nullptr == heap.get()) { + ALOGE("couldn't get memory heap!"); + return ::testing::AssertionFailure(); + } + + uint8_t* ipBuffer = static_cast(static_cast(mem->unsecurePointer())); + memcpy(ipBuffer, kInBinaryBuffer, sizeof(kInBinaryBuffer)); + + // hidlMemory is not to be passed out of scope! + sp hidlMemory = fromHeap(heap); + + SharedBuffer srcBuffer = { + .heapBase = *hidlMemory, .offset = (uint64_t)offset, .size = (uint64_t)size}; + + DestinationBuffer dstBuffer; + dstBuffer.type = BufferType::SHARED_MEMORY; + dstBuffer.nonsecureMemory = srcBuffer; + + uint32_t outBytes; + hidl_string detailedError; + auto returnVoid = descrambler->descramble( + ScramblingControl::EVENKEY /*2*/, hidlSubSamples, srcBuffer, 0, dstBuffer, 0, + [&](Status status, uint32_t bytesWritten, const hidl_string& detailedErr) { + *descrambleStatus = status; + outBytes = bytesWritten; + detailedError = detailedErr; + }); + if (!returnVoid.isOk() || *descrambleStatus != Status::OK) { + ALOGI("descramble failed, trans=%s, status=%d, outBytes=%u, error=%s", + returnVoid.description().c_str(), *descrambleStatus, outBytes, detailedError.c_str()); + } + return ::testing::AssertionResult(returnVoid.isOk()); +} + +::testing::AssertionResult MediaCasHidlTest::descrambleTestOobInput( + const sp& descrambler, Status* descrambleStatus, + const OobInputTestParams& params) { + hidl_vec hidlSubSamples; + hidlSubSamples.setToExternal(const_cast(params.subSamples), params.numSubSamples, + false /*own*/); + + sp dealer = new MemoryDealer(params.imemSizeActual, "vts-cas"); + if (nullptr == dealer.get()) { + ALOGE("couldn't get MemoryDealer!"); + return ::testing::AssertionFailure(); + } + + sp mem = dealer->allocate(params.imemSizeActual); + if (nullptr == mem.get()) { + ALOGE("couldn't allocate IMemory!"); + return ::testing::AssertionFailure(); + } + + // build HidlMemory from memory heap + ssize_t offset; + size_t size; + sp heap = mem->getMemory(&offset, &size); + if (nullptr == heap.get()) { + ALOGE("couldn't get memory heap!"); + return ::testing::AssertionFailure(); + } + + // hidlMemory is not to be passed out of scope! + sp hidlMemory = fromHeap(heap); + + SharedBuffer srcBuffer = { + .heapBase = *hidlMemory, + .offset = (uint64_t)offset + params.imemOffset, + .size = (uint64_t)params.imemSize, + }; + + DestinationBuffer dstBuffer; + dstBuffer.type = BufferType::SHARED_MEMORY; + dstBuffer.nonsecureMemory = srcBuffer; + + uint32_t outBytes; + hidl_string detailedError; + auto returnVoid = descrambler->descramble( + ScramblingControl::EVENKEY /*2*/, hidlSubSamples, srcBuffer, params.srcOffset, + dstBuffer, params.dstOffset, + [&](Status status, uint32_t bytesWritten, const hidl_string& detailedErr) { + *descrambleStatus = status; + outBytes = bytesWritten; + detailedError = detailedErr; + }); + if (!returnVoid.isOk() || *descrambleStatus != Status::OK) { + ALOGI("descramble failed, trans=%s, status=%d, outBytes=%u, error=%s", + returnVoid.description().c_str(), *descrambleStatus, outBytes, detailedError.c_str()); + } + return ::testing::AssertionResult(returnVoid.isOk()); +} + +TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) { + description("Test that valid call sequences with SessionEvent send and receive"); + + ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID)); + + auto returnStatus = mMediaCas->provision(hidl_string(PROVISION_STR)); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + hidl_vec hidlPvtData; + hidlPvtData.resize(256); + returnStatus = mMediaCas->setPrivateData(hidlPvtData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + std::vector sessionId; + ASSERT_TRUE(openCasSession(&sessionId)); + returnStatus = mMediaCas->setSessionPrivateData(sessionId, hidlPvtData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + std::vector streamSessionId; + ASSERT_TRUE(openCasSession(&streamSessionId)); + returnStatus = mMediaCas->setSessionPrivateData(streamSessionId, hidlPvtData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + returnStatus = mDescramblerBase->setMediaCasSession(sessionId); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + returnStatus = mDescramblerBase->setMediaCasSession(streamSessionId); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + hidl_vec hidlNullPtr; + hidlNullPtr.setToExternal(static_cast(nullptr), 0); + returnStatus = mMediaCas->refreshEntitlements(3, hidlNullPtr); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + uint8_t refreshData[] = {0, 1, 2, 3}; + hidl_vec hidlRefreshData; + hidlRefreshData.setToExternal(static_cast(refreshData), sizeof(refreshData)); + returnStatus = mMediaCas->refreshEntitlements(10, hidlRefreshData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + int32_t eventID = 1; + int32_t eventArg = 2; + mCasListener->testEventEcho(mMediaCas, eventID, eventArg, hidlNullPtr); + mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, hidlNullPtr); + + eventID = 3; + eventArg = 4; + uint8_t eventData[] = {'e', 'v', 'e', 'n', 't', 'd', 'a', 't', 'a'}; + hidl_vec hidlEventData; + hidlEventData.setToExternal(static_cast(eventData), sizeof(eventData)); + mCasListener->testEventEcho(mMediaCas, eventID, eventArg, hidlEventData); + mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, hidlEventData); + + SessionIntent intent = SessionIntent::LIVE; + ScramblingMode mode = ScramblingMode::DVB_CSA1; + mCasListener->testStatusUpdate(mMediaCas, &sessionId, intent, mode); + + uint8_t clearKeyEmmData[] = {'c', 'l', 'e', 'a', 'r', 'k', 'e', 'y', 'e', 'm', 'm'}; + hidl_vec hidlClearKeyEmm; + hidlClearKeyEmm.setToExternal(static_cast(clearKeyEmmData), sizeof(clearKeyEmmData)); + returnStatus = mMediaCas->processEmm(hidlClearKeyEmm); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + hidl_vec hidlEcm; + hidlEcm.setToExternal(const_cast(kEcmBinaryBuffer), sizeof(kEcmBinaryBuffer)); + returnStatus = mMediaCas->processEcm(sessionId, hidlEcm); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + returnStatus = mMediaCas->processEcm(streamSessionId, hidlEcm); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + EXPECT_FALSE(mDescramblerBase->requiresSecureDecoderComponent("video/avc")); + + sp descrambler; + descrambler = IDescrambler::castFrom(mDescramblerBase); + ASSERT_NE(descrambler, nullptr); + + Status descrambleStatus = Status::OK; + sp dataMemory; + + ASSERT_TRUE(descrambleTestInputBuffer(descrambler, &descrambleStatus, &dataMemory)); + EXPECT_EQ(Status::OK, descrambleStatus); + + ASSERT_NE(nullptr, dataMemory.get()); + uint8_t* opBuffer = static_cast(static_cast(dataMemory->unsecurePointer())); + + int compareResult = + memcmp(static_cast(opBuffer), + static_cast(kOutRefBinaryBuffer), sizeof(kOutRefBinaryBuffer)); + EXPECT_EQ(0, compareResult); + + returnStatus = mDescramblerBase->release(); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + returnStatus = mMediaCas->release(); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); +} + +} // anonymous namespace + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + CasHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} From 07b442e96ce65509351ab8b6ca9289cde3962803 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Tue, 22 Oct 2019 12:08:47 -0700 Subject: [PATCH 0208/1022] MH2 | Write processedEvents instead of original events. Fix bug where the HalProxyCallback::postEvents method was passing the unaltered events vector to HalProxy::postEventsToMessageQueue instead of the processedEvents with altered sensorHandles. Add a unit test to test that the proper sensorHandles are seen compared to the event posted from subhal. Additionally, fix problems with fake subhals and their dummy sensors that allows VTS tests to pass all tests. Bug: 136511617 Test: New unit tests pass and VTS tests under module VtsHalSensorsV2_0Target passing. Change-Id: If30da03a2399666700844523cd1104b07f6b65d2 --- sensors/2.0/multihal/HalProxy.cpp | 19 +- sensors/2.0/multihal/tests/Android.bp | 2 + sensors/2.0/multihal/tests/HalProxy_test.cpp | 32 ++++ .../2.0/multihal/tests/fake_subhal/Sensor.cpp | 180 ++++++++---------- .../2.0/multihal/tests/fake_subhal/Sensor.h | 51 +++-- .../tests/fake_subhal/SensorsSubHal.cpp | 4 +- 6 files changed, 154 insertions(+), 134 deletions(-) diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index b78806ab6b..49c5a0d412 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -330,7 +330,7 @@ Return HalProxy::onDynamicSensorsConnected(const hidl_vec& dyn Return HalProxy::onDynamicSensorsDisconnected( const hidl_vec& dynamicSensorHandlesRemoved, int32_t subHalIndex) { - // TODO: Block this call until all pending events are flushed from queue + // TODO(b/143302327): Block this call until all pending events are flushed from queue std::vector sensorHandles; { std::lock_guard lock(mDynamicSensorsMutex); @@ -457,7 +457,8 @@ void HalProxy::startPendingWritesThread(HalProxy* halProxy) { } void HalProxy::handlePendingWrites() { - // TODO: Find a way to optimize locking strategy maybe using two mutexes instead of one. + // TODO(b/143302327): Find a way to optimize locking strategy maybe using two mutexes instead of + // one. std::unique_lock lock(mEventQueueWriteMutex); while (mThreadsRun.load()) { mEventQueueWriteCV.wait( @@ -485,8 +486,8 @@ void HalProxy::handlePendingWrites() { } lock.lock(); if (pendingWriteEvents.size() > eventQueueSize) { - // TODO: Check if this erase operation is too inefficient. It will copy all the - // events ahead of it down to fill gap off array at front after the erase. + // TODO(b/143302327): Check if this erase operation is too inefficient. It will copy + // all the events ahead of it down to fill gap off array at front after the erase. pendingWriteEvents.erase(pendingWriteEvents.begin(), pendingWriteEvents.begin() + eventQueueSize); } else { @@ -554,8 +555,8 @@ void HalProxy::postEventsToMessageQueue(const std::vector& events, size_t numToWrite = std::min(events.size(), mEventQueue->availableToWrite()); if (numToWrite > 0) { if (mEventQueue->write(events.data(), numToWrite)) { - // TODO: While loop if mEventQueue->avaiableToWrite > 0 to possibly fit in more - // writes immediately + // TODO(b/143302327): While loop if mEventQueue->avaiableToWrite > 0 to possibly fit + // in more writes immediately mEventQueueFlag->wake(static_cast(EventQueueFlagBits::READ_AND_PROCESS)); } else { numToWrite = 0; @@ -563,8 +564,8 @@ void HalProxy::postEventsToMessageQueue(const std::vector& events, size_t } } if (numToWrite < events.size()) { - // TODO: Bound the mPendingWriteEventsQueue so that we do not trigger OOMs if framework - // stalls + // TODO(b/143302327): Bound the mPendingWriteEventsQueue so that we do not trigger OOMs if + // framework stalls std::vector eventsLeft(events.begin() + numToWrite, events.end()); mPendingWriteEventsQueue.push({eventsLeft, numWakeupEvents}); mEventQueueWriteCV.notify_one(); @@ -655,7 +656,7 @@ void HalProxyCallback::postEvents(const std::vector& events, ScopedWakelo " w/ index %zu.", mSubHalIndex); } - mHalProxy->postEventsToMessageQueue(events, numWakeupEvents, std::move(wakelock)); + mHalProxy->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock)); } ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) { diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp index 50a55f946e..e7f9499db0 100644 --- a/sensors/2.0/multihal/tests/Android.bp +++ b/sensors/2.0/multihal/tests/Android.bp @@ -27,6 +27,7 @@ cc_defaults { "android.hardware.sensors@2.0", "libcutils", "libfmq", + "libhardware", "libhidlbase", "liblog", "libpower", @@ -85,6 +86,7 @@ cc_test { "libbase", "libcutils", "libfmq", + "libhardware", "libhidlbase", "liblog", "libpower", diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp index 75a4c22d11..1fd35d1afb 100644 --- a/sensors/2.0/multihal/tests/HalProxy_test.cpp +++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp @@ -692,6 +692,38 @@ TEST(HalProxyTest, InvalidSensorHandleSubHalIndexProxyCalls) { EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE); } +TEST(HalProxyTest, PostedEventSensorHandleSubHalIndexValid) { + constexpr size_t kQueueSize = 5; + constexpr int32_t subhal1Index = 0; + constexpr int32_t subhal2Index = 1; + AllSensorsSubHal subhal1; + AllSensorsSubHal subhal2; + std::vector subHals{&subhal1, &subhal2}; + + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); + ::android::sp callback = new SensorsCallback(); + HalProxy proxy(subHals); + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + + int32_t sensorHandleToPost = 0x00000001; + Event eventIn = makeAccelerometerEvent(); + eventIn.sensorHandle = sensorHandleToPost; + std::vector eventsToPost{eventIn}; + subhal1.postEvents(eventsToPost, false); + + Event eventOut; + EXPECT_TRUE(eventQueue->read(&eventOut)); + + EXPECT_EQ(eventOut.sensorHandle, (subhal1Index << 24) | sensorHandleToPost); + + subhal2.postEvents(eventsToPost, false); + + EXPECT_TRUE(eventQueue->read(&eventOut)); + + EXPECT_EQ(eventOut.sensorHandle, (subhal2Index << 24) | sensorHandleToPost); +} + // Helper implementations follow void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, const std::vector& subHalSensorsList) { diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp b/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp index 4d536653a9..de89a00ef9 100644 --- a/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp +++ b/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp @@ -16,6 +16,7 @@ #include "Sensor.h" +#include #include #include @@ -31,14 +32,21 @@ using ::android::hardware::sensors::V1_0::MetaDataEventType; using ::android::hardware::sensors::V1_0::SensorFlagBits; using ::android::hardware::sensors::V1_0::SensorStatus; -static constexpr float kDefaultMaxDelayUs = 10 * 1000 * 1000; - -Sensor::Sensor(ISensorsEventCallback* callback) +Sensor::Sensor(int32_t sensorHandle, ISensorsEventCallback* callback) : mIsEnabled(false), mSamplingPeriodNs(0), mLastSampleTimeNs(0), mCallback(callback), mMode(OperationMode::NORMAL) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + constexpr float kDefaultMaxDelayUs = 1000 * 1000; + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = 0; mRunThread = std::thread(startThread, this); } @@ -171,8 +179,10 @@ Result Sensor::injectEvent(const Event& event) { return result; } -OnChangeSensor::OnChangeSensor(ISensorsEventCallback* callback) - : Sensor(callback), mPreviousEventSet(false) {} +OnChangeSensor::OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : Sensor(sensorHandle, callback), mPreviousEventSet(false) { + mSensorInfo.flags |= SensorFlagBits::ON_CHANGE_MODE; +} void OnChangeSensor::activate(bool enable) { Sensor::activate(enable); @@ -196,175 +206,139 @@ std::vector OnChangeSensor::readEvents() { return outputEvents; } -AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) { - mSensorInfo.sensorHandle = sensorHandle; +ContinuousSensor::ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : Sensor(sensorHandle, callback) { + mSensorInfo.flags |= SensorFlagBits::CONTINUOUS_MODE; +} + +AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : ContinuousSensor(sensorHandle, callback) { mSensorInfo.name = "Accel Sensor"; - mSensorInfo.vendor = "Vendor String"; - mSensorInfo.version = 1; mSensorInfo.type = SensorType::ACCELEROMETER; - mSensorInfo.typeAsString = ""; + mSensorInfo.typeAsString = SENSOR_STRING_TYPE_ACCELEROMETER; mSensorInfo.maxRange = 78.4f; // +/- 8g mSensorInfo.resolution = 1.52e-5; mSensorInfo.power = 0.001f; // mA mSensorInfo.minDelay = 20 * 1000; // microseconds - mSensorInfo.maxDelay = kDefaultMaxDelayUs; - mSensorInfo.fifoReservedEventCount = 0; - mSensorInfo.fifoMaxEventCount = 0; - mSensorInfo.requiredPermission = ""; - mSensorInfo.flags = static_cast(SensorFlagBits::DATA_INJECTION); -}; + mSensorInfo.flags |= SensorFlagBits::DATA_INJECTION; +} + +std::vector AccelSensor::readEvents() { + std::vector events; + Event event; + event.sensorHandle = mSensorInfo.sensorHandle; + event.sensorType = mSensorInfo.type; + event.timestamp = ::android::elapsedRealtimeNano(); + event.u.vec3.x = 0; + event.u.vec3.y = 0; + event.u.vec3.z = -9.815; + event.u.vec3.status = SensorStatus::ACCURACY_HIGH; + events.push_back(event); + return events; +} PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : Sensor(callback) { - mSensorInfo.sensorHandle = sensorHandle; + : ContinuousSensor(sensorHandle, callback) { mSensorInfo.name = "Pressure Sensor"; - mSensorInfo.vendor = "Vendor String"; - mSensorInfo.version = 1; mSensorInfo.type = SensorType::PRESSURE; - mSensorInfo.typeAsString = ""; + mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PRESSURE; mSensorInfo.maxRange = 1100.0f; // hPa mSensorInfo.resolution = 0.005f; // hPa mSensorInfo.power = 0.001f; // mA mSensorInfo.minDelay = 100 * 1000; // microseconds - mSensorInfo.maxDelay = kDefaultMaxDelayUs; - mSensorInfo.fifoReservedEventCount = 0; - mSensorInfo.fifoMaxEventCount = 0; - mSensorInfo.requiredPermission = ""; - mSensorInfo.flags = 0; -}; +} MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : Sensor(callback) { - mSensorInfo.sensorHandle = sensorHandle; + : ContinuousSensor(sensorHandle, callback) { mSensorInfo.name = "Magnetic Field Sensor"; - mSensorInfo.vendor = "Vendor String"; - mSensorInfo.version = 1; mSensorInfo.type = SensorType::MAGNETIC_FIELD; - mSensorInfo.typeAsString = ""; + mSensorInfo.typeAsString = SENSOR_STRING_TYPE_MAGNETIC_FIELD; mSensorInfo.maxRange = 1300.0f; mSensorInfo.resolution = 0.01f; mSensorInfo.power = 0.001f; // mA mSensorInfo.minDelay = 20 * 1000; // microseconds - mSensorInfo.maxDelay = kDefaultMaxDelayUs; - mSensorInfo.fifoReservedEventCount = 0; - mSensorInfo.fifoMaxEventCount = 0; - mSensorInfo.requiredPermission = ""; - mSensorInfo.flags = 0; -}; +} LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : OnChangeSensor(callback) { - mSensorInfo.sensorHandle = sensorHandle; + : OnChangeSensor(sensorHandle, callback) { mSensorInfo.name = "Light Sensor"; - mSensorInfo.vendor = "Vendor String"; - mSensorInfo.version = 1; mSensorInfo.type = SensorType::LIGHT; - mSensorInfo.typeAsString = ""; + mSensorInfo.typeAsString = SENSOR_STRING_TYPE_LIGHT; mSensorInfo.maxRange = 43000.0f; mSensorInfo.resolution = 10.0f; mSensorInfo.power = 0.001f; // mA mSensorInfo.minDelay = 200 * 1000; // microseconds - mSensorInfo.maxDelay = kDefaultMaxDelayUs; - mSensorInfo.fifoReservedEventCount = 0; - mSensorInfo.fifoMaxEventCount = 0; - mSensorInfo.requiredPermission = ""; - mSensorInfo.flags = static_cast(SensorFlagBits::ON_CHANGE_MODE); -}; +} ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : OnChangeSensor(callback) { - mSensorInfo.sensorHandle = sensorHandle; + : OnChangeSensor(sensorHandle, callback) { mSensorInfo.name = "Proximity Sensor"; - mSensorInfo.vendor = "Vendor String"; - mSensorInfo.version = 1; mSensorInfo.type = SensorType::PROXIMITY; - mSensorInfo.typeAsString = ""; + mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PROXIMITY; mSensorInfo.maxRange = 5.0f; mSensorInfo.resolution = 1.0f; mSensorInfo.power = 0.012f; // mA mSensorInfo.minDelay = 200 * 1000; // microseconds - mSensorInfo.maxDelay = kDefaultMaxDelayUs; - mSensorInfo.fifoReservedEventCount = 0; - mSensorInfo.fifoMaxEventCount = 0; - mSensorInfo.requiredPermission = ""; - mSensorInfo.flags = - static_cast(SensorFlagBits::ON_CHANGE_MODE | SensorFlagBits::WAKE_UP); -}; + mSensorInfo.flags |= SensorFlagBits::WAKE_UP; +} -GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) { - mSensorInfo.sensorHandle = sensorHandle; +GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : ContinuousSensor(sensorHandle, callback) { mSensorInfo.name = "Gyro Sensor"; - mSensorInfo.vendor = "Vendor String"; - mSensorInfo.version = 1; mSensorInfo.type = SensorType::GYROSCOPE; - mSensorInfo.typeAsString = ""; + mSensorInfo.typeAsString = SENSOR_STRING_TYPE_GYROSCOPE; mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f; mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f); mSensorInfo.power = 0.001f; mSensorInfo.minDelay = 2.5f * 1000; // microseconds - mSensorInfo.maxDelay = kDefaultMaxDelayUs; - mSensorInfo.fifoReservedEventCount = 0; - mSensorInfo.fifoMaxEventCount = 0; - mSensorInfo.requiredPermission = ""; - mSensorInfo.flags = 0; -}; +} + +std::vector GyroSensor::readEvents() { + std::vector events; + Event event; + event.sensorHandle = mSensorInfo.sensorHandle; + event.sensorType = mSensorInfo.type; + event.timestamp = ::android::elapsedRealtimeNano(); + event.u.vec3.x = 0; + event.u.vec3.y = 0; + event.u.vec3.z = 0; + event.u.vec3.status = SensorStatus::ACCURACY_HIGH; + events.push_back(event); + return events; +} AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : OnChangeSensor(callback) { - mSensorInfo.sensorHandle = sensorHandle; + : OnChangeSensor(sensorHandle, callback) { mSensorInfo.name = "Ambient Temp Sensor"; - mSensorInfo.vendor = "Vendor String"; - mSensorInfo.version = 1; mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE; - mSensorInfo.typeAsString = ""; + mSensorInfo.typeAsString = SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE; mSensorInfo.maxRange = 80.0f; mSensorInfo.resolution = 0.01f; mSensorInfo.power = 0.001f; mSensorInfo.minDelay = 40 * 1000; // microseconds - mSensorInfo.maxDelay = kDefaultMaxDelayUs; - mSensorInfo.fifoReservedEventCount = 0; - mSensorInfo.fifoMaxEventCount = 0; - mSensorInfo.requiredPermission = ""; - mSensorInfo.flags = static_cast(SensorFlagBits::ON_CHANGE_MODE); -}; +} DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : OnChangeSensor(callback) { - mSensorInfo.sensorHandle = sensorHandle; + : ContinuousSensor(sensorHandle, callback) { mSensorInfo.name = "Device Temp Sensor"; - mSensorInfo.vendor = "Vendor String"; - mSensorInfo.version = 1; mSensorInfo.type = SensorType::TEMPERATURE; - mSensorInfo.typeAsString = ""; + mSensorInfo.typeAsString = SENSOR_STRING_TYPE_TEMPERATURE; mSensorInfo.maxRange = 80.0f; mSensorInfo.resolution = 0.01f; mSensorInfo.power = 0.001f; mSensorInfo.minDelay = 40 * 1000; // microseconds - mSensorInfo.maxDelay = kDefaultMaxDelayUs; - mSensorInfo.fifoReservedEventCount = 0; - mSensorInfo.fifoMaxEventCount = 0; - mSensorInfo.requiredPermission = ""; - mSensorInfo.flags = static_cast(SensorFlagBits::ON_CHANGE_MODE); } RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : OnChangeSensor(callback) { - mSensorInfo.sensorHandle = sensorHandle; + : OnChangeSensor(sensorHandle, callback) { mSensorInfo.name = "Relative Humidity Sensor"; - mSensorInfo.vendor = "Vendor String"; - mSensorInfo.version = 1; mSensorInfo.type = SensorType::RELATIVE_HUMIDITY; - mSensorInfo.typeAsString = ""; + mSensorInfo.typeAsString = SENSOR_STRING_TYPE_RELATIVE_HUMIDITY; mSensorInfo.maxRange = 100.0f; mSensorInfo.resolution = 0.1f; mSensorInfo.power = 0.001f; mSensorInfo.minDelay = 40 * 1000; // microseconds - mSensorInfo.maxDelay = kDefaultMaxDelayUs; - mSensorInfo.fifoReservedEventCount = 0; - mSensorInfo.fifoMaxEventCount = 0; - mSensorInfo.requiredPermission = ""; - mSensorInfo.flags = static_cast(SensorFlagBits::ON_CHANGE_MODE); } } // namespace implementation diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.h b/sensors/2.0/multihal/tests/fake_subhal/Sensor.h index 980ea54559..60f5d3d40a 100644 --- a/sensors/2.0/multihal/tests/fake_subhal/Sensor.h +++ b/sensors/2.0/multihal/tests/fake_subhal/Sensor.h @@ -45,7 +45,7 @@ class ISensorsEventCallback { class Sensor { public: - Sensor(ISensorsEventCallback* callback); + Sensor(int32_t sensorHandle, ISensorsEventCallback* callback); virtual ~Sensor(); const SensorInfo& getSensorInfo() const; @@ -81,7 +81,7 @@ class Sensor { class OnChangeSensor : public Sensor { public: - OnChangeSensor(ISensorsEventCallback* callback); + OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback); virtual void activate(bool enable) override; @@ -93,14 +93,40 @@ class OnChangeSensor : public Sensor { bool mPreviousEventSet; }; -class AccelSensor : public Sensor { +class ContinuousSensor : public Sensor { public: - AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback); + ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback); }; -class GyroSensor : public Sensor { +class AccelSensor : public ContinuousSensor { + public: + AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback); + + protected: + std::vector readEvents() override; +}; + +class GyroSensor : public ContinuousSensor { public: GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback); + + protected: + std::vector readEvents() override; +}; + +class DeviceTempSensor : public ContinuousSensor { + public: + DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class PressureSensor : public ContinuousSensor { + public: + PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class MagnetometerSensor : public ContinuousSensor { + public: + MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback); }; class AmbientTempSensor : public OnChangeSensor { @@ -108,21 +134,6 @@ class AmbientTempSensor : public OnChangeSensor { AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback); }; -class DeviceTempSensor : public OnChangeSensor { - public: - DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback); -}; - -class PressureSensor : public Sensor { - public: - PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback); -}; - -class MagnetometerSensor : public Sensor { - public: - MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback); -}; - class LightSensor : public OnChangeSensor { public: LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback); diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp index 0da424622f..ff5ff38541 100644 --- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp +++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp @@ -172,11 +172,11 @@ ContinuousSensorsSubHal::ContinuousSensorsSubHal() { AddSensor(); AddSensor(); AddSensor(); + AddSensor(); } OnChangeSensorsSubHal::OnChangeSensorsSubHal() { AddSensor(); - AddSensor(); AddSensor(); AddSensor(); AddSensor(); @@ -187,8 +187,8 @@ AllSensorsSubHal::AllSensorsSubHal() { AddSensor(); AddSensor(); AddSensor(); - AddSensor(); AddSensor(); + AddSensor(); AddSensor(); AddSensor(); AddSensor(); From 8613f809fafd37d2d389989e1de05c670968e392 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 18 Oct 2019 13:09:35 -0700 Subject: [PATCH 0209/1022] audio: Parametrize core VTS tests Parametrize tests to accept IDevicesFactory instance name and IDevice instance name. For audio HAL versions 2..5 the factory instance name is taken from the VTS environment, and the device is always "primary". For the next versions the factories are discovered by the test, and the devices are taken from the audio policy configuration (to be implemented, see added FIXME comments). Split the Environment class into two versions: for HAL 2..5 and for next versions. They use different base class. Move device factories and device caching into dedicated classes DevicesFactoryManager and DeviceManager. They deal with instance caching and proper release of server resources. Bug: 141847510 Bug: 141989952 Test: atest VtsHalAudioV5_0TargetTest atest VtsHalAudioV6_0TargetTest Change-Id: I92c44e0c3f900164dded7e9c4bfc642ca2c335db --- .../include/utility/EnvironmentTearDown.h | 13 +- .../2.0/AudioPrimaryHidlHalTest.cpp | 9 +- .../vts/functional/2.0/EnvironmentTearDown.h | 34 ++ .../4.0/AudioPrimaryHidlHalTest.cpp | 71 ++- .../vts/functional/6.0/EnvironmentTearDown.h | 35 ++ .../vts/functional/AudioPrimaryHidlHalTest.h | 434 ++++++++++++------ .../vts/functional/DeviceManager.h | 143 ++++++ 7 files changed, 537 insertions(+), 202 deletions(-) create mode 100644 audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h create mode 100644 audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h create mode 100644 audio/core/all-versions/vts/functional/DeviceManager.h diff --git a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h index 0e416f3c64..2b240ce309 100644 --- a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h +++ b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h @@ -20,9 +20,6 @@ #include #include -#include -#include - namespace android { namespace hardware { namespace audio { @@ -34,18 +31,20 @@ namespace utility { * Avoid destroying static objects after main return. * Post main return destruction leads to incorrect gtest timing measurements as * well as harder debuging if anything goes wrong during destruction. */ -class Environment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: +class EnvironmentTearDown { + public: using TearDownFunc = std::function; void registerTearDown(TearDownFunc&& tearDown) { tearDowns.push_front(std::move(tearDown)); } - private: - void HidlTearDown() override { + protected: + void executeAllTearDowns() { // Call the tear downs in reverse order of insertion for (auto& tearDown : tearDowns) { tearDown(); } } + + private: std::list tearDowns; }; diff --git a/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp index 7906bf1b62..c1894645fd 100644 --- a/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp @@ -60,19 +60,20 @@ TEST_IO_STREAM(SetConnectedState, "deconnection", testConnectedState(stream.get())) -TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", ASSERT_IS_OK(device->getHwAvSync())); +TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", + ASSERT_IS_OK(getDevice()->getHwAvSync())); -TEST_F(AudioPrimaryHidlTest, setMode) { +TEST_P(AudioPrimaryHidlTest, setMode) { doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise"); // Test Invalid values for (AudioMode mode : {AudioMode::INVALID, AudioMode::CURRENT, AudioMode::CNT}) { SCOPED_TRACE("mode=" + toString(mode)); - ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(mode)); + ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(mode)); } // Test valid values for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE, AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) { SCOPED_TRACE("mode=" + toString(mode)); - ASSERT_OK(device->setMode(mode)); + ASSERT_OK(getDevice()->setMode(mode)); } } diff --git a/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h b/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h new file mode 100644 index 0000000000..6373e39111 --- /dev/null +++ b/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H +#define ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H + +#include +#include + +#include "utility/EnvironmentTearDown.h" + +class Environment : public ::android::hardware::audio::common::test::utility::EnvironmentTearDown, + public ::testing::VtsHalHidlTargetTestEnvBase { + private: + void HidlTearDown() override { + executeAllTearDowns(); + VtsHalHidlTargetTestEnvBase::HidlTearDown(); + } +}; + +#endif // ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp index 15be3bf470..b8defb620a 100644 --- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp @@ -16,25 +16,14 @@ #include "AudioPrimaryHidlHalTest.h" -static void waitForDeviceDestruction() { - // FIXME: there is no way to know when the remote IDevice is being destroyed - // Binder does not support testing if an object is alive, thus - // wait for 100ms to let the binder destruction propagates and - // the remote device has the time to be destroyed. - // flushCommand makes sure all local command are sent, thus should reduce - // the latency between local and remote destruction. - IPCThreadState::self()->flushCommands(); - usleep(100 * 1000); -} - -TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) { +TEST_P(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) { doc::test("Calling openDevice(\"primary\") should return the primary device."); struct WaitExecutor { - ~WaitExecutor() { waitForDeviceDestruction(); } + ~WaitExecutor() { DeviceManager::waitForInstanceDestruction(); } } waitExecutor; // Make sure we wait for the device destruction on exiting from the test. Result result; sp baseDevice; - ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice))); + ASSERT_OK(getDevicesFactory()->openDevice("primary", returnIn(result, baseDevice))); if (result != Result::OK && isPrimaryDeviceOptional()) { GTEST_SKIP() << "No primary device on this factory"; // returns } @@ -50,10 +39,10 @@ TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) { /////////////////////////// get(Active)Microphones /////////////////////////// ////////////////////////////////////////////////////////////////////////////// -TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) { +TEST_P(AudioPrimaryHidlTest, GetMicrophonesTest) { doc::test("Make sure getMicrophones always succeeds"); hidl_vec microphones; - ASSERT_OK(device->getMicrophones(returnIn(res, microphones))); + ASSERT_OK(getDevice()->getMicrophones(returnIn(res, microphones))); ASSERT_OK(res); if (microphones.size() > 0) { // When there is microphone on the phone, try to open an input stream @@ -75,15 +64,15 @@ TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) { } sp stream; AudioConfig suggestedConfig{}; - ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress, config, flags, - initMetadata, - returnIn(res, stream, suggestedConfig))); + ASSERT_OK(getDevice()->openInputStream(ioHandle, microphone.deviceAddress, config, + flags, initMetadata, + returnIn(res, stream, suggestedConfig))); if (res != Result::OK) { ASSERT_TRUE(stream == nullptr); AudioConfig suggestedConfigRetry{}; - ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress, - suggestedConfig, flags, initMetadata, - returnIn(res, stream, suggestedConfigRetry))); + ASSERT_OK(getDevice()->openInputStream( + ioHandle, microphone.deviceAddress, suggestedConfig, flags, initMetadata, + returnIn(res, stream, suggestedConfigRetry))); } ASSERT_OK(res); hidl_vec activeMicrophones; @@ -131,7 +120,7 @@ TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) { } } -TEST_F(AudioPrimaryHidlTest, SetConnectedState) { +TEST_P(AudioPrimaryHidlTest, SetConnectedState) { doc::test("Check that the HAL can be notified of device connection and deconnection"); using AD = AudioDevice; for (auto deviceType : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) { @@ -140,7 +129,7 @@ TEST_F(AudioPrimaryHidlTest, SetConnectedState) { SCOPED_TRACE("state=" + ::testing::PrintToString(state)); DeviceAddress address = {}; address.device = deviceType; - auto ret = device->setConnectedState(address, state); + auto ret = getDevice()->setConnectedState(address, state); ASSERT_TRUE(ret.isOk()); if (ret == Result::NOT_SUPPORTED) { doc::partialTest("setConnectedState is not supported"); @@ -153,9 +142,7 @@ TEST_F(AudioPrimaryHidlTest, SetConnectedState) { // Because there is no way of knowing if the devices were connected before // calling setConnectedState, there is no way to restore the HAL to its // initial state. To workaround this, destroy the HAL at the end of this test. - device.clear(); - waitForDeviceDestruction(); - ASSERT_NO_FATAL_FAILURE(initPrimaryDevice()); + ASSERT_TRUE(DeviceManager::getInstance().resetPrimary(getFactoryName())); } static void testGetDevices(IStream* stream, AudioDevice expectedDevice) { @@ -199,7 +186,7 @@ static void checkGetHwAVSync(IDevice* device) { } ASSERT_OK(res); } -TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(device.get())); +TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(getDevice().get())); TEST_P(InputStreamTest, updateSinkMetadata) { doc::test("The HAL should not crash on metadata change"); @@ -259,58 +246,58 @@ TEST_P(OutputStreamTest, updateSourceMetadata) { ASSERT_OK(stream->updateSourceMetadata(initMetadata)); } -TEST_F(AudioPrimaryHidlTest, setMode) { +TEST_P(AudioPrimaryHidlTest, setMode) { doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise"); // Test Invalid values for (int mode : {-2, -1, int(AudioMode::IN_COMMUNICATION) + 1}) { - ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(AudioMode(mode))) - << "mode=" << mode; + ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(AudioMode(mode))) + << "mode=" << mode; } // Test valid values for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE, AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) { - ASSERT_OK(device->setMode(mode)) << "mode=" << toString(mode); + ASSERT_OK(getDevice()->setMode(mode)) << "mode=" << toString(mode); } } -TEST_F(AudioPrimaryHidlTest, setBtHfpSampleRate) { +TEST_P(AudioPrimaryHidlTest, setBtHfpSampleRate) { doc::test( "Make sure setBtHfpSampleRate either succeeds or " "indicates that it is not supported at all, or that the provided value is invalid"); for (auto samplingRate : {8000, 16000, 22050, 24000}) { - ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, device->setBtHfpSampleRate(samplingRate)); + ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, getDevice()->setBtHfpSampleRate(samplingRate)); } } -TEST_F(AudioPrimaryHidlTest, setBtHfpVolume) { +TEST_P(AudioPrimaryHidlTest, setBtHfpVolume) { doc::test( "Make sure setBtHfpVolume is either not supported or " "only succeed if volume is in [0,1]"); - auto ret = device->setBtHfpVolume(0.0); + auto ret = getDevice()->setBtHfpVolume(0.0); ASSERT_TRUE(ret.isOk()); if (ret == Result::NOT_SUPPORTED) { doc::partialTest("setBtHfpVolume is not supported"); return; } - testUnitaryGain([](float volume) { return device->setBtHfpVolume(volume); }); + testUnitaryGain([this](float volume) { return getDevice()->setBtHfpVolume(volume); }); } -TEST_F(AudioPrimaryHidlTest, setBtScoHeadsetDebugName) { +TEST_P(AudioPrimaryHidlTest, setBtScoHeadsetDebugName) { doc::test( "Make sure setBtScoHeadsetDebugName either succeeds or " "indicates that it is not supported"); - ASSERT_RESULT(okOrNotSupported, device->setBtScoHeadsetDebugName("test")); + ASSERT_RESULT(okOrNotSupported, getDevice()->setBtScoHeadsetDebugName("test")); } -TEST_F(AudioPrimaryHidlTest, updateRotation) { +TEST_P(AudioPrimaryHidlTest, updateRotation) { doc::test("Check that the hal can receive the current rotation"); for (Rotation rotation : {Rotation::DEG_0, Rotation::DEG_90, Rotation::DEG_180, Rotation::DEG_270, Rotation::DEG_0}) { - ASSERT_RESULT(okOrNotSupported, device->updateRotation(rotation)); + ASSERT_RESULT(okOrNotSupported, getDevice()->updateRotation(rotation)); } } -TEST_F(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) { +TEST_P(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) { doc::test("Query and set the BT HFP state"); testAccessors("BtHfpEnabled", Initial{false, OPTIONAL}, {true}, &IPrimaryDevice::setBtHfpEnabled, &IPrimaryDevice::getBtHfpEnabled); diff --git a/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h b/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h new file mode 100644 index 0000000000..593759f17c --- /dev/null +++ b/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H +#define ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H + +#include + +#include "utility/EnvironmentTearDown.h" + +class Environment : public ::android::hardware::audio::common::test::utility::EnvironmentTearDown, + public ::testing::Environment { + public: + void init(int* /*argc*/, char** /*argv*/) {} // emulate VtsHalHidlTargetTestEnvBase + private: + void TearDown() override { executeAllTearDowns(); } +}; + +// FIXME: Will be removed while making getDeviceParameters to use the config +static constexpr const char* kDefaultServiceName = "default"; + +#endif // ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h index 6c51c1ba7f..e59ab9855e 100644 --- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -31,7 +32,9 @@ #include +#if MAJOR_VERSION <= 5 #include +#endif #include @@ -44,16 +47,25 @@ #include #include #include +#if MAJOR_VERSION >= 6 +#include +#include +#endif #include #include "utility/AssertOk.h" #include "utility/Documentation.h" -#include "utility/EnvironmentTearDown.h" #include "utility/PrettyPrintAudioTypes.h" #include "utility/ReturnIn.h" #include "utility/ValidateXml.h" +#if MAJOR_VERSION <= 5 +#include "2.0/EnvironmentTearDown.h" +#elif MAJOR_VERSION >= 6 +#include "6.0/EnvironmentTearDown.h" +#endif + /** Provide version specific functions that are used in the generic tests */ #if MAJOR_VERSION == 2 #include "2.0/AudioPrimaryHidlHalUtils.h" @@ -105,14 +117,23 @@ static auto invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUP class AudioHidlTestEnvironment : public ::Environment { public: - virtual void registerTestServices() override { registerTestService(); } +#if MAJOR_VERSION <= 5 + void registerTestServices() override { registerTestService(); } +#endif }; // Instance to register global tearDown static AudioHidlTestEnvironment* environment; +#define AUDIO_PRIMARY_HIDL_HAL_TEST +#include "DeviceManager.h" + +#if MAJOR_VERSION <= 5 class HidlTest : public ::testing::VtsHalHidlTargetTestBase { - protected: +#elif MAJOR_VERSION >= 6 +class HidlTest : public ::testing::Test { +#endif + protected: // Convenient member to store results Result res; }; @@ -201,6 +222,21 @@ class AudioPolicyConfigTest : public HidlTest { ASSERT_TRUE(mPrimaryConfig) << "Could not find primary module in configuration file: " << policyConfig.getFilePath(); } + + protected: + sp getDevicesFactory(const std::string& factoryName) const { + return DevicesFactoryManager::getInstance().get(factoryName); + } + + sp getPrimaryDevice(const std::string& factoryName) const { + return DeviceManager::getInstance().getPrimary(factoryName); + } + + bool isPrimaryDeviceOptional(const std::string& factoryName) const { + // It's OK not to have "primary" device on non-default audio HAL service. + return factoryName != kDefaultServiceName; + } + sp mPrimaryConfig = nullptr; }; @@ -208,42 +244,86 @@ TEST_F(AudioPolicyConfigTest, LoadAudioPolicyXMLConfiguration) { doc::test("Test parsing audio_policy_configuration.xml (called in SetUp)"); } +////////////////////////////////////////////////////////////////////////////// +//////////////////// Test parameter types and definitions //////////////////// +////////////////////////////////////////////////////////////////////////////// + +enum { PARAM_FACTORY_NAME, PARAM_DEVICE_NAME }; +using DeviceParameter = std::tuple; + +static inline std::string DeviceParameterToString( + const ::testing::TestParamInfo& info) { +#if MAJOR_VERSION <= 5 + return std::get(info.param); +#elif MAJOR_VERSION >= 6 + const auto factoryName = + ::android::hardware::PrintInstanceNameToString(::testing::TestParamInfo{ + std::get(info.param), info.index}); + const auto& deviceName = std::get(info.param); + return !deviceName.empty() ? factoryName + "_" + deviceName : factoryName; +#endif +} + +#if MAJOR_VERSION <= 5 +// For V2..5 the factory is looked up using the instance name passed +// in the environment, only one factory is returned. This is because the VTS +// framework will call the test for each instance. Only the primary device of +// the factory specified in the environment is tested. +const std::vector& getDeviceParameters() { + static std::vector parameters = { + {environment->getServiceName(), DeviceManager::kPrimaryDevice}}; + return parameters; +} +#elif MAJOR_VERSION >= 6 +// FIXME: Will be replaced with code that analyzes the audio policy config file. +const std::vector& getDeviceParameters() { + static std::vector parameters = [] { + const auto instances = + ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor); + std::vector result; + result.reserve(instances.size()); + for (const auto& instance : instances) { + result.emplace_back(instance, DeviceManager::kPrimaryDevice); + } + return result; + }(); + return parameters; +} +#endif + +class AudioHidlTestWithDeviceParameter : public AudioPolicyConfigTest, + public ::testing::WithParamInterface { + protected: + const std::string& getFactoryName() const { return std::get(GetParam()); } + bool isPrimaryDeviceOptional() const { + return AudioPolicyConfigTest::isPrimaryDeviceOptional(getFactoryName()); + } + sp getDevicesFactory() const { + return AudioPolicyConfigTest::getDevicesFactory(getFactoryName()); + } + sp getPrimaryDevice() const { + return AudioPolicyConfigTest::getPrimaryDevice(getFactoryName()); + } +}; + ////////////////////////////////////////////////////////////////////////////// ////////////////////// getService audio_devices_factory ////////////////////// ////////////////////////////////////////////////////////////////////////////// // Test all audio devices -class AudioHidlTest : public AudioPolicyConfigTest { - public: - static void SetUpTestSuite() { - devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService( - environment->getServiceName()); - } - - static void TearDownTestSuite() { devicesFactory.clear(); } - - void SetUp() override { - ASSERT_NO_FATAL_FAILURE(AudioPolicyConfigTest::SetUp()); // setup base - // Failures during SetUpTestSuite do not cause test termination. - ASSERT_TRUE(devicesFactory != nullptr); - } - - protected: - // Cache the devicesFactory retrieval to speed up each test by ~0.5s - static sp devicesFactory; - - static bool isPrimaryDeviceOptional() { - // It's OK not to have "primary" device on non-default audio HAL service. - return environment->getServiceName() != kDefaultServiceName; +class AudioHidlTest : public AudioHidlTestWithDeviceParameter { + public: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceParameter::SetUp()); // setup base + ASSERT_TRUE(getDevicesFactory() != nullptr); } }; -sp AudioHidlTest::devicesFactory; -TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) { +TEST_P(AudioHidlTest, GetAudioDevicesFactoryService) { doc::test("Test the getService"); } -TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) { +TEST_P(AudioHidlTest, OpenDeviceInvalidParameter) { doc::test("Test passing an invalid parameter to openDevice"); Result result; sp device; @@ -252,11 +332,14 @@ TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) { #elif MAJOR_VERSION >= 4 auto invalidDevice = "Non existing device"; #endif - ASSERT_OK(devicesFactory->openDevice(invalidDevice, returnIn(result, device))); + ASSERT_OK(getDevicesFactory()->openDevice(invalidDevice, returnIn(result, device))); ASSERT_EQ(Result::INVALID_ARGUMENTS, result); ASSERT_TRUE(device == nullptr); } +INSTANTIATE_TEST_CASE_P(AudioHidl, AudioHidlTest, ::testing::ValuesIn(getDeviceParameters()), + &DeviceParameterToString); + ////////////////////////////////////////////////////////////////////////////// /////////////////////////////// openDevice primary /////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -264,57 +347,30 @@ TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) { // Test the primary device class AudioPrimaryHidlTest : public AudioHidlTest { public: - static void SetUpTestSuite() { - ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUpTestSuite()); - ASSERT_NO_FATAL_FAILURE(initPrimaryDevice()); - } - - static void TearDownTestSuite() { - device.clear(); - AudioHidlTest::TearDownTestSuite(); - } - void SetUp() override { ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base - if (device == nullptr && isPrimaryDeviceOptional()) { + if (getDevice() == nullptr && isPrimaryDeviceOptional()) { GTEST_SKIP() << "No primary device on this factory"; } - ASSERT_TRUE(device != nullptr); + ASSERT_TRUE(getDevice() != nullptr); } protected: - // Cache the device opening to speed up each test by ~0.5s - static sp device; - - static void initPrimaryDevice() { - // Failures during test suite set up do not cause test termination. - ASSERT_TRUE(devicesFactory != nullptr); - Result result; -#if MAJOR_VERSION == 2 - sp baseDevice; - ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device::PRIMARY, - returnIn(result, baseDevice))); - ASSERT_OK(result); - ASSERT_TRUE(baseDevice != nullptr); - - device = IPrimaryDevice::castFrom(baseDevice); -#elif MAJOR_VERSION >= 4 - ASSERT_OK(devicesFactory->openPrimaryDevice(returnIn(result, device))); - ASSERT_OK(result); -#endif - } + sp getDevice() const { return getPrimaryDevice(); } }; -sp AudioPrimaryHidlTest::device; -TEST_F(AudioPrimaryHidlTest, OpenPrimaryDevice) { +TEST_P(AudioPrimaryHidlTest, OpenPrimaryDevice) { doc::test("Test the openDevice (called during setup)"); } -TEST_F(AudioPrimaryHidlTest, Init) { +TEST_P(AudioPrimaryHidlTest, Init) { doc::test("Test that the audio primary hal initialized correctly"); - ASSERT_OK(device->initCheck()); + ASSERT_OK(getDevice()->initCheck()); } +INSTANTIATE_TEST_CASE_P(AudioPrimaryHidl, AudioPrimaryHidlTest, + ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); + ////////////////////////////////////////////////////////////////////////////// ///////////////////// {set,get}{Master,Mic}{Mute,Volume} ///////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -339,7 +395,7 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK}; Property initialValue = expectedInitial.value; - ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue))); + ASSERT_OK((getDevice().get()->*getter)(returnIn(res, initialValue))); ASSERT_RESULT(expectedResults, res); if (res == Result::OK && expectedInitial.check == REQUIRED) { EXPECT_EQ(expectedInitial.value, initialValue); @@ -350,7 +406,7 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { for (Property setValue : valuesToTest) { SCOPED_TRACE("Test " + propertyName + " getter and setter for " + testing::PrintToString(setValue)); - auto ret = (device.get()->*setter)(setValue); + auto ret = (getDevice().get()->*setter)(setValue); ASSERT_RESULT(expectedResults, ret); if (ret == Result::NOT_SUPPORTED) { doc::partialTest(propertyName + " setter is not supported"); @@ -358,7 +414,7 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { } Property getValue; // Make sure the getter returns the same value just set - ASSERT_OK((device.get()->*getter)(returnIn(res, getValue))); + ASSERT_OK((getDevice().get()->*getter)(returnIn(res, getValue))); ASSERT_RESULT(expectedResults, res); if (res == Result::NOT_SUPPORTED) { doc::partialTest(propertyName + " getter is not supported"); @@ -370,31 +426,34 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { for (Property invalidValue : invalidValues) { SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " + testing::PrintToString(invalidValue)); - EXPECT_RESULT(invalidArgsOrNotSupported, (device.get()->*setter)(invalidValue)); + EXPECT_RESULT(invalidArgsOrNotSupported, (getDevice().get()->*setter)(invalidValue)); } // Restore initial value - EXPECT_RESULT(expectedResults, (device.get()->*setter)(initialValue)); + EXPECT_RESULT(expectedResults, (getDevice().get()->*setter)(initialValue)); } }; using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; -TEST_F(BoolAccessorPrimaryHidlTest, MicMuteTest) { +TEST_P(BoolAccessorPrimaryHidlTest, MicMuteTest) { doc::test("Check that the mic can be muted and unmuted"); testAccessors("mic mute", Initial{false}, {true}, &IDevice::setMicMute, &IDevice::getMicMute); // TODO: check that the mic is really muted (all sample are 0) } -TEST_F(BoolAccessorPrimaryHidlTest, MasterMuteTest) { +TEST_P(BoolAccessorPrimaryHidlTest, MasterMuteTest) { doc::test("If master mute is supported, try to mute and unmute the master output"); testAccessors("master mute", Initial{false}, {true}, &IDevice::setMasterMute, &IDevice::getMasterMute); // TODO: check that the master volume is really muted } +INSTANTIATE_TEST_CASE_P(BoolAccessorPrimaryHidl, BoolAccessorPrimaryHidlTest, + ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); + using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; -TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) { +TEST_P(FloatAccessorPrimaryHidlTest, MasterVolumeTest) { doc::test("Test the master volume if supported"); testAccessors( "master volume", Initial{1}, {0, 0.5}, &IDevice::setMasterVolume, &IDevice::getMasterVolume, @@ -402,16 +461,19 @@ TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) { // TODO: check that the master volume is really changed } +INSTANTIATE_TEST_CASE_P(FloatAccessorPrimaryHidl, FloatAccessorPrimaryHidlTest, + ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); + ////////////////////////////////////////////////////////////////////////////// //////////////////////////////// AudioPatches //////////////////////////////// ////////////////////////////////////////////////////////////////////////////// class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest { protected: - bool areAudioPatchesSupported() { return extract(device->supportsAudioPatches()); } + bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); } }; -TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) { +TEST_P(AudioPatchPrimaryHidlTest, AudioPatches) { doc::test("Test if audio patches are supported"); if (!areAudioPatchesSupported()) { doc::partialTest("Audio patches are not supported"); @@ -420,6 +482,9 @@ TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) { // TODO: test audio patches } +INSTANTIATE_TEST_CASE_P(AudioPatchPrimaryHidl, AudioPatchPrimaryHidlTest, + ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); + ////////////////////////////////////////////////////////////////////////////// //////////////// Required and recommended audio format support /////////////// // From: @@ -429,8 +494,7 @@ TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) { /////////// TODO: move to the beginning of the file for easier update //////// ////////////////////////////////////////////////////////////////////////////// -class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest { - public: +struct ConfigHelper { // for retro compatibility only test the primary device IN_BUILTIN_MIC // FIXME: in the next audio HAL version, test all available devices static bool primaryHasMic() { @@ -502,21 +566,51 @@ class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest { } }; +// Nesting a tuple in another tuple allows to use GTest Combine function to generate +// all combinations of devices and configs. +enum { PARAM_DEVICE, PARAM_CONFIG }; +using DeviceConfigParameter = std::tuple; + /** Generate a test name based on an audio config. * * As the only parameter changing are channel mask and sample rate, * only print those ones in the test name. */ -static string generateTestName(const testing::TestParamInfo& info) { - const AudioConfig& config = info.param; - return to_string(info.index) + "__" + to_string(config.sampleRateHz) + "_" + +static string DeviceConfigParameterToString( + const testing::TestParamInfo& info) { + const AudioConfig& config = std::get(info.param); + const auto deviceName = DeviceParameterToString(::testing::TestParamInfo{ + std::get(info.param), info.index}); + return (deviceName.empty() ? "" : deviceName + "_") + to_string(info.index) + "__" + + to_string(config.sampleRateHz) + "_" + // "MONO" is more clear than "FRONT_LEFT" ((config.channelMask == mkEnumBitfield(AudioChannelMask::OUT_MONO) || config.channelMask == mkEnumBitfield(AudioChannelMask::IN_MONO)) - ? "MONO" - : ::testing::PrintToString(config.channelMask)); + ? "MONO" + : ::testing::PrintToString(config.channelMask)); } +class AudioHidlTestWithDeviceConfigParameter + : public AudioPolicyConfigTest, + public ::testing::WithParamInterface { + protected: + const std::string& getFactoryName() const { + return std::get(std::get(GetParam())); + } + bool isPrimaryDeviceOptional() const { + return AudioPolicyConfigTest::isPrimaryDeviceOptional(getFactoryName()); + } + sp getDevicesFactory() const { + return AudioPolicyConfigTest::getDevicesFactory(getFactoryName()); + } + sp getPrimaryDevice() const { + return AudioPolicyConfigTest::getPrimaryDevice(getFactoryName()); + } + const AudioConfig& getConfig() const { return std::get(GetParam()); } + // FIXME: Split out tests that don't require primary device + sp getDevice() const { return getPrimaryDevice(); } +}; + ////////////////////////////////////////////////////////////////////////////// ///////////////////////////// getInputBufferSize ///////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -525,12 +619,21 @@ static string generateTestName(const testing::TestParamInfo& info) // android.hardware.microphone // how to get this value ? is it a property ??? -class AudioCaptureConfigPrimaryTest : public AudioConfigPrimaryTest, - public ::testing::WithParamInterface { - protected: +class AudioCaptureConfigPrimaryTest : public AudioHidlTestWithDeviceConfigParameter { + public: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceConfigParameter::SetUp()); // setup base + ASSERT_TRUE(getDevicesFactory() != nullptr); + if (getDevice() == nullptr && isPrimaryDeviceOptional()) { + GTEST_SKIP() << "No primary device on this factory"; + } + ASSERT_TRUE(getDevice() != nullptr); + } + + protected: void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) { uint64_t bufferSize; - ASSERT_OK(device->getInputBufferSize(audioConfig, returnIn(res, bufferSize))); + ASSERT_OK(getDevice()->getInputBufferSize(audioConfig, returnIn(res, bufferSize))); switch (res) { case Result::INVALID_ARGUMENTS: @@ -554,16 +657,19 @@ TEST_P(RequiredInputBufferSizeTest, RequiredInputBufferSizeTest) { doc::test( "Input buffer size must be retrievable for a format with required " "support."); - inputBufferSizeTest(GetParam(), true); + inputBufferSizeTest(getConfig(), true); } INSTANTIATE_TEST_CASE_P( - RequiredInputBufferSize, RequiredInputBufferSizeTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()), - &generateTestName); + RequiredInputBufferSize, RequiredInputBufferSizeTest, + ::testing::Combine( + ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())), + &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( - SupportedInputBufferSize, RequiredInputBufferSizeTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()), - &generateTestName); + SupportedInputBufferSize, RequiredInputBufferSizeTest, + ::testing::Combine(::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig())), + &DeviceConfigParameterToString); // Test that the recommended capture config are supported or lead to a // INVALID_ARGUMENTS return @@ -572,21 +678,23 @@ TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) { doc::test( "Input buffer size should be retrievable for a format with recommended " "support."); - inputBufferSizeTest(GetParam(), false); + inputBufferSizeTest(getConfig(), false); } INSTANTIATE_TEST_CASE_P( - RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()), - &generateTestName); + RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest, + ::testing::Combine( + ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())), + &DeviceConfigParameterToString); ////////////////////////////////////////////////////////////////////////////// /////////////////////////////// setScreenState /////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -TEST_F(AudioPrimaryHidlTest, setScreenState) { +TEST_P(AudioPrimaryHidlTest, setScreenState) { doc::test("Check that the hal can receive the screen state"); for (bool turnedOn : {false, true, true, false, false}) { - ASSERT_RESULT(okOrNotSupported, device->setScreenState(turnedOn)); + ASSERT_RESULT(okOrNotSupported, getDevice()->setScreenState(turnedOn)); } } @@ -594,15 +702,15 @@ TEST_F(AudioPrimaryHidlTest, setScreenState) { //////////////////////////// {get,set}Parameters ///////////////////////////// ////////////////////////////////////////////////////////////////////////////// -TEST_F(AudioPrimaryHidlTest, getParameters) { +TEST_P(AudioPrimaryHidlTest, getParameters) { doc::test("Check that the hal can set and get parameters"); hidl_vec context; hidl_vec keys; hidl_vec values; - ASSERT_OK(Parameters::get(device, keys, returnIn(res, values))); - ASSERT_OK(Parameters::set(device, values)); + ASSERT_OK(Parameters::get(getDevice(), keys, returnIn(res, values))); + ASSERT_OK(Parameters::set(getDevice(), values)); values.resize(0); - ASSERT_OK(Parameters::set(device, values)); + ASSERT_OK(Parameters::set(getDevice(), values)); } ////////////////////////////////////////////////////////////////////////////// @@ -643,14 +751,14 @@ static void testDebugDump(DebugDump debugDump) { EXPECT_EQ(0, close(fds[1])) << errno; } -TEST_F(AudioPrimaryHidlTest, DebugDump) { +TEST_P(AudioPrimaryHidlTest, DebugDump) { doc::test("Check that the hal can dump its state without error"); - testDebugDump([](const auto& handle) { return dump(device, handle); }); + testDebugDump([this](const auto& handle) { return dump(getDevice(), handle); }); } -TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) { +TEST_P(AudioPrimaryHidlTest, DebugDumpInvalidArguments) { doc::test("Check that the hal dump doesn't crash on invalid arguments"); - ASSERT_OK(dump(device, hidl_handle())); + ASSERT_OK(dump(getDevice(), hidl_handle())); } ////////////////////////////////////////////////////////////////////////////// @@ -658,9 +766,17 @@ TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) { ////////////////////////////////////////////////////////////////////////////// template -class OpenStreamTest : public AudioConfigPrimaryTest, - public ::testing::WithParamInterface { - protected: +class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter { + protected: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceConfigParameter::SetUp()); // setup base + ASSERT_TRUE(getDevicesFactory() != nullptr); + if (getDevice() == nullptr && isPrimaryDeviceOptional()) { + GTEST_SKIP() << "No primary device on this factory"; + } + ASSERT_TRUE(getDevice() != nullptr); + } + template void testOpen(Open openStream, const AudioConfig& config) { // FIXME: Open a stream without an IOHandle @@ -701,7 +817,7 @@ class OpenStreamTest : public AudioConfigPrimaryTest, return res; } - void waitForStreamDestruction() { + static void waitForStreamDestruction() { // FIXME: there is no way to know when the remote IStream is being destroyed // Binder does not support testing if an object is alive, thus // wait for 100ms to let the binder destruction propagates and @@ -712,12 +828,14 @@ class OpenStreamTest : public AudioConfigPrimaryTest, usleep(100 * 1000); } - private: + bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); } + + private: void TearDown() override { if (open) { ASSERT_OK(closeStream()); } - AudioConfigPrimaryTest::TearDown(); + AudioPolicyConfigTest::TearDown(); } protected: @@ -734,18 +852,19 @@ class OutputStreamTest : public OpenStreamTest { ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base if (IsSkipped()) return; // do not attempt to use 'device' address.device = AudioDevice::OUT_DEFAULT; - const AudioConfig& config = GetParam(); + const AudioConfig& config = getConfig(); // TODO: test all flag combination auto flags = mkEnumBitfield(AudioOutputFlag::NONE); testOpen( - [&](AudioIoHandle handle, AudioConfig config, auto cb) { + [&](AudioIoHandle handle, AudioConfig config, auto cb) { #if MAJOR_VERSION == 2 - return device->openOutputStream(handle, address, config, flags, cb); + return getDevice()->openOutputStream(handle, address, config, flags, cb); #elif MAJOR_VERSION >= 4 - return device->openOutputStream(handle, address, config, flags, initMetadata, cb); + return getDevice()->openOutputStream(handle, address, config, flags, + initMetadata, cb); #endif - }, - config); + }, + config); } #if MAJOR_VERSION >= 4 @@ -763,18 +882,23 @@ TEST_P(OutputStreamTest, OpenOutputStreamTest) { // Open done in SetUp } INSTANTIATE_TEST_CASE_P( - RequiredOutputStreamConfigSupport, OutputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()), - &generateTestName); + RequiredOutputStreamConfigSupport, OutputStreamTest, + ::testing::Combine( + ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getRequiredSupportPlaybackAudioConfig())), + &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( - SupportedOutputStreamConfig, OutputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()), - &generateTestName); + SupportedOutputStreamConfig, OutputStreamTest, + ::testing::Combine(::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getSupportedPlaybackAudioConfig())), + &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( - RecommendedOutputStreamConfigSupport, OutputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()), - &generateTestName); + RecommendedOutputStreamConfigSupport, OutputStreamTest, + ::testing::Combine( + ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getRecommendedSupportPlaybackAudioConfig())), + &DeviceConfigParameterToString); ////////////////////////////// openInputStream ////////////////////////////// @@ -783,14 +907,15 @@ class InputStreamTest : public OpenStreamTest { ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base if (IsSkipped()) return; // do not attempt to use 'device' address.device = AudioDevice::IN_DEFAULT; - const AudioConfig& config = GetParam(); + const AudioConfig& config = getConfig(); // TODO: test all supported flags and source auto flags = mkEnumBitfield(AudioInputFlag::NONE); testOpen( - [&](AudioIoHandle handle, AudioConfig config, auto cb) { - return device->openInputStream(handle, address, config, flags, initMetadata, cb); - }, - config); + [&](AudioIoHandle handle, AudioConfig config, auto cb) { + return getDevice()->openInputStream(handle, address, config, flags, + initMetadata, cb); + }, + config); } protected: @@ -808,18 +933,23 @@ TEST_P(InputStreamTest, OpenInputStreamTest) { // Open done in setup } INSTANTIATE_TEST_CASE_P( - RequiredInputStreamConfigSupport, InputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()), - &generateTestName); + RequiredInputStreamConfigSupport, InputStreamTest, + ::testing::Combine( + ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())), + &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( - SupportedInputStreamConfig, InputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()), - &generateTestName); + SupportedInputStreamConfig, InputStreamTest, + ::testing::Combine(::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig())), + &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( - RecommendedInputStreamConfigSupport, InputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()), - &generateTestName); + RecommendedInputStreamConfigSupport, InputStreamTest, + ::testing::Combine( + ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())), + &DeviceConfigParameterToString); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////// IStream getters /////////////////////////////// @@ -1332,19 +1462,19 @@ TEST_P(OutputStreamTest, GetPresentationPositionStop) { /////////////////////////////// PrimaryDevice //////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -TEST_F(AudioPrimaryHidlTest, setVoiceVolume) { +TEST_P(AudioPrimaryHidlTest, setVoiceVolume) { doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]"); - testUnitaryGain([](float volume) { return device->setVoiceVolume(volume); }); + testUnitaryGain([this](float volume) { return getDevice()->setVoiceVolume(volume); }); } -TEST_F(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) { +TEST_P(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) { doc::test("Query and set the BT SCO NR&EC state"); testAccessors("BtScoNrecEnabled", Initial{false, OPTIONAL}, {true}, &IPrimaryDevice::setBtScoNrecEnabled, &IPrimaryDevice::getBtScoNrecEnabled); } -TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) { +TEST_P(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) { doc::test("Query and set the SCO whideband state"); testAccessors("BtScoWideband", Initial{false, OPTIONAL}, {true}, &IPrimaryDevice::setBtScoWidebandEnabled, @@ -1352,15 +1482,17 @@ TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) { } using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; -TEST_F(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) { +TEST_P(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) { doc::test("Query and set the TTY mode state"); testAccessors( "TTY mode", Initial{IPrimaryDevice::TtyMode::OFF}, {IPrimaryDevice::TtyMode::HCO, IPrimaryDevice::TtyMode::VCO, IPrimaryDevice::TtyMode::FULL}, &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode); } +INSTANTIATE_TEST_CASE_P(TtyModeAccessorPrimaryHidl, TtyModeAccessorPrimaryHidlTest, + ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); -TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) { +TEST_P(BoolAccessorPrimaryHidlTest, setGetHac) { doc::test("Query and set the HAC state"); testAccessors("HAC", Initial{false}, {true}, &IPrimaryDevice::setHacEnabled, &IPrimaryDevice::getHacEnabled); @@ -1372,9 +1504,13 @@ TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) { int main(int argc, char** argv) { environment = new AudioHidlTestEnvironment; + // For V2..5 it's critical to initialize environment before GTest. + // The environment parses the service name from the command line, + // then it can be used in GTest parameter generators which are + // initialized during the call to InitGoogleTest. + environment->init(&argc, argv); ::testing::AddGlobalTestEnvironment(environment); ::testing::InitGoogleTest(&argc, argv); - environment->init(&argc, argv); int status = RUN_ALL_TESTS(); return status; } diff --git a/audio/core/all-versions/vts/functional/DeviceManager.h b/audio/core/all-versions/vts/functional/DeviceManager.h new file mode 100644 index 0000000000..b6e2db0685 --- /dev/null +++ b/audio/core/all-versions/vts/functional/DeviceManager.h @@ -0,0 +1,143 @@ +/* + * 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. + */ + +// Code in this file uses 'environment' +#ifndef AUDIO_PRIMARY_HIDL_HAL_TEST +#error Must be included from AudioPrimaryHidlTest.h +#endif + +template +class InterfaceManager { + public: + sp get(const Key& name) { + auto existing = instances.find(name); + if (existing != instances.end()) return existing->second; + auto [inserted, _] = instances.emplace(name, Derived::createInterfaceInstance(name)); + if (inserted->second) { + environment->registerTearDown([name]() { (void)Derived::getInstance().reset(name); }); + } + return inserted->second; + } + + // The test must check that reset was successful. Reset failure means that the test code + // is holding a strong reference to the device. + bool reset(const Key& name) __attribute__((warn_unused_result)) { + auto iter = instances.find(name); + if (iter == instances.end()) return true; + ::android::wp weak = iter->second; + instances.erase(iter); + if (weak.promote() != nullptr) return false; + waitForInstanceDestruction(); + return true; + } + + static void waitForInstanceDestruction() { + // FIXME: there is no way to know when the remote IDevice is being destroyed + // Binder does not support testing if an object is alive, thus + // wait for 100ms to let the binder destruction propagates and + // the remote device has the time to be destroyed. + // flushCommand makes sure all local command are sent, thus should reduce + // the latency between local and remote destruction. + IPCThreadState::self()->flushCommands(); + usleep(100 * 1000); + } + + protected: + std::map> instances; +}; + +class DevicesFactoryManager + : public InterfaceManager { + public: + static DevicesFactoryManager& getInstance() { + static DevicesFactoryManager instance; + return instance; + } + static sp createInterfaceInstance(const std::string& name) { +#if MAJOR_VERSION <= 5 + return ::testing::VtsHalHidlTargetTestBase::getService(name); +#elif MAJOR_VERSION >= 6 + return IDevicesFactory::getService(name); +#endif + } +}; + +using FactoryAndDevice = std::tuple; +class DeviceManager : public InterfaceManager { + public: + static DeviceManager& getInstance() { + static DeviceManager instance; + return instance; + } + static sp createInterfaceInstance(const FactoryAndDevice& factoryAndDevice) { + auto [factoryName, name] = factoryAndDevice; + sp factory = DevicesFactoryManager::getInstance().get(factoryName); + return name == kPrimaryDevice ? openPrimaryDevice(factory) : openDevice(factory, name); + } + using InterfaceManager::reset; + + static constexpr const char* kPrimaryDevice = "primary"; + + sp get(const std::string& factoryName, const std::string& name) { + return InterfaceManager::get(std::make_tuple(factoryName, name)); + } + sp getPrimary(const std::string& factoryName) { + sp device = get(factoryName, kPrimaryDevice); + return device != nullptr ? IPrimaryDevice::castFrom(device) : nullptr; + } + bool reset(const std::string& factoryName, const std::string& name) + __attribute__((warn_unused_result)) { + return InterfaceManager::reset(std::make_tuple(factoryName, name)); + } + bool resetPrimary(const std::string& factoryName) __attribute__((warn_unused_result)) { + return reset(factoryName, kPrimaryDevice); + } + + private: + static sp openDevice(const sp& factory, const std::string& name) { + if (factory == nullptr) return nullptr; + sp device; +#if MAJOR_VERSION >= 4 + Result result; + auto ret = factory->openDevice(name, returnIn(result, device)); + if (!ret.isOk() || result != Result::OK || device == nullptr) { + ALOGW("Device %s can not be opened, transaction: %s, result %d, device %p", + name.c_str(), ret.description().c_str(), result, device.get()); + return nullptr; + } +#else + (void)name; +#endif + return device; + } + + static sp openPrimaryDevice(const sp& factory) { + if (factory == nullptr) return nullptr; + Result result; + sp device; +#if MAJOR_VERSION == 2 + auto ret = factory->openDevice(IDevicesFactory::Device::PRIMARY, returnIn(result, device)); +#elif MAJOR_VERSION >= 4 + auto ret = factory->openPrimaryDevice(returnIn(result, device)); +#endif + if (!ret.isOk() || result != Result::OK || device == nullptr) { + ALOGW("Primary device can not be opened, transaction: %s, result %d, device %p", + ret.description().c_str(), result, device.get()); + return nullptr; + } + return device; + } +}; From 80feb3cdf0865cc3e71d92633000f87b54a4bdf1 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Thu, 24 Oct 2019 19:15:27 -0700 Subject: [PATCH 0210/1022] Wifi: Handle invalid error values from vendor HAL The HAL shim (default implementation) expects all vendor hal functions to return valid wifi_error values. In case the vendor hal returning a value outside this range of values, the HAL service crashes. This commit is to handle this type of error by defaulting to WIFI_ERROR_UNKNOWN. Bug: 143317834 Test: Manual Test: Pass an invalid error code, and make sure it is properly handled Change-Id: Ifaba8a7e4e866a2be154c9dcaeb521cd758010ee --- wifi/1.4/default/wifi_status_util.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wifi/1.4/default/wifi_status_util.cpp b/wifi/1.4/default/wifi_status_util.cpp index 597c04b609..8ceb9265f1 100644 --- a/wifi/1.4/default/wifi_status_util.cpp +++ b/wifi/1.4/default/wifi_status_util.cpp @@ -46,6 +46,8 @@ std::string legacyErrorToString(legacy_hal::wifi_error error) { return "BUSY"; case legacy_hal::WIFI_ERROR_UNKNOWN: return "UNKNOWN"; + default: + return "UNKNOWN ERROR"; } } @@ -92,6 +94,10 @@ WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error, case legacy_hal::WIFI_ERROR_UNKNOWN: return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown"); + + default: + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, + "unknown error"); } } From e5125a89abc277b4f408966c8659878a123feff5 Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Mon, 14 Oct 2019 13:49:21 -0700 Subject: [PATCH 0211/1022] Add Filter linkage and seperate interface Test: Manual bug: 135708935 Change-Id: I5782a183936ffca4f345d14c353ad34210f12df7 --- tv/tuner/1.0/Android.bp | 8 +- tv/tuner/1.0/IDemux.hal | 332 +-- tv/tuner/1.0/IDescrambler.hal | 10 +- tv/tuner/1.0/IDvr.hal | 133 ++ tv/tuner/1.0/IDvrCallback.hal | 33 + tv/tuner/1.0/IFilter.hal | 143 ++ ...IDemuxCallback.hal => IFilterCallback.hal} | 26 +- tv/tuner/1.0/IFrontend.hal | 4 +- tv/tuner/1.0/IFrontendCallback.hal | 10 - tv/tuner/1.0/ILnb.hal | 26 +- tv/tuner/1.0/ILnbCallback.hal | 36 + tv/tuner/1.0/ITimeFilter.hal | 88 + tv/tuner/1.0/ITuner.hal | 18 +- tv/tuner/1.0/types.hal | 1928 +++++++++++++---- 14 files changed, 1988 insertions(+), 807 deletions(-) create mode 100644 tv/tuner/1.0/IDvr.hal create mode 100644 tv/tuner/1.0/IDvrCallback.hal create mode 100644 tv/tuner/1.0/IFilter.hal rename tv/tuner/1.0/{IDemuxCallback.hal => IFilterCallback.hal} (54%) create mode 100644 tv/tuner/1.0/ILnbCallback.hal create mode 100644 tv/tuner/1.0/ITimeFilter.hal diff --git a/tv/tuner/1.0/Android.bp b/tv/tuner/1.0/Android.bp index 09265f7fce..d78f3f2f5c 100644 --- a/tv/tuner/1.0/Android.bp +++ b/tv/tuner/1.0/Android.bp @@ -9,15 +9,21 @@ hidl_interface { srcs: [ "types.hal", "IDemux.hal", - "IDemuxCallback.hal", "IDescrambler.hal", + "IDvr.hal", + "IDvrCallback.hal", + "IFilter.hal", + "IFilterCallback.hal", "IFrontend.hal", "IFrontendCallback.hal", "ILnb.hal", + "ILnbCallback.hal", + "ITimeFilter.hal", "ITuner.hal", ], interfaces: [ "android.hidl.base@1.0", + "android.hidl.safe_union@1.0", ], gen_java: false, gen_java_constants: true, diff --git a/tv/tuner/1.0/IDemux.hal b/tv/tuner/1.0/IDemux.hal index 7fd7e265bc..9e799b43f7 100644 --- a/tv/tuner/1.0/IDemux.hal +++ b/tv/tuner/1.0/IDemux.hal @@ -16,7 +16,11 @@ package android.hardware.tv.tuner@1.0; -import IDemuxCallback; +import IDvr; +import IDvrCallback; +import IFilter; +import IFilterCallback; +import ITimeFilter; /** * Demultiplexer(Demux) takes a single multiplexed input and splits it into @@ -24,7 +28,6 @@ import IDemuxCallback; * */ interface IDemux { - /** * Set a frontend resource as data input of the demux * @@ -39,134 +42,51 @@ interface IDemux { setFrontendDataSource(FrontendId frontendId) generates (Result result); /** - * Add a filter to the demux + * Open a new filter in the demux * - * It is used by the client to add a filter to the demux. + * It is used by the client to open a filter in the demux. * * @param type the type of the filter to be added. - * @param bufferSize the buffer size of the filter to be added. It's used to - * create a FMQ(Fast Message Queue) to hold data output from the filter. + * @param bufferSize the buffer size of the filter to be opened. It's used + * to create a FMQ(Fast Message Queue) to hold data output from the filter. * @param cb the callback for the filter to be used to send notifications * back to the client. * @return result Result status of the operation. * SUCCESS if successful, * INVALID_STATE if failed for wrong state. * UNKNOWN_ERROR if failed for other reasons. - * @return filterId the ID of the newly added filter. + * @return filter the filter instance of the newly added. */ - addFilter(DemuxFilterType type, uint32_t bufferSize, IDemuxCallback cb) - generates (Result result, DemuxFilterId filterId); + openFilter(DemuxFilterType type, uint32_t bufferSize, IFilterCallback cb) + generates (Result result, IFilter filter); /** - * Get the descriptor of the filter's FMQ + * Open time filter of the demux * - * It is used by the client to get the descriptor of the filter's Fast - * Message Queue. The data in FMQ is filtered out from MPEG transport - * stream. The data is organized to data blocks which may have - * different length. The length's information of one or multiple data blocks - * is sent to client through DemuxFilterEvent. + * It is used by the client to open time filter of the demux. * - * @param filterId the ID of the filter. * @return result Result status of the operation. * SUCCESS if successful, - * INVALID_ARGUMENT if failed for wrong filter ID. + * UNAVAILABLE if time filter is not supported. * INVALID_STATE if failed for wrong state. * UNKNOWN_ERROR if failed for other reasons. - * @return queue the descriptor of the filter's FMQ + * @return timeFilter the time filter instance of the newly added. */ - getFilterQueueDesc(DemuxFilterId filterId) - generates (Result result, fmq_sync queue); - - /** - * Configure the filter. - * - * It is used by the client to configure the filter so that it can filter out - * intended data. - * - * @param filterId the ID of the filter. - * @param settings the settings of the filter. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_ARGUMENT if failed for wrong filter ID. - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - configureFilter(DemuxFilterId filterId, DemuxFilterSettings settings) - generates(Result result); - - /** - * Start the filter. - * - * It is used by the client to ask the filter to start filtering data. - * - * @param filterId the ID of the filter. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_ARGUMENT if failed for wrong filter ID. - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - startFilter(DemuxFilterId filterId) generates (Result result); - - /** - * Stop the filter. - * - * It is used by the client to ask the filter to stop filterring data. - * It won't discard the data already filtered out by the filter. The filter - * will be stopped and removed automatically if the demux is closed. - * - * @param filterId the ID of the filter. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_ARGUMENT if failed for wrong filter ID. - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - stopFilter(DemuxFilterId filterId) generates (Result result); - - /** - * Flush the filter. - * - * It is used by the client to ask the filter to flush the data which is - * already produced but not consumed yet. - * - * @param filterId the ID of the filter. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_ARGUMENT if failed for wrong filter ID. - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - flushFilter(DemuxFilterId filterId) generates (Result result); - - /** - * Remove a filter from the demux - * - * It is used by the client to remove a filter from the demux. - * - * @param filterId the ID of the removed filter. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_ARGUMENT if failed for wrong filter ID. - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - removeFilter(DemuxFilterId filterId) generates (Result result); + openTimeFilter() generates (Result result, ITimeFilter timeFilter); /** * Get hardware sync ID for audio and video. * * It is used by the client to get the hardware sync ID for audio and video. * - * @param filterId the ID of the filter. + * @param filter the filter instance. * @return result Result status of the operation. * SUCCESS if successful, * INVALID_ARGUMENT if failed for a wrong filter ID. * UNKNOWN_ERROR if failed for other reasons. * @return avSyncHwId the id of hardware A/V sync. */ - getAvSyncHwId(DemuxFilterId filterId) - generates (Result result, AvSyncHwId avSyncHwId); + getAvSyncHwId(IFilter filter) generates (Result result, AvSyncHwId avSyncHwId); /** * Get current time stamp to use for A/V sync @@ -182,8 +102,7 @@ interface IDemux { * @return time the current time stamp of hardware A/V sync. The time stamp * based on 90KHz has the same format as PTS (Presentation Time Stamp). */ - getAvSyncTime(AvSyncHwId avSyncHwId) - generates (Result result, uint64_t time); + getAvSyncTime(AvSyncHwId avSyncHwId) generates (Result result, uint64_t time); /** * Close the Demux instance @@ -198,218 +117,21 @@ interface IDemux { close() generates (Result result); /** - * Add output to the demux + * Open a DVR (Digital Video Record) instance in the demux * - * It is used by the client to record output data from selected filters. + * It is used by the client to record and playback. * + * @param type specify which kind of DVR to open. * @param bufferSize the buffer size of the output to be added. It's used to * create a FMQ(Fast Message Queue) to hold data from selected filters. - * @param cb the callback for the demux to be used to send notifications + * @param cb the callback for the DVR to be used to send notifications * back to the client. * @return result Result status of the operation. * SUCCESS if successful, * OUT_OF_MEMORY if failed for not enough memory. * UNKNOWN_ERROR if failed for other reasons. + * @return dvr a DVR instance. */ - addOutput(uint32_t bufferSize, IDemuxCallback cb) generates (Result result); - - /** - * Get the descriptor of the output's FMQ - * - * It is used by the client to get the descriptor of the output's Fast - * Message Queue. The data in FMQ is muxed packets output from selected - * filters. The packet's format is specified by DemuxDataFormat in - * DemuxOutputSettings. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * UNKNOWN_ERROR if failed for other reasons. - * @return queue the descriptor of the output's FMQ - */ - getOutputQueueDesc() generates (Result result, fmq_sync queue); - - /** - * Configure the demux's output. - * - * It is used by the client to configure the demux's output for recording. - * - * @param settings the settings of the demux's output. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - configureOutput(DemuxOutputSettings settings) generates (Result result); - - /** - * Attach one filter to the demux's output. - * - * It is used by the client to mux one filter's output to demux's output. - * - * @param filterId the ID of the attached filter. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - attachOutputFilter(DemuxFilterId filterId) generates (Result result); - - /** - * Detach one filter from the demux's output. - * - * It is used by the client to remove one filter's output from demux's - * output. - * - * @param filterId the ID of the detached filter. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - detachOutputFilter(DemuxFilterId filterId) generates (Result result); - - /** - * Start to take data to the demux's output. - * - * It is used by the client to ask the output to start to take data from - * attached filters. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - startOutput() generates (Result result); - - /** - * Stop to take data to the demux's output. - * - * It is used by the client to ask the output to stop to take data from - * attached filters. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - stopOutput() generates (Result result); - - /** - * Flush unconsumed data in the demux's output. - * - * It is used by the client to ask the demux to flush the data which is - * already produced but not consumed yet in the demux's output. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - flushOutput() generates (Result result); - - /** - * Remove the demux's output. - * - * It is used by the client to remove the demux's output. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - removeOutput() generates (Result result); - - /** - * Add input to the demux - * - * It is used by the client to add the demux's input for playback content. - * - * @param bufferSize the buffer size of the demux's input to be added. - * It's used to create a FMQ(Fast Message Queue) to hold input data. - * @param cb the callback for the demux to be used to send notifications - * back to the client. - * @return result Result status of the operation. - * SUCCESS if successful, - * OUT_OF_MEMORY if failed for not enough memory. - * UNKNOWN_ERROR if failed for other reasons. - */ - addInput(uint32_t bufferSize, IDemuxCallback cb) generates (Result result); - - /** - * Get the descriptor of the input's FMQ - * - * It is used by the client to get the descriptor of the input's Fast - * Message Queue. The data in FMQ is fed by client. Data format is specifed - * by DemuxDataFormat in DemuxInputSettings. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * UNKNOWN_ERROR if failed for other reasons. - * @return queue the descriptor of the output's FMQ - */ - getInputQueueDesc() generates (Result result, fmq_sync queue); - - /** - * Configure the demux's input. - * - * It is used by the client to configure the demux's input for playback. - * - * @param settings the settings of the demux's input. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - configureInput(DemuxInputSettings settings) generates (Result result); - - /** - * Start to consume the data from the demux's input. - * - * It is used by the client to ask the demux to start to consume data from - * the demux's input. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - startInput() generates (Result result); - - /** - * Stop to consume the data from the demux's input. - * - * It is used by the client to ask the demux to stop to consume data from - * the demux's input. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - stopInput() generates (Result result); - - /** - * Flush unconsumed data in the demux's input. - * - * It is used by the client to ask the demux to flush the data which is - * already produced but not consumed yet in the demux's input. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - flushInput() generates (Result result); - - /** - * Remove the demux's input. - * - * It is used by the client to remove the demux's input. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - removeInput() generates (Result result); + openDvr(DvrType type, uint32_t bufferSize, IDvrCallback cb) + generates (Result result, IDvr dvr); }; diff --git a/tv/tuner/1.0/IDescrambler.hal b/tv/tuner/1.0/IDescrambler.hal index 61ff1df4bd..7f98865c19 100644 --- a/tv/tuner/1.0/IDescrambler.hal +++ b/tv/tuner/1.0/IDescrambler.hal @@ -15,6 +15,9 @@ */ package android.hardware.tv.tuner@1.0; + +import IFilter; + /** * Descrambler is used to descramble input data. * @@ -59,12 +62,13 @@ interface IDescrambler { * packets from different PIDs. * * @param pid the PID of packets to start to be descrambled. + * @param filter an optional filter instance to identify upper stream. * @return result Result status of the operation. * SUCCESS if successful, * INVALID_STATE if failed for wrong state. * UNKNOWN_ERROR if failed for other reasons. */ - addPid(DemuxTpid pid) generates (Result result); + addPid(DemuxPid pid, IFilter optionalSourceFilter) generates (Result result); /** * Remove packets' PID from the descrambler @@ -73,12 +77,13 @@ interface IDescrambler { * descrambler stop to descramble. * * @param pid the PID of packets to stop to be descrambled. + * @param filter an optional filter instance to identify upper stream. * @return result Result status of the operation. * SUCCESS if successful, * INVALID_STATE if failed for wrong state. * UNKNOWN_ERROR if failed for other reasons. */ - removePid(DemuxTpid pid) generates (Result result); + removePid(DemuxPid pid, IFilter optionalSourceFilter) generates (Result result); /** * Release the descrambler instance @@ -92,4 +97,3 @@ interface IDescrambler { */ close() generates (Result result); }; - diff --git a/tv/tuner/1.0/IDvr.hal b/tv/tuner/1.0/IDvr.hal new file mode 100644 index 0000000000..f57e4b6768 --- /dev/null +++ b/tv/tuner/1.0/IDvr.hal @@ -0,0 +1,133 @@ +/* + * 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. + */ + +package android.hardware.tv.tuner@1.0; + +import IFilter; + +/** + * Digtal Video Record (DVR) interface provides record control on Demux's + * output buffer and playback control on Demux's input buffer. + */ +interface IDvr { + /** + * Get the descriptor of the DVR's FMQ + * + * It is used by the client to get the descriptor of the DVR's Fast + * Message Queue. The FMQ is used to transfer record or playback data + * between the client and the HAL. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + * @return queue the descriptor of the DVR's FMQ + */ + getQueueDesc() generates (Result result, fmq_sync queue); + + /** + * Configure the DVR. + * + * It is used by the client to configure the DVR interface. + * + * @param settings the settings of the DVR interface. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + configure(DvrSettings settings) generates (Result result); + + /** + * Attach one filter to DVR interface for recording. + * + * It is used by the client to add the data filtered out from the filter + * to record. + * + * @param filter the instance of the attached filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + attachFilter(IFilter filter) generates (Result result); + + /** + * Detach one filter from the DVR's recording. + * + * It is used by the client to remove the data of the filter from DVR's + * recording. + * + * @param filter the instance of the detached filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + detachFilter(IFilter filter) generates (Result result); + + /** + * Start DVR. + * + * It is used by the client to ask the DVR to start consuming playback data + * or producing data for record. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + start() generates (Result result); + + /** + * Stop DVR. + * + * It is used by the client to ask the DVR to stop consuming playback data + * or producing data for record. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + stop() generates (Result result); + + /** + * Flush DVR data. + * + * It is used by the client to ask the DVR to flush the data which is + * not consumed by HAL for playback or the client for record yet. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + flush() generates (Result result); + + /** + * close the DVR instance to release resource for DVR. + * + * It is used by the client to close the DVR instance, and HAL clears + * underneath resource for this DVR instance. Client mustn't access the + * instance any more and all methods should return a failure. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + close() generates (Result result); +}; diff --git a/tv/tuner/1.0/IDvrCallback.hal b/tv/tuner/1.0/IDvrCallback.hal new file mode 100644 index 0000000000..337eddcede --- /dev/null +++ b/tv/tuner/1.0/IDvrCallback.hal @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package android.hardware.tv.tuner@1.0; + +interface IDvrCallback { + /** + * Notify the client a new status of the demux's record. + * + * @param status a new status of the demux's record. + */ + oneway onRecordStatus(RecordStatus status); + + /** + * Notify the client a new status of the demux's playback. + * + * @param status a new status of the demux's playback. + */ + oneway onPlaybackStatus(PlaybackStatus status); +}; diff --git a/tv/tuner/1.0/IFilter.hal b/tv/tuner/1.0/IFilter.hal new file mode 100644 index 0000000000..deaf3d473e --- /dev/null +++ b/tv/tuner/1.0/IFilter.hal @@ -0,0 +1,143 @@ +/* + * 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. + */ + +package android.hardware.tv.tuner@1.0; + +import IFilterCallback; + +/** + * The Filter is used to filter wanted data according to the filter's + * configuration. + */ +interface IFilter { + /** + * Get the descriptor of the filter's FMQ + * + * It is used by the client to get the descriptor of the filter's Fast + * Message Queue. The data in FMQ is filtered out from demux input or upper + * stream's filter. The data is origanized to data blocks which may have + * different length. The length's information of one or multiple data blocks + * is sent to client through DemuxFilterEvent. The data in each block + * follows the stardard specified by filter's type. + * E.X. one data block from the filter with Main_Type==TS and Sub_Type==PES + * is Packetized Elementary Stream from Transport Stream according to + * ISO/IEC 13818-1. + * + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNAVAILABLE if the filter doesn't have FMQ. + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + * @return queue the descriptor of the filter's FMQ + */ + getQueueDesc() generates (Result result, fmq_sync queue); + + /** + * Configure the filter. + * + * It is used by the client to configure the filter so that it can filter out + * intended data. + * + * @param settings the settings of the filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + configure(DemuxFilterSettings settings) generates (Result result); + + /** + * Start the filter. + * + * It is used by the client to ask the filter to start filterring data. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + start() generates (Result result); + + /** + * Stop the filter. + * + * It is used by the client to ask the filter to stop filterring data. + * It won't discard the data already filtered out by the filter. The filter + * will be stopped and removed automatically if the demux is closed. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + stop() generates (Result result); + + /** + * Flush the filter. + * + * It is used by the client to ask the filter to flush the data which is + * already produced but not consumed yet. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + flush() generates (Result result); + + /** + * Get the filter Id. + * + * It is used by the client to ask the hardware resource id for the filter. + * + * @param filterId the hardware resource Id for the filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + getId() generates (Result result, uint32_t filterId); + + /** + * Set the filter's data source. + * + * A filter uses demux as data source by default. If the data was packetized + * by multiple protocols, multiple filters may need to work together to + * extract all protocols' header. Then a filter's data source can be output + * from another filter. + * + * @param filter the filter instance which provides data input. Switch to + * use demux as data source if the filter instance is NULL. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + setDataSource(IFilter filter) generates (Result result); + + /** + * Release the Filter instance + * + * It is used by the client to release the Filter instance. HAL clear + * underneath resource. client mustn't access the instance any more. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + */ + close() generates (Result result); +}; diff --git a/tv/tuner/1.0/IDemuxCallback.hal b/tv/tuner/1.0/IFilterCallback.hal similarity index 54% rename from tv/tuner/1.0/IDemuxCallback.hal rename to tv/tuner/1.0/IFilterCallback.hal index 7bce9efeb1..a0ff62ead4 100644 --- a/tv/tuner/1.0/IDemuxCallback.hal +++ b/tv/tuner/1.0/IFilterCallback.hal @@ -16,34 +16,18 @@ package android.hardware.tv.tuner@1.0; -interface IDemuxCallback { +interface IFilterCallback { /** * Notify the client that a new filter event happened. * - * @param filterEvent a demux filter event. + * @param filterEvent a filter event. */ oneway onFilterEvent(DemuxFilterEvent filterEvent); /** - * Notify the client a new status of a demux filter. + * Notify the client a new status of a filter. * - * @param filterId the demux filter ID. - * @param status a new status of the demux filter. + * @param status a new status of the filter. */ - oneway onFilterStatus(DemuxFilterId filterId, DemuxFilterStatus status); - - /** - * Notify the client a new status of the demux's output. - * - * @param status a new status of the demux's output. - */ - oneway onOutputStatus(DemuxOutputStatus status); - - /** - * Notify the client a new status of the demux's input. - * - * @param status a new status of the demux's input. - */ - oneway onInputStatus(DemuxInputStatus status); + oneway onFilterStatus(DemuxFilterStatus status); }; - diff --git a/tv/tuner/1.0/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal index 83e390ddcf..756ab4650e 100644 --- a/tv/tuner/1.0/IFrontend.hal +++ b/tv/tuner/1.0/IFrontend.hal @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package android.hardware.tv.tuner@1.0; import IFrontendCallback; @@ -128,7 +129,8 @@ interface IFrontend { * @return statuses an array of statuses which response the caller's * request. */ - getStatus(vec statusTypes) generates (Result result, vec statuses); + getStatus(vec statusTypes) + generates (Result result, vec statuses); /** * Sets Low-Noise Block downconverter (LNB) for satellite frontend. diff --git a/tv/tuner/1.0/IFrontendCallback.hal b/tv/tuner/1.0/IFrontendCallback.hal index 8896a09b62..88b96c474c 100644 --- a/tv/tuner/1.0/IFrontendCallback.hal +++ b/tv/tuner/1.0/IFrontendCallback.hal @@ -24,16 +24,6 @@ interface IFrontendCallback { */ oneway onEvent(FrontendEventType frontendEventType); - /** - * The callback function that must be called by HAL implementation to notify - * the client of new DiSEqC message. - * - * @param diseqcMessage a byte array of data for DiSEqC (Digital Satellite - * Equipment Control) message which is specified by EUTELSAT Bus Functional - * Specification Version 4.2. - */ - oneway onDiseqcMessage(vec diseqcMessage); - /** * The callback function that must be called by HAL implementation to notify * the client of scan messages. diff --git a/tv/tuner/1.0/ILnb.hal b/tv/tuner/1.0/ILnb.hal index 6b7119e046..5070519dcb 100644 --- a/tv/tuner/1.0/ILnb.hal +++ b/tv/tuner/1.0/ILnb.hal @@ -13,14 +13,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package android.hardware.tv.tuner@1.0; +import ILnbCallback; + /** * A Tuner LNB (low-noise block downconverter) is used by satellite frontend * to receive the microwave signal from the satellite, amplify it, and * downconvert the frequency to a lower frequency. */ interface ILnb { + /** + * Set the lnb callback. + * + * ILnbCallback is used by the client to receive events from the Lnb. + * Only one callback per ILnb instance is supported. The callback + * will be replaced if it's set again. + * + * @param callback Callback object to pass Lnb events to the system. + * The previously registered callback must be replaced with this one. + * It can be null. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if callback can't be set at current stage, + * UNKNOWN_ERROR if callback setting failed for other reasons. + */ + setCallback(ILnbCallback callback) generates (Result result); + /** * Set the lnb's power voltage. * @@ -30,7 +50,7 @@ interface ILnb { * INVALID_ARGUMENT if the selected voltage isn't allowed, * UNKNOWN_ERROR if failed for other reasons. */ - setVoltage(FrontendLnbVoltage voltage) generates (Result result); + setVoltage(LnbVoltage voltage) generates (Result result); /** * Set the lnb's tone mode. @@ -41,7 +61,7 @@ interface ILnb { * INVALID_ARGUMENT if the selected tone mode isn't allowed, * UNKNOWN_ERROR if failed for other reasons. */ - setTone(FrontendLnbTone tone) generates (Result result); + setTone(LnbTone tone) generates (Result result); /** * Select the lnb's position. @@ -52,7 +72,7 @@ interface ILnb { * INVALID_ARGUMENT if the selected position isn't allowed, * UNKNOWN_ERROR if failed for other reasons. */ - setSatellitePosition(FrontendLnbPosition position) generates (Result result); + setSatellitePosition(LnbPosition position) generates (Result result); /** * Sends DiSEqC (Digital Satellite Equipment Control) message. diff --git a/tv/tuner/1.0/ILnbCallback.hal b/tv/tuner/1.0/ILnbCallback.hal new file mode 100644 index 0000000000..68e9c356f2 --- /dev/null +++ b/tv/tuner/1.0/ILnbCallback.hal @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package android.hardware.tv.tuner@1.0; + +interface ILnbCallback { + /** + * Notify the client that a new event happened on the Lnb. + * + * @param LnbEventType the event type. + */ + oneway onEvent(LnbEventType lnbEventType); + + /** + * The callback function that must be called by HAL implementation to notify + * the client of new DiSEqC message. + * + * @param diseqcMessage a byte array of data for DiSEqC (Digital Satellite + * Equipment Control) message which is specified by EUTELSAT Bus Functional + * Specification Version 4.2. + */ + oneway onDiseqcMessage(vec diseqcMessage); +}; diff --git a/tv/tuner/1.0/ITimeFilter.hal b/tv/tuner/1.0/ITimeFilter.hal new file mode 100644 index 0000000000..ce285dbb24 --- /dev/null +++ b/tv/tuner/1.0/ITimeFilter.hal @@ -0,0 +1,88 @@ +/* + * 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. + */ + +package android.hardware.tv.tuner@1.0; + +/** + * Timer Filter is used by Demux to filter data based on time stamp. + */ +interface ITimeFilter { + /** + * Set time stamp for time based filter. + * + * It is used by the client to set initial time stamp and enable time + * filtering. The time will be incremented locally. The demux discards + * the content which time stamp is older than the time in the time filter. + * + * @param timeStamp initial time stamp for the time filter. It based on + * 90KHz has the same format as PTS (Presentation Time Stamp). + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + */ + setTimeStamp(uint64_t timeStamp) generates (Result result); + + /** + * Clear the time stamp in the time filter. + * + * It is used by the client to clear the time value of the time filter, + * then disable time filter. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + */ + clearTimeStamp() generates (Result result); + + /** + * Get the current time in the time filter. + * + * It is used by the client to inquiry current time in the time filter. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + * @return timeStamp current time stamp in the time filter. + */ + getTimeStamp() generates (Result result, uint64_t timeStamp); + + /** + * Get the time from the beginning of current data source. + * + * It is used by the client to inquiry the time stamp from the beginning + * of current data source. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + * @return timeStamp time stamp from the beginning of current data source. + */ + getSourceTime() generates (Result result, uint64_t timeStamp); + + /** + * Close the Time Filter instance + * + * It is used by the client to release the demux instance. HAL clear + * underneath resource. client mustn't access the instance any more. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + */ + close() generates (Result result); +}; diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal index 1cf0e387b6..2712c13708 100644 --- a/tv/tuner/1.0/ITuner.hal +++ b/tv/tuner/1.0/ITuner.hal @@ -23,7 +23,7 @@ import ILnb; /** * Top level interface to manage Frontend, Demux and Decrambler hardware - * resources which are needed for Android TV. + * resouces which are needed for Android TV. */ interface ITuner { /** @@ -50,8 +50,7 @@ interface ITuner { * UNKNOWN_ERROR if creation failed for other reasons. * @return frontend the newly created frontend interface. */ - openFrontendById(FrontendId frontendId) - generates (Result result, IFrontend frontend); + openFrontendById(FrontendId frontendId) generates (Result result, IFrontend frontend); /** * Create a new instance of Demux. @@ -64,8 +63,7 @@ interface ITuner { * @return demuxId newly created demux id. * @return demux the newly created demux interface. */ - openDemux() - generates (Result result, DemuxId demuxId, IDemux demux); + openDemux() generates (Result result, DemuxId demuxId, IDemux demux); /** * Retrieve the Demux's Capabilities. @@ -87,8 +85,7 @@ interface ITuner { * UNKNOWN_ERROR if creation failed for other reasons. * @return descrambler the newly created descrambler interface. */ - openDescrambler() - generates (Result result, IDescrambler descrambler); + openDescrambler() generates (Result result, IDescrambler descrambler); /** * Retrieve the frontend's information. @@ -99,8 +96,7 @@ interface ITuner { * UNKNOWN_ERROR if the inquiry failed for other reasons. * @return info the frontend's information. */ - getFrontendInfo(FrontendId frontendId) - generates (Result result, FrontendInfo info); + getFrontendInfo(FrontendId frontendId) generates (Result result, FrontendInfo info); /** * Get low-noise block downconverter (LNB) IDs. @@ -126,7 +122,5 @@ interface ITuner { * UNKNOWN_ERROR if creation failed for other reasons. * @return lnb the newly created Lnb interface. */ - openLnbById(LnbId lnbId) - generates (Result result, ILnb lnb); + openLnbById(LnbId lnbId) generates (Result result, ILnb lnb); }; - diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index 890c1edd01..fa00a6e923 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -17,6 +17,7 @@ package android.hardware.tv.tuner@1.0; import android.hidl.safe_union@1.0; +import android.hidl.safe_union@1.0::Monostate; @export enum Result : int32_t { @@ -41,9 +42,13 @@ typedef uint32_t FrontendId; enum FrontendType : uint32_t { UNDEFINED = 0, ANALOG, - /* Advanced Television Systems Committee (ATSC) Standard A/72. */ + /** + * Advanced Television Systems Committee (ATSC) Standard A/72. + */ ATSC, - /* Advanced Television Systems Committee (ATSC 3.0) Standard A/300. */ + /** + * Advanced Television Systems Committee (ATSC 3.0) Standard A/300. + */ ATSC3, /** * Digital Video Broadcasting - Cable @@ -62,15 +67,18 @@ enum FrontendType : uint32_t { * ETSI EN 302 755 V1.4.1. */ DVBT, - /* Integrated Services Digital Broadcasting-Satellite (ISDB-S) + /** + * Integrated Services Digital Broadcasting-Satellite (ISDB-S) * ARIB STD-B20 is technical document of ISDB-S. */ ISDBS, - /* Integrated Services Digital Broadcasting-Satellite (ISDB-S) + /** + * Integrated Services Digital Broadcasting-Satellite (ISDB-S) * ARIB STD-B44 is technical document of ISDB-S3. */ ISDBS3, - /* Integrated Services Digital Broadcasting-Terrestrial (ISDB-T or SBTVD) + /** + * Integrated Services Digital Broadcasting-Terrestrial (ISDB-T or SBTVD) * ABNT NBR 15603 is technical document of ISDB-T. */ ISDBT, @@ -82,79 +90,153 @@ enum FrontendType : uint32_t { */ @export enum FrontendInnerFec : uint64_t { - /* Not defined */ + /** + * Not defined + */ FEC_UNDEFINED = 0, - /* hardware is able to detect and set FEC automatically */ + /** + * hardware is able to detect and set FEC automatically + */ AUTO = 1 << 0, - /* 1/2 conv. code rate */ + /** + * 1/2 conv. code rate + */ FEC_1_2 = 1 << 1, - /* 1/3 conv. code rate */ + /** + * 1/3 conv. code rate + */ FEC_1_3 = 1 << 2, - /* 1/4 conv. code rate */ + /** + * 1/4 conv. code rate + */ FEC_1_4 = 1 << 3, - /* 1/5 conv. code rate */ + /** + * 1/5 conv. code rate + */ FEC_1_5 = 1 << 4, - /* 2/3 conv. code rate */ + /** + * 2/3 conv. code rate + */ FEC_2_3 = 1 << 5, - /* 2/5 conv. code rate */ + /** + * 2/5 conv. code rate + */ FEC_2_5 = 1 << 6, - /* 2/9 conv. code rate */ + /** + * 2/9 conv. code rate + */ FEC_2_9 = 1 << 7, - /* 3/4 conv. code rate */ + /** + * 3/4 conv. code rate + */ FEC_3_4 = 1 << 8, - /* 3/5 conv. code rate */ + /** + * 3/5 conv. code rate + */ FEC_3_5 = 1 << 9, - /* 4/5 conv. code rate */ + /** + * 4/5 conv. code rate + */ FEC_4_5 = 1 << 10, - /* 4/15 conv. code rate */ + /** + * 4/15 conv. code rate + */ FEC_4_15 = 1 << 11, - /* 5/6 conv. code rate */ + /** + * 5/6 conv. code rate + */ FEC_5_6 = 1 << 12, - /* 5/9 conv. code rate */ + /** + * 5/9 conv. code rate + */ FEC_5_9 = 1 << 13, - /* 6/7 conv. code rate */ + /** + * 6/7 conv. code rate + */ FEC_6_7 = 1 << 14, - /* 7/8 conv. code rate */ + /** + * 7/8 conv. code rate + */ FEC_7_8 = 1 << 15, - /* 7/9 conv. code rate */ + /** + * 7/9 conv. code rate + */ FEC_7_9 = 1 << 16, - /* 7/15 conv. code rate */ + /** + * 7/15 conv. code rate + */ FEC_7_15 = 1 << 17, - /* 8/9 conv. code rate */ + /** + * 8/9 conv. code rate + */ FEC_8_9 = 1 << 18, - /* 8/15 conv. code rate */ + /** + * 8/15 conv. code rate + */ FEC_8_15 = 1 << 19, - /* 9/10 conv. code rate */ + /** + * 9/10 conv. code rate + */ FEC_9_10 = 1 << 20, - /* 9/20 conv. code rate */ + /** + * 9/20 conv. code rate + */ FEC_9_20 = 1 << 21, - /* 11/15 conv. code rate */ + /** + * 11/15 conv. code rate + */ FEC_11_15 = 1 << 22, - /* 11/20 conv. code rate */ + /** + * 11/20 conv. code rate + */ FEC_11_20 = 1 << 23, - /* 11/45 conv. code rate */ + /** + * 11/45 conv. code rate + */ FEC_11_45 = 1 << 24, - /* 13/18 conv. code rate */ + /** + * 13/18 conv. code rate + */ FEC_13_18 = 1 << 25, - /* 13/45 conv. code rate */ + /** + * 13/45 conv. code rate + */ FEC_13_45 = 1 << 26, - /* 14/45 conv. code rate */ + /** + * 14/45 conv. code rate + */ FEC_14_45 = 1 << 27, - /* 23/36 conv. code rate */ + /** + * 23/36 conv. code rate + */ FEC_23_36 = 1 << 28, - /* 25/36 conv. code rate */ + /** + * 25/36 conv. code rate + */ FEC_25_36 = 1 << 29, - /* 26/45 conv. code rate */ + /** + * 26/45 conv. code rate + */ FEC_26_45 = 1 << 30, - /* 28/45 conv. code rate */ + /** + * 28/45 conv. code rate + */ FEC_28_45 = 1 << 31, - /* 29/45 conv. code rate */ + /** + * 29/45 conv. code rate + */ FEC_29_45 = 1 << 32, - /* 31/45 conv. code rate */ + /** + * 31/45 conv. code rate + */ FEC_31_45 = 1 << 33, - /* 32/45 conv. code rate */ + /** + * 32/45 conv. code rate + */ FEC_32_45 = 1 << 34, - /* 77/90 conv. code rate */ + /** + * 77/90 conv. code rate + */ FEC_77_90 = 1 << 35, }; @@ -164,9 +246,11 @@ enum FrontendInnerFec : uint64_t { @export enum FrontendAtscModulation : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set modulation automatically */ - AUTO = 1 << 0, - MOD_8VSB = 1 << 2, + /** + * hardware is able to detect and set modulation automatically + */ + AUTO = 1 << 0, + MOD_8VSB = 1 << 2, MOD_16VSB = 1 << 3, }; @@ -174,8 +258,11 @@ enum FrontendAtscModulation : uint32_t { * Signal Settings for an ATSC Frontend. */ struct FrontendAtscSettings { - /** Signal frequency in Hertz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; + FrontendAtscModulation modulation; }; @@ -183,7 +270,9 @@ struct FrontendAtscSettings { * Capabilities for ATSC Frontend. */ struct FrontendAtscCapabilities { - /** Modulation capability */ + /** + * Modulation capability + */ bitfield modulationCap; }; @@ -193,12 +282,14 @@ struct FrontendAtscCapabilities { @export enum FrontendAtsc3Modulation : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set modulation automatically */ - AUTO = 1 << 0, - MOD_QPSK = 1 << 1, - MOD_16QAM = 1 << 2, - MOD_64QAM = 1 << 3, - MOD_256QAM = 1 << 4, + /** + * hardware is able to detect and set modulation automatically + */ + AUTO = 1 << 0, + MOD_QPSK = 1 << 1, + MOD_16QAM = 1 << 2, + MOD_64QAM = 1 << 3, + MOD_256QAM = 1 << 4, MOD_1024QAM = 1 << 5, MOD_4096QAM = 1 << 6, }; @@ -209,7 +300,9 @@ enum FrontendAtsc3Modulation : uint32_t { @export enum FrontendAtsc3Bandwidth : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set bandwidth automatically */ + /** + * hardware is able to detect and set bandwidth automatically + */ AUTO = 1 << 0, BANDWIDTH_6MHZ = 1 << 1, BANDWIDTH_7MHZ = 1 << 2, @@ -222,10 +315,12 @@ enum FrontendAtsc3Bandwidth : uint32_t { @export enum FrontendAtsc3TimeInterleaveMode : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set TimeInterleaveMode automatically */ + /** + * hardware is able to detect and set TimeInterleaveMode automatically + */ AUTO = 1 << 0, - CTI = 1 << 1, - HTI = 1 << 2, + CTI = 1 << 1, + HTI = 1 << 2, }; /** @@ -234,20 +329,22 @@ enum FrontendAtsc3TimeInterleaveMode : uint32_t { @export enum FrontendAtsc3CodeRate : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Coderate automatically */ - AUTO = 1 << 0, - CODERATE_2_15 = 1 << 1, - CODERATE_3_15 = 1 << 2, - CODERATE_4_15 = 1 << 3, - CODERATE_5_15 = 1 << 4, - CODERATE_6_15 = 1 << 5, - CODERATE_7_15 = 1 << 6, - CODERATE_8_15 = 1 << 7, - CODERATE_9_15 = 1 << 8, - CODERATE_10_15 = 1 << 9, - CODERATE_11_15 = 1 << 10, - CODERATE_12_15 = 1 << 11, - CODERATE_13_15 = 1 << 12, + /** + * hardware is able to detect and set Coderate automatically + */ + AUTO = 1 << 0, + CODERATE_2_15 = 1 << 1, + CODERATE_3_15 = 1 << 2, + CODERATE_4_15 = 1 << 3, + CODERATE_5_15 = 1 << 4, + CODERATE_6_15 = 1 << 5, + CODERATE_7_15 = 1 << 6, + CODERATE_8_15 = 1 << 7, + CODERATE_9_15 = 1 << 8, + CODERATE_10_15 = 1 << 9, + CODERATE_11_15 = 1 << 10, + CODERATE_12_15 = 1 << 11, + CODERATE_13_15 = 1 << 12, }; /** @@ -256,14 +353,16 @@ enum FrontendAtsc3CodeRate : uint32_t { @export enum FrontendAtsc3Fec : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set FEC automatically */ - AUTO = 1 << 0, + /** + * hardware is able to detect and set FEC automatically + */ + AUTO = 1 << 0, BCH_LDPC_16K = 1 << 1, BCH_LDPC_64K = 1 << 2, CRC_LDPC_16K = 1 << 3, CRC_LDPC_64K = 1 << 4, - LDPC_16K = 1 << 5, - LDPC_64K = 1 << 6, + LDPC_16K = 1 << 5, + LDPC_64K = 1 << 6, }; /** @@ -271,12 +370,18 @@ enum FrontendAtsc3Fec : uint32_t { */ @export enum FrontendAtsc3DemodOutputFormat : uint8_t { - /** Dummy. Scan uses this. */ + /** + * Dummy. Scan uses this. + */ UNDEFINED = 0, - /** ALP format. Typically used in US region. */ + /** + * ALP format. Typically used in US region. + */ ATSC3_LINKLAYER_PACKET = 1 << 0, - /** BaseBand packet format. Typically used in Korea region. */ - BASEBAND_PACKET = 1 << 1, + /** + * BaseBand packet format. Typically used in Korea region. + */ + BASEBAND_PACKET = 1 << 1, }; /** @@ -284,9 +389,13 @@ enum FrontendAtsc3DemodOutputFormat : uint8_t { */ struct FrontendAtsc3PlpSettings { uint8_t plpId; + FrontendAtsc3Modulation modulation; + FrontendAtsc3TimeInterleaveMode interleaveMode; + FrontendAtsc3CodeRate codeRate; + FrontendAtsc3Fec fec; }; @@ -294,11 +403,18 @@ struct FrontendAtsc3PlpSettings { * Signal Settings for an ATSC3 Frontend. */ struct FrontendAtsc3Settings { - /** Signal frequency in Hertz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; - /** Bandwidth of tuning band. */ + + /** + * Bandwidth of tuning band. + */ FrontendAtsc3Bandwidth bandwidth; + FrontendAtsc3DemodOutputFormat demodOutputFormat; + vec plpSettings; }; @@ -306,17 +422,34 @@ struct FrontendAtsc3Settings { * Capabilities for ATSC3 Frontend. */ struct FrontendAtsc3Capabilities { - /** Bandwidth capability */ + /** + * Bandwidth capability + */ bitfield bandwidthCap; - /** Modulation capability */ + + /** + * Modulation capability + */ bitfield modulationCap; - /** TimeInterleaveMode capability */ + + /** + * TimeInterleaveMode capability + */ bitfield timeInterleaveModeCap; - /** CodeRate capability */ + + /** + * CodeRate capability + */ bitfield codeRateCap; - /** FEC capability */ + + /** + * FEC capability + */ bitfield fecCap; - /** Demodulator Output Format capability */ + + /** + * Demodulator Output Format capability + */ bitfield demodOutputFormatCap; }; @@ -326,7 +459,9 @@ struct FrontendAtsc3Capabilities { @export enum FrontendDvbsModulation : int32_t { UNDEFINED = 0, - /** hardware is able to detect and set Modulation automatically */ + /** + * hardware is able to detect and set Modulation automatically + */ AUTO = 1 << 0, MOD_QPSK = 1 << 1, MOD_8PSK = 1 << 2, @@ -340,7 +475,9 @@ enum FrontendDvbsModulation : int32_t { MOD_64APSK = 1 << 10, MOD_128APSK = 1 << 11, MOD_256APSK = 1 << 12, - /** Reserved for Proprietary modulation */ + /** + * Reserved for Proprietary modulation + */ MOD_RESERVED = 1 << 13, }; @@ -374,10 +511,17 @@ enum FrontendDvbsPilot : uint32_t { */ struct FrontendDvbsCodeRate { FrontendInnerFec fec; + bool isLinear; - /* true if enable short frame */ + + /** + * true if enable short frame + */ bool isShortFrames; - /* bits number in 1000 symbol. 0 if use the default. */ + + /** + * bits number in 1000 symbol. 0 if use the default. + */ uint32_t bitsPer1000Symbol; }; @@ -396,15 +540,26 @@ enum FrontendDvbsStandard : uint8_t { * Signal Settings for an DVBS Frontend. */ struct FrontendDvbsSettings { - /** Signal frequency in Hertz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; + FrontendDvbsModulation modulation; + FrontendDvbsCodeRate coderate; - /** Symbols per second */ + + /** + * Symbols per second + */ uint32_t symbolRate; + FrontendDvbsRolloff rolloff; + FrontendDvbsPilot pilot; + uint32_t inputStreamId; + FrontendDvbsStandard standard; }; @@ -413,8 +568,10 @@ struct FrontendDvbsSettings { */ struct FrontendDvbsCapabilities { bitfield modulationCap; + bitfield innerfecCap; - bitfield standard; + + bitfield standard; }; /** @@ -423,7 +580,9 @@ struct FrontendDvbsCapabilities { @export enum FrontendDvbcModulation : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Modulation automatically */ + /** + * hardware is able to detect and set Modulation automatically + */ AUTO = 1 << 0, MOD_16QAM = 1 << 1, MOD_32QAM = 1 << 2, @@ -467,14 +626,24 @@ enum FrontendDvbcSpectralInversion : uint32_t { * Signal Settings for an DVBC Frontend. */ struct FrontendDvbcSettings { - /** Signal frequency in Hertz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; + FrontendDvbcModulation modulation; + FrontendInnerFec fec; - /** Symbols per second */ + + /** + * Symbols per second + */ uint32_t symbolRate; + FrontendDvbcOuterFec outerFec; + FrontendDvbcAnnex annex; + FrontendDvbcSpectralInversion spectralInversion; }; @@ -483,7 +652,9 @@ struct FrontendDvbcSettings { */ struct FrontendDvbcCapabilities { bitfield modulationCap; + bitfield fecCap; + bitfield annexCap; }; @@ -493,7 +664,9 @@ struct FrontendDvbcCapabilities { @export enum FrontendDvbtBandwidth : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Bandwidth automatically */ + /** + * hardware is able to detect and set Bandwidth automatically + */ AUTO = 1 << 0, BANDWIDTH_8MHZ = 1 << 1, BANDWIDTH_7MHZ = 1 << 2, @@ -509,7 +682,9 @@ enum FrontendDvbtBandwidth : uint32_t { @export enum FrontendDvbtConstellation : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Constellation automatically */ + /** + * hardware is able to detect and set Constellation automatically + */ AUTO = 1 << 0, CONSTELLATION_QPSK = 1 << 1, CONSTELLATION_16QAM = 1 << 2, @@ -523,7 +698,9 @@ enum FrontendDvbtConstellation : uint32_t { @export enum FrontendDvbtHierarchy : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Hierarchy automatically */ + /** + * hardware is able to detect and set Hierarchy automatically + */ AUTO = 1 << 0, HIERARCHY_NON_NATIVE = 1 << 1, HIERARCHY_1_NATIVE = 1 << 2, @@ -541,7 +718,9 @@ enum FrontendDvbtHierarchy : uint32_t { @export enum FrontendDvbtCoderate : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Hierarchy automatically */ + /** + * hardware is able to detect and set Hierarchy automatically + */ AUTO = 1 << 0, CODERATE_1_2 = 1 << 1, CODERATE_2_3 = 1 << 2, @@ -560,7 +739,9 @@ enum FrontendDvbtCoderate : uint32_t { @export enum FrontendDvbtGuardInterval : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Guard Interval automatically */ + /** + * hardware is able to detect and set Guard Interval automatically + */ AUTO = 1 << 0, INTERVAL_1_32 = 1 << 1, INTERVAL_1_16 = 1 << 2, @@ -577,7 +758,9 @@ enum FrontendDvbtGuardInterval : uint32_t { @export enum FrontendDvbtTransmissionMode : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Transmission Mode automatically */ + /** + * hardware is able to detect and set Transmission Mode automatically + */ AUTO = 1 << 0, MODE_2K = 1 << 1, MODE_8K = 1 << 2, @@ -607,27 +790,50 @@ enum FrontendDvbtStandard : uint8_t { }; /** - * Signal Setting for DVBT Frontend. + * Signal Settings for DVBT Frontend. */ struct FrontendDvbtSettings { - /** Signal frequency in Hertz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; + FrontendDvbtTransmissionMode transmissionMode; + FrontendDvbtBandwidth bandwidth; + FrontendDvbtConstellation constellation; + FrontendDvbtHierarchy hierarchy; - /** Code Rate for High Priority level */ + + /** + * Code Rate for High Priority level + */ FrontendDvbtCoderate hpCoderate; - /** Code Rate for Low Priority level */ + + /** + * Code Rate for Low Priority level + */ FrontendDvbtCoderate lpCoderate; + FrontendDvbtGuardInterval guardInterval; + bool isHighPriority; + FrontendDvbtStandard standard; + bool isMiso; + FrontendDvbtPlpMode plpMode; - /** Physical Layer Pipe (PLP) Id */ + + /** + * Physical Layer Pipe (PLP) Id + */ uint8_t plpId; - /** Group Id for Physical Layer Pipe (PLP) */ + + /** + * Group Id for Physical Layer Pipe (PLP) + */ uint8_t plpGroupId; }; @@ -636,12 +842,19 @@ struct FrontendDvbtSettings { */ struct FrontendDvbtCapabilities { bitfield transmissionModeCap; + bitfield bandwidthCap; + bitfield constellationCap; + bitfield coderateCap; + bitfield hierarchyCap; + bitfield guardIntervalCap; + bool isT2Supported; + bool isMisoSupported; }; @@ -660,11 +873,13 @@ enum FrontendIsdbsRolloff : uint32_t { @export enum FrontendIsdbsModulation : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Modulation automatically */ - AUTO = 1 << 0, - MOD_BPSK = 1 << 1, - MOD_QPSK = 1 << 2, - MOD_TC8PSK = 1 << 3, + /** + * hardware is able to detect and set Modulation automatically + */ + AUTO = 1 << 0, + MOD_BPSK = 1 << 1, + MOD_QPSK = 1 << 2, + MOD_TC8PSK = 1 << 3, }; /** @@ -673,13 +888,15 @@ enum FrontendIsdbsModulation : uint32_t { @export enum FrontendIsdbsCoderate : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Code Rate automatically */ - AUTO = 1 << 0, - CODERATE_1_2 = 1 << 1, - CODERATE_2_3 = 1 << 2, - CODERATE_3_4 = 1 << 3, - CODERATE_5_6 = 1 << 4, - CODERATE_7_8 = 1 << 5, + /** + * hardware is able to detect and set Code Rate automatically + */ + AUTO = 1 << 0, + CODERATE_1_2 = 1 << 1, + CODERATE_2_3 = 1 << 2, + CODERATE_3_4 = 1 << 3, + CODERATE_5_6 = 1 << 4, + CODERATE_7_8 = 1 << 5, }; /** @@ -692,17 +909,27 @@ enum FrontendIsdbsStreamIdType : uint32_t { }; /** - * Signal Setting for ISDBS Frontend. + * Signal Settings for ISDBS Frontend. */ struct FrontendIsdbsSettings { - /** Signal frequency in Hertz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; + uint16_t streamId; + FrontendIsdbsStreamIdType streamIdType; + FrontendIsdbsModulation modulation; + FrontendIsdbsCoderate coderate; - /** Symbols per second */ + + /** + * Symbols per second + */ uint32_t symbolRate; + FrontendIsdbsRolloff rolloff; }; @@ -711,6 +938,7 @@ struct FrontendIsdbsSettings { */ struct FrontendIsdbsCapabilities { bitfield modulationCap; + bitfield coderateCap; }; @@ -729,13 +957,15 @@ enum FrontendIsdbs3Rolloff : uint32_t { @export enum FrontendIsdbs3Modulation : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Modulation automatically */ - AUTO = 1 << 5, - MOD_BPSK = 1 << 1, - MOD_QPSK = 1 << 2, - MOD_8PSK = 1 << 3, - MOD_16APSK = 1 << 4, - MOD_32APSK = 1 << 5, + /** + * hardware is able to detect and set Modulation automatically + */ + AUTO = 1 << 5, + MOD_BPSK = 1 << 1, + MOD_QPSK = 1 << 2, + MOD_8PSK = 1 << 3, + MOD_16APSK = 1 << 4, + MOD_32APSK = 1 << 5, }; /** @@ -744,33 +974,45 @@ enum FrontendIsdbs3Modulation : uint32_t { @export enum FrontendIsdbs3Coderate : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Code Rate automatically */ - AUTO = 1 << 0, - CODERATE_1_3 = 1 << 1, - CODERATE_2_5 = 1 << 2, - CODERATE_1_2 = 1 << 3, - CODERATE_3_5 = 1 << 4, - CODERATE_2_3 = 1 << 5, - CODERATE_3_4 = 1 << 6, - CODERATE_7_9 = 1 << 7, - CODERATE_4_5 = 1 << 8, - CODERATE_5_6 = 1 << 9, - CODERATE_7_8 = 1 << 10, - CODERATE_9_10 = 1 << 11, + /** + * hardware is able to detect and set Code Rate automatically + */ + AUTO = 1 << 0, + CODERATE_1_3 = 1 << 1, + CODERATE_2_5 = 1 << 2, + CODERATE_1_2 = 1 << 3, + CODERATE_3_5 = 1 << 4, + CODERATE_2_3 = 1 << 5, + CODERATE_3_4 = 1 << 6, + CODERATE_7_9 = 1 << 7, + CODERATE_4_5 = 1 << 8, + CODERATE_5_6 = 1 << 9, + CODERATE_7_8 = 1 << 10, + CODERATE_9_10 = 1 << 11, }; /** - * Signal Setting for ISDBS3 Frontend. + * Signal Settings for ISDBS3 Frontend. */ struct FrontendIsdbs3Settings { - /** Signal frequency in Hertz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; + uint16_t streamId; + FrontendIsdbsStreamIdType streamIdType; + FrontendIsdbs3Modulation modulation; + FrontendIsdbs3Coderate coderate; - /** Symbols per second */ + + /** + * Symbols per second + */ uint32_t symbolRate; + FrontendIsdbs3Rolloff rolloff; }; @@ -779,6 +1021,7 @@ struct FrontendIsdbs3Settings { */ struct FrontendIsdbs3Capabilities { bitfield modulationCap; + bitfield coderateCap; }; @@ -788,7 +1031,9 @@ struct FrontendIsdbs3Capabilities { @export enum FrontendIsdbtMode : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Mode automatically */ + /** + * hardware is able to detect and set Mode automatically + */ AUTO = 1 << 0, MODE_1 = 1 << 1, MODE_2 = 1 << 2, @@ -801,7 +1046,9 @@ enum FrontendIsdbtMode : uint32_t { @export enum FrontendIsdbtBandwidth : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Bandwidth automatically */ + /** + * hardware is able to detect and set Bandwidth automatically + */ AUTO = 1 << 0, BANDWIDTH_8MHZ = 1 << 1, BANDWIDTH_7MHZ = 1 << 2, @@ -814,7 +1061,9 @@ enum FrontendIsdbtBandwidth : uint32_t { @export enum FrontendIsdbtModulation : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Modulation automatically */ + /** + * hardware is able to detect and set Modulation automatically + */ AUTO = 1 << 0, MOD_DQPSK = 1 << 1, MOD_QPSK = 1 << 2, @@ -822,23 +1071,29 @@ enum FrontendIsdbtModulation : uint32_t { MOD_64QAM = 1 << 4, }; -/** Code Rate for ISDBT. */ typedef FrontendDvbtCoderate FrontendIsdbtCoderate; -/** Guard Interval for ISDBT. */ typedef FrontendDvbtGuardInterval FrontendIsdbtGuardInterval; /** - * Signal Setting for ISDBT Frontend. + * Signal Settings for ISDBT Frontend. */ struct FrontendIsdbtSettings { - /** Signal frequency in Hertz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; + FrontendIsdbtModulation modulation; + FrontendIsdbtBandwidth bandwidth; + FrontendIsdbtMode mode; + FrontendIsdbtCoderate coderate; + FrontendIsdbtGuardInterval guardInterval; + uint32_t serviceAreaId; }; @@ -847,9 +1102,13 @@ struct FrontendIsdbtSettings { */ struct FrontendIsdbtCapabilities { bitfield modeCap; + bitfield bandwidthCap; + bitfield constellationCap; + bitfield coderateCap; + bitfield guardIntervalCap; }; @@ -872,7 +1131,7 @@ enum FrontendAnalogSifStandard : uint32_t { UNDEFINED = 0, BG = 1 << 0, BG_A2 = 1 << 1, - BG_NICAM = 1 << 2, + BG_NICAM = 1 << 2, I = 1 << 3, DK = 1 << 4, DK1 = 1 << 5, @@ -890,12 +1149,16 @@ enum FrontendAnalogSifStandard : uint32_t { }; /** - * Signal Setting for Analog Frontend. + * Signal Settings for Analog Frontend. */ struct FrontendAnalogSettings { - /** Signal frequency in Hertz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; + FrontendAnalogType type; + FrontendAnalogSifStandard sifStandard; }; @@ -904,21 +1167,30 @@ struct FrontendAnalogSettings { */ struct FrontendAnalogCapabilities { bitfield typeCap; + bitfield sifStandardCap; }; /** - * Signal Setting for Frontend. + * Signal Settings for Frontend. */ safe_union FrontendSettings { FrontendAnalogSettings analog; + FrontendAtscSettings atsc; + FrontendAtsc3Settings atsc3; + FrontendDvbsSettings dvbs; + FrontendDvbcSettings dvbc; + FrontendDvbtSettings dvbt; + FrontendIsdbsSettings isdbs; + FrontendIsdbs3Settings isdbs3; + FrontendIsdbtSettings isdbt; }; @@ -935,25 +1207,45 @@ enum FrontendScanType : uint32_t { * Scan Message Type for Frontend. */ enum FrontendScanMessageType : uint32_t { - /** Scan locked the signal. */ + /** + * Scan locked the signal. + */ LOCKED, - /** Scan stopped. */ + /** + * Scan stopped. + */ END, - /** Scan progress report. */ + /** + * Scan progress report. + */ PROGRESS_PERCENT, - /** Locked frequency report. */ + /** + * Locked frequency report. + */ FREQUENCY, - /** Locked symbol rate. */ + /** + * Locked symbol rate. + */ SYMBOL_RATE, - /** Locked Plp Ids for DVBT2 frontend. */ + /** + * Locked Plp Ids for DVBT2 frontend. + */ PLP_IDS, - /** Locked group Ids for DVBT2 frontend. */ + /** + * Locked group Ids for DVBT2 frontend. + */ GROUP_IDS, - /** Stream Ids. */ + /** + * Stream Ids. + */ INPUT_STREAM_IDS, - /** Locked signal standard. */ + /** + * Locked signal standard. + */ STANDARD, - /** PLP status in a tuned frequency band for ATSC3 frontend. */ + /** + * PLP status in a tuned frequency band for ATSC3 frontend. + */ ATSC3_PLP_INFO, }; @@ -962,6 +1254,7 @@ enum FrontendScanMessageType : uint32_t { */ struct FrontendScanAtsc3PlpInfo { uint8_t plpId; + bool bLlsFlag; }; @@ -970,21 +1263,39 @@ struct FrontendScanAtsc3PlpInfo { */ safe_union FrontendScanMessage { bool isLocked; + bool isEnd; - /** scan progress percent (0..100) */ + + /** + * scan progress percent (0..100) + */ uint8_t progressPercent; - /** Signal frequency in Hertz */ + + /** + * Signal frequency in Hertz + */ uint32_t frequency; - /** Symbols per second */ + + /** + * Symbols per second + */ uint32_t symbolRate; + vec plpIds; + vec groupIds; + vec inputStreamIds; + safe_union standard { FrontendDvbsStandard sStd; + FrontendDvbtStandard tStd; } std; - /** A list of PLP status in a tuned frequency band for ATSC3 frontend. */ + + /** + * A list of PLP status in a tuned frequency band for ATSC3 frontend. + */ vec atsc3PlpInfos; }; @@ -1008,22 +1319,6 @@ enum FrontendEventType : uint32_t { * event. */ LOST_LOCK, - /** - * If frontend detect that incoming Diseqc message is overflow. - */ - DISEQC_RX_OVERFLOW, - /** - * If frontend detect that outgoing Diseqc message isn't delivered on time. - */ - DISEQC_RX_TIMEOUT, - /** - * If frontend detect that the incoming Diseqc message has parity error. - */ - DISEQC_RX_PARITY_ERROR, - /** - * If frontend detect that the LNB is overload. - */ - LNB_OVERLOAD, }; /** @@ -1031,60 +1326,106 @@ enum FrontendEventType : uint32_t { */ @export enum FrontendStatusType : uint32_t { - /** Lock status for Demod. */ + /** + * Lock status for Demod. + */ DEMOD_LOCK, - /** Signal to Noise Ratio. */ + /** + * Signal to Noise Ratio. + */ SNR, - /** Bit Error Ratio. */ + /** + * Bit Error Ratio. + */ BER, - /** Packages Error Ratio. */ + /** + * Packages Error Ratio. + */ PER, - /** Bit Error Ratio before FEC. */ + /** + * Bit Error Ratio before FEC. + */ PRE_BER, - /* + /** * Signal Quality (0..100). Good data over total data in percent can be * used as a way to present Signal Quality. */ SIGNAL_QUALITY, - /** Signal Strength. */ + /** + * Signal Strength. + */ SIGNAL_STRENGTH, - /** Symbol Rate. */ + /** + * Symbol Rate. + */ SYMBOL_RATE, - /** Forward Error Correction Type. */ + /** + * Forward Error Correction Type. + */ FEC, - /** Modulation Type. */ + /** + * Modulation Type. + */ MODULATION, - /** Spectral Inversion Type. */ + /** + * Spectral Inversion Type. + */ SPECTRAL, - /** LNB Voltage. */ + /** + * LNB Voltage. + */ LNB_VOLTAGE, - /** Physical Layer Pipe ID. */ + /** + * Physical Layer Pipe ID. + */ PLP_ID, - /** Status for Emergency Warning Broadcasting System. */ + /** + * Status for Emergency Warning Broadcasting System. + */ EWBS, - /** Automatic Gain Control. */ + /** + * Automatic Gain Control. + */ AGC, - /** Low Noise Amplifier. */ + /** + * Low Noise Amplifier. + */ LNA, - /** Lock status for stream. */ - STREAM_LOCK, - /** Error status by layer. */ + /** + * Error status by layer. + */ LAYER_ERROR, - /** CN value by VBER. */ + /** + * CN value by VBER. + */ VBER_CN, - /** CN value by LBER. */ + /** + * CN value by LBER. + */ LBER_CN, - /** CN value by XER. */ + /** + * CN value by XER. + */ XER_CN, - /** Moduration Error Ratio. */ + /** + * Moduration Error Ratio. + */ MER, - /** Difference between tuning frequency and actual locked frequency. */ + /** + * Difference between tuning frequency and actual locked frequency. + */ FREQ_OFFSET, - /* Hierarchy for DVBT. */ + /** + * Hierarchy for DVBT. + */ HIERARCHY, - /** Lock status for RF. */ + /** + * Lock status for RF. + */ RF_LOCK, - /** PLP information in a frequency band for ATSC3.0 frontend. */ + /** + * PLP information in a frequency band for ATSC3.0 frontend. + */ ATSC3_PLP_INFO, }; @@ -1092,23 +1433,34 @@ enum FrontendStatusType : uint32_t { * Status for each tuning PLPs */ struct FrontendStatusAtsc3PlpInfo { - /** PLP Id value. */ + /** + * PLP Id value. + */ uint8_t plpId; - /** Demod Lock/Unlock status of this particular PLP. */ + + /** + * Demod Lock/Unlock status of this particular PLP. + */ bool isLocked; - /** Uncorrectable Error Counts (UEC) of this particular PLP since last tune operation. */ + + /** + * Uncorrectable Error Counts (UEC) of this particular PLP since last tune operation. + */ uint32_t uec; }; - /** * Modulation Type for Frontend's status. */ safe_union FrontendModulationStatus { FrontendDvbcModulation dvbc; + FrontendDvbsModulation dvbs; + FrontendIsdbsModulation isdbs; + FrontendIsdbs3Modulation isdbs3; + FrontendIsdbtModulation isdbt; }; @@ -1116,46 +1468,99 @@ safe_union FrontendModulationStatus { * The status for Frontend. */ safe_union FrontendStatus { - /** Lock status for Demod in True/False. */ + /** + * Lock status for Demod in True/False. + */ bool isDemodLocked; - /** SNR value measured by 0.001 dB. */ + + /** + * SNR value measured by 0.001 dB. + */ int32_t snr; - /** The number of error bit per 1 billion bits. */ + + /** + * The number of error bit per 1 billion bits. + */ uint32_t ber; - /** The number of error package per 1 billion packages. */ + + /** + * The number of error package per 1 billion packages. + */ uint32_t per; - /** The number of error bit per 1 billion bits before FEC. */ + + /** + * The number of error bit per 1 billion bits before FEC. + */ uint32_t preBer; - /** Signal Quality in percent. */ + + /** + * Signal Quality in percent. + */ uint32_t signalQuality; - /** Signal Strength measured by 0.001 dBm. */ + + /** + * Signal Strength measured by 0.001 dBm. + */ int32_t signalStrength; - /** Symbols per second */ + + /** + * Symbols per second + */ uint32_t symbolRate; + FrontendInnerFec innerFec; + FrontendModulationStatus modulation; + FrontendDvbcSpectralInversion inversion; - FrontendLnbVoltage lnbVoltage; + + LnbVoltage lnbVoltage; + uint8_t plpId; + bool isEWBS; - /** AGC value is normalized from 0 to 255. */ + + /** + * AGC value is normalized from 0 to 255. + */ uint8_t agc; + bool isLnaOn; - bool isStreamLock; + vec isLayerError; - /** CN value by VBER measured by 0.001 dB */ + + /** + * CN value by VBER measured by 0.001 dB + */ int32_t vberCn; - /** CN value by LBER measured by 0.001 dB */ + + /** + * CN value by LBER measured by 0.001 dB + */ int32_t lberCn; - /** CN value by XER measured by 0.001 dB */ + + /** + * CN value by XER measured by 0.001 dB + */ int32_t xerCn; - /** MER value measured by 0.001 dB */ + + /** + * MER value measured by 0.001 dB + */ int32_t mer; - /** Frequency difference in Hertz. */ + + /** + * Frequency difference in Hertz. + */ int32_t freqOffset; + FrontendDvbtHierarchy hierarchy; + bool isRfLocked; - /** A list of PLP status for tuned PLPs for ATSC3 frontend. */ + + /** + * A list of PLP status for tuned PLPs for ATSC3 frontend. + */ vec plpInfo; }; @@ -1164,32 +1569,60 @@ safe_union FrontendStatus { */ struct FrontendInfo { FrontendType type; - /** Frequency in Hertz */ + + /** + * Frequency in Hertz + */ uint32_t minFrequency; - /** Frequency in Hertz */ + + /** + * Frequency in Hertz + */ uint32_t maxFrequency; - /** Minimum symbols per second */ + + /** + * Minimum symbols per second + */ uint32_t minSymbolRate; - /** Maximum symbols per second */ + + /** + * Maximum symbols per second + */ uint32_t maxSymbolRate; - /** Range in Hertz */ + + /** + * Range in Hertz + */ uint32_t acquireRange; - /* + + /** * Frontends are assigned with the same exclusiveGroupId if they can't * function at same time. For instance, they share same hardware module. */ uint32_t exclusiveGroupId; - /** A list of supported status types which client can inquiry */ + + /** + * A list of supported status types which client can inquiry + */ vec statusCaps; + safe_union FrontendCapabilities { FrontendAnalogCapabilities analogCaps; + FrontendAtscCapabilities atscCaps; + FrontendAtsc3Capabilities atsc3Caps; + FrontendDvbsCapabilities dvbsCaps; + FrontendDvbcCapabilities dvbcCaps; + FrontendDvbtCapabilities dvbtCaps; + FrontendIsdbsCapabilities isdbsCaps; + FrontendIsdbs3Capabilities isdbs3Caps; + FrontendIsdbtCapabilities isdbtCaps; } frontendCaps; }; @@ -1204,7 +1637,7 @@ typedef uint32_t LnbId; * Power Voltage Type for LNB. */ @export -enum FrontendLnbVoltage : uint32_t { +enum LnbVoltage : uint32_t { NONE, VOLTAGE_5V, VOLTAGE_11V, @@ -1220,7 +1653,7 @@ enum FrontendLnbVoltage : uint32_t { * Tone Type for LNB. */ @export -enum FrontendLnbTone : int32_t { +enum LnbTone : int32_t { NONE, CONTINUOUS, }; @@ -1229,41 +1662,92 @@ enum FrontendLnbTone : int32_t { * The Position of LNB. */ @export -enum FrontendLnbPosition : int32_t { +enum LnbPosition : int32_t { UNDEFINED, POSITION_A, POSITION_B, }; +/** + * Lnb Event Type. + */ +@export +enum LnbEventType : uint32_t { + DISEQC_RX_OVERFLOW, + /** + * If LNB detect that outgoing Diseqc message isn't delivered on time. + */ + DISEQC_RX_TIMEOUT, + /** + * If LNB detect that the incoming Diseqc message has parity error. + */ + DISEQC_RX_PARITY_ERROR, + /** + * If LNB detect that the LNB is overload. + */ + LNB_OVERLOAD, +}; + /* Demux ID is used to associate with a hardware demux resource. */ typedef uint32_t DemuxId; -/* Filter ID is used to associate with a hardware filter resource. */ -typedef uint32_t DemuxFilterId; - /** - * Filter Type according to ISO/IEC 13818-1 + * Filter Main Type specifies the protocol that the filter use to extract data + * from input stream. */ @export -enum DemuxFilterType : uint32_t { +enum DemuxFilterMainType : uint32_t { /** - * A filter to filter section data out from input stream. + * Transport Stream according to ISO/IEC 13818-1. + */ + TS = 1 << 0, + /** + * MPEG Media Transport Protocol according to ISO/IEC 23008-1. + */ + MMTP = 1 << 1, + /** + * Internet Protocol. + */ + IP = 1 << 2, + /** + * Type Length Value according to ITU-R BT.1869. + */ + TLV = 1 << 3, + /** + * ATSC Link-Layer Protocol according to A/330 ATSC3.0. + */ + ALP = 1 << 4, +}; + +/** + * TS Filter Type according to ISO/IEC 13818-1 + */ +@export +enum DemuxTsFilterType : uint32_t { + UNDEFINED, + /** + * A filter to filter Section data out from input stream, and queue the + * data to the filter's FMQ (Fast Message Queue). */ SECTION, /** - * A filter to filter PES data out from input stream. + * A filter to filter Packetized Elementary Stream data out from input + * stream, and queue the data to the filter's FMQ. */ PES, /** - * A filter to filter TS payload out from input stream. + * A filter to filter a Transport Stream out from input stream, and queue + * the data to the filter's FMQ. */ TS, /** - * A filter to filter Audio Metadata out from input stream. + * A filter to filter Audio data out from input stream, and send Audio's + * Metadata to client through onFilterEvent. */ AUDIO, /** - * A filter to filter Video Metadata out from input stream. + * A filter to filter Video data out from input stream, and send Video's + * Metadata to client through onFilterEvent. */ VIDEO, /** @@ -1271,20 +1755,172 @@ enum DemuxFilterType : uint32_t { */ PCR, /** - * A filter to filter data directly to output buffer for record. + * A filter to filter data out from input stream, and queue the data to the + * buffer of the record. */ RECORD, }; +/** + * MMTP Filter Type according to ISO/IEC 23008-1 + */ +@export +enum DemuxMmtpFilterType : uint32_t { + UNDEFINED, + /** + * A filter to filter signaling data out from input stream, and queue the + * data to the filter's FMQ (Fast Message Queue). + */ + SECTION, + /** + * A filter to filter MFU (Media fragment unit) out from input stream, and + * queue the data to the filter's FMQ. + */ + PES, + /** + * A filter to filter a MMTP stream out from input stream, and queue the + * data to the filter's FMQ. + */ + MMTP, + /** + * A filter to filter Audio data out from input stream, and send Audio's + * Metadata to client through onFilterEvent. + */ + AUDIO, + /** + * A filter to filter Video data out from input stream, and send Video's + * Metadata to client through onFilterEvent. + */ + VIDEO, + /** + * A filter to filter data out from input stream, and queue the data to the + * buffer of the record. + */ + RECORD, + /** + * A filter to filter application data out from input stream, and queue the + * data to the filter's FMQ. + */ + DOWNLOAD, +}; + +/** + * IP Filter Type. + */ +@export +enum DemuxIpFilterType : uint32_t { + UNDEFINED, + /** + * A filter to filter section data out from input stream, and queue the + * data to the filter's FMQ (Fast Message Queue). + */ + SECTION, + /** + * A filter to set NTP (Network Time Procotol) channel from input stream. + */ + NTP, + /** + * A filter to strip out IP message header and queue the data to the + * filter's FMQ. + */ + IP_PAYLOAD, + /** + * A filter to filter a IP stream out from input stream. The output can be + * either upper stream of another filter or queued to the filter's FMQ. + */ + IP, + /** + * A filter to strip out IP message header and be a data source of another + * filter. + */ + PAYLOAD_THROUGH, +}; + +/** + * TLV Filter Type according to ITU-R BT.1869. + */ +@export +enum DemuxTlvFilterType : uint32_t { + UNDEFINED, + /** + * A filter to filter signaling data out from input stream, and queue the + * data to the filter's FMQ (Fast Message Queue). + */ + SECTION, + /** + * A filter to filter a TLV stream out from input stream. The output can be + * either upper stream of another filter or queued to the filter's FMQ. + */ + TLV, + /** + * A filter to strip out TLV message header and be a data source of another + * filter. + */ + PAYLOAD_THROUGH, +}; + +/** + * ALP Filter Type according to A/330 ATSC3.0. + */ +@export +enum DemuxAlpFilterType : uint32_t { + UNDEFINED, + /** + * A filter to filter signaling data out from input stream, and queue the + * data to the filter's FMQ (Fast Message Queue). + */ + SECTION, + /** + * A filter to set PTP (Precision Time Protocol) channel from input stream. + */ + PTP, + /** + * A filter to strip out ALP message header and be a data source of another + * filter. + */ + PAYLOAD_THROUGH, +}; + +/** + * Demux Filter Type. + */ +struct DemuxFilterType { + DemuxFilterMainType mainType; + + safe_union DemuxFilterSubType { + DemuxTsFilterType tsFilterType; + + DemuxMmtpFilterType mmtpFilterType; + + DemuxIpFilterType ipFilterType; + + DemuxTlvFilterType tlvFilterType; + + DemuxAlpFilterType alpFilterType; + } subType; +}; + /* Packet ID is used to specify packets in transport stream. */ typedef uint16_t DemuxTpid; +/* Packet ID is used to specify packets in MMTP */ +typedef uint16_t DemuxMmtpPid; + +/** + * Demux Packet ID. + */ +safe_union DemuxPid { + DemuxTpid tPid; + + DemuxMmtpPid mmtpPid; +}; + @export enum Constant : uint16_t { /** * An invalid packet ID in transport stream according to ISO/IEC 13818-1. */ - INVALID_TPID = 0xFFFF, + INVALID_TS_PID = 0xFFFF, /** * An invalid Stream ID. */ @@ -1304,7 +1940,7 @@ enum DemuxFilterStatus : uint8_t { * The available data amount in the filter buffer is at low level which is * set to 25 percent by default. */ - LOW_WATER = 1 << 1, + LOW_WATER = 1 << 1, /** * The available data amount in the filter buffer is at high level which is * set to 75 percent by default. @@ -1314,18 +1950,122 @@ enum DemuxFilterStatus : uint8_t { * The data in the filter buffer is full and newly filtered data is being * discarded. */ - OVERFLOW = 1 << 3, + OVERFLOW = 1 << 3, }; /** - * Bits Setting for Section Filter. + * Indexes can be tagged through TS (Transport Stream) header. + */ +@export +enum DemuxTsIndex : uint32_t { + FIRST_PACKET = 1 << 0, + PAYLOAD_UNIT_START_INDICATOR = 1 << 1, + CHANGE_TO_NOT_SCRAMBLED = 1 << 2, + CHANGE_TO_EVEN_SCRAMBLED = 1 << 3, + CHANGE_TO_ODD_SCRAMBLED = 1 << 4, + DISCONTINUITY_INDICATOR = 1 << 5, + RANDOM_ACCESS_INDICATOR = 1 << 6, + PRIORITY_INDICATOR = 1 << 7, + PCR_FLAG = 1 << 8, + OPCR_FLAG = 1 << 9, + SPLICING_POINT_FLAG = 1 << 10, + PRIVATE_DATA = 1 << 11, + ADAPTATION_EXTENSION_FLAG = 1 << 12, +}; + +/** + * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream) + * according to ISO/IEC 13818-1. + */ +@export +enum DemuxScIndex : uint32_t { + /** + * Start Code is for a new I Frame + */ + I_FRAME = 1 << 0, + /** + * Start Code is for a new P Frame + */ + P_FRAME = 1 << 1, + /** + * Start Code is for a new B Frame + */ + B_FRAME = 1 << 2, + /** + * Start Code is for a new Sequence + */ + SEQUENCE = 1 << 3, +}; + +/** + * Indexes can be tagged by NAL unit group in HEVC + * according to ISO/IEC 23008-2. + */ +@export +enum DemuxScHevcIndex : uint32_t { + SPS = 1 << 0, + AUD = 1 << 1, + SLICE_CE_BLA_W_LP = 1 << 2, + SLICE_BLA_W_RADL = 1 << 3, + SLICE_BLA_N_LP = 1 << 4, + SLICE_IDR_W_RADL = 1 << 5, + SLICE_IDR_N_LP = 1 << 6, + SLICE_TRAIL_CRA = 1 << 7, +}; + +/** + * Index type to be used in the filter for record + */ +@export +enum DemuxRecordIndexType : uint32_t { + /** + * Don't use index + */ + NONE, + /** + * Use TS index + */ + TS, + /** + * Use Start Code index + */ + SC, + /** + * Use Start Code index for HEVC + */ + SC_HEVC, +}; + +/** + * Filter Settings for Record data. + */ +struct DemuxFilterRecordSettings { + DemuxRecordIndexType indexType; + + safe_union IndexMask { + bitfield tsIndexMask; + + bitfield scIndexMask; + + bitfield scHevcIndexMask; + } indexMask; +}; + +/** + * Bits Settings for Section Filter. */ struct DemuxFilterSectionBits { - /* The bytes are configured for Section Filter */ + /** + * The bytes are configured for Section Filter + */ vec filter; - /* Active bits in the configured bytes to be used for filtering */ + + /** + * Active bits in the configured bytes to be used for filtering + */ vec mask; - /* + + /** * Do positive match at the bit position of the configured bytes when the * bit at same position of the mode is 0. * Do negative match at the bit position of the configured bytes when the @@ -1338,45 +2078,56 @@ struct DemuxFilterSectionBits { * Filter Settings for Section data according to ISO/IEC 13818-1. */ struct DemuxFilterSectionSettings { - DemuxTpid tpid; - DemuxFilterSectionBits bits; - /* Table ID for Section Filter */ - uint16_t tableId; - /* Version number for Section Filter */ - uint16_t version; - /* true if the filter checks CRC and discards data with wrong CRC */ + safe_union Condition { + DemuxFilterSectionBits sectionBits; + + struct TableInfo { + /** + * Table ID for Section Filter + */ + uint16_t tableId; + + /** + * Version number for Section Filter + */ + uint16_t version; + } tableInfo; + } condition; + + /** + * true if the filter checks CRC and discards data with wrong CRC + */ bool isCheckCrc; - /* true if the filter repeats the data with the same version */ + + /** + * true if the filter repeats the data with the same version + */ bool isRepeat; - /* true if the filter output raw data */ + + /** + * true if the filter send onFilterStatus instead of onFilterEvent. + */ bool isRaw; }; -/* Stream ID is used to specify one elementary stream */ typedef uint16_t DemuxStreamId; /** * Filter Settings for a PES Data. */ struct DemuxFilterPesDataSettings { - DemuxTpid tpid; DemuxStreamId streamId; - /* true if the filter output raw data */ + + /** + * true if the filter send onFilterStatus instead of onFilterEvent. + */ bool isRaw; }; /** - * Filter Settings for a TS Data. + * Filter Settings for a Video and Audio. */ -struct DemuxFilterTsSettings { - DemuxTpid tpid; -}; - -/** - * Filter Settings for a Audio. - */ -struct DemuxFilterAudioSettings { - DemuxTpid tpid; +struct DemuxFilterAvSettings { /** * true if the filter output goes to decoder directly in pass through mode. */ @@ -1384,107 +2135,181 @@ struct DemuxFilterAudioSettings { }; /** - * Filter Settings for a Video. + * Filter Settings for a Download. */ -struct DemuxFilterVideoSettings { +struct DemuxFilterDownloadSettings { + uint32_t downloadId; +}; + +/** + * IP Settings for a IP filter. + */ +struct DemuxIpAddress { + safe_union SrcIpAddress { + uint8_t[4] v4; + + uint8_t[16] v6; + } srcIpAddress; + + safe_union DstIpAddress { + uint8_t[4] v4; + + uint8_t[16] v6; + } dstIpAddress; + + uint16_t srcPort; + + uint16_t dstPort; +}; + +/** + * Filter Settings for a TS filter. + */ +struct DemuxTsFilterSettings { DemuxTpid tpid; + + safe_union FilterSettings { + /** + * Not additional parameters. it's used by PCR, TS subtype filters. + */ + Monostate noinit; + + DemuxFilterSectionSettings section; + + DemuxFilterAvSettings av; + + DemuxFilterPesDataSettings pesData; + + DemuxFilterRecordSettings record; + } filterSettings; +}; + +/** + * Filter Settings for a MMTP filter. + */ +struct DemuxMmtpFilterSettings { + DemuxMmtpPid mmtpPid; + + safe_union FilterSettings { + /** + * Not additional parameters. it's used by MMTP subtype filters. + */ + Monostate noinit; + + DemuxFilterSectionSettings section; + + DemuxFilterAvSettings av; + + DemuxFilterPesDataSettings pesData; + + DemuxFilterRecordSettings record; + + DemuxFilterDownloadSettings download; + } filterSettings; +}; + +/** + * Filter Settings for a IP filter. + */ +struct DemuxIpFilterSettings { + DemuxIpAddress ipAddr; + + safe_union FilterSettings { + /** + * Not additional parameters. it's used by NTP, IP_PAYLOAD, + * PAYLOAD_THROUGH subtype filters. + */ + Monostate noinit; + + DemuxFilterSectionSettings section; + + DemuxFilterPesDataSettings pesData; + + /** + * true if the data from IP subtype go to next filter directly + */ + bool bPassthrough; + } filterSettings; +}; + +/** + * Filter Settings for a TLV filter. + */ +struct DemuxTlvFilterSettings { + uint8_t packetType; + /** - * true if the filter output goes to decoder directly in pass through mode. + * true if the filtered data is commpressed ip packet */ - bool isPassthrough; + bool bIsCompressedIpPacket; + + safe_union FilterSettings { + /** + * Not additional parameters. it's used by PAYLOAD_THROUGH subtype + * filters. + */ + Monostate noinit; + + DemuxFilterSectionSettings section; + + /** + * true if the data from TLV subtype go to next filter directly + */ + bool bPassthrough; + } filterSettings; }; /** - * Filter Settings for a PCR (Program Clock Reference). - */ -struct DemuxFilterPcrSettings { - DemuxTpid tpid; -}; - -/** - * Indexes can be tagged through TS (Transport Stream) header. + * ALP Length Type */ @export -enum DemuxTsIndex : uint32_t { - FIRST_PACKET = 1 << 0, - PAYLOAD_UNIT_START_INDICATOR = 1 << 1, - CHANGE_TO_NOT_SCRAMBLED = 1 << 2, - CHANGE_TO_EVEN_SCRAMBLED = 1 << 3, - CHANGE_TO_ODD_SCRAMBLED = 1 << 4, - DISCONTINUITY_INDICATOR = 1 << 5, - RANDOM_ACCESS_INDICATOR = 1 << 6, - PRIORITY_INDICATOR = 1 << 7, - PCR_FLAG = 1 << 8, - OPCR_FLAG = 1 << 9, - SPLICING_POINT_FLAG = 1 << 10, - PRIVATE_DATA = 1 << 11, - ADAPTATION_EXTENSION_FLAG = 1 << 12, +enum DemuxAlpLengthType : uint8_t { + UNDEFINED = 0, + /** + * Length does NOT include additional header. Used in US region. + */ + WITHOUT_ADDITIONAL_HEADER, + /** + * Length includes additional header. Used in Korea region. + */ + WITH_ADDITIONAL_HEADER, }; /** - * A mask of TS indexes - * - * It's a combination of TS indexes. + * Filter Settings for a ALP filter. */ -typedef bitfield DemuxTsIndexMask; +struct DemuxAlpFilterSettings { + /** + * 0: IpV4, 2:Compressed Ip, 4:Signaling. + */ + uint8_t packetType; -/** - * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream) - * according to ISO/IEC 13818-1. - */ -@export -enum DemuxScIndex : uint32_t { - /* Start Code is for a new I Frame */ - I_FRAME = 1 << 0, - /* Start Code is for a new P Frame */ - P_FRAME = 1 << 1, - /* Start Code is for a new B Frame */ - B_FRAME = 1 << 2, - /* Start Code is for a new Sequence */ - SEQUENCE = 1 << 3, -}; + DemuxAlpLengthType lengthType; -/** - * A mask of Start Code Indexes - * - * It's a combination of Start Code Indexes. - */ -typedef bitfield DemuxScIndexMask; + safe_union FilterSettings { + /** + * Not additional parameters. it's used by PTP, PAYLOAD_THROUGH subtype + * filters. + */ + Monostate noinit; -/* Index type to be used in the filter for record */ -@export -enum DemuxRecordIndexType : uint32_t { - /* Don't use index */ - NONE, - /* Use TS index */ - TS, - /* Use Start Code index */ - SC, -}; - -/** - * Filter Settings for Record data. - */ -struct DemuxFilterRecordSettings { - DemuxTpid tpid; - DemuxRecordIndexType indexType; - safe_union IndexMask { - DemuxTsIndexMask tsIndexMask; - DemuxScIndexMask scIndexMask; - } indexMask; + DemuxFilterSectionSettings section; + } filterSettings; }; /** * Filter Settings. */ safe_union DemuxFilterSettings { - DemuxFilterSectionSettings section; - DemuxFilterPesDataSettings pesData; - DemuxFilterTsSettings ts; - DemuxFilterAudioSettings audio; - DemuxFilterVideoSettings video; - DemuxFilterPcrSettings pcr; - DemuxFilterRecordSettings record; + DemuxTsFilterSettings ts; + + DemuxMmtpFilterSettings mmtp; + + DemuxIpFilterSettings ip; + + DemuxTlvFilterSettings tlv; + + DemuxAlpFilterSettings alp; }; /** @@ -1493,38 +2318,106 @@ safe_union DemuxFilterSettings { */ @export enum DemuxQueueNotifyBits : uint32_t { - /* client writes data and notify HAL the data is ready. */ + /** + * client writes data and notify HAL the data is ready. + */ DATA_READY = 1 << 0, - /* client reads data and notify HAL the data is consumed. */ - DATA_CONSUMED = 1 << 1 + /** + * client reads data and notify HAL the data is consumed. + */ + DATA_CONSUMED = 1 << 1, }; /** * Filter Event for Section Filter. */ struct DemuxFilterSectionEvent { - /* Table ID of filtered data */ + /** + * Table ID of filtered data + */ uint16_t tableId; - /* Version number of filtered data */ + + /** + * Version number of filtered data + */ uint16_t version; - /* Section number of filtered data */ + + /** + * Section number of filtered data + */ uint16_t sectionNum; - /* Data size in bytes of filtered data */ + + /** + * Data size in bytes of filtered data + */ uint16_t dataLength; }; +/** + * Extra Meta Data from AD (Audio Descriptor) according to + * ETSI TS 101 154 V2.1.1. + */ +struct AudioExtraMetaData { + uint8_t adFade; + + uint8_t adPan; + + uint8_t versionTextTag; + + uint8_t adGainCenter; + + uint8_t adGainFront; + + uint8_t adGainSurround; +}; + /** * Filter Event for Audio or Video Filter. */ struct DemuxFilterMediaEvent { - /* Presentation Time Stamp for audio or video frame. It based on 90KHz has + DemuxStreamId streamId; + + /** + * true if PTS is present in PES header. + */ + bool isPtsPresent; + + /** + * Presentation Time Stamp for audio or video frame. It based on 90KHz has * the same format as PTS (Presentation Time Stamp). */ uint64_t pts; - /* Data size in bytes of audio or video frame */ - uint16_t dataLength; - /* A handle associated to the memory where audio or video data stays. */ - handle secureMemory; + + /** + * Data size in bytes of audio or video frame + */ + uint32_t dataLength; + + /** + * A handle associated to the memory where audio or video data stays. + */ + handle avMemory; + + /** + * True if the avMemory is in secure area, and isn't mappable. + */ + bool isSecureMemory; + + /** + * MPU sequence number of filtered data (only for MMTP) + */ + uint32_t mpuSequenceNumber; + + bool isPesPrivateData; + + safe_union ExtraMetaData { + /** + * Not additional parameters. it's used for video. + */ + Monostate noinit; + + AudioExtraMetaData audio; + } extraMetaData; }; /** @@ -1532,176 +2425,309 @@ struct DemuxFilterMediaEvent { */ struct DemuxFilterPesEvent { DemuxStreamId streamId; - /* Data size in bytes of PES data */ + + /** + * Data size in bytes of PES data + */ + uint16_t dataLength; + + /** + * MPU sequence number of filtered data (only for MMTP) + */ + uint32_t mpuSequenceNumber; +}; + +/** + * Filter Event for TS Record data. + */ +struct DemuxFilterTsRecordEvent { + DemuxPid pid; + + /** + * Indexes of record output + */ + safe_union IndexMask { + bitfield tsIndexMask; + + bitfield scIndexMask; + + bitfield scHevcIndexMask; + } indexMask; + + /** + * Byte number from beginning of the filter's output + */ + uint64_t byteNumber; +}; + +/** + * Filter Event for MMTP Record data. + */ +struct DemuxFilterMmtpRecordEvent { + bitfield scHevcIndexMask; + + /** + * Byte number from beginning of the filter's output + */ + uint64_t byteNumber; +}; + +/** + * Filter Event for Download data. + */ +struct DemuxFilterDownloadEvent { + uint32_t itemId; + + /** + * MPU sequence number of filtered data (only for MMTP) + */ + uint32_t mpuSequenceNumber; + + uint32_t itemFragmentIndex; + + uint32_t lastItemFragmentIndex; + + /** + * Data size in bytes of filtered data + */ uint16_t dataLength; }; /** - * Filter Event for Record data. + * Filter Event for IP payload data. */ -struct DemuxFilterRecordEvent { - DemuxTpid tpid; - /* Indexes of record output */ - safe_union IndexMask { - DemuxTsIndexMask tsIndexMask; - DemuxScIndexMask scIndexMask; - } indexMask; - /* Packet number from beginning of the filter's output */ - uint64_t packetNum; +struct DemuxFilterIpPayloadEvent { + /** + * Data size in bytes of IP data + */ + uint16_t dataLength; }; /** * Filter Event. */ struct DemuxFilterEvent { - DemuxFilterId filterId; - DemuxFilterType filterType; safe_union Event { DemuxFilterSectionEvent section; + DemuxFilterMediaEvent media; + DemuxFilterPesEvent pes; - DemuxFilterRecordEvent ts; + + DemuxFilterTsRecordEvent tsRecord; + + DemuxFilterMmtpRecordEvent mmtpRecord; + + DemuxFilterDownloadEvent download; + + DemuxFilterIpPayloadEvent ipPayload; }; - /* An array of events */ + + /** + * An array of events + */ vec events; }; -/** - * A hardware resource ID to be used for audio and video hardware sync. - */ typedef uint32_t AvSyncHwId; -/** - * A token to be used to link descrambler and key slot. It's opaque to - * framework and apps. - */ typedef vec TunerKeyToken; /** * A data format in demux's output or input according to ISO/IEC 13818-1. */ @export -enum DemuxDataFormat : uint32_t { - /* Data is Transport Stream. */ +enum DataFormat : uint32_t { + /** + * Data is Transport Stream. + */ TS, - /* Data is Packetized Elementary Stream. */ + /** + * Data is Packetized Elementary Stream. + */ PES, - /* Data is Elementary Stream. */ + /** + * Data is Elementary Stream. + */ ES, - /* Data is TLV (type-length-value) Stream for JP SHV */ + /** + * Data is TLV (type-length-value) Stream for JP SHV + */ SHV_TLV, }; -/** - * A status of the demux's output. - */ -typedef DemuxFilterStatus DemuxOutputStatus; +typedef DemuxFilterStatus RecordStatus; /** - * The Settings for the demux's output. + * The Settings for the record in DVR. */ -struct DemuxOutputSettings { +struct RecordSettings { /** * Register for interested status events so that the HAL can send these * status events back to client. */ - bitfield statusMask; + bitfield statusMask; + /** - * Unconsumed data size in bytes in the output. The HAL uses it to trigger - * DemuxOutputStatus::LOW_WATER. + * Unconsumed data size in bytes in the record. The HAL uses it to trigger + * OutputStatus::LOW_WATER. */ uint32_t lowThreshold; + /** - * Unconsumed data size in bytes in the output. The HAL uses it to trigger - * DemuxOutputStatus::High_WATER. + * Unconsumed data size in bytes in the record. The HAL uses it to trigger + * OutputStatus::High_WATER. */ uint32_t highThreshold; + /** - * The data format in the output. + * The data format in the record. */ - DemuxDataFormat dataFormat; + DataFormat dataFormat; + /** - * The packet size in bytes in the output. + * The packet size in bytes in the record. */ uint8_t packetSize; }; /** - * A status of the demux's input. + * A status of the playback in DVR. */ @export -enum DemuxInputStatus : uint32_t { +enum PlaybackStatus : uint32_t { /** - * The space of the demux's input is empty. + * The space of the demux's playback is empty. */ - SPACE_EMPTY = 1 << 0, + SPACE_EMPTY = 1 << 0, /** - * The spece of the demux's input is almost empty. + * The spece of the demux's playback is almost empty. */ SPACE_ALMOST_EMPTY = 1 << 1, /** - * The space of the demux's input is almost full. + * The space of the demux's playback is almost full. */ - SPACE_ALMOST_FULL = 1 << 2, + SPACE_ALMOST_FULL = 1 << 2, /** - * The space of the demux's input is full. + * The space of the demux's playback is full. */ - SPACE_FULL = 1 << 3, + SPACE_FULL = 1 << 3, }; /** - * The Settings for the demux's input. + * The Setting for the playback in DVR. */ -@export -struct DemuxInputSettings { +struct PlaybackSettings { /** * Register for interested status events so that the HAL can send these * status events back to client. */ - bitfield statusMask; + bitfield statusMask; + /** - * Unused space size in bytes in the input. The HAL uses it to trigger - * DemuxInputStatus::SPACE_ALMOST_EMPTY. + * Unused space size in bytes in the playback. The HAL uses it to trigger + * InputStatus::SPACE_ALMOST_EMPTY. */ uint32_t lowThreshold; + /** - * Unused space size in bytes in the input. The HAL uses it to trigger - * DemuxInputStatus::SPACE_ALMOST_FULL. + * Unused space size in bytes in the playback. The HAL uses it to trigger + * InputStatus::SPACE_ALMOST_FULL. */ uint32_t highThreshold; + /** - * The data format in the input. + * The data format in the playback. */ - DemuxDataFormat dataFormat; + DataFormat dataFormat; + /** - * The packet size in bytes in the input. + * The packet size in bytes in the playback. */ uint8_t packetSize; }; +/** + * The type of DVR. + */ +@export +enum DvrType : uint8_t { + RECORD, + PLAYBACK, +}; + +/** + * The Setting for DVR. + */ +safe_union DvrSettings { + RecordSettings record; + + PlaybackSettings playback; +}; + /** * Capabilities for Demux. */ -@export struct DemuxCapabilities { - /* The number of Demux to be supported. */ + /** + * The number of Demux to be supported. + */ uint32_t numDemux; - /* The number of Input to be supported. */ - uint32_t numInput; - /* The number of Output to be supported. */ - uint32_t numOutput; - /* The number of TS Filter to be supported. */ + + /** + * The number of record to be supported. + */ + uint32_t numRecord; + + /** + * The number of playback to be supported. + */ + uint32_t numPlayback; + + /** + * The number of TS Filter to be supported. + */ uint32_t numTsFilter; - /* The number of Section Filter to be supported. */ + + /** + * The number of Section Filter to be supported. + */ uint32_t numSectionFilter; - /* The number of Audio Filter to be supported. */ + + /** + * The number of Audio Filter to be supported. + */ uint32_t numAudioFilter; - /* The number of Video Filter to be supported. */ + + /** + * The number of Video Filter to be supported. + */ uint32_t numVideoFilter; - /* The number of PES Filter to be supported. */ + + /** + * The number of PES Filter to be supported. + */ uint32_t numPesFilter; - /* The number of PCR Filter to be supported. */ + + /** + * The number of PCR Filter to be supported. + */ uint32_t numPcrFilter; - /* The maximum number of bytes is supported in the mask of Section Filter. */ + + /** + * The maximum number of bytes is supported in the mask of Section Filter. + */ uint32_t numBytesInSectionFilter; + + bitfield filterCaps; + + /** + * The array has same elements as DemuxFilterMainType. linkCaps[i] presents + * filter's capability as soource for the ith type in DemuxFilterMainType. + * The jth bit of linkCaps[i] is 1 if the output of ith type filter can be + * data source for the filter type j. + */ + vec> linkCaps; + + bool bTimeFilter; }; From b4b680167cea86095c141273ba4f9be7f2d25b7d Mon Sep 17 00:00:00 2001 From: Amy Date: Tue, 15 Oct 2019 17:38:19 -0700 Subject: [PATCH 0212/1022] Refactor Tuner HAL Default Impl for Filter and Dvr separation Test: manual Bug: 135709325 Change-Id: I130f555315683fa02272f40d1e6209c5695c884a --- tv/tuner/1.0/default/Android.bp | 3 + tv/tuner/1.0/default/Demux.cpp | 732 ++------------------------- tv/tuner/1.0/default/Demux.h | 150 +----- tv/tuner/1.0/default/Descrambler.cpp | 6 +- tv/tuner/1.0/default/Descrambler.h | 6 +- tv/tuner/1.0/default/Dvr.cpp | 280 ++++++++++ tv/tuner/1.0/default/Dvr.h | 151 ++++++ tv/tuner/1.0/default/Filter.cpp | 456 +++++++++++++++++ tv/tuner/1.0/default/Filter.h | 179 +++++++ tv/tuner/1.0/default/Frontend.h | 2 +- tv/tuner/1.0/default/Lnb.cpp | 12 +- tv/tuner/1.0/default/Lnb.h | 15 +- tv/tuner/1.0/default/TimeFilter.cpp | 78 +++ tv/tuner/1.0/default/TimeFilter.h | 69 +++ 14 files changed, 1315 insertions(+), 824 deletions(-) create mode 100644 tv/tuner/1.0/default/Dvr.cpp create mode 100644 tv/tuner/1.0/default/Dvr.h create mode 100644 tv/tuner/1.0/default/Filter.cpp create mode 100644 tv/tuner/1.0/default/Filter.h create mode 100644 tv/tuner/1.0/default/TimeFilter.cpp create mode 100644 tv/tuner/1.0/default/TimeFilter.h diff --git a/tv/tuner/1.0/default/Android.bp b/tv/tuner/1.0/default/Android.bp index 0ae8bcdac8..989e25c6e3 100644 --- a/tv/tuner/1.0/default/Android.bp +++ b/tv/tuner/1.0/default/Android.bp @@ -4,9 +4,12 @@ cc_defaults { vendor: true, relative_install_path: "hw", srcs: [ + "Filter.cpp", "Frontend.cpp", "Descrambler.cpp", "Demux.cpp", + "Dvr.cpp", + "TimeFilter.cpp", "Tuner.cpp", "Lnb.cpp", "service.cpp", diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp index 8bb79f9702..c5921f74a9 100644 --- a/tv/tuner/1.0/default/Demux.cpp +++ b/tv/tuner/1.0/default/Demux.cpp @@ -28,45 +28,6 @@ namespace implementation { #define WAIT_TIMEOUT 3000000000 -const std::vector fakeDataInputBuffer{ - 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb, - 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03, - 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06, - 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, - 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, - 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d, - 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63, - 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, - 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, - 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, - 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20, - 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, - 0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d, - 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65, - 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31, - 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e, - 0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20, - 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, - 0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69, - 0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71, - 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, - 0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d, - 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, - 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, - 0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68, - 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f, - 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, - 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79, - 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, - 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20, - 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68, - 0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30, - 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20, - 0x73, 0x63, 0x65, 0x6e, 0x65, -}; - Demux::Demux(uint32_t demuxId, sp tuner) { mDemuxId = demuxId; mTunerService = tuner; @@ -93,8 +54,8 @@ Return Demux::setFrontendDataSource(uint32_t frontendId) { return startBroadcastInputLoop(); } -Return Demux::addFilter(DemuxFilterType type, uint32_t bufferSize, - const sp& cb, addFilter_cb _hidl_cb) { +Return Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize, + const sp& cb, openFilter_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); uint32_t filterId; @@ -105,137 +66,39 @@ Return Demux::addFilter(DemuxFilterType type, uint32_t bufferSize, mUnusedFilterIds.erase(filterId); } else { filterId = ++mLastUsedFilterId; - - mFilterCallbacks.resize(filterId + 1); - mFilterMQs.resize(filterId + 1); - mFilterEvents.resize(filterId + 1); - mFilterEventFlags.resize(filterId + 1); - mFilterThreadRunning.resize(filterId + 1); - mFilterThreads.resize(filterId + 1); - mFilterPids.resize(filterId + 1); - mFilterOutputs.resize(filterId + 1); - mFilterStatus.resize(filterId + 1); } mUsedFilterIds.insert(filterId); - if ((type != DemuxFilterType::PCR || type != DemuxFilterType::TS) && cb == nullptr) { + if (cb == nullptr) { ALOGW("callback can't be null"); - _hidl_cb(Result::INVALID_ARGUMENT, filterId); + _hidl_cb(Result::INVALID_ARGUMENT, new Filter()); return Void(); } - // Add callback - mFilterCallbacks[filterId] = cb; + sp filter = new Filter(type, filterId, bufferSize, cb, this); - // Mapping from the filter ID to the filter event - DemuxFilterEvent event{ - .filterId = filterId, - .filterType = type, - }; - mFilterEvents[filterId] = event; - - if (!createFilterMQ(bufferSize, filterId)) { - _hidl_cb(Result::UNKNOWN_ERROR, -1); + if (!filter->createFilterMQ()) { + _hidl_cb(Result::UNKNOWN_ERROR, filter); return Void(); } - _hidl_cb(Result::SUCCESS, filterId); + mFilters[filterId] = filter; + + _hidl_cb(Result::SUCCESS, filter); return Void(); } -Return Demux::getFilterQueueDesc(uint32_t filterId, getFilterQueueDesc_cb _hidl_cb) { +Return Demux::openTimeFilter(openTimeFilter_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); - if (mUsedFilterIds.find(filterId) == mUsedFilterIds.end()) { - ALOGW("No filter with id: %d exists to get desc", filterId); - _hidl_cb(Result::INVALID_ARGUMENT, FilterMQ::Descriptor()); - return Void(); - } + sp timeFilter = new TimeFilter(this); - _hidl_cb(Result::SUCCESS, *mFilterMQs[filterId]->getDesc()); + _hidl_cb(Result::SUCCESS, timeFilter); return Void(); } -Return Demux::configureFilter(uint32_t filterId, const DemuxFilterSettings& settings) { - ALOGV("%s", __FUNCTION__); - - switch (mFilterEvents[filterId].filterType) { - case DemuxFilterType::SECTION: - mFilterPids[filterId] = settings.section().tpid; - break; - case DemuxFilterType::PES: - mFilterPids[filterId] = settings.pesData().tpid; - break; - case DemuxFilterType::TS: - mFilterPids[filterId] = settings.ts().tpid; - break; - case DemuxFilterType::AUDIO: - mFilterPids[filterId] = settings.audio().tpid; - break; - case DemuxFilterType::VIDEO: - mFilterPids[filterId] = settings.video().tpid; - break; - case DemuxFilterType::RECORD: - mFilterPids[filterId] = settings.record().tpid; - break; - case DemuxFilterType::PCR: - mFilterPids[filterId] = settings.pcr().tpid; - break; - default: - return Result::UNKNOWN_ERROR; - } - return Result::SUCCESS; -} - -Return Demux::startFilter(uint32_t filterId) { - ALOGV("%s", __FUNCTION__); - Result result; - - if (mUsedFilterIds.find(filterId) == mUsedFilterIds.end()) { - ALOGW("No filter with id: %d exists to start filter", filterId); - return Result::INVALID_ARGUMENT; - } - - result = startFilterLoop(filterId); - - return result; -} - -Return Demux::stopFilter(uint32_t filterId) { - ALOGV("%s", __FUNCTION__); - - mFilterThreadRunning[filterId] = false; - - std::lock_guard lock(mFilterThreadLock); - - return Result::SUCCESS; -} - -Return Demux::flushFilter(uint32_t filterId) { - ALOGV("%s", __FUNCTION__); - - // temp implementation to flush the FMQ - int size = mFilterMQs[filterId]->availableToRead(); - char* buffer = new char[size]; - mOutputMQ->read((unsigned char*)&buffer[0], size); - delete[] buffer; - mFilterStatus[filterId] = DemuxFilterStatus::DATA_READY; - - return Result::SUCCESS; -} - -Return Demux::removeFilter(uint32_t filterId) { - ALOGV("%s", __FUNCTION__); - - // resetFilterRecords(filterId); - mUsedFilterIds.erase(filterId); - mUnusedFilterIds.insert(filterId); - - return Result::SUCCESS; -} - -Return Demux::getAvSyncHwId(uint32_t /* filterId */, getAvSyncHwId_cb _hidl_cb) { +Return Demux::getAvSyncHwId(const sp& /* filter */, getAvSyncHwId_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); AvSyncHwId avSyncHwId = 0; @@ -256,588 +119,81 @@ Return Demux::getAvSyncTime(AvSyncHwId /* avSyncHwId */, getAvSyncTime_cb Return Demux::close() { ALOGV("%s", __FUNCTION__); - set::iterator it; - mInputThread = 0; - mOutputThread = 0; - mFilterThreads.clear(); mUnusedFilterIds.clear(); mUsedFilterIds.clear(); - mFilterCallbacks.clear(); - mFilterMQs.clear(); - mFilterEvents.clear(); - mFilterEventFlags.clear(); - mFilterOutputs.clear(); - mFilterPids.clear(); mLastUsedFilterId = -1; return Result::SUCCESS; } -Return Demux::addOutput(uint32_t bufferSize, const sp& cb) { +Return Demux::openDvr(DvrType type, uint32_t bufferSize, const sp& cb, + openDvr_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); - // Create a synchronized FMQ that supports blocking read/write - std::unique_ptr tmpFilterMQ = - std::unique_ptr(new (std::nothrow) FilterMQ(bufferSize, true)); - if (!tmpFilterMQ->isValid()) { - ALOGW("Failed to create output FMQ"); - return Result::UNKNOWN_ERROR; - } - - mOutputMQ = std::move(tmpFilterMQ); - - if (EventFlag::createEventFlag(mOutputMQ->getEventFlagWord(), &mOutputEventFlag) != OK) { - return Result::UNKNOWN_ERROR; - } - - mOutputCallback = cb; - - return Result::SUCCESS; -} - -Return Demux::getOutputQueueDesc(getOutputQueueDesc_cb _hidl_cb) { - ALOGV("%s", __FUNCTION__); - - if (!mOutputMQ) { - _hidl_cb(Result::NOT_INITIALIZED, FilterMQ::Descriptor()); + if (cb == nullptr) { + ALOGW("DVR callback can't be null"); + _hidl_cb(Result::INVALID_ARGUMENT, new Dvr()); return Void(); } - _hidl_cb(Result::SUCCESS, *mOutputMQ->getDesc()); - return Void(); -} + sp dvr = new Dvr(type, bufferSize, cb, this); -Return Demux::configureOutput(const DemuxOutputSettings& settings) { - ALOGV("%s", __FUNCTION__); - - mOutputConfigured = true; - mOutputSettings = settings; - return Result::SUCCESS; -} - -Return Demux::attachOutputFilter(uint32_t /*filterId*/) { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Demux::detachOutputFilter(uint32_t /* filterId */) { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Demux::startOutput() { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Demux::stopOutput() { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Demux::flushOutput() { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Demux::removeOutput() { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Demux::addInput(uint32_t bufferSize, const sp& cb) { - ALOGV("%s", __FUNCTION__); - - // Create a synchronized FMQ that supports blocking read/write - std::unique_ptr tmpInputMQ = - std::unique_ptr(new (std::nothrow) FilterMQ(bufferSize, true)); - if (!tmpInputMQ->isValid()) { - ALOGW("Failed to create input FMQ"); - return Result::UNKNOWN_ERROR; - } - - mInputMQ = std::move(tmpInputMQ); - - if (EventFlag::createEventFlag(mInputMQ->getEventFlagWord(), &mInputEventFlag) != OK) { - return Result::UNKNOWN_ERROR; - } - - mInputCallback = cb; - - return Result::SUCCESS; -} - -Return Demux::getInputQueueDesc(getInputQueueDesc_cb _hidl_cb) { - ALOGV("%s", __FUNCTION__); - - if (!mInputMQ) { - _hidl_cb(Result::NOT_INITIALIZED, FilterMQ::Descriptor()); + if (!dvr->createDvrMQ()) { + _hidl_cb(Result::UNKNOWN_ERROR, dvr); return Void(); } - _hidl_cb(Result::SUCCESS, *mInputMQ->getDesc()); + _hidl_cb(Result::SUCCESS, dvr); return Void(); } -Return Demux::configureInput(const DemuxInputSettings& settings) { +Result Demux::removeFilter(uint32_t filterId) { ALOGV("%s", __FUNCTION__); - mInputConfigured = true; - mInputSettings = settings; + // resetFilterRecords(filterId); + mUsedFilterIds.erase(filterId); + mUnusedFilterIds.insert(filterId); + mFilters.erase(filterId); return Result::SUCCESS; } -Return Demux::startInput() { - ALOGV("%s", __FUNCTION__); - - if (!mInputCallback) { - return Result::NOT_INITIALIZED; - } - - if (!mInputConfigured) { - return Result::INVALID_STATE; - } - - pthread_create(&mInputThread, NULL, __threadLoopInput, this); - pthread_setname_np(mInputThread, "demux_input_waiting_loop"); - - // TODO start another thread to send filter status callback to the framework - - return Result::SUCCESS; -} - -Return Demux::stopInput() { - ALOGV("%s", __FUNCTION__); - - mInputThreadRunning = false; - - std::lock_guard lock(mInputThreadLock); - - return Result::SUCCESS; -} - -Return Demux::flushInput() { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Demux::removeInput() { - ALOGV("%s", __FUNCTION__); - - mInputMQ = nullptr; - - return Result::SUCCESS; -} - -Result Demux::startFilterLoop(uint32_t filterId) { - struct ThreadArgs* threadArgs = (struct ThreadArgs*)malloc(sizeof(struct ThreadArgs)); - threadArgs->user = this; - threadArgs->filterId = filterId; - - pthread_t mFilterThread; - pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs); - mFilterThreads[filterId] = mFilterThread; - pthread_setname_np(mFilterThread, "demux_filter_waiting_loop"); - - return Result::SUCCESS; -} - -Result Demux::startSectionFilterHandler(uint32_t filterId) { - if (mFilterOutputs[filterId].empty()) { - return Result::SUCCESS; - } - if (!writeSectionsAndCreateEvent(filterId, mFilterOutputs[filterId])) { - ALOGD("[Demux] filter %d fails to write into FMQ. Ending thread", filterId); - return Result::UNKNOWN_ERROR; - } - - mFilterOutputs[filterId].clear(); - - return Result::SUCCESS; -} - -Result Demux::startPesFilterHandler(uint32_t filterId) { - std::lock_guard lock(mFilterEventLock); - if (mFilterOutputs[filterId].empty()) { - return Result::SUCCESS; - } - - for (int i = 0; i < mFilterOutputs[filterId].size(); i += 188) { - if (mPesSizeLeft == 0) { - uint32_t prefix = (mFilterOutputs[filterId][i + 4] << 16) | - (mFilterOutputs[filterId][i + 5] << 8) | - mFilterOutputs[filterId][i + 6]; - ALOGD("[Demux] prefix %d", prefix); - if (prefix == 0x000001) { - // TODO handle mulptiple Pes filters - mPesSizeLeft = - (mFilterOutputs[filterId][i + 8] << 8) | mFilterOutputs[filterId][i + 9]; - mPesSizeLeft += 6; - ALOGD("[Demux] pes data length %d", mPesSizeLeft); - } else { - continue; - } - } - - int endPoint = min(184, mPesSizeLeft); - // append data and check size - vector::const_iterator first = mFilterOutputs[filterId].begin() + i + 4; - vector::const_iterator last = mFilterOutputs[filterId].begin() + i + 4 + endPoint; - mPesOutput.insert(mPesOutput.end(), first, last); - // size does not match then continue - mPesSizeLeft -= endPoint; - if (mPesSizeLeft > 0) { - continue; - } - // size match then create event - if (!writeDataToFilterMQ(mPesOutput, filterId)) { - mFilterOutputs[filterId].clear(); - return Result::INVALID_STATE; - } - maySendFilterStatusCallback(filterId); - DemuxFilterPesEvent pesEvent; - pesEvent = { - // temp dump meta data - .streamId = mPesOutput[3], - .dataLength = static_cast(mPesOutput.size()), - }; - ALOGD("[Demux] assembled pes data length %d", pesEvent.dataLength); - - int size = mFilterEvents[filterId].events.size(); - mFilterEvents[filterId].events.resize(size + 1); - mFilterEvents[filterId].events[size].pes(pesEvent); - mPesOutput.clear(); - } - - mFilterOutputs[filterId].clear(); - - return Result::SUCCESS; -} - -Result Demux::startTsFilterHandler() { - // TODO handle starting TS filter - return Result::SUCCESS; -} - -Result Demux::startMediaFilterHandler(uint32_t filterId) { - DemuxFilterMediaEvent mediaEvent; - mediaEvent = { - // temp dump meta data - .pts = 0, - .dataLength = 530, - .secureMemory = nullptr, - }; - mFilterEvents[filterId].events.resize(1); - mFilterEvents[filterId].events[0].media() = mediaEvent; - - mFilterOutputs[filterId].clear(); - // TODO handle write FQM for media stream - return Result::SUCCESS; -} - -Result Demux::startRecordFilterHandler(uint32_t filterId) { - DemuxFilterRecordEvent recordEvent; - recordEvent = { - // temp dump meta data - .tpid = 0, - .packetNum = 0, - }; - recordEvent.indexMask.tsIndexMask() = 0x01; - mFilterEvents[filterId].events.resize(1); - mFilterEvents[filterId].events[0].ts() = recordEvent; - - mFilterOutputs[filterId].clear(); - return Result::SUCCESS; -} - -Result Demux::startPcrFilterHandler() { - // TODO handle starting PCR filter - return Result::SUCCESS; -} - -bool Demux::createFilterMQ(uint32_t bufferSize, uint32_t filterId) { - ALOGV("%s", __FUNCTION__); - - // Create a synchronized FMQ that supports blocking read/write - std::unique_ptr tmpFilterMQ = - std::unique_ptr(new (std::nothrow) FilterMQ(bufferSize, true)); - if (!tmpFilterMQ->isValid()) { - ALOGW("Failed to create FMQ of filter with id: %d", filterId); - return false; - } - - mFilterMQs[filterId] = std::move(tmpFilterMQ); - - EventFlag* filterEventFlag; - if (EventFlag::createEventFlag(mFilterMQs[filterId]->getEventFlagWord(), &filterEventFlag) != - OK) { - return false; - } - mFilterEventFlags[filterId] = filterEventFlag; - - return true; -} - -bool Demux::writeSectionsAndCreateEvent(uint32_t filterId, vector data) { - // TODO check how many sections has been read - std::lock_guard lock(mFilterEventLock); - if (!writeDataToFilterMQ(data, filterId)) { - return false; - } - int size = mFilterEvents[filterId].events.size(); - mFilterEvents[filterId].events.resize(size + 1); - DemuxFilterSectionEvent secEvent; - secEvent = { - // temp dump meta data - .tableId = 0, - .version = 1, - .sectionNum = 1, - .dataLength = static_cast(data.size()), - }; - mFilterEvents[filterId].events[size].section(secEvent); - return true; -} - -bool Demux::writeDataToFilterMQ(const std::vector& data, uint32_t filterId) { - std::lock_guard lock(mWriteLock); - if (mFilterMQs[filterId]->write(data.data(), data.size())) { - return true; - } - return false; -} - -bool Demux::readInputFMQ() { - // Read input data from the input FMQ - int size = mInputMQ->availableToRead(); - int inputPacketSize = mInputSettings.packetSize; - vector dataOutputBuffer; - dataOutputBuffer.resize(inputPacketSize); - - // Dispatch the packet to the PID matching filter output buffer - for (int i = 0; i < size / inputPacketSize; i++) { - if (!mInputMQ->read(dataOutputBuffer.data(), inputPacketSize)) { - return false; - } - startTsFilter(dataOutputBuffer); - } - - return true; -} - void Demux::startTsFilter(vector data) { set::iterator it; for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff)); - ALOGW("start ts filter pid: %d", pid); - if (pid == mFilterPids[*it]) { - mFilterOutputs[*it].insert(mFilterOutputs[*it].end(), data.begin(), data.end()); + if (DEBUG_FILTER) { + ALOGW("start ts filter pid: %d", pid); + } + if (pid == mFilters[*it]->getTpid()) { + mFilters[*it]->updateFilterOutput(data); } } } bool Demux::startFilterDispatcher() { - Result result; set::iterator it; // Handle the output data per filter type for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { - switch (mFilterEvents[*it].filterType) { - case DemuxFilterType::SECTION: - result = startSectionFilterHandler(*it); - break; - case DemuxFilterType::PES: - result = startPesFilterHandler(*it); - break; - case DemuxFilterType::TS: - result = startTsFilterHandler(); - break; - case DemuxFilterType::AUDIO: - case DemuxFilterType::VIDEO: - result = startMediaFilterHandler(*it); - break; - case DemuxFilterType::RECORD: - result = startRecordFilterHandler(*it); - break; - case DemuxFilterType::PCR: - result = startPcrFilterHandler(); - break; - default: - return false; + if (mFilters[*it]->startFilterHandler() != Result::SUCCESS) { + return false; } } - return result == Result::SUCCESS; + return true; } -void* Demux::__threadLoopFilter(void* threadArg) { - Demux* const self = static_cast(((struct ThreadArgs*)threadArg)->user); - self->filterThreadLoop(((struct ThreadArgs*)threadArg)->filterId); - return 0; +Result Demux::startFilterHandler(uint32_t filterId) { + return mFilters[filterId]->startFilterHandler(); } -void* Demux::__threadLoopInput(void* user) { - Demux* const self = static_cast(user); - self->inputThreadLoop(); - return 0; +void Demux::updateFilterOutput(uint16_t filterId, vector data) { + mFilters[filterId]->updateFilterOutput(data); } -void Demux::filterThreadLoop(uint32_t filterId) { - ALOGD("[Demux] filter %d threadLoop start.", filterId); - std::lock_guard lock(mFilterThreadLock); - mFilterThreadRunning[filterId] = true; - - // For the first time of filter output, implementation needs to send the filter - // Event Callback without waiting for the DATA_CONSUMED to init the process. - while (mFilterThreadRunning[filterId]) { - if (mFilterEvents[filterId].events.size() == 0) { - ALOGD("[Demux] wait for filter data output."); - usleep(1000 * 1000); - continue; - } - // After successfully write, send a callback and wait for the read to be done - mFilterCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]); - mFilterEvents[filterId].events.resize(0); - mFilterStatus[filterId] = DemuxFilterStatus::DATA_READY; - mFilterCallbacks[filterId]->onFilterStatus(filterId, mFilterStatus[filterId]); - break; - } - - while (mFilterThreadRunning[filterId]) { - uint32_t efState = 0; - // We do not wait for the last round of writen data to be read to finish the thread - // because the VTS can verify the reading itself. - for (int i = 0; i < SECTION_WRITE_COUNT; i++) { - while (mFilterThreadRunning[filterId]) { - status_t status = mFilterEventFlags[filterId]->wait( - static_cast(DemuxQueueNotifyBits::DATA_CONSUMED), &efState, - WAIT_TIMEOUT, true /* retry on spurious wake */); - if (status != OK) { - ALOGD("[Demux] wait for data consumed"); - continue; - } - break; - } - - if (mFilterCallbacks[filterId] == nullptr) { - ALOGD("[Demux] filter %d does not hava callback. Ending thread", filterId); - break; - } - - maySendFilterStatusCallback(filterId); - - while (mFilterThreadRunning[filterId]) { - std::lock_guard lock(mFilterEventLock); - if (mFilterEvents[filterId].events.size() == 0) { - continue; - } - // After successfully write, send a callback and wait for the read to be done - mFilterCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]); - mFilterEvents[filterId].events.resize(0); - break; - } - // We do not wait for the last read to be done - // VTS can verify the read result itself. - if (i == SECTION_WRITE_COUNT - 1) { - ALOGD("[Demux] filter %d writing done. Ending thread", filterId); - break; - } - } - mFilterThreadRunning[filterId] = false; - } - - ALOGD("[Demux] filter thread ended."); -} - -void Demux::inputThreadLoop() { - ALOGD("[Demux] input threadLoop start."); - std::lock_guard lock(mInputThreadLock); - mInputThreadRunning = true; - - while (mInputThreadRunning) { - uint32_t efState = 0; - status_t status = - mInputEventFlag->wait(static_cast(DemuxQueueNotifyBits::DATA_READY), - &efState, WAIT_TIMEOUT, true /* retry on spurious wake */); - if (status != OK) { - ALOGD("[Demux] wait for data ready on the input FMQ"); - continue; - } - // Our current implementation filter the data and write it into the filter FMQ immediately - // after the DATA_READY from the VTS/framework - if (!readInputFMQ() || !startFilterDispatcher()) { - ALOGD("[Demux] input data failed to be filtered. Ending thread"); - break; - } - - maySendInputStatusCallback(); - } - - mInputThreadRunning = false; - ALOGD("[Demux] input thread ended."); -} - -void Demux::maySendInputStatusCallback() { - std::lock_guard lock(mInputStatusLock); - int availableToRead = mInputMQ->availableToRead(); - int availableToWrite = mInputMQ->availableToWrite(); - - DemuxInputStatus newStatus = - checkInputStatusChange(availableToWrite, availableToRead, mInputSettings.highThreshold, - mInputSettings.lowThreshold); - if (mIntputStatus != newStatus) { - mInputCallback->onInputStatus(newStatus); - mIntputStatus = newStatus; - } -} - -void Demux::maySendFilterStatusCallback(uint32_t filterId) { - std::lock_guard lock(mFilterStatusLock); - int availableToRead = mFilterMQs[filterId]->availableToRead(); - int availableToWrite = mFilterMQs[filterId]->availableToWrite(); - int fmqSize = mFilterMQs[filterId]->getQuantumCount(); - - DemuxFilterStatus newStatus = - checkFilterStatusChange(filterId, availableToWrite, availableToRead, - ceil(fmqSize * 0.75), ceil(fmqSize * 0.25)); - if (mFilterStatus[filterId] != newStatus) { - mFilterCallbacks[filterId]->onFilterStatus(filterId, newStatus); - mFilterStatus[filterId] = newStatus; - } -} - -DemuxInputStatus Demux::checkInputStatusChange(uint32_t availableToWrite, uint32_t availableToRead, - uint32_t highThreshold, uint32_t lowThreshold) { - if (availableToWrite == 0) { - return DemuxInputStatus::SPACE_FULL; - } else if (availableToRead > highThreshold) { - return DemuxInputStatus::SPACE_ALMOST_FULL; - } else if (availableToRead < lowThreshold) { - return DemuxInputStatus::SPACE_ALMOST_EMPTY; - } else if (availableToRead == 0) { - return DemuxInputStatus::SPACE_EMPTY; - } - return mIntputStatus; -} - -DemuxFilterStatus Demux::checkFilterStatusChange(uint32_t filterId, uint32_t availableToWrite, - uint32_t availableToRead, uint32_t highThreshold, - uint32_t lowThreshold) { - if (availableToWrite == 0) { - return DemuxFilterStatus::OVERFLOW; - } else if (availableToRead > highThreshold) { - return DemuxFilterStatus::HIGH_WATER; - } else if (availableToRead < lowThreshold) { - return DemuxFilterStatus::LOW_WATER; - } - return mFilterStatus[filterId]; +uint16_t Demux::getFilterTpid(uint32_t filterId) { + return mFilters[filterId]->getTpid(); } Result Demux::startBroadcastInputLoop() { @@ -876,6 +232,7 @@ void Demux::broadcastInputThreadLoop() { for (int i = 0; i < writePacketAmount; i++) { inputData.read(buffer, packetSize); if (!inputData) { + mKeepFetchingDataFromFrontend = false; mBroadcastInputThreadRunning = false; break; } @@ -888,7 +245,7 @@ void Demux::broadcastInputThreadLoop() { startTsFilter(byteBuffer); } startFilterDispatcher(); - sleep(1); + usleep(100); } } @@ -898,6 +255,7 @@ void Demux::broadcastInputThreadLoop() { } void Demux::stopBroadcastInput() { + ALOGD("[Demux] stop frontend on demux"); mKeepFetchingDataFromFrontend = false; mBroadcastInputThreadRunning = false; std::lock_guard lock(mBroadcastInputThreadLock); diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h index ba0b9b099a..a9756cc248 100644 --- a/tv/tuner/1.0/default/Demux.h +++ b/tv/tuner/1.0/default/Demux.h @@ -21,7 +21,10 @@ #include #include #include +#include "Dvr.h" +#include "Filter.h" #include "Frontend.h" +#include "TimeFilter.h" #include "Tuner.h" using namespace std; @@ -38,13 +41,17 @@ using ::android::hardware::kSynchronizedReadWrite; using ::android::hardware::MessageQueue; using ::android::hardware::MQDescriptorSync; using ::android::hardware::tv::tuner::V1_0::IDemux; -using ::android::hardware::tv::tuner::V1_0::IDemuxCallback; +using ::android::hardware::tv::tuner::V1_0::IDvrCallback; +using ::android::hardware::tv::tuner::V1_0::IFilterCallback; using ::android::hardware::tv::tuner::V1_0::Result; using FilterMQ = MessageQueue; -class Tuner; +class Dvr; +class Filter; class Frontend; +class TimeFilter; +class Tuner; class Demux : public IDemux { public: @@ -54,63 +61,27 @@ class Demux : public IDemux { virtual Return setFrontendDataSource(uint32_t frontendId) override; - virtual Return close() override; + virtual Return openFilter(const DemuxFilterType& type, uint32_t bufferSize, + const sp& cb, openFilter_cb _hidl_cb) override; - virtual Return addFilter(DemuxFilterType type, uint32_t bufferSize, - const sp& cb, addFilter_cb _hidl_cb) override; + virtual Return openTimeFilter(openTimeFilter_cb _hidl_cb) override; - virtual Return getFilterQueueDesc(uint32_t filterId, - getFilterQueueDesc_cb _hidl_cb) override; - - virtual Return configureFilter(uint32_t filterId, - const DemuxFilterSettings& settings) override; - - virtual Return startFilter(uint32_t filterId) override; - - virtual Return stopFilter(uint32_t filterId) override; - - virtual Return flushFilter(uint32_t filterId) override; - - virtual Return removeFilter(uint32_t filterId) override; - - virtual Return getAvSyncHwId(uint32_t filterId, getAvSyncHwId_cb _hidl_cb) override; + virtual Return getAvSyncHwId(const sp& filter, + getAvSyncHwId_cb _hidl_cb) override; virtual Return getAvSyncTime(AvSyncHwId avSyncHwId, getAvSyncTime_cb _hidl_cb) override; - virtual Return addInput(uint32_t bufferSize, const sp& cb) override; + virtual Return close() override; - virtual Return getInputQueueDesc(getInputQueueDesc_cb _hidl_cb) override; - - virtual Return configureInput(const DemuxInputSettings& settings) override; - - virtual Return startInput() override; - - virtual Return stopInput() override; - - virtual Return flushInput() override; - - virtual Return removeInput() override; - - virtual Return addOutput(uint32_t bufferSize, const sp& cb) override; - - virtual Return getOutputQueueDesc(getOutputQueueDesc_cb _hidl_cb) override; - - virtual Return configureOutput(const DemuxOutputSettings& settings) override; - - virtual Return attachOutputFilter(uint32_t filterId) override; - - virtual Return detachOutputFilter(uint32_t filterId) override; - - virtual Return startOutput() override; - - virtual Return stopOutput() override; - - virtual Return flushOutput() override; - - virtual Return removeOutput() override; + virtual Return openDvr(DvrType type, uint32_t bufferSize, const sp& cb, + openDvr_cb _hidl_cb) override; // Functions interacts with Tuner Service void stopBroadcastInput(); + Result removeFilter(uint32_t filterId); + Result startFilterHandler(uint32_t filterId); + void updateFilterOutput(uint16_t filterId, vector data); + uint16_t getFilterTpid(uint32_t filterId); private: // Tuner service @@ -126,19 +97,9 @@ class Demux : public IDemux { uint32_t filterId; }; - /** - * Filter handlers to handle the data filtering. - * They are also responsible to write the filtered output into the filter FMQ - * and update the filterEvent bound with the same filterId. - */ - Result startSectionFilterHandler(uint32_t filterId); - Result startPesFilterHandler(uint32_t filterId); - Result startTsFilterHandler(); - Result startMediaFilterHandler(uint32_t filterId); - Result startRecordFilterHandler(uint32_t filterId); - Result startPcrFilterHandler(); - Result startFilterLoop(uint32_t filterId); Result startBroadcastInputLoop(); + static void* __threadLoopBroadcast(void* user); + void broadcastInputThreadLoop(); /** * To create a FilterMQ with the the next available Filter ID. @@ -147,32 +108,14 @@ class Demux : public IDemux { * * Return false is any of the above processes fails. */ - bool createFilterMQ(uint32_t bufferSize, uint32_t filterId); - bool createMQ(FilterMQ* queue, EventFlag* eventFlag, uint32_t bufferSize); void deleteEventFlag(); - bool writeDataToFilterMQ(const std::vector& data, uint32_t filterId); bool readDataFromMQ(); - bool writeSectionsAndCreateEvent(uint32_t filterId, vector data); - void maySendInputStatusCallback(); - void maySendFilterStatusCallback(uint32_t filterId); - DemuxInputStatus checkInputStatusChange(uint32_t availableToWrite, uint32_t availableToRead, - uint32_t highThreshold, uint32_t lowThreshold); - DemuxFilterStatus checkFilterStatusChange(uint32_t filterId, uint32_t availableToWrite, - uint32_t availableToRead, uint32_t highThreshold, - uint32_t lowThreshold); /** * A dispatcher to read and dispatch input data to all the started filters. * Each filter handler handles the data filtering/output writing/filterEvent updating. */ - bool readInputFMQ(); - void startTsFilter(vector data); bool startFilterDispatcher(); - static void* __threadLoopFilter(void* data); - static void* __threadLoopInput(void* user); - static void* __threadLoopBroadcast(void* user); - void filterThreadLoop(uint32_t filterId); - void inputThreadLoop(); - void broadcastInputThreadLoop(); + void startTsFilter(vector data); uint32_t mDemuxId; /** @@ -196,69 +139,30 @@ class Demux : public IDemux { * A list of created FilterMQ ptrs. * The array number is the filter ID. */ - vector mFilterPids; - vector> mFilterOutputs; - vector> mFilterMQs; - vector mFilterEventFlags; - vector mFilterEvents; - unique_ptr mInputMQ; - unique_ptr mOutputMQ; - EventFlag* mInputEventFlag; - EventFlag* mOutputEventFlag; - /** - * Demux callbacks used on filter events or IO buffer status - */ - vector> mFilterCallbacks; - sp mInputCallback; - sp mOutputCallback; - bool mInputConfigured = false; - bool mOutputConfigured = false; - DemuxInputSettings mInputSettings; - DemuxOutputSettings mOutputSettings; + std::map> mFilters; // Thread handlers - pthread_t mInputThread; - pthread_t mOutputThread; pthread_t mBroadcastInputThread; - vector mFilterThreads; - - // FMQ status local records - DemuxInputStatus mIntputStatus; - vector mFilterStatus; /** * If a specific filter's writing loop is still running */ - vector mFilterThreadRunning; - bool mInputThreadRunning; bool mBroadcastInputThreadRunning; bool mKeepFetchingDataFromFrontend; /** * Lock to protect writes to the FMQs */ std::mutex mWriteLock; - /** - * Lock to protect writes to the filter event - */ - // TODO make each filter separate event lock - std::mutex mFilterEventLock; /** * Lock to protect writes to the input status */ - std::mutex mInputStatusLock; - std::mutex mFilterStatusLock; std::mutex mBroadcastInputThreadLock; - std::mutex mFilterThreadLock; - std::mutex mInputThreadLock; - /** - * How many times a filter should write - * TODO make this dynamic/random/can take as a parameter - */ - const uint16_t SECTION_WRITE_COUNT = 10; // temp handle single PES filter // TODO handle mulptiple Pes filters int mPesSizeLeft = 0; vector mPesOutput; + + const bool DEBUG_FILTER = false; }; } // namespace implementation diff --git a/tv/tuner/1.0/default/Descrambler.cpp b/tv/tuner/1.0/default/Descrambler.cpp index 085f2c8d54..e3f5b22bcb 100644 --- a/tv/tuner/1.0/default/Descrambler.cpp +++ b/tv/tuner/1.0/default/Descrambler.cpp @@ -50,13 +50,15 @@ Return Descrambler::setKeyToken(const hidl_vec& /* keyToken */) return Result::SUCCESS; } -Return Descrambler::addPid(uint16_t /* pid */) { +Return Descrambler::addPid(const DemuxPid& /* pid */, + const sp& /* optionalSourceFilter */) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; } -Return Descrambler::removePid(uint16_t /* pid */) { +Return Descrambler::removePid(const DemuxPid& /* pid */, + const sp& /* optionalSourceFilter */) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; diff --git a/tv/tuner/1.0/default/Descrambler.h b/tv/tuner/1.0/default/Descrambler.h index 436adcfc43..c8898200c0 100644 --- a/tv/tuner/1.0/default/Descrambler.h +++ b/tv/tuner/1.0/default/Descrambler.h @@ -40,9 +40,11 @@ class Descrambler : public IDescrambler { virtual Return setKeyToken(const hidl_vec& keyToken) override; - virtual Return addPid(uint16_t pid) override; + virtual Return addPid(const DemuxPid& pid, + const sp& optionalSourceFilter) override; - virtual Return removePid(uint16_t pid) override; + virtual Return removePid(const DemuxPid& pid, + const sp& optionalSourceFilter) override; virtual Return close() override; diff --git a/tv/tuner/1.0/default/Dvr.cpp b/tv/tuner/1.0/default/Dvr.cpp new file mode 100644 index 0000000000..eb38f9040e --- /dev/null +++ b/tv/tuner/1.0/default/Dvr.cpp @@ -0,0 +1,280 @@ +/* + * 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 "android.hardware.tv.tuner@1.0-Dvr" + +#include "Dvr.h" +#include + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +#define WAIT_TIMEOUT 3000000000 + +Dvr::Dvr() {} + +Dvr::Dvr(DvrType type, uint32_t bufferSize, const sp& cb, sp demux) { + mType = type; + mBufferSize = bufferSize; + mCallback = cb; + mDemux = demux; +} + +Dvr::~Dvr() {} + +Return Dvr::getQueueDesc(getQueueDesc_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + _hidl_cb(Result::SUCCESS, *mDvrMQ->getDesc()); + return Void(); +} + +Return Dvr::configure(const DvrSettings& settings) { + ALOGV("%s", __FUNCTION__); + + mDvrSettings = settings; + mDvrConfigured = true; + + return Result::SUCCESS; +} + +Return Dvr::attachFilter(const sp& filter) { + ALOGV("%s", __FUNCTION__); + + uint32_t filterId; + Result status; + + filter->getId([&](Result result, uint32_t id) { + filterId = id; + status = result; + }); + + if (status != Result::SUCCESS) { + return status; + } + + mFilters[filterId] = filter; + + return Result::SUCCESS; +} + +Return Dvr::detachFilter(const sp& filter) { + ALOGV("%s", __FUNCTION__); + + uint32_t filterId; + Result status; + + filter->getId([&](Result result, uint32_t id) { + filterId = id; + status = result; + }); + + if (status != Result::SUCCESS) { + return status; + } + + std::map>::iterator it; + + it = mFilters.find(filterId); + if (it != mFilters.end()) { + mFilters.erase(filterId); + } + + return Result::SUCCESS; +} + +Return Dvr::start() { + ALOGV("%s", __FUNCTION__); + + if (!mCallback) { + return Result::NOT_INITIALIZED; + } + + if (!mDvrConfigured) { + return Result::INVALID_STATE; + } + + if (mType == DvrType::PLAYBACK) { + pthread_create(&mDvrThread, NULL, __threadLoopPlayback, this); + pthread_setname_np(mDvrThread, "playback_waiting_loop"); + } else if (mType == DvrType::RECORD) { + /*pthread_create(&mInputThread, NULL, __threadLoopInput, this); + pthread_setname_np(mInputThread, "playback_waiting_loop");*/ + } + + // TODO start another thread to send filter status callback to the framework + + return Result::SUCCESS; +} + +Return Dvr::stop() { + ALOGV("%s", __FUNCTION__); + + mDvrThreadRunning = false; + + std::lock_guard lock(mDvrThreadLock); + + return Result::SUCCESS; +} + +Return Dvr::flush() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Dvr::close() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +bool Dvr::createDvrMQ() { + ALOGV("%s", __FUNCTION__); + + // Create a synchronized FMQ that supports blocking read/write + std::unique_ptr tmpDvrMQ = + std::unique_ptr(new (std::nothrow) DvrMQ(mBufferSize, true)); + if (!tmpDvrMQ->isValid()) { + ALOGW("Failed to create FMQ of DVR"); + return false; + } + + mDvrMQ = std::move(tmpDvrMQ); + + if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) { + return false; + } + + return true; +} + +void* Dvr::__threadLoopPlayback(void* user) { + Dvr* const self = static_cast(user); + self->playbackThreadLoop(); + return 0; +} + +void Dvr::playbackThreadLoop() { + ALOGD("[Dvr] playback threadLoop start."); + std::lock_guard lock(mDvrThreadLock); + mDvrThreadRunning = true; + + while (mDvrThreadRunning) { + uint32_t efState = 0; + status_t status = + mDvrEventFlag->wait(static_cast(DemuxQueueNotifyBits::DATA_READY), + &efState, WAIT_TIMEOUT, true /* retry on spurious wake */); + if (status != OK) { + ALOGD("[Dvr] wait for data ready on the playback FMQ"); + continue; + } + // Our current implementation filter the data and write it into the filter FMQ immediately + // after the DATA_READY from the VTS/framework + if (!readPlaybackFMQ() || !startFilterDispatcher()) { + ALOGD("[Dvr] playback data failed to be filtered. Ending thread"); + break; + } + + maySendPlaybackStatusCallback(); + } + + mDvrThreadRunning = false; + ALOGD("[Dvr] playback thread ended."); +} + +void Dvr::maySendPlaybackStatusCallback() { + std::lock_guard lock(mPlaybackStatusLock); + int availableToRead = mDvrMQ->availableToRead(); + int availableToWrite = mDvrMQ->availableToWrite(); + + PlaybackStatus newStatus = checkPlaybackStatusChange(availableToWrite, availableToRead, + mDvrSettings.playback().highThreshold, + mDvrSettings.playback().lowThreshold); + if (mPlaybackStatus != newStatus) { + mCallback->onPlaybackStatus(newStatus); + mPlaybackStatus = newStatus; + } +} + +PlaybackStatus Dvr::checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead, + uint32_t highThreshold, uint32_t lowThreshold) { + if (availableToWrite == 0) { + return PlaybackStatus::SPACE_FULL; + } else if (availableToRead > highThreshold) { + return PlaybackStatus::SPACE_ALMOST_FULL; + } else if (availableToRead < lowThreshold) { + return PlaybackStatus::SPACE_ALMOST_EMPTY; + } else if (availableToRead == 0) { + return PlaybackStatus::SPACE_EMPTY; + } + return mPlaybackStatus; +} + +bool Dvr::readPlaybackFMQ() { + // Read playback data from the input FMQ + int size = mDvrMQ->availableToRead(); + int playbackPacketSize = mDvrSettings.playback().packetSize; + vector dataOutputBuffer; + dataOutputBuffer.resize(playbackPacketSize); + + // Dispatch the packet to the PID matching filter output buffer + for (int i = 0; i < size / playbackPacketSize; i++) { + if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) { + return false; + } + startTpidFilter(dataOutputBuffer); + } + + return true; +} + +void Dvr::startTpidFilter(vector data) { + std::map>::iterator it; + for (it = mFilters.begin(); it != mFilters.end(); it++) { + uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff)); + if (DEBUG_DVR) { + ALOGW("[Dvr] start ts filter pid: %d", pid); + } + if (pid == mDemux->getFilterTpid(it->first)) { + mDemux->updateFilterOutput(it->first, data); + } + } +} + +bool Dvr::startFilterDispatcher() { + std::map>::iterator it; + + // Handle the output data per filter type + for (it = mFilters.begin(); it != mFilters.end(); it++) { + if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) { + return false; + } + } + + return true; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/tv/tuner/1.0/default/Dvr.h b/tv/tuner/1.0/default/Dvr.h new file mode 100644 index 0000000000..fbb778ca6c --- /dev/null +++ b/tv/tuner/1.0/default/Dvr.h @@ -0,0 +1,151 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_DVR_H_ +#define ANDROID_HARDWARE_TV_TUNER_V1_0_DVR_H_ + +#include +#include +#include +#include +#include "Demux.h" +#include "Frontend.h" +#include "Tuner.h" + +using namespace std; + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::EventFlag; +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; +using ::android::hardware::MQDescriptorSync; +using ::android::hardware::tv::tuner::V1_0::IDemux; +using ::android::hardware::tv::tuner::V1_0::IDvrCallback; +using ::android::hardware::tv::tuner::V1_0::Result; + +using DvrMQ = MessageQueue; + +class Demux; +class Filter; +class Frontend; +class Tuner; + +class Dvr : public IDvr { + public: + Dvr(); + + Dvr(DvrType type, uint32_t bufferSize, const sp& cb, sp demux); + + ~Dvr(); + + virtual Return getQueueDesc(getQueueDesc_cb _hidl_cb) override; + + virtual Return configure(const DvrSettings& settings) override; + + virtual Return attachFilter(const sp& filter) override; + + virtual Return detachFilter(const sp& filter) override; + + virtual Return start() override; + + virtual Return stop() override; + + virtual Return flush() override; + + virtual Return close() override; + + /** + * To create a DvrMQ and its Event Flag. + * + * Return false is any of the above processes fails. + */ + bool createDvrMQ(); + + private: + // Demux service + sp mDemux; + + DvrType mType; + uint32_t mBufferSize; + sp mCallback; + std::map> mFilters; + + void deleteEventFlag(); + bool readDataFromMQ(); + void maySendPlaybackStatusCallback(); + void maySendRecordStatusCallback(); + PlaybackStatus checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead, + uint32_t highThreshold, uint32_t lowThreshold); + /** + * A dispatcher to read and dispatch input data to all the started filters. + * Each filter handler handles the data filtering/output writing/filterEvent updating. + */ + bool readPlaybackFMQ(); + void startTpidFilter(vector data); + bool startFilterDispatcher(); + static void* __threadLoopPlayback(void* user); + static void* __threadLoopBroadcast(void* user); + void playbackThreadLoop(); + void broadcastInputThreadLoop(); + + unique_ptr mDvrMQ; + EventFlag* mDvrEventFlag; + /** + * Demux callbacks used on filter events or IO buffer status + */ + bool mDvrConfigured = false; + DvrSettings mDvrSettings; + + // Thread handlers + pthread_t mDvrThread; + pthread_t mBroadcastInputThread; + + // FMQ status local records + PlaybackStatus mPlaybackStatus; + /** + * If a specific filter's writing loop is still running + */ + bool mDvrThreadRunning; + bool mBroadcastInputThreadRunning; + bool mKeepFetchingDataFromFrontend; + /** + * Lock to protect writes to the FMQs + */ + std::mutex mWriteLock; + /** + * Lock to protect writes to the input status + */ + std::mutex mPlaybackStatusLock; + std::mutex mBroadcastInputThreadLock; + std::mutex mDvrThreadLock; + + const bool DEBUG_DVR = false; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_DVR_H_ \ No newline at end of file diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp new file mode 100644 index 0000000000..3d8a97731c --- /dev/null +++ b/tv/tuner/1.0/default/Filter.cpp @@ -0,0 +1,456 @@ +/* + * 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 "android.hardware.tv.tuner@1.0-Filter" + +#include "Filter.h" +#include + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +#define WAIT_TIMEOUT 3000000000 + +Filter::Filter() {} + +Filter::Filter(DemuxFilterType type, uint32_t filterId, uint32_t bufferSize, + const sp& cb, sp demux) { + mType = type; + mFilterId = filterId; + mBufferSize = bufferSize; + mCallback = cb; + mDemux = demux; +} + +Filter::~Filter() {} + +Return Filter::getId(getId_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + _hidl_cb(Result::SUCCESS, mFilterId); + return Void(); +} + +Return Filter::setDataSource(const sp& filter) { + ALOGV("%s", __FUNCTION__); + + mDataSource = filter; + mIsDataSourceDemux = false; + + return Result::SUCCESS; +} + +Return Filter::getQueueDesc(getQueueDesc_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + _hidl_cb(Result::SUCCESS, *mFilterMQ->getDesc()); + return Void(); +} + +Return Filter::configure(const DemuxFilterSettings& settings) { + ALOGV("%s", __FUNCTION__); + + mFilterSettings = settings; + switch (mType.mainType) { + case DemuxFilterMainType::TS: + mTpid = settings.ts().tpid; + break; + case DemuxFilterMainType::MMTP: + /*mmtpSettings*/ + break; + case DemuxFilterMainType::IP: + /*ipSettings*/ + break; + case DemuxFilterMainType::TLV: + /*tlvSettings*/ + break; + case DemuxFilterMainType::ALP: + /*alpSettings*/ + break; + default: + break; + } + + return Result::SUCCESS; +} + +Return Filter::start() { + ALOGV("%s", __FUNCTION__); + + return startFilterLoop(); +} + +Return Filter::stop() { + ALOGV("%s", __FUNCTION__); + + mFilterThreadRunning = false; + + std::lock_guard lock(mFilterThreadLock); + + return Result::SUCCESS; +} + +Return Filter::flush() { + ALOGV("%s", __FUNCTION__); + + // temp implementation to flush the FMQ + int size = mFilterMQ->availableToRead(); + char* buffer = new char[size]; + mFilterMQ->read((unsigned char*)&buffer[0], size); + delete[] buffer; + mFilterStatus = DemuxFilterStatus::DATA_READY; + + return Result::SUCCESS; +} + +Return Filter::close() { + ALOGV("%s", __FUNCTION__); + + return mDemux->removeFilter(mFilterId); +} + +bool Filter::createFilterMQ() { + ALOGV("%s", __FUNCTION__); + + // Create a synchronized FMQ that supports blocking read/write + std::unique_ptr tmpFilterMQ = + std::unique_ptr(new (std::nothrow) FilterMQ(mBufferSize, true)); + if (!tmpFilterMQ->isValid()) { + ALOGW("Failed to create FMQ of filter with id: %d", mFilterId); + return false; + } + + mFilterMQ = std::move(tmpFilterMQ); + + if (EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterEventFlag) != OK) { + return false; + } + + return true; +} + +Result Filter::startFilterLoop() { + pthread_create(&mFilterThread, NULL, __threadLoopFilter, this); + pthread_setname_np(mFilterThread, "filter_waiting_loop"); + + return Result::SUCCESS; +} + +void* Filter::__threadLoopFilter(void* user) { + Filter* const self = static_cast(user); + self->filterThreadLoop(); + return 0; +} + +void Filter::filterThreadLoop() { + ALOGD("[Filter] filter %d threadLoop start.", mFilterId); + std::lock_guard lock(mFilterThreadLock); + mFilterThreadRunning = true; + + // For the first time of filter output, implementation needs to send the filter + // Event Callback without waiting for the DATA_CONSUMED to init the process. + while (mFilterThreadRunning) { + if (mFilterEvent.events.size() == 0) { + ALOGD("[Filter] wait for filter data output."); + usleep(1000 * 1000); + continue; + } + // After successfully write, send a callback and wait for the read to be done + mCallback->onFilterEvent(mFilterEvent); + mFilterEvent.events.resize(0); + mFilterStatus = DemuxFilterStatus::DATA_READY; + mCallback->onFilterStatus(mFilterStatus); + break; + } + + while (mFilterThreadRunning) { + uint32_t efState = 0; + // We do not wait for the last round of written data to be read to finish the thread + // because the VTS can verify the reading itself. + for (int i = 0; i < SECTION_WRITE_COUNT; i++) { + while (mFilterThreadRunning) { + status_t status = mFilterEventFlag->wait( + static_cast(DemuxQueueNotifyBits::DATA_CONSUMED), &efState, + WAIT_TIMEOUT, true /* retry on spurious wake */); + if (status != OK) { + ALOGD("[Filter] wait for data consumed"); + continue; + } + break; + } + + if (mCallback == nullptr) { + ALOGD("[Filter] filter %d does not hava callback. Ending thread", mFilterId); + break; + } + + maySendFilterStatusCallback(); + + while (mFilterThreadRunning) { + std::lock_guard lock(mFilterEventLock); + if (mFilterEvent.events.size() == 0) { + continue; + } + // After successfully write, send a callback and wait for the read to be done + mCallback->onFilterEvent(mFilterEvent); + mFilterEvent.events.resize(0); + break; + } + // We do not wait for the last read to be done + // VTS can verify the read result itself. + if (i == SECTION_WRITE_COUNT - 1) { + ALOGD("[Filter] filter %d writing done. Ending thread", mFilterId); + break; + } + } + mFilterThreadRunning = false; + } + + ALOGD("[Filter] filter thread ended."); +} + +void Filter::maySendFilterStatusCallback() { + std::lock_guard lock(mFilterStatusLock); + int availableToRead = mFilterMQ->availableToRead(); + int availableToWrite = mFilterMQ->availableToWrite(); + int fmqSize = mFilterMQ->getQuantumCount(); + + DemuxFilterStatus newStatus = checkFilterStatusChange( + availableToWrite, availableToRead, ceil(fmqSize * 0.75), ceil(fmqSize * 0.25)); + if (mFilterStatus != newStatus) { + mCallback->onFilterStatus(newStatus); + mFilterStatus = newStatus; + } +} + +DemuxFilterStatus Filter::checkFilterStatusChange(uint32_t availableToWrite, + uint32_t availableToRead, uint32_t highThreshold, + uint32_t lowThreshold) { + if (availableToWrite == 0) { + return DemuxFilterStatus::OVERFLOW; + } else if (availableToRead > highThreshold) { + return DemuxFilterStatus::HIGH_WATER; + } else if (availableToRead < lowThreshold) { + return DemuxFilterStatus::LOW_WATER; + } + return mFilterStatus; +} + +uint16_t Filter::getTpid() { + return mTpid; +} + +void Filter::updateFilterOutput(vector data) { + std::lock_guard lock(mFilterOutputLock); + ALOGD("[Filter] handler output updated"); + mFilterOutput.insert(mFilterOutput.end(), data.begin(), data.end()); +} + +Result Filter::startFilterHandler() { + std::lock_guard lock(mFilterOutputLock); + switch (mType.mainType) { + case DemuxFilterMainType::TS: + switch (mType.subType.tsFilterType()) { + case DemuxTsFilterType::UNDEFINED: + break; + case DemuxTsFilterType::SECTION: + startSectionFilterHandler(); + break; + case DemuxTsFilterType::PES: + startPesFilterHandler(); + break; + case DemuxTsFilterType::TS: + startTsFilterHandler(); + break; + case DemuxTsFilterType::AUDIO: + case DemuxTsFilterType::VIDEO: + startMediaFilterHandler(); + break; + case DemuxTsFilterType::PCR: + startPcrFilterHandler(); + break; + case DemuxTsFilterType::RECORD: + startRecordFilterHandler(); + break; + } + break; + case DemuxFilterMainType::MMTP: + /*mmtpSettings*/ + break; + case DemuxFilterMainType::IP: + /*ipSettings*/ + break; + case DemuxFilterMainType::TLV: + /*tlvSettings*/ + break; + case DemuxFilterMainType::ALP: + /*alpSettings*/ + break; + default: + break; + } + return Result::SUCCESS; +} + +Result Filter::startSectionFilterHandler() { + if (mFilterOutput.empty()) { + return Result::SUCCESS; + } + if (!writeSectionsAndCreateEvent(mFilterOutput)) { + ALOGD("[Filter] filter %d fails to write into FMQ. Ending thread", mFilterId); + return Result::UNKNOWN_ERROR; + } + + mFilterOutput.clear(); + + return Result::SUCCESS; +} + +Result Filter::startPesFilterHandler() { + std::lock_guard lock(mFilterEventLock); + if (mFilterOutput.empty()) { + return Result::SUCCESS; + } + + for (int i = 0; i < mFilterOutput.size(); i += 188) { + if (mPesSizeLeft == 0) { + uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) | + mFilterOutput[i + 6]; + ALOGD("[Filter] prefix %d", prefix); + if (prefix == 0x000001) { + // TODO handle mulptiple Pes filters + mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9]; + mPesSizeLeft += 6; + ALOGD("[Filter] pes data length %d", mPesSizeLeft); + } else { + continue; + } + } + + int endPoint = min(184, mPesSizeLeft); + // append data and check size + vector::const_iterator first = mFilterOutput.begin() + i + 4; + vector::const_iterator last = mFilterOutput.begin() + i + 4 + endPoint; + mPesOutput.insert(mPesOutput.end(), first, last); + // size does not match then continue + mPesSizeLeft -= endPoint; + ALOGD("[Filter] pes data left %d", mPesSizeLeft); + if (mPesSizeLeft > 0) { + continue; + } + // size match then create event + if (!writeDataToFilterMQ(mPesOutput)) { + ALOGD("[Filter] pes data write failed"); + mFilterOutput.clear(); + return Result::INVALID_STATE; + } + maySendFilterStatusCallback(); + DemuxFilterPesEvent pesEvent; + pesEvent = { + // temp dump meta data + .streamId = mPesOutput[3], + .dataLength = static_cast(mPesOutput.size()), + }; + ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength); + + int size = mFilterEvent.events.size(); + mFilterEvent.events.resize(size + 1); + mFilterEvent.events[size].pes(pesEvent); + mPesOutput.clear(); + } + + mFilterOutput.clear(); + + return Result::SUCCESS; +} + +Result Filter::startTsFilterHandler() { + // TODO handle starting TS filter + return Result::SUCCESS; +} + +Result Filter::startMediaFilterHandler() { + DemuxFilterMediaEvent mediaEvent; + mediaEvent = { + // temp dump meta data + .pts = 0, + .dataLength = 530, + .avMemory = nullptr, + .isSecureMemory = false, + }; + mFilterEvent.events.resize(1); + mFilterEvent.events[0].media(mediaEvent); + + mFilterOutput.clear(); + // TODO handle write FQM for media stream + return Result::SUCCESS; +} + +Result Filter::startRecordFilterHandler() { + DemuxFilterTsRecordEvent tsRecordEvent; + tsRecordEvent.pid.tPid(0); + tsRecordEvent.indexMask.tsIndexMask(0x01); + mFilterEvent.events.resize(1); + mFilterEvent.events[0].tsRecord(tsRecordEvent); + + mFilterOutput.clear(); + return Result::SUCCESS; +} + +Result Filter::startPcrFilterHandler() { + // TODO handle starting PCR filter + return Result::SUCCESS; +} + +bool Filter::writeSectionsAndCreateEvent(vector data) { + // TODO check how many sections has been read + ALOGD("[Filter] section hander"); + std::lock_guard lock(mFilterEventLock); + if (!writeDataToFilterMQ(data)) { + return false; + } + int size = mFilterEvent.events.size(); + mFilterEvent.events.resize(size + 1); + DemuxFilterSectionEvent secEvent; + secEvent = { + // temp dump meta data + .tableId = 0, + .version = 1, + .sectionNum = 1, + .dataLength = static_cast(data.size()), + }; + mFilterEvent.events[size].section(secEvent); + return true; +} + +bool Filter::writeDataToFilterMQ(const std::vector& data) { + std::lock_guard lock(mWriteLock); + if (mFilterMQ->write(data.data(), data.size())) { + return true; + } + return false; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h new file mode 100644 index 0000000000..21d42974d7 --- /dev/null +++ b/tv/tuner/1.0/default/Filter.h @@ -0,0 +1,179 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_FILTER_H_ +#define ANDROID_HARDWARE_TV_TUNER_V1_0_FILTER_H_ + +#include +#include +#include +#include +#include "Demux.h" +#include "Frontend.h" + +using namespace std; + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::EventFlag; +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; +using ::android::hardware::MQDescriptorSync; +using ::android::hardware::tv::tuner::V1_0::IDemux; +using ::android::hardware::tv::tuner::V1_0::IFilterCallback; +using ::android::hardware::tv::tuner::V1_0::Result; + +using FilterMQ = MessageQueue; + +class Demux; + +class Filter : public IFilter { + public: + Filter(); + + Filter(DemuxFilterType type, uint32_t filterId, uint32_t bufferSize, + const sp& cb, sp demux); + + ~Filter(); + + virtual Return getId(getId_cb _hidl_cb) override; + + virtual Return setDataSource(const sp& filter) override; + + virtual Return getQueueDesc(getQueueDesc_cb _hidl_cb) override; + + virtual Return configure(const DemuxFilterSettings& settings) override; + + virtual Return start() override; + + virtual Return stop() override; + + virtual Return flush() override; + + virtual Return close() override; + + /** + * To create a FilterMQ and its Event Flag. + * + * Return false is any of the above processes fails. + */ + bool createFilterMQ(); + uint16_t getTpid(); + void updateFilterOutput(vector data); + Result startFilterHandler(); + + private: + // Tuner service + sp mDemux; + /** + * Filter callbacks used on filter events or FMQ status + */ + sp mCallback; + + uint32_t mFilterId; + uint32_t mBufferSize; + DemuxFilterType mType; + DemuxFilterSettings mFilterSettings; + + uint16_t mTpid; + sp mDataSource; + bool mIsDataSourceDemux = true; + vector mFilterOutput; + unique_ptr mFilterMQ; + EventFlag* mFilterEventFlag; + DemuxFilterEvent mFilterEvent; + + // Thread handlers + pthread_t mFilterThread; + + // FMQ status local records + DemuxFilterStatus mFilterStatus; + /** + * If a specific filter's writing loop is still running + */ + bool mFilterThreadRunning; + bool mKeepFetchingDataFromFrontend; + + /** + * How many times a filter should write + * TODO make this dynamic/random/can take as a parameter + */ + const uint16_t SECTION_WRITE_COUNT = 10; + + /** + * Filter handlers to handle the data filtering. + * They are also responsible to write the filtered output into the filter FMQ + * and update the filterEvent bound with the same filterId. + */ + Result startSectionFilterHandler(); + Result startPesFilterHandler(); + Result startTsFilterHandler(); + Result startMediaFilterHandler(); + Result startRecordFilterHandler(); + Result startPcrFilterHandler(); + Result startFilterLoop(); + + void deleteEventFlag(); + bool writeDataToFilterMQ(const std::vector& data); + bool readDataFromMQ(); + bool writeSectionsAndCreateEvent(vector data); + void maySendFilterStatusCallback(); + DemuxFilterStatus checkFilterStatusChange(uint32_t availableToWrite, uint32_t availableToRead, + uint32_t highThreshold, uint32_t lowThreshold); + /** + * A dispatcher to read and dispatch input data to all the started filters. + * Each filter handler handles the data filtering/output writing/filterEvent updating. + */ + void startTsFilter(vector data); + bool startFilterDispatcher(); + static void* __threadLoopFilter(void* user); + void filterThreadLoop(); + + /** + * Lock to protect writes to the FMQs + */ + std::mutex mWriteLock; + /** + * Lock to protect writes to the filter event + */ + // TODO make each filter separate event lock + std::mutex mFilterEventLock; + /** + * Lock to protect writes to the input status + */ + std::mutex mFilterStatusLock; + std::mutex mFilterThreadLock; + std::mutex mFilterOutputLock; + + // temp handle single PES filter + // TODO handle mulptiple Pes filters + int mPesSizeLeft = 0; + vector mPesOutput; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_FILTER_H_ \ No newline at end of file diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h index 07fa7b93ab..eab43a39fb 100644 --- a/tv/tuner/1.0/default/Frontend.h +++ b/tv/tuner/1.0/default/Frontend.h @@ -75,7 +75,7 @@ class Frontend : public IFrontend { FrontendType mType = FrontendType::UNDEFINED; FrontendId mId = 0; - const string FRONTEND_STREAM_FILE = "/vendor/etc/test1.ts"; + const string FRONTEND_STREAM_FILE = "/vendor/etc/dumpTs3.ts"; string mSourceStreamFile; std::ifstream mFrontendData; }; diff --git a/tv/tuner/1.0/default/Lnb.cpp b/tv/tuner/1.0/default/Lnb.cpp index 1446f7f344..51931d67fe 100644 --- a/tv/tuner/1.0/default/Lnb.cpp +++ b/tv/tuner/1.0/default/Lnb.cpp @@ -30,19 +30,25 @@ Lnb::Lnb() {} Lnb::~Lnb() {} -Return Lnb::setVoltage(FrontendLnbVoltage /* voltage */) { +Return Lnb::setCallback(const sp& /* callback */) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; } -Return Lnb::setTone(FrontendLnbTone /* tone */) { +Return Lnb::setVoltage(LnbVoltage /* voltage */) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; } -Return Lnb::setSatellitePosition(FrontendLnbPosition /* position */) { +Return Lnb::setTone(LnbTone /* tone */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Lnb::setSatellitePosition(LnbPosition /* position */) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; diff --git a/tv/tuner/1.0/default/Lnb.h b/tv/tuner/1.0/default/Lnb.h index 4c251f7591..f285cb9e65 100644 --- a/tv/tuner/1.0/default/Lnb.h +++ b/tv/tuner/1.0/default/Lnb.h @@ -29,20 +29,23 @@ namespace tuner { namespace V1_0 { namespace implementation { -using ::android::hardware::tv::tuner::V1_0::FrontendLnbPosition; -using ::android::hardware::tv::tuner::V1_0::FrontendLnbTone; -using ::android::hardware::tv::tuner::V1_0::FrontendLnbVoltage; +using ::android::hardware::tv::tuner::V1_0::ILnbCallback; +using ::android::hardware::tv::tuner::V1_0::LnbPosition; +using ::android::hardware::tv::tuner::V1_0::LnbTone; +using ::android::hardware::tv::tuner::V1_0::LnbVoltage; using ::android::hardware::tv::tuner::V1_0::Result; class Lnb : public ILnb { public: Lnb(); - virtual Return setVoltage(FrontendLnbVoltage voltage) override; + virtual Return setCallback(const sp& callback) override; - virtual Return setTone(FrontendLnbTone tone) override; + virtual Return setVoltage(LnbVoltage voltage) override; - virtual Return setSatellitePosition(FrontendLnbPosition position) override; + virtual Return setTone(LnbTone tone) override; + + virtual Return setSatellitePosition(LnbPosition position) override; virtual Return sendDiseqcMessage(const hidl_vec& diseqcMessage) override; diff --git a/tv/tuner/1.0/default/TimeFilter.cpp b/tv/tuner/1.0/default/TimeFilter.cpp new file mode 100644 index 0000000000..0b1fd1cfd2 --- /dev/null +++ b/tv/tuner/1.0/default/TimeFilter.cpp @@ -0,0 +1,78 @@ +/* + * 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 "android.hardware.tv.tuner@1.0-TimeFilter" + +#include "TimeFilter.h" +#include + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +TimeFilter::TimeFilter() {} + +TimeFilter::TimeFilter(sp demux) { + mDemux = demux; +} + +TimeFilter::~TimeFilter() {} + +Return TimeFilter::setTimeStamp(uint64_t /* timeStamp */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return TimeFilter::clearTimeStamp() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return TimeFilter::getTimeStamp(getTimeStamp_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + uint64_t timeStamp = 0; + + _hidl_cb(Result::SUCCESS, timeStamp); + return Void(); +} + +Return TimeFilter::getSourceTime(getSourceTime_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + uint64_t time = 0; + + _hidl_cb(Result::SUCCESS, time); + return Void(); +} + +Return TimeFilter::close() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/tv/tuner/1.0/default/TimeFilter.h b/tv/tuner/1.0/default/TimeFilter.h new file mode 100644 index 0000000000..7131df85f6 --- /dev/null +++ b/tv/tuner/1.0/default/TimeFilter.h @@ -0,0 +1,69 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_TIMEFILTER_H_ +#define ANDROID_HARDWARE_TV_TUNER_V1_0_TIMEFILTER_H_ + +#include +#include "Demux.h" + +using namespace std; + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::tv::tuner::V1_0::IDemux; +using ::android::hardware::tv::tuner::V1_0::IFilterCallback; +using ::android::hardware::tv::tuner::V1_0::Result; + +using FilterMQ = MessageQueue; + +class Demux; + +class TimeFilter : public ITimeFilter { + public: + TimeFilter(); + + TimeFilter(sp demux); + + ~TimeFilter(); + + virtual Return setTimeStamp(uint64_t timeStamp) override; + + virtual Return clearTimeStamp() override; + + virtual Return getTimeStamp(getTimeStamp_cb _hidl_cb) override; + + virtual Return getSourceTime(getSourceTime_cb _hidl_cb) override; + + virtual Return close() override; + + private: + sp mDemux; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_TIMEFILTER_H_ \ No newline at end of file From 0f94ba87a0184ff46827705683af851309a6acf8 Mon Sep 17 00:00:00 2001 From: Amy Date: Fri, 18 Oct 2019 18:05:39 -0700 Subject: [PATCH 0213/1022] VTS refactoring for filter separation Test: atest Bug: 135708935 Change-Id: I22b6249a953b81793fdfbf17adbadeebde12277a --- .../VtsHalTvTunerV1_0TargetTest.cpp | 612 +++++++++++------- 1 file changed, 380 insertions(+), 232 deletions(-) diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 7936185af5..c66622608d 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -20,8 +20,11 @@ #include #include #include -#include #include +#include +#include +#include +#include #include #include #include @@ -57,8 +60,9 @@ using android::hardware::MessageQueue; using android::hardware::MQDescriptorSync; using android::hardware::Return; using android::hardware::Void; -using android::hardware::tv::tuner::V1_0::DemuxDataFormat; +using android::hardware::tv::tuner::V1_0::DataFormat; using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterMainType; using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent; using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent; @@ -66,10 +70,11 @@ using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterStatus; using android::hardware::tv::tuner::V1_0::DemuxFilterType; -using android::hardware::tv::tuner::V1_0::DemuxInputSettings; -using android::hardware::tv::tuner::V1_0::DemuxInputStatus; -using android::hardware::tv::tuner::V1_0::DemuxOutputStatus; using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; +using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings; +using android::hardware::tv::tuner::V1_0::DemuxTsFilterType; +using android::hardware::tv::tuner::V1_0::DvrSettings; +using android::hardware::tv::tuner::V1_0::DvrType; using android::hardware::tv::tuner::V1_0::FrontendAtscModulation; using android::hardware::tv::tuner::V1_0::FrontendAtscSettings; using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings; @@ -80,11 +85,17 @@ using android::hardware::tv::tuner::V1_0::FrontendScanMessage; using android::hardware::tv::tuner::V1_0::FrontendScanMessageType; using android::hardware::tv::tuner::V1_0::FrontendSettings; using android::hardware::tv::tuner::V1_0::IDemux; -using android::hardware::tv::tuner::V1_0::IDemuxCallback; using android::hardware::tv::tuner::V1_0::IDescrambler; +using android::hardware::tv::tuner::V1_0::IDvr; +using android::hardware::tv::tuner::V1_0::IDvrCallback; +using android::hardware::tv::tuner::V1_0::IFilter; +using android::hardware::tv::tuner::V1_0::IFilterCallback; using android::hardware::tv::tuner::V1_0::IFrontend; using android::hardware::tv::tuner::V1_0::IFrontendCallback; using android::hardware::tv::tuner::V1_0::ITuner; +using android::hardware::tv::tuner::V1_0::PlaybackSettings; +using android::hardware::tv::tuner::V1_0::PlaybackStatus; +using android::hardware::tv::tuner::V1_0::RecordStatus; using android::hardware::tv::tuner::V1_0::Result; namespace { @@ -131,17 +142,28 @@ const std::vector goldenDataOutputBuffer{ 0x73, 0x63, 0x65, 0x6e, 0x65, }; -const uint16_t FMQ_SIZE_4K = 0x1000; +// const uint16_t FMQ_SIZE_4K = 0x1000; const uint32_t FMQ_SIZE_1M = 0x100000; +const uint32_t FMQ_SIZE_16M = 0x1000000; struct FilterConf { DemuxFilterType type; DemuxFilterSettings setting; }; -struct InputConf { +enum FilterEventType : uint8_t { + UNDEFINED, + SECTION, + MEDIA, + PES, + RECORD, + MMTPRECORD, + DOWNLOAD, +}; + +struct PlaybackConf { string inputDataFile; - DemuxInputSettings setting; + PlaybackSettings setting; }; class FrontendCallback : public IFrontendCallback { @@ -154,14 +176,6 @@ class FrontendCallback : public IFrontendCallback { return Void(); } - virtual Return onDiseqcMessage(const hidl_vec& diseqcMessage) override { - android::Mutex::Autolock autoLock(mMsgLock); - mDiseqcMessageReceived = true; - mEventMessage = diseqcMessage; - mMsgCondition.signal(); - return Void(); - } - virtual Return onScanMessage(FrontendScanMessageType /* type */, const FrontendScanMessage& /* message */) override { android::Mutex::Autolock autoLock(mMsgLock); @@ -211,14 +225,14 @@ void FrontendCallback::testOnDiseqcMessage(sp& frontend, FrontendSett } } -class DemuxCallback : public IDemuxCallback { +class FilterCallback : public IFilterCallback { public: virtual Return onFilterEvent(const DemuxFilterEvent& filterEvent) override { android::Mutex::Autolock autoLock(mMsgLock); // Temprarily we treat the first coming back filter data on the matching pid a success // once all of the MQ are cleared, means we got all the expected output - mFilterIdToEvent[filterEvent.filterId] = filterEvent; - readFilterEventData(filterEvent.filterId); + mFilterIdToEvent = filterEvent; + readFilterEventData(); mPidFilterOutputCount++; // mFilterIdToMQ.erase(filterEvent.filterId); @@ -227,96 +241,50 @@ class DemuxCallback : public IDemuxCallback { return Void(); } - virtual Return onFilterStatus(uint32_t /*filterId*/, - const DemuxFilterStatus /*status*/) override { + virtual Return onFilterStatus(const DemuxFilterStatus /*status*/) override { return Void(); } - virtual Return onOutputStatus(DemuxOutputStatus /*status*/) override { return Void(); } + void setFilterId(uint32_t filterId) { mFilterId = filterId; } + void setFilterEventType(FilterEventType type) { mFilterEventType = type; } - virtual Return onInputStatus(DemuxInputStatus status) override { - // android::Mutex::Autolock autoLock(mMsgLock); - ALOGW("[vts] input status %d", status); - switch (status) { - case DemuxInputStatus::SPACE_EMPTY: - case DemuxInputStatus::SPACE_ALMOST_EMPTY: - ALOGW("[vts] keep inputing %d", status); - mKeepWritingInputFMQ = true; - break; - case DemuxInputStatus::SPACE_ALMOST_FULL: - case DemuxInputStatus::SPACE_FULL: - ALOGW("[vts] stop inputing %d", status); - mKeepWritingInputFMQ = false; - break; - } - return Void(); - } - - void testOnFilterEvent(uint32_t filterId); void testFilterDataOutput(); - void stopInputThread(); - void startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor); void startFilterEventThread(DemuxFilterEvent event); - static void* __threadLoopInput(void* threadArgs); static void* __threadLoopFilter(void* threadArgs); - void inputThreadLoop(InputConf* inputConf, bool* keepWritingInputFMQ); void filterThreadLoop(DemuxFilterEvent& event); - void updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor); - void updateGoldenOutputMap(uint32_t filterId, string goldenOutputFile); - bool readFilterEventData(uint32_t filterId); + void updateFilterMQ(MQDesc& filterMQDescriptor); + void updateGoldenOutputMap(string goldenOutputFile); + bool readFilterEventData(); private: - struct InputThreadArgs { - DemuxCallback* user; - InputConf* inputConf; - bool* keepWritingInputFMQ; - }; struct FilterThreadArgs { - DemuxCallback* user; + FilterCallback* user; DemuxFilterEvent event; }; uint16_t mDataLength = 0; std::vector mDataOutputBuffer; - bool mFilterEventReceived; - std::map mFilterIdToGoldenOutput; + string mFilterIdToGoldenOutput; - std::map> mFilterIdToMQ; - std::unique_ptr mInputMQ; - std::map mFilterIdToMQEventFlag; - std::map mFilterIdToEvent; - EventFlag* mInputMQEventFlag; + uint32_t mFilterId; + FilterEventType mFilterEventType; + std::unique_ptr mFilterIdToMQ; + EventFlag* mFilterIdToMQEventFlag; + DemuxFilterEvent mFilterIdToEvent; android::Mutex mMsgLock; android::Mutex mFilterOutputLock; - android::Mutex mInputThreadLock; android::Condition mMsgCondition; android::Condition mFilterOutputCondition; - bool mKeepWritingInputFMQ = true; - bool mInputThreadRunning; - pthread_t mInputThread; pthread_t mFilterThread; int mPidFilterOutputCount = 0; }; -void DemuxCallback::startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor) { - mInputMQ = std::make_unique(inputMQDescriptor, true /* resetPointers */); - EXPECT_TRUE(mInputMQ); - struct InputThreadArgs* threadArgs = - (struct InputThreadArgs*)malloc(sizeof(struct InputThreadArgs)); - threadArgs->user = this; - threadArgs->inputConf = &inputConf; - threadArgs->keepWritingInputFMQ = &mKeepWritingInputFMQ; - - pthread_create(&mInputThread, NULL, __threadLoopInput, (void*)threadArgs); - pthread_setname_np(mInputThread, "test_playback_input_loop"); -} - -void DemuxCallback::startFilterEventThread(DemuxFilterEvent event) { +void FilterCallback::startFilterEventThread(DemuxFilterEvent event) { struct FilterThreadArgs* threadArgs = (struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs)); threadArgs->user = this; @@ -326,7 +294,7 @@ void DemuxCallback::startFilterEventThread(DemuxFilterEvent event) { pthread_setname_np(mFilterThread, "test_playback_input_loop"); } -void DemuxCallback::testFilterDataOutput() { +void FilterCallback::testFilterDataOutput() { android::Mutex::Autolock autoLock(mMsgLock); while (mPidFilterOutputCount < 1) { if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { @@ -338,95 +306,25 @@ void DemuxCallback::testFilterDataOutput() { ALOGW("[vts] pass and stop"); } -void DemuxCallback::stopInputThread() { - mInputThreadRunning = false; - mKeepWritingInputFMQ = false; - - android::Mutex::Autolock autoLock(mInputThreadLock); +void FilterCallback::updateFilterMQ(MQDesc& filterMQDescriptor) { + mFilterIdToMQ = std::make_unique(filterMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(mFilterIdToMQ); + EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ->getEventFlagWord(), + &mFilterIdToMQEventFlag) == android::OK); } -void DemuxCallback::updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor) { - mFilterIdToMQ[filterId] = - std::make_unique(filterMQDescriptor, true /* resetPointers */); - EXPECT_TRUE(mFilterIdToMQ[filterId]); - EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ[filterId]->getEventFlagWord(), - &mFilterIdToMQEventFlag[filterId]) == android::OK); +void FilterCallback::updateGoldenOutputMap(string goldenOutputFile) { + mFilterIdToGoldenOutput = goldenOutputFile; } -void DemuxCallback::updateGoldenOutputMap(uint32_t filterId, string goldenOutputFile) { - mFilterIdToGoldenOutput[filterId] = goldenOutputFile; -} - -void* DemuxCallback::__threadLoopInput(void* threadArgs) { - DemuxCallback* const self = - static_cast(((struct InputThreadArgs*)threadArgs)->user); - self->inputThreadLoop(((struct InputThreadArgs*)threadArgs)->inputConf, - ((struct InputThreadArgs*)threadArgs)->keepWritingInputFMQ); - return 0; -} - -void DemuxCallback::inputThreadLoop(InputConf* inputConf, bool* keepWritingInputFMQ) { - android::Mutex::Autolock autoLock(mInputThreadLock); - mInputThreadRunning = true; - - // Create the EventFlag that is used to signal the HAL impl that data have been - // written into the Input FMQ - EventFlag* inputMQEventFlag; - EXPECT_TRUE(EventFlag::createEventFlag(mInputMQ->getEventFlagWord(), &inputMQEventFlag) == - android::OK); - - // open the stream and get its length - std::ifstream inputData(inputConf->inputDataFile, std::ifstream::binary); - int writeSize = inputConf->setting.packetSize * 6; - char* buffer = new char[writeSize]; - ALOGW("[vts] input thread loop start %s", inputConf->inputDataFile.c_str()); - if (!inputData.is_open()) { - mInputThreadRunning = false; - ALOGW("[vts] Error %s", strerror(errno)); - } - - while (mInputThreadRunning) { - // move the stream pointer for packet size * 6 every read until the end - while (*keepWritingInputFMQ) { - inputData.read(buffer, writeSize); - if (!inputData) { - int leftSize = inputData.gcount(); - if (leftSize == 0) { - mInputThreadRunning = false; - break; - } - inputData.clear(); - inputData.read(buffer, leftSize); - // Write the left over of the input data and quit the thread - if (leftSize > 0) { - EXPECT_TRUE(mInputMQ->write((unsigned char*)&buffer[0], leftSize)); - inputMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); - } - mInputThreadRunning = false; - break; - } - // Write input FMQ and notify the Tuner Implementation - EXPECT_TRUE(mInputMQ->write((unsigned char*)&buffer[0], writeSize)); - inputMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); - inputData.seekg(writeSize, inputData.cur); - sleep(1); - } - } - - ALOGW("[vts] Input thread end."); - - delete[] buffer; - inputData.close(); -} - -void* DemuxCallback::__threadLoopFilter(void* threadArgs) { - DemuxCallback* const self = - static_cast(((struct FilterThreadArgs*)threadArgs)->user); +void* FilterCallback::__threadLoopFilter(void* threadArgs) { + FilterCallback* const self = + static_cast(((struct FilterThreadArgs*)threadArgs)->user); self->filterThreadLoop(((struct FilterThreadArgs*)threadArgs)->event); return 0; } -void DemuxCallback::filterThreadLoop(DemuxFilterEvent& /* event */) { +void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) { android::Mutex::Autolock autoLock(mFilterOutputLock); // Read from mFilterIdToMQ[event.filterId] per event and filter type @@ -439,30 +337,184 @@ void DemuxCallback::filterThreadLoop(DemuxFilterEvent& /* event */) { // end thread } -bool DemuxCallback::readFilterEventData(uint32_t filterId) { +bool FilterCallback::readFilterEventData() { bool result = false; - DemuxFilterEvent filterEvent = mFilterIdToEvent[filterId]; - ALOGW("[vts] reading from filter FMQ %d", filterId); + DemuxFilterEvent filterEvent = mFilterIdToEvent; + ALOGW("[vts] reading from filter FMQ %d", mFilterId); // todo separate filter handlers for (int i = 0; i < filterEvent.events.size(); i++) { - DemuxFilterPesEvent event = filterEvent.events[i].pes(); - mDataLength = event.dataLength; + switch (mFilterEventType) { + case FilterEventType::SECTION: + mDataLength = filterEvent.events[i].section().dataLength; + break; + case FilterEventType::PES: + mDataLength = filterEvent.events[i].pes().dataLength; + break; + case FilterEventType::MEDIA: + break; + case FilterEventType::RECORD: + break; + case FilterEventType::MMTPRECORD: + break; + case FilterEventType::DOWNLOAD: + break; + default: + break; + } // EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not // match"; mDataOutputBuffer.resize(mDataLength); - result = mFilterIdToMQ[filterId]->read(mDataOutputBuffer.data(), mDataLength); + result = mFilterIdToMQ->read(mDataOutputBuffer.data(), mDataLength); EXPECT_TRUE(result) << "can't read from Filter MQ"; /*for (int i = 0; i < mDataLength; i++) { EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match"; }*/ } - mFilterIdToMQEventFlag[filterId]->wake( - static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); + mFilterIdToMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); return result; } +class DvrCallback : public IDvrCallback { + public: + virtual Return onRecordStatus(RecordStatus /*status*/) override { return Void(); } + + virtual Return onPlaybackStatus(PlaybackStatus status) override { + // android::Mutex::Autolock autoLock(mMsgLock); + ALOGW("[vts] playback status %d", status); + switch (status) { + case PlaybackStatus::SPACE_EMPTY: + case PlaybackStatus::SPACE_ALMOST_EMPTY: + ALOGW("[vts] keep playback inputing %d", status); + mKeepWritingPlaybackFMQ = true; + break; + case PlaybackStatus::SPACE_ALMOST_FULL: + case PlaybackStatus::SPACE_FULL: + ALOGW("[vts] stop playback inputing %d", status); + mKeepWritingPlaybackFMQ = false; + break; + } + return Void(); + } + + void testFilterDataOutput(); + void stopPlaybackThread(); + + void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor); + static void* __threadLoopPlayback(void* threadArgs); + void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ); + + private: + struct PlaybackThreadArgs { + DvrCallback* user; + PlaybackConf* playbackConf; + bool* keepWritingPlaybackFMQ; + }; + uint16_t mDataLength = 0; + std::vector mDataOutputBuffer; + + std::map> mFilterIdToMQ; + std::unique_ptr mPlaybackMQ; + std::map mFilterIdToMQEventFlag; + std::map mFilterIdToEvent; + EventFlag* mPlaybackMQEventFlag; + + android::Mutex mMsgLock; + android::Mutex mPlaybackThreadLock; + android::Condition mMsgCondition; + + bool mKeepWritingPlaybackFMQ = true; + bool mPlaybackThreadRunning; + pthread_t mPlaybackThread; + + int mPidFilterOutputCount = 0; +}; + +void DvrCallback::startPlaybackInputThread(PlaybackConf playbackConf, + MQDesc& playbackMQDescriptor) { + mPlaybackMQ = std::make_unique(playbackMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(mPlaybackMQ); + struct PlaybackThreadArgs* threadArgs = + (struct PlaybackThreadArgs*)malloc(sizeof(struct PlaybackThreadArgs)); + threadArgs->user = this; + threadArgs->playbackConf = &playbackConf; + threadArgs->keepWritingPlaybackFMQ = &mKeepWritingPlaybackFMQ; + + pthread_create(&mPlaybackThread, NULL, __threadLoopPlayback, (void*)threadArgs); + pthread_setname_np(mPlaybackThread, "test_playback_input_loop"); +} + +void DvrCallback::stopPlaybackThread() { + mPlaybackThreadRunning = false; + mKeepWritingPlaybackFMQ = false; + + android::Mutex::Autolock autoLock(mPlaybackThreadLock); +} + +void* DvrCallback::__threadLoopPlayback(void* threadArgs) { + DvrCallback* const self = + static_cast(((struct PlaybackThreadArgs*)threadArgs)->user); + self->playbackThreadLoop(((struct PlaybackThreadArgs*)threadArgs)->playbackConf, + ((struct PlaybackThreadArgs*)threadArgs)->keepWritingPlaybackFMQ); + return 0; +} + +void DvrCallback::playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ) { + android::Mutex::Autolock autoLock(mPlaybackThreadLock); + mPlaybackThreadRunning = true; + + // Create the EventFlag that is used to signal the HAL impl that data have been + // written into the Playback FMQ + EventFlag* playbackMQEventFlag; + EXPECT_TRUE(EventFlag::createEventFlag(mPlaybackMQ->getEventFlagWord(), &playbackMQEventFlag) == + android::OK); + + // open the stream and get its length + std::ifstream inputData(playbackConf->inputDataFile, std::ifstream::binary); + int writeSize = playbackConf->setting.packetSize * 6; + char* buffer = new char[writeSize]; + ALOGW("[vts] playback thread loop start %s", playbackConf->inputDataFile.c_str()); + if (!inputData.is_open()) { + mPlaybackThreadRunning = false; + ALOGW("[vts] Error %s", strerror(errno)); + } + + while (mPlaybackThreadRunning) { + // move the stream pointer for packet size * 6 every read until the end + while (*keepWritingPlaybackFMQ) { + inputData.read(buffer, writeSize); + if (!inputData) { + int leftSize = inputData.gcount(); + if (leftSize == 0) { + mPlaybackThreadRunning = false; + break; + } + inputData.clear(); + inputData.read(buffer, leftSize); + // Write the left over of the input data and quit the thread + if (leftSize > 0) { + EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], leftSize)); + playbackMQEventFlag->wake( + static_cast(DemuxQueueNotifyBits::DATA_READY)); + } + mPlaybackThreadRunning = false; + break; + } + // Write input FMQ and notify the Tuner Implementation + EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], writeSize)); + playbackMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); + inputData.seekg(writeSize, inputData.cur); + sleep(1); + } + } + + ALOGW("[vts] Playback thread end."); + + delete[] buffer; + inputData.close(); +} + // Test environment for Tuner HIDL HAL. class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: @@ -494,16 +546,21 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { sp mFrontendCallback; sp mDescrambler; sp mDemux; - sp mDemuxCallback; + sp mDvr; + sp mFilter; + std::map> mFilters; + std::map> mFilterCallbacks; + sp mFilterCallback; + sp mDvrCallback; MQDesc mFilterMQDescriptor; - MQDesc mInputMQDescriptor; + MQDesc mPlaybackMQDescriptor; vector mUsedFilterIds; uint32_t mDemuxId; uint32_t mFilterId; - pthread_t mInputThread; - bool mInputThreadRunning; + pthread_t mPlaybackshread; + bool mPlaybackThreadRunning; ::testing::AssertionResult createFrontend(int32_t frontendId); ::testing::AssertionResult tuneFrontend(int32_t frontendId); @@ -512,16 +569,16 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { ::testing::AssertionResult createDemux(); ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId, FrontendSettings settings); - ::testing::AssertionResult getInputMQDescriptor(); - ::testing::AssertionResult addInputToDemux(DemuxInputSettings setting); + ::testing::AssertionResult getPlaybackMQDescriptor(); + ::testing::AssertionResult addPlaybackToDemux(PlaybackSettings setting); ::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting); - ::testing::AssertionResult getFilterMQDescriptor(const uint32_t filterId); + ::testing::AssertionResult getFilterMQDescriptor(); ::testing::AssertionResult closeDemux(); ::testing::AssertionResult createDescrambler(); ::testing::AssertionResult closeDescrambler(); ::testing::AssertionResult playbackDataFlowTest(vector filterConf, - InputConf inputConf, + PlaybackConf playbackConf, vector goldenOutputFiles); ::testing::AssertionResult broadcastDataFlowTest(vector filterConf, vector goldenOutputFiles); @@ -665,39 +722,43 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionResult(status == Result::SUCCESS); } -::testing::AssertionResult TunerHidlTest::addInputToDemux(DemuxInputSettings setting) { +::testing::AssertionResult TunerHidlTest::addPlaybackToDemux(PlaybackSettings setting) { Result status; if (!mDemux && createDemux() == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } - // Create demux callback - if (!mDemuxCallback) { - mDemuxCallback = new DemuxCallback(); - } + // Create dvr callback + mDvrCallback = new DvrCallback(); // Add playback input to the local demux - status = mDemux->addInput(FMQ_SIZE_1M, mDemuxCallback); + mDemux->openDvr(DvrType::PLAYBACK, FMQ_SIZE_1M, mDvrCallback, + [&](Result result, const sp& dvr) { + mDvr = dvr; + status = result; + }); if (status != Result::SUCCESS) { return ::testing::AssertionFailure(); } - status = mDemux->configureInput(setting); + DvrSettings dvrSetting; + dvrSetting.playback(setting); + status = mDvr->configure(dvrSetting); return ::testing::AssertionResult(status == Result::SUCCESS); } -::testing::AssertionResult TunerHidlTest::getInputMQDescriptor() { +::testing::AssertionResult TunerHidlTest::getPlaybackMQDescriptor() { Result status; - if (!mDemux && createDemux() == ::testing::AssertionFailure()) { + if ((!mDemux && createDemux() == ::testing::AssertionFailure()) || !mDvr) { return ::testing::AssertionFailure(); } - mDemux->getInputQueueDesc([&](Result result, const MQDesc& inputMQDesc) { - mInputMQDescriptor = inputMQDesc; + mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) { + mPlaybackMQDescriptor = dvrMQDesc; status = result; }); @@ -713,13 +774,20 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { } // Create demux callback - if (!mDemuxCallback) { - mDemuxCallback = new DemuxCallback(); - } + mFilterCallback = new FilterCallback(); // Add filter to the local demux - mDemux->addFilter(type, FMQ_SIZE_4K, mDemuxCallback, [&](Result result, uint32_t filterId) { - // TODO use a map to save all the filter id and FMQ + mDemux->openFilter(type, FMQ_SIZE_16M, mFilterCallback, + [&](Result result, const sp& filter) { + mFilter = filter; + status = result; + }); + + if (status != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + + mFilter->getId([&](Result result, uint32_t filterId) { mFilterId = filterId; status = result; }); @@ -728,20 +796,64 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionFailure(); } + mFilterCallback->setFilterId(mFilterId); + + FilterEventType eventType = FilterEventType::UNDEFINED; + switch (type.mainType) { + case DemuxFilterMainType::TS: + switch (type.subType.tsFilterType()) { + case DemuxTsFilterType::UNDEFINED: + break; + case DemuxTsFilterType::SECTION: + eventType = FilterEventType::SECTION; + break; + case DemuxTsFilterType::PES: + eventType = FilterEventType::PES; + break; + case DemuxTsFilterType::TS: + break; + case DemuxTsFilterType::AUDIO: + case DemuxTsFilterType::VIDEO: + eventType = FilterEventType::MEDIA; + break; + case DemuxTsFilterType::PCR: + break; + case DemuxTsFilterType::RECORD: + eventType = FilterEventType::RECORD; + break; + } + break; + case DemuxFilterMainType::MMTP: + /*mmtpSettings*/ + break; + case DemuxFilterMainType::IP: + /*ipSettings*/ + break; + case DemuxFilterMainType::TLV: + /*tlvSettings*/ + break; + case DemuxFilterMainType::ALP: + /*alpSettings*/ + break; + default: + break; + } + mFilterCallback->setFilterEventType(eventType); + // Configure the filter - status = mDemux->configureFilter(mFilterId, setting); + status = mFilter->configure(setting); return ::testing::AssertionResult(status == Result::SUCCESS); } -::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor(const uint32_t filterId) { +::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor() { Result status; - if (!mDemux) { + if (!mDemux || !mFilter) { return ::testing::AssertionFailure(); } - mDemux->getFilterQueueDesc(filterId, [&](Result result, const MQDesc& filterMQDesc) { + mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) { mFilterMQDescriptor = filterMQDesc; status = result; }); @@ -750,7 +862,8 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { } ::testing::AssertionResult TunerHidlTest::playbackDataFlowTest( - vector filterConf, InputConf inputConf, vector /*goldenOutputFiles*/) { + vector filterConf, PlaybackConf playbackConf, + vector /*goldenOutputFiles*/) { Result status; int filterIdsSize; // Filter Configuration Module @@ -758,45 +871,58 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) == ::testing::AssertionFailure() || // TODO use a map to save the FMQs/EvenFlags and pass to callback - getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure()) { + getFilterMQDescriptor() == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } filterIdsSize = mUsedFilterIds.size(); mUsedFilterIds.resize(filterIdsSize + 1); mUsedFilterIds[filterIdsSize] = mFilterId; - mDemuxCallback->updateFilterMQ(mFilterId, mFilterMQDescriptor); - // mDemuxCallback->updateGoldenOutputMap(mFilterId, goldenOutputFiles[i]); - status = mDemux->startFilter(mFilterId); + mFilters[mFilterId] = mFilter; + mFilterCallbacks[mFilterId] = mFilterCallback; + mFilterCallback->updateFilterMQ(mFilterMQDescriptor); + // mDemuxCallback->updateGoldenOutputMap(goldenOutputFiles[i]); + status = mFilter->start(); if (status != Result::SUCCESS) { return ::testing::AssertionFailure(); } } // Playback Input Module - DemuxInputSettings inputSetting = inputConf.setting; - if (addInputToDemux(inputSetting) == ::testing::AssertionFailure() || - getInputMQDescriptor() == ::testing::AssertionFailure()) { + PlaybackSettings playbackSetting = playbackConf.setting; + if (addPlaybackToDemux(playbackSetting) == ::testing::AssertionFailure() || + getPlaybackMQDescriptor() == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } - mDemuxCallback->startPlaybackInputThread(inputConf, mInputMQDescriptor); - status = mDemux->startInput(); + for (int i = 0; i <= filterIdsSize; i++) { + if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + } + mDvrCallback->startPlaybackInputThread(playbackConf, mPlaybackMQDescriptor); + status = mDvr->start(); if (status != Result::SUCCESS) { return ::testing::AssertionFailure(); } // Data Verify Module - mDemuxCallback->testFilterDataOutput(); - mDemuxCallback->stopInputThread(); + std::map>::iterator it; + for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) { + it->second->testFilterDataOutput(); + } + mDvrCallback->stopPlaybackThread(); // Clean Up Module for (int i = 0; i <= filterIdsSize; i++) { - if (mDemux->stopFilter(mUsedFilterIds[i]) != Result::SUCCESS) { + if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) { return ::testing::AssertionFailure(); } } - if (mDemux->stopInput() != Result::SUCCESS) { + if (mDvr->stop() != Result::SUCCESS) { return ::testing::AssertionFailure(); } + mUsedFilterIds.clear(); + mFilterCallbacks.clear(); + mFilters.clear(); return closeDemux(); } @@ -831,31 +957,39 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) == ::testing::AssertionFailure() || // TODO use a map to save the FMQs/EvenFlags and pass to callback - getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure()) { + getFilterMQDescriptor() == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } filterIdsSize = mUsedFilterIds.size(); mUsedFilterIds.resize(filterIdsSize + 1); mUsedFilterIds[filterIdsSize] = mFilterId; - mDemuxCallback->updateFilterMQ(mFilterId, mFilterMQDescriptor); - status = mDemux->startFilter(mFilterId); + mFilters[mFilterId] = mFilter; + mFilterCallbacks[mFilterId] = mFilterCallback; + mFilterCallback->updateFilterMQ(mFilterMQDescriptor); + status = mFilter->start(); if (status != Result::SUCCESS) { return ::testing::AssertionFailure(); } } // Data Verify Module - mDemuxCallback->testFilterDataOutput(); + std::map>::iterator it; + for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) { + it->second->testFilterDataOutput(); + } // Clean Up Module for (int i = 0; i <= filterIdsSize; i++) { - if (mDemux->stopFilter(mUsedFilterIds[i]) != Result::SUCCESS) { + if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) { return ::testing::AssertionFailure(); } } if (mFrontend->stopTune() != Result::SUCCESS) { return ::testing::AssertionFailure(); } + mUsedFilterIds.clear(); + mFilterCallbacks.clear(); + mFilters.clear(); return closeDemux(); } @@ -992,7 +1126,7 @@ TEST_F(TunerHidlTest, CloseDescrambler) { /* * DATA FLOW TESTS */ -TEST_F(TunerHidlTest, PlaybackDataFlowWithPesFilterTest) { +TEST_F(TunerHidlTest, PlaybackDataFlowWithSectionFilterTest) { description("Feed ts data from playback and configure pes filter to get output"); // todo modulize the filter conf parser @@ -1000,32 +1134,39 @@ TEST_F(TunerHidlTest, PlaybackDataFlowWithPesFilterTest) { filterConf.resize(1); DemuxFilterSettings filterSetting; - DemuxFilterPesDataSettings pesFilterSetting{ + DemuxTsFilterSettings tsFilterSetting{ .tpid = 18, }; - filterSetting.pesData(pesFilterSetting); - FilterConf pesFilterConf{ - .type = DemuxFilterType::PES, + DemuxFilterSectionSettings sectionFilterSetting; + tsFilterSetting.filterSettings.section(sectionFilterSetting); + filterSetting.ts(tsFilterSetting); + + DemuxFilterType type{ + .mainType = DemuxFilterMainType::TS, + }; + type.subType.tsFilterType(DemuxTsFilterType::SECTION); + FilterConf sectionFilterConf{ + .type = type, .setting = filterSetting, }; - filterConf[0] = pesFilterConf; + filterConf[0] = sectionFilterConf; - DemuxInputSettings inputSetting{ + PlaybackSettings playbackSetting{ .statusMask = 0xf, .lowThreshold = 0x1000, .highThreshold = 0x07fff, - .dataFormat = DemuxDataFormat::TS, + .dataFormat = DataFormat::TS, .packetSize = 188, }; - InputConf inputConf{ + PlaybackConf playbackConf{ .inputDataFile = "/vendor/etc/test1.ts", - .setting = inputSetting, + .setting = playbackSetting, }; vector goldenOutputFiles; - ASSERT_TRUE(playbackDataFlowTest(filterConf, inputConf, goldenOutputFiles)); + ASSERT_TRUE(playbackDataFlowTest(filterConf, playbackConf, goldenOutputFiles)); } TEST_F(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) { @@ -1036,12 +1177,19 @@ TEST_F(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) { filterConf.resize(1); DemuxFilterSettings filterSetting; - DemuxFilterPesDataSettings pesFilterSetting{ - .tpid = 18, + DemuxTsFilterSettings tsFilterSetting{ + .tpid = 119, }; - filterSetting.pesData(pesFilterSetting); + DemuxFilterPesDataSettings pesFilterSetting; + tsFilterSetting.filterSettings.pesData(pesFilterSetting); + filterSetting.ts(tsFilterSetting); + + DemuxFilterType type{ + .mainType = DemuxFilterMainType::TS, + }; + type.subType.tsFilterType(DemuxTsFilterType::PES); FilterConf pesFilterConf{ - .type = DemuxFilterType::PES, + .type = type, .setting = filterSetting, }; filterConf[0] = pesFilterConf; From 7882ae68054ba53c31f182c9b56faeb9b816e370 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 10 Oct 2019 17:04:47 -0700 Subject: [PATCH 0214/1022] composer 2.4: add api to control vsync period Add new functions to improve vsync period switching by the platform: - Adding a list of supported vsync periods to Config to avoid the need to expose separate Configs for each vsync period. - Adding an API to set the vsync period with timeline constraints to allow better synchronization with vsync period change. - Extending onVsync() callback to provide the current vsync period. Test: rev up composer to 2.4 and test refresh rate switching Bug: 141329414 Change-Id: I1a6f395d9634edadc68649d02f624f00173ec519 --- graphics/composer/2.4/Android.bp | 2 + graphics/composer/2.4/IComposerCallback.hal | 35 ++++ graphics/composer/2.4/IComposerClient.hal | 87 +++++++++ graphics/composer/2.4/types.hal | 32 ++++ .../2.4/ComposerCommandBuffer.h | 2 +- .../include/composer-hal/2.4/ComposerClient.h | 82 ++++++++ .../include/composer-hal/2.4/ComposerHal.h | 26 ++- .../include/composer-passthrough/2.4/HwcHal.h | 130 ++++++++++++- .../composer/2.4/utils/vts/ComposerVts.cpp | 36 +++- .../include/composer-vts/2.4/ComposerVts.h | 14 +- .../VtsHalGraphicsComposerV2_4TargetTest.cpp | 177 ++++++++++++++++++ 11 files changed, 617 insertions(+), 6 deletions(-) create mode 100644 graphics/composer/2.4/IComposerCallback.hal create mode 100644 graphics/composer/2.4/types.hal diff --git a/graphics/composer/2.4/Android.bp b/graphics/composer/2.4/Android.bp index 0e1bc0940a..5f700bed9b 100644 --- a/graphics/composer/2.4/Android.bp +++ b/graphics/composer/2.4/Android.bp @@ -7,7 +7,9 @@ hidl_interface { enabled: true, }, srcs: [ + "types.hal", "IComposer.hal", + "IComposerCallback.hal", "IComposerClient.hal", ], interfaces: [ diff --git a/graphics/composer/2.4/IComposerCallback.hal b/graphics/composer/2.4/IComposerCallback.hal new file mode 100644 index 0000000000..5c3f8bd99c --- /dev/null +++ b/graphics/composer/2.4/IComposerCallback.hal @@ -0,0 +1,35 @@ +/* + * Copyright 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. + */ + +package android.hardware.graphics.composer@2.4; + +import @2.1::Display; +import @2.1::IComposerCallback; + +interface IComposerCallback extends @2.1::IComposerCallback { + /** + * Notifies the client that a vsync event has occurred. This callback must + * only be triggered when vsync is enabled for this display (through + * setVsyncEnabled). + * + * @param display is the display which has received a vsync event + * @param timestamp is the CLOCK_MONOTONIC time at which the vsync event + * occurred, in nanoseconds. + * @param vsyncPeriodNanos is the display vsync period in nanoseconds i.e. the next onVsync_2_4 + * is expected to be called vsyncPeriodNanos nanoseconds after this call. + */ + oneway onVsync_2_4(Display display, int64_t timestamp, VsyncPeriodNanos vsyncPeriodNanos); +}; diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal index 60445f5327..c2102d5f53 100644 --- a/graphics/composer/2.4/IComposerClient.hal +++ b/graphics/composer/2.4/IComposerClient.hal @@ -16,6 +16,8 @@ package android.hardware.graphics.composer@2.4; +import IComposerCallback; +import @2.1::Config; import @2.1::Display; import @2.1::Error; import @2.3::IComposerClient; @@ -49,6 +51,32 @@ interface IComposerClient extends @2.3::IComposerClient { EXTERNAL = 1, }; + /** + * Constraints for changing vsync period. + */ + struct VsyncPeriodChangeConstraints { + /** + * Time in CLOCK_MONOTONIC after which the vsync period may change + * (i.e., the vsync period must not change before this time). + */ + int64_t desiredTimeNanos; + /** + * If true, requires that the vsync period change must happen seamlessly without + * a noticeable visual artifact. + */ + bool seamlessRequired; + }; + + /** + * Provides a IComposerCallback object for the device to call. + * + * This function must be called only once. + * + * @param callback is the IComposerCallback object. + */ + @entry + registerCallback_2_4(IComposerCallback callback); + /** * Provides a list of supported capabilities (as described in the * definition of DisplayCapability above). This list must not change after @@ -69,4 +97,63 @@ interface IComposerClient extends @2.3::IComposerClient { * @return type is the connection type of the display. */ getDisplayConnectionType(Display display) generates (Error error, DisplayConnectionType type); + + /** + * Provides a list of the vsync periods supported by the display in the given configuration + * + * @param display is the display for which the vsync periods are queried. + * @param config is the display configuration for which the vsync periods are queried. + * + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * BAD_CONFIG when an invalid config handle was passed in. + * @return supportedVsyncPeriods is a list of supported vsync periods. + */ + getSupportedDisplayVsyncPeriods(Display display, Config config) + generates (Error error, vec supportedVsyncPeriods); + + /** + * Retrieves which vsync period the display is currently using. + * + * If no display configuration is currently active, this function must + * return BAD_CONFIG. If the vsync period is about to change due to a + * setActiveConfigAndVsyncPeriod call, this function must return the current vsync period + * until the change takes place. + * + * @param display is the display for which the vsync period is queried. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * BAD_CONFIG when no configuration is currently active. + * @return vsyncPeriodNanos is the current vsync period of the display. + */ + getDisplayVsyncPeriod(Display display) + generates (Error error, VsyncPeriodNanos vsyncPeriodNanos); + + /** + * Sets the active configuration and the refresh rate for this display. + * If the config is the same as the current config, only the vsync period shall change. + * Upon returning, the given display configuration, except vsync period, must be active and + * remain so until either this function is called again or the display is disconnected. + * When the display starts to refresh at the new vsync period, onVsync_2_4 callback must be + * called with the new vsync period. + * + * @param display is the display for which the active config is set. + * @param config is the new display configuration. + * @param vsyncPeriodNanos is the new display vsync period. + * @param vsyncPeriodChangeConstraints are the constraints required for changing vsync period. + * + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * BAD_CONFIG when the configuration handle passed in is not valid + * for this display. + * BAD_VSYNC_PERIOD when an invalid vsync period is passed in. + * SEAMLESS_NOT_POSSIBLE when seamlessRequired was true but the display cannot achieve + * the vsync period change without a noticeable visual artifact. + * @return newVsyncAppliedTime is the time in CLOCK_MONOTONIC when the new display will start to + * refresh at the new vsync period. + */ + setActiveConfigAndVsyncPeriod(Display display, Config config, + VsyncPeriodNanos vsyncPeriodNanos, + VsyncPeriodChangeConstraints vsyncPeriodChangeConstraints) + generates (Error error, int64_t newVsyncAppliedTime); }; diff --git a/graphics/composer/2.4/types.hal b/graphics/composer/2.4/types.hal new file mode 100644 index 0000000000..b45d7a69f7 --- /dev/null +++ b/graphics/composer/2.4/types.hal @@ -0,0 +1,32 @@ +/* + * Copyright 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. + */ + +package android.hardware.graphics.composer@2.4; + +import @2.1::Error; + +enum Error : @2.1::Error { + /** + * Invalid vsync period + */ + BAD_VSYNC_PERIOD = 9, + /** + * Seamless requirements cannot be met + */ + SEAMLESS_NOT_POSSIBLE = 10, +}; + +typedef uint32_t VsyncPeriodNanos; diff --git a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h index 6b64c163c0..cb391be144 100644 --- a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h +++ b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h @@ -34,7 +34,7 @@ namespace composer { namespace V2_4 { using android::hardware::MessageQueue; -using android::hardware::graphics::composer::V2_1::Error; +using android::hardware::graphics::composer::V2_4::Error; using android::hardware::graphics::composer::V2_4::IComposerClient; // This class helps build a command queue. Note that all sizes/lengths are in diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h index c810186665..ddf209bee3 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h @@ -20,8 +20,10 @@ #warning "ComposerClient.h included without LOG_TAG" #endif +#include #include #include +#include namespace android { namespace hardware { @@ -38,6 +40,54 @@ class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImplunregisterEventCallback_2_4(); } + + class HalEventCallback : public Hal::EventCallback_2_4 { + public: + HalEventCallback(const sp callback, + V2_1::hal::ComposerResources* resources) + : mCallback(callback), mResources(resources) {} + + void onHotplug(Display display, IComposerCallback::Connection connected) override { + if (connected == IComposerCallback::Connection::CONNECTED) { + mResources->addPhysicalDisplay(display); + } else if (connected == IComposerCallback::Connection::DISCONNECTED) { + mResources->removeDisplay(display); + } + + auto ret = mCallback->onHotplug(display, connected); + ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s", ret.description().c_str()); + } + + void onRefresh(Display display) override { + mResources->setDisplayMustValidateState(display, true); + auto ret = mCallback->onRefresh(display); + ALOGE_IF(!ret.isOk(), "failed to send onRefresh: %s", ret.description().c_str()); + } + + void onVsync(Display display, int64_t timestamp) override { + auto ret = mCallback->onVsync(display, timestamp); + ALOGE_IF(!ret.isOk(), "failed to send onVsync: %s", ret.description().c_str()); + } + + void onVsync_2_4(Display display, int64_t timestamp, + VsyncPeriodNanos vsyncPeriodNanos) override { + auto ret = mCallback->onVsync_2_4(display, timestamp, vsyncPeriodNanos); + ALOGE_IF(!ret.isOk(), "failed to send onVsync_2_4: %s", ret.description().c_str()); + } + + protected: + const sp mCallback; + V2_1::hal::ComposerResources* const mResources; + }; + + Return registerCallback_2_4(const sp& callback) override { + // no locking as we require this function to be called only once + mHalEventCallback_2_4 = std::make_unique(callback, mResources.get()); + mHal->registerEventCallback_2_4(mHalEventCallback_2_4.get()); + return Void(); + } + Return getDisplayCapabilities_2_4( Display display, IComposerClient::getDisplayCapabilities_2_4_cb hidl_cb) override { std::vector capabilities; @@ -54,6 +104,36 @@ class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImpl getSupportedDisplayVsyncPeriods( + Display display, Config config, + IComposerClient::getSupportedDisplayVsyncPeriods_cb hidl_cb) override { + std::vector supportedVsyncPeriods; + Error error = + mHal->getSupportedDisplayVsyncPeriods(display, config, &supportedVsyncPeriods); + hidl_cb(error, supportedVsyncPeriods); + return Void(); + } + + Return getDisplayVsyncPeriod(Display display, + IComposerClient::getDisplayVsyncPeriod_cb hidl_cb) override { + VsyncPeriodNanos vsyncPeriods; + Error error = mHal->getDisplayVsyncPeriod(display, &vsyncPeriods); + hidl_cb(error, vsyncPeriods); + return Void(); + } + + Return setActiveConfigAndVsyncPeriod( + Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos, + const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, + IComposerClient::setActiveConfigAndVsyncPeriod_cb hidl_cb) override { + int64_t newVsyncAppliedTime = 0; + Error error = mHal->setActiveConfigAndVsyncPeriod(display, config, vsyncPeriodNanos, + vsyncPeriodChangeConstraints, + &newVsyncAppliedTime); + hidl_cb(error, newVsyncAppliedTime); + return Void(); + } + static std::unique_ptr create(Hal* hal) { auto client = std::make_unique(hal); return client->init() ? std::move(client) : nullptr; @@ -63,6 +143,8 @@ class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImpl; using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl; using BaseType2_1::mHal; + std::unique_ptr mHalEventCallback_2_4; + using BaseType2_1::mResources; }; } // namespace detail diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h index c3bb535360..0739f625ab 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h @@ -16,6 +16,7 @@ #pragma once +#include #include namespace android { @@ -30,16 +31,39 @@ using common::V1_2::ColorMode; using common::V1_2::Dataspace; using common::V1_2::Hdr; using common::V1_2::PixelFormat; +using V2_1::Config; using V2_1::Display; -using V2_1::Error; using V2_1::Layer; +using V2_4::Error; +using V2_4::VsyncPeriodNanos; class ComposerHal : public V2_3::hal::ComposerHal { public: + class EventCallback_2_4 { + public: + virtual ~EventCallback_2_4() = default; + virtual void onHotplug(Display display, IComposerCallback::Connection connected) = 0; + virtual void onRefresh(Display display) = 0; + virtual void onVsync(Display display, int64_t timestamp) = 0; + virtual void onVsync_2_4(Display display, int64_t timestamp, + VsyncPeriodNanos vsyncPeriodNanos) = 0; + }; + + virtual void registerEventCallback_2_4(EventCallback_2_4* callback) = 0; + + virtual void unregisterEventCallback_2_4() = 0; + virtual Error getDisplayCapabilities_2_4( Display display, std::vector* outCapabilities) = 0; virtual Error getDisplayConnectionType(Display display, IComposerClient::DisplayConnectionType* outType) = 0; + virtual Error getSupportedDisplayVsyncPeriods( + Display display, Config config, std::vector* outVsyncPeriod) = 0; + virtual Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) = 0; + virtual Error setActiveConfigAndVsyncPeriod( + Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos, + const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, + int64_t* outNewVsyncAppliedTime) = 0; }; } // namespace hal diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h index fd05f6630b..3420c8cc07 100644 --- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h +++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h @@ -22,6 +22,7 @@ #include +#include #include #include @@ -39,18 +40,49 @@ using common::V1_2::ColorMode; using common::V1_2::Dataspace; using common::V1_2::Hdr; using common::V1_2::PixelFormat; +using V2_1::Config; using V2_1::Display; -using V2_1::Error; +using V2_4::Error; // HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2 template class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { public: + void registerEventCallback_2_4(hal::ComposerHal::EventCallback_2_4* callback) override { + mEventCallback_2_4 = callback; + + mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this, + reinterpret_cast(hotplugHook)); + mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this, + reinterpret_cast(refreshHook)); + mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this, + reinterpret_cast(vsyncHook)); + mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_2_4, this, + reinterpret_cast(vsync_2_4_Hook)); + } + + void unregisterEventCallback_2_4() override { + // we assume the callback functions + // + // - can be unregistered + // - can be in-flight + // - will never be called afterward + // + // which is likely incorrect + mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this, nullptr); + mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this, nullptr); + mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this, nullptr); + mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_2_4, this, nullptr); + + mEventCallback_2_4 = nullptr; + } + Error getDisplayCapabilities_2_4( Display display, std::vector* outCapabilities) override { std::vector capabilities; - Error error = BaseType2_3::getDisplayCapabilities(display, &capabilities); + V2_3::Error error_2_3 = BaseType2_3::getDisplayCapabilities(display, &capabilities); + Error error = static_cast(error_2_3); if (error != Error::NONE) { return error; } @@ -74,6 +106,63 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { return static_cast(error); } + Error getSupportedDisplayVsyncPeriods(Display display, Config config, + std::vector* outVsyncPeriods) override { + if (!mDispatch.getSupportedDisplayVsyncPeriods) { + return Error::UNSUPPORTED; + } + + uint32_t count = 0; + int32_t error = mDispatch.getSupportedDisplayVsyncPeriods(mDevice, display, config, &count, + nullptr); + if (error != HWC2_ERROR_NONE) { + return static_cast(error); + } + outVsyncPeriods->resize(count); + error = mDispatch.getSupportedDisplayVsyncPeriods(mDevice, display, config, &count, + outVsyncPeriods->data()); + if (error != HWC2_ERROR_NONE) { + *outVsyncPeriods = std::vector(); + return static_cast(error); + } + return Error::NONE; + } + + Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) override { + if (!mDispatch.getDisplayVsyncPeriod) { + return Error::UNSUPPORTED; + } + + int32_t error = mDispatch.getDisplayVsyncPeriod(mDevice, display, outVsyncPeriod); + if (error != HWC2_ERROR_NONE) { + return static_cast(error); + } + return Error::NONE; + } + + Error setActiveConfigAndVsyncPeriod( + Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos, + const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, + int64_t* outNewVsyncAppliedTime) override { + if (!mDispatch.setActiveConfigAndVsyncPeriod) { + return Error::UNSUPPORTED; + } + + hwc_vsync_period_change_constraints_t vsync_period_change_constraints; + vsync_period_change_constraints.desiredTimeNanos = + vsyncPeriodChangeConstraints.desiredTimeNanos; + vsync_period_change_constraints.seamlessRequired = + vsyncPeriodChangeConstraints.seamlessRequired; + + int32_t error = mDispatch.setActiveConfigAndVsyncPeriod( + mDevice, display, config, vsyncPeriodNanos, &vsync_period_change_constraints, + outNewVsyncAppliedTime); + if (error != HWC2_ERROR_NONE) { + return static_cast(error); + } + return Error::NONE; + } + protected: bool initDispatch() override { if (!BaseType2_3::initDispatch()) { @@ -82,14 +171,51 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_CONNECTION_TYPE, &mDispatch.getDisplayConnectionType); + this->initOptionalDispatch(HWC2_FUNCTION_REGISTER_CALLBACK, &mDispatch.registerCallback); + this->initOptionalDispatch(HWC2_FUNCTION_GET_SUPPORTED_DISPLAY_VSYNC_PERIODS, + &mDispatch.getSupportedDisplayVsyncPeriods); + this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_VSYNC_PERIOD, + &mDispatch.getDisplayVsyncPeriod); + this->initOptionalDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_AND_VSYNC_PERIOD, + &mDispatch.setActiveConfigAndVsyncPeriod); return true; } + static void hotplugHook(hwc2_callback_data_t callbackData, hwc2_display_t display, + int32_t connected) { + auto hal = static_cast(callbackData); + hal->mEventCallback_2_4->onHotplug(display, + static_cast(connected)); + } + + static void refreshHook(hwc2_callback_data_t callbackData, hwc2_display_t display) { + auto hal = static_cast(callbackData); + hal->mEventCallback_2_4->onRefresh(display); + } + + static void vsyncHook(hwc2_callback_data_t callbackData, hwc2_display_t display, + int64_t timestamp) { + auto hal = static_cast(callbackData); + hal->mEventCallback_2_4->onVsync(display, timestamp); + } + + static void vsync_2_4_Hook(hwc2_callback_data_t callbackData, hwc2_display_t display, + int64_t timestamp, hwc2_vsync_period_t vsyncPeriodNanos) { + auto hal = static_cast(callbackData); + hal->mEventCallback_2_4->onVsync_2_4(display, timestamp, vsyncPeriodNanos); + } + private: struct { HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE getDisplayConnectionType; + HWC2_PFN_REGISTER_CALLBACK registerCallback; + HWC2_PFN_GET_SUPPORTED_DISPLAY_VSYNC_PERIODS getSupportedDisplayVsyncPeriods; + HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD getDisplayVsyncPeriod; + HWC2_PFN_SET_ACTIVE_CONFIG_AND_VSYNC_PERIOD setActiveConfigAndVsyncPeriod; } mDispatch = {}; + hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr; + using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl; using BaseType2_3 = V2_3::passthrough::detail::HwcHalImpl; using BaseType2_1::mDevice; diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp index 937b50efb4..b02a59a90a 100644 --- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp @@ -25,7 +25,7 @@ namespace composer { namespace V2_4 { namespace vts { -using V2_1::Error; +using V2_4::Error; Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService()) {} @@ -70,6 +70,40 @@ Error ComposerClient::getDisplayConnectionType(Display display, return error; } +Error ComposerClient::getSupportedDisplayVsyncPeriods( + Display display, Config config, std::vector* outSupportedVsyncPeriods) { + Error error = Error::NONE; + mClient->getSupportedDisplayVsyncPeriods( + display, config, [&](const auto& tmpError, const auto& tmpSupportedVsyncPeriods) { + error = tmpError; + *outSupportedVsyncPeriods = tmpSupportedVsyncPeriods; + }); + return error; +} + +Error ComposerClient::getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) { + Error error = Error::NONE; + mClient->getDisplayVsyncPeriod(display, [&](const auto& tmpError, const auto& tmpVsyncPeriod) { + error = tmpError; + *outVsyncPeriod = tmpVsyncPeriod; + }); + return error; +} + +Error ComposerClient::setActiveConfigAndVsyncPeriod( + Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos, + const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, + int64_t* outNewVsyncAppliedTime) { + Error error = Error::NONE; + mClient->setActiveConfigAndVsyncPeriod( + display, config, vsyncPeriodNanos, vsyncPeriodChangeConstraints, + [&](const auto& tmpError, const auto& tmpNewVsyncAppliedTime) { + error = tmpError; + *outNewVsyncAppliedTime = tmpNewVsyncAppliedTime; + }); + return error; +} + } // namespace vts } // namespace V2_4 } // namespace composer diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h index a7d7f8644f..e8a3905c2b 100644 --- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h @@ -37,10 +37,12 @@ using common::V1_2::ColorMode; using common::V1_2::Dataspace; using common::V1_2::Hdr; using common::V1_2::PixelFormat; +using V2_1::Config; using V2_1::Display; -using V2_1::Error; +using V2_4::Error; using V2_4::IComposer; using V2_4::IComposerClient; +using V2_4::VsyncPeriodNanos; class ComposerClient; @@ -74,6 +76,16 @@ class ComposerClient : public V2_3::vts::ComposerClient { Error getDisplayConnectionType(Display display, IComposerClient::DisplayConnectionType* outType); + Error getSupportedDisplayVsyncPeriods(Display display, Config config, + std::vector* outSupportedVsyncPeriods); + + Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriods); + + Error setActiveConfigAndVsyncPeriod( + Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos, + const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, + int64_t* outNewVsyncAppliedTime); + private: const sp mClient; }; diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index 76c0039cf2..3d967fc1ea 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "graphics_composer_hidl_hal_test@2.4" #include +#include #include #include @@ -26,6 +27,7 @@ #include #include #include +#include namespace android { namespace hardware { @@ -110,8 +112,27 @@ class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return 0; } + // returns an invalid config id (one that has not been registered to a + // display). Currently assuming that a device will never have close to + // std::numeric_limit::max() configs registered while running tests + Display GetInvalidConfigId(Display display) { + std::vector validConfigs = mComposerClient->getDisplayConfigs(display); + uint64_t id = std::numeric_limits::max(); + while (id > 0) { + if (std::find(validConfigs.begin(), validConfigs.end(), id) == validConfigs.end()) { + return id; + } + id--; + } + + return 0; + } + void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } + void Test_setActiveConfigAndVsyncPeriod( + const IComposerClient::VsyncPeriodChangeConstraints& constraints); + std::unique_ptr mComposer; std::unique_ptr mComposerClient; sp mComposerCallback; @@ -189,6 +210,162 @@ TEST_F(GraphicsComposerHidlTest, getDisplayConnectionType) { } } +TEST_F(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods_BadDisplay) { + std::vector supportedVsyncPeriods; + EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->getSupportedDisplayVsyncPeriods( + mInvalidDisplayId, Config(0), &supportedVsyncPeriods)); +} + +TEST_F(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods_BadConfig) { + for (Display display : mComposerCallback->getDisplays()) { + Config invalidConfigId = GetInvalidConfigId(display); + std::vector supportedVsyncPeriods; + EXPECT_EQ(Error::BAD_CONFIG, mComposerClient->getSupportedDisplayVsyncPeriods( + display, invalidConfigId, &supportedVsyncPeriods)); + } +} + +TEST_F(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods) { + for (Display display : mComposerCallback->getDisplays()) { + for (Config config : mComposerClient->getDisplayConfigs(display)) { + std::vector supportedVsyncPeriods; + + // Get the default vsync period from the config + VsyncPeriodNanos defaultVsyncPeiord = mComposerClient->getDisplayAttribute( + display, config, IComposerClient::Attribute::VSYNC_PERIOD); + // Get all supported vsync periods for this config + EXPECT_EQ(Error::NONE, mComposerClient->getSupportedDisplayVsyncPeriods( + display, config, &supportedVsyncPeriods)); + // Default vsync period must be present in the list + EXPECT_NE(std::find(supportedVsyncPeriods.begin(), supportedVsyncPeriods.end(), + defaultVsyncPeiord), + supportedVsyncPeriods.end()); + + // Each vsync period must be unique + std::unordered_set vsyncPeriodSet; + for (VsyncPeriodNanos vsyncPeriodNanos : supportedVsyncPeriods) { + EXPECT_TRUE(vsyncPeriodSet.insert(vsyncPeriodNanos).second); + } + } + } +} + +TEST_F(GraphicsComposerHidlTest, getDisplayVsyncPeriod_BadDisplay) { + VsyncPeriodNanos vsyncPeriodNanos; + EXPECT_EQ(Error::BAD_DISPLAY, + mComposerClient->getDisplayVsyncPeriod(mInvalidDisplayId, &vsyncPeriodNanos)); +} + +TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadDisplay) { + int64_t newVsyncAppliedTime; + IComposerClient::VsyncPeriodChangeConstraints constraints; + + constraints.seamlessRequired = false; + constraints.desiredTimeNanos = systemTime(); + + EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setActiveConfigAndVsyncPeriod( + mInvalidDisplayId, Config(0), VsyncPeriodNanos(0), + constraints, &newVsyncAppliedTime)); +} + +TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadConfig) { + int64_t newVsyncAppliedTime; + IComposerClient::VsyncPeriodChangeConstraints constraints; + + constraints.seamlessRequired = false; + constraints.desiredTimeNanos = systemTime(); + + for (Display display : mComposerCallback->getDisplays()) { + Config invalidConfigId = GetInvalidConfigId(display); + EXPECT_EQ(Error::BAD_CONFIG, mComposerClient->setActiveConfigAndVsyncPeriod( + display, invalidConfigId, VsyncPeriodNanos(0), + constraints, &newVsyncAppliedTime)); + } +} + +TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadVsyncPeriod) { + int64_t newVsyncAppliedTime; + IComposerClient::VsyncPeriodChangeConstraints constraints; + + constraints.seamlessRequired = false; + constraints.desiredTimeNanos = systemTime(); + + for (Display display : mComposerCallback->getDisplays()) { + for (Config config : mComposerClient->getDisplayConfigs(display)) { + EXPECT_EQ(Error::BAD_VSYNC_PERIOD, mComposerClient->setActiveConfigAndVsyncPeriod( + display, config, VsyncPeriodNanos(0), + constraints, &newVsyncAppliedTime)); + } + } +} + +void GraphicsComposerHidlTest::Test_setActiveConfigAndVsyncPeriod( + const IComposerClient::VsyncPeriodChangeConstraints& constraints) { + int64_t newVsyncAppliedTime; + + for (Display display : mComposerCallback->getDisplays()) { + for (Config config : mComposerClient->getDisplayConfigs(display)) { + std::vector supportedVsyncPeriods; + + EXPECT_EQ(Error::NONE, mComposerClient->getSupportedDisplayVsyncPeriods( + display, config, &supportedVsyncPeriods)); + for (VsyncPeriodNanos newVsyncPeriod : supportedVsyncPeriods) { + VsyncPeriodNanos vsyncPeriodNanos; + EXPECT_EQ(Error::NONE, + mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); + + if (vsyncPeriodNanos == newVsyncPeriod) { + continue; + } + + EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigAndVsyncPeriod( + display, config, newVsyncPeriod, constraints, + &newVsyncAppliedTime)); + + EXPECT_TRUE(newVsyncAppliedTime >= constraints.desiredTimeNanos); + + // Refresh rate should change within a reasonable time + constexpr nsecs_t kReasonableTimeForChange = 1'000'000'000; // 1 second + EXPECT_TRUE(newVsyncAppliedTime - constraints.desiredTimeNanos <= + kReasonableTimeForChange); + + while (systemTime() <= newVsyncAppliedTime) { + EXPECT_EQ(Error::NONE, + mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); + if (systemTime() <= constraints.desiredTimeNanos) { + EXPECT_NE(vsyncPeriodNanos, newVsyncPeriod); + } + + if (vsyncPeriodNanos == newVsyncPeriod) { + break; + } + std::this_thread::sleep_for(10ms); + } + EXPECT_EQ(Error::NONE, + mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); + EXPECT_EQ(vsyncPeriodNanos, newVsyncPeriod); + } + } + } +} + +TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod) { + IComposerClient::VsyncPeriodChangeConstraints constraints; + + constraints.seamlessRequired = false; + constraints.desiredTimeNanos = systemTime(); + Test_setActiveConfigAndVsyncPeriod(constraints); +} + +TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_delayed) { + IComposerClient::VsyncPeriodChangeConstraints constraints; + + constexpr auto kDelayForChange = 300ms; + constraints.seamlessRequired = false; + constraints.desiredTimeNanos = systemTime() + kDelayForChange.count(); + Test_setActiveConfigAndVsyncPeriod(constraints); +} + } // namespace } // namespace vts } // namespace V2_4 From 94e44b5764314ab14a8179919c99d5e4bbb3a938 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Tue, 29 Oct 2019 13:38:53 -0700 Subject: [PATCH 0215/1022] Revert sensors multihal 2.0 changes temporarily. Revert the changes that added multihal support to sensors HAL 2.0 while waiting for merge from the same changes added to AOSP. 07b442e96 (refs/published/mh2_2) MH2 | Write processedEvents instead of original events. b38f2e251 Merge "MH2 | Check that subhal index is in range" d38f99474 Merge "MH2 | Implement debug method of HalProxy" bf46132fe (refs/published/mh2_4, mh2_4) MH2 | Implement debug method of HalProxy 1de5bb334 MH2 | Fix wakelock name e07215347 (refs/published/mh2_3, mh2_3) MH2 | Check that subhal index is in range 336c1c71e MH2 | Add restart logic in HalProxy::initialize method. 731d7125b MH2 | Change rc file to more appropriate settings f09465d11 MH2 | Add makeFMQ helpers to HalProxy_test 75cc7bf2f MH2 | Implement wakelock processing thread e93fdf9a4 MH2 | Implement dynamic sensors callbacks on HalProxy 82b84148c Remove libhwbinder/libhidltransport deps d45e49b4b Merge "MH2 | Implement pending writes thread" 597142692 MH2 | Implement pending writes thread db23aa825 MH2 | Implement direct channel and direct report methods 83e4370ae MH2 | Implement injectSensorData method of HalProxy d0cd57d4c MH2 | Implement ScopeWakelock ctor and dtor 537c0274b MH2 | Add rough proxy callback postEvents method f97a3f357 Multihal 2.0 - Small tweaks to sensorHandle handling 7a7235461 MultiHal 2.0 - setOperationMode and init direct channel flags dc7a8e789 MultiHal 2.0 - Get sensors list from subhals 4b4c7b744 MultiHal 2.0 - activate, batch, flush methods of HalProxy 1638531df MultiHal 2.0 - proxying api calls helper methods aacbf9485 Set up shell to use for unit tests 2879067dd Multihal 2.0 - Implement SubHal discovery c34e6683b Add a sub-HAL implementation for testing multi-HAL a689f8a65 Add skeleton for multihal 2.0 Bug: 136511617 Test: N/A Change-Id: Ic3588f42cf60aee6ca915be19b834462aeb7a95c --- sensors/2.0/multihal/Android.bp | 73 -- sensors/2.0/multihal/HalProxy.cpp | 686 --------------- sensors/2.0/multihal/OWNERS | 3 - sensors/2.0/multihal/ScopedWakelock.cpp | 48 - .../android.hardware.sensors@2.0-multihal.xml | 11 - ...d.hardware.sensors@2.0-service-multihal.rc | 7 - sensors/2.0/multihal/include/HalProxy.h | 396 --------- sensors/2.0/multihal/include/ScopedWakelock.h | 104 --- sensors/2.0/multihal/include/SubHal.h | 170 ---- sensors/2.0/multihal/service.cpp | 39 - sensors/2.0/multihal/tests/Android.bp | 99 --- sensors/2.0/multihal/tests/HalProxy_test.cpp | 833 ------------------ sensors/2.0/multihal/tests/fake_subhal/README | 19 - .../2.0/multihal/tests/fake_subhal/Sensor.cpp | 349 -------- .../2.0/multihal/tests/fake_subhal/Sensor.h | 157 ---- .../tests/fake_subhal/SensorsSubHal.cpp | 240 ----- .../tests/fake_subhal/SensorsSubHal.h | 165 ---- 17 files changed, 3399 deletions(-) delete mode 100644 sensors/2.0/multihal/Android.bp delete mode 100644 sensors/2.0/multihal/HalProxy.cpp delete mode 100644 sensors/2.0/multihal/OWNERS delete mode 100644 sensors/2.0/multihal/ScopedWakelock.cpp delete mode 100644 sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml delete mode 100644 sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc delete mode 100644 sensors/2.0/multihal/include/HalProxy.h delete mode 100644 sensors/2.0/multihal/include/ScopedWakelock.h delete mode 100644 sensors/2.0/multihal/include/SubHal.h delete mode 100644 sensors/2.0/multihal/service.cpp delete mode 100644 sensors/2.0/multihal/tests/Android.bp delete mode 100644 sensors/2.0/multihal/tests/HalProxy_test.cpp delete mode 100644 sensors/2.0/multihal/tests/fake_subhal/README delete mode 100644 sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp delete mode 100644 sensors/2.0/multihal/tests/fake_subhal/Sensor.h delete mode 100644 sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp delete mode 100644 sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp deleted file mode 100644 index c13eaf2e92..0000000000 --- a/sensors/2.0/multihal/Android.bp +++ /dev/null @@ -1,73 +0,0 @@ -// -// 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. - -cc_defaults { - name: "android.hardware.sensors@2.0-multihal-defaults", - header_libs: [ - "android.hardware.sensors@2.0-multihal.header", - ], - shared_libs: [ - "android.hardware.sensors@1.0", - "android.hardware.sensors@2.0", - "libbase", - "libcutils", - "libfmq", - "libhidlbase", - "liblog", - "libpower", - "libutils", - ], - cflags: ["-DLOG_TAG=\"SensorsMultiHal\""], -} - -cc_binary { - name: "android.hardware.sensors@2.0-service.multihal", - defaults: [ - "hidl_defaults", - "android.hardware.sensors@2.0-multihal-defaults", - ], - vendor: true, - relative_install_path: "hw", - srcs: [ - "service.cpp", - "HalProxy.cpp", - "ScopedWakelock.cpp", - ], - init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"], - vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"], -} - -cc_library_headers { - name: "android.hardware.sensors@2.0-multihal.header", - vendor_available: true, - export_include_dirs: ["include"], -} - -// The below targets should only be used for testing. -cc_test_library { - name: "android.hardware.sensors@2.0-HalProxy", - defaults: ["android.hardware.sensors@2.0-multihal-defaults"], - vendor_available: true, - srcs: [ - "HalProxy.cpp", - "ScopedWakelock.cpp", - ], - export_header_lib_headers: [ - "android.hardware.sensors@2.0-multihal.header", - ], - shared_libs: [ - "libutils", - ], -} diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp deleted file mode 100644 index 49c5a0d412..0000000000 --- a/sensors/2.0/multihal/HalProxy.cpp +++ /dev/null @@ -1,686 +0,0 @@ -/* - * 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. - */ - -#include "HalProxy.h" - -#include "SubHal.h" - -#include - -#include -#include "hardware_legacy/power.h" - -#include - -#include -#include -#include -#include -#include - -namespace android { -namespace hardware { -namespace sensors { -namespace V2_0 { -namespace implementation { - -using ::android::hardware::sensors::V2_0::EventQueueFlagBits; -using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; -using ::android::hardware::sensors::V2_0::implementation::getTimeNow; -using ::android::hardware::sensors::V2_0::implementation::kWakelockTimeoutNs; - -typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*); - -static constexpr int32_t kBitsAfterSubHalIndex = 24; - -/** - * Set the subhal index as first byte of sensor handle and return this modified version. - * - * @param sensorHandle The sensor handle to modify. - * @param subHalIndex The index in the hal proxy of the sub hal this sensor belongs to. - * - * @return The modified sensor handle. - */ -int32_t setSubHalIndex(int32_t sensorHandle, size_t subHalIndex) { - return sensorHandle | (static_cast(subHalIndex) << kBitsAfterSubHalIndex); -} - -/** - * Extract the subHalIndex from sensorHandle. - * - * @param sensorHandle The sensorHandle to extract from. - * - * @return The subhal index. - */ -size_t extractSubHalIndex(int32_t sensorHandle) { - return static_cast(sensorHandle >> kBitsAfterSubHalIndex); -} - -/** - * Convert nanoseconds to milliseconds. - * - * @param nanos The nanoseconds input. - * - * @return The milliseconds count. - */ -int64_t msFromNs(int64_t nanos) { - constexpr int64_t nanosecondsInAMillsecond = 1000000; - return nanos / nanosecondsInAMillsecond; -} - -HalProxy::HalProxy() { - const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf"; - initializeSubHalListFromConfigFile(kMultiHalConfigFile); - init(); -} - -HalProxy::HalProxy(std::vector& subHalList) : mSubHalList(subHalList) { - init(); -} - -HalProxy::~HalProxy() { - stopThreads(); -} - -Return HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) { - std::vector sensors; - for (const auto& iter : mSensors) { - sensors.push_back(iter.second); - } - _hidl_cb(sensors); - return Void(); -} - -Return HalProxy::setOperationMode(OperationMode mode) { - Result result = Result::OK; - size_t subHalIndex; - for (subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) { - ISensorsSubHal* subHal = mSubHalList[subHalIndex]; - result = subHal->setOperationMode(mode); - if (result != Result::OK) { - ALOGE("setOperationMode failed for SubHal: %s", subHal->getName().c_str()); - break; - } - } - if (result != Result::OK) { - // Reset the subhal operation modes that have been flipped - for (size_t i = 0; i < subHalIndex; i++) { - ISensorsSubHal* subHal = mSubHalList[i]; - subHal->setOperationMode(mCurrentOperationMode); - } - } else { - mCurrentOperationMode = mode; - } - return result; -} - -Return HalProxy::activate(int32_t sensorHandle, bool enabled) { - if (!isSubHalIndexValid(sensorHandle)) { - return Result::BAD_VALUE; - } - return getSubHalForSensorHandle(sensorHandle) - ->activate(clearSubHalIndex(sensorHandle), enabled); -} - -Return HalProxy::initialize( - const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, - const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback) { - Result result = Result::OK; - - stopThreads(); - resetSharedWakelock(); - - // So that the pending write events queue can be cleared safely and when we start threads - // again we do not get new events until after initialize resets the subhals. - disableAllSensors(); - - // Clears the queue if any events were pending write before. - mPendingWriteEventsQueue = std::queue, size_t>>(); - - // Clears previously connected dynamic sensors - mDynamicSensors.clear(); - - mDynamicSensorsCallback = sensorsCallback; - - // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions. - mEventQueue = - std::make_unique(eventQueueDescriptor, true /* resetPointers */); - - // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP - // events have been successfully read and handled by the framework. - mWakeLockQueue = - std::make_unique(wakeLockDescriptor, true /* resetPointers */); - - if (mEventQueueFlag != nullptr) { - EventFlag::deleteEventFlag(&mEventQueueFlag); - } - if (mWakelockQueueFlag != nullptr) { - EventFlag::deleteEventFlag(&mWakelockQueueFlag); - } - if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) { - result = Result::BAD_VALUE; - } - if (EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakelockQueueFlag) != OK) { - result = Result::BAD_VALUE; - } - if (!mDynamicSensorsCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) { - result = Result::BAD_VALUE; - } - - mThreadsRun.store(true); - - mPendingWritesThread = std::thread(startPendingWritesThread, this); - mWakelockThread = std::thread(startWakelockThread, this); - - for (size_t i = 0; i < mSubHalList.size(); i++) { - auto subHal = mSubHalList[i]; - const auto& subHalCallback = mSubHalCallbacks[i]; - Result currRes = subHal->initialize(subHalCallback); - if (currRes != Result::OK) { - result = currRes; - ALOGE("Subhal '%s' failed to initialize.", subHal->getName().c_str()); - break; - } - } - - mCurrentOperationMode = OperationMode::NORMAL; - - return result; -} - -Return HalProxy::batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) { - if (!isSubHalIndexValid(sensorHandle)) { - return Result::BAD_VALUE; - } - return getSubHalForSensorHandle(sensorHandle) - ->batch(clearSubHalIndex(sensorHandle), samplingPeriodNs, maxReportLatencyNs); -} - -Return HalProxy::flush(int32_t sensorHandle) { - if (!isSubHalIndexValid(sensorHandle)) { - return Result::BAD_VALUE; - } - return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle)); -} - -Return HalProxy::injectSensorData(const Event& event) { - Result result = Result::OK; - if (mCurrentOperationMode == OperationMode::NORMAL && - event.sensorType != V1_0::SensorType::ADDITIONAL_INFO) { - ALOGE("An event with type != ADDITIONAL_INFO passed to injectSensorData while operation" - " mode was NORMAL."); - result = Result::BAD_VALUE; - } - if (result == Result::OK) { - Event subHalEvent = event; - if (!isSubHalIndexValid(event.sensorHandle)) { - return Result::BAD_VALUE; - } - subHalEvent.sensorHandle = clearSubHalIndex(event.sensorHandle); - result = getSubHalForSensorHandle(event.sensorHandle)->injectSensorData(subHalEvent); - } - return result; -} - -Return HalProxy::registerDirectChannel(const SharedMemInfo& mem, - registerDirectChannel_cb _hidl_cb) { - if (mDirectChannelSubHal == nullptr) { - _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */); - } else { - mDirectChannelSubHal->registerDirectChannel(mem, _hidl_cb); - } - return Return(); -} - -Return HalProxy::unregisterDirectChannel(int32_t channelHandle) { - Result result; - if (mDirectChannelSubHal == nullptr) { - result = Result::INVALID_OPERATION; - } else { - result = mDirectChannelSubHal->unregisterDirectChannel(channelHandle); - } - return result; -} - -Return HalProxy::configDirectReport(int32_t sensorHandle, int32_t channelHandle, - RateLevel rate, configDirectReport_cb _hidl_cb) { - if (mDirectChannelSubHal == nullptr) { - _hidl_cb(Result::INVALID_OPERATION, -1 /* reportToken */); - } else { - mDirectChannelSubHal->configDirectReport(clearSubHalIndex(sensorHandle), channelHandle, - rate, _hidl_cb); - } - return Return(); -} - -Return HalProxy::debug(const hidl_handle& fd, const hidl_vec& /*args*/) { - if (fd.getNativeHandle() == nullptr || fd->numFds < 1) { - ALOGE("%s: missing fd for writing", __FUNCTION__); - return Void(); - } - - android::base::borrowed_fd writeFd = dup(fd->data[0]); - - std::ostringstream stream; - stream << "===HalProxy===" << std::endl; - stream << "Internal values:" << std::endl; - stream << " Threads are running: " << (mThreadsRun.load() ? "true" : "false") << std::endl; - int64_t now = getTimeNow(); - stream << " Wakelock timeout start time: " << msFromNs(now - mWakelockTimeoutStartTime) - << " ms ago" << std::endl; - stream << " Wakelock timeout reset time: " << msFromNs(now - mWakelockTimeoutResetTime) - << " ms ago" << std::endl; - // TODO(b/142969448): Add logging for history of wakelock acquisition per subhal. - stream << " Wakelock ref count: " << mWakelockRefCount << std::endl; - stream << " Size of pending write events queue: " << mPendingWriteEventsQueue.size() - << std::endl; - if (!mPendingWriteEventsQueue.empty()) { - stream << " Size of events list on front of pending writes queue: " - << mPendingWriteEventsQueue.front().first.size() << std::endl; - } - stream << " # of non-dynamic sensors across all subhals: " << mSensors.size() << std::endl; - stream << " # of dynamic sensors across all subhals: " << mDynamicSensors.size() << std::endl; - stream << "SubHals (" << mSubHalList.size() << "):" << std::endl; - for (ISensorsSubHal* subHal : mSubHalList) { - stream << " Name: " << subHal->getName() << std::endl; - stream << " Debug dump: " << std::endl; - android::base::WriteStringToFd(stream.str(), writeFd); - subHal->debug(fd, {}); - stream.str(""); - stream << std::endl; - } - android::base::WriteStringToFd(stream.str(), writeFd); - return Return(); -} - -Return HalProxy::onDynamicSensorsConnected(const hidl_vec& dynamicSensorsAdded, - int32_t subHalIndex) { - std::vector sensors; - { - std::lock_guard lock(mDynamicSensorsMutex); - for (SensorInfo sensor : dynamicSensorsAdded) { - if (!subHalIndexIsClear(sensor.sensorHandle)) { - ALOGE("Dynamic sensor added %s had sensorHandle with first byte not 0.", - sensor.name.c_str()); - } else { - sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex); - mDynamicSensors[sensor.sensorHandle] = sensor; - sensors.push_back(sensor); - } - } - } - mDynamicSensorsCallback->onDynamicSensorsConnected(sensors); - return Return(); -} - -Return HalProxy::onDynamicSensorsDisconnected( - const hidl_vec& dynamicSensorHandlesRemoved, int32_t subHalIndex) { - // TODO(b/143302327): Block this call until all pending events are flushed from queue - std::vector sensorHandles; - { - std::lock_guard lock(mDynamicSensorsMutex); - for (int32_t sensorHandle : dynamicSensorHandlesRemoved) { - if (!subHalIndexIsClear(sensorHandle)) { - ALOGE("Dynamic sensorHandle removed had first byte not 0."); - } else { - sensorHandle = setSubHalIndex(sensorHandle, subHalIndex); - if (mDynamicSensors.find(sensorHandle) != mDynamicSensors.end()) { - mDynamicSensors.erase(sensorHandle); - sensorHandles.push_back(sensorHandle); - } - } - } - } - mDynamicSensorsCallback->onDynamicSensorsDisconnected(sensorHandles); - return Return(); -} - -void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) { - std::ifstream subHalConfigStream(configFileName); - if (!subHalConfigStream) { - ALOGE("Failed to load subHal config file: %s", configFileName); - } else { - std::string subHalLibraryFile; - while (subHalConfigStream >> subHalLibraryFile) { - void* handle = dlopen(subHalLibraryFile.c_str(), RTLD_NOW); - if (handle == nullptr) { - ALOGE("dlopen failed for library: %s", subHalLibraryFile.c_str()); - } else { - SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr = - (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal"); - if (sensorsHalGetSubHalPtr == nullptr) { - ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s", - subHalLibraryFile.c_str()); - } else { - std::function sensorsHalGetSubHal = - *sensorsHalGetSubHalPtr; - uint32_t version; - ISensorsSubHal* subHal = sensorsHalGetSubHal(&version); - if (version != SUB_HAL_2_0_VERSION) { - ALOGE("SubHal version was not 2.0 for library: %s", - subHalLibraryFile.c_str()); - } else { - ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str()); - mSubHalList.push_back(subHal); - } - } - } - } - } -} - -void HalProxy::initializeSubHalCallbacks() { - for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) { - sp callback = new HalProxyCallback(this, subHalIndex); - mSubHalCallbacks.push_back(callback); - } -} - -void HalProxy::initializeSensorList() { - for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) { - ISensorsSubHal* subHal = mSubHalList[subHalIndex]; - auto result = subHal->getSensorsList([&](const auto& list) { - for (SensorInfo sensor : list) { - if (!subHalIndexIsClear(sensor.sensorHandle)) { - ALOGE("SubHal sensorHandle's first byte was not 0"); - } else { - ALOGV("Loaded sensor: %s", sensor.name.c_str()); - sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex); - setDirectChannelFlags(&sensor, subHal); - mSensors[sensor.sensorHandle] = sensor; - } - } - }); - if (!result.isOk()) { - ALOGE("getSensorsList call failed for SubHal: %s", subHal->getName().c_str()); - } - } -} - -void HalProxy::init() { - initializeSubHalCallbacks(); - initializeSensorList(); -} - -void HalProxy::stopThreads() { - mThreadsRun.store(false); - if (mEventQueueFlag != nullptr && mEventQueue != nullptr) { - size_t numToRead = mEventQueue->availableToRead(); - std::vector events(numToRead); - mEventQueue->read(events.data(), numToRead); - mEventQueueFlag->wake(static_cast(EventQueueFlagBits::EVENTS_READ)); - } - if (mWakelockQueueFlag != nullptr && mWakeLockQueue != nullptr) { - uint32_t kZero = 0; - mWakeLockQueue->write(&kZero); - mWakelockQueueFlag->wake(static_cast(WakeLockQueueFlagBits::DATA_WRITTEN)); - } - mWakelockCV.notify_one(); - mEventQueueWriteCV.notify_one(); - if (mPendingWritesThread.joinable()) { - mPendingWritesThread.join(); - } - if (mWakelockThread.joinable()) { - mWakelockThread.join(); - } -} - -void HalProxy::disableAllSensors() { - for (const auto& sensorEntry : mSensors) { - int32_t sensorHandle = sensorEntry.first; - activate(sensorHandle, false /* enabled */); - } - std::lock_guard dynamicSensorsLock(mDynamicSensorsMutex); - for (const auto& sensorEntry : mDynamicSensors) { - int32_t sensorHandle = sensorEntry.first; - activate(sensorHandle, false /* enabled */); - } -} - -void HalProxy::startPendingWritesThread(HalProxy* halProxy) { - halProxy->handlePendingWrites(); -} - -void HalProxy::handlePendingWrites() { - // TODO(b/143302327): Find a way to optimize locking strategy maybe using two mutexes instead of - // one. - std::unique_lock lock(mEventQueueWriteMutex); - while (mThreadsRun.load()) { - mEventQueueWriteCV.wait( - lock, [&] { return !mPendingWriteEventsQueue.empty() || !mThreadsRun.load(); }); - if (mThreadsRun.load()) { - std::vector& pendingWriteEvents = mPendingWriteEventsQueue.front().first; - size_t numWakeupEvents = mPendingWriteEventsQueue.front().second; - size_t eventQueueSize = mEventQueue->getQuantumCount(); - size_t numToWrite = std::min(pendingWriteEvents.size(), eventQueueSize); - lock.unlock(); - if (!mEventQueue->writeBlocking( - pendingWriteEvents.data(), numToWrite, - static_cast(EventQueueFlagBits::EVENTS_READ), - static_cast(EventQueueFlagBits::READ_AND_PROCESS), - kPendingWriteTimeoutNs, mEventQueueFlag)) { - ALOGE("Dropping %zu events after blockingWrite failed.", numToWrite); - if (numWakeupEvents > 0) { - if (pendingWriteEvents.size() > eventQueueSize) { - decrementRefCountAndMaybeReleaseWakelock( - countNumWakeupEvents(pendingWriteEvents, eventQueueSize)); - } else { - decrementRefCountAndMaybeReleaseWakelock(numWakeupEvents); - } - } - } - lock.lock(); - if (pendingWriteEvents.size() > eventQueueSize) { - // TODO(b/143302327): Check if this erase operation is too inefficient. It will copy - // all the events ahead of it down to fill gap off array at front after the erase. - pendingWriteEvents.erase(pendingWriteEvents.begin(), - pendingWriteEvents.begin() + eventQueueSize); - } else { - mPendingWriteEventsQueue.pop(); - } - } - } -} - -void HalProxy::startWakelockThread(HalProxy* halProxy) { - halProxy->handleWakelocks(); -} - -void HalProxy::handleWakelocks() { - std::unique_lock lock(mWakelockMutex); - while (mThreadsRun.load()) { - mWakelockCV.wait(lock, [&] { return mWakelockRefCount > 0 || !mThreadsRun.load(); }); - if (mThreadsRun.load()) { - int64_t timeLeft; - if (sharedWakelockDidTimeout(&timeLeft)) { - resetSharedWakelock(); - } else { - uint32_t numWakeLocksProcessed; - lock.unlock(); - bool success = mWakeLockQueue->readBlocking( - &numWakeLocksProcessed, 1, 0, - static_cast(WakeLockQueueFlagBits::DATA_WRITTEN), timeLeft); - lock.lock(); - if (success) { - decrementRefCountAndMaybeReleaseWakelock( - static_cast(numWakeLocksProcessed)); - } - } - } - } - resetSharedWakelock(); -} - -bool HalProxy::sharedWakelockDidTimeout(int64_t* timeLeft) { - bool didTimeout; - int64_t duration = getTimeNow() - mWakelockTimeoutStartTime; - if (duration > kWakelockTimeoutNs) { - didTimeout = true; - } else { - didTimeout = false; - *timeLeft = kWakelockTimeoutNs - duration; - } - return didTimeout; -} - -void HalProxy::resetSharedWakelock() { - std::lock_guard lockGuard(mWakelockMutex); - decrementRefCountAndMaybeReleaseWakelock(mWakelockRefCount); - mWakelockTimeoutResetTime = getTimeNow(); -} - -void HalProxy::postEventsToMessageQueue(const std::vector& events, size_t numWakeupEvents, - ScopedWakelock wakelock) { - size_t numToWrite = 0; - std::lock_guard lock(mEventQueueWriteMutex); - if (wakelock.isLocked()) { - incrementRefCountAndMaybeAcquireWakelock(numWakeupEvents); - } - if (mPendingWriteEventsQueue.empty()) { - numToWrite = std::min(events.size(), mEventQueue->availableToWrite()); - if (numToWrite > 0) { - if (mEventQueue->write(events.data(), numToWrite)) { - // TODO(b/143302327): While loop if mEventQueue->avaiableToWrite > 0 to possibly fit - // in more writes immediately - mEventQueueFlag->wake(static_cast(EventQueueFlagBits::READ_AND_PROCESS)); - } else { - numToWrite = 0; - } - } - } - if (numToWrite < events.size()) { - // TODO(b/143302327): Bound the mPendingWriteEventsQueue so that we do not trigger OOMs if - // framework stalls - std::vector eventsLeft(events.begin() + numToWrite, events.end()); - mPendingWriteEventsQueue.push({eventsLeft, numWakeupEvents}); - mEventQueueWriteCV.notify_one(); - } -} - -bool HalProxy::incrementRefCountAndMaybeAcquireWakelock(size_t delta, - int64_t* timeoutStart /* = nullptr */) { - if (!mThreadsRun.load()) return false; - std::lock_guard lockGuard(mWakelockMutex); - if (mWakelockRefCount == 0) { - acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakelockName); - mWakelockCV.notify_one(); - } - mWakelockTimeoutStartTime = getTimeNow(); - mWakelockRefCount += delta; - if (timeoutStart != nullptr) { - *timeoutStart = mWakelockTimeoutStartTime; - } - return true; -} - -void HalProxy::decrementRefCountAndMaybeReleaseWakelock(size_t delta, - int64_t timeoutStart /* = -1 */) { - if (!mThreadsRun.load()) return; - std::lock_guard lockGuard(mWakelockMutex); - if (timeoutStart == -1) timeoutStart = mWakelockTimeoutResetTime; - if (mWakelockRefCount == 0 || timeoutStart < mWakelockTimeoutResetTime) return; - mWakelockRefCount -= std::min(mWakelockRefCount, delta); - if (mWakelockRefCount == 0) { - release_wake_lock(kWakelockName); - } -} - -void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal) { - bool sensorSupportsDirectChannel = - (sensorInfo->flags & (V1_0::SensorFlagBits::MASK_DIRECT_REPORT | - V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL)) != 0; - if (mDirectChannelSubHal == nullptr && sensorSupportsDirectChannel) { - mDirectChannelSubHal = subHal; - } else if (mDirectChannelSubHal != nullptr && subHal != mDirectChannelSubHal) { - // disable direct channel capability for sensors in subHals that are not - // the only one we will enable - sensorInfo->flags &= ~(V1_0::SensorFlagBits::MASK_DIRECT_REPORT | - V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL); - } -} - -ISensorsSubHal* HalProxy::getSubHalForSensorHandle(int32_t sensorHandle) { - return mSubHalList[extractSubHalIndex(sensorHandle)]; -} - -bool HalProxy::isSubHalIndexValid(int32_t sensorHandle) { - return extractSubHalIndex(sensorHandle) < mSubHalList.size(); -} - -size_t HalProxy::countNumWakeupEvents(const std::vector& events, size_t n) { - size_t numWakeupEvents = 0; - for (size_t i = 0; i < n; i++) { - int32_t sensorHandle = events[i].sensorHandle; - if (mSensors[sensorHandle].flags & static_cast(V1_0::SensorFlagBits::WAKE_UP)) { - numWakeupEvents++; - } - } - return numWakeupEvents; -} - -int32_t HalProxy::clearSubHalIndex(int32_t sensorHandle) { - return sensorHandle & (~kSensorHandleSubHalIndexMask); -} - -bool HalProxy::subHalIndexIsClear(int32_t sensorHandle) { - return (sensorHandle & kSensorHandleSubHalIndexMask) == 0; -} - -void HalProxyCallback::postEvents(const std::vector& events, ScopedWakelock wakelock) { - if (events.empty() || !mHalProxy->areThreadsRunning()) return; - size_t numWakeupEvents; - std::vector processedEvents = processEvents(events, &numWakeupEvents); - if (numWakeupEvents > 0) { - ALOG_ASSERT(wakelock.isLocked(), - "Wakeup events posted while wakelock unlocked for subhal" - " w/ index %zu.", - mSubHalIndex); - } else { - ALOG_ASSERT(!wakelock.isLocked(), - "No Wakeup events posted but wakelock locked for subhal" - " w/ index %zu.", - mSubHalIndex); - } - mHalProxy->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock)); -} - -ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) { - ScopedWakelock wakelock(mHalProxy, lock); - return wakelock; -} - -std::vector HalProxyCallback::processEvents(const std::vector& events, - size_t* numWakeupEvents) const { - *numWakeupEvents = 0; - std::vector eventsOut; - for (Event event : events) { - event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex); - eventsOut.push_back(event); - const SensorInfo& sensor = mHalProxy->getSensorInfo(event.sensorHandle); - if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) { - (*numWakeupEvents)++; - } - } - return eventsOut; -} - -} // namespace implementation -} // namespace V2_0 -} // namespace sensors -} // namespace hardware -} // namespace android diff --git a/sensors/2.0/multihal/OWNERS b/sensors/2.0/multihal/OWNERS deleted file mode 100644 index e9556700d6..0000000000 --- a/sensors/2.0/multihal/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -arthuri@google.com -bduddie@google.com -stange@google.com \ No newline at end of file diff --git a/sensors/2.0/multihal/ScopedWakelock.cpp b/sensors/2.0/multihal/ScopedWakelock.cpp deleted file mode 100644 index d85d4a7891..0000000000 --- a/sensors/2.0/multihal/ScopedWakelock.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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. - */ - -#include "ScopedWakelock.h" - -namespace android { -namespace hardware { -namespace sensors { -namespace V2_0 { -namespace implementation { - -int64_t getTimeNow() { - return std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()) - .count(); -} - -ScopedWakelock::ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked) - : mRefCounter(refCounter), mLocked(locked) { - if (mLocked) { - mLocked = mRefCounter->incrementRefCountAndMaybeAcquireWakelock(1, &mCreatedAtTimeNs); - } -} - -ScopedWakelock::~ScopedWakelock() { - if (mLocked) { - mRefCounter->decrementRefCountAndMaybeReleaseWakelock(1, mCreatedAtTimeNs); - } -} - -} // namespace implementation -} // namespace V2_0 -} // namespace sensors -} // namespace hardware -} // namespace android \ No newline at end of file diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml b/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml deleted file mode 100644 index a771100ecc..0000000000 --- a/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - android.hardware.sensors - hwbinder - 2.0 - - ISensors - multihal - - - diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc deleted file mode 100644 index a4da3b084b..0000000000 --- a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc +++ /dev/null @@ -1,7 +0,0 @@ -service vendor.sensors-hal-2-0-multihal /vendor/bin/hw/android.hardware.sensors@2.0-service.multihal - class hal - user system - group system wakelock - writepid /dev/cpuset/system-background/tasks - capabilities BLOCK_SUSPEND - rlimit rtprio 10 10 diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h deleted file mode 100644 index b1dd737025..0000000000 --- a/sensors/2.0/multihal/include/HalProxy.h +++ /dev/null @@ -1,396 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include "ScopedWakelock.h" -#include "SubHal.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace android { -namespace hardware { -namespace sensors { -namespace V2_0 { -namespace implementation { - -using ::android::sp; -using ::android::hardware::EventFlag; -using ::android::hardware::hidl_string; -using ::android::hardware::hidl_vec; -using ::android::hardware::MessageQueue; -using ::android::hardware::MQDescriptor; -using ::android::hardware::Return; -using ::android::hardware::Void; - -class HalProxy : public ISensors, public IScopedWakelockRefCounter { - public: - using Event = ::android::hardware::sensors::V1_0::Event; - using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; - using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; - using Result = ::android::hardware::sensors::V1_0::Result; - using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo; - using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; - using ISensorsSubHal = ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal; - - explicit HalProxy(); - // Test only constructor. - explicit HalProxy(std::vector& subHalList); - ~HalProxy(); - - // Methods from ::android::hardware::sensors::V2_0::ISensors follow. - Return getSensorsList(getSensorsList_cb _hidl_cb) override; - - Return setOperationMode(OperationMode mode) override; - - Return activate(int32_t sensorHandle, bool enabled) override; - - Return initialize( - const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, - const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback) override; - - Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) override; - - Return flush(int32_t sensorHandle) override; - - Return injectSensorData(const Event& event) override; - - Return registerDirectChannel(const SharedMemInfo& mem, - registerDirectChannel_cb _hidl_cb) override; - - Return unregisterDirectChannel(int32_t channelHandle) override; - - Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, - configDirectReport_cb _hidl_cb) override; - - Return debug(const hidl_handle& fd, const hidl_vec& args) override; - - // Below methods from ::android::hardware::sensors::V2_0::ISensorsCallback with a minor change - // to pass in the sub-HAL index. While the above methods are invoked from the sensors framework - // via the binder, these methods are invoked from a callback provided to sub-HALs inside the - // same process as the HalProxy, but potentially running on different threads. - Return onDynamicSensorsConnected(const hidl_vec& dynamicSensorsAdded, - int32_t subHalIndex); - - Return onDynamicSensorsDisconnected(const hidl_vec& dynamicSensorHandlesRemoved, - int32_t subHalIndex); - - // Below methods are for HalProxyCallback - - /** - * Post events to the event message queue if there is room to write them. Otherwise post the - * remaining events to a background thread for a blocking write with a kPendingWriteTimeoutNs - * timeout. - * - * @param events The list of events to post to the message queue. - * @param numWakeupEvents The number of wakeup events in events. - * @param wakelock The wakelock associated with this post of events. - */ - void postEventsToMessageQueue(const std::vector& events, size_t numWakeupEvents, - ScopedWakelock wakelock); - - /** - * Get the sensor info associated with that sensorHandle. - * - * @param sensorHandle The sensor handle. - * - * @return The sensor info object in the mapping. - */ - const SensorInfo& getSensorInfo(int32_t sensorHandle) { return mSensors[sensorHandle]; } - - bool areThreadsRunning() { return mThreadsRun.load(); } - - // Below methods are from IScopedWakelockRefCounter interface - bool incrementRefCountAndMaybeAcquireWakelock(size_t delta, - int64_t* timeoutStart = nullptr) override; - - void decrementRefCountAndMaybeReleaseWakelock(size_t delta, int64_t timeoutStart = -1) override; - - private: - using EventMessageQueue = MessageQueue; - using WakeLockMessageQueue = MessageQueue; - - /** - * The Event FMQ where sensor events are written - */ - std::unique_ptr mEventQueue; - - /** - * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events - */ - std::unique_ptr mWakeLockQueue; - - /** - * Event Flag to signal to the framework when sensor events are available to be read and to - * interrupt event queue blocking write. - */ - EventFlag* mEventQueueFlag = nullptr; - - //! Event Flag to signal internally that the wakelock queue should stop its blocking read. - EventFlag* mWakelockQueueFlag = nullptr; - - /** - * Callback to the sensors framework to inform it that new sensors have been added or removed. - */ - sp mDynamicSensorsCallback; - - /** - * SubHal object pointers that have been saved from vendor dynamic libraries. - */ - std::vector mSubHalList; - - //! The list of subhal callbacks for each subhal where the indices correlate with mSubHalList - std::vector> mSubHalCallbacks; - - /** - * Map of sensor handles to SensorInfo objects that contains the sensor info from subhals as - * well as the modified sensor handle for the framework. - * - * The subhal index is encoded in the first byte of the sensor handle and the remaining - * bytes are generated by the subhal to identify the sensor. - */ - std::map mSensors; - - //! Map of the dynamic sensors that have been added to halproxy. - std::map mDynamicSensors; - - //! The current operation mode for all subhals. - OperationMode mCurrentOperationMode = OperationMode::NORMAL; - - //! The single subHal that supports directChannel reporting. - ISensorsSubHal* mDirectChannelSubHal = nullptr; - - //! The timeout for each pending write on background thread for events. - static const int64_t kPendingWriteTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */; - - //! The bit mask used to get the subhal index from a sensor handle. - static constexpr int32_t kSensorHandleSubHalIndexMask = 0xFF000000; - - /** - * A FIFO queue of pairs of vector of events and the number of wakeup events in that vector - * which are waiting to be written to the events fmq in the background thread. - */ - std::queue, size_t>> mPendingWriteEventsQueue; - - //! The mutex protecting writing to the fmq and the pending events queue - std::mutex mEventQueueWriteMutex; - - //! The condition variable waiting on pending write events to stack up - std::condition_variable mEventQueueWriteCV; - - //! The thread object ptr that handles pending writes - std::thread mPendingWritesThread; - - //! The thread object that handles wakelocks - std::thread mWakelockThread; - - //! The bool indicating whether to end the threads started in initialize - std::atomic_bool mThreadsRun = true; - - //! The mutex protecting access to the dynamic sensors added and removed methods. - std::mutex mDynamicSensorsMutex; - - // WakelockRefCount membar vars below - - //! The mutex protecting the wakelock refcount and subsequent wakelock releases and - //! acquisitions - std::recursive_mutex mWakelockMutex; - - std::condition_variable_any mWakelockCV; - - //! The refcount of how many ScopedWakelocks and pending wakeup events are active - size_t mWakelockRefCount = 0; - - int64_t mWakelockTimeoutStartTime = getTimeNow(); - - int64_t mWakelockTimeoutResetTime = getTimeNow(); - - const char* kWakelockName = "SensorsHAL_WAKEUP"; - - /** - * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries - * listed in a config file. - */ - void initializeSubHalListFromConfigFile(const char* configFileName); - - /** - * Initialize the HalProxyCallback vector using the list of subhals. - */ - void initializeSubHalCallbacks(); - - /** - * Initialize the list of SensorInfo objects in mSensorList by getting sensors from each - * subhal. - */ - void initializeSensorList(); - - /** - * Calls the helper methods that all ctors use. - */ - void init(); - - /** - * Stops all threads by setting the threads running flag to false and joining to them. - */ - void stopThreads(); - - /** - * Disable all the sensors observed by the HalProxy. - */ - void disableAllSensors(); - - /** - * Starts the thread that handles pending writes to event fmq. - * - * @param halProxy The HalProxy object pointer. - */ - static void startPendingWritesThread(HalProxy* halProxy); - - //! Handles the pending writes on events to eventqueue. - void handlePendingWrites(); - - /** - * Starts the thread that handles decrementing the ref count on wakeup events processed by the - * framework and timing out wakelocks. - * - * @param halProxy The HalProxy object pointer. - */ - static void startWakelockThread(HalProxy* halProxy); - - //! Handles the wakelocks. - void handleWakelocks(); - - /** - * @param timeLeft The variable that should be set to the timeleft before timeout will occur or - * unmodified if timeout occurred. - * - * @return true if the shared wakelock has been held passed the timeout and should be released - */ - bool sharedWakelockDidTimeout(int64_t* timeLeft); - - /** - * Reset all the member variables associated with the wakelock ref count and maybe release - * the shared wakelock. - */ - void resetSharedWakelock(); - - /** - * Clear direct channel flags if the HalProxy has already chosen a subhal as its direct channel - * subhal. Set the directChannelSubHal pointer to the subHal passed in if this is the first - * direct channel enabled sensor seen. - * - * @param sensorInfo The SensorInfo object that may be altered to have direct channel support - * disabled. - * @param subHal The subhal pointer that the current sensorInfo object came from. - */ - void setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal); - - /* - * Get the subhal pointer which can be found by indexing into the mSubHalList vector - * using the index from the first byte of sensorHandle. - * - * @param sensorHandle The handle used to identify a sensor in one of the subhals. - */ - ISensorsSubHal* getSubHalForSensorHandle(int32_t sensorHandle); - - /** - * Checks that sensorHandle's subhal index byte is within bounds of mSubHalList. - * - * @param sensorHandle The sensor handle to check. - * - * @return true if sensorHandles's subhal index byte is valid. - */ - bool isSubHalIndexValid(int32_t sensorHandle); - - /** - * Count the number of wakeup events in the first n events of the vector. - * - * @param events The vector of Event objects. - * @param n The end index not inclusive of events to consider. - * - * @return The number of wakeup events of the considered events. - */ - size_t countNumWakeupEvents(const std::vector& events, size_t n); - - /* - * Clear out the subhal index bytes from a sensorHandle. - * - * @param sensorHandle The sensor handle to modify. - * - * @return The modified version of the sensor handle. - */ - static int32_t clearSubHalIndex(int32_t sensorHandle); - - /** - * @param sensorHandle The sensor handle to modify. - * - * @return true if subHalIndex byte of sensorHandle is zeroed. - */ - static bool subHalIndexIsClear(int32_t sensorHandle); -}; - -/** - * Callback class used to provide the HalProxy with the index of which subHal is invoking - */ -class HalProxyCallback : public IHalProxyCallback { - using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo; - - public: - HalProxyCallback(HalProxy* halProxy, int32_t subHalIndex) - : mHalProxy(halProxy), mSubHalIndex(subHalIndex) {} - - Return onDynamicSensorsConnected( - const hidl_vec& dynamicSensorsAdded) override { - return mHalProxy->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex); - } - - Return onDynamicSensorsDisconnected( - const hidl_vec& dynamicSensorHandlesRemoved) override { - return mHalProxy->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex); - } - - void postEvents(const std::vector& events, ScopedWakelock wakelock); - - ScopedWakelock createScopedWakelock(bool lock); - - private: - HalProxy* mHalProxy; - int32_t mSubHalIndex; - - std::vector processEvents(const std::vector& events, - size_t* numWakeupEvents) const; -}; - -} // namespace implementation -} // namespace V2_0 -} // namespace sensors -} // namespace hardware -} // namespace android diff --git a/sensors/2.0/multihal/include/ScopedWakelock.h b/sensors/2.0/multihal/include/ScopedWakelock.h deleted file mode 100644 index aa6d9db3d4..0000000000 --- a/sensors/2.0/multihal/include/ScopedWakelock.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace android { -namespace hardware { -namespace sensors { -namespace V2_0 { -namespace implementation { - -using ::android::hardware::sensors::V2_0::SensorTimeout; - -const int64_t kWakelockTimeoutNs = - static_cast(SensorTimeout::WAKE_LOCK_SECONDS) * INT64_C(1000000000); - -int64_t getTimeNow(); - -class IScopedWakelockRefCounter : public RefBase { - public: - /** - * Increment the wakelock ref count and maybe acquire the shared wakelock if incrementing - * from 0 then return the time of incrementing back to caller. - * - * @param delta The amount to change ref count by. - * @param timeoutStart The ptr to the timestamp in ns that the increment occurred which will be - * set in the function or nullptr if not specified. - * - * @return true if successfully incremented the wakelock ref count. - */ - virtual bool incrementRefCountAndMaybeAcquireWakelock(size_t delta, - int64_t* timeoutStart = nullptr) = 0; - /** - * Decrement the wakelock ref count and maybe release wakelock if ref count ends up 0. - * - * @param delta The amount to change ref count by. - * @param timeoutStart The timestamp in ns that the calling context kept track of when - * incrementing the ref count or -1 by default - */ - virtual void decrementRefCountAndMaybeReleaseWakelock(size_t delta, - int64_t timeoutStart = -1) = 0; - // Virtual dtor needed for compilation success - virtual ~IScopedWakelockRefCounter(){}; -}; - -/** - * Wrapper around wake lock acquisition functions (acquire/release_wake_lock) that provides a - * RAII-style mechanism for keeping a wake lock held for the duration of a scoped block. - * When a ScopedWakelock is created, it increments the reference count stored in the HalProxy - * for the sub-HALs specific wake lock, acquiring the wake lock if necessary. When the object goes - * out of scope, the ref count is decremented, potentially releasing the wake lock if no other - * references to the wake lock exist. - * - * This class is allocated through the createScopedWakelock callback inside the IHalProxyCallback - * provided to sub-HALs during initialization and should be used for all wake lock acquisition - * inside of the sub-HAL to ensure wake locks are not held indefinitely. - * - * The most prevalent use case for this class will be for posting events to the framework through - * the postEvents HalProxy callback. The expectation is that sub-HALs will create this - * ScopedWakelock through the createScopedWakelock upon receiving a sensor events. The lock boolean - * provided to createScopedWakelock will be set the according to whether the sensor events are - * from wakeup sensors. Then, the sub-HAL will perform any processing necessary before invoking the - * postEvents callback passing in the previously created ScopedWakelock. At this point, ownership - * of the object will be passed to the HalProxy that will then be responsible for ensuring any - * wake locks continue to be held, if necessary. - */ -class ScopedWakelock { - public: - ScopedWakelock(ScopedWakelock&&) = default; - ScopedWakelock& operator=(ScopedWakelock&&) = default; - virtual ~ScopedWakelock(); - - bool isLocked() const { return mLocked; } - - private: - friend class HalProxyCallback; - IScopedWakelockRefCounter* mRefCounter; - int64_t mCreatedAtTimeNs; - bool mLocked; - ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked); - ScopedWakelock(const ScopedWakelock&) = delete; - ScopedWakelock& operator=(const ScopedWakelock&) = delete; -}; - -} // namespace implementation -} // namespace V2_0 -} // namespace sensors -} // namespace hardware -} // namespace android \ No newline at end of file diff --git a/sensors/2.0/multihal/include/SubHal.h b/sensors/2.0/multihal/include/SubHal.h deleted file mode 100644 index 92ae3a61df..0000000000 --- a/sensors/2.0/multihal/include/SubHal.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include "ScopedWakelock.h" - -#include -#include - -#include - -// Indicates the current version of the multiHAL interface formatted as (HAL major version) << 24 | -// (HAL minor version) << 16 | (multiHAL version) -#define SUB_HAL_2_0_VERSION 0x02000000 - -namespace android { -namespace hardware { -namespace sensors { -namespace V2_0 { -namespace implementation { - -using ::android::hardware::sensors::V1_0::Event; -using ::android::hardware::sensors::V1_0::Result; -using ::android::hardware::sensors::V1_0::SensorInfo; - -/** - * Interface that contains several callbacks into the HalProxy class to communicate dynamic sensor - * changes and sensor events to the framework and acquire wake locks. The HalProxy will ensure - * callbacks occurring at the same time from multiple sub-HALs are synchronized in a safe, efficient - * manner. - */ -class IHalProxyCallback : public ISensorsCallback { - public: - /** - * Thread-safe callback used to post events to the HalProxy. Sub-HALs should invoke this - * whenever new sensor events need to be delivered to the sensors framework. Once invoked, the - * HalProxy will attempt to send events to the sensors framework using a blocking write with a - * 5 second timeout. This write may be done asynchronously if the queue used to communicate - * with the framework is full to avoid blocking sub-HALs for the length of the timeout. If the - * write fails, the events will be dropped and any wake locks held will be released. - * - * The provided ScopedWakelock must be locked if the events are from wakeup sensors. If it's - * not locked accordingly, the HalProxy will crash as this indicates the sub-HAL isn't compliant - * with the sensors HAL 2.0 specification. Additionally, since ScopedWakelock isn't copyable, - * the HalProxy will take ownership of the wake lock given when this method is invoked. Once the - * method returns, the HalProxy will handle holding the wake lock, if necessary, until the - * framework has successfully processed any wakeup events. - * - * No return type is used for this callback to avoid sub-HALs trying to resend events when - * writes fail. Writes should only fail when the framework is under inordinate stress which will - * likely result in a framework restart so retrying will likely only result in overloading the - * HalProxy. Sub-HALs should always assume that the write was a success and perform any - * necessary cleanup. Additionally, the HalProxy will ensure it logs any errors (through ADB and - * bug reports) it encounters during delivery to ensure it's obvious that a failure occurred. - * - * @param events the events that should be sent to the sensors framework - * @param wakelock ScopedWakelock that should be locked to send events from wake sensors and - * unlocked otherwise. - */ - virtual void postEvents(const std::vector& events, ScopedWakelock wakelock) = 0; - - /** - * Initializes a ScopedWakelock on the stack that, when locked, will increment the reference - * count for the sub-HAL's wake lock managed inside the HalProxy. See the ScopedWakelock class - * definition for how it should be used. - * - * @param lock whether the ScopedWakelock should be locked before it's returned. - * @return the created ScopedWakelock - */ - virtual ScopedWakelock createScopedWakelock(bool lock) = 0; -}; - -/** - * ISensorsSubHal is an interface that sub-HALs must implement in order to be compliant with - * multihal 2.0 and in order for the HalProxy to successfully load and communicate with the sub-HAL. - * - * Any vendor wishing to implement this interface and support multihal 2.0 will need to create a - * dynamic library that exposes sensorsHalGetSubHal (defined below). This library will be loaded by - * the HalProxy when the sensors HAL is initialized and then the HalProxy will retrieve the vendor's - * implementation of sensorsHalGetSubHal. - * - * With the exception of the initialize method, ISensorsSubHal will implement the ISensors.hal spec. - * Any sensor handles given to the HalProxy, either through getSensorsList() or the - * onDynamicSensors(Dis)Connected callbacks, will be translated to avoid clashing with other sub-HAL - * handles. To achieve this, the HalProxy will use the upper byte to store the sub-HAL index and - * sub-HALs can continue to use the lower 3 bytes of the handle. - */ -class ISensorsSubHal : public ISensors { - public: - // The ISensors version of initialize isn't used for multihal. Instead, sub-HALs must implement - // the version below to allow communciation logic to centralized in the HalProxy - Return initialize( - const ::android::hardware::MQDescriptorSync& /* eventQueueDescriptor */, - const ::android::hardware::MQDescriptorSync& /* wakeLockDescriptor */, - const sp& /* sensorsCallback */) final { - return Result::INVALID_OPERATION; - } - - /** - * Method defined in ::android::hidl::base::V1_0::IBase. - * - * This method should write debug information to hidl_handle that is useful for debugging - * issues. Suggestions include: - * - Sensor info including handle values and any other state available in the SensorInfo class - * - List of active sensors and their current sampling period and reporting latency - * - Information about pending flush requests - * - Current operating mode - * - Currently registered direct channel info - * - A history of any of the above - */ - virtual Return debug(const hidl_handle& fd, const hidl_vec& args) = 0; - - /** - * @return A human-readable name for use in wake locks and logging. - */ - virtual const std::string getName() = 0; - - /** - * This is the first method invoked on the sub-HAL after it's allocated through - * sensorsHalGetSubHal() by the HalProxy. Sub-HALs should use this to initialize any state and - * retain the callback given in order to communicate with the HalProxy. Method will be called - * anytime the sensors framework restarts. Therefore, this method will be responsible for - * reseting the state of the subhal and cleaning up and reallocating any previously allocated - * data. Initialize should ensure that the subhal has reset its operation mode to NORMAL state - * as well. - * - * @param halProxyCallback callback used to inform the HalProxy when a dynamic sensor's state - * changes, new sensor events should be sent to the framework, and when a new ScopedWakelock - * should be created. - * @return result OK on success - */ - virtual Return initialize(const sp& halProxyCallback) = 0; -}; - -} // namespace implementation -} // namespace V2_0 -} // namespace sensors -} // namespace hardware -} // namespace android - -using ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal; - -/** - * Function that must be exported so the HalProxy class can invoke it on the sub-HAL dynamic - * library. This function will only be invoked once at initialization time. - * - * NOTE: The supported sensors HAL version must match SUB_HAL_2_0_VERSION exactly or the HalProxy - * will fail to initialize. - * - * @param uint32_t when this function returns, this parameter must contain the HAL version that - * this sub-HAL supports. To support this version of multi-HAL, this must be set to - * SUB_HAL_2_0_VERSION. - * @return A statically allocated, valid ISensorsSubHal implementation. - */ -__attribute__((visibility("default"))) extern "C" ISensorsSubHal* sensorsHalGetSubHal( - uint32_t* version); diff --git a/sensors/2.0/multihal/service.cpp b/sensors/2.0/multihal/service.cpp deleted file mode 100644 index ef77048020..0000000000 --- a/sensors/2.0/multihal/service.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include -#include "HalProxy.h" - -using android::hardware::configureRpcThreadpool; -using android::hardware::joinRpcThreadpool; -using android::hardware::sensors::V2_0::ISensors; -using android::hardware::sensors::V2_0::implementation::HalProxy; - -int main(int /* argc */, char** /* argv */) { - configureRpcThreadpool(1, true); - - android::sp halProxy = new HalProxy(); - if (halProxy->registerAsService() != ::android::OK) { - ALOGE("Failed to register Sensors HAL instance"); - return -1; - } - - joinRpcThreadpool(); - return 1; // joinRpcThreadpool shouldn't exit -} diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp deleted file mode 100644 index e7f9499db0..0000000000 --- a/sensors/2.0/multihal/tests/Android.bp +++ /dev/null @@ -1,99 +0,0 @@ -// -// 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. - -cc_defaults { - name: "android.hardware.sensors@2.0-fakesubhal-defaults", - srcs: [ - "fake_subhal/*.cpp", - ], - header_libs: [ - "android.hardware.sensors@2.0-multihal.header", - ], - export_include_dirs: ["fake_subhal"], - shared_libs: [ - "android.hardware.sensors@1.0", - "android.hardware.sensors@2.0", - "libcutils", - "libfmq", - "libhardware", - "libhidlbase", - "liblog", - "libpower", - "libutils", - ], - static_libs: [ - "android.hardware.sensors@2.0-HalProxy", - ], - cflags: [ - "-DLOG_TAG=\"FakeSubHal\"" - ], -} - -cc_library { - name: "android.hardware.sensors@2.0-fakesubhal-config1", - vendor: true, - defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"], - cflags: [ - "-DSUPPORT_CONTINUOUS_SENSORS", - "-DSUB_HAL_NAME=\"FakeSubHal-Continuous\"", - ], -} - -cc_library { - name: "android.hardware.sensors@2.0-fakesubhal-config2", - vendor: true, - defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"], - cflags: [ - "-DSUPPORT_ON_CHANGE_SENSORS", - "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"", - ], -} - -cc_test_library { - name: "android.hardware.sensors@2.0-fakesubhal-unittest", - vendor_available: true, - defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"], - cflags: [ - "-DSUPPORT_ON_CHANGE_SENSORS", - "-DSUPPORT_CONTINUOUS_SENSORS", - "-DSUB_HAL_NAME=\"FakeSubHal-Test\"", - ], -} - -cc_test { - name: "android.hardware.sensors@2.0-halproxy-unit-tests", - srcs: ["HalProxy_test.cpp"], - vendor: true, - static_libs: [ - "android.hardware.sensors@2.0-HalProxy", - "android.hardware.sensors@2.0-fakesubhal-unittest", - ], - shared_libs: [ - "android.hardware.sensors@1.0", - "android.hardware.sensors@2.0", - "libbase", - "libcutils", - "libfmq", - "libhardware", - "libhidlbase", - "liblog", - "libpower", - "libutils", - ], - test_suites: ["device-tests"], - cflags: [ - "-DLOG_TAG=\"HalProxyUnitTests\"", - ], -} diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp deleted file mode 100644 index 1fd35d1afb..0000000000 --- a/sensors/2.0/multihal/tests/HalProxy_test.cpp +++ /dev/null @@ -1,833 +0,0 @@ -// -// 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. - -#include - -#include -#include - -#include "HalProxy.h" -#include "ScopedWakelock.h" -#include "SensorsSubHal.h" - -#include -#include -#include -#include - -namespace { - -using ::android::hardware::EventFlag; -using ::android::hardware::hidl_vec; -using ::android::hardware::MessageQueue; -using ::android::hardware::Return; -using ::android::hardware::sensors::V1_0::EventPayload; -using ::android::hardware::sensors::V1_0::SensorFlagBits; -using ::android::hardware::sensors::V1_0::SensorInfo; -using ::android::hardware::sensors::V1_0::SensorType; -using ::android::hardware::sensors::V2_0::EventQueueFlagBits; -using ::android::hardware::sensors::V2_0::ISensorsCallback; -using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; -using ::android::hardware::sensors::V2_0::implementation::HalProxy; -using ::android::hardware::sensors::V2_0::implementation::HalProxyCallback; -using ::android::hardware::sensors::V2_0::subhal::implementation::AddAndRemoveDynamicSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation:: - AllSupportDirectChannelSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation:: - DoesNotSupportDirectChannelSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation:: - SetOperationModeFailingSensorsSubHal; - -using EventMessageQueue = MessageQueue; -using WakeupMessageQueue = MessageQueue; - -// The barebones sensors callback class passed into halproxy initialize calls -class SensorsCallback : public ISensorsCallback { - public: - Return onDynamicSensorsConnected( - const hidl_vec& /*dynamicSensorsAdded*/) override { - // Nothing yet - return Return(); - } - - Return onDynamicSensorsDisconnected( - const hidl_vec& /*dynamicSensorHandlesRemoved*/) override { - // Nothing yet - return Return(); - } -}; - -// The sensors callback that expects a variable list of sensors to be added -class TestSensorsCallback : public ISensorsCallback { - public: - Return onDynamicSensorsConnected( - const hidl_vec& dynamicSensorsAdded) override { - mSensorsConnected.insert(mSensorsConnected.end(), dynamicSensorsAdded.begin(), - dynamicSensorsAdded.end()); - return Return(); - } - - Return onDynamicSensorsDisconnected( - const hidl_vec& dynamicSensorHandlesRemoved) override { - mSensorHandlesDisconnected.insert(mSensorHandlesDisconnected.end(), - dynamicSensorHandlesRemoved.begin(), - dynamicSensorHandlesRemoved.end()); - return Return(); - } - - const std::vector& getSensorsConnected() const { return mSensorsConnected; } - const std::vector& getSensorHandlesDisconnected() const { - return mSensorHandlesDisconnected; - } - - private: - std::vector mSensorsConnected; - std::vector mSensorHandlesDisconnected; -}; - -// Helper declarations follow - -/** - * Tests that for each SensorInfo object from a proxy getSensorsList call each corresponding - * object from a subhal getSensorsList call has the same type and its last 3 bytes are the - * same for sensorHandle field. - * - * @param proxySensorsList The list of SensorInfo objects from the proxy.getSensorsList callback. - * @param subHalSenosrsList The list of SensorInfo objects from the subHal.getSensorsList callback. - */ -void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, - const std::vector& subHalSensorsList); - -/** - * Tests that there is exactly one subhal that allows its sensors to have direct channel enabled. - * Therefore, all SensorInfo objects that are not from the enabled subhal should be disabled for - * direct channel. - * - * @param sensorsList The SensorInfo object list from proxy.getSensorsList call. - * @param enabledSubHalIndex The index of the subhal in the halproxy that is expected to be - * enabled. - */ -void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector& sensorsList, - size_t enabledSubHalIndex); - -void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr& wakelockQueue, - EventFlag* wakelockQueueFlag); - -bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& eventQueue, - EventFlag* eventQueueFlag); - -std::unique_ptr makeEventFMQ(size_t size); - -std::unique_ptr makeWakelockFMQ(size_t size); - -/** - * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor - * which is a wakeup type sensor. - * - * @return A proximity event. - */ -Event makeProximityEvent(); - -/** - * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor - * which is a wakeup type sensor. - * - * @return A proximity event. - */ -Event makeAccelerometerEvent(); - -/** - * Make a certain number of proximity type events with the sensorHandle field set to - * the proper number for AllSensorsSubHal subhal type. - * - * @param numEvents The number of events to make. - * - * @return The created list of events. - */ -std::vector makeMultipleProximityEvents(size_t numEvents); - -/** - * Make a certain number of accelerometer type events with the sensorHandle field set to - * the proper number for AllSensorsSubHal subhal type. - * - * @param numEvents The number of events to make. - * - * @return The created list of events. - */ -std::vector makeMultipleAccelerometerEvents(size_t numEvents); - -/** - * Given a SensorInfo vector and a sensor handles vector populate 'sensors' with SensorInfo - * objects that have the sensorHandle property set to int32_ts from start to start + size - * (exclusive) and push those sensorHandles also onto 'sensorHandles'. - * - * @param start The starting sensorHandle value. - * @param size The ending (not included) sensorHandle value. - * @param sensors The SensorInfo object vector reference to push_back to. - * @param sensorHandles The sensor handles int32_t vector reference to push_back to. - */ -void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size, - std::vector& sensors, - std::vector& sensorHandles); - -// Tests follow -TEST(HalProxyTest, GetSensorsListOneSubHalTest) { - AllSensorsSubHal subHal; - std::vector fakeSubHals{&subHal}; - HalProxy proxy(fakeSubHals); - - proxy.getSensorsList([&](const auto& proxySensorsList) { - subHal.getSensorsList([&](const auto& subHalSensorsList) { - testSensorsListFromProxyAndSubHal(proxySensorsList, subHalSensorsList); - }); - }); -} - -TEST(HalProxyTest, GetSensorsListTwoSubHalTest) { - ContinuousSensorsSubHal continuousSubHal; - OnChangeSensorsSubHal onChangeSubHal; - std::vector fakeSubHals; - fakeSubHals.push_back(&continuousSubHal); - fakeSubHals.push_back(&onChangeSubHal); - HalProxy proxy(fakeSubHals); - - std::vector proxySensorsList, combinedSubHalSensorsList; - - proxy.getSensorsList([&](const auto& list) { proxySensorsList = list; }); - continuousSubHal.getSensorsList([&](const auto& list) { - combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end()); - }); - onChangeSubHal.getSensorsList([&](const auto& list) { - combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end()); - }); - - testSensorsListFromProxyAndSubHal(proxySensorsList, combinedSubHalSensorsList); -} - -TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) { - ContinuousSensorsSubHal subHal1; - OnChangeSensorsSubHal subHal2; - - std::vector fakeSubHals{&subHal1, &subHal2}; - HalProxy proxy(fakeSubHals); - - EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL); - EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL); - - Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION); - - EXPECT_EQ(result, Result::OK); - EXPECT_EQ(subHal1.getOperationMode(), OperationMode::DATA_INJECTION); - EXPECT_EQ(subHal2.getOperationMode(), OperationMode::DATA_INJECTION); -} - -TEST(HalProxyTest, SetOperationModeTwoSubHalFailTest) { - AllSensorsSubHal subHal1; - SetOperationModeFailingSensorsSubHal subHal2; - - std::vector fakeSubHals{&subHal1, &subHal2}; - HalProxy proxy(fakeSubHals); - - EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL); - EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL); - - Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION); - - EXPECT_NE(result, Result::OK); - EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL); - EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL); -} - -TEST(HalProxyTest, InitDirectChannelTwoSubHalsUnitTest) { - AllSupportDirectChannelSensorsSubHal subHal1; - AllSupportDirectChannelSensorsSubHal subHal2; - - std::vector fakeSubHals{&subHal1, &subHal2}; - HalProxy proxy(fakeSubHals); - - proxy.getSensorsList([&](const auto& sensorsList) { - testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 0); - }); -} - -TEST(HalProxyTest, InitDirectChannelThreeSubHalsUnitTest) { - DoesNotSupportDirectChannelSensorsSubHal subHal1; - AllSupportDirectChannelSensorsSubHal subHal2, subHal3; - std::vector fakeSubHals{&subHal1, &subHal2, &subHal3}; - HalProxy proxy(fakeSubHals); - - proxy.getSensorsList([&](const auto& sensorsList) { - testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 1); - }); -} - -TEST(HalProxyTest, PostSingleNonWakeupEvent) { - constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; - std::vector subHals{&subHal}; - HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - - std::vector events{makeAccelerometerEvent()}; - subHal.postEvents(events, false /* wakeup */); - - EXPECT_EQ(eventQueue->availableToRead(), 1); -} - -TEST(HalProxyTest, PostMultipleNonWakeupEvent) { - constexpr size_t kQueueSize = 5; - constexpr size_t kNumEvents = 3; - AllSensorsSubHal subHal; - std::vector subHals{&subHal}; - HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal.postEvents(events, false /* wakeup */); - - EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); -} - -TEST(HalProxyTest, PostSingleWakeupEvent) { - constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; - std::vector subHals{&subHal}; - HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - - EventFlag* eventQueueFlag; - EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag); - - EventFlag* wakelockQueueFlag; - EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag); - - std::vector events{makeProximityEvent()}; - subHal.postEvents(events, true /* wakeup */); - - EXPECT_EQ(eventQueue->availableToRead(), 1); - - readEventsOutOfQueue(1, eventQueue, eventQueueFlag); - ackWakeupEventsToHalProxy(1, wakeLockQueue, wakelockQueueFlag); -} - -TEST(HalProxyTest, PostMultipleWakeupEvents) { - constexpr size_t kQueueSize = 5; - constexpr size_t kNumEvents = 3; - AllSensorsSubHal subHal; - std::vector subHals{&subHal}; - HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - - EventFlag* eventQueueFlag; - EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag); - - EventFlag* wakelockQueueFlag; - EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag); - - std::vector events = makeMultipleProximityEvents(kNumEvents); - subHal.postEvents(events, true /* wakeup */); - - EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); - - readEventsOutOfQueue(kNumEvents, eventQueue, eventQueueFlag); - ackWakeupEventsToHalProxy(kNumEvents, wakeLockQueue, wakelockQueueFlag); -} - -TEST(HalProxyTest, PostEventsMultipleSubhals) { - constexpr size_t kQueueSize = 5; - constexpr size_t kNumEvents = 2; - AllSensorsSubHal subHal1, subHal2; - std::vector subHals{&subHal1, &subHal2}; - HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal1.postEvents(events, false /* wakeup */); - - EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); - - subHal2.postEvents(events, false /* wakeup */); - - EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2); -} - -TEST(HalProxyTest, PostEventsDelayedWrite) { - constexpr size_t kQueueSize = 5; - constexpr size_t kNumEvents = 6; - AllSensorsSubHal subHal1, subHal2; - std::vector subHals{&subHal1, &subHal2}; - HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - - EventFlag* eventQueueFlag; - EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag); - - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal1.postEvents(events, false /* wakeup */); - - EXPECT_EQ(eventQueue->availableToRead(), kQueueSize); - - // readblock a full queue size worth of events out of queue, timeout for half a second - EXPECT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag)); - - // proxy background thread should have wrote remaining events when it saw space - EXPECT_TRUE(readEventsOutOfQueue(kNumEvents - kQueueSize, eventQueue, eventQueueFlag)); - - EXPECT_EQ(eventQueue->availableToRead(), 0); -} - -TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) { - constexpr size_t kQueueSize = 5; - constexpr size_t kNumEvents = 2; - AllSensorsSubHal subHal1, subHal2; - std::vector subHals{&subHal1, &subHal2}; - HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - - std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, events, false); - std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, events, false); - - t1.join(); - t2.join(); - - EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2); -} - -TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThread) { - constexpr size_t kQueueSize = 5; - constexpr size_t kNumEvents = 6; - AllSensorsSubHal subHal; - std::vector subHals{&subHal}; - - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); - HalProxy proxy(subHals); - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal.postEvents(events, false /* wakeup */); - - // Destructing HalProxy object with events on the background thread -} - -TEST(HalProxyTest, DestructingWithUnackedWakeupEventsPosted) { - constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; - std::vector subHals{&subHal}; - - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); - HalProxy proxy(subHals); - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - - std::vector events{makeProximityEvent()}; - subHal.postEvents(events, true /* wakeup */); - - // Not sending any acks back through wakeLockQueue - - // Destructing HalProxy object with unacked wakeup events posted -} - -TEST(HalProxyTest, ReinitializeWithEventsPendingOnBackgroundThread) { - constexpr size_t kQueueSize = 5; - constexpr size_t kNumEvents = 10; - AllSensorsSubHal subHal; - std::vector subHals{&subHal}; - - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); - HalProxy proxy(subHals); - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal.postEvents(events, false /* wakeup */); - - eventQueue = makeEventFMQ(kQueueSize); - wakeLockQueue = makeWakelockFMQ(kQueueSize); - - Result secondInitResult = - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - EXPECT_EQ(secondInitResult, Result::OK); - // Small sleep so that pending writes thread has a change to hit writeBlocking call. - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - Event eventOut; - EXPECT_FALSE(eventQueue->read(&eventOut)); -} - -TEST(HalProxyTest, ReinitializingWithUnackedWakeupEventsPosted) { - constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; - std::vector subHals{&subHal}; - - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); - HalProxy proxy(subHals); - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - - std::vector events{makeProximityEvent()}; - subHal.postEvents(events, true /* wakeup */); - - // Not sending any acks back through wakeLockQueue - - eventQueue = makeEventFMQ(kQueueSize); - wakeLockQueue = makeWakelockFMQ(kQueueSize); - - Result secondInitResult = - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - EXPECT_EQ(secondInitResult, Result::OK); -} - -TEST(HalProxyTest, InitializeManyTimesInARow) { - constexpr size_t kQueueSize = 5; - constexpr size_t kNumTimesToInit = 100; - AllSensorsSubHal subHal; - std::vector subHals{&subHal}; - - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); - HalProxy proxy(subHals); - - for (size_t i = 0; i < kNumTimesToInit; i++) { - Result secondInitResult = - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - EXPECT_EQ(secondInitResult, Result::OK); - } -} - -TEST(HalProxyTest, OperationModeResetOnInitialize) { - constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; - std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); - HalProxy proxy(subHals); - proxy.setOperationMode(OperationMode::DATA_INJECTION); - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - Event event = makeAccelerometerEvent(); - // Should not be able to inject a non AdditionInfo type event because operation mode should - // have been reset to NORMAL - EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE); -} - -TEST(HalProxyTest, DynamicSensorsDiscardedOnInitialize) { - constexpr size_t kQueueSize = 5; - constexpr size_t kNumSensors = 5; - AddAndRemoveDynamicSensorsSubHal subHal; - std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - HalProxy proxy(subHals); - - std::vector sensorsToConnect; - std::vector sensorHandlesToAttemptToRemove; - makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect, - sensorHandlesToAttemptToRemove); - - std::vector nonDynamicSensorHandles; - for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) { - nonDynamicSensorHandles.push_back(sensorHandle); - } - - TestSensorsCallback* callback = new TestSensorsCallback(); - ::android::sp callbackPtr = callback; - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); - subHal.addDynamicSensors(sensorsToConnect); - - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); - subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove); - - std::vector sensorHandlesActuallyRemoved = callback->getSensorHandlesDisconnected(); - - // Should not have received the sensorHandles for any dynamic sensors that were removed since - // all of them should have been removed in the second initialize call. - EXPECT_TRUE(sensorHandlesActuallyRemoved.empty()); -} - -TEST(HalProxyTest, DynamicSensorsConnectedTest) { - constexpr size_t kNumSensors = 3; - AddAndRemoveDynamicSensorsSubHal subHal; - std::vector subHals{&subHal}; - HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(0); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(0); - - std::vector sensorsToConnect; - std::vector sensorHandlesToExpect; - makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect, - sensorHandlesToExpect); - - TestSensorsCallback* callback = new TestSensorsCallback(); - ::android::sp callbackPtr = callback; - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); - subHal.addDynamicSensors(sensorsToConnect); - - std::vector sensorsSeen = callback->getSensorsConnected(); - EXPECT_EQ(kNumSensors, sensorsSeen.size()); - for (size_t i = 0; i < kNumSensors; i++) { - auto sensorHandleSeen = sensorsSeen[i].sensorHandle; - // Note since only one subhal we do not need to change first byte for expected - auto sensorHandleExpected = sensorHandlesToExpect[i]; - EXPECT_EQ(sensorHandleSeen, sensorHandleExpected); - } -} - -TEST(HalProxyTest, DynamicSensorsDisconnectedTest) { - constexpr size_t kNumSensors = 3; - AddAndRemoveDynamicSensorsSubHal subHal; - std::vector subHals{&subHal}; - HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(0); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(0); - - std::vector sensorsToConnect; - std::vector sensorHandlesToExpect; - makeSensorsAndSensorHandlesStartingAndOfSize(20, kNumSensors, sensorsToConnect, - sensorHandlesToExpect); - - std::vector nonDynamicSensorHandles; - for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) { - nonDynamicSensorHandles.push_back(sensorHandle); - } - - std::set nonDynamicSensorHandlesSet(nonDynamicSensorHandles.begin(), - nonDynamicSensorHandles.end()); - - std::vector sensorHandlesToAttemptToRemove; - sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(), - sensorHandlesToExpect.begin(), - sensorHandlesToExpect.end()); - sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(), - nonDynamicSensorHandles.begin(), - nonDynamicSensorHandles.end()); - - TestSensorsCallback* callback = new TestSensorsCallback(); - ::android::sp callbackPtr = callback; - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); - subHal.addDynamicSensors(sensorsToConnect); - subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove); - - std::vector sensorHandlesSeen = callback->getSensorHandlesDisconnected(); - EXPECT_EQ(kNumSensors, sensorHandlesSeen.size()); - for (size_t i = 0; i < kNumSensors; i++) { - auto sensorHandleSeen = sensorHandlesSeen[i]; - // Note since only one subhal we do not need to change first byte for expected - auto sensorHandleExpected = sensorHandlesToExpect[i]; - EXPECT_EQ(sensorHandleSeen, sensorHandleExpected); - EXPECT_TRUE(nonDynamicSensorHandlesSet.find(sensorHandleSeen) == - nonDynamicSensorHandlesSet.end()); - } -} - -TEST(HalProxyTest, InvalidSensorHandleSubHalIndexProxyCalls) { - constexpr size_t kNumSubHals = 3; - constexpr size_t kQueueSize = 5; - int32_t kNumSubHalsInt32 = static_cast(kNumSubHals); - std::vector subHalObjs(kNumSubHals); - std::vector subHals; - for (const auto& subHal : subHalObjs) { - subHals.push_back((ISensorsSubHal*)(&subHal)); - } - - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); - HalProxy proxy(subHals); - // Initialize for the injectSensorData call so callback postEvents is valid - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - - // For testing proxy.injectSensorData properly - proxy.setOperationMode(OperationMode::DATA_INJECTION); - - // kNumSubHalsInt32 index is one off the end of mSubHalList in proxy object - EXPECT_EQ(proxy.activate(0x00000001 | (kNumSubHalsInt32 << 24), true), Result::BAD_VALUE); - EXPECT_EQ(proxy.batch(0x00000001 | (kNumSubHalsInt32 << 24), 0, 0), Result::BAD_VALUE); - EXPECT_EQ(proxy.flush(0x00000001 | (kNumSubHalsInt32 << 24)), Result::BAD_VALUE); - Event event; - event.sensorHandle = 0x00000001 | (kNumSubHalsInt32 << 24); - EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE); -} - -TEST(HalProxyTest, PostedEventSensorHandleSubHalIndexValid) { - constexpr size_t kQueueSize = 5; - constexpr int32_t subhal1Index = 0; - constexpr int32_t subhal2Index = 1; - AllSensorsSubHal subhal1; - AllSensorsSubHal subhal2; - std::vector subHals{&subhal1, &subhal2}; - - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); - HalProxy proxy(subHals); - proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - - int32_t sensorHandleToPost = 0x00000001; - Event eventIn = makeAccelerometerEvent(); - eventIn.sensorHandle = sensorHandleToPost; - std::vector eventsToPost{eventIn}; - subhal1.postEvents(eventsToPost, false); - - Event eventOut; - EXPECT_TRUE(eventQueue->read(&eventOut)); - - EXPECT_EQ(eventOut.sensorHandle, (subhal1Index << 24) | sensorHandleToPost); - - subhal2.postEvents(eventsToPost, false); - - EXPECT_TRUE(eventQueue->read(&eventOut)); - - EXPECT_EQ(eventOut.sensorHandle, (subhal2Index << 24) | sensorHandleToPost); -} - -// Helper implementations follow -void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, - const std::vector& subHalSensorsList) { - EXPECT_EQ(proxySensorsList.size(), subHalSensorsList.size()); - - for (size_t i = 0; i < proxySensorsList.size(); i++) { - const SensorInfo& proxySensor = proxySensorsList[i]; - const SensorInfo& subHalSensor = subHalSensorsList[i]; - - EXPECT_EQ(proxySensor.type, subHalSensor.type); - EXPECT_EQ(proxySensor.sensorHandle & 0x00FFFFFF, subHalSensor.sensorHandle); - } -} - -void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector& sensorsList, - size_t enabledSubHalIndex) { - for (const SensorInfo& sensor : sensorsList) { - size_t subHalIndex = static_cast(sensor.sensorHandle >> 24); - if (subHalIndex == enabledSubHalIndex) { - // First subhal should have been picked as the direct channel subhal - // and so have direct channel enabled on all of its sensors - EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0); - EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0); - } else { - // All other subhals should have direct channel disabled for all sensors - EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0); - EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0); - } - } -} - -void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr& wakelockQueue, - EventFlag* wakelockQueueFlag) { - uint32_t numEventsUInt32 = static_cast(numEvents); - wakelockQueue->write(&numEventsUInt32); - wakelockQueueFlag->wake(static_cast(WakeLockQueueFlagBits::DATA_WRITTEN)); -} - -bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& eventQueue, - EventFlag* eventQueueFlag) { - constexpr int64_t kReadBlockingTimeout = INT64_C(500000000); - std::vector events(numEvents); - return eventQueue->readBlocking(events.data(), numEvents, - static_cast(EventQueueFlagBits::EVENTS_READ), - static_cast(EventQueueFlagBits::READ_AND_PROCESS), - kReadBlockingTimeout, eventQueueFlag); -} - -std::unique_ptr makeEventFMQ(size_t size) { - return std::make_unique(size, true); -} - -std::unique_ptr makeWakelockFMQ(size_t size) { - return std::make_unique(size, true); -} - -Event makeProximityEvent() { - Event event; - event.timestamp = 0xFF00FF00; - // This is the sensorhandle of proximity, which is wakeup type - event.sensorHandle = 0x00000008; - event.sensorType = SensorType::PROXIMITY; - event.u = EventPayload(); - return event; -} - -Event makeAccelerometerEvent() { - Event event; - event.timestamp = 0xFF00FF00; - // This is the sensorhandle of proximity, which is wakeup type - event.sensorHandle = 0x00000001; - event.sensorType = SensorType::ACCELEROMETER; - event.u = EventPayload(); - return event; -} - -std::vector makeMultipleProximityEvents(size_t numEvents) { - std::vector events; - for (size_t i = 0; i < numEvents; i++) { - events.push_back(makeProximityEvent()); - } - return events; -} - -std::vector makeMultipleAccelerometerEvents(size_t numEvents) { - std::vector events; - for (size_t i = 0; i < numEvents; i++) { - events.push_back(makeAccelerometerEvent()); - } - return events; -} - -void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size, - std::vector& sensors, - std::vector& sensorHandles) { - for (int32_t sensorHandle = start; sensorHandle < start + static_cast(size); - sensorHandle++) { - SensorInfo sensor; - // Just set the sensorHandle field to the correct value so as to not have - // to compare every field - sensor.sensorHandle = sensorHandle; - sensors.push_back(sensor); - sensorHandles.push_back(sensorHandle); - } -} - -} // namespace diff --git a/sensors/2.0/multihal/tests/fake_subhal/README b/sensors/2.0/multihal/tests/fake_subhal/README deleted file mode 100644 index ddcc58452f..0000000000 --- a/sensors/2.0/multihal/tests/fake_subhal/README +++ /dev/null @@ -1,19 +0,0 @@ -This directory contains a modified version of the default implementation -provided for sensors HAL 2.0 to support multi-HAL 2.0. It should be used as a -means to verify the multi-HAL 2.0 implementation can successfully load and -interact with sub-HALs. - -This sub-HAL implementation has two macros that can be used to configure support -for different sets of sensors. One "SUPPORT_CONTINUOUS_SENSORS", enables -support for continuous sensors like accel, and gyro whereas the other -"SUPPORT_ON_CHANGE_SENSORS" enables support for on change sensors like the -light and proximity sensor. A build target is defined for each of these macros, -but more targets could be added to support both in one sub-HAL or none at all, -if necessary. - -When built, the library will be written to -out/target/product//vendor/lib64/android.hardware.sensors@2.0-fakesubhal.so - -Take this .so and place it where the multi-HAL config will cause the HalProxy to -look and then restart the system server with adb shell stop / adb shell start -to cause the multi-HAL to restart and attempt to load in the sub-HAL. diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp b/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp deleted file mode 100644 index de89a00ef9..0000000000 --- a/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp +++ /dev/null @@ -1,349 +0,0 @@ -/* - * 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. - */ - -#include "Sensor.h" - -#include -#include - -#include - -namespace android { -namespace hardware { -namespace sensors { -namespace V2_0 { -namespace subhal { -namespace implementation { - -using ::android::hardware::sensors::V1_0::MetaDataEventType; -using ::android::hardware::sensors::V1_0::SensorFlagBits; -using ::android::hardware::sensors::V1_0::SensorStatus; - -Sensor::Sensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : mIsEnabled(false), - mSamplingPeriodNs(0), - mLastSampleTimeNs(0), - mCallback(callback), - mMode(OperationMode::NORMAL) { - mSensorInfo.sensorHandle = sensorHandle; - mSensorInfo.vendor = "Vendor String"; - mSensorInfo.version = 1; - constexpr float kDefaultMaxDelayUs = 1000 * 1000; - mSensorInfo.maxDelay = kDefaultMaxDelayUs; - mSensorInfo.fifoReservedEventCount = 0; - mSensorInfo.fifoMaxEventCount = 0; - mSensorInfo.requiredPermission = ""; - mSensorInfo.flags = 0; - mRunThread = std::thread(startThread, this); -} - -Sensor::~Sensor() { - // Ensure that lock is unlocked before calling mRunThread.join() or a - // deadlock will occur. - { - std::unique_lock lock(mRunMutex); - mStopThread = true; - mIsEnabled = false; - mWaitCV.notify_all(); - } - mRunThread.join(); -} - -const SensorInfo& Sensor::getSensorInfo() const { - return mSensorInfo; -} - -void Sensor::batch(int32_t samplingPeriodNs) { - samplingPeriodNs = - std::clamp(samplingPeriodNs, mSensorInfo.minDelay * 1000, mSensorInfo.maxDelay * 1000); - - if (mSamplingPeriodNs != samplingPeriodNs) { - mSamplingPeriodNs = samplingPeriodNs; - // Wake up the 'run' thread to check if a new event should be generated now - mWaitCV.notify_all(); - } -} - -void Sensor::activate(bool enable) { - if (mIsEnabled != enable) { - std::unique_lock lock(mRunMutex); - mIsEnabled = enable; - mWaitCV.notify_all(); - } -} - -Result Sensor::flush() { - // Only generate a flush complete event if the sensor is enabled and if the sensor is not a - // one-shot sensor. - if (!mIsEnabled || (mSensorInfo.flags & static_cast(SensorFlagBits::ONE_SHOT_MODE))) { - return Result::BAD_VALUE; - } - - // Note: If a sensor supports batching, write all of the currently batched events for the sensor - // to the Event FMQ prior to writing the flush complete event. - Event ev; - ev.sensorHandle = mSensorInfo.sensorHandle; - ev.sensorType = SensorType::META_DATA; - ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE; - std::vector evs{ev}; - mCallback->postEvents(evs, isWakeUpSensor()); - - return Result::OK; -} - -void Sensor::startThread(Sensor* sensor) { - sensor->run(); -} - -void Sensor::run() { - std::unique_lock runLock(mRunMutex); - constexpr int64_t kNanosecondsInSeconds = 1000 * 1000 * 1000; - - while (!mStopThread) { - if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) { - mWaitCV.wait(runLock, [&] { - return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread); - }); - } else { - timespec curTime; - clock_gettime(CLOCK_REALTIME, &curTime); - int64_t now = (curTime.tv_sec * kNanosecondsInSeconds) + curTime.tv_nsec; - int64_t nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs; - - if (now >= nextSampleTime) { - mLastSampleTimeNs = now; - nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs; - mCallback->postEvents(readEvents(), isWakeUpSensor()); - } - - mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now)); - } - } -} - -bool Sensor::isWakeUpSensor() { - return mSensorInfo.flags & static_cast(SensorFlagBits::WAKE_UP); -} - -std::vector Sensor::readEvents() { - std::vector events; - Event event; - event.sensorHandle = mSensorInfo.sensorHandle; - event.sensorType = mSensorInfo.type; - event.timestamp = ::android::elapsedRealtimeNano(); - event.u.vec3.x = 0; - event.u.vec3.y = 0; - event.u.vec3.z = 0; - event.u.vec3.status = SensorStatus::ACCURACY_HIGH; - events.push_back(event); - return events; -} - -void Sensor::setOperationMode(OperationMode mode) { - if (mMode != mode) { - std::unique_lock lock(mRunMutex); - mMode = mode; - mWaitCV.notify_all(); - } -} - -bool Sensor::supportsDataInjection() const { - return mSensorInfo.flags & static_cast(SensorFlagBits::DATA_INJECTION); -} - -Result Sensor::injectEvent(const Event& event) { - Result result = Result::OK; - if (event.sensorType == SensorType::ADDITIONAL_INFO) { - // When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation - // environment data into the device. - } else if (!supportsDataInjection()) { - result = Result::INVALID_OPERATION; - } else if (mMode == OperationMode::DATA_INJECTION) { - mCallback->postEvents(std::vector{event}, isWakeUpSensor()); - } else { - result = Result::BAD_VALUE; - } - return result; -} - -OnChangeSensor::OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : Sensor(sensorHandle, callback), mPreviousEventSet(false) { - mSensorInfo.flags |= SensorFlagBits::ON_CHANGE_MODE; -} - -void OnChangeSensor::activate(bool enable) { - Sensor::activate(enable); - if (!enable) { - mPreviousEventSet = false; - } -} - -std::vector OnChangeSensor::readEvents() { - std::vector events = Sensor::readEvents(); - std::vector outputEvents; - - for (auto iter = events.begin(); iter != events.end(); ++iter) { - Event ev = *iter; - if (ev.u.vec3 != mPreviousEvent.u.vec3 || !mPreviousEventSet) { - outputEvents.push_back(ev); - mPreviousEvent = ev; - mPreviousEventSet = true; - } - } - return outputEvents; -} - -ContinuousSensor::ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : Sensor(sensorHandle, callback) { - mSensorInfo.flags |= SensorFlagBits::CONTINUOUS_MODE; -} - -AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : ContinuousSensor(sensorHandle, callback) { - mSensorInfo.name = "Accel Sensor"; - mSensorInfo.type = SensorType::ACCELEROMETER; - mSensorInfo.typeAsString = SENSOR_STRING_TYPE_ACCELEROMETER; - mSensorInfo.maxRange = 78.4f; // +/- 8g - mSensorInfo.resolution = 1.52e-5; - mSensorInfo.power = 0.001f; // mA - mSensorInfo.minDelay = 20 * 1000; // microseconds - mSensorInfo.flags |= SensorFlagBits::DATA_INJECTION; -} - -std::vector AccelSensor::readEvents() { - std::vector events; - Event event; - event.sensorHandle = mSensorInfo.sensorHandle; - event.sensorType = mSensorInfo.type; - event.timestamp = ::android::elapsedRealtimeNano(); - event.u.vec3.x = 0; - event.u.vec3.y = 0; - event.u.vec3.z = -9.815; - event.u.vec3.status = SensorStatus::ACCURACY_HIGH; - events.push_back(event); - return events; -} - -PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : ContinuousSensor(sensorHandle, callback) { - mSensorInfo.name = "Pressure Sensor"; - mSensorInfo.type = SensorType::PRESSURE; - mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PRESSURE; - mSensorInfo.maxRange = 1100.0f; // hPa - mSensorInfo.resolution = 0.005f; // hPa - mSensorInfo.power = 0.001f; // mA - mSensorInfo.minDelay = 100 * 1000; // microseconds -} - -MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : ContinuousSensor(sensorHandle, callback) { - mSensorInfo.name = "Magnetic Field Sensor"; - mSensorInfo.type = SensorType::MAGNETIC_FIELD; - mSensorInfo.typeAsString = SENSOR_STRING_TYPE_MAGNETIC_FIELD; - mSensorInfo.maxRange = 1300.0f; - mSensorInfo.resolution = 0.01f; - mSensorInfo.power = 0.001f; // mA - mSensorInfo.minDelay = 20 * 1000; // microseconds -} - -LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : OnChangeSensor(sensorHandle, callback) { - mSensorInfo.name = "Light Sensor"; - mSensorInfo.type = SensorType::LIGHT; - mSensorInfo.typeAsString = SENSOR_STRING_TYPE_LIGHT; - mSensorInfo.maxRange = 43000.0f; - mSensorInfo.resolution = 10.0f; - mSensorInfo.power = 0.001f; // mA - mSensorInfo.minDelay = 200 * 1000; // microseconds -} - -ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : OnChangeSensor(sensorHandle, callback) { - mSensorInfo.name = "Proximity Sensor"; - mSensorInfo.type = SensorType::PROXIMITY; - mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PROXIMITY; - mSensorInfo.maxRange = 5.0f; - mSensorInfo.resolution = 1.0f; - mSensorInfo.power = 0.012f; // mA - mSensorInfo.minDelay = 200 * 1000; // microseconds - mSensorInfo.flags |= SensorFlagBits::WAKE_UP; -} - -GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : ContinuousSensor(sensorHandle, callback) { - mSensorInfo.name = "Gyro Sensor"; - mSensorInfo.type = SensorType::GYROSCOPE; - mSensorInfo.typeAsString = SENSOR_STRING_TYPE_GYROSCOPE; - mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f; - mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f); - mSensorInfo.power = 0.001f; - mSensorInfo.minDelay = 2.5f * 1000; // microseconds -} - -std::vector GyroSensor::readEvents() { - std::vector events; - Event event; - event.sensorHandle = mSensorInfo.sensorHandle; - event.sensorType = mSensorInfo.type; - event.timestamp = ::android::elapsedRealtimeNano(); - event.u.vec3.x = 0; - event.u.vec3.y = 0; - event.u.vec3.z = 0; - event.u.vec3.status = SensorStatus::ACCURACY_HIGH; - events.push_back(event); - return events; -} - -AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : OnChangeSensor(sensorHandle, callback) { - mSensorInfo.name = "Ambient Temp Sensor"; - mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE; - mSensorInfo.typeAsString = SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE; - mSensorInfo.maxRange = 80.0f; - mSensorInfo.resolution = 0.01f; - mSensorInfo.power = 0.001f; - mSensorInfo.minDelay = 40 * 1000; // microseconds -} - -DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback) - : ContinuousSensor(sensorHandle, callback) { - mSensorInfo.name = "Device Temp Sensor"; - mSensorInfo.type = SensorType::TEMPERATURE; - mSensorInfo.typeAsString = SENSOR_STRING_TYPE_TEMPERATURE; - mSensorInfo.maxRange = 80.0f; - mSensorInfo.resolution = 0.01f; - mSensorInfo.power = 0.001f; - mSensorInfo.minDelay = 40 * 1000; // microseconds -} - -RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle, - ISensorsEventCallback* callback) - : OnChangeSensor(sensorHandle, callback) { - mSensorInfo.name = "Relative Humidity Sensor"; - mSensorInfo.type = SensorType::RELATIVE_HUMIDITY; - mSensorInfo.typeAsString = SENSOR_STRING_TYPE_RELATIVE_HUMIDITY; - mSensorInfo.maxRange = 100.0f; - mSensorInfo.resolution = 0.1f; - mSensorInfo.power = 0.001f; - mSensorInfo.minDelay = 40 * 1000; // microseconds -} - -} // namespace implementation -} // namespace subhal -} // namespace V2_0 -} // namespace sensors -} // namespace hardware -} // namespace android diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.h b/sensors/2.0/multihal/tests/fake_subhal/Sensor.h deleted file mode 100644 index 60f5d3d40a..0000000000 --- a/sensors/2.0/multihal/tests/fake_subhal/Sensor.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -#include -#include -#include -#include -#include - -using ::android::hardware::sensors::V1_0::Event; -using ::android::hardware::sensors::V1_0::OperationMode; -using ::android::hardware::sensors::V1_0::Result; -using ::android::hardware::sensors::V1_0::SensorInfo; -using ::android::hardware::sensors::V1_0::SensorType; - -namespace android { -namespace hardware { -namespace sensors { -namespace V2_0 { -namespace subhal { -namespace implementation { - -class ISensorsEventCallback { - public: - virtual ~ISensorsEventCallback(){}; - virtual void postEvents(const std::vector& events, bool wakeup) = 0; -}; - -class Sensor { - public: - Sensor(int32_t sensorHandle, ISensorsEventCallback* callback); - virtual ~Sensor(); - - const SensorInfo& getSensorInfo() const; - void batch(int32_t samplingPeriodNs); - virtual void activate(bool enable); - Result flush(); - - void setOperationMode(OperationMode mode); - bool supportsDataInjection() const; - Result injectEvent(const Event& event); - - protected: - void run(); - virtual std::vector readEvents(); - static void startThread(Sensor* sensor); - - bool isWakeUpSensor(); - - bool mIsEnabled; - int64_t mSamplingPeriodNs; - int64_t mLastSampleTimeNs; - SensorInfo mSensorInfo; - - std::atomic_bool mStopThread; - std::condition_variable mWaitCV; - std::mutex mRunMutex; - std::thread mRunThread; - - ISensorsEventCallback* mCallback; - - OperationMode mMode; -}; - -class OnChangeSensor : public Sensor { - public: - OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback); - - virtual void activate(bool enable) override; - - protected: - virtual std::vector readEvents() override; - - protected: - Event mPreviousEvent; - bool mPreviousEventSet; -}; - -class ContinuousSensor : public Sensor { - public: - ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback); -}; - -class AccelSensor : public ContinuousSensor { - public: - AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback); - - protected: - std::vector readEvents() override; -}; - -class GyroSensor : public ContinuousSensor { - public: - GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback); - - protected: - std::vector readEvents() override; -}; - -class DeviceTempSensor : public ContinuousSensor { - public: - DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback); -}; - -class PressureSensor : public ContinuousSensor { - public: - PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback); -}; - -class MagnetometerSensor : public ContinuousSensor { - public: - MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback); -}; - -class AmbientTempSensor : public OnChangeSensor { - public: - AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback); -}; - -class LightSensor : public OnChangeSensor { - public: - LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback); -}; - -class ProximitySensor : public OnChangeSensor { - public: - ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback); -}; - -class RelativeHumiditySensor : public OnChangeSensor { - public: - RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback); -}; - -} // namespace implementation -} // namespace subhal -} // namespace V2_0 -} // namespace sensors -} // namespace hardware -} // namespace android diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp deleted file mode 100644 index ff5ff38541..0000000000 --- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp +++ /dev/null @@ -1,240 +0,0 @@ -/* - * 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. - */ - -#include "SensorsSubHal.h" - -#include -#include - -ISensorsSubHal* sensorsHalGetSubHal(uint32_t* version) { -#if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS - static ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal subHal; -#elif defined SUPPORT_CONTINUOUS_SENSORS - static ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal - subHal; -#elif defined SUPPORT_ON_CHANGE_SENSORS - static ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal subHal; -#else - static ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal subHal; -#endif // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS - *version = SUB_HAL_2_0_VERSION; - return &subHal; -} - -namespace android { -namespace hardware { -namespace sensors { -namespace V2_0 { -namespace subhal { -namespace implementation { - -using ::android::hardware::Void; -using ::android::hardware::sensors::V1_0::Event; -using ::android::hardware::sensors::V1_0::OperationMode; -using ::android::hardware::sensors::V1_0::RateLevel; -using ::android::hardware::sensors::V1_0::Result; -using ::android::hardware::sensors::V1_0::SharedMemInfo; -using ::android::hardware::sensors::V2_0::SensorTimeout; -using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; -using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock; - -SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {} - -// Methods from ::android::hardware::sensors::V2_0::ISensors follow. -Return SensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) { - std::vector sensors; - for (const auto& sensor : mSensors) { - sensors.push_back(sensor.second->getSensorInfo()); - } - - _hidl_cb(sensors); - return Void(); -} - -Return SensorsSubHal::setOperationMode(OperationMode mode) { - for (auto sensor : mSensors) { - sensor.second->setOperationMode(mode); - } - mCurrentOperationMode = mode; - return Result::OK; -} - -Return SensorsSubHal::activate(int32_t sensorHandle, bool enabled) { - auto sensor = mSensors.find(sensorHandle); - if (sensor != mSensors.end()) { - sensor->second->activate(enabled); - return Result::OK; - } - return Result::BAD_VALUE; -} - -Return SensorsSubHal::batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t /* maxReportLatencyNs */) { - auto sensor = mSensors.find(sensorHandle); - if (sensor != mSensors.end()) { - sensor->second->batch(samplingPeriodNs); - return Result::OK; - } - return Result::BAD_VALUE; -} - -Return SensorsSubHal::flush(int32_t sensorHandle) { - auto sensor = mSensors.find(sensorHandle); - if (sensor != mSensors.end()) { - return sensor->second->flush(); - } - return Result::BAD_VALUE; -} - -Return SensorsSubHal::injectSensorData(const Event& event) { - auto sensor = mSensors.find(event.sensorHandle); - if (sensor != mSensors.end()) { - return sensor->second->injectEvent(event); - } - - return Result::BAD_VALUE; -} - -Return SensorsSubHal::registerDirectChannel(const SharedMemInfo& /* mem */, - registerDirectChannel_cb _hidl_cb) { - _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */); - return Return(); -} - -Return SensorsSubHal::unregisterDirectChannel(int32_t /* channelHandle */) { - return Result::INVALID_OPERATION; -} - -Return SensorsSubHal::configDirectReport(int32_t /* sensorHandle */, - int32_t /* channelHandle */, RateLevel /* rate */, - configDirectReport_cb _hidl_cb) { - _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */); - return Return(); -} - -Return SensorsSubHal::debug(const hidl_handle& fd, const hidl_vec& args) { - if (fd.getNativeHandle() == nullptr || fd->numFds < 1) { - ALOGE("%s: missing fd for writing", __FUNCTION__); - return Void(); - } - - FILE* out = fdopen(dup(fd->data[0]), "w"); - - if (args.size() != 0) { - fprintf(out, - "Note: sub-HAL %s currently does not support args. Input arguments are " - "ignored.\n", - getName().c_str()); - } - - std::ostringstream stream; - stream << "Available sensors:" << std::endl; - for (auto sensor : mSensors) { - SensorInfo info = sensor.second->getSensorInfo(); - stream << "Name: " << info.name << std::endl; - stream << "Min delay: " << info.minDelay << std::endl; - stream << "Flags: " << info.flags << std::endl; - } - stream << std::endl; - - fprintf(out, "%s", stream.str().c_str()); - - fclose(out); - return Return(); -} - -Return SensorsSubHal::initialize(const sp& halProxyCallback) { - mCallback = halProxyCallback; - setOperationMode(OperationMode::NORMAL); - return Result::OK; -} - -void SensorsSubHal::postEvents(const std::vector& events, bool wakeup) { - ScopedWakelock wakelock = mCallback->createScopedWakelock(wakeup); - mCallback->postEvents(events, std::move(wakelock)); -} - -ContinuousSensorsSubHal::ContinuousSensorsSubHal() { - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); -} - -OnChangeSensorsSubHal::OnChangeSensorsSubHal() { - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); -} - -AllSensorsSubHal::AllSensorsSubHal() { - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); -} - -Return SetOperationModeFailingSensorsSubHal::setOperationMode(OperationMode /*mode*/) { - return Result::BAD_VALUE; -} - -Return AllSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) { - std::vector sensors; - for (const auto& sensor : mSensors) { - SensorInfo sensorInfo = sensor.second->getSensorInfo(); - sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL; - sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_REPORT; - sensors.push_back(sensorInfo); - } - _hidl_cb(sensors); - return Void(); -} - -Return DoesNotSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) { - std::vector sensors; - for (const auto& sensor : mSensors) { - SensorInfo sensorInfo = sensor.second->getSensorInfo(); - sensorInfo.flags &= ~static_cast(V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL); - sensorInfo.flags &= ~static_cast(V1_0::SensorFlagBits::MASK_DIRECT_REPORT); - sensors.push_back(sensorInfo); - } - _hidl_cb(sensors); - return Void(); -} - -void AddAndRemoveDynamicSensorsSubHal::addDynamicSensors( - const std::vector& sensorsAdded) { - mCallback->onDynamicSensorsConnected(sensorsAdded); -} - -void AddAndRemoveDynamicSensorsSubHal::removeDynamicSensors( - const std::vector& sensorHandlesRemoved) { - mCallback->onDynamicSensorsDisconnected(sensorHandlesRemoved); -} - -} // namespace implementation -} // namespace subhal -} // namespace V2_0 -} // namespace sensors -} // namespace hardware -} // namespace android diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h deleted file mode 100644 index c1e36472cf..0000000000 --- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include "SubHal.h" - -#include "Sensor.h" - -#include - -namespace android { -namespace hardware { -namespace sensors { -namespace V2_0 { -namespace subhal { -namespace implementation { - -using ::android::hardware::sensors::V1_0::OperationMode; -using ::android::hardware::sensors::V1_0::Result; -using ::android::hardware::sensors::V2_0::implementation::IHalProxyCallback; - -/** - * Implementation of a ISensorsSubHal that can be used to test the implementation of multihal 2.0. - * See the README file for more details on how this class can be used for testing. - */ -class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { - using Event = ::android::hardware::sensors::V1_0::Event; - using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; - using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; - - public: - SensorsSubHal(); - - // Methods from ::android::hardware::sensors::V2_0::ISensors follow. - virtual Return getSensorsList(getSensorsList_cb _hidl_cb) override; - - virtual Return setOperationMode(OperationMode mode) override; - - OperationMode getOperationMode() const { return mCurrentOperationMode; } - - Return activate(int32_t sensorHandle, bool enabled) override; - - Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) override; - - Return flush(int32_t sensorHandle) override; - - Return injectSensorData(const Event& event) override; - - Return registerDirectChannel(const SharedMemInfo& mem, - registerDirectChannel_cb _hidl_cb) override; - - Return unregisterDirectChannel(int32_t channelHandle) override; - - Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, - configDirectReport_cb _hidl_cb) override; - - Return debug(const hidl_handle& fd, const hidl_vec& args) override; - - // Methods from ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal follow. - const std::string getName() override { -#ifdef SUB_HAL_NAME - return SUB_HAL_NAME; -#else // SUB_HAL_NAME - return "FakeSubHal"; -#endif // SUB_HAL_NAME - } - - Return initialize(const sp& halProxyCallback) override; - - // Method from ISensorsEventCallback. - void postEvents(const std::vector& events, bool wakeup) override; - - protected: - template - void AddSensor() { - std::shared_ptr sensor = - std::make_shared(mNextHandle++ /* sensorHandle */, this /* callback */); - mSensors[sensor->getSensorInfo().sensorHandle] = sensor; - } - - /** - * A map of the available sensors - */ - std::map> mSensors; - - /** - * Callback used to communicate to the HalProxy when dynamic sensors are connected / - * disconnected, sensor events need to be sent to the framework, and when a wakelock should be - * acquired. - */ - sp mCallback; - - private: - /** - * The current operation mode of the multihal framework. Ensures that all subhals are set to - * the same operation mode. - */ - OperationMode mCurrentOperationMode = OperationMode::NORMAL; - - /** - * The next available sensor handle - */ - int32_t mNextHandle; -}; - -// SubHal that has continuous sensors for testing purposes. -class ContinuousSensorsSubHal : public SensorsSubHal { - public: - ContinuousSensorsSubHal(); -}; - -// SubHal that has on-change sensors for testing purposes. -class OnChangeSensorsSubHal : public SensorsSubHal { - public: - OnChangeSensorsSubHal(); -}; - -// SubHal that has both continuous and on-change sensors for testing purposes. -class AllSensorsSubHal : public SensorsSubHal { - public: - AllSensorsSubHal(); -}; - -class SetOperationModeFailingSensorsSubHal : public AllSensorsSubHal { - public: - Return setOperationMode(OperationMode mode) override; -}; - -class AllSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { - public: - Return getSensorsList(getSensorsList_cb _hidl_cb) override; -}; - -class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { - public: - Return getSensorsList(getSensorsList_cb _hidl_cb) override; -}; - -class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal { - public: - void addDynamicSensors(const std::vector& sensorsAdded); - void removeDynamicSensors(const std::vector& sensorHandlesAdded); -}; - -} // namespace implementation -} // namespace subhal -} // namespace V2_0 -} // namespace sensors -} // namespace hardware -} // namespace android From 07ccc7a17e5b2dc74e424c5dec32dc7b78651f7d Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Wed, 24 Jul 2019 14:40:25 -0700 Subject: [PATCH 0216/1022] Camera: Add bokeh mode tags in camera metadata Introduce new bokeh mode metadata tags for camera device to enable bokeh effect. Test: Build and read docs Bug: 118258123 Change-Id: I99b85fe60ee8af008592922ae2cce64be33e88a2 --- camera/metadata/3.5/types.hal | 33 ++++++ .../VtsHalCameraProviderV2_4TargetTest.cpp | 100 +++++++++++++++++- 2 files changed, 131 insertions(+), 2 deletions(-) diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal index 0fec947b97..b9451c852b 100644 --- a/camera/metadata/3.5/types.hal +++ b/camera/metadata/3.5/types.hal @@ -28,10 +28,43 @@ import android.hardware.camera.metadata@3.4; // No new metadata sections added in this revision +/** + * Main enumeration for defining camera metadata tags added in this revision + * + *

    Partial documentation is included for each tag; for complete documentation, reference + * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.

    + */ +enum CameraMetadataTag : @3.4::CameraMetadataTag { + /** android.control.availableBokehCapabilities [static, int32[], public] + * + *

    The list of bokeh modes that are supported by this camera device, and each bokeh mode's + * maximum streaming (non-stall) size with bokeh effect.

    + */ + ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3, + + /** android.control.bokehMode [dynamic, enum, public] + * + *

    Whether bokeh mode is enabled for a particular capture request.

    + */ + ANDROID_CONTROL_BOKEH_MODE, + + ANDROID_CONTROL_END_3_5, + +}; + /* * Enumeration definitions for the various entries that need them */ +/** android.control.bokehMode enumeration values + * @see ANDROID_CONTROL_BOKEH_MODE + */ +enum CameraMetadataEnumAndroidControlBokehMode : uint32_t { + ANDROID_CONTROL_BOKEH_MODE_OFF, + ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE, + ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS, +}; + /** android.request.availableCapabilities enumeration values added since v3.4 * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES */ diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 67d5bbe929..1b0d7cb94f 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -778,6 +778,7 @@ public: const CameraMetadata& chars, int deviceVersion, const hidl_vec& deviceNames); void verifyCameraCharacteristics(Status status, const CameraMetadata& chars); + void verifyBokehCharacteristics(const camera_metadata_t* metadata); void verifyRecommendedConfigs(const CameraMetadata& metadata); void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion); void verifyMonochromeCameraResult( @@ -801,7 +802,7 @@ public: bool isDepthOnly(camera_metadata_t* staticMeta); - static Status getAvailableOutputStreams(camera_metadata_t *staticMeta, + static Status getAvailableOutputStreams(const camera_metadata_t *staticMeta, std::vector &outputStreams, const AvailableStream *threshold = nullptr); static Status getJpegBufferSize(camera_metadata_t *staticMeta, @@ -4856,7 +4857,7 @@ TEST_F(CameraHidlTest, providerDeviceStateNotification) { // Retrieve all valid output stream resolutions from the camera // static characteristics. -Status CameraHidlTest::getAvailableOutputStreams(camera_metadata_t *staticMeta, +Status CameraHidlTest::getAvailableOutputStreams(const camera_metadata_t *staticMeta, std::vector &outputStreams, const AvailableStream *threshold) { AvailableStream depthPreviewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, @@ -5839,6 +5840,101 @@ void CameraHidlTest::verifyCameraCharacteristics(Status status, const CameraMeta ADD_FAILURE() << "Get Heic maxJpegAppSegmentsCount failed!"; } } + + verifyBokehCharacteristics(metadata); +} + +void CameraHidlTest::verifyBokehCharacteristics(const camera_metadata_t* metadata) { + camera_metadata_ro_entry entry; + int retcode = 0; + + // Check key availability in capabilities, request and result. + + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry); + bool hasBokehRequestKey = false; + if ((0 == retcode) && (entry.count > 0)) { + hasBokehRequestKey = std::find(entry.data.i32, entry.data.i32+entry.count, + ANDROID_CONTROL_BOKEH_MODE) != entry.data.i32+entry.count; + } else { + ADD_FAILURE() << "Get camera availableRequestKeys failed!"; + } + + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry); + bool hasBokehResultKey = false; + if ((0 == retcode) && (entry.count > 0)) { + hasBokehResultKey = std::find(entry.data.i32, entry.data.i32+entry.count, + ANDROID_CONTROL_BOKEH_MODE) != entry.data.i32+entry.count; + } else { + ADD_FAILURE() << "Get camera availableResultKeys failed!"; + } + + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry); + bool hasBokehCharacteristicsKey = false; + if ((0 == retcode) && (entry.count > 0)) { + hasBokehCharacteristicsKey = std::find(entry.data.i32, entry.data.i32+entry.count, + ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES) != entry.data.i32+entry.count; + } else { + ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!"; + } + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES, &entry); + bool hasAvailableBokehCaps = (0 == retcode && entry.count > 0); + + // Bokeh keys must all be available, or all be unavailable. + bool noBokeh = !hasBokehRequestKey && !hasBokehResultKey && !hasBokehCharacteristicsKey && + !hasAvailableBokehCaps; + if (noBokeh) { + return; + } + bool hasBokeh = hasBokehRequestKey && hasBokehResultKey && hasBokehCharacteristicsKey && + hasAvailableBokehCaps; + ASSERT_TRUE(hasBokeh); + + // Must have OFF, and must have one of STILL_CAPTURE and CONTINUOUS. + ASSERT_TRUE(entry.count == 6 || entry.count == 9); + bool hasOffMode = false; + bool hasStillCaptureMode = false; + bool hasContinuousMode = false; + std::vector outputStreams; + ASSERT_EQ(Status::OK, getAvailableOutputStreams(metadata, outputStreams)); + for (int i = 0; i < entry.count; i += 3) { + int32_t mode = entry.data.i32[i]; + int32_t maxWidth = entry.data.i32[i+1]; + int32_t maxHeight = entry.data.i32[i+2]; + switch (mode) { + case ANDROID_CONTROL_BOKEH_MODE_OFF: + hasOffMode = true; + ASSERT_TRUE(maxWidth == 0 && maxHeight == 0); + break; + case ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE: + hasStillCaptureMode = true; + break; + case ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS: + hasContinuousMode = true; + break; + default: + ADD_FAILURE() << "Invalid bokehMode advertised: " << mode; + break; + } + + if (mode != ANDROID_CONTROL_BOKEH_MODE_OFF) { + bool sizeSupported = false; + for (const auto& stream : outputStreams) { + if ((stream.format == static_cast(PixelFormat::YCBCR_420_888) || + stream.format == static_cast(PixelFormat::IMPLEMENTATION_DEFINED)) + && stream.width == maxWidth && stream.height == maxHeight) { + sizeSupported = true; + break; + } + } + ASSERT_TRUE(sizeSupported); + } + } + ASSERT_TRUE(hasOffMode); + ASSERT_TRUE(hasStillCaptureMode || hasContinuousMode); } void CameraHidlTest::verifyMonochromeCharacteristics(const CameraMetadata& chars, From ff7462064d9a5d089a6297b6629028912f5be633 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Tue, 22 Oct 2019 10:47:58 -0700 Subject: [PATCH 0217/1022] Convert VtsHalGraphicsComposerV2_*TargetTest to be parameterized test Bug: 142397658 Test: atest VtsHalGraphicsComposerV2_1TargetTest Change-Id: Idd6b0a0314be706e06f7812fbf8eb787edd078b1 --- .../include/composer-vts/2.1/ComposerVts.h | 4 +- .../composer/2.1/vts/functional/Android.bp | 3 +- .../VtsHalGraphicsComposerV2_1TargetTest.cpp | 157 ++++++++---------- 3 files changed, 72 insertions(+), 92 deletions(-) diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h index 429465779b..63aa713e54 100644 --- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h +++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h @@ -57,6 +57,7 @@ class Composer { public: Composer(); explicit Composer(const std::string& name); + explicit Composer(const sp& composer); sp getRaw() const; @@ -67,9 +68,6 @@ class Composer { std::string dumpDebugInfo(); std::unique_ptr createClient(); - protected: - explicit Composer(const sp& composer); - private: const sp mComposer; diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp index 799ca919b9..5f1ed63936 100644 --- a/graphics/composer/2.1/vts/functional/Android.bp +++ b/graphics/composer/2.1/vts/functional/Android.bp @@ -42,5 +42,6 @@ cc_test { header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", ], - test_suites: ["general-tests"], + disable_framework: true, + test_suites: ["general-tests", "vts-core"], } diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp index 9477ee665b..b92279d45f 100644 --- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp +++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp @@ -20,13 +20,14 @@ #include #include #include +#include #include +#include +#include #include #include #include -#include -#include #include #include @@ -52,30 +53,11 @@ using android::hardware::graphics::common::V1_0::PixelFormat; using android::hardware::graphics::common::V1_0::Transform; using GrallocError = android::hardware::graphics::mapper::V2_0::Error; -// Test environment for graphics.composer -class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static GraphicsComposerHidlEnvironment* Instance() { - static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { registerTestService(); } - - private: - GraphicsComposerHidlEnvironment() {} - - GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment); -}; - -class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { - protected: +class GraphicsComposerHidlTest : public ::testing::TestWithParam { + protected: void SetUp() override { - VtsHalHidlTargetTestBase::SetUp(); ASSERT_NO_FATAL_FAILURE( - mComposer = std::make_unique( - GraphicsComposerHidlEnvironment::Instance()->getServiceName())); + mComposer = std::make_unique(IComposer::getService(GetParam()))); ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); mComposerCallback = new GraphicsComposerCallback; @@ -102,7 +84,6 @@ class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount()); EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount()); } - VtsHalHidlTargetTestBase::TearDown(); } // returns an invalid display id (one that has not been registered to a @@ -151,7 +132,7 @@ class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { * * Test that IComposer::getCapabilities returns no invalid capabilities. */ -TEST_F(GraphicsComposerHidlTest, GetCapabilities) { +TEST_P(GraphicsComposerHidlTest, GetCapabilities) { auto capabilities = mComposer->getCapabilities(); ASSERT_EQ(capabilities.end(), std::find(capabilities.begin(), capabilities.end(), IComposer::Capability::INVALID)); @@ -160,7 +141,7 @@ TEST_F(GraphicsComposerHidlTest, GetCapabilities) { /** * Test IComposer::dumpDebugInfo. */ -TEST_F(GraphicsComposerHidlTest, DumpDebugInfo) { +TEST_P(GraphicsComposerHidlTest, DumpDebugInfo) { mComposer->dumpDebugInfo(); } @@ -169,7 +150,7 @@ TEST_F(GraphicsComposerHidlTest, DumpDebugInfo) { * * Test that IComposerClient is a singleton. */ -TEST_F(GraphicsComposerHidlTest, CreateClientSingleton) { +TEST_P(GraphicsComposerHidlTest, CreateClientSingleton) { mComposer->getRaw()->createClient( [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::NO_RESOURCES, tmpError); }); } @@ -180,7 +161,7 @@ TEST_F(GraphicsComposerHidlTest, CreateClientSingleton) { * * Test that virtual displays can be created and has the correct display type. */ -TEST_F(GraphicsComposerHidlTest, CreateVirtualDisplay) { +TEST_P(GraphicsComposerHidlTest, CreateVirtualDisplay) { if (mComposerClient->getMaxVirtualDisplayCount() == 0) { GTEST_SUCCEED() << "no virtual display support"; return; @@ -205,7 +186,7 @@ TEST_F(GraphicsComposerHidlTest, CreateVirtualDisplay) { * Test that passing a bad display handle to destroyVirtualDisplay * returns a BAD_DISPLAY error */ -TEST_F(GraphicsComposerHidlTest, DestroyVirtualDisplayBadDisplay) { +TEST_P(GraphicsComposerHidlTest, DestroyVirtualDisplayBadDisplay) { if (mComposerClient->getMaxVirtualDisplayCount() == 0) { GTEST_SUCCEED() << "no virtual display support"; return; @@ -220,7 +201,7 @@ TEST_F(GraphicsComposerHidlTest, DestroyVirtualDisplayBadDisplay) { * * Test that layers can be created and destroyed. */ -TEST_F(GraphicsComposerHidlTest, CreateLayer) { +TEST_P(GraphicsComposerHidlTest, CreateLayer) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -234,7 +215,7 @@ TEST_F(GraphicsComposerHidlTest, CreateLayer) { * Test that passing in an invalid display handle to createLayer returns * BAD_DISPLAY. */ -TEST_F(GraphicsComposerHidlTest, CreateLayerBadDisplay) { +TEST_P(GraphicsComposerHidlTest, CreateLayerBadDisplay) { Error error; mComposerClient->getRaw()->createLayer( mInvalidDisplayId, kBufferSlotCount, @@ -248,7 +229,7 @@ TEST_F(GraphicsComposerHidlTest, CreateLayerBadDisplay) { * Test that passing in an invalid display handle to destroyLayer returns * BAD_DISPLAY */ -TEST_F(GraphicsComposerHidlTest, DestroyLayerBadDisplay) { +TEST_P(GraphicsComposerHidlTest, DestroyLayerBadDisplay) { Error error; Layer layer; ASSERT_NO_FATAL_FAILURE(layer = @@ -267,7 +248,7 @@ TEST_F(GraphicsComposerHidlTest, DestroyLayerBadDisplay) { * Test that passing in an invalid layer handle to destroyLayer returns * BAD_LAYER */ -TEST_F(GraphicsComposerHidlTest, DestroyLayerBadLayerError) { +TEST_P(GraphicsComposerHidlTest, DestroyLayerBadLayerError) { // We haven't created any layers yet, so any id should be invalid Error error = mComposerClient->getRaw()->destroyLayer(mPrimaryDisplay, 1); @@ -280,7 +261,7 @@ TEST_F(GraphicsComposerHidlTest, DestroyLayerBadLayerError) { * Test that passing in a bad display handle to getActiveConfig generates a * BAD_DISPLAY error */ -TEST_F(GraphicsComposerHidlTest, GetActiveConfigBadDisplay) { +TEST_P(GraphicsComposerHidlTest, GetActiveConfigBadDisplay) { Error error; mComposerClient->getRaw()->getActiveConfig( mInvalidDisplayId, [&](const auto& tmpOutError, const auto&) { error = tmpOutError; }); @@ -293,7 +274,7 @@ TEST_F(GraphicsComposerHidlTest, GetActiveConfigBadDisplay) { * Test IComposerClient::getDisplayConfigs returns no error * when passed in a valid display */ -TEST_F(GraphicsComposerHidlTest, GetDisplayConfig) { +TEST_P(GraphicsComposerHidlTest, GetDisplayConfig) { std::vector configs; ASSERT_NO_FATAL_FAILURE(configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay)); } @@ -304,7 +285,7 @@ TEST_F(GraphicsComposerHidlTest, GetDisplayConfig) { * Test IComposerClient::getDisplayConfigs returns BAD_DISPLAY * when passed in an invalid display handle */ -TEST_F(GraphicsComposerHidlTest, GetDisplayConfigBadDisplay) { +TEST_P(GraphicsComposerHidlTest, GetDisplayConfigBadDisplay) { Error error; mComposerClient->getRaw()->getDisplayConfigs( mInvalidDisplayId, [&](const auto& tmpOutError, const auto&) { error = tmpOutError; }); @@ -314,7 +295,7 @@ TEST_F(GraphicsComposerHidlTest, GetDisplayConfigBadDisplay) { /** * Test IComposerClient::getDisplayName. */ -TEST_F(GraphicsComposerHidlTest, GetDisplayName) { +TEST_P(GraphicsComposerHidlTest, GetDisplayName) { mComposerClient->getDisplayName(mPrimaryDisplay); } @@ -324,7 +305,7 @@ TEST_F(GraphicsComposerHidlTest, GetDisplayName) { * Test that IComposerClient::getDisplayType returns the correct display type * for the primary display. */ -TEST_F(GraphicsComposerHidlTest, GetDisplayType) { +TEST_P(GraphicsComposerHidlTest, GetDisplayType) { ASSERT_EQ(IComposerClient::DisplayType::PHYSICAL, mComposerClient->getDisplayType(mPrimaryDisplay)); } @@ -335,7 +316,7 @@ TEST_F(GraphicsComposerHidlTest, GetDisplayType) { * Test that IComposerClient::getClientTargetSupport returns true for the * required client targets. */ -TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport) { +TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport) { std::vector configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay); for (auto config : configs) { int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, @@ -358,7 +339,7 @@ TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport) { * Test that IComposerClient::getClientTargetSupport returns BAD_DISPLAY when * passed an invalid display handle */ -TEST_F(GraphicsComposerHidlTest, GetClientTargetSupportBadDisplay) { +TEST_P(GraphicsComposerHidlTest, GetClientTargetSupportBadDisplay) { std::vector configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay); for (auto config : configs) { int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, @@ -382,7 +363,7 @@ TEST_F(GraphicsComposerHidlTest, GetClientTargetSupportBadDisplay) { * Test that IComposerClient::getDisplayAttribute succeeds for the required * formats, and succeeds or fails correctly for optional attributes. */ -TEST_F(GraphicsComposerHidlTest, GetDisplayAttribute) { +TEST_P(GraphicsComposerHidlTest, GetDisplayAttribute) { std::vector configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay); for (auto config : configs) { const std::array requiredAttributes = {{ @@ -408,7 +389,7 @@ TEST_F(GraphicsComposerHidlTest, GetDisplayAttribute) { /** * Test IComposerClient::getHdrCapabilities. */ -TEST_F(GraphicsComposerHidlTest, GetHdrCapabilities) { +TEST_P(GraphicsComposerHidlTest, GetHdrCapabilities) { float maxLuminance; float maxAverageLuminance; float minLuminance; @@ -419,7 +400,7 @@ TEST_F(GraphicsComposerHidlTest, GetHdrCapabilities) { /** * Test IComposerClient::setClientTargetSlotCount. */ -TEST_F(GraphicsComposerHidlTest, SetClientTargetSlotCount) { +TEST_P(GraphicsComposerHidlTest, SetClientTargetSlotCount) { mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount); } @@ -429,7 +410,7 @@ TEST_F(GraphicsComposerHidlTest, SetClientTargetSlotCount) { * Test that IComposerClient::setActiveConfig succeeds for all display * configs. */ -TEST_F(GraphicsComposerHidlTest, SetActiveConfig) { +TEST_P(GraphicsComposerHidlTest, SetActiveConfig) { std::vector configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay); for (auto config : configs) { mComposerClient->setActiveConfig(mPrimaryDisplay, config); @@ -443,7 +424,7 @@ TEST_F(GraphicsComposerHidlTest, SetActiveConfig) { * Test that config set during IComposerClient::setActiveConfig is maintained * during a display on/off power cycle */ -TEST_F(GraphicsComposerHidlTest, SetActiveConfigPowerCycle) { +TEST_P(GraphicsComposerHidlTest, SetActiveConfigPowerCycle) { ASSERT_NO_FATAL_FAILURE( mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::OFF)); ASSERT_NO_FATAL_FAILURE( @@ -467,7 +448,7 @@ TEST_F(GraphicsComposerHidlTest, SetActiveConfigPowerCycle) { * * Test that IComposerClient::getColorMode always returns ColorMode::NATIVE */ -TEST_F(GraphicsComposerHidlTest, GetColorModes) { +TEST_P(GraphicsComposerHidlTest, GetColorModes) { std::vector modes = mComposerClient->getColorModes(mPrimaryDisplay); auto nativeModeLocation = std::find(modes.begin(), modes.end(), ColorMode::NATIVE); @@ -479,7 +460,7 @@ TEST_F(GraphicsComposerHidlTest, GetColorModes) { * * Test that IComposerClient::setColorMode succeeds for all color modes. */ -TEST_F(GraphicsComposerHidlTest, SetColorMode) { +TEST_P(GraphicsComposerHidlTest, SetColorMode) { std::unordered_set validModes; for (auto mode : hidl_enum_range()) { validModes.insert(mode); @@ -499,7 +480,7 @@ TEST_F(GraphicsComposerHidlTest, SetColorMode) { * Test that IComposerClient::setColorMode returns BAD_DISPLAY for * an invalid display handle */ -TEST_F(GraphicsComposerHidlTest, SetColorModeBadDisplay) { +TEST_P(GraphicsComposerHidlTest, SetColorModeBadDisplay) { std::vector modes = mComposerClient->getColorModes(mPrimaryDisplay); for (auto mode : modes) { Error error = mComposerClient->getRaw()->setColorMode(mInvalidDisplayId, mode); @@ -513,7 +494,7 @@ TEST_F(GraphicsComposerHidlTest, SetColorModeBadDisplay) { * Test that IComposerClient::setColorMode returns BAD_PARAMETER when passed in * an invalid color mode */ -TEST_F(GraphicsComposerHidlTest, SetColorModeBadParameter) { +TEST_P(GraphicsComposerHidlTest, SetColorModeBadParameter) { Error error = mComposerClient->getRaw()->setColorMode(mPrimaryDisplay, static_cast(-1)); ASSERT_EQ(Error::BAD_PARAMETER, error); @@ -525,7 +506,7 @@ TEST_F(GraphicsComposerHidlTest, SetColorModeBadParameter) { * Test that IComposerClient::getDozeSupport returns * BAD_DISPLAY when passed an invalid display handle */ -TEST_F(GraphicsComposerHidlTest, GetDozeSupportBadDisplay) { +TEST_P(GraphicsComposerHidlTest, GetDozeSupportBadDisplay) { Error error; mComposerClient->getRaw()->getDozeSupport( mInvalidDisplayId, [&](const auto& tmpOutError, const auto&) { error = tmpOutError; }); @@ -537,7 +518,7 @@ TEST_F(GraphicsComposerHidlTest, GetDozeSupportBadDisplay) { * * Test that IComposerClient::setPowerMode succeeds for all power modes. */ -TEST_F(GraphicsComposerHidlTest, SetPowerMode) { +TEST_P(GraphicsComposerHidlTest, SetPowerMode) { std::vector modes; modes.push_back(IComposerClient::PowerMode::OFF); @@ -560,7 +541,7 @@ TEST_F(GraphicsComposerHidlTest, SetPowerMode) { * Test IComposerClient::setPowerMode succeeds with different * orderings of power modes */ -TEST_F(GraphicsComposerHidlTest, SetPowerModeVariations) { +TEST_P(GraphicsComposerHidlTest, SetPowerModeVariations) { std::vector modes; modes.push_back(IComposerClient::PowerMode::OFF); modes.push_back(IComposerClient::PowerMode::ON); @@ -611,7 +592,7 @@ TEST_F(GraphicsComposerHidlTest, SetPowerModeVariations) { * Test IComposerClient::setPowerMode returns BAD_DISPLAY when passed an invalid * display handle */ -TEST_F(GraphicsComposerHidlTest, SetPowerModeBadDisplay) { +TEST_P(GraphicsComposerHidlTest, SetPowerModeBadDisplay) { Error error = mComposerClient->getRaw()->setPowerMode(mInvalidDisplayId, IComposerClient::PowerMode::ON); ASSERT_EQ(Error::BAD_DISPLAY, error); @@ -623,7 +604,7 @@ TEST_F(GraphicsComposerHidlTest, SetPowerModeBadDisplay) { * Test that IComposerClient::setPowerMode returns UNSUPPORTED when passed DOZE * or DOZE_SUSPEND on devices that do not support DOZE/DOZE_SUSPEND */ -TEST_F(GraphicsComposerHidlTest, SetPowerModeUnsupported) { +TEST_P(GraphicsComposerHidlTest, SetPowerModeUnsupported) { if (!mComposerClient->getDozeSupport(mPrimaryDisplay)) { Error error = mComposerClient->getRaw()->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::DOZE); @@ -641,7 +622,7 @@ TEST_F(GraphicsComposerHidlTest, SetPowerModeUnsupported) { * Tests that IComposerClient::setPowerMode returns BAD_PARAMETER when passed an invalid * PowerMode */ -TEST_F(GraphicsComposerHidlTest, SetPowerModeBadParameter) { +TEST_P(GraphicsComposerHidlTest, SetPowerModeBadParameter) { Error error = mComposerClient->getRaw()->setPowerMode( mPrimaryDisplay, static_cast(-1)); ASSERT_EQ(Error::BAD_PARAMETER, error); @@ -653,7 +634,7 @@ TEST_F(GraphicsComposerHidlTest, SetPowerModeBadParameter) { * Test that IComposerClient::setVsyncEnabled succeeds and there is no * spurious vsync events. */ -TEST_F(GraphicsComposerHidlTest, SetVsyncEnabled) { +TEST_P(GraphicsComposerHidlTest, SetVsyncEnabled) { mComposerCallback->setVsyncAllowed(true); mComposerClient->setVsyncEnabled(mPrimaryDisplay, true); @@ -705,7 +686,7 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { /** * Test IComposerClient::Command::SET_COLOR_TRANSFORM. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_COLOR_TRANSFORM) { +TEST_P(GraphicsComposerHidlCommandTest, SET_COLOR_TRANSFORM) { const std::array identity = {{ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, @@ -720,7 +701,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_COLOR_TRANSFORM) { /** * Test IComposerClient::Command::SET_CLIENT_TARGET. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_CLIENT_TARGET) { +TEST_P(GraphicsComposerHidlCommandTest, SET_CLIENT_TARGET) { mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount); mWriter->selectDisplay(mPrimaryDisplay); @@ -733,7 +714,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_CLIENT_TARGET) { /** * Test IComposerClient::Command::SET_OUTPUT_BUFFER. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_OUTPUT_BUFFER) { +TEST_P(GraphicsComposerHidlCommandTest, SET_OUTPUT_BUFFER) { if (mComposerClient->getMaxVirtualDisplayCount() == 0) { GTEST_SUCCEED() << "no virtual display support"; return; @@ -756,7 +737,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_OUTPUT_BUFFER) { /** * Test IComposerClient::Command::VALIDATE_DISPLAY. */ -TEST_F(GraphicsComposerHidlCommandTest, VALIDATE_DISPLAY) { +TEST_P(GraphicsComposerHidlCommandTest, VALIDATE_DISPLAY) { mWriter->selectDisplay(mPrimaryDisplay); mWriter->validateDisplay(); execute(); @@ -765,7 +746,7 @@ TEST_F(GraphicsComposerHidlCommandTest, VALIDATE_DISPLAY) { /** * Test IComposerClient::Command::ACCEPT_DISPLAY_CHANGES. */ -TEST_F(GraphicsComposerHidlCommandTest, ACCEPT_DISPLAY_CHANGES) { +TEST_P(GraphicsComposerHidlCommandTest, ACCEPT_DISPLAY_CHANGES) { mWriter->selectDisplay(mPrimaryDisplay); mWriter->validateDisplay(); mWriter->acceptDisplayChanges(); @@ -775,7 +756,7 @@ TEST_F(GraphicsComposerHidlCommandTest, ACCEPT_DISPLAY_CHANGES) { /** * Test IComposerClient::Command::PRESENT_DISPLAY. */ -TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY) { +TEST_P(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY) { mWriter->selectDisplay(mPrimaryDisplay); mWriter->validateDisplay(); mWriter->presentDisplay(); @@ -789,7 +770,7 @@ TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY) { * additional call to validateDisplay when only the layer buffer handle and * surface damage have been set */ -TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) { +TEST_P(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) { if (!mComposer->hasCapability( static_cast(HWC2_CAPABILITY_SKIP_VALIDATE))) { std::cout << "Device does not have skip validate capability, skipping" << std::endl; @@ -845,7 +826,7 @@ TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) /** * Test IComposerClient::Command::SET_LAYER_CURSOR_POSITION. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_CURSOR_POSITION) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_CURSOR_POSITION) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -887,7 +868,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_CURSOR_POSITION) { /** * Test IComposerClient::Command::SET_LAYER_BUFFER. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_BUFFER) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_BUFFER) { auto handle = allocate(); ASSERT_NE(nullptr, handle); @@ -904,7 +885,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_BUFFER) { /** * Test IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SURFACE_DAMAGE) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_SURFACE_DAMAGE) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -923,7 +904,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SURFACE_DAMAGE) { /** * Test IComposerClient::Command::SET_LAYER_BLEND_MODE. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_BLEND_MODE) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_BLEND_MODE) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -939,7 +920,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_BLEND_MODE) { /** * Test IComposerClient::Command::SET_LAYER_COLOR. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_COLOR) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_COLOR) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -954,7 +935,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_COLOR) { /** * Test IComposerClient::Command::SET_LAYER_COMPOSITION_TYPE. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_COMPOSITION_TYPE) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_COMPOSITION_TYPE) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -971,7 +952,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_COMPOSITION_TYPE) { /** * Test IComposerClient::Command::SET_LAYER_DATASPACE. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_DATASPACE) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_DATASPACE) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -985,7 +966,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_DATASPACE) { /** * Test IComposerClient::Command::SET_LAYER_DISPLAY_FRAME. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_DISPLAY_FRAME) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_DISPLAY_FRAME) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -999,7 +980,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_DISPLAY_FRAME) { /** * Test IComposerClient::Command::SET_LAYER_PLANE_ALPHA. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PLANE_ALPHA) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_PLANE_ALPHA) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -1014,7 +995,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PLANE_ALPHA) { /** * Test IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SIDEBAND_STREAM) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_SIDEBAND_STREAM) { if (!mComposer->hasCapability(IComposer::Capability::SIDEBAND_STREAM)) { GTEST_SUCCEED() << "no sideband stream support"; return; @@ -1036,7 +1017,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SIDEBAND_STREAM) { /** * Test IComposerClient::Command::SET_LAYER_SOURCE_CROP. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SOURCE_CROP) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_SOURCE_CROP) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -1050,7 +1031,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SOURCE_CROP) { /** * Test IComposerClient::Command::SET_LAYER_TRANSFORM. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_TRANSFORM) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_TRANSFORM) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -1071,7 +1052,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_TRANSFORM) { /** * Test IComposerClient::Command::SET_LAYER_VISIBLE_REGION. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_VISIBLE_REGION) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_VISIBLE_REGION) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -1090,7 +1071,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_VISIBLE_REGION) { /** * Test IComposerClient::Command::SET_LAYER_Z_ORDER. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_Z_ORDER) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_Z_ORDER) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -1102,6 +1083,16 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_Z_ORDER) { execute(); } +INSTANTIATE_TEST_SUITE_P( + PerInstance, GraphicsComposerHidlCommandTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), + android::hardware::PrintInstanceNameToString); + +INSTANTIATE_TEST_SUITE_P( + PerInstance, GraphicsComposerHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), + android::hardware::PrintInstanceNameToString); + } // namespace } // namespace vts } // namespace V2_1 @@ -1109,13 +1100,3 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_Z_ORDER) { } // namespace graphics } // namespace hardware } // namespace android - -int main(int argc, char** argv) { - using android::hardware::graphics::composer::V2_1::vts::GraphicsComposerHidlEnvironment; - ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); - return status; -} From 0479020425a1211bcbac32de909d88a377a9f164 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 25 Oct 2019 13:04:19 -0700 Subject: [PATCH 0218/1022] audio: Run VTS tests for non-primary modules for HAL V6 Implement parsing of AudioPolicyManager config for finding out declared modules (IDevice instances) with permanently attached devices and run tests for them. This only applies when running tests for HAL V6. Change class hierarchy to use IDevice interface as much as possible, only use IPrimaryDevice for its specific methods. Fix the following issues found while running the tests for "r_submix" and "msd" modules: - IDevice::getMicrophones can return NOT_SUPPORTED status; - IDevice::get/setParameters can return NOT_SUPPORTED. Other changes: - Factor out common code for getting devices via DeviceManager; - Factor out AudioPolicyConfigTest.HasPrimaryModule test from SetUp code; - Add device parameter generator for primary device only. Bug: 141989952 Bug: 141847510 Test: atest VtsHalAudioV5_0TargetTest atest VtsHalAudioV6_0TargetTest also, run modified V5_0 test using generators for V6_0 Change-Id: I51cec21670120d8dce75609954a18b886cc0c18d --- audio/6.0/IDevice.hal | 3 +- .../4.0/AudioPrimaryHidlHalTest.cpp | 16 +- .../6.0/AudioPrimaryHidlHalTest.cpp | 48 +++ .../vts/functional/AudioPrimaryHidlHalTest.h | 341 ++++++++++-------- 4 files changed, 254 insertions(+), 154 deletions(-) diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal index 42a545b0be..e885fe2267 100644 --- a/audio/6.0/IDevice.hal +++ b/audio/6.0/IDevice.hal @@ -260,7 +260,8 @@ interface IDevice { /** * Returns an array with available microphones in device. * - * @return retval INVALID_STATE if the call is not successful, + * @return retval NOT_SUPPORTED if there are no microphones on this device + * INVALID_STATE if the call is not successful, * OK otherwise. * * @return microphones array with microphones info diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp index b8defb620a..cd93643b95 100644 --- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp @@ -18,15 +18,16 @@ TEST_P(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) { doc::test("Calling openDevice(\"primary\") should return the primary device."); + if (getDeviceName() != DeviceManager::kPrimaryDevice) { + GTEST_SKIP() << "No primary device on this factory"; // returns + } + struct WaitExecutor { ~WaitExecutor() { DeviceManager::waitForInstanceDestruction(); } } waitExecutor; // Make sure we wait for the device destruction on exiting from the test. Result result; sp baseDevice; ASSERT_OK(getDevicesFactory()->openDevice("primary", returnIn(result, baseDevice))); - if (result != Result::OK && isPrimaryDeviceOptional()) { - GTEST_SKIP() << "No primary device on this factory"; // returns - } ASSERT_OK(result); ASSERT_TRUE(baseDevice != nullptr); @@ -39,10 +40,13 @@ TEST_P(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) { /////////////////////////// get(Active)Microphones /////////////////////////// ////////////////////////////////////////////////////////////////////////////// -TEST_P(AudioPrimaryHidlTest, GetMicrophonesTest) { +TEST_P(AudioHidlDeviceTest, GetMicrophonesTest) { doc::test("Make sure getMicrophones always succeeds"); hidl_vec microphones; ASSERT_OK(getDevice()->getMicrophones(returnIn(res, microphones))); + if (res == Result::NOT_SUPPORTED) { + GTEST_SKIP() << "getMicrophones is not supported"; // returns + } ASSERT_OK(res); if (microphones.size() > 0) { // When there is microphone on the phone, try to open an input stream @@ -120,7 +124,7 @@ TEST_P(AudioPrimaryHidlTest, GetMicrophonesTest) { } } -TEST_P(AudioPrimaryHidlTest, SetConnectedState) { +TEST_P(AudioHidlDeviceTest, SetConnectedState) { doc::test("Check that the HAL can be notified of device connection and deconnection"); using AD = AudioDevice; for (auto deviceType : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) { @@ -142,7 +146,7 @@ TEST_P(AudioPrimaryHidlTest, SetConnectedState) { // Because there is no way of knowing if the devices were connected before // calling setConnectedState, there is no way to restore the HAL to its // initial state. To workaround this, destroy the HAL at the end of this test. - ASSERT_TRUE(DeviceManager::getInstance().resetPrimary(getFactoryName())); + ASSERT_TRUE(resetDevice()); } static void testGetDevices(IStream* stream, AudioDevice expectedDevice) { diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp index 6314ea72ec..937de0a18d 100644 --- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp @@ -16,3 +16,51 @@ // pull in all the <= 5.0 tests #include "5.0/AudioPrimaryHidlHalTest.cpp" + +const std::vector& getDeviceParametersForFactoryTests() { + static std::vector parameters = [] { + std::vector result; + const auto factories = + ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor); + for (const auto& factoryName : factories) { + result.emplace_back(factoryName, + DeviceManager::getInstance().getPrimary(factoryName) != nullptr + ? DeviceManager::kPrimaryDevice + : ""); + } + return result; + }(); + return parameters; +} + +const std::vector& getDeviceParametersForPrimaryDeviceTests() { + static std::vector parameters = [] { + std::vector result; + const auto primary = std::find_if( + getDeviceParameters().begin(), getDeviceParameters().end(), [](const auto& elem) { + return std::get(elem) == DeviceManager::kPrimaryDevice; + }); + if (primary != getDeviceParameters().end()) result.push_back(*primary); + return result; + }(); + return parameters; +} + +const std::vector& getDeviceParameters() { + static std::vector parameters = [] { + std::vector result; + const auto factories = + ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor); + const auto devices = getCachedPolicyConfig().getModulesWithDevicesNames(); + result.reserve(devices.size()); + for (const auto& factoryName : factories) { + for (const auto& deviceName : devices) { + if (DeviceManager::getInstance().get(factoryName, deviceName) != nullptr) { + result.emplace_back(factoryName, deviceName); + } + } + } + return result; + }(); + return parameters; +} diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h index e59ab9855e..7bdc5e1eb1 100644 --- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -129,11 +130,31 @@ static AudioHidlTestEnvironment* environment; #include "DeviceManager.h" #if MAJOR_VERSION <= 5 -class HidlTest : public ::testing::VtsHalHidlTargetTestBase { +using HidlTestBase = ::testing::VtsHalHidlTargetTestBase; #elif MAJOR_VERSION >= 6 -class HidlTest : public ::testing::Test { +using HidlTestBase = ::testing::Test; #endif + +class HidlTest : public HidlTestBase { + public: + virtual ~HidlTest() = default; + protected: + // Factory and device name getters to be overridden in subclasses. + virtual const std::string& getFactoryName() const = 0; + virtual const std::string& getDeviceName() const = 0; + + sp getDevicesFactory() const { + return DevicesFactoryManager::getInstance().get(getFactoryName()); + } + sp getDevice() const { + return DeviceManager::getInstance().get(getFactoryName(), getDeviceName()); + } + bool resetDevice() const { + return DeviceManager::getInstance().reset(getFactoryName(), getDeviceName()); + } + bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); } + // Convenient member to store results Result res; }; @@ -179,7 +200,25 @@ class PolicyConfig : private PolicyConfigData, public AudioPolicyConfig { } mStatus = android::deserializeAudioPolicyFile(mFilePath.c_str(), this); if (mStatus == OK) { - mPrimaryModule = getHwModules().getModuleFromName("primary"); + mPrimaryModule = getHwModules().getModuleFromName(DeviceManager::kPrimaryDevice); + // Available devices are not 'attached' to modules at this moment. + // Need to go over available devices and find their module. + for (const auto& device : availableOutputDevices) { + for (const auto& module : hwModules) { + if (module->getDeclaredDevices().indexOf(device) >= 0) { + mModulesWithDevicesNames.insert(module->getName()); + break; + } + } + } + for (const auto& device : availableInputDevices) { + for (const auto& module : hwModules) { + if (module->getDeclaredDevices().indexOf(device) >= 0) { + mModulesWithDevicesNames.insert(module->getName()); + break; + } + } + } } } status_t getStatus() const { return mStatus; } @@ -193,11 +232,15 @@ class PolicyConfig : private PolicyConfigData, public AudioPolicyConfig { } const std::string& getFilePath() const { return mFilePath; } sp getPrimaryModule() const { return mPrimaryModule; } + const std::set& getModulesWithDevicesNames() const { + return mModulesWithDevicesNames; + } private: status_t mStatus = NO_INIT; std::string mFilePath; sp mPrimaryModule = nullptr; + std::set mModulesWithDevicesNames; }; // Cached policy config after parsing for faster test startup @@ -210,40 +253,26 @@ const PolicyConfig& getCachedPolicyConfig() { return *policyConfig; } -class AudioPolicyConfigTest : public HidlTest { - public: +class AudioPolicyConfigTest : public HidlTestBase { + public: void SetUp() override { - ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp()); // setup base - + ASSERT_NO_FATAL_FAILURE(HidlTestBase::SetUp()); // setup base auto& policyConfig = getCachedPolicyConfig(); ASSERT_EQ(0, policyConfig.getStatus()) << policyConfig.getError(); - - mPrimaryConfig = policyConfig.getPrimaryModule(); - ASSERT_TRUE(mPrimaryConfig) << "Could not find primary module in configuration file: " - << policyConfig.getFilePath(); } - - protected: - sp getDevicesFactory(const std::string& factoryName) const { - return DevicesFactoryManager::getInstance().get(factoryName); - } - - sp getPrimaryDevice(const std::string& factoryName) const { - return DeviceManager::getInstance().getPrimary(factoryName); - } - - bool isPrimaryDeviceOptional(const std::string& factoryName) const { - // It's OK not to have "primary" device on non-default audio HAL service. - return factoryName != kDefaultServiceName; - } - - sp mPrimaryConfig = nullptr; }; TEST_F(AudioPolicyConfigTest, LoadAudioPolicyXMLConfiguration) { doc::test("Test parsing audio_policy_configuration.xml (called in SetUp)"); } +TEST_F(AudioPolicyConfigTest, HasPrimaryModule) { + auto& policyConfig = getCachedPolicyConfig(); + ASSERT_TRUE(policyConfig.getPrimaryModule() != nullptr) + << "Could not find primary module in configuration file: " + << policyConfig.getFilePath(); +} + ////////////////////////////////////////////////////////////////////////////// //////////////////// Test parameter types and definitions //////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -253,13 +282,13 @@ using DeviceParameter = std::tuple; static inline std::string DeviceParameterToString( const ::testing::TestParamInfo& info) { + const auto& deviceName = std::get(info.param); #if MAJOR_VERSION <= 5 - return std::get(info.param); + return !deviceName.empty() ? deviceName : std::to_string(info.index); #elif MAJOR_VERSION >= 6 const auto factoryName = ::android::hardware::PrintInstanceNameToString(::testing::TestParamInfo{ std::get(info.param), info.index}); - const auto& deviceName = std::get(info.param); return !deviceName.empty() ? factoryName + "_" + deviceName : factoryName; #endif } @@ -268,41 +297,48 @@ static inline std::string DeviceParameterToString( // For V2..5 the factory is looked up using the instance name passed // in the environment, only one factory is returned. This is because the VTS // framework will call the test for each instance. Only the primary device of -// the factory specified in the environment is tested. -const std::vector& getDeviceParameters() { +// the default service factory can be tested. + +// Return a pair of <"default", "primary"> or <[non-default name], ""> +// This is used to parametrize device factory tests. +// The device name is used to indicate whether IPrimaryDevice is required. +const std::vector& getDeviceParametersForFactoryTests() { static std::vector parameters = { - {environment->getServiceName(), DeviceManager::kPrimaryDevice}}; + {environment->getServiceName(), + environment->getServiceName() == kDefaultServiceName + ? DeviceManager::kPrimaryDevice + : ""}}; return parameters; } +// Return a pair of <"default", "primary"> or nothing. +// This is used to parametrize primary device tests. +const std::vector& getDeviceParametersForPrimaryDeviceTests() { + static std::vector parameters = + !std::get(*getDeviceParametersForFactoryTests().begin()).empty() + ? getDeviceParametersForFactoryTests() + : std::vector{}; + return parameters; +} +// In V2..5 device tests must only test the primary device. +// No device tests are executed for non-primary devices. +const std::vector& getDeviceParameters() { + return getDeviceParametersForPrimaryDeviceTests(); +} #elif MAJOR_VERSION >= 6 -// FIXME: Will be replaced with code that analyzes the audio policy config file. -const std::vector& getDeviceParameters() { - static std::vector parameters = [] { - const auto instances = - ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor); - std::vector result; - result.reserve(instances.size()); - for (const auto& instance : instances) { - result.emplace_back(instance, DeviceManager::kPrimaryDevice); - } - return result; - }(); - return parameters; -} +// For V6 and above these functions are implemented in 6.0/AudioPrimaryHidlHalTest.cpp +const std::vector& getDeviceParametersForFactoryTests(); +const std::vector& getDeviceParametersForPrimaryDeviceTests(); +const std::vector& getDeviceParameters(); #endif -class AudioHidlTestWithDeviceParameter : public AudioPolicyConfigTest, +class AudioHidlTestWithDeviceParameter : public HidlTest, public ::testing::WithParamInterface { protected: - const std::string& getFactoryName() const { return std::get(GetParam()); } - bool isPrimaryDeviceOptional() const { - return AudioPolicyConfigTest::isPrimaryDeviceOptional(getFactoryName()); + const std::string& getFactoryName() const override { + return std::get(GetParam()); } - sp getDevicesFactory() const { - return AudioPolicyConfigTest::getDevicesFactory(getFactoryName()); - } - sp getPrimaryDevice() const { - return AudioPolicyConfigTest::getPrimaryDevice(getFactoryName()); + const std::string& getDeviceName() const override { + return std::get(GetParam()); } }; @@ -310,7 +346,7 @@ class AudioHidlTestWithDeviceParameter : public AudioPolicyConfigTest, ////////////////////// getService audio_devices_factory ////////////////////// ////////////////////////////////////////////////////////////////////////////// -// Test all audio devices +// Test audio devices factory class AudioHidlTest : public AudioHidlTestWithDeviceParameter { public: void SetUp() override { @@ -337,53 +373,75 @@ TEST_P(AudioHidlTest, OpenDeviceInvalidParameter) { ASSERT_TRUE(device == nullptr); } -INSTANTIATE_TEST_CASE_P(AudioHidl, AudioHidlTest, ::testing::ValuesIn(getDeviceParameters()), +INSTANTIATE_TEST_CASE_P(AudioHidl, AudioHidlTest, + ::testing::ValuesIn(getDeviceParametersForFactoryTests()), &DeviceParameterToString); +////////////////////////////////////////////////////////////////////////////// +/////////////////////////////// openDevice /////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// Test all audio devices +class AudioHidlDeviceTest : public AudioHidlTest { + public: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base + ASSERT_TRUE(getDevice() != nullptr); + } +}; + +TEST_P(AudioHidlDeviceTest, OpenDevice) { + doc::test("Test openDevice (called during setup)"); +} + +TEST_P(AudioHidlDeviceTest, Init) { + doc::test("Test that the audio hal initialized correctly"); + ASSERT_OK(getDevice()->initCheck()); +} + +INSTANTIATE_TEST_CASE_P(AudioHidlDevice, AudioHidlDeviceTest, + ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); + ////////////////////////////////////////////////////////////////////////////// /////////////////////////////// openDevice primary /////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Test the primary device -class AudioPrimaryHidlTest : public AudioHidlTest { - public: +class AudioPrimaryHidlTest : public AudioHidlDeviceTest { + public: void SetUp() override { - ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base - if (getDevice() == nullptr && isPrimaryDeviceOptional()) { - GTEST_SKIP() << "No primary device on this factory"; - } + ASSERT_NO_FATAL_FAILURE(AudioHidlDeviceTest::SetUp()); // setup base ASSERT_TRUE(getDevice() != nullptr); } - protected: - sp getDevice() const { return getPrimaryDevice(); } + protected: + sp getDevice() const { + return DeviceManager::getInstance().getPrimary(getFactoryName()); + } }; TEST_P(AudioPrimaryHidlTest, OpenPrimaryDevice) { - doc::test("Test the openDevice (called during setup)"); -} - -TEST_P(AudioPrimaryHidlTest, Init) { - doc::test("Test that the audio primary hal initialized correctly"); - ASSERT_OK(getDevice()->initCheck()); + doc::test("Test openPrimaryDevice (called during setup)"); } INSTANTIATE_TEST_CASE_P(AudioPrimaryHidl, AudioPrimaryHidlTest, - ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), + &DeviceParameterToString); ////////////////////////////////////////////////////////////////////////////// ///////////////////// {set,get}{Master,Mic}{Mute,Volume} ///////////////////// ////////////////////////////////////////////////////////////////////////////// -template -class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { - protected: +template +class AccessorHidlTest : public BaseTestClass { + protected: enum Optionality { REQUIRED, OPTIONAL }; struct Initial { // Initial property value Initial(Property value, Optionality check = REQUIRED) : value(value), check(check) {} Property value; Optionality check; // If this initial value should be checked }; + using BaseTestClass::res; /** Test a property getter and setter. * The getter and/or the setter may return NOT_SUPPORTED if optionality == OPTIONAL. */ @@ -395,7 +453,7 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK}; Property initialValue = expectedInitial.value; - ASSERT_OK((getDevice().get()->*getter)(returnIn(res, initialValue))); + ASSERT_OK((BaseTestClass::getDevice().get()->*getter)(returnIn(res, initialValue))); ASSERT_RESULT(expectedResults, res); if (res == Result::OK && expectedInitial.check == REQUIRED) { EXPECT_EQ(expectedInitial.value, initialValue); @@ -406,7 +464,7 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { for (Property setValue : valuesToTest) { SCOPED_TRACE("Test " + propertyName + " getter and setter for " + testing::PrintToString(setValue)); - auto ret = (getDevice().get()->*setter)(setValue); + auto ret = (BaseTestClass::getDevice().get()->*setter)(setValue); ASSERT_RESULT(expectedResults, ret); if (ret == Result::NOT_SUPPORTED) { doc::partialTest(propertyName + " setter is not supported"); @@ -414,7 +472,7 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { } Property getValue; // Make sure the getter returns the same value just set - ASSERT_OK((getDevice().get()->*getter)(returnIn(res, getValue))); + ASSERT_OK((BaseTestClass::getDevice().get()->*getter)(returnIn(res, getValue))); ASSERT_RESULT(expectedResults, res); if (res == Result::NOT_SUPPORTED) { doc::partialTest(propertyName + " getter is not supported"); @@ -426,34 +484,40 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { for (Property invalidValue : invalidValues) { SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " + testing::PrintToString(invalidValue)); - EXPECT_RESULT(invalidArgsOrNotSupported, (getDevice().get()->*setter)(invalidValue)); + EXPECT_RESULT(invalidArgsOrNotSupported, + (BaseTestClass::getDevice().get()->*setter)(invalidValue)); } // Restore initial value - EXPECT_RESULT(expectedResults, (getDevice().get()->*setter)(initialValue)); + EXPECT_RESULT(expectedResults, (BaseTestClass::getDevice().get()->*setter)(initialValue)); } }; -using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; +using BoolAccessorHidlTest = AccessorHidlTest; +using BoolAccessorPrimaryHidlTest = AccessorHidlTest; -TEST_P(BoolAccessorPrimaryHidlTest, MicMuteTest) { +TEST_P(BoolAccessorHidlTest, MicMuteTest) { doc::test("Check that the mic can be muted and unmuted"); - testAccessors("mic mute", Initial{false}, {true}, &IDevice::setMicMute, &IDevice::getMicMute); + testAccessors("mic mute", Initial{false}, {true}, &IDevice::setMicMute, + &IDevice::getMicMute); // TODO: check that the mic is really muted (all sample are 0) } -TEST_P(BoolAccessorPrimaryHidlTest, MasterMuteTest) { +TEST_P(BoolAccessorHidlTest, MasterMuteTest) { doc::test("If master mute is supported, try to mute and unmute the master output"); testAccessors("master mute", Initial{false}, {true}, &IDevice::setMasterMute, &IDevice::getMasterMute); // TODO: check that the master volume is really muted } -INSTANTIATE_TEST_CASE_P(BoolAccessorPrimaryHidl, BoolAccessorPrimaryHidlTest, +INSTANTIATE_TEST_CASE_P(BoolAccessorHidl, BoolAccessorHidlTest, ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); +INSTANTIATE_TEST_CASE_P(BoolAccessorPrimaryHidl, BoolAccessorPrimaryHidlTest, + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), + &DeviceParameterToString); -using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; -TEST_P(FloatAccessorPrimaryHidlTest, MasterVolumeTest) { +using FloatAccessorHidlTest = AccessorHidlTest; +TEST_P(FloatAccessorHidlTest, MasterVolumeTest) { doc::test("Test the master volume if supported"); testAccessors( "master volume", Initial{1}, {0, 0.5}, &IDevice::setMasterVolume, &IDevice::getMasterVolume, @@ -461,28 +525,29 @@ TEST_P(FloatAccessorPrimaryHidlTest, MasterVolumeTest) { // TODO: check that the master volume is really changed } -INSTANTIATE_TEST_CASE_P(FloatAccessorPrimaryHidl, FloatAccessorPrimaryHidlTest, +INSTANTIATE_TEST_CASE_P(FloatAccessorHidl, FloatAccessorHidlTest, ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); ////////////////////////////////////////////////////////////////////////////// //////////////////////////////// AudioPatches //////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest { - protected: - bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); } +class AudioPatchHidlTest : public AudioHidlDeviceTest { + public: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(AudioHidlDeviceTest::SetUp()); // setup base + if (!areAudioPatchesSupported()) { + GTEST_SKIP() << "Audio patches are not supported"; + } + } }; -TEST_P(AudioPatchPrimaryHidlTest, AudioPatches) { +TEST_P(AudioPatchHidlTest, AudioPatches) { doc::test("Test if audio patches are supported"); - if (!areAudioPatchesSupported()) { - doc::partialTest("Audio patches are not supported"); - return; - } // TODO: test audio patches } -INSTANTIATE_TEST_CASE_P(AudioPatchPrimaryHidl, AudioPatchPrimaryHidlTest, +INSTANTIATE_TEST_CASE_P(AudioPatchHidl, AudioPatchHidlTest, ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); ////////////////////////////////////////////////////////////////////////////// @@ -591,24 +656,21 @@ static string DeviceConfigParameterToString( } class AudioHidlTestWithDeviceConfigParameter - : public AudioPolicyConfigTest, + : public HidlTest, public ::testing::WithParamInterface { protected: - const std::string& getFactoryName() const { + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp()); // setup base + ASSERT_TRUE(getDevicesFactory() != nullptr); + ASSERT_TRUE(getDevice() != nullptr); + } + const std::string& getFactoryName() const override { return std::get(std::get(GetParam())); } - bool isPrimaryDeviceOptional() const { - return AudioPolicyConfigTest::isPrimaryDeviceOptional(getFactoryName()); - } - sp getDevicesFactory() const { - return AudioPolicyConfigTest::getDevicesFactory(getFactoryName()); - } - sp getPrimaryDevice() const { - return AudioPolicyConfigTest::getPrimaryDevice(getFactoryName()); + const std::string& getDeviceName() const override { + return std::get(std::get(GetParam())); } const AudioConfig& getConfig() const { return std::get(GetParam()); } - // FIXME: Split out tests that don't require primary device - sp getDevice() const { return getPrimaryDevice(); } }; ////////////////////////////////////////////////////////////////////////////// @@ -620,16 +682,6 @@ class AudioHidlTestWithDeviceConfigParameter // how to get this value ? is it a property ??? class AudioCaptureConfigPrimaryTest : public AudioHidlTestWithDeviceConfigParameter { - public: - void SetUp() override { - ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceConfigParameter::SetUp()); // setup base - ASSERT_TRUE(getDevicesFactory() != nullptr); - if (getDevice() == nullptr && isPrimaryDeviceOptional()) { - GTEST_SKIP() << "No primary device on this factory"; - } - ASSERT_TRUE(getDevice() != nullptr); - } - protected: void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) { uint64_t bufferSize; @@ -661,8 +713,9 @@ TEST_P(RequiredInputBufferSizeTest, RequiredInputBufferSizeTest) { } INSTANTIATE_TEST_CASE_P( RequiredInputBufferSize, RequiredInputBufferSizeTest, + // FIXME: uses primaryHasMic ::testing::Combine( - ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())), &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( @@ -682,8 +735,9 @@ TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) { } INSTANTIATE_TEST_CASE_P( RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest, + // FIXME: uses primaryHasMic ::testing::Combine( - ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())), &DeviceConfigParameterToString); @@ -691,7 +745,7 @@ INSTANTIATE_TEST_CASE_P( /////////////////////////////// setScreenState /////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -TEST_P(AudioPrimaryHidlTest, setScreenState) { +TEST_P(AudioHidlDeviceTest, setScreenState) { doc::test("Check that the hal can receive the screen state"); for (bool turnedOn : {false, true, true, false, false}) { ASSERT_RESULT(okOrNotSupported, getDevice()->setScreenState(turnedOn)); @@ -702,15 +756,16 @@ TEST_P(AudioPrimaryHidlTest, setScreenState) { //////////////////////////// {get,set}Parameters ///////////////////////////// ////////////////////////////////////////////////////////////////////////////// -TEST_P(AudioPrimaryHidlTest, getParameters) { +TEST_P(AudioHidlDeviceTest, getParameters) { doc::test("Check that the hal can set and get parameters"); hidl_vec context; hidl_vec keys; hidl_vec values; ASSERT_OK(Parameters::get(getDevice(), keys, returnIn(res, values))); - ASSERT_OK(Parameters::set(getDevice(), values)); + ASSERT_RESULT(okOrNotSupported, res); + ASSERT_RESULT(okOrNotSupported, Parameters::set(getDevice(), values)); values.resize(0); - ASSERT_OK(Parameters::set(getDevice(), values)); + ASSERT_RESULT(okOrNotSupported, Parameters::set(getDevice(), values)); } ////////////////////////////////////////////////////////////////////////////// @@ -751,12 +806,12 @@ static void testDebugDump(DebugDump debugDump) { EXPECT_EQ(0, close(fds[1])) << errno; } -TEST_P(AudioPrimaryHidlTest, DebugDump) { +TEST_P(AudioHidlDeviceTest, DebugDump) { doc::test("Check that the hal can dump its state without error"); testDebugDump([this](const auto& handle) { return dump(getDevice(), handle); }); } -TEST_P(AudioPrimaryHidlTest, DebugDumpInvalidArguments) { +TEST_P(AudioHidlDeviceTest, DebugDumpInvalidArguments) { doc::test("Check that the hal dump doesn't crash on invalid arguments"); ASSERT_OK(dump(getDevice(), hidl_handle())); } @@ -768,15 +823,6 @@ TEST_P(AudioPrimaryHidlTest, DebugDumpInvalidArguments) { template class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter { protected: - void SetUp() override { - ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceConfigParameter::SetUp()); // setup base - ASSERT_TRUE(getDevicesFactory() != nullptr); - if (getDevice() == nullptr && isPrimaryDeviceOptional()) { - GTEST_SKIP() << "No primary device on this factory"; - } - ASSERT_TRUE(getDevice() != nullptr); - } - template void testOpen(Open openStream, const AudioConfig& config) { // FIXME: Open a stream without an IOHandle @@ -828,14 +874,12 @@ class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter { usleep(100 * 1000); } - bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); } - private: void TearDown() override { if (open) { ASSERT_OK(closeStream()); } - AudioPolicyConfigTest::TearDown(); + AudioHidlTestWithDeviceConfigParameter::TearDown(); } protected: @@ -850,7 +894,6 @@ class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter { class OutputStreamTest : public OpenStreamTest { void SetUp() override { ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base - if (IsSkipped()) return; // do not attempt to use 'device' address.device = AudioDevice::OUT_DEFAULT; const AudioConfig& config = getConfig(); // TODO: test all flag combination @@ -881,10 +924,11 @@ TEST_P(OutputStreamTest, OpenOutputStreamTest) { "recommended config"); // Open done in SetUp } +// FIXME: Add instantiations for non-primary devices with configs harvested from the APM config file INSTANTIATE_TEST_CASE_P( RequiredOutputStreamConfigSupport, OutputStreamTest, ::testing::Combine( - ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), ::testing::ValuesIn(ConfigHelper::getRequiredSupportPlaybackAudioConfig())), &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( @@ -896,7 +940,7 @@ INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P( RecommendedOutputStreamConfigSupport, OutputStreamTest, ::testing::Combine( - ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), ::testing::ValuesIn(ConfigHelper::getRecommendedSupportPlaybackAudioConfig())), &DeviceConfigParameterToString); @@ -905,7 +949,6 @@ INSTANTIATE_TEST_CASE_P( class InputStreamTest : public OpenStreamTest { void SetUp() override { ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base - if (IsSkipped()) return; // do not attempt to use 'device' address.device = AudioDevice::IN_DEFAULT; const AudioConfig& config = getConfig(); // TODO: test all supported flags and source @@ -934,8 +977,9 @@ TEST_P(InputStreamTest, OpenInputStreamTest) { } INSTANTIATE_TEST_CASE_P( RequiredInputStreamConfigSupport, InputStreamTest, + // FIXME: uses primaryHasMic ::testing::Combine( - ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())), &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( @@ -946,8 +990,9 @@ INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P( RecommendedInputStreamConfigSupport, InputStreamTest, + // FIXME: uses primaryHasMic ::testing::Combine( - ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())), &DeviceConfigParameterToString); @@ -1481,7 +1526,8 @@ TEST_P(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) { &IPrimaryDevice::getBtScoWidebandEnabled); } -using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; +using TtyModeAccessorPrimaryHidlTest = + AccessorHidlTest; TEST_P(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) { doc::test("Query and set the TTY mode state"); testAccessors( @@ -1490,7 +1536,8 @@ TEST_P(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) { &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode); } INSTANTIATE_TEST_CASE_P(TtyModeAccessorPrimaryHidl, TtyModeAccessorPrimaryHidlTest, - ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), + &DeviceParameterToString); TEST_P(BoolAccessorPrimaryHidlTest, setGetHac) { doc::test("Query and set the HAC state"); From 93a389c708725131c041a9b90e98d9b0a6d0daae Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Fri, 1 Nov 2019 20:08:24 -0700 Subject: [PATCH 0219/1022] Convert VtsHalGraphicsComposerV2_4TargetTest to be parameterized test Bug: 142397658 Test: TODO Change-Id: I8aaada238d70fbcb7619f894d6aa174a2d8471c7 --- .../include/composer-vts/2.4/ComposerVts.h | 4 +- .../composer/2.4/vts/functional/Android.bp | 2 + .../VtsHalGraphicsComposerV2_4TargetTest.cpp | 62 +++++++------------ 3 files changed, 24 insertions(+), 44 deletions(-) diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h index e8a3905c2b..5db3e16eaf 100644 --- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h @@ -51,12 +51,10 @@ class Composer : public V2_3::vts::Composer { public: Composer(); explicit Composer(const std::string& name); + explicit Composer(const sp& composer); std::unique_ptr createClient(); - protected: - explicit Composer(const sp& composer); - private: const sp mComposer; }; diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp index 921c42155f..937af3d4d2 100644 --- a/graphics/composer/2.4/vts/functional/Android.bp +++ b/graphics/composer/2.4/vts/functional/Android.bp @@ -51,4 +51,6 @@ cc_test { "android.hardware.graphics.composer@2.3-command-buffer", "android.hardware.graphics.composer@2.4-command-buffer", ], + disable_framework: true, + test_suites: ["general-tests", "vts-core"], } diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index 3d967fc1ea..2c87666efb 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -19,13 +19,15 @@ #include #include -#include #include #include #include #include #include #include +#include +#include +#include #include #include @@ -45,29 +47,11 @@ using common::V1_2::PixelFormat; using mapper::V2_0::IMapper; using mapper::V2_0::vts::Gralloc; -// Test environment for graphics.composer -class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static GraphicsComposerHidlEnvironment* Instance() { - static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { registerTestService(); } - - private: - GraphicsComposerHidlEnvironment() {} - - GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment); -}; - -class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class GraphicsComposerHidlTest : public ::testing::TestWithParam { protected: void SetUp() override { ASSERT_NO_FATAL_FAILURE( - mComposer = std::make_unique( - GraphicsComposerHidlEnvironment::Instance()->getServiceName())); + mComposer = std::make_unique(IComposer::getService(GetParam()))); ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); mComposerCallback = new V2_1::vts::GraphicsComposerCallback; @@ -194,13 +178,13 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { std::unique_ptr mGralloc; }; -TEST_F(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) { +TEST_P(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) { std::vector capabilities; const auto error = mComposerClient->getDisplayCapabilities(mInvalidDisplayId, &capabilities); EXPECT_EQ(Error::BAD_DISPLAY, error); } -TEST_F(GraphicsComposerHidlTest, getDisplayConnectionType) { +TEST_P(GraphicsComposerHidlTest, getDisplayConnectionType) { IComposerClient::DisplayConnectionType type; EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->getDisplayConnectionType(mInvalidDisplayId, &type)); @@ -210,13 +194,13 @@ TEST_F(GraphicsComposerHidlTest, getDisplayConnectionType) { } } -TEST_F(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods_BadDisplay) { +TEST_P(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods_BadDisplay) { std::vector supportedVsyncPeriods; EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->getSupportedDisplayVsyncPeriods( mInvalidDisplayId, Config(0), &supportedVsyncPeriods)); } -TEST_F(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods_BadConfig) { +TEST_P(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods_BadConfig) { for (Display display : mComposerCallback->getDisplays()) { Config invalidConfigId = GetInvalidConfigId(display); std::vector supportedVsyncPeriods; @@ -225,7 +209,7 @@ TEST_F(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods_BadConfig) { } } -TEST_F(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods) { +TEST_P(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods) { for (Display display : mComposerCallback->getDisplays()) { for (Config config : mComposerClient->getDisplayConfigs(display)) { std::vector supportedVsyncPeriods; @@ -250,13 +234,13 @@ TEST_F(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods) { } } -TEST_F(GraphicsComposerHidlTest, getDisplayVsyncPeriod_BadDisplay) { +TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod_BadDisplay) { VsyncPeriodNanos vsyncPeriodNanos; EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->getDisplayVsyncPeriod(mInvalidDisplayId, &vsyncPeriodNanos)); } -TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadDisplay) { +TEST_P(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadDisplay) { int64_t newVsyncAppliedTime; IComposerClient::VsyncPeriodChangeConstraints constraints; @@ -268,7 +252,7 @@ TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadDisplay) { constraints, &newVsyncAppliedTime)); } -TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadConfig) { +TEST_P(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadConfig) { int64_t newVsyncAppliedTime; IComposerClient::VsyncPeriodChangeConstraints constraints; @@ -283,7 +267,7 @@ TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadConfig) { } } -TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadVsyncPeriod) { +TEST_P(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadVsyncPeriod) { int64_t newVsyncAppliedTime; IComposerClient::VsyncPeriodChangeConstraints constraints; @@ -349,7 +333,7 @@ void GraphicsComposerHidlTest::Test_setActiveConfigAndVsyncPeriod( } } -TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod) { +TEST_P(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod) { IComposerClient::VsyncPeriodChangeConstraints constraints; constraints.seamlessRequired = false; @@ -357,7 +341,7 @@ TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod) { Test_setActiveConfigAndVsyncPeriod(constraints); } -TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_delayed) { +TEST_P(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_delayed) { IComposerClient::VsyncPeriodChangeConstraints constraints; constexpr auto kDelayForChange = 300ms; @@ -366,6 +350,11 @@ TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_delayed) { Test_setActiveConfigAndVsyncPeriod(constraints); } +INSTANTIATE_TEST_SUITE_P( + PerInstance, GraphicsComposerHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), + android::hardware::PrintInstanceNameToString); + } // namespace } // namespace vts } // namespace V2_4 @@ -373,12 +362,3 @@ TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_delayed) { } // namespace graphics } // namespace hardware } // namespace android - -int main(int argc, char** argv) { - using android::hardware::graphics::composer::V2_4::vts::GraphicsComposerHidlEnvironment; - ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - return status; -} From 65d03e4d8f545707b4bc5339c8a64630fbe3ea39 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Mon, 28 Oct 2019 13:44:49 -0700 Subject: [PATCH 0220/1022] [hardware][interfaces][sensors] fix -Wreorder-init-list again C++20 will require members in a designated initializer to be in order unlike C99. This snuck in because I haven't upgraded the platform toolchain yet. Bug: 139945549 Test: mm Change-Id: Ica2844a213467e41d9b6a8955f1750692da8b444 Signed-off-by: Nick Desaulniers --- sensors/common/vts/utils/GrallocWrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sensors/common/vts/utils/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp index e63faa2e1c..1cad9135b7 100644 --- a/sensors/common/vts/utils/GrallocWrapper.cpp +++ b/sensors/common/vts/utils/GrallocWrapper.cpp @@ -147,8 +147,8 @@ BufferDescriptor GrallocHalWrapper::getDescriptor(uint32_t .width = size, .height = 1, .layerCount = 1, - .format = static_cast(PixelFormat::BLOB), .usage = kBufferUsage, + .format = static_cast(PixelFormat::BLOB), }; BufferDescriptor descriptor; From de2a5dcd48074fdf08932c9e8e7f38132a1464ee Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Tue, 5 Nov 2019 13:15:36 -0800 Subject: [PATCH 0221/1022] [hardware][interfaces][graphics] fix -Wimplicit-int-float-conversion IEEE 754 single precision cannot precisely represent the value of large 32b integrals. Accept the imprecision from implicit casts by making the casts explicit. One case is comparing the value before and after converting a float to an int32_t and back, the other is used when printing a value. Bug: 139945549 Test: mm Change-Id: Id30edce2cd29c0f9c24cd52ba5fb33f7c56a3100 Signed-off-by: Nick Desaulniers --- .../2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp b/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp index 3d138f7308..5a75ae1591 100644 --- a/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp +++ b/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp @@ -1389,7 +1389,7 @@ static std::string rectString(hwc_rect_t rect) { } static std::string approximateFloatString(float f) { - if (static_cast(f) == f) { + if (static_cast(static_cast(f)) == f) { return std::to_string(static_cast(f)); } int32_t truncated = static_cast(f * 10); @@ -1680,10 +1680,10 @@ std::string HWC2On1Adapter::Display::Config::toString(bool splitLine) const { if (mAttributes.count(HWC2::Attribute::DpiX) != 0 && mAttributes.at(HWC2::Attribute::DpiX) != -1) { std::memset(buffer, 0, BUFFER_SIZE); - writtenBytes = snprintf(buffer, BUFFER_SIZE, - ", DPI: %.1f x %.1f", - mAttributes.at(HWC2::Attribute::DpiX) / 1000.0f, - mAttributes.at(HWC2::Attribute::DpiY) / 1000.0f); + writtenBytes = + snprintf(buffer, BUFFER_SIZE, ", DPI: %.1f x %.1f", + static_cast(mAttributes.at(HWC2::Attribute::DpiX)) / 1000.0f, + static_cast(mAttributes.at(HWC2::Attribute::DpiY)) / 1000.0f); output.append(buffer, writtenBytes); } From 040bfea972a82f85d2d32e35b355a2c86e127fbf Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 6 Nov 2019 11:03:01 -0800 Subject: [PATCH 0222/1022] audio: Add CALL_SCREEN audio mode. Add new audio mode AudioMode.CALL_SCREEN allowing call screening to take place while other audio use cases are still active. Also add audio policy configuration attribute indicating if the vendor implementation supports this audio mode. Bug: 140384450 Test: make Change-Id: I2714a9949f2c45b1f8e5a5c40368a6152bd91572 --- audio/6.0/config/api/current.txt | 2 ++ audio/6.0/config/audio_policy_configuration.xsd | 1 + audio/common/6.0/types.hal | 2 ++ 3 files changed, 5 insertions(+) diff --git a/audio/6.0/config/api/current.txt b/audio/6.0/config/api/current.txt index 7aa147cbb5..e67831c6c9 100644 --- a/audio/6.0/config/api/current.txt +++ b/audio/6.0/config/api/current.txt @@ -250,7 +250,9 @@ package audio.policy.configuration.V6_0 { public class GlobalConfiguration { ctor public GlobalConfiguration(); + method public boolean getCall_screen_mode_supported(); method public boolean getSpeaker_drc_enabled(); + method public void setCall_screen_mode_supported(boolean); method public void setSpeaker_drc_enabled(boolean); } diff --git a/audio/6.0/config/audio_policy_configuration.xsd b/audio/6.0/config/audio_policy_configuration.xsd index 0dc89bb1a7..29f6f3811b 100644 --- a/audio/6.0/config/audio_policy_configuration.xsd +++ b/audio/6.0/config/audio_policy_configuration.xsd @@ -66,6 +66,7 @@ + diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal index 132f86dc4e..0c97c3686c 100644 --- a/audio/common/6.0/types.hal +++ b/audio/common/6.0/types.hal @@ -556,6 +556,8 @@ enum AudioMode : int32_t { IN_CALL = 2, /** Calls handled by apps (Eg: Hangout). */ IN_COMMUNICATION = 3, + /** Call screening in progress */ + CALL_SCREEN = 4, }; @export(name="", value_prefix="AUDIO_DEVICE_") From a90619662b6d0b1874180d9729719061efe4a570 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Mon, 4 Nov 2019 12:53:09 -0800 Subject: [PATCH 0223/1022] Improve error handling with separate ICanErrorListener Error handling highlights: - moved onError from ICanMessageListener to ICanErrorListener - added isFatal callback argument to request client disconnect - don't down interface that's already down Also: - don't crash if it's not possible to unregister ICanBus - don't crash while trying to down interface that failed - make hidl-utils available to vendor libraries Bug: 143779011 Test: implemented a VHAL service prototype that communicates with this HAL Change-Id: I98d054da9da0ead5ef952aebc086e052ac996212 --- automotive/can/1.0/Android.bp | 1 + automotive/can/1.0/ICanBus.hal | 12 ++ automotive/can/1.0/ICanErrorListener.hal | 32 ++++++ automotive/can/1.0/ICanMessageListener.hal | 7 -- automotive/can/1.0/default/CanBus.cpp | 103 +++++++++++++----- automotive/can/1.0/default/CanBus.h | 21 +++- automotive/can/1.0/default/CanController.cpp | 13 ++- automotive/can/1.0/default/CanSocket.cpp | 20 +++- automotive/can/1.0/default/CanSocket.h | 3 +- automotive/can/1.0/default/CloseHandle.cpp | 2 +- automotive/can/1.0/default/CloseHandle.h | 4 +- automotive/can/1.0/hidl-utils/Android.bp | 1 + automotive/can/1.0/types.hal | 3 + .../functional/VtsHalCanBusV1_0TargetTest.cpp | 39 ++++++- .../VtsHalCanBusVirtualV1_0TargetTest.cpp | 7 +- 15 files changed, 209 insertions(+), 59 deletions(-) create mode 100644 automotive/can/1.0/ICanErrorListener.hal diff --git a/automotive/can/1.0/Android.bp b/automotive/can/1.0/Android.bp index fe2a2bed21..2221e6623e 100644 --- a/automotive/can/1.0/Android.bp +++ b/automotive/can/1.0/Android.bp @@ -10,6 +10,7 @@ hidl_interface { "types.hal", "ICanBus.hal", "ICanController.hal", + "ICanErrorListener.hal", "ICanMessageListener.hal", "ICloseHandle.hal", ], diff --git a/automotive/can/1.0/ICanBus.hal b/automotive/can/1.0/ICanBus.hal index 6ed89f3b22..e68f16c6fc 100644 --- a/automotive/can/1.0/ICanBus.hal +++ b/automotive/can/1.0/ICanBus.hal @@ -15,6 +15,7 @@ */ package android.hardware.automotive.can@1.0; +import ICanErrorListener; import ICanMessageListener; import ICloseHandle; @@ -57,4 +58,15 @@ interface ICanBus { */ listen(vec filter, ICanMessageListener listener) generates (Result result, ICloseHandle close); + + /** + * Adds a new listener for CAN bus or interface errors. + * + * If the error is fatal, the client is supposed to drop any references to + * this specific ICanBus instance (see ICanErrorListener). + * + * @param listener The interface to receive the error events on + * @return close A handle to call in order to remove the listener + */ + listenForErrors(ICanErrorListener listener) generates (ICloseHandle close); }; diff --git a/automotive/can/1.0/ICanErrorListener.hal b/automotive/can/1.0/ICanErrorListener.hal new file mode 100644 index 0000000000..8a6ba054bc --- /dev/null +++ b/automotive/can/1.0/ICanErrorListener.hal @@ -0,0 +1,32 @@ +/* + * 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. + */ +package android.hardware.automotive.can@1.0; + +/** + * CAN error listener. + */ +interface ICanErrorListener { + /** + * Called on error event. + * + * If the error is fatal, the client is supposed to drop any references to + * this specific ICanBus instance. + * + * @param error Error type + * @param isFatal Whether an error would result with ICanBus instance being unusable. + */ + onError(ErrorEvent error, bool isFatal); +}; diff --git a/automotive/can/1.0/ICanMessageListener.hal b/automotive/can/1.0/ICanMessageListener.hal index 992d1c77ff..28161fa747 100644 --- a/automotive/can/1.0/ICanMessageListener.hal +++ b/automotive/can/1.0/ICanMessageListener.hal @@ -30,11 +30,4 @@ interface ICanMessageListener { * @param message Received CAN message */ onReceive(CanMessage message); - - /** - * Called on error event. - * - * @param error Error type - */ - onError(ErrorEvent error); }; diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp index 65da291b0b..38a9974771 100644 --- a/automotive/can/1.0/default/CanBus.cpp +++ b/automotive/can/1.0/default/CanBus.cpp @@ -68,14 +68,14 @@ Return CanBus::listen(const hidl_vec& filter, return {}; } - std::lock_guard lckListeners(mListenersGuard); + std::lock_guard lckListeners(mMsgListenersGuard); sp closeHandle = new CloseHandle([this, listenerCb]() { - std::lock_guard lck(mListenersGuard); - std::erase_if(mListeners, [&](const auto& e) { return e.callback == listenerCb; }); + std::lock_guard lck(mMsgListenersGuard); + std::erase_if(mMsgListeners, [&](const auto& e) { return e.callback == listenerCb; }); }); - mListeners.emplace_back(CanMessageListener{listenerCb, filter, closeHandle}); - auto& listener = mListeners.back(); + mMsgListeners.emplace_back(CanMessageListener{listenerCb, filter, closeHandle}); + auto& listener = mMsgListeners.back(); // fix message IDs to have all zeros on bits not covered by mask std::for_each(listener.filter.begin(), listener.filter.end(), @@ -91,8 +91,15 @@ CanBus::~CanBus() { std::lock_guard lck(mIsUpGuard); CHECK(!mIsUp) << "Interface is still up while being destroyed"; - std::lock_guard lckListeners(mListenersGuard); - CHECK(mListeners.empty()) << "Listeners list is not empty while interface is being destroyed"; + std::lock_guard lckListeners(mMsgListenersGuard); + CHECK(mMsgListeners.empty()) << "Listener list is not empty while interface is being destroyed"; +} + +void CanBus::setErrorCallback(ErrorCallback errcb) { + CHECK(!mIsUp) << "Can't set error callback while interface is up"; + CHECK(mErrCb == nullptr) << "Error callback is already set"; + mErrCb = errcb; + CHECK(!mIsUp) << "Can't set error callback while interface is up"; } ICanController::Result CanBus::preUp() { @@ -120,19 +127,19 @@ ICanController::Result CanBus::up() { LOG(ERROR) << "Interface " << mIfname << " didn't get prepared"; return ICanController::Result::BAD_ADDRESS; } - mWasUpInitially = *isUp; - if (!mWasUpInitially && !netdevice::up(mIfname)) { + if (!*isUp && !netdevice::up(mIfname)) { LOG(ERROR) << "Can't bring " << mIfname << " up"; return ICanController::Result::UNKNOWN_ERROR; } + mDownAfterUse = !*isUp; using namespace std::placeholders; CanSocket::ReadCallback rdcb = std::bind(&CanBus::onRead, this, _1, _2); - CanSocket::ErrorCallback errcb = std::bind(&CanBus::onError, this); + CanSocket::ErrorCallback errcb = std::bind(&CanBus::onError, this, _1); mSocket = CanSocket::open(mIfname, rdcb, errcb); if (!mSocket) { - if (!mWasUpInitially) netdevice::down(mIfname); + if (mDownAfterUse) netdevice::down(mIfname); return ICanController::Result::UNKNOWN_ERROR; } @@ -140,24 +147,50 @@ ICanController::Result CanBus::up() { return ICanController::Result::OK; } -void CanBus::clearListeners() { +void CanBus::clearMsgListeners() { std::vector> listenersToClose; { - std::lock_guard lck(mListenersGuard); - std::transform(mListeners.begin(), mListeners.end(), std::back_inserter(listenersToClose), + std::lock_guard lck(mMsgListenersGuard); + std::transform(mMsgListeners.begin(), mMsgListeners.end(), + std::back_inserter(listenersToClose), [](const auto& e) { return e.closeHandle; }); } for (auto& weakListener : listenersToClose) { /* Between populating listenersToClose and calling close method here, some listeners might - * have been already removed from the original mListeners list (resulting in a dangling weak - * pointer here). It's fine - we just want to clean them up. */ + * have been already removed from the original mMsgListeners list (resulting in a dangling + * weak pointer here). It's fine - we just want to clean them up. */ auto listener = weakListener.promote(); if (listener != nullptr) listener->close(); } - std::lock_guard lck(mListenersGuard); - CHECK(mListeners.empty()) << "Listeners list wasn't emptied"; + std::lock_guard lck(mMsgListenersGuard); + CHECK(mMsgListeners.empty()) << "Listeners list wasn't emptied"; +} + +void CanBus::clearErrListeners() { + std::lock_guard lck(mErrListenersGuard); + mErrListeners.clear(); +} + +Return> CanBus::listenForErrors(const sp& listener) { + if (listener == nullptr) { + return new CloseHandle(); + } + + std::lock_guard upLck(mIsUpGuard); + if (!mIsUp) { + listener->onError(ErrorEvent::INTERFACE_DOWN, true); + return new CloseHandle(); + } + + std::lock_guard errLck(mErrListenersGuard); + mErrListeners.emplace_back(listener); + + return new CloseHandle([this, listener]() { + std::lock_guard lck(mErrListenersGuard); + std::erase(mErrListeners, listener); + }); } bool CanBus::down() { @@ -169,12 +202,13 @@ bool CanBus::down() { } mIsUp = false; - clearListeners(); + clearMsgListeners(); + clearErrListeners(); mSocket.reset(); bool success = true; - if (!mWasUpInitially && !netdevice::down(mIfname)) { + if (mDownAfterUse && !netdevice::down(mIfname)) { LOG(ERROR) << "Can't bring " << mIfname << " down"; // don't return yet, let's try to do best-effort cleanup success = false; @@ -223,22 +257,35 @@ void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds ti LOG(VERBOSE) << "Got message " << toString(message); } - std::lock_guard lck(mListenersGuard); - for (auto& listener : mListeners) { + std::lock_guard lck(mMsgListenersGuard); + for (auto& listener : mMsgListeners) { if (!match(listener.filter, message.id)) continue; - if (!listener.callback->onReceive(message).isOk()) { + if (!listener.callback->onReceive(message).isOk() && !listener.failedOnce) { + listener.failedOnce = true; LOG(WARNING) << "Failed to notify listener about message"; } } } -void CanBus::onError() { - std::lock_guard lck(mListenersGuard); - for (auto& listener : mListeners) { - if (!listener.callback->onError(ErrorEvent::HARDWARE_ERROR).isOk()) { - LOG(WARNING) << "Failed to notify listener about error"; +void CanBus::onError(int errnoVal) { + auto eventType = ErrorEvent::HARDWARE_ERROR; + + if (errnoVal == ENODEV || errnoVal == ENETDOWN) { + mDownAfterUse = false; + eventType = ErrorEvent::INTERFACE_DOWN; + } + + { + std::lock_guard lck(mErrListenersGuard); + for (auto& listener : mErrListeners) { + if (!listener->onError(eventType, true).isOk()) { + LOG(WARNING) << "Failed to notify listener about error"; + } } } + + const auto errcb = mErrCb; + if (errcb != nullptr) errcb(); } } // namespace implementation diff --git a/automotive/can/1.0/default/CanBus.h b/automotive/can/1.0/default/CanBus.h index 81a83c82b8..30a2924942 100644 --- a/automotive/can/1.0/default/CanBus.h +++ b/automotive/can/1.0/default/CanBus.h @@ -34,12 +34,16 @@ namespace V1_0 { namespace implementation { struct CanBus : public ICanBus { + using ErrorCallback = std::function; + virtual ~CanBus(); Return send(const CanMessage& message) override; Return listen(const hidl_vec& filter, const sp& listener, listen_cb _hidl_cb) override; + Return> listenForErrors(const sp& listener) override; + void setErrorCallback(ErrorCallback errcb); ICanController::Result up(); bool down(); @@ -68,17 +72,22 @@ struct CanBus : public ICanBus { sp callback; hidl_vec filter; wp closeHandle; + bool failedOnce = false; }; - void clearListeners(); + void clearMsgListeners(); + void clearErrListeners(); void onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp); - void onError(); + void onError(int errnoVal); - std::mutex mListenersGuard; - std::vector mListeners GUARDED_BY(mListenersGuard); + std::mutex mMsgListenersGuard; + std::vector mMsgListeners GUARDED_BY(mMsgListenersGuard); + + std::mutex mErrListenersGuard; + std::vector> mErrListeners GUARDED_BY(mErrListenersGuard); std::unique_ptr mSocket; - bool mWasUpInitially; + bool mDownAfterUse; /** * Guard for up flag is required to be held for entire time when the interface is being used @@ -87,6 +96,8 @@ struct CanBus : public ICanBus { */ std::mutex mIsUpGuard; bool mIsUp GUARDED_BY(mIsUpGuard) = false; + + ErrorCallback mErrCb; }; } // namespace implementation diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp index 20adbe120e..3b63fe404b 100644 --- a/automotive/can/1.0/default/CanController.cpp +++ b/automotive/can/1.0/default/CanController.cpp @@ -81,6 +81,8 @@ Return CanController::upInterface( return ICanController::Result::NOT_SUPPORTED; } + busService->setErrorCallback([this, name = config.name]() { downInterface(name); }); + const auto result = busService->up(); if (result != ICanController::Result::OK) return result; @@ -97,6 +99,14 @@ Return CanController::upInterface( return ICanController::Result::OK; } +static bool unregisterCanBusService(const hidl_string& name, sp busService) { + auto manager = hidl::manager::V1_2::IServiceManager::getService(); + if (!manager) return false; + const auto res = manager->tryUnregister(ICanBus::descriptor, name, busService); + if (!res.isOk()) return false; + return res; +} + Return CanController::downInterface(const hidl_string& name) { LOG(VERBOSE) << "Attempting to bring interface down: " << name; @@ -110,8 +120,7 @@ Return CanController::downInterface(const hidl_string& name) { auto success = true; - auto manager = hidl::manager::V1_2::IServiceManager::getService(); - if (!manager || !manager->tryUnregister(ICanBus::descriptor, name, busEntry.mapped())) { + if (!unregisterCanBusService(name, busEntry.mapped())) { LOG(ERROR) << "Couldn't unregister " << name; // don't return yet, let's try to do best-effort cleanup success = false; diff --git a/automotive/can/1.0/default/CanSocket.cpp b/automotive/can/1.0/default/CanSocket.cpp index 4d86de6a28..ecf4044db8 100644 --- a/automotive/can/1.0/default/CanSocket.cpp +++ b/automotive/can/1.0/default/CanSocket.cpp @@ -61,7 +61,14 @@ CanSocket::CanSocket(base::unique_fd socket, ReadCallback rdcb, ErrorCallback er CanSocket::~CanSocket() { mStopReaderThread = true; - mReaderThread.join(); + + /* CanSocket can be brought down as a result of read failure, from the same thread, + * so let's just detach and let it finish on its own. */ + if (mReaderThreadFinished) { + mReaderThread.detach(); + } else { + mReaderThread.join(); + } } bool CanSocket::send(const struct canfd_frame& frame) { @@ -94,6 +101,7 @@ static int selectRead(const base::unique_fd& fd, std::chrono::microseconds timeo void CanSocket::readerThread() { LOG(VERBOSE) << "Reader thread started"; + int errnoCopy = 0; while (!mStopReaderThread) { /* The ideal would be to have a blocking read(3) call and interrupt it with shutdown(3). @@ -130,14 +138,20 @@ void CanSocket::readerThread() { } if (errno == EAGAIN) continue; - LOG(ERROR) << "Failed to read CAN packet: " << errno; + errnoCopy = errno; + LOG(ERROR) << "Failed to read CAN packet: " << strerror(errno) << " (" << errno << ")"; break; } mReadCallback(frame, ts); } - if (!mStopReaderThread) mErrorCallback(); + bool failed = !mStopReaderThread; + auto errCb = mErrorCallback; + mReaderThreadFinished = true; + + // Don't access any fields from here, see CanSocket::~CanSocket comment about detached thread + if (failed) errCb(errnoCopy); LOG(VERBOSE) << "Reader thread stopped"; } diff --git a/automotive/can/1.0/default/CanSocket.h b/automotive/can/1.0/default/CanSocket.h index cd7162db75..284e1ea25e 100644 --- a/automotive/can/1.0/default/CanSocket.h +++ b/automotive/can/1.0/default/CanSocket.h @@ -36,7 +36,7 @@ namespace implementation { */ struct CanSocket { using ReadCallback = std::function; - using ErrorCallback = std::function; + using ErrorCallback = std::function; /** * Open and bind SocketCAN socket. @@ -68,6 +68,7 @@ struct CanSocket { const base::unique_fd mSocket; std::thread mReaderThread; std::atomic mStopReaderThread = false; + std::atomic mReaderThreadFinished = false; DISALLOW_COPY_AND_ASSIGN(CanSocket); }; diff --git a/automotive/can/1.0/default/CloseHandle.cpp b/automotive/can/1.0/default/CloseHandle.cpp index 13693d29e6..aba2c49a48 100644 --- a/automotive/can/1.0/default/CloseHandle.cpp +++ b/automotive/can/1.0/default/CloseHandle.cpp @@ -33,7 +33,7 @@ Return CloseHandle::close() { const auto wasClosed = mIsClosed.exchange(true); if (wasClosed) return {}; - mCallback(); + if (mCallback != nullptr) mCallback(); return {}; } diff --git a/automotive/can/1.0/default/CloseHandle.h b/automotive/can/1.0/default/CloseHandle.h index 94972e03b5..5191739e07 100644 --- a/automotive/can/1.0/default/CloseHandle.h +++ b/automotive/can/1.0/default/CloseHandle.h @@ -39,13 +39,13 @@ struct CloseHandle : public ICloseHandle { * * \param callback Called on the first close() call, or on destruction of the handle */ - CloseHandle(Callback callback); + CloseHandle(Callback callback = nullptr); virtual ~CloseHandle(); Return close() override; private: - Callback mCallback; + const Callback mCallback; std::atomic mIsClosed = false; DISALLOW_COPY_AND_ASSIGN(CloseHandle); diff --git a/automotive/can/1.0/hidl-utils/Android.bp b/automotive/can/1.0/hidl-utils/Android.bp index bc8ff136e5..63b07c9391 100644 --- a/automotive/can/1.0/hidl-utils/Android.bp +++ b/automotive/can/1.0/hidl-utils/Android.bp @@ -17,4 +17,5 @@ cc_library_headers { name: "android.hardware.automotive.can@hidl-utils-lib", export_include_dirs: ["include"], + vendor_available: true, } diff --git a/automotive/can/1.0/types.hal b/automotive/can/1.0/types.hal index 37877c6023..6f690f7851 100644 --- a/automotive/can/1.0/types.hal +++ b/automotive/can/1.0/types.hal @@ -95,6 +95,9 @@ enum ErrorEvent : uint8_t { /** A problem with CAN interface HW. */ HARDWARE_ERROR, + /** CAN interface is down. */ + INTERFACE_DOWN, + /** TX buffer overflow: client is sending too many packets. */ TX_OVERFLOW, diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp index 215328e878..1a05716fd0 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp @@ -36,8 +36,11 @@ using hardware::hidl_vec; static utils::SimpleHidlEnvironment* gEnv = nullptr; struct CanMessageListener : public can::V1_0::ICanMessageListener { - virtual Return onReceive(const can::V1_0::CanMessage&) { return {}; } - virtual Return onError(can::V1_0::ErrorEvent) { return {}; } + virtual Return onReceive(const can::V1_0::CanMessage&) override { return {}; } +}; + +struct CanErrorListener : public can::V1_0::ICanErrorListener { + virtual Return onError(ErrorEvent, bool) override { return {}; } }; class CanBusHalTest : public ::testing::VtsHalHidlTargetTestBase { @@ -47,6 +50,7 @@ class CanBusHalTest : public ::testing::VtsHalHidlTargetTestBase { std::tuple> listen(const hidl_vec& filter, const sp& listener); + sp listenForErrors(const sp& listener); sp mCanBus; }; @@ -70,6 +74,12 @@ std::tuple> CanBusHalTest::listen( return {halResult, closeHandle}; } +sp CanBusHalTest::listenForErrors(const sp& listener) { + const auto res = mCanBus->listenForErrors(listener); + res.assertOk(); + return res; +} + TEST_F(CanBusHalTest, SendNoPayload) { CanMessage msg = {}; msg.id = 0x123; @@ -129,7 +139,7 @@ TEST_F(CanBusHalTest, ListenNull) { ASSERT_EQ(Result::INVALID_ARGUMENTS, result); } -TEST_F(CanBusHalTest, DoubleCloseListen) { +TEST_F(CanBusHalTest, DoubleCloseListener) { const auto [result, closeHandle] = listen({}, new CanMessageListener()); ASSERT_EQ(Result::OK, result); @@ -137,11 +147,32 @@ TEST_F(CanBusHalTest, DoubleCloseListen) { closeHandle->close().assertOk(); } -TEST_F(CanBusHalTest, DontCloseListen) { +TEST_F(CanBusHalTest, DontCloseListener) { const auto [result, closeHandle] = listen({}, new CanMessageListener()); ASSERT_EQ(Result::OK, result); } +TEST_F(CanBusHalTest, DoubleCloseErrorListener) { + auto closeHandle = listenForErrors(new CanErrorListener()); + ASSERT_NE(nullptr, closeHandle.get()); + + closeHandle->close().assertOk(); + closeHandle->close().assertOk(); +} + +TEST_F(CanBusHalTest, DoubleCloseNullErrorListener) { + auto closeHandle = listenForErrors(nullptr); + ASSERT_NE(nullptr, closeHandle.get()); + + closeHandle->close().assertOk(); + closeHandle->close().assertOk(); +} + +TEST_F(CanBusHalTest, DontCloseErrorListener) { + auto closeHandle = listenForErrors(new CanErrorListener()); + ASSERT_NE(nullptr, closeHandle.get()); +} + } // namespace vts } // namespace V1_0 } // namespace can diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp index 699c1387a3..ba29c29e9c 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp @@ -50,18 +50,13 @@ struct CanMessageListener : public can::V1_0::ICanMessageListener { CanMessageListener() {} - virtual Return onReceive(const can::V1_0::CanMessage& msg) { + virtual Return onReceive(const can::V1_0::CanMessage& msg) override { std::unique_lock lk(mMessagesGuard); mMessages.push_back(msg); mMessagesUpdated.notify_one(); return {}; } - virtual Return onError(can::V1_0::ErrorEvent event) { - EXPECT_TRUE(false) << "Got error: " << event; - return {}; - } - virtual ~CanMessageListener() { mCloseHandle->close(); } void assignCloseHandle(sp closeHandle) { From eeb53385b3b7615234da8be84d5a24e863478e2e Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Thu, 10 Oct 2019 20:18:31 -0700 Subject: [PATCH 0224/1022] Wifi: Add 802.11ax support to RTT This CL makes modidfication to support Wifi 802.11ax to RTT procedures. Bug: 139354972 Test: vts test Change-Id: I79fba504e7c7380a254a0b8c175a13e8b993fc8e --- wifi/1.4/Android.bp | 4 + wifi/1.4/IWifiApIface.hal | 2 +- wifi/1.4/IWifiChip.hal | 46 +++ wifi/1.4/IWifiRttController.hal | 102 +++++ wifi/1.4/IWifiRttControllerEventCallback.hal | 33 ++ wifi/1.4/default/hidl_struct_util.cpp | 13 +- wifi/1.4/default/hidl_struct_util.h | 1 + .../default/tests/wifi_chip_unit_tests.cpp | 4 +- wifi/1.4/default/wifi_chip.cpp | 87 ++-- wifi/1.4/default/wifi_chip.h | 14 +- wifi/1.4/default/wifi_rtt_controller.cpp | 192 ++++++--- wifi/1.4/default/wifi_rtt_controller.h | 48 ++- wifi/1.4/default/wifi_status_util.h | 2 +- wifi/1.4/types.hal | 380 ++++++++++++++++++ 14 files changed, 810 insertions(+), 118 deletions(-) create mode 100644 wifi/1.4/IWifiChip.hal create mode 100644 wifi/1.4/IWifiRttController.hal create mode 100644 wifi/1.4/IWifiRttControllerEventCallback.hal create mode 100644 wifi/1.4/types.hal diff --git a/wifi/1.4/Android.bp b/wifi/1.4/Android.bp index aba8b4443a..e19785967a 100644 --- a/wifi/1.4/Android.bp +++ b/wifi/1.4/Android.bp @@ -7,8 +7,12 @@ hidl_interface { enabled: true, }, srcs: [ + "types.hal", "IWifi.hal", "IWifiApIface.hal", + "IWifiChip.hal", + "IWifiRttController.hal", + "IWifiRttControllerEventCallback.hal", ], interfaces: [ "android.hardware.wifi@1.0", diff --git a/wifi/1.4/IWifiApIface.hal b/wifi/1.4/IWifiApIface.hal index af88afbea0..80c576dbfc 100644 --- a/wifi/1.4/IWifiApIface.hal +++ b/wifi/1.4/IWifiApIface.hal @@ -49,5 +49,5 @@ interface IWifiApIface extends @1.0::IWifiApIface { * |WifiStatusCode.ERROR_UNKNOWN| * @return mac factory MAC address of the interface */ - getFactoryMacAddress() generates (WifiStatus status, MacAddress mac); + getFactoryMacAddress() generates (WifiStatus status, MacAddress mac); }; diff --git a/wifi/1.4/IWifiChip.hal b/wifi/1.4/IWifiChip.hal new file mode 100644 index 0000000000..d269427a6d --- /dev/null +++ b/wifi/1.4/IWifiChip.hal @@ -0,0 +1,46 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi@1.4; + +import @1.0::WifiStatus; +import @1.0::IWifiIface; +import @1.3::IWifiChip; +import IWifiRttController; + +/** + * Interface that represents a chip that must be configured as a single unit. + */ +interface IWifiChip extends @1.3::IWifiChip { + /** + * Create a RTTController instance. + * + * RTT controller can be either: + * a) Bound to a specific iface by passing in the corresponding |IWifiIface| + * object in |iface| param, OR + * b) Let the implementation decide the iface to use for RTT operations by + * passing null in |iface| param. + * + * @param boundIface HIDL interface object representing the iface if + * the responder must be bound to a specific iface, null otherwise. + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID| + */ + createRttController_1_4(IWifiIface boundIface) + generates (WifiStatus status, IWifiRttController rtt); +}; diff --git a/wifi/1.4/IWifiRttController.hal b/wifi/1.4/IWifiRttController.hal new file mode 100644 index 0000000000..5c71975f2f --- /dev/null +++ b/wifi/1.4/IWifiRttController.hal @@ -0,0 +1,102 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi@1.4; + +import @1.0::IWifiRttController; +import @1.0::CommandId; +import @1.0::WifiChannelInfo; +import @1.0::WifiStatus; +import IWifiRttControllerEventCallback; + +/** + * Interface used to perform RTT(Round trip time) operations. + */ +interface IWifiRttController extends @1.0::IWifiRttController { + /** + * Requests notifications of significant events on this rtt controller. + * Multiple calls to this must register multiple callbacks each of which must + * receive all events. + * + * @param callback An instance of the |IWifiRttControllerEventCallback| HIDL + * interface object. + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID| + */ + registerEventCallback_1_4(IWifiRttControllerEventCallback callback) + generates (WifiStatus status); + + /** + * API to request RTT measurement. + * + * @param cmdId command Id to use for this invocation. + * @param rttConfigs Vector of |RttConfig| parameters. + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|, + * |WifiStatusCode.ERROR_INVALID_ARGS|, + * |WifiStatusCode.ERROR_NOT_AVAILABLE|, + * |WifiStatusCode.ERROR_UNKNOWN| + */ + rangeRequest_1_4(CommandId cmdId, vec rttConfigs) generates (WifiStatus status); + + /** + * RTT capabilities of the device. + * + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|, + * |WifiStatusCode.ERROR_UNKNOWN| + * @return capabilities Instance of |RttCapabilities|. + */ + getCapabilities_1_4() generates (WifiStatus status, RttCapabilities capabilities); + + /** + * Get RTT responder information e.g. WiFi channel to enable responder on. + * + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|, + * |WifiStatusCode.ERROR_NOT_AVAILABLE|, + * |WifiStatusCode.ERROR_UNKNOWN| + * @return info Instance of |RttResponderInfo|. + */ + getResponderInfo_1_4() generates (WifiStatus status, RttResponder info); + + /** + * Enable RTT responder mode. + * + * @param cmdId command Id to use for this invocation. + * @parm channelHint Hint of the channel information where RTT responder must + * be enabled on. + * @param maxDurationInSeconds Timeout of responder mode. + * @param info Instance of |RttResponderInfo|. + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|, + * |WifiStatusCode.ERROR_INVALID_ARGS|, + * |WifiStatusCode.ERROR_NOT_AVAILABLE|, + * |WifiStatusCode.ERROR_UNKNOWN| + */ + enableResponder_1_4(CommandId cmdId, WifiChannelInfo channelHint, + uint32_t maxDurationInSeconds, RttResponder info) generates (WifiStatus status); +}; diff --git a/wifi/1.4/IWifiRttControllerEventCallback.hal b/wifi/1.4/IWifiRttControllerEventCallback.hal new file mode 100644 index 0000000000..75de3d43d3 --- /dev/null +++ b/wifi/1.4/IWifiRttControllerEventCallback.hal @@ -0,0 +1,33 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi@1.4; + +import @1.0::IWifiRttControllerEventCallback; +import @1.0::CommandId; + +/** + * RTT Response and Event Callbacks. + */ +interface IWifiRttControllerEventCallback extends @1.0::IWifiRttControllerEventCallback { + /* + * Invoked when an RTT result is available. + * + * @param cmdId command Id corresponding to the original request. + * @param results Vector of |RttResult| instances. + */ + oneway onResults_1_4(CommandId cmdId, vec results); +}; diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp index 47713cde22..61f311ec24 100644 --- a/wifi/1.4/default/hidl_struct_util.cpp +++ b/wifi/1.4/default/hidl_struct_util.cpp @@ -2279,6 +2279,8 @@ legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(RttPreamble type) { return legacy_hal::WIFI_RTT_PREAMBLE_HT; case RttPreamble::VHT: return legacy_hal::WIFI_RTT_PREAMBLE_VHT; + case RttPreamble::HE: + return legacy_hal::WIFI_RTT_PREAMBLE_HE; }; CHECK(false); } @@ -2291,6 +2293,8 @@ RttPreamble convertLegacyRttPreambleToHidl(legacy_hal::wifi_rtt_preamble type) { return RttPreamble::HT; case legacy_hal::WIFI_RTT_PREAMBLE_VHT: return RttPreamble::VHT; + case legacy_hal::WIFI_RTT_PREAMBLE_HE: + return RttPreamble::HE; }; CHECK(false) << "Unknown legacy type: " << type; } @@ -2354,6 +2358,8 @@ WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) { return WifiRatePreamble::HT; case 3: return WifiRatePreamble::VHT; + case 4: + return WifiRatePreamble::HE; default: return WifiRatePreamble::RESERVED; }; @@ -2579,9 +2585,10 @@ bool convertLegacyRttCapabilitiesToHidl( hidl_capabilities->responderSupported = legacy_capabilities.responder_supported; hidl_capabilities->preambleSupport = 0; - for (const auto flag : {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY, - legacy_hal::WIFI_RTT_PREAMBLE_HT, - legacy_hal::WIFI_RTT_PREAMBLE_VHT}) { + for (const auto flag : + {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY, + legacy_hal::WIFI_RTT_PREAMBLE_HT, legacy_hal::WIFI_RTT_PREAMBLE_VHT, + legacy_hal::WIFI_RTT_PREAMBLE_HE}) { if (legacy_capabilities.preamble_support & flag) { hidl_capabilities->preambleSupport |= static_cast::type>( diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h index c9f1c262d5..a99c1ac051 100644 --- a/wifi/1.4/default/hidl_struct_util.h +++ b/wifi/1.4/default/hidl_struct_util.h @@ -25,6 +25,7 @@ #include #include #include +#include #include "wifi_legacy_hal.h" diff --git a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp index b0357ba980..90e81e12c1 100644 --- a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp +++ b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp @@ -252,7 +252,7 @@ class WifiChipTest : public Test { bool createRttController() { bool success = false; - chip_->createRttController( + chip_->createRttController_1_4( NULL, [&success](const WifiStatus& status, const sp& rtt) { if (WifiStatusCode::SUCCESS == status.code) { @@ -750,7 +750,7 @@ TEST_F(WifiChipV2_AwareIfaceCombinationTest, // Create RTT controller sp rtt_controller; - chip_->createRttController( + chip_->createRttController_1_4( NULL, [&rtt_controller](const WifiStatus& status, const sp& rtt) { if (WifiStatusCode::SUCCESS == status.code) { diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp index 408096fdc0..7685ac61d9 100644 --- a/wifi/1.4/default/wifi_chip.cpp +++ b/wifi/1.4/default/wifi_chip.cpp @@ -620,6 +620,14 @@ Return WifiChip::debug(const hidl_handle& handle, return Void(); } +Return WifiChip::createRttController_1_4( + const sp& bound_iface, + createRttController_1_4_cb hidl_status_cb) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::createRttControllerInternal_1_4, + hidl_status_cb, bound_iface); +} + void WifiChip::invalidateAndRemoveAllIfaces() { invalidateAndClearAll(ap_ifaces_); invalidateAndClearAll(nan_ifaces_); @@ -669,30 +677,6 @@ std::pair WifiChip::getCapabilitiesInternal() { return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0}; } -std::pair WifiChip::getCapabilitiesInternal_1_3() { - legacy_hal::wifi_error legacy_status; - uint32_t legacy_feature_set; - uint32_t legacy_logger_feature_set; - const auto ifname = getFirstActiveWlanIfaceName(); - std::tie(legacy_status, legacy_feature_set) = - legacy_hal_.lock()->getSupportedFeatureSet(ifname); - if (legacy_status != legacy_hal::WIFI_SUCCESS) { - return {createWifiStatusFromLegacyError(legacy_status), 0}; - } - std::tie(legacy_status, legacy_logger_feature_set) = - legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname); - if (legacy_status != legacy_hal::WIFI_SUCCESS) { - // some devices don't support querying logger feature set - legacy_logger_feature_set = 0; - } - uint32_t hidl_caps; - if (!hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities( - legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) { - return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0}; - } - return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps}; -} - std::pair> WifiChip::getAvailableModesInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), modes_}; @@ -996,18 +980,10 @@ WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) { return createWifiStatus(WifiStatusCode::SUCCESS); } -std::pair> -WifiChip::createRttControllerInternal(const sp& bound_iface) { - if (sta_ifaces_.size() == 0 && - !canCurrentModeSupportIfaceOfType(IfaceType::STA)) { - LOG(ERROR) << "createRttControllerInternal: Chip cannot support STAs " - "(and RTT by extension)"; - return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; - } - sp rtt = new WifiRttController( - getFirstActiveWlanIfaceName(), bound_iface, legacy_hal_); - rtt_controllers_.emplace_back(rtt); - return {createWifiStatus(WifiStatusCode::SUCCESS), rtt}; +std::pair> +WifiChip::createRttControllerInternal(const sp& /*bound_iface*/) { + LOG(ERROR) << "createRttController is not supported on this HAL"; + return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } std::pair> @@ -1158,6 +1134,45 @@ WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2( return createWifiStatusFromLegacyError(legacy_status); } +std::pair WifiChip::getCapabilitiesInternal_1_3() { + legacy_hal::wifi_error legacy_status; + uint32_t legacy_feature_set; + uint32_t legacy_logger_feature_set; + const auto ifname = getFirstActiveWlanIfaceName(); + std::tie(legacy_status, legacy_feature_set) = + legacy_hal_.lock()->getSupportedFeatureSet(ifname); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {createWifiStatusFromLegacyError(legacy_status), 0}; + } + std::tie(legacy_status, legacy_logger_feature_set) = + legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + // some devices don't support querying logger feature set + legacy_logger_feature_set = 0; + } + uint32_t hidl_caps; + if (!hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities( + legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) { + return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0}; + } + return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps}; +} + +std::pair> +WifiChip::createRttControllerInternal_1_4(const sp& bound_iface) { + if (sta_ifaces_.size() == 0 && + !canCurrentModeSupportIfaceOfType(IfaceType::STA)) { + LOG(ERROR) + << "createRttControllerInternal_1_4: Chip cannot support STAs " + "(and RTT by extension)"; + return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; + } + sp rtt = new WifiRttController( + getFirstActiveWlanIfaceName(), bound_iface, legacy_hal_); + rtt_controllers_.emplace_back(rtt); + return {createWifiStatus(WifiStatusCode::SUCCESS), rtt}; +} + WifiStatus WifiChip::handleChipConfiguration( /* NONNULL */ std::unique_lock* lock, ChipModeId mode_id) { diff --git a/wifi/1.4/default/wifi_chip.h b/wifi/1.4/default/wifi_chip.h index 0d7061c0e3..3bf18475ae 100644 --- a/wifi/1.4/default/wifi_chip.h +++ b/wifi/1.4/default/wifi_chip.h @@ -21,7 +21,8 @@ #include #include -#include +#include +#include #include "hidl_callback_util.h" #include "ringbuffer.h" @@ -46,7 +47,7 @@ using namespace android::hardware::wifi::V1_0; * Since there is only a single chip instance used today, there is no * identifying handle information stored here. */ -class WifiChip : public V1_3::IWifiChip { +class WifiChip : public V1_4::IWifiChip { public: WifiChip( ChipId chip_id, @@ -152,6 +153,9 @@ class WifiChip : public V1_3::IWifiChip { getCapabilities_cb hidl_status_cb) override; Return debug(const hidl_handle& handle, const hidl_vec& options) override; + Return createRttController_1_4( + const sp& bound_iface, + createRttController_1_4_cb hidl_status_cb) override; private: void invalidateAndRemoveAllIfaces(); @@ -195,8 +199,8 @@ class WifiChip : public V1_3::IWifiChip { std::pair> getStaIfaceInternal( const std::string& ifname); WifiStatus removeStaIfaceInternal(const std::string& ifname); - std::pair> createRttControllerInternal( - const sp& bound_iface); + std::pair> + createRttControllerInternal(const sp& bound_iface); std::pair> getDebugRingBuffersStatusInternal(); WifiStatus startLoggingToDebugRingBufferInternal( @@ -217,6 +221,8 @@ class WifiChip : public V1_3::IWifiChip { const sp& event_callback); WifiStatus selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario); std::pair getCapabilitiesInternal_1_3(); + std::pair> + createRttControllerInternal_1_4(const sp& bound_iface); WifiStatus handleChipConfiguration( std::unique_lock* lock, ChipModeId mode_id); WifiStatus registerDebugRingBufferCallback(); diff --git a/wifi/1.4/default/wifi_rtt_controller.cpp b/wifi/1.4/default/wifi_rtt_controller.cpp index d50c7cf68a..594a11660f 100644 --- a/wifi/1.4/default/wifi_rtt_controller.cpp +++ b/wifi/1.4/default/wifi_rtt_controller.cpp @@ -58,7 +58,7 @@ Return WifiRttController::getBoundIface(getBoundIface_cb hidl_status_cb) { } Return WifiRttController::registerEventCallback( - const sp& callback, + const sp& callback, registerEventCallback_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, @@ -67,7 +67,7 @@ Return WifiRttController::registerEventCallback( } Return WifiRttController::rangeRequest( - uint32_t cmd_id, const hidl_vec& rtt_configs, + uint32_t cmd_id, const hidl_vec& rtt_configs, rangeRequest_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, @@ -115,7 +115,7 @@ Return WifiRttController::getResponderInfo( Return WifiRttController::enableResponder( uint32_t cmd_id, const WifiChannelInfo& channel_hint, - uint32_t max_duration_seconds, const RttResponder& info, + uint32_t max_duration_seconds, const V1_0::RttResponder& info, enableResponder_cb hidl_status_cb) { return validateAndCall( this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, @@ -130,49 +130,64 @@ Return WifiRttController::disableResponder( &WifiRttController::disableResponderInternal, hidl_status_cb, cmd_id); } +Return WifiRttController::registerEventCallback_1_4( + const sp& callback, + registerEventCallback_1_4_cb hidl_status_cb) { + return validateAndCall( + this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, + &WifiRttController::registerEventCallbackInternal_1_4, hidl_status_cb, + callback); +} + +Return WifiRttController::rangeRequest_1_4( + uint32_t cmd_id, const hidl_vec& rtt_configs, + rangeRequest_1_4_cb hidl_status_cb) { + return validateAndCall(this, + WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, + &WifiRttController::rangeRequestInternal_1_4, + hidl_status_cb, cmd_id, rtt_configs); +} + +Return WifiRttController::getCapabilities_1_4( + getCapabilities_1_4_cb hidl_status_cb) { + return validateAndCall( + this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, + &WifiRttController::getCapabilitiesInternal_1_4, hidl_status_cb); +} + +Return WifiRttController::getResponderInfo_1_4( + getResponderInfo_1_4_cb hidl_status_cb) { + return validateAndCall( + this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, + &WifiRttController::getResponderInfoInternal_1_4, hidl_status_cb); +} + +Return WifiRttController::enableResponder_1_4( + uint32_t cmd_id, const WifiChannelInfo& channel_hint, + uint32_t max_duration_seconds, const RttResponder& info, + enableResponder_1_4_cb hidl_status_cb) { + return validateAndCall( + this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, + &WifiRttController::enableResponderInternal_1_4, hidl_status_cb, cmd_id, + channel_hint, max_duration_seconds, info); +} + std::pair> WifiRttController::getBoundIfaceInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), bound_iface_}; } WifiStatus WifiRttController::registerEventCallbackInternal( - const sp& callback) { - // TODO(b/31632518): remove the callback when the client is destroyed - event_callbacks_.emplace_back(callback); - return createWifiStatus(WifiStatusCode::SUCCESS); + const sp& /* callback */) { + // Deprecated support for this api + return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED); } WifiStatus WifiRttController::rangeRequestInternal( - uint32_t cmd_id, const std::vector& rtt_configs) { - std::vector legacy_configs; - if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy( - rtt_configs, &legacy_configs)) { - return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); - } - android::wp weak_ptr_this(this); - const auto& on_results_callback = - [weak_ptr_this]( - legacy_hal::wifi_request_id id, - const std::vector& results) { - const auto shared_ptr_this = weak_ptr_this.promote(); - if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { - LOG(ERROR) << "Callback invoked on an invalid object"; - return; - } - std::vector hidl_results; - if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl( - results, &hidl_results)) { - LOG(ERROR) << "Failed to convert rtt results to HIDL structs"; - return; - } - for (const auto& callback : shared_ptr_this->getEventCallbacks()) { - callback->onResults(id, hidl_results); - } - }; - legacy_hal::wifi_error legacy_status = - legacy_hal_.lock()->startRttRangeRequest( - ifname_, cmd_id, legacy_configs, on_results_callback); - return createWifiStatusFromLegacyError(legacy_status); + uint32_t /* cmd_id */, + const std::vector& /* rtt_configs */) { + // Deprecated support for this api + return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED); } WifiStatus WifiRttController::rangeCancelInternal( @@ -187,21 +202,10 @@ WifiStatus WifiRttController::rangeCancelInternal( return createWifiStatusFromLegacyError(legacy_status); } -std::pair +std::pair WifiRttController::getCapabilitiesInternal() { - legacy_hal::wifi_error legacy_status; - legacy_hal::wifi_rtt_capabilities legacy_caps; - std::tie(legacy_status, legacy_caps) = - legacy_hal_.lock()->getRttCapabilities(ifname_); - if (legacy_status != legacy_hal::WIFI_SUCCESS) { - return {createWifiStatusFromLegacyError(legacy_status), {}}; - } - RttCapabilities hidl_caps; - if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps, - &hidl_caps)) { - return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}}; - } - return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps}; + // Deprecated support for this api + return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}}; } WifiStatus WifiRttController::setLciInternal(uint32_t cmd_id, @@ -228,8 +232,84 @@ WifiStatus WifiRttController::setLcrInternal(uint32_t cmd_id, return createWifiStatusFromLegacyError(legacy_status); } -std::pair +std::pair WifiRttController::getResponderInfoInternal() { + // Deprecated support for this api + return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}}; +} + +WifiStatus WifiRttController::enableResponderInternal( + uint32_t /* cmd_id */, const WifiChannelInfo& /* channel_hint */, + uint32_t /* max_duration_seconds */, const V1_0::RttResponder& /* info */) { + // Deprecated support for this api + return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED)}; +} + +WifiStatus WifiRttController::disableResponderInternal(uint32_t cmd_id) { + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->disableRttResponder(ifname_, cmd_id); + return createWifiStatusFromLegacyError(legacy_status); +} + +WifiStatus WifiRttController::registerEventCallbackInternal_1_4( + const sp& callback) { + // TODO(b/31632518): remove the callback when the client is destroyed + event_callbacks_.emplace_back(callback); + return createWifiStatus(WifiStatusCode::SUCCESS); +} + +WifiStatus WifiRttController::rangeRequestInternal_1_4( + uint32_t cmd_id, const std::vector& rtt_configs) { + std::vector legacy_configs; + if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy( + rtt_configs, &legacy_configs)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + android::wp weak_ptr_this(this); + const auto& on_results_callback = + [weak_ptr_this]( + legacy_hal::wifi_request_id id, + const std::vector& results) { + const auto shared_ptr_this = weak_ptr_this.promote(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + std::vector hidl_results; + if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl( + results, &hidl_results)) { + LOG(ERROR) << "Failed to convert rtt results to HIDL structs"; + return; + } + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + callback->onResults_1_4(id, hidl_results); + } + }; + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->startRttRangeRequest( + ifname_, cmd_id, legacy_configs, on_results_callback); + return createWifiStatusFromLegacyError(legacy_status); +} + +std::pair +WifiRttController::getCapabilitiesInternal_1_4() { + legacy_hal::wifi_error legacy_status; + legacy_hal::wifi_rtt_capabilities legacy_caps; + std::tie(legacy_status, legacy_caps) = + legacy_hal_.lock()->getRttCapabilities(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {createWifiStatusFromLegacyError(legacy_status), {}}; + } + RttCapabilities hidl_caps; + if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps, + &hidl_caps)) { + return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}}; + } + return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps}; +} + +std::pair +WifiRttController::getResponderInfoInternal_1_4() { legacy_hal::wifi_error legacy_status; legacy_hal::wifi_rtt_responder legacy_responder; std::tie(legacy_status, legacy_responder) = @@ -245,7 +325,7 @@ WifiRttController::getResponderInfoInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_responder}; } -WifiStatus WifiRttController::enableResponderInternal( +WifiStatus WifiRttController::enableResponderInternal_1_4( uint32_t cmd_id, const WifiChannelInfo& channel_hint, uint32_t max_duration_seconds, const RttResponder& info) { legacy_hal::wifi_channel_info legacy_channel_info; @@ -264,12 +344,6 @@ WifiStatus WifiRttController::enableResponderInternal( legacy_responder); return createWifiStatusFromLegacyError(legacy_status); } - -WifiStatus WifiRttController::disableResponderInternal(uint32_t cmd_id) { - legacy_hal::wifi_error legacy_status = - legacy_hal_.lock()->disableRttResponder(ifname_, cmd_id); - return createWifiStatusFromLegacyError(legacy_status); -} } // namespace implementation } // namespace V1_4 } // namespace wifi diff --git a/wifi/1.4/default/wifi_rtt_controller.h b/wifi/1.4/default/wifi_rtt_controller.h index 1415ff7ce6..1f125555d0 100644 --- a/wifi/1.4/default/wifi_rtt_controller.h +++ b/wifi/1.4/default/wifi_rtt_controller.h @@ -19,8 +19,8 @@ #include #include -#include -#include +#include +#include #include "wifi_legacy_hal.h" @@ -33,7 +33,7 @@ namespace implementation { /** * HIDL interface object used to control all RTT operations. */ -class WifiRttController : public V1_0::IWifiRttController { +class WifiRttController : public V1_4::IWifiRttController { public: WifiRttController( const std::string& iface_name, const sp& bound_iface, @@ -47,10 +47,10 @@ class WifiRttController : public V1_0::IWifiRttController { // HIDL methods exposed. Return getBoundIface(getBoundIface_cb hidl_status_cb) override; Return registerEventCallback( - const sp& callback, + const sp& callback, registerEventCallback_cb hidl_status_cb) override; Return rangeRequest(uint32_t cmd_id, - const hidl_vec& rtt_configs, + const hidl_vec& rtt_configs, rangeRequest_cb hidl_status_cb) override; Return rangeCancel(uint32_t cmd_id, const hidl_vec>& addrs, @@ -64,29 +64,53 @@ class WifiRttController : public V1_0::IWifiRttController { Return enableResponder(uint32_t cmd_id, const WifiChannelInfo& channel_hint, uint32_t max_duration_seconds, - const RttResponder& info, + const V1_0::RttResponder& info, enableResponder_cb hidl_status_cb) override; Return disableResponder(uint32_t cmd_id, disableResponder_cb hidl_status_cb) override; + Return registerEventCallback_1_4( + const sp& callback, + registerEventCallback_1_4_cb hidl_status_cb) override; + Return rangeRequest_1_4(uint32_t cmd_id, + const hidl_vec& rtt_configs, + rangeRequest_1_4_cb hidl_status_cb) override; + Return getCapabilities_1_4( + getCapabilities_1_4_cb hidl_status_cb) override; + Return getResponderInfo_1_4( + getResponderInfo_1_4_cb hidl_status_cb) override; + Return enableResponder_1_4( + uint32_t cmd_id, const WifiChannelInfo& channel_hint, + uint32_t max_duration_seconds, const RttResponder& info, + enableResponder_1_4_cb hidl_status_cb) override; private: // Corresponding worker functions for the HIDL methods. std::pair> getBoundIfaceInternal(); WifiStatus registerEventCallbackInternal( - const sp& callback); - WifiStatus rangeRequestInternal(uint32_t cmd_id, - const std::vector& rtt_configs); + const sp& callback); + WifiStatus rangeRequestInternal( + uint32_t cmd_id, const std::vector& rtt_configs); WifiStatus rangeCancelInternal( uint32_t cmd_id, const std::vector>& addrs); - std::pair getCapabilitiesInternal(); + std::pair getCapabilitiesInternal(); WifiStatus setLciInternal(uint32_t cmd_id, const RttLciInformation& lci); WifiStatus setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr); - std::pair getResponderInfoInternal(); + std::pair getResponderInfoInternal(); WifiStatus enableResponderInternal(uint32_t cmd_id, const WifiChannelInfo& channel_hint, uint32_t max_duration_seconds, - const RttResponder& info); + const V1_0::RttResponder& info); WifiStatus disableResponderInternal(uint32_t cmd_id); + WifiStatus registerEventCallbackInternal_1_4( + const sp& callback); + WifiStatus rangeRequestInternal_1_4( + uint32_t cmd_id, const std::vector& rtt_configs); + std::pair getCapabilitiesInternal_1_4(); + std::pair getResponderInfoInternal_1_4(); + WifiStatus enableResponderInternal_1_4(uint32_t cmd_id, + const WifiChannelInfo& channel_hint, + uint32_t max_duration_seconds, + const RttResponder& info); std::string ifname_; sp bound_iface_; diff --git a/wifi/1.4/default/wifi_status_util.h b/wifi/1.4/default/wifi_status_util.h index 41bcfaf741..3ff58f0c0a 100644 --- a/wifi/1.4/default/wifi_status_util.h +++ b/wifi/1.4/default/wifi_status_util.h @@ -17,7 +17,7 @@ #ifndef WIFI_STATUS_UTIL_H_ #define WIFI_STATUS_UTIL_H_ -#include +#include #include "wifi_legacy_hal.h" diff --git a/wifi/1.4/types.hal b/wifi/1.4/types.hal new file mode 100644 index 0000000000..232e26ff80 --- /dev/null +++ b/wifi/1.4/types.hal @@ -0,0 +1,380 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi@1.4; + +import @1.0::MacAddress; +import @1.0::Rssi; +import @1.0::RttBw; +import @1.0::RttConfig; +import @1.0::RttPeerType; +import @1.0::RttPreamble; +import @1.0::RttStatus; +import @1.0::RttType; +import @1.0::TimeSpanInPs; +import @1.0::TimeStampInUs; +import @1.0::WifiChannelInfo; +import @1.0::WifiChannelWidthInMhz; +import @1.0::WifiInformationElement; +import @1.0::WifiRateNss; +import @1.0::WifiRatePreamble; + +/** + * Wifi Rate Preamble + */ +enum WifiRatePreamble : @1.0::WifiRatePreamble { + /** + * Preamble type for 11ax + */ + HE = 5, +}; + +/** + * RTT Measurement Preamble. + */ +enum RttPreamble : @1.0::RttPreamble { + /** + * Preamble type for 11ax + */ + HE = 0x8, +}; + +/** + * RTT configuration. + */ +struct RttConfig { + /** + * Peer device mac address. + */ + MacAddress addr; + + /** + * 1-sided or 2-sided RTT. + */ + RttType type; + + /** + * Optional - peer device hint (STA, P2P, AP). + */ + RttPeerType peer; + + /** + * Required for STA-AP mode, optional for P2P, NBD etc. + */ + WifiChannelInfo channel; + + /** + * Time interval between bursts (units: 100 ms). + * Applies to 1-sided and 2-sided RTT multi-burst requests. + * Range: 0-31, 0: no preference by initiator (2-sided RTT). + */ + uint32_t burstPeriod; + + /** + * Total number of RTT bursts to be executed. It will be + * specified in the same way as the parameter "Number of + * Burst Exponent" found in the FTM frame format. It + * applies to both: 1-sided RTT and 2-sided RTT. Valid + * values are 0 to 15 as defined in 802.11mc std. + * 0 means single shot + * The implication of this parameter on the maximum + * number of RTT results is the following: + * for 1-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst) + * for 2-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst - 1) + */ + uint32_t numBurst; + + /** + * Num of frames per burst. + * Minimum value = 1, Maximum value = 31 + * For 2-sided this equals the number of FTM frames + * to be attempted in a single burst. This also + * equals the number of FTM frames that the + * initiator will request that the responder send + * in a single frame. + */ + uint32_t numFramesPerBurst; + + /** + * Number of retries for a failed RTT frame. + * Applies to 1-sided RTT only. Minimum value = 0, Maximum value = 3 + */ + uint32_t numRetriesPerRttFrame; + + /** + * Following fields are only valid for 2-side RTT. + * + * + * Maximum number of retries that the initiator can + * retry an FTMR frame. + * Minimum value = 0, Maximum value = 3 + */ + uint32_t numRetriesPerFtmr; + + /** + * Whether to request location civic info or not. + */ + bool mustRequestLci; + + /** + * Whether to request location civic records or not. + */ + bool mustRequestLcr; + + /** + * Applies to 1-sided and 2-sided RTT. Valid values will + * be 2-11 and 15 as specified by the 802.11mc std for + * the FTM parameter burst duration. In a multi-burst + * request, if responder overrides with larger value, + * the initiator will return failure. In a single-burst + * request if responder overrides with larger value, + * the initiator will sent TMR_STOP to terminate RTT + * at the end of the burst_duration it requested. + */ + uint32_t burstDuration; + + /** + * RTT preamble to be used in the RTT frames. + */ + RttPreamble preamble; + + /** + * RTT BW to be used in the RTT frames. + */ + RttBw bw; +}; + +/** + * RTT Capabilities. + */ +struct RttCapabilities { + /** + * if 1-sided rtt data collection is supported. + */ + bool rttOneSidedSupported; + + /** + * if ftm rtt data collection is supported. + */ + bool rttFtmSupported; + + /** + * if initiator supports LCI request. Applies to 2-sided RTT. + */ + bool lciSupported; + + /** + * if initiator supports LCR request. Applies to 2-sided RTT. + */ + bool lcrSupported; + + /** + * if 11mc responder mode is supported. + */ + bool responderSupported; + + /** + * Bit mask indicates what preamble is supported by initiator. + * Combination of |RttPreamble| values. + */ + bitfield preambleSupport; + + /** + * Bit mask indicates what BW is supported by initiator. + * Combination of |RttBw| values. + */ + bitfield bwSupport; + + /** + * Draft 11mc spec version supported by chip. + * For instance, version 4.0 must be 40 and version 4.3 must be 43 etc. + */ + uint8_t mcVersion; +}; + +/** + * RTT Responder information + */ +struct RttResponder { + WifiChannelInfo channel; + + RttPreamble preamble; +}; + +/** + * Wifi rate info. + */ +struct WifiRateInfo { + /** + * Preamble used for RTT measurements. + */ + WifiRatePreamble preamble; + + /** + * Number of spatial streams. + */ + WifiRateNss nss; + + /** + * Bandwidth of channel. + */ + WifiChannelWidthInMhz bw; + + /** + * OFDM/CCK rate code would be as per ieee std in the units of 0.5mbps. + * HT/VHT/HE it would be mcs index. + */ + uint8_t rateMcsIdx; + + /** + * Bitrate in units of 100 Kbps. + */ + uint32_t bitRateInKbps; +}; + +/** + * RTT results. + */ +struct RttResult { + /** + * Peer device mac address. + */ + MacAddress addr; + + /** + * Burst number in a multi-burst request. + */ + uint32_t burstNum; + + /** + * Total RTT measurement frames attempted. + */ + uint32_t measurementNumber; + + /** + * Total successful RTT measurement frames. + */ + uint32_t successNumber; + + /** + * Maximum number of "FTM frames per burst" supported by + * the responder STA. Applies to 2-sided RTT only. + * If reponder overrides with larger value: + * - for single-burst request initiator will truncate the + * larger value and send a TMR_STOP after receiving as + * many frames as originally requested. + * - for multi-burst request, initiator will return + * failure right away. + */ + uint8_t numberPerBurstPeer; + + /** + * Ranging status. + */ + RttStatus status; + + /** + * When status == RTT_STATUS_FAIL_BUSY_TRY_LATER, + * this will be the time provided by the responder as to + * when the request can be tried again. Applies to 2-sided + * RTT only. In sec, 1-31sec. + */ + uint8_t retryAfterDuration; + + /** + * RTT type. + */ + RttType type; + + /** + * Average rssi in 0.5 dB steps e.g. 143 implies -71.5 dB. + */ + Rssi rssi; + + /** + * Rssi spread in 0.5 dB steps e.g. 5 implies 2.5 dB spread (optional). + */ + Rssi rssiSpread; + + /** + * 1-sided RTT: TX rate of RTT frame. + * 2-sided RTT: TX rate of initiator's Ack in response to FTM frame. + */ + WifiRateInfo txRate; + + /** + * 1-sided RTT: TX rate of Ack from other side. + * 2-sided RTT: TX rate of FTM frame coming from responder. + */ + WifiRateInfo rxRate; + + /** + * Round trip time in picoseconds + */ + TimeSpanInPs rtt; + + /** + * Rtt standard deviation in picoseconds. + */ + TimeSpanInPs rttSd; + + /** + * Difference between max and min rtt times recorded in picoseconds. + */ + TimeSpanInPs rttSpread; + + /** + * Distance in mm (optional). + */ + int32_t distanceInMm; + + /** + * Standard deviation in mm (optional). + */ + int32_t distanceSdInMm; + + /** + * Difference between max and min distance recorded in mm (optional). + */ + int32_t distanceSpreadInMm; + + /** + * Time of the measurement (in microseconds since boot). + */ + TimeStampInUs timeStampInUs; + + /** + * in ms, actual time taken by the FW to finish one burst + * measurement. Applies to 1-sided and 2-sided RTT. + */ + uint32_t burstDurationInMs; + + /** + * Number of bursts allowed by the responder. Applies + * to 2-sided RTT only. + */ + uint32_t negotiatedBurstNum; + + /** + * for 11mc only. + */ + WifiInformationElement lci; + + /** + * for 11mc only. + */ + WifiInformationElement lcr; +}; From a6a2af85d7c3255cb398dcf53189717955459bc1 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Wed, 6 Nov 2019 12:49:23 -0800 Subject: [PATCH 0225/1022] gralloc: clarify lock access region Update lock to clarify that if the access region is outside the bounds of the buffer, the lock call should fail. Bug: 141631415 Test: VtsHalGraphicsMapperV4_0TargetTest Change-Id: Ic9ccac9361c8cafc59660b107686d2cbb54faf2d --- graphics/mapper/4.0/IMapper.hal | 3 +- .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 43 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal index 85c7c81e85..46506f543f 100644 --- a/graphics/mapper/4.0/IMapper.hal +++ b/graphics/mapper/4.0/IMapper.hal @@ -219,7 +219,8 @@ interface IMapper { * - `BAD_BUFFER` if the buffer is invalid or is incompatible with this * function. * - `BAD_VALUE` if @p cpuUsage is 0, contains non-CPU usage flags, or - * is incompatible with the buffer. + * is incompatible with the buffer. Also if the @p accessRegion is + * outside the bounds of the buffer or the accessRegion is invalid. * - `NO_RESOURCES` if the buffer cannot be locked at this time. Note * that locking may succeed at a later time. * @return data CPU-accessible pointer to the buffer data. diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 706c658f69..ef7a626a8f 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -403,6 +403,49 @@ TEST_F(GraphicsMapperHidlTest, LockYCbCrBasic) { } } +/** + * Test IMapper::unlock with bad access region + */ +TEST_F(GraphicsMapperHidlTest, LockBadAccessRegion) { + const auto& info = mDummyDescriptorInfo; + + const native_handle_t* bufferHandle; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true)); + + const IMapper::Rect accessRegion{0, 0, static_cast(info.width * 2), + static_cast(info.height * 2)}; + int acquireFence = -1; + + NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0); + hidl_handle acquireFenceHandle; + if (acquireFence >= 0) { + auto h = native_handle_init(acquireFenceStorage, 1, 0); + h->data[0] = acquireFence; + acquireFenceHandle = h; + } + + auto buffer = const_cast(bufferHandle); + mGralloc->getMapper()->lock(buffer, info.usage, accessRegion, acquireFenceHandle, + [&](const auto& tmpError, const auto& /*tmpData*/, + int32_t /*tmpBytesPerPixel*/, int32_t /*tmpBytesPerStride*/) { + EXPECT_EQ(Error::BAD_VALUE, tmpError) + << "locking with a bad access region should fail"; + }); + + if (::testing::Test::HasFailure()) { + if (acquireFence >= 0) { + close(acquireFence); + } + + int releaseFence = -1; + ASSERT_NO_FATAL_FAILURE(releaseFence = mGralloc->unlock(bufferHandle)); + + if (releaseFence >= 0) { + close(releaseFence); + } + } +} + /** * Test IMapper::unlock with invalid buffers. */ From bf9f6d39edee1c2c3dab27354847a1da823c8e6f Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Tue, 5 Nov 2019 14:58:52 -0800 Subject: [PATCH 0226/1022] gralloc: name buffer at allocation time Allow the client to name their buffer at allocation time. b/141632767 will let the client(s) query the name of the buffer later. Bug: 144026910 Test: VtsHalGraphicsMapperV4_0TargetTest Change-Id: Ib08c1909c10a1778c50b59e0a42ddf19140d8f03 --- .../vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp | 7 +++++-- graphics/mapper/4.0/IMapper.hal | 5 +++++ graphics/mapper/4.0/types.hal | 2 +- .../vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp | 1 + 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 67d5bbe929..667aed4470 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -6224,9 +6224,10 @@ void CameraHidlTest::allocateGraphicBuffer(uint32_t width, uint32_t height, uint android::hardware::graphics::mapper::V3_0::IMapper::getService(); sp mapper = android::hardware::graphics::mapper::V2_0::IMapper::getService(); - ::android::hardware::hidl_vec descriptor; if (mapperV4 != nullptr && allocatorV4 != nullptr) { + ::android::hardware::hidl_vec descriptor; android::hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo descriptorInfo{}; + descriptorInfo.name = "VtsHalCameraProviderV2_4"; descriptorInfo.width = width; descriptorInfo.height = height; descriptorInfo.layerCount = 1; @@ -6236,7 +6237,7 @@ void CameraHidlTest::allocateGraphicBuffer(uint32_t width, uint32_t height, uint auto ret = mapperV4->createDescriptor( descriptorInfo, [&descriptor](android::hardware::graphics::mapper::V4_0::Error err, - ::android::hardware::hidl_vec desc) { + ::android::hardware::hidl_vec desc) { ASSERT_EQ(err, android::hardware::graphics::mapper::V4_0::Error::NONE); descriptor = desc; }); @@ -6253,6 +6254,7 @@ void CameraHidlTest::allocateGraphicBuffer(uint32_t width, uint32_t height, uint }); ASSERT_TRUE(ret.isOk()); } else if (mapperV3 != nullptr && allocatorV3 != nullptr) { + ::android::hardware::hidl_vec descriptor; android::hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo descriptorInfo {}; descriptorInfo.width = width; descriptorInfo.height = height; @@ -6278,6 +6280,7 @@ void CameraHidlTest::allocateGraphicBuffer(uint32_t width, uint32_t height, uint }); ASSERT_TRUE(ret.isOk()); } else { + ::android::hardware::hidl_vec descriptor; ASSERT_NE(mapper.get(), nullptr); ASSERT_NE(allocator.get(), nullptr); android::hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo descriptorInfo {}; diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal index 85c7c81e85..c8093497c5 100644 --- a/graphics/mapper/4.0/IMapper.hal +++ b/graphics/mapper/4.0/IMapper.hal @@ -22,6 +22,11 @@ import android.hardware.graphics.common@1.2::Rect; interface IMapper { struct BufferDescriptorInfo { + /** + * The name of the buffer. Useful for debugging/tracing. + */ + string name; + /** * The width specifies how many columns of pixels must be in the * allocated buffer, but does not necessarily represent the offset in diff --git a/graphics/mapper/4.0/types.hal b/graphics/mapper/4.0/types.hal index 603b243db6..2fdfa6586b 100644 --- a/graphics/mapper/4.0/types.hal +++ b/graphics/mapper/4.0/types.hal @@ -51,7 +51,7 @@ enum Error : int32_t { * createDescriptor(). It describes the properties of a buffer and is consumed * by the allocator. */ -typedef vec BufferDescriptor; +typedef vec BufferDescriptor; /** * Structure for describing YCbCr formats for consumption by applications. diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 706c658f69..6a4bd494dd 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -58,6 +58,7 @@ class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase { GraphicsMapperHidlEnvironment::Instance()->getServiceName(), GraphicsMapperHidlEnvironment::Instance()->getServiceName())); + mDummyDescriptorInfo.name = "dummy"; mDummyDescriptorInfo.width = 64; mDummyDescriptorInfo.height = 64; mDummyDescriptorInfo.layerCount = 1; From 5b8fc1298af57c08d271f80f07753fdd131a06da Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 1 Nov 2019 16:28:37 -0700 Subject: [PATCH 0227/1022] audio: Run VTS tests for streams of non-primary modules for HAL V6 Implement parsing of AudioPolicyManager config for finding out supported format configurations of streams. This only applies when running tests for HAL V6. Previously format configurations mandated by CDD were used for testing, this does not work well for non-primary modules. Fix the following issues found while running the tests for "r_submix" and "msd" modules: - IStream::getSupportedFormats must return a status to indicate that this capability is not supported by HAL; - it is allowed for IStream::setDevices to return NOT_SUPPORTED status. Other changes: - Factor out helper functions for generating format configurations; - Fix generation of the channel mask component in the names of tests that use AudioConfig, add sampling rate to test names. Bug: 141989952 Bug: 141847510 Test: atest VtsHalAudioV5_0TargetTest atest VtsHalAudioV6_0TargetTest also, run modified V5_0 test using generators for V6_0 Change-Id: If0d330881901908e546baab89f63d3333003e355 --- audio/6.0/IStream.hal | 4 +- audio/core/all-versions/default/Stream.cpp | 9 + .../4.0/AudioPrimaryHidlHalTest.cpp | 5 +- .../functional/4.0/AudioPrimaryHidlHalUtils.h | 9 +- .../6.0/AudioPrimaryHidlHalTest.cpp | 74 ++++++ .../vts/functional/AudioPrimaryHidlHalTest.h | 248 ++++++++++-------- .../vts/functional/ConfigHelper.h | 120 +++++++++ 7 files changed, 349 insertions(+), 120 deletions(-) create mode 100644 audio/core/all-versions/vts/functional/ConfigHelper.h diff --git a/audio/6.0/IStream.hal b/audio/6.0/IStream.hal index f4c91f826d..451e1162bf 100644 --- a/audio/6.0/IStream.hal +++ b/audio/6.0/IStream.hal @@ -123,9 +123,11 @@ interface IStream { * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_FORMATS on the legacy * HAL. * + * @return retval operation completion status. * @return formats supported audio formats. + * Must be non empty if retval is OK. */ - getSupportedFormats() generates (vec formats); + getSupportedFormats() generates (Result retval, vec formats); /** * Sets the audio format of the stream. Calling this method is equivalent to diff --git a/audio/core/all-versions/default/Stream.cpp b/audio/core/all-versions/default/Stream.cpp index 2a4ef6dc31..74e59450f0 100644 --- a/audio/core/all-versions/default/Stream.cpp +++ b/audio/core/all-versions/default/Stream.cpp @@ -175,8 +175,17 @@ Return Stream::getSupportedFormats(getSupportedFormats_cb _hidl_cb) { for (size_t i = 0; i < halFormats.size(); ++i) { formats[i] = AudioFormat(halFormats[i]); } + // Legacy get_parameter does not return a status_t, thus can not advertise of failure. + // Note that the method must not return an empty list if this capability is supported. + if (formats.size() == 0) { + result = Result::NOT_SUPPORTED; + } } +#if MAJOR_VERSION <= 5 _hidl_cb(formats); +#elif MAJOR_VERSION >= 6 + _hidl_cb(result, formats); +#endif return Void(); } diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp index cd93643b95..e267a5ea72 100644 --- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp @@ -172,9 +172,10 @@ static void testSetDevices(IStream* stream, const DeviceAddress& address) { DeviceAddress otherAddress = address; otherAddress.device = (address.device & AudioDevice::BIT_IN) == 0 ? AudioDevice::OUT_SPEAKER : AudioDevice::IN_BUILTIN_MIC; - EXPECT_OK(stream->setDevices({otherAddress})); + EXPECT_RESULT(okOrNotSupported, stream->setDevices({otherAddress})); - ASSERT_OK(stream->setDevices({address})); // Go back to the original value + ASSERT_RESULT(okOrNotSupported, + stream->setDevices({address})); // Go back to the original value } TEST_IO_STREAM(SetDevices, "Check that the stream can be rerouted to SPEAKER or BUILTIN_MIC", diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h index 8415053ffc..7a52d0e364 100644 --- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h +++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h @@ -75,11 +75,18 @@ struct GetSupported { return res; } +#if MAJOR_VERSION <= 5 static Result formats(IStream* stream, hidl_vec& capabilities) { EXPECT_OK(stream->getSupportedFormats(returnIn(capabilities))); - // TODO: this should be an optional function return Result::OK; } +#elif MAJOR_VERSION >= 6 + static Result formats(IStream* stream, hidl_vec& capabilities) { + Result res; + EXPECT_OK(stream->getSupportedFormats(returnIn(res, capabilities))); + return res; + } +#endif }; template diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp index 937de0a18d..c56445cc9e 100644 --- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp @@ -64,3 +64,77 @@ const std::vector& getDeviceParameters() { }(); return parameters; } + +const std::vector& getOutputDeviceConfigParameters() { + static std::vector parameters = [] { + std::vector result; + for (const auto& device : getDeviceParameters()) { + auto module = + getCachedPolicyConfig().getModuleFromName(std::get(device)); + for (const auto& ioProfile : module->getOutputProfiles()) { + for (const auto& profile : ioProfile->getAudioProfiles()) { + auto configs = ConfigHelper::combineAudioConfig(profile->getChannels(), + profile->getSampleRates(), + profile->getFormat()); + auto flags = ioProfile->getFlags(); + for (auto& config : configs) { + // Some combinations of flags declared in the config file require special + // treatment. + bool special = false; + if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { + config.offloadInfo.sampleRateHz = config.sampleRateHz; + config.offloadInfo.channelMask = config.channelMask; + config.offloadInfo.format = config.format; + config.offloadInfo.streamType = AudioStreamType::MUSIC; + config.offloadInfo.bitRatePerSecond = 320; + config.offloadInfo.durationMicroseconds = -1; + config.offloadInfo.bitWidth = 16; + config.offloadInfo.bufferSize = 256; // arbitrary value + config.offloadInfo.usage = AudioUsage::MEDIA; + result.emplace_back( + device, config, + AudioOutputFlag(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)); + special = true; + } + if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) && + !(flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC)) { + result.emplace_back(device, config, + AudioOutputFlag(AUDIO_OUTPUT_FLAG_DIRECT)); + special = true; + } + if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) { // ignore the flag + flags &= ~AUDIO_OUTPUT_FLAG_PRIMARY; + } + if (!special) { + result.emplace_back(device, config, AudioOutputFlag(flags)); + } + } + } + } + } + return result; + }(); + return parameters; +} + +const std::vector& getInputDeviceConfigParameters() { + static std::vector parameters = [] { + std::vector result; + for (const auto& device : getDeviceParameters()) { + auto module = + getCachedPolicyConfig().getModuleFromName(std::get(device)); + for (const auto& ioProfile : module->getInputProfiles()) { + for (const auto& profile : ioProfile->getAudioProfiles()) { + auto configs = ConfigHelper::combineAudioConfig(profile->getChannels(), + profile->getSampleRates(), + profile->getFormat()); + for (const auto& config : configs) { + result.emplace_back(device, config, AudioInputFlag(ioProfile->getFlags())); + } + } + } + } + return result; + }(); + return parameters; +} diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h index 7bdc5e1eb1..468f9b2da6 100644 --- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -97,7 +98,9 @@ using ::android::hardware::kSynchronizedReadWrite; using ::android::hardware::MessageQueue; using ::android::hardware::MQDescriptorSync; using ::android::hardware::Return; +using ::android::hardware::audio::common::utils::EnumBitfield; using ::android::hardware::audio::common::utils::mkEnumBitfield; +using ::android::hardware::details::toHexString; using namespace ::android::hardware::audio::common::CPP_VERSION; using namespace ::android::hardware::audio::common::test::utility; @@ -231,6 +234,9 @@ class PolicyConfig : private PolicyConfigData, public AudioPolicyConfig { } } const std::string& getFilePath() const { return mFilePath; } + sp getModuleFromName(const std::string& name) const { + return getHwModules().getModuleFromName(name.c_str()); + } sp getPrimaryModule() const { return mPrimaryModule; } const std::set& getModulesWithDevicesNames() const { return mModulesWithDevicesNames; @@ -550,91 +556,28 @@ TEST_P(AudioPatchHidlTest, AudioPatches) { INSTANTIATE_TEST_CASE_P(AudioPatchHidl, AudioPatchHidlTest, ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); -////////////////////////////////////////////////////////////////////////////// -//////////////// Required and recommended audio format support /////////////// -// From: -// https://source.android.com/compatibility/android-cdd.html#5_4_audio_recording -// From: -// https://source.android.com/compatibility/android-cdd.html#5_5_audio_playback -/////////// TODO: move to the beginning of the file for easier update //////// -////////////////////////////////////////////////////////////////////////////// - -struct ConfigHelper { - // for retro compatibility only test the primary device IN_BUILTIN_MIC - // FIXME: in the next audio HAL version, test all available devices - static bool primaryHasMic() { - auto& policyConfig = getCachedPolicyConfig(); - if (policyConfig.getStatus() != OK || policyConfig.getPrimaryModule() == nullptr) { - return true; // Could not get the information, run all tests - } - auto getMic = [](auto& devs) { return devs.getDevice( - AUDIO_DEVICE_IN_BUILTIN_MIC, {}, AUDIO_FORMAT_DEFAULT); }; - auto primaryMic = getMic(policyConfig.getPrimaryModule()->getDeclaredDevices()); - auto availableMic = getMic(policyConfig.getAvailableInputDevices()); - - return primaryMic != nullptr && primaryMic->equals(availableMic); - } - - // Cache result ? - static const vector getRequiredSupportPlaybackAudioConfig() { - return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO}, - {8000, 11025, 16000, 22050, 32000, 44100}, - {AudioFormat::PCM_16_BIT}); - } - - static const vector getRecommendedSupportPlaybackAudioConfig() { - return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO}, - {24000, 48000}, {AudioFormat::PCM_16_BIT}); - } - - static const vector getSupportedPlaybackAudioConfig() { - // TODO: retrieve audio config supported by the platform - // as declared in the policy configuration - return {}; - } - - static const vector getRequiredSupportCaptureAudioConfig() { - if (!primaryHasMic()) return {}; - return combineAudioConfig({AudioChannelMask::IN_MONO}, {8000, 11025, 16000, 44100}, - {AudioFormat::PCM_16_BIT}); - } - static const vector getRecommendedSupportCaptureAudioConfig() { - if (!primaryHasMic()) return {}; - return combineAudioConfig({AudioChannelMask::IN_STEREO}, {22050, 48000}, - {AudioFormat::PCM_16_BIT}); - } - static const vector getSupportedCaptureAudioConfig() { - // TODO: retrieve audio config supported by the platform - // as declared in the policy configuration - return {}; - } - - private: - static const vector combineAudioConfig(vector channelMasks, - vector sampleRates, - vector formats) { - vector configs; - for (auto channelMask : channelMasks) { - for (auto sampleRate : sampleRates) { - for (auto format : formats) { - AudioConfig config{}; - // leave offloadInfo to 0 - config.channelMask = mkEnumBitfield(channelMask); - config.sampleRateHz = sampleRate; - config.format = format; - // FIXME: leave frameCount to 0 ? - configs.push_back(config); - } - } - } - return configs; - } -}; - // Nesting a tuple in another tuple allows to use GTest Combine function to generate // all combinations of devices and configs. -enum { PARAM_DEVICE, PARAM_CONFIG }; -using DeviceConfigParameter = std::tuple; +enum { PARAM_DEVICE, PARAM_CONFIG, PARAM_FLAGS }; +enum { INDEX_INPUT, INDEX_OUTPUT }; +using DeviceConfigParameter = + std::tuple>; + +#if MAJOR_VERSION >= 6 +const std::vector& getInputDeviceConfigParameters(); +const std::vector& getOutputDeviceConfigParameters(); +#endif + +#if MAJOR_VERSION >= 4 +static string SanitizeStringForGTestName(const string& s) { + string result = s; + for (size_t i = 0; i < result.size(); i++) { + // gtest test names must only contain alphanumeric characters + if (!std::isalnum(result[i])) result[i] = '_'; + } + return result; +} +#endif /** Generate a test name based on an audio config. * @@ -652,7 +595,32 @@ static string DeviceConfigParameterToString( ((config.channelMask == mkEnumBitfield(AudioChannelMask::OUT_MONO) || config.channelMask == mkEnumBitfield(AudioChannelMask::IN_MONO)) ? "MONO" - : ::testing::PrintToString(config.channelMask)); +#if MAJOR_VERSION == 2 + : ::testing::PrintToString(config.channelMask) +#elif MAJOR_VERSION >= 4 + // In V4 and above the channel mask is a bitfield. + // Printing its value using HIDL's toString for a bitfield emits a lot of extra + // text due to overlapping constant values. Instead, we print the bitfield value + // as if it was a single value + its hex representation + : SanitizeStringForGTestName( + ::testing::PrintToString(AudioChannelMask(config.channelMask)) + "_" + + toHexString(config.channelMask)) +#endif + ) + + "_" + +#if MAJOR_VERSION == 2 + std::visit([](auto&& arg) -> std::string { return ::testing::PrintToString(arg); }, + std::get(info.param)); +#elif MAJOR_VERSION >= 4 + SanitizeStringForGTestName(std::visit( + [](auto&& arg) -> std::string { + using T = std::decay_t; + // Need to use FQN of toString to avoid confusing the compiler + return ::android::hardware::audio::common::CPP_VERSION::toString( + hidl_bitfield(arg)); + }, + std::get(info.param))); +#endif } class AudioHidlTestWithDeviceConfigParameter @@ -671,8 +639,27 @@ class AudioHidlTestWithDeviceConfigParameter return std::get(std::get(GetParam())); } const AudioConfig& getConfig() const { return std::get(GetParam()); } +#if MAJOR_VERSION == 2 + AudioInputFlag getInputFlags() const { + return std::get(std::get(GetParam())); + } + AudioOutputFlag getOutputFlags() const { + return std::get(std::get(GetParam())); + } +#elif MAJOR_VERSION >= 4 + hidl_bitfield getInputFlags() const { + return hidl_bitfield( + std::get(std::get(GetParam()))); + } + hidl_bitfield getOutputFlags() const { + return hidl_bitfield( + std::get(std::get(GetParam()))); + } +#endif }; +#include "ConfigHelper.h" + ////////////////////////////////////////////////////////////////////////////// ///////////////////////////// getInputBufferSize ///////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -681,7 +668,7 @@ class AudioHidlTestWithDeviceConfigParameter // android.hardware.microphone // how to get this value ? is it a property ??? -class AudioCaptureConfigPrimaryTest : public AudioHidlTestWithDeviceConfigParameter { +class AudioCaptureConfigTest : public AudioHidlTestWithDeviceConfigParameter { protected: void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) { uint64_t bufferSize; @@ -704,42 +691,51 @@ class AudioCaptureConfigPrimaryTest : public AudioHidlTestWithDeviceConfigParame // Test that the required capture config and those declared in the policy are // indeed supported -class RequiredInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {}; +class RequiredInputBufferSizeTest : public AudioCaptureConfigTest {}; TEST_P(RequiredInputBufferSizeTest, RequiredInputBufferSizeTest) { doc::test( "Input buffer size must be retrievable for a format with required " "support."); inputBufferSizeTest(getConfig(), true); } + +// Test that the recommended capture config are supported or lead to a +// INVALID_ARGUMENTS return +class OptionalInputBufferSizeTest : public AudioCaptureConfigTest {}; +TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) { + doc::test( + "Input buffer size should be retrievable for a format with recommended " + "support."); + inputBufferSizeTest(getConfig(), false); +} + +#if MAJOR_VERSION <= 5 +// For V2..5 test the primary device according to CDD requirements. INSTANTIATE_TEST_CASE_P( RequiredInputBufferSize, RequiredInputBufferSizeTest, - // FIXME: uses primaryHasMic ::testing::Combine( ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), - ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig()), + ::testing::Values(AudioInputFlag::NONE)), &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( SupportedInputBufferSize, RequiredInputBufferSizeTest, ::testing::Combine(::testing::ValuesIn(getDeviceParameters()), - ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig()), + ::testing::Values(AudioInputFlag::NONE)), &DeviceConfigParameterToString); - -// Test that the recommended capture config are supported or lead to a -// INVALID_ARGUMENTS return -class OptionalInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {}; -TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) { - doc::test( - "Input buffer size should be retrievable for a format with recommended " - "support."); - inputBufferSizeTest(getConfig(), false); -} INSTANTIATE_TEST_CASE_P( RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest, - // FIXME: uses primaryHasMic ::testing::Combine( ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), - ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig()), + ::testing::Values(AudioInputFlag::NONE)), &DeviceConfigParameterToString); +#elif MAJOR_VERSION >= 6 +INSTANTIATE_TEST_CASE_P(SupportedInputBufferSize, RequiredInputBufferSizeTest, + ::testing::ValuesIn(getInputDeviceConfigParameters()), + &DeviceConfigParameterToString); +#endif ////////////////////////////////////////////////////////////////////////////// /////////////////////////////// setScreenState /////////////////////////////// @@ -896,8 +892,7 @@ class OutputStreamTest : public OpenStreamTest { ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base address.device = AudioDevice::OUT_DEFAULT; const AudioConfig& config = getConfig(); - // TODO: test all flag combination - auto flags = mkEnumBitfield(AudioOutputFlag::NONE); + auto flags = getOutputFlags(); testOpen( [&](AudioIoHandle handle, AudioConfig config, auto cb) { #if MAJOR_VERSION == 2 @@ -924,25 +919,37 @@ TEST_P(OutputStreamTest, OpenOutputStreamTest) { "recommended config"); // Open done in SetUp } -// FIXME: Add instantiations for non-primary devices with configs harvested from the APM config file + +#if MAJOR_VERSION <= 5 +// For V2..5 test the primary device according to CDD requirements. INSTANTIATE_TEST_CASE_P( RequiredOutputStreamConfigSupport, OutputStreamTest, ::testing::Combine( ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), - ::testing::ValuesIn(ConfigHelper::getRequiredSupportPlaybackAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getRequiredSupportPlaybackAudioConfig()), + ::testing::Values(AudioOutputFlag::NONE)), &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( SupportedOutputStreamConfig, OutputStreamTest, ::testing::Combine(::testing::ValuesIn(getDeviceParameters()), - ::testing::ValuesIn(ConfigHelper::getSupportedPlaybackAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getSupportedPlaybackAudioConfig()), + ::testing::Values(AudioOutputFlag::NONE)), &DeviceConfigParameterToString); - INSTANTIATE_TEST_CASE_P( RecommendedOutputStreamConfigSupport, OutputStreamTest, ::testing::Combine( ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), - ::testing::ValuesIn(ConfigHelper::getRecommendedSupportPlaybackAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getRecommendedSupportPlaybackAudioConfig()), + ::testing::Values(AudioOutputFlag::NONE)), &DeviceConfigParameterToString); +#elif MAJOR_VERSION >= 6 +// For V6 and above test according to the audio policy manager configuration. +// This is more correct as CDD is written from the apps perspective. +// Audio system provides necessary format conversions for the missing configurations. +INSTANTIATE_TEST_CASE_P(DeclaredOutputStreamConfigSupport, OutputStreamTest, + ::testing::ValuesIn(getOutputDeviceConfigParameters()), + &DeviceConfigParameterToString); +#endif ////////////////////////////// openInputStream ////////////////////////////// @@ -951,8 +958,7 @@ class InputStreamTest : public OpenStreamTest { ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base address.device = AudioDevice::IN_DEFAULT; const AudioConfig& config = getConfig(); - // TODO: test all supported flags and source - auto flags = mkEnumBitfield(AudioInputFlag::NONE); + auto flags = getInputFlags(); testOpen( [&](AudioIoHandle handle, AudioConfig config, auto cb) { return getDevice()->openInputStream(handle, address, config, flags, @@ -975,26 +981,36 @@ TEST_P(InputStreamTest, OpenInputStreamTest) { "recommended config"); // Open done in setup } +#if MAJOR_VERSION <= 5 +// For V2..5 test the primary device according to CDD requirements. INSTANTIATE_TEST_CASE_P( RequiredInputStreamConfigSupport, InputStreamTest, - // FIXME: uses primaryHasMic ::testing::Combine( ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), - ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig()), + ::testing::Values(AudioInputFlag::NONE)), &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( SupportedInputStreamConfig, InputStreamTest, ::testing::Combine(::testing::ValuesIn(getDeviceParameters()), - ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig()), + ::testing::Values(AudioInputFlag::NONE)), &DeviceConfigParameterToString); - INSTANTIATE_TEST_CASE_P( RecommendedInputStreamConfigSupport, InputStreamTest, - // FIXME: uses primaryHasMic ::testing::Combine( ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), - ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig()), + ::testing::Values(AudioInputFlag::NONE)), &DeviceConfigParameterToString); +#elif MAJOR_VERSION >= 6 +// For V6 and above test according to the audio policy manager configuration. +// This is more correct as CDD is written from the apps perspective. +// Audio system provides necessary format conversions for the missing configurations. +INSTANTIATE_TEST_CASE_P(DeclaredInputStreamConfigSupport, InputStreamTest, + ::testing::ValuesIn(getInputDeviceConfigParameters()), + &DeviceConfigParameterToString); +#endif ////////////////////////////////////////////////////////////////////////////// ////////////////////////////// IStream getters /////////////////////////////// diff --git a/audio/core/all-versions/vts/functional/ConfigHelper.h b/audio/core/all-versions/vts/functional/ConfigHelper.h new file mode 100644 index 0000000000..604c0c50e6 --- /dev/null +++ b/audio/core/all-versions/vts/functional/ConfigHelper.h @@ -0,0 +1,120 @@ +/* + * 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. + */ + +// Code in this file uses 'getCachedPolicyConfig' +#ifndef AUDIO_PRIMARY_HIDL_HAL_TEST +#error Must be included from AudioPrimaryHidlTest.h +#endif + +////////////////////////////////////////////////////////////////////////////// +//////////////// Required and recommended audio format support /////////////// +// From: +// https://source.android.com/compatibility/android-cdd.html#5_4_audio_recording +// From: +// https://source.android.com/compatibility/android-cdd.html#5_5_audio_playback +/////////// TODO: move to the beginning of the file for easier update //////// +////////////////////////////////////////////////////////////////////////////// + +struct ConfigHelper { + // for retro compatibility only test the primary device IN_BUILTIN_MIC + // FIXME: in the next audio HAL version, test all available devices + static bool primaryHasMic() { + auto& policyConfig = getCachedPolicyConfig(); + if (policyConfig.getStatus() != OK || policyConfig.getPrimaryModule() == nullptr) { + return true; // Could not get the information, run all tests + } + auto getMic = [](auto& devs) { + return devs.getDevice(AUDIO_DEVICE_IN_BUILTIN_MIC, {}, AUDIO_FORMAT_DEFAULT); + }; + auto primaryMic = getMic(policyConfig.getPrimaryModule()->getDeclaredDevices()); + auto availableMic = getMic(policyConfig.getAvailableInputDevices()); + + return primaryMic != nullptr && primaryMic->equals(availableMic); + } + + // Cache result ? + static const vector getRequiredSupportPlaybackAudioConfig() { + return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO}, + {8000, 11025, 16000, 22050, 32000, 44100}, + {AudioFormat::PCM_16_BIT}); + } + + static const vector getRecommendedSupportPlaybackAudioConfig() { + return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO}, + {24000, 48000}, {AudioFormat::PCM_16_BIT}); + } + + static const vector getSupportedPlaybackAudioConfig() { + // TODO: retrieve audio config supported by the platform + // as declared in the policy configuration + return {}; + } + + static const vector getRequiredSupportCaptureAudioConfig() { + if (!primaryHasMic()) return {}; + return combineAudioConfig({AudioChannelMask::IN_MONO}, {8000, 11025, 16000, 44100}, + {AudioFormat::PCM_16_BIT}); + } + static const vector getRecommendedSupportCaptureAudioConfig() { + if (!primaryHasMic()) return {}; + return combineAudioConfig({AudioChannelMask::IN_STEREO}, {22050, 48000}, + {AudioFormat::PCM_16_BIT}); + } + static const vector getSupportedCaptureAudioConfig() { + // TODO: retrieve audio config supported by the platform + // as declared in the policy configuration + return {}; + } + + static vector combineAudioConfig(android::ChannelMaskSet channelMasks, + android::SampleRateSet sampleRates, + audio_format_t format) { + vector configs; + configs.reserve(channelMasks.size() * sampleRates.size()); + for (auto channelMask : channelMasks) { + for (auto sampleRate : sampleRates) { + AudioConfig config{}; + // leave offloadInfo to 0 + config.channelMask = EnumBitfield(channelMask); + config.sampleRateHz = sampleRate; + config.format = AudioFormat(format); + configs.push_back(config); + } + } + return configs; + } + + static vector combineAudioConfig(vector channelMasks, + vector sampleRates, + vector formats) { + vector configs; + configs.reserve(channelMasks.size() * sampleRates.size() * formats.size()); + for (auto channelMask : channelMasks) { + for (auto sampleRate : sampleRates) { + for (auto format : formats) { + AudioConfig config{}; + // leave offloadInfo to 0 + config.channelMask = mkEnumBitfield(channelMask); + config.sampleRateHz = sampleRate; + config.format = format; + // FIXME: leave frameCount to 0 ? + configs.push_back(config); + } + } + } + return configs; + } +}; From 0ce0f981a7706c18f2fb4e8004425fcc7dfd6219 Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Tue, 29 Oct 2019 13:01:25 -0700 Subject: [PATCH 0228/1022] Add cas@1.2 support Test: Manual bug: 141783130 Change-Id: I487aa47c13ad1a50831ddbcb3b9b25de9972e5b7 --- cas/1.2/types.hal | 4 ++++ compatibility_matrices/compatibility_matrix.current.xml | 2 +- current.txt | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cas/1.2/types.hal b/cas/1.2/types.hal index 40c06cf1c7..06199cda16 100644 --- a/cas/1.2/types.hal +++ b/cas/1.2/types.hal @@ -45,6 +45,10 @@ enum Status : @1.0::Status { * ERROR_CAS_BLACKOUT is used to report geographical blackout. */ ERROR_CAS_BLACKOUT, + /** + * ERROR_CAS_REBOOTING is used to report CAS is during rebooting. + */ + ERROR_CAS_REBOOTING, }; /** diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 8ffed4ba46..15359794df 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -123,7 +123,7 @@
    android.hardware.cas - 1.1 + 1.1-2 IMediaCasService default diff --git a/current.txt b/current.txt index e22db18e2f..b86c080e07 100644 --- a/current.txt +++ b/current.txt @@ -587,6 +587,10 @@ fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardwar # HALs released in Android R 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types +c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas +9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener +f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardware.cas@1.2::IMediaCasService +4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types From 68c3234ad343040d0992ac5b09cadac27a14f263 Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Wed, 23 Oct 2019 10:35:07 -0700 Subject: [PATCH 0229/1022] NN HAL: Upgrade IPreparedModelCallback::notify to 1.3. Bug: 143242728 Test: 1.3 VTS with sample driver Change-Id: I56bc7a2fb179a9576036ad0c2aae0e1f41ec4e2c --- current.txt | 4 +- neuralnetworks/1.3/Android.bp | 1 + neuralnetworks/1.3/IDevice.hal | 87 +++++++- neuralnetworks/1.3/IPreparedModelCallback.hal | 57 ++++++ neuralnetworks/1.3/vts/functional/Android.bp | 19 ++ .../1.3/vts/functional/Callbacks.cpp | 76 +++++++ .../functional/CompilationCachingTests.cpp | 8 +- .../vts/functional/GeneratedTestHarness.cpp | 4 +- .../1.3/vts/functional/ValidateModel.cpp | 4 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 4 +- .../1.3/vts/functional/VtsHalNeuralnetworks.h | 4 +- .../vts/functional/include/1.3/Callbacks.h | 185 ++++++++++++++++++ 12 files changed, 436 insertions(+), 17 deletions(-) create mode 100644 neuralnetworks/1.3/IPreparedModelCallback.hal create mode 100644 neuralnetworks/1.3/vts/functional/Callbacks.cpp create mode 100644 neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h diff --git a/current.txt b/current.txt index e22db18e2f..f9382b65b4 100644 --- a/current.txt +++ b/current.txt @@ -590,7 +590,8 @@ fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardwar ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types -34515afa2bb792d3c6d8495a5f5d907d179c8507ca5e55c10050d02ae1d516ef android.hardware.neuralnetworks@1.3::IDevice +9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice +fd5a2b723b75acbdd9f31bd07e0f83293c52f99f8d9b87bf58eeb6018f665fde android.hardware.neuralnetworks@1.3::IPreparedModelCallback b74fe72cfe438f50e772e6a307657ff449d5bde83c15dd1f140ff2edbe73499c android.hardware.neuralnetworks@1.3::types 544049dcda3f943ad67d83d5277f06681a3782982a9af5a78b5d4e8d295d061a android.hardware.vibrator@1.4::IVibrator 5e1c12efbbba89c9143d10b1b90eceff8bc79aa079f5106215b528e104fef101 android.hardware.vibrator@1.4::IVibratorCallback @@ -605,4 +606,3 @@ b0f8c9cd61a45a8c1b4a8e40913ecaea0921011cbe2305a6fa5a2feaa0d36c30 android.hardwar a8691c71747c3f14f7a043598e856425077f755e55990507a9132ad62f8ab3f7 android.hardware.radio@1.5::IRadio a62a93faf173b14a6175b683ebf61ffa568dc61f81e369d2dce7b1265e86cf2f android.hardware.radio@1.5::IRadioIndication 15daf260aaf6781b911450bc94e1a164901f9c0fe0bda68f8434f0a903f66e05 android.hardware.radio@1.5::IRadioResponse - diff --git a/neuralnetworks/1.3/Android.bp b/neuralnetworks/1.3/Android.bp index 0615ec67dd..8e3e9f11be 100644 --- a/neuralnetworks/1.3/Android.bp +++ b/neuralnetworks/1.3/Android.bp @@ -9,6 +9,7 @@ hidl_interface { srcs: [ "types.hal", "IDevice.hal", + "IPreparedModelCallback.hal", ], interfaces: [ "android.hardware.neuralnetworks@1.0", diff --git a/neuralnetworks/1.3/IDevice.hal b/neuralnetworks/1.3/IDevice.hal index ee36fb4e51..1295d6ac23 100644 --- a/neuralnetworks/1.3/IDevice.hal +++ b/neuralnetworks/1.3/IDevice.hal @@ -22,7 +22,7 @@ import @1.2::Constant; import @1.2::DeviceType; import @1.2::Extension; import @1.2::IDevice; -import @1.2::IPreparedModelCallback; +import IPreparedModelCallback; /** * This interface represents a device driver. @@ -134,18 +134,18 @@ interface IDevice extends @1.2::IDevice { * not provided, or match the numModelCache returned from * getNumberOfCacheFilesNeeded. The cache handles will be provided in * the same order when retrieving the preparedModel from cache files - * with prepareModelFromCache. + * with prepareModelFromCache_1_3. * @param dataCache A vector of handles with each entry holding exactly one * cache file descriptor for the constants' cache. The length of the * vector must either be 0 indicating that caching information is not * provided, or match the numDataCache returned from * getNumberOfCacheFilesNeeded. The cache handles will be provided in * the same order when retrieving the preparedModel from cache files - * with prepareModelFromCache. + * with prepareModelFromCache_1_3. * @param token A caching token of length Constant::BYTE_SIZE_OF_CACHE_TOKEN * identifying the prepared model. The same token will be provided when * retrieving the prepared model from the cache files with - * prepareModelFromCache. Tokens should be chosen to have a low rate of + * prepareModelFromCache_1_3. Tokens should be chosen to have a low rate of * collision for a particular application. The driver cannot detect a * collision; a collision will result in a failed execution or in a * successful execution that produces incorrect output values. If both @@ -168,4 +168,83 @@ interface IDevice extends @1.2::IDevice { uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token, IPreparedModelCallback callback) generates (ErrorStatus status); + + /** + * Creates a prepared model from cache files for execution. + * + * prepareModelFromCache_1_3 is used to retrieve a prepared model directly from + * cache files to avoid slow model compilation time. There are + * two types of cache file handles provided to the driver: model cache + * and data cache. For more information on the two types of cache handles, + * refer to getNumberOfCacheFilesNeeded. + * + * The file descriptors must be opened with read and write permission. A file may + * have any size, and the corresponding file descriptor may have any offset. The + * driver must truncate a file to zero size before writing to that file. The file + * descriptors may be closed by the client once the asynchronous preparation has + * finished. The driver must dup a file descriptor if it wants to get access to + * the cache file later. + * + * The model is prepared asynchronously with respect to the caller. The + * prepareModelFromCache_1_3 function must verify the inputs to the + * prepareModelFromCache_1_3 function are correct, and that the security-sensitive + * cache has not been modified since it was last written by the driver. + * If there is an error, or if compilation caching is not supported, or if the + * security-sensitive cache has been modified, prepareModelFromCache_1_3 must + * immediately invoke the callback with the appropriate ErrorStatus value and + * nullptr for the IPreparedModel, then return with the same ErrorStatus. If + * the inputs to the prepareModelFromCache_1_3 function are valid, the security-sensitive + * cache is not modified, and there is no error, prepareModelFromCache_1_3 must launch an + * asynchronous task to prepare the model in the background, and immediately return + * from prepareModelFromCache_1_3 with ErrorStatus::NONE. If the asynchronous task + * fails to launch, prepareModelFromCache_1_3 must immediately invoke the callback + * with ErrorStatus::GENERAL_FAILURE and nullptr for the IPreparedModel, then + * return with ErrorStatus::GENERAL_FAILURE. + * + * When the asynchronous task has finished preparing the model, it must + * immediately invoke the callback function provided as an input to + * prepareModelFromCache_1_3. If the model was prepared successfully, the + * callback object must be invoked with an error status of ErrorStatus::NONE + * and the produced IPreparedModel object. If an error occurred preparing + * the model, the callback object must be invoked with the appropriate + * ErrorStatus value and nullptr for the IPreparedModel. + * + * The only information that may be unknown to the model at this stage is + * the shape of the tensors, which may only be known at execution time. As + * such, some driver services may return partially prepared models, where + * the prepared model may only be finished when it is paired with a set of + * inputs to the model. Note that the same prepared model object may be + * used with different shapes of inputs on different (possibly concurrent) + * executions. + * + * @param modelCache A vector of handles with each entry holding exactly one + * cache file descriptor for the security-sensitive cache. The length of + * the vector must match the numModelCache returned from getNumberOfCacheFilesNeeded. + * The cache handles will be provided in the same order as with prepareModel_1_3. + * @param dataCache A vector of handles with each entry holding exactly one + * cache file descriptor for the constants' cache. The length of the vector + * must match the numDataCache returned from getNumberOfCacheFilesNeeded. + * The cache handles will be provided in the same order as with prepareModel_1_3. + * @param token A caching token of length Constant::BYTE_SIZE_OF_CACHE_TOKEN + * identifying the prepared model. It is the same token provided when saving + * the cache files with prepareModel_1_3. Tokens should be chosen + * to have a low rate of collision for a particular application. The driver + * cannot detect a collision; a collision will result in a failed execution + * or in a successful execution that produces incorrect output values. + * @param callback A callback object used to return the error status of + * preparing the model for execution and the prepared model if + * successful, nullptr otherwise. The callback object's notify function + * must be called exactly once, even if the model could not be prepared. + * @return status Error status of launching a task which prepares the model + * in the background; must be: + * - NONE if preparation task is successfully launched + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if caching is not supported or if there is an + * unspecified error + * - INVALID_ARGUMENT if one of the input arguments is invalid + */ + prepareModelFromCache_1_3(vec modelCache, vec dataCache, + uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token, + IPreparedModelCallback callback) + generates (ErrorStatus status); }; diff --git a/neuralnetworks/1.3/IPreparedModelCallback.hal b/neuralnetworks/1.3/IPreparedModelCallback.hal new file mode 100644 index 0000000000..7cc5ae0da4 --- /dev/null +++ b/neuralnetworks/1.3/IPreparedModelCallback.hal @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package android.hardware.neuralnetworks@1.3; + +import @1.0::ErrorStatus; +import @1.2::IPreparedModelCallback; +import @1.2::IPreparedModel; + +/** + * IPreparedModelCallback must be used to return a prepared model produced by an + * asynchronous task launched from IDevice::prepareModel. + */ +interface IPreparedModelCallback extends @1.2::IPreparedModelCallback { + + /** + * There are three notify methods declared for the IPreparedModelCallback + * interface: notify_1_3, notify_1_2, and notify. One of the three + * notify methods must be invoked immediately after the asynchronous + * task holding this callback has finished preparing the model. If the model was + * successfully prepared, one of the notify methods must be invoked with + * ErrorStatus::NONE and the prepared model. If the model was not able to be + * successfully prepared, one of the notify methods must be invoked with the + * appropriate ErrorStatus and nullptr as the IPreparedModel. If the asynchronous + * task holding this callback fails to launch or if the model provided to + * IDevice::prepareModel is invalid, one of the notify methods must be invoked + * with the appropriate error as well as nullptr for the IPreparedModel. + * + * @param status Error status returned from the asynchronous model + * preparation task; must be: + * - NONE if the asynchronous task successfully prepared the + * model + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the asynchronous task resulted in an + * unspecified error + * - INVALID_ARGUMENT if one of the input arguments to + * prepareModel is invalid + * @param preparedModel A model that has been asynchronously prepared for + * execution. If the model was unable to be prepared + * due to an error, nullptr must be passed in place of + * the IPreparedModel object. + */ + oneway notify_1_3(ErrorStatus status, IPreparedModel preparedModel); +}; diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp index 0f2720e7ef..e2795de420 100644 --- a/neuralnetworks/1.3/vts/functional/Android.bp +++ b/neuralnetworks/1.3/vts/functional/Android.bp @@ -14,6 +14,24 @@ // limitations under the License. // +cc_library_static { + name: "VtsHalNeuralNetworksV1_3Callbacks", + defaults: ["VtsHalTargetTestDefaults"], + export_include_dirs: ["include"], + srcs: [ + "Callbacks.cpp", + ], + static_libs: [ + "android.hardware.neuralnetworks@1.0", + "android.hardware.neuralnetworks@1.1", + "android.hardware.neuralnetworks@1.2", + "android.hardware.neuralnetworks@1.3", + ], + header_libs: [ + "libbase_headers", + ] +} + cc_test { name: "VtsHalNeuralnetworksV1_3TargetTest", defaults: ["VtsHalTargetTestDefaults"], @@ -44,6 +62,7 @@ cc_test { "libneuralnetworks_utils", "VtsHalNeuralNetworksV1_0_utils", "VtsHalNeuralNetworksV1_2Callbacks", + "VtsHalNeuralNetworksV1_3Callbacks", ], whole_static_libs: [ "neuralnetworks_generated_V1_0_example", diff --git a/neuralnetworks/1.3/vts/functional/Callbacks.cpp b/neuralnetworks/1.3/vts/functional/Callbacks.cpp new file mode 100644 index 0000000000..435db46271 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/Callbacks.cpp @@ -0,0 +1,76 @@ +/* + * 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 "Callbacks" + +#include "1.3/Callbacks.h" + +#include + +#include + +namespace android::hardware::neuralnetworks::V1_3::implementation { + +using V1_0::ErrorStatus; + +// PreparedModelCallback methods begin here + +Return PreparedModelCallback::notify(ErrorStatus errorStatus, + const sp& preparedModel) { + { + std::lock_guard hold(mMutex); + + // quick-return if object has already been notified + if (mNotified) { + return Void(); + } + + // store results and mark as notified + mErrorStatus = errorStatus; + mPreparedModel = preparedModel; + mNotified = true; + } + + mCondition.notify_all(); + return Void(); +} + +Return PreparedModelCallback::notify_1_2(ErrorStatus errorStatus, + const sp& preparedModel) { + return notify(errorStatus, preparedModel); +} + +Return PreparedModelCallback::notify_1_3(ErrorStatus errorStatus, + const sp& preparedModel) { + return notify(errorStatus, preparedModel); +} + +void PreparedModelCallback::wait() const { + std::unique_lock lock(mMutex); + mCondition.wait(lock, [this] { return mNotified; }); +} + +ErrorStatus PreparedModelCallback::getStatus() const { + wait(); + return mErrorStatus; +} + +sp PreparedModelCallback::getPreparedModel() const { + wait(); + return mPreparedModel; +} + +} // namespace android::hardware::neuralnetworks::V1_3::implementation diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp index 0ac4738fff..ea2398bf2d 100644 --- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp @@ -28,7 +28,7 @@ #include #include -#include "1.2/Callbacks.h" +#include "1.3/Callbacks.h" #include "GeneratedTestHarness.h" #include "MemoryUtils.h" #include "TestHarness.h" @@ -48,12 +48,12 @@ const test_helper::TestModel& get_test_model(); namespace android::hardware::neuralnetworks::V1_3::vts::functional { using namespace test_helper; +using implementation::PreparedModelCallback; using V1_0::ErrorStatus; using V1_1::ExecutionPreference; using V1_2::Constant; using V1_2::IPreparedModel; using V1_2::OperationType; -using V1_2::implementation::PreparedModelCallback; namespace float32_model { @@ -231,7 +231,7 @@ class CompilationCachingTestBase : public testing::Test { ASSERT_NE(kDevice.get(), nullptr); // Create cache directory. The cache directory and a temporary cache file is always created - // to test the behavior of prepareModelFromCache, even when caching is not supported. + // to test the behavior of prepareModelFromCache_1_3, even when caching is not supported. char cacheDirTemp[] = "/data/local/tmp/TestCompilationCachingXXXXXX"; char* cacheDir = mkdtemp(cacheDirTemp); ASSERT_NE(cacheDir, nullptr); @@ -370,7 +370,7 @@ class CompilationCachingTestBase : public testing::Test { // Launch prepare model from cache. sp preparedModelCallback = new PreparedModelCallback(); hidl_array cacheToken(mToken); - Return prepareLaunchStatus = kDevice->prepareModelFromCache( + Return prepareLaunchStatus = kDevice->prepareModelFromCache_1_3( modelCache, dataCache, cacheToken, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); if (static_cast(prepareLaunchStatus) != ErrorStatus::NONE) { diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 8a7ed24c9d..4f9b6f9c15 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #include "1.0/Utils.h" #include "1.2/Callbacks.h" +#include "1.3/Callbacks.h" #include "ExecutionBurstController.h" #include "MemoryUtils.h" #include "TestHarness.h" @@ -52,6 +54,7 @@ namespace android::hardware::neuralnetworks::V1_3::vts::functional { using namespace test_helper; using hidl::memory::V1_0::IMemory; +using implementation::PreparedModelCallback; using V1_0::DataLocation; using V1_0::ErrorStatus; using V1_0::OperandLifeTime; @@ -65,7 +68,6 @@ using V1_2::OutputShape; using V1_2::SymmPerChannelQuantParams; using V1_2::Timing; using V1_2::implementation::ExecutionCallback; -using V1_2::implementation::PreparedModelCallback; using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 44b32a9fec..bdda7904e9 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -17,12 +17,13 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" #include "1.0/Utils.h" -#include "1.2/Callbacks.h" +#include "1.3/Callbacks.h" #include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" namespace android::hardware::neuralnetworks::V1_3::vts::functional { +using implementation::PreparedModelCallback; using V1_0::ErrorStatus; using V1_0::OperandLifeTime; using V1_1::ExecutionPreference; @@ -30,7 +31,6 @@ using V1_2::IPreparedModel; using V1_2::OperationType; using V1_2::OperationTypeRange; using V1_2::SymmPerChannelQuantParams; -using V1_2::implementation::PreparedModelCallback; using HidlToken = hidl_array(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index 4f0e150b32..da5d95b8bf 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -21,8 +21,8 @@ #include #include #include -#include "1.0/Callbacks.h" #include "1.0/Utils.h" +#include "1.3/Callbacks.h" #include "GeneratedTestHarness.h" #include "TestHarness.h" @@ -30,11 +30,11 @@ namespace android::hardware::neuralnetworks::V1_3::vts::functional { using HidlToken = hidl_array(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; +using implementation::PreparedModelCallback; using V1_0::ErrorStatus; using V1_0::Request; using V1_1::ExecutionPreference; using V1_2::IPreparedModel; -using V1_2::implementation::PreparedModelCallback; // internal helper function void createPreparedModel(const sp& device, const Model& model, diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h index fc654ce8f0..9ccc911625 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h @@ -22,7 +22,7 @@ #include #include #include "1.0/Utils.h" -#include "1.2/Callbacks.h" +#include "1.3/Callbacks.h" namespace android::hardware::neuralnetworks::V1_3::vts::functional { @@ -51,7 +51,7 @@ void createPreparedModel(const sp& device, const Model& model, // Utility function to get PreparedModel from callback and downcast to V1_2. sp getPreparedModel_1_2( - const sp& callback); + const sp& callback); } // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h b/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h new file mode 100644 index 0000000000..9376a92b87 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h @@ -0,0 +1,185 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_3_CALLBACKS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_3_CALLBACKS_H + +#include +#include +#include +#include +#include +#include +#include + +/* + * The Callback classes are used internally by the NeuralNetworks runtime to + * synchronize between different threads. An asynchronous task is launched + * paired with a callback object. When a client thread requires the output being + * generated by the asynchronous task, the client thread can wait for the result + * and be blocked until it has completed. Any wait may safely be called + * concurrently, even on the same callback object. When the asynchronous task + * has finished its workload, it must immediately call "notify*". If the + * asynchronous task has failed to launch, the function that tried to launch the + * asynchronous task must immediately call "notify*". This "notify*" call + * awakens any client threads waiting on the callback object. + * + * These classes exist to enable synchronization across HIDL. When + * synchronization is only required in the same process, consider using + * std::future, std::mutex, std::condition_variable, or std::experimental::latch + * instead. + */ + +namespace android::hardware::neuralnetworks::V1_3::implementation { + +/** + * The PreparedModelCallback class is used to receive the error status of + * preparing a model as well as the prepared model from a task executing + * asynchronously with respect to the runtime. If a calling thread calls wait + * or get* on a PreparedModelCallback object and the corresponding asynchronous + * task has not finished preparing the model, the calling thread will block + * until the asynchronous task has called notify*. + * + * If the callback object is notified more than once, only the results of the + * first call to notify* are used, and the results from subsequent calls are + * discarded. + * + * This callback object is passed as an argument to IDevice::prepareModel*. + */ +class PreparedModelCallback : public IPreparedModelCallback { + public: + /** + * IPreparedModelCallback::notify marks the callback object with the return + * status of the asynchronous model preparation along with the prepared + * model, and allows all prior and future wait calls on the + * PreparedModelCallback object to proceed. + * + * One of IPreparedModelCallback::notify, IPreparedModelCallback::notify_1_2, + * or IPreparedModelCallback::notify_1_3 must be called on a given + * PreparedModelCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + * @param preparedModel Returned model that has been prepared for execution, + * nullptr if the model was unable to be prepared. + */ + Return notify(V1_0::ErrorStatus status, + const sp& preparedModel) override; + + /** + * IPreparedModelCallback::notify_1_2 marks the callback object with the + * return status of the asynchronous model preparation along with the + * prepared model, and allows all prior and future wait calls on the + * PreparedModelCallback object to proceed. + * + * One of IPreparedModelCallback::notify, IPreparedModelCallback::notify_1_2, + * or IPreparedModelCallback::notify_1_3 must be called on a given + * PreparedModelCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + * @param preparedModel Returned model that has been prepared for execution, + * nullptr if the model was unable to be prepared. + */ + Return notify_1_2(V1_0::ErrorStatus status, + const sp& preparedModel) override; + + /** + * IPreparedModelCallback::notify_1_3 marks the callback object with the + * return status of the asynchronous model preparation along with the + * prepared model, and allows all prior and future wait calls on the + * PreparedModelCallback object to proceed. + * + * One of IPreparedModelCallback::notify, IPreparedModelCallback::notify_1_2, + * or IPreparedModelCallback::notify_1_3 must be called on a given + * PreparedModelCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + * @param preparedModel Returned model that has been prepared for execution, + * nullptr if the model was unable to be prepared. + */ + Return notify_1_3(V1_0::ErrorStatus status, + const sp& preparedModel) override; + + /** + * PreparedModelCallback::wait blocks until notify* has been called on the + * callback object. + */ + void wait() const; + + /** + * Retrieves the error status returned from the asynchronous task launched + * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished + * asynchronously preparing the model, this call will block until the + * asynchronous task notifies the object. + * + * @return status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + */ + V1_0::ErrorStatus getStatus() const; + + /** + * Retrieves the model that has been prepared for execution from the + * asynchronous task launched by IDevice::prepareModel*. If + * IDevice::prepareModel* has not finished asynchronously preparing the + * model, this call will block until the asynchronous task notifies the + * object. + * + * @return preparedModel Returned model that has been prepared for + * execution, nullptr if the model was unable to be prepared. + */ + sp getPreparedModel() const; + + private: + mutable std::mutex mMutex; + mutable std::condition_variable mCondition; + bool mNotified GUARDED_BY(mMutex) = false; + V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; + sp mPreparedModel; +}; + +} // namespace android::hardware::neuralnetworks::V1_3::implementation + +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_CALLBACKS_H From 62a760c32d61e4630f02e9b61350f445cc56fbd6 Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Fri, 25 Oct 2019 12:07:17 -0700 Subject: [PATCH 0230/1022] NN HAL: Upgrade IPreparedModel::execute to 1.3. Bug: 143242728 Test: 1.3 VTS with sample driver Change-Id: I9ca1e28ddc97fe880a72885afe7afb6c93903697 --- current.txt | 3 +- neuralnetworks/1.3/Android.bp | 1 + neuralnetworks/1.3/IPreparedModel.hal | 90 +++++++++++++++++++ neuralnetworks/1.3/IPreparedModelCallback.hal | 2 +- .../1.3/vts/functional/Callbacks.cpp | 2 +- .../functional/CompilationCachingTests.cpp | 1 - .../vts/functional/GeneratedTestHarness.cpp | 4 +- .../1.3/vts/functional/GeneratedTestHarness.h | 7 +- .../1.3/vts/functional/ValidateBurst.cpp | 1 - .../1.3/vts/functional/ValidateModel.cpp | 3 +- .../1.3/vts/functional/ValidateRequest.cpp | 5 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 5 +- .../1.3/vts/functional/VtsHalNeuralnetworks.h | 7 +- .../vts/functional/include/1.3/Callbacks.h | 2 +- 14 files changed, 109 insertions(+), 24 deletions(-) create mode 100644 neuralnetworks/1.3/IPreparedModel.hal diff --git a/current.txt b/current.txt index f9382b65b4..3b236a50b1 100644 --- a/current.txt +++ b/current.txt @@ -591,7 +591,8 @@ ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardwar 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice -fd5a2b723b75acbdd9f31bd07e0f83293c52f99f8d9b87bf58eeb6018f665fde android.hardware.neuralnetworks@1.3::IPreparedModelCallback +4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel +94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback b74fe72cfe438f50e772e6a307657ff449d5bde83c15dd1f140ff2edbe73499c android.hardware.neuralnetworks@1.3::types 544049dcda3f943ad67d83d5277f06681a3782982a9af5a78b5d4e8d295d061a android.hardware.vibrator@1.4::IVibrator 5e1c12efbbba89c9143d10b1b90eceff8bc79aa079f5106215b528e104fef101 android.hardware.vibrator@1.4::IVibratorCallback diff --git a/neuralnetworks/1.3/Android.bp b/neuralnetworks/1.3/Android.bp index 8e3e9f11be..0b07a5806a 100644 --- a/neuralnetworks/1.3/Android.bp +++ b/neuralnetworks/1.3/Android.bp @@ -9,6 +9,7 @@ hidl_interface { srcs: [ "types.hal", "IDevice.hal", + "IPreparedModel.hal", "IPreparedModelCallback.hal", ], interfaces: [ diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal new file mode 100644 index 0000000000..c04809fea1 --- /dev/null +++ b/neuralnetworks/1.3/IPreparedModel.hal @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package android.hardware.neuralnetworks@1.3; + +import @1.0::ErrorStatus; +import @1.0::Request; +import @1.2::MeasureTiming; +import @1.2::IExecutionCallback; +import @1.2::IPreparedModel; + +/** + * IPreparedModel describes a model that has been prepared for execution and + * is used to launch executions. + */ +interface IPreparedModel extends @1.2::IPreparedModel { + /** + * Launches an asynchronous execution on a prepared model. + * + * The execution is performed asynchronously with respect to the caller. + * execute_1_3 must verify the inputs to the function are correct. If there is + * an error, execute_1_3 must immediately invoke the callback with the + * appropriate ErrorStatus value, then return with the same ErrorStatus. If + * the inputs to the function are valid and there is no error, execute_1_3 must + * launch an asynchronous task to perform the execution in the background, + * and immediately return with ErrorStatus::NONE. If the asynchronous task + * fails to launch, execute_1_3 must immediately invoke the callback with + * ErrorStatus::GENERAL_FAILURE, then return with + * ErrorStatus::GENERAL_FAILURE. + * + * When the asynchronous task has finished its execution, it must + * immediately invoke the callback object provided as an input to the + * execute_1_3 function. This callback must be provided with the ErrorStatus of + * the execution. + * + * If the launch is successful, the caller must not change the content of + * any data object referenced by 'request' (described by the + * {@link @1.0::DataLocation} of a {@link @1.0::RequestArgument}) until the + * asynchronous task has invoked the callback object. The asynchronous task + * must not change the content of any of the data objects corresponding to + * 'request' inputs. + * + * If the prepared model was prepared from a model wherein all tensor + * operands have fully specified dimensions, and the inputs to the function + * are valid, then: + * - the execution should launch successfully (ErrorStatus::NONE): There + * must be no failure unless the device itself is in a bad state. + * - if at execution time every operation's input operands have legal + * values, the execution should complete successfully (ErrorStatus::NONE): + * There must be no failure unless the device itself is in a bad state. + * + * Any number of calls to the execute, execute_1_2, execute_1_3, and executeSynchronously + * functions, in any combination, may be made concurrently, even on the same + * IPreparedModel object. + * + * @param request The input and output information on which the prepared + * model is to be executed. + * @param measure Specifies whether or not to measure duration of the execution. + * The duration runs from the time the driver sees the call + * to the execute_1_3 function to the time the driver invokes + * the callback. + * @param callback A callback object used to return the error status of + * the execution. The callback object's notify function must + * be called exactly once, even if the execution was + * unsuccessful. + * @return status Error status of the call, must be: + * - NONE if task is successfully launched + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is + * not large enough to store the resultant values + * - INVALID_ARGUMENT if one of the input arguments is + * invalid + */ + execute_1_3(Request request, MeasureTiming measure, IExecutionCallback callback) + generates (ErrorStatus status); +}; diff --git a/neuralnetworks/1.3/IPreparedModelCallback.hal b/neuralnetworks/1.3/IPreparedModelCallback.hal index 7cc5ae0da4..ff295a230e 100644 --- a/neuralnetworks/1.3/IPreparedModelCallback.hal +++ b/neuralnetworks/1.3/IPreparedModelCallback.hal @@ -18,7 +18,7 @@ package android.hardware.neuralnetworks@1.3; import @1.0::ErrorStatus; import @1.2::IPreparedModelCallback; -import @1.2::IPreparedModel; +import IPreparedModel; /** * IPreparedModelCallback must be used to return a prepared model produced by an diff --git a/neuralnetworks/1.3/vts/functional/Callbacks.cpp b/neuralnetworks/1.3/vts/functional/Callbacks.cpp index 435db46271..4f08e72a86 100644 --- a/neuralnetworks/1.3/vts/functional/Callbacks.cpp +++ b/neuralnetworks/1.3/vts/functional/Callbacks.cpp @@ -54,7 +54,7 @@ Return PreparedModelCallback::notify_1_2(ErrorStatus errorStatus, } Return PreparedModelCallback::notify_1_3(ErrorStatus errorStatus, - const sp& preparedModel) { + const sp& preparedModel) { return notify(errorStatus, preparedModel); } diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp index ea2398bf2d..d8a7534461 100644 --- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp @@ -52,7 +52,6 @@ using implementation::PreparedModelCallback; using V1_0::ErrorStatus; using V1_1::ExecutionPreference; using V1_2::Constant; -using V1_2::IPreparedModel; using V1_2::OperationType; namespace float32_model { diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 4f9b6f9c15..325d641744 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -61,7 +62,6 @@ using V1_0::OperandLifeTime; using V1_0::Request; using V1_1::ExecutionPreference; using V1_2::Constant; -using V1_2::IPreparedModel; using V1_2::MeasureTiming; using V1_2::OperationType; using V1_2::OutputShape; @@ -181,7 +181,7 @@ static void makeOutputDimensionsUnspecified(Model* model) { static Return ExecutePreparedModel(const sp& preparedModel, const Request& request, MeasureTiming measure, sp& callback) { - return preparedModel->execute_1_2(request, measure, callback); + return preparedModel->execute_1_3(request, measure, callback); } static Return ExecutePreparedModel(const sp& preparedModel, const Request& request, MeasureTiming measure, diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h index b9277cfd4a..45cff5b75b 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h @@ -17,8 +17,8 @@ #ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H #define ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H -#include #include +#include #include #include #include @@ -55,10 +55,9 @@ class ValidationTest : public GeneratedTestBase {}; Model createModel(const test_helper::TestModel& testModel); -void PrepareModel(const sp& device, const Model& model, - sp* preparedModel); +void PrepareModel(const sp& device, const Model& model, sp* preparedModel); -void EvaluatePreparedModel(const sp& preparedModel, +void EvaluatePreparedModel(const sp& preparedModel, const test_helper::TestModel& testModel, bool testDynamicOutputShape); } // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp index 2c97294fad..7df804645a 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp @@ -40,7 +40,6 @@ using V1_2::FmqRequestDatum; using V1_2::FmqResultDatum; using V1_2::IBurstCallback; using V1_2::IBurstContext; -using V1_2::IPreparedModel; using V1_2::MeasureTiming; using V1_2::Timing; using ExecutionBurstCallback = ExecutionBurstController::ExecutionBurstCallback; diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index bdda7904e9..1ff02dc198 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -27,7 +27,6 @@ using implementation::PreparedModelCallback; using V1_0::ErrorStatus; using V1_0::OperandLifeTime; using V1_1::ExecutionPreference; -using V1_2::IPreparedModel; using V1_2::OperationType; using V1_2::OperationTypeRange; using V1_2::SymmPerChannelQuantParams; @@ -61,7 +60,7 @@ static void validatePrepareModel(const sp& device, const std::string& m preparedModelCallback->wait(); ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus); - sp preparedModel = getPreparedModel_1_2(preparedModelCallback); + sp preparedModel = getPreparedModel_1_3(preparedModelCallback); ASSERT_EQ(nullptr, preparedModel.get()); } diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index c00512c4d3..2cf30d54bc 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -29,7 +29,6 @@ namespace android::hardware::neuralnetworks::V1_3::vts::functional { using V1_0::ErrorStatus; using V1_0::Request; -using V1_2::IPreparedModel; using V1_2::MeasureTiming; using V1_2::OutputShape; using V1_2::Timing; @@ -61,11 +60,11 @@ static void validate(const sp& preparedModel, const std::string& // asynchronous { - SCOPED_TRACE(message + " [execute_1_2]"); + SCOPED_TRACE(message + " [execute_1_3]"); sp executionCallback = new ExecutionCallback(); Return executeLaunchStatus = - preparedModel->execute_1_2(request, measure, executionCallback); + preparedModel->execute_1_3(request, measure, executionCallback); ASSERT_TRUE(executeLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(executeLaunchStatus)); diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index da5d95b8bf..625913d485 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -34,7 +34,6 @@ using implementation::PreparedModelCallback; using V1_0::ErrorStatus; using V1_0::Request; using V1_1::ExecutionPreference; -using V1_2::IPreparedModel; // internal helper function void createPreparedModel(const sp& device, const Model& model, @@ -64,7 +63,7 @@ void createPreparedModel(const sp& device, const Model& model, // retrieve prepared model preparedModelCallback->wait(); const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); - *preparedModel = getPreparedModel_1_2(preparedModelCallback); + *preparedModel = getPreparedModel_1_3(preparedModelCallback); // The getSupportedOperations_1_3 call returns a list of operations that are // guaranteed not to fail if prepareModel_1_3 is called, and @@ -165,7 +164,7 @@ TEST_P(ValidationTest, Test) { INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); -sp getPreparedModel_1_2(const sp& callback) { +sp getPreparedModel_1_3(const sp& callback) { sp preparedModelV1_0 = callback->getPreparedModel(); return IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr); } diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h index 9ccc911625..8cb42d47e5 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h @@ -17,8 +17,8 @@ #ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H #define ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H -#include #include +#include #include #include #include "1.0/Utils.h" @@ -47,11 +47,10 @@ std::string printNeuralnetworksHidlTest( // Create an IPreparedModel object. If the model cannot be prepared, // "preparedModel" will be nullptr instead. void createPreparedModel(const sp& device, const Model& model, - sp* preparedModel); + sp* preparedModel); // Utility function to get PreparedModel from callback and downcast to V1_2. -sp getPreparedModel_1_2( - const sp& callback); +sp getPreparedModel_1_3(const sp& callback); } // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h b/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h index 9376a92b87..fb19a841e1 100644 --- a/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h +++ b/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h @@ -137,7 +137,7 @@ class PreparedModelCallback : public IPreparedModelCallback { * nullptr if the model was unable to be prepared. */ Return notify_1_3(V1_0::ErrorStatus status, - const sp& preparedModel) override; + const sp& preparedModel) override; /** * PreparedModelCallback::wait blocks until notify* has been called on the From 89157a4baad6ea1457db522ba63841627bba202d Mon Sep 17 00:00:00 2001 From: Sunil Ravi Date: Thu, 31 Oct 2019 15:28:47 -0700 Subject: [PATCH 0231/1022] Wifi: MBO-OCE feature support (phase 1) 1. Added hidl API to return MBO and OCE feature capability. 2. Added hidl API to update the cellular data status. Bug: 139474288 Test: Manual Test: VTS test Change-Id: I4fe1c2ff054f5cc7288e9ed234d29a8ffcca7456 --- current.txt | 4 +-- wifi/supplicant/1.3/ISupplicantStaIface.hal | 22 ++++++++++++ wifi/supplicant/1.3/types.hal | 14 ++++++++ .../supplicant_sta_iface_hidl_test.cpp | 36 +++++++++++++++++++ 4 files changed, 74 insertions(+), 2 deletions(-) diff --git a/current.txt b/current.txt index e22db18e2f..28277ed8a9 100644 --- a/current.txt +++ b/current.txt @@ -597,10 +597,10 @@ b74fe72cfe438f50e772e6a307657ff449d5bde83c15dd1f140ff2edbe73499c android.hardwar 033eae03c09ebc75e82db37bc39995dfaa9086745577b44d9e14e9ccb48bd8cc android.hardware.vibrator@1.4::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant -0a7ff83fd0326b82232e1609da98f34960be11335df72fc407ad238d7bd0e081 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface +44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface 619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork -b0f8c9cd61a45a8c1b4a8e40913ecaea0921011cbe2305a6fa5a2feaa0d36c30 android.hardware.wifi.supplicant@1.3::types +9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types 41c602462ccd1b19cfd645994be4de4c07fc197ff58a54e84476b31908e61e21 android.hardware.radio@1.5::types a8691c71747c3f14f7a043598e856425077f755e55990507a9132ad62f8ab3f7 android.hardware.radio@1.5::IRadio a62a93faf173b14a6175b683ebf61ffa568dc61f81e369d2dce7b1265e86cf2f android.hardware.radio@1.5::IRadioIndication diff --git a/wifi/supplicant/1.3/ISupplicantStaIface.hal b/wifi/supplicant/1.3/ISupplicantStaIface.hal index cb207d836e..bfd8946251 100644 --- a/wifi/supplicant/1.3/ISupplicantStaIface.hal +++ b/wifi/supplicant/1.3/ISupplicantStaIface.hal @@ -54,4 +54,26 @@ interface ISupplicantStaIface extends @1.2::ISupplicantStaIface { */ getConnectionCapabilities() generates (SupplicantStatus status, ConnectionCapabilities capabilities); + + /** + * Get wpa driver capabilities. + * + * @return status Status of the operation, and a bitmap of wpa driver features. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + */ + getWpaDriverCapabilities() generates (SupplicantStatus status, + bitfield driverCapabilitiesMask); + + /** + * Set MBO cellular data status. + * + * @param available true means cellular data available, false otherwise. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_UNKNOWN| + */ + setMboCellularDataStatus(bool available) generates (SupplicantStatus status); }; diff --git a/wifi/supplicant/1.3/types.hal b/wifi/supplicant/1.3/types.hal index 787439984b..4e01ab1df8 100644 --- a/wifi/supplicant/1.3/types.hal +++ b/wifi/supplicant/1.3/types.hal @@ -58,3 +58,17 @@ struct ConnectionCapabilities { */ WifiTechnology technology; }; + +/** + * WPA Driver capability. + */ +enum WpaDriverCapabilitiesMask : uint32_t { + /** + * Multi Band Operation. + */ + MBO = 1 << 0, + /** + * Optimized Connectivity Experience. + */ + OCE = 1 << 1, +}; diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp index 62f3228c40..2cf58813ad 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp @@ -41,6 +41,7 @@ using ::android::hardware::wifi::supplicant::V1_3::ConnectionCapabilities; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIfaceCallback; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork; +using ::android::hardware::wifi::supplicant::V1_3::WpaDriverCapabilitiesMask; class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { public: @@ -191,3 +192,38 @@ TEST_F(SupplicantStaIfaceHidlTest, GetConnectionCapabilities) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); }); } + +/* + * GetWpaDriverCapabilities + */ +TEST_F(SupplicantStaIfaceHidlTest, GetWpaDriverCapabilities) { + sta_iface_->getWpaDriverCapabilities( + [&](const SupplicantStatus& status, uint32_t) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); +} + +/* + * SetMboCellularDataStatus + */ +TEST_F(SupplicantStaIfaceHidlTest, SetMboCellularDataStatus) { + uint32_t driverCapMask = 0; + + // Get MBO support from the device. + sta_iface_->getWpaDriverCapabilities( + [&](const SupplicantStatus& status, uint32_t driverCapMaskInternal) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + + driverCapMask = driverCapMaskInternal; + }); + + SupplicantStatusCode expectedStatusCode = + (driverCapMask & WpaDriverCapabilitiesMask::MBO) + ? SupplicantStatusCode::SUCCESS + : SupplicantStatusCode::FAILURE_UNKNOWN; + + sta_iface_->setMboCellularDataStatus( + true, [expectedStatusCode](const SupplicantStatus& status) { + EXPECT_EQ(expectedStatusCode, status.code); + }); +} From 4e9c4061ca9a925c4fd5fcaa9ff3ee88776d957d Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 8 Nov 2019 15:15:09 -0800 Subject: [PATCH 0232/1022] audio vts: Remove explicit dependency on the new types Avoid using the new ChannelMaskSet and SampleRateSet types directly to simplify upstreaming. Bug: 141989952 Bug: 141847510 Test: atest VtsHalAudioV5_0TargetTest Change-Id: I4477334be0375a95d79324a3ab38b03eb3f9998f --- .../functional/6.0/AudioPrimaryHidlHalTest.cpp | 18 ++++++++++++------ .../all-versions/vts/functional/ConfigHelper.h | 4 ++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp index c56445cc9e..30f8a7ade7 100644 --- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp @@ -73,9 +73,12 @@ const std::vector& getOutputDeviceConfigParameters() { getCachedPolicyConfig().getModuleFromName(std::get(device)); for (const auto& ioProfile : module->getOutputProfiles()) { for (const auto& profile : ioProfile->getAudioProfiles()) { - auto configs = ConfigHelper::combineAudioConfig(profile->getChannels(), - profile->getSampleRates(), - profile->getFormat()); + const auto& channels = profile->getChannels(); + const auto& sampleRates = profile->getSampleRates(); + auto configs = ConfigHelper::combineAudioConfig( + vector(channels.begin(), channels.end()), + vector(sampleRates.begin(), sampleRates.end()), + profile->getFormat()); auto flags = ioProfile->getFlags(); for (auto& config : configs) { // Some combinations of flags declared in the config file require special @@ -125,9 +128,12 @@ const std::vector& getInputDeviceConfigParameters() { getCachedPolicyConfig().getModuleFromName(std::get(device)); for (const auto& ioProfile : module->getInputProfiles()) { for (const auto& profile : ioProfile->getAudioProfiles()) { - auto configs = ConfigHelper::combineAudioConfig(profile->getChannels(), - profile->getSampleRates(), - profile->getFormat()); + const auto& channels = profile->getChannels(); + const auto& sampleRates = profile->getSampleRates(); + auto configs = ConfigHelper::combineAudioConfig( + vector(channels.begin(), channels.end()), + vector(sampleRates.begin(), sampleRates.end()), + profile->getFormat()); for (const auto& config : configs) { result.emplace_back(device, config, AudioInputFlag(ioProfile->getFlags())); } diff --git a/audio/core/all-versions/vts/functional/ConfigHelper.h b/audio/core/all-versions/vts/functional/ConfigHelper.h index 604c0c50e6..48aae8c5b3 100644 --- a/audio/core/all-versions/vts/functional/ConfigHelper.h +++ b/audio/core/all-versions/vts/functional/ConfigHelper.h @@ -79,8 +79,8 @@ struct ConfigHelper { return {}; } - static vector combineAudioConfig(android::ChannelMaskSet channelMasks, - android::SampleRateSet sampleRates, + static vector combineAudioConfig(vector channelMasks, + vector sampleRates, audio_format_t format) { vector configs; configs.reserve(channelMasks.size() * sampleRates.size()); From b14c364004116971a2e38164750a1f7d7b93657e Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Sun, 10 Nov 2019 20:21:38 -0800 Subject: [PATCH 0233/1022] vibrator@1.4: remove from current.txt Since it is being replaced by an AIDL HAL interface. Bug: 141828236 Test: N/A Change-Id: Ie46843cd17540665f0575798ea97355e174a359c --- current.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/current.txt b/current.txt index e22db18e2f..77128353ac 100644 --- a/current.txt +++ b/current.txt @@ -592,9 +592,6 @@ ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardwar db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types 34515afa2bb792d3c6d8495a5f5d907d179c8507ca5e55c10050d02ae1d516ef android.hardware.neuralnetworks@1.3::IDevice b74fe72cfe438f50e772e6a307657ff449d5bde83c15dd1f140ff2edbe73499c android.hardware.neuralnetworks@1.3::types -544049dcda3f943ad67d83d5277f06681a3782982a9af5a78b5d4e8d295d061a android.hardware.vibrator@1.4::IVibrator -5e1c12efbbba89c9143d10b1b90eceff8bc79aa079f5106215b528e104fef101 android.hardware.vibrator@1.4::IVibratorCallback -033eae03c09ebc75e82db37bc39995dfaa9086745577b44d9e14e9ccb48bd8cc android.hardware.vibrator@1.4::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant 0a7ff83fd0326b82232e1609da98f34960be11335df72fc407ad238d7bd0e081 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface From 8774f10b76bb38c1b1b0fd7e7f397f04979a1f72 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Thu, 31 Oct 2019 18:12:50 +0000 Subject: [PATCH 0234/1022] Add NNAPI 1.3 OperationType * Add 1.3 OperationType. * Remove "using V1_2::OperationType" from 1.3 VTS tests. * Update current.txt Test: mma Change-Id: Ieaede9b7a6cecb16dbcc753f347f7ff04c009f20 --- current.txt | 2 +- neuralnetworks/1.3/types.hal | 4542 ++++++++++++++++- neuralnetworks/1.3/types.t | 89 +- .../vts/functional/GeneratedTestHarness.cpp | 1 - .../1.3/vts/functional/TestAssertions.cpp | 2 - .../1.3/vts/functional/ValidateModel.cpp | 1 - 6 files changed, 4588 insertions(+), 49 deletions(-) diff --git a/current.txt b/current.txt index 74586b7502..fc004aa0a2 100644 --- a/current.txt +++ b/current.txt @@ -597,7 +597,7 @@ db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardwar 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice 4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -b74fe72cfe438f50e772e6a307657ff449d5bde83c15dd1f140ff2edbe73499c android.hardware.neuralnetworks@1.3::types +c511b1427b1c3f76af90967bbddaaf250db983a8d3abb9ff189fb5a807cf3d4d android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant 44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index 86ab287067..7df14b18f6 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -73,6 +73,4500 @@ enum OperandTypeRange : uint32_t { BASE_MAX = 0xFFFF, }; +/** + * Operation types. + * + * The type of an operation in a model. + */ +enum OperationType : int32_t { + + /** + * Adds two tensors, element-wise. + * + * Takes two input tensors of identical {@link OperandType} and compatible + * dimensions. The output is the sum of both input tensors, optionally + * modified by an activation function. + * + * Two dimensions are compatible when: + * 1. they are equal, or + * 2. one of them is 1 + * + * The size of the output is the maximum size along each dimension of the + * input operands. It starts with the trailing dimensions, and works its + * way forward. + * + * Example: + * + * input1.dimension = {4, 1, 2} + * input2.dimension = {5, 4, 3, 1} + * output.dimension = {5, 4, 3, 2} + * + * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero + * dimension is only compatible with 0 or 1. The size of the output + * dimension is zero if either of corresponding input dimension is zero. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: A tensor. + * * 1: A tensor of the same {@link OperandType}, and compatible dimensions + * as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scales and zeroPoint can be different from input0 scale and zeroPoint. + * * 2: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * + * Outputs: + * * 0: The sum, a tensor of the same {@link OperandType} as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from inputs' scale and zeroPoint. + */ + ADD = @1.2::OperationType:ADD, + + /** + * Performs a 2-D average pooling operation. + * + * The output dimensions are functions of the filter dimensions, stride, and + * padding. + * + * The values in the output tensor are computed as: + * + * output[b, i, j, channel] = + * sum_{di, dj}( + * input[b, strides[1] * i + di, strides[2] * j + dj, channel] + * ) / sum(1) + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. + * + * Both explicit padding and implicit padding are supported. + * + * Inputs (explicit padding): + * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying + * the input. + * Since HAL version 1.2, zero batches is supported for this tensor. + * * 1: An {@link OperandType::INT32} scalar, specifying the padding on + * the left, in the ‘width’ dimension. + * * 2: An {@link OperandType::INT32} scalar, specifying the padding on + * the right, in the ‘width’ dimension. + * * 3: An {@link OperandType::INT32} scalar, specifying the padding on + * the top, in the ‘height’ dimension. + * * 4: An {@link OperandType::INT32} scalar, specifying the padding on + * the bottom, in the ‘height’ dimension. + * * 5: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘width’ dimension. + * * 6: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘height’ dimension. + * * 7: An {@link OperandType::INT32} scalar, specifying the filter + * width. + * * 8: An {@link OperandType::INT32} scalar, specifying the filter + * height. + * * 9: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * * 10: An optional {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * Available since HAL version 1.2. + * + * Inputs (implicit padding): + * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying + * the input. + * Since HAL version 1.2, zero batches is supported for this tensor. + * * 1: An {@link OperandType::INT32} scalar, specifying the implicit + * padding scheme, has to be one of the + * following values: {0 (NONE), 1 (SAME), 2 (VALID)}. + * * 2: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘width’ dimension. + * * 3: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘height’ dimension. + * * 4: An {@link OperandType::INT32} scalar, specifying the filter + * width. + * * 5: An {@link OperandType::INT32} scalar, specifying the filter + * height. + * * 6: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * * 7: An optional {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * Available since HAL version 1.2. + * + * Outputs: + * * 0: The output 4-D tensor, of shape + * [batches, out_height, out_width, depth]. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + AVERAGE_POOL_2D = @1.2::OperationType:AVERAGE_POOL_2D, + + /** + * Concatenates the input tensors along the given dimension. + * + * The input tensors must have identical {@link OperandType} and the same + * dimensions except the dimension along the concatenation axis. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * (full support since HAL version 1.2, see the input section) + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0 ~ n-1: The list of n input tensors, of shape + * [D0, D1, ..., Daxis(i), ..., Dm]. + * Before HAL version 1.2, all input tensors of + * {@link OperandType::TENSOR_QUANT8_ASYMM} + * must have the same scale and zeroPoint as the output tensor. + * Since HAL version 1.2, zero-sized tensors are supported. + * * n: An {@link OperandType::INT32} scalar, specifying the + * concatenation axis. + * + * Outputs: + * * 0: The output, a tensor of the same {@link OperandType} as the input + * tensors. The output shape is [D0, D1, ..., sum(Daxis(i)), ..., Dm]. + * Since HAL version 1.2, for a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint values can be different from + * input tensors. Before HAL version 1.2 they have to be the same as for the input tensors. + */ + CONCATENATION = @1.2::OperationType:CONCATENATION, + + /** + * Performs a 2-D convolution operation. + * + * The CONV_2D op sweeps a 2-D filter that can mix channels together over a + * batch of images, applying the filter to each window of each image of the + * appropriate size. + * + * The output dimensions are functions of the filter dimensions, stride, and + * padding. + * + * The values in the output tensor are computed as: + * + * output[b, i, j, channel] = + * sum_{di, dj, k} ( + * input[b, strides[1] * i + di, strides[2] * j + dj, k] * + * filter[channel, di, dj, k] + * ) + bias[channel] + * + * Supported tensor {@link OperandType} configurations: + * * 32 bit floating point: + * * * {@link OperandType::TENSOR_FLOAT32} for input, filter, output, and bias. + * + * * Quantized: + * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, filter, and output. + * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to + * * * input.scale * filter.scale). + * + * Available since HAL version 1.2: + * * 16 bit floating point: + * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias. + * + * * Quantized with symmetric per channel quantization for the filter: + * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, and output. + * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter. + * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0, + * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. + * + * Both explicit padding and implicit padding are supported. + * + * Inputs (explicit padding): + * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], + * specifying the input. + * Since HAL version 1.2, zero batches is supported for this tensor. + * * 1: A 4-D tensor, of shape + * [depth_out, filter_height, filter_width, depth_in], specifying the + * filter. + * For tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} + * the channel dimension (SymmPerChannelQuantParams::channelDim) + * must be set to 0. + * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input + * tensor of type {@link OperandType::TENSOR_FLOAT32} + * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same + * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint + * of 0 and bias_scale == input_scale * filter_scale. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 + * and bias_scale of 0. The actual scale of each value 'i' is equal to + * bias_scale[i] = input_scale * filter_scale[i]. + * * 3: An {@link OperandType::INT32} scalar, specifying the padding on + * the left, in the ‘width’ dimension. + * * 4: An {@link OperandType::INT32} scalar, specifying the padding on + * the right, in the ‘width’ dimension. + * * 5: An {@link OperandType::INT32} scalar, specifying the padding on + * the top, in the ‘height’ dimension. + * * 6: An {@link OperandType::INT32} scalar, specifying the padding on + * the bottom, in the ‘height’ dimension. + * * 7: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘width’ dimension. + * * 8: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘height’ dimension. + * * 9: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * * 10: An optional {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * Available since HAL version 1.2. + * * 11: An optional {@link OperandType::INT32} scalar, specifying the dilation + * factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped + * cells between each filter element on width dimension. If this input is set, + * input 12 (dilation factor for height) must be specified as well. + * Available since HAL version 1.2. + * * 12: An optional {@link OperandType::INT32} scalar, specifying the dilation + * factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped + * cells between each filter element on height dimension. If this input is set, + * input 11 (dilation factor for width) must be specified as well. + * Available since HAL version 1.2. + * + * Inputs (implicit padding): + * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], + * specifying the input. + * Since HAL version 1.2, zero batches is supported for this tensor. + * * 1: A 4-D tensor, of shape + * [depth_out, filter_height, filter_width, depth_in], specifying the + * filter. + * For tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} + * the channel dimension (SymmPerChannelQuantParams::channelDim) + * must be set to 0. + * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input + * tensor of type {@link OperandType::TENSOR_FLOAT32} + * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same + * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint + * of 0 and bias_scale == input_scale * filter_scale. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 + * and bias_scale of 0. The actual scale of each value 'i' is equal to + * bias_scale[i] = input_scale * filter_scale[i]. + * * 3: An {@link OperandType::INT32} scalar, specifying the implicit + * padding scheme, has to be one of the + * following values: {0 (NONE), 1 (SAME), 2 (VALID)}. + * * 4: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘width’ dimension. + * * 5: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘height’ dimension. + * * 6: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * * 7: An optional {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * Available since HAL version 1.2. + * * 8: An optional {@link OperandType::INT32} scalar, specifying the dilation + * factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped + * cells between each filter element on width dimension. If this input is set, + * input 9 (dilation factor for height) must be specified as well. + * Available since HAL version 1.2. + * * 9: An optional {@link OperandType::INT32} scalar, specifying the dilation + * factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped + * cells between each filter element on height dimension. If this input is set, + * input 8 (dilation factor for width) must be specified as well. + * Available since HAL version 1.2. + * + * Outputs: + * * 0: The output 4-D tensor, of shape + * [batches, out_height, out_width, depth_out]. + * Before HAL version 1.2, for output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the following condition must be satisfied: output_scale > input_scale * filter_scale + */ + CONV_2D = @1.2::OperationType:CONV_2D, + + /** + * Performs a depthwise 2-D convolution operation. + * + * Given an input tensor of shape [batches, height, width, depth_in] and a + * filter tensor of shape [1, filter_height, filter_width, depth_out] + * containing depth_out convolutional filters of depth 1, DEPTHWISE_CONV + * applies a different filter to each input channel (expanding from 1 + * channel to channel_multiplier channels for each), then concatenates the + * results together. + * + * The output has depth_out = depth_in * depth_multiplier channels. + * The output dimensions are functions of the filter dimensions, stride, and + * padding. + * + * The values in the output tensor are computed as: + * + * output[b, i, j, k * channel_multiplier + q] = + * sum_{di, dj} ( + * input[b, strides[1] * i + di, strides[2] * j + dj, k] * + * filter[1, di, dj, k * channel_multiplier + q] + * ) + bias[k * channel_multiplier + q] + * + * Supported tensor {@link OperandType} configurations: + * * 32 bit floating point: + * * * {@link OperandType::TENSOR_FLOAT32} for input, filter, output, and bias. + * + * * Quantized: + * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, filter, and output. + * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to + * * * input.scale * filter.scale). + * + * Available since HAL version 1.2: + * * 16 bit floating point: + * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias. + * + * * Quantized with symmetric per channel quantization for the filter: + * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, and output. + * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter. + * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0, + * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. + * + * Both explicit padding and implicit padding are supported. + * + * Inputs (explicit padding): + * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], + * specifying the input. + * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out], + * specifying the filter. + * For tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} + * the channel dimension (SymmPerChannelQuantParams::channelDim) + * must be set to 3. + * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input + * tensor of type {@link OperandType::TENSOR_FLOAT32} + * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same + * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint + * of 0 and bias_scale == input_scale * filter_scale. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 + * and bias_scale of 0. The actual scale of each value 'i' is equal to + * bias_scale[i] = input_scale * filter_scale[i]. + * * 3: An {@link OperandType::INT32} scalar, specifying the padding on + * the left, in the ‘width’ dimension. + * * 4: An {@link OperandType::INT32} scalar, specifying the padding on + * the right, in the ‘width’ dimension. + * * 5: An {@link OperandType::INT32} scalar, specifying the padding on + * the top, in the ‘height’ dimension. + * * 6: An {@link OperandType::INT32} scalar, specifying the padding on + * the bottom, in the ‘height’ dimension. + * * 7: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘width’ dimension. + * * 8: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘height’ dimension. + * * 9: An {@link OperandType::INT32} scalar, specifying the depthwise + * multiplier. + * * 10: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * * 11: An optional {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * Available since HAL version 1.2. + * * 12: An optional {@link OperandType::INT32} scalar, specifying the dilation + * factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped + * cells between each filter element on width dimension. If this input is set, + * input 13 (dilation factor for height) must be specified as well. + * Available since HAL version 1.2. + * * 13: An optional {@link OperandType::INT32} scalar, specifying the dilation + * factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped + * cells between each filter element on height dimension. If this input is set, + * input 12 (dilation factor for width) must be specified as well. + * Available since HAL version 1.2. + * + * Inputs (implicit padding): + * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], + * specifying the input. + * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out], + * specifying the filter. + * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input + * tensor of type {@link OperandType::TENSOR_FLOAT32} + * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same + * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint + * of 0 and bias_scale == input_scale * filter_scale. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 + * and bias_scale of 0. The actual scale of each value 'i' is equal to + * bias_scale[i] = input_scale * filter_scale[i]. + * * 3: An {@link OperandType::INT32} scalar, specifying the implicit + * padding scheme, has to be one of the + * following values: {0 (NONE), 1 (SAME), 2 (VALID)}. + * * 4: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘width’ dimension. + * * 5: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘height’ dimension. + * * 6: An {@link OperandType::INT32} scalar, specifying the depthwise + * multiplier. + * * 7: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * * 8: An optional {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * Available since HAL version 1.2. + * * 9: An optional {@link OperandType::INT32} scalar, specifying the dilation + * factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped + * cells between each filter element on width dimension. If this input is set, + * input 10 (dilation factor for height) must be specified as well. + * Available since HAL version 1.2. + * * 10: An optional {@link OperandType::INT32} scalar, specifying the dilation + * factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped + * cells between each filter element on height dimension. If this input is set, + * input 9 (dilation factor for width) must be specified as well. + * Available since HAL version 1.2. + * + * Outputs: + * * 0: The output 4-D tensor, of shape + * [batches, out_height, out_width, depth_out]. Before HAL version 1.2, for + * output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the following condition must be satisfied: + * output_scale > input_scale * filter_scale + */ + DEPTHWISE_CONV_2D = @1.2::OperationType:DEPTHWISE_CONV_2D, + + /** + * Rearranges data from depth into blocks of spatial data. + * + * More specifically, this op outputs a copy of the input tensor where + * values from the depth dimension are moved in spatial blocks to the height + * and width dimensions. The value block_size indicates the input block size + * and how the data is moved. + * + * Chunks of data of size block_size * block_size from depth are rearranged + * into non-overlapping blocks of size block_size x block_size. + * + * The width of the output tensor is input_depth * block_size, whereas the + * height is input_height * block_size. The depth of the input tensor must + * be divisible by block_size * block_size + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. + * + * Inputs: + * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], + * specifying the input. + * * 1: An {@link OperandType::INT32} scalar, specifying the block_size. + * block_size must be >=1 and block_size * block_size must be a divisor + * of the input depth. + * * 2: An optional {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * Available since HAL version 1.2. + * + * Outputs: + * * 0: The output 4-D tensor, of shape [batch, height*block_size, + * width*block_size, depth/(block_size*block_size)]. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + DEPTH_TO_SPACE = @1.2::OperationType:DEPTH_TO_SPACE, + + /** + * Dequantizes the input tensor. + * + * The formula is: + * + * output = (input - zeroPoint) * scale. + * + * Supported input tensor {@link OperandType}: + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_SYMM} (since HAL version 1.2) + * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} (since HAL version 1.2) + * + * Supported output tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32}. + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: A tensor. + * Since HAL version 1.2, this tensor may be zero-sized. + * + * Outputs: + * * 0: A tensor with the same shape as input0. + */ + DEQUANTIZE = @1.2::OperationType:DEQUANTIZE, + + /** + * Looks up sub-tensors in the input tensor. + * + * This operator takes for input a tensor of values (Values) and + * a one-dimensional tensor of selection indices (Lookups). + * The output tensor is the concatenation of sub-tensors of Values as + * selected by Lookups. + * + * Think of Values as being sliced along its first dimension: + * The entries in Lookups select which slices are concatenated together + * to create the output tensor. + * + * For example, if Values has shape of [40, 200, 300] and + * Lookups has shape of [3], all three values found in Lookups are + * expected to be between 0 and 39. The resulting tensor must + * have shape of [3, 200, 300]. + * + * If a value in Lookups is out of bounds, the operation must fail + * and an error must be reported. + * + * Supported value tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported value tensor rank: from 2 + * + * Inputs: + * * 0: Lookups. A 1-D tensor of {@link OperandType::TENSOR_INT32}. + * The values are indices into the first dimension of Values. + * * 1: Values. An n-D tensor, where n >= 2, from which sub-tensors are + * extracted. + * + * Output: + * * 0: A n-D tensor with the same rank and shape as the Values + * tensor, except for the first dimension which has the same size + * as Lookups' only dimension. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input1. + */ + EMBEDDING_LOOKUP = @1.2::OperationType:EMBEDDING_LOOKUP, + + /** + * Computes element-wise floor() on the input tensor. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: A tensor. + * + * Outputs: + * * 0: The output tensor, of the same {@link OperandType} and dimensions as + * the input tensor. + */ + FLOOR = @1.2::OperationType:FLOOR, + + /** + * Denotes a fully (densely) connected layer, which connects all elements + * in the input tensor with each element in the output tensor. + * + * This layer implements the operation: + * + * outputs = activation(inputs * weights’ + bias) + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4. + * + * Inputs: + * * 0: A tensor of at least rank 2, specifying the input. If rank is + * greater than 2, then it gets flattened to a 2-D Tensor. The + * (flattened) 2-D Tensor is reshaped (if necessary) to + * [batch_size, input_size], where "input_size" corresponds to the + * number of inputs to the layer, matching the second dimension of + * weights, and "batch_size" is calculated by dividing the number of + * elements by "input_size". + * Since HAL version 1.2, zero batch_size is supported for this tensor. + * * 1: A 2-D tensor, specifying the weights, of shape + * [num_units, input_size], where "num_units" corresponds to the number + * of output nodes. + * * 2: A 1-D tensor, of shape [num_units], specifying the bias. For input + * tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should + * also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor + * of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be + * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and + * bias_scale == input_scale * filter_scale. + * * 3: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * + * Outputs: + * * 0: The output tensor, of shape [batch_size, num_units]. Before HAL version 1.2, for + * output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the following + * condition must be satisfied: output_scale > input_scale * filter_scale. + */ + FULLY_CONNECTED = @1.2::OperationType:FULLY_CONNECTED, + + /** + * Looks up sub-tensors in the input tensor using a key-value map. + * + * This operator takes for input a tensor of values (Values), + * a one-dimensional tensor of selection values (Lookups) and + * a one-dimensional tensor that maps these values to Values + * indexes. The output tensor is the concatenation of sub-tensors of + * Values as selected by Lookups via Keys. + * + * Think of Values as being sliced along its outer-most dimension. + * The output is a concatenation of selected slices, with one slice + * for each entry of Lookups. The slice selected is the one at the + * same index as the Maps entry that matches the value in Lookups. + * + * For a hit, the corresponding sub-tensor of Values is included + * in the Output tensor. For a miss, the corresponding sub-tensor in + * Output must have zero values. + * + * For example, if Values has shape of [40, 200, 300], + * Keys should have a shape of [40]. If Lookups tensor has shape + * of [3], three slices are being concatenated, so the resulting tensor + * must have the shape of [3, 200, 300]. If the first entry in Lookups + * has the value 123456, that value must be located in Keys tensor. + * If the sixth entry of Keys contains 123456, the sixth slice of Values + * must be selected. If no entry in Keys has 123456, a slice of zeroes + * must be concatenated. + * + * Supported value tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported value tensor rank: from 2 + * + * Inputs: + * * 0: Lookups. A 1-D {@link OperandType::TENSOR_INT32} tensor with + * shape [ k ]. + * * 1: Keys. A 1-D {@link OperandType::TENSOR_INT32} tensor with shape + * [ n ]; Keys and Values pair represent a map, i.e., the ith element + * in Keys (Keys[i]) is the key to select the ith sub-tensor in Values + * (Values[i]), where 0 <= i <= n-1. Keys tensor *MUST* be sorted in + * ascending order. + * * 2: Values. A tensor with shape of [ n, … ]; i.e., the first dimension + * must be n. + * + * Outputs: + * * 0: Output. A tensor with shape [ k …]. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input2. + * * 1: Hits. A boolean tensor with shape [ k ] indicates whether the lookup + * hits (True) or not (False). + * Stored as {@link OperandType::TENSOR_QUANT8_ASYMM} with offset 0 + * and scale 1.0f. + * A non-zero byte represents True, a hit. A zero indicates otherwise. + */ + HASHTABLE_LOOKUP = @1.2::OperationType:HASHTABLE_LOOKUP, + + /** + * Applies L2 normalization along the depth dimension. + * + * The values in the output tensor are computed as: + * + * output[batch, row, col, channel] = + * input[batch, row, col, channel] / + * sqrt(sum_{c} pow(input[batch, row, col, c], 2)) + * + * For input tensor with rank less than 4, independently normalizes each + * 1-D slice along dimension dim. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) + * + * Supported tensor rank: up to 4 + * Tensors with rank less than 4 are only supported since HAL version 1.2. + * + * Inputs: + * * 0: An n-D tensor, specifying the tensor to be normalized. + * * 1: An optional {@link OperandType::INT32} scalar, default to -1, + * specifying the dimension normalization would be performed on. + * Negative index is used to specify axis from the end (e.g. -1 for + * the last axis). Must be in the range [-n, n). + * Available since HAL version 1.2. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} and same shape as input0. + * For {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the scale must be 1.f / 128 and the zeroPoint must be 128. + */ + L2_NORMALIZATION = @1.2::OperationType:L2_NORMALIZATION, + + /** + * Performs an 2-D L2 pooling operation. + * + * The output dimensions are functions of the filter dimensions, stride, and + * padding. + * + * The values in the output tensor are computed as: + * + * output[b, i, j, c] = + * sqrt(sum_{di, dj} pow(input[b, strides[1] * i + di, strides[2] * j + dj, c], 2) / + * sum(1)) + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. + * + * Both explicit padding and implicit padding are supported. + * + * Inputs (explicit padding): + * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying + * the input. + * Since HAL version 1.2, zero batches is supported for this tensor. + * * 1: An {@link OperandType::INT32} scalar, specifying the padding on + * the left, in the ‘width’ dimension. + * * 2: An {@link OperandType::INT32} scalar, specifying the padding on + * the right, in the ‘width’ dimension. + * * 3: An {@link OperandType::INT32} scalar, specifying the padding on + * the top, in the ‘height’ dimension. + * * 4: An {@link OperandType::INT32} scalar, specifying the padding on + * the bottom, in the ‘height’ dimension. + * * 5: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘width’ dimension. + * * 6: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘height’ dimension. + * * 7: An {@link OperandType::INT32} scalar, specifying the filter + * width. + * * 8: An {@link OperandType::INT32} scalar, specifying the filter + * height. + * * 9: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * * 10: An optional {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * Available since HAL version 1.2. + * + * Inputs (implicit padding): + * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying + * the input. + * Since HAL version 1.2, zero batches is supported for this tensor. + * * 1: An {@link OperandType::INT32} scalar, specifying the implicit + * padding scheme, has to be one of the + * following values: {0 (NONE), 1 (SAME), 2 (VALID)}. + * * 2: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘width’ dimension. + * * 3: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘height’ dimension. + * * 4: An {@link OperandType::INT32} scalar, specifying the filter + * width. + * * 5: An {@link OperandType::INT32} scalar, specifying the filter + * height. + * * 6: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * * 7: An optional {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * Available since HAL version 1.2. + * + * Outputs: + * * 0: The output 4-D tensor, of shape + * [batches, out_height, out_width, depth]. + */ + L2_POOL_2D = @1.2::OperationType:L2_POOL_2D, + + /** + * Applies Local Response Normalization along the depth dimension. + * + * The 4-D input tensor is treated as a 3-D array of 1-D vectors (along the + * last dimension), and each vector is normalized independently. Within a + * given vector, each component is divided by the weighted, squared sum of + * inputs within depth_radius. + * + * The output is calculated using this formula: + * + * sqr_sum[a, b, c, d] = sum( + * pow(input[a, b, c, d - depth_radius : d + depth_radius + 1], 2)) + * output = input / pow((bias + alpha * sqr_sum), beta) + * + * For input tensor with rank less than 4, independently normalizes each + * 1-D slice along specified dimension. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: up to 4 + * Tensors with rank less than 4 are only supported since HAL version 1.2. + * + * Inputs: + * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying + * the input. + * * 1: An {@link OperandType::INT32} scalar, specifying the radius of + * the normalization window. + * * 2: A scalar, specifying the bias, must not be zero. + * For input tensor of {@link OperandType::TENSOR_FLOAT16}, the bias + * value must be of {@link OperandType::FLOAT16}. + * For input tensor of {@link OperandType::TENSOR_FLOAT32}, the bias + * value must be of {@link OperandType::FLOAT32}. + * * 3: A scalar, specifying the scale factor, alpha. + * For input tensor of {@link OperandType::TENSOR_FLOAT16}, the + * alpha value must be of {@link OperandType::FLOAT16}. + * For input tensor of {@link OperandType::TENSOR_FLOAT32}, the + * alpha value must be of {@link OperandType::FLOAT32}. + * * 4: A scalar, specifying the exponent, beta. + * For input tensor of {@link OperandType::TENSOR_FLOAT16}, the beta + * value must be of {@link OperandType::FLOAT16}. + * For input tensor of {@link OperandType::TENSOR_FLOAT32}, the beta + * value must be of {@link OperandType::FLOAT32}. + * * 5: An optional {@link OperandType::INT32} scalar, default to -1, + * specifying the dimension normalization would be performed on. + * Negative index is used to specify axis from the end (e.g. -1 for + * the last axis). Must be in the range [-n, n). + * Available since HAL version 1.2. + * + * Outputs: + * * 0: The output tensor of same shape as input0. + */ + LOCAL_RESPONSE_NORMALIZATION = @1.2::OperationType:LOCAL_RESPONSE_NORMALIZATION, + + /** + * Computes sigmoid activation on the input tensor element-wise. + * + * The output is calculated using this formula: + * + * output = 1 / (1 + exp(-input)) + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4. + * + * Inputs: + * * 0: A tensor, specifying the input. + * Since HAL version 1.2, this tensor may be zero-sized. + * + * Outputs: + * * 0: The output tensor of same shape as input0. + * For {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the scale must be 1.f / 256 and the zeroPoint must be 0. + */ + LOGISTIC = @1.2::OperationType:LOGISTIC, + + /** + * Projects an input to a bit vector via locality senstive hashing. + * + * Supported input tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported input tensor rank: from 1 + * + * Inputs: + * * 0: Hash functions. Dim.size == 2, DataType: Float. + * Tensor[0].Dim[0]: Number of hash functions. + * Tensor[0].Dim[1]: Number of projected output bits generated by each + * hash function. + * If the projection type is Sparse: + * Tensor[0].Dim[1] + ceil(log2(Tensor[0].Dim[0])) <= 32 + * + * * 1: Input. Dim.size >= 1, no restriction on DataType. + * * 2: Weight. Optional. Dim.size == 1, DataType: Float. + * If not set, each input element is considered to have the same weight + * of 1.0. + * Tensor[1].Dim[0] == Tensor[2].Dim[0] + * * 3: Type: + * Sparse: + * Value LSHProjectionType_SPARSE(=3) (since HAL version 1.2). + * Computed bit vector is considered to be sparse. + * Each output element is an int32 made up of multiple bits + * computed from hash functions. + * + * NOTE: To avoid collisions across hash functions, an offset value + * of k * (1 << Tensor[0].Dim[1]) will be added to each signature, + * where k is the index of the hash function. + * + * Value LSHProjectionType_SPARSE_DEPRECATED(=1). + * Legacy behavior that does not include the offset value. + * + * Dense: + * Value LSHProjectionType_DENSE(=2). + * Computed bit vector is considered to be dense. Each output + * element represents a bit and can take the value of either + * 0 or 1. + * + * Outputs: + * * 0: If the projection type is Sparse: + * Output.Dim == { Tensor[0].Dim[0] } + * A tensor of int32 that represents hash signatures. + * + * If the projection type is Dense: + * Output.Dim == { Tensor[0].Dim[0] * Tensor[0].Dim[1] } + * A flattened tensor that represents projected bit vectors. + * The offset value for sparse projections was added in HAL version 1.2. + */ + LSH_PROJECTION = @1.2::OperationType:LSH_PROJECTION, + + /** + * Performs a single time step in a Long Short-Term Memory (LSTM) layer + * + * The LSTM operation is described by the following equations. + * + * \f{eqnarray*}{ + * i_t =& \sigma(W_{xi}x_t+W_{hi}h_{t-1}+W_{ci}C_{t-1}+b_i) & \\ + * f_t =& \sigma(W_{xf}x_t+W_{hf}h_{t-1}+W_{cf}C_{t-1}+b_f) & \\ + * C_t =& clip(f_t \odot C_{t-1} + i_t \odot + * g(W_{xc}x_t+W_{hc}h_{t-1}+b_c),\ t_{cell}) & \\ + * o_t =& \sigma(W_{xo}x_t+W_{ho}h_{t-1}+W_{co}C_t+b_o) & \\ + * & & \\ + * & clip(W_{proj}(o_t \odot g(C_t))+b_{proj},\ t_{proj}) + * & if\ there\ is\ a\ projection; \\ + * h_t =& & \\ + * & o_t \odot g(C_t) & otherwise. \\ + * \f} + * Where: + * * \f$x_t\f$ is the input, + * * \f$i_t\f$ is the input gate, + * * \f$f_t\f$ is the forget gate, + * * \f$C_t\f$ is the cell state, + * * \f$o_t\f$ is the output, + * * \f$h_t\f$ is the output state, + * * \f$\sigma\f$ is the logistic sigmoid function, + * * \f$g\f$ is the cell input and cell output activation function, usually + * \f$tahn\f$, + * * \f$W_{xi}\f$ is the input-to-input weight matrix, + * * \f$W_{hi}\f$ is the recurrent to input weight matrix, + * * \f$W_{ci}\f$ is the cell-to-input weight matrix, + * * \f$b_i\f$ is the input gate bias, + * * \f$W_{xf}\f$ is the input-to-forget weight matrix, + * * \f$W_{hf}\f$ is the recurrent-to-forget weight matrix, + * * \f$W_{cf}\f$ is the cell-to-forget weight matrix, + * * \f$b_f\f$ is the forget gate bias, + * * \f$W_{xc}\f$ is the input-to-cell weight matrix, + * * \f$W_{hc}\f$ is the recurrent-to-cell weight matrix, + * * \f$b_c\f$ is the cell bias, + * * \f$W_{xo}\f$ is the input-to-output weight matrix, + * * \f$W_{ho}\f$ is the recurrent-to-output weight matrix, + * * \f$W_{co}\f$ is the cell-to-output weight matrix, + * * \f$b_o\f$ is the output gate bias, + * * \f$W_{proj}\f$ is the projection weight matrix, + * * \f$b_{proj}\f$ is the projection bias, + * * \f$t_{cell}\f$ is the threshold for clipping the cell state, and + * * \f$t_{proj}\f$ is the threshold for clipping the projected output. + * * \f$\odot\f$ is the + * + * Hadamard product that takes two matrices and produces another + * matrix, each element of which is the product of the corresponding + * elements of the input matrices. + * + * Since HAL version 1.2 LSTM supports layer normalization. + * In case layer normalization is used, the inputs to internal activation + * functions (sigmoid and \f$g\f$) are normalized, rescaled and recentered + * following an approach from section 3.1 from + * https://arxiv.org/pdf/1607.06450.pdf + * + * The operation has the following independently optional inputs: + * * The cell-to-input weights (\f$W_{ci}\f$), cell-to-forget weights + * (\f$W_{cf}\f$) and cell-to-output weights (\f$W_{co}\f$) either all + * have values or neither of them have values (i.e., all set to null). If + * they have values, the peephole optimization is used. + * * The input-to-input weights (\f$W_{xi}\f$), recurrent-to-input weights + * (\f$W_{hi}\f$) and input gate bias (\f$b_i\f$) either all have values, + * or none of them have values. If they have no values, coupling of input + * and forget gates (CIFG) is used, in which case the input gate + * (\f$i_t\f$) is calculated using the following equation instead. + * \f{eqnarray*}{ + * i_t = 1 - f_t + * \f} + * In case peephole optimization is used and CIFG is not used + * cell-to-input (\f$W_{ci}\f$) weights must be present. Otherwise, the + * cell-to-input weights must have no value. + * * The projection weights (\f$W_{proj}\f$) is required only for the + * recurrent projection layer, and should otherwise have no value. + * * The projection bias (\f$b_{proj}\f$) may (but not required to) have a + * value if the recurrent projection layer exists, and should otherwise + * have no value. + * * (HAL version 1.2 or later) The four layer normalization weights either all have + * values or none of them have values. Additionally, if CIFG is used, + * input layer normalization weights tensor is omitted and the other layer + * normalization weights either all have values or none of them have + * values. Layer normalization is used when the values of all the layer + * normalization weights are present. + * + * References: + * + * The default non-peephole non-CIFG implementation is based on: + * http://www.bioinf.jku.at/publications/older/2604.pdf + * S. Hochreiter and J. Schmidhuber. "Long Short-Term Memory". Neural + * Computation, 9(8):1735-1780, 1997. + * + * The peephole implementation and projection layer is based on: + * https://research.google.com/pubs/archive/43905.pdf + * Hasim Sak, Andrew Senior, and Francoise Beaufays. "Long short-term memory + * recurrent neural network architectures for large scale acoustic + * modeling." INTERSPEECH, 2014. + * (However, the concept of peephole optimization was introduced in work + * prior to this paper.) + * + * The coupling of input and forget gate (CIFG) is based on: + * http://arxiv.org/pdf/1503.04069.pdf + * Greff et al. "LSTM: A Search Space Odyssey" + * + * The layer normalization is based on: + * https://arxiv.org/pdf/1607.06450.pdf + * Jimmy Ba et al. "Layer Normalization" + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * + * All input and output tensors must be of the same type. + * + * Inputs: + * * 0: The input (\f$x_t\f$). + * A 2-D tensor of shape [batch_size, input_size], where “batch_size” + * corresponds to the batching dimension, and “input_size” is the size + * of the input. + * * 1: The input-to-input weights (\f$W_{xi}\f$). Optional. + * A 2-D tensor of shape [num_units, input_size], where “num_units” + * corresponds to the number of cell units. + * * 2: The input-to-forget weights (\f$W_{xf}\f$). + * A 2-D tensor of shape [num_units, input_size]. + * * 3: The input-to-cell weights (\f$W_{xc}\f$). + * A 2-D tensor of shape [num_units, input_size]. + * * 4: The input-to-output weights (\f$W_{xo}\f$). + * A 2-D tensor of shape [num_units, input_size]. + * * 5: The recurrent-to-input weights (\f$W_{hi}\f$). Optional. + * A 2-D tensor of shape [num_units, output_size], where “output_size” + * corresponds to either the number of cell units (i.e., “num_units”), + * or the second dimension of the “projection_weights”, if defined. + * * 6: The recurrent-to-forget weights (\f$W_{hf}\f$). + * A 2-D tensor of shape [num_units, output_size]. + * * 7: The recurrent-to-cell weights (\f$W_{hc}\f$). + * A 2-D tensor of shape [num_units, output_size]. + * * 8: The recurrent-to-output weights (\f$W_{ho}\f$). + * A 2-D tensor of shape [num_units, output_size]. + * * 9: The cell-to-input weights (\f$W_{ci}\f$). Optional. + * A 1-D tensor of shape [num_units]. + * * 10:The cell-to-forget weights (\f$W_{cf}\f$). Optional. + * A 1-D tensor of shape [num_units]. + * * 11:The cell-to-output weights (\f$W_{co}\f$). Optional. + * A 1-D tensor of shape [num_units]. + * * 12:The input gate bias (\f$b_i\f$). Optional. + * A 1-D tensor of shape [num_units]. + * * 13:The forget gate bias (\f$b_f\f$). + * A 1-D tensor of shape [num_units]. + * * 14:The cell bias (\f$b_c\f$). + * A 1-D tensor of shape [num_units]. + * * 15:The output gate bias (\f$b_o\f$). + * A 1-D tensor of shape [num_units]. + * * 16:The projection weights (\f$W_{proj}\f$). Optional. + * A 2-D tensor of shape [output_size, num_units]. + * * 17:The projection bias (\f$b_{proj}\f$). Optional. + * A 1-D tensor of shape [output_size]. + * * 18:The output state (in) (\f$h_{t-1}\f$). + * A 2-D tensor of shape [batch_size, output_size]. + * * 19:The cell state (in) (\f$C_{t-1}\f$). + * A 2-D tensor of shape [batch_size, num_units]. + * * 20:The activation function (\f$g\f$). + * A value indicating the activation function: + *
      + *
    • 0: None; + *
    • 1: Relu; + *
    • 3: Relu6; + *
    • 4: Tanh; + *
    • 6: Sigmoid. + *
    + * * 21:The clipping threshold (\f$t_{cell}\f$) for the cell state, such + * that values are bound within [-cell_clip, cell_clip]. If set to 0.0 + * then clipping is disabled. + * Until HAL version 1.2 this scalar must be of type {@link + * OperandType::FLOAT32}. Since HAL version 1.2, if all the input + * tensors have type {@link OperandType::TENSOR_FLOAT32}, this + * scalar must be of the type {@link OperandType::FLOAT32}, + * otherwise if all the input tensors have the type {@link + * OperandType::TENSOR_FLOAT16}, this scalar must be of type {@link + * OperandType::FLOAT16}. + * * 22:The clipping threshold (\f$t_{proj}\f$) for the output from the + * projection layer, such that values are bound within + * [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled. + * Until HAL version 1.2 this scalar must be of type {@link + * OperandType::FLOAT32}. Since HAL version 1.2, if all the input + * tensors have type {@link OperandType::TENSOR_FLOAT32}, this + * scalar must be of the type {@link OperandType::FLOAT32}, + * otherwise if all the input tensors have the type {@link + * OperandType::TENSOR_FLOAT16}, this scalar must be of type {@link + * OperandType::FLOAT16}. + * Since HAL version 1.2 there are additional inputs to this op: + * * 23:The input layer normalization weights. + * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs + * to activation at input gate. + * * 24:The forget layer normalization weights. + * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs + * to activation at forget gate. + * * 25:The cell layer normalization weights. + * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs + * to activation at cell gate. + * * 26:The output layer normalization weights. + * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs + * to activation at output gate. + * + * Outputs: + * * 0: The scratch buffer. + * A 2-D tensor of shape [batch_size, num_units * 3] with CIFG, or + * [batch_size, num_units * 4] without CIFG. + * * 1: The output state (out) (\f$h_t\f$). + * A 2-D tensor of shape [batch_size, output_size]. + * * 2: The cell state (out) (\f$C_t\f$). + * A 2-D tensor of shape [batch_size, num_units]. + * * 3: The output (\f$o_t\f$). + * A 2-D tensor of shape [batch_size, output_size]. This is effectively + * the same as the current “output state (out)” value. + */ + LSTM = @1.2::OperationType:LSTM, + + /** + * Performs an 2-D max pooling operation. + * + * The output dimensions are functions of the filter dimensions, stride, and + * padding. + * + * The values in the output tensor are computed as: + * + * output[b, i, j, channel] = + * max_{di, dj} ( + * input[b, strides[1] * i + di, strides[2] * j + dj, channel] + * ) + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. + * + * Both explicit padding and implicit padding are supported. + * + * Inputs (explicit padding): + * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying + * the input. + * Since HAL version 1.2, zero batches is supported for this tensor. + * * 1: An {@link OperandType::INT32} scalar, specifying the padding on + * the left, in the ‘width’ dimension. + * * 2: An {@link OperandType::INT32} scalar, specifying the padding on + * the right, in the ‘width’ dimension. + * * 3: An {@link OperandType::INT32} scalar, specifying the padding on + * the top, in the ‘height’ dimension. + * * 4: An {@link OperandType::INT32} scalar, specifying the padding on + * the bottom, in the ‘height’ dimension. + * * 5: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘width’ dimension. + * * 6: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘height’ dimension. + * * 7: An {@link OperandType::INT32} scalar, specifying the filter + * width. + * * 8: An {@link OperandType::INT32} scalar, specifying the filter + * height. + * * 9: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * * 10: An optional {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * Available since HAL version 1.2. + * + * Inputs (implicit padding): + * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying + * the input. + * Since HAL version 1.2, zero batches is supported for this tensor. + * * 1: An {@link OperandType::INT32} scalar, specifying the implicit + * padding scheme, has to be one of the + * following values: {0 (NONE), 1 (SAME), 2 (VALID)}. + * * 2: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘width’ dimension. + * * 3: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘height’ dimension. + * * 4: An {@link OperandType::INT32} scalar, specifying the filter + * width. + * * 5: An {@link OperandType::INT32} scalar, specifying the filter + * height. + * * 6: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * * 7: An optional {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * Available since HAL version 1.2. + * + * Outputs: + * * 0: The output 4-D tensor, of shape + * [batches, out_height, out_width, depth]. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + MAX_POOL_2D = @1.2::OperationType:MAX_POOL_2D, + + /** + * Multiplies two tensors, element-wise. + * + * Takes two input tensors of identical {@link OperandType} and compatible + * dimensions. The output is the product of both input tensors, optionally + * modified by an activation function. + * + * Two dimensions are compatible when: + * 1. they are equal, or + * 2. one of them is 1 + * + * The size of the resulting output is the maximum size along each dimension + * of the input operands. It starts with the trailing dimensions, and works + * its way forward. + * + * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero + * dimension is only compatible with 0 or 1. The size of the output + * dimension is zero if either of corresponding input dimension is zero. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: A tensor. + * * 1: A tensor of the same {@link OperandType}, and compatible dimensions + * as input0. + * * 2: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * + * Outputs: + * * 0: The product, a tensor of the same {@link OperandType} as input0. + * For output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the following condition must be satisfied: + * output_scale > input1_scale * input2_scale. + */ + MUL = @1.2::OperationType:MUL, + + /** + * Computes rectified linear activation on the input tensor element-wise. + * + * The output is calculated using this formula: + * + * output = max(0, input) + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4. + * + * Inputs: + * * 0: A tensor, specifying the input. + * Since HAL version 1.2, this tensor may be zero-sized. + * + * Outputs: + * * 0: The output tensor of same shape as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + RELU = @1.2::OperationType:RELU, + + /** + * Computes rectified linear 1 activation on the input tensor element-wise. + * + * The output is calculated using this formula: + * + * output = min(1.f, max(-1.f, input)) + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4. + * + * Inputs: + * * 0: A tensor, specifying the input. + * Since HAL version 1.2, this tensor may be zero-sized. + * + * Outputs: + * * 0: The output tensor of the same shape as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + RELU1 = @1.2::OperationType:RELU1, + + /** + * Computes rectified linear 6 activation on the input tensor element-wise. + * + * The output is calculated using this formula: + * + * output = min(6, max(0, input)) + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4. + * + * Inputs: + * * 0: A tensor, specifying the input. + * Since HAL version 1.2, this tensor may be zero-sized. + * + * Outputs: + * * 0: The output tensor of same shape as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + RELU6 = @1.2::OperationType:RELU6, + + /** + * Reshapes a tensor. + * + * Given tensor, this operation returns a tensor that has the same values as + * tensor, but with a newly specified shape. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4. + * + * Inputs: + * * 0: A tensor, specifying the tensor to be reshaped. + * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}, defining the + * shape of the output tensor. The number of elements implied by shape + * must be the same as the number of elements in the input tensor. + * + * If one component of shape is the special value -1, the size of that + * dimension is computed so that the total size remains constant. In + * particular, a shape of [-1] flattens into 1-D. At most one component + * of shape can be -1. + * + * Outputs: + * * 0: The output tensor, of shape specified by the input shape. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + RESHAPE = @1.2::OperationType:RESHAPE, + + /** + * Resizes images to given size using the bilinear interpretation. + * + * Resized images must be distorted if their output aspect ratio is not the + * same as input aspect ratio. The corner pixels of output may not be the + * same as corner pixels of input. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. + * + * Both resizing by shape and resizing by scale are supported. + * + * Inputs (resizing by shape): + * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying + * the input. + * Since HAL version 1.2, zero batches is supported for this tensor. + * * 1: An {@link OperandType::INT32} scalar, specifying the output + * width of the output tensor. + * * 2: An {@link OperandType::INT32} scalar, specifying the output + * height of the output tensor. + * * 3: An optional {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * Available since HAL version 1.2. + * + * Inputs (resizing by scale, since HAL version 1.2): + * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying + * the input. Zero batches is supported for this tensor. + * * 1: A scalar, specifying width_scale, the scaling factor of the width + * dimension from the input tensor to the output tensor. The output + * width is calculated as new_width = floor(width * width_scale). + * The scalar must be of {@link OperandType::FLOAT16} if input0 is + * of {@link OperandType::TENSOR_FLOAT16} and of + * {@link OperandType::FLOAT32} otherwise. + * * 2: A scalar, specifying height_scale, the scaling factor of the height + * dimension from the input tensor to the output tensor. The output + * height is calculated as new_height = floor(height * height_scale). + * The scalar must be of {@link OperandType::FLOAT16} if input0 is + * of {@link OperandType::TENSOR_FLOAT16} and of + * {@link OperandType::FLOAT32} otherwise. + * * 3: An optional {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * + * Outputs: + * * 0: The output 4-D tensor, of shape + * [batches, new_height, new_width, depth]. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + RESIZE_BILINEAR = @1.2::OperationType:RESIZE_BILINEAR, + + /** + * A basic recurrent neural network layer. + * + * This layer implements the operation: + * outputs = state = activation(inputs * input_weights + + * state * recurrent_weights + bias) + * + * Where: + * * “input_weights” is a weight matrix that multiplies the inputs; + * * “recurrent_weights” is a weight matrix that multiplies the current + * “state” which itself is the output from the previous time step + * computation; + * * “bias” is a bias vector (added to each output vector in the batch); + * * “activation” is the function passed as the “fused_activation_function” + * argument (if not “NONE”). + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * + * The input tensors must all be the same type. + * + * Inputs: + * * 0: input. + * A 2-D tensor of shape [batch_size, input_size], where “batch_size” + * corresponds to the batching dimension, and “input_size” is the size + * of the input. + * * 1: weights. + * A 2-D tensor of shape [num_units, input_size], where “num_units” + * corresponds to the number of units. + * * 2: recurrent_weights. + * A 2-D tensor of shape [num_units, num_units], with columns + * corresponding to the weights from each unit. + * * 3: bias. + * A 1-D tensor of shape [num_units]. + * * 4: hidden state (in). + * A 2-D tensor of shape [batch_size, num_units]. + * * 5: fused_activation_function. + * An optional {@link FusedActivationFunc} value indicating the + * activation function. If “NONE” is specified then it results in a + * linear activation. + * + * Outputs: + * * 0: hidden state (out). + * A 2-D tensor of shape [batch_size, num_units]. + * + * * 1: output. + * A 2-D tensor of shape [batch_size, num_units]. This is effectively + * the same as the current state value. + */ + RNN = @1.2::OperationType:RNN, + + /** + * Computes the softmax activation on the input tensor element-wise, per + * batch, by normalizing the input vector so the maximum coefficient is + * zero. + * + * The output is calculated using this formula: + * + * output[batch, i] = + * exp((input[batch, i] - max(input[batch, :])) * beta) / + * sum_{k}{exp((input[batch, k] - max(input[batch, :])) * beta)} + * + * For input tensor with rank other than 2, the activation will be applied + * independently on each 1-D slice along specified dimension. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4. + * Tensors with rank other than 2 or 4 are only supported since HAL version 1.2. + * + * Inputs: + * * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped. + * Since HAL version 1.2, this tensor may be zero-sized. + * * 1: A scalar, specifying the positive scaling factor for the exponent, + * beta. If input0 is of {@link OperandType::TENSOR_FLOAT32} or + * {@link OperandType::TENSOR_QUANT8_ASYMM}, the scalar must be of + * {@link OperandType::FLOAT32}. + * If input0 is of {@link OperandType::TENSOR_FLOAT16}, then the + * scalar must be of {@link OperandType::FLOAT16}. + * * 2: An optional {@link OperandType::INT32} scalar, default to -1, + * specifying the dimension the activation would be performed on. + * Negative index is used to specify axis from the end (e.g. -1 for + * the last axis). Must be in the range [-n, n). + * Available since HAL version 1.2. + * + * Outputs: + * * 0: The output tensor of same shape as input0. + * For {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the scale must be 1.f / 256 and the zeroPoint must be 0. + */ + SOFTMAX = @1.2::OperationType:SOFTMAX, + + /** + * Rearranges blocks of spatial data, into depth. + * + * More specifically, this op outputs a copy of the input tensor where + * values from the height and width dimensions are moved to the depth + * dimension. The value block_size indicates the input block size and how + * the data is moved. + * + * Chunks of data of size block_size * block_size from depth are rearranged + * into non-overlapping blocks of size block_size x block_size. + * + * The depth of the output tensor is input_depth * block_size * block_size. + * The input tensor's height and width must be divisible by block_size. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. + * + * Inputs: + * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], + * specifying the input. + * * 1: An {@link OperandType::INT32} scalar, specifying the block_size. + * block_size must be >=1 and block_size must be a divisor of both the + * input height and width. + * * 2: An optional {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * Available since HAL version 1.2. + * + * Outputs: + * * 0: The output 4-D tensor, of shape [batches, height/block_size, + * width/block_size, depth_in*block_size*block_size]. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + SPACE_TO_DEPTH = @1.2::OperationType:SPACE_TO_DEPTH, + + /** + * SVDF op is a kind of stateful layer derived from the notion that a + * densely connected layer that's processing a sequence of input frames can + * be approximated by using a singular value decomposition of each of its + * nodes. The implementation is based on: + * + * https://research.google.com/pubs/archive/43813.pdf + * + * P. Nakkiran, R. Alvarez, R. Prabhavalkar, C. Parada. + * “Compressing Deep Neural Networks using a Rank-Constrained Topology”. + * INTERSPEECH, 2015. + * + * It processes the incoming input using a 2-stage filtering mechanism: + * * stage 1 performs filtering on the "features" dimension, whose outputs + * get pushed into a memory of fixed-size memory_size. + * * stage 2 performs filtering on the "time" dimension of the memory_size + * memoized outputs of stage 1. + * + * Specifically, for rank 1, this layer implements the operation: + * + * memory = push(conv1d(inputs, weights_feature, feature_dim, + * "PADDING_VALID")); + * outputs = activation(memory * weights_time + bias); + * + * Where: + * * “weights_feature” is a weights matrix that processes the inputs (by + * convolving the input with every “feature filter”), and whose outputs + * get pushed, stacked in order, into the fixed-size “memory” (the oldest + * entry gets dropped); + * * “weights_time” is a weights matrix that processes the “memory” (by a + * batched matrix multiplication on the num_units); + * * “bias” is an optional bias vector (added to each output vector in the + * batch); and + * * “activation” is the function passed as the “fused_activation_function” + * argument (if not “NONE”). + * + * Each rank adds a dimension to the weights matrices by means of stacking + * the filters. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * + * All input tensors must be the same type. + * + * Inputs: + * * 0: input. + * A 2-D tensor of shape [batch_size, input_size], where “batch_size” + * corresponds to the batching dimension, and “input_size” is the size + * of the input. + * * 1: weights_feature. + * A 2-D tensor of shape [num_units, input_size], where “num_units” + * corresponds to the number of units. + * * 2: weights_time. + * A 2-D tensor of shape [num_units, memory_size], where “memory_size” + * corresponds to the fixed-size of the memory. + * * 3: bias. + * An optional 1-D tensor of shape [num_units]. + * * 4: state (in). + * A 2-D tensor of shape [batch_size, (memory_size - 1) * num_units * rank]. + * * 5: rank. + * The rank of the SVD approximation. + * * 6: fused_activation_function. + * An optional {@link FusedActivationFunc} value indicating the + * activation function. If “NONE” is specified then it results in a + * linear activation. + * + * Outputs: + * * 0: state (out). + * A 2-D tensor of the same {@link OperandType} as the inputs, with shape + * [batch_size, (memory_size - 1) * num_units * rank]. + * * 1: output. + * A 2-D tensor of the same {@link OperandType} as the inputs, with shape + * [batch_size, num_units]. + */ + SVDF = @1.2::OperationType:SVDF, + + /** + * Computes hyperbolic tangent of input tensor element-wise. + * + * The output is calculated using this formula: + * + * output = tanh(input) + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) + * + * Supported tensor rank: up to 4. + * + * Inputs: + * * 0: A tensor, specifying the input. + * Since HAL version 1.2, this tensor may be zero-sized. + * + * Outputs: + * * 0: The output tensor of same shape as input0. + * For {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the scale must be 1.f / 128 and the zeroPoint must be 128. + */ + TANH = @1.2::OperationType:TANH, + + /** + * BatchToSpace for N-dimensional tensors. + * + * This operation reshapes the batch dimension (dimension 0) into M + 1 + * dimensions of shape block_shape + [batch], interleaves these blocks back + * into the grid defined by the spatial dimensions [1, ..., M], to obtain a + * result with the same rank as the input. + * + * This is the reverse of SpaceToBatch. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. + * + * Inputs: + * * 0: An n-D tensor, specifying the tensor to be reshaped + * * 1: A 1-D Tensor of {@link OperandType::TENSOR_INT32}, the block + * sizes for each spatial dimension of the input tensor. All values + * must be >= 1. + * * 2: An optional {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * Available since API level 29. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + BATCH_TO_SPACE_ND = @1.2::OperationType:BATCH_TO_SPACE_ND, + + /** + * Element-wise division of two tensors. + * + * Takes two input tensors of identical {@link OperandType} and compatible + * dimensions. The output is the result of dividing the first input tensor + * by the second, optionally modified by an activation function. + * + * Two dimensions are compatible when: + * 1. they are equal, or + * 2. one of them is 1 + * + * The size of the output is the maximum size along each dimension of the + * input operands. It starts with the trailing dimensions, and works its way + * forward. + * + * Example: + * input1.dimension = {4, 1, 2} + * input2.dimension = {5, 4, 3, 1} + * output.dimension = {5, 4, 3, 2} + * + * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero + * dimension is only compatible with 0 or 1. The size of the output + * dimension is zero if either of corresponding input dimension is zero. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: An n-D tensor, specifying the first input. + * * 1: A tensor of the same {@link OperandType}, and compatible dimensions + * as input0. + * * 2: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. + */ + DIV = @1.2::OperationType:DIV, + + /** + * Computes the mean of elements across dimensions of a tensor. + * + * Reduces the input tensor along the given dimensions to reduce. Unless + * keep_dims is true, the rank of the tensor is reduced by 1 for each entry + * in axis. If keep_dims is true, the reduced dimensions are retained with + * length 1. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: A tensor, specifying the input. + * * 1: A 1-D Tensor of {@link OperandType::TENSOR_INT32}. The dimensions + * to reduce. Must be in the range + * [-rank(input_tensor), rank(input_tensor)). + * + * NOTE: When the operation was introduced, the documentation + * incorrectly stated that if dimensions were empty, the operation + * would reduce across all dimensions. This behavior was never + * implemented. + * + * * 2: An {@link OperandType::INT32} scalar, keep_dims. If positive, + * retains reduced dimensions with length 1. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be same as input0. + */ + MEAN = @1.2::OperationType:MEAN, + + /** + * Pads a tensor. + * + * This operation pads a tensor according to the specified paddings. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * (full support since HAL version 1.2, see the output section) + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: An n-D tensor, specifying the tensor to be padded. + * * 1: A 2-D Tensor of {@link OperandType::TENSOR_INT32}, the paddings + * for each spatial dimension of the input tensor. The shape of the + * tensor must be {rank(input0), 2}. + * padding[i, 0] specifies the number of elements to be padded in the + * front of dimension i. + * padding[i, 1] specifies the number of elements to be padded after the + * end of dimension i. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. The + * output tensor has the same rank as input0, and each + * dimension of the output tensor has the same size as the + * corresponding dimension of the input tensor plus the size + * of the padding: + * output0.dimension[i] = + * padding[i, 0] + input0.dimension[i] + padding[i, 1] + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + * + * NOTE: Before HAL version 1.2, the pad value for + * {@link OperandType::TENSOR_QUANT8_ASYMM} is undefined. + * Since HAL version 1.2, the pad value is always the logical zero. + */ + PAD = @1.2::OperationType:PAD, + + /** + * SpaceToBatch for N-Dimensional tensors. + * + * This operation divides "spatial" dimensions [1, ..., M] of the input into + * a grid of blocks of shape block_shape, and interleaves these blocks with + * the "batch" dimension (0) such that in the output, the spatial dimensions + * [1, ..., M] correspond to the position within the grid, and the batch + * dimension combines both the position within a spatial block and the + * original batch position. Prior to division into blocks, the spatial + * dimensions of the input are optionally zero padded according to paddings. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * (full support since HAL version 1.2, see the output section) + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * NCHW is supported since HAL version 1.2. + * + * Inputs: + * * 0: An n-D tensor, specifying the input. + * * 1: A 1-D Tensor of {@link OperandType::TENSOR_INT32}, the block + * sizes for each spatial dimension of the input tensor. All values + * must be >= 1. + * * 2: A 2-D Tensor of {@link OperandType::TENSOR_INT32}, the paddings + * for each spatial dimension of the input tensor. All values must be + * >= 0. The shape of the tensor must be {M, 2}, where M is the number + * of spatial dimensions. + * padding[i, 0] specifies the number of element to be padded in the + * front of dimension i. + * padding[i, 1] specifies the number of element to be padded after the + * end of dimension i. + * * 3: An optional {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * Available since HAL version 1.2. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + * + * NOTE: Before HAL version 1.2, the pad value for + * {@link OperandType::TENSOR_QUANT8_ASYMM} is undefined. + * Since HAL version 1.2, the pad value is always the logical zero. + */ + SPACE_TO_BATCH_ND = @1.2::OperationType:SPACE_TO_BATCH_ND, + + /** + * Removes dimensions of size 1 from the shape of a tensor. + * + * Given a tensor input, this operation returns a tensor of the same + * {@link OperandType} with all dimensions of size 1 removed. If you don't + * want to remove all size 1 dimensions, you can remove specific size 1 + * dimensions by specifying the axes (input1). + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: An n-D tensor, the tensor to be squeezed. + * * 1: An optional 1-D tensor of {@link OperandType::TENSOR_INT32}. The + * dimensions to squeeze. If specified only squeezes the dimensions + * listed. Otherwise, squeezes all dimensions. The dimension index + * starts at 0. An error must be reported if squeezing a dimension that + * is not 1. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. Contains the + * same data as input, but has one or more dimensions of size 1 + * removed. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + SQUEEZE = @1.2::OperationType:SQUEEZE, + + /** + * Extracts a strided slice of a tensor. + * + * Roughly speaking, this op extracts a slice of size (end - begin) / stride + * from the given input tensor. Starting at the location specified by begin + * the slice continues by adding stride to the index until all dimensions + * are not less than end. Note that a stride can be negative, which causes a + * reverse slice. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: An n-D tensor, specifying the tensor to be sliced. + * * 1: begin, a 1-D tensor of {@link OperandType::TENSOR_INT32}. The + * starts of the dimensions of the input tensor to be sliced. The + * length must be of rank(input0). + * * 2: end, a 1-D tensor of {@link OperandType::TENSOR_INT32}. The + * ends of the dimensions of the input tensor to be sliced. The length + * must be of rank(input0). + * * 3: strides, a 1-D tensor of {@link OperandType::TENSOR_INT32}. The + * strides of the dimensions of the input tensor to be sliced. The + * length must be of rank(input0). The entries must be non-zero. + * * 4: begin_mask, an {@link OperandType::INT32} scalar. If the ith bit + * of begin_mask is set, begin[i] is ignored and the fullest possible + * range in that dimension is used instead. + * * 5: end_mask, an {@link OperandType::INT32} scalar. If the ith bit of + * end_mask is set, end[i] is ignored and the fullest possible range in + * that dimension is used instead. + * * 6: shrink_axis_mask, an {@link OperandType::INT32} scalar. If the + * ith bit of shrink_axis_mask is set, the ith dimension specification + * shrinks the dimensionality by 1, taking on the value at index + * begin[i]. In this case, the ith specification must define a + * slice of size 1, e.g. begin[i] = x, end[i] = x + 1. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0 and rank (n - k), + * where k is the number of bits set in shrink_axis_mask. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + STRIDED_SLICE = @1.2::OperationType:STRIDED_SLICE, + + /** + * Element-wise subtraction of two tensors. + * + * Takes two input tensors of identical {@link OperandType} and compatible + * dimensions. The output is the result of subtracting the second input + * tensor from the first one, optionally modified by an activation function. + * + * Two dimensions are compatible when: + * 1. they are equal, or + * 2. one of them is 1 + * + * The size of the output is the maximum size along each dimension of the + * input operands. It starts with the trailing dimensions, and works its way + * forward. + * + * Example: + * input1.dimension = {4, 1, 2} + * input2.dimension = {5, 4, 3, 1} + * output.dimension = {5, 4, 3, 2} + * + * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero + * dimension is only compatible with 0 or 1. The size of the output + * dimension is zero if either of corresponding input dimension is zero. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: An n-D tensor, specifying the first input. + * * 1: A tensor of the same {@link OperandType}, and compatible dimensions + * as input0. + * * 2: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from inputs' scale and zeroPoint. + */ + SUB = @1.2::OperationType:SUB, + + /** + * Transposes the input tensor, permuting the dimensions according to the + * perm tensor. + * + * The returned tensor's dimension i corresponds to the input dimension + * perm[i]. If perm is not given, it is set to (n-1...0), where n is the + * rank of the input tensor. Hence by default, this operation performs a + * regular matrix transpose on 2-D input Tensors. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: An n-D tensor, specifying the tensor to be transposed. + * Since HAL version 1.2, this tensor may be zero-sized. + * * 1: An optional 1-D Tensor of {@link OperandType::TENSOR_INT32}, + * the permutation of the dimensions of the input tensor. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + TRANSPOSE = @1.2::OperationType:TRANSPOSE, + + /** + * Computes the absolute value of a tensor, element-wise. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: from 1. + * + * Inputs: + * * 0: A tensor. + * + * Outputs: + * * 0: The output tensor of same shape as input0. + */ + ABS = @1.2::OperationType:ABS, + + /** + * Returns the index of the largest element along an axis. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * Inputs: + * * 0: An n-D tensor specifying the input. Must be non-empty. + * * 1: An {@link OperandType::INT32} scalar specifying the axis to + * reduce across. Negative index is used to specify axis from the + * end (e.g. -1 for the last axis). Must be in the range [-n, n). + * + * Outputs: + * * 0: An (n - 1)-D {@link OperandType::TENSOR_INT32} tensor. + */ + // There is no underscore in ARG_MAX to avoid name conflict with + // the macro defined in libc/kernel/uapi/linux/limits.h. + ARGMAX = @1.2::OperationType:ARGMAX, + + /** + * Returns the index of the smallest element along an axis. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * Inputs: + * * 0: An n-D tensor specifying the input. Must be non-empty. + * * 1: An {@link OperandType::INT32} scalar specifying the axis to + * reduce across. Negative index is used to specify axis from the + * end (e.g. -1 for the last axis). Must be in the range [-n, n). + * + * Outputs: + * * 0: An (n - 1)-D {@link OperandType::TENSOR_INT32} tensor. + */ + ARGMIN = @1.2::OperationType:ARGMIN, // See ARGMAX for naming discussion. + + /** + * Transform axis-aligned bounding box proposals using bounding box deltas. + * + * Given the positions of bounding box proposals and the corresponding + * bounding box deltas for each class, return the refined bounding box + * regions. The resulting bounding boxes are cliped against the edges of + * the image. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT16_ASYMM} + * + * Inputs: + * * 0: A 2-D Tensor of shape [num_rois, 4], specifying the locations of the + * bounding box proposals, each line with format [x1, y1, x2, y2]. + * For tensor of type {@link OperandType::TENSOR_QUANT16_ASYMM}, + * the zeroPoint must be 0 and the scale must be 0.125. Zero num_rois + * is supported for this tensor. + * * 1: A 2-D Tensor of shape [num_rois, num_classes * 4], specifying the + * bounding box delta for each region of interest and each class. The + * bounding box deltas are organized in the following order + * [dx, dy, dw, dh], where dx and dy is the relative correction factor + * for the center position of the bounding box with respect to the width + * and height, dw and dh is the log-scale relative correction factor + * for the width and height. For input0 of type + * {@link OperandType::TENSOR_QUANT16_ASYMM}, this tensor should be + * of {@link OperandType::TENSOR_QUANT8_ASYMM}. Zero num_rois is + * supported for this tensor. + * * 2: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape + * [num_rois], specifying the batch index of each box. Boxes with + * the same batch index are grouped together. Zero num_rois is + * supported for this tensor. + * * 3: A 2-D Tensor of shape [batches, 2], specifying the information of + * each image in the batch, each line with format + * [image_height, image_width]. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0, with shape + * [num_rois, num_classes * 4], specifying the coordinates of each + * output bounding box for each class, with format [x1, y1, x2, y2]. + * For type of {@link OperandType::TENSOR_QUANT16_ASYMM}, the + * scale must be 0.125 and the zero point must be 0. + */ + AXIS_ALIGNED_BBOX_TRANSFORM = @1.2::OperationType:AXIS_ALIGNED_BBOX_TRANSFORM, + + /** + * Performs a forward LSTM on the input followed by a backward LSTM. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: 3, either time-major or batch-major. + * + * All input and output tensors must be of the same type. + * + * + * Inputs: + * * 0: The input. + * A 3-D tensor of shape: + * If time-major: [max_time, batch_size, input_size] + * If batch-major: [batch_size, max_time, input_size] + * where "max_time" is the number of timesteps (sequence length), + * "batch_size" corresponds to the batching dimension, and + * "input_size" is the size of the input. + * * 1: The forward input-to-input weights. Optional. + * A 2-D tensor of shape [fw_num_units, input_size], where “fw_num_units” + * corresponds to the number of forward cell units. + * * 2: The forward input-to-forget weights. + * A 2-D tensor of shape [fw_num_units, input_size]. + * * 3: The forward input-to-cell weights. + * A 2-D tensor of shape [fw_num_units, input_size]. + * * 4: The forward input-to-output weights. + * A 2-D tensor of shape [fw_num_units, input_size]. + * * 5: The forward recurrent-to-input weights. Optional. + * A 2-D tensor of shape [fw_num_units, fw_output_size], where “fw_output_size” + * corresponds to either the number of cell units (i.e., fw_num_units), + * or the second dimension of the “fw_projection_weights”, if defined. + * * 6: The forward recurrent-to-forget weights. + * A 2-D tensor of shape [fw_num_units, fw_output_size]. + * * 7: The forward recurrent-to-cell weights. + * A 2-D tensor of shape [fw_num_units, fw_output_size]. + * * 8: The forward recurrent-to-output weights. + * A 2-D tensor of shape [fw_num_units, fw_output_size]. + * * 9: The forward cell-to-input weights. Optional. + * A 1-D tensor of shape [fw_num_units]. + * * 10: The forward cell-to-forget weights. Optional. + * A 1-D tensor of shape [fw_num_units]. + * * 11: The forward cell-to-output weights. Optional. + * A 1-D tensor of shape [fw_num_units]. + * * 12: The forward input gate bias. Optional. + * A 1-D tensor of shape [fw_num_units]. + * * 13: The forward forget gate bias. + * A 1-D tensor of shape [fw_num_units]. + * * 14: The forward cell gate bias. + * A 1-D tensor of shape [fw_num_units]. + * * 15: The forward output gate bias. + * A 1-D tensor of shape [fw_num_units]. + * * 16: The forward projection weights. Optional. + * A 2-D tensor of shape [fw_output_size, fw_num_units]. + * * 17: The forward projection bias. Optional. + * A 1-D tensor of shape [fw_output_size]. + * * 18: The backward input-to-input weights. Optional. + * A 2-D tensor of shape [bw_num_units, input_size], where “bw_num_units” + * corresponds to the number of backward cell units. + * * 19: The backward input-to-forget weights. + * A 2-D tensor of shape [bw_num_units, input_size]. + * * 20: The backward input-to-cell weights. + * A 2-D tensor of shape [bw_num_units, input_size]. + * * 21: The backward input-to-output weights. + * A 2-D tensor of shape [bw_num_units, input_size]. + * * 22: The backward recurrent-to-input weights. Optional. + * A 2-D tensor of shape [bw_num_units, bw_output_size], where “bw_output_size” + * corresponds to either the number of cell units (i.e., “bw_num_units”), + * or the second dimension of the “bw_projection_weights”, if defined. + * * 23: The backward recurrent-to-forget weights. + * A 2-D tensor of shape [bw_num_units, bw_output_size]. + * * 24: The backward recurrent-to-cell weights. + * A 2-D tensor of shape [bw_num_units, bw_output_size]. + * * 25: The backward recurrent-to-output weights. + * A 2-D tensor of shape [bw_num_units, bw_output_size]. + * * 26: The backward cell-to-input weights. Optional. + * A 1-D tensor of shape [bw_num_units]. + * * 27: The backward cell-to-forget weights. Optional. + * A 1-D tensor of shape [bw_num_units]. + * * 28: The backward cell-to-output weights. Optional. + * A 1-D tensor of shape [bw_num_units]. + * * 29: The backward input gate bias. Optional. + * A 1-D tensor of shape [bw_num_units]. + * * 30: The backward forget gate bias. + * A 1-D tensor of shape [bw_num_units]. + * * 31: The backward cell gate bias. + * A 1-D tensor of shape [bw_num_units]. + * * 32: The backward output gate bias. + * A 1-D tensor of shape [bw_num_units]. + * * 33: The backward projection weights. Optional. + * A 2-D tensor of shape [bw_output_size, bw_num_units]. + * * 34: The backward projection bias. Optional. + * A 1-D tensor of shape [bw_output_size]. + * * 35: The forward input activation state. + * A 2-D tensor of shape [batch_size, bw_output_size]. + * * 36: The forward input cell state. + * A 2-D tensor of shape [batch_size, bw_num_units]. + * * 37: The backward input activation state. + * A 2-D tensor of shape [batch_size, bw_output_size]. + * * 38: The backward input cell state. + * A 2-D tensor of shape [batch_size, bw_num_units]. + * * 39: The auxiliary input. Optional. + * A 3-D tensor of shape [max_time, batch_size, input_size], where “batch_size” + * corresponds to the batching dimension, and “input_size” is the size + * of the input. + * * 40: The forward auxiliary input-to-input weights. Optional. + * A 2-D tensor of shape [fw_num_units, input_size]. + * * 41: The forward auxiliary input-to-forget weights. Optional. + * A 2-D tensor of shape [fw_num_units, input_size]. + * * 42: The forward auxiliary input-to-cell weights. Optional. + * A 2-D tensor of shape [fw_num_units, input_size]. + * * 43: The forward auxiliary input-to-output weights. Optional. + * A 2-D tensor of shape [fw_num_units, input_size]. + * * 44: The backward auxiliary input-to-input weights. Optional. + * A 2-D tensor of shape [bw_num_units, input_size]. + * * 45: The backward auxiliary input-to-forget weights. Optional. + * A 2-D tensor of shape [bw_num_units, input_size]. + * * 46: The backward auxiliary input-to-cell weights. Optional. + * A 2-D tensor of shape [bw_num_units, input_size]. + * * 47: The backward auxiliary input-to-output weights. Optional. + * A 2-D tensor of shape [bw_num_units, input_size]. + * * 48: The activation function. + * A value indicating the activation function: + *
      + *
    • 0: None; + *
    • 1: Relu; + *
    • 3: Relu6; + *
    • 4: Tanh; + *
    • 6: Sigmoid. + *
    + * * 49: The clipping threshold for the cell state, such + * that values are bound within [-cell_clip, cell_clip]. If set to 0.0 + * then clipping is disabled. + * If all the input tensors have type {@link OperandType::TENSOR_FLOAT32}, + * this scalar must be of the type {@link OperandType::FLOAT32}, + * otherwise if all the input tensors have the type {@link OperandType::TENSOR_FLOAT16}, + * this scalar must be of type {@link OperandType::FLOAT16}. + * * 50: The clipping threshold for the output from the + * projection layer, such that values are bound within + * [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled. + * If all the input tensors have type {@link OperandType::TENSOR_FLOAT32}, + * this scalar must be of the type {@link OperandType::FLOAT32}, + * otherwise if all the input tensors have the type {@link OperandType::TENSOR_FLOAT16}, + * this scalar must be of type {@link OperandType::FLOAT16}. + * * 51: merge_outputs + * An {@link OperandType::BOOL} scalar specifying if the outputs + * from forward and backward cells should be merged. + * * 52: time_major + * An {@link OperandType::BOOL} scalar specifying the shape format + * of input and output tensors. + * * 53: The forward input layer normalization weights. Optional. + * A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs + * to activation at input gate. + * * 54: The forward forget layer normalization weights. Optional. + * A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs + * to activation at forget gate. + * * 55: The forward cell layer normalization weights. Optional. + * A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs + * to activation at cell gate. + * * 56: The forward output layer normalization weights. Optional. + * A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs + * to activation at output gate. + * * 57: The backward input layer normalization weights. Optional. + * A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs + * to activation at input gate. + * * 58: The backward forget layer normalization weights. Optional. + * A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs + * to activation at forget gate. + * * 59: The backward cell layer normalization weights. Optional. + * A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs + * to activation at cell gate. + * * 60: The backward output layer normalization weights. Optional. + * A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs + * to activation at output gate. + * + * Outputs: + * * 0: The forward output. + * A 3-D tensor of shape: + * If time-major and not merge_outputs: + * [max_time, batch_size, fw_output_size] + * If time-major and merge_outputs: + * [max_time, batch_size, fw_output_size + bw_output_size] + * If batch-major and not merge_outputs: + * [batch_size, max_time, fw_output_size] + * If batch-major and merge_outputs: + * [batch_size, max_time, fw_output_size + bw_output_size] + * * 1: The backward output. Unused if merge_outputs is true. + * A 3-D tensor of shape: + * If time-major: [max_time, batch_size, bw_output_size] + * If batch-major: [batch_size, max_time, bw_output_size] + */ + BIDIRECTIONAL_SEQUENCE_LSTM = @1.2::OperationType:BIDIRECTIONAL_SEQUENCE_LSTM, + + /** + * A recurrent neural network layer that applies a basic RNN cell to a + * sequence of inputs in forward and backward directions. + * + * This Op unrolls the input along the sequence dimension, and implements + * the following operation for each element in the sequence s = + * 1...sequence_length: + * fw_outputs[s] = fw_state = activation(inputs[s] * fw_input_weights’ + + * fw_state * fw_recurrent_weights’ + fw_bias) + * + * And for each element in sequence t = sequence_length : 1 + * bw_outputs[t] = bw_state = activation(inputs[t] * bw_input_weights’ + + * bw_state * bw_recurrent_weights’ + bw_bias) + * + * Where: + * * “{fw,bw}_input_weights” is a weight matrix that multiplies the inputs; + * * “{fw,bw}_recurrent_weights” is a weight matrix that multiplies the + * current “state” which itself is the output from the previous time step + * computation; + * * “{fw,bw}_bias” is a bias vector (added to each output vector in the + * batch); + * * “activation” is the function passed as the “fused_activation_function” + * argument (if not “NONE”). + * + * The op also supports an auxiliary input. Regular cell feeds one input + * into the two RNN cells in the following way: + * + * INPUT (INPUT_REVERSED) + * | | + * --------------------- + * | FW_RNN BW_RNN | + * --------------------- + * | | + * FW_OUT BW_OUT + * + * An op with an auxiliary input takes two inputs and feeds them into the + * RNN cells in the following way: + * + * AUX_INPUT (AUX_INPUT_REVERSED) + * | | + * INPUT | (INPUT_R'D.)| + * | | | | + * ----------------------- + * | \ / \ / | + * | FW_RNN BW_RNN | + * ----------------------- + * | | + * FW_OUT BW_OUT + * + * While stacking this op on top of itself, this allows to connect both + * forward and backward outputs from previous cell to the next cell's + * inputs. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * The input tensors must all be the same type. + * + * Inputs: + * * 0: input. + * A 3-D tensor. The shape is defined by the input 6 (timeMajor). If + * it is set to true, then the input has a shape [maxTime, batchSize, + * inputSize], otherwise the input has a shape [batchSize, maxTime, + * inputSize]. + * * 1: fwWeights. + * A 2-D tensor of shape [fwNumUnits, inputSize]. + * * 2: fwRecurrentWeights. + * A 2-D tensor of shape [fwNumUnits, fwNumUnits]. + * * 3: fwBias. + * A 1-D tensor of shape [fwNumUnits]. + * * 4: fwHiddenState. + * A 2-D tensor of shape [batchSize, fwNumUnits]. Specifies a hidden + * state input for the first time step of the computation. + * * 5: bwWeights. + * A 2-D tensor of shape [bwNumUnits, inputSize]. + * * 6: bwRecurrentWeights. + * A 2-D tensor of shape [bwNumUnits, bwNumUnits]. + * * 7: bwBias. + * A 1-D tensor of shape [bwNumUnits]. + * * 8: bwHiddenState + * A 2-D tensor of shape [batchSize, bwNumUnits]. Specifies a hidden + * state input for the first time step of the computation. + * * 9: auxInput. + * A 3-D tensor. The shape is the same as of the input 0. + * * 10:fwAuxWeights. + * A 2-D tensor of shape [fwNumUnits, inputSize]. + * * 11:bwAuxWeights. + * A 2-D tensor of shape [bwNumUnits, inputSize]. + * * 12:fusedActivationFunction. + * A {@link FusedActivationFunc} value indicating the activation function. If + * “NONE” is specified then it results in a linear activation. + * * 13:timeMajor + * An {@link OperandType::BOOL} scalar specifying the shape format + * of input and output tensors. + * * 14:mergeOutputs + * An {@link OperandType::BOOL} scalar specifying if the outputs + * from forward and backward cells are separate (if set to false) or + * concatenated (if set to true). + * Outputs: + * * 0: fwOutput. + * A 3-D tensor. The first two dimensions of the shape are defined by + * the input 6 (timeMajor) and the third dimension is defined by the + * input 14 (mergeOutputs). If timeMajor is set to true, then the first + * two dimensions are [maxTime, batchSize], otherwise they are set to + * [batchSize, maxTime]. If mergeOutputs is set to true, then the third + * dimension is equal to (fwNumUnits + bwNumUnits), otherwise it is set + * to fwNumUnits. + * * 1: bwOutput. + * A 3-D tensor. If the input 14 (mergeOutputs) is set to true, then + * this tensor is not produced. The shape is defined by the input 6 + * (timeMajor). If it is set to true, then the shape is set to + * [maxTime, batchSize, bwNumUnits], otherwise the shape is set to + * [batchSize, maxTime, bwNumUnits]. + */ + BIDIRECTIONAL_SEQUENCE_RNN = @1.2::OperationType:BIDIRECTIONAL_SEQUENCE_RNN, + + /** + * Greedily selects a subset of bounding boxes in descending order of score. + * + * This op applies NMS algorithm to each class. In each loop of execution, + * the box with maximum score gets selected and removed from the pending set. + * The scores of the rest of boxes are lowered according to the + * intersection-over-union (IOU) overlapping with the previously selected + * boxes and a specified NMS kernel method. Any boxes with score less + * than a threshold are removed from the pending set. + * + * Three NMS kernels are supported: + * * Hard: score_new = score_old * (1 if IoU < threshold else 0) + * * Linear: score_new = score_old * (1 if IoU < threshold else 1 - IoU) + * * Gaussian: score_new = score_old * exp(- IoU^2 / sigma) + * + * Axis-aligned bounding boxes are represented by its upper-left corner + * coordinate (x1,y1) and lower-right corner coordinate (x2,y2). A valid + * bounding box should satisfy x1 <= x2 and y1 <= y2. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Inputs: + * * 0: A 2-D Tensor of shape [num_rois, num_classes], specifying the score + * of each bounding box proposal. The boxes are grouped by batches in the + * first dimension. Zero num_rois is supported for this tensor. + * * 1: A 2-D Tensor specifying the bounding boxes of shape + * [num_rois, num_classes * 4], organized in the order [x1, y1, x2, y2]. + * The boxes are grouped by batches in the first dimension. The sequential + * order of the boxes corresponds with input0. For input0 of type + * {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should be of + * {@link OperandType::TENSOR_QUANT16_ASYMM}, with zeroPoint of 0 and + * scale of 0.125. Zero num_rois is supported for this tensor. + * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape + * [num_rois], specifying the batch index of each box. Boxes with + * the same batch index are grouped together. + * * 3: An {@link OperandType::FLOAT32} scalar, score_threshold. Boxes + * with scores lower than the threshold are filtered before sending + * to the NMS algorithm. + * * 4: An {@link OperandType::INT32} scalar, specifying the maximum + * number of selected bounding boxes for each image. Set to a negative + * value for unlimited number of output bounding boxes. + * * 5: An {@link OperandType::INT32} scalar, specifying the NMS + * kernel method, options are 0:hard, 1:linear, 2:gaussian. + * * 6: An {@link OperandType::FLOAT32} scalar, specifying the IoU + * threshold in hard and linear NMS kernel. This field is ignored if + * gaussian kernel is selected. + * * 7: An {@link OperandType::FLOAT32} scalar, specifying the sigma in + * gaussian NMS kernel. This field is ignored if gaussian kernel is + * not selected. + * * 8: An {@link OperandType::FLOAT32} scalar, nms_score_threshold. + * Boxes with scores lower than the threshold are dropped during the + * score updating phase in soft NMS. + * + * Outputs: + * * 0: A 1-D Tensor of the same {@link OperandType} as input0, with shape + * [num_output_rois], specifying the score of each output box. The boxes + * are grouped by batches, but the sequential order in each batch is not + * guaranteed. For type of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the scale and zero point must be the same as input0. + * * 1: A 2-D Tensor of the same {@link OperandType} as input1, with shape + * [num_output_rois, 4], specifying the coordinates of each + * output bounding box with the same format as input1. The sequential + * order of the boxes corresponds with output0. For type of + * {@link OperandType::TENSOR_QUANT16_ASYMM}, the scale must be + * 0.125 and the zero point must be 0. + * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape + * [num_output_rois], specifying the class of each output box. The + * sequential order of the boxes corresponds with output0. + * * 3: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape + * [num_output_rois], specifying the batch index of each box. Boxes + * with the same batch index are grouped together. + */ + BOX_WITH_NMS_LIMIT = @1.2::OperationType:BOX_WITH_NMS_LIMIT, + + /** + * Casts a tensor to a new type. + * + * This operation ignores the scale and zeroPoint of quanized tensors, + * e.g. it treats a {@link OperandType::TENSOR_QUANT8_ASYMM} input + * as a tensor of uint8 values. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * Inputs: + * * 0: A tensor. + * + * Outputs: + * * 0: A tensor with the same shape as input0. + */ + CAST = @1.2::OperationType:CAST, + + /** + * Shuffle the channels of the input tensor. + * + * Given an input tensor and a integer value of num_groups, CHANNEL_SHUFFLE + * divide the channel dimension into num_groups groups, and reorganize the + * channels by grouping channels with the same index in each group. + * + * Along the channel dimension, the output is calculated using this formula: + * + * output_channel[k * num_groups + g] = input_channel[g * group_size + k] + * + * where group_size = num_channels / num_groups + * + * The number of channels must be divisible by num_groups. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: An n-D tensor, specifying the tensor to be shuffled. + * * 1: An {@link OperandType::INT32} scalar, specifying the number of + * groups. + * * 2: An {@link OperandType::INT32} scalar, specifying the dimension + * channel shuffle would be performed on. Negative index is used to + * specify axis from the end (e.g. -1 for the last axis). Must be in + * the range [-n, n). + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} and same shape as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + CHANNEL_SHUFFLE = @1.2::OperationType:CHANNEL_SHUFFLE, + + /** + * Apply postprocessing steps to bounding box detections. + * + * Bounding box detections are generated by applying transformation on a set + * of predefined anchors with the bounding box deltas from bounding box + * regression. A final step of hard NMS is applied to limit the number of + * returned boxes. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Inputs: + * * 0: A 3-D Tensor of shape [batches, num_anchors, num_classes], specifying + * the score of each anchor with each class. Class 0 for each + * [batches, num_anchors, 0] is background and will be ignored. + * * 1: A 3-D Tensor of shape [batches, num_anchors, length_box_encoding], with + * the first four values in length_box_encoding specifying the bounding + * box deltas. The box deltas are encoded in the order of [dy, dx, dh, dw], + * where dy and dx is the linear-scale relative correction factor for the + * center position of the bounding box with respect to the width and height, + * dh and dw is the log-scale relative correction factor for the width and + * height. All the entries in length_box_encoding beyond the first four + * values are ignored in this operation. + * * 2: A 2-D Tensor of shape [num_anchors, 4], specifying the shape of each + * predefined anchor, with format [ctr_y, ctr_x, h, w], where ctr_y and + * ctr_x are the center position of the box, and h and w are the height + * and the width. + * * 3: An {@link OperandType::FLOAT32} scalar, specifying the scaling + * factor for dy in bounding box deltas. + * * 4: An {@link OperandType::FLOAT32} scalar, specifying the scaling + * factor for dx in bounding box deltas. + * * 5: An {@link OperandType::FLOAT32} scalar, specifying the scaling + * factor for dh in bounding box deltas. + * * 6: An {@link OperandType::FLOAT32} scalar, specifying the scaling + * factor for dw in bounding box deltas. + * * 7: An {@link OperandType::BOOL} scalar, set to true to use regular + * multi-class NMS algorithm that do NMS separately for each class, + * set to false for a faster algorithm that only do one single NMS + * using the highest class score.. + * * 8: An {@link OperandType::INT32} scalar, max_num_detections, specifying + * the maximum number of boxes for the output. Boxes with the lowest + * scores are discarded to meet the limit. + * * 9: An {@link OperandType::INT32} scalar, only used when input7 is + * set to false, specifying the maximum number of classes per detection. + * * 10: An {@link OperandType::INT32} scalar, only used when input7 is + * set to true, specifying the maximum number of detections when + * applying NMS algorithm for each single class. + * * 11: A scalar, score_threshold. Boxes with scores lower than the + * threshold are filtered before sending to the NMS algorithm. The + * scalar must be of {@link OperandType::FLOAT16} if input0 is of + * {@link OperandType::TENSOR_FLOAT16} and of + * {@link OperandType::FLOAT32} if input0 is of + * {@link OperandType::TENSOR_FLOAT32}. + * * 12: A scalar, specifying the IoU threshold for hard NMS. The scalar + * must be of {@link OperandType::FLOAT16} if input0 is of + * {@link OperandType::TENSOR_FLOAT16} and of + * {@link OperandType::FLOAT32} if input0 is of + * {@link OperandType::TENSOR_FLOAT32}. + * * 13: An {@link OperandType::BOOL} scalar, set to true to include + * background class in the list of label map for the output, set + * to false to not include the background. When the background + * class is included, it has label 0 and the output classes start + * at 1 in the label map, otherwise, the output classes start at 0. + * + * Outputs: + * * 0: A 2-D tensor of the same {@link OperandType} as input0, with shape + * [batches, max_num_detections], specifying the score of each output + * detections. + * * 1: A 3-D tensor of shape [batches, max_num_detections, 4], specifying the + * coordinates of each output bounding box, with format + * [y1, x1, y2, x2]. + * * 2: A 2-D {@link OperandType::TENSOR_INT32} tensor, of shape + * [batches, max_num_detections], specifying the class label for each + * output detection. + * * 3: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape [batches], + * specifying the number of valid output detections for each batch. + */ + DETECTION_POSTPROCESSING = @1.2::OperationType:DETECTION_POSTPROCESSING, + + /** + * For input tensors x and y, computes x == y elementwise. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_BOOL8} + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * This operation supports broadcasting. + * + * Inputs: + * * 0: A tensor. + * * 1: A tensor of the same {@link OperandType} and dimensions compatible + * with input0. + * + * Outputs: + * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. + */ + EQUAL = @1.2::OperationType:EQUAL, + + /** + * Computes exponential of x element-wise. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: from 1. + * + * Inputs: + * * 0: A tensor. + * + * Outputs: + * * 0: The output tensor of same shape as input0. + */ + EXP = @1.2::OperationType:EXP, + + /** + * Inserts a dimension of 1 into a tensor's shape. + * + * Given a tensor input, this operation inserts a dimension of 1 at the + * given dimension index of input's shape. The dimension index starts at + * zero; if you specify a negative dimension index, it is counted backward + * from the end. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * Inputs: + * * 0: An n-D tensor. + * * 1: An {@link OperandType::INT32} scalar specifying the dimension + * index to expand. Must be in the range [-(n + 1), (n + 1)). + * + * Outputs: + * * 0: An (n + 1)-D tensor with the same {@link OperandType} and data as + * input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + EXPAND_DIMS = @1.2::OperationType:EXPAND_DIMS, + + /** + * Gathers values along an axis. + * + * Produces an output tensor with shape + * input0.dimension[:axis] + indices.dimension + input0.dimension[axis + 1:] + * where: + * # Vector indices (output is rank(input0)). + * output[a_0, ..., a_n, i, b_0, ..., b_n] = + * input0[a_0, ..., a_n, indices[i], b_0, ..., b_n] + * + * # Higher rank indices (output is rank(input0) + rank(indices) - 1). + * output[a_0, ..., a_n, i, ..., j, b_0, ... b_n] = + * input0[a_0, ..., a_n, indices[i, ..., j], b_0, ..., b_n] + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * Inputs: + * * 0: An n-D tensor from which to gather values. + * * 1: An {@link OperandType::INT32} scalar specifying the axis. + * Negative index is used to specify axis from the end + * (e.g. -1 for the last axis). Must be in the range [-n, n). + * * 2: A k-D tensor {@link OperandType::TENSOR_INT32} of indices. + * The values must be in the bounds of the corresponding dimensions + * of input0. + * + * Outputs: + * * 0: An (n + k - 1)-D tensor with the same {@link OperandType} as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + GATHER = @1.2::OperationType:GATHER, + + /** + * Generate aixs-aligned bounding box proposals. + * + * Bounding box proposals are generated by applying transformation on a set + * of predefined anchors with the bounding box deltas from bounding box + * regression. A final step of hard NMS is applied to limit the number of + * returned boxes. + * + * Axis-aligned bounding boxes are represented by its upper-left corner + * coordinate (x1,y1) and lower-right corner coordinate (x2,y2). A valid + * bounding box should satisfy x1 <= x2 and y1 <= y2. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Inputs: + * * 0: A 4-D Tensor specifying the score of each anchor at each + * location. With "NHWC" data layout, the tensor shape is + * [batches, height, width, num_anchors]. With "NCHW" data layout, + * the tensor shape is [batches, num_anchors, height, width]. + * * 1: A 4-D Tensor specifying the bounding box deltas. With "NHWC" data + * layout, the tensor shape is [batches, height, width, num_anchors * 4]. + * With "NCHW" data layout, the tensor shape is + * [batches, num_anchors * 4, height, width]. The box deltas are encoded + * in the order of [dx, dy, dw, dh], where dx and dy is the linear-scale + * relative correction factor for the center position of the bounding box + * with respect to the width and height, dw and dh is the log-scale + * relative correction factor for the width and height. The last + * dimensions is the channel dimension. + * * 2: A 2-D Tensor of shape [num_anchors, 4], specifying the shape of each + * predefined anchor, with format [x1, y1, x2, y2]. For input0 of type + * {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should be of + * {@link OperandType::TENSOR_QUANT16_SYMM}, with scale of 0.125. + * * 3: A 2-D Tensor of shape [batches, 2], specifying the size of + * each image in the batch, with format [image_height, image_width]. + * For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM}, this + * tensor should be of {@link OperandType::TENSOR_QUANT16_SYMM}, with + * scale of 0.125. + * * 4: An {@link OperandType::FLOAT32} scalar, specifying the ratio + * from the height of original image to the height of feature map. + * * 5: An {@link OperandType::FLOAT32} scalar, specifying the ratio + * from the width of original image to the width of feature map. + * * 6: An {@link OperandType::INT32} scalar, specifying the maximum + * number of boxes before going into the hard NMS algorithm. Boxes + * with the lowest scores are discarded to meet the limit. Set to + * a non-positive value for unlimited number. + * * 7: An {@link OperandType::INT32} scalar, specifying the maximum + * number of boxes returning from the hard NMS algorithm. Boxes + * with the lowest scores are discarded to meet the limit. Set to + * a non-positive value for unlimited number. + * * 8: An {@link OperandType::FLOAT32} scalar, specifying the IoU + * threshold for hard NMS. + * * 9: An {@link OperandType::FLOAT32} scalar, min_size. Boxes with + * height or width lower than the absolute threshold are filtered out. + * * 10: An {@link OperandType::BOOL} scalar, set to true to specify + * NCHW data layout for input0 and input1. Set to false for NHWC. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0, of shape + * [num_output_rois], specifying the score of each output box. + * The boxes are grouped by batches, but the sequential order in + * each batch is not guaranteed. For type of + * {@link OperandType::TENSOR_QUANT8_ASYMM}, the scale and zero + * point must be the same as input0. + * * 1: A tensor of the same {@link OperandType} as input3, of shape + * [num_output_rois, 4], specifying the coordinates of each output + * bounding box for each class, with format [x1, y1, x2, y2]. + * The sequential order of the boxes corresponds with output0. + * For type of {@link OperandType::TENSOR_QUANT16_ASYMM}, the + * scale must be 0.125 and the zero point must be 0. + * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape + * [num_output_rois], specifying the batch index of each box. Boxes + * with the same batch index are grouped together. + */ + GENERATE_PROPOSALS = @1.2::OperationType:GENERATE_PROPOSALS, + + /** + * For input tensors x and y, computes x > y elementwise. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_BOOL8} + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * This operation supports broadcasting. + * + * Inputs: + * * 0: A tensor. + * * 1: A tensor of the same {@link OperandType} and dimensions compatible + * with input0. + * + * Outputs: + * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. + */ + GREATER = @1.2::OperationType:GREATER, + /** + * For input tensors x and y, computes x >= y elementwise. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_BOOL8} + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * This operation supports broadcasting. + * + * Inputs: + * * 0: A tensor. + * * 1: A tensor of the same {@link OperandType} and dimensions compatible + * with input0. + * + * Outputs: + * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. + */ + GREATER_EQUAL = @1.2::OperationType:GREATER_EQUAL, + + /** + * Performs a grouped 2-D convolution operation. + * + * Given an input tensor of shape [batches, height, width, depth_in] and a + * filter tensor of shape [depth_out, filter_height, filter_width, depth_group] + * containing depth_out convolutional filters of depth depth_group, GROUPED_CONV + * applies a group of different filters to each input channel group, then + * concatenates the results together. + * + * Specifically, the input channels are divided into num_groups groups, each with + * depth depth_group, i.e. depth_in = num_groups * depth_group. The convolutional + * filters are also divided into num_groups groups, i.e. depth_out is divisible + * by num_groups. GROUPED_CONV applies each group of filters to the corresponding + * input channel group, and the result are concatenated together. + * + * The output dimensions are functions of the filter dimensions, stride, and + * padding. + * + * The values in the output tensor are computed as: + * + * output[b, i, j, g * channel_multiplier + q] = + * sum_{di, dj, dk} ( + * input[b, strides[1] * i + di, strides[2] * j + dj, + * g * depth_group + dk] * + * filter[g * channel_multiplier + q, di, dj, dk] + * ) + bias[channel] + * + * where channel_multiplier = depth_out / num_groups + * + * Supported tensor {@link OperandType} configurations: + * * 16 bit floating point: + * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias. + * + * * 32 bit floating point: + * * * {@link OperandType::TENSOR_FLOAT32} for input, filter, output, and bias. + * + * * Quantized: + * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, filter, and output. + * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to + * * * input.scale * filter.scale). + * + * * Quantized with symmetric per channel quantization for the filter: + * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, and output. + * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter. + * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0, + * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * + * Both explicit padding and implicit padding are supported. + * + * Inputs (explicit padding): + * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], + * specifying the input, where depth_in = num_groups * depth_group. + * * 1: A 4-D tensor, of shape + * [depth_out, filter_height, filter_width, depth_group], specifying + * the filter, where depth_out must be divisible by num_groups. For + * tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} + * the channel dimension (channelDim at + * {@link SymmPerChannelQuantParams}) must be set to 0. + * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input + * tensor of type {@link OperandType::TENSOR_FLOAT32} or + * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same + * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint + * of 0 and bias_scale == input_scale * filter_scale. For filter tensor + * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias + * should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of + * 0 and bias_scale of 0. The actual scale of each value 'i' is equal to + * bias_scale[i] = input_scale * filter_scale[i]. + * * 3: An {@link OperandType::INT32} scalar, specifying the padding on + * the left, in the ‘width’ dimension. + * * 4: An {@link OperandType::INT32} scalar, specifying the padding on + * the right, in the ‘width’ dimension. + * * 5: An {@link OperandType::INT32} scalar, specifying the padding on + * the top, in the ‘height’ dimension. + * * 6: An {@link OperandType::INT32} scalar, specifying the padding on + * the bottom, in the ‘height’ dimension. + * * 7: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘width’ dimension. + * * 8: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘height’ dimension. + * * 9: An {@link OperandType::INT32} scalar, specifying the number of + groups. + * * 10: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * * 11: An {@link OperandType::BOOL} scalar, set to true to specify + * NCHW data layout for input0 and output0. Set to false for NHWC. + * + * Inputs (implicit padding): + * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], + * specifying the input, where depth_in = num_groups * depth_group. + * * 1: A 4-D tensor, of shape + * [depth_out, filter_height, filter_width, depth_group], specifying + * the filter, where depth_out must be divisible by num_groups. For + * tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} + * the channel dimension (SymmPerChannelQuantParams::channelDim) + * must be set to 0. + * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input + * tensor of type {@link OperandType::TENSOR_FLOAT32} or + * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same + * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint + * of 0 and bias_scale == input_scale * filter_scale. For filter tensor + * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias + * should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of + * 0 and bias_scale of 0. The actual scale of each value 'i' is equal to + * bias_scale[i] = input_scale * filter_scale[i]. + * * 3: An {@link OperandType::INT32} scalar, specifying the implicit + * padding scheme, has to be one of the + * following values: {0 (NONE), 1 (SAME), 2 (VALID)}. + * * 4: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘width’ dimension. + * * 5: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘height’ dimension. + * * 6: An {@link OperandType::INT32} scalar, specifying the number of + * groups. + * * 7: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * * 8: An {@link OperandType::BOOL} scalar, set to true to specify + * NCHW data layout for input0 and output0. Set to false for NHWC. + * + * Outputs: + * * 0: The output 4-D tensor, of shape + * [batches, out_height, out_width, depth_out]. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from inputs' scale and zeroPoint. + */ + GROUPED_CONV_2D = @1.2::OperationType:GROUPED_CONV_2D, + + /** + * Localize the maximum keypoints from heatmaps. + * + * This operation approximates the accurate maximum keypoint scores and + * indices after bicubic upscaling by using Taylor expansion up to the + * quadratic term. + * + * The bounding box is represented by its upper-left corner coordinate + * (x1,y1) and lower-right corner coordinate (x2,y2) in the original image. + * A valid bounding box should satisfy x1 <= x2 and y1 <= y2. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * + * Inputs: + * * 0: A 4-D Tensor of shape + * [num_boxes, heatmap_size, heatmap_size, num_keypoints], + * specifying the heatmaps, the height and width of heatmaps should + * be the same, and must be greater than or equal to 2. + * * 1: A 2-D Tensor of shape [num_boxes, 4], specifying the bounding boxes, + * each with format [x1, y1, x2, y2]. For input0 of type + * {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should + * be of {@link OperandType::TENSOR_QUANT16_ASYMM}, with zeroPoint + * of 0 and scale of 0.125. + * * 2: An {@link OperandType::BOOL} scalar, set to true to specify + * NCHW data layout for input0. Set to false for NHWC. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0, with shape + * [num_boxes, num_keypoints], specifying score of the keypoints. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from input0 scale and zeroPoint. + * * 1: A tensor of the same {@link OperandType} as input1, with shape + * [num_boxes, num_keypoints, 2], specifying the location of + * the keypoints, the second dimension is organized as + * [keypoint_x, keypoint_y]. + * For type of {@link OperandType::TENSOR_QUANT16_ASYMM}, the + * scale must be 0.125 and the zero point must be 0. + */ + HEATMAP_MAX_KEYPOINT = @1.2::OperationType:HEATMAP_MAX_KEYPOINT, + + /** + * Applies instance normalization to the input tensor. + * + * The values in the output tensor are computed as: + * + * output[b, h, w, c] = + * (input[b, h, w, c] - mean[b, c]) * gamma / + * sqrt(var[b, c] + epsilon) + beta + * + * Where the mean and variance are computed across the spatial dimensions: + * + * mean[b, c] = + * sum_{h, w}(input[b, h, w, c]) / sum(1) + * + * var[b, c] = + * sum_{h, w}(pow(input[b, h, w, c] - mean[b, c], 2)) / sum(1) + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * + * Inputs: + * * 0: An n-D tensor, specifying the tensor to be normalized. + * * 1: A scalar, specifying gamma, the scale applied to the normalized + * tensor. The scalar must be of {@link OperandType::FLOAT16} if + * input0 is of {@link OperandType::TENSOR_FLOAT16} and of + * {@link OperandType::FLOAT32} if input0 is of + * {@link OperandType::TENSOR_FLOAT32}. + * * 2: A scalar, specifying beta, the offset applied to the normalized + * tensor. The scalar must be of {@link OperandType::FLOAT16} if + * input0 is of {@link OperandType::TENSOR_FLOAT16} and of + * {@link OperandType::FLOAT32} if input0 is of + * {@link OperandType::TENSOR_FLOAT32}. + * * 3: A scalar, specifying epsilon, the small value added to variance to + * avoid dividing by zero. The scalar must be of {@link OperandType::FLOAT16} if + * input0 is of {@link OperandType::TENSOR_FLOAT16} and of + * {@link OperandType::FLOAT32} if input0 is of + * {@link OperandType::TENSOR_FLOAT32}. + * * 4: An {@link OperandType::BOOL} scalar, set to true to specify + * NCHW data layout for input0 and output0. Set to false for NHWC. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} and same shape as input0. + */ + INSTANCE_NORMALIZATION = @1.2::OperationType:INSTANCE_NORMALIZATION, + + /** + * For input tensors x and y, computes x < y elementwise. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_BOOL8} + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * This operation supports broadcasting. + * + * Inputs: + * * 0: A tensor. + * * 1: A tensor of the same {@link OperandType} and dimensions compatible + * with input0. + * + * Outputs: + * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. + */ + LESS = @1.2::OperationType:LESS, + + /** + * For input tensors x and y, computes x <= y elementwise. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_BOOL8} + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * This operation supports broadcasting. + * + * Inputs: + * * 0: A tensor. + * * 1: A tensor of the same {@link OperandType} and dimensions compatible + * with input0. + * + * Outputs: + * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. + */ + LESS_EQUAL = @1.2::OperationType:LESS_EQUAL, + + /** + * Computes natural logarithm of x element-wise. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: from 1. + * + * Inputs: + * * 0: A tensor. + * + * Outputs: + * * 0: The output tensor of same shape as input0. + */ + LOG = @1.2::OperationType:LOG, + + /** + * Returns the truth value of x AND y element-wise. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_BOOL8} + * + * Supported tensor rank: from 1 + * + * This operation supports broadcasting. + * + * Inputs: + * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. + * * 1: A tensor of {@link OperandType::TENSOR_BOOL8} and dimensions + * compatible with input0. + * + * Outputs: + * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. + */ + LOGICAL_AND = @1.2::OperationType:LOGICAL_AND, + + /** + * Computes the truth value of NOT x element-wise. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_BOOL8} + * + * Supported tensor rank: from 1. + * + * Inputs: + * * 0: A tensor. + * + * Outputs: + * * 0: The output tensor of same shape as input0. + */ + LOGICAL_NOT = @1.2::OperationType:LOGICAL_NOT, + + /** + * Returns the truth value of x OR y element-wise. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_BOOL8} + * + * Supported tensor rank: from 1 + * + * This operation supports broadcasting. + * + * Inputs: + * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. + * * 1: A tensor of {@link OperandType::TENSOR_BOOL8} and dimensions + * compatible with input0. + * + * Outputs: + * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. + */ + LOGICAL_OR = @1.2::OperationType:LOGICAL_OR, + + /** + * Computes the log softmax activations given logits. + * + * The output is calculated using this formula: + * + * output = logits * beta - log(reduce_sum(exp(logits * beta), axis)) + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: from 1. + * + * Inputs: + * * 0: A tensor specifying the input logits. + * * 1: A scalar, specifying the positive scaling factor for the exponent, + * beta. + * For input tensor of {@link OperandType::TENSOR_FLOAT16}, the beta + * value must be of {@link OperandType::FLOAT16}. + * For input tensor of {@link OperandType::TENSOR_FLOAT32}, the beta + * value must be of {@link OperandType::FLOAT32}. + * * 2: An {@link OperandType::INT32} scalar specifying the axis to + * reduce across. Negative index is used to specify axis from the + * end (e.g. -1 for the last axis). Must be in the range [-n, n). + * + * Outputs: + * * 0: The output tensor of the same {@link OperandType} and shape as + * input0. + */ + LOG_SOFTMAX = @1.2::OperationType:LOG_SOFTMAX, + + /** + * Returns the element-wise maximum of two tensors. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1. + * + * Inputs: + * * 0: A tensor. + * * 1: A tensor of the same {@link OperandType} and compatible dimensions + * with input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scales and zeroPoint can be different from input0 scale and zeroPoint. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from inputs' scale and zeroPoint. + */ + MAXIMUM = @1.2::OperationType:MAXIMUM, + + /** + * Returns the element-wise minimum of two tensors. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1. + * + * Inputs: + * * 0: A tensor. + * * 1: A tensor of the same {@link OperandType} and compatible dimensions + * with input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scales and zeroPoint can be different from input0 scale and zeroPoint. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from inputs' scale and zeroPoint. + */ + MINIMUM = @1.2::OperationType:MINIMUM, + + /** + * Computes numerical negative value element-wise. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * + * Supported tensor rank: from 1. + * + * Inputs: + * * 0: A tensor. + * + * Outputs: + * * 0: The output tensor of same shape as input0. + */ + NEG = @1.2::OperationType:NEG, + + /** + * For input tensors x and y, computes x != y elementwise. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_BOOL8} + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * This operation supports broadcasting. + * + * Inputs: + * * 0: A tensor. + * * 1: A tensor of the same {@link OperandType} and dimensions compatible + * with input0. + * + * Outputs: + * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}. + */ + NOT_EQUAL = @1.2::OperationType:NOT_EQUAL, + + /** + * Pads a tensor with the given constant value according to the specified + * paddings. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: An n-D tensor, specifying the tensor to be padded. + * * 1: A 2-D Tensor of {@link OperandType::TENSOR_INT32}, the paddings + * for each spatial dimension of the input tensor. The shape of the + * tensor must be {rank(input0), 2}. + * padding[i, 0] specifies the number of elements to be padded in the + * front of dimension i. + * padding[i, 1] specifies the number of elements to be padded after + * the end of dimension i. + * * 2: An scalar specifying the value to use for padding input0. + * For input tensor of {@link OperandType::TENSOR_FLOAT16}, the + * pad value must be of {@link OperandType::FLOAT16}. + * For input tensor of {@link OperandType::TENSOR_FLOAT32}, the + * pad value must be of {@link OperandType::FLOAT32}. + * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the pad value must be of {@link OperandType::INT32}. The + * scale and zeroPoint are assumed to be the same as in input0. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. The + * output tensor has the same rank as input0, and each + * dimension of the output tensor has the same size as the + * corresponding dimension of the input tensor plus the size + * of the padding: + * output0.dimension[i] = + * padding[i, 0] + input0.dimension[i] + padding[i, 1] + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + PAD_V2 = @1.2::OperationType:PAD_V2, + + /** + * Computes the power of one value to another. + * + * Given a tensor base and a tensor exponent, this operation computes + * base^exponent elementwise. + * + * This operations supports broadcasting. The size of the output is the + * maximum size along each dimension of the input operands. It starts with + * the trailing dimensions, and works its way forward. + * + * For example: + * base.dimension = {4, 1, 2} + * exponent.dimension = {5, 4, 3, 1} + * output.dimension = {5, 4, 3, 2} + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: from 1 + * + * Inputs: + * * 0: A tensor specifying the base. + * * 1: A tensor specifying the exponent. + * + * Outputs: + * * 0: An output tensor. + */ + POW = @1.2::OperationType:POW, + + /** + * Parametric Rectified Linear Unit. + * + * It follows: f(x) = alpha * x for x < 0, f(x) = x for x >= 0, where alpha + * is a learned array with the same {@link OperandType} and compatible + * dimensions as input x. + * + * Two dimensions are compatible when: + * 1. they are equal, or + * 2. one of them is 1 + * + * The size of the output is the maximum size along each dimension of the + * input operands. It starts with the trailing dimensions, and works its way + * forward. + * + * Example: + * input.dimension = {4, 1, 2} + * alpha.dimension = {5, 4, 3, 1} + * output.dimension = {5, 4, 3, 2} + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * Inputs: + * * 0: A tensor, specifying the input. + * * 1: A tensor of the same {@link OperandType}, and compatible dimensions + * as input0, specifying the alpha. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be diffent from the input0 scale and zeroPoint. + */ + PRELU = @1.2::OperationType:PRELU, + + /** + * Quantizes the input tensor. + * + * The formula is: + * + * output = max(0, min(255, round(input / scale) + zeroPoint) + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: from 1 + * + * Inputs: + * * 0: A tensor, may be zero-sized. + * + * Outputs: + * * 0: The output tensor of same shape as input0, but with + * {@link OperandType::TENSOR_QUANT8_ASYMM}. + */ + QUANTIZE = @1.2::OperationType:QUANTIZE, + + /** + * A version of quantized LSTM, using 16 bit quantization for internal + * state. + * + * There is no projection layer, so cell state size is equal to the output + * size. + * + * Inputs: + * * 0: A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM} + * and shape [numBatches, inputSize] specifying the input to the LSTM + * cell. Tensor is quantized with a fixed quantization range of + * [-1, 127/128] (scale = 1/128, zeroPoint = 128). + * * 1: The input-to-input weights. + * A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM} + * and shape [outputSize, inputSize] specifying input-to-input part of + * weights for fully-connected layer inside the LSTM cell. + * Quantization zero point and scale must be the same across all the + * weights. + * * 2: The input-to-forget weights. + * A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM} + * and shape [outputSize, inputSize] specifying input-to-forget part of + * weights for fully-connected layer inside the LSTM cell. + * Quantization zero point and scale must be the same across all the + * weights. + * * 3: The input-to-cell weights. + * A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM} + * and shape [outputSize, inputSize] specifying input-to-cell part of + * weights for fully-connected layer inside the LSTM cell. + * Quantization zero point and scale must be the same across all the + * weights. + * * 4: The input-to-output weights. + * A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM} + * and shape [outputSize, inputSize] specifying input-to-output part of + * weights for fully-connected layer inside the LSTM cell. + * Quantization zero point and scale must be the same across all the + * weights. + * * 5: The recurrent-to-input weights. + * A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM} + * and shape [outputSize, outputSize] specifying recurrent-to-input part + * of weights for fully-connected layer inside the LSTM cell. + * Quantization zero point and scale must be the same across all the + * weights. + * * 6: The recurrent-to-forget weights. + * A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM} + * and shape [outputSize, outputSize] specifying recurrent-to-forget + * part of weights for fully-connected layer inside the LSTM cell. + * Quantization zero point and scale must be the same across all the + * weights. + * * 7: The recurrent-to-cell weights. + * A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM} + * and shape [outputSize, outputSize] specifying recurrent-to-cell part + * of weights for fully-connected layer inside the LSTM cell. + * Quantization zero point and scale must be the same across all the + * weights. + * * 8: The recurrent-to-output weights. + * A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM} + * and shape [outputSize, outputSize] specifying recurrent-to-output + * part of weights for fully-connected layer inside the LSTM cell. + * Quantization zero point and scale must be the same across all the + * weights. + * * 9: The input gate bias. + * A 1-D tensor of type {@link OperandType::TENSOR_INT32} and shape + * [outputSize] specifying the bias for the fully-connected layer + * inside the LSTM cell. Bias is quantized with scale being a product + * of input and weights scales and zeroPoint equal to 0. + * * 10:The forget gate bias. + * A 1-D tensor of type {@link OperandType::TENSOR_INT32} and shape + * [outputSize] specifying the bias for the fully-connected layer + * inside the LSTM cell. Bias is quantized with scale being a product + * of input and weights scales and zeroPoint equal to 0. + * * 11:The cell bias. + * A 1-D tensor of type {@link OperandType::TENSOR_INT32} and shape + * [outputSize] specifying the bias for the fully-connected layer + * inside the LSTM cell. Bias is quantized with scale being a product + * of input and weights scales and zeroPoint equal to 0. + * * 12:The output gate bias. + * A 1-D tensor of type {@link OperandType::TENSOR_INT32} and shape + * [outputSize] specifying the bias for the fully-connected layer + * inside the LSTM cell. Bias is quantized with scale being a product + * of input and weights scales and zeroPoint equal to 0. + * * 13: A 2-D tensor of type {@link OperandType::TENSOR_QUANT16_SYMM} + * and shape [numBatches, outputSize] specifying the cell state from the + * previous time step of the LSTM cell. It is quantized using a + * quantization range of [-2^4, 2^4 * 32767/32768] (scale = 2^4 / + * 32768, zeroPoint = 0). + * * 14: A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM} + * and shape [numBathes, outputSize] specifying the output of the LSTM + * cell from previous time-step. Tensor is quantized with a fixed + * quantization range of [-1, 127/128] (scale = 1/128, zeroPoint = + * 128). + * + * + * Outputs: + * * 0: A 2-D tensor of type {@link OperandType::TENSOR_QUANT16_SYMM} + * and shape [numBatches, outputSize] which contains a cell state from + * the current time step. Tensor is quantized using a quantization + * range of [-2^4, 2^4 * 32767/32768] (scale = 2^4 / 32768, zeroPoint = + * 0). + * * 1: A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM} + * and shape [numBathes, outputSize] which contains the output value. + * Tensor is quantized with a fixed quantization range of [-1, 127/128] + * (scale = 1/128, zeroPoint = 128). + */ + QUANTIZED_16BIT_LSTM = @1.2::OperationType:QUANTIZED_16BIT_LSTM, + + /** + * Draws samples from a multinomial distribution. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Inputs: + * * 0: A 2-D tensor with shape [batches, classes], specifying the + * unnormalized log-probabilities for all classes. + * * 1: A scalar {@link OperandType::INT32}, specifying the number of + * independent samples to draw for each row slice. + * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor with shape [2], + * specifying seeds used to initialize the random distribution. + * Outputs: + * * 0: A 2-D {@link OperandType::TENSOR_INT32} tensor with shape + * [batches, samples], containing the drawn samples. + */ + RANDOM_MULTINOMIAL = @1.2::OperationType:RANDOM_MULTINOMIAL, + + /** + * Reduces a tensor by computing the "logical and" of elements along given + * dimensions. + * + * If keep_dims is true, the reduced dimensions are + * retained with length 1. Otherwise, the rank of the tensor is reduced by + * 1 for each entry in dimensions. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_BOOL8} + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: An n-D tensor. + * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions + * to reduce. Dimension values must be in the range [-n, n). + * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true, + * retains reduced dimensions with length 1. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. + */ + REDUCE_ALL = @1.2::OperationType:REDUCE_ALL, + + /** + * Reduces a tensor by computing the "logical or" of elements along given + * dimensions. + * + * If keep_dims is true, the reduced dimensions are + * retained with length 1. Otherwise, the rank of the tensor is reduced by + * 1 for each entry in dimensions. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_BOOL8} + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: An n-D tensor. + * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions + * to reduce. Dimension values must be in the range [-n, n). + * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true, + * retains reduced dimensions with length 1. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. + */ + REDUCE_ANY = @1.2::OperationType:REDUCE_ANY, + + /** + * Reduces a tensor by computing the maximum of elements along given + * dimensions. + * + * If keep_dims is true, the reduced dimensions are + * retained with length 1. Otherwise, the rank of the tensor is reduced by + * 1 for each entry in dimensions. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: An n-D tensor. + * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions + * to reduce. Dimension values must be in the range [-n, n). + * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true, + * retains reduced dimensions with length 1. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + REDUCE_MAX = @1.2::OperationType:REDUCE_MAX, + + /** + * Reduces a tensor by computing the minimum of elements along given + * dimensions. + * + * If keep_dims is true, the reduced dimensions are + * retained with length 1. Otherwise, the rank of the tensor is reduced by + * 1 for each entry in dimensions. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: An n-D tensor. + * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions + * to reduce. Dimension values must be in the range [-n, n). + * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true, + * retains reduced dimensions with length 1. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + REDUCE_MIN = @1.2::OperationType:REDUCE_MIN, + + /** + * Reduces a tensor by multiplying elements along given dimensions. + * + * If keep_dims is true, the reduced dimensions are + * retained with length 1. Otherwise, the rank of the tensor is reduced by + * 1 for each entry in dimensions. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: An n-D tensor. + * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions + * to reduce. Dimension values must be in the range [-n, n). + * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true, + * retains reduced dimensions with length 1. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. + */ + REDUCE_PROD = @1.2::OperationType:REDUCE_PROD, + + /** + * Reduces a tensor by summing elements along given dimensions. + * + * If keep_dims is true, the reduced dimensions are + * retained with length 1. Otherwise, the rank of the tensor is reduced by + * 1 for each entry in dimensions. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: up to 4 + * + * Inputs: + * * 0: An n-D tensor. + * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions + * to reduce. Dimension values must be in the range [-n, n). + * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true, + * retains reduced dimensions with length 1. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. + */ + REDUCE_SUM = @1.2::OperationType:REDUCE_SUM, + + /** + * Select and scale the feature map of each region of interest to a unified + * output size by average pooling sampling points from bilinear interpolation. + * + * The region of interest is represented by its upper-left corner coordinate + * (x1,y1) and lower-right corner coordinate (x2,y2) in the original image. + * A spatial scaling factor is applied to map into feature map coordinate. + * A valid region of interest should satisfy x1 <= x2 and y1 <= y2. + * + * No rounding is applied in this operation. The sampling points are unified + * distributed in the pooling bin and their values are calculated by bilinear + * interpolation. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * + * Inputs: + * * 0: A 4-D tensor, specifying the feature map. + * * 1: A 2-D Tensor of shape [num_rois, 4], specifying the locations of + * the regions of interest, each line with format [x1, y1, x2, y2]. + * For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM}, + * this tensor should be of {@link OperandType::TENSOR_QUANT16_ASYMM}, + * with zeroPoint of 0 and scale of 0.125. Zero num_rois is + * supported for this tensor. + * * 2: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape + * [num_rois], specifying the batch index of each box. Boxes with + * the same batch index are grouped together. Zero num_rois is + * supported for this tensor. + * * 3: An {@link OperandType::INT32} scalar, specifying the output + * height of the output tensor. + * * 4: An {@link OperandType::INT32} scalar, specifying the output + * width of the output tensor. + * * 5: An {@link OperandType::FLOAT32} scalar, specifying the ratio + * from the height of original image to the height of feature map. + * * 6: An {@link OperandType::FLOAT32} scalar, specifying the ratio + * from the width of original image to the width of feature map. + * * 7: An {@link OperandType::INT32} scalar, specifying the number of + * sampling points in height dimension used to compute the output. + * Set to 0 for adaptive value of ceil(roi_height/out_height). + * * 8: An {@link OperandType::INT32} scalar, specifying the number of + * sampling points in width dimension used to compute the output. + * Set to 0 for adaptive value of ceil(roi_width/out_width). + * * 9: An {@link OperandType::BOOL} scalar, set to true to specify + * NCHW data layout for input0 and output0. Set to false for NHWC. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. The output + * shape is [num_rois, out_height, out_width, depth]. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from the input0 scale and zeroPoint. + */ + ROI_ALIGN = @1.2::OperationType:ROI_ALIGN, + + /** + * Select and scale the feature map of each region of interest to a unified + * output size by max-pooling. + * + * The region of interest is represented by its upper-left corner coordinate + * (x1,y1) and lower-right corner coordinate (x2,y2) in the original image. + * A spatial scaling factor is applied to map into feature map coordinate. + * A valid region of interest should satisfy x1 <= x2 and y1 <= y2. + * + * Rounding is applied in this operation to ensure integer boundary for + * regions of interest and pooling bins. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * + * Inputs: + * * 0: A 4-D tensor, specifying the feature map. + * * 1: A 2-D Tensor of shape [num_rois, 4], specifying the locations of + * the regions of interest, each line with format [x1, y1, x2, y2]. + * For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM}, + * this tensor should be of {@link OperandType::TENSOR_QUANT16_ASYMM}, + * with zeroPoint of 0 and scale of 0.125. + * * 2: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape + * [num_rois], specifying the batch index of each box. Boxes with + * the same batch index are grouped together. + * * 3: An {@link OperandType::INT32} scalar, specifying the output + * height of the output tensor. + * * 4: An {@link OperandType::INT32} scalar, specifying the output + * width of the output tensor. + * * 5: An {@link OperandType::FLOAT32} scalar, specifying the ratio + * from the height of original image to the height of feature map. + * * 6: An {@link OperandType::FLOAT32} scalar, specifying the ratio + * from the width of original image to the width of feature map. + * * 7: An {@link OperandType::BOOL} scalar, set to true to specify + * NCHW data layout for input0 and output0. Set to false for NHWC. + * + * Outputs: + * * 0: A tensor of the same {@link OperandType} as input0. The output + * shape is [num_rois, out_height, out_width, depth]. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + ROI_POOLING = @1.2::OperationType:ROI_POOLING, + + /** + * Computes reciprocal of square root of x element-wise. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: from 1. + * + * Inputs: + * * 0: A tensor. + * + * Outputs: + * * 0: The output tensor of same shape as input0. + */ + RSQRT = @1.2::OperationType:RSQRT, + + /** + * Using a tensor of booleans c and input tensors x and y select values + * elementwise from both input tensors: + * + * O[i] = C[i] ? x[i] : y[i]. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * Inputs: + * * 0: A tensor of type {@link OperandType::TENSOR_BOOL8} acting as a + * mask that chooses, based on the value at each element, whether the + * corresponding element in the output should be taken from input1 (if + * true) or input2 (if false). + * * 1: An input tensor of the same shape as input0. + * * 2: An input tensor of the same shape and type as input1. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scales and zeroPoint can be different from input1 scale and zeroPoint. + * + * Outputs: + * * 0: A tensor of the same type and shape as input1 and input2. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from inputs' scale and zeroPoint. + * + */ + SELECT = @1.2::OperationType:SELECT, + + /** + * Computes sin of x element-wise. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: from 1. + * + * Inputs: + * * 0: A tensor. + * + * Outputs: + * * 0: The output tensor of same shape as input0. + */ + SIN = @1.2::OperationType:SIN, + + /** + * Extracts a slice of specified size from the input tensor starting at a + * specified location. + * + * The starting location is specified as a 1-D tensor containing offsets + * for each dimension. The size is specified as a 1-D tensor containing + * either size of a slice along corresponding dimension or -1. In the latter + * case, all the remaining elements in dimension are included in the slice. + * + * A sum of begin offset and a size of a slice must not exceed size of a + * corresponding dimension. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * Inputs: + * * 0: An n-D tensor to take slice from, may be zero-sized. + * * 1: A 1-D tensor of type {@link OperandType::TENSOR_INT32} specifying + * the beginning indices of the slice in each dimension. + * * 2: A 1-D tensor of type {@link OperandType::TENSOR_INT32} specifying + * the size of the slice in each dimension. + * + * Outputs: + * * 0: An n-D tensor of the same type as the input containing the slice. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * its scale and zeroPoint has to be same as the input0 scale and zeroPoint. + */ + SLICE = @1.2::OperationType:SLICE, + + /** + * Splits a tensor along a given axis into num_splits subtensors. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * Inputs: + * * 0: An n-D tensor to split. + * * 1: An {@link OperandType::INT32} scalar specifying the axis along + * which to split. + * * 2: An {@link OperandType::INT32} scalar indicating the number of + * splits along given axis. Must evenly divide axis size. + * + * Outputs: + * * 0 ~ (num_splits - 1): Resulting subtensors. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + SPLIT = @1.2::OperationType:SPLIT, + + /** + * Computes square root of x element-wise. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: from 1. + * + * Inputs: + * * 0: A tensor. + * + * Outputs: + * * 0: The output tensor of same shape as input0. + */ + SQRT = @1.2::OperationType:SQRT, + + /** + * Constructs a tensor by tiling a given tensor. + * + * This operation creates a new tensor by replicating `input` `multiples` + * times. The output tensor's i-th dimension has `input.dims(i) * multiples[i]` + * elements, and the values of `input` are replicated `multiples[i]` times + * along the i-th dimension. + * For example, tiling `[a b c d]` by `[2]` produces `[a b c d a b c d]`. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * Inputs: + * * 0: input, an n-D tensor specifying the input. + * * 1: multiples, a 1-D tensor of {@link OperandType::TENSOR_INT32}. + * The length of multiples must be n. + * + * Outputs: + * * 0: A tiled tensor of the same {@link OperandType} and rank as `input`. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + TILE = @1.2::OperationType:TILE, + + /** + * Finds values and indices of the k largest entries for the last dimension. + * + * Resulting values in each dimensions are sorted in descending order. If + * two values are equal, the one with larger index appears first. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: from 1 + * + * Inputs: + * * 0: input, an n-D tensor specifying the input. + * * 1: k, an {@link OperandType::INT32} scalar, specifying the number of + * top elements to look for along the last dimension. + * + * Outputs: + * * 0: An n-D tensor of the same type as the input, containing the k + * largest elements along each last dimensional slice. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + * * 1: An n-D tensor of type {@link OperandType::TENSOR_INT32} + * containing the indices of values within the last dimension of input. + */ + TOPK_V2 = @1.2::OperationType:TOPK_V2, + + /** + * Performs the transpose of 2-D convolution operation. + * + * This operation is sometimes called "deconvolution" after Deconvolutional + * Networks, but is actually the transpose (gradient) of + * {@link OperandType::CONV_2D} rather than an actual deconvolution. + * + * The output dimensions are functions of the filter dimensions, stride, and + * padding. + * + * Supported tensor {@link OperandType} configurations: + * * 16 bit floating point: + * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias. + * + * * 32 bit floating point: + * * * {@link OperandType::TENSOR_FLOAT32} for input, filter, output, and bias. + * + * * Quantized: + * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, filter, and output. + * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to + * * * input.scale * filter.scale). + * + * * Quantized with symmetric per channel quantization for the filter: + * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, and output. + * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter. + * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0, + * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * + * Both explicit padding and implicit padding are supported. + * + * Inputs (explicit padding): + * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], + * specifying the input. + * * 1: A 4-D tensor, of shape + * [depth_out, filter_height, filter_width, depth_in], specifying the + * filter. For tensor of type + * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel + * dimension (SymmPerChannelQuantParams::channelDim) must be set to 0. + * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input + * tensor of type {@link OperandType::TENSOR_FLOAT32} or + * {@link OperandType::TENSOR_FLOAT16}, the bias should be of the + * same type. For input tensor of type + * {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be + * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and + * bias_scale == input_scale * filter_scale. For filter tensor of + * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias + * must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of + * 0 and bias_scale of 0. The actual scale of each value 'i' is equal + * to bias_scale[i] = input_scale * filter_scale[i]. + * * 3: An {@link OperandType::INT32} scalar, specifying the padding on + * the left, in the ‘width’ dimension. + * * 4: An {@link OperandType::INT32} scalar, specifying the padding on + * the right, in the ‘width’ dimension. + * * 5: An {@link OperandType::INT32} scalar, specifying the padding on + * the top, in the ‘height’ dimension. + * * 6: An {@link OperandType::INT32} scalar, specifying the padding on + * the bottom, in the ‘height’ dimension. + * * 7: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘width’ dimension. + * * 8: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘height’ dimension. + * * 9: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * * 10: An {@link OperandType::BOOL} scalar, set to true to specify + * NCHW data layout for input0 and output0. Set to false for NHWC. + * + * Inputs (implicit padding): + * * 0: A 4-D tensor, of shape [batches, height, width, depth_in], + * specifying the input. + * * 1: A 4-D tensor, of shape + * [depth_out, filter_height, filter_width, depth_in], specifying the + * filter. For tensor of type + * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel + * dimension (SymmPerChannelQuantParams::channelDim) must be set to 0. + * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input + * tensor of type {@link OperandType::TENSOR_FLOAT32} or + * {@link OperandType::TENSOR_FLOAT16}, the bias should be of the + * same type. For input tensor of type + * {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be + * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and + * bias_scale == input_scale * filter_scale. For filter tensor of + * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias + * must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of + * 0 and bias_scale of 0. The actual scale of each value 'i' is equal + * to bias_scale[i] = input_scale * filter_scale[i]. + * * 3: An {@link OperandType::TENSOR_INT32} tensor, specifying the output + * tensor shape. + * * 4: An {@link OperandType::INT32} scalar, specifying the implicit + * padding scheme, has to be one of the + * following values: {0 (NONE), 1 (SAME), 2 (VALID)}. + * * 5: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘width’ dimension. + * * 6: An {@link OperandType::INT32} scalar, specifying the stride when + * walking through input in the ‘height’ dimension. + * * 7: An {@link OperandType::INT32} scalar, and has to be one of the + * {@link FusedActivationFunc} values. Specifies the activation to + * invoke on the result. + * * 8: An {@link OperandType::BOOL} scalar, set to true to specify + * NCHW data layout for input0 and output0. Set to false for NHWC. + * + * Outputs: + * * 0: The output 4-D tensor, of shape + * [batches, out_height, out_width, depth_out]. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint can be different from inputs' scale and zeroPoint. + */ + TRANSPOSE_CONV_2D = @1.2::OperationType:TRANSPOSE_CONV_2D, + + /** + * A recurrent neural network specified by an LSTM cell. + * + * Performs (fully) dynamic unrolling of input. + * + * This Op unrolls the input along the time dimension, and implements the + * following operation for each element in the sequence + * s = 1...sequence_length: + * outputs[s] = projection(state = activation(LSTMOp(inputs[s]))) + * + * Where LSTMOp is the LSTM op as in {@link OperandType::LSTM}, + * the "projection" is an optional projection layer from state and output + * and the “activation” is the function passed as the + * “fused_activation_function” argument (if not “NONE”). + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Supported tensor rank: 3, either time-major or batch-major. + * + * All input and output tensors must be of the same type. + * + * Inputs: + * * 0: The input (\f$x_t\f$). + * A 3-D tensor of shape: + * If time-major: [max_time, batch_size, input_size] + * If batch-major: [batch_size, max_time, input_size] + * where “max_time” is the number of timesteps (sequence length), + * “batch_size” corresponds to the batching dimension, and + * “input_size” is the size of the input. + * * 1: The input-to-input weights (\f$W_{xi}\f$). Optional. + * A 2-D tensor of shape [num_units, input_size], where “num_units” + * corresponds to the number of cell units. + * * 2: The input-to-forget weights (\f$W_{xf}\f$). + * A 2-D tensor of shape [num_units, input_size]. + * * 3: The input-to-cell weights (\f$W_{xc}\f$). + * A 2-D tensor of shape [num_units, input_size]. + * * 4: The input-to-output weights (\f$W_{xo}\f$). + * A 2-D tensor of shape [num_units, input_size]. + * * 5: The recurrent-to-input weights (\f$W_{hi}\f$). Optional. + * A 2-D tensor of shape [num_units, output_size], where “output_size” + * corresponds to either the number of cell units (i.e., “num_units”), + * or the second dimension of the “projection_weights”, if defined. + * * 6: The recurrent-to-forget weights (\f$W_{hf}\f$). + * A 2-D tensor of shape [num_units, output_size]. + * * 7: The recurrent-to-cell weights (\f$W_{hc}\f$). + * A 2-D tensor of shape [num_units, output_size]. + * * 8: The recurrent-to-output weights (\f$W_{ho}\f$). + * A 2-D tensor of shape [num_units, output_size]. + * * 9: The cell-to-input weights (\f$W_{ci}\f$). Optional. + * A 1-D tensor of shape [num_units]. + * * 10:The cell-to-forget weights (\f$W_{cf}\f$). Optional. + * A 1-D tensor of shape [num_units]. + * * 11:The cell-to-output weights (\f$W_{co}\f$). Optional. + * A 1-D tensor of shape [num_units]. + * * 12:The input gate bias (\f$b_i\f$). Optional. + * A 1-D tensor of shape [num_units]. + * * 13:The forget gate bias (\f$b_f\f$). + * A 1-D tensor of shape [num_units]. + * * 14:The cell bias (\f$b_c\f$). + * A 1-D tensor of shape [num_units]. + * * 15:The output gate bias (\f$b_o\f$). + * A 1-D tensor of shape [num_units]. + * * 16:The projection weights (\f$W_{proj}\f$). Optional. + * A 2-D tensor of shape [output_size, num_units]. + * * 17:The projection bias (\f$b_{proj}\f$). Optional. + * A 1-D tensor of shape [output_size]. + * * 18:The output state (in) (\f$h_{t-1}\f$). + * A 2-D tensor of shape [batch_size, output_size]. + * * 19:The cell state (in) (\f$C_{t-1}\f$). + * A 2-D tensor of shape [batch_size, num_units]. + * * 20:The activation function (\f$g\f$). + * A value indicating the activation function: + *
      + *
    • 0: None; + *
    • 1: Relu; + *
    • 3: Relu6; + *
    • 4: Tanh; + *
    • 6: Sigmoid. + *
    + * * 21:The clipping threshold (\f$t_{cell}\f$) for the cell state, such + * that values are bound within [-cell_clip, cell_clip]. If set to 0.0 + * then clipping is disabled. + * * 22:The clipping threshold (\f$t_{proj}\f$) for the output from the + * projection layer, such that values are bound within + * [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled. + * * 23:Time-major if true, batch-major if false. + * * 24:The input layer normalization weights. Optional. + * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs + * to activation at input gate. + * * 25:The forget layer normalization weights. Optional. + * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs + * to activation at forget gate. + * * 26:The cell layer normalization weights. Optional. + * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs + * to activation at cell gate. + * * 27:The output layer normalization weights. Optional. + * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs + * to activation at output gate. + * + * Outputs: + * * 0: The output (\f$o_t\f$). + * A 3-D tensor of shape: + * If time-major: [max_time, batch_size, output_size] + * If batch-major: [batch_size, max_time, output_size] + */ + UNIDIRECTIONAL_SEQUENCE_LSTM = @1.2::OperationType:UNIDIRECTIONAL_SEQUENCE_LSTM, + + /** + * A recurrent neural network layer that applies a basic RNN cell to a + * sequence of inputs. + * + * This layer unrolls the input along the sequence dimension, and implements + * the following operation + * for each element in the sequence s = 1...sequence_length: + * outputs[s] = state = activation(inputs[s] * input_weights’ + state * + * recurrent_weights’ + bias) + * + * Where: + * * “input_weights” is a weight matrix that multiplies the inputs; + * * “recurrent_weights” is a weight matrix that multiplies the current + * “state” which itself is the output from the previous time step + * computation; + * * “bias” is a bias vector (added to each output vector in the batch); + * * “activation” is the function passed as the “fused_activation_function” + * argument (if not “NONE”). + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * The input tensors must all be the same type. + * + * Inputs: + * * 0: input. + * A 3-D tensor. The shape is defined by the input 6 (timeMajor). If + * it is set to 1, then the input has a shape [maxTime, batchSize, + * inputSize], otherwise the input has a shape [batchSize, maxTime, + * inputSize]. + * * 1: weights. + * A 2-D tensor of shape [numUnits, inputSize]. + * * 2: recurrent_weights. + * A 2-D tensor of shape [numUnits, numUnits]. + * * 3: bias. + * A 1-D tensor of shape [numUnits]. + * * 4: hidden state + * A 2-D tensor of shape [batchSize, numUnits]. Specifies a hidden + * state input for the first time step of the computation. + * * 5: fusedActivationFunction. + * A {@link FusedActivationFunc} value indicating the activation function. If + * “NONE” is specified then it results in a linear activation. + * * 6: timeMajor + * An {@link OperandType::INT32} scalar specifying the shape format + * of input and output tensors. Must be set to either 0 or 1. + * Outputs: + * * 0: output. + * A 3-D tensor. The shape is defined by the input 6 (timeMajor). If + * it is set to 1, then the output has a shape [maxTime, batchSize, + * numUnits], otherwise the output has a shape [batchSize, maxTime, + * numUnits]. + */ + UNIDIRECTIONAL_SEQUENCE_RNN = @1.2::OperationType:UNIDIRECTIONAL_SEQUENCE_RNN, + + /** + * Resizes images to given size using the nearest neighbor interpretation. + * + * Resized images must be distorted if their output aspect ratio is not the + * same as input aspect ratio. The corner pixels of output may not be the + * same as corner pixels of input. + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * + * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. + * With the default data layout NHWC, the data is stored in the order of: + * [batch, height, width, channels]. Alternatively, the data layout could + * be NCHW, the data storage order of: [batch, channels, height, width]. + * + * Both resizing by shape and resizing by scale are supported. + * + * Inputs (resizing by shape): + * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying + * the input. Zero batches is supported for this tensor. + * * 1: An {@link OperandType::INT32} scalar, specifying the output + * width of the output tensor. + * * 2: An {@link OperandType::INT32} scalar, specifying the output + * height of the output tensor. + * * 3: An {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * + * Inputs (resizing by scale): + * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying + * the input. Zero batches is supported for this tensor. + * * 1: A scalar, specifying width_scale, the scaling factor of the width + * dimension from the input tensor to the output tensor. The output + * width is calculated as new_width = floor(width * width_scale). + * The scalar must be of {@link OperandType::FLOAT16} if input0 is + * of {@link OperandType::TENSOR_FLOAT16} and of + * {@link OperandType::FLOAT32} otherwise. + * * 2: A scalar, specifying height_scale, the scaling factor of the height + * dimension from the input tensor to the output tensor. The output + * height is calculated as new_height = floor(height * height_scale). + * The scalar must be of {@link OperandType::FLOAT16} if input0 is + * of {@link OperandType::TENSOR_FLOAT16} and of + * {@link OperandType::FLOAT32} otherwise. + * * 3: An {@link OperandType::BOOL} scalar, default to false. + * Set to true to specify NCHW data layout for input0 and output0. + * + * Outputs: + * * 0: The output 4-D tensor, of shape + * [batches, new_height, new_width, depth]. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * the scale and zeroPoint must be the same as input0. + */ + RESIZE_NEAREST_NEIGHBOR = @1.2::OperationType:RESIZE_NEAREST_NEIGHBOR, + + /** + * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to + * OEM operation and data types. + * + * This operation is OEM specific. It should only be used for OEM + * applications. + */ + OEM_OPERATION = @1.2::OperationType:OEM_OPERATION, + /* ADDING A NEW FUNDAMENTAL OPERATION REQUIRES UPDATING THE VALUE OF + * OperationTypeRange::FUNDAMENTAL_MAX. + */ + /* ADDING A NEW OEM OPERATION REQUIRES UPDATING THE VALUE OF + * OperationTypeRange::OEM_MAX. + */ +}; + +/** + * The range of values in the OperationType enum. + */ +enum OperationTypeRange : uint32_t { + BASE_MIN = 0, + FUNDAMENTAL_MIN = 0, + FUNDAMENTAL_MAX = 94, + OEM_MIN = 10000, + OEM_MAX = 10000, + BASE_MAX = 0xFFFF, +}; + /** * The capabilities of a driver. @@ -108,6 +4602,32 @@ struct Capabilities { vec operandPerformance; }; +/** + * Describes one operation of the model's graph. + */ +struct Operation { + /** + * The operation type. + * + * Besides the values listed in {@link OperationType}, any value above + * {@link OperationTypeRange::BASE_MAX} is possible and should be interpreted + * as an extension type according to {@link Model::extensionNameToPrefix}. + */ + OperationType type; + + /** + * Describes the table that contains the indexes of the inputs of the + * operation. The offset is the index in the operandIndexes table. + */ + vec inputs; + + /** + * Describes the table that contains the indexes of the outputs of the + * operation. The offset is the index in the operandIndexes table. + */ + vec outputs; +}; + /** * Describes one operand of the model's graph. */ @@ -232,28 +4752,6 @@ struct Operand { } extraParams; }; -/** - * Describes one operation of the model's graph. - */ -struct Operation { - /** - * The operation type. - */ - OperationType type; - - /** - * Describes the table that contains the indexes of the inputs of the - * operation. The offset is the index in the operandIndexes table. - */ - vec inputs; - - /** - * Describes the table that contains the indexes of the outputs of the - * operation. The offset is the index in the operandIndexes table. - */ - vec outputs; -}; - /** * A Neural Network Model. * diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t index d41cfd2c92..e06f5d630d 100644 --- a/neuralnetworks/1.3/types.t +++ b/neuralnetworks/1.3/types.t @@ -44,6 +44,47 @@ enum OperandTypeRange : uint32_t { BASE_MAX = 0xFFFF, }; +/** + * Operation types. + * + * The type of an operation in a model. + */ +enum OperationType : int32_t { + +%insert Operation_1.0 + +%insert Operation_1.1 + +%insert Operation_1.2 + + /** + * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to + * OEM operation and data types. + * + * This operation is OEM specific. It should only be used for OEM + * applications. + */ + OEM_OPERATION = @1.2::OperationType:OEM_OPERATION, + /* ADDING A NEW FUNDAMENTAL OPERATION REQUIRES UPDATING THE VALUE OF + * OperationTypeRange::FUNDAMENTAL_MAX. + */ + /* ADDING A NEW OEM OPERATION REQUIRES UPDATING THE VALUE OF + * OperationTypeRange::OEM_MAX. + */ +}; + +/** + * The range of values in the OperationType enum. + */ +enum OperationTypeRange : uint32_t { + BASE_MIN = 0, + FUNDAMENTAL_MIN = 0, +%insert Operation_1.3_MAX + OEM_MIN = 10000, + OEM_MAX = 10000, + BASE_MAX = 0xFFFF, +}; + /** * The capabilities of a driver. @@ -79,6 +120,32 @@ struct Capabilities { vec operandPerformance; }; +/** + * Describes one operation of the model's graph. + */ +struct Operation { + /** + * The operation type. + * + * Besides the values listed in {@link OperationType}, any value above + * {@link OperationTypeRange::BASE_MAX} is possible and should be interpreted + * as an extension type according to {@link Model::extensionNameToPrefix}. + */ + OperationType type; + + /** + * Describes the table that contains the indexes of the inputs of the + * operation. The offset is the index in the operandIndexes table. + */ + vec inputs; + + /** + * Describes the table that contains the indexes of the outputs of the + * operation. The offset is the index in the operandIndexes table. + */ + vec outputs; +}; + /** * Describes one operand of the model's graph. */ @@ -203,28 +270,6 @@ struct Operand { } extraParams; }; -/** - * Describes one operation of the model's graph. - */ -struct Operation { - /** - * The operation type. - */ - OperationType type; - - /** - * Describes the table that contains the indexes of the inputs of the - * operation. The offset is the index in the operandIndexes table. - */ - vec inputs; - - /** - * Describes the table that contains the indexes of the outputs of the - * operation. The offset is the index in the operandIndexes table. - */ - vec outputs; -}; - /** * A Neural Network Model. * diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 325d641744..a1e04c58de 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -63,7 +63,6 @@ using V1_0::Request; using V1_1::ExecutionPreference; using V1_2::Constant; using V1_2::MeasureTiming; -using V1_2::OperationType; using V1_2::OutputShape; using V1_2::SymmPerChannelQuantParams; using V1_2::Timing; diff --git a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp index 7361078eca..a7569e6dfe 100644 --- a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp +++ b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp @@ -25,8 +25,6 @@ using namespace test_helper; #define CHECK_TEST_ENUM(EnumType, enumValue) \ static_assert(static_cast(Test##EnumType::enumValue) == EnumType::enumValue) -using V1_2::OperationType; - CHECK_TEST_ENUM(OperandType, FLOAT32); CHECK_TEST_ENUM(OperandType, INT32); CHECK_TEST_ENUM(OperandType, UINT32); diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 1ff02dc198..46bbd3f655 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -27,7 +27,6 @@ using implementation::PreparedModelCallback; using V1_0::ErrorStatus; using V1_0::OperandLifeTime; using V1_1::ExecutionPreference; -using V1_2::OperationType; using V1_2::OperationTypeRange; using V1_2::SymmPerChannelQuantParams; using HidlToken = From 86e5880d82ad144394b497bc346ce285c5e3e875 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Mon, 11 Nov 2019 22:49:21 -0800 Subject: [PATCH 0235/1022] Log and return error if failed to listen to a socket Test: build by `mm` Change-Id: I5cf38c4011274ff70a02ac7472a10670b779aa85 --- automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp index 9eb8894385..068333cf36 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp @@ -92,7 +92,10 @@ bool SocketComm::listen() { } ALOGI("%s: Listening for connections on port %d", __FUNCTION__, DEBUG_SOCKET); - ::listen(mListenFd, 1); + if (::listen(mListenFd, 1) == -1) { + ALOGE("%s: Error on listening: errno: %d: %s", __FUNCTION__, errno, strerror(errno)); + return false; + } return true; } From 66f598e10db888214e2288f0e9af0f9b43e89d07 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Wed, 2 Oct 2019 17:32:06 +0100 Subject: [PATCH 0236/1022] Combine test parameters into TestConfig structure Test: VtsHalNeuralnetworksV1_2TargetTest --gtest_filter="GeneratedTests*" Change-Id: I928aaa42e4745b4a8e0e461046e9632b052d0135 --- .../vts/functional/GeneratedTestHarness.cpp | 95 +++++++++---------- .../vts/functional/GeneratedTestHarness.cpp | 95 +++++++++---------- 2 files changed, 92 insertions(+), 98 deletions(-) diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp index aacb38500b..c1bf494328 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp @@ -58,8 +58,20 @@ using V1_0::Request; using V1_1::ExecutionPreference; using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; +namespace { + +enum class Executor { ASYNC, SYNC, BURST }; + enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; +struct TestConfig { + Executor executor; + MeasureTiming measureTiming; + OutputType outputType; +}; + +} // namespace + Model createModel(const TestModel& testModel) { // Model operands. hidl_vec operands(testModel.operands.size()); @@ -194,31 +206,31 @@ static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst( return android::nn::ExecutionBurstController::create(preparedModel, std::chrono::microseconds{0}); } -enum class Executor { ASYNC, SYNC, BURST }; void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel, - Executor executor, MeasureTiming measure, OutputType outputType) { + const TestConfig& testConfig) { // If output0 does not have size larger than one byte, we can not test with insufficient buffer. - if (outputType == OutputType::INSUFFICIENT && !isOutputSizeGreaterThanOne(testModel, 0)) { + if (testConfig.outputType == OutputType::INSUFFICIENT && + !isOutputSizeGreaterThanOne(testModel, 0)) { return; } Request request = createRequest(testModel); - if (outputType == OutputType::INSUFFICIENT) { + if (testConfig.outputType == OutputType::INSUFFICIENT) { makeOutputInsufficientSize(/*outputIndex=*/0, &request); } ErrorStatus executionStatus; hidl_vec outputShapes; Timing timing; - switch (executor) { + switch (testConfig.executor) { case Executor::ASYNC: { SCOPED_TRACE("asynchronous"); // launch execution sp executionCallback = new ExecutionCallback(); - Return executionLaunchStatus = - ExecutePreparedModel(preparedModel, request, measure, executionCallback); + Return executionLaunchStatus = ExecutePreparedModel( + preparedModel, request, testConfig.measureTiming, executionCallback); ASSERT_TRUE(executionLaunchStatus.isOk()); EXPECT_EQ(ErrorStatus::NONE, static_cast(executionLaunchStatus)); @@ -234,8 +246,8 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo SCOPED_TRACE("synchronous"); // execute - Return executionReturnStatus = - ExecutePreparedModel(preparedModel, request, measure, &outputShapes, &timing); + Return executionReturnStatus = ExecutePreparedModel( + preparedModel, request, testConfig.measureTiming, &outputShapes, &timing); ASSERT_TRUE(executionReturnStatus.isOk()); executionStatus = static_cast(executionReturnStatus); @@ -258,14 +270,14 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo // execute burst int n; std::tie(n, outputShapes, timing, std::ignore) = - controller->compute(request, measure, keys); + controller->compute(request, testConfig.measureTiming, keys); executionStatus = nn::convertResultCodeToErrorStatus(n); break; } } - if (outputType != OutputType::FULLY_SPECIFIED && + if (testConfig.outputType != OutputType::FULLY_SPECIFIED && executionStatus == ErrorStatus::GENERAL_FAILURE) { LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " "execute model that it does not support."; @@ -274,7 +286,7 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo << std::endl; GTEST_SKIP(); } - if (measure == MeasureTiming::NO) { + if (testConfig.measureTiming == MeasureTiming::NO) { EXPECT_EQ(UINT64_MAX, timing.timeOnDevice); EXPECT_EQ(UINT64_MAX, timing.timeInDriver); } else { @@ -283,7 +295,7 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo } } - switch (outputType) { + switch (testConfig.outputType) { case OutputType::FULLY_SPECIFIED: // If the model output operands are fully specified, outputShapes must be either // either empty, or have the same number of elements as the number of outputs. @@ -321,44 +333,29 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel, bool testDynamicOutputShape) { + std::initializer_list outputTypesList; + std::initializer_list measureTimingList; + std::initializer_list executorList; + if (testDynamicOutputShape) { - EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO, - OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO, - OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO, - OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES, - OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES, - OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES, - OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO, - OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO, - OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO, - OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES, - OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES, - OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES, - OutputType::INSUFFICIENT); + outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT}; + measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; + executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; } else { - EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO, - OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO, - OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO, - OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES, - OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES, - OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES, - OutputType::FULLY_SPECIFIED); + outputTypesList = {OutputType::FULLY_SPECIFIED}; + measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; + executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; + } + + for (const OutputType outputType : outputTypesList) { + for (const MeasureTiming measureTiming : measureTimingList) { + for (const Executor executor : executorList) { + const TestConfig testConfig = {.executor = executor, + .measureTiming = measureTiming, + .outputType = outputType}; + EvaluatePreparedModel(preparedModel, testModel, testConfig); + } + } } } diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index a1e04c58de..2ec29887df 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -69,8 +69,20 @@ using V1_2::Timing; using V1_2::implementation::ExecutionCallback; using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; +namespace { + +enum class Executor { ASYNC, SYNC, BURST }; + enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; +struct TestConfig { + Executor executor; + MeasureTiming measureTiming; + OutputType outputType; +}; + +} // namespace + Model createModel(const TestModel& testModel) { // Model operands. hidl_vec operands(testModel.operands.size()); @@ -205,31 +217,31 @@ static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst( return android::nn::ExecutionBurstController::create(preparedModel, std::chrono::microseconds{0}); } -enum class Executor { ASYNC, SYNC, BURST }; void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel, - Executor executor, MeasureTiming measure, OutputType outputType) { + const TestConfig& testConfig) { // If output0 does not have size larger than one byte, we can not test with insufficient buffer. - if (outputType == OutputType::INSUFFICIENT && !isOutputSizeGreaterThanOne(testModel, 0)) { + if (testConfig.outputType == OutputType::INSUFFICIENT && + !isOutputSizeGreaterThanOne(testModel, 0)) { return; } Request request = createRequest(testModel); - if (outputType == OutputType::INSUFFICIENT) { + if (testConfig.outputType == OutputType::INSUFFICIENT) { makeOutputInsufficientSize(/*outputIndex=*/0, &request); } ErrorStatus executionStatus; hidl_vec outputShapes; Timing timing; - switch (executor) { + switch (testConfig.executor) { case Executor::ASYNC: { SCOPED_TRACE("asynchronous"); // launch execution sp executionCallback = new ExecutionCallback(); - Return executionLaunchStatus = - ExecutePreparedModel(preparedModel, request, measure, executionCallback); + Return executionLaunchStatus = ExecutePreparedModel( + preparedModel, request, testConfig.measureTiming, executionCallback); ASSERT_TRUE(executionLaunchStatus.isOk()); EXPECT_EQ(ErrorStatus::NONE, static_cast(executionLaunchStatus)); @@ -245,8 +257,8 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo SCOPED_TRACE("synchronous"); // execute - Return executionReturnStatus = - ExecutePreparedModel(preparedModel, request, measure, &outputShapes, &timing); + Return executionReturnStatus = ExecutePreparedModel( + preparedModel, request, testConfig.measureTiming, &outputShapes, &timing); ASSERT_TRUE(executionReturnStatus.isOk()); executionStatus = static_cast(executionReturnStatus); @@ -269,14 +281,14 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo // execute burst int n; std::tie(n, outputShapes, timing, std::ignore) = - controller->compute(request, measure, keys); + controller->compute(request, testConfig.measureTiming, keys); executionStatus = nn::convertResultCodeToErrorStatus(n); break; } } - if (outputType != OutputType::FULLY_SPECIFIED && + if (testConfig.outputType != OutputType::FULLY_SPECIFIED && executionStatus == ErrorStatus::GENERAL_FAILURE) { LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " "execute model that it does not support."; @@ -285,7 +297,7 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo << std::endl; GTEST_SKIP(); } - if (measure == MeasureTiming::NO) { + if (testConfig.measureTiming == MeasureTiming::NO) { EXPECT_EQ(UINT64_MAX, timing.timeOnDevice); EXPECT_EQ(UINT64_MAX, timing.timeInDriver); } else { @@ -294,7 +306,7 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo } } - switch (outputType) { + switch (testConfig.outputType) { case OutputType::FULLY_SPECIFIED: // If the model output operands are fully specified, outputShapes must be either // either empty, or have the same number of elements as the number of outputs. @@ -332,44 +344,29 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel, bool testDynamicOutputShape) { + std::initializer_list outputTypesList; + std::initializer_list measureTimingList; + std::initializer_list executorList; + if (testDynamicOutputShape) { - EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO, - OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO, - OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO, - OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES, - OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES, - OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES, - OutputType::UNSPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO, - OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO, - OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO, - OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES, - OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES, - OutputType::INSUFFICIENT); - EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES, - OutputType::INSUFFICIENT); + outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT}; + measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; + executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; } else { - EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO, - OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO, - OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO, - OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES, - OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES, - OutputType::FULLY_SPECIFIED); - EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES, - OutputType::FULLY_SPECIFIED); + outputTypesList = {OutputType::FULLY_SPECIFIED}; + measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; + executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; + } + + for (const OutputType outputType : outputTypesList) { + for (const MeasureTiming measureTiming : measureTimingList) { + for (const Executor executor : executorList) { + const TestConfig testConfig = {.executor = executor, + .measureTiming = measureTiming, + .outputType = outputType}; + EvaluatePreparedModel(preparedModel, testModel, testConfig); + } + } } } From 6f4a232928aae15999c866ef0ff67bc7bde024e4 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Tue, 12 Nov 2019 13:48:58 -0800 Subject: [PATCH 0237/1022] hardware: interfaces: sensors: fix -Wreorder-init-list C++20 is stricter about member ordering in designated initializers than C99. Bug: 139945549 Test: mm Change-Id: I22179dfb829c328462c9b31caf543692d3cf57d9 Signed-off-by: Nick Desaulniers --- sensors/common/vts/utils/GrallocWrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sensors/common/vts/utils/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp index 1cad9135b7..e63faa2e1c 100644 --- a/sensors/common/vts/utils/GrallocWrapper.cpp +++ b/sensors/common/vts/utils/GrallocWrapper.cpp @@ -147,8 +147,8 @@ BufferDescriptor GrallocHalWrapper::getDescriptor(uint32_t .width = size, .height = 1, .layerCount = 1, - .usage = kBufferUsage, .format = static_cast(PixelFormat::BLOB), + .usage = kBufferUsage, }; BufferDescriptor descriptor; From 1f4012f417831ae076bb3861e1ac3f4c14fe2d7c Mon Sep 17 00:00:00 2001 From: Shuo Qian Date: Tue, 29 Oct 2019 17:11:10 -0700 Subject: [PATCH 0238/1022] Add Signal Strength Threshold HAL for 4G and 5G Test: Build Bug: 135717625 Change-Id: I324cfd592ca53a12ebe1161f242ae3b9c7fc59a4 --- current.txt | 6 +- radio/1.5/IRadio.hal | 28 ++ radio/1.5/IRadioResponse.hal | 9 + radio/1.5/types.hal | 97 +++++++ .../1.5/vts/functional/radio_hidl_hal_api.cpp | 263 ++++++++++++++++++ .../functional/radio_hidl_hal_utils_v1_5.h | 3 + radio/1.5/vts/functional/radio_response.cpp | 8 + 7 files changed, 411 insertions(+), 3 deletions(-) diff --git a/current.txt b/current.txt index 74586b7502..c162e5b4c2 100644 --- a/current.txt +++ b/current.txt @@ -604,7 +604,7 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar 619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types -41c602462ccd1b19cfd645994be4de4c07fc197ff58a54e84476b31908e61e21 android.hardware.radio@1.5::types -a8691c71747c3f14f7a043598e856425077f755e55990507a9132ad62f8ab3f7 android.hardware.radio@1.5::IRadio +d3636ff9d5fef59f59f678887209156b2608d29f676fb1e600fe33b7e57a8a61 android.hardware.radio@1.5::types +c8e81d912827a5d49b2ddcdc4eb4556c5d231a899a1dca879309e04210daa4a0 android.hardware.radio@1.5::IRadio a62a93faf173b14a6175b683ebf61ffa568dc61f81e369d2dce7b1265e86cf2f android.hardware.radio@1.5::IRadioIndication -15daf260aaf6781b911450bc94e1a164901f9c0fe0bda68f8434f0a903f66e05 android.hardware.radio@1.5::IRadioResponse +260ce05806d753d728f844d405e832179ed7d9b65986ec18fef3d21cf7285587 android.hardware.radio@1.5::IRadioResponse diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal index de20dd08fd..74ec56d4da 100644 --- a/radio/1.5/IRadio.hal +++ b/radio/1.5/IRadio.hal @@ -17,6 +17,8 @@ package android.hardware.radio@1.5; import @1.4::IRadio; +import @1.5::AccessNetwork; +import @1.5::SignalThresholdInfo; /** * This interface is used by telephony and telecom to talk to cellular radio. @@ -27,4 +29,30 @@ import @1.4::IRadio; * setResponseFunctions must work with @1.5::IRadioResponse and @1.5::IRadioIndication. */ interface IRadio extends @1.4::IRadio { + + /** + * Sets the signal strength reporting criteria. + * + * The resulting reporting rules are the AND of all the supplied criteria. For each RAN + * The hysteresisDb and thresholds apply to only the following measured quantities: + * -GERAN - RSSI + * -CDMA2000 - RSSI + * -UTRAN - RSCP + * -EUTRAN - RSRP/RSRQ/RSSNR + * -NGRAN - SSRSRP/SSRSRQ/SSSINR + * + * Note: Reporting criteria must be individually set for each RAN. For any unset reporting + * criteria, the value is implementation-defined. + * + * Response callback is + * IRadioResponse.setSignalStrengthReportingCriteriaResponse_1_5() + * + * @param serial Serial number of request. + * @param signalThresholdInfo Signal threshold info including the threshold values, + * hysteresisDb, and hysteresisMs. See @1.5::SignalThresholdInfo + * for details. + * @param accessNetwork The type of network for which to apply these thresholds. + */ + oneway setSignalStrengthReportingCriteria_1_5(int32_t serial, + SignalThresholdInfo signalThresholdInfo, AccessNetwork accessNetwork); }; diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal index d4c4f766af..91dc1e0d86 100644 --- a/radio/1.5/IRadioResponse.hal +++ b/radio/1.5/IRadioResponse.hal @@ -23,4 +23,13 @@ import @1.4::IRadioResponse; * Interface declaring response functions to solicited radio requests. */ interface IRadioResponse extends @1.4::IRadioResponse { + /** + * @param info Response info struct containing response type, serial no. and error + * + * Valid errors returned: + * RadioError:NONE + * RadioError:INVALID_ARGUMENTS + * RadioError:RADIO_NOT_AVAILABLE + */ + oneway setSignalStrengthReportingCriteriaResponse_1_5(RadioResponseInfo info); }; diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index a639a8d1d9..216ca1f156 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -15,3 +15,100 @@ */ package android.hardware.radio@1.5; + +import @1.4::AccessNetwork; + +/** + * Defining signal strength type. + */ +enum SignalMeasurementType : int32_t { + /** + * Received Signal Strength Indication. + * Range: -113 dBm and -51 dBm + * Used RAN: GERAN, CDMA2000 + * Reference: 3GPP TS 27.007 section 8.5. + */ + RSSI = 1, + /** + * Received Signal Code Power. + * Range: -120 dBm to -25 dBm; + * Used RAN: UTRAN + * Reference: 3GPP TS 25.123, section 9.1.1.1 + */ + RSCP = 2, + /** + * Reference Signal Received Power. + * Range: -140 dBm to -44 dBm; + * Used RAN: EUTRAN + * Reference: 3GPP TS 36.133 9.1.4 + */ + RSRP = 3, + /** + * Reference Signal Received Quality + * Range: -20 dB to -3 dB; + * Used RAN: EUTRAN + * Reference: 3GPP TS 36.133 9.1.7 + */ + RSRQ = 4, + /** + * Reference Signal Signal to Noise Ratio + * Range: -20 dB to -30 dB; + * Used RAN: EUTRAN + * Reference: 3GPP TS 36.101 8.1.1 + */ + RSSNR = 5, + /** + * 5G SS reference signal received power. + * Range: -140 dBm to -44 dBm. + * Used RAN: NGRAN + * Reference: 3GPP TS 38.215. + */ + SSRSRP = 6, + /** + * 5G SS reference signal received quality. + * Range: -20 dB to -3 dB. + * Used RAN: NGRAN + * Reference: 3GPP TS 38.215. + */ + SSRSRQ = 7, + /** + * 5G SS signal-to-noise and interference ratio. + * Range: -23 dB to 40 dB + * Used RAN: NGRAN + * Reference: 3GPP TS 38.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1. + */ + SSSINR = 8, +}; + +/** + * Contains the threshold values of each signal measurement type. + */ +struct SignalThresholdInfo { + /** Signal Measurement Type */ + SignalMeasurementType signalMeasurement; + + /** A hysteresis time in milliseconds to prevent flapping. A value of 0 disables hysteresis */ + int32_t hysteresisMs; + + /** + * An interval in dB defining the required magnitude change between reports. + * hysteresisDb must be smaller than the smallest threshold delta. + * An interval value of 0 disables hysteresis. + */ + int32_t hysteresisDb; + + /** + * List of threshold values. + * Range and unit must reference specific @1.5::SignalMeasurementType. + * The threshold values for which to apply criteria. + * A vector size of 0 disables the use of thresholds for reporting. + */ + vec thresholds; +}; + +enum AccessNetwork : @1.4::AccessNetwork { + /** + * Next-Generation Radio Access Network (NGRAN) + */ + NGRAN = 6, +}; \ No newline at end of file diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp index b86fa5f59b..650ede44d2 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp @@ -17,3 +17,266 @@ #include #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) + +/* + * Test IRadio.setSignalStrengthReportingCriteria_1_5() with invalid hysteresisDb + */ +TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_invalidHysteresisDb) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; + signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSI; + signalThresholdInfo.hysteresisMs = 5000; + signalThresholdInfo.hysteresisDb = 10; // hysteresisDb too large given threshold list deltas + signalThresholdInfo.thresholds = {-109, -103, -97, -89}; + + Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( + serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::GERAN); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + ALOGI("setSignalStrengthReportingCriteria_1_5_invalidHysteresisDb, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); +} + +/* + * Test IRadio.setSignalStrengthReportingCriteria_1_5() with empty thresholds + */ +TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_EmptyThresholds) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; + signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSI; + signalThresholdInfo.hysteresisMs = 0; + signalThresholdInfo.hysteresisDb = 0; + + Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( + serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::GERAN); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + ALOGI("setSignalStrengthReportingCriteria_1_5_EmptyParams, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE})); +} + +/* + * Test IRadio.setSignalStrengthReportingCriteria_1_5() for GERAN + */ +TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Geran) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; + signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSI; + signalThresholdInfo.hysteresisMs = 5000; + signalThresholdInfo.hysteresisDb = 2; + signalThresholdInfo.thresholds = {-109, -103, -97, -89}; + + Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( + serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::GERAN); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + ALOGI("setSignalStrengthReportingCriteria_1_5_Geran, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE})); +} + +/* + * Test IRadio.setSignalStrengthReportingCriteria_1_5() for UTRAN + */ +TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Utran) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; + signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSCP; + signalThresholdInfo.hysteresisMs = 5000; + signalThresholdInfo.hysteresisDb = 2; + signalThresholdInfo.thresholds = {-110, -97, -73, -49, -25}; + + Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( + serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::UTRAN); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + ALOGI("setSignalStrengthReportingCriteria_1_5_Utran, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE})); +} + +/* + * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN + */ +TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRP) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; + signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSRP; + signalThresholdInfo.hysteresisMs = 5000; + signalThresholdInfo.hysteresisDb = 2; + signalThresholdInfo.thresholds = {-128, -108, -88, -68}; + + Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( + serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + ALOGI("setSignalStrengthReportingCriteria_1_5_Eutran, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE})); +} + +/* + * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN + */ +TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRQ) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; + signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSRQ; + signalThresholdInfo.hysteresisMs = 5000; + signalThresholdInfo.hysteresisDb = 2; + signalThresholdInfo.thresholds = {-27, -20, -13, -6}; + + Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( + serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + ALOGI("setSignalStrengthReportingCriteria_1_5_Eutran, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE})); +} + +/* + * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN + */ +TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSSNR) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; + signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSNR; + signalThresholdInfo.hysteresisMs = 5000; + signalThresholdInfo.hysteresisDb = 2; + signalThresholdInfo.thresholds = {-10, 0, 10, 20}; + + Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( + serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + ALOGI("setSignalStrengthReportingCriteria_1_5_Eutran, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE})); +} + +/* + * Test IRadio.setSignalStrengthReportingCriteria_1_5() for CDMA2000 + */ +TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Cdma2000) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; + signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSI; + signalThresholdInfo.hysteresisMs = 5000; + signalThresholdInfo.hysteresisDb = 2; + signalThresholdInfo.thresholds = {-105, -90, -75, -65}; + + Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( + serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::CDMA2000); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + ALOGI("setSignalStrengthReportingCriteria_1_5_Cdma2000, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE})); +} + +/* + * Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSRSRP + */ +TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRP) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; + signalThresholdInfo.signalMeasurement = SignalMeasurementType::SSRSRP; + signalThresholdInfo.hysteresisMs = 5000; + signalThresholdInfo.hysteresisDb = 0; + signalThresholdInfo.thresholds = {-105, -90, -75, -65}; + + Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( + serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::NGRAN); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + ALOGI("setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRP, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE})); +} + +/* + * Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSRSRQ + */ +TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRQ) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; + signalThresholdInfo.signalMeasurement = SignalMeasurementType::SSRSRQ; + signalThresholdInfo.hysteresisMs = 5000; + signalThresholdInfo.hysteresisDb = 0; + signalThresholdInfo.thresholds = {-15, -10, -5, -4}; + + Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( + serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::NGRAN); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + ALOGI("setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRQ, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE})); +} + +/* + * Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSSINR + */ +TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; + signalThresholdInfo.signalMeasurement = SignalMeasurementType::SSSINR; + signalThresholdInfo.hysteresisMs = 5000; + signalThresholdInfo.hysteresisDb = 0; + signalThresholdInfo.thresholds = {-10, 3, 16, 18}; + + Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( + serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::NGRAN); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + ALOGI("setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE})); +} \ No newline at end of file diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index 799702b9a1..683fdfc5fb 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -521,6 +521,9 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon Return getAllowedCarriersResponse_1_4(const RadioResponseInfo& info, const CarrierRestrictionsWithPriority& carriers, SimLockMultiSimPolicy multiSimPolicy); + + /* 1.5 Api */ + Return setSignalStrengthReportingCriteriaResponse_1_5(const RadioResponseInfo& info); }; /* Callback class for radio indication */ diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp index 1e5cc4775b..29a92506ab 100644 --- a/radio/1.5/vts/functional/radio_response.cpp +++ b/radio/1.5/vts/functional/radio_response.cpp @@ -885,3 +885,11 @@ Return RadioResponse_v1_5::getAllowedCarriersResponse_1_4( parent_v1_5.notify(info.serial); return Void(); } + +/* 1.5 Apis */ +Return RadioResponse_v1_5::setSignalStrengthReportingCriteriaResponse_1_5( + const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} \ No newline at end of file From bbf5959db68123e2c420fb98cb25f8d54d4fabd6 Mon Sep 17 00:00:00 2001 From: Emilian Peev Date: Tue, 12 Nov 2019 17:15:22 -0800 Subject: [PATCH 0239/1022] Camera: Signal when all Hal requested buffers return Depending on timing 'waitForBuffersReturned' can be called before all Hal requested buffer are able to return. To avoid potential timeout, check for any outstanding buffers and signal accordingly before returning from 'returnStreamBuffers'. Bug: 144308932 Test: adb shell /system/bin/VtsHalCameraProviderV2_4TargetTest --hal_service_instance=android.hardware.camera.provider@2.4::ICameraProvider/internal/0 Change-Id: Idb3d8bd6fdbdfe0798c38a1b83c17f1a8379738e --- .../vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 49f9fe17b1..6505440a26 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -1494,7 +1494,7 @@ Return CameraHidlTest::DeviceCb::returnStreamBuffers( ADD_FAILURE(); } - std::lock_guard l(mLock); + std::unique_lock l(mLock); for (const auto& buf : buffers) { bool found = false; for (size_t idx = 0; idx < mOutstandingBufferIds.size(); idx++) { @@ -1514,6 +1514,10 @@ Return CameraHidlTest::DeviceCb::returnStreamBuffers( ALOGE("%s: unknown buffer ID %" PRIu64, __FUNCTION__, buf.bufferId); ADD_FAILURE(); } + if (!hasOutstandingBuffersLocked()) { + l.unlock(); + mFlushedCondition.notify_one(); + } return Void(); } From 046257fd2e916ced9a16596d66e003402b90dce2 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Thu, 7 Nov 2019 18:27:23 -0800 Subject: [PATCH 0240/1022] Wifi: Support check on device capability for 6GHZ This commit adds the HAL APIs and implementation to support checking whether device supports 6GHz band or not. VTS test has been added for the new api. Bug: 139354972 Test: Manual: Make sure capability is read correctly. Test: VTS test. Change-Id: I03b0c6017666ffd3663d5979d6e6a2bd93043c48 --- wifi/1.4/Android.bp | 1 + wifi/1.4/IWifiStaIface.hal | 50 +++++++++++++++ wifi/1.4/default/hidl_struct_util.cpp | 9 ++- wifi/1.4/default/hidl_struct_util.h | 3 +- wifi/1.4/default/wifi_legacy_hal.cpp | 2 +- wifi/1.4/default/wifi_sta_iface.cpp | 51 +++++++++------ wifi/1.4/default/wifi_sta_iface.h | 7 ++- .../functional/wifi_sta_iface_hidl_test.cpp | 62 +++++++++++++++++++ 8 files changed, 158 insertions(+), 27 deletions(-) create mode 100644 wifi/1.4/IWifiStaIface.hal create mode 100644 wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp diff --git a/wifi/1.4/Android.bp b/wifi/1.4/Android.bp index e19785967a..5750e426ad 100644 --- a/wifi/1.4/Android.bp +++ b/wifi/1.4/Android.bp @@ -13,6 +13,7 @@ hidl_interface { "IWifiChip.hal", "IWifiRttController.hal", "IWifiRttControllerEventCallback.hal", + "IWifiStaIface.hal", ], interfaces: [ "android.hardware.wifi@1.0", diff --git a/wifi/1.4/IWifiStaIface.hal b/wifi/1.4/IWifiStaIface.hal new file mode 100644 index 0000000000..fb658cd37c --- /dev/null +++ b/wifi/1.4/IWifiStaIface.hal @@ -0,0 +1,50 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi@1.4; + +import @1.0::WifiStatus; +import @1.0::MacAddress; +import @1.0::IWifiStaIface; +import @1.3::IWifiStaIface; + +/** + * Interface used to represent a single STA iface. + * + * IWifiChip.createStaIface() may return a @1.4::IWifiStaIface when supported. + */ +interface IWifiStaIface extends @1.3::IWifiStaIface { + + enum StaIfaceCapabilityMask : @1.0::IWifiStaIface.StaIfaceCapabilityMask { + STA_6G = 1 << 15 + }; + + /** + * Get the capabilities supported by this STA iface. + * + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|, + * |WifiStatusCode.ERROR_NOT_AVAILABLE|, + * |WifiStatusCode.ERROR_NOT_SUPPORTED|, + * |WifiStatusCode.ERROR_UNKNOWN| + * @return capabilities Bitset of |StaIfaceCapabilityMask| values. + */ + getCapabilities_1_4() + generates (WifiStatus status, + bitfield capabilities); +}; diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp index 61f311ec24..13a09f3438 100644 --- a/wifi/1.4/default/hidl_struct_util.cpp +++ b/wifi/1.4/default/hidl_struct_util.cpp @@ -91,7 +91,7 @@ V1_3::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability( } IWifiStaIface::StaIfaceCapabilityMask -convertLegacyFeatureToHidlStaIfaceCapability(uint32_t feature) { +convertLegacyFeatureToHidlStaIfaceCapability(uint64_t feature) { using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask; switch (feature) { case WIFI_FEATURE_GSCAN: @@ -120,6 +120,8 @@ convertLegacyFeatureToHidlStaIfaceCapability(uint32_t feature) { return HidlStaIfaceCaps::ND_OFFLOAD; case WIFI_FEATURE_MKEEP_ALIVE: return HidlStaIfaceCaps::KEEP_ALIVE; + case WIFI_FEATURE_INFRA_6G: + return HidlStaIfaceCaps::STA_6G; }; CHECK(false) << "Unknown legacy feature: " << feature; return {}; @@ -365,7 +367,7 @@ bool convertLegacyWifiMacInfosToHidl( } bool convertLegacyFeaturesToHidlStaCapabilities( - uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set, + uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set, uint32_t* hidl_caps) { if (!hidl_caps) { return false; @@ -384,7 +386,8 @@ bool convertLegacyFeaturesToHidlStaCapabilities( WIFI_FEATURE_IE_WHITELIST, WIFI_FEATURE_SCAN_RAND, WIFI_FEATURE_INFRA_5G, WIFI_FEATURE_HOTSPOT, WIFI_FEATURE_PNO, WIFI_FEATURE_TDLS, WIFI_FEATURE_TDLS_OFFCHANNEL, - WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE}) { + WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE, + WIFI_FEATURE_INFRA_6G}) { if (feature & legacy_feature_set) { *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature); } diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h index a99c1ac051..cfaa4adccc 100644 --- a/wifi/1.4/default/hidl_struct_util.h +++ b/wifi/1.4/default/hidl_struct_util.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "wifi_legacy_hal.h" @@ -69,7 +70,7 @@ bool convertLegacyWifiMacInfosToHidl( // STA iface conversion methods. bool convertLegacyFeaturesToHidlStaCapabilities( - uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set, + uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set, uint32_t* hidl_caps); bool convertLegacyApfCapabilitiesToHidl( const legacy_hal::PacketFilterCapabilities& legacy_caps, diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp index 8139253272..ae3c447a01 100644 --- a/wifi/1.4/default/wifi_legacy_hal.cpp +++ b/wifi/1.4/default/wifi_legacy_hal.cpp @@ -479,7 +479,7 @@ WifiLegacyHal::requestFirmwareMemoryDump(const std::string& iface_name) { std::pair WifiLegacyHal::getSupportedFeatureSet( const std::string& iface_name) { feature_set set; - static_assert(sizeof(set) == sizeof(uint32_t), + static_assert(sizeof(set) == sizeof(uint64_t), "Some feature_flags can not be represented in output"); wifi_error status = global_func_table_.wifi_get_supported_feature_set( getIfaceHandle(iface_name), &set); diff --git a/wifi/1.4/default/wifi_sta_iface.cpp b/wifi/1.4/default/wifi_sta_iface.cpp index 3e0127ed2a..8e1ada1032 100644 --- a/wifi/1.4/default/wifi_sta_iface.cpp +++ b/wifi/1.4/default/wifi_sta_iface.cpp @@ -266,6 +266,13 @@ Return WifiStaIface::getFactoryMacAddress( hidl_status_cb); } +Return WifiStaIface::getCapabilities_1_4( + getCapabilities_cb hidl_status_cb) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::getCapabilitiesInternal_1_4, + hidl_status_cb); +} + std::pair WifiStaIface::getNameInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_}; } @@ -283,26 +290,7 @@ WifiStatus WifiStaIface::registerEventCallbackInternal( } std::pair WifiStaIface::getCapabilitiesInternal() { - legacy_hal::wifi_error legacy_status; - uint32_t legacy_feature_set; - std::tie(legacy_status, legacy_feature_set) = - legacy_hal_.lock()->getSupportedFeatureSet(ifname_); - if (legacy_status != legacy_hal::WIFI_SUCCESS) { - return {createWifiStatusFromLegacyError(legacy_status), 0}; - } - uint32_t legacy_logger_feature_set; - std::tie(legacy_status, legacy_logger_feature_set) = - legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_); - if (legacy_status != legacy_hal::WIFI_SUCCESS) { - // some devices don't support querying logger feature set - legacy_logger_feature_set = 0; - } - uint32_t hidl_caps; - if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities( - legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) { - return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0}; - } - return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps}; + return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0}; } std::pair @@ -640,6 +628,29 @@ WifiStaIface::getFactoryMacAddressInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), mac}; } +std::pair WifiStaIface::getCapabilitiesInternal_1_4() { + legacy_hal::wifi_error legacy_status; + uint64_t legacy_feature_set; + std::tie(legacy_status, legacy_feature_set) = + legacy_hal_.lock()->getSupportedFeatureSet(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {createWifiStatusFromLegacyError(legacy_status), 0}; + } + uint32_t legacy_logger_feature_set; + std::tie(legacy_status, legacy_logger_feature_set) = + legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + // some devices don't support querying logger feature set + legacy_logger_feature_set = 0; + } + uint32_t hidl_caps; + if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities( + legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) { + return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0}; + } + return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps}; +} + } // namespace implementation } // namespace V1_4 } // namespace wifi diff --git a/wifi/1.4/default/wifi_sta_iface.h b/wifi/1.4/default/wifi_sta_iface.h index d8f7a01ade..ccf234f98e 100644 --- a/wifi/1.4/default/wifi_sta_iface.h +++ b/wifi/1.4/default/wifi_sta_iface.h @@ -19,7 +19,7 @@ #include #include -#include +#include #include "hidl_callback_util.h" #include "wifi_iface_util.h" @@ -35,7 +35,7 @@ using namespace android::hardware::wifi::V1_0; /** * HIDL interface object used to control a STA Iface instance. */ -class WifiStaIface : public V1_3::IWifiStaIface { +class WifiStaIface : public V1_4::IWifiStaIface { public: WifiStaIface(const std::string& ifname, const std::weak_ptr legacy_hal, @@ -111,6 +111,8 @@ class WifiStaIface : public V1_3::IWifiStaIface { setMacAddress_cb hidl_status_cb) override; Return getFactoryMacAddress( getFactoryMacAddress_cb hidl_status_cb) override; + Return getCapabilities_1_4( + getCapabilities_1_4_cb hidl_status_cb) override; private: // Corresponding worker functions for the HIDL methods. @@ -159,6 +161,7 @@ class WifiStaIface : public V1_3::IWifiStaIface { WifiStatus setMacAddressInternal(const std::array& mac); std::pair> getFactoryMacAddressInternal(); + std::pair getCapabilitiesInternal_1_4(); std::string ifname_; std::weak_ptr legacy_hal_; diff --git a/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp new file mode 100644 index 0000000000..ec4b2c949d --- /dev/null +++ b/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Staache 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 + +#include + +#include "wifi_hidl_call_util.h" +#include "wifi_hidl_test_utils.h" + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::wifi::V1_0::WifiStatus; +using ::android::hardware::wifi::V1_0::WifiStatusCode; +using ::android::hardware::wifi::V1_4::IWifiStaIface; + +/** + * Fixture to use for all STA Iface HIDL interface tests. + */ +class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface()); + ASSERT_NE(nullptr, wifi_sta_iface_.get()); + } + + virtual void TearDown() override { stopWifi(); } + + protected: + sp wifi_sta_iface_; +}; + +/* + * GetCapabilities_1_4 + */ +TEST_F(WifiStaIfaceHidlTest, GetCapabilities_1_4) { + configureChipForIfaceType(IfaceType::STA, true); + + const auto& status_and_caps = + HIDL_INVOKE(wifi_sta_iface_, getCapabilities_1_4); + if (status_and_caps.first.code != WifiStatusCode::SUCCESS) { + EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, + status_and_caps.first.code); + return; + } + EXPECT_NE(0u, status_and_caps.second); +} From cf36cea0929bc106cbe32eee6212bed1d143c0f2 Mon Sep 17 00:00:00 2001 From: chrisweir Date: Fri, 8 Nov 2019 16:41:02 -0800 Subject: [PATCH 0241/1022] Add support for SLCAN * Adding support for SLCAN type interfaces * Made some of the formatting more consistent Bug: 142656299 Test: Manually with canhalctrl, canhaldump, and canhalsend Change-Id: Ifa4c234beb75f8a0ea93bfd75555c5ed8d68dca4 --- automotive/can/1.0/default/Android.bp | 1 + automotive/can/1.0/default/CanBus.cpp | 6 +- automotive/can/1.0/default/CanBus.h | 14 +- automotive/can/1.0/default/CanBusSlcan.cpp | 166 ++++++++++++++++++ automotive/can/1.0/default/CanBusSlcan.h | 50 ++++++ automotive/can/1.0/default/CanController.cpp | 13 +- automotive/can/1.0/default/CanSocket.cpp | 12 +- automotive/can/1.0/default/CanSocket.h | 4 +- automotive/can/1.0/default/CloseHandle.h | 4 +- .../1.0/default/libnetdevice/NetlinkRequest.h | 10 +- .../1.0/default/libnetdevice/NetlinkSocket.h | 6 +- .../libnetdevice/include/libnetdevice/can.h | 7 +- .../include/libnetdevice/libnetdevice.h | 26 +-- automotive/can/1.0/tools/canhaldump.cpp | 2 +- .../VtsHalCanBusVirtualV1_0TargetTest.cpp | 3 +- .../VtsHalCanControllerV1_0TargetTest.cpp | 3 +- 16 files changed, 275 insertions(+), 52 deletions(-) create mode 100644 automotive/can/1.0/default/CanBusSlcan.cpp create mode 100644 automotive/can/1.0/default/CanBusSlcan.h diff --git a/automotive/can/1.0/default/Android.bp b/automotive/can/1.0/default/Android.bp index 8aa1d6bff7..ee2e92bdb1 100644 --- a/automotive/can/1.0/default/Android.bp +++ b/automotive/can/1.0/default/Android.bp @@ -39,6 +39,7 @@ cc_binary { "CanBus.cpp", "CanBusNative.cpp", "CanBusVirtual.cpp", + "CanBusSlcan.cpp", "CanController.cpp", "CanSocket.cpp", "CloseHandle.cpp", diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp index 38a9974771..42d2e3c277 100644 --- a/automotive/can/1.0/default/CanBus.cpp +++ b/automotive/can/1.0/default/CanBus.cpp @@ -30,9 +30,7 @@ namespace can { namespace V1_0 { namespace implementation { -/** - * Whether to log sent/received packets. - */ +/** Whether to log sent/received packets. */ static constexpr bool kSuperVerbose = false; Return CanBus::send(const CanMessage& message) { @@ -85,6 +83,8 @@ Return CanBus::listen(const hidl_vec& filter, return {}; } +CanBus::CanBus() {} + CanBus::CanBus(const std::string& ifname) : mIfname(ifname) {} CanBus::~CanBus() { diff --git a/automotive/can/1.0/default/CanBus.h b/automotive/can/1.0/default/CanBus.h index 30a2924942..365e90c439 100644 --- a/automotive/can/1.0/default/CanBus.h +++ b/automotive/can/1.0/default/CanBus.h @@ -48,12 +48,22 @@ struct CanBus : public ICanBus { bool down(); protected: + /** + * Blank constructor, since some interface types (such as SLCAN) don't get a name until after + * being initialized. + * + * If using this constructor, you MUST initialize mIfname prior to the completion of preUp(). + */ + CanBus(); + CanBus(const std::string& ifname); /** * Prepare the SocketCAN interface. * * After calling this method, mIfname network interface is available and ready to be brought up. + * + * \return OK on success, or an error state on failure. See ICanController::Result */ virtual ICanController::Result preUp(); @@ -61,11 +71,13 @@ struct CanBus : public ICanBus { * Cleanup after bringing the interface down. * * This is a counterpart to preUp(). + * + * \return true upon success and false upon failure */ virtual bool postDown(); /** Network interface name. */ - const std::string mIfname; + std::string mIfname; private: struct CanMessageListener { diff --git a/automotive/can/1.0/default/CanBusSlcan.cpp b/automotive/can/1.0/default/CanBusSlcan.cpp new file mode 100644 index 0000000000..7dce838ff1 --- /dev/null +++ b/automotive/can/1.0/default/CanBusSlcan.cpp @@ -0,0 +1,166 @@ +/* + * 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. + */ + +#include "CanBusSlcan.h" + +#include +#include +#include + +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace implementation { + +namespace slcanprotocol { +static const std::string kOpenCommand = "O\r"; +static const std::string kCloseCommand = "C\r"; +static constexpr int kSlcanDiscipline = N_SLCAN; +static constexpr int kDefaultDiscipline = N_TTY; + +static const std::map kBitrateCommands = { + {10000, "C\rS0\r"}, {20000, "C\rS1\r"}, {50000, "C\rS2\r"}, + {100000, "C\rS3\r"}, {125000, "C\rS4\r"}, {250000, "C\rS5\r"}, + {500000, "C\rS6\r"}, {800000, "C\rS7\r"}, {1000000, "C\rS8\r"}}; +} // namespace slcanprotocol + +/** + * Serial Line CAN constructor + * \param string uartName - name of slcan device (e.x. /dev/ttyUSB0) + * \param uint32_t bitrate - speed of the CAN bus (125k = MSCAN, 500k = HSCAN) + */ +CanBusSlcan::CanBusSlcan(const std::string& uartName, uint32_t bitrate) + : CanBus(), mUartName(uartName), kBitrate(bitrate) {} + +ICanController::Result CanBusSlcan::preUp() { + // verify valid bitrate and translate to serial command format + const auto lookupIt = slcanprotocol::kBitrateCommands.find(kBitrate); + if (lookupIt == slcanprotocol::kBitrateCommands.end()) { + return ICanController::Result::BAD_BAUDRATE; + } + const auto canBitrateCommand = lookupIt->second; + + /* Attempt to open the uart in r/w without blocking or becoming the + * controlling terminal */ + mFd = base::unique_fd(open(mUartName.c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY)); + if (!mFd.ok()) { + LOG(ERROR) << "SLCAN Failed to open " << mUartName << ": " << strerror(errno); + return ICanController::Result::BAD_ADDRESS; + } + + // blank terminal settings and pull them from the device + struct termios terminalSettings = {}; + if (tcgetattr(mFd.get(), &terminalSettings) < 0) { + LOG(ERROR) << "Failed to read attrs of" << mUartName << ": " << strerror(errno); + return ICanController::Result::UNKNOWN_ERROR; + } + + // change settings to raw mode + cfmakeraw(&terminalSettings); + + // disable software flow control + terminalSettings.c_iflag &= ~IXOFF; + // enable hardware flow control + terminalSettings.c_cflag |= CRTSCTS; + + struct serial_struct serialSettings; + // get serial settings + if (ioctl(mFd.get(), TIOCGSERIAL, &serialSettings) < 0) { + LOG(ERROR) << "Failed to read serial settings from " << mUartName << ": " + << strerror(errno); + return ICanController::Result::UNKNOWN_ERROR; + } + // set low latency mode + serialSettings.flags |= ASYNC_LOW_LATENCY; + // apply serial settings + if (ioctl(mFd.get(), TIOCSSERIAL, &serialSettings) < 0) { + LOG(ERROR) << "Failed to set low latency mode on " << mUartName << ": " << strerror(errno); + return ICanController::Result::UNKNOWN_ERROR; + } + + /* TCSADRAIN applies settings after we finish writing the rest of our + * changes (as opposed to TCSANOW, which changes immediately) */ + if (tcsetattr(mFd.get(), TCSADRAIN, &terminalSettings) < 0) { + LOG(ERROR) << "Failed to apply terminal settings to " << mUartName << ": " + << strerror(errno); + return ICanController::Result::UNKNOWN_ERROR; + } + + // apply speed setting for CAN + if (write(mFd.get(), canBitrateCommand.c_str(), canBitrateCommand.length()) <= 0) { + LOG(ERROR) << "Failed to apply CAN bitrate: " << strerror(errno); + return ICanController::Result::UNKNOWN_ERROR; + } + + // set open flag TODO: also support listen only + if (write(mFd.get(), slcanprotocol::kOpenCommand.c_str(), + slcanprotocol::kOpenCommand.length()) <= 0) { + LOG(ERROR) << "Failed to set open flag: " << strerror(errno); + return ICanController::Result::UNKNOWN_ERROR; + } + + // set line discipline to slcan + if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kSlcanDiscipline) < 0) { + LOG(ERROR) << "Failed to set line discipline to slcan: " << strerror(errno); + return ICanController::Result::UNKNOWN_ERROR; + } + + // get the name of the device we created + struct ifreq ifrequest = {}; + if (ioctl(mFd.get(), SIOCGIFNAME, ifrequest.ifr_name) < 0) { + LOG(ERROR) << "Failed to get the name of the created device: " << strerror(errno); + return ICanController::Result::UNKNOWN_ERROR; + } + + // Update the CanBus object with name that was assigned to it + mIfname = ifrequest.ifr_name; + + return ICanController::Result::OK; +} + +bool CanBusSlcan::postDown() { + // reset the line discipline to TTY mode + if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kDefaultDiscipline) < 0) { + LOG(ERROR) << "Failed to reset line discipline!"; + return false; + } + + // issue the close command + if (write(mFd.get(), slcanprotocol::kCloseCommand.c_str(), + slcanprotocol::kCloseCommand.length()) <= 0) { + LOG(ERROR) << "Failed to close tty!"; + return false; + } + + // close our unique_fd + mFd.reset(); + + return true; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/can/1.0/default/CanBusSlcan.h b/automotive/can/1.0/default/CanBusSlcan.h new file mode 100644 index 0000000000..2713da86d9 --- /dev/null +++ b/automotive/can/1.0/default/CanBusSlcan.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include "CanBus.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace can { +namespace V1_0 { +namespace implementation { + +struct CanBusSlcan : public CanBus { + CanBusSlcan(const std::string& uartName, uint32_t bitrate); + + protected: + virtual ICanController::Result preUp() override; + virtual bool postDown() override; + + private: + const std::string mUartName; + const uint32_t kBitrate; + base::unique_fd mFd; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace can +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp index 3b63fe404b..ffdc9125fc 100644 --- a/automotive/can/1.0/default/CanController.cpp +++ b/automotive/can/1.0/default/CanController.cpp @@ -17,6 +17,7 @@ #include "CanController.h" #include "CanBusNative.h" +#include "CanBusSlcan.h" #include "CanBusVirtual.h" #include @@ -34,10 +35,8 @@ namespace implementation { using IfaceIdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator; Return CanController::getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) { - _hidl_cb({ - ICanController::InterfaceType::VIRTUAL, - ICanController::InterfaceType::SOCKETCAN, - }); + _hidl_cb({ICanController::InterfaceType::VIRTUAL, ICanController::InterfaceType::SOCKETCAN, + ICanController::InterfaceType::SLCAN}); return {}; } @@ -77,6 +76,12 @@ Return CanController::upInterface( } else { return ICanController::Result::BAD_ADDRESS; } + } else if (config.iftype == ICanController::InterfaceType::SLCAN) { + if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) { + busService = new CanBusSlcan(config.interfaceId.address(), config.baudrate); + } else { + return ICanController::Result::BAD_ADDRESS; + } } else { return ICanController::Result::NOT_SUPPORTED; } diff --git a/automotive/can/1.0/default/CanSocket.cpp b/automotive/can/1.0/default/CanSocket.cpp index ecf4044db8..86e12d19b1 100644 --- a/automotive/can/1.0/default/CanSocket.cpp +++ b/automotive/can/1.0/default/CanSocket.cpp @@ -33,12 +33,10 @@ namespace implementation { using namespace std::chrono_literals; -/** - * How frequently the read thread checks whether the interface was asked to be down. +/* How frequently the read thread checks whether the interface was asked to be down. * * Note: This does *not* affect read timing or bandwidth, just CPU load vs time to - * down the interface. - */ + * down the interface. */ static constexpr auto kReadPooling = 100ms; std::unique_ptr CanSocket::open(const std::string& ifname, ReadCallback rdcb, @@ -105,8 +103,7 @@ void CanSocket::readerThread() { while (!mStopReaderThread) { /* The ideal would be to have a blocking read(3) call and interrupt it with shutdown(3). - * This is unfortunately not supported for SocketCAN, so we need to rely on select(3). - */ + * This is unfortunately not supported for SocketCAN, so we need to rely on select(3). */ const auto sel = selectRead(mSocket, kReadPooling); if (sel == 0) continue; // timeout if (sel == -1) { @@ -127,8 +124,7 @@ void CanSocket::readerThread() { * Apart from the added complexity, it's possible the added calculations and system calls * would add so much time to the processing pipeline so the precision of the reported time * was buried under the subsystem latency. Let's just use a local time since boot here and - * leave precise hardware timestamps for custom proprietary implementations (if needed). - */ + * leave precise hardware timestamps for custom proprietary implementations (if needed). */ const std::chrono::nanoseconds ts(elapsedRealtimeNano()); if (nbytes != CAN_MTU) { diff --git a/automotive/can/1.0/default/CanSocket.h b/automotive/can/1.0/default/CanSocket.h index 284e1ea25e..c98330bfe0 100644 --- a/automotive/can/1.0/default/CanSocket.h +++ b/automotive/can/1.0/default/CanSocket.h @@ -31,9 +31,7 @@ namespace can { namespace V1_0 { namespace implementation { -/** - * Wrapper around SocketCAN socket. - */ +/** Wrapper around SocketCAN socket. */ struct CanSocket { using ReadCallback = std::function; using ErrorCallback = std::function; diff --git a/automotive/can/1.0/default/CloseHandle.h b/automotive/can/1.0/default/CloseHandle.h index 5191739e07..eade1098a4 100644 --- a/automotive/can/1.0/default/CloseHandle.h +++ b/automotive/can/1.0/default/CloseHandle.h @@ -26,9 +26,7 @@ namespace can { namespace V1_0 { namespace implementation { -/** - * Generic ICloseHandle implementation ignoring double-close events. - */ +/** Generic ICloseHandle implementation ignoring double-close events. */ struct CloseHandle : public ICloseHandle { using Callback = std::function; diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h index 21202e39bc..ba9b65bdd3 100644 --- a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h +++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h @@ -27,9 +27,7 @@ namespace netdevice { typedef unsigned short rtattrtype_t; // as in rtnetlink.h typedef __u16 nlmsgtype_t; // as in netlink.h -/** - * Implementation details, do not use outside NetlinkRequest template. - */ +/** Implementation details, do not use outside NetlinkRequest template. */ namespace impl { struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data, @@ -59,7 +57,7 @@ struct NetlinkRequest { mRequest.nlmsg.nlmsg_flags = flags; } - /** Returns pointer to raw netlink message header. */ + /** \return pointer to raw netlink message header. */ struct nlmsghdr* header() { return &mRequest.nlmsg; } @@ -89,9 +87,7 @@ struct NetlinkRequest { if (ap == nullptr) mIsGood = false; } - /** - * Guard class to frame nested attributes. See nest(int). - */ + /** Guard class to frame nested attributes. See nest(int). */ struct Nest { Nest(NetlinkRequest& req, rtattrtype_t type) : mReq(req), mAttr(req.nestStart(type)) {} ~Nest() { mReq.nestEnd(mAttr); } diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h index 81d6224e7f..90e1f3f95d 100644 --- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h +++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h @@ -38,8 +38,8 @@ struct NetlinkSocket { /** * Send Netlink message to Kernel. * - * @param msg Message to send, nlmsg_seq will be set to next sequence number - * @return true, if succeeded + * \param msg Message to send, nlmsg_seq will be set to next sequence number + * \return true, if succeeded */ template bool send(NetlinkRequest& req) { @@ -50,7 +50,7 @@ struct NetlinkSocket { /** * Receive Netlink ACK message from Kernel. * - * @return true if received ACK message, false in case of error + * \return true if received ACK message, false in case of error */ bool receiveAck(); diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h index ec3f96257a..d75361eaa0 100644 --- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h +++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h @@ -27,13 +27,16 @@ namespace can { /** * Opens and binds SocketCAN socket. * - * @param ifname Interface to open a socket against - * @return Socket's FD or -1 in case of failure + * \param ifname Interface to open a socket against + * \return Socket's FD or -1 in case of failure */ base::unique_fd socket(const std::string& ifname); /** * Sets CAN interface bitrate. + * + * \param ifname Interface for which the bitrate is to be set + * \return true on success, false on failure */ bool setBitrate(std::string ifname, uint32_t bitrate); diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h index 33d5de5ef8..e22eafb723 100644 --- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h +++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h @@ -25,49 +25,49 @@ namespace netdevice { /** * Checks, if the network interface exists. * - * @param ifname Interface to check - * @return true if it exists, false otherwise + * \param ifname Interface to check + * \return true if it exists, false otherwise */ bool exists(std::string ifname); /** * Checks if network interface is up. * - * @param ifname Interface to check - * @return true/false if the check succeeded, nullopt otherwise + * \param ifname Interface to check + * \return true/false if the check succeeded, nullopt otherwise */ std::optional isUp(std::string ifname); /** * Brings network interface up. * - * @param ifname Interface to bring up - * @return true in case of success, false otherwise + * \param ifname Interface to bring up + * \return true in case of success, false otherwise */ bool up(std::string ifname); /** * Brings network interface down. * - * @param ifname Interface to bring down - * @return true in case of success, false otherwise + * \param ifname Interface to bring down + * \return true in case of success, false otherwise */ bool down(std::string ifname); /** * Adds virtual link. * - * @param dev the name of the new virtual device - * @param type the type of the new device - * @return true in case of success, false otherwise + * \param dev the name of the new virtual device + * \param type the type of the new device + * \return true in case of success, false otherwise */ bool add(std::string dev, std::string type); /** * Deletes virtual link. * - * @param dev the name of the device to remove - * @return true in case of success, false otherwise + * \param dev the name of the device to remove + * \return true in case of success, false otherwise */ bool del(std::string dev); diff --git a/automotive/can/1.0/tools/canhaldump.cpp b/automotive/can/1.0/tools/canhaldump.cpp index 5713d17e8d..99fd14a7dc 100644 --- a/automotive/can/1.0/tools/canhaldump.cpp +++ b/automotive/can/1.0/tools/canhaldump.cpp @@ -49,7 +49,7 @@ struct CanMessageListener : public V1_0::ICanMessageListener { } else { std::cout << " [" << message.payload.size() << "] "; for (const auto byte : message.payload) { - std::cout << " " << unsigned(byte); + std::cout << " " << std::setfill('0') << std::setw(2) << unsigned(byte); } } std::cout << std::nouppercase << std::dec << std::endl; diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp index ba29c29e9c..225984dd93 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp @@ -91,8 +91,7 @@ struct Bus { EXPECT_EQ(ICanController::Result::OK, result); /* Not using ICanBus::getService here, since it ignores interfaces not in the manifest - * file -- this is a test, so we don't want to add dummy services to a device manifest. - */ + * file -- this is a test, so we don't want to add dummy services to a device manifest. */ auto manager = hidl::manager::V1_2::IServiceManager::getService(); auto service = manager->get(ICanBus::descriptor, config.name); mBus = ICanBus::castFrom(service); diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp index 70f9fe44b5..64e7a96823 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp @@ -95,8 +95,7 @@ bool CanControllerHalTest::up(InterfaceType iftype, std::string srvname, std::st void CanControllerHalTest::assertRegistered(std::string srvname, bool expectRegistered) { /* Not using ICanBus::tryGetService here, since it ignores interfaces not in the manifest - * file -- this is a test, so we don't want to add dummy services to a device manifest. - */ + * file -- this is a test, so we don't want to add dummy services to a device manifest. */ auto manager = hidl::manager::V1_2::IServiceManager::getService(); auto busService = manager->get(ICanBus::descriptor, srvname); ASSERT_EQ(expectRegistered, busService.withDefault(nullptr) != nullptr) From 03b66e1dedb2f2ebd3fda7037f928959a4b856c8 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Tue, 5 Nov 2019 14:47:28 -0800 Subject: [PATCH 0242/1022] graphics/common: add stable AIDL types Gralloc 4 (IAllocator 4.0 and IMapper 4.0) is a HIDL interface that will support getting and setting buffer metadata. To allow vendors to easily add arbitrary metadata, the interface accepts metadata as a bytestream. Some of the metadata gralloc 4 will use is already defined in HIDL. Unfortunately, some of the metadata was defined in composer which is a binderized HIDL interface. IMapper is a HIDL-SP interface so it cannot reuse composer's definitions. Since the display HIDL interfaces will likely move to stable AIDL soon, redefine the metadata in stable AIDL. IMapper uses a byte stream so the types can be defined anywhere. By redefining the types in stable AIDL, we won't have three definitons of the exact same type in the future. Bug: 141632767 Test: N/A - This patch just adds types. There are tests in the patches that use the types. Change-Id: Icaf6200c327d71a41d66a3e66dd6890ab5c2041a --- graphics/common/aidl/Android.bp | 20 + .../hardware/graphics/common/BlendMode.aidl | 35 + .../graphics/common/ChromaSiting.aidl | 39 + .../hardware/graphics/common/Compression.aidl | 30 + .../hardware/graphics/common/Dataspace.aidl | 682 ++++++++++++++++++ .../graphics/common/ExtendableType.aidl | 52 ++ .../hardware/graphics/common/Interlaced.aidl | 35 + .../hardware/graphics/common/PlaneLayout.aidl | 125 ++++ .../graphics/common/PlaneLayoutComponent.aidl | 67 ++ .../common/PlaneLayoutComponentType.aidl | 46 ++ .../hardware/graphics/common/Rect.aidl | 29 + .../graphics/common/StandardMetadataType.aidl | 282 ++++++++ 12 files changed, 1442 insertions(+) create mode 100644 graphics/common/aidl/Android.bp create mode 100644 graphics/common/aidl/android/hardware/graphics/common/BlendMode.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/ChromaSiting.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/Compression.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/Interlaced.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/Rect.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp new file mode 100644 index 0000000000..497c0f824d --- /dev/null +++ b/graphics/common/aidl/Android.bp @@ -0,0 +1,20 @@ +aidl_interface { + name: "vintf-graphics-common", + vendor_available: true, + vndk: { + enabled: true, + support_system_process: true, + }, + srcs: [ + "android/hardware/graphics/common/*.aidl", + ], + stability: "vintf", + backend: { + java: { + enabled: false, + }, + cpp: { + enabled: false, + }, + }, +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/BlendMode.aidl b/graphics/common/aidl/android/hardware/graphics/common/BlendMode.aidl new file mode 100644 index 0000000000..242813555b --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/BlendMode.aidl @@ -0,0 +1,35 @@ +/** + * 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. + */ + +package android.hardware.graphics.common; + +/** + * Blend modes, settable per layer. + */ +@VintfStability +@Backing(type="int") +enum BlendMode { + INVALID = 0, + + /** colorOut = colorSrc */ + NONE = 1, + + /** colorOut = colorSrc + colorDst * (1 - alphaSrc) */ + PREMULTIPLIED = 2, + + /** colorOut = colorSrc * alphaSrc + colorDst * (1 - alphaSrc) */ + COVERAGE = 3, +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/ChromaSiting.aidl b/graphics/common/aidl/android/hardware/graphics/common/ChromaSiting.aidl new file mode 100644 index 0000000000..562a664587 --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/ChromaSiting.aidl @@ -0,0 +1,39 @@ +/** + * 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. + */ + +package android.hardware.graphics.common; + +/** + * Used by IAllocator/IMapper (gralloc) to describe standard chroma siting + */ +@VintfStability +@Backing(type="long") +enum ChromaSiting { + /* This format does not have chroma siting. */ + NONE = 0, + + /* This format has chroma siting but the type being used is unknown. */ + UNKNOWN = 1, + + /* Cb and Cr are sited interstitially, halfway between alternate luma samples. + * This is used by 4:2:0 for JPEG/JFIF, H.261, MPEG-1. */ + SITED_INTERSTITIAL = 2, + + /* Cb and Cr are horizontally sited coincident with a luma sample. + * Cb and Cr are vertically sited interstitially. + * This is used by 4:2:0 for MPEG-2 frame pictures. */ + COSITED_HORIZONTAL = 3, +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/Compression.aidl b/graphics/common/aidl/android/hardware/graphics/common/Compression.aidl new file mode 100644 index 0000000000..4cca1baff0 --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/Compression.aidl @@ -0,0 +1,30 @@ +/** + * 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. + */ + +package android.hardware.graphics.common; + +/** + * Used by IAllocator/IMapper (gralloc) to describe standard compression strategies + */ +@VintfStability +@Backing(type="long") +enum Compression { + /* Represents all uncompressed buffers */ + NONE = 0, + + /* VESA Display Stream Compression (DSC) */ + DISPLAY_STREAM_COMPRESSION = 1, +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl new file mode 100644 index 0000000000..81a21ab180 --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl @@ -0,0 +1,682 @@ +/** + * 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. + */ + +package android.hardware.graphics.common; + +@VintfStability +@Backing(type="int") +enum Dataspace { + /** + * Default-assumption data space, when not explicitly specified. + * + * It is safest to assume the buffer is an image with sRGB primaries and + * encoding ranges, but the consumer and/or the producer of the data may + * simply be using defaults. No automatic gamma transform should be + * expected, except for a possible display gamma transform when drawn to a + * screen. + */ + UNKNOWN = 0x0, + + /** + * Arbitrary dataspace with manually defined characteristics. Definition + * for colorspaces or other meaning must be communicated separately. + * + * This is used when specifying primaries, transfer characteristics, + * etc. separately. + * + * A typical use case is in video encoding parameters (e.g. for H.264), + * where a colorspace can have separately defined primaries, transfer + * characteristics, etc. + */ + ARBITRARY = 0x1, + + /** + * Color-description aspects + * + * The following aspects define various characteristics of the color + * specification. These represent bitfields, so that a data space value + * can specify each of them independently. + */ + + STANDARD_SHIFT = 16, + + /** + * Standard aspect + * + * Defines the chromaticity coordinates of the source primaries in terms of + * the CIE 1931 definition of x and y specified in ISO 11664-1. + */ + STANDARD_MASK = 63 << 16, // 63 << STANDARD_SHIFT = 0x3F + + /** + * Chromacity coordinates are unknown or are determined by the application. + * Implementations shall use the following suggested standards: + * + * All YCbCr formats: BT709 if size is 720p or larger (since most video + * content is letterboxed this corresponds to width is + * 1280 or greater, or height is 720 or greater). + * BT601_625 if size is smaller than 720p or is JPEG. + * All RGB formats: BT709. + * + * For all other formats standard is undefined, and implementations should use + * an appropriate standard for the data represented. + */ + STANDARD_UNSPECIFIED = 0 << 16, // STANDARD_SHIFT + + /** + * Primaries: x y + * green 0.300 0.600 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + * + * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation + * for RGB conversion. + */ + STANDARD_BT709 = 1 << 16, // 1 << STANDARD_SHIFT + + /** + * Primaries: x y + * green 0.290 0.600 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + * + * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation + * for RGB conversion from the one purely determined by the primaries + * to minimize the color shift into RGB space that uses BT.709 + * primaries. + */ + STANDARD_BT601_625 = 2 << 16, // 2 << STANDARD_SHIFT, + + /** + * Primaries: x y + * green 0.290 0.600 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + * + * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation + * for RGB conversion. + */ + STANDARD_BT601_625_UNADJUSTED = 3 << 16, // 3 << STANDARD_SHIFT + + /** + * Primaries: x y + * green 0.310 0.595 + * blue 0.155 0.070 + * red 0.630 0.340 + * white (D65) 0.3127 0.3290 + * + * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation + * for RGB conversion from the one purely determined by the primaries + * to minimize the color shift into RGB space that uses BT.709 + * primaries. + */ + STANDARD_BT601_525 = 4 << 16, // 4 << STANDARD_SHIFT + + /** + * Primaries: x y + * green 0.310 0.595 + * blue 0.155 0.070 + * red 0.630 0.340 + * white (D65) 0.3127 0.3290 + * + * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation + * for RGB conversion (as in SMPTE 240M). + */ + STANDARD_BT601_525_UNADJUSTED = 5 << 16, // 5 << STANDARD_SHIFT + + /** + * Primaries: x y + * green 0.170 0.797 + * blue 0.131 0.046 + * red 0.708 0.292 + * white (D65) 0.3127 0.3290 + * + * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation + * for RGB conversion. + */ + STANDARD_BT2020 = 6 << 16, // 6 << STANDARD_SHIFT + + /** + * Primaries: x y + * green 0.170 0.797 + * blue 0.131 0.046 + * red 0.708 0.292 + * white (D65) 0.3127 0.3290 + * + * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation + * for RGB conversion using the linear domain. + */ + STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << 16, // 7 << STANDARD_SHIFT + + /** + * Primaries: x y + * green 0.21 0.71 + * blue 0.14 0.08 + * red 0.67 0.33 + * white (C) 0.310 0.316 + * + * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation + * for RGB conversion. + */ + STANDARD_BT470M = 8 << 16, // 8 << STANDARD_SHIFT + + /** + * Primaries: x y + * green 0.243 0.692 + * blue 0.145 0.049 + * red 0.681 0.319 + * white (C) 0.310 0.316 + * + * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation + * for RGB conversion. + */ + STANDARD_FILM = 9 << 16, // 9 << STANDARD_SHIFT + + /** + * SMPTE EG 432-1 and SMPTE RP 431-2. (DCI-P3) + * Primaries: x y + * green 0.265 0.690 + * blue 0.150 0.060 + * red 0.680 0.320 + * white (D65) 0.3127 0.3290 + */ + STANDARD_DCI_P3 = 10 << 16, // 10 << STANDARD_SHIFT + + /** + * Adobe RGB + * Primaries: x y + * green 0.210 0.710 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + */ + STANDARD_ADOBE_RGB = 11 << 16, // 11 << STANDARD_SHIFT + + + + TRANSFER_SHIFT = 22, + + /** + * Transfer aspect + * + * Transfer characteristics are the opto-electronic transfer characteristic + * at the source as a function of linear optical intensity (luminance). + * + * For digital signals, E corresponds to the recorded value. Normally, the + * transfer function is applied in RGB space to each of the R, G and B + * components independently. This may result in color shift that can be + * minized by applying the transfer function in Lab space only for the L + * component. Implementation may apply the transfer function in RGB space + * for all pixel formats if desired. + */ + + TRANSFER_MASK = 31 << 22, // 31 << TRANSFER_SHIFT = 0x1F + + /** + * Transfer characteristics are unknown or are determined by the + * application. + * + * Implementations should use the following transfer functions: + * + * For YCbCr formats: use TRANSFER_SMPTE_170M + * For RGB formats: use TRANSFER_SRGB + * + * For all other formats transfer function is undefined, and implementations + * should use an appropriate standard for the data represented. + */ + TRANSFER_UNSPECIFIED = 0 << 22, // 0 << TRANSFER_SHIFT + + /** + * Transfer characteristic curve: + * E = L + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + */ + TRANSFER_LINEAR = 1 << 22, // 1 << TRANSFER_SHIFT + + /** + * Transfer characteristic curve: + * + * E = 1.055 * L^(1/2.4) - 0.055 for 0.0031308 <= L <= 1 + * = 12.92 * L for 0 <= L < 0.0031308 + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + */ + TRANSFER_SRGB = 2 << 22, // 2 << TRANSFER_SHIFT + + /** + * BT.601 525, BT.601 625, BT.709, BT.2020 + * + * Transfer characteristic curve: + * E = 1.099 * L ^ 0.45 - 0.099 for 0.018 <= L <= 1 + * = 4.500 * L for 0 <= L < 0.018 + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + */ + TRANSFER_SMPTE_170M = 3 << 22, // 3 << TRANSFER_SHIFT + + /** + * Assumed display gamma 2.2. + * + * Transfer characteristic curve: + * E = L ^ (1/2.2) + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + */ + TRANSFER_GAMMA2_2 = 4 << 22, // 4 << TRANSFER_SHIFT + + /** + * display gamma 2.6. + * + * Transfer characteristic curve: + * E = L ^ (1/2.6) + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + */ + TRANSFER_GAMMA2_6 = 5 << 22, // 5 << TRANSFER_SHIFT + + /** + * display gamma 2.8. + * + * Transfer characteristic curve: + * E = L ^ (1/2.8) + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + */ + TRANSFER_GAMMA2_8 = 6 << 22, // 6 << TRANSFER_SHIFT + + /** + * SMPTE ST 2084 (Dolby Perceptual Quantizer) + * + * Transfer characteristic curve: + * E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m + * c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375 + * c2 = 32 * 2413 / 4096 = 18.8515625 + * c3 = 32 * 2392 / 4096 = 18.6875 + * m = 128 * 2523 / 4096 = 78.84375 + * n = 0.25 * 2610 / 4096 = 0.1593017578125 + * L - luminance of image 0 <= L <= 1 for HDR colorimetry. + * L = 1 corresponds to 10000 cd/m2 + * E - corresponding electrical signal + */ + TRANSFER_ST2084 = 7 << 22, // 7 << TRANSFER_SHIFT + + /** + * ARIB STD-B67 Hybrid Log Gamma + * + * Transfer characteristic curve: + * E = r * L^0.5 for 0 <= L <= 1 + * = a * ln(L - b) + c for 1 < L + * a = 0.17883277 + * b = 0.28466892 + * c = 0.55991073 + * r = 0.5 + * L - luminance of image 0 <= L for HDR colorimetry. L = 1 corresponds + * to reference white level of 100 cd/m2 + * E - corresponding electrical signal + */ + TRANSFER_HLG = 8 << 22, // 8 << TRANSFER_SHIFT + + RANGE_SHIFT = 27, + + /** + * Range aspect + * + * Defines the range of values corresponding to the unit range of 0-1. + * This is defined for YCbCr only, but can be expanded to RGB space. + */ + RANGE_MASK = 7 << 27, // 7 << RANGE_SHIFT = 0x7 + + /** + * Range is unknown or are determined by the application. Implementations + * shall use the following suggested ranges: + * + * All YCbCr formats: limited range. + * All RGB or RGBA formats (including RAW and Bayer): full range. + * All Y formats: full range + * + * For all other formats range is undefined, and implementations should use + * an appropriate range for the data represented. + */ + RANGE_UNSPECIFIED = 0 << 27, // 0 << RANGE_SHIFT = 0x0 + + /** + * Full range uses all values for Y, Cb and Cr from + * 0 to 2^b-1, where b is the bit depth of the color format. + */ + RANGE_FULL = 1 << 27, // 1 << RANGE_SHIFT = 0x8000000 + + /** + * Limited range uses values 16/256*2^b to 235/256*2^b for Y, and + * 1/16*2^b to 15/16*2^b for Cb, Cr, R, G and B, where b is the bit depth of + * the color format. + * + * E.g. For 8-bit-depth formats: + * Luma (Y) samples should range from 16 to 235, inclusive + * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive + * + * For 10-bit-depth formats: + * Luma (Y) samples should range from 64 to 940, inclusive + * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive + */ + RANGE_LIMITED = 2 << 27, // 2 << RANGE_SHIFT = 0x10000000 + + /** + * Extended range is used for scRGB. Intended for use with + * floating point pixel formats. [0.0 - 1.0] is the standard + * sRGB space. Values outside the range 0.0 - 1.0 can encode + * color outside the sRGB gamut. + * Used to blend / merge multiple dataspaces on a single display. + */ + RANGE_EXTENDED = 3 << 27, // 3 << RANGE_SHIFT = 0x18000000 + + /** + * sRGB linear encoding: + * + * The red, green, and blue components are stored in sRGB space, but + * are linear, not gamma-encoded. + * The RGB primaries and the white point are the same as BT.709. + * + * The values are encoded using the full range ([0,255] for 8-bit) for all + * components. + */ + SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // deprecated, use V0_SRGB_LINEAR + + V0_SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL + + + /** + * scRGB linear encoding: + * + * The red, green, and blue components are stored in extended sRGB space, + * but are linear, not gamma-encoded. + * The RGB primaries and the white point are the same as BT.709. + * + * The values are floating point. + * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits. + * Values beyond the range [0.0 - 1.0] would correspond to other colors + * spaces and/or HDR content. + */ + V0_SCRGB_LINEAR = 1 << 16 | 1 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED + + + /** + * sRGB gamma encoding: + * + * The red, green and blue components are stored in sRGB space, and + * converted to linear space when read, using the SRGB transfer function + * for each of the R, G and B components. When written, the inverse + * transformation is performed. + * + * The alpha component, if present, is always stored in linear space and + * is left unmodified when read or written. + * + * Use full range and BT.709 standard. + */ + SRGB = 1 << 16 | 2 << 22 | 1 << 27, // deprecated, use V0_SRGB + + V0_SRGB = 1 << 16 | 2 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL + + + /** + * scRGB: + * + * The red, green, and blue components are stored in extended sRGB space, + * but are linear, not gamma-encoded. + * The RGB primaries and the white point are the same as BT.709. + * + * The values are floating point. + * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits. + * Values beyond the range [0.0 - 1.0] would correspond to other colors + * spaces and/or HDR content. + */ + V0_SCRGB = 1 << 16 | 2 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED + + /** + * YCbCr Colorspaces + * ----------------- + * + * Primaries are given using (x,y) coordinates in the CIE 1931 definition + * of x and y specified by ISO 11664-1. + * + * Transfer characteristics are the opto-electronic transfer characteristic + * at the source as a function of linear optical intensity (luminance). + */ + + /** + * JPEG File Interchange Format (JFIF) + * + * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255 + * + * Use full range, BT.601 transfer and BT.601_625 standard. + */ + JFIF = 2 << 16 | 3 << 22 | 1 << 27, // deprecated, use V0_JFIF + + V0_JFIF = 2 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL + + /** + * ITU-R Recommendation 601 (BT.601) - 625-line + * + * Standard-definition television, 625 Lines (PAL) + * + * Use limited range, BT.601 transfer and BT.601_625 standard. + */ + BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT601_625 + + V0_BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED + + + /** + * ITU-R Recommendation 601 (BT.601) - 525-line + * + * Standard-definition television, 525 Lines (NTSC) + * + * Use limited range, BT.601 transfer and BT.601_525 standard. + */ + BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT601_525 + + V0_BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED + + /** + * ITU-R Recommendation 709 (BT.709) + * + * High-definition television + * + * Use limited range, BT.709 transfer and BT.709 standard. + */ + BT709 = 1 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT709 + + V0_BT709 = 1 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED + + + /** + * SMPTE EG 432-1 and SMPTE RP 431-2. + * + * Digital Cinema DCI-P3 + * + * Use full range, linear transfer and D65 DCI-P3 standard + */ + DCI_P3_LINEAR = 10 << 16 | 1 << 22 | 1 << 27, // STANDARD_DCI_P3 | TRANSFER_LINEAR | RANGE_FULL + + + /** + * SMPTE EG 432-1 and SMPTE RP 431-2. + * + * Digital Cinema DCI-P3 + * + * Use full range, gamma 2.6 transfer and D65 DCI-P3 standard + * Note: Application is responsible for gamma encoding the data as + * a 2.6 gamma encoding is not supported in HW. + */ + DCI_P3 = 10 << 16 | 5 << 22 | 1 << 27, // STANDARD_DCI_P3 | TRANSFER_GAMMA2_6 | RANGE_FULL + + + /** + * Display P3 + * + * Display P3 uses same primaries and white-point as DCI-P3 + * linear transfer function makes this the same as DCI_P3_LINEAR. + */ + DISPLAY_P3_LINEAR = 10 << 16 | 1 << 22 | 1 << 27, // STANDARD_DCI_P3 | TRANSFER_LINEAR | RANGE_FULL + + + /** + * Display P3 + * + * Use same primaries and white-point as DCI-P3 + * but sRGB transfer function. + */ + DISPLAY_P3 = 10 << 16 | 2 << 22 | 1 << 27, // STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_FULL + + + /** + * Adobe RGB + * + * Use full range, gamma 2.2 transfer and Adobe RGB primaries + * Note: Application is responsible for gamma encoding the data as + * a 2.2 gamma encoding is not supported in HW. + */ + ADOBE_RGB = 11 << 16 | 4 << 22 | 1 << 27, // STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2 | RANGE_FULL + + + /** + * ITU-R Recommendation 2020 (BT.2020) + * + * Ultra High-definition television + * + * Use full range, linear transfer and BT2020 standard + */ + BT2020_LINEAR = 6 << 16 | 1 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_LINEAR | RANGE_FULL + + + /** + * ITU-R Recommendation 2020 (BT.2020) + * + * Ultra High-definition television + * + * Use full range, BT.709 transfer and BT2020 standard + */ + BT2020 = 6 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL + + /** + * ITU-R Recommendation 2020 (BT.2020) + * + * Ultra High-definition television + * + * Use full range, SMPTE 2084 (PQ) transfer and BT2020 standard + */ + BT2020_PQ = 6 << 16 | 7 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL + + + /** + * Data spaces for non-color formats + */ + + /** + * The buffer contains depth ranging measurements from a depth camera. + * This value is valid with formats: + * HAL_PIXEL_FORMAT_Y16: 16-bit samples, consisting of a depth measurement + * and an associated confidence value. The 3 MSBs of the sample make + * up the confidence value, and the low 13 LSBs of the sample make up + * the depth measurement. + * For the confidence section, 0 means 100% confidence, 1 means 0% + * confidence. The mapping to a linear float confidence value between + * 0.f and 1.f can be obtained with + * float confidence = (((depthSample >> 13) - 1) & 0x7) / 7.0f; + * The depth measurement can be extracted simply with + * uint16_t range = (depthSample & 0x1FFF); + * HAL_PIXEL_FORMAT_BLOB: A depth point cloud, as + * a variable-length float (x,y,z, confidence) coordinate point list. + * The point cloud will be represented with the android_depth_points + * structure. + */ + DEPTH = 0x1000, + + /** + * The buffer contains sensor events from sensor direct report. + * This value is valid with formats: + * HAL_PIXEL_FORMAT_BLOB: an array of sensor event structure that forms + * a lock free queue. Format of sensor event structure is specified + * in Sensors HAL. + */ + SENSOR = 0x1001, + + /** + * ITU-R Recommendation 2020 (BT.2020) + * + * Ultra High-definition television + * + * Use limited range, BT.709 transfer and BT2020 standard + */ + BT2020_ITU = 6 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_LIMITED + + /** + * ITU-R Recommendation 2100 (BT.2100) + * + * High dynamic range television + * + * Use limited/full range, PQ/HLG transfer, and BT2020 standard + * limited range is the preferred / normative definition for BT.2100 + */ + BT2020_ITU_PQ = 6 << 16 | 7 << 22 | 2 << 27, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED + BT2020_ITU_HLG = 6 << 16 | 8 << 22 | 2 << 27, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_LIMITED + BT2020_HLG = 6 << 16 | 8 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_FULL + + /** + * ITU-R Recommendation 2020 (BT.2020) + * + * Ultra High-definition television + * + * Use full range, sRGB transfer and BT2020 standard + */ + DISPLAY_BT2020 = 6 << 16 | 2 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_SRGB | RANGE_FULL + + /** + * ISO 16684-1:2011(E) + * + * Embedded depth metadata following the dynamic depth specification. + */ + DYNAMIC_DEPTH = 0x1002, + + /** + * JPEG APP segments format as specified by JEIDA spec + * + * The buffer must only contain APP1 (Application Marker) segment followed + * by zero or more APPn segments, as is specified by JEITA CP-3451C section 4.5.4. + * The APP1 segment optionally contains a thumbnail. The buffer will not + * contain main compressed image. + * + * This value is valid with formats: + * HAL_PIXEL_FORMAT_BLOB: JPEG APP segments optionally containing thumbnail image + * in APP1. BLOB buffer with this dataspace is output by HAL, and used by + * camera framework to encode into a HEIC image. + */ + JPEG_APP_SEGMENTS = 0x1003, + + /** + * ISO/IEC 23008-12 + * + * High Efficiency Image File Format (HEIF) + * + * This value is valid with formats: + * HAL_PIXEL_FORMAT_BLOB: A HEIC image encoded by HEIC or HEVC encoder + * according to ISO/IEC 23008-12. + */ + HEIF = 0x1004, +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl b/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl new file mode 100644 index 0000000000..04d87106df --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl @@ -0,0 +1,52 @@ +/** + * 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. + */ + +package android.hardware.graphics.common; + +/** + * This struct is used for types that are commonly extended by vendors. For example, buffer + * compression is typically SoC specific. It is not possible for Android to define every possible + * proprietary vendor compression strategy. Instead, compression is represented using this + * ExtendableType that can support standard compression strategies while still allowing + * every vendor to easily add their own non-standard definitions. + */ +@VintfStability +parcelable ExtendableType { + /** + * Name of the stable aidl interface whose value is stored in this structure. + * + * For standard types, the "name" field will be set to the stable aidl name of the type such as + * "android.hardware.graphics.common.Compression". + * + * For custom vendor types, the "name" field will be set to the name of the custom + * @VendorStability vendor AIDL interface such as + * "vendor.mycompanyname.graphics.common.Compression". The name of the vendor extension should + * contain the name of the company that owns the extension. Including the company + * name in the "name" field prevents type collisions between different vendors. + */ + @utf8InCpp String name; + + /** + * Enum value of the from the stable aidl interface + * + * For standard types, the "value" field will be set to an enum value from that stable aidl + * type such as "NONE". + * + * For vendor types, the "value" field should be set to the enum value from the custom + * @VendorStability vendor AIDL interface extended type such as "MY_COMPRESSION_TYPE1". + */ + long value = 0; +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/Interlaced.aidl b/graphics/common/aidl/android/hardware/graphics/common/Interlaced.aidl new file mode 100644 index 0000000000..a3f1baa53a --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/Interlaced.aidl @@ -0,0 +1,35 @@ +/** + * 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. + */ + +package android.hardware.graphics.common; + +/** + * Used by IAllocator/IMapper (gralloc) to describe standard interlaced strategies + */ +@VintfStability +@Backing(type="long") +enum Interlaced { + /* The buffer is not interlaced. */ + NONE = 0, + + /* The buffer's planes are interlaced horizontally. The height of each interlaced plane is + * 1/2 the height of the buffer's height. */ + TOP_BOTTOM = 1, + + /* The buffer's planes are interlaced vertically. The width of each interlaced plane is + * 1/2 the width of the buffer's width. */ + RIGHT_LEFT = 2, +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl new file mode 100644 index 0000000000..168028ddcc --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl @@ -0,0 +1,125 @@ +/** + * 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. + */ + +package android.hardware.graphics.common; + +import android.hardware.graphics.common.PlaneLayoutComponent; +import android.hardware.graphics.common.Rect; + +/** + * Used by IAllocator/IMapper (gralloc) to describe the plane layout of a buffer. + * + * PlaneLayout uses the following definitions: + * + * - Component - a component is one channel of a pixel. For example, an RGBA format has + * four components: R, G, B and A. + * - Sample - a sample is comprised of all the components in a given plane. For example, + * a buffer with one Y plane and one CbCr plane has one plane with a sample of Y + * and one plane with a sample of CbCr. + * - Pixel - a pixel is comprised of all the (non-metadata/raw) components in buffer across + * all planes. For example, a buffer with a plane of Y and a plane of CbCr has a pixel + * of YCbCr. + */ + +@VintfStability +parcelable PlaneLayout { + /** + * An list of plane layout components. This list of components should include + * every component in this plane. For example, a CbCr plane should return a + * vector of size two with one PlaneLayoutComponent for Cb and one for Cr. + */ + PlaneLayoutComponent[] components; + + /** + * Offset to the first byte of the plane (in bytes), from the start of the allocation. + */ + long offsetInBytes; + + /** + * Bits per sample increment (aka column increment): describes the distance + * in bits from one sample to the next sample (to the right) on the same row for the + * the component plane. + * + * The default value is 0. Return the default value if the increment is undefined, unknown, + * or variable. + * + * This can be negative. A negative increment indicates that the samples are read from + * right to left. + */ + long sampleIncrementInBits; + + /** + * Horizontal stride: number of bytes between two vertically adjacent + * samples in given plane. This can be mathematically described by: + * + * strideInBytes = ALIGN(widthInSamples * bps / 8, alignment) + * + * where, + * + * bps: average bits per sample + * alignment (in bytes): dependent upon pixel format and usage + * + * strideInBytes can contain additional padding beyond the widthInSamples. + * + * The default value is 0. Return the default value if the stride is undefined, unknown, + * or variable. + * + * This can be negative. A negative stride indicates that the rows are read from + * bottom to top. + */ + long strideInBytes; + + /** + * Dimensions of plane (in samples). + * + * This is the number of samples in the plane, even if subsampled. + * + * See 'strideInBytes' for relationship between strideInBytes and widthInSamples. + */ + long widthInSamples; + long heightInSamples; + + /** + * Can be used to get the total size in bytes of any memory used by the plane + * including extra padding. This should not include any extra metadata used to describe the + * plane. + */ + long totalSizeInBytes; + + /** + * Horizontal and vertical subsampling. Must be a positive power of 2. + * + * These fields indicate the number of horizontally or vertically adjacent pixels that use + * the same pixel data. A value of 1 indicates no subsampling. + */ + long horizontalSubsampling; + long verticalSubsampling; + + /** + * Some buffer producers require extra padding to their output buffer; therefore the + * physical size of the native buffer will be larger than its logical size. + * The crop rectangle determines the offset and logical size of the buffer that should be + * read by consumers. + * + * The crop rectangle is measured in samples and is relative to the offset of the + * plane. Valid crop rectangles are within the boundaries of the plane: + * [0, 0, widthInSamples, heightInSamples]. + * + * The default crop rectangle is a rectangle the same size as the plane: + * [0, 0, widthInSamples, heightInSamples]. + */ + Rect crop; +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl new file mode 100644 index 0000000000..3fca53b937 --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl @@ -0,0 +1,67 @@ +/** + * 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. + */ + +package android.hardware.graphics.common; + +import android.hardware.graphics.common.ExtendableType; + +/** + * Used by IAllocator/IMapper (gralloc) to describe the type and location of a component in a + * buffer's plane. + * + * PlaneLayoutComponent uses the following definitions: + * + * - Component - a component is one channel of a pixel. For example, an RGBA format has + * four components: R, G, B and A. + * - Sample - a sample is comprised of all the components in a given plane. For example, + * a buffer with one Y plane and one CbCr plane has one plane with a sample of Y + * and one plane with a sample of CbCr. + * - Pixel - a pixel is comprised of all the (non-metadata/raw) components in buffer across + * all planes. For example, a buffer with a plane of Y and a plane of CbCr has a pixel + * of YCbCr. + */ + +@VintfStability +parcelable PlaneLayoutComponent { + /** + * The type of this plane layout component. + * + * android.hardware.graphics.common.PlaneLayoutComponent defines the standard + * plane layout component types. Vendors may extend this type to include any + * non-standard plane layout component types. For instructions on how to + * create a vendor extension, refer to ExtendableType.aidl. + */ + ExtendableType type; + + /** + * Offset in bits to the first instance of this component in the plane. + * This is relative to the plane's offset (PlaneLayout::offset). + * + * If the offset cannot be described using a int64_t, this should be set to -1. + * For example, if the plane is compressed and the offset is not defined or + * relevant, return -1. + */ + long offsetInBits; + + /** + * The number of bits used per component in the plane. + * + * If the plane layout component cannot be described using componentSizeInBits, this + * should be set to -1. For example, if the component varies in size throughout + * the plane, return -1. + */ + long sizeInBits; +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl new file mode 100644 index 0000000000..18c4a2e154 --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl @@ -0,0 +1,46 @@ +/** + * 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. + */ + +package android.hardware.graphics.common; + +/** + * Used by IAllocator/IMapper (gralloc) to describe standard plane layout component types + * + * The enum values have been taken directly from gralloc1's android_flex_component for compatiblity + * reasons. However, unlike gralloc1's android_flex_component, this field is NOT a bit field. + * A plane's components should NOT be expressed by bitwise OR-ing different + * PlaneLayoutComponentTypes together. + */ +@VintfStability +@Backing(type="long") +enum PlaneLayoutComponentType { + /* Luma */ + Y = 1 << 0, + /* Chroma blue */ + CB = 1 << 1, + /* Chroma red */ + CR = 1 << 2, + + /* Red */ + R = 1 << 10, + /* Green */ + G = 1 << 11, + /* Blue */ + B = 1 << 12, + + /* Alpha */ + A = 1 << 30, +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl b/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl new file mode 100644 index 0000000000..1a3bc11e4f --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl @@ -0,0 +1,29 @@ +/** + * 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. + */ + +package android.hardware.graphics.common; + +/** + * General purpose definition of a rectangle. + */ + +@VintfStability +parcelable Rect { + int left; + int top; + int right; + int bottom; +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl new file mode 100644 index 0000000000..060d12c46e --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl @@ -0,0 +1,282 @@ +/** + * Copyright (c) 2019,libgralloctypes_helper 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. + */ + +package android.hardware.graphics.common; + +/** + * Used by IAllocator/IMapper (gralloc) to describe standard metadata types. + * + * This is an enum that defines the common types of gralloc 4 buffer metadata. The comments for + * each enum include a description of the metadata that is associated with the type. + * + * IMapper@4.x must support getting the following standard buffer metadata types. IMapper@4.x may + * support setting these standard buffer metadata types as well. + */ +@VintfStability +@Backing(type="long") +enum StandardMetadataType { + INVALID = 0, + + /** + * Can be used to get the random ID of the buffer. This ID should be psuedorandom with + * sufficient entropy. + * + * This ID should only be used for debugging purposes. It cannot be used as a basis for any + * control flows. + * + * The buffer ID is determined at allocation time and should not change during the lifetime + * of the buffer. + * + * The buffer ID is a uint64_t. + * + * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian. + */ + BUFFER_ID = 1, + + /** + * Can be used to get the name passed in by the client at allocation time in the + * BufferDescriptorInfo. + * + * The buffer name is determined at allocation time and should not change during the lifetime + * of the buffer. + * + * The buffer name is a string. + * + * When it is encoded into a byte stream, the length of the string is written using 8 bytes in + * little endian. It is followed by a char array of the string's + * characters. The array is not null-terminated. + */ + NAME = 2, + + /** + * Can be used to get the number of elements per buffer row requested at allocation time in + * the BufferDescriptorInfo. + * + * The width is determined at allocation time and should not change during the lifetime + * of the buffer. + * + * The width is a uint64_t. + * + * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian. + */ + WIDTH = 3, + + /** + * Can be used to get the number of elements per buffer column requested at allocation time in + * the BufferDescriptorInfo. + * + * The height is determined at allocation time and should not change during the lifetime + * of the buffer. + * + * The height is a uint64_t. + * + * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian. + */ + HEIGHT = 4, + + /** + * Can be used to get the number of layers requested at allocation time in the + * BufferDescriptorInfo. + * + * The layer count is determined at allocation time and should not change during the lifetime + * of the buffer. + * + * The layer count is a uint64_t. + * + * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian. + */ + LAYER_COUNT = 5, + + /** + * Can be used to get the buffer format requested at allocation time in the + * BufferDescriptorInfo. + * + * The requested pixel format is determined at allocation time and should not change during + * the lifetime of the buffer. + * + * The requested pixel format is a android.hardware.graphics.common@1.2::PixelFormat. + * + * When it is encoded into a byte stream, it is first cast to a int32_t and then represented in + * the byte stream by 4 bytes written in little endian. + */ + PIXEL_FORMAT_REQUESTED = 6, + + /** + * Can be used to get the fourcc code for the format. Fourcc codes are standard across all + * devices of the same kernel version. Fourcc codes must follow the Linux definition of a + * fourcc format found in: include/uapi/drm/drm_fourcc.h. + * + * The pixel format fourcc code is represented by a uint32_t. + * + * When it is encoded into a byte stream, it is represented by 4 bytes written in little endian. + */ + PIXEL_FORMAT_FOURCC = 7, + + /** + * Can be used to get the modifier for the format. Together fourcc and modifier describe the + * real pixel format. Each fourcc and modifier pair is unique and must fully define the format + * and layout of the buffer. Modifiers can change any property of the buffer. Modifiers must + * follow the Linux definition of a modifier found in: include/uapi/drm/drm_fourcc.h. + * + * The pixel format modifier is represented by a uint64_t. + * + * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian. + */ + PIXEL_FORMAT_MODIFIER = 8, + + /** + * Can be used to get the usage requested at allocation time in the BufferDescriptorInfo. + * + * The usage is determined at allocation time and should not change during the lifetime + * of the buffer. + * + * The usage is a uint64_t bit field of android.hardware.graphics.common@1.2::BufferUsage's. + * + * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian. + */ + USAGE = 9, + + /** + * Can be used to get the total size in bytes of any memory used by the buffer including its + * metadata and extra padding. This is the total number of bytes used by the buffer allocation. + * + * The allocation size is a uint64_t. + * + * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian. + */ + ALLOCATION_SIZE = 10, + + /** + * Can be used to get if a buffer has protected content. If the buffer does not have protected + * content, this should return 0. If a buffer has protected content, this should return 1. + * + * In future versions, this field will be extended to expose more information about the type + * of protected content in the buffer. + * + * The protected content is a uint64_t. + * + * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian. + */ + PROTECTED_CONTENT = 11, + + /** + * Can be used to get the compression strategy of the buffer. If the device has more than one + * compression strategy, it should have different unique values for each compression + * strategy. + * + * Compression is a stable aidl android.hardware.graphics.common.ExtendableType. + * + * android.hardware.graphics.common.Compression defines the standard compression + * strategies. Vendors may extend this type to include any compression strategies. + * + * When it is encoded into a byte stream, the length of the name field string is written using + * 8 bytes in little endian. It is followed by a char array of the string's + * characters. The array is not null-terminated. Finally the value field is written as 8 bytes + * in little endian. + */ + COMPRESSION = 12, + + /** + * Can be used to get how the buffer's planes are interlaced. + * + * Interlaced is a stable aidl android.hardware.graphics.common.ExtendableType. + * + * android.hardware.graphics.common.Interlaced defines the standard interlaced + * strategies. Vendors may extend this type to include any non-standard interlaced + * strategies. + * + * When it is encoded into a byte stream, the length of the name field string is written using + * 8 bytes in little endian. It is followed by a char array of the string's + * characters. The array is not null-terminated. Finally the value field is written as 8 bytes + * in little endian. + */ + INTERLACED = 13, + + /** + * Can be used to get the chroma siting of a buffer. + * + * Chroma siting is a stable aidl android.hardware.graphics.common.ExtendableType. + * + * android.hardware.graphics.common.ChromaSiting defines the standard chroma + * sitings. Vendors may extend this type to include any non-standard chroma sitings. + * + * When it is encoded into a byte stream, the length of the name field string is written using + * 8 bytes in little endian. It is followed by a char array of the string's + * characters. The array is not null-terminated. Finally the value field is written as 8 bytes + * in little endian. + */ + CHROMA_SITING = 14, + + /** + * Can be used to get the PlaneLayout(s) of the buffer. There should be one PlaneLayout per + * plane in the buffer. For example if the buffer only has one plane, only one PlaneLayout + * should be returned. + * + * If the buffer has planes interlaced through time, the returned PlaneLayout structs should be + * ordered by time. The nth PlaneLayout should be from the same time or earlier than the + * n+1 PlaneLayout. + * + * The plane layout is a list of stable aidl android.hardware.graphics.common.PlaneLayout's. + * + * When it is encoded into a byte stream, the total number of PlaneLayouts is written using + * 8 bytes in little endian. It is followed by each PlaneLayout. + * + * To encode a PlaneLayout, write the length of its PlaneLayoutComponent[] components + * field as 8 bytes in little endian and then encode each of its components. Finally, write the + * following fields in this order each as 8 bytes in little endian: offsetInBytes, + * sampleIncrementInBits, strideInBytes, widthInSamples, totalSizeInBytes, + * horizontalSubsampling, verticalSubsampling. + * + * To encode a PlaneLayoutComponent, encode its PlaneLayoutComponentType type field. Next + * encode offsetInBits followed by sizeInBits each as 8 bytes in little endian. + * + * To encode a PlaneLayoutComponentType, write the length of the name field string as + * 8 bytes in little endian. It is followed by a char array of the string's + * characters. The array is not null-terminated. Finally the value field is written as 8 bytes + * in little endian. + */ + PLANE_LAYOUTS = 15, + + /** + * Can be used to get or set the dataspace of the buffer. The framework may attempt to set + * this value. + * + * The default dataspace is Dataspace::UNKNOWN. If this dataspace is set to any valid value + * other than Dataspace::UNKNOWN, this dataspace overrides all other dataspaces. For example, + * if the buffer has Dataspace::DISPLAY_P3 and it is being displayed on a composer Layer that + * is Dataspace::sRGB, the buffer should be treated as a DISPLAY_P3 buffer. + * + * The dataspace is a stable aidl android.hardware.graphics.common.Dataspace. + * + * When it is encoded into a byte stream, it is first cast to a int32_t and then represented in + * the byte stream by 4 bytes written in little endian. + */ + DATASPACE = 16, + + /** + * Can be used to get or set the BlendMode. The framework may attempt to set this value. + * + * The default blend mode is INVALID. If the BlendMode is set to any + * valid value other than INVALID, this BlendMode overrides all other + * dataspaces. For a longer description of this behavior see MetadataType::DATASPACE. + * + * The blend mode is a stable aidl android.hardware.graphics.common.BlendMode. + * + * When it is encoded into a byte stream, it is first cast to a int32_t and then represented by + * 4 bytes written in little endian. + */ + BLEND_MODE = 17, +} From 16c43fb4f811d731caf08cb66af10184f6652ffb Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Wed, 13 Nov 2019 11:06:14 -0800 Subject: [PATCH 0243/1022] wifi(vts): Set the iface up as a part of setup Attempts to fix a VTS test failure reported by OEM's on devices supporting concurrent AP iface. Bug: 143096362 Test: make vts && vts-tradefed run commandAndExit vts --module VtsHalWifiV1_0Host Test: Will need to ask OEM to verify the fix. Change-Id: I0958d720411258761f4ac5bcccc823b06a55d518 --- wifi/1.0/vts/functional/Android.bp | 4 ++++ .../vts/functional/wifi_hidl_test_utils.cpp | 18 ++++++++++++++++++ wifi/1.1/vts/functional/Android.bp | 1 + wifi/1.2/vts/functional/Android.bp | 2 ++ wifi/1.3/vts/functional/Android.bp | 1 + wifi/1.4/vts/functional/Android.bp | 1 + 6 files changed, 27 insertions(+) diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp index 6fa6e7ed6d..f3068f2aad 100644 --- a/wifi/1.0/vts/functional/Android.bp +++ b/wifi/1.0/vts/functional/Android.bp @@ -30,6 +30,7 @@ cc_library_static { ], static_libs: [ "android.hardware.wifi@1.0", + "libwifi-system-iface" ], } @@ -49,6 +50,7 @@ cc_test { "android.hardware.wifi@1.1", "android.hardware.wifi@1.2", "android.hardware.wifi@1.3", + "libwifi-system-iface" ], test_suites: ["general-tests"], } @@ -66,6 +68,7 @@ cc_test { static_libs: [ "VtsHalWifiV1_0TargetTestUtil", "android.hardware.wifi@1.0", + "libwifi-system-iface" ], test_suites: ["general-tests"], } @@ -83,6 +86,7 @@ cc_test { static_libs: [ "VtsHalWifiV1_0TargetTestUtil", "android.hardware.wifi@1.0", + "libwifi-system-iface" ], test_suites: ["general-tests"], } diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp index f89f7b4b44..45454bf7e3 100644 --- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp +++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp @@ -18,12 +18,15 @@ #include +#include + #include "wifi_hidl_call_util.h" #include "wifi_hidl_test_utils.h" using ::android::hardware::wifi::V1_0::IWifi; using ::android::hardware::wifi::V1_0::IWifiApIface; using ::android::hardware::wifi::V1_0::IWifiChip; +using ::android::hardware::wifi::V1_0::IWifiIface; using ::android::hardware::wifi::V1_0::IWifiNanIface; using ::android::hardware::wifi::V1_0::IWifiP2pIface; using ::android::hardware::wifi::V1_0::IWifiRttController; @@ -36,6 +39,7 @@ using ::android::hardware::wifi::V1_0::WifiStatusCode; using ::android::sp; using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; +using ::android::wifi_system::InterfaceTool; extern WifiHidlEnvironment* gEnv; @@ -131,6 +135,16 @@ sp getWifiChip(const std::string& instance_name) { return status_and_chip.second; } +void setIfaceUp(const sp& iface) { + // Set the iface up before retrurning the object. + const auto& status_and_name = HIDL_INVOKE(iface, getName); + if (status_and_name.first.code == WifiStatusCode::SUCCESS) { + const auto& iface_name = status_and_name.second; + InterfaceTool iface_tool; + iface_tool.SetUpState(iface_name.c_str(), true); + } +} + sp getWifiApIface(const std::string& instance_name) { sp wifi_chip = getWifiChip(instance_name); if (!wifi_chip.get()) { @@ -143,6 +157,7 @@ sp getWifiApIface(const std::string& instance_name) { if (status_and_iface.first.code != WifiStatusCode::SUCCESS) { return nullptr; } + setIfaceUp(status_and_iface.second); return status_and_iface.second; } @@ -158,6 +173,7 @@ sp getWifiNanIface(const std::string& instance_name) { if (status_and_iface.first.code != WifiStatusCode::SUCCESS) { return nullptr; } + setIfaceUp(status_and_iface.second); return status_and_iface.second; } @@ -173,6 +189,7 @@ sp getWifiP2pIface(const std::string& instance_name) { if (status_and_iface.first.code != WifiStatusCode::SUCCESS) { return nullptr; } + setIfaceUp(status_and_iface.second); return status_and_iface.second; } @@ -188,6 +205,7 @@ sp getWifiStaIface(const std::string& instance_name) { if (status_and_iface.first.code != WifiStatusCode::SUCCESS) { return nullptr; } + setIfaceUp(status_and_iface.second); return status_and_iface.second; } diff --git a/wifi/1.1/vts/functional/Android.bp b/wifi/1.1/vts/functional/Android.bp index 6662314aa5..6d7635d455 100644 --- a/wifi/1.1/vts/functional/Android.bp +++ b/wifi/1.1/vts/functional/Android.bp @@ -26,6 +26,7 @@ cc_test { "android.hardware.wifi@1.1", "android.hardware.wifi@1.2", "android.hardware.wifi@1.3", + "libwifi-system-iface" ], test_suites: ["general-tests"], } diff --git a/wifi/1.2/vts/functional/Android.bp b/wifi/1.2/vts/functional/Android.bp index b2956ce3c4..97853d0300 100644 --- a/wifi/1.2/vts/functional/Android.bp +++ b/wifi/1.2/vts/functional/Android.bp @@ -28,6 +28,7 @@ cc_test { "android.hardware.wifi@1.1", "android.hardware.wifi@1.2", "android.hardware.wifi@1.3", + "libwifi-system-iface" ], test_suites: ["general-tests"], } @@ -44,6 +45,7 @@ cc_test { "android.hardware.wifi@1.0", "android.hardware.wifi@1.1", "android.hardware.wifi@1.2", + "libwifi-system-iface" ], test_suites: ["general-tests"], } diff --git a/wifi/1.3/vts/functional/Android.bp b/wifi/1.3/vts/functional/Android.bp index 53c8f08516..9ffda8be47 100644 --- a/wifi/1.3/vts/functional/Android.bp +++ b/wifi/1.3/vts/functional/Android.bp @@ -28,5 +28,6 @@ cc_test { "android.hardware.wifi@1.1", "android.hardware.wifi@1.2", "android.hardware.wifi@1.3", + "libwifi-system-iface" ], } diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp index 42c60f2f0e..215a810097 100644 --- a/wifi/1.4/vts/functional/Android.bp +++ b/wifi/1.4/vts/functional/Android.bp @@ -29,5 +29,6 @@ cc_test { "android.hardware.wifi@1.2", "android.hardware.wifi@1.3", "android.hardware.wifi@1.4", + "libwifi-system-iface" ], } From 7ba4cf867c81d836367da368ec91128edabb9671 Mon Sep 17 00:00:00 2001 From: Kai Date: Thu, 24 Oct 2019 18:13:39 -0700 Subject: [PATCH 0244/1022] Support chose permissions for vendor property Add property SUPPORT_CUSTOMIZE_VENDOR_PERMISSION. Add enum VehicleVendorPermission. The configArray of new property indicate vendor property Id and the permission selected by vendor. Update google VHAL as an example how to use it. Bug: 109950289 Test: build and flash with google HAL check permission via property test in KitchenSink Change-Id: Ic8dcb661ce69bfb82ebc00781426dfbb98fb393d --- .../default/impl/vhal_v2_0/DefaultConfig.h | 18 ++++ automotive/vehicle/2.0/types.hal | 90 +++++++++++++++++++ 2 files changed, 108 insertions(+) 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 f41b33c910..2dbcbba28f 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 @@ -948,6 +948,24 @@ const ConfigDeclaration kVehicleProperties[]{ .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE}, .initialValue = {.stringValue = "Vendor String Property"}}, + + {.config = + { + .prop = toInt(VehicleProperty::SUPPORT_CUSTOMIZE_VENDOR_PERMISSION), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = + {kMixedTypePropertyForTest, + (int)VehicleVendorPermission::PERMISSION_GET_VENDOR_CATEGORY_INFO, + (int)VehicleVendorPermission::PERMISSION_SET_VENDOR_CATEGORY_INFO, + VENDOR_EXTENSION_INT_PROPERTY, + (int)VehicleVendorPermission::PERMISSION_GET_VENDOR_CATEGORY_SEAT, + (int)VehicleVendorPermission::PERMISSION_NOT_ACCESSIBLE, + VENDOR_EXTENSION_FLOAT_PROPERTY, + (int)VehicleVendorPermission::PERMISSION_DEFAULT, + (int)VehicleVendorPermission::PERMISSION_DEFAULT}, + }, + .initialValue = {.int32Values = {1}}}, }; } // impl diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index bc0b4d3d9e..279d5cd30a 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -2349,6 +2349,96 @@ enum VehicleProperty : int32_t { | VehiclePropertyType:INT32 | VehicleArea:SEAT), + /** + * Support customize permissions for vendor properties + * + * Implement this property if vehicle hal support customize vendor permissions feature. + * VehiclePropConfig.configArray is used to indicate vendor properties and permissions + * which selected for this vendor property. The permission must be one of enum in + * VehicleVendorPermission. + * The configArray is set as follows: + * configArray[n] = propId : property ID for the vendor property + * configArray[n+1] = one of enums in VehicleVendorPermission. It indicates the permission + * for reading value of the property. + * configArray[n+2] = one of enums in VehicleVendorPermission. It indicates the permission + * for writing value of the property. + * + * For example: + * configArray = { + * vendor_prop_1, PERMISSION_VENDOR_SEAT_READ, PERMISSION_VENDOR_SEAT_WRITE, + * vendor_prop_2, PERMISSION_VENDOR_INFO, PERMISSION_NOT_ACCESSIBLE, + * } + * If vendor properties are not in this array, they will have the default vendor permission. + * If vendor chose PERMISSION_NOT_ACCESSIBLE, android will not have access to the property. In + * the example, Android can not write value for vendor_prop_2. + * + * @change_mode VehiclePropertyChangeMode:STATIC + * @access VehiclePropertyAccess:READ + */ + SUPPORT_CUSTOMIZE_VENDOR_PERMISSION = ( + 0x0F05 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:GLOBAL), + +}; + +/** + * Used by SUPPORT_CUSTOMIZE_VENDOR_PERMISSION to indicate the permission of vendor properties. + */ +enum VehicleVendorPermission : int32_t { + PERMISSION_DEFAULT = 0x00000000, + + // permissions for the property related with window + PERMISSION_SET_VENDOR_CATEGORY_WINDOW= 0X00000001, + PERMISSION_GET_VENDOR_CATEGORY_WINDOW = 0x00000002, + // permissions for the property related with door + PERMISSION_SET_VENDOR_CATEGORY_DOOR = 0x00000003, + PERMISSION_GET_VENDOR_CATEGORY_DOOR = 0x00000004, + // permissions for the property related with seat + PERMISSION_SET_VENDOR_CATEGORY_SEAT = 0x00000005, + PERMISSION_GET_VENDOR_CATEGORY_SEAT = 0x00000006, + // permissions for the property related with mirror + PERMISSION_SET_VENDOR_CATEGORY_MIRROR= 0x00000007, + PERMISSION_GET_VENDOR_CATEGORY_MIRROR = 0x00000008, + + // permissions for the property related with car's information + PERMISSION_SET_VENDOR_CATEGORY_INFO = 0x00000009, + PERMISSION_GET_VENDOR_CATEGORY_INFO = 0x0000000A, + // permissions for the property related with car's engine + PERMISSION_SET_VENDOR_CATEGORY_ENGINE= 0x0000000B, + PERMISSION_GET_VENDOR_CATEGORY_ENGINE = 0x0000000C, + // permissions for the property related with car's HVAC + PERMISSION_SET_VENDOR_CATEGORY_HVAC = 0x0000000D, + PERMISSION_GET_VENDOR_CATEGORY_HVAC = 0x0000000E, + // permissions for the property related with car's light + PERMISSION_SET_VENDOR_CATEGORY_LIGHT = 0x0000000F, + PERMISSION_GET_VENDOR_CATEGORY_LIGHT = 0x00000010, + + // permissions reserved for other vendor permission + PERMISSION_SET_VENDOR_CATEGORY_1 = 0x00010000, + PERMISSION_GET_VENDOR_CATEGORY_1 = 0x00011000, + PERMISSION_SET_VENDOR_CATEGORY_2 = 0x00020000, + PERMISSION_GET_VENDOR_CATEGORY_2 = 0x00021000, + PERMISSION_SET_VENDOR_CATEGORY_3 = 0x00030000, + PERMISSION_GET_VENDOR_CATEGORY_3 = 0x00031000, + PERMISSION_SET_VENDOR_CATEGORY_4 = 0x00040000, + PERMISSION_GET_VENDOR_CATEGORY_4 = 0x00041000, + PERMISSION_SET_VENDOR_CATEGORY_5 = 0x00050000, + PERMISSION_GET_VENDOR_CATEGORY_5 = 0x00051000, + PERMISSION_SET_VENDOR_CATEGORY_6 = 0x00060000, + PERMISSION_GET_VENDOR_CATEGORY_6 = 0x00061000, + PERMISSION_SET_VENDOR_CATEGORY_7 = 0x00070000, + PERMISSION_GET_VENDOR_CATEGORY_7 = 0x00071000, + PERMISSION_SET_VENDOR_CATEGORY_8 = 0x00080000, + PERMISSION_GET_VENDOR_CATEGORY_8 = 0x00081000, + PERMISSION_SET_VENDOR_CATEGORY_9 = 0x00090000, + PERMISSION_GET_VENDOR_CATEGORY_9 = 0x00091000, + PERMISSION_SET_VENDOR_CATEGORY_10 = 0x000A0000, + PERMISSION_GET_VENDOR_CATEGORY_10 = 0x000A1000, + + // Indicate not available for android to access. + PERMISSION_NOT_ACCESSIBLE = 0xF0000000 }; /** From 336fe46ae53fe2a92524a770ffdd519dc8973301 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Fri, 8 Nov 2019 11:17:11 -0800 Subject: [PATCH 0245/1022] Convert VtsHalWifiV1_*Target to be parameterized test Bug: 142397658 Bug: 142304083 Test: atest \ VtsHalWifiV1_0TargetTest \ VtsHalWifiNanV1_0TargetTest \ VtsHalWifiApV1_0TargetTest \ VtsHalWifiV1_1TargetTest \ VtsHalWifiV1_2TargetTest \ VtsHalWifiNanV1_2TargetTest \ VtsHalWifiV1_3TargetTest \ VtsHalWifiApV1_4TargetTest Change-Id: I05bf1c4cff378a99c015ac514eefb49debb8b1af --- wifi/1.0/vts/functional/Android.bp | 6 +- .../functional/VtsHalWifiV1_0TargetTest.cpp | 34 +----- .../functional/wifi_ap_iface_hidl_test.cpp | 35 +++--- .../vts/functional/wifi_chip_hidl_ap_test.cpp | 30 +++-- .../functional/wifi_chip_hidl_nan_test.cpp | 30 +++-- .../vts/functional/wifi_chip_hidl_test.cpp | 85 +++++++------- wifi/1.0/vts/functional/wifi_hidl_test.cpp | 20 +++- .../vts/functional/wifi_hidl_test_utils.cpp | 2 +- .../functional/wifi_nan_iface_hidl_test.cpp | 104 ++++++++++-------- .../functional/wifi_p2p_iface_hidl_test.cpp | 26 +++-- .../wifi_rtt_controller_hidl_test.cpp | 26 +++-- .../functional/wifi_sta_iface_hidl_test.cpp | 55 +++++---- wifi/1.1/vts/functional/Android.bp | 2 +- .../functional/VtsHalWifiV1_1TargetTest.cpp | 34 +----- .../vts/functional/wifi_chip_hidl_test.cpp | 24 ++-- wifi/1.2/vts/functional/Android.bp | 6 +- .../functional/VtsHalWifiV1_2TargetTest.cpp | 35 +----- .../vts/functional/wifi_chip_hidl_test.cpp | 27 +++-- .../functional/wifi_nan_iface_hidl_test.cpp | 39 ++++--- .../functional/wifi_sta_iface_hidl_test.cpp | 26 +++-- wifi/1.3/vts/functional/Android.bp | 2 + .../functional/VtsHalWifiV1_3TargetTest.cpp | 37 +------ .../vts/functional/wifi_chip_hidl_test.cpp | 27 +++-- .../functional/wifi_sta_iface_hidl_test.cpp | 26 +++-- wifi/1.4/vts/functional/Android.bp | 1 + .../functional/VtsHalWifiV1_4TargetTest.cpp | 37 +------ .../functional/wifi_ap_iface_hidl_test.cpp | 29 +++-- 27 files changed, 421 insertions(+), 384 deletions(-) diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp index 6fa6e7ed6d..25dd240203 100644 --- a/wifi/1.0/vts/functional/Android.bp +++ b/wifi/1.0/vts/functional/Android.bp @@ -50,7 +50,7 @@ cc_test { "android.hardware.wifi@1.2", "android.hardware.wifi@1.3", ], - test_suites: ["general-tests"], + test_suites: ["general-tests", "vts-core"], } // These tests are split out so that they can be conditioned on presence of the @@ -67,7 +67,7 @@ cc_test { "VtsHalWifiV1_0TargetTestUtil", "android.hardware.wifi@1.0", ], - test_suites: ["general-tests"], + test_suites: ["general-tests", "vts-core"], } // These tests are split out so that they can be conditioned on presence of @@ -84,5 +84,5 @@ cc_test { "VtsHalWifiV1_0TargetTestUtil", "android.hardware.wifi@1.0", ], - test_suites: ["general-tests"], + test_suites: ["general-tests", "vts-core"], } diff --git a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp index 9d25014229..128dae5a87 100644 --- a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp +++ b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp @@ -14,34 +14,8 @@ * limitations under the License. */ -#include +#include -#include "wifi_hidl_test_utils.h" - -class WifiVtsHidlEnvironment_1_0 : public WifiHidlEnvironment { - public: - // get the test environment singleton - static WifiVtsHidlEnvironment_1_0* Instance() { - static WifiVtsHidlEnvironment_1_0* instance = - new WifiVtsHidlEnvironment_1_0; - return instance; - } - - virtual void registerTestServices() override { - registerTestService(); - } - - private: - WifiVtsHidlEnvironment_1_0() {} -}; - -WifiHidlEnvironment* gEnv = WifiVtsHidlEnvironment_1_0::Instance(); - -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(gEnv); - ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; -} +// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is +// updated. +::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr; \ No newline at end of file diff --git a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp index c55221d105..8be8a0cb76 100644 --- a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp @@ -16,35 +16,37 @@ #include +#include #include - -#include +#include +#include +#include #include "wifi_hidl_call_util.h" #include "wifi_hidl_test_utils.h" +using ::android::sp; using ::android::hardware::wifi::V1_0::IfaceType; +using ::android::hardware::wifi::V1_0::IWifi; using ::android::hardware::wifi::V1_0::IWifiApIface; using ::android::hardware::wifi::V1_0::WifiBand; using ::android::hardware::wifi::V1_0::WifiStatusCode; -using ::android::sp; /** * Fixture to use for all AP Iface HIDL interface tests. */ -class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class WifiApIfaceHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { - wifi_ap_iface_ = getWifiApIface(); + wifi_ap_iface_ = getWifiApIface(GetInstanceName()); ASSERT_NE(nullptr, wifi_ap_iface_.get()); } - virtual void TearDown() override { - stopWifi(); - } + virtual void TearDown() override { stopWifi(GetInstanceName()); } protected: sp wifi_ap_iface_; + std::string GetInstanceName() { return GetParam(); } }; /* @@ -52,16 +54,15 @@ class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { * Ensures that an instance of the IWifiApIface proxy object is * successfully created. */ -TEST(WifiApIfaceHidlTestNoFixture, Create) { - EXPECT_NE(nullptr, getWifiApIface().get()); - stopWifi(); +TEST_P(WifiApIfaceHidlTest, Create) { + // The creation of a proxy object is tested as part of SetUp method. } /* * GetType: * Ensures that the correct interface type is returned for AP interface. */ -TEST_F(WifiApIfaceHidlTest, GetType) { +TEST_P(WifiApIfaceHidlTest, GetType) { const auto& status_and_type = HIDL_INVOKE(wifi_ap_iface_, getType); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_type.first.code); EXPECT_EQ(IfaceType::AP, status_and_type.second); @@ -72,7 +73,7 @@ TEST_F(WifiApIfaceHidlTest, GetType) { * Ensures that a call to set the country code will return with a success * status code. */ -TEST_F(WifiApIfaceHidlTest, SetCountryCode) { +TEST_P(WifiApIfaceHidlTest, SetCountryCode) { const android::hardware::hidl_array kCountryCode{ std::array{{0x55, 0x53}}}; EXPECT_EQ(WifiStatusCode::SUCCESS, @@ -83,9 +84,15 @@ TEST_F(WifiApIfaceHidlTest, SetCountryCode) { * GetValidFrequenciesForBand: * Ensures that we can retrieve valid frequencies for 2.4 GHz band. */ -TEST_F(WifiApIfaceHidlTest, GetValidFrequenciesForBand) { +TEST_P(WifiApIfaceHidlTest, GetValidFrequenciesForBand) { const auto& status_and_freqs = HIDL_INVOKE( wifi_ap_iface_, getValidFrequenciesForBand, WifiBand::BAND_24GHZ); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_freqs.first.code); EXPECT_GT(status_and_freqs.second.size(), 0u); } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiApIfaceHidlTest, + testing::ValuesIn( + android::hardware::getAllHalInstanceNames(IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp index 232ffdd58b..33817d5f95 100644 --- a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp +++ b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp @@ -16,9 +16,11 @@ #include +#include #include - -#include +#include +#include +#include #include "wifi_hidl_call_util.h" #include "wifi_hidl_test_utils.h" @@ -26,6 +28,7 @@ using ::android::sp; using ::android::hardware::wifi::V1_0::ChipModeId; using ::android::hardware::wifi::V1_0::IfaceType; +using ::android::hardware::wifi::V1_0::IWifi; using ::android::hardware::wifi::V1_0::IWifiApIface; using ::android::hardware::wifi::V1_0::IWifiChip; using ::android::hardware::wifi::V1_0::IWifiIface; @@ -35,14 +38,14 @@ using ::android::hardware::wifi::V1_0::WifiStatusCode; /** * Fixture for IWifiChip tests that are conditioned on SoftAP support. */ -class WifiChipHidlApTest : public ::testing::VtsHalHidlTargetTestBase { +class WifiChipHidlApTest : public ::testing::TestWithParam { public: virtual void SetUp() override { - wifi_chip_ = getWifiChip(); + wifi_chip_ = getWifiChip(GetInstanceName()); ASSERT_NE(nullptr, wifi_chip_.get()); } - virtual void TearDown() override { stopWifi(); } + virtual void TearDown() override { stopWifi(GetInstanceName()); } protected: // Helper function to configure the Chip in one of the supported modes. @@ -72,6 +75,9 @@ class WifiChipHidlApTest : public ::testing::VtsHalHidlTargetTestBase { } sp wifi_chip_; + + private: + std::string GetInstanceName() { return GetParam(); } }; /* @@ -79,7 +85,7 @@ class WifiChipHidlApTest : public ::testing::VtsHalHidlTargetTestBase { * Configures the chip in AP mode and ensures that at least 1 iface creation * succeeds. */ -TEST_F(WifiChipHidlApTest, CreateApIface) { +TEST_P(WifiChipHidlApTest, CreateApIface) { configureChipForIfaceType(IfaceType::AP, true); sp iface; @@ -93,7 +99,7 @@ TEST_F(WifiChipHidlApTest, CreateApIface) { * before creating the iface. Then, create the iface and ensure that * iface name is returned via the list. */ -TEST_F(WifiChipHidlApTest, GetApIfaceNames) { +TEST_P(WifiChipHidlApTest, GetApIfaceNames) { configureChipForIfaceType(IfaceType::AP, true); const auto& status_and_iface_names1 = @@ -125,7 +131,7 @@ TEST_F(WifiChipHidlApTest, GetApIfaceNames) { * the iface object using the correct name and ensure any other name * doesn't retrieve an iface object. */ -TEST_F(WifiChipHidlApTest, GetApIface) { +TEST_P(WifiChipHidlApTest, GetApIface) { configureChipForIfaceType(IfaceType::AP, true); sp ap_iface; @@ -151,7 +157,7 @@ TEST_F(WifiChipHidlApTest, GetApIface) { * the iface object using the correct name and ensure any other name * doesn't remove the iface. */ -TEST_F(WifiChipHidlApTest, RemoveApIface) { +TEST_P(WifiChipHidlApTest, RemoveApIface) { configureChipForIfaceType(IfaceType::AP, true); sp ap_iface; @@ -166,3 +172,9 @@ TEST_F(WifiChipHidlApTest, RemoveApIface) { // No such iface exists now. So, this should return failure. EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(iface_name)); } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiChipHidlApTest, + testing::ValuesIn( + android::hardware::getAllHalInstanceNames(IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp index 595f23a109..95f223d5de 100644 --- a/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp +++ b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp @@ -16,9 +16,11 @@ #include +#include #include - -#include +#include +#include +#include #include "wifi_hidl_call_util.h" #include "wifi_hidl_test_utils.h" @@ -26,6 +28,7 @@ using ::android::sp; using ::android::hardware::wifi::V1_0::ChipModeId; using ::android::hardware::wifi::V1_0::IfaceType; +using ::android::hardware::wifi::V1_0::IWifi; using ::android::hardware::wifi::V1_0::IWifiChip; using ::android::hardware::wifi::V1_0::IWifiIface; using ::android::hardware::wifi::V1_0::IWifiNanIface; @@ -35,14 +38,14 @@ using ::android::hardware::wifi::V1_0::WifiStatusCode; /** * Fixture for IWifiChip tests that are conditioned on NAN support. */ -class WifiChipHidlNanTest : public ::testing::VtsHalHidlTargetTestBase { +class WifiChipHidlNanTest : public ::testing::TestWithParam { public: virtual void SetUp() override { - wifi_chip_ = getWifiChip(); + wifi_chip_ = getWifiChip(GetInstanceName()); ASSERT_NE(nullptr, wifi_chip_.get()); } - virtual void TearDown() override { stopWifi(); } + virtual void TearDown() override { stopWifi(GetInstanceName()); } protected: // Helper function to configure the Chip in one of the supported modes. @@ -72,6 +75,9 @@ class WifiChipHidlNanTest : public ::testing::VtsHalHidlTargetTestBase { } sp wifi_chip_; + + private: + std::string GetInstanceName() { return GetParam(); } }; /* @@ -79,7 +85,7 @@ class WifiChipHidlNanTest : public ::testing::VtsHalHidlTargetTestBase { * Configures the chip in NAN mode and ensures that at least 1 iface creation * succeeds. */ -TEST_F(WifiChipHidlNanTest, CreateNanIface) { +TEST_P(WifiChipHidlNanTest, CreateNanIface) { configureChipForIfaceType(IfaceType::NAN, true); sp iface; @@ -93,7 +99,7 @@ TEST_F(WifiChipHidlNanTest, CreateNanIface) { * before creating the iface. Then, create the iface and ensure that * iface name is returned via the list. */ -TEST_F(WifiChipHidlNanTest, GetNanIfaceNames) { +TEST_P(WifiChipHidlNanTest, GetNanIfaceNames) { configureChipForIfaceType(IfaceType::NAN, true); const auto& status_and_iface_names1 = @@ -125,7 +131,7 @@ TEST_F(WifiChipHidlNanTest, GetNanIfaceNames) { * the iface object using the correct name and ensure any other name * doesn't retrieve an iface object. */ -TEST_F(WifiChipHidlNanTest, GetNanIface) { +TEST_P(WifiChipHidlNanTest, GetNanIface) { configureChipForIfaceType(IfaceType::NAN, true); sp nan_iface; @@ -151,7 +157,7 @@ TEST_F(WifiChipHidlNanTest, GetNanIface) { * the iface object using the correct name and ensure any other name * doesn't remove the iface. */ -TEST_F(WifiChipHidlNanTest, RemoveNanIface) { +TEST_P(WifiChipHidlNanTest, RemoveNanIface) { configureChipForIfaceType(IfaceType::NAN, true); sp nan_iface; @@ -167,3 +173,9 @@ TEST_F(WifiChipHidlNanTest, RemoveNanIface) { // No such iface exists now. So, this should return failure. EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(iface_name)); } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiChipHidlNanTest, + testing::ValuesIn( + android::hardware::getAllHalInstanceNames(IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp index 2601b78743..ec96fcf50c 100644 --- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp @@ -16,10 +16,12 @@ #include +#include #include #include - -#include +#include +#include +#include #include "wifi_hidl_call_util.h" #include "wifi_hidl_test_utils.h" @@ -27,19 +29,20 @@ using ::android::sp; using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; -using ::android::hardware::wifi::V1_0::IfaceType; using ::android::hardware::wifi::V1_0::ChipId; using ::android::hardware::wifi::V1_0::ChipModeId; -using ::android::hardware::wifi::V1_0::WifiDebugRingBufferStatus; -using ::android::hardware::wifi::V1_0::WifiDebugRingBufferVerboseLevel; -using ::android::hardware::wifi::V1_0::WifiDebugHostWakeReasonStats; -using ::android::hardware::wifi::V1_0::WifiStatus; -using ::android::hardware::wifi::V1_0::WifiStatusCode; +using ::android::hardware::wifi::V1_0::IfaceType; +using ::android::hardware::wifi::V1_0::IWifi; using ::android::hardware::wifi::V1_0::IWifiChip; using ::android::hardware::wifi::V1_0::IWifiIface; using ::android::hardware::wifi::V1_0::IWifiP2pIface; using ::android::hardware::wifi::V1_0::IWifiRttController; using ::android::hardware::wifi::V1_0::IWifiStaIface; +using ::android::hardware::wifi::V1_0::WifiDebugHostWakeReasonStats; +using ::android::hardware::wifi::V1_0::WifiDebugRingBufferStatus; +using ::android::hardware::wifi::V1_0::WifiDebugRingBufferVerboseLevel; +using ::android::hardware::wifi::V1_0::WifiStatus; +using ::android::hardware::wifi::V1_0::WifiStatusCode; extern WifiHidlEnvironment* gEnv; @@ -67,14 +70,14 @@ bool hasAnyRingBufferCapabilities(uint32_t caps) { * Tests that require SoftAP or NAN support should go into WifiChipHidlApTest or * WifiChipHidlNanTest respectively. */ -class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class WifiChipHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { - wifi_chip_ = getWifiChip(); + wifi_chip_ = getWifiChip(GetInstanceName()); ASSERT_NE(nullptr, wifi_chip_.get()); } - virtual void TearDown() override { stopWifi(); } + virtual void TearDown() override { stopWifi(GetInstanceName()); } protected: // Helper function to configure the Chip in one of the supported modes. @@ -136,6 +139,9 @@ class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { } sp wifi_chip_; + + protected: + std::string GetInstanceName() { return GetParam(); } }; /* @@ -143,15 +149,14 @@ class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { * Ensures that an instance of the IWifiChip proxy object is * successfully created. */ -TEST(WifiChipHidlTestNoFixture, Create) { - EXPECT_NE(nullptr, getWifiChip().get()); - stopWifi(); +TEST_P(WifiChipHidlTest, Create) { + // The creation of a proxy object is tested as part of SetUp method. } /* * GetId: */ -TEST_F(WifiChipHidlTest, GetId) { +TEST_P(WifiChipHidlTest, GetId) { EXPECT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(wifi_chip_, getId).first.code); } @@ -159,7 +164,7 @@ TEST_F(WifiChipHidlTest, GetId) { /* * GetAvailableMode: */ -TEST_F(WifiChipHidlTest, GetAvailableModes) { +TEST_P(WifiChipHidlTest, GetAvailableModes) { const auto& status_and_modes = HIDL_INVOKE(wifi_chip_, getAvailableModes); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_modes.first.code); EXPECT_LT(0u, status_and_modes.second.size()); @@ -168,17 +173,17 @@ TEST_F(WifiChipHidlTest, GetAvailableModes) { /* * ConfigureChip: */ -TEST_F(WifiChipHidlTest, ConfigureChip) { +TEST_P(WifiChipHidlTest, ConfigureChip) { const auto& status_and_modes = HIDL_INVOKE(wifi_chip_, getAvailableModes); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_modes.first.code); EXPECT_LT(0u, status_and_modes.second.size()); for (const auto& mode : status_and_modes.second) { // configureChip() requires to be called with a fresh IWifiChip object. - wifi_chip_ = getWifiChip(); + wifi_chip_ = getWifiChip(GetInstanceName()); ASSERT_NE(nullptr, wifi_chip_.get()); EXPECT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(wifi_chip_, configureChip, mode.id).code); - stopWifi(); + stopWifi(GetInstanceName()); // Sleep for 5 milliseconds between each wifi state toggle. usleep(5000); } @@ -187,7 +192,7 @@ TEST_F(WifiChipHidlTest, ConfigureChip) { /* * GetCapabilities: */ -TEST_F(WifiChipHidlTest, GetCapabilities) { +TEST_P(WifiChipHidlTest, GetCapabilities) { configureChipForIfaceType(IfaceType::STA, true); const auto& status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities); if (status_and_caps.first.code != WifiStatusCode::SUCCESS) { @@ -200,7 +205,7 @@ TEST_F(WifiChipHidlTest, GetCapabilities) { /* * GetMode: */ -TEST_F(WifiChipHidlTest, GetMode) { +TEST_P(WifiChipHidlTest, GetMode) { ChipModeId chip_mode_id = configureChipForIfaceType(IfaceType::STA, true); const auto& status_and_mode = HIDL_INVOKE(wifi_chip_, getMode); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mode.first.code); @@ -210,7 +215,7 @@ TEST_F(WifiChipHidlTest, GetMode) { /* * RequestChipDebugInfo: */ -TEST_F(WifiChipHidlTest, RequestChipDebugInfo) { +TEST_P(WifiChipHidlTest, RequestChipDebugInfo) { configureChipForIfaceType(IfaceType::STA, true); const auto& status_and_chip_info = HIDL_INVOKE(wifi_chip_, requestChipDebugInfo); @@ -222,7 +227,7 @@ TEST_F(WifiChipHidlTest, RequestChipDebugInfo) { /* * RequestFirmwareDebugDump */ -TEST_F(WifiChipHidlTest, RequestFirmwareDebugDump) { +TEST_P(WifiChipHidlTest, RequestFirmwareDebugDump) { uint32_t caps = configureChipForStaIfaceAndGetCapabilities(); const auto& status_and_firmware_dump = HIDL_INVOKE(wifi_chip_, requestFirmwareDebugDump); @@ -237,7 +242,7 @@ TEST_F(WifiChipHidlTest, RequestFirmwareDebugDump) { /* * RequestDriverDebugDump */ -TEST_F(WifiChipHidlTest, RequestDriverDebugDump) { +TEST_P(WifiChipHidlTest, RequestDriverDebugDump) { uint32_t caps = configureChipForStaIfaceAndGetCapabilities(); const auto& status_and_driver_dump = HIDL_INVOKE(wifi_chip_, requestDriverDebugDump); @@ -254,7 +259,7 @@ TEST_F(WifiChipHidlTest, RequestDriverDebugDump) { /* * GetDebugRingBuffersStatus */ -TEST_F(WifiChipHidlTest, GetDebugRingBuffersStatus) { +TEST_P(WifiChipHidlTest, GetDebugRingBuffersStatus) { uint32_t caps = configureChipForStaIfaceAndGetCapabilities(); const auto& status_and_ring_buffer_status = HIDL_INVOKE(wifi_chip_, getDebugRingBuffersStatus); @@ -273,7 +278,7 @@ TEST_F(WifiChipHidlTest, GetDebugRingBuffersStatus) { /* * StartLoggingToDebugRingBuffer */ -TEST_F(WifiChipHidlTest, StartLoggingToDebugRingBuffer) { +TEST_P(WifiChipHidlTest, StartLoggingToDebugRingBuffer) { uint32_t caps = configureChipForStaIfaceAndGetCapabilities(); std::string ring_name; const auto& status_and_ring_buffer_status = @@ -301,7 +306,7 @@ TEST_F(WifiChipHidlTest, StartLoggingToDebugRingBuffer) { /* * ForceDumpToDebugRingBuffer */ -TEST_F(WifiChipHidlTest, ForceDumpToDebugRingBuffer) { +TEST_P(WifiChipHidlTest, ForceDumpToDebugRingBuffer) { uint32_t caps = configureChipForStaIfaceAndGetCapabilities(); std::string ring_name; const auto& status_and_ring_buffer_status = @@ -327,7 +332,7 @@ TEST_F(WifiChipHidlTest, ForceDumpToDebugRingBuffer) { /* * GetDebugHostWakeReasonStats */ -TEST_F(WifiChipHidlTest, GetDebugHostWakeReasonStats) { +TEST_P(WifiChipHidlTest, GetDebugHostWakeReasonStats) { uint32_t caps = configureChipForStaIfaceAndGetCapabilities(); const auto& status_and_debug_wake_reason = HIDL_INVOKE(wifi_chip_, getDebugHostWakeReasonStats); @@ -345,7 +350,7 @@ TEST_F(WifiChipHidlTest, GetDebugHostWakeReasonStats) { * Configures the chip in P2P mode and ensures that at least 1 iface creation * succeeds. */ -TEST_F(WifiChipHidlTest, CreateP2pIface) { +TEST_P(WifiChipHidlTest, CreateP2pIface) { configureChipForIfaceType(IfaceType::P2P, true); sp iface; @@ -359,7 +364,7 @@ TEST_F(WifiChipHidlTest, CreateP2pIface) { * before creating the iface. Then, create the iface and ensure that * iface name is returned via the list. */ -TEST_F(WifiChipHidlTest, GetP2pIfaceNames) { +TEST_P(WifiChipHidlTest, GetP2pIfaceNames) { configureChipForIfaceType(IfaceType::P2P, true); const auto& status_and_iface_names1 = @@ -391,7 +396,7 @@ TEST_F(WifiChipHidlTest, GetP2pIfaceNames) { * the iface object using the correct name and ensure any other name * doesn't retrieve an iface object. */ -TEST_F(WifiChipHidlTest, GetP2pIface) { +TEST_P(WifiChipHidlTest, GetP2pIface) { configureChipForIfaceType(IfaceType::P2P, true); sp p2p_iface; @@ -417,7 +422,7 @@ TEST_F(WifiChipHidlTest, GetP2pIface) { * the iface object using the correct name and ensure any other name * doesn't remove the iface. */ -TEST_F(WifiChipHidlTest, RemoveP2pIface) { +TEST_P(WifiChipHidlTest, RemoveP2pIface) { configureChipForIfaceType(IfaceType::P2P, true); sp p2p_iface; @@ -438,7 +443,7 @@ TEST_F(WifiChipHidlTest, RemoveP2pIface) { * Configures the chip in STA mode and ensures that at least 1 iface creation * succeeds. */ -TEST_F(WifiChipHidlTest, CreateStaIface) { +TEST_P(WifiChipHidlTest, CreateStaIface) { configureChipForIfaceType(IfaceType::STA, true); sp iface; @@ -452,7 +457,7 @@ TEST_F(WifiChipHidlTest, CreateStaIface) { * before creating the iface. Then, create the iface and ensure that * iface name is returned via the list. */ -TEST_F(WifiChipHidlTest, GetStaIfaceNames) { +TEST_P(WifiChipHidlTest, GetStaIfaceNames) { configureChipForIfaceType(IfaceType::STA, true); const auto& status_and_iface_names1 = @@ -484,7 +489,7 @@ TEST_F(WifiChipHidlTest, GetStaIfaceNames) { * the iface object using the correct name and ensure any other name * doesn't retrieve an iface object. */ -TEST_F(WifiChipHidlTest, GetStaIface) { +TEST_P(WifiChipHidlTest, GetStaIface) { configureChipForIfaceType(IfaceType::STA, true); sp sta_iface; @@ -510,7 +515,7 @@ TEST_F(WifiChipHidlTest, GetStaIface) { * the iface object using the correct name and ensure any other name * doesn't remove the iface. */ -TEST_F(WifiChipHidlTest, RemoveStaIface) { +TEST_P(WifiChipHidlTest, RemoveStaIface) { configureChipForIfaceType(IfaceType::STA, true); sp sta_iface; @@ -529,7 +534,7 @@ TEST_F(WifiChipHidlTest, RemoveStaIface) { /* * CreateRttController */ -TEST_F(WifiChipHidlTest, CreateRttController) { +TEST_P(WifiChipHidlTest, CreateRttController) { configureChipForIfaceType(IfaceType::STA, true); sp iface; @@ -541,3 +546,9 @@ TEST_F(WifiChipHidlTest, CreateRttController) { EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_rtt_controller.first.code); EXPECT_NE(nullptr, status_and_rtt_controller.second.get()); } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiChipHidlTest, + testing::ValuesIn( + android::hardware::getAllHalInstanceNames(IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/wifi/1.0/vts/functional/wifi_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_hidl_test.cpp index b8e501c0a5..512701a40c 100644 --- a/wifi/1.0/vts/functional/wifi_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_hidl_test.cpp @@ -18,7 +18,9 @@ #include -#include +#include +#include +#include #include "wifi_hidl_test_utils.h" @@ -28,13 +30,14 @@ using ::android::sp; /** * Fixture to use for all root Wifi HIDL interface tests. */ -class WifiHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class WifiHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override {} - virtual void TearDown() override { stopWifi(); } + virtual void TearDown() override { stopWifi(GetInstanceName()); } protected: + std::string GetInstanceName() { return GetParam(); } }; /* @@ -42,7 +45,12 @@ class WifiHidlTest : public ::testing::VtsHalHidlTargetTestBase { * Ensures that an instance of the IWifi proxy object is * successfully created. */ -TEST(WifiHidlTestNoFixture, Create) { - EXPECT_NE(nullptr, getWifi().get()); - stopWifi(); +TEST_P(WifiHidlTest, Create) { + // The creation of a proxy object is tested as part of SetUp method. } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiHidlTest, + testing::ValuesIn( + android::hardware::getAllHalInstanceNames(IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp index f89f7b4b44..0e576e7734 100644 --- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp +++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp @@ -196,7 +196,7 @@ sp getWifiRttController(const std::string& instance_name) { if (!wifi_chip.get()) { return nullptr; } - sp wifi_sta_iface = getWifiStaIface(); + sp wifi_sta_iface = getWifiStaIface(instance_name); if (!wifi_sta_iface.get()) { return nullptr; } diff --git a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp index 64b4fb6d1a..422e3f6bba 100644 --- a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp @@ -16,10 +16,12 @@ #include +#include #include #include - -#include +#include +#include +#include #include #include #include @@ -29,27 +31,28 @@ using namespace ::android::hardware::wifi::V1_0; +using ::android::sp; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::sp; +using ::android::hardware::wifi::V1_0::IWifi; #define TIMEOUT_PERIOD 10 /** * Fixture to use for all NAN Iface HIDL interface tests. */ -class WifiNanIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { - public: +class WifiNanIfaceHidlTest : public ::testing::TestWithParam { + public: virtual void SetUp() override { - iwifiNanIface = getWifiNanIface(); - ASSERT_NE(nullptr, iwifiNanIface.get()); - ASSERT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(iwifiNanIface, registerEventCallback, - new WifiNanIfaceEventCallback(*this)).code); + iwifiNanIface = getWifiNanIface(GetInstanceName()); + ASSERT_NE(nullptr, iwifiNanIface.get()); + ASSERT_EQ(WifiStatusCode::SUCCESS, + HIDL_INVOKE(iwifiNanIface, registerEventCallback, + new WifiNanIfaceEventCallback(*this)) + .code); } - virtual void TearDown() override { - stopWifi(); - } + virtual void TearDown() override { stopWifi(GetInstanceName()); } /* Used as a mechanism to inform the test about data/event callback */ inline void notify() { @@ -438,6 +441,8 @@ class WifiNanIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { NanFollowupReceivedInd nanFollowupReceivedInd; NanDataPathRequestInd nanDataPathRequestInd; NanDataPathConfirmInd nanDataPathConfirmInd; + + std::string GetInstanceName() { return GetParam(); } }; /* @@ -445,9 +450,8 @@ class WifiNanIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { * Ensures that an instance of the IWifiNanIface proxy object is * successfully created. */ -TEST(WifiNanIfaceHidlTestNoFixture, Create) { - ASSERT_NE(nullptr, getWifiNanIface().get()); - stopWifi(); +TEST_P(WifiNanIfaceHidlTest, Create) { + // The creation of a proxy object is tested as part of SetUp method. } /* @@ -455,41 +459,51 @@ TEST(WifiNanIfaceHidlTestNoFixture, Create) { * Ensure that API calls fail with ERROR_WIFI_IFACE_INVALID when using an interface once wifi * is disabled. */ -TEST(WifiNanIfaceHidlTestNoFixture, FailOnIfaceInvalid) { - android::sp iwifiNanIface = getWifiNanIface(); - ASSERT_NE(nullptr, iwifiNanIface.get()); - stopWifi(); - sleep(5); // make sure that all chips/interfaces are invalidated - ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID, - HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, 0).code); +TEST_P(WifiNanIfaceHidlTest, FailOnIfaceInvalid) { + stopWifi(GetInstanceName()); + android::sp iwifiNanIface = + getWifiNanIface(GetInstanceName()); + ASSERT_NE(nullptr, iwifiNanIface.get()); + stopWifi(GetInstanceName()); + sleep(5); // make sure that all chips/interfaces are invalidated + ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, 0).code); } /* * getCapabilitiesRequest: validate that returns capabilities. */ -TEST_F(WifiNanIfaceHidlTest, getCapabilitiesRequest) { - uint16_t inputCmdId = 10; - callbackType = INVALID; - ASSERT_EQ(WifiStatusCode::SUCCESS, +TEST_P(WifiNanIfaceHidlTest, getCapabilitiesRequest) { + uint16_t inputCmdId = 10; + callbackType = INVALID; + ASSERT_EQ( + WifiStatusCode::SUCCESS, HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, inputCmdId).code); - // wait for a callback - ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE)); - ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callbackType); - ASSERT_EQ(id, inputCmdId); + // wait for a callback + ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE)); + ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callbackType); + ASSERT_EQ(id, inputCmdId); - // check for reasonable capability values - EXPECT_GT(capabilities.maxConcurrentClusters, (unsigned int) 0); - EXPECT_GT(capabilities.maxPublishes, (unsigned int) 0); - EXPECT_GT(capabilities.maxSubscribes, (unsigned int) 0); - EXPECT_EQ(capabilities.maxServiceNameLen, (unsigned int) 255); - EXPECT_EQ(capabilities.maxMatchFilterLen, (unsigned int) 255); - EXPECT_GT(capabilities.maxTotalMatchFilterLen, (unsigned int) 255); - EXPECT_EQ(capabilities.maxServiceSpecificInfoLen, (unsigned int) 255); - EXPECT_GE(capabilities.maxExtendedServiceSpecificInfoLen, (unsigned int) 255); - EXPECT_GT(capabilities.maxNdiInterfaces, (unsigned int) 0); - EXPECT_GT(capabilities.maxNdpSessions, (unsigned int) 0); - EXPECT_GT(capabilities.maxAppInfoLen, (unsigned int) 0); - EXPECT_GT(capabilities.maxQueuedTransmitFollowupMsgs, (unsigned int) 0); - EXPECT_GT(capabilities.maxSubscribeInterfaceAddresses, (unsigned int) 0); - EXPECT_NE(capabilities.supportedCipherSuites, (unsigned int) 0); + // check for reasonable capability values + EXPECT_GT(capabilities.maxConcurrentClusters, (unsigned int)0); + EXPECT_GT(capabilities.maxPublishes, (unsigned int)0); + EXPECT_GT(capabilities.maxSubscribes, (unsigned int)0); + EXPECT_EQ(capabilities.maxServiceNameLen, (unsigned int)255); + EXPECT_EQ(capabilities.maxMatchFilterLen, (unsigned int)255); + EXPECT_GT(capabilities.maxTotalMatchFilterLen, (unsigned int)255); + EXPECT_EQ(capabilities.maxServiceSpecificInfoLen, (unsigned int)255); + EXPECT_GE(capabilities.maxExtendedServiceSpecificInfoLen, + (unsigned int)255); + EXPECT_GT(capabilities.maxNdiInterfaces, (unsigned int)0); + EXPECT_GT(capabilities.maxNdpSessions, (unsigned int)0); + EXPECT_GT(capabilities.maxAppInfoLen, (unsigned int)0); + EXPECT_GT(capabilities.maxQueuedTransmitFollowupMsgs, (unsigned int)0); + EXPECT_GT(capabilities.maxSubscribeInterfaceAddresses, (unsigned int)0); + EXPECT_NE(capabilities.supportedCipherSuites, (unsigned int)0); } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiNanIfaceHidlTest, + testing::ValuesIn( + android::hardware::getAllHalInstanceNames(IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp index 269eb6c62e..8f3327150c 100644 --- a/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp @@ -16,25 +16,29 @@ #include +#include #include - -#include +#include +#include +#include #include "wifi_hidl_test_utils.h" -using ::android::hardware::wifi::V1_0::IWifiP2pIface; using ::android::sp; +using ::android::hardware::wifi::V1_0::IWifi; +using ::android::hardware::wifi::V1_0::IWifiP2pIface; /** * Fixture to use for all P2P Iface HIDL interface tests. */ -class WifiP2pIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class WifiP2pIfaceHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override {} - virtual void TearDown() override { stopWifi(); } + virtual void TearDown() override { stopWifi(GetInstanceName()); } protected: + std::string GetInstanceName() { return GetParam(); } }; /* @@ -42,7 +46,13 @@ class WifiP2pIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { * Ensures that an instance of the IWifiP2pIface proxy object is * successfully created. */ -TEST(WifiP2pIfaceHidlTestNoFixture, Create) { - EXPECT_NE(nullptr, getWifiP2pIface().get()); - stopWifi(); +TEST_P(WifiP2pIfaceHidlTest, Create) { + stopWifi(GetInstanceName()); + EXPECT_NE(nullptr, getWifiP2pIface(GetInstanceName()).get()); } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiP2pIfaceHidlTest, + testing::ValuesIn( + android::hardware::getAllHalInstanceNames(IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp index e13086d2ec..e1ee34fef0 100644 --- a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp @@ -16,25 +16,29 @@ #include +#include #include - -#include +#include +#include +#include #include "wifi_hidl_test_utils.h" -using ::android::hardware::wifi::V1_0::IWifiRttController; using ::android::sp; +using ::android::hardware::wifi::V1_0::IWifi; +using ::android::hardware::wifi::V1_0::IWifiRttController; /** * Fixture to use for all RTT controller HIDL interface tests. */ -class WifiRttControllerHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class WifiRttControllerHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override {} - virtual void TearDown() override { stopWifi(); } + virtual void TearDown() override { stopWifi(GetInstanceName()); } protected: + std::string GetInstanceName() { return GetParam(); } }; /* @@ -42,7 +46,13 @@ class WifiRttControllerHidlTest : public ::testing::VtsHalHidlTargetTestBase { * Ensures that an instance of the IWifiRttController proxy object is * successfully created. */ -TEST(WifiRttControllerHidlTestNoFixture, Create) { - EXPECT_NE(nullptr, getWifiRttController().get()); - stopWifi(); +TEST_P(WifiRttControllerHidlTest, Create) { + stopWifi(GetInstanceName()); + EXPECT_NE(nullptr, getWifiRttController(GetInstanceName()).get()); } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiRttControllerHidlTest, + testing::ValuesIn( + android::hardware::getAllHalInstanceNames(IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp index a41386338b..30b6fba38c 100644 --- a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp @@ -16,10 +16,12 @@ #include +#include #include #include - -#include +#include +#include +#include #include "wifi_hidl_call_util.h" #include "wifi_hidl_test_utils.h" @@ -28,6 +30,7 @@ using ::android::sp; using ::android::hardware::wifi::V1_0::Bssid; using ::android::hardware::wifi::V1_0::CommandId; using ::android::hardware::wifi::V1_0::IfaceType; +using ::android::hardware::wifi::V1_0::IWifi; using ::android::hardware::wifi::V1_0::IWifiStaIface; using ::android::hardware::wifi::V1_0::Rssi; using ::android::hardware::wifi::V1_0::Ssid; @@ -41,14 +44,14 @@ using ::android::hardware::wifi::V1_0::WifiStatusCode; /** * Fixture to use for all STA Iface HIDL interface tests. */ -class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class WifiStaIfaceHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { - wifi_sta_iface_ = getWifiStaIface(); + wifi_sta_iface_ = getWifiStaIface(GetInstanceName()); ASSERT_NE(nullptr, wifi_sta_iface_.get()); } - virtual void TearDown() override { stopWifi(); } + virtual void TearDown() override { stopWifi(GetInstanceName()); } protected: bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask cap_mask) { @@ -59,6 +62,7 @@ class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { } sp wifi_sta_iface_; + std::string GetInstanceName() { return GetParam(); } }; /* @@ -66,15 +70,14 @@ class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { * Ensures that an instance of the IWifiStaIface proxy object is * successfully created. */ -TEST(WifiStaIfaceHidlTestNoFixture, Create) { - EXPECT_NE(nullptr, getWifiStaIface().get()); - stopWifi(); +TEST_P(WifiStaIfaceHidlTest, Create) { + // The creation of a proxy object is tested as part of SetUp method. } /* * GetCapabilities: */ -TEST_F(WifiStaIfaceHidlTest, GetCapabilities) { +TEST_P(WifiStaIfaceHidlTest, GetCapabilities) { const auto& status_and_caps = HIDL_INVOKE(wifi_sta_iface_, getCapabilities); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code); EXPECT_GT(status_and_caps.second, 0u); @@ -84,7 +87,7 @@ TEST_F(WifiStaIfaceHidlTest, GetCapabilities) { * GetType: * Ensures that the correct interface type is returned for station interface. */ -TEST_F(WifiStaIfaceHidlTest, GetType) { +TEST_P(WifiStaIfaceHidlTest, GetType) { const auto& status_and_type = HIDL_INVOKE(wifi_sta_iface_, getType); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_type.first.code); EXPECT_EQ(IfaceType::STA, status_and_type.second); @@ -94,7 +97,7 @@ TEST_F(WifiStaIfaceHidlTest, GetType) { * GetApfPacketFilterCapabilities: * Ensures that we can retrieve APF packet filter capabilites. */ -TEST_F(WifiStaIfaceHidlTest, GetApfPacketFilterCapabilities) { +TEST_P(WifiStaIfaceHidlTest, GetApfPacketFilterCapabilities) { if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::APF)) { // No-op if APF packet filer is not supported. return; @@ -109,7 +112,7 @@ TEST_F(WifiStaIfaceHidlTest, GetApfPacketFilterCapabilities) { * GetBackgroundScanCapabilities: * Ensures that we can retrieve background scan capabilities. */ -TEST_F(WifiStaIfaceHidlTest, GetBackgroundScanCapabilities) { +TEST_P(WifiStaIfaceHidlTest, GetBackgroundScanCapabilities) { if (!isCapabilitySupported( IWifiStaIface::StaIfaceCapabilityMask::BACKGROUND_SCAN)) { // No-op if background scan is not supported. @@ -125,7 +128,7 @@ TEST_F(WifiStaIfaceHidlTest, GetBackgroundScanCapabilities) { * GetValidFrequenciesForBand: * Ensures that we can retrieve valid frequencies for 2.4 GHz band. */ -TEST_F(WifiStaIfaceHidlTest, GetValidFrequenciesForBand) { +TEST_P(WifiStaIfaceHidlTest, GetValidFrequenciesForBand) { const auto& status_and_freqs = HIDL_INVOKE( wifi_sta_iface_, getValidFrequenciesForBand, WifiBand::BAND_24GHZ); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_freqs.first.code); @@ -137,7 +140,7 @@ TEST_F(WifiStaIfaceHidlTest, GetValidFrequenciesForBand) { * Ensures that calls to enable, disable, and retrieve link layer stats * will return a success status code. */ -TEST_F(WifiStaIfaceHidlTest, LinkLayerStatsCollection) { +TEST_P(WifiStaIfaceHidlTest, LinkLayerStatsCollection) { if (!isCapabilitySupported( IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) { // No-op if link layer stats is not supported. @@ -172,7 +175,7 @@ TEST_F(WifiStaIfaceHidlTest, LinkLayerStatsCollection) { * Ensures that calls to disable RSSI monitoring will return an error status * code if RSSI monitoring is not enabled. */ -TEST_F(WifiStaIfaceHidlTest, RSSIMonitoring) { +TEST_P(WifiStaIfaceHidlTest, RSSIMonitoring) { if (!isCapabilitySupported( IWifiStaIface::StaIfaceCapabilityMask::RSSI_MONITOR)) { // No-op if RSSI monitor is not supported. @@ -197,7 +200,7 @@ TEST_F(WifiStaIfaceHidlTest, RSSIMonitoring) { * Ensures that calls to configure and enable roaming will return a success * status code. */ -TEST_F(WifiStaIfaceHidlTest, RoamingControl) { +TEST_P(WifiStaIfaceHidlTest, RoamingControl) { if (!isCapabilitySupported( IWifiStaIface::StaIfaceCapabilityMask::CONTROL_ROAMING)) { // No-op if roaming control is not supported. @@ -242,9 +245,9 @@ TEST_F(WifiStaIfaceHidlTest, RoamingControl) { * Ensures that calls to enable neighbor discovery offload will return a success * status code. */ -TEST_F(WifiStaIfaceHidlTest, EnableNDOffload) { - if (!isCapabilitySupported( - IWifiStaIface::StaIfaceCapabilityMask::ND_OFFLOAD)) { +TEST_P(WifiStaIfaceHidlTest, EnableNDOffload) { + if (!isCapabilitySupported( + IWifiStaIface::StaIfaceCapabilityMask::ND_OFFLOAD)) { // No-op if nd offload is not supported. return; } @@ -257,7 +260,7 @@ TEST_F(WifiStaIfaceHidlTest, EnableNDOffload) { * Ensures that calls to set scanning MAC OUI will return a success status * code. */ -TEST_F(WifiStaIfaceHidlTest, SetScanningMacOui) { +TEST_P(WifiStaIfaceHidlTest, SetScanningMacOui) { if (!isCapabilitySupported( IWifiStaIface::StaIfaceCapabilityMask::SCAN_RAND)) { // No-op if SetScanningMacOui is not supported. @@ -274,9 +277,9 @@ TEST_F(WifiStaIfaceHidlTest, SetScanningMacOui) { * Ensures that calls to start packet fate monitoring and retrieve TX/RX * packets will return a success status code. */ -TEST_F(WifiStaIfaceHidlTest, PacketFateMonitoring) { - if (!isCapabilitySupported( - IWifiStaIface::StaIfaceCapabilityMask::DEBUG_PACKET_FATE)) { +TEST_P(WifiStaIfaceHidlTest, PacketFateMonitoring) { + if (!isCapabilitySupported( + IWifiStaIface::StaIfaceCapabilityMask::DEBUG_PACKET_FATE)) { // No-op if packet fate monitor is not supported. return; } @@ -291,3 +294,9 @@ TEST_F(WifiStaIfaceHidlTest, PacketFateMonitoring) { EXPECT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(wifi_sta_iface_, getDebugRxPacketFates).first.code); } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiStaIfaceHidlTest, + testing::ValuesIn( + android::hardware::getAllHalInstanceNames(IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/wifi/1.1/vts/functional/Android.bp b/wifi/1.1/vts/functional/Android.bp index 6662314aa5..1774cb46a8 100644 --- a/wifi/1.1/vts/functional/Android.bp +++ b/wifi/1.1/vts/functional/Android.bp @@ -27,5 +27,5 @@ cc_test { "android.hardware.wifi@1.2", "android.hardware.wifi@1.3", ], - test_suites: ["general-tests"], + test_suites: ["general-tests", "vts-core"], } diff --git a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp index 673fed3675..4b62b15699 100644 --- a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp +++ b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp @@ -14,34 +14,8 @@ * limitations under the License. */ -#include -#include +#include -#include "wifi_hidl_test_utils.h" - -class WifiHidlEnvironment_1_1 : public WifiHidlEnvironment { - public: - // get the test environment singleton - static WifiHidlEnvironment_1_1* Instance() { - static WifiHidlEnvironment_1_1* instance = new WifiHidlEnvironment_1_1; - return instance; - } - - virtual void registerTestServices() override { - registerTestService(); - } - - private: - WifiHidlEnvironment_1_1() {} -}; - -WifiHidlEnvironment* gEnv = WifiHidlEnvironment_1_1::Instance(); - -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(gEnv); - ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; -} +// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is +// updated. +::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr; diff --git a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp index 63235472af..08de240252 100644 --- a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp @@ -19,8 +19,9 @@ #include #include #include - -#include +#include +#include +#include #include "wifi_hidl_call_util.h" #include "wifi_hidl_test_utils.h" @@ -45,14 +46,14 @@ constexpr IWifiChip::TxPowerScenario kFakePowerScenario = /** * Fixture to use for all Wifi chip HIDL interface tests. */ -class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class WifiChipHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { - wifi_chip_ = IWifiChip::castFrom(getWifiChip()); + wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName())); ASSERT_NE(nullptr, wifi_chip_.get()); } - virtual void TearDown() override { stopWifi(); } + virtual void TearDown() override { stopWifi(GetInstanceName()); } protected: uint32_t configureChipForStaIfaceAndGetCapabilities() { @@ -77,12 +78,15 @@ class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { } sp wifi_chip_; + + private: + std::string GetInstanceName() { return GetParam(); } }; /* * SelectTxPowerScenario */ -TEST_F(WifiChipHidlTest, SelectTxPowerScenario) { +TEST_P(WifiChipHidlTest, SelectTxPowerScenario) { uint32_t caps = configureChipForStaIfaceAndGetCapabilities(); const auto& status = HIDL_INVOKE(wifi_chip_, selectTxPowerScenario, kFakePowerScenario); @@ -96,7 +100,7 @@ TEST_F(WifiChipHidlTest, SelectTxPowerScenario) { /* * ResetTxPowerScenario */ -TEST_F(WifiChipHidlTest, ResetTxPowerScenario) { +TEST_P(WifiChipHidlTest, ResetTxPowerScenario) { uint32_t caps = configureChipForStaIfaceAndGetCapabilities(); const auto& status = HIDL_INVOKE(wifi_chip_, resetTxPowerScenario); @@ -106,3 +110,9 @@ TEST_F(WifiChipHidlTest, ResetTxPowerScenario) { EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code); } } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiChipHidlTest, + testing::ValuesIn( + android::hardware::getAllHalInstanceNames(IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/wifi/1.2/vts/functional/Android.bp b/wifi/1.2/vts/functional/Android.bp index b2956ce3c4..1eaf877ba4 100644 --- a/wifi/1.2/vts/functional/Android.bp +++ b/wifi/1.2/vts/functional/Android.bp @@ -29,7 +29,8 @@ cc_test { "android.hardware.wifi@1.2", "android.hardware.wifi@1.3", ], - test_suites: ["general-tests"], + disable_framework: true, + test_suites: ["general-tests", "vts-core"], } cc_test { @@ -45,5 +46,6 @@ cc_test { "android.hardware.wifi@1.1", "android.hardware.wifi@1.2", ], - test_suites: ["general-tests"], + disable_framework: true, + test_suites: ["general-tests", "vts-core"], } diff --git a/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp b/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp index c765cdcc3b..52c7a4ad0d 100644 --- a/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp +++ b/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp @@ -14,35 +14,8 @@ * limitations under the License. */ -#include -#include +#include -#include "wifi_hidl_test_utils.h" - -using ::android::hardware::wifi::V1_2::IWifi; - -// Test environment for Wifi HIDL HAL. -class WifiHidlEnvironment_1_2 : public WifiHidlEnvironment { - public: - // get the test environment singleton - static WifiHidlEnvironment_1_2* Instance() { - static WifiHidlEnvironment_1_2* instance = new WifiHidlEnvironment_1_2; - return instance; - } - - virtual void registerTestServices() override { registerTestService(); } - - private: - WifiHidlEnvironment_1_2() {} -}; - -WifiHidlEnvironment_1_2* gEnv = WifiHidlEnvironment_1_2::Instance(); - -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(gEnv); - ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; -} +// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is +// updated. +::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr; \ No newline at end of file diff --git a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp index 9d567feafa..47faec8b88 100644 --- a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp @@ -16,12 +16,14 @@ #include +#include #include #include #include - +#include +#include +#include #include -#include #include "wifi_hidl_call_util.h" #include "wifi_hidl_test_utils.h" @@ -50,14 +52,14 @@ constexpr IWifiChip::TxPowerScenario kPowerScenarioVoiceCall = /** * Fixture to use for all Wifi chip HIDL interface tests. */ -class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class WifiChipHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { - wifi_chip_ = IWifiChip::castFrom(getWifiChip()); + wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName())); ASSERT_NE(nullptr, wifi_chip_.get()); } - virtual void TearDown() override { stopWifi(); } + virtual void TearDown() override { stopWifi(GetInstanceName()); } // A simple test implementation of WifiChipEventCallback. class WifiChipEventCallback @@ -123,6 +125,9 @@ class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { } sp wifi_chip_; + + private: + std::string GetInstanceName() { return GetParam(); } }; /* @@ -130,7 +135,7 @@ class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { * This test case tests the selectTxPowerScenario_1_2() API with SAR scenarios * newly defined in 1.2 */ -TEST_F(WifiChipHidlTest, SelectTxPowerScenario_1_2_body) { +TEST_P(WifiChipHidlTest, SelectTxPowerScenario_1_2_body) { uint32_t caps = configureChipForStaIfaceAndGetCapabilities(); const auto& status = HIDL_INVOKE(wifi_chip_, selectTxPowerScenario_1_2, kPowerScenarioBody); @@ -147,7 +152,7 @@ TEST_F(WifiChipHidlTest, SelectTxPowerScenario_1_2_body) { * This test case tests the selectTxPowerScenario_1_2() API with previously * defined SAR scenarios */ -TEST_F(WifiChipHidlTest, SelectTxPowerScenario_1_2_voiceCall) { +TEST_P(WifiChipHidlTest, SelectTxPowerScenario_1_2_voiceCall) { uint32_t caps = configureChipForStaIfaceAndGetCapabilities(); const auto& status = HIDL_INVOKE(wifi_chip_, selectTxPowerScenario_1_2, kPowerScenarioVoiceCall); @@ -167,9 +172,15 @@ TEST_F(WifiChipHidlTest, SelectTxPowerScenario_1_2_voiceCall) { * since event is triggered internally in the HAL implementation, and can not be * triggered from the test case */ -TEST_F(WifiChipHidlTest, registerEventCallback_1_2) { +TEST_P(WifiChipHidlTest, registerEventCallback_1_2) { sp wifiChipEventCallback = new WifiChipEventCallback(); const auto& status = HIDL_INVOKE(wifi_chip_, registerEventCallback_1_2, wifiChipEventCallback); EXPECT_EQ(WifiStatusCode::SUCCESS, status.code); } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiChipHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + ::android::hardware::wifi::V1_2::IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp index 4dbc82bd99..f3f76e1564 100644 --- a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp +++ b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp @@ -16,10 +16,12 @@ #include +#include #include #include - -#include +#include +#include +#include #include #include #include @@ -36,19 +38,19 @@ using ::android::sp; #define TIMEOUT_PERIOD 10 -android::sp -getWifiNanIface_1_2() { +android::sp getWifiNanIface_1_2( + const std::string& instance_name) { return android::hardware::wifi::V1_2::IWifiNanIface::castFrom( - getWifiNanIface()); + getWifiNanIface(instance_name)); } /** * Fixture to use for all NAN Iface HIDL interface tests. */ -class WifiNanIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class WifiNanIfaceHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { - iwifiNanIface = getWifiNanIface_1_2(); + iwifiNanIface = getWifiNanIface_1_2(GetInstanceName()); ASSERT_NE(nullptr, iwifiNanIface.get()); ASSERT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(iwifiNanIface, registerEventCallback_1_2, @@ -56,7 +58,7 @@ class WifiNanIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { .code); } - virtual void TearDown() override { stopWifi(); } + virtual void TearDown() override { stopWifi(GetInstanceName()); } /* Used as a mechanism to inform the test about data/event callback */ inline void notify() { @@ -458,6 +460,8 @@ class WifiNanIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { ::android::hardware::wifi::V1_2::NanDataPathConfirmInd nanDataPathConfirmInd_1_2; NanDataPathScheduleUpdateInd nanDataPathScheduleUpdateInd; + + std::string GetInstanceName() { return GetParam(); } }; /* @@ -465,15 +469,14 @@ class WifiNanIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { * Ensures that an instance of the IWifiNanIface proxy object is * successfully created. */ -TEST(WifiNanIfaceHidlTestNoFixture, Create) { - ASSERT_NE(nullptr, getWifiNanIface_1_2().get()); - stopWifi(); +TEST_P(WifiNanIfaceHidlTest, Create) { + // The creation of a proxy object is tested as part of SetUp method. } /* * enableRequest_1_2InvalidArgs: validate that fails with invalid arguments */ -TEST_F(WifiNanIfaceHidlTest, enableRequest_1_2InvalidArgs) { +TEST_P(WifiNanIfaceHidlTest, enableRequest_1_2InvalidArgs) { uint16_t inputCmdId = 10; callbackType = INVALID; NanEnableRequest nanEnableRequest = {}; @@ -493,7 +496,7 @@ TEST_F(WifiNanIfaceHidlTest, enableRequest_1_2InvalidArgs) { * enableRequest_1_2ShimInvalidArgs: validate that fails with invalid arguments * to the shim */ -TEST_F(WifiNanIfaceHidlTest, enableRequest_1_2ShimInvalidArgs) { +TEST_P(WifiNanIfaceHidlTest, enableRequest_1_2ShimInvalidArgs) { uint16_t inputCmdId = 10; NanEnableRequest nanEnableRequest = {}; nanEnableRequest.configParams.numberOfPublishServiceIdsInBeacon = @@ -508,7 +511,7 @@ TEST_F(WifiNanIfaceHidlTest, enableRequest_1_2ShimInvalidArgs) { /* * configRequest_1_2InvalidArgs: validate that fails with invalid arguments */ -TEST_F(WifiNanIfaceHidlTest, configRequest_1_2InvalidArgs) { +TEST_P(WifiNanIfaceHidlTest, configRequest_1_2InvalidArgs) { uint16_t inputCmdId = 10; callbackType = INVALID; NanConfigRequest nanConfigRequest = {}; @@ -528,7 +531,7 @@ TEST_F(WifiNanIfaceHidlTest, configRequest_1_2InvalidArgs) { * configRequest_1_2ShimInvalidArgs: validate that fails with invalid arguments * to the shim */ -TEST_F(WifiNanIfaceHidlTest, configRequest_1_2ShimInvalidArgs) { +TEST_P(WifiNanIfaceHidlTest, configRequest_1_2ShimInvalidArgs) { uint16_t inputCmdId = 10; NanConfigRequest nanConfigRequest = {}; nanConfigRequest.numberOfPublishServiceIdsInBeacon = 128; // must be <= 127 @@ -538,3 +541,9 @@ TEST_F(WifiNanIfaceHidlTest, configRequest_1_2ShimInvalidArgs) { nanConfigRequest, nanConfigRequestSupp) .code); } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiNanIfaceHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + ::android::hardware::wifi::V1_2::IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp index 92f5d1453e..1b907b272f 100644 --- a/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp +++ b/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp @@ -19,9 +19,11 @@ #include +#include #include - -#include +#include +#include +#include #include "wifi_hidl_call_util.h" #include "wifi_hidl_test_utils.h" @@ -34,14 +36,15 @@ using ::android::hardware::wifi::V1_2::IWifiStaIface; /** * Fixture to use for all STA Iface HIDL interface tests. */ -class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class WifiStaIfaceHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { - wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface()); + wifi_sta_iface_ = + IWifiStaIface::castFrom(getWifiStaIface(GetInstanceName())); ASSERT_NE(nullptr, wifi_sta_iface_.get()); } - virtual void TearDown() override { stopWifi(); } + virtual void TearDown() override { stopWifi(GetInstanceName()); } protected: bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask cap_mask) { @@ -52,6 +55,9 @@ class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { } sp wifi_sta_iface_; + + private: + std::string GetInstanceName() { return GetParam(); } }; /* @@ -59,7 +65,7 @@ class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { * Ensures that calls to set MAC address will return a success status * code. */ -TEST_F(WifiStaIfaceHidlTest, SetMacAddress) { +TEST_P(WifiStaIfaceHidlTest, SetMacAddress) { const android::hardware::hidl_array kMac{ std::array{{0x12, 0x22, 0x33, 0x52, 0x10, 0x41}}}; EXPECT_EQ(WifiStatusCode::SUCCESS, @@ -76,7 +82,7 @@ TEST_F(WifiStaIfaceHidlTest, SetMacAddress) { * TODO: We can't execute APF opcodes from this test because there's no way * to loop test packets through the wifi firmware (b/73804303#comment29). */ -TEST_F(WifiStaIfaceHidlTest, DISABLED_ReadApfPacketFilterData) { +TEST_P(WifiStaIfaceHidlTest, DISABLED_ReadApfPacketFilterData) { if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::APF)) { // Disable test if APF packet filer is not supported. LOG(WARNING) << "TEST SKIPPED: APF packet filtering not supported"; @@ -107,3 +113,9 @@ TEST_F(WifiStaIfaceHidlTest, DISABLED_ReadApfPacketFilterData) { EXPECT_EQ(status_and_data.second, data); } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiStaIfaceHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + ::android::hardware::wifi::V1_2::IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/wifi/1.3/vts/functional/Android.bp b/wifi/1.3/vts/functional/Android.bp index 53c8f08516..d21c0af1e8 100644 --- a/wifi/1.3/vts/functional/Android.bp +++ b/wifi/1.3/vts/functional/Android.bp @@ -29,4 +29,6 @@ cc_test { "android.hardware.wifi@1.2", "android.hardware.wifi@1.3", ], + disable_framework: true, + test_suites: ["general-tests", "vts-core"], } diff --git a/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp b/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp index faf426e999..52c7a4ad0d 100644 --- a/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp +++ b/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp @@ -14,37 +14,8 @@ * limitations under the License. */ -#include -#include +#include -#include "wifi_hidl_test_utils.h" - -using ::android::hardware::wifi::V1_3::IWifi; - -// Test environment for Wifi HIDL HAL. -class WifiHidlEnvironment_1_3 : public WifiHidlEnvironment { - public: - // get the test environment singleton - static WifiHidlEnvironment_1_3* Instance() { - static WifiHidlEnvironment_1_3* instance = new WifiHidlEnvironment_1_3; - return instance; - } - - virtual void registerTestServices() override { - registerTestService(); - } - - private: - WifiHidlEnvironment_1_3() {} -}; - -WifiHidlEnvironment_1_3* gEnv = WifiHidlEnvironment_1_3::Instance(); - -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(gEnv); - ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; -} +// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is +// updated. +::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr; \ No newline at end of file diff --git a/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp index d980fcb310..db939679ad 100644 --- a/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp @@ -16,9 +16,11 @@ #include +#include #include - -#include +#include +#include +#include #include "wifi_hidl_call_util.h" #include "wifi_hidl_test_utils.h" @@ -39,14 +41,14 @@ constexpr IWifiChip::LatencyMode kLatencyModeLow = IWifiChip::LatencyMode::LOW; /** * Fixture to use for all Wifi chip HIDL interface tests. */ -class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class WifiChipHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { - wifi_chip_ = IWifiChip::castFrom(getWifiChip()); + wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName())); ASSERT_NE(nullptr, wifi_chip_.get()); } - virtual void TearDown() override { stopWifi(); } + virtual void TearDown() override { stopWifi(GetInstanceName()); } protected: // Helper function to configure the Chip in one of the supported modes. @@ -70,6 +72,9 @@ class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { } sp wifi_chip_; + + private: + std::string GetInstanceName() { return GetParam(); } }; /* @@ -77,7 +82,7 @@ class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { * This test case tests the setLatencyMode() API with * Latency mode NORMAL */ -TEST_F(WifiChipHidlTest, SetLatencyMode_normal) { +TEST_P(WifiChipHidlTest, SetLatencyMode_normal) { uint32_t caps = configureChipForStaIfaceAndGetCapabilities(); const auto& status = HIDL_INVOKE(wifi_chip_, setLatencyMode, kLatencyModeNormal); @@ -92,7 +97,7 @@ TEST_F(WifiChipHidlTest, SetLatencyMode_normal) { * SetLatencyMode_low * This test case tests the setLatencyMode() API with Latency mode LOW */ -TEST_F(WifiChipHidlTest, SetLatencyMode_low) { +TEST_P(WifiChipHidlTest, SetLatencyMode_low) { uint32_t caps = configureChipForStaIfaceAndGetCapabilities(); const auto& status = HIDL_INVOKE(wifi_chip_, setLatencyMode, kLatencyModeLow); @@ -106,7 +111,7 @@ TEST_F(WifiChipHidlTest, SetLatencyMode_low) { /* * GetCapabilities_1_3 */ -TEST_F(WifiChipHidlTest, GetCapabilities_1_3) { +TEST_P(WifiChipHidlTest, GetCapabilities_1_3) { configureChipForIfaceType(IfaceType::STA, true); const auto& status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities_1_3); if (status_and_caps.first.code != WifiStatusCode::SUCCESS) { @@ -116,3 +121,9 @@ TEST_F(WifiChipHidlTest, GetCapabilities_1_3) { } EXPECT_NE(0u, status_and_caps.second); } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiChipHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + ::android::hardware::wifi::V1_3::IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp index d382f30e0f..c5acc3c1b2 100644 --- a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp +++ b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp @@ -19,9 +19,11 @@ #include +#include #include - -#include +#include +#include +#include #include "wifi_hidl_call_util.h" #include "wifi_hidl_test_utils.h" @@ -35,14 +37,15 @@ using ::android::hardware::wifi::V1_3::IWifiStaIface; /** * Fixture to use for all STA Iface HIDL interface tests. */ -class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class WifiStaIfaceHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { - wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface()); + wifi_sta_iface_ = + IWifiStaIface::castFrom(getWifiStaIface(GetInstanceName())); ASSERT_NE(nullptr, wifi_sta_iface_.get()); } - virtual void TearDown() override { stopWifi(); } + virtual void TearDown() override { stopWifi(GetInstanceName()); } protected: bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask cap_mask) { @@ -53,6 +56,9 @@ class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { } sp wifi_sta_iface_; + + private: + std::string GetInstanceName() { return GetParam(); } }; /* @@ -60,7 +66,7 @@ class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { * Ensures that calls to get factory MAC address will retrieve a non-zero MAC * and return a success status code. */ -TEST_F(WifiStaIfaceHidlTest, GetFactoryMacAddress) { +TEST_P(WifiStaIfaceHidlTest, GetFactoryMacAddress) { std::pair > status_and_mac = HIDL_INVOKE(wifi_sta_iface_, getFactoryMacAddress); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mac.first.code); @@ -73,7 +79,7 @@ TEST_F(WifiStaIfaceHidlTest, GetFactoryMacAddress) { * Ensures that calls to get link layer stats V1_3 will retrieve a non-empty * StaLinkLayerStats after link layer stats collection is enabled. */ -TEST_F(WifiStaIfaceHidlTest, GetLinkLayerStats_1_3) { +TEST_P(WifiStaIfaceHidlTest, GetLinkLayerStats_1_3) { if (!isCapabilitySupported( IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) { // No-op if link layer stats is not supported. @@ -94,3 +100,9 @@ TEST_F(WifiStaIfaceHidlTest, GetLinkLayerStats_1_3) { WifiStatusCode::SUCCESS, HIDL_INVOKE(wifi_sta_iface_, disableLinkLayerStatsCollection).code); } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiStaIfaceHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + ::android::hardware::wifi::V1_3::IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp index 42c60f2f0e..2c85d9a927 100644 --- a/wifi/1.4/vts/functional/Android.bp +++ b/wifi/1.4/vts/functional/Android.bp @@ -30,4 +30,5 @@ cc_test { "android.hardware.wifi@1.3", "android.hardware.wifi@1.4", ], + test_suites: ["general-tests", "vts-core"], } diff --git a/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp b/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp index deac0fa0cf..7e0f3cdc47 100644 --- a/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp +++ b/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp @@ -14,37 +14,8 @@ * limitations under the License. */ -#include -#include +#include -#include "wifi_hidl_test_utils.h" - -using ::android::hardware::wifi::V1_4::IWifi; - -// Test environment for Wifi HIDL HAL. -class WifiHidlEnvironment_1_4 : public WifiHidlEnvironment { - public: - // get the test environment singleton - static WifiHidlEnvironment_1_4* Instance() { - static WifiHidlEnvironment_1_4* instance = new WifiHidlEnvironment_1_4; - return instance; - } - - virtual void registerTestServices() override { - registerTestService(); - } - - private: - WifiHidlEnvironment_1_4() {} -}; - -WifiHidlEnvironment_1_4* gEnv = WifiHidlEnvironment_1_4::Instance(); - -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(gEnv); - ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; -} +// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is +// updated. +::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr; \ No newline at end of file diff --git a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp index 68e9bbbde2..017ecb6b6d 100644 --- a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp +++ b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp @@ -14,9 +14,11 @@ * limitations under the License. */ +#include #include - -#include +#include +#include +#include #include "wifi_hidl_call_util.h" #include "wifi_hidl_test_utils.h" @@ -25,6 +27,7 @@ using ::android::sp; using ::android::hardware::hidl_array; using ::android::hardware::wifi::V1_0::WifiStatus; using ::android::hardware::wifi::V1_0::WifiStatusCode; +using ::android::hardware::wifi::V1_4::IWifi; using ::android::hardware::wifi::V1_4::IWifiApIface; extern WifiHidlEnvironment* gEnv; @@ -32,19 +35,21 @@ extern WifiHidlEnvironment* gEnv; /** * Fixture to use for all STA Iface HIDL interface tests. */ -class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class WifiApIfaceHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { - wifi_ap_iface_ = IWifiApIface::castFrom(getWifiApIface()); + wifi_ap_iface_ = + IWifiApIface::castFrom(getWifiApIface(GetInstanceName())); ASSERT_NE(nullptr, wifi_ap_iface_.get()); } - virtual void TearDown() override { - stopWifi(); - } + virtual void TearDown() override { stopWifi(GetInstanceName()); } protected: sp wifi_ap_iface_; + + private: + std::string GetInstanceName() { return GetParam(); } }; /* @@ -52,7 +57,7 @@ class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { * Ensures that calls to set MAC address will return a success status * code. */ -TEST_F(WifiApIfaceHidlTest, SetMacAddress) { +TEST_P(WifiApIfaceHidlTest, SetMacAddress) { const hidl_array kMac{{0x12, 0x22, 0x33, 0x52, 0x10, 0x41}}; EXPECT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(wifi_ap_iface_, setMacAddress, kMac).code); @@ -63,10 +68,16 @@ TEST_F(WifiApIfaceHidlTest, SetMacAddress) { * Ensures that calls to get factory MAC address will retrieve a non-zero MAC * and return a success status code. */ -TEST_F(WifiApIfaceHidlTest, GetFactoryMacAddress) { +TEST_P(WifiApIfaceHidlTest, GetFactoryMacAddress) { std::pair > status_and_mac = HIDL_INVOKE(wifi_ap_iface_, getFactoryMacAddress); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mac.first.code); hidl_array all_zero{}; EXPECT_NE(all_zero, status_and_mac.second); } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiApIfaceHidlTest, + testing::ValuesIn( + android::hardware::getAllHalInstanceNames(IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file From 0d3fe0857a65e3a57c6f6a21e4e599e10ea6287a Mon Sep 17 00:00:00 2001 From: Long Ling Date: Thu, 31 Oct 2019 16:31:04 -0700 Subject: [PATCH 0246/1022] graphics: fix failed VTS cases Return BAD_DISPLAY or BAD_PARAMETER as expected. Bug: 140158240 Test: run vts -m VtsHalGraphicsComposerV2_2Target Change-Id: I0f5a7103bc134ed87984bd13248aee7597a95d68 --- .../include/composer-passthrough/2.2/HwcHal.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h b/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h index 93da0a5d94..9b3aa903ef 100644 --- a/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h +++ b/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h @@ -173,6 +173,14 @@ class HwcHalImpl : public V2_1::passthrough::detail::HwcHalImpl { Error getRenderIntents(Display display, ColorMode mode, std::vector* outIntents) override { if (!mDispatch.getRenderIntents) { + IComposerClient::DisplayType type; + if (getDisplayType(display, &type) == Error::BAD_DISPLAY) { + return Error::BAD_DISPLAY; + } + if (mode < ColorMode::NATIVE || mode > ColorMode::DISPLAY_P3) { + return Error::BAD_PARAMETER; + } + *outIntents = std::vector({RenderIntent::COLORIMETRIC}); return Error::NONE; } @@ -199,6 +207,9 @@ class HwcHalImpl : public V2_1::passthrough::detail::HwcHalImpl { Error setColorMode_2_2(Display display, ColorMode mode, RenderIntent intent) override { if (!mDispatch.setColorModeWithRenderIntent) { + if (intent < RenderIntent::COLORIMETRIC || intent > RenderIntent::TONE_MAP_ENHANCE) { + return Error::BAD_PARAMETER; + } if (intent != RenderIntent::COLORIMETRIC) { return Error::UNSUPPORTED; } @@ -282,6 +293,7 @@ class HwcHalImpl : public V2_1::passthrough::detail::HwcHalImpl { private: using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl; using BaseType2_1::getColorModes; + using BaseType2_1::getDisplayType; using BaseType2_1::mDevice; using BaseType2_1::setColorMode; using BaseType2_1::createVirtualDisplay; From 42f01a6477fc224d67b3112cc50a7d7d56f753f2 Mon Sep 17 00:00:00 2001 From: Shuo Qian Date: Thu, 14 Nov 2019 19:53:34 +0000 Subject: [PATCH 0247/1022] Mark RSSNR in 4G as an optional support, and vendor dependency Test: build Bug: 135717625 Change-Id: Iaf42797b2d388843778ce5fedbd28861f340ec5c --- current.txt | 2 +- radio/1.5/types.hal | 6 ++++-- radio/1.5/vts/functional/radio_hidl_hal_api.cpp | 6 +----- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/current.txt b/current.txt index b81aca2cf6..136e396f69 100644 --- a/current.txt +++ b/current.txt @@ -604,7 +604,7 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar 619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types -d3636ff9d5fef59f59f678887209156b2608d29f676fb1e600fe33b7e57a8a61 android.hardware.radio@1.5::types +ba759fab7dd4cd621b492ef8f44312d4a716af786786f404d1477cc8cea6f392 android.hardware.radio@1.5::types c8e81d912827a5d49b2ddcdc4eb4556c5d231a899a1dca879309e04210daa4a0 android.hardware.radio@1.5::IRadio a62a93faf173b14a6175b683ebf61ffa568dc61f81e369d2dce7b1265e86cf2f android.hardware.radio@1.5::IRadioIndication 260ce05806d753d728f844d405e832179ed7d9b65986ec18fef3d21cf7285587 android.hardware.radio@1.5::IRadioResponse diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index 216ca1f156..9ef1d3180c 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -54,7 +54,9 @@ enum SignalMeasurementType : int32_t { * Reference Signal Signal to Noise Ratio * Range: -20 dB to -30 dB; * Used RAN: EUTRAN - * Reference: 3GPP TS 36.101 8.1.1 + * Note: this field is optional; how to support it can be decided by the + * corresponding vendor. Though the response code is not enforced, + * vendor's implementation must ensure this interface not crashing. */ RSSNR = 5, /** @@ -111,4 +113,4 @@ enum AccessNetwork : @1.4::AccessNetwork { * Next-Generation Radio Access Network (NGRAN) */ NGRAN = 6, -}; \ No newline at end of file +}; diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp index 650ede44d2..d173411bca 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp @@ -179,10 +179,6 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSSNR) EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); - - ALOGI("setSignalStrengthReportingCriteria_1_5_Eutran, rspInfo.error = %s\n", - toString(radioRsp_v1_5->rspInfo.error).c_str()); - ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE})); } /* @@ -279,4 +275,4 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR) ALOGI("setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR, rspInfo.error = %s\n", toString(radioRsp_v1_5->rspInfo.error).c_str()); ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE})); -} \ No newline at end of file +} From b9fb7e58fc0faff026bf053770f69e63c1080b80 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Mon, 4 Nov 2019 16:09:03 -0800 Subject: [PATCH 0248/1022] Interface Definition of Vehicle HAL Connector/Vehicle Server Pair Test: compiled by `mm` Change-Id: I0616e9abfca28656242a82e6ca6addad9b9b812c --- .../include/vhal_v2_0/VehicleConnector.h | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h new file mode 100644 index 0000000000..56ecd67ea2 --- /dev/null +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h @@ -0,0 +1,141 @@ +/* + * 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_VehicleConnector_H_ +#define android_hardware_automotive_vehicle_V2_0_VehicleConnector_H_ + +#include + +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +/** + * This file defines the interface of client/server pair for HAL-vehicle + * communication. Vehicle HAL may use this interface to talk to the vehicle + * regardless of the underlying communication channels. + */ + +/** + * Vehicle HAL talks to the vehicle through a client, instead of accessing + * the car bus directly, to give us more flexibility on the implementation. + * Android OS do not need direct access to the vehicle, and the communication + * channel is also customizable. + * + * Client lives on the Android (HAL) side to talk to the vehicle + */ +class IVehicleClient { + public: + IVehicleClient() = default; + + IVehicleClient(const IVehicleClient&) = delete; + + IVehicleClient& operator=(const IVehicleClient&) = delete; + + IVehicleClient(IVehicleClient&&) = default; + + virtual ~IVehicleClient() = default; + + // Get configuration of all properties from server + virtual std::vector getAllPropertyConfig() const = 0; + + // Send the set property request to server + virtual StatusCode setProperty(const VehiclePropValue& value) = 0; + + // Receive a new property value from server + virtual void onPropertyValue(const VehiclePropValue& value) = 0; +}; + +/** + * Server lives on the vehicle side to talk to Android HAL + */ +class IVehicleServer { + public: + IVehicleServer() = default; + + IVehicleServer(const IVehicleServer&) = delete; + + IVehicleServer& operator=(const IVehicleServer&) = delete; + + IVehicleServer(IVehicleServer&&) = default; + + virtual ~IVehicleServer() = default; + + // Receive the get property configuration request from HAL. + // Return a list of all property config + virtual std::vector onGetAllPropertyConfig() const = 0; + + // Receive the set property request from HAL. + // Process the setting and return the status code + virtual StatusCode onSetProperty(const VehiclePropValue& value) = 0; + + // Receive a new property value from car (via direct connection to the car bus or the emulator) + // and forward the value to HAL + virtual void onPropertyValueFromCar(const VehiclePropValue& value) = 0; +}; + +/** + * If Android has direct access to the vehicle, then the client and + * the server may act in passthrough mode to avoid extra IPC + * + * Template is used here for spliting the logic of operating Android objects (VehicleClientType), + * talking to cars (VehicleServerType) and the commucation between client and server (passthrough + * mode in this case), so that we can easily combine different parts together without duplicating + * codes (for example, in Google VHAL, the server talks to the fake car in the same way no matter + * if it is on top of passthrough connector or VSOCK or any other communication channels between + * client and server) + * + * The alternative may be factoring the common logic of every operations for both client and + * server. Which is not always the case. Making sure different non-template connectors calling + * the same method is hard, especially when the engineer maintaining the code may not be aware + * of it when making changes. Template is a clean and easy way to solve this problem in this + * case. + */ +template +class IPassThroughConnector : public VehicleClientType, public VehicleServerType { + static_assert(std::is_base_of_v); + static_assert(std::is_base_of_v); + + public: + std::vector getAllPropertyConfig() const override { + return this->onGetAllPropertyConfig(); + } + + StatusCode setProperty(const VehiclePropValue& value) override { + return this->onSetProperty(value); + } + + void onPropertyValueFromCar(const VehiclePropValue& value) override { + return this->onPropertyValue(value); + } + + // To be implemented: + // virtual std::vector onGetAllPropertyConfig() = 0; + // virtual void onPropertyValue(const VehiclePropValue& value) = 0; + // virtual StatusCode onSetProperty(const VehiclePropValue& value) = 0; +}; + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_0_VehicleConnector_H_ From a31394b245eaaf830c0a913e14ae83f4c551414a Mon Sep 17 00:00:00 2001 From: Pawin Vongmasa Date: Fri, 25 Oct 2019 04:32:14 -0700 Subject: [PATCH 0249/1022] Add media.c2@1.1 Add configureVideoTunnel() to IComponent. Test: make vts -j123 && vts-tradefed run commandAndExit vts \ -m VtsHalMediaC2V1_0Host Bug: 136316504 Change-Id: I505b7b89a02e5aaf2bd735dced1e39cd9e8b8991 --- .../compatibility_matrix.current.xml | 2 +- media/c2/1.1/Android.bp | 27 +++++++ media/c2/1.1/IComponent.hal | 72 +++++++++++++++++++ media/c2/1.1/IComponentStore.hal | 64 +++++++++++++++++ 4 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 media/c2/1.1/Android.bp create mode 100644 media/c2/1.1/IComponent.hal create mode 100644 media/c2/1.1/IComponentStore.hal diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 15359794df..f6d055ad8d 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -280,7 +280,7 @@ android.hardware.media.c2 - 1.0 + 1.0-1 IComponentStore default[0-9]* diff --git a/media/c2/1.1/Android.bp b/media/c2/1.1/Android.bp new file mode 100644 index 0000000000..c3e30b215f --- /dev/null +++ b/media/c2/1.1/Android.bp @@ -0,0 +1,27 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.media.c2@1.1", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "IComponent.hal", + "IComponentStore.hal", + ], + interfaces: [ + "android.hardware.graphics.bufferqueue@1.0", + "android.hardware.graphics.bufferqueue@2.0", + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + "android.hardware.media.bufferpool@2.0", + "android.hardware.media.c2@1.0", + "android.hardware.media.omx@1.0", + "android.hardware.media@1.0", + "android.hidl.base@1.0", + "android.hidl.safe_union@1.0", + ], + gen_java: false, +} diff --git a/media/c2/1.1/IComponent.hal b/media/c2/1.1/IComponent.hal new file mode 100644 index 0000000000..97382ddbac --- /dev/null +++ b/media/c2/1.1/IComponent.hal @@ -0,0 +1,72 @@ +/* + * Copyright 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. + */ + +package android.hardware.media.c2@1.1; + +import android.hardware.media.c2@1.0::IComponent; +import android.hardware.media.c2@1.0::Status; + +/** + * Interface for a Codec2 component corresponding to API level 1.0 or below. + * Components have two states: stopped and running. The running state has three + * sub-states: executing, tripped and error. + * + * All methods in `IComponent` must not block. If a method call cannot be + * completed in a timely manner, it must return `TIMED_OUT` in the return + * status. + * + * @note This is an extension of version 1.0 of `IComponent`. The purpose of the + * extension is to add support for tunneling. + */ +interface IComponent extends @1.0::IComponent { + /** + * Configures a component for a tunneled playback mode. + * + * A successful call to this method puts the component in the *tunneled* + * mode. In this mode, the output `Worklet`s returned in + * IComponentListener::onWorkDone() may not contain any buffers. The output + * buffers are passed directly to the consumer end of a buffer queue whose + * producer side is configured with the returned @p sidebandStream passed + * to IGraphicBufferProducer::setSidebandStream(). + * + * The component is initially in the non-tunneled mode by default. The + * tunneled mode can be toggled on only before the component starts + * processing. Once the component is put into the tunneled mode, it shall + * stay in the tunneled mode until and only until reset() is called. + * + * @param avSyncHwId A resource ID for hardware sync. The generator of sync + * IDs must ensure that this number is unique among all services at any + * given time. For example, if both the audio HAL and the tuner HAL + * support this feature, sync IDs from the audio HAL must not clash + * with sync IDs from the tuner HAL. + * @return status Status of the call, which may be + * - `OK` - The operation completed successfully. In this case, + * @p sidebandHandle shall not be a null handle. + * - `OMITTED` - The component does not support video tunneling. + * - `BAD_STATE` - The component is already running. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return sidebandHandle Codec-allocated sideband stream handle. This can + * be passed to IGraphicBufferProducer::setSidebandStream() to + * establish a direct channel to the consumer. + */ + configureVideoTunnel( + uint32_t avSyncHwId + ) generates ( + Status status, + handle sidebandHandle + ); +}; diff --git a/media/c2/1.1/IComponentStore.hal b/media/c2/1.1/IComponentStore.hal new file mode 100644 index 0000000000..38e0fc60be --- /dev/null +++ b/media/c2/1.1/IComponentStore.hal @@ -0,0 +1,64 @@ +/* + * Copyright 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. + */ + +package android.hardware.media.c2@1.1; + +import android.hardware.media.bufferpool@2.0::IClientManager; +import android.hardware.media.c2@1.0::IComponentListener; +import android.hardware.media.c2@1.0::IComponentStore; +import android.hardware.media.c2@1.0::Status; + +import IComponent; + +/** + * Entry point for Codec2 HAL. + * + * All methods in `IComponentStore` must not block. If a method call cannot be + * completed in a timely manner, it must return `TIMED_OUT` in the return + * status. The only exceptions are getPoolClientManager() and getConfigurable(), + * which must always return immediately. + * + * @note This is an extension of version 1.0 of `IComponentStore`. The purpose + * of the extension is to add support for tunneling. + */ +interface IComponentStore extends @1.0::IComponentStore { + /** + * Creates a component by name. + * + * @param name Name of the component to create. This must match one of the + * names returned by listComponents(). + * @param listener Callback receiver. + * @param pool `IClientManager` object of the BufferPool in the client + * process. This may be null if the client does not own a BufferPool. + * @return status Status of the call, which may be + * - `OK` - The component was created successfully. + * - `NOT_FOUND` - There is no component with the given name. + * - `NO_MEMORY` - Not enough memory to create the component. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return comp The created component if @p status is `OK`. + * + * @sa IComponentListener. + */ + createComponent_1_1( + string name, + IComponentListener listener, + IClientManager pool + ) generates ( + Status status, + IComponent comp + ); +}; From 4ffd6b6152ec4a7de10de58c56cb4fc36e4b8ba7 Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Thu, 14 Nov 2019 08:05:57 -0700 Subject: [PATCH 0250/1022] Add hashes for Keymaster 4.1 KM4.1 is actually landing in AOSP, but it creates a merge conflict. This is to deconflict the merge. Test: N/A Change-Id: If0705662121c91f7f4a5753bba9e2f9a07890686 --- current.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/current.txt b/current.txt index b81aca2cf6..dc2e6b07f1 100644 --- a/current.txt +++ b/current.txt @@ -594,6 +594,9 @@ f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardwar ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types +c228aaa27f66c48e147159a4f4996c5273191fece1b08de31bd171c61334855e android.hardware.keymaster@4.1::IKeymasterDevice +adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardware.keymaster@4.1::IOperation +7a04ea5595ed418ca3e91c28b8bd7353dd988be9be7b0c8c9e64fb4b77bd4523 android.hardware.keymaster@4.1::types 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice 4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback From ad2b44760de163e4d2104c74ec64e37f37723ff3 Mon Sep 17 00:00:00 2001 From: Zongheng Wang Date: Fri, 15 Nov 2019 20:40:33 +0000 Subject: [PATCH 0251/1022] Revert "Wifi: Support check on device capability for 6GHZ" This reverts commit 046257fd2e916ced9a16596d66e003402b90dce2. Reason for revert: b/144576287 broke git_master Change-Id: I357df4a242a3ae22c793f8f4120199f04cbcdfa2 --- wifi/1.4/Android.bp | 1 - wifi/1.4/IWifiStaIface.hal | 50 --------------- wifi/1.4/default/hidl_struct_util.cpp | 9 +-- wifi/1.4/default/hidl_struct_util.h | 3 +- wifi/1.4/default/wifi_legacy_hal.cpp | 2 +- wifi/1.4/default/wifi_sta_iface.cpp | 51 ++++++--------- wifi/1.4/default/wifi_sta_iface.h | 7 +-- .../functional/wifi_sta_iface_hidl_test.cpp | 62 ------------------- 8 files changed, 27 insertions(+), 158 deletions(-) delete mode 100644 wifi/1.4/IWifiStaIface.hal delete mode 100644 wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp diff --git a/wifi/1.4/Android.bp b/wifi/1.4/Android.bp index 5750e426ad..e19785967a 100644 --- a/wifi/1.4/Android.bp +++ b/wifi/1.4/Android.bp @@ -13,7 +13,6 @@ hidl_interface { "IWifiChip.hal", "IWifiRttController.hal", "IWifiRttControllerEventCallback.hal", - "IWifiStaIface.hal", ], interfaces: [ "android.hardware.wifi@1.0", diff --git a/wifi/1.4/IWifiStaIface.hal b/wifi/1.4/IWifiStaIface.hal deleted file mode 100644 index fb658cd37c..0000000000 --- a/wifi/1.4/IWifiStaIface.hal +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 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. - */ - -package android.hardware.wifi@1.4; - -import @1.0::WifiStatus; -import @1.0::MacAddress; -import @1.0::IWifiStaIface; -import @1.3::IWifiStaIface; - -/** - * Interface used to represent a single STA iface. - * - * IWifiChip.createStaIface() may return a @1.4::IWifiStaIface when supported. - */ -interface IWifiStaIface extends @1.3::IWifiStaIface { - - enum StaIfaceCapabilityMask : @1.0::IWifiStaIface.StaIfaceCapabilityMask { - STA_6G = 1 << 15 - }; - - /** - * Get the capabilities supported by this STA iface. - * - * @return status WifiStatus of the operation. - * Possible status codes: - * |WifiStatusCode.SUCCESS|, - * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|, - * |WifiStatusCode.ERROR_NOT_AVAILABLE|, - * |WifiStatusCode.ERROR_NOT_SUPPORTED|, - * |WifiStatusCode.ERROR_UNKNOWN| - * @return capabilities Bitset of |StaIfaceCapabilityMask| values. - */ - getCapabilities_1_4() - generates (WifiStatus status, - bitfield capabilities); -}; diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp index 13a09f3438..61f311ec24 100644 --- a/wifi/1.4/default/hidl_struct_util.cpp +++ b/wifi/1.4/default/hidl_struct_util.cpp @@ -91,7 +91,7 @@ V1_3::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability( } IWifiStaIface::StaIfaceCapabilityMask -convertLegacyFeatureToHidlStaIfaceCapability(uint64_t feature) { +convertLegacyFeatureToHidlStaIfaceCapability(uint32_t feature) { using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask; switch (feature) { case WIFI_FEATURE_GSCAN: @@ -120,8 +120,6 @@ convertLegacyFeatureToHidlStaIfaceCapability(uint64_t feature) { return HidlStaIfaceCaps::ND_OFFLOAD; case WIFI_FEATURE_MKEEP_ALIVE: return HidlStaIfaceCaps::KEEP_ALIVE; - case WIFI_FEATURE_INFRA_6G: - return HidlStaIfaceCaps::STA_6G; }; CHECK(false) << "Unknown legacy feature: " << feature; return {}; @@ -367,7 +365,7 @@ bool convertLegacyWifiMacInfosToHidl( } bool convertLegacyFeaturesToHidlStaCapabilities( - uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set, + uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set, uint32_t* hidl_caps) { if (!hidl_caps) { return false; @@ -386,8 +384,7 @@ bool convertLegacyFeaturesToHidlStaCapabilities( WIFI_FEATURE_IE_WHITELIST, WIFI_FEATURE_SCAN_RAND, WIFI_FEATURE_INFRA_5G, WIFI_FEATURE_HOTSPOT, WIFI_FEATURE_PNO, WIFI_FEATURE_TDLS, WIFI_FEATURE_TDLS_OFFCHANNEL, - WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE, - WIFI_FEATURE_INFRA_6G}) { + WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE}) { if (feature & legacy_feature_set) { *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature); } diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h index cfaa4adccc..a99c1ac051 100644 --- a/wifi/1.4/default/hidl_struct_util.h +++ b/wifi/1.4/default/hidl_struct_util.h @@ -25,7 +25,6 @@ #include #include #include -#include #include #include "wifi_legacy_hal.h" @@ -70,7 +69,7 @@ bool convertLegacyWifiMacInfosToHidl( // STA iface conversion methods. bool convertLegacyFeaturesToHidlStaCapabilities( - uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set, + uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set, uint32_t* hidl_caps); bool convertLegacyApfCapabilitiesToHidl( const legacy_hal::PacketFilterCapabilities& legacy_caps, diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp index ae3c447a01..8139253272 100644 --- a/wifi/1.4/default/wifi_legacy_hal.cpp +++ b/wifi/1.4/default/wifi_legacy_hal.cpp @@ -479,7 +479,7 @@ WifiLegacyHal::requestFirmwareMemoryDump(const std::string& iface_name) { std::pair WifiLegacyHal::getSupportedFeatureSet( const std::string& iface_name) { feature_set set; - static_assert(sizeof(set) == sizeof(uint64_t), + static_assert(sizeof(set) == sizeof(uint32_t), "Some feature_flags can not be represented in output"); wifi_error status = global_func_table_.wifi_get_supported_feature_set( getIfaceHandle(iface_name), &set); diff --git a/wifi/1.4/default/wifi_sta_iface.cpp b/wifi/1.4/default/wifi_sta_iface.cpp index 8e1ada1032..3e0127ed2a 100644 --- a/wifi/1.4/default/wifi_sta_iface.cpp +++ b/wifi/1.4/default/wifi_sta_iface.cpp @@ -266,13 +266,6 @@ Return WifiStaIface::getFactoryMacAddress( hidl_status_cb); } -Return WifiStaIface::getCapabilities_1_4( - getCapabilities_cb hidl_status_cb) { - return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, - &WifiStaIface::getCapabilitiesInternal_1_4, - hidl_status_cb); -} - std::pair WifiStaIface::getNameInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_}; } @@ -290,7 +283,26 @@ WifiStatus WifiStaIface::registerEventCallbackInternal( } std::pair WifiStaIface::getCapabilitiesInternal() { - return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0}; + legacy_hal::wifi_error legacy_status; + uint32_t legacy_feature_set; + std::tie(legacy_status, legacy_feature_set) = + legacy_hal_.lock()->getSupportedFeatureSet(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {createWifiStatusFromLegacyError(legacy_status), 0}; + } + uint32_t legacy_logger_feature_set; + std::tie(legacy_status, legacy_logger_feature_set) = + legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + // some devices don't support querying logger feature set + legacy_logger_feature_set = 0; + } + uint32_t hidl_caps; + if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities( + legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) { + return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0}; + } + return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps}; } std::pair @@ -628,29 +640,6 @@ WifiStaIface::getFactoryMacAddressInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), mac}; } -std::pair WifiStaIface::getCapabilitiesInternal_1_4() { - legacy_hal::wifi_error legacy_status; - uint64_t legacy_feature_set; - std::tie(legacy_status, legacy_feature_set) = - legacy_hal_.lock()->getSupportedFeatureSet(ifname_); - if (legacy_status != legacy_hal::WIFI_SUCCESS) { - return {createWifiStatusFromLegacyError(legacy_status), 0}; - } - uint32_t legacy_logger_feature_set; - std::tie(legacy_status, legacy_logger_feature_set) = - legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_); - if (legacy_status != legacy_hal::WIFI_SUCCESS) { - // some devices don't support querying logger feature set - legacy_logger_feature_set = 0; - } - uint32_t hidl_caps; - if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities( - legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) { - return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0}; - } - return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps}; -} - } // namespace implementation } // namespace V1_4 } // namespace wifi diff --git a/wifi/1.4/default/wifi_sta_iface.h b/wifi/1.4/default/wifi_sta_iface.h index ccf234f98e..d8f7a01ade 100644 --- a/wifi/1.4/default/wifi_sta_iface.h +++ b/wifi/1.4/default/wifi_sta_iface.h @@ -19,7 +19,7 @@ #include #include -#include +#include #include "hidl_callback_util.h" #include "wifi_iface_util.h" @@ -35,7 +35,7 @@ using namespace android::hardware::wifi::V1_0; /** * HIDL interface object used to control a STA Iface instance. */ -class WifiStaIface : public V1_4::IWifiStaIface { +class WifiStaIface : public V1_3::IWifiStaIface { public: WifiStaIface(const std::string& ifname, const std::weak_ptr legacy_hal, @@ -111,8 +111,6 @@ class WifiStaIface : public V1_4::IWifiStaIface { setMacAddress_cb hidl_status_cb) override; Return getFactoryMacAddress( getFactoryMacAddress_cb hidl_status_cb) override; - Return getCapabilities_1_4( - getCapabilities_1_4_cb hidl_status_cb) override; private: // Corresponding worker functions for the HIDL methods. @@ -161,7 +159,6 @@ class WifiStaIface : public V1_4::IWifiStaIface { WifiStatus setMacAddressInternal(const std::array& mac); std::pair> getFactoryMacAddressInternal(); - std::pair getCapabilitiesInternal_1_4(); std::string ifname_; std::weak_ptr legacy_hal_; diff --git a/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp deleted file mode 100644 index ec4b2c949d..0000000000 --- a/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Staache 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 - -#include - -#include "wifi_hidl_call_util.h" -#include "wifi_hidl_test_utils.h" - -using ::android::sp; -using ::android::hardware::hidl_array; -using ::android::hardware::wifi::V1_0::WifiStatus; -using ::android::hardware::wifi::V1_0::WifiStatusCode; -using ::android::hardware::wifi::V1_4::IWifiStaIface; - -/** - * Fixture to use for all STA Iface HIDL interface tests. - */ -class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { - public: - virtual void SetUp() override { - wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface()); - ASSERT_NE(nullptr, wifi_sta_iface_.get()); - } - - virtual void TearDown() override { stopWifi(); } - - protected: - sp wifi_sta_iface_; -}; - -/* - * GetCapabilities_1_4 - */ -TEST_F(WifiStaIfaceHidlTest, GetCapabilities_1_4) { - configureChipForIfaceType(IfaceType::STA, true); - - const auto& status_and_caps = - HIDL_INVOKE(wifi_sta_iface_, getCapabilities_1_4); - if (status_and_caps.first.code != WifiStatusCode::SUCCESS) { - EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, - status_and_caps.first.code); - return; - } - EXPECT_NE(0u, status_and_caps.second); -} From 95e36b70351dbd1c2ad285547eaa8d2d06fdcab2 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Fri, 15 Nov 2019 21:24:53 +0000 Subject: [PATCH 0252/1022] Revert "Revert "Wifi: Support check on device capability for 6GHZ"" This reverts commit ad2b44760de163e4d2104c74ec64e37f37723ff3. Reason for revert: Fix is ready Change-Id: I16e30afe843e048429eae430a82aa5e90e591c2e --- wifi/1.4/Android.bp | 1 + wifi/1.4/IWifiStaIface.hal | 50 +++++++++++++++ wifi/1.4/default/hidl_struct_util.cpp | 9 ++- wifi/1.4/default/hidl_struct_util.h | 3 +- wifi/1.4/default/wifi_legacy_hal.cpp | 2 +- wifi/1.4/default/wifi_sta_iface.cpp | 51 +++++++++------ wifi/1.4/default/wifi_sta_iface.h | 7 ++- .../functional/wifi_sta_iface_hidl_test.cpp | 62 +++++++++++++++++++ 8 files changed, 158 insertions(+), 27 deletions(-) create mode 100644 wifi/1.4/IWifiStaIface.hal create mode 100644 wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp diff --git a/wifi/1.4/Android.bp b/wifi/1.4/Android.bp index e19785967a..5750e426ad 100644 --- a/wifi/1.4/Android.bp +++ b/wifi/1.4/Android.bp @@ -13,6 +13,7 @@ hidl_interface { "IWifiChip.hal", "IWifiRttController.hal", "IWifiRttControllerEventCallback.hal", + "IWifiStaIface.hal", ], interfaces: [ "android.hardware.wifi@1.0", diff --git a/wifi/1.4/IWifiStaIface.hal b/wifi/1.4/IWifiStaIface.hal new file mode 100644 index 0000000000..fb658cd37c --- /dev/null +++ b/wifi/1.4/IWifiStaIface.hal @@ -0,0 +1,50 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi@1.4; + +import @1.0::WifiStatus; +import @1.0::MacAddress; +import @1.0::IWifiStaIface; +import @1.3::IWifiStaIface; + +/** + * Interface used to represent a single STA iface. + * + * IWifiChip.createStaIface() may return a @1.4::IWifiStaIface when supported. + */ +interface IWifiStaIface extends @1.3::IWifiStaIface { + + enum StaIfaceCapabilityMask : @1.0::IWifiStaIface.StaIfaceCapabilityMask { + STA_6G = 1 << 15 + }; + + /** + * Get the capabilities supported by this STA iface. + * + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|, + * |WifiStatusCode.ERROR_NOT_AVAILABLE|, + * |WifiStatusCode.ERROR_NOT_SUPPORTED|, + * |WifiStatusCode.ERROR_UNKNOWN| + * @return capabilities Bitset of |StaIfaceCapabilityMask| values. + */ + getCapabilities_1_4() + generates (WifiStatus status, + bitfield capabilities); +}; diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp index 61f311ec24..13a09f3438 100644 --- a/wifi/1.4/default/hidl_struct_util.cpp +++ b/wifi/1.4/default/hidl_struct_util.cpp @@ -91,7 +91,7 @@ V1_3::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability( } IWifiStaIface::StaIfaceCapabilityMask -convertLegacyFeatureToHidlStaIfaceCapability(uint32_t feature) { +convertLegacyFeatureToHidlStaIfaceCapability(uint64_t feature) { using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask; switch (feature) { case WIFI_FEATURE_GSCAN: @@ -120,6 +120,8 @@ convertLegacyFeatureToHidlStaIfaceCapability(uint32_t feature) { return HidlStaIfaceCaps::ND_OFFLOAD; case WIFI_FEATURE_MKEEP_ALIVE: return HidlStaIfaceCaps::KEEP_ALIVE; + case WIFI_FEATURE_INFRA_6G: + return HidlStaIfaceCaps::STA_6G; }; CHECK(false) << "Unknown legacy feature: " << feature; return {}; @@ -365,7 +367,7 @@ bool convertLegacyWifiMacInfosToHidl( } bool convertLegacyFeaturesToHidlStaCapabilities( - uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set, + uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set, uint32_t* hidl_caps) { if (!hidl_caps) { return false; @@ -384,7 +386,8 @@ bool convertLegacyFeaturesToHidlStaCapabilities( WIFI_FEATURE_IE_WHITELIST, WIFI_FEATURE_SCAN_RAND, WIFI_FEATURE_INFRA_5G, WIFI_FEATURE_HOTSPOT, WIFI_FEATURE_PNO, WIFI_FEATURE_TDLS, WIFI_FEATURE_TDLS_OFFCHANNEL, - WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE}) { + WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE, + WIFI_FEATURE_INFRA_6G}) { if (feature & legacy_feature_set) { *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature); } diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h index a99c1ac051..cfaa4adccc 100644 --- a/wifi/1.4/default/hidl_struct_util.h +++ b/wifi/1.4/default/hidl_struct_util.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "wifi_legacy_hal.h" @@ -69,7 +70,7 @@ bool convertLegacyWifiMacInfosToHidl( // STA iface conversion methods. bool convertLegacyFeaturesToHidlStaCapabilities( - uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set, + uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set, uint32_t* hidl_caps); bool convertLegacyApfCapabilitiesToHidl( const legacy_hal::PacketFilterCapabilities& legacy_caps, diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp index 8139253272..ae3c447a01 100644 --- a/wifi/1.4/default/wifi_legacy_hal.cpp +++ b/wifi/1.4/default/wifi_legacy_hal.cpp @@ -479,7 +479,7 @@ WifiLegacyHal::requestFirmwareMemoryDump(const std::string& iface_name) { std::pair WifiLegacyHal::getSupportedFeatureSet( const std::string& iface_name) { feature_set set; - static_assert(sizeof(set) == sizeof(uint32_t), + static_assert(sizeof(set) == sizeof(uint64_t), "Some feature_flags can not be represented in output"); wifi_error status = global_func_table_.wifi_get_supported_feature_set( getIfaceHandle(iface_name), &set); diff --git a/wifi/1.4/default/wifi_sta_iface.cpp b/wifi/1.4/default/wifi_sta_iface.cpp index 3e0127ed2a..8e1ada1032 100644 --- a/wifi/1.4/default/wifi_sta_iface.cpp +++ b/wifi/1.4/default/wifi_sta_iface.cpp @@ -266,6 +266,13 @@ Return WifiStaIface::getFactoryMacAddress( hidl_status_cb); } +Return WifiStaIface::getCapabilities_1_4( + getCapabilities_cb hidl_status_cb) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::getCapabilitiesInternal_1_4, + hidl_status_cb); +} + std::pair WifiStaIface::getNameInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_}; } @@ -283,26 +290,7 @@ WifiStatus WifiStaIface::registerEventCallbackInternal( } std::pair WifiStaIface::getCapabilitiesInternal() { - legacy_hal::wifi_error legacy_status; - uint32_t legacy_feature_set; - std::tie(legacy_status, legacy_feature_set) = - legacy_hal_.lock()->getSupportedFeatureSet(ifname_); - if (legacy_status != legacy_hal::WIFI_SUCCESS) { - return {createWifiStatusFromLegacyError(legacy_status), 0}; - } - uint32_t legacy_logger_feature_set; - std::tie(legacy_status, legacy_logger_feature_set) = - legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_); - if (legacy_status != legacy_hal::WIFI_SUCCESS) { - // some devices don't support querying logger feature set - legacy_logger_feature_set = 0; - } - uint32_t hidl_caps; - if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities( - legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) { - return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0}; - } - return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps}; + return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0}; } std::pair @@ -640,6 +628,29 @@ WifiStaIface::getFactoryMacAddressInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), mac}; } +std::pair WifiStaIface::getCapabilitiesInternal_1_4() { + legacy_hal::wifi_error legacy_status; + uint64_t legacy_feature_set; + std::tie(legacy_status, legacy_feature_set) = + legacy_hal_.lock()->getSupportedFeatureSet(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {createWifiStatusFromLegacyError(legacy_status), 0}; + } + uint32_t legacy_logger_feature_set; + std::tie(legacy_status, legacy_logger_feature_set) = + legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + // some devices don't support querying logger feature set + legacy_logger_feature_set = 0; + } + uint32_t hidl_caps; + if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities( + legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) { + return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0}; + } + return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps}; +} + } // namespace implementation } // namespace V1_4 } // namespace wifi diff --git a/wifi/1.4/default/wifi_sta_iface.h b/wifi/1.4/default/wifi_sta_iface.h index d8f7a01ade..ccf234f98e 100644 --- a/wifi/1.4/default/wifi_sta_iface.h +++ b/wifi/1.4/default/wifi_sta_iface.h @@ -19,7 +19,7 @@ #include #include -#include +#include #include "hidl_callback_util.h" #include "wifi_iface_util.h" @@ -35,7 +35,7 @@ using namespace android::hardware::wifi::V1_0; /** * HIDL interface object used to control a STA Iface instance. */ -class WifiStaIface : public V1_3::IWifiStaIface { +class WifiStaIface : public V1_4::IWifiStaIface { public: WifiStaIface(const std::string& ifname, const std::weak_ptr legacy_hal, @@ -111,6 +111,8 @@ class WifiStaIface : public V1_3::IWifiStaIface { setMacAddress_cb hidl_status_cb) override; Return getFactoryMacAddress( getFactoryMacAddress_cb hidl_status_cb) override; + Return getCapabilities_1_4( + getCapabilities_1_4_cb hidl_status_cb) override; private: // Corresponding worker functions for the HIDL methods. @@ -159,6 +161,7 @@ class WifiStaIface : public V1_3::IWifiStaIface { WifiStatus setMacAddressInternal(const std::array& mac); std::pair> getFactoryMacAddressInternal(); + std::pair getCapabilitiesInternal_1_4(); std::string ifname_; std::weak_ptr legacy_hal_; diff --git a/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp new file mode 100644 index 0000000000..ec4b2c949d --- /dev/null +++ b/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Staache 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 + +#include + +#include "wifi_hidl_call_util.h" +#include "wifi_hidl_test_utils.h" + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::wifi::V1_0::WifiStatus; +using ::android::hardware::wifi::V1_0::WifiStatusCode; +using ::android::hardware::wifi::V1_4::IWifiStaIface; + +/** + * Fixture to use for all STA Iface HIDL interface tests. + */ +class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface()); + ASSERT_NE(nullptr, wifi_sta_iface_.get()); + } + + virtual void TearDown() override { stopWifi(); } + + protected: + sp wifi_sta_iface_; +}; + +/* + * GetCapabilities_1_4 + */ +TEST_F(WifiStaIfaceHidlTest, GetCapabilities_1_4) { + configureChipForIfaceType(IfaceType::STA, true); + + const auto& status_and_caps = + HIDL_INVOKE(wifi_sta_iface_, getCapabilities_1_4); + if (status_and_caps.first.code != WifiStatusCode::SUCCESS) { + EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, + status_and_caps.first.code); + return; + } + EXPECT_NE(0u, status_and_caps.second); +} From e3c8d131b9f0b8a797620432cef2afe244d7ee58 Mon Sep 17 00:00:00 2001 From: Shuo Qian Date: Fri, 15 Nov 2019 18:55:43 -0800 Subject: [PATCH 0253/1022] Fix a mistake in the RSSNR range. Test: build Bug: 135717625 Change-Id: I2e7db25d6f9abb142f8c113d4f1d9666defe6be4 --- current.txt | 2 +- radio/1.5/types.hal | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/current.txt b/current.txt index 26de8ffb0e..bc91af5e1d 100644 --- a/current.txt +++ b/current.txt @@ -607,7 +607,7 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar 619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types -ba759fab7dd4cd621b492ef8f44312d4a716af786786f404d1477cc8cea6f392 android.hardware.radio@1.5::types +274fb1254a6d1a97824ec5c880eeefc0e410dc6d3a2a4c34052201169d2b7de0 android.hardware.radio@1.5::types c8e81d912827a5d49b2ddcdc4eb4556c5d231a899a1dca879309e04210daa4a0 android.hardware.radio@1.5::IRadio a62a93faf173b14a6175b683ebf61ffa568dc61f81e369d2dce7b1265e86cf2f android.hardware.radio@1.5::IRadioIndication 260ce05806d753d728f844d405e832179ed7d9b65986ec18fef3d21cf7285587 android.hardware.radio@1.5::IRadioResponse diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index 9ef1d3180c..2441b65178 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -52,7 +52,7 @@ enum SignalMeasurementType : int32_t { RSRQ = 4, /** * Reference Signal Signal to Noise Ratio - * Range: -20 dB to -30 dB; + * Range: -20 dB to 30 dB; * Used RAN: EUTRAN * Note: this field is optional; how to support it can be decided by the * corresponding vendor. Though the response code is not enforced, From c88f4c60a8564809231cea78734396f8d79b98f3 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Thu, 3 Oct 2019 14:43:18 +0100 Subject: [PATCH 0254/1022] Add quantization coupling test Quantization coupling test is ran only on models that contain only one operator and at least one of its inputs has a type of TENSOR_QUANT8_ASYMM. The test verifies that a model with all the operands converted to TENSOR_QUANT8_ASYMM_SIGNED will produce the same result (OK/SKIPPED/FAILED). Bug: 137828994 Test: VtsHalNeuralNetworksV1_3TargetTest --gtest_filter="*QuantizationCouplingTest*" Change-Id: I5a2e09b2b1bd790e7e37dde133554e516155a34d --- .../functional/CompilationCachingTests.cpp | 42 ++--- .../vts/functional/GeneratedTestHarness.cpp | 150 +++++++++++++++--- .../1.3/vts/functional/GeneratedTestHarness.h | 13 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 5 +- .../1.3/vts/functional/VtsHalNeuralnetworks.h | 2 +- 5 files changed, 160 insertions(+), 52 deletions(-) diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp index d8a7534461..60992d57d7 100644 --- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp @@ -456,8 +456,7 @@ TEST_P(CompilationCachingTest, CacheSavingAndRetrieval) { } // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); } TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) { @@ -519,8 +518,7 @@ TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) { } // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); } TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { @@ -541,8 +539,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -566,8 +563,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -590,8 +586,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -615,8 +610,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -727,8 +721,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -752,8 +745,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -776,8 +768,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -801,8 +792,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -914,8 +904,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -937,8 +926,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -1082,8 +1070,7 @@ TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) { ASSERT_EQ(preparedModel, nullptr); } else { ASSERT_NE(preparedModel, nullptr); - EvaluatePreparedModel(preparedModel, testModelAdd, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModelAdd, /*testKind=*/TestKind::GENERAL); } } } @@ -1144,8 +1131,7 @@ TEST_P(CompilationCachingTest, PrepareFromCache_TOCTOU) { ASSERT_EQ(preparedModel, nullptr); } else { ASSERT_NE(preparedModel, nullptr); - EvaluatePreparedModel(preparedModel, testModelAdd, - /*testDynamicOutputShape=*/false); + EvaluatePreparedModel(preparedModel, testModelAdd, /*testKind=*/TestKind::GENERAL); } } } diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 2ec29887df..3e947f5163 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -79,6 +79,21 @@ struct TestConfig { Executor executor; MeasureTiming measureTiming; OutputType outputType; + // `reportSkipping` indicates if a test should print an info message in case + // it is skipped. The field is set to true by default and is set to false in + // quantization coupling tests to suppress skipping a test + bool reportSkipping; + TestConfig(Executor executor, MeasureTiming measureTiming, OutputType outputType) + : executor(executor), + measureTiming(measureTiming), + outputType(outputType), + reportSkipping(true) {} + TestConfig(Executor executor, MeasureTiming measureTiming, OutputType outputType, + bool reportSkipping) + : executor(executor), + measureTiming(measureTiming), + outputType(outputType), + reportSkipping(reportSkipping) {} }; } // namespace @@ -219,7 +234,10 @@ static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst( } void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel, - const TestConfig& testConfig) { + const TestConfig& testConfig, bool* skipped = nullptr) { + if (skipped != nullptr) { + *skipped = false; + } // If output0 does not have size larger than one byte, we can not test with insufficient buffer. if (testConfig.outputType == OutputType::INSUFFICIENT && !isOutputSizeGreaterThanOne(testModel, 0)) { @@ -290,6 +308,12 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo if (testConfig.outputType != OutputType::FULLY_SPECIFIED && executionStatus == ErrorStatus::GENERAL_FAILURE) { + if (skipped != nullptr) { + *skipped = true; + } + if (!testConfig.reportSkipping) { + return; + } LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " "execute model that it does not support."; std::cout << "[ ] Early termination of test because vendor service cannot " @@ -343,44 +367,117 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo } void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel, - bool testDynamicOutputShape) { + TestKind testKind) { std::initializer_list outputTypesList; std::initializer_list measureTimingList; std::initializer_list executorList; - if (testDynamicOutputShape) { - outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT}; - measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; - executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; - } else { - outputTypesList = {OutputType::FULLY_SPECIFIED}; - measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; - executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; + switch (testKind) { + case TestKind::GENERAL: { + outputTypesList = {OutputType::FULLY_SPECIFIED}; + measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; + executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; + } break; + case TestKind::DYNAMIC_SHAPE: { + outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT}; + measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; + executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; + } break; + case TestKind::QUANTIZATION_COUPLING: { + LOG(FATAL) << "Wrong TestKind for EvaluatePreparedModel"; + return; + } break; } for (const OutputType outputType : outputTypesList) { for (const MeasureTiming measureTiming : measureTimingList) { for (const Executor executor : executorList) { - const TestConfig testConfig = {.executor = executor, - .measureTiming = measureTiming, - .outputType = outputType}; + const TestConfig testConfig(executor, measureTiming, outputType); EvaluatePreparedModel(preparedModel, testModel, testConfig); } } } } -void Execute(const sp& device, const TestModel& testModel, bool testDynamicOutputShape) { +void EvaluatePreparedCoupledModels(const sp& preparedModel, + const TestModel& testModel, + const sp& preparedCoupledModel, + const TestModel& coupledModel) { + std::initializer_list outputTypesList = {OutputType::FULLY_SPECIFIED}; + std::initializer_list measureTimingList = {MeasureTiming::NO, + MeasureTiming::YES}; + std::initializer_list executorList = {Executor::ASYNC, Executor::SYNC, + Executor::BURST}; + + for (const OutputType outputType : outputTypesList) { + for (const MeasureTiming measureTiming : measureTimingList) { + for (const Executor executor : executorList) { + const TestConfig testConfig(executor, measureTiming, outputType, + /*reportSkipping=*/false); + bool baseSkipped = false; + EvaluatePreparedModel(preparedModel, testModel, testConfig, &baseSkipped); + bool coupledSkipped = false; + EvaluatePreparedModel(preparedCoupledModel, coupledModel, testConfig, + &coupledSkipped); + ASSERT_EQ(baseSkipped, coupledSkipped); + if (baseSkipped) { + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " + "execute model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service " + "cannot " + "execute model that it does not support." + << std::endl; + GTEST_SKIP(); + } + } + } + } +} + +void Execute(const sp& device, const TestModel& testModel, TestKind testKind) { Model model = createModel(testModel); - if (testDynamicOutputShape) { + if (testKind == TestKind::DYNAMIC_SHAPE) { makeOutputDimensionsUnspecified(&model); } sp preparedModel; - createPreparedModel(device, model, &preparedModel); - if (preparedModel == nullptr) return; - - EvaluatePreparedModel(preparedModel, testModel, testDynamicOutputShape); + switch (testKind) { + case TestKind::GENERAL: { + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; + EvaluatePreparedModel(preparedModel, testModel, TestKind::GENERAL); + } break; + case TestKind::DYNAMIC_SHAPE: { + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; + EvaluatePreparedModel(preparedModel, testModel, TestKind::DYNAMIC_SHAPE); + } break; + case TestKind::QUANTIZATION_COUPLING: { + ASSERT_TRUE(testModel.hasQuant8AsymmOperands()); + createPreparedModel(device, model, &preparedModel, /*reportSkipping*/ false); + TestModel signedQuantizedModel = convertQuant8AsymmOperandsToSigned(testModel); + sp preparedCoupledModel; + createPreparedModel(device, createModel(signedQuantizedModel), &preparedCoupledModel, + /*reportSkipping*/ false); + // If we couldn't prepare a model with unsigned quantization, we must + // fail to prepare a model with signed quantization as well. + if (preparedModel == nullptr) { + ASSERT_EQ(preparedCoupledModel, nullptr); + // If we failed to prepare both of the models, we can safely skip + // the test. + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " + "prepare model that it does not support."; + std::cout + << "[ ] Early termination of test because vendor service cannot " + "prepare model that it does not support." + << std::endl; + GTEST_SKIP(); + } + ASSERT_NE(preparedCoupledModel, nullptr); + EvaluatePreparedCoupledModels(preparedModel, testModel, preparedCoupledModel, + signedQuantizedModel); + } break; + } } void GeneratedTestBase::SetUp() { @@ -403,12 +500,19 @@ class GeneratedTest : public GeneratedTestBase {}; // Tag for the dynamic output shape tests class DynamicOutputShapeTest : public GeneratedTest {}; +// Tag for the dynamic output shape tests +class DISABLED_QuantizationCouplingTest : public GeneratedTest {}; + TEST_P(GeneratedTest, Test) { - Execute(kDevice, kTestModel, /*testDynamicOutputShape=*/false); + Execute(kDevice, kTestModel, /*testKind=*/TestKind::GENERAL); } TEST_P(DynamicOutputShapeTest, Test) { - Execute(kDevice, kTestModel, /*testDynamicOutputShape=*/true); + Execute(kDevice, kTestModel, /*testKind=*/TestKind::DYNAMIC_SHAPE); +} + +TEST_P(DISABLED_QuantizationCouplingTest, Test) { + Execute(kDevice, kTestModel, /*testKind=*/TestKind::QUANTIZATION_COUPLING); } INSTANTIATE_GENERATED_TEST(GeneratedTest, @@ -417,4 +521,8 @@ INSTANTIATE_GENERATED_TEST(GeneratedTest, INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); +INSTANTIATE_GENERATED_TEST(DISABLED_QuantizationCouplingTest, [](const TestModel& testModel) { + return testModel.hasQuant8AsymmOperands() && testModel.operations.size() == 1; +}); + } // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h index 45cff5b75b..ad6323f48c 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h @@ -57,8 +57,19 @@ Model createModel(const test_helper::TestModel& testModel); void PrepareModel(const sp& device, const Model& model, sp* preparedModel); +enum class TestKind { + // Runs a test model and compares the results to a golden data + GENERAL, + // Same as GENERAL but sets dimensions for the output tensors to zeros + DYNAMIC_SHAPE, + // Tests if quantized model with TENSOR_QUANT8_ASYMM produces the same result + // (OK/SKIPPED/FAILED) as the model with all such tensors converted to + // TENSOR_QUANT8_ASYMM_SIGNED. + QUANTIZATION_COUPLING +}; + void EvaluatePreparedModel(const sp& preparedModel, - const test_helper::TestModel& testModel, bool testDynamicOutputShape); + const test_helper::TestModel& testModel, TestKind testKind); } // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index 625913d485..92d8fa7376 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -37,7 +37,7 @@ using V1_1::ExecutionPreference; // internal helper function void createPreparedModel(const sp& device, const Model& model, - sp* preparedModel) { + sp* preparedModel, bool reportSkipping) { ASSERT_NE(nullptr, preparedModel); *preparedModel = nullptr; @@ -74,6 +74,9 @@ void createPreparedModel(const sp& device, const Model& model, // can continue. if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { ASSERT_EQ(nullptr, preparedModel->get()); + if (!reportSkipping) { + return; + } LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot prepare " "model that it does not support."; std::cout << "[ ] Early termination of test because vendor service cannot " diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h index 8cb42d47e5..4e51052966 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h @@ -47,7 +47,7 @@ std::string printNeuralnetworksHidlTest( // Create an IPreparedModel object. If the model cannot be prepared, // "preparedModel" will be nullptr instead. void createPreparedModel(const sp& device, const Model& model, - sp* preparedModel); + sp* preparedModel, bool reportSkipping = true); // Utility function to get PreparedModel from callback and downcast to V1_2. sp getPreparedModel_1_3(const sp& callback); From 04bf939c7ad760457bb811dafd5ac362624c0ad0 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Fri, 1 Nov 2019 17:24:02 +0000 Subject: [PATCH 0255/1022] Add QUANT8_ASYMM_SIGNED support to SELECT op Also fix repo hook complaining about comment formatting. Bug: 143935354 Test: NNTest_static and VTS_1_3 with --gtest_filter="*QuantizationCouplingTest*select*" Change-Id: I1b0d1e987ebccc6700dd172b4222f9996105513d --- current.txt | 4 ++-- neuralnetworks/1.2/types.hal | 11 ++++++----- neuralnetworks/1.3/types.hal | 15 +++++++++------ 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/current.txt b/current.txt index b81aca2cf6..4903992613 100644 --- a/current.txt +++ b/current.txt @@ -579,7 +579,7 @@ f1109cbb10297b7429a11fab42afa912710b303c9bf20bd5cdb8bd57b9c84186 android.hardwar 9d8ee57c490ffeaa28f702eaea8d198cb510e4bbfb99e6cb5f63e73341057c7c android.hardware.neuralnetworks@1.1::types fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice 40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel -71c0f7127335e5b74d1615d5e7f129831b43ffbae5318ad0924d7d8d8910a859 android.hardware.neuralnetworks@1.2::types +72de91c3feba4b19c159cd1c413cbea596b78240caa43e31194e20e6f5b05c49 android.hardware.neuralnetworks@1.2::types a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface @@ -597,7 +597,7 @@ db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardwar 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice 4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -c511b1427b1c3f76af90967bbddaaf250db983a8d3abb9ff189fb5a807cf3d4d android.hardware.neuralnetworks@1.3::types +554baa3b317e077b850afcbaac99daeef56861b1786540e56275a4fcad1f43e3 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant 44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal index 837ced5b48..ef71ea8712 100644 --- a/neuralnetworks/1.2/types.hal +++ b/neuralnetworks/1.2/types.hal @@ -2448,15 +2448,17 @@ enum OperationType : int32_t { * then clipping is disabled. * If all the input tensors have type {@link OperandType::TENSOR_FLOAT32}, * this scalar must be of the type {@link OperandType::FLOAT32}, - * otherwise if all the input tensors have the type {@link OperandType::TENSOR_FLOAT16}, - * this scalar must be of type {@link OperandType::FLOAT16}. + * otherwise if all the input tensors have the type + * {@link OperandType::TENSOR_FLOAT16}, this scalar must be + * of type {@link OperandType::FLOAT16}. * * 50: The clipping threshold for the output from the * projection layer, such that values are bound within * [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled. * If all the input tensors have type {@link OperandType::TENSOR_FLOAT32}, * this scalar must be of the type {@link OperandType::FLOAT32}, - * otherwise if all the input tensors have the type {@link OperandType::TENSOR_FLOAT16}, - * this scalar must be of type {@link OperandType::FLOAT16}. + * otherwise if all the input tensors have the type + * {@link OperandType::TENSOR_FLOAT16}, this scalar must be + * of type {@link OperandType::FLOAT16}. * * 51: merge_outputs * An {@link OperandType::BOOL} scalar specifying if the outputs * from forward and backward cells should be merged. @@ -4124,7 +4126,6 @@ enum OperationType : int32_t { * * 0: A tensor of the same type and shape as input1 and input2. * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint can be different from inputs' scale and zeroPoint. - * */ SELECT = 84, diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index 7df14b18f6..f959e45b5a 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -2375,15 +2375,17 @@ enum OperationType : int32_t { * then clipping is disabled. * If all the input tensors have type {@link OperandType::TENSOR_FLOAT32}, * this scalar must be of the type {@link OperandType::FLOAT32}, - * otherwise if all the input tensors have the type {@link OperandType::TENSOR_FLOAT16}, - * this scalar must be of type {@link OperandType::FLOAT16}. + * otherwise if all the input tensors have the type + * {@link OperandType::TENSOR_FLOAT16}, this scalar must be + * of type {@link OperandType::FLOAT16}. * * 50: The clipping threshold for the output from the * projection layer, such that values are bound within * [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled. * If all the input tensors have type {@link OperandType::TENSOR_FLOAT32}, * this scalar must be of the type {@link OperandType::FLOAT32}, - * otherwise if all the input tensors have the type {@link OperandType::TENSOR_FLOAT16}, - * this scalar must be of type {@link OperandType::FLOAT16}. + * otherwise if all the input tensors have the type + * {@link OperandType::TENSOR_FLOAT16}, this scalar must be + * of type {@link OperandType::FLOAT16}. * * 51: merge_outputs * An {@link OperandType::BOOL} scalar specifying if the outputs * from forward and backward cells should be merged. @@ -4034,6 +4036,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -4044,14 +4047,14 @@ enum OperationType : int32_t { * true) or input2 (if false). * * 1: An input tensor of the same shape as input0. * * 2: An input tensor of the same shape and type as input1. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} + * and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scales and zeroPoint can be different from input1 scale and zeroPoint. * * Outputs: * * 0: A tensor of the same type and shape as input1 and input2. * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint can be different from inputs' scale and zeroPoint. - * */ SELECT = @1.2::OperationType:SELECT, From a63b53f9a86a1898dc2d415a20ae100afd4832e9 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Mon, 18 Nov 2019 11:03:13 -0800 Subject: [PATCH 0256/1022] hal(wifi): Set HAL logd severity based on ringbuffer verbosity This avoid the framework from setting the HAL daemon's log severity when verbose logging is enabled by the user. Bug: 144695435 Test: Manually verified log level change Change-Id: I71777bb5f7cb8216bc0ecee27fbaa410c39a6a16 --- wifi/1.4/default/wifi_chip.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp index 7685ac61d9..40f73b532a 100644 --- a/wifi/1.4/default/wifi_chip.cpp +++ b/wifi/1.4/default/wifi_chip.cpp @@ -1021,6 +1021,12 @@ WifiStatus WifiChip::startLoggingToDebugRingBufferInternal( max_interval_in_sec, min_data_size_in_bytes); ringbuffer_map_.insert(std::pair( ring_name, Ringbuffer(kMaxBufferSizeBytes))); + // if verbose logging enabled, turn up HAL daemon logging as well. + if (verbose_level < WifiDebugRingBufferVerboseLevel::VERBOSE) { + android::base::SetMinimumLogSeverity(android::base::DEBUG); + } else { + android::base::SetMinimumLogSeverity(android::base::VERBOSE); + } return createWifiStatusFromLegacyError(legacy_status); } From ebd88ba8d2223a6bf06c6495500df4f654c8b398 Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Mon, 28 Oct 2019 11:11:19 -0700 Subject: [PATCH 0257/1022] NN HAL: Upgrade IPreparedModel::executeSynchronously to 1.3. Bug: 143242728 Test: 1.3 VTS with sample driver Change-Id: I4b74e8ac031c5d793cf7e5d66190734949367538 --- current.txt | 2 +- neuralnetworks/1.3/IPreparedModel.hal | 64 ++++++++++++++++++- .../vts/functional/GeneratedTestHarness.cpp | 2 +- .../1.3/vts/functional/ValidateRequest.cpp | 8 +-- 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/current.txt b/current.txt index b81aca2cf6..b46f37f2d2 100644 --- a/current.txt +++ b/current.txt @@ -595,7 +595,7 @@ ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardwar 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice -4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel +258825966435b3ed08832055bb736d81516013e405f161d9ccde9a90cfcdde83 android.hardware.neuralnetworks@1.3::IPreparedModel 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback c511b1427b1c3f76af90967bbddaaf250db983a8d3abb9ff189fb5a807cf3d4d android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal index c04809fea1..7aea4160b0 100644 --- a/neuralnetworks/1.3/IPreparedModel.hal +++ b/neuralnetworks/1.3/IPreparedModel.hal @@ -18,9 +18,11 @@ package android.hardware.neuralnetworks@1.3; import @1.0::ErrorStatus; import @1.0::Request; -import @1.2::MeasureTiming; import @1.2::IExecutionCallback; import @1.2::IPreparedModel; +import @1.2::MeasureTiming; +import @1.2::OutputShape; +import @1.2::Timing; /** * IPreparedModel describes a model that has been prepared for execution and @@ -62,8 +64,8 @@ interface IPreparedModel extends @1.2::IPreparedModel { * values, the execution should complete successfully (ErrorStatus::NONE): * There must be no failure unless the device itself is in a bad state. * - * Any number of calls to the execute, execute_1_2, execute_1_3, and executeSynchronously - * functions, in any combination, may be made concurrently, even on the same + * Any number of calls to the execute* and executeSynchronously* functions, + * in any combination, may be made concurrently, even on the same * IPreparedModel object. * * @param request The input and output information on which the prepared @@ -87,4 +89,60 @@ interface IPreparedModel extends @1.2::IPreparedModel { */ execute_1_3(Request request, MeasureTiming measure, IExecutionCallback callback) generates (ErrorStatus status); + + /** + * Performs a synchronous execution on a prepared model. + * + * The execution is performed synchronously with respect to the caller. + * executeSynchronously_1_3 must verify the inputs to the function are + * correct. If there is an error, executeSynchronously_1_3 must immediately + * return with the appropriate ErrorStatus value. If the inputs to the + * function are valid and there is no error, executeSynchronously_1_3 must + * perform the execution, and must not return until the execution is + * complete. + * + * The caller must not change the content of any data object referenced by + * 'request' (described by the {@link @1.0::DataLocation} of a + * {@link @1.0::RequestArgument}) until executeSynchronously_1_3 + * returns. executeSynchronously_1_3 must not change the content of any of the + * data objects corresponding to 'request' inputs. + * + * If the prepared model was prepared from a model wherein all tensor + * operands have fully specified dimensions, and the inputs to the function + * are valid, and at execution time every operation's input operands have + * legal values, then the execution should complete successfully + * (ErrorStatus::NONE): There must be no failure unless the device itself is + * in a bad state. + * + * Any number of calls to the execute* and executeSynchronously* functions, + * in any combination, may be made concurrently, even on the same + * IPreparedModel object. + * + * @param request The input and output information on which the prepared + * model is to be executed. + * @param measure Specifies whether or not to measure duration of the execution. + * The duration runs from the time the driver sees the call + * to the executeSynchronously_1_3 function to the time the driver + * returns from the function. + * @return status Error status of the execution, must be: + * - NONE if execution is performed successfully + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - OUTPUT_INSUFFICIENT_SIZE if at least one output + * operand buffer is not large enough to store the + * corresponding output + * - INVALID_ARGUMENT if one of the input arguments is + * invalid + * @return outputShapes A list of shape information of model output operands. + * The index into "outputShapes" corresponds to the index + * of the output operand in the Request outputs vector. + * outputShapes must be empty unless the status is either + * NONE or OUTPUT_INSUFFICIENT_SIZE. + * @return Timing Duration of execution. Unless measure is YES and status is + * NONE, all times must be reported as UINT64_MAX. A driver may + * choose to report any time as UINT64_MAX, indicating that + * measurement is not available. + */ + executeSynchronously_1_3(Request request, MeasureTiming measure) + generates (ErrorStatus status, vec outputShapes, Timing timing); }; diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index a1e04c58de..1059bded52 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -187,7 +187,7 @@ static Return ExecutePreparedModel(const sp& prepar hidl_vec* outputShapes, Timing* timing) { ErrorStatus result; - Return ret = preparedModel->executeSynchronously( + Return ret = preparedModel->executeSynchronously_1_3( request, measure, [&result, outputShapes, timing](ErrorStatus error, const hidl_vec& shapes, const Timing& time) { diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index 2cf30d54bc..8092d04bcb 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -79,9 +79,9 @@ static void validate(const sp& preparedModel, const std::string& // synchronous { - SCOPED_TRACE(message + " [executeSynchronously]"); + SCOPED_TRACE(message + " [executeSynchronously_1_3]"); - Return executeStatus = preparedModel->executeSynchronously( + Return executeStatus = preparedModel->executeSynchronously_1_3( request, measure, [](ErrorStatus error, const hidl_vec& outputShapes, const Timing& timing) { @@ -158,8 +158,8 @@ void validateRequest(const sp& preparedModel, const Request& req } void validateRequestFailure(const sp& preparedModel, const Request& request) { - SCOPED_TRACE("Expecting request to fail [executeSynchronously]"); - Return executeStatus = preparedModel->executeSynchronously( + SCOPED_TRACE("Expecting request to fail [executeSynchronously_1_3]"); + Return executeStatus = preparedModel->executeSynchronously_1_3( request, MeasureTiming::NO, [](ErrorStatus error, const hidl_vec& outputShapes, const Timing& timing) { ASSERT_NE(ErrorStatus::NONE, error); From 7623ed9258081a20a530e6b052121966e1f1f55e Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Thu, 14 Nov 2019 13:57:15 -0800 Subject: [PATCH 0258/1022] Audio V6 wrapper: IDevice|IStream|IEffect.close releases HAL resource Fixed behavior of IStream|IEffect.close to release the underlying HAL resource synchronously. This is to avoid adding artificial delays in VTS that become totally unpractical in V6. Added clarification about expected client behavior for IStream|IEffect.close w.r.t. audio data transfer. Added IDevice.close method which releases HAL device resource. Updated VTS tests to remove delays in V6. Bug: 114451103 Bug: 141989952 Test: atest VtsHalAudioV6_0TargetTest Change-Id: I439f0f923c091af2ab234d15ca847cfade341f25 --- audio/6.0/IDevice.hal | 11 +++++++++ audio/6.0/IStream.hal | 6 ++++- audio/core/all-versions/default/Device.cpp | 17 ++++++++++--- .../all-versions/default/PrimaryDevice.cpp | 11 ++++++++- audio/core/all-versions/default/StreamIn.cpp | 15 +++++++----- audio/core/all-versions/default/StreamOut.cpp | 17 +++++++------ .../default/include/core/default/Device.h | 8 ++++++- .../include/core/default/PrimaryDevice.h | 3 +++ .../default/include/core/default/StreamIn.h | 1 - .../default/include/core/default/StreamOut.h | 1 - .../4.0/AudioPrimaryHidlHalTest.cpp | 24 +++++++++---------- .../vts/functional/AudioPrimaryHidlHalTest.h | 2 ++ .../vts/functional/DeviceManager.h | 24 +++++++++++++++---- audio/effect/6.0/IEffect.hal | 5 +++- audio/effect/all-versions/default/Effect.cpp | 19 ++++++++++----- audio/effect/all-versions/default/Effect.h | 1 - 16 files changed, 120 insertions(+), 45 deletions(-) diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal index e885fe2267..520e776c21 100644 --- a/audio/6.0/IDevice.hal +++ b/audio/6.0/IDevice.hal @@ -280,4 +280,15 @@ interface IDevice { */ setConnectedState(DeviceAddress address, bool connected) generates (Result retval); + + /** + * Called by the framework to deinitialize the device and free up + * all currently allocated resources. It is recommended to close + * the device on the client side as soon as it is becomes unused. + * + * @return retval OK in case the success. + * INVALID_STATE if the device was already closed. + */ + @exit + close() generates (Result retval); }; diff --git a/audio/6.0/IStream.hal b/audio/6.0/IStream.hal index 451e1162bf..1f62017cae 100644 --- a/audio/6.0/IStream.hal +++ b/audio/6.0/IStream.hal @@ -300,13 +300,17 @@ interface IStream { /** * Called by the framework to deinitialize the stream and free up - * all the currently allocated resources. It is recommended to close + * all currently allocated resources. It is recommended to close * the stream on the client side as soon as it is becomes unused. * + * The client must ensure that this function is not called while + * audio data is being transferred through the stream's message queues. + * * @return retval OK in case the success. * NOT_SUPPORTED if called on IStream instead of input or * output stream interface. * INVALID_STATE if the stream was already closed. */ + @exit close() generates (Result retval); }; diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp index 1a9df217e1..5ea4c8df59 100644 --- a/audio/core/all-versions/default/Device.cpp +++ b/audio/core/all-versions/default/Device.cpp @@ -39,11 +39,10 @@ namespace implementation { using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils; -Device::Device(audio_hw_device_t* device) : mDevice(device) {} +Device::Device(audio_hw_device_t* device) : mIsClosed(false), mDevice(device) {} Device::~Device() { - int status = audio_hw_device_close(mDevice); - ALOGW_IF(status, "Error closing audio hw device %p: %s", mDevice, strerror(-status)); + (void)doClose(); mDevice = nullptr; } @@ -383,6 +382,18 @@ Return Device::setConnectedState(const DeviceAddress& address, bool conn } #endif +Result Device::doClose() { + if (mIsClosed) return Result::INVALID_STATE; + mIsClosed = true; + return analyzeStatus("close", audio_hw_device_close(mDevice)); +} + +#if MAJOR_VERSION >= 6 +Return Device::close() { + return doClose(); +} +#endif + } // namespace implementation } // namespace CPP_VERSION } // namespace audio diff --git a/audio/core/all-versions/default/PrimaryDevice.cpp b/audio/core/all-versions/default/PrimaryDevice.cpp index 99590b0bdc..3cf09320aa 100644 --- a/audio/core/all-versions/default/PrimaryDevice.cpp +++ b/audio/core/all-versions/default/PrimaryDevice.cpp @@ -31,7 +31,11 @@ namespace implementation { PrimaryDevice::PrimaryDevice(audio_hw_device_t* device) : mDevice(new Device(device)) {} -PrimaryDevice::~PrimaryDevice() {} +PrimaryDevice::~PrimaryDevice() { + // Do not call mDevice->close here. If there are any unclosed streams, + // they only hold IDevice instance, not IPrimaryDevice, thus IPrimaryDevice + // "part" of a device can be destroyed before the streams. +} // Methods from ::android::hardware::audio::CPP_VERSION::IDevice follow. Return PrimaryDevice::initCheck() { @@ -160,6 +164,11 @@ Return PrimaryDevice::setConnectedState(const DeviceAddress& address, bo return mDevice->setConnectedState(address, connected); } #endif +#if MAJOR_VERSION >= 6 +Return PrimaryDevice::close() { + return mDevice->close(); +} +#endif // Methods from ::android::hardware::audio::CPP_VERSION::IPrimaryDevice follow. Return PrimaryDevice::setVoiceVolume(float volume) { diff --git a/audio/core/all-versions/default/StreamIn.cpp b/audio/core/all-versions/default/StreamIn.cpp index d316f83617..f1152ca542 100644 --- a/audio/core/all-versions/default/StreamIn.cpp +++ b/audio/core/all-versions/default/StreamIn.cpp @@ -139,8 +139,7 @@ bool ReadThread::threadLoop() { } // namespace StreamIn::StreamIn(const sp& device, audio_stream_in_t* stream) - : mIsClosed(false), - mDevice(device), + : mDevice(device), mStream(stream), mStreamCommon(new Stream(&stream->common)), mStreamMmap(new StreamMmap(stream)), @@ -159,7 +158,9 @@ StreamIn::~StreamIn() { status_t status = EventFlag::deleteEventFlag(&mEfGroup); ALOGE_IF(status, "read MQ event flag deletion error: %s", strerror(-status)); } +#if MAJOR_VERSION <= 5 mDevice->closeInputStream(mStream); +#endif mStream = nullptr; } @@ -303,14 +304,16 @@ Return StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) { } Return StreamIn::close() { - if (mIsClosed) return Result::INVALID_STATE; - mIsClosed = true; - if (mReadThread.get()) { - mStopReadThread.store(true, std::memory_order_release); + if (mStopReadThread.load(std::memory_order_relaxed)) { // only this thread writes + return Result::INVALID_STATE; } + mStopReadThread.store(true, std::memory_order_release); if (mEfGroup) { mEfGroup->wake(static_cast(MessageQueueFlagBits::NOT_FULL)); } +#if MAJOR_VERSION >= 6 + mDevice->closeInputStream(mStream); +#endif return Result::OK; } diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp index 82cc408e99..396d354179 100644 --- a/audio/core/all-versions/default/StreamOut.cpp +++ b/audio/core/all-versions/default/StreamOut.cpp @@ -138,8 +138,7 @@ bool WriteThread::threadLoop() { } // namespace StreamOut::StreamOut(const sp& device, audio_stream_out_t* stream) - : mIsClosed(false), - mDevice(device), + : mDevice(device), mStream(stream), mStreamCommon(new Stream(&stream->common)), mStreamMmap(new StreamMmap(stream)), @@ -148,7 +147,7 @@ StreamOut::StreamOut(const sp& device, audio_stream_out_t* stream) StreamOut::~StreamOut() { ATRACE_CALL(); - close(); + (void)close(); if (mWriteThread.get()) { ATRACE_NAME("mWriteThread->join"); status_t status = mWriteThread->join(); @@ -159,10 +158,12 @@ StreamOut::~StreamOut() { ALOGE_IF(status, "write MQ event flag deletion error: %s", strerror(-status)); } mCallback.clear(); +#if MAJOR_VERSION <= 5 mDevice->closeOutputStream(mStream); // Closing the output stream in the HAL waits for the callback to finish, // and joins the callback thread. Thus is it guaranteed that the callback // thread will not be accessing our object anymore. +#endif mStream = nullptr; } @@ -291,14 +292,16 @@ Return StreamOut::setParameters(const hidl_vec& context, #endif Return StreamOut::close() { - if (mIsClosed) return Result::INVALID_STATE; - mIsClosed = true; - if (mWriteThread.get()) { - mStopWriteThread.store(true, std::memory_order_release); + if (mStopWriteThread.load(std::memory_order_relaxed)) { // only this thread writes + return Result::INVALID_STATE; } + mStopWriteThread.store(true, std::memory_order_release); if (mEfGroup) { mEfGroup->wake(static_cast(MessageQueueFlagBits::NOT_EMPTY)); } +#if MAJOR_VERSION >= 6 + mDevice->closeOutputStream(mStream); +#endif return Result::OK; } diff --git a/audio/core/all-versions/default/include/core/default/Device.h b/audio/core/all-versions/default/include/core/default/Device.h index e64f00f205..dc53a3961a 100644 --- a/audio/core/all-versions/default/include/core/default/Device.h +++ b/audio/core/all-versions/default/include/core/default/Device.h @@ -114,6 +114,9 @@ struct Device : public IDevice, public ParametersUtil { Return getMicrophones(getMicrophones_cb _hidl_cb) override; Return setConnectedState(const DeviceAddress& address, bool connected) override; #endif +#if MAJOR_VERSION >= 6 + Return close() override; +#endif Return debug(const hidl_handle& fd, const hidl_vec& options) override; @@ -124,11 +127,14 @@ struct Device : public IDevice, public ParametersUtil { void closeOutputStream(audio_stream_out_t* stream); audio_hw_device_t* device() const { return mDevice; } - private: + private: + bool mIsClosed; audio_hw_device_t* mDevice; virtual ~Device(); + Result doClose(); + // Methods from ParametersUtil. char* halGetParameters(const char* keys) override; int halSetParameters(const char* keysAndValues) override; diff --git a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h index 9d69cb0994..f5f38482ee 100644 --- a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h +++ b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h @@ -96,6 +96,9 @@ struct PrimaryDevice : public IPrimaryDevice { Return getMicrophones(getMicrophones_cb _hidl_cb) override; Return setConnectedState(const DeviceAddress& address, bool connected) override; #endif +#if MAJOR_VERSION >= 6 + Return close() override; +#endif Return debug(const hidl_handle& fd, const hidl_vec& options) override; diff --git a/audio/core/all-versions/default/include/core/default/StreamIn.h b/audio/core/all-versions/default/include/core/default/StreamIn.h index 6209b8f996..24f994406c 100644 --- a/audio/core/all-versions/default/include/core/default/StreamIn.h +++ b/audio/core/all-versions/default/include/core/default/StreamIn.h @@ -120,7 +120,6 @@ struct StreamIn : public IStreamIn { uint64_t* time); private: - bool mIsClosed; const sp mDevice; audio_stream_in_t* mStream; const sp mStreamCommon; diff --git a/audio/core/all-versions/default/include/core/default/StreamOut.h b/audio/core/all-versions/default/include/core/default/StreamOut.h index b0980053e4..6334785a03 100644 --- a/audio/core/all-versions/default/include/core/default/StreamOut.h +++ b/audio/core/all-versions/default/include/core/default/StreamOut.h @@ -126,7 +126,6 @@ struct StreamOut : public IStreamOut { TimeSpec* timeStamp); private: - bool mIsClosed; const sp mDevice; audio_stream_out_t* mStream; const sp mStreamCommon; diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp index e267a5ea72..81f963d34d 100644 --- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp @@ -22,18 +22,16 @@ TEST_P(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) { GTEST_SKIP() << "No primary device on this factory"; // returns } - struct WaitExecutor { - ~WaitExecutor() { DeviceManager::waitForInstanceDestruction(); } - } waitExecutor; // Make sure we wait for the device destruction on exiting from the test. - Result result; - sp baseDevice; - ASSERT_OK(getDevicesFactory()->openDevice("primary", returnIn(result, baseDevice))); - ASSERT_OK(result); - ASSERT_TRUE(baseDevice != nullptr); - - Return> primaryDevice = IPrimaryDevice::castFrom(baseDevice); - ASSERT_TRUE(primaryDevice.isOk()); - ASSERT_TRUE(sp(primaryDevice) != nullptr); + { // Scope for device SPs + sp baseDevice = + DeviceManager::getInstance().get(getFactoryName(), DeviceManager::kPrimaryDevice); + ASSERT_TRUE(baseDevice != nullptr); + Return> primaryDevice = IPrimaryDevice::castFrom(baseDevice); + EXPECT_TRUE(primaryDevice.isOk()); + EXPECT_TRUE(sp(primaryDevice) != nullptr); + } + EXPECT_TRUE( + DeviceManager::getInstance().reset(getFactoryName(), DeviceManager::kPrimaryDevice)); } ////////////////////////////////////////////////////////////////////////////// @@ -113,10 +111,12 @@ TEST_P(AudioHidlDeviceTest, GetMicrophonesTest) { ASSERT_NE(0U, activeMicrophones.size()); } stream->close(); +#if MAJOR_VERSION <= 5 // Workaround for b/139329877. Ensures the stream gets closed on the audio hal side. stream.clear(); IPCThreadState::self()->flushCommands(); usleep(1000); +#endif if (efGroup) { EventFlag::deleteEventFlag(&efGroup); } diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h index 468f9b2da6..52917fd10f 100644 --- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -860,6 +860,7 @@ class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter { } static void waitForStreamDestruction() { +#if MAJOR_VERSION <= 5 // FIXME: there is no way to know when the remote IStream is being destroyed // Binder does not support testing if an object is alive, thus // wait for 100ms to let the binder destruction propagates and @@ -868,6 +869,7 @@ class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter { // the latency between local and remote destruction. IPCThreadState::self()->flushCommands(); usleep(100 * 1000); +#endif } private: diff --git a/audio/core/all-versions/vts/functional/DeviceManager.h b/audio/core/all-versions/vts/functional/DeviceManager.h index b6e2db0685..d849f85eba 100644 --- a/audio/core/all-versions/vts/functional/DeviceManager.h +++ b/audio/core/all-versions/vts/functional/DeviceManager.h @@ -22,25 +22,33 @@ template class InterfaceManager { public: + sp getExisting(const Key& name) { + auto existing = instances.find(name); + return existing != instances.end() ? existing->second : sp(); + } + sp get(const Key& name) { auto existing = instances.find(name); if (existing != instances.end()) return existing->second; auto [inserted, _] = instances.emplace(name, Derived::createInterfaceInstance(name)); if (inserted->second) { - environment->registerTearDown([name]() { (void)Derived::getInstance().reset(name); }); + environment->registerTearDown( + [name]() { (void)Derived::getInstance().reset(name, false); }); } return inserted->second; } // The test must check that reset was successful. Reset failure means that the test code // is holding a strong reference to the device. - bool reset(const Key& name) __attribute__((warn_unused_result)) { + bool reset(const Key& name, bool waitForDestruction) __attribute__((warn_unused_result)) { auto iter = instances.find(name); if (iter == instances.end()) return true; ::android::wp weak = iter->second; instances.erase(iter); if (weak.promote() != nullptr) return false; - waitForInstanceDestruction(); + if (waitForDestruction) { + waitForInstanceDestruction(); + } return true; } @@ -100,7 +108,15 @@ class DeviceManager : public InterfaceManager= 6 + { + sp device = getExisting(std::make_tuple(factoryName, name)); + if (device != nullptr) device->close(); + } + return InterfaceManager::reset(std::make_tuple(factoryName, name), false); +#endif } bool resetPrimary(const std::string& factoryName) __attribute__((warn_unused_result)) { return reset(factoryName, kPrimaryDevice); diff --git a/audio/effect/6.0/IEffect.hal b/audio/effect/6.0/IEffect.hal index b35afee260..f4c50a20aa 100644 --- a/audio/effect/6.0/IEffect.hal +++ b/audio/effect/6.0/IEffect.hal @@ -407,9 +407,12 @@ interface IEffect { /** * Called by the framework to deinitialize the effect and free up - * all the currently allocated resources. It is recommended to close + * all currently allocated resources. It is recommended to close * the effect on the client side as soon as it is becomes unused. * + * The client must ensure that this function is not called while + * audio data is being transferred through the effect's message queues. + * * @return retval OK in case the success. * INVALID_STATE if the effect was already closed. */ diff --git a/audio/effect/all-versions/default/Effect.cpp b/audio/effect/all-versions/default/Effect.cpp index 3c0d8788ab..0afa779f03 100644 --- a/audio/effect/all-versions/default/Effect.cpp +++ b/audio/effect/all-versions/default/Effect.cpp @@ -138,11 +138,11 @@ const char* Effect::sContextCallToCommand = "error"; const char* Effect::sContextCallFunction = sContextCallToCommand; Effect::Effect(effect_handle_t handle) - : mIsClosed(false), mHandle(handle), mEfGroup(nullptr), mStopProcessThread(false) {} + : mHandle(handle), mEfGroup(nullptr), mStopProcessThread(false) {} Effect::~Effect() { ATRACE_CALL(); - close(); + (void)close(); if (mProcessThread.get()) { ATRACE_NAME("mProcessThread->join"); status_t status = mProcessThread->join(); @@ -154,8 +154,10 @@ Effect::~Effect() { } mInBuffer.clear(); mOutBuffer.clear(); +#if MAJOR_VERSION <= 5 int status = EffectRelease(mHandle); ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status)); +#endif EffectMap::getInstance().remove(mHandle); mHandle = 0; } @@ -699,15 +701,20 @@ Return Effect::setCurrentConfigForFeature(uint32_t featureId, } Return Effect::close() { - if (mIsClosed) return Result::INVALID_STATE; - mIsClosed = true; - if (mProcessThread.get()) { - mStopProcessThread.store(true, std::memory_order_release); + if (mStopProcessThread.load(std::memory_order_relaxed)) { // only this thread modifies + return Result::INVALID_STATE; } + mStopProcessThread.store(true, std::memory_order_release); if (mEfGroup) { mEfGroup->wake(static_cast(MessageQueueFlagBits::REQUEST_QUIT)); } +#if MAJOR_VERSION <= 5 return Result::OK; +#elif MAJOR_VERSION >= 6 + // No need to join the processing thread, it is part of the API contract that the client + // must finish processing before closing the effect. + return analyzeStatus("EffectRelease", "", sContextCallFunction, EffectRelease(mHandle)); +#endif } Return Effect::debug(const hidl_handle& fd, const hidl_vec& /* options */) { diff --git a/audio/effect/all-versions/default/Effect.h b/audio/effect/all-versions/default/Effect.h index 3d99a0e42f..181e54241a 100644 --- a/audio/effect/all-versions/default/Effect.h +++ b/audio/effect/all-versions/default/Effect.h @@ -170,7 +170,6 @@ struct Effect : public IEffect { static const char* sContextCallToCommand; static const char* sContextCallFunction; - bool mIsClosed; effect_handle_t mHandle; sp mInBuffer; sp mOutBuffer; From a70e4317e631737d1ac775f2e56f8cfc1c433589 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 15 Nov 2019 16:21:38 -0800 Subject: [PATCH 0259/1022] Audio VTS: Fix MMAP tests Ensure stream test runs for output MMAP profiles. Enhance checks for MMAP buffer size. Bug: 144575694 Test: atest VtsHalAudioV6_0TargetTest Change-Id: I93e66b12c93c466d661e65c4dbbb5deb32772848 --- audio/6.0/IStream.hal | 2 +- .../6.0/AudioPrimaryHidlHalTest.cpp | 3 ++- .../vts/functional/AudioPrimaryHidlHalTest.h | 20 +++++++++---------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/audio/6.0/IStream.hal b/audio/6.0/IStream.hal index 451e1162bf..b48a05d36b 100644 --- a/audio/6.0/IStream.hal +++ b/audio/6.0/IStream.hal @@ -277,7 +277,7 @@ interface IStream { * @return retval OK in case the success. * NOT_SUPPORTED on non mmap mode streams * NOT_INITIALIZED in case of memory allocation error - * INVALID_ARGUMENTS if the requested buffer size is too large + * INVALID_ARGUMENTS if the requested buffer size is invalid * INVALID_STATE if called out of sequence * @return info a MmapBufferInfo struct containing information on the MMMAP buffer created. */ diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp index 30f8a7ade7..7e931ff1b1 100644 --- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp @@ -100,7 +100,8 @@ const std::vector& getOutputDeviceConfigParameters() { special = true; } if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) && - !(flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC)) { + !(flags & + (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ))) { result.emplace_back(device, config, AudioOutputFlag(AUDIO_OUTPUT_FLAG_DIRECT)); special = true; diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h index 468f9b2da6..c7a7a733bc 100644 --- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -1202,19 +1202,17 @@ TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice", waitForStreamDestruction()) // clang-format on -static void testCreateTooBigMmapBuffer(IStream* stream) { - MmapBufferInfo info; - Result res; - // Assume that int max is a value too big to be allocated - // This is true currently with a 32bit media server, but might not when it - // will run in 64 bit - auto minSizeFrames = std::numeric_limits::max(); - ASSERT_OK(stream->createMmapBuffer(minSizeFrames, returnIn(res, info))); - ASSERT_RESULT(invalidArgsOrNotSupported, res); +static void testMmapBufferOfInvalidSize(IStream* stream) { + for (int32_t value : {-1, 0, std::numeric_limits::max()}) { + MmapBufferInfo info; + Result res; + EXPECT_OK(stream->createMmapBuffer(value, returnIn(res, info))); + EXPECT_RESULT(invalidArgsOrNotSupported, res) << "value=" << value; + } } -TEST_IO_STREAM(CreateTooBigMmapBuffer, "Create mmap buffer too big should fail", - testCreateTooBigMmapBuffer(stream.get())) +TEST_IO_STREAM(CreateTooBigMmapBuffer, "Create mmap buffer of invalid size must fail", + testMmapBufferOfInvalidSize(stream.get())) static void testGetMmapPositionOfNonMmapedStream(IStream* stream) { Result res; From 5bfecf49a7986fea819949fd7d6a49788726108a Mon Sep 17 00:00:00 2001 From: Zhaoming Yin Date: Mon, 18 Nov 2019 19:27:01 -0800 Subject: [PATCH 0260/1022] Make HAL default service run on crosshatch_car (VINTF registration) Bug: 144734708 Test: manually, once compiled and flashed, the service will be in the VINTF service list. Change-Id: I92d05557ddc7c95f697d2f5a88ab8f481c4d0e5b --- automotive/audiocontrol/1.0/default/Android.bp | 2 +- .../1.0/default/audiocontrol_manifest.xml | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 automotive/audiocontrol/1.0/default/audiocontrol_manifest.xml diff --git a/automotive/audiocontrol/1.0/default/Android.bp b/automotive/audiocontrol/1.0/default/Android.bp index 314830b92a..3d04c890bc 100644 --- a/automotive/audiocontrol/1.0/default/Android.bp +++ b/automotive/audiocontrol/1.0/default/Android.bp @@ -29,7 +29,7 @@ cc_binary { "liblog", "libutils", ], - + vintf_fragments: ["audiocontrol_manifest.xml"], cflags: [ "-DLOG_TAG=\"AudCntrlDrv\"", "-O0", diff --git a/automotive/audiocontrol/1.0/default/audiocontrol_manifest.xml b/automotive/audiocontrol/1.0/default/audiocontrol_manifest.xml new file mode 100644 index 0000000000..0981eb71ad --- /dev/null +++ b/automotive/audiocontrol/1.0/default/audiocontrol_manifest.xml @@ -0,0 +1,11 @@ + + + android.hardware.automotive.audiocontrol + hwbinder + 1.0 + + IAudioControl + default + + + \ No newline at end of file From dead48f5fbcc7dc9b764b8dfdd865ac8d0d34391 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Tue, 19 Nov 2019 23:03:30 +0100 Subject: [PATCH 0261/1022] Add hash for media.c2@1.1 Bug: 136316504 Change-Id: Ic78f472723e327758985ed1a9e30faabba3ed365 --- current.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/current.txt b/current.txt index bc91af5e1d..8c7b4daf0e 100644 --- a/current.txt +++ b/current.txt @@ -597,6 +597,8 @@ db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardwar c228aaa27f66c48e147159a4f4996c5273191fece1b08de31bd171c61334855e android.hardware.keymaster@4.1::IKeymasterDevice adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardware.keymaster@4.1::IOperation 7a04ea5595ed418ca3e91c28b8bd7353dd988be9be7b0c8c9e64fb4b77bd4523 android.hardware.keymaster@4.1::types +df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent +a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice 4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback From 88d87faec908588db0dcf8fe9705ac72516ea82a Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Tue, 5 Nov 2019 14:57:51 -0800 Subject: [PATCH 0262/1022] gralloc: add get and set BufferMetadata support Add get and set functions that allow buffer metadata to be set on the buffer. This patch has been reviewed by vendors on AOSP. It is a combination of the following patches. They have been squashed (and updated) to make them easier to review. Two of the patches are proposals by ARM that have been incorporated into this patch. https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1107574 https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1109946 https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1124857 https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1126861 Bug: 141632767, 141631993 Test: VtsHalGraphicsMapperV4_0TargetTest Change-Id: I0e79d73a7687f2f5b51828a7454888e6d8ff9460 --- graphics/common/aidl/Android.bp | 1 + graphics/mapper/4.0/IMapper.hal | 222 +++- graphics/mapper/4.0/utils/vts/Android.bp | 3 + graphics/mapper/4.0/utils/vts/MapperVts.cpp | 88 +- .../vts/include/mapper-vts/4.0/MapperVts.h | 16 +- graphics/mapper/4.0/vts/functional/Android.bp | 6 +- .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 1080 ++++++++++++++++- 7 files changed, 1381 insertions(+), 35 deletions(-) diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp index 497c0f824d..e0c7674bba 100644 --- a/graphics/common/aidl/Android.bp +++ b/graphics/common/aidl/Android.bp @@ -1,5 +1,6 @@ aidl_interface { name: "vintf-graphics-common", + host_supported: true, vendor_available: true, vndk: { enabled: true, diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal index 640539fcee..a5413826ce 100644 --- a/graphics/mapper/4.0/IMapper.hal +++ b/graphics/mapper/4.0/IMapper.hal @@ -35,18 +35,20 @@ interface IMapper { */ uint32_t width; - /** - * The height specifies how many rows of pixels must be in the - * allocated buffer. - */ + /** + * The height specifies how many rows of pixels must be in the + * allocated buffer. + */ uint32_t height; - /** - * The number of image layers that must be in the allocated buffer. - */ + /** + * The number of image layers that must be in the allocated buffer. + */ uint32_t layerCount; - /** Buffer pixel format. */ + /** + * Buffer pixel format. + */ PixelFormat format; /** @@ -309,5 +311,209 @@ interface IMapper { generates (Error error, bool supported); + + /** + * Description for get(...), set(...) and getFromBufferDescriptorInfo(...) + * + * ------------ Overview ----------------------------------- + * Gralloc 4 adds support for getting and setting buffer metadata on a buffer. + * + * To get buffer metadata, the client passes in a buffer handle and a token that + * represents the type of buffer metadata they would like to get. IMapper returns + * a byte stream that contains the buffer metadata. To set the buffer metadata, the + * client passes in a buffer handle and a token that represents the type of buffer + * metadata they would like to set and a byte stream that contains the buffer metadata + * they are setting. + * + * Buffer metadata is global for a buffer. When the metadata is set on the buffer + * in a process, the updated metadata should be available to all other processes. + * Please see "Storing and Propagating Metadata" below for more details. + * + * The getter and setter functions have been optimized for easy vendor extension. + * They do not require a formal HIDL extension to add support for getting and setting + * vendor defined buffer metadata. In order to allow easy extension, the types used + * here are not typical HIDL types. See "Buffer Metadata Token" and + * "Buffer Metadata Stream" below for more details. + * + * ------------ Storing and Propagating Metadata ----------- + * Buffer metadata must be global. Any changes to the metadata must be propagated + * to all other processes immediately. Vendors may chose how they would like support + * this functionality. + * + * We recommend supporting this functionality by allocating an extra page of shared + * memory and storing it in the buffer's native_handle_t. The buffer metadata can + * be stored in the extra page of shared memory. Set operations are automatically + * propagated to all other processes. + * + * ------------ Buffer Metadata Synchronization ------------ + * There are no explicit buffer metadata synchronization primitives. Many devices + * before gralloc 4 already support getting and setting of global buffer metadata + * with no explicit synchronization primitives. Adding synchronization primitives + * would just add unnecessary complexity. + * + * The general rule is if a process has permission to write to a buffer, they + * have permission to write to the buffer's metadata. If a process has permission + * to read from a buffer, they have permission to read the buffer's metadata. + * + * There is one exception to this rule. Fences CANNOT be used to protect a buffer's + * metadata. A process should finish writing to a buffer's metadata before sending + * sending the buffer to another process that will read or write to the buffer. + * This exception is needed because sometimes userspace needs to read the + * buffer's metadata before the buffer's contents are ready. + * + * As a simple example: an app renders to a buffer and then displays the buffer. + * In this example when the app renders to the buffer, both the buffer and its + * metadata need to be updated. The app's process queues up its work on the GPU + * and gets back an acquire fence. The app's process must update the buffer's + * metadata before enqueuing the buffer to SurfaceFlinger. The app process CANNOT + * update the buffer's metadata after enqueuing the buffer. When HardwareComposer + * receives the buffer, it is immediately safe to read the buffer's metadata + * and use it to program the display driver. To read the buffer's contents, + * display driver must still wait on the acquire fence. + * + * ------------ Buffer Metadata Token ---------------------- + * In order to allow arbitrary vendor defined metadata, we could not use a + * HIDL enum as the buffer metadata token. Extending a HIDL enum requires a full + * HIDL extension. We also could not use a simple non-HIDL enum because vendor + * defined enums from different vendors could collide. Instead we have defined + * a struct that has a string representing the enum type and an int that + * represents the enum value. The string protects different enum values from + * colliding. + * + * The token struct (MetadataType) is defined as a HIDL struct since it + * is passed into a HIDL function. The standard buffer metadata types are NOT + * defined as a HIDL enum because it would have required a new IMapper version + * just to add future standard buffer metadata types. By putting the enum in the + * stable AIDL (hardware/interfaces/graphics/common/aidl/android/hardware/ + * graphics/common/StandardMetadataType.aidl), vendors will be able to optionally + * choose to support future standard buffer metadata types without upgrading + * HIDL versions. For more information see the description of "struct MetadataType". + * + * ------------ Buffer Metadata Stream --------------------- + * The buffer metadata is get and set as a byte stream (vec). By getting + * and setting buffer metadata as a byte stream, vendors can use the standard + * getters and setter functions defined here. Vendors do NOT need to add their own + * getters and setter functions for each new type of buffer metadata. + * + * Converting buffer metadata into a byte stream can be non-trivial. For the standard + * buffer metadata types defined in StandardMetadataType.aidl, there are also + * support functions that will encode the buffer metadata into a byte stream + * and decode the buffer metadata from a byte stream. We STRONGLY recommend using + * these support functions. The framework will use them when getting and setting + * metadata. The support functions are defined in + * frameworks/native/libs/gralloc/types/include/gralloctypes/Gralloc4.h. + */ + + /** + * MetadataType represents the different types of buffer metadata that could be + * associated with a buffer. It is used by IMapper to help get and set buffer metadata + * on the buffer's native handle. + * + * Standard buffer metadata will have the name field set to + * "android.hardware.graphics.common.StandardMetadataType" and will contain values + * from StandardMetadataType.aidl. + * + * This struct should be "extended" by devices that use a proprietary or non-standard + * buffer metadata. To extend the struct, first create a custom @VendorStability vendor + * AIDL interface that defines the new type(s) you would like to support. Set the + * struct's name field to the custom aidl interface's name + * (eg. "vendor.mycompanyname.graphics.common.MetadataType"). Set the struct's value + * field to the custom @VendorStabilty vendor AIDL interface. + * + * Each company should create their own StandardMetadataType.aidl extension. The name + * field prevents values from different companies from colliding. + */ + struct MetadataType { + string name; + int64_t value; + }; + + /** + * Gets the buffer metadata for a given MetadataType. + * + * Buffer metadata can be changed after allocation so clients should avoid "caching" + * the buffer metadata. For example, if the video resolution changes and the buffers + * are not reallocated, several buffer metadata values may change without warning. + * Clients should not expect the values to be constant. They should requery them every + * frame. The only exception is buffer metadata that is determined at allocation + * time. For StandardMetadataType values, only BUFFER_ID, NAME, WIDTH, + * HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and USAGE are safe to cache because + * they are determined at allocation time. + * + * @param buffer Buffer containing desired metadata + * @param metadataType MetadataType for the metadata value being queried + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the raw handle is invalid. + * - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of + * resources. + * - `UNSUPPORTED` when metadataType is unknown/unsupported. + * IMapper must support getting all StandardMetadataType.aidl values defined + * at the time the device first launches. + * @return metadata Vector of bytes representing the buffer metadata associated with + * the MetadataType. + */ + get(pointer buffer, MetadataType metadataType) + generates (Error error, + vec metadata); + + /** + * Sets the global value for a given MetadataType. + * + * Metadata fields are not required to be settable. This function can + * return Error::UNSUPPORTED whenever it doesn't support setting a + * particular Metadata field. + * + * The framework may attempt to set the following StandardMetadataType + * values: DATASPACE, PER_FRAME_METADATA, PER_FRAME_METADATA_BLOB and BLEND_MODE. + * We strongly encourage everyone to support setting as many of those fields as + * possible. If a device's Composer implementation supports a field, it should be + * supported here. Over time these metadata fields will be moved out of + * Composer/BufferQueue/etc. and into the buffer's Metadata fields. + * If a device's IMapper doesn't support setting those Metadata fields, + * eventually the device may not longer be able to support these fields. + * + * @param buffer Buffer receiving desired metadata + * @param metadataType MetadataType for the metadata value being set + * @param metadata Vector of bytes representing the value associated with + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the raw handle is invalid. + * - `BAD_VALUE` when the field is constant and can never be set (such as + * BUFFER_ID, NAME, WIDTH, HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and + * USAGE) + * - `NO_RESOURCES` if the set cannot be fullfilled due to unavailability of + * resources. + * - `UNSUPPORTED` when metadataType is unknown/unsupported or setting + * it is unsupported. Unsupported should also be returned if the metadata + * is malformed. + */ + set(pointer buffer, MetadataType metadataType, vec metadata) + generates (Error error); + + /** + * Given a BufferDescriptorInfo, gets the starting value of a given + * MetadataType. This can be used to query basic information about a buffer + * before the buffer is allocated. + * + * @param description Attributes of the descriptor. + * @param metadataType MetadataType for the metadata value being queried + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_VALUE` if any of the specified BufferDescriptorInfo attributes + * are invalid. + * - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of + * resources. + * - `UNSUPPORTED` when any of the description attributes are unsupported or + * if the metadataType is unknown/unsupported. This should also be + * returned if the requested metadata is not defined until a buffer has been + * allocated. + * @return metadata Vector of bytes representing the value associated with + * the MetadataType value. + */ + getFromBufferDescriptorInfo(BufferDescriptorInfo description, + MetadataType metadataType) + generates (Error error, + vec metadata); }; diff --git a/graphics/mapper/4.0/utils/vts/Android.bp b/graphics/mapper/4.0/utils/vts/Android.bp index e451584958..56ff116a43 100644 --- a/graphics/mapper/4.0/utils/vts/Android.bp +++ b/graphics/mapper/4.0/utils/vts/Android.bp @@ -26,6 +26,9 @@ cc_library_static { "android.hardware.graphics.allocator@4.0", "android.hardware.graphics.mapper@4.0", ], + shared_libs: [ + "libgralloctypes", + ], export_static_lib_headers: [ "android.hardware.graphics.allocator@4.0", "android.hardware.graphics.mapper@4.0", diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp index 056b7c9da4..531f31131c 100644 --- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp +++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include #include @@ -92,28 +93,39 @@ const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle) { std::vector Gralloc::allocate(const BufferDescriptor& descriptor, uint32_t count, bool import, - uint32_t* outStride) { + bool allowFailure, uint32_t* outStride) { std::vector bufferHandles; bufferHandles.reserve(count); - mAllocator->allocate(descriptor, count, - [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) { - ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers"; - ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array"; + mAllocator->allocate( + descriptor, count, + [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers"; + ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array"; - for (uint32_t i = 0; i < count; i++) { - if (import) { - ASSERT_NO_FATAL_FAILURE( - bufferHandles.push_back(importBuffer(tmpBuffers[i]))); - } else { - ASSERT_NO_FATAL_FAILURE( - bufferHandles.push_back(cloneBuffer(tmpBuffers[i]))); - } - } + for (uint32_t i = 0; i < count; i++) { + const native_handle_t* bufferHandle = nullptr; + if (import) { + if (allowFailure) { + bufferHandle = importBuffer(tmpBuffers[i]); + } else { + ASSERT_NO_FATAL_FAILURE(bufferHandle = importBuffer(tmpBuffers[i])); + } + } else { + if (allowFailure) { + bufferHandle = cloneBuffer(tmpBuffers[i]); + } else { + ASSERT_NO_FATAL_FAILURE(bufferHandle = cloneBuffer(tmpBuffers[i])); + } + } + if (bufferHandle) { + bufferHandles.push_back(bufferHandle); + } + } - if (outStride) { - *outStride = tmpStride; - } - }); + if (outStride) { + *outStride = tmpStride; + } + }); if (::testing::Test::HasFatalFailure()) { bufferHandles.clear(); @@ -123,17 +135,20 @@ std::vector Gralloc::allocate(const BufferDescriptor& de } const native_handle_t* Gralloc::allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, - bool import, uint32_t* outStride) { + bool import, bool allowFailure, uint32_t* outStride) { BufferDescriptor descriptor = createDescriptor(descriptorInfo); if (::testing::Test::HasFatalFailure()) { return nullptr; } - auto buffers = allocate(descriptor, 1, import, outStride); + auto buffers = allocate(descriptor, 1, import, allowFailure, outStride); if (::testing::Test::HasFatalFailure()) { return nullptr; } + if (buffers.size() != 1) { + return nullptr; + } return buffers[0]; } @@ -167,6 +182,10 @@ const native_handle_t* Gralloc::importBuffer(const hidl_handle& rawHandle) { } void Gralloc::freeBuffer(const native_handle_t* bufferHandle) { + if (bufferHandle == nullptr) { + return; + } + auto buffer = const_cast(bufferHandle); if (mImportedBuffers.erase(bufferHandle)) { @@ -296,6 +315,35 @@ bool Gralloc::isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo) { return supported; } +Error Gralloc::get(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType, + hidl_vec* outVec) { + Error err; + mMapper->get(const_cast(bufferHandle), metadataType, + [&](const auto& tmpError, const hidl_vec& tmpVec) { + err = tmpError; + *outVec = tmpVec; + }); + return err; +} + +Error Gralloc::set(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType, + const hidl_vec& vec) { + return mMapper->set(const_cast(bufferHandle), metadataType, vec); +} + +Error Gralloc::getFromBufferDescriptorInfo(const IMapper::BufferDescriptorInfo& descriptorInfo, + const IMapper::MetadataType& metadataType, + hidl_vec* outVec) { + Error err; + mMapper->getFromBufferDescriptorInfo( + descriptorInfo, metadataType, + [&](const auto& tmpError, const hidl_vec& tmpVec) { + err = tmpError; + *outVec = tmpVec; + }); + return err; +} + } // namespace vts } // namespace V4_0 } // namespace mapper diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h index 03ce764d8b..28555fa05d 100644 --- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h +++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h @@ -51,9 +51,11 @@ class Gralloc { // // Either case, the returned buffers must be freed with freeBuffer. std::vector allocate(const BufferDescriptor& descriptor, uint32_t count, - bool import = true, uint32_t* outStride = nullptr); + bool import = true, bool allowFailure = false, + uint32_t* outStride = nullptr); const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, - bool import = true, uint32_t* outStride = nullptr); + bool import = true, bool allowFailure = false, + uint32_t* outStride = nullptr); // IMapper methods @@ -81,6 +83,16 @@ class Gralloc { bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo); + Error get(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType, + hidl_vec* outVec); + + Error set(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType, + const hidl_vec& vec); + + Error getFromBufferDescriptorInfo(const IMapper::BufferDescriptorInfo& descriptorInfo, + const IMapper::MetadataType& metadataType, + hidl_vec* outVec); + private: void init(const std::string& allocatorServiceName, const std::string& mapperServiceName); diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp index a90ee0ca1c..5a7548a4f8 100644 --- a/graphics/mapper/4.0/vts/functional/Android.bp +++ b/graphics/mapper/4.0/vts/functional/Android.bp @@ -19,12 +19,16 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"], static_libs: [ + "android.hardware.graphics.mapper@4.0-vts", + ], + shared_libs: [ "android.hardware.graphics.allocator@4.0", "android.hardware.graphics.common@1.0", "android.hardware.graphics.common@1.1", "android.hardware.graphics.common@1.2", "android.hardware.graphics.mapper@4.0", - "android.hardware.graphics.mapper@4.0-vts", + "libgralloctypes", + "vintf-graphics-common-ndk_platform", ], test_suites: ["general-tests"], } diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 62ff6134ff..1e8ec01e33 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -22,6 +22,7 @@ #include #include +#include #include namespace android { @@ -34,6 +35,15 @@ namespace { using android::hardware::graphics::common::V1_2::BufferUsage; using android::hardware::graphics::common::V1_2::PixelFormat; +using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType; +using aidl::android::hardware::graphics::common::BlendMode; +using aidl::android::hardware::graphics::common::Dataspace; +using aidl::android::hardware::graphics::common::ExtendableType; +using aidl::android::hardware::graphics::common::PlaneLayout; +using aidl::android::hardware::graphics::common::PlaneLayoutComponent; + +using DecodeFunction = std::function& vec)>; // Test environment for graphics.mapper. class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { @@ -57,6 +67,8 @@ class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase { mGralloc = std::make_unique( GraphicsMapperHidlEnvironment::Instance()->getServiceName(), GraphicsMapperHidlEnvironment::Instance()->getServiceName())); + ASSERT_NE(nullptr, mGralloc->getAllocator().get()); + ASSERT_NE(nullptr, mGralloc->getMapper().get()); mDummyDescriptorInfo.name = "dummy"; mDummyDescriptorInfo.width = 64; @@ -69,6 +81,85 @@ class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase { void TearDown() override {} + void testGet(const IMapper::BufferDescriptorInfo& descriptorInfo, + const MetadataType& metadataType, DecodeFunction decode) { + const native_handle_t* bufferHandle = nullptr; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(descriptorInfo, true)); + + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, metadataType, &vec)); + + ASSERT_NO_FATAL_FAILURE(decode(descriptorInfo, vec)); + } + + void testSet(const IMapper::BufferDescriptorInfo& descriptorInfo, + const MetadataType& metadataType, const hidl_vec& metadata, + DecodeFunction decode) { + const native_handle_t* bufferHandle = nullptr; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(descriptorInfo, true)); + + Error err = mGralloc->set(bufferHandle, metadataType, metadata); + if (err == Error::UNSUPPORTED) { + GTEST_SUCCEED() << "setting this metadata is unsupported"; + } + ASSERT_EQ(err, Error::NONE); + + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, metadataType, &vec)); + + ASSERT_NO_FATAL_FAILURE(decode(descriptorInfo, vec)); + } + + void verifyDummyDescriptorInfoPlaneLayouts(const std::vector& planeLayouts) { + ASSERT_EQ(1, planeLayouts.size()); + + const auto& planeLayout = planeLayouts.front(); + + ASSERT_EQ(4, planeLayout.components.size()); + + int64_t offsetInBitsR = -1; + int64_t offsetInBitsG = -1; + int64_t offsetInBitsB = -1; + int64_t offsetInBitsA = -1; + + for (const auto& component : planeLayout.components) { + EXPECT_EQ(GRALLOC4_PLANE_LAYOUT_COMPONENT_TYPE, component.type.name); + EXPECT_EQ(8, component.sizeInBits); + if (component.type.value == gralloc4::PlaneLayoutComponentType_R.value) { + offsetInBitsR = component.offsetInBits; + } + if (component.type.value == gralloc4::PlaneLayoutComponentType_G.value) { + offsetInBitsG = component.offsetInBits; + } + if (component.type.value == gralloc4::PlaneLayoutComponentType_B.value) { + offsetInBitsB = component.offsetInBits; + } + if (component.type.value == gralloc4::PlaneLayoutComponentType_A.value) { + offsetInBitsA = component.offsetInBits; + } + } + + EXPECT_EQ(0, offsetInBitsR); + EXPECT_EQ(8, offsetInBitsG); + EXPECT_EQ(16, offsetInBitsB); + EXPECT_EQ(24, offsetInBitsA); + + EXPECT_EQ(0, planeLayout.offsetInBytes); + EXPECT_EQ(8, planeLayout.sampleIncrementInBits); + // Skip testing stride because any stride is valid + EXPECT_EQ(mDummyDescriptorInfo.width, planeLayout.widthInSamples); + EXPECT_EQ(mDummyDescriptorInfo.height, planeLayout.heightInSamples); + EXPECT_LE(planeLayout.widthInSamples * planeLayout.heightInSamples * 4, + planeLayout.totalSizeInBytes); + EXPECT_EQ(1, planeLayout.horizontalSubsampling); + EXPECT_EQ(1, planeLayout.verticalSubsampling); + + EXPECT_EQ(0, planeLayout.crop.left); + EXPECT_EQ(0, planeLayout.crop.top); + EXPECT_EQ(planeLayout.widthInSamples, planeLayout.crop.right); + EXPECT_EQ(planeLayout.heightInSamples, planeLayout.crop.bottom); + } + std::unique_ptr mGralloc; IMapper::BufferDescriptorInfo mDummyDescriptorInfo{}; }; @@ -90,8 +181,8 @@ TEST_F(GraphicsMapperHidlTest, AllocatorAllocate) { for (uint32_t count = 0; count < 5; count++) { std::vector bufferHandles; uint32_t stride; - ASSERT_NO_FATAL_FAILURE(bufferHandles = - mGralloc->allocate(descriptor, count, false, &stride)); + ASSERT_NO_FATAL_FAILURE( + bufferHandles = mGralloc->allocate(descriptor, count, false, false, &stride)); if (count >= 1) { EXPECT_LE(mDummyDescriptorInfo.width, stride) << "invalid buffer stride"; @@ -293,7 +384,7 @@ TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) { const native_handle_t* bufferHandle; uint32_t stride; - ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, &stride)); + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, false, &stride)); // lock buffer for writing const IMapper::Rect region{0, 0, static_cast(info.width), @@ -354,7 +445,7 @@ TEST_F(GraphicsMapperHidlTest, LockYCbCrBasic) { const native_handle_t* bufferHandle; uint32_t stride; - ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, &stride)); + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, false, &stride)); // lock buffer for writing const IMapper::Rect region{0, 0, static_cast(info.width), @@ -519,6 +610,987 @@ TEST_F(GraphicsMapperHidlTest, IsSupportedY16) { ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info)); } +/** + * Test IMapper::get(BufferId) + */ +TEST_F(GraphicsMapperHidlTest, GetBufferId) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_BufferId, + [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + uint64_t bufferId = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodeBufferId(vec, &bufferId)); + }); +} + +/** + * Test IMapper::get(Name) + */ +TEST_F(GraphicsMapperHidlTest, GetName) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Name, + [](const IMapper::BufferDescriptorInfo& info, const hidl_vec& vec) { + std::string name; + ASSERT_EQ(NO_ERROR, gralloc4::decodeName(vec, &name)); + EXPECT_EQ(info.name, name); + }); +} + +/** + * Test IMapper::get(Width) + */ +TEST_F(GraphicsMapperHidlTest, GetWidth) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Width, + [](const IMapper::BufferDescriptorInfo& info, const hidl_vec& vec) { + uint64_t width = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodeWidth(vec, &width)); + EXPECT_EQ(info.width, width); + }); +} + +/** + * Test IMapper::get(Height) + */ +TEST_F(GraphicsMapperHidlTest, GetHeight) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Height, + [](const IMapper::BufferDescriptorInfo& info, const hidl_vec& vec) { + uint64_t height = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodeHeight(vec, &height)); + EXPECT_EQ(info.height, height); + }); +} + +/** + * Test IMapper::get(LayerCount) + */ +TEST_F(GraphicsMapperHidlTest, GetLayerCount) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_LayerCount, + [](const IMapper::BufferDescriptorInfo& info, const hidl_vec& vec) { + uint64_t layerCount = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodeLayerCount(vec, &layerCount)); + EXPECT_EQ(info.layerCount, layerCount); + }); +} + +/** + * Test IMapper::get(PixelFormatRequested) + */ +TEST_F(GraphicsMapperHidlTest, GetPixelFormatRequested) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatRequested, + [](const IMapper::BufferDescriptorInfo& info, const hidl_vec& vec) { + PixelFormat pixelFormatRequested = PixelFormat::BLOB; + ASSERT_EQ(NO_ERROR, + gralloc4::decodePixelFormatRequested(vec, &pixelFormatRequested)); + EXPECT_EQ(info.format, pixelFormatRequested); + }); +} + +/** + * Test IMapper::get(PixelFormatFourCC) + */ +TEST_F(GraphicsMapperHidlTest, GetPixelFormatFourCC) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC, + [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + uint32_t pixelFormatFourCC = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatFourCC(vec, &pixelFormatFourCC)); + }); +} + +/** + * Test IMapper::get(PixelFormatModifier) + */ +TEST_F(GraphicsMapperHidlTest, GetPixelFormatModifier) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier, + [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + uint64_t pixelFormatModifier = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatModifier(vec, &pixelFormatModifier)); + }); +} + +/** + * Test IMapper::get(Usage) + */ +TEST_F(GraphicsMapperHidlTest, GetUsage) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage, + [](const IMapper::BufferDescriptorInfo& info, const hidl_vec& vec) { + uint64_t usage = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &usage)); + EXPECT_EQ(info.usage, usage); + }); +} + +/** + * Test IMapper::get(AllocationSize) + */ +TEST_F(GraphicsMapperHidlTest, GetAllocationSize) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_AllocationSize, + [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + uint64_t allocationSize = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodeAllocationSize(vec, &allocationSize)); + }); +} + +/** + * Test IMapper::get(ProtectedContent) + */ +TEST_F(GraphicsMapperHidlTest, GetProtectedContent) { + auto info = mDummyDescriptorInfo; + info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY; + + const native_handle_t* bufferHandle = nullptr; + bufferHandle = mGralloc->allocate(info, true, true); + if (bufferHandle) { + GTEST_SUCCEED() << "unable to allocate protected content"; + } + + hidl_vec vec; + ASSERT_EQ(Error::NONE, + mGralloc->get(bufferHandle, gralloc4::MetadataType_ProtectedContent, &vec)); + + uint64_t protectedContent = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodeProtectedContent(vec, &protectedContent)); + EXPECT_EQ(1, protectedContent); +} + +/** + * Test IMapper::get(Compression) + */ +TEST_F(GraphicsMapperHidlTest, GetCompression) { + auto info = mDummyDescriptorInfo; + info.usage = static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); + + testGet(info, gralloc4::MetadataType_Compression, + [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + ExtendableType compression = gralloc4::Compression_DisplayStreamCompression; + ASSERT_EQ(NO_ERROR, gralloc4::decodeCompression(vec, &compression)); + + EXPECT_EQ(gralloc4::Compression_None.name, compression.name); + EXPECT_EQ(gralloc4::Compression_None.value, compression.value); + }); +} + +/** + * Test IMapper::get(Interlaced) + */ +TEST_F(GraphicsMapperHidlTest, GetInterlaced) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Interlaced, + [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + ExtendableType interlaced = gralloc4::Interlaced_TopBottom; + ASSERT_EQ(NO_ERROR, gralloc4::decodeInterlaced(vec, &interlaced)); + + EXPECT_EQ(gralloc4::Interlaced_None.name, interlaced.name); + EXPECT_EQ(gralloc4::Interlaced_None.value, interlaced.value); + }); +} + +/** + * Test IMapper::get(ChromaSiting) + */ +TEST_F(GraphicsMapperHidlTest, GetChromaSiting) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_ChromaSiting, + [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + ExtendableType chromaSiting = gralloc4::ChromaSiting_Unknown; + ASSERT_EQ(NO_ERROR, gralloc4::decodeChromaSiting(vec, &chromaSiting)); + + EXPECT_EQ(gralloc4::ChromaSiting_None.name, chromaSiting.name); + EXPECT_EQ(gralloc4::ChromaSiting_None.value, chromaSiting.value); + }); +} + +/** + * Test IMapper::get(PlaneLayouts) + */ +TEST_F(GraphicsMapperHidlTest, GetPlaneLayouts) { + const native_handle_t* bufferHandle = nullptr; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); + + 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_NO_FATAL_FAILURE(verifyDummyDescriptorInfoPlaneLayouts(planeLayouts)); +} + +/** + * Test IMapper::get(Dataspace) + */ +TEST_F(GraphicsMapperHidlTest, GetDataspace) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Dataspace, + [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + Dataspace dataspace = Dataspace::DISPLAY_P3; + ASSERT_EQ(NO_ERROR, gralloc4::decodeDataspace(vec, &dataspace)); + EXPECT_EQ(Dataspace::UNKNOWN, dataspace); + }); +} + +/** + * Test IMapper::get(BlendMode) + */ +TEST_F(GraphicsMapperHidlTest, GetBlendMode) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_BlendMode, + [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + BlendMode blendMode = BlendMode::NONE; + ASSERT_EQ(NO_ERROR, gralloc4::decodeBlendMode(vec, &blendMode)); + EXPECT_EQ(BlendMode::INVALID, blendMode); + }); +} + +/** + * Test IMapper::get(metadata) with a bad buffer + */ +TEST_F(GraphicsMapperHidlTest, GetMetadataBadValue) { + const native_handle_t* bufferHandle = nullptr; + hidl_vec vec; + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_BufferId, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Name, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Width, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Height, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_LayerCount, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_PixelFormatFourCC, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_PixelFormatModifier, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Usage, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_AllocationSize, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_ProtectedContent, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_Compression, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_Interlaced, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_ChromaSiting, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_Dataspace, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_BlendMode, &vec)); + ASSERT_EQ(0, vec.size()); +} + +/** + * Test IMapper::get(metadata) for unsupported metadata + */ +TEST_F(GraphicsMapperHidlTest, GetUnsupportedMetadata) { + const native_handle_t* bufferHandle = nullptr; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); + + MetadataType metadataTypeFake = {"FAKE", 1}; + + hidl_vec vec; + ASSERT_EQ(Error::UNSUPPORTED, mGralloc->get(bufferHandle, metadataTypeFake, &vec)); + ASSERT_EQ(0, vec.size()); +} + +/** + * Test IMapper::get(metadata) for unsupported standard metadata + */ +TEST_F(GraphicsMapperHidlTest, GetUnsupportedStandardMetadata) { + const native_handle_t* bufferHandle = nullptr; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); + + MetadataType metadataTypeFake = {GRALLOC4_STANDARD_METADATA_TYPE, 9999}; + + hidl_vec vec; + ASSERT_EQ(Error::UNSUPPORTED, mGralloc->get(bufferHandle, metadataTypeFake, &vec)); + ASSERT_EQ(0, vec.size()); +} + +/** + * Test IMapper::set(PixelFormatFourCC) + */ +TEST_F(GraphicsMapperHidlTest, SetPixelFormatFourCC) { + uint32_t pixelFormatFourCC = 0x34324142; // DRM_FORMAT_BGRA8888 + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatFourCC(pixelFormatFourCC, &vec)); + + testSet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + uint32_t realPixelFormatFourCC = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatFourCC(vec, &realPixelFormatFourCC)); + EXPECT_EQ(pixelFormatFourCC, realPixelFormatFourCC); + }); +} + +/** + * Test IMapper::set(PixelFormatModifier) + */ +TEST_F(GraphicsMapperHidlTest, SetPixelFormatModifier) { + uint64_t pixelFormatModifier = 10; + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatModifier(pixelFormatModifier, &vec)); + + testSet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + uint64_t realPixelFormatModifier = 0; + ASSERT_EQ(NO_ERROR, + gralloc4::decodePixelFormatModifier(vec, &realPixelFormatModifier)); + EXPECT_EQ(pixelFormatModifier, realPixelFormatModifier); + }); +} + +/** + * Test IMapper::set(Usage) remove flag + */ +TEST_F(GraphicsMapperHidlTest, SetUsageRemoveBit) { + uint64_t usage = static_cast(BufferUsage::CPU_WRITE_OFTEN); + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec)); + + testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + uint64_t realUsage = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage)); + EXPECT_EQ(usage, realUsage); + }); +} +/** + * Test IMapper::set(Usage) add flag + */ +TEST_F(GraphicsMapperHidlTest, SetUsageAddBit) { + uint64_t usage = mDummyDescriptorInfo.usage | static_cast(BufferUsage::GPU_TEXTURE); + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec)); + + testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + uint64_t realUsage = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage)); + EXPECT_EQ(usage, realUsage); + }); +} + +/** + * Test IMapper::set(Usage) to test protected content + */ +TEST_F(GraphicsMapperHidlTest, SetUsageProtected) { + const native_handle_t* bufferHandle = nullptr; + auto info = mDummyDescriptorInfo; + info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY; + + bufferHandle = mGralloc->allocate(info, true, true); + if (bufferHandle) { + GTEST_SUCCEED() << "unable to allocate protected content"; + } + + uint64_t usage = static_cast(BufferUsage::COMPOSER_OVERLAY); + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec)); + + Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec); + ASSERT_EQ(err, Error::UNSUPPORTED); + vec.resize(0); + + uint64_t realUsage = 0; + ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_Usage, &vec)); + ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage)); + EXPECT_EQ(info.usage, realUsage); +} + +/** + * Test IMapper::set(AllocationSize) + */ +TEST_F(GraphicsMapperHidlTest, SetAllocationSize) { + uint64_t allocationSize = 1000000; + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeAllocationSize(allocationSize, &vec)); + + testSet(mDummyDescriptorInfo, gralloc4::MetadataType_AllocationSize, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + uint64_t realAllocationSize = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodeAllocationSize(vec, &realAllocationSize)); + EXPECT_EQ(allocationSize, realAllocationSize); + }); +} + +/** + * Test IMapper::set(ProtectedContent) + */ +TEST_F(GraphicsMapperHidlTest, SetProtectedContent) { + const native_handle_t* bufferHandle = nullptr; + auto info = mDummyDescriptorInfo; + info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY; + + bufferHandle = mGralloc->allocate(info, true, true); + if (bufferHandle) { + GTEST_SUCCEED() << "unable to allocate protected content"; + } + + uint64_t protectedContent = 0; + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeProtectedContent(protectedContent, &vec)); + + Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_ProtectedContent, vec); + ASSERT_EQ(err, Error::UNSUPPORTED); + vec.resize(0); + + uint64_t realProtectedContent = 0; + ASSERT_EQ(Error::NONE, + mGralloc->get(bufferHandle, gralloc4::MetadataType_ProtectedContent, &vec)); + ASSERT_EQ(NO_ERROR, gralloc4::decodeProtectedContent(vec, &realProtectedContent)); + EXPECT_EQ(1, realProtectedContent); +} + +/** + * Test IMapper::set(Compression) + */ +TEST_F(GraphicsMapperHidlTest, SetCompression) { + auto info = mDummyDescriptorInfo; + info.usage = static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); + + ExtendableType compression = gralloc4::Compression_DisplayStreamCompression; + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeCompression(compression, &vec)); + + testSet(info, gralloc4::MetadataType_Compression, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + ExtendableType realCompression = gralloc4::Compression_None; + ASSERT_EQ(NO_ERROR, gralloc4::decodeCompression(vec, &realCompression)); + + EXPECT_EQ(compression.name, realCompression.name); + EXPECT_EQ(compression.value, realCompression.value); + }); +} + +/** + * Test IMapper::set(Interlaced) + */ +TEST_F(GraphicsMapperHidlTest, SetInterlaced) { + ExtendableType interlaced = gralloc4::Interlaced_RightLeft; + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeInterlaced(interlaced, &vec)); + + testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Interlaced, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + ExtendableType realInterlaced = gralloc4::Interlaced_None; + ASSERT_EQ(NO_ERROR, gralloc4::decodeInterlaced(vec, &realInterlaced)); + + EXPECT_EQ(interlaced.name, realInterlaced.name); + EXPECT_EQ(interlaced.value, realInterlaced.value); + }); +} + +/** + * Test IMapper::set(ChromaSiting) + */ +TEST_F(GraphicsMapperHidlTest, SetChromaSiting) { + ExtendableType chromaSiting = gralloc4::ChromaSiting_SitedInterstitial; + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeChromaSiting(chromaSiting, &vec)); + + testSet(mDummyDescriptorInfo, gralloc4::MetadataType_ChromaSiting, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + ExtendableType realChromaSiting = gralloc4::ChromaSiting_None; + ASSERT_EQ(NO_ERROR, gralloc4::decodeChromaSiting(vec, &realChromaSiting)); + + EXPECT_EQ(chromaSiting.name, realChromaSiting.name); + EXPECT_EQ(chromaSiting.value, realChromaSiting.value); + }); +} + +/** + * Test IMapper::set(PlaneLayouts) + */ +TEST_F(GraphicsMapperHidlTest, SetPlaneLayouts) { + const native_handle_t* bufferHandle = nullptr; + auto info = mDummyDescriptorInfo; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true)); + + std::vector planeLayouts; + PlaneLayout planeLayoutA; + PlaneLayout planeLayoutRGB; + PlaneLayoutComponent component; + + planeLayoutA.offsetInBytes = 0; + planeLayoutA.sampleIncrementInBits = 8; + planeLayoutA.strideInBytes = info.width + 20; + planeLayoutA.widthInSamples = info.width; + planeLayoutA.heightInSamples = info.height; + planeLayoutA.totalSizeInBytes = planeLayoutA.strideInBytes * info.height; + planeLayoutA.horizontalSubsampling = 1; + planeLayoutA.verticalSubsampling = 1; + planeLayoutA.crop.left = 0; + planeLayoutA.crop.top = 0; + planeLayoutA.crop.right = info.width; + planeLayoutA.crop.bottom = info.height; + + component.type = gralloc4::PlaneLayoutComponentType_A; + component.offsetInBits = 0; + component.sizeInBits = 8; + planeLayoutA.components.push_back(component); + + planeLayouts.push_back(planeLayoutA); + + planeLayoutRGB.offsetInBytes = 0; + planeLayoutRGB.sampleIncrementInBits = 32; + planeLayoutRGB.strideInBytes = info.width + 20; + planeLayoutRGB.widthInSamples = info.width; + planeLayoutRGB.heightInSamples = info.height; + planeLayoutRGB.totalSizeInBytes = planeLayoutRGB.strideInBytes * info.height; + planeLayoutRGB.horizontalSubsampling = 1; + planeLayoutRGB.verticalSubsampling = 1; + planeLayoutRGB.crop.left = 0; + planeLayoutRGB.crop.top = 0; + planeLayoutRGB.crop.right = info.width; + planeLayoutRGB.crop.bottom = info.height; + + component.type = gralloc4::PlaneLayoutComponentType_R; + planeLayoutRGB.components.push_back(component); + component.type = gralloc4::PlaneLayoutComponentType_G; + planeLayoutRGB.components.push_back(component); + component.type = gralloc4::PlaneLayoutComponentType_B; + planeLayoutRGB.components.push_back(component); + + planeLayouts.push_back(planeLayoutRGB); + + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodePlaneLayouts(planeLayouts, &vec)); + + Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_PlaneLayouts, vec); + if (err == Error::UNSUPPORTED) { + GTEST_SUCCEED() << "setting this metadata is unsupported"; + } + ASSERT_EQ(err, Error::NONE); + + std::vector realPlaneLayouts; + ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &realPlaneLayouts)); + + ASSERT_EQ(planeLayouts.size(), realPlaneLayouts.size()); + + for (int i = 0; i < realPlaneLayouts.size(); i++) { + const auto& planeLayout = planeLayouts[i]; + const auto& realPlaneLayout = realPlaneLayouts[i]; + + EXPECT_EQ(planeLayout.offsetInBytes, realPlaneLayout.offsetInBytes); + EXPECT_EQ(planeLayout.sampleIncrementInBits, realPlaneLayout.sampleIncrementInBits); + EXPECT_EQ(planeLayout.strideInBytes, realPlaneLayout.strideInBytes); + EXPECT_EQ(planeLayout.widthInSamples, realPlaneLayout.widthInSamples); + EXPECT_EQ(planeLayout.heightInSamples, realPlaneLayout.heightInSamples); + EXPECT_LE(planeLayout.totalSizeInBytes, realPlaneLayout.totalSizeInBytes); + EXPECT_EQ(planeLayout.horizontalSubsampling, realPlaneLayout.horizontalSubsampling); + EXPECT_EQ(planeLayout.verticalSubsampling, realPlaneLayout.verticalSubsampling); + + EXPECT_EQ(planeLayout.crop.left, realPlaneLayout.crop.left); + EXPECT_EQ(planeLayout.crop.top, realPlaneLayout.crop.top); + EXPECT_EQ(planeLayout.crop.right, realPlaneLayout.crop.right); + EXPECT_EQ(planeLayout.crop.bottom, realPlaneLayout.crop.bottom); + + ASSERT_EQ(planeLayout.components.size(), realPlaneLayout.components.size()); + + for (int j = 0; j < realPlaneLayout.components.size(); j++) { + const auto& component = planeLayout.components[j]; + const auto& realComponent = realPlaneLayout.components[j]; + + EXPECT_EQ(component.type.name, realComponent.type.name); + EXPECT_EQ(component.type.value, realComponent.type.value); + EXPECT_EQ(component.sizeInBits, realComponent.sizeInBits); + EXPECT_EQ(component.offsetInBits, realComponent.offsetInBits); + } + } +} + +/** + * Test IMapper::set(Dataspace) + */ +TEST_F(GraphicsMapperHidlTest, SetDataspace) { + Dataspace dataspace = Dataspace::V0_SRGB_LINEAR; + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &vec)); + + testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Dataspace, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + Dataspace realDataspace = Dataspace::UNKNOWN; + ASSERT_EQ(NO_ERROR, gralloc4::decodeDataspace(vec, &realDataspace)); + EXPECT_EQ(dataspace, realDataspace); + }); +} + +/** + * Test IMapper::set(BlendMode) + */ +TEST_F(GraphicsMapperHidlTest, SetBlendMode) { + BlendMode blendMode = BlendMode::PREMULTIPLIED; + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeBlendMode(blendMode, &vec)); + + testSet(mDummyDescriptorInfo, gralloc4::MetadataType_BlendMode, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + BlendMode realBlendMode = BlendMode::INVALID; + ASSERT_EQ(NO_ERROR, gralloc4::decodeBlendMode(vec, &realBlendMode)); + EXPECT_EQ(blendMode, realBlendMode); + }); +} + +/** + * Test IMapper::set(metadata) with a bad buffer + */ +TEST_F(GraphicsMapperHidlTest, SetMetadataNullBuffer) { + const native_handle_t* bufferHandle = nullptr; + hidl_vec vec; + ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, vec)); + ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, vec)); + ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, vec)); + ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, vec)); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, vec)); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, vec)); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatFourCC, vec)); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatModifier, vec)); + ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec)); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->set(bufferHandle, gralloc4::MetadataType_AllocationSize, vec)); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->set(bufferHandle, gralloc4::MetadataType_ProtectedContent, vec)); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->set(bufferHandle, gralloc4::MetadataType_Compression, vec)); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->set(bufferHandle, gralloc4::MetadataType_Interlaced, vec)); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->set(bufferHandle, gralloc4::MetadataType_ChromaSiting, vec)); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->set(bufferHandle, gralloc4::MetadataType_PlaneLayouts, vec)); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec)); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec)); +} + +/** + * Test IMapper::set(metadata) for constant metadata + */ +TEST_F(GraphicsMapperHidlTest, SetConstantMetadata) { + const native_handle_t* bufferHandle = nullptr; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); + + hidl_vec vec; + ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, vec)); + ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, vec)); + ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, vec)); + ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, vec)); + ASSERT_EQ(Error::BAD_VALUE, + mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, vec)); + ASSERT_EQ(Error::BAD_VALUE, + mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, vec)); + ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec)); +} + +/** + * Test IMapper::set(metadata) for bad metadata + */ +TEST_F(GraphicsMapperHidlTest, SetBadMetadata) { + const native_handle_t* bufferHandle = nullptr; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); + + hidl_vec vec; + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, vec)); + ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, vec)); + ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, vec)); + ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, vec)); + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, vec)); + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, vec)); + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatFourCC, vec)); + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatModifier, vec)); + ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec)); + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_AllocationSize, vec)); + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_ProtectedContent, vec)); + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_Compression, vec)); + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_Interlaced, vec)); + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_ChromaSiting, vec)); + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_PlaneLayouts, vec)); + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec)); + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec)); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(BufferId) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBufferId) { + hidl_vec vec; + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, + gralloc4::MetadataType_BufferId, &vec)); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(Name) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoName) { + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( + mDummyDescriptorInfo, gralloc4::MetadataType_Name, &vec)); + + std::string name; + ASSERT_EQ(NO_ERROR, gralloc4::decodeName(vec, &name)); + EXPECT_EQ(mDummyDescriptorInfo.name, name); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(Width) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoWidth) { + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( + mDummyDescriptorInfo, gralloc4::MetadataType_Width, &vec)); + + uint64_t width = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodeWidth(vec, &width)); + EXPECT_EQ(mDummyDescriptorInfo.width, width); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(Height) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoHeight) { + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( + mDummyDescriptorInfo, gralloc4::MetadataType_Height, &vec)); + + uint64_t height = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodeHeight(vec, &height)); + EXPECT_EQ(mDummyDescriptorInfo.height, height); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(PixelFormatRequested) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatRequested) { + hidl_vec vec; + ASSERT_EQ(Error::NONE, + mGralloc->getFromBufferDescriptorInfo( + mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatRequested, &vec)); + + PixelFormat pixelFormatRequested = PixelFormat::BLOB; + ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatRequested(vec, &pixelFormatRequested)); + EXPECT_EQ(mDummyDescriptorInfo.format, pixelFormatRequested); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(PixelFormatFourCC) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatFourCC) { + hidl_vec vec; + Error err = mGralloc->getFromBufferDescriptorInfo( + mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC, &vec); + if (err == Error::UNSUPPORTED) { + GTEST_SUCCEED() << "setting this metadata is unsupported"; + } + ASSERT_EQ(err, Error::NONE); + + uint32_t pixelFormatFourCC = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatFourCC(vec, &pixelFormatFourCC)); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(PixelFormatModifier) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatModifier) { + hidl_vec vec; + Error err = mGralloc->getFromBufferDescriptorInfo( + mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier, &vec); + if (err == Error::UNSUPPORTED) { + GTEST_SUCCEED() << "setting this metadata is unsupported"; + } + ASSERT_EQ(err, Error::NONE); + + uint64_t pixelFormatModifier = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatModifier(vec, &pixelFormatModifier)); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(Usage) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUsage) { + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( + mDummyDescriptorInfo, gralloc4::MetadataType_Usage, &vec)); + + uint64_t usage = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &usage)); + EXPECT_EQ(mDummyDescriptorInfo.usage, usage); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(AllocationSize) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoAllocationSize) { + hidl_vec vec; + Error err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, + gralloc4::MetadataType_AllocationSize, &vec); + if (err == Error::UNSUPPORTED) { + GTEST_SUCCEED() << "setting this metadata is unsupported"; + } + ASSERT_EQ(err, Error::NONE); + + uint64_t allocationSize = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodeAllocationSize(vec, &allocationSize)); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(ProtectedContent) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoProtectedContent) { + auto info = mDummyDescriptorInfo; + info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY; + + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( + info, gralloc4::MetadataType_ProtectedContent, &vec)); + + uint64_t protectedContent = 0; + ASSERT_EQ(NO_ERROR, gralloc4::decodeProtectedContent(vec, &protectedContent)); + EXPECT_EQ(1, protectedContent); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(Compression) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCompression) { + auto info = mDummyDescriptorInfo; + info.usage = static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); + + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( + info, gralloc4::MetadataType_Compression, &vec)); + + ExtendableType compression = gralloc4::Compression_DisplayStreamCompression; + ASSERT_EQ(NO_ERROR, gralloc4::decodeCompression(vec, &compression)); + + EXPECT_EQ(gralloc4::Compression_None.name, compression.name); + EXPECT_EQ(gralloc4::Compression_None.value, compression.value); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(Interlaced) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoInterlaced) { + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( + mDummyDescriptorInfo, gralloc4::MetadataType_Interlaced, &vec)); + + ExtendableType interlaced = gralloc4::Interlaced_TopBottom; + ASSERT_EQ(NO_ERROR, gralloc4::decodeInterlaced(vec, &interlaced)); + + EXPECT_EQ(gralloc4::Interlaced_None.name, interlaced.name); + EXPECT_EQ(gralloc4::Interlaced_None.value, interlaced.value); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(ChromaSiting) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoChromaSiting) { + hidl_vec vec; + ASSERT_EQ(Error::NONE, + mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, + gralloc4::MetadataType_ChromaSiting, &vec)); + + ExtendableType chromaSiting = gralloc4::ChromaSiting_CositedHorizontal; + ASSERT_EQ(NO_ERROR, gralloc4::decodeChromaSiting(vec, &chromaSiting)); + + EXPECT_EQ(gralloc4::ChromaSiting_None.name, chromaSiting.name); + EXPECT_EQ(gralloc4::ChromaSiting_None.value, chromaSiting.value); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(PlaneLayouts) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPlaneLayouts) { + hidl_vec vec; + ASSERT_EQ(Error::NONE, + mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, + gralloc4::MetadataType_PlaneLayouts, &vec)); + + std::vector planeLayouts; + ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts)); + ASSERT_NO_FATAL_FAILURE(verifyDummyDescriptorInfoPlaneLayouts(planeLayouts)); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(Dataspace) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoDataspace) { + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( + mDummyDescriptorInfo, gralloc4::MetadataType_Dataspace, &vec)); + + Dataspace dataspace = Dataspace::DISPLAY_P3; + ASSERT_EQ(NO_ERROR, gralloc4::decodeDataspace(vec, &dataspace)); + EXPECT_EQ(Dataspace::UNKNOWN, dataspace); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(BlendMode) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBlendMode) { + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( + mDummyDescriptorInfo, gralloc4::MetadataType_BlendMode, &vec)); + + BlendMode blendMode = BlendMode::COVERAGE; + ASSERT_EQ(NO_ERROR, gralloc4::decodeBlendMode(vec, &blendMode)); + EXPECT_EQ(BlendMode::INVALID, blendMode); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported metadata + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedMetadata) { + MetadataType metadataTypeFake = {"FAKE", 1}; + + hidl_vec vec; + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, metadataTypeFake, &vec)); + ASSERT_EQ(0, vec.size()); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported standard metadata + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedStandardMetadata) { + MetadataType metadataTypeFake = {GRALLOC4_STANDARD_METADATA_TYPE, 9999}; + + hidl_vec vec; + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, metadataTypeFake, &vec)); + ASSERT_EQ(0, vec.size()); +} + } // namespace } // namespace vts } // namespace V4_0 From 122bc2c0cc36f46b9d82bafde69b3881faaa71c0 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Tue, 19 Nov 2019 17:37:06 +0000 Subject: [PATCH 0263/1022] Add TENSOR_QUANT8_ASYMM_SIGNED support to ADD, MUL and SUB. Bug: 143934463 Bug: 143934627 Bug: 143935040 Test: NNTest_static and 1.3 VTS Change-Id: I47ffc2c264390f3c6b98aa9567fb47f2c58333fe --- current.txt | 2 +- neuralnetworks/1.3/types.hal | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/current.txt b/current.txt index f176ab21ce..0433a1c912 100644 --- a/current.txt +++ b/current.txt @@ -602,7 +602,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice 4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -554baa3b317e077b850afcbaac99daeef56861b1786540e56275a4fcad1f43e3 android.hardware.neuralnetworks@1.3::types +103cb87c5ed46851badac097f8d190da60f39b5ab32d60e2e93f64d3014ea75c android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant 44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index f959e45b5a..db86bf6ea1 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -109,6 +109,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -116,7 +117,8 @@ enum OperationType : int32_t { * * 0: A tensor. * * 1: A tensor of the same {@link OperandType}, and compatible dimensions * as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scales and zeroPoint can be different from input0 scale and zeroPoint. * * 2: An {@link OperandType::INT32} scalar, and has to be one of the * {@link FusedActivationFunc} values. Specifies the activation to @@ -124,7 +126,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: The sum, a tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint can be different from inputs' scale and zeroPoint. */ ADD = @1.2::OperationType:ADD, @@ -1345,6 +1348,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -1358,7 +1362,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: The product, a tensor of the same {@link OperandType} as input0. - * For output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * For output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} + * and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, * the following condition must be satisfied: * output_scale > input1_scale * input2_scale. */ @@ -2083,6 +2088,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -2096,7 +2102,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint can be different from inputs' scale and zeroPoint. */ SUB = @1.2::OperationType:SUB, From a1df7c3d1f3aa2cad2439222c5da8163c1f486d9 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 22 Oct 2019 16:56:08 -0700 Subject: [PATCH 0264/1022] composer: few changes for refresh rate switching - getDisplayConfigs is required to remain backward compatible with composer@2.3 and older versions. To keep it that way a new config attribute was added to group similar configs. - getSupportedDisplayVsyncPeriods was removed as the vsync period can be obtained by getDisplayAttribute for each individual config. - renamed setActiveConfigAndVsyncPeriod -> setActiveConfigWithConstraints to better describe what this function does. - added VsyncPeriodChangeTimeline and onVsyncPeriodTimingChanged With these changes composer is expected to return all possible configurations when getDisplayConfigs (similar to older composer versions). The client knows whether a seamless vsync period is possible or not by the config groups. Test: rev up composer to 2.4 and test refresh rate switching Bug: 141329414 Change-Id: I1b4525f7e00b62cdaf260274abe4a6a5962ed1ab --- graphics/composer/2.4/IComposerCallback.hal | 10 + graphics/composer/2.4/IComposerClient.hal | 54 ++-- graphics/composer/2.4/types.hal | 27 +- .../include/composer-hal/2.4/ComposerClient.h | 35 +-- .../include/composer-hal/2.4/ComposerHal.h | 13 +- .../include/composer-passthrough/2.4/HwcHal.h | 102 ++++---- .../composer/2.4/utils/vts/ComposerVts.cpp | 36 +-- .../include/composer-vts/2.4/ComposerVts.h | 10 +- .../VtsHalGraphicsComposerV2_4TargetTest.cpp | 233 ++++++++++-------- 9 files changed, 308 insertions(+), 212 deletions(-) diff --git a/graphics/composer/2.4/IComposerCallback.hal b/graphics/composer/2.4/IComposerCallback.hal index 5c3f8bd99c..fea24a1cbf 100644 --- a/graphics/composer/2.4/IComposerCallback.hal +++ b/graphics/composer/2.4/IComposerCallback.hal @@ -32,4 +32,14 @@ interface IComposerCallback extends @2.1::IComposerCallback { * is expected to be called vsyncPeriodNanos nanoseconds after this call. */ oneway onVsync_2_4(Display display, int64_t timestamp, VsyncPeriodNanos vsyncPeriodNanos); + + /** + * Notifies the client that the previously reported timing for vsync period change has been + * updated. This may occur if the composer missed the deadline for changing the vsync period + * or the client submitted a refresh frame too late. + * + * @param display is the display which vsync period change is in progress + * @param updatedTimeline is the new timeline for the vsync period change. + */ + oneway onVsyncPeriodTimingChanged(Display display, VsyncPeriodChangeTimeline updatedTimeline); }; diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal index c2102d5f53..f23536cd2d 100644 --- a/graphics/composer/2.4/IComposerClient.hal +++ b/graphics/composer/2.4/IComposerClient.hal @@ -20,9 +20,22 @@ import IComposerCallback; import @2.1::Config; import @2.1::Display; import @2.1::Error; +import @2.1::IComposerClient; import @2.3::IComposerClient; interface IComposerClient extends @2.3::IComposerClient { + /** + * Display attributes queryable through getDisplayAttribute_2_4. + */ + enum Attribute : @2.1::IComposerClient.Attribute { + /** + * The configuration group ID (as int32_t) this config is associated to. + * Switching between configurations within the same group may be done seamlessly + * in some conditions via setActiveConfigWithConstraints. + */ + CONFIG_GROUP = 7, + }; + /** * Required capabilities which are supported by the display. The * particular set of supported capabilities for a given display may be @@ -60,6 +73,7 @@ interface IComposerClient extends @2.3::IComposerClient { * (i.e., the vsync period must not change before this time). */ int64_t desiredTimeNanos; + /** * If true, requires that the vsync period change must happen seamlessly without * a noticeable visual artifact. @@ -74,7 +88,6 @@ interface IComposerClient extends @2.3::IComposerClient { * * @param callback is the IComposerCallback object. */ - @entry registerCallback_2_4(IComposerCallback callback); /** @@ -99,25 +112,29 @@ interface IComposerClient extends @2.3::IComposerClient { getDisplayConnectionType(Display display) generates (Error error, DisplayConnectionType type); /** - * Provides a list of the vsync periods supported by the display in the given configuration - * - * @param display is the display for which the vsync periods are queried. - * @param config is the display configuration for which the vsync periods are queried. + * Returns a display attribute value for a particular display + * configuration. * + * @param display is the display to query. + * @param config is the display configuration for which to return + * attribute values. * @return error is NONE upon success. Otherwise, - * BAD_DISPLAY when an invalid display handle was passed in. - * BAD_CONFIG when an invalid config handle was passed in. - * @return supportedVsyncPeriods is a list of supported vsync periods. + * BAD_DISPLAY when an invalid display handle was passed in. + * BAD_CONFIG when config does not name a valid configuration for + * this display. + * BAD_PARAMETER when attribute is unrecognized. + * UNSUPPORTED when attribute cannot be queried for the config. + * @return value is the value of the attribute. */ - getSupportedDisplayVsyncPeriods(Display display, Config config) - generates (Error error, vec supportedVsyncPeriods); + getDisplayAttribute_2_4(Display display, Config config, Attribute attribute) + generates (Error error, int32_t value); /** * Retrieves which vsync period the display is currently using. * * If no display configuration is currently active, this function must * return BAD_CONFIG. If the vsync period is about to change due to a - * setActiveConfigAndVsyncPeriod call, this function must return the current vsync period + * setActiveConfigWithConstraints call, this function must return the current vsync period * until the change takes place. * * @param display is the display for which the vsync period is queried. @@ -131,7 +148,8 @@ interface IComposerClient extends @2.3::IComposerClient { /** * Sets the active configuration and the refresh rate for this display. - * If the config is the same as the current config, only the vsync period shall change. + * If the new config shares the same config group as the current config, + * only the vsync period shall change. * Upon returning, the given display configuration, except vsync period, must be active and * remain so until either this function is called again or the display is disconnected. * When the display starts to refresh at the new vsync period, onVsync_2_4 callback must be @@ -139,21 +157,19 @@ interface IComposerClient extends @2.3::IComposerClient { * * @param display is the display for which the active config is set. * @param config is the new display configuration. - * @param vsyncPeriodNanos is the new display vsync period. * @param vsyncPeriodChangeConstraints are the constraints required for changing vsync period. * * @return error is NONE upon success. Otherwise, * BAD_DISPLAY when an invalid display handle was passed in. * BAD_CONFIG when the configuration handle passed in is not valid * for this display. - * BAD_VSYNC_PERIOD when an invalid vsync period is passed in. + * SEAMLESS_NOT_ALLOWED when seamlessRequired was true but config provided doesn't + * share the same config group as the current config. * SEAMLESS_NOT_POSSIBLE when seamlessRequired was true but the display cannot achieve * the vsync period change without a noticeable visual artifact. - * @return newVsyncAppliedTime is the time in CLOCK_MONOTONIC when the new display will start to - * refresh at the new vsync period. + * @return timeline is the timeline for the vsync period change. */ - setActiveConfigAndVsyncPeriod(Display display, Config config, - VsyncPeriodNanos vsyncPeriodNanos, + setActiveConfigWithConstraints(Display display, Config config, VsyncPeriodChangeConstraints vsyncPeriodChangeConstraints) - generates (Error error, int64_t newVsyncAppliedTime); + generates (Error error, VsyncPeriodChangeTimeline timeline); }; diff --git a/graphics/composer/2.4/types.hal b/graphics/composer/2.4/types.hal index b45d7a69f7..065f024551 100644 --- a/graphics/composer/2.4/types.hal +++ b/graphics/composer/2.4/types.hal @@ -20,13 +20,36 @@ import @2.1::Error; enum Error : @2.1::Error { /** - * Invalid vsync period + * Seamless cannot be required for configurations that don't share a config group */ - BAD_VSYNC_PERIOD = 9, + SEAMLESS_NOT_ALLOWED = 9, /** * Seamless requirements cannot be met */ SEAMLESS_NOT_POSSIBLE = 10, }; +/** + * Timing for a vsync period change. + */ +struct VsyncPeriodChangeTimeline { + /** + * The time in CLOCK_MONOTONIC when the new display will start to refresh at + * the new vsync period. + */ + int64_t newVsyncAppliedTimeNanos; + + /** + * Set to true if the client is required to send a frame to be displayed before + * the change can take place. + */ + bool refreshRequired; + + /** + * The time in CLOCK_MONOTONIC when the client is expected to send the new frame. + * Should be ignored if refreshRequired is false. + */ + int64_t refreshTimeNanos; +}; + typedef uint32_t VsyncPeriodNanos; diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h index ddf209bee3..4160ed97bf 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h @@ -76,6 +76,13 @@ class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImplonVsyncPeriodTimingChanged(display, updatedTimeline); + ALOGE_IF(!ret.isOk(), "failed to send onVsyncPeriodTimingChanged: %s", + ret.description().c_str()); + } + protected: const sp mCallback; V2_1::hal::ComposerResources* const mResources; @@ -104,13 +111,12 @@ class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImpl getSupportedDisplayVsyncPeriods( - Display display, Config config, - IComposerClient::getSupportedDisplayVsyncPeriods_cb hidl_cb) override { - std::vector supportedVsyncPeriods; - Error error = - mHal->getSupportedDisplayVsyncPeriods(display, config, &supportedVsyncPeriods); - hidl_cb(error, supportedVsyncPeriods); + Return getDisplayAttribute_2_4( + Display display, Config config, IComposerClient::Attribute attribute, + IComposerClient::getDisplayAttribute_2_4_cb hidl_cb) override { + int32_t value = 0; + Error error = mHal->getDisplayAttribute_2_4(display, config, attribute, &value); + hidl_cb(error, value); return Void(); } @@ -122,15 +128,14 @@ class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImpl setActiveConfigAndVsyncPeriod( - Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos, + Return setActiveConfigWithConstraints( + Display display, Config config, const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, - IComposerClient::setActiveConfigAndVsyncPeriod_cb hidl_cb) override { - int64_t newVsyncAppliedTime = 0; - Error error = mHal->setActiveConfigAndVsyncPeriod(display, config, vsyncPeriodNanos, - vsyncPeriodChangeConstraints, - &newVsyncAppliedTime); - hidl_cb(error, newVsyncAppliedTime); + IComposerClient::setActiveConfigWithConstraints_cb hidl_cb) override { + VsyncPeriodChangeTimeline timeline = {}; + Error error = mHal->setActiveConfigWithConstraints(display, config, + vsyncPeriodChangeConstraints, &timeline); + hidl_cb(error, timeline); return Void(); } diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h index 0739f625ab..89dbe66d60 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h @@ -47,6 +47,8 @@ class ComposerHal : public V2_3::hal::ComposerHal { virtual void onVsync(Display display, int64_t timestamp) = 0; virtual void onVsync_2_4(Display display, int64_t timestamp, VsyncPeriodNanos vsyncPeriodNanos) = 0; + virtual void onVsyncPeriodTimingChanged(Display display, + const VsyncPeriodChangeTimeline& timeline) = 0; }; virtual void registerEventCallback_2_4(EventCallback_2_4* callback) = 0; @@ -57,13 +59,14 @@ class ComposerHal : public V2_3::hal::ComposerHal { Display display, std::vector* outCapabilities) = 0; virtual Error getDisplayConnectionType(Display display, IComposerClient::DisplayConnectionType* outType) = 0; - virtual Error getSupportedDisplayVsyncPeriods( - Display display, Config config, std::vector* outVsyncPeriod) = 0; + virtual Error getDisplayAttribute_2_4(Display display, Config config, + IComposerClient::Attribute attribute, + int32_t* outValue) = 0; virtual Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) = 0; - virtual Error setActiveConfigAndVsyncPeriod( - Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos, + virtual Error setActiveConfigWithConstraints( + Display display, Config config, const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, - int64_t* outNewVsyncAppliedTime) = 0; + VsyncPeriodChangeTimeline* timeline) = 0; }; } // namespace hal diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h index 3420c8cc07..d59d0d5361 100644 --- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h +++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h @@ -25,6 +25,7 @@ #include #include #include +#include namespace android { namespace hardware { @@ -51,14 +52,22 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { void registerEventCallback_2_4(hal::ComposerHal::EventCallback_2_4* callback) override { mEventCallback_2_4 = callback; - mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this, - reinterpret_cast(hotplugHook)); - mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this, - reinterpret_cast(refreshHook)); - mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this, - reinterpret_cast(vsyncHook)); - mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_2_4, this, - reinterpret_cast(vsync_2_4_Hook)); + BaseType2_1::mDispatch.registerCallback( + mDevice, HWC2_CALLBACK_HOTPLUG, this, + reinterpret_cast(hotplugHook)); + BaseType2_1::mDispatch.registerCallback( + mDevice, HWC2_CALLBACK_REFRESH, this, + reinterpret_cast(refreshHook)); + BaseType2_1::mDispatch.registerCallback( + mDevice, HWC2_CALLBACK_VSYNC, this, + reinterpret_cast(vsyncHook)); + BaseType2_1::mDispatch.registerCallback( + mDevice, HWC2_CALLBACK_VSYNC_2_4, this, + reinterpret_cast(vsync_2_4_Hook)); + + BaseType2_1::mDispatch.registerCallback( + mDevice, HWC2_CALLBACK_VSYNC_PERIOD_TIMING_CHANGED, this, + reinterpret_cast(vsyncPeriodTimingChangedHook)); } void unregisterEventCallback_2_4() override { @@ -69,10 +78,12 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { // - will never be called afterward // // which is likely incorrect - mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this, nullptr); - mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this, nullptr); - mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this, nullptr); - mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_2_4, this, nullptr); + BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this, nullptr); + BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this, nullptr); + BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this, nullptr); + BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_2_4, this, nullptr); + BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_PERIOD_TIMING_CHANGED, + this, nullptr); mEventCallback_2_4 = nullptr; } @@ -106,26 +117,16 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { return static_cast(error); } - Error getSupportedDisplayVsyncPeriods(Display display, Config config, - std::vector* outVsyncPeriods) override { - if (!mDispatch.getSupportedDisplayVsyncPeriods) { - return Error::UNSUPPORTED; + Error getDisplayAttribute_2_4(Display display, Config config, + IComposerClient::Attribute attribute, + int32_t* outValue) override { + int32_t err = BaseType2_1::mDispatch.getDisplayAttribute( + mDevice, display, config, static_cast(attribute), outValue); + if (err != HWC2_ERROR_NONE && *outValue == -1) { + // Convert the error from hwcomposer2 to IComposerClient definition + return Error::BAD_PARAMETER; } - - uint32_t count = 0; - int32_t error = mDispatch.getSupportedDisplayVsyncPeriods(mDevice, display, config, &count, - nullptr); - if (error != HWC2_ERROR_NONE) { - return static_cast(error); - } - outVsyncPeriods->resize(count); - error = mDispatch.getSupportedDisplayVsyncPeriods(mDevice, display, config, &count, - outVsyncPeriods->data()); - if (error != HWC2_ERROR_NONE) { - *outVsyncPeriods = std::vector(); - return static_cast(error); - } - return Error::NONE; + return static_cast(err); } Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) override { @@ -140,11 +141,11 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { return Error::NONE; } - Error setActiveConfigAndVsyncPeriod( - Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos, + Error setActiveConfigWithConstraints( + Display display, Config config, const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, - int64_t* outNewVsyncAppliedTime) override { - if (!mDispatch.setActiveConfigAndVsyncPeriod) { + VsyncPeriodChangeTimeline* timeline) override { + if (!mDispatch.setActiveConfigWithConstraints) { return Error::UNSUPPORTED; } @@ -154,12 +155,15 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { vsync_period_change_constraints.seamlessRequired = vsyncPeriodChangeConstraints.seamlessRequired; - int32_t error = mDispatch.setActiveConfigAndVsyncPeriod( - mDevice, display, config, vsyncPeriodNanos, &vsync_period_change_constraints, - outNewVsyncAppliedTime); + hwc_vsync_period_change_timeline_t out_timeline; + int32_t error = mDispatch.setActiveConfigWithConstraints( + mDevice, display, config, &vsync_period_change_constraints, &out_timeline); if (error != HWC2_ERROR_NONE) { return static_cast(error); } + timeline->newVsyncAppliedTimeNanos = out_timeline.newVsyncAppliedTimeNanos; + timeline->refreshRequired = out_timeline.refreshRequired; + timeline->refreshTimeNanos = out_timeline.refreshTimeNanos; return Error::NONE; } @@ -171,13 +175,10 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_CONNECTION_TYPE, &mDispatch.getDisplayConnectionType); - this->initOptionalDispatch(HWC2_FUNCTION_REGISTER_CALLBACK, &mDispatch.registerCallback); - this->initOptionalDispatch(HWC2_FUNCTION_GET_SUPPORTED_DISPLAY_VSYNC_PERIODS, - &mDispatch.getSupportedDisplayVsyncPeriods); this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_VSYNC_PERIOD, &mDispatch.getDisplayVsyncPeriod); - this->initOptionalDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_AND_VSYNC_PERIOD, - &mDispatch.setActiveConfigAndVsyncPeriod); + this->initOptionalDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS, + &mDispatch.setActiveConfigWithConstraints); return true; } @@ -205,13 +206,22 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { hal->mEventCallback_2_4->onVsync_2_4(display, timestamp, vsyncPeriodNanos); } + static void vsyncPeriodTimingChangedHook(hwc2_callback_data_t callbackData, + hwc2_display_t display, + hwc_vsync_period_change_timeline_t* updated_timeline) { + auto hal = static_cast(callbackData); + VsyncPeriodChangeTimeline timeline; + timeline.newVsyncAppliedTimeNanos = updated_timeline->newVsyncAppliedTimeNanos; + timeline.refreshRequired = updated_timeline->refreshRequired; + timeline.refreshTimeNanos = updated_timeline->refreshTimeNanos; + hal->mEventCallback_2_4->onVsyncPeriodTimingChanged(display, timeline); + } + private: struct { HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE getDisplayConnectionType; - HWC2_PFN_REGISTER_CALLBACK registerCallback; - HWC2_PFN_GET_SUPPORTED_DISPLAY_VSYNC_PERIODS getSupportedDisplayVsyncPeriods; HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD getDisplayVsyncPeriod; - HWC2_PFN_SET_ACTIVE_CONFIG_AND_VSYNC_PERIOD setActiveConfigAndVsyncPeriod; + HWC2_PFN_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS setActiveConfigWithConstraints; } mDispatch = {}; hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr; diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp index b02a59a90a..35ac23f7ff 100644 --- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp @@ -70,15 +70,18 @@ Error ComposerClient::getDisplayConnectionType(Display display, return error; } -Error ComposerClient::getSupportedDisplayVsyncPeriods( - Display display, Config config, std::vector* outSupportedVsyncPeriods) { - Error error = Error::NONE; - mClient->getSupportedDisplayVsyncPeriods( - display, config, [&](const auto& tmpError, const auto& tmpSupportedVsyncPeriods) { - error = tmpError; - *outSupportedVsyncPeriods = tmpSupportedVsyncPeriods; +int32_t ComposerClient::getDisplayAttribute_2_4( + android::hardware::graphics::composer::V2_1::Display display, + android::hardware::graphics::composer::V2_1::Config config, + IComposerClient::Attribute attribute) { + int32_t value = 0; + mClient->getDisplayAttribute_2_4( + display, config, attribute, [&](const auto& tmpError, const auto& tmpValue) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to get display attribute"; + value = tmpValue; }); - return error; + + return value; } Error ComposerClient::getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) { @@ -90,17 +93,16 @@ Error ComposerClient::getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* o return error; } -Error ComposerClient::setActiveConfigAndVsyncPeriod( - Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos, +Error ComposerClient::setActiveConfigWithConstraints( + Display display, Config config, const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, - int64_t* outNewVsyncAppliedTime) { + VsyncPeriodChangeTimeline* timeline) { Error error = Error::NONE; - mClient->setActiveConfigAndVsyncPeriod( - display, config, vsyncPeriodNanos, vsyncPeriodChangeConstraints, - [&](const auto& tmpError, const auto& tmpNewVsyncAppliedTime) { - error = tmpError; - *outNewVsyncAppliedTime = tmpNewVsyncAppliedTime; - }); + mClient->setActiveConfigWithConstraints(display, config, vsyncPeriodChangeConstraints, + [&](const auto& tmpError, const auto& tmpTimeline) { + error = tmpError; + *timeline = tmpTimeline; + }); return error; } diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h index 5db3e16eaf..83e74ed698 100644 --- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h @@ -74,15 +74,15 @@ class ComposerClient : public V2_3::vts::ComposerClient { Error getDisplayConnectionType(Display display, IComposerClient::DisplayConnectionType* outType); - Error getSupportedDisplayVsyncPeriods(Display display, Config config, - std::vector* outSupportedVsyncPeriods); + int32_t getDisplayAttribute_2_4(Display display, Config config, + IComposerClient::Attribute attribute); Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriods); - Error setActiveConfigAndVsyncPeriod( - Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos, + Error setActiveConfigWithConstraints( + Display display, Config config, const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, - int64_t* outNewVsyncAppliedTime); + VsyncPeriodChangeTimeline* timeline); private: const sp mClient; diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index 2c87666efb..f038f551e3 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -114,7 +114,7 @@ class GraphicsComposerHidlTest : public ::testing::TestWithParam { void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } - void Test_setActiveConfigAndVsyncPeriod( + void Test_setActiveConfigWithConstraints( const IComposerClient::VsyncPeriodChangeConstraints& constraints); std::unique_ptr mComposer; @@ -194,42 +194,28 @@ TEST_P(GraphicsComposerHidlTest, getDisplayConnectionType) { } } -TEST_P(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods_BadDisplay) { - std::vector supportedVsyncPeriods; - EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->getSupportedDisplayVsyncPeriods( - mInvalidDisplayId, Config(0), &supportedVsyncPeriods)); -} +TEST_P(GraphicsComposerHidlTest, GetDisplayAttribute_2_4) { + std::vector configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay); + for (auto config : configs) { + const std::array requiredAttributes = {{ + IComposerClient::Attribute::WIDTH, + IComposerClient::Attribute::HEIGHT, + IComposerClient::Attribute::VSYNC_PERIOD, + IComposerClient::Attribute::CONFIG_GROUP, + }}; + for (auto attribute : requiredAttributes) { + mComposerClient->getDisplayAttribute_2_4(mPrimaryDisplay, config, attribute); + } -TEST_P(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods_BadConfig) { - for (Display display : mComposerCallback->getDisplays()) { - Config invalidConfigId = GetInvalidConfigId(display); - std::vector supportedVsyncPeriods; - EXPECT_EQ(Error::BAD_CONFIG, mComposerClient->getSupportedDisplayVsyncPeriods( - display, invalidConfigId, &supportedVsyncPeriods)); - } -} - -TEST_P(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods) { - for (Display display : mComposerCallback->getDisplays()) { - for (Config config : mComposerClient->getDisplayConfigs(display)) { - std::vector supportedVsyncPeriods; - - // Get the default vsync period from the config - VsyncPeriodNanos defaultVsyncPeiord = mComposerClient->getDisplayAttribute( - display, config, IComposerClient::Attribute::VSYNC_PERIOD); - // Get all supported vsync periods for this config - EXPECT_EQ(Error::NONE, mComposerClient->getSupportedDisplayVsyncPeriods( - display, config, &supportedVsyncPeriods)); - // Default vsync period must be present in the list - EXPECT_NE(std::find(supportedVsyncPeriods.begin(), supportedVsyncPeriods.end(), - defaultVsyncPeiord), - supportedVsyncPeriods.end()); - - // Each vsync period must be unique - std::unordered_set vsyncPeriodSet; - for (VsyncPeriodNanos vsyncPeriodNanos : supportedVsyncPeriods) { - EXPECT_TRUE(vsyncPeriodSet.insert(vsyncPeriodNanos).second); - } + const std::array optionalAttributes = {{ + IComposerClient::Attribute::DPI_X, + IComposerClient::Attribute::DPI_Y, + }}; + for (auto attribute : optionalAttributes) { + mComposerClient->getRaw()->getDisplayAttribute_2_4( + mPrimaryDisplay, config, attribute, [&](const auto& tmpError, const auto&) { + EXPECT_TRUE(tmpError == Error::NONE || tmpError == Error::UNSUPPORTED); + }); } } } @@ -240,20 +226,40 @@ TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod_BadDisplay) { mComposerClient->getDisplayVsyncPeriod(mInvalidDisplayId, &vsyncPeriodNanos)); } -TEST_P(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadDisplay) { - int64_t newVsyncAppliedTime; +TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod) { + for (Display display : mComposerCallback->getDisplays()) { + for (Config config : mComposerClient->getDisplayConfigs(display)) { + mComposerClient->setActiveConfig(display, config); + + VsyncPeriodNanos vsyncPeriodNanos; + VsyncPeriodNanos expectedvsyncPeriodNanos = mComposerClient->getDisplayAttribute_2_4( + display, config, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD); + int retryCount = 100; + do { + std::this_thread::sleep_for(10ms); + EXPECT_EQ(Error::NONE, + mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); + --retryCount; + } while (retryCount > 0); + + EXPECT_EQ(vsyncPeriodNanos, expectedvsyncPeriodNanos); + } + } +} + +TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_BadDisplay) { + VsyncPeriodChangeTimeline timeline; IComposerClient::VsyncPeriodChangeConstraints constraints; constraints.seamlessRequired = false; constraints.desiredTimeNanos = systemTime(); - EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setActiveConfigAndVsyncPeriod( - mInvalidDisplayId, Config(0), VsyncPeriodNanos(0), - constraints, &newVsyncAppliedTime)); + EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setActiveConfigWithConstraints( + mInvalidDisplayId, Config(0), constraints, &timeline)); } -TEST_P(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadConfig) { - int64_t newVsyncAppliedTime; +TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_BadConfig) { + VsyncPeriodChangeTimeline timeline; IComposerClient::VsyncPeriodChangeConstraints constraints; constraints.seamlessRequired = false; @@ -261,93 +267,114 @@ TEST_P(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadConfig) { for (Display display : mComposerCallback->getDisplays()) { Config invalidConfigId = GetInvalidConfigId(display); - EXPECT_EQ(Error::BAD_CONFIG, mComposerClient->setActiveConfigAndVsyncPeriod( - display, invalidConfigId, VsyncPeriodNanos(0), - constraints, &newVsyncAppliedTime)); + EXPECT_EQ(Error::BAD_CONFIG, mComposerClient->setActiveConfigWithConstraints( + display, invalidConfigId, constraints, &timeline)); } } -TEST_P(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadVsyncPeriod) { - int64_t newVsyncAppliedTime; +TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_SeamlessNotAllowed) { + VsyncPeriodChangeTimeline timeline; IComposerClient::VsyncPeriodChangeConstraints constraints; - constraints.seamlessRequired = false; + constraints.seamlessRequired = true; constraints.desiredTimeNanos = systemTime(); for (Display display : mComposerCallback->getDisplays()) { for (Config config : mComposerClient->getDisplayConfigs(display)) { - EXPECT_EQ(Error::BAD_VSYNC_PERIOD, mComposerClient->setActiveConfigAndVsyncPeriod( - display, config, VsyncPeriodNanos(0), - constraints, &newVsyncAppliedTime)); - } - } -} + int32_t configGroup = mComposerClient->getDisplayAttribute_2_4( + display, config, IComposerClient::IComposerClient::Attribute::CONFIG_GROUP); -void GraphicsComposerHidlTest::Test_setActiveConfigAndVsyncPeriod( - const IComposerClient::VsyncPeriodChangeConstraints& constraints) { - int64_t newVsyncAppliedTime; - - for (Display display : mComposerCallback->getDisplays()) { - for (Config config : mComposerClient->getDisplayConfigs(display)) { - std::vector supportedVsyncPeriods; - - EXPECT_EQ(Error::NONE, mComposerClient->getSupportedDisplayVsyncPeriods( - display, config, &supportedVsyncPeriods)); - for (VsyncPeriodNanos newVsyncPeriod : supportedVsyncPeriods) { - VsyncPeriodNanos vsyncPeriodNanos; - EXPECT_EQ(Error::NONE, - mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); - - if (vsyncPeriodNanos == newVsyncPeriod) { - continue; + for (Config otherConfig : mComposerClient->getDisplayConfigs(display)) { + int32_t otherConfigGroup = mComposerClient->getDisplayAttribute_2_4( + display, otherConfig, + IComposerClient::IComposerClient::Attribute::CONFIG_GROUP); + if (configGroup != otherConfigGroup) { + mComposerClient->setActiveConfig(display, config); + EXPECT_EQ(Error::SEAMLESS_NOT_ALLOWED, + mComposerClient->setActiveConfigWithConstraints( + display, otherConfig, constraints, &timeline)); } - - EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigAndVsyncPeriod( - display, config, newVsyncPeriod, constraints, - &newVsyncAppliedTime)); - - EXPECT_TRUE(newVsyncAppliedTime >= constraints.desiredTimeNanos); - - // Refresh rate should change within a reasonable time - constexpr nsecs_t kReasonableTimeForChange = 1'000'000'000; // 1 second - EXPECT_TRUE(newVsyncAppliedTime - constraints.desiredTimeNanos <= - kReasonableTimeForChange); - - while (systemTime() <= newVsyncAppliedTime) { - EXPECT_EQ(Error::NONE, - mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); - if (systemTime() <= constraints.desiredTimeNanos) { - EXPECT_NE(vsyncPeriodNanos, newVsyncPeriod); - } - - if (vsyncPeriodNanos == newVsyncPeriod) { - break; - } - std::this_thread::sleep_for(10ms); - } - EXPECT_EQ(Error::NONE, - mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); - EXPECT_EQ(vsyncPeriodNanos, newVsyncPeriod); } } } } -TEST_P(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod) { +void GraphicsComposerHidlTest::Test_setActiveConfigWithConstraints( + const IComposerClient::VsyncPeriodChangeConstraints& constraints) { + VsyncPeriodChangeTimeline timeline = {}; + + for (Display display : mComposerCallback->getDisplays()) { + for (Config config : mComposerClient->getDisplayConfigs(display)) { + mComposerClient->setActiveConfig(display, config); + + int32_t configVsyncPeriod = mComposerClient->getDisplayAttribute_2_4( + display, config, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD); + for (Config otherConfig : mComposerClient->getDisplayConfigs(display)) { + if (config == otherConfig) { + continue; + } + + int32_t otherVsyncPeriod = mComposerClient->getDisplayAttribute_2_4( + display, otherConfig, + IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD); + + if (configVsyncPeriod == otherVsyncPeriod) { + continue; + } + + EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigWithConstraints( + display, otherConfig, constraints, &timeline)); + + if (timeline.refreshRequired) { + // TODO(b/143775556): handle this case; + continue; + } + + EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos >= constraints.desiredTimeNanos); + + // Refresh rate should change within a reasonable time + constexpr nsecs_t kReasonableTimeForChange = 1'000'000'000; // 1 second + EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos - constraints.desiredTimeNanos <= + kReasonableTimeForChange); + + while (systemTime() <= timeline.newVsyncAppliedTimeNanos) { + VsyncPeriodNanos vsyncPeriodNanos; + EXPECT_EQ(Error::NONE, + mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); + + if (systemTime() <= constraints.desiredTimeNanos) { + EXPECT_NE(vsyncPeriodNanos, otherVsyncPeriod); + } + + if (vsyncPeriodNanos == otherVsyncPeriod) { + break; + } + std::this_thread::sleep_for(10ms); + } + VsyncPeriodNanos vsyncPeriodNanos; + EXPECT_EQ(Error::NONE, + mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); + EXPECT_EQ(vsyncPeriodNanos, otherVsyncPeriod); + } + } + } +} + +TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints) { IComposerClient::VsyncPeriodChangeConstraints constraints; constraints.seamlessRequired = false; constraints.desiredTimeNanos = systemTime(); - Test_setActiveConfigAndVsyncPeriod(constraints); + Test_setActiveConfigWithConstraints(constraints); } -TEST_P(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_delayed) { +TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_delayed) { IComposerClient::VsyncPeriodChangeConstraints constraints; constexpr auto kDelayForChange = 300ms; constraints.seamlessRequired = false; constraints.desiredTimeNanos = systemTime() + kDelayForChange.count(); - Test_setActiveConfigAndVsyncPeriod(constraints); + Test_setActiveConfigWithConstraints(constraints); } INSTANTIATE_TEST_SUITE_P( From 0001a5d5ba5376403491b2bd06f7a665a4065c84 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Mon, 11 Nov 2019 10:50:05 -0800 Subject: [PATCH 0265/1022] gralloc: list supported metadata types Add function to get the metadata types supported by IMapper. In future releases, we will add more standard types but upgrading devices may not support those types. This function will allow the framework to identify which metadata types the device supports. Bug: 141632767 Test: VtsHalGraphicsMapperV4_0TargetTest Change-Id: I760cf054d2b6f08a52ad70f4ae60a39a63500939 --- graphics/mapper/4.0/IMapper.hal | 38 ++++++++++ .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 70 +++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal index a5413826ce..888b2afd53 100644 --- a/graphics/mapper/4.0/IMapper.hal +++ b/graphics/mapper/4.0/IMapper.hal @@ -515,5 +515,43 @@ interface IMapper { MetadataType metadataType) generates (Error error, vec metadata); + + struct MetadataTypeDescription { + MetadataType metadataType; + /** + * description should contain a string representation of the MetadataType. + * + * For example: "MyExampleMetadataType is a 64-bit timestamp in nanoseconds + * that indicates when a buffer is decoded. It is set by the media HAL after + * a buffer is decoded. It is used by the display HAL for hardware + * synchronization". + * + * This field is required for any non-StandardMetadataTypes. + */ + string description; + /** + * isGettable represents if the MetadataType can be get. + */ + bool isGettable; + /** + * isSettable represents if the MetadataType can be set. + */ + bool isSettable; + }; + + /** + * Lists all the MetadataTypes supported by IMapper as well as a description + * of each supported MetadataType. For StandardMetadataTypes, the description + * string can be left empty. + * + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of + * resources. + * @return descriptions Vector of MetadataTypeDescriptions that represent the + * MetadataTypes supported by the device. + */ + listSupportedMetadataTypes() + generates (Error error, vec descriptions); }; diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 1e8ec01e33..2a66cbf0dd 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -41,6 +41,7 @@ using aidl::android::hardware::graphics::common::Dataspace; using aidl::android::hardware::graphics::common::ExtendableType; using aidl::android::hardware::graphics::common::PlaneLayout; using aidl::android::hardware::graphics::common::PlaneLayoutComponent; +using aidl::android::hardware::graphics::common::StandardMetadataType; using DecodeFunction = std::function& vec)>; @@ -162,6 +163,27 @@ class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase { std::unique_ptr mGralloc; IMapper::BufferDescriptorInfo mDummyDescriptorInfo{}; + static const std::set sRequiredMetadataTypes; +}; + +const std::set GraphicsMapperHidlTest::sRequiredMetadataTypes{ + StandardMetadataType::BUFFER_ID, + StandardMetadataType::NAME, + StandardMetadataType::WIDTH, + StandardMetadataType::HEIGHT, + StandardMetadataType::LAYER_COUNT, + StandardMetadataType::PIXEL_FORMAT_REQUESTED, + StandardMetadataType::PIXEL_FORMAT_FOURCC, + StandardMetadataType::PIXEL_FORMAT_MODIFIER, + StandardMetadataType::USAGE, + StandardMetadataType::ALLOCATION_SIZE, + StandardMetadataType::PROTECTED_CONTENT, + StandardMetadataType::COMPRESSION, + StandardMetadataType::INTERLACED, + StandardMetadataType::CHROMA_SITING, + StandardMetadataType::PLANE_LAYOUTS, + StandardMetadataType::DATASPACE, + StandardMetadataType::BLEND_MODE, }; /** @@ -1591,6 +1613,54 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedStandardMet ASSERT_EQ(0, vec.size()); } +/** + * Test IMapper::listSupportedMetadataTypes() + */ +TEST_F(GraphicsMapperHidlTest, ListSupportedMetadataTypes) { + hidl_vec descriptions; + mGralloc->getMapper()->listSupportedMetadataTypes( + [&](const auto& tmpError, const auto& tmpDescriptions) { + ASSERT_EQ(Error::NONE, tmpError); + descriptions = tmpDescriptions; + }); + + std::set foundMetadataTypes; + + std::set notSettableMetadataTypes{ + StandardMetadataType::BUFFER_ID, StandardMetadataType::NAME, + StandardMetadataType::WIDTH, StandardMetadataType::HEIGHT, + StandardMetadataType::LAYER_COUNT, StandardMetadataType::PIXEL_FORMAT_REQUESTED, + StandardMetadataType::USAGE}; + + ASSERT_LE(sRequiredMetadataTypes.size(), descriptions.size()); + + for (const auto& description : descriptions) { + const auto& metadataType = description.metadataType; + + if (!gralloc4::isStandardMetadataType(metadataType)) { + EXPECT_GT(0, description.description.size()); + continue; + } + + StandardMetadataType type = gralloc4::getStandardMetadataTypeValue(metadataType); + + if (sRequiredMetadataTypes.find(type) == sRequiredMetadataTypes.end()) { + continue; + } + + ASSERT_EQ(foundMetadataTypes.find(type), foundMetadataTypes.end()); + foundMetadataTypes.insert(type); + + ASSERT_TRUE(description.isGettable); + + if (notSettableMetadataTypes.find(type) != notSettableMetadataTypes.end()) { + ASSERT_FALSE(description.isSettable); + } + } + + ASSERT_EQ(sRequiredMetadataTypes, foundMetadataTypes); +} + } // namespace } // namespace vts } // namespace V4_0 From 697cb33c45a36982c4346b20aa360207359ad9ea Mon Sep 17 00:00:00 2001 From: Keun young Park Date: Wed, 20 Nov 2019 18:29:35 -0800 Subject: [PATCH 0266/1022] Add DISABLED_OPTIONAL_FEATURES property - This allows disabling specific optional features in car service from vehicle hal layer. Bug: 144504820 Test: run with car service Change-Id: I419ad86b75151aba129730bdc75c9bc1e47333cf --- automotive/vehicle/2.0/types.hal | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index 279d5cd30a..24fcf76b2f 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -2381,6 +2381,26 @@ enum VehicleProperty : int32_t { | VehiclePropertyType:BOOLEAN | VehicleArea:GLOBAL), + /** + * Allow disabling optional featurs from vhal. + * + * This property reports optional features that should be disabled. + * All allowed optional features for the system is declared in Car service overlay, + * config_allowed_optional_car_features. + * This property allows disabling features defined in the overlay. Without this property, + * all the features declared in the overlay will be enabled. + * + * Value read should include all features disabled with ',' separation. + * ex) "com.android.car.user.CarUserNoticeService,storage_monitoring" + * @change_mode VehiclePropertyChangeMode:STATIC + * @access VehiclePropertyAccess:READ + */ + DISABLED_OPTIONAL_FEATURES = ( + 0x0F06 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:STRING + | VehicleArea:GLOBAL), + }; /** From 7eab6201a9421b48888294dd9e719678022fb102 Mon Sep 17 00:00:00 2001 From: "Harpreet \\\"Eli\\\" Sangha" Date: Wed, 23 Oct 2019 09:25:52 +0900 Subject: [PATCH 0267/1022] vibrator: Add Composition APIs Bug: 139762802 Test: Manual Invocation via 'idlcli' Change-Id: Ibc938d08f186039681d523784b90f4172a52af51 Signed-off-by: Harpreet \"Eli\" Sangha --- .../hardware/vibrator/CompositeEffect.aidl | 28 ++++ .../hardware/vibrator/CompositePrimitive.aidl | 29 +++++ .../android/hardware/vibrator/IVibrator.aidl | 45 ++++++- vibrator/aidl/default/Vibrator.cpp | 58 ++++++++- .../default/include/vibrator-impl/Vibrator.h | 6 +- .../aidl/vts/VtsHalVibratorTargetTest.cpp | 122 +++++++++++++++++- 6 files changed, 275 insertions(+), 13 deletions(-) create mode 100644 vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl create mode 100644 vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl diff --git a/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl b/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl new file mode 100644 index 0000000000..84556b57bb --- /dev/null +++ b/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl @@ -0,0 +1,28 @@ +/* + * 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. + */ + +package android.hardware.vibrator; + +import android.hardware.vibrator.CompositePrimitive; + +@VintfStability +parcelable CompositeEffect { + /* Period of silence preceding primitive. */ + int delayMs; + CompositePrimitive primitive; + /* 0.0 (exclusive) - 1.0 (inclusive) */ + float scale; +} diff --git a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl new file mode 100644 index 0000000000..2a9d0be31d --- /dev/null +++ b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package android.hardware.vibrator; + +@VintfStability +@Backing(type="int") +enum CompositePrimitive { + NOOP, + CLICK, + THUD, + SPIN, + QUICK_RISE, + SLOW_RISE, + QUICK_FALL, +} diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl index 8c4fd055c3..ebf5faa47a 100644 --- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl +++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl @@ -19,6 +19,8 @@ package android.hardware.vibrator; import android.hardware.vibrator.IVibratorCallback; import android.hardware.vibrator.Effect; import android.hardware.vibrator.EffectStrength; +import android.hardware.vibrator.CompositeEffect; +import android.hardware.vibrator.CompositePrimitive; @VintfStability interface IVibrator { @@ -42,6 +44,10 @@ interface IVibrator { * Whether setAmplitude is supported (when external control is enabled) */ const int CAP_EXTERNAL_AMPLITUDE_CONTROL = 1 << 4; + /** + * Whether compose is supported. + */ + const int CAP_COMPOSE_EFFECTS = 1 << 5; /** * Determine capabilities of the vibrator HAL (CAP_* mask) @@ -107,11 +113,10 @@ interface IVibrator { * CAP_EXTERNAL_AMPLITUDE_CONTROL. * * @param amplitude The unitless force setting. Note that this number must - * be between 1 and 255, inclusive. If the motor does not - * have exactly 255 steps, it must do it's best to map it - * onto the number of steps it does have. + * be between 0.0 (exclusive) and 1.0 (inclusive). It must + * do it's best to map it onto the number of steps it does have. */ - void setAmplitude(in int amplitude); + void setAmplitude(in float amplitude); /** * Enables/disables control override of vibrator to audio. @@ -128,4 +133,36 @@ interface IVibrator { * @param enabled Whether external control should be enabled or disabled. */ void setExternalControl(in boolean enabled); + + /** + * Retrieve composition delay limit. + * + * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS). + * + * @return Maximum delay for a single CompositeEffect[] entry. + */ + int getCompositionDelayMax(); + + /** + * Retrieve composition size limit. + * + * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS). + * + * @return Maximum number of entries in CompositeEffect[]. + * @param maxDelayMs Maximum delay for a single CompositeEffect[] entry. + */ + int getCompositionSizeMax(); + + /** + * Fire off a string of effect primitives, combined to perform richer effects. + * + * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS). + * + * Doing this operation while the vibrator is already on is undefined behavior. Clients should + * explicitly call off. + * + * @param composite Array of composition parameters. + */ + void compose(in CompositeEffect[] composite, in IVibratorCallback callback); + } diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp index 09cd2345bf..a77c49a0a2 100644 --- a/vibrator/aidl/default/Vibrator.cpp +++ b/vibrator/aidl/default/Vibrator.cpp @@ -24,11 +24,14 @@ namespace android { namespace hardware { namespace vibrator { +static constexpr int32_t kComposeDelayMaxMs = 1000; +static constexpr int32_t kComposeSizeMax = 256; + ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) { LOG(INFO) << "Vibrator reporting capabilities"; *_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK | IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL | - IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL; + IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS; return ndk::ScopedAStatus::ok(); } @@ -84,9 +87,9 @@ ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector* _aidl_retu return ndk::ScopedAStatus::ok(); } -ndk::ScopedAStatus Vibrator::setAmplitude(int32_t amplitude) { +ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) { LOG(INFO) << "Vibrator set amplitude: " << amplitude; - if (amplitude <= 0 || amplitude > 255) { + if (amplitude <= 0.0f || amplitude > 1.0f) { return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT)); } return ndk::ScopedAStatus::ok(); @@ -97,6 +100,55 @@ ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) { return ndk::ScopedAStatus::ok(); } +ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t* maxDelayMs) { + *maxDelayMs = kComposeDelayMaxMs; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* maxSize) { + *maxSize = kComposeSizeMax; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::compose(const std::vector& composite, + const std::shared_ptr& callback) { + if (composite.size() > kComposeSizeMax) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + + for (auto& e : composite) { + if (e.delayMs > kComposeDelayMaxMs) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + if (e.scale <= 0.0f || e.scale > 1.0f) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + if (e.primitive < CompositePrimitive::NOOP || + e.primitive > CompositePrimitive::QUICK_FALL) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + } + + std::thread([=] { + LOG(INFO) << "Starting compose on another thread"; + + for (auto& e : composite) { + if (e.delayMs) { + usleep(e.delayMs * 1000); + } + LOG(INFO) << "triggering primitive " << static_cast(e.primitive) << " @ scale " + << e.scale; + } + + if (callback != nullptr) { + LOG(INFO) << "Notifying perform complete"; + callback->onComplete(); + } + }).detach(); + + return ndk::ScopedAStatus::ok(); +} + } // namespace vibrator } // namespace hardware } // namespace android diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h index 14e7292b43..817ec805fa 100644 --- a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h +++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h @@ -32,8 +32,12 @@ class Vibrator : public BnVibrator { const std::shared_ptr& callback, int32_t* _aidl_return) override; ndk::ScopedAStatus getSupportedEffects(std::vector* _aidl_return) override; - ndk::ScopedAStatus setAmplitude(int32_t amplitude) override; + ndk::ScopedAStatus setAmplitude(float amplitude) override; ndk::ScopedAStatus setExternalControl(bool enabled) override; + ndk::ScopedAStatus getCompositionDelayMax(int32_t* maxDelayMs); + ndk::ScopedAStatus getCompositionSizeMax(int32_t* maxSize); + ndk::ScopedAStatus compose(const std::vector& composite, + const std::shared_ptr& callback) override; }; } // namespace vibrator diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp index b6aa9e2fd0..5c6120b6f5 100644 --- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp +++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp @@ -28,6 +28,8 @@ using android::sp; using android::String16; using android::binder::Status; using android::hardware::vibrator::BnVibratorCallback; +using android::hardware::vibrator::CompositeEffect; +using android::hardware::vibrator::CompositePrimitive; using android::hardware::vibrator::Effect; using android::hardware::vibrator::EffectStrength; using android::hardware::vibrator::IVibrator; @@ -55,6 +57,20 @@ const std::vector kInvalidEffectStrengths = { static_cast(static_cast(kEffectStrengths.back()) + 1), }; +// TODO(b/143992652): autogenerate +const std::vector kCompositePrimitives = { + CompositePrimitive::NOOP, CompositePrimitive::CLICK, + CompositePrimitive::THUD, CompositePrimitive::SPIN, + CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE, + CompositePrimitive::QUICK_FALL, +}; +// TODO(b/143992652): autogenerate + +const std::vector kInvalidPrimitives = { + static_cast(static_cast(kCompositePrimitives.front()) - 1), + static_cast(static_cast(kCompositePrimitives.back()) + 1), +}; + class CompletionCallback : public BnVibratorCallback { public: CompletionCallback(const std::function& callback) : mCallback(callback) {} @@ -201,11 +217,11 @@ TEST_P(VibratorAidl, InvalidEffectsUnsupported) { TEST_P(VibratorAidl, ChangeVibrationAmplitude) { if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) { - EXPECT_TRUE(vibrator->setAmplitude(1).isOk()); + EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(0.1f).exceptionCode()); EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk()); - EXPECT_TRUE(vibrator->setAmplitude(128).isOk()); + EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(0.5f).exceptionCode()); sleep(1); - EXPECT_TRUE(vibrator->setAmplitude(255).isOk()); + EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(1.0f).exceptionCode()); sleep(1); } } @@ -214,7 +230,7 @@ TEST_P(VibratorAidl, AmplitudeOutsideRangeFails) { if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) { EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(-1).exceptionCode()); EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(0).exceptionCode()); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(256).exceptionCode()); + EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(1.1).exceptionCode()); } } @@ -240,7 +256,7 @@ TEST_P(VibratorAidl, ExternalAmplitudeControl) { if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) { EXPECT_TRUE(vibrator->setExternalControl(true).isOk()); - Status amplitudeStatus = vibrator->setAmplitude(128); + Status amplitudeStatus = vibrator->setAmplitude(0.5); if (supportsExternalAmplitudeControl) { EXPECT_TRUE(amplitudeStatus.isOk()); } else { @@ -259,6 +275,102 @@ TEST_P(VibratorAidl, ExternalControlUnsupportedMatchingCapabilities) { } } +TEST_P(VibratorAidl, ComposeValidPrimitives) { + if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { + int32_t maxDelay, maxSize; + + EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode()); + EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode()); + + std::vector composite; + + for (auto primitive : kCompositePrimitives) { + CompositeEffect effect; + + effect.delayMs = std::rand() % (maxDelay + 1); + effect.primitive = primitive; + effect.scale = static_cast(std::rand()) / RAND_MAX ?: 1.0f; + composite.emplace_back(effect); + + if (composite.size() == maxSize) { + EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode()); + composite.clear(); + vibrator->off(); + } + } + + if (composite.size() != 0) { + EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode()); + vibrator->off(); + } + } +} + +TEST_P(VibratorAidl, ComposeUnsupportedPrimitives) { + if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { + for (auto primitive : kInvalidPrimitives) { + std::vector composite(1); + + for (auto& effect : composite) { + effect.delayMs = 0; + effect.primitive = primitive; + effect.scale = 1.0f; + } + EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, + vibrator->compose(composite, nullptr).exceptionCode()); + vibrator->off(); + } + } +} + +TEST_P(VibratorAidl, CompseDelayBoundary) { + if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { + int32_t maxDelay; + + EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode()); + + std::vector composite(1); + CompositeEffect effect; + + effect.delayMs = 1; + effect.primitive = CompositePrimitive::CLICK; + effect.scale = 1.0f; + + std::fill(composite.begin(), composite.end(), effect); + EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode()); + + effect.delayMs = maxDelay + 1; + + std::fill(composite.begin(), composite.end(), effect); + EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, + vibrator->compose(composite, nullptr).exceptionCode()); + vibrator->off(); + } +} + +TEST_P(VibratorAidl, CompseSizeBoundary) { + if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { + int32_t maxSize; + + EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode()); + + std::vector composite(maxSize); + CompositeEffect effect; + + effect.delayMs = 1; + effect.primitive = CompositePrimitive::CLICK; + effect.scale = 1.0f; + + std::fill(composite.begin(), composite.end(), effect); + EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode()); + + composite.emplace_back(effect); + EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, + vibrator->compose(composite, nullptr).exceptionCode()); + vibrator->off(); + } +} + INSTANTIATE_TEST_SUITE_P(Vibrator, VibratorAidl, testing::ValuesIn(android::getAidlHalInstanceNames(IVibrator::descriptor)), android::PrintInstanceNameToString); From 3f17cc3daa2a81127f736e13346d95e35c710e65 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Wed, 20 Nov 2019 13:55:16 +0000 Subject: [PATCH 0268/1022] Add TENSOR_QUANT8_ASYMM_SIGNED support for pooling ops * Update AVERAGE_POOL_2D and MAX_POOL_2D Bug: 143934716 Bug: 143934303 Test: quantization coupling tests in CTS and VTS Change-Id: I15f36d6f819c92f96a46c40f9cc1491627644278 --- current.txt | 2 +- neuralnetworks/1.3/types.hal | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/current.txt b/current.txt index 0433a1c912..b1171f027e 100644 --- a/current.txt +++ b/current.txt @@ -602,7 +602,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice 4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -103cb87c5ed46851badac097f8d190da60f39b5ab32d60e2e93f64d3014ea75c android.hardware.neuralnetworks@1.3::types +6256b2b1df586fc01e80ecf001770d941385602682ec2055ba7b3979a02c8ebf android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant 44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index db86bf6ea1..3641355221 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -149,6 +149,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -210,7 +211,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, out_height, out_width, depth]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ AVERAGE_POOL_2D = @1.2::OperationType:AVERAGE_POOL_2D, @@ -1259,6 +1261,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -1320,7 +1323,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, out_height, out_width, depth]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ MAX_POOL_2D = @1.2::OperationType:MAX_POOL_2D, From 3466c78b04ee9cbbd8622157ef1357f1dfb5bb6a Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Thu, 21 Nov 2019 17:35:30 +0000 Subject: [PATCH 0269/1022] Add TENSOR_QUANT8_ASYMM_SIGNED support for activations Ops updated: RELU, RELU1, RELU6, TANH, LOGISTIC Change-Id: Id5e7a8c6b30463708bd93dbf6a3f30d05c2bcf40 Fix: 143933951 Fix: 143934720 Fix: 143933831 Fix: 143934770 Fix: 143934743 Test: quantization coupling tests in CTS and VTS --- current.txt | 2 +- neuralnetworks/1.3/types.hal | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/current.txt b/current.txt index b1171f027e..4b4c8cb47e 100644 --- a/current.txt +++ b/current.txt @@ -602,7 +602,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice 4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -6256b2b1df586fc01e80ecf001770d941385602682ec2055ba7b3979a02c8ebf android.hardware.neuralnetworks@1.3::types +2d16429145dc1158bf3e45c7de86a39e461dec3ec00512c11a7e5249535a2e96 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant 44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index 3641355221..3551d5762a 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -956,6 +956,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4. * @@ -967,6 +968,8 @@ enum OperationType : int32_t { * * 0: The output tensor of same shape as input0. * For {@link OperandType::TENSOR_QUANT8_ASYMM}, * the scale must be 1.f / 256 and the zeroPoint must be 0. + * For {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, + * the scale must be 1.f / 256 and the zeroPoint must be -128. */ LOGISTIC = @1.2::OperationType:LOGISTIC, @@ -1384,6 +1387,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4. * @@ -1393,7 +1397,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of same shape as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ RELU = @1.2::OperationType:RELU, @@ -1409,6 +1414,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4. * @@ -1418,7 +1424,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of the same shape as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ RELU1 = @1.2::OperationType:RELU1, @@ -1434,6 +1441,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4. * @@ -1443,7 +1451,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of same shape as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ RELU6 = @1.2::OperationType:RELU6, @@ -1764,6 +1773,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4. * @@ -1775,6 +1785,8 @@ enum OperationType : int32_t { * * 0: The output tensor of same shape as input0. * For {@link OperandType::TENSOR_QUANT8_ASYMM}, * the scale must be 1.f / 128 and the zeroPoint must be 128. + * For {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, + * the scale must be 1.f / 128 and the zeroPoint must be 0. */ TANH = @1.2::OperationType:TANH, From cda8e6e03a37face2ddaccd2a1198c8dd0ef2375 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Thu, 7 Nov 2019 11:40:54 -0800 Subject: [PATCH 0270/1022] Implement the connector for emulated vehicles Some functions are copyed from the original VHAL implementation. The ones left in the old implementation will be removed after enabling the Vehicle Connector. Keeping them right now because otherwise it will break the build. Bug: b/141493212 Test: since nothing changed in the "active" code, just compiled by `mm` Change-Id: Ibf525ffe056d6a4c789a7a407eb0b54f61858041 --- .../vhal_v2_0/EmulatedVehicleConnector.cpp | 254 ++++++++++++++++++ .../impl/vhal_v2_0/EmulatedVehicleConnector.h | 110 ++++++++ 2 files changed, 364 insertions(+) create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp new file mode 100644 index 0000000000..168999d829 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp @@ -0,0 +1,254 @@ +/* + * 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. + */ +#include +#include + +#include "DefaultConfig.h" +#include "EmulatedVehicleConnector.h" +#include "JsonFakeValueGenerator.h" +#include "LinearFakeValueGenerator.h" +#include "Obd2SensorStore.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +void EmulatedVehicleClient::onPropertyValue(const VehiclePropValue& value) { + if (!mPropCallback) { + LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!"; + return; + } + return mPropCallback(value); +} + +void EmulatedVehicleClient::registerPropertyValueCallback(PropertyCallBackType&& callback) { + if (mPropCallback) { + LOG(ERROR) << __func__ << ": Cannot register multiple callbacks!"; + return; + } + mPropCallback = std::move(callback); +} + +GeneratorHub* EmulatedVehicleServer::getGenerator() { + return &mGeneratorHub; +} + +VehiclePropValuePool* EmulatedVehicleServer::getValuePool() const { + if (!mValuePool) { + LOG(WARNING) << __func__ << ": Value pool not set!"; + } + return mValuePool; +} + +void EmulatedVehicleServer::setValuePool(VehiclePropValuePool* valuePool) { + if (!valuePool) { + LOG(WARNING) << __func__ << ": Setting value pool to nullptr!"; + } + mValuePool = valuePool; +} + +void EmulatedVehicleServer::onFakeValueGenerated(const VehiclePropValue& value) { + LOG(DEBUG) << __func__ << ": " << toString(value); + auto updatedPropValue = getValuePool()->obtain(value); + if (updatedPropValue) { + updatedPropValue->timestamp = value.timestamp; + updatedPropValue->status = VehiclePropertyStatus::AVAILABLE; + onPropertyValueFromCar(*updatedPropValue); + } +} + +std::vector EmulatedVehicleServer::onGetAllPropertyConfig() const { + std::vector vehiclePropConfigs; + constexpr size_t numOfVehiclePropConfigs = + sizeof(kVehicleProperties) / sizeof(kVehicleProperties[0]); + vehiclePropConfigs.reserve(numOfVehiclePropConfigs); + for (auto& it : kVehicleProperties) { + vehiclePropConfigs.emplace_back(it.config); + } + return vehiclePropConfigs; +} + +StatusCode EmulatedVehicleServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) { + LOG(INFO) << __func__; + const auto& v = request.value; + if (!v.int32Values.size()) { + LOG(ERROR) << __func__ << ": expected at least \"command\" field in int32Values"; + return StatusCode::INVALID_ARG; + } + + FakeDataCommand command = static_cast(v.int32Values[0]); + + switch (command) { + case FakeDataCommand::StartLinear: { + LOG(INFO) << __func__ << ", FakeDataCommand::StartLinear"; + if (v.int32Values.size() < 2) { + LOG(ERROR) << __func__ << ": expected property ID in int32Values"; + return StatusCode::INVALID_ARG; + } + if (!v.int64Values.size()) { + LOG(ERROR) << __func__ << ": interval is not provided in int64Values"; + return StatusCode::INVALID_ARG; + } + if (v.floatValues.size() < 3) { + LOG(ERROR) << __func__ << ": expected at least 3 elements in floatValues, got: " + << v.floatValues.size(); + return StatusCode::INVALID_ARG; + } + int32_t cookie = v.int32Values[1]; + getGenerator()->registerGenerator(cookie, + std::make_unique(request)); + break; + } + case FakeDataCommand::StartJson: { + LOG(INFO) << __func__ << ", FakeDataCommand::StartJson"; + if (v.stringValue.empty()) { + LOG(ERROR) << __func__ << ": path to JSON file is missing"; + return StatusCode::INVALID_ARG; + } + int32_t cookie = std::hash()(v.stringValue); + getGenerator()->registerGenerator(cookie, + std::make_unique(request)); + break; + } + case FakeDataCommand::StopLinear: { + LOG(INFO) << __func__ << ", FakeDataCommand::StopLinear"; + if (v.int32Values.size() < 2) { + LOG(ERROR) << __func__ << ": expected property ID in int32Values"; + return StatusCode::INVALID_ARG; + } + int32_t cookie = v.int32Values[1]; + getGenerator()->unregisterGenerator(cookie); + break; + } + case FakeDataCommand::StopJson: { + LOG(INFO) << __func__ << ", FakeDataCommand::StopJson"; + if (v.stringValue.empty()) { + LOG(ERROR) << __func__ << ": path to JSON file is missing"; + return StatusCode::INVALID_ARG; + } + int32_t cookie = std::hash()(v.stringValue); + getGenerator()->unregisterGenerator(cookie); + break; + } + case FakeDataCommand::KeyPress: { + LOG(INFO) << __func__ << ", FakeDataCommand::KeyPress"; + int32_t keyCode = request.value.int32Values[2]; + int32_t display = request.value.int32Values[3]; + // Send back to HAL + onPropertyValueFromCar( + *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display)); + onPropertyValueFromCar( + *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display)); + break; + } + default: { + LOG(ERROR) << __func__ << ": unexpected command: " << toInt(command); + return StatusCode::INVALID_ARG; + } + } + return StatusCode::OK; +} + +VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createApPowerStateReq( + VehicleApPowerStateReq state, int32_t param) { + auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2); + req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ); + req->areaId = 0; + req->timestamp = elapsedRealtimeNano(); + req->status = VehiclePropertyStatus::AVAILABLE; + req->value.int32Values[0] = toInt(state); + req->value.int32Values[1] = param; + return req; +} + +VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createHwInputKeyProp( + VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) { + auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3); + keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT); + keyEvent->areaId = 0; + keyEvent->timestamp = elapsedRealtimeNano(); + keyEvent->status = VehiclePropertyStatus::AVAILABLE; + keyEvent->value.int32Values[0] = toInt(action); + keyEvent->value.int32Values[1] = keyCode; + keyEvent->value.int32Values[2] = targetDisplay; + return keyEvent; +} + +StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value) { + // Some properties need to be treated non-trivially + switch (value.prop) { + case AP_POWER_STATE_REPORT: + switch (value.value.int32Values[0]) { + case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT): + case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED): + case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL): + // CPMS is in WAIT_FOR_VHAL state, simply move to ON + // Send back to HAL + onPropertyValueFromCar( + *createApPowerStateReq(VehicleApPowerStateReq::ON, 0)); + break; + case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY): + case toInt(VehicleApPowerStateReport::SHUTDOWN_START): + // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command + // Send back to HAL + onPropertyValueFromCar( + *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0)); + break; + case toInt(VehicleApPowerStateReport::ON): + case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE): + case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE): + // Do nothing + break; + default: + // Unknown state + break; + } + break; + default: + break; + } + + // In the real vhal, the value will be sent to Car ECU. + // We just pretend it is done here. + return StatusCode::OK; +} + +StatusCode EmulatedVehicleServer::onSetPropertyFromVehicle(const VehiclePropValue& value) { + if (value.prop == kGenerateFakeDataControllingProperty) { + auto status = handleGenerateFakeDataRequest(value); + return status; + } else { + // Send back to HAL + onPropertyValueFromCar(value); + return StatusCode::OK; + } +} + +EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() { + return std::make_unique(); +} + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h new file mode 100644 index 0000000000..d424cd83e7 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h @@ -0,0 +1,110 @@ +/* + * 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_ +#define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_ + +#include +#include + +#include "GeneratorHub.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +// Extension of the client/server interfaces for emulated vehicle + +class EmulatedVehicleClient : public IVehicleClient { + public: + // Type of callback function for handling the new property values + using PropertyCallBackType = std::function; + + // Method from IVehicleClient + void onPropertyValue(const VehiclePropValue& value) override; + + // Request to change the value on the VEHICLE side (for testing) + virtual StatusCode setPropertyFromVehicle(const VehiclePropValue& value) = 0; + + void registerPropertyValueCallback(PropertyCallBackType&& callback); + + private: + PropertyCallBackType mPropCallback; +}; + +class EmulatedVehicleServer : public IVehicleServer { + public: + // Methods from IVehicleServer + + std::vector onGetAllPropertyConfig() const override; + + StatusCode onSetProperty(const VehiclePropValue& value) override; + + // Process the request to change the value on the VEHICLE side (for testing) + StatusCode onSetPropertyFromVehicle(const VehiclePropValue& value); + + // Set the Property Value Pool used in this server + void setValuePool(VehiclePropValuePool* valuePool); + + private: + GeneratorHub* getGenerator(); + + VehiclePropValuePool* getValuePool() const; + + void onFakeValueGenerated(const VehiclePropValue& value); + + StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request); + + VehicleHal::VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param); + + VehicleHal::VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, + int32_t keyCode, int32_t targetDisplay); + + // private data members + + GeneratorHub mGeneratorHub{ + std::bind(&EmulatedVehicleServer::onFakeValueGenerated, this, std::placeholders::_1)}; + + VehiclePropValuePool* mValuePool{nullptr}; +}; + +class EmulatedPassthroughConnector + : public IPassThroughConnector { + public: + StatusCode setPropertyFromVehicle(const VehiclePropValue& value) override { + return this->onSetPropertyFromVehicle(value); + } +}; + +// Helper functions + +using EmulatedPassthroughConnectorPtr = std::unique_ptr; + +EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector(); + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_ From 5be5483f4cb3d1b211c097be75240574eb178d8a Mon Sep 17 00:00:00 2001 From: Ytai Ben-Tsvi Date: Tue, 12 Nov 2019 10:44:26 -0800 Subject: [PATCH 0271/1022] More memory test interfaces Change-Id: I21bb7c28aa774801cad94cd530ccb6b5c3b621e0 Bug: 143566068 --- tests/memory/2.0/Android.bp | 12 ++++++++++++ tests/memory/2.0/IMemoryInterface.hal | 12 ++++++++++++ tests/memory/2.0/types.hal | 6 ++++++ 3 files changed, 30 insertions(+) create mode 100644 tests/memory/2.0/Android.bp create mode 100644 tests/memory/2.0/IMemoryInterface.hal create mode 100644 tests/memory/2.0/types.hal diff --git a/tests/memory/2.0/Android.bp b/tests/memory/2.0/Android.bp new file mode 100644 index 0000000000..5166652120 --- /dev/null +++ b/tests/memory/2.0/Android.bp @@ -0,0 +1,12 @@ +hidl_interface { + name: "android.hardware.tests.memory@2.0", + root: "android.hardware", + srcs: [ + "IMemoryInterface.hal", + "types.hal", + ], + interfaces: [ + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/tests/memory/2.0/IMemoryInterface.hal b/tests/memory/2.0/IMemoryInterface.hal new file mode 100644 index 0000000000..2c824bfdec --- /dev/null +++ b/tests/memory/2.0/IMemoryInterface.hal @@ -0,0 +1,12 @@ +package android.hardware.tests.memory@2.0; + +interface IMemoryInterface { + // Flips all the bits in the given memory buffer. + bitwiseNot(memory mem); + // Returns a read-only buffer of size 8, containing the bytes 0..7. + getTestMem() generates(memory mem); + // Given two memory regions of the same size, returns two memory fields of + // equal size, the first contains the byte-wise sum and the other the byte- + // wise difference. + getSumDiff(TwoMemory in) generates(TwoMemory out); +}; diff --git a/tests/memory/2.0/types.hal b/tests/memory/2.0/types.hal new file mode 100644 index 0000000000..9ec357ba9e --- /dev/null +++ b/tests/memory/2.0/types.hal @@ -0,0 +1,6 @@ +package android.hardware.tests.memory@2.0; + +struct TwoMemory { + memory mem1; + memory mem2; +}; From 2a652cec4b981ac50a00fc22f8393bf4a7f02f0a Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Thu, 21 Nov 2019 14:03:19 -0800 Subject: [PATCH 0272/1022] audio effect: Avoid using stack-allocated arrays This is to prevent OOB write in case when a sufficiently large HIDL vector is provided via a HwBinder call. Bug: 143787559 Test: atest VtsHalAudioEffectV5_0TargetTest Change-Id: I6ea78804a5a3ed7a245929d3de47580b12c0da9a --- audio/effect/all-versions/default/Effect.cpp | 28 +++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/audio/effect/all-versions/default/Effect.cpp b/audio/effect/all-versions/default/Effect.cpp index 0afa779f03..e11e123038 100644 --- a/audio/effect/all-versions/default/Effect.cpp +++ b/audio/effect/all-versions/default/Effect.cpp @@ -307,12 +307,11 @@ void Effect::getConfigImpl(int commandCode, const char* commandName, GetConfigCa Result Effect::getCurrentConfigImpl(uint32_t featureId, uint32_t configSize, GetCurrentConfigSuccessCallback onSuccess) { uint32_t halCmd = featureId; - uint32_t halResult[alignedSizeIn(sizeof(uint32_t) + configSize)]; - memset(halResult, 0, sizeof(halResult)); + std::vector halResult(alignedSizeIn(sizeof(uint32_t) + configSize), 0); uint32_t halResultSize = 0; - return sendCommandReturningStatusAndData(EFFECT_CMD_GET_FEATURE_CONFIG, "GET_FEATURE_CONFIG", - sizeof(uint32_t), &halCmd, &halResultSize, halResult, - sizeof(uint32_t), [&] { onSuccess(&halResult[1]); }); + return sendCommandReturningStatusAndData( + EFFECT_CMD_GET_FEATURE_CONFIG, "GET_FEATURE_CONFIG", sizeof(uint32_t), &halCmd, + &halResultSize, &halResult[0], sizeof(uint32_t), [&] { onSuccess(&halResult[1]); }); } Result Effect::getParameterImpl(uint32_t paramSize, const void* paramData, @@ -339,8 +338,7 @@ Result Effect::getSupportedConfigsImpl(uint32_t featureId, uint32_t maxConfigs, GetSupportedConfigsSuccessCallback onSuccess) { uint32_t halCmd[2] = {featureId, maxConfigs}; uint32_t halResultSize = 2 * sizeof(uint32_t) + maxConfigs * sizeof(configSize); - uint8_t halResult[halResultSize]; - memset(&halResult[0], 0, halResultSize); + std::vector halResult(static_cast(halResultSize), 0); return sendCommandReturningStatusAndData( EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS, "GET_FEATURE_SUPPORTED_CONFIGS", sizeof(halCmd), halCmd, &halResultSize, &halResult[0], 2 * sizeof(uint32_t), [&] { @@ -519,9 +517,9 @@ Return Effect::setAndGetVolume(const hidl_vec& volumes, uint32_t halDataSize; std::unique_ptr halData = hidlVecToHal(volumes, &halDataSize); uint32_t halResultSize = halDataSize; - uint32_t halResult[volumes.size()]; + std::vector halResult(volumes.size(), 0); Result retval = sendCommandReturningData(EFFECT_CMD_SET_VOLUME, "SET_VOLUME", halDataSize, - &halData[0], &halResultSize, halResult); + &halData[0], &halResultSize, &halResult[0]); hidl_vec result; if (retval == Result::OK) { result.setToExternal(&halResult[0], halResultSize); @@ -581,8 +579,6 @@ Return Effect::getSupportedAuxChannelsConfigs(uint32_t maxConfigs, } Return Effect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) { - uint32_t halResult[alignedSizeIn(sizeof(uint32_t) + sizeof(channel_config_t))]; - memset(halResult, 0, sizeof(halResult)); EffectAuxChannelsConfig result; Result retval = getCurrentConfigImpl( EFFECT_FEATURE_AUX_CHANNELS, sizeof(channel_config_t), [&](void* configData) { @@ -594,11 +590,12 @@ Return Effect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) { } Return Effect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) { - uint32_t halCmd[alignedSizeIn(sizeof(uint32_t) + sizeof(channel_config_t))]; + std::vector halCmd( + alignedSizeIn(sizeof(uint32_t) + sizeof(channel_config_t)), 0); halCmd[0] = EFFECT_FEATURE_AUX_CHANNELS; effectAuxChannelsConfigToHal(config, reinterpret_cast(&halCmd[1])); return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG, - "SET_FEATURE_CONFIG AUX_CHANNELS", sizeof(halCmd), halCmd); + "SET_FEATURE_CONFIG AUX_CHANNELS", halCmd.size(), &halCmd[0]); } Return Effect::setAudioSource(AudioSource source) { @@ -692,12 +689,11 @@ Return Effect::getCurrentConfigForFeature(uint32_t featureId, uint32_t con Return Effect::setCurrentConfigForFeature(uint32_t featureId, const hidl_vec& configData) { - uint32_t halCmd[alignedSizeIn(sizeof(uint32_t) + configData.size())]; - memset(halCmd, 0, sizeof(halCmd)); + std::vector halCmd(alignedSizeIn(sizeof(uint32_t) + configData.size()), 0); halCmd[0] = featureId; memcpy(&halCmd[1], &configData[0], configData.size()); return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG, "SET_FEATURE_CONFIG", - sizeof(halCmd), halCmd); + halCmd.size(), &halCmd[0]); } Return Effect::close() { From 3ebbb8273f9eeb32559249d2b9ab9f80ee68d9b5 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Wed, 20 Nov 2019 15:49:55 -0800 Subject: [PATCH 0273/1022] Add GRPC Server as a Library to VHal Build File Bug: b/141493212 Test: Tested with ag/9775633, successfully compiled, also tested with ag/9775563 Change-Id: Icf046aafe3d5794a8b79183baa370bdbbcdb796a --- .../default/impl/vhal_v2_0/proto/Android.bp | 61 +++++++++++++++++++ .../vhal_v2_0/proto/VehicleHalProto.proto | 1 - .../impl/vhal_v2_0/proto/VehicleServer.proto | 47 ++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto 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 6754843bf5..2eedecda2a 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 @@ -29,3 +29,64 @@ cc_library_static { ], srcs: ["VehicleHalProto.proto"] } + +cc_library_static { + name: "android.hardware.automotive.vehicle@2.0-grpc", + vendor: true, + include_dirs: [ + "external/protobuf/src", + ], + generated_headers: [ + "DefaultVehicleHalProtoStub_h", + ], + export_generated_headers: [ + "DefaultVehicleHalProtoStub_h", + ], + generated_sources: [ + "DefaultVehicleHalProtoStub_cc", + ], + shared_libs: [ + "libgrpc++_unsecure", + ], + cflags: [ + "-Wno-unused-parameter" + ], +} + +genrule { + name: "DefaultVehicleHalProtoStub_h", + tools: [ + "aprotoc", + "protoc-gen-grpc-cpp-plugin", + ], + cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)", + srcs: [ + "VehicleHalProto.proto", + "VehicleServer.proto", + ], + out: [ + "VehicleHalProto.pb.h", + "VehicleHalProto.grpc.pb.h", + "VehicleServer.pb.h", + "VehicleServer.grpc.pb.h", + ], +} + +genrule { + name: "DefaultVehicleHalProtoStub_cc", + tools: [ + "aprotoc", + "protoc-gen-grpc-cpp-plugin", + ], + cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)", + srcs: [ + "VehicleHalProto.proto", + "VehicleServer.proto", + ], + out: [ + "VehicleHalProto.pb.cc", + "VehicleHalProto.grpc.pb.cc", + "VehicleServer.pb.cc", + "VehicleServer.grpc.pb.cc", + ], +} diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto index 2ef64fbfab..04df5a8a21 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto @@ -15,7 +15,6 @@ */ syntax = "proto2"; -option optimize_for = LITE_RUNTIME; package emulator; diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto new file mode 100644 index 0000000000..7ce3c32273 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto @@ -0,0 +1,47 @@ +/* + * 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. + */ + +syntax = "proto2"; + +package emulator; + +import "google/protobuf/empty.proto"; +import "VehicleHalProto.proto"; + +// correspond to StatusCode defined in types.hal +enum VehicleHalStatusCode { + OK = 0; + TRY_AGAIN = 1; + INVALID_ARG = 2; + NOT_AVAILABLE = 3; + ACCESS_DENIED = 4; + INTERNAL_ERROR = 5; +} + +message VehicleHalCallStatus { + required VehicleHalStatusCode status_code = 1; +} + +service VehicleServer { + rpc GetAllPropertyConfig(google.protobuf.Empty) returns (stream VehiclePropConfig) {} + + // Change the property value of the vehicle + rpc SetProperty(VehiclePropValue) returns (VehicleHalCallStatus) {} + + // Start a vehicle property value stream + rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream VehiclePropValue) {} +} + From fba3ac86cc0f450bd01265313eff65279a38f590 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Thu, 7 Nov 2019 11:55:25 -0800 Subject: [PATCH 0274/1022] Applying the vehicle connector to the VHAL Make VHAL to use the connector/server interfaces instead of talking to the (faked) vehicle directly. Use passthrough connector for now since we have not moved to the virtualized scenario yet (but soon :) Bug: b/141493212 Test: On both Osprey and Hawk. Build and flash the image. If on Osprey, see go/enable-google-vhal-on-osprey; if on hawk, `aae app vhal apply google` to enable Google VHAL ``` # no VHAL crash $ adb logcat $ vts-tradefed > run vts-hal-auto -m VtsHalAutomotiveVehicleV2_0Host # 30 passed, 2 failed, the same as the result before this patch # See value changed in Vehicle HAL tab, KitchenSink app: $ python packages/services/Car/tools/emulator/prop_event_simulator.py --property VEHICLEPROPERTY_HVAC_AC_ON --area 0 --value 1 # unit tests $ atest packages/services/Car/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarPropertyTest.java ``` Change-Id: Iab77a0ae32db2c55b4c65aa8f3e4f73ec9ef2644 --- automotive/vehicle/2.0/default/Android.bp | 1 + .../vehicle/2.0/default/VehicleService.cpp | 7 +- .../impl/vhal_v2_0/EmulatedVehicleHal.cpp | 179 ++---------------- .../impl/vhal_v2_0/EmulatedVehicleHal.h | 11 +- 4 files changed, 31 insertions(+), 167 deletions(-) diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp index ed09859443..f9c25d1d0e 100644 --- a/automotive/vehicle/2.0/default/Android.bp +++ b/automotive/vehicle/2.0/default/Android.bp @@ -58,6 +58,7 @@ cc_library_static { defaults: ["vhal_v2_0_defaults"], srcs: [ "impl/vhal_v2_0/CommConn.cpp", + "impl/vhal_v2_0/EmulatedVehicleConnector.cpp", "impl/vhal_v2_0/EmulatedVehicleHal.cpp", "impl/vhal_v2_0/VehicleEmulator.cpp", "impl/vhal_v2_0/PipeComm.cpp", diff --git a/automotive/vehicle/2.0/default/VehicleService.cpp b/automotive/vehicle/2.0/default/VehicleService.cpp index d1fd55567e..127eb98e43 100644 --- a/automotive/vehicle/2.0/default/VehicleService.cpp +++ b/automotive/vehicle/2.0/default/VehicleService.cpp @@ -20,8 +20,9 @@ #include -#include +#include #include +#include using namespace android; using namespace android::hardware; @@ -29,9 +30,11 @@ using namespace android::hardware::automotive::vehicle::V2_0; int main(int /* argc */, char* /* argv */ []) { auto store = std::make_unique(); - auto hal = std::make_unique(store.get()); + auto connector = impl::makeEmulatedPassthroughConnector(); + auto hal = std::make_unique(store.get(), connector.get()); auto emulator = std::make_unique(hal.get()); auto service = std::make_unique(hal.get()); + connector->setValuePool(hal->getValuePool()); configureRpcThreadpool(4, true /* callerWillJoin */); 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 dc051d8e53..6508efea2b 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 @@ -87,17 +87,19 @@ static std::unique_ptr fillDefaultObd2Frame(size_t numVendorInt return sensorStore; } -EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore) +EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, + EmulatedVehicleClient* client) : mPropStore(propStore), mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)), mRecurrentTimer( std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)), - mGeneratorHub( - std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1)) { + mVehicleClient(client) { initStaticConfig(); for (size_t i = 0; i < arraysize(kVehicleProperties); i++) { mPropStore->registerProperty(kVehicleProperties[i].config); } + mVehicleClient->registerPropertyValueCallback( + std::bind(&EmulatedVehicleHal::onPropertyValue, this, std::placeholders::_1)); } VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get( @@ -162,7 +164,8 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { } if (propValue.prop == kGenerateFakeDataControllingProperty) { - StatusCode status = handleGenerateFakeDataRequest(propValue); + // send the generator controlling request to the server + auto status = mVehicleClient->setPropertyFromVehicle(propValue); if (status != StatusCode::OK) { return status; } @@ -186,29 +189,6 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { // Placeholder for future implementation of VMS property in the default hal. For // now, just returns OK; otherwise, hal clients crash with property not supported. return StatusCode::OK; - case AP_POWER_STATE_REPORT: - switch (propValue.value.int32Values[0]) { - case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT): - case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED): - case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL): - // CPMS is in WAIT_FOR_VHAL state, simply move to ON - doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::ON, 0)); - break; - case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY): - case toInt(VehicleApPowerStateReport::SHUTDOWN_START): - // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command - doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0)); - break; - case toInt(VehicleApPowerStateReport::ON): - case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE): - case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE): - // Do nothing - break; - default: - // Unknown state - break; - } - break; } } @@ -231,10 +211,16 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { /** * After checking all conditions, such as the property is available, a real vhal will * sent the events to Car ECU to take actions. - * Google HAL will just add a timestamp for the value and triggle the callback to android. */ VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(propValue); updatedPropValue->timestamp = elapsedRealtimeNano(); + + // Send the value to the vehicle server, the server will talk to the (real or emulated) car + auto setValueStatus = mVehicleClient->setProperty(*updatedPropValue); + if (setValueStatus != StatusCode::OK) { + return setValueStatus; + } + if (!mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus)) { return StatusCode::INTERNAL_ERROR; } @@ -361,144 +347,19 @@ bool EmulatedVehicleHal::isContinuousProperty(int32_t propId) const { } bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) { - static constexpr bool shouldUpdateStatus = true; - - if (propValue.prop == kGenerateFakeDataControllingProperty) { - StatusCode status = handleGenerateFakeDataRequest(propValue); - if (status != StatusCode::OK) { - return false; - } - } - - if (mPropStore->writeValue(propValue, shouldUpdateStatus)) { - doHalEvent(getValuePool()->obtain(propValue)); - return true; - } else { - return false; - } + return mVehicleClient->setPropertyFromVehicle(propValue) == StatusCode::OK; } std::vector EmulatedVehicleHal::getAllProperties() const { return mPropStore->readAllValues(); } -StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropValue& request) { - ALOGI("%s", __func__); - const auto& v = request.value; - if (!v.int32Values.size()) { - ALOGE("%s: expected at least \"command\" field in int32Values", __func__); - return StatusCode::INVALID_ARG; - } - - FakeDataCommand command = static_cast(v.int32Values[0]); - - switch (command) { - case FakeDataCommand::StartLinear: { - ALOGI("%s, FakeDataCommand::StartLinear", __func__); - if (v.int32Values.size() < 2) { - ALOGE("%s: expected property ID in int32Values", __func__); - return StatusCode::INVALID_ARG; - } - if (!v.int64Values.size()) { - ALOGE("%s: interval is not provided in int64Values", __func__); - return StatusCode::INVALID_ARG; - } - if (v.floatValues.size() < 3) { - ALOGE("%s: expected at least 3 elements in floatValues, got: %zu", __func__, - v.floatValues.size()); - return StatusCode::INVALID_ARG; - } - int32_t cookie = v.int32Values[1]; - mGeneratorHub.registerGenerator(cookie, - std::make_unique(request)); - break; - } - case FakeDataCommand::StartJson: { - ALOGI("%s, FakeDataCommand::StartJson", __func__); - if (v.stringValue.empty()) { - ALOGE("%s: path to JSON file is missing", __func__); - return StatusCode::INVALID_ARG; - } - int32_t cookie = std::hash()(v.stringValue); - mGeneratorHub.registerGenerator(cookie, - std::make_unique(request)); - break; - } - case FakeDataCommand::StopLinear: { - ALOGI("%s, FakeDataCommand::StopLinear", __func__); - if (v.int32Values.size() < 2) { - ALOGE("%s: expected property ID in int32Values", __func__); - return StatusCode::INVALID_ARG; - } - int32_t cookie = v.int32Values[1]; - mGeneratorHub.unregisterGenerator(cookie); - break; - } - case FakeDataCommand::StopJson: { - ALOGI("%s, FakeDataCommand::StopJson", __func__); - if (v.stringValue.empty()) { - ALOGE("%s: path to JSON file is missing", __func__); - return StatusCode::INVALID_ARG; - } - int32_t cookie = std::hash()(v.stringValue); - mGeneratorHub.unregisterGenerator(cookie); - break; - } - case FakeDataCommand::KeyPress: { - ALOGI("%s, FakeDataCommand::KeyPress", __func__); - int32_t keyCode = request.value.int32Values[2]; - int32_t display = request.value.int32Values[3]; - doHalEvent( - createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display)); - doHalEvent(createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display)); - break; - } - default: { - ALOGE("%s: unexpected command: %d", __func__, command); - return StatusCode::INVALID_ARG; - } - } - return StatusCode::OK; -} - -VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createApPowerStateReq( - VehicleApPowerStateReq state, int32_t param) { - auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2); - req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ); - req->areaId = 0; - req->timestamp = elapsedRealtimeNano(); - req->status = VehiclePropertyStatus::AVAILABLE; - req->value.int32Values[0] = toInt(state); - req->value.int32Values[1] = param; - return req; -} - -VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createHwInputKeyProp( - VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) { - auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3); - keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT); - keyEvent->areaId = 0; - keyEvent->timestamp = elapsedRealtimeNano(); - keyEvent->status = VehiclePropertyStatus::AVAILABLE; - keyEvent->value.int32Values[0] = toInt(action); - keyEvent->value.int32Values[1] = keyCode; - keyEvent->value.int32Values[2] = targetDisplay; - return keyEvent; -} - -void EmulatedVehicleHal::onFakeValueGenerated(const VehiclePropValue& value) { - ALOGD("%s: %s", __func__, toString(value).c_str()); - static constexpr bool shouldUpdateStatus = false; - +void EmulatedVehicleHal::onPropertyValue(const VehiclePropValue& value) { + static constexpr bool shouldUpdateStatus = true; VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value); - if (updatedPropValue) { - updatedPropValue->timestamp = value.timestamp; - updatedPropValue->status = VehiclePropertyStatus::AVAILABLE; - mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus); - auto changeMode = mPropStore->getConfigOrDie(value.prop)->changeMode; - if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) { - doHalEvent(std::move(updatedPropValue)); - } + + if (mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus)) { + doHalEvent(std::move(updatedPropValue)); } } diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h index 78895e3db2..98315ec32e 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h @@ -30,6 +30,7 @@ #include "vhal_v2_0/VehiclePropertyStore.h" #include "DefaultConfig.h" +#include "EmulatedVehicleConnector.h" #include "GeneratorHub.h" #include "VehicleEmulator.h" @@ -44,7 +45,8 @@ namespace impl { /** Implementation of VehicleHal that connected to emulator instead of real vehicle network. */ class EmulatedVehicleHal : public EmulatedVehicleHalIface { public: - EmulatedVehicleHal(VehiclePropertyStore* propStore); + EmulatedVehicleHal(VehiclePropertyStore* propStore, + EmulatedVehicleClient* client); ~EmulatedVehicleHal() = default; // Methods from VehicleHal @@ -66,10 +68,7 @@ private: } StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request); - void onFakeValueGenerated(const VehiclePropValue& value); - VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param); - VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode, - int32_t targetDisplay); + void onPropertyValue(const VehiclePropValue& value); void onContinuousPropertyTimer(const std::vector& properties); bool isContinuousProperty(int32_t propId) const; @@ -85,7 +84,7 @@ private: VehiclePropertyStore* mPropStore; std::unordered_set mHvacPowerProps; RecurrentTimer mRecurrentTimer; - GeneratorHub mGeneratorHub; + EmulatedVehicleClient* mVehicleClient; }; } // impl From 9c5ebfc5ba3b90231391bb77d717699f7198f2fb Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Tue, 5 Nov 2019 14:59:27 -0800 Subject: [PATCH 0275/1022] gralloc: update lock and lockYCbCr IMapper 4.0 does support lockYCbCr functionality through lock and BufferMetadata getters. However, we will wait to add the support in one central gralloc library. For now just stub out the call so there aren't any compiler errors. Bug: 141631415 Test: Compiles Change-Id: I9d2f70c87412f8ac2114db85eb6dc01539876e2b --- camera/common/1.0/default/HandleImporter.cpp | 11 ++- .../composer/2.1/utils/vts/ComposerVts.cpp | 5 +- graphics/mapper/4.0/IMapper.hal | 60 +++---------- graphics/mapper/4.0/types.hal | 29 ------- graphics/mapper/4.0/utils/vts/MapperVts.cpp | 38 +-------- .../vts/include/mapper-vts/4.0/MapperVts.h | 5 +- .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 84 ++----------------- 7 files changed, 29 insertions(+), 203 deletions(-) diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp index 76f97789c0..ac32c954c4 100644 --- a/camera/common/1.0/default/HandleImporter.cpp +++ b/camera/common/1.0/default/HandleImporter.cpp @@ -252,8 +252,7 @@ void* HandleImporter::lock( // No need to use bytesPerPixel and bytesPerStride because we are using // an 1-D buffer and accressRegion. mMapperV4->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle, - [&](const auto& tmpError, const auto& tmpPtr, const auto& /*bytesPerPixel*/, - const auto& /*bytesPerStride*/) { + [&](const auto& tmpError, const auto& tmpPtr) { if (tmpError == MapperErrorV4::NONE) { ret = tmpPtr; } else { @@ -301,7 +300,13 @@ YCbCrLayout HandleImporter::lockYCbCr( } if (mMapperV4 != nullptr) { - return lockYCbCrInternal(mMapperV4, buf, cpuUsage, accessRegion); + // No device currently supports IMapper 4.0 so it is safe to just return an error code here. + // + // This will be supported by a combination of lock and BufferMetadata getters. We are going + // to refactor all the IAllocator/IMapper versioning code into a shared library. We will + // then add the IMapper 4.0 lockYCbCr support then. + ALOGE("%s: MapperV4 doesn't support lockYCbCr directly!", __FUNCTION__); + return {}; } if (mMapperV3 != nullptr) { diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp index a0745cef60..a8e1480d4f 100644 --- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp @@ -369,10 +369,7 @@ void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, accessRegion.top = accessRegionRect.top; accessRegion.width = accessRegionRect.width; accessRegion.height = accessRegionRect.height; - int32_t bytesPerPixel; - int32_t bytesPerStride; - return mGralloc4->lock(bufferHandle, cpuUsage, accessRegion, acquireFence, &bytesPerPixel, - &bytesPerStride); + return mGralloc4->lock(bufferHandle, cpuUsage, accessRegion, acquireFence); } else if (mGralloc3) { IMapper3::Rect accessRegion; accessRegion.left = accessRegionRect.left; diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal index a5413826ce..98ac02c020 100644 --- a/graphics/mapper/4.0/IMapper.hal +++ b/graphics/mapper/4.0/IMapper.hal @@ -199,16 +199,20 @@ interface IMapper { * outside of @p accessRegion is undefined, except that it must not cause * process termination. * + * This function can lock both single-planar and multi-planar formats. The caller + * should use get() to get information about the buffer they are locking. + * get() can be used to get information about the planes, offsets, stride, + * etc. + * + * This function must also work on buffers with + * `AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_*` if supported by the device, as well + * as with any other formats requested by multimedia codecs when they are + * configured with a flexible-YUV-compatible color format. + * * On success, @p data must be filled with a pointer to the locked buffer * memory. This address will represent the top-left corner of the entire * buffer, even if @p accessRegion does not begin at the top-left corner. * - * On success, bytesPerPixel must contain the number of bytes per pixel in - * the buffer. If the bytesPerPixel is unknown or variable, a value of -1 - * should be returned. bytesPerStride must contain the bytes per stride of - * the buffer. If the bytesPerStride is unknown or variable, a value of -1 - * should be returned. - * * The locked buffer must adhere to the format requested at allocation time * in the BufferDescriptorInfo. * @@ -231,55 +235,13 @@ interface IMapper { * - `NO_RESOURCES` if the buffer cannot be locked at this time. Note * that locking may succeed at a later time. * @return data CPU-accessible pointer to the buffer data. - * @return bytesPerPixel the number of bytes per pixel in the buffer - * @return bytesPerStride the number of bytes per stride of the buffer */ lock(pointer buffer, uint64_t cpuUsage, Rect accessRegion, handle acquireFence) generates (Error error, - pointer data, - int32_t bytesPerPixel, - int32_t bytesPerStride); - - /** - * Locks a YCbCr buffer for the specified CPU usage. - * - * This is largely the same as lock(), except that instead of returning a - * pointer directly to the buffer data, it returns a `YCbCrLayout` struct - * describing how to access the data planes. - * - * This function must work on buffers with - * `AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_*` if supported by the device, as well - * as with any other formats requested by multimedia codecs when they are - * configured with a flexible-YUV-compatible color format. - * - * @param buffer Buffer to lock. - * @param cpuUsage CPU usage flags to request. See +ndk - * libnativewindow#AHardwareBuffer_UsageFlags for possible values. - * @param accessRegion Portion of the buffer that the client intends to - * access. - * @param acquireFence Handle containing a file descriptor referring to a - * sync fence object, which will be signaled when it is safe for the - * mapper to lock the buffer. @p acquireFence may be empty if it is - * already safe to lock. - * @return error Error status of the call, which may be - * - `NONE` upon success. - * - `BAD_BUFFER` if the buffer is invalid or is incompatible with this - * function. - * - `BAD_VALUE` if @p cpuUsage is 0, contains non-CPU usage flags, or - * is incompatible with the buffer. - * - `NO_RESOURCES` if the buffer cannot be locked at this time. Note - * that locking may succeed at a later time. - * @return layout Data layout of the locked buffer. - */ - lockYCbCr(pointer buffer, - uint64_t cpuUsage, - Rect accessRegion, - handle acquireFence) - generates (Error error, - YCbCrLayout layout); + pointer data); /** * Unlocks a buffer to indicate all CPU accesses to the buffer have diff --git a/graphics/mapper/4.0/types.hal b/graphics/mapper/4.0/types.hal index 2fdfa6586b..00b660743a 100644 --- a/graphics/mapper/4.0/types.hal +++ b/graphics/mapper/4.0/types.hal @@ -53,32 +53,3 @@ enum Error : int32_t { */ typedef vec BufferDescriptor; -/** - * Structure for describing YCbCr formats for consumption by applications. - * This is used with PixelFormat::YCBCR_*_888. - * - * Buffer chroma subsampling is defined in the format. - * e.g. PixelFormat::YCBCR_420_888 has subsampling 4:2:0. - * - * Buffers must have a 8 bit depth. - * - * y, cb, and cr point to the first byte of their respective planes. - * - * Stride describes the distance in bytes from the first value of one row of - * the image to the first value of the next row. It includes the width of the - * image plus padding. - * yStride is the stride of the luma plane. - * cStride is the stride of the chroma planes. - * - * chromaStep is the distance in bytes from one chroma pixel value to the - * next. This is 2 bytes for semiplanar (because chroma values are interleaved - * and each chroma value is one byte) and 1 for planar. - */ -struct YCbCrLayout { - pointer y; - pointer cb; - pointer cr; - uint32_t yStride; - uint32_t cStride; - uint32_t chromaStep; -}; diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp index 531f31131c..8073e6924c 100644 --- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp +++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp @@ -199,8 +199,7 @@ void Gralloc::freeBuffer(const native_handle_t* bufferHandle) { } void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, - const IMapper::Rect& accessRegion, int acquireFence, int32_t* outBytesPerPixel, - int32_t* outBytesPerStride) { + const IMapper::Rect& accessRegion, int acquireFence) { auto buffer = const_cast(bufferHandle); NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0); @@ -211,17 +210,11 @@ void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, acquireFenceHandle = h; } - *outBytesPerPixel = -1; - *outBytesPerStride = -1; - void* data = nullptr; mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle, - [&](const auto& tmpError, const auto& tmpData, int32_t tmpBytesPerPixel, - int32_t tmpBytesPerStride) { + [&](const auto& tmpError, const auto& tmpData) { ASSERT_EQ(Error::NONE, tmpError) << "failed to lock buffer " << buffer; data = tmpData; - *outBytesPerPixel = tmpBytesPerPixel; - *outBytesPerStride = tmpBytesPerStride; }); if (acquireFence >= 0) { @@ -231,33 +224,6 @@ void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, return data; } -YCbCrLayout Gralloc::lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage, - const IMapper::Rect& accessRegion, int acquireFence) { - auto buffer = const_cast(bufferHandle); - - NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0); - hidl_handle acquireFenceHandle; - if (acquireFence >= 0) { - auto h = native_handle_init(acquireFenceStorage, 1, 0); - h->data[0] = acquireFence; - acquireFenceHandle = h; - } - - YCbCrLayout layout = {}; - mMapper->lockYCbCr(buffer, cpuUsage, accessRegion, acquireFenceHandle, - [&](const auto& tmpError, const auto& tmpLayout) { - ASSERT_EQ(Error::NONE, tmpError) - << "failed to lockYCbCr buffer " << buffer; - layout = tmpLayout; - }); - - if (acquireFence >= 0) { - close(acquireFence); - } - - return layout; -} - int Gralloc::unlock(const native_handle_t* bufferHandle) { auto buffer = const_cast(bufferHandle); diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h index 28555fa05d..6251e6649c 100644 --- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h +++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h @@ -70,10 +70,7 @@ class Gralloc { // in and out of the mapper. The ownership of the fd is always transferred // with each of these functions. void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, - const IMapper::Rect& accessRegion, int acquireFence, int32_t* outBytesPerPixel, - int32_t* outBytesPerStride); - YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage, - const IMapper::Rect& accessRegion, int acquireFence); + const IMapper::Rect& accessRegion, int acquireFence); int unlock(const native_handle_t* bufferHandle); bool validateBufferSize(const native_handle_t* bufferHandle, diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 1e8ec01e33..781476fba4 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -20,6 +20,9 @@ #include #include +//#include +//#include + #include #include #include @@ -391,15 +394,8 @@ TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) { static_cast(info.height)}; int fence = -1; uint8_t* data; - int32_t bytesPerPixel = -1; - int32_t bytesPerStride = -1; ASSERT_NO_FATAL_FAILURE( - data = static_cast(mGralloc->lock(bufferHandle, info.usage, region, fence, - &bytesPerPixel, &bytesPerStride))); - - // Valid return values are -1 for unsupported or the number bytes for supported which is >=0 - EXPECT_GT(bytesPerPixel, -1); - EXPECT_GT(bytesPerStride, -1); + data = static_cast(mGralloc->lock(bufferHandle, info.usage, region, fence))); // RGBA_8888 size_t strideInBytes = stride * 4; @@ -412,13 +408,9 @@ TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) { ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); - bytesPerPixel = -1; - bytesPerStride = -1; - // lock again for reading ASSERT_NO_FATAL_FAILURE( - data = static_cast(mGralloc->lock(bufferHandle, info.usage, region, fence, - &bytesPerPixel, &bytesPerStride))); + data = static_cast(mGralloc->lock(bufferHandle, info.usage, region, fence))); for (uint32_t y = 0; y < info.height; y++) { for (size_t i = 0; i < writeInBytes; i++) { EXPECT_EQ(static_cast(y), data[i]); @@ -426,69 +418,6 @@ TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) { data += strideInBytes; } - EXPECT_GT(bytesPerPixel, -1); - EXPECT_GT(bytesPerStride, -1); - - ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); - if (fence >= 0) { - close(fence); - } -} - -/** - * Test IMapper::lockYCbCr. This locks a YV12 buffer, and makes sure we can - * write to and read from it. - */ -TEST_F(GraphicsMapperHidlTest, LockYCbCrBasic) { - auto info = mDummyDescriptorInfo; - info.format = PixelFormat::YV12; - - const native_handle_t* bufferHandle; - uint32_t stride; - ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, false, &stride)); - - // lock buffer for writing - const IMapper::Rect region{0, 0, static_cast(info.width), - static_cast(info.height)}; - int fence = -1; - YCbCrLayout layout; - ASSERT_NO_FATAL_FAILURE(layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence)); - - auto yData = static_cast(layout.y); - auto cbData = static_cast(layout.cb); - auto crData = static_cast(layout.cr); - for (uint32_t y = 0; y < info.height; y++) { - for (uint32_t x = 0; x < info.width; x++) { - auto val = static_cast(info.height * y + x); - - yData[layout.yStride * y + x] = val; - if (y % 2 == 0 && x % 2 == 0) { - cbData[layout.cStride * y / 2 + x / 2] = val; - crData[layout.cStride * y / 2 + x / 2] = val; - } - } - } - - ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); - - // lock again for reading - ASSERT_NO_FATAL_FAILURE(layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence)); - - yData = static_cast(layout.y); - cbData = static_cast(layout.cb); - crData = static_cast(layout.cr); - for (uint32_t y = 0; y < info.height; y++) { - for (uint32_t x = 0; x < info.width; x++) { - auto val = static_cast(info.height * y + x); - - EXPECT_EQ(val, yData[layout.yStride * y + x]); - if (y % 2 == 0 && x % 2 == 0) { - EXPECT_EQ(val, cbData[layout.cStride * y / 2 + x / 2]); - EXPECT_EQ(val, crData[layout.cStride * y / 2 + x / 2]); - } - } - } - ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); if (fence >= 0) { close(fence); @@ -518,8 +447,7 @@ TEST_F(GraphicsMapperHidlTest, LockBadAccessRegion) { auto buffer = const_cast(bufferHandle); mGralloc->getMapper()->lock(buffer, info.usage, accessRegion, acquireFenceHandle, - [&](const auto& tmpError, const auto& /*tmpData*/, - int32_t /*tmpBytesPerPixel*/, int32_t /*tmpBytesPerStride*/) { + [&](const auto& tmpError, const auto& /*tmpData*/) { EXPECT_EQ(Error::BAD_VALUE, tmpError) << "locking with a bad access region should fail"; }); From 0129f433665fb641157f6afd9c12a0c2a856968d Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Mon, 18 Nov 2019 12:48:24 -0800 Subject: [PATCH 0276/1022] gralloc: clean up comments Clean up code comments based on review comments in ag/9684750 and ag/9684750. Bug: 144551649 Test: Compiles Change-Id: I96f5962d2c1b79352f85dcf9354689814310ecc0 --- .../aidl/android/hardware/graphics/common/ExtendableType.aidl | 2 +- graphics/mapper/4.0/IMapper.hal | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl b/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl index 04d87106df..495693c9bd 100644 --- a/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl +++ b/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl @@ -34,7 +34,7 @@ parcelable ExtendableType { * For custom vendor types, the "name" field will be set to the name of the custom * @VendorStability vendor AIDL interface such as * "vendor.mycompanyname.graphics.common.Compression". The name of the vendor extension should - * contain the name of the company that owns the extension. Including the company + * contain the name of the owner of the extension. Including the company * name in the "name" field prevents type collisions between different vendors. */ @utf8InCpp String name; diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal index a5413826ce..4ed193bdc7 100644 --- a/graphics/mapper/4.0/IMapper.hal +++ b/graphics/mapper/4.0/IMapper.hal @@ -356,7 +356,7 @@ interface IMapper { * to read from a buffer, they have permission to read the buffer's metadata. * * There is one exception to this rule. Fences CANNOT be used to protect a buffer's - * metadata. A process should finish writing to a buffer's metadata before sending + * metadata. A process should finish writing to a buffer's metadata before * sending the buffer to another process that will read or write to the buffer. * This exception is needed because sometimes userspace needs to read the * buffer's metadata before the buffer's contents are ready. From 83e3ca82e6398603df98c4697360e2d66b6efdae Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 7 Nov 2019 10:43:16 -0800 Subject: [PATCH 0277/1022] Set up IRadioConfig 1.3 skeleton Create IRadioConfig, IRadioConfigIndication, IRadioConfigResponse Create vts for 1.3 Create default implementation for 1.3 Test: run vts -m VtsHalRadioConfigV1_3Target Bug: 144101226 Change-Id: Ibf92683ca48b4053e86de3fb655ac15ad1e0725d --- .../compatibility_matrix.current.xml | 5 +- current.txt | 6 +- radio/config/1.3/Android.bp | 23 ++++ radio/config/1.3/IRadioConfig.hal | 31 +++++ radio/config/1.3/IRadioConfigIndication.hal | 26 ++++ radio/config/1.3/IRadioConfigResponse.hal | 26 ++++ radio/config/1.3/default/Android.bp | 28 ++++ radio/config/1.3/default/RadioConfig.cpp | 113 ++++++++++++++++ radio/config/1.3/default/RadioConfig.h | 74 ++++++++++ .../1.3/default/RadioConfigIndication.cpp | 49 +++++++ .../1.3/default/RadioConfigIndication.h | 59 ++++++++ .../1.3/default/RadioConfigResponse.cpp | 81 +++++++++++ .../config/1.3/default/RadioConfigResponse.h | 77 +++++++++++ ...droid.hardware.radio.config@1.3-service.rc | 7 + .../1.3/default/radio-config-default.xml | 29 ++++ radio/config/1.3/default/service.cpp | 41 ++++++ radio/config/1.3/types.hal | 17 +++ radio/config/1.3/vts/functional/Android.bp | 35 +++++ .../VtsHalRadioConfigV1_3TargetTest.cpp | 23 ++++ .../functional/radio_config_hidl_hal_api.cpp | 19 +++ .../functional/radio_config_hidl_hal_test.cpp | 58 ++++++++ .../functional/radio_config_hidl_hal_utils.h | 128 ++++++++++++++++++ .../vts/functional/radio_config_response.cpp | 65 +++++++++ 23 files changed, 1015 insertions(+), 5 deletions(-) create mode 100644 radio/config/1.3/Android.bp create mode 100644 radio/config/1.3/IRadioConfig.hal create mode 100644 radio/config/1.3/IRadioConfigIndication.hal create mode 100644 radio/config/1.3/IRadioConfigResponse.hal create mode 100644 radio/config/1.3/default/Android.bp create mode 100644 radio/config/1.3/default/RadioConfig.cpp create mode 100644 radio/config/1.3/default/RadioConfig.h create mode 100644 radio/config/1.3/default/RadioConfigIndication.cpp create mode 100644 radio/config/1.3/default/RadioConfigIndication.h create mode 100644 radio/config/1.3/default/RadioConfigResponse.cpp create mode 100644 radio/config/1.3/default/RadioConfigResponse.h create mode 100644 radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc create mode 100644 radio/config/1.3/default/radio-config-default.xml create mode 100644 radio/config/1.3/default/service.cpp create mode 100644 radio/config/1.3/types.hal create mode 100644 radio/config/1.3/vts/functional/Android.bp create mode 100644 radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp create mode 100644 radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp create mode 100644 radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp create mode 100644 radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h create mode 100644 radio/config/1.3/vts/functional/radio_config_response.cpp diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 7d4f7a334a..465795c4e9 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -367,10 +367,7 @@ android.hardware.radio.config - - 1.1 + 1.3 IRadioConfig default diff --git a/current.txt b/current.txt index 68d7d73c80..6bb62708b9 100644 --- a/current.txt +++ b/current.txt @@ -614,4 +614,8 @@ c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardwar 274fb1254a6d1a97824ec5c880eeefc0e410dc6d3a2a4c34052201169d2b7de0 android.hardware.radio@1.5::types c8e81d912827a5d49b2ddcdc4eb4556c5d231a899a1dca879309e04210daa4a0 android.hardware.radio@1.5::IRadio a62a93faf173b14a6175b683ebf61ffa568dc61f81e369d2dce7b1265e86cf2f android.hardware.radio@1.5::IRadioIndication -260ce05806d753d728f844d405e832179ed7d9b65986ec18fef3d21cf7285587 android.hardware.radio@1.5::IRadioResponse \ No newline at end of file +260ce05806d753d728f844d405e832179ed7d9b65986ec18fef3d21cf7285587 android.hardware.radio@1.5::IRadioResponse +55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types +b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig +742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication +7683fed9d253956071f18b152e6be657719536f98d9b534433d5e411bcde5061 android.hardware.radio.config@1.3::IRadioConfigResponse diff --git a/radio/config/1.3/Android.bp b/radio/config/1.3/Android.bp new file mode 100644 index 0000000000..88de666618 --- /dev/null +++ b/radio/config/1.3/Android.bp @@ -0,0 +1,23 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.radio.config@1.3", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IRadioConfig.hal", + "IRadioConfigIndication.hal", + "IRadioConfigResponse.hal", + ], + interfaces: [ + "android.hardware.radio.config@1.0", + "android.hardware.radio.config@1.1", + "android.hardware.radio.config@1.2", + "android.hardware.radio@1.0", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/radio/config/1.3/IRadioConfig.hal b/radio/config/1.3/IRadioConfig.hal new file mode 100644 index 0000000000..a0ce6e089d --- /dev/null +++ b/radio/config/1.3/IRadioConfig.hal @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package android.hardware.radio.config@1.3; + +import @1.1::IRadioConfig; + +/** + * This interface is used by telephony and telecom to talk to cellular radio for the purpose of + * radio configuration, and it is not associated with any specific modem or slot. + * All the functions have minimum one parameter: + * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the + * duration of a method call. If clients provide colliding serials (including passing the same + * serial to different methods), multiple responses (one for each method call) must still be served. + */ +interface IRadioConfig extends @1.1::IRadioConfig { + +}; diff --git a/radio/config/1.3/IRadioConfigIndication.hal b/radio/config/1.3/IRadioConfigIndication.hal new file mode 100644 index 0000000000..9ef496c4ba --- /dev/null +++ b/radio/config/1.3/IRadioConfigIndication.hal @@ -0,0 +1,26 @@ +/* + * 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. + */ + +package android.hardware.radio.config@1.3; + +import @1.2::IRadioConfigIndication; + +/** + * Interface declaring unsolicited radio config indications. + */ +interface IRadioConfigIndication extends @1.2::IRadioConfigIndication { + +}; diff --git a/radio/config/1.3/IRadioConfigResponse.hal b/radio/config/1.3/IRadioConfigResponse.hal new file mode 100644 index 0000000000..9c4c971f9f --- /dev/null +++ b/radio/config/1.3/IRadioConfigResponse.hal @@ -0,0 +1,26 @@ +/* + * 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. + */ + +package android.hardware.radio.config@1.3; + +import @1.2::IRadioConfigResponse; + +/** + * Interface declaring response functions to solicited radio config requests. + */ +interface IRadioConfigResponse extends @1.2::IRadioConfigResponse { + +}; diff --git a/radio/config/1.3/default/Android.bp b/radio/config/1.3/default/Android.bp new file mode 100644 index 0000000000..163c5c5d63 --- /dev/null +++ b/radio/config/1.3/default/Android.bp @@ -0,0 +1,28 @@ +cc_binary { + name: "android.hardware.radio.config@1.3-service", + init_rc: ["android.hardware.radio.config@1.3-service.rc"], + relative_install_path: "hw", + vintf_fragments: ["radio-config-default.xml"], + vendor: true, + srcs: [ + "RadioConfig.cpp", + "RadioConfigIndication.cpp", + "RadioConfigResponse.cpp", + "service.cpp", + ], + shared_libs: [ + "libhidlbase", + "liblog", + "libutils", + "android.hardware.radio.config@1.0", + "android.hardware.radio.config@1.1", + "android.hardware.radio.config@1.2", + "android.hardware.radio.config@1.3", + "android.hardware.radio@1.0", + "android.hardware.radio@1.1", + "android.hardware.radio@1.2", + "android.hardware.radio@1.3", + "android.hardware.radio@1.4", + "android.hardware.radio@1.5", + ], +} diff --git a/radio/config/1.3/default/RadioConfig.cpp b/radio/config/1.3/default/RadioConfig.cpp new file mode 100644 index 0000000000..c28119c311 --- /dev/null +++ b/radio/config/1.3/default/RadioConfig.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.1 (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.1 + * + * 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 "RadioConfig.h" + +namespace android { +namespace hardware { +namespace radio { +namespace config { +namespace V1_3 { +namespace implementation { + +using namespace ::android::hardware::radio::V1_0; +using namespace ::android::hardware::radio::config; + +// Methods from ::android::hardware::radio::config::V1_0::IRadioConfig follow. +Return RadioConfig::setResponseFunctions( + const sp& radioConfigResponse, + const sp& radioConfigIndication) { + mRadioConfigResponse = radioConfigResponse; + mRadioConfigIndication = radioConfigIndication; + + mRadioConfigResponseV1_3 = + V1_3::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr); + mRadioConfigIndicationV1_3 = + V1_3::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr); + if (mRadioConfigResponseV1_3 == nullptr || mRadioConfigIndicationV1_3 == nullptr) { + mRadioConfigResponseV1_3 = nullptr; + mRadioConfigIndicationV1_3 = nullptr; + } + + mRadioConfigResponseV1_2 = + V1_2::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr); + mRadioConfigIndicationV1_2 = + V1_2::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr); + if (mRadioConfigResponseV1_2 == nullptr || mRadioConfigIndicationV1_2 == nullptr) { + mRadioConfigResponseV1_2 = nullptr; + mRadioConfigIndicationV1_2 = nullptr; + } + + mRadioConfigResponseV1_1 = + V1_1::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr); + mRadioConfigIndicationV1_1 = + V1_1::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr); + if (mRadioConfigResponseV1_1 == nullptr || mRadioConfigIndicationV1_1 == nullptr) { + mRadioConfigResponseV1_1 = nullptr; + mRadioConfigIndicationV1_1 = nullptr; + } + + return Void(); +} + +Return RadioConfig::getSimSlotsStatus(int32_t /* serial */) { + hidl_vec slotStatus; + RadioResponseInfo info; + mRadioConfigResponse->getSimSlotsStatusResponse(info, slotStatus); + return Void(); +} + +Return RadioConfig::setSimSlotsMapping(int32_t /* serial */, + const hidl_vec& /* slotMap */) { + RadioResponseInfo info; + mRadioConfigResponse->setSimSlotsMappingResponse(info); + return Void(); +} + +// Methods from ::android::hardware::radio::config::V1_1::IRadioConfig follow. +Return RadioConfig::getPhoneCapability(int32_t /* serial */) { + V1_1::PhoneCapability phoneCapability; + RadioResponseInfo info; + mRadioConfigResponseV1_1->getPhoneCapabilityResponse(info, phoneCapability); + return Void(); +} + +Return RadioConfig::setPreferredDataModem(int32_t /* serial */, uint8_t /* modemId */) { + RadioResponseInfo info; + mRadioConfigResponseV1_1->setPreferredDataModemResponse(info); + return Void(); +} + +Return RadioConfig::setModemsConfig(int32_t /* serial */, + const V1_1::ModemsConfig& /* modemsConfig */) { + RadioResponseInfo info; + mRadioConfigResponseV1_1->setModemsConfigResponse(info); + return Void(); +} + +Return RadioConfig::getModemsConfig(int32_t /* serial */) { + V1_1::ModemsConfig modemsConfig; + RadioResponseInfo info; + mRadioConfigResponseV1_1->getModemsConfigResponse(info, modemsConfig); + return Void(); +} + +} // namespace implementation +} // namespace V1_3 +} // namespace config +} // namespace radio +} // namespace hardware +} // namespace android diff --git a/radio/config/1.3/default/RadioConfig.h b/radio/config/1.3/default/RadioConfig.h new file mode 100644 index 0000000000..00585e6df2 --- /dev/null +++ b/radio/config/1.3/default/RadioConfig.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.1 (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.1 + * + * 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_RADIO_CONFIG_V1_3_RADIOCONFIG_H +#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIG_H + +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace radio { +namespace config { +namespace V1_3 { +namespace implementation { + +using namespace ::android::hardware::radio::config; + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +struct RadioConfig : public V1_3::IRadioConfig { + sp mRadioConfigResponse; + sp mRadioConfigIndication; + sp mRadioConfigResponseV1_1; + sp mRadioConfigIndicationV1_1; + sp mRadioConfigResponseV1_2; + sp mRadioConfigIndicationV1_2; + sp mRadioConfigResponseV1_3; + sp mRadioConfigIndicationV1_3; + + // Methods from ::android::hardware::radio::config::V1_0::IRadioConfig follow. + Return setResponseFunctions( + const sp& radioConfigResponse, + const sp& radioConfigIndication); + Return getSimSlotsStatus(int32_t serial); + Return setSimSlotsMapping(int32_t serial, const hidl_vec& slotMap); + + // Methods from ::android::hardware::radio::config::V1_1::IRadioConfig follow. + Return getPhoneCapability(int32_t serial); + Return setPreferredDataModem(int32_t serial, uint8_t modemId); + Return setModemsConfig(int32_t serial, const V1_1::ModemsConfig& modemsConfig); + Return getModemsConfig(int32_t serial); +}; + +} // namespace implementation +} // namespace V1_3 +} // namespace config +} // namespace radio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIG_H diff --git a/radio/config/1.3/default/RadioConfigIndication.cpp b/radio/config/1.3/default/RadioConfigIndication.cpp new file mode 100644 index 0000000000..eb77a48ec1 --- /dev/null +++ b/radio/config/1.3/default/RadioConfigIndication.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.1 (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.1 + * + * 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 "RadioConfigIndication.h" + +namespace android { +namespace hardware { +namespace radio { +namespace config { +namespace V1_3 { +namespace implementation { + +using namespace ::android::hardware::radio::V1_0; +using namespace ::android::hardware::radio::config::V1_0; +using namespace ::android::hardware::radio::config::V1_2; + +// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigIndication follow. +Return RadioConfigIndication::simSlotsStatusChanged( + RadioIndicationType /* type */, const hidl_vec& /* slotStatus */) { + // TODO implement + return Void(); +} + +// Methods from ::android::hardware::radio::config::V1_2::IRadioConfigIndication follow. +Return RadioConfigIndication::simSlotsStatusChanged_1_2( + RadioIndicationType /* type */, const hidl_vec& /* slotStatus */) { + // TODO implement + return Void(); +} + +} // namespace implementation +} // namespace V1_3 +} // namespace config +} // namespace radio +} // namespace hardware +} // namespace android diff --git a/radio/config/1.3/default/RadioConfigIndication.h b/radio/config/1.3/default/RadioConfigIndication.h new file mode 100644 index 0000000000..3697492375 --- /dev/null +++ b/radio/config/1.3/default/RadioConfigIndication.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.1 (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.1 + * + * 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_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H +#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H + +#include +#include +#include + +namespace android { +namespace hardware { +namespace radio { +namespace config { +namespace V1_3 { +namespace implementation { + +using namespace ::android::hardware::radio::V1_0; +using namespace ::android::hardware::radio::config; + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +struct RadioConfigIndication : public IRadioConfigIndication { + // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigIndication follow. + Return simSlotsStatusChanged(RadioIndicationType type, + const hidl_vec& slotStatus) override; + + // Methods from ::android::hardware::radio::config::V1_2::IRadioConfigIndication follow. + Return simSlotsStatusChanged_1_2( + RadioIndicationType type, const hidl_vec& slotStatus) override; +}; + +} // namespace implementation +} // namespace V1_3 +} // namespace config +} // namespace radio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H diff --git a/radio/config/1.3/default/RadioConfigResponse.cpp b/radio/config/1.3/default/RadioConfigResponse.cpp new file mode 100644 index 0000000000..48e81dade3 --- /dev/null +++ b/radio/config/1.3/default/RadioConfigResponse.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.1 (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.1 + * + * 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 "RadioConfigResponse.h" + +namespace android { +namespace hardware { +namespace radio { +namespace config { +namespace V1_3 { +namespace implementation { + +using namespace ::android::hardware::radio::V1_0; +using namespace ::android::hardware::radio::config::V1_0; +using namespace ::android::hardware::radio::config::V1_1; +using namespace ::android::hardware::radio::config::V1_2; + +// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow. +Return RadioConfigResponse::getSimSlotsStatusResponse( + const RadioResponseInfo& /* info */, + const hidl_vec& /* slotStatus */) { + // TODO implement + return Void(); +} + +Return RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponseInfo& /* info */) { + // TODO implement + return Void(); +} + +// Methods from ::android::hardware::radio::config::V1_1::IRadioConfigResponse follow. +Return RadioConfigResponse::getPhoneCapabilityResponse( + const RadioResponseInfo& /* info */, const V1_1::PhoneCapability& /* phoneCapability */) { + // TODO implement + return Void(); +} + +Return RadioConfigResponse::setPreferredDataModemResponse( + const RadioResponseInfo& /* info */) { + // TODO implement + return Void(); +} + +Return RadioConfigResponse::setModemsConfigResponse(const RadioResponseInfo& /* info */) { + // TODO implement + return Void(); +} + +Return RadioConfigResponse::getModemsConfigResponse( + const RadioResponseInfo& /* info */, const V1_1::ModemsConfig& /* modemsConfig */) { + // TODO implement + return Void(); +} + +// Methods from ::android::hardware::radio::config::V1_2::IRadioConfigResponse follow. +Return RadioConfigResponse::getSimSlotsStatusResponse_1_2( + const RadioResponseInfo& /* info */, + const hidl_vec& /* slotStatus */) { + // TODO implement + return Void(); +} + +} // namespace implementation +} // namespace V1_3 +} // namespace config +} // namespace radio +} // namespace hardware +} // namespace android diff --git a/radio/config/1.3/default/RadioConfigResponse.h b/radio/config/1.3/default/RadioConfigResponse.h new file mode 100644 index 0000000000..0f0033fa6a --- /dev/null +++ b/radio/config/1.3/default/RadioConfigResponse.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.1 (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.1 + * + * 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_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H +#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H + +#include +#include +#include + +namespace android { +namespace hardware { +namespace radio { +namespace config { +namespace V1_3 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +struct RadioConfigResponse : public IRadioConfigResponse { + // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow. + Return getSimSlotsStatusResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& info, + const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus) + override; + Return setSimSlotsMappingResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override; + + // Methods from ::android::hardware::radio::config::V1_1::IRadioConfigResponse follow. + Return getPhoneCapabilityResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& info, + const ::android::hardware::radio::config::V1_1::PhoneCapability& phoneCapability) + override; + Return setPreferredDataModemResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override; + Return setModemsConfigResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override; + Return getModemsConfigResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& info, + const ::android::hardware::radio::config::V1_1::ModemsConfig& modemsConfig) override; + + // Methods from ::android::hardware::radio::config::V1_2::IRadioConfigResponse follow. + Return getSimSlotsStatusResponse_1_2( + const ::android::hardware::radio::V1_0::RadioResponseInfo& info, + const hidl_vec<::android::hardware::radio::config::V1_2::SimSlotStatus>& slotStatus) + override; + + // Methods from ::android::hidl::base::V1_0::IBase follow. +}; + +} // namespace implementation +} // namespace V1_3 +} // namespace config +} // namespace radio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H diff --git a/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc b/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc new file mode 100644 index 0000000000..6df9b52ba5 --- /dev/null +++ b/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc @@ -0,0 +1,7 @@ +service vendor.radio-config-hal-1-3 /vendor/bin/hw/android.hardware.radio.config@1.3-service + interface android.hardware.radio.config@1.0::IRadioConfig default + interface android.hardware.radio.config@1.1::IRadioConfig default + interface android.hardware.radio.config@1.3::IRadioConfig default + class hal + user system + group system diff --git a/radio/config/1.3/default/radio-config-default.xml b/radio/config/1.3/default/radio-config-default.xml new file mode 100644 index 0000000000..72f363e30f --- /dev/null +++ b/radio/config/1.3/default/radio-config-default.xml @@ -0,0 +1,29 @@ + + + + + android.hardware.radio.config + hwbinder + 1.3 + + IRadioConfig + default + + + diff --git a/radio/config/1.3/default/service.cpp b/radio/config/1.3/default/service.cpp new file mode 100644 index 0000000000..b1e67366e9 --- /dev/null +++ b/radio/config/1.3/default/service.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.1 (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.1 + * + * 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 "android.hardware.radio.config@1.3-service" + +#include +#include + +#include "RadioConfig.h" + +using android::OK; +using android::sp; +using android::status_t; +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::radio::config::V1_3::IRadioConfig; +using android::hardware::radio::config::V1_3::implementation::RadioConfig; + +int main() { + configureRpcThreadpool(1, true); + sp radioConfig = new RadioConfig; + const status_t status = radioConfig->registerAsService(); + ALOGW_IF(status != OK, "Could not register IRadioConfig 1.3"); + ALOGD("Default service is ready."); + + joinRpcThreadpool(); + return 1; +} diff --git a/radio/config/1.3/types.hal b/radio/config/1.3/types.hal new file mode 100644 index 0000000000..866002acad --- /dev/null +++ b/radio/config/1.3/types.hal @@ -0,0 +1,17 @@ +/* + * 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. + */ + +package android.hardware.radio.config@1.3; diff --git a/radio/config/1.3/vts/functional/Android.bp b/radio/config/1.3/vts/functional/Android.bp new file mode 100644 index 0000000000..6b28faf7a0 --- /dev/null +++ b/radio/config/1.3/vts/functional/Android.bp @@ -0,0 +1,35 @@ +// +// 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. +// + +cc_test { + name: "VtsHalRadioConfigV1_3TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "radio_config_hidl_hal_api.cpp", + "radio_config_hidl_hal_test.cpp", + "radio_config_response.cpp", + "VtsHalRadioConfigV1_3TargetTest.cpp", + ], + static_libs: [ + "RadioVtsTestUtilBase", + "android.hardware.radio.config@1.0", + "android.hardware.radio.config@1.1", + "android.hardware.radio.config@1.2", + "android.hardware.radio.config@1.3", + ], + header_libs: ["radio.util.header@1.0"], + test_suites: ["general-tests", "vts-core"], +} diff --git a/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp b/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp new file mode 100644 index 0000000000..3bacacf63c --- /dev/null +++ b/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp @@ -0,0 +1,23 @@ +/* + * 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. + */ + +#include + +INSTANTIATE_TEST_SUITE_P( + PerInstance, RadioConfigHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + ::android::hardware::radio::config::V1_3::IRadioConfig::descriptor)), + android::hardware::PrintInstanceNameToString); diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp new file mode 100644 index 0000000000..07e9eded5a --- /dev/null +++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp @@ -0,0 +1,19 @@ +/* + * 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. + */ + +#include + +#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp new file mode 100644 index 0000000000..dbb4bf44e3 --- /dev/null +++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#include + +void RadioConfigHidlTest::SetUp() { + radioConfig = ::android::hardware::radio::config::V1_3::IRadioConfig::getService(GetParam()); + ASSERT_NE(nullptr, radioConfig.get()); + + radioConfigRsp = new (std::nothrow) RadioConfigResponse(*this); + ASSERT_NE(nullptr, radioConfigRsp.get()); + + count_ = 0; + + radioConfig->setResponseFunctions(radioConfigRsp, nullptr); +} + +/* + * Notify that the response message is received. + */ +void RadioConfigHidlTest::notify(int receivedSerial) { + std::unique_lock lock(mtx_); + if (serial == receivedSerial) { + count_++; + cv_.notify_one(); + } +} + +/* + * Wait till the response message is notified or till TIMEOUT_PERIOD. + */ +std::cv_status RadioConfigHidlTest::wait() { + std::unique_lock lock(mtx_); + + std::cv_status status = std::cv_status::no_timeout; + auto now = std::chrono::system_clock::now(); + while (count_ == 0) { + status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD)); + if (status == std::cv_status::timeout) { + return status; + } + } + count_--; + return status; +} diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h new file mode 100644 index 0000000000..9b78c04944 --- /dev/null +++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h @@ -0,0 +1,128 @@ +/* + * 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. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "vts_test_util.h" + +using namespace ::android::hardware::radio::config::V1_1; +using namespace ::android::hardware::radio::config::V1_2; +using namespace ::android::hardware::radio::config::V1_3; + +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +using ::android::hardware::radio::V1_0::RadioResponseInfo; +using ::android::hardware::radio::V1_0::RadioResponseType; + +#define TIMEOUT_PERIOD 75 + +class RadioConfigHidlTest; + +/* Callback class for radio config response */ +class RadioConfigResponse : public ::android::hardware::radio::config::V1_3::IRadioConfigResponse { + protected: + RadioConfigHidlTest& parent; + + public: + RadioResponseInfo rspInfo; + PhoneCapability phoneCap; + + RadioConfigResponse(RadioConfigHidlTest& parent); + virtual ~RadioConfigResponse() = default; + + /* 1.0 Api */ + Return getSimSlotsStatusResponse( + const RadioResponseInfo& info, + const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus); + + Return setSimSlotsMappingResponse(const RadioResponseInfo& info); + + /* 1.1 Api */ + Return getPhoneCapabilityResponse(const RadioResponseInfo& info, + const PhoneCapability& phoneCapability); + + Return setPreferredDataModemResponse(const RadioResponseInfo& info); + + Return getModemsConfigResponse(const RadioResponseInfo& info, + const ModemsConfig& mConfig); + + Return setModemsConfigResponse(const RadioResponseInfo& info); + + /* 1.2 Api */ + Return getSimSlotsStatusResponse_1_2(const RadioResponseInfo& info, + const hidl_vec& slotStatus); +}; + +/* Callback class for radio config indication */ +class RadioConfigIndication + : public ::android::hardware::radio::config::V1_3::IRadioConfigIndication { + protected: + RadioConfigHidlTest& parent; + + public: + RadioConfigIndication(RadioConfigHidlTest& parent); + virtual ~RadioConfigIndication() = default; + + /* 1.2 Api */ + Return simSlotsStatusChanged_1_2( + ::android::hardware::radio::V1_0::RadioIndicationType type, + const hidl_vec& slotStatus); +}; + +// The main test class for Radio config HIDL. +class RadioConfigHidlTest : public ::testing::TestWithParam { + protected: + std::mutex mtx_; + std::condition_variable cv_; + int count_; + + public: + virtual void SetUp() override; + + /* Used as a mechanism to inform the test about data/event callback */ + void notify(int receivedSerial); + + /* Test code calls this function to wait for response */ + std::cv_status wait(); + + void updateSimCardStatus(); + + /* Serial number for radio request */ + int serial; + + /* radio config service handle */ + sp<::android::hardware::radio::config::V1_3::IRadioConfig> radioConfig; + + /* radio config response handle */ + sp radioConfigRsp; +}; diff --git a/radio/config/1.3/vts/functional/radio_config_response.cpp b/radio/config/1.3/vts/functional/radio_config_response.cpp new file mode 100644 index 0000000000..1ca960eae9 --- /dev/null +++ b/radio/config/1.3/vts/functional/radio_config_response.cpp @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#include + +using ::android::hardware::radio::V1_0::RadioResponseInfo; + +// SimSlotStatus slotStatus; + +RadioConfigResponse::RadioConfigResponse(RadioConfigHidlTest& parent) : parent(parent) {} + +/* 1.0 Apis */ +Return RadioConfigResponse::getSimSlotsStatusResponse( + const RadioResponseInfo& /* info */, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::config::V1_0::SimSlotStatus>& /* slotStatus */) { + return Void(); +} + +Return RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponseInfo& /* info */) { + return Void(); +} + +/* 1.1 Apis */ +Return RadioConfigResponse::getPhoneCapabilityResponse( + const RadioResponseInfo& info, const PhoneCapability& phoneCapability) { + rspInfo = info; + phoneCap = phoneCapability; + parent.notify(info.serial); + return Void(); +} + +Return RadioConfigResponse::setPreferredDataModemResponse( + const RadioResponseInfo& /* info */) { + return Void(); +} + +Return RadioConfigResponse::getModemsConfigResponse(const RadioResponseInfo& /* info */, + const ModemsConfig& /* mConfig */) { + return Void(); +} + +Return RadioConfigResponse::setModemsConfigResponse(const RadioResponseInfo& /* info */) { + return Void(); +} + +/* 1.2 Apis */ +Return RadioConfigResponse::getSimSlotsStatusResponse_1_2( + const RadioResponseInfo& /* info */, + const ::android::hardware::hidl_vec& /* slotStatus */) { + return Void(); +} \ No newline at end of file From 98fd5447127cb884950afa478093d19043fca625 Mon Sep 17 00:00:00 2001 From: jiabin Date: Fri, 22 Nov 2019 14:13:23 -0800 Subject: [PATCH 0278/1022] Refactor for audio device type in conversion. As audio device type can not be used as bit mask any more, refactoring audio device type usages in conversion from/to HAL. Use a set of audio device types instead of bit mask. Bug: 135621476 Test: atest VtsHalAudioV5_0TargetTest Change-Id: I1a0f574744f855bb1684cd28613571399781abbc --- .../core/all-versions/default/Conversions.cpp | 41 ++++++++----------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/audio/core/all-versions/default/Conversions.cpp b/audio/core/all-versions/default/Conversions.cpp index 11872c0e00..eddff556e7 100644 --- a/audio/core/all-versions/default/Conversions.cpp +++ b/audio/core/all-versions/default/Conversions.cpp @@ -19,6 +19,7 @@ #include #include +#include namespace android { namespace hardware { @@ -31,26 +32,22 @@ std::string deviceAddressToHal(const DeviceAddress& address) { char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN]; memset(halAddress, 0, sizeof(halAddress)); uint32_t halDevice = static_cast(address.device); - const bool isInput = (halDevice & AUDIO_DEVICE_BIT_IN) != 0; - if (isInput) halDevice &= ~AUDIO_DEVICE_BIT_IN; - if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) || - (isInput && (halDevice & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) { + if (getAudioDeviceOutAllA2dpSet().count(halDevice) > 0 || + halDevice == AUDIO_DEVICE_IN_BLUETOOTH_A2DP) { snprintf(halAddress, sizeof(halAddress), "%02X:%02X:%02X:%02X:%02X:%02X", address.address.mac[0], address.address.mac[1], address.address.mac[2], address.address.mac[3], address.address.mac[4], address.address.mac[5]); - } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_IP) != 0) || - (isInput && (halDevice & AUDIO_DEVICE_IN_IP) != 0)) { + } else if (halDevice == AUDIO_DEVICE_OUT_IP || halDevice == AUDIO_DEVICE_IN_IP) { snprintf(halAddress, sizeof(halAddress), "%d.%d.%d.%d", address.address.ipv4[0], address.address.ipv4[1], address.address.ipv4[2], address.address.ipv4[3]); - } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_USB) != 0) || - (isInput && (halDevice & AUDIO_DEVICE_IN_ALL_USB) != 0)) { + } else if (getAudioDeviceOutAllUsbSet().count(halDevice) > 0 || + getAudioDeviceInAllUsbSet().count(halDevice) > 0) { snprintf(halAddress, sizeof(halAddress), "card=%d;device=%d", address.address.alsa.card, address.address.alsa.device); - } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_BUS) != 0) || - (isInput && (halDevice & AUDIO_DEVICE_IN_BUS) != 0)) { + } else if (halDevice == AUDIO_DEVICE_OUT_BUS || halDevice == AUDIO_DEVICE_IN_BUS) { snprintf(halAddress, sizeof(halAddress), "%s", address.busAddress.c_str()); - } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0 || - (isInput && (halDevice & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) { + } else if (halDevice == AUDIO_DEVICE_OUT_REMOTE_SUBMIX || + halDevice == AUDIO_DEVICE_IN_REMOTE_SUBMIX) { snprintf(halAddress, sizeof(halAddress), "%s", address.rSubmixAddress.c_str()); } return halAddress; @@ -67,32 +64,28 @@ status_t deviceAddressFromHal(audio_devices_t device, const char* halAddress, return OK; } - const bool isInput = (device & AUDIO_DEVICE_BIT_IN) != 0; - if (isInput) device &= ~AUDIO_DEVICE_BIT_IN; - if ((!isInput && (device & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) || - (isInput && (device & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) { + if (getAudioDeviceOutAllA2dpSet().count(device) > 0 || + device == AUDIO_DEVICE_IN_BLUETOOTH_A2DP) { int status = sscanf(halAddress, "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX", &address->address.mac[0], &address->address.mac[1], &address->address.mac[2], &address->address.mac[3], &address->address.mac[4], &address->address.mac[5]); return status == 6 ? OK : BAD_VALUE; - } else if ((!isInput && (device & AUDIO_DEVICE_OUT_IP) != 0) || - (isInput && (device & AUDIO_DEVICE_IN_IP) != 0)) { + } else if (device == AUDIO_DEVICE_OUT_IP || device == AUDIO_DEVICE_IN_IP) { int status = sscanf(halAddress, "%hhu.%hhu.%hhu.%hhu", &address->address.ipv4[0], &address->address.ipv4[1], &address->address.ipv4[2], &address->address.ipv4[3]); return status == 4 ? OK : BAD_VALUE; - } else if ((!isInput && (device & AUDIO_DEVICE_OUT_ALL_USB)) != 0 || - (isInput && (device & AUDIO_DEVICE_IN_ALL_USB)) != 0) { + } else if (getAudioDeviceOutAllUsbSet().count(device) > 0 || + getAudioDeviceInAllUsbSet().count(device) > 0) { int status = sscanf(halAddress, "card=%d;device=%d", &address->address.alsa.card, &address->address.alsa.device); return status == 2 ? OK : BAD_VALUE; - } else if ((!isInput && (device & AUDIO_DEVICE_OUT_BUS) != 0) || - (isInput && (device & AUDIO_DEVICE_IN_BUS) != 0)) { + } else if (device == AUDIO_DEVICE_OUT_BUS || device == AUDIO_DEVICE_IN_BUS) { address->busAddress = halAddress; return OK; - } else if ((!isInput && (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0 || - (isInput && (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) { + } else if (device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX || + device == AUDIO_DEVICE_IN_REMOTE_SUBMIX) { address->rSubmixAddress = halAddress; return OK; } From b20389e2b47e7078380e1a835b634a62dcf5f580 Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Tue, 19 Nov 2019 22:11:11 -0800 Subject: [PATCH 0279/1022] Avoid injected location fused in GNSS location Bug: 144104269 Test: atest VtsHalGnssV1_0TargetTest Change-Id: I1266c6b7118d83e24a40dfe4ce4d4ba53a053343 --- .../functional/VtsHalGnssV1_0TargetTest.cpp | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp index 1a80ecf44c..6183a1ae28 100644 --- a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp +++ b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -402,6 +403,34 @@ TEST_P(GnssHalTest, InjectDelete) { StopAndClearLocations(); } +/* + * InjectSeedLocation: + * Injects a seed location and ensures the injected seed location is not fused in the resulting + * GNSS location. + */ +TEST_P(GnssHalTest, InjectSeedLocation) { + // An arbitrary position in North Pacific Ocean (where no VTS labs will ever likely be located). + const double seedLatDegrees = 32.312894; + const double seedLngDegrees = -172.954117; + const float seedAccuracyMeters = 150.0; + + auto result = gnss_hal_->injectLocation(seedLatDegrees, seedLngDegrees, seedAccuracyMeters); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); + + StartAndGetSingleLocation(false); + + // Ensure we don't get a location anywhere within 111km (1 degree of lat or lng) of the seed + // location. + EXPECT_TRUE(std::abs(last_location_.latitudeDegrees - seedLatDegrees) > 1.0 || + std::abs(last_location_.longitudeDegrees - seedLngDegrees) > 1.0); + + StopAndClearLocations(); + + auto resultVoid = gnss_hal_->deleteAidingData(IGnss::GnssAidingData::DELETE_POSITION); + ASSERT_TRUE(resultVoid.isOk()); +} + /* * GetAllExtentions: * Tries getting all optional extensions, and ensures a valid return From a164db9e840ed9265403394a10bde3f778c7e6ac Mon Sep 17 00:00:00 2001 From: Malcolm Chen Date: Tue, 12 Nov 2019 19:03:12 -0800 Subject: [PATCH 0280/1022] Adding HAL API for disabling subscription Bug: 141018421 Test: vts on cuttlefish Change-Id: I90ded163ddc047916c205513ab77a886ebcc48f7 --- .../compatibility_matrix.current.xml | 2 +- current.txt | 7 +- radio/1.5/IRadio.hal | 41 +++++ radio/1.5/IRadioIndication.hal | 7 + radio/1.5/IRadioResponse.hal | 37 ++++ .../1.5/vts/functional/radio_hidl_hal_api.cpp | 170 ++++++++++++++++++ .../functional/radio_hidl_hal_utils_v1_5.h | 13 ++ radio/1.5/vts/functional/radio_indication.cpp | 5 + radio/1.5/vts/functional/radio_response.cpp | 24 ++- 9 files changed, 301 insertions(+), 5 deletions(-) diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 99ffeaedfc..c6fd76ed7e 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -349,7 +349,7 @@ android.hardware.radio - 1.4 + 1.5 IRadio slot1 diff --git a/current.txt b/current.txt index 34621a585d..676beb0be2 100644 --- a/current.txt +++ b/current.txt @@ -612,10 +612,11 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types 274fb1254a6d1a97824ec5c880eeefc0e410dc6d3a2a4c34052201169d2b7de0 android.hardware.radio@1.5::types -c8e81d912827a5d49b2ddcdc4eb4556c5d231a899a1dca879309e04210daa4a0 android.hardware.radio@1.5::IRadio -a62a93faf173b14a6175b683ebf61ffa568dc61f81e369d2dce7b1265e86cf2f android.hardware.radio@1.5::IRadioIndication -260ce05806d753d728f844d405e832179ed7d9b65986ec18fef3d21cf7285587 android.hardware.radio@1.5::IRadioResponse +4c666aaf3944ad91c2428b8456d0db4a2f81191f8c294f046a2f539e9fc7b6fd android.hardware.radio@1.5::IRadio +3afac66f21a33bc9c4b80481c7d5540038348651d9a7d8af64ea13610af138da android.hardware.radio@1.5::IRadioIndication +70e977f2ccefd2e503bedb3a66313639b53fbc7bde025538b07f41e2292b6624 android.hardware.radio@1.5::IRadioResponse 55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication 7683fed9d253956071f18b152e6be657719536f98d9b534433d5e411bcde5061 android.hardware.radio.config@1.3::IRadioConfigResponse + diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal index 74ec56d4da..a3001fdfa2 100644 --- a/radio/1.5/IRadio.hal +++ b/radio/1.5/IRadio.hal @@ -55,4 +55,45 @@ interface IRadio extends @1.4::IRadio { */ oneway setSignalStrengthReportingCriteria_1_5(int32_t serial, SignalThresholdInfo signalThresholdInfo, AccessNetwork accessNetwork); + + /** + * Enable or disable UiccApplications on the SIM. If disabled: + * - Modem will not register on any network. + * - SIM must be PRESENT, and the IccId of the SIM must still be accessible. + * - The corresponding modem stack is still functional, e.g. able to make emergency calls or + * do network scan. + * By default if this API is not called, the uiccApplications must be enabled automatically. + * It must work for both single SIM and DSDS cases for UX consistency. + * The preference is per SIM, and must be remembered over power cycle, modem reboot, or SIM + * insertion / unplug. + * + * @param serial: Serial number of request. + * @param enable: true if to enable uiccApplications, false to disable. + + * Response callback is IRadioResponse.enableUiccApplicationsResponse() + */ + oneway enableUiccApplications(int32_t serial, bool enable); + + /** + * Whether uiccApplications are enabled, or disabled. + * + * By default uiccApplications must be enabled, unless enableUiccApplications() with enable + * being false is called. + * + * @param serial Serial number of request. + * + * Response callback is IRadioResponse.areUiccApplicationsEnabledResponse() + */ + oneway areUiccApplicationsEnabled(int32_t serial); + + /** + * Query whether disabling and enabling UiccApplications functionality is supported. If not, + * calling enableUiccApplications with a different value will return + * RadioError:REQUEST_NOT_SUPPORTED. + * + * @param serial Serial number of request. + * + * Response callback is IRadioResponse.canToggleUiccApplicationsEnablementResponse() + */ + oneway canToggleUiccApplicationsEnablement(int32_t serial); }; diff --git a/radio/1.5/IRadioIndication.hal b/radio/1.5/IRadioIndication.hal index d4884041c5..81452abb13 100644 --- a/radio/1.5/IRadioIndication.hal +++ b/radio/1.5/IRadioIndication.hal @@ -23,4 +23,11 @@ import @1.4::IRadioIndication; * Interface declaring unsolicited radio indications. */ interface IRadioIndication extends @1.4::IRadioIndication { + /** + * Report change of whether uiccApplications are enabled, or disabled. + * + * @param type Type of radio indication + * @param enabled whether uiccApplications are enabled, or disabled + */ + oneway uiccApplicationsEnablementChanged(RadioIndicationType type, bool enabled); }; diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal index 91dc1e0d86..c136ba610a 100644 --- a/radio/1.5/IRadioResponse.hal +++ b/radio/1.5/IRadioResponse.hal @@ -32,4 +32,41 @@ interface IRadioResponse extends @1.4::IRadioResponse { * RadioError:RADIO_NOT_AVAILABLE */ oneway setSignalStrengthReportingCriteriaResponse_1_5(RadioResponseInfo info); + + /** + * @param info Response info struct containing response type, serial no. and error + * + * Valid errors returned: + * RadioError:NONE + * RadioError:SIM_ABSENT + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:INTERNAL_ERR + * RadioError:BUSY + * RadioError:REQUEST_NOT_SUPPORTED + */ + oneway enableUiccApplicationsResponse(RadioResponseInfo info); + + /** + * @param info Response info struct containing response type, serial no. and error + * @param enabled whether Uicc applications are enabled. + * + * Valid errors returned: + * RadioError:NONE + * RadioError:SIM_ABSENT + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:INTERNAL_ERR + * RadioError:REQUEST_NOT_SUPPORTED + */ + oneway areUiccApplicationsEnabledResponse(RadioResponseInfo info, bool enabled); + + /** + * @param info Response info struct containing response type, serial no. and error + * @param canToggle whether toggling UiccApplications functionality is supported. + * + * Valid errors returned: + * RadioError:NONE + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:INTERNAL_ERR + */ + oneway canToggleUiccApplicationsEnablementResponse(RadioResponseInfo info, bool canToggle); }; diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp index d173411bca..72e8d5ebb3 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp @@ -276,3 +276,173 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR) toString(radioRsp_v1_5->rspInfo.error).c_str()); ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE})); } + +/* + * Test IRadio.enableUiccApplications() for the response returned. + */ +TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsNotSupported) { + serial = GetRandomSerialNumber(); + + radio_v1_5->canToggleUiccApplicationsEnablement(serial); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + // No error should happen. + EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); + + // Supported case will be tested by other test cases. + if (radioRsp_v1_5->canToggleUiccApplicationsEnablement) return; + + // Enabling UiccApplications should still work as it should be enabled by default. + serial = GetRandomSerialNumber(); + radio_v1_5->enableUiccApplications(serial, true); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); + + // Disabling UiccApplications should return REQUEST_NOT_SUPPORTED error. + serial = GetRandomSerialNumber(); + radio_v1_5->enableUiccApplications(serial, false); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + EXPECT_EQ(RadioError::REQUEST_NOT_SUPPORTED, radioRsp_v1_5->rspInfo.error); + + // Query areUiccApplicationsEnabled should return true. + serial = GetRandomSerialNumber(); + radio_v1_5->areUiccApplicationsEnabled(serial); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); + ASSERT_TRUE(radioRsp_v1_5->areUiccApplicationsEnabled); +} + +/* + * Test IRadio.enableUiccApplications() for the response returned. + * For SIM ABSENT case. + */ +TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsSupportedSimAbsent) { + serial = GetRandomSerialNumber(); + + radio_v1_5->canToggleUiccApplicationsEnablement(serial); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + // No error should happen. + EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); + // Not supported case will be tested by togglingUiccApplicationsNotSupported test case. + if (!radioRsp_v1_5->canToggleUiccApplicationsEnablement) return; + + // This test case only test SIM ABSENT case. + if (cardStatus.base.base.cardState != CardState::ABSENT) return; + + // Disable Uicc applications. + serial = GetRandomSerialNumber(); + radio_v1_5->enableUiccApplications(serial, false); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + // As SIM is absent, RadioError::SIM_ABSENT should be thrown. + EXPECT_EQ(RadioError::SIM_ABSENT, radioRsp_v1_5->rspInfo.error); + + // Query Uicc application enablement. + serial = GetRandomSerialNumber(); + radio_v1_5->areUiccApplicationsEnabled(serial); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + // As SIM is absent, RadioError::SIM_ABSENT should be thrown. + EXPECT_EQ(RadioError::SIM_ABSENT, radioRsp_v1_5->rspInfo.error); +} + +/* + * Test IRadio.enableUiccApplications() for the response returned. + * For SIM PRESENT case. + */ +TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsSupportedSimPresent) { + serial = GetRandomSerialNumber(); + + radio_v1_5->canToggleUiccApplicationsEnablement(serial); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + // No error should happen. + EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); + // Not supported case will be tested by disablingUiccApplicationsNotSupported test case. + if (!radioRsp_v1_5->canToggleUiccApplicationsEnablement) return; + + // This test case only test SIM ABSENT case. + if (cardStatus.base.base.cardState != CardState::PRESENT) return; + + // Disable Uicc applications. + serial = GetRandomSerialNumber(); + radio_v1_5->enableUiccApplications(serial, false); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + // As SIM is present, there shouldn't be error. + EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); + + // Query Uicc application enablement. + serial = GetRandomSerialNumber(); + radio_v1_5->areUiccApplicationsEnabled(serial); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + // As SIM is present, there shouldn't be error. + EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); + ASSERT_FALSE(radioRsp_v1_5->areUiccApplicationsEnabled); + + // Enable Uicc applications. + serial = GetRandomSerialNumber(); + radio_v1_5->enableUiccApplications(serial, true); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + // As SIM is present, there shouldn't be error. + EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); + + // Query Uicc application enablement. + serial = GetRandomSerialNumber(); + radio_v1_5->areUiccApplicationsEnabled(serial); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + // As SIM is present, there shouldn't be error. + EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); + ASSERT_TRUE(radioRsp_v1_5->areUiccApplicationsEnabled); +} + +/* + * Test IRadio.areUiccApplicationsEnabled() for the response returned. + */ +TEST_F(RadioHidlTest_v1_5, areUiccApplicationsEnabled) { + serial = GetRandomSerialNumber(); + + radio_v1_5->canToggleUiccApplicationsEnablement(serial); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + // No error should happen. + EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); + + // Not supported case will be tested by togglingUiccApplicationsNotSupported test case. + if (!radioRsp_v1_5->canToggleUiccApplicationsEnablement) return; + + // Disable Uicc applications. + serial = GetRandomSerialNumber(); + radio_v1_5->areUiccApplicationsEnabled(serial); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + // If SIM is absent, RadioError::SIM_ABSENT should be thrown. Otherwise there shouldn't be any + // error. + if (cardStatus.base.base.cardState == CardState::ABSENT) { + EXPECT_EQ(RadioError::SIM_ABSENT, radioRsp_v1_5->rspInfo.error); + } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); + } +} diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index 683fdfc5fb..c05359d631 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -80,6 +80,12 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon ::android::hardware::radio::V1_4::CarrierRestrictionsWithPriority carrierRestrictionsResp; ::android::hardware::radio::V1_4::SimLockMultiSimPolicy multiSimPolicyResp; + // Whether toggling uicc applications operation is supported. + bool canToggleUiccApplicationsEnablement; + + // Whether Uicc applications are enabled or not. + bool areUiccApplicationsEnabled; + RadioResponse_v1_5(RadioHidlTest_v1_5& parent_v1_5); virtual ~RadioResponse_v1_5() = default; @@ -524,6 +530,10 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon /* 1.5 Api */ Return setSignalStrengthReportingCriteriaResponse_1_5(const RadioResponseInfo& info); + Return enableUiccApplicationsResponse(const RadioResponseInfo& info); + Return areUiccApplicationsEnabledResponse(const RadioResponseInfo& info, bool enabled); + Return canToggleUiccApplicationsEnablementResponse(const RadioResponseInfo& info, + bool canToggle); }; /* Callback class for radio indication */ @@ -535,6 +545,9 @@ class RadioIndication_v1_5 : public ::android::hardware::radio::V1_5::IRadioIndi RadioIndication_v1_5(RadioHidlTest_v1_5& parent_v1_5); virtual ~RadioIndication_v1_5() = default; + /* 1.5 Api */ + Return uiccApplicationsEnablementChanged(RadioIndicationType type, bool enabled); + /* 1.4 Api */ Return currentEmergencyNumberList( RadioIndicationType type, diff --git a/radio/1.5/vts/functional/radio_indication.cpp b/radio/1.5/vts/functional/radio_indication.cpp index b63b74571e..acffbbea3d 100644 --- a/radio/1.5/vts/functional/radio_indication.cpp +++ b/radio/1.5/vts/functional/radio_indication.cpp @@ -328,3 +328,8 @@ Return RadioIndication_v1_5::modemReset(RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*reason*/) { return Void(); } + +Return RadioIndication_v1_5::uiccApplicationsEnablementChanged(RadioIndicationType /*type*/, + bool /*enabled*/) { + return Void(); +} diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp index 29a92506ab..78c03a9773 100644 --- a/radio/1.5/vts/functional/radio_response.cpp +++ b/radio/1.5/vts/functional/radio_response.cpp @@ -892,4 +892,26 @@ Return RadioResponse_v1_5::setSignalStrengthReportingCriteriaResponse_1_5( rspInfo = info; parent_v1_5.notify(info.serial); return Void(); -} \ No newline at end of file +} + +Return RadioResponse_v1_5::enableUiccApplicationsResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::areUiccApplicationsEnabledResponse(const RadioResponseInfo& info, + bool enabled) { + rspInfo = info; + areUiccApplicationsEnabled = enabled; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::canToggleUiccApplicationsEnablementResponse( + const RadioResponseInfo& info, bool canToggle) { + rspInfo = info; + canToggleUiccApplicationsEnablement = canToggle; + parent_v1_5.notify(info.serial); + return Void(); +} From a5aedc3293c7ac3d151d07d95966388e3949ffd3 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Mon, 25 Nov 2019 16:17:52 -0800 Subject: [PATCH 0281/1022] Clean up BeginCommand. BUG: N/A Test: build, flash and boot Change-Id: Ife6132307152e271548a54e11a472751c52d95e4 --- .../2.2/ComposerCommandBuffer.h | 11 ++++++----- .../2.3/ComposerCommandBuffer.h | 11 ++++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h index 138d70005e..35162a6b8e 100644 --- a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h +++ b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h @@ -93,17 +93,18 @@ class CommandWriterBase : public V2_1::CommandWriterBase { } protected: - void beginCommand_2_2(IComposerClient::Command command, uint16_t length) { - V2_1::CommandWriterBase::beginCommand( - static_cast(static_cast(command)), length); - } - void writeFloatColor(const IComposerClient::FloatColor& color) { writeFloat(color.r); writeFloat(color.g); writeFloat(color.b); writeFloat(color.a); } + + private: + void beginCommand_2_2(IComposerClient::Command command, uint16_t length) { + V2_1::CommandWriterBase::beginCommand( + static_cast(static_cast(command)), length); + } }; // This class helps parse a command queue. Note that all sizes/lengths are in diff --git a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h index 11863faced..162915e9a0 100644 --- a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h +++ b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h @@ -119,17 +119,18 @@ class CommandWriterBase : public V2_2::CommandWriterBase { } protected: - void beginCommand_2_3(IComposerClient::Command command, uint16_t length) { - V2_2::CommandWriterBase::beginCommand_2_2( - static_cast(static_cast(command)), length); - } - void writeBlob(uint32_t length, const unsigned char* blob) { memcpy(&mData[mDataWritten], blob, length); uint32_t numElements = length / 4; mDataWritten += numElements; mDataWritten += (length - (numElements * 4) > 0) ? 1 : 0; } + + private: + void beginCommand_2_3(IComposerClient::Command command, uint16_t length) { + V2_1::CommandWriterBase::beginCommand( + static_cast(static_cast(command)), length); + } }; // This class helps parse a command queue. Note that all sizes/lengths are in From da54091640531ae927d25a56c44c1efc1f247a51 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Mon, 25 Nov 2019 14:35:11 -0800 Subject: [PATCH 0282/1022] gralloc: move VtsHalCameraProviderV2_4TargetTest to GraphicBufferAllocator/Mapper libui's GraphicBufferAllocator/Mapper already wrap the different gralloc functions and hide the details from the caller. There is no reason VtsHalCameraProviderV2_4TargetTest needs to directly talk to gralloc. This patch updates VtsHalCameraProviderV2_4TargetTest to use libui. Bug: 145139476 Test: adb shell /system/bin/VtsHalCameraProviderV2_4TargetTest --hal_service_instance=android.hardware.camera.provider@2.4::ICameraProvider/internal/0 Change-Id: I2c2a913f6c5aea2ce7260b68293df404f40e0ddd --- camera/provider/2.4/vts/functional/Android.bp | 7 +- .../VtsHalCameraProviderV2_4TargetTest.cpp | 136 +++--------------- 2 files changed, 23 insertions(+), 120 deletions(-) diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp index 5fe7b197d0..080fa19d24 100644 --- a/camera/provider/2.4/vts/functional/Android.bp +++ b/camera/provider/2.4/vts/functional/Android.bp @@ -25,6 +25,7 @@ cc_test { "libcamera_metadata", "libcutils", "libfmq", + "libgralloctypes", "libgui", "libui", ], @@ -41,13 +42,7 @@ cc_test { "android.hardware.camera.metadata@3.4", "android.hardware.camera.provider@2.4", "android.hardware.camera.provider@2.5", - "android.hardware.graphics.allocator@2.0", - "android.hardware.graphics.allocator@3.0", - "android.hardware.graphics.allocator@4.0", "android.hardware.graphics.common@1.0", - "android.hardware.graphics.mapper@2.0", - "android.hardware.graphics.mapper@3.0", - "android.hardware.graphics.mapper@4.0", "android.hidl.allocator@1.0", "libgrallocusage", "libhidlmemory", diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 6505440a26..9416a5430e 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -26,21 +26,21 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -52,14 +52,9 @@ #include #include #include +#include +#include -#include -#include -#include -#include -#include -#include -#include #include #include #include @@ -6311,102 +6306,15 @@ void CameraHidlTest::allocateGraphicBuffer(uint32_t width, uint32_t height, uint PixelFormat format, hidl_handle *buffer_handle /*out*/) { ASSERT_NE(buffer_handle, nullptr); - sp allocator = - android::hardware::graphics::allocator::V2_0::IAllocator::getService(); - sp allocatorV3 = - android::hardware::graphics::allocator::V3_0::IAllocator::getService(); - sp allocatorV4 = - android::hardware::graphics::allocator::V4_0::IAllocator::getService(); + buffer_handle_t buffer; + uint32_t stride; - sp mapperV4 = - android::hardware::graphics::mapper::V4_0::IMapper::getService(); - sp mapperV3 = - android::hardware::graphics::mapper::V3_0::IMapper::getService(); - sp mapper = - android::hardware::graphics::mapper::V2_0::IMapper::getService(); - if (mapperV4 != nullptr && allocatorV4 != nullptr) { - ::android::hardware::hidl_vec descriptor; - android::hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo descriptorInfo{}; - descriptorInfo.name = "VtsHalCameraProviderV2_4"; - descriptorInfo.width = width; - descriptorInfo.height = height; - descriptorInfo.layerCount = 1; - descriptorInfo.format = - static_cast(format); - descriptorInfo.usage = usage; + android::status_t err = android::GraphicBufferAllocator::get().allocate( + width, height, static_cast(format), 1u /*layerCount*/, usage, &buffer, &stride, + "VtsHalCameraProviderV2_4"); + ASSERT_EQ(err, android::NO_ERROR); - auto ret = mapperV4->createDescriptor( - descriptorInfo, [&descriptor](android::hardware::graphics::mapper::V4_0::Error err, - ::android::hardware::hidl_vec desc) { - ASSERT_EQ(err, android::hardware::graphics::mapper::V4_0::Error::NONE); - descriptor = desc; - }); - ASSERT_TRUE(ret.isOk()); - - ret = allocatorV4->allocate( - descriptor, 1u, - [&](android::hardware::graphics::mapper::V4_0::Error err, uint32_t /*stride*/, - const ::android::hardware::hidl_vec<::android::hardware::hidl_handle>& - buffers) { - ASSERT_EQ(android::hardware::graphics::mapper::V4_0::Error::NONE, err); - ASSERT_EQ(buffers.size(), 1u); - *buffer_handle = buffers[0]; - }); - ASSERT_TRUE(ret.isOk()); - } else if (mapperV3 != nullptr && allocatorV3 != nullptr) { - ::android::hardware::hidl_vec descriptor; - android::hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo descriptorInfo {}; - descriptorInfo.width = width; - descriptorInfo.height = height; - descriptorInfo.layerCount = 1; - descriptorInfo.format = - static_cast(format); - descriptorInfo.usage = usage; - - auto ret = mapperV3->createDescriptor( - descriptorInfo, [&descriptor](android::hardware::graphics::mapper::V3_0::Error err, - ::android::hardware::hidl_vec desc) { - ASSERT_EQ(err, android::hardware::graphics::mapper::V3_0::Error::NONE); - descriptor = desc; - }); - ASSERT_TRUE(ret.isOk()); - - ret = allocatorV3->allocate(descriptor, 1u, - [&](android::hardware::graphics::mapper::V3_0::Error err, uint32_t /*stride*/, - const ::android::hardware::hidl_vec<::android::hardware::hidl_handle>& buffers) { - ASSERT_EQ(android::hardware::graphics::mapper::V3_0::Error::NONE, err); - ASSERT_EQ(buffers.size(), 1u); - *buffer_handle = buffers[0]; - }); - ASSERT_TRUE(ret.isOk()); - } else { - ::android::hardware::hidl_vec descriptor; - ASSERT_NE(mapper.get(), nullptr); - ASSERT_NE(allocator.get(), nullptr); - android::hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo descriptorInfo {}; - descriptorInfo.width = width; - descriptorInfo.height = height; - descriptorInfo.layerCount = 1; - descriptorInfo.format = format; - descriptorInfo.usage = usage; - - auto ret = mapper->createDescriptor( - descriptorInfo, [&descriptor](android::hardware::graphics::mapper::V2_0::Error err, - ::android::hardware::hidl_vec desc) { - ASSERT_EQ(err, android::hardware::graphics::mapper::V2_0::Error::NONE); - descriptor = desc; - }); - ASSERT_TRUE(ret.isOk()); - - ret = allocator->allocate(descriptor, 1u, - [&](android::hardware::graphics::mapper::V2_0::Error err, uint32_t /*stride*/, - const ::android::hardware::hidl_vec<::android::hardware::hidl_handle>& buffers) { - ASSERT_EQ(android::hardware::graphics::mapper::V2_0::Error::NONE, err); - ASSERT_EQ(buffers.size(), 1u); - *buffer_handle = buffers[0]; - }); - ASSERT_TRUE(ret.isOk()); - } + buffer_handle->setTo(const_cast(buffer), true /*shouldOwn*/); } void CameraHidlTest::verifyRecommendedConfigs(const CameraMetadata& chars) { From 89f12f58b06710ed12c3142deb5881f958ec7cd8 Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Tue, 5 Nov 2019 13:48:59 -0800 Subject: [PATCH 0283/1022] Add TEMI filter, releasing AV handle and CI-CAM Test: Manual bug: 135708935 Change-Id: I21701185feb274dc1e8b3cff3db59b9d3f73edf1 --- tv/tuner/1.0/IDemux.hal | 27 +++++++++++++++- tv/tuner/1.0/IFilter.hal | 15 +++++++++ tv/tuner/1.0/default/Demux.cpp | 14 ++++++++ tv/tuner/1.0/default/Demux.h | 5 +++ tv/tuner/1.0/default/Filter.cpp | 16 +++++++++- tv/tuner/1.0/default/Filter.h | 5 ++- tv/tuner/1.0/types.hal | 32 ++++++++++++++++++- .../VtsHalTvTunerV1_0TargetTest.cpp | 4 +++ 8 files changed, 114 insertions(+), 4 deletions(-) diff --git a/tv/tuner/1.0/IDemux.hal b/tv/tuner/1.0/IDemux.hal index 9e799b43f7..16fc39279d 100644 --- a/tv/tuner/1.0/IDemux.hal +++ b/tv/tuner/1.0/IDemux.hal @@ -25,7 +25,6 @@ import ITimeFilter; /** * Demultiplexer(Demux) takes a single multiplexed input and splits it into * one or more output. - * */ interface IDemux { /** @@ -134,4 +133,30 @@ interface IDemux { */ openDvr(DvrType type, uint32_t bufferSize, IDvrCallback cb) generates (Result result, IDvr dvr); + + /** + * Connect Conditional Access Modules (CAM) through Common Interface (CI) + * + * It is used by the client to connect CI-CAM. The demux uses the output + * from the frontend as the input by default, and must change to use the + * output from CI-CAM as the input after this call take place. + * + * @param ciCamId specify CI-CAM Id to connect. + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + */ + connectCiCam(uint32_t ciCamId) generates (Result result); + + /** + * Disconnect Conditional Access Modules (CAM) + * + * It is used by the client to disconnect CI-CAM. The demux will use the + * output from the frontend as the input after this call take place. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + */ + disconnectCiCam() generates (Result result); }; diff --git a/tv/tuner/1.0/IFilter.hal b/tv/tuner/1.0/IFilter.hal index deaf3d473e..3ed09f6db5 100644 --- a/tv/tuner/1.0/IFilter.hal +++ b/tv/tuner/1.0/IFilter.hal @@ -112,6 +112,21 @@ interface IFilter { */ getId() generates (Result result, uint32_t filterId); + /** + * Release the handle reported by the HAL for AV memory. + * + * It is used by the client to notify the HAL that the AV handle won't be + * used any more in client side, so that the HAL can mark the memory + * presented by file descripor in the handle as released. + * + * @param avMemory A handle associated to the memory for audio or video. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_ARGUMENT if failed for wrong parameter. + * UNKNOWN_ERROR if failed for other reasons. + */ + releaseAvHandle(handle avMemory) generates (Result result); + /** * Set the filter's data source. * diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp index c5921f74a9..71a26ab6ec 100644 --- a/tv/tuner/1.0/default/Demux.cpp +++ b/tv/tuner/1.0/default/Demux.cpp @@ -147,6 +147,20 @@ Return Demux::openDvr(DvrType type, uint32_t bufferSize, const sp Demux::connectCiCam(uint32_t ciCamId) { + ALOGV("%s", __FUNCTION__); + + mCiCamId = ciCamId; + + return Result::SUCCESS; +} + +Return Demux::disconnectCiCam() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + Result Demux::removeFilter(uint32_t filterId) { ALOGV("%s", __FUNCTION__); diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h index a9756cc248..037429dd97 100644 --- a/tv/tuner/1.0/default/Demux.h +++ b/tv/tuner/1.0/default/Demux.h @@ -76,6 +76,10 @@ class Demux : public IDemux { virtual Return openDvr(DvrType type, uint32_t bufferSize, const sp& cb, openDvr_cb _hidl_cb) override; + virtual Return connectCiCam(uint32_t ciCamId) override; + + virtual Return disconnectCiCam() override; + // Functions interacts with Tuner Service void stopBroadcastInput(); Result removeFilter(uint32_t filterId); @@ -118,6 +122,7 @@ class Demux : public IDemux { void startTsFilter(vector data); uint32_t mDemuxId; + uint32_t mCiCamId; /** * Record the last used filter id. Initial value is -1. * Filter Id starts with 0. diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp index 3d8a97731c..befd1e6550 100644 --- a/tv/tuner/1.0/default/Filter.cpp +++ b/tv/tuner/1.0/default/Filter.cpp @@ -120,6 +120,12 @@ Return Filter::flush() { return Result::SUCCESS; } +Return Filter::releaseAvHandle(const hidl_handle& /*avMemory*/) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + Return Filter::close() { ALOGV("%s", __FUNCTION__); @@ -289,6 +295,9 @@ Result Filter::startFilterHandler() { case DemuxTsFilterType::RECORD: startRecordFilterHandler(); break; + case DemuxTsFilterType::TEMI: + startTemiFilterHandler(); + break; } break; case DemuxFilterMainType::MMTP: @@ -419,6 +428,11 @@ Result Filter::startPcrFilterHandler() { return Result::SUCCESS; } +Result Filter::startTemiFilterHandler() { + // TODO handle starting TEMI filter + return Result::SUCCESS; +} + bool Filter::writeSectionsAndCreateEvent(vector data) { // TODO check how many sections has been read ALOGD("[Filter] section hander"); @@ -453,4 +467,4 @@ bool Filter::writeDataToFilterMQ(const std::vector& data) { } // namespace tuner } // namespace tv } // namespace hardware -} // namespace android \ No newline at end of file +} // namespace android diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h index 21d42974d7..fbd965a1a1 100644 --- a/tv/tuner/1.0/default/Filter.h +++ b/tv/tuner/1.0/default/Filter.h @@ -68,6 +68,8 @@ class Filter : public IFilter { virtual Return flush() override; + virtual Return releaseAvHandle(const hidl_handle& avMemory) override; + virtual Return close() override; /** @@ -129,6 +131,7 @@ class Filter : public IFilter { Result startMediaFilterHandler(); Result startRecordFilterHandler(); Result startPcrFilterHandler(); + Result startTemiFilterHandler(); Result startFilterLoop(); void deleteEventFlag(); @@ -176,4 +179,4 @@ class Filter : public IFilter { } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_FILTER_H_ \ No newline at end of file +#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_FILTER_H_ diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index fa00a6e923..707f5dfa60 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -1759,6 +1759,12 @@ enum DemuxTsFilterType : uint32_t { * buffer of the record. */ RECORD, + /** + * A filter to filter out Timed External Media Information (TEMI) according + * to ISO/IEC 13818-1:2013/ DAM 6 from input stream, and send TEMI event to + * client through onFilterEvent. + */ + TEMI, }; /** @@ -2170,7 +2176,8 @@ struct DemuxTsFilterSettings { safe_union FilterSettings { /** - * Not additional parameters. it's used by PCR, TS subtype filters. + * Not additional parameters. it's used by PCR, TS, TEMI subtype + * filters. */ Monostate noinit; @@ -2460,6 +2467,27 @@ struct DemuxFilterTsRecordEvent { uint64_t byteNumber; }; +/** + * Filter Event for Timed External Media Information (TEMI) data. + */ +struct DemuxFilterTemiEvent { + /** + * Presentation Time Stamp for audio or video frame. It based on 90KHz has + * the same format as PTS (Presentation Time Stamp) in ISO/IEC 13818-1. + */ + uint64_t pts; + + /** + * TEMI Descriptor Tag + */ + uint8_t descrTag; + + /** + * TEMI Descriptor + */ + vec descrData; +}; + /** * Filter Event for MMTP Record data. */ @@ -2521,6 +2549,8 @@ struct DemuxFilterEvent { DemuxFilterDownloadEvent download; DemuxFilterIpPayloadEvent ipPayload; + + DemuxFilterTemiEvent temi; }; /** diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index c66622608d..da3e300fc5 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -159,6 +159,7 @@ enum FilterEventType : uint8_t { RECORD, MMTPRECORD, DOWNLOAD, + TEMI, }; struct PlaybackConf { @@ -821,6 +822,9 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { case DemuxTsFilterType::RECORD: eventType = FilterEventType::RECORD; break; + case DemuxTsFilterType::TEMI: + eventType = FilterEventType::TEMI; + break; } break; case DemuxFilterMainType::MMTP: From 1cefaf6241bf9a73ec3ed148104fc7dd7c30c7fc Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Mon, 25 Nov 2019 11:41:58 -0800 Subject: [PATCH 0284/1022] [AWARE] Protect string copy against buffer overflow Fixes: 143789898 Test: (Unit) atest com.android.server.wifi Test: ACTS ThroughputTest:test_iperf_single_ndp_aware_only_ib Test: (VTS) atest VtsHalWifiApV1_4TargetTest Change-Id: I5b8aa1d9a6388fe20cb7e1cd6a76d5e59e14d099 --- wifi/1.4/default/hidl_struct_util.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp index 13a09f3438..6eeb6422e5 100644 --- a/wifi/1.4/default/hidl_struct_util.cpp +++ b/wifi/1.4/default/hidl_struct_util.cpp @@ -1822,7 +1822,13 @@ bool convertHidlNanDataPathInitiatorRequestToLegacy( convertHidlNanDataPathChannelCfgToLegacy( hidl_request.channelRequestType); legacy_request->channel = hidl_request.channel; - strcpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str()); + if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) { + LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: " + "ifaceName too long"; + return false; + } + strncpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(), + IFNAMSIZ + 1); legacy_request->ndp_cfg.security_cfg = (hidl_request.securityConfig.securityType != NanDataPathSecurityType::OPEN) @@ -1903,7 +1909,13 @@ bool convertHidlNanDataPathIndicationResponseToLegacy( ? legacy_hal::NAN_DP_REQUEST_ACCEPT : legacy_hal::NAN_DP_REQUEST_REJECT; legacy_request->ndp_instance_id = hidl_request.ndpInstanceId; - strcpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str()); + if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) { + LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: " + "ifaceName too long"; + return false; + } + strncpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(), + IFNAMSIZ + 1); legacy_request->ndp_cfg.security_cfg = (hidl_request.securityConfig.securityType != NanDataPathSecurityType::OPEN) From 382ed1d65dbec0cb6e38f418de927c37e84c92cb Mon Sep 17 00:00:00 2001 From: Kathan Shukla Date: Mon, 25 Nov 2019 22:50:53 -0800 Subject: [PATCH 0285/1022] Occupant Awareness HAL definitions. Occupant awareness default HAL and VTS tests will be added as part of a separate commit / CL. Bug: 142383127 Test: Verified that system starts default hal. Change-Id: I24e1c52c9873fc4e0fc09db24d0def9a04175120 --- automotive/occupant_awareness/aidl/Android.bp | 13 +++ .../occupant_awareness/ConfidenceLevel.aidl | 40 +++++++++ .../DriverMonitoringDetection.aidl | 36 ++++++++ .../occupant_awareness/GazeDetection.aidl | 57 ++++++++++++ .../IOccupantAwareness.aidl | 88 +++++++++++++++++++ .../IOccupantAwarenessClientCallback.aidl | 38 ++++++++ .../OccupantAwarenessStatus.aidl | 41 +++++++++ .../occupant_awareness/OccupantDetection.aidl | 50 +++++++++++ .../OccupantDetections.aidl | 34 +++++++ .../occupant_awareness/PresenceDetection.aidl | 31 +++++++ .../automotive/occupant_awareness/Role.aidl | 83 +++++++++++++++++ .../occupant_awareness/VehicleRegion.aidl | 39 ++++++++ 12 files changed, 550 insertions(+) create mode 100644 automotive/occupant_awareness/aidl/Android.bp create mode 100644 automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl create mode 100644 automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl create mode 100644 automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/GazeDetection.aidl create mode 100644 automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl create mode 100644 automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl create mode 100644 automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl create mode 100644 automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl create mode 100644 automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl create mode 100644 automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl create mode 100644 automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/Role.aidl create mode 100644 automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl diff --git a/automotive/occupant_awareness/aidl/Android.bp b/automotive/occupant_awareness/aidl/Android.bp new file mode 100644 index 0000000000..6e9e8aa386 --- /dev/null +++ b/automotive/occupant_awareness/aidl/Android.bp @@ -0,0 +1,13 @@ +aidl_interface { + name: "android.hardware.automotive.occupant_awareness", + vendor_available: true, + srcs: [ + "android/hardware/automotive/occupant_awareness/*.aidl", + ], + stability: "vintf", + backend: { + java: { + enabled: false, + }, + } +} diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl new file mode 100644 index 0000000000..8597ddbbd5 --- /dev/null +++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package android.hardware.automotive.occupant_awareness; + +@VintfStability +@Backing(type="byte") +enum ConfidenceLevel { + /** + * No prediction could be made. + */ + NONE, + /** + * Best-guess, low-confidence prediction. Predictions exceeding this threshold are adequate + * for non-critical applications. + */ + LOW, + /** + * High-confidence prediction. Predictions exceeding this threshold are adequate for + * applications that require reliable predictions. + */ + HIGH, + /** + * Highest confidence rate achievable. + */ + MAX, +} diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl new file mode 100644 index 0000000000..f5cc9d5a42 --- /dev/null +++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package android.hardware.automotive.occupant_awareness; + +import android.hardware.automotive.occupant_awareness.ConfidenceLevel; + +@VintfStability +parcelable DriverMonitoringDetection { + /* + * Confidence of the computed attention data. + */ + ConfidenceLevel confidenceScore; + /* + * Is the driver currently looking on-road? + */ + boolean isLookingOnRoad; + /* + * Duration the driver has been looking on or off road, in milliseconds. + */ + long gazeDurationMillis; +} + diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/GazeDetection.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/GazeDetection.aidl new file mode 100644 index 0000000000..fc36e13904 --- /dev/null +++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/GazeDetection.aidl @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package android.hardware.automotive.occupant_awareness; + +import android.hardware.automotive.occupant_awareness.VehicleRegion; +import android.hardware.automotive.occupant_awareness.ConfidenceLevel; + +@VintfStability +parcelable GazeDetection { + /* + * Confidence level for the gaze detection. + */ + ConfidenceLevel gazeConfidence; + /* + * Head position, in millimeters. The vehicle coordinate system is specified in the cabin space + * configuration. headPosition is double[3] array. + */ + double[] headPosition; + /* + * Unit vector for the head pose direction. The vehicle coordinate system is specified in the + * cabin space configuration. headAngleUnitVector is double[3] array. + */ + double[] headAngleUnitVector; + /* + * Unit vector for the gaze direction. The vehicle coordinate system is specified in the cabin + * space configuration. gazeAngleUnitVector is double[3] array. + */ + double[] gazeAngleUnitVector; + /* + * Current gaze target. + */ + VehicleRegion gazeTarget; + /* + * Custom gaze target string. This only need to be populated when gazeTarget is CUSTOM_TARGET. + * Vendors should use "com.vendor_name.target_name" format to avoid name collision with other + * vendors. + */ + String customGazeTarget; + /* + * Duration that the subject has been looking at the current gaze target in milliseconds. + */ + long timeOnTargetMillis; +} diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl new file mode 100644 index 0000000000..86d9e2f206 --- /dev/null +++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl @@ -0,0 +1,88 @@ +/* + * 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. + */ + +package android.hardware.automotive.occupant_awareness; + +import android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus; +import android.hardware.automotive.occupant_awareness.Role; +import android.hardware.automotive.occupant_awareness.IOccupantAwarenessClientCallback; +import android.hardware.automotive.occupant_awareness.OccupantDetections; + +@VintfStability +interface IOccupantAwareness { + /* + * System not able to generate any occupancy awareness. + */ + const int CAP_NONE = 0; + /* + * System is able to detect the presence of humans. + */ + const int CAP_PRESENSE_DETECTION = 1 << 0; + /* + * System is able to detect the gaze of humans. + */ + const int CAP_GAZE_DETECTION = 1 << 1; + /* + * System is able to compute the attention details of humans. + */ + const int CAP_DRIVER_MONITORING_DETECTION = 1 << 2; + + /** + * Starts the occupant awareness detection system. This is a non-blocking function call. + * Once system is ready, state will be modified. State update can be inrquired using callback + * or getState() function. + * @return status is the current system state. + */ + OccupantAwarenessStatus startDetection(); + + /** + * Stops the occupant awareness detection system. This is a non-blocking function call. + * Once system is reset, state will be modified. State update can be inrquired using callback + * or getState() function. + * @return status is the current system state. + */ + OccupantAwarenessStatus stopDetection(); + + /** + * Returns list of Awareness Capability supported for the given type of occupants. + * + * @param out Bitwise OR of supported capabilities (CAP_* mask). + */ + int getCapabilityForRole(in Role occupantRole); + + /** + * Inquires the current state of the occupant awareness system. + * @param occupantRole specifies the role of occupants of interest. + * @param detectionCapability specifies a single detection capability (CAP_* ) of interest. + * + * @return status is the current system state. + */ + OccupantAwarenessStatus getState(in Role occupantRole, in int detectionCapability); + + /** + * Registers a callback for data streaming. Only single callback is supported. setCallback() + * should replace existing callback with new callback. + * @return: returns ok if successful. + */ + void setCallback(in IOccupantAwarenessClientCallback callback); + + /** + * Returns the most recent set of detections. + * @param OccupantDetections output detections. + * @return returns ok if successful. + */ + void getLatestDetection(out OccupantDetections detections); +} diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl new file mode 100644 index 0000000000..69f7b0b082 --- /dev/null +++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package android.hardware.automotive.occupant_awareness; + +import android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus; +import android.hardware.automotive.occupant_awareness.OccupantDetections; + +@VintfStability +interface IOccupantAwarenessClientCallback { + /** + * A callback invoked when the system status changes. + * + * @param detectionFlags The detection subsystem(s) whose status has changed. + * @param status The new system status. + */ + oneway void onSystemStatusChanged(in int detectionFlags, in OccupantAwarenessStatus status); + + /** + * A callback invoked when a new set of detections are available. + * + * @param detections Occupant detections. + */ + oneway void onDetectionEvent(in OccupantDetections detections); +} diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl new file mode 100644 index 0000000000..6a3453d5aa --- /dev/null +++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package android.hardware.automotive.occupant_awareness; + +@VintfStability +@Backing(type="byte") +enum OccupantAwarenessStatus { + /* + * System is online and ready to serve requests. + */ + READY = 0, + /** + * Detection is not supported in this vehicle due to a permanent lack of capabilities. Clients + * need not retry. + */ + NOT_SUPPORTED = 1, + /* + * The system has not yet been initialized. No requests can be served until the + * initialization process completes. This state does not indicate any error and + * clients should retry later. + */ + NOT_INITIALIZED = 2, + /* + * A permanent failure has occurred. No detections will be provided. + */ + FAILURE = 3, +} diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl new file mode 100644 index 0000000000..47ca35a6b1 --- /dev/null +++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package android.hardware.automotive.occupant_awareness; + +import android.hardware.automotive.occupant_awareness.Role; +import android.hardware.automotive.occupant_awareness.PresenceDetection; +import android.hardware.automotive.occupant_awareness.GazeDetection; +import android.hardware.automotive.occupant_awareness.DriverMonitoringDetection; + +/* + * A complete detection for a single occupant in the vehicle. Includes data about the subject's + * presence in the vehicle, gaze and attention. + */ + @VintfStability +parcelable OccupantDetection { + /* + * Role of the occupant (e.g., driver, passenger). + */ + Role role; + /* + * Occupant presence state for a single occupant. + * If the vector is empty, no data could be generated. + */ + PresenceDetection[] presenceData; + /* + * Gaze data for a single occupant. + * If the vector is empty, no data could be generated. + */ + GazeDetection[] gazeData; + /* + * Attention data for a single occupant. + * If the vector is empty, no data could be generated. + */ + DriverMonitoringDetection[] attentionData; +} + diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl new file mode 100644 index 0000000000..e8f6621cd2 --- /dev/null +++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package android.hardware.automotive.occupant_awareness; + +import android.hardware.automotive.occupant_awareness.OccupantDetection; + +@VintfStability +parcelable OccupantDetections { + /** + * Timestamp that the underlying source image was captured, in milliseconds since Jan 1, 1970 + * (Unix time). + */ + long timeStampMillis; + /** + * A vector of detections for all occupants in the vehicle. One OccupantDetection will be + * generated per detected face. + */ + OccupantDetection[] detections; +} + diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl new file mode 100644 index 0000000000..a018106280 --- /dev/null +++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package android.hardware.automotive.occupant_awareness; + +@VintfStability +parcelable PresenceDetection { + /* + * Boolean representing whether an occupant was detected. + */ + boolean isOccupantDetected; + /** + * Duration that a particular occupant has been continuously + * detected, in milliseconds. Will be zero duration if the occupant is not + * currently detected. + */ + long detectionDurationMillis; +} diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/Role.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/Role.aidl new file mode 100644 index 0000000000..42e86ad3a5 --- /dev/null +++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/Role.aidl @@ -0,0 +1,83 @@ +/* + * 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. + */ + +package android.hardware.automotive.occupant_awareness; + +@VintfStability +@Backing(type="int") +enum Role { + /* + * All valid role(s) must have at least 1 bit set. + */ + INVALID = 0, + /* + * System could not determine role for this occupant. + */ + UNKNOWN = 1 << 0, + /* + * Occupants that the system detects as front seat passengers. + */ + FRONT_PASSENGER = 1 << 1, + /* + * Occupants that the system detects as driver(s). + */ + DRIVER = 1 << 2, + /* + * Occupants on left seat of row 2. + */ + ROW_2_PASSENGER_LEFT = 1 << 3, + /* + * Occupants on center seat of row 2. + */ + ROW_2_PASSENGER_CENTER = 1 << 4, + /* + * Occupants on right seat of row 2. + */ + ROW_2_PASSENGER_RIGHT = 1 << 5, + /* + * Occupants on left seat of row 3. + */ + ROW_3_PASSENGER_LEFT = 1 << 6, + /* + * Occupants on center seat of row 3. + */ + ROW_3_PASSENGER_CENTER = 1 << 7, + /* + * Occupants on right seat of row 3. + */ + ROW_3_PASSENGER_RIGHT = 1 << 8, + + /* + * Occupants that the system detects as front seat occupant. + * FRONT_OCCUPANTS = DRIVER | FRONT_PASSENGER + */ + FRONT_OCCUPANTS = 1 << 1 | 1 << 2, + /* + * Occupants of row 2. + * ROW_2_OCCUPANTS = ROW_2_PASSENGER_LEFT | ROW_2_PASSENGER_CENTER | ROW_2_PASSENGER_RIGHT + */ + ROW_2_OCCUPANTS = 1 << 3 | 1 << 4 | 1 << 5, + /* + * Occupants of row 3. + * ROW_3_OCCUPANTS = ROW_3_PASSENGER_LEFT | ROW_3_PASSENGER_CENTER | ROW_3_PASSENGER_RIGHT + */ + ROW_3_OCCUPANTS = 1 << 6 | 1 << 7 | 1 << 8, + /* + * All the occupants in the vehicle. + * ALL_OCCUPANTS = UNKNOWN | FRONT_OCCUPANTS | ROW_2_OCCUPANTS | ROW_3_OCCUPANTS + */ + ALL_OCCUPANTS = 0x1FF, +} diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl new file mode 100644 index 0000000000..9ee9d52f39 --- /dev/null +++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package android.hardware.automotive.occupant_awareness; + +@VintfStability +@Backing(type="int") +enum VehicleRegion { + /* + * List of targets in the car. + */ + UNKNOWN = 0, + INSTRUMENT_CLUSTER = 1, + REAR_VIEW_MIRROR = 2, + LEFT_SIDE_MIRROR = 3, + RIGHT_SIDE_MIRROR = 4, + FORWARD_ROADWAY = 5, + LEFT_ROADWAY = 6, + RIGHT_ROADWAY = 7, + HEAD_UNIT_DISPLAY = 8, + /* + * Vendors can use this value along with customGazeTarget string to uniquely identify their + * custom region. + */ + CUSTOM_TARGET = 200, +} From b6261cb2ae1cd3099d0549f14c757944f6159dba Mon Sep 17 00:00:00 2001 From: Kathan Shukla Date: Mon, 25 Nov 2019 22:52:12 -0800 Subject: [PATCH 0286/1022] Default hal for Occupant Awareness. Bug: 142383127 Test: Verified that the system starts the default hal automatically. Change-Id: I851f85bc283165891943b82c6c07f3273847b032 --- .../aidl/default/Android.bp | 32 +++++ .../aidl/default/OccupantAwareness.cpp | 122 ++++++++++++++++++ .../aidl/default/OccupantAwareness.h | 67 ++++++++++ ...tomotive.occupant_awareness@1.0-service.rc | 4 + .../aidl/default/service.cpp | 55 ++++++++ .../compatibility_matrix.current.xml | 7 + 6 files changed, 287 insertions(+) create mode 100644 automotive/occupant_awareness/aidl/default/Android.bp create mode 100644 automotive/occupant_awareness/aidl/default/OccupantAwareness.cpp create mode 100644 automotive/occupant_awareness/aidl/default/OccupantAwareness.h create mode 100644 automotive/occupant_awareness/aidl/default/android.hardware.automotive.occupant_awareness@1.0-service.rc create mode 100644 automotive/occupant_awareness/aidl/default/service.cpp diff --git a/automotive/occupant_awareness/aidl/default/Android.bp b/automotive/occupant_awareness/aidl/default/Android.bp new file mode 100644 index 0000000000..1b2fba2ea4 --- /dev/null +++ b/automotive/occupant_awareness/aidl/default/Android.bp @@ -0,0 +1,32 @@ +/* + * 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. + */ + +cc_binary { + name: "android.hardware.automotive.occupant_awareness@1.0-service", + init_rc: ["android.hardware.automotive.occupant_awareness@1.0-service.rc"], + relative_install_path: "hw", + vendor: true, + srcs: [ + "service.cpp", + "OccupantAwareness.cpp", + ], + shared_libs: [ + "libbase", + "libbinder_ndk", + "libutils", + "android.hardware.automotive.occupant_awareness-ndk_platform", + ], +} diff --git a/automotive/occupant_awareness/aidl/default/OccupantAwareness.cpp b/automotive/occupant_awareness/aidl/default/OccupantAwareness.cpp new file mode 100644 index 0000000000..ef5055f599 --- /dev/null +++ b/automotive/occupant_awareness/aidl/default/OccupantAwareness.cpp @@ -0,0 +1,122 @@ +/* + * 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. + */ + +#include "OccupantAwareness.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace occupant_awareness { +namespace V1_0 { +namespace implementation { + +using ndk::ScopedAStatus; + +static const int32_t kAllCapabilities = OccupantAwareness::CAP_PRESENSE_DETECTION | + OccupantAwareness::CAP_GAZE_DETECTION | + OccupantAwareness::CAP_DRIVER_MONITORING_DETECTION; + +ScopedAStatus OccupantAwareness::startDetection(OccupantAwarenessStatus* status) { + std::lock_guard lock(mMutex); + if (mStatus != OccupantAwarenessStatus::NOT_SUPPORTED) { + mStatus = OccupantAwarenessStatus::NOT_SUPPORTED; + if (mCallback) { + mCallback->onSystemStatusChanged(kAllCapabilities, + OccupantAwarenessStatus::NOT_SUPPORTED); + } + } + *status = mStatus; + return ScopedAStatus::ok(); +} + +ScopedAStatus OccupantAwareness::stopDetection(OccupantAwarenessStatus* status) { + std::lock_guard lock(mMutex); + if (mStatus != OccupantAwarenessStatus::NOT_INITIALIZED) { + mStatus = OccupantAwarenessStatus::NOT_INITIALIZED; + if (mCallback) { + mCallback->onSystemStatusChanged(kAllCapabilities, + OccupantAwarenessStatus::NOT_INITIALIZED); + } + } + *status = mStatus; + return ScopedAStatus::ok(); +} + +ScopedAStatus OccupantAwareness::getCapabilityForRole(Role occupantRole, int32_t* capabilities) { + if (!isValidRole(occupantRole)) { + return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED); + } + + // No awareness capability for default HAL. + *capabilities = 0; + return ScopedAStatus::ok(); +} + +ScopedAStatus OccupantAwareness::getState(Role occupantRole, int detectionCapability, + OccupantAwarenessStatus* status) { + if (!isValidRole(occupantRole)) { + return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED); + } + + if (!isValidDetectionCapabilities(detectionCapability) || + !isSingularCapability(detectionCapability)) { + return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED); + } + + std::lock_guard lock(mMutex); + *status = mStatus; + return ScopedAStatus::ok(); +} + +ScopedAStatus OccupantAwareness::setCallback( + const std::shared_ptr& callback) { + if (callback == nullptr) { + return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED); + } + + std::lock_guard lock(mMutex); + mCallback = callback; + return ScopedAStatus::ok(); +} + +ScopedAStatus OccupantAwareness::getLatestDetection(OccupantDetections* detections) { + // No detection generated for default hal. + (void)detections; + return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED); +} + +bool OccupantAwareness::isValidRole(Role occupantRole) { + int intVal = static_cast(occupantRole); + int allOccupants = static_cast(Role::ALL_OCCUPANTS); + return (occupantRole != Role::INVALID) && ((intVal & (~allOccupants)) == 0); +} + +bool OccupantAwareness::isValidDetectionCapabilities(int detectionCapabilities) { + return (detectionCapabilities != CAP_NONE) && + ((detectionCapabilities & (~kAllCapabilities)) == 0); +} + +bool OccupantAwareness::isSingularCapability(int detectionCapability) { + // Check whether the value is 0, or the value has only one bit set. + return (detectionCapability & (detectionCapability - 1)) == 0; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace occupant_awareness +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/occupant_awareness/aidl/default/OccupantAwareness.h b/automotive/occupant_awareness/aidl/default/OccupantAwareness.h new file mode 100644 index 0000000000..ac51aa4327 --- /dev/null +++ b/automotive/occupant_awareness/aidl/default/OccupantAwareness.h @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#pragma once +#include +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace occupant_awareness { +namespace V1_0 { +namespace implementation { + +using ::aidl::android::hardware::automotive::occupant_awareness::BnOccupantAwareness; +using ::aidl::android::hardware::automotive::occupant_awareness::IOccupantAwarenessClientCallback; +using ::aidl::android::hardware::automotive::occupant_awareness::OccupantAwarenessStatus; +using ::aidl::android::hardware::automotive::occupant_awareness::OccupantDetections; +using ::aidl::android::hardware::automotive::occupant_awareness::Role; + +/** + * The default HAL mimics a system which has no Occupant awareness capability. The hal does not + * do any useful work, and returns appropriate failure code / status. + **/ +class OccupantAwareness : public BnOccupantAwareness { + public: + // Methods from ::android::hardware::automotive::occupant_awareness::IOccupantAwareness + // follow. + ndk::ScopedAStatus startDetection(OccupantAwarenessStatus* status) override; + ndk::ScopedAStatus stopDetection(OccupantAwarenessStatus* status) override; + ndk::ScopedAStatus getCapabilityForRole(Role occupantRole, int32_t* capabilities) override; + ndk::ScopedAStatus getState(Role occupantRole, int detectionCapability, + OccupantAwarenessStatus* status) override; + ndk::ScopedAStatus setCallback( + const std::shared_ptr& callback) override; + ndk::ScopedAStatus getLatestDetection(OccupantDetections* detections) override; + + private: + bool isValidRole(Role occupantRole); + bool isValidDetectionCapabilities(int detectionCapabilities); + bool isSingularCapability(int detectionCapability); + + std::mutex mMutex; + std::shared_ptr mCallback = nullptr; + OccupantAwarenessStatus mStatus = OccupantAwarenessStatus::NOT_INITIALIZED; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace occupant_awareness +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/occupant_awareness/aidl/default/android.hardware.automotive.occupant_awareness@1.0-service.rc b/automotive/occupant_awareness/aidl/default/android.hardware.automotive.occupant_awareness@1.0-service.rc new file mode 100644 index 0000000000..35d5bca66c --- /dev/null +++ b/automotive/occupant_awareness/aidl/default/android.hardware.automotive.occupant_awareness@1.0-service.rc @@ -0,0 +1,4 @@ +service hal_occupant_awareness_default /vendor/bin/hw/android.hardware.automotive.occupant_awareness@1.0-service + class hal + user system + group system diff --git a/automotive/occupant_awareness/aidl/default/service.cpp b/automotive/occupant_awareness/aidl/default/service.cpp new file mode 100644 index 0000000000..44960fb13d --- /dev/null +++ b/automotive/occupant_awareness/aidl/default/service.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 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 "android.hardware.automotive.occupant_awareness@1.0-service" + +#include + +#include +#include +#include + +#include "OccupantAwareness.h" + +using ::aidl::android::hardware::automotive::occupant_awareness::IOccupantAwareness; +using ::android::hardware::automotive::occupant_awareness::V1_0::implementation::OccupantAwareness; +using ::ndk::ScopedAStatus; +using ::ndk::SharedRefBase; + +const static char kOccupantAwarenessServiceName[] = "default"; + +int main() { + ABinderProcess_setThreadPoolMaxThreadCount(0); + LOG(INFO) << "Occupant Awareness service is starting"; + std::shared_ptr occupantAwareness = SharedRefBase::make(); + + const std::string instance = + std::string() + IOccupantAwareness::descriptor + "/" + kOccupantAwarenessServiceName; + + binder_status_t status = + AServiceManager_addService(occupantAwareness->asBinder().get(), instance.c_str()); + if (status == STATUS_OK) { + LOG(INFO) << "Service " << kOccupantAwarenessServiceName << " is ready"; + ABinderProcess_joinThreadPool(); + } else { + LOG(ERROR) << "Could not register service " << kOccupantAwarenessServiceName + << ", status: " << status; + } + + // In normal operation, we don't expect the thread pool to exit. + LOG(ERROR) << "Occupant Awareness service is shutting down"; + return 1; +} diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 4bd833251a..c9eb6d4ef9 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -49,6 +49,13 @@ default + + android.hardware.automotive.occupant_awareness + + IOccupantAwareness + default + + android.hardware.automotive.vehicle 2.0 From 37e52fa88da707b715adcc179efaee72c4f1ae63 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 20 Nov 2019 23:09:11 -0800 Subject: [PATCH 0287/1022] Add Drm 1.3 New API(s): * IDrmFactory::getSupportedCryptoScheme Bug: 139134043 Test: MediaDrmTest Change-Id: Ibe8c7eabcbdd96618c7c336281582ff19f349de9 --- .../compatibility_matrix.current.xml | 2 +- current.txt | 2 + drm/1.3/Android.bp | 20 ++++++++++ drm/1.3/ICryptoFactory.hal | 32 ++++++++++++++++ drm/1.3/IDrmFactory.hal | 38 +++++++++++++++++++ 5 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 drm/1.3/Android.bp create mode 100644 drm/1.3/ICryptoFactory.hal create mode 100644 drm/1.3/IDrmFactory.hal diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index c6fd76ed7e..cf27a3f646 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -155,7 +155,7 @@ android.hardware.drm - 1.0-2 + 1.0-3 ICryptoFactory .* diff --git a/current.txt b/current.txt index 676beb0be2..8374ea4e5d 100644 --- a/current.txt +++ b/current.txt @@ -593,6 +593,8 @@ c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardwar 9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardware.cas@1.2::IMediaCasService 4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types +66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory +994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types diff --git a/drm/1.3/Android.bp b/drm/1.3/Android.bp new file mode 100644 index 0000000000..b0ffcb92a5 --- /dev/null +++ b/drm/1.3/Android.bp @@ -0,0 +1,20 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.drm@1.3", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "IDrmFactory.hal", + "ICryptoFactory.hal", + ], + interfaces: [ + "android.hardware.drm@1.0", + "android.hardware.drm@1.1", + "android.hardware.drm@1.2", + "android.hidl.base@1.0", + ], + gen_java: false, +} diff --git a/drm/1.3/ICryptoFactory.hal b/drm/1.3/ICryptoFactory.hal new file mode 100644 index 0000000000..d7864eba61 --- /dev/null +++ b/drm/1.3/ICryptoFactory.hal @@ -0,0 +1,32 @@ +/* + * 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. + */ +package android.hardware.drm@1.3; + +import @1.2::ICryptoFactory; + +/** + * ICryptoFactory is the main entry point for interacting with a vendor's + * crypto HAL to create crypto plugins. Crypto plugins create crypto sessions + * which are used by a codec to decrypt protected video content. + * + * The 1.3 factory must always create 1.2 ICryptoPlugin interfaces, which are + * returned via the 1.0 createPlugin method. + * + * The ICryptoFactory hal is required because all top-level interfaces + * have to be updated in a minor uprev. + */ +interface ICryptoFactory extends @1.2::ICryptoFactory { +}; diff --git a/drm/1.3/IDrmFactory.hal b/drm/1.3/IDrmFactory.hal new file mode 100644 index 0000000000..520802892a --- /dev/null +++ b/drm/1.3/IDrmFactory.hal @@ -0,0 +1,38 @@ +/* + * 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. + */ +package android.hardware.drm@1.3; + +import @1.2::IDrmFactory; + +/** + * IDrmFactory is the main entry point for interacting with a vendor's + * drm HAL to create drm plugin instances. A drm plugin instance + * creates drm sessions which are used to obtain keys for a crypto + * session so it can decrypt protected video content. + * + * The 1.3 factory must always create 1.2 IDrmPlugin interfaces, which are + * returned via the 1.0 createPlugin method. + */ + +interface IDrmFactory extends @1.2::IDrmFactory { + /** + * Return vector of uuids identifying crypto schemes supported by this HAL. + * + * @return schemes Vector of uuids for which isCryptoSchemeSupported is true; + * each uuid can be used as input to createPlugin. + */ + getSupportedCryptoSchemes() generates(vec schemes); +}; From 6d3cdc322b973f8bd25ecd7f4fd13d35c617e51e Mon Sep 17 00:00:00 2001 From: Przemyslaw Szczepaniak Date: Mon, 25 Nov 2019 11:04:19 +0000 Subject: [PATCH 0288/1022] Add TENSOR_QUANT8_ASYMM_SIGNED support for more ops Updated: BATCH_TO_SPACE_ND CHANNEL_SHUFFLE DEPTH_TO_SPACE GROUPED_CONV_2D PAD PAD_V2 QUANTIZE RESIZE_BILINEAR RESIZE_NEAREST_NEIGHBOR SPACE_TO_BATCH_ND SPACE_TO_DEPTH SPLIT TILE TOPK_V2 TRANSPOSE Bug: 143934582 Bug: 143934585 Bug: 143934628 Bug: 143934630 Bug: 143934721 Bug: 143935039 Bug: 143935052 Bug: 143935113 Bug: 143935115 Bug: 143935141 Bug: 143935353 Bug: 143935355 Bug: 143935392 Bug: 143935394 Bug: 143935413 Test: quantization coupling tests in CTS and VTS Change-Id: I7e1b65507ea0f7dcdfdb5fd98e7871d84f569ed7 --- current.txt | 4 +- neuralnetworks/1.2/types.hal | 14 ++- neuralnetworks/1.3/types.hal | 94 ++++++++++++++----- .../1.3/vts/functional/ValidateModel.cpp | 12 ++- 4 files changed, 95 insertions(+), 29 deletions(-) diff --git a/current.txt b/current.txt index 676beb0be2..6cc64d80fc 100644 --- a/current.txt +++ b/current.txt @@ -579,7 +579,7 @@ f1109cbb10297b7429a11fab42afa912710b303c9bf20bd5cdb8bd57b9c84186 android.hardwar 9d8ee57c490ffeaa28f702eaea8d198cb510e4bbfb99e6cb5f63e73341057c7c android.hardware.neuralnetworks@1.1::types fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice 40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel -72de91c3feba4b19c159cd1c413cbea596b78240caa43e31194e20e6f5b05c49 android.hardware.neuralnetworks@1.2::types +b40eb9dc491e3b203be2edca330ccd0417e9ca77b1b1b0f4c628a5fd269764a2 android.hardware.neuralnetworks@1.2::types a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface @@ -604,7 +604,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice 4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -2d16429145dc1158bf3e45c7de86a39e461dec3ec00512c11a7e5249535a2e96 android.hardware.neuralnetworks@1.3::types +8900b3a4ef6c0be540821fad0ad8b58b3654b70cfa38df662c640b88ea486d9f android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant 44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal index ef71ea8712..65ee81c7b0 100644 --- a/neuralnetworks/1.2/types.hal +++ b/neuralnetworks/1.2/types.hal @@ -3141,8 +3141,8 @@ enum OperationType : int32_t { * {@link SymmPerChannelQuantParams}) must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or - * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. For filter tensor * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias @@ -3181,7 +3181,8 @@ enum OperationType : int32_t { * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. For filter tensor * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias @@ -3668,14 +3669,17 @@ enum OperationType : int32_t { /** * Quantizes the input tensor. * - * The formula is: + * The formula for {@link OperandType::TENSOR_QUANT8_ASYMM} output tensor is: * * output = max(0, min(255, round(input / scale) + zeroPoint) * - * Supported tensor {@link OperandType}: + * Supported input tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * + * Supported output tensor {@link OperandType}: + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * Supported tensor rank: from 1 * * Inputs: diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index 3551d5762a..5fbf4e61c2 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -563,6 +563,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -583,7 +584,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape [batch, height*block_size, * width*block_size, depth/(block_size*block_size)]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ DEPTH_TO_SPACE = @1.2::OperationType:DEPTH_TO_SPACE, @@ -1499,6 +1501,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -1541,7 +1544,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, new_height, new_width, depth]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ RESIZE_BILINEAR = @1.2::OperationType:RESIZE_BILINEAR, @@ -1660,6 +1664,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -1680,7 +1685,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape [batches, height/block_size, * width/block_size, depth_in*block_size*block_size]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ SPACE_TO_DEPTH = @1.2::OperationType:SPACE_TO_DEPTH, @@ -1804,6 +1810,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -1822,7 +1829,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ BATCH_TO_SPACE_ND = @1.2::OperationType:BATCH_TO_SPACE_ND, @@ -1915,6 +1923,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * (full support since HAL version 1.2, see the output section) * * Supported tensor rank: up to 4 @@ -1937,7 +1946,8 @@ enum OperationType : int32_t { * of the padding: * output0.dimension[i] = * padding[i, 0] + input0.dimension[i] + padding[i, 1] - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * NOTE: Before HAL version 1.2, the pad value for @@ -1961,6 +1971,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * (full support since HAL version 1.2, see the output section) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. @@ -1988,7 +1999,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * NOTE: Before HAL version 1.2, the pad value for @@ -2137,6 +2149,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -2148,7 +2161,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint must be the same as input0. */ TRANSPOSE = @1.2::OperationType:TRANSPOSE, @@ -2694,6 +2708,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -2708,7 +2723,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} and same shape as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint must be the same as input0. */ CHANNEL_SHUFFLE = @1.2::OperationType:CHANNEL_SHUFFLE, @@ -3067,12 +3083,23 @@ enum OperationType : int32_t { * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to * * * input.scale * filter.scale). * + * * Quantized signed (since HAL version 1.3): + * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output. + * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to + * * * input.scale * filter.scale). + * * * Quantized with symmetric per channel quantization for the filter: * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, and output. * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter. * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0, * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). * + * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3): + * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, and output. + * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter. + * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0, + * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). + * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could @@ -3091,8 +3118,9 @@ enum OperationType : int32_t { * {@link SymmPerChannelQuantParams}) must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or - * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. For filter tensor * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias @@ -3131,7 +3159,9 @@ enum OperationType : int32_t { * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. For filter tensor * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias @@ -3156,7 +3186,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, out_height, out_width, depth_out]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint can be different from inputs' scale and zeroPoint. */ GROUPED_CONV_2D = @1.2::OperationType:GROUPED_CONV_2D, @@ -3512,6 +3543,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -3529,7 +3561,8 @@ enum OperationType : int32_t { * pad value must be of {@link OperandType::FLOAT16}. * For input tensor of {@link OperandType::TENSOR_FLOAT32}, the * pad value must be of {@link OperandType::FLOAT32}. - * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, * the pad value must be of {@link OperandType::INT32}. The * scale and zeroPoint are assumed to be the same as in input0. * @@ -3541,7 +3574,8 @@ enum OperationType : int32_t { * of the padding: * output0.dimension[i] = * padding[i, 0] + input0.dimension[i] + padding[i, 1] - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ PAD_V2 = @1.2::OperationType:PAD_V2, @@ -3618,14 +3652,23 @@ enum OperationType : int32_t { /** * Quantizes the input tensor. * - * The formula is: + * The formula for {@link OperandType::TENSOR_QUANT8_ASYMM} output tensor is: * * output = max(0, min(255, round(input / scale) + zeroPoint) * - * Supported tensor {@link OperandType}: + * The formula for {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} output + * tensor is: + * + * output = max(-128, min(127, round(input / scale) + zeroPoint) + * + * Supported input tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * + * Supported output tensor {@link OperandType}: + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) + * * Supported tensor rank: from 1 * * Inputs: @@ -3633,7 +3676,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of same shape as input0, but with - * {@link OperandType::TENSOR_QUANT8_ASYMM}. + * {@link OperandType::TENSOR_QUANT8_ASYMM} or. + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}. */ QUANTIZE = @1.2::OperationType:QUANTIZE, @@ -4140,6 +4184,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -4152,7 +4197,8 @@ enum OperationType : int32_t { * * Outputs: * * 0 ~ (num_splits - 1): Resulting subtensors. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ SPLIT = @1.2::OperationType:SPLIT, @@ -4188,6 +4234,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -4198,7 +4245,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tiled tensor of the same {@link OperandType} and rank as `input`. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ TILE = @1.2::OperationType:TILE, @@ -4214,6 +4262,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -4225,7 +4274,8 @@ enum OperationType : int32_t { * Outputs: * * 0: An n-D tensor of the same type as the input, containing the k * largest elements along each last dimensional slice. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * 1: An n-D tensor of type {@link OperandType::TENSOR_INT32} * containing the indices of values within the last dimension of input. @@ -4521,6 +4571,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -4560,7 +4611,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, new_height, new_width, depth]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ RESIZE_NEAREST_NEIGHBOR = @1.2::OperationType:RESIZE_NEAREST_NEIGHBOR, diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 46bbd3f655..242e12ecc7 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -344,7 +344,17 @@ static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, con return true; } } break; - case OperationType::QUANTIZE: + case OperationType::QUANTIZE: { + if (operand == operation.inputs[0] && + (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32)) { + return true; + } + if (operand == operation.outputs[0] && + (type == OperandType::TENSOR_QUANT8_ASYMM || + type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED)) { + return true; + } + } break; case OperationType::RANDOM_MULTINOMIAL: { if (operand == operation.inputs[0] && (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32)) { From 0cf075621d0783831ab2c2ccabfac4c379a1b5e8 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 7 Nov 2019 09:17:43 -0800 Subject: [PATCH 0289/1022] gralloc: add dump buffer(s) Add functions to IMapper to dump a buffer and to dump all the buffers in the current process. The dump includes all gettable or settable metadata. Bug: 141632317 Test: VtsHalGraphicsMapperV4_0TargetTest Change-Id: Iaa54b899aef185867b3fd66025c0eb251a9a7bd1 --- graphics/mapper/4.0/IMapper.hal | 45 ++++++++++ .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 89 +++++++++++++++++++ 2 files changed, 134 insertions(+) diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal index a1f07a4388..298f31ed56 100644 --- a/graphics/mapper/4.0/IMapper.hal +++ b/graphics/mapper/4.0/IMapper.hal @@ -515,5 +515,50 @@ interface IMapper { */ listSupportedMetadataTypes() generates (Error error, vec descriptions); + + struct MetadataDump { + /** + * The type of metadata being dumped. + */ + MetadataType metadataType; + /** + * The byte stream representation of the metadata. If the metadata is not + * gettable, the vector must be empty. + */ + vec metadata; + }; + + struct BufferDump { + /** + * A vector of all the metadata that is being dumped for a particular buffer. + */ + vec metadataDump; + }; + + /** + * Dumps a buffer's metadata. + * + * @param buffer Buffer that is being dumped + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the raw handle is invalid. + * - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of + * resources. + * @return bufferDump Struct representing the metadata being dumped + */ + dumpBuffer(pointer buffer) + generates (Error error, BufferDump bufferDump); + + /** + * Dumps the metadata for all the buffers in the current process. + * + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of + * resources. + * @return bufferDumps Vector of structs representing the buffers being dumped + */ + dumpBuffers() + generates (Error error, vec bufferDumps); }; diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index dd748db12b..870e6eb058 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -164,6 +164,42 @@ class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase { EXPECT_EQ(planeLayout.heightInSamples, planeLayout.crop.bottom); } + void verifyBufferDump(const IMapper::BufferDump& bufferDump, + const native_handle_t* bufferHandle = nullptr) { + std::set foundMetadataTypes; + + const std::vector metadataDump = bufferDump.metadataDump; + + for (const auto& dump : metadataDump) { + const auto& metadataType = dump.metadataType; + const auto& metadata = dump.metadata; + + if (!gralloc4::isStandardMetadataType(metadataType)) { + continue; + } + + StandardMetadataType type = gralloc4::getStandardMetadataTypeValue(metadataType); + + if (sRequiredMetadataTypes.find(type) == sRequiredMetadataTypes.end()) { + continue; + } + + ASSERT_EQ(foundMetadataTypes.find(type), foundMetadataTypes.end()); + foundMetadataTypes.insert(type); + + if (!bufferHandle) { + continue; + } + + hidl_vec metadataFromGet; + ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, metadataType, &metadataFromGet)); + + ASSERT_EQ(metadataFromGet, metadata); + } + + EXPECT_EQ(sRequiredMetadataTypes, foundMetadataTypes); + } + std::unique_ptr mGralloc; IMapper::BufferDescriptorInfo mDummyDescriptorInfo{}; static const std::set sRequiredMetadataTypes; @@ -1589,6 +1625,59 @@ TEST_F(GraphicsMapperHidlTest, ListSupportedMetadataTypes) { ASSERT_EQ(sRequiredMetadataTypes, foundMetadataTypes); } +/** + * Test IMapper::dumpBuffer() + */ +TEST_F(GraphicsMapperHidlTest, DumpBuffer) { + const native_handle_t* bufferHandle = nullptr; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); + auto buffer = const_cast(bufferHandle); + + IMapper::BufferDump bufferDump; + mGralloc->getMapper()->dumpBuffer(buffer, [&](const auto& tmpError, const auto& tmpBufferDump) { + ASSERT_EQ(Error::NONE, tmpError); + bufferDump = tmpBufferDump; + }); + + ASSERT_NO_FATAL_FAILURE(verifyBufferDump(bufferDump, buffer)); +} + +/** + * Test IMapper::dumpBuffer() with an invalid buffer + */ +TEST_F(GraphicsMapperHidlTest, DumpBufferNullBuffer) { + native_handle_t* bufferHandle = nullptr; + auto buffer = const_cast(bufferHandle); + + mGralloc->getMapper()->dumpBuffer(buffer, + [&](const auto& tmpError, const auto& /*tmpBufferDump*/) { + ASSERT_EQ(Error::BAD_BUFFER, tmpError); + }); +} + +/** + * Test IMapper::dumpBuffer() multiple + */ +TEST_F(GraphicsMapperHidlTest, DumpBuffers) { + size_t bufferCount = 10; + + for (int i = 0; i < bufferCount; i++) { + ASSERT_NO_FATAL_FAILURE(mGralloc->allocate(mDummyDescriptorInfo, true)); + } + + hidl_vec bufferDump; + mGralloc->getMapper()->dumpBuffers([&](const auto& tmpError, const auto& tmpBufferDump) { + ASSERT_EQ(Error::NONE, tmpError); + bufferDump = tmpBufferDump; + }); + + ASSERT_EQ(bufferCount, bufferDump.size()); + + for (const auto& dump : bufferDump) { + ASSERT_NO_FATAL_FAILURE(verifyBufferDump(dump)); + } +} + } // namespace } // namespace vts } // namespace V4_0 From 91134e7fb9cd0b6830d5fdbd6f640f631f283c25 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Tue, 26 Nov 2019 15:10:09 +0000 Subject: [PATCH 0290/1022] Add TENSOR_QUANT8_ASYMM_SIGNED support for more ops Updated: CONCATENATION REDUCE_MIN REDUCE_MAX STRIDED_SLICE RESHAPE SQUEEZE MEAN Bug: 143934554 Bug: 143935314 Bug: 143934726 Bug: 143934771 Bug: 143934557 Bug: 143934306 Bug: 143935140 Test: quantization coupling tests in CTS and VTS Change-Id: Ie73d070fd6f0a27185c1f26561710635b6e03b26 --- current.txt | 6 +- neuralnetworks/1.1/types.hal | 2 +- neuralnetworks/1.2/types.hal | 16 ++--- neuralnetworks/1.3/types.hal | 126 +++++++++++++---------------------- 4 files changed, 56 insertions(+), 94 deletions(-) diff --git a/current.txt b/current.txt index 6cc64d80fc..22db077383 100644 --- a/current.txt +++ b/current.txt @@ -576,10 +576,10 @@ cfa81f229b69f9011c58f48264fcb552447430fe68610eac514e811e65bc306a android.hardwar b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel f1109cbb10297b7429a11fab42afa912710b303c9bf20bd5cdb8bd57b9c84186 android.hardware.neuralnetworks@1.0::types -9d8ee57c490ffeaa28f702eaea8d198cb510e4bbfb99e6cb5f63e73341057c7c android.hardware.neuralnetworks@1.1::types +5f6d3097ba84cb63c430787123f4de1b31c11f90b531b98eae9a8623a5ae962a android.hardware.neuralnetworks@1.1::types fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice 40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel -b40eb9dc491e3b203be2edca330ccd0417e9ca77b1b1b0f4c628a5fd269764a2 android.hardware.neuralnetworks@1.2::types +2d5483fbf59d5fd2de94665a6df05da5c3d09de67561d0db5e9f09e59e9aea46 android.hardware.neuralnetworks@1.2::types a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface @@ -604,7 +604,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice 4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -8900b3a4ef6c0be540821fad0ad8b58b3654b70cfa38df662c640b88ea486d9f android.hardware.neuralnetworks@1.3::types +cf1d55e8c68300090747ab90b94c22e4c859b29c84ced68a317c595bb115eab2 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant 44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface diff --git a/neuralnetworks/1.1/types.hal b/neuralnetworks/1.1/types.hal index 3d78fb654d..da7ba78734 100644 --- a/neuralnetworks/1.1/types.hal +++ b/neuralnetworks/1.1/types.hal @@ -125,7 +125,7 @@ enum OperationType : @1.0::OperationType { * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, - * the scale and zeroPoint must be same as input0. + * the scale and zeroPoint must be the same as input0. */ MEAN = 31, diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal index 65ee81c7b0..b111d96e96 100644 --- a/neuralnetworks/1.2/types.hal +++ b/neuralnetworks/1.2/types.hal @@ -1954,7 +1954,7 @@ enum OperationType : int32_t { * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, - * the scale and zeroPoint must be same as input0. + * the scale and zeroPoint must be the same as input0. */ MEAN = @1.1::OperationType:MEAN, @@ -3141,8 +3141,8 @@ enum OperationType : int32_t { * {@link SymmPerChannelQuantParams}) must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or - * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type. - * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same + * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. For filter tensor * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias @@ -3181,8 +3181,7 @@ enum OperationType : int32_t { * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same - * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type. - * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. For filter tensor * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias @@ -3669,17 +3668,14 @@ enum OperationType : int32_t { /** * Quantizes the input tensor. * - * The formula for {@link OperandType::TENSOR_QUANT8_ASYMM} output tensor is: + * The formula is: * * output = max(0, min(255, round(input / scale) + zeroPoint) * - * Supported input tensor {@link OperandType}: + * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * - * Supported output tensor {@link OperandType}: - * * {@link OperandType::TENSOR_QUANT8_ASYMM} - * * Supported tensor rank: from 1 * * Inputs: diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index 5fbf4e61c2..84c48139ab 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -228,6 +228,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * (full support since HAL version 1.2, see the input section) + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -237,6 +238,9 @@ enum OperationType : int32_t { * Before HAL version 1.2, all input tensors of * {@link OperandType::TENSOR_QUANT8_ASYMM} * must have the same scale and zeroPoint as the output tensor. + * Input tensors of + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} + * are allowed to have different scale and zeroPoint. * Since HAL version 1.2, zero-sized tensors are supported. * * n: An {@link OperandType::INT32} scalar, specifying the * concatenation axis. @@ -247,6 +251,8 @@ enum OperationType : int32_t { * Since HAL version 1.2, for a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint values can be different from * input tensors. Before HAL version 1.2 they have to be the same as for the input tensors. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, + * the scale and zeroPoint values can be different from input tensors. */ CONCATENATION = @1.2::OperationType:CONCATENATION, @@ -563,7 +569,6 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} - * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -584,8 +589,7 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape [batch, height*block_size, * width*block_size, depth/(block_size*block_size)]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint must be the same as input0. */ DEPTH_TO_SPACE = @1.2::OperationType:DEPTH_TO_SPACE, @@ -1469,6 +1473,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4. * @@ -1485,7 +1490,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor, of shape specified by the input shape. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ RESHAPE = @1.2::OperationType:RESHAPE, @@ -1501,7 +1507,6 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) - * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -1544,8 +1549,7 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, new_height, new_width, depth]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint must be the same as input0. */ RESIZE_BILINEAR = @1.2::OperationType:RESIZE_BILINEAR, @@ -1664,7 +1668,6 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} - * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -1685,8 +1688,7 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape [batches, height/block_size, * width/block_size, depth_in*block_size*block_size]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint must be the same as input0. */ SPACE_TO_DEPTH = @1.2::OperationType:SPACE_TO_DEPTH, @@ -1810,7 +1812,6 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} - * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -1829,8 +1830,7 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint must be the same as input0. */ BATCH_TO_SPACE_ND = @1.2::OperationType:BATCH_TO_SPACE_ND, @@ -1890,6 +1890,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -1909,8 +1910,9 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, - * the scale and zeroPoint must be same as input0. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, + * the scale and zeroPoint must be the same as input0. */ MEAN = @1.2::OperationType:MEAN, @@ -1923,7 +1925,6 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} - * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * (full support since HAL version 1.2, see the output section) * * Supported tensor rank: up to 4 @@ -1946,8 +1947,7 @@ enum OperationType : int32_t { * of the padding: * output0.dimension[i] = * padding[i, 0] + input0.dimension[i] + padding[i, 1] - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint must be the same as input0. * * NOTE: Before HAL version 1.2, the pad value for @@ -1971,7 +1971,6 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} - * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * (full support since HAL version 1.2, see the output section) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. @@ -1999,8 +1998,7 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint must be the same as input0. * * NOTE: Before HAL version 1.2, the pad value for @@ -2021,6 +2019,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -2036,7 +2035,8 @@ enum OperationType : int32_t { * * 0: A tensor of the same {@link OperandType} as input0. Contains the * same data as input, but has one or more dimensions of size 1 * removed. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ SQUEEZE = @1.2::OperationType:SQUEEZE, @@ -2054,6 +2054,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -2083,7 +2084,8 @@ enum OperationType : int32_t { * Outputs: * * 0: A tensor of the same {@link OperandType} as input0 and rank (n - k), * where k is the number of bits set in shrink_axis_mask. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ STRIDED_SLICE = @1.2::OperationType:STRIDED_SLICE, @@ -2149,7 +2151,6 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} - * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -2161,8 +2162,7 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint must be the same as input0. */ TRANSPOSE = @1.2::OperationType:TRANSPOSE, @@ -2708,7 +2708,6 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} - * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -2723,8 +2722,7 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} and same shape as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint must be the same as input0. */ CHANNEL_SHUFFLE = @1.2::OperationType:CHANNEL_SHUFFLE, @@ -3083,23 +3081,12 @@ enum OperationType : int32_t { * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to * * * input.scale * filter.scale). * - * * Quantized signed (since HAL version 1.3): - * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output. - * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to - * * * input.scale * filter.scale). - * * * Quantized with symmetric per channel quantization for the filter: * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, and output. * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter. * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0, * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). * - * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3): - * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, and output. - * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter. - * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0, - * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). - * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could @@ -3118,9 +3105,8 @@ enum OperationType : int32_t { * {@link SymmPerChannelQuantParams}) must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or - * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type. - * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} + * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same + * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. For filter tensor * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias @@ -3159,9 +3145,7 @@ enum OperationType : int32_t { * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same - * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type. - * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} + * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. For filter tensor * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias @@ -3186,8 +3170,7 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, out_height, out_width, depth_out]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint can be different from inputs' scale and zeroPoint. */ GROUPED_CONV_2D = @1.2::OperationType:GROUPED_CONV_2D, @@ -3543,7 +3526,6 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} - * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -3561,8 +3543,7 @@ enum OperationType : int32_t { * pad value must be of {@link OperandType::FLOAT16}. * For input tensor of {@link OperandType::TENSOR_FLOAT32}, the * pad value must be of {@link OperandType::FLOAT32}. - * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, + * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the pad value must be of {@link OperandType::INT32}. The * scale and zeroPoint are assumed to be the same as in input0. * @@ -3574,8 +3555,7 @@ enum OperationType : int32_t { * of the padding: * output0.dimension[i] = * padding[i, 0] + input0.dimension[i] + padding[i, 1] - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint must be the same as input0. */ PAD_V2 = @1.2::OperationType:PAD_V2, @@ -3652,23 +3632,14 @@ enum OperationType : int32_t { /** * Quantizes the input tensor. * - * The formula for {@link OperandType::TENSOR_QUANT8_ASYMM} output tensor is: + * The formula is: * * output = max(0, min(255, round(input / scale) + zeroPoint) * - * The formula for {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} output - * tensor is: - * - * output = max(-128, min(127, round(input / scale) + zeroPoint) - * - * Supported input tensor {@link OperandType}: + * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * - * Supported output tensor {@link OperandType}: - * * {@link OperandType::TENSOR_QUANT8_ASYMM} - * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) - * * Supported tensor rank: from 1 * * Inputs: @@ -3676,8 +3647,7 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of same shape as input0, but with - * {@link OperandType::TENSOR_QUANT8_ASYMM} or. - * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}. + * {@link OperandType::TENSOR_QUANT8_ASYMM}. */ QUANTIZE = @1.2::OperationType:QUANTIZE, @@ -3868,6 +3838,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -3880,7 +3851,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ REDUCE_MAX = @1.2::OperationType:REDUCE_MAX, @@ -3897,6 +3869,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -3909,7 +3882,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ REDUCE_MIN = @1.2::OperationType:REDUCE_MIN, @@ -4184,7 +4158,6 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} - * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -4197,8 +4170,7 @@ enum OperationType : int32_t { * * Outputs: * * 0 ~ (num_splits - 1): Resulting subtensors. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint must be the same as input0. */ SPLIT = @1.2::OperationType:SPLIT, @@ -4234,7 +4206,6 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} - * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -4245,8 +4216,7 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tiled tensor of the same {@link OperandType} and rank as `input`. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint must be the same as input0. */ TILE = @1.2::OperationType:TILE, @@ -4262,7 +4232,6 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} - * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -4274,8 +4243,7 @@ enum OperationType : int32_t { * Outputs: * * 0: An n-D tensor of the same type as the input, containing the k * largest elements along each last dimensional slice. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint must be the same as input0. * * 1: An n-D tensor of type {@link OperandType::TENSOR_INT32} * containing the indices of values within the last dimension of input. @@ -4571,7 +4539,6 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} - * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -4611,8 +4578,7 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, new_height, new_width, depth]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint must be the same as input0. */ RESIZE_NEAREST_NEIGHBOR = @1.2::OperationType:RESIZE_NEAREST_NEIGHBOR, From 1b2c678bfcc23dd346b77743d26650835d3f3b42 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Mon, 2 Dec 2019 10:05:23 -0800 Subject: [PATCH 0291/1022] gralloc: test lock YCBCR_420_888 Gralloc 4 removes lockYCbCr but clients will still expect similar functionality to lockYCbCr. This test case ensure that gralloc will still behave sufficiently similarly when locking YCBCR_420_888. Bug: 141631415 Test: VtsHalGraphicsMapperV4_0TargetTest Change-Id: I60d2c220bab858eabe89a95b225d2816ab7289cc --- graphics/mapper/4.0/vts/functional/Android.bp | 3 + .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 147 +++++++++++++++++- 2 files changed, 148 insertions(+), 2 deletions(-) diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp index 5a7548a4f8..a8030ab633 100644 --- a/graphics/mapper/4.0/vts/functional/Android.bp +++ b/graphics/mapper/4.0/vts/functional/Android.bp @@ -30,5 +30,8 @@ cc_test { "libgralloctypes", "vintf-graphics-common-ndk_platform", ], + header_libs: [ + "libsystem_headers", + ], test_suites: ["general-tests"], } diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 870e6eb058..d63b078d1b 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -20,13 +20,13 @@ #include #include -//#include -//#include +#include #include #include #include #include +#include namespace android { namespace hardware { @@ -44,6 +44,7 @@ using aidl::android::hardware::graphics::common::Dataspace; using aidl::android::hardware::graphics::common::ExtendableType; using aidl::android::hardware::graphics::common::PlaneLayout; using aidl::android::hardware::graphics::common::PlaneLayoutComponent; +using aidl::android::hardware::graphics::common::PlaneLayoutComponentType; using aidl::android::hardware::graphics::common::StandardMetadataType; using DecodeFunction = std::function vec; + ASSERT_EQ(Error::NONE, + mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec)); + std::vector planeLayouts; + ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts)); + + outYCbCr->y = nullptr; + outYCbCr->cb = nullptr; + outYCbCr->cr = nullptr; + outYCbCr->ystride = 0; + outYCbCr->cstride = 0; + outYCbCr->chroma_step = 0; + + for (const auto& planeLayout : planeLayouts) { + for (const auto& planeLayoutComponent : planeLayout.components) { + std::string componentTypeName = planeLayoutComponent.type.name; + if (!std::strncmp(componentTypeName.c_str(), GRALLOC4_PLANE_LAYOUT_COMPONENT_TYPE, + componentTypeName.size())) { + continue; + } + ASSERT_EQ(0, planeLayoutComponent.offsetInBits % 8); + + uint8_t* tmpData = + data + planeLayout.offsetInBytes + (planeLayoutComponent.offsetInBits / 8); + uint64_t sampleIncrementInBytes; + + auto type = static_cast(planeLayoutComponent.type.value); + switch (type) { + case PlaneLayoutComponentType::Y: + ASSERT_EQ(nullptr, outYCbCr->y); + ASSERT_EQ(8, planeLayoutComponent.sizeInBits); + ASSERT_EQ(8, planeLayout.sampleIncrementInBits); + outYCbCr->y = tmpData; + outYCbCr->ystride = planeLayout.strideInBytes; + break; + + case PlaneLayoutComponentType::CB: + case PlaneLayoutComponentType::CR: + ASSERT_EQ(0, planeLayout.sampleIncrementInBits % 8); + + sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8; + ASSERT_TRUE(sampleIncrementInBytes == 1 || sampleIncrementInBytes == 2); + + if (outYCbCr->cstride == 0 && outYCbCr->chroma_step == 0) { + outYCbCr->cstride = planeLayout.strideInBytes; + outYCbCr->chroma_step = sampleIncrementInBytes; + } else { + ASSERT_EQ(outYCbCr->cstride, planeLayout.strideInBytes); + ASSERT_EQ(outYCbCr->chroma_step, sampleIncrementInBytes); + } + + if (type == PlaneLayoutComponentType::CB) { + ASSERT_EQ(nullptr, outYCbCr->cb); + outYCbCr->cb = tmpData; + } else { + ASSERT_EQ(nullptr, outYCbCr->cr); + outYCbCr->cr = tmpData; + } + break; + default: + break; + }; + } + } + + ASSERT_NE(nullptr, outYCbCr->y); + ASSERT_NE(nullptr, outYCbCr->cb); + ASSERT_NE(nullptr, outYCbCr->cr); + } + std::unique_ptr mGralloc; IMapper::BufferDescriptorInfo mDummyDescriptorInfo{}; static const std::set sRequiredMetadataTypes; @@ -482,6 +555,76 @@ TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) { } } +TEST_F(GraphicsMapperHidlTest, Lock_YCBCR_420_888) { + auto info = mDummyDescriptorInfo; + info.format = PixelFormat::YCBCR_420_888; + + const native_handle_t* bufferHandle; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, false, &stride)); + + // lock buffer for writing + const IMapper::Rect region{0, 0, static_cast(info.width), + static_cast(info.height)}; + int fence = -1; + uint8_t* data; + + ASSERT_NO_FATAL_FAILURE( + data = static_cast(mGralloc->lock(bufferHandle, info.usage, region, fence))); + + android_ycbcr yCbCr; + ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(bufferHandle, data, &yCbCr)); + + auto yData = static_cast(yCbCr.y); + auto cbData = static_cast(yCbCr.cb); + auto crData = static_cast(yCbCr.cr); + auto yStride = yCbCr.ystride; + auto cStride = yCbCr.cstride; + auto chromaStep = yCbCr.chroma_step; + + for (uint32_t y = 0; y < info.height; y++) { + for (uint32_t x = 0; x < info.width; x++) { + auto val = static_cast(info.height * y + x); + + yData[yStride * y + x] = val; + + if (y % chromaStep && x % chromaStep == 0) { + cbData[cStride * y / chromaStep + x / chromaStep] = val; + crData[cStride * y / chromaStep + x / chromaStep] = val; + } + } + } + + ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); + + // lock again for reading + ASSERT_NO_FATAL_FAILURE( + data = static_cast(mGralloc->lock(bufferHandle, info.usage, region, fence))); + + ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(bufferHandle, data, &yCbCr)); + + yData = static_cast(yCbCr.y); + cbData = static_cast(yCbCr.cb); + crData = static_cast(yCbCr.cr); + for (uint32_t y = 0; y < info.height; y++) { + for (uint32_t x = 0; x < info.width; x++) { + auto val = static_cast(info.height * y + x); + + EXPECT_EQ(val, yData[yStride * y + x]); + + if (y % chromaStep == 0 && x % chromaStep == 0) { + EXPECT_EQ(val, cbData[cStride * y / chromaStep + x / chromaStep]); + EXPECT_EQ(val, crData[cStride * y / chromaStep + x / chromaStep]); + } + } + } + + ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); + if (fence >= 0) { + close(fence); + } +} + /** * Test IMapper::unlock with bad access region */ From d36e12776fadfb4249c86eff4c3314773c35a358 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Tue, 26 Nov 2019 11:33:32 -0800 Subject: [PATCH 0292/1022] gralloc: add reserved region This patch adds a reserved region of shared memory to every gralloc native_handle_t. The reserved region of memory will allow future versions of Android to add new buffer features without requiring gralloc upgrades. Bug: 145232031 Test: VtsHalGraphicsMapperV4_0TargetTest Change-Id: I1bdfec0a6ef85097096035d3d38e5c9e7fcc32f2 --- graphics/mapper/4.0/IMapper.hal | 43 ++++++- graphics/mapper/4.0/utils/vts/MapperVts.cpp | 13 ++ .../vts/include/mapper-vts/4.0/MapperVts.h | 3 + .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 120 ++++++++++++++++++ 4 files changed, 176 insertions(+), 3 deletions(-) diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal index 298f31ed56..89d4128518 100644 --- a/graphics/mapper/4.0/IMapper.hal +++ b/graphics/mapper/4.0/IMapper.hal @@ -56,6 +56,12 @@ interface IMapper { * BufferUsage. */ bitfield usage; + + /** + * The size in bytes of the reserved region associated with the buffer. + * See getReservedRegion for more information. + */ + uint64_t reservedSize; }; struct Rect { @@ -71,9 +77,10 @@ interface IMapper { * * Since the buffer descriptor fully describes a buffer, any device * dependent or device independent checks must be performed here whenever - * possible. Specifically, when layered buffers are not supported, this - * function must return `UNSUPPORTED` if `description.layers` is great than - * 1. + * possible. When layered buffers are not supported, this function must + * return `UNSUPPORTED` if `description.layers` is great than 1. This + * function may return `UNSUPPORTED` if `description.reservedSize` is + * larger than a page. * * @param description Attributes of the descriptor. * @return error Error status of the call, which may be @@ -560,5 +567,35 @@ interface IMapper { */ dumpBuffers() generates (Error error, vec bufferDumps); + + /** + * Returns the region of shared memory associated with the buffer that is + * reserved for client use. + * + * The shared memory may be allocated from any shared memory allocator. + * The shared memory must be CPU-accessible and virtually contiguous. The + * starting address must be word-aligned. + * + * This function may only be called after importBuffer() has been called by the + * client. The reserved region must remain accessible until freeBuffer() has + * been called. After freeBuffer() has been called, the client must not access + * the reserved region. + * + * This reserved memory may be used in future versions of Android to + * help clients implement backwards compatible features without requiring + * IAllocator/IMapper updates. + * + * @param buffer Imported buffer handle. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the buffer is invalid. + * @return reservedRegion CPU-accessible pointer to the reserved region + * @return reservedSize the size of the reservedRegion that was requested + * in the BufferDescriptorInfo. + */ + getReservedRegion(pointer buffer) + generates (Error error, + pointer reservedRegion, + uint64_t reservedSize); }; diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp index 8073e6924c..1dafd4a455 100644 --- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp +++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp @@ -310,6 +310,19 @@ Error Gralloc::getFromBufferDescriptorInfo(const IMapper::BufferDescriptorInfo& return err; } +Error Gralloc::getReservedRegion(const native_handle_t* bufferHandle, void** outReservedRegion, + uint64_t* outReservedSize) { + Error err; + mMapper->getReservedRegion( + const_cast(bufferHandle), + [&](const auto& tmpError, const auto& tmpReservedRegion, const auto& tmpReservedSize) { + err = tmpError; + *outReservedRegion = tmpReservedRegion; + *outReservedSize = tmpReservedSize; + }); + return err; +} + } // namespace vts } // namespace V4_0 } // namespace mapper diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h index 6251e6649c..de77e1ff59 100644 --- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h +++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h @@ -90,6 +90,9 @@ class Gralloc { const IMapper::MetadataType& metadataType, hidl_vec* outVec); + Error getReservedRegion(const native_handle_t* bufferHandle, void** outReservedRegion, + uint64_t* outReservedSize); + private: void init(const std::string& allocatorServiceName, const std::string& mapperServiceName); diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index d63b078d1b..f5c0617cd7 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "VtsHalGraphicsMapperV4_0TargetTest" +#include #include #include #include @@ -82,6 +83,7 @@ class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase { mDummyDescriptorInfo.format = PixelFormat::RGBA_8888; mDummyDescriptorInfo.usage = static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); + mDummyDescriptorInfo.reservedSize = 0; } void TearDown() override {} @@ -1821,6 +1823,124 @@ TEST_F(GraphicsMapperHidlTest, DumpBuffers) { } } +/** + * Test IMapper::getReservedRegion() + */ +TEST_F(GraphicsMapperHidlTest, GetReservedRegion) { + const native_handle_t* bufferHandle = nullptr; + auto info = mDummyDescriptorInfo; + + const int pageSize = getpagesize(); + ASSERT_GE(0, pageSize); + std::vector requestedReservedSizes{1, 10, 333, static_cast(pageSize) / 2, + static_cast(pageSize)}; + + for (auto requestedReservedSize : requestedReservedSizes) { + info.reservedSize = requestedReservedSize; + + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true)); + + void* reservedRegion = nullptr; + uint64_t reservedSize = 0; + ASSERT_EQ(Error::NONE, + mGralloc->getReservedRegion(bufferHandle, &reservedRegion, &reservedSize)); + ASSERT_NE(nullptr, reservedRegion); + ASSERT_EQ(requestedReservedSize, reservedSize); + + uint8_t testValue = 1; + memset(reservedRegion, testValue, reservedSize); + for (uint64_t i = 0; i < reservedSize; i++) { + ASSERT_EQ(testValue, static_cast(reservedRegion)[i]); + } + } +} + +/** + * Test IMapper::getReservedRegion() request over a page + */ +TEST_F(GraphicsMapperHidlTest, GetLargeReservedRegion) { + const native_handle_t* bufferHandle = nullptr; + auto info = mDummyDescriptorInfo; + + const int pageSize = getpagesize(); + ASSERT_GE(0, pageSize); + std::vector requestedReservedSizes{static_cast(pageSize) * 2, + static_cast(pageSize) * 10, + static_cast(pageSize) * 1000}; + + for (auto requestedReservedSize : requestedReservedSizes) { + info.reservedSize = requestedReservedSize; + + BufferDescriptor descriptor; + ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(info)); + + Error err; + mGralloc->getAllocator()->allocate( + descriptor, 1, + [&](const auto& tmpError, const auto&, const auto&) { err = tmpError; }); + if (err == Error::UNSUPPORTED) { + continue; + } + ASSERT_EQ(Error::NONE, err); + + void* reservedRegion = nullptr; + uint64_t reservedSize = 0; + err = mGralloc->getReservedRegion(bufferHandle, &reservedRegion, &reservedSize); + + ASSERT_EQ(Error::NONE, err); + ASSERT_NE(nullptr, reservedRegion); + ASSERT_EQ(requestedReservedSize, reservedSize); + } +} + +/** + * Test IMapper::getReservedRegion() across multiple mappers + */ +TEST_F(GraphicsMapperHidlTest, GetReservedRegionMultiple) { + const native_handle_t* bufferHandle = nullptr; + auto info = mDummyDescriptorInfo; + + const int pageSize = getpagesize(); + ASSERT_GE(0, pageSize); + info.reservedSize = pageSize; + + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true)); + + void* reservedRegion1 = nullptr; + uint64_t reservedSize1 = 0; + ASSERT_EQ(Error::NONE, + mGralloc->getReservedRegion(bufferHandle, &reservedRegion1, &reservedSize1)); + ASSERT_NE(nullptr, reservedRegion1); + ASSERT_EQ(info.reservedSize, reservedSize1); + + std::unique_ptr anotherGralloc; + ASSERT_NO_FATAL_FAILURE( + anotherGralloc = std::make_unique( + GraphicsMapperHidlEnvironment::Instance()->getServiceName(), + GraphicsMapperHidlEnvironment::Instance()->getServiceName())); + + void* reservedRegion2 = nullptr; + uint64_t reservedSize2 = 0; + ASSERT_EQ(Error::NONE, + mGralloc->getReservedRegion(bufferHandle, &reservedRegion2, &reservedSize2)); + ASSERT_EQ(reservedRegion1, reservedRegion2); + ASSERT_EQ(reservedSize1, reservedSize2); +} + +/** + * Test IMapper::getReservedRegion() with a bad buffer + */ +TEST_F(GraphicsMapperHidlTest, GetReservedRegionBadBuffer) { + const native_handle_t* bufferHandle = nullptr; + + void* reservedRegion = nullptr; + uint64_t reservedSize = 0; + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->getReservedRegion(bufferHandle, &reservedRegion, &reservedSize)); + ASSERT_EQ(nullptr, reservedRegion); + ASSERT_EQ(0, reservedSize); +} + } // namespace } // namespace vts } // namespace V4_0 From b6663d17030927cd3841392f5f16c99e9a033d0a Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Fri, 1 Nov 2019 13:19:31 -0700 Subject: [PATCH 0293/1022] Add HAL for 5G bands Added NgranBands and RadioAccessNetwork NGRAN Updated RadioAccessSpecifier and NetworkScanRequest Updated IRadio and IRadioResponse to use updated structs/enums Bug: 143683654 Test: build Change-Id: I2e751a544b626d48a7c78b7bdcb4ac6477e25bc6 --- current.txt | 7 +- radio/1.5/IRadio.hal | 31 +- radio/1.5/IRadioResponse.hal | 24 + radio/1.5/types.hal | 138 ++++++ .../functional/VtsHalRadioV1_5TargetTest.cpp | 2 +- .../1.5/vts/functional/radio_hidl_hal_api.cpp | 419 ++++++++++++++++++ .../functional/radio_hidl_hal_utils_v1_5.h | 9 +- radio/1.5/vts/functional/radio_response.cpp | 13 + 8 files changed, 636 insertions(+), 7 deletions(-) diff --git a/current.txt b/current.txt index 22db077383..3e2a5d13b7 100644 --- a/current.txt +++ b/current.txt @@ -611,12 +611,11 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar 619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types -274fb1254a6d1a97824ec5c880eeefc0e410dc6d3a2a4c34052201169d2b7de0 android.hardware.radio@1.5::types -4c666aaf3944ad91c2428b8456d0db4a2f81191f8c294f046a2f539e9fc7b6fd android.hardware.radio@1.5::IRadio +521d1fe5b9f212b7b37ab71c0d33f5d2622618837e318e99a80d882f186af6b9 android.hardware.radio@1.5::types +3f1e2410d9bed4e7d41c6a589fe3a7943bc904b0066e40e0199a7c58427ac4e9 android.hardware.radio@1.5::IRadio 3afac66f21a33bc9c4b80481c7d5540038348651d9a7d8af64ea13610af138da android.hardware.radio@1.5::IRadioIndication -70e977f2ccefd2e503bedb3a66313639b53fbc7bde025538b07f41e2292b6624 android.hardware.radio@1.5::IRadioResponse +caf00e0d942b77b17d7061b38de11e5b19e1da90d4818434cb4916ba89e30686 android.hardware.radio@1.5::IRadioResponse 55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication 7683fed9d253956071f18b152e6be657719536f98d9b534433d5e411bcde5061 android.hardware.radio.config@1.3::IRadioConfigResponse - diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal index a3001fdfa2..6d422bed0b 100644 --- a/radio/1.5/IRadio.hal +++ b/radio/1.5/IRadio.hal @@ -18,6 +18,8 @@ package android.hardware.radio@1.5; import @1.4::IRadio; import @1.5::AccessNetwork; +import @1.5::NetworkScanRequest; +import @1.5::RadioAccessSpecifier; import @1.5::SignalThresholdInfo; /** @@ -29,7 +31,6 @@ import @1.5::SignalThresholdInfo; * setResponseFunctions must work with @1.5::IRadioResponse and @1.5::IRadioIndication. */ interface IRadio extends @1.4::IRadio { - /** * Sets the signal strength reporting criteria. * @@ -96,4 +97,32 @@ interface IRadio extends @1.4::IRadio { * Response callback is IRadioResponse.canToggleUiccApplicationsEnablementResponse() */ oneway canToggleUiccApplicationsEnablement(int32_t serial); + + /** + * Specify which bands modem's background scan must act on. + * If specifyChannels is true, it only scans bands specified in specifiers. + * If specifyChannels is false, it scans all bands. + * + * For example, CBRS is only on LTE band 48. By specifying this band, + * modem saves more power. + * + * @param serial Serial number of request. + * @param specifyChannels whether to scan bands defined in specifiers. + * @param specifiers which bands to scan. Only used if specifyChannels is true. + * + * Response callback is IRadioResponse.setSystemSelectionChannelsResponse() + */ + oneway setSystemSelectionChannels_1_5(int32_t serial, bool specifyChannels, + vec specifiers); + + /** + * Starts a network scan + * + * @param serial Serial number of request. + * @param request Defines the radio networks/bands/channels which need to be scanned. + * + * Same API as @1.4::IRadio.startNetworkScan_1_4, except using + * 1.5 version of NetworkScanRequest + */ + oneway startNetworkScan_1_5(int32_t serial, NetworkScanRequest request); }; diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal index c136ba610a..e7a3852728 100644 --- a/radio/1.5/IRadioResponse.hal +++ b/radio/1.5/IRadioResponse.hal @@ -69,4 +69,28 @@ interface IRadioResponse extends @1.4::IRadioResponse { * RadioError:INTERNAL_ERR */ oneway canToggleUiccApplicationsEnablementResponse(RadioResponseInfo info, bool canToggle); + + /** + * @param info Response info struct containing response type, serial no. and error + * + * Valid errors returned: + * RadioError:NONE + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:INTERNAL_ERR + * RadioError:INVALID_ARGUMENTS + */ + oneway setSystemSelectionChannelsResponse_1_5(RadioResponseInfo info); + + /** + * @param info Response info struct containing response type, serial no. and error + * + * Valid errors returned: + * RadioError:NONE + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:DEVICE_IN_USE + * RadioError:INTERNAL_ERR + * RadioError:MODEM_ERR + * RadioError:INVALID_ARGUMENTS + */ + oneway startNetworkScanResponse_1_5(RadioResponseInfo info); }; diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index 2441b65178..068f56b252 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -16,6 +16,13 @@ package android.hardware.radio@1.5; +import @1.1::EutranBands; +import @1.1::GeranBands; +import @1.1::RadioAccessNetworks; +import @1.1::RadioAccessSpecifier; +import @1.1::ScanType; +import @1.1::UtranBands; +import @1.2::NetworkScanRequest; import @1.4::AccessNetwork; /** @@ -114,3 +121,134 @@ enum AccessNetwork : @1.4::AccessNetwork { */ NGRAN = 6, }; + +enum RadioAccessNetworks : @1.1::RadioAccessNetworks { + NGRAN = 4, +}; + +/** + * Overwritten from @1.1::RadioAccessSpecifier to add NGRAN and NgranBands + */ +struct RadioAccessSpecifier { + /** + * The type of network to scan. + */ + RadioAccessNetworks radioAccessNetwork; + + /** + * The frequency bands to scan. + * Maximum length of the vector is 8. + */ + safe_union Bands { + /** Valid only if radioAccessNetwork = GERAN. */ + vec geranBands; + /** Valid only if radioAccessNetwork = UTRAN. */ + vec utranBands; + /** Valid only if radioAccessNetwork = EUTRAN. */ + vec eutranBands; + /** Valid only if radioAccessNetwork = NGRAN. */ + vec ngranBands; + } bands; + + /** + * The radio channels to scan as defined in 3GPP TS 25.101 and 36.101. + * Maximum length of the vector is 32. + */ + vec channels; +}; + +enum NgranBands : int32_t { + /** 3GPP TS 28.101-1, Table 5.2-1: FR1 bands */ + BAND_1 = 1, + BAND_2 = 2, + BAND_3 = 3, + BAND_5 = 5, + BAND_7 = 7, + BAND_8 = 8, + BAND_12 = 12, + BAND_20 = 20, + BAND_25 = 25, + BAND_28 = 28, + BAND_34 = 34, + BAND_38 = 38, + BAND_39 = 39, + BAND_40 = 40, + BAND_41 = 41, + BAND_50 = 50, + BAND_51 = 51, + BAND_66 = 66, + BAND_70 = 70, + BAND_71 = 71, + BAND_74 = 74, + BAND_75 = 75, + BAND_76 = 76, + BAND_77 = 77, + BAND_78 = 78, + BAND_79 = 79, + BAND_80 = 80, + BAND_81 = 81, + BAND_82 = 82, + BAND_83 = 83, + BAND_84 = 84, + BAND_86 = 86, + /** 3GPP TS 28.101-2, Table 5.2-1: FR2 bands */ + BAND_257 = 257, + BAND_258 = 258, + BAND_260 = 260, + BAND_261 = 261, +}; + +/** + * Overwritten from @1.2::NetworkScanRequest to update + * RadioAccessSpecifier to 1.5 version + */ +struct NetworkScanRequest { + ScanType type; + + /** + * Time interval in seconds between the completion of one scan and the start of + * a subsequent scan. + * Implementations may ignore this field unless the 'type' is 'PERIODIC'. + * Range: ScanIntervalRange:MIN to ScanIntervalRange:MAX + */ + int32_t interval; + + /** + * Networks with bands/channels to scan + * Maximum length of the vector is RadioConst:RADIO_ACCESS_SPECIFIER_MAX_SIZE + */ + vec specifiers; + + /** + * Maximum duration of the periodic search (in seconds). + * If the search lasts maxSearchTime, it must be terminated. + * Range: MaxSearchTimeRange:MIN to MaxSearchTimeRange:MAX + */ + int32_t maxSearchTime; + + /** + * Indicates whether the modem must report incremental results of the network scan + * to the client. + * FALSE – Incremental results must not be reported. + * TRUE – Incremental must be reported. + */ + bool incrementalResults; + + /** + * Indicates the periodicity with which the modem must report incremental results to + * the client (in seconds). + * Implementations may ignore this value if the incremental results are not requested. + * This value must be less than or equal to maxSearchTime. + * Range: IncrementalResultsPeriodicityRange:MIN to IncrementalResultsPeriodicityRange:MAX + */ + int32_t incrementalResultsPeriodicity; + + /** + * Describes the List of PLMN ids (MCC-MNC) + * If any PLMN of this list is found, search must end at that point and results with all + * PLMN found until that point should be sent as response. + * If the list is not sent, search to be completed until end and all PLMNs found to be + * reported. + */ + vec mccMncs; +}; diff --git a/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp b/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp index b72febddf0..5f11d19520 100644 --- a/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp +++ b/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp @@ -23,4 +23,4 @@ int main(int argc, char** argv) { int status = RUN_ALL_TESTS(); LOG(INFO) << "Test result = " << status; return status; -} \ No newline at end of file +} diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp index 72e8d5ebb3..4df5b14b1c 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp @@ -446,3 +446,422 @@ TEST_F(RadioHidlTest_v1_5, areUiccApplicationsEnabled) { EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); } } + +/* + * Test IRadio.setSystemSelectionChannels_1_5() for the response returned. + */ +TEST_F(RadioHidlTest_v1_5, setSystemSelectionChannels_1_5) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; + rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480}; + + ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = { + .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN, + .bands = rasBands, + .channels = {1, 2}}; + + Return res = radio_v1_5->setSystemSelectionChannels_1_5(serial, true, {specifier}); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + ALOGI("setSystemSelectionChannels, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_v1_5->rspInfo.error, + {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR})); + + if (radioRsp_v1_5->rspInfo.error == RadioError::NONE) { + serial = GetRandomSerialNumber(); + Return res = radio_v1_5->setSystemSelectionChannels_1_5(serial, false, {specifier}); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + ALOGI("setSystemSelectionChannels, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); + } +} + +/* + * Test IRadio.startNetworkScan_1_5() for the response returned. + */ +TEST_F(RadioHidlTest_v1_5, startNetworkScan) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; + rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480}; + + ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = { + .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN, + .bands = rasBands, + .channels = {1, 2}}; + + ::android::hardware::radio::V1_5::NetworkScanRequest request = { + .type = ScanType::ONE_SHOT, + .interval = 60, + .specifiers = {specifier}, + .maxSearchTime = 60, + .incrementalResults = false, + .incrementalResultsPeriodicity = 1}; + + Return res = radio_v1_5->startNetworkScan_1_5(serial, request); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + ALOGI("startNetworkScan, rspInfo.error = %s\n", toString(radioRsp_v1_5->rspInfo.error).c_str()); + + if (cardStatus.base.base.cardState == CardState::ABSENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::SIM_ABSENT})); + } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + // OPERATION_NOT_ALLOWED should not be allowed; however, some vendors do + // not support the required manual GSM search functionality. This is + // tracked in b/112206766. Modems have "GSM" rat scan need to + // support scanning requests combined with some parameters. + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED})); + } +} + +/* + * Test IRadio.startNetworkScan_1_5() with invalid specifier. + */ +TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidArgument) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::NetworkScanRequest request = {.type = ScanType::ONE_SHOT, + .interval = 60}; + + Return res = radio_v1_5->startNetworkScan_1_5(serial, request); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + ALOGI("startNetworkScan_InvalidArgument, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + + if (cardStatus.base.base.cardState == CardState::ABSENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); + } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_v1_5->rspInfo.error, + {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + } +} + +/* + * Test IRadio.startNetworkScan_1_5() with invalid interval (lower boundary). + */ +TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidInterval1) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; + rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480}; + + ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = { + .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN, + .bands = rasBands, + .channels = {1, 2}}; + + ::android::hardware::radio::V1_5::NetworkScanRequest request = { + .type = ScanType::ONE_SHOT, + .interval = 4, + .specifiers = {specifier}, + .maxSearchTime = 60, + .incrementalResults = false, + .incrementalResultsPeriodicity = 1}; + + Return res = radio_v1_5->startNetworkScan_1_5(serial, request); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + ALOGI("startNetworkScan_InvalidInterval1, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + if (cardStatus.base.base.cardState == CardState::ABSENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); + } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_v1_5->rspInfo.error, + {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + } +} + +/* + * Test IRadio.startNetworkScan_1_5() with invalid interval (upper boundary). + */ +TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidInterval2) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; + rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480}; + + ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = { + .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN, + .bands = rasBands, + .channels = {1, 2}}; + + ::android::hardware::radio::V1_5::NetworkScanRequest request = { + .type = ScanType::ONE_SHOT, + .interval = 301, + .specifiers = {specifier}, + .maxSearchTime = 60, + .incrementalResults = false, + .incrementalResultsPeriodicity = 1}; + + Return res = radio_v1_5->startNetworkScan_1_5(serial, request); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + ALOGI("startNetworkScan_InvalidInterval2, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + if (cardStatus.base.base.cardState == CardState::ABSENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); + } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_v1_5->rspInfo.error, + {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + } +} + +/* + * Test IRadio.startNetworkScan_1_5() with invalid max search time (lower boundary). + */ +TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidMaxSearchTime1) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; + rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480}; + + ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = { + .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN, + .bands = rasBands, + .channels = {1, 2}}; + + ::android::hardware::radio::V1_5::NetworkScanRequest request = { + .type = ScanType::ONE_SHOT, + .interval = 60, + .specifiers = {specifier}, + .maxSearchTime = 59, + .incrementalResults = false, + .incrementalResultsPeriodicity = 1}; + + Return res = radio_v1_5->startNetworkScan_1_5(serial, request); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + ALOGI("startNetworkScan_InvalidMaxSearchTime1, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + if (cardStatus.base.base.cardState == CardState::ABSENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); + } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_v1_5->rspInfo.error, + {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + } +} + +/* + * Test IRadio.startNetworkScan_1_5() with invalid max search time (upper boundary). + */ +TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidMaxSearchTime2) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; + rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480}; + + ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = { + .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN, + .bands = rasBands, + .channels = {1, 2}}; + + ::android::hardware::radio::V1_5::NetworkScanRequest request = { + .type = ScanType::ONE_SHOT, + .interval = 60, + .specifiers = {specifier}, + .maxSearchTime = 3601, + .incrementalResults = false, + .incrementalResultsPeriodicity = 1}; + + Return res = radio_v1_5->startNetworkScan_1_5(serial, request); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + ALOGI("startNetworkScan_InvalidMaxSearchTime2, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + if (cardStatus.base.base.cardState == CardState::ABSENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); + } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_v1_5->rspInfo.error, + {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + } +} + +/* + * Test IRadio.startNetworkScan_1_5() with invalid periodicity (lower boundary). + */ +TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidPeriodicity1) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; + rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480}; + + ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = { + .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN, + .bands = rasBands, + .channels = {1, 2}}; + + ::android::hardware::radio::V1_5::NetworkScanRequest request = { + .type = ScanType::ONE_SHOT, + .interval = 60, + .specifiers = {specifier}, + .maxSearchTime = 600, + .incrementalResults = true, + .incrementalResultsPeriodicity = 0}; + + Return res = radio_v1_5->startNetworkScan_1_5(serial, request); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + ALOGI("startNetworkScan_InvalidPeriodicity1, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + if (cardStatus.base.base.cardState == CardState::ABSENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); + } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_v1_5->rspInfo.error, + {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + } +} + +/* + * Test IRadio.startNetworkScan_1_5() with invalid periodicity (upper boundary). + */ +TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidPeriodicity2) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; + rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480}; + + ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = { + .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN, + .bands = rasBands, + .channels = {1, 2}}; + + ::android::hardware::radio::V1_5::NetworkScanRequest request = { + .type = ScanType::ONE_SHOT, + .interval = 60, + .specifiers = {specifier}, + .maxSearchTime = 600, + .incrementalResults = true, + .incrementalResultsPeriodicity = 11}; + + Return res = radio_v1_5->startNetworkScan_1_5(serial, request); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + ALOGI("startNetworkScan_InvalidPeriodicity2, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + if (cardStatus.base.base.cardState == CardState::ABSENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); + } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_v1_5->rspInfo.error, + {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + } +} + +/* + * Test IRadio.startNetworkScan_1_5() with valid periodicity + */ +TEST_F(RadioHidlTest_v1_5, startNetworkScan_GoodRequest1) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; + rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480}; + + ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = { + .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN, + .bands = rasBands, + .channels = {1, 2}}; + + ::android::hardware::radio::V1_5::NetworkScanRequest request = { + .type = ScanType::ONE_SHOT, + .interval = 60, + .specifiers = {specifier}, + .maxSearchTime = 360, + .incrementalResults = false, + .incrementalResultsPeriodicity = 10}; + + Return res = radio_v1_5->startNetworkScan_1_5(serial, request); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + ALOGI("startNetworkScan_GoodRequest1, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + if (cardStatus.base.base.cardState == CardState::ABSENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::NONE, RadioError::SIM_ABSENT})); + } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::NONE, RadioError::INVALID_ARGUMENTS, + RadioError::REQUEST_NOT_SUPPORTED})); + } +} + +/* + * Test IRadio.startNetworkScan_1_5() with valid periodicity and plmns + */ +TEST_F(RadioHidlTest_v1_5, startNetworkScan_GoodRequest2) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; + rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480}; + + ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = { + .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN, + .bands = rasBands, + .channels = {1, 2}}; + + ::android::hardware::radio::V1_5::NetworkScanRequest request = { + .type = ScanType::ONE_SHOT, + .interval = 60, + .specifiers = {specifier}, + .maxSearchTime = 360, + .incrementalResults = false, + .incrementalResultsPeriodicity = 10, + .mccMncs = {"310410"}}; + + Return res = radio_v1_5->startNetworkScan_1_5(serial, request); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + ALOGI("startNetworkScan_GoodRequest2, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + if (cardStatus.base.base.cardState == CardState::ABSENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::NONE, RadioError::SIM_ABSENT})); + } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::NONE, RadioError::INVALID_ARGUMENTS, + RadioError::REQUEST_NOT_SUPPORTED})); + } +} diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index c05359d631..01bda698bc 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -53,7 +53,7 @@ using ::android::hardware::Void; class RadioHidlTest_v1_5; extern ::android::hardware::radio::V1_4::CardStatus cardStatus; -/* Callback class for radio respons v1_5 */ +/* Callback class for radio response v1_5 */ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioResponse { protected: RadioHidlTest_v1_5& parent_v1_5; @@ -530,10 +530,17 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon /* 1.5 Api */ Return setSignalStrengthReportingCriteriaResponse_1_5(const RadioResponseInfo& info); + Return enableUiccApplicationsResponse(const RadioResponseInfo& info); + Return areUiccApplicationsEnabledResponse(const RadioResponseInfo& info, bool enabled); + Return canToggleUiccApplicationsEnablementResponse(const RadioResponseInfo& info, bool canToggle); + + Return setSystemSelectionChannelsResponse_1_5(const RadioResponseInfo& info); + + Return startNetworkScanResponse_1_5(const RadioResponseInfo& info); }; /* Callback class for radio indication */ diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp index 78c03a9773..5964c96d35 100644 --- a/radio/1.5/vts/functional/radio_response.cpp +++ b/radio/1.5/vts/functional/radio_response.cpp @@ -915,3 +915,16 @@ Return RadioResponse_v1_5::canToggleUiccApplicationsEnablementResponse( parent_v1_5.notify(info.serial); return Void(); } + +Return RadioResponse_v1_5::setSystemSelectionChannelsResponse_1_5( + const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::startNetworkScanResponse_1_5(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} From 2391e8c16eb30184ff025c8f9304d5858f0c1fc8 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 3 Dec 2019 11:04:11 -0800 Subject: [PATCH 0294/1022] composer: register only vsync_2_4 callback Composer 2.4 extends vsync callback by exposing a new vsync_2_4 callback. Both should not be registered at the same time. Test: rev up composer to 2.4 and test refresh rate switching Bug: 141329414 Change-Id: If41f45cab21ed16a7b2f36b3b95fb3591b04c900 --- .../passthrough/include/composer-passthrough/2.4/HwcHal.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h index d59d0d5361..53a0a3a70c 100644 --- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h +++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h @@ -58,9 +58,6 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { BaseType2_1::mDispatch.registerCallback( mDevice, HWC2_CALLBACK_REFRESH, this, reinterpret_cast(refreshHook)); - BaseType2_1::mDispatch.registerCallback( - mDevice, HWC2_CALLBACK_VSYNC, this, - reinterpret_cast(vsyncHook)); BaseType2_1::mDispatch.registerCallback( mDevice, HWC2_CALLBACK_VSYNC_2_4, this, reinterpret_cast(vsync_2_4_Hook)); @@ -80,7 +77,6 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { // which is likely incorrect BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this, nullptr); BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this, nullptr); - BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this, nullptr); BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_2_4, this, nullptr); BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_PERIOD_TIMING_CHANGED, this, nullptr); From f2ee9c19df15cea38830f2e74b1b1af1f07dc600 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Fri, 1 Nov 2019 15:03:03 -0700 Subject: [PATCH 0295/1022] Convert VtsHalGraphicsComposerV2_2TargetTest to be parameterized test Bug: 142397658 Test: atest VtsHalGraphicsComposerV2_2TargetTest Change-Id: I85cfd932f420a73a4fbf1853313b8d0127157757 --- .../composer/2.2/vts/functional/Android.bp | 3 +- ...VtsHalGraphicsComposerV2_2ReadbackTest.cpp | 93 +++++++++--------- .../VtsHalGraphicsComposerV2_2TargetTest.cpp | 97 ++++++++----------- 3 files changed, 91 insertions(+), 102 deletions(-) diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp index 21ba9f3d7d..f987516a33 100644 --- a/graphics/composer/2.2/vts/functional/Android.bp +++ b/graphics/composer/2.2/vts/functional/Android.bp @@ -57,5 +57,6 @@ cc_test { "android.hardware.graphics.composer@2.1-command-buffer", "android.hardware.graphics.composer@2.2-command-buffer", ], - test_suites: ["general-tests"], + disable_framework: true, + test_suites: ["general-tests", "vts-core"], } diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp index 6a6f7de6ac..044bd9640e 100644 --- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp @@ -16,14 +16,15 @@ #define LOG_TAG "graphics_composer_hidl_hal_readback_tests@2.2" -#include -#include #include #include #include #include #include #include +#include +#include +#include #include #include #include @@ -50,29 +51,12 @@ using V2_1::Display; using V2_1::vts::TestCommandReader; using vts::Gralloc; -// Test environment for graphics.composer -class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static GraphicsComposerHidlEnvironment* Instance() { - static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment; - return instance; - } - virtual void registerTestServices() override { registerTestService(); } - - private: - GraphicsComposerHidlEnvironment() {} - GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment); -}; - -class GraphicsCompositionTest : public ::testing::VtsHalHidlTargetTestBase { +class GraphicsCompositionTestBase : public ::testing::Test { protected: using PowerMode = V2_1::IComposerClient::PowerMode; - void SetUp() override { - VtsHalHidlTargetTestBase::SetUp(); + void SetUpBase(const std::string& service_name) { ASSERT_NO_FATAL_FAILURE( - mComposer = std::make_unique( - GraphicsComposerHidlEnvironment::Instance()->getServiceName())); + mComposer = std::make_unique(IComposer::getService(service_name))); ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); mComposerCallback = new V2_1::vts::GraphicsComposerCallback; mComposerClient->registerCallback(mComposerCallback); @@ -132,7 +116,6 @@ class GraphicsCompositionTest : public ::testing::VtsHalHidlTargetTestBase { EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount()); EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount()); } - VtsHalHidlTargetTestBase::TearDown(); } void clearCommandReaderState() { @@ -198,7 +181,13 @@ class GraphicsCompositionTest : public ::testing::VtsHalHidlTargetTestBase { } }; -TEST_F(GraphicsCompositionTest, SingleSolidColorLayer) { +class GraphicsCompositionTest : public GraphicsCompositionTestBase, + public testing::WithParamInterface { + public: + void SetUp() override { SetUpBase(GetParam()); } +}; + +TEST_P(GraphicsCompositionTest, SingleSolidColorLayer) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -260,7 +249,7 @@ TEST_F(GraphicsCompositionTest, SingleSolidColorLayer) { } } -TEST_F(GraphicsCompositionTest, SetLayerBuffer) { +TEST_P(GraphicsCompositionTest, SetLayerBuffer) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -332,7 +321,7 @@ TEST_F(GraphicsCompositionTest, SetLayerBuffer) { } } -TEST_F(GraphicsCompositionTest, SetLayerBufferNoEffect) { +TEST_P(GraphicsCompositionTest, SetLayerBufferNoEffect) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -394,7 +383,7 @@ TEST_F(GraphicsCompositionTest, SetLayerBufferNoEffect) { } } -TEST_F(GraphicsCompositionTest, ClientComposition) { +TEST_P(GraphicsCompositionTest, ClientComposition) { ASSERT_NO_FATAL_FAILURE( mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount)); @@ -511,7 +500,7 @@ TEST_F(GraphicsCompositionTest, ClientComposition) { } } -TEST_F(GraphicsCompositionTest, DeviceAndClientComposition) { +TEST_P(GraphicsCompositionTest, DeviceAndClientComposition) { ASSERT_NO_FATAL_FAILURE( mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount)); @@ -637,7 +626,7 @@ TEST_F(GraphicsCompositionTest, DeviceAndClientComposition) { } } -TEST_F(GraphicsCompositionTest, SetLayerDamage) { +TEST_P(GraphicsCompositionTest, SetLayerDamage) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -722,7 +711,7 @@ TEST_F(GraphicsCompositionTest, SetLayerDamage) { } } -TEST_F(GraphicsCompositionTest, SetLayerPlaneAlpha) { +TEST_P(GraphicsCompositionTest, SetLayerPlaneAlpha) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -783,7 +772,7 @@ TEST_F(GraphicsCompositionTest, SetLayerPlaneAlpha) { } } -TEST_F(GraphicsCompositionTest, SetLayerSourceCrop) { +TEST_P(GraphicsCompositionTest, SetLayerSourceCrop) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -854,7 +843,7 @@ TEST_F(GraphicsCompositionTest, SetLayerSourceCrop) { } } -TEST_F(GraphicsCompositionTest, SetLayerZOrder) { +TEST_P(GraphicsCompositionTest, SetLayerZOrder) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -941,18 +930,17 @@ TEST_F(GraphicsCompositionTest, SetLayerZOrder) { } } -class GraphicsBlendModeCompositionTest : public GraphicsCompositionTest, - public ::testing::WithParamInterface { +class GraphicsBlendModeCompositionTest + : public GraphicsCompositionTestBase, + public testing::WithParamInterface> { public: void SetUp() override { - GraphicsCompositionTest::SetUp(); + SetUpBase(std::get<0>(GetParam())); mTestColorModes = {ColorMode::SRGB}; // TODO: add more color mode support mBackgroundColor = BLACK; mTopLayerColor = RED; } - void TearDown() override { GraphicsCompositionTest::TearDown(); } - void setBackgroundColor(IComposerClient::Color color) { mBackgroundColor = color; } void setTopLayerColor(IComposerClient::Color color) { mTopLayerColor = color; } @@ -977,7 +965,7 @@ class GraphicsBlendModeCompositionTest : public GraphicsCompositionTest, ASSERT_NO_FATAL_FAILURE(layer->setBuffer(topLayerPixelColors)); layer->setBlendMode(blendMode); - layer->setAlpha(GetParam()); + layer->setAlpha(std::stof(std::get<1>(GetParam()))); mLayers.push_back(backgroundLayer); mLayers.push_back(layer); @@ -1023,7 +1011,8 @@ class GraphicsBlendModeCompositionTest : public GraphicsCompositionTest, IComposerClient::Color mTopLayerColor; }; -TEST_P(GraphicsBlendModeCompositionTest, None) { +// TODO(b/145557764): Re-enable after the bug is fixed. +TEST_P(GraphicsBlendModeCompositionTest, DISABLED_None) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -1188,9 +1177,6 @@ TEST_P(GraphicsBlendModeCompositionTest, Premultiplied) { } } -INSTANTIATE_TEST_CASE_P(BlendModeTest, GraphicsBlendModeCompositionTest, - ::testing::Values(.2, 1.0)); - class GraphicsTransformCompositionTest : public GraphicsCompositionTest { protected: void SetUp() override { @@ -1229,7 +1215,7 @@ class GraphicsTransformCompositionTest : public GraphicsCompositionTest { int mSideLength; }; -TEST_F(GraphicsTransformCompositionTest, FLIP_H) { +TEST_P(GraphicsTransformCompositionTest, FLIP_H) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -1284,7 +1270,7 @@ TEST_F(GraphicsTransformCompositionTest, FLIP_H) { } } -TEST_F(GraphicsTransformCompositionTest, FLIP_V) { +TEST_P(GraphicsTransformCompositionTest, FLIP_V) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -1339,7 +1325,7 @@ TEST_F(GraphicsTransformCompositionTest, FLIP_V) { } } -TEST_F(GraphicsTransformCompositionTest, ROT_180) { +TEST_P(GraphicsTransformCompositionTest, ROT_180) { for (ColorMode mode : mTestColorModes) { std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---" << std::endl; @@ -1395,6 +1381,23 @@ TEST_F(GraphicsTransformCompositionTest, ROT_180) { } } +INSTANTIATE_TEST_SUITE_P( + PerInstance, GraphicsCompositionTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), + android::hardware::PrintInstanceNameToString); + +INSTANTIATE_TEST_CASE_P( + BlendModeTest, GraphicsBlendModeCompositionTest, + testing::Combine( + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), + testing::Values("0.2", "1.0")), + android::hardware::PrintInstanceTupleNameToString<>); + +INSTANTIATE_TEST_SUITE_P( + PerInstance, GraphicsTransformCompositionTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), + android::hardware::PrintInstanceNameToString); + } // anonymous namespace } // namespace vts } // namespace V2_2 diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp index 51832f9f4c..95a0f69c32 100644 --- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp @@ -16,12 +16,14 @@ #define LOG_TAG "graphics_composer_hidl_hal_test@2.2" -#include #include #include #include #include #include +#include +#include +#include #include namespace android { @@ -41,29 +43,11 @@ using common::V1_1::PixelFormat; using common::V1_1::RenderIntent; using mapper::V2_0::IMapper; -// Test environment for graphics.composer -class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static GraphicsComposerHidlEnvironment* Instance() { - static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { registerTestService(); } - - private: - GraphicsComposerHidlEnvironment() {} - - GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment); -}; - -class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { - protected: +class GraphicsComposerHidlTest : public ::testing::TestWithParam { + protected: void SetUp() override { ASSERT_NO_FATAL_FAILURE( - mComposer = std::make_unique( - GraphicsComposerHidlEnvironment::Instance()->getServiceName())); + mComposer = std::make_unique(IComposer::getService(GetParam()))); ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); mComposerCallback = new V2_1::vts::GraphicsComposerCallback; @@ -188,7 +172,7 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { /** * Test IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -239,7 +223,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) { /** * Test IComposerClient::getPerFrameMetadataKeys. */ -TEST_F(GraphicsComposerHidlTest, GetPerFrameMetadataKeys) { +TEST_P(GraphicsComposerHidlTest, GetPerFrameMetadataKeys) { std::vector keys; Error error = Error::NONE; mComposerClient->getRaw()->getPerFrameMetadataKeys( @@ -261,7 +245,7 @@ TEST_F(GraphicsComposerHidlTest, GetPerFrameMetadataKeys) { * * Test that virtual displays can be created and has the correct display type. */ -TEST_F(GraphicsComposerHidlTest, CreateVirtualDisplay_2_2) { +TEST_P(GraphicsComposerHidlTest, CreateVirtualDisplay_2_2) { if (mComposerClient->getMaxVirtualDisplayCount() == 0) { GTEST_SUCCEED() << "no virtual display support"; return; @@ -286,7 +270,7 @@ TEST_F(GraphicsComposerHidlTest, CreateVirtualDisplay_2_2) { * Test that IComposerClient::getClientTargetSupport returns true for the * required client targets. */ -TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_2) { +TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_2) { std::vector configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay); for (auto config : configs) { int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, @@ -310,7 +294,7 @@ TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_2) { * Error::BAD_DISPLAY when passed in an invalid display handle */ -TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_2BadDisplay) { +TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_2BadDisplay) { std::vector configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay); for (auto config : configs) { int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, @@ -332,7 +316,7 @@ TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_2BadDisplay) { /** * Test IComposerClient::setPowerMode_2_2. */ -TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2) { +TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2) { std::vector modes; modes.push_back(IComposerClient::PowerMode::OFF); modes.push_back(IComposerClient::PowerMode::ON_SUSPEND); @@ -349,7 +333,7 @@ TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2) { * Test that IComposerClient::setPowerMode_2_2 succeeds for different varations * of PowerMode */ -TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2Variations) { +TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2Variations) { std::vector modes; modes.push_back(IComposerClient::PowerMode::OFF); @@ -404,7 +388,7 @@ TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2Variations) { * Tests that IComposerClient::setPowerMode_2_2 returns BAD_DISPLAY when passed an * invalid display handle */ -TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2BadDisplay) { +TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2BadDisplay) { Error error = mComposerClient->getRaw()->setPowerMode_2_2(mInvalidDisplayId, IComposerClient::PowerMode::ON); ASSERT_EQ(Error::BAD_DISPLAY, error); @@ -416,7 +400,7 @@ TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2BadDisplay) { * Test that IComposerClient::setPowerMode_2_2 returns BAD_PARAMETER when passed * an invalid PowerMode */ -TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2BadParameter) { +TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2BadParameter) { Error error = mComposerClient->getRaw()->setPowerMode_2_2( mPrimaryDisplay, static_cast(-1)); ASSERT_EQ(Error::BAD_PARAMETER, error); @@ -428,7 +412,7 @@ TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2BadParameter) { * Test that IComposerClient::setPowerMode_2_2 returns UNSUPPORTED when passed * DOZE or DOZE_SUPPORT on a device that does not support these modes */ -TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2Unsupported) { +TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2Unsupported) { if (!mComposerClient->getDozeSupport(mPrimaryDisplay)) { Error error = mComposerClient->getRaw()->setPowerMode_2_2(mPrimaryDisplay, IComposerClient::PowerMode::DOZE); @@ -445,7 +429,7 @@ TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2Unsupported) { * * Test IComposerClient::setReadbackBuffer */ -TEST_F(GraphicsComposerHidlTest, SetReadbackBuffer) { +TEST_P(GraphicsComposerHidlTest, SetReadbackBuffer) { if (!mHasReadbackBuffer) { return; } @@ -469,7 +453,7 @@ TEST_F(GraphicsComposerHidlTest, SetReadbackBuffer) { * Test that IComposerClient::setReadbackBuffer returns an Error::BAD_DISPLAY * when passed an invalid display handle */ -TEST_F(GraphicsComposerHidlTest, SetReadbackBufferBadDisplay) { +TEST_P(GraphicsComposerHidlTest, SetReadbackBufferBadDisplay) { if (!mHasReadbackBuffer) { return; } @@ -493,7 +477,7 @@ TEST_F(GraphicsComposerHidlTest, SetReadbackBufferBadDisplay) { * Test that IComposerClient::setReadbackBuffer returns Error::BAD_PARAMETER * when passed an invalid buffer handle */ -TEST_F(GraphicsComposerHidlTest, SetReadbackBufferBadParameter) { +TEST_P(GraphicsComposerHidlTest, SetReadbackBufferBadParameter) { if (!mHasReadbackBuffer) { return; } @@ -502,7 +486,7 @@ TEST_F(GraphicsComposerHidlTest, SetReadbackBufferBadParameter) { ASSERT_EQ(Error::BAD_PARAMETER, error); } -TEST_F(GraphicsComposerHidlTest, GetReadbackBufferFenceInactive) { +TEST_P(GraphicsComposerHidlTest, GetReadbackBufferFenceInactive) { if (!mHasReadbackBuffer) { return; } @@ -516,7 +500,7 @@ TEST_F(GraphicsComposerHidlTest, GetReadbackBufferFenceInactive) { /** * Test IComposerClient::Command::SET_LAYER_FLOAT_COLOR. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_FLOAT_COLOR) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_FLOAT_COLOR) { V2_1::Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -554,7 +538,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_FLOAT_COLOR) { /** * Test IComposerClient::getDataspaceSaturationMatrix. */ -TEST_F(GraphicsComposerHidlTest, GetDataspaceSaturationMatrix) { +TEST_P(GraphicsComposerHidlTest, GetDataspaceSaturationMatrix) { auto matrix = mComposerClient->getDataspaceSaturationMatrix(Dataspace::SRGB_LINEAR); // the last row is known ASSERT_EQ(0.0f, matrix[12]); @@ -570,7 +554,7 @@ TEST_F(GraphicsComposerHidlTest, GetDataspaceSaturationMatrix) { * Error::BAD_PARAMETER when passed a dataspace other than * Dataspace::SRGB_LINEAR */ -TEST_F(GraphicsComposerHidlTest, GetDataspaceSaturationMatrixBadParameter) { +TEST_P(GraphicsComposerHidlTest, GetDataspaceSaturationMatrixBadParameter) { mComposerClient->getRaw()->getDataspaceSaturationMatrix( Dataspace::UNKNOWN, [&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_PARAMETER, tmpError); }); @@ -579,7 +563,7 @@ TEST_F(GraphicsComposerHidlTest, GetDataspaceSaturationMatrixBadParameter) { /** * Test IComposerClient::getColorMode_2_2. */ -TEST_F(GraphicsComposerHidlTest, GetColorMode_2_2) { +TEST_P(GraphicsComposerHidlTest, GetColorMode_2_2) { std::vector modes = mComposerClient->getColorModes(mPrimaryDisplay); auto nativeMode = std::find(modes.cbegin(), modes.cend(), ColorMode::NATIVE); @@ -592,7 +576,7 @@ TEST_F(GraphicsComposerHidlTest, GetColorMode_2_2) { * Test that IComposerClient::getColorMode returns Error::BAD_DISPLAY when * passed an invalid display handle */ -TEST_F(GraphicsComposerHidlTest, GetColorMode_2_2BadDisplay) { +TEST_P(GraphicsComposerHidlTest, GetColorMode_2_2BadDisplay) { mComposerClient->getRaw()->getColorModes_2_2( mInvalidDisplayId, [&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_DISPLAY, tmpError); }); @@ -601,7 +585,7 @@ TEST_F(GraphicsComposerHidlTest, GetColorMode_2_2BadDisplay) { /** * Test IComposerClient::getRenderIntents. */ -TEST_F(GraphicsComposerHidlTest, GetRenderIntents) { +TEST_P(GraphicsComposerHidlTest, GetRenderIntents) { std::vector modes = mComposerClient->getColorModes(mPrimaryDisplay); for (auto mode : modes) { std::vector intents = @@ -631,7 +615,7 @@ TEST_F(GraphicsComposerHidlTest, GetRenderIntents) { * Test that IComposerClient::getRenderIntent returns Error::BAD_DISPLAY when * passed an invalid display handle */ -TEST_F(GraphicsComposerHidlTest, GetRenderIntentsBadDisplay) { +TEST_P(GraphicsComposerHidlTest, GetRenderIntentsBadDisplay) { std::vector modes = mComposerClient->getColorModes(mPrimaryDisplay); for (auto mode : modes) { mComposerClient->getRaw()->getRenderIntents( @@ -646,7 +630,7 @@ TEST_F(GraphicsComposerHidlTest, GetRenderIntentsBadDisplay) { * Test that IComposerClient::getRenderIntents returns Error::BAD_PARAMETER when * pased either an invalid Color mode or an invalid Render Intent */ -TEST_F(GraphicsComposerHidlTest, GetRenderIntentsBadParameter) { +TEST_P(GraphicsComposerHidlTest, GetRenderIntentsBadParameter) { mComposerClient->getRaw()->getRenderIntents( mPrimaryDisplay, static_cast(-1), [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_PARAMETER, tmpError); }); @@ -655,7 +639,7 @@ TEST_F(GraphicsComposerHidlTest, GetRenderIntentsBadParameter) { /** * Test IComposerClient::setColorMode_2_2. */ -TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2) { +TEST_P(GraphicsComposerHidlTest, SetColorMode_2_2) { std::vector modes = mComposerClient->getColorModes(mPrimaryDisplay); for (auto mode : modes) { std::vector intents = @@ -674,7 +658,7 @@ TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2) { * Test that IComposerClient::setColorMode_2_2 returns an Error::BAD_DISPLAY * when passed an invalid display handle */ -TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2BadDisplay) { +TEST_P(GraphicsComposerHidlTest, SetColorMode_2_2BadDisplay) { Error error = mComposerClient->getRaw()->setColorMode_2_2(mInvalidDisplayId, ColorMode::NATIVE, RenderIntent::COLORIMETRIC); @@ -687,7 +671,7 @@ TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2BadDisplay) { * Test that IComposerClient::setColorMode_2_2 returns Error::BAD_PARAMETER when * passed an invalid Color mode or an invalid render intent */ -TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2BadParameter) { +TEST_P(GraphicsComposerHidlTest, SetColorMode_2_2BadParameter) { Error colorModeError = mComposerClient->getRaw()->setColorMode_2_2( mPrimaryDisplay, static_cast(-1), RenderIntent::COLORIMETRIC); EXPECT_EQ(Error::BAD_PARAMETER, colorModeError); @@ -697,6 +681,16 @@ TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2BadParameter) { EXPECT_EQ(Error::BAD_PARAMETER, renderIntentError); } +INSTANTIATE_TEST_SUITE_P( + PerInstance, GraphicsComposerHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), + android::hardware::PrintInstanceNameToString); + +INSTANTIATE_TEST_SUITE_P( + PerInstance, GraphicsComposerHidlCommandTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), + android::hardware::PrintInstanceNameToString); + } // namespace } // namespace vts } // namespace V2_2 @@ -704,12 +698,3 @@ TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2BadParameter) { } // namespace graphics } // namespace hardware } // namespace android - -int main(int argc, char** argv) { - using android::hardware::graphics::composer::V2_2::vts::GraphicsComposerHidlEnvironment; - ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - return status; -} From ae5d68fd11bdcb3e41fee87b087f02391833a351 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Thu, 31 Oct 2019 12:47:18 -0700 Subject: [PATCH 0296/1022] Convert VtsHalGraphicsComposerV2_3TargetTest to be parameterized test Bug: 142397658 Test: atest VtsHalGraphicsComposerV2_3TargetTest Change-Id: Id9ace8eaac026df03f26ec22fbef078f9ff53728 --- .../include/composer-vts/2.3/ComposerVts.h | 4 +- .../composer/2.3/vts/functional/Android.bp | 2 + .../VtsHalGraphicsComposerV2_3TargetTest.cpp | 93 ++++++++----------- 3 files changed, 42 insertions(+), 57 deletions(-) diff --git a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h index 0d4e5b8d5b..e5ac842262 100644 --- a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h +++ b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h @@ -49,12 +49,10 @@ class Composer : public V2_2::vts::Composer { public: Composer(); explicit Composer(const std::string& name); + explicit Composer(const sp& composer); std::unique_ptr createClient(); - protected: - explicit Composer(const sp& composer); - private: const sp mComposer; }; diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp index b729062637..fa4823efbd 100644 --- a/graphics/composer/2.3/vts/functional/Android.bp +++ b/graphics/composer/2.3/vts/functional/Android.bp @@ -49,4 +49,6 @@ cc_test { "android.hardware.graphics.composer@2.2-command-buffer", "android.hardware.graphics.composer@2.3-command-buffer", ], + disable_framework: true, + test_suites: ["general-tests", "vts-core"], } diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp index dafe58786b..94766af480 100644 --- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp +++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp @@ -18,13 +18,15 @@ #include -#include #include #include #include #include #include #include +#include +#include +#include #include namespace android { @@ -43,29 +45,11 @@ using common::V1_2::PixelFormat; using mapper::V2_0::IMapper; using V2_2::vts::Gralloc; -// Test environment for graphics.composer -class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static GraphicsComposerHidlEnvironment* Instance() { - static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { registerTestService(); } - - private: - GraphicsComposerHidlEnvironment() {} - - GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment); -}; - -class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { - protected: +class GraphicsComposerHidlTest : public ::testing::TestWithParam { + protected: void SetUp() override { ASSERT_NO_FATAL_FAILURE( - mComposer = std::make_unique( - GraphicsComposerHidlEnvironment::Instance()->getServiceName())); + mComposer = std::make_unique(IComposer::getService(GetParam()))); ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); mComposerCallback = new V2_1::vts::GraphicsComposerCallback; @@ -175,7 +159,7 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { * * TODO: Check that ports are unique for multiple displays. */ -TEST_F(GraphicsComposerHidlTest, GetDisplayIdentificationData) { +TEST_P(GraphicsComposerHidlTest, GetDisplayIdentificationData) { uint8_t port0; std::vector data0; if (mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &port0, &data0)) { @@ -193,7 +177,7 @@ TEST_F(GraphicsComposerHidlTest, GetDisplayIdentificationData) { /** * Test IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA. */ -TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) { +TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -244,7 +228,7 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) { /** * Test IComposerClient::getHdrCapabilities_2_3 */ -TEST_F(GraphicsComposerHidlTest, GetHdrCapabilities_2_3) { +TEST_P(GraphicsComposerHidlTest, GetHdrCapabilities_2_3) { float maxLuminance; float maxAverageLuminance; float minLuminance; @@ -256,7 +240,7 @@ TEST_F(GraphicsComposerHidlTest, GetHdrCapabilities_2_3) { /** * Test IComposerClient::getPerFrameMetadataKeys_2_3 */ -TEST_F(GraphicsComposerHidlTest, GetPerFrameMetadataKeys_2_3) { +TEST_P(GraphicsComposerHidlTest, GetPerFrameMetadataKeys_2_3) { std::vector keys; mComposerClient->getRaw()->getPerFrameMetadataKeys_2_3( mPrimaryDisplay, [&](const auto tmpError, const auto outKeys) { @@ -270,7 +254,7 @@ TEST_F(GraphicsComposerHidlTest, GetPerFrameMetadataKeys_2_3) { /** * TestIComposerClient::getReadbackBufferAttributes_2_3 */ -TEST_F(GraphicsComposerHidlTest, GetReadbackBufferAttributes_2_3) { +TEST_P(GraphicsComposerHidlTest, GetReadbackBufferAttributes_2_3) { Dataspace dataspace; PixelFormat pixelFormat; @@ -288,7 +272,7 @@ TEST_F(GraphicsComposerHidlTest, GetReadbackBufferAttributes_2_3) { /** * Test IComposerClient::getClientTargetSupport_2_3 */ -TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_3) { +TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_3) { std::vector configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay); for (auto config : configs) { int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, @@ -311,7 +295,7 @@ TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_3) { * Error::BAD_DISPLAY when passed in an invalid display handle */ -TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_3BadDisplay) { +TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_3BadDisplay) { std::vector configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay); for (auto config : configs) { int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, @@ -333,7 +317,7 @@ TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_3BadDisplay) { /** * Test IComposerClient::getRenderIntents_2_3 */ -TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3) { +TEST_P(GraphicsComposerHidlTest, GetRenderIntents_2_3) { std::vector modes = mComposerClient->getColorModes_2_3(mPrimaryDisplay); for (auto mode : modes) { std::vector intents = @@ -363,7 +347,7 @@ TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3) { * Test that IComposerClient::getRenderIntents_2_3 returns Error::BAD_DISPLAY when * passed an invalid display handle */ -TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3BadDisplay) { +TEST_P(GraphicsComposerHidlTest, GetRenderIntents_2_3BadDisplay) { std::vector modes = mComposerClient->getColorModes_2_3(mPrimaryDisplay); for (auto mode : modes) { mComposerClient->getRaw()->getRenderIntents_2_3( @@ -378,7 +362,7 @@ TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3BadDisplay) { * Test that IComposerClient::getRenderIntents_2_3 returns Error::BAD_PARAMETER when * pased either an invalid Color mode or an invalid Render Intent */ -TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3BadParameter) { +TEST_P(GraphicsComposerHidlTest, GetRenderIntents_2_3BadParameter) { mComposerClient->getRaw()->getRenderIntents_2_3( mPrimaryDisplay, static_cast(-1), [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_PARAMETER, tmpError); }); @@ -387,7 +371,7 @@ TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3BadParameter) { /** * IComposerClient::getColorModes_2_3 */ -TEST_F(GraphicsComposerHidlTest, GetColorModes_2_3) { +TEST_P(GraphicsComposerHidlTest, GetColorModes_2_3) { std::vector colorModes = mComposerClient->getColorModes_2_3(mPrimaryDisplay); auto native = std::find(colorModes.cbegin(), colorModes.cend(), ColorMode::NATIVE); @@ -400,7 +384,7 @@ TEST_F(GraphicsComposerHidlTest, GetColorModes_2_3) { * Test that IComposerClient::getColorModes_2_3 returns Error::BAD_DISPLAY when * passed an invalid display handle */ -TEST_F(GraphicsComposerHidlTest, GetColorMode_2_3BadDisplay) { +TEST_P(GraphicsComposerHidlTest, GetColorMode_2_3BadDisplay) { mComposerClient->getRaw()->getColorModes_2_3( mInvalidDisplayId, [&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_DISPLAY, tmpError); }); @@ -409,7 +393,7 @@ TEST_F(GraphicsComposerHidlTest, GetColorMode_2_3BadDisplay) { /** * IComposerClient::setColorMode_2_3 */ -TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3) { +TEST_P(GraphicsComposerHidlTest, SetColorMode_2_3) { std::vector colorModes = mComposerClient->getColorModes_2_3(mPrimaryDisplay); for (auto mode : colorModes) { std::vector intents = @@ -430,7 +414,7 @@ TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3) { * Test that IComposerClient::setColorMode_2_3 returns an Error::BAD_DISPLAY * when passed an invalid display handle */ -TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3BadDisplay) { +TEST_P(GraphicsComposerHidlTest, SetColorMode_2_3BadDisplay) { Error error = mComposerClient->getRaw()->setColorMode_2_3(mInvalidDisplayId, ColorMode::NATIVE, RenderIntent::COLORIMETRIC); @@ -443,7 +427,7 @@ TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3BadDisplay) { * Test that IComposerClient::setColorMode_2_3 returns Error::BAD_PARAMETER when * passed an invalid Color mode or an invalid render intent */ -TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3BadParameter) { +TEST_P(GraphicsComposerHidlTest, SetColorMode_2_3BadParameter) { Error colorModeError = mComposerClient->getRaw()->setColorMode_2_3( mPrimaryDisplay, static_cast(-1), RenderIntent::COLORIMETRIC); EXPECT_EQ(Error::BAD_PARAMETER, colorModeError); @@ -458,7 +442,7 @@ TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3BadParameter) { * TODO Add color to the layer, use matrix to keep only red component, * and check. */ -TEST_F(GraphicsComposerHidlTest, SetLayerColorTransform) { +TEST_P(GraphicsComposerHidlTest, SetLayerColorTransform) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -485,7 +469,7 @@ TEST_F(GraphicsComposerHidlTest, SetLayerColorTransform) { } } -TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSamplingAttributes) { +TEST_P(GraphicsComposerHidlTest, GetDisplayedContentSamplingAttributes) { int constexpr invalid = -1; auto format = static_cast(invalid); auto dataspace = static_cast(invalid); @@ -505,7 +489,7 @@ TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSamplingAttributes) { static_cast>(invalid)); }; -TEST_F(GraphicsComposerHidlTest, SetDisplayedContentSamplingEnabled) { +TEST_P(GraphicsComposerHidlTest, SetDisplayedContentSamplingEnabled) { auto const maxFrames = 10; auto const enableAllComponents = 0; auto error = mComposerClient->setDisplayedContentSamplingEnabled( @@ -523,7 +507,7 @@ TEST_F(GraphicsComposerHidlTest, SetDisplayedContentSamplingEnabled) { EXPECT_EQ(error, Error::NONE); } -TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSample) { +TEST_P(GraphicsComposerHidlTest, GetDisplayedContentSample) { int constexpr invalid = -1; auto format = static_cast(invalid); auto dataspace = static_cast(invalid); @@ -558,7 +542,7 @@ TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSample) { * getDisplayCapabilities is required in composer 2.3 * Test some constraints. */ -TEST_F(GraphicsComposerHidlTest, getDisplayCapabilitiesBasic) { +TEST_P(GraphicsComposerHidlTest, getDisplayCapabilitiesBasic) { std::vector capabilities; const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities); ASSERT_EQ(Error::NONE, error); @@ -572,13 +556,13 @@ TEST_F(GraphicsComposerHidlTest, getDisplayCapabilitiesBasic) { EXPECT_EQ(mComposerClient->getDisplayBrightnessSupport(mPrimaryDisplay), hasBrightnessSupport); } -TEST_F(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) { +TEST_P(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) { std::vector capabilities; const auto error = mComposerClient->getDisplayCapabilities(mInvalidDisplayId, &capabilities); EXPECT_EQ(Error::BAD_DISPLAY, error); } -TEST_F(GraphicsComposerHidlTest, SetLayerPerFrameMetadataBlobs) { +TEST_P(GraphicsComposerHidlTest, SetLayerPerFrameMetadataBlobs) { Layer layer; ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); @@ -604,7 +588,7 @@ TEST_F(GraphicsComposerHidlTest, SetLayerPerFrameMetadataBlobs) { /* * Test that if brightness operations are supported, setDisplayBrightness works as expected. */ -TEST_F(GraphicsComposerHidlTest, setDisplayBrightness) { +TEST_P(GraphicsComposerHidlTest, setDisplayBrightness) { std::vector capabilities; const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities); ASSERT_EQ(Error::NONE, error); @@ -627,6 +611,16 @@ TEST_F(GraphicsComposerHidlTest, setDisplayBrightness) { EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, -2.0f), Error::BAD_PARAMETER); } +INSTANTIATE_TEST_SUITE_P( + PerInstance, GraphicsComposerHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), + android::hardware::PrintInstanceNameToString); + +INSTANTIATE_TEST_SUITE_P( + PerInstance, GraphicsComposerHidlCommandTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), + android::hardware::PrintInstanceNameToString); + } // namespace } // namespace vts } // namespace V2_3 @@ -634,12 +628,3 @@ TEST_F(GraphicsComposerHidlTest, setDisplayBrightness) { } // namespace graphics } // namespace hardware } // namespace android - -int main(int argc, char** argv) { - using android::hardware::graphics::composer::V2_3::vts::GraphicsComposerHidlEnvironment; - ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - return status; -} From c06b5366620e5ecd6457449d019f4e5760f0886e Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Fri, 25 Oct 2019 14:14:35 -0700 Subject: [PATCH 0297/1022] Add GNSS HAL 2.1 Bug: 136136192 Bug: 141758837 Test: atest VtsHalGnssV2_1TargetTest Change-Id: I8e6d52695c8ab0aeacacb0107a6c0c8271983ed3 --- .../compatibility_matrix.current.xml | 2 +- current.txt | 4 + gnss/1.1/default/Android.bp | 2 + gnss/1.1/default/Gnss.cpp | 18 +- gnss/2.0/default/Android.bp | 5 +- gnss/2.0/default/Gnss.cpp | 21 +- gnss/2.0/default/GnssMeasurement.cpp | 58 +--- gnss/2.0/default/GnssMeasurement.h | 1 - gnss/2.0/vts/functional/Android.bp | 1 + gnss/2.1/Android.bp | 24 ++ gnss/2.1/IGnss.hal | 53 +++ gnss/2.1/IGnssCallback.hal | 58 ++++ gnss/2.1/IGnssMeasurement.hal | 51 +++ gnss/2.1/IGnssMeasurementCallback.hal | 77 +++++ gnss/2.1/default/Android.bp | 42 +++ gnss/2.1/default/Gnss.cpp | 301 ++++++++++++++++++ gnss/2.1/default/Gnss.h | 106 ++++++ gnss/2.1/default/GnssMeasurement.cpp | 123 +++++++ gnss/2.1/default/GnssMeasurement.h | 78 +++++ gnss/2.1/default/OWNERS | 4 + .../android.hardware.gnss@2.1-service.rc | 4 + .../android.hardware.gnss@2.1-service.xml | 12 + gnss/2.1/default/service.cpp | 41 +++ gnss/2.1/vts/OWNERS | 4 + gnss/2.1/vts/functional/Android.bp | 35 ++ .../functional/VtsHalGnssV2_1TargetTest.cpp | 29 ++ gnss/2.1/vts/functional/gnss_hal_test.cpp | 217 +++++++++++++ gnss/2.1/vts/functional/gnss_hal_test.h | 191 +++++++++++ .../vts/functional/gnss_hal_test_cases.cpp | 128 ++++++++ gnss/common/utils/default/Android.bp | 4 + gnss/common/utils/default/Utils.cpp | 200 ++++++++++-- gnss/common/utils/default/include/Utils.h | 26 +- 32 files changed, 1805 insertions(+), 115 deletions(-) create mode 100644 gnss/2.1/Android.bp create mode 100644 gnss/2.1/IGnss.hal create mode 100644 gnss/2.1/IGnssCallback.hal create mode 100644 gnss/2.1/IGnssMeasurement.hal create mode 100644 gnss/2.1/IGnssMeasurementCallback.hal create mode 100644 gnss/2.1/default/Android.bp create mode 100644 gnss/2.1/default/Gnss.cpp create mode 100644 gnss/2.1/default/Gnss.h create mode 100644 gnss/2.1/default/GnssMeasurement.cpp create mode 100644 gnss/2.1/default/GnssMeasurement.h create mode 100644 gnss/2.1/default/OWNERS create mode 100644 gnss/2.1/default/android.hardware.gnss@2.1-service.rc create mode 100644 gnss/2.1/default/android.hardware.gnss@2.1-service.xml create mode 100644 gnss/2.1/default/service.cpp create mode 100644 gnss/2.1/vts/OWNERS create mode 100644 gnss/2.1/vts/functional/Android.bp create mode 100644 gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp create mode 100644 gnss/2.1/vts/functional/gnss_hal_test.cpp create mode 100644 gnss/2.1/vts/functional/gnss_hal_test.h create mode 100644 gnss/2.1/vts/functional/gnss_hal_test_cases.cpp diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index cf27a3f646..aecc4e0407 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -189,7 +189,7 @@ - test DeviceManifestTest#GnssHalVersionCompatibility. --> 1.1 - 2.0 + 2.0-1 IGnss default diff --git a/current.txt b/current.txt index 5847f71162..940575e034 100644 --- a/current.txt +++ b/current.txt @@ -595,6 +595,10 @@ f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardwar 4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types 66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory 994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory +1bd8028b974bf1d65cfa102196a2b008afc5d42fe73fed2cb94fa7533d07f581 android.hardware.gnss@2.1::IGnss +ba62e1e8993bfb9f27fa04816fa0f2241ae2d01edfa3d0c04182e2e5de80045c android.hardware.gnss@2.1::IGnssCallback +5a125c49ca83629e22afc8c39e865509343bfa2c38f0baea9a186bbac103492d android.hardware.gnss@2.1::IGnssMeasurement +0bfb291708dd4a7c6ec6b9883e2b8592357edde8d7e962ef83918e4a2154ce69 android.hardware.gnss@2.1::IGnssMeasurementCallback ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types diff --git a/gnss/1.1/default/Android.bp b/gnss/1.1/default/Android.bp index 95bd7f33cb..9c498d58a0 100644 --- a/gnss/1.1/default/Android.bp +++ b/gnss/1.1/default/Android.bp @@ -14,6 +14,8 @@ cc_binary { "libhidlbase", "libutils", "liblog", + "android.hardware.gnss@2.1", + "android.hardware.gnss@2.0", "android.hardware.gnss@1.1", "android.hardware.gnss@1.0", ], diff --git a/gnss/1.1/default/Gnss.cpp b/gnss/1.1/default/Gnss.cpp index 4abe707d4a..5043649b2d 100644 --- a/gnss/1.1/default/Gnss.cpp +++ b/gnss/1.1/default/Gnss.cpp @@ -44,7 +44,7 @@ Return Gnss::start() { auto svStatus = this->getMockSvStatus(); this->reportSvStatus(svStatus); - auto location = Utils::getMockLocation(); + auto location = Utils::getMockLocationV1_0(); this->reportLocation(location); std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs)); @@ -197,14 +197,14 @@ Return Gnss::injectBestLocation(const GnssLocation&) { Return Gnss::getMockSvStatus() const { std::unique_lock lock(mGnssConfiguration->getMutex()); GnssSvInfo mockGnssSvInfoList[] = { - Utils::getSvInfo(3, GnssConstellationType::GPS, 32.5, 59.1, 166.5), - Utils::getSvInfo(5, GnssConstellationType::GPS, 27.0, 29.0, 56.5), - Utils::getSvInfo(17, GnssConstellationType::GPS, 30.5, 71.0, 77.0), - Utils::getSvInfo(26, GnssConstellationType::GPS, 24.1, 28.0, 253.0), - Utils::getSvInfo(5, GnssConstellationType::GLONASS, 20.5, 11.5, 116.0), - Utils::getSvInfo(17, GnssConstellationType::GLONASS, 21.5, 28.5, 186.0), - Utils::getSvInfo(18, GnssConstellationType::GLONASS, 28.3, 38.8, 69.0), - Utils::getSvInfo(10, GnssConstellationType::GLONASS, 25.0, 66.0, 247.0)}; + Utils::getMockSvInfoV1_0(3, GnssConstellationType::GPS, 32.5, 59.1, 166.5), + Utils::getMockSvInfoV1_0(5, GnssConstellationType::GPS, 27.0, 29.0, 56.5), + Utils::getMockSvInfoV1_0(17, GnssConstellationType::GPS, 30.5, 71.0, 77.0), + Utils::getMockSvInfoV1_0(26, GnssConstellationType::GPS, 24.1, 28.0, 253.0), + Utils::getMockSvInfoV1_0(5, GnssConstellationType::GLONASS, 20.5, 11.5, 116.0), + Utils::getMockSvInfoV1_0(17, GnssConstellationType::GLONASS, 21.5, 28.5, 186.0), + Utils::getMockSvInfoV1_0(18, GnssConstellationType::GLONASS, 28.3, 38.8, 69.0), + Utils::getMockSvInfoV1_0(10, GnssConstellationType::GLONASS, 25.0, 66.0, 247.0)}; GnssSvStatus svStatus = {.numSvs = sizeof(mockGnssSvInfoList) / sizeof(GnssSvInfo)}; for (uint32_t i = 0; i < svStatus.numSvs; i++) { diff --git a/gnss/2.0/default/Android.bp b/gnss/2.0/default/Android.bp index 3ba89da6aa..37de55dfe3 100644 --- a/gnss/2.0/default/Android.bp +++ b/gnss/2.0/default/Android.bp @@ -25,7 +25,7 @@ cc_binary { "AGnss.cpp", "AGnssRil.cpp", "Gnss.cpp", - "GnssBatching.cpp", + "GnssBatching.cpp", "GnssMeasurement.cpp", "GnssMeasurementCorrections.cpp", "GnssVisibilityControl.cpp", @@ -35,9 +35,10 @@ cc_binary { "libhidlbase", "libutils", "liblog", - "android.hardware.gnss@2.0", "android.hardware.gnss.measurement_corrections@1.0", "android.hardware.gnss.visibility_control@1.0", + "android.hardware.gnss@2.1", + "android.hardware.gnss@2.0", "android.hardware.gnss@1.0", "android.hardware.gnss@1.1", ], diff --git a/gnss/2.0/default/Gnss.cpp b/gnss/2.0/default/Gnss.cpp index 3d64fc30cc..09f2fc0ef2 100644 --- a/gnss/2.0/default/Gnss.cpp +++ b/gnss/2.0/default/Gnss.cpp @@ -19,7 +19,6 @@ #include "Gnss.h" #include -#include #include "AGnss.h" #include "AGnssRil.h" @@ -47,24 +46,6 @@ using GnssSvFlags = IGnssCallback::GnssSvFlags; sp Gnss::sGnssCallback_2_0 = nullptr; sp Gnss::sGnssCallback_1_1 = nullptr; -namespace { - -V2_0::GnssLocation getMockLocationV2_0() { - const ElapsedRealtime timestamp = { - .flags = ElapsedRealtimeFlags::HAS_TIMESTAMP_NS | - ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS, - .timestampNs = static_cast(::android::elapsedRealtimeNano()), - // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks. - // In an actual implementation provide an estimate of the synchronization uncertainty - // or don't set the field. - .timeUncertaintyNs = 1000000}; - - V2_0::GnssLocation location = {.v1_0 = Utils::getMockLocation(), .elapsedRealtime = timestamp}; - return location; -} - -} // namespace - Gnss::Gnss() : mMinIntervalMs(1000) {} Gnss::~Gnss() { @@ -86,7 +67,7 @@ Return Gnss::start() { mIsActive = true; mThread = std::thread([this]() { while (mIsActive == true) { - const auto location = getMockLocationV2_0(); + const auto location = Utils::getMockLocationV2_0(); this->reportLocation(location); std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs)); diff --git a/gnss/2.0/default/GnssMeasurement.cpp b/gnss/2.0/default/GnssMeasurement.cpp index 1f95ff95dc..d778d508cd 100644 --- a/gnss/2.0/default/GnssMeasurement.cpp +++ b/gnss/2.0/default/GnssMeasurement.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "GnssMeasurement" #include "GnssMeasurement.h" +#include "Utils.h" #include #include @@ -29,6 +30,7 @@ namespace implementation { using GnssConstellationType = V2_0::GnssConstellationType; using GnssMeasurementFlags = V1_0::IGnssMeasurementCallback::GnssMeasurementFlags; using GnssMeasurementState = V2_0::IGnssMeasurementCallback::GnssMeasurementState; +using Utils = common::Utils; sp GnssMeasurement::sCallback = nullptr; @@ -81,7 +83,7 @@ void GnssMeasurement::start() { mIsActive = true; mThread = std::thread([this]() { while (mIsActive == true) { - auto measurement = this->getMockMeasurement(); + auto measurement = Utils::getMockMeasurementV2_0(); this->reportMeasurement(measurement); std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis)); @@ -97,60 +99,6 @@ void GnssMeasurement::stop() { } } -GnssData GnssMeasurement::getMockMeasurement() { - V1_0::IGnssMeasurementCallback::GnssMeasurement measurement_1_0 = { - .flags = (uint32_t)GnssMeasurementFlags::HAS_CARRIER_FREQUENCY, - .svid = (int16_t)6, - .constellation = V1_0::GnssConstellationType::UNKNOWN, - .timeOffsetNs = 0.0, - .receivedSvTimeInNs = 8195997131077, - .receivedSvTimeUncertaintyInNs = 15, - .cN0DbHz = 30.0, - .pseudorangeRateMps = -484.13739013671875, - .pseudorangeRateUncertaintyMps = 1.0379999876022339, - .accumulatedDeltaRangeState = (uint32_t)V1_0::IGnssMeasurementCallback:: - GnssAccumulatedDeltaRangeState::ADR_STATE_UNKNOWN, - .accumulatedDeltaRangeM = 0.0, - .accumulatedDeltaRangeUncertaintyM = 0.0, - .carrierFrequencyHz = 1.59975e+09, - .multipathIndicator = - V1_0::IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_UNKNOWN}; - V1_1::IGnssMeasurementCallback::GnssMeasurement measurement_1_1 = {.v1_0 = measurement_1_0}; - V2_0::IGnssMeasurementCallback::GnssMeasurement measurement_2_0 = { - .v1_1 = measurement_1_1, - .codeType = "C", - .state = GnssMeasurementState::STATE_CODE_LOCK | GnssMeasurementState::STATE_BIT_SYNC | - GnssMeasurementState::STATE_SUBFRAME_SYNC | - GnssMeasurementState::STATE_TOW_DECODED | - GnssMeasurementState::STATE_GLO_STRING_SYNC | - GnssMeasurementState::STATE_GLO_TOD_DECODED, - .constellation = GnssConstellationType::GLONASS, - }; - - hidl_vec measurements(1); - measurements[0] = measurement_2_0; - V1_0::IGnssMeasurementCallback::GnssClock clock = {.timeNs = 2713545000000, - .fullBiasNs = -1226701900521857520, - .biasNs = 0.59689998626708984, - .biasUncertaintyNs = 47514.989972114563, - .driftNsps = -51.757811607455452, - .driftUncertaintyNsps = 310.64968328491528, - .hwClockDiscontinuityCount = 1}; - - ElapsedRealtime timestamp = { - .flags = ElapsedRealtimeFlags::HAS_TIMESTAMP_NS | - ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS, - .timestampNs = static_cast(::android::elapsedRealtimeNano()), - // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks. - // In an actual implementation provide an estimate of the synchronization uncertainty - // or don't set the field. - .timeUncertaintyNs = 1000000}; - - GnssData gnssData = { - .measurements = measurements, .clock = clock, .elapsedRealtime = timestamp}; - return gnssData; -} - void GnssMeasurement::reportMeasurement(const GnssData& data) { ALOGD("reportMeasurement()"); std::unique_lock lock(mMutex); diff --git a/gnss/2.0/default/GnssMeasurement.h b/gnss/2.0/default/GnssMeasurement.h index c24c00e341..d8ffd59305 100644 --- a/gnss/2.0/default/GnssMeasurement.h +++ b/gnss/2.0/default/GnssMeasurement.h @@ -59,7 +59,6 @@ struct GnssMeasurement : public IGnssMeasurement { private: void start(); void stop(); - GnssData getMockMeasurement(); void reportMeasurement(const GnssData&); static sp sCallback; diff --git a/gnss/2.0/vts/functional/Android.bp b/gnss/2.0/vts/functional/Android.bp index 9aa13349b0..da5289d006 100644 --- a/gnss/2.0/vts/functional/Android.bp +++ b/gnss/2.0/vts/functional/Android.bp @@ -28,6 +28,7 @@ cc_test { "android.hardware.gnss@1.0", "android.hardware.gnss@1.1", "android.hardware.gnss@2.0", + "android.hardware.gnss@2.1", "android.hardware.gnss@common-vts-lib", ], test_suites: ["general-tests", "vts-core"], diff --git a/gnss/2.1/Android.bp b/gnss/2.1/Android.bp new file mode 100644 index 0000000000..5d3d62df80 --- /dev/null +++ b/gnss/2.1/Android.bp @@ -0,0 +1,24 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.gnss@2.1", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "IGnss.hal", + "IGnssCallback.hal", + "IGnssMeasurement.hal", + "IGnssMeasurementCallback.hal", + ], + interfaces: [ + "android.hardware.gnss.measurement_corrections@1.0", + "android.hardware.gnss.visibility_control@1.0", + "android.hardware.gnss@1.0", + "android.hardware.gnss@1.1", + "android.hardware.gnss@2.0", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/gnss/2.1/IGnss.hal b/gnss/2.1/IGnss.hal new file mode 100644 index 0000000000..812f9cc370 --- /dev/null +++ b/gnss/2.1/IGnss.hal @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.1; + +import @2.0::IGnss; + +import IGnssCallback; +import IGnssMeasurement; + +/** + * Represents the standard GNSS (Global Navigation Satellite System) interface. + */ +interface IGnss extends @2.0::IGnss { + /** + * Opens the interface and provides the callback routines to the implementation of this + * interface. + * + * The framework calls this method to instruct the GPS engine to prepare for serving requests + * from the framework. The GNSS HAL implementation must respond to all GNSS requests from the + * framework upon successful return from this method until cleanup() method is called to + * close this interface. + * + * @param callback Callback interface for IGnss. + * + * @return success Returns true on success. + */ + setCallback_2_1(IGnssCallback callback) generates (bool success); + + /** + * This method returns the IGnssMeasurement interface. + * + * At least one of getExtensionGnssMeasurement(), getExtensionGnssMeasurement_1_1(), + * getExtensionGnssMeasurement_2_0(), and getExtensionGnssMeasurement_2_1() methods must return + * a non-null handle, and the other methods must return nullptr. + * + * @return gnssMeasurementIface Handle to the IGnssMeasurement interface. + */ + getExtensionGnssMeasurement_2_1() generates (IGnssMeasurement gnssMeasurementIface); +}; \ No newline at end of file diff --git a/gnss/2.1/IGnssCallback.hal b/gnss/2.1/IGnssCallback.hal new file mode 100644 index 0000000000..da7074263c --- /dev/null +++ b/gnss/2.1/IGnssCallback.hal @@ -0,0 +1,58 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.1; + +import @2.0::IGnssCallback; + +/** + * This interface is required for the HAL to communicate certain information + * like status and location info back to the platform, the platform implements + * the interfaces and passes a handle to the HAL. + */ +interface IGnssCallback extends @2.0::IGnssCallback { + + /** Extends a GnssSvInfo, adding a basebandCN0DbHz. */ + struct GnssSvInfo { + /** + * GNSS satellite information for a single satellite and frequency. + */ + @2.0::IGnssCallback.GnssSvInfo v2_0; + + /** + * Baseband Carrier-to-noise density in dB-Hz, typically in the range [0, 63]. It contains + * the measured C/N0 value for the signal measured at the baseband. + * + * This is typically a few dB weaker than the value estimated for C/N0 at the antenna port, + * which is reported in cN0DbHz. + * + * If a signal has separate components (e.g. Pilot and Data channels) and the receiver only + * processes one of the components, then the reported basebandCN0DbHz reflects only the + * component that is processed. + * + * This value is mandatory. Like cN0DbHz, it may be reported as 0 for satellites being + * reported that may be searched for, but not yet tracked. + */ + double basebandCN0DbHz; + }; + + /** + * Callback for the HAL to pass a vector of GnssSvInfo back to the client. + * + * @param svInfoList SV info list information from HAL. + */ + gnssSvStatusCb_2_1(vec svInfoList); +}; diff --git a/gnss/2.1/IGnssMeasurement.hal b/gnss/2.1/IGnssMeasurement.hal new file mode 100644 index 0000000000..d2c76e6989 --- /dev/null +++ b/gnss/2.1/IGnssMeasurement.hal @@ -0,0 +1,51 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.1; + +import @1.0::IGnssMeasurement; +import @1.1::IGnssMeasurement; +import @2.0::IGnssMeasurement; +import IGnssMeasurementCallback; + +/** + * Extended interface for GNSS Measurements support. + */ +interface IGnssMeasurement extends @2.0::IGnssMeasurement { + + /** + * Initializes the interface and registers the callback routines with the HAL. After a + * successful call to 'setCallback_2_1' the HAL must begin to provide updates at an average + * output rate of 1Hz (occasional intra-measurement time offsets in the range from 0-2000msec + * can be tolerated.) + * + * @param callback Handle to GnssMeasurement callback interface. + * @param enableFullTracking If true, GNSS chipset must switch off duty cycling. In such mode + * no clock discontinuities are expected and, when supported, carrier phase should be + * continuous in good signal conditions. All non-blacklisted, healthy constellations, + * satellites and frequency bands that the chipset supports must be reported in this mode. + * The GNSS chipset is allowed to consume more power in this mode. If false, API must behave + * as in HAL V1_0, optimizing power via duty cycling, constellations and frequency limits, + * etc. + * + * @return initRet Returns SUCCESS if successful. Returns ERROR_ALREADY_INIT if a callback has + * already been registered without a corresponding call to 'close'. Returns ERROR_GENERIC + * for any other error. The HAL must not generate any other updates upon returning this + * error code. + */ + setCallback_2_1(IGnssMeasurementCallback callback, bool enableFullTracking) + generates (GnssMeasurementStatus initRet); +}; diff --git a/gnss/2.1/IGnssMeasurementCallback.hal b/gnss/2.1/IGnssMeasurementCallback.hal new file mode 100644 index 0000000000..ca6175f508 --- /dev/null +++ b/gnss/2.1/IGnssMeasurementCallback.hal @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.1; + +import @1.0::IGnssMeasurementCallback; +import @1.1::IGnssMeasurementCallback; +import @2.0::IGnssMeasurementCallback; +import @2.0::ElapsedRealtime; + +/** The callback interface to report measurements from the HAL. */ +interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback { + + /** + * Extends a GNSS Measurement, adding a basebandCN0DbHz. + */ + struct GnssMeasurement { + /** + * GNSS measurement information for a single satellite and frequency, as in the 2.0 version + * of the HAL. + */ + @2.0::IGnssMeasurementCallback.GnssMeasurement v2_0; + + /** + * Baseband Carrier-to-noise density in dB-Hz, typically in the range [0, 63]. It contains + * the measured C/N0 value for the signal measured at the baseband. + * + * This is typically a few dB weaker than the value estimated for C/N0 at the antenna port, + * which is reported in cN0DbHz. + * + * If a signal has separate components (e.g. Pilot and Data channels) and the receiver only + * processes one of the components, then the reported basebandCN0DbHz reflects only the + * component that is processed. + * + * This value is mandatory. + */ + double basebandCN0DbHz; + }; + + /** + * Complete set of GNSS Measurement data, same as 2.0 with additional double (i.e., + * basebandCN0DbHz) in measurements. + */ + struct GnssData { + /** The full set of satellite measurement observations. */ + vec measurements; + + /** The GNSS clock time reading. */ + GnssClock clock; + + /** + * Timing information of the GNSS data synchronized with SystemClock.elapsedRealtimeNanos() + * clock. + */ + ElapsedRealtime elapsedRealtime; + }; + + /** + * Callback for the hal to pass a GnssData structure back to the client. + * + * @param data Contains a reading of GNSS measurements. + */ + gnssMeasurementCb_2_1(GnssData data); +}; diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp new file mode 100644 index 0000000000..a7cf63da5a --- /dev/null +++ b/gnss/2.1/default/Android.bp @@ -0,0 +1,42 @@ +/* + * 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. + */ + +cc_binary { + name: "android.hardware.gnss@2.1-service", + init_rc: ["android.hardware.gnss@2.1-service.rc"], + relative_install_path: "hw", + vendor: true, + vintf_fragments: ["android.hardware.gnss@2.1-service.xml"], + srcs: [ + "Gnss.cpp", + "GnssMeasurement.cpp", + "service.cpp" + ], + shared_libs: [ + "libhidlbase", + "libutils", + "liblog", + "android.hardware.gnss.measurement_corrections@1.0", + "android.hardware.gnss.visibility_control@1.0", + "android.hardware.gnss@2.1", + "android.hardware.gnss@1.0", + "android.hardware.gnss@1.1", + "android.hardware.gnss@2.0", + ], + static_libs: [ + "android.hardware.gnss@common-default-lib", + ], +} diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp new file mode 100644 index 0000000000..2771f27b79 --- /dev/null +++ b/gnss/2.1/default/Gnss.cpp @@ -0,0 +1,301 @@ +/* + * 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 "Gnss" + +#include "Gnss.h" +#include "GnssMeasurement.h" +#include "Utils.h" + +#include + +using ::android::hardware::gnss::common::Utils; + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_1 { +namespace implementation { + +sp Gnss::sGnssCallback_2_1 = nullptr; + +Gnss::Gnss() : mMinIntervalMs(1000) {} + +Gnss::~Gnss() { + stop(); +} + +Return Gnss::start() { + ALOGD("start"); + if (mIsActive) { + ALOGW("Gnss has started. Restarting..."); + stop(); + } + + mIsActive = true; + mThread = std::thread([this]() { + while (mIsActive == true) { + auto svStatus = Utils::getMockSvInfoListV2_1(); + this->reportSvStatus(svStatus); + + const auto location = Utils::getMockLocationV2_0(); + this->reportLocation(location); + + std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs)); + } + }); + return true; +} + +Return Gnss::stop() { + ALOGD("stop"); + mIsActive = false; + if (mThread.joinable()) { + mThread.join(); + } + return true; +} + +// Methods from V1_0::IGnss follow. +Return Gnss::setCallback(const sp&) { + // TODO implement + return bool{}; +} + +Return Gnss::cleanup() { + // TODO implement + return Void(); +} + +Return Gnss::injectTime(int64_t, int64_t, int32_t) { + // TODO implement + return bool{}; +} + +Return Gnss::injectLocation(double, double, float) { + // TODO implement + return bool{}; +} + +Return Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData) { + // TODO implement + return Void(); +} + +Return Gnss::setPositionMode(V1_0::IGnss::GnssPositionMode, + V1_0::IGnss::GnssPositionRecurrence, uint32_t, uint32_t, + uint32_t) { + // TODO implement + return bool{}; +} + +Return> Gnss::getExtensionAGnssRil() { + // TODO implement + return ::android::sp{}; +} + +Return> Gnss::getExtensionGnssGeofencing() { + // TODO implement + return ::android::sp{}; +} + +Return> Gnss::getExtensionAGnss() { + // TODO implement + return ::android::sp{}; +} + +Return> Gnss::getExtensionGnssNi() { + // TODO implement + return ::android::sp{}; +} + +Return> Gnss::getExtensionGnssMeasurement() { + // TODO implement + return ::android::sp{}; +} + +Return> Gnss::getExtensionGnssNavigationMessage() { + // TODO implement + return ::android::sp{}; +} + +Return> Gnss::getExtensionXtra() { + // TODO implement + return ::android::sp{}; +} + +Return> Gnss::getExtensionGnssConfiguration() { + // TODO implement + return ::android::sp{}; +} + +Return> Gnss::getExtensionGnssDebug() { + // TODO implement + return ::android::sp{}; +} + +Return> Gnss::getExtensionGnssBatching() { + // TODO implement + return ::android::sp{}; +} + +// Methods from V1_1::IGnss follow. +Return Gnss::setCallback_1_1(const sp&) { + // TODO implement + return bool{}; +} + +Return Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode, + V1_0::IGnss::GnssPositionRecurrence, uint32_t, uint32_t, + uint32_t, bool) { + return true; +} + +Return> Gnss::getExtensionGnssConfiguration_1_1() { + // TODO implement + return ::android::sp{}; +} + +Return> Gnss::getExtensionGnssMeasurement_1_1() { + // TODO implement + return ::android::sp{}; +} + +Return Gnss::injectBestLocation(const V1_0::GnssLocation&) { + // TODO implement + return bool{}; +} + +// Methods from V2_0::IGnss follow. +Return Gnss::setCallback_2_0(const sp&) { + // TODO implement + return bool{}; +} + +Return> Gnss::getExtensionGnssConfiguration_2_0() { + // TODO implement + return ::android::sp{}; +} + +Return> Gnss::getExtensionGnssDebug_2_0() { + // TODO implement + return ::android::sp{}; +} + +Return> Gnss::getExtensionAGnss_2_0() { + // TODO implement + return ::android::sp{}; +} + +Return> Gnss::getExtensionAGnssRil_2_0() { + // TODO implement + return ::android::sp{}; +} + +Return> Gnss::getExtensionGnssMeasurement_2_0() { + // TODO implement + return ::android::sp{}; +} + +Return> +Gnss::getExtensionMeasurementCorrections() { + // TODO implement + return ::android::sp{}; +} + +Return> Gnss::getExtensionVisibilityControl() { + // TODO implement + return ::android::sp{}; +} + +Return> Gnss::getExtensionGnssBatching_2_0() { + // TODO implement + return ::android::sp{}; +} + +Return Gnss::injectBestLocation_2_0(const V2_0::GnssLocation&) { + // TODO implement + return bool{}; +} + +// Methods from V2_1::IGnss follow. +Return Gnss::setCallback_2_1(const sp& callback) { + ALOGD("Gnss::setCallback_2_1"); + if (callback == nullptr) { + ALOGE("%s: Null callback ignored", __func__); + return false; + } + + sGnssCallback_2_1 = callback; + + using Capabilities = V2_0::IGnssCallback::Capabilities; + const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS | + Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST; + auto ret = sGnssCallback_2_1->gnssSetCapabilitiesCb_2_0(capabilities); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2020}; + + ret = sGnssCallback_2_1->gnssSetSystemInfoCb(gnssInfo); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + auto gnssName = "Android Mock GNSS Implementation v2.1"; + ret = sGnssCallback_2_1->gnssNameCb(gnssName); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + return true; +} + +Return> Gnss::getExtensionGnssMeasurement_2_1() { + ALOGD("Gnss::getExtensionGnssMeasurement_2_1"); + return new GnssMeasurement(); +} + +void Gnss::reportSvStatus(const hidl_vec& svInfoList) const { + std::unique_lock lock(mMutex); + if (sGnssCallback_2_1 == nullptr) { + ALOGE("%s: sGnssCallback v2.1 is null.", __func__); + return; + } + auto ret = sGnssCallback_2_1->gnssSvStatusCb_2_1(svInfoList); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +void Gnss::reportLocation(const V2_0::GnssLocation& location) const { + std::unique_lock lock(mMutex); + if (sGnssCallback_2_1 == nullptr) { + ALOGE("%s: sGnssCallback v2.1 is null.", __func__); + return; + } + auto ret = sGnssCallback_2_1->gnssLocationCb_2_0(location); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +} // namespace implementation +} // namespace V2_1 +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/2.1/default/Gnss.h b/gnss/2.1/default/Gnss.h new file mode 100644 index 0000000000..a61f71cf75 --- /dev/null +++ b/gnss/2.1/default/Gnss.h @@ -0,0 +1,106 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_1 { + +using GnssSvInfo = IGnssCallback::GnssSvInfo; + +namespace implementation { + +struct Gnss : public IGnss { + Gnss(); + ~Gnss(); + // Methods from V1_0::IGnss follow. + Return setCallback(const sp& callback) override; + Return start() override; + Return stop() override; + Return cleanup() override; + Return injectTime(int64_t timeMs, int64_t timeReferenceMs, + int32_t uncertaintyMs) override; + Return injectLocation(double latitudeDegrees, double longitudeDegrees, + float accuracyMeters) override; + Return deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) override; + Return setPositionMode(V1_0::IGnss::GnssPositionMode mode, + V1_0::IGnss::GnssPositionRecurrence recurrence, + uint32_t minIntervalMs, uint32_t preferredAccuracyMeters, + uint32_t preferredTimeMs) override; + Return> getExtensionAGnssRil() override; + Return> getExtensionGnssGeofencing() override; + Return> getExtensionAGnss() override; + Return> getExtensionGnssNi() override; + Return> getExtensionGnssMeasurement() override; + Return> getExtensionGnssNavigationMessage() override; + Return> getExtensionXtra() override; + Return> getExtensionGnssConfiguration() override; + Return> getExtensionGnssDebug() override; + Return> getExtensionGnssBatching() override; + + // Methods from V1_1::IGnss follow. + Return setCallback_1_1(const sp& callback) override; + Return setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode, + V1_0::IGnss::GnssPositionRecurrence recurrence, + uint32_t minIntervalMs, uint32_t preferredAccuracyMeters, + uint32_t preferredTimeMs, bool lowPowerMode) override; + Return> getExtensionGnssConfiguration_1_1() override; + Return> getExtensionGnssMeasurement_1_1() override; + Return injectBestLocation(const V1_0::GnssLocation& location) override; + + // Methods from V2_0::IGnss follow. + Return setCallback_2_0(const sp& callback) override; + Return> getExtensionGnssConfiguration_2_0() override; + Return> getExtensionGnssDebug_2_0() override; + Return> getExtensionAGnss_2_0() override; + Return> getExtensionAGnssRil_2_0() override; + Return> getExtensionGnssMeasurement_2_0() override; + Return> + getExtensionMeasurementCorrections() override; + Return> getExtensionVisibilityControl() + override; + Return> getExtensionGnssBatching_2_0() override; + Return injectBestLocation_2_0(const V2_0::GnssLocation& location) override; + + // Methods from V2_1::IGnss follow. + Return setCallback_2_1(const sp& callback) override; + Return> getExtensionGnssMeasurement_2_1() override; + + private: + void reportLocation(const V2_0::GnssLocation&) const; + void reportSvStatus(const hidl_vec&) const; + + static sp sGnssCallback_2_1; + std::atomic mMinIntervalMs; + std::atomic mIsActive; + std::thread mThread; + mutable std::mutex mMutex; +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/2.1/default/GnssMeasurement.cpp b/gnss/2.1/default/GnssMeasurement.cpp new file mode 100644 index 0000000000..ebfa7ddf1d --- /dev/null +++ b/gnss/2.1/default/GnssMeasurement.cpp @@ -0,0 +1,123 @@ +/* + * 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 "GnssMeasurement" + +#include "GnssMeasurement.h" +#include +#include "Utils.h" + +namespace android { +namespace hardware { +namespace gnss { + +using common::Utils; + +namespace V2_1 { +namespace implementation { + +sp GnssMeasurement::sCallback = nullptr; + +GnssMeasurement::GnssMeasurement() : mMinIntervalMillis(1000) {} + +GnssMeasurement::~GnssMeasurement() { + stop(); +} + +// Methods from V1_0::IGnssMeasurement follow. +Return GnssMeasurement::setCallback( + const sp&) { + // TODO implement + return V1_0::IGnssMeasurement::GnssMeasurementStatus{}; +} + +Return GnssMeasurement::close() { + ALOGD("close"); + std::unique_lock lock(mMutex); + stop(); + sCallback = nullptr; + return Void(); +} + +// Methods from V1_1::IGnssMeasurement follow. +Return GnssMeasurement::setCallback_1_1( + const sp&, bool) { + // TODO implement + return V1_0::IGnssMeasurement::GnssMeasurementStatus{}; +} + +// Methods from V2_0::IGnssMeasurement follow. +Return GnssMeasurement::setCallback_2_0( + const sp&, bool) { + // TODO implement + return V1_0::IGnssMeasurement::GnssMeasurementStatus{}; +} + +// Methods from V2_1::IGnssMeasurement follow. +Return GnssMeasurement::setCallback_2_1( + const sp& callback, bool) { + ALOGD("setCallback_2_1"); + std::unique_lock lock(mMutex); + sCallback = callback; + + if (mIsActive) { + ALOGW("GnssMeasurement callback already set. Resetting the callback..."); + stop(); + } + start(); + + return V1_0::IGnssMeasurement::GnssMeasurementStatus::SUCCESS; +} + +void GnssMeasurement::start() { + ALOGD("start"); + mIsActive = true; + mThread = std::thread([this]() { + while (mIsActive == true) { + auto measurement = Utils::getMockMeasurementV2_1(); + this->reportMeasurement(measurement); + + std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis)); + } + }); +} + +void GnssMeasurement::stop() { + ALOGD("stop"); + mIsActive = false; + if (mThread.joinable()) { + mThread.join(); + } +} + +void GnssMeasurement::reportMeasurement(const GnssDataV2_1& data) { + ALOGD("reportMeasurement()"); + std::unique_lock lock(mMutex); + if (sCallback == nullptr) { + ALOGE("%s: GnssMeasurement::sCallback is null.", __func__); + return; + } + auto ret = sCallback->gnssMeasurementCb_2_1(data); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +} // namespace implementation +} // namespace V2_1 +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/2.1/default/GnssMeasurement.h b/gnss/2.1/default/GnssMeasurement.h new file mode 100644 index 0000000000..ee329039d9 --- /dev/null +++ b/gnss/2.1/default/GnssMeasurement.h @@ -0,0 +1,78 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_1 { +namespace implementation { + +using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData; + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +struct GnssMeasurement : public IGnssMeasurement { + GnssMeasurement(); + ~GnssMeasurement(); + // Methods from V1_0::IGnssMeasurement follow. + Return setCallback( + const sp& callback) override; + Return close() override; + + // Methods from V1_1::IGnssMeasurement follow. + Return setCallback_1_1( + const sp& callback, bool enableFullTracking) override; + + // Methods from V2_0::IGnssMeasurement follow. + Return setCallback_2_0( + const sp& callback, bool enableFullTracking) override; + + // Methods from V2_1::IGnssMeasurement follow. + Return setCallback_2_1( + const sp& callback, bool enableFullTracking) override; + + private: + void start(); + void stop(); + void reportMeasurement(const GnssDataV2_1&); + + static sp sCallback; + std::atomic mMinIntervalMillis; + std::atomic mIsActive; + std::thread mThread; + mutable std::mutex mMutex; +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/2.1/default/OWNERS b/gnss/2.1/default/OWNERS new file mode 100644 index 0000000000..b7b4a2e902 --- /dev/null +++ b/gnss/2.1/default/OWNERS @@ -0,0 +1,4 @@ +gomo@google.com +smalkos@google.com +wyattriley@google.com +yuhany@google.com diff --git a/gnss/2.1/default/android.hardware.gnss@2.1-service.rc b/gnss/2.1/default/android.hardware.gnss@2.1-service.rc new file mode 100644 index 0000000000..5926c775d2 --- /dev/null +++ b/gnss/2.1/default/android.hardware.gnss@2.1-service.rc @@ -0,0 +1,4 @@ +service vendor.gnss-2-1 /vendor/bin/hw/android.hardware.gnss@2.1-service + class hal + user system + group system diff --git a/gnss/2.1/default/android.hardware.gnss@2.1-service.xml b/gnss/2.1/default/android.hardware.gnss@2.1-service.xml new file mode 100644 index 0000000000..12a1fdfa08 --- /dev/null +++ b/gnss/2.1/default/android.hardware.gnss@2.1-service.xml @@ -0,0 +1,12 @@ + + + android.hardware.gnss + hwbinder + 2.1 + 1.1 + + IGnss + default + + + diff --git a/gnss/2.1/default/service.cpp b/gnss/2.1/default/service.cpp new file mode 100644 index 0000000000..5e004d5697 --- /dev/null +++ b/gnss/2.1/default/service.cpp @@ -0,0 +1,41 @@ +/* + * 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 "android.hardware.gnss@2.1-service" + +#include +#include +#include "Gnss.h" + +using ::android::OK; +using ::android::sp; +using ::android::hardware::configureRpcThreadpool; +using ::android::hardware::joinRpcThreadpool; +using ::android::hardware::gnss::V2_1::IGnss; +using ::android::hardware::gnss::V2_1::implementation::Gnss; + +int main(int /* argc */, char* /* argv */[]) { + sp gnss = new Gnss(); + configureRpcThreadpool(1, true /* will join */); + if (gnss->registerAsService() != OK) { + ALOGE("Could not register gnss 2.1 service."); + return 1; + } + joinRpcThreadpool(); + + ALOGE("Service exited!"); + return 1; +} \ No newline at end of file diff --git a/gnss/2.1/vts/OWNERS b/gnss/2.1/vts/OWNERS new file mode 100644 index 0000000000..b7b4a2e902 --- /dev/null +++ b/gnss/2.1/vts/OWNERS @@ -0,0 +1,4 @@ +gomo@google.com +smalkos@google.com +wyattriley@google.com +yuhany@google.com diff --git a/gnss/2.1/vts/functional/Android.bp b/gnss/2.1/vts/functional/Android.bp new file mode 100644 index 0000000000..83404992de --- /dev/null +++ b/gnss/2.1/vts/functional/Android.bp @@ -0,0 +1,35 @@ +// +// 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. +// + +cc_test { + name: "VtsHalGnssV2_1TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "gnss_hal_test.cpp", + "gnss_hal_test_cases.cpp", + "VtsHalGnssV2_1TargetTest.cpp", + ], + static_libs: [ + "android.hardware.gnss.measurement_corrections@1.0", + "android.hardware.gnss.visibility_control@1.0", + "android.hardware.gnss@1.0", + "android.hardware.gnss@1.1", + "android.hardware.gnss@2.0", + "android.hardware.gnss@2.1", + "android.hardware.gnss@common-vts-lib", + ], + test_suites: ["general-tests", "vts-core"], +} diff --git a/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp b/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp new file mode 100644 index 0000000000..e61d885654 --- /dev/null +++ b/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp @@ -0,0 +1,29 @@ +/* + * 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 "VtsHalGnssV2_1TargetTest" + +#include +#include +#include + +#include "gnss_hal_test.h" + +using android::hardware::gnss::V2_1::IGnss; + +INSTANTIATE_TEST_SUITE_P( + PerInstance, GnssHalTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/gnss/2.1/vts/functional/gnss_hal_test.cpp b/gnss/2.1/vts/functional/gnss_hal_test.cpp new file mode 100644 index 0000000000..7cfe0db381 --- /dev/null +++ b/gnss/2.1/vts/functional/gnss_hal_test.cpp @@ -0,0 +1,217 @@ +/* + * 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 "GnssHalTest" + +#include +#include +#include "Utils.h" + +#include + +using ::android::hardware::gnss::common::Utils; + +// Implementations for the main test class for GNSS HAL +void GnssHalTest::SetUp() { + gnss_hal_ = IGnss::getService(GetParam()); + ASSERT_NE(gnss_hal_, nullptr); + + SetUpGnssCallback(); +} + +void GnssHalTest::TearDown() { + if (gnss_hal_ != nullptr) { + gnss_hal_->cleanup(); + gnss_hal_ = nullptr; + } + + // Set to nullptr to destruct the callback event queues and warn of any unprocessed events. + gnss_cb_ = nullptr; +} + +void GnssHalTest::SetUpGnssCallback() { + gnss_cb_ = new GnssCallback(); + ASSERT_NE(gnss_cb_, nullptr); + + auto result = gnss_hal_->setCallback_2_1(gnss_cb_); + if (!result.isOk()) { + ALOGE("result of failed setCallback %s", result.description().c_str()); + } + + ASSERT_TRUE(result.isOk()); + ASSERT_TRUE(result); + + /* + * All capabilities, name and systemInfo callbacks should trigger + */ + EXPECT_TRUE(gnss_cb_->capabilities_cbq_.retrieve(gnss_cb_->last_capabilities_, TIMEOUT_SEC)); + EXPECT_TRUE(gnss_cb_->info_cbq_.retrieve(gnss_cb_->last_info_, TIMEOUT_SEC)); + EXPECT_TRUE(gnss_cb_->name_cbq_.retrieve(gnss_cb_->last_name_, TIMEOUT_SEC)); + + EXPECT_EQ(gnss_cb_->capabilities_cbq_.calledCount(), 1); + EXPECT_EQ(gnss_cb_->info_cbq_.calledCount(), 1); + EXPECT_EQ(gnss_cb_->name_cbq_.calledCount(), 1); +} + +void GnssHalTest::StopAndClearLocations() { + const auto result = gnss_hal_->stop(); + + EXPECT_TRUE(result.isOk()); + EXPECT_TRUE(result); + + /* + * Clear notify/waiting counter, allowing up till the timeout after + * the last reply for final startup messages to arrive (esp. system + * info.) + */ + while (gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, TIMEOUT_SEC)) { + } + gnss_cb_->location_cbq_.reset(); +} + +void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_power_mode) { + const int kPreferredAccuracy = 0; // Ideally perfect (matches GnssLocationProvider) + const int kPreferredTimeMsec = 0; // Ideally immediate + + const auto result = gnss_hal_->setPositionMode_1_1( + IGnss::GnssPositionMode::MS_BASED, IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC, + min_interval_msec, kPreferredAccuracy, kPreferredTimeMsec, low_power_mode); + + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); +} + +bool GnssHalTest::StartAndCheckFirstLocation() { + const auto result = gnss_hal_->start(); + + EXPECT_TRUE(result.isOk()); + EXPECT_TRUE(result); + + /* + * GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS, + * so allow time to demodulate ephemeris over the air. + */ + const int kFirstGnssLocationTimeoutSeconds = 75; + + EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, + kFirstGnssLocationTimeoutSeconds)); + int locationCalledCount = gnss_cb_->location_cbq_.calledCount(); + EXPECT_EQ(locationCalledCount, 1); + + if (locationCalledCount > 0) { + // don't require speed on first fix + CheckLocation(gnss_cb_->last_location_, false); + return true; + } + return false; +} + +void GnssHalTest::CheckLocation(const GnssLocation_2_0& location, bool check_speed) { + const bool check_more_accuracies = + (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017); + + Utils::checkLocation(location.v1_0, check_speed, check_more_accuracies); +} + +void GnssHalTest::StartAndCheckLocations(int count) { + const int kMinIntervalMsec = 500; + const int kLocationTimeoutSubsequentSec = 2; + const bool kLowPowerMode = false; + + SetPositionMode(kMinIntervalMsec, kLowPowerMode); + + EXPECT_TRUE(StartAndCheckFirstLocation()); + + for (int i = 1; i < count; i++) { + EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, + kLocationTimeoutSubsequentSec)); + int locationCalledCount = gnss_cb_->location_cbq_.calledCount(); + EXPECT_EQ(locationCalledCount, i + 1); + // Don't cause confusion by checking details if no location yet + if (locationCalledCount > 0) { + // Should be more than 1 location by now, but if not, still don't check first fix speed + CheckLocation(gnss_cb_->last_location_, locationCalledCount > 1); + } + } +} + +GnssHalTest::GnssCallback::GnssCallback() + : info_cbq_("system_info"), + name_cbq_("name"), + capabilities_cbq_("capabilities"), + location_cbq_("location"), + sv_info_list_cbq_("sv_info") {} + +Return GnssHalTest::GnssCallback::gnssSetSystemInfoCb( + const IGnssCallback_1_0::GnssSystemInfo& info) { + ALOGI("Info received, year %d", info.yearOfHw); + info_cbq_.store(info); + return Void(); +} + +Return GnssHalTest::GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) { + ALOGI("Capabilities received %d", capabilities); + capabilities_cbq_.store(capabilities); + return Void(); +} + +Return GnssHalTest::GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) { + ALOGI("Capabilities (v2.0) received %d", capabilities); + capabilities_cbq_.store(capabilities); + return Void(); +} + +Return GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) { + ALOGI("Name received: %s", name.c_str()); + name_cbq_.store(name); + return Void(); +} + +Return GnssHalTest::GnssCallback::gnssLocationCb(const GnssLocation_1_0& location) { + ALOGI("Location received"); + GnssLocation_2_0 location_v2_0; + location_v2_0.v1_0 = location; + return gnssLocationCbImpl(location_v2_0); +} + +Return GnssHalTest::GnssCallback::gnssLocationCb_2_0(const GnssLocation_2_0& location) { + ALOGI("Location (v2.0) received"); + return gnssLocationCbImpl(location); +} + +Return GnssHalTest::GnssCallback::gnssLocationCbImpl(const GnssLocation_2_0& location) { + location_cbq_.store(location); + return Void(); +} + +Return GnssHalTest::GnssCallback::gnssSvStatusCb(const IGnssCallback_1_0::GnssSvStatus&) { + ALOGI("gnssSvStatusCb"); + return Void(); +} + +Return GnssHalTest::GnssCallback::gnssSvStatusCb_2_1( + const hidl_vec& svInfoList) { + ALOGI("gnssSvStatusCb_2_1. Size = %d", (int)svInfoList.size()); + sv_info_list_cbq_.store(svInfoList); + return Void(); +} + +Return GnssHalTest::GnssMeasurementCallback::gnssMeasurementCb_2_1( + const IGnssMeasurementCallback_2_1::GnssData& data) { + ALOGD("GnssMeasurement v2.1 received. Size = %d", (int)data.measurements.size()); + measurement_cbq_.store(data); + return Void(); +} diff --git a/gnss/2.1/vts/functional/gnss_hal_test.h b/gnss/2.1/vts/functional/gnss_hal_test.h new file mode 100644 index 0000000000..2e1add01ea --- /dev/null +++ b/gnss/2.1/vts/functional/gnss_hal_test.h @@ -0,0 +1,191 @@ +/* + * 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. + */ + +#ifndef GNSS_HAL_TEST_H_ +#define GNSS_HAL_TEST_H_ + +#include +#include "GnssCallbackEventQueue.h" + +#include + +using android::hardware::hidl_vec; +using android::hardware::Return; +using android::hardware::Void; + +using android::hardware::gnss::common::GnssCallbackEventQueue; +using android::hardware::gnss::V1_0::GnssLocationFlags; +using android::hardware::gnss::V2_1::IGnss; + +using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation; +using GnssLocation_2_0 = android::hardware::gnss::V2_0::GnssLocation; + +using IGnssCallback_1_0 = android::hardware::gnss::V1_0::IGnssCallback; +using IGnssCallback_2_0 = android::hardware::gnss::V2_0::IGnssCallback; +using IGnssCallback_2_1 = android::hardware::gnss::V2_1::IGnssCallback; + +using IGnssMeasurementCallback_1_0 = android::hardware::gnss::V1_0::IGnssMeasurementCallback; +using IGnssMeasurementCallback_1_1 = android::hardware::gnss::V1_1::IGnssMeasurementCallback; +using IGnssMeasurementCallback_2_0 = android::hardware::gnss::V2_0::IGnssMeasurementCallback; +using IGnssMeasurementCallback_2_1 = android::hardware::gnss::V2_1::IGnssMeasurementCallback; + +using android::sp; + +#define TIMEOUT_SEC 2 // for basic commands/responses + +// The main test class for GNSS HAL. +class GnssHalTest : public testing::TestWithParam { + public: + virtual void SetUp() override; + + virtual void TearDown() override; + + /* Callback class for data & Event. */ + class GnssCallback : public IGnssCallback_2_1 { + public: + IGnssCallback_1_0::GnssSystemInfo last_info_; + android::hardware::hidl_string last_name_; + uint32_t last_capabilities_; + GnssLocation_2_0 last_location_; + + GnssCallbackEventQueue info_cbq_; + GnssCallbackEventQueue name_cbq_; + GnssCallbackEventQueue capabilities_cbq_; + GnssCallbackEventQueue location_cbq_; + GnssCallbackEventQueue> sv_info_list_cbq_; + + GnssCallback(); + virtual ~GnssCallback() = default; + + // Dummy callback handlers + Return gnssStatusCb(const IGnssCallback_1_0::GnssStatusValue /* status */) override { + return Void(); + } + Return gnssNmeaCb(int64_t /* timestamp */, + const android::hardware::hidl_string& /* nmea */) override { + return Void(); + } + Return gnssAcquireWakelockCb() override { return Void(); } + Return gnssReleaseWakelockCb() override { return Void(); } + Return gnssRequestLocationCb(bool /* independentFromGnss */) override { + return Void(); + } + Return gnssRequestTimeCb() override { return Void(); } + // Actual (test) callback handlers + Return gnssNameCb(const android::hardware::hidl_string& name) override; + Return gnssLocationCb(const GnssLocation_1_0& location) override; + Return gnssSetCapabilitesCb(uint32_t capabilities) override; + Return gnssSetSystemInfoCb(const IGnssCallback_1_0::GnssSystemInfo& info) override; + Return gnssSvStatusCb(const IGnssCallback_1_0::GnssSvStatus& svStatus) override; + + // New in v2.0 + Return gnssLocationCb_2_0(const GnssLocation_2_0& location) override; + Return gnssRequestLocationCb_2_0(bool /* independentFromGnss */, + bool /* isUserEmergency */) override { + return Void(); + } + Return gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override; + Return gnssSvStatusCb_2_0(const hidl_vec&) override { + return Void(); + } + + // New in v2.1 + Return gnssSvStatusCb_2_1( + const hidl_vec& svInfoList) override; + + private: + Return gnssLocationCbImpl(const GnssLocation_2_0& location); + }; + + /* Callback class for GnssMeasurement. */ + class GnssMeasurementCallback : public IGnssMeasurementCallback_2_1 { + public: + GnssCallbackEventQueue measurement_cbq_; + + GnssMeasurementCallback() : measurement_cbq_("measurement"){}; + virtual ~GnssMeasurementCallback() = default; + + // Methods from V1_0::IGnssMeasurementCallback follow. + Return GnssMeasurementCb(const IGnssMeasurementCallback_1_0::GnssData&) override { + return Void(); + } + + // Methods from V1_1::IGnssMeasurementCallback follow. + Return gnssMeasurementCb(const IGnssMeasurementCallback_1_1::GnssData&) override { + return Void(); + } + + // Methods from V2_0::IGnssMeasurementCallback follow. + Return gnssMeasurementCb_2_0(const IGnssMeasurementCallback_2_0::GnssData&) override { + return Void(); + } + + // Methods from V2_1::IGnssMeasurementCallback follow. + Return gnssMeasurementCb_2_1(const IGnssMeasurementCallback_2_1::GnssData&) override; + }; + + /* + * SetUpGnssCallback: + * Set GnssCallback and verify the result. + */ + void SetUpGnssCallback(); + + /* + * StartAndCheckFirstLocation: + * Helper function to start location, and check the first one. + * + *

    Note this leaves the Location request active, to enable Stop call vs. other call + * reordering tests. + * + * returns true if a location was successfully generated + */ + bool StartAndCheckFirstLocation(); + + /* + * CheckLocation: + * Helper function to vet Location fields + * + * check_speed: true if speed related fields are also verified. + */ + void CheckLocation(const GnssLocation_2_0& location, const bool check_speed); + + /* + * StartAndCheckLocations: + * Helper function to collect, and check a number of + * normal ~1Hz locations. + * + * Note this leaves the Location request active, to enable Stop call vs. other call + * reordering tests. + */ + void StartAndCheckLocations(int count); + + /* + * StopAndClearLocations: + * Helper function to stop locations, and clear any remaining notifications + */ + void StopAndClearLocations(); + + /* + * SetPositionMode: + * Helper function to set positioning mode and verify output + */ + void SetPositionMode(const int min_interval_msec, const bool low_power_mode); + + sp gnss_hal_; // GNSS HAL to call into + sp gnss_cb_; // Primary callback interface +}; + +#endif // GNSS_HAL_TEST_H_ diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp new file mode 100644 index 0000000000..ef8249b4d0 --- /dev/null +++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp @@ -0,0 +1,128 @@ +/* + * 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 "GnssHalTestCases" + +#include +#include "Utils.h" + +#include + +using android::hardware::hidl_string; +using android::hardware::hidl_vec; + +using android::hardware::gnss::common::Utils; + +using IGnssMeasurement_2_1 = android::hardware::gnss::V2_1::IGnssMeasurement; +using IGnssMeasurement_2_0 = android::hardware::gnss::V2_0::IGnssMeasurement; +using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement; +using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement; + +/* + * SetupTeardownCreateCleanup: + * Requests the gnss HAL then calls cleanup + * + * Empty test fixture to verify basic Setup & Teardown + */ +TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {} + +/* + * TestGnssMeasurementExtension: + * Gets the GnssMeasurementExtension and verifies that it returns an actual extension. + */ +TEST_P(GnssHalTest, TestGnssMeasurementExtension) { + auto gnssMeasurement_2_1 = gnss_hal_->getExtensionGnssMeasurement_2_1(); + auto gnssMeasurement_2_0 = gnss_hal_->getExtensionGnssMeasurement_2_0(); + auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1(); + auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement(); + ASSERT_TRUE(gnssMeasurement_2_1.isOk() && gnssMeasurement_2_0.isOk() && + gnssMeasurement_1_1.isOk() && gnssMeasurement_1_0.isOk()); + sp iGnssMeas_2_1 = gnssMeasurement_2_1; + sp iGnssMeas_2_0 = gnssMeasurement_2_0; + sp iGnssMeas_1_1 = gnssMeasurement_1_1; + sp iGnssMeas_1_0 = gnssMeasurement_1_0; + // At least one interface is non-null. + int numNonNull = (int)(iGnssMeas_2_1 != nullptr) + (int)(iGnssMeas_2_0 != nullptr) + + (int)(iGnssMeas_1_1 != nullptr) + (int)(iGnssMeas_1_0 != nullptr); + ASSERT_TRUE(numNonNull >= 1); +} + +/* + * TestGnssMeasurementFields: + * Sets a GnssMeasurementCallback, waits for a measurement, and verifies + * 1. basebandCN0DbHz is valid + */ +TEST_P(GnssHalTest, TestGnssMeasurementFields) { + const int kFirstGnssMeasurementTimeoutSeconds = 10; + + auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_1(); + ASSERT_TRUE(gnssMeasurement.isOk()); + + // Skip test if GnssMeasurement v2.1 is not supported + sp iGnssMeasurement = gnssMeasurement; + if (iGnssMeasurement == nullptr) { + return; + } + + sp callback = new GnssMeasurementCallback(); + auto result = iGnssMeasurement->setCallback_2_1(callback, /* enableFullTracking= */ true); + ASSERT_TRUE(result.isOk()); + EXPECT_EQ(result, IGnssMeasurement_1_0::GnssMeasurementStatus::SUCCESS); + + IGnssMeasurementCallback_2_1::GnssData lastMeasurement; + ASSERT_TRUE(callback->measurement_cbq_.retrieve(lastMeasurement, + kFirstGnssMeasurementTimeoutSeconds)); + EXPECT_EQ(callback->measurement_cbq_.calledCount(), 1); + ASSERT_TRUE(lastMeasurement.measurements.size() > 0); + for (auto measurement : lastMeasurement.measurements) { + // Verify basebandCn0DbHz is valid. + ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0); + } + + iGnssMeasurement->close(); +} + +/* + * TestGnssSvInfoFields: + * Gets 1 location and a GnssSvInfo, and verifies + * 1. basebandCN0DbHz is valid. + */ +TEST_P(GnssHalTest, TestGnssSvInfoFields) { + gnss_cb_->location_cbq_.reset(); + StartAndCheckFirstLocation(); + 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, 0); + ALOGD("Observed %d GnssSvStatus, while awaiting one location (%d received)", + sv_info_list_cbq_size, location_called_count); + + hidl_vec last_sv_info_list; + ASSERT_TRUE(gnss_cb_->sv_info_list_cbq_.retrieve(last_sv_info_list, 1)); + + bool nonZeroCn0Found = false; + for (auto sv_info : last_sv_info_list) { + ASSERT_TRUE(sv_info.basebandCN0DbHz >= 0.0 && sv_info.basebandCN0DbHz <= 65.0); + if (sv_info.basebandCN0DbHz > 0.0) { + nonZeroCn0Found = true; + } + } + // Assert at least one value is non-zero. Zero is ok in status as it's possibly + // reporting a searched but not found satellite. + ASSERT_TRUE(nonZeroCn0Found); + StopAndClearLocations(); +} diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp index 4ea97fac67..577f6ae5e3 100644 --- a/gnss/common/utils/default/Android.bp +++ b/gnss/common/utils/default/Android.bp @@ -28,6 +28,10 @@ cc_library_static { ], export_include_dirs: ["include"], shared_libs: [ + "libhidlbase", + "libutils", "android.hardware.gnss@1.0", + "android.hardware.gnss@2.0", + "android.hardware.gnss@2.1", ], } diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp index b9a06e8d6d..6c6d696f3d 100644 --- a/gnss/common/utils/default/Utils.cpp +++ b/gnss/common/utils/default/Utils.cpp @@ -16,6 +16,7 @@ #include #include +#include namespace android { namespace hardware { @@ -23,31 +24,188 @@ namespace gnss { namespace common { using GnssSvFlags = V1_0::IGnssCallback::GnssSvFlags; +using GnssMeasurementFlags = V1_0::IGnssMeasurementCallback::GnssMeasurementFlags; +using GnssMeasurementStateV2_0 = V2_0::IGnssMeasurementCallback::GnssMeasurementState; +using ElapsedRealtime = V2_0::ElapsedRealtime; +using ElapsedRealtimeFlags = V2_0::ElapsedRealtimeFlags; +using GnssConstellationTypeV2_0 = V2_0::GnssConstellationType; +using IGnssMeasurementCallbackV2_0 = V2_0::IGnssMeasurementCallback; -GnssLocation Utils::getMockLocation() { - GnssLocation location = {.gnssLocationFlags = 0xFF, - .latitudeDegrees = kMockLatitudeDegrees, - .longitudeDegrees = kMockLongitudeDegrees, - .altitudeMeters = kMockAltitudeMeters, - .speedMetersPerSec = kMockSpeedMetersPerSec, - .bearingDegrees = kMockBearingDegrees, - .horizontalAccuracyMeters = kMockHorizontalAccuracyMeters, - .verticalAccuracyMeters = kMockVerticalAccuracyMeters, - .speedAccuracyMetersPerSecond = kMockSpeedAccuracyMetersPerSecond, - .bearingAccuracyDegrees = kMockBearingAccuracyDegrees, - .timestamp = kMockTimestamp}; +GnssDataV2_1 Utils::getMockMeasurementV2_1() { + GnssDataV2_0 gnssDataV2_0 = Utils::getMockMeasurementV2_0(); + V2_1::IGnssMeasurementCallback::GnssMeasurement gnssMeasurementV2_1 = { + .v2_0 = gnssDataV2_0.measurements[0], + .basebandCN0DbHz = 25.0, + }; + hidl_vec measurements(1); + measurements[0] = gnssMeasurementV2_1; + GnssDataV2_1 gnssDataV2_1 = { + .measurements = measurements, + .clock = gnssDataV2_0.clock, + .elapsedRealtime = gnssDataV2_0.elapsedRealtime, + }; + return gnssDataV2_1; +} + +GnssDataV2_0 Utils::getMockMeasurementV2_0() { + V1_0::IGnssMeasurementCallback::GnssMeasurement measurement_1_0 = { + .flags = (uint32_t)GnssMeasurementFlags::HAS_CARRIER_FREQUENCY, + .svid = (int16_t)6, + .constellation = V1_0::GnssConstellationType::UNKNOWN, + .timeOffsetNs = 0.0, + .receivedSvTimeInNs = 8195997131077, + .receivedSvTimeUncertaintyInNs = 15, + .cN0DbHz = 30.0, + .pseudorangeRateMps = -484.13739013671875, + .pseudorangeRateUncertaintyMps = 1.0379999876022339, + .accumulatedDeltaRangeState = (uint32_t)V1_0::IGnssMeasurementCallback:: + GnssAccumulatedDeltaRangeState::ADR_STATE_UNKNOWN, + .accumulatedDeltaRangeM = 0.0, + .accumulatedDeltaRangeUncertaintyM = 0.0, + .carrierFrequencyHz = 1.59975e+09, + .multipathIndicator = + V1_0::IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_UNKNOWN}; + V1_1::IGnssMeasurementCallback::GnssMeasurement measurement_1_1 = {.v1_0 = measurement_1_0}; + V2_0::IGnssMeasurementCallback::GnssMeasurement measurement_2_0 = { + .v1_1 = measurement_1_1, + .codeType = "C", + .state = GnssMeasurementStateV2_0::STATE_CODE_LOCK | + GnssMeasurementStateV2_0::STATE_BIT_SYNC | + GnssMeasurementStateV2_0::STATE_SUBFRAME_SYNC | + GnssMeasurementStateV2_0::STATE_TOW_DECODED | + GnssMeasurementStateV2_0::STATE_GLO_STRING_SYNC | + GnssMeasurementStateV2_0::STATE_GLO_TOD_DECODED, + .constellation = GnssConstellationTypeV2_0::GLONASS, + }; + + hidl_vec measurements(1); + measurements[0] = measurement_2_0; + V1_0::IGnssMeasurementCallback::GnssClock clock = {.timeNs = 2713545000000, + .fullBiasNs = -1226701900521857520, + .biasNs = 0.59689998626708984, + .biasUncertaintyNs = 47514.989972114563, + .driftNsps = -51.757811607455452, + .driftUncertaintyNsps = 310.64968328491528, + .hwClockDiscontinuityCount = 1}; + + ElapsedRealtime timestamp = { + .flags = ElapsedRealtimeFlags::HAS_TIMESTAMP_NS | + ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS, + .timestampNs = static_cast(::android::elapsedRealtimeNano()), + // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks. + // In an actual implementation provide an estimate of the synchronization uncertainty + // or don't set the field. + .timeUncertaintyNs = 1000000}; + + GnssDataV2_0 gnssData = { + .measurements = measurements, .clock = clock, .elapsedRealtime = timestamp}; + return gnssData; +} + +V2_0::GnssLocation Utils::getMockLocationV2_0() { + const V2_0::ElapsedRealtime timestamp = { + .flags = V2_0::ElapsedRealtimeFlags::HAS_TIMESTAMP_NS | + V2_0::ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS, + .timestampNs = static_cast(::android::elapsedRealtimeNano()), + // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks. + // In an actual implementation provide an estimate of the synchronization uncertainty + // or don't set the field. + .timeUncertaintyNs = 1000000}; + + V2_0::GnssLocation location = {.v1_0 = Utils::getMockLocationV1_0(), + .elapsedRealtime = timestamp}; return location; } -GnssSvInfo Utils::getSvInfo(int16_t svid, GnssConstellationType type, float cN0DbHz, - float elevationDegrees, float azimuthDegrees) { - GnssSvInfo svInfo = {.svid = svid, - .constellation = type, - .cN0Dbhz = cN0DbHz, - .elevationDegrees = elevationDegrees, - .azimuthDegrees = azimuthDegrees, - .svFlag = GnssSvFlags::USED_IN_FIX | GnssSvFlags::HAS_EPHEMERIS_DATA | - GnssSvFlags::HAS_ALMANAC_DATA}; +V1_0::GnssLocation Utils::getMockLocationV1_0() { + V1_0::GnssLocation location = { + .gnssLocationFlags = 0xFF, + .latitudeDegrees = kMockLatitudeDegrees, + .longitudeDegrees = kMockLongitudeDegrees, + .altitudeMeters = kMockAltitudeMeters, + .speedMetersPerSec = kMockSpeedMetersPerSec, + .bearingDegrees = kMockBearingDegrees, + .horizontalAccuracyMeters = kMockHorizontalAccuracyMeters, + .verticalAccuracyMeters = kMockVerticalAccuracyMeters, + .speedAccuracyMetersPerSecond = kMockSpeedAccuracyMetersPerSecond, + .bearingAccuracyDegrees = kMockBearingAccuracyDegrees, + .timestamp = kMockTimestamp}; + return location; +} + +hidl_vec Utils::getMockSvInfoListV2_1() { + GnssSvInfoV1_0 gnssSvInfoV1_0 = + Utils::getMockSvInfoV1_0(3, V1_0::GnssConstellationType::GPS, 32.5, 59.1, 166.5); + GnssSvInfoV2_0 gnssSvInfoV2_0 = + Utils::getMockSvInfoV2_0(gnssSvInfoV1_0, V2_0::GnssConstellationType::GPS); + hidl_vec gnssSvInfoList = { + Utils::getMockSvInfoV2_1(gnssSvInfoV2_0, 27.5), + getMockSvInfoV2_1( + getMockSvInfoV2_0(getMockSvInfoV1_0(5, V1_0::GnssConstellationType::GPS, 27.0, + 29.0, 56.5), + V2_0::GnssConstellationType::GPS), + 22.0), + getMockSvInfoV2_1( + getMockSvInfoV2_0(getMockSvInfoV1_0(17, V1_0::GnssConstellationType::GPS, 30.5, + 71.0, 77.0), + V2_0::GnssConstellationType::GPS), + 25.5), + getMockSvInfoV2_1( + getMockSvInfoV2_0(getMockSvInfoV1_0(26, V1_0::GnssConstellationType::GPS, 24.1, + 28.0, 253.0), + V2_0::GnssConstellationType::GPS), + 19.1), + getMockSvInfoV2_1( + getMockSvInfoV2_0(getMockSvInfoV1_0(5, V1_0::GnssConstellationType::GLONASS, + 20.5, 11.5, 116.0), + V2_0::GnssConstellationType::GLONASS), + 15.5), + getMockSvInfoV2_1( + getMockSvInfoV2_0(getMockSvInfoV1_0(17, V1_0::GnssConstellationType::GLONASS, + 21.5, 28.5, 186.0), + V2_0::GnssConstellationType::GLONASS), + 16.5), + getMockSvInfoV2_1( + getMockSvInfoV2_0(getMockSvInfoV1_0(18, V1_0::GnssConstellationType::GLONASS, + 28.3, 38.8, 69.0), + V2_0::GnssConstellationType::GLONASS), + 25.3), + getMockSvInfoV2_1( + getMockSvInfoV2_0(getMockSvInfoV1_0(10, V1_0::GnssConstellationType::GLONASS, + 25.0, 66.0, 247.0), + V2_0::GnssConstellationType::GLONASS), + 20.0), + }; + return gnssSvInfoList; +} + +GnssSvInfoV2_1 Utils::getMockSvInfoV2_1(GnssSvInfoV2_0 gnssSvInfoV2_0, float basebandCN0DbHz) { + GnssSvInfoV2_1 gnssSvInfoV2_1 = { + .v2_0 = gnssSvInfoV2_0, + .basebandCN0DbHz = basebandCN0DbHz, + }; + return gnssSvInfoV2_1; +} + +GnssSvInfoV2_0 Utils::getMockSvInfoV2_0(GnssSvInfoV1_0 gnssSvInfoV1_0, + V2_0::GnssConstellationType type) { + GnssSvInfoV2_0 gnssSvInfoV2_0 = { + .v1_0 = gnssSvInfoV1_0, + .constellation = type, + }; + return gnssSvInfoV2_0; +} + +GnssSvInfoV1_0 Utils::getMockSvInfoV1_0(int16_t svid, V1_0::GnssConstellationType type, + float cN0DbHz, float elevationDegrees, + float azimuthDegrees) { + GnssSvInfoV1_0 svInfo = {.svid = svid, + .constellation = type, + .cN0Dbhz = cN0DbHz, + .elevationDegrees = elevationDegrees, + .azimuthDegrees = azimuthDegrees, + .svFlag = GnssSvFlags::USED_IN_FIX | GnssSvFlags::HAS_EPHEMERIS_DATA | + GnssSvFlags::HAS_ALMANAC_DATA}; return svInfo; } diff --git a/gnss/common/utils/default/include/Utils.h b/gnss/common/utils/default/include/Utils.h index 47c88129f3..e0c61a41e1 100644 --- a/gnss/common/utils/default/include/Utils.h +++ b/gnss/common/utils/default/include/Utils.h @@ -18,20 +18,34 @@ #define android_hardware_gnss_common_default_Utils_H_ #include +#include +#include -using GnssConstellationType = ::android::hardware::gnss::V1_0::GnssConstellationType; -using GnssLocation = ::android::hardware::gnss::V1_0::GnssLocation; -using GnssSvInfo = ::android::hardware::gnss::V1_0::IGnssCallback::GnssSvInfo; +using ::android::hardware::hidl_vec; namespace android { namespace hardware { namespace gnss { namespace common { +using GnssDataV2_0 = V2_0::IGnssMeasurementCallback::GnssData; +using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData; +using GnssSvInfoV1_0 = V1_0::IGnssCallback::GnssSvInfo; +using GnssSvInfoV2_0 = V2_0::IGnssCallback::GnssSvInfo; +using GnssSvInfoV2_1 = V2_1::IGnssCallback::GnssSvInfo; + struct Utils { - static GnssLocation getMockLocation(); - static GnssSvInfo getSvInfo(int16_t svid, GnssConstellationType type, float cN0DbHz, - float elevationDegrees, float azimuthDegrees); + static GnssDataV2_0 getMockMeasurementV2_0(); + static GnssDataV2_1 getMockMeasurementV2_1(); + static V2_0::GnssLocation getMockLocationV2_0(); + static V1_0::GnssLocation getMockLocationV1_0(); + static hidl_vec getMockSvInfoListV2_1(); + static GnssSvInfoV2_1 getMockSvInfoV2_1(GnssSvInfoV2_0 gnssSvInfoV2_0, float basebandCN0DbHz); + static GnssSvInfoV2_0 getMockSvInfoV2_0(GnssSvInfoV1_0 gnssSvInfoV1_0, + V2_0::GnssConstellationType type); + static GnssSvInfoV1_0 getMockSvInfoV1_0(int16_t svid, V1_0::GnssConstellationType type, + float cN0DbHz, float elevationDegrees, + float azimuthDegrees); }; } // namespace common From dbb5f9d74566f2aa859fb6ca46ad736b953dbdb3 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Tue, 3 Dec 2019 12:35:56 -0800 Subject: [PATCH 0298/1022] Update NGRAN bands Test: build Bug: 143683654 Change-Id: I7b59cd52dffdccc30b536a0bef9cab5ad977d371 --- current.txt | 2 +- radio/1.5/types.hal | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/current.txt b/current.txt index 5847f71162..706dae802a 100644 --- a/current.txt +++ b/current.txt @@ -613,7 +613,7 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar 619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types -521d1fe5b9f212b7b37ab71c0d33f5d2622618837e318e99a80d882f186af6b9 android.hardware.radio@1.5::types +35cd6586225912718c599421606d69260707e43732d874f2064e28de45c87fac android.hardware.radio@1.5::types 3f1e2410d9bed4e7d41c6a589fe3a7943bc904b0066e40e0199a7c58427ac4e9 android.hardware.radio@1.5::IRadio 3afac66f21a33bc9c4b80481c7d5540038348651d9a7d8af64ea13610af138da android.hardware.radio@1.5::IRadioIndication caf00e0d942b77b17d7061b38de11e5b19e1da90d4818434cb4916ba89e30686 android.hardware.radio@1.5::IRadioResponse diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index 068f56b252..664ddc441b 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -158,7 +158,7 @@ struct RadioAccessSpecifier { }; enum NgranBands : int32_t { - /** 3GPP TS 28.101-1, Table 5.2-1: FR1 bands */ + /** 3GPP TS 38.101-1, Table 5.2-1: FR1 bands */ BAND_1 = 1, BAND_2 = 2, BAND_3 = 3, @@ -166,16 +166,22 @@ enum NgranBands : int32_t { BAND_7 = 7, BAND_8 = 8, BAND_12 = 12, + BAND_14 = 14, + BAND_18 = 18, BAND_20 = 20, BAND_25 = 25, BAND_28 = 28, + BAND_29 = 29, + BAND_30 = 30, BAND_34 = 34, BAND_38 = 38, BAND_39 = 39, BAND_40 = 40, BAND_41 = 41, + BAND_48 = 48, BAND_50 = 50, BAND_51 = 51, + BAND_65 = 65, BAND_66 = 66, BAND_70 = 70, BAND_71 = 71, @@ -191,7 +197,8 @@ enum NgranBands : int32_t { BAND_83 = 83, BAND_84 = 84, BAND_86 = 86, - /** 3GPP TS 28.101-2, Table 5.2-1: FR2 bands */ + BAND_90 = 90, + /** 3GPP TS 38.101-2, Table 5.2-1: FR2 bands */ BAND_257 = 257, BAND_258 = 258, BAND_260 = 260, From 88d63ccbd75f63645161762eca30688fd9c70cc3 Mon Sep 17 00:00:00 2001 From: Kathan Shukla Date: Wed, 4 Dec 2019 15:51:14 -0800 Subject: [PATCH 0299/1022] Fix spelling of presence in Occupant Awareness. Test: Build test Change-Id: I1961c54cafd343acd75fac04535e952000dbdb99 --- .../automotive/occupant_awareness/IOccupantAwareness.aidl | 2 +- .../occupant_awareness/aidl/default/OccupantAwareness.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl index 86d9e2f206..1df0bda469 100644 --- a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl +++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl @@ -30,7 +30,7 @@ interface IOccupantAwareness { /* * System is able to detect the presence of humans. */ - const int CAP_PRESENSE_DETECTION = 1 << 0; + const int CAP_PRESENCE_DETECTION = 1 << 0; /* * System is able to detect the gaze of humans. */ diff --git a/automotive/occupant_awareness/aidl/default/OccupantAwareness.cpp b/automotive/occupant_awareness/aidl/default/OccupantAwareness.cpp index ef5055f599..a156075c09 100644 --- a/automotive/occupant_awareness/aidl/default/OccupantAwareness.cpp +++ b/automotive/occupant_awareness/aidl/default/OccupantAwareness.cpp @@ -25,7 +25,7 @@ namespace implementation { using ndk::ScopedAStatus; -static const int32_t kAllCapabilities = OccupantAwareness::CAP_PRESENSE_DETECTION | +static const int32_t kAllCapabilities = OccupantAwareness::CAP_PRESENCE_DETECTION | OccupantAwareness::CAP_GAZE_DETECTION | OccupantAwareness::CAP_DRIVER_MONITORING_DETECTION; From fd809fcdfce151d5f948198c88ed35fbcf99c8df Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Fri, 15 Nov 2019 18:19:15 -0800 Subject: [PATCH 0300/1022] Wifi: Add 6GHz bands to WifiBand This commit adds 6GHz band to WifiBand and update the impacted structures and methods in Wifi HAL. Note that Background scar related HAL API will not be using the new band, and will continue with the legacy set of bands. Bug: 139354972 Test: Manual Test: VTS test Test: Unit test: ./hardware/interfaces/wifi/1.4/default/tests/runtests.sh Change-Id: I54662251034806338ad64d4622ade259ca260a79 --- wifi/1.4/Android.bp | 1 + wifi/1.4/IWifiChip.hal | 17 +++ wifi/1.4/IWifiChipEventCallback.hal | 65 +++++++++ wifi/1.4/default/hidl_struct_util.cpp | 36 +++-- wifi/1.4/default/hidl_struct_util.h | 7 +- .../tests/hidl_struct_util_unit_tests.cpp | 28 ++-- wifi/1.4/default/wifi_ap_iface.cpp | 4 +- wifi/1.4/default/wifi_ap_iface.h | 5 +- wifi/1.4/default/wifi_chip.cpp | 32 +++-- wifi/1.4/default/wifi_chip.h | 10 +- wifi/1.4/default/wifi_sta_iface.cpp | 4 +- wifi/1.4/default/wifi_sta_iface.h | 5 +- wifi/1.4/types.hal | 23 +++ wifi/1.4/vts/functional/Android.bp | 1 + .../vts/functional/wifi_chip_hidl_test.cpp | 135 ++++++++++++++++++ 15 files changed, 320 insertions(+), 53 deletions(-) create mode 100644 wifi/1.4/IWifiChipEventCallback.hal create mode 100644 wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp diff --git a/wifi/1.4/Android.bp b/wifi/1.4/Android.bp index 5750e426ad..e63b1ebaed 100644 --- a/wifi/1.4/Android.bp +++ b/wifi/1.4/Android.bp @@ -11,6 +11,7 @@ hidl_interface { "IWifi.hal", "IWifiApIface.hal", "IWifiChip.hal", + "IWifiChipEventCallback.hal", "IWifiRttController.hal", "IWifiRttControllerEventCallback.hal", "IWifiStaIface.hal", diff --git a/wifi/1.4/IWifiChip.hal b/wifi/1.4/IWifiChip.hal index d269427a6d..de5a64e1b9 100644 --- a/wifi/1.4/IWifiChip.hal +++ b/wifi/1.4/IWifiChip.hal @@ -19,12 +19,29 @@ package android.hardware.wifi@1.4; import @1.0::WifiStatus; import @1.0::IWifiIface; import @1.3::IWifiChip; +import IWifiChipEventCallback; import IWifiRttController; /** * Interface that represents a chip that must be configured as a single unit. */ interface IWifiChip extends @1.3::IWifiChip { + /** + * Requests notifications of significant events on this chip. Multiple calls + * to this must register multiple callbacks each of which must receive all + * events. + * + * @param callback An instance of the |IWifiChipEventCallback| HIDL interface + * object. + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_NOT_SUPPORTED|, + * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID| + */ + registerEventCallback_1_4(IWifiChipEventCallback callback) + generates (WifiStatus status); + /** * Create a RTTController instance. * diff --git a/wifi/1.4/IWifiChipEventCallback.hal b/wifi/1.4/IWifiChipEventCallback.hal new file mode 100644 index 0000000000..ecd0a44b6f --- /dev/null +++ b/wifi/1.4/IWifiChipEventCallback.hal @@ -0,0 +1,65 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi@1.4; + +import @1.2::IWifiChipEventCallback; +import WifiBand; + +/** + * Wifi chip event callbacks. + */ +interface IWifiChipEventCallback extends @1.2::IWifiChipEventCallback { + /** + * Struct describing the state of each hardware radio chain (hardware MAC) + * on the device. + */ + struct RadioModeInfo { + /** + * Identifier for this radio chain. This is vendor dependent & used + * only for debugging purposes. + */ + uint32_t radioId; + /** + * List of bands on which this radio chain is operating. + * Can be one of: + * a) WifiBand.BAND_24GHZ => 2.4Ghz. + * b) WifiBand.BAND_5GHZ => 5Ghz. + * c) WifiBand.BAND_24GHZ_5GHZ = 2.4Ghz + 5Ghz (Radio is time sharing + * across the 2 bands). + * d) WifiBand.BAND_6GHZ => 6Ghz. + * e) WifiBand.BAND_5GHZ_6GHZ => 5Ghz + 6Ghz (Radio is time sharing + * across the 2 bands). + * f) WifiBand.BAND_24GHZ_5GHZ_6GHZ => 2.4Ghz + 5Ghz + 6Ghz (Radio is + * time sharing across the 3 bands). + */ + WifiBand bandInfo; + /** List of interfaces on this radio chain (hardware MAC). */ + vec ifaceInfos; + }; + + /** + * Asynchronous callback indicating a radio mode change. + * Radio mode change could be a result of: + * a) Bringing up concurrent interfaces (For ex: STA + AP). + * b) Change in operating band of one of the concurrent interfaces (For ex: + * STA connection moved from 2.4G to 5G) + * + * @param radioModeInfos List of RadioModeInfo structures for each + * radio chain (hardware MAC) on the device. + */ + oneway onRadioModeChange_1_4(vec radioModeInfos); +}; diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp index 6eeb6422e5..35c683984d 100644 --- a/wifi/1.4/default/hidl_struct_util.cpp +++ b/wifi/1.4/default/hidl_struct_util.cpp @@ -316,7 +316,7 @@ legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy( bool convertLegacyWifiMacInfoToHidl( const legacy_hal::WifiMacInfo& legacy_mac_info, - V1_2::IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) { + IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) { if (!hidl_radio_mode_info) { return false; } @@ -325,8 +325,17 @@ bool convertLegacyWifiMacInfoToHidl( hidl_radio_mode_info->radioId = legacy_mac_info.wlan_mac_id; // Convert from bitmask of bands in the legacy HAL to enum value in // the HIDL interface. - if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND && - legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) { + if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND && + legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND && + legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) { + hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ_6GHZ; + } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND && + legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) { + hidl_radio_mode_info->bandInfo = WifiBand::BAND_5GHZ_6GHZ; + } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND) { + hidl_radio_mode_info->bandInfo = WifiBand::BAND_6GHZ; + } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND && + legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) { hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ; } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) { hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ; @@ -348,15 +357,14 @@ bool convertLegacyWifiMacInfoToHidl( bool convertLegacyWifiMacInfosToHidl( const std::vector& legacy_mac_infos, - std::vector* - hidl_radio_mode_infos) { + std::vector* hidl_radio_mode_infos) { if (!hidl_radio_mode_infos) { return false; } *hidl_radio_mode_infos = {}; for (const auto& legacy_mac_info : legacy_mac_infos) { - V1_2::IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info; + IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info; if (!convertLegacyWifiMacInfoToHidl(legacy_mac_info, &hidl_radio_mode_info)) { return false; @@ -449,21 +457,21 @@ bool convertLegacyGscanCapabilitiesToHidl( return true; } -legacy_hal::wifi_band convertHidlWifiBandToLegacy(WifiBand band) { +legacy_hal::wifi_band convertHidlWifiBandToLegacy(V1_0::WifiBand band) { switch (band) { - case WifiBand::BAND_UNSPECIFIED: + case V1_0::WifiBand::BAND_UNSPECIFIED: return legacy_hal::WIFI_BAND_UNSPECIFIED; - case WifiBand::BAND_24GHZ: + case V1_0::WifiBand::BAND_24GHZ: return legacy_hal::WIFI_BAND_BG; - case WifiBand::BAND_5GHZ: + case V1_0::WifiBand::BAND_5GHZ: return legacy_hal::WIFI_BAND_A; - case WifiBand::BAND_5GHZ_DFS: + case V1_0::WifiBand::BAND_5GHZ_DFS: return legacy_hal::WIFI_BAND_A_DFS; - case WifiBand::BAND_5GHZ_WITH_DFS: + case V1_0::WifiBand::BAND_5GHZ_WITH_DFS: return legacy_hal::WIFI_BAND_A_WITH_DFS; - case WifiBand::BAND_24GHZ_5GHZ: + case V1_0::WifiBand::BAND_24GHZ_5GHZ: return legacy_hal::WIFI_BAND_ABG; - case WifiBand::BAND_24GHZ_5GHZ_WITH_DFS: + case V1_0::WifiBand::BAND_24GHZ_5GHZ_WITH_DFS: return legacy_hal::WIFI_BAND_ABG_WITH_DFS; }; CHECK(false); diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h index cfaa4adccc..987891b5b2 100644 --- a/wifi/1.4/default/hidl_struct_util.h +++ b/wifi/1.4/default/hidl_struct_util.h @@ -21,10 +21,10 @@ #include #include -#include #include #include #include +#include #include #include @@ -65,8 +65,7 @@ legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2( V1_2::IWifiChip::TxPowerScenario hidl_scenario); bool convertLegacyWifiMacInfosToHidl( const std::vector& legacy_mac_infos, - std::vector* - hidl_radio_mode_infos); + std::vector* hidl_radio_mode_infos); // STA iface conversion methods. bool convertLegacyFeaturesToHidlStaCapabilities( @@ -78,7 +77,7 @@ bool convertLegacyApfCapabilitiesToHidl( bool convertLegacyGscanCapabilitiesToHidl( const legacy_hal::wifi_gscan_capabilities& legacy_caps, StaBackgroundScanCapabilities* hidl_caps); -legacy_hal::wifi_band convertHidlWifiBandToLegacy(WifiBand band); +legacy_hal::wifi_band convertHidlWifiBandToLegacy(V1_0::WifiBand band); bool convertHidlGscanParamsToLegacy( const StaBackgroundScanParameters& hidl_scan_params, legacy_hal::wifi_scan_cmd_params* legacy_scan_params); diff --git a/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp index 14a15048fe..b71d549d9c 100644 --- a/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp +++ b/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp @@ -55,8 +55,7 @@ TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithOneMac) { legacy_mac_info1.iface_infos.push_back(legacy_iface_info2); legacy_mac_infos.push_back(legacy_mac_info1); - std::vector - hidl_radio_mode_infos; + std::vector hidl_radio_mode_infos; ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl( legacy_mac_infos, &hidl_radio_mode_infos)); @@ -90,20 +89,18 @@ TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithTwoMac) { legacy_mac_info2.iface_infos.push_back(legacy_iface_info2); legacy_mac_infos.push_back(legacy_mac_info2); - std::vector - hidl_radio_mode_infos; + std::vector hidl_radio_mode_infos; ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl( legacy_mac_infos, &hidl_radio_mode_infos)); ASSERT_EQ(2u, hidl_radio_mode_infos.size()); // Find mac info 1. - const auto hidl_radio_mode_info1 = - std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(), - [&legacy_mac_info1]( - const V1_2::IWifiChipEventCallback::RadioModeInfo& x) { - return x.radioId == legacy_mac_info1.wlan_mac_id; - }); + const auto hidl_radio_mode_info1 = std::find_if( + hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(), + [&legacy_mac_info1](const IWifiChipEventCallback::RadioModeInfo& x) { + return x.radioId == legacy_mac_info1.wlan_mac_id; + }); ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info1); EXPECT_EQ(WifiBand::BAND_5GHZ, hidl_radio_mode_info1->bandInfo); ASSERT_EQ(1u, hidl_radio_mode_info1->ifaceInfos.size()); @@ -113,12 +110,11 @@ TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithTwoMac) { hidl_iface_info1.channel); // Find mac info 2. - const auto hidl_radio_mode_info2 = - std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(), - [&legacy_mac_info2]( - const V1_2::IWifiChipEventCallback::RadioModeInfo& x) { - return x.radioId == legacy_mac_info2.wlan_mac_id; - }); + const auto hidl_radio_mode_info2 = std::find_if( + hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(), + [&legacy_mac_info2](const IWifiChipEventCallback::RadioModeInfo& x) { + return x.radioId == legacy_mac_info2.wlan_mac_id; + }); ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info2); EXPECT_EQ(WifiBand::BAND_24GHZ, hidl_radio_mode_info2->bandInfo); ASSERT_EQ(1u, hidl_radio_mode_info2->ifaceInfos.size()); diff --git a/wifi/1.4/default/wifi_ap_iface.cpp b/wifi/1.4/default/wifi_ap_iface.cpp index e677f197b8..8777a4cb9c 100644 --- a/wifi/1.4/default/wifi_ap_iface.cpp +++ b/wifi/1.4/default/wifi_ap_iface.cpp @@ -64,7 +64,7 @@ Return WifiApIface::setCountryCode(const hidl_array& code, } Return WifiApIface::getValidFrequenciesForBand( - WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) { + V1_0::WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, &WifiApIface::getValidFrequenciesForBandInternal, hidl_status_cb, band); @@ -100,7 +100,7 @@ WifiStatus WifiApIface::setCountryCodeInternal( } std::pair> -WifiApIface::getValidFrequenciesForBandInternal(WifiBand band) { +WifiApIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) { static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t), "Size mismatch"); legacy_hal::wifi_error legacy_status; diff --git a/wifi/1.4/default/wifi_ap_iface.h b/wifi/1.4/default/wifi_ap_iface.h index 4f3438c298..bf16d5eb85 100644 --- a/wifi/1.4/default/wifi_ap_iface.h +++ b/wifi/1.4/default/wifi_ap_iface.h @@ -49,7 +49,8 @@ class WifiApIface : public V1_4::IWifiApIface { Return setCountryCode(const hidl_array& code, setCountryCode_cb hidl_status_cb) override; Return getValidFrequenciesForBand( - WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) override; + V1_0::WifiBand band, + getValidFrequenciesForBand_cb hidl_status_cb) override; Return setMacAddress(const hidl_array& mac, setMacAddress_cb hidl_status_cb) override; Return getFactoryMacAddress( @@ -61,7 +62,7 @@ class WifiApIface : public V1_4::IWifiApIface { std::pair getTypeInternal(); WifiStatus setCountryCodeInternal(const std::array& code); std::pair> - getValidFrequenciesForBandInternal(WifiBand band); + getValidFrequenciesForBandInternal(V1_0::WifiBand band); WifiStatus setMacAddressInternal(const std::array& mac); std::pair> getFactoryMacAddressInternal(); diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp index 40f73b532a..2b015d3115 100644 --- a/wifi/1.4/default/wifi_chip.cpp +++ b/wifi/1.4/default/wifi_chip.cpp @@ -341,7 +341,7 @@ void WifiChip::invalidate() { bool WifiChip::isValid() { return is_valid_; } -std::set> WifiChip::getEventCallbacks() { +std::set> WifiChip::getEventCallbacks() { return event_cb_handler_.getCallbacks(); } @@ -628,6 +628,14 @@ Return WifiChip::createRttController_1_4( hidl_status_cb, bound_iface); } +Return WifiChip::registerEventCallback_1_4( + const sp& event_callback, + registerEventCallback_cb hidl_status_cb) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::registerEventCallbackInternal_1_4, + hidl_status_cb, event_callback); +} + void WifiChip::invalidateAndRemoveAllIfaces() { invalidateAndClearAll(ap_ifaces_); invalidateAndClearAll(nan_ifaces_); @@ -1125,11 +1133,9 @@ WifiStatus WifiChip::setLatencyModeInternal(LatencyMode mode) { } WifiStatus WifiChip::registerEventCallbackInternal_1_2( - const sp& event_callback) { - if (!event_cb_handler_.addCallback(event_callback)) { - return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); - } - return createWifiStatus(WifiStatusCode::SUCCESS); + const sp& /* event_callback */) { + // Deprecated support for this callback. + return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED); } WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2( @@ -1179,6 +1185,14 @@ WifiChip::createRttControllerInternal_1_4(const sp& bound_iface) { return {createWifiStatus(WifiStatusCode::SUCCESS), rtt}; } +WifiStatus WifiChip::registerEventCallbackInternal_1_4( + const sp& event_callback) { + if (!event_cb_handler_.addCallback(event_callback)) { + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } + return createWifiStatus(WifiStatusCode::SUCCESS); +} + WifiStatus WifiChip::handleChipConfiguration( /* NONNULL */ std::unique_lock* lock, ChipModeId mode_id) { @@ -1281,7 +1295,7 @@ WifiStatus WifiChip::registerRadioModeChangeCallback() { LOG(ERROR) << "Callback invoked on an invalid object"; return; } - std::vector + std::vector hidl_radio_mode_infos; if (!hidl_struct_util::convertLegacyWifiMacInfosToHidl( mac_infos, &hidl_radio_mode_infos)) { @@ -1289,9 +1303,9 @@ WifiStatus WifiChip::registerRadioModeChangeCallback() { return; } for (const auto& callback : shared_ptr_this->getEventCallbacks()) { - if (!callback->onRadioModeChange(hidl_radio_mode_infos) + if (!callback->onRadioModeChange_1_4(hidl_radio_mode_infos) .isOk()) { - LOG(ERROR) << "Failed to invoke onRadioModeChange" + LOG(ERROR) << "Failed to invoke onRadioModeChange_1_4" << " callback on: " << toString(callback); } } diff --git a/wifi/1.4/default/wifi_chip.h b/wifi/1.4/default/wifi_chip.h index 3bf18475ae..c76eabf18e 100644 --- a/wifi/1.4/default/wifi_chip.h +++ b/wifi/1.4/default/wifi_chip.h @@ -71,7 +71,7 @@ class WifiChip : public V1_4::IWifiChip { // marked valid before processing them. void invalidate(); bool isValid(); - std::set> getEventCallbacks(); + std::set> getEventCallbacks(); // HIDL methods exposed. Return getId(getId_cb hidl_status_cb) override; @@ -156,6 +156,9 @@ class WifiChip : public V1_4::IWifiChip { Return createRttController_1_4( const sp& bound_iface, createRttController_1_4_cb hidl_status_cb) override; + Return registerEventCallback_1_4( + const sp& event_callback, + registerEventCallback_1_4_cb hidl_status_cb) override; private: void invalidateAndRemoveAllIfaces(); @@ -223,6 +226,9 @@ class WifiChip : public V1_4::IWifiChip { std::pair getCapabilitiesInternal_1_3(); std::pair> createRttControllerInternal_1_4(const sp& bound_iface); + WifiStatus registerEventCallbackInternal_1_4( + const sp& event_callback); + WifiStatus handleChipConfiguration( std::unique_lock* lock, ChipModeId mode_id); WifiStatus registerDebugRingBufferCallback(); @@ -271,7 +277,7 @@ class WifiChip : public V1_4::IWifiChip { // registration mechanism. Use this to check if we have already // registered a callback. bool debug_ring_buffer_cb_registered_; - hidl_callback_util::HidlCallbackHandler + hidl_callback_util::HidlCallbackHandler event_cb_handler_; DISALLOW_COPY_AND_ASSIGN(WifiChip); diff --git a/wifi/1.4/default/wifi_sta_iface.cpp b/wifi/1.4/default/wifi_sta_iface.cpp index 8e1ada1032..68c989d6a6 100644 --- a/wifi/1.4/default/wifi_sta_iface.cpp +++ b/wifi/1.4/default/wifi_sta_iface.cpp @@ -113,7 +113,7 @@ Return WifiStaIface::getBackgroundScanCapabilities( } Return WifiStaIface::getValidFrequenciesForBand( - WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) { + V1_0::WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, &WifiStaIface::getValidFrequenciesForBandInternal, hidl_status_cb, band); @@ -344,7 +344,7 @@ WifiStaIface::getBackgroundScanCapabilitiesInternal() { } std::pair> -WifiStaIface::getValidFrequenciesForBandInternal(WifiBand band) { +WifiStaIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) { static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t), "Size mismatch"); legacy_hal::wifi_error legacy_status; diff --git a/wifi/1.4/default/wifi_sta_iface.h b/wifi/1.4/default/wifi_sta_iface.h index ccf234f98e..e85e39d310 100644 --- a/wifi/1.4/default/wifi_sta_iface.h +++ b/wifi/1.4/default/wifi_sta_iface.h @@ -63,7 +63,8 @@ class WifiStaIface : public V1_4::IWifiStaIface { Return getBackgroundScanCapabilities( getBackgroundScanCapabilities_cb hidl_status_cb) override; Return getValidFrequenciesForBand( - WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) override; + V1_0::WifiBand band, + getValidFrequenciesForBand_cb hidl_status_cb) override; Return startBackgroundScan( uint32_t cmd_id, const StaBackgroundScanParameters& params, startBackgroundScan_cb hidl_status_cb) override; @@ -130,7 +131,7 @@ class WifiStaIface : public V1_4::IWifiStaIface { std::pair getBackgroundScanCapabilitiesInternal(); std::pair> - getValidFrequenciesForBandInternal(WifiBand band); + getValidFrequenciesForBandInternal(V1_0::WifiBand band); WifiStatus startBackgroundScanInternal( uint32_t cmd_id, const StaBackgroundScanParameters& params); WifiStatus stopBackgroundScanInternal(uint32_t cmd_id); diff --git a/wifi/1.4/types.hal b/wifi/1.4/types.hal index 232e26ff80..0db0c2c224 100644 --- a/wifi/1.4/types.hal +++ b/wifi/1.4/types.hal @@ -26,12 +26,35 @@ import @1.0::RttStatus; import @1.0::RttType; import @1.0::TimeSpanInPs; import @1.0::TimeStampInUs; +import @1.0::WifiBand; import @1.0::WifiChannelInfo; import @1.0::WifiChannelWidthInMhz; import @1.0::WifiInformationElement; import @1.0::WifiRateNss; import @1.0::WifiRatePreamble; +/** + * Wifi bands defined in 80211 spec. + */ +enum WifiBand : @1.0::WifiBand { + /** + * 6 GHz. + */ + BAND_6GHZ = 8, + /** + * 5 GHz no DFS + 6 GHz. + */ + BAND_5GHZ_6GHZ = 10, + /** + * 2.4 GHz + 5 GHz no DFS + 6 GHz. + */ + BAND_24GHZ_5GHZ_6GHZ = 11, + /** + * 2.4 GHz + 5 GHz with DFS + 6 GHz. + */ + BAND_24GHZ_5GHZ_WITH_DFS_6GHZ = 15 +}; + /** * Wifi Rate Preamble */ diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp index c71b319acf..f3be25db55 100644 --- a/wifi/1.4/vts/functional/Android.bp +++ b/wifi/1.4/vts/functional/Android.bp @@ -21,6 +21,7 @@ cc_test { srcs: [ "VtsHalWifiV1_4TargetTest.cpp", "wifi_ap_iface_hidl_test.cpp", + "wifi_chip_hidl_test.cpp" ], static_libs: [ "VtsHalWifiV1_0TargetTestUtil", diff --git a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp new file mode 100644 index 0000000000..8ca5214fc5 --- /dev/null +++ b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp @@ -0,0 +1,135 @@ +/* + * 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. + */ + +#include +#include + +#undef NAN // NAN is defined in bionic/libc/include/math.h:38 + +#include +#include +#include +#include +#include +#include + +#include "wifi_hidl_call_util.h" +#include "wifi_hidl_test_utils.h" + +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::wifi::V1_0::IfaceType; +using ::android::hardware::wifi::V1_0::WifiDebugRingBufferStatus; +using ::android::hardware::wifi::V1_0::WifiStatus; +using ::android::hardware::wifi::V1_0::WifiStatusCode; +using ::android::hardware::wifi::V1_4::IWifiChip; +using ::android::hardware::wifi::V1_4::IWifiChipEventCallback; + +/** + * Fixture to use for all Wifi chip HIDL interface tests. + */ +class WifiChipHidlTest : public ::testing::TestWithParam { + public: + virtual void SetUp() override { + wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName())); + ASSERT_NE(nullptr, wifi_chip_.get()); + } + + virtual void TearDown() override { stopWifi(GetInstanceName()); } + + // A simple test implementation of WifiChipEventCallback. + class WifiChipEventCallback + : public ::testing::VtsHalHidlTargetCallbackBase, + public IWifiChipEventCallback { + public: + WifiChipEventCallback(){}; + + virtual ~WifiChipEventCallback() = default; + + Return onChipReconfigured(uint32_t modeId __unused) { + return Void(); + }; + + Return onChipReconfigureFailure( + const WifiStatus& status __unused) { + return Void(); + }; + + Return onIfaceAdded(IfaceType type __unused, + const hidl_string& name __unused) { + return Void(); + }; + + Return onIfaceRemoved(IfaceType type __unused, + const hidl_string& name __unused) { + return Void(); + }; + + Return onDebugRingBufferDataAvailable( + const WifiDebugRingBufferStatus& status __unused, + const hidl_vec& data __unused) { + return Void(); + }; + + Return onDebugErrorAlert(int32_t errorCode __unused, + const hidl_vec& debugData + __unused) { + return Void(); + }; + + Return onRadioModeChange( + const hidl_vec<::android::hardware::wifi::V1_2:: + IWifiChipEventCallback::RadioModeInfo>& + radioModeInfos __unused) { + return Void(); + }; + + Return onRadioModeChange_1_4( + const hidl_vec& radioModeInfos __unused) { + return Void(); + }; + }; + + protected: + sp wifi_chip_; + + private: + std::string GetInstanceName() { return GetParam(); } +}; + +/* + * registerEventCallback_1_4 + * This test case tests the registerEventCallback_1_4() API which registers + * a call back function with the hal implementation + * + * Note: it is not feasible to test the invocation of the call back function + * since event is triggered internally in the HAL implementation, and can not be + * triggered from the test case + */ +TEST_P(WifiChipHidlTest, registerEventCallback_1_4) { + sp wifiChipEventCallback = + new WifiChipEventCallback(); + const auto& status = HIDL_INVOKE(wifi_chip_, registerEventCallback_1_4, + wifiChipEventCallback); + + if (status.code != WifiStatusCode::SUCCESS) { + EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code); + return; + } +} From 2bd0b3339cc278ed283dc10aa0daf438b5540ad9 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Thu, 5 Dec 2019 16:57:30 +0000 Subject: [PATCH 0301/1022] Add TENSOR_QUANT8_ASYMM_SIGNED support for DEQUANTIZE Add TENSOR_QUANT8_ASYMM_SIGNED to the list of exceptions when mutating DEQUANTIZE for validation. Bug: 143934768 Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: I1b3b0a362d3949d4e31708388100d4794846ca3a --- neuralnetworks/1.3/vts/functional/ValidateModel.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 242e12ecc7..6c618b30dd 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -323,8 +323,8 @@ static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, con // - CAST's argument can be any of TENSOR_(FLOAT16|FLOAT32|INT32|QUANT8_ASYMM). // - RANDOM_MULTINOMIAL's argument can be either TENSOR_FLOAT16 or TENSOR_FLOAT32. // - DEQUANTIZE input can be any of - // TENSOR_(QUANT8_ASYMM|QUANT8_SYMM|QUANT8_SYMM_PER_CHANNEL), output can - // be of either TENSOR_FLOAT16 or TENSOR_FLOAT32. + // TENSOR_(QUANT8_ASYMM|QUANT8_ASYMM_SIGNED|QUANT8_SYMM|QUANT8_SYMM_PER_CHANNEL), + // output can be of either TENSOR_FLOAT16 or TENSOR_FLOAT32. // - QUANTIZE input can be either TENSOR_FLOAT16 or TENSOR_FLOAT32 // - CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL // - DEPTHWISE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL @@ -364,6 +364,7 @@ static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, con case OperationType::DEQUANTIZE: { if (operand == operation.inputs[0] && (type == OperandType::TENSOR_QUANT8_ASYMM || + type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED || type == OperandType::TENSOR_QUANT8_SYMM || type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL)) { return true; From 479ee3380104bf5989f57d8f054faa2b3724a8b8 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Thu, 5 Dec 2019 11:03:09 -0800 Subject: [PATCH 0302/1022] Add Audio HAL V6 hashes to current.txt Done using the following command: hidl-gen -L hash -r android.hardware:hardware/interfaces \ -r android.hidl:system/libhidl/transport \ android.hardware.audio@6.0 \ android.hardware.audio.common@6.0 \ android.hardware.audio.effect@6.0 Bug: 138747770 Test: N/A Change-Id: I9cbd5c2358a663ec346d8624d0e6a12c643147e3 --- current.txt | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/current.txt b/current.txt index 6d1e6c645e..37e0640bef 100644 --- a/current.txt +++ b/current.txt @@ -585,6 +585,30 @@ a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardwar fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface # HALs released in Android R +e966a3437d6a98d9d9e14e9d672088771716031900c0deb55a0946c751a03a44 android.hardware.audio@6.0::types +2736c59abaccacac407ebe80c5e48d446edf015051d05632fb679ba471779e6e android.hardware.audio@6.0::IDevice +2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory +bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice +7318b521ea12fdd4b6e3f381085c71784c810d1ec7a8d701ec2250f3f86712e4 android.hardware.audio@6.0::IStream +2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn +78e4138cc8307c11fc777c3bd376e581ba4ba48196b05ca1d7cdfa515c87b48a android.hardware.audio@6.0::IStreamOut +997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback +7cc6bedbecf4c1a348c99d3f69e409ff815b90a5abf0781b054e99567fcb5c8e android.hardware.audio.common@6.0::types +817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types +525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect +8d76bbe3719d051a8e9a1dcf9244f37f5b0a491feb249fa48391edf7cb4f3131 android.hardware.audio.effect@6.0::IAutomaticGainControlEffect +461b1114cb35d89f87e5694e0792ba53c112a7fa9a14d9b95188cf9c4764be23 android.hardware.audio.effect@6.0::IBassBoostEffect +8bc597d166e07e9eba633267fc2872c4c53d13d3f0025b778c98e13324a165de android.hardware.audio.effect@6.0::IDownmixEffect +9ee022c81e79da6051fde0836c1c1c4d5414e0c9a6cccc0ce17a90346ceb1391 android.hardware.audio.effect@6.0::IEffect +75c99a70577d543359910a0b378bcbf5a0d6076712e58e6864cd8803f76c8684 android.hardware.audio.effect@6.0::IEffectBufferProviderCallback +5910bdd600fc6501a67233a9a3f4f21dda86af08c05497322712600131d1fa8f android.hardware.audio.effect@6.0::IEffectsFactory +dd377f404a8e71f6191d295e10067db629b0f0c28e594af906f2bea5d87fe2cc android.hardware.audio.effect@6.0::IEnvironmentalReverbEffect +455e085e136767302ec34d02b51a085c310e79bf500b76dda7c96a7f3637f11a android.hardware.audio.effect@6.0::IEqualizerEffect +24b5e107a0cbd2b322f764a4d5f7fb8b5d8c337a060b9a4a26b9af050c57b5d0 android.hardware.audio.effect@6.0::ILoudnessEnhancerEffect +4aae0a13f53a8ce20fad372de2d1d864a0bae194b0f1b1d2c090367af8615af2 android.hardware.audio.effect@6.0::INoiseSuppressionEffect +5237c42d3913ef569f07bec802568084b615155d05a7951e75085da54856508c android.hardware.audio.effect@6.0::IPresetReverbEffect +282193799d60bff27a84c65a36218c1e7d8f582f5828e2e059383d1b90aa56bd android.hardware.audio.effect@6.0::IVirtualizerEffect +0868e00f7c5ee16723bda1a8f57099763d04100ae7126a1c2d3a9a87c844a7e8 android.hardware.audio.effect@6.0::IVisualizerEffect 79e115c8f8970b8b914bafc66df5425e065fda4dcda97222966ef12451d2a1cc android.hardware.bluetooth@1.1::IBluetoothHci 40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl From 56c98e4cf1af7472e3d17fb6cab8348b2c5f149f Mon Sep 17 00:00:00 2001 From: Kathan Shukla Date: Mon, 25 Nov 2019 22:53:31 -0800 Subject: [PATCH 0303/1022] Mock hal for Occupant Awareness interface. Mock hal has limited capability - driver and front passenger presence detection and driver monitoring detection. Bug: 142383127 Test: VTS tests Change-Id: I72e4b443a0d8063288e14333bd9ebbb1f2c19720 --- .../occupant_awareness/aidl/mock/Android.bp | 32 ++++ .../aidl/mock/DetectionGenerator.cpp | 71 +++++++ .../aidl/mock/DetectionGenerator.h | 50 +++++ .../aidl/mock/OccupantAwareness.cpp | 176 ++++++++++++++++++ .../aidl/mock/OccupantAwareness.h | 83 +++++++++ .../occupant_awareness/aidl/mock/service.cpp | 55 ++++++ 6 files changed, 467 insertions(+) create mode 100644 automotive/occupant_awareness/aidl/mock/Android.bp create mode 100644 automotive/occupant_awareness/aidl/mock/DetectionGenerator.cpp create mode 100644 automotive/occupant_awareness/aidl/mock/DetectionGenerator.h create mode 100644 automotive/occupant_awareness/aidl/mock/OccupantAwareness.cpp create mode 100644 automotive/occupant_awareness/aidl/mock/OccupantAwareness.h create mode 100644 automotive/occupant_awareness/aidl/mock/service.cpp diff --git a/automotive/occupant_awareness/aidl/mock/Android.bp b/automotive/occupant_awareness/aidl/mock/Android.bp new file mode 100644 index 0000000000..4b3086660c --- /dev/null +++ b/automotive/occupant_awareness/aidl/mock/Android.bp @@ -0,0 +1,32 @@ +/* + * 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. + */ + +cc_binary { + name: "android.hardware.automotive.occupant_awareness@1.0-service_mock", + relative_install_path: "hw", + vendor: true, + srcs: [ + "service.cpp", + "OccupantAwareness.cpp", + "DetectionGenerator.cpp", + ], + shared_libs: [ + "libbase", + "libbinder_ndk", + "libutils", + "android.hardware.automotive.occupant_awareness-ndk_platform", + ], +} diff --git a/automotive/occupant_awareness/aidl/mock/DetectionGenerator.cpp b/automotive/occupant_awareness/aidl/mock/DetectionGenerator.cpp new file mode 100644 index 0000000000..79d4dbc25c --- /dev/null +++ b/automotive/occupant_awareness/aidl/mock/DetectionGenerator.cpp @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#include + +#include "DetectionGenerator.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace occupant_awareness { +namespace V1_0 { +namespace implementation { + +using ::aidl::android::hardware::automotive::occupant_awareness::ConfidenceLevel; +using ::aidl::android::hardware::automotive::occupant_awareness::DriverMonitoringDetection; +using ::aidl::android::hardware::automotive::occupant_awareness::OccupantDetection; +using ::aidl::android::hardware::automotive::occupant_awareness::PresenceDetection; + +static int64_t kNanoSecondsPerMilliSecond = 1000 * 1000; + +OccupantDetections DetectionGenerator::GetNextDetections() { + OccupantDetections detections; + detections.timeStampMillis = android::elapsedRealtimeNano() / kNanoSecondsPerMilliSecond; + int remainingRoles = getSupportedRoles(); + while (remainingRoles) { + int currentRole = remainingRoles & (~(remainingRoles - 1)); + remainingRoles = remainingRoles & (remainingRoles - 1); + + OccupantDetection occupantDetection; + occupantDetection.role = static_cast(currentRole); + + // Add presence detection object for this occupant. + PresenceDetection presenceDetection; + presenceDetection.isOccupantDetected = true; + presenceDetection.detectionDurationMillis = detections.timeStampMillis; + occupantDetection.presenceData.emplace_back(presenceDetection); + + if (occupantDetection.role == Role::DRIVER) { + // Add driver monitoring detection object for this occupant. + DriverMonitoringDetection driverMonitoringDetection; + driverMonitoringDetection.confidenceScore = ConfidenceLevel::HIGH; + driverMonitoringDetection.isLookingOnRoad = 0; + driverMonitoringDetection.gazeDurationMillis = detections.timeStampMillis; + occupantDetection.attentionData.emplace_back(driverMonitoringDetection); + } + + detections.detections.emplace_back(occupantDetection); + } + return detections; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace occupant_awareness +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/occupant_awareness/aidl/mock/DetectionGenerator.h b/automotive/occupant_awareness/aidl/mock/DetectionGenerator.h new file mode 100644 index 0000000000..0884685124 --- /dev/null +++ b/automotive/occupant_awareness/aidl/mock/DetectionGenerator.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace occupant_awareness { +namespace V1_0 { +namespace implementation { + +using ::aidl::android::hardware::automotive::occupant_awareness::BnOccupantAwareness; +using ::aidl::android::hardware::automotive::occupant_awareness::OccupantDetections; +using ::aidl::android::hardware::automotive::occupant_awareness::Role; + +class DetectionGenerator { + public: + static int getSupportedRoles() { + return static_cast(Role::DRIVER) | static_cast(Role::FRONT_PASSENGER); + } + static int getSupportedCapabilities() { + return static_cast(BnOccupantAwareness::CAP_PRESENCE_DETECTION) | + static_cast(BnOccupantAwareness::CAP_DRIVER_MONITORING_DETECTION); + } + + OccupantDetections GetNextDetections(); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace occupant_awareness +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/occupant_awareness/aidl/mock/OccupantAwareness.cpp b/automotive/occupant_awareness/aidl/mock/OccupantAwareness.cpp new file mode 100644 index 0000000000..910760a88c --- /dev/null +++ b/automotive/occupant_awareness/aidl/mock/OccupantAwareness.cpp @@ -0,0 +1,176 @@ +/* + * 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. + */ + +#include + +#include "OccupantAwareness.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace occupant_awareness { +namespace V1_0 { +namespace implementation { + +using ndk::ScopedAStatus; + +static const int32_t kAllCapabilities = OccupantAwareness::CAP_PRESENCE_DETECTION | + OccupantAwareness::CAP_GAZE_DETECTION | + OccupantAwareness::CAP_DRIVER_MONITORING_DETECTION; + +constexpr int64_t kNanoSecondsPerMilliSecond = 1000 * 1000; + +ScopedAStatus OccupantAwareness::startDetection(OccupantAwarenessStatus* status) { + std::lock_guard lock(mMutex); + if (mStatus != OccupantAwarenessStatus::NOT_INITIALIZED) { + return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED); + } + + mStatus = OccupantAwarenessStatus::READY; + mWorkerThread = std::thread(startWorkerThread, this); + if (mCallback) { + mCallback->onSystemStatusChanged(kAllCapabilities, mStatus); + } + + *status = mStatus; + return ScopedAStatus::ok(); +} + +ScopedAStatus OccupantAwareness::stopDetection(OccupantAwarenessStatus* status) { + std::lock_guard lock(mMutex); + if (mStatus != OccupantAwarenessStatus::READY) { + return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED); + } + + mStatus = OccupantAwarenessStatus::NOT_INITIALIZED; + mWorkerThread.join(); + if (mCallback) { + mCallback->onSystemStatusChanged(kAllCapabilities, mStatus); + } + + *status = mStatus; + return ScopedAStatus::ok(); +} + +ScopedAStatus OccupantAwareness::getCapabilityForRole(Role occupantRole, int32_t* capabilities) { + if (!isValidRole(occupantRole)) { + return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED); + } + + int intVal = static_cast(occupantRole); + if ((intVal & DetectionGenerator::getSupportedRoles()) == intVal) { + int capabilities_ = DetectionGenerator::getSupportedCapabilities(); + if (occupantRole != Role::DRIVER) { + capabilities_ &= ~CAP_DRIVER_MONITORING_DETECTION; + } + *capabilities = capabilities_; + } else { + *capabilities = 0; + } + + return ScopedAStatus::ok(); +} + +ScopedAStatus OccupantAwareness::getState(Role occupantRole, int detectionCapability, + OccupantAwarenessStatus* status) { + if (!isValidRole(occupantRole)) { + return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED); + } + + if (!isValidDetectionCapabilities(detectionCapability) || + !isSingularCapability(detectionCapability)) { + return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED); + } + + int roleVal = static_cast(occupantRole); + + if (((roleVal & DetectionGenerator::getSupportedRoles()) != roleVal) || + ((detectionCapability & DetectionGenerator::getSupportedCapabilities()) != + detectionCapability)) { + *status = OccupantAwarenessStatus::NOT_SUPPORTED; + return ScopedAStatus::ok(); + } + + std::lock_guard lock(mMutex); + *status = mStatus; + return ScopedAStatus::ok(); +} + +ScopedAStatus OccupantAwareness::setCallback( + const std::shared_ptr& callback) { + if (callback == nullptr) { + return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED); + } + + std::lock_guard lock(mMutex); + mCallback = callback; + return ScopedAStatus::ok(); +} + +ScopedAStatus OccupantAwareness::getLatestDetection(OccupantDetections* detections) { + std::lock_guard lock(mMutex); + + if (mStatus != OccupantAwarenessStatus::READY) { + return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED); + } + + *detections = mLatestDetections; + return ScopedAStatus::ok(); +} + +bool OccupantAwareness::isValidRole(Role occupantRole) { + int intVal = static_cast(occupantRole); + int allOccupants = static_cast(Role::ALL_OCCUPANTS); + return (occupantRole != Role::INVALID) && ((intVal & (~allOccupants)) == 0); +} + +bool OccupantAwareness::isValidDetectionCapabilities(int detectionCapabilities) { + return (detectionCapabilities != OccupantAwareness::CAP_NONE) && + ((detectionCapabilities & (~kAllCapabilities)) == 0); +} + +bool OccupantAwareness::isSingularCapability(int detectionCapability) { + // Check whether the value is 0, or the value has only one bit set. + return (detectionCapability & (detectionCapability - 1)) == 0; +} + +void OccupantAwareness::startWorkerThread(OccupantAwareness* occupantAwareness) { + occupantAwareness->workerThreadFunction(); +} + +void OccupantAwareness::workerThreadFunction() { + bool isFirstDetection = true; + int64_t prevDetectionTimeMs; + while (mStatus == OccupantAwarenessStatus::READY) { + int64_t currentTimeMs = android::elapsedRealtimeNano() / kNanoSecondsPerMilliSecond; + if ((isFirstDetection) || (currentTimeMs - prevDetectionTimeMs > mDetectionDurationMs)) { + std::lock_guard lock(mMutex); + mLatestDetections = mGenerator.GetNextDetections(); + if (mCallback != nullptr) { + mCallback->onDetectionEvent(mLatestDetections); + } + isFirstDetection = false; + prevDetectionTimeMs = currentTimeMs; + } + } +} + +} // namespace implementation +} // namespace V1_0 +} // namespace occupant_awareness +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/occupant_awareness/aidl/mock/OccupantAwareness.h b/automotive/occupant_awareness/aidl/mock/OccupantAwareness.h new file mode 100644 index 0000000000..c5f6dd637e --- /dev/null +++ b/automotive/occupant_awareness/aidl/mock/OccupantAwareness.h @@ -0,0 +1,83 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include +#include +#include + +#include "DetectionGenerator.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace occupant_awareness { +namespace V1_0 { +namespace implementation { + +using ::aidl::android::hardware::automotive::occupant_awareness::BnOccupantAwareness; +using ::aidl::android::hardware::automotive::occupant_awareness::IOccupantAwarenessClientCallback; +using ::aidl::android::hardware::automotive::occupant_awareness::OccupantAwarenessStatus; +using ::aidl::android::hardware::automotive::occupant_awareness::OccupantDetections; +using ::aidl::android::hardware::automotive::occupant_awareness::Role; + +/** + * The mock HAL can detect presence of Driver and front passenger, and driver awareness detection + * for driver. + **/ +class OccupantAwareness : public BnOccupantAwareness { + public: + // Methods from ::android::hardware::automotive::occupant_awareness::IOccupantAwareness + // follow. + ndk::ScopedAStatus startDetection(OccupantAwarenessStatus* status) override; + ndk::ScopedAStatus stopDetection(OccupantAwarenessStatus* status) override; + ndk::ScopedAStatus getCapabilityForRole(Role occupantRole, int32_t* capabilities) override; + ndk::ScopedAStatus getState(Role occupantRole, int detectionCapability, + OccupantAwarenessStatus* status) override; + ndk::ScopedAStatus setCallback( + const std::shared_ptr& callback) override; + ndk::ScopedAStatus getLatestDetection(OccupantDetections* detections) override; + + private: + bool isValidRole(Role occupantRole); + bool isValidDetectionCapabilities(int detectionCapabilities); + bool isSingularCapability(int detectionCapability); + + void workerThreadFunction(); + static void startWorkerThread(OccupantAwareness* occupantAwareness); + + std::mutex mMutex; + std::shared_ptr mCallback = nullptr; + OccupantAwarenessStatus mStatus = OccupantAwarenessStatus::NOT_INITIALIZED; + + OccupantDetections mLatestDetections; + std::thread mWorkerThread; + + DetectionGenerator mGenerator; + + // Generate a new detection every 1ms. + const int64_t mDetectionDurationMs = 1; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace occupant_awareness +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/occupant_awareness/aidl/mock/service.cpp b/automotive/occupant_awareness/aidl/mock/service.cpp new file mode 100644 index 0000000000..d8860dff3d --- /dev/null +++ b/automotive/occupant_awareness/aidl/mock/service.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 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 "android.hardware.automotive.occupant_awareness@1.0-service_mock" + +#include + +#include +#include +#include + +#include "OccupantAwareness.h" + +using ::aidl::android::hardware::automotive::occupant_awareness::IOccupantAwareness; +using ::android::hardware::automotive::occupant_awareness::V1_0::implementation::OccupantAwareness; +using ::ndk::ScopedAStatus; +using ::ndk::SharedRefBase; + +const static char kOccupantAwarenessServiceName[] = "default"; + +int main() { + ABinderProcess_setThreadPoolMaxThreadCount(0); + LOG(INFO) << "Occupant Awareness service is starting"; + std::shared_ptr occupantAwareness = SharedRefBase::make(); + + const std::string instance = + std::string() + IOccupantAwareness::descriptor + "/" + kOccupantAwarenessServiceName; + + binder_status_t status = + AServiceManager_addService(occupantAwareness->asBinder().get(), instance.c_str()); + if (status == STATUS_OK) { + LOG(INFO) << "Service " << kOccupantAwarenessServiceName << " is ready"; + ABinderProcess_joinThreadPool(); + } else { + LOG(ERROR) << "Could not register service " << kOccupantAwarenessServiceName + << ", status: " << status; + } + + // In normal operation, we don't expect the thread pool to exit. + LOG(ERROR) << "Occupant Awareness service is shutting down"; + return 1; +} From 201734e5512abbd70f8e24642c778fc07fdf70df Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Thu, 5 Dec 2019 13:54:50 -0800 Subject: [PATCH 0304/1022] Fix sp<> crash on stack-allocated service object. Bug: 145609858 Test: build, boot Change-Id: Ia705750c77ee8ba950d19eae9bbd208b0dac2310 --- automotive/can/1.0/default/service.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/automotive/can/1.0/default/service.cpp b/automotive/can/1.0/default/service.cpp index 7ef44fc297..ebc2f8c51f 100644 --- a/automotive/can/1.0/default/service.cpp +++ b/automotive/can/1.0/default/service.cpp @@ -32,8 +32,8 @@ static void canControllerService() { configureRpcThreadpool(16, true); LOG(DEBUG) << "CAN controller service starting..."; - CanController canController; - if (canController.registerAsService("socketcan") != OK) { + sp canController(new CanController); + if (canController->registerAsService("socketcan") != OK) { LOG(FATAL) << "Failed to register CAN controller"; return; } From d37e5c122a69a3be3418e052227d16cf2d29980a Mon Sep 17 00:00:00 2001 From: Kathan Shukla Date: Mon, 25 Nov 2019 22:53:57 -0800 Subject: [PATCH 0305/1022] Add VTS tests for Occupant Awareness HIDL. Test: VTS tests Change-Id: Ib278986334439d181348800c01332606f9d36a89 --- .../aidl/vts/functional/Android.bp | 17 ++ .../VtsHalOccupantAwarenessV1_0TargetTest.cpp | 203 ++++++++++++++++++ 2 files changed, 220 insertions(+) create mode 100644 automotive/occupant_awareness/aidl/vts/functional/Android.bp create mode 100644 automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp diff --git a/automotive/occupant_awareness/aidl/vts/functional/Android.bp b/automotive/occupant_awareness/aidl/vts/functional/Android.bp new file mode 100644 index 0000000000..1256b69c67 --- /dev/null +++ b/automotive/occupant_awareness/aidl/vts/functional/Android.bp @@ -0,0 +1,17 @@ +cc_test { + name: "VtsHalOccupantAwarenessV1_0TargetTest", + defaults: [ + "VtsHalTargetTestDefaults", + "use_libaidlvintf_gtest_helper_static", + ], + srcs: ["VtsHalOccupantAwarenessV1_0TargetTest.cpp"], + shared_libs: [ + "libbinder", + ], + static_libs: [ + "android.hardware.automotive.occupant_awareness-cpp", + ], + test_suites: [ + "vts-core", + ], +} diff --git a/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp b/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp new file mode 100644 index 0000000000..c431f9d3b8 --- /dev/null +++ b/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp @@ -0,0 +1,203 @@ +/* + * 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 "**** HAL log ****" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace android::hardware::automotive::occupant_awareness; +using android::hardware::automotive::occupant_awareness::IOccupantAwareness; + +using android::ProcessState; +using android::sp; +using android::String16; +using android::binder::Status; + +constexpr auto kTimeout = std::chrono::seconds(3); + +#define EXPECT_OK(ret) ASSERT_TRUE((ret).isOk()) + +class OccupantAwarenessCallback : public BnOccupantAwarenessClientCallback { + public: + OccupantAwarenessCallback(const std::function& callback) + : mCallback(callback) {} + Status onSystemStatusChanged(int detectionFlags, OccupantAwarenessStatus status) override { + mCallback(detectionFlags, status); + return Status::ok(); + } + + Status onDetectionEvent(const OccupantDetections& detections) override { + (void)detections; + return Status::ok(); + } + + private: + std::function mCallback; +}; + +class OccupantAwarenessAidl : public testing::TestWithParam { + public: + virtual void SetUp() override { + mOccupantAwarenessService = + android::waitForDeclaredService(String16(GetParam().c_str())); + ASSERT_NE(mOccupantAwarenessService, nullptr); + } + + sp mOccupantAwarenessService; +}; + +// Test that startDetection() returns within the timeout. +TEST_P(OccupantAwarenessAidl, StartDetectionTest) { + auto start = std::chrono::system_clock::now(); + OccupantAwarenessStatus occupantAwarenessStatus; + Status status = mOccupantAwarenessService->startDetection(&occupantAwarenessStatus); + auto elapsed = std::chrono::system_clock::now() - start; + EXPECT_OK(status); + ASSERT_LE(elapsed, kTimeout); + + EXPECT_OK(mOccupantAwarenessService->stopDetection(&occupantAwarenessStatus)); +} + +// Test that getCapabilityForRole() returns supported capabilities for the role. The test only +// verifies that the IPC call returns successfully and does not verify the supported capabilities. +TEST_P(OccupantAwarenessAidl, GetCapabilityTest) { + std::vector rolesToTest = {Role::FRONT_PASSENGER, Role::DRIVER, + Role::ROW_2_PASSENGER_LEFT, Role::ROW_2_PASSENGER_CENTER, + Role::ROW_2_PASSENGER_RIGHT, Role::ROW_3_PASSENGER_LEFT, + Role::ROW_3_PASSENGER_CENTER, Role::ROW_3_PASSENGER_RIGHT, + Role::FRONT_OCCUPANTS, Role::ROW_2_OCCUPANTS, + Role::ROW_3_OCCUPANTS, Role::ALL_OCCUPANTS}; + + for (auto role : rolesToTest) { + int32_t capabilities; + EXPECT_OK(mOccupantAwarenessService->getCapabilityForRole(role, &capabilities)); + } +} + +// Test that getCapabilityForRole() returns failure when arguments are invalid. +TEST_P(OccupantAwarenessAidl, GetCapabilityFailureTest) { + int32_t capabilities; + EXPECT_FALSE( + mOccupantAwarenessService->getCapabilityForRole(Role::INVALID, &capabilities).isOk()); + + Role invalidRole = static_cast(static_cast(Role::ALL_OCCUPANTS) + 1); + EXPECT_FALSE( + mOccupantAwarenessService->getCapabilityForRole(invalidRole, &capabilities).isOk()); +} + +// Test that getState() returns within the timeout. The test do not attempt to verify the state, but +// only checks that the IPC call returns successfully. +TEST_P(OccupantAwarenessAidl, GetStateTest) { + std::vector rolesToTest = {Role::FRONT_PASSENGER, Role::DRIVER, + Role::ROW_2_PASSENGER_LEFT, Role::ROW_2_PASSENGER_CENTER, + Role::ROW_2_PASSENGER_RIGHT, Role::ROW_3_PASSENGER_LEFT, + Role::ROW_3_PASSENGER_CENTER, Role::ROW_3_PASSENGER_RIGHT, + Role::FRONT_OCCUPANTS, Role::ROW_2_OCCUPANTS, + Role::ROW_3_OCCUPANTS, Role::ALL_OCCUPANTS}; + + std::vector detectionCapabilities = {IOccupantAwareness::CAP_PRESENCE_DETECTION, + IOccupantAwareness::CAP_GAZE_DETECTION, + IOccupantAwareness::CAP_DRIVER_MONITORING_DETECTION}; + + for (auto role : rolesToTest) { + for (auto detectionCapability : detectionCapabilities) { + OccupantAwarenessStatus oasStatus; + EXPECT_OK(mOccupantAwarenessService->getState(role, detectionCapability, &oasStatus)); + } + } +} + +// Test that getState() returns failure with invalid args. +TEST_P(OccupantAwarenessAidl, GetStateFailureTest) { + // Verify that getState() returns error when role is invalid (0). + OccupantAwarenessStatus oasStatus; + EXPECT_FALSE(mOccupantAwarenessService + ->getState(Role::INVALID, IOccupantAwareness::CAP_PRESENCE_DETECTION, + &oasStatus) + .isOk()); + + // Verify that getState() returns error when role is invalid (invalid flag). + int invalidRole = static_cast(Role::ALL_OCCUPANTS) + 1; + EXPECT_FALSE(mOccupantAwarenessService + ->getState(static_cast(invalidRole), + IOccupantAwareness::CAP_PRESENCE_DETECTION, &oasStatus) + .isOk()); + + // Verify that getState() returns error when capability is invalid (none). + EXPECT_FALSE(mOccupantAwarenessService + ->getState(Role::FRONT_PASSENGER, IOccupantAwareness::CAP_NONE, &oasStatus) + .isOk()); + + // Verify that getState() returns error when capability is invalid (invalid flag). + int invalidDetectionFlags = 0x10; + EXPECT_FALSE(mOccupantAwarenessService + ->getState(Role::FRONT_PASSENGER, invalidDetectionFlags, &oasStatus) + .isOk()); +} + +// Test that setCallback() returns within the timeout. +TEST_P(OccupantAwarenessAidl, SetCallbackTest) { + sp callback = + new OccupantAwarenessCallback([](int detectionFlags, OccupantAwarenessStatus status) { + (void)detectionFlags; + (void)status; + }); + auto start = std::chrono::system_clock::now(); + Status status = mOccupantAwarenessService->setCallback(callback); + auto elapsed = std::chrono::system_clock::now() - start; + EXPECT_OK(status); + ASSERT_LE(elapsed, kTimeout); +} + +// Test that setCallback() returns failure with invalid args. +TEST_P(OccupantAwarenessAidl, SetCallbackFailureTest) { + sp callback = nullptr; + Status status = mOccupantAwarenessService->setCallback(callback); + EXPECT_FALSE(status.isOk()); +} + +// Test that getLatestDetection() returns within the timeout. +TEST_P(OccupantAwarenessAidl, GetLatestDetectionTest) { + auto start = std::chrono::system_clock::now(); + OccupantDetections detections; + // Do not check status here, since error status is returned when no detection is present. + (void)mOccupantAwarenessService->getLatestDetection(&detections); + auto elapsed = std::chrono::system_clock::now() - start; + ASSERT_LE(elapsed, kTimeout); +} + +INSTANTIATE_TEST_SUITE_P( + InstantiationName, OccupantAwarenessAidl, + testing::ValuesIn(android::getAidlHalInstanceNames(IOccupantAwareness::descriptor)), + android::PrintInstanceNameToString); + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + ProcessState::self()->setThreadPoolMaxThreadCount(1); + ProcessState::self()->startThreadPool(); + return RUN_ALL_TESTS(); +} From 83baffdac242ca5d4d86e1ad2b170db23dc3f1d2 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Fri, 15 Nov 2019 19:20:41 -0800 Subject: [PATCH 0306/1022] Wifi: Add 6GHz band to NAN structures and methods This commit adds 6GHz band to NAN related structures and methods. Bug: 139354972 Test: Manual Test: VTS test Test: Unit test: Test: ./hardware/interfaces/wifi/1.4/default/tests/runtests.sh Change-Id: I33f63fde67d5a839678076fdb7c76d5eb8645131 --- wifi/1.4/Android.bp | 1 + wifi/1.4/IWifiNanIface.hal | 80 +++ wifi/1.4/default/hidl_struct_util.cpp | 15 +- wifi/1.4/default/hidl_struct_util.h | 4 +- .../default/tests/wifi_chip_unit_tests.cpp | 17 +- .../tests/wifi_nan_iface_unit_tests.cpp | 13 +- wifi/1.4/default/wifi_nan_iface.cpp | 48 +- wifi/1.4/default/wifi_nan_iface.h | 33 +- wifi/1.4/types.hal | 161 ++++++ wifi/1.4/vts/functional/Android.bp | 3 +- .../functional/wifi_nan_iface_hidl_test.cpp | 544 ++++++++++++++++++ 11 files changed, 886 insertions(+), 33 deletions(-) create mode 100644 wifi/1.4/IWifiNanIface.hal create mode 100644 wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp diff --git a/wifi/1.4/Android.bp b/wifi/1.4/Android.bp index e63b1ebaed..b4432301af 100644 --- a/wifi/1.4/Android.bp +++ b/wifi/1.4/Android.bp @@ -12,6 +12,7 @@ hidl_interface { "IWifiApIface.hal", "IWifiChip.hal", "IWifiChipEventCallback.hal", + "IWifiNanIface.hal", "IWifiRttController.hal", "IWifiRttControllerEventCallback.hal", "IWifiStaIface.hal", diff --git a/wifi/1.4/IWifiNanIface.hal b/wifi/1.4/IWifiNanIface.hal new file mode 100644 index 0000000000..56e3c2d096 --- /dev/null +++ b/wifi/1.4/IWifiNanIface.hal @@ -0,0 +1,80 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi@1.4; + +import @1.0::CommandIdShort; +import @1.0::WifiStatus; +import @1.2::IWifiNanIface; +import @1.2::NanConfigRequestSupplemental; +import NanConfigRequest; +import NanEnableRequest; + +/** + * Interface used to represent a single NAN (Neighbour Aware Network) iface. + * + * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness + * Networking (NAN) Technical Specification". + */ +interface IWifiNanIface extends @1.2::IWifiNanIface { + /** + * Enable NAN: configures and activates NAN clustering (does not start + * a discovery session or set up data-interfaces or data-paths). Use the + * |IWifiNanIface.configureRequest| method to change the configuration of an already enabled + * NAN interface. + * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyEnableResponse|. + * + * Note: supersedes the @1.2::IWifiNanIface.enableRequest() method which is deprecated as of + * HAL version 1.4. + * + * @param cmdId command Id to use for this invocation. + * @param msg1 Instance of |NanEnableRequest|. + * @param msg2 Instance of |NanConfigRequestSupplemental|. + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_NOT_SUPPORTED|, + * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|, + * |WifiStatusCode.ERROR_INVALID_ARGS|, + * |WifiStatusCode.ERROR_UNKNOWN| + */ + enableRequest_1_4(CommandIdShort cmdId, NanEnableRequest msg1, + NanConfigRequestSupplemental msg2) + generates (WifiStatus status); + + /** + * Configure NAN: configures an existing NAN functionality (i.e. assumes + * |IWifiNanIface.enableRequest| already submitted and succeeded). + * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyConfigResponse|. + * + * Note: supersedes the @1.2::IWifiNanIface.configRequest() method which is deprecated as of + * HAL version 1.4. + * + * @param cmdId command Id to use for this invocation. + * @param msg1 Instance of |NanConfigRequest|. + * @param msg1 Instance of |NanConfigRequestSupplemental|. + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_NOT_SUPPORTED|, + * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|, + * |WifiStatusCode.ERROR_INVALID_ARGS|, + * |WifiStatusCode.ERROR_UNKNOWN| + */ + configRequest_1_4(CommandIdShort cmdId, NanConfigRequest msg1, + NanConfigRequestSupplemental msg2) + generates (WifiStatus status); +}; diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp index 35c683984d..a7c568603a 100644 --- a/wifi/1.4/default/hidl_struct_util.cpp +++ b/wifi/1.4/default/hidl_struct_util.cpp @@ -1270,16 +1270,20 @@ bool convertHidlNanEnableRequestToLegacy( hidl_request.debugConfigs .useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ]; + /* TODO: b/145609058 + * Missing updates needed to legacy_hal::NanEnableRequest and conversion to + * it for 6GHz band */ + return true; } -bool convertHidlNanEnableRequest_1_2ToLegacy( +bool convertHidlNanEnableRequest_1_4ToLegacy( const NanEnableRequest& hidl_request1, const V1_2::NanConfigRequestSupplemental& hidl_request2, legacy_hal::NanEnableRequest* legacy_request) { if (!legacy_request) { LOG(ERROR) - << "convertHidlNanEnableRequest_1_2ToLegacy: null legacy_request"; + << "convertHidlNanEnableRequest_1_4ToLegacy: null legacy_request"; return false; } @@ -1780,16 +1784,19 @@ bool convertHidlNanConfigRequestToLegacy( legacy_request->config_dw.dw_5g_interval_val = hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ] .discoveryWindowIntervalVal; + /* TODO: b/145609058 + * Missing updates needed to legacy_hal::NanConfigRequest and conversion to + * it for 6GHz band */ return true; } -bool convertHidlNanConfigRequest_1_2ToLegacy( +bool convertHidlNanConfigRequest_1_4ToLegacy( const NanConfigRequest& hidl_request1, const V1_2::NanConfigRequestSupplemental& hidl_request2, legacy_hal::NanConfigRequest* legacy_request) { if (!legacy_request) { - LOG(ERROR) << "convertHidlNanConfigRequest_1_2ToLegacy: legacy_request " + LOG(ERROR) << "convertHidlNanConfigRequest_1_4ToLegacy: legacy_request " "is null"; return false; } diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h index 987891b5b2..160870a7ca 100644 --- a/wifi/1.4/default/hidl_struct_util.h +++ b/wifi/1.4/default/hidl_struct_util.h @@ -118,11 +118,11 @@ bool convertHidlNanEnableRequestToLegacy( bool convertHidlNanConfigRequestToLegacy( const NanConfigRequest& hidl_request, legacy_hal::NanConfigRequest* legacy_request); -bool convertHidlNanEnableRequest_1_2ToLegacy( +bool convertHidlNanEnableRequest_1_4ToLegacy( const NanEnableRequest& hidl_request1, const V1_2::NanConfigRequestSupplemental& hidl_request2, legacy_hal::NanEnableRequest* legacy_request); -bool convertHidlNanConfigRequest_1_2ToLegacy( +bool convertHidlNanConfigRequest_1_4ToLegacy( const NanConfigRequest& hidl_request1, const V1_2::NanConfigRequestSupplemental& hidl_request2, legacy_hal::NanConfigRequest* legacy_request); diff --git a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp index 90e81e12c1..d35adbc125 100644 --- a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp +++ b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp @@ -720,13 +720,16 @@ TEST_F(WifiChipV2_AwareIfaceCombinationTest, ASSERT_EQ(iface_names[0], "wlan0"); }); // Retrieve the exact iface object. - sp nan_iface; - chip_->getNanIface("wlan0", [&nan_iface](const WifiStatus& status, - const sp& iface) { - ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); - ASSERT_NE(iface.get(), nullptr); - nan_iface = iface; - }); + sp nan_iface; + chip_->getNanIface( + "wlan0", + [&nan_iface]( + const WifiStatus& status, + const sp& iface) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + ASSERT_NE(iface.get(), nullptr); + nan_iface = iface; + }); // Remove the STA iface. removeIface(IfaceType::STA, "wlan0"); diff --git a/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp index 8aefa92412..90227925dd 100644 --- a/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp +++ b/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp @@ -41,6 +41,9 @@ namespace wifi { namespace V1_4 { namespace implementation { +using android::hardware::wifi::V1_2::IWifiNanIfaceEventCallback; +using android::hardware::wifi::V1_2::NanDataPathConfirmInd; + bool CaptureIfaceEventHandlers( const std::string& /* iface_name*/, iface_util::IfaceEventHandlers in_iface_event_handlers, @@ -96,9 +99,15 @@ class MockNanIfaceEventCallback : public IWifiNanIfaceEventCallback { Return(uint16_t, const WifiNanStatus&)); MOCK_METHOD1(eventDataPathRequest, Return(const NanDataPathRequestInd&)); - MOCK_METHOD1(eventDataPathConfirm, - Return(const NanDataPathConfirmInd&)); + MOCK_METHOD1( + eventDataPathConfirm, + Return( + const android::hardware::wifi::V1_0::NanDataPathConfirmInd&)); MOCK_METHOD1(eventDataPathTerminated, Return(uint32_t)); + MOCK_METHOD1(eventDataPathConfirm_1_2, + Return(const NanDataPathConfirmInd&)); + MOCK_METHOD1(eventDataPathScheduleUpdate, + Return(const NanDataPathScheduleUpdateInd&)); }; class WifiNanIfaceTest : public Test { diff --git a/wifi/1.4/default/wifi_nan_iface.cpp b/wifi/1.4/default/wifi_nan_iface.cpp index 981acb282c..073101cbd5 100644 --- a/wifi/1.4/default/wifi_nan_iface.cpp +++ b/wifi/1.4/default/wifi_nan_iface.cpp @@ -576,7 +576,7 @@ Return WifiNanIface::getCapabilitiesRequest( } Return WifiNanIface::enableRequest(uint16_t cmd_id, - const NanEnableRequest& msg, + const V1_0::NanEnableRequest& msg, enableRequest_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, &WifiNanIface::enableRequestInternal, hidl_status_cb, @@ -584,7 +584,7 @@ Return WifiNanIface::enableRequest(uint16_t cmd_id, } Return WifiNanIface::configRequest(uint16_t cmd_id, - const NanConfigRequest& msg, + const V1_0::NanConfigRequest& msg, configRequest_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, &WifiNanIface::configRequestInternal, hidl_status_cb, @@ -687,7 +687,7 @@ Return WifiNanIface::registerEventCallback_1_2( } Return WifiNanIface::enableRequest_1_2( - uint16_t cmd_id, const NanEnableRequest& msg1, + uint16_t cmd_id, const V1_0::NanEnableRequest& msg1, const V1_2::NanConfigRequestSupplemental& msg2, enableRequest_1_2_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, @@ -696,7 +696,7 @@ Return WifiNanIface::enableRequest_1_2( } Return WifiNanIface::configRequest_1_2( - uint16_t cmd_id, const NanConfigRequest& msg1, + uint16_t cmd_id, const V1_0::NanConfigRequest& msg1, const V1_2::NanConfigRequestSupplemental& msg2, configRequest_1_2_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, @@ -704,6 +704,24 @@ Return WifiNanIface::configRequest_1_2( hidl_status_cb, cmd_id, msg1, msg2); } +Return WifiNanIface::enableRequest_1_4( + uint16_t cmd_id, const NanEnableRequest& msg1, + const V1_2::NanConfigRequestSupplemental& msg2, + enableRequest_1_4_cb hidl_status_cb) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::enableRequest_1_4Internal, + hidl_status_cb, cmd_id, msg1, msg2); +} + +Return WifiNanIface::configRequest_1_4( + uint16_t cmd_id, const NanConfigRequest& msg1, + const V1_2::NanConfigRequestSupplemental& msg2, + configRequest_1_4_cb hidl_status_cb) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::configRequest_1_4Internal, + hidl_status_cb, cmd_id, msg1, msg2); +} + std::pair WifiNanIface::getNameInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_}; } @@ -727,12 +745,12 @@ WifiStatus WifiNanIface::getCapabilitiesRequestInternal(uint16_t cmd_id) { } WifiStatus WifiNanIface::enableRequestInternal( - uint16_t /* cmd_id */, const NanEnableRequest& /* msg */) { + uint16_t /* cmd_id */, const V1_0::NanEnableRequest& /* msg */) { return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED); } WifiStatus WifiNanIface::configRequestInternal( - uint16_t /* cmd_id */, const NanConfigRequest& /* msg */) { + uint16_t /* cmd_id */, const V1_0::NanConfigRequest& /* msg */) { return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED); } @@ -855,10 +873,22 @@ WifiStatus WifiNanIface::registerEventCallback_1_2Internal( } WifiStatus WifiNanIface::enableRequest_1_2Internal( + uint16_t /* cmd_id */, const V1_0::NanEnableRequest& /* msg1 */, + const V1_2::NanConfigRequestSupplemental& /*msg2 */) { + return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED); +} + +WifiStatus WifiNanIface::configRequest_1_2Internal( + uint16_t /* cmd_id */, const V1_0::NanConfigRequest& /* msg1 */, + const V1_2::NanConfigRequestSupplemental& /* msg2 */) { + return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED); +} + +WifiStatus WifiNanIface::enableRequest_1_4Internal( uint16_t cmd_id, const NanEnableRequest& msg1, const V1_2::NanConfigRequestSupplemental& msg2) { legacy_hal::NanEnableRequest legacy_msg; - if (!hidl_struct_util::convertHidlNanEnableRequest_1_2ToLegacy( + if (!hidl_struct_util::convertHidlNanEnableRequest_1_4ToLegacy( msg1, msg2, &legacy_msg)) { return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); } @@ -867,11 +897,11 @@ WifiStatus WifiNanIface::enableRequest_1_2Internal( return createWifiStatusFromLegacyError(legacy_status); } -WifiStatus WifiNanIface::configRequest_1_2Internal( +WifiStatus WifiNanIface::configRequest_1_4Internal( uint16_t cmd_id, const NanConfigRequest& msg1, const V1_2::NanConfigRequestSupplemental& msg2) { legacy_hal::NanConfigRequest legacy_msg; - if (!hidl_struct_util::convertHidlNanConfigRequest_1_2ToLegacy( + if (!hidl_struct_util::convertHidlNanConfigRequest_1_4ToLegacy( msg1, msg2, &legacy_msg)) { return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); } diff --git a/wifi/1.4/default/wifi_nan_iface.h b/wifi/1.4/default/wifi_nan_iface.h index e3a5c34cd3..c16628bbf6 100644 --- a/wifi/1.4/default/wifi_nan_iface.h +++ b/wifi/1.4/default/wifi_nan_iface.h @@ -19,7 +19,7 @@ #include #include -#include +#include #include "hidl_callback_util.h" #include "wifi_iface_util.h" @@ -31,11 +31,12 @@ namespace wifi { namespace V1_4 { namespace implementation { using namespace android::hardware::wifi::V1_0; +using namespace android::hardware::wifi::V1_2; /** * HIDL interface object used to control a NAN Iface instance. */ -class WifiNanIface : public V1_2::IWifiNanIface { +class WifiNanIface : public V1_4::IWifiNanIface { public: WifiNanIface(const std::string& ifname, const std::weak_ptr legacy_hal, @@ -53,9 +54,11 @@ class WifiNanIface : public V1_2::IWifiNanIface { registerEventCallback_cb hidl_status_cb) override; Return getCapabilitiesRequest( uint16_t cmd_id, getCapabilitiesRequest_cb hidl_status_cb) override; - Return enableRequest(uint16_t cmd_id, const NanEnableRequest& msg, + Return enableRequest(uint16_t cmd_id, + const V1_0::NanEnableRequest& msg, enableRequest_cb hidl_status_cb) override; - Return configRequest(uint16_t cmd_id, const NanConfigRequest& msg, + Return configRequest(uint16_t cmd_id, + const V1_0::NanConfigRequest& msg, configRequest_cb hidl_status_cb) override; Return disableRequest(uint16_t cmd_id, disableRequest_cb hidl_status_cb) override; @@ -94,10 +97,18 @@ class WifiNanIface : public V1_2::IWifiNanIface { const sp& callback, registerEventCallback_1_2_cb hidl_status_cb) override; Return enableRequest_1_2( - uint16_t cmd_id, const NanEnableRequest& msg1, + uint16_t cmd_id, const V1_0::NanEnableRequest& msg1, const V1_2::NanConfigRequestSupplemental& msg2, enableRequest_1_2_cb hidl_status_cb) override; Return configRequest_1_2( + uint16_t cmd_id, const V1_0::NanConfigRequest& msg1, + const V1_2::NanConfigRequestSupplemental& msg2, + configRequest_1_2_cb hidl_status_cb) override; + Return enableRequest_1_4( + uint16_t cmd_id, const NanEnableRequest& msg1, + const V1_2::NanConfigRequestSupplemental& msg2, + enableRequest_1_2_cb hidl_status_cb) override; + Return configRequest_1_4( uint16_t cmd_id, const NanConfigRequest& msg1, const V1_2::NanConfigRequestSupplemental& msg2, configRequest_1_2_cb hidl_status_cb) override; @@ -110,9 +121,9 @@ class WifiNanIface : public V1_2::IWifiNanIface { const sp& callback); WifiStatus getCapabilitiesRequestInternal(uint16_t cmd_id); WifiStatus enableRequestInternal(uint16_t cmd_id, - const NanEnableRequest& msg); + const V1_0::NanEnableRequest& msg); WifiStatus configRequestInternal(uint16_t cmd_id, - const NanConfigRequest& msg); + const V1_0::NanConfigRequest& msg); WifiStatus disableRequestInternal(uint16_t cmd_id); WifiStatus startPublishRequestInternal(uint16_t cmd_id, const NanPublishRequest& msg); @@ -136,9 +147,15 @@ class WifiNanIface : public V1_2::IWifiNanIface { WifiStatus registerEventCallback_1_2Internal( const sp& callback); WifiStatus enableRequest_1_2Internal( - uint16_t cmd_id, const NanEnableRequest& msg1, + uint16_t cmd_id, const V1_0::NanEnableRequest& msg1, const V1_2::NanConfigRequestSupplemental& msg2); WifiStatus configRequest_1_2Internal( + uint16_t cmd_id, const V1_0::NanConfigRequest& msg, + const V1_2::NanConfigRequestSupplemental& msg2); + WifiStatus enableRequest_1_4Internal( + uint16_t cmd_id, const NanEnableRequest& msg1, + const V1_2::NanConfigRequestSupplemental& msg2); + WifiStatus configRequest_1_4Internal( uint16_t cmd_id, const NanConfigRequest& msg, const V1_2::NanConfigRequestSupplemental& msg2); diff --git a/wifi/1.4/types.hal b/wifi/1.4/types.hal index 0db0c2c224..07a298e336 100644 --- a/wifi/1.4/types.hal +++ b/wifi/1.4/types.hal @@ -17,6 +17,8 @@ package android.hardware.wifi@1.4; import @1.0::MacAddress; +import @1.0::NanBandIndex; +import @1.0::NanBandSpecificConfig; import @1.0::Rssi; import @1.0::RttBw; import @1.0::RttConfig; @@ -28,6 +30,7 @@ import @1.0::TimeSpanInPs; import @1.0::TimeStampInUs; import @1.0::WifiBand; import @1.0::WifiChannelInfo; +import @1.0::WifiChannelInMhz; import @1.0::WifiChannelWidthInMhz; import @1.0::WifiInformationElement; import @1.0::WifiRateNss; @@ -55,6 +58,16 @@ enum WifiBand : @1.0::WifiBand { BAND_24GHZ_5GHZ_WITH_DFS_6GHZ = 15 }; +/** + * The discovery bands supported by NAN. + */ +enum NanBandIndex : @1.0::NanBandIndex { + /** + * Index for 6 GHz band. + */ + NAN_BAND_6GHZ = 2, +}; + /** * Wifi Rate Preamble */ @@ -75,6 +88,154 @@ enum RttPreamble : @1.0::RttPreamble { HE = 0x8, }; +/** + * Debug configuration parameters. Many of these allow non-standard-compliant operation and are + * not intended for normal operational mode. + */ +struct NanDebugConfig { + /** + * Specification of the lower 2 bytes of the cluster ID. The cluster ID is 50-60-9a-01-00-00 to + * 50-60-9a-01-FF-FF. Configuration of the bottom and top values of the range (which defaults to + * 0x0000 and 0xFFFF respectively). + * Configuration is only used if |validClusterIdVals| is set to true. + */ + bool validClusterIdVals; + uint16_t clusterIdBottomRangeVal; + uint16_t clusterIdTopRangeVal; + /** + * NAN management interface address, if specified (|validIntfAddrVal| is true) then overrides any + * other configuration (specifically the default randomization configured by + * |NanConfigRequest.macAddressRandomizationIntervalSec|). + */ + bool validIntfAddrVal; + MacAddress intfAddrVal; + /** + * Combination of the 24 bit Organizationally Unique ID (OUI) and the 8 bit OUI Type. + * Used if |validOuiVal| is set to true. + */ + bool validOuiVal; + uint32_t ouiVal; + /** + * Force the Random Factor to the specified value for all transmitted Sync/Discovery beacons. + * Used if |validRandomFactorForceVal| is set to true. + * NAN Spec: Master Indication Attribute / Random Factor + */ + bool validRandomFactorForceVal; + uint8_t randomFactorForceVal; + /** + * Forces the hop-count for all transmitted Sync and Discovery Beacons NO matter the real + * hop-count being received over the air. Used if the |validHopCountForceVal}| flag is set to + * true. + * NAN Spec: Cluster Attribute / Anchor Master Information / Hop Count to Anchor Master + */ + bool validHopCountForceVal; + uint8_t hopCountForceVal; + /** + * Frequency in MHz to of the discovery channel in the specified band. Indexed by |NanBandIndex|. + * Used if the |validDiscoveryChannelVal| is set to true. + */ + bool validDiscoveryChannelVal; + WifiChannelInMhz[3] discoveryChannelMhzVal; + /** + * Specifies whether sync/discovery beacons are transmitted in the specified band. Indexed by + * |NanBandIndex|. Used if the |validUseBeaconsInBandVal| is set to true. + */ + bool validUseBeaconsInBandVal; + bool[3] useBeaconsInBandVal; + /** + * Specifies whether SDF (service discovery frames) are transmitted in the specified band. Indexed + * by |NanBandIndex|. Used if the |validUseSdfInBandVal| is set to true. + */ + bool validUseSdfInBandVal; + bool[3] useSdfInBandVal; +}; + +/** + * Configuration parameters of NAN: used when enabling and re-configuring a NAN cluster. + */ +struct NanConfigRequest { + /** + * Master preference of this device. + * NAN Spec: Master Indication Attribute / Master Preference + */ + uint8_t masterPref; + /** + * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered + * for |NanClusterEventType.DISCOVERY_MAC_ADDRESS_CHANGED|. + */ + bool disableDiscoveryAddressChangeIndication; + /** + * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered + * for |NanClusterEventType.STARTED_CLUSTER|. + */ + bool disableStartedClusterIndication; + /** + * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered + * for |NanClusterEventType.JOINED_CLUSTER|. + */ + bool disableJoinedClusterIndication; + /** + * Control whether publish service IDs are included in Sync/Discovery beacons. + * NAN Spec: Service ID List Attribute + */ + bool includePublishServiceIdsInBeacon; + /** + * If |includePublishServiceIdsInBeacon| is true then specifies the number of publish service IDs + * to include in the Sync/Discovery beacons: + * Value = 0: include as many service IDs as will fit into the maximum allowed beacon frame size. + * Value must fit within 7 bits - i.e. <= 127. + */ + uint8_t numberOfPublishServiceIdsInBeacon; + /** + * Control whether subscribe service IDs are included in Sync/Discovery beacons. + * Spec: Subscribe Service ID List Attribute + */ + bool includeSubscribeServiceIdsInBeacon; + /** + * If |includeSubscribeServiceIdsInBeacon| is true then specifies the number of subscribe service + * IDs to include in the Sync/Discovery beacons: + * Value = 0: include as many service IDs as will fit into the maximum allowed beacon frame size. + * Value must fit within 7 bits - i.e. <= 127. + */ + uint8_t numberOfSubscribeServiceIdsInBeacon; + /** + * Number of samples used to calculate RSSI. + */ + uint16_t rssiWindowSize; + /** + * Specifies the interval in seconds that the NAN management interface MAC address is randomized. + * A value of 0 is used to disable the MAC address randomization + */ + uint32_t macAddressRandomizationIntervalSec; + /** + * Additional configuration provided per band: indexed by |NanBandIndex|. + */ + NanBandSpecificConfig[3] bandSpecificConfig; +}; + +/** + * Enable requests for NAN: start-up configuration |IWifiNanIface.enableRequest|. + */ +struct NanEnableRequest { + /** + * Enable operation in a specific band: indexed by |NanBandIndex|. + */ + bool[3] operateInBand; + /** + * Specify extent of cluster by specifying the max hop count. + */ + uint8_t hopCountMax; + /** + * Configurations of NAN cluster operation. Can also be modified at run-time using + * |IWifiNanIface.configRequest|. + */ + NanConfigRequest configParams; + /** + * Non-standard configurations of NAN cluster operation - useful for debugging operations. + */ + NanDebugConfig debugConfigs; +}; + /** * RTT configuration. */ diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp index f3be25db55..46ac3ee5a5 100644 --- a/wifi/1.4/vts/functional/Android.bp +++ b/wifi/1.4/vts/functional/Android.bp @@ -21,7 +21,8 @@ cc_test { srcs: [ "VtsHalWifiV1_4TargetTest.cpp", "wifi_ap_iface_hidl_test.cpp", - "wifi_chip_hidl_test.cpp" + "wifi_chip_hidl_test.cpp", + "wifi_nan_iface_hidl_test.cpp" ], static_libs: [ "VtsHalWifiV1_0TargetTestUtil", diff --git a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp new file mode 100644 index 0000000000..245e9063ea --- /dev/null +++ b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp @@ -0,0 +1,544 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Nanache 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wifi_hidl_call_util.h" +#include "wifi_hidl_test_utils.h" + +using namespace ::android::hardware::wifi::V1_0; +using namespace ::android::hardware::wifi::V1_2; +using namespace ::android::hardware::wifi::V1_4; + +using ::android::sp; +using ::android::hardware::Return; +using ::android::hardware::Void; + +#define TIMEOUT_PERIOD 10 + +android::sp getWifiNanIface_1_4( + const std::string& instance_name) { + return android::hardware::wifi::V1_4::IWifiNanIface::castFrom( + getWifiNanIface(instance_name)); +} + +/** + * Fixture to use for all NAN Iface HIDL interface tests. + */ +class WifiNanIfaceHidlTest : public ::testing::TestWithParam { + public: + virtual void SetUp() override { + iwifiNanIface = getWifiNanIface_1_4(GetInstanceName()); + ASSERT_NE(nullptr, iwifiNanIface.get()); + ASSERT_EQ(WifiStatusCode::SUCCESS, + HIDL_INVOKE(iwifiNanIface, registerEventCallback_1_2, + new WifiNanIfaceEventCallback(*this)) + .code); + } + + virtual void TearDown() override { stopWifi(GetInstanceName()); } + + /* Used as a mechanism to inform the test about data/event callback */ + inline void notify() { + std::unique_lock lock(mtx_); + count_++; + cv_.notify_one(); + } + + enum CallbackType { + INVALID = -2, + ANY_CALLBACK = -1, + + NOTIFY_CAPABILITIES_RESPONSE = 0, + NOTIFY_ENABLE_RESPONSE, + NOTIFY_CONFIG_RESPONSE, + NOTIFY_DISABLE_RESPONSE, + NOTIFY_START_PUBLISH_RESPONSE, + NOTIFY_STOP_PUBLISH_RESPONSE, + NOTIFY_START_SUBSCRIBE_RESPONSE, + NOTIFY_STOP_SUBSCRIBE_RESPONSE, + NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE, + NOTIFY_CREATE_DATA_INTERFACE_RESPONSE, + NOTIFY_DELETE_DATA_INTERFACE_RESPONSE, + NOTIFY_INITIATE_DATA_PATH_RESPONSE, + NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE, + NOTIFY_TERMINATE_DATA_PATH_RESPONSE, + + EVENT_CLUSTER_EVENT, + EVENT_DISABLED, + EVENT_PUBLISH_TERMINATED, + EVENT_SUBSCRIBE_TERMINATED, + EVENT_MATCH, + EVENT_MATCH_EXPIRED, + EVENT_FOLLOWUP_RECEIVED, + EVENT_TRANSMIT_FOLLOWUP, + EVENT_DATA_PATH_REQUEST, + EVENT_DATA_PATH_CONFIRM, + EVENT_DATA_PATH_TERMINATED, + EVENT_DATA_PATH_CONFIRM_1_2, + EVENT_DATA_PATH_SCHEDULE_UPDATE + }; + + /* Test code calls this function to wait for data/event callback */ + /* Must set callbackType = INVALID before call this function */ + inline std::cv_status wait(CallbackType waitForCallbackType) { + std::unique_lock lock(mtx_); + + EXPECT_NE(INVALID, waitForCallbackType); // can't ASSERT in a + // non-void-returning method + + std::cv_status status = std::cv_status::no_timeout; + auto now = std::chrono::system_clock::now(); + while (count_ == 0) { + status = cv_.wait_until(lock, + now + std::chrono::seconds(TIMEOUT_PERIOD)); + if (status == std::cv_status::timeout) return status; + if (waitForCallbackType != ANY_CALLBACK && + callbackType != INVALID && + callbackType != waitForCallbackType) { + count_--; + } + } + count_--; + return status; + } + + class WifiNanIfaceEventCallback + : public ::android::hardware::wifi::V1_2::IWifiNanIfaceEventCallback { + WifiNanIfaceHidlTest& parent_; + + public: + WifiNanIfaceEventCallback(WifiNanIfaceHidlTest& parent) + : parent_(parent){}; + + virtual ~WifiNanIfaceEventCallback() = default; + + Return notifyCapabilitiesResponse( + uint16_t id, const WifiNanStatus& status, + const NanCapabilities& capabilities) override { + parent_.callbackType = NOTIFY_CAPABILITIES_RESPONSE; + + parent_.id = id; + parent_.status = status; + parent_.capabilities = capabilities; + + parent_.notify(); + return Void(); + } + + Return notifyEnableResponse( + uint16_t id, const WifiNanStatus& status) override { + parent_.callbackType = NOTIFY_ENABLE_RESPONSE; + + parent_.id = id; + parent_.status = status; + + parent_.notify(); + return Void(); + } + + Return notifyConfigResponse( + uint16_t id, const WifiNanStatus& status) override { + parent_.callbackType = NOTIFY_CONFIG_RESPONSE; + + parent_.id = id; + parent_.status = status; + + parent_.notify(); + return Void(); + } + + Return notifyDisableResponse( + uint16_t id, const WifiNanStatus& status) override { + parent_.callbackType = NOTIFY_DISABLE_RESPONSE; + + parent_.id = id; + parent_.status = status; + + parent_.notify(); + return Void(); + } + + Return notifyStartPublishResponse(uint16_t id, + const WifiNanStatus& status, + uint8_t sessionId) override { + parent_.callbackType = NOTIFY_START_PUBLISH_RESPONSE; + + parent_.id = id; + parent_.status = status; + parent_.sessionId = sessionId; + + parent_.notify(); + return Void(); + } + + Return notifyStopPublishResponse( + uint16_t id, const WifiNanStatus& status) override { + parent_.callbackType = NOTIFY_STOP_PUBLISH_RESPONSE; + + parent_.id = id; + parent_.status = status; + + parent_.notify(); + return Void(); + } + + Return notifyStartSubscribeResponse(uint16_t id, + const WifiNanStatus& status, + uint8_t sessionId) override { + parent_.callbackType = NOTIFY_START_SUBSCRIBE_RESPONSE; + + parent_.id = id; + parent_.status = status; + parent_.sessionId = sessionId; + + parent_.notify(); + return Void(); + } + + Return notifyStopSubscribeResponse( + uint16_t id, const WifiNanStatus& status) override { + parent_.callbackType = NOTIFY_STOP_SUBSCRIBE_RESPONSE; + + parent_.id = id; + parent_.status = status; + + parent_.notify(); + return Void(); + } + + Return notifyTransmitFollowupResponse( + uint16_t id, const WifiNanStatus& status) override { + parent_.callbackType = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE; + + parent_.id = id; + parent_.status = status; + + parent_.notify(); + return Void(); + } + + Return notifyCreateDataInterfaceResponse( + uint16_t id, const WifiNanStatus& status) override { + parent_.callbackType = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE; + + parent_.id = id; + parent_.status = status; + + parent_.notify(); + return Void(); + } + + Return notifyDeleteDataInterfaceResponse( + uint16_t id, const WifiNanStatus& status) override { + parent_.callbackType = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE; + + parent_.id = id; + parent_.status = status; + + parent_.notify(); + return Void(); + } + + Return notifyInitiateDataPathResponse( + uint16_t id, const WifiNanStatus& status, + uint32_t ndpInstanceId) override { + parent_.callbackType = NOTIFY_INITIATE_DATA_PATH_RESPONSE; + + parent_.id = id; + parent_.status = status; + parent_.ndpInstanceId = ndpInstanceId; + + parent_.notify(); + return Void(); + } + + Return notifyRespondToDataPathIndicationResponse( + uint16_t id, const WifiNanStatus& status) override { + parent_.callbackType = + NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE; + + parent_.id = id; + parent_.status = status; + + parent_.notify(); + return Void(); + } + + Return notifyTerminateDataPathResponse( + uint16_t id, const WifiNanStatus& status) override { + parent_.callbackType = NOTIFY_TERMINATE_DATA_PATH_RESPONSE; + + parent_.id = id; + parent_.status = status; + + parent_.notify(); + return Void(); + } + + Return eventClusterEvent( + const NanClusterEventInd& event) override { + parent_.callbackType = EVENT_CLUSTER_EVENT; + + parent_.nanClusterEventInd = event; + + parent_.notify(); + return Void(); + } + + Return eventDisabled(const WifiNanStatus& status) override { + parent_.callbackType = EVENT_DISABLED; + + parent_.status = status; + + parent_.notify(); + return Void(); + } + + Return eventPublishTerminated( + uint8_t sessionId, const WifiNanStatus& status) override { + parent_.callbackType = EVENT_PUBLISH_TERMINATED; + + parent_.sessionId = sessionId; + parent_.status = status; + + parent_.notify(); + return Void(); + } + + Return eventSubscribeTerminated( + uint8_t sessionId, const WifiNanStatus& status) override { + parent_.callbackType = EVENT_SUBSCRIBE_TERMINATED; + + parent_.sessionId = sessionId; + parent_.status = status; + + parent_.notify(); + return Void(); + } + + Return eventMatch(const NanMatchInd& event) override { + parent_.callbackType = EVENT_MATCH; + + parent_.nanMatchInd = event; + + parent_.notify(); + return Void(); + } + + Return eventMatchExpired(uint8_t discoverySessionId, + uint32_t peerId) override { + parent_.callbackType = EVENT_MATCH_EXPIRED; + + parent_.sessionId = discoverySessionId; + parent_.peerId = peerId; + + parent_.notify(); + return Void(); + } + + Return eventFollowupReceived( + const NanFollowupReceivedInd& event) override { + parent_.callbackType = EVENT_FOLLOWUP_RECEIVED; + + parent_.nanFollowupReceivedInd = event; + + parent_.notify(); + return Void(); + } + + Return eventTransmitFollowup( + uint16_t id, const WifiNanStatus& status) override { + parent_.callbackType = EVENT_TRANSMIT_FOLLOWUP; + + parent_.id = id; + parent_.status = status; + + parent_.notify(); + return Void(); + } + + Return eventDataPathRequest( + const NanDataPathRequestInd& event) override { + parent_.callbackType = EVENT_DATA_PATH_REQUEST; + + parent_.nanDataPathRequestInd = event; + + parent_.notify(); + return Void(); + } + + Return eventDataPathConfirm( + const ::android::hardware::wifi::V1_0::NanDataPathConfirmInd& event) + override { + parent_.callbackType = EVENT_DATA_PATH_CONFIRM; + + parent_.nanDataPathConfirmInd = event; + + parent_.notify(); + return Void(); + } + + Return eventDataPathTerminated(uint32_t ndpInstanceId) override { + parent_.callbackType = EVENT_DATA_PATH_TERMINATED; + + parent_.ndpInstanceId = ndpInstanceId; + + parent_.notify(); + return Void(); + } + + Return eventDataPathConfirm_1_2( + const ::android::hardware::wifi::V1_2::NanDataPathConfirmInd& event) + override { + parent_.callbackType = EVENT_DATA_PATH_CONFIRM_1_2; + + parent_.nanDataPathConfirmInd_1_2 = event; + + parent_.notify(); + return Void(); + } + + Return eventDataPathScheduleUpdate( + const NanDataPathScheduleUpdateInd& event) override { + parent_.callbackType = EVENT_DATA_PATH_SCHEDULE_UPDATE; + + parent_.nanDataPathScheduleUpdateInd = event; + + parent_.notify(); + return Void(); + } + }; + + private: + // synchronization objects + std::mutex mtx_; + std::condition_variable cv_; + int count_; + + protected: + android::sp<::android::hardware::wifi::V1_4::IWifiNanIface> iwifiNanIface; + + // Data from IWifiNanIfaceEventCallback callbacks: this is the collection of + // all arguments to all callbacks. They are set by the callback + // (notifications or events) and can be retrieved by tests. + CallbackType callbackType; + uint16_t id; + WifiNanStatus status; + NanCapabilities capabilities; + uint8_t sessionId; + uint32_t ndpInstanceId; + NanClusterEventInd nanClusterEventInd; + NanMatchInd nanMatchInd; + uint32_t peerId; + NanFollowupReceivedInd nanFollowupReceivedInd; + NanDataPathRequestInd nanDataPathRequestInd; + ::android::hardware::wifi::V1_0::NanDataPathConfirmInd + nanDataPathConfirmInd; + ::android::hardware::wifi::V1_2::NanDataPathConfirmInd + nanDataPathConfirmInd_1_2; + NanDataPathScheduleUpdateInd nanDataPathScheduleUpdateInd; + + std::string GetInstanceName() { return GetParam(); } +}; + +/* + * Create: + * Ensures that an instance of the IWifiNanIface proxy object is + * successfully created. + */ +TEST_P(WifiNanIfaceHidlTest, Create) { + // The creation of a proxy object is tested as part of SetUp method. +} + +/* + * enableRequest_1_4InvalidArgs: validate that fails with invalid arguments + */ +TEST_P(WifiNanIfaceHidlTest, enableRequest_1_4InvalidArgs) { + uint16_t inputCmdId = 10; + callbackType = INVALID; + ::android::hardware::wifi::V1_4::NanEnableRequest nanEnableRequest = {}; + NanConfigRequestSupplemental nanConfigRequestSupp = {}; + ASSERT_EQ(WifiStatusCode::SUCCESS, + HIDL_INVOKE(iwifiNanIface, enableRequest_1_4, inputCmdId, + nanEnableRequest, nanConfigRequestSupp) + .code); + // wait for a callback + ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE)); + ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callbackType); + ASSERT_EQ(id, inputCmdId); + ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS); +} + +/* + * enableRequest_1_4ShimInvalidArgs: validate that fails with invalid arguments + * to the shim + */ +TEST_P(WifiNanIfaceHidlTest, enableRequest_1_4ShimInvalidArgs) { + uint16_t inputCmdId = 10; + ::android::hardware::wifi::V1_4::NanEnableRequest nanEnableRequest = {}; + nanEnableRequest.configParams.numberOfPublishServiceIdsInBeacon = + 128; // must be <= 127 + NanConfigRequestSupplemental nanConfigRequestSupp = {}; + ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, + HIDL_INVOKE(iwifiNanIface, enableRequest_1_4, inputCmdId, + nanEnableRequest, nanConfigRequestSupp) + .code); +} + +/* + * configRequest_1_4InvalidArgs: validate that fails with invalid arguments + */ +TEST_P(WifiNanIfaceHidlTest, configRequest_1_4InvalidArgs) { + uint16_t inputCmdId = 10; + callbackType = INVALID; + ::android::hardware::wifi::V1_4::NanConfigRequest nanConfigRequest = {}; + NanConfigRequestSupplemental nanConfigRequestSupp = {}; + ASSERT_EQ(WifiStatusCode::SUCCESS, + HIDL_INVOKE(iwifiNanIface, configRequest_1_4, inputCmdId, + nanConfigRequest, nanConfigRequestSupp) + .code); + // wait for a callback + ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE)); + ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callbackType); + ASSERT_EQ(id, inputCmdId); + ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS); +} + +/* + * configRequest_1_4ShimInvalidArgs: validate that fails with invalid arguments + * to the shim + */ +TEST_P(WifiNanIfaceHidlTest, configRequest_1_4ShimInvalidArgs) { + uint16_t inputCmdId = 10; + ::android::hardware::wifi::V1_4::NanConfigRequest nanConfigRequest = {}; + nanConfigRequest.numberOfPublishServiceIdsInBeacon = 128; // must be <= 127 + NanConfigRequestSupplemental nanConfigRequestSupp = {}; + ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, + HIDL_INVOKE(iwifiNanIface, configRequest_1_4, inputCmdId, + nanConfigRequest, nanConfigRequestSupp) + .code); +} From d5ae42e54009240bb244947ed2f5ccc386ffc6d0 Mon Sep 17 00:00:00 2001 From: Shuo Qian Date: Tue, 26 Nov 2019 19:37:05 -0800 Subject: [PATCH 0307/1022] Support isEnabled feature in reporting criteria for SignalStrenghth Test: build Bug: 135717625 Change-Id: Ia56b54f44345650117f884942ef917e3547277a9 --- current.txt | 4 +-- radio/1.5/IRadio.hal | 12 ++++--- radio/1.5/types.hal | 9 ++++++ .../1.5/vts/functional/radio_hidl_hal_api.cpp | 32 +++++++++++++++++++ 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/current.txt b/current.txt index 37e0640bef..e53fc52661 100644 --- a/current.txt +++ b/current.txt @@ -641,8 +641,8 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar 619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types -35cd6586225912718c599421606d69260707e43732d874f2064e28de45c87fac android.hardware.radio@1.5::types -3f1e2410d9bed4e7d41c6a589fe3a7943bc904b0066e40e0199a7c58427ac4e9 android.hardware.radio@1.5::IRadio +eaf870a7439838c66127a74e1896c4a2346979c116eb1931785ebb4d353230ae android.hardware.radio@1.5::types +584001c25a16e3a29d496cff28dee690833cd2bda5376febe01cecd476ce876f android.hardware.radio@1.5::IRadio 3afac66f21a33bc9c4b80481c7d5540038348651d9a7d8af64ea13610af138da android.hardware.radio@1.5::IRadioIndication caf00e0d942b77b17d7061b38de11e5b19e1da90d4818434cb4916ba89e30686 android.hardware.radio@1.5::IRadioResponse 55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal index 6d422bed0b..aa93ef328d 100644 --- a/radio/1.5/IRadio.hal +++ b/radio/1.5/IRadio.hal @@ -42,16 +42,20 @@ interface IRadio extends @1.4::IRadio { * -EUTRAN - RSRP/RSRQ/RSSNR * -NGRAN - SSRSRP/SSRSRQ/SSSINR * - * Note: Reporting criteria must be individually set for each RAN. For any unset reporting - * criteria, the value is implementation-defined. + * Note: Reporting criteria must be individually set for each RAN. For each RAN, if none of + * reporting criteria of any measurement is set enabled + * (see @1.5::SignalThresholdInfo.isEnabled), the reporting criteria for this RAN is + * implementation-defined. For each RAN, if any of reporting criteria of any measure is set + * enabled, the reporting criteria of the other measures in this RAN are set disabled + * (see @1.5::SignalThresholdInfo.isEnabled) until they are set enabled. * * Response callback is * IRadioResponse.setSignalStrengthReportingCriteriaResponse_1_5() * * @param serial Serial number of request. * @param signalThresholdInfo Signal threshold info including the threshold values, - * hysteresisDb, and hysteresisMs. See @1.5::SignalThresholdInfo - * for details. + * hysteresisDb, hysteresisMs and isEnabled. + * See @1.5::SignalThresholdInfo for details. * @param accessNetwork The type of network for which to apply these thresholds. */ oneway setSignalStrengthReportingCriteria_1_5(int32_t serial, diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index 664ddc441b..04a9bcfeb8 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -113,6 +113,15 @@ struct SignalThresholdInfo { * A vector size of 0 disables the use of thresholds for reporting. */ vec thresholds; + + /** + * Indicates whether the reporting criteria of the corresponding measurement is enabled + * (isEnabled==true) or disabled (isEnabled==false). + * + * If enabled, modem must trigger the report based on the criteria. + * If disabled, modem must not trigger the report based on the criteria. + */ + bool isEnabled; }; enum AccessNetwork : @1.4::AccessNetwork { diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp index 4df5b14b1c..6bf81704ca 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp @@ -29,6 +29,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_invalidHystere signalThresholdInfo.hysteresisMs = 5000; signalThresholdInfo.hysteresisDb = 10; // hysteresisDb too large given threshold list deltas signalThresholdInfo.thresholds = {-109, -103, -97, -89}; + signalThresholdInfo.isEnabled = true; Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::GERAN); @@ -52,6 +53,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_EmptyThreshold signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSI; signalThresholdInfo.hysteresisMs = 0; signalThresholdInfo.hysteresisDb = 0; + signalThresholdInfo.isEnabled = true; Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::GERAN); @@ -76,6 +78,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Geran) { signalThresholdInfo.hysteresisMs = 5000; signalThresholdInfo.hysteresisDb = 2; signalThresholdInfo.thresholds = {-109, -103, -97, -89}; + signalThresholdInfo.isEnabled = true; Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::GERAN); @@ -100,6 +103,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Utran) { signalThresholdInfo.hysteresisMs = 5000; signalThresholdInfo.hysteresisDb = 2; signalThresholdInfo.thresholds = {-110, -97, -73, -49, -25}; + signalThresholdInfo.isEnabled = true; Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::UTRAN); @@ -124,6 +128,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRP) { signalThresholdInfo.hysteresisMs = 5000; signalThresholdInfo.hysteresisDb = 2; signalThresholdInfo.thresholds = {-128, -108, -88, -68}; + signalThresholdInfo.isEnabled = true; Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN); @@ -148,6 +153,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRQ) { signalThresholdInfo.hysteresisMs = 5000; signalThresholdInfo.hysteresisDb = 2; signalThresholdInfo.thresholds = {-27, -20, -13, -6}; + signalThresholdInfo.isEnabled = true; Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN); @@ -172,6 +178,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSSNR) signalThresholdInfo.hysteresisMs = 5000; signalThresholdInfo.hysteresisDb = 2; signalThresholdInfo.thresholds = {-10, 0, 10, 20}; + signalThresholdInfo.isEnabled = true; Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN); @@ -192,6 +199,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Cdma2000) { signalThresholdInfo.hysteresisMs = 5000; signalThresholdInfo.hysteresisDb = 2; signalThresholdInfo.thresholds = {-105, -90, -75, -65}; + signalThresholdInfo.isEnabled = true; Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::CDMA2000); @@ -216,6 +224,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRP) signalThresholdInfo.hysteresisMs = 5000; signalThresholdInfo.hysteresisDb = 0; signalThresholdInfo.thresholds = {-105, -90, -75, -65}; + signalThresholdInfo.isEnabled = true; Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::NGRAN); @@ -240,6 +249,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRQ) signalThresholdInfo.hysteresisMs = 5000; signalThresholdInfo.hysteresisDb = 0; signalThresholdInfo.thresholds = {-15, -10, -5, -4}; + signalThresholdInfo.isEnabled = true; Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::NGRAN); @@ -253,6 +263,27 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRQ) ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE})); } +/* + * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN + */ +TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Disable_RSSNR) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; + signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSNR; + signalThresholdInfo.hysteresisMs = 5000; + signalThresholdInfo.hysteresisDb = 2; + signalThresholdInfo.thresholds = {-10, 0, 10, 20}; + signalThresholdInfo.isEnabled = false; + + Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( + serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); +} + /* * Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSSINR */ @@ -264,6 +295,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR) signalThresholdInfo.hysteresisMs = 5000; signalThresholdInfo.hysteresisDb = 0; signalThresholdInfo.thresholds = {-10, 3, 16, 18}; + signalThresholdInfo.isEnabled = true; Return res = radio_v1_5->setSignalStrengthReportingCriteria_1_5( serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::NGRAN); From 6d48565360a8a2bf4e0b6cc0186add980a03e98f Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Tue, 12 Nov 2019 14:59:08 -0800 Subject: [PATCH 0308/1022] audio: add audio session for device effects Add specific audio session ID for effects applied to a particular audio device. Bug: 136294538 Test: make Change-Id: Iea3e3a07f404e1075844422c740d2dc4d5163598 --- audio/common/6.0/types.hal | 5 +++++ current.txt | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal index 0c97c3686c..fa2f3a9c12 100644 --- a/audio/common/6.0/types.hal +++ b/audio/common/6.0/types.hal @@ -155,6 +155,11 @@ typedef int32_t AudioSession; */ @export(name="audio_session_t", value_prefix="AUDIO_SESSION_") enum AudioSessionConsts : int32_t { + /** + * Session for effects attached to a particular sink or source audio device + * (e.g an effect only applied to a speaker) + */ + DEVICE = -2, /** * Session for effects attached to a particular output stream * (value must be less than 0) diff --git a/current.txt b/current.txt index 37e0640bef..bdfb58fa73 100644 --- a/current.txt +++ b/current.txt @@ -593,7 +593,7 @@ bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardwar 2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn 78e4138cc8307c11fc777c3bd376e581ba4ba48196b05ca1d7cdfa515c87b48a android.hardware.audio@6.0::IStreamOut 997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback -7cc6bedbecf4c1a348c99d3f69e409ff815b90a5abf0781b054e99567fcb5c8e android.hardware.audio.common@6.0::types +0b291ebd7e94dd1cfaadd41a8b9a80bc9389bbb76f5ad5b3df94db5fe7faea9d android.hardware.audio.common@6.0::types 817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types 525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect 8d76bbe3719d051a8e9a1dcf9244f37f5b0a491feb249fa48391edf7cb4f3131 android.hardware.audio.effect@6.0::IAutomaticGainControlEffect From b983f10362c9adeb86c0ee77f785d135da819daf Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Fri, 6 Dec 2019 13:55:56 -0800 Subject: [PATCH 0309/1022] Stop location to avoid timing issue Before setting constellation blacklist, the location report should be stopped first. Otherwise, the sv status which contains blacklist constellation is still reporting and may be counted in checking SvList. According to the comments of this case, location should be turned off as 2a step. Also adding another test that a blacklist request that comes in while tracking is started, takes effect after a stop/start cycle. Bug: 144675840 Test: on device Change-Id: I04894426e8384d25f2b5e269961a9cf051cab40f --- gnss/1.1/vts/functional/gnss_hal_test.cpp | 42 +++++++ gnss/1.1/vts/functional/gnss_hal_test.h | 11 ++ .../vts/functional/gnss_hal_test_cases.cpp | 118 ++++++++++++------ 3 files changed, 133 insertions(+), 38 deletions(-) diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp index 2c8a7b1399..b87f558f28 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test.cpp +++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp @@ -175,6 +175,48 @@ bool GnssHalTest::IsGnssHalVersion_1_1() const { return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0; } +GnssConstellationType 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_status_cbq_size = gnss_cb_->sv_status_cbq_.size(); + EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait); + ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", sv_status_cbq_size, + kLocationsToAwait, location_called_count); + + // Find first non-GPS constellation to blacklist + const int kGnssSvStatusTimeout = 2; + GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN; + for (int i = 0; i < sv_status_cbq_size; ++i) { + IGnssCallback::GnssSvStatus gnss_sv_status; + gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout); + for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) { + const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv]; + if ((gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) && + (gnss_sv.constellation != GnssConstellationType::UNKNOWN) && + (gnss_sv.constellation != GnssConstellationType::GPS)) { + // found a non-GPS constellation + constellation_to_blacklist = gnss_sv.constellation; + break; + } + } + if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) { + break; + } + } + + if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) { + ALOGI("No non-GPS constellations found, constellation blacklist test less effective."); + // Proceed functionally to blacklist something. + constellation_to_blacklist = GnssConstellationType::GLONASS; + } + return constellation_to_blacklist; +} + GnssHalTest::GnssCallback::GnssCallback() : info_cbq_("system_info"), name_cbq_("name"), diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h index 169cd62c59..b0e52befe2 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test.h +++ b/gnss/1.1/vts/functional/gnss_hal_test.h @@ -28,6 +28,7 @@ using android::hardware::Void; using android::hardware::gnss::V1_0::GnssLocation; using android::hardware::gnss::common::GnssCallbackEventQueue; +using android::hardware::gnss::V1_0::GnssConstellationType; using android::hardware::gnss::V1_0::GnssLocationFlags; using android::hardware::gnss::V1_1::IGnss; using android::hardware::gnss::V1_1::IGnssCallback; @@ -139,6 +140,16 @@ class GnssHalTest : public testing::TestWithParam { */ bool IsGnssHalVersion_1_1() const; + /* + * 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 startLocationAndGetNonGpsConstellation(); + sp gnss_hal_; // GNSS HAL to call into sp gnss_cb_; // Primary callback interface }; diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp index 79da84ac10..afba61fe44 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp @@ -352,7 +352,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. @@ -361,50 +361,19 @@ 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_1_1()) { ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1."); return; } 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_status_cbq_size = gnss_cb_->sv_status_cbq_.size(); - EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait); - ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", sv_status_cbq_size, - kLocationsToAwait, location_called_count); - // Find first non-GPS constellation to blacklist - const int kGnssSvStatusTimeout = 2; - GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN; - for (int i = 0; i < sv_status_cbq_size; ++i) { - IGnssCallback::GnssSvStatus gnss_sv_status; - gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout); - for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) { - const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv]; - if ((gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) && - (gnss_sv.constellation != GnssConstellationType::UNKNOWN) && - (gnss_sv.constellation != GnssConstellationType::GPS)) { - // found a non-GPS constellation - constellation_to_blacklist = gnss_sv.constellation; - break; - } - } - if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) { - break; - } - } + GnssConstellationType constellation_to_blacklist = startLocationAndGetNonGpsConstellation(); + + // Turns off location + StopAndClearLocations(); - if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) { - ALOGI("No non-GPS constellations found, constellation blacklist test less effective."); - // Proceed functionally to blacklist something. - constellation_to_blacklist = GnssConstellationType::GLONASS; - } IGnssConfiguration::BlacklistedSource source_to_blacklist; source_to_blacklist.constellation = constellation_to_blacklist; source_to_blacklist.svid = 0; // documented wildcard for all satellites in this constellation @@ -418,6 +387,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); @@ -429,10 +399,82 @@ TEST_P(GnssHalTest, BlacklistConstellation) { StartAndCheckLocations(kLocationsToAwait); // Tolerate 1 less sv status to handle edge cases in reporting. - sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size(); + int sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size(); EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait); ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_status_cbq_size, kLocationsToAwait); + const int kGnssSvStatusTimeout = 2; + for (int i = 0; i < sv_status_cbq_size; ++i) { + IGnssCallback::GnssSvStatus gnss_sv_status; + gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout); + for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) { + const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv]; + EXPECT_FALSE((gnss_sv.constellation == source_to_blacklist.constellation) && + (gnss_sv.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) Turns off location, and blacklist first non-GPS constellations. + * 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_1_1()) { + ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1."); + return; + } + + const int kLocationsToAwait = 3; + // Find first non-GPS constellation to blacklist + GnssConstellationType constellation_to_blacklist = startLocationAndGetNonGpsConstellation(); + + IGnssConfiguration::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 still 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_status_cbq_.reset(); + + gnss_cb_->location_cbq_.reset(); + StartAndCheckLocations(kLocationsToAwait); + + // Tolerate 1 less sv status to handle edge cases in reporting. + int sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size(); + EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait); + ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_status_cbq_size, + kLocationsToAwait); + const int kGnssSvStatusTimeout = 2; for (int i = 0; i < sv_status_cbq_size; ++i) { IGnssCallback::GnssSvStatus gnss_sv_status; gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout); From 1c1fdca026ab83817fa38c8ca4cec48e33a714fc Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Fri, 15 Nov 2019 14:20:34 -0800 Subject: [PATCH 0310/1022] Protobuf message converter should be a public utility library Test: Built, and flashed to Osprey (go/enable-google-vhal-on-osprey) ``` # See value changed in Vehicle HAL tab, KitchenSink app: $ python packages/services/Car/tools/emulator/prop_event_simulator.py --property VEHICLEPROPERTY_HVAC_AC_ON --area 0 --value 1 # unit tests $ atest android.hardware.automotive.vehicle@2.0-default-impl-unit-tests ``` Change-Id: I3841870614f316f2f0e2f54283674223a0b036f4 --- automotive/vehicle/2.0/default/Android.bp | 16 ++ .../impl/vhal_v2_0/ProtoMessageConverter.cpp | 216 ++++++++++++++++++ .../impl/vhal_v2_0/ProtoMessageConverter.h | 56 +++++ .../impl/vhal_v2_0/VehicleEmulator.cpp | 83 +------ .../tests/ProtoMessageConverter_test.cpp | 110 +++++++++ 5 files changed, 401 insertions(+), 80 deletions(-) create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp index f9c25d1d0e..2050038d62 100644 --- a/automotive/vehicle/2.0/default/Android.bp +++ b/automotive/vehicle/2.0/default/Android.bp @@ -62,6 +62,7 @@ cc_library_static { "impl/vhal_v2_0/EmulatedVehicleHal.cpp", "impl/vhal_v2_0/VehicleEmulator.cpp", "impl/vhal_v2_0/PipeComm.cpp", + "impl/vhal_v2_0/ProtoMessageConverter.cpp", "impl/vhal_v2_0/SocketComm.cpp", "impl/vhal_v2_0/LinearFakeValueGenerator.cpp", "impl/vhal_v2_0/JsonFakeValueGenerator.cpp", @@ -98,6 +99,21 @@ cc_test { test_suites: ["general-tests"], } +cc_test { + name: "android.hardware.automotive.vehicle@2.0-default-impl-unit-tests", + vendor: true, + defaults: ["vhal_v2_0_defaults"], + srcs: [ + "impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp", + ], + static_libs: [ + "android.hardware.automotive.vehicle@2.0-default-impl-lib", + "android.hardware.automotive.vehicle@2.0-libproto-native", + "libprotobuf-cpp-lite", + ], + test_suites: ["general-tests"], +} + cc_binary { name: "android.hardware.automotive.vehicle@2.0-service", defaults: ["vhal_v2_0_defaults"], diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp new file mode 100644 index 0000000000..db653be5d7 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp @@ -0,0 +1,216 @@ +/* + * 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 "ProtoMsgConverter" + +#include +#include + +#include + +#include + +#include "ProtoMessageConverter.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +namespace proto_msg_converter { + +// If protobuf class PROTO_VALUE has value in field PROTO_VARNAME, +// then casting the value by CAST and copying it to VHAL_TYPE_VALUE->VHAL_TYPE_VARNAME +#define CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, \ + VHAL_TYPE_VARNAME, CAST) \ + if (PROTO_VALUE.has_##PROTO_VARNAME()) { \ + (VHAL_TYPE_VALUE)->VHAL_TYPE_VARNAME = CAST(PROTO_VALUE.PROTO_VARNAME()); \ + } + +// Copying the vector PROTO_VECNAME of protobuf class PROTO_VALUE to +// VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME, every element of PROTO_VECNAME +// is casted by CAST +#define CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, \ + VHAL_TYPE_VECNAME, CAST) \ + do { \ + (VHAL_TYPE_VALUE)->VHAL_TYPE_VECNAME.resize(PROTO_VALUE.PROTO_VECNAME##_size()); \ + size_t idx = 0; \ + for (auto& value : PROTO_VALUE.PROTO_VECNAME()) { \ + VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME[idx++] = CAST(value); \ + } \ + } while (0) + +// If protobuf message has value in field PROTO_VARNAME, +// then copying it to VHAL_TYPE_VALUE->VHAL_TYPE_VARNAME +#define CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, \ + VHAL_TYPE_VARNAME) \ + CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE( \ + PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, VHAL_TYPE_VARNAME, /*NO CAST*/) + +// Copying the vector PROTO_VECNAME of protobuf class PROTO_VALUE to +// VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME +#define COPY_PROTOBUF_VEC_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, \ + VHAL_TYPE_VECNAME) \ + CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE( \ + PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, VHAL_TYPE_VECNAME, /*NO CAST*/) + +void toProto(emulator::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg) { + protoCfg->set_prop(cfg.prop); + protoCfg->set_access(toInt(cfg.access)); + protoCfg->set_change_mode(toInt(cfg.changeMode)); + protoCfg->set_value_type(toInt(getPropType(cfg.prop))); + + for (auto& configElement : cfg.configArray) { + protoCfg->add_config_array(configElement); + } + + if (cfg.configString.size() > 0) { + protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size()); + } + + protoCfg->clear_area_configs(); + for (auto& areaConfig : cfg.areaConfigs) { + auto* protoACfg = protoCfg->add_area_configs(); + protoACfg->set_area_id(areaConfig.areaId); + + switch (getPropType(cfg.prop)) { + case VehiclePropertyType::STRING: + case VehiclePropertyType::BOOLEAN: + case VehiclePropertyType::INT32_VEC: + case VehiclePropertyType::INT64_VEC: + case VehiclePropertyType::FLOAT_VEC: + case VehiclePropertyType::BYTES: + case VehiclePropertyType::MIXED: + // Do nothing. These types don't have min/max values + break; + case VehiclePropertyType::INT64: + protoACfg->set_min_int64_value(areaConfig.minInt64Value); + protoACfg->set_max_int64_value(areaConfig.maxInt64Value); + break; + case VehiclePropertyType::FLOAT: + protoACfg->set_min_float_value(areaConfig.minFloatValue); + protoACfg->set_max_float_value(areaConfig.maxFloatValue); + break; + case VehiclePropertyType::INT32: + protoACfg->set_min_int32_value(areaConfig.minInt32Value); + protoACfg->set_max_int32_value(areaConfig.maxInt32Value); + break; + default: + ALOGW("%s: Unknown property type: 0x%x", __func__, toInt(getPropType(cfg.prop))); + break; + } + } + + protoCfg->set_min_sample_rate(cfg.minSampleRate); + protoCfg->set_max_sample_rate(cfg.maxSampleRate); +} + +void fromProto(VehiclePropConfig* cfg, const emulator::VehiclePropConfig& protoCfg) { + CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, prop, cfg, prop); + CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, access, cfg, access, + static_cast); + CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, change_mode, cfg, changeMode, + static_cast); + COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoCfg, config_array, cfg, configArray); + CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, config_string, cfg, configString); + + auto cast_to_acfg = [](const emulator::VehicleAreaConfig& protoAcfg) { + VehicleAreaConfig acfg; + CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, area_id, &acfg, areaId); + CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_int32_value, &acfg, minInt32Value); + CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_int32_value, &acfg, maxInt32Value); + CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_int64_value, &acfg, minInt64Value); + CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_int64_value, &acfg, maxInt64Value); + CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_float_value, &acfg, minFloatValue); + CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_float_value, &acfg, maxFloatValue); + return acfg; + }; + + CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoCfg, area_configs, cfg, areaConfigs, cast_to_acfg); + + CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, min_sample_rate, cfg, minSampleRate); + CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, max_sample_rate, cfg, maxSampleRate); +} + +void toProto(emulator::VehiclePropValue* protoVal, const VehiclePropValue& val) { + protoVal->set_prop(val.prop); + protoVal->set_value_type(toInt(getPropType(val.prop))); + protoVal->set_timestamp(val.timestamp); + protoVal->set_status((emulator::VehiclePropStatus)(val.status)); + protoVal->set_area_id(val.areaId); + + // Copy value data if it is set. + // - for bytes and strings, this is indicated by size > 0 + // - for int32, int64, and float, copy the values if vectors have data + if (val.value.stringValue.size() > 0) { + protoVal->set_string_value(val.value.stringValue.c_str(), val.value.stringValue.size()); + } + + if (val.value.bytes.size() > 0) { + protoVal->set_bytes_value(val.value.bytes.data(), val.value.bytes.size()); + } + + for (auto& int32Value : val.value.int32Values) { + protoVal->add_int32_values(int32Value); + } + + for (auto& int64Value : val.value.int64Values) { + protoVal->add_int64_values(int64Value); + } + + for (auto& floatValue : val.value.floatValues) { + protoVal->add_float_values(floatValue); + } +} + +void fromProto(VehiclePropValue* val, const emulator::VehiclePropValue& protoVal) { + CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, prop, val, prop); + CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, timestamp, val, timestamp); + CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, status, val, status, + static_cast); + CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, area_id, val, areaId); + + // Copy value data + CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, string_value, val, value.stringValue); + + auto cast_proto_bytes_to_vec = [](auto&& bytes) { + return std::vector(bytes.begin(), bytes.end()); + }; + CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, bytes_value, val, value.bytes, + cast_proto_bytes_to_vec); + + COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, int32_values, val, value.int32Values); + COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, int64_values, val, value.int64Values); + COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, float_values, val, value.floatValues); +} + +#undef COPY_PROTOBUF_VEC_TO_VHAL_TYPE +#undef CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE +#undef CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE +#undef CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE + +} // namespace proto_msg_converter + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h new file mode 100644 index 0000000000..90e6540d43 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_impl_ProtoMessageConverter_H_ +#define android_hardware_automotive_vehicle_V2_0_impl_ProtoMessageConverter_H_ + +#include + +#include "VehicleHalProto.pb.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +namespace proto_msg_converter { + +// VehiclePropConfig + +void toProto(emulator::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg); + +void fromProto(VehiclePropConfig* cfg, const emulator::VehiclePropConfig& protoCfg); + +// VehiclePropValue + +void toProto(emulator::VehiclePropValue* protoVal, const VehiclePropValue& val); + +void fromProto(VehiclePropValue* val, const emulator::VehiclePropValue& protoVal); + +} // namespace proto_msg_converter + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_0_impl_VehicleHalEmulator_H_ diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp index 9dc70859c9..2a68900a3f 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp @@ -24,6 +24,7 @@ #include #include "PipeComm.h" +#include "ProtoMessageConverter.h" #include "SocketComm.h" #include "VehicleEmulator.h" @@ -217,90 +218,12 @@ void VehicleEmulator::processMessage(emulator::EmulatorMessage const& rxMsg, void VehicleEmulator::populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg) { - protoCfg->set_prop(cfg.prop); - protoCfg->set_access(toInt(cfg.access)); - protoCfg->set_change_mode(toInt(cfg.changeMode)); - protoCfg->set_value_type(toInt(getPropType(cfg.prop))); - - for (auto& configElement : cfg.configArray) { - protoCfg->add_config_array(configElement); - } - - if (cfg.configString.size() > 0) { - protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size()); - } - - // Populate the min/max values based on property type - switch (getPropType(cfg.prop)) { - case VehiclePropertyType::STRING: - case VehiclePropertyType::BOOLEAN: - case VehiclePropertyType::INT32_VEC: - case VehiclePropertyType::INT64_VEC: - case VehiclePropertyType::FLOAT_VEC: - case VehiclePropertyType::BYTES: - case VehiclePropertyType::MIXED: - // Do nothing. These types don't have min/max values - break; - case VehiclePropertyType::INT64: - if (cfg.areaConfigs.size() > 0) { - emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs(); - aCfg->set_min_int64_value(cfg.areaConfigs[0].minInt64Value); - aCfg->set_max_int64_value(cfg.areaConfigs[0].maxInt64Value); - } - break; - case VehiclePropertyType::FLOAT: - if (cfg.areaConfigs.size() > 0) { - emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs(); - aCfg->set_min_float_value(cfg.areaConfigs[0].minFloatValue); - aCfg->set_max_float_value(cfg.areaConfigs[0].maxFloatValue); - } - break; - case VehiclePropertyType::INT32: - if (cfg.areaConfigs.size() > 0) { - emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs(); - aCfg->set_min_int32_value(cfg.areaConfigs[0].minInt32Value); - aCfg->set_max_int32_value(cfg.areaConfigs[0].maxInt32Value); - } - break; - default: - ALOGW("%s: Unknown property type: 0x%x", __func__, toInt(getPropType(cfg.prop))); - break; - } - - protoCfg->set_min_sample_rate(cfg.minSampleRate); - protoCfg->set_max_sample_rate(cfg.maxSampleRate); + return proto_msg_converter::toProto(protoCfg, cfg); } void VehicleEmulator::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal, const VehiclePropValue* val) { - protoVal->set_prop(val->prop); - protoVal->set_value_type(toInt(getPropType(val->prop))); - protoVal->set_timestamp(val->timestamp); - protoVal->set_status((emulator::VehiclePropStatus)(val->status)); - protoVal->set_area_id(val->areaId); - - // Copy value data if it is set. - // - for bytes and strings, this is indicated by size > 0 - // - for int32, int64, and float, copy the values if vectors have data - if (val->value.stringValue.size() > 0) { - protoVal->set_string_value(val->value.stringValue.c_str(), val->value.stringValue.size()); - } - - if (val->value.bytes.size() > 0) { - protoVal->set_bytes_value(val->value.bytes.data(), val->value.bytes.size()); - } - - for (auto& int32Value : val->value.int32Values) { - protoVal->add_int32_values(int32Value); - } - - for (auto& int64Value : val->value.int64Values) { - protoVal->add_int64_values(int64Value); - } - - for (auto& floatValue : val->value.floatValues) { - protoVal->add_float_values(floatValue); - } + return proto_msg_converter::toProto(protoVal, *val); } } // impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp new file mode 100644 index 0000000000..d16c7c40f5 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp @@ -0,0 +1,110 @@ +/* + * 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. + */ + +#include + +#include + +#include "vhal_v2_0/DefaultConfig.h" +#include "vhal_v2_0/ProtoMessageConverter.h" +#include "vhal_v2_0/VehicleUtils.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { +namespace impl { +namespace proto_msg_converter { + +namespace { + +void CheckPropConfigConversion(const VehiclePropConfig& config) { + emulator::VehiclePropConfig protoCfg; + VehiclePropConfig tmpConfig; + + toProto(&protoCfg, config); + fromProto(&tmpConfig, protoCfg); + + EXPECT_EQ(config.prop, tmpConfig.prop); + EXPECT_EQ(config.access, tmpConfig.access); + EXPECT_EQ(config.changeMode, tmpConfig.changeMode); + EXPECT_EQ(config.configString, tmpConfig.configString); + EXPECT_EQ(config.minSampleRate, tmpConfig.minSampleRate); + EXPECT_EQ(config.maxSampleRate, tmpConfig.maxSampleRate); + EXPECT_EQ(config.configArray, tmpConfig.configArray); + + EXPECT_EQ(config.areaConfigs.size(), tmpConfig.areaConfigs.size()); + + auto cfgType = getPropType(config.prop); + for (size_t idx = 0; idx < std::min(config.areaConfigs.size(), tmpConfig.areaConfigs.size()); + ++idx) { + auto& lhs = config.areaConfigs[idx]; + auto& rhs = tmpConfig.areaConfigs[idx]; + EXPECT_EQ(lhs.areaId, rhs.areaId); + switch (cfgType) { + case VehiclePropertyType::INT64: + EXPECT_EQ(lhs.minInt64Value, rhs.minInt64Value); + EXPECT_EQ(lhs.maxInt64Value, rhs.maxInt64Value); + break; + case VehiclePropertyType::FLOAT: + EXPECT_EQ(lhs.minFloatValue, rhs.minFloatValue); + EXPECT_EQ(lhs.maxFloatValue, rhs.maxFloatValue); + break; + case VehiclePropertyType::INT32: + EXPECT_EQ(lhs.minInt32Value, rhs.minInt32Value); + EXPECT_EQ(lhs.maxInt32Value, rhs.maxInt32Value); + break; + default: + // ignore min/max values + break; + } + } +} + +void CheckPropValueConversion(const VehiclePropValue& val) { + emulator::VehiclePropValue protoVal; + VehiclePropValue tmpVal; + + toProto(&protoVal, val); + fromProto(&tmpVal, protoVal); + + EXPECT_EQ(val, tmpVal); +} + +TEST(ProtoMessageConverterTest, basic) { + for (auto& property : impl::kVehicleProperties) { + CheckPropConfigConversion(property.config); + + VehiclePropValue prop; + prop.timestamp = elapsedRealtimeNano(); + prop.areaId = 123; + prop.prop = property.config.prop; + prop.value = property.initialValue; + prop.status = VehiclePropertyStatus::ERROR; + CheckPropValueConversion(prop); + } +} + +} // namespace + +} // namespace proto_msg_converter +} // namespace impl +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android From 5deac06ad9034f0ea756ce22aba76d661866984b Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Fri, 22 Nov 2019 15:49:14 -0800 Subject: [PATCH 0311/1022] A more generalized package name for VHal proto IDLs Test: build; test (and submit) with ag/9868729 Change-Id: Iacdf518d8c90485430a009e341dd1fd705b7ee83 --- .../2.0/default/impl/vhal_v2_0/CommConn.cpp | 6 +- .../2.0/default/impl/vhal_v2_0/CommConn.h | 6 +- .../impl/vhal_v2_0/ProtoMessageConverter.cpp | 12 ++-- .../impl/vhal_v2_0/ProtoMessageConverter.h | 8 +-- .../2.0/default/impl/vhal_v2_0/SocketComm.cpp | 2 +- .../2.0/default/impl/vhal_v2_0/SocketComm.h | 2 +- .../impl/vhal_v2_0/VehicleEmulator.cpp | 66 +++++++++---------- .../default/impl/vhal_v2_0/VehicleEmulator.h | 10 +-- .../vhal_v2_0/proto/VehicleHalProto.proto | 2 +- .../impl/vhal_v2_0/proto/VehicleServer.proto | 6 +- .../tests/ProtoMessageConverter_test.cpp | 4 +- 11 files changed, 62 insertions(+), 62 deletions(-) diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp index bf1de8165a..136b2e0758 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp @@ -41,7 +41,7 @@ void CommConn::stop() { } } -void CommConn::sendMessage(emulator::EmulatorMessage const& msg) { +void CommConn::sendMessage(vhal_proto::EmulatorMessage const& msg) { int numBytes = msg.ByteSize(); std::vector buffer(static_cast(numBytes)); if (!msg.SerializeToArray(buffer.data(), numBytes)) { @@ -61,9 +61,9 @@ void CommConn::readThread() { break; } - emulator::EmulatorMessage rxMsg; + vhal_proto::EmulatorMessage rxMsg; if (rxMsg.ParseFromArray(buffer.data(), static_cast(buffer.size()))) { - emulator::EmulatorMessage respMsg; + vhal_proto::EmulatorMessage respMsg; mMessageProcessor->processMessage(rxMsg, respMsg); sendMessage(respMsg); diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h index 87b0dfc17d..6d36da417f 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h @@ -44,8 +44,8 @@ class MessageProcessor { * Process a single message received over a CommConn. Populate the given respMsg with the reply * message we should send. */ - virtual void processMessage(emulator::EmulatorMessage const& rxMsg, - emulator::EmulatorMessage& respMsg) = 0; + virtual void processMessage(vhal_proto::EmulatorMessage const& rxMsg, + vhal_proto::EmulatorMessage& respMsg) = 0; }; /** @@ -93,7 +93,7 @@ class CommConn { /** * Serialized and send the given message to the other side. */ - void sendMessage(emulator::EmulatorMessage const& msg); + void sendMessage(vhal_proto::EmulatorMessage const& msg); protected: std::unique_ptr mReadThread; diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp index db653be5d7..77cb114164 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp @@ -70,7 +70,7 @@ namespace proto_msg_converter { CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE( \ PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, VHAL_TYPE_VECNAME, /*NO CAST*/) -void toProto(emulator::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg) { +void toProto(vhal_proto::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg) { protoCfg->set_prop(cfg.prop); protoCfg->set_access(toInt(cfg.access)); protoCfg->set_change_mode(toInt(cfg.changeMode)); @@ -121,7 +121,7 @@ void toProto(emulator::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg protoCfg->set_max_sample_rate(cfg.maxSampleRate); } -void fromProto(VehiclePropConfig* cfg, const emulator::VehiclePropConfig& protoCfg) { +void fromProto(VehiclePropConfig* cfg, const vhal_proto::VehiclePropConfig& protoCfg) { CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, prop, cfg, prop); CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, access, cfg, access, static_cast); @@ -130,7 +130,7 @@ void fromProto(VehiclePropConfig* cfg, const emulator::VehiclePropConfig& protoC COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoCfg, config_array, cfg, configArray); CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, config_string, cfg, configString); - auto cast_to_acfg = [](const emulator::VehicleAreaConfig& protoAcfg) { + auto cast_to_acfg = [](const vhal_proto::VehicleAreaConfig& protoAcfg) { VehicleAreaConfig acfg; CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, area_id, &acfg, areaId); CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_int32_value, &acfg, minInt32Value); @@ -148,11 +148,11 @@ void fromProto(VehiclePropConfig* cfg, const emulator::VehiclePropConfig& protoC CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, max_sample_rate, cfg, maxSampleRate); } -void toProto(emulator::VehiclePropValue* protoVal, const VehiclePropValue& val) { +void toProto(vhal_proto::VehiclePropValue* protoVal, const VehiclePropValue& val) { protoVal->set_prop(val.prop); protoVal->set_value_type(toInt(getPropType(val.prop))); protoVal->set_timestamp(val.timestamp); - protoVal->set_status((emulator::VehiclePropStatus)(val.status)); + protoVal->set_status((vhal_proto::VehiclePropStatus)(val.status)); protoVal->set_area_id(val.areaId); // Copy value data if it is set. @@ -179,7 +179,7 @@ void toProto(emulator::VehiclePropValue* protoVal, const VehiclePropValue& val) } } -void fromProto(VehiclePropValue* val, const emulator::VehiclePropValue& protoVal) { +void fromProto(VehiclePropValue* val, const vhal_proto::VehiclePropValue& protoVal) { CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, prop, val, prop); CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, timestamp, val, timestamp); CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, status, val, status, diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h index 90e6540d43..01f3beb49b 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h @@ -33,15 +33,15 @@ namespace proto_msg_converter { // VehiclePropConfig -void toProto(emulator::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg); +void toProto(vhal_proto::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg); -void fromProto(VehiclePropConfig* cfg, const emulator::VehiclePropConfig& protoCfg); +void fromProto(VehiclePropConfig* cfg, const vhal_proto::VehiclePropConfig& protoCfg); // VehiclePropValue -void toProto(emulator::VehiclePropValue* protoVal, const VehiclePropValue& val); +void toProto(vhal_proto::VehiclePropValue* protoVal, const VehiclePropValue& val); -void fromProto(VehiclePropValue* val, const emulator::VehiclePropValue& protoVal); +void fromProto(VehiclePropValue* val, const vhal_proto::VehiclePropValue& protoVal); } // namespace proto_msg_converter diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp index 068333cf36..916c320b90 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp @@ -60,7 +60,7 @@ void SocketComm::stop() { } } -void SocketComm::sendMessage(emulator::EmulatorMessage const& msg) { +void SocketComm::sendMessage(vhal_proto::EmulatorMessage const& msg) { std::lock_guard lock(mMutex); for (std::unique_ptr const& conn : mOpenConnections) { conn->sendMessage(msg); diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h index 88b852bb33..52326b9fc7 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h @@ -47,7 +47,7 @@ class SocketComm { /** * Serialized and send the given message to all connected clients. */ - void sendMessage(emulator::EmulatorMessage const& msg); + void sendMessage(vhal_proto::EmulatorMessage const& msg); private: int mListenFd; diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp index 2a68900a3f..263ca62f42 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp @@ -63,11 +63,11 @@ VehicleEmulator::~VehicleEmulator() { * changed. */ void VehicleEmulator::doSetValueFromClient(const VehiclePropValue& propValue) { - emulator::EmulatorMessage msg; - emulator::VehiclePropValue *val = msg.add_value(); + vhal_proto::EmulatorMessage msg; + vhal_proto::VehiclePropValue* val = msg.add_value(); populateProtoVehiclePropValue(val, &propValue); - msg.set_status(emulator::RESULT_OK); - msg.set_msg_type(emulator::SET_PROPERTY_ASYNC); + msg.set_status(vhal_proto::RESULT_OK); + msg.set_msg_type(vhal_proto::SET_PROPERTY_ASYNC); mSocketComm->sendMessage(msg); if (mPipeComm) { @@ -78,17 +78,17 @@ void VehicleEmulator::doSetValueFromClient(const VehiclePropValue& propValue) { void VehicleEmulator::doGetConfig(VehicleEmulator::EmulatorMessage const& rxMsg, VehicleEmulator::EmulatorMessage& respMsg) { std::vector configs = mHal->listProperties(); - emulator::VehiclePropGet getProp = rxMsg.prop(0); + vhal_proto::VehiclePropGet getProp = rxMsg.prop(0); - respMsg.set_msg_type(emulator::GET_CONFIG_RESP); - respMsg.set_status(emulator::ERROR_INVALID_PROPERTY); + respMsg.set_msg_type(vhal_proto::GET_CONFIG_RESP); + respMsg.set_status(vhal_proto::ERROR_INVALID_PROPERTY); for (auto& config : configs) { // Find the config we are looking for if (config.prop == getProp.prop()) { - emulator::VehiclePropConfig* protoCfg = respMsg.add_config(); + vhal_proto::VehiclePropConfig* protoCfg = respMsg.add_config(); populateProtoVehicleConfig(protoCfg, config); - respMsg.set_status(emulator::RESULT_OK); + respMsg.set_status(vhal_proto::RESULT_OK); break; } } @@ -98,11 +98,11 @@ void VehicleEmulator::doGetConfigAll(VehicleEmulator::EmulatorMessage const& /* VehicleEmulator::EmulatorMessage& respMsg) { std::vector configs = mHal->listProperties(); - respMsg.set_msg_type(emulator::GET_CONFIG_ALL_RESP); - respMsg.set_status(emulator::RESULT_OK); + respMsg.set_msg_type(vhal_proto::GET_CONFIG_ALL_RESP); + respMsg.set_status(vhal_proto::RESULT_OK); for (auto& config : configs) { - emulator::VehiclePropConfig* protoCfg = respMsg.add_config(); + vhal_proto::VehiclePropConfig* protoCfg = respMsg.add_config(); populateProtoVehicleConfig(protoCfg, config); } } @@ -110,11 +110,11 @@ void VehicleEmulator::doGetConfigAll(VehicleEmulator::EmulatorMessage const& /* void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage const& rxMsg, VehicleEmulator::EmulatorMessage& respMsg) { int32_t areaId = 0; - emulator::VehiclePropGet getProp = rxMsg.prop(0); + vhal_proto::VehiclePropGet getProp = rxMsg.prop(0); int32_t propId = getProp.prop(); - emulator::Status status = emulator::ERROR_INVALID_PROPERTY; + vhal_proto::Status status = vhal_proto::ERROR_INVALID_PROPERTY; - respMsg.set_msg_type(emulator::GET_PROPERTY_RESP); + respMsg.set_msg_type(vhal_proto::GET_PROPERTY_RESP); if (getProp.has_area_id()) { areaId = getProp.area_id(); @@ -128,9 +128,9 @@ void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage const& rxMs StatusCode halStatus; auto val = mHal->get(request, &halStatus); if (val != nullptr) { - emulator::VehiclePropValue* protoVal = respMsg.add_value(); + vhal_proto::VehiclePropValue* protoVal = respMsg.add_value(); populateProtoVehiclePropValue(protoVal, val.get()); - status = emulator::RESULT_OK; + status = vhal_proto::RESULT_OK; } } @@ -139,12 +139,12 @@ void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage const& rxMs void VehicleEmulator::doGetPropertyAll(VehicleEmulator::EmulatorMessage const& /* rxMsg */, VehicleEmulator::EmulatorMessage& respMsg) { - respMsg.set_msg_type(emulator::GET_PROPERTY_ALL_RESP); - respMsg.set_status(emulator::RESULT_OK); + respMsg.set_msg_type(vhal_proto::GET_PROPERTY_ALL_RESP); + respMsg.set_status(vhal_proto::RESULT_OK); { for (const auto& prop : mHal->getAllProperties()) { - emulator::VehiclePropValue* protoVal = respMsg.add_value(); + vhal_proto::VehiclePropValue* protoVal = respMsg.add_value(); populateProtoVehiclePropValue(protoVal, &prop); } } @@ -152,7 +152,7 @@ void VehicleEmulator::doGetPropertyAll(VehicleEmulator::EmulatorMessage const& / void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage const& rxMsg, VehicleEmulator::EmulatorMessage& respMsg) { - emulator::VehiclePropValue protoVal = rxMsg.value(0); + vhal_proto::VehiclePropValue protoVal = rxMsg.value(0); VehiclePropValue val = { .timestamp = elapsedRealtimeNano(), .areaId = protoVal.area_id(), @@ -160,7 +160,7 @@ void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage const& rxMs .status = (VehiclePropertyStatus)protoVal.status(), }; - respMsg.set_msg_type(emulator::SET_PROPERTY_RESP); + respMsg.set_msg_type(vhal_proto::SET_PROPERTY_RESP); // Copy value data if it is set. This automatically handles complex data types if needed. if (protoVal.has_string_value()) { @@ -188,40 +188,40 @@ void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage const& rxMs } bool halRes = mHal->setPropertyFromVehicle(val); - respMsg.set_status(halRes ? emulator::RESULT_OK : emulator::ERROR_INVALID_PROPERTY); + respMsg.set_status(halRes ? vhal_proto::RESULT_OK : vhal_proto::ERROR_INVALID_PROPERTY); } -void VehicleEmulator::processMessage(emulator::EmulatorMessage const& rxMsg, - emulator::EmulatorMessage& respMsg) { +void VehicleEmulator::processMessage(vhal_proto::EmulatorMessage const& rxMsg, + vhal_proto::EmulatorMessage& respMsg) { switch (rxMsg.msg_type()) { - case emulator::GET_CONFIG_CMD: + case vhal_proto::GET_CONFIG_CMD: doGetConfig(rxMsg, respMsg); break; - case emulator::GET_CONFIG_ALL_CMD: + case vhal_proto::GET_CONFIG_ALL_CMD: doGetConfigAll(rxMsg, respMsg); break; - case emulator::GET_PROPERTY_CMD: + case vhal_proto::GET_PROPERTY_CMD: doGetProperty(rxMsg, respMsg); break; - case emulator::GET_PROPERTY_ALL_CMD: + case vhal_proto::GET_PROPERTY_ALL_CMD: doGetPropertyAll(rxMsg, respMsg); break; - case emulator::SET_PROPERTY_CMD: + case vhal_proto::SET_PROPERTY_CMD: doSetProperty(rxMsg, respMsg); break; default: ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type()); - respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD); + respMsg.set_status(vhal_proto::ERROR_UNIMPLEMENTED_CMD); break; } } -void VehicleEmulator::populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg, +void VehicleEmulator::populateProtoVehicleConfig(vhal_proto::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg) { return proto_msg_converter::toProto(protoCfg, cfg); } -void VehicleEmulator::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal, +void VehicleEmulator::populateProtoVehiclePropValue(vhal_proto::VehiclePropValue* protoVal, const VehiclePropValue* val) { return proto_msg_converter::toProto(protoVal, *val); } diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h index 58e387a749..82947beef1 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h @@ -72,21 +72,21 @@ class VehicleEmulator : public MessageProcessor { virtual ~VehicleEmulator(); void doSetValueFromClient(const VehiclePropValue& propValue); - void processMessage(emulator::EmulatorMessage const& rxMsg, - emulator::EmulatorMessage& respMsg) override; + void processMessage(vhal_proto::EmulatorMessage const& rxMsg, + vhal_proto::EmulatorMessage& respMsg) override; private: friend class ConnectionThread; - using EmulatorMessage = emulator::EmulatorMessage; + using EmulatorMessage = vhal_proto::EmulatorMessage; void doGetConfig(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg); void doGetConfigAll(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg); void doGetProperty(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg); void doGetPropertyAll(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg); void doSetProperty(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg); - void populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg, + void populateProtoVehicleConfig(vhal_proto::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg); - void populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal, + void populateProtoVehiclePropValue(vhal_proto::VehiclePropValue* protoVal, const VehiclePropValue* val); private: diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto index 04df5a8a21..4902a5d8fb 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto @@ -16,7 +16,7 @@ syntax = "proto2"; -package emulator; +package vhal_proto; // CMD messages are from workstation --> VHAL // RESP messages are from VHAL --> workstation diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto index 7ce3c32273..2cc6595248 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto @@ -14,9 +14,9 @@ * limitations under the License. */ -syntax = "proto2"; +syntax = "proto3"; -package emulator; +package vhal_proto; import "google/protobuf/empty.proto"; import "VehicleHalProto.proto"; @@ -32,7 +32,7 @@ enum VehicleHalStatusCode { } message VehicleHalCallStatus { - required VehicleHalStatusCode status_code = 1; + VehicleHalStatusCode status_code = 1; } service VehicleServer { diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp index d16c7c40f5..3817e4406e 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp @@ -33,7 +33,7 @@ namespace proto_msg_converter { namespace { void CheckPropConfigConversion(const VehiclePropConfig& config) { - emulator::VehiclePropConfig protoCfg; + vhal_proto::VehiclePropConfig protoCfg; VehiclePropConfig tmpConfig; toProto(&protoCfg, config); @@ -76,7 +76,7 @@ void CheckPropConfigConversion(const VehiclePropConfig& config) { } void CheckPropValueConversion(const VehiclePropValue& val) { - emulator::VehiclePropValue protoVal; + vhal_proto::VehiclePropValue protoVal; VehiclePropValue tmpVal; toProto(&protoVal, val); From 845f6d54e4a131b67f2b34d6fa5cff0ee72b8387 Mon Sep 17 00:00:00 2001 From: Sasha Kuznetsov Date: Wed, 4 Dec 2019 12:17:50 -0800 Subject: [PATCH 0312/1022] Add support to blacklist IRNSS in HAL 2.1 Test: atest VtsHalGnssV2_1TargetTest Bug: 135042665 Change-Id: I10a12f5171c640e400af4ee66ce9ab63cf6e94f2 --- current.txt | 3 +- gnss/2.1/Android.bp | 1 + gnss/2.1/IGnss.hal | 12 + gnss/2.1/IGnssConfiguration.hal | 68 ++++ gnss/2.1/default/Android.bp | 1 + gnss/2.1/default/Gnss.cpp | 18 +- gnss/2.1/default/Gnss.h | 4 + gnss/2.1/default/GnssConfiguration.cpp | 106 +++++ gnss/2.1/default/GnssConfiguration.h | 101 +++++ .../vts/functional/gnss_hal_test_cases.cpp | 363 ++++++++++++++++++ gnss/common/utils/default/Utils.cpp | 5 + 11 files changed, 679 insertions(+), 3 deletions(-) create mode 100644 gnss/2.1/IGnssConfiguration.hal create mode 100644 gnss/2.1/default/GnssConfiguration.cpp create mode 100644 gnss/2.1/default/GnssConfiguration.h diff --git a/current.txt b/current.txt index 6d1e6c645e..19a3c0f4a7 100644 --- a/current.txt +++ b/current.txt @@ -595,8 +595,9 @@ f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardwar 4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types 66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory 994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory -1bd8028b974bf1d65cfa102196a2b008afc5d42fe73fed2cb94fa7533d07f581 android.hardware.gnss@2.1::IGnss +3dacec7801968e1e4479724dc0180442d9e915466bff051f80996266b1a51c2c android.hardware.gnss@2.1::IGnss ba62e1e8993bfb9f27fa04816fa0f2241ae2d01edfa3d0c04182e2e5de80045c android.hardware.gnss@2.1::IGnssCallback +ccdf3c0fb2c02a6d4dc57afb276c3497ae8172b80b00ebc0bf8a0238dd38b01d android.hardware.gnss@2.1::IGnssConfiguration 5a125c49ca83629e22afc8c39e865509343bfa2c38f0baea9a186bbac103492d android.hardware.gnss@2.1::IGnssMeasurement 0bfb291708dd4a7c6ec6b9883e2b8592357edde8d7e962ef83918e4a2154ce69 android.hardware.gnss@2.1::IGnssMeasurementCallback ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth diff --git a/gnss/2.1/Android.bp b/gnss/2.1/Android.bp index 5d3d62df80..8b0c374469 100644 --- a/gnss/2.1/Android.bp +++ b/gnss/2.1/Android.bp @@ -11,6 +11,7 @@ hidl_interface { "IGnssCallback.hal", "IGnssMeasurement.hal", "IGnssMeasurementCallback.hal", + "IGnssConfiguration.hal", ], interfaces: [ "android.hardware.gnss.measurement_corrections@1.0", diff --git a/gnss/2.1/IGnss.hal b/gnss/2.1/IGnss.hal index 812f9cc370..2d633928dd 100644 --- a/gnss/2.1/IGnss.hal +++ b/gnss/2.1/IGnss.hal @@ -20,6 +20,7 @@ import @2.0::IGnss; import IGnssCallback; import IGnssMeasurement; +import IGnssConfiguration; /** * Represents the standard GNSS (Global Navigation Satellite System) interface. @@ -50,4 +51,15 @@ interface IGnss extends @2.0::IGnss { * @return gnssMeasurementIface Handle to the IGnssMeasurement interface. */ getExtensionGnssMeasurement_2_1() generates (IGnssMeasurement gnssMeasurementIface); + + /** + * This method returns the IGnssConfiguration interface. + * + * At least one of getExtensionGnssConfiguration(), getExtensionGnssConfiguration_1_1(), + * getExtensionGnssConfiguration_2_0(), and getExtensionGnssConfiguration_2_1() methods must + * return a non-null handle, and the other methods must return nullptr. + * + * @return gnssConfigurationIface Handle to the IGnssConfiguration interface. + */ + getExtensionGnssConfiguration_2_1() generates (IGnssConfiguration gnssConfigurationIface); }; \ No newline at end of file diff --git a/gnss/2.1/IGnssConfiguration.hal b/gnss/2.1/IGnssConfiguration.hal new file mode 100644 index 0000000000..8360ba9953 --- /dev/null +++ b/gnss/2.1/IGnssConfiguration.hal @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.1; + +import @2.0::IGnssConfiguration; +import @2.0::GnssConstellationType; + +/** + * Extended interface for GNSS Configuration support. + */ +interface IGnssConfiguration extends @2.0::IGnssConfiguration { + /** + * Represents a blacklisted source, updating the GnssConstellationType to 2.0, which supports + * IRNSS. + */ + struct BlacklistedSource { + /** + * Defines the constellation of the given satellite(s). + */ + GnssConstellationType constellation; + + /** + * Satellite (space vehicle) ID number, as defined in GnssSvInfo::svid + * + * Or 0 to blacklist all svid's for the specified constellation + */ + int16_t svid; + }; + + /** + * Injects a vector of BlacklistedSource(s) which the HAL must not use to calculate the + * GNSS location output. + * + * The superset of all satellite sources provided, including wildcards, in the latest call + * to this method, is the set of satellites sources that must not be used in calculating + * location. + * + * All measurements from the specified satellites, across frequency bands, are blacklisted + * together. + * + * If this method is never called after the IGnssConfiguration.hal connection is made on boot, + * or is called with an empty vector, then no satellites are to be blacklisted as a result of + * this API. + * + * This blacklist must be considered as an additional source of which satellites + * should not be trusted for location on top of existing sources of similar information + * such as satellite broadcast health being unhealthy and measurement outlier removal. + * + * @param blacklist The BlacklistedSource(s) of satellites the HAL must not use. + * + * @return success Whether the HAL accepts and abides by the provided blacklist. + */ + setBlacklist_2_1(vec blacklist) generates (bool success); +}; \ No newline at end of file diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp index a7cf63da5a..57233aa6cb 100644 --- a/gnss/2.1/default/Android.bp +++ b/gnss/2.1/default/Android.bp @@ -23,6 +23,7 @@ cc_binary { srcs: [ "Gnss.cpp", "GnssMeasurement.cpp", + "GnssConfiguration.cpp", "service.cpp" ], shared_libs: [ diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp index 2771f27b79..384fd49cf6 100644 --- a/gnss/2.1/default/Gnss.cpp +++ b/gnss/2.1/default/Gnss.cpp @@ -32,7 +32,7 @@ namespace implementation { sp Gnss::sGnssCallback_2_1 = nullptr; -Gnss::Gnss() : mMinIntervalMs(1000) {} +Gnss::Gnss() : mMinIntervalMs(1000), mGnssConfiguration{new GnssConfiguration()} {} Gnss::~Gnss() { stop(); @@ -48,7 +48,7 @@ Return Gnss::start() { mIsActive = true; mThread = std::thread([this]() { while (mIsActive == true) { - auto svStatus = Utils::getMockSvInfoListV2_1(); + auto svStatus = filterBlacklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1()); this->reportSvStatus(svStatus); const auto location = Utils::getMockLocationV2_0(); @@ -60,6 +60,16 @@ Return Gnss::start() { return true; } +hidl_vec Gnss::filterBlacklistedSatellitesV2_1(hidl_vec gnssSvInfoList) { + for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) { + if (mGnssConfiguration->isBlacklistedV2_1(gnssSvInfoList[i])) { + gnssSvInfoList[i].v2_0.v1_0.svFlag &= + ~static_cast(V1_0::IGnssCallback::GnssSvFlags::USED_IN_FIX); + } + } + return gnssSvInfoList; +} + Return Gnss::stop() { ALOGD("stop"); mIsActive = false; @@ -270,6 +280,10 @@ Return> Gnss::getExtensionGnssMeasurement_2_1() { return new GnssMeasurement(); } +Return> Gnss::getExtensionGnssConfiguration_2_1() { + return mGnssConfiguration; +} + void Gnss::reportSvStatus(const hidl_vec& svInfoList) const { std::unique_lock lock(mMutex); if (sGnssCallback_2_1 == nullptr) { diff --git a/gnss/2.1/default/Gnss.h b/gnss/2.1/default/Gnss.h index a61f71cf75..674b070d99 100644 --- a/gnss/2.1/default/Gnss.h +++ b/gnss/2.1/default/Gnss.h @@ -22,6 +22,7 @@ #include #include #include +#include "GnssConfiguration.h" namespace android { namespace hardware { @@ -87,6 +88,7 @@ struct Gnss : public IGnss { // Methods from V2_1::IGnss follow. Return setCallback_2_1(const sp& callback) override; Return> getExtensionGnssMeasurement_2_1() override; + Return> getExtensionGnssConfiguration_2_1() override; private: void reportLocation(const V2_0::GnssLocation&) const; @@ -94,9 +96,11 @@ struct Gnss : public IGnss { static sp sGnssCallback_2_1; std::atomic mMinIntervalMs; + sp mGnssConfiguration; std::atomic mIsActive; std::thread mThread; mutable std::mutex mMutex; + hidl_vec filterBlacklistedSatellitesV2_1(hidl_vec gnssSvInfoList); }; } // namespace implementation diff --git a/gnss/2.1/default/GnssConfiguration.cpp b/gnss/2.1/default/GnssConfiguration.cpp new file mode 100644 index 0000000000..cd8f07fcc4 --- /dev/null +++ b/gnss/2.1/default/GnssConfiguration.cpp @@ -0,0 +1,106 @@ +/* + * 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 "GnssConfiguration" + +#include "GnssConfiguration.h" +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_1 { +namespace implementation { + +// Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow. +Return GnssConfiguration::setSuplEs(bool enable) { + ALOGD("setSuplEs enable: %d", enable); + // Method deprecated in 2.0 and not expected to be called by the framework. + return false; +} + +Return GnssConfiguration::setSuplVersion(uint32_t) { + return true; +} + +Return GnssConfiguration::setSuplMode(hidl_bitfield) { + return true; +} + +Return GnssConfiguration::setGpsLock(hidl_bitfield gpsLock) { + ALOGD("setGpsLock gpsLock: %hhu", static_cast(gpsLock)); + // Method deprecated in 2.0 and not expected to be called by the framework. + return false; +} + +Return GnssConfiguration::setLppProfile(hidl_bitfield) { + return true; +} + +Return GnssConfiguration::setGlonassPositioningProtocol(hidl_bitfield) { + return true; +} + +Return GnssConfiguration::setEmergencySuplPdn(bool) { + return true; +} + +// Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow. +Return GnssConfiguration::setBlacklist( + const hidl_vec&) { + // TODO (b/122463906): Reuse 1.1 implementation. + return bool{}; +} + +// Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow. +Return GnssConfiguration::setEsExtensionSec(uint32_t emergencyExtensionSeconds) { + ALOGD("setEsExtensionSec emergencyExtensionSeconds: %d", emergencyExtensionSeconds); + return true; +} + +// Methods from ::android::hardware::gnss::V2_1::IGnssConfiguration follow. +Return GnssConfiguration::setBlacklist_2_1( + const hidl_vec& sourceList) { + std::unique_lock lock(mMutex); + mBlacklistedConstellationSet.clear(); + mBlacklistedSourceSet.clear(); + for (auto source : sourceList) { + if (source.svid == 0) { + // Wildcard blacklist, i.e., blacklist entire constellation. + mBlacklistedConstellationSet.insert(source.constellation); + } else { + mBlacklistedSourceSet.insert(source); + } + } + return true; +} + +Return GnssConfiguration::isBlacklistedV2_1(const GnssSvInfoV2_1& gnssSvInfo) const { + std::unique_lock lock(mMutex); + if (mBlacklistedConstellationSet.find(gnssSvInfo.v2_0.constellation) != + mBlacklistedConstellationSet.end()) { + return true; + } + BlacklistedSourceV2_1 source = {.constellation = gnssSvInfo.v2_0.constellation, + .svid = gnssSvInfo.v2_0.v1_0.svid}; + return (mBlacklistedSourceSet.find(source) != mBlacklistedSourceSet.end()); +} + +} // namespace implementation +} // namespace V2_1 +} // namespace gnss +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/gnss/2.1/default/GnssConfiguration.h b/gnss/2.1/default/GnssConfiguration.h new file mode 100644 index 0000000000..662d61d038 --- /dev/null +++ b/gnss/2.1/default/GnssConfiguration.h @@ -0,0 +1,101 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H +#define ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H + +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_1 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +using BlacklistedSourceV2_1 = + ::android::hardware::gnss::V2_1::IGnssConfiguration::BlacklistedSource; +using GnssConstellationTypeV2_0 = V2_0::GnssConstellationType; +using GnssSvInfoV2_1 = V2_1::IGnssCallback::GnssSvInfo; + +struct BlacklistedSourceHashV2_1 { + inline int operator()(const BlacklistedSourceV2_1& source) const { + return int(source.constellation) * 1000 + int(source.svid); + } +}; + +struct BlacklistedSourceEqualV2_1 { + inline bool operator()(const BlacklistedSourceV2_1& s1, const BlacklistedSourceV2_1& s2) const { + return (s1.constellation == s2.constellation) && (s1.svid == s2.svid); + } +}; + +using BlacklistedSourceSetV2_1 = + std::unordered_set; +using BlacklistedConstellationSetV2_1 = std::unordered_set; + +struct GnssConfiguration : public IGnssConfiguration { + // Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow. + Return setSuplEs(bool enabled) override; + Return setSuplVersion(uint32_t version) override; + Return setSuplMode(hidl_bitfield mode) override; + Return setGpsLock(hidl_bitfield lock) override; + Return setLppProfile(hidl_bitfield lppProfile) override; + Return setGlonassPositioningProtocol(hidl_bitfield protocol) override; + Return setEmergencySuplPdn(bool enable) override; + + // Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow. + Return setBlacklist( + const hidl_vec& blacklist) override; + + std::recursive_mutex& getMutex() const; + + // Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow. + Return setEsExtensionSec(uint32_t emergencyExtensionSeconds) override; + + // Methods from ::android::hardware::gnss::V2_1::IGnssConfiguration follow. + Return setBlacklist_2_1( + const hidl_vec& blacklist) override; + + Return isBlacklistedV2_1(const GnssSvInfoV2_1& gnssSvInfo) const; + + private: + mutable std::recursive_mutex mMutex; + + BlacklistedSourceSetV2_1 mBlacklistedSourceSet; + BlacklistedConstellationSetV2_1 mBlacklistedConstellationSet; +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H \ No newline at end of file diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp index ef8249b4d0..45a3d2ae4d 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp @@ -30,6 +30,13 @@ using IGnssMeasurement_2_1 = android::hardware::gnss::V2_1::IGnssMeasurement; using IGnssMeasurement_2_0 = android::hardware::gnss::V2_0::IGnssMeasurement; using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement; using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement; +using IGnssConfiguration_2_1 = android::hardware::gnss::V2_1::IGnssConfiguration; +using IGnssConfiguration_2_0 = android::hardware::gnss::V2_0::IGnssConfiguration; +using IGnssConfiguration_1_1 = android::hardware::gnss::V1_1::IGnssConfiguration; +using IGnssConfiguration_1_0 = android::hardware::gnss::V1_0::IGnssConfiguration; + +using android::hardware::gnss::V2_0::GnssConstellationType; +using android::hardware::gnss::V2_1::IGnssConfiguration; /* * SetupTeardownCreateCleanup: @@ -60,6 +67,27 @@ TEST_P(GnssHalTest, TestGnssMeasurementExtension) { ASSERT_TRUE(numNonNull >= 1); } +/* + * TestGnssConfigurationExtension: + * Gets the GnssConfigurationExtension and verifies that it returns an actual extension. + */ +TEST_P(GnssHalTest, TestGnssConfigurationExtension) { + auto gnssConfiguration_2_1 = gnss_hal_->getExtensionGnssConfiguration_2_1(); + auto gnssConfiguration_2_0 = gnss_hal_->getExtensionGnssConfiguration_2_0(); + auto gnssConfiguration_1_1 = gnss_hal_->getExtensionGnssConfiguration_1_1(); + auto gnssConfiguration_1_0 = gnss_hal_->getExtensionGnssConfiguration(); + ASSERT_TRUE(gnssConfiguration_2_1.isOk() && gnssConfiguration_2_0.isOk() && + gnssConfiguration_1_1.isOk() && gnssConfiguration_1_0.isOk()); + sp iGnssConfig_2_1 = gnssConfiguration_2_1; + sp iGnssConfig_2_0 = gnssConfiguration_2_0; + sp iGnssConfig_1_1 = gnssConfiguration_1_1; + sp iGnssConfig_1_0 = gnssConfiguration_1_0; + // At least one interface is non-null. + int numNonNull = (int)(iGnssConfig_2_1 != nullptr) + (int)(iGnssConfig_2_0 != nullptr) + + (int)(iGnssConfig_1_1 != nullptr) + (int)(iGnssConfig_1_0 != nullptr); + ASSERT_TRUE(numNonNull >= 1); +} + /* * TestGnssMeasurementFields: * Sets a GnssMeasurementCallback, waits for a measurement, and verifies @@ -126,3 +154,338 @@ TEST_P(GnssHalTest, TestGnssSvInfoFields) { ASSERT_TRUE(nonZeroCn0Found); StopAndClearLocations(); } + +/* + * FindStrongFrequentNonGpsSource: + * + * Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times + * + * returns the strongest source, + * or a source with constellation == UNKNOWN if none are found sufficient times + * TODO(skz): create a template for this to reduce code duplication of v2.1 and v2.0 since both + * are using vectors. + */ +IGnssConfiguration::BlacklistedSource FindStrongFrequentNonGpsSource( + const std::list> sv_info_list, + const int min_observations) { + struct ComparableBlacklistedSource { + IGnssConfiguration::BlacklistedSource id; + + ComparableBlacklistedSource() { + id.constellation = GnssConstellationType::UNKNOWN; + id.svid = 0; + } + + bool operator<(const ComparableBlacklistedSource& compare) const { + return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) && + (id.constellation < compare.id.constellation))); + } + }; + + struct SignalCounts { + int observations; + float max_cn0_dbhz; + }; + + std::map mapSignals; + + for (const auto& sv_info_vec : sv_info_list) { + for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) { + const auto& gnss_sv = sv_info_vec[iSv]; + if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) && + (gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) { + ComparableBlacklistedSource source; + source.id.svid = gnss_sv.v2_0.v1_0.svid; + source.id.constellation = gnss_sv.v2_0.constellation; + + const auto& itSignal = mapSignals.find(source); + if (itSignal == mapSignals.end()) { + SignalCounts counts; + counts.observations = 1; + counts.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz; + mapSignals.insert( + std::pair(source, counts)); + } else { + itSignal->second.observations++; + if (itSignal->second.max_cn0_dbhz < gnss_sv.v2_0.v1_0.cN0Dbhz) { + itSignal->second.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz; + } + } + } + } + } + + float max_cn0_dbhz_with_sufficient_count = 0.; + int total_observation_count = 0; + int blacklisted_source_count_observation = 0; + + ComparableBlacklistedSource source_to_blacklist; // initializes to zero = UNKNOWN constellation + for (auto const& pairSignal : mapSignals) { + total_observation_count += pairSignal.second.observations; + if ((pairSignal.second.observations >= min_observations) && + (pairSignal.second.max_cn0_dbhz > max_cn0_dbhz_with_sufficient_count)) { + source_to_blacklist = pairSignal.first; + blacklisted_source_count_observation = pairSignal.second.observations; + max_cn0_dbhz_with_sufficient_count = pairSignal.second.max_cn0_dbhz; + } + } + ALOGD("Among %d observations, chose svid %d, constellation %d, " + "with %d observations at %.1f max CNo", + total_observation_count, source_to_blacklist.id.svid, + (int)source_to_blacklist.id.constellation, blacklisted_source_count_observation, + max_cn0_dbhz_with_sufficient_count); + + return source_to_blacklist.id; +} + +/* + * BlacklistIndividualSatellites: + * + * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding + * GnssStatus for common satellites (strongest and one other.) + * 2a & b) Turns off location, and blacklists common satellites. + * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding + * GnssStatus does not use those satellites. + * 4a & b) Turns off location, and send in empty blacklist. + * 5a) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding + * GnssStatus does re-use at least the previously strongest satellite + * 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the + * formerly strongest satellite + */ +TEST_P(GnssHalTest, BlacklistIndividualSatellites) { + const int kLocationsToAwait = 3; + const int kRetriesToUnBlacklist = 10; + + gnss_cb_->location_cbq_.reset(); + StartAndCheckLocations(kLocationsToAwait); + 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 GnssSvInfo, while awaiting %d Locations (%d received)", + sv_info_list_cbq_size, kLocationsToAwait, location_called_count); + + /* + * Identify strongest SV seen at least kLocationsToAwait -1 times + * Why -1? To avoid test flakiness in case of (plausible) slight flakiness in strongest signal + * observability (one epoch RF null) + */ + + const int kGnssSvInfoListTimeout = 2; + std::list> sv_info_vec_list; + int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec_list, sv_info_list_cbq_size, + kGnssSvInfoListTimeout); + + ASSERT_EQ(count, sv_info_list_cbq_size); + + IGnssConfiguration::BlacklistedSource source_to_blacklist = + FindStrongFrequentNonGpsSource(sv_info_vec_list, kLocationsToAwait - 1); + + if (source_to_blacklist.constellation == GnssConstellationType::UNKNOWN) { + // Cannot find a non-GPS satellite. Let the test pass. + ALOGD("Cannot find a non-GPS satellite. Letting the test pass."); + return; + } + + // Stop locations, blacklist the common SV + StopAndClearLocations(); + + auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_2_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; + + auto result = gnss_configuration_hal->setBlacklist_2_1(sources); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); + + // retry and ensure satellite not used + gnss_cb_->sv_info_list_cbq_.reset(); + + gnss_cb_->location_cbq_.reset(); + StartAndCheckLocations(kLocationsToAwait); + + // early exit if test is being run with insufficient signal + location_called_count = gnss_cb_->location_cbq_.calledCount(); + if (location_called_count == 0) { + ALOGE("0 Gnss locations received - ensure sufficient signal and retry"); + } + ASSERT_TRUE(location_called_count > 0); + + // Tolerate 1 less sv status to handle edge cases in reporting. + sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size(); + EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait); + ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)", + sv_info_list_cbq_size, kLocationsToAwait, location_called_count); + for (int i = 0; i < sv_info_list_cbq_size; ++i) { + hidl_vec sv_info_vec; + gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout); + for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) { + const auto& gnss_sv = sv_info_vec[iSv]; + EXPECT_FALSE((gnss_sv.v2_0.v1_0.svid == source_to_blacklist.svid) && + (gnss_sv.v2_0.constellation == source_to_blacklist.constellation) && + (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)); + } + } + + // clear blacklist and restart - this time updating the blacklist while location is still on + sources.resize(0); + + result = gnss_configuration_hal->setBlacklist_2_1(sources); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); + + bool strongest_sv_is_reobserved = false; + // do several loops awaiting a few locations, allowing non-immediate reacquisition strategies + int unblacklist_loops_remaining = kRetriesToUnBlacklist; + while (!strongest_sv_is_reobserved && (unblacklist_loops_remaining-- > 0)) { + StopAndClearLocations(); + gnss_cb_->sv_info_list_cbq_.reset(); + + gnss_cb_->location_cbq_.reset(); + StartAndCheckLocations(kLocationsToAwait); + + // early exit loop if test is being run with insufficient signal + location_called_count = gnss_cb_->location_cbq_.calledCount(); + if (location_called_count == 0) { + ALOGE("0 Gnss locations received - ensure sufficient signal and retry"); + } + ASSERT_TRUE(location_called_count > 0); + + // Tolerate 1 less sv status to handle edge cases in reporting. + sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size(); + EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait); + ALOGD("Clear blacklist, observed %d GnssSvInfo, while awaiting %d Locations" + ", tries remaining %d", + sv_info_list_cbq_size, kLocationsToAwait, unblacklist_loops_remaining); + + for (int i = 0; i < sv_info_list_cbq_size; ++i) { + hidl_vec sv_info_vec; + gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout); + for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) { + const auto& gnss_sv = sv_info_vec[iSv]; + if ((gnss_sv.v2_0.v1_0.svid == source_to_blacklist.svid) && + (gnss_sv.v2_0.constellation == source_to_blacklist.constellation) && + (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)) { + strongest_sv_is_reobserved = true; + break; + } + } + if (strongest_sv_is_reobserved) break; + } + } + EXPECT_TRUE(strongest_sv_is_reobserved); + StopAndClearLocations(); +} + +/* + * BlacklistConstellation: + * + * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding + * GnssStatus for any non-GPS constellations. + * 2a & b) Turns off location, and blacklist first non-GPS constellations. + * 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, BlacklistConstellation) { + 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 GnssSvInfo, while awaiting %d Locations (%d received)", + sv_info_list_cbq_size, kLocationsToAwait, location_called_count); + + // Find first non-GPS constellation to blacklist + const int kGnssSvInfoListTimeout = 2; + GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN; + for (int i = 0; i < sv_info_list_cbq_size; ++i) { + hidl_vec sv_info_vec; + gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout); + for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) { + const auto& gnss_sv = sv_info_vec[iSv]; + if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) && + (gnss_sv.v2_0.constellation != GnssConstellationType::UNKNOWN) && + (gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) { + // found a non-GPS constellation + constellation_to_blacklist = gnss_sv.v2_0.constellation; + break; + } + } + if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) { + break; + } + } + + // Turns off location + StopAndClearLocations(); + + if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) { + ALOGI("No non-GPS constellations found, constellation blacklist test less effective."); + // Proceed functionally to blacklist something. + constellation_to_blacklist = GnssConstellationType::GLONASS; + } + IGnssConfiguration::BlacklistedSource source_to_blacklist_1; + source_to_blacklist_1.constellation = constellation_to_blacklist; + source_to_blacklist_1.svid = 0; // documented wildcard for all satellites in this constellation + + // IRNSS was added in 2.0. Always attempt to blacklist IRNSS to verify that the new enum is + // supported. + IGnssConfiguration::BlacklistedSource source_to_blacklist_2; + source_to_blacklist_2.constellation = GnssConstellationType::IRNSS; + source_to_blacklist_2.svid = 0; // documented wildcard for all satellites in this constellation + + auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_2_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(2); + sources[0] = source_to_blacklist_1; + sources[1] = source_to_blacklist_2; + + auto result = gnss_configuration_hal->setBlacklist_2_1(sources); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); + + // 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. + sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size(); + EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait); + ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations", sv_info_list_cbq_size, + kLocationsToAwait); + for (int i = 0; i < sv_info_list_cbq_size; ++i) { + hidl_vec sv_info_vec; + gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout); + for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) { + const auto& gnss_sv = sv_info_vec[iSv]; + EXPECT_FALSE((gnss_sv.v2_0.constellation == source_to_blacklist_1.constellation) && + (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)); + EXPECT_FALSE((gnss_sv.v2_0.constellation == source_to_blacklist_2.constellation) && + (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)); + } + } + + // clean up + StopAndClearLocations(); + sources.resize(0); + result = gnss_configuration_hal->setBlacklist_2_1(sources); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); +} \ No newline at end of file diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp index 6c6d696f3d..ccb91b100f 100644 --- a/gnss/common/utils/default/Utils.cpp +++ b/gnss/common/utils/default/Utils.cpp @@ -175,6 +175,11 @@ hidl_vec Utils::getMockSvInfoListV2_1() { 25.0, 66.0, 247.0), V2_0::GnssConstellationType::GLONASS), 20.0), + getMockSvInfoV2_1( + getMockSvInfoV2_0(getMockSvInfoV1_0(3, V1_0::GnssConstellationType::UNKNOWN, + 22.0, 35.0, 112.0), + V2_0::GnssConstellationType::IRNSS), + 19.7), }; return gnssSvInfoList; } From e374a4a0a6a14609f9cd6f485b002178134febd6 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Mon, 16 Sep 2019 16:09:27 +0800 Subject: [PATCH 0313/1022] Wifi: WAPI constants and methods This change includes two parts: * Define WAPI proto, key management, and cipher constants. * Expose WAPI HAL API for setting the certificate suite. Bug: 139257562 Test: atest VtsHalWifiSupplicantV1_3TargetTest Change-Id: Id7a58b242776d641a091b9ede3f147b7d42003d1 --- current.txt | 4 +- wifi/supplicant/1.3/ISupplicantStaIface.hal | 14 ++ wifi/supplicant/1.3/ISupplicantStaNetwork.hal | 163 ++++++++++++++++ .../supplicant_sta_iface_hidl_test.cpp | 19 ++ .../supplicant_sta_network_hidl_test.cpp | 184 +++++++++++++++++- 5 files changed, 381 insertions(+), 3 deletions(-) diff --git a/current.txt b/current.txt index 6d1e6c645e..70c413ee66 100644 --- a/current.txt +++ b/current.txt @@ -613,9 +613,9 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar cf1d55e8c68300090747ab90b94c22e4c859b29c84ced68a317c595bb115eab2 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant -44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface +213457930af81ff3ea344fbc9d4a0d0a2bb70527f96b7b6a32ee3b5e4c17057e android.hardware.wifi.supplicant@1.3::ISupplicantStaIface 619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback -c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork +a6163000e2804472924733bcf8b4269db776460cc4df64f9c4dc8350d7aeafc5 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types 35cd6586225912718c599421606d69260707e43732d874f2064e28de45c87fac android.hardware.radio@1.5::types 3f1e2410d9bed4e7d41c6a589fe3a7943bc904b0066e40e0199a7c58427ac4e9 android.hardware.radio@1.5::IRadio diff --git a/wifi/supplicant/1.3/ISupplicantStaIface.hal b/wifi/supplicant/1.3/ISupplicantStaIface.hal index bfd8946251..fa88b91c6c 100644 --- a/wifi/supplicant/1.3/ISupplicantStaIface.hal +++ b/wifi/supplicant/1.3/ISupplicantStaIface.hal @@ -18,6 +18,7 @@ package android.hardware.wifi.supplicant@1.3; import @1.0::SupplicantStatus; import @1.2::ISupplicantStaIface; +import @1.3::ISupplicantStaNetwork; import ISupplicantStaIfaceCallback; /** @@ -76,4 +77,17 @@ interface ISupplicantStaIface extends @1.2::ISupplicantStaIface { * |SupplicantStatusCode.FAILURE_UNKNOWN| */ setMboCellularDataStatus(bool available) generates (SupplicantStatus status); + + /** + * Get Key management capabilities of the device + * + * @return status Status of the operation, and a bitmap of key management mask. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN| + */ + getKeyMgmtCapabilities_1_3() + generates (SupplicantStatus status, bitfield keyMgmtMask); }; diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal index ab08cff9c5..1bcf7bcde2 100644 --- a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal +++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal @@ -16,6 +16,7 @@ package android.hardware.wifi.supplicant@1.3; +import @1.0::ISupplicantStaNetwork; import @1.0::SupplicantStatus; import @1.2::ISupplicantStaNetwork; @@ -24,6 +25,32 @@ import @1.2::ISupplicantStaNetwork; * configuration it controls. */ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { + /** Possble mask of values for Proto param. */ + enum ProtoMask : @1.0::ISupplicantStaNetwork.ProtoMask { + WAPI = 1 << 2, + }; + + /** Possble mask of values for KeyMgmt param. */ + enum KeyMgmtMask : @1.2::ISupplicantStaNetwork.KeyMgmtMask { + /* WAPI Psk */ + WAPI_PSK = 1 << 12, + + /** WAPI Cert */ + WAPI_CERT = 1 << 13, + }; + + /** Possble mask of values for PairwiseCipher param. */ + enum PairwiseCipherMask : @1.2::ISupplicantStaNetwork.PairwiseCipherMask { + /** SMS4 Pairwise Cipher */ + SMS4 = 1 << 7, + }; + + /** Possble mask of values for GroupCipher param. */ + enum GroupCipherMask : @1.2::ISupplicantStaNetwork.GroupCipherMask { + /** SMS4 Group Cipher */ + SMS4 = 1 << 7, + }; + /** * Set OCSP (Online Certificate Status Protocol) type for this network. * @@ -48,6 +75,142 @@ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { */ getOcsp() generates (SupplicantStatus status, OcspType ocspType); + /** + * Set key management mask for the network. + * + * @param keyMgmtMask value to set. + * Combination of |KeyMgmtMask| values. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN| + */ + setKeyMgmt_1_3(bitfield keyMgmtMask) generates (SupplicantStatus status); + + /** + * Get the key mgmt mask set for the network. + * + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN| + * @return keyMgmtMask Combination of |KeyMgmtMask| values. + */ + getKeyMgmt_1_3() + generates (SupplicantStatus status, bitfield keyMgmtMask); + + /** + * Set proto mask for the network. + * + * @param protoMask value to set. + * Combination of |ProtoMask| values. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN| + */ + setProto_1_3(bitfield protoMask) generates (SupplicantStatus status); + + /** + * Get the proto mask set for the network. + * + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN| + * @return protoMask Combination of |ProtoMask| values. + */ + getProto_1_3() generates (SupplicantStatus status, bitfield protoMask); + + /** + * Set group cipher mask for the network. + * + * @param groupCipherMask value to set. + * Combination of |ProtoMask| values. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN| + */ + setGroupCipher_1_3(bitfield groupCipherMask) + generates (SupplicantStatus status); + + /** + * Get the pairwise cipher mask set for the network. + * + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN| + * @return pairwiseCipherMask Combination of |PairwiseCipherMask| values. + */ + getPairwiseCipher_1_3() + generates (SupplicantStatus status, + bitfield pairwiseCipherMask); + + /** + * Set pairwise cipher mask for the network. + * + * @param pairwiseCipherMask value to set. + * Combination of |ProtoMask| values. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN| + */ + setPairwiseCipher_1_3(bitfield pairwiseCipherMask) + generates (SupplicantStatus status); + + /** + * Get the group cipher mask set for the network. + * + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN| + * @return groupCipherMask Combination of |GroupCipherMask| values. + */ + getGroupCipher_1_3() + generates (SupplicantStatus status, + bitfield groupCipherMask); + + /** + * Set WAPI certificate suite for this network. + * + * @param suite value to set. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN| + */ + setWapiCertSuite(string suite) generates (SupplicantStatus status); + + /** + * Get WAPI certificate suite set for this network. + * + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN| + * @return suite The name of a suite. + */ + getWapiCertSuite() generates (SupplicantStatus status, string suite); + /** * Add a PMK into supplicant PMK cache. * diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp index 2cf58813ad..ca3265e960 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp @@ -227,3 +227,22 @@ TEST_F(SupplicantStaIfaceHidlTest, SetMboCellularDataStatus) { EXPECT_EQ(expectedStatusCode, status.code); }); } + +/* + * GetKeyMgmtCapabilities_1_3 + */ +TEST_F(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities_1_3) { + sta_iface_->getKeyMgmtCapabilities_1_3([&](const SupplicantStatus& status, + uint32_t keyMgmtMask) { + if (SupplicantStatusCode::SUCCESS != status.code) { + // for unsupport case + EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code); + } else { + // Even though capabilities vary, these two are always set in HAL + // v1.3 + EXPECT_TRUE(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::NONE); + EXPECT_TRUE(keyMgmtMask & + ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X); + } + }); +} diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp index 07bc9d8103..d6f55f54fc 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp @@ -17,15 +17,18 @@ #include #include +#include #include #include "supplicant_hidl_test_utils.h" #include "supplicant_hidl_test_utils_1_3.h" using ::android::sp; +using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus; using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; +using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork; using ::android::hardware::wifi::supplicant::V1_3::OcspType; namespace { @@ -39,15 +42,37 @@ class SupplicantStaNetworkHidlTest virtual void SetUp() override { startSupplicantAndWaitForHidlService(); EXPECT_TRUE(turnOnExcessiveLogging()); + sta_iface_ = getSupplicantStaIface_1_3(); + ASSERT_NE(nullptr, sta_iface_.get()); sta_network_ = createSupplicantStaNetwork_1_3(); - ASSERT_NE(sta_network_.get(), nullptr); + ASSERT_NE(nullptr, sta_network_.get()); } virtual void TearDown() override { stopSupplicant(); } protected: + sp sta_iface_; // ISupplicantStaNetwork object used for all tests in this fixture. sp sta_network_; + + bool isWapiSupported() { + uint32_t keyMgmtMask = 0; + + // We need to first get the key management capabilities from the device. + // If WAPI is not supported, we just pass the test. + sta_iface_->getKeyMgmtCapabilities_1_3( + [&](const SupplicantStatus &status, uint32_t keyMgmtMaskInternal) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + keyMgmtMask = keyMgmtMaskInternal; + }); + + if (!(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::WAPI_PSK)) { + // WAPI not supported + return false; + } + + return true; + } }; /* @@ -84,3 +109,160 @@ TEST_F(SupplicantStaNetworkHidlTest, SetPmkCache) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); }); } + +/* + * SetGetKeyMgmt_1_3, check new WAPI proto support + */ +TEST_F(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_3) { + uint32_t keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::WAPI_PSK; + + sta_network_->setKeyMgmt_1_3(keyMgmt, [](const SupplicantStatus &status) { + if (SupplicantStatusCode::SUCCESS != status.code) { + // for unsupport case + EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code); + } + }); + + sta_network_->getKeyMgmt_1_3( + [&keyMgmt](const SupplicantStatus &status, uint32_t keyMgmtOut) { + if (SupplicantStatusCode::SUCCESS != status.code) { + // for unsupport case + EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code); + } else { + EXPECT_EQ(keyMgmtOut, keyMgmt); + } + }); + + keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::WAPI_CERT; + sta_network_->setKeyMgmt_1_3(keyMgmt, [](const SupplicantStatus &status) { + if (SupplicantStatusCode::SUCCESS != status.code) { + // for unsupport case + EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code); + } + }); + + sta_network_->getKeyMgmt_1_3( + [&keyMgmt](const SupplicantStatus &status, uint32_t keyMgmtOut) { + if (SupplicantStatusCode::SUCCESS != status.code) { + // for unsupport case + EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code); + } else { + EXPECT_EQ(keyMgmtOut, keyMgmt); + } + }); +} + +/* + * SetGetProto_1_3, check new WAPI proto support + */ +TEST_F(SupplicantStaNetworkHidlTest, SetGetProto_1_3) { + uint32_t wapiProto = (uint32_t)ISupplicantStaNetwork::ProtoMask::WAPI; + sta_network_->setProto(wapiProto, [](const SupplicantStatus &status) { + if (SupplicantStatusCode::SUCCESS != status.code) { + // for unsupport case + EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code); + } + }); + sta_network_->getProto([&](const SupplicantStatus &status, uint32_t proto) { + if (SupplicantStatusCode::SUCCESS != status.code) { + // for unsupport case + EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code); + } else { + EXPECT_EQ(proto, wapiProto); + } + }); +} + +/* + * SetGetGroupCipher_1_3, check new WAPI support + */ +TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_3) { + uint32_t groupCipher = + (uint32_t)ISupplicantStaNetwork::GroupCipherMask::SMS4; + + sta_network_->setGroupCipher_1_3( + groupCipher, [](const SupplicantStatus &status) { + if (SupplicantStatusCode::SUCCESS != status.code) { + // for unsupport case + EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code); + } + }); + + sta_network_->getGroupCipher_1_3( + [&groupCipher](const SupplicantStatus &status, + uint32_t groupCipherOut) { + if (SupplicantStatusCode::SUCCESS != status.code) { + // for unsupport case + EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code); + } else { + EXPECT_EQ(groupCipherOut, groupCipher); + } + }); +} + +/* + * SetGetPairwiseCipher_1_3, check new WAPI support + */ +TEST_F(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_3) { + uint32_t pairwiseCipher = + (uint32_t)ISupplicantStaNetwork::PairwiseCipherMask::SMS4; + + sta_network_->setPairwiseCipher_1_3( + pairwiseCipher, [](const SupplicantStatus &status) { + if (SupplicantStatusCode::SUCCESS != status.code) { + // for unsupport case + EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code); + } + }); + + sta_network_->getPairwiseCipher_1_3( + [&pairwiseCipher](const SupplicantStatus &status, + uint32_t pairwiseCipherOut) { + if (SupplicantStatusCode::SUCCESS != status.code) { + // for unsupport case + EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code); + } else { + EXPECT_EQ(pairwiseCipherOut, pairwiseCipher); + } + }); +} + +/* + * SetGetWapiCertSuite + */ +TEST_F(SupplicantStaNetworkHidlTest, SetGetWapiCertSuite) { + hidl_string testWapiCertSuite = "suite"; + + if (isWapiSupported()) { + sta_network_->setWapiCertSuite( + testWapiCertSuite, [](const SupplicantStatus &status) { + if (SupplicantStatusCode::SUCCESS != status.code) { + // for unsupport case + EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, + status.code); + } + }); + + sta_network_->getWapiCertSuite([testWapiCertSuite]( + const SupplicantStatus &status, + const hidl_string &wapiCertSuite) { + if (SupplicantStatusCode::SUCCESS != status.code) { + // for unsupport case + EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code); + } else { + EXPECT_EQ(testWapiCertSuite, wapiCertSuite); + } + }); + } else { + sta_network_->setWapiCertSuite( + testWapiCertSuite, [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code); + }); + + sta_network_->getWapiCertSuite( + [testWapiCertSuite](const SupplicantStatus &status, + const hidl_string &wapiCertSuite __unused) { + EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code); + }); + } +} From ceaeee1d73ac422ce146519fcd1a235c7f9ec0c9 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 13 Nov 2019 13:47:50 -0800 Subject: [PATCH 0314/1022] Audio effect HAL: Add device ID to createEffect API Add the possibility to specify a target audio device when creating an audio effect by passing its audio port handle to createEffect API. To attach an effect to a device, the framework will use session ID AudioSessionConsts.DEVICE and provide a valid AudioPortHandle as device ID. Bug: 136294538 Test: make Change-Id: Ic697eeafbd5df6800ad4c7fd9e0698e3d8e3beae --- audio/effect/6.0/IEffectsFactory.hal | 6 +++- .../all-versions/default/EffectsFactory.cpp | 30 +++++++++++++---- .../all-versions/default/EffectsFactory.h | 12 +++++-- .../VtsHalAudioEffectTargetTest.cpp | 32 +++++++++++-------- current.txt | 2 +- 5 files changed, 59 insertions(+), 23 deletions(-) diff --git a/audio/effect/6.0/IEffectsFactory.hal b/audio/effect/6.0/IEffectsFactory.hal index e08b2deb4b..4c37bad2e2 100644 --- a/audio/effect/6.0/IEffectsFactory.hal +++ b/audio/effect/6.0/IEffectsFactory.hal @@ -48,11 +48,15 @@ interface IEffectsFactory { * stream. * @param ioHandle identifies the output or input stream this effect is * directed to in audio HAL. + * @param device identifies the sink or source device this effect is directed to in the + * audio HAL. Must be specified if session is AudioSessionConsts.DEVICE. + * "device" is the AudioPortHandle used for the device when the audio + * patch is created at the audio HAL. * @return retval operation completion status. * @return result the interface for the created effect. * @return effectId the unique ID of the effect to be used with * IStream::addEffect and IStream::removeEffect methods. */ - createEffect(Uuid uid, AudioSession session, AudioIoHandle ioHandle) + createEffect(Uuid uid, AudioSession session, AudioIoHandle ioHandle, AudioPortHandle device) generates (Result retval, IEffect result, uint64_t effectId); }; diff --git a/audio/effect/all-versions/default/EffectsFactory.cpp b/audio/effect/all-versions/default/EffectsFactory.cpp index 6283e7bc13..acce7deaad 100644 --- a/audio/effect/all-versions/default/EffectsFactory.cpp +++ b/audio/effect/all-versions/default/EffectsFactory.cpp @@ -133,9 +133,9 @@ exit: return Void(); } -Return EffectsFactory::getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb) { +Return EffectsFactory::getDescriptor(const Uuid& uuid, getDescriptor_cb _hidl_cb) { effect_uuid_t halUuid; - HidlUtils::uuidToHal(uid, &halUuid); + HidlUtils::uuidToHal(uuid, &halUuid); effect_descriptor_t halDescriptor; status_t status = EffectGetDescriptor(&halUuid, &halDescriptor); EffectDescriptor descriptor; @@ -154,13 +154,31 @@ Return EffectsFactory::getDescriptor(const Uuid& uid, getDescriptor_cb _hi return Void(); } -Return EffectsFactory::createEffect(const Uuid& uid, int32_t session, int32_t ioHandle, - createEffect_cb _hidl_cb) { +#if MAJOR_VERSION <= 5 +Return EffectsFactory::createEffect(const Uuid& uuid, int32_t session, int32_t ioHandle, + EffectsFactory::createEffect_cb _hidl_cb) { + return createEffectImpl(uuid, session, ioHandle, AUDIO_PORT_HANDLE_NONE, _hidl_cb); +} +#else +Return EffectsFactory::createEffect(const Uuid& uuid, int32_t session, int32_t ioHandle, + int32_t device, + EffectsFactory::createEffect_cb _hidl_cb) { + return createEffectImpl(uuid, session, ioHandle, device, _hidl_cb); +} +#endif + +Return EffectsFactory::createEffectImpl(const Uuid& uuid, int32_t session, int32_t ioHandle, + int32_t device, createEffect_cb _hidl_cb) { effect_uuid_t halUuid; - HidlUtils::uuidToHal(uid, &halUuid); + HidlUtils::uuidToHal(uuid, &halUuid); effect_handle_t handle; Result retval(Result::OK); - status_t status = EffectCreate(&halUuid, session, ioHandle, &handle); + status_t status; + if (session == AUDIO_SESSION_DEVICE) { + status = EffectCreateOnDevice(&halUuid, device, ioHandle, &handle); + } else { + status = EffectCreate(&halUuid, session, ioHandle, &handle); + } sp effect; uint64_t effectId = EffectMap::INVALID_ID; if (status == OK) { diff --git a/audio/effect/all-versions/default/EffectsFactory.h b/audio/effect/all-versions/default/EffectsFactory.h index f0d09ec3a4..0b86836e4b 100644 --- a/audio/effect/all-versions/default/EffectsFactory.h +++ b/audio/effect/all-versions/default/EffectsFactory.h @@ -47,9 +47,15 @@ using namespace ::android::hardware::audio::effect::CPP_VERSION; struct EffectsFactory : public IEffectsFactory { // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffectsFactory follow. Return getAllDescriptors(getAllDescriptors_cb _hidl_cb) override; - Return getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb) override; - Return createEffect(const Uuid& uid, int32_t session, int32_t ioHandle, + Return getDescriptor(const Uuid& uuid, getDescriptor_cb _hidl_cb) override; +#if MAJOR_VERSION <= 5 + Return createEffect(const Uuid& uuid, int32_t session, int32_t ioHandle, createEffect_cb _hidl_cb) override; +#else + Return createEffect(const Uuid& uuid, int32_t session, int32_t ioHandle, int32_t device, + createEffect_cb _hidl_cb) override; +#endif + Return debugDump( const hidl_handle& fd); //< in CPP_VERSION::IEffectsFactory only, alias of debug Return debug(const hidl_handle& fd, const hidl_vec& options) override; @@ -57,6 +63,8 @@ struct EffectsFactory : public IEffectsFactory { private: static sp dispatchEffectInstanceCreation(const effect_descriptor_t& halDescriptor, effect_handle_t handle); + Return createEffectImpl(const Uuid& uuid, int32_t session, int32_t ioHandle, + int32_t device, createEffect_cb _hidl_cb); }; extern "C" IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* name); diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp index 3c712b5ca3..c151d3ad22 100644 --- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp +++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp @@ -134,13 +134,16 @@ EFFECT_TEST(AudioEffectsFactoryHidlTest, CreateEffect) { Result retval = Result::NOT_INITIALIZED; sp effect; ret = effectsFactory->createEffect( - effectUuid, 1 /*session*/, 1 /*ioHandle*/, - [&](Result r, const sp& result, uint64_t /*effectId*/) { - retval = r; - if (r == Result::OK) { - effect = result; - } - }); + effectUuid, 1 /*session*/, 1 /*ioHandle*/, +#if MAJOR_VERSION >= 6 + 0 /*device*/, +#endif + [&](Result r, const sp& result, uint64_t /*effectId*/) { + retval = r; + if (r == Result::OK) { + effect = result; + } + }); EXPECT_TRUE(ret.isOk()); EXPECT_EQ(Result::OK, retval); EXPECT_NE(nullptr, effect.get()); @@ -236,12 +239,15 @@ void AudioEffectHidlTest::findAndCreateEffect(const Uuid& type) { Uuid effectUuid; findEffectInstance(type, &effectUuid); Return ret = effectsFactory->createEffect( - effectUuid, 1 /*session*/, 1 /*ioHandle*/, - [&](Result r, const sp& result, uint64_t /*effectId*/) { - if (r == Result::OK) { - effect = result; - } - }); + effectUuid, 1 /*session*/, 1 /*ioHandle*/, +#if MAJOR_VERSION >= 6 + 0 /*device*/, +#endif + [&](Result r, const sp& result, uint64_t /*effectId*/) { + if (r == Result::OK) { + effect = result; + } + }); ASSERT_TRUE(ret.isOk()); } diff --git a/current.txt b/current.txt index bdfb58fa73..ec8e5d33a2 100644 --- a/current.txt +++ b/current.txt @@ -601,7 +601,7 @@ bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardwar 8bc597d166e07e9eba633267fc2872c4c53d13d3f0025b778c98e13324a165de android.hardware.audio.effect@6.0::IDownmixEffect 9ee022c81e79da6051fde0836c1c1c4d5414e0c9a6cccc0ce17a90346ceb1391 android.hardware.audio.effect@6.0::IEffect 75c99a70577d543359910a0b378bcbf5a0d6076712e58e6864cd8803f76c8684 android.hardware.audio.effect@6.0::IEffectBufferProviderCallback -5910bdd600fc6501a67233a9a3f4f21dda86af08c05497322712600131d1fa8f android.hardware.audio.effect@6.0::IEffectsFactory +b138d519696f23af2c7cb92c532178c35f4b3a5c1b689260b1c308fe00249f8b android.hardware.audio.effect@6.0::IEffectsFactory dd377f404a8e71f6191d295e10067db629b0f0c28e594af906f2bea5d87fe2cc android.hardware.audio.effect@6.0::IEnvironmentalReverbEffect 455e085e136767302ec34d02b51a085c310e79bf500b76dda7c96a7f3637f11a android.hardware.audio.effect@6.0::IEqualizerEffect 24b5e107a0cbd2b322f764a4d5f7fb8b5d8c337a060b9a4a26b9af050c57b5d0 android.hardware.audio.effect@6.0::ILoudnessEnhancerEffect From 2c45bb16f577110e16f4b95f455527221604c71a Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Fri, 18 Oct 2019 13:31:36 -0700 Subject: [PATCH 0315/1022] gralloc: add flush and reread for locked buffers When a buffer is locked (mapped to the CPU) by two or more clients, there is no good way to manage a reader/writer relationship. There are no requirements for how the writes should propagate to the readers. Clients must unlock and relock to be sure writes are flushed. They must unlock and relock to get the lastest copy of the buffer. This patch adds explicit flush and reread commands to help readers and writers synchronize without having to unmap and remap the buffer. Bug: 136316517 Test: TODO Change-Id: I10d3de1b0e46c4f3b50dc34aea653701933638a9 --- graphics/mapper/4.0/IMapper.hal | 44 ++++++++ graphics/mapper/4.0/utils/vts/MapperVts.cpp | 28 +++++ .../vts/include/mapper-vts/4.0/MapperVts.h | 3 + graphics/mapper/4.0/vts/functional/Android.bp | 1 + .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 103 +++++++++++++++--- 5 files changed, 166 insertions(+), 13 deletions(-) diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal index 298f31ed56..fa69987c0b 100644 --- a/graphics/mapper/4.0/IMapper.hal +++ b/graphics/mapper/4.0/IMapper.hal @@ -258,6 +258,50 @@ interface IMapper { */ unlock(pointer buffer) generates (Error error, handle releaseFence); + /** + * Flushes the contents of a locked buffer. + * + * This function flushes the CPUs caches for the range of all the buffer's + * planes and metadata. This should behave similarly to unlock() except the + * buffer should remain mapped to the CPU. + * + * The client is still responsible for calling unlock() when it is done + * with all CPU accesses to the buffer. + * + * If non-CPU blocks are simultaneously writing the buffer, the locked + * copy should still be flushed but what happens is undefined except that + * it should not cause any crashes. + * + * @param buffer Buffer to flush. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the buffer is invalid or not locked. + * @return releaseFence Handle containing a file descriptor referring to a + * sync fence object. The sync fence object will be signaled when the + * mapper has completed any pending work. @p releaseFence may be an + * empty fence. + */ + flushLockedBuffer(pointer buffer) generates (Error error, handle releaseFence); + + /** + * Rereads the contents of a locked buffer. + * + * This should fetch the most recent copy of the locked buffer. + * + * It may reread locked copies of the buffer in other processes. + * + * The client is still responsible for calling unlock() when it is done + * with all CPU accesses to the buffer. + * + * @param buffer Buffer to reread. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the buffer is invalid or not locked. + * - `NO_RESOURCES` if the buffer cannot be reread at this time. Note + * that rereading may succeed at a later time. + */ + rereadLockedBuffer(pointer buffer) generates(Error error); + /** * Test whether the given BufferDescriptorInfo is allocatable. * diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp index 8073e6924c..d0edffb84f 100644 --- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp +++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp @@ -246,6 +246,34 @@ int Gralloc::unlock(const native_handle_t* bufferHandle) { return releaseFence; } +int Gralloc::flushLockedBuffer(const native_handle_t* bufferHandle) { + auto buffer = const_cast(bufferHandle); + + int releaseFence = -1; + mMapper->flushLockedBuffer(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to flush locked buffer " << buffer; + + auto fenceHandle = tmpReleaseFence.getNativeHandle(); + if (fenceHandle) { + ASSERT_EQ(0, fenceHandle->numInts) << "invalid fence handle " << fenceHandle; + if (fenceHandle->numFds == 1) { + releaseFence = dup(fenceHandle->data[0]); + ASSERT_LT(0, releaseFence) << "failed to dup fence fd"; + } else { + ASSERT_EQ(0, fenceHandle->numFds) << " invalid fence handle " << fenceHandle; + } + } + }); + + return releaseFence; +} + +void Gralloc::rereadLockedBuffer(const native_handle_t* bufferHandle) { + auto buffer = const_cast(bufferHandle); + + ASSERT_EQ(Error::NONE, mMapper->rereadLockedBuffer(buffer)); +} + bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle, const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride) { diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h index 6251e6649c..271041852d 100644 --- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h +++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h @@ -73,6 +73,9 @@ class Gralloc { const IMapper::Rect& accessRegion, int acquireFence); int unlock(const native_handle_t* bufferHandle); + int flushLockedBuffer(const native_handle_t* bufferHandle); + void rereadLockedBuffer(const native_handle_t* bufferHandle); + bool validateBufferSize(const native_handle_t* bufferHandle, const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride); void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds, diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp index a8030ab633..506026d8bf 100644 --- a/graphics/mapper/4.0/vts/functional/Android.bp +++ b/graphics/mapper/4.0/vts/functional/Android.bp @@ -20,6 +20,7 @@ cc_test { srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"], static_libs: [ "android.hardware.graphics.mapper@4.0-vts", + "libsync", ], shared_libs: [ "android.hardware.graphics.allocator@4.0", diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index d63b078d1b..be53bc5334 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -273,6 +274,24 @@ class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase { ASSERT_NE(nullptr, outYCbCr->cr); } + void fillRGBA8888(uint8_t* data, uint32_t height, size_t strideInBytes, size_t widthInBytes, + uint32_t seed = 0) { + for (uint32_t y = 0; y < height; y++) { + memset(data, y + seed, widthInBytes); + data += strideInBytes; + } + } + + void verifyRGBA8888(uint8_t* data, uint32_t height, size_t strideInBytes, size_t widthInBytes, + uint32_t seed = 0) { + for (uint32_t y = 0; y < height; y++) { + for (size_t i = 0; i < widthInBytes; i++) { + EXPECT_EQ(static_cast(y + seed), data[i]); + } + data += strideInBytes; + } + } + std::unique_ptr mGralloc; IMapper::BufferDescriptorInfo mDummyDescriptorInfo{}; static const std::set sRequiredMetadataTypes; @@ -529,25 +548,14 @@ TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) { data = static_cast(mGralloc->lock(bufferHandle, info.usage, region, fence))); // RGBA_8888 - size_t strideInBytes = stride * 4; - size_t writeInBytes = info.width * 4; - - for (uint32_t y = 0; y < info.height; y++) { - memset(data, y, writeInBytes); - data += strideInBytes; - } + fillRGBA8888(data, info.height, stride * 4, info.width * 4); ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); // lock again for reading ASSERT_NO_FATAL_FAILURE( data = static_cast(mGralloc->lock(bufferHandle, info.usage, region, fence))); - for (uint32_t y = 0; y < info.height; y++) { - for (size_t i = 0; i < writeInBytes; i++) { - EXPECT_EQ(static_cast(y), data[i]); - } - data += strideInBytes; - } + ASSERT_NO_FATAL_FAILURE(verifyRGBA8888(data, info.height, stride * 4, info.width * 4)); ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); if (fence >= 0) { @@ -705,6 +713,75 @@ TEST_F(GraphicsMapperHidlTest, UnlockNegative) { #endif } +/** + * Test IMapper::flush and IMapper::reread. + */ +TEST_F(GraphicsMapperHidlTest, FlushRereadBasic) { + const auto& info = mDummyDescriptorInfo; + + const native_handle_t* rawHandle; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE( + rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false, false, &stride)); + + const native_handle_t* writeBufferHandle; + const native_handle_t* readBufferHandle; + ASSERT_NO_FATAL_FAILURE(writeBufferHandle = mGralloc->importBuffer(rawHandle)); + ASSERT_NO_FATAL_FAILURE(readBufferHandle = mGralloc->importBuffer(rawHandle)); + + // lock buffer for writing + const IMapper::Rect region{0, 0, static_cast(info.width), + static_cast(info.height)}; + uint8_t* writeData; + ASSERT_NO_FATAL_FAILURE( + writeData = static_cast(mGralloc->lock( + writeBufferHandle, static_cast(BufferUsage::CPU_WRITE_OFTEN), region, + -1))); + + uint8_t* readData; + ASSERT_NO_FATAL_FAILURE( + readData = static_cast(mGralloc->lock( + readBufferHandle, static_cast(BufferUsage::CPU_READ_OFTEN), region, + -1))); + + fillRGBA8888(writeData, info.height, stride * 4, info.width * 4); + + int fence; + ASSERT_NO_FATAL_FAILURE(fence = mGralloc->flushLockedBuffer(writeBufferHandle)); + ASSERT_EQ(0, sync_wait(fence, 3500)); + close(fence); + + ASSERT_NO_FATAL_FAILURE(mGralloc->rereadLockedBuffer(readBufferHandle)); + + ASSERT_NO_FATAL_FAILURE(verifyRGBA8888(readData, info.height, stride * 4, info.width * 4)); + + ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(readBufferHandle)); + if (fence >= 0) { + close(fence); + } + ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(writeBufferHandle)); + if (fence >= 0) { + close(fence); + } +} + +/** + * Test IMapper::flushLockedBuffer with bad buffer + */ +TEST_F(GraphicsMapperHidlTest, FlushLockedBufferBadBuffer) { + ASSERT_NO_FATAL_FAILURE(mGralloc->getMapper()->flushLockedBuffer( + nullptr, [&](const auto& tmpError, const auto& /*tmpReleaseFence*/) { + ASSERT_EQ(Error::BAD_BUFFER, tmpError); + })); +} + +/** + * Test IMapper::rereadLockedBuffer with bad buffer + */ +TEST_F(GraphicsMapperHidlTest, RereadLockedBufferBadBuffer) { + ASSERT_EQ(Error::BAD_BUFFER, mGralloc->getMapper()->rereadLockedBuffer(nullptr)); +} + /** * Test IMapper::isSupported with required format RGBA_8888 */ From 46b5698a33d6574993ac53a9b05baf4482b9396a Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Mon, 9 Dec 2019 21:47:42 -0800 Subject: [PATCH 0316/1022] Fix format for android.hardware.wifi@1.4 This commit includes the format changes when running the command: hidl-gen -Lformat android.hardware.wifi@1.4 -randroid.hardware:hardware/interfaces Bug: 145961722 Test: Build successful Change-Id: I59b3c4e3f12389ff2660a563b6eb0454a637c35e --- wifi/1.4/IWifiChip.hal | 3 +- wifi/1.4/IWifiChipEventCallback.hal | 6 +- wifi/1.4/IWifiNanIface.hal | 6 +- wifi/1.4/IWifiStaIface.hal | 32 ++- wifi/1.4/types.hal | 327 +++++++++++++++------------- 5 files changed, 201 insertions(+), 173 deletions(-) diff --git a/wifi/1.4/IWifiChip.hal b/wifi/1.4/IWifiChip.hal index de5a64e1b9..07f4a65955 100644 --- a/wifi/1.4/IWifiChip.hal +++ b/wifi/1.4/IWifiChip.hal @@ -39,8 +39,7 @@ interface IWifiChip extends @1.3::IWifiChip { * |WifiStatusCode.ERROR_NOT_SUPPORTED|, * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID| */ - registerEventCallback_1_4(IWifiChipEventCallback callback) - generates (WifiStatus status); + registerEventCallback_1_4(IWifiChipEventCallback callback) generates (WifiStatus status); /** * Create a RTTController instance. diff --git a/wifi/1.4/IWifiChipEventCallback.hal b/wifi/1.4/IWifiChipEventCallback.hal index ecd0a44b6f..9ead344bb4 100644 --- a/wifi/1.4/IWifiChipEventCallback.hal +++ b/wifi/1.4/IWifiChipEventCallback.hal @@ -33,6 +33,7 @@ interface IWifiChipEventCallback extends @1.2::IWifiChipEventCallback { * only for debugging purposes. */ uint32_t radioId; + /** * List of bands on which this radio chain is operating. * Can be one of: @@ -47,7 +48,10 @@ interface IWifiChipEventCallback extends @1.2::IWifiChipEventCallback { * time sharing across the 3 bands). */ WifiBand bandInfo; - /** List of interfaces on this radio chain (hardware MAC). */ + + /** + * List of interfaces on this radio chain (hardware MAC). + */ vec ifaceInfos; }; diff --git a/wifi/1.4/IWifiNanIface.hal b/wifi/1.4/IWifiNanIface.hal index 56e3c2d096..881d06c585 100644 --- a/wifi/1.4/IWifiNanIface.hal +++ b/wifi/1.4/IWifiNanIface.hal @@ -52,8 +52,7 @@ interface IWifiNanIface extends @1.2::IWifiNanIface { * |WifiStatusCode.ERROR_UNKNOWN| */ enableRequest_1_4(CommandIdShort cmdId, NanEnableRequest msg1, - NanConfigRequestSupplemental msg2) - generates (WifiStatus status); + NanConfigRequestSupplemental msg2) generates (WifiStatus status); /** * Configure NAN: configures an existing NAN functionality (i.e. assumes @@ -75,6 +74,5 @@ interface IWifiNanIface extends @1.2::IWifiNanIface { * |WifiStatusCode.ERROR_UNKNOWN| */ configRequest_1_4(CommandIdShort cmdId, NanConfigRequest msg1, - NanConfigRequestSupplemental msg2) - generates (WifiStatus status); + NanConfigRequestSupplemental msg2) generates (WifiStatus status); }; diff --git a/wifi/1.4/IWifiStaIface.hal b/wifi/1.4/IWifiStaIface.hal index fb658cd37c..8bb0de80cb 100644 --- a/wifi/1.4/IWifiStaIface.hal +++ b/wifi/1.4/IWifiStaIface.hal @@ -27,24 +27,22 @@ import @1.3::IWifiStaIface; * IWifiChip.createStaIface() may return a @1.4::IWifiStaIface when supported. */ interface IWifiStaIface extends @1.3::IWifiStaIface { - enum StaIfaceCapabilityMask : @1.0::IWifiStaIface.StaIfaceCapabilityMask { - STA_6G = 1 << 15 + STA_6G = 1 << 15, }; - /** - * Get the capabilities supported by this STA iface. - * - * @return status WifiStatus of the operation. - * Possible status codes: - * |WifiStatusCode.SUCCESS|, - * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|, - * |WifiStatusCode.ERROR_NOT_AVAILABLE|, - * |WifiStatusCode.ERROR_NOT_SUPPORTED|, - * |WifiStatusCode.ERROR_UNKNOWN| - * @return capabilities Bitset of |StaIfaceCapabilityMask| values. - */ - getCapabilities_1_4() - generates (WifiStatus status, - bitfield capabilities); + /** + * Get the capabilities supported by this STA iface. + * + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|, + * |WifiStatusCode.ERROR_NOT_AVAILABLE|, + * |WifiStatusCode.ERROR_NOT_SUPPORTED|, + * |WifiStatusCode.ERROR_UNKNOWN| + * @return capabilities Bitset of |StaIfaceCapabilityMask| values. + */ + getCapabilities_1_4() + generates (WifiStatus status, bitfield capabilities); }; diff --git a/wifi/1.4/types.hal b/wifi/1.4/types.hal index 07a298e336..4f1d22e407 100644 --- a/wifi/1.4/types.hal +++ b/wifi/1.4/types.hal @@ -40,32 +40,32 @@ import @1.0::WifiRatePreamble; * Wifi bands defined in 80211 spec. */ enum WifiBand : @1.0::WifiBand { - /** - * 6 GHz. - */ - BAND_6GHZ = 8, - /** - * 5 GHz no DFS + 6 GHz. - */ - BAND_5GHZ_6GHZ = 10, - /** - * 2.4 GHz + 5 GHz no DFS + 6 GHz. - */ - BAND_24GHZ_5GHZ_6GHZ = 11, - /** - * 2.4 GHz + 5 GHz with DFS + 6 GHz. - */ - BAND_24GHZ_5GHZ_WITH_DFS_6GHZ = 15 + /** + * 6 GHz. + */ + BAND_6GHZ = 8, + /** + * 5 GHz no DFS + 6 GHz. + */ + BAND_5GHZ_6GHZ = 10, + /** + * 2.4 GHz + 5 GHz no DFS + 6 GHz. + */ + BAND_24GHZ_5GHZ_6GHZ = 11, + /** + * 2.4 GHz + 5 GHz with DFS + 6 GHz. + */ + BAND_24GHZ_5GHZ_WITH_DFS_6GHZ = 15, }; /** * The discovery bands supported by NAN. */ enum NanBandIndex : @1.0::NanBandIndex { - /** - * Index for 6 GHz band. - */ - NAN_BAND_6GHZ = 2, + /** + * Index for 6 GHz band. + */ + NAN_BAND_6GHZ = 2, }; /** @@ -93,147 +93,176 @@ enum RttPreamble : @1.0::RttPreamble { * not intended for normal operational mode. */ struct NanDebugConfig { - /** - * Specification of the lower 2 bytes of the cluster ID. The cluster ID is 50-60-9a-01-00-00 to - * 50-60-9a-01-FF-FF. Configuration of the bottom and top values of the range (which defaults to - * 0x0000 and 0xFFFF respectively). - * Configuration is only used if |validClusterIdVals| is set to true. - */ - bool validClusterIdVals; - uint16_t clusterIdBottomRangeVal; - uint16_t clusterIdTopRangeVal; - /** - * NAN management interface address, if specified (|validIntfAddrVal| is true) then overrides any - * other configuration (specifically the default randomization configured by - * |NanConfigRequest.macAddressRandomizationIntervalSec|). - */ - bool validIntfAddrVal; - MacAddress intfAddrVal; - /** - * Combination of the 24 bit Organizationally Unique ID (OUI) and the 8 bit OUI Type. - * Used if |validOuiVal| is set to true. - */ - bool validOuiVal; - uint32_t ouiVal; - /** - * Force the Random Factor to the specified value for all transmitted Sync/Discovery beacons. - * Used if |validRandomFactorForceVal| is set to true. - * NAN Spec: Master Indication Attribute / Random Factor - */ - bool validRandomFactorForceVal; - uint8_t randomFactorForceVal; - /** - * Forces the hop-count for all transmitted Sync and Discovery Beacons NO matter the real - * hop-count being received over the air. Used if the |validHopCountForceVal}| flag is set to - * true. - * NAN Spec: Cluster Attribute / Anchor Master Information / Hop Count to Anchor Master - */ - bool validHopCountForceVal; - uint8_t hopCountForceVal; - /** - * Frequency in MHz to of the discovery channel in the specified band. Indexed by |NanBandIndex|. - * Used if the |validDiscoveryChannelVal| is set to true. - */ - bool validDiscoveryChannelVal; - WifiChannelInMhz[3] discoveryChannelMhzVal; - /** - * Specifies whether sync/discovery beacons are transmitted in the specified band. Indexed by - * |NanBandIndex|. Used if the |validUseBeaconsInBandVal| is set to true. - */ - bool validUseBeaconsInBandVal; - bool[3] useBeaconsInBandVal; - /** - * Specifies whether SDF (service discovery frames) are transmitted in the specified band. Indexed - * by |NanBandIndex|. Used if the |validUseSdfInBandVal| is set to true. - */ - bool validUseSdfInBandVal; - bool[3] useSdfInBandVal; + /** + * Specification of the lower 2 bytes of the cluster ID. The cluster ID is 50-60-9a-01-00-00 to + * 50-60-9a-01-FF-FF. Configuration of the bottom and top values of the range (which defaults to + * 0x0000 and 0xFFFF respectively). + * Configuration is only used if |validClusterIdVals| is set to true. + */ + bool validClusterIdVals; + + uint16_t clusterIdBottomRangeVal; + + uint16_t clusterIdTopRangeVal; + + /** + * NAN management interface address, if specified (|validIntfAddrVal| is true) then overrides any + * other configuration (specifically the default randomization configured by + * |NanConfigRequest.macAddressRandomizationIntervalSec|). + */ + bool validIntfAddrVal; + + MacAddress intfAddrVal; + + /** + * Combination of the 24 bit Organizationally Unique ID (OUI) and the 8 bit OUI Type. + * Used if |validOuiVal| is set to true. + */ + bool validOuiVal; + + uint32_t ouiVal; + + /** + * Force the Random Factor to the specified value for all transmitted Sync/Discovery beacons. + * Used if |validRandomFactorForceVal| is set to true. + * NAN Spec: Master Indication Attribute / Random Factor + */ + bool validRandomFactorForceVal; + + uint8_t randomFactorForceVal; + + /** + * Forces the hop-count for all transmitted Sync and Discovery Beacons NO matter the real + * hop-count being received over the air. Used if the |validHopCountForceVal}| flag is set to + * true. + * NAN Spec: Cluster Attribute / Anchor Master Information / Hop Count to Anchor Master + */ + bool validHopCountForceVal; + + uint8_t hopCountForceVal; + + /** + * Frequency in MHz to of the discovery channel in the specified band. Indexed by |NanBandIndex|. + * Used if the |validDiscoveryChannelVal| is set to true. + */ + bool validDiscoveryChannelVal; + + WifiChannelInMhz[3] discoveryChannelMhzVal; + + /** + * Specifies whether sync/discovery beacons are transmitted in the specified band. Indexed by + * |NanBandIndex|. Used if the |validUseBeaconsInBandVal| is set to true. + */ + bool validUseBeaconsInBandVal; + + bool[3] useBeaconsInBandVal; + + /** + * Specifies whether SDF (service discovery frames) are transmitted in the specified band. Indexed + * by |NanBandIndex|. Used if the |validUseSdfInBandVal| is set to true. + */ + bool validUseSdfInBandVal; + + bool[3] useSdfInBandVal; }; /** * Configuration parameters of NAN: used when enabling and re-configuring a NAN cluster. */ struct NanConfigRequest { - /** - * Master preference of this device. - * NAN Spec: Master Indication Attribute / Master Preference - */ - uint8_t masterPref; - /** - * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered - * for |NanClusterEventType.DISCOVERY_MAC_ADDRESS_CHANGED|. - */ - bool disableDiscoveryAddressChangeIndication; - /** - * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered - * for |NanClusterEventType.STARTED_CLUSTER|. - */ - bool disableStartedClusterIndication; - /** - * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered - * for |NanClusterEventType.JOINED_CLUSTER|. - */ - bool disableJoinedClusterIndication; - /** - * Control whether publish service IDs are included in Sync/Discovery beacons. - * NAN Spec: Service ID List Attribute - */ - bool includePublishServiceIdsInBeacon; - /** - * If |includePublishServiceIdsInBeacon| is true then specifies the number of publish service IDs - * to include in the Sync/Discovery beacons: - * Value = 0: include as many service IDs as will fit into the maximum allowed beacon frame size. - * Value must fit within 7 bits - i.e. <= 127. - */ - uint8_t numberOfPublishServiceIdsInBeacon; - /** - * Control whether subscribe service IDs are included in Sync/Discovery beacons. - * Spec: Subscribe Service ID List Attribute - */ - bool includeSubscribeServiceIdsInBeacon; - /** - * If |includeSubscribeServiceIdsInBeacon| is true then specifies the number of subscribe service - * IDs to include in the Sync/Discovery beacons: - * Value = 0: include as many service IDs as will fit into the maximum allowed beacon frame size. - * Value must fit within 7 bits - i.e. <= 127. - */ - uint8_t numberOfSubscribeServiceIdsInBeacon; - /** - * Number of samples used to calculate RSSI. - */ - uint16_t rssiWindowSize; - /** - * Specifies the interval in seconds that the NAN management interface MAC address is randomized. - * A value of 0 is used to disable the MAC address randomization - */ - uint32_t macAddressRandomizationIntervalSec; - /** - * Additional configuration provided per band: indexed by |NanBandIndex|. - */ - NanBandSpecificConfig[3] bandSpecificConfig; + /** + * Master preference of this device. + * NAN Spec: Master Indication Attribute / Master Preference + */ + uint8_t masterPref; + + /** + * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered + * for |NanClusterEventType.DISCOVERY_MAC_ADDRESS_CHANGED|. + */ + bool disableDiscoveryAddressChangeIndication; + + /** + * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered + * for |NanClusterEventType.STARTED_CLUSTER|. + */ + bool disableStartedClusterIndication; + + /** + * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered + * for |NanClusterEventType.JOINED_CLUSTER|. + */ + bool disableJoinedClusterIndication; + + /** + * Control whether publish service IDs are included in Sync/Discovery beacons. + * NAN Spec: Service ID List Attribute + */ + bool includePublishServiceIdsInBeacon; + + /** + * If |includePublishServiceIdsInBeacon| is true then specifies the number of publish service IDs + * to include in the Sync/Discovery beacons: + * Value = 0: include as many service IDs as will fit into the maximum allowed beacon frame size. + * Value must fit within 7 bits - i.e. <= 127. + */ + uint8_t numberOfPublishServiceIdsInBeacon; + + /** + * Control whether subscribe service IDs are included in Sync/Discovery beacons. + * Spec: Subscribe Service ID List Attribute + */ + bool includeSubscribeServiceIdsInBeacon; + + /** + * If |includeSubscribeServiceIdsInBeacon| is true then specifies the number of subscribe service + * IDs to include in the Sync/Discovery beacons: + * Value = 0: include as many service IDs as will fit into the maximum allowed beacon frame size. + * Value must fit within 7 bits - i.e. <= 127. + */ + uint8_t numberOfSubscribeServiceIdsInBeacon; + + /** + * Number of samples used to calculate RSSI. + */ + uint16_t rssiWindowSize; + + /** + * Specifies the interval in seconds that the NAN management interface MAC address is randomized. + * A value of 0 is used to disable the MAC address randomization + */ + uint32_t macAddressRandomizationIntervalSec; + + /** + * Additional configuration provided per band: indexed by |NanBandIndex|. + */ + NanBandSpecificConfig[3] bandSpecificConfig; }; /** * Enable requests for NAN: start-up configuration |IWifiNanIface.enableRequest|. */ struct NanEnableRequest { - /** - * Enable operation in a specific band: indexed by |NanBandIndex|. - */ - bool[3] operateInBand; - /** - * Specify extent of cluster by specifying the max hop count. - */ - uint8_t hopCountMax; - /** - * Configurations of NAN cluster operation. Can also be modified at run-time using - * |IWifiNanIface.configRequest|. - */ - NanConfigRequest configParams; - /** - * Non-standard configurations of NAN cluster operation - useful for debugging operations. - */ - NanDebugConfig debugConfigs; + /** + * Enable operation in a specific band: indexed by |NanBandIndex|. + */ + bool[3] operateInBand; + + /** + * Specify extent of cluster by specifying the max hop count. + */ + uint8_t hopCountMax; + + /** + * Configurations of NAN cluster operation. Can also be modified at run-time using + * |IWifiNanIface.configRequest|. + */ + NanConfigRequest configParams; + + /** + * Non-standard configurations of NAN cluster operation - useful for debugging operations. + */ + NanDebugConfig debugConfigs; }; /** From b7287d2e797a701ebd5edcb71e437a7f73c57f30 Mon Sep 17 00:00:00 2001 From: nelsonli Date: Mon, 25 Nov 2019 17:05:59 +0800 Subject: [PATCH 0317/1022] [vts-core] add VtsHalCameraProviderV2_4TargetTest to vts-core Convert VtsHalCameraProviderV2_4TargetTest to be parameterized test and add it to vts-core Bug: 142397658 Test: $atest VtsHalCameraProviderV2_4TargetTest Change-Id: I76b20be8ef18dadc4fc5d10db5c541aadf3b9b18 --- camera/provider/2.4/vts/functional/Android.bp | 4 +- .../VtsHalCameraProviderV2_4TargetTest.cpp | 139 ++++++++---------- 2 files changed, 60 insertions(+), 83 deletions(-) diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp index 080fa19d24..d14ccfaf2e 100644 --- a/camera/provider/2.4/vts/functional/Android.bp +++ b/camera/provider/2.4/vts/functional/Android.bp @@ -25,7 +25,6 @@ cc_test { "libcamera_metadata", "libcutils", "libfmq", - "libgralloctypes", "libgui", "libui", ], @@ -46,6 +45,7 @@ cc_test { "android.hidl.allocator@1.0", "libgrallocusage", "libhidlmemory", + "libgralloctypes", ], - test_suites: ["general-tests"], + test_suites: ["general-tests", "vts-core"], } diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 9416a5430e..5995bb310b 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -47,8 +47,12 @@ #include #include #include +#include #include #include +#include +#include +#include #include #include #include @@ -59,9 +63,6 @@ #include #include -#include -#include - using namespace ::android::hardware::camera::device; using ::android::hardware::Return; using ::android::hardware::Void; @@ -283,27 +284,6 @@ namespace { } } -// Test environment for camera -class CameraHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static CameraHidlEnvironment* Instance() { - static CameraHidlEnvironment* instance = new CameraHidlEnvironment; - return instance; - } - - virtual void HidlSetUp() override { ALOGI("SetUp CameraHidlEnvironment"); } - - virtual void HidlTearDown() override { ALOGI("TearDown CameraHidlEnvironment"); } - - virtual void registerTestServices() override { registerTestService(); } - - private: - CameraHidlEnvironment() {} - - GTEST_DISALLOW_COPY_AND_ASSIGN_(CameraHidlEnvironment); -}; - struct BufferItemHander: public BufferItemConsumer::FrameAvailableListener { BufferItemHander(wp consumer) : mConsumer(consumer) {} @@ -544,12 +524,13 @@ Return PreviewWindowCb::setTimestamp(int64_t timestamp) { } // The main test class for camera HIDL HAL. -class CameraHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class CameraHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { - string service_name = CameraHidlEnvironment::Instance()->getServiceName(); + std::string service_name = GetParam(); ALOGI("get service with name: %s", service_name.c_str()); - mProvider = ::testing::VtsHalHidlTargetTestBase::getService(service_name); + mProvider = ICameraProvider::getService(service_name); + ASSERT_NE(mProvider, nullptr); uint32_t id; @@ -878,7 +859,7 @@ protected: // return from HAL but framework. ::android::Vector resultOutputBuffers; - std::unordered_set expectedPhysicalResults; + std::unordered_set expectedPhysicalResults; InFlightRequest() : shutterTimestamp(0), @@ -912,7 +893,7 @@ protected: InFlightRequest(ssize_t numBuffers, bool hasInput, bool partialResults, uint32_t partialCount, - const std::unordered_set& extraPhysicalResult, + const std::unordered_set& extraPhysicalResult, std::shared_ptr queue = nullptr) : shutterTimestamp(0), errorCodeValid(false), @@ -1573,7 +1554,7 @@ hidl_vec CameraHidlTest::getCameraDeviceNames(sp p } // Test devices with first_api_level >= P does not advertise device@1.0 -TEST_F(CameraHidlTest, noHal1AfterP) { +TEST_P(CameraHidlTest, noHal1AfterP) { constexpr int32_t HAL1_PHASE_OUT_API_LEVEL = 28; int32_t firstApiLevel = 0; getFirstApiLevel(&firstApiLevel); @@ -1598,7 +1579,7 @@ TEST_F(CameraHidlTest, noHal1AfterP) { // Test if ICameraProvider::isTorchModeSupported returns Status::OK // Also if first_api_level >= Q torch API must be supported. -TEST_F(CameraHidlTest, isTorchModeSupported) { +TEST_P(CameraHidlTest, isTorchModeSupported) { constexpr int32_t API_LEVEL_Q = 29; int32_t firstApiLevel = 0; getFirstApiLevel(&firstApiLevel); @@ -1615,7 +1596,7 @@ TEST_F(CameraHidlTest, isTorchModeSupported) { } // TODO: consider removing this test if getCameraDeviceNames() has the same coverage -TEST_F(CameraHidlTest, getCameraIdList) { +TEST_P(CameraHidlTest, getCameraIdList) { Return ret; ret = mProvider->getCameraIdList([&](auto status, const auto& idList) { ALOGI("getCameraIdList returns status:%d", (int)status); @@ -1628,7 +1609,7 @@ TEST_F(CameraHidlTest, getCameraIdList) { } // Test if ICameraProvider::getVendorTags returns Status::OK -TEST_F(CameraHidlTest, getVendorTags) { +TEST_P(CameraHidlTest, getVendorTags) { Return ret; ret = mProvider->getVendorTags([&](auto status, const auto& vendorTagSecs) { ALOGI("getVendorTags returns status:%d numSections %zu", (int)status, vendorTagSecs.size()); @@ -1646,7 +1627,7 @@ TEST_F(CameraHidlTest, getVendorTags) { } // Test if ICameraProvider::setCallback returns Status::OK -TEST_F(CameraHidlTest, setCallback) { +TEST_P(CameraHidlTest, setCallback) { struct ProviderCb : public ICameraProviderCallback { virtual Return cameraDeviceStatusChange( const hidl_string& cameraDeviceName, @@ -1674,7 +1655,7 @@ TEST_F(CameraHidlTest, setCallback) { } // Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device -TEST_F(CameraHidlTest, getCameraDeviceInterface) { +TEST_P(CameraHidlTest, getCameraDeviceInterface) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -1716,7 +1697,7 @@ TEST_F(CameraHidlTest, getCameraDeviceInterface) { // Verify that the device resource cost can be retrieved and the values are // sane. -TEST_F(CameraHidlTest, getResourceCost) { +TEST_P(CameraHidlTest, getResourceCost) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -1786,7 +1767,7 @@ TEST_F(CameraHidlTest, getResourceCost) { // Verify that the static camera info can be retrieved // successfully. -TEST_F(CameraHidlTest, getCameraInfo) { +TEST_P(CameraHidlTest, getCameraInfo) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -1834,7 +1815,7 @@ TEST_F(CameraHidlTest, getCameraInfo) { } // Check whether preview window can be configured -TEST_F(CameraHidlTest, setPreviewWindow) { +TEST_P(CameraHidlTest, setPreviewWindow) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -1854,7 +1835,7 @@ TEST_F(CameraHidlTest, setPreviewWindow) { } // Verify that setting preview window fails in case device is not open -TEST_F(CameraHidlTest, setPreviewWindowInvalid) { +TEST_P(CameraHidlTest, setPreviewWindowInvalid) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -1879,7 +1860,7 @@ TEST_F(CameraHidlTest, setPreviewWindowInvalid) { } // Start and stop preview checking whether it gets enabled in between. -TEST_F(CameraHidlTest, startStopPreview) { +TEST_P(CameraHidlTest, startStopPreview) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -1904,7 +1885,7 @@ TEST_F(CameraHidlTest, startStopPreview) { // Start preview without active preview window. Preview should start as soon // as a valid active window gets configured. -TEST_F(CameraHidlTest, startStopPreviewDelayed) { +TEST_P(CameraHidlTest, startStopPreviewDelayed) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -1934,7 +1915,7 @@ TEST_F(CameraHidlTest, startStopPreviewDelayed) { } // Verify that image capture behaves as expected along with preview callbacks. -TEST_F(CameraHidlTest, takePicture) { +TEST_P(CameraHidlTest, takePicture) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -1983,7 +1964,7 @@ TEST_F(CameraHidlTest, takePicture) { } // Image capture should fail in case preview didn't get enabled first. -TEST_F(CameraHidlTest, takePictureFail) { +TEST_P(CameraHidlTest, takePictureFail) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -2003,7 +1984,7 @@ TEST_F(CameraHidlTest, takePictureFail) { } // Verify that image capture can be cancelled. -TEST_F(CameraHidlTest, cancelPicture) { +TEST_P(CameraHidlTest, cancelPicture) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -2030,7 +2011,7 @@ TEST_F(CameraHidlTest, cancelPicture) { } // Image capture cancel is a no-op when image capture is not running. -TEST_F(CameraHidlTest, cancelPictureNOP) { +TEST_P(CameraHidlTest, cancelPictureNOP) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -2053,7 +2034,7 @@ TEST_F(CameraHidlTest, cancelPictureNOP) { } // Test basic video recording. -TEST_F(CameraHidlTest, startStopRecording) { +TEST_P(CameraHidlTest, startStopRecording) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -2131,7 +2112,7 @@ TEST_F(CameraHidlTest, startStopRecording) { } // It shouldn't be possible to start recording without enabling preview first. -TEST_F(CameraHidlTest, startRecordingFail) { +TEST_P(CameraHidlTest, startRecordingFail) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -2155,7 +2136,7 @@ TEST_F(CameraHidlTest, startRecordingFail) { } // Check autofocus support if available. -TEST_F(CameraHidlTest, autoFocus) { +TEST_P(CameraHidlTest, autoFocus) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); std::vector focusModes = {CameraParameters::FOCUS_MODE_AUTO, CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE, @@ -2216,7 +2197,7 @@ TEST_F(CameraHidlTest, autoFocus) { } // In case autofocus is supported verify that it can be cancelled. -TEST_F(CameraHidlTest, cancelAutoFocus) { +TEST_P(CameraHidlTest, cancelAutoFocus) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -2262,7 +2243,7 @@ TEST_F(CameraHidlTest, cancelAutoFocus) { } // Check whether face detection is available and try to enable&disable. -TEST_F(CameraHidlTest, sendCommandFaceDetection) { +TEST_P(CameraHidlTest, sendCommandFaceDetection) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -2317,7 +2298,7 @@ TEST_F(CameraHidlTest, sendCommandFaceDetection) { } // Check whether smooth zoom is available and try to enable&disable. -TEST_F(CameraHidlTest, sendCommandSmoothZoom) { +TEST_P(CameraHidlTest, sendCommandSmoothZoom) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -2365,7 +2346,7 @@ TEST_F(CameraHidlTest, sendCommandSmoothZoom) { } // Basic sanity tests related to camera parameters. -TEST_F(CameraHidlTest, getSetParameters) { +TEST_P(CameraHidlTest, getSetParameters) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -2457,7 +2438,7 @@ TEST_F(CameraHidlTest, getSetParameters) { // Verify that the static camera characteristics can be retrieved // successfully. -TEST_F(CameraHidlTest, getCameraCharacteristics) { +TEST_P(CameraHidlTest, getCameraCharacteristics) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -2523,7 +2504,7 @@ TEST_F(CameraHidlTest, getCameraCharacteristics) { //In case it is supported verify that torch can be enabled. //Check for corresponding toch callbacks as well. -TEST_F(CameraHidlTest, setTorchMode) { +TEST_P(CameraHidlTest, setTorchMode) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); bool torchControlSupported = false; Return ret; @@ -2661,7 +2642,7 @@ TEST_F(CameraHidlTest, setTorchMode) { } // Check dump functionality. -TEST_F(CameraHidlTest, dumpState) { +TEST_P(CameraHidlTest, dumpState) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); Return ret; @@ -2726,7 +2707,7 @@ TEST_F(CameraHidlTest, dumpState) { } // Open, dumpStates, then close -TEST_F(CameraHidlTest, openClose) { +TEST_P(CameraHidlTest, openClose) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); Return ret; @@ -2819,7 +2800,7 @@ TEST_F(CameraHidlTest, openClose) { // Check whether all common default request settings can be sucessfully // constructed. -TEST_F(CameraHidlTest, constructDefaultRequestSettings) { +TEST_P(CameraHidlTest, constructDefaultRequestSettings) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -2909,7 +2890,7 @@ TEST_F(CameraHidlTest, constructDefaultRequestSettings) { // Verify that all supported stream formats and sizes can be configured // successfully. -TEST_F(CameraHidlTest, configureStreamsAvailableOutputs) { +TEST_P(CameraHidlTest, configureStreamsAvailableOutputs) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); std::vector outputStreams; @@ -3017,7 +2998,7 @@ TEST_F(CameraHidlTest, configureStreamsAvailableOutputs) { } // Check for correct handling of invalid/incorrect configuration parameters. -TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) { +TEST_P(CameraHidlTest, configureStreamsInvalidOutputs) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); std::vector outputStreams; @@ -3213,7 +3194,7 @@ TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) { // Check whether all supported ZSL output stream combinations can be // configured successfully. -TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) { +TEST_P(CameraHidlTest, configureStreamsZSLInputOutputs) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); std::vector inputStreams; std::vector inputOutputMap; @@ -3379,7 +3360,7 @@ TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) { // Check whether session parameters are supported. If Hal support for them // exist, then try to configure a preview stream using them. -TEST_F(CameraHidlTest, configureStreamsWithSessionParameters) { +TEST_P(CameraHidlTest, configureStreamsWithSessionParameters) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); std::vector outputPreviewStreams; AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, @@ -3498,7 +3479,7 @@ TEST_F(CameraHidlTest, configureStreamsWithSessionParameters) { // Verify that all supported preview + still capture stream combinations // can be configured successfully. -TEST_F(CameraHidlTest, configureStreamsPreviewStillOutputs) { +TEST_P(CameraHidlTest, configureStreamsPreviewStillOutputs) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); std::vector outputBlobStreams; std::vector outputPreviewStreams; @@ -3621,7 +3602,7 @@ TEST_F(CameraHidlTest, configureStreamsPreviewStillOutputs) { // In case constrained mode is supported, test whether it can be // configured. Additionally check for common invalid inputs when // using this mode. -TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) { +TEST_P(CameraHidlTest, configureStreamsConstrainedOutputs) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { @@ -3826,7 +3807,7 @@ TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) { // Verify that all supported video + snapshot stream combinations can // be configured successfully. -TEST_F(CameraHidlTest, configureStreamsVideoStillOutputs) { +TEST_P(CameraHidlTest, configureStreamsVideoStillOutputs) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); std::vector outputBlobStreams; std::vector outputVideoStreams; @@ -3947,7 +3928,7 @@ TEST_F(CameraHidlTest, configureStreamsVideoStillOutputs) { } // Generate and verify a camera capture request -TEST_F(CameraHidlTest, processCaptureRequestPreview) { +TEST_P(CameraHidlTest, processCaptureRequestPreview) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, static_cast(PixelFormat::IMPLEMENTATION_DEFINED)}; @@ -4115,7 +4096,7 @@ TEST_F(CameraHidlTest, processCaptureRequestPreview) { } // Generate and verify a multi-camera capture request -TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) { +TEST_P(CameraHidlTest, processMultiCaptureRequestPreview) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, static_cast(PixelFormat::YCBCR_420_888)}; @@ -4184,7 +4165,7 @@ TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) { // Leave only 2 physical devices in the id set. auto it = physicalIds.begin(); - string physicalDeviceId = *it; it++; + std::string physicalDeviceId = *it; it++; physicalIds.erase(++it, physicalIds.end()); ASSERT_EQ(physicalIds.size(), 2u); @@ -4362,7 +4343,7 @@ TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) { } // Generate and verify a burst containing alternating sensor sensitivity values -TEST_F(CameraHidlTest, processCaptureRequestBurstISO) { +TEST_P(CameraHidlTest, processCaptureRequestBurstISO) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, static_cast(PixelFormat::IMPLEMENTATION_DEFINED)}; @@ -4520,7 +4501,7 @@ TEST_F(CameraHidlTest, processCaptureRequestBurstISO) { // Test whether an incorrect capture request with missing settings will // be reported correctly. -TEST_F(CameraHidlTest, processCaptureRequestInvalidSinglePreview) { +TEST_P(CameraHidlTest, processCaptureRequestInvalidSinglePreview) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); std::vector outputPreviewStreams; AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, @@ -4595,7 +4576,7 @@ TEST_F(CameraHidlTest, processCaptureRequestInvalidSinglePreview) { // Check whether an invalid capture request with missing output buffers // will be reported correctly. -TEST_F(CameraHidlTest, processCaptureRequestInvalidBuffer) { +TEST_P(CameraHidlTest, processCaptureRequestInvalidBuffer) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); std::vector outputBlobStreams; AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, @@ -4660,7 +4641,7 @@ TEST_F(CameraHidlTest, processCaptureRequestInvalidBuffer) { } // Generate, trigger and flush a preview request -TEST_F(CameraHidlTest, flushPreviewRequest) { +TEST_P(CameraHidlTest, flushPreviewRequest) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); std::vector outputPreviewStreams; AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, @@ -4803,7 +4784,7 @@ TEST_F(CameraHidlTest, flushPreviewRequest) { } // Verify that camera flushes correctly without any pending requests. -TEST_F(CameraHidlTest, flushEmpty) { +TEST_P(CameraHidlTest, flushEmpty) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); std::vector outputPreviewStreams; AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, @@ -4848,7 +4829,7 @@ TEST_F(CameraHidlTest, flushEmpty) { } // Test camera provider@2.5 notify method -TEST_F(CameraHidlTest, providerDeviceStateNotification) { +TEST_P(CameraHidlTest, providerDeviceStateNotification) { notifyDeviceState(provider::V2_5::DeviceState::BACK_COVERED); notifyDeviceState(provider::V2_5::DeviceState::NORMAL); @@ -6434,11 +6415,7 @@ void CameraHidlTest::verifySessionReconfigurationQuery( } } -int main(int argc, char **argv) { - ::testing::AddGlobalTestEnvironment(CameraHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - CameraHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); - return status; -} +INSTANTIATE_TEST_SUITE_P( + PerInstance, CameraHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ICameraProvider::descriptor)), + android::hardware::PrintInstanceNameToString); From 0bad28f064a31fc1c659b16e1f3383247b525d43 Mon Sep 17 00:00:00 2001 From: lesl Date: Mon, 2 Dec 2019 23:48:58 +0800 Subject: [PATCH 0318/1022] IHostapd: Add hostapd 1.2 Add new API: forceClientDisconnect Bug:142752869 Test: Manual Test Test: VTS: VtsHalWifiHostapdV1_2Target Change-Id: Ia05ec993815c16731aa9be1f257f941eacf1575f --- .../compatibility_matrix.current.xml | 2 +- wifi/hostapd/1.2/Android.bp | 20 +++ wifi/hostapd/1.2/IHostapd.hal | 42 ++++++ wifi/hostapd/1.2/types.hal | 55 +++++++ wifi/hostapd/1.2/vts/OWNERS | 2 + wifi/hostapd/1.2/vts/functional/Android.bp | 37 +++++ .../VtsHalWifiHostapdV1_2TargetTest.cpp | 21 +++ .../1.2/vts/functional/hostapd_hidl_test.cpp | 140 ++++++++++++++++++ 8 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 wifi/hostapd/1.2/Android.bp create mode 100644 wifi/hostapd/1.2/IHostapd.hal create mode 100644 wifi/hostapd/1.2/types.hal create mode 100644 wifi/hostapd/1.2/vts/OWNERS create mode 100644 wifi/hostapd/1.2/vts/functional/Android.bp create mode 100644 wifi/hostapd/1.2/vts/functional/VtsHalWifiHostapdV1_2TargetTest.cpp create mode 100644 wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 8abbd48d11..b0a82a5298 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -512,7 +512,7 @@ android.hardware.wifi.hostapd - 1.0-1 + 1.0-2 IHostapd default diff --git a/wifi/hostapd/1.2/Android.bp b/wifi/hostapd/1.2/Android.bp new file mode 100644 index 0000000000..3dcad71881 --- /dev/null +++ b/wifi/hostapd/1.2/Android.bp @@ -0,0 +1,20 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.wifi.hostapd@1.2", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IHostapd.hal", + ], + interfaces: [ + "android.hardware.wifi.hostapd@1.0", + "android.hardware.wifi.hostapd@1.1", + "android.hardware.wifi.supplicant@1.0", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/wifi/hostapd/1.2/IHostapd.hal b/wifi/hostapd/1.2/IHostapd.hal new file mode 100644 index 0000000000..31ade13ab8 --- /dev/null +++ b/wifi/hostapd/1.2/IHostapd.hal @@ -0,0 +1,42 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi.hostapd@1.2; + +import @1.1::IHostapd; +import HostapdStatus; +import MacAddress; +import Ieee80211ReasonCode; + +/** + * Top-level object for managing SoftAPs. + */ +interface IHostapd extends @1.1::IHostapd { + /** + * force one of the hotspot clients disconnect.. + * + * @param ifaceName Name of the interface. + * @param clientAddress Mac Address of the hotspot client. + * @param reasonCode One of disconnect reason code which defined by 802.11. + * @return status Status of the operation. + * Possible status codes: + * |HostapdStatusCode.SUCCESS|, + * |HostapdStatusCode.FAILURE_IFACE_UNKNOWN| + * |HostapdStatusCode.FAILURE_CLIENT_UNKNOWN| + */ + forceClientDisconnect(string ifaceName, MacAddress clientAddress, + Ieee80211ReasonCode reasonCode) generates (HostapdStatus status); +}; diff --git a/wifi/hostapd/1.2/types.hal b/wifi/hostapd/1.2/types.hal new file mode 100644 index 0000000000..06e890b2cc --- /dev/null +++ b/wifi/hostapd/1.2/types.hal @@ -0,0 +1,55 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi.hostapd@1.2; + +import @1.0::HostapdStatusCode; + +/** + * Enum values indicating the status of any hostapd operation. + */ +enum HostapdStatusCode : @1.0::HostapdStatusCode { + /** + * Failure because unknown the client. + */ + FAILURE_CLIENT_UNKNOWN, +}; + +/** + * Enum values indicating the reason code for disconnect packet. + * Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45). + */ +enum Ieee80211ReasonCode : uint16_t { + WLAN_REASON_UNSPECIFIED = 1, + WLAN_REASON_PREV_AUTH_NOT_VALID = 2, + WLAN_REASON_DISASSOC_AP_BUSY = 5, +}; + +typedef uint8_t[6] MacAddress; + +/** + * Generic structure to return the status of any hostapd operation. + */ +struct HostapdStatus { + HostapdStatusCode code; + + /** + * A vendor-specific error message to provide more information beyond the + * status code. + * This must be used for debugging purposes only. + */ + string debugMessage; +}; diff --git a/wifi/hostapd/1.2/vts/OWNERS b/wifi/hostapd/1.2/vts/OWNERS new file mode 100644 index 0000000000..8bfb14882c --- /dev/null +++ b/wifi/hostapd/1.2/vts/OWNERS @@ -0,0 +1,2 @@ +rpius@google.com +etancohen@google.com diff --git a/wifi/hostapd/1.2/vts/functional/Android.bp b/wifi/hostapd/1.2/vts/functional/Android.bp new file mode 100644 index 0000000000..50cfdee612 --- /dev/null +++ b/wifi/hostapd/1.2/vts/functional/Android.bp @@ -0,0 +1,37 @@ +// +// 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. +// + +cc_test { + name: "VtsHalWifiHostapdV1_2TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "VtsHalWifiHostapdV1_2TargetTest.cpp", + "hostapd_hidl_test.cpp", + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "VtsHalWifiHostapdV1_0TargetTestUtil", + "android.hardware.wifi.hostapd@1.0", + "android.hardware.wifi.hostapd@1.1", + "android.hardware.wifi.hostapd@1.2", + "android.hardware.wifi@1.0", + "libgmock", + "libwifi-system", + "libwifi-system-iface", + ], + test_suites: ["general-tests", "vts-core"], +} + diff --git a/wifi/hostapd/1.2/vts/functional/VtsHalWifiHostapdV1_2TargetTest.cpp b/wifi/hostapd/1.2/vts/functional/VtsHalWifiHostapdV1_2TargetTest.cpp new file mode 100644 index 0000000000..7e0f3cdc47 --- /dev/null +++ b/wifi/hostapd/1.2/vts/functional/VtsHalWifiHostapdV1_2TargetTest.cpp @@ -0,0 +1,21 @@ +/* + * 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. + */ + +#include + +// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is +// updated. +::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr; \ No newline at end of file diff --git a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp new file mode 100644 index 0000000000..0d372213ce --- /dev/null +++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp @@ -0,0 +1,140 @@ +/* + * 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. + */ + +#include +#include + +#include +#include +#include + +#include +#include + +#include "hostapd_hidl_call_util.h" +#include "hostapd_hidl_test_utils.h" + +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::wifi::hostapd::V1_2::HostapdStatusCode; +using ::android::hardware::wifi::hostapd::V1_2::Ieee80211ReasonCode; +using ::android::hardware::wifi::hostapd::V1_2::IHostapd; +using ::android::hardware::wifi::V1_0::IWifi; + +namespace { +constexpr unsigned char kNwSsid[] = {'t', 'e', 's', 't', '1', + '2', '3', '4', '5'}; +constexpr int kIfaceChannel = 6; +constexpr uint8_t kTestZeroMacAddr[] = {[0 ... 5] = 0x0}; +constexpr Ieee80211ReasonCode kTestDisconnectReasonCode = + Ieee80211ReasonCode::WLAN_REASON_UNSPECIFIED; +} // namespace + +class HostapdHidlTest + : public ::testing::TestWithParam> { + public: + virtual void SetUp() override { + wifi_instance_name_ = std::get<0>(GetParam()); + hostapd_instance_name_ = std::get<1>(GetParam()); + stopSupplicantIfNeeded(wifi_instance_name_); + startHostapdAndWaitForHidlService(wifi_instance_name_, + hostapd_instance_name_); + hostapd_ = IHostapd::getService(hostapd_instance_name_); + ASSERT_NE(hostapd_.get(), nullptr); + } + + virtual void TearDown() override { stopHostapd(wifi_instance_name_); } + + protected: + std::string getPrimaryWlanIfaceName() { + std::array buffer; + auto res = property_get("ro.vendor.wifi.sap.interface", buffer.data(), + nullptr); + if (res > 0) return buffer.data(); + property_get("wifi.interface", buffer.data(), "wlan0"); + return buffer.data(); + } + + IHostapd::IfaceParams getIfaceParamsWithoutAcs() { + ::android::hardware::wifi::hostapd::V1_0::IHostapd::IfaceParams + iface_params; + IHostapd::IfaceParams iface_params_1_1; + + iface_params.ifaceName = getPrimaryWlanIfaceName(); + iface_params.hwModeParams.enable80211N = true; + iface_params.hwModeParams.enable80211AC = false; + iface_params.channelParams.enableAcs = false; + iface_params.channelParams.acsShouldExcludeDfs = false; + iface_params.channelParams.channel = kIfaceChannel; + iface_params.channelParams.band = IHostapd::Band::BAND_2_4_GHZ; + iface_params_1_1.V1_0 = iface_params; + return iface_params_1_1; + } + + IHostapd::NetworkParams getOpenNwParams() { + IHostapd::NetworkParams nw_params; + nw_params.ssid = + std::vector(kNwSsid, kNwSsid + sizeof(kNwSsid)); + nw_params.isHidden = false; + nw_params.encryptionType = IHostapd::EncryptionType::NONE; + return nw_params; + } + + // IHostapd object used for all tests in this fixture. + sp hostapd_; + std::string wifi_instance_name_; + std::string hostapd_instance_name_; +}; + +/** + * forceClientDisconnect should return FAILURE_IFACE_UNKNOWN + * when hotspot interface doesn't init.. + */ +TEST_P(HostapdHidlTest, DisconnectClientWhenIfaceNotAvailable) { + auto status = + HIDL_INVOKE(hostapd_, forceClientDisconnect, getPrimaryWlanIfaceName(), + kTestZeroMacAddr, kTestDisconnectReasonCode); + EXPECT_EQ(HostapdStatusCode::FAILURE_IFACE_UNKNOWN, status.code); +} + +/** + * forceClientDisconnect should return FAILURE_CLIENT_UNKNOWN + * when hotspot interface available. + */ +TEST_P(HostapdHidlTest, DisconnectClientWhenIfacAvailable) { + auto status_1_0 = + HIDL_INVOKE(hostapd_, addAccessPoint_1_1, getIfaceParamsWithoutAcs(), + getOpenNwParams()); + EXPECT_EQ( + android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS, + status_1_0.code); + + auto status_1_2 = + HIDL_INVOKE(hostapd_, forceClientDisconnect, getPrimaryWlanIfaceName(), + kTestZeroMacAddr, kTestDisconnectReasonCode); + EXPECT_EQ(HostapdStatusCode::FAILURE_CLIENT_UNKNOWN, status_1_2.code); +} + +INSTANTIATE_TEST_CASE_P( + PerInstance, HostapdHidlTest, + testing::Combine( + testing::ValuesIn( + android::hardware::getAllHalInstanceNames(IWifi::descriptor)), + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::wifi::hostapd::V1_2::IHostapd::descriptor))), + android::hardware::PrintInstanceTupleNameToString<>); From 2bd7d433250031cba7dba0280c42b12ad3b24037 Mon Sep 17 00:00:00 2001 From: Galia Peycheva Date: Fri, 1 Nov 2019 11:04:42 +0100 Subject: [PATCH 0319/1022] Add controls for ALLM and Content Types to composer hal Also extending the passthrough interface with setLowLatencyMode and setContentType. Bug:132731049 Test: make -j$(nproc) Test: vts-tradefed run vts-hal --skip-device-info -m VtsHalGraphicsComposerV2_4Target Change-Id: I0ec5a5be796700074bdd8cac75cd67f96cd5df58 --- graphics/composer/2.4/IComposerClient.hal | 74 +++++++++++ .../include/composer-hal/2.4/ComposerClient.h | 18 +++ .../include/composer-hal/2.4/ComposerHal.h | 5 + .../include/composer-passthrough/2.4/HwcHal.h | 59 +++++++++ .../composer/2.4/utils/vts/ComposerVts.cpp | 19 +++ .../include/composer-vts/2.4/ComposerVts.h | 7 ++ .../VtsHalGraphicsComposerV2_4TargetTest.cpp | 119 ++++++++++++++++++ 7 files changed, 301 insertions(+) diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal index f23536cd2d..06b4c5e53a 100644 --- a/graphics/composer/2.4/IComposerClient.hal +++ b/graphics/composer/2.4/IComposerClient.hal @@ -48,6 +48,12 @@ interface IComposerClient extends @2.3::IComposerClient { * with protected buffers. */ PROTECTED_CONTENTS = 4, + + /** + * Indicates that both the composer HAL implementation and the given display + * support a low latency mode, such as HDMI 2.1 Auto Low Latency Mode. + */ + AUTO_LOW_LATENCY_MODE = 5, }; /** @@ -64,6 +70,18 @@ interface IComposerClient extends @2.3::IComposerClient { EXTERNAL = 1, }; + enum ContentType : uint32_t { + NONE = 0, + + /** + * These modes correspond to those found in the HDMI 1.4 specification. + */ + GRAPHICS = 1, + PHOTO = 2, + CINEMA = 3, + GAME = 4, + }; + /** * Constraints for changing vsync period. */ @@ -172,4 +190,60 @@ interface IComposerClient extends @2.3::IComposerClient { setActiveConfigWithConstraints(Display display, Config config, VsyncPeriodChangeConstraints vsyncPeriodChangeConstraints) generates (Error error, VsyncPeriodChangeTimeline timeline); + + /** + * Requests the display to enable/disable its low latency mode. + * + * If the display is connected via HDMI 2.1, then Auto Low Latency Mode should be triggered. If + * the display is internally connected and a custom low latency mode is available, that should + * be triggered. + * + * This function should only be called if the display reports support for + * DisplayCapability::AUTO_LOW_LATENCY_MODE from getDisplayCapabilities_2_4. + * + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * UNSUPPORTED when AUTO_LOW_LATENCY_MODE is not supported by the composer + * implementation or the given display + */ + setAutoLowLatencyMode(Display display, bool on) + generates (Error error); + + /** + * Provides a list of all the content types supported by this display (any of + * ContentType::{GRAPHICS, PHOTO, CINEMA, GAME}). This list must not change after + * initialization. + * + * Content types are introduced in HDMI 1.4 and supporting them is optional. The + * ContentType::NONE is always supported and will not be returned by this method.. + * + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * @return supportedContentTypes is a list of supported content types. + */ + getSupportedContentTypes(Display display) + generates(Error error, vec supportedContentTypes); + + /** + * Instructs the connected display that the content being shown is of the given type - one of + * GRAPHICS, PHOTO, CINEMA, GAME. + * + * Content types are introduced in HDMI 1.4 and supporting them is optional. If they are + * supported, this signal should switch the display to a mode that is optimal for the given + * type of content. See HDMI 1.4 specification for more information. + * + * If the display is internally connected (not through HDMI), and such modes are available, + * this method should trigger them. + * + * This function should only be called if the display reports support for the corresponding + * content type (ContentType::{GRAPHICS, PHOTO, CINEMA, GAME}) from getSupportedContentTypes. + * ContentType::NONE is supported by default and can always be set. + * + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * UNSUPPORTED when the given content type is not supported by the composer + * implementation or the given display + */ + setContentType(Display display, ContentType type) + generates (Error error); }; diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h index 4160ed97bf..dcd959dfb5 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h @@ -139,6 +139,24 @@ class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImpl setAutoLowLatencyMode(Display display, bool on) override { + return mHal->setAutoLowLatencyMode(display, on); + } + + Return getSupportedContentTypes( + Display display, IComposerClient::getSupportedContentTypes_cb hidl_cb) override { + std::vector supportedContentTypes; + Error error = mHal->getSupportedContentTypes(display, &supportedContentTypes); + + hidl_cb(error, supportedContentTypes); + return Void(); + } + + Return setContentType(Display display, + IComposerClient::ContentType contentType) override { + return mHal->setContentType(display, contentType); + } + static std::unique_ptr create(Hal* hal) { auto client = std::make_unique(hal); return client->init() ? std::move(client) : nullptr; diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h index 89dbe66d60..a1e56ae6ed 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h @@ -67,6 +67,11 @@ class ComposerHal : public V2_3::hal::ComposerHal { Display display, Config config, const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, VsyncPeriodChangeTimeline* timeline) = 0; + virtual Error setAutoLowLatencyMode(Display display, bool on) = 0; + virtual Error getSupportedContentTypes( + Display display, + std::vector* outSupportedContentTypes) = 0; + virtual Error setContentType(Display display, IComposerClient::ContentType contentType) = 0; }; } // namespace hal diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h index d59d0d5361..a27582a0e7 100644 --- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h +++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h @@ -167,6 +167,57 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { return Error::NONE; } + Error setAutoLowLatencyMode(Display display, bool on) override { + if (!mDispatch.setAutoLowLatencyMode) { + return Error::UNSUPPORTED; + } + + int32_t error = mDispatch.setAutoLowLatencyMode(mDevice, display, on); + if (error != HWC2_ERROR_NONE) { + return static_cast(error); + } + return Error::NONE; + } + + Error getSupportedContentTypes( + Display display, + std::vector* outSupportedContentTypes) override { + if (!mDispatch.getSupportedContentTypes) { + return Error::UNSUPPORTED; + } + + uint32_t count = 0; + int32_t error = mDispatch.getSupportedContentTypes(mDevice, display, &count, nullptr); + if (error != HWC2_ERROR_NONE) { + return static_cast(error); + } + + outSupportedContentTypes->resize(count); + + error = mDispatch.getSupportedContentTypes( + mDevice, display, &count, + reinterpret_cast::type*>( + outSupportedContentTypes->data())); + if (error != HWC2_ERROR_NONE) { + *outSupportedContentTypes = std::vector(); + return static_cast(error); + } + return Error::NONE; + } + + Error setContentType(Display display, IComposerClient::ContentType contentType) override { + if (!mDispatch.setContentType) { + return Error::UNSUPPORTED; + } + + int32_t error = + mDispatch.setContentType(mDevice, display, static_cast(contentType)); + if (error != HWC2_ERROR_NONE) { + return static_cast(error); + } + return Error::NONE; + } + protected: bool initDispatch() override { if (!BaseType2_3::initDispatch()) { @@ -179,6 +230,11 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { &mDispatch.getDisplayVsyncPeriod); this->initOptionalDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS, &mDispatch.setActiveConfigWithConstraints); + this->initOptionalDispatch(HWC2_FUNCTION_SET_AUTO_LOW_LATENCY_MODE, + &mDispatch.setAutoLowLatencyMode); + this->initOptionalDispatch(HWC2_FUNCTION_GET_SUPPORTED_CONTENT_TYPES, + &mDispatch.getSupportedContentTypes); + this->initOptionalDispatch(HWC2_FUNCTION_SET_CONTENT_TYPE, &mDispatch.setContentType); return true; } @@ -222,6 +278,9 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE getDisplayConnectionType; HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD getDisplayVsyncPeriod; HWC2_PFN_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS setActiveConfigWithConstraints; + HWC2_PFN_SET_AUTO_LOW_LATENCY_MODE setAutoLowLatencyMode; + HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES getSupportedContentTypes; + HWC2_PFN_SET_CONTENT_TYPE setContentType; } mDispatch = {}; hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr; diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp index 35ac23f7ff..5b06d6d3ff 100644 --- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp @@ -106,6 +106,25 @@ Error ComposerClient::setActiveConfigWithConstraints( return error; } +Error ComposerClient::setAutoLowLatencyMode(Display display, bool on) { + return mClient->setAutoLowLatencyMode(display, on); +} + +Error ComposerClient::getSupportedContentTypes( + Display display, std::vector* outSupportedContentTypes) { + Error error = Error::NONE; + mClient->getSupportedContentTypes( + display, [&](const auto& tmpError, const auto& tmpSupportedContentTypes) { + error = tmpError; + *outSupportedContentTypes = tmpSupportedContentTypes; + }); + return error; +} + +Error ComposerClient::setContentType(Display display, IComposerClient::ContentType contentType) { + return mClient->setContentType(display, contentType); +} + } // namespace vts } // namespace V2_4 } // namespace composer diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h index 83e74ed698..b094bc8028 100644 --- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h @@ -84,6 +84,13 @@ class ComposerClient : public V2_3::vts::ComposerClient { const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, VsyncPeriodChangeTimeline* timeline); + Error setAutoLowLatencyMode(Display display, bool on); + + Error getSupportedContentTypes( + Display display, std::vector* outSupportedContentTypes); + + Error setContentType(Display display, IComposerClient::ContentType contentType); + private: const sp mClient; }; diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index f038f551e3..6b6f2a5b5d 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -47,6 +47,9 @@ using common::V1_2::PixelFormat; using mapper::V2_0::IMapper; using mapper::V2_0::vts::Gralloc; +using ContentType = IComposerClient::ContentType; +using DisplayCapability = IComposerClient::DisplayCapability; + class GraphicsComposerHidlTest : public ::testing::TestWithParam { protected: void SetUp() override { @@ -117,6 +120,11 @@ class GraphicsComposerHidlTest : public ::testing::TestWithParam { void Test_setActiveConfigWithConstraints( const IComposerClient::VsyncPeriodChangeConstraints& constraints); + void Test_setContentType(const ContentType& contentType, const char* contentTypeStr); + void Test_setContentTypeForDisplay(const Display& display, + const std::vector& capabilities, + const ContentType& contentType, const char* contentTypeStr); + std::unique_ptr mComposer; std::unique_ptr mComposerClient; sp mComposerCallback; @@ -377,6 +385,117 @@ TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_delayed) { Test_setActiveConfigWithConstraints(constraints); } +TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyModeBadDisplay) { + EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setAutoLowLatencyMode(mInvalidDisplayId, true)); + EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setAutoLowLatencyMode(mInvalidDisplayId, false)); +} + +TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyMode) { + for (Display display : mComposerCallback->getDisplays()) { + std::vector capabilities; + const auto error = mComposerClient->getDisplayCapabilities(display, &capabilities); + EXPECT_EQ(Error::NONE, error); + + const bool allmSupport = + std::find(capabilities.begin(), capabilities.end(), + DisplayCapability::AUTO_LOW_LATENCY_MODE) != capabilities.end(); + + if (!allmSupport) { + EXPECT_EQ(Error::UNSUPPORTED, + mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, true)); + EXPECT_EQ(Error::UNSUPPORTED, + mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false)); + GTEST_SUCCEED() << "Auto Low Latency Mode is not supported on display " + << to_string(display) << ", skipping test"; + return; + } + + EXPECT_EQ(Error::NONE, mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, true)); + EXPECT_EQ(Error::NONE, mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false)); + } +} + +TEST_P(GraphicsComposerHidlTest, getSupportedContentTypesBadDisplay) { + std::vector supportedContentTypes; + const auto error = + mComposerClient->getSupportedContentTypes(mInvalidDisplayId, &supportedContentTypes); + EXPECT_EQ(Error::BAD_DISPLAY, error); +} + +TEST_P(GraphicsComposerHidlTest, getSupportedContentTypes) { + std::vector supportedContentTypes; + for (Display display : mComposerCallback->getDisplays()) { + supportedContentTypes.clear(); + const auto error = + mComposerClient->getSupportedContentTypes(display, &supportedContentTypes); + const bool noneSupported = + std::find(supportedContentTypes.begin(), supportedContentTypes.end(), + ContentType::NONE) != supportedContentTypes.end(); + EXPECT_EQ(Error::NONE, error); + EXPECT_FALSE(noneSupported); + } +} + +TEST_P(GraphicsComposerHidlTest, setContentTypeNoneAlwaysAccepted) { + for (Display display : mComposerCallback->getDisplays()) { + const auto error = mComposerClient->setContentType(display, ContentType::NONE); + EXPECT_NE(Error::UNSUPPORTED, error); + } +} + +TEST_P(GraphicsComposerHidlTest, setContentTypeBadDisplay) { + const auto types = {ContentType::NONE, ContentType::GRAPHICS, ContentType::PHOTO, + ContentType::CINEMA, ContentType::GAME}; + for (auto type : types) { + EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setContentType(mInvalidDisplayId, type)); + } +} + +void GraphicsComposerHidlTest::Test_setContentTypeForDisplay( + const Display& display, const std::vector& capabilities, + const ContentType& contentType, const char* contentTypeStr) { + const bool contentTypeSupport = + std::find(capabilities.begin(), capabilities.end(), contentType) != capabilities.end(); + + if (!contentTypeSupport) { + EXPECT_EQ(Error::UNSUPPORTED, mComposerClient->setContentType(display, contentType)); + GTEST_SUCCEED() << contentTypeStr << " content type is not supported on display " + << to_string(display) << ", skipping test"; + return; + } + + EXPECT_EQ(Error::NONE, mComposerClient->setContentType(display, contentType)); + EXPECT_EQ(Error::NONE, mComposerClient->setContentType(display, ContentType::NONE)); +} + +void GraphicsComposerHidlTest::Test_setContentType(const ContentType& contentType, + const char* contentTypeStr) { + for (Display display : mComposerCallback->getDisplays()) { + std::vector supportedContentTypes; + const auto error = + mComposerClient->getSupportedContentTypes(display, &supportedContentTypes); + EXPECT_EQ(Error::NONE, error); + + Test_setContentTypeForDisplay(display, supportedContentTypes, contentType, contentTypeStr); + } +} + +TEST_P(GraphicsComposerHidlTest, setGraphicsContentType) { + Test_setContentType(ContentType::GRAPHICS, "GRAPHICS"); +} + +TEST_P(GraphicsComposerHidlTest, setPhotoContentType) { + Test_setContentType(ContentType::PHOTO, "PHOTO"); +} + +TEST_P(GraphicsComposerHidlTest, setCinemaContentType) { + Test_setContentType(ContentType::CINEMA, "CINEMA"); +} + +TEST_P(GraphicsComposerHidlTest, setGameContentType) { + Test_setContentType(ContentType::GAME, "GAME"); +} + INSTANTIATE_TEST_SUITE_P( PerInstance, GraphicsComposerHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), From e9f0b92568bd30782b844e7aff943844257d720d Mon Sep 17 00:00:00 2001 From: Przemyslaw Szczepaniak Date: Fri, 29 Nov 2019 09:49:17 +0000 Subject: [PATCH 0320/1022] Add TENSOR_QUANT8_ASYMM_SIGNED support for ARG(MIN|MAX) Test: CTS/VTS Change-Id: I4a90642f4d8500237fd41de76687fbe4c021b652 --- neuralnetworks/1.3/vts/functional/ValidateModel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 242e12ecc7..6fd54071f9 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -340,7 +340,8 @@ static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, con case OperationType::ARGMAX: case OperationType::ARGMIN: { if (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32 || - type == OperandType::TENSOR_INT32 || type == OperandType::TENSOR_QUANT8_ASYMM) { + type == OperandType::TENSOR_INT32 || type == OperandType::TENSOR_QUANT8_ASYMM || + type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) { return true; } } break; From 84c4d394806cc9787763eccd468b08e4f95d8796 Mon Sep 17 00:00:00 2001 From: lesl Date: Fri, 6 Dec 2019 13:54:52 +0800 Subject: [PATCH 0321/1022] Freeze wifi hostapd 1.2 HAL For R release, so that the tree is in a shippable state. If further changes to it are needed in R, this hash can be updated. Bug: 142752869 Test: build (checks hashes) Change-Id: If035ab957d472ca1b347eecd1f1dddfbbd3cd1c4 --- current.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/current.txt b/current.txt index c716c5431b..b828c6ccf7 100644 --- a/current.txt +++ b/current.txt @@ -637,6 +637,8 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback cf1d55e8c68300090747ab90b94c22e4c859b29c84ced68a317c595bb115eab2 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi +03d37dfebbc27b13adce1ed6389ac483bf7cf32488ca14037c5569bc3e903e4f android.hardware.wifi.hostapd@1.2::IHostapd +2defa258951e25a132aaeb36e3febe6f41bf9c6dbb1b1ebdf0b41708ab4e107e android.hardware.wifi.hostapd@1.2::types a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant 44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface 619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback From 96856f48b0a819626fbe846a8f2f18558c4f1018 Mon Sep 17 00:00:00 2001 From: Hayden Gomes Date: Mon, 9 Dec 2019 16:41:44 -0800 Subject: [PATCH 0322/1022] Adding audiocontrol and evs hashes to current.txt - Added hashes for IAudioControl, IEvsCamera, IEvsCameraStream, IEvsDisplay, IEvsEnumeration, and evs@1.0::types - SHAs changed due to changes in comments. No API functionality changes have been made Bug: 142877791 Test: Ran vts module VtsTrebleVendorVintfTest Change-Id: I01d74858addaf0d59bd6c99407dc265d70045e27 --- current.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/current.txt b/current.txt index c716c5431b..099fa3d78e 100644 --- a/current.txt +++ b/current.txt @@ -572,6 +572,12 @@ efbb061c969fa9553d243da6ee23b83fe5d4aa663a7b8896adc52e2b015bc2f3 android.hardwar cfa81f229b69f9011c58f48264fcb552447430fe68610eac514e811e65bc306a android.hardware.wifi.supplicant@1.2::types # ABI preserving changes to HALs during Android R +c3ec182ce325862b7d79e526f3e170c02cfee1497ed309d7c60d0de4ca636b0b android.hardware.automotive.audiocontrol@1.0::IAudioControl +1b6d0927615ddbf4c56a993fa1845bca15543e315fb6f48c77276e2fa2918ac5 android.hardware.automotive.evs@1.0::IEvsCamera +3901859d36b7b4d32910d61cd1e8982b0ffeb8fb77b457ac6349e8bf1abcd595 android.hardware.automotive.evs@1.0::IEvsCameraStream +578f640c653726d58f99c84a7e1bb63862e21ef7cbb4f7d95c3cc62de00dca35 android.hardware.automotive.evs@1.0::IEvsDisplay +f5bc6aa840db933cb9fd36668b06d3e2021cf5384bb70e459f22e2f2f921fba5 android.hardware.automotive.evs@1.0::IEvsEnumerator +d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardware.automotive.evs@1.0::types 2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel From 353357bffe8e6ee5a01109f4c77f5f7bd5153aee Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Fri, 6 Dec 2019 09:30:29 -0800 Subject: [PATCH 0323/1022] gralloc: use gralloctypes helper Use the gralloctypes helper function to determine if a PlaneLayoutComponentType is a standard type. Also update the lock RGBA_8888 function to ignore non-standard PlaneLayoutComponentTypes. Bug: 141632767 Test: VtsHalGraphicsMapperV4_0TargetTest Change-Id: Ie3ea4a22b2c9ecf4b1d85932833978d2e23f77c1 --- .../vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 347eca6063..b8414d4448 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -131,7 +131,9 @@ class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase { int64_t offsetInBitsA = -1; for (const auto& component : planeLayout.components) { - EXPECT_EQ(GRALLOC4_PLANE_LAYOUT_COMPONENT_TYPE, component.type.name); + if (!gralloc4::isStandardPlaneLayoutComponentType(component.type)) { + continue; + } EXPECT_EQ(8, component.sizeInBits); if (component.type.value == gralloc4::PlaneLayoutComponentType_R.value) { offsetInBitsR = component.offsetInBits; @@ -221,9 +223,7 @@ class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase { for (const auto& planeLayout : planeLayouts) { for (const auto& planeLayoutComponent : planeLayout.components) { - std::string componentTypeName = planeLayoutComponent.type.name; - if (!std::strncmp(componentTypeName.c_str(), GRALLOC4_PLANE_LAYOUT_COMPONENT_TYPE, - componentTypeName.size())) { + if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) { continue; } ASSERT_EQ(0, planeLayoutComponent.offsetInBits % 8); From 46245c59d79c82c8ebba2f7f3d6b0c09b4250ca2 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Fri, 6 Dec 2019 16:12:53 -0800 Subject: [PATCH 0324/1022] Convert VtsHalGraphicsMapperV4_0TargetTest to be parameterized test Bug: 142397658 Test: atest VtsHalGraphicsMapperV4_0TargetTest Change-Id: I3854f9d4e601d37952e41a5c503f3b1d833c47a5 --- graphics/mapper/4.0/utils/vts/MapperVts.cpp | 10 +- .../vts/include/mapper-vts/4.0/MapperVts.h | 1 + graphics/mapper/4.0/vts/functional/Android.bp | 6 +- .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 228 ++++++++---------- 4 files changed, 112 insertions(+), 133 deletions(-) diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp index c317ed2918..8a5f54ebac 100644 --- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp +++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp @@ -17,8 +17,6 @@ #include #include -#include - namespace android { namespace hardware { namespace graphics { @@ -36,19 +34,19 @@ Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& map } void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) { - mAllocator = ::testing::VtsHalHidlTargetTestBase::getService(allocatorServiceName); + mAllocator = IAllocator::getService(allocatorServiceName); ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service"; - mMapper = ::testing::VtsHalHidlTargetTestBase::getService(mapperServiceName); + mMapper = IMapper::getService(mapperServiceName); ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service"; ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode"; } void Gralloc::initNoErr(const std::string& allocatorServiceName, const std::string& mapperServiceName) { - mAllocator = ::testing::VtsHalHidlTargetTestBase::getService(allocatorServiceName); + mAllocator = IAllocator::getService(allocatorServiceName); - mMapper = ::testing::VtsHalHidlTargetTestBase::getService(mapperServiceName); + mMapper = IMapper::getService(mapperServiceName); if (mMapper.get()) { ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode"; } diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h index eed043f46c..1c635c402c 100644 --- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h +++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h @@ -22,6 +22,7 @@ #include #include +#include #include namespace android { diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp index 506026d8bf..926cf31f5c 100644 --- a/graphics/mapper/4.0/vts/functional/Android.bp +++ b/graphics/mapper/4.0/vts/functional/Android.bp @@ -20,7 +20,9 @@ cc_test { srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"], static_libs: [ "android.hardware.graphics.mapper@4.0-vts", + "libgralloctypes", "libsync", + "vintf-graphics-common-ndk_platform", ], shared_libs: [ "android.hardware.graphics.allocator@4.0", @@ -28,11 +30,9 @@ cc_test { "android.hardware.graphics.common@1.1", "android.hardware.graphics.common@1.2", "android.hardware.graphics.mapper@4.0", - "libgralloctypes", - "vintf-graphics-common-ndk_platform", ], header_libs: [ "libsystem_headers", ], - test_suites: ["general-tests"], + test_suites: ["general-tests", "vts-core"], } diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 347eca6063..4ca5e7e064 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -23,10 +23,12 @@ #include -#include #include #include #include +#include +#include +#include #include #include @@ -52,28 +54,12 @@ using aidl::android::hardware::graphics::common::StandardMetadataType; using DecodeFunction = std::function& vec)>; -// Test environment for graphics.mapper. -class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static GraphicsMapperHidlEnvironment* Instance() { - static GraphicsMapperHidlEnvironment* instance = new GraphicsMapperHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { - registerTestService(); - registerTestService(); - } -}; - -class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class GraphicsMapperHidlTest + : public ::testing::TestWithParam> { protected: void SetUp() override { - ASSERT_NO_FATAL_FAILURE( - mGralloc = std::make_unique( - GraphicsMapperHidlEnvironment::Instance()->getServiceName(), - GraphicsMapperHidlEnvironment::Instance()->getServiceName())); + ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique(std::get<0>(GetParam()), + std::get<1>(GetParam()))); ASSERT_NE(nullptr, mGralloc->getAllocator().get()); ASSERT_NE(nullptr, mGralloc->getMapper().get()); @@ -322,14 +308,14 @@ const std::set GraphicsMapperHidlTest::sRequiredMetadataTy /** * Test IAllocator::dumpDebugInfo by calling it. */ -TEST_F(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) { +TEST_P(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) { mGralloc->dumpDebugInfo(); } /** * Test IAllocator::allocate with valid buffer descriptors. */ -TEST_F(GraphicsMapperHidlTest, AllocatorAllocate) { +TEST_P(GraphicsMapperHidlTest, AllocatorAllocate) { BufferDescriptor descriptor; ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo)); @@ -352,7 +338,7 @@ TEST_F(GraphicsMapperHidlTest, AllocatorAllocate) { /** * Test IAllocator::allocate with invalid buffer descriptors. */ -TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNegative) { +TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNegative) { // this assumes any valid descriptor is non-empty BufferDescriptor descriptor; mGralloc->getAllocator()->allocate(descriptor, 1, @@ -364,7 +350,7 @@ TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNegative) { /** * Test IAllocator::allocate does not leak. */ -TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) { +TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) { auto info = mDummyDescriptorInfo; info.width = 1024; info.height = 1024; @@ -378,7 +364,7 @@ TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) { /** * Test that IAllocator::allocate is thread-safe. */ -TEST_F(GraphicsMapperHidlTest, AllocatorAllocateThreaded) { +TEST_P(GraphicsMapperHidlTest, AllocatorAllocateThreaded) { BufferDescriptor descriptor; ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo)); @@ -409,14 +395,14 @@ TEST_F(GraphicsMapperHidlTest, AllocatorAllocateThreaded) { /** * Test IMapper::createDescriptor with valid descriptor info. */ -TEST_F(GraphicsMapperHidlTest, CreateDescriptorBasic) { +TEST_P(GraphicsMapperHidlTest, CreateDescriptorBasic) { ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo)); } /** * Test IMapper::createDescriptor with invalid descriptor info. */ -TEST_F(GraphicsMapperHidlTest, CreateDescriptorNegative) { +TEST_P(GraphicsMapperHidlTest, CreateDescriptorNegative) { auto info = mDummyDescriptorInfo; info.width = 0; mGralloc->getMapper()->createDescriptor(info, [&](const auto& tmpError, const auto&) { @@ -427,7 +413,7 @@ TEST_F(GraphicsMapperHidlTest, CreateDescriptorNegative) { /** * Test IMapper::importBuffer and IMapper::freeBuffer with allocated buffers. */ -TEST_F(GraphicsMapperHidlTest, ImportFreeBufferBasic) { +TEST_P(GraphicsMapperHidlTest, ImportFreeBufferBasic) { const native_handle_t* bufferHandle; ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle)); @@ -436,7 +422,7 @@ TEST_F(GraphicsMapperHidlTest, ImportFreeBufferBasic) { /** * Test IMapper::importBuffer and IMapper::freeBuffer with cloned buffers. */ -TEST_F(GraphicsMapperHidlTest, ImportFreeBufferClone) { +TEST_P(GraphicsMapperHidlTest, ImportFreeBufferClone) { const native_handle_t* clonedBufferHandle; ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false)); @@ -454,7 +440,7 @@ TEST_F(GraphicsMapperHidlTest, ImportFreeBufferClone) { /** * Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances. */ -TEST_F(GraphicsMapperHidlTest, ImportFreeBufferSingleton) { +TEST_P(GraphicsMapperHidlTest, ImportFreeBufferSingleton) { const native_handle_t* rawHandle; ASSERT_NO_FATAL_FAILURE(rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false)); @@ -466,10 +452,8 @@ TEST_F(GraphicsMapperHidlTest, ImportFreeBufferSingleton) { // free the imported handle with another mapper std::unique_ptr anotherGralloc; - ASSERT_NO_FATAL_FAILURE( - anotherGralloc = std::make_unique( - GraphicsMapperHidlEnvironment::Instance()->getServiceName(), - GraphicsMapperHidlEnvironment::Instance()->getServiceName())); + ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique(std::get<0>(GetParam()), + std::get<1>(GetParam()))); Error error = mGralloc->getMapper()->freeBuffer(importedHandle); ASSERT_EQ(Error::NONE, error); @@ -479,7 +463,7 @@ TEST_F(GraphicsMapperHidlTest, ImportFreeBufferSingleton) { /** * Test IMapper::importBuffer and IMapper::freeBuffer do not leak. */ -TEST_F(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) { +TEST_P(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) { auto info = mDummyDescriptorInfo; info.width = 1024; info.height = 1024; @@ -493,7 +477,7 @@ TEST_F(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) { /** * Test IMapper::importBuffer with invalid buffers. */ -TEST_F(GraphicsMapperHidlTest, ImportBufferNegative) { +TEST_P(GraphicsMapperHidlTest, ImportBufferNegative) { native_handle_t* invalidHandle = nullptr; mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_BUFFER, tmpError) @@ -511,7 +495,7 @@ TEST_F(GraphicsMapperHidlTest, ImportBufferNegative) { /** * Test IMapper::freeBuffer with invalid buffers. */ -TEST_F(GraphicsMapperHidlTest, FreeBufferNegative) { +TEST_P(GraphicsMapperHidlTest, FreeBufferNegative) { native_handle_t* invalidHandle = nullptr; Error error = mGralloc->getMapper()->freeBuffer(invalidHandle); EXPECT_EQ(Error::BAD_BUFFER, error) << "freeBuffer with nullptr did not fail with BAD_BUFFER"; @@ -534,7 +518,7 @@ TEST_F(GraphicsMapperHidlTest, FreeBufferNegative) { /** * Test IMapper::lock and IMapper::unlock. */ -TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) { +TEST_P(GraphicsMapperHidlTest, LockUnlockBasic) { const auto& info = mDummyDescriptorInfo; const native_handle_t* bufferHandle; @@ -565,7 +549,7 @@ TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) { } } -TEST_F(GraphicsMapperHidlTest, Lock_YCBCR_420_888) { +TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_420_888) { auto info = mDummyDescriptorInfo; info.format = PixelFormat::YCBCR_420_888; @@ -638,7 +622,7 @@ TEST_F(GraphicsMapperHidlTest, Lock_YCBCR_420_888) { /** * Test IMapper::unlock with bad access region */ -TEST_F(GraphicsMapperHidlTest, LockBadAccessRegion) { +TEST_P(GraphicsMapperHidlTest, LockBadAccessRegion) { const auto& info = mDummyDescriptorInfo; const native_handle_t* bufferHandle; @@ -680,7 +664,7 @@ TEST_F(GraphicsMapperHidlTest, LockBadAccessRegion) { /** * Test IMapper::unlock with invalid buffers. */ -TEST_F(GraphicsMapperHidlTest, UnlockNegative) { +TEST_P(GraphicsMapperHidlTest, UnlockNegative) { native_handle_t* invalidHandle = nullptr; mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_BUFFER, tmpError) @@ -718,7 +702,7 @@ TEST_F(GraphicsMapperHidlTest, UnlockNegative) { /** * Test IMapper::flush and IMapper::reread. */ -TEST_F(GraphicsMapperHidlTest, FlushRereadBasic) { +TEST_P(GraphicsMapperHidlTest, FlushRereadBasic) { const auto& info = mDummyDescriptorInfo; const native_handle_t* rawHandle; @@ -770,7 +754,7 @@ TEST_F(GraphicsMapperHidlTest, FlushRereadBasic) { /** * Test IMapper::flushLockedBuffer with bad buffer */ -TEST_F(GraphicsMapperHidlTest, FlushLockedBufferBadBuffer) { +TEST_P(GraphicsMapperHidlTest, FlushLockedBufferBadBuffer) { ASSERT_NO_FATAL_FAILURE(mGralloc->getMapper()->flushLockedBuffer( nullptr, [&](const auto& tmpError, const auto& /*tmpReleaseFence*/) { ASSERT_EQ(Error::BAD_BUFFER, tmpError); @@ -780,14 +764,14 @@ TEST_F(GraphicsMapperHidlTest, FlushLockedBufferBadBuffer) { /** * Test IMapper::rereadLockedBuffer with bad buffer */ -TEST_F(GraphicsMapperHidlTest, RereadLockedBufferBadBuffer) { +TEST_P(GraphicsMapperHidlTest, RereadLockedBufferBadBuffer) { ASSERT_EQ(Error::BAD_BUFFER, mGralloc->getMapper()->rereadLockedBuffer(nullptr)); } /** * Test IMapper::isSupported with required format RGBA_8888 */ -TEST_F(GraphicsMapperHidlTest, IsSupportedRGBA8888) { +TEST_P(GraphicsMapperHidlTest, IsSupportedRGBA8888) { const auto& info = mDummyDescriptorInfo; bool supported = false; @@ -798,7 +782,7 @@ TEST_F(GraphicsMapperHidlTest, IsSupportedRGBA8888) { /** * Test IMapper::isSupported with required format YV12 */ -TEST_F(GraphicsMapperHidlTest, IsSupportedYV12) { +TEST_P(GraphicsMapperHidlTest, IsSupportedYV12) { auto info = mDummyDescriptorInfo; info.format = PixelFormat::YV12; bool supported = false; @@ -810,7 +794,7 @@ TEST_F(GraphicsMapperHidlTest, IsSupportedYV12) { /** * Test IMapper::isSupported with optional format Y16 */ -TEST_F(GraphicsMapperHidlTest, IsSupportedY16) { +TEST_P(GraphicsMapperHidlTest, IsSupportedY16) { auto info = mDummyDescriptorInfo; info.format = PixelFormat::Y16; bool supported = false; @@ -821,7 +805,7 @@ TEST_F(GraphicsMapperHidlTest, IsSupportedY16) { /** * Test IMapper::get(BufferId) */ -TEST_F(GraphicsMapperHidlTest, GetBufferId) { +TEST_P(GraphicsMapperHidlTest, GetBufferId) { testGet(mDummyDescriptorInfo, gralloc4::MetadataType_BufferId, [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { uint64_t bufferId = 0; @@ -832,7 +816,7 @@ TEST_F(GraphicsMapperHidlTest, GetBufferId) { /** * Test IMapper::get(Name) */ -TEST_F(GraphicsMapperHidlTest, GetName) { +TEST_P(GraphicsMapperHidlTest, GetName) { testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Name, [](const IMapper::BufferDescriptorInfo& info, const hidl_vec& vec) { std::string name; @@ -844,7 +828,7 @@ TEST_F(GraphicsMapperHidlTest, GetName) { /** * Test IMapper::get(Width) */ -TEST_F(GraphicsMapperHidlTest, GetWidth) { +TEST_P(GraphicsMapperHidlTest, GetWidth) { testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Width, [](const IMapper::BufferDescriptorInfo& info, const hidl_vec& vec) { uint64_t width = 0; @@ -856,7 +840,7 @@ TEST_F(GraphicsMapperHidlTest, GetWidth) { /** * Test IMapper::get(Height) */ -TEST_F(GraphicsMapperHidlTest, GetHeight) { +TEST_P(GraphicsMapperHidlTest, GetHeight) { testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Height, [](const IMapper::BufferDescriptorInfo& info, const hidl_vec& vec) { uint64_t height = 0; @@ -868,7 +852,7 @@ TEST_F(GraphicsMapperHidlTest, GetHeight) { /** * Test IMapper::get(LayerCount) */ -TEST_F(GraphicsMapperHidlTest, GetLayerCount) { +TEST_P(GraphicsMapperHidlTest, GetLayerCount) { testGet(mDummyDescriptorInfo, gralloc4::MetadataType_LayerCount, [](const IMapper::BufferDescriptorInfo& info, const hidl_vec& vec) { uint64_t layerCount = 0; @@ -880,7 +864,7 @@ TEST_F(GraphicsMapperHidlTest, GetLayerCount) { /** * Test IMapper::get(PixelFormatRequested) */ -TEST_F(GraphicsMapperHidlTest, GetPixelFormatRequested) { +TEST_P(GraphicsMapperHidlTest, GetPixelFormatRequested) { testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatRequested, [](const IMapper::BufferDescriptorInfo& info, const hidl_vec& vec) { PixelFormat pixelFormatRequested = PixelFormat::BLOB; @@ -893,7 +877,7 @@ TEST_F(GraphicsMapperHidlTest, GetPixelFormatRequested) { /** * Test IMapper::get(PixelFormatFourCC) */ -TEST_F(GraphicsMapperHidlTest, GetPixelFormatFourCC) { +TEST_P(GraphicsMapperHidlTest, GetPixelFormatFourCC) { testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC, [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { uint32_t pixelFormatFourCC = 0; @@ -904,7 +888,7 @@ TEST_F(GraphicsMapperHidlTest, GetPixelFormatFourCC) { /** * Test IMapper::get(PixelFormatModifier) */ -TEST_F(GraphicsMapperHidlTest, GetPixelFormatModifier) { +TEST_P(GraphicsMapperHidlTest, GetPixelFormatModifier) { testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier, [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { uint64_t pixelFormatModifier = 0; @@ -915,7 +899,7 @@ TEST_F(GraphicsMapperHidlTest, GetPixelFormatModifier) { /** * Test IMapper::get(Usage) */ -TEST_F(GraphicsMapperHidlTest, GetUsage) { +TEST_P(GraphicsMapperHidlTest, GetUsage) { testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage, [](const IMapper::BufferDescriptorInfo& info, const hidl_vec& vec) { uint64_t usage = 0; @@ -927,7 +911,7 @@ TEST_F(GraphicsMapperHidlTest, GetUsage) { /** * Test IMapper::get(AllocationSize) */ -TEST_F(GraphicsMapperHidlTest, GetAllocationSize) { +TEST_P(GraphicsMapperHidlTest, GetAllocationSize) { testGet(mDummyDescriptorInfo, gralloc4::MetadataType_AllocationSize, [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { uint64_t allocationSize = 0; @@ -938,7 +922,7 @@ TEST_F(GraphicsMapperHidlTest, GetAllocationSize) { /** * Test IMapper::get(ProtectedContent) */ -TEST_F(GraphicsMapperHidlTest, GetProtectedContent) { +TEST_P(GraphicsMapperHidlTest, GetProtectedContent) { auto info = mDummyDescriptorInfo; info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY; @@ -960,7 +944,7 @@ TEST_F(GraphicsMapperHidlTest, GetProtectedContent) { /** * Test IMapper::get(Compression) */ -TEST_F(GraphicsMapperHidlTest, GetCompression) { +TEST_P(GraphicsMapperHidlTest, GetCompression) { auto info = mDummyDescriptorInfo; info.usage = static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); @@ -977,7 +961,7 @@ TEST_F(GraphicsMapperHidlTest, GetCompression) { /** * Test IMapper::get(Interlaced) */ -TEST_F(GraphicsMapperHidlTest, GetInterlaced) { +TEST_P(GraphicsMapperHidlTest, GetInterlaced) { testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Interlaced, [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { ExtendableType interlaced = gralloc4::Interlaced_TopBottom; @@ -991,7 +975,7 @@ TEST_F(GraphicsMapperHidlTest, GetInterlaced) { /** * Test IMapper::get(ChromaSiting) */ -TEST_F(GraphicsMapperHidlTest, GetChromaSiting) { +TEST_P(GraphicsMapperHidlTest, GetChromaSiting) { testGet(mDummyDescriptorInfo, gralloc4::MetadataType_ChromaSiting, [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { ExtendableType chromaSiting = gralloc4::ChromaSiting_Unknown; @@ -1005,7 +989,7 @@ TEST_F(GraphicsMapperHidlTest, GetChromaSiting) { /** * Test IMapper::get(PlaneLayouts) */ -TEST_F(GraphicsMapperHidlTest, GetPlaneLayouts) { +TEST_P(GraphicsMapperHidlTest, GetPlaneLayouts) { const native_handle_t* bufferHandle = nullptr; ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); @@ -1021,7 +1005,7 @@ TEST_F(GraphicsMapperHidlTest, GetPlaneLayouts) { /** * Test IMapper::get(Dataspace) */ -TEST_F(GraphicsMapperHidlTest, GetDataspace) { +TEST_P(GraphicsMapperHidlTest, GetDataspace) { testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Dataspace, [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { Dataspace dataspace = Dataspace::DISPLAY_P3; @@ -1033,7 +1017,7 @@ TEST_F(GraphicsMapperHidlTest, GetDataspace) { /** * Test IMapper::get(BlendMode) */ -TEST_F(GraphicsMapperHidlTest, GetBlendMode) { +TEST_P(GraphicsMapperHidlTest, GetBlendMode) { testGet(mDummyDescriptorInfo, gralloc4::MetadataType_BlendMode, [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { BlendMode blendMode = BlendMode::NONE; @@ -1045,7 +1029,7 @@ TEST_F(GraphicsMapperHidlTest, GetBlendMode) { /** * Test IMapper::get(metadata) with a bad buffer */ -TEST_F(GraphicsMapperHidlTest, GetMetadataBadValue) { +TEST_P(GraphicsMapperHidlTest, GetMetadataBadValue) { const native_handle_t* bufferHandle = nullptr; hidl_vec vec; ASSERT_EQ(Error::BAD_BUFFER, @@ -1100,7 +1084,7 @@ TEST_F(GraphicsMapperHidlTest, GetMetadataBadValue) { /** * Test IMapper::get(metadata) for unsupported metadata */ -TEST_F(GraphicsMapperHidlTest, GetUnsupportedMetadata) { +TEST_P(GraphicsMapperHidlTest, GetUnsupportedMetadata) { const native_handle_t* bufferHandle = nullptr; ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); @@ -1114,7 +1098,7 @@ TEST_F(GraphicsMapperHidlTest, GetUnsupportedMetadata) { /** * Test IMapper::get(metadata) for unsupported standard metadata */ -TEST_F(GraphicsMapperHidlTest, GetUnsupportedStandardMetadata) { +TEST_P(GraphicsMapperHidlTest, GetUnsupportedStandardMetadata) { const native_handle_t* bufferHandle = nullptr; ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); @@ -1128,7 +1112,7 @@ TEST_F(GraphicsMapperHidlTest, GetUnsupportedStandardMetadata) { /** * Test IMapper::set(PixelFormatFourCC) */ -TEST_F(GraphicsMapperHidlTest, SetPixelFormatFourCC) { +TEST_P(GraphicsMapperHidlTest, SetPixelFormatFourCC) { uint32_t pixelFormatFourCC = 0x34324142; // DRM_FORMAT_BGRA8888 hidl_vec vec; ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatFourCC(pixelFormatFourCC, &vec)); @@ -1144,7 +1128,7 @@ TEST_F(GraphicsMapperHidlTest, SetPixelFormatFourCC) { /** * Test IMapper::set(PixelFormatModifier) */ -TEST_F(GraphicsMapperHidlTest, SetPixelFormatModifier) { +TEST_P(GraphicsMapperHidlTest, SetPixelFormatModifier) { uint64_t pixelFormatModifier = 10; hidl_vec vec; ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatModifier(pixelFormatModifier, &vec)); @@ -1161,7 +1145,7 @@ TEST_F(GraphicsMapperHidlTest, SetPixelFormatModifier) { /** * Test IMapper::set(Usage) remove flag */ -TEST_F(GraphicsMapperHidlTest, SetUsageRemoveBit) { +TEST_P(GraphicsMapperHidlTest, SetUsageRemoveBit) { uint64_t usage = static_cast(BufferUsage::CPU_WRITE_OFTEN); hidl_vec vec; ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec)); @@ -1176,7 +1160,7 @@ TEST_F(GraphicsMapperHidlTest, SetUsageRemoveBit) { /** * Test IMapper::set(Usage) add flag */ -TEST_F(GraphicsMapperHidlTest, SetUsageAddBit) { +TEST_P(GraphicsMapperHidlTest, SetUsageAddBit) { uint64_t usage = mDummyDescriptorInfo.usage | static_cast(BufferUsage::GPU_TEXTURE); hidl_vec vec; ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec)); @@ -1192,7 +1176,7 @@ TEST_F(GraphicsMapperHidlTest, SetUsageAddBit) { /** * Test IMapper::set(Usage) to test protected content */ -TEST_F(GraphicsMapperHidlTest, SetUsageProtected) { +TEST_P(GraphicsMapperHidlTest, SetUsageProtected) { const native_handle_t* bufferHandle = nullptr; auto info = mDummyDescriptorInfo; info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY; @@ -1219,7 +1203,7 @@ TEST_F(GraphicsMapperHidlTest, SetUsageProtected) { /** * Test IMapper::set(AllocationSize) */ -TEST_F(GraphicsMapperHidlTest, SetAllocationSize) { +TEST_P(GraphicsMapperHidlTest, SetAllocationSize) { uint64_t allocationSize = 1000000; hidl_vec vec; ASSERT_EQ(NO_ERROR, gralloc4::encodeAllocationSize(allocationSize, &vec)); @@ -1235,7 +1219,7 @@ TEST_F(GraphicsMapperHidlTest, SetAllocationSize) { /** * Test IMapper::set(ProtectedContent) */ -TEST_F(GraphicsMapperHidlTest, SetProtectedContent) { +TEST_P(GraphicsMapperHidlTest, SetProtectedContent) { const native_handle_t* bufferHandle = nullptr; auto info = mDummyDescriptorInfo; info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY; @@ -1263,7 +1247,7 @@ TEST_F(GraphicsMapperHidlTest, SetProtectedContent) { /** * Test IMapper::set(Compression) */ -TEST_F(GraphicsMapperHidlTest, SetCompression) { +TEST_P(GraphicsMapperHidlTest, SetCompression) { auto info = mDummyDescriptorInfo; info.usage = static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); @@ -1284,7 +1268,7 @@ TEST_F(GraphicsMapperHidlTest, SetCompression) { /** * Test IMapper::set(Interlaced) */ -TEST_F(GraphicsMapperHidlTest, SetInterlaced) { +TEST_P(GraphicsMapperHidlTest, SetInterlaced) { ExtendableType interlaced = gralloc4::Interlaced_RightLeft; hidl_vec vec; ASSERT_EQ(NO_ERROR, gralloc4::encodeInterlaced(interlaced, &vec)); @@ -1302,7 +1286,7 @@ TEST_F(GraphicsMapperHidlTest, SetInterlaced) { /** * Test IMapper::set(ChromaSiting) */ -TEST_F(GraphicsMapperHidlTest, SetChromaSiting) { +TEST_P(GraphicsMapperHidlTest, SetChromaSiting) { ExtendableType chromaSiting = gralloc4::ChromaSiting_SitedInterstitial; hidl_vec vec; ASSERT_EQ(NO_ERROR, gralloc4::encodeChromaSiting(chromaSiting, &vec)); @@ -1320,7 +1304,7 @@ TEST_F(GraphicsMapperHidlTest, SetChromaSiting) { /** * Test IMapper::set(PlaneLayouts) */ -TEST_F(GraphicsMapperHidlTest, SetPlaneLayouts) { +TEST_P(GraphicsMapperHidlTest, SetPlaneLayouts) { const native_handle_t* bufferHandle = nullptr; auto info = mDummyDescriptorInfo; ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true)); @@ -1421,7 +1405,7 @@ TEST_F(GraphicsMapperHidlTest, SetPlaneLayouts) { /** * Test IMapper::set(Dataspace) */ -TEST_F(GraphicsMapperHidlTest, SetDataspace) { +TEST_P(GraphicsMapperHidlTest, SetDataspace) { Dataspace dataspace = Dataspace::V0_SRGB_LINEAR; hidl_vec vec; ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &vec)); @@ -1437,7 +1421,7 @@ TEST_F(GraphicsMapperHidlTest, SetDataspace) { /** * Test IMapper::set(BlendMode) */ -TEST_F(GraphicsMapperHidlTest, SetBlendMode) { +TEST_P(GraphicsMapperHidlTest, SetBlendMode) { BlendMode blendMode = BlendMode::PREMULTIPLIED; hidl_vec vec; ASSERT_EQ(NO_ERROR, gralloc4::encodeBlendMode(blendMode, &vec)); @@ -1453,7 +1437,7 @@ TEST_F(GraphicsMapperHidlTest, SetBlendMode) { /** * Test IMapper::set(metadata) with a bad buffer */ -TEST_F(GraphicsMapperHidlTest, SetMetadataNullBuffer) { +TEST_P(GraphicsMapperHidlTest, SetMetadataNullBuffer) { const native_handle_t* bufferHandle = nullptr; hidl_vec vec; ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, vec)); @@ -1490,7 +1474,7 @@ TEST_F(GraphicsMapperHidlTest, SetMetadataNullBuffer) { /** * Test IMapper::set(metadata) for constant metadata */ -TEST_F(GraphicsMapperHidlTest, SetConstantMetadata) { +TEST_P(GraphicsMapperHidlTest, SetConstantMetadata) { const native_handle_t* bufferHandle = nullptr; ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); @@ -1509,7 +1493,7 @@ TEST_F(GraphicsMapperHidlTest, SetConstantMetadata) { /** * Test IMapper::set(metadata) for bad metadata */ -TEST_F(GraphicsMapperHidlTest, SetBadMetadata) { +TEST_P(GraphicsMapperHidlTest, SetBadMetadata) { const native_handle_t* bufferHandle = nullptr; ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); @@ -1549,7 +1533,7 @@ TEST_F(GraphicsMapperHidlTest, SetBadMetadata) { /** * Test IMapper::getFromBufferDescriptorInfo(BufferId) */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBufferId) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBufferId) { hidl_vec vec; ASSERT_EQ(Error::UNSUPPORTED, mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, @@ -1559,7 +1543,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBufferId) { /** * Test IMapper::getFromBufferDescriptorInfo(Name) */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoName) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoName) { hidl_vec vec; ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( mDummyDescriptorInfo, gralloc4::MetadataType_Name, &vec)); @@ -1572,7 +1556,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoName) { /** * Test IMapper::getFromBufferDescriptorInfo(Width) */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoWidth) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoWidth) { hidl_vec vec; ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( mDummyDescriptorInfo, gralloc4::MetadataType_Width, &vec)); @@ -1585,7 +1569,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoWidth) { /** * Test IMapper::getFromBufferDescriptorInfo(Height) */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoHeight) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoHeight) { hidl_vec vec; ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( mDummyDescriptorInfo, gralloc4::MetadataType_Height, &vec)); @@ -1598,7 +1582,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoHeight) { /** * Test IMapper::getFromBufferDescriptorInfo(PixelFormatRequested) */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatRequested) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatRequested) { hidl_vec vec; ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( @@ -1612,7 +1596,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatRequested) /** * Test IMapper::getFromBufferDescriptorInfo(PixelFormatFourCC) */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatFourCC) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatFourCC) { hidl_vec vec; Error err = mGralloc->getFromBufferDescriptorInfo( mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC, &vec); @@ -1628,7 +1612,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatFourCC) { /** * Test IMapper::getFromBufferDescriptorInfo(PixelFormatModifier) */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatModifier) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatModifier) { hidl_vec vec; Error err = mGralloc->getFromBufferDescriptorInfo( mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier, &vec); @@ -1644,7 +1628,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatModifier) { /** * Test IMapper::getFromBufferDescriptorInfo(Usage) */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUsage) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUsage) { hidl_vec vec; ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( mDummyDescriptorInfo, gralloc4::MetadataType_Usage, &vec)); @@ -1657,7 +1641,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUsage) { /** * Test IMapper::getFromBufferDescriptorInfo(AllocationSize) */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoAllocationSize) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoAllocationSize) { hidl_vec vec; Error err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, gralloc4::MetadataType_AllocationSize, &vec); @@ -1673,7 +1657,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoAllocationSize) { /** * Test IMapper::getFromBufferDescriptorInfo(ProtectedContent) */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoProtectedContent) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoProtectedContent) { auto info = mDummyDescriptorInfo; info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY; @@ -1689,7 +1673,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoProtectedContent) { /** * Test IMapper::getFromBufferDescriptorInfo(Compression) */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCompression) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCompression) { auto info = mDummyDescriptorInfo; info.usage = static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); @@ -1707,7 +1691,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCompression) { /** * Test IMapper::getFromBufferDescriptorInfo(Interlaced) */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoInterlaced) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoInterlaced) { hidl_vec vec; ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( mDummyDescriptorInfo, gralloc4::MetadataType_Interlaced, &vec)); @@ -1722,7 +1706,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoInterlaced) { /** * Test IMapper::getFromBufferDescriptorInfo(ChromaSiting) */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoChromaSiting) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoChromaSiting) { hidl_vec vec; ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, @@ -1738,7 +1722,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoChromaSiting) { /** * Test IMapper::getFromBufferDescriptorInfo(PlaneLayouts) */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPlaneLayouts) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPlaneLayouts) { hidl_vec vec; ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, @@ -1752,7 +1736,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPlaneLayouts) { /** * Test IMapper::getFromBufferDescriptorInfo(Dataspace) */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoDataspace) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoDataspace) { hidl_vec vec; ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( mDummyDescriptorInfo, gralloc4::MetadataType_Dataspace, &vec)); @@ -1765,7 +1749,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoDataspace) { /** * Test IMapper::getFromBufferDescriptorInfo(BlendMode) */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBlendMode) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBlendMode) { hidl_vec vec; ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( mDummyDescriptorInfo, gralloc4::MetadataType_BlendMode, &vec)); @@ -1778,7 +1762,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBlendMode) { /** * Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported metadata */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedMetadata) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedMetadata) { MetadataType metadataTypeFake = {"FAKE", 1}; hidl_vec vec; @@ -1790,7 +1774,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedMetadata) { /** * Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported standard metadata */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedStandardMetadata) { +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedStandardMetadata) { MetadataType metadataTypeFake = {GRALLOC4_STANDARD_METADATA_TYPE, 9999}; hidl_vec vec; @@ -1802,7 +1786,7 @@ TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedStandardMet /** * Test IMapper::listSupportedMetadataTypes() */ -TEST_F(GraphicsMapperHidlTest, ListSupportedMetadataTypes) { +TEST_P(GraphicsMapperHidlTest, ListSupportedMetadataTypes) { hidl_vec descriptions; mGralloc->getMapper()->listSupportedMetadataTypes( [&](const auto& tmpError, const auto& tmpDescriptions) { @@ -1850,7 +1834,7 @@ TEST_F(GraphicsMapperHidlTest, ListSupportedMetadataTypes) { /** * Test IMapper::dumpBuffer() */ -TEST_F(GraphicsMapperHidlTest, DumpBuffer) { +TEST_P(GraphicsMapperHidlTest, DumpBuffer) { const native_handle_t* bufferHandle = nullptr; ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); auto buffer = const_cast(bufferHandle); @@ -1867,7 +1851,7 @@ TEST_F(GraphicsMapperHidlTest, DumpBuffer) { /** * Test IMapper::dumpBuffer() with an invalid buffer */ -TEST_F(GraphicsMapperHidlTest, DumpBufferNullBuffer) { +TEST_P(GraphicsMapperHidlTest, DumpBufferNullBuffer) { native_handle_t* bufferHandle = nullptr; auto buffer = const_cast(bufferHandle); @@ -1880,7 +1864,7 @@ TEST_F(GraphicsMapperHidlTest, DumpBufferNullBuffer) { /** * Test IMapper::dumpBuffer() multiple */ -TEST_F(GraphicsMapperHidlTest, DumpBuffers) { +TEST_P(GraphicsMapperHidlTest, DumpBuffers) { size_t bufferCount = 10; for (int i = 0; i < bufferCount; i++) { @@ -1903,7 +1887,7 @@ TEST_F(GraphicsMapperHidlTest, DumpBuffers) { /** * Test IMapper::getReservedRegion() */ -TEST_F(GraphicsMapperHidlTest, GetReservedRegion) { +TEST_P(GraphicsMapperHidlTest, GetReservedRegion) { const native_handle_t* bufferHandle = nullptr; auto info = mDummyDescriptorInfo; @@ -1935,7 +1919,7 @@ TEST_F(GraphicsMapperHidlTest, GetReservedRegion) { /** * Test IMapper::getReservedRegion() request over a page */ -TEST_F(GraphicsMapperHidlTest, GetLargeReservedRegion) { +TEST_P(GraphicsMapperHidlTest, GetLargeReservedRegion) { const native_handle_t* bufferHandle = nullptr; auto info = mDummyDescriptorInfo; @@ -1973,7 +1957,7 @@ TEST_F(GraphicsMapperHidlTest, GetLargeReservedRegion) { /** * Test IMapper::getReservedRegion() across multiple mappers */ -TEST_F(GraphicsMapperHidlTest, GetReservedRegionMultiple) { +TEST_P(GraphicsMapperHidlTest, GetReservedRegionMultiple) { const native_handle_t* bufferHandle = nullptr; auto info = mDummyDescriptorInfo; @@ -1991,10 +1975,8 @@ TEST_F(GraphicsMapperHidlTest, GetReservedRegionMultiple) { ASSERT_EQ(info.reservedSize, reservedSize1); std::unique_ptr anotherGralloc; - ASSERT_NO_FATAL_FAILURE( - anotherGralloc = std::make_unique( - GraphicsMapperHidlEnvironment::Instance()->getServiceName(), - GraphicsMapperHidlEnvironment::Instance()->getServiceName())); + ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique(std::get<0>(GetParam()), + std::get<1>(GetParam()))); void* reservedRegion2 = nullptr; uint64_t reservedSize2 = 0; @@ -2007,7 +1989,7 @@ TEST_F(GraphicsMapperHidlTest, GetReservedRegionMultiple) { /** * Test IMapper::getReservedRegion() with a bad buffer */ -TEST_F(GraphicsMapperHidlTest, GetReservedRegionBadBuffer) { +TEST_P(GraphicsMapperHidlTest, GetReservedRegionBadBuffer) { const native_handle_t* bufferHandle = nullptr; void* reservedRegion = nullptr; @@ -2018,6 +2000,14 @@ TEST_F(GraphicsMapperHidlTest, GetReservedRegionBadBuffer) { ASSERT_EQ(0, reservedSize); } +INSTANTIATE_TEST_CASE_P( + PerInstance, GraphicsMapperHidlTest, + testing::Combine( + testing::ValuesIn( + android::hardware::getAllHalInstanceNames(IAllocator::descriptor)), + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMapper::descriptor))), + android::hardware::PrintInstanceTupleNameToString<>); + } // namespace } // namespace vts } // namespace V4_0 @@ -2025,13 +2015,3 @@ TEST_F(GraphicsMapperHidlTest, GetReservedRegionBadBuffer) { } // namespace graphics } // namespace hardware } // namespace android - -int main(int argc, char** argv) { - using android::hardware::graphics::mapper::V4_0::vts::GraphicsMapperHidlEnvironment; - ::testing::AddGlobalTestEnvironment(GraphicsMapperHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - GraphicsMapperHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; -} From d334593715eb6a3dd3b3deabc02240e71f1d381d Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Tue, 10 Dec 2019 16:47:00 -0800 Subject: [PATCH 0325/1022] Add AUDIO_INPUT_FLAG_DIRECT to Audio HAL constants This flag used to be framework only. To simplify constants management it's better to have it defined at all layers. Currently it is only used for MSD module but potentially can be used for HDMI inputs. Bug: 141273649 Test: use AOSP MSD on Pixel atest VtsHalAudioV6_0TargetTest Change-Id: I3b853d5d0a05cc4d4bacd0a9ae432099bb47fad9 --- audio/common/6.0/types.hal | 1 + current.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal index fa2f3a9c12..32692c05b3 100644 --- a/audio/common/6.0/types.hal +++ b/audio/common/6.0/types.hal @@ -739,6 +739,7 @@ enum AudioInputFlag : int32_t { MMAP_NOIRQ = 0x10, // input operates in MMAP no IRQ mode. VOIP_TX = 0x20, // preferred input for VoIP calls. HW_AV_SYNC = 0x40, // input connected to an output that uses a hardware A/V sync + DIRECT = 0x80, // for acquiring encoded streams }; @export(name="audio_usage_t", value_prefix="AUDIO_USAGE_") diff --git a/current.txt b/current.txt index bdfb58fa73..088a43ee61 100644 --- a/current.txt +++ b/current.txt @@ -593,7 +593,7 @@ bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardwar 2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn 78e4138cc8307c11fc777c3bd376e581ba4ba48196b05ca1d7cdfa515c87b48a android.hardware.audio@6.0::IStreamOut 997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback -0b291ebd7e94dd1cfaadd41a8b9a80bc9389bbb76f5ad5b3df94db5fe7faea9d android.hardware.audio.common@6.0::types +e7d91d8293cc04117969b238c1a7292ef8db8eca2018542bce775bdc87e5522d android.hardware.audio.common@6.0::types 817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types 525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect 8d76bbe3719d051a8e9a1dcf9244f37f5b0a491feb249fa48391edf7cb4f3131 android.hardware.audio.effect@6.0::IAutomaticGainControlEffect From 96e7a344689ea798abc6422003bbb54f7bbf8c4a Mon Sep 17 00:00:00 2001 From: "Harpreet \\\"Eli\\\" Sangha" Date: Mon, 9 Sep 2019 11:04:54 +0900 Subject: [PATCH 0326/1022] vibrator: Support Always-On Effects Bug: 138909021 Test: Verify always-on haptics are configured on boot and settings change. Change-Id: I11ce5f2b974267c6e84b1843a750847492a7de15 Signed-off-by: Harpreet \"Eli\" Sangha --- .../android/hardware/vibrator/IVibrator.aidl | 31 +++++++++++++++++++ vibrator/aidl/default/Vibrator.cpp | 25 ++++++++++++++- .../default/include/vibrator-impl/Vibrator.h | 3 ++ .../aidl/vts/VtsHalVibratorTargetTest.cpp | 26 ++++++++++++++++ 4 files changed, 84 insertions(+), 1 deletion(-) diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl index ebf5faa47a..f553664eeb 100644 --- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl +++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl @@ -48,6 +48,10 @@ interface IVibrator { * Whether compose is supported. */ const int CAP_COMPOSE_EFFECTS = 1 << 5; + /** + * Whether alwaysOnEnable/alwaysOnDisable is supported. + */ + const int CAP_ALWAYS_ON_CONTROL = 1 << 6; /** * Determine capabilities of the vibrator HAL (CAP_* mask) @@ -165,4 +169,31 @@ interface IVibrator { */ void compose(in CompositeEffect[] composite, in IVibratorCallback callback); + /** + * List of supported always-on effects. + * + * Return the effects which are supported by the alwaysOnEnable (an effect + * is expected to be supported at every strength level. + */ + Effect[] getSupportedAlwaysOnEffects(); + + /** + * Enable an always-on haptic source, assigning a specific effect. An + * always-on haptic source is a source that can be triggered externally + * once enabled and assigned an effect to play. This may not be supported + * and this support is reflected in getCapabilities (CAP_ALWAYS_ON_CONTROL). + * + * @param id The device-specific always-on source ID to enable. + * @param effect The type of haptic event to trigger. + * @param strength The intensity of haptic event to trigger. + */ + void alwaysOnEnable(in int id, in Effect effect, in EffectStrength strength); + + /** + * Disable an always-on haptic source. This may not be supported and this + * support is reflected in getCapabilities (CAP_ALWAYS_ON_CONTROL). + * + * @param id The device-specific always-on source ID to disable. + */ + void alwaysOnDisable(in int id); } diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp index befdeab08a..cedd9cb89c 100644 --- a/vibrator/aidl/default/Vibrator.cpp +++ b/vibrator/aidl/default/Vibrator.cpp @@ -31,7 +31,8 @@ ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) { LOG(INFO) << "Vibrator reporting capabilities"; *_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK | IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL | - IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS; + IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS | + IVibrator::CAP_ALWAYS_ON_CONTROL; return ndk::ScopedAStatus::ok(); } @@ -151,6 +152,28 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector& composi return ndk::ScopedAStatus::ok(); } +ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector* _aidl_return) { + return getSupportedEffects(_aidl_return); +} + +ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) { + std::vector effects; + getSupportedAlwaysOnEffects(&effects); + + if (std::find(effects.begin(), effects.end(), effect) == effects.end()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } else { + LOG(INFO) << "Enabling always-on ID " << id << " with " << toString(effect) << "/" + << toString(strength); + return ndk::ScopedAStatus::ok(); + } +} + +ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id) { + LOG(INFO) << "Disabling always-on ID " << id; + return ndk::ScopedAStatus::ok(); +} + } // namespace vibrator } // namespace hardware } // namespace android diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h index 817ec805fa..0eb957d9fa 100644 --- a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h +++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h @@ -38,6 +38,9 @@ class Vibrator : public BnVibrator { ndk::ScopedAStatus getCompositionSizeMax(int32_t* maxSize); ndk::ScopedAStatus compose(const std::vector& composite, const std::shared_ptr& callback) override; + ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector* _aidl_return) override; + ndk::ScopedAStatus alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) override; + ndk::ScopedAStatus alwaysOnDisable(int32_t id) override; }; } // namespace vibrator diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp index 6f9ba1a96e..f47b10d34f 100644 --- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp +++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp @@ -370,6 +370,32 @@ TEST_P(VibratorAidl, CompseSizeBoundary) { } } +TEST_P(VibratorAidl, AlwaysOn) { + if (capabilities & IVibrator::CAP_ALWAYS_ON_CONTROL) { + std::vector supported; + ASSERT_TRUE(vibrator->getSupportedAlwaysOnEffects(&supported).isOk()); + + for (Effect effect : kEffects) { + bool isEffectSupported = + std::find(supported.begin(), supported.end(), effect) != supported.end(); + + for (EffectStrength strength : kEffectStrengths) { + Status status = vibrator->alwaysOnEnable(0, effect, strength); + + if (isEffectSupported) { + EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) + << toString(effect) << " " << toString(strength); + } else { + EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode()) + << toString(effect) << " " << toString(strength); + } + } + } + + EXPECT_EQ(Status::EX_NONE, vibrator->alwaysOnDisable(0).exceptionCode()); + } +} + INSTANTIATE_TEST_SUITE_P(Vibrator, VibratorAidl, testing::ValuesIn(android::getAidlHalInstanceNames(IVibrator::descriptor)), android::PrintInstanceNameToString); From 17e69212c93c2a64feb64503d43348d72c8702d4 Mon Sep 17 00:00:00 2001 From: Sasha Kuznetsov Date: Wed, 11 Dec 2019 12:38:07 -0800 Subject: [PATCH 0327/1022] Fix comment in 1.1 GNSS HAL VTS tests Test: n/a Change-Id: I12cbf004f6b7d494b066478d62a62af22f67c1ac --- gnss/1.1/vts/functional/gnss_hal_test_cases.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp index afba61fe44..fc86a3e252 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp @@ -427,7 +427,7 @@ TEST_P(GnssHalTest, BlacklistConstellationWithLocationOff) { * * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding * GnssStatus for any non-GPS constellations. - * 2a & b) Turns off location, and blacklist first non-GPS constellations. + * 2a & b) Blacklist first non-GPS constellation, and turn 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. From 3b6cfe061e80a23a0f827afdf8a3fa2f8e65f92d Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Wed, 11 Dec 2019 12:45:20 -0800 Subject: [PATCH 0328/1022] camera-vts: don't import gralloc buffer after allocating Before moving to GraphicBufferAllocator, the test just allocated the buffer. GraphicBufferAllocator allocates and imports the buffer. Update the test to only allocate the buffer. Bug: 145941038 Test: VtsHalCameraProviderV2_4TargetTest Change-Id: Ib3801d06265836eec2875f13ae6f2ec070d7d353 --- .../2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 9416a5430e..dd4cdca70a 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -6309,7 +6309,7 @@ void CameraHidlTest::allocateGraphicBuffer(uint32_t width, uint32_t height, uint buffer_handle_t buffer; uint32_t stride; - android::status_t err = android::GraphicBufferAllocator::get().allocate( + android::status_t err = android::GraphicBufferAllocator::get().allocateRawHandle( width, height, static_cast(format), 1u /*layerCount*/, usage, &buffer, &stride, "VtsHalCameraProviderV2_4"); ASSERT_EQ(err, android::NO_ERROR); From 9c451cfb3125ed77f9310136f01536bac4018d4c Mon Sep 17 00:00:00 2001 From: Sasha Kuznetsov Date: Wed, 11 Dec 2019 12:59:52 -0800 Subject: [PATCH 0329/1022] Add test to setBlacklist with location on Test: atest VtsHalGnssV2_1TargetTest Bug: 135042665 Change-Id: Ibeb11f811990eceaad8d794befc50650b4bdbd21 --- gnss/2.1/vts/functional/gnss_hal_test.cpp | 41 ++++++ gnss/2.1/vts/functional/gnss_hal_test.h | 12 ++ .../vts/functional/gnss_hal_test_cases.cpp | 119 ++++++++++++------ 3 files changed, 135 insertions(+), 37 deletions(-) diff --git a/gnss/2.1/vts/functional/gnss_hal_test.cpp b/gnss/2.1/vts/functional/gnss_hal_test.cpp index 7cfe0db381..22268f676d 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test.cpp +++ b/gnss/2.1/vts/functional/gnss_hal_test.cpp @@ -148,6 +148,47 @@ void GnssHalTest::StartAndCheckLocations(int count) { } } +GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation( + const int locations_to_await, const int gnss_sv_info_list_timeout) { + gnss_cb_->location_cbq_.reset(); + StartAndCheckLocations(locations_to_await); + 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, locations_to_await); + ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)", + sv_info_list_cbq_size, locations_to_await, location_called_count); + + // Find first non-GPS constellation to blacklist + GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN; + for (int i = 0; i < sv_info_list_cbq_size; ++i) { + hidl_vec sv_info_vec; + gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, gnss_sv_info_list_timeout); + for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) { + const auto& gnss_sv = sv_info_vec[iSv]; + if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) && + (gnss_sv.v2_0.constellation != GnssConstellationType::UNKNOWN) && + (gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) { + // found a non-GPS constellation + constellation_to_blacklist = gnss_sv.v2_0.constellation; + break; + } + } + if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) { + break; + } + } + + if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) { + ALOGI("No non-GPS constellations found, constellation blacklist test less effective."); + // Proceed functionally to blacklist something. + constellation_to_blacklist = GnssConstellationType::GLONASS; + } + + return constellation_to_blacklist; +} + GnssHalTest::GnssCallback::GnssCallback() : info_cbq_("system_info"), name_cbq_("name"), diff --git a/gnss/2.1/vts/functional/gnss_hal_test.h b/gnss/2.1/vts/functional/gnss_hal_test.h index 2e1add01ea..6b67e139c3 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test.h +++ b/gnss/2.1/vts/functional/gnss_hal_test.h @@ -28,6 +28,7 @@ using android::hardware::Void; using android::hardware::gnss::common::GnssCallbackEventQueue; using android::hardware::gnss::V1_0::GnssLocationFlags; +using android::hardware::gnss::V2_0::GnssConstellationType; using android::hardware::gnss::V2_1::IGnss; using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation; @@ -184,6 +185,17 @@ 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 startLocationAndGetNonGpsConstellation( + const int locations_to_await, const int gnss_sv_info_list_timeout); + sp gnss_hal_; // GNSS HAL to call into sp gnss_cb_; // Primary callback interface }; diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp index 45a3d2ae4d..2c51717665 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp @@ -384,7 +384,7 @@ TEST_P(GnssHalTest, BlacklistIndividualSatellites) { } /* - * BlacklistConstellation: + * BlacklistConstellationLocationOff: * * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding * GnssStatus for any non-GPS constellations. @@ -393,48 +393,17 @@ 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, BlacklistConstellationLocationOff) { 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 GnssSvInfo, while awaiting %d Locations (%d received)", - sv_info_list_cbq_size, kLocationsToAwait, location_called_count); + const int kGnssSvInfoListTimeout = 2; // Find first non-GPS constellation to blacklist - const int kGnssSvInfoListTimeout = 2; - GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN; - for (int i = 0; i < sv_info_list_cbq_size; ++i) { - hidl_vec sv_info_vec; - gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout); - for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) { - const auto& gnss_sv = sv_info_vec[iSv]; - if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) && - (gnss_sv.v2_0.constellation != GnssConstellationType::UNKNOWN) && - (gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) { - // found a non-GPS constellation - constellation_to_blacklist = gnss_sv.v2_0.constellation; - break; - } - } - if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) { - break; - } - } + GnssConstellationType constellation_to_blacklist = + startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvInfoListTimeout); // Turns off location StopAndClearLocations(); - if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) { - ALOGI("No non-GPS constellations found, constellation blacklist test less effective."); - // Proceed functionally to blacklist something. - constellation_to_blacklist = GnssConstellationType::GLONASS; - } IGnssConfiguration::BlacklistedSource source_to_blacklist_1; source_to_blacklist_1.constellation = constellation_to_blacklist; source_to_blacklist_1.svid = 0; // documented wildcard for all satellites in this constellation @@ -466,7 +435,83 @@ 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 GnssSvInfo, while awaiting %d Locations", sv_info_list_cbq_size, + kLocationsToAwait); + for (int i = 0; i < sv_info_list_cbq_size; ++i) { + hidl_vec sv_info_vec; + gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout); + for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) { + const auto& gnss_sv = sv_info_vec[iSv]; + EXPECT_FALSE((gnss_sv.v2_0.constellation == source_to_blacklist_1.constellation) && + (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)); + EXPECT_FALSE((gnss_sv.v2_0.constellation == source_to_blacklist_2.constellation) && + (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)); + } + } + + // clean up + StopAndClearLocations(); + sources.resize(0); + result = gnss_configuration_hal->setBlacklist_2_1(sources); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); +} + +/* + * BlacklistConstellationLocationOn: + * + * 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 constellation, and turn 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, BlacklistConstellationLocationOn) { + const int kLocationsToAwait = 3; + const int kGnssSvInfoListTimeout = 2; + + // Find first non-GPS constellation to blacklist + GnssConstellationType constellation_to_blacklist = + startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvInfoListTimeout); + + IGnssConfiguration::BlacklistedSource source_to_blacklist_1; + source_to_blacklist_1.constellation = constellation_to_blacklist; + source_to_blacklist_1.svid = 0; // documented wildcard for all satellites in this constellation + + // IRNSS was added in 2.0. Always attempt to blacklist IRNSS to verify that the new enum is + // supported. + IGnssConfiguration::BlacklistedSource source_to_blacklist_2; + source_to_blacklist_2.constellation = GnssConstellationType::IRNSS; + source_to_blacklist_2.svid = 0; // documented wildcard for all satellites in this constellation + + auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_2_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(2); + sources[0] = source_to_blacklist_1; + sources[1] = source_to_blacklist_2; + + auto result = gnss_configuration_hal->setBlacklist_2_1(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 GnssSvInfo, while awaiting %d Locations", sv_info_list_cbq_size, kLocationsToAwait); From 3c181a6fd678a39eb1a9cfbcacb29191244fbd3b Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 6 Dec 2019 18:16:09 -0800 Subject: [PATCH 0330/1022] audio: add call assistant usage Add audio usage for call assistant use cases. Used by apps playing over call uplink path for call screening or other in call assitant features. Bug: 135213843 Test: make Change-Id: I7eeea676fe188946ff86f1e11e8e00a624a4ec5c --- audio/common/6.0/types.hal | 1 + current.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal index 32692c05b3..e69d9691b7 100644 --- a/audio/common/6.0/types.hal +++ b/audio/common/6.0/types.hal @@ -760,6 +760,7 @@ enum AudioUsage : int32_t { GAME = 14, VIRTUAL_SOURCE = 15, ASSISTANT = 16, + CALL_ASSISTANT = 17, }; /** Type of audio generated by an application. */ diff --git a/current.txt b/current.txt index 5ad5b3554d..11e87c8072 100644 --- a/current.txt +++ b/current.txt @@ -599,7 +599,7 @@ bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardwar 2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn 78e4138cc8307c11fc777c3bd376e581ba4ba48196b05ca1d7cdfa515c87b48a android.hardware.audio@6.0::IStreamOut 997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback -e7d91d8293cc04117969b238c1a7292ef8db8eca2018542bce775bdc87e5522d android.hardware.audio.common@6.0::types +1349686814402fa10f711cc5763bc629aafc64a5f5843b4b21b8cd86ffb923e6 android.hardware.audio.common@6.0::types 817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types 525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect 8d76bbe3719d051a8e9a1dcf9244f37f5b0a491feb249fa48391edf7cb4f3131 android.hardware.audio.effect@6.0::IAutomaticGainControlEffect From fdfd6f9de3f2659b327c46d71765a91d3d15a24f Mon Sep 17 00:00:00 2001 From: Sasha Kuznetsov Date: Wed, 11 Dec 2019 13:58:12 -0800 Subject: [PATCH 0331/1022] Remove duplicate constants. Test: in progress Change-Id: I7d266a9378a679ed30b6ee2af2dbcc4e79df91a5 --- gnss/1.1/vts/functional/gnss_hal_test.cpp | 14 ++++++-------- gnss/1.1/vts/functional/gnss_hal_test.h | 3 ++- gnss/1.1/vts/functional/gnss_hal_test_cases.cpp | 12 ++++++++---- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp index b87f558f28..24de37d0e2 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test.cpp +++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp @@ -175,25 +175,23 @@ bool GnssHalTest::IsGnssHalVersion_1_1() const { return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0; } -GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation() { - const int kLocationsToAwait = 3; - +GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation( + const int locations_to_await, const int gnss_sv_info_list_timeout) { gnss_cb_->location_cbq_.reset(); - StartAndCheckLocations(kLocationsToAwait); + StartAndCheckLocations(locations_to_await); const int location_called_count = gnss_cb_->location_cbq_.calledCount(); // Tolerate 1 less sv status to handle edge cases in reporting. int sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size(); - EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait); + EXPECT_GE(sv_status_cbq_size + 1, locations_to_await); ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", sv_status_cbq_size, - kLocationsToAwait, location_called_count); + locations_to_await, location_called_count); // Find first non-GPS constellation to blacklist - const int kGnssSvStatusTimeout = 2; GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN; for (int i = 0; i < sv_status_cbq_size; ++i) { IGnssCallback::GnssSvStatus gnss_sv_status; - gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout); + gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, gnss_sv_info_list_timeout); for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) { const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv]; if ((gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) && diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h index b0e52befe2..88b77236ae 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test.h +++ b/gnss/1.1/vts/functional/gnss_hal_test.h @@ -148,7 +148,8 @@ class GnssHalTest : public testing::TestWithParam { * Note that location is not stopped in this method. The client should call * StopAndClearLocations() after the call. */ - GnssConstellationType startLocationAndGetNonGpsConstellation(); + GnssConstellationType startLocationAndGetNonGpsConstellation( + const int locations_to_await, const int gnss_sv_info_list_timeout); sp gnss_hal_; // GNSS HAL to call into sp gnss_cb_; // Primary callback interface diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp index afba61fe44..6481db465b 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp @@ -368,8 +368,11 @@ TEST_P(GnssHalTest, BlacklistConstellationWithLocationOff) { } const int kLocationsToAwait = 3; + const int kGnssSvStatusTimeout = 2; + // Find first non-GPS constellation to blacklist - GnssConstellationType constellation_to_blacklist = startLocationAndGetNonGpsConstellation(); + GnssConstellationType constellation_to_blacklist = + startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvStatusTimeout); // Turns off location StopAndClearLocations(); @@ -403,7 +406,6 @@ TEST_P(GnssHalTest, BlacklistConstellationWithLocationOff) { EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait); ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_status_cbq_size, kLocationsToAwait); - const int kGnssSvStatusTimeout = 2; for (int i = 0; i < sv_status_cbq_size; ++i) { IGnssCallback::GnssSvStatus gnss_sv_status; gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout); @@ -439,8 +441,11 @@ TEST_P(GnssHalTest, BlacklistConstellationWithLocationOn) { } const int kLocationsToAwait = 3; + const int kGnssSvStatusTimeout = 2; + // Find first non-GPS constellation to blacklist - GnssConstellationType constellation_to_blacklist = startLocationAndGetNonGpsConstellation(); + GnssConstellationType constellation_to_blacklist = + startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvStatusTimeout); IGnssConfiguration::BlacklistedSource source_to_blacklist; source_to_blacklist.constellation = constellation_to_blacklist; @@ -474,7 +479,6 @@ TEST_P(GnssHalTest, BlacklistConstellationWithLocationOn) { EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait); ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_status_cbq_size, kLocationsToAwait); - const int kGnssSvStatusTimeout = 2; for (int i = 0; i < sv_status_cbq_size; ++i) { IGnssCallback::GnssSvStatus gnss_sv_status; gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout); From b2178b9248827b87a65441ebc37525e8cbbbb010 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Wed, 11 Dec 2019 15:04:43 -0800 Subject: [PATCH 0332/1022] audio: Add check for MMap buffer size to the default implementation Add documentation and check that 'minSizeFrames' parameter is a positive value. Previously a similar check was added to Pixel HAL. Bug: 141989952 Test: atest VtsHalAudioV6_0TargetTest Change-Id: I526431fc214f7f5bc424f0c9e4c890cf918ca2b2 --- audio/6.0/IStream.hal | 1 + .../core/all-versions/default/include/core/default/Stream.h | 5 +++++ current.txt | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/audio/6.0/IStream.hal b/audio/6.0/IStream.hal index d7d3c8437c..2ea1ab3680 100644 --- a/audio/6.0/IStream.hal +++ b/audio/6.0/IStream.hal @@ -274,6 +274,7 @@ interface IStream { * * @param minSizeFrames minimum buffer size requested. The actual buffer * size returned in struct MmapBufferInfo can be larger. + * The size must be a positive value. * @return retval OK in case the success. * NOT_SUPPORTED on non mmap mode streams * NOT_INITIALIZED in case of memory allocation error diff --git a/audio/core/all-versions/default/include/core/default/Stream.h b/audio/core/all-versions/default/include/core/default/Stream.h index 91df0c7703..ce0003bfbf 100644 --- a/audio/core/all-versions/default/include/core/default/Stream.h +++ b/audio/core/all-versions/default/include/core/default/Stream.h @@ -157,6 +157,10 @@ Return StreamMmap::createMmapBuffer(int32_t minSizeFrames, size_t frame native_handle_t* hidlHandle = nullptr; if (mStream->create_mmap_buffer != NULL) { + if (minSizeFrames <= 0) { + retval = Result::INVALID_ARGUMENTS; + goto exit; + } struct audio_mmap_buffer_info halInfo; retval = Stream::analyzeStatus( "create_mmap_buffer", mStream->create_mmap_buffer(mStream, minSizeFrames, &halInfo)); @@ -184,6 +188,7 @@ Return StreamMmap::createMmapBuffer(int32_t minSizeFrames, size_t frame info.burstSizeFrames = halInfo.burst_size_frames; } } +exit: _hidl_cb(retval, info); if (hidlHandle != nullptr) { native_handle_delete(hidlHandle); diff --git a/current.txt b/current.txt index bdfb58fa73..209b218479 100644 --- a/current.txt +++ b/current.txt @@ -589,7 +589,7 @@ e966a3437d6a98d9d9e14e9d672088771716031900c0deb55a0946c751a03a44 android.hardwar 2736c59abaccacac407ebe80c5e48d446edf015051d05632fb679ba471779e6e android.hardware.audio@6.0::IDevice 2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice -7318b521ea12fdd4b6e3f381085c71784c810d1ec7a8d701ec2250f3f86712e4 android.hardware.audio@6.0::IStream +fd1f1b29f26b42e886220f04a08086c00e5ade9d7b53f095438e578ab9d42a93 android.hardware.audio@6.0::IStream 2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn 78e4138cc8307c11fc777c3bd376e581ba4ba48196b05ca1d7cdfa515c87b48a android.hardware.audio@6.0::IStreamOut 997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback From efb7ffa6ca2090458dae7c39ba9ec30876a1dcd3 Mon Sep 17 00:00:00 2001 From: shubang Date: Wed, 11 Dec 2019 15:33:20 -0800 Subject: [PATCH 0333/1022] Add @export to frontend scan enums Test: make; Change-Id: I9489ae28722e73de0aba7e83b115935546e8e357 --- tv/tuner/1.0/types.hal | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index 707f5dfa60..d7628e2837 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -1197,6 +1197,7 @@ safe_union FrontendSettings { /** * Scan type for Frontend. */ +@export enum FrontendScanType : uint32_t { SCAN_UNDEFINED = 0, SCAN_AUTO = 1 << 0, @@ -1206,6 +1207,7 @@ enum FrontendScanType : uint32_t { /** * Scan Message Type for Frontend. */ +@export enum FrontendScanMessageType : uint32_t { /** * Scan locked the signal. From 1d3b15cd3e908fe8e7e6b47393facc658dfb758b Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Tue, 5 Nov 2019 15:39:32 -0800 Subject: [PATCH 0334/1022] Add APN type XCAP Add XCAP and update DataProfileInfo Test: build Bug: 73792201 Change-Id: I7cb450c91a458d66eec558265a8d9f48792cfa77 --- current.txt | 6 +- radio/1.5/IRadio.hal | 76 ++++++++++ radio/1.5/IRadioResponse.hal | 55 +++++++ radio/1.5/types.hal | 21 +++ .../1.5/vts/functional/radio_hidl_hal_api.cpp | 137 ++++++++++++++++++ .../functional/radio_hidl_hal_utils_v1_5.h | 8 + radio/1.5/vts/functional/radio_response.cpp | 20 +++ 7 files changed, 320 insertions(+), 3 deletions(-) diff --git a/current.txt b/current.txt index ca2949cdbb..2ff05fc644 100644 --- a/current.txt +++ b/current.txt @@ -656,10 +656,10 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar 619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types -eaf870a7439838c66127a74e1896c4a2346979c116eb1931785ebb4d353230ae android.hardware.radio@1.5::types -ae2fd16a80caff9cb6e3f91875c7f68f7ff76c75334056549d38496673eafe5b android.hardware.radio@1.5::IRadio +0e3c23f1c815469fdcdc39bc33a486817771c7c6b6e5303f2f25569499fc6c69 android.hardware.radio@1.5::types +52abfa4c94104189fa4b2bc3132fc7c9852b7428283463b020d1a3671a4f374c android.hardware.radio@1.5::IRadio 3afac66f21a33bc9c4b80481c7d5540038348651d9a7d8af64ea13610af138da android.hardware.radio@1.5::IRadioIndication -e7268d32bedcf7d98324ffc808ec3dc45248d47ff4d04519d09e3c71767a7ad1 android.hardware.radio@1.5::IRadioResponse +957ffbaf195aa046431ebe05a5906d215e80650e8e4933b394d6454b217ef3a9 android.hardware.radio@1.5::IRadioResponse 55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal index a4eb93c698..a3a3d908fb 100644 --- a/radio/1.5/IRadio.hal +++ b/radio/1.5/IRadio.hal @@ -16,8 +16,10 @@ package android.hardware.radio@1.5; +import @1.2::DataRequestReason; import @1.4::IRadio; import @1.5::AccessNetwork; +import @1.5::DataProfileInfo; import @1.5::NetworkScanRequest; import @1.5::RadioAccessSpecifier; import @1.5::SignalThresholdInfo; @@ -118,4 +120,78 @@ interface IRadio extends @1.4::IRadio { * 1.5 version of NetworkScanRequest */ oneway startNetworkScan_1_5(int32_t serial, NetworkScanRequest request); + + /** + * Setup a packet data connection. If DataCallResponse.status returns DataCallFailCause:NONE, + * the data connection must be added to data calls and a unsolDataCallListChanged() must be + * sent. The call remains until removed by subsequent unsolDataCallIstChanged(). It may be + * lost due to many factors, including deactivateDataCall() being issued, the radio powered + * off, reception lost or even transient factors like congestion. This data call list is + * returned by getDataCallList() and dataCallListChanged(). + * + * The Radio is expected to: + * - Create one data call context. + * - Create and configure a dedicated interface for the context. + * - The interface must be point to point. + * - The interface is configured with one or more addresses and is capable of sending and + * receiving packets. The prefix length of the addresses must be /32 for IPv4 and /128 + * for IPv6. + * - Must not modify routing configuration related to this interface; routing management is + * exclusively within the purview of the Android OS. + * - Support simultaneous data call contexts up to DataRegStateResult.maxDataCalls specified + * in the response of getDataRegistrationState. + * + * @param serial Serial number of request. + * @param accessNetwork The access network to setup the data call. If the data connection cannot + * be established on the specified access network, the setup request must be failed. + * @param dataProfileInfo Data profile info. + * @param roamingAllowed Indicates whether or not data roaming is allowed by the user. + * @param reason The request reason. Must be DataRequestReason.NORMAL or + * DataRequestReason.HANDOVER. + * @param addresses If the reason is DataRequestReason.HANDOVER, this indicates the list of link + * addresses of the existing data connection. The format is IP address with optional "/" + * prefix length (The format is defined in RFC-4291 section 2.3). For example, "192.0.1.3", + * "192.0.1.11/16", or "2001:db8::1/64". Typically one IPv4 or one IPv6 or one of each. If + * the prefix length is absent, then the addresses are assumed to be point to point with + * IPv4 with prefix length 32 or IPv6 with prefix length 128. This parameter must be ignored + * unless reason is DataRequestReason.HANDOVER. + * @param dnses If the reason is DataRequestReason.HANDOVER, this indicates the list of DNS + * addresses of the existing data connection. The format is defined in RFC-4291 section + * 2.2. For example, "192.0.1.3" or "2001:db8::1". This parameter must be ignored unless + * reason is DataRequestReason.HANDOVER. + * + * Response function is IRadioResponse.setupDataCallResponse_1_5() + * + * Note this API is the same as the 1.4 version except using the + * 1.5 AccessNetwork and DataProfileInto as the input param. + */ + oneway setupDataCall_1_5(int32_t serial, AccessNetwork accessNetwork, + DataProfileInfo dataProfileInfo, bool roamingAllowed, + DataRequestReason reason, vec addresses, vec dnses); + + /** + * Set an apn to initial attach network + * + * @param serial Serial number of request. + * @param dataProfileInfo data profile containing APN settings + * + * Response callback is IRadioResponse.setInitialAttachApnResponse_1_5() + * + * Note this API is the same as the 1.4 version except using the 1.5 DataProfileInfo + * as the input param. + */ + oneway setInitialAttachApn_1_5(int32_t serial, DataProfileInfo dataProfileInfo); + + /** + * Send data profiles of the current carrier to the modem. + * + * @param serial Serial number of request. + * @param profiles Array of DataProfile to set. + * + * Response callback is IRadioResponse.setDataProfileResponse_1_5() + * + * Note this API is the same as the 1.4 version except using the 1.5 DataProfileInfo + * as the input param. + */ + oneway setDataProfile_1_5(int32_t serial, vec profiles); }; diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal index 505c595a84..11ec2657a9 100644 --- a/radio/1.5/IRadioResponse.hal +++ b/radio/1.5/IRadioResponse.hal @@ -18,6 +18,7 @@ package android.hardware.radio@1.5; import @1.0::RadioResponseInfo; import @1.4::IRadioResponse; +import @1.4::SetupDataCallResult; /** * Interface declaring response functions to solicited radio requests. @@ -80,4 +81,58 @@ interface IRadioResponse extends @1.4::IRadioResponse { * RadioError:INVALID_ARGUMENTS */ oneway startNetworkScanResponse_1_5(RadioResponseInfo info); + + /** + * @param info Response info struct containing response type, serial no. and error + * @param dcResponse SetupDataCallResult defined in types.hal + * + * Valid errors returned: + * RadioError:NONE must be returned on both success and failure of setup with the + * DataCallResponse.status containing the actual status + * For all other errors the DataCallResponse is ignored. + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:OP_NOT_ALLOWED_BEFORE_REG_TO_NW + * RadioError:OP_NOT_ALLOWED_DURING_VOICE_CALL + * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:INVALID_ARGUMENTS + * RadioError:INTERNAL_ERR + * RadioError:NO_RESOURCES + * RadioError:SIM_ABSENT + */ + oneway setupDataCallResponse_1_5(RadioResponseInfo info, SetupDataCallResult dcResponse); + + /** + * @param info Response info struct containing response type, serial no. and error + * + * Valid errors returned: + * RadioError:NONE + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:SUBSCRIPTION_NOT_AVAILABLE + * RadioError:NO_MEMORY + * RadioError:INTERNAL_ERR + * RadioError:SYSTEM_ERR + * RadioError:MODEM_ERR + * RadioError:INVALID_ARGUMENTS + * RadioError:NOT_PROVISIONED + * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:NO_RESOURCES + * RadioError:CANCELLED + */ + oneway setInitialAttachApnResponse_1_5(RadioResponseInfo info); + + /** + * @param info Response info struct containing response type, serial no. and error + * + * Valid errors returned: + * RadioError:NONE + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:SUBSCRIPTION_NOT_AVAILABLE + * RadioError:INTERNAL_ERR + * RadioError:NO_MEMORY + * RadioError:NO_RESOURCES + * RadioError:CANCELLED + * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:SIM_ABSENT + */ + oneway setDataProfileResponse_1_5(RadioResponseInfo info); }; diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index 04a9bcfeb8..5795f7b925 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -24,6 +24,8 @@ import @1.1::ScanType; import @1.1::UtranBands; import @1.2::NetworkScanRequest; import @1.4::AccessNetwork; +import @1.4::ApnTypes; +import @1.4::DataProfileInfo; /** * Defining signal strength type. @@ -268,3 +270,22 @@ struct NetworkScanRequest { */ vec mccMncs; }; + +enum ApnTypes : @1.4::ApnTypes { + /** + * APN type for XCAP + * NOTE: Due to the addition of this new value, the value ALL defined in + * 1.0::ApnTypes is deprecated and should not be used. + */ + XCAP = 1 << 11, +}; + +/** + * Extended from @1.4::DataProfileInfo to update ApnTypes to 1.5 version + */ +struct DataProfileInfo { + @1.4::DataProfileInfo base; + + /** Supported APN types bitmap. See ApnTypes for the value of each bit. */ + bitfield supportedApnTypesBitmap; +}; diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp index 67438ae72d..1243bed2b1 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp @@ -821,3 +821,140 @@ TEST_F(RadioHidlTest_v1_5, startNetworkScan_GoodRequest2) { RadioError::REQUEST_NOT_SUPPORTED})); } } + +/* + * Test IRadio.setupDataCall_1_5() for the response returned. + */ +TEST_F(RadioHidlTest_v1_5, setupDataCall_1_5) { + serial = GetRandomSerialNumber(); + + ::android::hardware::radio::V1_5::AccessNetwork accessNetwork = + ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN; + + android::hardware::radio::V1_5::DataProfileInfo dataProfileInfo; + memset(&dataProfileInfo, 0, sizeof(dataProfileInfo)); + dataProfileInfo.base.profileId = DataProfileId::DEFAULT; + dataProfileInfo.base.apn = hidl_string("internet"); + dataProfileInfo.base.protocol = PdpProtocolType::IP; + dataProfileInfo.base.roamingProtocol = PdpProtocolType::IP; + dataProfileInfo.base.authType = ApnAuthType::NO_PAP_NO_CHAP; + dataProfileInfo.base.user = hidl_string("username"); + dataProfileInfo.base.password = hidl_string("password"); + dataProfileInfo.base.type = DataProfileInfoType::THREE_GPP; + dataProfileInfo.base.maxConnsTime = 300; + dataProfileInfo.base.maxConns = 20; + dataProfileInfo.base.waitTime = 0; + dataProfileInfo.base.enabled = true; + dataProfileInfo.supportedApnTypesBitmap = 320; + dataProfileInfo.base.bearerBitmap = 161543; + dataProfileInfo.base.mtu = 0; + dataProfileInfo.base.preferred = true; + dataProfileInfo.base.persistent = false; + + bool roamingAllowed = false; + + ::android::hardware::radio::V1_2::DataRequestReason reason = + ::android::hardware::radio::V1_2::DataRequestReason::NORMAL; + std::vector addresses = {""}; + std::vector dnses = {""}; + + Return res = radio_v1_5->setupDataCall_1_5(serial, accessNetwork, dataProfileInfo, + roamingAllowed, reason, addresses, dnses); + ASSERT_OK(res); + + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + if (cardStatus.base.base.cardState == CardState::ABSENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE, + RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW})); + } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, + RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW})); + } +} + +TEST_F(RadioHidlTest_v1_5, setInitialAttachApn_1_5) { + serial = GetRandomSerialNumber(); + + // Create a dataProfileInfo + android::hardware::radio::V1_5::DataProfileInfo dataProfileInfo; + memset(&dataProfileInfo, 0, sizeof(dataProfileInfo)); + dataProfileInfo.base.profileId = DataProfileId::DEFAULT; + dataProfileInfo.base.apn = hidl_string("internet"); + dataProfileInfo.base.protocol = PdpProtocolType::IPV4V6; + dataProfileInfo.base.roamingProtocol = PdpProtocolType::IPV4V6; + dataProfileInfo.base.authType = ApnAuthType::NO_PAP_NO_CHAP; + dataProfileInfo.base.user = hidl_string("username"); + dataProfileInfo.base.password = hidl_string("password"); + dataProfileInfo.base.type = DataProfileInfoType::THREE_GPP; + dataProfileInfo.base.maxConnsTime = 300; + dataProfileInfo.base.maxConns = 20; + dataProfileInfo.base.waitTime = 0; + dataProfileInfo.base.enabled = true; + dataProfileInfo.supportedApnTypesBitmap = 320; + dataProfileInfo.base.bearerBitmap = 161543; + dataProfileInfo.base.mtu = 0; + dataProfileInfo.base.preferred = true; + dataProfileInfo.base.persistent = false; + + radio_v1_5->setInitialAttachApn_1_5(serial, dataProfileInfo); + + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + if (cardStatus.base.base.cardState == CardState::ABSENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE})); + } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE})); + } +} + +TEST_F(RadioHidlTest_v1_5, setDataProfile_1_5) { + serial = GetRandomSerialNumber(); + + // Create a dataProfileInfo + android::hardware::radio::V1_5::DataProfileInfo dataProfileInfo; + memset(&dataProfileInfo, 0, sizeof(dataProfileInfo)); + dataProfileInfo.base.profileId = DataProfileId::DEFAULT; + dataProfileInfo.base.apn = hidl_string("internet"); + dataProfileInfo.base.protocol = PdpProtocolType::IPV4V6; + dataProfileInfo.base.roamingProtocol = PdpProtocolType::IPV4V6; + dataProfileInfo.base.authType = ApnAuthType::NO_PAP_NO_CHAP; + dataProfileInfo.base.user = hidl_string("username"); + dataProfileInfo.base.password = hidl_string("password"); + dataProfileInfo.base.type = DataProfileInfoType::THREE_GPP; + dataProfileInfo.base.maxConnsTime = 300; + dataProfileInfo.base.maxConns = 20; + dataProfileInfo.base.waitTime = 0; + dataProfileInfo.base.enabled = true; + dataProfileInfo.supportedApnTypesBitmap = 320; + dataProfileInfo.base.bearerBitmap = 161543; + dataProfileInfo.base.mtu = 0; + dataProfileInfo.base.preferred = true; + dataProfileInfo.base.persistent = true; + + // Create a dataProfileInfoList + android::hardware::hidl_vec + dataProfileInfoList = {dataProfileInfo}; + + radio_v1_5->setDataProfile_1_5(serial, dataProfileInfoList); + + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + if (cardStatus.base.base.cardState == CardState::ABSENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE})); + } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE})); + } +} diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index 01bda698bc..f7526d9c5a 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -541,6 +541,14 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon Return setSystemSelectionChannelsResponse_1_5(const RadioResponseInfo& info); Return startNetworkScanResponse_1_5(const RadioResponseInfo& info); + + Return setupDataCallResponse_1_5( + const RadioResponseInfo& info, + const android::hardware::radio::V1_4::SetupDataCallResult& dcResponse); + + Return setInitialAttachApnResponse_1_5(const RadioResponseInfo& info); + + Return setDataProfileResponse_1_5(const RadioResponseInfo& info); }; /* Callback class for radio indication */ diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp index 5964c96d35..5dee191dbc 100644 --- a/radio/1.5/vts/functional/radio_response.cpp +++ b/radio/1.5/vts/functional/radio_response.cpp @@ -928,3 +928,23 @@ Return RadioResponse_v1_5::startNetworkScanResponse_1_5(const RadioRespons parent_v1_5.notify(info.serial); return Void(); } + +Return RadioResponse_v1_5::setupDataCallResponse_1_5( + const RadioResponseInfo& info, + const android::hardware::radio::V1_4::SetupDataCallResult& /* dcResponse */) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::setInitialAttachApnResponse_1_5(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::setDataProfileResponse_1_5(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} From 1e90019220b5ba78f573c00636a8650410d4e358 Mon Sep 17 00:00:00 2001 From: Nicholas Ambur Date: Tue, 1 Oct 2019 13:11:26 -0700 Subject: [PATCH 0335/1022] add SoundTrigger HAL V2.3 add support for model parameter control APIs with THRESHOLD_FACTOR as the first supported parameter Bug: 141929369 Test: Tested manually with test app, GTS test gts-tradefed run gts-dev -m GtsAssistIntentTestCases and VTS test vts-tradefed run vts-hal -m VtsHalSoundtriggerV2_3Target Change-Id: I79d2b6365cc63fbdfe06fa94f1d0878903cbf554 --- .../all-versions/default/service/Android.bp | 1 + .../all-versions/default/service/service.cpp | 7 +- .../compatibility_matrix.current.xml | 2 +- current.txt | 2 + soundtrigger/2.3/Android.bp | 22 + soundtrigger/2.3/ISoundTriggerHw.hal | 87 ++ soundtrigger/2.3/default/Android.bp | 37 + soundtrigger/2.3/default/SoundTriggerHw.cpp | 804 ++++++++++++++++++ soundtrigger/2.3/default/SoundTriggerHw.h | 207 +++++ soundtrigger/2.3/types.hal | 61 ++ soundtrigger/2.3/vts/functional/Android.bp | 31 + .../VtsHalSoundtriggerV2_3TargetTest.cpp | 59 ++ 12 files changed, 1316 insertions(+), 4 deletions(-) create mode 100644 soundtrigger/2.3/Android.bp create mode 100644 soundtrigger/2.3/ISoundTriggerHw.hal create mode 100644 soundtrigger/2.3/default/Android.bp create mode 100644 soundtrigger/2.3/default/SoundTriggerHw.cpp create mode 100644 soundtrigger/2.3/default/SoundTriggerHw.h create mode 100644 soundtrigger/2.3/types.hal create mode 100644 soundtrigger/2.3/vts/functional/Android.bp create mode 100644 soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp index 45657305d5..f58a599024 100644 --- a/audio/common/all-versions/default/service/Android.bp +++ b/audio/common/all-versions/default/service/Android.bp @@ -41,6 +41,7 @@ cc_binary { "android.hardware.soundtrigger@2.0", "android.hardware.soundtrigger@2.1", "android.hardware.soundtrigger@2.2", + "android.hardware.soundtrigger@2.3", ], } diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp index 2730f3b1bb..00bcb19c2f 100644 --- a/audio/common/all-versions/default/service/service.cpp +++ b/audio/common/all-versions/default/service/service.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -78,9 +79,9 @@ int main(int /* argc */, char* /* argv */ []) { "Could not register audio effect API"); // clang-format on - ALOGW_IF((registerPassthroughServiceImplementations()), + ALOGW_IF((registerPassthroughServiceImplementations< + soundtrigger::V2_3::ISoundTriggerHw, soundtrigger::V2_2::ISoundTriggerHw, + soundtrigger::V2_1::ISoundTriggerHw, soundtrigger::V2_0::ISoundTriggerHw>()), "Could not register soundtrigger API"); ALOGW_IF(registerPassthroughServiceImplementations< diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index b0a82a5298..f5acdd441e 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -408,7 +408,7 @@ android.hardware.soundtrigger - 2.0-2 + 2.0-3 ISoundTriggerHw default diff --git a/current.txt b/current.txt index ca2949cdbb..686c487834 100644 --- a/current.txt +++ b/current.txt @@ -664,3 +664,5 @@ e7268d32bedcf7d98324ffc808ec3dc45248d47ff4d04519d09e3c71767a7ad1 android.hardwar b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication 7683fed9d253956071f18b152e6be657719536f98d9b534433d5e411bcde5061 android.hardware.radio.config@1.3::IRadioConfigResponse +c411dc16855fcb786cd5e08fe2889acbd72fd54217bd27fe0373813de230ce5f android.hardware.soundtrigger@2.3::types +5abad7b54d3400fab633cb7a36ffc1747e037bf805d3d9e3517cb6aabf26b002 android.hardware.soundtrigger@2.3::ISoundTriggerHw diff --git a/soundtrigger/2.3/Android.bp b/soundtrigger/2.3/Android.bp new file mode 100644 index 0000000000..3253a86695 --- /dev/null +++ b/soundtrigger/2.3/Android.bp @@ -0,0 +1,22 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.soundtrigger@2.3", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "ISoundTriggerHw.hal", + ], + interfaces: [ + "android.hardware.audio.common@2.0", + "android.hardware.soundtrigger@2.0", + "android.hardware.soundtrigger@2.1", + "android.hardware.soundtrigger@2.2", + "android.hidl.base@1.0", + "android.hidl.safe_union@1.0", + ], + gen_java: true, +} diff --git a/soundtrigger/2.3/ISoundTriggerHw.hal b/soundtrigger/2.3/ISoundTriggerHw.hal new file mode 100644 index 0000000000..207b9b74f9 --- /dev/null +++ b/soundtrigger/2.3/ISoundTriggerHw.hal @@ -0,0 +1,87 @@ +/* + * Copyright 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. + */ + +package android.hardware.soundtrigger@2.3; + +import @2.0::SoundModelHandle; +import @2.2::ISoundTriggerHw; + +/** + * SoundTrigger HAL interface. Used for hardware recognition of hotwords + * and other sounds. + */ +interface ISoundTriggerHw extends @2.2::ISoundTriggerHw { + + /** + * Set a model specific parameter with the given value. This parameter + * will keep its value for the duration the model is loaded regardless of starting and stopping + * recognition. Once the model is unloaded, the value will be lost. + * It is expected to check if the handle supports the parameter via the queryParameter + * API prior to calling this method. + * + * @param modelHandle The sound model handle indicating which model to modify parameters + * @param modelParam Parameter to set which will be validated against the + * ModelParameter type. Not putting ModelParameter type + * directly in the definition and validating internally + * allows for forward compatibility. + * @param value The value to set for the given model parameter + * @return status Operation completion status: 0 in case of success, + * -ENODEV if the native service cannot be reached + * -EINVAL invalid input parameter + */ + setParameter(SoundModelHandle modelHandle, ModelParameter modelParam, int32_t value) + generates (int32_t status); + + /** + * Get a model specific parameter. This parameter will keep its value + * for the duration the model is loaded regardless of starting and stopping recognition. + * Once the model is unloaded, the value will be lost. If the value is not set, a default + * value is returned. See ModelParameter for parameter default values. + * It is expected to check if the handle supports the parameter via the queryParameter + * API prior to calling this method. + * + * @param modelHandle The sound model associated with given modelParam + * @param modelParam Parameter to set which will be validated against the + * ModelParameter type. Not putting ModelParameter type + * directly in the definition and validating internally + * allows for forward compatibility. + * @return status Operation completion status: 0 in case of success, + * -ENODEV if the native service cannot be reached + * -EINVAL invalid input parameter + * @return value Value set to the requested parameter. Value is only set when status + * indicates success. + */ + getParameter(SoundModelHandle modelHandle, ModelParameter modelParam) + generates (int32_t status, int32_t value); + + /** + * Get supported parameter attributes with respect to the provided model + * handle. Along with determining the valid range, this API is also used + * to determine if a given parameter ID is supported at all by the + * modelHandle for use with getParameter and setParameter APIs. + * + * @param modelHandle The sound model handle indicating which model to query + * @param modelParam Parameter to set which will be validated against the + * ModelParameter type + * @return status Operation completion status: 0 in case of success + * -ENODEV if the native service cannot be reached + * -EINVAL invalid input parameter + * @return retval ModelParameter structure indicating supported attributes + * of the parameter for the given model handle + */ + queryParameter(SoundModelHandle modelHandle, ModelParameter modelParam) + generates (int32_t status, OptionalModelParameterRange retval); +}; diff --git a/soundtrigger/2.3/default/Android.bp b/soundtrigger/2.3/default/Android.bp new file mode 100644 index 0000000000..be2c8b0961 --- /dev/null +++ b/soundtrigger/2.3/default/Android.bp @@ -0,0 +1,37 @@ +// +// 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. + +cc_library_shared { + name: "android.hardware.soundtrigger@2.3-impl", + relative_install_path: "hw", + vendor: true, + srcs: [ + "SoundTriggerHw.cpp", + ], + shared_libs: [ + "libhidlbase", + "liblog", + "libhidlmemory", + "libutils", + "libhardware", + "android.hardware.soundtrigger@2.0", + "android.hardware.soundtrigger@2.0-core", + "android.hardware.soundtrigger@2.1", + "android.hardware.soundtrigger@2.2", + "android.hardware.soundtrigger@2.3", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + ], +} diff --git a/soundtrigger/2.3/default/SoundTriggerHw.cpp b/soundtrigger/2.3/default/SoundTriggerHw.cpp new file mode 100644 index 0000000000..4a39ab562d --- /dev/null +++ b/soundtrigger/2.3/default/SoundTriggerHw.cpp @@ -0,0 +1,804 @@ +/* + * 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 "SoundTriggerHw" + +#include "SoundTriggerHw.h" + +#include +#include +#include +#include + +using android::hardware::hidl_memory; +using android::hidl::allocator::V1_0::IAllocator; +using android::hidl::memory::V1_0::IMemory; + +namespace android { +namespace hardware { +namespace soundtrigger { +namespace V2_3 { +namespace implementation { + +/** + * According to the HIDL C++ Users Guide: client and server implementations + * should never directly refer to anything other than the interface header + * generated from the HIDL definition file (ie. ISoundTriggerHw.hal), so + * this V2_3 implementation copies the previous implementations and + * then adds the new implementation. + */ + +// Begin V2_0 implementation, copied from +// hardware/interfaces/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp + +// static +void soundModelCallback_(struct sound_trigger_model_event* halEvent, void* cookie) { + if (halEvent == NULL) { + ALOGW("soundModelCallback called with NULL event"); + return; + } + sp client = + wp( + static_cast(cookie)) + .promote(); + if (client == 0) { + ALOGW("soundModelCallback called on stale client"); + return; + } + if (halEvent->model != client->getHalHandle()) { + ALOGW("soundModelCallback call with wrong handle %d on client with handle %d", + (int)halEvent->model, (int)client->getHalHandle()); + return; + } + + client->soundModelCallback(halEvent); +} + +// static +void recognitionCallback_(struct sound_trigger_recognition_event* halEvent, void* cookie) { + if (halEvent == NULL) { + ALOGW("recognitionCallback call NULL event"); + return; + } + sp client = + wp( + static_cast(cookie)) + .promote(); + if (client == 0) { + ALOGW("recognitionCallback called on stale client"); + return; + } + + client->recognitionCallback(halEvent); +} + +Return SoundTriggerHw::getProperties(ISoundTriggerHw::getProperties_cb _hidl_cb) { + ALOGV("getProperties() mHwDevice %p", mHwDevice); + int ret; + struct sound_trigger_properties halProperties; + ISoundTriggerHw::Properties properties; + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + ret = mHwDevice->get_properties(mHwDevice, &halProperties); + + convertPropertiesFromHal(&properties, &halProperties); + + ALOGV("getProperties implementor %s recognitionModes %08x", properties.implementor.c_str(), + properties.recognitionModes); + +exit: + _hidl_cb(ret, properties); + return Void(); +} + +int SoundTriggerHw::doLoadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel, + sp client) { + int32_t ret = 0; + struct sound_trigger_sound_model* halSoundModel; + + ALOGV("doLoadSoundModel() data size %zu", soundModel.data.size()); + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + halSoundModel = convertSoundModelToHal(&soundModel); + if (halSoundModel == NULL) { + ret = -EINVAL; + goto exit; + } + + sound_model_handle_t halHandle; + ret = mHwDevice->load_sound_model(mHwDevice, halSoundModel, soundModelCallback_, client.get(), + &halHandle); + + free(halSoundModel); + + if (ret != 0) { + goto exit; + } + + client->setHalHandle(halHandle); + { + AutoMutex lock(mLock); + mClients.add(client->getId(), client); + } + +exit: + return ret; +} + +Return SoundTriggerHw::loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel, + const sp& callback, + V2_0::ISoundTriggerHwCallback::CallbackCookie cookie, + ISoundTriggerHw::loadSoundModel_cb _hidl_cb) { + sp client = + new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback); + _hidl_cb(doLoadSoundModel(soundModel, client), client->getId()); + return Void(); +} + +Return SoundTriggerHw::loadPhraseSoundModel( + const V2_0::ISoundTriggerHw::PhraseSoundModel& soundModel, + const sp& callback, + V2_0::ISoundTriggerHwCallback::CallbackCookie cookie, + ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb) { + sp client = + new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback); + _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel, client), + client->getId()); + return Void(); +} + +Return SoundTriggerHw::unloadSoundModel(int32_t modelHandle) { + int32_t ret; + sp client; + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + ret = -ENOSYS; + goto exit; + } + } + + ret = mHwDevice->unload_sound_model(mHwDevice, client->getHalHandle()); + + mClients.removeItem(modelHandle); + +exit: + return ret; +} + +Return SoundTriggerHw::startRecognition( + int32_t modelHandle, const V2_0::ISoundTriggerHw::RecognitionConfig& config, + const sp& /* callback */, int32_t /* cookie */) { + int32_t ret; + sp client; + struct sound_trigger_recognition_config* halConfig; + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + ret = -ENOSYS; + goto exit; + } + } + + halConfig = + convertRecognitionConfigToHal((const V2_0::ISoundTriggerHw::RecognitionConfig*)&config); + + if (halConfig == NULL) { + ret = -EINVAL; + goto exit; + } + ret = mHwDevice->start_recognition(mHwDevice, client->getHalHandle(), halConfig, + recognitionCallback_, client.get()); + + free(halConfig); + +exit: + return ret; +} + +Return SoundTriggerHw::stopRecognition(int32_t modelHandle) { + int32_t ret; + sp client; + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + ret = -ENOSYS; + goto exit; + } + } + + ret = mHwDevice->stop_recognition(mHwDevice, client->getHalHandle()); + +exit: + return ret; +} + +Return SoundTriggerHw::stopAllRecognitions() { + int32_t ret; + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + ret = mHwDevice->stop_all_recognitions(mHwDevice); + +exit: + return ret; +} + +SoundTriggerHw::SoundTriggerHw() : mModuleName("primary"), mHwDevice(NULL), mNextModelId(1) {} + +void SoundTriggerHw::onFirstRef() { + const hw_module_t* mod; + int rc; + + rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod); + if (rc != 0) { + ALOGE("couldn't load sound trigger module %s.%s (%s)", SOUND_TRIGGER_HARDWARE_MODULE_ID, + mModuleName, strerror(-rc)); + return; + } + rc = sound_trigger_hw_device_open(mod, &mHwDevice); + if (rc != 0) { + ALOGE("couldn't open sound trigger hw device in %s.%s (%s)", + SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc)); + mHwDevice = NULL; + return; + } + if (mHwDevice->common.version != SOUND_TRIGGER_DEVICE_API_VERSION_1_3) { + ALOGE("wrong sound trigger hw device version %04x", mHwDevice->common.version); + sound_trigger_hw_device_close(mHwDevice); + mHwDevice = NULL; + return; + } + + ALOGI("onFirstRef() mModuleName %s mHwDevice %p", mModuleName, mHwDevice); +} + +SoundTriggerHw::~SoundTriggerHw() { + if (mHwDevice != NULL) { + sound_trigger_hw_device_close(mHwDevice); + } +} + +uint32_t SoundTriggerHw::nextUniqueModelId() { + uint32_t modelId = 0; + { + AutoMutex lock(mLock); + do { + modelId = atomic_fetch_add_explicit(&mNextModelId, (uint_fast32_t)1, + memory_order_acq_rel); + } while (mClients.valueFor(modelId) != 0 && modelId != 0); + } + LOG_ALWAYS_FATAL_IF(modelId == 0, "wrap around in sound model IDs, num loaded models %zu", + mClients.size()); + return modelId; +} + +void SoundTriggerHw::convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid) { + uuid->timeLow = halUuid->timeLow; + uuid->timeMid = halUuid->timeMid; + uuid->versionAndTimeHigh = halUuid->timeHiAndVersion; + uuid->variantAndClockSeqHigh = halUuid->clockSeq; + memcpy(&uuid->node[0], &halUuid->node[0], 6); +} + +void SoundTriggerHw::convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid) { + halUuid->timeLow = uuid->timeLow; + halUuid->timeMid = uuid->timeMid; + halUuid->timeHiAndVersion = uuid->versionAndTimeHigh; + halUuid->clockSeq = uuid->variantAndClockSeqHigh; + memcpy(&halUuid->node[0], &uuid->node[0], 6); +} + +void SoundTriggerHw::convertPropertiesFromHal( + ISoundTriggerHw::Properties* properties, + const struct sound_trigger_properties* halProperties) { + properties->implementor = halProperties->implementor; + properties->description = halProperties->description; + properties->version = halProperties->version; + convertUuidFromHal(&properties->uuid, &halProperties->uuid); + properties->maxSoundModels = halProperties->max_sound_models; + properties->maxKeyPhrases = halProperties->max_key_phrases; + properties->maxUsers = halProperties->max_users; + properties->recognitionModes = halProperties->recognition_modes; + properties->captureTransition = halProperties->capture_transition; + properties->maxBufferMs = halProperties->max_buffer_ms; + properties->concurrentCapture = halProperties->concurrent_capture; + properties->triggerInEvent = halProperties->trigger_in_event; + properties->powerConsumptionMw = halProperties->power_consumption_mw; +} + +void SoundTriggerHw::convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase, + const ISoundTriggerHw::Phrase* triggerPhrase) { + halTriggerPhrase->id = triggerPhrase->id; + halTriggerPhrase->recognition_mode = triggerPhrase->recognitionModes; + unsigned int i; + + halTriggerPhrase->num_users = + std::min((int)triggerPhrase->users.size(), SOUND_TRIGGER_MAX_USERS); + for (i = 0; i < halTriggerPhrase->num_users; i++) { + halTriggerPhrase->users[i] = triggerPhrase->users[i]; + } + + strlcpy(halTriggerPhrase->locale, triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN); + strlcpy(halTriggerPhrase->text, triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN); +} + +struct sound_trigger_sound_model* SoundTriggerHw::convertSoundModelToHal( + const V2_0::ISoundTriggerHw::SoundModel* soundModel) { + struct sound_trigger_sound_model* halModel = NULL; + if (soundModel->type == V2_0::SoundModelType::KEYPHRASE) { + size_t allocSize = + sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size(); + struct sound_trigger_phrase_sound_model* halKeyPhraseModel = + static_cast(malloc(allocSize)); + LOG_ALWAYS_FATAL_IF(halKeyPhraseModel == NULL, + "malloc failed for size %zu in convertSoundModelToHal PHRASE", + allocSize); + + const V2_0::ISoundTriggerHw::PhraseSoundModel* keyPhraseModel = + reinterpret_cast(soundModel); + + size_t i; + for (i = 0; i < keyPhraseModel->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) { + convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i], &keyPhraseModel->phrases[i]); + } + halKeyPhraseModel->num_phrases = (unsigned int)i; + halModel = reinterpret_cast(halKeyPhraseModel); + halModel->data_offset = sizeof(struct sound_trigger_phrase_sound_model); + } else { + size_t allocSize = sizeof(struct sound_trigger_sound_model) + soundModel->data.size(); + halModel = static_cast(malloc(allocSize)); + LOG_ALWAYS_FATAL_IF(halModel == NULL, + "malloc failed for size %zu in convertSoundModelToHal GENERIC", + allocSize); + + halModel->data_offset = sizeof(struct sound_trigger_sound_model); + } + halModel->type = (sound_trigger_sound_model_type_t)soundModel->type; + convertUuidToHal(&halModel->uuid, &soundModel->uuid); + convertUuidToHal(&halModel->vendor_uuid, &soundModel->vendorUuid); + halModel->data_size = soundModel->data.size(); + uint8_t* dst = reinterpret_cast(halModel) + halModel->data_offset; + const uint8_t* src = reinterpret_cast(&soundModel->data[0]); + memcpy(dst, src, soundModel->data.size()); + + return halModel; +} + +void SoundTriggerHw::convertPhraseRecognitionExtraToHal( + struct sound_trigger_phrase_recognition_extra* halExtra, + const V2_0::PhraseRecognitionExtra* extra) { + halExtra->id = extra->id; + halExtra->recognition_modes = extra->recognitionModes; + halExtra->confidence_level = extra->confidenceLevel; + + unsigned int i; + for (i = 0; i < extra->levels.size() && i < SOUND_TRIGGER_MAX_USERS; i++) { + halExtra->levels[i].user_id = extra->levels[i].userId; + halExtra->levels[i].level = extra->levels[i].levelPercent; + } + halExtra->num_levels = i; +} + +struct sound_trigger_recognition_config* SoundTriggerHw::convertRecognitionConfigToHal( + const V2_0::ISoundTriggerHw::RecognitionConfig* config) { + size_t allocSize = sizeof(struct sound_trigger_recognition_config) + config->data.size(); + struct sound_trigger_recognition_config* halConfig = + static_cast(malloc(allocSize)); + + LOG_ALWAYS_FATAL_IF(halConfig == NULL, + "malloc failed for size %zu in convertRecognitionConfigToHal", allocSize); + + halConfig->capture_handle = (audio_io_handle_t)config->captureHandle; + halConfig->capture_device = (audio_devices_t)config->captureDevice; + halConfig->capture_requested = config->captureRequested; + + unsigned int i; + for (i = 0; i < config->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) { + convertPhraseRecognitionExtraToHal(&halConfig->phrases[i], &config->phrases[i]); + } + halConfig->num_phrases = i; + + halConfig->data_offset = sizeof(struct sound_trigger_recognition_config); + halConfig->data_size = config->data.size(); + uint8_t* dst = reinterpret_cast(halConfig) + halConfig->data_offset; + const uint8_t* src = reinterpret_cast(&config->data[0]); + memcpy(dst, src, config->data.size()); + return halConfig; +} + +// static +void SoundTriggerHw::convertSoundModelEventFromHal( + V2_0::ISoundTriggerHwCallback::ModelEvent* event, + const struct sound_trigger_model_event* halEvent) { + event->status = (V2_0::ISoundTriggerHwCallback::SoundModelStatus)halEvent->status; + // event->model to be remapped by called + event->data.setToExternal(const_cast(reinterpret_cast(halEvent)) + + halEvent->data_offset, + halEvent->data_size); +} + +// static +void SoundTriggerHw::convertPhaseRecognitionEventFromHal( + V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent* event, + const struct sound_trigger_phrase_recognition_event* halEvent) { + event->phraseExtras.resize(halEvent->num_phrases); + for (unsigned int i = 0; i < halEvent->num_phrases; i++) { + convertPhraseRecognitionExtraFromHal(&event->phraseExtras[i], &halEvent->phrase_extras[i]); + } + convertRecognitionEventFromHal(&event->common, &halEvent->common); +} + +// static +void SoundTriggerHw::convertRecognitionEventFromHal( + V2_0::ISoundTriggerHwCallback::RecognitionEvent* event, + const struct sound_trigger_recognition_event* halEvent) { + event->status = static_cast(halEvent->status); + event->type = static_cast(halEvent->type); + // event->model to be remapped by called + event->captureAvailable = halEvent->capture_available; + event->captureSession = halEvent->capture_session; + event->captureDelayMs = halEvent->capture_delay_ms; + event->capturePreambleMs = halEvent->capture_preamble_ms; + event->triggerInData = halEvent->trigger_in_data; + event->audioConfig.sampleRateHz = halEvent->audio_config.sample_rate; + event->audioConfig.channelMask = + (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask; + event->audioConfig.format = (audio::common::V2_0::AudioFormat)halEvent->audio_config.format; + event->data.setToExternal(const_cast(reinterpret_cast(halEvent)) + + halEvent->data_offset, + halEvent->data_size); +} + +// static +void SoundTriggerHw::convertPhraseRecognitionExtraFromHal( + V2_0::PhraseRecognitionExtra* extra, + const struct sound_trigger_phrase_recognition_extra* halExtra) { + extra->id = halExtra->id; + extra->recognitionModes = halExtra->recognition_modes; + extra->confidenceLevel = halExtra->confidence_level; + + extra->levels.resize(halExtra->num_levels); + for (unsigned int i = 0; i < halExtra->num_levels; i++) { + extra->levels[i].userId = halExtra->levels[i].user_id; + extra->levels[i].levelPercent = halExtra->levels[i].level; + } +} + +void SoundTriggerHw::SoundModelClient_2_0::recognitionCallback( + struct sound_trigger_recognition_event* halEvent) { + if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) { + V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event; + convertPhaseRecognitionEventFromHal( + &event, reinterpret_cast(halEvent)); + event.common.model = mId; + mCallback->phraseRecognitionCallback(event, mCookie); + } else { + V2_0::ISoundTriggerHwCallback::RecognitionEvent event; + convertRecognitionEventFromHal(&event, halEvent); + event.model = mId; + mCallback->recognitionCallback(event, mCookie); + } +} + +void SoundTriggerHw::SoundModelClient_2_0::soundModelCallback( + struct sound_trigger_model_event* halEvent) { + V2_0::ISoundTriggerHwCallback::ModelEvent event; + convertSoundModelEventFromHal(&event, halEvent); + event.model = mId; + mCallback->soundModelCallback(event, mCookie); +} + +// Begin V2_1 implementation, copied from +// hardware/interfaces/soundtrigger/2.1/default/SoundTriggerHw.cpp + +namespace { + +// Backs up by the vector with the contents of shared memory. +// It is assumed that the passed hidl_vector is empty, so it's +// not cleared if the memory is a null object. +// The caller needs to keep the returned sp as long as +// the data is needed. +std::pair> memoryAsVector(const hidl_memory& m, hidl_vec* vec) { + sp memory; + if (m.size() == 0) { + return std::make_pair(true, memory); + } + memory = mapMemory(m); + if (memory != nullptr) { + memory->read(); + vec->setToExternal(static_cast(static_cast(memory->getPointer())), + memory->getSize()); + return std::make_pair(true, memory); + } + ALOGE("%s: Could not map HIDL memory to IMemory", __func__); + return std::make_pair(false, memory); +} + +// Moves the data from the vector into allocated shared memory, +// emptying the vector. +// It is assumed that the passed hidl_memory is a null object, so it's +// not reset if the vector is empty. +// The caller needs to keep the returned sp as long as +// the data is needed. +std::pair> moveVectorToMemory(hidl_vec* v, hidl_memory* mem) { + sp memory; + if (v->size() == 0) { + return std::make_pair(true, memory); + } + sp ashmem = IAllocator::getService("ashmem"); + if (ashmem == 0) { + ALOGE("Failed to retrieve ashmem allocator service"); + return std::make_pair(false, memory); + } + bool success = false; + Return r = ashmem->allocate(v->size(), [&](bool s, const hidl_memory& m) { + success = s; + if (success) *mem = m; + }); + if (r.isOk() && success) { + memory = hardware::mapMemory(*mem); + if (memory != 0) { + memory->update(); + memcpy(memory->getPointer(), v->data(), v->size()); + memory->commit(); + v->resize(0); + return std::make_pair(true, memory); + } else { + ALOGE("Failed to map allocated ashmem"); + } + } else { + ALOGE("Failed to allocate %llu bytes from ashmem", (unsigned long long)v->size()); + } + return std::make_pair(false, memory); +} + +} // namespace + +Return SoundTriggerHw::loadSoundModel_2_1( + const V2_1::ISoundTriggerHw::SoundModel& soundModel, + const sp& callback, int32_t cookie, + V2_1::ISoundTriggerHw::loadSoundModel_2_1_cb _hidl_cb) { + // It is assumed that legacy data vector is empty, thus making copy is cheap. + V2_0::ISoundTriggerHw::SoundModel soundModel_2_0(soundModel.header); + auto result = memoryAsVector(soundModel.data, &soundModel_2_0.data); + if (result.first) { + sp client = + new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback); + _hidl_cb(doLoadSoundModel(soundModel_2_0, client), client->getId()); + return Void(); + } + _hidl_cb(-ENOMEM, 0); + return Void(); +} + +Return SoundTriggerHw::loadPhraseSoundModel_2_1( + const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel, + const sp& callback, int32_t cookie, + V2_1::ISoundTriggerHw::loadPhraseSoundModel_2_1_cb _hidl_cb) { + V2_0::ISoundTriggerHw::PhraseSoundModel soundModel_2_0; + // It is assumed that legacy data vector is empty, thus making copy is cheap. + soundModel_2_0.common = soundModel.common.header; + // Avoid copying phrases data. + soundModel_2_0.phrases.setToExternal( + const_cast(soundModel.phrases.data()), + soundModel.phrases.size()); + auto result = memoryAsVector(soundModel.common.data, &soundModel_2_0.common.data); + if (result.first) { + sp client = + new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback); + _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel_2_0, client), + client->getId()); + return Void(); + } + _hidl_cb(-ENOMEM, 0); + return Void(); +} + +Return SoundTriggerHw::startRecognition_2_1( + int32_t modelHandle, const V2_1::ISoundTriggerHw::RecognitionConfig& config, + const sp& callback, int32_t cookie) { + // It is assumed that legacy data vector is empty, thus making copy is cheap. + V2_0::ISoundTriggerHw::RecognitionConfig config_2_0(config.header); + auto result = memoryAsVector(config.data, &config_2_0.data); + return result.first ? startRecognition(modelHandle, config_2_0, callback, cookie) + : Return(-ENOMEM); +} + +void SoundTriggerHw::SoundModelClient_2_1::recognitionCallback( + struct sound_trigger_recognition_event* halEvent) { + if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) { + V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event_2_0; + convertPhaseRecognitionEventFromHal( + &event_2_0, reinterpret_cast(halEvent)); + event_2_0.common.model = mId; + V2_1::ISoundTriggerHwCallback::PhraseRecognitionEvent event; + event.phraseExtras.setToExternal(event_2_0.phraseExtras.data(), + event_2_0.phraseExtras.size()); + auto result = moveVectorToMemory(&event_2_0.common.data, &event.common.data); + if (result.first) { + // The data vector is now empty, thus copying is cheap. + event.common.header = event_2_0.common; + mCallback->phraseRecognitionCallback_2_1(event, mCookie); + } + } else { + V2_1::ISoundTriggerHwCallback::RecognitionEvent event; + convertRecognitionEventFromHal(&event.header, halEvent); + event.header.model = mId; + auto result = moveVectorToMemory(&event.header.data, &event.data); + if (result.first) { + mCallback->recognitionCallback_2_1(event, mCookie); + } + } +} + +void SoundTriggerHw::SoundModelClient_2_1::soundModelCallback( + struct sound_trigger_model_event* halEvent) { + V2_1::ISoundTriggerHwCallback::ModelEvent event; + convertSoundModelEventFromHal(&event.header, halEvent); + event.header.model = mId; + auto result = moveVectorToMemory(&event.header.data, &event.data); + if (result.first) { + mCallback->soundModelCallback_2_1(event, mCookie); + } +} + +// Begin V2_2 implementation, copied from +// hardware/interfaces/soundtrigger/2.2/default/SoundTriggerHw.cpp + +Return SoundTriggerHw::getModelState(int32_t modelHandle) { + sp client; + if (mHwDevice == NULL) { + return -ENODEV; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + return -ENOSYS; + } + } + + return mHwDevice->get_model_state(mHwDevice, client->getHalHandle()); +} + +// Begin V2_3 implementation + +Return SoundTriggerHw::setParameter(V2_0::SoundModelHandle modelHandle, + ModelParameter modelParam, int32_t value) { + sp client; + if (mHwDevice == NULL) { + return -ENODEV; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + return -EINVAL; + } + } + + return mHwDevice->set_parameter(mHwDevice, client->getHalHandle(), + convertModelParameterToHal(modelParam), value); +} + +Return SoundTriggerHw::getParameter(V2_0::SoundModelHandle modelHandle, + ModelParameter modelParam, getParameter_cb _hidl_cb) { + sp client; + if (mHwDevice == NULL) { + _hidl_cb(-ENODEV, 0); + return Void(); + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + _hidl_cb(-EINVAL, 0); + return Void(); + } + } + + int32_t value; + int32_t status = mHwDevice->get_parameter(mHwDevice, client->getHalHandle(), + convertModelParameterToHal(modelParam), &value); + _hidl_cb(status, value); + return Void(); +} + +Return SoundTriggerHw::queryParameter(V2_0::SoundModelHandle modelHandle, + ModelParameter modelParam, queryParameter_cb _hidl_cb) { + OptionalModelParameterRange optionalParamRange; + sp client; + if (mHwDevice == NULL) { + _hidl_cb(-ENODEV, optionalParamRange); + return Void(); + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + _hidl_cb(-EINVAL, optionalParamRange); + return Void(); + } + } + + sound_trigger_model_parameter_range_t paramRange; + int32_t status = mHwDevice->query_parameter( + mHwDevice, client->getHalHandle(), convertModelParameterToHal(modelParam), ¶mRange); + + if (status == 0) { + optionalParamRange.range({.start = paramRange.start, .end = paramRange.end}); + } + _hidl_cb(status, optionalParamRange); + return Void(); +} + +// static +sound_trigger_model_parameter_t SoundTriggerHw::convertModelParameterToHal(ModelParameter param) { + switch (param) { + case ModelParameter::THRESHOLD_FACTOR: + return MODEL_PARAMETER_THRESHOLD_FACTOR; + case ModelParameter::INVALID: + default: + return MODEL_PARAMETER_INVALID; + } +} + +// Methods from ::android::hidl::base::V1_0::IBase follow. + +ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* /* name */) { + return new SoundTriggerHw(); +} + +} // namespace implementation +} // namespace V2_3 +} // namespace soundtrigger +} // namespace hardware +} // namespace android diff --git a/soundtrigger/2.3/default/SoundTriggerHw.h b/soundtrigger/2.3/default/SoundTriggerHw.h new file mode 100644 index 0000000000..c82c9ea0e2 --- /dev/null +++ b/soundtrigger/2.3/default/SoundTriggerHw.h @@ -0,0 +1,207 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_V2_3_SOUNDTRIGGERHW_H +#define ANDROID_HARDWARE_SOUNDTRIGGER_V2_3_SOUNDTRIGGERHW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace soundtrigger { +namespace V2_3 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::audio::common::V2_0::Uuid; + +/** + * According to the HIDL C++ Users Guide: client and server implementations + * should never directly refer to anything other than the interface header + * generated from the HIDL definition file (ie. ISoundTriggerHw.hal), so + * this V2_3 implementation copies the previous implementations and + * then adds the new implementation. + */ +struct SoundTriggerHw : public ISoundTriggerHw { + // Methods from V2_0::ISoundTriggerHw follow. + Return getProperties(getProperties_cb _hidl_cb) override; + Return loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel, + const sp& callback, int32_t cookie, + loadSoundModel_cb _hidl_cb) override; + Return loadPhraseSoundModel(const V2_0::ISoundTriggerHw::PhraseSoundModel& soundModel, + const sp& callback, + int32_t cookie, loadPhraseSoundModel_cb _hidl_cb) override; + Return unloadSoundModel(int32_t modelHandle) override; + Return startRecognition(int32_t modelHandle, + const V2_0::ISoundTriggerHw::RecognitionConfig& config, + const sp& callback, + int32_t cookie) override; + Return stopRecognition(int32_t modelHandle) override; + Return stopAllRecognitions() override; + + // Methods from V2_1::ISoundTriggerHw follow. + Return loadSoundModel_2_1(const V2_1::ISoundTriggerHw::SoundModel& soundModel, + const sp& callback, + int32_t cookie, loadSoundModel_2_1_cb _hidl_cb) override; + Return loadPhraseSoundModel_2_1(const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel, + const sp& callback, + int32_t cookie, + loadPhraseSoundModel_2_1_cb _hidl_cb) override; + Return startRecognition_2_1(int32_t modelHandle, + const V2_1::ISoundTriggerHw::RecognitionConfig& config, + const sp& callback, + int32_t cookie) override; + + // Methods from V2_2::ISoundTriggerHw follow. + Return getModelState(int32_t modelHandle) override; + + // Methods from V2_3::ISoundTriggerHw follow. + Return setParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam, + int32_t value) override; + Return getParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam, + ISoundTriggerHw::getParameter_cb _hidl_cb) override; + Return queryParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam, + ISoundTriggerHw::queryParameter_cb _hidl_cb) override; + + SoundTriggerHw(); + + // Copied from hardware/interfaces/soundtrigger/2.0/default/SoundTriggerHalImpl.h + + /** + * Client object holding active handles and callback sctructures. Used for referencing + * which models map to which client of the HAL. SoundModelClients are stored in the + * mClients object while the model is active. + */ + class SoundModelClient : public RefBase { + public: + SoundModelClient(uint32_t id, V2_0::ISoundTriggerHwCallback::CallbackCookie cookie) + : mId(id), mCookie(cookie) {} + virtual ~SoundModelClient() {} + + uint32_t getId() const { return mId; } + sound_model_handle_t getHalHandle() const { return mHalHandle; } + void setHalHandle(sound_model_handle_t handle) { mHalHandle = handle; } + + virtual void recognitionCallback(struct sound_trigger_recognition_event* halEvent) = 0; + virtual void soundModelCallback(struct sound_trigger_model_event* halEvent) = 0; + + protected: + const uint32_t mId; + sound_model_handle_t mHalHandle; + V2_0::ISoundTriggerHwCallback::CallbackCookie mCookie; + }; + + private: + static void convertPhaseRecognitionEventFromHal( + V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent* event, + const struct sound_trigger_phrase_recognition_event* halEvent); + static void convertRecognitionEventFromHal( + V2_0::ISoundTriggerHwCallback::RecognitionEvent* event, + const struct sound_trigger_recognition_event* halEvent); + static void convertSoundModelEventFromHal(V2_0::ISoundTriggerHwCallback::ModelEvent* event, + const struct sound_trigger_model_event* halEvent); + + virtual ~SoundTriggerHw(); + + uint32_t nextUniqueModelId(); + int doLoadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel, + sp client); + + // RefBase + void onFirstRef() override; + + class SoundModelClient_2_0 : public SoundModelClient { + public: + SoundModelClient_2_0(uint32_t id, V2_0::ISoundTriggerHwCallback::CallbackCookie cookie, + sp callback) + : SoundModelClient(id, cookie), mCallback(callback) {} + + void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override; + void soundModelCallback(struct sound_trigger_model_event* halEvent) override; + + private: + sp mCallback; + }; + + void convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid); + void convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid); + void convertPropertiesFromHal(V2_0::ISoundTriggerHw::Properties* properties, + const struct sound_trigger_properties* halProperties); + static sound_trigger_model_parameter_t convertModelParameterToHal(ModelParameter param); + void convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase, + const V2_0::ISoundTriggerHw::Phrase* triggerPhrase); + // returned HAL sound model must be freed by caller + struct sound_trigger_sound_model* convertSoundModelToHal( + const V2_0::ISoundTriggerHw::SoundModel* soundModel); + void convertPhraseRecognitionExtraToHal(struct sound_trigger_phrase_recognition_extra* halExtra, + const V2_0::PhraseRecognitionExtra* extra); + // returned recognition config must be freed by caller + struct sound_trigger_recognition_config* convertRecognitionConfigToHal( + const V2_0::ISoundTriggerHw::RecognitionConfig* config); + + static void convertPhraseRecognitionExtraFromHal( + V2_0::PhraseRecognitionExtra* extra, + const struct sound_trigger_phrase_recognition_extra* halExtra); + + static void soundModelCallback(struct sound_trigger_model_event* halEvent, void* cookie); + static void recognitionCallback(struct sound_trigger_recognition_event* halEvent, void* cookie); + + const char* mModuleName; + struct sound_trigger_hw_device* mHwDevice; + volatile atomic_uint_fast32_t mNextModelId; + DefaultKeyedVector> mClients; + Mutex mLock; + + // Copied from hardware/interfaces/soundtrigger/2.1/default/SoundTriggerHw.h + class SoundModelClient_2_1 : public SoundModelClient { + public: + SoundModelClient_2_1(uint32_t id, V2_1::ISoundTriggerHwCallback::CallbackCookie cookie, + sp callback) + : SoundModelClient(id, cookie), mCallback(callback) {} + + void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override; + void soundModelCallback(struct sound_trigger_model_event* halEvent) override; + + private: + sp mCallback; + }; +}; + +extern "C" ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* name); + +} // namespace implementation +} // namespace V2_3 +} // namespace soundtrigger +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SOUNDTRIGGER_V2_2_SOUNDTRIGGERHW_H diff --git a/soundtrigger/2.3/types.hal b/soundtrigger/2.3/types.hal new file mode 100644 index 0000000000..c3a522b31f --- /dev/null +++ b/soundtrigger/2.3/types.hal @@ -0,0 +1,61 @@ +/* + * Copyright 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. + */ + +package android.hardware.soundtrigger@2.3; + +import android.hidl.safe_union@1.0::Monostate; + +/** + * Model specific parameters to be used with parameter set and get APIs + */ +enum ModelParameter : int32_t { + /** + * Placeholder for invalid model parameter used for returning error or + * passing an invalid value. + */ + INVALID = -1, + + /** + * Controls the sensitivity threshold adjustment factor for a given model. + * Negative value corresponds to less sensitive model (high threshold) and + * a positive value corresponds to a more sensitive model (low threshold). + * Default value is 0. + */ + THRESHOLD_FACTOR = 0 +}; + +/** + * Safe union wrapping ModelParameterRange. + * Monostate is used to indicate there is no valid range + */ +safe_union OptionalModelParameterRange { + Monostate noinit; + ModelParameterRange range; +}; + +/** + * Model specific range support for a given parameter + */ +struct ModelParameterRange { + /** + * start of supported value range inclusive + */ + int32_t start; + /** + * end of supported value range inclusive + */ + int32_t end; +}; diff --git a/soundtrigger/2.3/vts/functional/Android.bp b/soundtrigger/2.3/vts/functional/Android.bp new file mode 100644 index 0000000000..e3855fc372 --- /dev/null +++ b/soundtrigger/2.3/vts/functional/Android.bp @@ -0,0 +1,31 @@ +// +// 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. +// + +cc_test { + name: "VtsHalSoundtriggerV2_3TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalSoundtriggerV2_3TargetTest.cpp"], + static_libs: [ + "android.hardware.soundtrigger@2.0", + "android.hardware.soundtrigger@2.1", + "android.hardware.soundtrigger@2.2", + "android.hardware.soundtrigger@2.3", + ], + test_suites: [ + "general-tests", + "vts-core", + ], +} diff --git a/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp new file mode 100644 index 0000000000..202eb6c09b --- /dev/null +++ b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp @@ -0,0 +1,59 @@ +/* + * 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 "SoundTriggerHidlHalTest" + +#include +#include +#include +#include +#include +#include +#include + +using ::android::sp; +using ::android::hardware::Return; +using ::android::hardware::soundtrigger::V2_3::ISoundTriggerHw; + +/** + * Test class holding the instance of the SoundTriggerHW service to test. + * The passed parameter is the registered name of the implementing service + * supplied by INSTANTIATE_TEST_SUITE_P() call. + */ +class SoundTriggerHidlTest : public testing::TestWithParam { + public: + void SetUp() override { + soundtrigger = ISoundTriggerHw::getService(GetParam()); + + ASSERT_NE(soundtrigger, nullptr); + LOG(INFO) << "Test is remote " << soundtrigger->isRemote(); + } + + sp soundtrigger; +}; + +/** + * Empty test is in place to ensure service is initalized. + * Due to the nature of SoundTrigger HAL providing an interface for + * proprietary or vendor specific implementations, limited testing on + * individual APIs is possible. + */ +TEST_P(SoundTriggerHidlTest, ServiceIsInstantiated) {} + +INSTANTIATE_TEST_SUITE_P( + PerInstance, SoundTriggerHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)), + android::hardware::PrintInstanceNameToString); From 18b38eb441b35d0982c578706353c4fc0ca8687a Mon Sep 17 00:00:00 2001 From: "Nate(Qiang) Jiang" Date: Wed, 11 Dec 2019 12:48:13 -0800 Subject: [PATCH 0336/1022] Fix 6GHz support for NAN add NAN 6Ghz support in 1.4, size of bandSpecificConfig should be 3. Bug: 146062988 Test: unit test Test: acts AttachTest DiscoveryTest DataPathTest Change-Id: I3bd0a4f32d804eae848bc15d9813d5ccb3e5fc62 --- wifi/1.4/default/hidl_struct_util.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp index a7c568603a..45ffdde19d 100644 --- a/wifi/1.4/default/hidl_struct_util.cpp +++ b/wifi/1.4/default/hidl_struct_util.cpp @@ -1135,9 +1135,9 @@ bool convertHidlNanEnableRequestToLegacy( legacy_request->disc_mac_addr_rand_interval_sec = hidl_request.configParams.macAddressRandomizationIntervalSec; legacy_request->config_2dot4g_rssi_close = 1; - if (hidl_request.configParams.bandSpecificConfig.size() != 2) { + if (hidl_request.configParams.bandSpecificConfig.size() != 3) { LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: " - "bandSpecificConfig.size() != 2"; + "bandSpecificConfig.size() != 3"; return false; } legacy_request->rssi_close_2dot4g_val = From 497cc64544d50c0dace6109d75b0ea53a60ea2b1 Mon Sep 17 00:00:00 2001 From: Zhaoming Yin Date: Thu, 12 Dec 2019 11:37:05 -0800 Subject: [PATCH 0337/1022] Add fuzzer for FormatConvert Bug: 146086281 Test: Follow go/android-fuzzing to build and test Change-Id: Id94c57ba1b327cd4af2ae72fb0259953fa941d45 --- .../evs/common/utils/default/Android.bp | 1 + .../common/utils/default/test/fuzz/Android.bp | 99 +++++++++++++++++++ .../default/test/fuzz/FormatConvertFuzzer.cpp | 57 +++++++++++ 3 files changed, 157 insertions(+) create mode 100644 automotive/evs/common/utils/default/test/fuzz/Android.bp create mode 100644 automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp diff --git a/automotive/evs/common/utils/default/Android.bp b/automotive/evs/common/utils/default/Android.bp index 7734f5c19e..776ef81875 100644 --- a/automotive/evs/common/utils/default/Android.bp +++ b/automotive/evs/common/utils/default/Android.bp @@ -15,6 +15,7 @@ // cc_library_static { + host_supported: true, name: "android.hardware.automotive.evs@common-default-lib", vendor_available: true, relative_install_path: "hw", diff --git a/automotive/evs/common/utils/default/test/fuzz/Android.bp b/automotive/evs/common/utils/default/test/fuzz/Android.bp new file mode 100644 index 0000000000..105ec68b04 --- /dev/null +++ b/automotive/evs/common/utils/default/test/fuzz/Android.bp @@ -0,0 +1,99 @@ +// +// 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. +// + +cc_fuzz { + host_supported: true, + name : "FormatConvertFuzzer_copyNV21toRGB32", + srcs: [ + "FormatConvertFuzzer.cpp", + ], + static_libs: [ + "android.hardware.automotive.evs@common-default-lib" + ], + cflags: [ + "-DCOPY_NV21_TO_RGB32", + ], +} + +cc_fuzz { + host_supported: true, + name : "FormatConvertFuzzer_copyNV21toBGR32", + srcs: [ + "FormatConvertFuzzer.cpp", + ], + static_libs: [ + "android.hardware.automotive.evs@common-default-lib" + ], + cflags: [ + "-DCOPY_NV21_TO_BGR32", + ], +} + +cc_fuzz { + host_supported: true, + name : "FormatConvertFuzzer_copyYV12toRGB32", + srcs: [ + "FormatConvertFuzzer.cpp", + ], + static_libs: [ + "android.hardware.automotive.evs@common-default-lib" + ], + cflags: [ + "-DCOPY_YV12_TO_RGB32", + ], +} + +cc_fuzz { + host_supported: true, + name : "FormatConvertFuzzer_copyYV12toBGR32", + srcs: [ + "FormatConvertFuzzer.cpp", + ], + static_libs: [ + "android.hardware.automotive.evs@common-default-lib" + ], + cflags: [ + "-DCOPY_YV12_TO_BGR32", + ], +} + +cc_fuzz { + host_supported: true, + name : "FormatConvertFuzzer_copyYUYVtoRGB32", + srcs: [ + "FormatConvertFuzzer.cpp", + ], + static_libs: [ + "android.hardware.automotive.evs@common-default-lib" + ], + cflags: [ + "-DCOPY_YUYV_TO_RGB32", + ], +} + +cc_fuzz { + host_supported: true, + name : "FormatConvertFuzzer_copyYUYVtoBGR32", + srcs: [ + "FormatConvertFuzzer.cpp", + ], + static_libs: [ + "android.hardware.automotive.evs@common-default-lib" + ], + cflags: [ + "-DCOPY_YUYV_TO_BGR32", + ], +} diff --git a/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp b/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp new file mode 100644 index 0000000000..583a455160 --- /dev/null +++ b/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include "FormatConvert.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, std::size_t size) { + if (size < 256) { + return 0; + } + + std::srand(std::time(nullptr)); // use current time as seed for random generator + int random_variable = std::rand() % 10; + int width = (int)sqrt(size); + int height = width * ((float)random_variable / 10.0); + + uint8_t* src = (uint8_t*)malloc(sizeof(uint8_t) * size); + memcpy(src, data, sizeof(uint8_t) * (size)); + uint32_t* tgt = (uint32_t*)malloc(sizeof(uint32_t) * size); + +#ifdef COPY_NV21_TO_RGB32 + android::hardware::automotive::evs::common::Utils::copyNV21toRGB32(width, height, src, tgt, 0); +#elif COPY_NV21_TO_BGR32 + android::hardware::automotive::evs::common::Utils::copyNV21toBGR32(width, height, src, tgt, 0); +#elif COPY_YV12_TO_RGB32 + android::hardware::automotive::evs::common::Utils::copyYV12toRGB32(width, height, src, tgt, 0); +#elif COPY_YV12_TO_BGR32 + android::hardware::automotive::evs::common::Utils::copyYV12toBGR32(width, height, src, tgt, 0); +#elif COPY_YUYV_TO_RGB32 + android::hardware::automotive::evs::common::Utils::copyYUYVtoRGB32(width, height, src, 0, tgt, + 0); +#elif COPY_YUYV_TO_BGR32 + android::hardware::automotive::evs::common::Utils::copyYUYVtoBGR32(width, height, src, 0, tgt, + 0); +#endif + + free(src); + free(tgt); + + return 0; +} From 6c29bf20963069a6ba36cf1bf4ff7293e102fbe6 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 6 Dec 2019 17:56:32 -0800 Subject: [PATCH 0338/1022] Audio HAL: Add API to attach an effect to a device Add a method to IDevice interface allowing the attachement of an audio effect to an audio device. This is used when an audio effect is implemented below the HAL (e.g by an audio DSP) and is attached/enabled when a particular sink(e.g speaker) or source(e.g mic) device is selected. Bug: 136294538 Test: make Change-Id: I73d78c4f234fd80443a1cb3772c2d65457968652 --- audio/6.0/IDevice.hal | 24 +++++++++++++ audio/core/all-versions/default/Device.cpp | 35 +++++++++++++++++++ .../all-versions/default/PrimaryDevice.cpp | 8 +++++ .../default/include/core/default/Device.h | 3 +- .../include/core/default/PrimaryDevice.h | 2 ++ current.txt | 2 +- 6 files changed, 72 insertions(+), 2 deletions(-) diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal index 122c550ee7..2347696035 100644 --- a/audio/6.0/IDevice.hal +++ b/audio/6.0/IDevice.hal @@ -295,4 +295,28 @@ interface IDevice { */ @exit close() generates (Result retval); + + /** + * Applies an audio effect to an audio device. + * + * @param device identifies the sink or source device this effect must be applied to. + * "device" is the AudioPortHandle indicated for the device when the audio + * patch connecting that device was created. + * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of + * the effect to add. + * @return retval operation completion status. + */ + addDeviceEffect(AudioPortHandle device, uint64_t effectId) generates (Result retval); + + /** + * Stops applying an audio effect to an audio device. + * + * @param device identifies the sink or source device this effect was applied to. + * "device" is the AudioPortHandle indicated for the device when the audio + * patch is created at the audio HAL. + * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of + * the effect. + * @return retval operation completion status. + */ + removeDeviceEffect(AudioPortHandle device, uint64_t effectId) generates (Result retval); }; diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp index 21dab00387..525349f727 100644 --- a/audio/core/all-versions/default/Device.cpp +++ b/audio/core/all-versions/default/Device.cpp @@ -18,6 +18,7 @@ #include "core/default/Device.h" #include +#include "common/all-versions/default/EffectMap.h" #include "core/default/Conversions.h" #include "core/default/StreamIn.h" #include "core/default/StreamOut.h" @@ -25,6 +26,7 @@ //#define LOG_NDEBUG 0 +#include #include #include #include @@ -398,6 +400,39 @@ Result Device::doClose() { Return Device::close() { return doClose(); } + +Return Device::addDeviceEffect(AudioPortHandle device, uint64_t effectId) { + if (version() < AUDIO_DEVICE_API_VERSION_3_1 || mDevice->add_device_effect == nullptr) { + return Result::NOT_SUPPORTED; + } + + effect_handle_t halEffect = EffectMap::getInstance().get(effectId); + if (halEffect != NULL) { + return analyzeStatus("add_device_effect", + mDevice->add_device_effect( + mDevice, static_cast(device), halEffect)); + } else { + ALOGW("%s Invalid effect ID passed from client: %" PRIu64 "", __func__, effectId); + return Result::INVALID_ARGUMENTS; + } +} + +Return Device::removeDeviceEffect(AudioPortHandle device, uint64_t effectId) { + if (version() < AUDIO_DEVICE_API_VERSION_3_1 || mDevice->remove_device_effect == nullptr) { + return Result::NOT_SUPPORTED; + } + + effect_handle_t halEffect = EffectMap::getInstance().get(effectId); + if (halEffect != NULL) { + return analyzeStatus("remove_device_effect", + mDevice->remove_device_effect( + mDevice, static_cast(device), halEffect)); + } else { + ALOGW("%s Invalid effect ID passed from client: %" PRIu64 "", __func__, effectId); + return Result::INVALID_ARGUMENTS; + } +} + #endif } // namespace implementation diff --git a/audio/core/all-versions/default/PrimaryDevice.cpp b/audio/core/all-versions/default/PrimaryDevice.cpp index 3cf09320aa..0f1aba0f2f 100644 --- a/audio/core/all-versions/default/PrimaryDevice.cpp +++ b/audio/core/all-versions/default/PrimaryDevice.cpp @@ -168,6 +168,14 @@ Return PrimaryDevice::setConnectedState(const DeviceAddress& address, bo Return PrimaryDevice::close() { return mDevice->close(); } + +Return PrimaryDevice::addDeviceEffect(AudioPortHandle device, uint64_t effectId) { + return mDevice->addDeviceEffect(device, effectId); +} + +Return PrimaryDevice::removeDeviceEffect(AudioPortHandle device, uint64_t effectId) { + return mDevice->removeDeviceEffect(device, effectId); +} #endif // Methods from ::android::hardware::audio::CPP_VERSION::IPrimaryDevice follow. diff --git a/audio/core/all-versions/default/include/core/default/Device.h b/audio/core/all-versions/default/include/core/default/Device.h index 11ab6077ab..80a9638004 100644 --- a/audio/core/all-versions/default/include/core/default/Device.h +++ b/audio/core/all-versions/default/include/core/default/Device.h @@ -116,8 +116,9 @@ struct Device : public IDevice, public ParametersUtil { #endif #if MAJOR_VERSION >= 6 Return close() override; + Return addDeviceEffect(AudioPortHandle device, uint64_t effectId) override; + Return removeDeviceEffect(AudioPortHandle device, uint64_t effectId) override; #endif - Return debug(const hidl_handle& fd, const hidl_vec& options) override; // Utility methods for extending interfaces. diff --git a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h index f5f38482ee..9fc90c39fe 100644 --- a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h +++ b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h @@ -98,6 +98,8 @@ struct PrimaryDevice : public IPrimaryDevice { #endif #if MAJOR_VERSION >= 6 Return close() override; + Return addDeviceEffect(AudioPortHandle device, uint64_t effectId) override; + Return removeDeviceEffect(AudioPortHandle device, uint64_t effectId) override; #endif Return debug(const hidl_handle& fd, const hidl_vec& options) override; diff --git a/current.txt b/current.txt index 9a7110a321..999b207899 100644 --- a/current.txt +++ b/current.txt @@ -598,7 +598,7 @@ fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardwar # HALs released in Android R e966a3437d6a98d9d9e14e9d672088771716031900c0deb55a0946c751a03a44 android.hardware.audio@6.0::types -2736c59abaccacac407ebe80c5e48d446edf015051d05632fb679ba471779e6e android.hardware.audio@6.0::IDevice +4540d12fe1cea996f21bd1712d4ae0906dcbd58177dac494efc605b004902d43 android.hardware.audio@6.0::IDevice 2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice fd1f1b29f26b42e886220f04a08086c00e5ade9d7b53f095438e578ab9d42a93 android.hardware.audio@6.0::IStream From bee3d2c3c98ccb6b59f55e22eb7a0605fb3895d5 Mon Sep 17 00:00:00 2001 From: chrisweir Date: Tue, 19 Nov 2019 10:23:37 -0800 Subject: [PATCH 0339/1022] Add support for error, RTR, and EFF frames Error frames, remote transmission request, and extended format frames require some changes to the way that we set up our sockets. Bug: 142655821 Bug: 144774939 Test: manual Change-Id: I06212cb852d480c1c7093e8c509ca8aa9f85f81f --- automotive/can/1.0/default/CanBus.cpp | 83 ++++++++++++++++--- automotive/can/1.0/default/CanBus.h | 2 + .../can/1.0/default/libnetdevice/can.cpp | 9 ++ automotive/can/1.0/tools/canhaldump.cpp | 9 +- automotive/can/1.0/types.hal | 28 +++++++ .../functional/VtsHalCanBusV1_0TargetTest.cpp | 6 +- .../VtsHalCanBusVirtualV1_0TargetTest.cpp | 8 +- 7 files changed, 122 insertions(+), 23 deletions(-) diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp index 42d2e3c277..86df5dc93b 100644 --- a/automotive/can/1.0/default/CanBus.cpp +++ b/automotive/can/1.0/default/CanBus.cpp @@ -22,6 +22,8 @@ #include #include #include +#include +#include namespace android { namespace hardware { @@ -219,6 +221,21 @@ bool CanBus::down() { return success; } +/** + * Helper function to determine if a flag meets the requirements of a + * FilterFlag. See definition of FilterFlag in types.hal + * + * \param filterFlag FilterFlag object to match flag against + * \param flag bool object from CanMessage object + */ +static bool satisfiesFilterFlag(FilterFlag filterFlag, bool flag) { + // TODO(b/144458917) add testing for this to VTS tests + if (filterFlag == FilterFlag::DONT_CARE) return true; + if (filterFlag == FilterFlag::REQUIRE) return flag; + if (filterFlag == FilterFlag::EXCLUDE) return !flag; + return false; +} + /** * Match the filter set against message id. * @@ -229,13 +246,16 @@ bool CanBus::down() { * \param id Message id to filter * \return true if the message id matches the filter, false otherwise */ -static bool match(const hidl_vec& filter, CanMessageId id) { +static bool match(const hidl_vec& filter, CanMessageId id, bool isExtendedId, + bool isRtr) { if (filter.size() == 0) return true; bool anyNonInvertedPresent = false; bool anyNonInvertedSatisfied = false; for (auto& rule : filter) { - const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted; + const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted && + satisfiesFilterFlag(rule.rtr, isRtr) && + satisfiesFilterFlag(rule.extendedFormat, isExtendedId); if (rule.inverted) { // Any inverted (blacklist) rule not being satisfied invalidates the whole filter set. if (!satisfied) return false; @@ -247,11 +267,54 @@ static bool match(const hidl_vec& filter, CanMessageId id) { return !anyNonInvertedPresent || anyNonInvertedSatisfied; } +void CanBus::notifyErrorListeners(ErrorEvent err, bool isFatal) { + std::lock_guard lck(mErrListenersGuard); + for (auto& listener : mErrListeners) { + if (!listener->onError(err, isFatal).isOk()) { + LOG(WARNING) << "Failed to notify listener about error"; + } + } +} + +static ErrorEvent parseErrorFrame(const struct canfd_frame& frame) { + // decode error frame (to a degree) + if ((frame.can_id & (CAN_ERR_BUSERROR | CAN_ERR_BUSOFF)) != 0) { + return ErrorEvent::BUS_ERROR; + } + if ((frame.data[1] & CAN_ERR_CRTL_TX_OVERFLOW) != 0) { + return ErrorEvent::TX_OVERFLOW; + } + if ((frame.data[1] & CAN_ERR_CRTL_RX_OVERFLOW) != 0) { + return ErrorEvent::RX_OVERFLOW; + } + if ((frame.data[2] & CAN_ERR_PROT_OVERLOAD) != 0) { + return ErrorEvent::BUS_OVERLOAD; + } + if ((frame.can_id & CAN_ERR_PROT) != 0) { + return ErrorEvent::MALFORMED_INPUT; + } + if ((frame.can_id & (CAN_ERR_CRTL | CAN_ERR_TRX | CAN_ERR_RESTARTED)) != 0) { + // "controller restarted" constitutes a HARDWARE_ERROR imo + return ErrorEvent::HARDWARE_ERROR; + } + return ErrorEvent::UNKNOWN_ERROR; +} + void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp) { + if ((frame.can_id & CAN_ERR_FLAG) != 0) { + // error bit is set + LOG(WARNING) << "CAN Error frame received"; + // TODO(b/144458917) consider providing different values for isFatal, depending on error + notifyErrorListeners(parseErrorFrame(frame), false); + return; + } + CanMessage message = {}; - message.id = frame.can_id; + message.id = frame.can_id & CAN_EFF_MASK; // mask out eff/rtr/err flags message.payload = hidl_vec(frame.data, frame.data + frame.len); message.timestamp = timestamp.count(); + message.isExtendedId = (frame.can_id & CAN_EFF_FLAG) != 0; + message.remoteTransmissionRequest = (frame.can_id & CAN_RTR_FLAG) != 0; if (UNLIKELY(kSuperVerbose)) { LOG(VERBOSE) << "Got message " << toString(message); @@ -259,7 +322,9 @@ void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds ti std::lock_guard lck(mMsgListenersGuard); for (auto& listener : mMsgListeners) { - if (!match(listener.filter, message.id)) continue; + if (!match(listener.filter, message.id, message.remoteTransmissionRequest, + message.isExtendedId)) + continue; if (!listener.callback->onReceive(message).isOk() && !listener.failedOnce) { listener.failedOnce = true; LOG(WARNING) << "Failed to notify listener about message"; @@ -274,15 +339,7 @@ void CanBus::onError(int errnoVal) { mDownAfterUse = false; eventType = ErrorEvent::INTERFACE_DOWN; } - - { - std::lock_guard lck(mErrListenersGuard); - for (auto& listener : mErrListeners) { - if (!listener->onError(eventType, true).isOk()) { - LOG(WARNING) << "Failed to notify listener about error"; - } - } - } + notifyErrorListeners(eventType, true); const auto errcb = mErrCb; if (errcb != nullptr) errcb(); diff --git a/automotive/can/1.0/default/CanBus.h b/automotive/can/1.0/default/CanBus.h index 365e90c439..da3fc5a5d8 100644 --- a/automotive/can/1.0/default/CanBus.h +++ b/automotive/can/1.0/default/CanBus.h @@ -89,6 +89,8 @@ struct CanBus : public ICanBus { void clearMsgListeners(); void clearErrListeners(); + void notifyErrorListeners(ErrorEvent err, bool isFatal); + void onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp); void onError(int errnoVal); diff --git a/automotive/can/1.0/default/libnetdevice/can.cpp b/automotive/can/1.0/default/libnetdevice/can.cpp index 87617dde74..6452d9b8d1 100644 --- a/automotive/can/1.0/default/libnetdevice/can.cpp +++ b/automotive/can/1.0/default/libnetdevice/can.cpp @@ -24,12 +24,16 @@ #include #include +#include #include +#include namespace android { namespace netdevice { namespace can { +static constexpr can_err_mask_t kErrMask = CAN_ERR_MASK; + base::unique_fd socket(const std::string& ifname) { struct sockaddr_can addr = {}; addr.can_family = AF_CAN; @@ -45,6 +49,11 @@ base::unique_fd socket(const std::string& ifname) { return {}; } + if (setsockopt(sock.get(), SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &kErrMask, sizeof(kErrMask)) < 0) { + LOG(ERROR) << "Can't receive error frames, CAN setsockpt failed: " << strerror(errno); + return {}; + } + if (0 != fcntl(sock.get(), F_SETFL, O_RDWR | O_NONBLOCK)) { LOG(ERROR) << "Couldn't put CAN socket in non-blocking mode"; return {}; diff --git a/automotive/can/1.0/tools/canhaldump.cpp b/automotive/can/1.0/tools/canhaldump.cpp index 99fd14a7dc..55b2a347c7 100644 --- a/automotive/can/1.0/tools/canhaldump.cpp +++ b/automotive/can/1.0/tools/canhaldump.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -42,12 +43,14 @@ struct CanMessageListener : public V1_0::ICanMessageListener { CanMessageListener(std::string name) : name(name) {} virtual Return onReceive(const V1_0::CanMessage& message) { - std::cout << " " << name << " " << std::hex << std::uppercase << std::setw(3) + int msgIdWidth = 3; + if (message.isExtendedId) msgIdWidth = 8; + std::cout << " " << name << " " << std::hex << std::uppercase << std::setw(msgIdWidth) << std::setfill('0') << message.id << std::setw(0); + std::cout << " [" << message.payload.size() << "] "; if (message.remoteTransmissionRequest) { - std::cout << " RTR"; + std::cout << "remote request"; } else { - std::cout << " [" << message.payload.size() << "] "; for (const auto byte : message.payload) { std::cout << " " << std::setfill('0') << std::setw(2) << unsigned(byte); } diff --git a/automotive/can/1.0/types.hal b/automotive/can/1.0/types.hal index 6f690f7851..f09c9403c1 100644 --- a/automotive/can/1.0/types.hal +++ b/automotive/can/1.0/types.hal @@ -58,6 +58,15 @@ struct CanMessage { * If this flag is set, payload must be empty. */ bool remoteTransmissionRequest; + + /** + * Flag indicating if the message has an extended ID. + * + * Extended ID's are 29 bits long, as opposed to the standard 11 bit ID. + * It can not simply be inferred from the length of the ID itself, as the + * message ID 0x00000123 != message ID 0x123. + */ + bool isExtendedId; }; /** @@ -70,11 +79,30 @@ struct CanMessage { * one) and all inverted filters must match. In other words: * - a single matching non-inverted filter makes the whole set matching; * - a single non-matching inverted filter makes the whole set non-matching. + * + * Additional less common options for filtering include: + * rtr - Remote Transmission Request; another ECU requests DLC bytes of data on this message ID + * extendedFormat - 29 bit message ID is used instead of 11 bits */ struct CanMessageFilter { CanMessageId id; uint32_t mask; bool inverted; + FilterFlag rtr; + FilterFlag extendedFormat; +}; + + +/** + * Types of filter that can be applied to a CanMessageFilter + */ +enum FilterFlag : uint8_t { + /** Default, FilterFlag doesn't effect what messages filtered */ + DONT_CARE = 0, + /** This FilterFlag MUST be present in received messages to pass though the filter */ + REQUIRE, + /** This FilterFlag must NOT be present in received messages to pass though the filter */ + EXCLUDE, }; enum Result : uint8_t { diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp index 1a05716fd0..250caf2375 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp @@ -123,9 +123,9 @@ TEST_F(CanBusHalTest, ListenNoFilter) { TEST_F(CanBusHalTest, ListenSomeFilter) { hidl_vec filters = { - {0x123, 0x1FF, false}, - {0x001, 0x00F, true}, - {0x200, 0x100, false}, + {0x123, 0x1FF, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE}, + {0x001, 0x00F, true, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE}, + {0x200, 0x100, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE}, }; const auto [result, closeHandle] = listen(filters, new CanMessageListener()); diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp index 225984dd93..695b9fb4ab 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp @@ -244,14 +244,14 @@ TEST_F(CanBusVirtualHalTest, Filter) { auto bus2 = makeBus(); hidl_vec filterPositive = { - {0x101, 0x100, false}, - {0x010, 0x0F0, false}, + {0x101, 0x100, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE}, + {0x010, 0x0F0, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE}, }; auto listenerPositive = bus2.listen(filterPositive); hidl_vec filterNegative = { - {0x123, 0x0FF, true}, - {0x004, 0x00F, true}, + {0x123, 0x0FF, true, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE}, + {0x004, 0x00F, true, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE}, }; auto listenerNegative = bus2.listen(filterNegative); From b23485ddc58945200de6d9923f3d2c3984d8ccca Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Mon, 9 Dec 2019 15:24:16 -0800 Subject: [PATCH 0340/1022] Remove 6GHz capability query through HAL It was decided to perform the check on the device support of 6GHz through overlay configs instead of through HAL. This commit removes the Hidl API changes that were used for that check. Bug: 145936758 Bug: 139354972 Test: Manual Test: VTS test Test: Unit test: hardware/interfaces/wifi/1.4/default/tests/runtests.sh Change-Id: I81fdf603a668a71e3e875211367111fffee20e54 --- wifi/1.4/Android.bp | 1 - wifi/1.4/IWifiStaIface.hal | 48 -------------- wifi/1.4/default/hidl_struct_util.cpp | 5 +- wifi/1.4/default/hidl_struct_util.h | 1 - wifi/1.4/default/wifi_chip.cpp | 5 +- wifi/1.4/default/wifi_chip.h | 4 +- wifi/1.4/default/wifi_sta_iface.cpp | 51 ++++++--------- wifi/1.4/default/wifi_sta_iface.h | 7 +-- .../functional/wifi_sta_iface_hidl_test.cpp | 62 ------------------- 9 files changed, 28 insertions(+), 156 deletions(-) delete mode 100644 wifi/1.4/IWifiStaIface.hal delete mode 100644 wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp diff --git a/wifi/1.4/Android.bp b/wifi/1.4/Android.bp index b4432301af..3b94619b3d 100644 --- a/wifi/1.4/Android.bp +++ b/wifi/1.4/Android.bp @@ -15,7 +15,6 @@ hidl_interface { "IWifiNanIface.hal", "IWifiRttController.hal", "IWifiRttControllerEventCallback.hal", - "IWifiStaIface.hal", ], interfaces: [ "android.hardware.wifi@1.0", diff --git a/wifi/1.4/IWifiStaIface.hal b/wifi/1.4/IWifiStaIface.hal deleted file mode 100644 index 8bb0de80cb..0000000000 --- a/wifi/1.4/IWifiStaIface.hal +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 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. - */ - -package android.hardware.wifi@1.4; - -import @1.0::WifiStatus; -import @1.0::MacAddress; -import @1.0::IWifiStaIface; -import @1.3::IWifiStaIface; - -/** - * Interface used to represent a single STA iface. - * - * IWifiChip.createStaIface() may return a @1.4::IWifiStaIface when supported. - */ -interface IWifiStaIface extends @1.3::IWifiStaIface { - enum StaIfaceCapabilityMask : @1.0::IWifiStaIface.StaIfaceCapabilityMask { - STA_6G = 1 << 15, - }; - - /** - * Get the capabilities supported by this STA iface. - * - * @return status WifiStatus of the operation. - * Possible status codes: - * |WifiStatusCode.SUCCESS|, - * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|, - * |WifiStatusCode.ERROR_NOT_AVAILABLE|, - * |WifiStatusCode.ERROR_NOT_SUPPORTED|, - * |WifiStatusCode.ERROR_UNKNOWN| - * @return capabilities Bitset of |StaIfaceCapabilityMask| values. - */ - getCapabilities_1_4() - generates (WifiStatus status, bitfield capabilities); -}; diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp index 45ffdde19d..4996e358b2 100644 --- a/wifi/1.4/default/hidl_struct_util.cpp +++ b/wifi/1.4/default/hidl_struct_util.cpp @@ -120,8 +120,6 @@ convertLegacyFeatureToHidlStaIfaceCapability(uint64_t feature) { return HidlStaIfaceCaps::ND_OFFLOAD; case WIFI_FEATURE_MKEEP_ALIVE: return HidlStaIfaceCaps::KEEP_ALIVE; - case WIFI_FEATURE_INFRA_6G: - return HidlStaIfaceCaps::STA_6G; }; CHECK(false) << "Unknown legacy feature: " << feature; return {}; @@ -394,8 +392,7 @@ bool convertLegacyFeaturesToHidlStaCapabilities( WIFI_FEATURE_IE_WHITELIST, WIFI_FEATURE_SCAN_RAND, WIFI_FEATURE_INFRA_5G, WIFI_FEATURE_HOTSPOT, WIFI_FEATURE_PNO, WIFI_FEATURE_TDLS, WIFI_FEATURE_TDLS_OFFCHANNEL, - WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE, - WIFI_FEATURE_INFRA_6G}) { + WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE}) { if (feature & legacy_feature_set) { *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature); } diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h index 160870a7ca..d040c1fd2e 100644 --- a/wifi/1.4/default/hidl_struct_util.h +++ b/wifi/1.4/default/hidl_struct_util.h @@ -25,7 +25,6 @@ #include #include #include -#include #include #include "wifi_legacy_hal.h" diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp index 2b015d3115..a70457bded 100644 --- a/wifi/1.4/default/wifi_chip.cpp +++ b/wifi/1.4/default/wifi_chip.cpp @@ -938,7 +938,8 @@ WifiStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) { return createWifiStatus(WifiStatusCode::SUCCESS); } -std::pair> WifiChip::createStaIfaceInternal() { +std::pair> +WifiChip::createStaIfaceInternal() { if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::STA)) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } @@ -962,7 +963,7 @@ WifiChip::getStaIfaceNamesInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)}; } -std::pair> WifiChip::getStaIfaceInternal( +std::pair> WifiChip::getStaIfaceInternal( const std::string& ifname) { const auto iface = findUsingName(sta_ifaces_, ifname); if (!iface.get()) { diff --git a/wifi/1.4/default/wifi_chip.h b/wifi/1.4/default/wifi_chip.h index c76eabf18e..3323ade681 100644 --- a/wifi/1.4/default/wifi_chip.h +++ b/wifi/1.4/default/wifi_chip.h @@ -197,9 +197,9 @@ class WifiChip : public V1_4::IWifiChip { std::pair> getP2pIfaceInternal( const std::string& ifname); WifiStatus removeP2pIfaceInternal(const std::string& ifname); - std::pair> createStaIfaceInternal(); + std::pair> createStaIfaceInternal(); std::pair> getStaIfaceNamesInternal(); - std::pair> getStaIfaceInternal( + std::pair> getStaIfaceInternal( const std::string& ifname); WifiStatus removeStaIfaceInternal(const std::string& ifname); std::pair> diff --git a/wifi/1.4/default/wifi_sta_iface.cpp b/wifi/1.4/default/wifi_sta_iface.cpp index 68c989d6a6..e2ea6e464e 100644 --- a/wifi/1.4/default/wifi_sta_iface.cpp +++ b/wifi/1.4/default/wifi_sta_iface.cpp @@ -266,13 +266,6 @@ Return WifiStaIface::getFactoryMacAddress( hidl_status_cb); } -Return WifiStaIface::getCapabilities_1_4( - getCapabilities_cb hidl_status_cb) { - return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, - &WifiStaIface::getCapabilitiesInternal_1_4, - hidl_status_cb); -} - std::pair WifiStaIface::getNameInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_}; } @@ -290,7 +283,26 @@ WifiStatus WifiStaIface::registerEventCallbackInternal( } std::pair WifiStaIface::getCapabilitiesInternal() { - return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0}; + legacy_hal::wifi_error legacy_status; + uint64_t legacy_feature_set; + std::tie(legacy_status, legacy_feature_set) = + legacy_hal_.lock()->getSupportedFeatureSet(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {createWifiStatusFromLegacyError(legacy_status), 0}; + } + uint32_t legacy_logger_feature_set; + std::tie(legacy_status, legacy_logger_feature_set) = + legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + // some devices don't support querying logger feature set + legacy_logger_feature_set = 0; + } + uint32_t hidl_caps; + if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities( + legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) { + return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0}; + } + return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps}; } std::pair @@ -628,29 +640,6 @@ WifiStaIface::getFactoryMacAddressInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), mac}; } -std::pair WifiStaIface::getCapabilitiesInternal_1_4() { - legacy_hal::wifi_error legacy_status; - uint64_t legacy_feature_set; - std::tie(legacy_status, legacy_feature_set) = - legacy_hal_.lock()->getSupportedFeatureSet(ifname_); - if (legacy_status != legacy_hal::WIFI_SUCCESS) { - return {createWifiStatusFromLegacyError(legacy_status), 0}; - } - uint32_t legacy_logger_feature_set; - std::tie(legacy_status, legacy_logger_feature_set) = - legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_); - if (legacy_status != legacy_hal::WIFI_SUCCESS) { - // some devices don't support querying logger feature set - legacy_logger_feature_set = 0; - } - uint32_t hidl_caps; - if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities( - legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) { - return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0}; - } - return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps}; -} - } // namespace implementation } // namespace V1_4 } // namespace wifi diff --git a/wifi/1.4/default/wifi_sta_iface.h b/wifi/1.4/default/wifi_sta_iface.h index e85e39d310..dee04f2a69 100644 --- a/wifi/1.4/default/wifi_sta_iface.h +++ b/wifi/1.4/default/wifi_sta_iface.h @@ -19,7 +19,7 @@ #include #include -#include +#include #include "hidl_callback_util.h" #include "wifi_iface_util.h" @@ -35,7 +35,7 @@ using namespace android::hardware::wifi::V1_0; /** * HIDL interface object used to control a STA Iface instance. */ -class WifiStaIface : public V1_4::IWifiStaIface { +class WifiStaIface : public V1_3::IWifiStaIface { public: WifiStaIface(const std::string& ifname, const std::weak_ptr legacy_hal, @@ -112,8 +112,6 @@ class WifiStaIface : public V1_4::IWifiStaIface { setMacAddress_cb hidl_status_cb) override; Return getFactoryMacAddress( getFactoryMacAddress_cb hidl_status_cb) override; - Return getCapabilities_1_4( - getCapabilities_1_4_cb hidl_status_cb) override; private: // Corresponding worker functions for the HIDL methods. @@ -162,7 +160,6 @@ class WifiStaIface : public V1_4::IWifiStaIface { WifiStatus setMacAddressInternal(const std::array& mac); std::pair> getFactoryMacAddressInternal(); - std::pair getCapabilitiesInternal_1_4(); std::string ifname_; std::weak_ptr legacy_hal_; diff --git a/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp deleted file mode 100644 index ec4b2c949d..0000000000 --- a/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Staache 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 - -#include - -#include "wifi_hidl_call_util.h" -#include "wifi_hidl_test_utils.h" - -using ::android::sp; -using ::android::hardware::hidl_array; -using ::android::hardware::wifi::V1_0::WifiStatus; -using ::android::hardware::wifi::V1_0::WifiStatusCode; -using ::android::hardware::wifi::V1_4::IWifiStaIface; - -/** - * Fixture to use for all STA Iface HIDL interface tests. - */ -class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { - public: - virtual void SetUp() override { - wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface()); - ASSERT_NE(nullptr, wifi_sta_iface_.get()); - } - - virtual void TearDown() override { stopWifi(); } - - protected: - sp wifi_sta_iface_; -}; - -/* - * GetCapabilities_1_4 - */ -TEST_F(WifiStaIfaceHidlTest, GetCapabilities_1_4) { - configureChipForIfaceType(IfaceType::STA, true); - - const auto& status_and_caps = - HIDL_INVOKE(wifi_sta_iface_, getCapabilities_1_4); - if (status_and_caps.first.code != WifiStatusCode::SUCCESS) { - EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, - status_and_caps.first.code); - return; - } - EXPECT_NE(0u, status_and_caps.second); -} From 517ac2ecae25312dd3b522d103b52b2f99636747 Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Fri, 13 Dec 2019 22:03:10 +0000 Subject: [PATCH 0341/1022] Revert submission Based on Forrest run with earlier base build 6069142, the build with this submission failed apct/bluetooth/instrumentation_test Reason for revert: Break tests Change-Id: I4f59a7e3d5c5f401a260f3c8ab3457cf4e2fe386 --- graphics/composer/2.4/IComposerClient.hal | 74 ----------- .../include/composer-hal/2.4/ComposerClient.h | 18 --- .../include/composer-hal/2.4/ComposerHal.h | 5 - .../include/composer-passthrough/2.4/HwcHal.h | 59 --------- .../composer/2.4/utils/vts/ComposerVts.cpp | 19 --- .../include/composer-vts/2.4/ComposerVts.h | 7 -- .../VtsHalGraphicsComposerV2_4TargetTest.cpp | 119 ------------------ 7 files changed, 301 deletions(-) diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal index 06b4c5e53a..f23536cd2d 100644 --- a/graphics/composer/2.4/IComposerClient.hal +++ b/graphics/composer/2.4/IComposerClient.hal @@ -48,12 +48,6 @@ interface IComposerClient extends @2.3::IComposerClient { * with protected buffers. */ PROTECTED_CONTENTS = 4, - - /** - * Indicates that both the composer HAL implementation and the given display - * support a low latency mode, such as HDMI 2.1 Auto Low Latency Mode. - */ - AUTO_LOW_LATENCY_MODE = 5, }; /** @@ -70,18 +64,6 @@ interface IComposerClient extends @2.3::IComposerClient { EXTERNAL = 1, }; - enum ContentType : uint32_t { - NONE = 0, - - /** - * These modes correspond to those found in the HDMI 1.4 specification. - */ - GRAPHICS = 1, - PHOTO = 2, - CINEMA = 3, - GAME = 4, - }; - /** * Constraints for changing vsync period. */ @@ -190,60 +172,4 @@ interface IComposerClient extends @2.3::IComposerClient { setActiveConfigWithConstraints(Display display, Config config, VsyncPeriodChangeConstraints vsyncPeriodChangeConstraints) generates (Error error, VsyncPeriodChangeTimeline timeline); - - /** - * Requests the display to enable/disable its low latency mode. - * - * If the display is connected via HDMI 2.1, then Auto Low Latency Mode should be triggered. If - * the display is internally connected and a custom low latency mode is available, that should - * be triggered. - * - * This function should only be called if the display reports support for - * DisplayCapability::AUTO_LOW_LATENCY_MODE from getDisplayCapabilities_2_4. - * - * @return error is NONE upon success. Otherwise, - * BAD_DISPLAY when an invalid display handle was passed in. - * UNSUPPORTED when AUTO_LOW_LATENCY_MODE is not supported by the composer - * implementation or the given display - */ - setAutoLowLatencyMode(Display display, bool on) - generates (Error error); - - /** - * Provides a list of all the content types supported by this display (any of - * ContentType::{GRAPHICS, PHOTO, CINEMA, GAME}). This list must not change after - * initialization. - * - * Content types are introduced in HDMI 1.4 and supporting them is optional. The - * ContentType::NONE is always supported and will not be returned by this method.. - * - * @return error is NONE upon success. Otherwise, - * BAD_DISPLAY when an invalid display handle was passed in. - * @return supportedContentTypes is a list of supported content types. - */ - getSupportedContentTypes(Display display) - generates(Error error, vec supportedContentTypes); - - /** - * Instructs the connected display that the content being shown is of the given type - one of - * GRAPHICS, PHOTO, CINEMA, GAME. - * - * Content types are introduced in HDMI 1.4 and supporting them is optional. If they are - * supported, this signal should switch the display to a mode that is optimal for the given - * type of content. See HDMI 1.4 specification for more information. - * - * If the display is internally connected (not through HDMI), and such modes are available, - * this method should trigger them. - * - * This function should only be called if the display reports support for the corresponding - * content type (ContentType::{GRAPHICS, PHOTO, CINEMA, GAME}) from getSupportedContentTypes. - * ContentType::NONE is supported by default and can always be set. - * - * @return error is NONE upon success. Otherwise, - * BAD_DISPLAY when an invalid display handle was passed in. - * UNSUPPORTED when the given content type is not supported by the composer - * implementation or the given display - */ - setContentType(Display display, ContentType type) - generates (Error error); }; diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h index dcd959dfb5..4160ed97bf 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h @@ -139,24 +139,6 @@ class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImpl setAutoLowLatencyMode(Display display, bool on) override { - return mHal->setAutoLowLatencyMode(display, on); - } - - Return getSupportedContentTypes( - Display display, IComposerClient::getSupportedContentTypes_cb hidl_cb) override { - std::vector supportedContentTypes; - Error error = mHal->getSupportedContentTypes(display, &supportedContentTypes); - - hidl_cb(error, supportedContentTypes); - return Void(); - } - - Return setContentType(Display display, - IComposerClient::ContentType contentType) override { - return mHal->setContentType(display, contentType); - } - static std::unique_ptr create(Hal* hal) { auto client = std::make_unique(hal); return client->init() ? std::move(client) : nullptr; diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h index a1e56ae6ed..89dbe66d60 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h @@ -67,11 +67,6 @@ class ComposerHal : public V2_3::hal::ComposerHal { Display display, Config config, const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, VsyncPeriodChangeTimeline* timeline) = 0; - virtual Error setAutoLowLatencyMode(Display display, bool on) = 0; - virtual Error getSupportedContentTypes( - Display display, - std::vector* outSupportedContentTypes) = 0; - virtual Error setContentType(Display display, IComposerClient::ContentType contentType) = 0; }; } // namespace hal diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h index a27582a0e7..d59d0d5361 100644 --- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h +++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h @@ -167,57 +167,6 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { return Error::NONE; } - Error setAutoLowLatencyMode(Display display, bool on) override { - if (!mDispatch.setAutoLowLatencyMode) { - return Error::UNSUPPORTED; - } - - int32_t error = mDispatch.setAutoLowLatencyMode(mDevice, display, on); - if (error != HWC2_ERROR_NONE) { - return static_cast(error); - } - return Error::NONE; - } - - Error getSupportedContentTypes( - Display display, - std::vector* outSupportedContentTypes) override { - if (!mDispatch.getSupportedContentTypes) { - return Error::UNSUPPORTED; - } - - uint32_t count = 0; - int32_t error = mDispatch.getSupportedContentTypes(mDevice, display, &count, nullptr); - if (error != HWC2_ERROR_NONE) { - return static_cast(error); - } - - outSupportedContentTypes->resize(count); - - error = mDispatch.getSupportedContentTypes( - mDevice, display, &count, - reinterpret_cast::type*>( - outSupportedContentTypes->data())); - if (error != HWC2_ERROR_NONE) { - *outSupportedContentTypes = std::vector(); - return static_cast(error); - } - return Error::NONE; - } - - Error setContentType(Display display, IComposerClient::ContentType contentType) override { - if (!mDispatch.setContentType) { - return Error::UNSUPPORTED; - } - - int32_t error = - mDispatch.setContentType(mDevice, display, static_cast(contentType)); - if (error != HWC2_ERROR_NONE) { - return static_cast(error); - } - return Error::NONE; - } - protected: bool initDispatch() override { if (!BaseType2_3::initDispatch()) { @@ -230,11 +179,6 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { &mDispatch.getDisplayVsyncPeriod); this->initOptionalDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS, &mDispatch.setActiveConfigWithConstraints); - this->initOptionalDispatch(HWC2_FUNCTION_SET_AUTO_LOW_LATENCY_MODE, - &mDispatch.setAutoLowLatencyMode); - this->initOptionalDispatch(HWC2_FUNCTION_GET_SUPPORTED_CONTENT_TYPES, - &mDispatch.getSupportedContentTypes); - this->initOptionalDispatch(HWC2_FUNCTION_SET_CONTENT_TYPE, &mDispatch.setContentType); return true; } @@ -278,9 +222,6 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE getDisplayConnectionType; HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD getDisplayVsyncPeriod; HWC2_PFN_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS setActiveConfigWithConstraints; - HWC2_PFN_SET_AUTO_LOW_LATENCY_MODE setAutoLowLatencyMode; - HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES getSupportedContentTypes; - HWC2_PFN_SET_CONTENT_TYPE setContentType; } mDispatch = {}; hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr; diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp index 5b06d6d3ff..35ac23f7ff 100644 --- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp @@ -106,25 +106,6 @@ Error ComposerClient::setActiveConfigWithConstraints( return error; } -Error ComposerClient::setAutoLowLatencyMode(Display display, bool on) { - return mClient->setAutoLowLatencyMode(display, on); -} - -Error ComposerClient::getSupportedContentTypes( - Display display, std::vector* outSupportedContentTypes) { - Error error = Error::NONE; - mClient->getSupportedContentTypes( - display, [&](const auto& tmpError, const auto& tmpSupportedContentTypes) { - error = tmpError; - *outSupportedContentTypes = tmpSupportedContentTypes; - }); - return error; -} - -Error ComposerClient::setContentType(Display display, IComposerClient::ContentType contentType) { - return mClient->setContentType(display, contentType); -} - } // namespace vts } // namespace V2_4 } // namespace composer diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h index b094bc8028..83e74ed698 100644 --- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h @@ -84,13 +84,6 @@ class ComposerClient : public V2_3::vts::ComposerClient { const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, VsyncPeriodChangeTimeline* timeline); - Error setAutoLowLatencyMode(Display display, bool on); - - Error getSupportedContentTypes( - Display display, std::vector* outSupportedContentTypes); - - Error setContentType(Display display, IComposerClient::ContentType contentType); - private: const sp mClient; }; diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index 6b6f2a5b5d..f038f551e3 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -47,9 +47,6 @@ using common::V1_2::PixelFormat; using mapper::V2_0::IMapper; using mapper::V2_0::vts::Gralloc; -using ContentType = IComposerClient::ContentType; -using DisplayCapability = IComposerClient::DisplayCapability; - class GraphicsComposerHidlTest : public ::testing::TestWithParam { protected: void SetUp() override { @@ -120,11 +117,6 @@ class GraphicsComposerHidlTest : public ::testing::TestWithParam { void Test_setActiveConfigWithConstraints( const IComposerClient::VsyncPeriodChangeConstraints& constraints); - void Test_setContentType(const ContentType& contentType, const char* contentTypeStr); - void Test_setContentTypeForDisplay(const Display& display, - const std::vector& capabilities, - const ContentType& contentType, const char* contentTypeStr); - std::unique_ptr mComposer; std::unique_ptr mComposerClient; sp mComposerCallback; @@ -385,117 +377,6 @@ TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_delayed) { Test_setActiveConfigWithConstraints(constraints); } -TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyModeBadDisplay) { - EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setAutoLowLatencyMode(mInvalidDisplayId, true)); - EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setAutoLowLatencyMode(mInvalidDisplayId, false)); -} - -TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyMode) { - for (Display display : mComposerCallback->getDisplays()) { - std::vector capabilities; - const auto error = mComposerClient->getDisplayCapabilities(display, &capabilities); - EXPECT_EQ(Error::NONE, error); - - const bool allmSupport = - std::find(capabilities.begin(), capabilities.end(), - DisplayCapability::AUTO_LOW_LATENCY_MODE) != capabilities.end(); - - if (!allmSupport) { - EXPECT_EQ(Error::UNSUPPORTED, - mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, true)); - EXPECT_EQ(Error::UNSUPPORTED, - mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false)); - GTEST_SUCCEED() << "Auto Low Latency Mode is not supported on display " - << to_string(display) << ", skipping test"; - return; - } - - EXPECT_EQ(Error::NONE, mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, true)); - EXPECT_EQ(Error::NONE, mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false)); - } -} - -TEST_P(GraphicsComposerHidlTest, getSupportedContentTypesBadDisplay) { - std::vector supportedContentTypes; - const auto error = - mComposerClient->getSupportedContentTypes(mInvalidDisplayId, &supportedContentTypes); - EXPECT_EQ(Error::BAD_DISPLAY, error); -} - -TEST_P(GraphicsComposerHidlTest, getSupportedContentTypes) { - std::vector supportedContentTypes; - for (Display display : mComposerCallback->getDisplays()) { - supportedContentTypes.clear(); - const auto error = - mComposerClient->getSupportedContentTypes(display, &supportedContentTypes); - const bool noneSupported = - std::find(supportedContentTypes.begin(), supportedContentTypes.end(), - ContentType::NONE) != supportedContentTypes.end(); - EXPECT_EQ(Error::NONE, error); - EXPECT_FALSE(noneSupported); - } -} - -TEST_P(GraphicsComposerHidlTest, setContentTypeNoneAlwaysAccepted) { - for (Display display : mComposerCallback->getDisplays()) { - const auto error = mComposerClient->setContentType(display, ContentType::NONE); - EXPECT_NE(Error::UNSUPPORTED, error); - } -} - -TEST_P(GraphicsComposerHidlTest, setContentTypeBadDisplay) { - const auto types = {ContentType::NONE, ContentType::GRAPHICS, ContentType::PHOTO, - ContentType::CINEMA, ContentType::GAME}; - for (auto type : types) { - EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setContentType(mInvalidDisplayId, type)); - } -} - -void GraphicsComposerHidlTest::Test_setContentTypeForDisplay( - const Display& display, const std::vector& capabilities, - const ContentType& contentType, const char* contentTypeStr) { - const bool contentTypeSupport = - std::find(capabilities.begin(), capabilities.end(), contentType) != capabilities.end(); - - if (!contentTypeSupport) { - EXPECT_EQ(Error::UNSUPPORTED, mComposerClient->setContentType(display, contentType)); - GTEST_SUCCEED() << contentTypeStr << " content type is not supported on display " - << to_string(display) << ", skipping test"; - return; - } - - EXPECT_EQ(Error::NONE, mComposerClient->setContentType(display, contentType)); - EXPECT_EQ(Error::NONE, mComposerClient->setContentType(display, ContentType::NONE)); -} - -void GraphicsComposerHidlTest::Test_setContentType(const ContentType& contentType, - const char* contentTypeStr) { - for (Display display : mComposerCallback->getDisplays()) { - std::vector supportedContentTypes; - const auto error = - mComposerClient->getSupportedContentTypes(display, &supportedContentTypes); - EXPECT_EQ(Error::NONE, error); - - Test_setContentTypeForDisplay(display, supportedContentTypes, contentType, contentTypeStr); - } -} - -TEST_P(GraphicsComposerHidlTest, setGraphicsContentType) { - Test_setContentType(ContentType::GRAPHICS, "GRAPHICS"); -} - -TEST_P(GraphicsComposerHidlTest, setPhotoContentType) { - Test_setContentType(ContentType::PHOTO, "PHOTO"); -} - -TEST_P(GraphicsComposerHidlTest, setCinemaContentType) { - Test_setContentType(ContentType::CINEMA, "CINEMA"); -} - -TEST_P(GraphicsComposerHidlTest, setGameContentType) { - Test_setContentType(ContentType::GAME, "GAME"); -} - INSTANTIATE_TEST_SUITE_P( PerInstance, GraphicsComposerHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), From 755bad2ce632f300ae7ef7c266d67efefc3c496d Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 13 Dec 2019 14:22:46 -0800 Subject: [PATCH 0342/1022] wifi adapter cleanspec hidl-gen -L c++-adapter-main doesn't create a proper depfile or have other dependencies listed, and so the intermediates aren't getting updated. This only causes compilation problems when an interface is removed, but may break tests when interfaces are added. Fixes: 146227852 Test: reproduce error and use cleanspec to fix it Change-Id: Ia2c5c30355eb2da9abbf32a9a000f41c3b4461b8 --- CleanSpec.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/CleanSpec.mk b/CleanSpec.mk index 76594fb448..1eca2a1c21 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -84,3 +84,4 @@ $(call add-clean-step, rm -f $(PRODUCT_OUT)/etc/init/android.hardware.audio@2.0- $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.cas@1.1*) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.cas@1.1*) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/vintf/manifest/android.hardware.cas@1.1*) +$(call add-clean-step, rm -rf $(OUT_DIR)/soong/.intermediates/hardware/interfaces/wifi/1.4/android.hardware.wifi@1.4-adapter_genc++/) From d53513312751f509d0c4f8944b1ae1d24e18660c Mon Sep 17 00:00:00 2001 From: Pawin Vongmasa Date: Tue, 12 Nov 2019 19:33:23 -0800 Subject: [PATCH 0343/1022] Add AIDL type for HardwareBuffer This includes other types needed by HardwareBuffer. Test: Builds Bug: 145839204 Change-Id: I86c9d2f0cb04b597da9a93b7b6210b041312e1ac --- common/aidl/Android.bp | 21 + .../android/hardware/common/NativeHandle.aidl | 26 + graphics/common/aidl/Android.bp | 3 + .../hardware/graphics/common/BufferUsage.aidl | 114 ++++ .../graphics/common/HardwareBuffer.aidl | 32 ++ .../common/HardwareBufferDescription.aidl | 35 ++ .../hardware/graphics/common/PixelFormat.aidl | 516 ++++++++++++++++++ 7 files changed, 747 insertions(+) create mode 100644 common/aidl/Android.bp create mode 100644 common/aidl/android/hardware/common/NativeHandle.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp new file mode 100644 index 0000000000..6f2d292930 --- /dev/null +++ b/common/aidl/Android.bp @@ -0,0 +1,21 @@ +aidl_interface { + name: "vintf-common", + host_supported: true, + vendor_available: true, + vndk: { + enabled: true, + support_system_process: true, + }, + srcs: [ + "android/hardware/common/*.aidl", + ], + stability: "vintf", + backend: { + java: { + enabled: false, + }, + cpp: { + enabled: false, + }, + }, +} diff --git a/common/aidl/android/hardware/common/NativeHandle.aidl b/common/aidl/android/hardware/common/NativeHandle.aidl new file mode 100644 index 0000000000..2c250a2ac1 --- /dev/null +++ b/common/aidl/android/hardware/common/NativeHandle.aidl @@ -0,0 +1,26 @@ +/* + * Copyright 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. + */ + +package android.hardware.common; + +/** + * Representation of a native handle. + */ +@VintfStability +parcelable NativeHandle { + ParcelFileDescriptor[] fds; + int[] ints; +} diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp index e0c7674bba..fcd4efc68e 100644 --- a/graphics/common/aidl/Android.bp +++ b/graphics/common/aidl/Android.bp @@ -10,6 +10,9 @@ aidl_interface { "android/hardware/graphics/common/*.aidl", ], stability: "vintf", + imports: [ + "vintf-common" + ], backend: { java: { enabled: false, diff --git a/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl b/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl new file mode 100644 index 0000000000..5f9888a854 --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl @@ -0,0 +1,114 @@ +/* + * Copyright 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. + */ + +package android.hardware.graphics.common; + +/** + * Buffer usage definitions. + */ +@VintfStability +@Backing(type="long") +enum BufferUsage { + /** bit 0-3 is an enum */ + CPU_READ_MASK = 0xf, + /** buffer is never read by CPU */ + CPU_READ_NEVER = 0, + /** buffer is rarely read by CPU */ + CPU_READ_RARELY = 2, + /** buffer is often read by CPU */ + CPU_READ_OFTEN = 3, + + /** bit 4-7 is an enum */ + CPU_WRITE_MASK = 0xf << 4, + /** buffer is never written by CPU */ + CPU_WRITE_NEVER = 0 << 4, + /** buffer is rarely written by CPU */ + CPU_WRITE_RARELY = 2 << 4, + /** buffer is often written by CPU */ + CPU_WRITE_OFTEN = 3 << 4, + + /** buffer is used as a GPU texture */ + GPU_TEXTURE = 1 << 8, + + /** buffer is used as a GPU render target */ + GPU_RENDER_TARGET = 1 << 9, + + /** bit 10 must be zero */ + + /** buffer is used as a composer HAL overlay layer */ + COMPOSER_OVERLAY = 1 << 11, + /** buffer is used as a composer HAL client target */ + COMPOSER_CLIENT_TARGET = 1 << 12, + + /** bit 13 must be zero */ + + /** + * Buffer is allocated with hardware-level protection against copying the + * contents (or information derived from the contents) into unprotected + * memory. + */ + PROTECTED = 1 << 14, + + /** buffer is used as a hwcomposer HAL cursor layer */ + COMPOSER_CURSOR = 1 << 15, + + /** buffer is used as a video encoder input */ + VIDEO_ENCODER = 1 << 16, + + /** buffer is used as a camera HAL output */ + CAMERA_OUTPUT = 1 << 17, + + /** buffer is used as a camera HAL input */ + CAMERA_INPUT = 1 << 18, + + /** bit 19 must be zero */ + + /** buffer is used as a renderscript allocation */ + RENDERSCRIPT = 1 << 20, + + /** bit 21 must be zero */ + + /** buffer is used as a video decoder output */ + VIDEO_DECODER = 1 << 22, + + /** buffer is used as a sensor direct report output */ + SENSOR_DIRECT_DATA = 1 << 23, + + /** buffer is used as a cube map texture */ + GPU_CUBE_MAP = 1 << 25, + + /** buffer contains a complete mipmap hierarchy */ + GPU_MIPMAP_COMPLETE = 1 << 26, + + /** + * Buffer is used as input for HEIC encoder. + */ + HW_IMAGE_ENCODER = 1 << 27, + + /** + * buffer is used as as an OpenGL shader storage or uniform + * buffer object + */ + GPU_DATA_BUFFER = 1 << 24, + + /** bits 25-27 must be zero and are reserved for future versions */ + /** bits 28-31 are reserved for vendor extensions */ + VENDOR_MASK = 0xf << 28, + + /** bits 32-47 must be zero and are reserved for future versions */ + /** bits 48-63 are reserved for vendor extensions */ + VENDOR_MASK_HI = 0xffff << 48, +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl b/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl new file mode 100644 index 0000000000..5a22c0f8d4 --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl @@ -0,0 +1,32 @@ +/* + * Copyright 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. + */ + +package android.hardware.graphics.common; + +import android.hardware.common.NativeHandle; +import android.hardware.graphics.common.HardwareBufferDescription; + +/** + * Stable AIDL counterpart of AHardwareBuffer. + * + * @note This is different from the public HardwareBuffer. + * @sa +ndk libnativewindow#AHardwareBuffer + */ +@VintfStability +parcelable HardwareBuffer { + HardwareBufferDescription description; + NativeHandle handle; +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl b/graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl new file mode 100644 index 0000000000..e1e3492376 --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl @@ -0,0 +1,35 @@ +/* + * Copyright 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. + */ + +package android.hardware.graphics.common; + +import android.hardware.graphics.common.BufferUsage; +import android.hardware.graphics.common.PixelFormat; + +/** + * Stable AIDL counterpart of AHardwareBuffer_Desc. + * + * @sa +ndk libnativewindow#AHardwareBuffer_Desc + */ +@VintfStability +parcelable HardwareBufferDescription { + int width; + int height; + int layers; + PixelFormat format; + BufferUsage usage; + int stride; +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl new file mode 100644 index 0000000000..49424622c2 --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl @@ -0,0 +1,516 @@ +/* + * Copyright 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. + */ + +package android.hardware.graphics.common; + +/** + * Pixel formats for graphics buffers. + */ +@VintfStability +@Backing(type="int") +enum PixelFormat { + /** + * This value may be used in an operation where the format is optional. + */ + UNSPECIFIED = 0, + /** + * 32-bit format that has 8-bit R, G, B, and A components, in that order, + * from the lowest memory address to the highest memory address. + * + * The component values are unsigned normalized to the range [0, 1], whose + * interpretation is defined by the dataspace. + */ + RGBA_8888 = 0x1, + + /** + * 32-bit format that has 8-bit R, G, B, and unused components, in that + * order, from the lowest memory address to the highest memory address. + * + * The component values are unsigned normalized to the range [0, 1], whose + * interpretation is defined by the dataspace. + */ + RGBX_8888 = 0x2, + + /** + * 24-bit format that has 8-bit R, G, and B components, in that order, + * from the lowest memory address to the highest memory address. + * + * The component values are unsigned normalized to the range [0, 1], whose + * interpretation is defined by the dataspace. + */ + RGB_888 = 0x3, + + /** + * 16-bit packed format that has 5-bit R, 6-bit G, and 5-bit B components, + * in that order, from the most-sigfinicant bits to the least-significant + * bits. + * + * The component values are unsigned normalized to the range [0, 1], whose + * interpretation is defined by the dataspace. + */ + RGB_565 = 0x4, + + /** + * 32-bit format that has 8-bit B, G, R, and A components, in that order, + * from the lowest memory address to the highest memory address. + * + * The component values are unsigned normalized to the range [0, 1], whose + * interpretation is defined by the dataspace. + */ + BGRA_8888 = 0x5, + + /** + * Legacy formats deprecated in favor of YCBCR_420_888. + */ + YCBCR_422_SP = 0x10, // NV16 + YCRCB_420_SP = 0x11, // NV21 + YCBCR_422_I = 0x14, // YUY2 + + /** + * 64-bit format that has 16-bit R, G, B, and A components, in that order, + * from the lowest memory address to the highest memory address. + * + * The component values are signed floats, whose interpretation is defined + * by the dataspace. + */ + RGBA_FP16 = 0x16, + + /** + * RAW16 is a single-channel, 16-bit, little endian format, typically + * representing raw Bayer-pattern images from an image sensor, with minimal + * processing. + * + * The exact pixel layout of the data in the buffer is sensor-dependent, and + * needs to be queried from the camera device. + * + * Generally, not all 16 bits are used; more common values are 10 or 12 + * bits. If not all bits are used, the lower-order bits are filled first. + * All parameters to interpret the raw data (black and white points, + * color space, etc) must be queried from the camera device. + * + * This format assumes + * - an even width + * - an even height + * - a horizontal stride multiple of 16 pixels + * - a vertical stride equal to the height + * - strides are specified in pixels, not in bytes + * + * size = stride * height * 2 + * + * This format must be accepted by the allocator when used with the + * following usage flags: + * + * - BufferUsage::CAMERA_* + * - BufferUsage::CPU_* + * - BufferUsage::RENDERSCRIPT + * + * The mapping of the dataspace to buffer contents for RAW16 is as + * follows: + * + * Dataspace value | Buffer contents + * -------------------------------+----------------------------------------- + * Dataspace::ARBITRARY | Raw image sensor data, layout is as + * | defined above. + * Dataspace::DEPTH | Unprocessed implementation-dependent raw + * | depth measurements, opaque with 16 bit + * | samples. + * Other | Unsupported + */ + RAW16 = 0x20, + + /** + * BLOB is used to carry task-specific data which does not have a standard + * image structure. The details of the format are left to the two + * endpoints. + * + * A typical use case is for transporting JPEG-compressed images from the + * Camera HAL to the framework or to applications. + * + * Buffers of this format must have a height of 1, and width equal to their + * size in bytes. + * + * The mapping of the dataspace to buffer contents for BLOB is as + * follows: + * + * Dataspace value | Buffer contents + * -------------------------------+----------------------------------------- + * Dataspace::JFIF | An encoded JPEG image + * Dataspace::DEPTH | An android_depth_points buffer + * Dataspace::SENSOR | Sensor event data. + * Other | Unsupported + */ + BLOB = 0x21, + + /** + * A format indicating that the choice of format is entirely up to the + * allocator. + * + * The allocator should examine the usage bits passed in when allocating a + * buffer with this format, and it should derive the pixel format from + * those usage flags. This format must never be used with any of the + * BufferUsage::CPU_* usage flags. + * + * Even when the internally chosen format has an alpha component, the + * clients must assume the alpha vlaue to be 1.0. + * + * The interpretation of the component values is defined by the dataspace. + */ + IMPLEMENTATION_DEFINED = 0x22, + + /** + * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:0 + * buffer layout, while still describing the general format in a + * layout-independent manner. While called YCbCr, it can be used to + * describe formats with either chromatic ordering, as well as + * whole planar or semiplanar layouts. + * + * This format must be accepted by the allocator when BufferUsage::CPU_* + * are set. + * + * Buffers with this format must be locked with IMapper::lockYCbCr. + * Locking with IMapper::lock must return an error. + * + * The interpretation of the component values is defined by the dataspace. + */ + YCBCR_420_888 = 0x23, + + /** + * RAW_OPAQUE is a format for unprocessed raw image buffers coming from an + * image sensor. The actual structure of buffers of this format is + * implementation-dependent. + * + * This format must be accepted by the allocator when used with the + * following usage flags: + * + * - BufferUsage::CAMERA_* + * - BufferUsage::CPU_* + * - BufferUsage::RENDERSCRIPT + * + * The mapping of the dataspace to buffer contents for RAW_OPAQUE is as + * follows: + * + * Dataspace value | Buffer contents + * -------------------------------+----------------------------------------- + * Dataspace::ARBITRARY | Raw image sensor data. + * Other | Unsupported + */ + RAW_OPAQUE = 0x24, + + /** + * RAW10 is a single-channel, 10-bit per pixel, densely packed in each row, + * unprocessed format, usually representing raw Bayer-pattern images coming from + * an image sensor. + * + * In an image buffer with this format, starting from the first pixel of each + * row, each 4 consecutive pixels are packed into 5 bytes (40 bits). Each one + * of the first 4 bytes contains the top 8 bits of each pixel, The fifth byte + * contains the 2 least significant bits of the 4 pixels, the exact layout data + * for each 4 consecutive pixels is illustrated below (Pi[j] stands for the jth + * bit of the ith pixel): + * + * bit 7 bit 0 + * =====|=====|=====|=====|=====|=====|=====|=====| + * Byte 0: |P0[9]|P0[8]|P0[7]|P0[6]|P0[5]|P0[4]|P0[3]|P0[2]| + * |-----|-----|-----|-----|-----|-----|-----|-----| + * Byte 1: |P1[9]|P1[8]|P1[7]|P1[6]|P1[5]|P1[4]|P1[3]|P1[2]| + * |-----|-----|-----|-----|-----|-----|-----|-----| + * Byte 2: |P2[9]|P2[8]|P2[7]|P2[6]|P2[5]|P2[4]|P2[3]|P2[2]| + * |-----|-----|-----|-----|-----|-----|-----|-----| + * Byte 3: |P3[9]|P3[8]|P3[7]|P3[6]|P3[5]|P3[4]|P3[3]|P3[2]| + * |-----|-----|-----|-----|-----|-----|-----|-----| + * Byte 4: |P3[1]|P3[0]|P2[1]|P2[0]|P1[1]|P1[0]|P0[1]|P0[0]| + * =============================================== + * + * This format assumes + * - a width multiple of 4 pixels + * - an even height + * - a vertical stride equal to the height + * - strides are specified in bytes, not in pixels + * + * size = stride * height + * + * When stride is equal to width * (10 / 8), there will be no padding bytes at + * the end of each row, the entire image data is densely packed. When stride is + * larger than width * (10 / 8), padding bytes will be present at the end of each + * row (including the last row). + * + * This format must be accepted by the allocator when used with the + * following usage flags: + * + * - BufferUsage::CAMERA_* + * - BufferUsage::CPU_* + * - BufferUsage::RENDERSCRIPT + * + * The mapping of the dataspace to buffer contents for RAW10 is as + * follows: + * + * Dataspace value | Buffer contents + * -------------------------------+----------------------------------------- + * Dataspace::ARBITRARY | Raw image sensor data. + * Other | Unsupported + */ + RAW10 = 0x25, + + /** + * RAW12 is a single-channel, 12-bit per pixel, densely packed in each row, + * unprocessed format, usually representing raw Bayer-pattern images coming from + * an image sensor. + * + * In an image buffer with this format, starting from the first pixel of each + * row, each two consecutive pixels are packed into 3 bytes (24 bits). The first + * and second byte contains the top 8 bits of first and second pixel. The third + * byte contains the 4 least significant bits of the two pixels, the exact layout + * data for each two consecutive pixels is illustrated below (Pi[j] stands for + * the jth bit of the ith pixel): + * + * bit 7 bit 0 + * ======|======|======|======|======|======|======|======| + * Byte 0: |P0[11]|P0[10]|P0[ 9]|P0[ 8]|P0[ 7]|P0[ 6]|P0[ 5]|P0[ 4]| + * |------|------|------|------|------|------|------|------| + * Byte 1: |P1[11]|P1[10]|P1[ 9]|P1[ 8]|P1[ 7]|P1[ 6]|P1[ 5]|P1[ 4]| + * |------|------|------|------|------|------|------|------| + * Byte 2: |P1[ 3]|P1[ 2]|P1[ 1]|P1[ 0]|P0[ 3]|P0[ 2]|P0[ 1]|P0[ 0]| + * ======================================================= + * + * This format assumes: + * - a width multiple of 4 pixels + * - an even height + * - a vertical stride equal to the height + * - strides are specified in bytes, not in pixels + * + * size = stride * height + * + * When stride is equal to width * (12 / 8), there will be no padding bytes at + * the end of each row, the entire image data is densely packed. When stride is + * larger than width * (12 / 8), padding bytes will be present at the end of + * each row (including the last row). + * + * This format must be accepted by the allocator when used with the + * following usage flags: + * + * - BufferUsage::CAMERA_* + * - BufferUsage::CPU_* + * - BufferUsage::RENDERSCRIPT + * + * The mapping of the dataspace to buffer contents for RAW12 is as + * follows: + * + * Dataspace value | Buffer contents + * -------------------------------+----------------------------------------- + * Dataspace::ARBITRARY | Raw image sensor data. + * Other | Unsupported + */ + RAW12 = 0x26, + + /** 0x27 to 0x2A are reserved for flexible formats */ + + /** + * 32-bit packed format that has 2-bit A, 10-bit B, G, and R components, + * in that order, from the most-sigfinicant bits to the least-significant + * bits. + * + * The component values are unsigned normalized to the range [0, 1], whose + * interpretation is defined by the dataspace. + */ + RGBA_1010102 = 0x2B, + + /** + * 0x100 - 0x1FF + * + * This range is reserved for vendor extensions. Formats in this range + * must support BufferUsage::GPU_TEXTURE. Clients must assume they do not + * have an alpha component. + */ + + /** + * Y8 is a YUV planar format comprised of a WxH Y plane, with each pixel + * being represented by 8 bits. It is equivalent to just the Y plane from + * YV12. + * + * This format assumes + * - an even width + * - an even height + * - a horizontal stride multiple of 16 pixels + * - a vertical stride equal to the height + * + * size = stride * height + * + * This format must be accepted by the allocator when used with the + * following usage flags: + * + * - BufferUsage::CAMERA_* + * - BufferUsage::CPU_* + * + * The component values are unsigned normalized to the range [0, 1], whose + * interpretation is defined by the dataspace. + */ + Y8 = 0x20203859, + + /** + * Y16 is a YUV planar format comprised of a WxH Y plane, with each pixel + * being represented by 16 bits. It is just like Y8, but has double the + * bits per pixel (little endian). + * + * This format assumes + * - an even width + * - an even height + * - a horizontal stride multiple of 16 pixels + * - a vertical stride equal to the height + * - strides are specified in pixels, not in bytes + * + * size = stride * height * 2 + * + * This format must be accepted by the allocator when used with the + * following usage flags: + * + * - BufferUsage::CAMERA_* + * - BufferUsage::CPU_* + * + * The component values are unsigned normalized to the range [0, 1], whose + * interpretation is defined by the dataspace. When the dataspace is + * Dataspace::DEPTH, each pixel is a distance value measured by a depth + * camera, plus an associated confidence value. + */ + Y16 = 0x20363159, + + /** + * YV12 is a 4:2:0 YCrCb planar format comprised of a WxH Y plane followed + * by (W/2) x (H/2) Cr and Cb planes. + * + * This format assumes + * - an even width + * - an even height + * - a horizontal stride multiple of 16 pixels + * - a vertical stride equal to the height + * + * y_size = stride * height + * c_stride = ALIGN(stride/2, 16) + * c_size = c_stride * height/2 + * size = y_size + c_size * 2 + * cr_offset = y_size + * cb_offset = y_size + c_size + * + * This range is reserved for vendor extensions. Formats in this range + * must support BufferUsage::GPU_TEXTURE. Clients must assume they do not + * have an alpha component. + * + * This format must be accepted by the allocator when used with the + * following usage flags: + * + * - BufferUsage::CAMERA_* + * - BufferUsage::CPU_* + * - BufferUsage::GPU_TEXTURE + * + * The component values are unsigned normalized to the range [0, 1], whose + * interpretation is defined by the dataspace. + */ + YV12 = 0x32315659, // YCrCb 4:2:0 Planar + + /** + * 16-bit format that has a single 16-bit depth component. + * + * The component values are unsigned normalized to the range [0, 1], whose + * interpretation is defined by the dataspace. + */ + DEPTH_16 = 0x30, + + /** + * 32-bit format that has a single 24-bit depth component and, optionally, + * 8 bits that are unused. + * + * The component values are unsigned normalized to the range [0, 1], whose + * interpretation is defined by the dataspace. + */ + DEPTH_24 = 0x31, + + /** + * 32-bit format that has a 24-bit depth component and an 8-bit stencil + * component packed into 32-bits. + * + * The depth component values are unsigned normalized to the range [0, 1], + * whose interpretation is defined by the dataspace. The stencil values are + * unsigned integers, whose interpretation is defined by the dataspace. + */ + DEPTH_24_STENCIL_8 = 0x32, + + /** + * 32-bit format that has a single 32-bit depth component. + * + * The component values are signed floats, whose interpretation is defined + * by the dataspace. + */ + DEPTH_32F = 0x33, + + /** + * Two-component format that has a 32-bit depth component, an 8-bit stencil + * component, and optionally 24-bits unused. + * + * The depth component values are signed floats, whose interpretation is + * defined by the dataspace. The stencil bits are unsigned integers, whose + * interpretation is defined by the dataspace. + */ + DEPTH_32F_STENCIL_8 = 0x34, + + /** + * 8-bit format that has a single 8-bit stencil component. + * + * The component values are unsigned integers, whose interpretation is + * defined by the dataspace. + */ + STENCIL_8 = 0x35, + + /** + * P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane + * followed immediately by a Wx(H/2) CbCr plane. Each sample is + * represented by a 16-bit little-endian value, with the lower 6 bits set + * to zero. + * + * This format assumes + * - an even height + * - a vertical stride equal to the height + * + * stride_in_bytes = stride * 2 + * y_size = stride_in_bytes * height + * cbcr_size = stride_in_bytes * (height / 2) + * cb_offset = y_size + * cr_offset = cb_offset + 2 + * + * This format must be accepted by the allocator when used with the + * following usage flags: + * + * - BufferUsage::VIDEO_* + * - BufferUsage::CPU_* + * - BufferUsage::GPU_TEXTURE + * + * The component values are unsigned normalized to the range [0, 1], whose + * interpretation is defined by the dataspace. + * + * This format is appropriate for 10bit video content. + * + * Buffers with this format must be locked with IMapper::lockYCbCr + * or with IMapper::lock. + */ + YCBCR_P010 = 0x36, + + /** + * 24-bit format that has 8-bit H, S, and V components, in that order, + * from the lowest memory address to the highest memory address. + * + * The component values are unsigned normalized to the range [0, 1], whose + * interpretation is defined by the dataspace. + */ + HSV_888 = 0x37, +} From c1c257bc9d2b949f3460d0ca7c001b2cd260ae7e Mon Sep 17 00:00:00 2001 From: Sasha Kuznetsov Date: Fri, 13 Dec 2019 13:08:16 -0800 Subject: [PATCH 0344/1022] Implement some methods in 2.1 default implementation Test: atest VtsHalGnssV2_0TargetTest builds and runs Bug: 146216289 Change-Id: I8b024bff5b04b97298813293e39ee865eaf389b4 --- gnss/2.1/default/Gnss.cpp | 44 ++++++++++++++++++++++++++++++++------- gnss/2.1/default/Gnss.h | 1 + 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp index 384fd49cf6..fd7a9dfd0d 100644 --- a/gnss/2.1/default/Gnss.cpp +++ b/gnss/2.1/default/Gnss.cpp @@ -31,6 +31,7 @@ namespace V2_1 { namespace implementation { sp Gnss::sGnssCallback_2_1 = nullptr; +sp Gnss::sGnssCallback_2_0 = nullptr; Gnss::Gnss() : mMinIntervalMs(1000), mGnssConfiguration{new GnssConfiguration()} {} @@ -190,14 +191,42 @@ Return Gnss::injectBestLocation(const V1_0::GnssLocation&) { } // Methods from V2_0::IGnss follow. -Return Gnss::setCallback_2_0(const sp&) { - // TODO implement - return bool{}; +Return Gnss::setCallback_2_0(const sp& callback) { + ALOGD("Gnss::setCallback_2_0"); + if (callback == nullptr) { + ALOGE("%s: Null callback ignored", __func__); + return false; + } + + sGnssCallback_2_0 = callback; + + using Capabilities = V2_0::IGnssCallback::Capabilities; + const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS | + Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST; + auto ret = sGnssCallback_2_0->gnssSetCapabilitiesCb_2_0(capabilities); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2019}; + + ret = sGnssCallback_2_0->gnssSetSystemInfoCb(gnssInfo); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + auto gnssName = "Google Mock GNSS Implementation v2.0"; + ret = sGnssCallback_2_0->gnssNameCb(gnssName); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + return true; } Return> Gnss::getExtensionGnssConfiguration_2_0() { - // TODO implement - return ::android::sp{}; + ALOGD("Gnss::getExtensionGnssConfiguration_2_0"); + return mGnssConfiguration; } Return> Gnss::getExtensionGnssDebug_2_0() { @@ -216,8 +245,8 @@ Return> Gnss::getExtensionAGnssRil_2_0() { } Return> Gnss::getExtensionGnssMeasurement_2_0() { - // TODO implement - return ::android::sp{}; + ALOGD("Gnss::getExtensionGnssMeasurement_2_0"); + return new GnssMeasurement(); } Return> @@ -281,6 +310,7 @@ Return> Gnss::getExtensionGnssMeasurement_2_1() { } Return> Gnss::getExtensionGnssConfiguration_2_1() { + ALOGD("Gnss::getExtensionGnssConfiguration_2_1"); return mGnssConfiguration; } diff --git a/gnss/2.1/default/Gnss.h b/gnss/2.1/default/Gnss.h index 674b070d99..7917bbd6a2 100644 --- a/gnss/2.1/default/Gnss.h +++ b/gnss/2.1/default/Gnss.h @@ -95,6 +95,7 @@ struct Gnss : public IGnss { void reportSvStatus(const hidl_vec&) const; static sp sGnssCallback_2_1; + static sp sGnssCallback_2_0; std::atomic mMinIntervalMs; sp mGnssConfiguration; std::atomic mIsActive; From 6c070ca4e89c4d5d044153d05bc53f9339b36f3c Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Wed, 11 Dec 2019 12:36:26 -0800 Subject: [PATCH 0345/1022] audio: Add IDevice::updateAudioPatch method Add method 'updateAudioPatch' which should be used when an existing patch needs to be updated with new routing. Use of this method allows audio HAL to avoid disrupting audio stream while changing routing. Bug: 79248321 Test: atest VtsHalAudioV6_0TargetTest Change-Id: I6c87f67fa4f2463ba9e8f0272a3232f5c9c55714 --- audio/6.0/IDevice.hal | 19 ++++++++++++ audio/core/all-versions/default/Device.cpp | 29 ++++++++++++++++--- .../all-versions/default/PrimaryDevice.cpp | 7 +++++ .../default/include/core/default/Device.h | 6 ++++ .../include/core/default/PrimaryDevice.h | 3 ++ .../6.0/AudioPrimaryHidlHalTest.cpp | 9 ++++++ current.txt | 2 +- 7 files changed, 70 insertions(+), 5 deletions(-) diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal index 2347696035..c2e310ce69 100644 --- a/audio/6.0/IDevice.hal +++ b/audio/6.0/IDevice.hal @@ -167,6 +167,25 @@ interface IDevice { createAudioPatch(vec sources, vec sinks) generates (Result retval, AudioPatchHandle patch); + /** + * Updates an audio patch. + * + * Use of this function is preferred to releasing and re-creating a patch + * as the HAL module can figure out a way of switching the route without + * causing audio disruption. + * + * @param previousPatch handle of the previous patch to update. + * @param sources new patch sources. + * @param sinks new patch sinks. + * @return retval operation completion status. + * @return patch updated patch handle. + */ + updateAudioPatch( + AudioPatchHandle previousPatch, + vec sources, + vec sinks) generates ( + Result retval, AudioPatchHandle patch); + /** * Release an audio patch. * diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp index ad841caf2e..47e31c1801 100644 --- a/audio/core/all-versions/default/Device.cpp +++ b/audio/core/all-versions/default/Device.cpp @@ -269,12 +269,21 @@ Return Device::supportsAudioPatches() { Return Device::createAudioPatch(const hidl_vec& sources, const hidl_vec& sinks, createAudioPatch_cb _hidl_cb) { + auto [retval, patch] = createOrUpdateAudioPatch( + static_cast(AudioHandleConsts::AUDIO_PATCH_HANDLE_NONE), sources, + sinks); + _hidl_cb(retval, patch); + return Void(); +} + +std::tuple Device::createOrUpdateAudioPatch( + AudioPatchHandle patch, const hidl_vec& sources, + const hidl_vec& sinks) { Result retval(Result::NOT_SUPPORTED); - AudioPatchHandle patch = 0; if (version() >= AUDIO_DEVICE_API_VERSION_3_0) { std::unique_ptr halSources(HidlUtils::audioPortConfigsToHal(sources)); std::unique_ptr halSinks(HidlUtils::audioPortConfigsToHal(sinks)); - audio_patch_handle_t halPatch = AUDIO_PATCH_HANDLE_NONE; + audio_patch_handle_t halPatch = static_cast(patch); retval = analyzeStatus("create_audio_patch", mDevice->create_audio_patch(mDevice, sources.size(), &halSources[0], sinks.size(), &halSinks[0], &halPatch)); @@ -282,8 +291,7 @@ Return Device::createAudioPatch(const hidl_vec& sources, patch = static_cast(halPatch); } } - _hidl_cb(retval, patch); - return Void(); + return {retval, patch}; } Return Device::releaseAudioPatch(int32_t patch) { @@ -438,6 +446,19 @@ Return Device::removeDeviceEffect(AudioPortHandle device, uint64_t effec } } +Return Device::updateAudioPatch(int32_t previousPatch, + const hidl_vec& sources, + const hidl_vec& sinks, + createAudioPatch_cb _hidl_cb) { + if (previousPatch != static_cast(AudioHandleConsts::AUDIO_PATCH_HANDLE_NONE)) { + auto [retval, patch] = createOrUpdateAudioPatch(previousPatch, sources, sinks); + _hidl_cb(retval, patch); + } else { + _hidl_cb(Result::INVALID_ARGUMENTS, previousPatch); + } + return Void(); +} + #endif } // namespace implementation diff --git a/audio/core/all-versions/default/PrimaryDevice.cpp b/audio/core/all-versions/default/PrimaryDevice.cpp index 0f1aba0f2f..679f85dad3 100644 --- a/audio/core/all-versions/default/PrimaryDevice.cpp +++ b/audio/core/all-versions/default/PrimaryDevice.cpp @@ -176,6 +176,13 @@ Return PrimaryDevice::addDeviceEffect(AudioPortHandle device, uint64_t e Return PrimaryDevice::removeDeviceEffect(AudioPortHandle device, uint64_t effectId) { return mDevice->removeDeviceEffect(device, effectId); } + +Return PrimaryDevice::updateAudioPatch(int32_t previousPatch, + const hidl_vec& sources, + const hidl_vec& sinks, + updateAudioPatch_cb _hidl_cb) { + return mDevice->updateAudioPatch(previousPatch, sources, sinks, _hidl_cb); +} #endif // Methods from ::android::hardware::audio::CPP_VERSION::IPrimaryDevice follow. diff --git a/audio/core/all-versions/default/include/core/default/Device.h b/audio/core/all-versions/default/include/core/default/Device.h index 80a9638004..b0e72d9600 100644 --- a/audio/core/all-versions/default/include/core/default/Device.h +++ b/audio/core/all-versions/default/include/core/default/Device.h @@ -118,6 +118,9 @@ struct Device : public IDevice, public ParametersUtil { Return close() override; Return addDeviceEffect(AudioPortHandle device, uint64_t effectId) override; Return removeDeviceEffect(AudioPortHandle device, uint64_t effectId) override; + Return updateAudioPatch(int32_t previousPatch, const hidl_vec& sources, + const hidl_vec& sinks, + createAudioPatch_cb _hidl_cb) override; #endif Return debug(const hidl_handle& fd, const hidl_vec& options) override; @@ -136,6 +139,9 @@ struct Device : public IDevice, public ParametersUtil { virtual ~Device(); Result doClose(); + std::tuple createOrUpdateAudioPatch( + AudioPatchHandle patch, const hidl_vec& sources, + const hidl_vec& sinks); // Methods from ParametersUtil. char* halGetParameters(const char* keys) override; diff --git a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h index 9fc90c39fe..ccdb7b26c1 100644 --- a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h +++ b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h @@ -100,6 +100,9 @@ struct PrimaryDevice : public IPrimaryDevice { Return close() override; Return addDeviceEffect(AudioPortHandle device, uint64_t effectId) override; Return removeDeviceEffect(AudioPortHandle device, uint64_t effectId) override; + Return updateAudioPatch(int32_t previousPatch, const hidl_vec& sources, + const hidl_vec& sinks, + updateAudioPatch_cb _hidl_cb) override; #endif Return debug(const hidl_handle& fd, const hidl_vec& options) override; diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp index 2afbbb8fc4..09ef330be6 100644 --- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp @@ -181,3 +181,12 @@ TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedInputStreams) { ASSERT_OK(getDevice()->close()); ASSERT_TRUE(resetDevice()); } + +TEST_P(AudioPatchHidlTest, UpdatePatchInvalidHandle) { + doc::test("Verify that passing an invalid handle to updateAudioPatch is checked"); + AudioPatchHandle ignored; + ASSERT_OK(getDevice()->updateAudioPatch( + static_cast(AudioHandleConsts::AUDIO_PATCH_HANDLE_NONE), + hidl_vec(), hidl_vec(), returnIn(res, ignored))); + ASSERT_RESULT(Result::INVALID_ARGUMENTS, res); +} diff --git a/current.txt b/current.txt index 999b207899..1fe17d5ca4 100644 --- a/current.txt +++ b/current.txt @@ -598,7 +598,7 @@ fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardwar # HALs released in Android R e966a3437d6a98d9d9e14e9d672088771716031900c0deb55a0946c751a03a44 android.hardware.audio@6.0::types -4540d12fe1cea996f21bd1712d4ae0906dcbd58177dac494efc605b004902d43 android.hardware.audio@6.0::IDevice +dd3e9280be60a5e042331c1046d13938e2cc323dc4b267cc74d544bf62fc0314 android.hardware.audio@6.0::IDevice 2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice fd1f1b29f26b42e886220f04a08086c00e5ade9d7b53f095438e578ab9d42a93 android.hardware.audio@6.0::IStream From 6a2ecb424ce390167ded62eb937746217cdfa80e Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 12 Dec 2019 14:34:49 -0800 Subject: [PATCH 0346/1022] gralloc4: remove dumpDebugInfo dumpDebugInfo could be called by anyone. A safer approach is for processes to dump their own buffers via IMapper's dumpBuffers. Bug: 137966819 Test: Compiles Change-Id: I4c8c7a6415babfb93034ee8674ba0f40cd8c1bb8 --- graphics/allocator/4.0/IAllocator.hal | 8 -------- graphics/mapper/4.0/utils/vts/MapperVts.cpp | 7 ------- .../4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h | 2 -- .../vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp | 7 ------- 4 files changed, 24 deletions(-) diff --git a/graphics/allocator/4.0/IAllocator.hal b/graphics/allocator/4.0/IAllocator.hal index 9931685abc..7934867be9 100644 --- a/graphics/allocator/4.0/IAllocator.hal +++ b/graphics/allocator/4.0/IAllocator.hal @@ -19,14 +19,6 @@ package android.hardware.graphics.allocator@4.0; import android.hardware.graphics.mapper@4.0; interface IAllocator { - /** - * Retrieves implementation-defined debug information, which will be - * displayed during, for example, `dumpsys SurfaceFlinger`. - * - * @return debugInfo is a string of debug information. - */ - dumpDebugInfo() generates (string debugInfo); - /** * Allocates buffers with the properties specified by the descriptor. * diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp index 8a5f54ebac..cb90fa0597 100644 --- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp +++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp @@ -71,13 +71,6 @@ sp Gralloc::getAllocator() const { return mAllocator; } -std::string Gralloc::dumpDebugInfo() { - std::string debugInfo; - mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); }); - - return debugInfo; -} - const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle) { const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle()); EXPECT_NE(nullptr, bufferHandle); diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h index 1c635c402c..cd40aa4151 100644 --- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h +++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h @@ -45,8 +45,6 @@ class Gralloc { sp getAllocator() const; - std::string dumpDebugInfo(); - // When import is false, this simply calls IAllocator::allocate. When import // is true, the returned buffers are also imported into the mapper. // diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 7dc733cb98..4a0aabf1a3 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -305,13 +305,6 @@ const std::set GraphicsMapperHidlTest::sRequiredMetadataTy StandardMetadataType::BLEND_MODE, }; -/** - * Test IAllocator::dumpDebugInfo by calling it. - */ -TEST_P(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) { - mGralloc->dumpDebugInfo(); -} - /** * Test IAllocator::allocate with valid buffer descriptors. */ From f95e14d1b43f6fc708a81a4fb66443fabf9c20f5 Mon Sep 17 00:00:00 2001 From: Pawin Vongmasa Date: Mon, 9 Dec 2019 01:54:50 -0800 Subject: [PATCH 0347/1022] Add HDR metadata types to graphics/common Bug: 120990898 Bug: 141632767 Test: Builds Change-Id: I94a592d1cc0854b37622a2c85575083b59803793 --- .../hardware/graphics/common/Cta861_3.aidl | 34 ++++ .../hardware/graphics/common/Smpte2086.aidl | 51 +++++ .../graphics/common/StandardMetadataType.aidl | 39 ++++ .../hardware/graphics/common/XyColor.aidl | 30 +++ graphics/mapper/4.0/IMapper.hal | 2 +- .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 179 ++++++++++++++++++ 6 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl diff --git a/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl b/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl new file mode 100644 index 0000000000..4fbc6b2344 --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl @@ -0,0 +1,34 @@ +/** + * 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. + */ + +package android.hardware.graphics.common; + +/** + * HDR static metadata extension as specified by CTA-861.3. + * + * This is an AIDL counterpart of the NDK struct `AHdrMetadata_cta861_3`. + */ +@VintfStability +parcelable Cta861_3 { + /** + * Maximum content light level. + */ + float maxContentLightLevel; + /** + * Maximum frame average light level. + */ + float maxFrameAverageLightLevel; +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl b/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl new file mode 100644 index 0000000000..60614cd9bb --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl @@ -0,0 +1,51 @@ +/** + * 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. + */ + +package android.hardware.graphics.common; +import android.hardware.graphics.common.XyColor; + +/** + * Mastering display metadata as specified by SMPTE ST 2086. + * + * This is an AIDL counterpart of the NDK struct `AHdrMetadata_smpte2086`. + */ +@VintfStability +parcelable Smpte2086 { + /** + * CIE XYZ chromaticity for red in the RGB primaries. + */ + XyColor primaryRed; + /** + * CIE XYZ chromaticity for green in the RGB primaries. + */ + XyColor primaryGreen; + /** + * CIE XYZ chromaticity for blue in the RGB primaries. + */ + XyColor primaryBlue; + /** + * CIE XYZ chromaticity for the white point. + */ + XyColor whitePoint; + /** + * Maximum luminance in candelas per square meter. + */ + float maxLuminance; + /** + * Minimum luminance in candelas per square meter. + */ + float minLuminance; +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl index 060d12c46e..68c99ee055 100644 --- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl +++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl @@ -279,4 +279,43 @@ enum StandardMetadataType { * 4 bytes written in little endian. */ BLEND_MODE = 17, + + /** + * Can be used to get or set static HDR metadata specified by SMPTE ST 2086. + * + * This metadata is a stable aidl android.hardware.graphics.common.Smpte2086. + * + * This is not used in tone mapping until it has been set for the first time. + * + * When it is encoded into a byte stream, each float member is represented by 4 bytes written in + * little endian. The ordering of float values follows the definition of Smpte2086 and XyColor. + * If this is unset when encoded into a byte stream, the byte stream is empty. + */ + SMPTE2086 = 18, + + /** + * Can be used to get or set static HDR metadata specified by CTA 861.3. + * + * This metadata is a stable aidl android.hardware.graphics.common.Cta861_3. + * + * This is not used in tone mapping until it has been set for the first time. + * + * When it is encoded into a byte stream, each float member is represented by 4 bytes written in + * little endian. The ordering of float values follows the definition of Cta861_3. + * If this is unset when encoded into a byte stream, the byte stream is empty. + */ + CTA861_3 = 19, + + /** + * Can be used to get or set dynamic HDR metadata specified by SMPTE ST 2094-40:2016. + * + * This metadata is uint8_t byte array. + * + * This is not used in tone mapping until it has been set for the first time. + * + * When it is encoded into a byte stream, the length of the HDR metadata byte array is written + * using 8 bytes in little endian. It is followed by the uint8_t byte array. + * If this is unset when encoded into a byte stream, the byte stream is empty. + */ + SMPTE2094_40 = 20, } diff --git a/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl b/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl new file mode 100644 index 0000000000..9571273d7d --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl @@ -0,0 +1,30 @@ +/** + * 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. + */ + +package android.hardware.graphics.common; + +/** + * Chromaticity based on 2 parameters. + * + * This is an AIDL counterpart of the NDK struct `AColor_xy`. + * + * @note This can be used to represent any 2-dimensional chromaticity. + */ +@VintfStability +parcelable XyColor { + float x; + float y; +} diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal index 03dfef1e3f..3be2152971 100644 --- a/graphics/mapper/4.0/IMapper.hal +++ b/graphics/mapper/4.0/IMapper.hal @@ -478,7 +478,7 @@ interface IMapper { * particular Metadata field. * * The framework may attempt to set the following StandardMetadataType - * values: DATASPACE, PER_FRAME_METADATA, PER_FRAME_METADATA_BLOB and BLEND_MODE. + * values: DATASPACE, SMPTE2086, CTA861_3, SMPTE2094_40 and BLEND_MODE. * We strongly encourage everyone to support setting as many of those fields as * possible. If a device's Composer implementation supports a field, it should be * supported here. Over time these metadata fields will be moved out of diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 4a0aabf1a3..3b87bc261d 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -44,11 +44,13 @@ using android::hardware::graphics::common::V1_2::BufferUsage; using android::hardware::graphics::common::V1_2::PixelFormat; using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType; using aidl::android::hardware::graphics::common::BlendMode; +using aidl::android::hardware::graphics::common::Cta861_3; using aidl::android::hardware::graphics::common::Dataspace; using aidl::android::hardware::graphics::common::ExtendableType; using aidl::android::hardware::graphics::common::PlaneLayout; using aidl::android::hardware::graphics::common::PlaneLayoutComponent; using aidl::android::hardware::graphics::common::PlaneLayoutComponentType; +using aidl::android::hardware::graphics::common::Smpte2086; using aidl::android::hardware::graphics::common::StandardMetadataType; using DecodeFunction = std::function& vec) { + std::optional smpte2086; + ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086)); + EXPECT_FALSE(smpte2086.has_value()); + }); +} + +/** + * Test IMapper::get(Cta861_3) + */ +TEST_F(GraphicsMapperHidlTest, GetCta861_3) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, + [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + std::optional cta861_3; + ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3)); + EXPECT_FALSE(cta861_3.has_value()); + }); +} + +/** + * Test IMapper::get(Smpte2094_40) + */ +TEST_F(GraphicsMapperHidlTest, GetSmpte2094_40) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_40, + [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + std::optional> smpte2094_40; + ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40)); + EXPECT_FALSE(smpte2094_40.has_value()); + }); +} + /** * Test IMapper::get(metadata) with a bad buffer */ @@ -1072,6 +1110,15 @@ TEST_P(GraphicsMapperHidlTest, GetMetadataBadValue) { ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_BlendMode, &vec)); ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2086, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_Cta861_3, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2094_40, &vec)); + ASSERT_EQ(0, vec.size()); } /** @@ -1427,6 +1474,90 @@ TEST_P(GraphicsMapperHidlTest, SetBlendMode) { }); } +/** + * Test IMapper::set(Smpte2086) + */ +TEST_F(GraphicsMapperHidlTest, SetSmpte2086) { + /** + * DISPLAY_P3 is a color space that uses the DCI_P3 primaries, + * the D65 white point and the SRGB transfer functions. + * Rendering Intent: Colorimetric + * Primaries: + * x y + * green 0.265 0.690 + * blue 0.150 0.060 + * red 0.680 0.320 + * white (D65) 0.3127 0.3290 + */ + std::optional smpte2086; + smpte2086->primaryRed.x = 0.680; + smpte2086->primaryRed.y = 0.320; + smpte2086->primaryGreen.x = 0.265; + smpte2086->primaryGreen.y = 0.690; + smpte2086->primaryBlue.x = 0.150; + smpte2086->primaryBlue.y = 0.060; + smpte2086->whitePoint.x = 0.3127; + smpte2086->whitePoint.y = 0.3290; + smpte2086->maxLuminance = 100.0; + smpte2086->minLuminance = 0.1; + + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2086(smpte2086, &vec)); + + testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + std::optional realSmpte2086; + ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &realSmpte2086)); + ASSERT_TRUE(realSmpte2086.has_value()); + EXPECT_EQ(smpte2086->primaryRed.x, realSmpte2086->primaryRed.x); + EXPECT_EQ(smpte2086->primaryRed.y, realSmpte2086->primaryRed.y); + EXPECT_EQ(smpte2086->primaryGreen.x, realSmpte2086->primaryGreen.x); + EXPECT_EQ(smpte2086->primaryGreen.y, realSmpte2086->primaryGreen.y); + EXPECT_EQ(smpte2086->primaryBlue.x, realSmpte2086->primaryBlue.x); + EXPECT_EQ(smpte2086->primaryBlue.y, realSmpte2086->primaryBlue.y); + EXPECT_EQ(smpte2086->whitePoint.x, realSmpte2086->whitePoint.x); + EXPECT_EQ(smpte2086->whitePoint.y, realSmpte2086->whitePoint.y); + EXPECT_EQ(smpte2086->maxLuminance, realSmpte2086->maxLuminance); + EXPECT_EQ(smpte2086->minLuminance, realSmpte2086->minLuminance); + }); +} + +/** + * Test IMapper::set(Cta8613) + */ +TEST_F(GraphicsMapperHidlTest, SetCta861_3) { + std::optional cta861_3; + cta861_3->maxContentLightLevel = 78.0; + cta861_3->maxFrameAverageLightLevel = 62.0; + + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeCta861_3(cta861_3, &vec)); + + testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + std::optional realCta861_3; + ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &realCta861_3)); + ASSERT_TRUE(realCta861_3.has_value()); + EXPECT_EQ(cta861_3->maxContentLightLevel, realCta861_3->maxContentLightLevel); + EXPECT_EQ(cta861_3->maxFrameAverageLightLevel, + realCta861_3->maxFrameAverageLightLevel); + }); +} + +/** + * Test IMapper::set(Smpte2094_40) + */ +TEST_F(GraphicsMapperHidlTest, SetSmpte2094_40) { + hidl_vec vec; + + testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_40, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + std::optional> realSmpte2094_40; + ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &realSmpte2094_40)); + EXPECT_FALSE(realSmpte2094_40.has_value()); + }); +} + /** * Test IMapper::set(metadata) with a bad buffer */ @@ -1462,6 +1593,11 @@ TEST_P(GraphicsMapperHidlTest, SetMetadataNullBuffer) { mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec)); ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec)); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec)); + ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec)); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2094_40, vec)); } /** @@ -1521,6 +1657,10 @@ TEST_P(GraphicsMapperHidlTest, SetBadMetadata) { mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec)); ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec)); + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec)); + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec)); } /** @@ -1752,6 +1892,45 @@ TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBlendMode) { EXPECT_EQ(BlendMode::INVALID, blendMode); } +/** + * Test IMapper::getFromBufferDescriptorInfo(Smpte2086) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2086) { + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( + mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086, &vec)); + + std::optional smpte2086; + ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086)); + EXPECT_FALSE(smpte2086.has_value()); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(Cta861_3) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCta861_3) { + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( + mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, &vec)); + + std::optional cta861_3; + ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3)); + EXPECT_FALSE(cta861_3.has_value()); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(Smpte2094_40) + */ +TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2094_40) { + hidl_vec vec; + ASSERT_EQ(Error::NONE, + mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, + gralloc4::MetadataType_Smpte2094_40, &vec)); + std::optional> smpte2094_40; + ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40)); + EXPECT_FALSE(smpte2094_40.has_value()); +} + /** * Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported metadata */ From 3bc7741e914a6a1761c63bcddbcead706c45a78d Mon Sep 17 00:00:00 2001 From: Baekgyeong Kim Date: Tue, 19 Nov 2019 16:08:11 +0900 Subject: [PATCH 0348/1022] Add audio stream and usage for virtual assistant New stream type: AUDIO_STREAM_ASSISTANT This is intended to be used by a virtual assistant like Google Assistant, Bixby, etc. The audio stream has own volume alias and the volume does not change by volume changes of other streams. Bug: 123745215 Test: make Change-Id: I3696d8fba32070954cc6a330574af8507fea7a74 --- audio/6.0/config/api/current.txt | 1 + .../6.0/config/audio_policy_configuration.xsd | 1 + audio/common/6.0/types.hal | 1 + audio/effect/6.0/xml/api/current.txt | 1 + audio/effect/6.0/xml/audio_effects_conf.xsd | 231 +++++++++++++++++- current.txt | 2 +- 6 files changed, 235 insertions(+), 2 deletions(-) mode change 120000 => 100644 audio/effect/6.0/xml/audio_effects_conf.xsd diff --git a/audio/6.0/config/api/current.txt b/audio/6.0/config/api/current.txt index ddd4d1ccc6..0407d69c35 100644 --- a/audio/6.0/config/api/current.txt +++ b/audio/6.0/config/api/current.txt @@ -361,6 +361,7 @@ package audio.policy.configuration.V6_0 { method public String getRawName(); enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ACCESSIBILITY; enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ALARM; + enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ASSISTANT; enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_BLUETOOTH_SCO; enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_DTMF; enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ENFORCED_AUDIBLE; diff --git a/audio/6.0/config/audio_policy_configuration.xsd b/audio/6.0/config/audio_policy_configuration.xsd index 3fab7dc151..05c8ab46e8 100644 --- a/audio/6.0/config/audio_policy_configuration.xsd +++ b/audio/6.0/config/audio_policy_configuration.xsd @@ -551,6 +551,7 @@ + diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal index e69d9691b7..563e05d6ca 100644 --- a/audio/common/6.0/types.hal +++ b/audio/common/6.0/types.hal @@ -106,6 +106,7 @@ enum AudioStreamType : int32_t { TTS = 9, // Transmitted Through Speaker. Plays over speaker // only, silent on other devices ACCESSIBILITY = 10, // For accessibility talk back prompts + ASSISTANT = 11, // For virtual assistant service }; @export(name="audio_source_t", value_prefix="AUDIO_SOURCE_") diff --git a/audio/effect/6.0/xml/api/current.txt b/audio/effect/6.0/xml/api/current.txt index 2021639630..2dfcb9b348 100644 --- a/audio/effect/6.0/xml/api/current.txt +++ b/audio/effect/6.0/xml/api/current.txt @@ -82,6 +82,7 @@ package audio.effects.V6_0 { public enum StreamOutputType { method public String getRawName(); enum_constant public static final audio.effects.V6_0.StreamOutputType alarm; + enum_constant public static final audio.effects.V6_0.StreamOutputType assistant; enum_constant public static final audio.effects.V6_0.StreamOutputType bluetooth_sco; enum_constant public static final audio.effects.V6_0.StreamOutputType dtmf; enum_constant public static final audio.effects.V6_0.StreamOutputType enforced_audible; diff --git a/audio/effect/6.0/xml/audio_effects_conf.xsd b/audio/effect/6.0/xml/audio_effects_conf.xsd deleted file mode 120000 index 9d85fa7c68..0000000000 --- a/audio/effect/6.0/xml/audio_effects_conf.xsd +++ /dev/null @@ -1 +0,0 @@ -../../2.0/xml/audio_effects_conf.xsd \ No newline at end of file diff --git a/audio/effect/6.0/xml/audio_effects_conf.xsd b/audio/effect/6.0/xml/audio_effects_conf.xsd new file mode 100644 index 0000000000..a7ff20bb1c --- /dev/null +++ b/audio/effect/6.0/xml/audio_effects_conf.xsd @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + List of effect libraries to load. Each library element must have "name" and + "path" attributes. The latter is giving the path of the library .so file + relative to the standard effect folders: /(vendor|odm|system)/lib(64)?/soundfx/ + Example for a library in "/vendor/lib/soundfx/lib.so": + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + List of effects to load. Each effect element must contain "name", + "library", and "uuid" attrs. The value of the "library" attr must + correspond to the name of a "library" element. The name of the effect + element is indicative, only the value of the "uuid" element designates + the effect for the audio framework. The uuid is the implementation + specific UUID as specified by the effect vendor. This is not the generic + effect type UUID. + For effect proxy implementations, SW and HW implemetations of the effect + can be specified. + Example: + + + + + + + + + + + + + + + + + + + + + + + + + Audio preprocessing configuration. The processing configuration consists + of a list of elements each describing processing settings for a given + input stream. Valid input stream types are listed in "streamInputType". + Each stream element contains a list of "apply" elements. The value of the + "effect" attr must correspond to the name of an "effect" element. + Example: + + + + + + + + + + + + + + + + Audio postprocessing configuration. The processing configuration consists + of a list of elements each describing processing settings for a given + output stream. Valid output stream types are listed in "streamOutputType". + Each stream element contains a list of "apply" elements. The value of the + "effect" attr must correspond to the name of an "effect" element. + Example: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/current.txt b/current.txt index 1fe17d5ca4..b54c16aad4 100644 --- a/current.txt +++ b/current.txt @@ -605,7 +605,7 @@ fd1f1b29f26b42e886220f04a08086c00e5ade9d7b53f095438e578ab9d42a93 android.hardwar 2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn 78e4138cc8307c11fc777c3bd376e581ba4ba48196b05ca1d7cdfa515c87b48a android.hardware.audio@6.0::IStreamOut 997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback -1349686814402fa10f711cc5763bc629aafc64a5f5843b4b21b8cd86ffb923e6 android.hardware.audio.common@6.0::types +8c4232772efeb9905b4c287723e0ee8b2c4bf5ba11728d051171b070e3d79144 android.hardware.audio.common@6.0::types 817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types 525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect 8d76bbe3719d051a8e9a1dcf9244f37f5b0a491feb249fa48391edf7cb4f3131 android.hardware.audio.effect@6.0::IAutomaticGainControlEffect From 91e07785b5fa6b9fbb4791d07dc327d4d594d5e8 Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Mon, 7 Oct 2019 15:18:42 -0700 Subject: [PATCH 0349/1022] Camera: add OFFLINE_PROCESSING APIs Also a typo fix in metadata doc. Test: N/A. New API skeleton, no implementation yet. Bug: 135142453 Change-Id: I4852ee28242afabe81b02cfef39994c5d2705359 --- camera/device/3.6/Android.bp | 24 ++++ camera/device/3.6/ICameraDeviceSession.hal | 132 ++++++++++++++++++ camera/device/3.6/ICameraOfflineSession.hal | 80 +++++++++++ camera/device/3.6/types.hal | 143 ++++++++++++++++++++ camera/metadata/3.2/types.hal | 2 +- camera/metadata/3.5/Android.bp | 1 - camera/metadata/3.5/types.hal | 1 + current.txt | 2 + 8 files changed, 383 insertions(+), 2 deletions(-) create mode 100644 camera/device/3.6/Android.bp create mode 100644 camera/device/3.6/ICameraDeviceSession.hal create mode 100644 camera/device/3.6/ICameraOfflineSession.hal create mode 100644 camera/device/3.6/types.hal diff --git a/camera/device/3.6/Android.bp b/camera/device/3.6/Android.bp new file mode 100644 index 0000000000..8766b931f4 --- /dev/null +++ b/camera/device/3.6/Android.bp @@ -0,0 +1,24 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.camera.device@3.6", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "ICameraDeviceSession.hal", + "ICameraOfflineSession.hal", + ], + interfaces: [ + "android.hardware.camera.common@1.0", + "android.hardware.camera.device@3.2", + "android.hardware.camera.device@3.3", + "android.hardware.camera.device@3.4", + "android.hardware.camera.device@3.5", + "android.hardware.graphics.common@1.0", + "android.hidl.base@1.0", + ], + gen_java: false, +} diff --git a/camera/device/3.6/ICameraDeviceSession.hal b/camera/device/3.6/ICameraDeviceSession.hal new file mode 100644 index 0000000000..00ebcc3382 --- /dev/null +++ b/camera/device/3.6/ICameraDeviceSession.hal @@ -0,0 +1,132 @@ +/* + * 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. + */ + +package android.hardware.camera.device@3.6; + +import android.hardware.camera.common@1.0::Status; +import @3.5::ICameraDeviceSession; +import @3.5::StreamConfiguration; +import ICameraOfflineSession; + +/** + * Camera device active session interface. + * + * Obtained via ICameraDevice::open(), this interface contains the methods to + * configure and request captures from an active camera device. + */ +interface ICameraDeviceSession extends @3.5::ICameraDeviceSession { + /** + * configureStreams_3_6: + * + * Identical to @3.5::ICameraDeviceSession.configureStreams, except that: + * + * - a boolean supportOffline is added to HalStreamConfiguration to indicate + * if this stream can be switched to offline mode later. + * + * @return status Status code for the operation, one of: + * OK: + * On successful stream configuration. + * INTERNAL_ERROR: + * If there has been a fatal error and the device is no longer + * operational. Only close() can be called successfully by the + * framework after this error is returned. + * ILLEGAL_ARGUMENT: + * If the requested stream configuration is invalid. Some examples + * of invalid stream configurations include: + * - Including more than 1 INPUT stream + * - Not including any OUTPUT streams + * - Including streams with unsupported formats, or an unsupported + * size for that format. + * - Including too many output streams of a certain format. + * - Unsupported rotation configuration + * - Stream sizes/formats don't satisfy the + * StreamConfigurationMode requirements + * for non-NORMAL mode, or the requested operation_mode is not + * supported by the HAL. + * - Unsupported usage flag + * The camera service cannot filter out all possible illegal stream + * configurations, since some devices may support more simultaneous + * streams or larger stream resolutions than the minimum required + * for a given camera device hardware level. The HAL must return an + * ILLEGAL_ARGUMENT for any unsupported stream set, and then be + * ready to accept a future valid stream configuration in a later + * configureStreams call. + * @return halConfiguration The stream parameters desired by the HAL for + * each stream, including maximum buffers, the usage flags, and the + * override format. + */ + configureStreams_3_6(@3.5::StreamConfiguration requestedConfiguration) + generates (Status status, HalStreamConfiguration halConfiguration); + + /** + * switchToOffline: + * + * Switch the current running session from actively streaming mode to the + * offline mode. See ICameraOfflineSession for more details. + * + * The streamsToKeep argument contains list of streams IDs where application + * still needs its output. For all streams application does not need anymore, + * camera HAL can send ERROR_BUFFER to speed up the transition, or even send + * ERROR_REQUEST if all output targets of a request is not needed. By the + * time this call returns, camera HAL must have returned all buffers coming + * from streams no longer needed and have erased buffer caches of such streams. + * + * For all requests that are going to be transferred to offline session, + * the ICameraDeviceSession is responsible to capture all input buffers from + * the image sensor before the switchToOffline call returns. Before + * switchToOffline returns, camera HAL must have completed all requests not + * switching to offline mode, and collected information on what streams and + * requests are going to continue in the offline session, in the + * offlineSessionInfo output argument. + * + * If there are no requests qualified to be transferred to offline session, + * the camera HAL must return a null ICameraOfflineSession object with OK + * status. In this scenario, the camera HAL still must flush all inflight + * requests and unconfigure all streams before returning this call. + * + * After switchToOffline returns, the ICameraDeviceSession must be back to + * unconfigured state as if it is just created and no streams are configured. + * Also, camera HAL must not call any methods in ICameraDeviceCallback since + * all unfinished requests are now transferred to the offline session. + * After the call returns, camera service may then call close to close + * the camera device, or call configureStream* again to reconfigure the + * camera and then send new capture requests with processCaptureRequest. In + * the latter case, it is legitimate for camera HAL to call methods in + * ICameraDeviceCallback again in response to the newly submitted capture + * requests. + * + * @return status Status code for the operation, one of: + * OK: + * On switching to offline session and unconfiguring streams + * successfully. + * ILLEGAL_ARGUMENT: + * If camera does not support offline mode in any one of streams + * in streamsToKeep argument. Note that the camera HAL must report + * if a stream supports offline mode in HalStreamConfiguration + * output of configureStreams_3_6 method. If all streams in + * streamsToKeep argument support offline mode, then the camera HAL + * must not return this error. + * + * + * @return offlineSessionInfo Information on what streams and requests will + * be transferred to offline session to continue processing. + * + * @return offlineSession The offline session object camera service will use + * to interact with. + */ + switchToOffline(vec streamsToKeep) generates (Status status, + CameraOfflineSessionInfo offlineSessionInfo, ICameraOfflineSession offlineSession); +}; diff --git a/camera/device/3.6/ICameraOfflineSession.hal b/camera/device/3.6/ICameraOfflineSession.hal new file mode 100644 index 0000000000..03cea64a0c --- /dev/null +++ b/camera/device/3.6/ICameraOfflineSession.hal @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package android.hardware.camera.device@3.6; + +import @3.5::ICameraDeviceCallback; + +/** + * Camera device offline session interface. + * + * Obtained via ICameraDeviceSession::switchToOffline(), this interface contains + * the methods and callback interfaces that define how camera service interacts + * with an offline session. + * + * An offline session contains some unfinished capture requests that were submitted + * to the parent ICameraDeviceSession before calling switchToOffline, and is + * responsible for delivering these capture results back to camera service regardless + * of whether the parent camera device is still opened or not. An offline session must + * not have access to the camera device's image sensor. During switchToOffline + * call, camera HAL must capture all necessary frames from the image sensor that + * is needed for completing the requests offline later. + */ +interface ICameraOfflineSession { + /** + * Set the callbacks for offline session to communicate with camera service. + * + * Offline session is responsible to store all callbacks the camera HAL + * generated after the return of ICameraDeviceSession::switchToOffline, and + * send them to camera service once this method is called. + * + * Camera service must not call this method more than once, so these + * callbacks can be assumed to be constant after the first setCallback call. + */ + setCallback(ICameraDeviceCallback cb); + + /** + * getCaptureResultMetadataQueue: + * + * Retrieves the queue used along with + * ICameraDeviceCallback#processCaptureResult. + * + * Clients to ICameraOfflineSession must: + * - Call getCaptureRequestMetadataQueue to retrieve the fast message queue; + * - In implementation of ICameraDeviceCallback, test whether + * .fmqResultSize field is zero. + * - If .fmqResultSize != 0, read result metadata from the fast message + * queue; + * - otherwise, read result metadata in CaptureResult.result. + * + * @return queue the queue that implementation writes result metadata to. + */ + getCaptureResultMetadataQueue() generates (fmq_sync queue); + + /** + * Close the offline session and release all resources. + * + * Camera service may call this method before or after the offline session + * has finished all requests it needs to handle. If there are still unfinished + * requests when close is called, camera HAL must send ERROR_REQUEST for + * all unfinished requests and return all buffers via + * ICameraDeviceCallback#processCaptureResult or + * ICameraDeviceCallback#returnStreamBuffers. + * Also, all buffer caches maintained by the offline session must be erased + * before the close call returns. + */ + close(); +}; diff --git a/camera/device/3.6/types.hal b/camera/device/3.6/types.hal new file mode 100644 index 0000000000..743b139877 --- /dev/null +++ b/camera/device/3.6/types.hal @@ -0,0 +1,143 @@ +/* + * 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. + */ + +package android.hardware.camera.device@3.6; + +import @3.2::BufferCache; +import @3.4::HalStream; + +/** + * OfflineRequest: + * + * Information about a capture request being switched to offline mode via the + * ICameraDeviceSession#switchToOffline method. + * + */ +struct OfflineRequest { + /** + * Must match a inflight CaptureRequest sent by camera service + */ + uint32_t frameNumber; + + /** + * Stream IDs for outputs that will be returned via ICameraDeviceCallback. + * The stream ID must be within one of offline stream listed in + * CameraOfflineSessionInfo. + * Camera service will validate these pending buffers are matching camera + * service's record to make sure no buffers are leaked during the + * switchToOffline call. + */ + vec pendingStreams; +}; + +/** + * OfflineStream: + * + * Information about a stream being switched to offline mode via the + * ICameraDeviceSession#switchToOffline method. + * + */ +struct OfflineStream { + /** + * IDs of a stream to be transferred to offline session. + * + * For devices that do not support HAL buffer management, this must be + * one of stream ID listed in streamsToKeep argument of the + * switchToOffline call. + * For devices that support HAL buffer management, this could be any stream + * that was configured right before calling switchToOffline. + */ + int32_t id; + + /** + * Number of outstanding buffers that will be returned via offline session + */ + uint32_t numOutstandingBuffers; + + /** + * Buffer ID of buffers currently cached between camera service and this + * stream, which may or may not be owned by the camera HAL right now. + * See StreamBuffer#bufferId for more details. + */ + vec circulatingBufferIds; +}; + +/** + * CameraOfflineSessionInfo: + * + * Information about pending outputs that's being transferred to an offline + * session from an active session using the + * ICameraDeviceSession#switchToOffline method. + * + */ +struct CameraOfflineSessionInfo { + /** + * Information on what streams will be preserved in offline session. + * Streams not listed here will be removed by camera service after + * switchToOffline call returns. + */ + vec offlineStreams; + + /** + * Information for requests that will be handled by offline session + * Camera service will validate this matches what camera service has on + * record. + */ + vec offlineRequests; +}; + +/** + * HalStream: + * + * The camera HAL's response to each requested stream configuration. + * + * This version extends the @3.4 HalStream with the physicalCameraId + * field + */ +struct HalStream { + /** + * The definition of HalStream from the prior version. + */ + @3.4::HalStream v3_4; + + /** + * Whether this stream can be switch to offline mode. + * + * For devices that does not support the OFFLINE_PROCESSING capability, this + * fields will always be false. + * + * For devices support the OFFLINE_PROCESSING capability: any input stream + * and any output stream that can be output of the input stream must set + * this field to true. Also any stream of YUV420_888 format or JPEG format, + * with CPU_READ usage flag, must set this field to true. All other streams + * are up to camera HAL to advertise support or not, though it is not + * recommended to list support for streams with hardware composer or video + * encoder usage flags as these streams tend to be targeted continuously and + * can lead to long latency when trying to switch to offline. + * + */ + bool supportOffline; +}; + +/** + * HalStreamConfiguration: + * + * Identical to @3.4::HalStreamConfiguration, except that it contains @3.6::HalStream entries. + * + */ +struct HalStreamConfiguration { + vec streams; +}; diff --git a/camera/metadata/3.2/types.hal b/camera/metadata/3.2/types.hal index cef0397931..f5034ccd0b 100644 --- a/camera/metadata/3.2/types.hal +++ b/camera/metadata/3.2/types.hal @@ -410,7 +410,7 @@ enum CameraMetadataTag : uint32_t { * *

    List of the maximum number of regions that can be used for metering in * auto-exposure (AE), auto-white balance (AWB), and auto-focus (AF); - * this corresponds to the the maximum number of elements in + * this corresponds to the maximum number of elements in * ANDROID_CONTROL_AE_REGIONS, ANDROID_CONTROL_AWB_REGIONS, * and ANDROID_CONTROL_AF_REGIONS.

    * diff --git a/camera/metadata/3.5/Android.bp b/camera/metadata/3.5/Android.bp index 4ebd069d3a..224c36976a 100644 --- a/camera/metadata/3.5/Android.bp +++ b/camera/metadata/3.5/Android.bp @@ -16,4 +16,3 @@ hidl_interface { ], gen_java: true, } - diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal index b9451c852b..2fd8a0d0fa 100644 --- a/camera/metadata/3.5/types.hal +++ b/camera/metadata/3.5/types.hal @@ -71,4 +71,5 @@ enum CameraMetadataEnumAndroidControlBokehMode : uint32_t { enum CameraMetadataEnumAndroidRequestAvailableCapabilities : @3.4::CameraMetadataEnumAndroidRequestAvailableCapabilities { ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA, + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING, }; diff --git a/current.txt b/current.txt index e25101f321..03b4da8b56 100644 --- a/current.txt +++ b/current.txt @@ -585,6 +585,8 @@ c3ec182ce325862b7d79e526f3e170c02cfee1497ed309d7c60d0de4ca636b0b android.hardwar f5bc6aa840db933cb9fd36668b06d3e2021cf5384bb70e459f22e2f2f921fba5 android.hardware.automotive.evs@1.0::IEvsEnumerator d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardware.automotive.evs@1.0::types 2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types +cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types +2bdc6baf3f80f7a87fb5a5d03599e2ee37aadd3dbb107b7c9c060657702942a8 android.hardware.camera.metadata@3.5::types b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel f1109cbb10297b7429a11fab42afa912710b303c9bf20bd5cdb8bd57b9c84186 android.hardware.neuralnetworks@1.0::types From 4fba44c159c59ea91f9b55a4f3152b01d4e67260 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Sun, 17 Nov 2019 20:28:38 -0800 Subject: [PATCH 0350/1022] HAL for Resume on Reboot This adds a HAL interface for escrowing a key over reboot during an OTA that will unlock the Synthetic Password when the OTA has completed successfully. Bug: 63928581 Test: make Test: atest VtsHalRebootEscrowTargetTest Change-Id: I8485f3821157e67b6651f4fe425e46cb4499c710 --- .../compatibility_matrix.current.xml | 7 ++ rebootescrow/aidl/Android.bp | 18 ++++ .../hardware/rebootescrow/IRebootEscrow.aidl | 44 ++++++++ rebootescrow/aidl/vts/functional/Android.bp | 34 ++++++ .../VtsHalRebootEscrowTargetTest.cpp | 101 ++++++++++++++++++ 5 files changed, 204 insertions(+) create mode 100644 rebootescrow/aidl/Android.bp create mode 100644 rebootescrow/aidl/android/hardware/rebootescrow/IRebootEscrow.aidl create mode 100644 rebootescrow/aidl/vts/functional/Android.bp create mode 100644 rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index f5acdd441e..1e3f74332a 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -388,6 +388,13 @@ default
    + + android.hardware.rebootescrow + + IRebootEscrow + default + + android.hardware.secure_element 1.0 diff --git a/rebootescrow/aidl/Android.bp b/rebootescrow/aidl/Android.bp new file mode 100644 index 0000000000..7bc8d6ff3f --- /dev/null +++ b/rebootescrow/aidl/Android.bp @@ -0,0 +1,18 @@ +aidl_interface { + name: "vintf-rebootescrow", + vendor_available: true, + srcs: [ + "android/hardware/rebootescrow/IRebootEscrow.aidl", + ], + stability: "vintf", + backend: { + java: { + platform_apis: true, + }, + ndk: { + vndk: { + enabled: true, + }, + }, + }, +} diff --git a/rebootescrow/aidl/android/hardware/rebootescrow/IRebootEscrow.aidl b/rebootescrow/aidl/android/hardware/rebootescrow/IRebootEscrow.aidl new file mode 100644 index 0000000000..edc695d301 --- /dev/null +++ b/rebootescrow/aidl/android/hardware/rebootescrow/IRebootEscrow.aidl @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package android.hardware.rebootescrow; + +/** + * This HAL defines the interface to the device-specific implementation + * of retaining a secret to unlock the Synthetic Password stored during + * a reboot to perform an OTA update. The implementation of this interface + * should never store the key on any non-volatile medium. The key should be + * overwritten with zeroes when destroyKey() is called. All care should be given + * to provide the shortest lifetime for the storage of the key in volatile and + * erasable storage. + * + * This HAL is optional so does not require an implementation on device. + */ +@VintfStability +interface IRebootEscrow { + /** + * Store the key for reboot. + */ + void storeKey(in byte[] kek); + + /** + * Retrieve the possible keys. If the implementation is probabalistic, it + * should return the keys in order from most-probable to least-probable. + * There is not a hard limit to the number of keys, but it is suggested to + * keep the number of key possibilities less than 32. + */ + byte[] retrieveKey(); +} diff --git a/rebootescrow/aidl/vts/functional/Android.bp b/rebootescrow/aidl/vts/functional/Android.bp new file mode 100644 index 0000000000..dadf2509d8 --- /dev/null +++ b/rebootescrow/aidl/vts/functional/Android.bp @@ -0,0 +1,34 @@ +// +// 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. +// + +cc_test { + name: "VtsHalRebootEscrowTargetTest", + defaults: [ + "VtsHalTargetTestDefaults", + "use_libaidlvintf_gtest_helper_static", + ], + srcs: ["VtsHalRebootEscrowTargetTest.cpp"], + shared_libs: [ + "libbinder", + ], + static_libs: [ + "vintf-rebootescrow-cpp", + ], + test_suites: [ + "vts-core", + ], + require_root: true, +} diff --git a/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp new file mode 100644 index 0000000000..f69cf877ad --- /dev/null +++ b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp @@ -0,0 +1,101 @@ +/* + * 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. + */ + +#include +#include + +#include + +#include +#include + +using android::sp; +using android::String16; +using android::hardware::rebootescrow::IRebootEscrow; + +/** + * This tests that the key can be written, read, and removed. It does not test + * that the key survives a reboot. That needs a host-based test. + * + * atest VtsHalRebootEscrowV1_0TargetTest + */ +class RebootEscrowAidlTest : public testing::TestWithParam { + public: + virtual void SetUp() override { + rebootescrow = android::waitForDeclaredService(String16(GetParam().c_str())); + ASSERT_NE(rebootescrow, nullptr); + } + + sp rebootescrow; + + std::vector KEY_1{ + 0xA5, 0x00, 0xFF, 0x01, 0xA5, 0x5a, 0xAA, 0x55, 0x00, 0xD3, 0x2A, + 0x8C, 0x2E, 0x83, 0x0E, 0x65, 0x9E, 0x8D, 0xC6, 0xAC, 0x1E, 0x83, + 0x21, 0xB3, 0x95, 0x02, 0x89, 0x64, 0x64, 0x92, 0x12, 0x1F, + }; + std::vector KEY_2{ + 0xFF, 0x00, 0x00, 0xAA, 0x5A, 0x19, 0x20, 0x71, 0x9F, 0xFB, 0xDA, + 0xB6, 0x2D, 0x06, 0xD5, 0x49, 0x7E, 0xEF, 0x63, 0xAC, 0x18, 0xFF, + 0x5A, 0xA3, 0x40, 0xBB, 0x64, 0xFA, 0x67, 0xC1, 0x10, 0x18, + }; + std::vector EMPTY_KEY{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; +}; + +TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_Success) { + ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk()); + + std::vector actualKey; + ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk()); + EXPECT_EQ(actualKey, KEY_1); +} + +TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_SecondRetrieveSucceeds) { + ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk()); + + std::vector actualKey; + ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk()); + EXPECT_EQ(actualKey, KEY_1); + + ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk()); + EXPECT_EQ(actualKey, KEY_1); +} + +TEST_P(RebootEscrowAidlTest, StoreTwiceOverwrites_Success) { + ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk()); + ASSERT_TRUE(rebootescrow->storeKey(KEY_2).isOk()); + + std::vector actualKey; + ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk()); + EXPECT_EQ(actualKey, KEY_2); +} + +TEST_P(RebootEscrowAidlTest, StoreEmpty_AfterGetEmptyKey_Success) { + rebootescrow->storeKey(KEY_1); + rebootescrow->storeKey(EMPTY_KEY); + + std::vector actualKey; + ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk()); + EXPECT_EQ(actualKey, EMPTY_KEY); +} + +INSTANTIATE_TEST_SUITE_P( + RebootEscrow, RebootEscrowAidlTest, + testing::ValuesIn(android::getAidlHalInstanceNames(IRebootEscrow::descriptor)), + android::PrintInstanceNameToString); From ead8b45fc85b0ce091660e4b946cf0c21bbaffee Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Thu, 12 Dec 2019 21:46:00 -0800 Subject: [PATCH 0351/1022] Add BT709 with full range. Add support for BT709 full range support with SMPTE 170M transfer function. Minor: Remove deprecated dataspace support in aidl. BUG: b/130737986 Test: build Change-Id: I17b1f7d868e99396df9779bdd53d63bdcd2a06af --- .../hardware/graphics/common/Dataspace.aidl | 51 +++++++++---------- .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 2 +- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl index 81a21ab180..42cdd8128c 100644 --- a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl +++ b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl @@ -208,8 +208,6 @@ enum Dataspace { */ STANDARD_ADOBE_RGB = 11 << 16, // 11 << STANDARD_SHIFT - - TRANSFER_SHIFT = 22, /** @@ -396,9 +394,7 @@ enum Dataspace { * The values are encoded using the full range ([0,255] for 8-bit) for all * components. */ - SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // deprecated, use V0_SRGB_LINEAR - - V0_SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL + SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL /** @@ -413,7 +409,7 @@ enum Dataspace { * Values beyond the range [0.0 - 1.0] would correspond to other colors * spaces and/or HDR content. */ - V0_SCRGB_LINEAR = 1 << 16 | 1 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED + SCRGB_LINEAR = 1 << 16 | 1 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED /** @@ -429,9 +425,7 @@ enum Dataspace { * * Use full range and BT.709 standard. */ - SRGB = 1 << 16 | 2 << 22 | 1 << 27, // deprecated, use V0_SRGB - - V0_SRGB = 1 << 16 | 2 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL + SRGB = 1 << 16 | 2 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL /** @@ -446,7 +440,7 @@ enum Dataspace { * Values beyond the range [0.0 - 1.0] would correspond to other colors * spaces and/or HDR content. */ - V0_SCRGB = 1 << 16 | 2 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED + SCRGB = 1 << 16 | 2 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED /** * YCbCr Colorspaces @@ -464,22 +458,18 @@ enum Dataspace { * * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255 * - * Use full range, BT.601 transfer and BT.601_625 standard. + * Use full range, SMPTE 170M transfer and BT.601_625 standard. */ - JFIF = 2 << 16 | 3 << 22 | 1 << 27, // deprecated, use V0_JFIF - - V0_JFIF = 2 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL + JFIF = 2 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL /** * ITU-R Recommendation 601 (BT.601) - 625-line * * Standard-definition television, 625 Lines (PAL) * - * Use limited range, BT.601 transfer and BT.601_625 standard. + * Use limited range, SMPTE 170M transfer and BT.601_625 standard. */ - BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT601_625 - - V0_BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED + BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED /** @@ -487,22 +477,18 @@ enum Dataspace { * * Standard-definition television, 525 Lines (NTSC) * - * Use limited range, BT.601 transfer and BT.601_525 standard. + * Use limited range, SMPTE 170M transfer and BT.601_525 standard. */ - BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT601_525 - - V0_BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED + BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED /** * ITU-R Recommendation 709 (BT.709) * * High-definition television * - * Use limited range, BT.709 transfer and BT.709 standard. + * Use limited range, SMPTE 170M transfer and BT.709 standard. */ - BT709 = 1 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT709 - - V0_BT709 = 1 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED + BT709 = 1 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED /** @@ -570,7 +556,7 @@ enum Dataspace { * * Ultra High-definition television * - * Use full range, BT.709 transfer and BT2020 standard + * Use full range, SMPTE 170M transfer and BT2020 standard */ BT2020 = 6 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL @@ -622,7 +608,7 @@ enum Dataspace { * * Ultra High-definition television * - * Use limited range, BT.709 transfer and BT2020 standard + * Use limited range, SMPTE 170M transfer and BT2020 standard */ BT2020_ITU = 6 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_LIMITED @@ -679,4 +665,13 @@ enum Dataspace { * according to ISO/IEC 23008-12. */ HEIF = 0x1004, + + /** + * ITU-R Recommendation 709 (BT.709) + * + * High-definition television + * + * Use full range, SMPTE 170M transfer and BT.709 standard. + */ + BT709_FULL_RANGE = 1 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_FULL } diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 7dc733cb98..3285fd601c 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -1406,7 +1406,7 @@ TEST_P(GraphicsMapperHidlTest, SetPlaneLayouts) { * Test IMapper::set(Dataspace) */ TEST_P(GraphicsMapperHidlTest, SetDataspace) { - Dataspace dataspace = Dataspace::V0_SRGB_LINEAR; + Dataspace dataspace = Dataspace::SRGB_LINEAR; hidl_vec vec; ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &vec)); From a0973458f5f645927c07e5b66d23932f090da7a1 Mon Sep 17 00:00:00 2001 From: Galia Peycheva Date: Fri, 1 Nov 2019 11:04:42 +0100 Subject: [PATCH 0352/1022] Add controls for ALLM and Content Types to composer hal Also extending the passthrough interface with setLowLatencyMode and setContentType. Bug:132731049 Test: make -j$(nproc) Test: vts-tradefed run vts-hal --skip-device-info -m VtsHalGraphicsComposerV2_4Target Change-Id: I14dd61a3d9c60fdb06f9028ccd6f49797267e9f4 --- graphics/composer/2.4/IComposerClient.hal | 74 +++++++++++ .../include/composer-hal/2.4/ComposerClient.h | 18 +++ .../include/composer-hal/2.4/ComposerHal.h | 5 + .../include/composer-passthrough/2.4/HwcHal.h | 59 +++++++++ .../composer/2.4/utils/vts/ComposerVts.cpp | 19 +++ .../include/composer-vts/2.4/ComposerVts.h | 7 ++ .../VtsHalGraphicsComposerV2_4TargetTest.cpp | 119 ++++++++++++++++++ 7 files changed, 301 insertions(+) diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal index f23536cd2d..06b4c5e53a 100644 --- a/graphics/composer/2.4/IComposerClient.hal +++ b/graphics/composer/2.4/IComposerClient.hal @@ -48,6 +48,12 @@ interface IComposerClient extends @2.3::IComposerClient { * with protected buffers. */ PROTECTED_CONTENTS = 4, + + /** + * Indicates that both the composer HAL implementation and the given display + * support a low latency mode, such as HDMI 2.1 Auto Low Latency Mode. + */ + AUTO_LOW_LATENCY_MODE = 5, }; /** @@ -64,6 +70,18 @@ interface IComposerClient extends @2.3::IComposerClient { EXTERNAL = 1, }; + enum ContentType : uint32_t { + NONE = 0, + + /** + * These modes correspond to those found in the HDMI 1.4 specification. + */ + GRAPHICS = 1, + PHOTO = 2, + CINEMA = 3, + GAME = 4, + }; + /** * Constraints for changing vsync period. */ @@ -172,4 +190,60 @@ interface IComposerClient extends @2.3::IComposerClient { setActiveConfigWithConstraints(Display display, Config config, VsyncPeriodChangeConstraints vsyncPeriodChangeConstraints) generates (Error error, VsyncPeriodChangeTimeline timeline); + + /** + * Requests the display to enable/disable its low latency mode. + * + * If the display is connected via HDMI 2.1, then Auto Low Latency Mode should be triggered. If + * the display is internally connected and a custom low latency mode is available, that should + * be triggered. + * + * This function should only be called if the display reports support for + * DisplayCapability::AUTO_LOW_LATENCY_MODE from getDisplayCapabilities_2_4. + * + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * UNSUPPORTED when AUTO_LOW_LATENCY_MODE is not supported by the composer + * implementation or the given display + */ + setAutoLowLatencyMode(Display display, bool on) + generates (Error error); + + /** + * Provides a list of all the content types supported by this display (any of + * ContentType::{GRAPHICS, PHOTO, CINEMA, GAME}). This list must not change after + * initialization. + * + * Content types are introduced in HDMI 1.4 and supporting them is optional. The + * ContentType::NONE is always supported and will not be returned by this method.. + * + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * @return supportedContentTypes is a list of supported content types. + */ + getSupportedContentTypes(Display display) + generates(Error error, vec supportedContentTypes); + + /** + * Instructs the connected display that the content being shown is of the given type - one of + * GRAPHICS, PHOTO, CINEMA, GAME. + * + * Content types are introduced in HDMI 1.4 and supporting them is optional. If they are + * supported, this signal should switch the display to a mode that is optimal for the given + * type of content. See HDMI 1.4 specification for more information. + * + * If the display is internally connected (not through HDMI), and such modes are available, + * this method should trigger them. + * + * This function should only be called if the display reports support for the corresponding + * content type (ContentType::{GRAPHICS, PHOTO, CINEMA, GAME}) from getSupportedContentTypes. + * ContentType::NONE is supported by default and can always be set. + * + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * UNSUPPORTED when the given content type is not supported by the composer + * implementation or the given display + */ + setContentType(Display display, ContentType type) + generates (Error error); }; diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h index 4160ed97bf..dcd959dfb5 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h @@ -139,6 +139,24 @@ class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImpl setAutoLowLatencyMode(Display display, bool on) override { + return mHal->setAutoLowLatencyMode(display, on); + } + + Return getSupportedContentTypes( + Display display, IComposerClient::getSupportedContentTypes_cb hidl_cb) override { + std::vector supportedContentTypes; + Error error = mHal->getSupportedContentTypes(display, &supportedContentTypes); + + hidl_cb(error, supportedContentTypes); + return Void(); + } + + Return setContentType(Display display, + IComposerClient::ContentType contentType) override { + return mHal->setContentType(display, contentType); + } + static std::unique_ptr create(Hal* hal) { auto client = std::make_unique(hal); return client->init() ? std::move(client) : nullptr; diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h index 89dbe66d60..a1e56ae6ed 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h @@ -67,6 +67,11 @@ class ComposerHal : public V2_3::hal::ComposerHal { Display display, Config config, const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, VsyncPeriodChangeTimeline* timeline) = 0; + virtual Error setAutoLowLatencyMode(Display display, bool on) = 0; + virtual Error getSupportedContentTypes( + Display display, + std::vector* outSupportedContentTypes) = 0; + virtual Error setContentType(Display display, IComposerClient::ContentType contentType) = 0; }; } // namespace hal diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h index d59d0d5361..a27582a0e7 100644 --- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h +++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h @@ -167,6 +167,57 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { return Error::NONE; } + Error setAutoLowLatencyMode(Display display, bool on) override { + if (!mDispatch.setAutoLowLatencyMode) { + return Error::UNSUPPORTED; + } + + int32_t error = mDispatch.setAutoLowLatencyMode(mDevice, display, on); + if (error != HWC2_ERROR_NONE) { + return static_cast(error); + } + return Error::NONE; + } + + Error getSupportedContentTypes( + Display display, + std::vector* outSupportedContentTypes) override { + if (!mDispatch.getSupportedContentTypes) { + return Error::UNSUPPORTED; + } + + uint32_t count = 0; + int32_t error = mDispatch.getSupportedContentTypes(mDevice, display, &count, nullptr); + if (error != HWC2_ERROR_NONE) { + return static_cast(error); + } + + outSupportedContentTypes->resize(count); + + error = mDispatch.getSupportedContentTypes( + mDevice, display, &count, + reinterpret_cast::type*>( + outSupportedContentTypes->data())); + if (error != HWC2_ERROR_NONE) { + *outSupportedContentTypes = std::vector(); + return static_cast(error); + } + return Error::NONE; + } + + Error setContentType(Display display, IComposerClient::ContentType contentType) override { + if (!mDispatch.setContentType) { + return Error::UNSUPPORTED; + } + + int32_t error = + mDispatch.setContentType(mDevice, display, static_cast(contentType)); + if (error != HWC2_ERROR_NONE) { + return static_cast(error); + } + return Error::NONE; + } + protected: bool initDispatch() override { if (!BaseType2_3::initDispatch()) { @@ -179,6 +230,11 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { &mDispatch.getDisplayVsyncPeriod); this->initOptionalDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS, &mDispatch.setActiveConfigWithConstraints); + this->initOptionalDispatch(HWC2_FUNCTION_SET_AUTO_LOW_LATENCY_MODE, + &mDispatch.setAutoLowLatencyMode); + this->initOptionalDispatch(HWC2_FUNCTION_GET_SUPPORTED_CONTENT_TYPES, + &mDispatch.getSupportedContentTypes); + this->initOptionalDispatch(HWC2_FUNCTION_SET_CONTENT_TYPE, &mDispatch.setContentType); return true; } @@ -222,6 +278,9 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE getDisplayConnectionType; HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD getDisplayVsyncPeriod; HWC2_PFN_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS setActiveConfigWithConstraints; + HWC2_PFN_SET_AUTO_LOW_LATENCY_MODE setAutoLowLatencyMode; + HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES getSupportedContentTypes; + HWC2_PFN_SET_CONTENT_TYPE setContentType; } mDispatch = {}; hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr; diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp index 35ac23f7ff..5b06d6d3ff 100644 --- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp @@ -106,6 +106,25 @@ Error ComposerClient::setActiveConfigWithConstraints( return error; } +Error ComposerClient::setAutoLowLatencyMode(Display display, bool on) { + return mClient->setAutoLowLatencyMode(display, on); +} + +Error ComposerClient::getSupportedContentTypes( + Display display, std::vector* outSupportedContentTypes) { + Error error = Error::NONE; + mClient->getSupportedContentTypes( + display, [&](const auto& tmpError, const auto& tmpSupportedContentTypes) { + error = tmpError; + *outSupportedContentTypes = tmpSupportedContentTypes; + }); + return error; +} + +Error ComposerClient::setContentType(Display display, IComposerClient::ContentType contentType) { + return mClient->setContentType(display, contentType); +} + } // namespace vts } // namespace V2_4 } // namespace composer diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h index 83e74ed698..b094bc8028 100644 --- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h @@ -84,6 +84,13 @@ class ComposerClient : public V2_3::vts::ComposerClient { const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, VsyncPeriodChangeTimeline* timeline); + Error setAutoLowLatencyMode(Display display, bool on); + + Error getSupportedContentTypes( + Display display, std::vector* outSupportedContentTypes); + + Error setContentType(Display display, IComposerClient::ContentType contentType); + private: const sp mClient; }; diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index f038f551e3..6b6f2a5b5d 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -47,6 +47,9 @@ using common::V1_2::PixelFormat; using mapper::V2_0::IMapper; using mapper::V2_0::vts::Gralloc; +using ContentType = IComposerClient::ContentType; +using DisplayCapability = IComposerClient::DisplayCapability; + class GraphicsComposerHidlTest : public ::testing::TestWithParam { protected: void SetUp() override { @@ -117,6 +120,11 @@ class GraphicsComposerHidlTest : public ::testing::TestWithParam { void Test_setActiveConfigWithConstraints( const IComposerClient::VsyncPeriodChangeConstraints& constraints); + void Test_setContentType(const ContentType& contentType, const char* contentTypeStr); + void Test_setContentTypeForDisplay(const Display& display, + const std::vector& capabilities, + const ContentType& contentType, const char* contentTypeStr); + std::unique_ptr mComposer; std::unique_ptr mComposerClient; sp mComposerCallback; @@ -377,6 +385,117 @@ TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_delayed) { Test_setActiveConfigWithConstraints(constraints); } +TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyModeBadDisplay) { + EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setAutoLowLatencyMode(mInvalidDisplayId, true)); + EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setAutoLowLatencyMode(mInvalidDisplayId, false)); +} + +TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyMode) { + for (Display display : mComposerCallback->getDisplays()) { + std::vector capabilities; + const auto error = mComposerClient->getDisplayCapabilities(display, &capabilities); + EXPECT_EQ(Error::NONE, error); + + const bool allmSupport = + std::find(capabilities.begin(), capabilities.end(), + DisplayCapability::AUTO_LOW_LATENCY_MODE) != capabilities.end(); + + if (!allmSupport) { + EXPECT_EQ(Error::UNSUPPORTED, + mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, true)); + EXPECT_EQ(Error::UNSUPPORTED, + mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false)); + GTEST_SUCCEED() << "Auto Low Latency Mode is not supported on display " + << to_string(display) << ", skipping test"; + return; + } + + EXPECT_EQ(Error::NONE, mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, true)); + EXPECT_EQ(Error::NONE, mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false)); + } +} + +TEST_P(GraphicsComposerHidlTest, getSupportedContentTypesBadDisplay) { + std::vector supportedContentTypes; + const auto error = + mComposerClient->getSupportedContentTypes(mInvalidDisplayId, &supportedContentTypes); + EXPECT_EQ(Error::BAD_DISPLAY, error); +} + +TEST_P(GraphicsComposerHidlTest, getSupportedContentTypes) { + std::vector supportedContentTypes; + for (Display display : mComposerCallback->getDisplays()) { + supportedContentTypes.clear(); + const auto error = + mComposerClient->getSupportedContentTypes(display, &supportedContentTypes); + const bool noneSupported = + std::find(supportedContentTypes.begin(), supportedContentTypes.end(), + ContentType::NONE) != supportedContentTypes.end(); + EXPECT_EQ(Error::NONE, error); + EXPECT_FALSE(noneSupported); + } +} + +TEST_P(GraphicsComposerHidlTest, setContentTypeNoneAlwaysAccepted) { + for (Display display : mComposerCallback->getDisplays()) { + const auto error = mComposerClient->setContentType(display, ContentType::NONE); + EXPECT_NE(Error::UNSUPPORTED, error); + } +} + +TEST_P(GraphicsComposerHidlTest, setContentTypeBadDisplay) { + const auto types = {ContentType::NONE, ContentType::GRAPHICS, ContentType::PHOTO, + ContentType::CINEMA, ContentType::GAME}; + for (auto type : types) { + EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setContentType(mInvalidDisplayId, type)); + } +} + +void GraphicsComposerHidlTest::Test_setContentTypeForDisplay( + const Display& display, const std::vector& capabilities, + const ContentType& contentType, const char* contentTypeStr) { + const bool contentTypeSupport = + std::find(capabilities.begin(), capabilities.end(), contentType) != capabilities.end(); + + if (!contentTypeSupport) { + EXPECT_EQ(Error::UNSUPPORTED, mComposerClient->setContentType(display, contentType)); + GTEST_SUCCEED() << contentTypeStr << " content type is not supported on display " + << to_string(display) << ", skipping test"; + return; + } + + EXPECT_EQ(Error::NONE, mComposerClient->setContentType(display, contentType)); + EXPECT_EQ(Error::NONE, mComposerClient->setContentType(display, ContentType::NONE)); +} + +void GraphicsComposerHidlTest::Test_setContentType(const ContentType& contentType, + const char* contentTypeStr) { + for (Display display : mComposerCallback->getDisplays()) { + std::vector supportedContentTypes; + const auto error = + mComposerClient->getSupportedContentTypes(display, &supportedContentTypes); + EXPECT_EQ(Error::NONE, error); + + Test_setContentTypeForDisplay(display, supportedContentTypes, contentType, contentTypeStr); + } +} + +TEST_P(GraphicsComposerHidlTest, setGraphicsContentType) { + Test_setContentType(ContentType::GRAPHICS, "GRAPHICS"); +} + +TEST_P(GraphicsComposerHidlTest, setPhotoContentType) { + Test_setContentType(ContentType::PHOTO, "PHOTO"); +} + +TEST_P(GraphicsComposerHidlTest, setCinemaContentType) { + Test_setContentType(ContentType::CINEMA, "CINEMA"); +} + +TEST_P(GraphicsComposerHidlTest, setGameContentType) { + Test_setContentType(ContentType::GAME, "GAME"); +} + INSTANTIATE_TEST_SUITE_P( PerInstance, GraphicsComposerHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), From 7337e0581be464ea72d4be9fd3e1d3b33eb61d5f Mon Sep 17 00:00:00 2001 From: Yichi Chen Date: Tue, 17 Dec 2019 21:01:57 +0800 Subject: [PATCH 0353/1022] composer 2.4: Add new test case for getDisplayCapabilities The original test case was only tested with bad display. The patch adds the test case with normal displays. Test: atest VtsHalGraphicsComposerV2_4TargetTest Bug: 145566569 Change-Id: Id6a25ebc1f63092194ca1d8837cd450e5bc19def --- .../functional/VtsHalGraphicsComposerV2_4TargetTest.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index f038f551e3..7c5f0ee3e9 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -184,6 +184,13 @@ TEST_P(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) { EXPECT_EQ(Error::BAD_DISPLAY, error); } +TEST_P(GraphicsComposerHidlTest, getDisplayCapabilities) { + for (Display display : mComposerCallback->getDisplays()) { + std::vector capabilities; + EXPECT_EQ(Error::NONE, mComposerClient->getDisplayCapabilities(display, &capabilities)); + } +} + TEST_P(GraphicsComposerHidlTest, getDisplayConnectionType) { IComposerClient::DisplayConnectionType type; EXPECT_EQ(Error::BAD_DISPLAY, From 20102da237cdc3eba7641763327e957e78306c57 Mon Sep 17 00:00:00 2001 From: Joseph Murphy Date: Tue, 17 Dec 2019 19:58:51 +0000 Subject: [PATCH 0354/1022] Revert submission Reason for revert: Buildcop - Build breaking references to std::optional Change-Id: I8595ca0a668bc7e3684bc7f7a1424a6905d3b547 --- .../hardware/graphics/common/Cta861_3.aidl | 34 ---- .../hardware/graphics/common/Smpte2086.aidl | 51 ----- .../graphics/common/StandardMetadataType.aidl | 39 ---- .../hardware/graphics/common/XyColor.aidl | 30 --- graphics/mapper/4.0/IMapper.hal | 2 +- .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 179 ------------------ 6 files changed, 1 insertion(+), 334 deletions(-) delete mode 100644 graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl delete mode 100644 graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl delete mode 100644 graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl diff --git a/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl b/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl deleted file mode 100644 index 4fbc6b2344..0000000000 --- a/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl +++ /dev/null @@ -1,34 +0,0 @@ -/** - * 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. - */ - -package android.hardware.graphics.common; - -/** - * HDR static metadata extension as specified by CTA-861.3. - * - * This is an AIDL counterpart of the NDK struct `AHdrMetadata_cta861_3`. - */ -@VintfStability -parcelable Cta861_3 { - /** - * Maximum content light level. - */ - float maxContentLightLevel; - /** - * Maximum frame average light level. - */ - float maxFrameAverageLightLevel; -} diff --git a/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl b/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl deleted file mode 100644 index 60614cd9bb..0000000000 --- a/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl +++ /dev/null @@ -1,51 +0,0 @@ -/** - * 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. - */ - -package android.hardware.graphics.common; -import android.hardware.graphics.common.XyColor; - -/** - * Mastering display metadata as specified by SMPTE ST 2086. - * - * This is an AIDL counterpart of the NDK struct `AHdrMetadata_smpte2086`. - */ -@VintfStability -parcelable Smpte2086 { - /** - * CIE XYZ chromaticity for red in the RGB primaries. - */ - XyColor primaryRed; - /** - * CIE XYZ chromaticity for green in the RGB primaries. - */ - XyColor primaryGreen; - /** - * CIE XYZ chromaticity for blue in the RGB primaries. - */ - XyColor primaryBlue; - /** - * CIE XYZ chromaticity for the white point. - */ - XyColor whitePoint; - /** - * Maximum luminance in candelas per square meter. - */ - float maxLuminance; - /** - * Minimum luminance in candelas per square meter. - */ - float minLuminance; -} diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl index 68c99ee055..060d12c46e 100644 --- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl +++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl @@ -279,43 +279,4 @@ enum StandardMetadataType { * 4 bytes written in little endian. */ BLEND_MODE = 17, - - /** - * Can be used to get or set static HDR metadata specified by SMPTE ST 2086. - * - * This metadata is a stable aidl android.hardware.graphics.common.Smpte2086. - * - * This is not used in tone mapping until it has been set for the first time. - * - * When it is encoded into a byte stream, each float member is represented by 4 bytes written in - * little endian. The ordering of float values follows the definition of Smpte2086 and XyColor. - * If this is unset when encoded into a byte stream, the byte stream is empty. - */ - SMPTE2086 = 18, - - /** - * Can be used to get or set static HDR metadata specified by CTA 861.3. - * - * This metadata is a stable aidl android.hardware.graphics.common.Cta861_3. - * - * This is not used in tone mapping until it has been set for the first time. - * - * When it is encoded into a byte stream, each float member is represented by 4 bytes written in - * little endian. The ordering of float values follows the definition of Cta861_3. - * If this is unset when encoded into a byte stream, the byte stream is empty. - */ - CTA861_3 = 19, - - /** - * Can be used to get or set dynamic HDR metadata specified by SMPTE ST 2094-40:2016. - * - * This metadata is uint8_t byte array. - * - * This is not used in tone mapping until it has been set for the first time. - * - * When it is encoded into a byte stream, the length of the HDR metadata byte array is written - * using 8 bytes in little endian. It is followed by the uint8_t byte array. - * If this is unset when encoded into a byte stream, the byte stream is empty. - */ - SMPTE2094_40 = 20, } diff --git a/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl b/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl deleted file mode 100644 index 9571273d7d..0000000000 --- a/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl +++ /dev/null @@ -1,30 +0,0 @@ -/** - * 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. - */ - -package android.hardware.graphics.common; - -/** - * Chromaticity based on 2 parameters. - * - * This is an AIDL counterpart of the NDK struct `AColor_xy`. - * - * @note This can be used to represent any 2-dimensional chromaticity. - */ -@VintfStability -parcelable XyColor { - float x; - float y; -} diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal index 3be2152971..03dfef1e3f 100644 --- a/graphics/mapper/4.0/IMapper.hal +++ b/graphics/mapper/4.0/IMapper.hal @@ -478,7 +478,7 @@ interface IMapper { * particular Metadata field. * * The framework may attempt to set the following StandardMetadataType - * values: DATASPACE, SMPTE2086, CTA861_3, SMPTE2094_40 and BLEND_MODE. + * values: DATASPACE, PER_FRAME_METADATA, PER_FRAME_METADATA_BLOB and BLEND_MODE. * We strongly encourage everyone to support setting as many of those fields as * possible. If a device's Composer implementation supports a field, it should be * supported here. Over time these metadata fields will be moved out of diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 3b87bc261d..4a0aabf1a3 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -44,13 +44,11 @@ using android::hardware::graphics::common::V1_2::BufferUsage; using android::hardware::graphics::common::V1_2::PixelFormat; using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType; using aidl::android::hardware::graphics::common::BlendMode; -using aidl::android::hardware::graphics::common::Cta861_3; using aidl::android::hardware::graphics::common::Dataspace; using aidl::android::hardware::graphics::common::ExtendableType; using aidl::android::hardware::graphics::common::PlaneLayout; using aidl::android::hardware::graphics::common::PlaneLayoutComponent; using aidl::android::hardware::graphics::common::PlaneLayoutComponentType; -using aidl::android::hardware::graphics::common::Smpte2086; using aidl::android::hardware::graphics::common::StandardMetadataType; using DecodeFunction = std::function& vec) { - std::optional smpte2086; - ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086)); - EXPECT_FALSE(smpte2086.has_value()); - }); -} - -/** - * Test IMapper::get(Cta861_3) - */ -TEST_F(GraphicsMapperHidlTest, GetCta861_3) { - testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, - [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { - std::optional cta861_3; - ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3)); - EXPECT_FALSE(cta861_3.has_value()); - }); -} - -/** - * Test IMapper::get(Smpte2094_40) - */ -TEST_F(GraphicsMapperHidlTest, GetSmpte2094_40) { - testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_40, - [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { - std::optional> smpte2094_40; - ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40)); - EXPECT_FALSE(smpte2094_40.has_value()); - }); -} - /** * Test IMapper::get(metadata) with a bad buffer */ @@ -1110,15 +1072,6 @@ TEST_P(GraphicsMapperHidlTest, GetMetadataBadValue) { ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_BlendMode, &vec)); ASSERT_EQ(0, vec.size()); - ASSERT_EQ(Error::BAD_BUFFER, - mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2086, &vec)); - ASSERT_EQ(0, vec.size()); - ASSERT_EQ(Error::BAD_BUFFER, - mGralloc->get(bufferHandle, gralloc4::MetadataType_Cta861_3, &vec)); - ASSERT_EQ(0, vec.size()); - ASSERT_EQ(Error::BAD_BUFFER, - mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2094_40, &vec)); - ASSERT_EQ(0, vec.size()); } /** @@ -1474,90 +1427,6 @@ TEST_P(GraphicsMapperHidlTest, SetBlendMode) { }); } -/** - * Test IMapper::set(Smpte2086) - */ -TEST_F(GraphicsMapperHidlTest, SetSmpte2086) { - /** - * DISPLAY_P3 is a color space that uses the DCI_P3 primaries, - * the D65 white point and the SRGB transfer functions. - * Rendering Intent: Colorimetric - * Primaries: - * x y - * green 0.265 0.690 - * blue 0.150 0.060 - * red 0.680 0.320 - * white (D65) 0.3127 0.3290 - */ - std::optional smpte2086; - smpte2086->primaryRed.x = 0.680; - smpte2086->primaryRed.y = 0.320; - smpte2086->primaryGreen.x = 0.265; - smpte2086->primaryGreen.y = 0.690; - smpte2086->primaryBlue.x = 0.150; - smpte2086->primaryBlue.y = 0.060; - smpte2086->whitePoint.x = 0.3127; - smpte2086->whitePoint.y = 0.3290; - smpte2086->maxLuminance = 100.0; - smpte2086->minLuminance = 0.1; - - hidl_vec vec; - ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2086(smpte2086, &vec)); - - testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086, vec, - [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { - std::optional realSmpte2086; - ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &realSmpte2086)); - ASSERT_TRUE(realSmpte2086.has_value()); - EXPECT_EQ(smpte2086->primaryRed.x, realSmpte2086->primaryRed.x); - EXPECT_EQ(smpte2086->primaryRed.y, realSmpte2086->primaryRed.y); - EXPECT_EQ(smpte2086->primaryGreen.x, realSmpte2086->primaryGreen.x); - EXPECT_EQ(smpte2086->primaryGreen.y, realSmpte2086->primaryGreen.y); - EXPECT_EQ(smpte2086->primaryBlue.x, realSmpte2086->primaryBlue.x); - EXPECT_EQ(smpte2086->primaryBlue.y, realSmpte2086->primaryBlue.y); - EXPECT_EQ(smpte2086->whitePoint.x, realSmpte2086->whitePoint.x); - EXPECT_EQ(smpte2086->whitePoint.y, realSmpte2086->whitePoint.y); - EXPECT_EQ(smpte2086->maxLuminance, realSmpte2086->maxLuminance); - EXPECT_EQ(smpte2086->minLuminance, realSmpte2086->minLuminance); - }); -} - -/** - * Test IMapper::set(Cta8613) - */ -TEST_F(GraphicsMapperHidlTest, SetCta861_3) { - std::optional cta861_3; - cta861_3->maxContentLightLevel = 78.0; - cta861_3->maxFrameAverageLightLevel = 62.0; - - hidl_vec vec; - ASSERT_EQ(NO_ERROR, gralloc4::encodeCta861_3(cta861_3, &vec)); - - testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, vec, - [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { - std::optional realCta861_3; - ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &realCta861_3)); - ASSERT_TRUE(realCta861_3.has_value()); - EXPECT_EQ(cta861_3->maxContentLightLevel, realCta861_3->maxContentLightLevel); - EXPECT_EQ(cta861_3->maxFrameAverageLightLevel, - realCta861_3->maxFrameAverageLightLevel); - }); -} - -/** - * Test IMapper::set(Smpte2094_40) - */ -TEST_F(GraphicsMapperHidlTest, SetSmpte2094_40) { - hidl_vec vec; - - testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_40, vec, - [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { - std::optional> realSmpte2094_40; - ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &realSmpte2094_40)); - EXPECT_FALSE(realSmpte2094_40.has_value()); - }); -} - /** * Test IMapper::set(metadata) with a bad buffer */ @@ -1593,11 +1462,6 @@ TEST_P(GraphicsMapperHidlTest, SetMetadataNullBuffer) { mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec)); ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec)); - ASSERT_EQ(Error::BAD_BUFFER, - mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec)); - ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec)); - ASSERT_EQ(Error::BAD_BUFFER, - mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2094_40, vec)); } /** @@ -1657,10 +1521,6 @@ TEST_P(GraphicsMapperHidlTest, SetBadMetadata) { mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec)); ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec)); - ASSERT_EQ(Error::UNSUPPORTED, - mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec)); - ASSERT_EQ(Error::UNSUPPORTED, - mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec)); } /** @@ -1892,45 +1752,6 @@ TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBlendMode) { EXPECT_EQ(BlendMode::INVALID, blendMode); } -/** - * Test IMapper::getFromBufferDescriptorInfo(Smpte2086) - */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2086) { - hidl_vec vec; - ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( - mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086, &vec)); - - std::optional smpte2086; - ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086)); - EXPECT_FALSE(smpte2086.has_value()); -} - -/** - * Test IMapper::getFromBufferDescriptorInfo(Cta861_3) - */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCta861_3) { - hidl_vec vec; - ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( - mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, &vec)); - - std::optional cta861_3; - ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3)); - EXPECT_FALSE(cta861_3.has_value()); -} - -/** - * Test IMapper::getFromBufferDescriptorInfo(Smpte2094_40) - */ -TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2094_40) { - hidl_vec vec; - ASSERT_EQ(Error::NONE, - mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, - gralloc4::MetadataType_Smpte2094_40, &vec)); - std::optional> smpte2094_40; - ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40)); - EXPECT_FALSE(smpte2094_40.has_value()); -} - /** * Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported metadata */ From 7fd5cc3a4b631abfd466088da70877fd6d104452 Mon Sep 17 00:00:00 2001 From: Sasha Kuznetsov Date: Mon, 9 Dec 2019 17:11:08 -0800 Subject: [PATCH 0355/1022] Fix 2.0 VTS and 2.1 HAL/default implementation Test: atest VtsHalGnssV2_0TargetTest && atest VtsHalGnssV2_1TargetTest Bug: 145830353, 146216289 Change-Id: I77d614783ee5451368a0e93eddc5e71c571193ed --- gnss/1.1/vts/functional/gnss_hal_test.cpp | 9 ++- gnss/2.0/vts/functional/gnss_hal_test.cpp | 27 ++++++- gnss/2.0/vts/functional/gnss_hal_test.h | 6 ++ .../vts/functional/gnss_hal_test_cases.cpp | 16 +++- gnss/2.1/default/Android.bp | 3 +- gnss/2.1/default/Gnss.cpp | 35 ++++++--- gnss/2.1/default/GnssMeasurement.cpp | 51 ++++++++++--- gnss/2.1/default/GnssMeasurement.h | 5 +- .../default/GnssMeasurementCorrections.cpp | 75 +++++++++++++++++++ gnss/2.1/default/GnssMeasurementCorrections.h | 49 ++++++++++++ 10 files changed, 248 insertions(+), 28 deletions(-) create mode 100644 gnss/2.1/default/GnssMeasurementCorrections.cpp create mode 100644 gnss/2.1/default/GnssMeasurementCorrections.h diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp index 24de37d0e2..88fbff8164 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test.cpp +++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp @@ -172,7 +172,14 @@ bool GnssHalTest::IsGnssHalVersion_1_1() const { hasGnssHalVersion_2_0 = registered.size() != 0; }); - return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0; + bool hasGnssHalVersion_2_1 = false; + manager->listManifestByInterface( + "android.hardware.gnss@2.1::IGnss", + [&hasGnssHalVersion_2_1](const hidl_vec& registered) { + hasGnssHalVersion_2_1 = registered.size() != 0; + }); + + return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0 && !hasGnssHalVersion_2_1; } GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation( diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp index 8ca3f684a3..b3a3203214 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test.cpp +++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp @@ -16,11 +16,14 @@ #define LOG_TAG "GnssHalTest" +#include #include +#include +#include #include #include "Utils.h" -#include +using ::android::hardware::hidl_string; using ::android::hardware::gnss::common::Utils; @@ -99,7 +102,6 @@ bool GnssHalTest::StartAndCheckFirstLocation() { EXPECT_TRUE(result.isOk()); EXPECT_TRUE(result); - /* * GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS, * so allow time to demodulate ephemeris over the air. @@ -148,6 +150,27 @@ void GnssHalTest::StartAndCheckLocations(int count) { } } +bool GnssHalTest::IsGnssHalVersion_2_0() const { + using ::android::hidl::manager::V1_2::IServiceManager; + sp manager = ::android::hardware::defaultServiceManager1_2(); + + bool hasGnssHalVersion_2_0 = false; + manager->listManifestByInterface( + "android.hardware.gnss@2.0::IGnss", + [&hasGnssHalVersion_2_0](const hidl_vec& registered) { + hasGnssHalVersion_2_0 = registered.size() != 0; + }); + + bool hasGnssHalVersion_2_1 = false; + manager->listManifestByInterface( + "android.hardware.gnss@2.1::IGnss", + [&hasGnssHalVersion_2_1](const hidl_vec& registered) { + hasGnssHalVersion_2_1 = registered.size() != 0; + }); + + return hasGnssHalVersion_2_0 && !hasGnssHalVersion_2_1; +} + GnssHalTest::GnssCallback::GnssCallback() : info_cbq_("system_info"), name_cbq_("name"), diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h index 4f7b87a485..55dc1bc4f6 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test.h +++ b/gnss/2.0/vts/functional/gnss_hal_test.h @@ -180,6 +180,12 @@ class GnssHalTest : public testing::TestWithParam { */ void StopAndClearLocations(); + /* + * IsGnssHalVersion_2_0: + * returns true if the GNSS HAL version is exactly 2.0. + */ + bool IsGnssHalVersion_2_0() const; + /* * SetPositionMode: * Helper function to set positioning mode and verify output 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 c442cc6bf8..0fa08b903e 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp @@ -182,6 +182,10 @@ TEST_P(GnssHalTest, TestAGnssRil_UpdateNetworkState_2_0) { * 3. state is valid. */ TEST_P(GnssHalTest, TestGnssMeasurementFields) { + if (!IsGnssHalVersion_2_0()) { + ALOGI("Test GnssMeasurementFields skipped. GNSS HAL version is greater than 2.0."); + return; + } const int kFirstGnssMeasurementTimeoutSeconds = 10; auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0(); @@ -464,7 +468,7 @@ TEST_P(GnssHalTest, GetLocationLowPower) { } EXPECT_LE(location_called_count, i); if (location_called_count != i) { - ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ", + ALOGW("GetLocationLowPower test - too many locations received. %d vs. %d expected ", location_called_count, i); } @@ -601,6 +605,11 @@ IGnssConfiguration_1_1::BlacklistedSource FindStrongFrequentNonGpsSource( * formerly strongest satellite */ TEST_P(GnssHalTest, BlacklistIndividualSatellites) { + if (!IsGnssHalVersion_2_0()) { + ALOGI("Test BlacklistIndividualSatellites skipped. GNSS HAL version is greater than 2.0."); + return; + } + if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) { ALOGI("Test BlacklistIndividualSatellites skipped. SATELLITE_BLACKLIST capability" " not supported."); @@ -746,6 +755,11 @@ TEST_P(GnssHalTest, BlacklistIndividualSatellites) { * 4a & b) Clean up by turning off location, and send in empty blacklist. */ TEST_P(GnssHalTest, BlacklistConstellation) { + 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; diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp index 57233aa6cb..7ef999081e 100644 --- a/gnss/2.1/default/Android.bp +++ b/gnss/2.1/default/Android.bp @@ -23,8 +23,9 @@ cc_binary { srcs: [ "Gnss.cpp", "GnssMeasurement.cpp", + "GnssMeasurementCorrections.cpp", "GnssConfiguration.cpp", - "service.cpp" + "service.cpp", ], shared_libs: [ "libhidlbase", diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp index fd7a9dfd0d..6b61a827d0 100644 --- a/gnss/2.1/default/Gnss.cpp +++ b/gnss/2.1/default/Gnss.cpp @@ -18,11 +18,14 @@ #include "Gnss.h" #include "GnssMeasurement.h" +#include "GnssMeasurementCorrections.h" #include "Utils.h" #include using ::android::hardware::gnss::common::Utils; +using ::android::hardware::gnss::measurement_corrections::V1_0::implementation:: + GnssMeasurementCorrections; namespace android { namespace hardware { @@ -87,7 +90,8 @@ Return Gnss::setCallback(const sp&) { } Return Gnss::cleanup() { - // TODO implement + sGnssCallback_2_1 = nullptr; + sGnssCallback_2_0 = nullptr; return Void(); } @@ -170,8 +174,9 @@ Return Gnss::setCallback_1_1(const sp&) { } Return Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode, - V1_0::IGnss::GnssPositionRecurrence, uint32_t, uint32_t, - uint32_t, bool) { + V1_0::IGnss::GnssPositionRecurrence, uint32_t minIntervalMs, + uint32_t, uint32_t, bool) { + mMinIntervalMs = minIntervalMs; return true; } @@ -215,7 +220,7 @@ Return Gnss::setCallback_2_0(const sp& callback) { ALOGE("%s: Unable to invoke callback", __func__); } - auto gnssName = "Google Mock GNSS Implementation v2.0"; + auto gnssName = "Google Mock GNSS Implementation v2.1"; ret = sGnssCallback_2_0->gnssNameCb(gnssName); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); @@ -251,8 +256,8 @@ Return> Gnss::getExtensionGnssMeasurement_2_0() { Return> Gnss::getExtensionMeasurementCorrections() { - // TODO implement - return ::android::sp{}; + ALOGD("Gnss::getExtensionMeasurementCorrections()"); + return new GnssMeasurementCorrections(); } Return> Gnss::getExtensionVisibilityControl() { @@ -266,7 +271,7 @@ Return> Gnss::getExtensionGnssBatching_2_0() { } Return Gnss::injectBestLocation_2_0(const V2_0::GnssLocation&) { - // TODO implement + // TODO(b/124012850): Implement function. return bool{}; } @@ -316,6 +321,7 @@ Return> Gnss::getExtensionGnssConfiguration_2_1() { void Gnss::reportSvStatus(const hidl_vec& svInfoList) const { std::unique_lock lock(mMutex); + // TODO(skz): update this to call 2_0 callback if non-null if (sGnssCallback_2_1 == nullptr) { ALOGE("%s: sGnssCallback v2.1 is null.", __func__); return; @@ -328,13 +334,20 @@ void Gnss::reportSvStatus(const hidl_vec& svInfoList) const { void Gnss::reportLocation(const V2_0::GnssLocation& location) const { std::unique_lock lock(mMutex); - if (sGnssCallback_2_1 == nullptr) { - ALOGE("%s: sGnssCallback v2.1 is null.", __func__); + if (sGnssCallback_2_1 != nullptr) { + auto ret = sGnssCallback_2_1->gnssLocationCb_2_0(location); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback v2.1", __func__); + } return; } - auto ret = sGnssCallback_2_1->gnssLocationCb_2_0(location); + if (sGnssCallback_2_0 == nullptr) { + ALOGE("%s: No non-null callback", __func__); + return; + } + auto ret = sGnssCallback_2_0->gnssLocationCb_2_0(location); if (!ret.isOk()) { - ALOGE("%s: Unable to invoke callback", __func__); + ALOGE("%s: Unable to invoke callback v2.0", __func__); } } diff --git a/gnss/2.1/default/GnssMeasurement.cpp b/gnss/2.1/default/GnssMeasurement.cpp index ebfa7ddf1d..34e20e5790 100644 --- a/gnss/2.1/default/GnssMeasurement.cpp +++ b/gnss/2.1/default/GnssMeasurement.cpp @@ -29,7 +29,8 @@ using common::Utils; namespace V2_1 { namespace implementation { -sp GnssMeasurement::sCallback = nullptr; +sp GnssMeasurement::sCallback_2_1 = nullptr; +sp GnssMeasurement::sCallback_2_0 = nullptr; GnssMeasurement::GnssMeasurement() : mMinIntervalMillis(1000) {} @@ -48,7 +49,8 @@ Return GnssMeasurement::close() { ALOGD("close"); std::unique_lock lock(mMutex); stop(); - sCallback = nullptr; + sCallback_2_1 = nullptr; + sCallback_2_0 = nullptr; return Void(); } @@ -61,9 +63,18 @@ Return GnssMeasurement::setCallba // Methods from V2_0::IGnssMeasurement follow. Return GnssMeasurement::setCallback_2_0( - const sp&, bool) { - // TODO implement - return V1_0::IGnssMeasurement::GnssMeasurementStatus{}; + const sp& callback, bool) { + ALOGD("setCallback_2_0"); + std::unique_lock lock(mMutex); + sCallback_2_0 = callback; + + if (mIsActive) { + ALOGW("GnssMeasurement callback already set. Resetting the callback..."); + stop(); + } + start(); + + return V1_0::IGnssMeasurement::GnssMeasurementStatus::SUCCESS; } // Methods from V2_1::IGnssMeasurement follow. @@ -71,7 +82,7 @@ Return GnssMeasurement::setCallba const sp& callback, bool) { ALOGD("setCallback_2_1"); std::unique_lock lock(mMutex); - sCallback = callback; + sCallback_2_1 = callback; if (mIsActive) { ALOGW("GnssMeasurement callback already set. Resetting the callback..."); @@ -87,8 +98,13 @@ void GnssMeasurement::start() { mIsActive = true; mThread = std::thread([this]() { while (mIsActive == true) { - auto measurement = Utils::getMockMeasurementV2_1(); - this->reportMeasurement(measurement); + if (sCallback_2_1 != nullptr) { + auto measurement = Utils::getMockMeasurementV2_1(); + this->reportMeasurement(measurement); + } else { + auto measurement = Utils::getMockMeasurementV2_0(); + this->reportMeasurement(measurement); + } std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis)); } @@ -103,14 +119,27 @@ void GnssMeasurement::stop() { } } +void GnssMeasurement::reportMeasurement(const GnssDataV2_0& data) { + ALOGD("reportMeasurement()"); + std::unique_lock lock(mMutex); + if (sCallback_2_0 == nullptr) { + ALOGE("%s: GnssMeasurement::sCallback_2_0 is null.", __func__); + return; + } + auto ret = sCallback_2_0->gnssMeasurementCb_2_0(data); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + void GnssMeasurement::reportMeasurement(const GnssDataV2_1& data) { ALOGD("reportMeasurement()"); std::unique_lock lock(mMutex); - if (sCallback == nullptr) { - ALOGE("%s: GnssMeasurement::sCallback is null.", __func__); + if (sCallback_2_1 == nullptr) { + ALOGE("%s: GnssMeasurement::sCallback_2_1 is null.", __func__); return; } - auto ret = sCallback->gnssMeasurementCb_2_1(data); + auto ret = sCallback_2_1->gnssMeasurementCb_2_1(data); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); } diff --git a/gnss/2.1/default/GnssMeasurement.h b/gnss/2.1/default/GnssMeasurement.h index ee329039d9..3ed7bc597d 100644 --- a/gnss/2.1/default/GnssMeasurement.h +++ b/gnss/2.1/default/GnssMeasurement.h @@ -30,6 +30,7 @@ namespace V2_1 { namespace implementation { using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData; +using GnssDataV2_0 = V2_0::IGnssMeasurementCallback::GnssData; using ::android::sp; using ::android::hardware::hidl_array; @@ -62,9 +63,11 @@ struct GnssMeasurement : public IGnssMeasurement { private: void start(); void stop(); + void reportMeasurement(const GnssDataV2_0&); void reportMeasurement(const GnssDataV2_1&); - static sp sCallback; + static sp sCallback_2_1; + static sp sCallback_2_0; std::atomic mMinIntervalMillis; std::atomic mIsActive; std::thread mThread; diff --git a/gnss/2.1/default/GnssMeasurementCorrections.cpp b/gnss/2.1/default/GnssMeasurementCorrections.cpp new file mode 100644 index 0000000000..2bf5601820 --- /dev/null +++ b/gnss/2.1/default/GnssMeasurementCorrections.cpp @@ -0,0 +1,75 @@ +/* + * 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 "GnssMeasurementCorrections" + +#include "GnssMeasurementCorrections.h" +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace measurement_corrections { +namespace V1_0 { +namespace implementation { + +// Methods from V1_0::IMeasurementCorrections follow. +Return GnssMeasurementCorrections::setCorrections(const MeasurementCorrections& corrections) { + ALOGD("setCorrections"); + ALOGD("corrections = lat: %f, lng: %f, alt: %f, hUnc: %f, vUnc: %f, toa: %llu, " + "satCorrections.size: %d", + corrections.latitudeDegrees, corrections.longitudeDegrees, corrections.altitudeMeters, + corrections.horizontalPositionUncertaintyMeters, + corrections.verticalPositionUncertaintyMeters, + static_cast(corrections.toaGpsNanosecondsOfWeek), + static_cast(corrections.satCorrections.size())); + for (auto singleSatCorrection : corrections.satCorrections) { + ALOGD("singleSatCorrection = flags: %d, constellation: %d, svid: %d, cfHz: %f, probLos: %f," + " epl: %f, eplUnc: %f", + static_cast(singleSatCorrection.singleSatCorrectionFlags), + static_cast(singleSatCorrection.constellation), + static_cast(singleSatCorrection.svid), singleSatCorrection.carrierFrequencyHz, + singleSatCorrection.probSatIsLos, singleSatCorrection.excessPathLengthMeters, + singleSatCorrection.excessPathLengthUncertaintyMeters); + ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f", + singleSatCorrection.reflectingPlane.latitudeDegrees, + singleSatCorrection.reflectingPlane.longitudeDegrees, + singleSatCorrection.reflectingPlane.altitudeMeters, + singleSatCorrection.reflectingPlane.azimuthDegrees); + } + + return true; +} + +Return GnssMeasurementCorrections::setCallback( + const sp& callback) { + using Capabilities = V1_0::IMeasurementCorrectionsCallback::Capabilities; + auto ret = + callback->setCapabilitiesCb(Capabilities::LOS_SATS | Capabilities::EXCESS_PATH_LENGTH | + Capabilities::REFLECTING_PLANE); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + return false; + } + return true; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace measurement_corrections +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/2.1/default/GnssMeasurementCorrections.h b/gnss/2.1/default/GnssMeasurementCorrections.h new file mode 100644 index 0000000000..4339bed55d --- /dev/null +++ b/gnss/2.1/default/GnssMeasurementCorrections.h @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace measurement_corrections { +namespace V1_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +struct GnssMeasurementCorrections : public IMeasurementCorrections { + // Methods from V1_0::IMeasurementCorrections follow. + Return setCorrections(const MeasurementCorrections& corrections) override; + Return setCallback(const sp& callback) override; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace measurement_corrections +} // namespace gnss +} // namespace hardware +} // namespace android From c828cff678ae6a58f4e3c3e67eecb5f4866ffb1f Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Fri, 15 Nov 2019 19:36:03 -0800 Subject: [PATCH 0356/1022] Wifi-hostapd: Add 6GHz impacts to softAP This commit adds changes needed to support the 6GHz band to SoftAP. Bug: 139354972 Test: Manual Test: VTS test Change-Id: Ib4e14facc7cbb54ba89ecf07e75df8dceacb361f --- current.txt | 2 +- wifi/hostapd/1.2/IHostapd.hal | 81 +++++++ .../1.2/vts/functional/hostapd_hidl_test.cpp | 209 +++++++++++++++++- 3 files changed, 281 insertions(+), 11 deletions(-) diff --git a/current.txt b/current.txt index 1fe17d5ca4..91ab339739 100644 --- a/current.txt +++ b/current.txt @@ -649,7 +649,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback cf1d55e8c68300090747ab90b94c22e4c859b29c84ced68a317c595bb115eab2 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi -03d37dfebbc27b13adce1ed6389ac483bf7cf32488ca14037c5569bc3e903e4f android.hardware.wifi.hostapd@1.2::IHostapd +36b3acf78ac4ecf8156be8741c1d8332cdce7a1ebf4dfa1562952f14a94e6c87 android.hardware.wifi.hostapd@1.2::IHostapd 2defa258951e25a132aaeb36e3febe6f41bf9c6dbb1b1ebdf0b41708ab4e107e android.hardware.wifi.hostapd@1.2::types a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant 44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface diff --git a/wifi/hostapd/1.2/IHostapd.hal b/wifi/hostapd/1.2/IHostapd.hal index 31ade13ab8..1bac1e7897 100644 --- a/wifi/hostapd/1.2/IHostapd.hal +++ b/wifi/hostapd/1.2/IHostapd.hal @@ -16,6 +16,7 @@ package android.hardware.wifi.hostapd@1.2; +import @1.0::IHostapd.NetworkParams; import @1.1::IHostapd; import HostapdStatus; import MacAddress; @@ -25,6 +26,86 @@ import Ieee80211ReasonCode; * Top-level object for managing SoftAPs. */ interface IHostapd extends @1.1::IHostapd { + /** + * Band bitmMask to use for the SoftAp operations. + * A combinatoin of these bits are used to identify the allowed bands + * to start the softAp + */ + enum BandMask : uint32_t { + /** + * 2.4 GHz band. + */ + BAND_2_GHZ = 1 << 0, + /** + * 5 GHz band. + */ + BAND_5_GHZ = 1 << 1, + /** + * 6 GHz band. + */ + BAND_6_GHZ = 1 << 2, + }; + + /** + * Parameters to control the HW mode for the interface. + */ + struct HwModeParams { + /** + * Whether IEEE 802.11ax (HE) is enabled or not. + * Note: hw_mode=a is used to specify that 5 GHz band or 6 GHz band is + * used with HE. + */ + bool enable80211AX; + /** + * Whether 6GHz band enabled or not on softAp. + * Note: hw_mode=a is used to specify that 5 GHz band or 6 GHz band is + * used. + */ + bool enable6GhzBand; + }; + + /** + * Parameters to control the channel selection for the interface. + */ + struct ChannelParams { + /** + * Band to use for the SoftAp operations. + */ + bitfield bandMask; + }; + + /** + * Parameters to use for setting up the access point interface. + */ + struct IfaceParams { + /** + * Baseline information as defined in HAL 1.1. + */ + @1.1::IHostapd.IfaceParams V1_1; + /** Additional Hw mode params for the interface */ + HwModeParams hwModeParams; + /** Additional Channel params for the interface */ + ChannelParams channelParams; + }; + + /** + * Adds a new access point for hostapd to control. + * + * This should trigger the setup of an access point with the specified + * interface and network params. + * + * @param ifaceParams AccessPoint Params for the access point. + * @param nwParams Network Params for the access point. + * @return status Status of the operation. + * Possible status codes: + * |HostapdStatusCode.SUCCESS|, + * |HostapdStatusCode.FAILURE_ARGS_INVALID|, + * |HostapdStatusCode.FAILURE_UNKNOWN|, + * |HostapdStatusCode.FAILURE_IFACE_EXISTS| + */ + addAccessPoint_1_2(IfaceParams ifaceParams, NetworkParams nwParams) + generates(HostapdStatus status); + /** * force one of the hotspot clients disconnect.. * diff --git a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp index 0d372213ce..b092d000ef 100644 --- a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp +++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp @@ -39,7 +39,9 @@ using ::android::hardware::wifi::V1_0::IWifi; namespace { constexpr unsigned char kNwSsid[] = {'t', 'e', 's', 't', '1', '2', '3', '4', '5'}; +constexpr char kNwPassphrase[] = "test12345"; constexpr int kIfaceChannel = 6; +constexpr int kIfaceInvalidChannel = 567; constexpr uint8_t kTestZeroMacAddr[] = {[0 ... 5] = 0x0}; constexpr Ieee80211ReasonCode kTestDisconnectReasonCode = Ieee80211ReasonCode::WLAN_REASON_UNSPECIFIED; @@ -73,7 +75,9 @@ class HostapdHidlTest IHostapd::IfaceParams getIfaceParamsWithoutAcs() { ::android::hardware::wifi::hostapd::V1_0::IHostapd::IfaceParams iface_params; - IHostapd::IfaceParams iface_params_1_1; + ::android::hardware::wifi::hostapd::V1_1::IHostapd::IfaceParams + iface_params_1_1; + IHostapd::IfaceParams iface_params_1_2; iface_params.ifaceName = getPrimaryWlanIfaceName(); iface_params.hwModeParams.enable80211N = true; @@ -81,9 +85,52 @@ class HostapdHidlTest iface_params.channelParams.enableAcs = false; iface_params.channelParams.acsShouldExcludeDfs = false; iface_params.channelParams.channel = kIfaceChannel; - iface_params.channelParams.band = IHostapd::Band::BAND_2_4_GHZ; iface_params_1_1.V1_0 = iface_params; - return iface_params_1_1; + iface_params_1_2.V1_1 = iface_params_1_1; + // Newly added attributes in V1_2 + iface_params_1_2.hwModeParams.enable80211AX = false; + iface_params_1_2.hwModeParams.enable6GhzBand = false; + iface_params_1_2.channelParams.bandMask = 0; + iface_params_1_2.channelParams.bandMask |= + IHostapd::BandMask::BAND_2_GHZ; + return iface_params_1_2; + } + + IHostapd::IfaceParams getIfaceParamsWithAcs() { + // First get the settings for WithoutAcs and then make changes + IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithoutAcs(); + iface_params_1_2.V1_1.V1_0.channelParams.enableAcs = true; + iface_params_1_2.V1_1.V1_0.channelParams.acsShouldExcludeDfs = true; + iface_params_1_2.V1_1.V1_0.channelParams.channel = 0; + iface_params_1_2.channelParams.bandMask |= + IHostapd::BandMask::BAND_5_GHZ; + + return iface_params_1_2; + } + + IHostapd::IfaceParams getIfaceParamsWithAcsAndChannelRange() { + IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithAcs(); + ::android::hardware::wifi::hostapd::V1_1::IHostapd::ChannelParams + channelParams; + ::android::hardware::wifi::hostapd::V1_1::IHostapd::AcsChannelRange + acsChannelRange; + acsChannelRange.start = 1; + acsChannelRange.end = 11; + std::vector< + ::android::hardware::wifi::hostapd::V1_1::IHostapd::AcsChannelRange> + vec_acsChannelRange; + vec_acsChannelRange.push_back(acsChannelRange); + channelParams.acsChannelRanges = vec_acsChannelRange; + iface_params_1_2.V1_1.channelParams = channelParams; + return iface_params_1_2; + } + + IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidChannelRange() { + IHostapd::IfaceParams iface_params_1_2 = + getIfaceParamsWithAcsAndChannelRange(); + iface_params_1_2.V1_1.channelParams.acsChannelRanges[0].start = 222; + iface_params_1_2.V1_1.channelParams.acsChannelRanges[0].end = 999; + return iface_params_1_2; } IHostapd::NetworkParams getOpenNwParams() { @@ -95,12 +142,156 @@ class HostapdHidlTest return nw_params; } + IHostapd::NetworkParams getPskNwParams() { + IHostapd::NetworkParams nw_params; + nw_params.ssid = + std::vector(kNwSsid, kNwSsid + sizeof(kNwSsid)); + nw_params.isHidden = false; + nw_params.encryptionType = IHostapd::EncryptionType::WPA2; + nw_params.pskPassphrase = kNwPassphrase; + return nw_params; + } + + IHostapd::NetworkParams getInvalidPskNwParams() { + IHostapd::NetworkParams nw_params; + nw_params.ssid = + std::vector(kNwSsid, kNwSsid + sizeof(kNwSsid)); + nw_params.isHidden = false; + nw_params.encryptionType = IHostapd::EncryptionType::WPA2; + return nw_params; + } + + IHostapd::IfaceParams getIfaceParamsWithInvalidChannel() { + IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithoutAcs(); + iface_params_1_2.V1_1.V1_0.channelParams.channel = kIfaceInvalidChannel; + return iface_params_1_2; + } + // IHostapd object used for all tests in this fixture. sp hostapd_; std::string wifi_instance_name_; std::string hostapd_instance_name_; }; +/** + * Adds an access point with PSK network config & ACS enabled. + * Access point creation should pass. + */ +TEST_P(HostapdHidlTest, AddPskAccessPointWithAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, + getIfaceParamsWithAcs(), getPskNwParams()); + // TODO: b/140172237, fix this in R. + // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with PSK network config, ACS enabled & channel Range. + * Access point creation should pass. + */ +TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndChannelRange) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint_1_2, + getIfaceParamsWithAcsAndChannelRange(), getPskNwParams()); + // TODO: b/140172237, fix this in R + // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with invalid channel range. + * Access point creation should fail. + */ +TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidChannelRange) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, + getIfaceParamsWithAcsAndInvalidChannelRange(), + getPskNwParams()); + // TODO: b/140172237, fix this in R + // EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with Open network config & ACS enabled. + * Access point creation should pass. + */ +TEST_P(HostapdHidlTest, AddOpenAccessPointWithAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, + getIfaceParamsWithAcs(), getOpenNwParams()); + // TODO: b/140172237, fix this in R + // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with PSK network config & ACS disabled. + * Access point creation should pass. + */ +TEST_P(HostapdHidlTest, AddPskAccessPointWithoutAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, + getIfaceParamsWithoutAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with Open network config & ACS disabled. + * Access point creation should pass. + */ +TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, + getIfaceParamsWithoutAcs(), getOpenNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds & then removes an access point with PSK network config & ACS enabled. + * Access point creation & removal should pass. + */ +TEST_P(HostapdHidlTest, RemoveAccessPointWithAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, + getIfaceParamsWithAcs(), getPskNwParams()); + // TODO: b/140172237, fix this in R + /* + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + status = + HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + */ +} + +/** + * Adds & then removes an access point with PSK network config & ACS disabled. + * Access point creation & removal should pass. + */ +TEST_P(HostapdHidlTest, RemoveAccessPointWithoutAcs) { + auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, + getIfaceParamsWithoutAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code); + auto status = + HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); + EXPECT_EQ( + android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS, + status.code); +} + +/** + * Adds an access point with invalid channel. + * Access point creation should fail. + */ +TEST_P(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint_1_2, + getIfaceParamsWithInvalidChannel(), getPskNwParams()); + EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with invalid PSK network config. + * Access point creation should fail. + */ +TEST_P(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(), + getInvalidPskNwParams()); + EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); +} + /** * forceClientDisconnect should return FAILURE_IFACE_UNKNOWN * when hotspot interface doesn't init.. @@ -117,14 +308,12 @@ TEST_P(HostapdHidlTest, DisconnectClientWhenIfaceNotAvailable) { * when hotspot interface available. */ TEST_P(HostapdHidlTest, DisconnectClientWhenIfacAvailable) { - auto status_1_0 = - HIDL_INVOKE(hostapd_, addAccessPoint_1_1, getIfaceParamsWithoutAcs(), - getOpenNwParams()); - EXPECT_EQ( - android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS, - status_1_0.code); - auto status_1_2 = + HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(), + getOpenNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code); + + status_1_2 = HIDL_INVOKE(hostapd_, forceClientDisconnect, getPrimaryWlanIfaceName(), kTestZeroMacAddr, kTestDisconnectReasonCode); EXPECT_EQ(HostapdStatusCode::FAILURE_CLIENT_UNKNOWN, status_1_2.code); From d5f570e7d791f6777e808fde6d7f7dffad14353d Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Tue, 3 Dec 2019 18:13:01 -0800 Subject: [PATCH 0357/1022] Tuner HAL minor corrections Test: Manual bug: 135708935 Change-Id: I2f74b2a4266ea86a80dab8b729bf57a78319b207 --- tv/tuner/1.0/IFilter.hal | 2 +- tv/tuner/1.0/types.hal | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tv/tuner/1.0/IFilter.hal b/tv/tuner/1.0/IFilter.hal index 3ed09f6db5..94e3c0ce26 100644 --- a/tv/tuner/1.0/IFilter.hal +++ b/tv/tuner/1.0/IFilter.hal @@ -104,11 +104,11 @@ interface IFilter { * * It is used by the client to ask the hardware resource id for the filter. * - * @param filterId the hardware resource Id for the filter. * @return result Result status of the operation. * SUCCESS if successful, * INVALID_STATE if failed for wrong state. * UNKNOWN_ERROR if failed for other reasons. + * @return filterId the hardware resource Id for the filter. */ getId() generates (Result result, uint32_t filterId); diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index 707f5dfa60..1dea04e552 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -2230,8 +2230,6 @@ struct DemuxIpFilterSettings { DemuxFilterSectionSettings section; - DemuxFilterPesDataSettings pesData; - /** * true if the data from IP subtype go to next filter directly */ @@ -2248,7 +2246,7 @@ struct DemuxTlvFilterSettings { /** * true if the filtered data is commpressed ip packet */ - bool bIsCompressedIpPacket; + bool isCompressedIpPacket; safe_union FilterSettings { /** From 5ed13574aa41138358ad040ebd62daad8b4497c0 Mon Sep 17 00:00:00 2001 From: Amy Date: Wed, 11 Dec 2019 15:33:51 -0800 Subject: [PATCH 0358/1022] Adding a DVR Record default implementation in Tuner HAL 1.0 Test: cuttlefish Bug: 135709325 Change-Id: I415426d6ec048bdd2ae61a3c5142ad02f1d7f1e4 --- tv/tuner/1.0/default/Demux.cpp | 112 +++++++++++++++++++++++++------- tv/tuner/1.0/default/Demux.h | 39 ++++++++--- tv/tuner/1.0/default/Dvr.cpp | 65 +++++++++++++++++- tv/tuner/1.0/default/Dvr.h | 15 ++++- tv/tuner/1.0/default/Filter.cpp | 51 ++++++++++++--- tv/tuner/1.0/default/Filter.h | 13 +++- tv/tuner/1.0/default/Tuner.cpp | 2 +- 7 files changed, 247 insertions(+), 50 deletions(-) diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp index 71a26ab6ec..43c4e3a086 100644 --- a/tv/tuner/1.0/default/Demux.cpp +++ b/tv/tuner/1.0/default/Demux.cpp @@ -51,7 +51,8 @@ Return Demux::setFrontendDataSource(uint32_t frontendId) { mFrontendSourceFile = mFrontend->getSourceFile(); mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId); - return startBroadcastInputLoop(); + + return startFrontendInputLoop(); } Return Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize, @@ -136,14 +137,14 @@ Return Demux::openDvr(DvrType type, uint32_t bufferSize, const sp dvr = new Dvr(type, bufferSize, cb, this); + mDvr = new Dvr(type, bufferSize, cb, this); - if (!dvr->createDvrMQ()) { - _hidl_cb(Result::UNKNOWN_ERROR, dvr); + if (!mDvr->createDvrMQ()) { + _hidl_cb(Result::UNKNOWN_ERROR, mDvr); return Void(); } - _hidl_cb(Result::SUCCESS, dvr); + _hidl_cb(Result::SUCCESS, mDvr); return Void(); } @@ -166,13 +167,14 @@ Result Demux::removeFilter(uint32_t filterId) { // resetFilterRecords(filterId); mUsedFilterIds.erase(filterId); + mRecordFilterIds.erase(filterId); mUnusedFilterIds.insert(filterId); mFilters.erase(filterId); return Result::SUCCESS; } -void Demux::startTsFilter(vector data) { +void Demux::startBroadcastTsFilter(vector data) { set::iterator it; for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff)); @@ -185,7 +187,17 @@ void Demux::startTsFilter(vector data) { } } -bool Demux::startFilterDispatcher() { +void Demux::sendFrontendInputToRecord(vector data) { + set::iterator it; + for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) { + if (DEBUG_FILTER) { + ALOGW("update record filter output"); + } + mFilters[*it]->updateRecordOutput(data); + } +} + +bool Demux::startBroadcastFilterDispatcher() { set::iterator it; // Handle the output data per filter type @@ -198,6 +210,18 @@ bool Demux::startFilterDispatcher() { return true; } +bool Demux::startRecordFilterDispatcher() { + set::iterator it; + + for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) { + if (mFilters[*it]->startRecordFilterHandler() != Result::SUCCESS) { + return false; + } + } + + return true; +} + Result Demux::startFilterHandler(uint32_t filterId) { return mFilters[filterId]->startFilterHandler(); } @@ -210,22 +234,22 @@ uint16_t Demux::getFilterTpid(uint32_t filterId) { return mFilters[filterId]->getTpid(); } -Result Demux::startBroadcastInputLoop() { - pthread_create(&mBroadcastInputThread, NULL, __threadLoopBroadcast, this); - pthread_setname_np(mBroadcastInputThread, "broadcast_input_thread"); +Result Demux::startFrontendInputLoop() { + pthread_create(&mFrontendInputThread, NULL, __threadLoopFrontend, this); + pthread_setname_np(mFrontendInputThread, "frontend_input_thread"); return Result::SUCCESS; } -void* Demux::__threadLoopBroadcast(void* user) { +void* Demux::__threadLoopFrontend(void* user) { Demux* const self = static_cast(user); - self->broadcastInputThreadLoop(); + self->frontendInputThreadLoop(); return 0; } -void Demux::broadcastInputThreadLoop() { - std::lock_guard lock(mBroadcastInputThreadLock); - mBroadcastInputThreadRunning = true; +void Demux::frontendInputThreadLoop() { + std::lock_guard lock(mFrontendInputThreadLock); + mFrontendInputThreadRunning = true; mKeepFetchingDataFromFrontend = true; // open the stream and get its length @@ -234,20 +258,20 @@ void Demux::broadcastInputThreadLoop() { int packetSize = 188; int writePacketAmount = 6; char* buffer = new char[packetSize]; - ALOGW("[Demux] broadcast input thread loop start %s", mFrontendSourceFile.c_str()); + ALOGW("[Demux] Frontend input thread loop start %s", mFrontendSourceFile.c_str()); if (!inputData.is_open()) { - mBroadcastInputThreadRunning = false; + mFrontendInputThreadRunning = false; ALOGW("[Demux] Error %s", strerror(errno)); } - while (mBroadcastInputThreadRunning) { + while (mFrontendInputThreadRunning) { // move the stream pointer for packet size * 6 every read until the end while (mKeepFetchingDataFromFrontend) { for (int i = 0; i < writePacketAmount; i++) { inputData.read(buffer, packetSize); if (!inputData) { mKeepFetchingDataFromFrontend = false; - mBroadcastInputThreadRunning = false; + mFrontendInputThreadRunning = false; break; } // filter and dispatch filter output @@ -256,23 +280,61 @@ void Demux::broadcastInputThreadLoop() { for (int index = 0; index < byteBuffer.size(); index++) { byteBuffer[index] = static_cast(buffer[index]); } - startTsFilter(byteBuffer); + if (mIsRecording) { + // Feed the data into the Dvr recording input + sendFrontendInputToRecord(byteBuffer); + } else { + // Feed the data into the broadcast demux filter + startBroadcastTsFilter(byteBuffer); + } + } + if (mIsRecording) { + // Dispatch the data into the broadcasting filters. + startRecordFilterDispatcher(); + } else { + // Dispatch the data into the broadcasting filters. + startBroadcastFilterDispatcher(); } - startFilterDispatcher(); usleep(100); } } - ALOGW("[Demux] Broadcast Input thread end."); + ALOGW("[Demux] Frontend Input thread end."); delete[] buffer; inputData.close(); } -void Demux::stopBroadcastInput() { +void Demux::stopFrontendInput() { ALOGD("[Demux] stop frontend on demux"); mKeepFetchingDataFromFrontend = false; - mBroadcastInputThreadRunning = false; - std::lock_guard lock(mBroadcastInputThreadLock); + mFrontendInputThreadRunning = false; + std::lock_guard lock(mFrontendInputThreadLock); +} + +void Demux::setIsRecording(bool isRecording) { + mIsRecording = isRecording; +} + +bool Demux::attachRecordFilter(int filterId) { + if (mFilters[filterId] == nullptr || mDvr == nullptr) { + return false; + } + + mRecordFilterIds.insert(filterId); + mFilters[filterId]->attachFilterToRecord(mDvr); + + return true; +} + +bool Demux::detachRecordFilter(int filterId) { + if (mFilters[filterId] == nullptr || mDvr == nullptr) { + return false; + } + + mRecordFilterIds.erase(filterId); + mFilters[filterId]->detachFilterFromRecord(); + + return true; } } // namespace implementation diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h index 037429dd97..1405d0c2ca 100644 --- a/tv/tuner/1.0/default/Demux.h +++ b/tv/tuner/1.0/default/Demux.h @@ -81,11 +81,14 @@ class Demux : public IDemux { virtual Return disconnectCiCam() override; // Functions interacts with Tuner Service - void stopBroadcastInput(); + void stopFrontendInput(); Result removeFilter(uint32_t filterId); + bool attachRecordFilter(int filterId); + bool detachRecordFilter(int filterId); Result startFilterHandler(uint32_t filterId); void updateFilterOutput(uint16_t filterId, vector data); uint16_t getFilterTpid(uint32_t filterId); + void setIsRecording(bool isRecording); private: // Tuner service @@ -101,9 +104,9 @@ class Demux : public IDemux { uint32_t filterId; }; - Result startBroadcastInputLoop(); - static void* __threadLoopBroadcast(void* user); - void broadcastInputThreadLoop(); + Result startFrontendInputLoop(); + static void* __threadLoopFrontend(void* user); + void frontendInputThreadLoop(); /** * To create a FilterMQ with the the next available Filter ID. @@ -117,9 +120,13 @@ class Demux : public IDemux { /** * A dispatcher to read and dispatch input data to all the started filters. * Each filter handler handles the data filtering/output writing/filterEvent updating. + * Note that recording filters are not included. */ - bool startFilterDispatcher(); - void startTsFilter(vector data); + bool startBroadcastFilterDispatcher(); + void startBroadcastTsFilter(vector data); + + void sendFrontendInputToRecord(vector data); + bool startRecordFilterDispatcher(); uint32_t mDemuxId; uint32_t mCiCamId; @@ -140,19 +147,33 @@ class Demux : public IDemux { * and added into usedFilterIds. */ set mUnusedFilterIds; + /** + * Record all the attached record filter Ids. + * Any removed filter id should be removed from this set. + */ + set mRecordFilterIds; /** * A list of created FilterMQ ptrs. * The array number is the filter ID. */ std::map> mFilters; + /** + * Local reference to the opened DVR object. + */ + sp mDvr; + // Thread handlers - pthread_t mBroadcastInputThread; + pthread_t mFrontendInputThread; /** * If a specific filter's writing loop is still running */ - bool mBroadcastInputThreadRunning; + bool mFrontendInputThreadRunning; bool mKeepFetchingDataFromFrontend; + /** + * If the dvr recording is running. + */ + bool mIsRecording = false; /** * Lock to protect writes to the FMQs */ @@ -160,7 +181,7 @@ class Demux : public IDemux { /** * Lock to protect writes to the input status */ - std::mutex mBroadcastInputThreadLock; + std::mutex mFrontendInputThreadLock; // temp handle single PES filter // TODO handle mulptiple Pes filters diff --git a/tv/tuner/1.0/default/Dvr.cpp b/tv/tuner/1.0/default/Dvr.cpp index eb38f9040e..3088a9d73b 100644 --- a/tv/tuner/1.0/default/Dvr.cpp +++ b/tv/tuner/1.0/default/Dvr.cpp @@ -70,7 +70,14 @@ Return Dvr::attachFilter(const sp& filter) { return status; } + // check if the attached filter is a record filter + mFilters[filterId] = filter; + mIsRecordFilterAttached = true; + if (!mDemux->attachRecordFilter(filterId)) { + return Result::INVALID_ARGUMENT; + } + mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached); return Result::SUCCESS; } @@ -95,6 +102,15 @@ Return Dvr::detachFilter(const sp& filter) { it = mFilters.find(filterId); if (it != mFilters.end()) { mFilters.erase(filterId); + if (!mDemux->detachRecordFilter(filterId)) { + return Result::INVALID_ARGUMENT; + } + } + + // If all the filters are detached, record can't be started + if (mFilters.empty()) { + mIsRecordFilterAttached = false; + mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached); } return Result::SUCCESS; @@ -115,8 +131,9 @@ Return Dvr::start() { pthread_create(&mDvrThread, NULL, __threadLoopPlayback, this); pthread_setname_np(mDvrThread, "playback_waiting_loop"); } else if (mType == DvrType::RECORD) { - /*pthread_create(&mInputThread, NULL, __threadLoopInput, this); - pthread_setname_np(mInputThread, "playback_waiting_loop");*/ + mRecordStatus = RecordStatus::DATA_READY; + mIsRecordStarted = true; + mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached); } // TODO start another thread to send filter status callback to the framework @@ -131,12 +148,17 @@ Return Dvr::stop() { std::lock_guard lock(mDvrThreadLock); + mIsRecordStarted = false; + mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached); + return Result::SUCCESS; } Return Dvr::flush() { ALOGV("%s", __FUNCTION__); + mRecordStatus = RecordStatus::DATA_READY; + return Result::SUCCESS; } @@ -272,6 +294,45 @@ bool Dvr::startFilterDispatcher() { return true; } +bool Dvr::writeRecordFMQ(const std::vector& data) { + std::lock_guard lock(mWriteLock); + ALOGW("[Dvr] write record FMQ"); + if (mDvrMQ->write(data.data(), data.size())) { + mDvrEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); + maySendRecordStatusCallback(); + return true; + } + + maySendRecordStatusCallback(); + return false; +} + +void Dvr::maySendRecordStatusCallback() { + std::lock_guard lock(mRecordStatusLock); + int availableToRead = mDvrMQ->availableToRead(); + int availableToWrite = mDvrMQ->availableToWrite(); + + RecordStatus newStatus = checkRecordStatusChange(availableToWrite, availableToRead, + mDvrSettings.record().highThreshold, + mDvrSettings.record().lowThreshold); + if (mRecordStatus != newStatus) { + mCallback->onRecordStatus(newStatus); + mRecordStatus = newStatus; + } +} + +RecordStatus Dvr::checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead, + uint32_t highThreshold, uint32_t lowThreshold) { + if (availableToWrite == 0) { + return DemuxFilterStatus::OVERFLOW; + } else if (availableToRead > highThreshold) { + return DemuxFilterStatus::HIGH_WATER; + } else if (availableToRead < lowThreshold) { + return DemuxFilterStatus::LOW_WATER; + } + return mRecordStatus; +} + } // namespace implementation } // namespace V1_0 } // namespace tuner diff --git a/tv/tuner/1.0/default/Dvr.h b/tv/tuner/1.0/default/Dvr.h index fbb778ca6c..f39d8db152 100644 --- a/tv/tuner/1.0/default/Dvr.h +++ b/tv/tuner/1.0/default/Dvr.h @@ -79,6 +79,8 @@ class Dvr : public IDvr { * Return false is any of the above processes fails. */ bool createDvrMQ(); + void sendBroadcastInputToDvrRecord(vector byteBuffer); + bool writeRecordFMQ(const std::vector& data); private: // Demux service @@ -95,6 +97,8 @@ class Dvr : public IDvr { void maySendRecordStatusCallback(); PlaybackStatus checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead, uint32_t highThreshold, uint32_t lowThreshold); + RecordStatus checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead, + uint32_t highThreshold, uint32_t lowThreshold); /** * A dispatcher to read and dispatch input data to all the started filters. * Each filter handler handles the data filtering/output writing/filterEvent updating. @@ -103,9 +107,9 @@ class Dvr : public IDvr { void startTpidFilter(vector data); bool startFilterDispatcher(); static void* __threadLoopPlayback(void* user); - static void* __threadLoopBroadcast(void* user); + static void* __threadLoopRecord(void* user); void playbackThreadLoop(); - void broadcastInputThreadLoop(); + void recordThreadLoop(); unique_ptr mDvrMQ; EventFlag* mDvrEventFlag; @@ -121,6 +125,7 @@ class Dvr : public IDvr { // FMQ status local records PlaybackStatus mPlaybackStatus; + RecordStatus mRecordStatus; /** * If a specific filter's writing loop is still running */ @@ -135,10 +140,16 @@ class Dvr : public IDvr { * Lock to protect writes to the input status */ std::mutex mPlaybackStatusLock; + std::mutex mRecordStatusLock; std::mutex mBroadcastInputThreadLock; std::mutex mDvrThreadLock; const bool DEBUG_DVR = false; + + // Booleans to check if recording is running. + // Recording is ready when both of the following are set to true. + bool mIsRecordStarted = false; + bool mIsRecordFilterAttached = false; }; } // namespace implementation diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp index befd1e6550..b3160fc1f7 100644 --- a/tv/tuner/1.0/default/Filter.cpp +++ b/tv/tuner/1.0/default/Filter.cpp @@ -265,10 +265,16 @@ uint16_t Filter::getTpid() { void Filter::updateFilterOutput(vector data) { std::lock_guard lock(mFilterOutputLock); - ALOGD("[Filter] handler output updated"); + ALOGD("[Filter] filter output updated"); mFilterOutput.insert(mFilterOutput.end(), data.begin(), data.end()); } +void Filter::updateRecordOutput(vector data) { + std::lock_guard lock(mRecordFilterOutputLock); + ALOGD("[Filter] record filter output updated"); + mRecordFilterOutput.insert(mRecordFilterOutput.end(), data.begin(), data.end()); +} + Result Filter::startFilterHandler() { std::lock_guard lock(mFilterOutputLock); switch (mType.mainType) { @@ -292,12 +298,11 @@ Result Filter::startFilterHandler() { case DemuxTsFilterType::PCR: startPcrFilterHandler(); break; - case DemuxTsFilterType::RECORD: - startRecordFilterHandler(); - break; case DemuxTsFilterType::TEMI: startTemiFilterHandler(); break; + default: + break; } break; case DemuxFilterMainType::MMTP: @@ -342,12 +347,16 @@ Result Filter::startPesFilterHandler() { if (mPesSizeLeft == 0) { uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) | mFilterOutput[i + 6]; - ALOGD("[Filter] prefix %d", prefix); + if (DEBUG_FILTER) { + ALOGD("[Filter] prefix %d", prefix); + } if (prefix == 0x000001) { // TODO handle mulptiple Pes filters mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9]; mPesSizeLeft += 6; - ALOGD("[Filter] pes data length %d", mPesSizeLeft); + if (DEBUG_FILTER) { + ALOGD("[Filter] pes data length %d", mPesSizeLeft); + } } else { continue; } @@ -360,7 +369,9 @@ Result Filter::startPesFilterHandler() { mPesOutput.insert(mPesOutput.end(), first, last); // size does not match then continue mPesSizeLeft -= endPoint; - ALOGD("[Filter] pes data left %d", mPesSizeLeft); + if (DEBUG_FILTER) { + ALOGD("[Filter] pes data left %d", mPesSizeLeft); + } if (mPesSizeLeft > 0) { continue; } @@ -377,7 +388,9 @@ Result Filter::startPesFilterHandler() { .streamId = mPesOutput[3], .dataLength = static_cast(mPesOutput.size()), }; - ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength); + if (DEBUG_FILTER) { + ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength); + } int size = mFilterEvent.events.size(); mFilterEvent.events.resize(size + 1); @@ -413,13 +426,23 @@ Result Filter::startMediaFilterHandler() { } Result Filter::startRecordFilterHandler() { - DemuxFilterTsRecordEvent tsRecordEvent; + /*DemuxFilterTsRecordEvent tsRecordEvent; tsRecordEvent.pid.tPid(0); tsRecordEvent.indexMask.tsIndexMask(0x01); mFilterEvent.events.resize(1); mFilterEvent.events[0].tsRecord(tsRecordEvent); +*/ + std::lock_guard lock(mRecordFilterOutputLock); + if (mRecordFilterOutput.empty()) { + return Result::SUCCESS; + } - mFilterOutput.clear(); + if (mDvr == nullptr || !mDvr->writeRecordFMQ(mRecordFilterOutput)) { + ALOGD("[Filter] dvr fails to write into record FMQ."); + return Result::UNKNOWN_ERROR; + } + + mRecordFilterOutput.clear(); return Result::SUCCESS; } @@ -462,6 +485,14 @@ bool Filter::writeDataToFilterMQ(const std::vector& data) { return false; } +void Filter::attachFilterToRecord(const sp dvr) { + mDvr = dvr; +} + +void Filter::detachFilterFromRecord() { + mDvr = nullptr; +} + } // namespace implementation } // namespace V1_0 } // namespace tuner diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h index fbd965a1a1..d397f73081 100644 --- a/tv/tuner/1.0/default/Filter.h +++ b/tv/tuner/1.0/default/Filter.h @@ -22,6 +22,7 @@ #include #include #include "Demux.h" +#include "Dvr.h" #include "Frontend.h" using namespace std; @@ -44,6 +45,7 @@ using ::android::hardware::tv::tuner::V1_0::Result; using FilterMQ = MessageQueue; class Demux; +class Dvr; class Filter : public IFilter { public: @@ -80,11 +82,17 @@ class Filter : public IFilter { bool createFilterMQ(); uint16_t getTpid(); void updateFilterOutput(vector data); + void updateRecordOutput(vector data); Result startFilterHandler(); + Result startRecordFilterHandler(); + void attachFilterToRecord(const sp dvr); + void detachFilterFromRecord(); private: // Tuner service sp mDemux; + // Dvr reference once the filter is attached to any + sp mDvr = nullptr; /** * Filter callbacks used on filter events or FMQ status */ @@ -99,6 +107,7 @@ class Filter : public IFilter { sp mDataSource; bool mIsDataSourceDemux = true; vector mFilterOutput; + vector mRecordFilterOutput; unique_ptr mFilterMQ; EventFlag* mFilterEventFlag; DemuxFilterEvent mFilterEvent; @@ -120,6 +129,8 @@ class Filter : public IFilter { */ const uint16_t SECTION_WRITE_COUNT = 10; + bool DEBUG_FILTER = false; + /** * Filter handlers to handle the data filtering. * They are also responsible to write the filtered output into the filter FMQ @@ -129,7 +140,6 @@ class Filter : public IFilter { Result startPesFilterHandler(); Result startTsFilterHandler(); Result startMediaFilterHandler(); - Result startRecordFilterHandler(); Result startPcrFilterHandler(); Result startTemiFilterHandler(); Result startFilterLoop(); @@ -165,6 +175,7 @@ class Filter : public IFilter { std::mutex mFilterStatusLock; std::mutex mFilterThreadLock; std::mutex mFilterOutputLock; + std::mutex mRecordFilterOutputLock; // temp handle single PES filter // TODO handle mulptiple Pes filters diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp index f86b28d3c6..c143d61154 100644 --- a/tv/tuner/1.0/default/Tuner.cpp +++ b/tv/tuner/1.0/default/Tuner.cpp @@ -148,7 +148,7 @@ void Tuner::frontendStopTune(uint32_t frontendId) { uint32_t demuxId; if (it != mFrontendToDemux.end()) { demuxId = it->second; - mDemuxes[demuxId]->stopBroadcastInput(); + mDemuxes[demuxId]->stopFrontendInput(); } } From 97ce9c553d1e446ab52da974ac0b66c97be65d32 Mon Sep 17 00:00:00 2001 From: Amy Date: Tue, 17 Dec 2019 15:44:36 -0800 Subject: [PATCH 0359/1022] Add a DVR Record data flow test in the Tuner HAL 1.0 VTS Test: atest on cuttlefish Bug: 135708935 Change-Id: I3923b7bcfae6ea07a46603bd9f97e743d36284e2 --- .../VtsHalTvTunerV1_0TargetTest.cpp | 284 +++++++++++++++++- 1 file changed, 282 insertions(+), 2 deletions(-) diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index da3e300fc5..7977f25389 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -65,6 +65,7 @@ using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; using android::hardware::tv::tuner::V1_0::DemuxFilterMainType; using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent; using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; @@ -95,6 +96,7 @@ using android::hardware::tv::tuner::V1_0::IFrontendCallback; using android::hardware::tv::tuner::V1_0::ITuner; using android::hardware::tv::tuner::V1_0::PlaybackSettings; using android::hardware::tv::tuner::V1_0::PlaybackStatus; +using android::hardware::tv::tuner::V1_0::RecordSettings; using android::hardware::tv::tuner::V1_0::RecordStatus; using android::hardware::tv::tuner::V1_0::Result; @@ -379,7 +381,20 @@ bool FilterCallback::readFilterEventData() { class DvrCallback : public IDvrCallback { public: - virtual Return onRecordStatus(RecordStatus /*status*/) override { return Void(); } + virtual Return onRecordStatus(DemuxFilterStatus status) override { + ALOGW("[vts] record status %hhu", status); + switch (status) { + case DemuxFilterStatus::DATA_READY: + break; + case DemuxFilterStatus::LOW_WATER: + break; + case DemuxFilterStatus::HIGH_WATER: + case DemuxFilterStatus::OVERFLOW: + ALOGW("[vts] record overflow. Flushing"); + break; + } + return Void(); + } virtual Return onPlaybackStatus(PlaybackStatus status) override { // android::Mutex::Autolock autoLock(mMsgLock); @@ -401,10 +416,17 @@ class DvrCallback : public IDvrCallback { void testFilterDataOutput(); void stopPlaybackThread(); + void testRecordOutput(); + void stopRecordThread(); void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor); + void startRecordOutputThread(RecordSettings recordSetting, MQDesc& recordMQDescriptor); static void* __threadLoopPlayback(void* threadArgs); + static void* __threadLoopRecord(void* threadArgs); void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ); + void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ); + + bool readRecordFMQ(); private: struct PlaybackThreadArgs { @@ -412,22 +434,31 @@ class DvrCallback : public IDvrCallback { PlaybackConf* playbackConf; bool* keepWritingPlaybackFMQ; }; + struct RecordThreadArgs { + DvrCallback* user; + RecordSettings* recordSetting; + bool* keepReadingRecordFMQ; + }; uint16_t mDataLength = 0; std::vector mDataOutputBuffer; std::map> mFilterIdToMQ; std::unique_ptr mPlaybackMQ; + std::unique_ptr mRecordMQ; std::map mFilterIdToMQEventFlag; std::map mFilterIdToEvent; - EventFlag* mPlaybackMQEventFlag; android::Mutex mMsgLock; android::Mutex mPlaybackThreadLock; + android::Mutex mRecordThreadLock; android::Condition mMsgCondition; bool mKeepWritingPlaybackFMQ = true; + bool mKeepReadingRecordFMQ = true; bool mPlaybackThreadRunning; + bool mRecordThreadRunning; pthread_t mPlaybackThread; + pthread_t mRecordThread; int mPidFilterOutputCount = 0; }; @@ -516,6 +547,92 @@ void DvrCallback::playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWriti inputData.close(); } +void DvrCallback::testRecordOutput() { + android::Mutex::Autolock autoLock(mMsgLock); + while (mDataOutputBuffer.empty()) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "record output matching pid does not output within timeout"; + return; + } + } + stopRecordThread(); + ALOGW("[vts] record pass and stop"); +} + +void DvrCallback::startRecordOutputThread(RecordSettings recordSetting, + MQDesc& recordMQDescriptor) { + mRecordMQ = std::make_unique(recordMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(mRecordMQ); + struct RecordThreadArgs* threadArgs = + (struct RecordThreadArgs*)malloc(sizeof(struct RecordThreadArgs)); + threadArgs->user = this; + threadArgs->recordSetting = &recordSetting; + threadArgs->keepReadingRecordFMQ = &mKeepReadingRecordFMQ; + + pthread_create(&mRecordThread, NULL, __threadLoopRecord, (void*)threadArgs); + pthread_setname_np(mRecordThread, "test_record_input_loop"); +} + +void* DvrCallback::__threadLoopRecord(void* threadArgs) { + DvrCallback* const self = + static_cast(((struct RecordThreadArgs*)threadArgs)->user); + self->recordThreadLoop(((struct RecordThreadArgs*)threadArgs)->recordSetting, + ((struct RecordThreadArgs*)threadArgs)->keepReadingRecordFMQ); + return 0; +} + +void DvrCallback::recordThreadLoop(RecordSettings* /*recordSetting*/, bool* keepReadingRecordFMQ) { + ALOGD("[vts] DvrCallback record threadLoop start."); + android::Mutex::Autolock autoLock(mRecordThreadLock); + mRecordThreadRunning = true; + + // Create the EventFlag that is used to signal the HAL impl that data have been + // read from the Record FMQ + EventFlag* recordMQEventFlag; + EXPECT_TRUE(EventFlag::createEventFlag(mRecordMQ->getEventFlagWord(), &recordMQEventFlag) == + android::OK); + + while (mRecordThreadRunning) { + while (*keepReadingRecordFMQ) { + uint32_t efState = 0; + android::status_t status = recordMQEventFlag->wait( + static_cast(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT, + true /* retry on spurious wake */); + if (status != android::OK) { + ALOGD("[vts] wait for data ready on the record FMQ"); + continue; + } + // Our current implementation filter the data and write it into the filter FMQ + // immediately after the DATA_READY from the VTS/framework + if (!readRecordFMQ()) { + ALOGD("[vts] record data failed to be filtered. Ending thread"); + mRecordThreadRunning = false; + break; + } + } + } + + mRecordThreadRunning = false; + ALOGD("[vts] record thread ended."); +} + +bool DvrCallback::readRecordFMQ() { + android::Mutex::Autolock autoLock(mMsgLock); + bool result = false; + mDataOutputBuffer.clear(); + mDataOutputBuffer.resize(mRecordMQ->availableToRead()); + result = mRecordMQ->read(mDataOutputBuffer.data(), mRecordMQ->availableToRead()); + EXPECT_TRUE(result) << "can't read from Record MQ"; + mMsgCondition.signal(); + return result; +} + +void DvrCallback::stopRecordThread() { + mKeepReadingRecordFMQ = false; + mRecordThreadRunning = false; + android::Mutex::Autolock autoLock(mRecordThreadLock); +} + // Test environment for Tuner HIDL HAL. class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: @@ -555,6 +672,7 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { sp mDvrCallback; MQDesc mFilterMQDescriptor; MQDesc mPlaybackMQDescriptor; + MQDesc mRecordMQDescriptor; vector mUsedFilterIds; uint32_t mDemuxId; @@ -572,6 +690,8 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { FrontendSettings settings); ::testing::AssertionResult getPlaybackMQDescriptor(); ::testing::AssertionResult addPlaybackToDemux(PlaybackSettings setting); + ::testing::AssertionResult getRecordMQDescriptor(); + ::testing::AssertionResult addRecordToDemux(RecordSettings setting); ::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting); ::testing::AssertionResult getFilterMQDescriptor(); ::testing::AssertionResult closeDemux(); @@ -581,6 +701,9 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { ::testing::AssertionResult playbackDataFlowTest(vector filterConf, PlaybackConf playbackConf, vector goldenOutputFiles); + ::testing::AssertionResult recordDataFlowTest(vector filterConf, + RecordSettings recordSetting, + vector goldenOutputFiles); ::testing::AssertionResult broadcastDataFlowTest(vector filterConf, vector goldenOutputFiles); }; @@ -766,6 +889,49 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionResult(status == Result::SUCCESS); } +::testing::AssertionResult TunerHidlTest::addRecordToDemux(RecordSettings setting) { + Result status; + + if (!mDemux && createDemux() == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + + // Create dvr callback + mDvrCallback = new DvrCallback(); + + // Add playback input to the local demux + mDemux->openDvr(DvrType::RECORD, FMQ_SIZE_1M, mDvrCallback, + [&](Result result, const sp& dvr) { + mDvr = dvr; + status = result; + }); + + if (status != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + + DvrSettings dvrSetting; + dvrSetting.record(setting); + status = mDvr->configure(dvrSetting); + + return ::testing::AssertionResult(status == Result::SUCCESS); +} + +::testing::AssertionResult TunerHidlTest::getRecordMQDescriptor() { + Result status; + + if ((!mDemux && createDemux() == ::testing::AssertionFailure()) || !mDvr) { + return ::testing::AssertionFailure(); + } + + mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) { + mRecordMQDescriptor = dvrMQDesc; + status = result; + }); + + return ::testing::AssertionResult(status == Result::SUCCESS); +} + ::testing::AssertionResult TunerHidlTest::addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting) { Result status; @@ -997,6 +1163,82 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return closeDemux(); } +::testing::AssertionResult TunerHidlTest::recordDataFlowTest(vector filterConf, + RecordSettings recordSetting, + vector /*goldenOutputFiles*/) { + Result status; + hidl_vec feIds; + + mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { + status = result; + feIds = frontendIds; + }); + + if (feIds.size() == 0) { + ALOGW("[ WARN ] Frontend isn't available"); + return ::testing::AssertionFailure(); + } + + FrontendDvbtSettings dvbt{ + .frequency = 1000, + }; + FrontendSettings settings; + settings.dvbt(dvbt); + + int filterIdsSize; + // Filter Configuration Module + for (int i = 0; i < filterConf.size(); i++) { + if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) == + ::testing::AssertionFailure() || + // TODO use a map to save the FMQs/EvenFlags and pass to callback + getFilterMQDescriptor() == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + filterIdsSize = mUsedFilterIds.size(); + mUsedFilterIds.resize(filterIdsSize + 1); + mUsedFilterIds[filterIdsSize] = mFilterId; + mFilters[mFilterId] = mFilter; + } + + // Record Config Module + if (addRecordToDemux(recordSetting) == ::testing::AssertionFailure() || + getRecordMQDescriptor() == ::testing::AssertionFailure()) { + return ::testing::AssertionFailure(); + } + for (int i = 0; i <= filterIdsSize; i++) { + if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + } + + mDvrCallback->startRecordOutputThread(recordSetting, mRecordMQDescriptor); + status = mDvr->start(); + if (status != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + + if (createDemuxWithFrontend(feIds[0], settings) != ::testing::AssertionSuccess()) { + return ::testing::AssertionFailure(); + } + + // Data Verify Module + mDvrCallback->testRecordOutput(); + + // Clean Up Module + for (int i = 0; i <= filterIdsSize; i++) { + if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + } + if (mFrontend->stopTune() != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + mUsedFilterIds.clear(); + mFilterCallbacks.clear(); + mFilters.clear(); + return closeDemux(); +} + /* * API STATUS TESTS */ @@ -1203,6 +1445,44 @@ TEST_F(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) { ASSERT_TRUE(broadcastDataFlowTest(filterConf, goldenOutputFiles)); } +TEST_F(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) { + description("Feed ts data from frontend to recording and test with ts record filter"); + + // todo modulize the filter conf parser + vector filterConf; + filterConf.resize(1); + + DemuxFilterSettings filterSetting; + DemuxTsFilterSettings tsFilterSetting{ + .tpid = 119, + }; + DemuxFilterRecordSettings recordFilterSetting; + tsFilterSetting.filterSettings.record(recordFilterSetting); + filterSetting.ts(tsFilterSetting); + + DemuxFilterType type{ + .mainType = DemuxFilterMainType::TS, + }; + type.subType.tsFilterType(DemuxTsFilterType::RECORD); + FilterConf recordFilterConf{ + .type = type, + .setting = filterSetting, + }; + filterConf[0] = recordFilterConf; + + RecordSettings recordSetting{ + .statusMask = 0xf, + .lowThreshold = 0x1000, + .highThreshold = 0x07fff, + .dataFormat = DataFormat::TS, + .packetSize = 188, + }; + + vector goldenOutputFiles; + + ASSERT_TRUE(recordDataFlowTest(filterConf, recordSetting, goldenOutputFiles)); +} + } // namespace int main(int argc, char** argv) { From 6856ca765081cae968c962c1d0edfa498dd14a89 Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Wed, 13 Nov 2019 11:27:07 -0800 Subject: [PATCH 0360/1022] Camera: Add support for CONTROL_ZOOM_RATIO - The new zoom API combines optical and digital zoom, and supports both zoom-out and zoom-in with more precision. - Support separate zoom range for different bokeh modes. Test: Camera vts test Bug: 130025314 Change-Id: I67e0fac281a81d54f8828456c2f36df56be1803f --- camera/metadata/3.5/types.hal | 30 ++- .../VtsHalCameraProviderV2_4TargetTest.cpp | 203 ++++++++++++++++-- current.txt | 1 - 3 files changed, 206 insertions(+), 28 deletions(-) diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal index 2fd8a0d0fa..62899ec0c5 100644 --- a/camera/metadata/3.5/types.hal +++ b/camera/metadata/3.5/types.hal @@ -35,12 +35,22 @@ import android.hardware.camera.metadata@3.4; * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.

    */ enum CameraMetadataTag : @3.4::CameraMetadataTag { - /** android.control.availableBokehCapabilities [static, int32[], public] + /** android.control.availableBokehMaxSizes [static, int32[], ndk_public] * - *

    The list of bokeh modes that are supported by this camera device, and each bokeh mode's - * maximum streaming (non-stall) size with bokeh effect.

    + *

    The list of bokeh modes for ANDROID_CONTROL_BOKEH_MODE that are supported by this camera + * device, and each bokeh mode's maximum streaming (non-stall) size with bokeh effect.

    + * + * @see ANDROID_CONTROL_BOKEH_MODE */ - ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3, + ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3, + + /** android.control.availableBokehZoomRatioRanges [static, float[], ndk_public] + * + *

    The ranges of supported zoom ratio for non-OFF ANDROID_CONTROL_BOKEH_MODE.

    + * + * @see ANDROID_CONTROL_BOKEH_MODE + */ + ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES, /** android.control.bokehMode [dynamic, enum, public] * @@ -48,6 +58,18 @@ enum CameraMetadataTag : @3.4::CameraMetadataTag { */ ANDROID_CONTROL_BOKEH_MODE, + /** android.control.zoomRatioRange [static, float[], public] + * + *

    Minimum and maximum zoom ratios supported by this camera device.

    + */ + ANDROID_CONTROL_ZOOM_RATIO_RANGE, + + /** android.control.zoomRatio [dynamic, float, public] + * + *

    The desired zoom ratio

    + */ + ANDROID_CONTROL_ZOOM_RATIO, + ANDROID_CONTROL_END_3_5, }; diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 69ec0d9604..650ec8b81d 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -755,6 +756,7 @@ public: const hidl_vec& deviceNames); void verifyCameraCharacteristics(Status status, const CameraMetadata& chars); void verifyBokehCharacteristics(const camera_metadata_t* metadata); + void verifyZoomCharacteristics(const camera_metadata_t* metadata); void verifyRecommendedConfigs(const CameraMetadata& metadata); void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion); void verifyMonochromeCameraResult( @@ -776,6 +778,8 @@ public: void verifySessionReconfigurationQuery(sp session3_5, camera_metadata* oldSessionParams, camera_metadata* newSessionParams); + void verifyRequestTemplate(const camera_metadata_t* metadata, RequestTemplate requestTemplate); + bool isDepthOnly(camera_metadata_t* staticMeta); static Status getAvailableOutputStreams(const camera_metadata_t *staticMeta, @@ -2857,13 +2861,7 @@ TEST_P(CameraHidlTest, constructDefaultRequestSettings) { metadata, &expectedSize); ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED)); - size_t entryCount = - get_camera_metadata_entry_count(metadata); - // TODO: we can do better than 0 here. Need to check how many required - // request keys we've defined for each template - ASSERT_GT(entryCount, 0u); - ALOGI("template %u metadata entry count is %zu", - t, entryCount); + verifyRequestTemplate(metadata, reqTemplate); } else { ASSERT_EQ(0u, req.size()); } @@ -5671,6 +5669,11 @@ void CameraHidlTest::verifyLogicalCameraMetadata(const std::string& cameraName, return; } + camera_metadata_ro_entry entry; + int retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry); + bool hasZoomRatioRange = (0 == retcode && entry.count == 2); + std::string version, cameraId; ASSERT_TRUE(::matchDeviceName(cameraName, mProviderType, &version, &cameraId)); std::unordered_set physicalIds; @@ -5678,15 +5681,37 @@ void CameraHidlTest::verifyLogicalCameraMetadata(const std::string& cameraName, for (auto physicalId : physicalIds) { ASSERT_NE(physicalId, cameraId); bool isPublicId = false; + std::string fullPublicId; for (auto& deviceName : deviceNames) { std::string publicVersion, publicId; ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId)); if (physicalId == publicId) { isPublicId = true; + fullPublicId = deviceName; break; } } if (isPublicId) { + ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> subDevice; + Return ret; + ret = mProvider->getCameraDeviceInterface_V3_x( + fullPublicId, [&](auto status, const auto& device) { + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + subDevice = device; + }); + ASSERT_TRUE(ret.isOk()); + + ret = subDevice->getCameraCharacteristics( + [&](auto status, const auto& chars) { + ASSERT_EQ(Status::OK, status); + retcode = find_camera_metadata_ro_entry( + (const camera_metadata_t *)chars.data(), + ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry); + bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2); + ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange); + }); + ASSERT_TRUE(ret.isOk()); continue; } @@ -5702,6 +5727,12 @@ void CameraHidlTest::verifyLogicalCameraMetadata(const std::string& cameraName, [&](auto status, const auto& chars) { verifyCameraCharacteristics(status, chars); verifyMonochromeCharacteristics(chars, deviceVersion); + + retcode = find_camera_metadata_ro_entry( + (const camera_metadata_t *)chars.data(), + ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry); + bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2); + ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange); }); ASSERT_TRUE(ret.isOk()); @@ -5721,8 +5752,7 @@ void CameraHidlTest::verifyLogicalCameraMetadata(const std::string& cameraName, // Make sure ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID is available in // result keys. if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5) { - camera_metadata_ro_entry entry; - int retcode = find_camera_metadata_ro_entry(metadata, + retcode = find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry); if ((0 == retcode) && (entry.count > 0)) { ASSERT_NE(std::find(entry.data.i32, entry.data.i32 + entry.count, @@ -5822,6 +5852,7 @@ void CameraHidlTest::verifyCameraCharacteristics(Status status, const CameraMeta } verifyBokehCharacteristics(metadata); + verifyZoomCharacteristics(metadata); } void CameraHidlTest::verifyBokehCharacteristics(const camera_metadata_t* metadata) { @@ -5852,38 +5883,51 @@ void CameraHidlTest::verifyBokehCharacteristics(const camera_metadata_t* metadat retcode = find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry); - bool hasBokehCharacteristicsKey = false; + bool hasBokehMaxSizesKey = false; + bool hasBokehZoomRatioRangesKey = false; if ((0 == retcode) && (entry.count > 0)) { - hasBokehCharacteristicsKey = std::find(entry.data.i32, entry.data.i32+entry.count, - ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES) != entry.data.i32+entry.count; + hasBokehMaxSizesKey = std::find(entry.data.i32, entry.data.i32+entry.count, + ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES) != entry.data.i32+entry.count; + hasBokehZoomRatioRangesKey = std::find(entry.data.i32, entry.data.i32+entry.count, + ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES) != entry.data.i32+entry.count; } else { ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!"; } + + camera_metadata_ro_entry maxSizesEntry; retcode = find_camera_metadata_ro_entry(metadata, - ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES, &entry); - bool hasAvailableBokehCaps = (0 == retcode && entry.count > 0); + ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES, &maxSizesEntry); + bool hasBokehMaxSizes = (0 == retcode && maxSizesEntry.count > 0); + + camera_metadata_ro_entry zoomRatioRangesEntry; + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES, &zoomRatioRangesEntry); + bool hasBokehZoomRatioRanges = (0 == retcode && zoomRatioRangesEntry.count > 0); // Bokeh keys must all be available, or all be unavailable. - bool noBokeh = !hasBokehRequestKey && !hasBokehResultKey && !hasBokehCharacteristicsKey && - !hasAvailableBokehCaps; + bool noBokeh = !hasBokehRequestKey && !hasBokehResultKey && !hasBokehMaxSizesKey && + !hasBokehZoomRatioRangesKey && !hasBokehMaxSizes && !hasBokehZoomRatioRanges; if (noBokeh) { return; } - bool hasBokeh = hasBokehRequestKey && hasBokehResultKey && hasBokehCharacteristicsKey && - hasAvailableBokehCaps; + bool hasBokeh = hasBokehRequestKey && hasBokehResultKey && hasBokehMaxSizesKey && + hasBokehZoomRatioRangesKey && hasBokehMaxSizes && hasBokehZoomRatioRanges; ASSERT_TRUE(hasBokeh); // Must have OFF, and must have one of STILL_CAPTURE and CONTINUOUS. - ASSERT_TRUE(entry.count == 6 || entry.count == 9); + // Only valid combinations: {OFF, CONTINUOUS}, {OFF, STILL_CAPTURE}, and + // {OFF, CONTINUOUS, STILL_CAPTURE}. + ASSERT_TRUE((maxSizesEntry.count == 6 && zoomRatioRangesEntry.count == 2) || + (maxSizesEntry.count == 9 && zoomRatioRangesEntry.count == 4)); bool hasOffMode = false; bool hasStillCaptureMode = false; bool hasContinuousMode = false; std::vector outputStreams; ASSERT_EQ(Status::OK, getAvailableOutputStreams(metadata, outputStreams)); - for (int i = 0; i < entry.count; i += 3) { - int32_t mode = entry.data.i32[i]; - int32_t maxWidth = entry.data.i32[i+1]; - int32_t maxHeight = entry.data.i32[i+2]; + for (int i = 0, j = 0; i < maxSizesEntry.count && j < zoomRatioRangesEntry.count; i += 3) { + int32_t mode = maxSizesEntry.data.i32[i]; + int32_t maxWidth = maxSizesEntry.data.i32[i+1]; + int32_t maxHeight = maxSizesEntry.data.i32[i+2]; switch (mode) { case ANDROID_CONTROL_BOKEH_MODE_OFF: hasOffMode = true; @@ -5891,9 +5935,11 @@ void CameraHidlTest::verifyBokehCharacteristics(const camera_metadata_t* metadat break; case ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE: hasStillCaptureMode = true; + j += 2; break; case ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS: hasContinuousMode = true; + j += 2; break; default: ADD_FAILURE() << "Invalid bokehMode advertised: " << mode; @@ -5901,6 +5947,7 @@ void CameraHidlTest::verifyBokehCharacteristics(const camera_metadata_t* metadat } if (mode != ANDROID_CONTROL_BOKEH_MODE_OFF) { + // Make sure size is supported. bool sizeSupported = false; for (const auto& stream : outputStreams) { if ((stream.format == static_cast(PixelFormat::YCBCR_420_888) || @@ -5911,12 +5958,102 @@ void CameraHidlTest::verifyBokehCharacteristics(const camera_metadata_t* metadat } } ASSERT_TRUE(sizeSupported); + + // Make sure zoom range is valid + float minZoomRatio = zoomRatioRangesEntry.data.f[0]; + float maxZoomRatio = zoomRatioRangesEntry.data.f[1]; + ASSERT_GT(minZoomRatio, 0.0f); + ASSERT_LE(minZoomRatio, maxZoomRatio); } } ASSERT_TRUE(hasOffMode); ASSERT_TRUE(hasStillCaptureMode || hasContinuousMode); } +void CameraHidlTest::verifyZoomCharacteristics(const camera_metadata_t* metadata) { + camera_metadata_ro_entry entry; + int retcode = 0; + + // Check key availability in capabilities, request and result. + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, &entry); + float maxDigitalZoom = 1.0; + if ((0 == retcode) && (entry.count == 1)) { + maxDigitalZoom = entry.data.f[0]; + } else { + ADD_FAILURE() << "Get camera scalerAvailableMaxDigitalZoom failed!"; + } + + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry); + bool hasZoomRequestKey = false; + if ((0 == retcode) && (entry.count > 0)) { + hasZoomRequestKey = std::find(entry.data.i32, entry.data.i32+entry.count, + ANDROID_CONTROL_ZOOM_RATIO) != entry.data.i32+entry.count; + } else { + ADD_FAILURE() << "Get camera availableRequestKeys failed!"; + } + + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry); + bool hasZoomResultKey = false; + if ((0 == retcode) && (entry.count > 0)) { + hasZoomResultKey = std::find(entry.data.i32, entry.data.i32+entry.count, + ANDROID_CONTROL_ZOOM_RATIO) != entry.data.i32+entry.count; + } else { + ADD_FAILURE() << "Get camera availableResultKeys failed!"; + } + + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry); + bool hasZoomCharacteristicsKey = false; + if ((0 == retcode) && (entry.count > 0)) { + hasZoomCharacteristicsKey = std::find(entry.data.i32, entry.data.i32+entry.count, + ANDROID_CONTROL_ZOOM_RATIO_RANGE) != entry.data.i32+entry.count; + } else { + ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!"; + } + + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry); + bool hasZoomRatioRange = (0 == retcode && entry.count == 2); + + // Zoom keys must all be available, or all be unavailable. + bool noZoomRatio = !hasZoomRequestKey && !hasZoomResultKey && !hasZoomCharacteristicsKey && + !hasZoomRatioRange; + if (noZoomRatio) { + return; + } + bool hasZoomRatio = hasZoomRequestKey && hasZoomResultKey && hasZoomCharacteristicsKey && + hasZoomRatioRange; + ASSERT_TRUE(hasZoomRatio); + + float minZoomRatio = entry.data.f[0]; + float maxZoomRatio = entry.data.f[1]; + if (maxDigitalZoom != maxZoomRatio) { + ADD_FAILURE() << "Maximum zoom ratio is different than maximum digital zoom!"; + } + if (minZoomRatio > maxZoomRatio) { + ADD_FAILURE() << "Maximum zoom ratio is less than minimum zoom ratio!"; + } + if (minZoomRatio > 1.0f) { + ADD_FAILURE() << "Minimum zoom ratio is more than 1.0!"; + } + if (maxZoomRatio < 1.0f) { + ADD_FAILURE() << "Maximum zoom ratio is less than 1.0!"; + } + + // Make sure CROPPING_TYPE is CENTER_ONLY + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_SCALER_CROPPING_TYPE, &entry); + if ((0 == retcode) && (entry.count == 1)) { + int8_t croppingType = entry.data.u8[0]; + ASSERT_EQ(croppingType, ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY); + } else { + ADD_FAILURE() << "Get camera scalerCroppingType failed!"; + } +} + void CameraHidlTest::verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion) { const camera_metadata_t* metadata = (camera_metadata_t*)chars.data(); @@ -6415,6 +6552,26 @@ void CameraHidlTest::verifySessionReconfigurationQuery( } } +void CameraHidlTest::verifyRequestTemplate(const camera_metadata_t* metadata, + RequestTemplate requestTemplate) { + ASSERT_NE(nullptr, metadata); + size_t entryCount = + get_camera_metadata_entry_count(metadata); + ALOGI("template %u metadata entry count is %zu", (int32_t)requestTemplate, entryCount); + // TODO: we can do better than 0 here. Need to check how many required + // request keys we've defined for each template + ASSERT_GT(entryCount, 0u); + + // Check zoomRatio + camera_metadata_ro_entry zoomRatioEntry; + int foundZoomRatio = find_camera_metadata_ro_entry(metadata, + ANDROID_CONTROL_ZOOM_RATIO, &zoomRatioEntry); + if (foundZoomRatio == 0) { + ASSERT_EQ(zoomRatioEntry.count, 1); + ASSERT_EQ(zoomRatioEntry.data.f[0], 1.0f); + } +} + INSTANTIATE_TEST_SUITE_P( PerInstance, CameraHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames(ICameraProvider::descriptor)), diff --git a/current.txt b/current.txt index 5a3ed77d55..13e82d6f8f 100644 --- a/current.txt +++ b/current.txt @@ -586,7 +586,6 @@ f5bc6aa840db933cb9fd36668b06d3e2021cf5384bb70e459f22e2f2f921fba5 android.hardwar d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardware.automotive.evs@1.0::types 2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types -2bdc6baf3f80f7a87fb5a5d03599e2ee37aadd3dbb107b7c9c060657702942a8 android.hardware.camera.metadata@3.5::types b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel f1109cbb10297b7429a11fab42afa912710b303c9bf20bd5cdb8bd57b9c84186 android.hardware.neuralnetworks@1.0::types From 8e8bbddf8955f212f6d0dc0db4961979aec57755 Mon Sep 17 00:00:00 2001 From: Pawin Vongmasa Date: Mon, 9 Dec 2019 01:54:50 -0800 Subject: [PATCH 0361/1022] Add HDR metadata types to graphics/common Bug: 120990898 Bug: 141632767 Test: Builds Change-Id: Ie37b38043ec4c015bbe439978a0344d4c6bbc124 --- .../hardware/graphics/common/Cta861_3.aidl | 34 ++++ .../hardware/graphics/common/Smpte2086.aidl | 51 +++++ .../graphics/common/StandardMetadataType.aidl | 39 ++++ .../hardware/graphics/common/XyColor.aidl | 30 +++ graphics/mapper/4.0/IMapper.hal | 2 +- .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 179 ++++++++++++++++++ 6 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl create mode 100644 graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl diff --git a/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl b/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl new file mode 100644 index 0000000000..4fbc6b2344 --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl @@ -0,0 +1,34 @@ +/** + * 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. + */ + +package android.hardware.graphics.common; + +/** + * HDR static metadata extension as specified by CTA-861.3. + * + * This is an AIDL counterpart of the NDK struct `AHdrMetadata_cta861_3`. + */ +@VintfStability +parcelable Cta861_3 { + /** + * Maximum content light level. + */ + float maxContentLightLevel; + /** + * Maximum frame average light level. + */ + float maxFrameAverageLightLevel; +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl b/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl new file mode 100644 index 0000000000..60614cd9bb --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl @@ -0,0 +1,51 @@ +/** + * 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. + */ + +package android.hardware.graphics.common; +import android.hardware.graphics.common.XyColor; + +/** + * Mastering display metadata as specified by SMPTE ST 2086. + * + * This is an AIDL counterpart of the NDK struct `AHdrMetadata_smpte2086`. + */ +@VintfStability +parcelable Smpte2086 { + /** + * CIE XYZ chromaticity for red in the RGB primaries. + */ + XyColor primaryRed; + /** + * CIE XYZ chromaticity for green in the RGB primaries. + */ + XyColor primaryGreen; + /** + * CIE XYZ chromaticity for blue in the RGB primaries. + */ + XyColor primaryBlue; + /** + * CIE XYZ chromaticity for the white point. + */ + XyColor whitePoint; + /** + * Maximum luminance in candelas per square meter. + */ + float maxLuminance; + /** + * Minimum luminance in candelas per square meter. + */ + float minLuminance; +} diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl index 060d12c46e..68c99ee055 100644 --- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl +++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl @@ -279,4 +279,43 @@ enum StandardMetadataType { * 4 bytes written in little endian. */ BLEND_MODE = 17, + + /** + * Can be used to get or set static HDR metadata specified by SMPTE ST 2086. + * + * This metadata is a stable aidl android.hardware.graphics.common.Smpte2086. + * + * This is not used in tone mapping until it has been set for the first time. + * + * When it is encoded into a byte stream, each float member is represented by 4 bytes written in + * little endian. The ordering of float values follows the definition of Smpte2086 and XyColor. + * If this is unset when encoded into a byte stream, the byte stream is empty. + */ + SMPTE2086 = 18, + + /** + * Can be used to get or set static HDR metadata specified by CTA 861.3. + * + * This metadata is a stable aidl android.hardware.graphics.common.Cta861_3. + * + * This is not used in tone mapping until it has been set for the first time. + * + * When it is encoded into a byte stream, each float member is represented by 4 bytes written in + * little endian. The ordering of float values follows the definition of Cta861_3. + * If this is unset when encoded into a byte stream, the byte stream is empty. + */ + CTA861_3 = 19, + + /** + * Can be used to get or set dynamic HDR metadata specified by SMPTE ST 2094-40:2016. + * + * This metadata is uint8_t byte array. + * + * This is not used in tone mapping until it has been set for the first time. + * + * When it is encoded into a byte stream, the length of the HDR metadata byte array is written + * using 8 bytes in little endian. It is followed by the uint8_t byte array. + * If this is unset when encoded into a byte stream, the byte stream is empty. + */ + SMPTE2094_40 = 20, } diff --git a/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl b/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl new file mode 100644 index 0000000000..9571273d7d --- /dev/null +++ b/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl @@ -0,0 +1,30 @@ +/** + * 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. + */ + +package android.hardware.graphics.common; + +/** + * Chromaticity based on 2 parameters. + * + * This is an AIDL counterpart of the NDK struct `AColor_xy`. + * + * @note This can be used to represent any 2-dimensional chromaticity. + */ +@VintfStability +parcelable XyColor { + float x; + float y; +} diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal index 03dfef1e3f..3be2152971 100644 --- a/graphics/mapper/4.0/IMapper.hal +++ b/graphics/mapper/4.0/IMapper.hal @@ -478,7 +478,7 @@ interface IMapper { * particular Metadata field. * * The framework may attempt to set the following StandardMetadataType - * values: DATASPACE, PER_FRAME_METADATA, PER_FRAME_METADATA_BLOB and BLEND_MODE. + * values: DATASPACE, SMPTE2086, CTA861_3, SMPTE2094_40 and BLEND_MODE. * We strongly encourage everyone to support setting as many of those fields as * possible. If a device's Composer implementation supports a field, it should be * supported here. Over time these metadata fields will be moved out of diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index c4b1c535a5..2aad24245e 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -44,11 +44,13 @@ using android::hardware::graphics::common::V1_2::BufferUsage; using android::hardware::graphics::common::V1_2::PixelFormat; using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType; using aidl::android::hardware::graphics::common::BlendMode; +using aidl::android::hardware::graphics::common::Cta861_3; using aidl::android::hardware::graphics::common::Dataspace; using aidl::android::hardware::graphics::common::ExtendableType; using aidl::android::hardware::graphics::common::PlaneLayout; using aidl::android::hardware::graphics::common::PlaneLayoutComponent; using aidl::android::hardware::graphics::common::PlaneLayoutComponentType; +using aidl::android::hardware::graphics::common::Smpte2086; using aidl::android::hardware::graphics::common::StandardMetadataType; using DecodeFunction = std::function& vec) { + std::optional smpte2086; + ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086)); + EXPECT_FALSE(smpte2086.has_value()); + }); +} + +/** + * Test IMapper::get(Cta861_3) + */ +TEST_P(GraphicsMapperHidlTest, GetCta861_3) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, + [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + std::optional cta861_3; + ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3)); + EXPECT_FALSE(cta861_3.has_value()); + }); +} + +/** + * Test IMapper::get(Smpte2094_40) + */ +TEST_P(GraphicsMapperHidlTest, GetSmpte2094_40) { + testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_40, + [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + std::optional> smpte2094_40; + ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40)); + EXPECT_FALSE(smpte2094_40.has_value()); + }); +} + /** * Test IMapper::get(metadata) with a bad buffer */ @@ -1072,6 +1110,15 @@ TEST_P(GraphicsMapperHidlTest, GetMetadataBadValue) { ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_BlendMode, &vec)); ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2086, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_Cta861_3, &vec)); + ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2094_40, &vec)); + ASSERT_EQ(0, vec.size()); } /** @@ -1427,6 +1474,90 @@ TEST_P(GraphicsMapperHidlTest, SetBlendMode) { }); } +/** + * Test IMapper::set(Smpte2086) + */ +TEST_P(GraphicsMapperHidlTest, SetSmpte2086) { + /** + * DISPLAY_P3 is a color space that uses the DCI_P3 primaries, + * the D65 white point and the SRGB transfer functions. + * Rendering Intent: Colorimetric + * Primaries: + * x y + * green 0.265 0.690 + * blue 0.150 0.060 + * red 0.680 0.320 + * white (D65) 0.3127 0.3290 + */ + std::optional smpte2086; + smpte2086->primaryRed.x = 0.680; + smpte2086->primaryRed.y = 0.320; + smpte2086->primaryGreen.x = 0.265; + smpte2086->primaryGreen.y = 0.690; + smpte2086->primaryBlue.x = 0.150; + smpte2086->primaryBlue.y = 0.060; + smpte2086->whitePoint.x = 0.3127; + smpte2086->whitePoint.y = 0.3290; + smpte2086->maxLuminance = 100.0; + smpte2086->minLuminance = 0.1; + + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2086(smpte2086, &vec)); + + testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + std::optional realSmpte2086; + ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &realSmpte2086)); + ASSERT_TRUE(realSmpte2086.has_value()); + EXPECT_EQ(smpte2086->primaryRed.x, realSmpte2086->primaryRed.x); + EXPECT_EQ(smpte2086->primaryRed.y, realSmpte2086->primaryRed.y); + EXPECT_EQ(smpte2086->primaryGreen.x, realSmpte2086->primaryGreen.x); + EXPECT_EQ(smpte2086->primaryGreen.y, realSmpte2086->primaryGreen.y); + EXPECT_EQ(smpte2086->primaryBlue.x, realSmpte2086->primaryBlue.x); + EXPECT_EQ(smpte2086->primaryBlue.y, realSmpte2086->primaryBlue.y); + EXPECT_EQ(smpte2086->whitePoint.x, realSmpte2086->whitePoint.x); + EXPECT_EQ(smpte2086->whitePoint.y, realSmpte2086->whitePoint.y); + EXPECT_EQ(smpte2086->maxLuminance, realSmpte2086->maxLuminance); + EXPECT_EQ(smpte2086->minLuminance, realSmpte2086->minLuminance); + }); +} + +/** + * Test IMapper::set(Cta8613) + */ +TEST_P(GraphicsMapperHidlTest, SetCta861_3) { + std::optional cta861_3; + cta861_3->maxContentLightLevel = 78.0; + cta861_3->maxFrameAverageLightLevel = 62.0; + + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeCta861_3(cta861_3, &vec)); + + testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + std::optional realCta861_3; + ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &realCta861_3)); + ASSERT_TRUE(realCta861_3.has_value()); + EXPECT_EQ(cta861_3->maxContentLightLevel, realCta861_3->maxContentLightLevel); + EXPECT_EQ(cta861_3->maxFrameAverageLightLevel, + realCta861_3->maxFrameAverageLightLevel); + }); +} + +/** + * Test IMapper::set(Smpte2094_40) + */ +TEST_P(GraphicsMapperHidlTest, SetSmpte2094_40) { + hidl_vec vec; + + testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_40, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + std::optional> realSmpte2094_40; + ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &realSmpte2094_40)); + EXPECT_FALSE(realSmpte2094_40.has_value()); + }); +} + /** * Test IMapper::set(metadata) with a bad buffer */ @@ -1462,6 +1593,11 @@ TEST_P(GraphicsMapperHidlTest, SetMetadataNullBuffer) { mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec)); ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec)); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec)); + ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec)); + ASSERT_EQ(Error::BAD_BUFFER, + mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2094_40, vec)); } /** @@ -1521,6 +1657,10 @@ TEST_P(GraphicsMapperHidlTest, SetBadMetadata) { mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec)); ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec)); + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec)); + ASSERT_EQ(Error::UNSUPPORTED, + mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec)); } /** @@ -1752,6 +1892,45 @@ TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBlendMode) { EXPECT_EQ(BlendMode::INVALID, blendMode); } +/** + * Test IMapper::getFromBufferDescriptorInfo(Smpte2086) + */ +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2086) { + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( + mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086, &vec)); + + std::optional smpte2086; + ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086)); + EXPECT_FALSE(smpte2086.has_value()); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(Cta861_3) + */ +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCta861_3) { + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo( + mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, &vec)); + + std::optional cta861_3; + ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3)); + EXPECT_FALSE(cta861_3.has_value()); +} + +/** + * Test IMapper::getFromBufferDescriptorInfo(Smpte2094_40) + */ +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2094_40) { + hidl_vec vec; + ASSERT_EQ(Error::NONE, + mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, + gralloc4::MetadataType_Smpte2094_40, &vec)); + std::optional> smpte2094_40; + ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40)); + EXPECT_FALSE(smpte2094_40.has_value()); +} + /** * Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported metadata */ From a0a12cfcf216c7ba3ee43ec86e81e708a8db2519 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Thu, 5 Dec 2019 21:50:22 -0800 Subject: [PATCH 0362/1022] Add hadamard utilities to encode keys Add the utility functions to encode & decode 32 bytes keys. The hadamard encoding will expand a 2 bytes word to 2^15 bits. And thus the 32 byte key will expand to 64KiB in space. The encoded value is more robust and we will be able to recover the key even if there is some corruption. Test: unittest pass Change-Id: Iae8a28a8c7c1699f8641f9250f0eccde5c2ff138 --- rebootescrow/aidl/default/Android.bp | 47 ++++++ rebootescrow/aidl/default/HadamardUtils.cpp | 157 ++++++++++++++++++ rebootescrow/aidl/default/HadamardUtils.h | 62 +++++++ .../aidl/default/HadamardUtilsTest.cpp | 126 ++++++++++++++ 4 files changed, 392 insertions(+) create mode 100644 rebootescrow/aidl/default/Android.bp create mode 100644 rebootescrow/aidl/default/HadamardUtils.cpp create mode 100644 rebootescrow/aidl/default/HadamardUtils.h create mode 100644 rebootescrow/aidl/default/HadamardUtilsTest.cpp diff --git a/rebootescrow/aidl/default/Android.bp b/rebootescrow/aidl/default/Android.bp new file mode 100644 index 0000000000..eb228ad827 --- /dev/null +++ b/rebootescrow/aidl/default/Android.bp @@ -0,0 +1,47 @@ +// +// 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. +// + +cc_library_static { + name: "libhadamardutils", + vendor_available: true, + host_supported: true, + shared_libs: [ + "libbase", + ], + srcs: [ + "HadamardUtils.cpp", + ], + visibility: [ + ":__subpackages__", + ], +} + +cc_test { + name: "HadamardUtilsTest", + host_supported: true, + srcs: [ + "HadamardUtilsTest.cpp", + ], + static_libs: [ + "libhadamardutils", + "libgtest_prod", + ], + shared_libs: [ + "liblog", + "libbase", + ], + test_suites: ["device-tests"], +} diff --git a/rebootescrow/aidl/default/HadamardUtils.cpp b/rebootescrow/aidl/default/HadamardUtils.cpp new file mode 100644 index 0000000000..5853d2def5 --- /dev/null +++ b/rebootescrow/aidl/default/HadamardUtils.cpp @@ -0,0 +1,157 @@ +/* + * 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. + */ + +#include + +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace rebootescrow { +namespace hadamard { + +constexpr auto BYTE_LENGTH = 8u; + +std::vector BitsetToBytes(const std::bitset& encoded_bits) { + CHECK_EQ(0, (encoded_bits.size() % BYTE_LENGTH)); + std::vector result; + for (size_t i = 0; i < encoded_bits.size(); i += 8) { + uint8_t current = 0; + // Set each byte starting from the LSB. + for (size_t j = 0; j < BYTE_LENGTH; j++) { + CHECK_LE(i + j, encoded_bits.size()); + if (encoded_bits[i + j]) { + current |= (1u << j); + } + } + result.push_back(current); + } + return result; +} + +std::bitset BytesToBitset(const std::vector& encoded) { + CHECK_EQ(ENCODE_LENGTH, encoded.size() * BYTE_LENGTH); + + std::bitset result; + size_t offset = 0; + for (const auto& byte : encoded) { + // Set each byte starting from the LSB. + for (size_t j = 0; j < BYTE_LENGTH; j++) { + result[offset + j] = byte & (1u << j); + } + offset += BYTE_LENGTH; + } + return result; +} + +// The encoding is equivalent to multiply the word with the generator matrix (and take the module +// of 2). Here is an example of encoding a number with 3 bits. The encoded length is thus +// 2^(3-1) = 4 bits. +// |1 1 1 1| |0| +// |0 1 1| * |0 0 1 1| = |1| +// |0 1 0 1| |1| +// |0| +std::bitset EncodeWord(uint16_t word) { + std::bitset result; + for (uint64_t i = ENCODE_LENGTH; i < 2 * ENCODE_LENGTH; i++) { + uint32_t wi = word & i; + // Sum all the bits in the word and check its parity. + wi ^= wi >> 8u; + wi ^= wi >> 4u; + wi ^= wi >> 2u; + wi ^= wi >> 1u; + result[i - ENCODE_LENGTH] = wi & 1u; + } + return result; +} + +std::vector EncodeKey(const std::vector& key) { + CHECK_EQ(KEY_SIZE_IN_BYTES, key.size()); + + std::vector result; + for (size_t i = 0; i < key.size(); i += 2) { + uint16_t word = static_cast(key[i + 1]) << BYTE_LENGTH | key[i]; + auto encoded_bits = EncodeWord(word); + auto byte_array = BitsetToBytes(encoded_bits); + std::move(byte_array.begin(), byte_array.end(), std::back_inserter(result)); + } + return result; +} + +std::vector DecodeKey(const std::vector& encoded) { + CHECK_EQ(0, (encoded.size() * 8) % ENCODE_LENGTH); + std::vector result; + for (size_t i = 0; i < encoded.size(); i += ENCODE_LENGTH / 8) { + auto current = + std::vector{encoded.begin() + i, encoded.begin() + i + ENCODE_LENGTH / 8}; + auto bits = BytesToBitset(current); + auto candidates = DecodeWord(bits); + CHECK(!candidates.empty()); + // TODO(xunchang) Do we want to try other candidates? + uint16_t val = candidates.top().second; + result.push_back(val & 0xffu); + result.push_back(val >> BYTE_LENGTH); + } + + return result; +} + +std::priority_queue> DecodeWord( + const std::bitset& encoded) { + std::vector scores; + scores.reserve(ENCODE_LENGTH); + // Convert 0 -> -1 in the encoded bits. e.g [0, 1, 1, 0] -> [-1, 1, 1, -1] + for (uint32_t i = 0; i < ENCODE_LENGTH; i++) { + scores.push_back(2 * encoded[i] - 1); + } + + // Multiply the hadamard matrix by the transformed input. + // |1 1 1 1| |-1| | 0| + // |1 -1 1 -1| * | 1| = | 0| + // |1 1 -1 -1| | 1| | 0| + // |1 -1 -1 1| |-1| |-4| + for (uint32_t i = 0; i < CODE_K; i++) { + uint16_t step = 1u << i; + for (uint32_t j = 0; j < ENCODE_LENGTH; j += 2 * step) { + for (uint32_t k = j; k < j + step; k++) { + auto a0 = scores[k]; + auto a1 = scores[k + step]; + scores[k] = a0 + a1; + scores[k + step] = a0 - a1; + } + } + } + + // Assign the corresponding score to each index; larger score indicates higher probability. e.g. + // value 3, encoding [0, 1, 1, 0] -> score: 4 + // value 7, encoding [1, 0, 0, 1] (3's complement) -> score: -4 + std::priority_queue> candidates; + // TODO(xunchang) limit the candidate size since we don't need all of them? + for (uint32_t i = 0; i < scores.size(); i++) { + candidates.emplace(-scores[i], i); + candidates.emplace(scores[i], (1u << CODE_K) | i); + } + + CHECK_EQ(2 * ENCODE_LENGTH, candidates.size()); + return candidates; +} + +} // namespace hadamard +} // namespace rebootescrow +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/rebootescrow/aidl/default/HadamardUtils.h b/rebootescrow/aidl/default/HadamardUtils.h new file mode 100644 index 0000000000..21cfc787e3 --- /dev/null +++ b/rebootescrow/aidl/default/HadamardUtils.h @@ -0,0 +1,62 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include +#include +#include +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace rebootescrow { +namespace hadamard { + +constexpr uint32_t CODE_K = 15; +constexpr uint32_t ENCODE_LENGTH = 1u << CODE_K; +constexpr auto KEY_SIZE_IN_BYTES = 32u; + +// Encodes a 2 bytes word with hadamard code. The encoding expands a word of k+1 bits to a 2^k +// bitset. Returns the encoded bitset. +std::bitset EncodeWord(uint16_t word); + +// Decodes the input bitset, and returns a sorted list of pair with (score, value). The value with +// a higher score indicates a greater likehood. +std::priority_queue> DecodeWord( + const std::bitset& encoded); + +// Encodes a key that has a size of KEY_SIZE_IN_BYTES. Returns a byte array representation of the +// encoded bitset. So a 32 bytes key will expand to 16*(2^15) bits = 64KiB. +std::vector EncodeKey(const std::vector& input); + +// Given a byte array representation of the encoded keys, decodes it and return the result. +std::vector DecodeKey(const std::vector& encoded); + +// Converts a bitset of length |ENCODE_LENGTH| to a byte array. +std::vector BitsetToBytes(const std::bitset& encoded_bits); + +// Converts a byte array of encoded words back to the bitset. +std::bitset BytesToBitset(const std::vector& encoded); + +} // namespace hadamard +} // namespace rebootescrow +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/rebootescrow/aidl/default/HadamardUtilsTest.cpp b/rebootescrow/aidl/default/HadamardUtilsTest.cpp new file mode 100644 index 0000000000..e397e7624e --- /dev/null +++ b/rebootescrow/aidl/default/HadamardUtilsTest.cpp @@ -0,0 +1,126 @@ +/* + * 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. + */ + +#include +#include + +#include +#include +#include + +#include + +#include + +using namespace aidl::android::hardware::rebootescrow::hadamard; + +class HadamardTest : public testing::Test { + protected: + void SetUp() override { + auto ones = std::bitset{}.set(); + // Expects 0x4000 to encode as top half as ones, and lower half as zeros. i.e. + // [1, 1 .. 1, 0, 0 .. 0] + expected_half_size_ = ones << half_size_; + + // Expects 0x1 to encode as interleaved 1 and 0s i.e. [1, 0, 1, 0 ..] + expected_one_ = ones; + for (uint32_t i = ENCODE_LENGTH / 2; i >= 1; i /= 2) { + expected_one_ ^= (expected_one_ >> i); + } + } + + uint16_t half_size_ = ENCODE_LENGTH / 2; + std::bitset expected_one_; + std::bitset expected_half_size_; +}; + +static void AddError(std::bitset* corrupted_bits) { + // The hadamard code has a hamming distance of ENCODE_LENGTH/2. So we should always be able to + // correct the data if less than a quarter of the encoded bits are corrupted. + auto corrupted_max = 0.24f * corrupted_bits->size(); + auto corrupted_num = 0; + for (size_t i = 0; i < corrupted_bits->size() && corrupted_num < corrupted_max; i++) { + if (random() % 2 == 0) { + (*corrupted_bits)[i] = !(*corrupted_bits)[i]; + corrupted_num += 1; + } + } +} + +static void EncodeAndDecodeKeys(const std::vector& key) { + auto encoded = EncodeKey(key); + ASSERT_EQ(64 * 1024, encoded.size()); + auto decoded = DecodeKey(encoded); + ASSERT_EQ(key, std::vector(decoded.begin(), decoded.begin() + key.size())); +} + +TEST_F(HadamardTest, Encode_smoke) { + ASSERT_EQ(expected_half_size_, EncodeWord(half_size_)); + ASSERT_EQ(expected_one_, EncodeWord(1)); + // Check the complement of 1. + ASSERT_EQ(~expected_one_, EncodeWord(1u << CODE_K | 1u)); +} + +TEST_F(HadamardTest, Decode_smoke) { + auto candidate = DecodeWord(expected_half_size_); + auto expected = std::pair{ENCODE_LENGTH, half_size_}; + ASSERT_EQ(expected, candidate.top()); + + candidate = DecodeWord(expected_one_); + expected = std::pair{ENCODE_LENGTH, 1}; + ASSERT_EQ(expected, candidate.top()); +} + +TEST_F(HadamardTest, Decode_error_correction) { + constexpr auto iteration = 10; + for (int i = 0; i < iteration; i++) { + uint16_t word = random() % (ENCODE_LENGTH * 2); + auto corrupted_bits = EncodeWord(word); + AddError(&corrupted_bits); + + auto candidate = DecodeWord(corrupted_bits); + ASSERT_EQ(word, candidate.top().second); + } +} + +TEST_F(HadamardTest, BytesToBitset_smoke) { + auto bytes = BitsetToBytes(expected_one_); + + auto read_back = BytesToBitset(bytes); + ASSERT_EQ(expected_one_, read_back); +} + +TEST_F(HadamardTest, EncodeAndDecodeKey) { + std::vector KEY_1{ + 0xA5, 0x00, 0xFF, 0x01, 0xA5, 0x5a, 0xAA, 0x55, 0x00, 0xD3, 0x2A, + 0x8C, 0x2E, 0x83, 0x0E, 0x65, 0x9E, 0x8D, 0xC6, 0xAC, 0x1E, 0x83, + 0x21, 0xB3, 0x95, 0x02, 0x89, 0x64, 0x64, 0x92, 0x12, 0x1F, + }; + std::vector KEY_2{ + 0xFF, 0x00, 0x00, 0xAA, 0x5A, 0x19, 0x20, 0x71, 0x9F, 0xFB, 0xDA, + 0xB6, 0x2D, 0x06, 0xD5, 0x49, 0x7E, 0xEF, 0x63, 0xAC, 0x18, 0xFF, + 0x5A, 0xA3, 0x40, 0xBB, 0x64, 0xFA, 0x67, 0xC1, 0x10, 0x18, + }; + + EncodeAndDecodeKeys(KEY_1); + EncodeAndDecodeKeys(KEY_2); + + std::vector key; + for (uint8_t i = 0; i < KEY_SIZE_IN_BYTES; i++) { + key.push_back(i); + }; + EncodeAndDecodeKeys(key); +} From d0c4f2bb404e87c96f83a0ef75c76145a1af6161 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Wed, 4 Dec 2019 07:54:20 -0800 Subject: [PATCH 0363/1022] Resume on Reboot default implementation A default implementation of the RebootEscrow HAL which relies on RAM retention to keep a key around during a reboot to apply an OTA. This should work on devices that use a "warm reboot" and most likely will work on devices that use a "cold reboot" as well. DRAM will retain information for several seconds depending on the temperature and other factors. This is enough to survive a reboot. With the Hadamard code used in this change for error recovery, many errors can be recovered. Bug: 63928581 Test: make Test: atest VtsHalRebootEscrowTargetTest Change-Id: Ib8db7888d64fee8d827d7c06892b9a1f2af87add --- rebootescrow/aidl/default/Android.bp | 41 ++++++++++ rebootescrow/aidl/default/RebootEscrow.cpp | 75 +++++++++++++++++++ .../include/rebootescrow-impl/RebootEscrow.h | 36 +++++++++ .../aidl/default/rebootescrow-default.rc | 9 +++ .../aidl/default/rebootescrow-default.xml | 6 ++ rebootescrow/aidl/default/service.cpp | 35 +++++++++ 6 files changed, 202 insertions(+) create mode 100644 rebootescrow/aidl/default/RebootEscrow.cpp create mode 100644 rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h create mode 100644 rebootescrow/aidl/default/rebootescrow-default.rc create mode 100644 rebootescrow/aidl/default/rebootescrow-default.xml create mode 100644 rebootescrow/aidl/default/service.cpp diff --git a/rebootescrow/aidl/default/Android.bp b/rebootescrow/aidl/default/Android.bp index eb228ad827..c8cbf48834 100644 --- a/rebootescrow/aidl/default/Android.bp +++ b/rebootescrow/aidl/default/Android.bp @@ -14,6 +14,47 @@ // limitations under the License. // +cc_library_static { + name: "librebootescrowdefaultimpl", + vendor: true, + shared_libs: [ + "libbase", + "libbinder_ndk", + "vintf-rebootescrow-ndk_platform", + ], + export_include_dirs: ["include"], + srcs: [ + "RebootEscrow.cpp", + ], + visibility: [ + ":__subpackages__", + ], +} + +cc_binary { + name: "android.hardware.rebootescrow-service.default", + init_rc: ["rebootescrow-default.rc"], + relative_install_path: "hw", + vintf_fragments: ["rebootescrow-default.xml"], + vendor: true, + srcs: [ + "service.cpp", + ], + cflags: [ + "-Wall", + "-Werror", + ], + shared_libs: [ + "libbase", + "libbinder_ndk", + "vintf-rebootescrow-ndk_platform", + ], + static_libs: [ + "libhadamardutils", + "librebootescrowdefaultimpl", + ], +} + cc_library_static { name: "libhadamardutils", vendor_available: true, diff --git a/rebootescrow/aidl/default/RebootEscrow.cpp b/rebootescrow/aidl/default/RebootEscrow.cpp new file mode 100644 index 0000000000..94d09010d9 --- /dev/null +++ b/rebootescrow/aidl/default/RebootEscrow.cpp @@ -0,0 +1,75 @@ +/* + * 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. + */ + +#include +#include +#include + +#include "HadamardUtils.h" +#include "rebootescrow-impl/RebootEscrow.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace rebootescrow { + +using ::android::base::unique_fd; + +ndk::ScopedAStatus RebootEscrow::storeKey(const std::vector& kek) { + int rawFd = TEMP_FAILURE_RETRY(::open(REBOOT_ESCROW_DEVICE, O_WRONLY | O_NOFOLLOW | O_CLOEXEC)); + unique_fd fd(rawFd); + if (fd.get() < 0) { + LOG(WARNING) << "Could not open reboot escrow device"; + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + } + + std::vector ukek(kek.begin(), kek.end()); + auto encoded = hadamard::EncodeKey(ukek); + + if (!::android::base::WriteFully(fd, encoded.data(), encoded.size())) { + LOG(WARNING) << "Could not write data fully to character device"; + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + } + + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus RebootEscrow::retrieveKey(std::vector* _aidl_return) { + int rawFd = TEMP_FAILURE_RETRY(::open(REBOOT_ESCROW_DEVICE, O_RDONLY | O_NOFOLLOW | O_CLOEXEC)); + unique_fd fd(rawFd); + if (fd.get() < 0) { + LOG(WARNING) << "Could not open reboot escrow device"; + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + } + + std::string encodedString; + if (!::android::base::ReadFdToString(fd, &encodedString)) { + LOG(WARNING) << "Could not read device to string"; + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + } + + std::vector encodedBytes(encodedString.begin(), encodedString.end()); + auto keyBytes = hadamard::DecodeKey(encodedBytes); + + std::vector signedKeyBytes(keyBytes.begin(), keyBytes.end()); + *_aidl_return = signedKeyBytes; + return ndk::ScopedAStatus::ok(); +} + +} // namespace rebootescrow +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h new file mode 100644 index 0000000000..1ed73978d9 --- /dev/null +++ b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace rebootescrow { + +static const char* REBOOT_ESCROW_DEVICE = "/dev/access-kregistry"; + +class RebootEscrow : public BnRebootEscrow { + ndk::ScopedAStatus storeKey(const std::vector& kek) override; + ndk::ScopedAStatus retrieveKey(std::vector* _aidl_return) override; +}; + +} // namespace rebootescrow +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/rebootescrow/aidl/default/rebootescrow-default.rc b/rebootescrow/aidl/default/rebootescrow-default.rc new file mode 100644 index 0000000000..e7a9cfcb70 --- /dev/null +++ b/rebootescrow/aidl/default/rebootescrow-default.rc @@ -0,0 +1,9 @@ +service vendor.rebootescrow-default /vendor/bin/hw/android.hardware.rebootescrow-service.default + interface aidl android.hardware.rebootescrow.IRebootEscrow/default + class hal + user system + group system + +on boot + chmod 770 /dev/access-kregistry + chown system system /dev/access-kregistry diff --git a/rebootescrow/aidl/default/rebootescrow-default.xml b/rebootescrow/aidl/default/rebootescrow-default.xml new file mode 100644 index 0000000000..0499fccdf3 --- /dev/null +++ b/rebootescrow/aidl/default/rebootescrow-default.xml @@ -0,0 +1,6 @@ + + + android.hardware.rebootescrow + IRebootEscrow/default + + diff --git a/rebootescrow/aidl/default/service.cpp b/rebootescrow/aidl/default/service.cpp new file mode 100644 index 0000000000..bd2378e513 --- /dev/null +++ b/rebootescrow/aidl/default/service.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.1 (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.1 + * + * 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 "rebootescrow-impl/RebootEscrow.h" + +#include +#include +#include + +using aidl::android::hardware::rebootescrow::RebootEscrow; + +int main() { + ABinderProcess_setThreadPoolMaxThreadCount(0); + + auto re = ndk::SharedRefBase::make(); + const std::string instance = std::string() + RebootEscrow::descriptor + "/default"; + binder_status_t status = AServiceManager_addService(re->asBinder().get(), instance.c_str()); + CHECK(status == STATUS_OK); + + ABinderProcess_joinThreadPool(); + return EXIT_FAILURE; +} From 4bb9cab24c32aa91126bfede4a83aaaffd4278ea Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 19 Dec 2019 13:15:44 -0800 Subject: [PATCH 0364/1022] graphics.mapper@4.0: Document previously-implicit accessRegion behavior. Existing Android framework code (and transitively, CTS test) require that an accessRegion of (0,0,0,0) is treated the same as an accessRegion covering the entire buffer, when calling lock() or lockYCbCr(). Document this so that there is no confusion about this going forward, since this requirement pre-dates the HIDL HALs. Bug: 119440345 Test: Builds, passes CTS Change-Id: I5ff86539ee28a72dd972255ad405db357e62536d --- graphics/mapper/4.0/IMapper.hal | 3 +++ 1 file changed, 3 insertions(+) diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal index 03dfef1e3f..d024c6e239 100644 --- a/graphics/mapper/4.0/IMapper.hal +++ b/graphics/mapper/4.0/IMapper.hal @@ -206,6 +206,9 @@ interface IMapper { * outside of @p accessRegion is undefined, except that it must not cause * process termination. * + * An accessRegion of all-zeros means the entire buffer. That is, it is + * equivalent to '(0,0)-(buffer width, buffer height)'. + * * This function can lock both single-planar and multi-planar formats. The caller * should use get() to get information about the buffer they are locking. * get() can be used to get information about the planes, offsets, stride, From 9506563fb4db15ad0cf60801d562927db0368a38 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 19 Dec 2019 13:36:27 -0800 Subject: [PATCH 0365/1022] gralloc: update doc to reflect security change The MetadataType must be prepended to any StandardMetadataType byte stream. The encode/decode support library already adds the MetadataType. This patch updates the documentation. Test: Compiles Bug: 137966819 Change-Id: I620f3cc0edd088b062844bb7a718f34360454d71 --- .../hardware/graphics/common/StandardMetadataType.aidl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl index 060d12c46e..e5a189e008 100644 --- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl +++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl @@ -24,6 +24,15 @@ package android.hardware.graphics.common; * * IMapper@4.x must support getting the following standard buffer metadata types. IMapper@4.x may * support setting these standard buffer metadata types as well. + * + * When encoding these StandardMetadataTypes into a byte stream, the associated MetadataType is + * is first encoded followed by the StandardMetadataType value. The MetadataType is encoded by + * writing the length of MetadataType.name using 8 bytes in little endian, followed by a char + * array of MetadataType.name's characters. The char array is not null terminated. Finally, + * MetadataType.value is represented by 8 bytes written in little endian. + * + * The StandardMetadataType encode/decode support library can be found in: + * frameworks/native/libs/gralloc/types/include/gralloctypes/Gralloc4.h. */ @VintfStability @Backing(type="long") From a9b1d79ed01045586d695f63a0501c29b593fd28 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 9 Dec 2019 14:02:56 -0800 Subject: [PATCH 0366/1022] Added SSC mode 3 support Added flags, deprecated time, and expired time field to the IP address. This will allow baseband vendor to mark an IP address as deprecated and inform upper layer when the IP address will become deprecated and expired. Test: Telephony sanity tests Bug: 135717900 Change-Id: Ia00827f5ff1201d36439f5b2219312b3fd2f0d24 --- current.txt | 6 +- radio/1.5/IRadio.hal | 14 +-- radio/1.5/IRadioResponse.hal | 2 +- radio/1.5/types.hal | 108 ++++++++++++++++++ .../1.5/vts/functional/radio_hidl_hal_api.cpp | 5 +- .../functional/radio_hidl_hal_utils_v1_5.h | 2 +- radio/1.5/vts/functional/radio_response.cpp | 2 +- 7 files changed, 123 insertions(+), 16 deletions(-) diff --git a/current.txt b/current.txt index 279167f530..eed694b524 100644 --- a/current.txt +++ b/current.txt @@ -658,10 +658,10 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar 619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types -0e3c23f1c815469fdcdc39bc33a486817771c7c6b6e5303f2f25569499fc6c69 android.hardware.radio@1.5::types -2bc87cde08fcd8d9a0f5d4a2b8560ea793264d94f5b763a6b22d4a63d0f3cd5a android.hardware.radio@1.5::IRadio +7a4ba60b5ddedf497e5d2bdff7d72b7d4a811969000e28677dd9e2389e683b34 android.hardware.radio@1.5::types +afa2d6cf4c0ba4b8482d5bcc097594ad5bc49be0bf3003034f75955cdaf66045 android.hardware.radio@1.5::IRadio 3afac66f21a33bc9c4b80481c7d5540038348651d9a7d8af64ea13610af138da android.hardware.radio@1.5::IRadioIndication -67c8d90dab3f5b8f1e9cf123d6d1f9e581d382846eacc14476335798b9670885 android.hardware.radio@1.5::IRadioResponse +f4888f9676890b43a459c6380f335fea7a6ad32ed3bafafeb018a88d6c0be8a4 android.hardware.radio@1.5::IRadioResponse 55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal index 62a2c61df0..fafc6e204d 100644 --- a/radio/1.5/IRadio.hal +++ b/radio/1.5/IRadio.hal @@ -18,8 +18,10 @@ package android.hardware.radio@1.5; import @1.2::DataRequestReason; import @1.4::IRadio; +import @1.4::DataProfileInfo; import @1.5::AccessNetwork; import @1.5::DataProfileInfo; +import @1.5::LinkAddress; import @1.5::NetworkScanRequest; import @1.5::RadioAccessSpecifier; import @1.5::SignalThresholdInfo; @@ -149,12 +151,8 @@ interface IRadio extends @1.4::IRadio { * @param reason The request reason. Must be DataRequestReason.NORMAL or * DataRequestReason.HANDOVER. * @param addresses If the reason is DataRequestReason.HANDOVER, this indicates the list of link - * addresses of the existing data connection. The format is IP address with optional "/" - * prefix length (The format is defined in RFC-4291 section 2.3). For example, "192.0.1.3", - * "192.0.1.11/16", or "2001:db8::1/64". Typically one IPv4 or one IPv6 or one of each. If - * the prefix length is absent, then the addresses are assumed to be point to point with - * IPv4 with prefix length 32 or IPv6 with prefix length 128. This parameter must be ignored - * unless reason is DataRequestReason.HANDOVER. + * addresses of the existing data connection. This parameter must be ignored unless reason + * is DataRequestReason.HANDOVER. * @param dnses If the reason is DataRequestReason.HANDOVER, this indicates the list of DNS * addresses of the existing data connection. The format is defined in RFC-4291 section * 2.2. For example, "192.0.1.3" or "2001:db8::1". This parameter must be ignored unless @@ -163,11 +161,11 @@ interface IRadio extends @1.4::IRadio { * Response function is IRadioResponse.setupDataCallResponse_1_5() * * Note this API is the same as the 1.4 version except using the - * 1.5 AccessNetwork and DataProfileInto as the input param. + * 1.5 AccessNetwork, DataProfileInto, and link addresses as the input param. */ oneway setupDataCall_1_5(int32_t serial, AccessNetwork accessNetwork, DataProfileInfo dataProfileInfo, bool roamingAllowed, - DataRequestReason reason, vec addresses, vec dnses); + DataRequestReason reason, vec addresses, vec dnses); /** * Set an apn to initial attach network diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal index 7a0bc579fa..968948b1ae 100644 --- a/radio/1.5/IRadioResponse.hal +++ b/radio/1.5/IRadioResponse.hal @@ -18,7 +18,7 @@ package android.hardware.radio@1.5; import @1.0::RadioResponseInfo; import @1.4::IRadioResponse; -import @1.4::SetupDataCallResult; +import @1.5::SetupDataCallResult; /** * Interface declaring response functions to solicited radio requests. diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index 5795f7b925..73751b81d6 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -25,7 +25,10 @@ import @1.1::UtranBands; import @1.2::NetworkScanRequest; import @1.4::AccessNetwork; import @1.4::ApnTypes; +import @1.4::DataCallFailCause; +import @1.4::DataConnActiveStatus; import @1.4::DataProfileInfo; +import @1.4::PdpProtocolType; /** * Defining signal strength type. @@ -289,3 +292,108 @@ struct DataProfileInfo { /** Supported APN types bitmap. See ApnTypes for the value of each bit. */ bitfield supportedApnTypesBitmap; }; + +/** + * The properties of the link address. This enum reflects the definition in + * if_addr.h in Linux kernel. + */ +enum AddressProperty : int32_t { + NONE = 0, + + /** Indicates this address is deprecated */ + DEPRECATED = 0x20, +}; + +/** + * Describes a data link address for mobile data connection. + */ +struct LinkAddress { + /** + * The format is IP address with optional "/" + * prefix length (The format is defined in RFC-4291 section 2.3). For example, "192.0.1.3", + * "192.0.1.11/16", or "2001:db8::1/64". Typically one IPv4 or one IPv6 or one of each. If + * the prefix length is absent, then the addresses are assumed to be point to point with + * IPv4 with prefix length 32 or IPv6 with prefix length 128. + */ + string address; + + /** + * The properties of the link address + */ + bitfield properties; + + /** + * The UTC time that this link address will be deprecated. 0 indicates this information is not + * available. + */ + uint64_t deprecatedTime; + + /** + * The UTC time that this link address will expire and no longer valid. 0 indicates this + * information is not available. + */ + uint64_t expiredTime; +}; + +/** + * Overwritten from @1.4::SetupDataCallResult in order to update the addresses to 1.5 + * version. In 1.5 the type of addresses changes to vector of LinkAddress. + */ +struct SetupDataCallResult { + /** Data call fail cause. DataCallFailCause.NONE if no error. */ + DataCallFailCause cause; + + /** + * If status != DataCallFailCause.NONE, this field indicates the suggested retry back-off timer + * value RIL wants to override the one pre-configured in FW. The unit is milliseconds. + * The value < 0 means no value is suggested. + * The value 0 means retry must be done ASAP. + * The value of INT_MAX(0x7fffffff) means no retry. + */ + int32_t suggestedRetryTime; + + /** Context ID, uniquely identifies this call. */ + int32_t cid; + + /** Data connection active status. */ + DataConnActiveStatus active; + + /** + * PDP_type values. If cause is DataCallFailCause.ONLY_SINGLE_BEARER_ALLOWED, this is the type + * supported such as "IP" or "IPV6". + */ + PdpProtocolType type; + + /** The network interface name. */ + string ifname; + + /** + * List of link address. + */ + vec addresses; + + /** + * List of DNS server addresses, e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1". Empty if no dns + * server addresses returned. + */ + vec dnses; + + /** + * List of default gateway addresses, e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1". + * When empty, the addresses represent point to point connections. + */ + vec gateways; + + /** + * List of P-CSCF(Proxy Call State Control Function) addresses via PCO(Protocol Configuration + * Option), e.g., "2001:db8::1 2001:db8::2 2001:db8::3". Empty if not IMS client. + */ + vec pcscf; + + /** + * MTU received from network. Value <= 0 means network has either not sent a value or sent an + * invalid value. + */ + int32_t mtu; +}; + diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp index d05d2cbe0f..77d9a02df0 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp @@ -853,10 +853,11 @@ TEST_F(RadioHidlTest_v1_5, setupDataCall_1_5) { bool roamingAllowed = false; + std::vector<::android::hardware::radio::V1_5::LinkAddress> addresses = {}; + std::vector dnses = {}; + ::android::hardware::radio::V1_2::DataRequestReason reason = ::android::hardware::radio::V1_2::DataRequestReason::NORMAL; - std::vector addresses = {""}; - std::vector dnses = {""}; Return res = radio_v1_5->setupDataCall_1_5(serial, accessNetwork, dataProfileInfo, roamingAllowed, reason, addresses, dnses); diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index c2ee94e401..ba1125767b 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -544,7 +544,7 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon Return setupDataCallResponse_1_5( const RadioResponseInfo& info, - const android::hardware::radio::V1_4::SetupDataCallResult& dcResponse); + const android::hardware::radio::V1_5::SetupDataCallResult& dcResponse); Return setInitialAttachApnResponse_1_5(const RadioResponseInfo& info); diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp index 8932a6499d..a0b3d5fa18 100644 --- a/radio/1.5/vts/functional/radio_response.cpp +++ b/radio/1.5/vts/functional/radio_response.cpp @@ -931,7 +931,7 @@ Return RadioResponse_v1_5::startNetworkScanResponse_1_5(const RadioRespons Return RadioResponse_v1_5::setupDataCallResponse_1_5( const RadioResponseInfo& info, - const android::hardware::radio::V1_4::SetupDataCallResult& /* dcResponse */) { + const android::hardware::radio::V1_5::SetupDataCallResult& /* dcResponse */) { rspInfo = info; parent_v1_5.notify(info.serial); return Void(); From 36768048c4fde736a000c5efd83ba1ceb2bc90a9 Mon Sep 17 00:00:00 2001 From: Hai Shalom Date: Wed, 4 Dec 2019 15:50:57 -0800 Subject: [PATCH 0367/1022] [DPP R2] Support for DPP R2 Added necessary types and enhanced the callbacks for DPP R2. Added VTS tests for DPP R2 using HAL 1.3. Bug: 139381558 Test: atest VtsHalWifiSupplicantV1_3Host Change-Id: I18a58d6bd0e0b8260946f2186abda5bac93729c7 --- current.txt | 4 +- .../1.3/ISupplicantStaIfaceCallback.hal | 27 +++ wifi/supplicant/1.3/types.hal | 27 +++ .../supplicant_sta_iface_hidl_test.cpp | 214 ++++++++++++++++++ 4 files changed, 270 insertions(+), 2 deletions(-) diff --git a/current.txt b/current.txt index c6e206d451..ecfe7bd67c 100644 --- a/current.txt +++ b/current.txt @@ -654,9 +654,9 @@ cf1d55e8c68300090747ab90b94c22e4c859b29c84ced68a317c595bb115eab2 android.hardwar 2defa258951e25a132aaeb36e3febe6f41bf9c6dbb1b1ebdf0b41708ab4e107e android.hardware.wifi.hostapd@1.2::types a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant 213457930af81ff3ea344fbc9d4a0d0a2bb70527f96b7b6a32ee3b5e4c17057e android.hardware.wifi.supplicant@1.3::ISupplicantStaIface -619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback +c1b8cfff5a86a7edef800a65b7c8fa025f4546cb95710d48e27bac50a8d16619 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback a6163000e2804472924733bcf8b4269db776460cc4df64f9c4dc8350d7aeafc5 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork -9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types +16e3e23eea763fbff39230ef069823643c5760b738b3661dbbdaf460c5b9ba13 android.hardware.wifi.supplicant@1.3::types 7a4ba60b5ddedf497e5d2bdff7d72b7d4a811969000e28677dd9e2389e683b34 android.hardware.radio@1.5::types afa2d6cf4c0ba4b8482d5bcc097594ad5bc49be0bf3003034f75955cdaf66045 android.hardware.radio@1.5::IRadio 3afac66f21a33bc9c4b80481c7d5540038348651d9a7d8af64ea13610af138da android.hardware.radio@1.5::IRadioIndication diff --git a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal index 107e0fc0f6..ae7f7970c3 100644 --- a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal +++ b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal @@ -35,4 +35,31 @@ interface ISupplicantStaIfaceCallback extends @1.2::ISupplicantStaIfaceCallback * opaque for the framework and depends on the native implementation. */ oneway onPmkCacheAdded(int64_t expirationTimeInSec, vec serializedEntry); + + /** + * Indicates a DPP success event. + */ + oneway onDppSuccess(DppSuccessCode code); + + /** + * Indicates a DPP progress event. + */ + oneway onDppProgress_1_3(DppProgressCode code); + + /** + * Indicates a DPP failure event. + * + * ssid: A string indicating the SSID for the AP that the Enrollee attempted to connect. + * channelList: A string containing a list of operating channels and operating classes + * indicating the channels that the Enrollee scanned in attempting to discover the AP. + * The list conforms to the following ABNF syntax: + * channel-list2 = class-and-channels *(“,” class-and-channels) + * class-and-channels = class “/” channel *(“,” channel) + * class = 1*3DIGIT + * channel = 1*3DIGIT + * bandList: A list of band parameters that are supported by the Enrollee expressed as the + * Operating Class. + */ + oneway onDppFailure_1_3(DppFailureCode code, string ssid, string channelList, + vecbandList); }; diff --git a/wifi/supplicant/1.3/types.hal b/wifi/supplicant/1.3/types.hal index 4e01ab1df8..2e5027954f 100644 --- a/wifi/supplicant/1.3/types.hal +++ b/wifi/supplicant/1.3/types.hal @@ -15,6 +15,8 @@ */ package android.hardware.wifi.supplicant@1.3; +import @1.2::DppProgressCode; +import @1.2::DppFailureCode; /** * OcspType: The type of OCSP request. @@ -72,3 +74,28 @@ enum WpaDriverCapabilitiesMask : uint32_t { */ OCE = 1 << 1, }; + +/** + * DppProgressCode: Progress codes for DPP (Easy Connect) + */ +enum DppProgressCode : @1.2::DppProgressCode { + CONFIGURATION_SENT_WAITING_RESPONSE, + CONFIGURATION_ACCEPTED, +}; + +/** + * DppSuccessCode: Success codes for DPP (Easy Connect) Configurator + */ +enum DppSuccessCode : uint32_t { + CONFIGURATION_SENT, /* Replaces @1.2::onDppSuccessConfigSent() */ + CONFIGURATION_APPLIED, +}; + +/** + * DppFailureCode: Error codes for DPP (Easy Connect) + */ +enum DppFailureCode : @1.2::DppFailureCode { + CONFIGURATION_REJECTED, + CANNOT_FIND_NETWORK, + ENROLLEE_AUTHENTICATION, +}; diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp index ca3265e960..2b08e48fd6 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp @@ -36,13 +36,18 @@ using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus; using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; using ::android::hardware::wifi::supplicant::V1_2::DppAkm; using ::android::hardware::wifi::supplicant::V1_2::DppFailureCode; +using ::android::hardware::wifi::supplicant::V1_2::DppNetRole; using ::android::hardware::wifi::supplicant::V1_2::DppProgressCode; using ::android::hardware::wifi::supplicant::V1_3::ConnectionCapabilities; +using ::android::hardware::wifi::supplicant::V1_3::DppSuccessCode; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIfaceCallback; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork; using ::android::hardware::wifi::supplicant::V1_3::WpaDriverCapabilitiesMask; +#define TIMEOUT_PERIOD 60 +class IfaceDppCallback; + class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { public: virtual void SetUp() override { @@ -57,9 +62,64 @@ class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { int64_t pmkCacheExpirationTimeInSec; std::vector serializedPmkCacheEntry; + enum DppCallbackType { + ANY_CALLBACK = -2, + INVALID = -1, + + EVENT_SUCCESS = 0, + EVENT_PROGRESS, + EVENT_FAILURE, + }; + + DppCallbackType dppCallbackType; + uint32_t code; + + /* Used as a mechanism to inform the test about data/event callback */ + inline void notify() { + std::unique_lock lock(mtx_); + count_++; + cv_.notify_one(); + } + + /* Test code calls this function to wait for data/event callback */ + inline std::cv_status wait(DppCallbackType waitForCallbackType) { + std::unique_lock lock(mtx_); + EXPECT_NE(INVALID, waitForCallbackType); // can't ASSERT in a + // non-void-returning method + auto now = std::chrono::system_clock::now(); + std::cv_status status = + cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD)); + return status; + } + + private: + // synchronization objects + std::mutex mtx_; + std::condition_variable cv_; + int count_; + protected: // ISupplicantStaIface object used for all tests in this fixture. sp sta_iface_; + bool isDppSupported() { + uint32_t keyMgmtMask = 0; + + // We need to first get the key management capabilities from the device. + // If DPP is not supported, we just pass the test. + sta_iface_->getKeyMgmtCapabilities( + [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + + keyMgmtMask = keyMgmtMaskInternal; + }); + + if (!(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::DPP)) { + // DPP not supported + return false; + } + + return true; + } }; class IfaceCallback : public ISupplicantStaIfaceCallback { @@ -150,6 +210,20 @@ class IfaceCallback : public ISupplicantStaIfaceCallback { Return onDppFailure(DppFailureCode /* code */) override { return Void(); } + Return onDppSuccess(DppSuccessCode /* code */) override { + return Void(); + } + Return onDppProgress_1_3( + ::android::hardware::wifi::supplicant::V1_3::DppProgressCode /* code */) + override { + return Void(); + } + Return onDppFailure_1_3( + ::android::hardware::wifi::supplicant::V1_3::DppFailureCode /* code */, + const hidl_string& /* ssid */, const hidl_string& /* channelList */, + const hidl_vec& /* bandList */) override { + return Void(); + } Return onPmkCacheAdded( int64_t /* expirationTimeInSec */, const hidl_vec& /* serializedEntry */) override { @@ -172,6 +246,39 @@ class IfacePmkCacheCallback : public IfaceCallback { : parent_(parent) {} }; +class IfaceDppCallback : public IfaceCallback { + SupplicantStaIfaceHidlTest& parent_; + Return onDppSuccess(DppSuccessCode code) override { + parent_.code = (uint32_t)code; + parent_.dppCallbackType = + SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_SUCCESS; + parent_.notify(); + return Void(); + } + Return onDppProgress_1_3( + ::android::hardware::wifi::supplicant::V1_3::DppProgressCode code) + override { + parent_.code = (uint32_t)code; + parent_.dppCallbackType = + SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_PROGRESS; + parent_.notify(); + return Void(); + } + Return onDppFailure_1_3( + ::android::hardware::wifi::supplicant::V1_3::DppFailureCode code, + const hidl_string& ssid __attribute__((unused)), + const hidl_string& channelList __attribute__((unused)), + const hidl_vec& bandList __attribute__((unused))) override { + parent_.code = (uint32_t)code; + parent_.dppCallbackType = + SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE; + parent_.notify(); + return Void(); + } + + public: + IfaceDppCallback(SupplicantStaIfaceHidlTest& parent) : parent_(parent){}; +}; /* * RegisterCallback_1_3 */ @@ -246,3 +353,110 @@ TEST_F(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities_1_3) { } }); } + +/* + * StartDppEnrolleeInitiator + */ +TEST_F(SupplicantStaIfaceHidlTest, StartDppEnrolleeInitiator) { + // We need to first get the key management capabilities from the device. + // If DPP is not supported, we just pass the test. + if (!isDppSupported()) { + // DPP not supported + return; + } + + hidl_string uri = + "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj" + "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;"; + uint32_t peer_id = 0; + + // Register callbacks + sta_iface_->registerCallback_1_3( + new IfaceDppCallback(*this), [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + // Add a peer URI + sta_iface_->addDppPeerUri( + uri, [&](const SupplicantStatus& status, uint32_t id) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + EXPECT_NE(0, id); + EXPECT_NE(-1, id); + + peer_id = id; + }); + + // Start DPP as Enrollee-Initiator. Since this operation requires two + // devices, we start the operation and expect a timeout. + sta_iface_->startDppEnrolleeInitiator( + peer_id, 0, [&](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + // Wait for the timeout callback + ASSERT_EQ(std::cv_status::no_timeout, + wait(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE)); + ASSERT_EQ(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE, + dppCallbackType); + + // ...and then remove the peer URI. + sta_iface_->removeDppUri(peer_id, [&](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); +} + +/* + * StartDppConfiguratorInitiator + */ +TEST_F(SupplicantStaIfaceHidlTest, StartDppConfiguratorInitiator) { + // We need to first get the key management capabilities from the device. + // If DPP is not supported, we just pass the test. + if (!isDppSupported()) { + // DPP not supported + return; + } + + hidl_string uri = + "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj" + "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;"; + uint32_t peer_id = 0; + + // Register callbacks + sta_iface_->registerCallback_1_3( + new IfaceDppCallback(*this), [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + // Add a peer URI + sta_iface_->addDppPeerUri( + uri, [&](const SupplicantStatus& status, uint32_t id) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + EXPECT_NE(0, id); + EXPECT_NE(-1, id); + + peer_id = id; + }); + + std::string ssid = + "6D795F746573745F73736964"; // 'my_test_ssid' encoded in hex + std::string password = "746F70736563726574"; // 'topsecret' encoded in hex + + // Start DPP as Configurator-Initiator. Since this operation requires two + // devices, we start the operation and expect a timeout. + sta_iface_->startDppConfiguratorInitiator( + peer_id, 0, ssid, password, NULL, DppNetRole::STA, DppAkm::PSK, + [&](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + // Wait for the timeout callback + ASSERT_EQ(std::cv_status::no_timeout, + wait(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE)); + ASSERT_EQ(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE, + dppCallbackType); + + // ...and then remove the peer URI. + sta_iface_->removeDppUri(peer_id, [&](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); +} From 55f21936e9c91d1515ede4076ed097cee5f4a15c Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 20 Dec 2019 09:20:24 -0800 Subject: [PATCH 0368/1022] Migrate CAN bus HAL to nested namespaces Test: it builds Change-Id: I83d9ef4f1fff1585e6487c95f09b55b1aa5b3e63 --- automotive/can/1.0/default/CanBus.cpp | 14 ++------------ automotive/can/1.0/default/CanBus.h | 14 ++------------ automotive/can/1.0/default/CanBusNative.cpp | 14 ++------------ automotive/can/1.0/default/CanBusNative.h | 14 ++------------ automotive/can/1.0/default/CanBusSlcan.cpp | 14 ++------------ automotive/can/1.0/default/CanBusSlcan.h | 14 ++------------ automotive/can/1.0/default/CanBusVirtual.cpp | 14 ++------------ automotive/can/1.0/default/CanBusVirtual.h | 14 ++------------ automotive/can/1.0/default/CanController.cpp | 14 ++------------ automotive/can/1.0/default/CanController.h | 14 ++------------ automotive/can/1.0/default/CanSocket.cpp | 14 ++------------ automotive/can/1.0/default/CanSocket.h | 14 ++------------ automotive/can/1.0/default/CloseHandle.cpp | 14 ++------------ automotive/can/1.0/default/CloseHandle.h | 14 ++------------ .../1.0/default/libnetdevice/NetlinkRequest.cpp | 8 ++------ .../1.0/default/libnetdevice/NetlinkRequest.h | 6 ++---- .../1.0/default/libnetdevice/NetlinkSocket.cpp | 6 ++---- .../can/1.0/default/libnetdevice/NetlinkSocket.h | 6 ++---- automotive/can/1.0/default/libnetdevice/can.cpp | 8 ++------ .../can/1.0/default/libnetdevice/common.cpp | 6 ++---- automotive/can/1.0/default/libnetdevice/common.h | 6 ++---- .../libnetdevice/include/libnetdevice/can.h | 8 ++------ .../include/libnetdevice/libnetdevice.h | 6 ++---- .../1.0/default/libnetdevice/libnetdevice.cpp | 6 ++---- automotive/can/1.0/default/service.cpp | 14 ++------------ .../hidl-utils/include/hidl-utils/hidl-utils.h | 10 ++-------- automotive/can/1.0/tools/canhalctrl.cpp | 10 ++-------- automotive/can/1.0/tools/canhaldump.cpp | 10 ++-------- automotive/can/1.0/tools/canhalsend.cpp | 10 ++-------- .../functional/VtsHalCanBusV1_0TargetTest.cpp | 14 ++------------ .../VtsHalCanBusVirtualV1_0TargetTest.cpp | 14 ++------------ .../VtsHalCanControllerV1_0TargetTest.cpp | 14 ++------------ .../include/can-vts-utils/can-hal-printers.h | 12 ++---------- .../include/can-vts-utils/environment-utils.h | 16 ++-------------- 34 files changed, 68 insertions(+), 318 deletions(-) diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp index 86df5dc93b..454ab008ef 100644 --- a/automotive/can/1.0/default/CanBus.cpp +++ b/automotive/can/1.0/default/CanBus.cpp @@ -25,12 +25,7 @@ #include #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace implementation { +namespace android::hardware::automotive::can::V1_0::implementation { /** Whether to log sent/received packets. */ static constexpr bool kSuperVerbose = false; @@ -345,9 +340,4 @@ void CanBus::onError(int errnoVal) { if (errcb != nullptr) errcb(); } -} // namespace implementation -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::implementation diff --git a/automotive/can/1.0/default/CanBus.h b/automotive/can/1.0/default/CanBus.h index da3fc5a5d8..8b73258318 100644 --- a/automotive/can/1.0/default/CanBus.h +++ b/automotive/can/1.0/default/CanBus.h @@ -26,12 +26,7 @@ #include #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace implementation { +namespace android::hardware::automotive::can::V1_0::implementation { struct CanBus : public ICanBus { using ErrorCallback = std::function; @@ -114,9 +109,4 @@ struct CanBus : public ICanBus { ErrorCallback mErrCb; }; -} // namespace implementation -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::implementation diff --git a/automotive/can/1.0/default/CanBusNative.cpp b/automotive/can/1.0/default/CanBusNative.cpp index 365b749cd7..88f9175f8b 100644 --- a/automotive/can/1.0/default/CanBusNative.cpp +++ b/automotive/can/1.0/default/CanBusNative.cpp @@ -20,12 +20,7 @@ #include #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace implementation { +namespace android::hardware::automotive::can::V1_0::implementation { CanBusNative::CanBusNative(const std::string& ifname, uint32_t baudrate) : CanBus(ifname), mBaudrate(baudrate) {} @@ -49,9 +44,4 @@ ICanController::Result CanBusNative::preUp() { return ICanController::Result::OK; } -} // namespace implementation -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::implementation diff --git a/automotive/can/1.0/default/CanBusNative.h b/automotive/can/1.0/default/CanBusNative.h index 126f1cb77c..7eda68342e 100644 --- a/automotive/can/1.0/default/CanBusNative.h +++ b/automotive/can/1.0/default/CanBusNative.h @@ -18,12 +18,7 @@ #include "CanBus.h" -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace implementation { +namespace android::hardware::automotive::can::V1_0::implementation { struct CanBusNative : public CanBus { CanBusNative(const std::string& ifname, uint32_t baudrate); @@ -35,9 +30,4 @@ struct CanBusNative : public CanBus { const uint32_t mBaudrate; }; -} // namespace implementation -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::implementation diff --git a/automotive/can/1.0/default/CanBusSlcan.cpp b/automotive/can/1.0/default/CanBusSlcan.cpp index 7dce838ff1..29d9d3c238 100644 --- a/automotive/can/1.0/default/CanBusSlcan.cpp +++ b/automotive/can/1.0/default/CanBusSlcan.cpp @@ -25,12 +25,7 @@ #include #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace implementation { +namespace android::hardware::automotive::can::V1_0::implementation { namespace slcanprotocol { static const std::string kOpenCommand = "O\r"; @@ -158,9 +153,4 @@ bool CanBusSlcan::postDown() { return true; } -} // namespace implementation -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::implementation diff --git a/automotive/can/1.0/default/CanBusSlcan.h b/automotive/can/1.0/default/CanBusSlcan.h index 2713da86d9..3328a9f4ca 100644 --- a/automotive/can/1.0/default/CanBusSlcan.h +++ b/automotive/can/1.0/default/CanBusSlcan.h @@ -22,12 +22,7 @@ #include #include "CanBus.h" -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace implementation { +namespace android::hardware::automotive::can::V1_0::implementation { struct CanBusSlcan : public CanBus { CanBusSlcan(const std::string& uartName, uint32_t bitrate); @@ -42,9 +37,4 @@ struct CanBusSlcan : public CanBus { base::unique_fd mFd; }; -} // namespace implementation -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::implementation diff --git a/automotive/can/1.0/default/CanBusVirtual.cpp b/automotive/can/1.0/default/CanBusVirtual.cpp index cc59fa97b8..32fe8d6340 100644 --- a/automotive/can/1.0/default/CanBusVirtual.cpp +++ b/automotive/can/1.0/default/CanBusVirtual.cpp @@ -19,12 +19,7 @@ #include #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace implementation { +namespace android::hardware::automotive::can::V1_0::implementation { CanBusVirtual::CanBusVirtual(const std::string& ifname) : CanBus(ifname) {} @@ -52,9 +47,4 @@ bool CanBusVirtual::postDown() { return true; } -} // namespace implementation -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::implementation diff --git a/automotive/can/1.0/default/CanBusVirtual.h b/automotive/can/1.0/default/CanBusVirtual.h index c2d5794502..3990b20a0f 100644 --- a/automotive/can/1.0/default/CanBusVirtual.h +++ b/automotive/can/1.0/default/CanBusVirtual.h @@ -18,12 +18,7 @@ #include "CanBus.h" -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace implementation { +namespace android::hardware::automotive::can::V1_0::implementation { struct CanBusVirtual : public CanBus { CanBusVirtual(const std::string& ifname); @@ -36,9 +31,4 @@ struct CanBusVirtual : public CanBus { bool mWasCreated = false; }; -} // namespace implementation -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::implementation diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp index ffdc9125fc..cd17dd8edb 100644 --- a/automotive/can/1.0/default/CanController.cpp +++ b/automotive/can/1.0/default/CanController.cpp @@ -25,12 +25,7 @@ #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace implementation { +namespace android::hardware::automotive::can::V1_0::implementation { using IfaceIdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator; @@ -139,9 +134,4 @@ Return CanController::downInterface(const hidl_string& name) { return success; } -} // namespace implementation -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::implementation diff --git a/automotive/can/1.0/default/CanController.h b/automotive/can/1.0/default/CanController.h index 0674d0edf7..99a551af77 100644 --- a/automotive/can/1.0/default/CanController.h +++ b/automotive/can/1.0/default/CanController.h @@ -20,12 +20,7 @@ #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace implementation { +namespace android::hardware::automotive::can::V1_0::implementation { struct CanController : public ICanController { Return getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) override; @@ -39,9 +34,4 @@ struct CanController : public ICanController { std::map> mCanBuses GUARDED_BY(mCanBusesGuard); }; -} // namespace implementation -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::implementation diff --git a/automotive/can/1.0/default/CanSocket.cpp b/automotive/can/1.0/default/CanSocket.cpp index 86e12d19b1..86ccc0e84e 100644 --- a/automotive/can/1.0/default/CanSocket.cpp +++ b/automotive/can/1.0/default/CanSocket.cpp @@ -24,12 +24,7 @@ #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace implementation { +namespace android::hardware::automotive::can::V1_0::implementation { using namespace std::chrono_literals; @@ -152,9 +147,4 @@ void CanSocket::readerThread() { LOG(VERBOSE) << "Reader thread stopped"; } -} // namespace implementation -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::implementation diff --git a/automotive/can/1.0/default/CanSocket.h b/automotive/can/1.0/default/CanSocket.h index c98330bfe0..fd956b50f6 100644 --- a/automotive/can/1.0/default/CanSocket.h +++ b/automotive/can/1.0/default/CanSocket.h @@ -24,12 +24,7 @@ #include #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace implementation { +namespace android::hardware::automotive::can::V1_0::implementation { /** Wrapper around SocketCAN socket. */ struct CanSocket { @@ -71,9 +66,4 @@ struct CanSocket { DISALLOW_COPY_AND_ASSIGN(CanSocket); }; -} // namespace implementation -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::implementation diff --git a/automotive/can/1.0/default/CloseHandle.cpp b/automotive/can/1.0/default/CloseHandle.cpp index aba2c49a48..e1ffe2b8cf 100644 --- a/automotive/can/1.0/default/CloseHandle.cpp +++ b/automotive/can/1.0/default/CloseHandle.cpp @@ -16,12 +16,7 @@ #include "CloseHandle.h" -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace implementation { +namespace android::hardware::automotive::can::V1_0::implementation { CloseHandle::CloseHandle(Callback callback) : mCallback(callback) {} @@ -37,9 +32,4 @@ Return CloseHandle::close() { return {}; } -} // namespace implementation -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::implementation diff --git a/automotive/can/1.0/default/CloseHandle.h b/automotive/can/1.0/default/CloseHandle.h index eade1098a4..c332d7493f 100644 --- a/automotive/can/1.0/default/CloseHandle.h +++ b/automotive/can/1.0/default/CloseHandle.h @@ -19,12 +19,7 @@ #include #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace implementation { +namespace android::hardware::automotive::can::V1_0::implementation { /** Generic ICloseHandle implementation ignoring double-close events. */ struct CloseHandle : public ICloseHandle { @@ -49,9 +44,4 @@ struct CloseHandle : public ICloseHandle { DISALLOW_COPY_AND_ASSIGN(CloseHandle); }; -} // namespace implementation -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::implementation diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp index 9845bc7dd6..556debfc09 100644 --- a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp +++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp @@ -18,9 +18,7 @@ #include -namespace android { -namespace netdevice { -namespace impl { +namespace android::netdevice::impl { static struct rtattr* nlmsg_tail(struct nlmsghdr* n) { return reinterpret_cast( // @@ -53,6 +51,4 @@ void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest) { nest->rta_len = nestLen; } -} // namespace impl -} // namespace netdevice -} // namespace android +} // namespace android::netdevice::impl diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h index ba9b65bdd3..3e28d78485 100644 --- a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h +++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h @@ -21,8 +21,7 @@ #include -namespace android { -namespace netdevice { +namespace android::netdevice { typedef unsigned short rtattrtype_t; // as in rtnetlink.h typedef __u16 nlmsgtype_t; // as in netlink.h @@ -151,5 +150,4 @@ struct NetlinkRequest { } }; -} // namespace netdevice -} // namespace android +} // namespace android::netdevice diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp index 05147647e6..6a7f50681d 100644 --- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp +++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp @@ -18,8 +18,7 @@ #include -namespace android { -namespace netdevice { +namespace android::netdevice { NetlinkSocket::NetlinkSocket(int protocol) { mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol)); @@ -110,5 +109,4 @@ bool NetlinkSocket::receiveAck() { return false; } -} // namespace netdevice -} // namespace android +} // namespace android::netdevice diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h index 90e1f3f95d..2b40ea20c0 100644 --- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h +++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h @@ -23,8 +23,7 @@ #include -namespace android { -namespace netdevice { +namespace android::netdevice { /** * A wrapper around AF_NETLINK sockets. @@ -64,5 +63,4 @@ struct NetlinkSocket { DISALLOW_COPY_AND_ASSIGN(NetlinkSocket); }; -} // namespace netdevice -} // namespace android +} // namespace android::netdevice diff --git a/automotive/can/1.0/default/libnetdevice/can.cpp b/automotive/can/1.0/default/libnetdevice/can.cpp index 6452d9b8d1..06d45d3b7d 100644 --- a/automotive/can/1.0/default/libnetdevice/can.cpp +++ b/automotive/can/1.0/default/libnetdevice/can.cpp @@ -28,9 +28,7 @@ #include #include -namespace android { -namespace netdevice { -namespace can { +namespace android::netdevice::can { static constexpr can_err_mask_t kErrMask = CAN_ERR_MASK; @@ -95,6 +93,4 @@ bool setBitrate(std::string ifname, uint32_t bitrate) { return sock.send(req) && sock.receiveAck(); } -} // namespace can -} // namespace netdevice -} // namespace android +} // namespace android::netdevice::can diff --git a/automotive/can/1.0/default/libnetdevice/common.cpp b/automotive/can/1.0/default/libnetdevice/common.cpp index 3deac3e7ff..5c624439cd 100644 --- a/automotive/can/1.0/default/libnetdevice/common.cpp +++ b/automotive/can/1.0/default/libnetdevice/common.cpp @@ -20,8 +20,7 @@ #include -namespace android { -namespace netdevice { +namespace android::netdevice { unsigned int nametoindex(const std::string& ifname) { const auto ifidx = if_nametoindex(ifname.c_str()); @@ -34,5 +33,4 @@ unsigned int nametoindex(const std::string& ifname) { return 0; } -} // namespace netdevice -} // namespace android +} // namespace android::netdevice diff --git a/automotive/can/1.0/default/libnetdevice/common.h b/automotive/can/1.0/default/libnetdevice/common.h index 9bdff4de21..8097f374ad 100644 --- a/automotive/can/1.0/default/libnetdevice/common.h +++ b/automotive/can/1.0/default/libnetdevice/common.h @@ -18,8 +18,7 @@ #include -namespace android { -namespace netdevice { +namespace android::netdevice { /** * Returns the index of a given network interface. @@ -32,5 +31,4 @@ namespace netdevice { */ unsigned int nametoindex(const std::string& ifname); -} // namespace netdevice -} // namespace android +} // namespace android::netdevice diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h index d75361eaa0..3886acf1cd 100644 --- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h +++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h @@ -20,9 +20,7 @@ #include -namespace android { -namespace netdevice { -namespace can { +namespace android::netdevice::can { /** * Opens and binds SocketCAN socket. @@ -40,6 +38,4 @@ base::unique_fd socket(const std::string& ifname); */ bool setBitrate(std::string ifname, uint32_t bitrate); -} // namespace can -} // namespace netdevice -} // namespace android +} // namespace android::netdevice::can diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h index e22eafb723..3818a31c4c 100644 --- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h +++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h @@ -19,8 +19,7 @@ #include #include -namespace android { -namespace netdevice { +namespace android::netdevice { /** * Checks, if the network interface exists. @@ -71,5 +70,4 @@ bool add(std::string dev, std::string type); */ bool del(std::string dev); -} // namespace netdevice -} // namespace android +} // namespace android::netdevice diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp index fc2b193355..aee820573f 100644 --- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp +++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp @@ -25,8 +25,7 @@ #include #include -namespace android { -namespace netdevice { +namespace android::netdevice { bool exists(std::string ifname) { return nametoindex(ifname) != 0; @@ -96,5 +95,4 @@ bool del(std::string dev) { return sock.send(req) && sock.receiveAck(); } -} // namespace netdevice -} // namespace android +} // namespace android::netdevice diff --git a/automotive/can/1.0/default/service.cpp b/automotive/can/1.0/default/service.cpp index ebc2f8c51f..b52a54a5b7 100644 --- a/automotive/can/1.0/default/service.cpp +++ b/automotive/can/1.0/default/service.cpp @@ -19,12 +19,7 @@ #include #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace implementation { +namespace android::hardware::automotive::can::V1_0::implementation { static void canControllerService() { base::SetDefaultTag("CanController"); @@ -42,12 +37,7 @@ static void canControllerService() { joinRpcThreadpool(); } -} // namespace implementation -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::implementation int main() { ::android::hardware::automotive::can::V1_0::implementation::canControllerService(); diff --git a/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h b/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h index 039f971c35..f63d43cf33 100644 --- a/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h +++ b/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h @@ -16,10 +16,7 @@ #pragma once -namespace android { -namespace hardware { -namespace automotive { -namespace hidl_utils { +namespace android::hardware::automotive::hidl_utils { /** * Helper functor to fetch results from multi-return HIDL calls. @@ -61,7 +58,4 @@ struct fill : public std::function { } }; -} // namespace hidl_utils -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::hidl_utils diff --git a/automotive/can/1.0/tools/canhalctrl.cpp b/automotive/can/1.0/tools/canhalctrl.cpp index fa1048d6ac..5c9849bf0a 100644 --- a/automotive/can/1.0/tools/canhalctrl.cpp +++ b/automotive/can/1.0/tools/canhalctrl.cpp @@ -22,10 +22,7 @@ #include #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { +namespace android::hardware::automotive::can { using ICanController = V1_0::ICanController; @@ -170,10 +167,7 @@ static int main(int argc, char* argv[]) { } } -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can int main(int argc, char* argv[]) { if (argc < 1) return -1; diff --git a/automotive/can/1.0/tools/canhaldump.cpp b/automotive/can/1.0/tools/canhaldump.cpp index 55b2a347c7..2f5ca61321 100644 --- a/automotive/can/1.0/tools/canhaldump.cpp +++ b/automotive/can/1.0/tools/canhaldump.cpp @@ -27,10 +27,7 @@ #include #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { +namespace android::hardware::automotive::can { using namespace std::chrono_literals; @@ -128,10 +125,7 @@ static int main(int argc, char* argv[]) { return candump(argv[0]); } -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can int main(int argc, char* argv[]) { if (argc < 1) return -1; diff --git a/automotive/can/1.0/tools/canhalsend.cpp b/automotive/can/1.0/tools/canhalsend.cpp index 29330c9c75..7e6833a8a6 100644 --- a/automotive/can/1.0/tools/canhalsend.cpp +++ b/automotive/can/1.0/tools/canhalsend.cpp @@ -21,10 +21,7 @@ #include #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { +namespace android::hardware::automotive::can { using ICanBus = V1_0::ICanBus; using Result = V1_0::Result; @@ -125,10 +122,7 @@ static int main(int argc, char* argv[]) { return cansend(busname, msgid, payload); } -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can int main(int argc, char* argv[]) { if (argc < 1) return -1; diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp index 250caf2375..8deaed642b 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp @@ -24,12 +24,7 @@ #include #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace vts { +namespace android::hardware::automotive::can::V1_0::vts { using hardware::hidl_vec; @@ -173,12 +168,7 @@ TEST_F(CanBusHalTest, DontCloseErrorListener) { ASSERT_NE(nullptr, closeHandle.get()); } -} // namespace vts -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::vts /** * Example manual invocation: diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp index 695b9fb4ab..1663663ac6 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp @@ -31,12 +31,7 @@ #include #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace vts { +namespace android::hardware::automotive::can::V1_0::vts { using namespace std::chrono_literals; @@ -290,12 +285,7 @@ TEST_F(CanBusVirtualHalTest, Filter) { ASSERT_EQ(expectedPositive, messagesPositive); } -} // namespace vts -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::vts /** * Example manual invocation: diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp index 64e7a96823..22dec2cb9a 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp @@ -26,12 +26,7 @@ #include #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace vts { +namespace android::hardware::automotive::can::V1_0::vts { using hardware::hidl_vec; using InterfaceType = ICanController::InterfaceType; @@ -233,12 +228,7 @@ TEST_F(CanControllerHalTest, FailBadSocketcanAddress) { assertRegistered(name, false); } -} // namespace vts -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::vts /** * Example manual invocation: diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h index 09239989ef..3c30744802 100644 --- a/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h +++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h @@ -18,11 +18,7 @@ #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { +namespace android::hardware::automotive::can::V1_0 { /** * Define gTest printer for a given HIDL type, but skip definition for Return. @@ -48,8 +44,4 @@ DEFINE_CAN_HAL_PRINTER(Result, toString) #undef DEFINE_CAN_HAL_PRINTER #undef DEFINE_CAN_HAL_PRINTER_SIMPLE -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0 diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h index a722dd0783..3eb9cc1b83 100644 --- a/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h +++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h @@ -18,13 +18,7 @@ #include -namespace android { -namespace hardware { -namespace automotive { -namespace can { -namespace V1_0 { -namespace vts { -namespace utils { +namespace android::hardware::automotive::can::V1_0::vts::utils { /** * Simple test environment. @@ -63,10 +57,4 @@ class SimpleHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { } }; -} // namespace utils -} // namespace vts -} // namespace V1_0 -} // namespace can -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::can::V1_0::vts::utils From de6835be3eefc7e5ab589e519d501659b14d3593 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Thu, 5 Dec 2019 16:36:19 -0800 Subject: [PATCH 0369/1022] Simplify Connector class APIs and hierachy Test: Build; unit tests `atest packages/services/Car/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarPropertyTest.java` Bug: b/141493212 Change-Id: I6c561d517646760dfff63cb6c6b50c3c5994098a --- .../include/vhal_v2_0/VehicleConnector.h | 24 +++++++---- .../vhal_v2_0/EmulatedVehicleConnector.cpp | 42 +++++++++---------- .../impl/vhal_v2_0/EmulatedVehicleConnector.h | 22 +++------- .../impl/vhal_v2_0/EmulatedVehicleHal.cpp | 33 +++++++-------- .../impl/vhal_v2_0/EmulatedVehicleHal.h | 2 +- 5 files changed, 59 insertions(+), 64 deletions(-) diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h index 56ecd67ea2..d40f122741 100644 --- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h @@ -57,10 +57,14 @@ class IVehicleClient { virtual std::vector getAllPropertyConfig() const = 0; // Send the set property request to server - virtual StatusCode setProperty(const VehiclePropValue& value) = 0; + // updateStatus indicate if VHal should change the status of the value + // it should be false except injecting values for e2e tests + virtual StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) = 0; // Receive a new property value from server - virtual void onPropertyValue(const VehiclePropValue& value) = 0; + // updateStatus is true if and only if the value is + // generated by car (ECU/fake generator/injected) + virtual void onPropertyValue(const VehiclePropValue& value, bool updateStatus) = 0; }; /** @@ -84,11 +88,15 @@ class IVehicleServer { // Receive the set property request from HAL. // Process the setting and return the status code - virtual StatusCode onSetProperty(const VehiclePropValue& value) = 0; + // updateStatus indicate if VHal should change the status of the value + // it should be false except injecting values for e2e tests + virtual StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) = 0; // Receive a new property value from car (via direct connection to the car bus or the emulator) // and forward the value to HAL - virtual void onPropertyValueFromCar(const VehiclePropValue& value) = 0; + // updateStatus is true if and only if the value is + // generated by car (ECU/fake generator/injected) + virtual void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) = 0; }; /** @@ -118,12 +126,12 @@ class IPassThroughConnector : public VehicleClientType, public VehicleServerType return this->onGetAllPropertyConfig(); } - StatusCode setProperty(const VehiclePropValue& value) override { - return this->onSetProperty(value); + StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) override { + return this->onSetProperty(value, updateStatus); } - void onPropertyValueFromCar(const VehiclePropValue& value) override { - return this->onPropertyValue(value); + void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) override { + return this->onPropertyValue(value, updateStatus); } // To be implemented: diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp index 168999d829..89c5a4b65c 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp @@ -30,12 +30,12 @@ namespace V2_0 { namespace impl { -void EmulatedVehicleClient::onPropertyValue(const VehiclePropValue& value) { +void EmulatedVehicleClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) { if (!mPropCallback) { LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!"; return; } - return mPropCallback(value); + return mPropCallback(value, updateStatus); } void EmulatedVehicleClient::registerPropertyValueCallback(PropertyCallBackType&& callback) { @@ -65,12 +65,13 @@ void EmulatedVehicleServer::setValuePool(VehiclePropValuePool* valuePool) { } void EmulatedVehicleServer::onFakeValueGenerated(const VehiclePropValue& value) { + constexpr bool updateStatus = true; LOG(DEBUG) << __func__ << ": " << toString(value); auto updatedPropValue = getValuePool()->obtain(value); if (updatedPropValue) { updatedPropValue->timestamp = value.timestamp; updatedPropValue->status = VehiclePropertyStatus::AVAILABLE; - onPropertyValueFromCar(*updatedPropValue); + onPropertyValueFromCar(*updatedPropValue, updateStatus); } } @@ -86,6 +87,8 @@ std::vector EmulatedVehicleServer::onGetAllPropertyConfig() c } StatusCode EmulatedVehicleServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) { + constexpr bool updateStatus = true; + LOG(INFO) << __func__; const auto& v = request.value; if (!v.int32Values.size()) { @@ -153,9 +156,11 @@ StatusCode EmulatedVehicleServer::handleGenerateFakeDataRequest(const VehiclePro int32_t display = request.value.int32Values[3]; // Send back to HAL onPropertyValueFromCar( - *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display)); + *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display), + updateStatus); onPropertyValueFromCar( - *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display)); + *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display), + updateStatus); break; } default: { @@ -191,9 +196,11 @@ VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createHwInputKeyProp( return keyEvent; } -StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value) { +StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, bool updateStatus) { // Some properties need to be treated non-trivially switch (value.prop) { + case kGenerateFakeDataControllingProperty: + return handleGenerateFakeDataRequest(value); case AP_POWER_STATE_REPORT: switch (value.value.int32Values[0]) { case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT): @@ -201,15 +208,18 @@ StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value) { case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL): // CPMS is in WAIT_FOR_VHAL state, simply move to ON // Send back to HAL - onPropertyValueFromCar( - *createApPowerStateReq(VehicleApPowerStateReq::ON, 0)); + // ALWAYS update status for generated property value + onPropertyValueFromCar(*createApPowerStateReq(VehicleApPowerStateReq::ON, 0), + true /* updateStatus */); break; case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY): case toInt(VehicleApPowerStateReport::SHUTDOWN_START): // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command // Send back to HAL + // ALWAYS update status for generated property value onPropertyValueFromCar( - *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0)); + *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0), + true /* updateStatus */); break; case toInt(VehicleApPowerStateReport::ON): case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE): @@ -226,21 +236,11 @@ StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value) { } // In the real vhal, the value will be sent to Car ECU. - // We just pretend it is done here. + // We just pretend it is done here and send back to HAL + onPropertyValueFromCar(value, updateStatus); return StatusCode::OK; } -StatusCode EmulatedVehicleServer::onSetPropertyFromVehicle(const VehiclePropValue& value) { - if (value.prop == kGenerateFakeDataControllingProperty) { - auto status = handleGenerateFakeDataRequest(value); - return status; - } else { - // Send back to HAL - onPropertyValueFromCar(value); - return StatusCode::OK; - } -} - EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() { return std::make_unique(); } diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h index d424cd83e7..5fc6493ba5 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h @@ -35,13 +35,10 @@ namespace impl { class EmulatedVehicleClient : public IVehicleClient { public: // Type of callback function for handling the new property values - using PropertyCallBackType = std::function; + using PropertyCallBackType = std::function; // Method from IVehicleClient - void onPropertyValue(const VehiclePropValue& value) override; - - // Request to change the value on the VEHICLE side (for testing) - virtual StatusCode setPropertyFromVehicle(const VehiclePropValue& value) = 0; + void onPropertyValue(const VehiclePropValue& value, bool updateStatus) override; void registerPropertyValueCallback(PropertyCallBackType&& callback); @@ -55,10 +52,7 @@ class EmulatedVehicleServer : public IVehicleServer { std::vector onGetAllPropertyConfig() const override; - StatusCode onSetProperty(const VehiclePropValue& value) override; - - // Process the request to change the value on the VEHICLE side (for testing) - StatusCode onSetPropertyFromVehicle(const VehiclePropValue& value); + StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override; // Set the Property Value Pool used in this server void setValuePool(VehiclePropValuePool* valuePool); @@ -85,16 +79,10 @@ class EmulatedVehicleServer : public IVehicleServer { VehiclePropValuePool* mValuePool{nullptr}; }; -class EmulatedPassthroughConnector - : public IPassThroughConnector { - public: - StatusCode setPropertyFromVehicle(const VehiclePropValue& value) override { - return this->onSetPropertyFromVehicle(value); - } -}; - // Helper functions +using EmulatedPassthroughConnector = + IPassThroughConnector; using EmulatedPassthroughConnectorPtr = std::unique_ptr; EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector(); 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 6508efea2b..2f5287378c 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 @@ -98,8 +98,9 @@ EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, for (size_t i = 0; i < arraysize(kVehicleProperties); i++) { mPropStore->registerProperty(kVehicleProperties[i].config); } - mVehicleClient->registerPropertyValueCallback( - std::bind(&EmulatedVehicleHal::onPropertyValue, this, std::placeholders::_1)); + mVehicleClient->registerPropertyValueCallback(std::bind(&EmulatedVehicleHal::onPropertyValue, + this, std::placeholders::_1, + std::placeholders::_2)); } VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get( @@ -131,7 +132,7 @@ VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get( } StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { - static constexpr bool shouldUpdateStatus = false; + constexpr bool updateStatus = false; // set the value from vehcile side, used in end to end test. if (propValue.prop == kSetIntPropertyFromVehcileForTest) { @@ -164,8 +165,12 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { } if (propValue.prop == kGenerateFakeDataControllingProperty) { - // send the generator controlling request to the server - auto status = mVehicleClient->setPropertyFromVehicle(propValue); + // Send the generator controlling request to the server. + // 'updateStatus' flag is only for the value sent by setProperty (propValue in this case) + // instead of the generated values triggered by it. 'propValue' works as a control signal + // here, since we never send the control signal back, the value of 'updateStatus' flag + // does not matter here. + auto status = mVehicleClient->setProperty(propValue, updateStatus); if (status != StatusCode::OK) { return status; } @@ -216,18 +221,11 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { updatedPropValue->timestamp = elapsedRealtimeNano(); // Send the value to the vehicle server, the server will talk to the (real or emulated) car - auto setValueStatus = mVehicleClient->setProperty(*updatedPropValue); + auto setValueStatus = mVehicleClient->setProperty(*updatedPropValue, updateStatus); if (setValueStatus != StatusCode::OK) { return setValueStatus; } - if (!mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus)) { - return StatusCode::INTERNAL_ERROR; - } - - getEmulatorOrDie()->doSetValueFromClient(*updatedPropValue); - doHalEvent(std::move(updatedPropValue)); - return StatusCode::OK; } @@ -347,18 +345,19 @@ bool EmulatedVehicleHal::isContinuousProperty(int32_t propId) const { } bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) { - return mVehicleClient->setPropertyFromVehicle(propValue) == StatusCode::OK; + constexpr bool updateStatus = true; + return mVehicleClient->setProperty(propValue, updateStatus) == StatusCode::OK; } std::vector EmulatedVehicleHal::getAllProperties() const { return mPropStore->readAllValues(); } -void EmulatedVehicleHal::onPropertyValue(const VehiclePropValue& value) { - static constexpr bool shouldUpdateStatus = true; +void EmulatedVehicleHal::onPropertyValue(const VehiclePropValue& value, bool updateStatus) { VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value); - if (mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus)) { + if (mPropStore->writeValue(*updatedPropValue, updateStatus)) { + getEmulatorOrDie()->doSetValueFromClient(*updatedPropValue); doHalEvent(std::move(updatedPropValue)); } } diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h index 98315ec32e..a8378da623 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h @@ -68,7 +68,7 @@ private: } StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request); - void onPropertyValue(const VehiclePropValue& value); + void onPropertyValue(const VehiclePropValue& value, bool updateStatus); void onContinuousPropertyTimer(const std::vector& properties); bool isContinuousProperty(int32_t propId) const; From 0885f9b10a3eda6baca60a4e0f4bfa89aac75ba1 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Thu, 5 Dec 2019 16:53:27 -0800 Subject: [PATCH 0370/1022] Set Timestamp By the Server when the client called 'set' Test: Build; unit tests `atest packages/services/Car/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarPropertyTest.java` Bug: b/141493212 Change-Id: I6686a15d6e9fa483d9b361acfe88001b7497b937 --- .../vhal_v2_0/EmulatedVehicleConnector.cpp | 35 ++++++++++++++++++- .../impl/vhal_v2_0/EmulatedVehicleHal.cpp | 35 +------------------ 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp index 89c5a4b65c..222fe5e21f 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp @@ -201,6 +201,36 @@ StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, b switch (value.prop) { case kGenerateFakeDataControllingProperty: return handleGenerateFakeDataRequest(value); + + // set the value from vehcile side, used in end to end test. + case kSetIntPropertyFromVehcileForTest: { + auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1); + updatedPropValue->prop = value.value.int32Values[0]; + updatedPropValue->value.int32Values[0] = value.value.int32Values[1]; + updatedPropValue->timestamp = value.value.int64Values[0]; + updatedPropValue->areaId = value.areaId; + onPropertyValueFromCar(*updatedPropValue, updateStatus); + return StatusCode::OK; + } + case kSetFloatPropertyFromVehcileForTest: { + auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1); + updatedPropValue->prop = value.value.int32Values[0]; + updatedPropValue->value.floatValues[0] = value.value.floatValues[0]; + updatedPropValue->timestamp = value.value.int64Values[0]; + updatedPropValue->areaId = value.areaId; + onPropertyValueFromCar(*updatedPropValue, updateStatus); + return StatusCode::OK; + } + case kSetBooleanPropertyFromVehcileForTest: { + auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1); + updatedPropValue->prop = value.value.int32Values[1]; + updatedPropValue->value.int32Values[0] = value.value.int32Values[0]; + updatedPropValue->timestamp = value.value.int64Values[0]; + updatedPropValue->areaId = value.areaId; + onPropertyValueFromCar(*updatedPropValue, updateStatus); + return StatusCode::OK; + } + case AP_POWER_STATE_REPORT: switch (value.value.int32Values[0]) { case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT): @@ -237,7 +267,10 @@ StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, b // In the real vhal, the value will be sent to Car ECU. // We just pretend it is done here and send back to HAL - onPropertyValueFromCar(value, updateStatus); + auto updatedPropValue = getValuePool()->obtain(value); + updatedPropValue->timestamp = elapsedRealtimeNano(); + + onPropertyValueFromCar(*updatedPropValue, updateStatus); return StatusCode::OK; } 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 2f5287378c..5c16bf75c1 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 @@ -134,36 +134,6 @@ VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get( StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { constexpr bool updateStatus = false; - // set the value from vehcile side, used in end to end test. - if (propValue.prop == kSetIntPropertyFromVehcileForTest) { - auto mockValue = createVehiclePropValue(VehiclePropertyType::INT32, 1); - mockValue->prop = propValue.value.int32Values[0]; - mockValue->value.int32Values[0] = propValue.value.int32Values[1]; - mockValue->timestamp = propValue.value.int64Values[0]; - mockValue->areaId = propValue.areaId; - setPropertyFromVehicle(*mockValue); - return StatusCode::OK; - } - - if (propValue.prop == kSetFloatPropertyFromVehcileForTest) { - auto mockValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1); - mockValue->prop = propValue.value.int32Values[0]; - mockValue->value.floatValues[0] = propValue.value.floatValues[0]; - mockValue->timestamp = propValue.value.int64Values[0]; - mockValue->areaId = propValue.areaId; - setPropertyFromVehicle(*mockValue); - return StatusCode::OK; - } - if (propValue.prop == kSetBooleanPropertyFromVehcileForTest) { - auto mockValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1); - mockValue->prop = propValue.value.int32Values[1]; - mockValue->value.int32Values[0] = propValue.value.int32Values[0]; - mockValue->timestamp = propValue.value.int64Values[0]; - mockValue->areaId = propValue.areaId; - setPropertyFromVehicle(*mockValue); - return StatusCode::OK; - } - if (propValue.prop == kGenerateFakeDataControllingProperty) { // Send the generator controlling request to the server. // 'updateStatus' flag is only for the value sent by setProperty (propValue in this case) @@ -217,11 +187,9 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { * After checking all conditions, such as the property is available, a real vhal will * sent the events to Car ECU to take actions. */ - VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(propValue); - updatedPropValue->timestamp = elapsedRealtimeNano(); // Send the value to the vehicle server, the server will talk to the (real or emulated) car - auto setValueStatus = mVehicleClient->setProperty(*updatedPropValue, updateStatus); + auto setValueStatus = mVehicleClient->setProperty(propValue, updateStatus); if (setValueStatus != StatusCode::OK) { return setValueStatus; } @@ -312,7 +280,6 @@ void EmulatedVehicleHal::onContinuousPropertyTimer(const std::vector& p } if (v.get()) { - v->timestamp = elapsedRealtimeNano(); doHalEvent(std::move(v)); } } From c675b182b3bf459637009ac82e0266959d8a8e90 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Wed, 18 Dec 2019 16:09:24 -0800 Subject: [PATCH 0371/1022] Transpose the encoding matrix Stripe together the encodings from each of the 16 codewords, so that if a 512-byte DRAM line is knocked out, it affects 256 bits from each codeword rather than 4096 bits from a single encoded codeword. Rather than using std::bitset, we directly set and read bits in the std::vector, because the striping means that copying it will now cost not4k in allocation but 64k. Decode directly to a word, without using list decoding. It seems we don't need list decoding for the error rates that matter here, and we never completed the implementation of it anyway. Declare and test only the full interface, now that it doesn't decompose quite so neatly. Bug: 63928581 Test: atest HadamardTest Change-Id: If022d3f4a8d6fccdf68119d4666f83ce5005bccb --- rebootescrow/aidl/default/HadamardUtils.cpp | 155 +++++++----------- rebootescrow/aidl/default/HadamardUtils.h | 27 +-- .../aidl/default/HadamardUtilsTest.cpp | 107 ++---------- 3 files changed, 84 insertions(+), 205 deletions(-) diff --git a/rebootescrow/aidl/default/HadamardUtils.cpp b/rebootescrow/aidl/default/HadamardUtils.cpp index 5853d2def5..8ee77e137c 100644 --- a/rebootescrow/aidl/default/HadamardUtils.cpp +++ b/rebootescrow/aidl/default/HadamardUtils.cpp @@ -16,6 +16,8 @@ #include +#include + #include namespace aidl { @@ -24,99 +26,52 @@ namespace hardware { namespace rebootescrow { namespace hadamard { -constexpr auto BYTE_LENGTH = 8u; +static inline void or_bit(std::vector* input, size_t bit, uint8_t val) { + (*input)[bit >> 3] |= (val & 1u) << (bit & 7); +} -std::vector BitsetToBytes(const std::bitset& encoded_bits) { - CHECK_EQ(0, (encoded_bits.size() % BYTE_LENGTH)); - std::vector result; - for (size_t i = 0; i < encoded_bits.size(); i += 8) { - uint8_t current = 0; - // Set each byte starting from the LSB. - for (size_t j = 0; j < BYTE_LENGTH; j++) { - CHECK_LE(i + j, encoded_bits.size()); - if (encoded_bits[i + j]) { - current |= (1u << j); - } +static inline uint8_t read_bit(const std::vector& input, size_t bit) { + return (input[bit >> 3] >> (bit & 7)) & 1u; +} + +// Apply an error correcting encoding. +// +// The error correcting code used is an augmented Hadamard code with +// k=15, so it takes a 16-bit input and produces a 2^15-bit output. +// We break the 32-byte key into 16 16-bit codewords and encode +// each codeword to a 2^15-bit output. +// +// To better defend against clustered errors, we stripe together the encoded +// codewords. Thus if a single 512-byte DRAM line is lost, instead of losing +// 2^11 bits from the encoding of a single code word, we lose 2^7 bits +// from the encoding of each of the 16 codewords. +std::vector EncodeKey(const std::vector& input) { + CHECK_EQ(input.size(), KEY_SIZE_IN_BYTES); + std::vector result(OUTPUT_SIZE_BYTES, 0); + static_assert(OUTPUT_SIZE_BYTES == 64 * 1024); + for (size_t i = 0; i < KEY_CODEWORDS; i++) { + uint16_t word = input[i * 2 + 1] << 8 | input[i * 2]; + for (size_t j = 0; j < ENCODE_LENGTH; j++) { + uint16_t wi = word & (j + ENCODE_LENGTH); + // Sum all the bits in the word and check its parity. + wi ^= wi >> 8u; + wi ^= wi >> 4u; + wi ^= wi >> 2u; + wi ^= wi >> 1u; + or_bit(&result, (j * KEY_CODEWORDS) + i, wi & 1); } - result.push_back(current); } return result; } -std::bitset BytesToBitset(const std::vector& encoded) { - CHECK_EQ(ENCODE_LENGTH, encoded.size() * BYTE_LENGTH); - - std::bitset result; - size_t offset = 0; - for (const auto& byte : encoded) { - // Set each byte starting from the LSB. - for (size_t j = 0; j < BYTE_LENGTH; j++) { - result[offset + j] = byte & (1u << j); - } - offset += BYTE_LENGTH; - } - return result; -} - -// The encoding is equivalent to multiply the word with the generator matrix (and take the module -// of 2). Here is an example of encoding a number with 3 bits. The encoded length is thus -// 2^(3-1) = 4 bits. -// |1 1 1 1| |0| -// |0 1 1| * |0 0 1 1| = |1| -// |0 1 0 1| |1| -// |0| -std::bitset EncodeWord(uint16_t word) { - std::bitset result; - for (uint64_t i = ENCODE_LENGTH; i < 2 * ENCODE_LENGTH; i++) { - uint32_t wi = word & i; - // Sum all the bits in the word and check its parity. - wi ^= wi >> 8u; - wi ^= wi >> 4u; - wi ^= wi >> 2u; - wi ^= wi >> 1u; - result[i - ENCODE_LENGTH] = wi & 1u; - } - return result; -} - -std::vector EncodeKey(const std::vector& key) { - CHECK_EQ(KEY_SIZE_IN_BYTES, key.size()); - - std::vector result; - for (size_t i = 0; i < key.size(); i += 2) { - uint16_t word = static_cast(key[i + 1]) << BYTE_LENGTH | key[i]; - auto encoded_bits = EncodeWord(word); - auto byte_array = BitsetToBytes(encoded_bits); - std::move(byte_array.begin(), byte_array.end(), std::back_inserter(result)); - } - return result; -} - -std::vector DecodeKey(const std::vector& encoded) { - CHECK_EQ(0, (encoded.size() * 8) % ENCODE_LENGTH); - std::vector result; - for (size_t i = 0; i < encoded.size(); i += ENCODE_LENGTH / 8) { - auto current = - std::vector{encoded.begin() + i, encoded.begin() + i + ENCODE_LENGTH / 8}; - auto bits = BytesToBitset(current); - auto candidates = DecodeWord(bits); - CHECK(!candidates.empty()); - // TODO(xunchang) Do we want to try other candidates? - uint16_t val = candidates.top().second; - result.push_back(val & 0xffu); - result.push_back(val >> BYTE_LENGTH); - } - - return result; -} - -std::priority_queue> DecodeWord( - const std::bitset& encoded) { +// Decode a single codeword. Because of the way codewords are striped together +// this takes the entire input, plus an offset telling it which word to decode. +static uint16_t DecodeWord(size_t word, const std::vector& encoded) { std::vector scores; scores.reserve(ENCODE_LENGTH); - // Convert 0 -> -1 in the encoded bits. e.g [0, 1, 1, 0] -> [-1, 1, 1, -1] + // Convert x -> -1^x in the encoded bits. e.g [1, 0, 0, 1] -> [-1, 1, 1, -1] for (uint32_t i = 0; i < ENCODE_LENGTH; i++) { - scores.push_back(2 * encoded[i] - 1); + scores.push_back(1 - 2 * read_bit(encoded, i * KEY_CODEWORDS + word)); } // Multiply the hadamard matrix by the transformed input. @@ -135,19 +90,31 @@ std::priority_queue> DecodeWord( } } } + auto hiscore = std::numeric_limits::min(); + uint16_t winner; + // TODO(b/146520538): this needs to be constant time + for (size_t i = 0; i < ENCODE_LENGTH; i++) { + if (scores[i] > hiscore) { + winner = i; + hiscore = scores[i]; - // Assign the corresponding score to each index; larger score indicates higher probability. e.g. - // value 3, encoding [0, 1, 1, 0] -> score: 4 - // value 7, encoding [1, 0, 0, 1] (3's complement) -> score: -4 - std::priority_queue> candidates; - // TODO(xunchang) limit the candidate size since we don't need all of them? - for (uint32_t i = 0; i < scores.size(); i++) { - candidates.emplace(-scores[i], i); - candidates.emplace(scores[i], (1u << CODE_K) | i); + } else if (-scores[i] > hiscore) { + winner = i | (1 << CODE_K); + hiscore = -scores[i]; + } } + return winner; +} - CHECK_EQ(2 * ENCODE_LENGTH, candidates.size()); - return candidates; +std::vector DecodeKey(const std::vector& encoded) { + CHECK_EQ(OUTPUT_SIZE_BYTES, encoded.size()); + std::vector result(KEY_SIZE_IN_BYTES, 0); + for (size_t i = 0; i < KEY_CODEWORDS; i++) { + uint16_t val = DecodeWord(i, encoded); + result[i * CODEWORD_BYTES] = val & 0xffu; + result[i * CODEWORD_BYTES + 1] = val >> 8u; + } + return result; } } // namespace hadamard diff --git a/rebootescrow/aidl/default/HadamardUtils.h b/rebootescrow/aidl/default/HadamardUtils.h index 21cfc787e3..85e635f2de 100644 --- a/rebootescrow/aidl/default/HadamardUtils.h +++ b/rebootescrow/aidl/default/HadamardUtils.h @@ -18,9 +18,6 @@ #include -#include -#include -#include #include namespace aidl { @@ -29,18 +26,14 @@ namespace hardware { namespace rebootescrow { namespace hadamard { -constexpr uint32_t CODE_K = 15; +constexpr auto BYTE_LENGTH = 8u; +constexpr auto CODEWORD_BYTES = 2u; // uint16_t +constexpr auto CODEWORD_BITS = CODEWORD_BYTES * BYTE_LENGTH; +constexpr uint32_t CODE_K = CODEWORD_BITS - 1; constexpr uint32_t ENCODE_LENGTH = 1u << CODE_K; -constexpr auto KEY_SIZE_IN_BYTES = 32u; - -// Encodes a 2 bytes word with hadamard code. The encoding expands a word of k+1 bits to a 2^k -// bitset. Returns the encoded bitset. -std::bitset EncodeWord(uint16_t word); - -// Decodes the input bitset, and returns a sorted list of pair with (score, value). The value with -// a higher score indicates a greater likehood. -std::priority_queue> DecodeWord( - const std::bitset& encoded); +constexpr auto KEY_CODEWORDS = 16u; +constexpr auto KEY_SIZE_IN_BYTES = KEY_CODEWORDS * CODEWORD_BYTES; +constexpr auto OUTPUT_SIZE_BYTES = KEY_CODEWORDS * ENCODE_LENGTH / BYTE_LENGTH; // Encodes a key that has a size of KEY_SIZE_IN_BYTES. Returns a byte array representation of the // encoded bitset. So a 32 bytes key will expand to 16*(2^15) bits = 64KiB. @@ -49,12 +42,6 @@ std::vector EncodeKey(const std::vector& input); // Given a byte array representation of the encoded keys, decodes it and return the result. std::vector DecodeKey(const std::vector& encoded); -// Converts a bitset of length |ENCODE_LENGTH| to a byte array. -std::vector BitsetToBytes(const std::bitset& encoded_bits); - -// Converts a byte array of encoded words back to the bitset. -std::bitset BytesToBitset(const std::vector& encoded); - } // namespace hadamard } // namespace rebootescrow } // namespace hardware diff --git a/rebootescrow/aidl/default/HadamardUtilsTest.cpp b/rebootescrow/aidl/default/HadamardUtilsTest.cpp index e397e7624e..1c9a2fb295 100644 --- a/rebootescrow/aidl/default/HadamardUtilsTest.cpp +++ b/rebootescrow/aidl/default/HadamardUtilsTest.cpp @@ -17,110 +17,35 @@ #include #include -#include -#include -#include - #include #include using namespace aidl::android::hardware::rebootescrow::hadamard; -class HadamardTest : public testing::Test { - protected: - void SetUp() override { - auto ones = std::bitset{}.set(); - // Expects 0x4000 to encode as top half as ones, and lower half as zeros. i.e. - // [1, 1 .. 1, 0, 0 .. 0] - expected_half_size_ = ones << half_size_; +class HadamardTest : public testing::Test {}; - // Expects 0x1 to encode as interleaved 1 and 0s i.e. [1, 0, 1, 0 ..] - expected_one_ = ones; - for (uint32_t i = ENCODE_LENGTH / 2; i >= 1; i /= 2) { - expected_one_ ^= (expected_one_ >> i); +static void AddError(std::vector* data) { + for (size_t i = 0; i < data->size(); i++) { + for (size_t j = 0; j < BYTE_LENGTH; j++) { + if (random() % 100 < 47) { + (*data)[i] ^= (1 << j); + } } } - - uint16_t half_size_ = ENCODE_LENGTH / 2; - std::bitset expected_one_; - std::bitset expected_half_size_; -}; - -static void AddError(std::bitset* corrupted_bits) { - // The hadamard code has a hamming distance of ENCODE_LENGTH/2. So we should always be able to - // correct the data if less than a quarter of the encoded bits are corrupted. - auto corrupted_max = 0.24f * corrupted_bits->size(); - auto corrupted_num = 0; - for (size_t i = 0; i < corrupted_bits->size() && corrupted_num < corrupted_max; i++) { - if (random() % 2 == 0) { - (*corrupted_bits)[i] = !(*corrupted_bits)[i]; - corrupted_num += 1; - } - } -} - -static void EncodeAndDecodeKeys(const std::vector& key) { - auto encoded = EncodeKey(key); - ASSERT_EQ(64 * 1024, encoded.size()); - auto decoded = DecodeKey(encoded); - ASSERT_EQ(key, std::vector(decoded.begin(), decoded.begin() + key.size())); -} - -TEST_F(HadamardTest, Encode_smoke) { - ASSERT_EQ(expected_half_size_, EncodeWord(half_size_)); - ASSERT_EQ(expected_one_, EncodeWord(1)); - // Check the complement of 1. - ASSERT_EQ(~expected_one_, EncodeWord(1u << CODE_K | 1u)); -} - -TEST_F(HadamardTest, Decode_smoke) { - auto candidate = DecodeWord(expected_half_size_); - auto expected = std::pair{ENCODE_LENGTH, half_size_}; - ASSERT_EQ(expected, candidate.top()); - - candidate = DecodeWord(expected_one_); - expected = std::pair{ENCODE_LENGTH, 1}; - ASSERT_EQ(expected, candidate.top()); } TEST_F(HadamardTest, Decode_error_correction) { constexpr auto iteration = 10; for (int i = 0; i < iteration; i++) { - uint16_t word = random() % (ENCODE_LENGTH * 2); - auto corrupted_bits = EncodeWord(word); - AddError(&corrupted_bits); - - auto candidate = DecodeWord(corrupted_bits); - ASSERT_EQ(word, candidate.top().second); + std::vector key; + for (int j = 0; j < KEY_SIZE_IN_BYTES; j++) { + key.emplace_back(random() & 0xff); + } + auto encoded = EncodeKey(key); + ASSERT_EQ(64 * 1024, encoded.size()); + AddError(&encoded); + auto decoded = DecodeKey(encoded); + ASSERT_EQ(key, std::vector(decoded.begin(), decoded.begin() + key.size())); } } - -TEST_F(HadamardTest, BytesToBitset_smoke) { - auto bytes = BitsetToBytes(expected_one_); - - auto read_back = BytesToBitset(bytes); - ASSERT_EQ(expected_one_, read_back); -} - -TEST_F(HadamardTest, EncodeAndDecodeKey) { - std::vector KEY_1{ - 0xA5, 0x00, 0xFF, 0x01, 0xA5, 0x5a, 0xAA, 0x55, 0x00, 0xD3, 0x2A, - 0x8C, 0x2E, 0x83, 0x0E, 0x65, 0x9E, 0x8D, 0xC6, 0xAC, 0x1E, 0x83, - 0x21, 0xB3, 0x95, 0x02, 0x89, 0x64, 0x64, 0x92, 0x12, 0x1F, - }; - std::vector KEY_2{ - 0xFF, 0x00, 0x00, 0xAA, 0x5A, 0x19, 0x20, 0x71, 0x9F, 0xFB, 0xDA, - 0xB6, 0x2D, 0x06, 0xD5, 0x49, 0x7E, 0xEF, 0x63, 0xAC, 0x18, 0xFF, - 0x5A, 0xA3, 0x40, 0xBB, 0x64, 0xFA, 0x67, 0xC1, 0x10, 0x18, - }; - - EncodeAndDecodeKeys(KEY_1); - EncodeAndDecodeKeys(KEY_2); - - std::vector key; - for (uint8_t i = 0; i < KEY_SIZE_IN_BYTES; i++) { - key.push_back(i); - }; - EncodeAndDecodeKeys(key); -} From a94e59a387d205b929a80529aa119f11bc498170 Mon Sep 17 00:00:00 2001 From: Hai Shalom Date: Fri, 20 Dec 2019 14:29:47 -0800 Subject: [PATCH 0372/1022] [DPP R2] Update VTS test for supplicant 1.2 Update VTS test for supplicant 1.2 to skip the DPP tests if the underyling HAL is 1.3. The reason is because 1.3 HAL uses different callbacks. Bug: 139381558 Test: atest VtsHalWifiSupplicantV1_2Host Change-Id: Ie9cd93e33bda3ca22ee2b5593d185f1918be847e --- wifi/supplicant/1.2/vts/functional/Android.bp | 1 + .../supplicant_sta_iface_hidl_test.cpp | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/wifi/supplicant/1.2/vts/functional/Android.bp b/wifi/supplicant/1.2/vts/functional/Android.bp index b7949d103d..7e9d4f6a47 100644 --- a/wifi/supplicant/1.2/vts/functional/Android.bp +++ b/wifi/supplicant/1.2/vts/functional/Android.bp @@ -51,6 +51,7 @@ cc_test { "android.hardware.wifi.supplicant@1.0", "android.hardware.wifi.supplicant@1.1", "android.hardware.wifi.supplicant@1.2", + "android.hardware.wifi.supplicant@1.3", "android.hardware.wifi@1.0", "android.hardware.wifi@1.1", "libgmock", diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp index 2ff7751fa8..6272d30a1c 100644 --- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp +++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -318,6 +320,19 @@ TEST_F(SupplicantStaIfaceHidlTest, StartDppEnrolleeInitiator) { return; } + /* Check if the underlying HAL version is 1.3 or higher and skip the test + * in this case. The 1.3 HAL uses different callbacks which are not + * supported by 1.2. This will cause this test to fail because the callbacks + * it is waiting for will never be called. Note that this test is also + * implemented in the 1.3 VTS test. + */ + sp<::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface> v1_3 = + ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface:: + castFrom(sta_iface_); + if (v1_3 != nullptr) { + GTEST_SKIP() << "Test not supported with this HAL version"; + } + hidl_string uri = "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj" "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;"; @@ -369,6 +384,21 @@ TEST_F(SupplicantStaIfaceHidlTest, StartDppConfiguratorInitiator) { return; } + /* Check if the underlying HAL version is 1.3 or higher and skip the test + * in this case. The 1.3 HAL uses different callbacks which are not + * supported by 1.2. This will cause this test to fail because the callbacks + * it is waiting for will never be called. Note that this test is also + * implemented in the 1.3 VTS test. + */ + sp<::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface> v1_3 = + ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface:: + castFrom(sta_iface_); + + if (v1_3 != nullptr) { + GTEST_SKIP() << "Test not supported with this HAL version"; + return; + } + hidl_string uri = "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj" "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;"; From 913d5604eeae25e049303fdee29cccb113282f60 Mon Sep 17 00:00:00 2001 From: Kumar Anand Date: Wed, 18 Dec 2019 16:02:37 -0800 Subject: [PATCH 0373/1022] wifi: Legacy HAL Thermal API stub Add the stub implementation for Wifi thermal API Bug: 140311866 Test: Manual, on device Change-Id: I401bf7a38fa52d160ae45cd519a225c07360cd3c --- wifi/1.4/default/wifi_legacy_hal.cpp | 7 +++++++ wifi/1.4/default/wifi_legacy_hal.h | 3 +++ wifi/1.4/default/wifi_legacy_hal_stubs.cpp | 1 + 3 files changed, 11 insertions(+) diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp index ae3c447a01..6f088d73e3 100644 --- a/wifi/1.4/default/wifi_legacy_hal.cpp +++ b/wifi/1.4/default/wifi_legacy_hal.cpp @@ -824,6 +824,13 @@ wifi_error WifiLegacyHal::setLatencyMode(const std::string& iface_name, mode); } +wifi_error WifiLegacyHal::setThermalMitigationMode( + const std::string& iface_name, wifi_thermal_mode mode, + uint32_t completion_window) { + return global_func_table_.wifi_set_thermal_mitigation_mode( + getIfaceHandle(iface_name), mode, completion_window); +} + std::pair WifiLegacyHal::getLoggerSupportedFeatureSet( const std::string& iface_name) { uint32_t supported_feature_flags; diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h index 7f16c30628..74cc84be30 100644 --- a/wifi/1.4/default/wifi_legacy_hal.h +++ b/wifi/1.4/default/wifi_legacy_hal.h @@ -259,6 +259,9 @@ class WifiLegacyHal { virtual wifi_error resetTxPowerScenario(const std::string& iface_name); wifi_error setLatencyMode(const std::string& iface_name, wifi_latency_mode mode); + wifi_error setThermalMitigationMode(const std::string& iface_name, + wifi_thermal_mode mode, + uint32_t completion_window); // Logger/debug functions. std::pair getLoggerSupportedFeatureSet( const std::string& iface_name); diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp index 27afa1ff06..bbe470e580 100644 --- a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp +++ b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp @@ -138,6 +138,7 @@ bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) { populateStubFor(&hal_fn->wifi_reset_tx_power_scenario); populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler); populateStubFor(&hal_fn->wifi_set_latency_mode); + populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode); return true; } } // namespace legacy_hal From c6489a5641abcb04c7ca10640825bcd676f326e2 Mon Sep 17 00:00:00 2001 From: Sunil Ravi Date: Fri, 6 Dec 2019 18:03:24 -0800 Subject: [PATCH 0374/1022] Wifi: MBO-OCE feature support (phase 3) Added hidl call back function to notify framework about bss transition request frame handling status. Also fixed few code style issues by running hidl-gen -Lformat. Bug: 139474288 Test: Manual Test: VTS test Change-Id: I00760f14d81a59e63042b1a5be9f9e3f74ff3a83 --- current.txt | 8 +- wifi/supplicant/1.3/ISupplicantStaIface.hal | 2 +- .../1.3/ISupplicantStaIfaceCallback.hal | 125 +++++++++++++++++- wifi/supplicant/1.3/ISupplicantStaNetwork.hal | 42 +++--- wifi/supplicant/1.3/types.hal | 6 +- .../supplicant_sta_iface_hidl_test.cpp | 21 +++ 6 files changed, 182 insertions(+), 22 deletions(-) diff --git a/current.txt b/current.txt index ecfe7bd67c..f026d7d47a 100644 --- a/current.txt +++ b/current.txt @@ -653,10 +653,10 @@ cf1d55e8c68300090747ab90b94c22e4c859b29c84ced68a317c595bb115eab2 android.hardwar 36b3acf78ac4ecf8156be8741c1d8332cdce7a1ebf4dfa1562952f14a94e6c87 android.hardware.wifi.hostapd@1.2::IHostapd 2defa258951e25a132aaeb36e3febe6f41bf9c6dbb1b1ebdf0b41708ab4e107e android.hardware.wifi.hostapd@1.2::types a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant -213457930af81ff3ea344fbc9d4a0d0a2bb70527f96b7b6a32ee3b5e4c17057e android.hardware.wifi.supplicant@1.3::ISupplicantStaIface -c1b8cfff5a86a7edef800a65b7c8fa025f4546cb95710d48e27bac50a8d16619 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback -a6163000e2804472924733bcf8b4269db776460cc4df64f9c4dc8350d7aeafc5 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork -16e3e23eea763fbff39230ef069823643c5760b738b3661dbbdaf460c5b9ba13 android.hardware.wifi.supplicant@1.3::types +c72cb37b3f66ef65aeb5c6438a3fbe17bbe847fdf62d1a76eafd7f3a8a526105 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface +342a8e12db4dca643f2755eb4167e8f103d96502053a25a1f51f42107a4530f1 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback +5477f8bafb29548875622fa83f1c0a29cee641acee613315eb747731001f4aff android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork +91015479f5a0fba9872e98d3cca4680995de64f42ae71461b4b7e5acc5a196ab android.hardware.wifi.supplicant@1.3::types 7a4ba60b5ddedf497e5d2bdff7d72b7d4a811969000e28677dd9e2389e683b34 android.hardware.radio@1.5::types afa2d6cf4c0ba4b8482d5bcc097594ad5bc49be0bf3003034f75955cdaf66045 android.hardware.radio@1.5::IRadio 3afac66f21a33bc9c4b80481c7d5540038348651d9a7d8af64ea13610af138da android.hardware.radio@1.5::IRadioIndication diff --git a/wifi/supplicant/1.3/ISupplicantStaIface.hal b/wifi/supplicant/1.3/ISupplicantStaIface.hal index fa88b91c6c..58ef165360 100644 --- a/wifi/supplicant/1.3/ISupplicantStaIface.hal +++ b/wifi/supplicant/1.3/ISupplicantStaIface.hal @@ -18,7 +18,7 @@ package android.hardware.wifi.supplicant@1.3; import @1.0::SupplicantStatus; import @1.2::ISupplicantStaIface; -import @1.3::ISupplicantStaNetwork; +import ISupplicantStaNetwork; import ISupplicantStaIfaceCallback; /** diff --git a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal index ae7f7970c3..72ba160ec9 100644 --- a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal +++ b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal @@ -27,6 +27,121 @@ import @1.2::ISupplicantStaIfaceCallback; * corresponding |ISupplicantStaIface.registerCallback_1_3| method. */ interface ISupplicantStaIfaceCallback extends @1.2::ISupplicantStaIfaceCallback { + /** + * IEEE Std 802.11-2016 - Table 9-357. + * BTM status code filled in BSS transition management response frame. + */ + enum BssTmStatusCode : uint8_t { + ACCEPT = 0, + REJECT_UNSPECIFIED = 1, + REJECT_INSUFFICIENT_BEACON = 2, + REJECT_INSUFFICIENT_CAPABITY = 3, + REJECT_BSS_TERMINATION_UNDESIRED = 4, + REJECT_BSS_TERMINATION_DELAY_REQUEST = 5, + REJECT_STA_CANDIDATE_LIST_PROVIDED = 6, + REJECT_NO_SUITABLE_CANDIDATES = 7, + REJECT_LEAVING_ESS = 8, + }; + + /** + * Bitmask of various information retrieved from BSS transition management request frame. + */ + enum BssTmDataFlagsMask : uint32_t { + /** + * Preferred candidate list included. + */ + WNM_MODE_PREFERRED_CANDIDATE_LIST_INCLUDED = 1 << 0, + /** + * Abridged. + */ + WNM_MODE_ABRIDGED = 1 << 1, + /** + * Disassociation Imminent. + */ + WNM_MODE_DISASSOCIATION_IMMINENT = 1 << 2, + /** + * BSS termination included. + */ + WNM_MODE_BSS_TERMINATION_INCLUDED = 1 << 3, + /** + * ESS Disassociation Imminent. + */ + WNM_MODE_ESS_DISASSOCIATION_IMMINENT = 1 << 4, + /** + * MBO transition reason code included. + */ + MBO_TRANSITION_REASON_CODE_INCLUDED = 1 << 5, + /** + * MBO retry delay time included. + */ + MBO_ASSOC_RETRY_DELAY_INCLUDED = 1 << 6, + /** + * MBO cellular data connection preference value included. + */ + MBO_CELLULAR_DATA_CONNECTION_PREFERENCE_INCLUDED = 1 << 7, + }; + + /** + * MBO spec v1.2, 4.2.6 Table 18: MBO transition reason code attribute + * values. + */ + enum MboTransitionReasonCode : uint8_t { + UNSPECIFIED = 0, + EXCESSIVE_FRAME_LOSS = 1, + EXCESSIVE_TRAFFIC_DELAY = 2, + INSUFFICIENT_BANDWIDTH = 3, + LOAD_BALANCING = 4, + LOW_RSSI = 5, + RX_EXCESSIVE_RETRIES = 6, + HIGH_INTERFERENCE = 7, + GRAY_ZONE = 8, + TRANSITION_TO_PREMIUM_AP = 9, + }; + + /** + * MBO spec v1.2, 4.2.5 Table 16: MBO Cellular Data connection preference + * attribute values. AP use this to indicate STA, its preference for the + * STA to move from BSS to cellular network. + */ + enum MboCellularDataConnectionPrefValue : uint8_t { + EXCLUDED = 0, + NOT_PREFERRED = 1, + /* + * 2-254 Reserved. + */ + PREFERRED = 255, + }; + + /** + * Data retrieved from received BSS transition management request frame. + */ + struct BssTmData { + /* + * Status code filled in BSS transition management response frame + */ + BssTmStatusCode status; + + /* + * Bitmask of BssTmDataFlagsMask + */ + bitfield flags; + + /* + * Duration for which STA shouldn't try to re-associate. + */ + uint32_t assocRetryDelayMs; + + /* + * Reason for BSS transition request. + */ + MboTransitionReasonCode mboTransitionReason; + + /* + * Cellular Data Connection preference value. + */ + MboCellularDataConnectionPrefValue mboCellPreference; + }; + /** * Indicates PMK cache added event. * @@ -61,5 +176,13 @@ interface ISupplicantStaIfaceCallback extends @1.2::ISupplicantStaIfaceCallback * Operating Class. */ oneway onDppFailure_1_3(DppFailureCode code, string ssid, string channelList, - vecbandList); + vec bandList); + + /** + * Indicates BTM request frame handling status. + * + * @param BssTmData Data retrieved from received BSS transition management + * request frame. + */ + oneway onBssTmHandlingDone(BssTmData tmData); }; diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal index 1bcf7bcde2..c18bffc93f 100644 --- a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal +++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal @@ -25,29 +25,44 @@ import @1.2::ISupplicantStaNetwork; * configuration it controls. */ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { - /** Possble mask of values for Proto param. */ + /** + * Possble mask of values for Proto param. + */ enum ProtoMask : @1.0::ISupplicantStaNetwork.ProtoMask { WAPI = 1 << 2, }; - /** Possble mask of values for KeyMgmt param. */ + /** + * Possble mask of values for KeyMgmt param. + */ enum KeyMgmtMask : @1.2::ISupplicantStaNetwork.KeyMgmtMask { - /* WAPI Psk */ + /* + * WAPI Psk + */ WAPI_PSK = 1 << 12, - - /** WAPI Cert */ + /** + * WAPI Cert + */ WAPI_CERT = 1 << 13, }; - /** Possble mask of values for PairwiseCipher param. */ + /** + * Possble mask of values for PairwiseCipher param. + */ enum PairwiseCipherMask : @1.2::ISupplicantStaNetwork.PairwiseCipherMask { - /** SMS4 Pairwise Cipher */ + /** + * SMS4 Pairwise Cipher + */ SMS4 = 1 << 7, }; - /** Possble mask of values for GroupCipher param. */ + /** + * Possble mask of values for GroupCipher param. + */ enum GroupCipherMask : @1.2::ISupplicantStaNetwork.GroupCipherMask { - /** SMS4 Group Cipher */ + /** + * SMS4 Group Cipher + */ SMS4 = 1 << 7, }; @@ -99,8 +114,7 @@ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { * |SupplicantStatusCode.FAILURE_UNKNOWN| * @return keyMgmtMask Combination of |KeyMgmtMask| values. */ - getKeyMgmt_1_3() - generates (SupplicantStatus status, bitfield keyMgmtMask); + getKeyMgmt_1_3() generates (SupplicantStatus status, bitfield keyMgmtMask); /** * Set proto mask for the network. @@ -154,8 +168,7 @@ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { * @return pairwiseCipherMask Combination of |PairwiseCipherMask| values. */ getPairwiseCipher_1_3() - generates (SupplicantStatus status, - bitfield pairwiseCipherMask); + generates (SupplicantStatus status, bitfield pairwiseCipherMask); /** * Set pairwise cipher mask for the network. @@ -183,8 +196,7 @@ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { * @return groupCipherMask Combination of |GroupCipherMask| values. */ getGroupCipher_1_3() - generates (SupplicantStatus status, - bitfield groupCipherMask); + generates (SupplicantStatus status, bitfield groupCipherMask); /** * Set WAPI certificate suite for this network. diff --git a/wifi/supplicant/1.3/types.hal b/wifi/supplicant/1.3/types.hal index 2e5027954f..05f4760126 100644 --- a/wifi/supplicant/1.3/types.hal +++ b/wifi/supplicant/1.3/types.hal @@ -15,6 +15,7 @@ */ package android.hardware.wifi.supplicant@1.3; + import @1.2::DppProgressCode; import @1.2::DppFailureCode; @@ -87,7 +88,10 @@ enum DppProgressCode : @1.2::DppProgressCode { * DppSuccessCode: Success codes for DPP (Easy Connect) Configurator */ enum DppSuccessCode : uint32_t { - CONFIGURATION_SENT, /* Replaces @1.2::onDppSuccessConfigSent() */ + /* + * Replaces @1.2::onDppSuccessConfigSent() + */ + CONFIGURATION_SENT, CONFIGURATION_APPLIED, }; diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp index 2b08e48fd6..8c9f9cd1e2 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp @@ -62,6 +62,9 @@ class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { int64_t pmkCacheExpirationTimeInSec; std::vector serializedPmkCacheEntry; + // Data retrieved from BSS transition management frame. + ISupplicantStaIfaceCallback::BssTmData tmData; + enum DppCallbackType { ANY_CALLBACK = -2, INVALID = -1, @@ -229,6 +232,10 @@ class IfaceCallback : public ISupplicantStaIfaceCallback { const hidl_vec& /* serializedEntry */) override { return Void(); } + Return onBssTmHandlingDone( + const ISupplicantStaIfaceCallback::BssTmData& /* data */) override { + return Void(); + } }; class IfacePmkCacheCallback : public IfaceCallback { @@ -279,6 +286,20 @@ class IfaceDppCallback : public IfaceCallback { public: IfaceDppCallback(SupplicantStaIfaceHidlTest& parent) : parent_(parent){}; }; + +class IfaceBssTmHandlingDoneCallback : public IfaceCallback { + SupplicantStaIfaceHidlTest& parent_; + Return onBssTmHandlingDone( + const ISupplicantStaIfaceCallback::BssTmData& data) override { + parent_.tmData = data; + return Void(); + } + + public: + IfaceBssTmHandlingDoneCallback(SupplicantStaIfaceHidlTest& parent) + : parent_(parent) {} +}; + /* * RegisterCallback_1_3 */ From 53c005ff34922adf38463201a1c41f876445aabf Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Mon, 23 Dec 2019 11:35:39 -0800 Subject: [PATCH 0375/1022] Shuffle the encoding to prevent systematic errors Bug: 63928581 Test: atest HadamardTest Change-Id: Ide8ead4bf5efa629c631df52249cbb322265cc8c --- rebootescrow/aidl/default/HadamardUtils.cpp | 36 +++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/rebootescrow/aidl/default/HadamardUtils.cpp b/rebootescrow/aidl/default/HadamardUtils.cpp index 8ee77e137c..c578152ba1 100644 --- a/rebootescrow/aidl/default/HadamardUtils.cpp +++ b/rebootescrow/aidl/default/HadamardUtils.cpp @@ -34,6 +34,14 @@ static inline uint8_t read_bit(const std::vector& input, size_t bit) { return (input[bit >> 3] >> (bit & 7)) & 1u; } +// Use a simple LCG which is easy to run in reverse. +// https://www.johndcook.com/blog/2017/07/05/simple-random-number-generator/ +constexpr uint64_t RNG_MODULUS = 0x7fffffff; +constexpr uint64_t RNG_MUL = 742938285; +constexpr uint64_t RNG_SEED = 20170705; +constexpr uint64_t RNG_INV_MUL = 1413043504; // (mul * inv_mul) % modulus == 1 +constexpr uint64_t RNG_INV_SEED = 1173538311; // (seed * mul**65534) % modulus + // Apply an error correcting encoding. // // The error correcting code used is an augmented Hadamard code with @@ -45,6 +53,9 @@ static inline uint8_t read_bit(const std::vector& input, size_t bit) { // codewords. Thus if a single 512-byte DRAM line is lost, instead of losing // 2^11 bits from the encoding of a single code word, we lose 2^7 bits // from the encoding of each of the 16 codewords. +// In addition we apply a Fisher-Yates shuffle to the bytes of the encoding; +// Hadamard encoding recovers much better from random errors than systematic +// ones, and this ensures that errors will be random. std::vector EncodeKey(const std::vector& input) { CHECK_EQ(input.size(), KEY_SIZE_IN_BYTES); std::vector result(OUTPUT_SIZE_BYTES, 0); @@ -61,6 +72,16 @@ std::vector EncodeKey(const std::vector& input) { or_bit(&result, (j * KEY_CODEWORDS) + i, wi & 1); } } + // Apply the inverse shuffle here; we apply the forward shuffle in decoding. + uint64_t rng_state = RNG_INV_SEED; + for (size_t i = OUTPUT_SIZE_BYTES - 1; i > 0; i--) { + auto j = rng_state % (i + 1); + auto t = result[i]; + result[i] = result[j]; + result[j] = t; + rng_state *= RNG_INV_MUL; + rng_state %= RNG_MODULUS; + } return result; } @@ -106,8 +127,19 @@ static uint16_t DecodeWord(size_t word, const std::vector& encoded) { return winner; } -std::vector DecodeKey(const std::vector& encoded) { - CHECK_EQ(OUTPUT_SIZE_BYTES, encoded.size()); +std::vector DecodeKey(const std::vector& shuffled) { + CHECK_EQ(OUTPUT_SIZE_BYTES, shuffled.size()); + // Apply the forward Fisher-Yates shuffle. + std::vector encoded(OUTPUT_SIZE_BYTES, 0); + encoded[0] = shuffled[0]; + uint64_t rng_state = RNG_SEED; + for (size_t i = 1; i < OUTPUT_SIZE_BYTES; i++) { + auto j = rng_state % (i + 1); + encoded[i] = encoded[j]; + encoded[j] = shuffled[i]; + rng_state *= RNG_MUL; + rng_state %= RNG_MODULUS; + } std::vector result(KEY_SIZE_IN_BYTES, 0); for (size_t i = 0; i < KEY_CODEWORDS; i++) { uint16_t val = DecodeWord(i, encoded); From a01974f56f38841f3bbb4d9b099cf7361f5864f0 Mon Sep 17 00:00:00 2001 From: Shuo Qian Date: Mon, 23 Dec 2019 13:34:36 -0800 Subject: [PATCH 0376/1022] Update documentation for RSRQ of SignalMeasurementType in types 1.5 Update the minimum value of range for RSRQ according to TS 36.133 v12.6.0. Test: build Bug: 133400544 Change-Id: I3ce8aed99b2109f89ddb9ab0a9a6328716c40998 --- current.txt | 2 +- radio/1.5/types.hal | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/current.txt b/current.txt index f026d7d47a..0345ce0cf6 100644 --- a/current.txt +++ b/current.txt @@ -657,7 +657,7 @@ c72cb37b3f66ef65aeb5c6438a3fbe17bbe847fdf62d1a76eafd7f3a8a526105 android.hardwar 342a8e12db4dca643f2755eb4167e8f103d96502053a25a1f51f42107a4530f1 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback 5477f8bafb29548875622fa83f1c0a29cee641acee613315eb747731001f4aff android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 91015479f5a0fba9872e98d3cca4680995de64f42ae71461b4b7e5acc5a196ab android.hardware.wifi.supplicant@1.3::types -7a4ba60b5ddedf497e5d2bdff7d72b7d4a811969000e28677dd9e2389e683b34 android.hardware.radio@1.5::types +c4026d6db206c880a69c9a90404b7298c564e3d946449a952a5a1581742a6d8f android.hardware.radio@1.5::types afa2d6cf4c0ba4b8482d5bcc097594ad5bc49be0bf3003034f75955cdaf66045 android.hardware.radio@1.5::IRadio 3afac66f21a33bc9c4b80481c7d5540038348651d9a7d8af64ea13610af138da android.hardware.radio@1.5::IRadioIndication f4888f9676890b43a459c6380f335fea7a6ad32ed3bafafeb018a88d6c0be8a4 android.hardware.radio@1.5::IRadioResponse diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index 73751b81d6..a34f5e63a8 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -57,9 +57,9 @@ enum SignalMeasurementType : int32_t { RSRP = 3, /** * Reference Signal Received Quality - * Range: -20 dB to -3 dB; + * Range: -34 dB to 3 dB; * Used RAN: EUTRAN - * Reference: 3GPP TS 36.133 9.1.7 + * Reference: 3GPP TS 36.133 v12.6.0 section 9.1.7 */ RSRQ = 4, /** From ae33929ac96597e17aa26a3296c617a1d76bbd4f Mon Sep 17 00:00:00 2001 From: Sunil Ravi Date: Mon, 23 Dec 2019 15:09:10 -0800 Subject: [PATCH 0377/1022] Wifi: DPP test cases failing in VTS test call 1_3 version of GetKeyMgmtCapabilities() from isDppSupported() method. Bug: 146804291 Test: atest -c VtsHalWifiSupplicantV1_3TargetTest Change-Id: Ib0bfe2e48b8cbe3d04e73f65bd926ab1992a4bae --- .../1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp index 8c9f9cd1e2..adc955e68b 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp @@ -109,10 +109,9 @@ class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { // We need to first get the key management capabilities from the device. // If DPP is not supported, we just pass the test. - sta_iface_->getKeyMgmtCapabilities( + sta_iface_->getKeyMgmtCapabilities_1_3( [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); - keyMgmtMask = keyMgmtMaskInternal; }); From 13834c4a796c665668deaec8af957349d1a8a82b Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Wed, 11 Dec 2019 11:00:49 -0800 Subject: [PATCH 0378/1022] Add a Registration Failure indication to IRadio Add an indication to IRadio that is fired whenever a cellular registration failure occurs. Bug: 143187065 Test: atest VtsHalRadioV1_5TargetTest Change-Id: I7765a7491f807a08272b9bc8923ae9377ff3b9d1 --- current.txt | 4 +-- radio/1.5/IRadioIndication.hal | 29 +++++++++++++++++++ radio/1.5/types.hal | 27 +++++++++++++++++ .../functional/radio_hidl_hal_utils_v1_5.h | 7 +++++ radio/1.5/vts/functional/radio_indication.cpp | 9 ++++++ 5 files changed, 74 insertions(+), 2 deletions(-) diff --git a/current.txt b/current.txt index 0345ce0cf6..921a103f68 100644 --- a/current.txt +++ b/current.txt @@ -657,9 +657,9 @@ c72cb37b3f66ef65aeb5c6438a3fbe17bbe847fdf62d1a76eafd7f3a8a526105 android.hardwar 342a8e12db4dca643f2755eb4167e8f103d96502053a25a1f51f42107a4530f1 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback 5477f8bafb29548875622fa83f1c0a29cee641acee613315eb747731001f4aff android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 91015479f5a0fba9872e98d3cca4680995de64f42ae71461b4b7e5acc5a196ab android.hardware.wifi.supplicant@1.3::types -c4026d6db206c880a69c9a90404b7298c564e3d946449a952a5a1581742a6d8f android.hardware.radio@1.5::types +d9044563a5ac5a17a239303b8dec1e51167761ac46e965f61e31654cc034d31b android.hardware.radio@1.5::types afa2d6cf4c0ba4b8482d5bcc097594ad5bc49be0bf3003034f75955cdaf66045 android.hardware.radio@1.5::IRadio -3afac66f21a33bc9c4b80481c7d5540038348651d9a7d8af64ea13610af138da android.hardware.radio@1.5::IRadioIndication +bc59237dbd93949238081f762710552e76670cb648c0e198138551460ac54b1e android.hardware.radio@1.5::IRadioIndication f4888f9676890b43a459c6380f335fea7a6ad32ed3bafafeb018a88d6c0be8a4 android.hardware.radio@1.5::IRadioResponse 55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig diff --git a/radio/1.5/IRadioIndication.hal b/radio/1.5/IRadioIndication.hal index 81452abb13..879e9addf4 100644 --- a/radio/1.5/IRadioIndication.hal +++ b/radio/1.5/IRadioIndication.hal @@ -30,4 +30,33 @@ interface IRadioIndication extends @1.4::IRadioIndication { * @param enabled whether uiccApplications are enabled, or disabled */ oneway uiccApplicationsEnablementChanged(RadioIndicationType type, bool enabled); + + /** + * Report that Registration or a Location/Routing/Tracking Area update has failed. + * + *

    Indicate whenever a registration procedure, including a location, routing, or tracking + * area update fails. This includes procedures that do not necessarily result in a change of + * the modem's registration status. If the modem's registration status changes, that is + * reflected in the onNetworkStateChanged() and subsequent get{Voice/Data}RegistrationState(). + * + * @param cellIdentity the CellIdentity, which must include the globally unique identifier for + * the cell (for example, all components of the CGI or ECGI). + * @param chosenPlmn a 5 or 6 digit alphanumeric PLMN (MCC|MNC) among those broadcast by the + * cell that was chosen for the failed registration attempt. + * @param domain Domain::CS, Domain::PS, or both in case of a combined procedure. + * @param causeCode the primary failure cause code of the procedure. + * For GSM/UMTS (MM), values are in TS 24.008 Sec 10.5.95 + * For GSM/UMTS (GMM), values are in TS 24.008 Sec 10.5.147 + * For LTE (EMM), cause codes are TS 24.301 Sec 9.9.3.9 + * For NR (5GMM), cause codes are TS 24.501 Sec 9.11.3.2 + * MAX_INT if this value is unused. + * @param additionalCauseCode the cause code of any secondary/combined procedure if appropriate. + * For UMTS, if a combined attach succeeds for PS only, then the GMM cause code shall be + * included as an additionalCauseCode. + * For LTE (ESM), cause codes are in TS 24.301 9.9.4.4 + * MAX_INT if this value is unused. + */ + oneway registrationFailed( + RadioIndicationType type, CellIdentity cellIdentity, string chosenPlmn, + bitfield domain, int32_t causeCode, int32_t additionalCauseCode); }; diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index a34f5e63a8..7d6ec417de 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -22,14 +22,22 @@ import @1.1::RadioAccessNetworks; import @1.1::RadioAccessSpecifier; import @1.1::ScanType; import @1.1::UtranBands; +import @1.2::CellIdentityCdma; +import @1.2::CellIdentityGsm; +import @1.2::CellIdentityWcdma; +import @1.2::CellIdentityTdscdma; +import @1.2::CellIdentityLte; import @1.2::NetworkScanRequest; import @1.4::AccessNetwork; import @1.4::ApnTypes; +import @1.4::CellIdentityNr; import @1.4::DataCallFailCause; import @1.4::DataConnActiveStatus; import @1.4::DataProfileInfo; import @1.4::PdpProtocolType; +import android.hidl.safe_union@1.0::Monostate; + /** * Defining signal strength type. */ @@ -397,3 +405,22 @@ struct SetupDataCallResult { int32_t mtu; }; +enum Domain : int32_t { + /** Circuit-switched */ + CS = 1 << 0, + + /** Packet-switched */ + PS = 1 << 1, +}; + +/** A union representing the CellIdentity of a single cell */ +safe_union CellIdentity { + Monostate noinit; + + CellIdentityGsm gsm; + CellIdentityWcdma wcdma; + CellIdentityTdscdma tdscdma; + CellIdentityCdma cdma; + CellIdentityLte lte; + CellIdentityNr nr; +}; diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index ba1125767b..49a315d838 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -739,6 +739,13 @@ class RadioIndication_v1_5 : public ::android::hardware::radio::V1_5::IRadioIndi Return modemReset(RadioIndicationType type, const ::android::hardware::hidl_string& reason); + + Return registrationFailed( + RadioIndicationType type, + const ::android::hardware::radio::V1_5::CellIdentity& cellIdentity, + const ::android::hardware::hidl_string& chosenPlmn, + ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_5::Domain> domain, + int32_t causeCode, int32_t additionalCauseCode); }; // Test environment for Radio HIDL HAL. diff --git a/radio/1.5/vts/functional/radio_indication.cpp b/radio/1.5/vts/functional/radio_indication.cpp index acffbbea3d..2416605447 100644 --- a/radio/1.5/vts/functional/radio_indication.cpp +++ b/radio/1.5/vts/functional/radio_indication.cpp @@ -333,3 +333,12 @@ Return RadioIndication_v1_5::uiccApplicationsEnablementChanged(RadioIndica bool /*enabled*/) { return Void(); } + +Return RadioIndication_v1_5::registrationFailed( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/, + const ::android::hardware::hidl_string& /*chosenPlmn*/, + ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_5::Domain> /*domain*/, + int32_t /*causeCode*/, int32_t /*additionalCauseCode*/) { + return Void(); +} From 0080bde5fa72fa96cd655ce7c3c8f7db99251730 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Mon, 23 Dec 2019 12:00:28 -0800 Subject: [PATCH 0379/1022] Speed up encoding Bug: 63928581 Test: atest HadamardTest Change-Id: I1e37a9559892288f76e69fe81a746b77e2bf7495 --- rebootescrow/aidl/default/HadamardUtils.cpp | 35 ++++++++++++--------- rebootescrow/aidl/default/HadamardUtils.h | 5 +-- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/rebootescrow/aidl/default/HadamardUtils.cpp b/rebootescrow/aidl/default/HadamardUtils.cpp index c578152ba1..d2422b9cd5 100644 --- a/rebootescrow/aidl/default/HadamardUtils.cpp +++ b/rebootescrow/aidl/default/HadamardUtils.cpp @@ -26,10 +26,6 @@ namespace hardware { namespace rebootescrow { namespace hadamard { -static inline void or_bit(std::vector* input, size_t bit, uint8_t val) { - (*input)[bit >> 3] |= (val & 1u) << (bit & 7); -} - static inline uint8_t read_bit(const std::vector& input, size_t bit) { return (input[bit >> 3] >> (bit & 7)) & 1u; } @@ -60,17 +56,28 @@ std::vector EncodeKey(const std::vector& input) { CHECK_EQ(input.size(), KEY_SIZE_IN_BYTES); std::vector result(OUTPUT_SIZE_BYTES, 0); static_assert(OUTPUT_SIZE_BYTES == 64 * 1024); - for (size_t i = 0; i < KEY_CODEWORDS; i++) { - uint16_t word = input[i * 2 + 1] << 8 | input[i * 2]; - for (size_t j = 0; j < ENCODE_LENGTH; j++) { - uint16_t wi = word & (j + ENCODE_LENGTH); - // Sum all the bits in the word and check its parity. - wi ^= wi >> 8u; - wi ^= wi >> 4u; - wi ^= wi >> 2u; - wi ^= wi >> 1u; - or_bit(&result, (j * KEY_CODEWORDS) + i, wi & 1); + // Transpose the key so that each row contains one bit from each codeword + uint16_t wordmatrix[CODEWORD_BITS]; + for (size_t i = 0; i < CODEWORD_BITS; i++) { + uint16_t word = 0; + for (size_t j = 0; j < KEY_CODEWORDS; j++) { + word |= read_bit(input, i + j * CODEWORD_BITS) << j; } + wordmatrix[i] = word; + } + // Fill in the encodings in Gray code order for speed. + uint16_t val = wordmatrix[CODEWORD_BITS - 1]; + size_t ix = 0; + for (size_t i = 0; i < ENCODE_LENGTH; i++) { + for (size_t b = 0; b < CODEWORD_BITS; b++) { + if (i & (1 << b)) { + ix ^= (1 << b); + val ^= wordmatrix[b]; + break; + } + } + result[ix * KEY_CODEWORD_BYTES] = val & 0xffu; + result[ix * KEY_CODEWORD_BYTES + 1] = val >> 8u; } // Apply the inverse shuffle here; we apply the forward shuffle in decoding. uint64_t rng_state = RNG_INV_SEED; diff --git a/rebootescrow/aidl/default/HadamardUtils.h b/rebootescrow/aidl/default/HadamardUtils.h index 85e635f2de..e04f7d5720 100644 --- a/rebootescrow/aidl/default/HadamardUtils.h +++ b/rebootescrow/aidl/default/HadamardUtils.h @@ -31,9 +31,10 @@ constexpr auto CODEWORD_BYTES = 2u; // uint16_t constexpr auto CODEWORD_BITS = CODEWORD_BYTES * BYTE_LENGTH; constexpr uint32_t CODE_K = CODEWORD_BITS - 1; constexpr uint32_t ENCODE_LENGTH = 1u << CODE_K; -constexpr auto KEY_CODEWORDS = 16u; +constexpr auto KEY_CODEWORD_BYTES = 2u; // uint16_t (after transpose) +constexpr auto KEY_CODEWORDS = KEY_CODEWORD_BYTES * BYTE_LENGTH; constexpr auto KEY_SIZE_IN_BYTES = KEY_CODEWORDS * CODEWORD_BYTES; -constexpr auto OUTPUT_SIZE_BYTES = KEY_CODEWORDS * ENCODE_LENGTH / BYTE_LENGTH; +constexpr auto OUTPUT_SIZE_BYTES = ENCODE_LENGTH * KEY_CODEWORD_BYTES; // Encodes a key that has a size of KEY_SIZE_IN_BYTES. Returns a byte array representation of the // encoded bitset. So a 32 bytes key will expand to 16*(2^15) bits = 64KiB. From ce00636ce5ce962013507a90a8cf5799fa5d7ce5 Mon Sep 17 00:00:00 2001 From: Kathan Shukla Date: Thu, 19 Dec 2019 02:56:31 -0800 Subject: [PATCH 0380/1022] Enable java backend for occupant awareness iface. This change also enables VNDK libbraries to use occupant awareness NDK. Test: Build test. Change-Id: Ib85ca91252b9b96b53d886ad85f723b1d1f6178e --- automotive/occupant_awareness/aidl/Android.bp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/automotive/occupant_awareness/aidl/Android.bp b/automotive/occupant_awareness/aidl/Android.bp index 6e9e8aa386..face235a42 100644 --- a/automotive/occupant_awareness/aidl/Android.bp +++ b/automotive/occupant_awareness/aidl/Android.bp @@ -7,7 +7,12 @@ aidl_interface { stability: "vintf", backend: { java: { - enabled: false, + platform_apis: true, }, - } + ndk: { + vndk: { + enabled: true, + }, + }, + }, } From 9e00293747fc1e06292bc12602235cace24b1be2 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Mon, 30 Dec 2019 12:58:18 +0800 Subject: [PATCH 0381/1022] hostapd: Add debug level control Add new API: setDebugParams Bug: 129111866 Test: manual test Test: atest VtsHalWifiHostapdV1_2TargetTest Change-Id: I0e61db3d029c89380b687ecddd38a00aafcff0cc --- current.txt | 4 ++-- wifi/hostapd/1.2/IHostapd.hal | 14 ++++++++++++++ wifi/hostapd/1.2/types.hal | 14 ++++++++++++++ .../1.2/vts/functional/hostapd_hidl_test.cpp | 9 +++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/current.txt b/current.txt index 921a103f68..68e4713a45 100644 --- a/current.txt +++ b/current.txt @@ -650,8 +650,8 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback cf1d55e8c68300090747ab90b94c22e4c859b29c84ced68a317c595bb115eab2 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi -36b3acf78ac4ecf8156be8741c1d8332cdce7a1ebf4dfa1562952f14a94e6c87 android.hardware.wifi.hostapd@1.2::IHostapd -2defa258951e25a132aaeb36e3febe6f41bf9c6dbb1b1ebdf0b41708ab4e107e android.hardware.wifi.hostapd@1.2::types +9bc274c9d73aae170fd9e18df2476ade4c19b629cfb38dd03dd237a6cc2d932b android.hardware.wifi.hostapd@1.2::IHostapd +11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant c72cb37b3f66ef65aeb5c6438a3fbe17bbe847fdf62d1a76eafd7f3a8a526105 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface 342a8e12db4dca643f2755eb4167e8f103d96502053a25a1f51f42107a4530f1 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback diff --git a/wifi/hostapd/1.2/IHostapd.hal b/wifi/hostapd/1.2/IHostapd.hal index 1bac1e7897..c296cd54b4 100644 --- a/wifi/hostapd/1.2/IHostapd.hal +++ b/wifi/hostapd/1.2/IHostapd.hal @@ -21,6 +21,7 @@ import @1.1::IHostapd; import HostapdStatus; import MacAddress; import Ieee80211ReasonCode; +import DebugLevel; /** * Top-level object for managing SoftAPs. @@ -120,4 +121,17 @@ interface IHostapd extends @1.1::IHostapd { */ forceClientDisconnect(string ifaceName, MacAddress clientAddress, Ieee80211ReasonCode reasonCode) generates (HostapdStatus status); + + /** + * Set debug parameters for the hostapd. + * + * @param level Debug logging level for the hostapd. + * (one of |DebugLevel| values). + * @return status Status of the operation. + * Possible status codes: + * |HostapdStatusCode.SUCCESS|, + * |HostapdStatusCode.FAILURE_UNKNOWN| + */ + setDebugParams(DebugLevel level) + generates (HostapdStatus status); }; diff --git a/wifi/hostapd/1.2/types.hal b/wifi/hostapd/1.2/types.hal index 06e890b2cc..54e6529852 100644 --- a/wifi/hostapd/1.2/types.hal +++ b/wifi/hostapd/1.2/types.hal @@ -53,3 +53,17 @@ struct HostapdStatus { */ string debugMessage; }; + +/** + * Debug levels for the hostapd. + * Only log messages with a level greater than the set level + * (via |setDebugParams|) will be logged. + */ +enum DebugLevel : uint32_t { + EXCESSIVE = 0, + MSGDUMP = 1, + DEBUG = 2, + INFO = 3, + WARNING = 4, + ERROR = 5 +}; diff --git a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp index b092d000ef..8245f8fc50 100644 --- a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp +++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp @@ -31,6 +31,7 @@ using ::android::sp; using ::android::hardware::hidl_string; using ::android::hardware::Return; using ::android::hardware::Void; +using ::android::hardware::wifi::hostapd::V1_2::DebugLevel; using ::android::hardware::wifi::hostapd::V1_2::HostapdStatusCode; using ::android::hardware::wifi::hostapd::V1_2::Ieee80211ReasonCode; using ::android::hardware::wifi::hostapd::V1_2::IHostapd; @@ -319,6 +320,14 @@ TEST_P(HostapdHidlTest, DisconnectClientWhenIfacAvailable) { EXPECT_EQ(HostapdStatusCode::FAILURE_CLIENT_UNKNOWN, status_1_2.code); } +/* + * SetDebugParams + */ +TEST_P(HostapdHidlTest, SetDebugParams) { + auto status = HIDL_INVOKE(hostapd_, setDebugParams, DebugLevel::EXCESSIVE); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + INSTANTIATE_TEST_CASE_P( PerInstance, HostapdHidlTest, testing::Combine( From 5a3e81c7fb359fcb14b86851e0d58ac4d339109c Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Sat, 28 Dec 2019 00:50:38 -0800 Subject: [PATCH 0382/1022] Fix vts test VtsHalWifiV1_2TargetTest VTS test for WifiChipHidlTest#registerEventCallback_1_2 was failing on the default implementation of the 1.4 HAL. This is because registerEventCallback_1_2() is no longer supported due to the upgrade to registerEventCallback_1_4(). This commit fixes this VTS test error by allowing ERROR_NOT_SUPPORTED as a valid test output. Bug: 146020950 Test: atest VtsHalWifiV1_2TargetTest Change-Id: Ia58b0dad5ed753c22d620b0fad6904d634e01e72 --- wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp index 47faec8b88..93aa0f3ae9 100644 --- a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp @@ -176,11 +176,15 @@ TEST_P(WifiChipHidlTest, registerEventCallback_1_2) { sp wifiChipEventCallback = new WifiChipEventCallback(); const auto& status = HIDL_INVOKE(wifi_chip_, registerEventCallback_1_2, wifiChipEventCallback); - EXPECT_EQ(WifiStatusCode::SUCCESS, status.code); + + if (status.code != WifiStatusCode::SUCCESS) { + EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code); + return; + } } INSTANTIATE_TEST_SUITE_P( PerInstance, WifiChipHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames( ::android::hardware::wifi::V1_2::IWifi::descriptor)), - android::hardware::PrintInstanceNameToString); \ No newline at end of file + android::hardware::PrintInstanceNameToString); From 36defb377e1d3d108e663fe3ddab97d4a5749411 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Sun, 29 Dec 2019 21:24:27 -0800 Subject: [PATCH 0383/1022] Wifi: Fix VTS tests This commit fixes VTS tests resulting from upgrading APIs and stopping support for old APIs. Bug: 144926452 Test: atest VtsHalWifiV1_0TargetTest Test: atest VtsHalWifiV1_3TargetTest Change-Id: I73140be1dfb969da24c802e658e97d4040837243 --- .../vts/functional/wifi_chip_hidl_test.cpp | 10 +++++--- .../vts/functional/wifi_hidl_test_utils.cpp | 17 -------------- .../1.0/vts/functional/wifi_hidl_test_utils.h | 2 -- .../wifi_rtt_controller_hidl_test.cpp | 23 +++++++++++++++++-- wifi/1.4/default/wifi_chip.cpp | 2 +- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp index ec96fcf50c..62874ef147 100644 --- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp @@ -543,12 +543,16 @@ TEST_P(WifiChipHidlTest, CreateRttController) { const auto& status_and_rtt_controller = HIDL_INVOKE(wifi_chip_, createRttController, iface); - EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_rtt_controller.first.code); - EXPECT_NE(nullptr, status_and_rtt_controller.second.get()); + if (status_and_rtt_controller.first.code != + WifiStatusCode::ERROR_NOT_SUPPORTED) { + EXPECT_EQ(WifiStatusCode::SUCCESS, + status_and_rtt_controller.first.code); + EXPECT_NE(nullptr, status_and_rtt_controller.second.get()); + } } INSTANTIATE_TEST_SUITE_P( PerInstance, WifiChipHidlTest, testing::ValuesIn( android::hardware::getAllHalInstanceNames(IWifi::descriptor)), - android::hardware::PrintInstanceNameToString); \ No newline at end of file + android::hardware::PrintInstanceNameToString); diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp index d584d4bdec..26e4821984 100644 --- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp +++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp @@ -209,23 +209,6 @@ sp getWifiStaIface(const std::string& instance_name) { return status_and_iface.second; } -sp getWifiRttController(const std::string& instance_name) { - sp wifi_chip = getWifiChip(instance_name); - if (!wifi_chip.get()) { - return nullptr; - } - sp wifi_sta_iface = getWifiStaIface(instance_name); - if (!wifi_sta_iface.get()) { - return nullptr; - } - const auto& status_and_controller = - HIDL_INVOKE(wifi_chip, createRttController, wifi_sta_iface); - if (status_and_controller.first.code != WifiStatusCode::SUCCESS) { - return nullptr; - } - return status_and_controller.second; -} - bool configureChipToSupportIfaceType(const sp& wifi_chip, IfaceType type, ChipModeId* configured_mode_id) { diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h index bdee2ec0ce..866013417f 100644 --- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h +++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h @@ -44,8 +44,6 @@ android::sp getWifiP2pIface( const std::string& instance_name = ""); android::sp getWifiStaIface( const std::string& instance_name = ""); -android::sp -getWifiRttController(const std::string& instance_name = ""); // Configure the chip in a mode to support the creation of the provided // iface type. bool configureChipToSupportIfaceType( diff --git a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp index e1ee34fef0..6c01995307 100644 --- a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp @@ -22,11 +22,15 @@ #include #include +#include "wifi_hidl_call_util.h" #include "wifi_hidl_test_utils.h" using ::android::sp; using ::android::hardware::wifi::V1_0::IWifi; +using ::android::hardware::wifi::V1_0::IWifiChip; using ::android::hardware::wifi::V1_0::IWifiRttController; +using ::android::hardware::wifi::V1_0::IWifiStaIface; +using ::android::hardware::wifi::V1_0::WifiStatusCode; /** * Fixture to use for all RTT controller HIDL interface tests. @@ -48,11 +52,26 @@ class WifiRttControllerHidlTest : public ::testing::TestWithParam { */ TEST_P(WifiRttControllerHidlTest, Create) { stopWifi(GetInstanceName()); - EXPECT_NE(nullptr, getWifiRttController(GetInstanceName()).get()); + + const std::string& instance_name = GetInstanceName(); + + sp wifi_chip = getWifiChip(instance_name); + EXPECT_NE(nullptr, wifi_chip.get()); + + sp wifi_sta_iface = getWifiStaIface(instance_name); + EXPECT_NE(nullptr, wifi_sta_iface.get()); + + const auto& status_and_controller = + HIDL_INVOKE(wifi_chip, createRttController, wifi_sta_iface); + if (status_and_controller.first.code != + WifiStatusCode::ERROR_NOT_SUPPORTED) { + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_controller.first.code); + EXPECT_NE(nullptr, status_and_controller.second.get()); + } } INSTANTIATE_TEST_SUITE_P( PerInstance, WifiRttControllerHidlTest, testing::ValuesIn( android::hardware::getAllHalInstanceNames(IWifi::descriptor)), - android::hardware::PrintInstanceNameToString); \ No newline at end of file + android::hardware::PrintInstanceNameToString); diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp index a70457bded..3498510e2e 100644 --- a/wifi/1.4/default/wifi_chip.cpp +++ b/wifi/1.4/default/wifi_chip.cpp @@ -992,7 +992,7 @@ WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) { std::pair> WifiChip::createRttControllerInternal(const sp& /*bound_iface*/) { LOG(ERROR) << "createRttController is not supported on this HAL"; - return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; + return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}}; } std::pair> From 436ab20ef64eb84c7a8d0f092febcd743782833f Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Sun, 29 Dec 2019 23:32:56 -0800 Subject: [PATCH 0384/1022] Wifi: Fix VTS tests in VtsHalWifiNanV1_2TargetTest This commit fixes VTS tests in VtsHalWifiNanV1_2TargetTest resulting from upgrading APIs and stopping support for old APIs. Bug: 146989939 Test: atest VtsHalWifiNanV1_2TargetTest Change-Id: Ibc71cdb3ead7fb346ac62ebfd132f82ee3d81eeb --- .../functional/wifi_nan_iface_hidl_test.cpp | 65 +++++++++++-------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp index f3f76e1564..d5d87ce73e 100644 --- a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp +++ b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp @@ -481,15 +481,18 @@ TEST_P(WifiNanIfaceHidlTest, enableRequest_1_2InvalidArgs) { callbackType = INVALID; NanEnableRequest nanEnableRequest = {}; NanConfigRequestSupplemental nanConfigRequestSupp = {}; - ASSERT_EQ(WifiStatusCode::SUCCESS, - HIDL_INVOKE(iwifiNanIface, enableRequest_1_2, inputCmdId, - nanEnableRequest, nanConfigRequestSupp) - .code); - // wait for a callback - ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE)); - ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callbackType); - ASSERT_EQ(id, inputCmdId); - ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS); + const auto& halStatus = + HIDL_INVOKE(iwifiNanIface, enableRequest_1_2, inputCmdId, + nanEnableRequest, nanConfigRequestSupp); + if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) { + ASSERT_EQ(WifiStatusCode::SUCCESS, halStatus.code); + + // wait for a callback + ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE)); + ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callbackType); + ASSERT_EQ(id, inputCmdId); + ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS); + } } /* @@ -502,10 +505,12 @@ TEST_P(WifiNanIfaceHidlTest, enableRequest_1_2ShimInvalidArgs) { nanEnableRequest.configParams.numberOfPublishServiceIdsInBeacon = 128; // must be <= 127 NanConfigRequestSupplemental nanConfigRequestSupp = {}; - ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, - HIDL_INVOKE(iwifiNanIface, enableRequest_1_2, inputCmdId, - nanEnableRequest, nanConfigRequestSupp) - .code); + const auto& halStatus = + HIDL_INVOKE(iwifiNanIface, enableRequest_1_2, inputCmdId, + nanEnableRequest, nanConfigRequestSupp); + if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) { + ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, halStatus.code); + } } /* @@ -516,15 +521,19 @@ TEST_P(WifiNanIfaceHidlTest, configRequest_1_2InvalidArgs) { callbackType = INVALID; NanConfigRequest nanConfigRequest = {}; NanConfigRequestSupplemental nanConfigRequestSupp = {}; - ASSERT_EQ(WifiStatusCode::SUCCESS, - HIDL_INVOKE(iwifiNanIface, configRequest_1_2, inputCmdId, - nanConfigRequest, nanConfigRequestSupp) - .code); - // wait for a callback - ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE)); - ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callbackType); - ASSERT_EQ(id, inputCmdId); - ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS); + const auto& halStatus = + HIDL_INVOKE(iwifiNanIface, configRequest_1_2, inputCmdId, + nanConfigRequest, nanConfigRequestSupp); + + if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) { + ASSERT_EQ(WifiStatusCode::SUCCESS, halStatus.code); + + // wait for a callback + ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE)); + ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callbackType); + ASSERT_EQ(id, inputCmdId); + ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS); + } } /* @@ -536,14 +545,16 @@ TEST_P(WifiNanIfaceHidlTest, configRequest_1_2ShimInvalidArgs) { NanConfigRequest nanConfigRequest = {}; nanConfigRequest.numberOfPublishServiceIdsInBeacon = 128; // must be <= 127 NanConfigRequestSupplemental nanConfigRequestSupp = {}; - ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, - HIDL_INVOKE(iwifiNanIface, configRequest_1_2, inputCmdId, - nanConfigRequest, nanConfigRequestSupp) - .code); + const auto& halStatus = + HIDL_INVOKE(iwifiNanIface, configRequest_1_2, inputCmdId, + nanConfigRequest, nanConfigRequestSupp); + if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) { + ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, halStatus.code); + } } INSTANTIATE_TEST_SUITE_P( PerInstance, WifiNanIfaceHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames( ::android::hardware::wifi::V1_2::IWifi::descriptor)), - android::hardware::PrintInstanceNameToString); \ No newline at end of file + android::hardware::PrintInstanceNameToString); From 9392b58da0feb828c527a1ad098f1b3469591c05 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Mon, 30 Dec 2019 10:11:57 -0800 Subject: [PATCH 0385/1022] Wifi: Fix VtsHalWifiHostapdV1_1TargetTest This commit fixes VTS tests in VtsHalWifiHostapdV1_1TargetTest resulting from upgrading APIs and stopping support for old APIs. Bug: 147006566 Test: atest VtsHalWifiHostapdV1_1TargetTest Change-Id: Ia6be7f08c160ef3b0478630193fb6a39e774e109 --- .../1.1/vts/functional/hostapd_hidl_test.cpp | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp index 1804d8ca85..345cf312d4 100644 --- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp +++ b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp @@ -233,7 +233,11 @@ TEST_P(HostapdHidlTest, AddOpenAccessPointWithAcs) { TEST_P(HostapdHidlTest, AddPskAccessPointWithoutAcs) { auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, getIfaceParamsWithoutAcs(), getPskNwParams()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + // FAILURE_UNKNOWN is used by higher versions to indicate this API is no + // longer supported (replaced by an upgraded API) + if (status.code != HostapdStatusCode::FAILURE_UNKNOWN) { + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + } } /** @@ -243,7 +247,11 @@ TEST_P(HostapdHidlTest, AddPskAccessPointWithoutAcs) { TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) { auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, getIfaceParamsWithoutAcs(), getOpenNwParams()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + // FAILURE_UNKNOWN is used by higher versions to indicate this API is no + // longer supported (replaced by an upgraded API) + if (status.code != HostapdStatusCode::FAILURE_UNKNOWN) { + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + } } /** @@ -269,10 +277,14 @@ TEST_P(HostapdHidlTest, RemoveAccessPointWithAcs) { TEST_P(HostapdHidlTest, RemoveAccessPointWithoutAcs) { auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, getIfaceParamsWithoutAcs(), getPskNwParams()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); - status = - HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + // FAILURE_UNKNOWN is used by higher versions to indicate this API is no + // longer supported (replaced by an upgraded API) + if (status.code != HostapdStatusCode::FAILURE_UNKNOWN) { + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + status = + HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + } } /** From 6a1d5e405fdc9be075c73bcde69fc8785ad390d1 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Thu, 2 Jan 2020 18:22:30 +0000 Subject: [PATCH 0386/1022] Add exceptions to the signed quantization coupling tests Main commit is in frameworks/ml/nn. This one only renames testModel.hasQuant8AsymmOperands() to testModel.hasQuant8CoupledOperands(). Bug: 143935412 Bug: 143934188 Bug: 143935353 Bug: 143934467 Bug: 143934184 Test: quantization coupling tests in CTS and VTS Change-Id: I0f7c331c355fe61ee06605786f09bc1ca7cdef57 --- neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index be894f27c7..e3c537635a 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -452,7 +452,7 @@ void Execute(const sp& device, const TestModel& testModel, TestKind tes EvaluatePreparedModel(preparedModel, testModel, TestKind::DYNAMIC_SHAPE); } break; case TestKind::QUANTIZATION_COUPLING: { - ASSERT_TRUE(testModel.hasQuant8AsymmOperands()); + ASSERT_TRUE(testModel.hasQuant8CoupledOperands()); createPreparedModel(device, model, &preparedModel, /*reportSkipping*/ false); TestModel signedQuantizedModel = convertQuant8AsymmOperandsToSigned(testModel); sp preparedCoupledModel; @@ -521,7 +521,7 @@ INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); INSTANTIATE_GENERATED_TEST(DISABLED_QuantizationCouplingTest, [](const TestModel& testModel) { - return testModel.hasQuant8AsymmOperands() && testModel.operations.size() == 1; + return testModel.hasQuant8CoupledOperands() && testModel.operations.size() == 1; }); } // namespace android::hardware::neuralnetworks::V1_3::vts::functional From f9e869e277c7f1607c71102d0e7206d73fa40e4c Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Thu, 2 Jan 2020 14:12:21 -0800 Subject: [PATCH 0387/1022] CAN bus HAL VTS: read interface names from device manifest Bug: 143635976 Test: VTS Change-Id: I99dc0de992dff8ffef03572fd38f57f38b7975ab --- automotive/can/1.0/vts/functional/Android.bp | 7 +++-- .../VtsHalCanBusVirtualV1_0TargetTest.cpp | 22 ++++++++++++-- .../VtsHalCanControllerV1_0TargetTest.cpp | 26 +++++++++++++--- automotive/can/1.0/vts/utils/Android.bp | 12 +++++++- .../can/1.0/vts/utils/bus-enumerator.cpp | 30 +++++++++++++++++++ .../include/can-vts-utils/bus-enumerator.h | 25 ++++++++++++++++ 6 files changed, 113 insertions(+), 9 deletions(-) create mode 100644 automotive/can/1.0/vts/utils/bus-enumerator.cpp create mode 100644 automotive/can/1.0/vts/utils/include/can-vts-utils/bus-enumerator.h diff --git a/automotive/can/1.0/vts/functional/Android.bp b/automotive/can/1.0/vts/functional/Android.bp index b4d91325ee..e3e770b047 100644 --- a/automotive/can/1.0/vts/functional/Android.bp +++ b/automotive/can/1.0/vts/functional/Android.bp @@ -16,13 +16,16 @@ cc_defaults { name: "android.hardware.automotive.can@vts-defaults", - defaults: ["VtsHalTargetTestDefaults", "android.hardware.automotive.can@defaults"], + defaults: [ + "VtsHalTargetTestDefaults", + "android.hardware.automotive.can@defaults", + ], header_libs: [ "android.hardware.automotive.can@hidl-utils-lib", - "android.hardware.automotive.can@vts-utils-lib", ], static_libs: [ "android.hardware.automotive.can@1.0", + "android.hardware.automotive.can@vts-utils-lib", "libgmock", ], test_suites: ["general-tests"], diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp index 1663663ac6..ca661feef0 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -139,14 +140,20 @@ class CanBusVirtualHalTest : public ::testing::VtsHalHidlTargetTestBase { Bus makeBus(); + protected: + static hidl_vec mBusNames; + private: unsigned mLastIface = 0; static sp mCanController; static bool mVirtualSupported; + static bool mTestCaseInitialized; }; sp CanBusVirtualHalTest::mCanController = nullptr; bool CanBusVirtualHalTest::mVirtualSupported; +hidl_vec CanBusVirtualHalTest::mBusNames; +bool CanBusVirtualHalTest::mTestCaseInitialized = false; static CanMessage makeMessage(CanMessageId id) { CanMessage msg = {}; @@ -160,6 +167,7 @@ static void clearTimestamps(std::vector& messages) { void CanBusVirtualHalTest::SetUp() { if (!mVirtualSupported) GTEST_SKIP(); + ASSERT_TRUE(mTestCaseInitialized); } void CanBusVirtualHalTest::SetUpTestCase() { @@ -170,6 +178,11 @@ void CanBusVirtualHalTest::SetUpTestCase() { hidl_vec supported; mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).assertOk(); mVirtualSupported = supported.contains(InterfaceType::VIRTUAL); + + mBusNames = utils::getBusNames(); + ASSERT_NE(0u, mBusNames.size()) << "No ICanBus HALs defined in device manifest"; + + mTestCaseInitialized = true; } void CanBusVirtualHalTest::TearDownTestCase() { @@ -177,10 +190,11 @@ void CanBusVirtualHalTest::TearDownTestCase() { } Bus CanBusVirtualHalTest::makeBus() { - const auto idx = ++mLastIface; + const auto idx = mLastIface++; + EXPECT_LT(idx, mBusNames.size()); ICanController::BusConfiguration config = {}; - config.name = "test" + std::to_string(idx); + config.name = mBusNames[idx]; config.iftype = InterfaceType::VIRTUAL; config.interfaceId.address("vcan50"); @@ -207,6 +221,7 @@ TEST_F(CanBusVirtualHalTest, SendAfterClose) { } TEST_F(CanBusVirtualHalTest, SendAndRecv) { + if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses."; auto bus1 = makeBus(); auto bus2 = makeBus(); @@ -226,6 +241,8 @@ TEST_F(CanBusVirtualHalTest, SendAndRecv) { } TEST_F(CanBusVirtualHalTest, DownOneOfTwo) { + if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses."; + auto bus1 = makeBus(); auto bus2 = makeBus(); @@ -235,6 +252,7 @@ TEST_F(CanBusVirtualHalTest, DownOneOfTwo) { } TEST_F(CanBusVirtualHalTest, Filter) { + if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses."; auto bus1 = makeBus(); auto bus2 = makeBus(); diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp index 22dec2cb9a..9bc789aa29 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,7 @@ class CanControllerHalTest : public ::testing::VtsHalHidlTargetTestBase { protected: virtual void SetUp() override; virtual void TearDown() override; + static void SetUpTestCase(); hidl_vec getSupportedInterfaceTypes(); bool isSupported(InterfaceType iftype); @@ -46,9 +48,18 @@ class CanControllerHalTest : public ::testing::VtsHalHidlTargetTestBase { void assertRegistered(const std::string srvname, bool expectRegistered); sp mCanController; + static hidl_vec mBusNames; + + private: + static bool mTestCaseInitialized; }; +hidl_vec CanControllerHalTest::mBusNames; +bool CanControllerHalTest::mTestCaseInitialized = false; + void CanControllerHalTest::SetUp() { + ASSERT_TRUE(mTestCaseInitialized); + const auto serviceName = gEnv->getServiceName(); mCanController = getService(serviceName); ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << serviceName; @@ -58,6 +69,13 @@ void CanControllerHalTest::TearDown() { mCanController.clear(); } +void CanControllerHalTest::SetUpTestCase() { + mBusNames = utils::getBusNames(); + ASSERT_NE(0u, mBusNames.size()) << "No ICanBus HALs defined in device manifest"; + + mTestCaseInitialized = true; +} + hidl_vec CanControllerHalTest::getSupportedInterfaceTypes() { hidl_vec iftypesResult; mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&iftypesResult)).assertOk(); @@ -104,7 +122,7 @@ TEST_F(CanControllerHalTest, SupportsSomething) { } TEST_F(CanControllerHalTest, BringUpDown) { - const std::string name = "dummy"; + const std::string name = mBusNames[0]; assertRegistered(name, false); if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::OK)) GTEST_SKIP(); @@ -122,7 +140,7 @@ TEST_F(CanControllerHalTest, DownDummy) { } TEST_F(CanControllerHalTest, UpTwice) { - const std::string name = "dummy"; + const std::string name = mBusNames[0]; assertRegistered(name, false); if (!up(InterfaceType::VIRTUAL, name, "vcan72", ICanController::Result::OK)) GTEST_SKIP(); @@ -211,7 +229,7 @@ TEST_F(CanControllerHalTest, FailBadName) { } TEST_F(CanControllerHalTest, FailBadVirtualAddress) { - const std::string name = "dummy"; + const std::string name = mBusNames[0]; assertRegistered(name, false); if (!up(InterfaceType::VIRTUAL, name, "", ICanController::Result::BAD_ADDRESS)) GTEST_SKIP(); @@ -219,7 +237,7 @@ TEST_F(CanControllerHalTest, FailBadVirtualAddress) { } TEST_F(CanControllerHalTest, FailBadSocketcanAddress) { - const std::string name = "dummy"; + const std::string name = mBusNames[0]; assertRegistered(name, false); if (!up(InterfaceType::SOCKETCAN, name, "can87", ICanController::Result::BAD_ADDRESS)) { diff --git a/automotive/can/1.0/vts/utils/Android.bp b/automotive/can/1.0/vts/utils/Android.bp index e925c8fe34..d03ead30eb 100644 --- a/automotive/can/1.0/vts/utils/Android.bp +++ b/automotive/can/1.0/vts/utils/Android.bp @@ -14,7 +14,17 @@ // limitations under the License. // -cc_library_headers { +cc_library_static { name: "android.hardware.automotive.can@vts-utils-lib", + defaults: ["android.hardware.automotive.can@defaults"], + srcs: [ + "bus-enumerator.cpp", + ], export_include_dirs: ["include"], + header_libs: [ + "android.hardware.automotive.can@hidl-utils-lib", + ], + static_libs: [ + "android.hardware.automotive.can@1.0", + ], } diff --git a/automotive/can/1.0/vts/utils/bus-enumerator.cpp b/automotive/can/1.0/vts/utils/bus-enumerator.cpp new file mode 100644 index 0000000000..c012dd21cf --- /dev/null +++ b/automotive/can/1.0/vts/utils/bus-enumerator.cpp @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#include +#include +#include + +namespace android::hardware::automotive::can::V1_0::vts::utils { + +hidl_vec getBusNames() { + auto manager = hidl::manager::V1_2::IServiceManager::getService(); + hidl_vec services; + manager->listManifestByInterface(ICanBus::descriptor, hidl_utils::fill(&services)); + return services; +} + +} // namespace android::hardware::automotive::can::V1_0::vts::utils diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/bus-enumerator.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/bus-enumerator.h new file mode 100644 index 0000000000..ef385eb395 --- /dev/null +++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/bus-enumerator.h @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace android::hardware::automotive::can::V1_0::vts::utils { + +hidl_vec getBusNames(); + +} // namespace android::hardware::automotive::can::V1_0::vts::utils From 216311fd97d42332537a0ec076a8a0b6387a4d24 Mon Sep 17 00:00:00 2001 From: Sasha Kuznetsov Date: Thu, 2 Jan 2020 17:23:42 -0800 Subject: [PATCH 0388/1022] Complete 2.1 gnss default implementation to pass all VTS tests Test: atest VtsHalGnssV2_1TargetTest && atest VtsHalGnssV2_0TargetTest && atest VtsHalGnssV1_1TargetTest && atest VtsHalGnssV1_0TargetTest Bug: 146216289 Change-Id: Idfd80f70b67359dcbf1dc033b9b4218aff0c869c --- gnss/2.1/default/Android.bp | 1 + gnss/2.1/default/Gnss.cpp | 112 ++++++++++++++++++++++++++------- gnss/2.1/default/Gnss.h | 3 + gnss/2.1/default/GnssDebug.cpp | 62 ++++++++++++++++++ gnss/2.1/default/GnssDebug.h | 51 +++++++++++++++ 5 files changed, 207 insertions(+), 22 deletions(-) create mode 100644 gnss/2.1/default/GnssDebug.cpp create mode 100644 gnss/2.1/default/GnssDebug.h diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp index 7ef999081e..834847e91e 100644 --- a/gnss/2.1/default/Android.bp +++ b/gnss/2.1/default/Android.bp @@ -22,6 +22,7 @@ cc_binary { vintf_fragments: ["android.hardware.gnss@2.1-service.xml"], srcs: [ "Gnss.cpp", + "GnssDebug.cpp", "GnssMeasurement.cpp", "GnssMeasurementCorrections.cpp", "GnssConfiguration.cpp", diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp index 6b61a827d0..7db86897f9 100644 --- a/gnss/2.1/default/Gnss.cpp +++ b/gnss/2.1/default/Gnss.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "Gnss" #include "Gnss.h" +#include "GnssDebug.h" #include "GnssMeasurement.h" #include "GnssMeasurementCorrections.h" #include "Utils.h" @@ -35,6 +36,8 @@ namespace implementation { sp Gnss::sGnssCallback_2_1 = nullptr; sp Gnss::sGnssCallback_2_0 = nullptr; +sp Gnss::sGnssCallback_1_1 = nullptr; +sp Gnss::sGnssCallback_1_0 = nullptr; Gnss::Gnss() : mMinIntervalMs(1000), mGnssConfiguration{new GnssConfiguration()} {} @@ -55,8 +58,13 @@ Return Gnss::start() { auto svStatus = filterBlacklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1()); this->reportSvStatus(svStatus); - const auto location = Utils::getMockLocationV2_0(); - this->reportLocation(location); + if (sGnssCallback_2_1 != nullptr || sGnssCallback_2_0 != nullptr) { + const auto location = Utils::getMockLocationV2_0(); + this->reportLocation(location); + } else { + const auto location = Utils::getMockLocationV1_0(); + this->reportLocation(location); + } std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs)); } @@ -84,9 +92,29 @@ Return Gnss::stop() { } // Methods from V1_0::IGnss follow. -Return Gnss::setCallback(const sp&) { - // TODO implement - return bool{}; +Return Gnss::setCallback(const sp& callback) { + if (callback == nullptr) { + ALOGE("%s: Null callback ignored", __func__); + return false; + } + + sGnssCallback_1_0 = callback; + + uint32_t capabilities = 0x0 | V1_0::IGnssCallback::Capabilities::MEASUREMENTS | + V1_0::IGnssCallback::Capabilities::SCHEDULING; + auto ret = sGnssCallback_1_0->gnssSetCapabilitesCb(capabilities); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2018}; + + ret = sGnssCallback_1_0->gnssSetSystemInfoCb(gnssInfo); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + return true; } Return Gnss::cleanup() { @@ -96,13 +124,11 @@ Return Gnss::cleanup() { } Return Gnss::injectTime(int64_t, int64_t, int32_t) { - // TODO implement - return bool{}; + return true; } Return Gnss::injectLocation(double, double, float) { - // TODO implement - return bool{}; + return true; } Return Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData) { @@ -111,10 +137,10 @@ Return Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData) { } Return Gnss::setPositionMode(V1_0::IGnss::GnssPositionMode, - V1_0::IGnss::GnssPositionRecurrence, uint32_t, uint32_t, - uint32_t) { - // TODO implement - return bool{}; + V1_0::IGnss::GnssPositionRecurrence, uint32_t minIntervalMs, + uint32_t, uint32_t) { + mMinIntervalMs = minIntervalMs; + return true; } Return> Gnss::getExtensionAGnssRil() { @@ -138,8 +164,8 @@ Return> Gnss::getExtensionGnssNi() { } Return> Gnss::getExtensionGnssMeasurement() { - // TODO implement - return ::android::sp{}; + ALOGD("Gnss::getExtensionGnssMeasurement"); + return new GnssMeasurement(); } Return> Gnss::getExtensionGnssNavigationMessage() { @@ -158,8 +184,7 @@ Return> Gnss::getExtensionGnssConfiguration() { } Return> Gnss::getExtensionGnssDebug() { - // TODO implement - return ::android::sp{}; + return new V1_1::implementation::GnssDebug(); } Return> Gnss::getExtensionGnssBatching() { @@ -168,9 +193,34 @@ Return> Gnss::getExtensionGnssBatching() { } // Methods from V1_1::IGnss follow. -Return Gnss::setCallback_1_1(const sp&) { - // TODO implement - return bool{}; +Return Gnss::setCallback_1_1(const sp& callback) { + if (callback == nullptr) { + ALOGE("%s: Null callback ignored", __func__); + return false; + } + + sGnssCallback_1_1 = callback; + + uint32_t capabilities = 0x0; + auto ret = sGnssCallback_1_1->gnssSetCapabilitesCb(capabilities); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2018}; + + ret = sGnssCallback_1_1->gnssSetSystemInfoCb(gnssInfo); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + auto gnssName = "Google Mock GNSS Implementation v2.1"; + ret = sGnssCallback_1_1->gnssNameCb(gnssName); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + return true; } Return Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode, @@ -191,8 +241,7 @@ Return> Gnss::getExtensionGnssMeasurement_1_1() { } Return Gnss::injectBestLocation(const V1_0::GnssLocation&) { - // TODO implement - return bool{}; + return true; } // Methods from V2_0::IGnss follow. @@ -332,6 +381,25 @@ void Gnss::reportSvStatus(const hidl_vec& svInfoList) const { } } +void Gnss::reportLocation(const V1_0::GnssLocation& location) const { + std::unique_lock lock(mMutex); + if (sGnssCallback_1_1 != nullptr) { + auto ret = sGnssCallback_1_1->gnssLocationCb(location); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback v1.1", __func__); + } + return; + } + if (sGnssCallback_1_0 == nullptr) { + ALOGE("%s: No non-null callback", __func__); + return; + } + auto ret = sGnssCallback_1_0->gnssLocationCb(location); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback v1.0", __func__); + } +} + void Gnss::reportLocation(const V2_0::GnssLocation& location) const { std::unique_lock lock(mMutex); if (sGnssCallback_2_1 != nullptr) { diff --git a/gnss/2.1/default/Gnss.h b/gnss/2.1/default/Gnss.h index 7917bbd6a2..7a2a2c953a 100644 --- a/gnss/2.1/default/Gnss.h +++ b/gnss/2.1/default/Gnss.h @@ -92,10 +92,13 @@ struct Gnss : public IGnss { private: void reportLocation(const V2_0::GnssLocation&) const; + void reportLocation(const V1_0::GnssLocation&) const; void reportSvStatus(const hidl_vec&) const; static sp sGnssCallback_2_1; static sp sGnssCallback_2_0; + static sp sGnssCallback_1_1; + static sp sGnssCallback_1_0; std::atomic mMinIntervalMs; sp mGnssConfiguration; std::atomic mIsActive; diff --git a/gnss/2.1/default/GnssDebug.cpp b/gnss/2.1/default/GnssDebug.cpp new file mode 100644 index 0000000000..a9f7ded2a7 --- /dev/null +++ b/gnss/2.1/default/GnssDebug.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 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 "GnssDebug" + +#include + +#include "Constants.h" +#include "GnssDebug.h" + +using namespace ::android::hardware::gnss::common; + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_1 { +namespace implementation { + +// Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow. +Return GnssDebug::getDebugData(V1_0::IGnssDebug::getDebugData_cb _hidl_cb) { + PositionDebug positionDebug = { + .valid = true, + .latitudeDegrees = kMockLatitudeDegrees, + .longitudeDegrees = kMockLongitudeDegrees, + .altitudeMeters = kMockAltitudeMeters, + .speedMetersPerSec = kMockSpeedMetersPerSec, + .bearingDegrees = kMockBearingDegrees, + .horizontalAccuracyMeters = kMockHorizontalAccuracyMeters, + .verticalAccuracyMeters = kMockVerticalAccuracyMeters, + .speedAccuracyMetersPerSecond = kMockSpeedAccuracyMetersPerSecond, + .bearingAccuracyDegrees = kMockBearingAccuracyDegrees, + .ageSeconds = 0.99}; + + TimeDebug timeDebug = {.timeEstimate = kMockTimestamp, + .timeUncertaintyNs = 1000, + .frequencyUncertaintyNsPerSec = 5.0e4}; + + DebugData data = {.position = positionDebug, .time = timeDebug}; + + _hidl_cb(data); + + return Void(); +} + +} // namespace implementation +} // namespace V1_1 +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/2.1/default/GnssDebug.h b/gnss/2.1/default/GnssDebug.h new file mode 100644 index 0000000000..969d337524 --- /dev/null +++ b/gnss/2.1/default/GnssDebug.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 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_gnss_V1_1_GnssDebug_H_ +#define android_hardware_gnss_V1_1_GnssDebug_H_ + +#include +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_1 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using V1_0::IGnssDebug; + +/* Interface for GNSS Debug support. */ +struct GnssDebug : public IGnssDebug { + /* + * Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow. + * These declarations were generated from IGnssDebug.hal. + */ + Return getDebugData(V1_0::IGnssDebug::getDebugData_cb _hidl_cb) override; +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_V1_1_GnssDebug_H_ From 16e8c9cc02673d58abaa3011f6708083c43d0489 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Thu, 2 Jan 2020 17:49:03 +0000 Subject: [PATCH 0389/1022] Add quant8 signed generated tests Fixes ValidateModel test for AXIS_ALIGNED_BBOX_TRANSFORM. Bug: 136735770 Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: Ie2959ba7258d8106d5b3dd36970181519b75e3b3 --- neuralnetworks/1.3/vts/functional/ValidateModel.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 65880b7cef..14ab897c8c 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -330,6 +330,8 @@ static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, con // - DEPTHWISE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL // - GROUPED_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL // - TRANSPOSE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL + // - AXIS_ALIGNED_BBOX_TRANSFORM bounding boxes (arg 1) can be of + // TENSOR_QUANT8_ASYMM or TENSOR_QUANT8_ASYMM_SIGNED. switch (operation.type) { case OperationType::LSH_PROJECTION: { if (operand == operation.inputs[1]) { @@ -385,6 +387,13 @@ static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, con return true; } } break; + case OperationType::AXIS_ALIGNED_BBOX_TRANSFORM: { + if (operand == operation.inputs[1] && + (type == OperandType::TENSOR_QUANT8_ASYMM || + type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED)) { + return true; + } + } break; default: break; } From 56c9b377957ebeb4ac3d625efe06d95e68af5afe Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Wed, 9 Oct 2019 14:04:31 -0700 Subject: [PATCH 0390/1022] Prerequsite changes for EVS multi-camera support This change modifies existing methods and data types for upcoming EVS multi-camera support. - deliverFrame_1_1() and doneWithFrame_1_1() are modified to take multiple buffer descriptors. - setIntParameter() and getIntParameter() are changed to return multiple parameter values. - Device ID and timestamp fields are added to BufferDesc. - EvsEvent is renamed as EvsEventDesc and Device Id is added. Bug: 142275664 Test: VtsHalEvsV1_1TargetTest Change-Id: I0415b2cb0642d1377f4d23a4e154080a66c81187 Signed-off-by: Changyeon Jo --- automotive/evs/1.1/IEvsCamera.hal | 26 +- automotive/evs/1.1/IEvsCameraStream.hal | 15 +- automotive/evs/1.1/default/Android.bp | 2 +- automotive/evs/1.1/default/ConfigManager.cpp | 179 ++++---- automotive/evs/1.1/default/ConfigManager.h | 56 +-- .../evs/1.1/default/ConfigManagerUtil.cpp | 24 + .../evs/1.1/default/ConfigManagerUtil.h | 8 + automotive/evs/1.1/default/EvsCamera.cpp | 18 +- automotive/evs/1.1/default/EvsCamera.h | 2 +- .../resources/evs_default_configuration.xml | 25 +- automotive/evs/1.1/types.hal | 14 +- .../evs/1.1/vts/functional/FrameHandler.cpp | 119 ++--- .../evs/1.1/vts/functional/FrameHandler.h | 19 +- .../functional/VtsHalEvsV1_1TargetTest.cpp | 415 ++++++++++++------ 14 files changed, 594 insertions(+), 328 deletions(-) diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal index 975b6c6cae..acc2eec257 100644 --- a/automotive/evs/1.1/IEvsCamera.hal +++ b/automotive/evs/1.1/IEvsCamera.hal @@ -51,7 +51,7 @@ interface IEvsCamera extends @1.0::IEvsCamera { resumeVideoStream() generates (EvsResult result); /** - * Returns a frame that was delivered by to the IEvsCameraStream. + * Returns frame that were delivered by to the IEvsCameraStream. * * When done consuming a frame delivered to the IEvsCameraStream * interface, it must be returned to the IEvsCamera for reuse. @@ -59,10 +59,10 @@ interface IEvsCamera extends @1.0::IEvsCamera { * as one), and if the supply is exhausted, no further frames may be * delivered until a buffer is returned. * - * @param buffer A buffer to be returned. + * @param buffer Buffers to be returned. * @return result Return EvsResult::OK if this call is successful. */ - doneWithFrame_1_1(BufferDesc buffer) generates (EvsResult result); + doneWithFrame_1_1(vec buffer) generates (EvsResult result); /** * Requests to be a master client. @@ -127,8 +127,13 @@ interface IEvsCamera extends @1.0::IEvsCamera { generates (int32_t min, int32_t max, int32_t step); /** - * Requests to set a camera parameter. Only a request from the master - * client will be processed successfully. + * Requests to set a camera parameter. + * + * Only a request from the master client will be processed successfully. + * When this method is called on a logical camera device, it will be forwarded + * to each physical device and, if it fails to program any physical device, + * it will return an error code with the same number of effective values as + * the number of backing camera devices. * * @param id The identifier of camera parameter, CameraParam enum. * value A desired parameter value. @@ -138,21 +143,22 @@ interface IEvsCamera extends @1.0::IEvsCamera { * parameter is not supported. * EvsResult::UNDERLYING_SERVICE_ERROR if it fails to * program a value by any other reason. - * effectiveValue A programmed parameter value. This may differ + * effectiveValue Programmed parameter values. This may differ * from what the client gives if, for example, the * driver does not support a target parameter. */ setIntParameter(CameraParam id, int32_t value) - generates (EvsResult result, int32_t effectiveValue); + generates (EvsResult result, vec effectiveValue); /** - * Retrieves a value of given camera parameter. + * Retrieves values of given camera parameter. * * @param id The identifier of camera parameter, CameraParam enum. * @return result EvsResult::OK if it succeeds to read a parameter. * EvsResult::INVALID_ARG if either a requested parameter is * not supported. - * value A value of requested camera parameter. + * value Values of requested camera parameter, the same number of + * values as backing camera devices. */ - getIntParameter(CameraParam id) generates(EvsResult result, int32_t value); + getIntParameter(CameraParam id) generates(EvsResult result, vec value); }; diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal index 9e4ea19f1d..aa35c62f45 100644 --- a/automotive/evs/1.1/IEvsCameraStream.hal +++ b/automotive/evs/1.1/IEvsCameraStream.hal @@ -18,7 +18,7 @@ package android.hardware.automotive.evs@1.1; import @1.0::IEvsCameraStream; import @1.1::BufferDesc; -import @1.1::EvsEvent; +import @1.1::EvsEventDesc; /** * Implemented on client side to receive asynchronous streaming event deliveries. @@ -26,7 +26,7 @@ import @1.1::EvsEvent; interface IEvsCameraStream extends @1.0::IEvsCameraStream { /** - * Receives calls from the HAL each time a video frame is ready for inspection. + * Receives calls from the HAL each time video frames is ready for inspection. * Buffer handles received by this method must be returned via calls to * IEvsCamera::doneWithFrame_1_1(). When the video stream is stopped via a call * to IEvsCamera::stopVideoStream(), this callback may continue to happen for @@ -35,14 +35,19 @@ interface IEvsCameraStream extends @1.0::IEvsCameraStream { * event must be delivered. No further frame deliveries may happen * thereafter. * - * @param buffer a buffer descriptor of a delivered image frame. + * A camera device will deliver the same number of frames as number of + * backing physical camera devices; it means, a physical camera device + * sends always a single frame and a logical camera device sends multiple + * frames as many as number of backing physical camera devices. + * + * @param buffer Buffer descriptors of delivered image frames. */ - oneway deliverFrame_1_1(BufferDesc buffer); + oneway deliverFrame_1_1(vec buffer); /** * Receives calls from the HAL each time an event happens. * * @param event EVS event with possible event information. */ - oneway notify(EvsEvent event); + oneway notify(EvsEventDesc event); }; diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp index 41cb4265e5..88fd6575ad 100644 --- a/automotive/evs/1.1/default/Android.bp +++ b/automotive/evs/1.1/default/Android.bp @@ -16,7 +16,7 @@ cc_binary { shared_libs: [ "android.hardware.automotive.evs@1.0", "android.hardware.automotive.evs@1.1", - "android.hardware.camera.device@3.2", + "android.hardware.camera.device@3.3", "libbase", "libbinder", "liblog", diff --git a/automotive/evs/1.1/default/ConfigManager.cpp b/automotive/evs/1.1/default/ConfigManager.cpp index 96a2f98576..986793e8a8 100644 --- a/automotive/evs/1.1/default/ConfigManager.cpp +++ b/automotive/evs/1.1/default/ConfigManager.cpp @@ -42,55 +42,32 @@ void ConfigManager::readCameraInfo(const XMLElement * const aCameraElem) { while (curElem != nullptr) { if (!strcmp(curElem->Name(), "group")) { /* camera group identifier */ - const char *group_id = curElem->FindAttribute("group_id")->Value(); + const char *id = curElem->FindAttribute("id")->Value(); - /* create CameraGroup */ - unique_ptr aCameraGroup(new ConfigManager::CameraGroup()); + /* create a camera group to be filled */ + CameraGroupInfo *aCamera = new CameraGroupInfo(); - /* add a camera device to its group */ - addCameraDevices(curElem->FindAttribute("device_id")->Value(), aCameraGroup); - - /* a list of camera stream configurations */ - const XMLElement *childElem = - curElem->FirstChildElement("caps")->FirstChildElement("stream"); - while (childElem != nullptr) { - /* read 5 attributes */ - const XMLAttribute *idAttr = childElem->FindAttribute("id"); - const XMLAttribute *widthAttr = childElem->FindAttribute("width"); - const XMLAttribute *heightAttr = childElem->FindAttribute("height"); - const XMLAttribute *fmtAttr = childElem->FindAttribute("format"); - const XMLAttribute *fpsAttr = childElem->FindAttribute("framerate"); - - const int32_t id = stoi(idAttr->Value()); - int32_t framerate = 0; - if (fpsAttr != nullptr) { - framerate = stoi(fpsAttr->Value()); - } - - int32_t pixFormat; - if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), - pixFormat)) { - RawStreamConfiguration cfg = { - id, - stoi(widthAttr->Value()), - stoi(heightAttr->Value()), - pixFormat, - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, - framerate - }; - aCameraGroup->streamConfigurations[id] = cfg; - } - - childElem = childElem->NextSiblingElement("stream"); + /* read camera device information */ + if (!readCameraDeviceInfo(aCamera, curElem)) { + ALOGW("Failed to read a camera information of %s", id); + delete aCamera; + continue; } /* camera group synchronization */ const char *sync = curElem->FindAttribute("synchronized")->Value(); - aCameraGroup->synchronized = - static_cast(strcmp(sync, "false")); + if (!strcmp(sync, "CALIBRATED")) { + aCamera->synchronized = + ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED; + } else if (!strcmp(sync, "APPROXIMATE")) { + aCamera->synchronized = + ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE; + } else { + aCamera->synchronized = 0; // Not synchronized + } /* add a group to hash map */ - mCameraGroups[group_id] = std::move(aCameraGroup); + mCameraGroupInfos.insert_or_assign(id, unique_ptr(aCamera)); } else if (!strcmp(curElem->Name(), "device")) { /* camera unique identifier */ const char *id = curElem->FindAttribute("id")->Value(); @@ -98,8 +75,18 @@ void ConfigManager::readCameraInfo(const XMLElement * const aCameraElem) { /* camera mount location */ const char *pos = curElem->FindAttribute("position")->Value(); + /* create a camera device to be filled */ + CameraInfo *aCamera = new CameraInfo(); + + /* read camera device information */ + if (!readCameraDeviceInfo(aCamera, curElem)) { + ALOGW("Failed to read a camera information of %s", id); + delete aCamera; + continue; + } + /* store read camera module information */ - mCameraInfo[id] = readCameraDeviceInfo(curElem); + mCameraInfo.insert_or_assign(id, unique_ptr(aCamera)); /* assign a camera device to a position group */ mCameraPosition[pos].emplace(id); @@ -113,15 +100,13 @@ void ConfigManager::readCameraInfo(const XMLElement * const aCameraElem) { } -unique_ptr -ConfigManager::readCameraDeviceInfo(const XMLElement *aDeviceElem) { - if (aDeviceElem == nullptr) { - return nullptr; +bool +ConfigManager::readCameraDeviceInfo(CameraInfo *aCamera, + const XMLElement *aDeviceElem) { + if (aCamera == nullptr || aDeviceElem == nullptr) { + return false; } - /* create a CameraInfo to be filled */ - unique_ptr aCamera(new ConfigManager::CameraInfo()); - /* size information to allocate camera_metadata_t */ size_t totalEntries = 0; size_t totalDataSize = 0; @@ -145,14 +130,15 @@ ConfigManager::readCameraDeviceInfo(const XMLElement *aDeviceElem) { "allocated memory was not large enough"); } - return aCamera; + return true; } -size_t ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem, - unique_ptr &aCamera, - size_t &dataSize) { - if (aCapElem == nullptr) { +size_t +ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem, + CameraInfo *aCamera, + size_t &dataSize) { + if (aCapElem == nullptr || aCamera == nullptr) { return 0; } @@ -214,7 +200,7 @@ size_t ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, framerate }; - aCamera->streamConfigurations[id] = cfg; + aCamera->streamConfigurations.insert_or_assign(id, cfg); } curElem = curElem->NextSiblingElement("stream"); @@ -232,10 +218,11 @@ size_t ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem, } -size_t ConfigManager::readCameraMetadata(const XMLElement * const aParamElem, - unique_ptr &aCamera, - size_t &dataSize) { - if (aParamElem == nullptr) { +size_t +ConfigManager::readCameraMetadata(const XMLElement * const aParamElem, + CameraInfo *aCamera, + size_t &dataSize) { + if (aParamElem == nullptr || aCamera == nullptr) { return 0; } @@ -258,8 +245,9 @@ size_t ConfigManager::readCameraMetadata(const XMLElement * const aParamElem, count ); - aCamera->cameraMetadata[tag] = - make_pair(make_unique(data), count); + aCamera->cameraMetadata.insert_or_assign( + tag, make_pair(make_unique(data), count) + ); ++numEntries; dataSize += calculate_camera_metadata_entry_data_size( @@ -269,6 +257,52 @@ size_t ConfigManager::readCameraMetadata(const XMLElement * const aParamElem, break; } + case ANDROID_REQUEST_AVAILABLE_CAPABILITIES: { + camera_metadata_enum_android_request_available_capabilities_t *data = + new camera_metadata_enum_android_request_available_capabilities_t[1]; + if (ConfigManagerUtil::convertToCameraCapability( + curElem->FindAttribute("value")->Value(), *data)) { + curElem->FindAttribute("value")->Value(), + aCamera->cameraMetadata.insert_or_assign( + tag, make_pair(make_unique(data), 1) + ); + + ++numEntries; + dataSize += calculate_camera_metadata_entry_data_size( + get_camera_metadata_tag_type(tag), 1 + ); + } + break; + } + + case ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS: { + /* a comma-separated list of physical camera devices */ + size_t len = strlen(curElem->FindAttribute("value")->Value()); + char *data = new char[len + 1]; + memcpy(data, + curElem->FindAttribute("value")->Value(), + len * sizeof(char)); + + /* replace commas with null char */ + char *p = data; + while (*p != '\0') { + if (*p == ',') { + *p = '\0'; + } + ++p; + } + + aCamera->cameraMetadata.insert_or_assign( + tag, make_pair(make_unique(data), len) + ); + + ++numEntries; + dataSize += calculate_camera_metadata_entry_data_size( + get_camera_metadata_tag_type(tag), len + ); + break; + } + default: ALOGW("Parameter %s is not supported", curElem->FindAttribute("name")->Value()); @@ -283,10 +317,11 @@ size_t ConfigManager::readCameraMetadata(const XMLElement * const aParamElem, } -bool ConfigManager::constructCameraMetadata(unique_ptr &aCamera, - const size_t totalEntries, - const size_t totalDataSize) { - if (!aCamera->allocate(totalEntries, totalDataSize)) { +bool +ConfigManager::constructCameraMetadata(CameraInfo *aCamera, + const size_t totalEntries, + const size_t totalDataSize) { + if (aCamera == nullptr || !aCamera->allocate(totalEntries, totalDataSize)) { ALOGE("Failed to allocate memory for camera metadata"); return false; } @@ -401,14 +436,14 @@ void ConfigManager::readDisplayInfo(const XMLElement * const aDisplayElem) { ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT, 0 // unused }; - dpy->streamConfigurations[id] = cfg; + dpy->streamConfigurations.insert_or_assign(id, cfg); } curStream = curStream->NextSiblingElement("stream"); } } - mDisplayInfo[id] = std::move(dpy); + mDisplayInfo.insert_or_assign(id, std::move(dpy)); curDev = curDev->NextSiblingElement("device"); } @@ -457,16 +492,6 @@ bool ConfigManager::readConfigDataFromXML() noexcept { } -void ConfigManager::addCameraDevices(const char *devices, - unique_ptr &aGroup) { - stringstream device_list(devices); - string token; - while (getline(device_list, token, ',')) { - aGroup->devices.emplace(token); - } -} - - std::unique_ptr ConfigManager::Create(const char *path) { unique_ptr cfgMgr(new ConfigManager(path)); diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h index 0275f904e5..870af1caa9 100644 --- a/automotive/evs/1.1/default/ConfigManager.h +++ b/automotive/evs/1.1/default/ConfigManager.h @@ -82,9 +82,6 @@ public: unordered_map> controls; - /* List of supported frame rates */ - unordered_set frameRates; - /* * List of supported output stream configurations; each array stores * format, width, height, and direction values in the order. @@ -102,21 +99,15 @@ public: camera_metadata_t *characteristics; }; - class CameraGroup { + class CameraGroupInfo : public CameraInfo { public: - CameraGroup() {} + CameraGroupInfo() {} /* ID of member camera devices */ unordered_set devices; /* The capture operation of member camera devices are synchronized */ bool synchronized = false; - - /* - * List of stream configurations that are supposed by all camera devices - * in this group. - */ - unordered_map streamConfigurations; }; class SystemInfo { @@ -165,11 +156,11 @@ public: /* * Return a list of cameras * - * @return CameraGroup + * @return CameraGroupInfo * A pointer to a camera group identified by a given id. */ - unique_ptr& getCameraGroup(const string& gid) { - return mCameraGroups[gid]; + unique_ptr& getCameraGroupInfo(const string& gid) { + return mCameraGroupInfos[gid]; } @@ -203,8 +194,8 @@ private: /* Internal data structure for camera device information */ unordered_map> mDisplayInfo; - /* Camera groups are stored in hash map */ - unordered_map> mCameraGroups; + /* Camera groups are stored in hash map */ + unordered_map> mCameraGroupInfos; /* * Camera positions are stored in hash map. @@ -253,16 +244,19 @@ private: /* * read camera device information * - * @param aDeviceElem + * @param aCamera + * A pointer to CameraInfo that will be completed by this + * method. + * aDeviceElem * A pointer to "device" XML element that contains camera module * capability info and its characteristics. * - * @return unique_ptr - * A pointer to CameraInfo class that contains camera module - * capability and characteristics. Please note that this transfers - * the ownership of created CameraInfo to the caller. + * @return bool + * Return false upon any failure in reading and processing camera + * device information. */ - unique_ptr readCameraDeviceInfo(const XMLElement *aDeviceElem); + bool readCameraDeviceInfo(CameraInfo *aCamera, + const XMLElement *aDeviceElem); /* * read camera metadata @@ -280,7 +274,7 @@ private: * Number of camera metadata entries */ size_t readCameraCapabilities(const XMLElement * const aCapElem, - unique_ptr &aCamera, + CameraInfo *aCamera, size_t &dataSize); /* @@ -298,7 +292,7 @@ private: * Number of camera metadata entries */ size_t readCameraMetadata(const XMLElement * const aParamElem, - unique_ptr &aCamera, + CameraInfo *aCamera, size_t &dataSize); /* @@ -316,21 +310,9 @@ private: * or its size is not large enough to add all found camera metadata * entries. */ - bool constructCameraMetadata(unique_ptr &aCamera, + bool constructCameraMetadata(CameraInfo *aCamera, const size_t totalEntries, const size_t totalDataSize); - - /* - * parse a comma-separated list of camera devices and add them to - * CameraGroup. - * - * @param devices - * A comma-separated list of camera device identifiers. - * @param aGroup - * Camera group which cameras will be added to. - */ - void addCameraDevices(const char *devices, - unique_ptr &aGroup); }; #endif // CONFIG_MANAGER_H diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.cpp b/automotive/evs/1.1/default/ConfigManagerUtil.cpp index 8206daa6d7..d10f236bd4 100644 --- a/automotive/evs/1.1/default/ConfigManagerUtil.cpp +++ b/automotive/evs/1.1/default/ConfigManagerUtil.cpp @@ -90,6 +90,30 @@ bool ConfigManagerUtil::convertToMetadataTag(const char *name, aTag = ANDROID_LENS_POSE_ROTATION; } else if (!strcmp(name, "LENS_POSE_TRANSLATION")) { aTag = ANDROID_LENS_POSE_TRANSLATION; + } else if (!strcmp(name, "REQUEST_AVAILABLE_CAPABILITIES")) { + aTag = ANDROID_REQUEST_AVAILABLE_CAPABILITIES; + } else if (!strcmp(name, "LOGICAL_MULTI_CAMERA_PHYSICAL_IDS")) { + aTag = ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS; + } else { + return false; + } + + return true; +} + + +bool ConfigManagerUtil::convertToCameraCapability( + const char *name, + camera_metadata_enum_android_request_available_capabilities_t &cap) { + + if (!strcmp(name, "DEPTH_OUTPUT")) { + cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT; + } else if (!strcmp(name, "LOGICAL_MULTI_CAMERA")) { + cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA; + } else if (!strcmp(name, "MONOCHROME")) { + cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME; + } else if (!strcmp(name, "SECURE_IMAGE_DATA")) { + cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA; } else { return false; } diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.h b/automotive/evs/1.1/default/ConfigManagerUtil.h index 8c89ae7745..1710cac4f2 100644 --- a/automotive/evs/1.1/default/ConfigManagerUtil.h +++ b/automotive/evs/1.1/default/ConfigManagerUtil.h @@ -55,6 +55,14 @@ public: */ static string trimString(const string &src, const string &ws = " \n\r\t\f\v"); + + /** + * Convert a given string to corresponding camera capabilities + */ + static bool convertToCameraCapability( + const char *name, + camera_metadata_enum_android_request_available_capabilities_t &cap); + }; #endif // CONFIG_MANAGER_UTIL_H diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp index 5ba753da2e..e200b53539 100644 --- a/automotive/evs/1.1/default/EvsCamera.cpp +++ b/automotive/evs/1.1/default/EvsCamera.cpp @@ -21,7 +21,7 @@ #include #include - +#include namespace android { namespace hardware { @@ -240,9 +240,12 @@ Return EvsCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) { } -Return EvsCamera::doneWithFrame_1_1(const BufferDesc_1_1& bufDesc) { +Return EvsCamera::doneWithFrame_1_1(const hidl_vec& buffers) { std::lock_guard lock(mAccessLock); - returnBuffer(bufDesc.bufferId, bufDesc.buffer.nativeHandle); + + for (auto&& buffer : buffers) { + returnBuffer(buffer.bufferId, buffer.buffer.nativeHandle); + } return EvsResult::OK; } @@ -490,12 +493,17 @@ void EvsCamera::generateFrames() { newBuffer.buffer.nativeHandle = mBuffers[idx].handle; newBuffer.pixelSize = sizeof(uint32_t); newBuffer.bufferId = idx; + newBuffer.deviceId = mDescription.v1.cameraId; + newBuffer.timestamp = elapsedRealtimeNano(); // Write test data into the image buffer fillTestFrame(newBuffer); // Issue the (asynchronous) callback to the client -- can't be holding the lock - auto result = mStream->deliverFrame_1_1(newBuffer); + hidl_vec frames; + frames.resize(1); + frames[0] = newBuffer; + auto result = mStream->deliverFrame_1_1(frames); if (result.isOk()) { ALOGD("Delivered %p as id %d", newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId); @@ -527,7 +535,7 @@ void EvsCamera::generateFrames() { } // If we've been asked to stop, send an event to signal the actual end of stream - EvsEvent event; + EvsEventDesc event; event.aType = EvsEventType::STREAM_STOPPED; auto result = mStream->notify(event); if (!result.isOk()) { diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h index c15b4b117b..a32fa75ec3 100644 --- a/automotive/evs/1.1/default/EvsCamera.h +++ b/automotive/evs/1.1/default/EvsCamera.h @@ -64,7 +64,7 @@ public: Return getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) override; Return pauseVideoStream() override; Return resumeVideoStream() override; - Return doneWithFrame_1_1(const BufferDesc_1_1& buffer) override; + Return doneWithFrame_1_1(const hidl_vec& buffer) override; Return setMaster() override; Return forceMaster(const sp& display) override; Return unsetMaster() override; diff --git a/automotive/evs/1.1/default/resources/evs_default_configuration.xml b/automotive/evs/1.1/default/resources/evs_default_configuration.xml index 692102ed38..a79e7c2b2d 100644 --- a/automotive/evs/1.1/default/resources/evs_default_configuration.xml +++ b/automotive/evs/1.1/default/resources/evs_default_configuration.xml @@ -28,8 +28,31 @@ - + + + + + + + + + + + + + + diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal index dcb2abb0e9..f88d2232b7 100644 --- a/automotive/evs/1.1/types.hal +++ b/automotive/evs/1.1/types.hal @@ -61,6 +61,14 @@ struct BufferDesc { * Opaque value from driver */ uint32_t bufferId; + /** + * Unique identifier of the physical camera device that produces this buffer. + */ + string deviceId; + /** + * Time that this buffer is being filled. + */ + int64_t timestamp; }; /** @@ -97,11 +105,15 @@ enum EvsEventType : uint32_t { /** * Structure that describes informative events occurred during EVS is streaming */ -struct EvsEvent { +struct EvsEventDesc { /** * Type of an informative event */ EvsEventType aType; + /** + * Device identifier + */ + string deviceId; /** * Possible additional information */ diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp index 6d53652f86..38c709fcd0 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp +++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp @@ -80,7 +80,7 @@ void FrameHandler::blockingStopStream() { asyncStopStream(); // Wait until the stream has actually stopped - std::unique_lock lock(mLock); + std::unique_lock lock(mEventLock); if (mRunning) { mEventSignal.wait(lock, [this]() { return !mRunning; }); } @@ -96,9 +96,9 @@ bool FrameHandler::returnHeldBuffer() { return false; } - BufferDesc_1_1 buffer = mHeldBuffers.front(); + hidl_vec buffers = mHeldBuffers.front(); mHeldBuffers.pop(); - mCamera->doneWithFrame_1_1(buffer); + mCamera->doneWithFrame_1_1(buffers); return true; } @@ -138,50 +138,52 @@ Return FrameHandler::deliverFrame(const BufferDesc_1_0& bufferArg) { } -Return FrameHandler::deliverFrame_1_1(const BufferDesc_1_1& bufDesc) { - const AHardwareBuffer_Desc* pDesc = - reinterpret_cast(&bufDesc.buffer.description); - ALOGD("Received a frame from the camera (%p)", - bufDesc.buffer.nativeHandle.getNativeHandle()); +Return FrameHandler::deliverFrame_1_1(const hidl_vec& buffers) { + for (auto&& buffer : buffers) { + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&buffer.buffer.description); + ALOGD("Received a frame from the camera (%p)", + buffer.buffer.nativeHandle.getNativeHandle()); - // Store a dimension of a received frame. - mFrameWidth = pDesc->width; - mFrameHeight = pDesc->height; + // Store a dimension of a received frame. + mFrameWidth = pDesc->width; + mFrameHeight = pDesc->height; - // If we were given an opened display at construction time, then send the received - // image back down the camera. - if (mDisplay.get()) { - // Get the output buffer we'll use to display the imagery - BufferDesc_1_0 tgtBuffer = {}; - mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) { - tgtBuffer = buff; - } - ); + // If we were given an opened display at construction time, then send the received + // image back down the camera. + if (mDisplay.get()) { + // Get the output buffer we'll use to display the imagery + BufferDesc_1_0 tgtBuffer = {}; + mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) { + tgtBuffer = buff; + } + ); - if (tgtBuffer.memHandle == nullptr) { - printf("Didn't get target buffer - frame lost\n"); - ALOGE("Didn't get requested output buffer -- skipping this frame."); - } else { - // Copy the contents of the of buffer.memHandle into tgtBuffer - copyBufferContents(tgtBuffer, bufDesc); - - // Send the target buffer back for display - Return result = mDisplay->returnTargetBufferForDisplay(tgtBuffer); - if (!result.isOk()) { - printf("HIDL error on display buffer (%s)- frame lost\n", - result.description().c_str()); - ALOGE("Error making the remote function call. HIDL said %s", - result.description().c_str()); - } else if (result != EvsResult::OK) { - printf("Display reported error - frame lost\n"); - ALOGE("We encountered error %d when returning a buffer to the display!", - (EvsResult) result); + if (tgtBuffer.memHandle == nullptr) { + printf("Didn't get target buffer - frame lost\n"); + ALOGE("Didn't get requested output buffer -- skipping this frame."); } else { - // Everything looks good! - // Keep track so tests or watch dogs can monitor progress - mLock.lock(); - mFramesDisplayed++; - mLock.unlock(); + // Copy the contents of the of buffer.memHandle into tgtBuffer + copyBufferContents(tgtBuffer, buffer); + + // Send the target buffer back for display + Return result = mDisplay->returnTargetBufferForDisplay(tgtBuffer); + if (!result.isOk()) { + printf("HIDL error on display buffer (%s)- frame lost\n", + result.description().c_str()); + ALOGE("Error making the remote function call. HIDL said %s", + result.description().c_str()); + } else if (result != EvsResult::OK) { + printf("Display reported error - frame lost\n"); + ALOGE("We encountered error %d when returning a buffer to the display!", + (EvsResult) result); + } else { + // Everything looks good! + // Keep track so tests or watch dogs can monitor progress + mLock.lock(); + mFramesDisplayed++; + mLock.unlock(); + } } } } @@ -191,11 +193,11 @@ Return FrameHandler::deliverFrame_1_1(const BufferDesc_1_1& bufDesc) { case eAutoReturn: // Send the camera buffer back now that the client has seen it ALOGD("Calling doneWithFrame"); - mCamera->doneWithFrame_1_1(bufDesc); + mCamera->doneWithFrame_1_1(buffers); break; case eNoAutoReturn: - // Hang onto the buffer handle for now -- the client will return it explicitly later - mHeldBuffers.push(bufDesc); + // Hang onto the buffer handles for now -- the client will return it explicitly later + mHeldBuffers.push(buffers); } mLock.lock(); @@ -209,7 +211,7 @@ Return FrameHandler::deliverFrame_1_1(const BufferDesc_1_1& bufDesc) { } -Return FrameHandler::notify(const EvsEvent& event) { +Return FrameHandler::notify(const EvsEventDesc& event) { // Local flag we use to keep track of when the stream is stopping mLock.lock(); mLatestEventDesc = event; @@ -223,7 +225,7 @@ Return FrameHandler::notify(const EvsEvent& event) { ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType)); } mLock.unlock(); - mEventSignal.notify_all(); + mEventSignal.notify_one(); return Void(); } @@ -342,19 +344,20 @@ void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) { } } -bool FrameHandler::waitForEvent(const EvsEventType aTargetEvent, - EvsEvent &event) { +bool FrameHandler::waitForEvent(const EvsEventDesc& aTargetEvent, + EvsEventDesc& aReceivedEvent) { // Wait until we get an expected parameter change event. - std::unique_lock lock(mLock); + std::unique_lock lock(mEventLock); auto now = std::chrono::system_clock::now(); bool result = mEventSignal.wait_until(lock, now + 5s, - [this, aTargetEvent, &event](){ - bool flag = mLatestEventDesc.aType == aTargetEvent; - if (flag) { - event.aType = mLatestEventDesc.aType; - event.payload[0] = mLatestEventDesc.payload[0]; - event.payload[1] = mLatestEventDesc.payload[1]; - } + [this, aTargetEvent, &aReceivedEvent](){ + bool flag = (mLatestEventDesc.aType == aTargetEvent.aType) && + (mLatestEventDesc.payload[0] == aTargetEvent.payload[0]) && + (mLatestEventDesc.payload[1] == aTargetEvent.payload[1]); + + aReceivedEvent.aType = mLatestEventDesc.aType; + aReceivedEvent.payload[0] = mLatestEventDesc.payload[0]; + aReceivedEvent.payload[1] = mLatestEventDesc.payload[1]; return flag; } diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h index e5f1b8f112..51e5a868e0 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.h +++ b/automotive/evs/1.1/vts/functional/FrameHandler.h @@ -73,8 +73,8 @@ public: bool isRunning(); void waitForFrameCount(unsigned frameCount); - bool waitForEvent(const EvsEventType aTargetEvent, - EvsEvent &eventDesc); + bool waitForEvent(const EvsEventDesc& aTargetEvent, + EvsEventDesc& aReceivedEvent); void getFramesCounters(unsigned* received, unsigned* displayed); void getFrameDimension(unsigned* width, unsigned* height); @@ -83,8 +83,8 @@ private: Return deliverFrame(const BufferDesc_1_0& buffer) override; // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream - Return deliverFrame_1_1(const BufferDesc_1_1& buffer) override; - Return notify(const EvsEvent& event) override; + Return deliverFrame_1_1(const hidl_vec& buffer) override; + Return notify(const EvsEventDesc& event) override; // Local implementation details bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer); @@ -99,17 +99,18 @@ private: // Since we get frames delivered to us asynchronously via the IEvsCameraStream interface, // we need to protect all member variables that may be modified while we're streaming // (ie: those below) - std::mutex mLock; - std::condition_variable mEventSignal; - std::condition_variable mFrameSignal; + std::mutex mLock; + std::mutex mEventLock; + std::condition_variable mEventSignal; + std::condition_variable mFrameSignal; + std::queue> mHeldBuffers; - std::queue mHeldBuffers; bool mRunning = false; unsigned mFramesReceived = 0; // Simple counter -- rolls over eventually! unsigned mFramesDisplayed = 0; // Simple counter -- rolls over eventually! unsigned mFrameWidth = 0; unsigned mFrameHeight = 0; - EvsEvent mLatestEventDesc; + EvsEventDesc mLatestEventDesc; }; diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index 1d3fd87356..8847a95e69 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -67,6 +67,7 @@ using ::android::hardware::hidl_vec; using ::android::hardware::hidl_handle; using ::android::hardware::hidl_string; using ::android::sp; +using ::android::wp; using ::android::hardware::camera::device::V3_2::Stream; using ::android::hardware::automotive::evs::V1_0::DisplayDesc; using ::android::hardware::automotive::evs::V1_0::DisplayState; @@ -117,7 +118,15 @@ public: mIsHwModule = !service_name.compare(kEnumeratorName); } - virtual void TearDown() override {} + virtual void TearDown() override { + // Attempt to close any active camera + for (auto &&c : activeCameras) { + sp cam = c.promote(); + if (cam != nullptr) { + pEnumerator->closeCamera(cam); + } + } + } protected: void loadCameraList() { @@ -141,10 +150,12 @@ protected: ASSERT_GE(cameraInfo.size(), 1u); } - sp pEnumerator; // Every test needs access to the service - std::vector cameraInfo; // Empty unless/until loadCameraList() is called - bool mIsHwModule; // boolean to tell current module under testing - // is HW module implementation. + sp pEnumerator; // Every test needs access to the service + std::vector cameraInfo; // Empty unless/until loadCameraList() is called + bool mIsHwModule; // boolean to tell current module under testing + // is HW module implementation. + std::deque> activeCameras; // A list of active camera handles that are + // needed to be cleaned up. }; @@ -169,11 +180,15 @@ TEST_F(EvsHidlTest, CameraOpenClean) { // Open and close each camera twice for (auto&& cam: cameraInfo) { for (int pass = 0; pass < 2; pass++) { + activeCameras.clear(); sp pCam = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); + // Store a camera handle for a clean-up + activeCameras.push_back(pCam); + // Verify that this camera self-identifies correctly pCam->getCameraInfo_1_1([&cam](CameraDesc desc) { ALOGD("Found camera %s", desc.v1.cameraId.c_str()); @@ -206,11 +221,15 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { // Open and close each camera twice for (auto&& cam: cameraInfo) { + activeCameras.clear(); sp pCam = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); + // Store a camera handle for a clean-up + activeCameras.push_back(pCam); + // Verify that this camera self-identifies correctly pCam->getCameraInfo_1_1([&cam](CameraDesc desc) { ALOGD("Found camera %s", desc.v1.cameraId.c_str()); @@ -221,9 +240,13 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { sp pCam2 = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); - ASSERT_NE(pCam, pCam2); ASSERT_NE(pCam2, nullptr); + // Store a camera handle for a clean-up + activeCameras.push_back(pCam2); + + ASSERT_NE(pCam, pCam2); + Return result = pCam->setMaxFramesInFlight(2); if (mIsHwModule) { // Verify that the old camera rejects calls via HW module. @@ -268,11 +291,15 @@ TEST_F(EvsHidlTest, CameraStreamPerformance) { // Test each reported camera for (auto&& cam: cameraInfo) { + activeCameras.clear(); sp pCam = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); + // Store a camera handle for a clean-up + activeCameras.push_back(pCam); + // Set up a frame receiver object which will fire up its own thread sp frameHandler = new FrameHandler(pCam, cam, nullptr, @@ -340,12 +367,15 @@ TEST_F(EvsHidlTest, CameraStreamBuffering) { // Test each reported camera for (auto&& cam: cameraInfo) { - + activeCameras.clear(); sp pCam = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); + // Store a camera handle for a clean-up + activeCameras.push_back(pCam); + // Ask for a crazy number of buffers in flight to ensure it errors correctly Return badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF); EXPECT_EQ(EvsResult::BUFFER_NOT_AVAILABLE, badResult); @@ -416,11 +446,15 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { // Test each reported camera for (auto&& cam: cameraInfo) { + activeCameras.clear(); sp pCam = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); + // Store a camera handle for a clean-up + activeCameras.push_back(pCam); + // Set up a frame receiver object which will fire up its own thread. sp frameHandler = new FrameHandler(pCam, cam, pDisplay, @@ -484,17 +518,24 @@ TEST_F(EvsHidlTest, MultiCameraStream) { // Test each reported camera for (auto&& cam: cameraInfo) { + activeCameras.clear(); // Create two camera clients. sp pCam0 = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam0, nullptr); + // Store a camera handle for a clean-up + activeCameras.push_back(pCam0); + sp pCam1 = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam1, nullptr); + // Store a camera handle for a clean-up + activeCameras.push_back(pCam1); + // Set up per-client frame receiver objects which will fire up its own thread sp frameHandler0 = new FrameHandler(pCam0, cam, nullptr, @@ -575,12 +616,16 @@ TEST_F(EvsHidlTest, CameraParameter) { // Test each reported camera Return result = EvsResult::OK; for (auto&& cam: cameraInfo) { + activeCameras.clear(); // Create a camera client sp pCam = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam, nullptr); + // Store a camera + activeCameras.push_back(pCam); + // Get the parameter list std::vector cmds; pCam->getParameterList([&cmds](hidl_vec cmdList) { @@ -626,48 +671,54 @@ TEST_F(EvsHidlTest, CameraParameter) { EvsResult result = EvsResult::OK; if (cmd == CameraParam::ABSOLUTE_FOCUS) { // Try to turn off auto-focus - int32_t val1 = 0; - pCam->getIntParameter(CameraParam::AUTO_FOCUS, - [&result, &val1](auto status, auto value) { + std::vector values; + pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &values](auto status, auto effectiveValues) { result = status; if (status == EvsResult::OK) { - val1 = value; + for (auto &&v : effectiveValues) { + values.push_back(v); + } } }); - if (val1 != 0) { - pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val1, 0); + ASSERT_EQ(EvsResult::OK, result); + for (auto &&v : values) { + ASSERT_EQ(v, 0); } } // Try to program a parameter with a random value [minVal, maxVal] int32_t val0 = minVal + (std::rand() % (maxVal - minVal)); - int32_t val1 = 0; + std::vector values; // Rounding down val0 = val0 - (val0 % step); pCam->setIntParameter(cmd, val0, - [&result, &val1](auto status, auto effectiveValue) { + [&result, &values](auto status, auto effectiveValues) { result = status; - val1 = effectiveValue; + if (status == EvsResult::OK) { + for (auto &&v : effectiveValues) { + values.push_back(v); + } + } }); ASSERT_EQ(EvsResult::OK, result); + values.clear(); pCam->getIntParameter(cmd, - [&result, &val1](auto status, auto value) { + [&result, &values](auto status, auto readValues) { result = status; if (status == EvsResult::OK) { - val1 = value; + for (auto &&v : readValues) { + values.push_back(v); + } } }); ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val0, val1) << "Values are not matched."; + for (auto &&v : values) { + ASSERT_EQ(val0, v) << "Values are not matched."; + } } result = pCam->unsetMaster(); @@ -704,16 +755,24 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { // Test each reported camera for (auto&& cam: cameraInfo) { + activeCameras.clear(); // Create two camera clients. sp pCamMaster = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCamMaster, nullptr); + + // Store a camera handle for a clean-up + activeCameras.push_back(pCamMaster); + sp pCamNonMaster = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCamNonMaster, nullptr); + // Store a camera handle for a clean-up + activeCameras.push_back(pCamNonMaster); + // Set up per-client frame receiver objects which will fire up its own thread sp frameHandlerMaster = new FrameHandler(pCamMaster, cam, @@ -750,13 +809,15 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { // Non-master client expects to receive a master role relesed // notification. - EvsEvent aNotification = {}; + EvsEventDesc aTargetEvent = {}; + EvsEventDesc aNotification = {}; // Release a master role. pCamMaster->unsetMaster(); // Verify a change notification. - frameHandlerNonMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); + aTargetEvent.aType = EvsEventType::MASTER_RELEASED; + frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification); ASSERT_EQ(EvsEventType::MASTER_RELEASED, static_cast(aNotification.aType)); @@ -772,7 +833,8 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { frameHandlerNonMaster->shutdown(); // Verify a change notification. - frameHandlerMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); + aTargetEvent.aType = EvsEventType::MASTER_RELEASED; + frameHandlerMaster->waitForEvent(aTargetEvent, aNotification); ASSERT_EQ(EvsEventType::MASTER_RELEASED, static_cast(aNotification.aType)); @@ -810,16 +872,24 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Test each reported camera for (auto&& cam: cameraInfo) { + activeCameras.clear(); // Create two camera clients. sp pCamMaster = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCamMaster, nullptr); + + // Store a camera handle for a clean-up + activeCameras.push_back(pCamMaster); + sp pCamNonMaster = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCamNonMaster, nullptr); + // Store a camera handle for a clean-up + activeCameras.push_back(pCamNonMaster); + // Get the parameter list std::vector camMasterCmds, camNonMasterCmds; pCamMaster->getParameterList([&camMasterCmds](hidl_vec cmdList) { @@ -879,7 +949,7 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { frameHandlerNonMaster->waitForFrameCount(1); int32_t val0 = 0; - int32_t val1 = 0; + std::vector values; for (auto &cmd : camMasterCmds) { // Get a valid parameter value range int32_t minVal, maxVal, step; @@ -895,14 +965,19 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { EvsResult result = EvsResult::OK; if (cmd == CameraParam::ABSOLUTE_FOCUS) { // Try to turn off auto-focus - int32_t val1 = 1; pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0, - [&result, &val1](auto status, auto effectiveValue) { + [&result, &values](auto status, auto effectiveValues) { result = status; - val1 = effectiveValue; + if (status == EvsResult::OK) { + for (auto &&v : effectiveValues) { + values.push_back(v); + } + } }); ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val1, 0); + for (auto &&v : values) { + ASSERT_EQ(v, 0); + } } // Try to program a parameter @@ -910,45 +985,63 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Rounding down val0 = val0 - (val0 % step); + values.clear(); pCamMaster->setIntParameter(cmd, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - - // Wait a moment - sleep(1); - - // Non-master client expects to receive a parameter change notification - // whenever a master client adjusts it. - EvsEvent aNotification = {}; - - pCamMaster->getIntParameter(cmd, - [&result, &val1](auto status, auto value) { + [&result, &values](auto status, auto effectiveValues) { result = status; if (status == EvsResult::OK) { - val1 = value; + for (auto &&v : effectiveValues) { + values.push_back(v); + } } }); ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val0, val1) << "Values are not matched."; + + // Non-master client expects to receive a parameter change notification + // whenever a master client adjusts it. + EvsEventDesc aTargetEvent = {}; + EvsEventDesc aNotification = {}; + + values.clear(); + pCamMaster->getIntParameter(cmd, + [&result, &values](auto status, auto readValues) { + result = status; + if (status == EvsResult::OK) { + for (auto &&v : readValues) { + values.push_back(v); + } + } + }); + ASSERT_EQ(EvsResult::OK, result); + for (auto &&v : values) { + ASSERT_EQ(val0, v) << "Values are not matched."; + } // Verify a change notification - frameHandlerNonMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); + aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; + aTargetEvent.payload[0] = static_cast(cmd); + aTargetEvent.payload[1] = static_cast(val0); + frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification); ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, static_cast(aNotification.aType)); ASSERT_EQ(cmd, static_cast(aNotification.payload[0])); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); + for (auto &&v : values) { + ASSERT_EQ(v, + static_cast(aNotification.payload[1])); + } } // Try to adjust a parameter via non-master client + values.clear(); pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0, - [&result, &val1](auto status, auto effectiveValue) { + [&result, &values](auto status, auto effectiveValues) { result = status; - val1 = effectiveValue; + if (status == EvsResult::OK) { + for (auto &&v : effectiveValues) { + values.push_back(v); + } + } }); ASSERT_EQ(EvsResult::INVALID_ARG, result); @@ -961,10 +1054,15 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { ASSERT_EQ(EvsResult::OK, result); // Try to adjust a parameter after being retired + values.clear(); pCamMaster->setIntParameter(camMasterCmds[0], val0, - [&result, &val1](auto status, auto effectiveValue) { + [&result, &values](auto status, auto effectiveValues) { result = status; - val1 = effectiveValue; + if (status == EvsResult::OK) { + for (auto &&v : effectiveValues) { + values.push_back(v); + } + } }); ASSERT_EQ(EvsResult::INVALID_ARG, result); @@ -986,16 +1084,22 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { ); EvsResult result = EvsResult::OK; + values.clear(); if (cmd == CameraParam::ABSOLUTE_FOCUS) { // Try to turn off auto-focus - int32_t val1 = 1; pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0, - [&result, &val1](auto status, auto effectiveValue) { + [&result, &values](auto status, auto effectiveValues) { result = status; - val1 = effectiveValue; + if (status == EvsResult::OK) { + for (auto &&v : effectiveValues) { + values.push_back(v); + } + } }); ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val1, 0); + for (auto &&v : values) { + ASSERT_EQ(v, 0); + } } // Try to program a parameter @@ -1003,38 +1107,51 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Rounding down val0 = val0 - (val0 % step); + values.clear(); pCamNonMaster->setIntParameter(cmd, val0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - - // Wait a moment - sleep(1); - - // Non-master client expects to receive a parameter change notification - // whenever a master client adjusts it. - EvsEvent aNotification = {}; - - pCamNonMaster->getIntParameter(cmd, - [&result, &val1](auto status, auto value) { + [&result, &values](auto status, auto effectiveValues) { result = status; if (status == EvsResult::OK) { - val1 = value; + for (auto &&v : effectiveValues) { + values.push_back(v); + } } }); ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val0, val1) << "Values are not matched."; + + // Non-master client expects to receive a parameter change notification + // whenever a master client adjusts it. + EvsEventDesc aTargetEvent = {}; + EvsEventDesc aNotification = {}; + + values.clear(); + pCamNonMaster->getIntParameter(cmd, + [&result, &values](auto status, auto readValues) { + result = status; + if (status == EvsResult::OK) { + for (auto &&v : readValues) { + values.push_back(v); + } + } + }); + ASSERT_EQ(EvsResult::OK, result); + for (auto &&v : values) { + ASSERT_EQ(val0, v) << "Values are not matched."; + } // Verify a change notification - frameHandlerMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); + aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; + aTargetEvent.payload[0] = static_cast(cmd); + aTargetEvent.payload[1] = static_cast(val0); + frameHandlerMaster->waitForEvent(aTargetEvent, aNotification); ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, static_cast(aNotification.aType)); ASSERT_EQ(cmd, static_cast(aNotification.payload[0])); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); + for (auto &&v : values) { + ASSERT_EQ(v, + static_cast(aNotification.payload[1])); + } } // New master retires from a master role @@ -1078,17 +1195,25 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { // Test each reported camera for (auto&& cam: cameraInfo) { + activeCameras.clear(); + // Create two clients sp pCam0 = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam0, nullptr); + // Store a camera handle for a clean-up + activeCameras.push_back(pCam0); + sp pCam1 = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); ASSERT_NE(pCam1, nullptr); + // Store a camera handle for a clean-up + activeCameras.push_back(pCam1); + // Get the parameter list; this test will use the first command in both // lists. std::vector cam0Cmds, cam1Cmds; @@ -1144,108 +1269,141 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { } ); + // Client1 becomes a master + result = pCam1->setMaster(); + ASSERT_EQ(EvsResult::OK, result); + + std::vector values; + EvsEventDesc aTargetEvent = {}; + EvsEventDesc aNotification = {}; if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) { // Try to turn off auto-focus - int32_t val1 = 0; - pCam1->getIntParameter(CameraParam::AUTO_FOCUS, - [&result, &val1](auto status, auto value) { + pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &values](auto status, auto effectiveValues) { result = status; if (status == EvsResult::OK) { - val1 = value; + for (auto &&v : effectiveValues) { + values.push_back(v); + } } }); - if (val1 != 0) { - pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val1, 0); + ASSERT_EQ(EvsResult::OK, result); + for (auto &&v : values) { + ASSERT_EQ(v, 0); } + + // Make sure AUTO_FOCUS is off. + aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; + aTargetEvent.payload[0] = static_cast(CameraParam::AUTO_FOCUS); + aTargetEvent.payload[1] = 0; + bool timeout = + frameHandler0->waitForEvent(aTargetEvent, aNotification); + ASSERT_FALSE(timeout) << "Expected event does not arrive"; } // Try to program a parameter with a random value [minVal, maxVal] int32_t val0 = minVal + (std::rand() % (maxVal - minVal)); - int32_t val1 = 0; // Rounding down val0 = val0 - (val0 % step); - - result = pCam1->setMaster(); - ASSERT_EQ(EvsResult::OK, result); - + values.clear(); pCam1->setIntParameter(cam1Cmds[0], val0, - [&result, &val1](auto status, auto effectiveValue) { + [&result, &values](auto status, auto effectiveValues) { result = status; - val1 = effectiveValue; + if (status == EvsResult::OK) { + for (auto &&v : effectiveValues) { + values.push_back(v); + } + } }); ASSERT_EQ(EvsResult::OK, result); + for (auto &&v : values) { + ASSERT_EQ(val0, v); + } // Verify a change notification - EvsEvent aNotification = {}; + aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; + aTargetEvent.payload[0] = static_cast(cam1Cmds[0]); + aTargetEvent.payload[1] = static_cast(val0); bool timeout = - frameHandler0->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); + frameHandler0->waitForEvent(aTargetEvent, aNotification); ASSERT_FALSE(timeout) << "Expected event does not arrive"; ASSERT_EQ(static_cast(aNotification.aType), EvsEventType::PARAMETER_CHANGED); ASSERT_EQ(static_cast(aNotification.payload[0]), cam1Cmds[0]); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); + for (auto &&v : values) { + ASSERT_EQ(v, static_cast(aNotification.payload[1])); + } // Client 0 steals a master role ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay)); - frameHandler1->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification); + aTargetEvent.aType = EvsEventType::MASTER_RELEASED; + aTargetEvent.payload[0] = 0; + aTargetEvent.payload[1] = 0; + frameHandler1->waitForEvent(aTargetEvent, aNotification); ASSERT_EQ(static_cast(aNotification.aType), EvsEventType::MASTER_RELEASED); // Client 0 programs a parameter val0 = minVal + (std::rand() % (maxVal - minVal)); - val1 = 0; // Rounding down val0 = val0 - (val0 % step); if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) { // Try to turn off auto-focus - int32_t val1 = 0; - pCam0->getIntParameter(CameraParam::AUTO_FOCUS, - [&result, &val1](auto status, auto value) { + values.clear(); + pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0, + [&result, &values](auto status, auto effectiveValues) { result = status; if (status == EvsResult::OK) { - val1 = value; + for (auto &&v : effectiveValues) { + values.push_back(v); + } } }); - if (val1 != 0) { - pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0, - [&result, &val1](auto status, auto effectiveValue) { - result = status; - val1 = effectiveValue; - }); - ASSERT_EQ(EvsResult::OK, result); - ASSERT_EQ(val1, 0); + ASSERT_EQ(EvsResult::OK, result); + for (auto &&v : values) { + ASSERT_EQ(v, 0); } + + // Make sure AUTO_FOCUS is off. + aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; + aTargetEvent.payload[0] = static_cast(CameraParam::AUTO_FOCUS); + aTargetEvent.payload[1] = 0; + bool timeout = + frameHandler1->waitForEvent(aTargetEvent, aNotification); + ASSERT_FALSE(timeout) << "Expected event does not arrive"; } + values.clear(); pCam0->setIntParameter(cam0Cmds[0], val0, - [&result, &val1](auto status, auto effectiveValue) { + [&result, &values](auto status, auto effectiveValues) { result = status; - val1 = effectiveValue; + if (status == EvsResult::OK) { + for (auto &&v : effectiveValues) { + values.push_back(v); + } + } }); ASSERT_EQ(EvsResult::OK, result); // Verify a change notification + aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; + aTargetEvent.payload[0] = static_cast(cam0Cmds[0]); + aTargetEvent.payload[1] = static_cast(val0); timeout = - frameHandler1->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification); + frameHandler1->waitForEvent(aTargetEvent, aNotification); ASSERT_FALSE(timeout) << "Expected event does not arrive"; ASSERT_EQ(static_cast(aNotification.aType), EvsEventType::PARAMETER_CHANGED); ASSERT_EQ(static_cast(aNotification.payload[0]), cam0Cmds[0]); - ASSERT_EQ(val1, - static_cast(aNotification.payload[1])); + for (auto &&v : values) { + ASSERT_EQ(v, static_cast(aNotification.payload[1])); + } // Turn off the display (yes, before the stream stops -- it should be handled) pDisplay->setDisplayState(DisplayState::NOT_VISIBLE); @@ -1282,6 +1440,7 @@ TEST_F(EvsHidlTest, CameraUseStreamConfigToDisplay) { // Test each reported camera for (auto&& cam: cameraInfo) { + activeCameras.clear(); // choose a configuration that has a frame rate faster than minReqFps. Stream targetCfg = {}; const int32_t minReqFps = 15; @@ -1324,6 +1483,9 @@ TEST_F(EvsHidlTest, CameraUseStreamConfigToDisplay) { .withDefault(nullptr); ASSERT_NE(pCam, nullptr); + // Store a camera handle for a clean-up + activeCameras.push_back(pCam); + // Set up a frame receiver object which will fire up its own thread. sp frameHandler = new FrameHandler(pCam, cam, pDisplay, @@ -1383,6 +1545,7 @@ TEST_F(EvsHidlTest, MultiCameraStreamUseConfig) { // Test each reported camera for (auto&& cam: cameraInfo) { + activeCameras.clear(); // choose a configuration that has a frame rate faster than minReqFps. Stream targetCfg = {}; const int32_t minReqFps = 15; @@ -1427,6 +1590,9 @@ TEST_F(EvsHidlTest, MultiCameraStreamUseConfig) { .withDefault(nullptr); ASSERT_NE(pCam0, nullptr); + // Store a camera handle for a clean-up + activeCameras.push_back(pCam0); + // Try to create the second camera client with different stream // configuration. int32_t id = targetCfg.id; @@ -1436,6 +1602,9 @@ TEST_F(EvsHidlTest, MultiCameraStreamUseConfig) { .withDefault(nullptr); ASSERT_EQ(pCam1, nullptr); + // Store a camera handle for a clean-up + activeCameras.push_back(pCam0); + // Try again with same stream configuration. targetCfg.id = id; pCam1 = From 3e80b3b5281dac0329e29802bd8a4e2a10b6f55c Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Mon, 25 Nov 2019 18:14:00 -0800 Subject: [PATCH 0391/1022] Fix EVS VTS test cases This change modifies logics to verify test results that need to parse events from EVS manager. Especially, test cases that run multiple camera clients spawn threads to listen EVS events. Also, this updates waitForEvent() method to return more precise results. Bug: 142275664 Test: VtsHalEvsV1_1Target Change-Id: Ic328217be1e49a3a862facf783a5356ac34ce9ed Signed-off-by: Changyeon Jo --- .../evs/1.1/vts/functional/FrameHandler.cpp | 46 +- .../evs/1.1/vts/functional/FrameHandler.h | 3 +- .../functional/VtsHalEvsV1_1TargetTest.cpp | 470 +++++++++++++++--- 3 files changed, 425 insertions(+), 94 deletions(-) diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp index 38c709fcd0..44783f65c3 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp +++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp @@ -88,7 +88,7 @@ void FrameHandler::blockingStopStream() { bool FrameHandler::returnHeldBuffer() { - std::unique_lock lock(mLock); + std::lock_guard lock(mLock); // Return the oldest buffer we're holding if (mHeldBuffers.empty()) { @@ -105,7 +105,7 @@ bool FrameHandler::returnHeldBuffer() { bool FrameHandler::isRunning() { - std::unique_lock lock(mLock); + std::lock_guard lock(mLock); return mRunning; } @@ -120,7 +120,7 @@ void FrameHandler::waitForFrameCount(unsigned frameCount) { void FrameHandler::getFramesCounters(unsigned* received, unsigned* displayed) { - std::unique_lock lock(mLock); + std::lock_guard lock(mLock); if (received) { *received = mFramesReceived; @@ -213,8 +213,10 @@ Return FrameHandler::deliverFrame_1_1(const hidl_vec& buff Return FrameHandler::notify(const EvsEventDesc& event) { // Local flag we use to keep track of when the stream is stopping - mLock.lock(); - mLatestEventDesc = event; + std::unique_lock lock(mEventLock); + mLatestEventDesc.aType = event.aType; + mLatestEventDesc.payload[0] = event.payload[0]; + mLatestEventDesc.payload[1] = event.payload[1]; if (mLatestEventDesc.aType == EvsEventType::STREAM_STOPPED) { // Signal that the last frame has been received and the stream is stopped mRunning = false; @@ -224,7 +226,7 @@ Return FrameHandler::notify(const EvsEventDesc& event) { } else { ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType)); } - mLock.unlock(); + lock.unlock(); mEventSignal.notify_one(); return Void(); @@ -345,25 +347,33 @@ void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) { } bool FrameHandler::waitForEvent(const EvsEventDesc& aTargetEvent, - EvsEventDesc& aReceivedEvent) { + EvsEventDesc& aReceivedEvent, + bool ignorePayload) { // Wait until we get an expected parameter change event. std::unique_lock lock(mEventLock); auto now = std::chrono::system_clock::now(); - bool result = mEventSignal.wait_until(lock, now + 5s, - [this, aTargetEvent, &aReceivedEvent](){ - bool flag = (mLatestEventDesc.aType == aTargetEvent.aType) && - (mLatestEventDesc.payload[0] == aTargetEvent.payload[0]) && - (mLatestEventDesc.payload[1] == aTargetEvent.payload[1]); + bool found = false; + while (!found) { + bool result = mEventSignal.wait_until(lock, now + 5s, + [this, aTargetEvent, ignorePayload, &aReceivedEvent, &found](){ + found = (mLatestEventDesc.aType == aTargetEvent.aType) && + (ignorePayload || (mLatestEventDesc.payload[0] == aTargetEvent.payload[0] && + mLatestEventDesc.payload[1] == aTargetEvent.payload[1])); - aReceivedEvent.aType = mLatestEventDesc.aType; - aReceivedEvent.payload[0] = mLatestEventDesc.payload[0]; - aReceivedEvent.payload[1] = mLatestEventDesc.payload[1]; + aReceivedEvent.aType = mLatestEventDesc.aType; + aReceivedEvent.payload[0] = mLatestEventDesc.payload[0]; + aReceivedEvent.payload[1] = mLatestEventDesc.payload[1]; + return found; + } + ); - return flag; + if (!result) { + ALOGW("A timer is expired before a target event has happened."); + break; } - ); + } - return !result; + return found; } const char *FrameHandler::eventToString(const EvsEventType aType) { diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h index 51e5a868e0..21e85fe0c5 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.h +++ b/automotive/evs/1.1/vts/functional/FrameHandler.h @@ -74,7 +74,8 @@ public: void waitForFrameCount(unsigned frameCount); bool waitForEvent(const EvsEventDesc& aTargetEvent, - EvsEventDesc& aReceivedEvent); + EvsEventDesc& aReceivedEvent, + bool ignorePayload = false); void getFramesCounters(unsigned* received, unsigned* displayed); void getFrameDimension(unsigned* width, unsigned* height); diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index 8847a95e69..8c8969f602 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -41,6 +41,7 @@ static const float kNanoToSeconds = 0.000000001f; #include #include #include +#include #include #include @@ -812,12 +813,42 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { EvsEventDesc aTargetEvent = {}; EvsEventDesc aNotification = {}; + bool listening = false; + std::mutex eventLock; + std::condition_variable eventCond; + std::thread listener = std::thread( + [&aNotification, &frameHandlerNonMaster, &listening, &eventCond]() { + // Notify that a listening thread is running. + listening = true; + eventCond.notify_all(); + + EvsEventDesc aTargetEvent; + aTargetEvent.aType = EvsEventType::MASTER_RELEASED; + if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification, true)) { + ALOGW("A timer is expired before a target event is fired."); + } + + } + ); + + // Wait until a listening thread starts. + std::unique_lock lock(eventLock); + auto timer = std::chrono::system_clock::now(); + while (!listening) { + timer += 1s; + eventCond.wait_until(lock, timer); + } + lock.unlock(); + // Release a master role. pCamMaster->unsetMaster(); - // Verify a change notification. - aTargetEvent.aType = EvsEventType::MASTER_RELEASED; - frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification); + // Join a listening thread. + if (listener.joinable()) { + listener.join(); + } + + // Verify change notifications. ASSERT_EQ(EvsEventType::MASTER_RELEASED, static_cast(aNotification.aType)); @@ -829,24 +860,49 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { result = pCamMaster->setMaster(); ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST); + listening = false; + listener = std::thread( + [&aNotification, &frameHandlerMaster, &listening, &eventCond]() { + // Notify that a listening thread is running. + listening = true; + eventCond.notify_all(); + + EvsEventDesc aTargetEvent; + aTargetEvent.aType = EvsEventType::MASTER_RELEASED; + if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification, true)) { + ALOGW("A timer is expired before a target event is fired."); + } + + } + ); + + // Wait until a listening thread starts. + timer = std::chrono::system_clock::now(); + lock.lock(); + while (!listening) { + eventCond.wait_until(lock, timer + 1s); + } + lock.unlock(); + // Closing current master client. frameHandlerNonMaster->shutdown(); - // Verify a change notification. - aTargetEvent.aType = EvsEventType::MASTER_RELEASED; - frameHandlerMaster->waitForEvent(aTargetEvent, aNotification); + // Join a listening thread. + if (listener.joinable()) { + listener.join(); + } + + // Verify change notifications. ASSERT_EQ(EvsEventType::MASTER_RELEASED, static_cast(aNotification.aType)); - // Closing another stream. + // Closing streams. frameHandlerMaster->shutdown(); // Explicitly release the camera pEnumerator->closeCamera(pCamMaster); pEnumerator->closeCamera(pCamNonMaster); } - - } @@ -950,6 +1006,8 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { int32_t val0 = 0; std::vector values; + EvsEventDesc aNotification0 = {}; + EvsEventDesc aNotification1 = {}; for (auto &cmd : camMasterCmds) { // Get a valid parameter value range int32_t minVal, maxVal, step; @@ -965,6 +1023,7 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { EvsResult result = EvsResult::OK; if (cmd == CameraParam::ABSOLUTE_FOCUS) { // Try to turn off auto-focus + values.clear(); pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0, [&result, &values](auto status, auto effectiveValues) { result = status; @@ -980,11 +1039,59 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { } } - // Try to program a parameter + // Calculate a parameter value to program. val0 = minVal + (std::rand() % (maxVal - minVal)); - - // Rounding down val0 = val0 - (val0 % step); + + // Prepare and start event listeners. + bool listening0 = false; + bool listening1 = false; + std::condition_variable eventCond; + std::thread listener0 = std::thread( + [cmd, val0, + &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() { + listening0 = true; + if (listening1) { + eventCond.notify_all(); + } + + EvsEventDesc aTargetEvent; + aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; + aTargetEvent.payload[0] = static_cast(cmd); + aTargetEvent.payload[1] = val0; + if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) { + ALOGW("A timer is expired before a target event is fired."); + } + } + ); + std::thread listener1 = std::thread( + [cmd, val0, + &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() { + listening1 = true; + if (listening0) { + eventCond.notify_all(); + } + + EvsEventDesc aTargetEvent; + aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; + aTargetEvent.payload[0] = static_cast(cmd); + aTargetEvent.payload[1] = val0; + if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) { + ALOGW("A timer is expired before a target event is fired."); + } + } + ); + + // Wait until a listening thread starts. + std::mutex eventLock; + std::unique_lock lock(eventLock); + auto timer = std::chrono::system_clock::now(); + while (!listening0 || !listening1) { + eventCond.wait_until(lock, timer + 1s); + } + lock.unlock(); + + // Try to program a parameter values.clear(); pCamMaster->setIntParameter(cmd, val0, [&result, &values](auto status, auto effectiveValues) { @@ -995,13 +1102,38 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { } } }); + ASSERT_EQ(EvsResult::OK, result); + for (auto &&v : values) { + ASSERT_EQ(val0, v) << "Values are not matched."; + } - // Non-master client expects to receive a parameter change notification + // Join a listening thread. + if (listener0.joinable()) { + listener0.join(); + } + if (listener1.joinable()) { + listener1.join(); + } + + // Verify a change notification + ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, + static_cast(aNotification0.aType)); + ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, + static_cast(aNotification1.aType)); + ASSERT_EQ(cmd, + static_cast(aNotification0.payload[0])); + ASSERT_EQ(cmd, + static_cast(aNotification1.payload[0])); + for (auto &&v : values) { + ASSERT_EQ(v, + static_cast(aNotification0.payload[1])); + ASSERT_EQ(v, + static_cast(aNotification1.payload[1])); + } + + // Clients expects to receive a parameter change notification // whenever a master client adjusts it. - EvsEventDesc aTargetEvent = {}; - EvsEventDesc aNotification = {}; - values.clear(); pCamMaster->getIntParameter(cmd, [&result, &values](auto status, auto readValues) { @@ -1016,20 +1148,6 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { for (auto &&v : values) { ASSERT_EQ(val0, v) << "Values are not matched."; } - - // Verify a change notification - aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; - aTargetEvent.payload[0] = static_cast(cmd); - aTargetEvent.payload[1] = static_cast(val0); - frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification); - ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, - static_cast(aNotification.aType)); - ASSERT_EQ(cmd, - static_cast(aNotification.payload[0])); - for (auto &&v : values) { - ASSERT_EQ(v, - static_cast(aNotification.payload[1])); - } } // Try to adjust a parameter via non-master client @@ -1050,9 +1168,38 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result); // Master client retires from a master role + bool listening = false; + std::condition_variable eventCond; + std::thread listener = std::thread( + [&aNotification0, &frameHandlerNonMaster, &listening, &eventCond]() { + listening = true; + eventCond.notify_all(); + + EvsEventDesc aTargetEvent; + aTargetEvent.aType = EvsEventType::MASTER_RELEASED; + if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification0, true)) { + ALOGW("A timer is expired before a target event is fired."); + } + } + ); + + std::mutex eventLock; + auto timer = std::chrono::system_clock::now(); + unique_lock lock(eventLock); + while (!listening) { + eventCond.wait_until(lock, timer + 1s); + } + lock.unlock(); + result = pCamMaster->unsetMaster(); ASSERT_EQ(EvsResult::OK, result); + if (listener.joinable()) { + listener.join(); + } + ASSERT_EQ(EvsEventType::MASTER_RELEASED, + static_cast(aNotification0.aType)); + // Try to adjust a parameter after being retired values.clear(); pCamMaster->setIntParameter(camMasterCmds[0], val0, @@ -1087,6 +1234,7 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { values.clear(); if (cmd == CameraParam::ABSOLUTE_FOCUS) { // Try to turn off auto-focus + values.clear(); pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0, [&result, &values](auto status, auto effectiveValues) { result = status; @@ -1102,11 +1250,57 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { } } - // Try to program a parameter + // Calculate a parameter value to program. This is being rounding down. val0 = minVal + (std::rand() % (maxVal - minVal)); - - // Rounding down val0 = val0 - (val0 % step); + + // Prepare and start event listeners. + bool listening0 = false; + bool listening1 = false; + std::condition_variable eventCond; + std::thread listener0 = std::thread( + [&cmd, &val0, &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() { + listening0 = true; + if (listening1) { + eventCond.notify_all(); + } + + EvsEventDesc aTargetEvent; + aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; + aTargetEvent.payload[0] = static_cast(cmd); + aTargetEvent.payload[1] = val0; + if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) { + ALOGW("A timer is expired before a target event is fired."); + } + } + ); + std::thread listener1 = std::thread( + [&cmd, &val0, &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() { + listening1 = true; + if (listening0) { + eventCond.notify_all(); + } + + EvsEventDesc aTargetEvent; + aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; + aTargetEvent.payload[0] = static_cast(cmd); + aTargetEvent.payload[1] = val0; + if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) { + ALOGW("A timer is expired before a target event is fired."); + } + } + ); + + // Wait until a listening thread starts. + std::mutex eventLock; + std::unique_lock lock(eventLock); + auto timer = std::chrono::system_clock::now(); + while (!listening0 || !listening1) { + eventCond.wait_until(lock, timer + 1s); + } + lock.unlock(); + + // Try to program a parameter values.clear(); pCamNonMaster->setIntParameter(cmd, val0, [&result, &values](auto status, auto effectiveValues) { @@ -1119,11 +1313,8 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { }); ASSERT_EQ(EvsResult::OK, result); - // Non-master client expects to receive a parameter change notification + // Clients expects to receive a parameter change notification // whenever a master client adjusts it. - EvsEventDesc aTargetEvent = {}; - EvsEventDesc aNotification = {}; - values.clear(); pCamNonMaster->getIntParameter(cmd, [&result, &values](auto status, auto readValues) { @@ -1139,18 +1330,28 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { ASSERT_EQ(val0, v) << "Values are not matched."; } + // Join a listening thread. + if (listener0.joinable()) { + listener0.join(); + } + if (listener1.joinable()) { + listener1.join(); + } + // Verify a change notification - aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; - aTargetEvent.payload[0] = static_cast(cmd); - aTargetEvent.payload[1] = static_cast(val0); - frameHandlerMaster->waitForEvent(aTargetEvent, aNotification); ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, - static_cast(aNotification.aType)); + static_cast(aNotification0.aType)); + ASSERT_EQ(EvsEventType::PARAMETER_CHANGED, + static_cast(aNotification1.aType)); ASSERT_EQ(cmd, - static_cast(aNotification.payload[0])); + static_cast(aNotification0.payload[0])); + ASSERT_EQ(cmd, + static_cast(aNotification1.payload[0])); for (auto &&v : values) { ASSERT_EQ(v, - static_cast(aNotification.payload[1])); + static_cast(aNotification0.payload[1])); + ASSERT_EQ(v, + static_cast(aNotification1.payload[1])); } } @@ -1276,7 +1477,33 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { std::vector values; EvsEventDesc aTargetEvent = {}; EvsEventDesc aNotification = {}; + bool listening = false; + std::mutex eventLock; + std::condition_variable eventCond; if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) { + std::thread listener = std::thread( + [&frameHandler0, &aNotification, &listening, &eventCond] { + listening = true; + eventCond.notify_all(); + + EvsEventDesc aTargetEvent; + aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; + aTargetEvent.payload[0] = static_cast(CameraParam::AUTO_FOCUS); + aTargetEvent.payload[1] = 0; + if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) { + ALOGW("A timer is expired before a target event is fired."); + } + } + ); + + // Wait until a lister starts. + std::unique_lock lock(eventLock); + auto timer = std::chrono::system_clock::now(); + while (!listening) { + eventCond.wait_until(lock, timer + 1s); + } + lock.unlock(); + // Try to turn off auto-focus pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0, [&result, &values](auto status, auto effectiveValues) { @@ -1292,20 +1519,45 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { ASSERT_EQ(v, 0); } + // Join a listener + if (listener.joinable()) { + listener.join(); + } + // Make sure AUTO_FOCUS is off. - aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; - aTargetEvent.payload[0] = static_cast(CameraParam::AUTO_FOCUS); - aTargetEvent.payload[1] = 0; - bool timeout = - frameHandler0->waitForEvent(aTargetEvent, aNotification); - ASSERT_FALSE(timeout) << "Expected event does not arrive"; + ASSERT_EQ(static_cast(aNotification.aType), + EvsEventType::PARAMETER_CHANGED); } - // Try to program a parameter with a random value [minVal, maxVal] + // Try to program a parameter with a random value [minVal, maxVal] after + // rounding it down. int32_t val0 = minVal + (std::rand() % (maxVal - minVal)); - - // Rounding down val0 = val0 - (val0 % step); + + std::thread listener = std::thread( + [&frameHandler1, &aNotification, &listening, &eventCond, &cam1Cmds, val0] { + listening = true; + eventCond.notify_all(); + + EvsEventDesc aTargetEvent; + aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; + aTargetEvent.payload[0] = static_cast(cam1Cmds[0]); + aTargetEvent.payload[1] = val0; + if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) { + ALOGW("A timer is expired before a target event is fired."); + } + } + ); + + // Wait until a lister starts. + listening = false; + std::unique_lock lock(eventLock); + auto timer = std::chrono::system_clock::now(); + while (!listening) { + eventCond.wait_until(lock, timer + 1s); + } + lock.unlock(); + values.clear(); pCam1->setIntParameter(cam1Cmds[0], val0, [&result, &values](auto status, auto effectiveValues) { @@ -1321,13 +1573,12 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { ASSERT_EQ(val0, v); } + // Join a listener + if (listener.joinable()) { + listener.join(); + } + // Verify a change notification - aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; - aTargetEvent.payload[0] = static_cast(cam1Cmds[0]); - aTargetEvent.payload[1] = static_cast(val0); - bool timeout = - frameHandler0->waitForEvent(aTargetEvent, aNotification); - ASSERT_FALSE(timeout) << "Expected event does not arrive"; ASSERT_EQ(static_cast(aNotification.aType), EvsEventType::PARAMETER_CHANGED); ASSERT_EQ(static_cast(aNotification.payload[0]), @@ -1336,13 +1587,36 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { ASSERT_EQ(v, static_cast(aNotification.payload[1])); } + listener = std::thread( + [&frameHandler1, &aNotification, &listening, &eventCond] { + listening = true; + eventCond.notify_all(); + + EvsEventDesc aTargetEvent; + aTargetEvent.aType = EvsEventType::MASTER_RELEASED; + if (!frameHandler1->waitForEvent(aTargetEvent, aNotification, true)) { + ALOGW("A timer is expired before a target event is fired."); + } + } + ); + + // Wait until a lister starts. + listening = false; + lock.lock(); + timer = std::chrono::system_clock::now(); + while (!listening) { + eventCond.wait_until(lock, timer + 1s); + } + lock.unlock(); + // Client 0 steals a master role ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay)); - aTargetEvent.aType = EvsEventType::MASTER_RELEASED; - aTargetEvent.payload[0] = 0; - aTargetEvent.payload[1] = 0; - frameHandler1->waitForEvent(aTargetEvent, aNotification); + // Join a listener + if (listener.joinable()) { + listener.join(); + } + ASSERT_EQ(static_cast(aNotification.aType), EvsEventType::MASTER_RELEASED); @@ -1353,6 +1627,29 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { val0 = val0 - (val0 % step); if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) { + std::thread listener = std::thread( + [&frameHandler1, &aNotification, &listening, &eventCond] { + listening = true; + eventCond.notify_all(); + + EvsEventDesc aTargetEvent; + aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; + aTargetEvent.payload[0] = static_cast(CameraParam::AUTO_FOCUS); + aTargetEvent.payload[1] = 0; + if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) { + ALOGW("A timer is expired before a target event is fired."); + } + } + ); + + // Wait until a lister starts. + std::unique_lock lock(eventLock); + auto timer = std::chrono::system_clock::now(); + while (!listening) { + eventCond.wait_until(lock, timer + 1s); + } + lock.unlock(); + // Try to turn off auto-focus values.clear(); pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0, @@ -1369,15 +1666,40 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { ASSERT_EQ(v, 0); } + // Join a listener + if (listener.joinable()) { + listener.join(); + } + // Make sure AUTO_FOCUS is off. - aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; - aTargetEvent.payload[0] = static_cast(CameraParam::AUTO_FOCUS); - aTargetEvent.payload[1] = 0; - bool timeout = - frameHandler1->waitForEvent(aTargetEvent, aNotification); - ASSERT_FALSE(timeout) << "Expected event does not arrive"; + ASSERT_EQ(static_cast(aNotification.aType), + EvsEventType::PARAMETER_CHANGED); } + listener = std::thread( + [&frameHandler0, &aNotification, &listening, &eventCond, &cam0Cmds, val0] { + listening = true; + eventCond.notify_all(); + + EvsEventDesc aTargetEvent; + aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; + aTargetEvent.payload[0] = static_cast(cam0Cmds[0]); + aTargetEvent.payload[1] = val0; + if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) { + ALOGW("A timer is expired before a target event is fired."); + } + } + ); + + // Wait until a lister starts. + listening = false; + timer = std::chrono::system_clock::now(); + lock.lock(); + while (!listening) { + eventCond.wait_until(lock, timer + 1s); + } + lock.unlock(); + values.clear(); pCam0->setIntParameter(cam0Cmds[0], val0, [&result, &values](auto status, auto effectiveValues) { @@ -1390,13 +1712,11 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { }); ASSERT_EQ(EvsResult::OK, result); + // Join a listener + if (listener.joinable()) { + listener.join(); + } // Verify a change notification - aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED; - aTargetEvent.payload[0] = static_cast(cam0Cmds[0]); - aTargetEvent.payload[1] = static_cast(val0); - timeout = - frameHandler1->waitForEvent(aTargetEvent, aNotification); - ASSERT_FALSE(timeout) << "Expected event does not arrive"; ASSERT_EQ(static_cast(aNotification.aType), EvsEventType::PARAMETER_CHANGED); ASSERT_EQ(static_cast(aNotification.payload[0]), From 273c37d303be566830e6864b9ab110dbc8a0b7ac Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Sun, 1 Dec 2019 14:46:43 -0800 Subject: [PATCH 0392/1022] Fix EVS frame handler for VTS This change updates FrameHandler to handle and count delivered EVS frames correctly. Bug: 142275664 Test: VtsHalEvsV1_1TargetTest Change-Id: I098bcf8155c9e4211ec0152b2a828520b6c22dc2 Signed-off-by: Changyeon Jo --- .../evs/1.1/vts/functional/FrameHandler.cpp | 89 ++++++++++--------- 1 file changed, 47 insertions(+), 42 deletions(-) diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp index 44783f65c3..d5fd173883 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp +++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp @@ -139,56 +139,58 @@ Return FrameHandler::deliverFrame(const BufferDesc_1_0& bufferArg) { Return FrameHandler::deliverFrame_1_1(const hidl_vec& buffers) { - for (auto&& buffer : buffers) { - const AHardwareBuffer_Desc* pDesc = - reinterpret_cast(&buffer.buffer.description); - ALOGD("Received a frame from the camera (%p)", - buffer.buffer.nativeHandle.getNativeHandle()); + mLock.lock(); + // For VTS tests, FrameHandler uses a single frame among delivered frames. + auto bufferIdx = mFramesDisplayed % buffers.size(); + auto buffer = buffers[bufferIdx]; + mLock.unlock(); - // Store a dimension of a received frame. - mFrameWidth = pDesc->width; - mFrameHeight = pDesc->height; + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&buffer.buffer.description); + ALOGD("Received a frame from the camera (%p)", + buffer.buffer.nativeHandle.getNativeHandle()); - // If we were given an opened display at construction time, then send the received - // image back down the camera. - if (mDisplay.get()) { - // Get the output buffer we'll use to display the imagery - BufferDesc_1_0 tgtBuffer = {}; - mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) { - tgtBuffer = buff; - } - ); + // Store a dimension of a received frame. + mFrameWidth = pDesc->width; + mFrameHeight = pDesc->height; - if (tgtBuffer.memHandle == nullptr) { - printf("Didn't get target buffer - frame lost\n"); - ALOGE("Didn't get requested output buffer -- skipping this frame."); + // If we were given an opened display at construction time, then send the received + // image back down the camera. + bool displayed = false; + if (mDisplay.get()) { + // Get the output buffer we'll use to display the imagery + BufferDesc_1_0 tgtBuffer = {}; + mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) { + tgtBuffer = buff; + } + ); + + if (tgtBuffer.memHandle == nullptr) { + printf("Didn't get target buffer - frame lost\n"); + ALOGE("Didn't get requested output buffer -- skipping this frame."); + } else { + // Copy the contents of the of buffer.memHandle into tgtBuffer + copyBufferContents(tgtBuffer, buffer); + + // Send the target buffer back for display + Return result = mDisplay->returnTargetBufferForDisplay(tgtBuffer); + if (!result.isOk()) { + printf("HIDL error on display buffer (%s)- frame lost\n", + result.description().c_str()); + ALOGE("Error making the remote function call. HIDL said %s", + result.description().c_str()); + } else if (result != EvsResult::OK) { + printf("Display reported error - frame lost\n"); + ALOGE("We encountered error %d when returning a buffer to the display!", + (EvsResult) result); } else { - // Copy the contents of the of buffer.memHandle into tgtBuffer - copyBufferContents(tgtBuffer, buffer); - - // Send the target buffer back for display - Return result = mDisplay->returnTargetBufferForDisplay(tgtBuffer); - if (!result.isOk()) { - printf("HIDL error on display buffer (%s)- frame lost\n", - result.description().c_str()); - ALOGE("Error making the remote function call. HIDL said %s", - result.description().c_str()); - } else if (result != EvsResult::OK) { - printf("Display reported error - frame lost\n"); - ALOGE("We encountered error %d when returning a buffer to the display!", - (EvsResult) result); - } else { - // Everything looks good! - // Keep track so tests or watch dogs can monitor progress - mLock.lock(); - mFramesDisplayed++; - mLock.unlock(); - } + // Everything looks good! + // Keep track so tests or watch dogs can monitor progress + displayed = true; } } } - switch (mReturnMode) { case eAutoReturn: // Send the camera buffer back now that the client has seen it @@ -198,10 +200,13 @@ Return FrameHandler::deliverFrame_1_1(const hidl_vec& buff case eNoAutoReturn: // Hang onto the buffer handles for now -- the client will return it explicitly later mHeldBuffers.push(buffers); + break; } mLock.lock(); + // increases counters ++mFramesReceived; + mFramesDisplayed += (int)displayed; mLock.unlock(); mFrameSignal.notify_all(); From a203a13bf3d434e99928aa61e30483a5d8b77cd8 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Sun, 1 Dec 2019 14:53:36 -0800 Subject: [PATCH 0393/1022] Update EVS VTS test cases This change updates existing EVS VTS test cases to verify the logical camera device. Bug: 142275664 Test: VtsHalEvsV1_1TargetTest Change-Id: Ieebb09a3bbf948ab60d0498a359be8f8c726735c Signed-off-by: Changyeon Jo --- .../evs/1.1/vts/functional/FrameHandler.cpp | 14 +- .../functional/VtsHalEvsV1_1TargetTest.cpp | 200 +++++++++++++++++- 2 files changed, 197 insertions(+), 17 deletions(-) diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp index d5fd173883..ebf488acb3 100644 --- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp +++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp @@ -191,6 +191,13 @@ Return FrameHandler::deliverFrame_1_1(const hidl_vec& buff } } + mLock.lock(); + // increases counters + ++mFramesReceived; + mFramesDisplayed += (int)displayed; + mLock.unlock(); + mFrameSignal.notify_all(); + switch (mReturnMode) { case eAutoReturn: // Send the camera buffer back now that the client has seen it @@ -203,13 +210,6 @@ Return FrameHandler::deliverFrame_1_1(const hidl_vec& buff break; } - mLock.lock(); - // increases counters - ++mFramesReceived; - mFramesDisplayed += (int)displayed; - mLock.unlock(); - mFrameSignal.notify_all(); - ALOGD("Frame handling complete"); return Void(); diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index 8c8969f602..2890ba500c 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -42,6 +42,7 @@ static const float kNanoToSeconds = 0.000000001f; #include #include #include +#include #include #include @@ -151,6 +152,84 @@ protected: ASSERT_GE(cameraInfo.size(), 1u); } + bool isLogicalCamera(const camera_metadata_t *metadata) { + if (metadata == nullptr) { + // A logical camera device must have a valid camera metadata. + return false; + } + + // Looking for LOGICAL_MULTI_CAMERA capability from metadata. + camera_metadata_ro_entry_t entry; + int rc = find_camera_metadata_ro_entry(metadata, + ANDROID_REQUEST_AVAILABLE_CAPABILITIES, + &entry); + if (0 != rc) { + // No capabilities are found. + return false; + } + + for (size_t i = 0; i < entry.count; ++i) { + uint8_t cap = entry.data.u8[i]; + if (cap == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) { + return true; + } + } + + return false; + } + + std::unordered_set getPhysicalCameraIds(const std::string& id, + bool& flag) { + std::unordered_set physicalCameras; + + auto it = cameraInfo.begin(); + while (it != cameraInfo.end()) { + if (it->v1.cameraId == id) { + break; + } + ++it; + } + + if (it == cameraInfo.end()) { + // Unknown camera is requested. Return an empty list. + return physicalCameras; + } + + const camera_metadata_t *metadata = + reinterpret_cast(&it->metadata[0]); + flag = isLogicalCamera(metadata); + if (!flag) { + // EVS assumes that the device w/o a valid metadata is a physical + // device. + ALOGI("%s is not a logical camera device.", id.c_str()); + physicalCameras.emplace(id); + return physicalCameras; + } + + // Look for physical camera identifiers + camera_metadata_ro_entry entry; + int rc = find_camera_metadata_ro_entry(metadata, + ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS, + &entry); + ALOGE_IF(rc, "No physical camera ID is found for a logical camera device"); + + const uint8_t *ids = entry.data.u8; + size_t start = 0; + for (size_t i = 0; i < entry.count; ++i) { + if (ids[i] == '\0') { + if (start != i) { + std::string id(reinterpret_cast(ids + start)); + physicalCameras.emplace(id); + } + start = i + 1; + } + } + + ALOGI("%s consists of %d physical camera devices.", id.c_str(), (int)physicalCameras.size()); + return physicalCameras; + } + + sp pEnumerator; // Every test needs access to the service std::vector cameraInfo; // Empty unless/until loadCameraList() is called bool mIsHwModule; // boolean to tell current module under testing @@ -180,6 +259,13 @@ TEST_F(EvsHidlTest, CameraOpenClean) { // Open and close each camera twice for (auto&& cam: cameraInfo) { + bool isLogicalCam = false; + auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); + if (mIsHwModule && isLogicalCam) { + ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str()); + continue; + } + for (int pass = 0; pass < 2; pass++) { activeCameras.clear(); sp pCam = @@ -222,6 +308,13 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { // Open and close each camera twice for (auto&& cam: cameraInfo) { + bool isLogicalCam = false; + getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); + if (mIsHwModule && isLogicalCam) { + ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str()); + continue; + } + activeCameras.clear(); sp pCam = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) @@ -292,6 +385,13 @@ TEST_F(EvsHidlTest, CameraStreamPerformance) { // Test each reported camera for (auto&& cam: cameraInfo) { + bool isLogicalCam = false; + auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); + if (mIsHwModule && isLogicalCam) { + ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str()); + continue; + } + activeCameras.clear(); sp pCam = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) @@ -308,6 +408,7 @@ TEST_F(EvsHidlTest, CameraStreamPerformance) { // Start the camera's video stream nsecs_t start = systemTime(SYSTEM_TIME_MONOTONIC); + bool startResult = frameHandler->startStream(); ASSERT_TRUE(startResult); @@ -315,9 +416,17 @@ TEST_F(EvsHidlTest, CameraStreamPerformance) { frameHandler->waitForFrameCount(1); nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC); nsecs_t timeToFirstFrame = systemTime(SYSTEM_TIME_MONOTONIC) - start; - EXPECT_LE(nanoseconds_to_milliseconds(timeToFirstFrame), kMaxStreamStartMilliseconds); - printf("Measured time to first frame %0.2f ms\n", timeToFirstFrame * kNanoToMilliseconds); - ALOGI("Measured time to first frame %0.2f ms", timeToFirstFrame * kNanoToMilliseconds); + + // Extra delays are expected when we attempt to start a video stream on + // the logical camera device. The amount of delay is expected the + // number of physical camera devices multiplied by + // kMaxStreamStartMilliseconds at most. + EXPECT_LE(nanoseconds_to_milliseconds(timeToFirstFrame), + kMaxStreamStartMilliseconds * devices.size()); + printf("%s: Measured time to first frame %0.2f ms\n", + cam.v1.cameraId.c_str(), timeToFirstFrame * kNanoToMilliseconds); + ALOGI("%s: Measured time to first frame %0.2f ms", + cam.v1.cameraId.c_str(), timeToFirstFrame * kNanoToMilliseconds); // Check aspect ratio unsigned width = 0, height = 0; @@ -327,6 +436,13 @@ TEST_F(EvsHidlTest, CameraStreamPerformance) { // Wait a bit, then ensure we get at least the required minimum number of frames sleep(5); nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC); + + // Even when the camera pointer goes out of scope, the FrameHandler object will + // keep the stream alive unless we tell it to shutdown. + // Also note that the FrameHandle and the Camera have a mutual circular reference, so + // we have to break that cycle in order for either of them to get cleaned up. + frameHandler->shutdown(); + unsigned framesReceived = 0; frameHandler->getFramesCounters(&framesReceived, nullptr); framesReceived = framesReceived - 1; // Back out the first frame we already waited for @@ -336,12 +452,6 @@ TEST_F(EvsHidlTest, CameraStreamPerformance) { ALOGI("Measured camera rate %3.2f fps", framesPerSecond); EXPECT_GE(framesPerSecond, kMinimumFramesPerSecond); - // Even when the camera pointer goes out of scope, the FrameHandler object will - // keep the stream alive unless we tell it to shutdown. - // Also note that the FrameHandle and the Camera have a mutual circular reference, so - // we have to break that cycle in order for either of them to get cleaned up. - frameHandler->shutdown(); - // Explicitly release the camera pEnumerator->closeCamera(pCam); } @@ -368,6 +478,13 @@ TEST_F(EvsHidlTest, CameraStreamBuffering) { // Test each reported camera for (auto&& cam: cameraInfo) { + bool isLogicalCam = false; + getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); + if (mIsHwModule && isLogicalCam) { + ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str()); + continue; + } + activeCameras.clear(); sp pCam = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) @@ -397,7 +514,7 @@ TEST_F(EvsHidlTest, CameraStreamBuffering) { // Check that the video stream stalls once we've gotten exactly the number of buffers // we requested since we told the frameHandler not to return them. - sleep(2); // 1 second should be enough for at least 5 frames to be delivered worst case + sleep(1); // 1 second should be enough for at least 5 frames to be delivered worst case unsigned framesReceived = 0; frameHandler->getFramesCounters(&framesReceived, nullptr); ASSERT_EQ(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit"; @@ -447,6 +564,13 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { // Test each reported camera for (auto&& cam: cameraInfo) { + bool isLogicalCam = false; + getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); + if (mIsHwModule && isLogicalCam) { + ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str()); + continue; + } + activeCameras.clear(); sp pCam = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) @@ -596,6 +720,11 @@ TEST_F(EvsHidlTest, MultiCameraStream) { // Explicitly release the camera pEnumerator->closeCamera(pCam0); pEnumerator->closeCamera(pCam1); + + // TODO(b/145459970, b/145457727): below sleep() is added to ensure the + // destruction of active camera objects; this may be related with two + // issues. + sleep(1); } } @@ -617,6 +746,15 @@ TEST_F(EvsHidlTest, CameraParameter) { // Test each reported camera Return result = EvsResult::OK; for (auto&& cam: cameraInfo) { + bool isLogicalCam = false; + getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); + if (isLogicalCam) { + // TODO(b/145465724): Support camera parameter programming on + // logical devices. + ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str()); + continue; + } + activeCameras.clear(); // Create a camera client sp pCam = @@ -756,6 +894,15 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { // Test each reported camera for (auto&& cam: cameraInfo) { + bool isLogicalCam = false; + getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); + if (isLogicalCam) { + // TODO(b/145465724): Support camera parameter programming on + // logical devices. + ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str()); + continue; + } + activeCameras.clear(); // Create two camera clients. sp pCamMaster = @@ -928,6 +1075,15 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { // Test each reported camera for (auto&& cam: cameraInfo) { + bool isLogicalCam = false; + getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); + if (isLogicalCam) { + // TODO(b/145465724): Support camera parameter programming on + // logical devices. + ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str()); + continue; + } + activeCameras.clear(); // Create two camera clients. sp pCamMaster = @@ -1995,6 +2151,30 @@ TEST_F(EvsHidlTest, MultiCameraStreamUseConfig) { } +/* + * LogicalCameraMetadata: + * Opens logical camera reported by the enumerator and validate its metadata by + * checking its capability and locating supporting physical camera device + * identifiers. + */ +TEST_F(EvsHidlTest, LogicalCameraMetadata) { + ALOGI("Starting LogicalCameraMetadata test"); + + // Get the camera list + loadCameraList(); + + // Open and close each camera twice + for (auto&& cam: cameraInfo) { + bool isLogicalCam = false; + auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); + if (isLogicalCam) { + ASSERT_GE(devices.size(), 1) << + "Logical camera device must have at least one physical camera device ID in its metadata."; + } + } +} + + int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance()); ::testing::InitGoogleTest(&argc, argv); From 6caf74b06185f575e90ad38801f35b803f140264 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Mon, 2 Dec 2019 09:50:41 -0800 Subject: [PATCH 0394/1022] Implement getPhysicalCameraInfo() method This change adds a new method, getPhysicalCameraInfo(), to IEvsCamera interface, implements it in the default implementation, and update corresponding VTS test cases. Bug: 142275664 Test: VtsHalEvsV1_1TargetTest Change-Id: Ic993d5670c34f05ef8d807708f27dec75008b04b Signed-off-by: Changyeon Jo --- automotive/evs/1.1/IEvsCamera.hal | 17 +++++++++++++++++ automotive/evs/1.1/default/EvsCamera.cpp | 11 +++++++++++ automotive/evs/1.1/default/EvsCamera.h | 2 ++ .../vts/functional/VtsHalEvsV1_1TargetTest.cpp | 9 +++++++++ 4 files changed, 39 insertions(+) diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal index acc2eec257..fc68e60a1e 100644 --- a/automotive/evs/1.1/IEvsCamera.hal +++ b/automotive/evs/1.1/IEvsCamera.hal @@ -33,6 +33,23 @@ interface IEvsCamera extends @1.0::IEvsCamera { */ getCameraInfo_1_1() generates (CameraDesc info); + /** + * Returns the description of the physical camera device that backs this + * logical camera. + * + * If a requested device does not either exist or back this logical device, + * this method returns a null camera descriptor. And, if this is called on + * a physical camera device, this method is the same as getCameraInfo_1_1() + * method if a given device ID is matched. Otherwise, this will return a + * null camera descriptor. + * + * @param deviceId Physical camera device identifier string. + * @return info The description of a member physical camera device. + * This must be the same value as reported by + * EvsEnumerator::getCameraList_1_1(). + */ + getPhysicalCameraInfo(string deviceId) generates (CameraDesc info); + /** * Requests to pause EVS camera stream events. * diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp index e200b53539..b7e4efac02 100644 --- a/automotive/evs/1.1/default/EvsCamera.cpp +++ b/automotive/evs/1.1/default/EvsCamera.cpp @@ -240,6 +240,17 @@ Return EvsCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) { } +Return EvsCamera::getPhysicalCameraInfo(const hidl_string& id, + getCameraInfo_1_1_cb _hidl_cb) { + ALOGD("%s", __FUNCTION__); + + // This works exactly same as getCameraInfo_1_1() in default implementation. + (void)id; + _hidl_cb(mDescription); + return Void(); +} + + Return EvsCamera::doneWithFrame_1_1(const hidl_vec& buffers) { std::lock_guard lock(mAccessLock); diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h index a32fa75ec3..72a1b5776b 100644 --- a/automotive/evs/1.1/default/EvsCamera.h +++ b/automotive/evs/1.1/default/EvsCamera.h @@ -62,6 +62,8 @@ public: // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow. Return getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) override; + Return getPhysicalCameraInfo(const hidl_string& id, + getPhysicalCameraInfo_cb _hidl_cb) override; Return pauseVideoStream() override; Return resumeVideoStream() override; Return doneWithFrame_1_1(const hidl_vec& buffer) override; diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index 2890ba500c..4fc4e4c144 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -273,6 +273,15 @@ TEST_F(EvsHidlTest, CameraOpenClean) { .withDefault(nullptr); ASSERT_NE(pCam, nullptr); + for (auto&& devName : devices) { + bool matched = false; + pCam->getPhysicalCameraInfo(devName, + [&devName, &matched](const CameraDesc& info) { + matched = devName == info.v1.cameraId; + }); + ASSERT_TRUE(matched); + } + // Store a camera handle for a clean-up activeCameras.push_back(pCam); From eb7f1756139dd5e5efe19d179a1e3dded720cc80 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Mon, 6 Jan 2020 12:52:06 +0000 Subject: [PATCH 0395/1022] NNAPI: Update docs for ops with signed quantization types.hal files are generated from current types.spec. Bug: 136735770 Test: mma Change-Id: Ide24606f8b1d5e755a71d46f230409942d8df7e9 --- current.txt | 6 +- neuralnetworks/1.0/types.hal | 25 ++- neuralnetworks/1.2/types.hal | 83 +++++----- neuralnetworks/1.3/types.hal | 311 ++++++++++++++++++++++++++--------- 4 files changed, 297 insertions(+), 128 deletions(-) diff --git a/current.txt b/current.txt index 68e4713a45..e35586784f 100644 --- a/current.txt +++ b/current.txt @@ -588,11 +588,11 @@ d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardwar cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel -f1109cbb10297b7429a11fab42afa912710b303c9bf20bd5cdb8bd57b9c84186 android.hardware.neuralnetworks@1.0::types +8eac60e1f724d141c71c69f06d4544acb720a55dfbbcd97fa01bb3d25ee4e2f5 android.hardware.neuralnetworks@1.0::types 5f6d3097ba84cb63c430787123f4de1b31c11f90b531b98eae9a8623a5ae962a android.hardware.neuralnetworks@1.1::types fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice 40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel -2d5483fbf59d5fd2de94665a6df05da5c3d09de67561d0db5e9f09e59e9aea46 android.hardware.neuralnetworks@1.2::types +7f7ef383268c95a1b8fe4e55c662bc806bb0ac11a154f6b049a113a44b0f024f android.hardware.neuralnetworks@1.2::types a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface @@ -648,7 +648,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice 258825966435b3ed08832055bb736d81516013e405f161d9ccde9a90cfcdde83 android.hardware.neuralnetworks@1.3::IPreparedModel 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -cf1d55e8c68300090747ab90b94c22e4c859b29c84ced68a317c595bb115eab2 android.hardware.neuralnetworks@1.3::types +35668befe89fc7f84d58fc1dab7dd3e4d6067c7eeccbae154fe36cd964dfaef7 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi 9bc274c9d73aae170fd9e18df2476ade4c19b629cfb38dd03dd237a6cc2d932b android.hardware.wifi.hostapd@1.2::IHostapd 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.0/types.hal b/neuralnetworks/1.0/types.hal index ba9d068e34..1175a309dd 100644 --- a/neuralnetworks/1.0/types.hal +++ b/neuralnetworks/1.0/types.hal @@ -261,8 +261,8 @@ enum OperationType : int32_t { * filter. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} - * the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. * * 3: An {@link OperandType::INT32} scalar, specifying the padding on @@ -290,7 +290,8 @@ enum OperationType : int32_t { * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} * the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. * * 3: An {@link OperandType::INT32} scalar, specifying the implicit @@ -355,8 +356,8 @@ enum OperationType : int32_t { * specifying the filter. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} - * the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. * * 3: An {@link OperandType::INT32} scalar, specifying the padding on @@ -384,8 +385,8 @@ enum OperationType : int32_t { * specifying the filter. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} - * the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. * * 3: An {@link OperandType::INT32} scalar, specifying the implicit @@ -492,8 +493,6 @@ enum OperationType : int32_t { * * Supported value tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT32} - * * {@link OperandType::TENSOR_INT32} - * * {@link OperandType::TENSOR_QUANT8_ASYMM} * * Supported value tensor rank: from 2 * @@ -556,10 +555,10 @@ enum OperationType : int32_t { * of output nodes. * * 2: A 1-D tensor, of shape [num_units], specifying the bias. For input * tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should - * also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor - * of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be - * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and - * bias_scale == input_scale * filter_scale. + * also be of {@link OperandType::TENSOR_FLOAT32}. + * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias should be of {@link OperandType::TENSOR_INT32}, + * with zeroPoint of 0 and bias_scale == input_scale * filter_scale. * * 3: An {@link OperandType::INT32} scalar, and has to be one of the * {@link FusedActivationFunc} values. Specifies the activation to * invoke on the result. diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal index b111d96e96..e867120906 100644 --- a/neuralnetworks/1.2/types.hal +++ b/neuralnetworks/1.2/types.hal @@ -375,8 +375,8 @@ enum OperationType : int32_t { * must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} - * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, @@ -425,7 +425,8 @@ enum OperationType : int32_t { * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, @@ -523,8 +524,8 @@ enum OperationType : int32_t { * must be set to 3. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} - * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, @@ -569,8 +570,8 @@ enum OperationType : int32_t { * specifying the filter. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} - * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, @@ -705,8 +706,8 @@ enum OperationType : int32_t { * * Supported value tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT32} - * * {@link OperandType::TENSOR_INT32} - * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_INT32} (since HAL version 1.2) + * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) * * Supported value tensor rank: from 2 * @@ -772,10 +773,10 @@ enum OperationType : int32_t { * of output nodes. * * 2: A 1-D tensor, of shape [num_units], specifying the bias. For input * tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should - * also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor - * of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be - * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and - * bias_scale == input_scale * filter_scale. + * also be of {@link OperandType::TENSOR_FLOAT32}. + * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias should be of {@link OperandType::TENSOR_INT32}, + * with zeroPoint of 0 and bias_scale == input_scale * filter_scale. * * 3: An {@link OperandType::INT32} scalar, and has to be one of the * {@link FusedActivationFunc} values. Specifies the activation to * invoke on the result. @@ -2659,7 +2660,8 @@ enum OperationType : int32_t { * order of the boxes corresponds with input0. For input0 of type * {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should be of * {@link OperandType::TENSOR_QUANT16_ASYMM}, with zeroPoint of 0 and - * scale of 0.125. Zero num_rois is supported for this tensor. + * scale of 0.125. + * Zero num_rois is supported for this tensor. * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape * [num_rois], specifying the batch index of each box. Boxes with * the same batch index are grouped together. @@ -2686,6 +2688,7 @@ enum OperationType : int32_t { * [num_output_rois], specifying the score of each output box. The boxes * are grouped by batches, but the sequential order in each batch is not * guaranteed. For type of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * guaranteed. For type of {@link OperandType::TENSOR_QUANT8_ASYMM} * the scale and zero point must be the same as input0. * * 1: A 2-D Tensor of the same {@link OperandType} as input1, with shape * [num_output_rois, 4], specifying the coordinates of each @@ -2703,7 +2706,7 @@ enum OperationType : int32_t { BOX_WITH_NMS_LIMIT = 44, /** - * Casts a tensor to a new type. + * Casts a tensor to a type. * * This operation ignores the scale and zeroPoint of quanized tensors, * e.g. it treats a {@link OperandType::TENSOR_QUANT8_ASYMM} input @@ -3141,8 +3144,8 @@ enum OperationType : int32_t { * {@link SymmPerChannelQuantParams}) must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or - * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. For filter tensor * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias @@ -3181,7 +3184,8 @@ enum OperationType : int32_t { * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. For filter tensor * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias @@ -3661,21 +3665,24 @@ enum OperationType : int32_t { * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, - * the scale and zeroPoint can be diffent from the input0 scale and zeroPoint. + * the scales and zeroPoint can be different from input0 scale and zeroPoint. */ PRELU = 71, /** * Quantizes the input tensor. * - * The formula is: + * The formula for {@link OperandType::TENSOR_QUANT8_ASYMM} output tensor is: * * output = max(0, min(255, round(input / scale) + zeroPoint) * - * Supported tensor {@link OperandType}: + * Supported input tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * + * Supported output tensor {@link OperandType}: + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * Supported tensor rank: from 1 * * Inputs: @@ -4325,15 +4332,15 @@ enum OperationType : int32_t { * dimension (SymmPerChannelQuantParams::channelDim) must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or - * {@link OperandType::TENSOR_FLOAT16}, the bias should be of the - * same type. For input tensor of type - * {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be - * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and - * bias_scale == input_scale * filter_scale. For filter tensor of - * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias - * must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of - * 0 and bias_scale of 0. The actual scale of each value 'i' is equal - * to bias_scale[i] = input_scale * filter_scale[i]. + * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the + * same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias should be of {@link OperandType::TENSOR_INT32}, + * with zeroPoint of 0 and bias_scale == input_scale * filter_scale. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, + * the bias must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 + * and bias_scale of 0. The actual scale of each value 'i' is equal to + * bias_scale[i] = input_scale * filter_scale[i]. * * 3: An {@link OperandType::INT32} scalar, specifying the padding on * the left, in the ‘width’ dimension. * * 4: An {@link OperandType::INT32} scalar, specifying the padding on @@ -4363,14 +4370,14 @@ enum OperationType : int32_t { * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or * {@link OperandType::TENSOR_FLOAT16}, the bias should be of the - * same type. For input tensor of type - * {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be - * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and - * bias_scale == input_scale * filter_scale. For filter tensor of - * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias - * must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of - * 0 and bias_scale of 0. The actual scale of each value 'i' is equal - * to bias_scale[i] = input_scale * filter_scale[i]. + * same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * the bias should be of {@link OperandType::TENSOR_INT32}, + * with zeroPoint of 0 and bias_scale == input_scale * filter_scale. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, + * the bias must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 + * and bias_scale of 0. The actual scale of each value 'i' is equal to + * bias_scale[i] = input_scale * filter_scale[i]. * * 3: An {@link OperandType::TENSOR_INT32} tensor, specifying the output * tensor shape. * * 4: An {@link OperandType::INT32} scalar, specifying the implicit diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index 84c48139ab..b70bd1bff4 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -110,6 +110,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) + * * {@link OperandType::TENSOR_INT32} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -123,11 +124,13 @@ enum OperationType : int32_t { * * 2: An {@link OperandType::INT32} scalar, and has to be one of the * {@link FusedActivationFunc} values. Specifies the activation to * invoke on the result. + * For a {@link OperandType::TENSOR_INT32} tensor, + * the {@link FusedActivationFunc} must be "NONE". * * Outputs: * * 0: The sum, a tensor of the same {@link OperandType} as input0. * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and - * {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint can be different from inputs' scale and zeroPoint. */ ADD = @1.2::OperationType:ADD, @@ -293,6 +296,18 @@ enum OperationType : int32_t { * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0, * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). * + * Available since HAL version 1.3: + * * Quantized signed (since HAL version 1.3): + * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output. + * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to + * * * input.scale * filter.scale). + * + * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3): + * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, and output. + * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter. + * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0, + * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). + * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could @@ -313,8 +328,9 @@ enum OperationType : int32_t { * must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} - * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} + * and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, @@ -363,7 +379,9 @@ enum OperationType : int32_t { * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} + * and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, @@ -443,6 +461,18 @@ enum OperationType : int32_t { * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0, * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). * + * Available since HAL version 1.3: + * * Quantized signed (since HAL version 1.3): + * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output. + * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to + * * * input.scale * filter.scale). + * + * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3): + * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, and output. + * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter. + * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0, + * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). + * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could @@ -461,8 +491,9 @@ enum OperationType : int32_t { * must be set to 3. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} - * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} + * and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, @@ -507,8 +538,9 @@ enum OperationType : int32_t { * specifying the filter. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} - * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} + * and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, @@ -569,6 +601,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -589,7 +622,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape [batch, height*block_size, * width*block_size, depth/(block_size*block_size)]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ DEPTH_TO_SPACE = @1.2::OperationType:DEPTH_TO_SPACE, @@ -605,6 +639,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_QUANT8_ASYMM} * * {@link OperandType::TENSOR_QUANT8_SYMM} (since HAL version 1.2) * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} (since HAL version 1.2) + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported output tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) @@ -642,9 +677,11 @@ enum OperationType : int32_t { * and an error must be reported. * * Supported value tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.3) * * {@link OperandType::TENSOR_FLOAT32} - * * {@link OperandType::TENSOR_INT32} - * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_INT32} (since HAL version 1.2) + * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported value tensor rank: from 2 * @@ -658,7 +695,8 @@ enum OperationType : int32_t { * * 0: A n-D tensor with the same rank and shape as the Values * tensor, except for the first dimension which has the same size * as Lookups' only dimension. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input1. */ EMBEDDING_LOOKUP = @1.2::OperationType:EMBEDDING_LOOKUP, @@ -693,6 +731,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4. * @@ -710,10 +749,11 @@ enum OperationType : int32_t { * of output nodes. * * 2: A 1-D tensor, of shape [num_units], specifying the bias. For input * tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should - * also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor - * of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be - * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and - * bias_scale == input_scale * filter_scale. + * also be of {@link OperandType::TENSOR_FLOAT32}. + * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} + * and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, + * the bias should be of {@link OperandType::TENSOR_INT32}, + * with zeroPoint of 0 and bias_scale == input_scale * filter_scale. * * 3: An {@link OperandType::INT32} scalar, and has to be one of the * {@link FusedActivationFunc} values. Specifies the activation to * invoke on the result. @@ -798,6 +838,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * Tensors with rank less than 4 are only supported since HAL version 1.2. @@ -814,6 +855,8 @@ enum OperationType : int32_t { * * 0: A tensor of the same {@link OperandType} and same shape as input0. * For {@link OperandType::TENSOR_QUANT8_ASYMM}, * the scale must be 1.f / 128 and the zeroPoint must be 128. + * For {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, + * the scale must be 1.f / 128 and the zeroPoint must be 0. */ L2_NORMALIZATION = @1.2::OperationType:L2_NORMALIZATION, @@ -1507,6 +1550,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -1549,7 +1593,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, new_height, new_width, depth]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ RESIZE_BILINEAR = @1.2::OperationType:RESIZE_BILINEAR, @@ -1624,6 +1669,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4. * Tensors with rank other than 2 or 4 are only supported since HAL version 1.2. @@ -1632,9 +1678,10 @@ enum OperationType : int32_t { * * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped. * Since HAL version 1.2, this tensor may be zero-sized. * * 1: A scalar, specifying the positive scaling factor for the exponent, - * beta. If input0 is of {@link OperandType::TENSOR_FLOAT32} or - * {@link OperandType::TENSOR_QUANT8_ASYMM}, the scalar must be of - * {@link OperandType::FLOAT32}. + * beta. If input0 is of {@link OperandType::TENSOR_FLOAT32}, + * {@link OperandType::TENSOR_QUANT8_ASYMM} or + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, the scalar + * must be of {@link OperandType::FLOAT32}. * If input0 is of {@link OperandType::TENSOR_FLOAT16}, then the * scalar must be of {@link OperandType::FLOAT16}. * * 2: An optional {@link OperandType::INT32} scalar, default to -1, @@ -1647,6 +1694,8 @@ enum OperationType : int32_t { * * 0: The output tensor of same shape as input0. * For {@link OperandType::TENSOR_QUANT8_ASYMM}, * the scale must be 1.f / 256 and the zeroPoint must be 0. + * For {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, + * the scale must be 1.f / 256 and the zeroPoint must be -128. */ SOFTMAX = @1.2::OperationType:SOFTMAX, @@ -1668,6 +1717,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -1688,7 +1738,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape [batches, height/block_size, * width/block_size, depth_in*block_size*block_size]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ SPACE_TO_DEPTH = @1.2::OperationType:SPACE_TO_DEPTH, @@ -1812,6 +1863,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -1830,7 +1882,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ BATCH_TO_SPACE_ND = @1.2::OperationType:BATCH_TO_SPACE_ND, @@ -1925,6 +1978,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * (full support since HAL version 1.2, see the output section) * * Supported tensor rank: up to 4 @@ -1947,7 +2001,8 @@ enum OperationType : int32_t { * of the padding: * output0.dimension[i] = * padding[i, 0] + input0.dimension[i] + padding[i, 1] - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * NOTE: Before HAL version 1.2, the pad value for @@ -1971,6 +2026,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * (full support since HAL version 1.2, see the output section) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. @@ -1998,7 +2054,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * NOTE: Before HAL version 1.2, the pad value for @@ -2151,6 +2208,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -2162,7 +2220,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ TRANSPOSE = @1.2::OperationType:TRANSPOSE, @@ -2192,6 +2251,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -2216,6 +2276,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -2257,7 +2318,8 @@ enum OperationType : int32_t { * and height, dw and dh is the log-scale relative correction factor * for the width and height. For input0 of type * {@link OperandType::TENSOR_QUANT16_ASYMM}, this tensor should be - * of {@link OperandType::TENSOR_QUANT8_ASYMM}. Zero num_rois is + * of {@link OperandType::TENSOR_QUANT8_ASYMM} or + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}. Zero num_rois is * supported for this tensor. * * 2: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape * [num_rois], specifying the batch index of each box. Boxes with @@ -2612,6 +2674,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Inputs: * * 0: A 2-D Tensor of shape [num_rois, num_classes], specifying the score @@ -2623,7 +2686,11 @@ enum OperationType : int32_t { * order of the boxes corresponds with input0. For input0 of type * {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should be of * {@link OperandType::TENSOR_QUANT16_ASYMM}, with zeroPoint of 0 and - * scale of 0.125. Zero num_rois is supported for this tensor. + * scale of 0.125. + * For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, + * this tensor should be of {@link OperandType::TENSOR_QUANT16_ASYMM}, + * with zeroPoint of -128 and scale of 0.125. + * Zero num_rois is supported for this tensor. * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape * [num_rois], specifying the batch index of each box. Boxes with * the same batch index are grouped together. @@ -2650,6 +2717,8 @@ enum OperationType : int32_t { * [num_output_rois], specifying the score of each output box. The boxes * are grouped by batches, but the sequential order in each batch is not * guaranteed. For type of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * guaranteed. For type of {@link OperandType::TENSOR_QUANT8_ASYMM} + * or {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, * the scale and zero point must be the same as input0. * * 1: A 2-D Tensor of the same {@link OperandType} as input1, with shape * [num_output_rois, 4], specifying the coordinates of each @@ -2667,7 +2736,7 @@ enum OperationType : int32_t { BOX_WITH_NMS_LIMIT = @1.2::OperationType:BOX_WITH_NMS_LIMIT, /** - * Casts a tensor to a new type. + * Casts a tensor to a type. * * This operation ignores the scale and zeroPoint of quanized tensors, * e.g. it treats a {@link OperandType::TENSOR_QUANT8_ASYMM} input @@ -2678,6 +2747,14 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Since HAL version 1.3, casting tensors of the following + * {@link OperandType} to the same {@link OperandType} is supported: + * * {@link OperandType::TENSOR_BOOL8} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT16_ASYMM} + * * {@link OperandType::TENSOR_QUANT16_SYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} + * * {@link OperandType::TENSOR_QUANT8_SYMM} * * Supported tensor rank: from 1 * @@ -2708,6 +2785,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -2722,7 +2800,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} and same shape as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ CHANNEL_SHUFFLE = @1.2::OperationType:CHANNEL_SHUFFLE, @@ -2816,6 +2895,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -2861,6 +2941,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -2872,7 +2953,8 @@ enum OperationType : int32_t { * Outputs: * * 0: An (n + 1)-D tensor with the same {@link OperandType} and data as * input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ EXPAND_DIMS = @1.2::OperationType:EXPAND_DIMS, @@ -2896,6 +2978,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -2910,7 +2993,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: An (n + k - 1)-D tensor with the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ GATHER = @1.2::OperationType:GATHER, @@ -2931,6 +3015,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Inputs: * * 0: A 4-D Tensor specifying the score of each anchor at each @@ -2948,11 +3033,13 @@ enum OperationType : int32_t { * dimensions is the channel dimension. * * 2: A 2-D Tensor of shape [num_anchors, 4], specifying the shape of each * predefined anchor, with format [x1, y1, x2, y2]. For input0 of type - * {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should be of + * {@link OperandType::TENSOR_QUANT8_ASYMM} or + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, this tensor should be of * {@link OperandType::TENSOR_QUANT16_SYMM}, with scale of 0.125. * * 3: A 2-D Tensor of shape [batches, 2], specifying the size of * each image in the batch, with format [image_height, image_width]. - * For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM}, this + * For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM} or + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, this * tensor should be of {@link OperandType::TENSOR_QUANT16_SYMM}, with * scale of 0.125. * * 4: An {@link OperandType::FLOAT32} scalar, specifying the ratio @@ -2979,7 +3066,8 @@ enum OperationType : int32_t { * [num_output_rois], specifying the score of each output box. * The boxes are grouped by batches, but the sequential order in * each batch is not guaranteed. For type of - * {@link OperandType::TENSOR_QUANT8_ASYMM}, the scale and zero + * {@link OperandType::TENSOR_QUANT8_ASYMM} or + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, the scale and zero * point must be the same as input0. * * 1: A tensor of the same {@link OperandType} as input3, of shape * [num_output_rois, 4], specifying the coordinates of each output @@ -3002,6 +3090,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -3025,6 +3114,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -3081,12 +3171,23 @@ enum OperationType : int32_t { * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to * * * input.scale * filter.scale). * + * * Quantized signed (since HAL version 1.3): + * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output. + * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to + * * * input.scale * filter.scale). + * * * Quantized with symmetric per channel quantization for the filter: * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, and output. * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter. * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0, * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). * + * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3): + * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, and output. + * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter. + * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0, + * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). + * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could @@ -3105,8 +3206,9 @@ enum OperationType : int32_t { * {@link SymmPerChannelQuantParams}) must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or - * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. For filter tensor * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias @@ -3145,7 +3247,9 @@ enum OperationType : int32_t { * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same - * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. For filter tensor * of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias @@ -3170,7 +3274,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, out_height, out_width, depth_out]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint can be different from inputs' scale and zeroPoint. */ GROUPED_CONV_2D = @1.2::OperationType:GROUPED_CONV_2D, @@ -3190,6 +3295,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -3206,13 +3312,18 @@ enum OperationType : int32_t { * {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should * be of {@link OperandType::TENSOR_QUANT16_ASYMM}, with zeroPoint * of 0 and scale of 0.125. + * For input0 of type + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, this tensor + * should be of {@link OperandType::TENSOR_QUANT16_ASYMM}, with + * zeroPoint of -128 and scale of 0.125. * * 2: An {@link OperandType::BOOL} scalar, set to true to specify * NCHW data layout for input0. Set to false for NHWC. * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0, with shape * [num_boxes, num_keypoints], specifying score of the keypoints. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} or + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint can be different from input0 scale and zeroPoint. * * 1: A tensor of the same {@link OperandType} as input1, with shape * [num_boxes, num_keypoints, 2], specifying the location of @@ -3283,6 +3394,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -3307,6 +3419,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -3434,6 +3547,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1. * @@ -3446,7 +3560,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint can be different from inputs' scale and zeroPoint. */ MAXIMUM = @1.2::OperationType:MAXIMUM, @@ -3459,6 +3574,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1. * @@ -3471,7 +3587,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint can be different from inputs' scale and zeroPoint. */ MINIMUM = @1.2::OperationType:MINIMUM, @@ -3503,6 +3620,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -3526,6 +3644,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -3543,7 +3662,8 @@ enum OperationType : int32_t { * pad value must be of {@link OperandType::FLOAT16}. * For input tensor of {@link OperandType::TENSOR_FLOAT32}, the * pad value must be of {@link OperandType::FLOAT32}. - * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, + * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, * the pad value must be of {@link OperandType::INT32}. The * scale and zeroPoint are assumed to be the same as in input0. * @@ -3555,7 +3675,8 @@ enum OperationType : int32_t { * of the padding: * output0.dimension[i] = * padding[i, 0] + input0.dimension[i] + padding[i, 1] - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ PAD_V2 = @1.2::OperationType:PAD_V2, @@ -3614,6 +3735,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -3624,22 +3746,32 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, - * the scale and zeroPoint can be diffent from the input0 scale and zeroPoint. + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, + * the scales and zeroPoint can be different from input0 scale and zeroPoint. */ PRELU = @1.2::OperationType:PRELU, /** * Quantizes the input tensor. * - * The formula is: + * The formula for {@link OperandType::TENSOR_QUANT8_ASYMM} output tensor is: * * output = max(0, min(255, round(input / scale) + zeroPoint) * - * Supported tensor {@link OperandType}: + * The formula for {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} output + * tensor is: + * + * output = max(-128, min(127, round(input / scale) + zeroPoint) + * + * Supported input tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * + * Supported output tensor {@link OperandType}: + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) + * * Supported tensor rank: from 1 * * Inputs: @@ -3647,7 +3779,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: The output tensor of same shape as input0, but with - * {@link OperandType::TENSOR_QUANT8_ASYMM}. + * {@link OperandType::TENSOR_QUANT8_ASYMM} or. + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}. */ QUANTIZE = @1.2::OperationType:QUANTIZE, @@ -3955,6 +4088,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -3993,7 +4127,8 @@ enum OperationType : int32_t { * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. The output * shape is [num_rois, out_height, out_width, depth]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint can be different from the input0 scale and zeroPoint. */ ROI_ALIGN = @1.2::OperationType:ROI_ALIGN, @@ -4014,6 +4149,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -4024,7 +4160,8 @@ enum OperationType : int32_t { * * 0: A 4-D tensor, specifying the feature map. * * 1: A 2-D Tensor of shape [num_rois, 4], specifying the locations of * the regions of interest, each line with format [x1, y1, x2, y2]. - * For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM}, + * For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * this tensor should be of {@link OperandType::TENSOR_QUANT16_ASYMM}, * with zeroPoint of 0 and scale of 0.125. * * 2: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape @@ -4044,7 +4181,8 @@ enum OperationType : int32_t { * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. The output * shape is [num_rois, out_height, out_width, depth]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ ROI_POOLING = @1.2::OperationType:ROI_POOLING, @@ -4133,6 +4271,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -4145,7 +4284,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: An n-D tensor of the same type as the input containing the slice. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * its scale and zeroPoint has to be same as the input0 scale and zeroPoint. */ SLICE = @1.2::OperationType:SLICE, @@ -4158,6 +4298,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -4170,7 +4311,8 @@ enum OperationType : int32_t { * * Outputs: * * 0 ~ (num_splits - 1): Resulting subtensors. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ SPLIT = @1.2::OperationType:SPLIT, @@ -4206,6 +4348,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -4216,7 +4359,8 @@ enum OperationType : int32_t { * * Outputs: * * 0: A tiled tensor of the same {@link OperandType} and rank as `input`. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ TILE = @1.2::OperationType:TILE, @@ -4232,6 +4376,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: from 1 * @@ -4243,7 +4388,8 @@ enum OperationType : int32_t { * Outputs: * * 0: An n-D tensor of the same type as the input, containing the k * largest elements along each last dimensional slice. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * 1: An n-D tensor of type {@link OperandType::TENSOR_INT32} * containing the indices of values within the last dimension of input. @@ -4278,6 +4424,18 @@ enum OperationType : int32_t { * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0, * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). * + * Available since HAL version 1.3: + * * Quantized signed (since HAL version 1.3): + * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output. + * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to + * * * input.scale * filter.scale). + * + * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3): + * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, and output. + * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter. + * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0, + * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). + * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could @@ -4295,15 +4453,16 @@ enum OperationType : int32_t { * dimension (SymmPerChannelQuantParams::channelDim) must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or - * {@link OperandType::TENSOR_FLOAT16}, the bias should be of the - * same type. For input tensor of type - * {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be - * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and - * bias_scale == input_scale * filter_scale. For filter tensor of - * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias - * must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of - * 0 and bias_scale of 0. The actual scale of each value 'i' is equal - * to bias_scale[i] = input_scale * filter_scale[i]. + * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the + * same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} + * and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, + * the bias should be of {@link OperandType::TENSOR_INT32}, + * with zeroPoint of 0 and bias_scale == input_scale * filter_scale. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, + * the bias must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 + * and bias_scale of 0. The actual scale of each value 'i' is equal to + * bias_scale[i] = input_scale * filter_scale[i]. * * 3: An {@link OperandType::INT32} scalar, specifying the padding on * the left, in the ‘width’ dimension. * * 4: An {@link OperandType::INT32} scalar, specifying the padding on @@ -4333,14 +4492,15 @@ enum OperationType : int32_t { * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} or * {@link OperandType::TENSOR_FLOAT16}, the bias should be of the - * same type. For input tensor of type - * {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be - * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and - * bias_scale == input_scale * filter_scale. For filter tensor of - * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias - * must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of - * 0 and bias_scale of 0. The actual scale of each value 'i' is equal - * to bias_scale[i] = input_scale * filter_scale[i]. + * same type. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} + * and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, + * the bias should be of {@link OperandType::TENSOR_INT32}, + * with zeroPoint of 0 and bias_scale == input_scale * filter_scale. + * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, + * the bias must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 + * and bias_scale of 0. The actual scale of each value 'i' is equal to + * bias_scale[i] = input_scale * filter_scale[i]. * * 3: An {@link OperandType::TENSOR_INT32} tensor, specifying the output * tensor shape. * * 4: An {@link OperandType::INT32} scalar, specifying the implicit @@ -4359,7 +4519,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, out_height, out_width, depth_out]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint can be different from inputs' scale and zeroPoint. */ TRANSPOSE_CONV_2D = @1.2::OperationType:TRANSPOSE_CONV_2D, @@ -4539,6 +4700,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -4578,7 +4740,8 @@ enum OperationType : int32_t { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, new_height, new_width, depth]. - * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, + * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and + * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. */ RESIZE_NEAREST_NEIGHBOR = @1.2::OperationType:RESIZE_NEAREST_NEIGHBOR, From f53a4e2ff359fc256bbda07e7e2f202364c17266 Mon Sep 17 00:00:00 2001 From: chrisweir Date: Tue, 19 Nov 2019 10:23:37 -0800 Subject: [PATCH 0396/1022] Add VTS tests for EFF/RTR Remote transmission request, and extended format id's require testing to verify that the feature works correctly. Also included is a fix which correctly sets the EFF and RTR flags of the canfd_frame object based on the state of the CanMessage object. A readability change is made to the types.hal which improves clarity of the way filters are defined. Bug: 146173498 Test: run the VTS tests in vts/functional - verify that they pass Change-Id: I9892a2e2465b8c381774e7ee277bfa8660f25028 --- automotive/can/1.0/default/CanBus.cpp | 29 +- automotive/can/1.0/types.hal | 23 +- .../functional/VtsHalCanBusV1_0TargetTest.cpp | 16 +- .../VtsHalCanBusVirtualV1_0TargetTest.cpp | 634 +++++++++++++++++- 4 files changed, 639 insertions(+), 63 deletions(-) diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp index 454ab008ef..8fb09eb10c 100644 --- a/automotive/can/1.0/default/CanBus.cpp +++ b/automotive/can/1.0/default/CanBus.cpp @@ -42,6 +42,8 @@ Return CanBus::send(const CanMessage& message) { struct canfd_frame frame = {}; frame.can_id = message.id; + if (message.isExtendedId) frame.can_id |= CAN_EFF_FLAG; + if (message.remoteTransmissionRequest) frame.can_id |= CAN_RTR_FLAG; frame.len = message.payload.size(); memcpy(frame.data, message.payload.data(), message.payload.size()); @@ -226,8 +228,8 @@ bool CanBus::down() { static bool satisfiesFilterFlag(FilterFlag filterFlag, bool flag) { // TODO(b/144458917) add testing for this to VTS tests if (filterFlag == FilterFlag::DONT_CARE) return true; - if (filterFlag == FilterFlag::REQUIRE) return flag; - if (filterFlag == FilterFlag::EXCLUDE) return !flag; + if (filterFlag == FilterFlag::SET) return flag; + if (filterFlag == FilterFlag::NOT_SET) return !flag; return false; } @@ -241,25 +243,26 @@ static bool satisfiesFilterFlag(FilterFlag filterFlag, bool flag) { * \param id Message id to filter * \return true if the message id matches the filter, false otherwise */ -static bool match(const hidl_vec& filter, CanMessageId id, bool isExtendedId, - bool isRtr) { +static bool match(const hidl_vec& filter, CanMessageId id, bool isRtr, + bool isExtendedId) { if (filter.size() == 0) return true; - bool anyNonInvertedPresent = false; - bool anyNonInvertedSatisfied = false; + bool anyNonExcludeRulePresent = false; + bool anyNonExcludeRuleSatisfied = false; for (auto& rule : filter) { - const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted && + const bool satisfied = ((id & rule.mask) == rule.id) && satisfiesFilterFlag(rule.rtr, isRtr) && satisfiesFilterFlag(rule.extendedFormat, isExtendedId); - if (rule.inverted) { - // Any inverted (blacklist) rule not being satisfied invalidates the whole filter set. - if (!satisfied) return false; + + if (rule.exclude) { + // Any excluded (blacklist) rule not being satisfied invalidates the whole filter set. + if (satisfied) return false; } else { - anyNonInvertedPresent = true; - if (satisfied) anyNonInvertedSatisfied = true; + anyNonExcludeRulePresent = true; + if (satisfied) anyNonExcludeRuleSatisfied = true; } } - return !anyNonInvertedPresent || anyNonInvertedSatisfied; + return !anyNonExcludeRulePresent || anyNonExcludeRuleSatisfied; } void CanBus::notifyErrorListeners(ErrorEvent err, bool isFatal) { diff --git a/automotive/can/1.0/types.hal b/automotive/can/1.0/types.hal index f09c9403c1..5eeed53349 100644 --- a/automotive/can/1.0/types.hal +++ b/automotive/can/1.0/types.hal @@ -73,23 +73,22 @@ struct CanMessage { * Single filter rule for CAN messages. * * A filter is satisfied if: - * ((receivedId & mask) == (id & mask)) == !inverted + * ((receivedId & mask) == (id & mask)) == !exclude * - * In order for set of filters to match, at least one non-inverted filters must match (if there is - * one) and all inverted filters must match. In other words: - * - a single matching non-inverted filter makes the whole set matching; - * - a single non-matching inverted filter makes the whole set non-matching. - * - * Additional less common options for filtering include: - * rtr - Remote Transmission Request; another ECU requests DLC bytes of data on this message ID - * extendedFormat - 29 bit message ID is used instead of 11 bits + * In order for set of filters to match, at least one non-exclude filters must match (if there is + * one) and all exclude filters must match. In other words: + * - a single matching non-exclude filter makes the whole set matching; + * - a single non-matching excluded filter makes the whole set non-matching. */ struct CanMessageFilter { CanMessageId id; uint32_t mask; - bool inverted; + /** Remote Transmission Request; another ECU requests bytes of data on this message ID */ FilterFlag rtr; + /** 29 bit message ID is used instead of 11 bits */ FilterFlag extendedFormat; + /** 'exclude' *DOES* apply to rtr and extendedFormat! */ + bool exclude; }; @@ -100,9 +99,9 @@ enum FilterFlag : uint8_t { /** Default, FilterFlag doesn't effect what messages filtered */ DONT_CARE = 0, /** This FilterFlag MUST be present in received messages to pass though the filter */ - REQUIRE, + SET, /** This FilterFlag must NOT be present in received messages to pass though the filter */ - EXCLUDE, + NOT_SET, }; enum Result : uint8_t { diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp index 8deaed642b..cdea8b6eec 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp @@ -78,7 +78,7 @@ sp CanBusHalTest::listenForErrors(const sp& lis TEST_F(CanBusHalTest, SendNoPayload) { CanMessage msg = {}; msg.id = 0x123; - + ASSERT_NE(mCanBus, nullptr); const auto result = mCanBus->send(msg); ASSERT_EQ(Result::OK, result); } @@ -118,9 +118,9 @@ TEST_F(CanBusHalTest, ListenNoFilter) { TEST_F(CanBusHalTest, ListenSomeFilter) { hidl_vec filters = { - {0x123, 0x1FF, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE}, - {0x001, 0x00F, true, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE}, - {0x200, 0x100, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE}, + {0x123, 0x1FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false}, + {0x001, 0x00F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true}, + {0x200, 0x100, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false}, }; const auto [result, closeHandle] = listen(filters, new CanMessageListener()); @@ -171,14 +171,20 @@ TEST_F(CanBusHalTest, DontCloseErrorListener) { } // namespace android::hardware::automotive::can::V1_0::vts /** + * This test requires that you bring up a valid bus first. + * + * Before running: + * mma -j && adb root && adb remount && adb sync + * * Example manual invocation: * adb shell /data/nativetest64/VtsHalCanBusV1_0TargetTest/VtsHalCanBusV1_0TargetTest \ - * --hal_service_instance=android.hardware.automotive.can@1.0::ICanBus/test + * --hal_service_instance=android.hardware.automotive.can@1.0::ICanBus/ */ int main(int argc, char** argv) { using android::hardware::automotive::can::V1_0::ICanBus; using android::hardware::automotive::can::V1_0::vts::gEnv; using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment; + setenv("TREBLE_TESTING_OVERRIDE", "true", true); android::base::SetDefaultTag("CanBusVts"); android::base::SetMinimumLogSeverity(android::base::VERBOSE); gEnv = new SimpleHidlEnvironment; diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp index ca661feef0..efaad53a78 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp @@ -121,6 +121,7 @@ struct Bus { } void send(const CanMessage& msg) { + EXPECT_NE(mBus, nullptr); const auto result = mBus->send(msg); EXPECT_EQ(Result::OK, result); } @@ -155,9 +156,11 @@ bool CanBusVirtualHalTest::mVirtualSupported; hidl_vec CanBusVirtualHalTest::mBusNames; bool CanBusVirtualHalTest::mTestCaseInitialized = false; -static CanMessage makeMessage(CanMessageId id) { +static CanMessage makeMessage(CanMessageId id, bool rtr, bool extended) { CanMessage msg = {}; msg.id = id; + msg.remoteTransmissionRequest = rtr; + msg.isExtendedId = extended; return msg; } @@ -251,56 +254,621 @@ TEST_F(CanBusVirtualHalTest, DownOneOfTwo) { bus1.send({}); } -TEST_F(CanBusVirtualHalTest, Filter) { +TEST_F(CanBusVirtualHalTest, FilterPositive) { if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses."; auto bus1 = makeBus(); auto bus2 = makeBus(); + /* clang-format off */ + /* id, mask, rtr, eff, exclude */ hidl_vec filterPositive = { - {0x101, 0x100, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE}, - {0x010, 0x0F0, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE}, + {0x334, 0x73F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false}, + {0x49D, 0x700, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false}, + {0x325, 0x7FC, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, false}, + {0x246, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, false}, + {0x1A2, 0x7FB, FilterFlag::SET, FilterFlag::NOT_SET, false}, + {0x607, 0x7C9, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, false}, + {0x7F4, 0x777, FilterFlag::NOT_SET, FilterFlag::NOT_SET, false}, + {0x1BF19EAF, 0x10F0F0F0, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false}, + {0x12E99200, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, false}, + {0x06B70270, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::DONT_CARE, false}, + {0x096CFD2B, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, false}, + {0x1BDCB008, 0x0F0F0F0F, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, false}, + {0x08318B46, 0x10F0F0F0, FilterFlag::NOT_SET, FilterFlag::SET, false}, + {0x06B, 0x70F, FilterFlag::DONT_CARE, FilterFlag::SET, false}, + {0x750, 0x70F, FilterFlag::SET, FilterFlag::SET, false}, + {0x5CF, 0x70F, FilterFlag::NOT_SET, FilterFlag::SET, false}, }; + /* clang-format on */ auto listenerPositive = bus2.listen(filterPositive); - hidl_vec filterNegative = { - {0x123, 0x0FF, true, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE}, - {0x004, 0x00F, true, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE}, - }; - auto listenerNegative = bus2.listen(filterNegative); + // 334:73F, DNC, DNC + bus1.send(makeMessage(0x3F4, false, false)); + bus1.send(makeMessage(0x334, false, true)); + bus1.send(makeMessage(0x374, true, false)); + bus1.send(makeMessage(0x3F4, true, true)); - bus1.send(makeMessage(0)); - bus1.send(makeMessage(0x1A0)); - bus1.send(makeMessage(0x1A1)); - bus1.send(makeMessage(0x2A0)); - bus1.send(makeMessage(0x3A0)); - bus1.send(makeMessage(0x010)); - bus1.send(makeMessage(0x123)); - bus1.send(makeMessage(0x023)); - bus1.send(makeMessage(0x124)); + // 49D:700, DNC, DNC + bus1.send(makeMessage(0x404, false, false)); + bus1.send(makeMessage(0x4A5, false, true)); + bus1.send(makeMessage(0x4FF, true, false)); + bus1.send(makeMessage(0x46B, true, true)); + + // 325:7FC, DNC, NS + bus1.send(makeMessage(0x324, false, false)); + bus1.send(makeMessage(0x325, false, true)); // filtered out + bus1.send(makeMessage(0x326, true, false)); + bus1.send(makeMessage(0x327, true, true)); // filtered out + + // 246:7FF, SET, DNC + bus1.send(makeMessage(0x246, false, false)); // filtered out + bus1.send(makeMessage(0x246, false, true)); // filtered out + bus1.send(makeMessage(0x246, true, false)); + bus1.send(makeMessage(0x246, true, true)); + + // 1A2:7FB, SET, NS + bus1.send(makeMessage(0x1A2, false, false)); // filtered out + bus1.send(makeMessage(0x1A6, false, true)); // filtered out + bus1.send(makeMessage(0x1A2, true, false)); + bus1.send(makeMessage(0x1A6, true, true)); // filtered out + + // 607:7C9, NS, DNC + bus1.send(makeMessage(0x607, false, false)); + bus1.send(makeMessage(0x613, false, true)); + bus1.send(makeMessage(0x625, true, false)); // filtered out + bus1.send(makeMessage(0x631, true, true)); // filtered out + + // 7F4:777, NS, NS + bus1.send(makeMessage(0x774, false, false)); + bus1.send(makeMessage(0x7F4, false, true)); // filtered out + bus1.send(makeMessage(0x77C, true, false)); // filtered out + bus1.send(makeMessage(0x7FC, true, false)); // filtered out + + // 1BF19EAF:10F0F0F0, DNC, DNC + bus1.send(makeMessage(0x11F293A4, false, false)); + bus1.send(makeMessage(0x15F697A8, false, true)); + bus1.send(makeMessage(0x19FA9BAC, true, false)); + bus1.send(makeMessage(0x1DFE9FA0, true, true)); + + // 12E99200:1FFFFFFF, DNC, SET + bus1.send(makeMessage(0x12E99200, false, false)); // filtered out + bus1.send(makeMessage(0x12E99200, false, true)); + bus1.send(makeMessage(0x12E99200, true, false)); // filtered out + bus1.send(makeMessage(0x12E99200, true, true)); + + // 06B70270:1FFFFFFF, SET, DNC + bus1.send(makeMessage(0x06B70270, false, false)); // filtered out + bus1.send(makeMessage(0x06B70270, false, true)); // filtered out + bus1.send(makeMessage(0x06B70270, true, false)); + bus1.send(makeMessage(0x06B70270, true, true)); + + // 096CFD2B:1FFFFFFF, SET, SET + bus1.send(makeMessage(0x096CFD2B, false, false)); // filtered out + bus1.send(makeMessage(0x096CFD2B, false, true)); // filtered out + bus1.send(makeMessage(0x096CFD2B, true, false)); // filtered out + bus1.send(makeMessage(0x096CFD2B, true, true)); + + // 1BDCB008:0F0F0F0F, NS, DNC + bus1.send(makeMessage(0x1B2C3048, false, false)); + bus1.send(makeMessage(0x0B5C6078, false, true)); + bus1.send(makeMessage(0x1B8C90A8, true, false)); // filtered out + bus1.send(makeMessage(0x0BBCC0D8, true, true)); // filtered out + + // 08318B46:10F0F0F0, NS, SET + bus1.send(makeMessage(0x0F3E8D4C, false, false)); // filtered out + bus1.send(makeMessage(0x0B3A8948, false, true)); + bus1.send(makeMessage(0x07368544, true, false)); // filtered out + bus1.send(makeMessage(0x03328140, true, true)); // filtered out + + // 06B:70F, DNC, SET + bus1.send(makeMessage(0x00B, false, false)); // filtered out + bus1.send(makeMessage(0x04B, false, true)); + bus1.send(makeMessage(0x08B, true, false)); // filtered out + bus1.send(makeMessage(0x0FB, true, true)); + + // 750:70F, SET, SET + bus1.send(makeMessage(0x7F0, false, false)); // filtered out + bus1.send(makeMessage(0x780, false, true)); // filtered out + bus1.send(makeMessage(0x740, true, false)); // filtered out + bus1.send(makeMessage(0x700, true, true)); + + // 5CF:70F, NS, SET + bus1.send(makeMessage(0x51F, false, false)); // filtered out + bus1.send(makeMessage(0x53F, false, true)); + bus1.send(makeMessage(0x57F, true, false)); // filtered out + bus1.send(makeMessage(0x5FF, true, true)); // filtered out std::vector expectedPositive{ - makeMessage(0x1A0), // - makeMessage(0x1A1), // - makeMessage(0x3A0), // - makeMessage(0x010), // - makeMessage(0x123), // - makeMessage(0x124), // + makeMessage(0x3F4, false, false), // 334:73F, DNC, DNC + makeMessage(0x334, false, true), // 334:73F, DNC, DNC + makeMessage(0x374, true, false), // 334:73F, DNC, DNC + makeMessage(0x3F4, true, true), // 334:73F, DNC, DNC + makeMessage(0x404, false, false), // 49D:700, DNC, DNC + makeMessage(0x4A5, false, true), // 49D:700, DNC, DNC + makeMessage(0x4FF, true, false), // 49D:700, DNC, DNC + makeMessage(0x46B, true, true), // 49D:700, DNC, DNC + makeMessage(0x324, false, false), // 325:7FC, DNC, NS + makeMessage(0x326, true, false), // 325:7FC, DNC, NS + makeMessage(0x246, true, false), // 246:7FF, SET, DNC + makeMessage(0x246, true, true), // 246:7FF, SET, DNC + makeMessage(0x1A2, true, false), // 1A2:7FB, SET, NS + makeMessage(0x607, false, false), // 607:7C9, NS, DNC + makeMessage(0x613, false, true), // 607:7C9, NS, DNC + makeMessage(0x774, false, false), // 7F4:777, NS, NS + makeMessage(0x11F293A4, false, false), // 1BF19EAF:10F0F0F0, DNC, DNC + makeMessage(0x15F697A8, false, true), // 1BF19EAF:10F0F0F0, DNC, DNC + makeMessage(0x19FA9BAC, true, false), // 1BF19EAF:10F0F0F0, DNC, DNC + makeMessage(0x1DFE9FA0, true, true), // 1BF19EAF:10F0F0F0, DNC, DNC + makeMessage(0x12E99200, false, true), // 12E99200:1FFFFFFF, DNC, SET + makeMessage(0x12E99200, true, true), // 12E99200:1FFFFFFF, DNC, SET + makeMessage(0x06B70270, true, false), // 06B70270:1FFFFFFF, SET, DNC + makeMessage(0x06B70270, true, true), // 06B70270:1FFFFFFF, SET, DNC + makeMessage(0x096CFD2B, true, true), // 096CFD2B:1FFFFFFF, SET, SET + makeMessage(0x1B2C3048, false, false), // 1BDCB008:0F0F0F0F, NS, DNC + makeMessage(0x0B5C6078, false, true), // 1BDCB008:0F0F0F0F, NS, DNC + makeMessage(0x0B3A8948, false, true), // 08318B46:10F0F0F0, NS, SET + makeMessage(0x04B, false, true), // 06B:70F, DNC, SET + makeMessage(0x0FB, true, true), // 06B:70F, DNC, SET + makeMessage(0x700, true, true), // 750:70F, SET, SET + makeMessage(0x53F, false, true), // 5CF:70F, NS, SET }; + + auto messagesPositive = listenerPositive->fetchMessages(100ms, expectedPositive.size()); + clearTimestamps(messagesPositive); + ASSERT_EQ(expectedPositive, messagesPositive); +} + +TEST_F(CanBusVirtualHalTest, FilterNegative) { + if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses."; + auto bus1 = makeBus(); + auto bus2 = makeBus(); + + /* clang-format off */ + /* id, mask, rtr, eff exclude */ + hidl_vec filterNegative = { + {0x063, 0x7F3, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true}, + {0x0A1, 0x78F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true}, + {0x18B, 0x7E3, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true}, + {0x1EE, 0x7EC, FilterFlag::SET, FilterFlag::DONT_CARE, true}, + {0x23F, 0x7A5, FilterFlag::SET, FilterFlag::NOT_SET, true}, + {0x31F, 0x77F, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true}, + {0x341, 0x77F, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true}, + {0x196573DB, 0x1FFFFF7F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true}, + {0x1CFCB417, 0x1FFFFFEC, FilterFlag::DONT_CARE, FilterFlag::SET, true}, + {0x17CCC433, 0x1FFFFFEC, FilterFlag::SET, FilterFlag::DONT_CARE, true}, + {0x0BC2F508, 0x1FFFFFC3, FilterFlag::SET, FilterFlag::SET, true}, + {0x1179B5D2, 0x1FFFFFC3, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true}, + {0x082AF63D, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true}, + {0x66D, 0x76F, FilterFlag::DONT_CARE, FilterFlag::SET, true}, + {0x748, 0x7CC, FilterFlag::SET, FilterFlag::SET, true}, + {0x784, 0x7CC, FilterFlag::NOT_SET, FilterFlag::SET, true}, + }; + /* clang-format on */ + + auto listenerNegative = bus2.listen(filterNegative); + + // 063:7F3, DNC, DNC: ~06[3,7,B,F] + bus1.send(makeMessage(0x063, false, false)); // filtered out + bus1.send(makeMessage(0x060, false, true)); + bus1.send(makeMessage(0x05B, true, false)); + bus1.send(makeMessage(0x06F, true, true)); // filtered out + + // 0A1:78F, DNC, DNC: ~0[8-F]1 + bus1.send(makeMessage(0x081, false, false)); // filtered out + bus1.send(makeMessage(0x031, false, true)); + bus1.send(makeMessage(0x061, true, false)); + bus1.send(makeMessage(0x071, true, true)); + + // 18B:7E3, DNC, NS: ~1[8-9][7,B,F] + bus1.send(makeMessage(0x18B, false, false)); // filtered out + bus1.send(makeMessage(0x188, false, true)); + bus1.send(makeMessage(0x123, true, false)); + bus1.send(makeMessage(0x1D5, true, true)); + + // 1EE:7EC, SET, DNC: ~1[E-F][C-F] + bus1.send(makeMessage(0x17E, false, false)); + bus1.send(makeMessage(0x138, false, true)); + bus1.send(makeMessage(0x123, true, false)); + bus1.send(makeMessage(0x1EC, true, true)); // filtered out + + // 23F:7A5, SET, NS: ~2[2,3,6,7][5,7,D,F] + bus1.send(makeMessage(0x222, false, false)); + bus1.send(makeMessage(0x275, false, true)); + bus1.send(makeMessage(0x23f, true, false)); // filtered out + bus1.send(makeMessage(0x241, true, false)); + bus1.send(makeMessage(0x2FF, true, true)); + + // 31F:77F, NS, DNC: ~3[1,9]F + bus1.send(makeMessage(0x32F, false, false)); + bus1.send(makeMessage(0x31F, false, true)); // filtered out + bus1.send(makeMessage(0x36F, false, true)); + bus1.send(makeMessage(0x31F, true, false)); + bus1.send(makeMessage(0x3F3, true, true)); + + // 341:77F, NS, NS: ~3[4,C]1 + bus1.send(makeMessage(0x341, false, false)); // filtered out + bus1.send(makeMessage(0x352, false, false)); + bus1.send(makeMessage(0x3AA, false, true)); + bus1.send(makeMessage(0x3BC, true, false)); + bus1.send(makeMessage(0x3FF, true, true)); + + // 196573DB:1FFFFF7F, DNC, DNC: ~196573[5,D]B + bus1.send(makeMessage(0x1965733B, false, false)); + bus1.send(makeMessage(0x1965734B, false, true)); + bus1.send(makeMessage(0x1965735B, true, false)); // filtered out + bus1.send(makeMessage(0x1965736B, true, true)); + + // 1CFCB417:1FFFFFEC, DNC, SET: ~1CFCB4[0-1][4-7] + bus1.send(makeMessage(0x1CFCB407, false, false)); + bus1.send(makeMessage(0x1CFCB4FF, false, true)); + bus1.send(makeMessage(0x1CFCB414, true, false)); + bus1.send(makeMessage(0x1CFCB407, true, true)); // filtered out + + // 17CCC433:1FFFFFEC, SET, DNC: ~17CCC4[2-3][0-3] + bus1.send(makeMessage(0x17CCC430, false, false)); + bus1.send(makeMessage(0x17CCC423, false, true)); + bus1.send(makeMessage(0x17CCC420, true, false)); // filtered out + bus1.send(makeMessage(0x17CCC444, true, true)); + + // 0BC2F508:1FFFFFC3, SET, SET: ~5[0-3][0,4,8,C] + bus1.send(makeMessage(0x0BC2F504, false, false)); + bus1.send(makeMessage(0x0BC2F518, false, true)); + bus1.send(makeMessage(0x0BC2F52C, true, false)); + bus1.send(makeMessage(0x0BC2F500, true, true)); // filtered out + bus1.send(makeMessage(0x0BC2F543, true, true)); + + // 1179B5D2:1FFFFFC3, NS, DNC: ~5[C-F][2,6,A,E] + bus1.send(makeMessage(0x1179B5BB, false, false)); + bus1.send(makeMessage(0x1179B5EA, false, true)); // filtered out + bus1.send(makeMessage(0x1179B5C2, true, false)); + bus1.send(makeMessage(0x1179B5DA, true, true)); + + // 082AF63D:1FFFFF6F, NS, SET: ~6[2,3,A,B]D + bus1.send(makeMessage(0x082AF62D, false, false)); + bus1.send(makeMessage(0x082AF63D, false, true)); // filtered out + bus1.send(makeMessage(0x082AF60D, false, true)); + bus1.send(makeMessage(0x082AF6AD, true, false)); + bus1.send(makeMessage(0x082AF6BD, true, true)); + + // 66D:76F, DNC, SET: ~6[6,7,E,F]D + bus1.send(makeMessage(0x66D, false, false)); + bus1.send(makeMessage(0x68D, false, true)); + bus1.send(makeMessage(0x67D, true, false)); + bus1.send(makeMessage(0x6ED, true, true)); // filtered out + + // 748:7CC, SET, SET: ~0x7[4-7][8-F] + bus1.send(makeMessage(0x749, false, false)); + bus1.send(makeMessage(0x75A, false, true)); + bus1.send(makeMessage(0x76B, true, false)); + bus1.send(makeMessage(0x748, true, true)); // filtered out + bus1.send(makeMessage(0x788, true, true)); + + // 784:7CC, NS, SET: ~0x7[8-F][4-7] + bus1.send(makeMessage(0x795, false, false)); + bus1.send(makeMessage(0x784, false, true)); // filtered out + bus1.send(makeMessage(0x71B, false, true)); + bus1.send(makeMessage(0x769, true, false)); + bus1.send(makeMessage(0x784, true, true)); + std::vector expectedNegative{ - makeMessage(0), // - makeMessage(0x1A0), // - makeMessage(0x1A1), // - makeMessage(0x2A0), // - makeMessage(0x3A0), // - makeMessage(0x010), // + makeMessage(0x060, false, true), // 063:7F3, DNC, DNC + makeMessage(0x05B, true, false), // 063:7F3, DNC, DNC + makeMessage(0x031, false, true), // 0A1:78F, DNC, DNC + makeMessage(0x061, true, false), // 0A1:78F, DNC, DNC + makeMessage(0x071, true, true), // 0A1:78F, DNC, DNC + makeMessage(0x188, false, true), // 18B:7E3, DNC, NS + makeMessage(0x123, true, false), // 18B:7E3, DNC, NS + makeMessage(0x1D5, true, true), // 18B:7E3, DNC, NS + makeMessage(0x17E, false, false), // 1EE:7EC, SET, DNC + makeMessage(0x138, false, true), // 1EE:7EC, SET, DNC + makeMessage(0x123, true, false), // 1EE:7EC, SET, DNC + makeMessage(0x222, false, false), // 23F:7A5, SET, NS + makeMessage(0x275, false, true), // 23F:7A5, SET, NS + makeMessage(0x241, true, false), // 23F:7A5, SET, NS + makeMessage(0x2FF, true, true), // 23F:7A5, SET, NS + makeMessage(0x32F, false, false), // 31F:77F, NS, DNC + makeMessage(0x36F, false, true), // 31F:77F, NS, DNC + makeMessage(0x31F, true, false), // 31F:77F, NS, DNC + makeMessage(0x3F3, true, true), // 31F:77F, NS, DNC + makeMessage(0x352, false, false), // 341:77F, NS, NS + makeMessage(0x3AA, false, true), // 341:77F, NS, NS + makeMessage(0x3BC, true, false), // 341:77F, NS, NS + makeMessage(0x3FF, true, true), // 341:77F, NS, NS + makeMessage(0x1965733B, false, false), // 196573DB:1FFFFF7F, DNC, DNC + makeMessage(0x1965734B, false, true), // 196573DB:1FFFFF7F, DNC, DNC + makeMessage(0x1965736B, true, true), // 196573DB:1FFFFF7F, DNC, DNC + makeMessage(0x1CFCB407, false, false), // 1CFCB417:1FFFFFEC, DNC, SET + makeMessage(0x1CFCB4FF, false, true), // 1CFCB417:1FFFFFEC, DNC, SET + makeMessage(0x1CFCB414, true, false), // 1CFCB417:1FFFFFEC, DNC, SET + makeMessage(0x17CCC430, false, false), // 17CCC433:1FFFFFEC, SET, DNC + makeMessage(0x17CCC423, false, true), // 17CCC433:1FFFFFEC, SET, DNC + makeMessage(0x17CCC444, true, true), // 17CCC433:1FFFFFEC, SET, DNC + makeMessage(0x0BC2F504, false, false), // 0BC2F508:1FFFFFC3, SET, SET + makeMessage(0x0BC2F518, false, true), // 0BC2F508:1FFFFFC3, SET, SET + makeMessage(0x0BC2F52C, true, false), // 0BC2F508:1FFFFFC3, SET, SET + makeMessage(0x0BC2F543, true, true), // 0BC2F508:1FFFFFC3, SET, SET + makeMessage(0x1179B5BB, false, false), // 1179B5D2:1FFFFFC3, NS, DNC + makeMessage(0x1179B5C2, true, false), // 1179B5D2:1FFFFFC3, NS, DNC + makeMessage(0x1179B5DA, true, true), // 1179B5D2:1FFFFFC3, NS, DNC + makeMessage(0x082AF62D, false, false), // 082AF63D:1FFFFF6F, NS, SET + makeMessage(0x082AF60D, false, true), // 082AF63D:1FFFFF6F, NS, SET + makeMessage(0x082AF6AD, true, false), // 082AF63D:1FFFFF6F, NS, SET + makeMessage(0x082AF6BD, true, true), // 082AF63D:1FFFFF6F, NS, SET + makeMessage(0x66D, false, false), // 66D:76F, DNC, SET + makeMessage(0x68D, false, true), // 66D:76F, DNC, SET + makeMessage(0x67D, true, false), // 66D:76F, DNC, SET + makeMessage(0x749, false, false), // 748:7CC, SET, SET + makeMessage(0x75A, false, true), // 748:7CC, SET, SET + makeMessage(0x76B, true, false), // 748:7CC, SET, SET + makeMessage(0x788, true, true), // 748:7CC, SET, SET + makeMessage(0x795, false, false), // 784:7CC, NS, SET + makeMessage(0x71B, false, true), // 784:7CC, NS, SET + makeMessage(0x769, true, false), // 784:7CC, NS, SET + makeMessage(0x784, true, true), // 784:7CC, NS, SET }; auto messagesNegative = listenerNegative->fetchMessages(100ms, expectedNegative.size()); - auto messagesPositive = listenerPositive->fetchMessages(100ms, expectedPositive.size()); clearTimestamps(messagesNegative); - clearTimestamps(messagesPositive); ASSERT_EQ(expectedNegative, messagesNegative); - ASSERT_EQ(expectedPositive, messagesPositive); +} + +TEST_F(CanBusVirtualHalTest, FilterMixed) { + if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses."; + auto bus1 = makeBus(); + auto bus2 = makeBus(); + + /* clang-format off */ + /* id, mask, rtr, eff exclude */ + hidl_vec filterMixed = { + {0x000, 0x700, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false}, + {0x0D5, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true}, + {0x046, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true}, + {0x11D89097, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true}, + {0x0AB, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true}, + {0x00D, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true}, + {0x0F82400E, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true}, + {0x08F, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true}, + {0x0BE, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true}, + {0x0A271011, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true}, + {0x0BE, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false}, + + {0x100, 0x700, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, false}, + {0x138, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true}, + {0x1BF, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true}, + {0x13AB6165, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true}, + {0x17A, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true}, + {0x13C, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true}, + {0x102C5197, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true}, + {0x19B, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true}, + {0x1B8, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true}, + {0x0D6D5185, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true}, + {0x1B8, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false}, + + {0x096A2200, 0x1FFFFF00, FilterFlag::DONT_CARE, FilterFlag::SET, false}, + {0x201, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true}, + {0x22A, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true}, + {0x1D1C3238, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true}, + {0x2C0, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true}, + {0x23C, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true}, + {0x016182C6, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true}, + {0x27B, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true}, + {0x2A5, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true}, + {0x160EB24B, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true}, + {0x2A5, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false}, + + {0x300, 0x700, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, false}, + {0x339, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true}, + {0x3D4, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true}, + {0x182263BE, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true}, + {0x327, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true}, + {0x36B, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true}, + {0x1A1D8374, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true}, + {0x319, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true}, + {0x39E, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true}, + {0x1B657332, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true}, + {0x39E, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false}, + + {0x06C5D400, 0x1FFFFF00, FilterFlag::NOT_SET, FilterFlag::SET, false}, + {0x492, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true}, + {0x4EE, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true}, + {0x07725454, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true}, + {0x4D5, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true}, + {0x402, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true}, + {0x139714A7, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true}, + {0x464, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true}, + {0x454, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true}, + {0x0EF4B46F, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true}, + {0x454, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false}, + + {0x500, 0x700, FilterFlag::SET, FilterFlag::DONT_CARE, false}, + {0x503, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true}, + {0x566, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true}, + {0x137605E7, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true}, + {0x564, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true}, + {0x58E, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true}, + {0x05F9052D, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true}, + {0x595, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true}, + {0x563, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true}, + {0x13358537, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true}, + {0x563, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false}, + + {0x600, 0x700, FilterFlag::SET, FilterFlag::NOT_SET, false}, + {0x64D, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true}, + {0x620, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true}, + {0x1069A676, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true}, + {0x62D, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true}, + {0x6C4, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true}, + {0x14C76629, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true}, + {0x689, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true}, + {0x6A4, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true}, + {0x0BCCA6C2, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true}, + {0x6A4, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false}, + + {0x04BB1700, 0x1FFFFF00, FilterFlag::SET, FilterFlag::SET, false}, + {0x784, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true}, + {0x7F9, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true}, + {0x0200F77D, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true}, + {0x783, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true}, + {0x770, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true}, + {0x06602719, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true}, + {0x76B, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true}, + {0x7DF, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true}, + {0x1939E736, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true}, + {0x7DF, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false}, + }; + /* clang-format on */ + + auto listenerMixed = bus2.listen(filterMixed); + + bus1.send(makeMessage(0x000, true, true)); // positive filter + bus1.send(makeMessage(0x0D5, false, false)); + bus1.send(makeMessage(0x046, true, false)); + bus1.send(makeMessage(0x046, false, false)); + bus1.send(makeMessage(0x11D89097, true, true)); + bus1.send(makeMessage(0x11D89097, false, true)); + bus1.send(makeMessage(0x0AB, false, false)); + bus1.send(makeMessage(0x0AB, false, true)); + bus1.send(makeMessage(0x00D, false, false)); + bus1.send(makeMessage(0x0F82400E, false, true)); + bus1.send(makeMessage(0x08F, true, false)); + bus1.send(makeMessage(0x08F, true, true)); + bus1.send(makeMessage(0x0BE, true, false)); + bus1.send(makeMessage(0x0A271011, true, true)); + bus1.send(makeMessage(0x0BE, false, true)); // not filtered + bus1.send(makeMessage(0x100, false, false)); // positive filter + bus1.send(makeMessage(0x138, false, true)); + bus1.send(makeMessage(0x138, true, false)); + bus1.send(makeMessage(0x1BF, false, false)); + bus1.send(makeMessage(0x1BF, true, false)); + bus1.send(makeMessage(0x13AB6165, false, true)); + bus1.send(makeMessage(0x13AB6165, true, true)); + bus1.send(makeMessage(0x17A, false, false)); + bus1.send(makeMessage(0x17A, false, true)); + bus1.send(makeMessage(0x13C, false, false)); + bus1.send(makeMessage(0x102C5197, false, true)); + bus1.send(makeMessage(0x19B, true, false)); + bus1.send(makeMessage(0x19B, true, true)); + bus1.send(makeMessage(0x1B8, true, false)); + bus1.send(makeMessage(0x0D6D5185, true, true)); + bus1.send(makeMessage(0x1B8, false, true)); // not filtered + bus1.send(makeMessage(0x096A2200, false, true)); // positive filter + bus1.send(makeMessage(0x201, false, true)); + bus1.send(makeMessage(0x201, true, false)); + bus1.send(makeMessage(0x22A, false, false)); + bus1.send(makeMessage(0x22A, true, false)); + bus1.send(makeMessage(0x1D1C3238, false, true)); + bus1.send(makeMessage(0x1D1C3238, true, true)); + bus1.send(makeMessage(0x2C0, false, false)); + bus1.send(makeMessage(0x2C0, false, true)); + bus1.send(makeMessage(0x23C, false, false)); + bus1.send(makeMessage(0x016182C6, false, true)); + bus1.send(makeMessage(0x27B, true, false)); + bus1.send(makeMessage(0x27B, true, true)); + bus1.send(makeMessage(0x2A5, true, false)); + bus1.send(makeMessage(0x160EB24B, true, true)); + bus1.send(makeMessage(0x2A5, false, true)); // not filtereed + bus1.send(makeMessage(0x300, false, false)); // positive filter + bus1.send(makeMessage(0x339, false, true)); + bus1.send(makeMessage(0x339, false, false)); + bus1.send(makeMessage(0x3D4, true, false)); + bus1.send(makeMessage(0x182263BE, false, true)); + bus1.send(makeMessage(0x182263BE, true, true)); + bus1.send(makeMessage(0x327, false, false)); + bus1.send(makeMessage(0x327, false, true)); + bus1.send(makeMessage(0x36B, false, false)); + bus1.send(makeMessage(0x1A1D8374, false, true)); + bus1.send(makeMessage(0x319, true, false)); + bus1.send(makeMessage(0x319, true, true)); + bus1.send(makeMessage(0x39E, true, false)); + bus1.send(makeMessage(0x1B657332, true, true)); + bus1.send(makeMessage(0x39E, false, true)); // not filtered + bus1.send(makeMessage(0x06C5D400, false, true)); // positive filter + bus1.send(makeMessage(0x492, false, true)); + bus1.send(makeMessage(0x492, true, false)); + bus1.send(makeMessage(0x4EE, false, false)); + bus1.send(makeMessage(0x4EE, true, false)); + bus1.send(makeMessage(0x07725454, false, true)); + bus1.send(makeMessage(0x07725454, true, true)); + bus1.send(makeMessage(0x4D5, false, false)); + bus1.send(makeMessage(0x4D5, false, true)); + bus1.send(makeMessage(0x402, false, false)); + bus1.send(makeMessage(0x139714A7, false, true)); + bus1.send(makeMessage(0x464, true, false)); + bus1.send(makeMessage(0x464, true, true)); + bus1.send(makeMessage(0x454, true, false)); + bus1.send(makeMessage(0x0EF4B46F, true, true)); + bus1.send(makeMessage(0x454, false, true)); // not filtered + bus1.send(makeMessage(0x500, true, false)); // positive filter + bus1.send(makeMessage(0x503, false, true)); + bus1.send(makeMessage(0x503, true, false)); + bus1.send(makeMessage(0x566, false, false)); + bus1.send(makeMessage(0x566, true, false)); + bus1.send(makeMessage(0x137605E7, false, true)); + bus1.send(makeMessage(0x137605E7, true, true)); + bus1.send(makeMessage(0x564, false, false)); + bus1.send(makeMessage(0x564, false, true)); + bus1.send(makeMessage(0x58E, false, false)); + bus1.send(makeMessage(0x05F9052D, false, true)); + bus1.send(makeMessage(0x595, true, false)); + bus1.send(makeMessage(0x595, true, true)); + bus1.send(makeMessage(0x563, true, false)); + bus1.send(makeMessage(0x13358537, true, true)); + bus1.send(makeMessage(0x563, false, true)); // not filtered + bus1.send(makeMessage(0x600, true, false)); // positive filter + bus1.send(makeMessage(0x64D, false, true)); + bus1.send(makeMessage(0x64D, true, false)); + bus1.send(makeMessage(0x620, false, false)); + bus1.send(makeMessage(0x620, true, false)); + bus1.send(makeMessage(0x1069A676, false, true)); + bus1.send(makeMessage(0x1069A676, true, true)); + bus1.send(makeMessage(0x62D, false, false)); + bus1.send(makeMessage(0x62D, false, true)); + bus1.send(makeMessage(0x6C4, false, false)); + bus1.send(makeMessage(0x14C76629, false, true)); + bus1.send(makeMessage(0x689, true, false)); + bus1.send(makeMessage(0x689, true, true)); + bus1.send(makeMessage(0x6A4, true, false)); + bus1.send(makeMessage(0x0BCCA6C2, true, true)); + bus1.send(makeMessage(0x6A4, false, true)); // not filtered + bus1.send(makeMessage(0x04BB1700, true, true)); // positive filter + bus1.send(makeMessage(0x784, false, true)); + bus1.send(makeMessage(0x784, true, false)); + bus1.send(makeMessage(0x7F9, false, false)); + bus1.send(makeMessage(0x7F9, true, false)); + bus1.send(makeMessage(0x0200F77D, false, true)); + bus1.send(makeMessage(0x0200F77D, true, true)); + bus1.send(makeMessage(0x783, false, false)); + bus1.send(makeMessage(0x783, false, true)); + bus1.send(makeMessage(0x770, false, false)); + bus1.send(makeMessage(0x06602719, false, true)); + bus1.send(makeMessage(0x76B, true, false)); + bus1.send(makeMessage(0x76B, true, true)); + bus1.send(makeMessage(0x7DF, true, false)); + bus1.send(makeMessage(0x1939E736, true, true)); + bus1.send(makeMessage(0x7DF, false, true)); // not filtered + + std::vector expectedMixed{ + makeMessage(0x000, true, true), // 0x000:0x700, DONT_CARE, DONT_CARE + makeMessage(0x0BE, false, true), + makeMessage(0x100, false, false), // 0x100:0x700, DONT_CARE, NOT_SET + makeMessage(0x1B8, false, true), + makeMessage(0x096A2200, false, true), // 0x096A2200:0x1FFFFF00, DONT_CARE, SET + makeMessage(0x2A5, false, true), + makeMessage(0x300, false, false), // 0x300:0x700, NOT_SET, DONT_CARE + makeMessage(0x39E, false, true), + makeMessage(0x06C5D400, false, true), // 0x06C5D400:0x1FFFFF00, NOT_SET, SET + makeMessage(0x454, false, true), + makeMessage(0x500, true, false), // 0x500:0x700, SET, DONT_CARE + makeMessage(0x563, false, true), + makeMessage(0x600, true, false), // 0x600:0x700, SET, NOT_SET + makeMessage(0x6A4, false, true), + makeMessage(0x04BB1700, true, true), // 0x04BB1700:0x1FFFFF00, SET, SET + makeMessage(0x7DF, false, true), + }; + + auto messagesMixed = listenerMixed->fetchMessages(100ms, expectedMixed.size()); + clearTimestamps(messagesMixed); + ASSERT_EQ(expectedMixed, messagesMixed); } } // namespace android::hardware::automotive::can::V1_0::vts From e85edb9067d524cb7ba60ea579ffc10930738266 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Sun, 5 Jan 2020 21:49:49 -0800 Subject: [PATCH 0397/1022] Add owners file for rebootescrow Applies to the default implementation and VTS tests. The AIDL is still managed by API review council. Test: No functional change Change-Id: Icb2d9182c1b3376d6b46b467388785e7180db1e9 --- rebootescrow/aidl/default/OWNERS | 2 ++ rebootescrow/aidl/vts/OWNERS | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 rebootescrow/aidl/default/OWNERS create mode 100644 rebootescrow/aidl/vts/OWNERS diff --git a/rebootescrow/aidl/default/OWNERS b/rebootescrow/aidl/default/OWNERS new file mode 100644 index 0000000000..c5288d6a79 --- /dev/null +++ b/rebootescrow/aidl/default/OWNERS @@ -0,0 +1,2 @@ +kroot@google.com +paulcrowley@google.com diff --git a/rebootescrow/aidl/vts/OWNERS b/rebootescrow/aidl/vts/OWNERS new file mode 100644 index 0000000000..c5288d6a79 --- /dev/null +++ b/rebootescrow/aidl/vts/OWNERS @@ -0,0 +1,2 @@ +kroot@google.com +paulcrowley@google.com From c4af97a1a84696142228e3eb685deea1e805fea1 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Thu, 2 Jan 2020 14:23:02 -0800 Subject: [PATCH 0398/1022] Wifi: IHostapd: Add 11ax parameters This commit adds the 802.11ax parameters for SoftAp. Bug: 141831296 Test: atest VtsHalWifiHostapdV1_2TargetTest Change-Id: I7258c10c5dda040e6e05c1a8ec595072017e3ace --- current.txt | 2 +- wifi/hostapd/1.2/IHostapd.hal | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/current.txt b/current.txt index 68e4713a45..27a318f722 100644 --- a/current.txt +++ b/current.txt @@ -650,7 +650,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback cf1d55e8c68300090747ab90b94c22e4c859b29c84ced68a317c595bb115eab2 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi -9bc274c9d73aae170fd9e18df2476ade4c19b629cfb38dd03dd237a6cc2d932b android.hardware.wifi.hostapd@1.2::IHostapd +7d136c169b62abdee0bb6abafb97638acd792ce2102dfccddaa5df98d4bd3df9 android.hardware.wifi.hostapd@1.2::IHostapd 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant c72cb37b3f66ef65aeb5c6438a3fbe17bbe847fdf62d1a76eafd7f3a8a526105 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface diff --git a/wifi/hostapd/1.2/IHostapd.hal b/wifi/hostapd/1.2/IHostapd.hal index c296cd54b4..b25ea97a87 100644 --- a/wifi/hostapd/1.2/IHostapd.hal +++ b/wifi/hostapd/1.2/IHostapd.hal @@ -63,6 +63,36 @@ interface IHostapd extends @1.1::IHostapd { * used. */ bool enable6GhzBand; + + /** + * Whether HE single user beamformer in enabled or not on softAp. + * Note: this is only applicable if 802.11ax is supported for softAp + */ + bool enableHeSingleUserBeamformer; + + /** + * Whether HE single user beamformee is enabled or not on softAp. + * Note: this is only applicable if 802.11ax is supported for softAp + */ + bool enableHeSingleUserBeamformee; + + /** + * Whether HE multiple user beamformer is enabled or not on softAp. + * Note: this is only applicable if 802.11ax is supported for softAp + */ + bool enableHeMultiUserBeamformer; + + /** + * Used BSS Color for softAp running in 802.11ax mode + * Note: this is only applicable if 802.11ax is supported for softAp + */ + uint32_t heBssColor; + + /** + * Whether HE Target Wait Time (TWT) is enabled or not on softAp. + * Note: this is only applicable if 802.11ax is supported for softAp + */ + bool enableHeTargetWakeTime; }; /** From 82cd11cc94f4c0cff4102bf014fa6c0c27a5cfd9 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 6 Jan 2020 13:21:52 -0800 Subject: [PATCH 0399/1022] rebootescrow: use package as name In order to provide a more descriptive name, and to be consistent with HIDL, the stable AIDL package names are switching from vintf-rebootescrow format to the package format (android.hardware.rebootescrow). Bug: N/A Test: all build time Change-Id: Ibb116e76761b751515d95ee8e515a6f7b97bb8d0 --- rebootescrow/aidl/Android.bp | 2 +- rebootescrow/aidl/default/Android.bp | 4 ++-- rebootescrow/aidl/vts/functional/Android.bp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rebootescrow/aidl/Android.bp b/rebootescrow/aidl/Android.bp index 7bc8d6ff3f..0742939621 100644 --- a/rebootescrow/aidl/Android.bp +++ b/rebootescrow/aidl/Android.bp @@ -1,5 +1,5 @@ aidl_interface { - name: "vintf-rebootescrow", + name: "android.hardware.rebootescrow", vendor_available: true, srcs: [ "android/hardware/rebootescrow/IRebootEscrow.aidl", diff --git a/rebootescrow/aidl/default/Android.bp b/rebootescrow/aidl/default/Android.bp index c8cbf48834..b77272f6d8 100644 --- a/rebootescrow/aidl/default/Android.bp +++ b/rebootescrow/aidl/default/Android.bp @@ -20,7 +20,7 @@ cc_library_static { shared_libs: [ "libbase", "libbinder_ndk", - "vintf-rebootescrow-ndk_platform", + "android.hardware.rebootescrow-ndk_platform", ], export_include_dirs: ["include"], srcs: [ @@ -47,7 +47,7 @@ cc_binary { shared_libs: [ "libbase", "libbinder_ndk", - "vintf-rebootescrow-ndk_platform", + "android.hardware.rebootescrow-ndk_platform", ], static_libs: [ "libhadamardutils", diff --git a/rebootescrow/aidl/vts/functional/Android.bp b/rebootescrow/aidl/vts/functional/Android.bp index dadf2509d8..5d51a53f06 100644 --- a/rebootescrow/aidl/vts/functional/Android.bp +++ b/rebootescrow/aidl/vts/functional/Android.bp @@ -25,7 +25,7 @@ cc_test { "libbinder", ], static_libs: [ - "vintf-rebootescrow-cpp", + "android.hardware.rebootescrow-cpp", ], test_suites: [ "vts-core", From 07f2694650f3569d3f3538f9a1ea30d8cc6da036 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 6 Jan 2020 13:40:51 -0800 Subject: [PATCH 0400/1022] vibrator: use package as name In order to provide a more descriptive name, and to be consistent with HIDL, the stable AIDL package names are switching from vintf-vibrator format to the package format (android.hardware.vibrator). Bug: N/A Test: all build time Change-Id: I52959482898f329ad1b3a3a5b345a0c6dc72197d --- tests/extension/vibrator/aidl/Android.bp | 4 +-- .../extension/vibrator/aidl/client/Android.bp | 28 +++++++++---------- .../vibrator/aidl/default/Android.bp | 4 +-- vibrator/aidl/Android.bp | 2 +- vibrator/aidl/default/Android.bp | 8 +++--- vibrator/aidl/vts/Android.bp | 2 +- 6 files changed, 23 insertions(+), 25 deletions(-) diff --git a/tests/extension/vibrator/aidl/Android.bp b/tests/extension/vibrator/aidl/Android.bp index ef9b39bd87..42e0a9200b 100644 --- a/tests/extension/vibrator/aidl/Android.bp +++ b/tests/extension/vibrator/aidl/Android.bp @@ -1,7 +1,7 @@ aidl_interface { // This is an example test interface showing how to add functionality // with setExtension/getExtension - name: "test-vintf-vibrator-ext", + name: "test-android.hardware.vibrator-ext", vendor_available: true, srcs: [ // Using android.hardware as the package because this is in @@ -18,7 +18,7 @@ aidl_interface { // This happens to use types from a core interface, so we import it, but // this won't always be needed. imports: [ - "vintf-vibrator", + "android.hardware.vibrator", ], backend: { diff --git a/tests/extension/vibrator/aidl/client/Android.bp b/tests/extension/vibrator/aidl/client/Android.bp index f7b71f79f0..c707dbe458 100644 --- a/tests/extension/vibrator/aidl/client/Android.bp +++ b/tests/extension/vibrator/aidl/client/Android.bp @@ -1,26 +1,24 @@ - // This example client is written as a test, but it is executing from a system // context. All this code would look the same if it was running in system // server for example. cc_test { - name: "test-vintf-vibrator-ext-client", + name: "test-android.hardware.vibrator-ext-client", srcs: [ - // system code has the option to use the unstable C++ libbinder API - // or the NDK one. For maximum code portability, using the ndk client - // makes the most sense, but both are provided here as an example. - "test-cpp-client.cpp", - "test-ndk-client.cpp", + // system code has the option to use the unstable C++ libbinder API + // or the NDK one. For maximum code portability, using the ndk client + // makes the most sense, but both are provided here as an example. + "test-cpp-client.cpp", + "test-ndk-client.cpp", ], shared_libs: [ - "libbinder", - "libutils", - "vintf-vibrator-cpp", - "test-vintf-vibrator-ext-cpp", + "libbinder", + "libutils", + "android.hardware.vibrator-cpp", + "test-android.hardware.vibrator-ext-cpp", - "libbinder_ndk", - "vintf-vibrator-ndk_platform", - "test-vintf-vibrator-ext-ndk_platform", + "libbinder_ndk", + "android.hardware.vibrator-ndk_platform", + "test-android.hardware.vibrator-ext-ndk_platform", ], } - diff --git a/tests/extension/vibrator/aidl/default/Android.bp b/tests/extension/vibrator/aidl/default/Android.bp index 9869657114..7c8fe1fc96 100644 --- a/tests/extension/vibrator/aidl/default/Android.bp +++ b/tests/extension/vibrator/aidl/default/Android.bp @@ -19,7 +19,7 @@ cc_binary { shared_libs: [ "libbase", "libbinder_ndk", - "vintf-vibrator-ndk_platform", - "test-vintf-vibrator-ext-ndk_platform", + "android.hardware.vibrator-ndk_platform", + "test-android.hardware.vibrator-ext-ndk_platform", ], } diff --git a/vibrator/aidl/Android.bp b/vibrator/aidl/Android.bp index 1eec1da18f..ae7f4348ff 100644 --- a/vibrator/aidl/Android.bp +++ b/vibrator/aidl/Android.bp @@ -1,5 +1,5 @@ aidl_interface { - name: "vintf-vibrator", + name: "android.hardware.vibrator", vendor_available: true, srcs: [ "android/hardware/vibrator/*.aidl", diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp index dc8867fadf..9e6d9cf2d9 100644 --- a/vibrator/aidl/default/Android.bp +++ b/vibrator/aidl/default/Android.bp @@ -4,13 +4,13 @@ cc_library_static { shared_libs: [ "libbase", "libbinder_ndk", - "vintf-vibrator-ndk_platform", + "android.hardware.vibrator-ndk_platform", ], export_include_dirs: ["include"], srcs: ["Vibrator.cpp"], visibility: [ - ":__subpackages__", - "//hardware/interfaces/tests/extension/vibrator:__subpackages__", + ":__subpackages__", + "//hardware/interfaces/tests/extension/vibrator:__subpackages__", ], } @@ -23,7 +23,7 @@ cc_binary { shared_libs: [ "libbase", "libbinder_ndk", - "vintf-vibrator-ndk_platform", + "android.hardware.vibrator-ndk_platform", ], static_libs: [ "libvibratorexampleimpl", diff --git a/vibrator/aidl/vts/Android.bp b/vibrator/aidl/vts/Android.bp index 20d53c7bcf..a01e432be6 100644 --- a/vibrator/aidl/vts/Android.bp +++ b/vibrator/aidl/vts/Android.bp @@ -9,7 +9,7 @@ cc_test { "libbinder", ], static_libs: [ - "vintf-vibrator-cpp", + "android.hardware.vibrator-cpp", ], test_suites: [ "vts-core", From 926aa80f044b64d1d3263b7678d1c1ac493a8a64 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 6 Jan 2020 13:58:00 -0800 Subject: [PATCH 0401/1022] *common: use package as name In order to provide a more descriptive name, and to be consistent with HIDL, the stable AIDL package names are switching from vintf-*common format to the package format (android.hardware.*common). Bug: N/A Test: all build time Change-Id: Ie1d92a50dddf7e3e1bd473e2a957279c6dadb865 --- common/aidl/Android.bp | 2 +- graphics/common/aidl/Android.bp | 4 ++-- graphics/mapper/4.0/vts/functional/Android.bp | 7 +++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp index 6f2d292930..f55e799d0d 100644 --- a/common/aidl/Android.bp +++ b/common/aidl/Android.bp @@ -1,5 +1,5 @@ aidl_interface { - name: "vintf-common", + name: "android.hardware.common", host_supported: true, vendor_available: true, vndk: { diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp index fcd4efc68e..601cabc2e5 100644 --- a/graphics/common/aidl/Android.bp +++ b/graphics/common/aidl/Android.bp @@ -1,5 +1,5 @@ aidl_interface { - name: "vintf-graphics-common", + name: "android.hardware.graphics.common", host_supported: true, vendor_available: true, vndk: { @@ -11,7 +11,7 @@ aidl_interface { ], stability: "vintf", imports: [ - "vintf-common" + "android.hardware.common", ], backend: { java: { diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp index 926cf31f5c..3542a6ee89 100644 --- a/graphics/mapper/4.0/vts/functional/Android.bp +++ b/graphics/mapper/4.0/vts/functional/Android.bp @@ -19,10 +19,10 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"], static_libs: [ + "android.hardware.graphics.common-ndk_platform", "android.hardware.graphics.mapper@4.0-vts", "libgralloctypes", "libsync", - "vintf-graphics-common-ndk_platform", ], shared_libs: [ "android.hardware.graphics.allocator@4.0", @@ -34,5 +34,8 @@ cc_test { header_libs: [ "libsystem_headers", ], - test_suites: ["general-tests", "vts-core"], + test_suites: [ + "general-tests", + "vts-core", + ], } From 08b70226f3e181eeb1d6720727b1b2092c4304c0 Mon Sep 17 00:00:00 2001 From: Hai Shalom Date: Mon, 6 Jan 2020 16:31:18 -0800 Subject: [PATCH 0402/1022] [SAE] Add support to add SAE Authentication algorithm Add support to add SAE Authentication algorithm in the framework (public API), and in the Supplicant HAL. Bug: 147253259 Test: Manual connection to SAE, PSK, OWE and Open APs Test: atest WifiConfigurationTest Change-Id: I853e816be1ba618d61ac0fcb4b116879baba4be2 --- current.txt | 2 +- wifi/supplicant/1.3/ISupplicantStaNetwork.hal | 40 +++++++++++++++++-- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/current.txt b/current.txt index 921a103f68..b24fab84a3 100644 --- a/current.txt +++ b/current.txt @@ -655,7 +655,7 @@ cf1d55e8c68300090747ab90b94c22e4c859b29c84ced68a317c595bb115eab2 android.hardwar a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant c72cb37b3f66ef65aeb5c6438a3fbe17bbe847fdf62d1a76eafd7f3a8a526105 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface 342a8e12db4dca643f2755eb4167e8f103d96502053a25a1f51f42107a4530f1 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback -5477f8bafb29548875622fa83f1c0a29cee641acee613315eb747731001f4aff android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork +8835e9799cddf7c239f60beff467cbdf164331f70a8b6c06ed78982d7810d835 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 91015479f5a0fba9872e98d3cca4680995de64f42ae71461b4b7e5acc5a196ab android.hardware.wifi.supplicant@1.3::types d9044563a5ac5a17a239303b8dec1e51167761ac46e965f61e31654cc034d31b android.hardware.radio@1.5::types afa2d6cf4c0ba4b8482d5bcc097594ad5bc49be0bf3003034f75955cdaf66045 android.hardware.radio@1.5::IRadio diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal index c18bffc93f..e579d24513 100644 --- a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal +++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal @@ -26,14 +26,14 @@ import @1.2::ISupplicantStaNetwork; */ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { /** - * Possble mask of values for Proto param. + * Possible mask of values for Proto param. */ enum ProtoMask : @1.0::ISupplicantStaNetwork.ProtoMask { WAPI = 1 << 2, }; /** - * Possble mask of values for KeyMgmt param. + * Possible mask of values for KeyMgmt param. */ enum KeyMgmtMask : @1.2::ISupplicantStaNetwork.KeyMgmtMask { /* @@ -47,7 +47,7 @@ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { }; /** - * Possble mask of values for PairwiseCipher param. + * Possible mask of values for PairwiseCipher param. */ enum PairwiseCipherMask : @1.2::ISupplicantStaNetwork.PairwiseCipherMask { /** @@ -57,7 +57,7 @@ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { }; /** - * Possble mask of values for GroupCipher param. + * Possible mask of values for GroupCipher param. */ enum GroupCipherMask : @1.2::ISupplicantStaNetwork.GroupCipherMask { /** @@ -66,6 +66,13 @@ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { SMS4 = 1 << 7, }; + /** + * Possible mask of values for AuthAlg param. + */ + enum AuthAlgMask : @1.0::ISupplicantStaNetwork.AuthAlgMask { + SAE = 1 << 4, + }; + /** * Set OCSP (Online Certificate Status Protocol) type for this network. * @@ -236,4 +243,29 @@ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| */ setPmkCache(vec serializedEntry) generates (SupplicantStatus status); + + /** + * Set auth alg mask for the network. + * + * @param authAlgMask value to set. + * Combination of |ProtoMask| values. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + setAuthAlg_1_3(bitfield authAlgMask) generates (SupplicantStatus status); + + /** + * Get the auth alg mask set for the network. + * + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + * @return authAlgMask Combination of |AuthAlgMask| values. + */ + getAuthAlg_1_3() generates (SupplicantStatus status, bitfield authAlgMask); }; From 39187dbbffcec942107b28fa1f7214ca04ff2d5c Mon Sep 17 00:00:00 2001 From: chrisweir Date: Mon, 6 Jan 2020 15:21:07 -0800 Subject: [PATCH 0403/1022] Add support for registering existing interfaces This adds support for native and slcan interfaces which are already configured up to be registered in the CAN bus HAL. Bug: 142655647 Test: manual Change-Id: Ifd129db14dbf473bb627ebc9b9d13f5cb945b611 --- automotive/can/1.0/default/CanBusNative.cpp | 5 +++ automotive/can/1.0/default/CanBusSlcan.cpp | 47 ++++++++++++++------- automotive/can/1.0/default/CanBusSlcan.h | 2 + 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/automotive/can/1.0/default/CanBusNative.cpp b/automotive/can/1.0/default/CanBusNative.cpp index 88f9175f8b..047b09091b 100644 --- a/automotive/can/1.0/default/CanBusNative.cpp +++ b/automotive/can/1.0/default/CanBusNative.cpp @@ -31,6 +31,11 @@ ICanController::Result CanBusNative::preUp() { return ICanController::Result::BAD_ADDRESS; } + if (mBaudrate == 0) { + // interface is already up and we just want to register it + return ICanController::Result::OK; + } + if (!netdevice::down(mIfname)) { LOG(ERROR) << "Can't bring " << mIfname << " down (to configure it)"; return ICanController::Result::UNKNOWN_ERROR; diff --git a/automotive/can/1.0/default/CanBusSlcan.cpp b/automotive/can/1.0/default/CanBusSlcan.cpp index 29d9d3c238..e42005b6db 100644 --- a/automotive/can/1.0/default/CanBusSlcan.cpp +++ b/automotive/can/1.0/default/CanBusSlcan.cpp @@ -47,13 +47,34 @@ static const std::map kBitrateCommands = { CanBusSlcan::CanBusSlcan(const std::string& uartName, uint32_t bitrate) : CanBus(), mUartName(uartName), kBitrate(bitrate) {} +/** helper function to update CanBusSlcan object's iface name */ +ICanController::Result CanBusSlcan::updateIfaceName(base::unique_fd& uartFd) { + struct ifreq ifrequest = {}; + /* + * Fetching the iface name with an ioctl won't interfere with an open socketCAN iface attached + * to this tty. This is important in the event we are trying to register a SLCAN based iface + * that has already been configured and brought up. + */ + if (ioctl(uartFd.get(), SIOCGIFNAME, ifrequest.ifr_name) < 0) { + LOG(ERROR) << "Failed to get the name of the created device: " << strerror(errno); + return ICanController::Result::UNKNOWN_ERROR; + } + + // Update the CanBus object with name that was assigned to it + mIfname = ifrequest.ifr_name; + return ICanController::Result::OK; +} + ICanController::Result CanBusSlcan::preUp() { // verify valid bitrate and translate to serial command format - const auto lookupIt = slcanprotocol::kBitrateCommands.find(kBitrate); - if (lookupIt == slcanprotocol::kBitrateCommands.end()) { - return ICanController::Result::BAD_BAUDRATE; + std::optional canBitrateCommand = std::nullopt; + if (kBitrate != 0) { + const auto lookupIt = slcanprotocol::kBitrateCommands.find(kBitrate); + if (lookupIt == slcanprotocol::kBitrateCommands.end()) { + return ICanController::Result::BAD_BAUDRATE; + } + canBitrateCommand = lookupIt->second; } - const auto canBitrateCommand = lookupIt->second; /* Attempt to open the uart in r/w without blocking or becoming the * controlling terminal */ @@ -63,6 +84,11 @@ ICanController::Result CanBusSlcan::preUp() { return ICanController::Result::BAD_ADDRESS; } + // If the device is already up, update the iface name in our CanBusSlcan object + if (kBitrate == 0) { + return updateIfaceName(mFd); + } + // blank terminal settings and pull them from the device struct termios terminalSettings = {}; if (tcgetattr(mFd.get(), &terminalSettings) < 0) { @@ -102,7 +128,7 @@ ICanController::Result CanBusSlcan::preUp() { } // apply speed setting for CAN - if (write(mFd.get(), canBitrateCommand.c_str(), canBitrateCommand.length()) <= 0) { + if (write(mFd.get(), canBitrateCommand->c_str(), canBitrateCommand->length()) <= 0) { LOG(ERROR) << "Failed to apply CAN bitrate: " << strerror(errno); return ICanController::Result::UNKNOWN_ERROR; } @@ -120,17 +146,8 @@ ICanController::Result CanBusSlcan::preUp() { return ICanController::Result::UNKNOWN_ERROR; } - // get the name of the device we created - struct ifreq ifrequest = {}; - if (ioctl(mFd.get(), SIOCGIFNAME, ifrequest.ifr_name) < 0) { - LOG(ERROR) << "Failed to get the name of the created device: " << strerror(errno); - return ICanController::Result::UNKNOWN_ERROR; - } - // Update the CanBus object with name that was assigned to it - mIfname = ifrequest.ifr_name; - - return ICanController::Result::OK; + return updateIfaceName(mFd); } bool CanBusSlcan::postDown() { diff --git a/automotive/can/1.0/default/CanBusSlcan.h b/automotive/can/1.0/default/CanBusSlcan.h index 3328a9f4ca..2328a2c65d 100644 --- a/automotive/can/1.0/default/CanBusSlcan.h +++ b/automotive/can/1.0/default/CanBusSlcan.h @@ -32,6 +32,8 @@ struct CanBusSlcan : public CanBus { virtual bool postDown() override; private: + ICanController::Result updateIfaceName(base::unique_fd& uartFd); + const std::string mUartName; const uint32_t kBitrate; base::unique_fd mFd; From dcfab61c9b458912991ac333947db2540864eb51 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Tue, 7 Jan 2020 17:38:02 -0800 Subject: [PATCH 0404/1022] Wifi: Make sure that VTS tests start with a clean state In current code base, The SetUp() method in wifi VTS tests does not reset Wifi state. Hence the first Wifi test runs with unspecified state. Following test cases are not impacted due to that TearDown() takes care of resetting the Wifi state. This commit adds the stopWifi() method to the SetUp() so all test cases start from the same Wifi state. Bug: 145312303 Test: Run all wifi VTS tests Test: atest Change-Id: I63d7c0d27f4ceb713dda3804786a199dc2274be5 --- wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp | 5 ++++- wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp | 5 ++++- wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp | 5 ++++- wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp | 3 +++ wifi/1.0/vts/functional/wifi_hidl_test.cpp | 7 +++++-- wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp | 5 ++++- wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp | 7 +++++-- wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp | 5 ++++- wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp | 5 ++++- wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp | 5 ++++- wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp | 7 +++++-- wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp | 3 +++ wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp | 5 ++++- wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp | 5 ++++- wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp | 5 ++++- wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp | 5 ++++- wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp | 3 +++ wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp | 3 +++ 18 files changed, 71 insertions(+), 17 deletions(-) diff --git a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp index 8be8a0cb76..3599b94075 100644 --- a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp @@ -38,6 +38,9 @@ using ::android::hardware::wifi::V1_0::WifiStatusCode; class WifiApIfaceHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { + // Make sure test starts with a clean state + stopWifi(GetInstanceName()); + wifi_ap_iface_ = getWifiApIface(GetInstanceName()); ASSERT_NE(nullptr, wifi_ap_iface_.get()); } @@ -95,4 +98,4 @@ INSTANTIATE_TEST_SUITE_P( PerInstance, WifiApIfaceHidlTest, testing::ValuesIn( android::hardware::getAllHalInstanceNames(IWifi::descriptor)), - android::hardware::PrintInstanceNameToString); \ No newline at end of file + android::hardware::PrintInstanceNameToString); diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp index 33817d5f95..5a2c6a740e 100644 --- a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp +++ b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp @@ -41,6 +41,9 @@ using ::android::hardware::wifi::V1_0::WifiStatusCode; class WifiChipHidlApTest : public ::testing::TestWithParam { public: virtual void SetUp() override { + // Make sure test starts with a clean state + stopWifi(GetInstanceName()); + wifi_chip_ = getWifiChip(GetInstanceName()); ASSERT_NE(nullptr, wifi_chip_.get()); } @@ -177,4 +180,4 @@ INSTANTIATE_TEST_SUITE_P( PerInstance, WifiChipHidlApTest, testing::ValuesIn( android::hardware::getAllHalInstanceNames(IWifi::descriptor)), - android::hardware::PrintInstanceNameToString); \ No newline at end of file + android::hardware::PrintInstanceNameToString); diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp index 95f223d5de..c95f4d2c81 100644 --- a/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp +++ b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp @@ -41,6 +41,9 @@ using ::android::hardware::wifi::V1_0::WifiStatusCode; class WifiChipHidlNanTest : public ::testing::TestWithParam { public: virtual void SetUp() override { + // Make sure test starts with a clean state + stopWifi(GetInstanceName()); + wifi_chip_ = getWifiChip(GetInstanceName()); ASSERT_NE(nullptr, wifi_chip_.get()); } @@ -178,4 +181,4 @@ INSTANTIATE_TEST_SUITE_P( PerInstance, WifiChipHidlNanTest, testing::ValuesIn( android::hardware::getAllHalInstanceNames(IWifi::descriptor)), - android::hardware::PrintInstanceNameToString); \ No newline at end of file + android::hardware::PrintInstanceNameToString); diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp index 62874ef147..f332001711 100644 --- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp @@ -73,6 +73,9 @@ bool hasAnyRingBufferCapabilities(uint32_t caps) { class WifiChipHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { + // Make sure test starts with a clean state + stopWifi(GetInstanceName()); + wifi_chip_ = getWifiChip(GetInstanceName()); ASSERT_NE(nullptr, wifi_chip_.get()); } diff --git a/wifi/1.0/vts/functional/wifi_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_hidl_test.cpp index 512701a40c..f3c82da3e9 100644 --- a/wifi/1.0/vts/functional/wifi_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_hidl_test.cpp @@ -32,7 +32,10 @@ using ::android::sp; */ class WifiHidlTest : public ::testing::TestWithParam { public: - virtual void SetUp() override {} + virtual void SetUp() override { + // Make sure test starts with a clean state + stopWifi(GetInstanceName()); + } virtual void TearDown() override { stopWifi(GetInstanceName()); } @@ -53,4 +56,4 @@ INSTANTIATE_TEST_SUITE_P( PerInstance, WifiHidlTest, testing::ValuesIn( android::hardware::getAllHalInstanceNames(IWifi::descriptor)), - android::hardware::PrintInstanceNameToString); \ No newline at end of file + android::hardware::PrintInstanceNameToString); diff --git a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp index 422e3f6bba..47a1938db9 100644 --- a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp @@ -44,6 +44,9 @@ using ::android::hardware::wifi::V1_0::IWifi; class WifiNanIfaceHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { + // Make sure test starts with a clean state + stopWifi(GetInstanceName()); + iwifiNanIface = getWifiNanIface(GetInstanceName()); ASSERT_NE(nullptr, iwifiNanIface.get()); ASSERT_EQ(WifiStatusCode::SUCCESS, @@ -506,4 +509,4 @@ INSTANTIATE_TEST_SUITE_P( PerInstance, WifiNanIfaceHidlTest, testing::ValuesIn( android::hardware::getAllHalInstanceNames(IWifi::descriptor)), - android::hardware::PrintInstanceNameToString); \ No newline at end of file + android::hardware::PrintInstanceNameToString); diff --git a/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp index 8f3327150c..fd175f5218 100644 --- a/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp @@ -33,7 +33,10 @@ using ::android::hardware::wifi::V1_0::IWifiP2pIface; */ class WifiP2pIfaceHidlTest : public ::testing::TestWithParam { public: - virtual void SetUp() override {} + virtual void SetUp() override { + // Make sure test starts with a clean state + stopWifi(GetInstanceName()); + } virtual void TearDown() override { stopWifi(GetInstanceName()); } @@ -55,4 +58,4 @@ INSTANTIATE_TEST_SUITE_P( PerInstance, WifiP2pIfaceHidlTest, testing::ValuesIn( android::hardware::getAllHalInstanceNames(IWifi::descriptor)), - android::hardware::PrintInstanceNameToString); \ No newline at end of file + android::hardware::PrintInstanceNameToString); diff --git a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp index 6c01995307..1eb9c99149 100644 --- a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp @@ -37,7 +37,10 @@ using ::android::hardware::wifi::V1_0::WifiStatusCode; */ class WifiRttControllerHidlTest : public ::testing::TestWithParam { public: - virtual void SetUp() override {} + virtual void SetUp() override { + // Make sure test starts with a clean state + stopWifi(GetInstanceName()); + } virtual void TearDown() override { stopWifi(GetInstanceName()); } diff --git a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp index 30b6fba38c..7db0526d1c 100644 --- a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp @@ -47,6 +47,9 @@ using ::android::hardware::wifi::V1_0::WifiStatusCode; class WifiStaIfaceHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { + // Make sure test starts with a clean state + stopWifi(GetInstanceName()); + wifi_sta_iface_ = getWifiStaIface(GetInstanceName()); ASSERT_NE(nullptr, wifi_sta_iface_.get()); } @@ -299,4 +302,4 @@ INSTANTIATE_TEST_SUITE_P( PerInstance, WifiStaIfaceHidlTest, testing::ValuesIn( android::hardware::getAllHalInstanceNames(IWifi::descriptor)), - android::hardware::PrintInstanceNameToString); \ No newline at end of file + android::hardware::PrintInstanceNameToString); diff --git a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp index 08de240252..4b94acb258 100644 --- a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp @@ -49,6 +49,9 @@ constexpr IWifiChip::TxPowerScenario kFakePowerScenario = class WifiChipHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { + // Make sure to start with a clean state + stopWifi(GetInstanceName()); + wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName())); ASSERT_NE(nullptr, wifi_chip_.get()); } @@ -115,4 +118,4 @@ INSTANTIATE_TEST_SUITE_P( PerInstance, WifiChipHidlTest, testing::ValuesIn( android::hardware::getAllHalInstanceNames(IWifi::descriptor)), - android::hardware::PrintInstanceNameToString); \ No newline at end of file + android::hardware::PrintInstanceNameToString); diff --git a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp index 93aa0f3ae9..b04acadef9 100644 --- a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp @@ -55,8 +55,11 @@ constexpr IWifiChip::TxPowerScenario kPowerScenarioVoiceCall = class WifiChipHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { - wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName())); - ASSERT_NE(nullptr, wifi_chip_.get()); + // Make sure test starts with a clean state + stopWifi(GetInstanceName()); + + wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName())); + ASSERT_NE(nullptr, wifi_chip_.get()); } virtual void TearDown() override { stopWifi(GetInstanceName()); } diff --git a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp index d5d87ce73e..6e55664d9b 100644 --- a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp +++ b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp @@ -50,6 +50,9 @@ android::sp getWifiNanIface_1_2( class WifiNanIfaceHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { + // Make sure to start with a clean state + stopWifi(GetInstanceName()); + iwifiNanIface = getWifiNanIface_1_2(GetInstanceName()); ASSERT_NE(nullptr, iwifiNanIface.get()); ASSERT_EQ(WifiStatusCode::SUCCESS, diff --git a/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp index 1b907b272f..066dcaae87 100644 --- a/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp +++ b/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp @@ -39,6 +39,9 @@ using ::android::hardware::wifi::V1_2::IWifiStaIface; class WifiStaIfaceHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { + // Make sure to start with a clean state + stopWifi(GetInstanceName()); + wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface(GetInstanceName())); ASSERT_NE(nullptr, wifi_sta_iface_.get()); @@ -118,4 +121,4 @@ INSTANTIATE_TEST_SUITE_P( PerInstance, WifiStaIfaceHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames( ::android::hardware::wifi::V1_2::IWifi::descriptor)), - android::hardware::PrintInstanceNameToString); \ No newline at end of file + android::hardware::PrintInstanceNameToString); diff --git a/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp index db939679ad..e99b34a7f8 100644 --- a/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp @@ -44,6 +44,9 @@ constexpr IWifiChip::LatencyMode kLatencyModeLow = IWifiChip::LatencyMode::LOW; class WifiChipHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { + // Make sure to start with a clean state + stopWifi(GetInstanceName()); + wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName())); ASSERT_NE(nullptr, wifi_chip_.get()); } @@ -126,4 +129,4 @@ INSTANTIATE_TEST_SUITE_P( PerInstance, WifiChipHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames( ::android::hardware::wifi::V1_3::IWifi::descriptor)), - android::hardware::PrintInstanceNameToString); \ No newline at end of file + android::hardware::PrintInstanceNameToString); diff --git a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp index c5acc3c1b2..41d4ebbcb1 100644 --- a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp +++ b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp @@ -40,6 +40,9 @@ using ::android::hardware::wifi::V1_3::IWifiStaIface; class WifiStaIfaceHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { + // Make sure to start with a clean state + stopWifi(GetInstanceName()); + wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface(GetInstanceName())); ASSERT_NE(nullptr, wifi_sta_iface_.get()); @@ -105,4 +108,4 @@ INSTANTIATE_TEST_SUITE_P( PerInstance, WifiStaIfaceHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames( ::android::hardware::wifi::V1_3::IWifi::descriptor)), - android::hardware::PrintInstanceNameToString); \ No newline at end of file + android::hardware::PrintInstanceNameToString); diff --git a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp index 017ecb6b6d..3507d3074a 100644 --- a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp +++ b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp @@ -38,6 +38,9 @@ extern WifiHidlEnvironment* gEnv; class WifiApIfaceHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { + // Make sure to start with a clean state + stopWifi(GetInstanceName()); + wifi_ap_iface_ = IWifiApIface::castFrom(getWifiApIface(GetInstanceName())); ASSERT_NE(nullptr, wifi_ap_iface_.get()); @@ -80,4 +83,4 @@ INSTANTIATE_TEST_SUITE_P( PerInstance, WifiApIfaceHidlTest, testing::ValuesIn( android::hardware::getAllHalInstanceNames(IWifi::descriptor)), - android::hardware::PrintInstanceNameToString); \ No newline at end of file + android::hardware::PrintInstanceNameToString); diff --git a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp index 8ca5214fc5..7896067d3a 100644 --- a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp @@ -47,6 +47,9 @@ using ::android::hardware::wifi::V1_4::IWifiChipEventCallback; class WifiChipHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { + // Make sure to start with a clean state + stopWifi(GetInstanceName()); + wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName())); ASSERT_NE(nullptr, wifi_chip_.get()); } diff --git a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp index 245e9063ea..688faf1b2a 100644 --- a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp +++ b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp @@ -51,6 +51,9 @@ android::sp getWifiNanIface_1_4( class WifiNanIfaceHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { + // Make sure to start with a clean state + stopWifi(GetInstanceName()); + iwifiNanIface = getWifiNanIface_1_4(GetInstanceName()); ASSERT_NE(nullptr, iwifiNanIface.get()); ASSERT_EQ(WifiStatusCode::SUCCESS, From cb49463796c56f00570111c4ae5051cba645102b Mon Sep 17 00:00:00 2001 From: Nicholas Ambur Date: Sun, 8 Dec 2019 21:52:36 -0800 Subject: [PATCH 0405/1022] add model arch to SoundTrigger Properties Bug: 142414689 Test: Assist GTS test suite and manual testing Change-Id: Ie8bb4bdd292aceaae92c6f550a9633068cabdd24 --- current.txt | 4 +- soundtrigger/2.3/ISoundTriggerHw.hal | 12 ++++++ soundtrigger/2.3/default/SoundTriggerHw.cpp | 37 ++++++++++++++++++- soundtrigger/2.3/default/SoundTriggerHw.h | 3 ++ soundtrigger/2.3/types.hal | 15 ++++++++ .../VtsHalSoundtriggerV2_3TargetTest.cpp | 28 ++++++++++++++ 6 files changed, 95 insertions(+), 4 deletions(-) diff --git a/current.txt b/current.txt index 8bf63c7d7f..847fed663d 100644 --- a/current.txt +++ b/current.txt @@ -665,5 +665,5 @@ f4888f9676890b43a459c6380f335fea7a6ad32ed3bafafeb018a88d6c0be8a4 android.hardwar b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication 7683fed9d253956071f18b152e6be657719536f98d9b534433d5e411bcde5061 android.hardware.radio.config@1.3::IRadioConfigResponse -c411dc16855fcb786cd5e08fe2889acbd72fd54217bd27fe0373813de230ce5f android.hardware.soundtrigger@2.3::types -5abad7b54d3400fab633cb7a36ffc1747e037bf805d3d9e3517cb6aabf26b002 android.hardware.soundtrigger@2.3::ISoundTriggerHw +b46d358537168c478762c3d34d5fe1555a3fcd89cd1f43621350ada395e6f795 android.hardware.soundtrigger@2.3::types +15924fbf38b3c282299a37e48c72405c97e322f844f815081db6acbca22d4165 android.hardware.soundtrigger@2.3::ISoundTriggerHw diff --git a/soundtrigger/2.3/ISoundTriggerHw.hal b/soundtrigger/2.3/ISoundTriggerHw.hal index 207b9b74f9..23aa36ead0 100644 --- a/soundtrigger/2.3/ISoundTriggerHw.hal +++ b/soundtrigger/2.3/ISoundTriggerHw.hal @@ -25,6 +25,18 @@ import @2.2::ISoundTriggerHw; */ interface ISoundTriggerHw extends @2.2::ISoundTriggerHw { + /** + * Retrieve extended implementation properties. + * The returned properties includes what is returned from the + * getProperties along with expanded implementation details. + * + * @return retval Operation completion status: 0 in case of success, + * -ENODEV in case of initialization error. + * @return properties A Properties structure containing implementation + * description and capabilities. + */ + getProperties_2_3() generates (int32_t retval, Properties properties); + /** * Set a model specific parameter with the given value. This parameter * will keep its value for the duration the model is loaded regardless of starting and stopping diff --git a/soundtrigger/2.3/default/SoundTriggerHw.cpp b/soundtrigger/2.3/default/SoundTriggerHw.cpp index 4a39ab562d..9fd8fe0e5c 100644 --- a/soundtrigger/2.3/default/SoundTriggerHw.cpp +++ b/soundtrigger/2.3/default/SoundTriggerHw.cpp @@ -89,7 +89,7 @@ Return SoundTriggerHw::getProperties(ISoundTriggerHw::getProperties_cb _hi ALOGV("getProperties() mHwDevice %p", mHwDevice); int ret; struct sound_trigger_properties halProperties; - ISoundTriggerHw::Properties properties; + V2_0::ISoundTriggerHw::Properties properties; if (mHwDevice == NULL) { ret = -ENODEV; @@ -333,7 +333,7 @@ void SoundTriggerHw::convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* } void SoundTriggerHw::convertPropertiesFromHal( - ISoundTriggerHw::Properties* properties, + V2_0::ISoundTriggerHw::Properties* properties, const struct sound_trigger_properties* halProperties) { properties->implementor = halProperties->implementor; properties->description = halProperties->description; @@ -350,6 +350,16 @@ void SoundTriggerHw::convertPropertiesFromHal( properties->powerConsumptionMw = halProperties->power_consumption_mw; } +void SoundTriggerHw::convertPropertiesFromHal( + V2_3::Properties* properties, const struct sound_trigger_properties_header* header) { + if (header->version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_3) { + const struct sound_trigger_properties_extended_1_3* halProperties = + (const struct sound_trigger_properties_extended_1_3*)header; + convertPropertiesFromHal(&properties->base, &halProperties->base); + properties->supportedModelArch = halProperties->supported_model_arch; + } +} + void SoundTriggerHw::convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase, const ISoundTriggerHw::Phrase* triggerPhrase) { halTriggerPhrase->id = triggerPhrase->id; @@ -708,6 +718,29 @@ Return SoundTriggerHw::getModelState(int32_t modelHandle) { // Begin V2_3 implementation +Return SoundTriggerHw::getProperties_2_3(ISoundTriggerHw::getProperties_2_3_cb _hidl_cb) { + ALOGV("getProperties_2_3() mHwDevice %p", mHwDevice); + int ret = 0; + V2_3::Properties properties; + const struct sound_trigger_properties_header* header; + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + header = mHwDevice->get_properties_extended(mHwDevice); + + convertPropertiesFromHal(&properties, header); + + ALOGV("getProperties_2_3 implementor %s supportedModelArch %s", + properties.base.implementor.c_str(), properties.supportedModelArch.c_str()); + +exit: + _hidl_cb(ret, properties); + return Void(); +} + Return SoundTriggerHw::setParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam, int32_t value) { sp client; diff --git a/soundtrigger/2.3/default/SoundTriggerHw.h b/soundtrigger/2.3/default/SoundTriggerHw.h index c82c9ea0e2..078debb81d 100644 --- a/soundtrigger/2.3/default/SoundTriggerHw.h +++ b/soundtrigger/2.3/default/SoundTriggerHw.h @@ -85,6 +85,7 @@ struct SoundTriggerHw : public ISoundTriggerHw { Return getModelState(int32_t modelHandle) override; // Methods from V2_3::ISoundTriggerHw follow. + Return getProperties_2_3(getProperties_2_3_cb _hidl_cb) override; Return setParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam, int32_t value) override; Return getParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam, @@ -156,6 +157,8 @@ struct SoundTriggerHw : public ISoundTriggerHw { void convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid); void convertPropertiesFromHal(V2_0::ISoundTriggerHw::Properties* properties, const struct sound_trigger_properties* halProperties); + void convertPropertiesFromHal(V2_3::Properties* properties, + const struct sound_trigger_properties_header* header); static sound_trigger_model_parameter_t convertModelParameterToHal(ModelParameter param); void convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase, const V2_0::ISoundTriggerHw::Phrase* triggerPhrase); diff --git a/soundtrigger/2.3/types.hal b/soundtrigger/2.3/types.hal index c3a522b31f..614912679a 100644 --- a/soundtrigger/2.3/types.hal +++ b/soundtrigger/2.3/types.hal @@ -17,6 +17,21 @@ package android.hardware.soundtrigger@2.3; import android.hidl.safe_union@1.0::Monostate; +import @2.0::ISoundTriggerHw.Properties; + +/** + * Extended implementation properties providing verbose implementation + * details. + */ +struct Properties { + @2.0::ISoundTriggerHw.Properties base; + + /** + * String naming the architecture used for running the supported models. + * (eg. DSP architecture) + */ + string supportedModelArch; +}; /** * Model specific parameters to be used with parameter set and get APIs diff --git a/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp index 202eb6c09b..ed38368d8c 100644 --- a/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp +++ b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp @@ -26,7 +26,9 @@ using ::android::sp; using ::android::hardware::Return; +using ::android::hardware::soundtrigger::V2_0::RecognitionMode; using ::android::hardware::soundtrigger::V2_3::ISoundTriggerHw; +using ::android::hardware::soundtrigger::V2_3::Properties; /** * Test class holding the instance of the SoundTriggerHW service to test. @@ -53,6 +55,32 @@ class SoundTriggerHidlTest : public testing::TestWithParam { */ TEST_P(SoundTriggerHidlTest, ServiceIsInstantiated) {} +/** + * Test ISoundTriggerHw::getProperties_2_3 method + * + * Verifies that: + * - the implementation implements the method + * - the method returns no error + * - the implementation supports at least one sound model and one key phrase + * - the implementation supports at least VOICE_TRIGGER recognition mode + */ +TEST_P(SoundTriggerHidlTest, GetProperties_2_3) { + Properties halProperties; + Return hidlReturn; + int ret = -ENODEV; + + hidlReturn = soundtrigger->getProperties_2_3([&](int rc, auto res) { + ret = rc; + halProperties = res; + }); + + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_EQ(0, ret); + EXPECT_GT(halProperties.base.maxSoundModels, 0u); + EXPECT_GT(halProperties.base.maxKeyPhrases, 0u); + EXPECT_NE(0u, (halProperties.base.recognitionModes & (uint32_t)RecognitionMode::VOICE_TRIGGER)); +} + INSTANTIATE_TEST_SUITE_P( PerInstance, SoundTriggerHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)), From 4b9ab65f96a9da1b7dcb17169f559e08ddb73e8c Mon Sep 17 00:00:00 2001 From: Nick Chalko Date: Wed, 8 Jan 2020 10:57:39 -0800 Subject: [PATCH 0406/1022] Improve documentation for FrontendEventType Test: m android.hardware.tv.tuner@1.0 Change-Id: I3eece06215debfdb5122faa84ce5a80c1a28a8db --- tv/tuner/1.0/types.hal | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index fa3c08b17d..d39439da99 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -1307,18 +1307,15 @@ safe_union FrontendScanMessage { @export enum FrontendEventType : uint32_t { /** - * If frontend locked the signal which is specified by tune method, HAL sends - * Locked event. + * The frontend has locked to the signal specified by the tune method. */ LOCKED, /** - * If frontend can't locked the signal which is specified by tune method, - * HAL sends NO_SIGNAL event. + * The frontend is unable to lock to the signal specified by the tune method. */ NO_SIGNAL, /** - * If frontend detect that the locked signal get lost, HAL sends LOST_LOCK - * event. + * The frontend has lost the lock to the signal specified by the tune method. */ LOST_LOCK, }; From 96ee56bcd82b180c5cce959b29aa506d216ccbbe Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Wed, 8 Jan 2020 14:54:02 -0800 Subject: [PATCH 0407/1022] Remove beginCommand variants with a helper template. BUG: b/147365206 Test: boot Change-Id: I30715fe3e1c221ba366bf521fbd531636136f0c9 --- .../2.1/ComposerCommandBuffer.h | 7 ++++++- .../2.2/ComposerCommandBuffer.h | 13 +++---------- .../2.3/ComposerCommandBuffer.h | 16 +++++----------- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h index ebac2e0f58..64ed4f3c5a 100644 --- a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h +++ b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h @@ -403,6 +403,11 @@ class CommandWriterBase { } protected: + template + void beginCommand(T command, uint16_t length) { + beginCommandBase(static_cast(command), length); + } + void setClientTargetInternal(uint32_t slot, const native_handle_t* target, int acquireFence, int32_t dataspace, const std::vector& damage) { @@ -429,7 +434,7 @@ class CommandWriterBase { endCommand(); } - void beginCommand(IComposerClient::Command command, uint16_t length) { + void beginCommandBase(IComposerClient::Command command, uint16_t length) { if (mCommandEnd) { LOG_FATAL("endCommand was not called before command 0x%x", command); } diff --git a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h index 35162a6b8e..00f427ac89 100644 --- a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h +++ b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h @@ -76,15 +76,14 @@ class CommandWriterBase : public V2_1::CommandWriterBase { static constexpr uint16_t kSetLayerFloatColorLength = 4; void setLayerFloatColor(IComposerClient::FloatColor color) { - beginCommand_2_2(IComposerClient::Command::SET_LAYER_FLOAT_COLOR, - kSetLayerFloatColorLength); + beginCommand(IComposerClient::Command::SET_LAYER_FLOAT_COLOR, kSetLayerFloatColorLength); writeFloatColor(color); endCommand(); } void setLayerPerFrameMetadata(const hidl_vec& metadataVec) { - beginCommand_2_2(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA, - metadataVec.size() * 2); + beginCommand(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA, + metadataVec.size() * 2); for (const auto& metadata : metadataVec) { writeSigned(static_cast(metadata.key)); writeFloat(metadata.value); @@ -99,12 +98,6 @@ class CommandWriterBase : public V2_1::CommandWriterBase { writeFloat(color.b); writeFloat(color.a); } - - private: - void beginCommand_2_2(IComposerClient::Command command, uint16_t length) { - V2_1::CommandWriterBase::beginCommand( - static_cast(static_cast(command)), length); - } }; // This class helps parse a command queue. Note that all sizes/lengths are in diff --git a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h index 3dfda19bba..afc22d8719 100644 --- a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h +++ b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h @@ -46,8 +46,8 @@ using android::hardware::graphics::composer::V2_3::IComposerClient; class CommandWriterBase : public V2_2::CommandWriterBase { public: void setLayerPerFrameMetadata(const hidl_vec& metadataVec) { - beginCommand_2_3(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA, - metadataVec.size() * 2); + beginCommand(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA, + metadataVec.size() * 2); for (const auto& metadata : metadataVec) { writeSigned(static_cast(metadata.key)); writeFloat(metadata.value); @@ -69,8 +69,8 @@ class CommandWriterBase : public V2_2::CommandWriterBase { static constexpr uint16_t kSetLayerColorTransformLength = 16; void setLayerColorTransform(const float* matrix) { - beginCommand_2_3(IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM, - kSetLayerColorTransformLength); + beginCommand(IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM, + kSetLayerColorTransformLength); for (int i = 0; i < 16; i++) { writeFloat(matrix[i]); } @@ -109,7 +109,7 @@ class CommandWriterBase : public V2_2::CommandWriterBase { // Blobs are written as: // {numElements, key1, size1, blob1, key2, size2, blob2, key3, size3...} uint16_t length = static_cast(commandLength); - beginCommand_2_3(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA_BLOBS, length); + beginCommand(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA_BLOBS, length); write(static_cast(metadata.size())); for (auto metadataBlob : metadata) { writeSigned(static_cast(metadataBlob.key)); @@ -126,12 +126,6 @@ class CommandWriterBase : public V2_2::CommandWriterBase { mDataWritten += numElements; mDataWritten += (length - (numElements * 4) > 0) ? 1 : 0; } - - private: - void beginCommand_2_3(IComposerClient::Command command, uint16_t length) { - V2_1::CommandWriterBase::beginCommand( - static_cast(static_cast(command)), length); - } }; // This class helps parse a command queue. Note that all sizes/lengths are in From 30d818e8b36cda1533109c6087e66888dbdc82b3 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 30 Dec 2019 12:59:08 -0800 Subject: [PATCH 0408/1022] composer: add seamlessPossible callback to composer 2.4 Add a callback to notify the client it should retry a setActiveConfigWithConstraints call in case of SEAMLESS_NOT_POSSIBLE error. Test: rev up composer to 2.4 Bug: 141329414 Change-Id: I6176638fde937e3916f58cc577d50cb755997c61 --- graphics/composer/2.4/IComposerCallback.hal | 10 ++++++++++ graphics/composer/2.4/IComposerClient.hal | 3 +++ .../hal/include/composer-hal/2.4/ComposerClient.h | 6 ++++++ .../utils/hal/include/composer-hal/2.4/ComposerHal.h | 1 + .../include/composer-passthrough/2.4/HwcHal.h | 11 ++++++++++- 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/graphics/composer/2.4/IComposerCallback.hal b/graphics/composer/2.4/IComposerCallback.hal index fea24a1cbf..f343ceef6e 100644 --- a/graphics/composer/2.4/IComposerCallback.hal +++ b/graphics/composer/2.4/IComposerCallback.hal @@ -42,4 +42,14 @@ interface IComposerCallback extends @2.1::IComposerCallback { * @param updatedTimeline is the new timeline for the vsync period change. */ oneway onVsyncPeriodTimingChanged(Display display, VsyncPeriodChangeTimeline updatedTimeline); + + /** + * Notifies the client that the conditions which previously led to returning + * SEAMLESS_NOT_POSSIBLE from setActiveConfigWithConstraints have changed and now seamless may + * be possible. Client should retry calling setActiveConfigWithConstraints. + * + * @param display is a display setActiveConfigWithConstraints previously failed with + * SEAMLESS_NOT_POSSIBLE. + */ + oneway onSeamlessPossible(Display display); }; diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal index 06b4c5e53a..1b8170beb5 100644 --- a/graphics/composer/2.4/IComposerClient.hal +++ b/graphics/composer/2.4/IComposerClient.hal @@ -185,6 +185,9 @@ interface IComposerClient extends @2.3::IComposerClient { * share the same config group as the current config. * SEAMLESS_NOT_POSSIBLE when seamlessRequired was true but the display cannot achieve * the vsync period change without a noticeable visual artifact. + * When the conditions change and it may be possible to change + * the vsync period seamlessly, onSeamlessPossible callback + * must be called to indicate that caller should retry. * @return timeline is the timeline for the vsync period change. */ setActiveConfigWithConstraints(Display display, Config config, diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h index dcd959dfb5..d48a9e7dd5 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h @@ -83,6 +83,12 @@ class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImplonSeamlessPossible(display); + ALOGE_IF(!ret.isOk(), "failed to send onSealmessPossible: %s", + ret.description().c_str()); + } + protected: const sp mCallback; V2_1::hal::ComposerResources* const mResources; diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h index a1e56ae6ed..bbc5405255 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h @@ -49,6 +49,7 @@ class ComposerHal : public V2_3::hal::ComposerHal { VsyncPeriodNanos vsyncPeriodNanos) = 0; virtual void onVsyncPeriodTimingChanged(Display display, const VsyncPeriodChangeTimeline& timeline) = 0; + virtual void onSeamlessPossible(Display display) = 0; }; virtual void registerEventCallback_2_4(EventCallback_2_4* callback) = 0; diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h index a27582a0e7..53e4404ea0 100644 --- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h +++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h @@ -64,10 +64,12 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { BaseType2_1::mDispatch.registerCallback( mDevice, HWC2_CALLBACK_VSYNC_2_4, this, reinterpret_cast(vsync_2_4_Hook)); - BaseType2_1::mDispatch.registerCallback( mDevice, HWC2_CALLBACK_VSYNC_PERIOD_TIMING_CHANGED, this, reinterpret_cast(vsyncPeriodTimingChangedHook)); + BaseType2_1::mDispatch.registerCallback( + mDevice, HWC2_CALLBACK_SEAMLESS_POSSIBLE, this, + reinterpret_cast(seamlessPossibleHook)); } void unregisterEventCallback_2_4() override { @@ -84,6 +86,8 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_2_4, this, nullptr); BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_PERIOD_TIMING_CHANGED, this, nullptr); + BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_SEAMLESS_POSSIBLE, this, + nullptr); mEventCallback_2_4 = nullptr; } @@ -273,6 +277,11 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { hal->mEventCallback_2_4->onVsyncPeriodTimingChanged(display, timeline); } + static void seamlessPossibleHook(hwc2_callback_data_t callbackData, hwc2_display_t display) { + auto hal = static_cast(callbackData); + hal->mEventCallback_2_4->onSeamlessPossible(display); + } + private: struct { HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE getDisplayConnectionType; From c8b0cd33b92db195e125171d7a1360af59a3ab8c Mon Sep 17 00:00:00 2001 From: Viet Dang Date: Tue, 26 Nov 2019 12:23:32 +0000 Subject: [PATCH 0409/1022] Add quantized LSTM op. Bug: 144841609 Test: NeuralNetworksTest_static Change-Id: I8aab51695382211e003d8fc442d33bae3006dc13 --- current.txt | 2 +- neuralnetworks/1.3/types.hal | 131 +++++++++++++++++- .../1.3/vts/functional/ValidateModel.cpp | 1 - 3 files changed, 131 insertions(+), 3 deletions(-) diff --git a/current.txt b/current.txt index bab1ff551f..5dc27cd3d7 100644 --- a/current.txt +++ b/current.txt @@ -648,7 +648,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice 258825966435b3ed08832055bb736d81516013e405f161d9ccde9a90cfcdde83 android.hardware.neuralnetworks@1.3::IPreparedModel 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -35668befe89fc7f84d58fc1dab7dd3e4d6067c7eeccbae154fe36cd964dfaef7 android.hardware.neuralnetworks@1.3::types +618a628f8c94d6f6e4cb401b69fa50ccb8b82191ea434e3a071252289b4f312c android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi 7d136c169b62abdee0bb6abafb97638acd792ce2102dfccddaa5df98d4bd3df9 android.hardware.wifi.hostapd@1.2::IHostapd 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index b70bd1bff4..74c259ca22 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -4746,6 +4746,135 @@ enum OperationType : int32_t { */ RESIZE_NEAREST_NEIGHBOR = @1.2::OperationType:RESIZE_NEAREST_NEIGHBOR, + /** + * Quantized version of {@link OperationType:LSTM}. + * + * The input and the output use asymmetric quantized types, while the rest + * use symmetric ones. + * + * Inputs: + * * 0: The input to the LSTM cell. + * Type: {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} + * Shape: [batchSize, inputSize] + * * 1: The input-to-input weights. Optional. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [numUnits, inputSize] + * * 2: The input-to-forget weights. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [numUnits, inputSize] + * * 3: The input-to-cell weights. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [numUnits, inputSize] + * * 4: The input-to-output weights. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [numUnits, inputSize] + * * 5: The recurrent-to-input weights. Optional. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [numUnits, outputSize] + * * 6: The recurrent-to-forget weights. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [numUnits, outputSize] + * * 7: The recurrent-to-cell weights. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [numUnits, outputSize] + * * 8: The recurrent-to-output weights. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [numUnits, outputSize] + * * 9: The cell-to-input weights (for peephole). Optional. + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [numUnits] + * * 10: The cell-to-forget weights (for peephole). Optional. + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [numUnits] + * * 11: The cell-to-output weights (for peephole). Optional. + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [numUnits] + * * 12: The input gate bias. Quantized with scale being the + * product of input and weights scales and zeroPoint equal to 0. + * Optional. + * Type: {@link OperandType::TENSOR_INT32} + * Shape: [numUnits] + * * 13: The forget gate bias. Quantized with scale being the + * product of input and weights scales and zeroPoint equal to 0. + * Type: {@link OperandType::TENSOR_INT32} + * Shape: [numUnits] + * * 14: The cell bias. Quantized with scale being the + * product of input and weights scales and zeroPoint equal to 0. + * Type: {@link OperandType::TENSOR_INT32} + * Shape: [numUnits] + * * 15: The output gate bias. Quantized with scale being the + * product of input and weights scales and zeroPoint equal to 0. + * Type: {@link OperandType::TENSOR_INT32} + * Shape: [numUnits] + * * 16: The projection weights. Optional. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [outputSize, numUnits] + * * 17: The projection bias. Quantized with scale being the + * product of input and weights scales and zeroPoint equal to 0. + * Optional. + * Type: {@link OperandType::TENSOR_INT32} + * Shape: [outputSize] + * * 18: The output from the previous time step. + * Type: {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} + * Shape: [batchSize, outputSize] + * * 19: The cell state from the previous time step. + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [batchSize, numUnits] + * * 20: The input layer normalization weights. Used to rescale + * normalized inputs to activation at input gate. Optional. + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [numUnits] + * * 21: The forget layer normalization weights. Used to + * rescale normalized inputs to activation at forget gate. Optional. + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [numUnits] + * * 22: The cell layer normalization weights. Used to rescale + * normalized inputs to activation at cell gate. Optional. + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [numUnits] + * * 23: The output layer normalization weights. Used to + * rescale normalized inputs to activation at output gate. Optional. + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [numUnits] + * * 24: The cell clip. If provided the cell state is clipped + * by this value prior to the cell output activation. Optional. + * Type: {@link OperandType::FLOAT32}. + * * 25: The projection clip. If provided and projection is enabled, + * this is used for clipping the projected values. Optional. + * Type: {@link OperandType::FLOAT32}. + * * 26: The scale of the intermediate result of matmul, + * i.e. input to layer normalization, at input gate. + * Type: {@link OperandType::FLOAT32}. + * * 27: The scale of the intermediate result of matmul, + * i.e. input to layer normalization, at forget gate. + * Type: {@link OperandType::FLOAT32}. + * * 28: The scale of the intermediate result of matmul, + * i.e. input to layer normalization, at cell gate. + * Type: {@link OperandType::FLOAT32}. + * * 29: The scale of the intermediate result of matmul, + * i.e. input to layer normalization, at output gate. + * Type: {@link OperandType::FLOAT32}. + * * 30: The zero point of the hidden state, i.e. input to + * projection. + * Type: {@link OperandType::INT32}. + * * 31: The scale of the hidden state, i.e. input to + * projection. + * Type: {@link OperandType::FLOAT32}. + * + * Outputs: + * * 0: The output state (out). + * Type: {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} + * Shape: [batchSize, outputSize] + * * 1: The cell state (out). + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [batchSize, numUnits] + * * 2: The output. This is effectively the same as the current + * "output state (out)" value. + * Type: {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} + * Shape: [batchSize, outputSize] + */ + QUANTIZED_LSTM = 95, + /** * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to * OEM operation and data types. @@ -4768,7 +4897,7 @@ enum OperationType : int32_t { enum OperationTypeRange : uint32_t { BASE_MIN = 0, FUNDAMENTAL_MIN = 0, - FUNDAMENTAL_MAX = 94, + FUNDAMENTAL_MAX = 95, OEM_MIN = 10000, OEM_MAX = 10000, BASE_MAX = 0xFFFF, diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 14ab897c8c..8395111d78 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -27,7 +27,6 @@ using implementation::PreparedModelCallback; using V1_0::ErrorStatus; using V1_0::OperandLifeTime; using V1_1::ExecutionPreference; -using V1_2::OperationTypeRange; using V1_2::SymmPerChannelQuantParams; using HidlToken = hidl_array(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; From baac15d5fd9678b1bb3b69b764e069b43407c272 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Thu, 9 Jan 2020 16:37:28 +0000 Subject: [PATCH 0410/1022] Enable QuantizationCouplingTest in NNAPI VTS Bug: 137828994 Test: NNTest_static and VtsHalNeuralnetworksV1_3TargetTest Change-Id: I9b4f20ab0287be9cae9fc1b69a8f64cc8f1996b0 --- neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index e3c537635a..eced063416 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -500,7 +500,7 @@ class GeneratedTest : public GeneratedTestBase {}; class DynamicOutputShapeTest : public GeneratedTest {}; // Tag for the dynamic output shape tests -class DISABLED_QuantizationCouplingTest : public GeneratedTest {}; +class QuantizationCouplingTest : public GeneratedTest {}; TEST_P(GeneratedTest, Test) { Execute(kDevice, kTestModel, /*testKind=*/TestKind::GENERAL); @@ -510,7 +510,7 @@ TEST_P(DynamicOutputShapeTest, Test) { Execute(kDevice, kTestModel, /*testKind=*/TestKind::DYNAMIC_SHAPE); } -TEST_P(DISABLED_QuantizationCouplingTest, Test) { +TEST_P(QuantizationCouplingTest, Test) { Execute(kDevice, kTestModel, /*testKind=*/TestKind::QUANTIZATION_COUPLING); } @@ -520,7 +520,7 @@ INSTANTIATE_GENERATED_TEST(GeneratedTest, INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); -INSTANTIATE_GENERATED_TEST(DISABLED_QuantizationCouplingTest, [](const TestModel& testModel) { +INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) { return testModel.hasQuant8CoupledOperands() && testModel.operations.size() == 1; }); From 0e99148d7aa863be1fe2c15a17cf24bb49bde58c Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Sat, 21 Dec 2019 12:56:47 -0800 Subject: [PATCH 0411/1022] Wifi: Add frequency list to chanelPrams in hostapd This commit adds a new parameter to the channel parameters for IHostapd Hidl interface to handle a list of channel freq in MHz to be used in ACS. This is needed as part of support of Wifi 6GHz band since 6GHz band channels use same channel numbers as 2.4/5GHz bands. Bug: 146186687 Bug: 139354972 Test: Manual Test: VTS test Change-Id: I8692f3cd28cfaae1d3b870c9f8dbcdd2ff350ee4 --- current.txt | 2 +- wifi/hostapd/1.2/IHostapd.hal | 37 +++++++++++-- .../1.2/vts/functional/hostapd_hidl_test.cpp | 53 +++++++++---------- 3 files changed, 61 insertions(+), 31 deletions(-) diff --git a/current.txt b/current.txt index 5dc27cd3d7..369b607c2c 100644 --- a/current.txt +++ b/current.txt @@ -650,7 +650,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback 618a628f8c94d6f6e4cb401b69fa50ccb8b82191ea434e3a071252289b4f312c android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi -7d136c169b62abdee0bb6abafb97638acd792ce2102dfccddaa5df98d4bd3df9 android.hardware.wifi.hostapd@1.2::IHostapd +514dc8b810658c45d7b0d34132b708cee2658ecedd9c7efc57d0d666ef182484 android.hardware.wifi.hostapd@1.2::IHostapd 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant c72cb37b3f66ef65aeb5c6438a3fbe17bbe847fdf62d1a76eafd7f3a8a526105 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface diff --git a/wifi/hostapd/1.2/IHostapd.hal b/wifi/hostapd/1.2/IHostapd.hal index b25ea97a87..5e6d80a616 100644 --- a/wifi/hostapd/1.2/IHostapd.hal +++ b/wifi/hostapd/1.2/IHostapd.hal @@ -57,6 +57,7 @@ interface IHostapd extends @1.1::IHostapd { * used with HE. */ bool enable80211AX; + /** * Whether 6GHz band enabled or not on softAp. * Note: hw_mode=a is used to specify that 5 GHz band or 6 GHz band is @@ -95,6 +96,21 @@ interface IHostapd extends @1.1::IHostapd { bool enableHeTargetWakeTime; }; + /** + * Parameters to specify the channel frequency range for ACS. + */ + struct AcsFrequencyRange { + /** + * Channel Frequency (in MHz) at the start of the range. + */ + uint32_t start; + + /** + * Channel Frequency (in MHz) at the end of the range. + */ + uint32_t end; + }; + /** * Parameters to control the channel selection for the interface. */ @@ -103,6 +119,15 @@ interface IHostapd extends @1.1::IHostapd { * Band to use for the SoftAp operations. */ bitfield bandMask; + + /** + * This option can be used to specify the channel frequencies (in MHz) selected by ACS. + * If this is an empty list, all channels allowed in selected HW mode + * are specified implicitly. + * Note: channels may be overridden by firmware. + * Note: this option is ignored if ACS is disabled. + */ + vec acsChannelFreqRangesMhz; }; /** @@ -113,9 +138,15 @@ interface IHostapd extends @1.1::IHostapd { * Baseline information as defined in HAL 1.1. */ @1.1::IHostapd.IfaceParams V1_1; - /** Additional Hw mode params for the interface */ + + /** + * Additional Hw mode params for the interface + */ HwModeParams hwModeParams; - /** Additional Channel params for the interface */ + + /** + * Additional Channel params for the interface + */ ChannelParams channelParams; }; @@ -135,7 +166,7 @@ interface IHostapd extends @1.1::IHostapd { * |HostapdStatusCode.FAILURE_IFACE_EXISTS| */ addAccessPoint_1_2(IfaceParams ifaceParams, NetworkParams nwParams) - generates(HostapdStatus status); + generates (HostapdStatus status); /** * force one of the hotspot clients disconnect.. diff --git a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp index 8245f8fc50..94cbb424b6 100644 --- a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp +++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp @@ -109,28 +109,26 @@ class HostapdHidlTest return iface_params_1_2; } - IHostapd::IfaceParams getIfaceParamsWithAcsAndChannelRange() { + IHostapd::IfaceParams getIfaceParamsWithAcsAndFreqRange() { IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithAcs(); - ::android::hardware::wifi::hostapd::V1_1::IHostapd::ChannelParams - channelParams; - ::android::hardware::wifi::hostapd::V1_1::IHostapd::AcsChannelRange - acsChannelRange; - acsChannelRange.start = 1; - acsChannelRange.end = 11; - std::vector< - ::android::hardware::wifi::hostapd::V1_1::IHostapd::AcsChannelRange> - vec_acsChannelRange; - vec_acsChannelRange.push_back(acsChannelRange); - channelParams.acsChannelRanges = vec_acsChannelRange; - iface_params_1_2.V1_1.channelParams = channelParams; + ::android::hardware::wifi::hostapd::V1_2::IHostapd::AcsFrequencyRange + acsFrequencyRange; + acsFrequencyRange.start = 2412; + acsFrequencyRange.end = 2462; + std::vector<::android::hardware::wifi::hostapd::V1_2::IHostapd:: + AcsFrequencyRange> + vec_acsFrequencyRange; + vec_acsFrequencyRange.push_back(acsFrequencyRange); + iface_params_1_2.channelParams.acsChannelFreqRangesMhz = + vec_acsFrequencyRange; return iface_params_1_2; } - IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidChannelRange() { + IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidFreqRange() { IHostapd::IfaceParams iface_params_1_2 = - getIfaceParamsWithAcsAndChannelRange(); - iface_params_1_2.V1_1.channelParams.acsChannelRanges[0].start = 222; - iface_params_1_2.V1_1.channelParams.acsChannelRanges[0].end = 999; + getIfaceParamsWithAcsAndFreqRange(); + iface_params_1_2.channelParams.acsChannelFreqRangesMhz[0].start = 222; + iface_params_1_2.channelParams.acsChannelFreqRangesMhz[0].end = 999; return iface_params_1_2; } @@ -186,13 +184,13 @@ TEST_P(HostapdHidlTest, AddPskAccessPointWithAcs) { } /** - * Adds an access point with PSK network config, ACS enabled & channel Range. + * Adds an access point with PSK network config, ACS enabled & frequency Range. * Access point creation should pass. */ -TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndChannelRange) { +TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndFreqRange) { auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, - getIfaceParamsWithAcsAndChannelRange(), getPskNwParams()); + getIfaceParamsWithAcsAndFreqRange(), getPskNwParams()); // TODO: b/140172237, fix this in R // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); } @@ -201,9 +199,9 @@ TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndChannelRange) { * Adds an access point with invalid channel range. * Access point creation should fail. */ -TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidChannelRange) { +TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidFreqRange) { auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, - getIfaceParamsWithAcsAndInvalidChannelRange(), + getIfaceParamsWithAcsAndInvalidFreqRange(), getPskNwParams()); // TODO: b/140172237, fix this in R // EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); @@ -245,14 +243,15 @@ TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) { * Access point creation & removal should pass. */ TEST_P(HostapdHidlTest, RemoveAccessPointWithAcs) { - auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, - getIfaceParamsWithAcs(), getPskNwParams()); + auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, + getIfaceParamsWithAcs(), getPskNwParams()); // TODO: b/140172237, fix this in R /* - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); - status = + EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code); + auto status = HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + EXPECT_EQ(android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS, + status.code); */ } From d64367312e27eae31523839ae46b5bcc9e66a6b3 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Tue, 5 Nov 2019 13:11:18 -0800 Subject: [PATCH 0412/1022] Convert VtsHalWifiSupplicantV1_*TargetTest to be parameterized test Bug: 142397658 Test: atest VtsHalWifiSupplicantV1_1TargetTest \ VtsHalWifiSupplicantV1_2TargetTest \ VtsHalWifiSupplicantP2pV1_2TargetTest Change-Id: I14a3e94d0b3681c5a3ebd17435dc36d279790c79 --- .../functional/supplicant_hidl_test_utils.cpp | 10 +++ wifi/supplicant/1.1/vts/functional/Android.bp | 7 +- .../VtsHalWifiSupplicantV1_1TargetTest.cpp | 43 +-------- .../vts/functional/supplicant_hidl_test.cpp | 54 +++++++----- .../supplicant_hidl_test_utils_1_1.cpp | 18 ++-- .../supplicant_hidl_test_utils_1_1.h | 44 ++++++++-- .../supplicant_sta_iface_hidl_test.cpp | 58 ++++++++----- .../supplicant_sta_network_hidl_test.cpp | 87 +++++++++++-------- wifi/supplicant/1.2/vts/functional/Android.bp | 12 ++- .../VtsHalWifiSupplicantV1_2TargetTest.cpp | 45 +--------- .../supplicant_hidl_test_utils_1_2.cpp | 22 +++-- .../supplicant_hidl_test_utils_1_2.h | 49 +++++++++-- .../supplicant_p2p_iface_hidl_test.cpp | 35 +++++--- .../supplicant_sta_iface_hidl_test.cpp | 37 +++++--- .../supplicant_sta_network_hidl_test.cpp | 43 +++++---- 15 files changed, 328 insertions(+), 236 deletions(-) diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp index d47e42f43e..d0df4a42a1 100644 --- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp +++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp @@ -57,6 +57,11 @@ namespace { // Helper function to initialize the driver and firmware to STA mode // using the vendor HAL HIDL interface. void initilializeDriverAndFirmware(const std::string& wifi_instance_name) { + // Skip if wifi instance is not set. + if (wifi_instance_name == "") { + return; + } + sp wifi_chip = getWifiChip(wifi_instance_name); ChipModeId mode_id; EXPECT_TRUE(configureChipToSupportIfaceType( @@ -66,6 +71,11 @@ void initilializeDriverAndFirmware(const std::string& wifi_instance_name) { // Helper function to deinitialize the driver and firmware // using the vendor HAL HIDL interface. void deInitilializeDriverAndFirmware(const std::string& wifi_instance_name) { + // Skip if wifi instance is not set. + if (wifi_instance_name == "") { + return; + } + stopWifi(wifi_instance_name); } diff --git a/wifi/supplicant/1.1/vts/functional/Android.bp b/wifi/supplicant/1.1/vts/functional/Android.bp index 84575321b8..6bcfa8ab5f 100644 --- a/wifi/supplicant/1.1/vts/functional/Android.bp +++ b/wifi/supplicant/1.1/vts/functional/Android.bp @@ -19,7 +19,7 @@ cc_library_static { defaults: ["VtsHalTargetTestDefaults"], srcs: ["supplicant_hidl_test_utils_1_1.cpp"], export_include_dirs: [ - "." + ".", ], static_libs: [ "VtsHalWifiV1_0TargetTestUtil", @@ -54,5 +54,8 @@ cc_test { "libwifi-system", "libwifi-system-iface", ], - test_suites: ["general-tests"], + test_suites: [ + "general-tests", + "vts-core", + ], } diff --git a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp b/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp index 9063a3ba4c..f582cc1ff6 100644 --- a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp +++ b/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp @@ -14,45 +14,8 @@ * limitations under the License. */ -#include -#include -#include - #include "supplicant_hidl_test_utils.h" -#include "wifi_hidl_test_utils.h" -class WifiSupplicantHidlEnvironment_1_1 : public WifiSupplicantHidlEnvironment { - public: - // get the test environment singleton - static WifiSupplicantHidlEnvironment_1_1* Instance() { - static WifiSupplicantHidlEnvironment_1_1* instance = - new WifiSupplicantHidlEnvironment_1_1; - return instance; - } - virtual void registerTestServices() override { - registerTestService<::android::hardware::wifi::V1_0::IWifi>(); - registerTestService<::android::hardware::wifi::V1_1::IWifi>(); - registerTestService< - ::android::hardware::wifi::supplicant::V1_0::ISupplicant>(); - registerTestService< - ::android::hardware::wifi::supplicant::V1_1::ISupplicant>(); - } - - private: - WifiSupplicantHidlEnvironment_1_1() {} -}; - -WifiSupplicantHidlEnvironment* gEnv = - WifiSupplicantHidlEnvironment_1_1::Instance(); - -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(gEnv); - ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - int status = gEnv->initFromOptions(argc, argv); - if (status == 0) { - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - } - return status; -} +// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is +// updated. +WifiSupplicantHidlEnvironment* gEnv = nullptr; diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp index 28f980cf85..24a7ec31aa 100644 --- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp +++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp @@ -17,10 +17,12 @@ #include #include -#include - +#include +#include #include #include +#include +#include #include "supplicant_hidl_test_utils.h" #include "supplicant_hidl_test_utils_1_1.h" @@ -33,22 +35,11 @@ using ::android::hardware::wifi::supplicant::V1_0::IfaceType; using ::android::hardware::wifi::supplicant::V1_1::ISupplicant; using ::android::sp; -extern WifiSupplicantHidlEnvironment* gEnv; - -class SupplicantHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class SupplicantHidlTest : public SupplicantHidlTestBase { public: - virtual void SetUp() override { - startSupplicantAndWaitForHidlService(); - supplicant_ = getSupplicant_1_1(); - ASSERT_NE(supplicant_.get(), nullptr); - } - - virtual void TearDown() override { stopSupplicant(); } + virtual void SetUp() override { SupplicantHidlTestBase::SetUp(); } protected: - // ISupplicant object used for all tests in this fixture. - sp supplicant_; - std::string getWlan0IfaceName() { std::array buffer; property_get("wifi.interface", buffer.data(), "wlan0"); @@ -65,7 +56,7 @@ class SupplicantHidlTest : public ::testing::VtsHalHidlTargetTestBase { /* * AddStaInterface */ -TEST_F(SupplicantHidlTest, AddStaInterface) { +TEST_P(SupplicantHidlTest, AddStaInterface) { ISupplicant::IfaceInfo iface_info; iface_info.name = getWlan0IfaceName(); iface_info.type = IfaceType::STA; @@ -82,8 +73,8 @@ TEST_F(SupplicantHidlTest, AddStaInterface) { /* * AddP2pInterface */ -TEST_F(SupplicantHidlTest, AddP2pInterface) { - if (!gEnv->isP2pOn) return; +TEST_P(SupplicantHidlTest, AddP2pInterface) { + if (isP2pOn_) return; ISupplicant::IfaceInfo iface_info; iface_info.name = getP2pIfaceName(); iface_info.type = IfaceType::P2P; @@ -100,7 +91,7 @@ TEST_F(SupplicantHidlTest, AddP2pInterface) { /* * RemoveStaInterface */ -TEST_F(SupplicantHidlTest, RemoveStaInterface) { +TEST_P(SupplicantHidlTest, RemoveStaInterface) { ISupplicant::IfaceInfo iface_info; iface_info.name = getWlan0IfaceName(); iface_info.type = IfaceType::STA; @@ -122,8 +113,8 @@ TEST_F(SupplicantHidlTest, RemoveStaInterface) { /* * RemoveP2pInterface */ -TEST_F(SupplicantHidlTest, RemoveP2pInterface) { - if (!gEnv->isP2pOn) return; +TEST_P(SupplicantHidlTest, RemoveP2pInterface) { + if (isP2pOn_) return; ISupplicant::IfaceInfo iface_info; iface_info.name = getP2pIfaceName(); iface_info.type = IfaceType::P2P; @@ -146,6 +137,23 @@ TEST_F(SupplicantHidlTest, RemoveP2pInterface) { * Terminate * This terminates the service. */ -TEST_F(SupplicantHidlTest, Terminate) { - supplicant_->terminate(); +TEST_P(SupplicantHidlTest, Terminate) { supplicant_->terminate(); } + +static std::vector get_wifi_instances() { + std::vector instances = + android::hardware::getAllHalInstanceNames( + android::hardware::wifi::V1_0::IWifi::descriptor); + // Also test when wifi instance is not set. + instances.push_back(""); + + return instances; } + +INSTANTIATE_TEST_CASE_P( + PerInstance, SupplicantHidlTest, + testing::Combine( + testing::ValuesIn(get_wifi_instances()), + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::wifi::supplicant::V1_1::ISupplicant:: + descriptor))), + android::hardware::PrintInstanceTupleNameToString<>); diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp index 04a5ed9d1a..b75a2fbccc 100644 --- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp +++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include "supplicant_hidl_test_utils.h" @@ -25,14 +24,19 @@ using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIface; using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaNetwork; using ::android::sp; -sp getSupplicant_1_1() { - return ISupplicant::castFrom(getSupplicant()); +sp getSupplicant_1_1(const std::string& supplicant_instance_name, + bool isP2pOn) { + return ISupplicant::castFrom( + getSupplicant(supplicant_instance_name, isP2pOn)); } -sp getSupplicantStaIface_1_1() { - return ISupplicantStaIface::castFrom(getSupplicantStaIface()); +sp getSupplicantStaIface_1_1( + const sp& supplicant) { + return ISupplicantStaIface::castFrom(getSupplicantStaIface(supplicant)); } -sp createSupplicantStaNetwork_1_1() { - return ISupplicantStaNetwork::castFrom(createSupplicantStaNetwork()); +sp createSupplicantStaNetwork_1_1( + const sp& supplicant) { + return ISupplicantStaNetwork::castFrom( + createSupplicantStaNetwork(supplicant)); } diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h index 1c13325f4f..3629882f94 100644 --- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h +++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h @@ -14,20 +14,52 @@ * limitations under the License. */ -#ifndef SUPPLICANT_HIDL_TEST_UTILS_1_1_H -#define SUPPLICANT_HIDL_TEST_UTILS_1_1_H +#pragma once +#pragma clang diagnostic ignored "-Wweak-vtables" +#include #include #include #include +#include android::sp - getSupplicant_1_1(); +getSupplicant_1_1(const std::string& supplicant_instance_name, bool isP2pOn); android::sp - getSupplicantStaIface_1_1(); +getSupplicantStaIface_1_1( + const android::sp& + supplicant); android::sp - createSupplicantStaNetwork_1_1(); +createSupplicantStaNetwork_1_1( + const android::sp& + supplicant); -#endif /* SUPPLICANT_HIDL_TEST_UTILS_1_1_H */ +class SupplicantHidlTestBase + : public ::testing::TestWithParam> { + public: + virtual void SetUp() override { + wifi_v1_0_instance_name_ = std::get<0>(GetParam()); + supplicant_v1_1_instance_name_ = std::get<1>(GetParam()); + isP2pOn_ = + testing::deviceSupportsFeature("android.hardware.wifi.direct"); + stopSupplicant(wifi_v1_0_instance_name_); + startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_, + supplicant_v1_1_instance_name_); + supplicant_ = + getSupplicant_1_1(supplicant_v1_1_instance_name_, isP2pOn_); + ASSERT_NE(supplicant_.get(), nullptr); + } + + virtual void TearDown() override { + stopSupplicant(wifi_v1_0_instance_name_); + } + + protected: + android::sp + supplicant_; + bool isP2pOn_ = false; + std::string wifi_v1_0_instance_name_; + std::string supplicant_v1_1_instance_name_; +}; diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp index c5e6319de9..8a1aeccf7d 100644 --- a/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp +++ b/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp @@ -16,9 +16,13 @@ #include -#include - +#include +#include +#include #include +#include +#include +#include #include "supplicant_hidl_test_utils.h" #include "supplicant_hidl_test_utils_1_1.h" @@ -29,26 +33,24 @@ using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIface; -using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIfaceCallback; using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus; using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; +using ::android::hardware::wifi::supplicant::V1_1::ISupplicant; +using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIface; +using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIfaceCallback; -class SupplicantStaIfaceHidlTest - : public ::testing::VtsHalHidlTargetTestBase { - public: - virtual void SetUp() override { - startSupplicantAndWaitForHidlService(); - EXPECT_TRUE(turnOnExcessiveLogging()); - sta_iface_ = getSupplicantStaIface_1_1(); - ASSERT_NE(sta_iface_.get(), nullptr); - } +class SupplicantStaIfaceHidlTest : public SupplicantHidlTestBase { + public: + virtual void SetUp() override { + SupplicantHidlTestBase::SetUp(); + EXPECT_TRUE(turnOnExcessiveLogging(supplicant_)); + sta_iface_ = getSupplicantStaIface_1_1(supplicant_); + ASSERT_NE(sta_iface_.get(), nullptr); + } - virtual void TearDown() override { stopSupplicant(); } - - protected: - // ISupplicantStaIface object used for all tests in this fixture. - sp sta_iface_; + protected: + // ISupplicantStaIface object used for all tests in this fixture. + sp sta_iface_; }; class IfaceCallback : public ISupplicantStaIfaceCallback { @@ -131,9 +133,19 @@ class IfaceCallback : public ISupplicantStaIfaceCallback { /* * RegisterCallback_1_1 */ -TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback_1_1) { - sta_iface_->registerCallback_1_1( - new IfaceCallback(), [](const SupplicantStatus& status) { - EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); - }); +TEST_P(SupplicantStaIfaceHidlTest, RegisterCallback_1_1) { + sta_iface_->registerCallback_1_1( + new IfaceCallback(), [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); } + +INSTANTIATE_TEST_CASE_P( + PerInstance, SupplicantStaIfaceHidlTest, + testing::Combine( + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::wifi::V1_0::IWifi::descriptor)), + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::wifi::supplicant::V1_1::ISupplicant:: + descriptor))), + android::hardware::PrintInstanceTupleNameToString<>); \ No newline at end of file diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_sta_network_hidl_test.cpp index fa52556b7a..a4b7d40b53 100644 --- a/wifi/supplicant/1.1/vts/functional/supplicant_sta_network_hidl_test.cpp +++ b/wifi/supplicant/1.1/vts/functional/supplicant_sta_network_hidl_test.cpp @@ -16,8 +16,11 @@ #include -#include +#include +#include #include +#include +#include #include "supplicant_hidl_test_utils.h" #include "supplicant_hidl_test_utils_1_1.h" @@ -26,27 +29,26 @@ using ::android::sp; using ::android::hardware::hidl_vec; using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus; using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; +using ::android::hardware::wifi::supplicant::V1_1::ISupplicant; using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaNetwork; + namespace { constexpr uint8_t kTestIdentity[] = {0x45, 0x67, 0x98, 0x67, 0x56}; constexpr uint8_t kTestEncryptedIdentity[] = {0x35, 0x37, 0x58, 0x57, 0x26}; } // namespace -class SupplicantStaNetworkHidlTest - : public ::testing::VtsHalHidlTargetTestBase { - public: - virtual void SetUp() override { - startSupplicantAndWaitForHidlService(); - EXPECT_TRUE(turnOnExcessiveLogging()); - sta_network_ = createSupplicantStaNetwork_1_1(); - ASSERT_NE(sta_network_.get(), nullptr); - } +class SupplicantStaNetworkHidlTest : public SupplicantHidlTestBase { + public: + virtual void SetUp() override { + SupplicantHidlTestBase::SetUp(); + EXPECT_TRUE(turnOnExcessiveLogging(supplicant_)); + sta_network_ = createSupplicantStaNetwork_1_1(supplicant_); + ASSERT_NE(sta_network_.get(), nullptr); + } - virtual void TearDown() override { stopSupplicant(); } - - protected: - // ISupplicantStaNetwork object used for all tests in this fixture. - sp sta_network_; + protected: + // ISupplicantStaNetwork object used for all tests in this fixture. + sp sta_network_; }; /* @@ -54,36 +56,49 @@ class SupplicantStaNetworkHidlTest * Ensures that an instance of the ISupplicantStaNetwork proxy object is * successfully created. */ -TEST(SupplicantStaNetworkHidlTestNoFixture, Create) { - startSupplicantAndWaitForHidlService(); - EXPECT_NE(nullptr, createSupplicantStaNetwork_1_1().get()); - stopSupplicant(); +TEST_P(SupplicantStaNetworkHidlTest, Create) { + stopSupplicant(wifi_v1_0_instance_name_); + startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_, + supplicant_v1_1_instance_name_); + sp supplicant = + getSupplicant_1_1(supplicant_v1_1_instance_name_, isP2pOn_); + EXPECT_NE(nullptr, createSupplicantStaNetwork_1_1(supplicant).get()); } /* * Ensure that the encrypted imsi identity is set successfully. */ -TEST_F(SupplicantStaNetworkHidlTest, setEapEncryptedImsiIdentity) { - std::vector encrypted_identity( - kTestEncryptedIdentity, - kTestEncryptedIdentity + sizeof(kTestEncryptedIdentity)); - sta_network_->setEapEncryptedImsiIdentity( - encrypted_identity, [](const SupplicantStatus &status) { - EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); - }); +TEST_P(SupplicantStaNetworkHidlTest, setEapEncryptedImsiIdentity) { + std::vector encrypted_identity( + kTestEncryptedIdentity, + kTestEncryptedIdentity + sizeof(kTestEncryptedIdentity)); + sta_network_->setEapEncryptedImsiIdentity( + encrypted_identity, [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); } /* * Ensure that the identity and the encrypted imsi identity are sent * successfully. */ -TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapIdentityResponse_1_1) { - sta_network_->sendNetworkEapIdentityResponse_1_1( - std::vector(kTestIdentity, - kTestIdentity + sizeof(kTestIdentity)), - std::vector(kTestEncryptedIdentity, - kTestIdentity + sizeof(kTestEncryptedIdentity)), - [](const SupplicantStatus &status) { - EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); - }); +TEST_P(SupplicantStaNetworkHidlTest, SendNetworkEapIdentityResponse_1_1) { + sta_network_->sendNetworkEapIdentityResponse_1_1( + std::vector(kTestIdentity, + kTestIdentity + sizeof(kTestIdentity)), + std::vector(kTestEncryptedIdentity, + kTestIdentity + sizeof(kTestEncryptedIdentity)), + [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); } + +INSTANTIATE_TEST_CASE_P( + PerInstance, SupplicantStaNetworkHidlTest, + testing::Combine( + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::wifi::V1_0::IWifi::descriptor)), + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::wifi::supplicant::V1_1::ISupplicant:: + descriptor))), + android::hardware::PrintInstanceTupleNameToString<>); \ No newline at end of file diff --git a/wifi/supplicant/1.2/vts/functional/Android.bp b/wifi/supplicant/1.2/vts/functional/Android.bp index 7e9d4f6a47..9781074a69 100644 --- a/wifi/supplicant/1.2/vts/functional/Android.bp +++ b/wifi/supplicant/1.2/vts/functional/Android.bp @@ -19,7 +19,7 @@ cc_library_static { defaults: ["VtsHalTargetTestDefaults"], srcs: ["supplicant_hidl_test_utils_1_2.cpp"], export_include_dirs: [ - "." + ".", ], static_libs: [ "VtsHalWifiV1_0TargetTestUtil", @@ -58,7 +58,10 @@ cc_test { "libwifi-system", "libwifi-system-iface", ], - test_suites: ["general-tests"], + test_suites: [ + "general-tests", + "vts-core", + ], } cc_test { @@ -82,5 +85,8 @@ cc_test { "libwifi-system", "libwifi-system-iface", ], + test_suites: [ + "general-tests", + "vts-core", + ], } - diff --git a/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp index 267fa67364..9dbeee104f 100644 --- a/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp +++ b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp @@ -14,47 +14,8 @@ * limitations under the License. */ -#include -#include -#include - #include "supplicant_hidl_test_utils.h" -#include "wifi_hidl_test_utils.h" -class WifiSupplicantHidlEnvironment_1_2 : public WifiSupplicantHidlEnvironment { - public: - // get the test environment singleton - static WifiSupplicantHidlEnvironment_1_2* Instance() { - static WifiSupplicantHidlEnvironment_1_2* instance = - new WifiSupplicantHidlEnvironment_1_2; - return instance; - } - virtual void registerTestServices() override { - registerTestService<::android::hardware::wifi::V1_0::IWifi>(); - registerTestService<::android::hardware::wifi::V1_1::IWifi>(); - registerTestService< - ::android::hardware::wifi::supplicant::V1_0::ISupplicant>(); - registerTestService< - ::android::hardware::wifi::supplicant::V1_1::ISupplicant>(); - registerTestService< - ::android::hardware::wifi::supplicant::V1_2::ISupplicant>(); - } - - private: - WifiSupplicantHidlEnvironment_1_2() {} -}; - -WifiSupplicantHidlEnvironment* gEnv = - WifiSupplicantHidlEnvironment_1_2::Instance(); - -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(gEnv); - ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - int status = gEnv->initFromOptions(argc, argv); - if (status == 0) { - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - } - return status; -} +// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is +// updated. +WifiSupplicantHidlEnvironment* gEnv = nullptr; diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp index f270bff673..480929af2b 100644 --- a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp +++ b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp @@ -26,18 +26,24 @@ using ::android::hardware::wifi::supplicant::V1_2::ISupplicantP2pIface; using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface; using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork; -sp getSupplicant_1_2() { - return ISupplicant::castFrom(getSupplicant()); +sp getSupplicant_1_2(const std::string& supplicant_instance_name, + bool isP2pOn) { + return ISupplicant::castFrom( + getSupplicant(supplicant_instance_name, isP2pOn)); } -sp getSupplicantStaIface_1_2() { - return ISupplicantStaIface::castFrom(getSupplicantStaIface()); +sp getSupplicantStaIface_1_2( + const sp& supplicant) { + return ISupplicantStaIface::castFrom(getSupplicantStaIface(supplicant)); } -sp createSupplicantStaNetwork_1_2() { - return ISupplicantStaNetwork::castFrom(createSupplicantStaNetwork()); +sp createSupplicantStaNetwork_1_2( + const sp& supplicant) { + return ISupplicantStaNetwork::castFrom( + createSupplicantStaNetwork(supplicant)); } -sp getSupplicantP2pIface_1_2() { - return ISupplicantP2pIface::castFrom(getSupplicantP2pIface()); +sp getSupplicantP2pIface_1_2( + const sp& supplicant) { + return ISupplicantP2pIface::castFrom(getSupplicantP2pIface(supplicant)); } diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h index 8a7ccc5dac..5ecfdd48ef 100644 --- a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h +++ b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h @@ -14,24 +14,59 @@ * limitations under the License. */ -#ifndef SUPPLICANT_HIDL_TEST_UTILS_1_2_H -#define SUPPLICANT_HIDL_TEST_UTILS_1_2_H +#pragma once +#pragma clang diagnostic ignored "-Wweak-vtables" +#include #include #include #include #include +#include android::sp -getSupplicant_1_2(); +getSupplicant_1_2(const std::string& supplicant_instance_name, bool isP2pOn); android::sp -getSupplicantStaIface_1_2(); +getSupplicantStaIface_1_2( + const android::sp& + supplicant); android::sp -createSupplicantStaNetwork_1_2(); +createSupplicantStaNetwork_1_2( + const android::sp& + supplicant); android::sp -getSupplicantP2pIface_1_2(); +getSupplicantP2pIface_1_2( + const android::sp& + supplicant); -#endif /* SUPPLICANT_HIDL_TEST_UTILS_1_2_H */ +class SupplicantHidlTestBase + : public ::testing::TestWithParam> { + public: + virtual void SetUp() override { + wifi_v1_0_instance_name_ = std::get<0>(GetParam()); + supplicant_v1_2_instance_name_ = std::get<1>(GetParam()); + isP2pOn_ = + testing::deviceSupportsFeature("android.hardware.wifi.direct"); + stopSupplicant(wifi_v1_0_instance_name_); + startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_, + supplicant_v1_2_instance_name_); + supplicant_ = + getSupplicant_1_2(supplicant_v1_2_instance_name_, isP2pOn_); + ASSERT_NE(supplicant_.get(), nullptr); + EXPECT_TRUE(turnOnExcessiveLogging(supplicant_)); + } + + virtual void TearDown() override { + stopSupplicant(wifi_v1_0_instance_name_); + } + + protected: + android::sp + supplicant_; + bool isP2pOn_ = false; + std::string wifi_v1_0_instance_name_; + std::string supplicant_v1_2_instance_name_; +}; diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp index 1b78ac3e01..2b63ad0ea0 100644 --- a/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp +++ b/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp @@ -18,7 +18,11 @@ #include +#include +#include #include +#include +#include #include "supplicant_hidl_test_utils.h" #include "supplicant_hidl_test_utils_1_2.h" @@ -26,6 +30,7 @@ using ::android::sp; using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus; using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; +using ::android::hardware::wifi::supplicant::V1_2::ISupplicant; using ::android::hardware::wifi::supplicant::V1_2::ISupplicantP2pIface; namespace { @@ -35,17 +40,15 @@ constexpr char kTestPassphrase[] = "P2pWorld1234"; constexpr uint8_t kTestZeroMacAddr[] = {[0 ... 5] = 0x0}; } // namespace -class SupplicantP2pIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class SupplicantP2pIfaceHidlTest : public SupplicantHidlTestBase { public: virtual void SetUp() override { - startSupplicantAndWaitForHidlService(); - EXPECT_TRUE(turnOnExcessiveLogging()); - p2p_iface_ = getSupplicantP2pIface_1_2(); + SupplicantHidlTestBase::SetUp(); + EXPECT_TRUE(turnOnExcessiveLogging(supplicant_)); + p2p_iface_ = getSupplicantP2pIface_1_2(supplicant_); ASSERT_NE(p2p_iface_.get(), nullptr); } - virtual void TearDown() override { stopSupplicant(); } - protected: // ISupplicantP2pIface object used for all tests in this fixture. sp p2p_iface_; @@ -54,7 +57,7 @@ class SupplicantP2pIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { /* * Verify that AddGroup_1_2 could create a group successfully. */ -TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_Success) { +TEST_P(SupplicantP2pIfaceHidlTest, AddGroup_1_2_Success) { std::vector ssid(kTestSsid, kTestSsid + sizeof(kTestSsid)); std::string passphrase = kTestPassphrase; int freq = 0; @@ -73,7 +76,7 @@ TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_Success) { /* * Verify that AddGroup_1_2 fails due to invalid SSID. */ -TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidSsid) { +TEST_P(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidSsid) { std::vector ssid; std::string passphrase = kTestPassphrase; int freq = 0; @@ -92,7 +95,7 @@ TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidSsid) { /* * Verify that AddGroup_1_2 fails due to invalid passphrase. */ -TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidPassphrase) { +TEST_P(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidPassphrase) { std::vector ssid(kTestSsid, kTestSsid + sizeof(kTestSsid)); std::string passphrase = "1234"; int freq = 0; @@ -111,7 +114,7 @@ TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidPassphrase) { /* * Verify that AddGroup_1_2 fails due to invalid frequency. */ -TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidFrequency) { +TEST_P(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidFrequency) { std::vector ssid(kTestSsid, kTestSsid + sizeof(kTestSsid)); std::string passphrase = kTestPassphrase; int freq = 9999; @@ -134,7 +137,7 @@ bool isMacRandomizationSupported(const SupplicantStatus& status) { /* * Verify that setMacRandomization successes. */ -TEST_F(SupplicantP2pIfaceHidlTest, EnableMacRandomization) { +TEST_P(SupplicantP2pIfaceHidlTest, EnableMacRandomization) { p2p_iface_->setMacRandomization(true, [](const SupplicantStatus& status) { if (!isMacRandomizationSupported(status)) return; EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); @@ -157,3 +160,13 @@ TEST_F(SupplicantP2pIfaceHidlTest, EnableMacRandomization) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); }); } + +INSTANTIATE_TEST_CASE_P( + PerInstance, SupplicantP2pIfaceHidlTest, + testing::Combine( + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::wifi::V1_0::IWifi::descriptor)), + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::wifi::supplicant::V1_2::ISupplicant:: + descriptor))), + android::hardware::PrintInstanceTupleNameToString<>); diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp index 6272d30a1c..8116c3f21a 100644 --- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp +++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp @@ -14,7 +14,8 @@ * limitations under the License. */ -#include +#include +#include #include #include #include @@ -24,7 +25,9 @@ #include #include #include +#include #include +#include #include #include "supplicant_hidl_test_utils.h" @@ -42,6 +45,7 @@ using ::android::hardware::wifi::supplicant::V1_2::DppAkm; using ::android::hardware::wifi::supplicant::V1_2::DppFailureCode; using ::android::hardware::wifi::supplicant::V1_2::DppNetRole; using ::android::hardware::wifi::supplicant::V1_2::DppProgressCode; +using ::android::hardware::wifi::supplicant::V1_2::ISupplicant; using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface; using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaIfaceCallback; using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork; @@ -49,18 +53,16 @@ using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork; #define TIMEOUT_PERIOD 60 class IfaceDppCallback; -class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class SupplicantStaIfaceHidlTest : public SupplicantHidlTestBase { public: virtual void SetUp() override { - startSupplicantAndWaitForHidlService(); - EXPECT_TRUE(turnOnExcessiveLogging()); - sta_iface_ = getSupplicantStaIface_1_2(); + SupplicantHidlTestBase::SetUp(); + EXPECT_TRUE(turnOnExcessiveLogging(supplicant_)); + sta_iface_ = getSupplicantStaIface_1_2(supplicant_); ASSERT_NE(sta_iface_.get(), nullptr); count_ = 0; } - virtual void TearDown() override { stopSupplicant(); } - enum DppCallbackType { ANY_CALLBACK = -2, INVALID = -1, @@ -101,6 +103,7 @@ class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { protected: // ISupplicantStaIface object used for all tests in this fixture. sp sta_iface_; + bool isDppSupported() { uint32_t keyMgmtMask = 0; @@ -254,7 +257,7 @@ class IfaceDppCallback : public IfaceCallback { /* * RegisterCallback_1_2 */ -TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback_1_2) { +TEST_P(SupplicantStaIfaceHidlTest, RegisterCallback_1_2) { sta_iface_->registerCallback_1_2( new IfaceCallback(), [](const SupplicantStatus& status) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); @@ -264,7 +267,7 @@ TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback_1_2) { /* * GetKeyMgmtCapabilities */ -TEST_F(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities) { +TEST_P(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities) { sta_iface_->getKeyMgmtCapabilities( [&](const SupplicantStatus& status, uint32_t keyMgmtMask) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); @@ -280,7 +283,7 @@ TEST_F(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities) { /* * AddDppPeerUriAndRomveUri */ -TEST_F(SupplicantStaIfaceHidlTest, AddDppPeerUriAndRomveUri) { +TEST_P(SupplicantStaIfaceHidlTest, AddDppPeerUriAndRomveUri) { // We need to first get the key management capabilities from the device. // If DPP is not supported, we just pass the test. if (!isDppSupported()) { @@ -312,7 +315,7 @@ TEST_F(SupplicantStaIfaceHidlTest, AddDppPeerUriAndRomveUri) { /* * StartDppEnrolleeInitiator */ -TEST_F(SupplicantStaIfaceHidlTest, StartDppEnrolleeInitiator) { +TEST_P(SupplicantStaIfaceHidlTest, StartDppEnrolleeInitiator) { // We need to first get the key management capabilities from the device. // If DPP is not supported, we just pass the test. if (!isDppSupported()) { @@ -376,7 +379,7 @@ TEST_F(SupplicantStaIfaceHidlTest, StartDppEnrolleeInitiator) { /* * StartDppConfiguratorInitiator */ -TEST_F(SupplicantStaIfaceHidlTest, StartDppConfiguratorInitiator) { +TEST_P(SupplicantStaIfaceHidlTest, StartDppConfiguratorInitiator) { // We need to first get the key management capabilities from the device. // If DPP is not supported, we just pass the test. if (!isDppSupported()) { @@ -443,3 +446,13 @@ TEST_F(SupplicantStaIfaceHidlTest, StartDppConfiguratorInitiator) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); }); } + +INSTANTIATE_TEST_CASE_P( + PerInstance, SupplicantStaIfaceHidlTest, + testing::Combine( + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::wifi::V1_0::IWifi::descriptor)), + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::wifi::supplicant::V1_2::ISupplicant:: + descriptor))), + android::hardware::PrintInstanceTupleNameToString<>); \ No newline at end of file diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp index ed421d73d7..4c3d808627 100644 --- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp +++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp @@ -16,8 +16,12 @@ #include -#include +#include +#include +#include #include +#include +#include #include "supplicant_hidl_test_utils.h" #include "supplicant_hidl_test_utils_1_2.h" @@ -26,24 +30,21 @@ using ::android::sp; using ::android::hardware::hidl_vec; using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus; using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; +using ::android::hardware::wifi::supplicant::V1_2::ISupplicant; using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork; // namespace { // constexpr uint8_t kTestIdentity[] = {0x45, 0x67, 0x98, 0x67, 0x56}; // constexpr uint8_t kTestEncryptedIdentity[] = {0x35, 0x37, 0x58, 0x57, 0x26}; //} // namespace -class SupplicantStaNetworkHidlTest - : public ::testing::VtsHalHidlTargetTestBase { +class SupplicantStaNetworkHidlTest : public SupplicantHidlTestBase { public: virtual void SetUp() override { - startSupplicantAndWaitForHidlService(); - EXPECT_TRUE(turnOnExcessiveLogging()); - sta_network_ = createSupplicantStaNetwork_1_2(); + SupplicantHidlTestBase::SetUp(); + sta_network_ = createSupplicantStaNetwork_1_2(supplicant_); ASSERT_NE(sta_network_.get(), nullptr); } - virtual void TearDown() override { stopSupplicant(); } - protected: // ISupplicantStaNetwork object used for all tests in this fixture. sp sta_network_; @@ -52,7 +53,7 @@ class SupplicantStaNetworkHidlTest /* * SetGetSaePassword */ -TEST_F(SupplicantStaNetworkHidlTest, SetGetSaePassword) { +TEST_P(SupplicantStaNetworkHidlTest, SetGetSaePassword) { std::string password = "topsecret"; sta_network_->setSaePassword(password, [](const SupplicantStatus &status) { @@ -69,7 +70,7 @@ TEST_F(SupplicantStaNetworkHidlTest, SetGetSaePassword) { /* * SetGetSaePasswordId */ -TEST_F(SupplicantStaNetworkHidlTest, SetGetSaePasswordId) { +TEST_P(SupplicantStaNetworkHidlTest, SetGetSaePasswordId) { std::string passwordId = "id1"; sta_network_->setSaePasswordId( @@ -87,7 +88,7 @@ TEST_F(SupplicantStaNetworkHidlTest, SetGetSaePasswordId) { /* * SetGetGroupMgmtCipher */ -TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupMgmtCipher) { +TEST_P(SupplicantStaNetworkHidlTest, SetGetGroupMgmtCipher) { uint32_t groupMgmtCipher = (uint32_t)ISupplicantStaNetwork::GroupMgmtCipherMask::BIP_GMAC_256; @@ -107,7 +108,7 @@ TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupMgmtCipher) { /* * SetGetKeyMgmt_1_2 */ -TEST_F(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_2) { +TEST_P(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_2) { uint32_t keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::SAE; sta_network_->setKeyMgmt_1_2(keyMgmt, [](const SupplicantStatus &status) { @@ -124,7 +125,7 @@ TEST_F(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_2) { /* * SetGetGroupCipher_1_2 */ -TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_2) { +TEST_P(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_2) { uint32_t groupCipher = (uint32_t)ISupplicantStaNetwork::GroupCipherMask::GCMP_256; @@ -144,7 +145,7 @@ TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_2) { /* * SetGetPairwiseCipher_1_2 */ -TEST_F(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_2) { +TEST_P(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_2) { uint32_t pairwiseCipher = (uint32_t)ISupplicantStaNetwork::PairwiseCipherMask::GCMP_256; @@ -164,7 +165,7 @@ TEST_F(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_2) { /* * EnableSuiteBEapOpenSslCiphers */ -TEST_F(SupplicantStaNetworkHidlTest, EnableSuiteBEapOpenSslCiphers) { +TEST_P(SupplicantStaNetworkHidlTest, EnableSuiteBEapOpenSslCiphers) { sta_network_->enableSuiteBEapOpenSslCiphers( [](const SupplicantStatus &status) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); @@ -179,7 +180,7 @@ TEST_F(SupplicantStaNetworkHidlTest, EnableSuiteBEapOpenSslCiphers) { /* * EnableTlsSuiteBEapPhase1Param */ -TEST_F(SupplicantStaNetworkHidlTest, EnableTlsSuiteBEapPhase1Param) { +TEST_P(SupplicantStaNetworkHidlTest, EnableTlsSuiteBEapPhase1Param) { sta_network_->enableTlsSuiteBEapPhase1Param( true, [](const SupplicantStatus &status) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); @@ -190,3 +191,13 @@ TEST_F(SupplicantStaNetworkHidlTest, EnableTlsSuiteBEapPhase1Param) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); }); } + +INSTANTIATE_TEST_CASE_P( + PerInstance, SupplicantStaNetworkHidlTest, + testing::Combine( + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::wifi::V1_0::IWifi::descriptor)), + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::wifi::supplicant::V1_2::ISupplicant:: + descriptor))), + android::hardware::PrintInstanceTupleNameToString<>); From 2be3570bc91f3d2661f3603dc1288cb2a9cea9ef Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Wed, 8 Jan 2020 13:48:09 -0800 Subject: [PATCH 0413/1022] Make sure passthrough fails initialization if required interfaces can not be initialized. All required interfaces must be able to initialized, make sure passthrough fails if the requirement is not met. BUG: b/147365206 Test: boot Change-Id: I148655bc5392b1c0bc45f33ea3d2020824bb6f4b --- .../include/composer-passthrough/2.3/HwcHal.h | 14 +++++++------- .../include/composer-passthrough/2.4/HwcHal.h | 11 +++++++---- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h index d3b29bb803..e0e1394027 100644 --- a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h +++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h @@ -294,9 +294,6 @@ class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl { (brightness < 0.0f && brightness != -1.0f)) { return Error::BAD_PARAMETER; } - if (!mDispatch.setDisplayBrightness) { - return Error::UNSUPPORTED; - } int32_t error = mDispatch.setDisplayBrightness(mDevice, display, brightness); return static_cast(error); } @@ -307,6 +304,13 @@ class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl { return false; } + if (!BaseType2_1::initDispatch(HWC2_FUNCTION_GET_DISPLAY_CAPABILITIES, + &mDispatch.getDisplayCapabilities) || + !BaseType2_1::initDispatch(HWC2_FUNCTION_SET_DISPLAY_BRIGHTNESS, + &mDispatch.setDisplayBrightness)) { + return false; + } + this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA, &mDispatch.getDisplayIdentificationData); this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM, @@ -317,14 +321,10 @@ class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl { &mDispatch.setDisplayedContentSamplingEnabled); this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAYED_CONTENT_SAMPLE, &mDispatch.getDisplayedContentSample); - this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_CAPABILITIES, - &mDispatch.getDisplayCapabilities); this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_PER_FRAME_METADATA_BLOBS, &mDispatch.setLayerPerFrameMetadataBlobs); this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_BRIGHTNESS_SUPPORT, &mDispatch.getDisplayBrightnessSupport); - this->initOptionalDispatch(HWC2_FUNCTION_SET_DISPLAY_BRIGHTNESS, - &mDispatch.setDisplayBrightness); return true; } diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h index a34572d843..9e7684d389 100644 --- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h +++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h @@ -220,12 +220,15 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { return false; } + if (!BaseType2_1::initDispatch(HWC2_FUNCTION_GET_DISPLAY_VSYNC_PERIOD, + &mDispatch.getDisplayVsyncPeriod) || + !BaseType2_1::initDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS, + &mDispatch.setActiveConfigWithConstraints)) { + return false; + } + this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_CONNECTION_TYPE, &mDispatch.getDisplayConnectionType); - this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_VSYNC_PERIOD, - &mDispatch.getDisplayVsyncPeriod); - this->initOptionalDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS, - &mDispatch.setActiveConfigWithConstraints); this->initOptionalDispatch(HWC2_FUNCTION_SET_AUTO_LOW_LATENCY_MODE, &mDispatch.setAutoLowLatencyMode); this->initOptionalDispatch(HWC2_FUNCTION_GET_SUPPORTED_CONTENT_TYPES, From ad96dd9f12a500124a82eef42e9368a83a4b75a6 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Thu, 9 Jan 2020 13:42:15 -0800 Subject: [PATCH 0414/1022] [composer] Add createCommandWriter to command engine. Command engine always uses V2.1 CommandWriterBase, change the creation of command writer inside command engine so that we can use the right version of command writer. BUG: b/147365206 Test: build and boot. Change-Id: I61fbbce19a44244725621e9a1cef750bd4c78b4d --- .../composer-hal/2.1/ComposerCommandEngine.h | 92 ++++++++++--------- .../composer-hal/2.2/ComposerCommandEngine.h | 9 +- .../composer-hal/2.3/ComposerCommandEngine.h | 11 ++- 3 files changed, 64 insertions(+), 48 deletions(-) diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h index 53b9202b97..b173e2eeb0 100644 --- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h +++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h @@ -39,8 +39,10 @@ namespace hal { // TODO own a CommandReaderBase rather than subclassing class ComposerCommandEngine : protected CommandReaderBase { public: - ComposerCommandEngine(ComposerHal* hal, ComposerResources* resources) - : mHal(hal), mResources(resources) {} + ComposerCommandEngine(ComposerHal* hal, ComposerResources* resources) + : mHal(hal), mResources(resources) { + mWriter = createCommandWriter(kWriterInitialSize); + } virtual ~ComposerCommandEngine() = default; @@ -74,16 +76,16 @@ class ComposerCommandEngine : protected CommandReaderBase { return Error::BAD_PARAMETER; } - return mWriter.writeQueue(outQueueChanged, outCommandLength, outCommandHandles) - ? Error::NONE - : Error::NO_RESOURCES; + return mWriter->writeQueue(outQueueChanged, outCommandLength, outCommandHandles) + ? Error::NONE + : Error::NO_RESOURCES; } - const MQDescriptorSync* getOutputMQDescriptor() { return mWriter.getMQDescriptor(); } + const MQDescriptorSync* getOutputMQDescriptor() { return mWriter->getMQDescriptor(); } void reset() { CommandReaderBase::reset(); - mWriter.reset(); + mWriter->reset(); } protected: @@ -140,13 +142,17 @@ class ComposerCommandEngine : protected CommandReaderBase { } } + virtual std::unique_ptr createCommandWriter(size_t writerInitialSize) { + return std::make_unique(writerInitialSize); + } + bool executeSelectDisplay(uint16_t length) { if (length != CommandWriterBase::kSelectDisplayLength) { return false; } mCurrentDisplay = read64(); - mWriter.selectDisplay(mCurrentDisplay); + mWriter->selectDisplay(mCurrentDisplay); return true; } @@ -174,7 +180,7 @@ class ComposerCommandEngine : protected CommandReaderBase { auto err = mHal->setColorTransform(mCurrentDisplay, matrix, transform); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -208,7 +214,7 @@ class ComposerCommandEngine : protected CommandReaderBase { close(fence); } if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -239,7 +245,7 @@ class ComposerCommandEngine : protected CommandReaderBase { close(fence); } if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -260,10 +266,10 @@ class ComposerCommandEngine : protected CommandReaderBase { &displayRequestMask, &requestedLayers, &requestMasks); mResources->setDisplayMustValidateState(mCurrentDisplay, false); if (err == Error::NONE) { - mWriter.setChangedCompositionTypes(changedLayers, compositionTypes); - mWriter.setDisplayRequests(displayRequestMask, requestedLayers, requestMasks); + mWriter->setChangedCompositionTypes(changedLayers, compositionTypes); + mWriter->setDisplayRequests(displayRequestMask, requestedLayers, requestMasks); } else { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -283,9 +289,9 @@ class ComposerCommandEngine : protected CommandReaderBase { ? Error::NOT_VALIDATED : mHal->presentDisplay(mCurrentDisplay, &presentFence, &layers, &fences); if (err == Error::NONE) { - mWriter.setPresentOrValidateResult(1); - mWriter.setPresentFence(presentFence); - mWriter.setReleaseFences(layers, fences); + mWriter->setPresentOrValidateResult(1); + mWriter->setPresentFence(presentFence); + mWriter->setReleaseFences(layers, fences); return true; } } @@ -301,11 +307,11 @@ class ComposerCommandEngine : protected CommandReaderBase { &displayRequestMask, &requestedLayers, &requestMasks); mResources->setDisplayMustValidateState(mCurrentDisplay, false); if (err == Error::NONE) { - mWriter.setPresentOrValidateResult(0); - mWriter.setChangedCompositionTypes(changedLayers, compositionTypes); - mWriter.setDisplayRequests(displayRequestMask, requestedLayers, requestMasks); + mWriter->setPresentOrValidateResult(0); + mWriter->setChangedCompositionTypes(changedLayers, compositionTypes); + mWriter->setDisplayRequests(displayRequestMask, requestedLayers, requestMasks); } else { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -318,7 +324,7 @@ class ComposerCommandEngine : protected CommandReaderBase { auto err = mHal->acceptDisplayChanges(mCurrentDisplay); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -334,10 +340,10 @@ class ComposerCommandEngine : protected CommandReaderBase { std::vector fences; auto err = mHal->presentDisplay(mCurrentDisplay, &presentFence, &layers, &fences); if (err == Error::NONE) { - mWriter.setPresentFence(presentFence); - mWriter.setReleaseFences(layers, fences); + mWriter->setPresentFence(presentFence); + mWriter->setReleaseFences(layers, fences); } else { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -351,7 +357,7 @@ class ComposerCommandEngine : protected CommandReaderBase { auto err = mHal->setLayerCursorPosition(mCurrentDisplay, mCurrentLayer, readSigned(), readSigned()); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -382,7 +388,7 @@ class ComposerCommandEngine : protected CommandReaderBase { close(fence); } if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -397,7 +403,7 @@ class ComposerCommandEngine : protected CommandReaderBase { auto damage = readRegion(length / 4); auto err = mHal->setLayerSurfaceDamage(mCurrentDisplay, mCurrentLayer, damage); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -410,7 +416,7 @@ class ComposerCommandEngine : protected CommandReaderBase { auto err = mHal->setLayerBlendMode(mCurrentDisplay, mCurrentLayer, readSigned()); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -423,7 +429,7 @@ class ComposerCommandEngine : protected CommandReaderBase { auto err = mHal->setLayerColor(mCurrentDisplay, mCurrentLayer, readColor()); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -436,7 +442,7 @@ class ComposerCommandEngine : protected CommandReaderBase { auto err = mHal->setLayerCompositionType(mCurrentDisplay, mCurrentLayer, readSigned()); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -449,7 +455,7 @@ class ComposerCommandEngine : protected CommandReaderBase { auto err = mHal->setLayerDataspace(mCurrentDisplay, mCurrentLayer, readSigned()); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -462,7 +468,7 @@ class ComposerCommandEngine : protected CommandReaderBase { auto err = mHal->setLayerDisplayFrame(mCurrentDisplay, mCurrentLayer, readRect()); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -475,7 +481,7 @@ class ComposerCommandEngine : protected CommandReaderBase { auto err = mHal->setLayerPlaneAlpha(mCurrentDisplay, mCurrentLayer, readFloat()); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -496,7 +502,7 @@ class ComposerCommandEngine : protected CommandReaderBase { err = mHal->setLayerSidebandStream(mCurrentDisplay, mCurrentLayer, stream); } if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -509,7 +515,7 @@ class ComposerCommandEngine : protected CommandReaderBase { auto err = mHal->setLayerSourceCrop(mCurrentDisplay, mCurrentLayer, readFRect()); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -522,7 +528,7 @@ class ComposerCommandEngine : protected CommandReaderBase { auto err = mHal->setLayerTransform(mCurrentDisplay, mCurrentLayer, readSigned()); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -537,7 +543,7 @@ class ComposerCommandEngine : protected CommandReaderBase { auto region = readRegion(length / 4); auto err = mHal->setLayerVisibleRegion(mCurrentDisplay, mCurrentLayer, region); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -550,7 +556,7 @@ class ComposerCommandEngine : protected CommandReaderBase { auto err = mHal->setLayerZOrder(mCurrentDisplay, mCurrentLayer, read()); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -579,12 +585,12 @@ class ComposerCommandEngine : protected CommandReaderBase { }; } - ComposerHal* mHal; - ComposerResources* mResources; - // 64KiB minus a small space for metadata such as read/write pointers static constexpr size_t kWriterInitialSize = 64 * 1024 / sizeof(uint32_t) - 16; - CommandWriterBase mWriter{kWriterInitialSize}; + + ComposerHal* mHal; + ComposerResources* mResources; + std::unique_ptr mWriter; Display mCurrentDisplay = 0; Layer mCurrentLayer = 0; diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h index d9f6226ad9..8d70ba2aac 100644 --- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h +++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h @@ -49,6 +49,11 @@ class ComposerCommandEngine : public V2_1::hal::ComposerCommandEngine { } } + std::unique_ptr createCommandWriter( + size_t writerInitialSize) override { + return std::make_unique(writerInitialSize); + } + bool executeSetLayerPerFrameMetadata(uint16_t length) { // (key, value) pairs if (length % 2 != 0) { @@ -65,7 +70,7 @@ class ComposerCommandEngine : public V2_1::hal::ComposerCommandEngine { auto err = mHal->setLayerPerFrameMetadata(mCurrentDisplay, mCurrentLayer, metadata); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -78,7 +83,7 @@ class ComposerCommandEngine : public V2_1::hal::ComposerCommandEngine { auto err = mHal->setLayerFloatColor(mCurrentDisplay, mCurrentLayer, readFloatColor()); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h index 329dbed51f..02f62127bd 100644 --- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h +++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h @@ -50,6 +50,11 @@ class ComposerCommandEngine : public V2_2::hal::ComposerCommandEngine { } } + std::unique_ptr createCommandWriter( + size_t writerInitialSize) override { + return std::make_unique(writerInitialSize); + } + bool executeSetLayerColorTransform(uint16_t length) { if (length != CommandWriterBase::kSetLayerColorTransformLength) { return false; @@ -61,7 +66,7 @@ class ComposerCommandEngine : public V2_2::hal::ComposerCommandEngine { } auto err = mHal->setLayerColorTransform(mCurrentDisplay, mCurrentLayer, matrix); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; @@ -97,7 +102,7 @@ class ComposerCommandEngine : public V2_2::hal::ComposerCommandEngine { } auto err = mHal->setLayerPerFrameMetadataBlobs(mCurrentDisplay, mCurrentLayer, metadata); if (err != Error::NONE) { - mWriter.setError(getCommandLoc(), err); + mWriter->setError(getCommandLoc(), err); } return true; } @@ -111,8 +116,8 @@ class ComposerCommandEngine : public V2_2::hal::ComposerCommandEngine { private: using BaseType2_1 = V2_1::hal::ComposerCommandEngine; - using BaseType2_1::mWriter; using BaseType2_2 = V2_2::hal::ComposerCommandEngine; + using BaseType2_1::mWriter; ComposerHal* mHal; }; From 1cc02e52d946cc5c1e51ce7d2686258ab8413628 Mon Sep 17 00:00:00 2001 From: lesl Date: Thu, 26 Dec 2019 15:18:58 +0800 Subject: [PATCH 0415/1022] hostapd: Add SAE Support Bug: 142752869 Test: Manuel Test: vts-tradefed run commandAndExit vts-hal --skip-all-system-status-check --primary-abi-only --skip-preconditions --module VtsHalWifiHostapdV1_2Target -l INFO Change-Id: I811760206d05825f11f07f71cef21ed03a8c7204 --- current.txt | 2 +- wifi/hostapd/1.2/IHostapd.hal | 25 ++++ .../1.2/vts/functional/hostapd_hidl_test.cpp | 112 +++++++++++++++--- 3 files changed, 119 insertions(+), 20 deletions(-) diff --git a/current.txt b/current.txt index 78e66fe984..b19bd10b4a 100644 --- a/current.txt +++ b/current.txt @@ -650,7 +650,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback 618a628f8c94d6f6e4cb401b69fa50ccb8b82191ea434e3a071252289b4f312c android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi -514dc8b810658c45d7b0d34132b708cee2658ecedd9c7efc57d0d666ef182484 android.hardware.wifi.hostapd@1.2::IHostapd +42e72d7c8fd843d2611ffb9142bfae61dcdb5325860c6602825863f086a91bff android.hardware.wifi.hostapd@1.2::IHostapd 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant c72cb37b3f66ef65aeb5c6438a3fbe17bbe847fdf62d1a76eafd7f3a8a526105 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface diff --git a/wifi/hostapd/1.2/IHostapd.hal b/wifi/hostapd/1.2/IHostapd.hal index 5e6d80a616..5126d1299c 100644 --- a/wifi/hostapd/1.2/IHostapd.hal +++ b/wifi/hostapd/1.2/IHostapd.hal @@ -16,6 +16,7 @@ package android.hardware.wifi.hostapd@1.2; +import @1.0::IHostapd.EncryptionType; import @1.0::IHostapd.NetworkParams; import @1.1::IHostapd; import HostapdStatus; @@ -27,6 +28,12 @@ import DebugLevel; * Top-level object for managing SoftAPs. */ interface IHostapd extends @1.1::IHostapd { + /** Possible Security types. */ + enum EncryptionType : @1.0::IHostapd.EncryptionType { + WPA3_SAE_TRANSITION, + WPA3_SAE, + }; + /** * Band bitmMask to use for the SoftAp operations. * A combinatoin of these bits are used to identify the allowed bands @@ -150,6 +157,24 @@ interface IHostapd extends @1.1::IHostapd { ChannelParams channelParams; }; + /** + * Parameters to use for setting up the access point network. + */ + struct NetworkParams { + /** + * Baseline information as defined in HAL 1.0. + */ + @1.0::IHostapd.NetworkParams V1_0; + /** Key management mask for the replace V1_0.encryptionType. */ + EncryptionType encryptionType; + /** + * Passphrase for WPA3_SAE network, WPA3_SAE_TRANSITION and + * WPA2_PSK. Replaces @1.0::IHostapd.NetworkParams.pskPassphrase. + */ + string passphrase; + }; + + /** * Adds a new access point for hostapd to control. * diff --git a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp index 94cbb424b6..9f57934a34 100644 --- a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp +++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp @@ -41,6 +41,9 @@ namespace { constexpr unsigned char kNwSsid[] = {'t', 'e', 's', 't', '1', '2', '3', '4', '5'}; constexpr char kNwPassphrase[] = "test12345"; +constexpr char kInvalidMaxPskNwPassphrase[] = + "0123456789012345678901234567890123456789012345678901234567890123456789"; +constexpr char kInvalidMinPskNwPassphrase[] = "test"; constexpr int kIfaceChannel = 6; constexpr int kIfaceInvalidChannel = 567; constexpr uint8_t kTestZeroMacAddr[] = {[0 ... 5] = 0x0}; @@ -61,7 +64,7 @@ class HostapdHidlTest ASSERT_NE(hostapd_.get(), nullptr); } - virtual void TearDown() override { stopHostapd(wifi_instance_name_); } + virtual void TearDown() override { stopHostapd(hostapd_instance_name_); } protected: std::string getPrimaryWlanIfaceName() { @@ -133,31 +136,59 @@ class HostapdHidlTest } IHostapd::NetworkParams getOpenNwParams() { - IHostapd::NetworkParams nw_params; - nw_params.ssid = + IHostapd::NetworkParams nw_params_1_2; + ::android::hardware::wifi::hostapd::V1_0::IHostapd::NetworkParams + nw_params_1_0; + nw_params_1_0.ssid = std::vector(kNwSsid, kNwSsid + sizeof(kNwSsid)); - nw_params.isHidden = false; - nw_params.encryptionType = IHostapd::EncryptionType::NONE; - return nw_params; + nw_params_1_0.isHidden = false; + nw_params_1_2.V1_0 = nw_params_1_0; + nw_params_1_2.encryptionType = IHostapd::EncryptionType::NONE; + return nw_params_1_2; } IHostapd::NetworkParams getPskNwParams() { - IHostapd::NetworkParams nw_params; - nw_params.ssid = - std::vector(kNwSsid, kNwSsid + sizeof(kNwSsid)); - nw_params.isHidden = false; - nw_params.encryptionType = IHostapd::EncryptionType::WPA2; - nw_params.pskPassphrase = kNwPassphrase; - return nw_params; + IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams(); + nw_params_1_2.encryptionType = IHostapd::EncryptionType::WPA2; + nw_params_1_2.passphrase = kNwPassphrase; + return nw_params_1_2; } IHostapd::NetworkParams getInvalidPskNwParams() { - IHostapd::NetworkParams nw_params; - nw_params.ssid = - std::vector(kNwSsid, kNwSsid + sizeof(kNwSsid)); - nw_params.isHidden = false; - nw_params.encryptionType = IHostapd::EncryptionType::WPA2; - return nw_params; + IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams(); + nw_params_1_2.encryptionType = IHostapd::EncryptionType::WPA2; + nw_params_1_2.passphrase = kInvalidMaxPskNwPassphrase; + + return nw_params_1_2; + } + + IHostapd::NetworkParams getSaeTransitionNwParams() { + IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams(); + nw_params_1_2.encryptionType = + IHostapd::EncryptionType::WPA3_SAE_TRANSITION; + nw_params_1_2.passphrase = kNwPassphrase; + return nw_params_1_2; + } + + IHostapd::NetworkParams getInvalidSaeTransitionNwParams() { + IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams(); + nw_params_1_2.encryptionType = IHostapd::EncryptionType::WPA2; + nw_params_1_2.passphrase = kInvalidMinPskNwPassphrase; + return nw_params_1_2; + } + + IHostapd::NetworkParams getSaeNwParams() { + IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams(); + nw_params_1_2.encryptionType = IHostapd::EncryptionType::WPA3_SAE; + nw_params_1_2.passphrase = kNwPassphrase; + return nw_params_1_2; + } + + IHostapd::NetworkParams getInvalidSaeNwParams() { + IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams(); + nw_params_1_2.encryptionType = IHostapd::EncryptionType::WPA3_SAE; + nw_params_1_2.passphrase = ""; + return nw_params_1_2; } IHostapd::IfaceParams getIfaceParamsWithInvalidChannel() { @@ -238,6 +269,27 @@ TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) { EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); } +/** + * Adds an access point with SAE Transition network config & ACS disabled. + * Access point creation should pass. + */ +TEST_P(HostapdHidlTest, AddSaeTransitionAccessPointWithoutAcs) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(), + getSaeTransitionNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with SAE network config & ACS disabled. + * Access point creation should pass. + */ +TEST_P(HostapdHidlTest, AddSAEAccessPointWithoutAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, + getIfaceParamsWithoutAcs(), getSaeNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + /** * Adds & then removes an access point with PSK network config & ACS enabled. * Access point creation & removal should pass. @@ -292,6 +344,28 @@ TEST_P(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) { EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); } +/** + * Adds an access point with invalid SAE transition network config. + * Access point creation should fail. + */ +TEST_P(HostapdHidlTest, AddInvalidSaeTransitionAccessPointWithoutAcs) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(), + getInvalidSaeTransitionNwParams()); + EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with invalid SAE network config. + * Access point creation should fail. + */ +TEST_P(HostapdHidlTest, AddInvalidSaeAccessPointWithoutAcs) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(), + getInvalidSaeNwParams()); + EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); +} + /** * forceClientDisconnect should return FAILURE_IFACE_UNKNOWN * when hotspot interface doesn't init.. From da5079c5cd6093cc6275e1f686b24a6a0c8a925c Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Fri, 10 Jan 2020 16:47:23 +0000 Subject: [PATCH 0416/1022] Fix quantized LSTM doc The CL changes explicit prefixes for types in types.spec to a macro, so that the prefixes of tensor types are correct both in NDK and HAL docs. Bug: 144841609 Test: mma Change-Id: I6d904bd3a858f555beed9270f141f080f96e429a --- current.txt | 2 +- neuralnetworks/1.3/types.hal | 2 +- neuralnetworks/1.3/types.t | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/current.txt b/current.txt index 78e66fe984..a4e223db4e 100644 --- a/current.txt +++ b/current.txt @@ -648,7 +648,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice 258825966435b3ed08832055bb736d81516013e405f161d9ccde9a90cfcdde83 android.hardware.neuralnetworks@1.3::IPreparedModel 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -618a628f8c94d6f6e4cb401b69fa50ccb8b82191ea434e3a071252289b4f312c android.hardware.neuralnetworks@1.3::types +f3c1e7298da628a755b452cd3325e8d0fe867a2debb873069baab6a27434a72d android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi 514dc8b810658c45d7b0d34132b708cee2658ecedd9c7efc57d0d666ef182484 android.hardware.wifi.hostapd@1.2::IHostapd 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index 74c259ca22..62c5833500 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -4747,7 +4747,7 @@ enum OperationType : int32_t { RESIZE_NEAREST_NEIGHBOR = @1.2::OperationType:RESIZE_NEAREST_NEIGHBOR, /** - * Quantized version of {@link OperationType:LSTM}. + * Quantized version of {@link OperationType::LSTM}. * * The input and the output use asymmetric quantized types, while the rest * use symmetric ones. diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t index e06f5d630d..0d20d06f7d 100644 --- a/neuralnetworks/1.3/types.t +++ b/neuralnetworks/1.3/types.t @@ -57,6 +57,8 @@ enum OperationType : int32_t { %insert Operation_1.2 +%insert Operation_1.3 + /** * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to * OEM operation and data types. From 857821c288f8279ad6d142a73b4ba2c5f10159ce Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 9 Jan 2020 18:59:44 -0800 Subject: [PATCH 0417/1022] Add Some Buffer Lines to Avoid Merge Conflicts Because other teams are changing HAL hashes downstream, the git conflict resolution algorithm detects conflicts due to changes in adjacent lines, even though they aren't real conflicts. This CL adds buffer lines to convince git and by extension the auto-merger that the changes may be safely merged. Note: these should be removed prior to release. Bug: 144366823 Test: make (non-functional change) Change-Id: Ie8785da99ce68e1db85face30c6c633385ecb085 --- current.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/current.txt b/current.txt index 3f169db58e..44f01d70f5 100644 --- a/current.txt +++ b/current.txt @@ -657,6 +657,9 @@ c72cb37b3f66ef65aeb5c6438a3fbe17bbe847fdf62d1a76eafd7f3a8a526105 android.hardwar 342a8e12db4dca643f2755eb4167e8f103d96502053a25a1f51f42107a4530f1 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback 8835e9799cddf7c239f60beff467cbdf164331f70a8b6c06ed78982d7810d835 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 91015479f5a0fba9872e98d3cca4680995de64f42ae71461b4b7e5acc5a196ab android.hardware.wifi.supplicant@1.3::types +## +# BEGIN Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present +## 2c0587a1e83facba604949c31163486f21eb5b47a29c8f29119a47d3bd052103 android.hardware.radio@1.5::types b5cfa87882b416105fe01e8a40a856d36c93d64f1103d77e12b1281cea13b0bd android.hardware.radio@1.5::IRadio bc59237dbd93949238081f762710552e76670cb648c0e198138551460ac54b1e android.hardware.radio@1.5::IRadioIndication @@ -665,5 +668,8 @@ ef10e15cdbe8ba63925302a95962d5679bbda6a4351400cc23e1589ca0e9f94b android.hardwar b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication 7683fed9d253956071f18b152e6be657719536f98d9b534433d5e411bcde5061 android.hardware.radio.config@1.3::IRadioConfigResponse +## +# END Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present +## b46d358537168c478762c3d34d5fe1555a3fcd89cd1f43621350ada395e6f795 android.hardware.soundtrigger@2.3::types 15924fbf38b3c282299a37e48c72405c97e322f844f815081db6acbca22d4165 android.hardware.soundtrigger@2.3::ISoundTriggerHw From 539cbb724fce5a841a5249cc66c1054619a3efcf Mon Sep 17 00:00:00 2001 From: Nicholas Ambur Date: Mon, 16 Dec 2019 11:31:13 -0800 Subject: [PATCH 0418/1022] add audioCapabilities to SoundTrigger properties Bug: 146363190 Test: Assist GTS test suite and manual testing Change-Id: Ie14844f63e8d87d3baad7e6c50230fe04153f8b4 --- current.txt | 4 +- soundtrigger/2.3/ISoundTriggerHw.hal | 23 +++++ soundtrigger/2.3/default/SoundTriggerHw.cpp | 85 ++++++++++++++++++- soundtrigger/2.3/default/SoundTriggerHw.h | 4 + soundtrigger/2.3/types.hal | 36 ++++++++ .../VtsHalSoundtriggerV2_3TargetTest.cpp | 3 + 6 files changed, 152 insertions(+), 3 deletions(-) diff --git a/current.txt b/current.txt index d171052dc3..2931495462 100644 --- a/current.txt +++ b/current.txt @@ -671,5 +671,5 @@ b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardwar ## # END Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present ## -b46d358537168c478762c3d34d5fe1555a3fcd89cd1f43621350ada395e6f795 android.hardware.soundtrigger@2.3::types -15924fbf38b3c282299a37e48c72405c97e322f844f815081db6acbca22d4165 android.hardware.soundtrigger@2.3::ISoundTriggerHw +51d1c8d285e0456da2a3fdfbf4700c6277165d5e83219894d651c8ea0e39aa8b android.hardware.soundtrigger@2.3::types +12d7533ff0754f45bf59ab300799074570a99a676545652c2c23abc73cb4515d android.hardware.soundtrigger@2.3::ISoundTriggerHw diff --git a/soundtrigger/2.3/ISoundTriggerHw.hal b/soundtrigger/2.3/ISoundTriggerHw.hal index 23aa36ead0..270b00e44f 100644 --- a/soundtrigger/2.3/ISoundTriggerHw.hal +++ b/soundtrigger/2.3/ISoundTriggerHw.hal @@ -17,7 +17,9 @@ package android.hardware.soundtrigger@2.3; import @2.0::SoundModelHandle; +import @2.0::ISoundTriggerHwCallback.CallbackCookie; import @2.2::ISoundTriggerHw; +import @2.1::ISoundTriggerHwCallback; /** * SoundTrigger HAL interface. Used for hardware recognition of hotwords @@ -37,6 +39,27 @@ interface ISoundTriggerHw extends @2.2::ISoundTriggerHw { */ getProperties_2_3() generates (int32_t retval, Properties properties); + /** + * Start recognition on a given model. Only one recognition active + * at a time per model. Once recognition succeeds or fails, the callback + * associated with the model handle is called. + * + * Must have the exact same semantics as startRecognition from + * ISoundTriggerHw@2.1 except that the RecognitionConfig includes audio + * capabilities applied when the recognition is active. + * + * @param modelHandle the handle of the sound model to use for recognition + * @param config A RecognitionConfig structure containing attributes of the + * recognition to perform + * @return retval Operation completion status: 0 in case of success, + * -EINVAL in case of invalid recognition attributes, + * -ENOSYS in case of invalid model handle, + * -ENOMEM in case of memory allocation failure, + * -ENODEV in case of initialization error. + */ + startRecognition_2_3(SoundModelHandle modelHandle, RecognitionConfig config) + generates (int32_t retval); + /** * Set a model specific parameter with the given value. This parameter * will keep its value for the duration the model is loaded regardless of starting and stopping diff --git a/soundtrigger/2.3/default/SoundTriggerHw.cpp b/soundtrigger/2.3/default/SoundTriggerHw.cpp index 9fd8fe0e5c..d3136b9a63 100644 --- a/soundtrigger/2.3/default/SoundTriggerHw.cpp +++ b/soundtrigger/2.3/default/SoundTriggerHw.cpp @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #define LOG_TAG "SoundTriggerHw" #include "SoundTriggerHw.h" @@ -357,6 +356,7 @@ void SoundTriggerHw::convertPropertiesFromHal( (const struct sound_trigger_properties_extended_1_3*)header; convertPropertiesFromHal(&properties->base, &halProperties->base); properties->supportedModelArch = halProperties->supported_model_arch; + properties->audioCapabilities = halProperties->audio_capabilities; } } @@ -460,6 +460,54 @@ struct sound_trigger_recognition_config* SoundTriggerHw::convertRecognitionConfi return halConfig; } +struct sound_trigger_recognition_config_header* SoundTriggerHw::convertRecognitionConfigToHalHeader( + const V2_3::RecognitionConfig* config) { + sp memory; + const V2_1::ISoundTriggerHw::RecognitionConfig* config_2_1 = &config->base; + const V2_0::ISoundTriggerHw::RecognitionConfig* config_2_0 = &config_2_1->header; + + size_t allocSize = + sizeof(struct sound_trigger_recognition_config_extended_1_3) + config_2_1->data.size(); + struct sound_trigger_recognition_config_extended_1_3* halConfigExtended = + static_cast(malloc(allocSize)); + LOG_ALWAYS_FATAL_IF(halConfigExtended == nullptr, + "malloc failed for size %zu in convertRecognitionConfigToHalHeader", + allocSize); + halConfigExtended->header.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_3; + halConfigExtended->header.size = allocSize; + + struct sound_trigger_recognition_config* halConfigBase = &halConfigExtended->base; + + halConfigBase->capture_handle = (audio_io_handle_t)config_2_0->captureHandle; + halConfigBase->capture_device = (audio_devices_t)config_2_0->captureDevice; + halConfigBase->capture_requested = config_2_0->captureRequested; + + unsigned int i; + for (i = 0; i < config_2_0->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) { + convertPhraseRecognitionExtraToHal(&halConfigBase->phrases[i], &config_2_0->phrases[i]); + } + halConfigBase->num_phrases = i; + + halConfigBase->data_offset = sizeof(struct sound_trigger_recognition_config_extended_1_3); + halConfigBase->data_size = config_2_1->data.size(); + if (config_2_1->data.size() != 0) { + memory = mapMemory(config_2_1->data); + LOG_ALWAYS_FATAL_IF(memory == nullptr, + "failed to map config memory in convertRecognitionConfigToHalHeader"); + memory->read(); + + uint8_t* dst = reinterpret_cast(halConfigExtended) + halConfigBase->data_offset; + const uint8_t* src = static_cast(static_cast(memory->getPointer())); + memcpy(dst, src, config_2_1->data.size()); + + memory->commit(); + } + + halConfigExtended->audio_capabilities = config->audioCapabilities; + + return &halConfigExtended->header; +} + // static void SoundTriggerHw::convertSoundModelEventFromHal( V2_0::ISoundTriggerHwCallback::ModelEvent* event, @@ -741,6 +789,41 @@ exit: return Void(); } +Return SoundTriggerHw::startRecognition_2_3(int32_t modelHandle, + const V2_3::RecognitionConfig& config) { + int32_t ret; + sp client; + struct sound_trigger_recognition_config_header* header; + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + ret = -ENOSYS; + goto exit; + } + } + + header = convertRecognitionConfigToHalHeader(&config); + + if (header == nullptr) { + ret = -EINVAL; + goto exit; + } + ret = mHwDevice->start_recognition_extended(mHwDevice, client->getHalHandle(), header, + recognitionCallback_, client.get()); + + free(header); + +exit: + return ret; +} + Return SoundTriggerHw::setParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam, int32_t value) { sp client; diff --git a/soundtrigger/2.3/default/SoundTriggerHw.h b/soundtrigger/2.3/default/SoundTriggerHw.h index 078debb81d..ccd468c5fa 100644 --- a/soundtrigger/2.3/default/SoundTriggerHw.h +++ b/soundtrigger/2.3/default/SoundTriggerHw.h @@ -86,6 +86,8 @@ struct SoundTriggerHw : public ISoundTriggerHw { // Methods from V2_3::ISoundTriggerHw follow. Return getProperties_2_3(getProperties_2_3_cb _hidl_cb) override; + Return startRecognition_2_3(int32_t modelHandle, + const V2_3::RecognitionConfig& config) override; Return setParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam, int32_t value) override; Return getParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam, @@ -170,6 +172,8 @@ struct SoundTriggerHw : public ISoundTriggerHw { // returned recognition config must be freed by caller struct sound_trigger_recognition_config* convertRecognitionConfigToHal( const V2_0::ISoundTriggerHw::RecognitionConfig* config); + struct sound_trigger_recognition_config_header* convertRecognitionConfigToHalHeader( + const V2_3::RecognitionConfig* config); static void convertPhraseRecognitionExtraFromHal( V2_0::PhraseRecognitionExtra* extra, diff --git a/soundtrigger/2.3/types.hal b/soundtrigger/2.3/types.hal index 614912679a..730f9695af 100644 --- a/soundtrigger/2.3/types.hal +++ b/soundtrigger/2.3/types.hal @@ -18,6 +18,22 @@ package android.hardware.soundtrigger@2.3; import android.hidl.safe_union@1.0::Monostate; import @2.0::ISoundTriggerHw.Properties; +import @2.1::ISoundTriggerHw.RecognitionConfig; + +/** + * AudioCapabilities supported by the implemented HAL + * driver. + */ +enum AudioCapabilities : uint32_t { + /** + * If set the underlying module supports AEC. + */ + ECHO_CANCELLATION = 1 << 0, + /** + * If set, the underlying module supports noise suppression. + */ + NOISE_SUPPRESSION = 1 << 1, +}; /** * Extended implementation properties providing verbose implementation @@ -31,6 +47,26 @@ struct Properties { * (eg. DSP architecture) */ string supportedModelArch; + + /** + * Bit field encoding of the AudioCapabilities + * supported by the firmware. + */ + bitfield audioCapabilities; +}; + +/** + * Configuration for sound trigger capture session passed to + * startRecognition_2_1() method. + */ +struct RecognitionConfig { + @2.1::ISoundTriggerHw.RecognitionConfig base; + + /** + * Bit field encoding of the AudioCapabilities + * supported by the firmware. + */ + uint32_t audioCapabilities; }; /** diff --git a/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp index ed38368d8c..2d147e4606 100644 --- a/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp +++ b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp @@ -27,6 +27,7 @@ using ::android::sp; using ::android::hardware::Return; using ::android::hardware::soundtrigger::V2_0::RecognitionMode; +using ::android::hardware::soundtrigger::V2_3::AudioCapabilities; using ::android::hardware::soundtrigger::V2_3::ISoundTriggerHw; using ::android::hardware::soundtrigger::V2_3::Properties; @@ -79,6 +80,8 @@ TEST_P(SoundTriggerHidlTest, GetProperties_2_3) { EXPECT_GT(halProperties.base.maxSoundModels, 0u); EXPECT_GT(halProperties.base.maxKeyPhrases, 0u); EXPECT_NE(0u, (halProperties.base.recognitionModes & (uint32_t)RecognitionMode::VOICE_TRIGGER)); + EXPECT_TRUE(halProperties.audioCapabilities <= + (AudioCapabilities::ECHO_CANCELLATION | AudioCapabilities::NOISE_SUPPRESSION)); } INSTANTIATE_TEST_SUITE_P( From 79e804d6fb396445d5bc531ddc403c4eb7a5daf7 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Thu, 14 Nov 2019 15:16:46 -0800 Subject: [PATCH 0419/1022] Convert VtsHalWifiSupplicantV1_3TargetTest to be parameterized test Bug: 142397658 Test: atest VtsHalWifiSupplicantV1_3TargetTest Change-Id: I85a064b05439776c3083f8cf9762d5f2a994b959 --- wifi/supplicant/1.3/vts/functional/Android.bp | 7 ++- .../VtsHalWifiSupplicantV1_3TargetTest.cpp | 47 +-------------- .../supplicant_hidl_test_utils_1_3.cpp | 20 +++++-- .../supplicant_hidl_test_utils_1_3.h | 12 +++- .../supplicant_sta_iface_hidl_test.cpp | 58 ++++++++++++++----- .../supplicant_sta_network_hidl_test.cpp | 58 ++++++++++++++----- 6 files changed, 121 insertions(+), 81 deletions(-) diff --git a/wifi/supplicant/1.3/vts/functional/Android.bp b/wifi/supplicant/1.3/vts/functional/Android.bp index abb86008b5..3dabe7cd93 100644 --- a/wifi/supplicant/1.3/vts/functional/Android.bp +++ b/wifi/supplicant/1.3/vts/functional/Android.bp @@ -19,7 +19,7 @@ cc_library_static { defaults: ["VtsHalTargetTestDefaults"], srcs: ["supplicant_hidl_test_utils_1_3.cpp"], export_include_dirs: [ - "." + ".", ], static_libs: [ "VtsHalWifiV1_0TargetTestUtil", @@ -61,5 +61,8 @@ cc_test { "libwifi-system", "libwifi-system-iface", ], - test_suites: ["general-tests"], + test_suites: [ + "general-tests", + "vts-core", + ], } diff --git a/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp b/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp index 4dbb64eeda..9dbeee104f 100644 --- a/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp +++ b/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp @@ -14,49 +14,8 @@ * limitations under the License. */ -#include -#include -#include - #include "supplicant_hidl_test_utils.h" -#include "wifi_hidl_test_utils.h" -class WifiSupplicantHidlEnvironment_1_3 : public WifiSupplicantHidlEnvironment { - public: - // get the test environment singleton - static WifiSupplicantHidlEnvironment_1_3* Instance() { - static WifiSupplicantHidlEnvironment_1_3* instance = - new WifiSupplicantHidlEnvironment_1_3; - return instance; - } - virtual void registerTestServices() override { - registerTestService<::android::hardware::wifi::V1_0::IWifi>(); - registerTestService<::android::hardware::wifi::V1_1::IWifi>(); - registerTestService< - ::android::hardware::wifi::supplicant::V1_0::ISupplicant>(); - registerTestService< - ::android::hardware::wifi::supplicant::V1_1::ISupplicant>(); - registerTestService< - ::android::hardware::wifi::supplicant::V1_2::ISupplicant>(); - registerTestService< - ::android::hardware::wifi::supplicant::V1_3::ISupplicant>(); - } - - private: - WifiSupplicantHidlEnvironment_1_3() {} -}; - -WifiSupplicantHidlEnvironment* gEnv = - WifiSupplicantHidlEnvironment_1_3::Instance(); - -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(gEnv); - ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - int status = gEnv->initFromOptions(argc, argv); - if (status == 0) { - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - } - return status; -} +// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is +// updated. +WifiSupplicantHidlEnvironment* gEnv = nullptr; diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp index 308808deff..7ea54620da 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp @@ -21,13 +21,25 @@ #include "supplicant_hidl_test_utils_1_3.h" using ::android::sp; +using ::android::hardware::wifi::supplicant::V1_3::ISupplicant; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork; -sp getSupplicantStaIface_1_3() { - return ISupplicantStaIface::castFrom(getSupplicantStaIface()); +sp getSupplicantStaIface_1_3( + const android::sp& + supplicant) { + return ISupplicantStaIface::castFrom(getSupplicantStaIface(supplicant)); } -sp createSupplicantStaNetwork_1_3() { - return ISupplicantStaNetwork::castFrom(createSupplicantStaNetwork()); +sp createSupplicantStaNetwork_1_3( + const android::sp& + supplicant) { + return ISupplicantStaNetwork::castFrom( + createSupplicantStaNetwork(supplicant)); +} + +sp getSupplicant_1_3(const std::string& supplicant_instance_name, + bool isP2pOn) { + return ISupplicant::castFrom( + getSupplicant(supplicant_instance_name, isP2pOn)); } diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h index 39dbb8fc96..f8dca138fd 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h +++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h @@ -17,12 +17,18 @@ #ifndef SUPPLICANT_HIDL_TEST_UTILS_1_3_H #define SUPPLICANT_HIDL_TEST_UTILS_1_3_H +#include #include #include android::sp -getSupplicantStaIface_1_3(); +getSupplicantStaIface_1_3( + const android::sp& + supplicant); android::sp -createSupplicantStaNetwork_1_3(); - +createSupplicantStaNetwork_1_3( + const android::sp& + supplicant); +android::sp +getSupplicant_1_3(const std::string& supplicant_instance_name, bool isP2pOn); #endif /* SUPPLICANT_HIDL_TEST_UTILS_1_3_H */ diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp index adc955e68b..48b14f35c3 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp @@ -14,13 +14,19 @@ * limitations under the License. */ -#include +#include +#include +#include #include +#include #include #include #include #include +#include +#include #include +#include #include #include "supplicant_hidl_test_utils.h" @@ -40,6 +46,7 @@ using ::android::hardware::wifi::supplicant::V1_2::DppNetRole; using ::android::hardware::wifi::supplicant::V1_2::DppProgressCode; using ::android::hardware::wifi::supplicant::V1_3::ConnectionCapabilities; using ::android::hardware::wifi::supplicant::V1_3::DppSuccessCode; +using ::android::hardware::wifi::supplicant::V1_3::ISupplicant; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIfaceCallback; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork; @@ -48,16 +55,27 @@ using ::android::hardware::wifi::supplicant::V1_3::WpaDriverCapabilitiesMask; #define TIMEOUT_PERIOD 60 class IfaceDppCallback; -class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class SupplicantStaIfaceHidlTest + : public ::testing::TestWithParam> { public: virtual void SetUp() override { - startSupplicantAndWaitForHidlService(); - EXPECT_TRUE(turnOnExcessiveLogging()); - sta_iface_ = getSupplicantStaIface_1_3(); + wifi_v1_0_instance_name_ = std::get<0>(GetParam()); + supplicant_v1_3_instance_name_ = std::get<1>(GetParam()); + isP2pOn_ = + testing::deviceSupportsFeature("android.hardware.wifi.direct"); + + startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_, + supplicant_v1_3_instance_name_); + supplicant_ = + getSupplicant_1_3(supplicant_v1_3_instance_name_, isP2pOn_); + EXPECT_TRUE(turnOnExcessiveLogging(supplicant_)); + sta_iface_ = getSupplicantStaIface_1_3(supplicant_); ASSERT_NE(sta_iface_.get(), nullptr); } - virtual void TearDown() override { stopSupplicant(); } + virtual void TearDown() override { + stopSupplicant(wifi_v1_0_instance_name_); + } int64_t pmkCacheExpirationTimeInSec; std::vector serializedPmkCacheEntry; @@ -104,6 +122,11 @@ class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { protected: // ISupplicantStaIface object used for all tests in this fixture. sp sta_iface_; + sp supplicant_; + bool isP2pOn_ = false; + std::string wifi_v1_0_instance_name_; + std::string supplicant_v1_3_instance_name_; + bool isDppSupported() { uint32_t keyMgmtMask = 0; @@ -302,7 +325,7 @@ class IfaceBssTmHandlingDoneCallback : public IfaceCallback { /* * RegisterCallback_1_3 */ -TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback_1_3) { +TEST_P(SupplicantStaIfaceHidlTest, RegisterCallback_1_3) { sta_iface_->registerCallback_1_3( new IfaceCallback(), [](const SupplicantStatus& status) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); @@ -312,7 +335,7 @@ TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback_1_3) { /* * getConnectionCapabilities */ -TEST_F(SupplicantStaIfaceHidlTest, GetConnectionCapabilities) { +TEST_P(SupplicantStaIfaceHidlTest, GetConnectionCapabilities) { sta_iface_->getConnectionCapabilities( [&](const SupplicantStatus& status, ConnectionCapabilities /* capabilities */) { @@ -323,7 +346,7 @@ TEST_F(SupplicantStaIfaceHidlTest, GetConnectionCapabilities) { /* * GetWpaDriverCapabilities */ -TEST_F(SupplicantStaIfaceHidlTest, GetWpaDriverCapabilities) { +TEST_P(SupplicantStaIfaceHidlTest, GetWpaDriverCapabilities) { sta_iface_->getWpaDriverCapabilities( [&](const SupplicantStatus& status, uint32_t) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); @@ -333,7 +356,7 @@ TEST_F(SupplicantStaIfaceHidlTest, GetWpaDriverCapabilities) { /* * SetMboCellularDataStatus */ -TEST_F(SupplicantStaIfaceHidlTest, SetMboCellularDataStatus) { +TEST_P(SupplicantStaIfaceHidlTest, SetMboCellularDataStatus) { uint32_t driverCapMask = 0; // Get MBO support from the device. @@ -358,7 +381,7 @@ TEST_F(SupplicantStaIfaceHidlTest, SetMboCellularDataStatus) { /* * GetKeyMgmtCapabilities_1_3 */ -TEST_F(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities_1_3) { +TEST_P(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities_1_3) { sta_iface_->getKeyMgmtCapabilities_1_3([&](const SupplicantStatus& status, uint32_t keyMgmtMask) { if (SupplicantStatusCode::SUCCESS != status.code) { @@ -377,7 +400,7 @@ TEST_F(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities_1_3) { /* * StartDppEnrolleeInitiator */ -TEST_F(SupplicantStaIfaceHidlTest, StartDppEnrolleeInitiator) { +TEST_P(SupplicantStaIfaceHidlTest, StartDppEnrolleeInitiator) { // We need to first get the key management capabilities from the device. // If DPP is not supported, we just pass the test. if (!isDppSupported()) { @@ -428,7 +451,7 @@ TEST_F(SupplicantStaIfaceHidlTest, StartDppEnrolleeInitiator) { /* * StartDppConfiguratorInitiator */ -TEST_F(SupplicantStaIfaceHidlTest, StartDppConfiguratorInitiator) { +TEST_P(SupplicantStaIfaceHidlTest, StartDppConfiguratorInitiator) { // We need to first get the key management capabilities from the device. // If DPP is not supported, we just pass the test. if (!isDppSupported()) { @@ -480,3 +503,12 @@ TEST_F(SupplicantStaIfaceHidlTest, StartDppConfiguratorInitiator) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); }); } +INSTANTIATE_TEST_CASE_P( + PerInstance, SupplicantStaIfaceHidlTest, + testing::Combine( + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::wifi::V1_0::IWifi::descriptor)), + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::wifi::supplicant::V1_3::ISupplicant:: + descriptor))), + android::hardware::PrintInstanceTupleNameToString<>); diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp index d6f55f54fc..d82db50c9c 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp @@ -16,9 +16,16 @@ #include +#include #include +#include +#include +#include #include #include +#include +#include +#include #include "supplicant_hidl_test_utils.h" #include "supplicant_hidl_test_utils_1_3.h" @@ -28,6 +35,7 @@ using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus; using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; +using ::android::hardware::wifi::supplicant::V1_3::ISupplicant; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork; using ::android::hardware::wifi::supplicant::V1_3::OcspType; @@ -37,23 +45,34 @@ constexpr OcspType kTestInvalidOcspType = (OcspType)-1; } // namespace class SupplicantStaNetworkHidlTest - : public ::testing::VtsHalHidlTargetTestBase { + : public ::testing::TestWithParam> { public: virtual void SetUp() override { - startSupplicantAndWaitForHidlService(); - EXPECT_TRUE(turnOnExcessiveLogging()); - sta_iface_ = getSupplicantStaIface_1_3(); - ASSERT_NE(nullptr, sta_iface_.get()); - sta_network_ = createSupplicantStaNetwork_1_3(); - ASSERT_NE(nullptr, sta_network_.get()); + wifi_v1_0_instance_name_ = std::get<0>(GetParam()); + supplicant_v1_3_instance_name_ = std::get<1>(GetParam()); + isP2pOn_ = + testing::deviceSupportsFeature("android.hardware.wifi.direct"); + startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_, + supplicant_v1_3_instance_name_); + supplicant_ = + getSupplicant_1_3(supplicant_v1_3_instance_name_, isP2pOn_); + EXPECT_TRUE(turnOnExcessiveLogging(supplicant_)); + sta_network_ = createSupplicantStaNetwork_1_3(supplicant_); + ASSERT_NE(sta_network_.get(), nullptr); } - virtual void TearDown() override { stopSupplicant(); } + virtual void TearDown() override { + stopSupplicant(wifi_v1_0_instance_name_); + } protected: sp sta_iface_; // ISupplicantStaNetwork object used for all tests in this fixture. sp sta_network_; + sp supplicant_; + bool isP2pOn_ = false; + std::string wifi_v1_0_instance_name_; + std::string supplicant_v1_3_instance_name_; bool isWapiSupported() { uint32_t keyMgmtMask = 0; @@ -78,7 +97,7 @@ class SupplicantStaNetworkHidlTest /* * SetGetOcsp */ -TEST_F(SupplicantStaNetworkHidlTest, SetGetOcsp) { +TEST_P(SupplicantStaNetworkHidlTest, SetGetOcsp) { OcspType testOcspType = kTestOcspType; sta_network_->setOcsp(testOcspType, [](const SupplicantStatus &status) { @@ -100,7 +119,7 @@ TEST_F(SupplicantStaNetworkHidlTest, SetGetOcsp) { /* * SetPmkCacheEntry */ -TEST_F(SupplicantStaNetworkHidlTest, SetPmkCache) { +TEST_P(SupplicantStaNetworkHidlTest, SetPmkCache) { uint8_t bytes[128] = {0}; std::vector serializedEntry(bytes, bytes + sizeof(bytes)); @@ -113,7 +132,7 @@ TEST_F(SupplicantStaNetworkHidlTest, SetPmkCache) { /* * SetGetKeyMgmt_1_3, check new WAPI proto support */ -TEST_F(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_3) { +TEST_P(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_3) { uint32_t keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::WAPI_PSK; sta_network_->setKeyMgmt_1_3(keyMgmt, [](const SupplicantStatus &status) { @@ -155,7 +174,7 @@ TEST_F(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_3) { /* * SetGetProto_1_3, check new WAPI proto support */ -TEST_F(SupplicantStaNetworkHidlTest, SetGetProto_1_3) { +TEST_P(SupplicantStaNetworkHidlTest, SetGetProto_1_3) { uint32_t wapiProto = (uint32_t)ISupplicantStaNetwork::ProtoMask::WAPI; sta_network_->setProto(wapiProto, [](const SupplicantStatus &status) { if (SupplicantStatusCode::SUCCESS != status.code) { @@ -176,7 +195,7 @@ TEST_F(SupplicantStaNetworkHidlTest, SetGetProto_1_3) { /* * SetGetGroupCipher_1_3, check new WAPI support */ -TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_3) { +TEST_P(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_3) { uint32_t groupCipher = (uint32_t)ISupplicantStaNetwork::GroupCipherMask::SMS4; @@ -203,7 +222,7 @@ TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_3) { /* * SetGetPairwiseCipher_1_3, check new WAPI support */ -TEST_F(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_3) { +TEST_P(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_3) { uint32_t pairwiseCipher = (uint32_t)ISupplicantStaNetwork::PairwiseCipherMask::SMS4; @@ -230,7 +249,7 @@ TEST_F(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_3) { /* * SetGetWapiCertSuite */ -TEST_F(SupplicantStaNetworkHidlTest, SetGetWapiCertSuite) { +TEST_P(SupplicantStaNetworkHidlTest, SetGetWapiCertSuite) { hidl_string testWapiCertSuite = "suite"; if (isWapiSupported()) { @@ -266,3 +285,12 @@ TEST_F(SupplicantStaNetworkHidlTest, SetGetWapiCertSuite) { }); } } +INSTANTIATE_TEST_CASE_P( + PerInstance, SupplicantStaNetworkHidlTest, + testing::Combine( + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::wifi::V1_0::IWifi::descriptor)), + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::wifi::supplicant::V1_3::ISupplicant:: + descriptor))), + android::hardware::PrintInstanceTupleNameToString<>); From 204b8f9206cca050643e152132109ceb5ceff8f5 Mon Sep 17 00:00:00 2001 From: chrisweir Date: Thu, 9 Jan 2020 15:25:45 -0800 Subject: [PATCH 0420/1022] Refactor baudrate to bitrate Refactoring baudrate to bitrate to be consistent with terminology in the broader literature. Bug: 147448388 Test: Manual + VTS Change-Id: I161b39727a3fd50ea5eddafed6fbd4924ccd149f --- automotive/can/1.0/ICanController.hal | 10 +++++----- automotive/can/1.0/default/CanBusNative.cpp | 12 ++++++------ automotive/can/1.0/default/CanBusNative.h | 4 ++-- automotive/can/1.0/default/CanBusSlcan.cpp | 2 +- automotive/can/1.0/default/CanController.cpp | 4 ++-- automotive/can/1.0/tools/canhalctrl.cpp | 14 +++++++------- .../VtsHalCanControllerV1_0TargetTest.cpp | 2 +- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/automotive/can/1.0/ICanController.hal b/automotive/can/1.0/ICanController.hal index 2c7494a907..0c6f53eff3 100644 --- a/automotive/can/1.0/ICanController.hal +++ b/automotive/can/1.0/ICanController.hal @@ -97,8 +97,8 @@ interface ICanController { */ BAD_ADDRESS, - /** Provided baud rate is not supported by the hardware. */ - BAD_BAUDRATE, + /** Provided bit rate is not supported by the hardware. */ + BAD_BITRATE, }; /** @@ -152,13 +152,13 @@ interface ICanController { } interfaceId; /** - * Baud rate for CAN communication. + * Bit rate for CAN communication. * - * Typical baud rates are: 100000, 125000, 250000, 500000. + * Typical bit rates are: 100000, 125000, 250000, 500000. * * For virtual interfaces this value is ignored. */ - uint32_t baudrate; + uint32_t bitrate; }; /** diff --git a/automotive/can/1.0/default/CanBusNative.cpp b/automotive/can/1.0/default/CanBusNative.cpp index 047b09091b..ef04d01832 100644 --- a/automotive/can/1.0/default/CanBusNative.cpp +++ b/automotive/can/1.0/default/CanBusNative.cpp @@ -22,8 +22,8 @@ namespace android::hardware::automotive::can::V1_0::implementation { -CanBusNative::CanBusNative(const std::string& ifname, uint32_t baudrate) - : CanBus(ifname), mBaudrate(baudrate) {} +CanBusNative::CanBusNative(const std::string& ifname, uint32_t bitrate) + : CanBus(ifname), mBitrate(bitrate) {} ICanController::Result CanBusNative::preUp() { if (!netdevice::exists(mIfname)) { @@ -31,7 +31,7 @@ ICanController::Result CanBusNative::preUp() { return ICanController::Result::BAD_ADDRESS; } - if (mBaudrate == 0) { + if (mBitrate == 0) { // interface is already up and we just want to register it return ICanController::Result::OK; } @@ -41,9 +41,9 @@ ICanController::Result CanBusNative::preUp() { return ICanController::Result::UNKNOWN_ERROR; } - if (!netdevice::can::setBitrate(mIfname, mBaudrate)) { - LOG(ERROR) << "Can't set bitrate " << mBaudrate << " for " << mIfname; - return ICanController::Result::BAD_BAUDRATE; + if (!netdevice::can::setBitrate(mIfname, mBitrate)) { + LOG(ERROR) << "Can't set bitrate " << mBitrate << " for " << mIfname; + return ICanController::Result::BAD_BITRATE; } return ICanController::Result::OK; diff --git a/automotive/can/1.0/default/CanBusNative.h b/automotive/can/1.0/default/CanBusNative.h index 7eda68342e..04d7194e37 100644 --- a/automotive/can/1.0/default/CanBusNative.h +++ b/automotive/can/1.0/default/CanBusNative.h @@ -21,13 +21,13 @@ namespace android::hardware::automotive::can::V1_0::implementation { struct CanBusNative : public CanBus { - CanBusNative(const std::string& ifname, uint32_t baudrate); + CanBusNative(const std::string& ifname, uint32_t bitrate); protected: virtual ICanController::Result preUp() override; private: - const uint32_t mBaudrate; + const uint32_t mBitrate; }; } // namespace android::hardware::automotive::can::V1_0::implementation diff --git a/automotive/can/1.0/default/CanBusSlcan.cpp b/automotive/can/1.0/default/CanBusSlcan.cpp index e42005b6db..0feee8f51a 100644 --- a/automotive/can/1.0/default/CanBusSlcan.cpp +++ b/automotive/can/1.0/default/CanBusSlcan.cpp @@ -71,7 +71,7 @@ ICanController::Result CanBusSlcan::preUp() { if (kBitrate != 0) { const auto lookupIt = slcanprotocol::kBitrateCommands.find(kBitrate); if (lookupIt == slcanprotocol::kBitrateCommands.end()) { - return ICanController::Result::BAD_BAUDRATE; + return ICanController::Result::BAD_BITRATE; } canBitrateCommand = lookupIt->second; } diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp index cd17dd8edb..fb648c1d80 100644 --- a/automotive/can/1.0/default/CanController.cpp +++ b/automotive/can/1.0/default/CanController.cpp @@ -61,7 +61,7 @@ Return CanController::upInterface( if (config.iftype == ICanController::InterfaceType::SOCKETCAN) { // TODO(b/135918744): support serialno if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) { - busService = new CanBusNative(config.interfaceId.address(), config.baudrate); + busService = new CanBusNative(config.interfaceId.address(), config.bitrate); } else { return ICanController::Result::BAD_ADDRESS; } @@ -73,7 +73,7 @@ Return CanController::upInterface( } } else if (config.iftype == ICanController::InterfaceType::SLCAN) { if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) { - busService = new CanBusSlcan(config.interfaceId.address(), config.baudrate); + busService = new CanBusSlcan(config.interfaceId.address(), config.bitrate); } else { return ICanController::Result::BAD_ADDRESS; } diff --git a/automotive/can/1.0/tools/canhalctrl.cpp b/automotive/can/1.0/tools/canhalctrl.cpp index 5c9849bf0a..5494ba31a3 100644 --- a/automotive/can/1.0/tools/canhalctrl.cpp +++ b/automotive/can/1.0/tools/canhalctrl.cpp @@ -29,12 +29,12 @@ using ICanController = V1_0::ICanController; static void usage() { std::cerr << "CAN bus HAL Control tool" << std::endl; std::cerr << std::endl << "usage:" << std::endl << std::endl; - std::cerr << "canhalctrl up [baudrate]" << std::endl; + std::cerr << "canhalctrl up [bitrate]" << std::endl; std::cerr << "where:" << std::endl; std::cerr << " bus name - name under which ICanBus will be published" << std::endl; std::cerr << " type - one of: virtual, socketcan, slcan, indexed" << std::endl; std::cerr << " interface - hardware identifier (like can0, vcan0, /dev/ttyUSB0)" << std::endl; - std::cerr << " baudrate - such as 100000, 125000, 250000, 500000" << std::endl; + std::cerr << " bitrate - such as 100000, 125000, 250000, 500000" << std::endl; std::cerr << std::endl; std::cerr << "canhalctrl down " << std::endl; std::cerr << "where:" << std::endl; @@ -59,7 +59,7 @@ static bool isSupported(sp ctrl, ICanController::InterfaceType i } static int up(const std::string& busName, ICanController::InterfaceType type, - const std::string& interface, uint32_t baudrate) { + const std::string& interface, uint32_t bitrate) { bool anySupported = false; for (auto&& service : getControlServices()) { auto ctrl = ICanController::getService(service); @@ -74,7 +74,7 @@ static int up(const std::string& busName, ICanController::InterfaceType type, ICanController::BusConfiguration config = {}; config.name = busName; config.iftype = type; - config.baudrate = baudrate; + config.bitrate = bitrate; if (type == ICanController::InterfaceType::INDEXED) { config.interfaceId.index(std::stol(interface)); @@ -146,12 +146,12 @@ static int main(int argc, char* argv[]) { return -1; } - long long baudrate = 0; + long long bitrate = 0; if (argc == 4) { - baudrate = std::stoll(argv[3]); + bitrate = std::stoll(argv[3]); } - return up(busName, *type, interface, baudrate); + return up(busName, *type, interface, bitrate); } else if (cmd == "down") { if (argc != 1) { std::cerr << "Invalid number of arguments to down command: " << argc << std::endl; diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp index 9bc789aa29..b2edd78391 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp @@ -172,7 +172,7 @@ TEST_F(CanControllerHalTest, IdentifierCompatibility) { ICanController::BusConfiguration config = {}; config.name = "compattestsrv"; config.iftype = iftype; - config.baudrate = 125000; + config.bitrate = 125000; // using random-ish addresses, which may not be valid - we can't test the success case if (iddisc == IdDisc::address) { From 5f9f9a45ae9416aca58ca15f95c27f8b6c904d5f Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 2 Jan 2020 14:28:39 -0800 Subject: [PATCH 0421/1022] composer: vts: send a refresh command when required + test fix When calling to setActiveConfigWithConstraints, the implementation may need the client to send a refresh frame before the active config can be changed. In addition, testing with a device with composer 2.4 revealed few bugs which are fixed by this change. Fix: 143775556 Test: adb shell data/nativetest64/VtsHalGraphicsComposerV2_4TargetTest/VtsHalGraphicsComposerV2_4TargetTest Change-Id: Iafa1e85de60d99190d5d813f1d42924a62d94cc5 --- graphics/composer/2.4/utils/vts/Android.bp | 1 + .../composer/2.4/utils/vts/ComposerVts.cpp | 4 + .../utils/vts/GraphicsComposerCallback.cpp | 137 ++++++++ .../include/composer-vts/2.4/ComposerVts.h | 2 + .../2.4/GraphicsComposerCallback.h | 74 +++++ .../VtsHalGraphicsComposerV2_4TargetTest.cpp | 309 ++++++++++++------ 6 files changed, 431 insertions(+), 96 deletions(-) create mode 100644 graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp create mode 100644 graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp index b87a116865..673c15eb28 100644 --- a/graphics/composer/2.4/utils/vts/Android.bp +++ b/graphics/composer/2.4/utils/vts/Android.bp @@ -19,6 +19,7 @@ cc_library_static { defaults: ["hidl_defaults"], srcs: [ "ComposerVts.cpp", + "GraphicsComposerCallback.cpp", ], static_libs: [ "VtsHalHidlTargetTestBase", diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp index 5b06d6d3ff..8a9c00608d 100644 --- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp @@ -84,6 +84,10 @@ int32_t ComposerClient::getDisplayAttribute_2_4( return value; } +void ComposerClient::registerCallback_2_4(const sp& callback) { + mClient->registerCallback_2_4(callback); +} + Error ComposerClient::getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) { Error error = Error::NONE; mClient->getDisplayVsyncPeriod(display, [&](const auto& tmpError, const auto& tmpVsyncPeriod) { diff --git a/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp b/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp new file mode 100644 index 0000000000..c9366a8495 --- /dev/null +++ b/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp @@ -0,0 +1,137 @@ +/* + * Copyright 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 + +namespace android::hardware::graphics::composer::V2_4::vts { + +void GraphicsComposerCallback::setVsyncAllowed(bool allowed) { + std::lock_guard lock(mMutex); + mVsyncAllowed = allowed; +} + +std::vector GraphicsComposerCallback::getDisplays() const { + std::lock_guard lock(mMutex); + return std::vector(mDisplays.begin(), mDisplays.end()); +} + +int32_t GraphicsComposerCallback::getInvalidHotplugCount() const { + std::lock_guard lock(mMutex); + return mInvalidHotplugCount; +} + +int32_t GraphicsComposerCallback::getInvalidRefreshCount() const { + std::lock_guard lock(mMutex); + return mInvalidRefreshCount; +} + +int32_t GraphicsComposerCallback::getInvalidVsyncCount() const { + std::lock_guard lock(mMutex); + return mInvalidVsyncCount; +} + +int32_t GraphicsComposerCallback::getInvalidVsync_2_4Count() const { + std::lock_guard lock(mMutex); + return mInvalidVsync_2_4Count; +} + +int32_t GraphicsComposerCallback::getInvalidVsyncPeriodChangeCount() const { + std::lock_guard lock(mMutex); + return mInvalidVsyncPeriodChangeCount; +} + +int32_t GraphicsComposerCallback::getInvalidSeamlessPossibleCount() const { + std::lock_guard lock(mMutex); + return mInvalidSeamlessPossibleCount; +} + +std::optional +GraphicsComposerCallback::takeLastVsyncPeriodChangeTimeline() { + std::lock_guard lock(mMutex); + + std::optional ret; + ret.swap(mTimeline); + + return ret; +} + +Return GraphicsComposerCallback::onHotplug(Display display, Connection connection) { + std::lock_guard lock(mMutex); + + if (connection == Connection::CONNECTED) { + if (!mDisplays.insert(display).second) { + mInvalidHotplugCount++; + } + } else if (connection == Connection::DISCONNECTED) { + if (!mDisplays.erase(display)) { + mInvalidHotplugCount++; + } + } + + return Void(); +} + +Return GraphicsComposerCallback::onRefresh(Display display) { + std::lock_guard lock(mMutex); + + if (mDisplays.count(display) == 0) { + mInvalidRefreshCount++; + } + + return Void(); +} + +Return GraphicsComposerCallback::onVsync(Display, int64_t) { + std::lock_guard lock(mMutex); + + // On composer 2.4, onVsync is not expected at all + mInvalidVsyncCount++; + + return Void(); +} + +Return GraphicsComposerCallback::onVsync_2_4(Display display, int64_t, VsyncPeriodNanos) { + std::lock_guard lock(mMutex); + + if (!mVsyncAllowed || mDisplays.count(display) == 0) { + mInvalidVsync_2_4Count++; + } + + return Void(); +} + +Return GraphicsComposerCallback::onVsyncPeriodTimingChanged( + Display display, const VsyncPeriodChangeTimeline& updatedTimeline) { + std::lock_guard lock(mMutex); + + if (mDisplays.count(display) == 0) { + mInvalidVsyncPeriodChangeCount++; + } + + mTimeline = updatedTimeline; + + return Void(); +} + +Return GraphicsComposerCallback::onSeamlessPossible(Display) { + std::lock_guard lock(mMutex); + + mInvalidSeamlessPossibleCount++; + + return Void(); +} + +} // namespace android::hardware::graphics::composer::V2_4::vts \ No newline at end of file diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h index b094bc8028..df75a48655 100644 --- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h @@ -77,6 +77,8 @@ class ComposerClient : public V2_3::vts::ComposerClient { int32_t getDisplayAttribute_2_4(Display display, Config config, IComposerClient::Attribute attribute); + void registerCallback_2_4(const sp& callback); + Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriods); Error setActiveConfigWithConstraints( diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h new file mode 100644 index 0000000000..f4e23ae1fd --- /dev/null +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h @@ -0,0 +1,74 @@ +/* + * Copyright 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. + */ +#pragma once + +#include + +#include +#include + +namespace android::hardware::graphics::composer::V2_4::vts { + +using Display = V2_1::Display; + +// IComposerCallback to be installed with IComposerClient::registerCallback. +class GraphicsComposerCallback : public IComposerCallback { + public: + void setVsyncAllowed(bool allowed); + + std::vector getDisplays() const; + + int32_t getInvalidHotplugCount() const; + + int32_t getInvalidRefreshCount() const; + + int32_t getInvalidVsyncCount() const; + + int32_t getInvalidVsync_2_4Count() const; + + int32_t getInvalidVsyncPeriodChangeCount() const; + + int32_t getInvalidSeamlessPossibleCount() const; + + std::optional takeLastVsyncPeriodChangeTimeline(); + + private: + Return onHotplug(Display display, Connection connection) override; + Return onRefresh(Display display) override; + Return onVsync(Display display, int64_t) override; + Return onVsync_2_4(Display display, int64_t, VsyncPeriodNanos vsyncPeriodNanos) override; + Return onVsyncPeriodTimingChanged( + Display display, const VsyncPeriodChangeTimeline& updatedTimeline) override; + Return onSeamlessPossible(Display display) override; + + mutable std::mutex mMutex; + // the set of all currently connected displays + std::unordered_set mDisplays; + // true only when vsync is enabled + bool mVsyncAllowed = true; + + std::optional mTimeline; + + // track invalid callbacks + int32_t mInvalidHotplugCount = 0; + int32_t mInvalidRefreshCount = 0; + int32_t mInvalidVsyncCount = 0; + int32_t mInvalidVsync_2_4Count = 0; + int32_t mInvalidVsyncPeriodChangeCount = 0; + int32_t mInvalidSeamlessPossibleCount = 0; +}; + +} // namespace android::hardware::graphics::composer::V2_4::vts diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index 5a96d779a8..800ff08a17 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -22,13 +22,15 @@ #include #include #include -#include #include #include +#include #include #include #include #include +#include +#include #include namespace android { @@ -45,7 +47,9 @@ using common::V1_2::ColorMode; using common::V1_2::Dataspace; using common::V1_2::PixelFormat; using mapper::V2_0::IMapper; -using mapper::V2_0::vts::Gralloc; +using V2_1::Layer; +using V2_2::Transform; +using V2_2::vts::Gralloc; using ContentType = IComposerClient::ContentType; using DisplayCapability = IComposerClient::DisplayCapability; @@ -57,8 +61,8 @@ class GraphicsComposerHidlTest : public ::testing::TestWithParam { mComposer = std::make_unique(IComposer::getService(GetParam()))); ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); - mComposerCallback = new V2_1::vts::GraphicsComposerCallback; - mComposerClient->registerCallback(mComposerCallback); + mComposerCallback = new GraphicsComposerCallback; + mComposerClient->registerCallback_2_4(mComposerCallback); // assume the first display is primary and is never removed mPrimaryDisplay = waitForFirstDisplay(); @@ -80,6 +84,9 @@ class GraphicsComposerHidlTest : public ::testing::TestWithParam { EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount()); EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount()); EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount()); + EXPECT_EQ(0, mComposerCallback->getInvalidVsync_2_4Count()); + EXPECT_EQ(0, mComposerCallback->getInvalidVsyncPeriodChangeCount()); + EXPECT_EQ(0, mComposerCallback->getInvalidSeamlessPossibleCount()); } } @@ -117,8 +124,19 @@ class GraphicsComposerHidlTest : public ::testing::TestWithParam { void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } - void Test_setActiveConfigWithConstraints( - const IComposerClient::VsyncPeriodChangeConstraints& constraints); + void forEachTwoConfigs(Display display, std::function func) { + const auto displayConfigs = mComposerClient->getDisplayConfigs(display); + for (const Config config1 : displayConfigs) { + for (const Config config2 : displayConfigs) { + if (config1 != config2) { + func(config1, config2); + } + } + } + } + + // use the slot count usually set by SF + static constexpr uint32_t kBufferSlotCount = 64; void Test_setContentType(const ContentType& contentType, const char* contentTypeStr); void Test_setContentTypeForDisplay(const Display& display, @@ -127,7 +145,7 @@ class GraphicsComposerHidlTest : public ::testing::TestWithParam { std::unique_ptr mComposer; std::unique_ptr mComposerClient; - sp mComposerCallback; + sp mComposerCallback; // the first display and is assumed never to be removed Display mPrimaryDisplay; Display mInvalidDisplayId; @@ -156,6 +174,12 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique()); + const Config activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay); + mDisplayWidth = mComposerClient->getDisplayAttribute_2_4(mPrimaryDisplay, activeConfig, + IComposerClient::Attribute::WIDTH); + mDisplayHeight = mComposerClient->getDisplayAttribute_2_4( + mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT); + mWriter = std::make_unique(1024); mReader = std::make_unique(); } @@ -166,21 +190,27 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { } const native_handle_t* allocate() { - IMapper::BufferDescriptorInfo info{}; - info.width = 64; - info.height = 64; - info.layerCount = 1; - info.format = static_cast(PixelFormat::RGBA_8888); - info.usage = - static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); - - return mGralloc->allocate(info); + return mGralloc->allocate( + /*width*/ 64, /*height*/ 64, /*layerCount*/ 1, + static_cast(PixelFormat::RGBA_8888), + static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN)); } void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } + void Test_setActiveConfigWithConstraints( + const IComposerClient::VsyncPeriodChangeConstraints& constraints, bool refreshMiss); + + void sendRefreshFrame(const VsyncPeriodChangeTimeline&); + + void waitForVsyncPeriodChange(Display display, const VsyncPeriodChangeTimeline& timeline, + int64_t desiredTimeNanos, int64_t oldPeriodNanos, + int64_t newPeriodNanos); + std::unique_ptr mWriter; std::unique_ptr mReader; + int32_t mDisplayWidth; + int32_t mDisplayHeight; private: std::unique_ptr mGralloc; @@ -219,7 +249,12 @@ TEST_P(GraphicsComposerHidlTest, GetDisplayAttribute_2_4) { IComposerClient::Attribute::CONFIG_GROUP, }}; for (auto attribute : requiredAttributes) { - mComposerClient->getDisplayAttribute_2_4(mPrimaryDisplay, config, attribute); + mComposerClient->getRaw()->getDisplayAttribute_2_4( + mPrimaryDisplay, config, attribute, + [&](const auto& tmpError, const auto& value) { + EXPECT_EQ(Error::NONE, tmpError); + EXPECT_NE(-1, value); + }); } const std::array optionalAttributes = {{ @@ -244,20 +279,20 @@ TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod_BadDisplay) { TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod) { for (Display display : mComposerCallback->getDisplays()) { for (Config config : mComposerClient->getDisplayConfigs(display)) { - mComposerClient->setActiveConfig(display, config); - - VsyncPeriodNanos vsyncPeriodNanos; - VsyncPeriodNanos expectedvsyncPeriodNanos = mComposerClient->getDisplayAttribute_2_4( + VsyncPeriodNanos expectedVsyncPeriodNanos = mComposerClient->getDisplayAttribute_2_4( display, config, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD); + + mComposerClient->setActiveConfig(display, config); + VsyncPeriodNanos vsyncPeriodNanos; int retryCount = 100; do { std::this_thread::sleep_for(10ms); EXPECT_EQ(Error::NONE, mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); --retryCount; - } while (retryCount > 0); + } while (vsyncPeriodNanos != expectedVsyncPeriodNanos && retryCount > 0); - EXPECT_EQ(vsyncPeriodNanos, expectedvsyncPeriodNanos); + EXPECT_EQ(vsyncPeriodNanos, expectedVsyncPeriodNanos); } } } @@ -295,101 +330,178 @@ TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_SeamlessNotAllow constraints.desiredTimeNanos = systemTime(); for (Display display : mComposerCallback->getDisplays()) { - for (Config config : mComposerClient->getDisplayConfigs(display)) { - int32_t configGroup = mComposerClient->getDisplayAttribute_2_4( - display, config, IComposerClient::IComposerClient::Attribute::CONFIG_GROUP); - - for (Config otherConfig : mComposerClient->getDisplayConfigs(display)) { - int32_t otherConfigGroup = mComposerClient->getDisplayAttribute_2_4( - display, otherConfig, - IComposerClient::IComposerClient::Attribute::CONFIG_GROUP); - if (configGroup != otherConfigGroup) { - mComposerClient->setActiveConfig(display, config); - EXPECT_EQ(Error::SEAMLESS_NOT_ALLOWED, - mComposerClient->setActiveConfigWithConstraints( - display, otherConfig, constraints, &timeline)); - } + forEachTwoConfigs(display, [&](Config config1, Config config2) { + const auto configGroup1 = mComposerClient->getDisplayAttribute_2_4( + display, config1, IComposerClient::IComposerClient::Attribute::CONFIG_GROUP); + const auto configGroup2 = mComposerClient->getDisplayAttribute_2_4( + display, config2, IComposerClient::IComposerClient::Attribute::CONFIG_GROUP); + if (configGroup1 != configGroup2) { + mComposerClient->setActiveConfig(display, config1); + EXPECT_EQ(Error::SEAMLESS_NOT_ALLOWED, + mComposerClient->setActiveConfigWithConstraints(display, config2, + constraints, &timeline)); } - } + }); } } -void GraphicsComposerHidlTest::Test_setActiveConfigWithConstraints( - const IComposerClient::VsyncPeriodChangeConstraints& constraints) { +static inline auto toTimePoint(nsecs_t time) { + return std::chrono::time_point(std::chrono::nanoseconds(time)); +} + +void GraphicsComposerHidlCommandTest::sendRefreshFrame(const VsyncPeriodChangeTimeline& timeline) { + // Refresh time should be before newVsyncAppliedTimeNanos + EXPECT_LT(timeline.refreshTimeNanos, timeline.newVsyncAppliedTimeNanos); + + std::this_thread::sleep_until(toTimePoint(timeline.refreshTimeNanos)); + + mWriter->selectDisplay(mPrimaryDisplay); + mComposerClient->setPowerMode(mPrimaryDisplay, V2_1::IComposerClient::PowerMode::ON); + mComposerClient->setColorMode_2_3(mPrimaryDisplay, ColorMode::NATIVE, + RenderIntent::COLORIMETRIC); + + auto handle = allocate(); + ASSERT_NE(nullptr, handle); + + IComposerClient::Rect displayFrame{0, 0, mDisplayWidth, mDisplayHeight}; + + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + mWriter->selectLayer(layer); + mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE); + mWriter->setLayerDisplayFrame(displayFrame); + mWriter->setLayerPlaneAlpha(1); + mWriter->setLayerSourceCrop({0, 0, (float)mDisplayWidth, (float)mDisplayHeight}); + mWriter->setLayerTransform(static_cast(0)); + mWriter->setLayerVisibleRegion(std::vector(1, displayFrame)); + mWriter->setLayerZOrder(10); + mWriter->setLayerBlendMode(IComposerClient::BlendMode::NONE); + mWriter->setLayerSurfaceDamage(std::vector(1, displayFrame)); + mWriter->setLayerBuffer(0, handle, -1); + mWriter->setLayerDataspace(Dataspace::UNKNOWN); + + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + GTEST_SUCCEED() << "Composition change requested, skipping test"; + return; + } + + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + 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->presentDisplay(); + execute(); +} + +void GraphicsComposerHidlCommandTest::waitForVsyncPeriodChange( + Display display, const VsyncPeriodChangeTimeline& timeline, int64_t desiredTimeNanos, + int64_t oldPeriodNanos, int64_t newPeriodNanos) { + const auto CHANGE_DEADLINE = toTimePoint(timeline.newVsyncAppliedTimeNanos) + 100ms; + while (std::chrono::steady_clock::now() <= CHANGE_DEADLINE) { + VsyncPeriodNanos vsyncPeriodNanos; + EXPECT_EQ(Error::NONE, mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); + if (systemTime() <= desiredTimeNanos) { + EXPECT_EQ(vsyncPeriodNanos, oldPeriodNanos); + } else if (vsyncPeriodNanos == newPeriodNanos) { + break; + } + std::this_thread::sleep_for(std::chrono::nanoseconds(oldPeriodNanos)); + } +} + +void GraphicsComposerHidlCommandTest::Test_setActiveConfigWithConstraints( + const IComposerClient::VsyncPeriodChangeConstraints& constraints, bool refreshMiss) { VsyncPeriodChangeTimeline timeline = {}; for (Display display : mComposerCallback->getDisplays()) { - for (Config config : mComposerClient->getDisplayConfigs(display)) { - mComposerClient->setActiveConfig(display, config); + forEachTwoConfigs(display, [&](Config config1, Config config2) { + mComposerClient->setActiveConfig(display, config1); - int32_t configVsyncPeriod = mComposerClient->getDisplayAttribute_2_4( - display, config, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD); - for (Config otherConfig : mComposerClient->getDisplayConfigs(display)) { - if (config == otherConfig) { - continue; - } + int32_t vsyncPeriod1 = mComposerClient->getDisplayAttribute_2_4( + display, config1, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD); + int32_t vsyncPeriod2 = mComposerClient->getDisplayAttribute_2_4( + display, config2, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD); - int32_t otherVsyncPeriod = mComposerClient->getDisplayAttribute_2_4( - display, otherConfig, - IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD); - - if (configVsyncPeriod == otherVsyncPeriod) { - continue; - } - - EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigWithConstraints( - display, otherConfig, constraints, &timeline)); - - if (timeline.refreshRequired) { - // TODO(b/143775556): handle this case; - continue; - } - - EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos >= constraints.desiredTimeNanos); - - // Refresh rate should change within a reasonable time - constexpr nsecs_t kReasonableTimeForChange = 1'000'000'000; // 1 second - EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos - constraints.desiredTimeNanos <= - kReasonableTimeForChange); - - while (systemTime() <= timeline.newVsyncAppliedTimeNanos) { - VsyncPeriodNanos vsyncPeriodNanos; - EXPECT_EQ(Error::NONE, - mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); - - if (systemTime() <= constraints.desiredTimeNanos) { - EXPECT_NE(vsyncPeriodNanos, otherVsyncPeriod); - } - - if (vsyncPeriodNanos == otherVsyncPeriod) { - break; - } - std::this_thread::sleep_for(10ms); - } - VsyncPeriodNanos vsyncPeriodNanos; - EXPECT_EQ(Error::NONE, - mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); - EXPECT_EQ(vsyncPeriodNanos, otherVsyncPeriod); + if (vsyncPeriod1 == vsyncPeriod2) { + return; // continue } - } + + EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigWithConstraints( + display, config2, constraints, &timeline)); + + EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos >= constraints.desiredTimeNanos); + // Refresh rate should change within a reasonable time + constexpr std::chrono::nanoseconds kReasonableTimeForChange = 1s; // 1 second + EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos - constraints.desiredTimeNanos <= + kReasonableTimeForChange.count()); + + if (timeline.refreshRequired) { + if (refreshMiss) { + // Miss the refresh frame on purpose to make sure the implementation sends a + // callback + std::this_thread::sleep_until(toTimePoint(timeline.refreshTimeNanos) + 100ms); + } + sendRefreshFrame(timeline); + } + waitForVsyncPeriodChange(display, timeline, constraints.desiredTimeNanos, vsyncPeriod1, + vsyncPeriod2); + + // 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(); + if (timeline.refreshRequired && refreshMiss) { + EXPECT_TRUE(newTimelime.has_value()); + } + + if (newTimelime.has_value()) { + if (timeline.refreshRequired) { + sendRefreshFrame(newTimelime.value()); + } + waitForVsyncPeriodChange(display, newTimelime.value(), constraints.desiredTimeNanos, + vsyncPeriod1, vsyncPeriod2); + } + + VsyncPeriodNanos vsyncPeriodNanos; + EXPECT_EQ(Error::NONE, + mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); + EXPECT_EQ(vsyncPeriodNanos, vsyncPeriod2); + }); } } -TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints) { +TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints) { IComposerClient::VsyncPeriodChangeConstraints constraints; constraints.seamlessRequired = false; constraints.desiredTimeNanos = systemTime(); - Test_setActiveConfigWithConstraints(constraints); + Test_setActiveConfigWithConstraints(constraints, false); } -TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_delayed) { +TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_Delayed) { IComposerClient::VsyncPeriodChangeConstraints constraints; - constexpr auto kDelayForChange = 300ms; + constexpr nsecs_t kDelayForChange = 300'000'000; // 300ms constraints.seamlessRequired = false; - constraints.desiredTimeNanos = systemTime() + kDelayForChange.count(); - Test_setActiveConfigWithConstraints(constraints); + constraints.desiredTimeNanos = systemTime() + kDelayForChange; + Test_setActiveConfigWithConstraints(constraints, false); +} + +TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_MissRefresh) { + IComposerClient::VsyncPeriodChangeConstraints constraints; + + constraints.seamlessRequired = false; + constraints.desiredTimeNanos = systemTime(); + Test_setActiveConfigWithConstraints(constraints, true); } TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyModeBadDisplay) { @@ -508,6 +620,11 @@ INSTANTIATE_TEST_SUITE_P( testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), android::hardware::PrintInstanceNameToString); +INSTANTIATE_TEST_SUITE_P( + PerInstance, GraphicsComposerHidlCommandTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), + android::hardware::PrintInstanceNameToString); + } // namespace } // namespace vts } // namespace V2_4 From 0f97764f222d65c6f77e6e6999692e64b505dc26 Mon Sep 17 00:00:00 2001 From: Isaac Chiou Date: Mon, 30 Dec 2019 14:57:15 +0800 Subject: [PATCH 0422/1022] Wifi: create new callback to deliver eap error code Create new callback to deliver eap error code from supplicant to framework Bug: 139880103 Test: atest VtsHalWifiSupplicantV1_3TargetTest Change-Id: I6604356672899d7a0933af6fb20879bb91871efd --- current.txt | 2 +- wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal | 5 +++++ .../1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/current.txt b/current.txt index 4ae4213dff..6f08e1c7b5 100644 --- a/current.txt +++ b/current.txt @@ -654,7 +654,7 @@ f3c1e7298da628a755b452cd3325e8d0fe867a2debb873069baab6a27434a72d android.hardwar 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant c72cb37b3f66ef65aeb5c6438a3fbe17bbe847fdf62d1a76eafd7f3a8a526105 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface -342a8e12db4dca643f2755eb4167e8f103d96502053a25a1f51f42107a4530f1 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback +168480869108d9c21bd09eb6ac550a2149b7f794ad05a16ae99e1628c75a5eb2 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback 8835e9799cddf7c239f60beff467cbdf164331f70a8b6c06ed78982d7810d835 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 91015479f5a0fba9872e98d3cca4680995de64f42ae71461b4b7e5acc5a196ab android.hardware.wifi.supplicant@1.3::types ## diff --git a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal index 72ba160ec9..0be43d84c7 100644 --- a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal +++ b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal @@ -185,4 +185,9 @@ interface ISupplicantStaIfaceCallback extends @1.2::ISupplicantStaIfaceCallback * request frame. */ oneway onBssTmHandlingDone(BssTmData tmData); + + /** + * Indicates an EAP authentication failure. + */ + oneway onEapFailure_1_3(uint32_t errorCode); }; diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp index 48b14f35c3..3a30cec04d 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp @@ -207,6 +207,9 @@ class IfaceCallback : public ISupplicantStaIfaceCallback { ISupplicantStaIfaceCallback::EapErrorCode /* eapErrorCode */) override { return Void(); } + Return onEapFailure_1_3(uint32_t /* eapErrorCode */) override { + return Void(); + } Return onWpsEventSuccess() override { return Void(); } Return onWpsEventFail( const hidl_array& /* bssid */, From fe019ac3f7a0ac95b014471dead465d289599a8c Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Mon, 23 Dec 2019 18:13:43 -0800 Subject: [PATCH 0423/1022] Add DataId for Audio Handle in Audio Track Test: Manual bug: 135708935 Change-Id: I639d65999dbf1bf727837298804c350698a9f08a --- tv/tuner/1.0/IFilter.hal | 3 +- tv/tuner/1.0/ITuner.hal | 17 +++++++ tv/tuner/1.0/default/Filter.cpp | 2 +- tv/tuner/1.0/default/Filter.h | 2 +- tv/tuner/1.0/default/Tuner.cpp | 9 ++++ tv/tuner/1.0/default/Tuner.h | 3 ++ tv/tuner/1.0/types.hal | 81 +++++++++++++++++++++++---------- 7 files changed, 90 insertions(+), 27 deletions(-) diff --git a/tv/tuner/1.0/IFilter.hal b/tv/tuner/1.0/IFilter.hal index 94e3c0ce26..567971f019 100644 --- a/tv/tuner/1.0/IFilter.hal +++ b/tv/tuner/1.0/IFilter.hal @@ -120,12 +120,13 @@ interface IFilter { * presented by file descripor in the handle as released. * * @param avMemory A handle associated to the memory for audio or video. + * @param avDataId An Id provides additional information for AV data. * @return result Result status of the operation. * SUCCESS if successful, * INVALID_ARGUMENT if failed for wrong parameter. * UNKNOWN_ERROR if failed for other reasons. */ - releaseAvHandle(handle avMemory) generates (Result result); + releaseAvHandle(handle avMemory, uint64_t avDataId) generates (Result result); /** * Set the filter's data source. diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal index 2712c13708..ba183f180d 100644 --- a/tv/tuner/1.0/ITuner.hal +++ b/tv/tuner/1.0/ITuner.hal @@ -123,4 +123,21 @@ interface ITuner { * @return lnb the newly created Lnb interface. */ openLnbById(LnbId lnbId) generates (Result result, ILnb lnb); + + /** + * Create a new instance of Lnb given a LNB name. + * + * It is used by the client to create a LNB instance for external device. + * + * @param lnbName the name for an external LNB to be opened. The app + * provides the name. Frammework doesn't depend on the name, instead + * use lnbId return from this call. + * @return result Result status of the operation. + * SUCCESS if successful, + * UNAVAILABLE if no resource. + * UNKNOWN_ERROR if creation failed for other reasons. + * @return lnbId the id of the LNB to be opened. + * @return lnb the newly created Lnb interface. + */ + openLnbByName(string lnbName) generates (Result result, LnbId lnbId, ILnb lnb); }; diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp index b3160fc1f7..54d09520e0 100644 --- a/tv/tuner/1.0/default/Filter.cpp +++ b/tv/tuner/1.0/default/Filter.cpp @@ -120,7 +120,7 @@ Return Filter::flush() { return Result::SUCCESS; } -Return Filter::releaseAvHandle(const hidl_handle& /*avMemory*/) { +Return Filter::releaseAvHandle(const hidl_handle& /*avMemory*/, uint64_t /*avDataId*/) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h index d397f73081..0dc992a2ba 100644 --- a/tv/tuner/1.0/default/Filter.h +++ b/tv/tuner/1.0/default/Filter.h @@ -70,7 +70,7 @@ class Filter : public IFilter { virtual Return flush() override; - virtual Return releaseAvHandle(const hidl_handle& avMemory) override; + virtual Return releaseAvHandle(const hidl_handle& avMemory, uint64_t avDataId) override; virtual Return close() override; diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp index c143d61154..c6017f0c76 100644 --- a/tv/tuner/1.0/default/Tuner.cpp +++ b/tv/tuner/1.0/default/Tuner.cpp @@ -139,6 +139,15 @@ sp Tuner::getFrontendById(uint32_t frontendId) { return mFrontends[frontendId]; } +Return Tuner::openLnbByName(const hidl_string& /*lnbName*/, openLnbByName_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + sp lnb = new Lnb(); + + _hidl_cb(Result::SUCCESS, 1234, lnb); + return Void(); +} + void Tuner::setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId) { mFrontendToDemux[frontendId] = demuxId; } diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h index 96da257b0a..7a8a9198ce 100644 --- a/tv/tuner/1.0/default/Tuner.h +++ b/tv/tuner/1.0/default/Tuner.h @@ -55,6 +55,9 @@ class Tuner : public ITuner { virtual Return openLnbById(LnbId lnbId, openLnbById_cb _hidl_cb) override; + virtual Return openLnbByName(const hidl_string& lnbName, + openLnbByName_cb _hidl_cb) override; + sp getFrontendById(uint32_t frontendId); void setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId); diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index d39439da99..e22e4877b5 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -536,6 +536,16 @@ enum FrontendDvbsStandard : uint8_t { S2X = 1 << 3, }; +/** + * VCM mode in DVBS. + */ +@export +enum FrontendDvbsVcmMode : uint32_t { + UNDEFINED, + AUTO, + MANUAL, +}; + /** * Signal Settings for an DVBS Frontend. */ @@ -561,6 +571,8 @@ struct FrontendDvbsSettings { uint32_t inputStreamId; FrontendDvbsStandard standard; + + FrontendDvbsVcmMode vcmMode; }; /** @@ -960,7 +972,7 @@ enum FrontendIsdbs3Modulation : uint32_t { /** * hardware is able to detect and set Modulation automatically */ - AUTO = 1 << 5, + AUTO = 1 << 0, MOD_BPSK = 1 << 1, MOD_QPSK = 1 << 2, MOD_8PSK = 1 << 3, @@ -1105,7 +1117,7 @@ struct FrontendIsdbtCapabilities { bitfield bandwidthCap; - bitfield constellationCap; + bitfield modulationCap; bitfield coderateCap; @@ -1229,6 +1241,11 @@ enum FrontendScanMessageType : uint32_t { * Locked symbol rate. */ SYMBOL_RATE, + /** + * Locked HIERARCHY for DVBT2 frontend. + */ + HIERARCHY, + ANALOG_TYPE, /** * Locked Plp Ids for DVBT2 frontend. */ @@ -1274,14 +1291,18 @@ safe_union FrontendScanMessage { uint8_t progressPercent; /** - * Signal frequency in Hertz + * Signal frequencies in Hertz */ - uint32_t frequency; + vec frequencies; /** * Symbols per second */ - uint32_t symbolRate; + vec symbolRates; + + FrontendDvbtHierarchy hierarchy; + + FrontendAnalogType analogType; vec plpIds; @@ -1289,10 +1310,12 @@ safe_union FrontendScanMessage { vec inputStreamIds; - safe_union standard { + safe_union Standard { FrontendDvbsStandard sStd; FrontendDvbtStandard tStd; + + FrontendAnalogSifStandard sifStd; } std; /** @@ -2019,18 +2042,14 @@ enum DemuxScHevcIndex : uint32_t { }; /** - * Index type to be used in the filter for record + * Start Code Index type to be used in the filter for record */ @export -enum DemuxRecordIndexType : uint32_t { +enum DemuxRecordScIndexType : uint32_t { /** - * Don't use index + * Don't use SC index */ NONE, - /** - * Use TS index - */ - TS, /** * Use Start Code index */ @@ -2045,15 +2064,16 @@ enum DemuxRecordIndexType : uint32_t { * Filter Settings for Record data. */ struct DemuxFilterRecordSettings { - DemuxRecordIndexType indexType; + bitfield tsIndexMask; - safe_union IndexMask { - bitfield tsIndexMask; + DemuxRecordScIndexType scIndexType; - bitfield scIndexMask; + safe_union ScIndexMask { - bitfield scHevcIndexMask; - } indexMask; + bitfield sc; + + bitfield scHevc; + } scIndexMask; }; /** @@ -2397,6 +2417,12 @@ struct DemuxFilterMediaEvent { */ uint32_t dataLength; + /** + * The offset in the memory block which is shared among multiple + * MediaEvents. + */ + uint32_t offset; + /** * A handle associated to the memory where audio or video data stays. */ @@ -2407,6 +2433,12 @@ struct DemuxFilterMediaEvent { */ bool isSecureMemory; + /** + * An Id is used by HAL to provide additional information for AV data. + * For secure audio, it's the audio handle used by Audio Track. + */ + uint64_t avDataId; + /** * MPU sequence number of filtered data (only for MMTP) */ @@ -2447,16 +2479,17 @@ struct DemuxFilterPesEvent { struct DemuxFilterTsRecordEvent { DemuxPid pid; + bitfield tsIndexMask; + /** * Indexes of record output */ - safe_union IndexMask { - bitfield tsIndexMask; + safe_union ScIndexMask { - bitfield scIndexMask; + bitfield sc; - bitfield scHevcIndexMask; - } indexMask; + bitfield scHevc; + } scIndexMask; /** * Byte number from beginning of the filter's output From cb8d72c70709996964b74ae651513e884a93d818 Mon Sep 17 00:00:00 2001 From: Tyler Trephan Date: Tue, 10 Dec 2019 18:43:05 -0800 Subject: [PATCH 0424/1022] Updated PERF_STEERING_ANGLE to support rear steering. Change-Id: I2d8d8eff076ab2b76476a8b4edc18d213df71d45 Fix: 146022250 Test: Tested on device. --- .../default/impl/vhal_v2_0/DefaultConfig.h | 19 ++++++++++++++++++- automotive/vehicle/2.0/types.hal | 17 ++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) 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 2dbcbba28f..5fa8438b0f 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 @@ -293,7 +293,24 @@ const ConfigDeclaration kVehicleProperties[]{ .maxSampleRate = 10.0f, }, .initialValue = {.floatValues = {0.0f}}}, - + {.config = + { + .prop = toInt(VehicleProperty::PERF_STEERING_ANGLE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .minSampleRate = 0.0f, + .maxSampleRate = 10.0f, + }, + .initialValue = {.floatValues = {0.0f}}}, + {.config = + { + .prop = toInt(VehicleProperty::PERF_REAR_STEERING_ANGLE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .minSampleRate = 0.0f, + .maxSampleRate = 10.0f, + }, + .initialValue = {.floatValues = {0.0f}}}, { .config = { diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index 24fcf76b2f..b3dfe846a7 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -340,7 +340,7 @@ enum VehicleProperty : int32_t { | VehicleArea:GLOBAL), /** - * Steering angle of the vehicle + * Front bicycle model steering angle for vehicle * * Angle is in degrees. Left is negative. * @@ -354,6 +354,21 @@ enum VehicleProperty : int32_t { | VehiclePropertyType:FLOAT | VehicleArea:GLOBAL), + /** + * Rear bicycle model steering angle for vehicle + * + * Angle is in degrees. Left is negative. + * + * @change_mode VehiclePropertyChangeMode:CONTINUOUS + * @access VehiclePropertyAccess:READ + * @unit VehicleUnit:DEGREES + */ + PERF_REAR_STEERING_ANGLE = ( + 0x0210 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:FLOAT + | VehicleArea:GLOBAL), + /** * Temperature of engine coolant * From e266073ed6747d0d2e85b0b623fceef29c004ad3 Mon Sep 17 00:00:00 2001 From: shubang Date: Wed, 15 Jan 2020 02:16:57 -0800 Subject: [PATCH 0425/1022] Export FrontendDvbtPlpMode Test: make; Change-Id: I3d4c0667ba1251b3038681759c50b453cd40a8ca --- tv/tuner/1.0/types.hal | 1 + 1 file changed, 1 insertion(+) diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index d39439da99..8e366160eb 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -773,6 +773,7 @@ enum FrontendDvbtTransmissionMode : uint32_t { /** * Physical Layer Pipe (PLP) Mode for DVBT. */ +@export enum FrontendDvbtPlpMode : uint32_t { UNDEFINED, AUTO, From 0e8175e8c23570ad78a0dd76df527bd3198ee548 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Wed, 15 Jan 2020 01:20:36 -0800 Subject: [PATCH 0426/1022] Wifi: Remove the IHostapd.HwModeParams.heBssColor This commit removes the heBssColor field from IHostapd.HwModeParams Bug: 141831296 Test: VTS Test Change-Id: I586a26e9b1057ccce23d4d91c7ea8dca13c59528 --- current.txt | 2 +- wifi/hostapd/1.2/IHostapd.hal | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/current.txt b/current.txt index 4ae4213dff..b549c51e2e 100644 --- a/current.txt +++ b/current.txt @@ -650,7 +650,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback f3c1e7298da628a755b452cd3325e8d0fe867a2debb873069baab6a27434a72d android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi -42e72d7c8fd843d2611ffb9142bfae61dcdb5325860c6602825863f086a91bff android.hardware.wifi.hostapd@1.2::IHostapd +c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant c72cb37b3f66ef65aeb5c6438a3fbe17bbe847fdf62d1a76eafd7f3a8a526105 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface diff --git a/wifi/hostapd/1.2/IHostapd.hal b/wifi/hostapd/1.2/IHostapd.hal index 5126d1299c..0869da0dac 100644 --- a/wifi/hostapd/1.2/IHostapd.hal +++ b/wifi/hostapd/1.2/IHostapd.hal @@ -90,12 +90,6 @@ interface IHostapd extends @1.1::IHostapd { */ bool enableHeMultiUserBeamformer; - /** - * Used BSS Color for softAp running in 802.11ax mode - * Note: this is only applicable if 802.11ax is supported for softAp - */ - uint32_t heBssColor; - /** * Whether HE Target Wait Time (TWT) is enabled or not on softAp. * Note: this is only applicable if 802.11ax is supported for softAp From c5ae069c79d492362cf06b9bc3ceb0c240025422 Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Wed, 8 Jan 2020 13:06:26 -0800 Subject: [PATCH 0427/1022] Camera: Add new pose reference value UNDEFINED If a camera device's location/orientation changes due to user action (such as phone fold/unfold), its pose reference can be set to UNDEFINED. Bug: 119325027 Test: VtsHalCameraProviderV2_4TargetTest Change-Id: I227be31db64db049a8fad57e6765e1b6e025529a --- camera/metadata/3.3/types.hal | 4 +++- camera/metadata/3.5/types.hal | 8 ++++++++ .../vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp | 8 ++++++++ current.txt | 1 + 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/camera/metadata/3.3/types.hal b/camera/metadata/3.3/types.hal index ca0c9d619b..0d896818bc 100644 --- a/camera/metadata/3.3/types.hal +++ b/camera/metadata/3.3/types.hal @@ -71,8 +71,10 @@ enum CameraMetadataTag : @3.2::CameraMetadataTag { /** android.lens.poseReference [static, enum, public] * - *

    The origin for ANDROID_LENS_POSE_TRANSLATION.

    + *

    The origin for ANDROID_LENS_POSE_TRANSLATION, and the accuracy of + * ANDROID_LENS_POSE_TRANSLATION and ANDROID_LENS_POSE_ROTATION.

    * + * @see ANDROID_LENS_POSE_ROTATION * @see ANDROID_LENS_POSE_TRANSLATION */ ANDROID_LENS_POSE_REFERENCE = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_LENS_END, diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal index 62899ec0c5..4c063dde75 100644 --- a/camera/metadata/3.5/types.hal +++ b/camera/metadata/3.5/types.hal @@ -87,6 +87,14 @@ enum CameraMetadataEnumAndroidControlBokehMode : uint32_t { ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS, }; +/** android.lens.poseReference enumeration values added since v3.3 + * @see ANDROID_LENS_POSE_REFERENCE + */ +enum CameraMetadataEnumAndroidLensPoseReference : + @3.3::CameraMetadataEnumAndroidLensPoseReference { + ANDROID_LENS_POSE_REFERENCE_UNDEFINED, +}; + /** android.request.availableCapabilities enumeration values added since v3.4 * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES */ diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 650ec8b81d..c9f9bf6856 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -5851,6 +5851,14 @@ void CameraHidlTest::verifyCameraCharacteristics(Status status, const CameraMeta } } + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_LENS_POSE_REFERENCE, &entry); + if (0 == retcode && entry.count > 0) { + uint8_t poseReference = entry.data.u8[0]; + ASSERT_TRUE(poseReference <= ANDROID_LENS_POSE_REFERENCE_UNDEFINED && + poseReference >= ANDROID_LENS_POSE_REFERENCE_PRIMARY_CAMERA); + } + verifyBokehCharacteristics(metadata); verifyZoomCharacteristics(metadata); } diff --git a/current.txt b/current.txt index 0fec2906ec..3f6c022737 100644 --- a/current.txt +++ b/current.txt @@ -586,6 +586,7 @@ f5bc6aa840db933cb9fd36668b06d3e2021cf5384bb70e459f22e2f2f921fba5 android.hardwar d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardware.automotive.evs@1.0::types 2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types +a05277065c28ebecd58118bd240fb8c55757361e8648c01f7c4dacdb7f2a95dc android.hardware.camera.metadata@3.3::types b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel 8eac60e1f724d141c71c69f06d4544acb720a55dfbbcd97fa01bb3d25ee4e2f5 android.hardware.neuralnetworks@1.0::types From 4060d8d7ae3005da608d57bc5dea1c65d74dae51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Gaffie?= Date: Tue, 19 Nov 2019 09:42:07 +0100 Subject: [PATCH 0428/1022] audio: update XSD for dynamic engine loading support config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 141989952 Test: atest VtsHalAudioV6_0TargetTest Change-Id: Ic0afc27f09d8387236444901dfddc5f0f074ba1b Signed-off-by: François Gaffie --- audio/6.0/config/api/current.txt | 8 ++++++++ audio/6.0/config/audio_policy_configuration.xsd | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/audio/6.0/config/api/current.txt b/audio/6.0/config/api/current.txt index 0407d69c35..6b49e5ed31 100644 --- a/audio/6.0/config/api/current.txt +++ b/audio/6.0/config/api/current.txt @@ -214,6 +214,12 @@ package audio.policy.configuration.V6_0 { method public void set_default(boolean); } + public enum EngineSuffix { + method public String getRawName(); + enum_constant public static final audio.policy.configuration.V6_0.EngineSuffix _default; + enum_constant public static final audio.policy.configuration.V6_0.EngineSuffix configurable; + } + public enum GainMode { method public String getRawName(); enum_constant public static final audio.policy.configuration.V6_0.GainMode AUDIO_GAIN_MODE_CHANNELS; @@ -253,8 +259,10 @@ package audio.policy.configuration.V6_0 { public class GlobalConfiguration { ctor public GlobalConfiguration(); method public boolean getCall_screen_mode_supported(); + method public audio.policy.configuration.V6_0.EngineSuffix getEngine_library(); method public boolean getSpeaker_drc_enabled(); method public void setCall_screen_mode_supported(boolean); + method public void setEngine_library(audio.policy.configuration.V6_0.EngineSuffix); method public void setSpeaker_drc_enabled(boolean); } diff --git a/audio/6.0/config/audio_policy_configuration.xsd b/audio/6.0/config/audio_policy_configuration.xsd index 05c8ab46e8..341c6b337a 100644 --- a/audio/6.0/config/audio_policy_configuration.xsd +++ b/audio/6.0/config/audio_policy_configuration.xsd @@ -67,6 +67,7 @@ + @@ -624,4 +625,10 @@ + + + + + + From bc51e0859645e71c399059e5db745b6e80e289f2 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Wed, 8 Jan 2020 15:33:30 -0800 Subject: [PATCH 0429/1022] Add getClientTargetProperty API entry. getClientTargetProperty will give hardware composer the ability to request some properties of the client target that hardware composer wants. Prior to this API, the client will does its best to produce the client target of which the properties are pretty much fixed. BUG: b/145968912 Test: mmma -j32 hardware/interfaces/graphics/composer/2.4/ Change-Id: I055f46b1eeba1d3e20d6a92a9d50a83e0f1ee694 --- .../2.1/ComposerCommandBuffer.h | 8 +- .../composer-hal/2.1/ComposerCommandEngine.h | 51 +++++------ graphics/composer/2.4/IComposerClient.hal | 22 +++++ .../2.4/ComposerCommandBuffer.h | 13 ++- graphics/composer/2.4/utils/hal/Android.bp | 4 +- .../include/composer-hal/2.4/ComposerClient.h | 9 +- .../composer-hal/2.4/ComposerCommandEngine.h | 85 +++++++++++++++++++ .../include/composer-hal/2.4/ComposerHal.h | 6 ++ .../include/composer-passthrough/2.4/HwcHal.h | 30 +++++++ 9 files changed, 193 insertions(+), 35 deletions(-) create mode 100644 graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h diff --git a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h index 64ed4f3c5a..499d3b96e3 100644 --- a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h +++ b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h @@ -626,9 +626,15 @@ class CommandReaderBase { } protected: + template + bool beginCommand(T* outCommand, uint16_t* outLength) { + return beginCommandBase(reinterpret_cast(outCommand), + outLength); + } + bool isEmpty() const { return (mDataRead >= mDataSize); } - bool beginCommand(IComposerClient::Command* outCommand, uint16_t* outLength) { + bool beginCommandBase(IComposerClient::Command* outCommand, uint16_t* outLength) { if (mCommandEnd) { LOG_FATAL("endCommand was not called for last command"); } diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h index b173e2eeb0..ab67eb10bc 100644 --- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h +++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h @@ -146,6 +146,25 @@ class ComposerCommandEngine : protected CommandReaderBase { return std::make_unique(writerInitialSize); } + virtual Error executeValidateDisplayInternal() { + std::vector changedLayers; + std::vector compositionTypes; + uint32_t displayRequestMask = 0x0; + std::vector requestedLayers; + std::vector requestMasks; + + auto err = mHal->validateDisplay(mCurrentDisplay, &changedLayers, &compositionTypes, + &displayRequestMask, &requestedLayers, &requestMasks); + mResources->setDisplayMustValidateState(mCurrentDisplay, false); + if (err == Error::NONE) { + mWriter->setChangedCompositionTypes(changedLayers, compositionTypes); + mWriter->setDisplayRequests(displayRequestMask, requestedLayers, requestMasks); + } else { + mWriter->setError(getCommandLoc(), err); + } + return err; + } + bool executeSelectDisplay(uint16_t length) { if (length != CommandWriterBase::kSelectDisplayLength) { return false; @@ -255,23 +274,7 @@ class ComposerCommandEngine : protected CommandReaderBase { if (length != CommandWriterBase::kValidateDisplayLength) { return false; } - - std::vector changedLayers; - std::vector compositionTypes; - uint32_t displayRequestMask = 0x0; - std::vector requestedLayers; - std::vector requestMasks; - - auto err = mHal->validateDisplay(mCurrentDisplay, &changedLayers, &compositionTypes, - &displayRequestMask, &requestedLayers, &requestMasks); - mResources->setDisplayMustValidateState(mCurrentDisplay, false); - if (err == Error::NONE) { - mWriter->setChangedCompositionTypes(changedLayers, compositionTypes); - mWriter->setDisplayRequests(displayRequestMask, requestedLayers, requestMasks); - } else { - mWriter->setError(getCommandLoc(), err); - } - + executeValidateDisplayInternal(); return true; } @@ -297,21 +300,9 @@ class ComposerCommandEngine : protected CommandReaderBase { } // Present has failed. We need to fallback to validate - std::vector changedLayers; - std::vector compositionTypes; - uint32_t displayRequestMask = 0x0; - std::vector requestedLayers; - std::vector requestMasks; - - auto err = mHal->validateDisplay(mCurrentDisplay, &changedLayers, &compositionTypes, - &displayRequestMask, &requestedLayers, &requestMasks); - mResources->setDisplayMustValidateState(mCurrentDisplay, false); + auto err = executeValidateDisplayInternal(); if (err == Error::NONE) { mWriter->setPresentOrValidateResult(0); - mWriter->setChangedCompositionTypes(changedLayers, compositionTypes); - mWriter->setDisplayRequests(displayRequestMask, requestedLayers, requestMasks); - } else { - mWriter->setError(getCommandLoc(), err); } return true; diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal index 1b8170beb5..7e0c33ce97 100644 --- a/graphics/composer/2.4/IComposerClient.hal +++ b/graphics/composer/2.4/IComposerClient.hal @@ -16,6 +16,9 @@ package android.hardware.graphics.composer@2.4; +import android.hardware.graphics.common@1.2::PixelFormat; +import android.hardware.graphics.common@1.2::Dataspace; +import android.hardware.graphics.composer@2.1::IComposerClient.Command; import IComposerCallback; import @2.1::Config; import @2.1::Display; @@ -56,6 +59,20 @@ interface IComposerClient extends @2.3::IComposerClient { AUTO_LOW_LATENCY_MODE = 5, }; + enum Command : @2.3::IComposerClient.Command { + /** + * SET_CLIENT_TARGET_PROPERTY has this pseudo prototype + * + * This command has the following binary layout in bytes: + * + * 0 - 3: clientTargetProperty.pixelFormat + * 4 - 7: clientTargetProperty.dataspace + * + * setClientTargetProperty(ClientTargetProperty clientTargetProperty); + */ + SET_CLIENT_TARGET_PROPERTY = 0x105 << @2.1::IComposerClient.Command:OPCODE_SHIFT, + }; + /** * Supersedes {@link @2.1::IComposerClient.DisplayType}. */ @@ -99,6 +116,11 @@ interface IComposerClient extends @2.3::IComposerClient { bool seamlessRequired; }; + struct ClientTargetProperty { + PixelFormat pixelFormat; + Dataspace dataspace; + }; + /** * Provides a IComposerCallback object for the device to call. * diff --git a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h index cb391be144..e84779ecbb 100644 --- a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h +++ b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h @@ -41,14 +41,25 @@ using android::hardware::graphics::composer::V2_4::IComposerClient; // units of uint32_t's. class CommandWriterBase : public V2_3::CommandWriterBase { public: + static constexpr uint16_t kSetClientTargetPropertyLength = 2; + CommandWriterBase(uint32_t initialMaxSize) : V2_3::CommandWriterBase(initialMaxSize) {} + + void setClientTargetProperty( + const IComposerClient::ClientTargetProperty& clientTargetProperty) { + beginCommand(IComposerClient::Command::SET_CLIENT_TARGET_PROPERTY, + kSetClientTargetPropertyLength); + writeSigned(static_cast(clientTargetProperty.pixelFormat)); + writeSigned(static_cast(clientTargetProperty.dataspace)); + endCommand(); + } }; // This class helps parse a command queue. Note that all sizes/lengths are in // units of uint32_t's. class CommandReaderBase : public V2_3::CommandReaderBase { public: - CommandReaderBase() : V2_3::CommandReaderBase(){}; + CommandReaderBase() : V2_3::CommandReaderBase() {} }; } // namespace V2_4 diff --git a/graphics/composer/2.4/utils/hal/Android.bp b/graphics/composer/2.4/utils/hal/Android.bp index 3ee4e19a7d..f4cdea49a8 100644 --- a/graphics/composer/2.4/utils/hal/Android.bp +++ b/graphics/composer/2.4/utils/hal/Android.bp @@ -26,11 +26,11 @@ cc_library_headers { ], header_libs: [ "android.hardware.graphics.composer@2.3-hal", - "android.hardware.graphics.composer@2.3-command-buffer", + "android.hardware.graphics.composer@2.4-command-buffer", ], export_header_lib_headers: [ "android.hardware.graphics.composer@2.3-hal", - "android.hardware.graphics.composer@2.3-command-buffer", + "android.hardware.graphics.composer@2.4-command-buffer", ], export_include_dirs: ["include"], } diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h index d48a9e7dd5..c864ce6961 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -168,12 +169,18 @@ class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImplinit() ? std::move(client) : nullptr; } + protected: + std::unique_ptr createCommandEngine() override { + return std::make_unique( + mHal, static_cast(mResources.get())); + } + private: using BaseType2_3 = V2_3::hal::detail::ComposerClientImpl; using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl; using BaseType2_1::mHal; - std::unique_ptr mHalEventCallback_2_4; using BaseType2_1::mResources; + std::unique_ptr mHalEventCallback_2_4; }; } // namespace detail diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h new file mode 100644 index 0000000000..e0153ceb81 --- /dev/null +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h @@ -0,0 +1,85 @@ +/* + * Copyright 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. + */ + +#pragma once + +#ifndef LOG_TAG +#warning "ComposerCommandEngine.h included without LOG_TAG" +#endif + +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_4 { +namespace hal { + +class ComposerCommandEngine : public V2_3::hal::ComposerCommandEngine { + public: + ComposerCommandEngine(ComposerHal* hal, V2_2::hal::ComposerResources* resources) + : BaseType2_3(hal, resources), mHal(hal) {} + + protected: + std::unique_ptr createCommandWriter( + size_t writerInitialSize) override { + return std::make_unique(writerInitialSize); + } + + private: + using BaseType2_1 = V2_1::hal::ComposerCommandEngine; + using BaseType2_3 = V2_3::hal::ComposerCommandEngine; + using BaseType2_1::mWriter; + + V2_1::Error executeValidateDisplayInternal() override { + std::vector changedLayers; + std::vector compositionTypes; + uint32_t displayRequestMask = 0x0; + std::vector requestedLayers; + std::vector requestMasks; + IComposerClient::ClientTargetProperty clientTargetProperty{PixelFormat::RGBA_8888, + Dataspace::UNKNOWN}; + + auto err = mHal->validateDisplay_2_4(mCurrentDisplay, &changedLayers, &compositionTypes, + &displayRequestMask, &requestedLayers, &requestMasks, + &clientTargetProperty); + mResources->setDisplayMustValidateState(mCurrentDisplay, false); + if (err == Error::NONE) { + mWriter->setChangedCompositionTypes(changedLayers, compositionTypes); + mWriter->setDisplayRequests(displayRequestMask, requestedLayers, requestMasks); + getWriter()->setClientTargetProperty(clientTargetProperty); + } else { + mWriter->setError(getCommandLoc(), static_cast(err)); + } + return static_cast(err); + } + + CommandWriterBase* getWriter() { return static_cast(mWriter.get()); } + + ComposerHal* mHal; +}; + +} // namespace hal +} // namespace V2_4 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h index bbc5405255..277055c0c6 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h @@ -73,6 +73,12 @@ class ComposerHal : public V2_3::hal::ComposerHal { Display display, std::vector* outSupportedContentTypes) = 0; virtual Error setContentType(Display display, IComposerClient::ContentType contentType) = 0; + virtual Error validateDisplay_2_4( + Display display, std::vector* outChangedLayers, + std::vector* outCompositionTypes, + uint32_t* outDisplayRequestMask, std::vector* outRequestedLayers, + std::vector* outRequestMasks, + IComposerClient::ClientTargetProperty* outClientTargetProperty) = 0; }; } // namespace hal diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h index 07d8607d14..616852a71b 100644 --- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h +++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h @@ -43,6 +43,7 @@ using common::V1_2::Hdr; using common::V1_2::PixelFormat; using V2_1::Config; using V2_1::Display; +using V2_1::Layer; using V2_4::Error; // HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2 @@ -218,6 +219,32 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { return Error::NONE; } + Error validateDisplay_2_4( + Display display, std::vector* outChangedLayers, + std::vector* outCompositionTypes, + uint32_t* outDisplayRequestMask, std::vector* outRequestedLayers, + std::vector* outRequestMasks, + IComposerClient::ClientTargetProperty* outClientTargetProperty) override { + auto err = static_cast(BaseType2_1::validateDisplay( + display, outChangedLayers, outCompositionTypes, outDisplayRequestMask, + outRequestedLayers, outRequestMasks)); + if (err != Error::NONE) { + return err; + } + + if (mDispatch.getClientTargetProperty) { + hwc_client_target_property_t clientTargetProperty; + err = static_cast( + mDispatch.getClientTargetProperty(mDevice, display, &clientTargetProperty)); + outClientTargetProperty->pixelFormat = + static_cast(clientTargetProperty.pixelFormat); + outClientTargetProperty->dataspace = + static_cast(clientTargetProperty.dataspace); + } + + return err; + } + protected: bool initDispatch() override { if (!BaseType2_3::initDispatch()) { @@ -238,6 +265,8 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { this->initOptionalDispatch(HWC2_FUNCTION_GET_SUPPORTED_CONTENT_TYPES, &mDispatch.getSupportedContentTypes); this->initOptionalDispatch(HWC2_FUNCTION_SET_CONTENT_TYPE, &mDispatch.setContentType); + this->initOptionalDispatch(HWC2_FUNCTION_GET_CLIENT_TARGET_PROPERTY, + &mDispatch.getClientTargetProperty); return true; } @@ -289,6 +318,7 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { HWC2_PFN_SET_AUTO_LOW_LATENCY_MODE setAutoLowLatencyMode; HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES getSupportedContentTypes; HWC2_PFN_SET_CONTENT_TYPE setContentType; + HWC2_PFN_GET_CLIENT_TARGET_PROPERTY getClientTargetProperty; } mDispatch = {}; hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr; From 931d5a18bc7d1bcf72c105bf86f928ba2bd5a939 Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Wed, 27 Nov 2019 12:46:48 -0800 Subject: [PATCH 0430/1022] Memory Domain HAL: Define HAL APIs. - Add and document memory domain HAL APIs. - Make necessary changes to the existing VTS codes to make them work with V1_3::Request. Bug: 141353602 Bug: 141363565 Test: mma Test: NNT_static Test: 1.3 VTS Change-Id: Ia32555d4fef149fad4a79728981c5d9cca675a1a --- current.txt | 7 +- neuralnetworks/1.3/Android.bp | 1 + neuralnetworks/1.3/IBuffer.hal | 57 ++++++++++++ neuralnetworks/1.3/IDevice.hal | 63 +++++++++++++ neuralnetworks/1.3/IPreparedModel.hal | 8 +- neuralnetworks/1.3/types.hal | 90 +++++++++++++++++++ neuralnetworks/1.3/types.t | 90 +++++++++++++++++++ .../vts/functional/GeneratedTestHarness.cpp | 18 ++-- .../1.3/vts/functional/ValidateRequest.cpp | 13 +-- .../vts/functional/VtsHalNeuralnetworks.cpp | 14 +-- 10 files changed, 337 insertions(+), 24 deletions(-) create mode 100644 neuralnetworks/1.3/IBuffer.hal diff --git a/current.txt b/current.txt index ec8e591689..dad3fb0fe8 100644 --- a/current.txt +++ b/current.txt @@ -649,10 +649,11 @@ adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardwar 7a04ea5595ed418ca3e91c28b8bd7353dd988be9be7b0c8c9e64fb4b77bd4523 android.hardware.keymaster@4.1::types df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore -9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice -258825966435b3ed08832055bb736d81516013e405f161d9ccde9a90cfcdde83 android.hardware.neuralnetworks@1.3::IPreparedModel +4b5c8546533db9412fec6d32c0ef42b22e5e68dbf390c775ec3c22bb2d501102 android.hardware.neuralnetworks@1.3::IBuffer +234cc547d63d2f24a447aee0a9a76cab68b31c080adadc5a960598b827a69fa2 android.hardware.neuralnetworks@1.3::IDevice +058b48f0e2e725bb2b3fa2b7917b0f0a696383d03a4c57afe26f0eadb6a7af28 android.hardware.neuralnetworks@1.3::IPreparedModel 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -f3c1e7298da628a755b452cd3325e8d0fe867a2debb873069baab6a27434a72d android.hardware.neuralnetworks@1.3::types +2576ba54711218ce0d7f207baa533fca9af3c630756938ede6e73fe197b7ea38 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi 42e72d7c8fd843d2611ffb9142bfae61dcdb5325860c6602825863f086a91bff android.hardware.wifi.hostapd@1.2::IHostapd 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.3/Android.bp b/neuralnetworks/1.3/Android.bp index 0b07a5806a..08e824d6e6 100644 --- a/neuralnetworks/1.3/Android.bp +++ b/neuralnetworks/1.3/Android.bp @@ -8,6 +8,7 @@ hidl_interface { }, srcs: [ "types.hal", + "IBuffer.hal", "IDevice.hal", "IPreparedModel.hal", "IPreparedModelCallback.hal", diff --git a/neuralnetworks/1.3/IBuffer.hal b/neuralnetworks/1.3/IBuffer.hal new file mode 100644 index 0000000000..84241c579b --- /dev/null +++ b/neuralnetworks/1.3/IBuffer.hal @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package android.hardware.neuralnetworks@1.3; + +import @1.0::ErrorStatus; + +/** + * This interface represents a device memory buffer. + */ +interface IBuffer { + /** + * Retrieves the content of this buffer to a shared memory region. + * + * The IBuffer object must have been initialized before the call to IBuffer::copyTo. + * For more information on the state of the IBuffer object, refer to IDevice::allocate. + * + * @param dst The destination shared memory region. + * @return status Error status of the call, must be: + * - NONE if successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the IBuffer object is uninitialized, or there is an unspecified + * error + * - INVALID_ARGUMENT if provided memory is invalid + */ + copyTo(memory dst) generates (ErrorStatus status); + + /** + * Sets the content of this buffer from a shared memory region. + * + * @param src The source shared memory region. + * @param dimensions Updated dimensional information. If the dimensions of the IBuffer object + * are not fully specified, then the dimensions must be fully specified here. If the + * dimensions of the IBuffer object are fully specified, then the dimensions may be empty + * here. If dimensions.size() > 0, then all dimensions must be specified here, and any + * dimension that was specified in the IBuffer object must have the same value here. + * @return status Error status of the call, must be: + * - NONE if successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if provided memory is invalid, or if the dimensions is invalid + */ + copyFrom(memory src, vec dimensions) generates (ErrorStatus status); +}; diff --git a/neuralnetworks/1.3/IDevice.hal b/neuralnetworks/1.3/IDevice.hal index 1295d6ac23..9afd77830d 100644 --- a/neuralnetworks/1.3/IDevice.hal +++ b/neuralnetworks/1.3/IDevice.hal @@ -22,6 +22,12 @@ import @1.2::Constant; import @1.2::DeviceType; import @1.2::Extension; import @1.2::IDevice; +import BufferDesc; +import BufferRole; +import Capabilities; +import Model; +import IBuffer; +import IPreparedModel; import IPreparedModelCallback; /** @@ -247,4 +253,61 @@ interface IDevice extends @1.2::IDevice { uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token, IPreparedModelCallback callback) generates (ErrorStatus status); + + /** + * Allocates a driver-managed buffer with the properties specified by the buffer descriptor + * as well as the input and output roles. + * + * The allocate function must verify its inputs are correct. If there is an error, or if a + * certain role or property is not supported by the driver, the allocate + * function must return with an appropriate ErrorStatus, a nullptr as the IBuffer, and 0 as the + * buffer token. If the allocation is successful, this method must return with ErrorStatus::NONE + * and the produced IBuffer with a positive token identifying the allocated buffer. A successful + * allocation must accommodate all of the specified roles and buffer properties. + * + * The buffer is allocated to an uninitialized state. An uninitialized buffer may only be used + * in ways that are specified by outputRoles. A buffer is initialized after it is used as an + * output in a successful execution, or after a successful invocation of IBuffer::copyFrom on + * the buffer. An initialized buffer may be used according to all roles specified in inputRoles + * and outputRoles. A buffer will return to the uninitialized state if it is used as an output + * in a failed execution, or after a failed invocation of IBuffer::copyFrom on the buffer. + * + * The dimensions of the buffer can be deduced from the buffer descriptor as well as the + * dimensions of the corresponding model operands of the input and output roles. The dimensions + * or rank of the buffer may be unknown at this stage. As such, some driver services may only + * create a placeholder and defer the actual allocation until execution time. Note that the + * same buffer may be used for different shapes of outputs on different executions. When the + * buffer is used as an input, the input shape must be the same as the output shape from the + * last execution using this buffer as an output. + * + * The driver must apply proper validatation upon every usage of the buffer, and must fail the + * execution immediately if the usage is illegal. + * + * @param desc A buffer descriptor specifying the properties of the buffer to allocate. + * @param preparedModels A vector of IPreparedModel objects. Must only contain IPreparedModel + * objects from the same IDevice as this method is being invoked on. + * @param inputRoles A vector of roles with each specifying an input to a prepared model. + * @param outputRoles A vector of roles with each specifying an output to a prepared model. + * Each role specified in inputRoles and outputRoles must be unique. The corresponding + * model operands of the roles must have the same OperandType, scale, zero point, and + * ExtraParams. The dimensions of the operands and the dimensions specified in the buffer + * descriptor must be compatible with each other. Two dimensions are incompatible if there + * is at least one axis that is fully specified in both but has different values. + * @return status Error status of the buffer allocation. Must be: + * - NONE if successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if a certain buffer property or a certain role is not supported, + * or if there is an unspecified error + * - INVALID_ARGUMENT if one of the input arguments is invalid + * @return buffer The allocated IBuffer object. If the buffer was unable to be allocated + * due to an error, nullptr must be returned. + * @return token A positive token identifying the allocated buffer. The same token will be + * provided when referencing the buffer as one of the memory pools in the request of an + * execution. The token must not collide with the tokens of other IBuffer objects that are + * currently alive in the same driver service. If the buffer was unable to be allocated + * due to an error, the token must be 0. + */ + allocate(BufferDesc desc, vec preparedModels, vec inputRoles, + vec outputRoles) + generates (ErrorStatus status, IBuffer buffer, int32_t token); }; diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal index 7aea4160b0..00adc1f950 100644 --- a/neuralnetworks/1.3/IPreparedModel.hal +++ b/neuralnetworks/1.3/IPreparedModel.hal @@ -17,12 +17,12 @@ package android.hardware.neuralnetworks@1.3; import @1.0::ErrorStatus; -import @1.0::Request; import @1.2::IExecutionCallback; import @1.2::IPreparedModel; import @1.2::MeasureTiming; import @1.2::OutputShape; import @1.2::Timing; +import Request; /** * IPreparedModel describes a model that has been prepared for execution and @@ -33,7 +33,8 @@ interface IPreparedModel extends @1.2::IPreparedModel { * Launches an asynchronous execution on a prepared model. * * The execution is performed asynchronously with respect to the caller. - * execute_1_3 must verify the inputs to the function are correct. If there is + * execute_1_3 must verify the inputs to the function are correct, and the usages + * of memory pools allocated by IDevice::allocate are valid. If there is * an error, execute_1_3 must immediately invoke the callback with the * appropriate ErrorStatus value, then return with the same ErrorStatus. If * the inputs to the function are valid and there is no error, execute_1_3 must @@ -95,7 +96,8 @@ interface IPreparedModel extends @1.2::IPreparedModel { * * The execution is performed synchronously with respect to the caller. * executeSynchronously_1_3 must verify the inputs to the function are - * correct. If there is an error, executeSynchronously_1_3 must immediately + * correct, and the usages of memory pools allocated by IDevice::allocate + * are valid. If there is an error, executeSynchronously_1_3 must immediately * return with the appropriate ErrorStatus value. If the inputs to the * function are valid and there is no error, executeSynchronously_1_3 must * perform the execution, and must not return until the execution is diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index 62c5833500..6c8fe43312 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -19,6 +19,7 @@ package android.hardware.neuralnetworks@1.3; import @1.0::DataLocation; import @1.0::OperandLifeTime; import @1.0::PerformanceInfo; +import @1.0::RequestArgument; import @1.2::OperandType; import @1.2::OperationType; import @1.2::SymmPerChannelQuantParams; @@ -5205,3 +5206,92 @@ struct Model { LOW_BITS_TYPE = 16, }; }; + +/** + * A buffer descriptor. Describes the properties of a buffer. + */ +struct BufferDesc { + /** + * Dimensions of the buffer. May have unknown dimensions or rank. A buffer with some number + * of unspecified dimensions is represented by setting each unspecified dimension to 0. A + * buffer with unspecified rank is represented by providing an empty dimensions vector. + */ + vec dimensions; +}; + +/** + * Describes a role of an input or output to a prepared model. + */ +struct BufferRole { + /** + * The index of the IPreparedModel within the "preparedModel" argument passed in + * IDevice::allocate. + */ + uint32_t modelIndex; + + /** + * The index of the input or output operand. + */ + uint32_t ioIndex; + + /** + * A floating-point value within the range (0.0, 1.0]. Describes how likely the + * buffer is to be used in the specified role. This is provided as a hint to + * optimize the case when multiple roles prefer different buffer locations or data + * layouts. + */ + float frequency; +}; + +/** + * Inputs to be sent to and outputs to be retrieved from a prepared model. + * + * A Request serves two primary tasks: + * 1) Provides the input and output data to be used when executing the model. + * 2) Specifies any updates to the input operand metadata that were left + * unspecified at model preparation time. + * + * An output must not overlap with any other output, with an input, or + * with an operand of lifetime CONSTANT_REFERENCE. + */ +struct Request { + /** + * Input data and information to be used in the execution of a prepared + * model. + * + * The index of the input corresponds to the index in Model.inputIndexes. + * E.g., input[i] corresponds to Model.inputIndexes[i]. + */ + vec inputs; + + /** + * Output data and information to be used in the execution of a prepared + * model. + * + * The index of the output corresponds to the index in Model.outputIndexes. + * E.g., output[i] corresponds to Model.outputIndexes[i]. + */ + vec outputs; + + /** + * A memory pool. + */ + safe_union MemoryPool { + /** + * Specifies a client-managed shared memory pool. + */ + memory hidlMemory; + + /** + * Specifies a driver-managed buffer. It is the token returned from IDevice::allocate, + * and is specific to the IDevice object. + */ + int32_t token; + }; + + /** + * A collection of memory pools containing operand data for both the + * inputs and the outputs to a model. + */ + vec pools; +}; diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t index 0d20d06f7d..b1c72a9a31 100644 --- a/neuralnetworks/1.3/types.t +++ b/neuralnetworks/1.3/types.t @@ -21,6 +21,7 @@ package android.hardware.neuralnetworks@1.3; import @1.0::DataLocation; import @1.0::OperandLifeTime; import @1.0::PerformanceInfo; +import @1.0::RequestArgument; import @1.2::OperandType; import @1.2::OperationType; import @1.2::SymmPerChannelQuantParams; @@ -389,3 +390,92 @@ struct Model { LOW_BITS_TYPE = 16, }; }; + +/** + * A buffer descriptor. Describes the properties of a buffer. + */ +struct BufferDesc { + /** + * Dimensions of the buffer. May have unknown dimensions or rank. A buffer with some number + * of unspecified dimensions is represented by setting each unspecified dimension to 0. A + * buffer with unspecified rank is represented by providing an empty dimensions vector. + */ + vec dimensions; +}; + +/** + * Describes a role of an input or output to a prepared model. + */ +struct BufferRole { + /** + * The index of the IPreparedModel within the "preparedModel" argument passed in + * IDevice::allocate. + */ + uint32_t modelIndex; + + /** + * The index of the input or output operand. + */ + uint32_t ioIndex; + + /** + * A floating-point value within the range (0.0, 1.0]. Describes how likely the + * buffer is to be used in the specified role. This is provided as a hint to + * optimize the case when multiple roles prefer different buffer locations or data + * layouts. + */ + float frequency; +}; + +/** + * Inputs to be sent to and outputs to be retrieved from a prepared model. + * + * A Request serves two primary tasks: + * 1) Provides the input and output data to be used when executing the model. + * 2) Specifies any updates to the input operand metadata that were left + * unspecified at model preparation time. + * + * An output must not overlap with any other output, with an input, or + * with an operand of lifetime CONSTANT_REFERENCE. + */ +struct Request { + /** + * Input data and information to be used in the execution of a prepared + * model. + * + * The index of the input corresponds to the index in Model.inputIndexes. + * E.g., input[i] corresponds to Model.inputIndexes[i]. + */ + vec inputs; + + /** + * Output data and information to be used in the execution of a prepared + * model. + * + * The index of the output corresponds to the index in Model.outputIndexes. + * E.g., output[i] corresponds to Model.outputIndexes[i]. + */ + vec outputs; + + /** + * A memory pool. + */ + safe_union MemoryPool { + /** + * Specifies a client-managed shared memory pool. + */ + memory hidlMemory; + + /** + * Specifies a driver-managed buffer. It is the token returned from IDevice::allocate, + * and is specific to the IDevice object. + */ + int32_t token; + }; + + /** + * A collection of memory pools containing operand data for both the + * inputs and the outputs to a model. + */ + vec pools; +}; diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index eced063416..09ccc9a719 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -60,7 +60,6 @@ using implementation::PreparedModelCallback; using V1_0::DataLocation; using V1_0::ErrorStatus; using V1_0::OperandLifeTime; -using V1_0::Request; using V1_1::ExecutionPreference; using V1_2::Constant; using V1_2::MeasureTiming; @@ -192,7 +191,7 @@ static bool isOutputSizeGreaterThanOne(const TestModel& testModel, uint32_t inde return byteSize > 1u; } -static void makeOutputInsufficientSize(uint32_t outputIndex, Request* request) { +static void makeOutputInsufficientSize(uint32_t outputIndex, V1_0::Request* request) { auto& length = request->outputs[outputIndex].location.length; ASSERT_GT(length, 1u); length -= 1u; @@ -245,10 +244,11 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo return; } - Request request = createRequest(testModel); + V1_0::Request request10 = createRequest(testModel); if (testConfig.outputType == OutputType::INSUFFICIENT) { - makeOutputInsufficientSize(/*outputIndex=*/0, &request); + makeOutputInsufficientSize(/*outputIndex=*/0, &request10); } + Request request = nn::convertToV1_3(request10); ErrorStatus executionStatus; hidl_vec outputShapes; @@ -284,6 +284,8 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo break; } case Executor::BURST: { + // TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains + // V1_2. SCOPED_TRACE("burst"); // create burst @@ -292,15 +294,15 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo ASSERT_NE(nullptr, controller.get()); // create memory keys - std::vector keys(request.pools.size()); + std::vector keys(request10.pools.size()); for (size_t i = 0; i < keys.size(); ++i) { - keys[i] = reinterpret_cast(&request.pools[i]); + keys[i] = reinterpret_cast(&request10.pools[i]); } // execute burst int n; std::tie(n, outputShapes, timing, std::ignore) = - controller->compute(request, testConfig.measureTiming, keys); + controller->compute(request10, testConfig.measureTiming, keys); executionStatus = nn::convertResultCodeToErrorStatus(n); break; @@ -361,7 +363,7 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo } // Retrieve execution results. - const std::vector outputs = getOutputBuffers(request); + const std::vector outputs = getOutputBuffers(request10); // We want "close-enough" results. checkResults(testModel, outputs); diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index 8092d04bcb..96dc589d50 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -28,7 +28,6 @@ namespace android::hardware::neuralnetworks::V1_3::vts::functional { using V1_0::ErrorStatus; -using V1_0::Request; using V1_2::MeasureTiming; using V1_2::OutputShape; using V1_2::Timing; @@ -93,9 +92,13 @@ static void validate(const sp& preparedModel, const std::string& } // burst + // TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2. { SCOPED_TRACE(message + " [burst]"); + ASSERT_TRUE(nn::compliantWithV1_0(request)); + V1_0::Request request10 = nn::convertToV1_0(request); + // create burst std::shared_ptr<::android::nn::ExecutionBurstController> burst = android::nn::ExecutionBurstController::create(preparedModel, @@ -103,13 +106,13 @@ static void validate(const sp& preparedModel, const std::string& ASSERT_NE(nullptr, burst.get()); // create memory keys - std::vector keys(request.pools.size()); + std::vector keys(request10.pools.size()); for (size_t i = 0; i < keys.size(); ++i) { - keys[i] = reinterpret_cast(&request.pools[i]); + keys[i] = reinterpret_cast(&request10.pools[i]); } // execute and verify - const auto [n, outputShapes, timing, fallback] = burst->compute(request, measure, keys); + const auto [n, outputShapes, timing, fallback] = burst->compute(request10, measure, keys); const ErrorStatus status = nn::convertResultCodeToErrorStatus(n); EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); EXPECT_EQ(outputShapes.size(), 0); @@ -117,7 +120,7 @@ static void validate(const sp& preparedModel, const std::string& EXPECT_FALSE(fallback); // additional burst testing - if (request.pools.size() > 0) { + if (request10.pools.size() > 0) { // valid free burst->freeMemory(keys.front()); diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index 92d8fa7376..1140b68635 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -25,6 +25,7 @@ #include "1.3/Callbacks.h" #include "GeneratedTestHarness.h" #include "TestHarness.h" +#include "Utils.h" namespace android::hardware::neuralnetworks::V1_3::vts::functional { @@ -32,7 +33,6 @@ using HidlToken = hidl_array(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; using implementation::PreparedModelCallback; using V1_0::ErrorStatus; -using V1_0::Request; using V1_1::ExecutionPreference; // internal helper function @@ -124,9 +124,9 @@ INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest); // Forward declaration from ValidateModel.cpp void validateModel(const sp& device, const Model& model); // Forward declaration from ValidateRequest.cpp -void validateRequest(const sp& preparedModel, const V1_0::Request& request); +void validateRequest(const sp& preparedModel, const Request& request); // Forward declaration from ValidateRequest.cpp -void validateRequestFailure(const sp& preparedModel, const V1_0::Request& request); +void validateRequestFailure(const sp& preparedModel, const Request& request); // Forward declaration from ValidateBurst.cpp void validateBurst(const sp& preparedModel, const V1_0::Request& request); @@ -139,7 +139,11 @@ void validateEverything(const sp& device, const Model& model, const Req if (preparedModel == nullptr) return; validateRequest(preparedModel, request); - validateBurst(preparedModel, request); + + // TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2. + ASSERT_TRUE(nn::compliantWithV1_0(request)); + V1_0::Request request10 = nn::convertToV1_0(request); + validateBurst(preparedModel, request10); } void validateFailure(const sp& device, const Model& model, const Request& request) { @@ -157,7 +161,7 @@ void validateFailure(const sp& device, const Model& model, const Reques TEST_P(ValidationTest, Test) { const Model model = createModel(kTestModel); - const Request request = createRequest(kTestModel); + const Request request = nn::convertToV1_3(createRequest(kTestModel)); if (kTestModel.expectFailure) { validateFailure(kDevice, model, request); } else { From 1f50e54cf8bb4dd39ebc7f3f62ddfb71e2a2c516 Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Mon, 13 Jan 2020 11:44:45 -0800 Subject: [PATCH 0431/1022] Add memory domain VTS generated tests. Bug: 141353602 Bug: 141363565 Test: 1.3 VTS Change-Id: Ifc7eb3fd6f15e28ba403f02bdf66b4568bddcb64 --- .../functional/CompilationCachingTests.cpp | 30 +- .../vts/functional/GeneratedTestHarness.cpp | 324 ++++++++++++++++-- .../1.3/vts/functional/GeneratedTestHarness.h | 4 +- 3 files changed, 317 insertions(+), 41 deletions(-) diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp index 60992d57d7..fe8d907d36 100644 --- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp @@ -456,7 +456,7 @@ TEST_P(CompilationCachingTest, CacheSavingAndRetrieval) { } // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); + EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL); } TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) { @@ -518,7 +518,7 @@ TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) { } // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); + EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL); } TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { @@ -539,7 +539,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); + EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -563,7 +563,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); + EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -586,7 +586,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); + EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -610,7 +610,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); + EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -721,7 +721,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); + EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -745,7 +745,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); + EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -768,7 +768,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); + EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -792,7 +792,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); + EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -904,7 +904,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); + EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -926,7 +926,7 @@ TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) { saveModelToCache(model, modelCache, dataCache, &preparedModel); ASSERT_NE(preparedModel, nullptr); // Execute and verify results. - EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL); + EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL); // Check if prepareModelFromCache fails. preparedModel = nullptr; ErrorStatus status; @@ -1070,7 +1070,8 @@ TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) { ASSERT_EQ(preparedModel, nullptr); } else { ASSERT_NE(preparedModel, nullptr); - EvaluatePreparedModel(preparedModel, testModelAdd, /*testKind=*/TestKind::GENERAL); + EvaluatePreparedModel(kDevice, preparedModel, testModelAdd, + /*testKind=*/TestKind::GENERAL); } } } @@ -1131,7 +1132,8 @@ TEST_P(CompilationCachingTest, PrepareFromCache_TOCTOU) { ASSERT_EQ(preparedModel, nullptr); } else { ASSERT_NE(preparedModel, nullptr); - EvaluatePreparedModel(preparedModel, testModelAdd, /*testKind=*/TestKind::GENERAL); + EvaluatePreparedModel(kDevice, preparedModel, testModelAdd, + /*testKind=*/TestKind::GENERAL); } } } diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 09ccc9a719..4f747f4afa 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -60,6 +60,7 @@ using implementation::PreparedModelCallback; using V1_0::DataLocation; using V1_0::ErrorStatus; using V1_0::OperandLifeTime; +using V1_0::RequestArgument; using V1_1::ExecutionPreference; using V1_2::Constant; using V1_2::MeasureTiming; @@ -75,27 +76,118 @@ enum class Executor { ASYNC, SYNC, BURST }; enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; +enum class MemoryType { SHARED, DEVICE }; + +enum class IOType { INPUT, OUTPUT }; + struct TestConfig { Executor executor; MeasureTiming measureTiming; OutputType outputType; + MemoryType memoryType; // `reportSkipping` indicates if a test should print an info message in case // it is skipped. The field is set to true by default and is set to false in // quantization coupling tests to suppress skipping a test bool reportSkipping; - TestConfig(Executor executor, MeasureTiming measureTiming, OutputType outputType) + TestConfig(Executor executor, MeasureTiming measureTiming, OutputType outputType, + MemoryType memoryType) : executor(executor), measureTiming(measureTiming), outputType(outputType), + memoryType(memoryType), reportSkipping(true) {} TestConfig(Executor executor, MeasureTiming measureTiming, OutputType outputType, - bool reportSkipping) + MemoryType memoryType, bool reportSkipping) : executor(executor), measureTiming(measureTiming), outputType(outputType), + memoryType(memoryType), reportSkipping(reportSkipping) {} }; +class DeviceMemoryAllocator { + public: + DeviceMemoryAllocator(const sp& device, const sp& preparedModel, + const TestModel& testModel) + : kDevice(device), kPreparedModel(preparedModel), kTestModel(testModel) {} + + // Allocate device memory for a target input/output operand. + // Return {IBuffer object, token} if successful. + // Return {nullptr, 0} if device memory is not supported. + template + std::pair, int32_t> allocate(uint32_t index) { + std::pair, int32_t> buffer; + allocateInternal(index, &buffer); + return buffer; + } + + private: + template + void allocateInternal(uint32_t index, std::pair, int32_t>* result) { + ASSERT_NE(result, nullptr); + + // Prepare arguments. + BufferRole role = {.modelIndex = 0, .ioIndex = index, .frequency = 1.0f}; + hidl_vec inputRoles, outputRoles; + if constexpr (ioType == IOType::INPUT) { + inputRoles = {role}; + } else { + outputRoles = {role}; + } + + // Allocate device memory. + ErrorStatus status; + sp buffer; + int32_t token; + const auto ret = kDevice->allocate( + {}, {kPreparedModel}, inputRoles, outputRoles, + [&status, &buffer, &token](ErrorStatus error, const sp& buf, int32_t tok) { + status = error; + buffer = buf; + token = tok; + }); + + // Check allocation results. + ASSERT_TRUE(ret.isOk()); + if (status == ErrorStatus::NONE) { + ASSERT_NE(buffer, nullptr); + ASSERT_GT(token, 0); + } else { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(buffer, nullptr); + ASSERT_EQ(token, 0); + } + + // Initialize input data from TestBuffer. + if constexpr (ioType == IOType::INPUT) { + if (buffer != nullptr) { + // TestBuffer -> Shared memory. + const auto& testBuffer = kTestModel.operands[kTestModel.inputIndexes[index]].data; + ASSERT_GT(testBuffer.size(), 0); + hidl_memory tmp = nn::allocateSharedMemory(testBuffer.size()); + sp inputMemory = mapMemory(tmp); + ASSERT_NE(inputMemory.get(), nullptr); + uint8_t* inputPtr = + static_cast(static_cast(inputMemory->getPointer())); + ASSERT_NE(inputPtr, nullptr); + const uint8_t* begin = testBuffer.get(); + const uint8_t* end = begin + testBuffer.size(); + std::copy(begin, end, inputPtr); + + // Shared memory -> IBuffer. + auto ret = buffer->copyFrom(tmp, {}); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(static_cast(ret), ErrorStatus::NONE); + } + } + *result = {std::move(buffer), token}; + } + + const sp kDevice; + const sp kPreparedModel; + const TestModel& kTestModel; +}; + } // namespace Model createModel(const TestModel& testModel) { @@ -191,7 +283,7 @@ static bool isOutputSizeGreaterThanOne(const TestModel& testModel, uint32_t inde return byteSize > 1u; } -static void makeOutputInsufficientSize(uint32_t outputIndex, V1_0::Request* request) { +static void makeOutputInsufficientSize(uint32_t outputIndex, Request* request) { auto& length = request->outputs[outputIndex].location.length; ASSERT_GT(length, 1u); length -= 1u; @@ -204,6 +296,161 @@ static void makeOutputDimensionsUnspecified(Model* model) { } } +constexpr uint32_t kInputPoolIndex = 0; +constexpr uint32_t kOutputPoolIndex = 1; +constexpr uint32_t kDeviceMemoryBeginIndex = 2; + +static std::pair>> createRequest( + const sp& device, const sp& preparedModel, + const TestModel& testModel, bool preferDeviceMemory) { + // Memory pools are organized as: + // - 0: Input shared memory pool + // - 1: Output shared memory pool + // - [2, 2+i): Input device memories + // - [2+i, 2+i+o): Output device memories + DeviceMemoryAllocator allocator(device, preparedModel, testModel); + std::vector> buffers; + std::vector tokens; + + // Model inputs. + hidl_vec inputs(testModel.inputIndexes.size()); + size_t inputSize = 0; + for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) { + const auto& op = testModel.operands[testModel.inputIndexes[i]]; + if (op.data.size() == 0) { + // Omitted input. + inputs[i] = {.hasNoValue = true}; + continue; + } else if (preferDeviceMemory) { + SCOPED_TRACE("Input index = " + std::to_string(i)); + auto [buffer, token] = allocator.allocate(i); + if (buffer != nullptr) { + DataLocation loc = {.poolIndex = static_cast(buffers.size() + + kDeviceMemoryBeginIndex)}; + buffers.push_back(std::move(buffer)); + tokens.push_back(token); + inputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}}; + continue; + } + } + + // Reserve shared memory for input. + DataLocation loc = {.poolIndex = kInputPoolIndex, + .offset = static_cast(inputSize), + .length = static_cast(op.data.size())}; + inputSize += op.data.alignedSize(); + inputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}}; + } + + // Model outputs. + hidl_vec outputs(testModel.outputIndexes.size()); + size_t outputSize = 0; + for (uint32_t i = 0; i < testModel.outputIndexes.size(); i++) { + const auto& op = testModel.operands[testModel.outputIndexes[i]]; + if (preferDeviceMemory) { + SCOPED_TRACE("Output index = " + std::to_string(i)); + auto [buffer, token] = allocator.allocate(i); + if (buffer != nullptr) { + DataLocation loc = {.poolIndex = static_cast(buffers.size() + + kDeviceMemoryBeginIndex)}; + buffers.push_back(std::move(buffer)); + tokens.push_back(token); + outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}}; + continue; + } + } + + // In the case of zero-sized output, we should at least provide a one-byte buffer. + // This is because zero-sized tensors are only supported internally to the driver, or + // reported in output shapes. It is illegal for the client to pre-specify a zero-sized + // tensor as model output. Otherwise, we will have two semantic conflicts: + // - "Zero dimension" conflicts with "unspecified dimension". + // - "Omitted operand buffer" conflicts with "zero-sized operand buffer". + size_t bufferSize = std::max(op.data.size(), 1); + + // Reserve shared memory for output. + DataLocation loc = {.poolIndex = kOutputPoolIndex, + .offset = static_cast(outputSize), + .length = static_cast(bufferSize)}; + outputSize += op.data.size() == 0 ? TestBuffer::kAlignment : op.data.alignedSize(); + outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}}; + } + + // Memory pools. + hidl_vec pools(kDeviceMemoryBeginIndex + buffers.size()); + pools[kInputPoolIndex].hidlMemory(nn::allocateSharedMemory(std::max(inputSize, 1))); + pools[kOutputPoolIndex].hidlMemory(nn::allocateSharedMemory(std::max(outputSize, 1))); + CHECK_NE(pools[kInputPoolIndex].hidlMemory().size(), 0u); + CHECK_NE(pools[kOutputPoolIndex].hidlMemory().size(), 0u); + for (uint32_t i = 0; i < buffers.size(); i++) { + pools[kDeviceMemoryBeginIndex + i].token(tokens[i]); + } + + // Copy input data to the input shared memory pool. + sp inputMemory = mapMemory(pools[kInputPoolIndex].hidlMemory()); + CHECK(inputMemory.get() != nullptr); + uint8_t* inputPtr = static_cast(static_cast(inputMemory->getPointer())); + CHECK(inputPtr != nullptr); + for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) { + if (!inputs[i].hasNoValue && inputs[i].location.poolIndex == kInputPoolIndex) { + const auto& op = testModel.operands[testModel.inputIndexes[i]]; + const uint8_t* begin = op.data.get(); + const uint8_t* end = begin + op.data.size(); + std::copy(begin, end, inputPtr + inputs[i].location.offset); + } + } + + Request request = { + .inputs = std::move(inputs), .outputs = std::move(outputs), .pools = std::move(pools)}; + return {std::move(request), std::move(buffers)}; +} + +// Get a TestBuffer with data copied from an IBuffer object. +static void getBuffer(const sp& buffer, size_t size, TestBuffer* testBuffer) { + // IBuffer -> Shared memory. + hidl_memory tmp = nn::allocateSharedMemory(size); + const auto ret = buffer->copyTo(tmp); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(static_cast(ret), ErrorStatus::NONE); + + // Shared memory -> TestBuffer. + sp outputMemory = mapMemory(tmp); + ASSERT_NE(outputMemory.get(), nullptr); + uint8_t* outputPtr = static_cast(static_cast(outputMemory->getPointer())); + ASSERT_NE(outputPtr, nullptr); + ASSERT_NE(testBuffer, nullptr); + *testBuffer = TestBuffer(size, outputPtr); +} + +static std::vector getOutputBuffers(const TestModel& testModel, const Request& request, + const std::vector>& buffers) { + sp outputMemory = mapMemory(request.pools[kOutputPoolIndex].hidlMemory()); + CHECK(outputMemory.get() != nullptr); + uint8_t* outputPtr = static_cast(static_cast(outputMemory->getPointer())); + CHECK(outputPtr != nullptr); + + // Copy out output results. + std::vector outputBuffers; + for (uint32_t i = 0; i < request.outputs.size(); i++) { + const auto& outputLoc = request.outputs[i].location; + if (outputLoc.poolIndex == kOutputPoolIndex) { + outputBuffers.emplace_back(outputLoc.length, outputPtr + outputLoc.offset); + } else { + const auto& op = testModel.operands[testModel.outputIndexes[i]]; + if (op.data.size() == 0) { + outputBuffers.emplace_back(); + } else { + SCOPED_TRACE("Output index = " + std::to_string(i)); + const uint32_t bufferIndex = outputLoc.poolIndex - kDeviceMemoryBeginIndex; + TestBuffer buffer; + getBuffer(buffers[bufferIndex], op.data.size(), &buffer); + outputBuffers.push_back(std::move(buffer)); + } + } + } + return outputBuffers; +} + static Return ExecutePreparedModel(const sp& preparedModel, const Request& request, MeasureTiming measure, sp& callback) { @@ -233,8 +480,9 @@ static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst( std::chrono::microseconds{0}); } -void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel, - const TestConfig& testConfig, bool* skipped = nullptr) { +void EvaluatePreparedModel(const sp& device, const sp& preparedModel, + const TestModel& testModel, const TestConfig& testConfig, + bool* skipped = nullptr) { if (skipped != nullptr) { *skipped = false; } @@ -244,11 +492,16 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo return; } - V1_0::Request request10 = createRequest(testModel); - if (testConfig.outputType == OutputType::INSUFFICIENT) { - makeOutputInsufficientSize(/*outputIndex=*/0, &request10); + auto [request, buffers] = + createRequest(device, preparedModel, testModel, + /*preferDeviceMemory=*/testConfig.memoryType == MemoryType::DEVICE); + // Skip if testing memory domain but no device memory has been allocated. + if (testConfig.memoryType == MemoryType::DEVICE && buffers.empty()) { + return; + } + if (testConfig.outputType == OutputType::INSUFFICIENT) { + makeOutputInsufficientSize(/*outputIndex=*/0, &request); } - Request request = nn::convertToV1_3(request10); ErrorStatus executionStatus; hidl_vec outputShapes; @@ -288,6 +541,10 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo // V1_2. SCOPED_TRACE("burst"); + // check compliance + ASSERT_TRUE(nn::compliantWithV1_0(request)); + V1_0::Request request10 = nn::convertToV1_0(request); + // create burst const std::shared_ptr<::android::nn::ExecutionBurstController> controller = CreateBurst(preparedModel); @@ -363,17 +620,18 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo } // Retrieve execution results. - const std::vector outputs = getOutputBuffers(request10); + const std::vector outputs = getOutputBuffers(testModel, request, buffers); // We want "close-enough" results. checkResults(testModel, outputs); } -void EvaluatePreparedModel(const sp& preparedModel, const TestModel& testModel, - TestKind testKind) { +void EvaluatePreparedModel(const sp& device, const sp& preparedModel, + const TestModel& testModel, TestKind testKind) { std::vector outputTypesList; std::vector measureTimingList; std::vector executorList; + MemoryType memoryType = MemoryType::SHARED; switch (testKind) { case TestKind::GENERAL: { @@ -386,6 +644,12 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; } break; + case TestKind::MEMORY_DOMAIN: { + outputTypesList = {OutputType::FULLY_SPECIFIED}; + measureTimingList = {MeasureTiming::NO}; + executorList = {Executor::ASYNC, Executor::SYNC}; + memoryType = MemoryType::DEVICE; + } break; case TestKind::QUANTIZATION_COUPLING: { LOG(FATAL) << "Wrong TestKind for EvaluatePreparedModel"; return; @@ -395,14 +659,15 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo for (const OutputType outputType : outputTypesList) { for (const MeasureTiming measureTiming : measureTimingList) { for (const Executor executor : executorList) { - const TestConfig testConfig(executor, measureTiming, outputType); - EvaluatePreparedModel(preparedModel, testModel, testConfig); + const TestConfig testConfig(executor, measureTiming, outputType, memoryType); + EvaluatePreparedModel(device, preparedModel, testModel, testConfig); } } } } -void EvaluatePreparedCoupledModels(const sp& preparedModel, +void EvaluatePreparedCoupledModels(const sp& device, + const sp& preparedModel, const TestModel& testModel, const sp& preparedCoupledModel, const TestModel& coupledModel) { @@ -413,12 +678,12 @@ void EvaluatePreparedCoupledModels(const sp& preparedModel, for (const OutputType outputType : outputTypesList) { for (const MeasureTiming measureTiming : measureTimingList) { for (const Executor executor : executorList) { - const TestConfig testConfig(executor, measureTiming, outputType, + const TestConfig testConfig(executor, measureTiming, outputType, MemoryType::SHARED, /*reportSkipping=*/false); bool baseSkipped = false; - EvaluatePreparedModel(preparedModel, testModel, testConfig, &baseSkipped); + EvaluatePreparedModel(device, preparedModel, testModel, testConfig, &baseSkipped); bool coupledSkipped = false; - EvaluatePreparedModel(preparedCoupledModel, coupledModel, testConfig, + EvaluatePreparedModel(device, preparedCoupledModel, coupledModel, testConfig, &coupledSkipped); ASSERT_EQ(baseSkipped, coupledSkipped); if (baseSkipped) { @@ -443,15 +708,12 @@ void Execute(const sp& device, const TestModel& testModel, TestKind tes sp preparedModel; switch (testKind) { - case TestKind::GENERAL: { + case TestKind::GENERAL: + case TestKind::DYNAMIC_SHAPE: + case TestKind::MEMORY_DOMAIN: { createPreparedModel(device, model, &preparedModel); if (preparedModel == nullptr) return; - EvaluatePreparedModel(preparedModel, testModel, TestKind::GENERAL); - } break; - case TestKind::DYNAMIC_SHAPE: { - createPreparedModel(device, model, &preparedModel); - if (preparedModel == nullptr) return; - EvaluatePreparedModel(preparedModel, testModel, TestKind::DYNAMIC_SHAPE); + EvaluatePreparedModel(device, preparedModel, testModel, testKind); } break; case TestKind::QUANTIZATION_COUPLING: { ASSERT_TRUE(testModel.hasQuant8CoupledOperands()); @@ -475,7 +737,7 @@ void Execute(const sp& device, const TestModel& testModel, TestKind tes GTEST_SKIP(); } ASSERT_NE(preparedCoupledModel, nullptr); - EvaluatePreparedCoupledModels(preparedModel, testModel, preparedCoupledModel, + EvaluatePreparedCoupledModels(device, preparedModel, testModel, preparedCoupledModel, signedQuantizedModel); } break; } @@ -501,6 +763,9 @@ class GeneratedTest : public GeneratedTestBase {}; // Tag for the dynamic output shape tests class DynamicOutputShapeTest : public GeneratedTest {}; +// Tag for the memory domain tests +class MemoryDomainTest : public GeneratedTest {}; + // Tag for the dynamic output shape tests class QuantizationCouplingTest : public GeneratedTest {}; @@ -512,6 +777,10 @@ TEST_P(DynamicOutputShapeTest, Test) { Execute(kDevice, kTestModel, /*testKind=*/TestKind::DYNAMIC_SHAPE); } +TEST_P(MemoryDomainTest, Test) { + Execute(kDevice, kTestModel, /*testKind=*/TestKind::MEMORY_DOMAIN); +} + TEST_P(QuantizationCouplingTest, Test) { Execute(kDevice, kTestModel, /*testKind=*/TestKind::QUANTIZATION_COUPLING); } @@ -522,6 +791,9 @@ INSTANTIATE_GENERATED_TEST(GeneratedTest, INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); +INSTANTIATE_GENERATED_TEST(MemoryDomainTest, + [](const TestModel& testModel) { return !testModel.expectFailure; }); + INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) { return testModel.hasQuant8CoupledOperands() && testModel.operations.size() == 1; }); diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h index ad6323f48c..2273e3bfe4 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h @@ -62,13 +62,15 @@ enum class TestKind { GENERAL, // Same as GENERAL but sets dimensions for the output tensors to zeros DYNAMIC_SHAPE, + // Same as GENERAL but use device memories for inputs and outputs + MEMORY_DOMAIN, // Tests if quantized model with TENSOR_QUANT8_ASYMM produces the same result // (OK/SKIPPED/FAILED) as the model with all such tensors converted to // TENSOR_QUANT8_ASYMM_SIGNED. QUANTIZATION_COUPLING }; -void EvaluatePreparedModel(const sp& preparedModel, +void EvaluatePreparedModel(const sp& device, const sp& preparedModel, const test_helper::TestModel& testModel, TestKind testKind); } // namespace android::hardware::neuralnetworks::V1_3::vts::functional From 322c4cc2860f8c1dc8c456635df81cd0f64a7140 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 20 Nov 2019 11:25:02 -0800 Subject: [PATCH 0432/1022] PhoneCapabilities changes for device capabilities Change PhoneCapability structure to contain static capabilities for: * the entire device * each modem/radio * each SIM slot Created SimSlotCapability and SlotType to hold information about device SIM slot capabilities (separate from SimSlotStatus). Created ModemFeatures to express modem capabilities as a bitfield of concurrently supportable modem features. PhoneCapability has fields for UE categories, bands, access networks, and modem switching linger time. It also contains a lists of logical modem UUIDs, SIM slot capabilities, and all possible concurrently supportable modem features. TelephonyManager will have an API that returns * the PhoneCapability for the device * active set of ModemFeatures Apps with CARRIER_PRIVILEGE can use these APIs to access all capabilities of a device (eg. 5G capable, DSDS capable, etc.) and use them to make decisions based on what the device can support. Test: atest FrameworksTelephonyTests Bug: 143238237 Bug: 143238191 Change-Id: I424ef176086d2308a4bf53b2c79407eabafb3178 --- current.txt | 6 +- radio/1.5/vts/functional/Android.bp | 1 + .../vts/functional/radio_hidl_hal_test.cpp | 4 +- .../functional/radio_hidl_hal_utils_v1_5.h | 2 +- radio/config/1.3/Android.bp | 3 + radio/config/1.3/IRadioConfig.hal | 10 +- radio/config/1.3/IRadioConfigResponse.hal | 13 +- radio/config/1.3/default/RadioConfig.cpp | 9 +- radio/config/1.3/default/RadioConfig.h | 3 + .../1.3/default/RadioConfigIndication.cpp | 4 - .../1.3/default/RadioConfigIndication.h | 4 - .../1.3/default/RadioConfigResponse.cpp | 12 +- .../config/1.3/default/RadioConfigResponse.h | 43 ++--- radio/config/1.3/types.hal | 178 ++++++++++++++++++ .../functional/radio_config_hidl_hal_api.cpp | 31 +++ .../functional/radio_config_hidl_hal_test.cpp | 2 +- .../functional/radio_config_hidl_hal_utils.h | 37 ++-- .../vts/functional/radio_config_response.cpp | 28 ++- 18 files changed, 315 insertions(+), 75 deletions(-) diff --git a/current.txt b/current.txt index 6ce12cc7e6..edc46ed19c 100644 --- a/current.txt +++ b/current.txt @@ -668,10 +668,10 @@ c72cb37b3f66ef65aeb5c6438a3fbe17bbe847fdf62d1a76eafd7f3a8a526105 android.hardwar 996f98ffe508a2f6f1755c1511b50067f7883f7c445dea9f3e931385f020b7ab android.hardware.radio@1.5::IRadio 20d52e66fd548f89bcb98cda42749a591ce8f439a2a7148617adac0c967ad937 android.hardware.radio@1.5::IRadioIndication 1512f6e1198e1aa0ebcbdb1694d0ed500a3e7791d6f305327866112331d82b66 android.hardware.radio@1.5::IRadioResponse -55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types -b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig +5971a891d7d8843e9fb9f44583a9a0a265ec42fd5e4e1c95c9803454d21fabf7 android.hardware.radio.config@1.3::types +a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication -7683fed9d253956071f18b152e6be657719536f98d9b534433d5e411bcde5061 android.hardware.radio.config@1.3::IRadioConfigResponse +0006ab8e8b0910cbd3bbb08d5f17d5fac7d65a2bdad5f2334e4851db9d1e6fa8 android.hardware.radio.config@1.3::IRadioConfigResponse ## # END Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present ## diff --git a/radio/1.5/vts/functional/Android.bp b/radio/1.5/vts/functional/Android.bp index 85c4f99db4..182985e68f 100644 --- a/radio/1.5/vts/functional/Android.bp +++ b/radio/1.5/vts/functional/Android.bp @@ -34,6 +34,7 @@ cc_test { "android.hardware.radio@1.0", "android.hardware.radio.config@1.0", "android.hardware.radio.config@1.1", + "android.hardware.radio.config@1.3", ], header_libs: ["radio.util.header@1.0"], test_suites: ["general-tests"] diff --git a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp index a5d236d47f..c29ebf940a 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp @@ -47,9 +47,9 @@ void RadioHidlTest_v1_5::SetUp() { EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); - sp<::android::hardware::radio::config::V1_1::IRadioConfig> radioConfig = + sp<::android::hardware::radio::config::V1_3::IRadioConfig> radioConfig = ::testing::VtsHalHidlTargetTestBase::getService< - ::android::hardware::radio::config::V1_1::IRadioConfig>(); + ::android::hardware::radio::config::V1_3::IRadioConfig>(); /* Enforce Vts tesing with RadioConfig is existed. */ ASSERT_NE(nullptr, radioConfig.get()); diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index 217caf5692..c2a7d8a800 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include diff --git a/radio/config/1.3/Android.bp b/radio/config/1.3/Android.bp index 88de666618..7360270310 100644 --- a/radio/config/1.3/Android.bp +++ b/radio/config/1.3/Android.bp @@ -17,6 +17,9 @@ hidl_interface { "android.hardware.radio.config@1.1", "android.hardware.radio.config@1.2", "android.hardware.radio@1.0", + "android.hardware.radio@1.1", + "android.hardware.radio@1.4", + "android.hardware.radio@1.5", "android.hidl.base@1.0", ], gen_java: true, diff --git a/radio/config/1.3/IRadioConfig.hal b/radio/config/1.3/IRadioConfig.hal index a0ce6e089d..d01f54b041 100644 --- a/radio/config/1.3/IRadioConfig.hal +++ b/radio/config/1.3/IRadioConfig.hal @@ -27,5 +27,13 @@ import @1.1::IRadioConfig; * serial to different methods), multiple responses (one for each method call) must still be served. */ interface IRadioConfig extends @1.1::IRadioConfig { - + /** + * Request current phone capability. + * + * @param serial Serial number of request. + * + * Response callback is IRadioResponse.getPhoneCapabilityResponse_1_3() which + * will return <@1.3::PhoneCapability>. + */ + oneway getPhoneCapability_1_3(int32_t serial); }; diff --git a/radio/config/1.3/IRadioConfigResponse.hal b/radio/config/1.3/IRadioConfigResponse.hal index 9c4c971f9f..e13aa1efb6 100644 --- a/radio/config/1.3/IRadioConfigResponse.hal +++ b/radio/config/1.3/IRadioConfigResponse.hal @@ -16,11 +16,22 @@ package android.hardware.radio.config@1.3; +import android.hardware.radio@1.0::RadioResponseInfo; import @1.2::IRadioConfigResponse; +import @1.3::PhoneCapability; /** * Interface declaring response functions to solicited radio config requests. */ interface IRadioConfigResponse extends @1.2::IRadioConfigResponse { - + /** + * @param info Response info struct containing response type, serial no. and error + * @param phoneCapability <@1.3::PhoneCapability> it defines modem's capability for example + * how many logical modems it has, how many data connections it supports. + * + * Valid errors returned: + * RadioError:NONE + * RadioError:RADIO_NOT_AVAILABLE + */ + oneway getPhoneCapabilityResponse_1_3(RadioResponseInfo info, PhoneCapability phoneCapability); }; diff --git a/radio/config/1.3/default/RadioConfig.cpp b/radio/config/1.3/default/RadioConfig.cpp index c28119c311..01e98f1dd6 100644 --- a/radio/config/1.3/default/RadioConfig.cpp +++ b/radio/config/1.3/default/RadioConfig.cpp @@ -24,7 +24,6 @@ namespace V1_3 { namespace implementation { using namespace ::android::hardware::radio::V1_0; -using namespace ::android::hardware::radio::config; // Methods from ::android::hardware::radio::config::V1_0::IRadioConfig follow. Return RadioConfig::setResponseFunctions( @@ -105,6 +104,14 @@ Return RadioConfig::getModemsConfig(int32_t /* serial */) { return Void(); } +// Methods from ::android::hardware::radio::config::V1_3::IRadioConfig follow. +Return RadioConfig::getPhoneCapability_1_3(int32_t /* serial */) { + V1_3::PhoneCapability phoneCapability; + RadioResponseInfo info; + mRadioConfigResponseV1_3->getPhoneCapabilityResponse_1_3(info, phoneCapability); + return Void(); +} + } // namespace implementation } // namespace V1_3 } // namespace config diff --git a/radio/config/1.3/default/RadioConfig.h b/radio/config/1.3/default/RadioConfig.h index 00585e6df2..57ff3689eb 100644 --- a/radio/config/1.3/default/RadioConfig.h +++ b/radio/config/1.3/default/RadioConfig.h @@ -62,6 +62,9 @@ struct RadioConfig : public V1_3::IRadioConfig { Return setPreferredDataModem(int32_t serial, uint8_t modemId); Return setModemsConfig(int32_t serial, const V1_1::ModemsConfig& modemsConfig); Return getModemsConfig(int32_t serial); + + // Methods from ::android::hardware::radio::config::V1_3::IRadioConfig follow. + Return getPhoneCapability_1_3(int32_t serial); }; } // namespace implementation diff --git a/radio/config/1.3/default/RadioConfigIndication.cpp b/radio/config/1.3/default/RadioConfigIndication.cpp index eb77a48ec1..608fa1c258 100644 --- a/radio/config/1.3/default/RadioConfigIndication.cpp +++ b/radio/config/1.3/default/RadioConfigIndication.cpp @@ -23,10 +23,6 @@ namespace config { namespace V1_3 { namespace implementation { -using namespace ::android::hardware::radio::V1_0; -using namespace ::android::hardware::radio::config::V1_0; -using namespace ::android::hardware::radio::config::V1_2; - // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigIndication follow. Return RadioConfigIndication::simSlotsStatusChanged( RadioIndicationType /* type */, const hidl_vec& /* slotStatus */) { diff --git a/radio/config/1.3/default/RadioConfigIndication.h b/radio/config/1.3/default/RadioConfigIndication.h index 3697492375..c92446cbe2 100644 --- a/radio/config/1.3/default/RadioConfigIndication.h +++ b/radio/config/1.3/default/RadioConfigIndication.h @@ -31,10 +31,6 @@ namespace implementation { using namespace ::android::hardware::radio::V1_0; using namespace ::android::hardware::radio::config; -using ::android::sp; -using ::android::hardware::hidl_array; -using ::android::hardware::hidl_memory; -using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; diff --git a/radio/config/1.3/default/RadioConfigResponse.cpp b/radio/config/1.3/default/RadioConfigResponse.cpp index 48e81dade3..1d48a13e37 100644 --- a/radio/config/1.3/default/RadioConfigResponse.cpp +++ b/radio/config/1.3/default/RadioConfigResponse.cpp @@ -23,11 +23,6 @@ namespace config { namespace V1_3 { namespace implementation { -using namespace ::android::hardware::radio::V1_0; -using namespace ::android::hardware::radio::config::V1_0; -using namespace ::android::hardware::radio::config::V1_1; -using namespace ::android::hardware::radio::config::V1_2; - // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow. Return RadioConfigResponse::getSimSlotsStatusResponse( const RadioResponseInfo& /* info */, @@ -73,6 +68,13 @@ Return RadioConfigResponse::getSimSlotsStatusResponse_1_2( return Void(); } +// Methods from ::android::hardware::radio::config::V1_3::IRadioConfigResponse follow. +Return RadioConfigResponse::getPhoneCapabilityResponse_1_3( + const RadioResponseInfo& /* info */, const V1_3::PhoneCapability& /* phoneCapability */) { + // TODO implement + return Void(); +} + } // namespace implementation } // namespace V1_3 } // namespace config diff --git a/radio/config/1.3/default/RadioConfigResponse.h b/radio/config/1.3/default/RadioConfigResponse.h index 0f0033fa6a..dc169bb635 100644 --- a/radio/config/1.3/default/RadioConfigResponse.h +++ b/radio/config/1.3/default/RadioConfigResponse.h @@ -28,43 +28,36 @@ namespace config { namespace V1_3 { namespace implementation { -using ::android::sp; -using ::android::hardware::hidl_array; -using ::android::hardware::hidl_memory; -using ::android::hardware::hidl_string; +using namespace ::android::hardware::radio::config; + using ::android::hardware::hidl_vec; using ::android::hardware::Return; -using ::android::hardware::Void; + +using ::android::hardware::radio::V1_0::RadioResponseInfo; struct RadioConfigResponse : public IRadioConfigResponse { // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow. Return getSimSlotsStatusResponse( - const ::android::hardware::radio::V1_0::RadioResponseInfo& info, - const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus) - override; - Return setSimSlotsMappingResponse( - const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override; + const RadioResponseInfo& info, + const hidl_vec& slotStatus) override; + Return setSimSlotsMappingResponse(const RadioResponseInfo& info) override; // Methods from ::android::hardware::radio::config::V1_1::IRadioConfigResponse follow. - Return getPhoneCapabilityResponse( - const ::android::hardware::radio::V1_0::RadioResponseInfo& info, - const ::android::hardware::radio::config::V1_1::PhoneCapability& phoneCapability) - override; - Return setPreferredDataModemResponse( - const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override; - Return setModemsConfigResponse( - const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override; - Return getModemsConfigResponse( - const ::android::hardware::radio::V1_0::RadioResponseInfo& info, - const ::android::hardware::radio::config::V1_1::ModemsConfig& modemsConfig) override; + Return getPhoneCapabilityResponse(const RadioResponseInfo& info, + const V1_1::PhoneCapability& phoneCapability) override; + Return setPreferredDataModemResponse(const RadioResponseInfo& info) override; + Return setModemsConfigResponse(const RadioResponseInfo& info) override; + Return getModemsConfigResponse(const RadioResponseInfo& info, + const V1_1::ModemsConfig& modemsConfig) override; // Methods from ::android::hardware::radio::config::V1_2::IRadioConfigResponse follow. Return getSimSlotsStatusResponse_1_2( - const ::android::hardware::radio::V1_0::RadioResponseInfo& info, - const hidl_vec<::android::hardware::radio::config::V1_2::SimSlotStatus>& slotStatus) - override; + const RadioResponseInfo& info, + const hidl_vec& slotStatus) override; - // Methods from ::android::hidl::base::V1_0::IBase follow. + // Methods from ::android::hardware::radio::config::V1_3::IRadioConfigResponse follow. + Return getPhoneCapabilityResponse_1_3( + const RadioResponseInfo& info, const V1_3::PhoneCapability& phoneCapability) override; }; } // namespace implementation diff --git a/radio/config/1.3/types.hal b/radio/config/1.3/types.hal index 866002acad..3414534138 100644 --- a/radio/config/1.3/types.hal +++ b/radio/config/1.3/types.hal @@ -15,3 +15,181 @@ */ package android.hardware.radio.config@1.3; + +import android.hardware.radio@1.1::GeranBands; +import android.hardware.radio@1.1::UtranBands; +import android.hardware.radio@1.1::EutranBands; +import android.hardware.radio@1.4::RadioAccessFamily; +import android.hardware.radio@1.5::NgranBands; + +/** Type for the SIM slot. */ +enum SlotType : int32_t { + /** Slot type for UICC/pSIM (physical SIM). */ + UICC = 1, + /** Slot type for iUICC/iSIM (integrated SIM). */ + IUICC = 2, + /** Slot type for eUICC/eSIM (embedded SIM). */ + EUICC = 3, + /** Slot type for soft SIM (no physical SIM). */ + SOFT_SIM = 4, +}; + +/** A field in PhoneCapability that holds information about the SIM slot. */ +struct SimSlotCapability { + /** Corresponds to physicalSlotId in Radio@1.2::CardStatus. */ + uint32_t physicalSlotId; + + /** Type of slot. */ + SlotType slotType; +}; + +/** Bitmask of features that can be supported by a single modem. */ +enum ModemFeatures : int32_t { + /** 3GPP2 capability. */ + THREE_GPP2_REG = 1 << 0, + /** 3GPP capability. */ + THREE_GPP_REG = 1 << 1, + /** CDMA 2000 with EHRPD capability. */ + CDMA2000_EHRPD_REG = 1 << 2, + /** GSM capability. */ + GERAN_REG = 1 << 3, + /** UMTS capability. */ + UTRAN_REG = 1 << 4, + /** LTE capability. */ + EUTRAN_REG = 1 << 5, + /** 5G capability. */ + NGRAN_REG = 1 << 6, + /** Dual Connectivity capability. */ + EN_DC_REG = 1 << 7, + /** VoLTE capability (IMS registered). */ + PS_VOICE_REG = 1 << 8, + /** CS voice call capability. */ + CS_VOICE_SESSION = 1 << 9, + /** Internet connection capability. */ + INTERACTIVE_DATA_SESSION = 1 << 10, + /** Dedicated bearer capability. */ + DEDICATED_BEARER = 1 << 11, + /** Network scanning capability. */ + NETWORK_SCAN = 1 << 12, + /** CDMA capability for SIM associated with modem. */ + CSIM = 1 << 13, +}; + +struct ConcurrentModemFeatures { + /** + * A vector of concurrently supportable modem features across all modems. + * Each entry in the vector is a bitfield of ModemFeatures that can be used + * concurrently with the other ModemFeatures in that list. + * Each bitfield must be the full set of features for a single modem. + * + * On a Dual-SIM device, each entry will be a vector of length 2. + * The examples below depict the modemFeatures for four Dual-SIM setups: + * 1. Only one modem can PS attach (IMS registered). + * { + * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG | + * CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER), + * (GERAN_REG | UTRAN_REG) + * } + * or + * { + * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG | + * INTERACTIVE_DATA_SESSION), + * (GERAN_REG | UTRAN_REG | CS_VOICE_SESSION) + * } + * 2. Both modems can PS attach (dual VoLTE). + * { + * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG | + * CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER), + * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG) + * } + * 3. Both modems can maintain an Internet connection, but they share + * one RF hardware. + * { + * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG | + * CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER), + * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG | + * INTERACTIVE_DATA_SESSION) + * } + * 4. Both modems can maintain an Internet connection, and they have + * their own RF hardware. + * { + * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG | + * CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER), + * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG | + * INTERACTIVE_DATA_SESSION | DEDICATED_BEARER) + * } + */ + vec> modemFeatures; +}; + +/** + * Overwritten from @1.1::PhoneCapability to add new capabilities and deprecate + * maxActiveData, maxActiveInternetData, isInternetLingeringSupported, logicalModemList. + * Replaces RadioConfig@1.1::ModemInfo and should replace Radio@1.4::RadioCapabilities + * in the next major version upgrade. In the future, this should be extended instead of overwritten. + */ +struct PhoneCapability { + /** + * 3GPP UE category for UTRAN downlink direction. + * 25.306 Table 5.1a + */ + uint8_t utranUeCategoryDl; + /** + * 3GPP UE category for UTRAN uplink direction. + * 25.306 Table 5.1g + */ + uint8_t utranUeCategoryUl; + /** + * 3GPP UE category for EUTRAN downlink direction. + * 25.306 Table 4.1a + */ + uint8_t eutranUeCategoryDl; + /** + * 3GPP UE category for EUTRAN uplink direction. + * 25.306 Table 4.1a-2 + */ + uint8_t eutranUeCategoryUl; + + /** + * Length of grace period for switching between logical modems, in milliseconds. + * Used only when the number of logical modems is greater than the number of + * Internet connections the device can support, otherwise must be 0. + */ + uint64_t psDataConnectionLingerTimeMillis; + + vec geranBands; + vec utranBands; + vec eutranBands; + vec ngranBands; + + /** + * 32-bit bitmap of supported Radio@1.4::RadioAccessFamily types. + * Note that RadioAccessFamily is actually the radio access technologies, so it should be + * renamed in the next major version upgrade. + */ + bitfield supportedRats; + + /** + * List of unique logical modem UUIDs from Radio@1.4::RadioCapabilities. + * A UUID is typically "com.xxxx.lmX" where X is the logical modem ID. + * Must be equal to the number of logical modems in the device. + * Radio@1.2::RadioConst::MAX_UUID_LENGTH is the max length of each UUID. + */ + vec logicalModemUuids; + + /** + * List of SIM slot capabilities. The order of physical slot IDs must correspond to + * the order of modems in logicalModemUuids. + */ + vec simSlotCapabilities; + + /** + * A vector of all sets of concurrently supportable modem feature sets. The order of modems + * in modemFeatures must correspond to the order of modems in logicalModemUuids. + * Each entry in concurrentFeatureSupport is independent of others in the list + * and represents a set of concurrently supportable features across all modems. + * Each entry in ConcurrentModemFeatures::modemFeatures is a bitfield of + * concurrently supported ModemFeatures for one modem. + */ + vec concurrentFeatureSupport; +}; diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp index 07e9eded5a..7f90023b89 100644 --- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp +++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp @@ -17,3 +17,34 @@ #include #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) + +/* + * Test IRadioConfig.getPhoneCapability_1_3() + */ +TEST_P(RadioConfigHidlTest, getPhoneCapability_1_3) { + serial = GetRandomSerialNumber(); + Return res = radioConfig->getPhoneCapability_1_3(serial); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioConfigRsp->rspInfo.type); + EXPECT_EQ(serial, radioConfigRsp->rspInfo.serial); + ALOGI("getPhoneCapability_1_3, rspInfo.error = %s\n", + toString(radioConfigRsp->rspInfo.error).c_str()); + + ASSERT_TRUE(CheckAnyOfErrors( + radioConfigRsp->rspInfo.error, + {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR})); + + if (radioConfigRsp->rspInfo.error == RadioError ::NONE) { + int numModems = radioConfigRsp->phoneCap_1_3.logicalModemUuids.size(); + EXPECT_GE(numModems, 0); + // length of simSlotCapabilities should be equal to length of logicalModemUuids. + EXPECT_EQ(numModems, radioConfigRsp->phoneCap_1_3.simSlotCapabilities.size()); + // length of modemFeatures in each ConcurrentModemFeatures should be + // equal to length of logicalModemUuids. + for (V1_3::ConcurrentModemFeatures cmf : + radioConfigRsp->phoneCap_1_3.concurrentFeatureSupport) { + EXPECT_EQ(numModems, cmf.modemFeatures.size()); + } + } +} diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp index dbb4bf44e3..cd48b25fac 100644 --- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp +++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp @@ -17,7 +17,7 @@ #include void RadioConfigHidlTest::SetUp() { - radioConfig = ::android::hardware::radio::config::V1_3::IRadioConfig::getService(GetParam()); + radioConfig = V1_3::IRadioConfig::getService(GetParam()); ASSERT_NE(nullptr, radioConfig.get()); radioConfigRsp = new (std::nothrow) RadioConfigResponse(*this); diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h index 9b78c04944..b21c7c0b84 100644 --- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h +++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h @@ -28,19 +28,18 @@ #include #include #include +#include #include "vts_test_util.h" -using namespace ::android::hardware::radio::config::V1_1; -using namespace ::android::hardware::radio::config::V1_2; -using namespace ::android::hardware::radio::config::V1_3; +using namespace ::android::hardware::radio::config; using ::android::sp; -using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; +using ::android::hardware::radio::V1_0::RadioIndicationType; using ::android::hardware::radio::V1_0::RadioResponseInfo; using ::android::hardware::radio::V1_0::RadioResponseType; @@ -49,43 +48,46 @@ using ::android::hardware::radio::V1_0::RadioResponseType; class RadioConfigHidlTest; /* Callback class for radio config response */ -class RadioConfigResponse : public ::android::hardware::radio::config::V1_3::IRadioConfigResponse { +class RadioConfigResponse : public V1_3::IRadioConfigResponse { protected: RadioConfigHidlTest& parent; public: RadioResponseInfo rspInfo; - PhoneCapability phoneCap; + V1_1::PhoneCapability phoneCap_1_1; + V1_3::PhoneCapability phoneCap_1_3; RadioConfigResponse(RadioConfigHidlTest& parent); virtual ~RadioConfigResponse() = default; /* 1.0 Api */ - Return getSimSlotsStatusResponse( - const RadioResponseInfo& info, - const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus); + Return getSimSlotsStatusResponse(const RadioResponseInfo& info, + const hidl_vec& slotStatus); Return setSimSlotsMappingResponse(const RadioResponseInfo& info); /* 1.1 Api */ Return getPhoneCapabilityResponse(const RadioResponseInfo& info, - const PhoneCapability& phoneCapability); + const V1_1::PhoneCapability& phoneCapability); Return setPreferredDataModemResponse(const RadioResponseInfo& info); Return getModemsConfigResponse(const RadioResponseInfo& info, - const ModemsConfig& mConfig); + const V1_1::ModemsConfig& mConfig); Return setModemsConfigResponse(const RadioResponseInfo& info); /* 1.2 Api */ Return getSimSlotsStatusResponse_1_2(const RadioResponseInfo& info, - const hidl_vec& slotStatus); + const hidl_vec& slotStatus); + + /* 1.3 Api */ + Return getPhoneCapabilityResponse_1_3(const RadioResponseInfo& info, + const V1_3::PhoneCapability& phoneCapability); }; /* Callback class for radio config indication */ -class RadioConfigIndication - : public ::android::hardware::radio::config::V1_3::IRadioConfigIndication { +class RadioConfigIndication : public V1_3::IRadioConfigIndication { protected: RadioConfigHidlTest& parent; @@ -94,9 +96,8 @@ class RadioConfigIndication virtual ~RadioConfigIndication() = default; /* 1.2 Api */ - Return simSlotsStatusChanged_1_2( - ::android::hardware::radio::V1_0::RadioIndicationType type, - const hidl_vec& slotStatus); + Return simSlotsStatusChanged_1_2(RadioIndicationType type, + const hidl_vec& slotStatus); }; // The main test class for Radio config HIDL. @@ -121,7 +122,7 @@ class RadioConfigHidlTest : public ::testing::TestWithParam { int serial; /* radio config service handle */ - sp<::android::hardware::radio::config::V1_3::IRadioConfig> radioConfig; + sp radioConfig; /* radio config response handle */ sp radioConfigRsp; diff --git a/radio/config/1.3/vts/functional/radio_config_response.cpp b/radio/config/1.3/vts/functional/radio_config_response.cpp index 1ca960eae9..22098d3d93 100644 --- a/radio/config/1.3/vts/functional/radio_config_response.cpp +++ b/radio/config/1.3/vts/functional/radio_config_response.cpp @@ -16,17 +16,18 @@ #include -using ::android::hardware::radio::V1_0::RadioResponseInfo; +using namespace ::android::hardware::radio::config; -// SimSlotStatus slotStatus; +using ::android::hardware::hidl_vec; + +using ::android::hardware::radio::V1_0::RadioResponseInfo; RadioConfigResponse::RadioConfigResponse(RadioConfigHidlTest& parent) : parent(parent) {} /* 1.0 Apis */ Return RadioConfigResponse::getSimSlotsStatusResponse( const RadioResponseInfo& /* info */, - const ::android::hardware::hidl_vec< - ::android::hardware::radio::config::V1_0::SimSlotStatus>& /* slotStatus */) { + const hidl_vec& /* slotStatus */) { return Void(); } @@ -36,9 +37,9 @@ Return RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponse /* 1.1 Apis */ Return RadioConfigResponse::getPhoneCapabilityResponse( - const RadioResponseInfo& info, const PhoneCapability& phoneCapability) { + const RadioResponseInfo& info, const V1_1::PhoneCapability& phoneCapability) { rspInfo = info; - phoneCap = phoneCapability; + phoneCap_1_1 = phoneCapability; parent.notify(info.serial); return Void(); } @@ -49,7 +50,7 @@ Return RadioConfigResponse::setPreferredDataModemResponse( } Return RadioConfigResponse::getModemsConfigResponse(const RadioResponseInfo& /* info */, - const ModemsConfig& /* mConfig */) { + const V1_1::ModemsConfig& /* mConfig */) { return Void(); } @@ -60,6 +61,15 @@ Return RadioConfigResponse::setModemsConfigResponse(const RadioResponseInf /* 1.2 Apis */ Return RadioConfigResponse::getSimSlotsStatusResponse_1_2( const RadioResponseInfo& /* info */, - const ::android::hardware::hidl_vec& /* slotStatus */) { + const hidl_vec& /* slotStatus */) { return Void(); -} \ No newline at end of file +} + +/* 1.3 Apis */ +Return RadioConfigResponse::getPhoneCapabilityResponse_1_3( + const RadioResponseInfo& info, const V1_3::PhoneCapability& phoneCapability) { + rspInfo = info; + phoneCap_1_3 = phoneCapability; + parent.notify(info.serial); + return Void(); +} From 5958d576edba8baeac0ef3b0daa332615afc4db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Gaffie?= Date: Fri, 13 Dec 2019 13:31:36 -0800 Subject: [PATCH 0433/1022] audio: Add VTS for configurable engine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL adds VTS tests for engine configuration. Test: atest VtsHalAudioPolicyV1_0TargetTest Bug: 141989952 Change-Id: Ied37edc5bba29ef461f6b68fa21781d5721b75bf Signed-off-by: François Gaffie Signed-off-by: Mikhail Naganov --- audio/policy/1.0/vts/OWNERS | 2 + audio/policy/1.0/vts/functional/Android.bp | 31 ++ .../ValidateEngineConfiguration.cpp | 38 ++ .../VtsHalAudioPolicyV1_0TargetTest.xml | 36 ++ audio/policy/1.0/xml/Android.bp | 5 + audio/policy/1.0/xml/api/current.txt | 296 +++++++++++++ audio/policy/1.0/xml/api/last_current.txt | 0 audio/policy/1.0/xml/api/last_removed.txt | 0 audio/policy/1.0/xml/api/removed.txt | 1 + .../xml/audio_policy_engine_configuration.xsd | 402 ++++++++++++++++++ 10 files changed, 811 insertions(+) create mode 100644 audio/policy/1.0/vts/OWNERS create mode 100644 audio/policy/1.0/vts/functional/Android.bp create mode 100644 audio/policy/1.0/vts/functional/ValidateEngineConfiguration.cpp create mode 100644 audio/policy/1.0/vts/functional/VtsHalAudioPolicyV1_0TargetTest.xml create mode 100644 audio/policy/1.0/xml/Android.bp create mode 100644 audio/policy/1.0/xml/api/current.txt create mode 100644 audio/policy/1.0/xml/api/last_current.txt create mode 100644 audio/policy/1.0/xml/api/last_removed.txt create mode 100644 audio/policy/1.0/xml/api/removed.txt create mode 100644 audio/policy/1.0/xml/audio_policy_engine_configuration.xsd diff --git a/audio/policy/1.0/vts/OWNERS b/audio/policy/1.0/vts/OWNERS new file mode 100644 index 0000000000..24071af220 --- /dev/null +++ b/audio/policy/1.0/vts/OWNERS @@ -0,0 +1,2 @@ +elaurent@google.com +mnaganov@google.com diff --git a/audio/policy/1.0/vts/functional/Android.bp b/audio/policy/1.0/vts/functional/Android.bp new file mode 100644 index 0000000000..f668a25fcf --- /dev/null +++ b/audio/policy/1.0/vts/functional/Android.bp @@ -0,0 +1,31 @@ +cc_test { + name: "VtsHalAudioPolicyV1_0TargetTest", + defaults: ["vts_target_tests_defaults"], + srcs: [ + "ValidateEngineConfiguration.cpp", + ], + static_libs: [ + "android.hardware.audio.common.test.utility", + "libxml2", + "liblog", + ], + // Use test_config for vts-core suite. + // TODO(b/146104851): Add auto-gen rules and remove it. + test_config: "VtsHalAudioPolicyV1_0TargetTest.xml", + cflags: [ + "-DXSD_DIR=\"/data/local/tmp\"", + "-Wall", + "-Werror", + "-Wno-unused-function", + "-O0", + "-g", + ], + data: [ + ":audio_policy_engine_conf_V1_0", + ], + gtest: true, + test_suites: [ + "general-tests", + "vts-core", + ], +} diff --git a/audio/policy/1.0/vts/functional/ValidateEngineConfiguration.cpp b/audio/policy/1.0/vts/functional/ValidateEngineConfiguration.cpp new file mode 100644 index 0000000000..1eb39f95c0 --- /dev/null +++ b/audio/policy/1.0/vts/functional/ValidateEngineConfiguration.cpp @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#include + +#include +#include +#include "utility/ValidateXml.h" + +static const std::vector locations = {"/odm/etc", "/vendor/etc", "/system/etc"}; +static const std::string config = "audio_policy_engine_configuration.xml"; +static const std::string schema = + std::string(XSD_DIR) + "/audio_policy_engine_configuration_V1_0.xsd"; + +/** + * @brief TEST to ensure the audio policy engine configuration file is validating schemas. + * Note: this configuration file is not mandatory, an hardcoded fallback is provided, so + * it does not fail if not found. + */ +TEST(ValidateConfiguration, audioPolicyEngineConfiguration) { + RecordProperty("description", + "Verify that the audio policy engine configuration file " + "is valid according to the schemas"); + EXPECT_VALID_XML_MULTIPLE_LOCATIONS(config.c_str(), locations, schema.c_str()); +} diff --git a/audio/policy/1.0/vts/functional/VtsHalAudioPolicyV1_0TargetTest.xml b/audio/policy/1.0/vts/functional/VtsHalAudioPolicyV1_0TargetTest.xml new file mode 100644 index 0000000000..4318e926e3 --- /dev/null +++ b/audio/policy/1.0/vts/functional/VtsHalAudioPolicyV1_0TargetTest.xml @@ -0,0 +1,36 @@ + + + + diff --git a/audio/policy/1.0/xml/Android.bp b/audio/policy/1.0/xml/Android.bp new file mode 100644 index 0000000000..6da7b5a3e5 --- /dev/null +++ b/audio/policy/1.0/xml/Android.bp @@ -0,0 +1,5 @@ +xsd_config { + name: "audio_policy_engine_conf_V1_0", + srcs: ["audio_policy_engine_configuration.xsd"], + package_name: "audio.policy.V1_0", +} diff --git a/audio/policy/1.0/xml/api/current.txt b/audio/policy/1.0/xml/api/current.txt new file mode 100644 index 0000000000..29a9cd402d --- /dev/null +++ b/audio/policy/1.0/xml/api/current.txt @@ -0,0 +1,296 @@ +// Signature format: 2.0 +package audio.policy.V1_0 { + + public class AttributesGroup { + ctor public AttributesGroup(); + method public java.util.List getAttributes_optional(); + method public audio.policy.V1_0.BundleType getBundle_optional(); + method public audio.policy.V1_0.ContentTypeType getContentType_optional(); + method public audio.policy.V1_0.FlagsType getFlags_optional(); + method public audio.policy.V1_0.SourceType getSource_optional(); + method public audio.policy.V1_0.Stream getStreamType(); + method public audio.policy.V1_0.UsageType getUsage_optional(); + method public String getVolumeGroup(); + method public void setBundle_optional(audio.policy.V1_0.BundleType); + method public void setContentType_optional(audio.policy.V1_0.ContentTypeType); + method public void setFlags_optional(audio.policy.V1_0.FlagsType); + method public void setSource_optional(audio.policy.V1_0.SourceType); + method public void setStreamType(audio.policy.V1_0.Stream); + method public void setUsage_optional(audio.policy.V1_0.UsageType); + method public void setVolumeGroup(String); + } + + public class AttributesRef { + ctor public AttributesRef(); + method public java.util.List getReference(); + } + + public class AttributesRefType { + ctor public AttributesRefType(); + method public audio.policy.V1_0.AttributesType getAttributes(); + method public String getName(); + method public void setAttributes(audio.policy.V1_0.AttributesType); + method public void setName(String); + } + + public class AttributesType { + ctor public AttributesType(); + method public String getAttributesRef(); + method public audio.policy.V1_0.BundleType getBundle(); + method public audio.policy.V1_0.ContentTypeType getContentType(); + method public audio.policy.V1_0.FlagsType getFlags(); + method public audio.policy.V1_0.SourceType getSource(); + method public audio.policy.V1_0.UsageType getUsage(); + method public void setAttributesRef(String); + method public void setBundle(audio.policy.V1_0.BundleType); + method public void setContentType(audio.policy.V1_0.ContentTypeType); + method public void setFlags(audio.policy.V1_0.FlagsType); + method public void setSource(audio.policy.V1_0.SourceType); + method public void setUsage(audio.policy.V1_0.UsageType); + } + + public class BundleType { + ctor public BundleType(); + method public String getKey(); + method public String getValue(); + method public void setKey(String); + method public void setValue(String); + } + + public class Configuration { + ctor public Configuration(); + method public java.util.List getAttributesRef(); + method public java.util.List getCriteria(); + method public java.util.List getCriterion_types(); + method public java.util.List getProductStrategies(); + method public audio.policy.V1_0.Version getVersion(); + method public java.util.List getVolumeGroups(); + method public java.util.List getVolumes(); + method public void setVersion(audio.policy.V1_0.Version); + } + + public enum ContentType { + method public String getRawName(); + enum_constant public static final audio.policy.V1_0.ContentType AUDIO_CONTENT_TYPE_MOVIE; + enum_constant public static final audio.policy.V1_0.ContentType AUDIO_CONTENT_TYPE_MUSIC; + enum_constant public static final audio.policy.V1_0.ContentType AUDIO_CONTENT_TYPE_SONIFICATION; + enum_constant public static final audio.policy.V1_0.ContentType AUDIO_CONTENT_TYPE_SPEECH; + enum_constant public static final audio.policy.V1_0.ContentType AUDIO_CONTENT_TYPE_UNKNOWN; + } + + public class ContentTypeType { + ctor public ContentTypeType(); + method public audio.policy.V1_0.ContentType getValue(); + method public void setValue(audio.policy.V1_0.ContentType); + } + + public class CriteriaType { + ctor public CriteriaType(); + method public java.util.List getCriterion(); + } + + public class CriterionType { + ctor public CriterionType(); + method public String getName(); + method public String getType(); + method public String get_default(); + method public void setName(String); + method public void setType(String); + method public void set_default(String); + } + + public class CriterionTypeType { + ctor public CriterionTypeType(); + method public String getName(); + method public audio.policy.V1_0.PfwCriterionTypeEnum getType(); + method public audio.policy.V1_0.ValuesType getValues(); + method public void setName(String); + method public void setType(audio.policy.V1_0.PfwCriterionTypeEnum); + method public void setValues(audio.policy.V1_0.ValuesType); + } + + public class CriterionTypesType { + ctor public CriterionTypesType(); + method public java.util.List getCriterion_type(); + } + + public enum DeviceCategory { + method public String getRawName(); + enum_constant public static final audio.policy.V1_0.DeviceCategory DEVICE_CATEGORY_EARPIECE; + enum_constant public static final audio.policy.V1_0.DeviceCategory DEVICE_CATEGORY_EXT_MEDIA; + enum_constant public static final audio.policy.V1_0.DeviceCategory DEVICE_CATEGORY_HEADSET; + enum_constant public static final audio.policy.V1_0.DeviceCategory DEVICE_CATEGORY_HEARING_AID; + enum_constant public static final audio.policy.V1_0.DeviceCategory DEVICE_CATEGORY_SPEAKER; + } + + public enum FlagType { + method public String getRawName(); + enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_AUDIBILITY_ENFORCED; + enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_BEACON; + enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY; + enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_BYPASS_MUTE; + enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_CAPTURE_PRIVATE; + enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_DEEP_BUFFER; + enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_HW_AV_SYNC; + enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_HW_HOTWORD; + enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_LOW_LATENCY; + enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_MUTE_HAPTIC; + enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_NONE; + enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_NO_MEDIA_PROJECTION; + enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_NO_SYSTEM_CAPTURE; + enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_SCO; + enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_SECURE; + } + + public class FlagsType { + ctor public FlagsType(); + method public java.util.List getValue(); + method public void setValue(java.util.List); + } + + public enum PfwCriterionTypeEnum { + method public String getRawName(); + enum_constant public static final audio.policy.V1_0.PfwCriterionTypeEnum exclusive; + enum_constant public static final audio.policy.V1_0.PfwCriterionTypeEnum inclusive; + } + + public class ProductStrategies { + ctor public ProductStrategies(); + method public java.util.List getProductStrategy(); + } + + public static class ProductStrategies.ProductStrategy { + ctor public ProductStrategies.ProductStrategy(); + method public java.util.List getAttributesGroup(); + method public String getName(); + method public void setName(String); + } + + public enum SourceEnumType { + method public String getRawName(); + enum_constant public static final audio.policy.V1_0.SourceEnumType AUDIO_SOURCE_CAMCORDER; + enum_constant public static final audio.policy.V1_0.SourceEnumType AUDIO_SOURCE_DEFAULT; + enum_constant public static final audio.policy.V1_0.SourceEnumType AUDIO_SOURCE_ECHO_REFERENCE; + enum_constant public static final audio.policy.V1_0.SourceEnumType AUDIO_SOURCE_FM_TUNER; + enum_constant public static final audio.policy.V1_0.SourceEnumType AUDIO_SOURCE_MIC; + enum_constant public static final audio.policy.V1_0.SourceEnumType AUDIO_SOURCE_REMOTE_SUBMIX; + enum_constant public static final audio.policy.V1_0.SourceEnumType AUDIO_SOURCE_UNPROCESSED; + enum_constant public static final audio.policy.V1_0.SourceEnumType AUDIO_SOURCE_VOICE_CALL; + enum_constant public static final audio.policy.V1_0.SourceEnumType AUDIO_SOURCE_VOICE_COMMUNICATION; + enum_constant public static final audio.policy.V1_0.SourceEnumType AUDIO_SOURCE_VOICE_DOWNLINK; + enum_constant public static final audio.policy.V1_0.SourceEnumType AUDIO_SOURCE_VOICE_PERFORMANCE; + enum_constant public static final audio.policy.V1_0.SourceEnumType AUDIO_SOURCE_VOICE_RECOGNITION; + enum_constant public static final audio.policy.V1_0.SourceEnumType AUDIO_SOURCE_VOICE_UPLINK; + } + + public class SourceType { + ctor public SourceType(); + method public audio.policy.V1_0.SourceEnumType getValue(); + method public void setValue(audio.policy.V1_0.SourceEnumType); + } + + public enum Stream { + method public String getRawName(); + enum_constant public static final audio.policy.V1_0.Stream AUDIO_STREAM_ACCESSIBILITY; + enum_constant public static final audio.policy.V1_0.Stream AUDIO_STREAM_ALARM; + enum_constant public static final audio.policy.V1_0.Stream AUDIO_STREAM_ASSISTANT; + enum_constant public static final audio.policy.V1_0.Stream AUDIO_STREAM_BLUETOOTH_SCO; + enum_constant public static final audio.policy.V1_0.Stream AUDIO_STREAM_DEFAULT; + enum_constant public static final audio.policy.V1_0.Stream AUDIO_STREAM_DTMF; + enum_constant public static final audio.policy.V1_0.Stream AUDIO_STREAM_ENFORCED_AUDIBLE; + enum_constant public static final audio.policy.V1_0.Stream AUDIO_STREAM_MUSIC; + enum_constant public static final audio.policy.V1_0.Stream AUDIO_STREAM_NOTIFICATION; + enum_constant public static final audio.policy.V1_0.Stream AUDIO_STREAM_RING; + enum_constant public static final audio.policy.V1_0.Stream AUDIO_STREAM_SYSTEM; + enum_constant public static final audio.policy.V1_0.Stream AUDIO_STREAM_TTS; + enum_constant public static final audio.policy.V1_0.Stream AUDIO_STREAM_VOICE_CALL; + } + + public enum UsageEnumType { + method public String getRawName(); + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ALARM; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANCE_SONIFICATION; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANT; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_CALL_ASSISTANT; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_GAME; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_MEDIA; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_UNKNOWN; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING; + } + + public class UsageType { + ctor public UsageType(); + method public audio.policy.V1_0.UsageEnumType getValue(); + method public void setValue(audio.policy.V1_0.UsageEnumType); + } + + public class ValueType { + ctor public ValueType(); + method public String getLiteral(); + method public int getNumerical(); + method public void setLiteral(String); + method public void setNumerical(int); + } + + public class ValuesType { + ctor public ValuesType(); + method public java.util.List getValue(); + } + + public enum Version { + method public String getRawName(); + enum_constant public static final audio.policy.V1_0.Version _1_0; + } + + public class Volume { + ctor public Volume(); + method public audio.policy.V1_0.DeviceCategory getDeviceCategory(); + method public java.util.List getPoint(); + method public String getRef(); + method public void setDeviceCategory(audio.policy.V1_0.DeviceCategory); + method public void setRef(String); + } + + public class VolumeGroupsType { + ctor public VolumeGroupsType(); + method public java.util.List getVolumeGroup(); + } + + public static class VolumeGroupsType.VolumeGroup { + ctor public VolumeGroupsType.VolumeGroup(); + method public int getIndexMax(); + method public int getIndexMin(); + method public String getName(); + method public java.util.List getVolume(); + method public void setIndexMax(int); + method public void setIndexMin(int); + method public void setName(String); + } + + public class VolumeRef { + ctor public VolumeRef(); + method public String getName(); + method public java.util.List getPoint(); + method public void setName(String); + } + + public class VolumesType { + ctor public VolumesType(); + method public java.util.List getReference(); + } + + public class XmlParser { + ctor public XmlParser(); + method public static audio.policy.V1_0.Configuration read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + } + +} + diff --git a/audio/policy/1.0/xml/api/last_current.txt b/audio/policy/1.0/xml/api/last_current.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/audio/policy/1.0/xml/api/last_removed.txt b/audio/policy/1.0/xml/api/last_removed.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/audio/policy/1.0/xml/api/removed.txt b/audio/policy/1.0/xml/api/removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/audio/policy/1.0/xml/api/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd new file mode 100644 index 0000000000..842e7246d6 --- /dev/null +++ b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Volume section defines a volume curve for a given use case and device category. + It contains a list of points of this curve expressing the attenuation in Millibels + for a given volume index from 0 to 100. + + 0,-9600 + 100,0 + + + It may also reference a reference/@name to avoid duplicating curves. + + + 0,-9600 + 100,0 + + + + + + + + + + + + + + + + + + + + + Comma separated pair of number. + The fist one is the framework level (between 0 and 100). + The second one is the volume to send to the HAL. + The framework will interpolate volumes not specified. + Their MUST be at least 2 points specified. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 94865666a76d5ce828e211f7d971cbd9255e0abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Gaffie?= Date: Wed, 18 Dec 2019 09:29:58 +0100 Subject: [PATCH 0434/1022] audiopolicy: engine: Add VTS for engine configurable configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL adds VTS test for engine PFW configuration files (Skipped for default engine, the check is performed by reading the audio_policy_configuration file AND parameter-framework top configuration file) AllSchemas.xsd is made by manual inclusion from all other xsd files. It is used for API files generation. Test: build & run vts --module VtsHalAudioPolicyV1_0Target atest VtsHalAudioPolicyV1_0TargetTest Bug: 141989952 Change-Id: I62730caadafdcb5ebb3083d683625424864afe97 Signed-off-by: François Gaffie --- audio/policy/1.0/vts/functional/Android.bp | 30 +- .../ValidateEngineConfiguration.cpp | 75 ++ .../VtsHalAudioPolicyV1_0TargetTest.xml | 12 + .../policy/1.0/xml/pfw_schemas/AllSchemas.xsd | 754 ++++++++++++++++++ audio/policy/1.0/xml/pfw_schemas/Android.bp | 107 +++ .../1.0/xml/pfw_schemas/ComponentLibrary.xsd | 15 + .../1.0/xml/pfw_schemas/ComponentTypeSet.xsd | 39 + .../xml/pfw_schemas/ConfigurableDomain.xsd | 117 +++ .../xml/pfw_schemas/ConfigurableDomains.xsd | 37 + .../1.0/xml/pfw_schemas/FileIncluder.xsd | 15 + .../policy/1.0/xml/pfw_schemas/Parameter.xsd | 213 +++++ .../ParameterFrameworkConfiguration.xsd | 40 + .../1.0/xml/pfw_schemas/ParameterSettings.xsd | 93 +++ audio/policy/1.0/xml/pfw_schemas/README.md | 87 ++ .../policy/1.0/xml/pfw_schemas/Subsystem.xsd | 32 + .../1.0/xml/pfw_schemas/SystemClass.xsd | 17 + .../1.0/xml/pfw_schemas/W3cXmlAttributes.xsd | 146 ++++ .../1.0/xml/pfw_schemas/api/current.txt | 495 ++++++++++++ .../1.0/xml/pfw_schemas/api/last_current.txt | 0 .../1.0/xml/pfw_schemas/api/last_removed.txt | 0 .../1.0/xml/pfw_schemas/api/removed.txt | 1 + 21 files changed, 2324 insertions(+), 1 deletion(-) create mode 100644 audio/policy/1.0/xml/pfw_schemas/AllSchemas.xsd create mode 100644 audio/policy/1.0/xml/pfw_schemas/Android.bp create mode 100644 audio/policy/1.0/xml/pfw_schemas/ComponentLibrary.xsd create mode 100644 audio/policy/1.0/xml/pfw_schemas/ComponentTypeSet.xsd create mode 100644 audio/policy/1.0/xml/pfw_schemas/ConfigurableDomain.xsd create mode 100644 audio/policy/1.0/xml/pfw_schemas/ConfigurableDomains.xsd create mode 100644 audio/policy/1.0/xml/pfw_schemas/FileIncluder.xsd create mode 100644 audio/policy/1.0/xml/pfw_schemas/Parameter.xsd create mode 100644 audio/policy/1.0/xml/pfw_schemas/ParameterFrameworkConfiguration.xsd create mode 100644 audio/policy/1.0/xml/pfw_schemas/ParameterSettings.xsd create mode 100644 audio/policy/1.0/xml/pfw_schemas/README.md create mode 100644 audio/policy/1.0/xml/pfw_schemas/Subsystem.xsd create mode 100644 audio/policy/1.0/xml/pfw_schemas/SystemClass.xsd create mode 100644 audio/policy/1.0/xml/pfw_schemas/W3cXmlAttributes.xsd create mode 100644 audio/policy/1.0/xml/pfw_schemas/api/current.txt create mode 100644 audio/policy/1.0/xml/pfw_schemas/api/last_current.txt create mode 100644 audio/policy/1.0/xml/pfw_schemas/api/last_removed.txt create mode 100644 audio/policy/1.0/xml/pfw_schemas/api/removed.txt diff --git a/audio/policy/1.0/vts/functional/Android.bp b/audio/policy/1.0/vts/functional/Android.bp index f668a25fcf..b50e501d15 100644 --- a/audio/policy/1.0/vts/functional/Android.bp +++ b/audio/policy/1.0/vts/functional/Android.bp @@ -5,15 +5,31 @@ cc_test { "ValidateEngineConfiguration.cpp", ], static_libs: [ - "android.hardware.audio.common.test.utility", "libxml2", "liblog", + "libmedia_helper", + "libaudiopolicyengine_config", + "libaudiopolicycomponents", + "libaudiopolicyengineconfigurable_pfwwrapper", + "android.hardware.audio.common.test.utility", + "libparameter", + "libpfw_utility", + "libremote-processor", + "libutils", + "libcutils", + "libhidlbase", + "liblog", + "libbase", + ], + shared_libs: [ + "libaudiofoundation", ], // Use test_config for vts-core suite. // TODO(b/146104851): Add auto-gen rules and remove it. test_config: "VtsHalAudioPolicyV1_0TargetTest.xml", cflags: [ "-DXSD_DIR=\"/data/local/tmp\"", + "-DXSD_PFW_DIR=\"/data/local/tmp/Schemas\"", "-Wall", "-Werror", "-Wno-unused-function", @@ -22,6 +38,18 @@ cc_test { ], data: [ ":audio_policy_engine_conf_V1_0", + ":audio_policy_engine_configurable_configuration_V1_0", + ":audio_policy_engine_configurable_configuration_ComponentLibrary_V1_0", + ":audio_policy_engine_configurable_configuration_ComponentTypeSet_V1_0", + ":audio_policy_engine_configurable_configuration_ConfigurableDomain_V1_0", + ":audio_policy_engine_configurable_configuration_ConfigurableDomains_V1_0", + ":audio_policy_engine_configurable_configuration_FileIncluder_V1_0", + ":audio_policy_engine_configurable_configuration_Parameter_V1_0", + ":audio_policy_engine_configurable_configuration_ParameterFrameworkConfiguration_V1_0", + ":audio_policy_engine_configurable_configuration_ParameterSettings_V1_0", + ":audio_policy_engine_configurable_configuration_Subsystem_V1_0", + ":audio_policy_engine_configurable_configuration_SystemClass_V1_0", + ":audio_policy_engine_configurable_configuration_W3cXmlAttributes_V1_0", ], gtest: true, test_suites: [ diff --git a/audio/policy/1.0/vts/functional/ValidateEngineConfiguration.cpp b/audio/policy/1.0/vts/functional/ValidateEngineConfiguration.cpp index 1eb39f95c0..a0aaa6e89f 100644 --- a/audio/policy/1.0/vts/functional/ValidateEngineConfiguration.cpp +++ b/audio/policy/1.0/vts/functional/ValidateEngineConfiguration.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +#include +#include + #include #include @@ -25,6 +28,11 @@ static const std::string config = "audio_policy_engine_configuration.xml"; static const std::string schema = std::string(XSD_DIR) + "/audio_policy_engine_configuration_V1_0.xsd"; +static const std::string configurableSchemas = + std::string(XSD_DIR) + "/audio_policy_engine_configurable_configuration_V1_0.xsd"; +static const std::string configurableConfig = + "parameter-framework/ParameterFrameworkConfigurationPolicy.xml"; + /** * @brief TEST to ensure the audio policy engine configuration file is validating schemas. * Note: this configuration file is not mandatory, an hardcoded fallback is provided, so @@ -36,3 +44,70 @@ TEST(ValidateConfiguration, audioPolicyEngineConfiguration) { "is valid according to the schemas"); EXPECT_VALID_XML_MULTIPLE_LOCATIONS(config.c_str(), locations, schema.c_str()); } + +/** + * @brief deviceUsesConfigurableEngine checks if the configuration file for + * the engine presents on the device AND + * for the configurable engine (aka Parameter-Framework top configuration file) presents. + */ +static bool deviceUsesConfigurableEngine() { + return android::hardware::audio::common::test::utility::validateXmlMultipleLocations( + "", "", "", config.c_str(), locations, schema.c_str()) && + android::hardware::audio::common::test::utility::validateXmlMultipleLocations( + "", "", "", configurableConfig.c_str(), locations, configurableSchemas.c_str()); +} + +TEST(ValidateConfiguration, audioPolicyEngineConfigurable) { + if (!deviceUsesConfigurableEngine()) { + GTEST_SKIP() << "Device using legacy engine without parameter-framework, n-op."; + } + RecordProperty("description", + "Verify that the audio policy engine PFW configuration files " + "are valid according to the schemas"); + + auto testAudioPolicyEnginePfw = [&](bool validateSchema, const std::string& schemasUri) { + auto result = android::engineConfig::parse(); + + ASSERT_NE(nullptr, result.parsedConfig) + << "failed to parse audio policy engine configuration"; + + ASSERT_EQ(result.nbSkippedElement, 0) << "skipped %zu elements " << result.nbSkippedElement; + + std::unique_ptr policyParameterMgr( + new android::audio_policy::ParameterManagerWrapper(validateSchema, schemasUri)); + ASSERT_NE(nullptr, policyParameterMgr) << "failed to create Audio Policy Engine PFW"; + + // Load the criterion types and criteria + for (auto& criterion : result.parsedConfig->criteria) { + android::engineConfig::CriterionType criterionType; + for (auto& configCriterionType : result.parsedConfig->criterionTypes) { + if (configCriterionType.name == criterion.typeName) { + criterionType = configCriterionType; + break; + } + } + ASSERT_FALSE(criterionType.name.empty()) + << "Invalid criterion type for " << criterion.name.c_str(); + policyParameterMgr->addCriterion(criterion.name, criterionType.isInclusive, + criterionType.valuePairs, + criterion.defaultLiteralValue); + } + ASSERT_EQ(0, result.nbSkippedElement) << "failed to parse Audio Policy Engine PFW criteria"; + + // If the PFW cannot validate, it will not start + std::string error; + auto status = policyParameterMgr->start(error); + ASSERT_EQ(status, android::NO_ERROR) + << "failed to " << (validateSchema ? "validate" : "start") + << " Audio Policy Engine PFW: " << error; + + ASSERT_TRUE(policyParameterMgr->isStarted()); + }; + + // First round for sanity to ensure we can launch the Audio Policy Engine PFW without + // schema validation successfully, otherwise it is not forth going on running validation... + testAudioPolicyEnginePfw(false, {}); + + // If second round fails, it means parameter-framework cannot validate schema + testAudioPolicyEnginePfw(true, {XSD_PFW_DIR}); +} diff --git a/audio/policy/1.0/vts/functional/VtsHalAudioPolicyV1_0TargetTest.xml b/audio/policy/1.0/vts/functional/VtsHalAudioPolicyV1_0TargetTest.xml index 4318e926e3..68b390f22a 100644 --- a/audio/policy/1.0/vts/functional/VtsHalAudioPolicyV1_0TargetTest.xml +++ b/audio/policy/1.0/vts/functional/VtsHalAudioPolicyV1_0TargetTest.xml @@ -27,6 +27,18 @@ android.hardware.usb.gadget - 1.0 + 1.0-1 IUsbGadget default diff --git a/usb/gadget/1.1/Android.bp b/usb/gadget/1.1/Android.bp new file mode 100644 index 0000000000..b41eb9cbc5 --- /dev/null +++ b/usb/gadget/1.1/Android.bp @@ -0,0 +1,17 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.usb.gadget@1.1", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "IUsbGadget.hal", + ], + interfaces: [ + "android.hardware.usb.gadget@1.0", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/usb/gadget/1.1/IUsbGadget.hal b/usb/gadget/1.1/IUsbGadget.hal new file mode 100644 index 0000000000..af88ef0762 --- /dev/null +++ b/usb/gadget/1.1/IUsbGadget.hal @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package android.hardware.usb.gadget@1.1; + +import @1.0::IUsbGadget; +import @1.0::Status; + +interface IUsbGadget extends @1.0::IUsbGadget { + /** + * This function is used to reset USB gadget driver. + * Performs USB data connection reset. The connection will disconnect and + * reconnect. + * + * return status indicate success or not. + */ + reset() generates(Status status); +}; From 78ca380c681048278b78cdc534eeb030959f163b Mon Sep 17 00:00:00 2001 From: Howard Yen Date: Mon, 2 Dec 2019 21:59:52 +0800 Subject: [PATCH 0444/1022] Add USB Gadget V1.1 with hash code Bug: 138702846 Test: build pass, function works Change-Id: I8b8db3636831adf6f4c7902dee81f2f7bae30182 --- current.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/current.txt b/current.txt index 7b223b3cc2..56bf8d77e8 100644 --- a/current.txt +++ b/current.txt @@ -679,3 +679,4 @@ b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardwar ## 51d1c8d285e0456da2a3fdfbf4700c6277165d5e83219894d651c8ea0e39aa8b android.hardware.soundtrigger@2.3::types 12d7533ff0754f45bf59ab300799074570a99a676545652c2c23abc73cb4515d android.hardware.soundtrigger@2.3::ISoundTriggerHw +7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget From 9bfb4352dcb18b2e57974730c93ac704a42c460c Mon Sep 17 00:00:00 2001 From: Howard Yen Date: Thu, 28 Nov 2019 21:14:57 +0800 Subject: [PATCH 0445/1022] Add USB Gadget Hal v1.1 default implementation Bug: 147645728 Test: Build pass and service running Change-Id: I5648b569dc470deba14a4fc8a0c841e76a0f1b86 --- usb/gadget/1.1/default/Android.bp | 39 +++ usb/gadget/1.1/default/UsbGadget.cpp | 229 +++++++++++++++ usb/gadget/1.1/default/UsbGadget.h | 98 +++++++ ...android.hardware.usb.gadget@1.1-service.rc | 6 + ...ndroid.hardware.usb.gadget@1.1-service.xml | 12 + usb/gadget/1.1/default/lib/Android.bp | 40 +++ usb/gadget/1.1/default/lib/MonitorFfs.cpp | 269 ++++++++++++++++++ usb/gadget/1.1/default/lib/UsbGadgetUtils.cpp | 193 +++++++++++++ .../1.1/default/lib/include/UsbGadgetCommon.h | 177 ++++++++++++ usb/gadget/1.1/default/service.cpp | 52 ++++ 10 files changed, 1115 insertions(+) create mode 100644 usb/gadget/1.1/default/Android.bp create mode 100644 usb/gadget/1.1/default/UsbGadget.cpp create mode 100644 usb/gadget/1.1/default/UsbGadget.h create mode 100644 usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.rc create mode 100644 usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.xml create mode 100644 usb/gadget/1.1/default/lib/Android.bp create mode 100644 usb/gadget/1.1/default/lib/MonitorFfs.cpp create mode 100644 usb/gadget/1.1/default/lib/UsbGadgetUtils.cpp create mode 100644 usb/gadget/1.1/default/lib/include/UsbGadgetCommon.h create mode 100644 usb/gadget/1.1/default/service.cpp diff --git a/usb/gadget/1.1/default/Android.bp b/usb/gadget/1.1/default/Android.bp new file mode 100644 index 0000000000..68e2a29857 --- /dev/null +++ b/usb/gadget/1.1/default/Android.bp @@ -0,0 +1,39 @@ +/* + * 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. + */ + +cc_binary { + name: "android.hardware.usb.gadget@1.1-service", + defaults: ["hidl_defaults"], + relative_install_path: "hw", + init_rc: ["android.hardware.usb.gadget@1.1-service.rc"], + vintf_fragments: ["android.hardware.usb.gadget@1.1-service.xml"], + vendor: true, + srcs: [ + "service.cpp", + "UsbGadget.cpp", + ], + shared_libs: [ + "android.hardware.usb.gadget@1.0", + "android.hardware.usb.gadget@1.1", + "libbase", + "libcutils", + "libhardware", + "libhidlbase", + "liblog", + "libutils", + ], + static_libs: ["libusbconfigfs"], +} diff --git a/usb/gadget/1.1/default/UsbGadget.cpp b/usb/gadget/1.1/default/UsbGadget.cpp new file mode 100644 index 0000000000..36d865dc2e --- /dev/null +++ b/usb/gadget/1.1/default/UsbGadget.cpp @@ -0,0 +1,229 @@ +/* + * 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. + */ + +#define LOG_TAG "android.hardware.usb.gadget@1.1-service" + +#include "UsbGadget.h" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace usb { +namespace gadget { +namespace V1_1 { +namespace implementation { + +UsbGadget::UsbGadget() { + if (access(OS_DESC_PATH, R_OK) != 0) { + ALOGE("configfs setup not done yet"); + abort(); + } +} + +void currentFunctionsAppliedCallback(bool functionsApplied, void* payload) { + UsbGadget* gadget = (UsbGadget*)payload; + gadget->mCurrentUsbFunctionsApplied = functionsApplied; +} + +Return UsbGadget::getCurrentUsbFunctions(const sp& callback) { + Return ret = callback->getCurrentUsbFunctionsCb( + mCurrentUsbFunctions, mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED + : Status::FUNCTIONS_NOT_APPLIED); + if (!ret.isOk()) ALOGE("Call to getCurrentUsbFunctionsCb failed %s", ret.description().c_str()); + + return Void(); +} + +V1_0::Status UsbGadget::tearDownGadget() { + if (resetGadget() != V1_0::Status::SUCCESS) return V1_0::Status::ERROR; + + if (monitorFfs.isMonitorRunning()) { + monitorFfs.reset(); + } else { + ALOGI("mMonitor not running"); + } + return V1_0::Status::SUCCESS; +} + +Return UsbGadget::reset() { + if (!WriteStringToFile("none", PULLUP_PATH)) { + ALOGI("Gadget cannot be pulled down"); + return Status::ERROR; + } + + return Status::SUCCESS; +} + +static V1_0::Status validateAndSetVidPid(uint64_t functions) { + V1_0::Status ret = V1_0::Status::SUCCESS; + + switch (functions) { + case static_cast(V1_0::GadgetFunction::MTP): + ret = setVidPid("0x18d1", "0x4ee1"); + break; + case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::MTP: + ret = setVidPid("0x18d1", "0x4ee2"); + break; + case static_cast(V1_0::GadgetFunction::RNDIS): + ret = setVidPid("0x18d1", "0x4ee3"); + break; + case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::RNDIS: + ret = setVidPid("0x18d1", "0x4ee4"); + break; + case static_cast(V1_0::GadgetFunction::PTP): + ret = setVidPid("0x18d1", "0x4ee5"); + break; + case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::PTP: + ret = setVidPid("0x18d1", "0x4ee6"); + break; + case static_cast(V1_0::GadgetFunction::ADB): + ret = setVidPid("0x18d1", "0x4ee7"); + break; + case static_cast(V1_0::GadgetFunction::MIDI): + ret = setVidPid("0x18d1", "0x4ee8"); + break; + case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::MIDI: + ret = setVidPid("0x18d1", "0x4ee9"); + break; + case static_cast(V1_0::GadgetFunction::ACCESSORY): + ret = setVidPid("0x18d1", "0x2d00"); + break; + case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::ACCESSORY: + ret = setVidPid("0x18d1", "0x2d01"); + break; + case static_cast(V1_0::GadgetFunction::AUDIO_SOURCE): + ret = setVidPid("0x18d1", "0x2d02"); + break; + case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::AUDIO_SOURCE: + ret = setVidPid("0x18d1", "0x2d03"); + break; + case V1_0::GadgetFunction::ACCESSORY | V1_0::GadgetFunction::AUDIO_SOURCE: + ret = setVidPid("0x18d1", "0x2d04"); + break; + case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::ACCESSORY | + V1_0::GadgetFunction::AUDIO_SOURCE: + ret = setVidPid("0x18d1", "0x2d05"); + break; + default: + ALOGE("Combination not supported"); + ret = V1_0::Status::CONFIGURATION_NOT_SUPPORTED; + } + return ret; +} + +V1_0::Status UsbGadget::setupFunctions(uint64_t functions, + const sp& callback, + uint64_t timeout) { + bool ffsEnabled = false; + int i = 0; + + if (addGenericAndroidFunctions(&monitorFfs, functions, &ffsEnabled, &i) != + V1_0::Status::SUCCESS) + return V1_0::Status::ERROR; + + if ((functions & V1_0::GadgetFunction::ADB) != 0) { + ffsEnabled = true; + if (addAdb(&monitorFfs, &i) != V1_0::Status::SUCCESS) return V1_0::Status::ERROR; + } + + // Pull up the gadget right away when there are no ffs functions. + if (!ffsEnabled) { + if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) return V1_0::Status::ERROR; + mCurrentUsbFunctionsApplied = true; + if (callback) callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS); + return V1_0::Status::SUCCESS; + } + + monitorFfs.registerFunctionsAppliedCallback(¤tFunctionsAppliedCallback, this); + // Monitors the ffs paths to pull up the gadget when descriptors are written. + // Also takes of the pulling up the gadget again if the userspace process + // dies and restarts. + monitorFfs.startMonitor(); + + if (kDebug) ALOGI("Mainthread in Cv"); + + if (callback) { + bool pullup = monitorFfs.waitForPullUp(timeout); + Return ret = callback->setCurrentUsbFunctionsCb( + functions, pullup ? V1_0::Status::SUCCESS : V1_0::Status::ERROR); + if (!ret.isOk()) ALOGE("setCurrentUsbFunctionsCb error %s", ret.description().c_str()); + } + + return V1_0::Status::SUCCESS; +} + +Return UsbGadget::setCurrentUsbFunctions(uint64_t functions, + const sp& callback, + uint64_t timeout) { + std::unique_lock lk(mLockSetCurrentFunction); + + mCurrentUsbFunctions = functions; + mCurrentUsbFunctionsApplied = false; + + // Unlink the gadget and stop the monitor if running. + V1_0::Status status = tearDownGadget(); + if (status != V1_0::Status::SUCCESS) { + goto error; + } + + ALOGI("Returned from tearDown gadget"); + + // Leave the gadget pulled down to give time for the host to sense disconnect. + usleep(kDisconnectWaitUs); + + if (functions == static_cast(V1_0::GadgetFunction::NONE)) { + if (callback == NULL) return Void(); + Return ret = callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS); + if (!ret.isOk()) + ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str()); + return Void(); + } + + status = validateAndSetVidPid(functions); + + if (status != V1_0::Status::SUCCESS) { + goto error; + } + + status = setupFunctions(functions, callback, timeout); + if (status != V1_0::Status::SUCCESS) { + goto error; + } + + ALOGI("Usb Gadget setcurrent functions called successfully"); + return Void(); + +error: + ALOGI("Usb Gadget setcurrent functions failed"); + if (callback == NULL) return Void(); + Return ret = callback->setCurrentUsbFunctionsCb(functions, status); + if (!ret.isOk()) + ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str()); + return Void(); +} +} // namespace implementation +} // namespace V1_1 +} // namespace gadget +} // namespace usb +} // namespace hardware +} // namespace android diff --git a/usb/gadget/1.1/default/UsbGadget.h b/usb/gadget/1.1/default/UsbGadget.h new file mode 100644 index 0000000000..b278071336 --- /dev/null +++ b/usb/gadget/1.1/default/UsbGadget.h @@ -0,0 +1,98 @@ +/* + * 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_USB_GADGET_V1_1_USBGADGET_H +#define ANDROID_HARDWARE_USB_GADGET_V1_1_USBGADGET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace usb { +namespace gadget { +namespace V1_1 { +namespace implementation { + +using ::android::sp; +using ::android::base::GetProperty; +using ::android::base::SetProperty; +using ::android::base::unique_fd; +using ::android::base::WriteStringToFile; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::usb::gadget::addAdb; +using ::android::hardware::usb::gadget::addEpollFd; +using ::android::hardware::usb::gadget::getVendorFunctions; +using ::android::hardware::usb::gadget::kDebug; +using ::android::hardware::usb::gadget::kDisconnectWaitUs; +using ::android::hardware::usb::gadget::linkFunction; +using ::android::hardware::usb::gadget::MonitorFfs; +using ::android::hardware::usb::gadget::resetGadget; +using ::android::hardware::usb::gadget::setVidPid; +using ::android::hardware::usb::gadget::unlinkFunctions; +using ::std::string; + +constexpr char kGadgetName[] = "a600000.dwc3"; +static MonitorFfs monitorFfs(kGadgetName); + +struct UsbGadget : public IUsbGadget { + UsbGadget(); + + // Makes sure that only one request is processed at a time. + std::mutex mLockSetCurrentFunction; + uint64_t mCurrentUsbFunctions; + bool mCurrentUsbFunctionsApplied; + + Return setCurrentUsbFunctions(uint64_t functions, + const sp& callback, + uint64_t timeout) override; + + Return getCurrentUsbFunctions(const sp& callback) override; + + Return reset() override; + + private: + V1_0::Status tearDownGadget(); + V1_0::Status setupFunctions(uint64_t functions, const sp& callback, + uint64_t timeout); +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace gadget +} // namespace usb +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_USB_V1_1_USBGADGET_H diff --git a/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.rc b/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.rc new file mode 100644 index 0000000000..34ea7da699 --- /dev/null +++ b/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.rc @@ -0,0 +1,6 @@ +service vendor.usb-gadget-hal-1-1 /vendor/bin/hw/android.hardware.usb.gadget@1.1-service + interface android.hardware.usb.gadget@1.0::IUsbGadget default + interface android.hardware.usb.gadget@1.1::IUsbGadget default + class hal + user root + group root shell mtp diff --git a/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.xml b/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.xml new file mode 100644 index 0000000000..b40fa776d6 --- /dev/null +++ b/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.xml @@ -0,0 +1,12 @@ + + + android.hardware.usb.gadget + hwbinder + 1.1 + + IUsbGadget + default + + + + diff --git a/usb/gadget/1.1/default/lib/Android.bp b/usb/gadget/1.1/default/lib/Android.bp new file mode 100644 index 0000000000..bba83409cc --- /dev/null +++ b/usb/gadget/1.1/default/lib/Android.bp @@ -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. + */ + +cc_library_static { + name: "libusbconfigfs", + vendor_available: true, + export_include_dirs: ["include"], + + srcs: [ + "UsbGadgetUtils.cpp", + "MonitorFfs.cpp", + ], + + cflags: [ + "-Wall", + "-Werror", + ], + + shared_libs: [ + "android.hardware.usb.gadget@1.0", + "android.hardware.usb.gadget@1.1", + "libbase", + "libcutils", + "libhidlbase", + "libutils", + ], +} diff --git a/usb/gadget/1.1/default/lib/MonitorFfs.cpp b/usb/gadget/1.1/default/lib/MonitorFfs.cpp new file mode 100644 index 0000000000..0cdf038de1 --- /dev/null +++ b/usb/gadget/1.1/default/lib/MonitorFfs.cpp @@ -0,0 +1,269 @@ +/* + * 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. + */ + +#define LOG_TAG "libusbconfigfs" + +#include "include/UsbGadgetCommon.h" + +namespace android { +namespace hardware { +namespace usb { +namespace gadget { + +static volatile bool gadgetPullup; + +MonitorFfs::MonitorFfs(const char* const gadget) + : mWatchFd(), + mEndpointList(), + mLock(), + mCv(), + mLockFd(), + mCurrentUsbFunctionsApplied(false), + mMonitor(), + mCallback(NULL), + mPayload(NULL), + mGadgetName(gadget), + mMonitorRunning(false) { + unique_fd eventFd(eventfd(0, 0)); + if (eventFd == -1) { + ALOGE("mEventFd failed to create %d", errno); + abort(); + } + + unique_fd epollFd(epoll_create(2)); + if (epollFd == -1) { + ALOGE("mEpollFd failed to create %d", errno); + abort(); + } + + unique_fd inotifyFd(inotify_init()); + if (inotifyFd < 0) { + ALOGE("inotify init failed"); + abort(); + } + + if (addEpollFd(epollFd, inotifyFd) == -1) abort(); + + if (addEpollFd(epollFd, eventFd) == -1) abort(); + + mEpollFd = move(epollFd); + mInotifyFd = move(inotifyFd); + mEventFd = move(eventFd); + gadgetPullup = false; +} + +static void displayInotifyEvent(struct inotify_event* i) { + ALOGE(" wd =%2d; ", i->wd); + if (i->cookie > 0) ALOGE("cookie =%4d; ", i->cookie); + + ALOGE("mask = "); + if (i->mask & IN_ACCESS) ALOGE("IN_ACCESS "); + if (i->mask & IN_ATTRIB) ALOGE("IN_ATTRIB "); + if (i->mask & IN_CLOSE_NOWRITE) ALOGE("IN_CLOSE_NOWRITE "); + if (i->mask & IN_CLOSE_WRITE) ALOGE("IN_CLOSE_WRITE "); + if (i->mask & IN_CREATE) ALOGE("IN_CREATE "); + if (i->mask & IN_DELETE) ALOGE("IN_DELETE "); + if (i->mask & IN_DELETE_SELF) ALOGE("IN_DELETE_SELF "); + if (i->mask & IN_IGNORED) ALOGE("IN_IGNORED "); + if (i->mask & IN_ISDIR) ALOGE("IN_ISDIR "); + if (i->mask & IN_MODIFY) ALOGE("IN_MODIFY "); + if (i->mask & IN_MOVE_SELF) ALOGE("IN_MOVE_SELF "); + if (i->mask & IN_MOVED_FROM) ALOGE("IN_MOVED_FROM "); + if (i->mask & IN_MOVED_TO) ALOGE("IN_MOVED_TO "); + if (i->mask & IN_OPEN) ALOGE("IN_OPEN "); + if (i->mask & IN_Q_OVERFLOW) ALOGE("IN_Q_OVERFLOW "); + if (i->mask & IN_UNMOUNT) ALOGE("IN_UNMOUNT "); + ALOGE("\n"); + + if (i->len > 0) ALOGE(" name = %s\n", i->name); +} + +void* MonitorFfs::startMonitorFd(void* param) { + MonitorFfs* monitorFfs = (MonitorFfs*)param; + char buf[kBufferSize]; + bool writeUdc = true, stopMonitor = false; + struct epoll_event events[kEpollEvents]; + steady_clock::time_point disconnect; + + bool descriptorWritten = true; + for (int i = 0; i < static_cast(monitorFfs->mEndpointList.size()); i++) { + if (access(monitorFfs->mEndpointList.at(i).c_str(), R_OK)) { + descriptorWritten = false; + break; + } + } + + // notify here if the endpoints are already present. + if (descriptorWritten) { + usleep(kPullUpDelay); + if (!!WriteStringToFile(monitorFfs->mGadgetName, PULLUP_PATH)) { + lock_guard lock(monitorFfs->mLock); + monitorFfs->mCurrentUsbFunctionsApplied = true; + monitorFfs->mCallback(monitorFfs->mCurrentUsbFunctionsApplied, monitorFfs->mPayload); + gadgetPullup = true; + writeUdc = false; + ALOGI("GADGET pulled up"); + monitorFfs->mCv.notify_all(); + } + } + + while (!stopMonitor) { + int nrEvents = epoll_wait(monitorFfs->mEpollFd, events, kEpollEvents, -1); + + if (nrEvents <= 0) { + ALOGE("epoll wait did not return descriptor number"); + continue; + } + + for (int i = 0; i < nrEvents; i++) { + ALOGI("event=%u on fd=%d\n", events[i].events, events[i].data.fd); + + if (events[i].data.fd == monitorFfs->mInotifyFd) { + // Process all of the events in buffer returned by read(). + int numRead = read(monitorFfs->mInotifyFd, buf, kBufferSize); + for (char* p = buf; p < buf + numRead;) { + struct inotify_event* event = (struct inotify_event*)p; + if (kDebug) displayInotifyEvent(event); + + p += sizeof(struct inotify_event) + event->len; + + bool descriptorPresent = true; + for (int j = 0; j < static_cast(monitorFfs->mEndpointList.size()); j++) { + if (access(monitorFfs->mEndpointList.at(j).c_str(), R_OK)) { + if (kDebug) ALOGI("%s absent", monitorFfs->mEndpointList.at(j).c_str()); + descriptorPresent = false; + break; + } + } + + if (!descriptorPresent && !writeUdc) { + if (kDebug) ALOGI("endpoints not up"); + writeUdc = true; + disconnect = std::chrono::steady_clock::now(); + } else if (descriptorPresent && writeUdc) { + steady_clock::time_point temp = steady_clock::now(); + + if (std::chrono::duration_cast(temp - disconnect).count() < + kPullUpDelay) + usleep(kPullUpDelay); + + if (!!WriteStringToFile(monitorFfs->mGadgetName, PULLUP_PATH)) { + lock_guard lock(monitorFfs->mLock); + monitorFfs->mCurrentUsbFunctionsApplied = true; + monitorFfs->mCallback(monitorFfs->mCurrentUsbFunctionsApplied, + monitorFfs->mPayload); + ALOGI("GADGET pulled up"); + writeUdc = false; + gadgetPullup = true; + // notify the main thread to signal userspace. + monitorFfs->mCv.notify_all(); + } + } + } + } else { + uint64_t flag; + read(monitorFfs->mEventFd, &flag, sizeof(flag)); + if (flag == 100) { + stopMonitor = true; + break; + } + } + } + } + return NULL; +} + +void MonitorFfs::reset() { + lock_guard lock(mLockFd); + uint64_t flag = 100; + unsigned long ret; + + if (mMonitorRunning) { + // Stop the monitor thread by writing into signal fd. + ret = TEMP_FAILURE_RETRY(write(mEventFd, &flag, sizeof(flag))); + if (ret < 0) ALOGE("Error writing eventfd errno=%d", errno); + + ALOGI("mMonitor signalled to exit"); + mMonitor->join(); + ALOGI("mMonitor destroyed"); + mMonitorRunning = false; + } + + for (std::vector::size_type i = 0; i != mWatchFd.size(); i++) + inotify_rm_watch(mInotifyFd, mWatchFd[i]); + + mEndpointList.clear(); + gadgetPullup = false; + mCallback = NULL; + mPayload = NULL; +} + +bool MonitorFfs::startMonitor() { + mMonitor = unique_ptr(new thread(this->startMonitorFd, this)); + mMonitorRunning = true; + return true; +} + +bool MonitorFfs::isMonitorRunning() { + return mMonitorRunning; +} + +bool MonitorFfs::waitForPullUp(int timeout_ms) { + std::unique_lock lk(mLock); + + if (gadgetPullup) return true; + + if (mCv.wait_for(lk, timeout_ms * 1ms, [] { return gadgetPullup; })) { + ALOGI("monitorFfs signalled true"); + return true; + } else { + ALOGI("monitorFfs signalled error"); + // continue monitoring as the descriptors might be written at a later + // point. + return false; + } +} + +bool MonitorFfs::addInotifyFd(string fd) { + lock_guard lock(mLockFd); + int wfd; + + wfd = inotify_add_watch(mInotifyFd, fd.c_str(), IN_ALL_EVENTS); + if (wfd == -1) + return false; + else + mWatchFd.push_back(wfd); + + return true; +} + +void MonitorFfs::addEndPoint(string ep) { + lock_guard lock(mLockFd); + + mEndpointList.push_back(ep); +} + +void MonitorFfs::registerFunctionsAppliedCallback(void (*callback)(bool functionsApplied, + void* payload), + void* payload) { + mCallback = callback; + mPayload = payload; +} + +} // namespace gadget +} // namespace usb +} // namespace hardware +} // namespace android diff --git a/usb/gadget/1.1/default/lib/UsbGadgetUtils.cpp b/usb/gadget/1.1/default/lib/UsbGadgetUtils.cpp new file mode 100644 index 0000000000..8402853b99 --- /dev/null +++ b/usb/gadget/1.1/default/lib/UsbGadgetUtils.cpp @@ -0,0 +1,193 @@ +/* + * 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. + */ + +#define LOG_TAG "libusbconfigfs" + +#include "include/UsbGadgetCommon.h" + +namespace android { +namespace hardware { +namespace usb { +namespace gadget { + +int unlinkFunctions(const char* path) { + DIR* config = opendir(path); + struct dirent* function; + char filepath[kMaxFilePathLength]; + int ret = 0; + + if (config == NULL) return -1; + + // d_type does not seems to be supported in /config + // so filtering by name. + while (((function = readdir(config)) != NULL)) { + if ((strstr(function->d_name, FUNCTION_NAME) == NULL)) continue; + // build the path for each file in the folder. + sprintf(filepath, "%s/%s", path, function->d_name); + ret = remove(filepath); + if (ret) { + ALOGE("Unable remove file %s errno:%d", filepath, errno); + break; + } + } + + closedir(config); + return ret; +} + +int addEpollFd(const unique_fd& epfd, const unique_fd& fd) { + struct epoll_event event; + int ret; + + event.data.fd = fd; + event.events = EPOLLIN; + + ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event); + if (ret) ALOGE("epoll_ctl error %d", errno); + + return ret; +} + +int linkFunction(const char* function, int index) { + char functionPath[kMaxFilePathLength]; + char link[kMaxFilePathLength]; + + sprintf(functionPath, "%s%s", FUNCTIONS_PATH, function); + sprintf(link, "%s%d", FUNCTION_PATH, index); + if (symlink(functionPath, link)) { + ALOGE("Cannot create symlink %s -> %s errno:%d", link, functionPath, errno); + return -1; + } + return 0; +} + +Status setVidPid(const char* vid, const char* pid) { + if (!WriteStringToFile(vid, VENDOR_ID_PATH)) return Status::ERROR; + + if (!WriteStringToFile(pid, PRODUCT_ID_PATH)) return Status::ERROR; + + return Status::SUCCESS; +} + +std::string getVendorFunctions() { + if (GetProperty(kBuildType, "") == "user") return "user"; + + std::string bootMode = GetProperty(PERSISTENT_BOOT_MODE, ""); + std::string persistVendorFunctions = GetProperty(kPersistentVendorConfig, ""); + std::string vendorFunctions = GetProperty(kVendorConfig, ""); + std::string ret = ""; + + if (vendorFunctions != "") { + ret = vendorFunctions; + } else if (bootMode == "usbradio" || bootMode == "factory" || bootMode == "ffbm-00" || + bootMode == "ffbm-01") { + if (persistVendorFunctions != "") + ret = persistVendorFunctions; + else + ret = "diag"; + // vendor.usb.config will reflect the current configured functions + SetProperty(kVendorConfig, ret); + } + + return ret; +} + +Status resetGadget() { + ALOGI("setCurrentUsbFunctions None"); + + if (!WriteStringToFile("none", PULLUP_PATH)) ALOGI("Gadget cannot be pulled down"); + + if (!WriteStringToFile("0", DEVICE_CLASS_PATH)) return Status::ERROR; + + if (!WriteStringToFile("0", DEVICE_SUB_CLASS_PATH)) return Status::ERROR; + + if (!WriteStringToFile("0", DEVICE_PROTOCOL_PATH)) return Status::ERROR; + + if (!WriteStringToFile("0", DESC_USE_PATH)) return Status::ERROR; + + if (unlinkFunctions(CONFIG_PATH)) return Status::ERROR; + + return Status::SUCCESS; +} + +Status addGenericAndroidFunctions(MonitorFfs* monitorFfs, uint64_t functions, bool* ffsEnabled, + int* functionCount) { + if (((functions & GadgetFunction::MTP) != 0)) { + *ffsEnabled = true; + ALOGI("setCurrentUsbFunctions mtp"); + if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR; + + if (!monitorFfs->addInotifyFd("/dev/usb-ffs/mtp/")) return Status::ERROR; + + if (linkFunction("ffs.mtp", (*functionCount)++)) return Status::ERROR; + + // Add endpoints to be monitored. + monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep1"); + monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep2"); + monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep3"); + } else if (((functions & GadgetFunction::PTP) != 0)) { + *ffsEnabled = true; + ALOGI("setCurrentUsbFunctions ptp"); + if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR; + + if (!monitorFfs->addInotifyFd("/dev/usb-ffs/ptp/")) return Status::ERROR; + + if (linkFunction("ffs.ptp", (*functionCount)++)) return Status::ERROR; + + // Add endpoints to be monitored. + monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep1"); + monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep2"); + monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep3"); + } + + if ((functions & GadgetFunction::MIDI) != 0) { + ALOGI("setCurrentUsbFunctions MIDI"); + if (linkFunction("midi.gs5", (*functionCount)++)) return Status::ERROR; + } + + if ((functions & GadgetFunction::ACCESSORY) != 0) { + ALOGI("setCurrentUsbFunctions Accessory"); + if (linkFunction("accessory.gs2", (*functionCount)++)) return Status::ERROR; + } + + if ((functions & GadgetFunction::AUDIO_SOURCE) != 0) { + ALOGI("setCurrentUsbFunctions Audio Source"); + if (linkFunction("audio_source.gs3", (*functionCount)++)) return Status::ERROR; + } + + if ((functions & GadgetFunction::RNDIS) != 0) { + ALOGI("setCurrentUsbFunctions rndis"); + if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR; + } + + return Status::SUCCESS; +} + +Status addAdb(MonitorFfs* monitorFfs, int* functionCount) { + ALOGI("setCurrentUsbFunctions Adb"); + if (!monitorFfs->addInotifyFd("/dev/usb-ffs/adb/")) return Status::ERROR; + + if (linkFunction("ffs.adb", (*functionCount)++)) return Status::ERROR; + monitorFfs->addEndPoint("/dev/usb-ffs/adb/ep1"); + monitorFfs->addEndPoint("/dev/usb-ffs/adb/ep2"); + ALOGI("Service started"); + return Status::SUCCESS; +} + +} // namespace gadget +} // namespace usb +} // namespace hardware +} // namespace android diff --git a/usb/gadget/1.1/default/lib/include/UsbGadgetCommon.h b/usb/gadget/1.1/default/lib/include/UsbGadgetCommon.h new file mode 100644 index 0000000000..b30f18e4e1 --- /dev/null +++ b/usb/gadget/1.1/default/lib/include/UsbGadgetCommon.h @@ -0,0 +1,177 @@ +/* + * 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 HARDWARE_USB_USBGADGETCOMMON_H +#define HARDWARE_USB_USBGADGETCOMMON_H + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace usb { +namespace gadget { + +constexpr int kBufferSize = 512; +constexpr int kMaxFilePathLength = 256; +constexpr int kEpollEvents = 10; +constexpr bool kDebug = false; +constexpr int kDisconnectWaitUs = 100000; +constexpr int kPullUpDelay = 500000; +constexpr int kShutdownMonitor = 100; + +constexpr char kBuildType[] = "ro.build.type"; +constexpr char kPersistentVendorConfig[] = "persist.vendor.usb.usbradio.config"; +constexpr char kVendorConfig[] = "vendor.usb.config"; + +#define GADGET_PATH "/config/usb_gadget/g1/" +#define PULLUP_PATH GADGET_PATH "UDC" +#define PERSISTENT_BOOT_MODE "ro.bootmode" +#define VENDOR_ID_PATH GADGET_PATH "idVendor" +#define PRODUCT_ID_PATH GADGET_PATH "idProduct" +#define DEVICE_CLASS_PATH GADGET_PATH "bDeviceClass" +#define DEVICE_SUB_CLASS_PATH GADGET_PATH "bDeviceSubClass" +#define DEVICE_PROTOCOL_PATH GADGET_PATH "bDeviceProtocol" +#define DESC_USE_PATH GADGET_PATH "os_desc/use" +#define OS_DESC_PATH GADGET_PATH "os_desc/b.1" +#define CONFIG_PATH GADGET_PATH "configs/b.1/" +#define FUNCTIONS_PATH GADGET_PATH "functions/" +#define FUNCTION_NAME "function" +#define FUNCTION_PATH CONFIG_PATH FUNCTION_NAME +#define RNDIS_PATH FUNCTIONS_PATH "gsi.rndis" + +using ::android::base::GetProperty; +using ::android::base::SetProperty; +using ::android::base::unique_fd; +using ::android::base::WriteStringToFile; +using ::android::hardware::usb::gadget::V1_0::GadgetFunction; +using ::android::hardware::usb::gadget::V1_0::Status; + +using ::std::lock_guard; +using ::std::move; +using ::std::mutex; +using ::std::string; +using ::std::thread; +using ::std::unique_ptr; +using ::std::vector; +using ::std::chrono::microseconds; +using ::std::chrono::steady_clock; +using ::std::literals::chrono_literals::operator""ms; + +// MonitorFfs automously manages gadget pullup by monitoring +// the ep file status. Restarts the usb gadget when the ep +// owner restarts. +class MonitorFfs { + private: + // Monitors the endpoints Inotify events. + unique_fd mInotifyFd; + // Control pipe for shutting down the mMonitor thread. + // mMonitor exits when SHUTDOWN_MONITOR is written into + // mEventFd/ + unique_fd mEventFd; + // Pools on mInotifyFd and mEventFd. + unique_fd mEpollFd; + vector mWatchFd; + + // Maintains the list of Endpoints. + vector mEndpointList; + // protects the CV. + std::mutex mLock; + std::condition_variable mCv; + // protects mInotifyFd, mEpollFd. + std::mutex mLockFd; + + // Flag to maintain the current status of gadget pullup. + bool mCurrentUsbFunctionsApplied; + + // Thread object that executes the ep monitoring logic. + unique_ptr mMonitor; + // Callback to be invoked when gadget is pulled up. + void (*mCallback)(bool functionsApplied, void* payload); + void* mPayload; + // Name of the USB gadget. Used for pullup. + const char* const mGadgetName; + // Monitor State + bool mMonitorRunning; + + public: + MonitorFfs(const char* const gadget); + // Inits all the UniqueFds. + void reset(); + // Starts monitoring endpoints and pullup the gadget when + // the descriptors are written. + bool startMonitor(); + // Waits for timeout_ms for gadget pull up to happen. + // Returns immediately if the gadget is already pulled up. + bool waitForPullUp(int timeout_ms); + // Adds the given fd to the watch list. + bool addInotifyFd(string fd); + // Adds the given endpoint to the watch list. + void addEndPoint(string ep); + // Registers the async callback from the caller to notify the caller + // when the gadget pull up happens. + void registerFunctionsAppliedCallback(void (*callback)(bool functionsApplied, void*(payload)), + void* payload); + bool isMonitorRunning(); + // Ep monitoring and the gadget pull up logic. + static void* startMonitorFd(void* param); +}; + +//**************** Helper functions ************************// + +// Adds the given fd to the epollfd(epfd). +int addEpollFd(const unique_fd& epfd, const unique_fd& fd); +// Removes all the usb functions link in the specified path. +int unlinkFunctions(const char* path); +// Craetes a configfs link for the function. +int linkFunction(const char* function, int index); +// Sets the USB VID and PID. +Status setVidPid(const char* vid, const char* pid); +// Extracts vendor functions from the vendor init properties. +std::string getVendorFunctions(); +// Adds Adb to the usb configuration. +Status addAdb(MonitorFfs* monitorFfs, int* functionCount); +// Adds all applicable generic android usb functions other than ADB. +Status addGenericAndroidFunctions(MonitorFfs* monitorFfs, uint64_t functions, bool* ffsEnabled, + int* functionCount); +// Pulls down USB gadget. +Status resetGadget(); + +} // namespace gadget +} // namespace usb +} // namespace hardware +} // namespace android +#endif diff --git a/usb/gadget/1.1/default/service.cpp b/usb/gadget/1.1/default/service.cpp new file mode 100644 index 0000000000..7414e89052 --- /dev/null +++ b/usb/gadget/1.1/default/service.cpp @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#define LOG_TAG "android.hardware.usb.gadget@1.1-service" + +#include +#include "UsbGadget.h" + +using android::sp; + +// libhwbinder: +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; + +// Generated HIDL files +using android::hardware::usb::gadget::V1_1::IUsbGadget; +using android::hardware::usb::gadget::V1_1::implementation::UsbGadget; + +using android::OK; +using android::status_t; + +int main() { + configureRpcThreadpool(1, true /*callerWillJoin*/); + + android::sp service2 = new UsbGadget(); + + status_t status = service2->registerAsService(); + + if (status != OK) { + ALOGE("Cannot register USB Gadget HAL service"); + return 1; + } + + ALOGI("USB Gadget HAL Ready."); + joinRpcThreadpool(); + // Under noraml cases, execution will not reach this line. + ALOGI("USB Gadget HAL failed to join thread pool."); + return 1; +} From 2adf7fb2d5e0c27962dc65f6a743dd21b84aeca0 Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Tue, 26 Nov 2019 09:00:08 -0700 Subject: [PATCH 0446/1022] Remove dependency on libsoftkeymaster. This is part of a refactor to facilitate reuse in Keymaster 4.1 VTS tests. Bug: 140193672 Bug: 140192237 Test: VtsHalKeymasterV4_0TargetTest Change-Id: I9310a851648c028850f9795d303419c6a7e29a11 --- .../include/keymasterV4_0/keymaster_utils.h | 3 + keymaster/4.0/support/keymaster_utils.cpp | 116 +++++++++++++++--- keymaster/4.0/vts/functional/Android.bp | 6 +- .../4.0/vts/functional/KeymasterHidlTest.cpp | 7 +- .../4.0/vts/functional/KeymasterHidlTest.h | 6 +- 5 files changed, 114 insertions(+), 24 deletions(-) diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h index 5e5ae8d0ed..61645f853e 100644 --- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h +++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h @@ -52,6 +52,9 @@ inline static hidl_vec blob2hidlVec(const std::vector& blob) { HardwareAuthToken hidlVec2AuthToken(const hidl_vec& buffer); hidl_vec authToken2HidlVec(const HardwareAuthToken& token); +uint32_t getOsVersion(); +uint32_t getOsPatchlevel(); + } // namespace support } // namespace V4_0 } // namespace keymaster diff --git a/keymaster/4.0/support/keymaster_utils.cpp b/keymaster/4.0/support/keymaster_utils.cpp index e35fdd36d5..850a7767bf 100644 --- a/keymaster/4.0/support/keymaster_utils.cpp +++ b/keymaster/4.0/support/keymaster_utils.cpp @@ -14,11 +14,13 @@ * limitations under the License. */ +#include + +#include #include #include -namespace android { -namespace hardware { +namespace android::hardware { inline static bool operator<(const hidl_vec& a, const hidl_vec& b) { auto result = memcmp(a.data(), b.data(), std::min(a.size(), b.size())); @@ -32,8 +34,7 @@ inline static bool operator<(const hidl_array& a, return memcmp(a.data(), b.data(), SIZE) == -1; } -namespace keymaster { -namespace V4_0 { +namespace keymaster::V4_0 { bool operator<(const HmacSharingParameters& a, const HmacSharingParameters& b) { return std::tie(a.seed, a.nonce) < std::tie(b.seed, b.nonce); @@ -58,9 +59,9 @@ constexpr size_t kHmacSize = 32; hidl_vec authToken2HidlVec(const HardwareAuthToken& token) { static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) + - sizeof(token.authenticatorId) + sizeof(token.authenticatorType) + - sizeof(token.timestamp) + kHmacSize == - sizeof(hw_auth_token_t), + sizeof(token.authenticatorId) + sizeof(token.authenticatorType) + + sizeof(token.timestamp) + kHmacSize == + sizeof(hw_auth_token_t), "HardwareAuthToken content size does not match hw_auth_token_t size"); hidl_vec result; @@ -86,9 +87,9 @@ hidl_vec authToken2HidlVec(const HardwareAuthToken& token) { HardwareAuthToken hidlVec2AuthToken(const hidl_vec& buffer) { HardwareAuthToken token; static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) + - sizeof(token.authenticatorId) + sizeof(token.authenticatorType) + - sizeof(token.timestamp) + kHmacSize == - sizeof(hw_auth_token_t), + sizeof(token.authenticatorId) + sizeof(token.authenticatorType) + + sizeof(token.timestamp) + kHmacSize == + sizeof(hw_auth_token_t), "HardwareAuthToken content size does not match hw_auth_token_t size"); if (buffer.size() != sizeof(hw_auth_token_t)) return {}; @@ -100,7 +101,7 @@ HardwareAuthToken hidlVec2AuthToken(const hidl_vec& buffer) { pos = copy_bytes_from_iterator(&token.authenticatorId, pos); pos = copy_bytes_from_iterator(&token.authenticatorType, pos); token.authenticatorType = static_cast( - ntohl(static_cast(token.authenticatorType))); + ntohl(static_cast(token.authenticatorType))); pos = copy_bytes_from_iterator(&token.timestamp, pos); token.timestamp = ntohq(token.timestamp); token.mac.resize(kHmacSize); @@ -109,8 +110,93 @@ HardwareAuthToken hidlVec2AuthToken(const hidl_vec& buffer) { return token; } +namespace { + +constexpr char kPlatformVersionProp[] = "ro.build.version.release"; +constexpr char kPlatformVersionRegex[] = "^([0-9]{1,2})(\\.([0-9]{1,2}))?(\\.([0-9]{1,2}))?"; +constexpr size_t kMajorVersionMatch = 1; +constexpr size_t kMinorVersionMatch = 3; +constexpr size_t kSubminorVersionMatch = 5; +constexpr size_t kPlatformVersionMatchCount = kSubminorVersionMatch + 1; + +constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch"; +constexpr char kPlatformPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-[0-9]{2}$"; +constexpr size_t kYearMatch = 1; +constexpr size_t kMonthMatch = 2; +constexpr size_t kPlatformPatchlevelMatchCount = kMonthMatch + 1; + +uint32_t match_to_uint32(const char* expression, const regmatch_t& match) { + if (match.rm_so == -1) return 0; + + size_t len = match.rm_eo - match.rm_so; + std::string s(expression + match.rm_so, len); + return std::stoul(s); +} + +std::string wait_and_get_property(const char* prop) { + std::string prop_value; + while (!android::base::WaitForPropertyCreation(prop)) + ; + prop_value = android::base::GetProperty(prop, "" /* default */); + return prop_value; +} + +} // anonymous namespace + +uint32_t getOsVersion(const char* version_str) { + regex_t regex; + if (regcomp(®ex, kPlatformVersionRegex, REG_EXTENDED)) { + return 0; + } + + regmatch_t matches[kPlatformVersionMatchCount]; + int not_match = + regexec(®ex, version_str, kPlatformVersionMatchCount, matches, 0 /* flags */); + regfree(®ex); + if (not_match) { + return 0; + } + + uint32_t major = match_to_uint32(version_str, matches[kMajorVersionMatch]); + uint32_t minor = match_to_uint32(version_str, matches[kMinorVersionMatch]); + uint32_t subminor = match_to_uint32(version_str, matches[kSubminorVersionMatch]); + + return (major * 100 + minor) * 100 + subminor; +} + +uint32_t getOsVersion() { + std::string version = wait_and_get_property(kPlatformVersionProp); + return getOsVersion(version.c_str()); +} + +uint32_t getOsPatchlevel(const char* patchlevel_str) { + regex_t regex; + if (regcomp(®ex, kPlatformPatchlevelRegex, REG_EXTENDED) != 0) { + return 0; + } + + regmatch_t matches[kPlatformPatchlevelMatchCount]; + int not_match = + regexec(®ex, patchlevel_str, kPlatformPatchlevelMatchCount, matches, 0 /* flags */); + regfree(®ex); + if (not_match) { + return 0; + } + + uint32_t year = match_to_uint32(patchlevel_str, matches[kYearMatch]); + uint32_t month = match_to_uint32(patchlevel_str, matches[kMonthMatch]); + + if (month < 1 || month > 12) { + return 0; + } + return year * 100 + month; +} + +uint32_t getOsPatchlevel() { + std::string patchlevel = wait_and_get_property(kPlatformPatchlevelProp); + return getOsPatchlevel(patchlevel.c_str()); +} + } // namespace support -} // namespace V4_0 -} // namespace keymaster -} // namespace hardware -} // namespace android +} // namespace keymaster::V4_0 +} // namespace android::hardware diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp index 5649f20f86..7244ae3c96 100644 --- a/keymaster/4.0/vts/functional/Android.bp +++ b/keymaster/4.0/vts/functional/Android.bp @@ -27,7 +27,9 @@ cc_test { "android.hardware.keymaster@4.0", "libcrypto_static", "libkeymaster4support", - "libsoftkeymasterdevice", ], - test_suites: ["general-tests", "vts-core"], + test_suites: [ + "general-tests", + "vts-core", + ], } diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp index 7241984694..1fbd721e24 100644 --- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp +++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp @@ -23,6 +23,7 @@ #include #include +#include namespace android { namespace hardware { @@ -56,11 +57,11 @@ void KeymasterHidlTest::InitializeKeymaster() { .isOk()); } -void KeymasterHidlTest::SetUp() { +void KeymasterHidlTest::SetUpTestCase() { InitializeKeymaster(); - os_version_ = ::keymaster::GetOsVersion(); - os_patch_level_ = ::keymaster::GetOsPatchlevel(); + os_version_ = support::getOsVersion(); + os_patch_level_ = support::getOsPatchlevel(); auto service_manager = android::hidl::manager::V1_0::IServiceManager::getService(); ASSERT_NE(nullptr, service_manager.get()); diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h index 4bd8b26db9..f7d6da2ca0 100644 --- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h +++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h @@ -18,10 +18,8 @@ #include #include -#include -#include -#include -#include + +#include #include From afa8636ce267da3b26ed866720c9f21a7f881865 Mon Sep 17 00:00:00 2001 From: "Harpreet \\\"Eli\\\" Sangha" Date: Tue, 21 Jan 2020 16:15:42 +0900 Subject: [PATCH 0447/1022] vibrator: Compose API Related Improvements - Allow querying duration of each primitive. - Allow querying of supported primitives. - Enforce all-of-nothing requirement for supported primitives via VTS. - Enforce callback support requirement via VTS. Bug: 139762802 Bug: 147852209 Test: atest VtsHalVibratorTargetTest Change-Id: I9009e38d446ed9ea38b3a9d6eb8dd55e6be2792f Signed-off-by: Harpreet \"Eli\" Sangha --- .../android/hardware/vibrator/IVibrator.aidl | 21 ++++++++- vibrator/aidl/default/Vibrator.cpp | 20 ++++++++ .../default/include/vibrator-impl/Vibrator.h | 3 ++ .../aidl/vts/VtsHalVibratorTargetTest.cpp | 47 +++++++++++++++++++ 4 files changed, 90 insertions(+), 1 deletion(-) diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl index f553664eeb..06a8bf5c17 100644 --- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl +++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl @@ -157,13 +157,32 @@ interface IVibrator { */ int getCompositionSizeMax(); + /** + * List of supported effect primitive. + * + * Return the effect primitives which are supported by the compose API. + * Implementations are expected to support all primitives of the interface + * version that they implement. + */ + CompositePrimitive[] getSupportedPrimitives(); + + /** + * Retrieve effect primitive's duration in milliseconds. + * + * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS). + * + * @return Best effort estimation of effect primitive's duration. + * @param primitive Effect primitive being queried. + */ + int getPrimitiveDuration(CompositePrimitive primitive); + /** * Fire off a string of effect primitives, combined to perform richer effects. * * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS). * * Doing this operation while the vibrator is already on is undefined behavior. Clients should - * explicitly call off. + * explicitly call off. IVibratorCallback.onComplete() support is required for this API. * * @param composite Array of composition parameters. */ diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp index cedd9cb89c..d6ce8a1c43 100644 --- a/vibrator/aidl/default/Vibrator.cpp +++ b/vibrator/aidl/default/Vibrator.cpp @@ -113,6 +113,26 @@ ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* maxSize) { return ndk::ScopedAStatus::ok(); } +ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector* supported) { + *supported = { + CompositePrimitive::NOOP, CompositePrimitive::CLICK, + CompositePrimitive::THUD, CompositePrimitive::SPIN, + CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE, + CompositePrimitive::QUICK_FALL, + }; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive, + int32_t* durationMs) { + if (primitive != CompositePrimitive::NOOP) { + *durationMs = 100; + } else { + *durationMs = 0; + } + return ndk::ScopedAStatus::ok(); +} + ndk::ScopedAStatus Vibrator::compose(const std::vector& composite, const std::shared_ptr& callback) { if (composite.size() > kComposeSizeMax) { diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h index 0eb957d9fa..c3f3616876 100644 --- a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h +++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h @@ -36,6 +36,9 @@ class Vibrator : public BnVibrator { ndk::ScopedAStatus setExternalControl(bool enabled) override; ndk::ScopedAStatus getCompositionDelayMax(int32_t* maxDelayMs); ndk::ScopedAStatus getCompositionSizeMax(int32_t* maxSize); + ndk::ScopedAStatus getSupportedPrimitives(std::vector* supported) override; + ndk::ScopedAStatus getPrimitiveDuration(CompositePrimitive primitive, + int32_t* durationMs) override; ndk::ScopedAStatus compose(const std::vector& composite, const std::shared_ptr& callback) override; ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector* _aidl_return) override; diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp index f197763be3..411fe7a2fe 100644 --- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp +++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp @@ -261,6 +261,29 @@ TEST_P(VibratorAidl, ExternalControlUnsupportedMatchingCapabilities) { } } +TEST_P(VibratorAidl, GetSupportedPrimitives) { + if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { + std::vector supported; + + EXPECT_EQ(Status::EX_NONE, vibrator->getSupportedPrimitives(&supported).exceptionCode()); + + std::sort(supported.begin(), supported.end()); + + EXPECT_EQ(kCompositePrimitives, supported); + } +} + +TEST_P(VibratorAidl, GetPrimitiveDuration) { + if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { + int32_t duration; + + for (auto primitive : kCompositePrimitives) { + EXPECT_EQ(Status::EX_NONE, + vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode()); + } + } +} + TEST_P(VibratorAidl, ComposeValidPrimitives) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { int32_t maxDelay, maxSize; @@ -357,6 +380,30 @@ TEST_P(VibratorAidl, CompseSizeBoundary) { } } +TEST_P(VibratorAidl, ComposeCallback) { + if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { + std::promise completionPromise; + std::future completionFuture{completionPromise.get_future()}; + sp callback = + new CompletionCallback([&completionPromise] { completionPromise.set_value(); }); + CompositePrimitive primitive = CompositePrimitive::CLICK; + CompositeEffect effect; + std::vector composite; + int32_t duration; + + effect.delayMs = 0; + effect.primitive = primitive; + effect.scale = 1.0f; + composite.emplace_back(effect); + + EXPECT_EQ(Status::EX_NONE, + vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode()); + EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, callback).exceptionCode()); + EXPECT_EQ(completionFuture.wait_for(std::chrono::milliseconds(duration * 2)), + std::future_status::ready); + } +} + TEST_P(VibratorAidl, AlwaysOn) { if (capabilities & IVibrator::CAP_ALWAYS_ON_CONTROL) { std::vector supported; From 5e1347cedfd3e3c553459263c194d3468860c31b Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Tue, 26 Nov 2019 15:05:51 -0700 Subject: [PATCH 0448/1022] Update Keymaster 4.0 VTS to use parameterized tests. Bug: 139437880 Test: VtsHalKeyamsterV4_0TargetTest Change-Id: I487000cc19fe355fdef88f1561a38b2cbfd3c3c3 --- .../4.0/vts/functional/HmacKeySharingTest.cpp | 70 +++++++++++-------- .../4.0/vts/functional/KeymasterHidlTest.cpp | 34 +++------ .../4.0/vts/functional/KeymasterHidlTest.h | 37 +++++----- .../vts/functional/VerificationTokenTest.cpp | 5 +- .../functional/keymaster_hidl_hal_test.cpp | 65 +++++++---------- .../4.1/vts/functional/EarlyBootKeyTest.cpp | 2 +- 6 files changed, 101 insertions(+), 112 deletions(-) diff --git a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp index c228ef709d..f57a6682f9 100644 --- a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp +++ b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp @@ -28,6 +28,16 @@ namespace test { */ class HmacKeySharingTest : public KeymasterHidlTest { protected: + const std::vector>& allKeymasters() { + if (all_keymasters_.empty()) { + auto names = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor); + for (const auto& name : names) { + all_keymasters_.push_back(IKeymasterDevice::getService(name)); + } + } + return all_keymasters_; + } + struct GetParamsResult { ErrorCode error; HmacSharingParameters params; @@ -99,8 +109,13 @@ class HmacKeySharingTest : public KeymasterHidlTest { EXPECT_EQ(expected, response.sharing_check) << "Sharing check values should match."; } } + + private: + static std::vector> all_keymasters_; }; +std::vector> HmacKeySharingTest::all_keymasters_; + TEST_P(HmacKeySharingTest, GetParameters) { auto result1 = getHmacSharingParameters(keymaster()); EXPECT_EQ(ErrorCode::OK, result1.error); @@ -115,26 +130,26 @@ TEST_P(HmacKeySharingTest, GetParameters) { } TEST_P(HmacKeySharingTest, ComputeSharedHmac) { - auto params = getHmacSharingParameters(all_keymasters()); - ASSERT_EQ(all_keymasters().size(), params.size()) - << "One or more keymasters failed to provide parameters."; + auto params = getHmacSharingParameters(allKeymasters()); + ASSERT_EQ(allKeymasters().size(), params.size()) + << "One or more keymasters failed to provide parameters."; auto nonces = copyNonces(params); - EXPECT_EQ(all_keymasters().size(), nonces.size()); + EXPECT_EQ(allKeymasters().size(), nonces.size()); std::sort(nonces.begin(), nonces.end()); std::unique(nonces.begin(), nonces.end()); - EXPECT_EQ(all_keymasters().size(), nonces.size()); + EXPECT_EQ(allKeymasters().size(), nonces.size()); - auto responses = computeSharedHmac(all_keymasters(), params); + auto responses = computeSharedHmac(allKeymasters(), params); ASSERT_GT(responses.size(), 0U); verifyResponses(responses[0].sharing_check, responses); // Do it a second time. Should get the same answers. - params = getHmacSharingParameters(all_keymasters()); - ASSERT_EQ(all_keymasters().size(), params.size()) - << "One or more keymasters failed to provide parameters."; + params = getHmacSharingParameters(allKeymasters()); + ASSERT_EQ(allKeymasters().size(), params.size()) + << "One or more keymasters failed to provide parameters."; - responses = computeSharedHmac(all_keymasters(), params); + responses = computeSharedHmac(allKeymasters(), params); ASSERT_GT(responses.size(), 0U); ASSERT_EQ(32U, responses[0].sharing_check.size()); verifyResponses(responses[0].sharing_check, responses); @@ -160,15 +175,16 @@ TEST_P(HmacKeySharingTest, ComputeSharedHmacCorruptNonce) { // sync with respect to the HMAC key. Granted that VTS tests aren't run on in-use production // devices, this still has the potential to cause confusion. To mitigate that, we always // (barring crashes :-/) re-run the unmodified agreement process on our way out. - auto fixup_hmac = finally( - [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); }); + auto fixup_hmac = finally([&]() { + computeSharedHmac(allKeymasters(), getHmacSharingParameters(allKeymasters())); + }); - auto params = getHmacSharingParameters(all_keymasters()); - ASSERT_EQ(all_keymasters().size(), params.size()) - << "One or more keymasters failed to provide parameters."; + auto params = getHmacSharingParameters(allKeymasters()); + ASSERT_EQ(allKeymasters().size(), params.size()) + << "One or more keymasters failed to provide parameters."; // All should be well in the normal case - auto responses = computeSharedHmac(all_keymasters(), params); + auto responses = computeSharedHmac(allKeymasters(), params); ASSERT_GT(responses.size(), 0U); HidlBuf correct_response = responses[0].sharing_check; @@ -181,7 +197,7 @@ TEST_P(HmacKeySharingTest, ComputeSharedHmacCorruptNonce) { uint8_t bit_to_tweak = rand() % 8; params[param_to_tweak].nonce[byte_to_tweak] ^= (1 << bit_to_tweak); - responses = computeSharedHmac(all_keymasters(), params); + responses = computeSharedHmac(allKeymasters(), params); for (size_t i = 0; i < responses.size(); ++i) { if (i == param_to_tweak) { EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error) @@ -199,15 +215,16 @@ TEST_P(HmacKeySharingTest, ComputeSharedHmacCorruptSeed) { // sync with respect to the HMAC key. Granted that VTS tests aren't run on in-use production // devices, this still has the potential to cause confusion. To mitigate that, we always // (barring crashes :-/) re-run the unmodified agreement process on our way out. - auto fixup_hmac = finally( - [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); }); + auto fixup_hmac = finally([&]() { + computeSharedHmac(allKeymasters(), getHmacSharingParameters(allKeymasters())); + }); - auto params = getHmacSharingParameters(all_keymasters()); - ASSERT_EQ(all_keymasters().size(), params.size()) - << "One or more keymasters failed to provide parameters."; + auto params = getHmacSharingParameters(allKeymasters()); + ASSERT_EQ(allKeymasters().size(), params.size()) + << "One or more keymasters failed to provide parameters."; // All should be well in the normal case - auto responses = computeSharedHmac(all_keymasters(), params); + auto responses = computeSharedHmac(allKeymasters(), params); ASSERT_GT(responses.size(), 0U); HidlBuf correct_response = responses[0].sharing_check; @@ -223,7 +240,7 @@ TEST_P(HmacKeySharingTest, ComputeSharedHmacCorruptSeed) { } to_tweak[0]++; - responses = computeSharedHmac(all_keymasters(), params); + responses = computeSharedHmac(allKeymasters(), params); for (size_t i = 0; i < responses.size(); ++i) { if (i == param_to_tweak) { EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error) @@ -236,10 +253,7 @@ TEST_P(HmacKeySharingTest, ComputeSharedHmacCorruptSeed) { } } -INSTANTIATE_TEST_SUITE_P( - PerInstance, HmacKeySharingTest, - testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor)), - android::hardware::PrintInstanceNameToString); +INSTANTIATE_KEYMASTER_HIDL_TEST(HmacKeySharingTest); } // namespace test } // namespace V4_0 diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp index 1fbd721e24..5d0e262ca5 100644 --- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp +++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp @@ -42,39 +42,27 @@ namespace V4_0 { namespace test { +using namespace std::literals::chrono_literals; + void KeymasterHidlTest::InitializeKeymaster() { - service_name_ = GetParam(); - keymaster_ = IKeymasterDevice::getService(service_name_); + keymaster_ = IKeymasterDevice::getService(GetParam()); ASSERT_NE(keymaster_, nullptr); ASSERT_TRUE(keymaster_ - ->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name, - const hidl_string& author) { - securityLevel_ = securityLevel; - name_ = name; - author_ = author; - }) - .isOk()); + ->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name, + const hidl_string& author) { + securityLevel_ = securityLevel; + name_ = name; + author_ = author; + }) + .isOk()); } -void KeymasterHidlTest::SetUpTestCase() { +void KeymasterHidlTest::SetUp() { InitializeKeymaster(); os_version_ = support::getOsVersion(); os_patch_level_ = support::getOsPatchlevel(); - - auto service_manager = android::hidl::manager::V1_0::IServiceManager::getService(); - ASSERT_NE(nullptr, service_manager.get()); - all_keymasters_.push_back(keymaster_); - service_manager->listByInterface( - IKeymasterDevice::descriptor, [&](const hidl_vec& names) { - for (auto& name : names) { - if (name == service_name_) continue; - auto keymaster = IKeymasterDevice::getService(name); - ASSERT_NE(keymaster, nullptr); - all_keymasters_.push_back(keymaster); - } - }); } ErrorCode KeymasterHidlTest::GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob, diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h index f7d6da2ca0..faa7c75409 100644 --- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h +++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h @@ -18,8 +18,9 @@ #include #include - -#include +#include +#include +#include #include @@ -33,13 +34,13 @@ namespace V4_0 { namespace test { using ::android::sp; -using ::std::string; using hidl::base::V1_0::DebugInfo; +using ::std::string; class HidlBuf : public hidl_vec { typedef hidl_vec super; - public: + public: HidlBuf() {} HidlBuf(const super& other) : super(other) {} HidlBuf(super&& other) : super(std::move(other)) {} @@ -68,20 +69,16 @@ constexpr uint64_t kOpHandleSentinel = 0xFFFFFFFFFFFFFFFF; class KeymasterHidlTest : public ::testing::TestWithParam { public: - void SetUp(); + void SetUp() override; void TearDown() override { if (key_blob_.size()) { CheckedDeleteKey(); } AbortIfNeeded(); - keymaster_.clear(); - all_keymasters_.clear(); } void InitializeKeymaster(); - IKeymasterDevice& keymaster() { return *keymaster_; } - const std::vector>& all_keymasters() { return all_keymasters_; } uint32_t os_version() { return os_version_; } uint32_t os_patch_level() { return os_patch_level_; } @@ -207,18 +204,22 @@ class KeymasterHidlTest : public ::testing::TestWithParam { KeyCharacteristics key_characteristics_; OperationHandle op_handle_ = kOpHandleSentinel; - private: - sp keymaster_; - std::vector> all_keymasters_; - uint32_t os_version_; - uint32_t os_patch_level_; + private: + sp keymaster_; + uint32_t os_version_; + uint32_t os_patch_level_; - SecurityLevel securityLevel_; - hidl_string name_; - hidl_string author_; - string service_name_; + SecurityLevel securityLevel_; + hidl_string name_; + hidl_string author_; }; +#define INSTANTIATE_KEYMASTER_HIDL_TEST(name) \ + INSTANTIATE_TEST_SUITE_P(PerInstance, name, \ + testing::ValuesIn(android::hardware::getAllHalInstanceNames( \ + IKeymasterDevice::descriptor)), \ + android::hardware::PrintInstanceNameToString) + } // namespace test } // namespace V4_0 } // namespace keymaster diff --git a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp index 693f4ae0e4..bab1439584 100644 --- a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp +++ b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp @@ -185,10 +185,7 @@ TEST_P(VerificationTokenTest, MacChangesOnChangingTimestamp) { memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size())); } -INSTANTIATE_TEST_SUITE_P( - PerInstance, VerificationTokenTest, - testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor)), - android::hardware::PrintInstanceNameToString); +INSTANTIATE_KEYMASTER_HIDL_TEST(VerificationTokenTest); } // namespace test } // namespace V4_0 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 66132adc94..d9131f59c7 100644 --- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp +++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp @@ -840,6 +840,8 @@ TEST_P(NewKeyGenerationTest, HmacDigestNone) { .Authorization(TAG_MIN_MAC_LENGTH, 128))); } +INSTANTIATE_KEYMASTER_HIDL_TEST(NewKeyGenerationTest); + typedef KeymasterHidlTest SigningOperationsTest; /* @@ -1509,6 +1511,8 @@ TEST_P(SigningOperationsTest, HmacRfc4231TestCase5) { } } +INSTANTIATE_KEYMASTER_HIDL_TEST(SigningOperationsTest); + typedef KeymasterHidlTest VerificationOperationsTest; /* @@ -1749,6 +1753,8 @@ TEST_P(VerificationOperationsTest, HmacSigningKeyCannotVerify) { CheckedDeleteKey(&verification_key); } +INSTANTIATE_KEYMASTER_HIDL_TEST(VerificationOperationsTest); + typedef KeymasterHidlTest ExportKeyTest; /* @@ -1828,6 +1834,8 @@ TEST_P(ExportKeyTest, AesKeyUnexportable) { EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::RAW, &export_data)); } +INSTANTIATE_KEYMASTER_HIDL_TEST(ExportKeyTest); + class ImportKeyTest : public KeymasterHidlTest { public: template @@ -2093,6 +2101,8 @@ TEST_P(ImportKeyTest, HmacKeySuccess) { VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(Digest::SHA_2_256)); } +INSTANTIATE_KEYMASTER_HIDL_TEST(ImportKeyTest); + auto wrapped_key = hex2str( "3082017902010004820100934bf94e2aa28a3f83c9f79297250262fbe3276b5a1c91159bbfa3ef8957aac84b59b30b" "455a79c2973480823d8b3863c3deef4a8e243590268d80e18751a0e130f67ce6a1ace9f79b95e097474febc981195b" @@ -2214,6 +2224,8 @@ TEST_P(ImportWrappedKeyTest, WrongPurpose) { .Padding(PaddingMode::RSA_OAEP))); } +INSTANTIATE_KEYMASTER_HIDL_TEST(ImportWrappedKeyTest); + typedef KeymasterHidlTest EncryptionOperationsTest; /* @@ -4111,6 +4123,8 @@ TEST_P(EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding) { EXPECT_EQ(message, plaintext); } +INSTANTIATE_KEYMASTER_HIDL_TEST(EncryptionOperationsTest); + typedef KeymasterHidlTest MaxOperationsTest; /* @@ -4166,6 +4180,8 @@ TEST_P(MaxOperationsTest, TestLimitRsa) { EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::SIGN, params)); } +INSTANTIATE_KEYMASTER_HIDL_TEST(MaxOperationsTest); + typedef KeymasterHidlTest AddEntropyTest; /* @@ -4196,6 +4212,8 @@ TEST_P(AddEntropyTest, AddLargeEntropy) { EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf(string(2 * 1024, 'a')))); } +INSTANTIATE_KEYMASTER_HIDL_TEST(AddEntropyTest); + typedef KeymasterHidlTest AttestationTest; /* @@ -4373,6 +4391,8 @@ TEST_P(AttestationTest, HmacAttestation) { &cert_chain)); } +INSTANTIATE_KEYMASTER_HIDL_TEST(AttestationTest); + typedef KeymasterHidlTest KeyDeletionTest; /** @@ -4478,6 +4498,8 @@ TEST_P(KeyDeletionTest, DeleteAllKeys) { } } +INSTANTIATE_KEYMASTER_HIDL_TEST(KeyDeletionTest); + using UpgradeKeyTest = KeymasterHidlTest; /* @@ -4497,6 +4519,8 @@ TEST_P(UpgradeKeyTest, UpgradeKey) { EXPECT_EQ(result, std::make_pair(ErrorCode::OK, HidlBuf())); } +INSTANTIATE_KEYMASTER_HIDL_TEST(UpgradeKeyTest); + using ClearOperationsTest = KeymasterHidlTest; /* @@ -4572,6 +4596,8 @@ TEST_P(ClearOperationsTest, ServiceDeath) { } } +INSTANTIATE_KEYMASTER_HIDL_TEST(ClearOperationsTest); + typedef KeymasterHidlTest TransportLimitTest; /* @@ -4624,44 +4650,7 @@ TEST_P(TransportLimitTest, LargeFinishInput) { CheckedDeleteKey(); } -static const auto kKeymasterDeviceChoices = - testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor)); - -INSTANTIATE_TEST_SUITE_P(PerInstance, NewKeyGenerationTest, kKeymasterDeviceChoices, - android::hardware::PrintInstanceNameToString); - -INSTANTIATE_TEST_SUITE_P(PerInstance, ImportKeyTest, kKeymasterDeviceChoices, - android::hardware::PrintInstanceNameToString); - -INSTANTIATE_TEST_SUITE_P(PerInstance, ImportWrappedKeyTest, kKeymasterDeviceChoices, - android::hardware::PrintInstanceNameToString); - -INSTANTIATE_TEST_SUITE_P(PerInstance, SigningOperationsTest, kKeymasterDeviceChoices, - android::hardware::PrintInstanceNameToString); - -INSTANTIATE_TEST_SUITE_P(PerInstance, VerificationOperationsTest, kKeymasterDeviceChoices, - android::hardware::PrintInstanceNameToString); - -INSTANTIATE_TEST_SUITE_P(PerInstance, ExportKeyTest, kKeymasterDeviceChoices, - android::hardware::PrintInstanceNameToString); - -INSTANTIATE_TEST_SUITE_P(PerInstance, EncryptionOperationsTest, kKeymasterDeviceChoices, - android::hardware::PrintInstanceNameToString); - -INSTANTIATE_TEST_SUITE_P(PerInstance, MaxOperationsTest, kKeymasterDeviceChoices, - android::hardware::PrintInstanceNameToString); - -INSTANTIATE_TEST_SUITE_P(PerInstance, AddEntropyTest, kKeymasterDeviceChoices, - android::hardware::PrintInstanceNameToString); - -INSTANTIATE_TEST_SUITE_P(PerInstance, AttestationTest, kKeymasterDeviceChoices, - android::hardware::PrintInstanceNameToString); - -INSTANTIATE_TEST_SUITE_P(PerInstance, KeyDeletionTest, kKeymasterDeviceChoices, - android::hardware::PrintInstanceNameToString); - -INSTANTIATE_TEST_SUITE_P(PerInstance, TransportLimitTest, kKeymasterDeviceChoices, - android::hardware::PrintInstanceNameToString); +INSTANTIATE_KEYMASTER_HIDL_TEST(TransportLimitTest); } // namespace test } // namespace V4_0 diff --git a/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp b/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp index 4a19010c46..d1978a9cdf 100644 --- a/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp +++ b/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp @@ -16,6 +16,6 @@ namespace android::hardware::keymaster::V4_1::test { -// TODO(swillden): Put tests here. + } // namespace android::hardware::keymaster::V4_1::test From c78dc91896ea91dc7d30727818abfe420dbccddb Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Tue, 26 Nov 2019 22:15:27 -0700 Subject: [PATCH 0449/1022] Change finish input test to avoid large sizes. We'll add a large-size test to the Keymaster 4.1 VTS tests. Test: VtsHalKeymasterV4_0TargetTest Change-Id: I2460106cf918e44ea5eeac5c518a89c311756eb3 --- .../functional/keymaster_hidl_hal_test.cpp | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) 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 d9131f59c7..7aaf7f8b52 100644 --- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp +++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp @@ -4601,9 +4601,9 @@ INSTANTIATE_KEYMASTER_HIDL_TEST(ClearOperationsTest); typedef KeymasterHidlTest TransportLimitTest; /* - * TransportLimitTest.LargeFinishInput + * TransportLimitTest.FinishInput * - * Verifies that passing large input data to finish either succeeds or fails as expected. + * Verifies that passing input data to finish succeeds as expected. */ TEST_P(TransportLimitTest, LargeFinishInput) { ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() @@ -4612,7 +4612,7 @@ TEST_P(TransportLimitTest, LargeFinishInput) { .BlockMode(BlockMode::ECB) .Padding(PaddingMode::NONE))); - for (int msg_size = 10 /*1KB*/; msg_size <= 17 /*128KB*/; msg_size++) { + for (int msg_size = 8 /* 256 bytes */; msg_size <= 11 /* 2 KiB */; msg_size++) { auto cipher_params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE); @@ -4623,31 +4623,19 @@ TEST_P(TransportLimitTest, LargeFinishInput) { string encrypted_message; auto rc = Finish(plain_message, &encrypted_message); - if (rc == ErrorCode::OK) { - EXPECT_EQ(plain_message.size(), encrypted_message.size()) - << "Encrypt finish returned OK, but did not consume all of the given input"; - } else { - EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, rc) - << "Encrypt finish failed in an unexpected way when given a large input"; - continue; - } + EXPECT_EQ(ErrorCode::OK, rc); + EXPECT_EQ(plain_message.size(), encrypted_message.size()) + << "Encrypt finish returned OK, but did not consume all of the given input"; cipher_params.push_back(out_params); EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params)); string decrypted_message; rc = Finish(encrypted_message, &decrypted_message); - - if (rc == ErrorCode::OK) { - EXPECT_EQ(plain_message.size(), decrypted_message.size()) - << "Decrypt finish returned OK, did not consume all of the given input"; - } else { - EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, rc) - << "Encrypt finish failed in an unexpected way when given a large input"; - } + EXPECT_EQ(ErrorCode::OK, rc); + EXPECT_EQ(plain_message.size(), decrypted_message.size()) + << "Decrypt finish returned OK, did not consume all of the given input"; } - - CheckedDeleteKey(); } INSTANTIATE_KEYMASTER_HIDL_TEST(TransportLimitTest); From de45c29522d3d7b9ab15aad46397d915870b9b8d Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Mon, 6 Jan 2020 13:11:31 -0800 Subject: [PATCH 0450/1022] Camera: Add android.scaler.rotateAndCrop control Test: New CTS tests pass Bug: 134631897 Change-Id: Ibdfee75b9e77f661e1db5c26faeecae7853342bd --- camera/metadata/3.5/types.hal | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal index 62899ec0c5..f139088c3b 100644 --- a/camera/metadata/3.5/types.hal +++ b/camera/metadata/3.5/types.hal @@ -72,6 +72,23 @@ enum CameraMetadataTag : @3.4::CameraMetadataTag { ANDROID_CONTROL_END_3_5, + /** android.scaler.availableRotateAndCropModes [static, byte[], public] + * + *

    List of rotate-and-crop modes for ANDROID_SCALER_ROTATE_AND_CROP that are supported by this camera device.

    + * + * @see ANDROID_SCALER_ROTATE_AND_CROP + */ + ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES = android.hardware.camera.metadata@3.4::CameraMetadataTag:ANDROID_SCALER_END_3_4, + + /** android.scaler.rotateAndCrop [dynamic, enum, public] + * + *

    Whether a rotation-and-crop operation is applied to processed + * outputs from the camera.

    + */ + ANDROID_SCALER_ROTATE_AND_CROP, + + ANDROID_SCALER_END_3_5, + }; /* @@ -95,3 +112,14 @@ enum CameraMetadataEnumAndroidRequestAvailableCapabilities : ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA, ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING, }; + +/** android.scaler.rotateAndCrop enumeration values + * @see ANDROID_SCALER_ROTATE_AND_CROP + */ +enum CameraMetadataEnumAndroidScalerRotateAndCrop : uint32_t { + ANDROID_SCALER_ROTATE_AND_CROP_NONE, + ANDROID_SCALER_ROTATE_AND_CROP_90, + ANDROID_SCALER_ROTATE_AND_CROP_180, + ANDROID_SCALER_ROTATE_AND_CROP_270, + ANDROID_SCALER_ROTATE_AND_CROP_AUTO, +}; From 13f4bf8491b676947a6da861f3de010b255ede40 Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Tue, 26 Nov 2019 22:16:54 -0700 Subject: [PATCH 0451/1022] Remove service death test. Moving to KM4.1 VTS. Test: VtsHalKeymasterV4_0TargetTest Change-Id: I8f2b7ab3305833fe8639fdefb9cc263f99684920 --- .../functional/keymaster_hidl_hal_test.cpp | 39 ------------------- 1 file changed, 39 deletions(-) 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 7aaf7f8b52..fb450d1bb4 100644 --- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp +++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp @@ -4557,45 +4557,6 @@ TEST_P(ClearOperationsTest, TooManyOperations) { AbortIfNeeded(); } -/* - * ClearSlotsTest.ServiceDeath - * - * Verifies that the service is restarted after death and the ongoing - * operations are cleared. - */ -TEST_P(ClearOperationsTest, ServiceDeath) { - ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() - .Authorization(TAG_NO_AUTH_REQUIRED) - .RsaEncryptionKey(2048, 65537) - .Padding(PaddingMode::NONE))); - - auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE); - int max_operations = SecLevel() == SecurityLevel::STRONGBOX ? 4 : 16; - OperationHandle op_handles[max_operations]; - AuthorizationSet out_params; - for(int i=0; i Date: Thu, 28 Nov 2019 20:15:25 -0700 Subject: [PATCH 0452/1022] Update KM4 VTS tests to allow s/w implementation to pass. Although no real devices should have a software implementation, emulator and cloud devices do, and it's useful to be able to use them as a development platform, which is facilitated by having useful VTS tests. This is in preparation for Keymaster 4.1 implementation and VTS work. Bug: 140193672 Bug: 140192237 Bug: 140824829 Test: VtsHalKeymaster4.0TargetTest Change-Id: Idc5de13c342ef1ac62d3131a1a2185d5e78a0d45 --- keymaster/4.0/support/attestation_record.cpp | 25 +++++----- .../4.0/vts/functional/KeymasterHidlTest.cpp | 46 +++++++++++-------- .../4.0/vts/functional/KeymasterHidlTest.h | 12 +++-- .../functional/keymaster_hidl_hal_test.cpp | 14 ++++-- 4 files changed, 58 insertions(+), 39 deletions(-) diff --git a/keymaster/4.0/support/attestation_record.cpp b/keymaster/4.0/support/attestation_record.cpp index 000d46e7db..27e00c173a 100644 --- a/keymaster/4.0/support/attestation_record.cpp +++ b/keymaster/4.0/support/attestation_record.cpp @@ -321,19 +321,20 @@ ErrorCode parse_root_of_trust(const uint8_t* asn1_key_desc, size_t asn1_key_desc LOG(ERROR) << AT << "Failed record parsing"; return ErrorCode::UNKNOWN_ERROR; } - if (!record->tee_enforced) { - LOG(ERROR) << AT << "Failed hardware characteristic parsing"; + + KM_ROOT_OF_TRUST* root_of_trust = nullptr; + if (record->tee_enforced && record->tee_enforced->root_of_trust) { + root_of_trust = record->tee_enforced->root_of_trust; + } else if (record->software_enforced && record->software_enforced->root_of_trust) { + root_of_trust = record->software_enforced->root_of_trust; + } else { + LOG(ERROR) << AT << " Failed root of trust parsing"; return ErrorCode::INVALID_ARGUMENT; } - if (!record->tee_enforced->root_of_trust) { - LOG(ERROR) << AT << "Failed root of trust parsing"; + if (!root_of_trust->verified_boot_key) { + LOG(ERROR) << AT << " Failed verified boot key parsing"; return ErrorCode::INVALID_ARGUMENT; } - if (!record->tee_enforced->root_of_trust->verified_boot_key) { - LOG(ERROR) << AT << "Failed verified boot key parsing"; - return ErrorCode::INVALID_ARGUMENT; - } - KM_ROOT_OF_TRUST* root_of_trust = record->tee_enforced->root_of_trust; auto& vb_key = root_of_trust->verified_boot_key; verified_boot_key->resize(vb_key->length); @@ -342,19 +343,19 @@ ErrorCode parse_root_of_trust(const uint8_t* asn1_key_desc, size_t asn1_key_desc *verified_boot_state = static_cast( ASN1_ENUMERATED_get(root_of_trust->verified_boot_state)); if (!verified_boot_state) { - LOG(ERROR) << AT << "Failed verified boot state parsing"; + LOG(ERROR) << AT << " Failed verified boot state parsing"; return ErrorCode::INVALID_ARGUMENT; } *device_locked = root_of_trust->device_locked; if (!device_locked) { - LOG(ERROR) << AT << "Failed device locked parsing"; + LOG(ERROR) << AT << " Failed device locked parsing"; return ErrorCode::INVALID_ARGUMENT; } auto& vb_hash = root_of_trust->verified_boot_hash; if (!vb_hash) { - LOG(ERROR) << AT << "Failed verified boot hash parsing"; + LOG(ERROR) << AT << " Failed verified boot hash parsing"; return ErrorCode::INVALID_ARGUMENT; } verified_boot_hash->resize(vb_hash->length); diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp index 5d0e262ca5..2d2ba632cb 100644 --- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp +++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp @@ -45,6 +45,7 @@ namespace test { using namespace std::literals::chrono_literals; void KeymasterHidlTest::InitializeKeymaster() { + std::string instance_name = GetParam(); keymaster_ = IKeymasterDevice::getService(GetParam()); ASSERT_NE(keymaster_, nullptr); @@ -127,7 +128,7 @@ ErrorCode KeymasterHidlTest::ImportWrappedKey(string wrapped_key, string wrappin string masking_key, const AuthorizationSet& unwrapping_params) { ErrorCode error; - ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key); + EXPECT_EQ(ErrorCode::OK, ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key)); EXPECT_TRUE(keymaster_ ->importWrappedKey(HidlBuf(wrapped_key), key_blob_, HidlBuf(masking_key), unwrapping_params.hidl_data(), 0 /* passwordSid */, @@ -196,7 +197,9 @@ void KeymasterHidlTest::CheckGetCharacteristics(const HidlBuf& key_blob, const H HidlBuf empty_buf = {}; EXPECT_EQ(ErrorCode::OK, GetCharacteristics(key_blob, client_id, app_data, key_characteristics)); - EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0); + if (SecLevel() != SecurityLevel::SOFTWARE) { + EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0); + } EXPECT_GT(key_characteristics->softwareEnforced.size(), 0); EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, @@ -636,23 +639,25 @@ std::vector KeymasterHidlTest::ValidKeySizes(Algorithm algorithm) { switch (algorithm) { case Algorithm::RSA: switch (SecLevel()) { + case SecurityLevel::SOFTWARE: case SecurityLevel::TRUSTED_ENVIRONMENT: return {2048, 3072, 4096}; case SecurityLevel::STRONGBOX: return {2048}; default: - CHECK(false) << "Invalid security level " << uint32_t(SecLevel()); + ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel()); break; } break; case Algorithm::EC: switch (SecLevel()) { + case SecurityLevel::SOFTWARE: case SecurityLevel::TRUSTED_ENVIRONMENT: return {224, 256, 384, 521}; case SecurityLevel::STRONGBOX: return {256}; default: - CHECK(false) << "Invalid security level " << uint32_t(SecLevel()); + ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel()); break; } break; @@ -667,25 +672,27 @@ std::vector KeymasterHidlTest::ValidKeySizes(Algorithm algorithm) { return retval; } default: - CHECK(false) << "Invalid Algorithm: " << algorithm; + ADD_FAILURE() << "Invalid Algorithm: " << algorithm; return {}; } - CHECK(false) << "Should be impossible to get here"; + ADD_FAILURE() << "Should be impossible to get here"; return {}; } + std::vector KeymasterHidlTest::InvalidKeySizes(Algorithm algorithm) { - if (SecLevel() == SecurityLevel::TRUSTED_ENVIRONMENT) return {}; - CHECK(SecLevel() == SecurityLevel::STRONGBOX); - switch (algorithm) { - case Algorithm::RSA: - return {3072, 4096}; - case Algorithm::EC: - return {224, 384, 521}; - case Algorithm::AES: - return {192}; - default: - return {}; + if (SecLevel() == SecurityLevel::STRONGBOX) { + switch (algorithm) { + case Algorithm::RSA: + return {3072, 4096}; + case Algorithm::EC: + return {224, 384, 521}; + case Algorithm::AES: + return {192}; + default: + return {}; + } } + return {}; } std::vector KeymasterHidlTest::ValidCurves() { @@ -704,6 +711,7 @@ std::vector KeymasterHidlTest::InvalidCurves() { std::vector KeymasterHidlTest::ValidDigests(bool withNone, bool withMD5) { switch (SecLevel()) { + case SecurityLevel::SOFTWARE: case SecurityLevel::TRUSTED_ENVIRONMENT: if (withNone) { if (withMD5) @@ -729,10 +737,10 @@ std::vector KeymasterHidlTest::ValidDigests(bool withNone, bool withMD5) return {Digest::SHA_2_256}; break; default: - CHECK(false) << "Invalid security level " << uint32_t(SecLevel()); + ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel()); break; } - CHECK(false) << "Should be impossible to get here"; + ADD_FAILURE() << "Should be impossible to get here"; return {}; } diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h index faa7c75409..34a4473976 100644 --- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h +++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h @@ -204,6 +204,11 @@ class KeymasterHidlTest : public ::testing::TestWithParam { KeyCharacteristics key_characteristics_; OperationHandle op_handle_ = kOpHandleSentinel; + static std::vector build_params() { + auto params = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor); + return params; + } + private: sp keymaster_; uint32_t os_version_; @@ -214,10 +219,9 @@ class KeymasterHidlTest : public ::testing::TestWithParam { hidl_string author_; }; -#define INSTANTIATE_KEYMASTER_HIDL_TEST(name) \ - INSTANTIATE_TEST_SUITE_P(PerInstance, name, \ - testing::ValuesIn(android::hardware::getAllHalInstanceNames( \ - IKeymasterDevice::descriptor)), \ +#define INSTANTIATE_KEYMASTER_HIDL_TEST(name) \ + INSTANTIATE_TEST_SUITE_P(PerInstance, name, \ + testing::ValuesIn(KeymasterHidlTest::build_params()), \ android::hardware::PrintInstanceNameToString) } // namespace test 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 fb450d1bb4..ace389bbd3 100644 --- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp +++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp @@ -397,10 +397,16 @@ bool verify_attestation_record(const string& challenge, const string& app_id, // true. A provided boolean tag that can be pulled back out of the certificate indicates correct // encoding. No need to check if it's in both lists, since the AuthorizationSet compare below // will handle mismatches of tags. - EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED)); + if (security_level == SecurityLevel::SOFTWARE) { + EXPECT_TRUE(expected_sw_enforced.Contains(TAG_NO_AUTH_REQUIRED)); + } else { + EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED)); + } // Alternatively this checks the opposite - a false boolean tag (one that isn't provided in // the authorization list during key generation) isn't being attested to in the certificate. + EXPECT_FALSE(expected_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED)); + EXPECT_FALSE(att_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED)); EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED)); EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED)); @@ -461,10 +467,10 @@ bool verify_attestation_record(const string& challenge, const string& app_id, verified_boot_key.size())); } else if (!strcmp(property_value, "red")) { EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_FAILED); - EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(), - verified_boot_key.size())); } else { - EXPECT_TRUE(false); + EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_UNVERIFIED); + EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(), + verified_boot_key.size())); } att_sw_enforced.Sort(); From b26a225b9c2ea63d7ef61a6427c3ff68770f1add Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Wed, 15 Jan 2020 19:09:50 -0700 Subject: [PATCH 0453/1022] Keymaster 4.1 VTS tests Test: VtsHalKeymasterV4_1TargetTest Change-Id: I488402079ebb3940e021ac1558aeee15c4b133c9 --- keymaster/4.0/support/authorization_set.cpp | 4 +- .../include/keymasterV4_0/keymaster_tags.h | 130 +++--- .../include/keymasterV4_0/openssl_utils.h | 2 + keymaster/4.0/vts/functional/Android.bp | 17 +- .../4.0/vts/functional/KeymasterHidlTest.cpp | 16 +- .../4.0/vts/functional/KeymasterHidlTest.h | 20 +- .../functional/keymaster_hidl_hal_test.cpp | 4 +- keymaster/4.1/support/Android.bp | 8 +- keymaster/4.1/support/attestation_record.cpp | 387 ++++++++++++++++++ .../keymasterV4_1/attestation_record.h | 57 +++ .../include/keymasterV4_1/keymaster_tags.h | 5 +- keymaster/4.1/vts/functional/Android.bp | 16 +- .../DeviceUniqueAttestationTest.cpp | 278 +++++++++++++ .../4.1/vts/functional/EarlyBootKeyTest.cpp | 70 ++++ .../vts/functional/Keymaster4_1HidlTest.cpp | 59 +++ .../4.1/vts/functional/Keymaster4_1HidlTest.h | 158 +++++++ .../functional/UnlockedDeviceRequiredTest.cpp | 63 +++ 17 files changed, 1191 insertions(+), 103 deletions(-) create mode 100644 keymaster/4.1/support/attestation_record.cpp create mode 100644 keymaster/4.1/support/include/keymasterV4_1/attestation_record.h create mode 100644 keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp create mode 100644 keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp create mode 100644 keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h create mode 100644 keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp diff --git a/keymaster/4.0/support/authorization_set.cpp b/keymaster/4.0/support/authorization_set.cpp index d6b50f5172..a024ff9c60 100644 --- a/keymaster/4.0/support/authorization_set.cpp +++ b/keymaster/4.0/support/authorization_set.cpp @@ -25,7 +25,7 @@ namespace hardware { namespace keymaster { namespace V4_0 { -inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) { +bool keyParamLess(const KeyParameter& a, const KeyParameter& b) { if (a.tag != b.tag) return a.tag < b.tag; int retval; switch (typeFromTag(a.tag)) { @@ -58,7 +58,7 @@ inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) { return false; } -inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) { +bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) { if (a.tag != b.tag) return false; switch (typeFromTag(a.tag)) { diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h index cb29c64b1e..bc7f311097 100644 --- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h +++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h @@ -355,95 +355,61 @@ inline NullOr>::type&> return accessTagValue(ttag, param); } +inline bool operator<(const KeyParameter& a, const KeyParameter& b) { + if (a.tag != b.tag) return a.tag < b.tag; + int retval; + switch (typeFromTag(a.tag)) { + case TagType::INVALID: + case TagType::BOOL: + return false; + case TagType::ENUM: + case TagType::ENUM_REP: + case TagType::UINT: + case TagType::UINT_REP: + return a.f.integer < b.f.integer; + case TagType::ULONG: + case TagType::ULONG_REP: + return a.f.longInteger < b.f.longInteger; + case TagType::DATE: + return a.f.dateTime < b.f.dateTime; + case TagType::BIGNUM: + case TagType::BYTES: + // Handle the empty cases. + if (a.blob.size() == 0) return b.blob.size() != 0; + if (b.blob.size() == 0) return false; + + retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size())); + // if one is the prefix of the other the longer wins + if (retval == 0) return a.blob.size() < b.blob.size(); + // Otherwise a is less if a is less. + else + return retval < 0; + } + return false; +} + inline bool operator==(const KeyParameter& a, const KeyParameter& b) { - if (a.tag != b.tag) { - return false; - } + if (a.tag != b.tag) return false; - switch (a.tag) { - /* Boolean tags */ - case Tag::INVALID: - case Tag::CALLER_NONCE: - case Tag::INCLUDE_UNIQUE_ID: - case Tag::BOOTLOADER_ONLY: - case Tag::NO_AUTH_REQUIRED: - case Tag::ALLOW_WHILE_ON_BODY: - case Tag::UNLOCKED_DEVICE_REQUIRED: - case Tag::ROLLBACK_RESISTANCE: - case Tag::RESET_SINCE_ID_ROTATION: - case Tag::TRUSTED_CONFIRMATION_REQUIRED: - case Tag::TRUSTED_USER_PRESENCE_REQUIRED: + switch (typeFromTag(a.tag)) { + case TagType::INVALID: + case TagType::BOOL: return true; - - /* Integer tags */ - case Tag::KEY_SIZE: - case Tag::MIN_MAC_LENGTH: - case Tag::MIN_SECONDS_BETWEEN_OPS: - case Tag::MAX_USES_PER_BOOT: - case Tag::OS_VERSION: - case Tag::OS_PATCHLEVEL: - case Tag::MAC_LENGTH: - case Tag::USER_ID: - case Tag::AUTH_TIMEOUT: - case Tag::VENDOR_PATCHLEVEL: - case Tag::BOOT_PATCHLEVEL: + case TagType::ENUM: + case TagType::ENUM_REP: + case TagType::UINT: + case TagType::UINT_REP: return a.f.integer == b.f.integer; - - /* Long integer tags */ - case Tag::RSA_PUBLIC_EXPONENT: - case Tag::USER_SECURE_ID: + case TagType::ULONG: + case TagType::ULONG_REP: return a.f.longInteger == b.f.longInteger; - - /* Date-time tags */ - case Tag::ACTIVE_DATETIME: - case Tag::ORIGINATION_EXPIRE_DATETIME: - case Tag::USAGE_EXPIRE_DATETIME: - case Tag::CREATION_DATETIME: + case TagType::DATE: return a.f.dateTime == b.f.dateTime; - - /* Bytes tags */ - case Tag::APPLICATION_ID: - case Tag::APPLICATION_DATA: - case Tag::ROOT_OF_TRUST: - case Tag::UNIQUE_ID: - case Tag::ATTESTATION_CHALLENGE: - case Tag::ATTESTATION_APPLICATION_ID: - case Tag::ATTESTATION_ID_BRAND: - case Tag::ATTESTATION_ID_DEVICE: - case Tag::ATTESTATION_ID_PRODUCT: - case Tag::ATTESTATION_ID_SERIAL: - case Tag::ATTESTATION_ID_IMEI: - case Tag::ATTESTATION_ID_MEID: - case Tag::ATTESTATION_ID_MANUFACTURER: - case Tag::ATTESTATION_ID_MODEL: - case Tag::ASSOCIATED_DATA: - case Tag::CONFIRMATION_TOKEN: - case Tag::NONCE: - return a.blob == b.blob; - - /* Enum tags */ - case Tag::PURPOSE: - return a.f.purpose == b.f.purpose; - case Tag::ALGORITHM: - return a.f.algorithm == b.f.algorithm; - case Tag::BLOCK_MODE: - return a.f.blockMode == b.f.blockMode; - case Tag::DIGEST: - return a.f.digest == b.f.digest; - case Tag::PADDING: - return a.f.paddingMode == b.f.paddingMode; - case Tag::EC_CURVE: - return a.f.ecCurve == b.f.ecCurve; - case Tag::BLOB_USAGE_REQUIREMENTS: - return a.f.keyBlobUsageRequirements == b.f.keyBlobUsageRequirements; - case Tag::USER_AUTH_TYPE: - return a.f.integer == b.f.integer; - case Tag::ORIGIN: - return a.f.origin == b.f.origin; - case Tag::HARDWARE_TYPE: - return a.f.hardwareType == b.f.hardwareType; + case TagType::BIGNUM: + case TagType::BYTES: + if (a.blob.size() != b.blob.size()) return false; + return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0; } - return false; } diff --git a/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h b/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h index cc71dd1326..b3869f4ca3 100644 --- a/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h +++ b/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h @@ -18,6 +18,8 @@ #define HARDWARE_INTERFACES_KEYMASTER_4_0_SUPPORT_OPENSSL_UTILS_H_ #include +#include +#include template struct UniquePtrDeleter { diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp index 7244ae3c96..db500805dc 100644 --- a/keymaster/4.0/vts/functional/Android.bp +++ b/keymaster/4.0/vts/functional/Android.bp @@ -19,7 +19,6 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: [ "HmacKeySharingTest.cpp", - "KeymasterHidlTest.cpp", "VerificationTokenTest.cpp", "keymaster_hidl_hal_test.cpp", ], @@ -27,9 +26,25 @@ cc_test { "android.hardware.keymaster@4.0", "libcrypto_static", "libkeymaster4support", + "libkeymaster4vtstest", ], test_suites: [ "general-tests", "vts-core", ], } + +cc_test_library { + name: "libkeymaster4vtstest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "KeymasterHidlTest.cpp", + ], + export_include_dirs: [ + ".", + ], + static_libs: [ + "android.hardware.keymaster@4.0", + "libkeymaster4support", + ], +} diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp index 2d2ba632cb..d0ad433464 100644 --- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp +++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp @@ -44,11 +44,9 @@ namespace test { using namespace std::literals::chrono_literals; -void KeymasterHidlTest::InitializeKeymaster() { - std::string instance_name = GetParam(); - keymaster_ = IKeymasterDevice::getService(GetParam()); - ASSERT_NE(keymaster_, nullptr); - +void KeymasterHidlTest::InitializeKeymaster(sp keymaster) { + ASSERT_NE(keymaster, nullptr); + keymaster_ = keymaster; ASSERT_TRUE(keymaster_ ->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name, const hidl_string& author) { @@ -57,15 +55,15 @@ void KeymasterHidlTest::InitializeKeymaster() { author_ = author; }) .isOk()); -} - -void KeymasterHidlTest::SetUp() { - InitializeKeymaster(); os_version_ = support::getOsVersion(); os_patch_level_ = support::getOsPatchlevel(); } +void KeymasterHidlTest::SetUp() { + InitializeKeymaster(IKeymasterDevice::getService(GetParam())); +} + ErrorCode KeymasterHidlTest::GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob, KeyCharacteristics* key_characteristics) { EXPECT_NE(key_blob, nullptr) << "Key blob pointer must not be null. Test bug"; diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h index 34a4473976..f495516146 100644 --- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h +++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h @@ -38,12 +38,14 @@ using hidl::base::V1_0::DebugInfo; using ::std::string; class HidlBuf : public hidl_vec { - typedef hidl_vec super; + using super = hidl_vec; public: HidlBuf() {} HidlBuf(const super& other) : super(other) {} - HidlBuf(super&& other) : super(std::move(other)) {} + HidlBuf(super&& other) : super(std::move(other)) { other = {}; } + HidlBuf(const HidlBuf& other) : super(other) {} + HidlBuf(HidlBuf&& other) : super(std::move(other)) { other = HidlBuf(); } explicit HidlBuf(const std::string& other) : HidlBuf() { *this = other; } HidlBuf& operator=(const super& other) { @@ -53,6 +55,18 @@ class HidlBuf : public hidl_vec { HidlBuf& operator=(super&& other) { super::operator=(std::move(other)); + other = {}; + return *this; + } + + HidlBuf& operator=(const HidlBuf& other) { + super::operator=(other); + return *this; + } + + HidlBuf& operator=(HidlBuf&& other) { + super::operator=(std::move(other)); + other.super::operator=({}); return *this; } @@ -77,7 +91,7 @@ class KeymasterHidlTest : public ::testing::TestWithParam { AbortIfNeeded(); } - void InitializeKeymaster(); + void InitializeKeymaster(sp keymaster); IKeymasterDevice& keymaster() { return *keymaster_; } uint32_t os_version() { return os_version_; } uint32_t os_patch_level() { return os_patch_level_; } 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 ace389bbd3..6cbe4dafae 100644 --- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp +++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp @@ -352,11 +352,11 @@ bool verify_attestation_record(const string& challenge, const string& app_id, EXPECT_EQ(ErrorCode::OK, error); if (error != ErrorCode::OK) return false; - EXPECT_TRUE(att_attestation_version == 3); + EXPECT_GE(att_attestation_version, 3U); expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, HidlBuf(app_id)); - EXPECT_EQ(att_keymaster_version, 4U); + EXPECT_GE(att_keymaster_version, 4U); EXPECT_EQ(security_level, att_keymaster_security_level); EXPECT_EQ(security_level, att_attestation_security_level); diff --git a/keymaster/4.1/support/Android.bp b/keymaster/4.1/support/Android.bp index 34b6108c9d..e4c3d47080 100644 --- a/keymaster/4.1/support/Android.bp +++ b/keymaster/4.1/support/Android.bp @@ -22,11 +22,17 @@ cc_library { "-Wextra", "-Werror", ], + srcs: [ + "attestation_record.cpp", + ], export_include_dirs: ["include"], shared_libs: [ "android.hardware.keymaster@3.0", "android.hardware.keymaster@4.0", "android.hardware.keymaster@4.1", + "libbase", + "libcrypto", + "libhidlbase", "libkeymaster4support", - ] + ], } diff --git a/keymaster/4.1/support/attestation_record.cpp b/keymaster/4.1/support/attestation_record.cpp new file mode 100644 index 0000000000..9eab1db316 --- /dev/null +++ b/keymaster/4.1/support/attestation_record.cpp @@ -0,0 +1,387 @@ +/* + * Copyright 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 +#include + +#include +#include +#include +#include + +#include +#include + +#define AT __FILE__ ":" << __LINE__ + +/* + * NOTE: The contents of this file are *extremely* similar to the contents of the V4_0 copy of the + * same support file. Unfortunately, small changes in the scheme mean that the schema types have to + * be distinct, which drives almost everything else to be different as well. In the next version we + * plan to abandon not just this openssl mechanism for parsing ASN.1, but ASN.1 entirely, so + * eventually all of this duplication can be removed. + */ + +namespace android { +namespace hardware { +namespace keymaster { +namespace V4_1 { + +struct stack_st_ASN1_TYPE_Delete { + void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); } +}; + +struct ASN1_STRING_Delete { + void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); } +}; + +struct ASN1_TYPE_Delete { + void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); } +}; + +#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER) + +typedef struct km_root_of_trust { + ASN1_OCTET_STRING* verified_boot_key; + ASN1_BOOLEAN* device_locked; + ASN1_ENUMERATED* verified_boot_state; + ASN1_OCTET_STRING* verified_boot_hash; +} KM_ROOT_OF_TRUST; + +ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = { + ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING), + ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN), + ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED), + ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_hash, ASN1_OCTET_STRING), +} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST); +IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST); + +typedef struct km_auth_list { + ASN1_INTEGER_SET* purpose; + ASN1_INTEGER* algorithm; + ASN1_INTEGER* key_size; + ASN1_INTEGER_SET* digest; + ASN1_INTEGER_SET* padding; + ASN1_INTEGER* ec_curve; + ASN1_INTEGER* rsa_public_exponent; + ASN1_INTEGER* active_date_time; + ASN1_INTEGER* origination_expire_date_time; + ASN1_INTEGER* usage_expire_date_time; + ASN1_NULL* no_auth_required; + ASN1_INTEGER* user_auth_type; + ASN1_INTEGER* auth_timeout; + ASN1_NULL* allow_while_on_body; + ASN1_NULL* all_applications; + ASN1_OCTET_STRING* application_id; + ASN1_INTEGER* creation_date_time; + ASN1_INTEGER* origin; + ASN1_NULL* rollback_resistance; + KM_ROOT_OF_TRUST* root_of_trust; + ASN1_INTEGER* os_version; + ASN1_INTEGER* os_patchlevel; + ASN1_OCTET_STRING* attestation_application_id; + ASN1_NULL* trusted_user_presence_required; + ASN1_NULL* trusted_confirmation_required; + ASN1_NULL* unlocked_device_required; + ASN1_INTEGER* vendor_patchlevel; + ASN1_INTEGER* boot_patchlevel; + ASN1_NULL* early_boot_only; + ASN1_NULL* device_unique_attestation; +} KM_AUTH_LIST; + +ASN1_SEQUENCE(KM_AUTH_LIST) = { + ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()), + ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()), + ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER, + TAG_RSA_PUBLIC_EXPONENT.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL, + TAG_ROLLBACK_RESISTANCE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER, + TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER, + TAG_USAGE_EXPIRE_DATETIME.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL, + TAG_ALLOW_WHILE_ON_BODY.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, trusted_user_presence_required, ASN1_NULL, + TAG_TRUSTED_USER_PRESENCE_REQUIRED.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, trusted_confirmation_required, ASN1_NULL, + TAG_TRUSTED_CONFIRMATION_REQUIRED.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, unlocked_device_required, ASN1_NULL, + TAG_UNLOCKED_DEVICE_REQUIRED.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER, + TAG_CREATION_DATETIME.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER, + TAG_VENDOR_PATCHLEVEL.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING, + TAG_ATTESTATION_APPLICATION_ID.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, device_unique_attestation, ASN1_NULL, + TAG_DEVICE_UNIQUE_ATTESTATION.maskedTag()), +} ASN1_SEQUENCE_END(KM_AUTH_LIST); +IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST); + +typedef struct km_key_description { + ASN1_INTEGER* attestation_version; + ASN1_ENUMERATED* attestation_security_level; + ASN1_INTEGER* keymaster_version; + ASN1_ENUMERATED* keymaster_security_level; + ASN1_OCTET_STRING* attestation_challenge; + KM_AUTH_LIST* software_enforced; + KM_AUTH_LIST* tee_enforced; + ASN1_INTEGER* unique_id; +} KM_KEY_DESCRIPTION; + +ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = { + ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_version, ASN1_INTEGER), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_security_level, ASN1_ENUMERATED), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_version, ASN1_INTEGER), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_security_level, ASN1_ENUMERATED), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_challenge, ASN1_OCTET_STRING), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST), +} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION); +IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION); + +template +void copyAuthTag(const stack_st_ASN1_INTEGER* stack, TypedTag ttag, + AuthorizationSet* auth_list) { + typedef typename V4_0::TypedTag2ValueType::type ValueT; + for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) { + auth_list->push_back( + ttag, static_cast(ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i)))); + } +} + +template +void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag ttag, + AuthorizationSet* auth_list) { + typedef typename V4_0::TypedTag2ValueType::type ValueT; + if (!asn1_int) return; + auth_list->push_back(ttag, static_cast(ASN1_INTEGER_get(asn1_int))); +} + +template +void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag ttag, + AuthorizationSet* auth_list) { + if (!asn1_int) return; + auth_list->push_back(ttag, ASN1_INTEGER_get(asn1_int)); +} + +BIGNUM* construct_uint_max() { + BIGNUM* value = BN_new(); + BIGNUM_Ptr one(BN_new()); + BN_one(one.get()); + BN_lshift(value, one.get(), 32); + return value; +} + +uint64_t BignumToUint64(BIGNUM* num) { + static_assert((sizeof(BN_ULONG) == sizeof(uint32_t)) || (sizeof(BN_ULONG) == sizeof(uint64_t)), + "This implementation only supports 32 and 64-bit BN_ULONG"); + if (sizeof(BN_ULONG) == sizeof(uint32_t)) { + BIGNUM_Ptr uint_max(construct_uint_max()); + BIGNUM_Ptr hi(BN_new()), lo(BN_new()); + BN_CTX_Ptr ctx(BN_CTX_new()); + BN_div(hi.get(), lo.get(), num, uint_max.get(), ctx.get()); + return static_cast(BN_get_word(hi.get())) << 32 | BN_get_word(lo.get()); + } else if (sizeof(BN_ULONG) == sizeof(uint64_t)) { + return BN_get_word(num); + } else { + return 0; + } +} + +template +void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag ttag, + AuthorizationSet* auth_list) { + if (!asn1_int) return; + BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr)); + auth_list->push_back(ttag, BignumToUint64(num.get())); +} + +template +void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag ttag, + AuthorizationSet* auth_list) { + if (!asn1_int) return; + BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr)); + auth_list->push_back(ttag, BignumToUint64(num.get())); +} + +template +void copyAuthTag(const ASN1_NULL* asn1_null, TypedTag ttag, + AuthorizationSet* auth_list) { + if (!asn1_null) return; + auth_list->push_back(ttag); +} + +template +void copyAuthTag(const ASN1_OCTET_STRING* asn1_string, TypedTag ttag, + AuthorizationSet* auth_list) { + if (!asn1_string) return; + hidl_vec buf; + buf.setToExternal(asn1_string->data, asn1_string->length); + auth_list->push_back(ttag, buf); +} + +// Extract the values from the specified ASN.1 record and place them in auth_list. +static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list) { + if (!record) return ErrorCode::OK; + + copyAuthTag(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list); + copyAuthTag(record->algorithm, TAG_ALGORITHM, auth_list); + copyAuthTag(record->application_id, TAG_APPLICATION_ID, auth_list); + copyAuthTag(record->auth_timeout, TAG_AUTH_TIMEOUT, auth_list); + copyAuthTag(record->creation_date_time, TAG_CREATION_DATETIME, auth_list); + copyAuthTag(record->digest, TAG_DIGEST, auth_list); + copyAuthTag(record->ec_curve, TAG_EC_CURVE, auth_list); + copyAuthTag(record->key_size, TAG_KEY_SIZE, auth_list); + copyAuthTag(record->no_auth_required, TAG_NO_AUTH_REQUIRED, auth_list); + copyAuthTag(record->origin, TAG_ORIGIN, auth_list); + copyAuthTag(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, auth_list); + copyAuthTag(record->os_patchlevel, TAG_OS_PATCHLEVEL, auth_list); + copyAuthTag(record->os_version, TAG_OS_VERSION, auth_list); + copyAuthTag(record->padding, TAG_PADDING, auth_list); + copyAuthTag(record->purpose, TAG_PURPOSE, auth_list); + copyAuthTag(record->rollback_resistance, TAG_ROLLBACK_RESISTANCE, auth_list); + copyAuthTag(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list); + copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list); + copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list); + copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list); + copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list); + copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list); + copyAuthTag(record->trusted_user_presence_required, TAG_TRUSTED_USER_PRESENCE_REQUIRED, + auth_list); + copyAuthTag(record->trusted_confirmation_required, TAG_TRUSTED_CONFIRMATION_REQUIRED, + auth_list); + copyAuthTag(record->unlocked_device_required, TAG_UNLOCKED_DEVICE_REQUIRED, auth_list); + copyAuthTag(record->early_boot_only, TAG_EARLY_BOOT_ONLY, auth_list); + copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list); + + return ErrorCode::OK; +} + +MAKE_OPENSSL_PTR_TYPE(KM_KEY_DESCRIPTION) + +// Parse the DER-encoded attestation record, placing the results in keymaster_version, +// attestation_challenge, software_enforced, tee_enforced and unique_id. +std::tuple parse_attestation_record(const hidl_vec& cert) { + const uint8_t* p = cert.data(); + X509_Ptr x509(d2i_X509(nullptr, &p, cert.size())); + + ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */)); + if (!oid.get()) { + LOG(ERROR) << "Error parsing OID"; + return {ErrorCode::UNKNOWN_ERROR, {}}; + } + + int location = X509_get_ext_by_OBJ(x509.get(), oid.get(), -1 /* search from beginning */); + if (location == -1) { + LOG(ERROR) << "Attestation extension not found in certificate"; + return {ErrorCode::UNKNOWN_ERROR, {}}; + } + + X509_EXTENSION* attest_rec_ext = X509_get_ext(x509.get(), location); + if (!attest_rec_ext) { + LOG(ERROR) << "Found extension but couldn't retrieve it. Probably BoringSSL bug."; + return {ErrorCode::UNKNOWN_ERROR, {}}; + } + + ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext); + if (!attest_rec_ext) { + LOG(ERROR) << "Attestation extension contained no data"; + return {ErrorCode::UNKNOWN_ERROR, {}}; + } + + p = attest_rec->data; + KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, attest_rec->length)); + if (!record.get()) return {ErrorCode::UNKNOWN_ERROR, {}}; + + AttestationRecord result; + + result.attestation_version = ASN1_INTEGER_get(record->attestation_version); + result.attestation_security_level = + static_cast(ASN1_ENUMERATED_get(record->attestation_security_level)); + result.keymaster_version = ASN1_INTEGER_get(record->keymaster_version); + result.keymaster_security_level = + static_cast(ASN1_ENUMERATED_get(record->keymaster_security_level)); + + auto& chall = record->attestation_challenge; + result.attestation_challenge.resize(chall->length); + memcpy(result.attestation_challenge.data(), chall->data, chall->length); + auto& uid = record->unique_id; + result.unique_id.resize(uid->length); + memcpy(result.unique_id.data(), uid->data, uid->length); + + ErrorCode error = extract_auth_list(record->software_enforced, &result.software_enforced); + if (error != ErrorCode::OK) return {error, {}}; + + error = extract_auth_list(record->tee_enforced, &result.hardware_enforced); + if (error != ErrorCode::OK) return {error, {}}; + + KM_ROOT_OF_TRUST* root_of_trust = nullptr; + if (record->tee_enforced && record->tee_enforced->root_of_trust) { + root_of_trust = record->tee_enforced->root_of_trust; + } else if (record->software_enforced && record->software_enforced->root_of_trust) { + root_of_trust = record->software_enforced->root_of_trust; + } else { + LOG(ERROR) << AT << " Failed root of trust parsing"; + return {ErrorCode::INVALID_ARGUMENT, {}}; + } + if (!root_of_trust->verified_boot_key) { + LOG(ERROR) << AT << " Failed verified boot key parsing"; + return {ErrorCode::INVALID_ARGUMENT, {}}; + } + + RootOfTrust& rot = result.root_of_trust; + auto& vb_key = root_of_trust->verified_boot_key; + rot.verified_boot_key.resize(vb_key->length); + memcpy(rot.verified_boot_key.data(), vb_key->data, vb_key->length); + + rot.verified_boot_state = static_cast( + ASN1_ENUMERATED_get(root_of_trust->verified_boot_state)); + rot.device_locked = root_of_trust->device_locked; + + auto& vb_hash = root_of_trust->verified_boot_hash; + if (!vb_hash) { + LOG(ERROR) << AT << " Failed verified boot hash parsing"; + return {ErrorCode::INVALID_ARGUMENT, {}}; + } + rot.verified_boot_hash.resize(vb_hash->length); + memcpy(rot.verified_boot_hash.data(), vb_hash->data, vb_hash->length); + + return {ErrorCode::OK, result}; +} + +} // namespace V4_1 +} // namespace keymaster +} // namespace hardware +} // namespace android diff --git a/keymaster/4.1/support/include/keymasterV4_1/attestation_record.h b/keymaster/4.1/support/include/keymasterV4_1/attestation_record.h new file mode 100644 index 0000000000..b543bddf13 --- /dev/null +++ b/keymaster/4.1/support/include/keymasterV4_1/attestation_record.h @@ -0,0 +1,57 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace keymaster { +namespace V4_1 { + +using V4_0::kAttestionRecordOid; +using V4_0::keymaster_verified_boot_t; + +struct RootOfTrust { + SecurityLevel security_level; + hidl_vec verified_boot_key; + hidl_vec verified_boot_hash; + keymaster_verified_boot_t verified_boot_state; + bool device_locked; +}; + +struct AttestationRecord { + RootOfTrust root_of_trust; + uint32_t attestation_version; + SecurityLevel attestation_security_level; + uint32_t keymaster_version; + SecurityLevel keymaster_security_level; + hidl_vec attestation_challenge; + AuthorizationSet software_enforced; + AuthorizationSet hardware_enforced; + hidl_vec unique_id; +}; + +std::tuple parse_attestation_record(const hidl_vec& cert); + +} // namespace V4_1 +} // namespace keymaster +} // namespace hardware +} // namespace android diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h index 6ffe8e104e..a90ad8ef14 100644 --- a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h +++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h @@ -26,10 +26,13 @@ namespace android::hardware::keymaster::V4_1 { using V4_0::BlockMode; using V4_0::Digest; using V4_0::EcCurve; -using V4_0::ErrorCode; using V4_0::HardwareAuthToken; +using V4_0::KeyCharacteristics; +using V4_0::KeyOrigin; using V4_0::KeyParameter; +using V4_0::KeyPurpose; using V4_0::PaddingMode; +using V4_0::SecurityLevel; using V4_0::TagType; using V4_0::VerificationToken; diff --git a/keymaster/4.1/vts/functional/Android.bp b/keymaster/4.1/vts/functional/Android.bp index f5a0c9c1aa..c2d7fa3547 100644 --- a/keymaster/4.1/vts/functional/Android.bp +++ b/keymaster/4.1/vts/functional/Android.bp @@ -19,12 +19,24 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: [ "EarlyBootKeyTest.cpp", + "DeviceUniqueAttestationTest.cpp", + "Keymaster4_1HidlTest.cpp", + "UnlockedDeviceRequiredTest.cpp", ], static_libs: [ "android.hardware.keymaster@4.0", "android.hardware.keymaster@4.1", - "libkeymaster4support", + "libcrypto_static", "libkeymaster4_1support", + "libkeymaster4support", + "libkeymaster4vtstest", + ], + cflags: [ + "-Wall", + "-O0", + ], + test_suites: [ + "general-tests", + "vts-core", ], - test_suites: ["vts-core"], } diff --git a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp new file mode 100644 index 0000000000..7ea3275851 --- /dev/null +++ b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp @@ -0,0 +1,278 @@ +/* + * 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 "Keymaster4_1HidlTest.h" + +#include + +#include + +#include +#include + +namespace android::hardware::keymaster::V4_0 { + +bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) { + return std::equal(a.begin(), a.end(), b.begin(), b.end()); +} + +} // namespace android::hardware::keymaster::V4_0 + +namespace android::hardware::keymaster::V4_1 { + +inline ::std::ostream& operator<<(::std::ostream& os, Tag tag) { + return os << toString(tag); +} + +namespace test { + +using std::string; +using std::tuple; + +namespace { + +char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + +string bin2hex(const hidl_vec& data) { + string retval; + retval.reserve(data.size() * 2 + 1); + for (uint8_t byte : data) { + retval.push_back(nibble2hex[0x0F & (byte >> 4)]); + retval.push_back(nibble2hex[0x0F & byte]); + } + return retval; +} + +struct AuthorizationSetDifferences { + string aName; + string bName; + AuthorizationSet aWhackB; + AuthorizationSet bWhackA; +}; + +std::ostream& operator<<(std::ostream& o, const AuthorizationSetDifferences& diffs) { + if (!diffs.aWhackB.empty()) { + o << "Set " << diffs.aName << " contains the following that " << diffs.bName << " does not" + << diffs.aWhackB; + if (!diffs.bWhackA.empty()) o << std::endl; + } + + if (!diffs.bWhackA.empty()) { + o << "Set " << diffs.bName << " contains the following that " << diffs.aName << " does not" + << diffs.bWhackA; + } + return o; +} + +// Computes and returns a \ b and b \ a ('\' is the set-difference operator, a \ b means all the +// elements that are in a but not b, i.e. take a and whack all the elements in b) to the provided +// stream. The sets must be sorted. +// +// This provides a simple and clear view of how the two sets differ, generally much +// easier than scrutinizing printouts of the two sets. +AuthorizationSetDifferences difference(string aName, const AuthorizationSet& a, string bName, + const AuthorizationSet& b) { + AuthorizationSetDifferences diffs = {std::move(aName), std::move(bName), {}, {}}; + std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(diffs.aWhackB)); + std::set_difference(b.begin(), b.end(), a.begin(), a.end(), std::back_inserter(diffs.bWhackA)); + return diffs; +} + +#define DIFFERENCE(a, b) difference(#a, a, #b, b) + +void check_root_of_trust(const RootOfTrust& root_of_trust) { + char vb_meta_device_state[PROPERTY_VALUE_MAX]; + if (property_get("ro.boot.vbmeta.device_state", vb_meta_device_state, "") == 0) return; + + char vb_meta_digest[PROPERTY_VALUE_MAX]; + EXPECT_GT(property_get("ro.boot.vbmeta.digest", vb_meta_digest, ""), 0); + EXPECT_EQ(vb_meta_digest, bin2hex(root_of_trust.verified_boot_hash)); + + // Verified boot key should be all 0's if the boot state is not verified or self signed + HidlBuf empty_boot_key(string(32, '\0')); + + char vb_meta_bootstate[PROPERTY_VALUE_MAX]; + auto& verified_boot_key = root_of_trust.verified_boot_key; + auto& verified_boot_state = root_of_trust.verified_boot_state; + EXPECT_GT(property_get("ro.boot.verifiedbootstate", vb_meta_bootstate, ""), 0); + if (!strcmp(vb_meta_bootstate, "green")) { + EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_VERIFIED); + EXPECT_NE(verified_boot_key, empty_boot_key); + } else if (!strcmp(vb_meta_bootstate, "yellow")) { + EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_SELF_SIGNED); + EXPECT_NE(verified_boot_key, empty_boot_key); + } else if (!strcmp(vb_meta_bootstate, "orange")) { + EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_UNVERIFIED); + EXPECT_EQ(verified_boot_key, empty_boot_key); + } else if (!strcmp(vb_meta_bootstate, "red")) { + EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_FAILED); + } else { + EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_UNVERIFIED); + EXPECT_EQ(verified_boot_key, empty_boot_key); + } +} + +void check_attestation_record(AttestationRecord attestation, const HidlBuf& challenge, + AuthorizationSet expected_sw_enforced, + AuthorizationSet expected_hw_enforced, + SecurityLevel expected_security_level) { + EXPECT_EQ(41U, attestation.keymaster_version); + EXPECT_EQ(4U, attestation.attestation_version); + EXPECT_EQ(expected_security_level, attestation.attestation_security_level); + EXPECT_EQ(expected_security_level, attestation.keymaster_security_level); + EXPECT_EQ(challenge, attestation.attestation_challenge); + + check_root_of_trust(attestation.root_of_trust); + + // Sort all of the authorization lists, so that equality matching works. + expected_sw_enforced.Sort(); + expected_hw_enforced.Sort(); + attestation.software_enforced.Sort(); + attestation.hardware_enforced.Sort(); + + EXPECT_EQ(expected_sw_enforced, attestation.software_enforced) + << DIFFERENCE(expected_sw_enforced, attestation.software_enforced); + EXPECT_EQ(expected_hw_enforced, attestation.hardware_enforced) + << DIFFERENCE(expected_hw_enforced, attestation.hardware_enforced); +} + +} // namespace + +using std::string; +using DeviceUniqueAttestationTest = Keymaster4_1HidlTest; + +TEST_P(DeviceUniqueAttestationTest, StrongBoxOnly) { + if (SecLevel() != SecurityLevel::STRONGBOX) return; + + ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(2048, 65537) + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN) + .Authorization(TAG_INCLUDE_UNIQUE_ID)))); + + hidl_vec> cert_chain; + EXPECT_EQ(ErrorCode::UNIMPLEMENTED, + convert(AttestKey( + AuthorizationSetBuilder() + .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION) + .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge")) + .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")), + &cert_chain))); + CheckedDeleteKey(); + + ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(EcCurve::P_256) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_INCLUDE_UNIQUE_ID)))); + + EXPECT_EQ(ErrorCode::UNIMPLEMENTED, + convert(AttestKey( + AuthorizationSetBuilder() + .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge")) + .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")), + &cert_chain))); +} + +TEST_P(DeviceUniqueAttestationTest, Rsa) { + if (SecLevel() != SecurityLevel::STRONGBOX) return; + ASSERT_EQ(ErrorCode::OK, + convert(GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(2048, 65537) + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN) + .Authorization(TAG_CREATION_DATETIME, 1)))); + + hidl_vec> cert_chain; + HidlBuf challenge("challenge"); + HidlBuf app_id("foo"); + EXPECT_EQ(ErrorCode::OK, + convert(AttestKey(AuthorizationSetBuilder() + .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION) + .Authorization(TAG_ATTESTATION_CHALLENGE, challenge) + .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id), + &cert_chain))); + + EXPECT_EQ(1U, cert_chain.size()); + auto [err, attestation] = parse_attestation_record(cert_chain[0]); + EXPECT_EQ(ErrorCode::OK, err); + + check_attestation_record(attestation, challenge, + /* sw_enforced */ + AuthorizationSetBuilder() + .Authorization(TAG_CREATION_DATETIME, 1) + .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id), + /* hw_enforced */ + AuthorizationSetBuilder() + .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION) + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(2048, 65537) + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN) + .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED) + .Authorization(TAG_OS_VERSION, os_version()) + .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()), + SecLevel()); +} + +TEST_P(DeviceUniqueAttestationTest, Ecdsa) { + if (SecLevel() != SecurityLevel::STRONGBOX) return; + ASSERT_EQ(ErrorCode::OK, + convert(GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(256) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_CREATION_DATETIME, 1)))); + + hidl_vec> cert_chain; + HidlBuf challenge("challenge"); + HidlBuf app_id("foo"); + EXPECT_EQ(ErrorCode::OK, + convert(AttestKey(AuthorizationSetBuilder() + .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION) + .Authorization(TAG_ATTESTATION_CHALLENGE, challenge) + .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id), + &cert_chain))); + + EXPECT_EQ(1U, cert_chain.size()); + auto [err, attestation] = parse_attestation_record(cert_chain[0]); + EXPECT_EQ(ErrorCode::OK, err); + + check_attestation_record(attestation, challenge, + /* sw_enforced */ + AuthorizationSetBuilder() + .Authorization(TAG_CREATION_DATETIME, 1) + .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id), + /* hw_enforced */ + AuthorizationSetBuilder() + .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION) + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(256) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_EC_CURVE, EcCurve::P_256) + .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED) + .Authorization(TAG_OS_VERSION, os_version()) + .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()), + SecLevel()); +} + +INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(DeviceUniqueAttestationTest); + +} // namespace test +} // namespace android::hardware::keymaster::V4_1 diff --git a/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp b/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp index d1978a9cdf..a26c688be9 100644 --- a/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp +++ b/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp @@ -14,8 +14,78 @@ * limitations under the License. */ +#include "Keymaster4_1HidlTest.h" + +#include + namespace android::hardware::keymaster::V4_1::test { +using std::string; +using EarlyBootKeyTest = Keymaster4_1HidlTest; + +// Because VTS tests are run on fully-booted machines, we can only run negative tests for early boot +// keys, which cannot be created or used after /data is mounted. This is the only test we can run +// in the normal case. The positive test will have to be done by the Android system, when it +// creates/uses early boot keys during boot. It should fail to boot if the early boot key usage +// fails. +TEST_P(EarlyBootKeyTest, CannotCreateEarlyBootKeys) { + auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] = + CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::EARLY_BOOT_ENDED); + + CheckedDeleteKeyData(&aesKeyData); + CheckedDeleteKeyData(&hmacKeyData); + CheckedDeleteKeyData(&rsaKeyData); + CheckedDeleteKeyData(&ecdsaKeyData); +} + +// This is a more comprenhensive test, but it can only be run on a machine which is still in early +// boot stage, which no proper Android device is by the time we can run VTS. To use this, +// un-disable it and modify vold to remove the call to earlyBootEnded(). Running the test will end +// early boot, so you'll have to reboot between runs. +TEST_P(EarlyBootKeyTest, DISABLED_FullTest) { + // Should be able to create keys, since early boot has not ended + auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] = + CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::OK); + + // TAG_EARLY_BOOT_ONLY should be in hw-enforced. + EXPECT_TRUE(contains(aesKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY)); + EXPECT_TRUE(contains(hmacKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY)); + EXPECT_TRUE(contains(rsaKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY)); + EXPECT_TRUE(contains(ecdsaKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY)); + + // Should be able to use keys, since early boot has not ended + EXPECT_EQ(ErrorCode::OK, UseAesKey(aesKeyData.blob)); + EXPECT_EQ(ErrorCode::OK, UseHmacKey(hmacKeyData.blob)); + EXPECT_EQ(ErrorCode::OK, UseRsaKey(rsaKeyData.blob)); + EXPECT_EQ(ErrorCode::OK, UseEcdsaKey(ecdsaKeyData.blob)); + + // End early boot + Return earlyBootResult = keymaster().earlyBootEnded(); + EXPECT_TRUE(earlyBootResult.isOk()); + EXPECT_EQ(earlyBootResult, ErrorCode::OK); + + // Should not be able to use already-created keys. + EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseAesKey(aesKeyData.blob)); + EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseHmacKey(hmacKeyData.blob)); + EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseRsaKey(rsaKeyData.blob)); + EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseEcdsaKey(ecdsaKeyData.blob)); + + CheckedDeleteKeyData(&aesKeyData); + CheckedDeleteKeyData(&hmacKeyData); + CheckedDeleteKeyData(&rsaKeyData); + CheckedDeleteKeyData(&ecdsaKeyData); + + // Should not be able to create new keys + std::tie(aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData) = + CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::EARLY_BOOT_ENDED); + + CheckedDeleteKeyData(&aesKeyData); + CheckedDeleteKeyData(&hmacKeyData); + CheckedDeleteKeyData(&rsaKeyData); + CheckedDeleteKeyData(&ecdsaKeyData); +} + +INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(EarlyBootKeyTest); } // namespace android::hardware::keymaster::V4_1::test diff --git a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp new file mode 100644 index 0000000000..efedf284c3 --- /dev/null +++ b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#include "Keymaster4_1HidlTest.h" + +namespace android::hardware::keymaster::V4_1::test { + +using std::string; + +void Keymaster4_1HidlTest::SetUp() { + keymaster41_ = IKeymasterDevice::getService(GetParam()); + InitializeKeymaster(keymaster41_); +} + +auto Keymaster4_1HidlTest::ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation, + const string& message, const AuthorizationSet& in_params) + -> std::tuple { + AuthorizationSet begin_out_params; + V4_0::ErrorCode result = Begin(operation, key_blob, in_params, &begin_out_params, &op_handle_); + AuthorizationSet out_params(std::move(begin_out_params)); + if (result != V4_0::ErrorCode::OK) { + return {convert(result), {}, out_params}; + } + + string output; + size_t consumed = 0; + AuthorizationSet update_params; + AuthorizationSet update_out_params; + result = Update(op_handle_, update_params, message, &update_out_params, &output, &consumed); + out_params.push_back(update_out_params); + if (result != V4_0::ErrorCode::OK) { + return {convert(result), output, out_params}; + } + + string unused; + AuthorizationSet finish_params; + AuthorizationSet finish_out_params; + result = Finish(op_handle_, finish_params, message.substr(consumed), unused, &finish_out_params, + &output); + op_handle_ = V4_0::test::kOpHandleSentinel; + out_params.push_back(finish_out_params); + + return {convert(result), output, out_params}; +} + +} // namespace android::hardware::keymaster::V4_1::test diff --git a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h new file mode 100644 index 0000000000..6332c43200 --- /dev/null +++ b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h @@ -0,0 +1,158 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include +#include + +namespace android::hardware::keymaster::V4_1::test { + +using V4_0::test::HidlBuf; + +class Keymaster4_1HidlTest : public V4_0::test::KeymasterHidlTest { + public: + using super = V4_0::test::KeymasterHidlTest; + + ErrorCode convert(V4_0::ErrorCode error_code) { return static_cast(error_code); } + + // These methods hide the base class versions. + void SetUp(); + IKeymasterDevice& keymaster() { return *keymaster41_; }; + + struct KeyData { + HidlBuf blob; + KeyCharacteristics characteristics; + }; + + std::tuple GenerateKeyData(const AuthorizationSet& keyDescription) { + KeyData keyData; + ErrorCode errorCode = convert( + super::GenerateKey(keyDescription, &keyData.blob, &keyData.characteristics)); + return {errorCode, keyData}; + } + + void CheckedDeleteKeyData(KeyData* keyData) { CheckedDeleteKey(&keyData->blob); } + + template + std::tuple + CreateTestKeys(TagType tagToTest, ErrorCode expectedReturn) { + ErrorCode errorCode; + + /* AES */ + KeyData aesKeyData; + std::tie(errorCode, aesKeyData) = + GenerateKeyData(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(tagToTest) + .BlockMode(BlockMode::ECB) + .Padding(PaddingMode::NONE) + .Authorization(TAG_NO_AUTH_REQUIRED)); + EXPECT_EQ(expectedReturn, errorCode); + + /* HMAC */ + KeyData hmacKeyData; + std::tie(errorCode, hmacKeyData) = + GenerateKeyData(AuthorizationSetBuilder() + .HmacKey(128) + .Authorization(tagToTest) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 128) + .Authorization(TAG_NO_AUTH_REQUIRED)); + EXPECT_EQ(expectedReturn, errorCode); + + /* RSA */ + KeyData rsaKeyData; + std::tie(errorCode, rsaKeyData) = + GenerateKeyData(AuthorizationSetBuilder() + .RsaSigningKey(2048, 65537) + .Authorization(tagToTest) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_NO_AUTH_REQUIRED)); + EXPECT_EQ(expectedReturn, errorCode); + + /* ECDSA */ + KeyData ecdsaKeyData; + std::tie(errorCode, ecdsaKeyData) = + GenerateKeyData(AuthorizationSetBuilder() + .EcdsaSigningKey(256) + .Authorization(tagToTest) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_NO_AUTH_REQUIRED)); + EXPECT_EQ(expectedReturn, errorCode); + + return {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData}; + } + + std::tuple + ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation, const std::string& message, + const AuthorizationSet& in_params); + + ErrorCode UseAesKey(const HidlBuf& aesKeyBlob) { + auto [result, ciphertext, out_params] = ProcessMessage( + aesKeyBlob, KeyPurpose::ENCRYPT, "1234567890123456", + AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE)); + return result; + } + + ErrorCode UseHmacKey(const HidlBuf& hmacKeyBlob) { + auto [result, mac, out_params] = + ProcessMessage(hmacKeyBlob, KeyPurpose::SIGN, "1234567890123456", + AuthorizationSetBuilder().Authorization(TAG_MAC_LENGTH, 128)); + return result; + } + + ErrorCode UseRsaKey(const HidlBuf& rsaKeyBlob) { + std::string message(2048 / 8, 'a'); + auto [result, signature, out_params] = ProcessMessage( + rsaKeyBlob, KeyPurpose::SIGN, message, + AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)); + return result; + } + + ErrorCode UseEcdsaKey(const HidlBuf& ecdsaKeyBlob) { + auto [result, signature, out_params] = + ProcessMessage(ecdsaKeyBlob, KeyPurpose::SIGN, "a", + AuthorizationSetBuilder().Digest(Digest::SHA_2_256)); + return result; + } + + static std::vector build_params() { + auto params = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor); + return params; + } + + private: + sp keymaster41_; +}; + +template +bool contains(hidl_vec& set, TypedTag typedTag) { + return std::find_if(set.begin(), set.end(), [&](const KeyParameter& param) { + return param.tag == static_cast(typedTag); + }) != set.end(); +} + +#define INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(name) \ + INSTANTIATE_TEST_SUITE_P(PerInstance, name, \ + testing::ValuesIn(Keymaster4_1HidlTest::build_params()), \ + android::hardware::PrintInstanceNameToString) + +} // namespace android::hardware::keymaster::V4_1::test diff --git a/keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp b/keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp new file mode 100644 index 0000000000..671bbbfe80 --- /dev/null +++ b/keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#include "Keymaster4_1HidlTest.h" + +#include + +namespace android::hardware::keymaster::V4_1::test { + +using UnlockedDeviceRequiredTest = Keymaster4_1HidlTest; + +// This may be a problematic test. It can't be run repeatedly without unlocking the device in +// between runs... and on most test devices there are no enrolled credentials so it can't be +// unlocked at all, meaning the only way to get the test to pass again on a properly-functioning +// device is to reboot it. For that reason, this is disabled by default. It can be used as part of +// a manual test process, which includes unlocking between runs, which is why it's included here. +// Well, that and the fact that it's the only test we can do without also making calls into the +// Gatekeeper HAL. We haven't written any cross-HAL tests, and don't know what all of the +// implications might be, so that may or may not be a solution. +// +// TODO(swillden): Use the Gatekeeper HAL to enroll some test credentials which we can verify to get +// an unlock auth token. If that works, enable the improved test. +TEST_P(UnlockedDeviceRequiredTest, DISABLED_KeysBecomeUnusable) { + auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] = + CreateTestKeys(TAG_UNLOCKED_DEVICE_REQUIRED, ErrorCode::OK); + + EXPECT_EQ(ErrorCode::OK, UseAesKey(aesKeyData.blob)); + EXPECT_EQ(ErrorCode::OK, UseHmacKey(hmacKeyData.blob)); + EXPECT_EQ(ErrorCode::OK, UseRsaKey(rsaKeyData.blob)); + EXPECT_EQ(ErrorCode::OK, UseEcdsaKey(ecdsaKeyData.blob)); + + Return rc = + keymaster().deviceLocked(false /* passwordOnly */, {} /* verificationToken */); + ASSERT_TRUE(rc.isOk()); + ASSERT_EQ(ErrorCode::OK, static_cast(rc)); + + EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseAesKey(aesKeyData.blob)); + EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseHmacKey(hmacKeyData.blob)); + EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseRsaKey(rsaKeyData.blob)); + EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseEcdsaKey(ecdsaKeyData.blob)); + + CheckedDeleteKeyData(&aesKeyData); + CheckedDeleteKeyData(&hmacKeyData); + CheckedDeleteKeyData(&rsaKeyData); + CheckedDeleteKeyData(&ecdsaKeyData); +} + +INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(UnlockedDeviceRequiredTest); + +} // namespace android::hardware::keymaster::V4_1::test From 3d035b9c0ba1dfc508e10e65e8c63ee458e4ab91 Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Thu, 16 Jan 2020 13:07:36 -0700 Subject: [PATCH 0454/1022] Add support lib wrappers for clients Test: CtsKeystoreTestCases Change-Id: I0157df310f85d83cef07282ea80204c035626518 --- keymaster/4.0/support/Android.bp | 10 +- .../include/keymasterV4_0/Keymaster4.h | 160 -------------- keymaster/4.1/default/Android.bp | 1 + keymaster/4.1/support/Android.bp | 8 + keymaster/{4.0 => 4.1}/support/Keymaster.cpp | 50 ++--- keymaster/{4.0 => 4.1}/support/Keymaster3.cpp | 71 +++---- keymaster/{4.0 => 4.1}/support/Keymaster4.cpp | 33 ++- .../include/keymasterV4_1}/Keymaster.h | 41 ++-- .../include/keymasterV4_1}/Keymaster3.h | 65 +++--- .../include/keymasterV4_1/Keymaster4.h | 197 ++++++++++++++++++ .../support/include/keymasterV4_1/Operation.h | 38 ++++ .../include/keymasterV4_1/authorization_set.h | 5 +- .../include/keymasterV4_1/keymaster_tags.h | 7 + .../include/keymasterV4_1/keymaster_utils.h | 26 +++ 14 files changed, 413 insertions(+), 299 deletions(-) delete mode 100644 keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h rename keymaster/{4.0 => 4.1}/support/Keymaster.cpp (85%) rename keymaster/{4.0 => 4.1}/support/Keymaster3.cpp (81%) rename keymaster/{4.0 => 4.1}/support/Keymaster4.cpp (54%) rename keymaster/{4.0/support/include/keymasterV4_0 => 4.1/support/include/keymasterV4_1}/Keymaster.h (73%) rename keymaster/{4.0/support/include/keymasterV4_0 => 4.1/support/include/keymasterV4_1}/Keymaster3.h (72%) create mode 100644 keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h create mode 100644 keymaster/4.1/support/include/keymasterV4_1/Operation.h create mode 100644 keymaster/4.1/support/include/keymasterV4_1/keymaster_utils.h diff --git a/keymaster/4.0/support/Android.bp b/keymaster/4.0/support/Android.bp index 2f40282351..9c5fbab735 100644 --- a/keymaster/4.0/support/Android.bp +++ b/keymaster/4.0/support/Android.bp @@ -27,11 +27,10 @@ cc_library { "authorization_set.cpp", "key_param_output.cpp", "keymaster_utils.cpp", - "Keymaster.cpp", - "Keymaster3.cpp", - "Keymaster4.cpp", ], - export_include_dirs: ["include"], + export_include_dirs: [ + "include", + ], shared_libs: [ "android.hardware.keymaster@3.0", "android.hardware.keymaster@4.0", @@ -39,6 +38,5 @@ cc_library { "libcrypto", "libhardware", "libhidlbase", - "libutils", - ] + ], } diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h deleted file mode 100644 index dfd03ef69f..0000000000 --- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - ** - ** Copyright 2017, 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 HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_ -#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_ - -#include "Keymaster.h" - -namespace android { -namespace hardware { -namespace keymaster { -namespace V4_0 { -namespace support { - -using android::sp; -using IKeymaster4Device = ::android::hardware::keymaster::V4_0::IKeymasterDevice; - -class Keymaster4 : public Keymaster { - public: - using WrappedIKeymasterDevice = IKeymaster4Device; - Keymaster4(sp km4_dev, const hidl_string& instanceName) - : Keymaster(IKeymaster4Device::descriptor, instanceName), - haveVersion_(false), - dev_(km4_dev) {} - - const VersionResult& halVersion() const override { - const_cast(this)->getVersionIfNeeded(); - return version_; - } - - Return getHardwareInfo(getHardwareInfo_cb _hidl_cb) override { - return dev_->getHardwareInfo(_hidl_cb); - } - - Return getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override { - return dev_->getHmacSharingParameters(_hidl_cb); - } - - Return computeSharedHmac(const hidl_vec& params, - computeSharedHmac_cb _hidl_cb) override { - return dev_->computeSharedHmac(params, _hidl_cb); - } - - Return verifyAuthorization(uint64_t operationHandle, const hidl_vec& params, - const HardwareAuthToken& authToken, - verifyAuthorization_cb _hidl_cb) override { - return dev_->verifyAuthorization(operationHandle, params, authToken, _hidl_cb); - } - - Return addRngEntropy(const hidl_vec& data) override { - return dev_->addRngEntropy(data); - } - - Return generateKey(const hidl_vec& keyParams, - generateKey_cb _hidl_cb) override { - return dev_->generateKey(keyParams, _hidl_cb); - } - - Return getKeyCharacteristics(const hidl_vec& keyBlob, - const hidl_vec& clientId, - const hidl_vec& appData, - getKeyCharacteristics_cb _hidl_cb) override { - return dev_->getKeyCharacteristics(keyBlob, clientId, appData, _hidl_cb); - } - - Return importKey(const hidl_vec& params, KeyFormat keyFormat, - const hidl_vec& keyData, importKey_cb _hidl_cb) override { - return dev_->importKey(params, keyFormat, keyData, _hidl_cb); - } - - Return importWrappedKey(const hidl_vec& wrappedKeyData, - const hidl_vec& wrappingKeyBlob, - const hidl_vec& maskingKey, - const hidl_vec& unwrappingParams, - uint64_t passwordSid, uint64_t biometricSid, - importWrappedKey_cb _hidl_cb) { - return dev_->importWrappedKey(wrappedKeyData, wrappingKeyBlob, maskingKey, unwrappingParams, - passwordSid, biometricSid, _hidl_cb); - } - - Return exportKey(KeyFormat exportFormat, const hidl_vec& keyBlob, - const hidl_vec& clientId, const hidl_vec& appData, - exportKey_cb _hidl_cb) override { - return dev_->exportKey(exportFormat, keyBlob, clientId, appData, _hidl_cb); - } - - Return attestKey(const hidl_vec& keyToAttest, - const hidl_vec& attestParams, - attestKey_cb _hidl_cb) override { - return dev_->attestKey(keyToAttest, attestParams, _hidl_cb); - } - - Return upgradeKey(const hidl_vec& keyBlobToUpgrade, - const hidl_vec& upgradeParams, - upgradeKey_cb _hidl_cb) override { - return dev_->upgradeKey(keyBlobToUpgrade, upgradeParams, _hidl_cb); - } - - Return deleteKey(const hidl_vec& keyBlob) override { - return dev_->deleteKey(keyBlob); - } - - Return deleteAllKeys() override { return dev_->deleteAllKeys(); } - - Return destroyAttestationIds() override { return dev_->destroyAttestationIds(); } - - Return begin(KeyPurpose purpose, const hidl_vec& key, - const hidl_vec& inParams, const HardwareAuthToken& authToken, - begin_cb _hidl_cb) override { - return dev_->begin(purpose, key, inParams, authToken, _hidl_cb); - } - - Return update(uint64_t operationHandle, const hidl_vec& inParams, - const hidl_vec& input, const HardwareAuthToken& authToken, - const VerificationToken& verificationToken, update_cb _hidl_cb) override { - return dev_->update(operationHandle, inParams, input, authToken, verificationToken, - _hidl_cb); - } - - Return finish(uint64_t operationHandle, const hidl_vec& inParams, - const hidl_vec& input, const hidl_vec& signature, - const HardwareAuthToken& authToken, - const VerificationToken& verificationToken, finish_cb _hidl_cb) override { - return dev_->finish(operationHandle, inParams, input, signature, authToken, - verificationToken, _hidl_cb); - } - - Return abort(uint64_t operationHandle) override { - return dev_->abort(operationHandle); - } - - private: - void getVersionIfNeeded(); - - bool haveVersion_; - VersionResult version_; - sp dev_; -}; - -} // namespace support -} // namespace V4_0 -} // namespace keymaster -} // namespace hardware -} // namespace android - -#endif // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_ diff --git a/keymaster/4.1/default/Android.bp b/keymaster/4.1/default/Android.bp index b06878bc77..27297b9e45 100644 --- a/keymaster/4.1/default/Android.bp +++ b/keymaster/4.1/default/Android.bp @@ -31,6 +31,7 @@ cc_binary { "libhidlbase", "libkeymaster4", "libkeymaster41", + "libkeymaster4_1support", "liblog", "libutils", ], diff --git a/keymaster/4.1/support/Android.bp b/keymaster/4.1/support/Android.bp index e4c3d47080..bdd0ca89ae 100644 --- a/keymaster/4.1/support/Android.bp +++ b/keymaster/4.1/support/Android.bp @@ -24,6 +24,9 @@ cc_library { ], srcs: [ "attestation_record.cpp", + "Keymaster.cpp", + "Keymaster3.cpp", + "Keymaster4.cpp", ], export_include_dirs: ["include"], shared_libs: [ @@ -34,5 +37,10 @@ cc_library { "libcrypto", "libhidlbase", "libkeymaster4support", + "libutils", + ], + export_shared_lib_headers: [ + "android.hardware.keymaster@4.1", + "libkeymaster4support", ], } diff --git a/keymaster/4.0/support/Keymaster.cpp b/keymaster/4.1/support/Keymaster.cpp similarity index 85% rename from keymaster/4.0/support/Keymaster.cpp rename to keymaster/4.1/support/Keymaster.cpp index f20f9511fc..ea6604e326 100644 --- a/keymaster/4.0/support/Keymaster.cpp +++ b/keymaster/4.1/support/Keymaster.cpp @@ -14,19 +14,18 @@ ** limitations under the License. */ -#include +#include #include #include #include -#include -#include #include #include +#include +#include -namespace android { -namespace hardware { +namespace android::hardware { template std::ostream& operator<<(std::ostream& os, const hidl_vec& vec) { @@ -57,6 +56,7 @@ std::ostream& operator<<(std::ostream& os, const hidl_array& vec) { } namespace keymaster { + namespace V4_0 { std::ostream& operator<<(std::ostream& os, const HmacSharingParameters& params) { @@ -66,7 +66,9 @@ std::ostream& operator<<(std::ostream& os, const HmacSharingParameters& params) return os; } -namespace support { +} // namespace V4_0 + +namespace V4_1::support { using ::android::sp; using ::android::hidl::manager::V1_2::IServiceManager; @@ -140,14 +142,14 @@ Keymaster::KeymasterSet Keymaster::enumerateAvailableDevices() { } static hidl_vec getHmacParameters( - const Keymaster::KeymasterSet& keymasters) { + const Keymaster::KeymasterSet& keymasters) { std::vector params_vec; params_vec.reserve(keymasters.size()); for (auto& keymaster : keymasters) { if (keymaster->halVersion().majorVersion < 4) continue; auto rc = keymaster->getHmacSharingParameters([&](auto error, auto& params) { - CHECK(error == ErrorCode::OK) - << "Failed to get HMAC parameters from " << *keymaster << " error " << error; + CHECK(error == V4_0::ErrorCode::OK) + << "Failed to get HMAC parameters from " << *keymaster << " error " << error; params_vec.push_back(params); }); CHECK(rc.isOk()) << "Failed to communicate with " << *keymaster @@ -169,18 +171,18 @@ static void computeHmac(const Keymaster::KeymasterSet& keymasters, if (keymaster->halVersion().majorVersion < 4) continue; LOG(DEBUG) << "Computing HMAC for " << *keymaster; auto rc = keymaster->computeSharedHmac( - params, [&](ErrorCode error, const hidl_vec& curSharingCheck) { - CHECK(error == ErrorCode::OK) - << "Failed to get HMAC parameters from " << *keymaster << " error " << error; - if (firstKeymaster) { - sharingCheck = curSharingCheck; - firstKeymaster = false; - } - if (curSharingCheck != sharingCheck) - LOG(WARNING) << "HMAC computation failed for " << *keymaster // - << " Expected: " << sharingCheck // - << " got: " << curSharingCheck; - }); + params, [&](V4_0::ErrorCode error, const hidl_vec& curSharingCheck) { + CHECK(error == V4_0::ErrorCode::OK) << "Failed to get HMAC parameters from " + << *keymaster << " error " << error; + if (firstKeymaster) { + sharingCheck = curSharingCheck; + firstKeymaster = false; + } + if (curSharingCheck != sharingCheck) + LOG(WARNING) << "HMAC computation failed for " << *keymaster // + << " Expected: " << sharingCheck // + << " got: " << curSharingCheck; + }); CHECK(rc.isOk()) << "Failed to communicate with " << *keymaster << " error: " << rc.description(); } @@ -190,8 +192,6 @@ void Keymaster::performHmacKeyAgreement(const KeymasterSet& keymasters) { computeHmac(keymasters, getHmacParameters(keymasters)); } -} // namespace support -} // namespace V4_0 +} // namespace V4_1::support } // namespace keymaster -} // namespace hardware -} // namespace android +} // namespace android::hardware diff --git a/keymaster/4.0/support/Keymaster3.cpp b/keymaster/4.1/support/Keymaster3.cpp similarity index 81% rename from keymaster/4.0/support/Keymaster3.cpp rename to keymaster/4.1/support/Keymaster3.cpp index b2cdbd9263..b6656895c7 100644 --- a/keymaster/4.0/support/Keymaster3.cpp +++ b/keymaster/4.1/support/Keymaster3.cpp @@ -15,23 +15,19 @@ ** limitations under the License. */ -#include +#include #include #include -namespace android { -namespace hardware { -namespace keymaster { -namespace V4_0 { -namespace support { +namespace android::hardware::keymaster::V4_1::support { using android::hardware::details::StatusOf; namespace { -ErrorCode convert(V3_0::ErrorCode error) { - return static_cast(error); +V4_0::ErrorCode convert(V3_0::ErrorCode error) { + return static_cast(error); } V3_0::KeyPurpose convert(KeyPurpose purpose) { @@ -53,7 +49,7 @@ V3_0::KeyParameter convert(const KeyParameter& param) { KeyParameter convert(const V3_0::KeyParameter& param) { KeyParameter converted; - converted.tag = static_cast(param.tag); + converted.tag = static_cast(param.tag); static_assert(sizeof(converted.f) == sizeof(param.f), "This function assumes sizes match"); memcpy(&converted.f, ¶m.f, sizeof(param.f)); converted.blob = param.blob; @@ -89,7 +85,7 @@ hidl_vec convertAndAddAuthToken(const hidl_vec converted[i] = convert(params[i]); } converted[params.size()].tag = V3_0::Tag::AUTH_TOKEN; - converted[params.size()].blob = authToken2HidlVec(authToken); + converted[params.size()].blob = V4_0::support::authToken2HidlVec(authToken); return converted; } @@ -107,16 +103,19 @@ void Keymaster3::getVersionIfNeeded() { if (haveVersion_) return; auto rc = km3_dev_->getHardwareFeatures( - [&](bool isSecure, bool supportsEllipticCurve, bool supportsSymmetricCryptography, - bool supportsAttestation, bool supportsAllDigests, const hidl_string& keymasterName, - const hidl_string& keymasterAuthorName) { - version_ = {keymasterName, keymasterAuthorName, 0 /* major version, filled below */, - isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE, - supportsEllipticCurve}; - supportsSymmetricCryptography_ = supportsSymmetricCryptography; - supportsAttestation_ = supportsAttestation; - supportsAllDigests_ = supportsAllDigests; - }); + [&](bool isSecure, bool supportsEllipticCurve, bool supportsSymmetricCryptography, + bool supportsAttestation, bool supportsAllDigests, const hidl_string& keymasterName, + const hidl_string& keymasterAuthorName) { + version_ = {keymasterName, + keymasterAuthorName, + 0 /* major version, filled below */, + 0 /* minor version */, + isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE, + supportsEllipticCurve}; + supportsSymmetricCryptography_ = supportsSymmetricCryptography; + supportsAttestation_ = supportsAttestation; + supportsAllDigests_ = supportsAllDigests; + }); CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware features"; @@ -139,10 +138,10 @@ Return Keymaster3::getHardwareInfo(Keymaster3::getHardwareInfo_cb _hidl_cb return Void(); } -Return Keymaster3::addRngEntropy(const hidl_vec& data) { +Return Keymaster3::addRngEntropy(const hidl_vec& data) { auto rc = km3_dev_->addRngEntropy(data); if (!rc.isOk()) { - return StatusOf(rc); + return StatusOf(rc); } return convert(rc); } @@ -215,21 +214,21 @@ Return Keymaster3::upgradeKey(const hidl_vec& keyBlobToUpgrade, return rc; } -Return Keymaster3::deleteKey(const hidl_vec& keyBlob) { +Return Keymaster3::deleteKey(const hidl_vec& keyBlob) { auto rc = km3_dev_->deleteKey(keyBlob); - if (!rc.isOk()) return StatusOf(rc); + if (!rc.isOk()) return StatusOf(rc); return convert(rc); } -Return Keymaster3::deleteAllKeys() { +Return Keymaster3::deleteAllKeys() { auto rc = km3_dev_->deleteAllKeys(); - if (!rc.isOk()) return StatusOf(rc); + if (!rc.isOk()) return StatusOf(rc); return convert(rc); } -Return Keymaster3::destroyAttestationIds() { +Return Keymaster3::destroyAttestationIds() { auto rc = km3_dev_->destroyAttestationIds(); - if (!rc.isOk()) return StatusOf(rc); + if (!rc.isOk()) return StatusOf(rc); return convert(rc); } @@ -242,7 +241,7 @@ Return Keymaster3::begin(KeyPurpose purpose, const hidl_vec& key, }; auto rc = - km3_dev_->begin(convert(purpose), key, convertAndAddAuthToken(inParams, authToken), cb); + km3_dev_->begin(convert(purpose), key, convertAndAddAuthToken(inParams, authToken), cb); rc.isOk(); // move ctor prereq return rc; } @@ -256,8 +255,8 @@ Return Keymaster3::update(uint64_t operationHandle, const hidl_vecupdate(operationHandle, convertAndAddAuthToken(inParams, authToken), input, cb); + auto rc = km3_dev_->update(operationHandle, convertAndAddAuthToken(inParams, authToken), input, + cb); rc.isOk(); // move ctor prereq return rc; } @@ -278,14 +277,10 @@ Return Keymaster3::finish(uint64_t operationHandle, const hidl_vec Keymaster3::abort(uint64_t operationHandle) { +Return Keymaster3::abort(uint64_t operationHandle) { auto rc = km3_dev_->abort(operationHandle); - if (!rc.isOk()) return StatusOf(rc); + if (!rc.isOk()) return StatusOf(rc); return convert(rc); } -} // namespace support -} // namespace V4_0 -} // namespace keymaster -} // namespace hardware -} // namespace android +} // namespace android::hardware::keymaster::V4_1::support diff --git a/keymaster/4.0/support/Keymaster4.cpp b/keymaster/4.1/support/Keymaster4.cpp similarity index 54% rename from keymaster/4.0/support/Keymaster4.cpp rename to keymaster/4.1/support/Keymaster4.cpp index cc3d656f07..33f4bb1037 100644 --- a/keymaster/4.0/support/Keymaster4.cpp +++ b/keymaster/4.1/support/Keymaster4.cpp @@ -1,5 +1,4 @@ /* -** ** Copyright 2017, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,32 +14,28 @@ ** limitations under the License. */ -#include +#include #include -namespace android { -namespace hardware { -namespace keymaster { -namespace V4_0 { -namespace support { +namespace android::hardware::keymaster::V4_1::support { void Keymaster4::getVersionIfNeeded() { if (haveVersion_) return; - auto rc = - dev_->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& keymasterName, - const hidl_string& authorName) { - version_ = {keymasterName, authorName, 4 /* major version */, securityLevel, - true /* supportsEc */}; - haveVersion_ = true; - }); + auto rc = km4_0_dev_->getHardwareInfo([&](SecurityLevel securityLevel, + const hidl_string& keymasterName, + const hidl_string& authorName) { + version_ = {keymasterName, + authorName, + 4 /* major version */, + static_cast((km4_1_dev_) ? 1 : 0) /* minor version */, + securityLevel, + true /* supportsEc */}; + haveVersion_ = true; + }); CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware info"; } -} // namespace support -} // namespace V4_0 -} // namespace keymaster -} // namespace hardware -} // namespace android +} // namespace android::hardware::keymaster::V4_1::support diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster.h similarity index 73% rename from keymaster/4.0/support/include/keymasterV4_0/Keymaster.h rename to keymaster/4.1/support/include/keymasterV4_1/Keymaster.h index ad83f17106..1f49e184e6 100644 --- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h +++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster.h @@ -15,28 +15,28 @@ ** limitations under the License. */ -#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_ -#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_ - -#include +#pragma once #include #include -namespace android { -namespace hardware { -namespace keymaster { -namespace V4_0 { -namespace support { +#include +#include + +namespace android::hardware::keymaster::V4_1::support { /** - * Keymaster abstracts the underlying V4_0::IKeymasterDevice. There is one implementation - * (Keymaster4) which is a trivial passthrough and one that wraps a V3_0::IKeymasterDevice. + * Keymaster abstracts the underlying V4_1::IKeymasterDevice. There are two implementations, + * Keymaster3 which wraps a V3_0::IKeymasterDevice and Keymaster4, which wraps either a + * V4_0::IKeymasterDevice or a V4_1::IKeymasterDevice. There is a V3_0::IKeymasterDevice + * implementation that is used to wrap pre-HIDL keymaster implementations, and Keymaster3 will wrap + * that. * * The reason for adding this additional layer, rather than simply using the latest HAL directly and * subclassing it to wrap any older HAL, is because this provides a place to put additional methods * which clients can use when they need to distinguish between different underlying HAL versions, - * while still having to use only the latest interface. + * while still having to use only the latest interface. Plus it's a handy place to keep some + * convenience methods. */ class Keymaster : public IKeymasterDevice { public: @@ -50,12 +50,14 @@ class Keymaster : public IKeymasterDevice { hidl_string keymasterName; hidl_string authorName; uint8_t majorVersion; + uint8_t minorVersion; SecurityLevel securityLevel; bool supportsEc; bool operator>(const VersionResult& other) const { - auto lhs = std::tie(securityLevel, majorVersion, supportsEc); - auto rhs = std::tie(other.securityLevel, other.majorVersion, other.supportsEc); + auto lhs = std::tie(securityLevel, majorVersion, minorVersion, supportsEc); + auto rhs = std::tie(other.securityLevel, other.majorVersion, other.minorVersion, + other.supportsEc); return lhs > rhs; } }; @@ -69,6 +71,9 @@ class Keymaster : public IKeymasterDevice { * There are no side effects otherwise. */ void logIfKeymasterVendorError(ErrorCode ec) const; + void logIfKeymasterVendorError(V4_0::ErrorCode ec) const { + logIfKeymasterVendorError(static_cast(ec)); + } /** * Returns all available Keymaster3 and Keymaster4 instances, in order of most secure to least @@ -93,10 +98,4 @@ class Keymaster : public IKeymasterDevice { std::ostream& operator<<(std::ostream& os, const Keymaster& keymaster); -} // namespace support -} // namespace V4_0 -} // namespace keymaster -} // namespace hardware -} // namespace android - -#endif // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_ +} // namespace android::hardware::keymaster::V4_1::support diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h similarity index 72% rename from keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h rename to keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h index c40be7c757..c201e8c0b2 100644 --- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h +++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h @@ -1,5 +1,4 @@ /* - ** ** Copyright 2017, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,18 +14,14 @@ ** limitations under the License. */ -#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_ -#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_ +#pragma once #include #include "Keymaster.h" +#include "Operation.h" -namespace android { -namespace hardware { -namespace keymaster { -namespace V4_0 { -namespace support { +namespace android::hardware::keymaster::V4_1::support { using IKeymaster3Device = ::android::hardware::keymaster::V3_0::IKeymasterDevice; @@ -38,8 +33,10 @@ using ::android::hardware::Void; using ::android::hardware::details::return_status; class Keymaster3 : public Keymaster { - public: + public: + // This definition is used for device enumeration. using WrappedIKeymasterDevice = IKeymaster3Device; + Keymaster3(sp km3_dev, const hidl_string& instanceName) : Keymaster(IKeymaster3Device::descriptor, instanceName), km3_dev_(km3_dev), @@ -53,24 +50,24 @@ class Keymaster3 : public Keymaster { Return getHardwareInfo(getHardwareInfo_cb _hidl_cb); Return getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override { - _hidl_cb(ErrorCode::UNIMPLEMENTED, {}); + _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {}); return Void(); } Return computeSharedHmac(const hidl_vec&, computeSharedHmac_cb _hidl_cb) override { - _hidl_cb(ErrorCode::UNIMPLEMENTED, {}); + _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {}); return Void(); } Return verifyAuthorization(uint64_t, const hidl_vec&, const HardwareAuthToken&, verifyAuthorization_cb _hidl_cb) override { - _hidl_cb(ErrorCode::UNIMPLEMENTED, {}); + _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {}); return Void(); } - Return addRngEntropy(const hidl_vec& data) override; + Return addRngEntropy(const hidl_vec& data) override; Return generateKey(const hidl_vec& keyParams, generateKey_cb _hidl_cb) override; Return getKeyCharacteristics(const hidl_vec& keyBlob, @@ -86,7 +83,7 @@ class Keymaster3 : public Keymaster { const hidl_vec& /* unwrappingParams */, uint64_t /* passwordSid */, uint64_t /* biometricSid */, importWrappedKey_cb _hidl_cb) { - _hidl_cb(ErrorCode::UNIMPLEMENTED, {}, {}); + _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {}, {}); return Void(); } @@ -99,9 +96,9 @@ class Keymaster3 : public Keymaster { Return upgradeKey(const hidl_vec& keyBlobToUpgrade, const hidl_vec& upgradeParams, upgradeKey_cb _hidl_cb) override; - Return deleteKey(const hidl_vec& keyBlob) override; - Return deleteAllKeys() override; - Return destroyAttestationIds() override; + Return deleteKey(const hidl_vec& keyBlob) override; + Return deleteAllKeys() override; + Return destroyAttestationIds() override; Return begin(KeyPurpose purpose, const hidl_vec& key, const hidl_vec& inParams, const HardwareAuthToken& authToken, begin_cb _hidl_cb) override; @@ -112,9 +109,31 @@ class Keymaster3 : public Keymaster { const hidl_vec& input, const hidl_vec& signature, const HardwareAuthToken& authToken, const VerificationToken& verificationToken, finish_cb _hidl_cb) override; - Return abort(uint64_t operationHandle) override; + Return abort(uint64_t operationHandle) override; - private: + /********************************** + * V4_1::IKeymasterDevice methods * + *********************************/ + + Return deviceLocked(bool /* passwordOnly */, + const VerificationToken& /* verificationToken */) override { + return ErrorCode::UNIMPLEMENTED; + } + + Return earlyBootEnded() override { return ErrorCode::UNIMPLEMENTED; } + + Return beginOp(KeyPurpose purpose, const hidl_vec& keyBlob, + const hidl_vec& inParams, const HardwareAuthToken& authToken, + beginOp_cb _hidl_cb) override { + return begin(purpose, keyBlob, inParams, authToken, + [&_hidl_cb](V4_0::ErrorCode errorCode, const hidl_vec& outParams, + OperationHandle operationHandle) { + _hidl_cb(static_cast(errorCode), outParams, + new Operation(operationHandle)); + }); + } + + private: void getVersionIfNeeded(); sp km3_dev_; @@ -126,10 +145,4 @@ class Keymaster3 : public Keymaster { bool supportsAllDigests_; }; -} // namespace support -} // namespace V4_0 -} // namespace keymaster -} // namespace hardware -} // namespace android - -#endif // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_ +} // namespace android::hardware::keymaster::V4_1::support diff --git a/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h new file mode 100644 index 0000000000..6d74d980a0 --- /dev/null +++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h @@ -0,0 +1,197 @@ +/* + ** Copyright 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. + */ + +#pragma once + +#include "Keymaster.h" +#include "Operation.h" + +namespace android::hardware::keymaster::V4_1::support { + +using android::sp; + +/** + * This class can wrap either a V4_0 or V4_1 IKeymasterDevice. + */ +class Keymaster4 : public Keymaster { + public: + // This definition is used for device enumeration; enumerating 4.0 devices will also + // enumerate 4.1. devices. + using WrappedIKeymasterDevice = V4_0::IKeymasterDevice; + + Keymaster4(sp km4_1_dev, const hidl_string& instanceName) + : Keymaster(V4_1::IKeymasterDevice::descriptor, instanceName), + haveVersion_(false), + km4_0_dev_(km4_1_dev), + km4_1_dev_(km4_1_dev) {} + + Keymaster4(sp km4_0_dev, const hidl_string& instanceName) + : Keymaster(V4_1::IKeymasterDevice::descriptor, instanceName), + haveVersion_(false), + km4_0_dev_(km4_0_dev), + km4_1_dev_() {} + + const VersionResult& halVersion() const override { + const_cast(this)->getVersionIfNeeded(); + return version_; + } + + /********************************** + * V4_0::IKeymasterDevice methods * + *********************************/ + + Return getHardwareInfo(getHardwareInfo_cb _hidl_cb) override { + return km4_0_dev_->getHardwareInfo(_hidl_cb); + } + + Return getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override { + return km4_0_dev_->getHmacSharingParameters(_hidl_cb); + } + + Return computeSharedHmac(const hidl_vec& params, + computeSharedHmac_cb _hidl_cb) override { + return km4_0_dev_->computeSharedHmac(params, _hidl_cb); + } + + Return verifyAuthorization(uint64_t operationHandle, const hidl_vec& params, + const HardwareAuthToken& authToken, + verifyAuthorization_cb _hidl_cb) override { + return km4_0_dev_->verifyAuthorization(operationHandle, params, authToken, _hidl_cb); + } + + Return addRngEntropy(const hidl_vec& data) override { + return km4_0_dev_->addRngEntropy(data); + } + + Return generateKey(const hidl_vec& keyParams, + generateKey_cb _hidl_cb) override { + return km4_0_dev_->generateKey(keyParams, _hidl_cb); + } + + Return getKeyCharacteristics(const hidl_vec& keyBlob, + const hidl_vec& clientId, + const hidl_vec& appData, + getKeyCharacteristics_cb _hidl_cb) override { + return km4_0_dev_->getKeyCharacteristics(keyBlob, clientId, appData, _hidl_cb); + } + + Return importKey(const hidl_vec& params, KeyFormat keyFormat, + const hidl_vec& keyData, importKey_cb _hidl_cb) override { + return km4_0_dev_->importKey(params, keyFormat, keyData, _hidl_cb); + } + + Return importWrappedKey(const hidl_vec& wrappedKeyData, + const hidl_vec& wrappingKeyBlob, + const hidl_vec& maskingKey, + const hidl_vec& unwrappingParams, + uint64_t passwordSid, uint64_t biometricSid, + importWrappedKey_cb _hidl_cb) { + return km4_0_dev_->importWrappedKey(wrappedKeyData, wrappingKeyBlob, maskingKey, + unwrappingParams, passwordSid, biometricSid, _hidl_cb); + } + + Return exportKey(KeyFormat exportFormat, const hidl_vec& keyBlob, + const hidl_vec& clientId, const hidl_vec& appData, + exportKey_cb _hidl_cb) override { + return km4_0_dev_->exportKey(exportFormat, keyBlob, clientId, appData, _hidl_cb); + } + + Return attestKey(const hidl_vec& keyToAttest, + const hidl_vec& attestParams, + attestKey_cb _hidl_cb) override { + return km4_0_dev_->attestKey(keyToAttest, attestParams, _hidl_cb); + } + + Return upgradeKey(const hidl_vec& keyBlobToUpgrade, + const hidl_vec& upgradeParams, + upgradeKey_cb _hidl_cb) override { + return km4_0_dev_->upgradeKey(keyBlobToUpgrade, upgradeParams, _hidl_cb); + } + + Return deleteKey(const hidl_vec& keyBlob) override { + return km4_0_dev_->deleteKey(keyBlob); + } + + Return deleteAllKeys() override { return km4_0_dev_->deleteAllKeys(); } + + Return destroyAttestationIds() override { + return km4_0_dev_->destroyAttestationIds(); + } + + Return begin(KeyPurpose purpose, const hidl_vec& key, + const hidl_vec& inParams, const HardwareAuthToken& authToken, + begin_cb _hidl_cb) override { + return km4_0_dev_->begin(purpose, key, inParams, authToken, _hidl_cb); + } + + Return update(uint64_t operationHandle, const hidl_vec& inParams, + const hidl_vec& input, const HardwareAuthToken& authToken, + const VerificationToken& verificationToken, update_cb _hidl_cb) override { + return km4_0_dev_->update(operationHandle, inParams, input, authToken, verificationToken, + _hidl_cb); + } + + Return finish(uint64_t operationHandle, const hidl_vec& inParams, + const hidl_vec& input, const hidl_vec& signature, + const HardwareAuthToken& authToken, + const VerificationToken& verificationToken, finish_cb _hidl_cb) override { + return km4_0_dev_->finish(operationHandle, inParams, input, signature, authToken, + verificationToken, _hidl_cb); + } + + Return abort(uint64_t operationHandle) override { + return km4_0_dev_->abort(operationHandle); + } + + /********************************** + * V4_1::IKeymasterDevice methods * + *********************************/ + + Return deviceLocked(bool passwordOnly, + const VerificationToken& verificationToken) override { + if (km4_1_dev_) return km4_1_dev_->deviceLocked(passwordOnly, verificationToken); + return ErrorCode::UNIMPLEMENTED; + } + + Return earlyBootEnded() override { + if (km4_1_dev_) return km4_1_dev_->earlyBootEnded(); + return ErrorCode::UNIMPLEMENTED; + } + + Return beginOp(KeyPurpose purpose, const hidl_vec& keyBlob, + const hidl_vec& inParams, const HardwareAuthToken& authToken, + beginOp_cb _hidl_cb) override { + if (km4_1_dev_) return km4_1_dev_->beginOp(purpose, keyBlob, inParams, authToken, _hidl_cb); + + return km4_0_dev_->begin( + purpose, keyBlob, inParams, authToken, + [&_hidl_cb](V4_0::ErrorCode errorCode, const hidl_vec& outParams, + OperationHandle operationHandle) { + _hidl_cb(static_cast(errorCode), outParams, + new Operation(operationHandle)); + }); + } + + private: + void getVersionIfNeeded(); + + bool haveVersion_; + VersionResult version_; + sp km4_0_dev_; + sp km4_1_dev_; +}; // namespace android::hardware::keymaster::V4_1::support + +} // namespace android::hardware::keymaster::V4_1::support diff --git a/keymaster/4.1/support/include/keymasterV4_1/Operation.h b/keymaster/4.1/support/include/keymasterV4_1/Operation.h new file mode 100644 index 0000000000..902d49ac20 --- /dev/null +++ b/keymaster/4.1/support/include/keymasterV4_1/Operation.h @@ -0,0 +1,38 @@ +/* + ** Copyright 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. + */ + +#pragma once + +#include + +#include + +namespace android::hardware::keymaster::V4_1::support { + +class Operation : public IOperation { + public: + Operation(OperationHandle handle) : handle_(handle) {} + + Return getOperationChallenge(getOperationChallenge_cb _hidl_cb) override { + _hidl_cb(V4_1::ErrorCode::OK, handle_); + return Void(); + } + + private: + OperationHandle handle_; +}; + +} // namespace android::hardware::keymaster::V4_1::support diff --git a/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h b/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h index afc0eafdc7..01605b7f4a 100644 --- a/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h +++ b/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_ -#define HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_ +#pragma once #include @@ -28,5 +27,3 @@ using V4_0::AuthorizationSetBuilder; using V4_0::KeyParameter; } // namespace android::hardware::keymaster::V4_1 - -#endif // HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_ diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h index a90ad8ef14..c5ce9505d3 100644 --- a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h +++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h @@ -23,19 +23,26 @@ namespace android::hardware::keymaster::V4_1 { +using V4_0::Algorithm; using V4_0::BlockMode; using V4_0::Digest; using V4_0::EcCurve; +using V4_0::HardwareAuthenticatorType; using V4_0::HardwareAuthToken; +using V4_0::HmacSharingParameters; +using V4_0::KeyBlobUsageRequirements; using V4_0::KeyCharacteristics; +using V4_0::KeyFormat; using V4_0::KeyOrigin; using V4_0::KeyParameter; using V4_0::KeyPurpose; +using V4_0::OperationHandle; using V4_0::PaddingMode; using V4_0::SecurityLevel; using V4_0::TagType; using V4_0::VerificationToken; +using V4_0::NullOr; using V4_0::TypedTag; using V4_0::TAG_ACTIVE_DATETIME; diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_utils.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_utils.h new file mode 100644 index 0000000000..2e280020e6 --- /dev/null +++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_utils.h @@ -0,0 +1,26 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace android::hardware::keymaster::V4_1::support { + +using V4_0::support::blob2hidlVec; +using V4_0::support::hidlVec2AuthToken; + +} // namespace android::hardware::keymaster::V4_1::support From 8a179f34995909213055af7817d305f7c5cc6577 Mon Sep 17 00:00:00 2001 From: Slava Shklyaev Date: Fri, 13 Dec 2019 12:21:44 +0000 Subject: [PATCH 0455/1022] Remove neuralnetworks@1.3::Model.Extension* in favor of 1.2 counterparts The types are the same as in 1.2. No changes are expected. Bug: 136735929 Test: m Change-Id: I7431d2e9263fafa0e63b8b1b40f6715e3832d17c --- current.txt | 2 +- neuralnetworks/1.3/types.hal | 42 ++++++------------------------------ neuralnetworks/1.3/types.t | 42 ++++++------------------------------ 3 files changed, 13 insertions(+), 73 deletions(-) diff --git a/current.txt b/current.txt index 7b223b3cc2..4f049971e1 100644 --- a/current.txt +++ b/current.txt @@ -654,7 +654,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 234cc547d63d2f24a447aee0a9a76cab68b31c080adadc5a960598b827a69fa2 android.hardware.neuralnetworks@1.3::IDevice 058b48f0e2e725bb2b3fa2b7917b0f0a696383d03a4c57afe26f0eadb6a7af28 android.hardware.neuralnetworks@1.3::IPreparedModel 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -2576ba54711218ce0d7f207baa533fca9af3c630756938ede6e73fe197b7ea38 android.hardware.neuralnetworks@1.3::types +1435cf1724f9f89ff5f97d4aa6fe2a031b0ef43034cb5801b16229dc2ecfea82 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index 6c8fe43312..bb924c26ba 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -20,6 +20,8 @@ import @1.0::DataLocation; import @1.0::OperandLifeTime; import @1.0::PerformanceInfo; import @1.0::RequestArgument; +import @1.2::Model.ExtensionNameAndPrefix; +import @1.2::Model.ExtensionTypeEncoding; import @1.2::OperandType; import @1.2::OperationType; import @1.2::SymmPerChannelQuantParams; @@ -5157,9 +5159,9 @@ struct Model { * {@link OperandTypeRange::BASE_MAX} or * {@link OperationTypeRange::BASE_MAX} respectively should be interpreted * as an extension operand. The low - * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value - * correspond to the type ID within the extension and the high - * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode + * {@link @1.2::Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the + * value correspond to the type ID within the extension and the high + * {@link @1.2::Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode * the "prefix", which maps uniquely to the extension name. * * For example, if a model contains an operation whose value is @@ -5172,39 +5174,7 @@ struct Model { * prefix corresponding to each extension name and at most one extension * name corresponding to each prefix. */ - vec extensionNameToPrefix; - - /** - * A correspondence between an extension name and a prefix of operand and - * operation type values. - */ - struct ExtensionNameAndPrefix { - /** - * The extension name. - * - * See {@link Extension::name} for the format specification. - */ - string name; - - /** - * The unique extension identifier within the model. - * - * See {@link Model::extensionNameToPrefix}. - */ - uint16_t prefix; - }; - - /** - * Numeric values of extension operand and operation types have the - * following structure: - * - 16 high bits represent the "prefix", which corresponds uniquely to the - * extension name. - * - 16 low bits represent the type ID within the extension. - */ - enum ExtensionTypeEncoding : uint8_t { - HIGH_BITS_PREFIX = 16, - LOW_BITS_TYPE = 16, - }; + vec<@1.2::Model.ExtensionNameAndPrefix> extensionNameToPrefix; }; /** diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t index b1c72a9a31..b4c37697a1 100644 --- a/neuralnetworks/1.3/types.t +++ b/neuralnetworks/1.3/types.t @@ -22,6 +22,8 @@ import @1.0::DataLocation; import @1.0::OperandLifeTime; import @1.0::PerformanceInfo; import @1.0::RequestArgument; +import @1.2::Model.ExtensionNameAndPrefix; +import @1.2::Model.ExtensionTypeEncoding; import @1.2::OperandType; import @1.2::OperationType; import @1.2::SymmPerChannelQuantParams; @@ -341,9 +343,9 @@ struct Model { * {@link OperandTypeRange::BASE_MAX} or * {@link OperationTypeRange::BASE_MAX} respectively should be interpreted * as an extension operand. The low - * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value - * correspond to the type ID within the extension and the high - * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode + * {@link @1.2::Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the + * value correspond to the type ID within the extension and the high + * {@link @1.2::Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode * the "prefix", which maps uniquely to the extension name. * * For example, if a model contains an operation whose value is @@ -356,39 +358,7 @@ struct Model { * prefix corresponding to each extension name and at most one extension * name corresponding to each prefix. */ - vec extensionNameToPrefix; - - /** - * A correspondence between an extension name and a prefix of operand and - * operation type values. - */ - struct ExtensionNameAndPrefix { - /** - * The extension name. - * - * See {@link Extension::name} for the format specification. - */ - string name; - - /** - * The unique extension identifier within the model. - * - * See {@link Model::extensionNameToPrefix}. - */ - uint16_t prefix; - }; - - /** - * Numeric values of extension operand and operation types have the - * following structure: - * - 16 high bits represent the "prefix", which corresponds uniquely to the - * extension name. - * - 16 low bits represent the type ID within the extension. - */ - enum ExtensionTypeEncoding : uint8_t { - HIGH_BITS_PREFIX = 16, - LOW_BITS_TYPE = 16, - }; + vec<@1.2::Model.ExtensionNameAndPrefix> extensionNameToPrefix; }; /** From a785a3faacaed173b7e8c697dfc48f791ae8c79c Mon Sep 17 00:00:00 2001 From: Slava Shklyaev Date: Fri, 13 Dec 2019 12:24:35 +0000 Subject: [PATCH 0456/1022] Add NNAPI control flow Bug: 136735929 Bug: 139181916 Test: m Change-Id: I7a75175f00fc98df626c40ea669021ccd40130e0 --- current.txt | 4 +- neuralnetworks/1.3/IDevice.hal | 11 +- neuralnetworks/1.3/types.hal | 223 +++++++++++++++--- neuralnetworks/1.3/types.t | 126 ++++++++-- .../functional/CompilationCachingTests.cpp | 2 +- .../vts/functional/GeneratedTestHarness.cpp | 13 +- .../1.3/vts/functional/ValidateModel.cpp | 117 ++++----- 7 files changed, 373 insertions(+), 123 deletions(-) diff --git a/current.txt b/current.txt index 4f049971e1..baa7b09dbf 100644 --- a/current.txt +++ b/current.txt @@ -651,10 +651,10 @@ ac429fca0da4ce91218768ec31b64ded88251f8a26d8c4f27c06abdc5b1926d9 android.hardwar df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore 4b5c8546533db9412fec6d32c0ef42b22e5e68dbf390c775ec3c22bb2d501102 android.hardware.neuralnetworks@1.3::IBuffer -234cc547d63d2f24a447aee0a9a76cab68b31c080adadc5a960598b827a69fa2 android.hardware.neuralnetworks@1.3::IDevice +5a6b75f13f0e010a4268defa4f627b862ab2899fb04f9d985194a25bd8f9fe0d android.hardware.neuralnetworks@1.3::IDevice 058b48f0e2e725bb2b3fa2b7917b0f0a696383d03a4c57afe26f0eadb6a7af28 android.hardware.neuralnetworks@1.3::IPreparedModel 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -1435cf1724f9f89ff5f97d4aa6fe2a031b0ef43034cb5801b16229dc2ecfea82 android.hardware.neuralnetworks@1.3::types +12c51f9d04a52324510419aeee3e37bb3607e6900556cdde79774d80ed989855 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.3/IDevice.hal b/neuralnetworks/1.3/IDevice.hal index 9afd77830d..8dc41f7c21 100644 --- a/neuralnetworks/1.3/IDevice.hal +++ b/neuralnetworks/1.3/IDevice.hal @@ -48,9 +48,14 @@ interface IDevice extends @1.2::IDevice { /** * Gets the supported operations in a model. * - * getSupportedOperations indicates which operations of a model are fully - * supported by the vendor driver. If an operation may not be supported for - * any reason, getSupportedOperations must return false for that operation. + * getSupportedOperations indicates which operations of the top-level + * subgraph are fully supported by the vendor driver. If an operation may + * not be supported for any reason, getSupportedOperations must return + * false for that operation. + * + * The {@link OperationType::IF} and {@link OperationType::WHILE} + * operations may only be fully supported if the vendor driver fully + * supports all operations in the referenced subgraphs. * * @param model A model whose operations--and their corresponding operands-- * are to be verified by the driver. diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index bb924c26ba..a6d274a05a 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -17,7 +17,6 @@ package android.hardware.neuralnetworks@1.3; import @1.0::DataLocation; -import @1.0::OperandLifeTime; import @1.0::PerformanceInfo; import @1.0::RequestArgument; import @1.2::Model.ExtensionNameAndPrefix; @@ -42,6 +41,13 @@ enum OperandType : @1.2::OperandType { */ TENSOR_QUANT8_ASYMM_SIGNED = 14, + /** + * A reference to a subgraph. + * + * Must have the lifetime {@link OperandLifeTime::SUBGRAPH}. + */ + SUBGRAPH = 15, + /* * DEPRECATED. Since HAL version 1.2, extensions are the preferred * alternative to OEM operation and data types. @@ -70,7 +76,7 @@ enum OperandType : @1.2::OperandType { enum OperandTypeRange : uint32_t { BASE_MIN = 0, FUNDAMENTAL_MIN = 0, - FUNDAMENTAL_MAX = 14, + FUNDAMENTAL_MAX = 15, OEM_MIN = 10000, OEM_MAX = 10001, BASE_MAX = 0xFFFF, @@ -4878,6 +4884,92 @@ enum OperationType : int32_t { */ QUANTIZED_LSTM = 95, + /** + * Executes one of the two referenced subgraphs as determined by a boolean + * value. + * + * 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. + * + * Inputs: + * * 0: A value of type {@link OperandType::TENSOR_BOOL8} and shape [1] + * that determines which of the two referenced subgraphs to execute. + * * 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 + * executed if the condition is false. + * * 3 ~ (n + 2): Inputs to be passed to the subgraph selected for execution. + * + * Outputs: + * * 0 ~ (m - 1): Outputs produced by the selected subgraph. + */ + IF = 96, + + /** + * Executes the body subgraph until the condition subgraph outputs false. + * + * The inputs to this operation are the condition subgraph, the body subgraph, + * and operand values for the first iteration of the loop. The values are + * implicitly split into three groups of input-output, state-only, and + * input-only values, as described below. + * + * The outputs of this operation are the final values of input-output + * operands. + * + * Both the condition and body subgraph receive (m + k + n) inputs. + * * The first m (m >= 1) inputs are input-output operands. For the first + * iteration, these are initialized from the corresponding inputs of the + * WHILE operation. In subsequent iterations, their values come from the + * corresponding outputs of the body subgraph produced during the previous + * iteration. + * * The next k (k >= 0) inputs are state-only operands. They are similar to + * the input-output operands, except that their values are no longer + * available after the loop terminates. + * * The last n (n >= 0) inputs are input-only operands. Their values come + * from the corresponding inputs of the WHILE operation. + * + * The body subgraph produces (m + k) outputs. + * * The first m outputs are input-output operands. They become the outputs + * of the WHILE operation when a termination condition is reached. + * * The last k outputs are state-only operands. Their values are no longer + * available after the loop terminates. + * + * The numbers m, k, and n are inferred by the driver as follows: + * m = (WHILE operation output count) + * k = (body subgraph output count) - m + * n = (body subgraph input count) - m - k + * + * The pseudo-code below illustrates the flow of a WHILE operation with + * inputs condition, body, initial_input_output, initial_state, input_only + * (m = 1, k = 1, n = 1): + * + * input_output = initial_input_output + * state = initial_state + * while condition(input_output, state, input_only): + * input_output, state = body(input_output, state, input_only) + * return input_output + * + * 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]. + * * 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. + * * (m inputs): Initial values for input-output operands. + * * (k inputs): Initial values for state-only operands. + * * (n inputs): Values for input-only operands. + * + * Outputs: + * * 0 ~ (m - 1): Outputs produced by the loop. + */ + WHILE = 97, + /** * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to * OEM operation and data types. @@ -4900,13 +4992,12 @@ enum OperationType : int32_t { enum OperationTypeRange : uint32_t { BASE_MIN = 0, FUNDAMENTAL_MIN = 0, - FUNDAMENTAL_MAX = 95, + FUNDAMENTAL_MAX = 97, OEM_MIN = 10000, OEM_MAX = 10000, BASE_MAX = 0xFFFF, }; - /** * The capabilities of a driver. * @@ -4967,6 +5058,59 @@ struct Operation { vec outputs; }; +/** + * How an operand is used. + */ +enum OperandLifeTime : int32_t { + /** + * The operand is internal to the model. It's created by an operation and + * consumed by other operations. It must be an output operand of + * exactly one operation. + */ + TEMPORARY_VARIABLE, + + /** + * The operand is an input of a subgraph. It must not be an output + * operand of any operation. + * + * An operand can't be both input and output of a subgraph. + */ + SUBGRAPH_INPUT, + + /** + * The operand is an output of a subgraph. It must be an output + * operand of exactly one operation. + * + * An operand can't be both input and output of a subgraph. + */ + SUBGRAPH_OUTPUT, + + /** + * The operand is a constant found in Model.operandValues. It must + * not be an output operand of any operation. + */ + CONSTANT_COPY, + + /** + * The operand is a constant that was specified via a Memory + * object. It must not be an output operand of any operation. + */ + CONSTANT_REFERENCE, + + /** + * The operand does not have a value. This is valid only for optional + * arguments of operations. + */ + NO_VALUE, + + /** + * The operand is a reference to a subgraph. It must be an input to one + * or more {@link OperationType::IF} or {@link OperationType::WHILE} + * operations. + */ + SUBGRAPH, +}; + /** * Describes one operand of the model's graph. */ @@ -5003,7 +5147,7 @@ struct Operand { * . The operand has lifetime CONSTANT_COPY or * CONSTANT_REFERENCE. * - * . The operand has lifetime MODEL_INPUT. Fully + * . The operand has lifetime SUBGRAPH_INPUT. Fully * specified dimensions must either be present in the * Operand or they must be provided in the corresponding * RequestArgument. @@ -5051,8 +5195,8 @@ struct Operand { /** * Where to find the data for this operand. - * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or - * NO_VALUE: + * If the lifetime is TEMPORARY_VARIABLE, SUBGRAPH_INPUT, SUBGRAPH_OUTPUT, + * or NO_VALUE: * - All the fields must be 0. * If the lifetime is CONSTANT_COPY: * - location.poolIndex is 0. @@ -5062,6 +5206,11 @@ struct Operand { * - location.poolIndex is set. * - location.offset is the offset in bytes into the specified pool. * - location.length is set. + * If the lifetime is SUBGRAPH: + * - location.poolIndex is 0. + * - location.offset is the index of the referenced subgraph in + * {@link Model::referenced}. + * - location.length is 0. */ DataLocation location; @@ -5100,32 +5249,19 @@ struct Operand { */ struct Model { /** - * All operands included in the model. + * The top-level subgraph. */ - vec operands; + Subgraph main; /** - * All operations included in the model. + * Referenced subgraphs. * - * The operations are sorted into execution order. Every operand - * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be - * written before it is read. - */ - vec operations; - - /** - * Input indexes of the model. There must be at least one. + * Each subgraph is referenced by the main subgraph or at least one other + * referenced subgraph. * - * Each value corresponds to the index of the operand in "operands". + * There must be no reference cycles. */ - vec inputIndexes; - - /** - * Output indexes of the model. There must be at least one. - * - * Each value corresponds to the index of the operand in "operands". - */ - vec outputIndexes; + vec referenced; /** * A byte buffer containing operand data that were copied into the model. @@ -5177,6 +5313,39 @@ struct Model { vec<@1.2::Model.ExtensionNameAndPrefix> extensionNameToPrefix; }; +/** + * An excerpt of the execution graph. + */ +struct Subgraph { + /** + * All operands included in the subgraph. + */ + vec operands; + + /** + * All operations included in the subgraph. + * + * The operations are sorted into execution order. Every operand + * with lifetime SUBGRAPH_OUTPUT or TEMPORARY_VARIABLE must be + * written before it is read. + */ + vec operations; + + /** + * Input indexes of the subgraph. There must be at least one. + * + * Each value corresponds to the index of the operand in "operands". + */ + vec inputIndexes; + + /** + * Output indexes of the subgraph. There must be at least one. + * + * Each value corresponds to the index of the operand in "operands". + */ + vec outputIndexes; +}; + /** * A buffer descriptor. Describes the properties of a buffer. */ diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t index b4c37697a1..f3319e5cbe 100644 --- a/neuralnetworks/1.3/types.t +++ b/neuralnetworks/1.3/types.t @@ -19,7 +19,6 @@ package android.hardware.neuralnetworks@1.3; import @1.0::DataLocation; -import @1.0::OperandLifeTime; import @1.0::PerformanceInfo; import @1.0::RequestArgument; import @1.2::Model.ExtensionNameAndPrefix; @@ -90,7 +89,6 @@ enum OperationTypeRange : uint32_t { BASE_MAX = 0xFFFF, }; - /** * The capabilities of a driver. * @@ -151,6 +149,59 @@ struct Operation { vec outputs; }; +/** + * How an operand is used. + */ +enum OperandLifeTime : int32_t { + /** + * The operand is internal to the model. It's created by an operation and + * consumed by other operations. It must be an output operand of + * exactly one operation. + */ + TEMPORARY_VARIABLE, + + /** + * The operand is an input of a subgraph. It must not be an output + * operand of any operation. + * + * An operand can't be both input and output of a subgraph. + */ + SUBGRAPH_INPUT, + + /** + * The operand is an output of a subgraph. It must be an output + * operand of exactly one operation. + * + * An operand can't be both input and output of a subgraph. + */ + SUBGRAPH_OUTPUT, + + /** + * The operand is a constant found in Model.operandValues. It must + * not be an output operand of any operation. + */ + CONSTANT_COPY, + + /** + * The operand is a constant that was specified via a Memory + * object. It must not be an output operand of any operation. + */ + CONSTANT_REFERENCE, + + /** + * The operand does not have a value. This is valid only for optional + * arguments of operations. + */ + NO_VALUE, + + /** + * The operand is a reference to a subgraph. It must be an input to one + * or more {@link OperationType::IF} or {@link OperationType::WHILE} + * operations. + */ + SUBGRAPH, +}; + /** * Describes one operand of the model's graph. */ @@ -187,7 +238,7 @@ struct Operand { * . The operand has lifetime CONSTANT_COPY or * CONSTANT_REFERENCE. * - * . The operand has lifetime MODEL_INPUT. Fully + * . The operand has lifetime SUBGRAPH_INPUT. Fully * specified dimensions must either be present in the * Operand or they must be provided in the corresponding * RequestArgument. @@ -235,8 +286,8 @@ struct Operand { /** * Where to find the data for this operand. - * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or - * NO_VALUE: + * If the lifetime is TEMPORARY_VARIABLE, SUBGRAPH_INPUT, SUBGRAPH_OUTPUT, + * or NO_VALUE: * - All the fields must be 0. * If the lifetime is CONSTANT_COPY: * - location.poolIndex is 0. @@ -246,6 +297,11 @@ struct Operand { * - location.poolIndex is set. * - location.offset is the offset in bytes into the specified pool. * - location.length is set. + * If the lifetime is SUBGRAPH: + * - location.poolIndex is 0. + * - location.offset is the index of the referenced subgraph in + * {@link Model::referenced}. + * - location.length is 0. */ DataLocation location; @@ -284,32 +340,19 @@ struct Operand { */ struct Model { /** - * All operands included in the model. + * The top-level subgraph. */ - vec operands; + Subgraph main; /** - * All operations included in the model. + * Referenced subgraphs. * - * The operations are sorted into execution order. Every operand - * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be - * written before it is read. - */ - vec operations; - - /** - * Input indexes of the model. There must be at least one. + * Each subgraph is referenced by the main subgraph or at least one other + * referenced subgraph. * - * Each value corresponds to the index of the operand in "operands". + * There must be no reference cycles. */ - vec inputIndexes; - - /** - * Output indexes of the model. There must be at least one. - * - * Each value corresponds to the index of the operand in "operands". - */ - vec outputIndexes; + vec referenced; /** * A byte buffer containing operand data that were copied into the model. @@ -361,6 +404,39 @@ struct Model { vec<@1.2::Model.ExtensionNameAndPrefix> extensionNameToPrefix; }; +/** + * An excerpt of the execution graph. + */ +struct Subgraph { + /** + * All operands included in the subgraph. + */ + vec operands; + + /** + * All operations included in the subgraph. + * + * The operations are sorted into execution order. Every operand + * with lifetime SUBGRAPH_OUTPUT or TEMPORARY_VARIABLE must be + * written before it is read. + */ + vec operations; + + /** + * Input indexes of the subgraph. There must be at least one. + * + * Each value corresponds to the index of the operand in "operands". + */ + vec inputIndexes; + + /** + * Output indexes of the subgraph. There must be at least one. + * + * Each value corresponds to the index of the operand in "operands". + */ + vec outputIndexes; +}; + /** * A buffer descriptor. Describes the properties of a buffer. */ diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp index fe8d907d36..5cb466fe28 100644 --- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp @@ -308,7 +308,7 @@ class CompilationCachingTestBase : public testing::Test { model, [&fullySupportsModel, &model](ErrorStatus status, const hidl_vec& supported) { ASSERT_EQ(ErrorStatus::NONE, status); - ASSERT_EQ(supported.size(), model.operations.size()); + ASSERT_EQ(supported.size(), model.main.operations.size()); fullySupportsModel = std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; }); }); diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 4f747f4afa..805d5b53aa 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -59,7 +59,6 @@ using hidl::memory::V1_0::IMemory; using implementation::PreparedModelCallback; using V1_0::DataLocation; using V1_0::ErrorStatus; -using V1_0::OperandLifeTime; using V1_0::RequestArgument; using V1_1::ExecutionPreference; using V1_2::Constant; @@ -269,10 +268,10 @@ Model createModel(const TestModel& testModel) { } } - return {.operands = std::move(operands), - .operations = std::move(operations), - .inputIndexes = testModel.inputIndexes, - .outputIndexes = testModel.outputIndexes, + return {.main = {.operands = std::move(operands), + .operations = std::move(operations), + .inputIndexes = testModel.inputIndexes, + .outputIndexes = testModel.outputIndexes}, .operandValues = std::move(operandValues), .pools = std::move(pools), .relaxComputationFloat32toFloat16 = testModel.isRelaxed}; @@ -290,8 +289,8 @@ static void makeOutputInsufficientSize(uint32_t outputIndex, Request* request) { } static void makeOutputDimensionsUnspecified(Model* model) { - for (auto i : model->outputIndexes) { - auto& dims = model->operands[i].dimensions; + for (auto i : model->main.outputIndexes) { + auto& dims = model->main.operands[i].dimensions; std::fill(dims.begin(), dims.end(), 0); } } diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 8395111d78..cc862645a5 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -25,7 +25,6 @@ namespace android::hardware::neuralnetworks::V1_3::vts::functional { using implementation::PreparedModelCallback; using V1_0::ErrorStatus; -using V1_0::OperandLifeTime; using V1_1::ExecutionPreference; using V1_2::SymmPerChannelQuantParams; using HidlToken = @@ -83,22 +82,22 @@ static void validate(const sp& device, const std::string& message, Mode } static uint32_t addOperand(Model* model) { - return hidl_vec_push_back(&model->operands, + return hidl_vec_push_back(&model->main.operands, { .type = OperandType::INT32, .dimensions = {}, .numberOfConsumers = 0, .scale = 0.0f, .zeroPoint = 0, - .lifetime = OperandLifeTime::MODEL_INPUT, + .lifetime = OperandLifeTime::SUBGRAPH_INPUT, .location = {.poolIndex = 0, .offset = 0, .length = 0}, }); } static uint32_t addOperand(Model* model, OperandLifeTime lifetime) { uint32_t index = addOperand(model); - model->operands[index].numberOfConsumers = 1; - model->operands[index].lifetime = lifetime; + model->main.operands[index].numberOfConsumers = 1; + model->main.operands[index].lifetime = lifetime; return index; } @@ -112,13 +111,13 @@ static const uint32_t invalidOperandTypes[] = { }; static void mutateOperandTypeTest(const sp& device, const Model& model) { - for (size_t operand = 0; operand < model.operands.size(); ++operand) { + for (size_t operand = 0; operand < model.main.operands.size(); ++operand) { for (uint32_t invalidOperandType : invalidOperandTypes) { const std::string message = "mutateOperandTypeTest: operand " + std::to_string(operand) + " set to value " + std::to_string(invalidOperandType); validate(device, message, model, [operand, invalidOperandType](Model* model) { - model->operands[operand].type = static_cast(invalidOperandType); + model->main.operands[operand].type = static_cast(invalidOperandType); }); } } @@ -150,15 +149,15 @@ static uint32_t getInvalidRank(OperandType type) { } static void mutateOperandRankTest(const sp& device, const Model& model) { - for (size_t operand = 0; operand < model.operands.size(); ++operand) { - const uint32_t invalidRank = getInvalidRank(model.operands[operand].type); + for (size_t operand = 0; operand < model.main.operands.size(); ++operand) { + const uint32_t invalidRank = getInvalidRank(model.main.operands[operand].type); if (invalidRank == 0) { continue; } const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) + " has rank of " + std::to_string(invalidRank); validate(device, message, model, [operand, invalidRank](Model* model) { - model->operands[operand].dimensions = std::vector(invalidRank, 0); + model->main.operands[operand].dimensions = std::vector(invalidRank, 0); }); } } @@ -190,12 +189,12 @@ static float getInvalidScale(OperandType type) { } static void mutateOperandScaleTest(const sp& device, const Model& model) { - for (size_t operand = 0; operand < model.operands.size(); ++operand) { - const float invalidScale = getInvalidScale(model.operands[operand].type); + for (size_t operand = 0; operand < model.main.operands.size(); ++operand) { + const float invalidScale = getInvalidScale(model.main.operands[operand].type); const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) + " has scale of " + std::to_string(invalidScale); validate(device, message, model, [operand, invalidScale](Model* model) { - model->operands[operand].scale = invalidScale; + model->main.operands[operand].scale = invalidScale; }); } } @@ -229,15 +228,15 @@ static std::vector getInvalidZeroPoints(OperandType type) { } static void mutateOperandZeroPointTest(const sp& device, const Model& model) { - for (size_t operand = 0; operand < model.operands.size(); ++operand) { + for (size_t operand = 0; operand < model.main.operands.size(); ++operand) { const std::vector invalidZeroPoints = - getInvalidZeroPoints(model.operands[operand].type); + getInvalidZeroPoints(model.main.operands[operand].type); for (int32_t invalidZeroPoint : invalidZeroPoints) { const std::string message = "mutateOperandZeroPointTest: operand " + std::to_string(operand) + " has zero point of " + std::to_string(invalidZeroPoint); validate(device, message, model, [operand, invalidZeroPoint](Model* model) { - model->operands[operand].zeroPoint = invalidZeroPoint; + model->main.operands[operand].zeroPoint = invalidZeroPoint; }); } } @@ -310,11 +309,11 @@ static void mutateOperand(Operand* operand, OperandType type) { static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, const Model& model) { // Do not test OEM types - if (type == model.operands[operand].type || type == OperandType::OEM || + if (type == model.main.operands[operand].type || type == OperandType::OEM || type == OperandType::TENSOR_OEM_BYTE) { return true; } - for (const Operation& operation : model.operations) { + for (const Operation& operation : model.main.operations) { // Skip mutateOperationOperandTypeTest for the following operations. // - LSH_PROJECTION's second argument is allowed to have any type. // - ARGMIN and ARGMAX's first argument can be any of @@ -401,7 +400,7 @@ static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, con } static void mutateOperationOperandTypeTest(const sp& device, const Model& model) { - for (size_t operand = 0; operand < model.operands.size(); ++operand) { + for (size_t operand = 0; operand < model.main.operands.size(); ++operand) { for (OperandType invalidOperandType : hidl_enum_range{}) { if (mutateOperationOperandTypeSkip(operand, invalidOperandType, model)) { continue; @@ -410,7 +409,7 @@ static void mutateOperationOperandTypeTest(const sp& device, const Mode std::to_string(operand) + " set to type " + toString(invalidOperandType); validate(device, message, model, [operand, invalidOperandType](Model* model) { - mutateOperand(&model->operands[operand], invalidOperandType); + mutateOperand(&model->main.operands[operand], invalidOperandType); }); } } @@ -425,13 +424,13 @@ static const uint32_t invalidOperationTypes[] = { }; static void mutateOperationTypeTest(const sp& device, const Model& model) { - for (size_t operation = 0; operation < model.operations.size(); ++operation) { + for (size_t operation = 0; operation < model.main.operations.size(); ++operation) { for (uint32_t invalidOperationType : invalidOperationTypes) { const std::string message = "mutateOperationTypeTest: operation " + std::to_string(operation) + " set to value " + std::to_string(invalidOperationType); validate(device, message, model, [operation, invalidOperationType](Model* model) { - model->operations[operation].type = + model->main.operations[operation].type = static_cast(invalidOperationType); }); } @@ -441,14 +440,14 @@ static void mutateOperationTypeTest(const sp& device, const Model& mode ///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX ///////////////////////// static void mutateOperationInputOperandIndexTest(const sp& device, const Model& model) { - for (size_t operation = 0; operation < model.operations.size(); ++operation) { - const uint32_t invalidOperand = model.operands.size(); - for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) { + for (size_t operation = 0; operation < model.main.operations.size(); ++operation) { + const uint32_t invalidOperand = model.main.operands.size(); + for (size_t input = 0; input < model.main.operations[operation].inputs.size(); ++input) { const std::string message = "mutateOperationInputOperandIndexTest: operation " + std::to_string(operation) + " input " + std::to_string(input); validate(device, message, model, [operation, input, invalidOperand](Model* model) { - model->operations[operation].inputs[input] = invalidOperand; + model->main.operations[operation].inputs[input] = invalidOperand; }); } } @@ -457,14 +456,15 @@ static void mutateOperationInputOperandIndexTest(const sp& device, cons ///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX ///////////////////////// static void mutateOperationOutputOperandIndexTest(const sp& device, const Model& model) { - for (size_t operation = 0; operation < model.operations.size(); ++operation) { - const uint32_t invalidOperand = model.operands.size(); - for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) { + for (size_t operation = 0; operation < model.main.operations.size(); ++operation) { + const uint32_t invalidOperand = model.main.operands.size(); + for (size_t output = 0; output < model.main.operations[operation].outputs.size(); + ++output) { const std::string message = "mutateOperationOutputOperandIndexTest: operation " + std::to_string(operation) + " output " + std::to_string(output); validate(device, message, model, [operation, output, invalidOperand](Model* model) { - model->operations[operation].outputs[output] = invalidOperand; + model->main.operations[operation].outputs[output] = invalidOperand; }); } } @@ -485,17 +485,17 @@ static void removeValueAndDecrementGreaterValues(hidl_vec* vec, uint32 } static void removeOperand(Model* model, uint32_t index) { - hidl_vec_removeAt(&model->operands, index); - for (Operation& operation : model->operations) { + hidl_vec_removeAt(&model->main.operands, index); + for (Operation& operation : model->main.operations) { removeValueAndDecrementGreaterValues(&operation.inputs, index); removeValueAndDecrementGreaterValues(&operation.outputs, index); } - removeValueAndDecrementGreaterValues(&model->inputIndexes, index); - removeValueAndDecrementGreaterValues(&model->outputIndexes, index); + removeValueAndDecrementGreaterValues(&model->main.inputIndexes, index); + removeValueAndDecrementGreaterValues(&model->main.outputIndexes, index); } static bool removeOperandSkip(size_t operand, const Model& model) { - for (const Operation& operation : model.operations) { + for (const Operation& operation : model.main.operations) { // Skip removeOperandTest for the following operations. // - SPLIT's outputs are not checked during prepareModel. if (operation.type == OperationType::SPLIT) { @@ -520,7 +520,7 @@ static bool removeOperandSkip(size_t operand, const Model& model) { } static void removeOperandTest(const sp& device, const Model& model) { - for (size_t operand = 0; operand < model.operands.size(); ++operand) { + for (size_t operand = 0; operand < model.main.operands.size(); ++operand) { if (removeOperandSkip(operand, model)) { continue; } @@ -533,14 +533,14 @@ static void removeOperandTest(const sp& device, const Model& model) { ///////////////////////// REMOVE OPERATION ///////////////////////// static void removeOperation(Model* model, uint32_t index) { - for (uint32_t operand : model->operations[index].inputs) { - model->operands[operand].numberOfConsumers--; + for (uint32_t operand : model->main.operations[index].inputs) { + model->main.operands[operand].numberOfConsumers--; } - hidl_vec_removeAt(&model->operations, index); + hidl_vec_removeAt(&model->main.operations, index); } static void removeOperationTest(const sp& device, const Model& model) { - for (size_t operation = 0; operation < model.operations.size(); ++operation) { + for (size_t operation = 0; operation < model.main.operations.size(); ++operation) { const std::string message = "removeOperationTest: operation " + std::to_string(operation); validate(device, message, model, [operation](Model* model) { removeOperation(model, operation); }); @@ -615,9 +615,9 @@ static bool removeOperationInputSkip(const Operation& op, size_t input) { } static void removeOperationInputTest(const sp& device, const Model& model) { - for (size_t operation = 0; operation < model.operations.size(); ++operation) { - for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) { - const Operation& op = model.operations[operation]; + for (size_t operation = 0; operation < model.main.operations.size(); ++operation) { + for (size_t input = 0; input < model.main.operations[operation].inputs.size(); ++input) { + const Operation& op = model.main.operations[operation]; if (removeOperationInputSkip(op, input)) { continue; } @@ -625,9 +625,9 @@ static void removeOperationInputTest(const sp& device, const Model& mod std::to_string(operation) + ", input " + std::to_string(input); validate(device, message, model, [operation, input](Model* model) { - uint32_t operand = model->operations[operation].inputs[input]; - model->operands[operand].numberOfConsumers--; - hidl_vec_removeAt(&model->operations[operation].inputs, input); + uint32_t operand = model->main.operations[operation].inputs[input]; + model->main.operands[operand].numberOfConsumers--; + hidl_vec_removeAt(&model->main.operations[operation].inputs, input); }); } } @@ -636,13 +636,14 @@ static void removeOperationInputTest(const sp& device, const Model& mod ///////////////////////// REMOVE OPERATION OUTPUT ///////////////////////// static void removeOperationOutputTest(const sp& device, const Model& model) { - for (size_t operation = 0; operation < model.operations.size(); ++operation) { - for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) { + for (size_t operation = 0; operation < model.main.operations.size(); ++operation) { + for (size_t output = 0; output < model.main.operations[operation].outputs.size(); + ++output) { const std::string message = "removeOperationOutputTest: operation " + std::to_string(operation) + ", output " + std::to_string(output); validate(device, message, model, [operation, output](Model* model) { - hidl_vec_removeAt(&model->operations[operation].outputs, output); + hidl_vec_removeAt(&model->main.operations[operation].outputs, output); }); } } @@ -669,15 +670,15 @@ static bool addOperationInputSkip(const Operation& op) { } static void addOperationInputTest(const sp& device, const Model& model) { - for (size_t operation = 0; operation < model.operations.size(); ++operation) { - if (addOperationInputSkip(model.operations[operation])) { + for (size_t operation = 0; operation < model.main.operations.size(); ++operation) { + if (addOperationInputSkip(model.main.operations[operation])) { continue; } const std::string message = "addOperationInputTest: operation " + std::to_string(operation); validate(device, message, model, [operation](Model* model) { - uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT); - hidl_vec_push_back(&model->operations[operation].inputs, index); - hidl_vec_push_back(&model->inputIndexes, index); + uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_INPUT); + hidl_vec_push_back(&model->main.operations[operation].inputs, index); + hidl_vec_push_back(&model->main.inputIndexes, index); }); } } @@ -685,13 +686,13 @@ static void addOperationInputTest(const sp& device, const Model& model) ///////////////////////// ADD OPERATION OUTPUT ///////////////////////// static void addOperationOutputTest(const sp& device, const Model& model) { - for (size_t operation = 0; operation < model.operations.size(); ++operation) { + for (size_t operation = 0; operation < model.main.operations.size(); ++operation) { const std::string message = "addOperationOutputTest: operation " + std::to_string(operation); validate(device, message, model, [operation](Model* model) { - uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT); - hidl_vec_push_back(&model->operations[operation].outputs, index); - hidl_vec_push_back(&model->outputIndexes, index); + uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_OUTPUT); + hidl_vec_push_back(&model->main.operations[operation].outputs, index); + hidl_vec_push_back(&model->main.outputIndexes, index); }); } } From c2143480f80ffb449e37faefb5a4694239d45529 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sat, 18 Jan 2020 14:04:19 -0800 Subject: [PATCH 0457/1022] Added TD-SCDMA bands for network scanning Added TD-SCDMA bands defined in 3GPP TS 25.102. Test: Telephony sanity tests Bug: 144939345 Change-Id: Ib1881ed41e6427edd294bb7af6f914baeb40d8f2 --- current.txt | 2 +- radio/1.5/types.hal | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/current.txt b/current.txt index 7b223b3cc2..f7c9b454cc 100644 --- a/current.txt +++ b/current.txt @@ -666,7 +666,7 @@ def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardwar ## # BEGIN Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present ## -73b5418353fe52721267d64592d4d4c1b77fbd1ef4261d964865de88e62ee0be android.hardware.radio@1.5::types +696f9000adf181682a49510baf93127e2ca62cfc84173b36afd164c797bc5771 android.hardware.radio@1.5::types 996f98ffe508a2f6f1755c1511b50067f7883f7c445dea9f3e931385f020b7ab android.hardware.radio@1.5::IRadio 20d52e66fd548f89bcb98cda42749a591ce8f439a2a7148617adac0c967ad937 android.hardware.radio@1.5::IRadioIndication 1512f6e1198e1aa0ebcbdb1694d0ed500a3e7791d6f305327866112331d82b66 android.hardware.radio@1.5::IRadioResponse diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index 724d014fb3..d629a3fe55 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -228,6 +228,16 @@ enum NgranBands : int32_t { BAND_261 = 261, }; +enum UtranBands : @1.1::UtranBands { + /** TD-SCDMA bands. 3GPP TS 25.102, Table 5.2: Frequency bands */ + BAND_A = 101, + BAND_B = 102, + BAND_C = 103, + BAND_D = 104, + BAND_E = 105, + BAND_F = 106, +}; + /** * Overwritten from @1.2::NetworkScanRequest to update * RadioAccessSpecifier to 1.5 version From 2d5d12860ceb8028aef398fd08728dc59e9d59c5 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Tue, 21 Jan 2020 11:57:38 -0800 Subject: [PATCH 0458/1022] rebootescrow: skip testing unsupported devices This HAL is optional, so we should skip devices that do not have it implemented instead of failing the test. Bug: 143695053 Bug: 63928581 Test: atest VtsHalRebootEscrowTargetTest Change-Id: Idaabdbe621cca0b8896377cef6f561b106ea252c --- .../vts/functional/VtsHalRebootEscrowTargetTest.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp index f69cf877ad..cd8cc3eaa1 100644 --- a/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp +++ b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp @@ -26,6 +26,9 @@ using android::sp; using android::String16; using android::hardware::rebootescrow::IRebootEscrow; +#define SKIP_UNSUPPORTED \ + if (rebootescrow == nullptr) GTEST_SKIP() << "Not supported on this device" + /** * This tests that the key can be written, read, and removed. It does not test * that the key survives a reboot. That needs a host-based test. @@ -36,7 +39,6 @@ class RebootEscrowAidlTest : public testing::TestWithParam { public: virtual void SetUp() override { rebootescrow = android::waitForDeclaredService(String16(GetParam().c_str())); - ASSERT_NE(rebootescrow, nullptr); } sp rebootescrow; @@ -59,6 +61,8 @@ class RebootEscrowAidlTest : public testing::TestWithParam { }; TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_Success) { + SKIP_UNSUPPORTED; + ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk()); std::vector actualKey; @@ -67,6 +71,8 @@ TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_Success) { } TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_SecondRetrieveSucceeds) { + SKIP_UNSUPPORTED; + ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk()); std::vector actualKey; @@ -78,6 +84,8 @@ TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_SecondRetrieveSucceeds) { } TEST_P(RebootEscrowAidlTest, StoreTwiceOverwrites_Success) { + SKIP_UNSUPPORTED; + ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk()); ASSERT_TRUE(rebootescrow->storeKey(KEY_2).isOk()); @@ -87,6 +95,8 @@ TEST_P(RebootEscrowAidlTest, StoreTwiceOverwrites_Success) { } TEST_P(RebootEscrowAidlTest, StoreEmpty_AfterGetEmptyKey_Success) { + SKIP_UNSUPPORTED; + rebootescrow->storeKey(KEY_1); rebootescrow->storeKey(EMPTY_KEY); From 200f8819c5e263cc99a5503569fc9a686ccfbe96 Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Tue, 14 Jan 2020 11:04:48 -0800 Subject: [PATCH 0459/1022] Add IRNSS svid range to HAL doc - IRNSS was added in GNSS HAL v2.0, and its svid range was not specified at that time. The existing client implementations wouldn't be broken because they either don't support IRNSS yet or already use such a range (specified in IRNSS ICD v1.1). Bug: 147675678 Test: doc only and builds Change-Id: If86555bf7d3019428d80299043c52ea81aa34bc5 --- current.txt | 1 + gnss/1.0/IGnssCallback.hal | 1 + 2 files changed, 2 insertions(+) diff --git a/current.txt b/current.txt index 5f57cd071a..50938735dd 100644 --- a/current.txt +++ b/current.txt @@ -587,6 +587,7 @@ d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardwar 2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types a05277065c28ebecd58118bd240fb8c55757361e8648c01f7c4dacdb7f2a95dc android.hardware.camera.metadata@3.3::types +9cb3df2bde2c6cd5fd96b7c41555420cacd7e276a556c684af91b7461c86460f android.hardware.gnss@1.0::IGnssCallback b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel 8eac60e1f724d141c71c69f06d4544acb720a55dfbbcd97fa01bb3d25ee4e2f5 android.hardware.neuralnetworks@1.0::types diff --git a/gnss/1.0/IGnssCallback.hal b/gnss/1.0/IGnssCallback.hal index d62676fb5e..311ab2166c 100644 --- a/gnss/1.0/IGnssCallback.hal +++ b/gnss/1.0/IGnssCallback.hal @@ -90,6 +90,7 @@ interface IGnssCallback { * - QZSS: 193-200 * - Galileo: 1-36 * - Beidou: 1-37 + * - IRNSS: 1-14 */ int16_t svid; From 32cc5ae339b4c5c86930a272994372f21dbfa4f0 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Wed, 15 Jan 2020 15:17:17 -0800 Subject: [PATCH 0460/1022] graphics: allow IAllocator 2.0 and IMapper to 2.1 Allows IAllocator 2.0 and IMapper 2.1 so that Cuttlefish can advertise API level 30 for R before 4.0 is implemented. Bug: b/136016160 Test: Compiles and boots Change-Id: I6d8ebc7013a2887521358b1ba73a2def14c20b9a --- compatibility_matrices/compatibility_matrix.current.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 1e3f74332a..2a4b94ed2d 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -204,6 +204,8 @@
    android.hardware.graphics.allocator + + 2.0 3.0 4.0 @@ -221,6 +223,8 @@ android.hardware.graphics.mapper + + 2.1 3.0 4.0 From c2499ecda1f398238d5fd5164c3fee96b68fc1f5 Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Wed, 11 Dec 2019 18:31:12 -0800 Subject: [PATCH 0461/1022] Add Quality of Service to NNAPI HAL This CL makes the following changes: * introduces a new Priority enum * extends ErrorStatus with new error codes * adds "supportsDeadline" method to IDevice * adds priority and deadline arguments to IDevice::prepareModel* * adds deadline argument to IPreparedModel::execute* * updates IExecutionCallback with new ErrorStatus * updates current.txt accordingly Bug: 136739795 Bug: 142902514 Bug: 145300530 Test: mma Change-Id: Iaa7877bde1f463635b8bbdb4e8a001d7b79b9c65 --- current.txt | 11 +-- neuralnetworks/1.3/Android.bp | 1 + neuralnetworks/1.3/IBuffer.hal | 2 +- neuralnetworks/1.3/IDevice.hal | 69 ++++++++++++++++++- neuralnetworks/1.3/IExecutionCallback.hal | 64 +++++++++++++++++ neuralnetworks/1.3/IPreparedModel.hal | 52 ++++++++++++-- neuralnetworks/1.3/IPreparedModelCallback.hal | 5 +- neuralnetworks/1.3/types.hal | 57 +++++++++++++++ neuralnetworks/1.3/types.t | 57 +++++++++++++++ 9 files changed, 303 insertions(+), 15 deletions(-) create mode 100644 neuralnetworks/1.3/IExecutionCallback.hal diff --git a/current.txt b/current.txt index baa7b09dbf..4896a3b26e 100644 --- a/current.txt +++ b/current.txt @@ -650,11 +650,12 @@ adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardwar ac429fca0da4ce91218768ec31b64ded88251f8a26d8c4f27c06abdc5b1926d9 android.hardware.keymaster@4.1::types df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore -4b5c8546533db9412fec6d32c0ef42b22e5e68dbf390c775ec3c22bb2d501102 android.hardware.neuralnetworks@1.3::IBuffer -5a6b75f13f0e010a4268defa4f627b862ab2899fb04f9d985194a25bd8f9fe0d android.hardware.neuralnetworks@1.3::IDevice -058b48f0e2e725bb2b3fa2b7917b0f0a696383d03a4c57afe26f0eadb6a7af28 android.hardware.neuralnetworks@1.3::IPreparedModel -94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -12c51f9d04a52324510419aeee3e37bb3607e6900556cdde79774d80ed989855 android.hardware.neuralnetworks@1.3::types +65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer +d1f382d14e1384b907d5bb5780df7f01934650d556fedbed2f15a90773c657d6 android.hardware.neuralnetworks@1.3::IDevice +4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback +7d23020248194abbee8091cc624f39a5a6d7ccba338b172d5d2d3df0cceffbee android.hardware.neuralnetworks@1.3::IPreparedModel +0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback +ee65638f8af3f9f4f222e7208eaa9f1f8e7f8e0a21545846ba67d0e27624efa1 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.3/Android.bp b/neuralnetworks/1.3/Android.bp index 08e824d6e6..56011e227d 100644 --- a/neuralnetworks/1.3/Android.bp +++ b/neuralnetworks/1.3/Android.bp @@ -10,6 +10,7 @@ hidl_interface { "types.hal", "IBuffer.hal", "IDevice.hal", + "IExecutionCallback.hal", "IPreparedModel.hal", "IPreparedModelCallback.hal", ], diff --git a/neuralnetworks/1.3/IBuffer.hal b/neuralnetworks/1.3/IBuffer.hal index 84241c579b..dfc57fe75e 100644 --- a/neuralnetworks/1.3/IBuffer.hal +++ b/neuralnetworks/1.3/IBuffer.hal @@ -16,7 +16,7 @@ package android.hardware.neuralnetworks@1.3; -import @1.0::ErrorStatus; +import ErrorStatus; /** * This interface represents a device memory buffer. diff --git a/neuralnetworks/1.3/IDevice.hal b/neuralnetworks/1.3/IDevice.hal index 8dc41f7c21..610db79456 100644 --- a/neuralnetworks/1.3/IDevice.hal +++ b/neuralnetworks/1.3/IDevice.hal @@ -16,7 +16,6 @@ package android.hardware.neuralnetworks@1.3; -import @1.0::ErrorStatus; import @1.1::ExecutionPreference; import @1.2::Constant; import @1.2::DeviceType; @@ -25,7 +24,10 @@ import @1.2::IDevice; import BufferDesc; import BufferRole; import Capabilities; +import ErrorStatus; import Model; +import OptionalTimePoint; +import Priority; import IBuffer; import IPreparedModel; import IPreparedModelCallback; @@ -45,6 +47,19 @@ interface IDevice extends @1.2::IDevice { */ getCapabilities_1_3() generates (ErrorStatus status, Capabilities capabilities); + /** + * Returns whether the device is able to complete or abort a task within a + * specified duration. + * + * @return prepareModelDeadline 'true' if the device supports completing or + * aborting model preparation by the deadline when the deadline is supplied, + * 'false' otherwise. + * @return executionDeadline 'true' if the device supports completing or + * aborting an execution by the deadline when the deadline is supplied, + * 'false' otherwise. + */ + supportsDeadlines() generates (bool prepareModelDeadline, bool executionDeadline); + /** * Gets the supported operations in a model. * @@ -118,6 +133,22 @@ interface IDevice extends @1.2::IDevice { * the callback object must be invoked with the appropriate ErrorStatus * value and nullptr for the IPreparedModel. * + * The model is prepared with a priority. This priority is relative to other + * prepared models owned by the same client. Higher priority executions may + * use more compute resources than lower priority executions, and may + * preempt or starve lower priority executions. + * + * prepareModel_1_3 can be called with an optional deadline. If the model + * is not able to be prepared before the provided deadline, the model + * preparation must be aborted, and either {@link + * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link + * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due + * to an abort must be sent the same way as other errors, described above. + * If the service reports that it does not support preparation deadlines via + * IDevice::supportsDeadlines, and prepareModel_1_3 is called with a + * deadline, then the argument is invalid, and {@link + * ErrorStatus::INVALID_ARGUMENT} must be returned. + * * Optionally, the driver may save the prepared model to cache during the * asynchronous preparation. Any error that occurs when saving to cache must * not affect the status of preparing the model. Even if the input arguments @@ -139,6 +170,11 @@ interface IDevice extends @1.2::IDevice { * @param model The model to be prepared for execution. * @param preference Indicates the intended execution behavior of a prepared * model. + * @param priority The priority of the prepared model relative to other + * prepared models owned by the client. + * @param deadline The time by which the model must be prepared. If the + * model cannot be prepared by the deadline, the preparation must be + * aborted. * @param modelCache A vector of handles with each entry holding exactly one * cache file descriptor for the security-sensitive cache. The length of * the vector must either be 0 indicating that caching information is @@ -173,8 +209,12 @@ interface IDevice extends @1.2::IDevice { * - GENERAL_FAILURE if there is an unspecified error * - INVALID_ARGUMENT if one of the input arguments related to preparing * the model is invalid + * - MISSED_DEADLINE_* if the deadline for preparing a model cannot be + * met + * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver */ prepareModel_1_3(Model model, ExecutionPreference preference, + Priority priority, OptionalTimePoint deadline, vec modelCache, vec dataCache, uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token, IPreparedModelCallback callback) @@ -220,6 +260,22 @@ interface IDevice extends @1.2::IDevice { * the model, the callback object must be invoked with the appropriate * ErrorStatus value and nullptr for the IPreparedModel. * + * The model is prepared with a priority. This priority is relative to other + * prepared models owned by the same client. Higher priority executions may + * use more compute resources than lower priority executions, and may + * preempt or starve lower priority executions. + * + * prepareModelFromCache_1_3 can be called with an optional deadline. If the + * model is not able to prepared before the provided deadline, the model + * preparation must be aborted, and either {@link + * ErrorStatus::MISSED_DEADLINE_TRANSIENT} + * or {@link ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The + * error due to an abort must be sent the same way as other errors, + * described above. If the service reports that it does not support + * preparation deadlines via IDevice::supportsDeadlines, and + * prepareModelFromCache_1_3 is called with a deadline, then the argument is + * invalid, and {@link ErrorStatus::INVALID_ARGUMENT} must be returned. + * * The only information that may be unknown to the model at this stage is * the shape of the tensors, which may only be known at execution time. As * such, some driver services may return partially prepared models, where @@ -228,6 +284,11 @@ interface IDevice extends @1.2::IDevice { * used with different shapes of inputs on different (possibly concurrent) * executions. * + * @param priority The priority of the prepared model relative to other + * prepared models owned by the client. + * @param deadline The time by which the model must be prepared. If the + * model cannot be prepared by the deadline, the preparation must be + * aborted. * @param modelCache A vector of handles with each entry holding exactly one * cache file descriptor for the security-sensitive cache. The length of * the vector must match the numModelCache returned from getNumberOfCacheFilesNeeded. @@ -253,8 +314,12 @@ interface IDevice extends @1.2::IDevice { * - GENERAL_FAILURE if caching is not supported or if there is an * unspecified error * - INVALID_ARGUMENT if one of the input arguments is invalid + * - MISSED_DEADLINE_* if the deadline for preparing a model cannot be + * met + * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver */ - prepareModelFromCache_1_3(vec modelCache, vec dataCache, + prepareModelFromCache_1_3(Priority priority, OptionalTimePoint deadline, + vec modelCache, vec dataCache, uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token, IPreparedModelCallback callback) generates (ErrorStatus status); diff --git a/neuralnetworks/1.3/IExecutionCallback.hal b/neuralnetworks/1.3/IExecutionCallback.hal new file mode 100644 index 0000000000..439428a5aa --- /dev/null +++ b/neuralnetworks/1.3/IExecutionCallback.hal @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package android.hardware.neuralnetworks@1.3; + +import @1.2::IExecutionCallback; +import @1.2::OutputShape; +import @1.2::Timing; + +/** + * IExecutionCallback must be used to return the error status result from an + * execution asynchronously launched from IPreparedModel::execute*. + */ +interface IExecutionCallback extends @1.2::IExecutionCallback { + + /** + * There are three notify methods declared for the IExecutionCallback + * interface: notify_1_3, notify_1_2, and notify. One of the three notify + * methods must be invoked immediately after the asynchronous task has + * finished performing the execution. One of the notify methods must be + * provided with the ErrorStatus from the execution. If the asynchronous + * task is not launched, one of the notify methods must be invoked with the + * appropriate error. + * + * @param status Error status returned from launching the asynchronous task + * (if the launch fails) or from the asynchronous task itself + * (if the launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the asynchronous task resulted in an + * unspecified error + * - OUTPUT_INSUFFICIENT_SIZE if at least one output + * operand buffer is not large enough to store the + * corresponding output + * - INVALID_ARGUMENT if one of the input arguments to + * prepareModel is invalid + * - MISSED_DEADLINE_* if the deadline could not be met + * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver + * @param outputShapes A list of shape information of model output operands. + * The index into "outputShapes" corresponds with to index + * of the output operand in the Request outputs vector. + * outputShapes must be empty unless the status is either + * NONE or OUTPUT_INSUFFICIENT_SIZE. + * @param timing Duration of execution. Unless MeasureTiming::YES was passed when + * launching the execution and status is NONE, all times must + * be reported as UINT64_MAX. A driver may choose to report + * any time as UINT64_MAX, indicating that particular measurement is + * not available. + */ + oneway notify_1_3(ErrorStatus status, vec outputShapes, Timing timing); +}; diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal index 00adc1f950..bce6ee227a 100644 --- a/neuralnetworks/1.3/IPreparedModel.hal +++ b/neuralnetworks/1.3/IPreparedModel.hal @@ -16,13 +16,14 @@ package android.hardware.neuralnetworks@1.3; -import @1.0::ErrorStatus; -import @1.2::IExecutionCallback; import @1.2::IPreparedModel; import @1.2::MeasureTiming; import @1.2::OutputShape; import @1.2::Timing; +import ErrorStatus; +import OptionalTimePoint; import Request; +import IExecutionCallback; /** * IPreparedModel describes a model that has been prepared for execution and @@ -65,6 +66,17 @@ interface IPreparedModel extends @1.2::IPreparedModel { * values, the execution should complete successfully (ErrorStatus::NONE): * There must be no failure unless the device itself is in a bad state. * + * execute_1_3 can be called with an optional deadline. If the execution + * is not able to completed before the provided deadline, the execution + * must be aborted, and either {@link + * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link + * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due + * to an abort must be sent the same way as other errors, described above. + * If the service reports that it does not support execution deadlines via + * IDevice::supportsDeadlines, and execute_1_3 is called with a deadline, + * then the argument is invalid, and {@link ErrorStatus::INVALID_ARGUMENT} + * must be returned. + * * Any number of calls to the execute* and executeSynchronously* functions, * in any combination, may be made concurrently, even on the same * IPreparedModel object. @@ -75,6 +87,9 @@ interface IPreparedModel extends @1.2::IPreparedModel { * The duration runs from the time the driver sees the call * to the execute_1_3 function to the time the driver invokes * the callback. + * @param deadline The time by which execution must complete. If the + * execution cannot be finished by the deadline, the + * execution must be aborted. * @param callback A callback object used to return the error status of * the execution. The callback object's notify function must * be called exactly once, even if the execution was @@ -87,8 +102,13 @@ interface IPreparedModel extends @1.2::IPreparedModel { * not large enough to store the resultant values * - INVALID_ARGUMENT if one of the input arguments is * invalid + * - MISSED_DEADLINE_* if the deadline for executing a model + * cannot be met + * - RESOURCE_EXHAUSTED_* if the task was aborted by the + * driver */ - execute_1_3(Request request, MeasureTiming measure, IExecutionCallback callback) + execute_1_3(Request request, MeasureTiming measure, OptionalTimePoint deadline, + IExecutionCallback callback) generates (ErrorStatus status); /** @@ -116,6 +136,17 @@ interface IPreparedModel extends @1.2::IPreparedModel { * (ErrorStatus::NONE): There must be no failure unless the device itself is * in a bad state. * + * executeSynchronously_1_3 can be called with an optional deadline. If the + * execution is not able to completed before the provided deadline, the + * execution must be aborted, and either {@link + * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link + * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due + * to an abort must be sent the same way as other errors, described above. + * If the service reports that it does not support execution deadlines via + * IDevice::supportsDeadlines, and executeSynchronously_1_3 is called with a + * deadline, then the argument is invalid, and + * {@link ErrorStatus::INVALID_ARGUMENT} must be returned. + * * Any number of calls to the execute* and executeSynchronously* functions, * in any combination, may be made concurrently, even on the same * IPreparedModel object. @@ -126,6 +157,9 @@ interface IPreparedModel extends @1.2::IPreparedModel { * The duration runs from the time the driver sees the call * to the executeSynchronously_1_3 function to the time the driver * returns from the function. + * @param deadline The time by which execution must complete. If the + * execution cannot be finished by the deadline, the + * execution must be aborted. * @return status Error status of the execution, must be: * - NONE if execution is performed successfully * - DEVICE_UNAVAILABLE if driver is offline or busy @@ -135,16 +169,22 @@ interface IPreparedModel extends @1.2::IPreparedModel { * corresponding output * - INVALID_ARGUMENT if one of the input arguments is * invalid + * - MISSED_DEADLINE_* if the deadline for executing a model + * cannot be met + * - RESOURCE_EXHAUSTED_* if the task was aborted by the + * driver * @return outputShapes A list of shape information of model output operands. * The index into "outputShapes" corresponds to the index * of the output operand in the Request outputs vector. * outputShapes must be empty unless the status is either * NONE or OUTPUT_INSUFFICIENT_SIZE. - * @return Timing Duration of execution. Unless measure is YES and status is + * @return timing Duration of execution. Unless measure is YES and status is * NONE, all times must be reported as UINT64_MAX. A driver may * choose to report any time as UINT64_MAX, indicating that * measurement is not available. */ - executeSynchronously_1_3(Request request, MeasureTiming measure) - generates (ErrorStatus status, vec outputShapes, Timing timing); + executeSynchronously_1_3(Request request, MeasureTiming measure, + OptionalTimePoint deadline) + generates (ErrorStatus status, vec outputShapes, + Timing timing); }; diff --git a/neuralnetworks/1.3/IPreparedModelCallback.hal b/neuralnetworks/1.3/IPreparedModelCallback.hal index ff295a230e..11ebbf4ab3 100644 --- a/neuralnetworks/1.3/IPreparedModelCallback.hal +++ b/neuralnetworks/1.3/IPreparedModelCallback.hal @@ -16,7 +16,6 @@ package android.hardware.neuralnetworks@1.3; -import @1.0::ErrorStatus; import @1.2::IPreparedModelCallback; import IPreparedModel; @@ -48,6 +47,10 @@ interface IPreparedModelCallback extends @1.2::IPreparedModelCallback { * unspecified error * - INVALID_ARGUMENT if one of the input arguments to * prepareModel is invalid + * - MISSED_DEADLINE_* if the deadline for executing a model + * cannot be met + * - RESOURCE_EXHAUSTED_* if the task was aborted by the + * driver * @param preparedModel A model that has been asynchronously prepared for * execution. If the model was unable to be prepared * due to an error, nullptr must be passed in place of diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index a6d274a05a..b330b50084 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -17,6 +17,7 @@ package android.hardware.neuralnetworks@1.3; import @1.0::DataLocation; +import @1.0::ErrorStatus; import @1.0::PerformanceInfo; import @1.0::RequestArgument; import @1.2::Model.ExtensionNameAndPrefix; @@ -4998,6 +4999,16 @@ enum OperationTypeRange : uint32_t { BASE_MAX = 0xFFFF, }; +/** + * Priority given to a prepared model for execution. + */ +enum Priority : int32_t { + LOW, + MEDIUM, + HIGH, +}; + + /** * The capabilities of a driver. * @@ -5434,3 +5445,49 @@ struct Request { */ vec pools; }; + +/** + * Optional time point of the steady clock (as from std::chrono::steady_clock) + * measured in nanoseconds. + */ +safe_union OptionalTimePoint { + /** No time point provided. */ + Monostate none; + + /** + * Time point of the steady clock (as from std::chrono::steady_clock) + * measured in nanoseconds. + */ + uint64_t nanoseconds; +}; + +/** + * Return status of a function. + */ +enum ErrorStatus : @1.0::ErrorStatus { + /** + * Failure because a deadline could not be met for a task, but future + * deadlines may still be met for the same task after a short delay. + */ + MISSED_DEADLINE_TRANSIENT, + + /** + * Failure because a deadline could not be met for a task, and future + * deadlines will likely also not be met for the same task even after a + * short delay. + */ + MISSED_DEADLINE_PERSISTENT, + + /** + * Failure because of a resource limitation within the driver, but future + * calls for the same task may still succeed after a short delay. + */ + RESOURCE_EXHAUSTED_TRANSIENT, + + /** + * Failure because of a resource limitation within the driver, and future + * calls for the same task will likely also fail even after a short + * delay. + */ + RESOURCE_EXHAUSTED_PERSISTENT, +}; diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t index f3319e5cbe..a973923d8d 100644 --- a/neuralnetworks/1.3/types.t +++ b/neuralnetworks/1.3/types.t @@ -19,6 +19,7 @@ package android.hardware.neuralnetworks@1.3; import @1.0::DataLocation; +import @1.0::ErrorStatus; import @1.0::PerformanceInfo; import @1.0::RequestArgument; import @1.2::Model.ExtensionNameAndPrefix; @@ -89,6 +90,16 @@ enum OperationTypeRange : uint32_t { BASE_MAX = 0xFFFF, }; +/** + * Priority given to a prepared model for execution. + */ +enum Priority : int32_t { + LOW, + MEDIUM, + HIGH, +}; + + /** * The capabilities of a driver. * @@ -525,3 +536,49 @@ struct Request { */ vec pools; }; + +/** + * Optional time point of the steady clock (as from std::chrono::steady_clock) + * measured in nanoseconds. + */ +safe_union OptionalTimePoint { + /** No time point provided. */ + Monostate none; + + /** + * Time point of the steady clock (as from std::chrono::steady_clock) + * measured in nanoseconds. + */ + uint64_t nanoseconds; +}; + +/** + * Return status of a function. + */ +enum ErrorStatus : @1.0::ErrorStatus { + /** + * Failure because a deadline could not be met for a task, but future + * deadlines may still be met for the same task after a short delay. + */ + MISSED_DEADLINE_TRANSIENT, + + /** + * Failure because a deadline could not be met for a task, and future + * deadlines will likely also not be met for the same task even after a + * short delay. + */ + MISSED_DEADLINE_PERSISTENT, + + /** + * Failure because of a resource limitation within the driver, but future + * calls for the same task may still succeed after a short delay. + */ + RESOURCE_EXHAUSTED_TRANSIENT, + + /** + * Failure because of a resource limitation within the driver, and future + * calls for the same task will likely also fail even after a short + * delay. + */ + RESOURCE_EXHAUSTED_PERSISTENT, +}; From 9449a28b2f905279550dd3fbe3602cb5207f3313 Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Wed, 11 Dec 2019 19:08:08 -0800 Subject: [PATCH 0462/1022] Update NNAPI 1.3 VTS tests with new types Bug: 136739795 Bug: 142902514 Bug: 145300530 Test: mma Test: atest VtsHalNeuralnetworksV1_3TargetTest Change-Id: Ie76da9dc9d6993a56bf644cfe20c5f5b421672c9 --- .../vts/functional/GeneratedTestHarness.cpp | 2 +- .../1.2/vts/functional/ValidateBurst.cpp | 5 +- .../1.2/vts/functional/ValidateRequest.cpp | 2 +- neuralnetworks/1.3/vts/functional/Android.bp | 11 +- .../1.3/vts/functional/BasicTests.cpp | 1 - .../1.3/vts/functional/Callbacks.cpp | 103 ++++++++- .../functional/CompilationCachingTests.cpp | 14 +- .../vts/functional/GeneratedTestHarness.cpp | 8 +- neuralnetworks/1.3/vts/functional/Utils.cpp | 27 +++ .../1.3/vts/functional/ValidateBurst.cpp | 20 +- .../1.3/vts/functional/ValidateModel.cpp | 8 +- .../1.3/vts/functional/ValidateRequest.cpp | 11 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 6 +- .../vts/functional/include/1.3/Callbacks.h | 212 +++++++++++++++++- .../1.3/vts/functional/include/1.3/Utils.h | 36 +++ 15 files changed, 411 insertions(+), 55 deletions(-) create mode 100644 neuralnetworks/1.3/vts/functional/Utils.cpp create mode 100644 neuralnetworks/1.3/vts/functional/include/1.3/Utils.h diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp index 4909214a3f..599fd1d9be 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp @@ -272,7 +272,7 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo int n; std::tie(n, outputShapes, timing, std::ignore) = controller->compute(request, testConfig.measureTiming, keys); - executionStatus = nn::convertResultCodeToErrorStatus(n); + executionStatus = nn::convertToV1_0(nn::convertResultCodeToErrorStatus(n)); break; } diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp index 416744f902..ec9629bccb 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp @@ -296,7 +296,8 @@ static void validateBurstFmqLength(const sp& preparedModel, // collect serialized result by running regular burst const auto [nRegular, outputShapesRegular, timingRegular, fallbackRegular] = controllerRegular->compute(request, MeasureTiming::NO, keys); - const ErrorStatus statusRegular = nn::convertResultCodeToErrorStatus(nRegular); + const ErrorStatus statusRegular = + nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nRegular)); EXPECT_FALSE(fallbackRegular); // skip test if regular burst output isn't useful for testing a failure @@ -312,7 +313,7 @@ static void validateBurstFmqLength(const sp& preparedModel, // large enough to return the serialized result const auto [nSmall, outputShapesSmall, timingSmall, fallbackSmall] = controllerSmall->compute(request, MeasureTiming::NO, keys); - const ErrorStatus statusSmall = nn::convertResultCodeToErrorStatus(nSmall); + const ErrorStatus statusSmall = nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nSmall)); EXPECT_NE(ErrorStatus::NONE, statusSmall); EXPECT_EQ(0u, outputShapesSmall.size()); EXPECT_TRUE(badTiming(timingSmall)); diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp index 2d83b8186c..7b5ff9b8e4 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp @@ -107,7 +107,7 @@ static void validate(const sp& preparedModel, const std::string& // execute and verify const auto [n, outputShapes, timing, fallback] = burst->compute(request, measure, keys); - const ErrorStatus status = nn::convertResultCodeToErrorStatus(n); + const ErrorStatus status = nn::convertToV1_0(nn::convertResultCodeToErrorStatus(n)); EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); EXPECT_EQ(outputShapes.size(), 0); EXPECT_TRUE(badTiming(timing)); diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp index e2795de420..e7a9fd34c3 100644 --- a/neuralnetworks/1.3/vts/functional/Android.bp +++ b/neuralnetworks/1.3/vts/functional/Android.bp @@ -15,11 +15,12 @@ // cc_library_static { - name: "VtsHalNeuralNetworksV1_3Callbacks", + name: "VtsHalNeuralNetworksV1_3_utils", defaults: ["VtsHalTargetTestDefaults"], export_include_dirs: ["include"], srcs: [ "Callbacks.cpp", + "Utils.cpp", ], static_libs: [ "android.hardware.neuralnetworks@1.0", @@ -29,7 +30,7 @@ cc_library_static { ], header_libs: [ "libbase_headers", - ] + ], } cc_test { @@ -50,6 +51,9 @@ cc_test { "libnativewindow", ], static_libs: [ + "VtsHalNeuralNetworksV1_0_utils", + "VtsHalNeuralNetworksV1_2Callbacks", + "VtsHalNeuralNetworksV1_3_utils", "android.hardware.neuralnetworks@1.0", "android.hardware.neuralnetworks@1.1", "android.hardware.neuralnetworks@1.2", @@ -60,9 +64,6 @@ cc_test { "libhidlmemory", "libneuralnetworks_generated_test_harness", "libneuralnetworks_utils", - "VtsHalNeuralNetworksV1_0_utils", - "VtsHalNeuralNetworksV1_2Callbacks", - "VtsHalNeuralNetworksV1_3Callbacks", ], whole_static_libs: [ "neuralnetworks_generated_V1_0_example", diff --git a/neuralnetworks/1.3/vts/functional/BasicTests.cpp b/neuralnetworks/1.3/vts/functional/BasicTests.cpp index b64dc2f61b..891850cfa4 100644 --- a/neuralnetworks/1.3/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.3/vts/functional/BasicTests.cpp @@ -21,7 +21,6 @@ namespace android::hardware::neuralnetworks::V1_3::vts::functional { using V1_0::DeviceStatus; -using V1_0::ErrorStatus; using V1_0::PerformanceInfo; using V1_2::Constant; using V1_2::DeviceType; diff --git a/neuralnetworks/1.3/vts/functional/Callbacks.cpp b/neuralnetworks/1.3/vts/functional/Callbacks.cpp index 4f08e72a86..5768e3794a 100644 --- a/neuralnetworks/1.3/vts/functional/Callbacks.cpp +++ b/neuralnetworks/1.3/vts/functional/Callbacks.cpp @@ -24,12 +24,16 @@ namespace android::hardware::neuralnetworks::V1_3::implementation { -using V1_0::ErrorStatus; +using V1_2::OutputShape; +using V1_2::Timing; + +constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits::max(), + .timeInDriver = std::numeric_limits::max()}; // PreparedModelCallback methods begin here -Return PreparedModelCallback::notify(ErrorStatus errorStatus, - const sp& preparedModel) { +Return PreparedModelCallback::notifyInternal(ErrorStatus errorStatus, + const sp& preparedModel) { { std::lock_guard hold(mMutex); @@ -48,14 +52,19 @@ Return PreparedModelCallback::notify(ErrorStatus errorStatus, return Void(); } -Return PreparedModelCallback::notify_1_2(ErrorStatus errorStatus, - const sp& preparedModel) { - return notify(errorStatus, preparedModel); +Return PreparedModelCallback::notify(V1_0::ErrorStatus errorStatus, + const sp& preparedModel) { + return notifyInternal(static_cast(errorStatus), preparedModel); } -Return PreparedModelCallback::notify_1_3(ErrorStatus errorStatus, +Return PreparedModelCallback::notify_1_2(V1_0::ErrorStatus errorStatus, + const sp& preparedModel) { + return notifyInternal(static_cast(errorStatus), preparedModel); +} + +Return PreparedModelCallback::notify_1_3(V1_3::ErrorStatus errorStatus, const sp& preparedModel) { - return notify(errorStatus, preparedModel); + return notifyInternal(errorStatus, preparedModel); } void PreparedModelCallback::wait() const { @@ -73,4 +82,82 @@ sp PreparedModelCallback::getPreparedModel() const { return mPreparedModel; } +// ExecutionCallback methods begin here + +Return ExecutionCallback::notify(V1_0::ErrorStatus errorStatus) { + return notifyInternal(static_cast(errorStatus), {}, kNoTiming); +} + +Return ExecutionCallback::notify_1_2(V1_0::ErrorStatus errorStatus, + const hidl_vec& outputShapes, + const Timing& timing) { + return notifyInternal(static_cast(errorStatus), outputShapes, timing); +} + +Return ExecutionCallback::notify_1_3(V1_3::ErrorStatus errorStatus, + const hidl_vec& outputShapes, + const Timing& timing) { + return notifyInternal(errorStatus, outputShapes, timing); +} + +void ExecutionCallback::wait() const { + std::unique_lock lock(mMutex); + mCondition.wait(lock, [this] { return mNotified; }); +} + +ErrorStatus ExecutionCallback::getStatus() const { + wait(); + return mErrorStatus; +} + +const std::vector& ExecutionCallback::getOutputShapes() const { + wait(); + return mOutputShapes; +} + +Timing ExecutionCallback::getTiming() const { + wait(); + return mTiming; +} + +Return ExecutionCallback::notifyInternal(ErrorStatus errorStatus, + hidl_vec outputShapes, Timing timing) { + // check results + if (errorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { + // outputShapes must not be empty if OUTPUT_INSUFFICIENT_SIZE. + if (outputShapes.size() == 0) { + LOG(ERROR) << "Notifid with empty output shape vector when OUTPUT_INSUFFICIENT_SIZE"; + errorStatus = ErrorStatus::GENERAL_FAILURE; + outputShapes = {}; + timing = kNoTiming; + } + } else if (errorStatus != ErrorStatus::NONE) { + // outputShapes must be empty if errorStatus is neither NONE nor OUTPUT_INSUFFICIENT_SIZE. + if (outputShapes.size() != 0) { + LOG(ERROR) << "Notified with non-empty output shape vector when error status is " + "neither NONE nor OUTPUT_INSUFFICIENT_SIZE"; + errorStatus = ErrorStatus::GENERAL_FAILURE; + outputShapes = {}; + timing = kNoTiming; + } + } + + // store results + { + std::lock_guard hold(mMutex); + + // quick-return if object has already been notified + if (mNotified) { + return Void(); + } + + mErrorStatus = errorStatus; + mOutputShapes = std::move(outputShapes); + mTiming = timing; + mNotified = true; + } + mCondition.notify_all(); + return Void(); +} + } // namespace android::hardware::neuralnetworks::V1_3::implementation diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp index 5cb466fe28..576e5240b0 100644 --- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp @@ -29,6 +29,7 @@ #include #include "1.3/Callbacks.h" +#include "1.3/Utils.h" #include "GeneratedTestHarness.h" #include "MemoryUtils.h" #include "TestHarness.h" @@ -49,7 +50,6 @@ namespace android::hardware::neuralnetworks::V1_3::vts::functional { using namespace test_helper; using implementation::PreparedModelCallback; -using V1_0::ErrorStatus; using V1_1::ExecutionPreference; using V1_2::Constant; using V1_2::OperationType; @@ -238,8 +238,8 @@ class CompilationCachingTestBase : public testing::Test { mCacheDir.push_back('/'); Return ret = kDevice->getNumberOfCacheFilesNeeded( - [this](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) { - EXPECT_EQ(ErrorStatus::NONE, status); + [this](V1_0::ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) { + EXPECT_EQ(V1_0::ErrorStatus::NONE, status); mNumModelCache = numModelCache; mNumDataCache = numDataCache; }); @@ -324,9 +324,9 @@ class CompilationCachingTestBase : public testing::Test { // Launch prepare model. sp preparedModelCallback = new PreparedModelCallback(); hidl_array cacheToken(mToken); - Return prepareLaunchStatus = - kDevice->prepareModel_1_3(model, ExecutionPreference::FAST_SINGLE_ANSWER, - modelCache, dataCache, cacheToken, preparedModelCallback); + Return prepareLaunchStatus = kDevice->prepareModel_1_3( + model, ExecutionPreference::FAST_SINGLE_ANSWER, kDefaultPriority, {}, modelCache, + dataCache, cacheToken, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(static_cast(prepareLaunchStatus), ErrorStatus::NONE); @@ -370,7 +370,7 @@ class CompilationCachingTestBase : public testing::Test { sp preparedModelCallback = new PreparedModelCallback(); hidl_array cacheToken(mToken); Return prepareLaunchStatus = kDevice->prepareModelFromCache_1_3( - modelCache, dataCache, cacheToken, preparedModelCallback); + kDefaultPriority, {}, modelCache, dataCache, cacheToken, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); if (static_cast(prepareLaunchStatus) != ErrorStatus::NONE) { *preparedModel = nullptr; diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 805d5b53aa..82e63ac546 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -44,7 +44,6 @@ #include #include "1.0/Utils.h" -#include "1.2/Callbacks.h" #include "1.3/Callbacks.h" #include "ExecutionBurstController.h" #include "MemoryUtils.h" @@ -56,9 +55,9 @@ namespace android::hardware::neuralnetworks::V1_3::vts::functional { using namespace test_helper; using hidl::memory::V1_0::IMemory; +using implementation::ExecutionCallback; using implementation::PreparedModelCallback; using V1_0::DataLocation; -using V1_0::ErrorStatus; using V1_0::RequestArgument; using V1_1::ExecutionPreference; using V1_2::Constant; @@ -66,7 +65,6 @@ using V1_2::MeasureTiming; using V1_2::OutputShape; using V1_2::SymmPerChannelQuantParams; using V1_2::Timing; -using V1_2::implementation::ExecutionCallback; using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; namespace { @@ -453,7 +451,7 @@ static std::vector getOutputBuffers(const TestModel& testModel, cons static Return ExecutePreparedModel(const sp& preparedModel, const Request& request, MeasureTiming measure, sp& callback) { - return preparedModel->execute_1_3(request, measure, callback); + return preparedModel->execute_1_3(request, measure, {}, callback); } static Return ExecutePreparedModel(const sp& preparedModel, const Request& request, MeasureTiming measure, @@ -461,7 +459,7 @@ static Return ExecutePreparedModel(const sp& prepar Timing* timing) { ErrorStatus result; Return ret = preparedModel->executeSynchronously_1_3( - request, measure, + request, measure, {}, [&result, outputShapes, timing](ErrorStatus error, const hidl_vec& shapes, const Timing& time) { result = error; diff --git a/neuralnetworks/1.3/vts/functional/Utils.cpp b/neuralnetworks/1.3/vts/functional/Utils.cpp new file mode 100644 index 0000000000..23e2af823e --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/Utils.cpp @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#include "1.3/Utils.h" + +#include + +namespace android::hardware::neuralnetworks::V1_3 { + +::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus) { + return os << toString(errorStatus); +} + +} // namespace android::hardware::neuralnetworks::V1_3 diff --git a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp index 7df804645a..6ff9dfd3a8 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp @@ -34,7 +34,6 @@ namespace android::hardware::neuralnetworks::V1_3::vts::functional { using nn::ExecutionBurstController; using nn::RequestChannelSender; using nn::ResultChannelReceiver; -using V1_0::ErrorStatus; using V1_0::Request; using V1_2::FmqRequestDatum; using V1_2::FmqResultDatum; @@ -80,16 +79,17 @@ static void createBurst(const sp& preparedModel, const sp burstContext; const Return ret = preparedModel->configureExecutionBurst( callback, *fmqRequestDescriptor, *fmqResultDescriptor, - [&errorStatus, &burstContext](ErrorStatus status, const sp& context) { + [&errorStatus, &burstContext](V1_0::ErrorStatus status, + const sp& context) { errorStatus = status; burstContext = context; }); ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(ErrorStatus::NONE, errorStatus); + ASSERT_EQ(V1_0::ErrorStatus::NONE, errorStatus); ASSERT_NE(nullptr, burstContext.get()); // return values @@ -144,7 +144,7 @@ static void validate(RequestChannelSender* sender, ResultChannelReceiver* receiv auto results = receiver->getBlocking(); ASSERT_TRUE(results.has_value()); const auto [status, outputShapes, timing] = std::move(*results); - EXPECT_NE(ErrorStatus::NONE, status); + EXPECT_NE(V1_0::ErrorStatus::NONE, status); EXPECT_EQ(0u, outputShapes.size()); EXPECT_TRUE(badTiming(timing)); } @@ -302,14 +302,15 @@ static void validateBurstFmqLength(const sp& preparedModel, // collect serialized result by running regular burst const auto [nRegular, outputShapesRegular, timingRegular, fallbackRegular] = controllerRegular->compute(request, MeasureTiming::NO, keys); - const ErrorStatus statusRegular = nn::convertResultCodeToErrorStatus(nRegular); + const V1_0::ErrorStatus statusRegular = + nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nRegular)); EXPECT_FALSE(fallbackRegular); // skip test if regular burst output isn't useful for testing a failure // caused by having too small of a length for the result FMQ const std::vector serialized = android::nn::serialize(statusRegular, outputShapesRegular, timingRegular); - if (statusRegular != ErrorStatus::NONE || + if (statusRegular != V1_0::ErrorStatus::NONE || serialized.size() <= kExecutionBurstChannelSmallLength) { return; } @@ -318,8 +319,9 @@ static void validateBurstFmqLength(const sp& preparedModel, // large enough to return the serialized result const auto [nSmall, outputShapesSmall, timingSmall, fallbackSmall] = controllerSmall->compute(request, MeasureTiming::NO, keys); - const ErrorStatus statusSmall = nn::convertResultCodeToErrorStatus(nSmall); - EXPECT_NE(ErrorStatus::NONE, statusSmall); + const V1_0::ErrorStatus statusSmall = + nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nSmall)); + EXPECT_NE(V1_0::ErrorStatus::NONE, statusSmall); EXPECT_EQ(0u, outputShapesSmall.size()); EXPECT_TRUE(badTiming(timingSmall)); EXPECT_FALSE(fallbackSmall); diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index cc862645a5..43e53ef55d 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -18,13 +18,13 @@ #include "1.0/Utils.h" #include "1.3/Callbacks.h" +#include "1.3/Utils.h" #include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" namespace android::hardware::neuralnetworks::V1_3::vts::functional { using implementation::PreparedModelCallback; -using V1_0::ErrorStatus; using V1_1::ExecutionPreference; using V1_2::SymmPerChannelQuantParams; using HidlToken = @@ -48,9 +48,9 @@ static void validatePrepareModel(const sp& device, const std::string& m SCOPED_TRACE(message + " [prepareModel_1_3]"); sp preparedModelCallback = new PreparedModelCallback(); - Return prepareLaunchStatus = - device->prepareModel_1_3(model, preference, hidl_vec(), - hidl_vec(), HidlToken(), preparedModelCallback); + Return prepareLaunchStatus = device->prepareModel_1_3( + model, preference, kDefaultPriority, {}, hidl_vec(), + hidl_vec(), HidlToken(), preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(prepareLaunchStatus)); diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index 96dc589d50..9fb4c6e55b 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -18,7 +18,7 @@ #include #include "1.0/Utils.h" -#include "1.2/Callbacks.h" +#include "1.3/Callbacks.h" #include "ExecutionBurstController.h" #include "GeneratedTestHarness.h" #include "TestHarness.h" @@ -27,11 +27,10 @@ namespace android::hardware::neuralnetworks::V1_3::vts::functional { -using V1_0::ErrorStatus; +using implementation::ExecutionCallback; using V1_2::MeasureTiming; using V1_2::OutputShape; using V1_2::Timing; -using V1_2::implementation::ExecutionCallback; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// @@ -63,7 +62,7 @@ static void validate(const sp& preparedModel, const std::string& sp executionCallback = new ExecutionCallback(); Return executeLaunchStatus = - preparedModel->execute_1_3(request, measure, executionCallback); + preparedModel->execute_1_3(request, measure, {}, executionCallback); ASSERT_TRUE(executeLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(executeLaunchStatus)); @@ -81,7 +80,7 @@ static void validate(const sp& preparedModel, const std::string& SCOPED_TRACE(message + " [executeSynchronously_1_3]"); Return executeStatus = preparedModel->executeSynchronously_1_3( - request, measure, + request, measure, {}, [](ErrorStatus error, const hidl_vec& outputShapes, const Timing& timing) { ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); @@ -163,7 +162,7 @@ void validateRequest(const sp& preparedModel, const Request& req void validateRequestFailure(const sp& preparedModel, const Request& request) { SCOPED_TRACE("Expecting request to fail [executeSynchronously_1_3]"); Return executeStatus = preparedModel->executeSynchronously_1_3( - request, MeasureTiming::NO, + request, MeasureTiming::NO, {}, [](ErrorStatus error, const hidl_vec& outputShapes, const Timing& timing) { ASSERT_NE(ErrorStatus::NONE, error); EXPECT_EQ(outputShapes.size(), 0); diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index 1140b68635..7a32b0441c 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -23,6 +23,7 @@ #include #include "1.0/Utils.h" #include "1.3/Callbacks.h" +#include "1.3/Utils.h" #include "GeneratedTestHarness.h" #include "TestHarness.h" #include "Utils.h" @@ -32,7 +33,6 @@ namespace android::hardware::neuralnetworks::V1_3::vts::functional { using HidlToken = hidl_array(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; using implementation::PreparedModelCallback; -using V1_0::ErrorStatus; using V1_1::ExecutionPreference; // internal helper function @@ -55,8 +55,8 @@ void createPreparedModel(const sp& device, const Model& model, // launch prepare model const sp preparedModelCallback = new PreparedModelCallback(); const Return prepareLaunchStatus = device->prepareModel_1_3( - model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec(), - hidl_vec(), HidlToken(), preparedModelCallback); + model, ExecutionPreference::FAST_SINGLE_ANSWER, kDefaultPriority, {}, + hidl_vec(), hidl_vec(), HidlToken(), preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); diff --git a/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h b/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h index fb19a841e1..e9dec2d7ae 100644 --- a/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h +++ b/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h @@ -18,8 +18,11 @@ #define ANDROID_HARDWARE_NEURALNETWORKS_V1_3_CALLBACKS_H #include +#include #include +#include #include +#include #include #include #include @@ -136,7 +139,7 @@ class PreparedModelCallback : public IPreparedModelCallback { * @param preparedModel Returned model that has been prepared for execution, * nullptr if the model was unable to be prepared. */ - Return notify_1_3(V1_0::ErrorStatus status, + Return notify_1_3(V1_3::ErrorStatus status, const sp& preparedModel) override; /** @@ -158,7 +161,7 @@ class PreparedModelCallback : public IPreparedModelCallback { * - GENERAL_FAILURE if there is an unspecified error * - INVALID_ARGUMENT if the input model is invalid */ - V1_0::ErrorStatus getStatus() const; + ErrorStatus getStatus() const; /** * Retrieves the model that has been prepared for execution from the @@ -173,13 +176,216 @@ class PreparedModelCallback : public IPreparedModelCallback { sp getPreparedModel() const; private: + Return notifyInternal(ErrorStatus status, const sp& preparedModel); + mutable std::mutex mMutex; mutable std::condition_variable mCondition; bool mNotified GUARDED_BY(mMutex) = false; - V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; + ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE; sp mPreparedModel; }; +/** + * The ExecutionCallback class is used to receive the results of the execution + * from a task executing asynchronously with respect to the runtime. If a + * calling thread calls wait or get* on a ExecutionCallback object and the + * corresponding asynchronous task has not finished the execution, the calling + * thread will block until the asynchronous task has either called one of the + * notify* methods. + * + * If the callback object is notified more than once, only the results of the + * first call to notify* are used, and the results from subsequent calls are + * discarded. + * + * This callback object is passed as an argument to IPreparedModel::execute*. + */ +class ExecutionCallback : public IExecutionCallback { + public: + /** + * IExecutionCallback::notify marks the callback object with the return + * status of the asynchronous execution that held this callback and enables + * all prior and future wait calls on the ExecutionCallback object to + * proceed. + * + * One of the IExecutionCallback::notify* methods must be called on a given + * ExecutionCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from launching the asynchronous task + * (if the launch fails) or from the asynchronous task itself (if the + * launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large + * enough to store the resultant values + * - INVALID_ARGUMENT if the input request is invalid + */ + Return notify(V1_0::ErrorStatus status) override; + + /** + * IExecutionCallback::notify_1_2 marks the callback object with the results + * (error status, dynamic output shapes, and timing information) of the + * asynchronous execution that held this callback and enables all prior and + * future wait calls on the ExecutionCallback object to proceed. + * + * One of the IExecutionCallback::notify* methods must be called on a given + * ExecutionCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from launching the asynchronous task + * (if the launch fails) or from the asynchronous task itself (if the + * launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified + * error + * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is + * not large enough to store the corresponding output + * - INVALID_ARGUMENT if one of the input arguments to prepareModel is + * invalid + * @param outputShapes A list of shape information of model output operands. + * The index into "outputShapes" corresponds to the index of the output + * operand in the Request outputs vector. outputShapes must be empty + * unless the status is either NONE or OUTPUT_INSUFFICIENT_SIZE. + * @param Timing Duration of execution. Unless MeasureTiming::YES was passed + * when launching the execution and status is NONE, all times must be + * reported as UINT64_MAX. A driver may choose to report any time as + * UINT64_MAX, indicating that particular measurement is not available. + */ + Return notify_1_2(V1_0::ErrorStatus status, + const hidl_vec& outputShapes, + const V1_2::Timing& timing) override; + + /** + * IExecutionCallback::notify_1_3 marks the callback object with the results + * (error status, dynamic output shapes, and timing information) of the + * asynchronous execution that held this callback and enables all prior and + * future wait calls on the ExecutionCallback object to proceed. + * + * One of the IExecutionCallback::notify* methods must be called on a given + * ExecutionCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from launching the asynchronous task + * (if the launch fails) or from the asynchronous task itself (if the + * launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified + * error + * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is + * not large enough to store the corresponding output + * - INVALID_ARGUMENT if one of the input arguments to prepareModel is + * invalid + * - MISSED_DEADLINE_* if the deadline was not met + * @param outputShapes A list of shape information of model output operands. + * The index into "outputShapes" corresponds to the index of the output + * operand in the Request outputs vector. outputShapes must be empty + * unless the status is either NONE or OUTPUT_INSUFFICIENT_SIZE. + * @param Timing Duration of execution. Unless MeasureTiming::YES was passed + * when launching the execution and status is NONE, all times must be + * reported as UINT64_MAX. A driver may choose to report any time as + * UINT64_MAX, indicating that particular measurement is not available. + */ + Return notify_1_3(V1_3::ErrorStatus status, + const hidl_vec& outputShapes, + const V1_2::Timing& timing) override; + + /** + * ExecutionCallback::wait blocks until notify* has been called on the + * callback object. + */ + void wait() const; + + /** + * Retrieves the error status returned from the asynchronous task launched + * by one of the IPreparedModel::execute* methods. If + * IPreparedModel::execute* (but not IPreparedModel::executeSynchronously*) + * has not finished asynchronously executing, this call will block until the + * asynchronous task notifies the object. + * + * @return status Error status returned from launching the asynchronous task + * (if the launch fails) or from the asynchronous task itself (if the + * launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified + * error + * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is + * not large enough to store the corresponding output + * - INVALID_ARGUMENT if one of the input arguments to prepareModel is + * invalid + * - MISSED_DEADLINE_* if the deadline could not be met + */ + V1_3::ErrorStatus getStatus() const; + + /** + * Retrieves the error status returned from the asynchronous task launched + * by one of the IPreparedModel::execute* methods. If + * IPreparedModel::execute* (but not IPreparedModel::executeSynchronously*) + * has not finished asynchronously executing, this call will block until the + * asynchronous task notifies the object. + * + * If the asynchronous task was launched by IPreparedModel::execute, an + * empty vector will be returned. + * + * @return outputShapes A list of shape information of model output + * operands. The index into "outputShapes" corresponds to the index of + * the output operand in the Request outputs vector. outputShapes must + * be empty unless the status is either NONE or + * OUTPUT_INSUFFICIENT_SIZE. outputShaps may be empty if the status is + * NONE and all model output operands are fully-specified at execution + * time. outputShapes must have the same number of elements as the + * number of model output operands if the status is + * OUTPUT_INSUFFICIENT_SIZE, or if the status is NONE and the model has + * at least one output operand that is not fully-specified. + */ + const std::vector& getOutputShapes() const; + + /** + * Retrieves the error status returned from the asynchronous task launched + * by one of the IPreparedModel::execute* methods. If + * IPreparedModel::execute* (but not IPreparedModel::executeSynchronously*) + * has not finished asynchronously executing, this call will block until the + * asynchronous task notifies the object. + * + * If the asynchronous task was launched by IPreparedModel::execute, every + * time must be UINT64_MAX. + * + * @return timing Duration of the execution. Every time must be UINT64_MAX + * unless the status is NONE. + */ + V1_2::Timing getTiming() const; + + private: + /* + * ExecutionCallback::notifyInternal stores the results of the execution + * (status, output shapes, and timing information) in the ExecutionCallback + * object before any call to wait or get* return. It then enables all prior + * and future wait calls on the ExecutionCallback object to proceed. + */ + Return notifyInternal(V1_3::ErrorStatus errorStatus, + hidl_vec outputShapes, V1_2::Timing timing); + + // members + mutable std::mutex mMutex; + mutable std::condition_variable mCondition; + bool mNotified GUARDED_BY(mMutex) = false; + V1_3::ErrorStatus mErrorStatus = V1_3::ErrorStatus::GENERAL_FAILURE; + std::vector mOutputShapes = {}; + V1_2::Timing mTiming = {}; +}; + } // namespace android::hardware::neuralnetworks::V1_3::implementation #endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_CALLBACKS_H diff --git a/neuralnetworks/1.3/vts/functional/include/1.3/Utils.h b/neuralnetworks/1.3/vts/functional/include/1.3/Utils.h new file mode 100644 index 0000000000..3661b66445 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/include/1.3/Utils.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_3_UTILS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_3_UTILS_H + +#include +#include + +namespace android::hardware::neuralnetworks { + +inline constexpr V1_3::Priority kDefaultPriority = V1_3::Priority::MEDIUM; + +} // namespace android::hardware::neuralnetworks + +namespace android::hardware::neuralnetworks::V1_3 { + +// pretty-print values for error messages +::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus); + +} // namespace android::hardware::neuralnetworks::V1_3 + +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_UTILS_H From 616701d3cdb4108a0482cf4539ce7eaff270fc2e Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Tue, 7 Jan 2020 14:52:44 -0800 Subject: [PATCH 0463/1022] Create VTS tests for QoS in NNAPI Bug: 136739795 Bug: 142902514 Bug: 145300530 Test: mma Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: If3ab91cfb3158e4c33e809ff3b149dff47cda76f --- neuralnetworks/1.3/vts/functional/Android.bp | 1 + .../vts/functional/GeneratedTestHarness.cpp | 10 +- .../1.3/vts/functional/GeneratedTestHarness.h | 1 + .../vts/functional/QualityOfServiceTests.cpp | 299 ++++++++++++++++++ .../1.3/vts/functional/ValidateModel.cpp | 32 +- .../1.3/vts/functional/ValidateRequest.cpp | 28 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 25 +- 7 files changed, 375 insertions(+), 21 deletions(-) create mode 100644 neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp index e7a9fd34c3..ce2d3a917a 100644 --- a/neuralnetworks/1.3/vts/functional/Android.bp +++ b/neuralnetworks/1.3/vts/functional/Android.bp @@ -40,6 +40,7 @@ cc_test { "BasicTests.cpp", "CompilationCachingTests.cpp", "GeneratedTestHarness.cpp", + "QualityOfServiceTests.cpp", "TestAssertions.cpp", "ValidateBurst.cpp", "ValidateModel.cpp", diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 82e63ac546..a2c0c4efa0 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -45,6 +45,7 @@ #include "1.0/Utils.h" #include "1.3/Callbacks.h" +#include "1.3/Utils.h" #include "ExecutionBurstController.h" #include "MemoryUtils.h" #include "TestHarness.h" @@ -714,7 +715,8 @@ void Execute(const sp& device, const TestModel& testModel, TestKind tes } break; case TestKind::QUANTIZATION_COUPLING: { ASSERT_TRUE(testModel.hasQuant8CoupledOperands()); - createPreparedModel(device, model, &preparedModel, /*reportSkipping*/ false); + createPreparedModel(device, model, &preparedModel, + /*reportSkipping*/ false); TestModel signedQuantizedModel = convertQuant8AsymmOperandsToSigned(testModel); sp preparedCoupledModel; createPreparedModel(device, createModel(signedQuantizedModel), &preparedCoupledModel, @@ -743,6 +745,12 @@ void Execute(const sp& device, const TestModel& testModel, TestKind tes void GeneratedTestBase::SetUp() { testing::TestWithParam::SetUp(); ASSERT_NE(kDevice, nullptr); + + const Return ret = + kDevice->supportsDeadlines([this](bool prepareModelDeadline, bool executionDeadline) { + mSupportsDeadlines = {prepareModelDeadline, executionDeadline}; + }); + ASSERT_TRUE(ret.isOk()); } std::vector getNamedModels(const FilterFn& filter) { diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h index 2273e3bfe4..fe695b471d 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h @@ -36,6 +36,7 @@ class GeneratedTestBase : public testing::TestWithParam { void SetUp() override; const sp kDevice = getData(std::get(GetParam())); const test_helper::TestModel& kTestModel = *getData(std::get(GetParam())); + std::pair mSupportsDeadlines; }; using FilterFn = std::function; diff --git a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp new file mode 100644 index 0000000000..62ffcda036 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp @@ -0,0 +1,299 @@ +/* + * 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. + */ + +#include "1.0/Utils.h" +#include "1.3/Callbacks.h" +#include "1.3/Utils.h" +#include "GeneratedTestHarness.h" +#include "Utils.h" + +namespace android::hardware::neuralnetworks::V1_3::vts::functional { + +using implementation::ExecutionCallback; +using implementation::PreparedModelCallback; +using test_helper::TestBuffer; +using test_helper::TestModel; +using V1_1::ExecutionPreference; +using V1_2::MeasureTiming; +using V1_2::OutputShape; +using V1_2::Timing; + +using HidlToken = + hidl_array(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; + +enum class DeadlineBoundType { NOW, UNLIMITED }; +constexpr std::array deadlineBounds = {DeadlineBoundType::NOW, + DeadlineBoundType::UNLIMITED}; +std::string toString(DeadlineBoundType type) { + switch (type) { + case DeadlineBoundType::NOW: + return "NOW"; + case DeadlineBoundType::UNLIMITED: + return "UNLIMITED"; + } + LOG(FATAL) << "Unrecognized DeadlineBoundType: " << static_cast(type); + return {}; +} + +using Results = std::tuple, Timing>; +using MaybeResults = std::optional; + +using ExecutionFunction = + std::function& preparedModel, const Request& request, + DeadlineBoundType deadlineBound)>; + +static OptionalTimePoint makeOptionalTimePoint(DeadlineBoundType deadlineBoundType) { + OptionalTimePoint deadline; + switch (deadlineBoundType) { + case DeadlineBoundType::NOW: { + const auto currentTime = std::chrono::steady_clock::now(); + const auto currentTimeInNanoseconds = + std::chrono::time_point_cast(currentTime); + const uint64_t nanosecondsSinceEpoch = + currentTimeInNanoseconds.time_since_epoch().count(); + deadline.nanoseconds(nanosecondsSinceEpoch); + } break; + case DeadlineBoundType::UNLIMITED: { + uint64_t unlimited = std::numeric_limits::max(); + deadline.nanoseconds(unlimited); + } break; + } + return deadline; +} + +void runPrepareModelTest(const sp& device, const Model& model, Priority priority, + std::optional deadlineBound) { + OptionalTimePoint deadline; + if (deadlineBound.has_value()) { + deadline = makeOptionalTimePoint(deadlineBound.value()); + } + + // see if service can handle model + bool fullySupportsModel = false; + const Return supportedCall = device->getSupportedOperations_1_3( + model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { + ASSERT_EQ(ErrorStatus::NONE, status); + ASSERT_NE(0ul, supported.size()); + fullySupportsModel = std::all_of(supported.begin(), supported.end(), + [](bool valid) { return valid; }); + }); + ASSERT_TRUE(supportedCall.isOk()); + + // launch prepare model + const sp preparedModelCallback = new PreparedModelCallback(); + const Return prepareLaunchStatus = device->prepareModel_1_3( + model, ExecutionPreference::FAST_SINGLE_ANSWER, priority, deadline, + hidl_vec(), hidl_vec(), HidlToken(), preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); + + // retrieve prepared model + preparedModelCallback->wait(); + const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + const sp preparedModelV1_0 = preparedModelCallback->getPreparedModel(); + const sp preparedModel = + IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr); + + // The getSupportedOperations_1_3 call returns a list of operations that are + // guaranteed not to fail if prepareModel_1_3 is called, and + // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed. + // If a driver has any doubt that it can prepare an operation, it must + // return false. So here, if a driver isn't sure if it can support an + // operation, but reports that it successfully prepared the model, the test + // can continue. + if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { + ASSERT_EQ(nullptr, preparedModel.get()); + return; + } + + // verify return status + if (!deadlineBound.has_value()) { + EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); + } else { + switch (deadlineBound.value()) { + case DeadlineBoundType::NOW: + // If the execution was launched with a deadline of NOW, the + // deadline has already passed when the driver would launch the + // execution. In this case, the driver must return + // MISSED_DEADLINE_*. + EXPECT_TRUE(prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT || + prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT); + break; + case DeadlineBoundType::UNLIMITED: + // If an unlimited deadline is supplied, we expect the execution to + // proceed normally. In this case, check it normally by breaking out + // of the switch statement. + EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); + break; + } + } + ASSERT_EQ(prepareReturnStatus == ErrorStatus::NONE, preparedModel.get() != nullptr); +} + +void runPrepareModelTests(const sp& device, const Model& model, + bool supportsPrepareModelDeadline) { + // test priority + for (auto priority : hidl_enum_range{}) { + SCOPED_TRACE("priority: " + toString(priority)); + if (priority == kDefaultPriority) continue; + runPrepareModelTest(device, model, priority, {}); + } + + // test deadline + if (supportsPrepareModelDeadline) { + for (auto deadlineBound : deadlineBounds) { + SCOPED_TRACE("deadlineBound: " + toString(deadlineBound)); + runPrepareModelTest(device, model, kDefaultPriority, deadlineBound); + } + } +} + +static MaybeResults executeAsynchronously(const sp& preparedModel, + const Request& request, DeadlineBoundType deadlineBound) { + SCOPED_TRACE("asynchronous"); + const MeasureTiming measure = MeasureTiming::NO; + const OptionalTimePoint deadline = makeOptionalTimePoint(deadlineBound); + + // launch execution + const sp callback = new ExecutionCallback(); + Return ret = preparedModel->execute_1_3(request, measure, deadline, callback); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(ErrorStatus::NONE, ret.withDefault(ErrorStatus::GENERAL_FAILURE)); + if (!ret.isOk() || ret != ErrorStatus::NONE) return std::nullopt; + + // retrieve execution results + callback->wait(); + const ErrorStatus status = callback->getStatus(); + hidl_vec outputShapes = callback->getOutputShapes(); + const Timing timing = callback->getTiming(); + + // return results + return Results{status, std::move(outputShapes), timing}; +} + +static MaybeResults executeSynchronously(const sp& preparedModel, + const Request& request, DeadlineBoundType deadlineBound) { + SCOPED_TRACE("synchronous"); + const MeasureTiming measure = MeasureTiming::NO; + const OptionalTimePoint deadline = makeOptionalTimePoint(deadlineBound); + + // configure results callback + MaybeResults results; + const auto cb = [&results](const auto&... args) { *results = {args...}; }; + + // run execution + const Return ret = + preparedModel->executeSynchronously_1_3(request, measure, deadline, cb); + EXPECT_TRUE(ret.isOk()); + if (!ret.isOk()) return std::nullopt; + + // return results + return results; +} + +void runExecutionTest(const sp& preparedModel, const TestModel& testModel, + const Request& request, bool synchronous, DeadlineBoundType deadlineBound) { + const ExecutionFunction execute = synchronous ? executeSynchronously : executeAsynchronously; + + // Perform execution and unpack results. + const auto results = execute(preparedModel, request, deadlineBound); + if (!results.has_value()) return; + const auto& [status, outputShapes, timing] = results.value(); + + // Verify no timing information was returned + EXPECT_EQ(UINT64_MAX, timing.timeOnDevice); + EXPECT_EQ(UINT64_MAX, timing.timeInDriver); + + // Validate deadline information if applicable. + switch (deadlineBound) { + case DeadlineBoundType::NOW: + // If the execution was launched with a deadline of NOW, the + // deadline has already passed when the driver would launch the + // execution. In this case, the driver must return + // MISSED_DEADLINE_*. + ASSERT_TRUE(status == ErrorStatus::MISSED_DEADLINE_TRANSIENT || + status == ErrorStatus::MISSED_DEADLINE_PERSISTENT); + return; + case DeadlineBoundType::UNLIMITED: + // If an unlimited deadline is supplied, we expect the execution to + // proceed normally. In this case, check it normally by breaking out + // of the switch statement. + ASSERT_EQ(ErrorStatus::NONE, status); + break; + } + + // If the model output operands are fully specified, outputShapes must be either + // either empty, or have the same number of elements as the number of outputs. + ASSERT_TRUE(outputShapes.size() == 0 || outputShapes.size() == testModel.outputIndexes.size()); + + // Go through all outputs, check returned output shapes. + for (uint32_t i = 0; i < outputShapes.size(); i++) { + EXPECT_TRUE(outputShapes[i].isSufficient); + const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions; + const std::vector actual = outputShapes[i].dimensions; + EXPECT_EQ(expect, actual); + } + + // Retrieve execution results. + ASSERT_TRUE(nn::compliantWithV1_0(request)); + const V1_0::Request request10 = nn::convertToV1_0(request); + const std::vector outputs = getOutputBuffers(request10); + + // We want "close-enough" results. + checkResults(testModel, outputs); +} + +void runExecutionTests(const sp& preparedModel, const TestModel& testModel, + const Request& request) { + for (bool synchronous : {false, true}) { + for (auto deadlineBound : deadlineBounds) { + runExecutionTest(preparedModel, testModel, request, synchronous, deadlineBound); + } + } +} + +void runTests(const sp& device, const TestModel& testModel, + std::pair supportsDeadlines) { + // setup + const auto [supportsPrepareModelDeadline, supportsExecutionDeadline] = supportsDeadlines; + if (!supportsPrepareModelDeadline && !supportsExecutionDeadline) return; + const Model model = createModel(testModel); + + // run prepare model tests + runPrepareModelTests(device, model, supportsPrepareModelDeadline); + + if (supportsExecutionDeadline) { + // prepare model + sp preparedModel; + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; + + // run execution tests + const Request request = nn::convertToV1_3(createRequest(testModel)); + runExecutionTests(preparedModel, testModel, request); + } +} + +class DeadlineTest : public GeneratedTestBase {}; + +TEST_P(DeadlineTest, Test) { + runTests(kDevice, kTestModel, mSupportsDeadlines); +} + +INSTANTIATE_GENERATED_TEST(DeadlineTest, + [](const TestModel& testModel) { return !testModel.expectFailure; }); + +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 43e53ef55d..a21142880e 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -44,12 +44,18 @@ static void validateGetSupportedOperations(const sp& device, const std: } static void validatePrepareModel(const sp& device, const std::string& message, - const Model& model, ExecutionPreference preference) { + const Model& model, ExecutionPreference preference, + bool testDeadline) { SCOPED_TRACE(message + " [prepareModel_1_3]"); + OptionalTimePoint deadline; + if (testDeadline) { + deadline.nanoseconds(std::numeric_limits::max()); + } + sp preparedModelCallback = new PreparedModelCallback(); Return prepareLaunchStatus = device->prepareModel_1_3( - model, preference, kDefaultPriority, {}, hidl_vec(), + model, preference, kDefaultPriority, deadline, hidl_vec(), hidl_vec(), HidlToken(), preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(prepareLaunchStatus)); @@ -73,12 +79,13 @@ static bool validExecutionPreference(ExecutionPreference preference) { // to the model does not leave this function. static void validate(const sp& device, const std::string& message, Model model, const std::function& mutation, - ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) { + ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER, + bool testDeadline = false) { mutation(&model); - if (validExecutionPreference(preference)) { + if (validExecutionPreference(preference) && !testDeadline) { validateGetSupportedOperations(device, message, model); } - validatePrepareModel(device, message, model, preference); + validatePrepareModel(device, message, model, preference, testDeadline); } static uint32_t addOperand(Model* model) { @@ -714,9 +721,19 @@ static void mutateExecutionPreferenceTest(const sp& device, const Model } } +///////////////////////// DEADLINE ///////////////////////// + +static void deadlineTest(const sp& device, const Model& model) { + const std::string message = "deadlineTest: deadline not supported"; + const auto noop = [](Model*) {}; + validate(device, message, model, noop, ExecutionPreference::FAST_SINGLE_ANSWER, + /*testDeadline=*/true); +} + ////////////////////////// ENTRY POINT ////////////////////////////// -void validateModel(const sp& device, const Model& model) { +void validateModel(const sp& device, const Model& model, + bool prepareModelDeadlineSupported) { mutateOperandTypeTest(device, model); mutateOperandRankTest(device, model); mutateOperandScaleTest(device, model); @@ -732,6 +749,9 @@ void validateModel(const sp& device, const Model& model) { addOperationInputTest(device, model); addOperationOutputTest(device, model); mutateExecutionPreferenceTest(device, model); + if (!prepareModelDeadlineSupported) { + deadlineTest(device, model); + } } } // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index 9fb4c6e55b..be4112ac2d 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -43,7 +43,8 @@ static bool badTiming(Timing timing) { // that use the request. Note that the request here is passed by value, and any // mutation to the request does not leave this function. static void validate(const sp& preparedModel, const std::string& message, - Request request, const std::function& mutation) { + Request request, const std::function& mutation, + bool testDeadline = false) { mutation(&request); // We'd like to test both with timing requested and without timing @@ -56,13 +57,18 @@ static void validate(const sp& preparedModel, const std::string& }; MeasureTiming measure = (hash & 1) ? MeasureTiming::YES : MeasureTiming::NO; + OptionalTimePoint deadline; + if (testDeadline) { + deadline.nanoseconds(std::numeric_limits::max()); + } + // asynchronous { SCOPED_TRACE(message + " [execute_1_3]"); sp executionCallback = new ExecutionCallback(); Return executeLaunchStatus = - preparedModel->execute_1_3(request, measure, {}, executionCallback); + preparedModel->execute_1_3(request, measure, deadline, executionCallback); ASSERT_TRUE(executeLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(executeLaunchStatus)); @@ -80,7 +86,7 @@ static void validate(const sp& preparedModel, const std::string& SCOPED_TRACE(message + " [executeSynchronously_1_3]"); Return executeStatus = preparedModel->executeSynchronously_1_3( - request, measure, {}, + request, measure, deadline, [](ErrorStatus error, const hidl_vec& outputShapes, const Timing& timing) { ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); @@ -92,7 +98,7 @@ static void validate(const sp& preparedModel, const std::string& // burst // TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2. - { + if (!testDeadline) { SCOPED_TRACE(message + " [burst]"); ASSERT_TRUE(nn::compliantWithV1_0(request)); @@ -152,11 +158,23 @@ static void removeOutputTest(const sp& preparedModel, const Requ } } +///////////////////////// DEADLINE //////////////////////////////////// + +static void deadlineTest(const sp& preparedModel, const Request& request) { + const std::string message = "deadlineTest: deadline not supported"; + const auto noop = [](Request*) {}; + validate(preparedModel, message, request, noop, /*testDeadline=*/true); +} + ///////////////////////////// ENTRY POINT ////////////////////////////////// -void validateRequest(const sp& preparedModel, const Request& request) { +void validateRequest(const sp& preparedModel, const Request& request, + bool executionDeadlineSupported) { removeInputTest(preparedModel, request); removeOutputTest(preparedModel, request); + if (!executionDeadlineSupported) { + deadlineTest(preparedModel, request); + } } void validateRequestFailure(const sp& preparedModel, const Request& request) { diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index 7a32b0441c..93c8f13c17 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -84,6 +84,7 @@ void createPreparedModel(const sp& device, const Model& model, << std::endl; GTEST_SKIP(); } + ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus); ASSERT_NE(nullptr, preparedModel->get()); } @@ -122,23 +123,27 @@ std::string printNeuralnetworksHidlTest( INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest); // Forward declaration from ValidateModel.cpp -void validateModel(const sp& device, const Model& model); +void validateModel(const sp& device, const Model& model, + bool prepareModelDeadlineSupported); // Forward declaration from ValidateRequest.cpp -void validateRequest(const sp& preparedModel, const Request& request); +void validateRequest(const sp& preparedModel, const Request& request, + bool executionDeadlineSupported); // Forward declaration from ValidateRequest.cpp void validateRequestFailure(const sp& preparedModel, const Request& request); // Forward declaration from ValidateBurst.cpp void validateBurst(const sp& preparedModel, const V1_0::Request& request); -void validateEverything(const sp& device, const Model& model, const Request& request) { - validateModel(device, model); +void validateEverything(const sp& device, const Model& model, const Request& request, + std::pair supportsDeadlines) { + const auto [prepareModelDeadlineSupported, executionDeadlineSupported] = supportsDeadlines; + validateModel(device, model, prepareModelDeadlineSupported); // Create IPreparedModel. sp preparedModel; createPreparedModel(device, model, &preparedModel); if (preparedModel == nullptr) return; - validateRequest(preparedModel, request); + validateRequest(preparedModel, request, executionDeadlineSupported); // TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2. ASSERT_TRUE(nn::compliantWithV1_0(request)); @@ -146,10 +151,12 @@ void validateEverything(const sp& device, const Model& model, const Req validateBurst(preparedModel, request10); } -void validateFailure(const sp& device, const Model& model, const Request& request) { +void validateFailure(const sp& device, const Model& model, const Request& request, + std::pair supportsDeadlines) { + const bool prepareModelDeadlineSupported = supportsDeadlines.first; // TODO: Should this always succeed? // What if the invalid input is part of the model (i.e., a parameter). - validateModel(device, model); + validateModel(device, model, prepareModelDeadlineSupported); // Create IPreparedModel. sp preparedModel; @@ -163,9 +170,9 @@ TEST_P(ValidationTest, Test) { const Model model = createModel(kTestModel); const Request request = nn::convertToV1_3(createRequest(kTestModel)); if (kTestModel.expectFailure) { - validateFailure(kDevice, model, request); + validateFailure(kDevice, model, request, mSupportsDeadlines); } else { - validateEverything(kDevice, model, request); + validateEverything(kDevice, model, request, mSupportsDeadlines); } } From 1d2be904dff069379b07b3bf2082f58d7193aba5 Mon Sep 17 00:00:00 2001 From: Enrico Granata Date: Tue, 21 Jan 2020 16:08:23 -0800 Subject: [PATCH 0464/1022] Remove spurious cflags from AudioControl HAL 1.0 Nothing in the Android tree appears to reference AudCntrlDrv, and there is no reason why we should ship a HAL implementation running at O0 Test: build Change-Id: I14a3d910d9654ce438930bfa83cec39a7ef99dc2 --- automotive/audiocontrol/1.0/default/Android.bp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/automotive/audiocontrol/1.0/default/Android.bp b/automotive/audiocontrol/1.0/default/Android.bp index 3d04c890bc..ae4b8057ae 100644 --- a/automotive/audiocontrol/1.0/default/Android.bp +++ b/automotive/audiocontrol/1.0/default/Android.bp @@ -30,9 +30,4 @@ cc_binary { "libutils", ], vintf_fragments: ["audiocontrol_manifest.xml"], - cflags: [ - "-DLOG_TAG=\"AudCntrlDrv\"", - "-O0", - "-g", - ], } From f7fd4fd72096abc2df4d8d133e6e01db879df8cd Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 16 Jan 2020 11:09:13 -0800 Subject: [PATCH 0465/1022] Support IPv6 MTU in IRadio 1.5 Change mtu->mtuV4 and add mtuV6 for DataProfileInfo and SetupDataCallResult Test: mm and build Bug: 146668814 Change-Id: I33320281730fdb91d2b07d11cd24a95d0834c9dd --- current.txt | 2 +- radio/1.5/types.hal | 84 ++++++++++++++-- .../1.5/vts/functional/radio_hidl_hal_api.cpp | 99 ++++++++++--------- 3 files changed, 130 insertions(+), 55 deletions(-) diff --git a/current.txt b/current.txt index 09759b92ad..e7b1e88ec0 100644 --- a/current.txt +++ b/current.txt @@ -666,7 +666,7 @@ def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardwar ## # BEGIN Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present ## -696f9000adf181682a49510baf93127e2ca62cfc84173b36afd164c797bc5771 android.hardware.radio@1.5::types +70cbe7cbeb51834f124a8b5940336dc9ec158a17487ab8b905ae9cf62f66f476 android.hardware.radio@1.5::types 996f98ffe508a2f6f1755c1511b50067f7883f7c445dea9f3e931385f020b7ab android.hardware.radio@1.5::IRadio 20d52e66fd548f89bcb98cda42749a591ce8f439a2a7148617adac0c967ad937 android.hardware.radio@1.5::IRadioIndication 1512f6e1198e1aa0ebcbdb1694d0ed500a3e7791d6f305327866112331d82b66 android.hardware.radio@1.5::IRadioResponse diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index d629a3fe55..efd2e35203 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -16,6 +16,10 @@ package android.hardware.radio@1.5; +import @1.0::ApnAuthType; +import @1.0::DataProfileId; +import @1.0::DataProfileInfoType; +import @1.0::RadioAccessFamily; import @1.1::EutranBands; import @1.1::GeranBands; import @1.1::RadioAccessNetworks; @@ -303,13 +307,74 @@ enum ApnTypes : @1.4::ApnTypes { }; /** - * Extended from @1.4::DataProfileInfo to update ApnTypes to 1.5 version + * Extended from @1.4::DataProfileInfo to update ApnTypes to 1.5 version and replace mtu with + * mtuV4 and mtuV6. In the future, this must be extended instead of overwritten. */ struct DataProfileInfo { - @1.4::DataProfileInfo base; + + /** ID of the data profile. */ + DataProfileId profileId; + + /** The APN name. */ + string apn; + + /** PDP_type values. */ + PdpProtocolType protocol; + + /** PDP_type values used on roaming network. */ + PdpProtocolType roamingProtocol; + + /** APN authentication type. */ + ApnAuthType authType; + + /** The username for APN, or empty string. */ + string user; + + /** The password for APN, or empty string. */ + string password; + + /** Data profile technology type. */ + DataProfileInfoType type; + + /** The period in seconds to limit the maximum connections. */ + int32_t maxConnsTime; + + /** The maximum connections during maxConnsTime. */ + int32_t maxConns; + + /** + * The required wait time in seconds after a successful UE initiated disconnect of a given PDN + * connection before the device can send a new PDN connection request for that given PDN. + */ + int32_t waitTime; + + /** True to enable the profile, false to disable. */ + bool enabled; /** Supported APN types bitmap. See ApnTypes for the value of each bit. */ bitfield supportedApnTypesBitmap; + + /** The bearer bitmap. See RadioAccessFamily for the value of each bit. */ + bitfield bearerBitmap; + + /** Maximum transmission unit (MTU) size in bytes for IPv4. */ + int32_t mtuV4; + + /** Maximum transmission unit (MTU) size in bytes for IPv6. */ + int32_t mtuV6; + + /** + * True if this data profile was used to bring up the last default (i.e internet) data + * connection successfully. + */ + bool preferred; + + /** + * If true, modem must persist this data profile and profileId must not be + * set to DataProfileId.INVALID. If the same data profile exists, this data profile must + * overwrite it. + */ + bool persistent; }; /** @@ -356,7 +421,8 @@ struct LinkAddress { /** * Overwritten from @1.4::SetupDataCallResult in order to update the addresses to 1.5 - * version. In 1.5 the type of addresses changes to vector of LinkAddress. + * version. In 1.5 the type of addresses changes to vector of LinkAddress, and mtu is replaced by + * mtuV4 and mtuV6. */ struct SetupDataCallResult { /** Data call fail cause. DataCallFailCause.NONE if no error. */ @@ -410,10 +476,16 @@ struct SetupDataCallResult { vec pcscf; /** - * MTU received from network. Value <= 0 means network has either not sent a value or sent an - * invalid value. + * MTU received from network for IPv4. + * Value <= 0 means network has either not sent a value or sent an invalid value. */ - int32_t mtu; + int32_t mtuV4; + + /** + * MTU received from network for IPv6. + * Value <= 0 means network has either not sent a value or sent an invalid value. + */ + int32_t mtuV6; }; enum Domain : int32_t { diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp index 77d9a02df0..01258cfebc 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp @@ -833,23 +833,24 @@ TEST_F(RadioHidlTest_v1_5, setupDataCall_1_5) { android::hardware::radio::V1_5::DataProfileInfo dataProfileInfo; memset(&dataProfileInfo, 0, sizeof(dataProfileInfo)); - dataProfileInfo.base.profileId = DataProfileId::DEFAULT; - dataProfileInfo.base.apn = hidl_string("internet"); - dataProfileInfo.base.protocol = PdpProtocolType::IP; - dataProfileInfo.base.roamingProtocol = PdpProtocolType::IP; - dataProfileInfo.base.authType = ApnAuthType::NO_PAP_NO_CHAP; - dataProfileInfo.base.user = hidl_string("username"); - dataProfileInfo.base.password = hidl_string("password"); - dataProfileInfo.base.type = DataProfileInfoType::THREE_GPP; - dataProfileInfo.base.maxConnsTime = 300; - dataProfileInfo.base.maxConns = 20; - dataProfileInfo.base.waitTime = 0; - dataProfileInfo.base.enabled = true; + dataProfileInfo.profileId = DataProfileId::DEFAULT; + dataProfileInfo.apn = hidl_string("internet"); + dataProfileInfo.protocol = PdpProtocolType::IP; + dataProfileInfo.roamingProtocol = PdpProtocolType::IP; + dataProfileInfo.authType = ApnAuthType::NO_PAP_NO_CHAP; + dataProfileInfo.user = hidl_string("username"); + dataProfileInfo.password = hidl_string("password"); + dataProfileInfo.type = DataProfileInfoType::THREE_GPP; + dataProfileInfo.maxConnsTime = 300; + dataProfileInfo.maxConns = 20; + dataProfileInfo.waitTime = 0; + dataProfileInfo.enabled = true; dataProfileInfo.supportedApnTypesBitmap = 320; - dataProfileInfo.base.bearerBitmap = 161543; - dataProfileInfo.base.mtu = 0; - dataProfileInfo.base.preferred = true; - dataProfileInfo.base.persistent = false; + dataProfileInfo.bearerBitmap = 161543; + dataProfileInfo.mtuV4 = 0; + dataProfileInfo.mtuV6 = 0; + dataProfileInfo.preferred = true; + dataProfileInfo.persistent = false; bool roamingAllowed = false; @@ -884,23 +885,24 @@ TEST_F(RadioHidlTest_v1_5, setInitialAttachApn_1_5) { // Create a dataProfileInfo android::hardware::radio::V1_5::DataProfileInfo dataProfileInfo; memset(&dataProfileInfo, 0, sizeof(dataProfileInfo)); - dataProfileInfo.base.profileId = DataProfileId::DEFAULT; - dataProfileInfo.base.apn = hidl_string("internet"); - dataProfileInfo.base.protocol = PdpProtocolType::IPV4V6; - dataProfileInfo.base.roamingProtocol = PdpProtocolType::IPV4V6; - dataProfileInfo.base.authType = ApnAuthType::NO_PAP_NO_CHAP; - dataProfileInfo.base.user = hidl_string("username"); - dataProfileInfo.base.password = hidl_string("password"); - dataProfileInfo.base.type = DataProfileInfoType::THREE_GPP; - dataProfileInfo.base.maxConnsTime = 300; - dataProfileInfo.base.maxConns = 20; - dataProfileInfo.base.waitTime = 0; - dataProfileInfo.base.enabled = true; + dataProfileInfo.profileId = DataProfileId::DEFAULT; + dataProfileInfo.apn = hidl_string("internet"); + dataProfileInfo.protocol = PdpProtocolType::IPV4V6; + dataProfileInfo.roamingProtocol = PdpProtocolType::IPV4V6; + dataProfileInfo.authType = ApnAuthType::NO_PAP_NO_CHAP; + dataProfileInfo.user = hidl_string("username"); + dataProfileInfo.password = hidl_string("password"); + dataProfileInfo.type = DataProfileInfoType::THREE_GPP; + dataProfileInfo.maxConnsTime = 300; + dataProfileInfo.maxConns = 20; + dataProfileInfo.waitTime = 0; + dataProfileInfo.enabled = true; dataProfileInfo.supportedApnTypesBitmap = 320; - dataProfileInfo.base.bearerBitmap = 161543; - dataProfileInfo.base.mtu = 0; - dataProfileInfo.base.preferred = true; - dataProfileInfo.base.persistent = false; + dataProfileInfo.bearerBitmap = 161543; + dataProfileInfo.mtuV4 = 0; + dataProfileInfo.mtuV6 = 0; + dataProfileInfo.preferred = true; + dataProfileInfo.persistent = false; radio_v1_5->setInitialAttachApn_1_5(serial, dataProfileInfo); @@ -923,23 +925,24 @@ TEST_F(RadioHidlTest_v1_5, setDataProfile_1_5) { // Create a dataProfileInfo android::hardware::radio::V1_5::DataProfileInfo dataProfileInfo; memset(&dataProfileInfo, 0, sizeof(dataProfileInfo)); - dataProfileInfo.base.profileId = DataProfileId::DEFAULT; - dataProfileInfo.base.apn = hidl_string("internet"); - dataProfileInfo.base.protocol = PdpProtocolType::IPV4V6; - dataProfileInfo.base.roamingProtocol = PdpProtocolType::IPV4V6; - dataProfileInfo.base.authType = ApnAuthType::NO_PAP_NO_CHAP; - dataProfileInfo.base.user = hidl_string("username"); - dataProfileInfo.base.password = hidl_string("password"); - dataProfileInfo.base.type = DataProfileInfoType::THREE_GPP; - dataProfileInfo.base.maxConnsTime = 300; - dataProfileInfo.base.maxConns = 20; - dataProfileInfo.base.waitTime = 0; - dataProfileInfo.base.enabled = true; + dataProfileInfo.profileId = DataProfileId::DEFAULT; + dataProfileInfo.apn = hidl_string("internet"); + dataProfileInfo.protocol = PdpProtocolType::IPV4V6; + dataProfileInfo.roamingProtocol = PdpProtocolType::IPV4V6; + dataProfileInfo.authType = ApnAuthType::NO_PAP_NO_CHAP; + dataProfileInfo.user = hidl_string("username"); + dataProfileInfo.password = hidl_string("password"); + dataProfileInfo.type = DataProfileInfoType::THREE_GPP; + dataProfileInfo.maxConnsTime = 300; + dataProfileInfo.maxConns = 20; + dataProfileInfo.waitTime = 0; + dataProfileInfo.enabled = true; dataProfileInfo.supportedApnTypesBitmap = 320; - dataProfileInfo.base.bearerBitmap = 161543; - dataProfileInfo.base.mtu = 0; - dataProfileInfo.base.preferred = true; - dataProfileInfo.base.persistent = true; + dataProfileInfo.bearerBitmap = 161543; + dataProfileInfo.mtuV4 = 0; + dataProfileInfo.mtuV6 = 0; + dataProfileInfo.preferred = true; + dataProfileInfo.persistent = true; // Create a dataProfileInfoList android::hardware::hidl_vec From 8f6b67b0a668ad4cacb88d933417e350716bc17f Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 16 Jan 2020 17:00:49 -0800 Subject: [PATCH 0466/1022] Add Support for RPLMN to Voice and Data RegState -Define RegistrationFailCause as an enum -Combine voice and data reg state into a single struct -Define a safe-union for AN-specific registration info Bug: 73629308 Test: make && make VtsHalRadioV1_5TargetTest && make cf_x86_64_phone-userdebug Change-Id: I43df3cffd4c55f2c5df8eaf0235772e5930dced5 --- current.txt | 6 +- radio/1.5/IRadio.hal | 18 ++ radio/1.5/IRadioResponse.hal | 28 +++ radio/1.5/types.hal | 190 ++++++++++++++++++ .../functional/radio_hidl_hal_utils_v1_5.h | 8 + radio/1.5/vts/functional/radio_response.cpp | 16 ++ 6 files changed, 263 insertions(+), 3 deletions(-) diff --git a/current.txt b/current.txt index 58b97558f3..fb6006fdce 100644 --- a/current.txt +++ b/current.txt @@ -666,10 +666,10 @@ def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardwar ## # BEGIN Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present ## -70cbe7cbeb51834f124a8b5940336dc9ec158a17487ab8b905ae9cf62f66f476 android.hardware.radio@1.5::types -996f98ffe508a2f6f1755c1511b50067f7883f7c445dea9f3e931385f020b7ab android.hardware.radio@1.5::IRadio +b3f250fe4f5f01ea3a2387eb7ae7e975699f6871e09b797d5ebfe18c2a489e98 android.hardware.radio@1.5::types +6268d208631b21d1e85bfad338642ac5ca7ac6c83b411283515a4342b5d673f7 android.hardware.radio@1.5::IRadio 20d52e66fd548f89bcb98cda42749a591ce8f439a2a7148617adac0c967ad937 android.hardware.radio@1.5::IRadioIndication -1512f6e1198e1aa0ebcbdb1694d0ed500a3e7791d6f305327866112331d82b66 android.hardware.radio@1.5::IRadioResponse +1344e7cfaa2cf259b05ea4f65a731552f0254df6604938cf8be94e04fd62a6a9 android.hardware.radio@1.5::IRadioResponse 5971a891d7d8843e9fb9f44583a9a0a265ec42fd5e4e1c95c9803454d21fabf7 android.hardware.radio.config@1.3::types a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal index e41989c90c..52e579aee9 100644 --- a/radio/1.5/IRadio.hal +++ b/radio/1.5/IRadio.hal @@ -245,4 +245,22 @@ interface IRadio extends @1.4::IRadio { * Response callback is IRadioResponse.getBarringInfoResponse() */ oneway getBarringInfo(int32_t serial); + + /** + * Request current voice registration state + * + * @param serial Serial number of request. + * + * Response function is IRadioResponse.getVoiceRegistrationStateResponse_1_5() + */ + oneway getVoiceRegistrationState_1_5(int32_t serial); + + /** + * Request current data registration state + * + * @param serial Serial number of request. + * + * Response function is IRadioResponse.getDataRegistrationStateResponse_1_5() + */ + oneway getDataRegistrationState_1_5(int32_t serial); }; diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal index 2ed789a7ab..3f832091e4 100644 --- a/radio/1.5/IRadioResponse.hal +++ b/radio/1.5/IRadioResponse.hal @@ -20,6 +20,7 @@ import @1.0::RadioResponseInfo; import @1.4::IRadioResponse; import @1.5::BarringInfo; import @1.5::SetupDataCallResult; +import @1.5::RegStateResult; /** * Interface declaring response functions to solicited radio requests. @@ -170,4 +171,31 @@ interface IRadioResponse extends @1.4::IRadioResponse { * RadioError:MODEM_ERR */ oneway getBarringInfoResponse(RadioResponseInfo info, vec barringInfos); + + /** + * @param info Response info struct containing response type, serial no. and error + * @param voiceRegResponse Current Voice registration response as defined by RegStateResult + * in types.hal + * + * Valid errors returned: + * RadioError:NONE + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:INTERNAL_ERR + */ + oneway getVoiceRegistrationStateResponse_1_5(RadioResponseInfo info, + RegStateResult voiceRegResponse); + + /** + * @param info Response info struct containing response type, serial no. and error + * @param dataRegResponse Current Data registration response as defined by RegStateResult in + * types.hal + * + * Valid errors returned: + * RadioError:NONE + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:INTERNAL_ERR + * RadioError:NOT_PROVISIONED + */ + oneway getDataRegistrationStateResponse_1_5(RadioResponseInfo info, + RegStateResult dataRegResponse); }; diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index efd2e35203..55f2137b2e 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -20,6 +20,7 @@ import @1.0::ApnAuthType; import @1.0::DataProfileId; import @1.0::DataProfileInfoType; import @1.0::RadioAccessFamily; +import @1.0::RegState; import @1.1::EutranBands; import @1.1::GeranBands; import @1.1::RadioAccessNetworks; @@ -39,7 +40,10 @@ import @1.4::CellIdentityNr; import @1.4::DataCallFailCause; import @1.4::DataConnActiveStatus; import @1.4::DataProfileInfo; +import @1.4::LteVopsInfo; +import @1.4::NrIndicators; import @1.4::PdpProtocolType; +import @1.4::RadioTechnology; import android.hidl.safe_union@1.0::Monostate; @@ -635,3 +639,189 @@ enum IndicationFilter : @1.2::IndicationFilter { /** Control the unsolicited sending of barring info updates via onBarringInfo */ BARRING_INFO = 1 << 6, }; + +/** + * Call fail causes for Circuit-switched service enumerated in 3GPP TS 24.008, 10.5.3.6 and + * 10.5.147. Additional detail is available in 3GPP TS 24.008 Annex G. + */ +enum RegistrationFailCause : int32_t { + /** 0 - None */ + NONE = 0, + /** 2 - IMSI unknown in HLR */ + IMSI_UNKNOWN_IN_HLR = 2, + /** 3 - Illegal MS */ + ILLEGAL_MS = 3, + /** 4 - Illegal ME */ + IMSI_UNKNOWN_IN_VLR = 4, + /** 5 - PLMN not allowed */ + IMEI_NOT_ACCEPTED = 5, + /** 6 - Location area not allowed */ + ILLEGAL_ME = 6, + /** 7 - Roaming not allowed */ + GPRS_SERVICES_NOT_ALLOWED = 7, + /** 8 - No Suitable Cells in this Location Area */ + GPRS_AND_NON_GPRS_SERVICES_NOT_ALLOWED = 8, + /** 9 - Network failure */ + MS_IDENTITY_CANNOT_BE_DERIVED_BY_NETWORK = 9, + /** 10 - Persistent location update reject */ + IMPLICITLY_DETACHED = 10, + /** 11 - PLMN not allowed */ + PLMN_NOT_ALLOWED = 11, + /** 12 - Location area not allowed */ + LOCATION_AREA_NOT_ALLOWED = 12, + /** 13 - Roaming not allowed in this Location Area */ + ROAMING_NOT_ALLOWED = 13, + /** 14 - GPRS Services not allowed in this PLMN */ + GPRS_SERVICES_NOT_ALLOWED_IN_PLMN = 14, + /** 15 - No Suitable Cells in this Location Area */ + NO_SUITABLE_CELLS = 15, + /** 16 - MSC temporarily not reachable */ + MSC_TEMPORARILY_NOT_REACHABLE = 15, + /** 17 - Network Failure */ + NETWORK_FAILURE = 17, + /** 20 - MAC Failure */ + MAC_FAILURE = 20, + /** 21 - Sync Failure */ + SYNC_FAILURE = 21, + /** 22 - Congestion */ + CONGESTION = 22, + /** 23 - GSM Authentication unacceptable */ + GSM_AUTHENTICATION_UNACCEPTABLE = 23, + /** 25 - Not Authorized for this CSG */ + NOT_AUTHORIZED_FOR_THIS_CSG = 25, + /** 28 SMS provided via GPRS in this routing area */ + SMS_PROVIDED_BY_GPRS_IN_ROUTING_AREA, + /** 32 - Service option not supported */ + SERVICE_OPTION_NOT_SUPPORTED = 32, + /** 33 - Requested service option not subscribed */ + SERVICE_OPTION_NOT_SUBSCRIBED = 33, + /** 34 - Service option temporarily out of order */ + SERVICE_OPTION_TEMPORARILY_OUT_OF_ORDER = 34, + /** 38 - Call cannot be identified */ + CALL_CANNOT_BE_IDENTIFIED = 38, + /** 40 No PDP context activated */ + NO_PDP_CONTEXT_ACTIVATED = 40, + /** 48-63 - Retry upon entry into a new cell */ + RETRY_UPON_ENTRY_INTO_NEW_CELL_1 = 48, + RETRY_UPON_ENTRY_INTO_NEW_CELL_2 = 49, + RETRY_UPON_ENTRY_INTO_NEW_CELL_3 = 50, + RETRY_UPON_ENTRY_INTO_NEW_CELL_4 = 51, + RETRY_UPON_ENTRY_INTO_NEW_CELL_5 = 52, + RETRY_UPON_ENTRY_INTO_NEW_CELL_6 = 53, + RETRY_UPON_ENTRY_INTO_NEW_CELL_7 = 54, + RETRY_UPON_ENTRY_INTO_NEW_CELL_8 = 55, + RETRY_UPON_ENTRY_INTO_NEW_CELL_9 = 56, + RETRY_UPON_ENTRY_INTO_NEW_CELL_10 = 57, + RETRY_UPON_ENTRY_INTO_NEW_CELL_11 = 58, + RETRY_UPON_ENTRY_INTO_NEW_CELL_12 = 59, + RETRY_UPON_ENTRY_INTO_NEW_CELL_13 = 60, + RETRY_UPON_ENTRY_INTO_NEW_CELL_14 = 61, + RETRY_UPON_ENTRY_INTO_NEW_CELL_15 = 62, + RETRY_UPON_ENTRY_INTO_NEW_CELL_16 = 63, + /** 95 - Semantically incorrect message */ + SEMANTICALLY_INCORRECT_MESSAGE = 95, + /** 96 - Invalid mandatory information */ + INVALID_MANDATORY_INFORMATION = 96, + /** 97 - Message type non-existent or not implemented */ + MESSAGE_TYPE_NON_EXISTENT_OR_NOT_IMPLEMENTED = 97, + /** 98 - Message type not compatible with protocol state */ + MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98, + /** 99 - Information element non-existent or not implemented */ + INFORMATION_ELEMENT_NON_EXISTENT_OR_NOT_IMPLEMENTED = 99, + /** 100 - Conditional IE error */ + CONDITIONAL_IE_ERROR = 100, + /** 101 - Message not compatible with protocol state */ + MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101, + /** 111 - Protocol error, unspecified */ + PROTOCOL_ERROR_UNSPECIFIED = 111, +}; + +enum PrlIndicator : int32_t { + NOT_REGISTERED = -1, + NOT_IN_PRL = 0, + IN_PRL = 1, +}; + +struct RegStateResult { + /** + * Registration state + * + * If the RAT is indicated as a GERAN, UTRAN, or CDMA2000 technology, this value reports + * registration in the Circuit-switched domain. + * If the RAT is indicated as an EUTRAN, NGRAN, or another technology that does not support + * circuit-switched services, this value reports registration in the Packet-switched domain. + */ + RegState regState; + + /** + * Indicates the available voice radio technology, valid values as + * defined by RadioTechnology. + */ + RadioTechnology rat; + + /** + * Cause code reported by the network in case registration fails. This will be a mobility + * management cause code defined for MM, GMM, MME or equivalent as appropriate for the RAT. + */ + RegistrationFailCause reasonForDenial; + + /** CellIdentity */ + CellIdentity cellIdentity; + + /** + * The most-recent PLMN-ID upon which the UE registered (or attempted to register if a failure + * is reported in the reasonForDenial field). This PLMN shall be in standard format consisting + * of a 3 digit MCC concatenated with a 2 or 3 digit MNC. + */ + string registeredPlmn; + + /** + * Access-technology-specific registration information, such as for Cdma2000. + */ + safe_union AccessTechnologySpecificInfo { + Monostate noinit; + + struct Cdma2000RegistrationInfo { + /** + * concurrent services support indicator. if registered on a CDMA system. + * false - Concurrent services not supported, + * true - Concurrent services supported + */ + bool cssSupported; + + /** + * TSB-58 Roaming Indicator if registered on a CDMA or EVDO system or -1 if not. + * Valid values are 0-255. + */ + int32_t roamingIndicator; + + /** + * Indicates whether the current system is in the PRL if registered on a CDMA or EVDO + * system or -1 if not. 0=not in the PRL, 1=in the PRL. + */ + PrlIndicator systemIsInPrl; + + /** + * Default Roaming Indicator from the PRL if registered on a CDMA or EVDO system or -1 + * if not. + * Valid values are 0-255. + */ + int32_t defaultRoamingIndicator; + } cdmaInfo; + + struct EutranRegistrationInfo { + /** + * Network capabilities for voice over PS services. This info is valid only on LTE + * network and must be present when device is camped on LTE. vopsInfo must be empty when + * device is camped only on 2G/3G. + */ + LteVopsInfo lteVopsInfo; // LTE network capability + + /** + * The parameters of NR 5G Non-Standalone. This value is only valid on E-UTRAN, + * otherwise must be empty. + */ + NrIndicators nrIndicators; + } eutranInfo; + } accessTechnologySpecificInfo; +}; diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index c2a7d8a800..9256c3eafe 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -558,6 +558,14 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon const RadioResponseInfo& info, const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo>& barringInfos); + + Return getVoiceRegistrationStateResponse_1_5( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_5::RegStateResult& regResponse); + + Return getDataRegistrationStateResponse_1_5( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_5::RegStateResult& regResponse); }; /* Callback class for radio indication */ diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp index 644a26298c..d16833c1ca 100644 --- a/radio/1.5/vts/functional/radio_response.cpp +++ b/radio/1.5/vts/functional/radio_response.cpp @@ -969,3 +969,19 @@ Return RadioResponse_v1_5::getBarringInfoResponse( parent_v1_5.notify(info.serial); return Void(); } + +Return RadioResponse_v1_5::getVoiceRegistrationStateResponse_1_5( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_5::RegStateResult& /*regResponse*/) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + +Return RadioResponse_v1_5::getDataRegistrationStateResponse_1_5( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_5::RegStateResult& /*regResponse*/) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} From 500733c45992cfa9e4ffb23aea2b6df9f802e4ee Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Mon, 20 Jan 2020 17:04:16 -0800 Subject: [PATCH 0467/1022] Add Multi-PLMN and CSG support Non-functional changes: -Clarify that the MCC+MNC in the CellIdentity should be used to report the Primary PLMN only; (this PLMN is globally unique, and can be used to construct a CGI/ECGI whereas other PLMN-IDs cannot). -Add clarification for the reporting of multi-PLMN 5G networks. Functional changes: -Add a list of PLMNs for MOCN Networks. This allows cells that are shared by multiple operators to be properly reported. -Add support for Closed Subscriber Group reporting to allow identification of small-cell deployments. Bug: 135921133 Test: make VtsHalRadioV1_5Target && make aosp_cf_x86_64_phone-userdebug Change-Id: Ibb0682de8ae9c4421e79086773c977a4e76ac4f1 --- current.txt | 6 +- radio/1.5/IRadioIndication.hal | 19 ++ radio/1.5/IRadioResponse.hal | 14 ++ radio/1.5/types.hal | 190 ++++++++++++++++++ .../functional/radio_hidl_hal_utils_v1_5.h | 14 ++ radio/1.5/vts/functional/radio_indication.cpp | 13 ++ radio/1.5/vts/functional/radio_response.cpp | 7 + 7 files changed, 260 insertions(+), 3 deletions(-) diff --git a/current.txt b/current.txt index fb6006fdce..2bacc033bb 100644 --- a/current.txt +++ b/current.txt @@ -666,10 +666,10 @@ def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardwar ## # BEGIN Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present ## -b3f250fe4f5f01ea3a2387eb7ae7e975699f6871e09b797d5ebfe18c2a489e98 android.hardware.radio@1.5::types +b48e25c1b90da7a011ccfd76d9e551c105783ef2b9fea4921d4fc5978b215e98 android.hardware.radio@1.5::types 6268d208631b21d1e85bfad338642ac5ca7ac6c83b411283515a4342b5d673f7 android.hardware.radio@1.5::IRadio -20d52e66fd548f89bcb98cda42749a591ce8f439a2a7148617adac0c967ad937 android.hardware.radio@1.5::IRadioIndication -1344e7cfaa2cf259b05ea4f65a731552f0254df6604938cf8be94e04fd62a6a9 android.hardware.radio@1.5::IRadioResponse +e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication +64e06cd5251bec38c402f71d05a6d52b89819a20c9099a192a694059ce4336fc android.hardware.radio@1.5::IRadioResponse 5971a891d7d8843e9fb9f44583a9a0a265ec42fd5e4e1c95c9803454d21fabf7 android.hardware.radio.config@1.3::types a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication diff --git a/radio/1.5/IRadioIndication.hal b/radio/1.5/IRadioIndication.hal index cafecbc3af..c40b473765 100644 --- a/radio/1.5/IRadioIndication.hal +++ b/radio/1.5/IRadioIndication.hal @@ -76,4 +76,23 @@ interface IRadioIndication extends @1.4::IRadioIndication { */ oneway barringInfoChanged( RadioIndicationType type, CellIdentity cellIdentity, vec barringInfos); + + /** + * Report all of the current cell information known to the radio. + * + * This indication is updated from IRadioIndication@1.4 to report the @1.5 version of + * CellInfo. + * + * @param type Type of radio indication + * @param records Current cell information + */ + oneway cellInfoList_1_5(RadioIndicationType type, vec records); + + /** + * Incremental network scan results. + * + * This indication is updated from IRadioIndication@1.4 to report the @1.5 version of + * CellInfo. + */ + oneway networkScanResult_1_5(RadioIndicationType type, NetworkScanResult result); }; diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal index 3f832091e4..4bdafbdb2d 100644 --- a/radio/1.5/IRadioResponse.hal +++ b/radio/1.5/IRadioResponse.hal @@ -19,6 +19,7 @@ package android.hardware.radio@1.5; import @1.0::RadioResponseInfo; import @1.4::IRadioResponse; import @1.5::BarringInfo; +import @1.5::CellInfo; import @1.5::SetupDataCallResult; import @1.5::RegStateResult; @@ -198,4 +199,17 @@ interface IRadioResponse extends @1.4::IRadioResponse { */ oneway getDataRegistrationStateResponse_1_5(RadioResponseInfo info, RegStateResult dataRegResponse); + + /** + * This is identitcal to getCellInfoListResponse_1_4 but uses an updated version of CellInfo. + * + * @param info Response info struct containing response type, serial no. and error + * @param cellInfo List of current cell information known to radio + * + * Valid errors returned: + * RadioError:NONE + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:INTERNAL_ERR + */ + oneway getCellInfoListResponse_1_5(RadioResponseInfo info, vec cellInfo); }; diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index 55f2137b2e..9c039794e2 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -19,21 +19,32 @@ package android.hardware.radio@1.5; import @1.0::ApnAuthType; import @1.0::DataProfileId; import @1.0::DataProfileInfoType; +import @1.0::CdmaSignalStrength; +import @1.0::EvdoSignalStrength; +import @1.0::GsmSignalStrength; +import @1.0::LteSignalStrength; import @1.0::RadioAccessFamily; +import @1.0::RadioError; import @1.0::RegState; +import @1.0::TimeStampType; import @1.1::EutranBands; import @1.1::GeranBands; import @1.1::RadioAccessNetworks; import @1.1::RadioAccessSpecifier; +import @1.1::ScanStatus; import @1.1::ScanType; import @1.1::UtranBands; +import @1.2::CellConnectionStatus; import @1.2::CellIdentityCdma; import @1.2::CellIdentityGsm; import @1.2::CellIdentityWcdma; import @1.2::CellIdentityTdscdma; import @1.2::CellIdentityLte; +import @1.2::CellInfoCdma; import @1.2::IndicationFilter; import @1.2::NetworkScanRequest; +import @1.2::TdscdmaSignalStrength; +import @1.2::WcdmaSignalStrength; import @1.4::AccessNetwork; import @1.4::ApnTypes; import @1.4::CellIdentityNr; @@ -42,6 +53,7 @@ import @1.4::DataConnActiveStatus; import @1.4::DataProfileInfo; import @1.4::LteVopsInfo; import @1.4::NrIndicators; +import @1.4::NrSignalStrength; import @1.4::PdpProtocolType; import @1.4::RadioTechnology; @@ -500,6 +512,166 @@ enum Domain : int32_t { PS = 1 << 1, }; +struct ClosedSubscriberGroupInfo { + /** + * Indicates whether the cell is restricted to only CSG members. A cell not broadcasting the + * CSG Indication but reporting CSG information is considered a Hybrid Cell. + * Refer to the "csg-Indication" field in 3GPP TS 36.331 section 6.2.2 + * SystemInformationBlockType1. + * Also refer to "CSG Indicator" in 3GPP TS 25.331 section 10.2.48.8.1 and TS 25.304. + */ + bool csgIndication; + + /** + * The human-readable name of the closed subscriber group operating this cell. + * Refer to "hnb-Name" in TS 36.331 section 6.2.2 SystemInformationBlockType9. + * Also refer to "HNB Name" in 3GPP TS25.331 section 10.2.48.8.23 and TS 23.003 section 4.8. + */ + string homeNodebName; + + /** + * The identity of the closed subscriber group that the cell belongs to. + * Refer to "CSG-Identity" in TS 36.336 section 6.3.4. + * Also refer to "CSG Identity" in 3GPP TS 25.331 section 10.3.2.8 and TS 23.003 section 4.7. + */ + int32_t csgIdentity; +}; + +safe_union OptionalCsgInfo { + /** + * If no CSG info is provided by the cell, then this structure shall be present. + */ + Monostate noinit; + + /** + * If CSG info is provided by the cell, this structure shall be present. + */ + ClosedSubscriberGroupInfo csgInfo; +}; + +struct CellIdentityGsm { + /** + * The fields "mcc" and "mnc" must contain the PLMN-ID of the primary PLMN of this cell. + */ + @1.2::CellIdentityGsm base; + + /** Additional PLMN-IDs beyond the primary PLMN broadcast for this cell */ + vec additionalPlmns; +}; + +struct CellIdentityWcdma { + /** + * The fields "mcc" and "mnc" must contain the PLMN-ID of the primary PLMN of this cell. + */ + @1.2::CellIdentityWcdma base; + + /** Additional PLMN-IDs beyond the primary PLMN broadcast for this cell */ + vec additionalPlmns; + + /** Information about any closed subscriber group ID for this cell */ + OptionalCsgInfo optionalCsgInfo; +}; + +struct CellIdentityTdscdma { + /** + * The fields "mcc" and "mnc" must contain the PLMN-ID of the primary PLMN of this cell. + */ + @1.2::CellIdentityTdscdma base; + + /** Additional PLMN-IDs beyond the primary PLMN broadcast for this cell */ + vec additionalPlmns; + + /** Information about any closed subscriber group ID for this cell */ + OptionalCsgInfo optionalCsgInfo; +}; + +struct CellIdentityLte { + /** + * The fields "mcc" and "mnc" must contain the PLMN-ID of the primary PLMN of this cell. + */ + @1.2::CellIdentityLte base; + + /** Additional PLMN-IDs beyond the primary PLMN broadcast for this cell */ + vec additionalPlmns; + + /** Information about any closed subscriber group ID for this cell */ + OptionalCsgInfo optionalCsgInfo; +}; + +/** + * The CellIdentity structure should be reported once for each element of the PLMN-IdentityInfoList + * broadcast in SIB1 CellAccessRelatedInfo as per 3GPP TS 38.331 Section 6.3.2. + */ +struct CellIdentityNr { + /** + * The fields "mcc" and "mnc" must contain the PLMN-ID of the primary PLMN of this cell. + */ + @1.4::CellIdentityNr base; + + /** Additional PLMN-IDs beyond the primary PLMN broadcast for this cell */ + vec additionalPlmns; +}; + +struct CellInfoGsm { + CellIdentityGsm cellIdentityGsm; + GsmSignalStrength signalStrengthGsm; +}; + +struct CellInfoWcdma { + CellIdentityWcdma cellIdentityWcdma; + WcdmaSignalStrength signalStrengthWcdma; +}; + +struct CellInfoTdscdma { + CellIdentityTdscdma cellIdentityTdscdma; + TdscdmaSignalStrength signalStrengthTdscdma; +}; + +struct CellInfoLte { + CellIdentityLte cellIdentityLte; + LteSignalStrength signalStrengthLte; +}; + +struct CellInfoNr { + CellIdentityNr cellIdentityNr; + NrSignalStrength signalStrengthNr; +}; + +struct CellInfo { + /** + * True if this cell is registered false if not registered. + */ + bool registered; + /** + * Type of time stamp represented by timeStamp. + */ + TimeStampType timeStampType; + /** + * Time in nanos as returned by ril_nano_time. + */ + uint64_t timeStamp; + /** + * Connection status for the cell. + */ + CellConnectionStatus connectionStatus; + + safe_union CellInfoRatSpecificInfo { + /** + * 3gpp CellInfo types. + */ + CellInfoGsm gsm; + CellInfoWcdma wcdma; + CellInfoTdscdma tdscdma; + CellInfoLte lte; + CellInfoNr nr; + + /** + * 3gpp2 CellInfo types; + */ + CellInfoCdma cdma; + } ratSpecificInfo; +}; + /** A union representing the CellIdentity of a single cell */ safe_union CellIdentity { Monostate noinit; @@ -825,3 +997,21 @@ struct RegStateResult { } eutranInfo; } accessTechnologySpecificInfo; }; + +/** Overwritten from @1.4::NetworkScanResult in order to update the CellInfo to 1.5 version. */ +struct NetworkScanResult { + /** + * The status of the scan. + */ + ScanStatus status; + + /** + * The error code of the incremental result. + */ + RadioError error; + + /** + * List of network information as CellInfo. + */ + vec networkInfos; +}; diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index 9256c3eafe..1e806fa231 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -566,6 +566,11 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon Return getDataRegistrationStateResponse_1_5( const RadioResponseInfo& info, const ::android::hardware::radio::V1_5::RegStateResult& regResponse); + + Return getCellInfoListResponse_1_5( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::CellInfo>& + cellInfo); }; /* Callback class for radio indication */ @@ -580,6 +585,15 @@ class RadioIndication_v1_5 : public ::android::hardware::radio::V1_5::IRadioIndi /* 1.5 Api */ Return uiccApplicationsEnablementChanged(RadioIndicationType type, bool enabled); + Return networkScanResult_1_5( + RadioIndicationType type, + const ::android::hardware::radio::V1_5::NetworkScanResult& result); + + Return cellInfoList_1_5( + RadioIndicationType type, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::CellInfo>& + records); + /* 1.4 Api */ Return currentEmergencyNumberList( RadioIndicationType type, diff --git a/radio/1.5/vts/functional/radio_indication.cpp b/radio/1.5/vts/functional/radio_indication.cpp index 1483907396..d448a226db 100644 --- a/radio/1.5/vts/functional/radio_indication.cpp +++ b/radio/1.5/vts/functional/radio_indication.cpp @@ -350,3 +350,16 @@ Return RadioIndication_v1_5::barringInfoChanged( /*barringInfos*/) { return Void(); } + +Return RadioIndication_v1_5::networkScanResult_1_5( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_5::NetworkScanResult& /*result*/) { + return Void(); +} + +Return RadioIndication_v1_5::cellInfoList_1_5( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_5::CellInfo>& /*records*/) { + return Void(); +} diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp index d16833c1ca..01556f505c 100644 --- a/radio/1.5/vts/functional/radio_response.cpp +++ b/radio/1.5/vts/functional/radio_response.cpp @@ -985,3 +985,10 @@ Return RadioResponse_v1_5::getDataRegistrationStateResponse_1_5( parent_v1_5.notify(info.serial); return Void(); } + +Return RadioResponse_v1_5::getCellInfoListResponse_1_5( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_5::CellInfo>& /*cellInfo*/) { + return Void(); +} From 0b4c7fb40487f55ba7b71367278908d416ec94c5 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 21 Jan 2020 10:46:00 -0800 Subject: [PATCH 0468/1022] Added NR band support Added band info in cell identity. Test: Telephony sanity tests Bug: 131061889 Change-Id: I5205aa70db0d83fd049c5f25b0b427ab7484727b --- current.txt | 2 +- radio/1.5/types.hal | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/current.txt b/current.txt index 2bacc033bb..f2b632a2ef 100644 --- a/current.txt +++ b/current.txt @@ -666,7 +666,7 @@ def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardwar ## # BEGIN Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present ## -b48e25c1b90da7a011ccfd76d9e551c105783ef2b9fea4921d4fc5978b215e98 android.hardware.radio@1.5::types +558660693d7df3b740562bcca71e9f6db314a2e87408f5533076fac9bc0e4867 android.hardware.radio@1.5::types 6268d208631b21d1e85bfad338642ac5ca7ac6c83b411283515a4342b5d673f7 android.hardware.radio@1.5::IRadio e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication 64e06cd5251bec38c402f71d05a6d52b89819a20c9099a192a694059ce4336fc android.hardware.radio@1.5::IRadioResponse diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index 9c039794e2..ad4df6d494 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -610,6 +610,9 @@ struct CellIdentityNr { /** Additional PLMN-IDs beyond the primary PLMN broadcast for this cell */ vec additionalPlmns; + + /** Band used by the cell */ + NgranBands band; }; struct CellInfoGsm { From 3efba537fe39c7629e76f2a8780dc9d11a5956f6 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 18 Dec 2019 17:37:27 -0800 Subject: [PATCH 0469/1022] Manual network selection by RAN type Support updated API for setNetworkSelectionModeManual Bug: 68116277 Test: atest FrameworksTelephonyTests Change-Id: I7076da1734d2d020adef568188cb4f4b4914f379 --- current.txt | 6 ++-- radio/1.5/IRadio.hal | 19 +++++++++++ radio/1.5/IRadioResponse.hal | 24 +++++++++++++ radio/1.5/types.hal | 4 +++ .../1.5/vts/functional/radio_hidl_hal_api.cpp | 34 ++++++++++++++++++- .../functional/radio_hidl_hal_utils_v1_5.h | 2 ++ radio/1.5/vts/functional/radio_response.cpp | 7 ++++ 7 files changed, 92 insertions(+), 4 deletions(-) diff --git a/current.txt b/current.txt index f2b632a2ef..02a4733b31 100644 --- a/current.txt +++ b/current.txt @@ -666,10 +666,10 @@ def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardwar ## # BEGIN Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present ## -558660693d7df3b740562bcca71e9f6db314a2e87408f5533076fac9bc0e4867 android.hardware.radio@1.5::types -6268d208631b21d1e85bfad338642ac5ca7ac6c83b411283515a4342b5d673f7 android.hardware.radio@1.5::IRadio +616456d7ce4435d88995f9fe0025a76bca14bd70799e4ca3ff4bae74d54d1166 android.hardware.radio@1.5::types +c68f5bd87f747f8e7968ff66ecc548b2d26f8e186b7bb805c11d6c883a838fc6 android.hardware.radio@1.5::IRadio e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication -64e06cd5251bec38c402f71d05a6d52b89819a20c9099a192a694059ce4336fc android.hardware.radio@1.5::IRadioResponse +9e962eff568dc8c712d83846f8c27460de5005ed9b836d3e08390e8aa56b5a46 android.hardware.radio@1.5::IRadioResponse 5971a891d7d8843e9fb9f44583a9a0a265ec42fd5e4e1c95c9803454d21fabf7 android.hardware.radio.config@1.3::types a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal index 52e579aee9..ee4438d08d 100644 --- a/radio/1.5/IRadio.hal +++ b/radio/1.5/IRadio.hal @@ -25,6 +25,7 @@ import @1.5::DataProfileInfo; import @1.5::IndicationFilter; import @1.5::LinkAddress; import @1.5::NetworkScanRequest; +import @1.5::RadioAccessNetworks; import @1.5::RadioAccessSpecifier; import @1.5::SignalThresholdInfo; @@ -263,4 +264,22 @@ interface IRadio extends @1.4::IRadio { * Response function is IRadioResponse.getDataRegistrationStateResponse_1_5() */ oneway getDataRegistrationState_1_5(int32_t serial); + + /* + * Manually select a specified network. + * This request must not respond until the new operator is selected and registered. + * Per TS 23.122, the RAN is just the initial suggested value. + * If registration fails, the RAN is not available afterwards, or the RAN is not within + * the network types specified by IRadio::setPreferredNetworkTypeBitmap, then the modem + * will need to select the next best RAN for network registration. + * + * @param serial Serial number of request. + * @param operatorNumeric String specifying MCCMNC of network to select (eg "310170"). + * @param ran Initial suggested radio access network type. If value is UNKNOWN, the modem + * will select the next best RAN for network registration. + * + * Response function is IRadioResponse.setNetworkSelectionModeManualResponse_1_5() + */ + oneway setNetworkSelectionModeManual_1_5(int32_t serial, string operatorNumeric, + RadioAccessNetworks ran); }; diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal index 4bdafbdb2d..e66e00b1ea 100644 --- a/radio/1.5/IRadioResponse.hal +++ b/radio/1.5/IRadioResponse.hal @@ -212,4 +212,28 @@ interface IRadioResponse extends @1.4::IRadioResponse { * RadioError:INTERNAL_ERR */ oneway getCellInfoListResponse_1_5(RadioResponseInfo info, vec cellInfo); + + + /** + * @param info Response info struct containing response type, serial no. and error + * + * Valid errors returned: + * RadioError:NONE + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:ILLEGAL_SIM_OR_ME + * RadioError:OPERATION_NOT_ALLOWED + * RadioError:INVALID_STATE + * RadioError:NO_MEMORY + * RadioError:INTERNAL_ERR + * RadioError:SYSTEM_ERR + * RadioError:INVALID_ARGUMENTS + * RadioError:MODEM_ERR + * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:NO_RESOURCES + * RadioError:CANCELLED + * + * Returns RadioError:ILLEGAL_SIM_OR_ME when the failure is permanent and + * no retries needed, such as illegal SIM or ME. + */ + oneway setNetworkSelectionModeManualResponse_1_5(RadioResponseInfo info); }; diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index ad4df6d494..5482acaf27 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -166,7 +166,11 @@ enum AccessNetwork : @1.4::AccessNetwork { }; enum RadioAccessNetworks : @1.1::RadioAccessNetworks { + UNKNOWN = 0, + /** Next Generation Radio Access Network */ NGRAN = 4, + /** CDMA 2000 Network */ + CDMA2000 = 5, }; /** diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp index 01258cfebc..a4095b7a91 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp @@ -879,6 +879,9 @@ TEST_F(RadioHidlTest_v1_5, setupDataCall_1_5) { } } +/* + * Test IRadio.setInitialAttachApn_1_5() for the response returned. + */ TEST_F(RadioHidlTest_v1_5, setInitialAttachApn_1_5) { serial = GetRandomSerialNumber(); @@ -919,6 +922,9 @@ TEST_F(RadioHidlTest_v1_5, setInitialAttachApn_1_5) { } } +/* + * Test IRadio.setDataProfile_1_5() for the response returned. + */ TEST_F(RadioHidlTest_v1_5, setDataProfile_1_5) { serial = GetRandomSerialNumber(); @@ -989,4 +995,30 @@ TEST_F(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancalled) { EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); -} \ No newline at end of file +} + +/* + * Test IRadio.setNetworkSelectionModeManual_1_5() for the response returned. + */ +TEST_F(RadioHidlTest_v1_5, setNetworkSelectionModeManual_1_5) { + serial = GetRandomSerialNumber(); + + // can't camp on nonexistent MCCMNC, so we expect this to fail. + Return res = radio_v1_5->setNetworkSelectionModeManual_1_5( + serial, "123456", android::hardware::radio::V1_5::RadioAccessNetworks::GERAN); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + if (cardStatus.base.base.cardState == CardState::ABSENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME, + RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE}, + CHECK_GENERAL_ERROR)); + } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, + RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE}, + CHECK_GENERAL_ERROR)); + } +} diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index 1e806fa231..abab452915 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -571,6 +571,8 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon const RadioResponseInfo& info, const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::CellInfo>& cellInfo); + + Return setNetworkSelectionModeManualResponse_1_5(const RadioResponseInfo& info); }; /* Callback class for radio indication */ diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp index 01556f505c..d7197d5eb1 100644 --- a/radio/1.5/vts/functional/radio_response.cpp +++ b/radio/1.5/vts/functional/radio_response.cpp @@ -992,3 +992,10 @@ Return RadioResponse_v1_5::getCellInfoListResponse_1_5( ::android::hardware::radio::V1_5::CellInfo>& /*cellInfo*/) { return Void(); } + +Return RadioResponse_v1_5::setNetworkSelectionModeManualResponse_1_5( + const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} From ee9d2bcf5b0139d74afedcd4b0c9e1c6345f6014 Mon Sep 17 00:00:00 2001 From: "Harpreet \\\"Eli\\\" Sangha" Date: Fri, 17 Jan 2020 14:46:37 +0900 Subject: [PATCH 0470/1022] vibrator: Add "Light Tick" Primitive Bug: 147844633 Test: adb shell idlcli vibrator compose 0 7 1.0 Change-Id: I208e56011f790c095afe734fd4326de10078525a Signed-off-by: Harpreet \"Eli\" Sangha --- .../aidl/android/hardware/vibrator/CompositePrimitive.aidl | 5 +++++ vibrator/aidl/default/Vibrator.cpp | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl index b9a80ec116..0fdfa5d5c2 100644 --- a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl +++ b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl @@ -49,4 +49,9 @@ enum CompositePrimitive { * A haptic effect that simulates quick downwards movement with gravity. */ QUICK_FALL, + /** + * This very short effect should produce a light crisp sensation intended + * to be used repetitively for dynamic feedback. + */ + LIGHT_TICK, } diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp index d6ce8a1c43..0d7131aaf8 100644 --- a/vibrator/aidl/default/Vibrator.cpp +++ b/vibrator/aidl/default/Vibrator.cpp @@ -118,7 +118,7 @@ ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector& composi return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } if (e.primitive < CompositePrimitive::NOOP || - e.primitive > CompositePrimitive::QUICK_FALL) { + e.primitive > CompositePrimitive::LIGHT_TICK) { return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } } From 2d7c489f6779698069bf0623fe11d29784ea96d4 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Mon, 20 Jan 2020 13:39:15 +0000 Subject: [PATCH 0471/1022] NNAPI: Regenerate types.hal to sync with types.spec Bug: 147765446 Test: mma Change-Id: I2b41bd959b7084ecb89674c659c66ebb158ac77d --- current.txt | 2 +- neuralnetworks/1.3/types.hal | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/current.txt b/current.txt index 29cc006949..8c2742baf5 100644 --- a/current.txt +++ b/current.txt @@ -655,7 +655,7 @@ d1f382d14e1384b907d5bb5780df7f01934650d556fedbed2f15a90773c657d6 android.hardwar 4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback 7d23020248194abbee8091cc624f39a5a6d7ccba338b172d5d2d3df0cceffbee android.hardware.neuralnetworks@1.3::IPreparedModel 0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback -ee65638f8af3f9f4f222e7208eaa9f1f8e7f8e0a21545846ba67d0e27624efa1 android.hardware.neuralnetworks@1.3::types +162515505235bc770601f02c3537f9ccf11582583bf7b11dd2ec81fab6855333 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index b330b50084..0f51b1a048 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -1415,6 +1415,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) + * * {@link OperandType::TENSOR_INT32} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -1425,6 +1426,8 @@ enum OperationType : int32_t { * * 2: An {@link OperandType::INT32} scalar, and has to be one of the * {@link FusedActivationFunc} values. Specifies the activation to * invoke on the result. + * For a {@link OperandType::TENSOR_INT32} tensor, + * the {@link FusedActivationFunc} must be "NONE". * * Outputs: * * 0: The product, a tensor of the same {@link OperandType} as input0. @@ -1905,6 +1908,11 @@ enum OperationType : int32_t { * dimensions. The output is the result of dividing the first input tensor * by the second, optionally modified by an activation function. * + * For inputs of {@link OperandType::TENSOR_INT32}, performs + * "floor division" ("//" in Python). For example, + * 5 // 2 = 2 + * -5 // 2 = -3 + * * Two dimensions are compatible when: * 1. they are equal, or * 2. one of them is 1 @@ -1925,6 +1933,7 @@ enum OperationType : int32_t { * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -1935,6 +1944,8 @@ enum OperationType : int32_t { * * 2: An {@link OperandType::INT32} scalar, and has to be one of the * {@link FusedActivationFunc} values. Specifies the activation to * invoke on the result. + * For a {@link OperandType::TENSOR_INT32} tensor, + * the {@link FusedActivationFunc} must be "NONE". * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. @@ -2186,6 +2197,7 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2) * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3) + * * {@link OperandType::TENSOR_INT32} (since HAL version 1.3) * * Supported tensor rank: up to 4 * @@ -2196,6 +2208,8 @@ enum OperationType : int32_t { * * 2: An {@link OperandType::INT32} scalar, and has to be one of the * {@link FusedActivationFunc} values. Specifies the activation to * invoke on the result. + * For a {@link OperandType::TENSOR_INT32} tensor, + * the {@link FusedActivationFunc} must be "NONE". * * Outputs: * * 0: A tensor of the same {@link OperandType} as input0. @@ -2242,6 +2256,7 @@ enum OperationType : int32_t { * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} (since HAL version 1.3) * * Supported tensor rank: from 1. * From aee67f83f9e97e060ff31e16e6898a15f4680d04 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Mon, 6 Jan 2020 12:16:31 +0000 Subject: [PATCH 0472/1022] Add ELU and HARD_SWISH Bug: 147482068 Bug: 147481241 Test: NNTest_static and VtsHalNeuralnetworksV1_3TargetTest Change-Id: Iab8da2a666ad9775dfb53d9297e94962fb651353 --- current.txt | 2 +- neuralnetworks/1.3/types.hal | 52 +++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/current.txt b/current.txt index 8c2742baf5..e571692776 100644 --- a/current.txt +++ b/current.txt @@ -655,7 +655,7 @@ d1f382d14e1384b907d5bb5780df7f01934650d556fedbed2f15a90773c657d6 android.hardwar 4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback 7d23020248194abbee8091cc624f39a5a6d7ccba338b172d5d2d3df0cceffbee android.hardware.neuralnetworks@1.3::IPreparedModel 0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback -162515505235bc770601f02c3537f9ccf11582583bf7b11dd2ec81fab6855333 android.hardware.neuralnetworks@1.3::types +26c643aedf4e28b8d82e517d9cd70601b37f881e1ea94f09808d9e233517e400 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index 0f51b1a048..6a852d14a6 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -4986,6 +4986,56 @@ enum OperationType : int32_t { */ WHILE = 97, + /** + * Computes exponential linear activation on the input tensor element-wise. + * + * The output is calculated using the following formula: + * + * ELU(x) = max(0, x) + min(0, alpha * (exp(x) - 1)) + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * + * Inputs: + * * 0: A tensor, specifying the input. May be zero-sized. + * * 1: A scalar, specifying the alpha parameter. + * For input tensor of {@link OperandType::TENSOR_FLOAT16}, + * the alpha value must be of {@link OperandType::FLOAT16}. + * For input tensor of {@link OperandType::TENSOR_FLOAT32}, + * the alpha value must be of {@link OperandType::FLOAT32}. + * + * Outputs: + * * 0: The output tensor of same shape and type as input0. + */ + ELU = 98, + + /** + * Computes hard-swish activation on the input tensor element-wise. + * + * Hard swish activation is introduced in + * https://arxiv.org/pdf/1905.02244.pdf + * + * The output is calculated using the following formula: + * + * h-swish(x) = x * max(0, min(6, (x + 3))) / 6 + + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} + * + * Inputs: + * * 0: A tensor, specifying the input. May be zero-sized. + * + * Outputs: + * * 0: The output tensor of same shape and type as input0. + * Scale and zero point of this tensor may be different from the input + * tensor's parameters. + */ + HARD_SWISH = 99, + /** * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to * OEM operation and data types. @@ -5008,7 +5058,7 @@ enum OperationType : int32_t { enum OperationTypeRange : uint32_t { BASE_MIN = 0, FUNDAMENTAL_MIN = 0, - FUNDAMENTAL_MAX = 97, + FUNDAMENTAL_MAX = 99, OEM_MIN = 10000, OEM_MAX = 10000, BASE_MAX = 0xFFFF, From 8b3f240ea3864debfc2c6f561029faf23d179f59 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Mon, 20 Jan 2020 18:54:46 +0000 Subject: [PATCH 0473/1022] Add FILL and RANK ops Bug: 148050168 Bug: 148049333 Test: NNTest_static and VtsHalNeuralnetworksV1_3TargetTest Change-Id: Iebdfa600d84e31532807740c21d95cae41c76ad5 --- current.txt | 2 +- neuralnetworks/1.3/types.hal | 52 ++++++++++++++++++- .../vts/functional/GeneratedTestHarness.cpp | 5 +- .../1.3/vts/functional/ValidateModel.cpp | 15 ++++++ 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/current.txt b/current.txt index e571692776..2bc5eb4fa8 100644 --- a/current.txt +++ b/current.txt @@ -655,7 +655,7 @@ d1f382d14e1384b907d5bb5780df7f01934650d556fedbed2f15a90773c657d6 android.hardwar 4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback 7d23020248194abbee8091cc624f39a5a6d7ccba338b172d5d2d3df0cceffbee android.hardware.neuralnetworks@1.3::IPreparedModel 0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback -26c643aedf4e28b8d82e517d9cd70601b37f881e1ea94f09808d9e233517e400 android.hardware.neuralnetworks@1.3::types +5f1a4e0c29fc686ed476f9f04eed35e4405d21288cb2746b978d6891de5cc37d android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index 6a852d14a6..abc33e77d3 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -5036,6 +5036,56 @@ enum OperationType : int32_t { */ HARD_SWISH = 99, + /** + * Creates a tensor filled with a scalar value. + * + * Supported output tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * + * Inputs: + * * 0: A 1-D tensor, specifying the desired output tensor shape. + * * 1: A scalar, specifying the value to fill the output tensors with. + * For output tensor of {@link OperandType::TENSOR_FLOAT16}, + * the scalar must be of {@link OperandType::FLOAT16}. + * For output tensor of {@link OperandType::TENSOR_FLOAT32}, + * the scalar must be of {@link OperandType::FLOAT32}. + * For output tensor of {@link OperandType::TENSOR_INT32}, + * the scalar must be of {@link OperandType::INT32}. + * + * Outputs: + * * 0: The output tensor. + */ + FILL = 100, + + /** + * Returns the rank of a tensor. + * + * The rank of a tensor is the number of dimensions in it. Also known as + * "order", "degree", "ndims". + * + * Supported tensor {@link OperandType}: + * * {@link OperandType::TENSOR_FLOAT16} + * * {@link OperandType::TENSOR_FLOAT32} + * * {@link OperandType::TENSOR_INT32} + * * {@link OperandType::TENSOR_QUANT8_ASYMM} + * * {@link OperandType::TENSOR_QUANT16_SYMM} + * * {@link OperandType::TENSOR_BOOL8} + * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} + * * {@link OperandType::TENSOR_QUANT16_ASYMM} + * * {@link OperandType::TENSOR_QUANT8_SYMM} + * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} + * + * Inputs: + * * 0: The input tensor. + * + * Outputs: + * * 0: A scalar of {@link OperandType::INT32}, specifying the rank + * of the input tensor. + */ + RANK = 101, + /** * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to * OEM operation and data types. @@ -5058,7 +5108,7 @@ enum OperationType : int32_t { enum OperationTypeRange : uint32_t { BASE_MIN = 0, FUNDAMENTAL_MIN = 0, - FUNDAMENTAL_MAX = 99, + FUNDAMENTAL_MAX = 101, OEM_MIN = 10000, OEM_MAX = 10000, BASE_MAX = 0xFFFF, diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index a2c0c4efa0..cba1f7766c 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -793,8 +793,9 @@ TEST_P(QuantizationCouplingTest, Test) { INSTANTIATE_GENERATED_TEST(GeneratedTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); -INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, - [](const TestModel& testModel) { return !testModel.expectFailure; }); +INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, [](const TestModel& testModel) { + return !testModel.expectFailure && !testModel.hasScalarOutputs(); +}); INSTANTIATE_GENERATED_TEST(MemoryDomainTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index a21142880e..1245432307 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -337,6 +337,7 @@ static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, con // - TRANSPOSE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL // - AXIS_ALIGNED_BBOX_TRANSFORM bounding boxes (arg 1) can be of // TENSOR_QUANT8_ASYMM or TENSOR_QUANT8_ASYMM_SIGNED. + // - RANK's input can have any TENSOR_* type. switch (operation.type) { case OperationType::LSH_PROJECTION: { if (operand == operation.inputs[1]) { @@ -399,6 +400,20 @@ static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, con return true; } } break; + case OperationType::RANK: { + if (operand == operation.inputs[0] && + (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32 || + type == OperandType::TENSOR_INT32 || + type == OperandType::TENSOR_QUANT8_ASYMM || + type == OperandType::TENSOR_QUANT16_SYMM || + type == OperandType::TENSOR_BOOL8 || + type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL || + type == OperandType::TENSOR_QUANT16_ASYMM || + type == OperandType::TENSOR_QUANT8_SYMM || + type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED)) { + return true; + } + } break; default: break; } From 90cf3dd37ce08973c7a709a951bc444470a0d20a Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Tue, 12 Nov 2019 14:02:16 -0800 Subject: [PATCH 0474/1022] Support sync fence in NNAPI - Add IPreparedModel::dispatchRequest to NNAPI 1.3 HAL - Add IDispatchExecutionCallback to allow clients query information related to the actual evaluation. Bug: 142778241 Test: mm Change-Id: I87cbb7f2aee87342b0418fce04eb4050e2bc1920 --- current.txt | 3 +- neuralnetworks/1.3/Android.bp | 1 + .../1.3/IFencedExecutionCallback.hal | 48 ++++++++++++++++ neuralnetworks/1.3/IPreparedModel.hal | 57 ++++++++++++++++++- 4 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 neuralnetworks/1.3/IFencedExecutionCallback.hal diff --git a/current.txt b/current.txt index 29cc006949..5e0c52c7a4 100644 --- a/current.txt +++ b/current.txt @@ -653,7 +653,8 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer d1f382d14e1384b907d5bb5780df7f01934650d556fedbed2f15a90773c657d6 android.hardware.neuralnetworks@1.3::IDevice 4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback -7d23020248194abbee8091cc624f39a5a6d7ccba338b172d5d2d3df0cceffbee android.hardware.neuralnetworks@1.3::IPreparedModel +29e26e83399b69c7998b787bd30426dd5baa2da350effca76bbee1ba877355c9 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback +384fd9fd6e4d43ea11d407e52ea81da5242c3c5f4b458b8707d8feb652a13e36 android.hardware.neuralnetworks@1.3::IPreparedModel 0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback ee65638f8af3f9f4f222e7208eaa9f1f8e7f8e0a21545846ba67d0e27624efa1 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi diff --git a/neuralnetworks/1.3/Android.bp b/neuralnetworks/1.3/Android.bp index 56011e227d..7b02cc510f 100644 --- a/neuralnetworks/1.3/Android.bp +++ b/neuralnetworks/1.3/Android.bp @@ -11,6 +11,7 @@ hidl_interface { "IBuffer.hal", "IDevice.hal", "IExecutionCallback.hal", + "IFencedExecutionCallback.hal", "IPreparedModel.hal", "IPreparedModelCallback.hal", ], diff --git a/neuralnetworks/1.3/IFencedExecutionCallback.hal b/neuralnetworks/1.3/IFencedExecutionCallback.hal new file mode 100644 index 0000000000..39076b9a16 --- /dev/null +++ b/neuralnetworks/1.3/IFencedExecutionCallback.hal @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package android.hardware.neuralnetworks@1.3; + +import @1.2::Timing; +import ErrorStatus; + +/** + * IFencedExecutionCallback can be used to query the error status result + * and duration information from an IPreparedModel::executeFenced call. + */ +interface IFencedExecutionCallback { + + /** + * The getExecutionInfo method is used by the clients to query error status + * result and duration information. The method must only be called after the actual + * evaluation has finished or resulted in an runtime error, as indicated by the status + * of the sync fence returned by the IPreparedModel::executeFenced call, otherwise + * GENERAL_FAILURE must be returned. + * + * @return status Error status returned from the asynchronously dispatched execution + * must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the asynchronous task resulted in an + * unspecified error + * @return timing Duration of execution. Unless MeasureTiming::YES was passed when + * launching the execution and status is NONE, all times must + * be reported as UINT64_MAX. A driver may choose to report + * any time as UINT64_MAX, indicating that particular measurement is + * not available. + */ + getExecutionInfo() generates (ErrorStatus status, Timing timing); +}; diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal index bce6ee227a..f84bcf4ffc 100644 --- a/neuralnetworks/1.3/IPreparedModel.hal +++ b/neuralnetworks/1.3/IPreparedModel.hal @@ -24,6 +24,7 @@ import ErrorStatus; import OptionalTimePoint; import Request; import IExecutionCallback; +import IFencedExecutionCallback; /** * IPreparedModel describes a model that has been prepared for execution and @@ -91,7 +92,8 @@ interface IPreparedModel extends @1.2::IPreparedModel { * execution cannot be finished by the deadline, the * execution must be aborted. * @param callback A callback object used to return the error status of - * the execution. The callback object's notify function must + * the execution, shape information of model output operands, and + * duration of execution. The callback object's notify function must * be called exactly once, even if the execution was * unsuccessful. * @return status Error status of the call, must be: @@ -187,4 +189,57 @@ interface IPreparedModel extends @1.2::IPreparedModel { OptionalTimePoint deadline) generates (ErrorStatus status, vec outputShapes, Timing timing); + + /** + * Launch a fenced asynchronous execution on a prepared model. + * + * The execution is performed asynchronously with respect to the caller. + * executeFenced must fully validate the request, and only accept one that is + * guaranteed to be completed, unless a hardware failure or kernel panic happens on the device. + * If there is an error during validation, executeFenced must immediately return with + * the corresponding ErrorStatus. If the request is valid and there is no error launching, + * executeFenced must dispatch an asynchronous task to perform the execution in the + * background, and immediately return with ErrorStatus::NONE, a sync_fence that will be + * signaled once the execution is completed, and a callback that can be used by the client + * to query the duration and runtime error status. If the task has finished + * before the call returns, empty handle may be returned for the sync fence. If the + * asynchronous task fails to launch, executeFenced must immediately return with + * ErrorStatus::GENERAL_FAILURE, and empty handle for the sync fence and nullptr + * for callback. The execution must wait for all the sync fences (if any) in wait_for to be + * signaled before starting the actual execution. + * + * If any of sync fences in wait_for changes to error status after the executeFenced + * call succeeds, the driver must immediately set the returned sync fence to error status. + * + * When the asynchronous task has finished its execution, it must + * immediately signal the sync_fence created when dispatching. After + * the sync_fence is signaled, the task must not modify the content of + * any data object referenced by 'request' (described by the + * {@link @1.0::DataLocation} of a {@link @1.0::RequestArgument}). + * + * Any number of calls to the executeFenced, execute* and executeSynchronously* + * functions, in any combination, may be made concurrently, even on the same + * IPreparedModel object. + * + * @param request The input and output information on which the prepared + * model is to be executed. + * @param waitFor A vector of sync fence file descriptors. + * Execution must not start until all sync fences have been signaled. + * @param measure Specifies whether or not to measure duration of the execution. + * The duration runs from the time the driver sees the call + * to the executeFenced function to the time sync_fence is triggered. + * @return status Error status of the call, must be: + * - NONE if task is successfully launched + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if one of the input arguments is invalid, including + * fences in error states. + * @return syncFence The sync fence that will be triggered when the task is completed. + * The sync fence will be set to error if a critical error, + * e.g. hardware failure or kernel panic, occurs when doing execution. + * @return callback The IFencedExecutionCallback can be used to query information like duration + * and error status when the execution is completed. + */ + executeFenced(Request request, vec waitFor, MeasureTiming measure) + generates (ErrorStatus status, handle syncFence, IFencedExecutionCallback callback); }; From 9bc9059842ee99ace64bf55f96a6a0a456d5e0dd Mon Sep 17 00:00:00 2001 From: Barani Muthukumaran Date: Thu, 16 Jan 2020 18:08:25 -0800 Subject: [PATCH 0475/1022] Add STORAGE_KEY tag to keymaster 4.1 These are keymaster keys used specifically for storage encryption. This provides the ability for keymaster implementations to securely protect storage encryption keys. Test: VtsHalKeymasterV4_1TargetTest Bug: 147733587 Change-Id: I5f7f83755fcbed96d8f38fa51812aa6d2eb0927b --- current.txt | 2 +- .../include/keymasterV4_1/keymaster_tags.h | 1 + keymaster/4.1/types.hal | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/current.txt b/current.txt index f6ec7fa87b..fd87484856 100644 --- a/current.txt +++ b/current.txt @@ -647,7 +647,7 @@ bbeee9604128ede83ee755b67e73b5ad29e6e1dbac9ec41fea6ffe2745b0c50a android.hardwar 6e1e28a96c90ba78d47257faea3f3bb4e6360affbbfa5822f0dc31211f9266ff android.hardware.identity@1.0::IWritableIdentityCredential 27ae3724053940462114228872b3ffaf0b8e6177d5ba97f5a76339d12b8a99dd android.hardware.keymaster@4.1::IKeymasterDevice adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardware.keymaster@4.1::IOperation -ac429fca0da4ce91218768ec31b64ded88251f8a26d8c4f27c06abdc5b1926d9 android.hardware.keymaster@4.1::types +ddcf89cd8ee2df0d32aee55050826446fb64f7aafde0a7cd946c64f61b1a364c android.hardware.keymaster@4.1::types df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore 65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h index c5ce9505d3..6c186f6429 100644 --- a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h +++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h @@ -100,6 +100,7 @@ using V4_0::TAG_VENDOR_PATCHLEVEL; DECLARE_KM_4_1_TYPED_TAG(EARLY_BOOT_ONLY); DECLARE_KM_4_1_TYPED_TAG(DEVICE_UNIQUE_ATTESTATION); +DECLARE_KM_4_1_TYPED_TAG(STORAGE_KEY); } // namespace android::hardware::keymaster::V4_1 diff --git a/keymaster/4.1/types.hal b/keymaster/4.1/types.hal index 9e8b30e590..f3bdcc6404 100644 --- a/keymaster/4.1/types.hal +++ b/keymaster/4.1/types.hal @@ -50,10 +50,29 @@ enum Tag : @4.0::Tag { * HAL attests to Credential Keys. IIdentityCredential produces Keymaster-style attestations. */ IDENTITY_CREDENTIAL_KEY = TagType:BOOL | 721, + + /** + * To prevent keys from being compromised if an attacker acquires read access to system / kernel + * memory, some inline encryption hardware supports protecting storage encryption keys in hardware + * without software having access to or the ability to set the plaintext keys. Instead, software + * only sees wrapped version of these keys. + * + * STORAGE_KEY is used to denote that a key generated or imported is a key used for storage + * encryption. Keys of this type can either be generated or imported or secure imported using + * keymaster. exportKey() can be used to re-wrap storage key with a per-boot ephemeral key wrapped + * key once the key characteristics are enforced. + * + * Keys with this tag cannot be used for any operation within keymaster. + * ErrorCode::INVALID_OPERATION is returned when a key with Tag::STORAGE_KEY is provided to + * begin(). + */ + STORAGE_KEY = TagType:BOOL | 722, }; enum ErrorCode : @4.0::ErrorCode { EARLY_BOOT_ENDED = -73, ATTESTATION_KEYS_NOT_PROVISIONED = -74, ATTESTATION_IDS_NOT_PROVISIONED = -75, + INVALID_OPERATION = -76, + STORAGE_KEY_UNSUPPORTED = -77, }; From ec0b6e26ea45a07ee00ca0127fdf7e3749ab515c Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Wed, 25 Dec 2019 15:59:49 -0800 Subject: [PATCH 0476/1022] Define biometrics.face@1.1 with remote enrollment Bug: 145027036 Test: hidl-gen -L check android.hardware.biometrics.face@1.1 Change-Id: I3b5cc1e7852509012aab7fea078b12b76bd83abb --- biometrics/face/1.1/Android.bp | 17 +++++ biometrics/face/1.1/IBiometricsFace.hal | 82 +++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 biometrics/face/1.1/Android.bp create mode 100644 biometrics/face/1.1/IBiometricsFace.hal diff --git a/biometrics/face/1.1/Android.bp b/biometrics/face/1.1/Android.bp new file mode 100644 index 0000000000..2206597dec --- /dev/null +++ b/biometrics/face/1.1/Android.bp @@ -0,0 +1,17 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.biometrics.face@1.1", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "IBiometricsFace.hal", + ], + interfaces: [ + "android.hardware.biometrics.face@1.0", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/biometrics/face/1.1/IBiometricsFace.hal b/biometrics/face/1.1/IBiometricsFace.hal new file mode 100644 index 0000000000..975001f30b --- /dev/null +++ b/biometrics/face/1.1/IBiometricsFace.hal @@ -0,0 +1,82 @@ +/* + * 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. + */ + +package android.hardware.biometrics.face@1.1; +import @1.0::IBiometricsFace; +import @1.0::Status; +import @1.0::Feature; + +/** + * The HAL interface for biometric face authentication. + */ +interface IBiometricsFace extends @1.0::IBiometricsFace { + /** + * Enrolls a user's face for a remote client, for example Android Auto. + * + * The HAL implementation is responsible for creating a secure communication + * channel and receiving the enrollment images from a mobile device with + * face authentication hardware. + * + * Note that the Hardware Authentication Token must be valid for the + * duration of enrollment and thus should be explicitly invalidated by a + * call to revokeChallenge() when enrollment is complete, to reduce the + * window of opportunity to re-use the challenge and HAT. For example, + * Settings calls generateChallenge() once to allow the user to enroll one + * or more faces or toggle secure settings without having to re-enter the + * PIN/pattern/password. Once the user completes the operation, Settings + * invokes revokeChallenge() to close the transaction. If the HAT is expired, + * the implementation must invoke onError with UNABLE_TO_PROCESS. + * + * Requirements for using this API: + * - Mobile devices MUST NOT delegate enrollment to another device by calling + * this API. This feature is intended only to allow enrollment on devices + * where it is impossible to enroll locally on the device. + * - The path MUST be protected by a secret key with rollback protection. + * - Synchronizing between devices MUST be accomplished by having both + * devices agree on a secret PIN entered by the user (similar to BT + * pairing procedure) and use a salted version of that PIN plus other secret + * to encrypt traffic. + * - All communication to/from the remote device MUST be encrypted and signed + * to prevent image injection and other man-in-the-middle type attacks. + * - generateChallenge() and revokeChallenge() MUST be implemented on both + * remote and local host (e.g. hash the result of the remote host with a + * local secret before responding to the API call) and any transmission of + * the challenge between hosts MUST be signed to prevent man-in-the-middle + * attacks. + * - In the event of a lost connection, the result of the last + * generateChallenge() MUST be invalidated and the process started over. + * - Both the remote and local host MUST honor the timeout and invalidate the + * challenge. + * + * This method triggers the IBiometricsFaceClientCallback#onEnrollResult() + * method. + * + * @param hat A valid Hardware Authentication Token, generated as a result + * of a generateChallenge() challenge being wrapped by the gatekeeper + * after a successful strong authentication request. + * @param timeoutSec A timeout in seconds, after which this enroll + * attempt is cancelled. Note that the framework can continue + * enrollment by calling this again with a valid HAT. This timeout is + * expected to be used to limit power usage if the device becomes idle + * during enrollment. The implementation is expected to send + * ERROR_TIMEOUT if this happens. + * @param disabledFeatures A list of features to be disabled during + * enrollment. Note that all features are enabled by default. + * @return status The status of this method call. + */ + enrollRemotely(vec hat, uint32_t timeoutSec, + vec disabledFeatures) generates (Status status); +}; From f21a4f0aee6045d06b94036f4c7020f186968fe0 Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Tue, 21 Jan 2020 21:40:04 -0800 Subject: [PATCH 0477/1022] Add VTS tests for biometrics.face@1.1 Bug: 145027036 Test: m vts -j Change-Id: I14c64aa784291c9027bf6888139f90d53908cf92 --- biometrics/face/1.1/vts/functional/Android.bp | 29 ++++ .../VtsHalBiometricsFaceV1_1TargetTest.cpp | 163 ++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 biometrics/face/1.1/vts/functional/Android.bp create mode 100644 biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp diff --git a/biometrics/face/1.1/vts/functional/Android.bp b/biometrics/face/1.1/vts/functional/Android.bp new file mode 100644 index 0000000000..ccbb3994e1 --- /dev/null +++ b/biometrics/face/1.1/vts/functional/Android.bp @@ -0,0 +1,29 @@ +/* + * Copyright 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. + */ + +cc_test { + name: "VtsHalBiometricsFaceV1_1TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalBiometricsFaceV1_1TargetTest.cpp"], + static_libs: [ + "android.hardware.biometrics.face@1.0", + "android.hardware.biometrics.face@1.1", + ], + test_suites: [ + "general-tests", + "vts-core", + ], +} diff --git a/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp new file mode 100644 index 0000000000..c2431c6727 --- /dev/null +++ b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp @@ -0,0 +1,163 @@ +/* + * Copyright 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. + */ + +#define LOG_TAG "biometrics_face_hidl_hal_test" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +using android::sp; +using android::hardware::hidl_vec; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::biometrics::face::V1_0::FaceAcquiredInfo; +using android::hardware::biometrics::face::V1_0::FaceError; +using android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback; +using android::hardware::biometrics::face::V1_0::OptionalUint64; +using android::hardware::biometrics::face::V1_0::Status; +using android::hardware::biometrics::face::V1_1::IBiometricsFace; + +namespace { + +// Arbitrary, nonexistent userId +constexpr uint32_t kUserId = 9; +constexpr uint32_t kTimeoutSec = 3; +constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec); +constexpr char kFacedataDir[] = "/data/vendor_de/0/facedata"; +constexpr char kCallbackNameOnError[] = "onError"; + +// Callback arguments that need to be captured for the tests. +struct FaceCallbackArgs { + // The error passed to the last onError() callback. + FaceError error; + + // The userId passed to the last callback. + int32_t userId; +}; + +// Test callback class for the BiometricsFace HAL. +// The HAL will call these callback methods to notify about completed operations +// or encountered errors. +class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase, + public IBiometricsFaceClientCallback { + public: + Return onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override { return Void(); } + + Return onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec&) override { + return Void(); + } + + Return onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override { + return Void(); + } + + Return onError(uint64_t, int32_t userId, FaceError error, int32_t) override { + FaceCallbackArgs args = {}; + args.error = error; + args.userId = userId; + NotifyFromCallback(kCallbackNameOnError, args); + return Void(); + } + + Return onRemoved(uint64_t, const hidl_vec&, int32_t) override { return Void(); } + + Return onEnumerate(uint64_t, const hidl_vec&, int32_t) override { + return Void(); + } + + Return onLockoutChanged(uint64_t) override { return Void(); } +}; + +// Test class for the BiometricsFace HAL. +class FaceHidlTest : public ::testing::TestWithParam { + public: + void SetUp() override { + mService = IBiometricsFace::getService(GetParam()); + ASSERT_NE(mService, nullptr); + mCallback = new FaceCallback(); + mCallback->SetWaitTimeoutDefault(kTimeout); + Return ret1 = mService->setCallback(mCallback, [](const OptionalUint64& res) { + ASSERT_EQ(Status::OK, res.status); + // Makes sure the "deviceId" represented by "res.value" is not 0. + // 0 would mean the HIDL is not available. + ASSERT_NE(0UL, res.value); + }); + ASSERT_TRUE(ret1.isOk()); + Return ret2 = mService->setActiveUser(kUserId, kFacedataDir); + ASSERT_EQ(Status::OK, static_cast(ret2)); + } + + void TearDown() override {} + + sp mService; + sp mCallback; +}; + +// enroll with an invalid (all zeroes) HAT should fail. +TEST_P(FaceHidlTest, EnrollRemotelyZeroHatTest) { + // Filling HAT with zeros + hidl_vec token(69); + for (size_t i = 0; i < 69; i++) { + token[i] = 0; + } + + Return ret = mService->enrollRemotely(token, kTimeoutSec, {}); + ASSERT_EQ(Status::OK, static_cast(ret)); + + // onError should be called with a meaningful (nonzero) error. + auto res = mCallback->WaitForCallback(kCallbackNameOnError); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kUserId, res.args->userId); + EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error); +} + +// enroll with an invalid HAT should fail. +TEST_P(FaceHidlTest, EnrollRemotelyGarbageHatTest) { + // Filling HAT with pseudorandom invalid data. + // Using default seed to make the test reproducible. + std::mt19937 gen(std::mt19937::default_seed); + std::uniform_int_distribution dist; + hidl_vec token(69); + for (size_t i = 0; i < 69; ++i) { + token[i] = dist(gen); + } + + Return ret = mService->enrollRemotely(token, kTimeoutSec, {}); + ASSERT_EQ(Status::OK, static_cast(ret)); + + // onError should be called with a meaningful (nonzero) error. + auto res = mCallback->WaitForCallback(kCallbackNameOnError); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kUserId, res.args->userId); + EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error); +} + +} // anonymous namespace + +INSTANTIATE_TEST_SUITE_P( + PerInstance, FaceHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBiometricsFace::descriptor)), + android::hardware::PrintInstanceNameToString); From 1dfeba3c4709744aee258dc66face7eb371adefe Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 22 Jan 2020 12:09:23 -0800 Subject: [PATCH 0478/1022] Update PhoneCapability to use 1.5 UTRAN bands Test: build Bug: 143238191 Change-Id: Id86ad81d837c983e2d34633fdebdfc308e219a3d --- current.txt | 2 +- radio/config/1.3/types.hal | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/current.txt b/current.txt index 7196e3966b..edf55391be 100644 --- a/current.txt +++ b/current.txt @@ -671,7 +671,7 @@ def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardwar c68f5bd87f747f8e7968ff66ecc548b2d26f8e186b7bb805c11d6c883a838fc6 android.hardware.radio@1.5::IRadio e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication 9e962eff568dc8c712d83846f8c27460de5005ed9b836d3e08390e8aa56b5a46 android.hardware.radio@1.5::IRadioResponse -5971a891d7d8843e9fb9f44583a9a0a265ec42fd5e4e1c95c9803454d21fabf7 android.hardware.radio.config@1.3::types +2fd107f3de1b7e36825e241a88dfae8edf3a77c166cb746f00ddf6440ab78db1 android.hardware.radio.config@1.3::types a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication 0006ab8e8b0910cbd3bbb08d5f17d5fac7d65a2bdad5f2334e4851db9d1e6fa8 android.hardware.radio.config@1.3::IRadioConfigResponse diff --git a/radio/config/1.3/types.hal b/radio/config/1.3/types.hal index 3414534138..7860006707 100644 --- a/radio/config/1.3/types.hal +++ b/radio/config/1.3/types.hal @@ -17,10 +17,10 @@ package android.hardware.radio.config@1.3; import android.hardware.radio@1.1::GeranBands; -import android.hardware.radio@1.1::UtranBands; import android.hardware.radio@1.1::EutranBands; import android.hardware.radio@1.4::RadioAccessFamily; import android.hardware.radio@1.5::NgranBands; +import android.hardware.radio@1.5::UtranBands; /** Type for the SIM slot. */ enum SlotType : int32_t { From a4bea0eac926e490eb2551b535f3fdee6857273a Mon Sep 17 00:00:00 2001 From: Dan Stoza Date: Mon, 21 Oct 2019 15:43:55 -0700 Subject: [PATCH 0479/1022] Add generic layer metadata to Composer 2.4 Bug: 139747351 Test: VtsHalGraphicsComposerV2_4TargetTest Test: Manual verification with a modified Composer implementation Change-Id: I800841ab1348a93c73c25c5f8bcf2254d9dc22e8 --- graphics/composer/2.4/IComposerClient.hal | 74 +++++++++++++++++++ .../2.4/ComposerCommandBuffer.h | 21 ++++++ .../include/composer-hal/2.4/ComposerClient.h | 8 ++ .../composer-hal/2.4/ComposerCommandEngine.h | 37 ++++++++++ .../include/composer-hal/2.4/ComposerHal.h | 4 + .../include/composer-passthrough/2.4/HwcHal.h | 62 ++++++++++++++++ .../composer/2.4/utils/vts/ComposerVts.cpp | 10 +++ .../include/composer-vts/2.4/ComposerVts.h | 3 + .../VtsHalGraphicsComposerV2_4TargetTest.cpp | 23 ++++++ 9 files changed, 242 insertions(+) diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal index 7e0c33ce97..9e3cf0e083 100644 --- a/graphics/composer/2.4/IComposerClient.hal +++ b/graphics/composer/2.4/IComposerClient.hal @@ -71,6 +71,51 @@ interface IComposerClient extends @2.3::IComposerClient { * setClientTargetProperty(ClientTargetProperty clientTargetProperty); */ SET_CLIENT_TARGET_PROPERTY = 0x105 << @2.1::IComposerClient.Command:OPCODE_SHIFT, + + /** + * SET_LAYER_GENERIC_METADATA has this pseudo prototype + * + * setLayerGenericMetadata(string key, bool mandatory, vec value); + * + * Sets a piece of generic metadata for the given layer. If this + * function is called twice with the same key but different values, the + * newer value must override the older one. Calling this function with a + * 0-length value must reset that key's metadata as if it had not been + * set. + * + * A given piece of metadata may either be mandatory or a hint + * (non-mandatory) as indicated by the second parameter. Mandatory + * metadata may affect the composition result, which is to say that it + * may cause a visible change in the final image. By contrast, hints may + * only affect the composition strategy, such as which layers are + * composited by the client, but must not cause a visible change in the + * final image. The value of the mandatory flag shall match the value + * returned from getLayerGenericMetadataKeys for the given key. + * + * Only keys which have been returned from getLayerGenericMetadataKeys() + * shall be accepted. Any other keys must result in an UNSUPPORTED error. + * + * The value passed into this function shall be the binary + * representation of a HIDL type corresponding to the given key. For + * example, a key of 'com.example.V1_3.Foo' shall be paired with a + * value of type com.example@1.3::Foo, which would be defined in a + * vendor HAL extension. + * + * This function will be encoded in the command buffer in this order: + * 1) The key length, stored as a uint32_t + * 2) The key itself, padded to a uint32_t boundary if necessary + * 3) The mandatory flag, stored as a uint32_t + * 4) The value length in bytes, stored as a uint32_t + * 5) The value itself, padded to a uint32_t boundary if necessary + * + * @param key indicates which metadata value should be set on this layer + * @param mandatory indicates whether this particular key represents + * mandatory metadata or a hint (non-mandatory metadata), as + * described above + * @param value is a binary representation of a HIDL struct + * corresponding to the key as described above + */ + SET_LAYER_GENERIC_METADATA = 0x40e << @2.1::IComposerClient.Command:OPCODE_SHIFT, }; /** @@ -271,4 +316,33 @@ interface IComposerClient extends @2.3::IComposerClient { */ setContentType(Display display, ContentType type) generates (Error error); + + struct LayerGenericMetadataKey { + /** + * Key names must comply with the requirements specified for + * getLayerGenericMetadataKeys below + */ + string name; + + /** + * The mandatory flag is defined in the description of + * setLayerGenericMetadata above + */ + bool mandatory; + }; + + /** + * Retrieves the set of keys that may be passed into setLayerGenericMetadata + * + * Key names must meet the following requirements: + * - Must be specified in reverse domain name notation + * - Must not start with 'com.android' or 'android' + * - Must be unique within the returned vector + * - Must correspond to a matching HIDL struct type, which defines the + * structure of its values. For example, the key 'com.example.V1-3.Foo' + * should correspond to a value of type com.example@1.3::Foo, which is + * defined in a vendor HAL extension + */ + getLayerGenericMetadataKeys() + generates(Error error, vec keys); }; diff --git a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h index e84779ecbb..eb35e5cb9e 100644 --- a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h +++ b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h @@ -53,6 +53,27 @@ class CommandWriterBase : public V2_3::CommandWriterBase { writeSigned(static_cast(clientTargetProperty.dataspace)); endCommand(); } + + void setLayerGenericMetadata(const hidl_string& key, const bool mandatory, + const hidl_vec& value) { + const size_t commandSize = 3 + sizeToElements(key.size()) + sizeToElements(value.size()); + if (commandSize > std::numeric_limits::max()) { + LOG_FATAL("Too much generic metadata (%zu elements)", commandSize); + return; + } + + beginCommand(IComposerClient::Command::SET_LAYER_GENERIC_METADATA, + static_cast(commandSize)); + write(key.size()); + writeBlob(key.size(), reinterpret_cast(key.c_str())); + write(mandatory); + write(value.size()); + writeBlob(value.size(), value.data()); + endCommand(); + } + + protected: + uint32_t sizeToElements(uint32_t size) { return (size + 3) / 4; } }; // This class helps parse a command queue. Note that all sizes/lengths are in diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h index c864ce6961..c889069143 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h @@ -164,6 +164,14 @@ class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImplsetContentType(display, contentType); } + Return getLayerGenericMetadataKeys( + IComposerClient::getLayerGenericMetadataKeys_cb hidl_cb) override { + std::vector keys; + Error error = mHal->getLayerGenericMetadataKeys(&keys); + hidl_cb(error, keys); + return Void(); + } + static std::unique_ptr create(Hal* hal) { auto client = std::make_unique(hal); return client->init() ? std::move(client) : nullptr; diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h index e0153ceb81..697d6b8a6b 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h @@ -74,6 +74,43 @@ class ComposerCommandEngine : public V2_3::hal::ComposerCommandEngine { CommandWriterBase* getWriter() { return static_cast(mWriter.get()); } + bool executeCommand(V2_1::IComposerClient::Command command, uint16_t length) override { + switch (static_cast(command)) { + case IComposerClient::Command::SET_LAYER_GENERIC_METADATA: + return executeSetLayerGenericMetadata(length); + default: + return BaseType2_3::executeCommand(command, length); + } + } + + bool executeSetLayerGenericMetadata(uint16_t length) { + // We expect at least two buffer lengths and a mandatory flag + if (length < 3) { + return false; + } + + const uint32_t keySize = read(); + std::string key; + key.resize(keySize); + readBlob(keySize, key.data()); + + const bool mandatory = read(); + + const uint32_t valueSize = read(); + std::vector value(valueSize); + readBlob(valueSize, value.data()); + + auto error = mHal->setLayerGenericMetadata(mCurrentDisplay, mCurrentLayer, key, mandatory, + value); + if (error != Error::NONE) { + // The error cast is safe because setLayerGenericMetadata doesn't + // return any of the new values added in V2_4::Error + mWriter->setError(getCommandLoc(), static_cast(error)); + } + + return true; + } + ComposerHal* mHal; }; diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h index 277055c0c6..58991c1d8d 100644 --- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h +++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h @@ -79,6 +79,10 @@ class ComposerHal : public V2_3::hal::ComposerHal { uint32_t* outDisplayRequestMask, std::vector* outRequestedLayers, std::vector* outRequestMasks, IComposerClient::ClientTargetProperty* outClientTargetProperty) = 0; + virtual Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key, + bool mandatory, const std::vector& value) = 0; + virtual Error getLayerGenericMetadataKeys( + std::vector* outKeys) = 0; }; } // namespace hal diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h index 616852a71b..d28e00625f 100644 --- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h +++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h @@ -245,6 +245,61 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { return err; } + Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key, + bool mandatory, const std::vector& value) override { + if (!mDispatch.setLayerGenericMetadata) { + return Error::UNSUPPORTED; + } + + if (key.size() > std::numeric_limits::max()) { + return Error::BAD_PARAMETER; + } + + if (value.size() > std::numeric_limits::max()) { + return Error::BAD_PARAMETER; + } + + int32_t error = mDispatch.setLayerGenericMetadata( + mDevice, display, layer, static_cast(key.size()), key.c_str(), mandatory, + static_cast(value.size()), value.data()); + return static_cast(error); + } + + Error getLayerGenericMetadataKeys( + std::vector* outKeys) override { + if (!mDispatch.getLayerGenericMetadataKey) { + return Error::UNSUPPORTED; + } + + std::vector keys; + + uint32_t index = 0; + uint32_t keyLength = 0; + while (true) { + mDispatch.getLayerGenericMetadataKey(mDevice, index, &keyLength, nullptr, nullptr); + if (keyLength == 0) { + break; + } + + IComposerClient::LayerGenericMetadataKey key; + std::string keyName; + keyName.resize(keyLength); + mDispatch.getLayerGenericMetadataKey(mDevice, index, &keyLength, keyName.data(), + &key.mandatory); + key.name = keyName; + keys.emplace_back(std::move(key)); + + // Only attempt to load the first 100 keys to avoid an infinite loop + // if something goes wrong + if (++index > 100) { + break; + } + } + + *outKeys = std::move(keys); + return Error::NONE; + } + protected: bool initDispatch() override { if (!BaseType2_3::initDispatch()) { @@ -267,6 +322,11 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { this->initOptionalDispatch(HWC2_FUNCTION_SET_CONTENT_TYPE, &mDispatch.setContentType); this->initOptionalDispatch(HWC2_FUNCTION_GET_CLIENT_TARGET_PROPERTY, &mDispatch.getClientTargetProperty); + this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_GENERIC_METADATA, + &mDispatch.setLayerGenericMetadata); + this->initOptionalDispatch(HWC2_FUNCTION_GET_LAYER_GENERIC_METADATA_KEY, + &mDispatch.getLayerGenericMetadataKey); + return true; } @@ -319,6 +379,8 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl { HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES getSupportedContentTypes; HWC2_PFN_SET_CONTENT_TYPE setContentType; HWC2_PFN_GET_CLIENT_TARGET_PROPERTY getClientTargetProperty; + HWC2_PFN_SET_LAYER_GENERIC_METADATA setLayerGenericMetadata; + HWC2_PFN_GET_LAYER_GENERIC_METADATA_KEY getLayerGenericMetadataKey; } mDispatch = {}; hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr; diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp index 8a9c00608d..8cdc452be3 100644 --- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp @@ -129,6 +129,16 @@ Error ComposerClient::setContentType(Display display, IComposerClient::ContentTy return mClient->setContentType(display, contentType); } +Error ComposerClient::getLayerGenericMetadataKeys( + std::vector* outKeys) { + Error error = Error::NONE; + mClient->getLayerGenericMetadataKeys([&](const auto tmpError, const auto& tmpKeys) { + error = tmpError; + *outKeys = tmpKeys; + }); + return error; +} + } // namespace vts } // namespace V2_4 } // namespace composer diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h index df75a48655..3dd8e500d6 100644 --- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h @@ -93,6 +93,9 @@ class ComposerClient : public V2_3::vts::ComposerClient { Error setContentType(Display display, IComposerClient::ContentType contentType); + Error getLayerGenericMetadataKeys( + std::vector* outKeys); + private: const sp mClient; }; diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index 800ff08a17..f6b46ffd74 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "graphics_composer_hidl_hal_test@2.4" #include +#include #include #include @@ -625,6 +626,28 @@ INSTANTIATE_TEST_SUITE_P( testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), android::hardware::PrintInstanceNameToString); +TEST_F(GraphicsComposerHidlCommandTest, getLayerGenericMetadataKeys) { + std::vector keys; + mComposerClient->getLayerGenericMetadataKeys(&keys); + + std::regex reverseDomainName("^[a-zA-Z-]{2,}(\\.[a-zA-Z0-9-]+)+$"); + std::unordered_set uniqueNames; + for (const auto& key : keys) { + std::string name(key.name.c_str()); + + // Keys must not start with 'android' or 'com.android' + ASSERT_FALSE(name.find("android") == 0); + ASSERT_FALSE(name.find("com.android") == 0); + + // Keys must be in reverse domain name format + ASSERT_TRUE(std::regex_match(name, reverseDomainName)); + + // Keys must be unique within this list + const auto& [iter, inserted] = uniqueNames.insert(name); + ASSERT_TRUE(inserted); + } +} + } // namespace } // namespace vts } // namespace V2_4 From bb89a958e5d762743393aab99b30f937474cf104 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 25 Jul 2019 17:13:52 -0700 Subject: [PATCH 0480/1022] Add AIDL Lights HAL to support multiple lights per type This is a revision of the previous 2.0 HIDL-based light HAL. It accomplishes 2 goals: 1) Support more than 1 light for a given type. This allows Assistant to use the HAL on TV platforms that have usually 4 indicator lights. 2) Use AIDL, which is the more modern way of writing HALs. The previous HAL is in hardware/interfaces/light/2.0 and the new one is in versioned as aidl, as that supports forward compatibility. Test: atest VtsHalLightTargetTest Bug: 142715294, 142230898 Change-Id: I08d831ca0380d8bb187e43f6d5c214810ff72f50 --- .../compatibility_matrix.current.xml | 7 + light/aidl/Android.bp | 18 ++ .../hardware/light/BrightnessMode.aidl | 58 ++++++ .../android/hardware/light/FlashMode.aidl | 34 ++++ .../aidl/android/hardware/light/HwLight.aidl | 42 +++++ .../android/hardware/light/HwLightState.aidl | 64 +++++++ .../aidl/android/hardware/light/ILights.aidl | 47 +++++ .../android/hardware/light/LightType.aidl | 35 ++++ light/aidl/default/Android.bp | 16 ++ light/aidl/default/Lights.cpp | 39 ++++ light/aidl/default/Lights.h | 35 ++++ light/aidl/default/lights-default.rc | 5 + light/aidl/default/lights-default.xml | 6 + light/aidl/default/main.cpp | 35 ++++ light/aidl/vts/functional/Android.bp | 35 ++++ .../vts/functional/VtsHalLightTargetTest.cpp | 171 ++++++++++++++++++ light/utils/Android.bp | 4 + light/utils/main.cpp | 106 +++++++---- 18 files changed, 725 insertions(+), 32 deletions(-) create mode 100644 light/aidl/Android.bp create mode 100644 light/aidl/android/hardware/light/BrightnessMode.aidl create mode 100644 light/aidl/android/hardware/light/FlashMode.aidl create mode 100644 light/aidl/android/hardware/light/HwLight.aidl create mode 100644 light/aidl/android/hardware/light/HwLightState.aidl create mode 100644 light/aidl/android/hardware/light/ILights.aidl create mode 100644 light/aidl/android/hardware/light/LightType.aidl create mode 100644 light/aidl/default/Android.bp create mode 100644 light/aidl/default/Lights.cpp create mode 100644 light/aidl/default/Lights.h create mode 100644 light/aidl/default/lights-default.rc create mode 100644 light/aidl/default/lights-default.xml create mode 100644 light/aidl/default/main.cpp create mode 100644 light/aidl/vts/functional/Android.bp create mode 100644 light/aidl/vts/functional/VtsHalLightTargetTest.cpp diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 24f114b811..83e3df6188 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -289,6 +289,13 @@ default + + android.hardware.light + + ILights + default + + android.hardware.media.c2 1.0-1 diff --git a/light/aidl/Android.bp b/light/aidl/Android.bp new file mode 100644 index 0000000000..916a857b58 --- /dev/null +++ b/light/aidl/Android.bp @@ -0,0 +1,18 @@ +aidl_interface { + name: "android.hardware.light", + vendor_available: true, + srcs: [ + "android/hardware/light/*.aidl", + ], + stability: "vintf", + backend: { + java: { + platform_apis: true, + }, + ndk: { + vndk: { + enabled: true, + }, + }, + }, +} diff --git a/light/aidl/android/hardware/light/BrightnessMode.aidl b/light/aidl/android/hardware/light/BrightnessMode.aidl new file mode 100644 index 0000000000..bc296990ce --- /dev/null +++ b/light/aidl/android/hardware/light/BrightnessMode.aidl @@ -0,0 +1,58 @@ +/* + * 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. + */ +package android.hardware.light; + +@VintfStability +enum BrightnessMode { + /** + * Light brightness is managed by a user setting. + */ + USER = 0, + + /** + * Light brightness is managed by a light sensor. This is typically used + * to control the display backlight, but not limited to it. HALs and + * hardware implementations are free to support sensor for other lights or + * none whatsoever. + */ + SENSOR = 1, + + /** + * Use a low-persistence mode for display backlights, where the pixel + * color transition times are lowered. + * + * When set, the device driver must switch to a mode optimized for low display + * persistence that is intended to be used when the device is being treated as a + * head mounted display (HMD). The actual display brightness in this mode is + * implementation dependent, and any value set for color in LightState may be + * overridden by the HAL implementation. + * + * For an optimal HMD viewing experience, the display must meet the following + * criteria in this mode: + * - Gray-to-Gray, White-to-Black, and Black-to-White switching time must be ≤ 3 ms. + * - The display must support low-persistence with ≤ 3.5 ms persistence. + * Persistence is defined as the amount of time for which a pixel is + * emitting light for a single frame. + * - Any "smart panel" or other frame buffering options that increase display + * latency are disabled. + * - Display brightness is set so that the display is still visible to the user + * under normal indoor lighting. + * - The display must update at 60 Hz at least, but higher refresh rates are + * recommended for low latency. + * + */ + LOW_PERSISTENCE = 2, +} diff --git a/light/aidl/android/hardware/light/FlashMode.aidl b/light/aidl/android/hardware/light/FlashMode.aidl new file mode 100644 index 0000000000..00c6b6a028 --- /dev/null +++ b/light/aidl/android/hardware/light/FlashMode.aidl @@ -0,0 +1,34 @@ +/* + * 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. + */ +package android.hardware.light; + +@VintfStability +enum FlashMode { + /** + * Keep the light steady on or off. + */ + NONE = 0, + /** + * Flash the light at specified rate, potentially using a software-based + * implementation. + */ + TIMED = 1, + /** + * Flash the light using hardware flashing support. This may or may not + * support a user-defined flashing rate or other features. + */ + HARDWARE = 2, +} diff --git a/light/aidl/android/hardware/light/HwLight.aidl b/light/aidl/android/hardware/light/HwLight.aidl new file mode 100644 index 0000000000..43fdb4bf81 --- /dev/null +++ b/light/aidl/android/hardware/light/HwLight.aidl @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package android.hardware.light; + +import android.hardware.light.LightType; + +/** + * A description of a single light. Multiple lights can map to the same physical + * LED. Separate physical LEDs are always represented by separate instances. + */ +@VintfStability +parcelable HwLight { + /** + * Integer ID used for controlling this light + */ + int id; + + /** + * For a group of lights of the same logical type, sorting by ordinal should + * be give their physical order. No other meaning is carried by it. + */ + int ordinal; + + /** + * Logical type use of this light. + */ + LightType type; +} diff --git a/light/aidl/android/hardware/light/HwLightState.aidl b/light/aidl/android/hardware/light/HwLightState.aidl new file mode 100644 index 0000000000..24d3250887 --- /dev/null +++ b/light/aidl/android/hardware/light/HwLightState.aidl @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package android.hardware.light; + +import android.hardware.light.BrightnessMode; +import android.hardware.light.FlashMode; + +/** + * The parameters that can be set for a given light. + * + * Not all lights must support all parameters. If you + * can do something backward-compatible, do it. + */ +@VintfStability +parcelable HwLightState { + /** + * The color of the LED in ARGB. + * + * The implementation of this in the HAL and hardware is a best-effort one. + * - If a light can only do red or green and blue is requested, green + * should be shown. + * - If only a brightness ramp is supported, then this formula applies: + * unsigned char brightness = ((77*((color>>16)&0x00ff)) + * + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8; + * - If only on and off are supported, 0 is off, anything else is on. + * + * The high byte should be ignored. Callers should set it to 0xff (which + * would correspond to 255 alpha). + */ + int color; + + /** + * To flash the light at a given rate, set flashMode to FLASH_TIMED. + */ + FlashMode flashMode; + + /** + * flashOnMs should be set to the number of milliseconds to turn the + * light on, before it's turned off. + */ + int flashOnMs; + + /** + * flashOfMs should be set to the number of milliseconds to turn the + * light off, before it's turned back on. + */ + int flashOffMs; + + BrightnessMode brightnessMode; +} diff --git a/light/aidl/android/hardware/light/ILights.aidl b/light/aidl/android/hardware/light/ILights.aidl new file mode 100644 index 0000000000..2253f73c36 --- /dev/null +++ b/light/aidl/android/hardware/light/ILights.aidl @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package android.hardware.light; + +import android.hardware.light.HwLightState; +import android.hardware.light.HwLight; + +/** + * Allows controlling logical lights/indicators, mapped to LEDs in a + * hardware-specific manner by the HAL implementation. + */ +@VintfStability +interface ILights { + /** + * Set light identified by id to the provided state. + * + * If control over an invalid light is requested, this method exists with + * EX_UNSUPPORTED_OPERATION. Control over supported lights is done on a + * device-specific best-effort basis and unsupported sub-features will not + * be reported. + * + * @param id ID of logical light to set as returned by getLights() + * @param state describes what the light should look like. + */ + void setLightState(in int id, in HwLightState state); + + /** + * Discover what lights are supported by the HAL implementation. + * + * @return List of available lights + */ + HwLight[] getLights(); +} diff --git a/light/aidl/android/hardware/light/LightType.aidl b/light/aidl/android/hardware/light/LightType.aidl new file mode 100644 index 0000000000..9a7f65619d --- /dev/null +++ b/light/aidl/android/hardware/light/LightType.aidl @@ -0,0 +1,35 @@ +/* + * 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. + */ +package android.hardware.light; + +/** + * These light IDs correspond to logical lights, not physical. + * So for example, if your INDICATOR light is in line with your + * BUTTONS, it might make sense to also light the INDICATOR + * light to a reasonable color when the BUTTONS are lit. + */ +@VintfStability +enum LightType { + BACKLIGHT = 0, + KEYBOARD = 1, + BUTTONS = 2, + BATTERY = 3, + NOTIFICATIONS = 4, + ATTENTION = 5, + BLUETOOTH = 6, + WIFI = 7, + MICROPHONE = 8, +} diff --git a/light/aidl/default/Android.bp b/light/aidl/default/Android.bp new file mode 100644 index 0000000000..ae3f4630de --- /dev/null +++ b/light/aidl/default/Android.bp @@ -0,0 +1,16 @@ +cc_binary { + name: "android.hardware.lights-service.example", + relative_install_path: "hw", + init_rc: ["lights-default.rc"], + vintf_fragments: ["lights-default.xml"], + vendor: true, + shared_libs: [ + "libbase", + "libbinder_ndk", + "android.hardware.light-ndk_platform", + ], + srcs: [ + "Lights.cpp", + "main.cpp", + ], +} diff --git a/light/aidl/default/Lights.cpp b/light/aidl/default/Lights.cpp new file mode 100644 index 0000000000..74747d57bd --- /dev/null +++ b/light/aidl/default/Lights.cpp @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#include "Lights.h" + +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace light { + +ndk::ScopedAStatus Lights::setLightState(int id, const HwLightState& state) { + LOG(INFO) << "Lights setting state for id=" << id << " to color " << std::hex << state.color; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +ndk::ScopedAStatus Lights::getLights(std::vector* /*lights*/) { + LOG(INFO) << "Lights reporting supported lights"; + return ndk::ScopedAStatus::ok(); +} + +} // namespace light +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/light/aidl/default/Lights.h b/light/aidl/default/Lights.h new file mode 100644 index 0000000000..8cba5a1cfd --- /dev/null +++ b/light/aidl/default/Lights.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace light { + +// Default implementation that reports no supported lights. +class Lights : public BnLights { + ndk::ScopedAStatus setLightState(int id, const HwLightState& state) override; + ndk::ScopedAStatus getLights(std::vector* types) override; +}; + +} // namespace light +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/light/aidl/default/lights-default.rc b/light/aidl/default/lights-default.rc new file mode 100644 index 0000000000..687ec97dd1 --- /dev/null +++ b/light/aidl/default/lights-default.rc @@ -0,0 +1,5 @@ +service vendor.light-default /vendor/bin/hw/android.hardware.lights-service.example + class hal + user nobody + group nobody + shutdown critical diff --git a/light/aidl/default/lights-default.xml b/light/aidl/default/lights-default.xml new file mode 100644 index 0000000000..db604d61f0 --- /dev/null +++ b/light/aidl/default/lights-default.xml @@ -0,0 +1,6 @@ + + + android.hardware.light + ILights/default + + diff --git a/light/aidl/default/main.cpp b/light/aidl/default/main.cpp new file mode 100644 index 0000000000..a860bf4a98 --- /dev/null +++ b/light/aidl/default/main.cpp @@ -0,0 +1,35 @@ +/* + * 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 "Lights.h" + +#include +#include +#include + +using ::aidl::android::hardware::light::Lights; + +int main() { + ABinderProcess_setThreadPoolMaxThreadCount(0); + std::shared_ptr lights = ndk::SharedRefBase::make(); + + const std::string instance = std::string() + Lights::descriptor + "/default"; + binder_status_t status = AServiceManager_addService(lights->asBinder().get(), instance.c_str()); + CHECK(status == STATUS_OK); + + ABinderProcess_joinThreadPool(); + return EXIT_FAILURE; // should not reached +} diff --git a/light/aidl/vts/functional/Android.bp b/light/aidl/vts/functional/Android.bp new file mode 100644 index 0000000000..3dd8cf64ce --- /dev/null +++ b/light/aidl/vts/functional/Android.bp @@ -0,0 +1,35 @@ +// +// 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. +// + +cc_test { + name: "VtsHalLightTargetTest", + defaults: [ + "VtsHalTargetTestDefaults", + "use_libaidlvintf_gtest_helper_static", + ], + srcs: [ + "VtsHalLightTargetTest.cpp", + ], + shared_libs: [ + "libbinder", + ], + static_libs: [ + "android.hardware.light-cpp", + ], + test_suites: [ + "vts-core", + ], +} diff --git a/light/aidl/vts/functional/VtsHalLightTargetTest.cpp b/light/aidl/vts/functional/VtsHalLightTargetTest.cpp new file mode 100644 index 0000000000..3c26278a19 --- /dev/null +++ b/light/aidl/vts/functional/VtsHalLightTargetTest.cpp @@ -0,0 +1,171 @@ +/* + * 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. + */ + +#define LOG_TAG "light_aidl_hal_test" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using android::ProcessState; +using android::sp; +using android::String16; +using android::binder::Status; +using android::hardware::hidl_vec; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::light::BrightnessMode; +using android::hardware::light::FlashMode; +using android::hardware::light::HwLight; +using android::hardware::light::HwLightState; +using android::hardware::light::ILights; +using android::hardware::light::LightType; + +#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) +#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk()) + +const std::set kAllTypes{android::enum_range().begin(), + android::enum_range().end()}; + +class LightsAidl : public testing::TestWithParam { + public: + virtual void SetUp() override { + lights = android::waitForDeclaredService(String16(GetParam().c_str())); + ASSERT_NE(lights, nullptr); + ASSERT_TRUE(lights->getLights(&supportedLights).isOk()); + } + + sp lights; + std::vector supportedLights; + + virtual void TearDown() override { + for (const HwLight& light : supportedLights) { + HwLightState off; + off.color = 0x00000000; + off.flashMode = FlashMode::NONE; + off.brightnessMode = BrightnessMode::USER; + EXPECT_TRUE(lights->setLightState(light.id, off).isOk()); + } + + // must leave the device in a useable condition + for (const HwLight& light : supportedLights) { + if (light.type == LightType::BACKLIGHT) { + HwLightState backlightOn; + backlightOn.color = 0xFFFFFFFF; + backlightOn.flashMode = FlashMode::TIMED; + backlightOn.brightnessMode = BrightnessMode::USER; + EXPECT_TRUE(lights->setLightState(light.id, backlightOn).isOk()); + } + } + } +}; + +/** + * Ensure all reported lights actually work. + */ +TEST_P(LightsAidl, TestSupported) { + HwLightState whiteFlashing; + whiteFlashing.color = 0xFFFFFFFF; + whiteFlashing.flashMode = FlashMode::TIMED; + whiteFlashing.flashOnMs = 100; + whiteFlashing.flashOffMs = 50; + whiteFlashing.brightnessMode = BrightnessMode::USER; + for (const HwLight& light : supportedLights) { + EXPECT_TRUE(lights->setLightState(light.id, whiteFlashing).isOk()); + } +} + +/** + * Ensure all reported lights have one of the supported types. + */ +TEST_P(LightsAidl, TestSupportedLightTypes) { + for (const HwLight& light : supportedLights) { + EXPECT_TRUE(kAllTypes.find(light.type) != kAllTypes.end()); + } +} + +/** + * Ensure all lights have a unique id. + */ +TEST_P(LightsAidl, TestUniqueIds) { + std::set ids; + for (const HwLight& light : supportedLights) { + EXPECT_TRUE(ids.find(light.id) == ids.end()); + ids.insert(light.id); + } +} + +/** + * Ensure all lights have a unique ordinal for a given type. + */ +TEST_P(LightsAidl, TestUniqueOrdinalsForType) { + std::map> ordinalsByType; + for (const HwLight& light : supportedLights) { + auto& ordinals = ordinalsByType[(int)light.type]; + EXPECT_TRUE(ordinals.find(light.ordinal) == ordinals.end()); + ordinals.insert(light.ordinal); + } +} + +/** + * Ensure EX_UNSUPPORTED_OPERATION is returned if LOW_PERSISTENCE is not supported. + */ +TEST_P(LightsAidl, TestLowPersistence) { + HwLightState lowPersistence; + lowPersistence.color = 0xFF123456; + lowPersistence.flashMode = FlashMode::TIMED; + lowPersistence.flashOnMs = 100; + lowPersistence.flashOffMs = 50; + lowPersistence.brightnessMode = BrightnessMode::LOW_PERSISTENCE; + for (const HwLight& light : supportedLights) { + Status status = lights->setLightState(light.id, lowPersistence); + EXPECT_TRUE(status.isOk() || Status::EX_UNSUPPORTED_OPERATION == status.exceptionCode()); + } +} + +/** + * Ensure EX_UNSUPPORTED_OPERATION is returns for an invalid light id. + */ +TEST_P(LightsAidl, TestInvalidLightIdUnsupported) { + int maxId = INT_MIN; + for (const HwLight& light : supportedLights) { + maxId = std::max(maxId, light.id); + } + + Status status = lights->setLightState(maxId + 1, HwLightState()); + EXPECT_TRUE(status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION); +} + +INSTANTIATE_TEST_SUITE_P(Lights, LightsAidl, + testing::ValuesIn(android::getAidlHalInstanceNames(ILights::descriptor)), + android::PrintInstanceNameToString); + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + ProcessState::self()->setThreadPoolMaxThreadCount(1); + ProcessState::self()->startThreadPool(); + return RUN_ALL_TESTS(); +} diff --git a/light/utils/Android.bp b/light/utils/Android.bp index 4c287e4620..e901129d1f 100644 --- a/light/utils/Android.bp +++ b/light/utils/Android.bp @@ -23,7 +23,11 @@ cc_binary { shared_libs: [ "android.hardware.light@2.0", "libbase", + "libbinder", "libhidlbase", "libutils", ], + static_libs: [ + "android.hardware.light-cpp", + ], } diff --git a/light/utils/main.cpp b/light/utils/main.cpp index b83413246b..b9b6489eec 100644 --- a/light/utils/main.cpp +++ b/light/utils/main.cpp @@ -19,34 +19,23 @@ #include #include +#include +#include + +using android::sp; +using android::waitForVintfService; +using android::binder::Status; +using android::hardware::hidl_vec; + +namespace V2_0 = android::hardware::light::V2_0; +namespace aidl = android::hardware::light; void error(const std::string& msg) { LOG(ERROR) << msg; std::cerr << msg << std::endl; } -int main(int argc, char* argv[]) { - using ::android::hardware::hidl_vec; - using ::android::hardware::light::V2_0::Brightness; - using ::android::hardware::light::V2_0::Flash; - using ::android::hardware::light::V2_0::ILight; - using ::android::hardware::light::V2_0::LightState; - using ::android::hardware::light::V2_0::Status; - using ::android::hardware::light::V2_0::Type; - using ::android::sp; - - sp service = ILight::getService(); - if (service == nullptr) { - error("Could not retrieve light service."); - return -1; - } - - static LightState off = { - .color = 0u, - .flashMode = Flash::NONE, - .brightnessMode = Brightness::USER, - }; - +int parseArgs(int argc, char* argv[], unsigned int* color) { if (argc > 2) { error("Usage: blank_screen [color]"); return -1; @@ -54,25 +43,78 @@ int main(int argc, char* argv[]) { if (argc > 1) { char* col_ptr; - unsigned int col_new; - col_new = strtoul(argv[1], &col_ptr, 0); + *color = strtoul(argv[1], &col_ptr, 0); if (*col_ptr != '\0') { error("Failed to convert " + std::string(argv[1]) + " to number"); return -1; } - off.color = col_new; + + return 0; } - service->getSupportedTypes([&](const hidl_vec& types) { - for (Type type : types) { - Status ret = service->setLight(type, off); - if (ret != Status::SUCCESS) { - error("Failed to shut off screen for type " + + *color = 0u; + return 0; +} + +void setToColorAidl(sp hal, unsigned int color) { + static aidl::HwLightState off; + off.color = color; + off.flashMode = aidl::FlashMode::NONE; + off.brightnessMode = aidl::BrightnessMode::USER; + + std::vector lights; + Status status = hal->getLights(&lights); + if (!status.isOk()) { + error("Failed to list lights"); + return; + } + + for (auto light : lights) { + Status setStatus = hal->setLightState(light.id, off); + if (!setStatus.isOk()) { + error("Failed to shut off light id " + std::to_string(light.id)); + } + } +} + +void setToColorHidl(sp hal, unsigned int color) { + static V2_0::LightState off = { + .color = color, + .flashMode = V2_0::Flash::NONE, + .brightnessMode = V2_0::Brightness::USER, + }; + + hal->getSupportedTypes([&](const hidl_vec& types) { + for (auto type : types) { + V2_0::Status ret = hal->setLight(type, off); + if (ret != V2_0::Status::SUCCESS) { + error("Failed to shut off light for type " + std::to_string(static_cast(type))); } } }); - - return 0; +} + +int main(int argc, char* argv[]) { + unsigned int inputColor; + int result = parseArgs(argc, argv, &inputColor); + if (result != 0) { + return result; + } + + auto aidlHal = waitForVintfService(); + if (aidlHal != nullptr) { + setToColorAidl(aidlHal, inputColor); + return 0; + } + + sp hidlHal = V2_0::ILight::getService(); + if (hidlHal != nullptr) { + setToColorHidl(hidlHal, inputColor); + return 0; + } + + error("Could not retrieve light service."); + return -1; } From a29bfaf17a96cc72e91908e05a3c1b7ca1a2bde8 Mon Sep 17 00:00:00 2001 From: Amy Date: Thu, 16 Jan 2020 17:40:11 -0800 Subject: [PATCH 0481/1022] Convert VtsHalTvTunerV1_0TargetTest to be parameterized test Bug: 139309306 Test: atest VtsHalTvTunerV1_0TargetTest Change-Id: I02cd4b7c58b8339bc2fdc69ecb8fc0e88f5baa3f --- tv/tuner/1.0/vts/functional/Android.bp | 7 ++- .../VtsHalTvTunerV1_0TargetTest.cpp | 56 +++++++------------ 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp index 7d6b990a7b..3637708a6a 100644 --- a/tv/tuner/1.0/vts/functional/Android.bp +++ b/tv/tuner/1.0/vts/functional/Android.bp @@ -30,5 +30,10 @@ cc_test { shared_libs: [ "libbinder", ], - test_suites: ["general-tests"], + test_suites: [ + "general-tests", + "vts-core", + ], + + require_root: true, } diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 4e7dcc3ae4..820c58c4ce 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -31,8 +31,11 @@ #include #include #include +#include +#include #include #include +#include #include #include #include @@ -633,23 +636,10 @@ void DvrCallback::stopRecordThread() { android::Mutex::Autolock autoLock(mRecordThreadLock); } -// Test environment for Tuner HIDL HAL. -class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static TunerHidlEnvironment* Instance() { - static TunerHidlEnvironment* instance = new TunerHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { registerTestService(); } -}; - -class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class TunerHidlTest : public testing::TestWithParam { public: virtual void SetUp() override { - mService = ::testing::VtsHalHidlTargetTestBase::getService( - TunerHidlEnvironment::Instance()->getServiceName()); + mService = ITuner::getService(GetParam()); ASSERT_NE(mService, nullptr); } @@ -1242,7 +1232,7 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { /* * API STATUS TESTS */ -TEST_F(TunerHidlTest, CreateFrontend) { +TEST_P(TunerHidlTest, CreateFrontend) { Result status; hidl_vec feIds; @@ -1262,7 +1252,7 @@ TEST_F(TunerHidlTest, CreateFrontend) { } } -TEST_F(TunerHidlTest, TuneFrontend) { +TEST_P(TunerHidlTest, TuneFrontend) { Result status; hidl_vec feIds; @@ -1282,7 +1272,7 @@ TEST_F(TunerHidlTest, TuneFrontend) { } } -TEST_F(TunerHidlTest, StopTuneFrontend) { +TEST_P(TunerHidlTest, StopTuneFrontend) { Result status; hidl_vec feIds; @@ -1302,7 +1292,7 @@ TEST_F(TunerHidlTest, StopTuneFrontend) { } } -TEST_F(TunerHidlTest, CloseFrontend) { +TEST_P(TunerHidlTest, CloseFrontend) { Result status; hidl_vec feIds; @@ -1322,7 +1312,7 @@ TEST_F(TunerHidlTest, CloseFrontend) { } } -TEST_F(TunerHidlTest, CreateDemuxWithFrontend) { +TEST_P(TunerHidlTest, CreateDemuxWithFrontend) { Result status; hidl_vec feIds; @@ -1349,22 +1339,22 @@ TEST_F(TunerHidlTest, CreateDemuxWithFrontend) { } } -TEST_F(TunerHidlTest, CreateDemux) { +TEST_P(TunerHidlTest, CreateDemux) { description("Create Demux"); ASSERT_TRUE(createDemux()); } -TEST_F(TunerHidlTest, CloseDemux) { +TEST_P(TunerHidlTest, CloseDemux) { description("Close Demux"); ASSERT_TRUE(closeDemux()); } -TEST_F(TunerHidlTest, CreateDescrambler) { +TEST_P(TunerHidlTest, CreateDescrambler) { description("Create Descrambler"); ASSERT_TRUE(createDescrambler()); } -TEST_F(TunerHidlTest, CloseDescrambler) { +TEST_P(TunerHidlTest, CloseDescrambler) { description("Close Descrambler"); ASSERT_TRUE(closeDescrambler()); } @@ -1374,7 +1364,7 @@ TEST_F(TunerHidlTest, CloseDescrambler) { * * TODO: re-enable the tests after finalizing the testing stream. */ -/*TEST_F(TunerHidlTest, PlaybackDataFlowWithSectionFilterTest) { +/*TEST_P(TunerHidlTest, PlaybackDataFlowWithSectionFilterTest) { description("Feed ts data from playback and configure pes filter to get output"); // todo modulize the filter conf parser @@ -1417,7 +1407,7 @@ TEST_F(TunerHidlTest, CloseDescrambler) { ASSERT_TRUE(playbackDataFlowTest(filterConf, playbackConf, goldenOutputFiles)); } -TEST_F(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) { +TEST_P(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) { description("Feed ts data from frontend and test with PES filter"); // todo modulize the filter conf parser @@ -1447,7 +1437,7 @@ TEST_F(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) { ASSERT_TRUE(broadcastDataFlowTest(filterConf, goldenOutputFiles)); } -TEST_F(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) { +TEST_P(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) { description("Feed ts data from frontend to recording and test with ts record filter"); // todo modulize the filter conf parser @@ -1487,11 +1477,7 @@ TEST_F(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) { } // namespace -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(TunerHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - TunerHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; -} +INSTANTIATE_TEST_SUITE_P( + PerInstance, TunerHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), + android::hardware::PrintInstanceNameToString); From c9e2c6d31967e1d164ad724812032192196f026c Mon Sep 17 00:00:00 2001 From: Hunter Knepshield Date: Wed, 15 Jan 2020 17:48:01 -0800 Subject: [PATCH 0482/1022] Make IDumpstateDevice 1.1 Add dumpstateBoard_1_1 to accept a mode parameter (e.g. for limiting vendor logs to the right bug reports). Add setDeviceLoggingEnabled for the user to toggle vendor logging on and off. Bug: 143183758 Bug: 143184495 Test: atest VtsHalDumpstateV1_1TargetTest Change-Id: I5420e5e4ce88619c7e40cf967382f98babc3c3d5 --- .../compatibility_matrix.current.xml | 2 +- current.txt | 2 + .../VtsHalDumpstateV1_0TargetTest.cpp | 2 + dumpstate/1.1/Android.bp | 18 ++ dumpstate/1.1/IDumpstateDevice.hal | 53 ++++++ dumpstate/1.1/types.hal | 62 +++++++ dumpstate/1.1/vts/functional/Android.bp | 29 +++ .../VtsHalDumpstateV1_1TargetTest.cpp | 171 ++++++++++++++++++ 8 files changed, 338 insertions(+), 1 deletion(-) create mode 100644 dumpstate/1.1/Android.bp create mode 100644 dumpstate/1.1/IDumpstateDevice.hal create mode 100644 dumpstate/1.1/types.hal create mode 100644 dumpstate/1.1/vts/functional/Android.bp create mode 100644 dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 24f114b811..14d9866e60 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -174,7 +174,7 @@ android.hardware.dumpstate - 1.0 + 1.1 IDumpstateDevice default diff --git a/current.txt b/current.txt index 8724170496..d0458785af 100644 --- a/current.txt +++ b/current.txt @@ -633,6 +633,8 @@ f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardwar 4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types 66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory 994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory +881aa8720fb1d69aa9843bfab69d810ab7654a61d2f5ab5e2626cbf240f24eaf android.hardware.dumpstate@1.1::types +13b33f623521ded51a6c0f7ea5b77e97066d0aa1e38a83c2873f08ad67294f89 android.hardware.dumpstate@1.1::IDumpstateDevice 3dacec7801968e1e4479724dc0180442d9e915466bff051f80996266b1a51c2c android.hardware.gnss@2.1::IGnss ba62e1e8993bfb9f27fa04816fa0f2241ae2d01edfa3d0c04182e2e5de80045c android.hardware.gnss@2.1::IGnssCallback ccdf3c0fb2c02a6d4dc57afb276c3497ae8172b80b00ebc0bf8a0238dd38b01d android.hardware.gnss@2.1::IGnssConfiguration diff --git a/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp b/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp index 96b13c5c38..343d4c9bcf 100644 --- a/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp +++ b/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp @@ -78,6 +78,7 @@ TEST_P(DumpstateHidlTest, TestOk) { ASSERT_EQ(1, read(fds[0], &buff, 1)) << "dumped nothing"; native_handle_close(handle); + native_handle_delete(handle); } // Positive test: make sure dumpstateBoard() doesn't crash with two FDs. @@ -96,6 +97,7 @@ TEST_P(DumpstateHidlTest, TestHandleWithTwoFds) { ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description(); native_handle_close(handle); + native_handle_delete(handle); } INSTANTIATE_TEST_SUITE_P( diff --git a/dumpstate/1.1/Android.bp b/dumpstate/1.1/Android.bp new file mode 100644 index 0000000000..2aa8c82dc7 --- /dev/null +++ b/dumpstate/1.1/Android.bp @@ -0,0 +1,18 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.dumpstate@1.1", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IDumpstateDevice.hal", + ], + interfaces: [ + "android.hardware.dumpstate@1.0", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/dumpstate/1.1/IDumpstateDevice.hal b/dumpstate/1.1/IDumpstateDevice.hal new file mode 100644 index 0000000000..24831b37b2 --- /dev/null +++ b/dumpstate/1.1/IDumpstateDevice.hal @@ -0,0 +1,53 @@ +/* + * 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. + */ +package android.hardware.dumpstate@1.1; + +import @1.0::IDumpstateDevice; + +interface IDumpstateDevice extends @1.0::IDumpstateDevice { + /** + * Extension of dumpstateBoard which also accepts a mode parameter to limit dumped data. + * + * For an example of when this is relevant, consider a bug report being generated with + * DumpstateMode::CONNECTIVITY - there is no reason to include camera or USB logs in this type + * of report. + * + * The 1.0 version of #dumpstateBoard(handle) should just delegate to this new method and pass + * DumpstateMode::DEFAULT and a timeout of 30,000ms (30 seconds). + * + * @param h A native handle with one or two valid file descriptors. The first FD is for text + * output, the second (if present) is for binary output. + * @param mode A mode value to restrict dumped content. + * @param timeoutMillis An approximate "budget" for how much time this call has been allotted. + * If execution runs longer than this, the IDumpstateDevice service may be killed and only + * partial information will be included in the report. + */ + dumpstateBoard_1_1(handle h, DumpstateMode mode, uint64_t timeoutMillis); + + /** + * Turns device vendor logging on or off. + * + * The setting should be persistent across reboots. Underlying implementations may need to start + * vendor logging daemons, set system properties, or change logging masks, for example. Given + * that many vendor logs contain significant amounts of private information and may come with + * memory/storage/battery impacts, calling this method on a user build should only be done after + * user consent has been obtained, e.g. from a toggle in developer settings. + * + * @param enable Whether to enable or disable device vendor logging. + * @return success Whether or not the change took effect. + */ + setDeviceLoggingEnabled(bool enable) generates (bool success); +}; diff --git a/dumpstate/1.1/types.hal b/dumpstate/1.1/types.hal new file mode 100644 index 0000000000..a6f391aded --- /dev/null +++ b/dumpstate/1.1/types.hal @@ -0,0 +1,62 @@ +/* + * 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. + */ +package android.hardware.dumpstate@1.1; + +/** + * Constants that define the type of bug report being taken to restrict content appropriately. + */ +enum DumpstateMode : uint32_t { + /** + * Takes a bug report without user interference. + */ + FULL = 0, + + /** + * Interactive bug report, i.e. triggered by the user. + */ + INTERACTIVE = 1, + + /** + * Remote bug report triggered by DevicePolicyManager, for example. + */ + REMOTE = 2, + + /** + * Bug report triggered on a wear device. + */ + WEAR = 3, + + /** + * Bug report limited to only connectivity info (cellular, wifi, and networking). Sometimes + * called "telephony" in legacy contexts. + * + * All reported information MUST directly relate to connectivity debugging or customer support + * and MUST NOT contain unrelated private information. This information MUST NOT identify + * user-installed packages (UIDs are OK, package names are not), and MUST NOT contain logs of + * user application traffic. + */ + CONNECTIVITY = 4, + + /** + * Bug report limited to only wifi info. + */ + WIFI = 5, + + /** + * Default mode. + */ + DEFAULT = 6 +}; diff --git a/dumpstate/1.1/vts/functional/Android.bp b/dumpstate/1.1/vts/functional/Android.bp new file mode 100644 index 0000000000..5267706c0b --- /dev/null +++ b/dumpstate/1.1/vts/functional/Android.bp @@ -0,0 +1,29 @@ +// +// 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. +// + +cc_test { + name: "VtsHalDumpstateV1_1TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalDumpstateV1_1TargetTest.cpp"], + static_libs: [ + "android.hardware.dumpstate@1.0", + "android.hardware.dumpstate@1.1", + ], + test_suites: [ + "general-tests", + "vts-core", + ], +} diff --git a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp new file mode 100644 index 0000000000..3b6051cb7b --- /dev/null +++ b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp @@ -0,0 +1,171 @@ +/* + * 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. + */ + +#define LOG_TAG "dumpstate_1_1_hidl_hal_test" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using ::android::sp; +using ::android::hardware::Return; +using ::android::hardware::dumpstate::V1_1::DumpstateMode; +using ::android::hardware::dumpstate::V1_1::IDumpstateDevice; + +class DumpstateHidl1_1Test : public ::testing::TestWithParam { + public: + virtual void SetUp() override { + dumpstate = IDumpstateDevice::getService(GetParam()); + ASSERT_NE(dumpstate, nullptr) << "Could not get HIDL instance"; + } + + sp dumpstate; +}; + +#define TEST_FOR_DUMPSTATE_MODE(name, body, mode) \ + TEST_P(DumpstateHidl1_1Test, name##_##mode) { body(DumpstateMode::mode); } + +#define TEST_FOR_ALL_DUMPSTATE_MODES(name, body) \ + TEST_FOR_DUMPSTATE_MODE(name, body, FULL); \ + TEST_FOR_DUMPSTATE_MODE(name, body, INTERACTIVE); \ + TEST_FOR_DUMPSTATE_MODE(name, body, REMOTE); \ + TEST_FOR_DUMPSTATE_MODE(name, body, WEAR); \ + TEST_FOR_DUMPSTATE_MODE(name, body, CONNECTIVITY); \ + TEST_FOR_DUMPSTATE_MODE(name, body, WIFI); \ + TEST_FOR_DUMPSTATE_MODE(name, body, DEFAULT); + +const uint64_t kDefaultTimeoutMillis = 30 * 1000; // 30 seconds + +// Negative test: make sure dumpstateBoard() doesn't crash when passed a null pointer. +TEST_FOR_ALL_DUMPSTATE_MODES(TestNullHandle, [this](DumpstateMode mode) { + Return status = dumpstate->dumpstateBoard_1_1(nullptr, mode, kDefaultTimeoutMillis); + + ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description(); +}); + +// Negative test: make sure dumpstateBoard() ignores a handle with no FD. +TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithNoFd, [this](DumpstateMode mode) { + native_handle_t* handle = native_handle_create(0, 0); + ASSERT_NE(handle, nullptr) << "Could not create native_handle"; + + Return status = dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis); + + ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description(); + + native_handle_close(handle); + native_handle_delete(handle); +}); + +// Positive test: make sure dumpstateBoard() writes something to the FD. +TEST_FOR_ALL_DUMPSTATE_MODES(TestOk, [this](DumpstateMode mode) { + // Index 0 corresponds to the read end of the pipe; 1 to the write end. + int fds[2]; + ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno; + + native_handle_t* handle = native_handle_create(1, 0); + ASSERT_NE(handle, nullptr) << "Could not create native_handle"; + handle->data[0] = fds[1]; + + Return status = dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis); + ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description(); + + // Check that at least one byte was written + char buff; + ASSERT_EQ(1, read(fds[0], &buff, 1)) << "dumped nothing"; + + native_handle_close(handle); + native_handle_delete(handle); +}); + +// Positive test: make sure dumpstateBoard() doesn't crash with two FDs. +TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithTwoFds, [this](DumpstateMode mode) { + int fds1[2]; + int fds2[2]; + ASSERT_EQ(0, pipe2(fds1, O_NONBLOCK)) << errno; + ASSERT_EQ(0, pipe2(fds2, O_NONBLOCK)) << errno; + + native_handle_t* handle = native_handle_create(2, 0); + ASSERT_NE(handle, nullptr) << "Could not create native_handle"; + handle->data[0] = fds1[1]; + handle->data[1] = fds2[1]; + + Return status = dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis); + ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description(); + + native_handle_close(handle); + native_handle_delete(handle); +}); + +// Make sure dumpstateBoard_1_1 actually validates its arguments. +TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Negative) { + int fds[2]; + ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno; + + native_handle_t* handle = native_handle_create(1, 0); + ASSERT_NE(handle, nullptr) << "Could not create native_handle"; + handle->data[0] = fds[1]; + + Return status = dumpstate->dumpstateBoard_1_1(handle, static_cast(-100), + kDefaultTimeoutMillis); + ASSERT_FALSE(status.isOk()) << "Status should not be ok with invalid mode param: " + << status.description(); + + native_handle_close(handle); + native_handle_delete(handle); +} + +TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Undefined) { + int fds[2]; + ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno; + + native_handle_t* handle = native_handle_create(1, 0); + ASSERT_NE(handle, nullptr) << "Could not create native_handle"; + handle->data[0] = fds[1]; + + Return status = dumpstate->dumpstateBoard_1_1(handle, static_cast(9001), + kDefaultTimeoutMillis); + ASSERT_FALSE(status.isOk()) << "Status should not be ok with invalid mode param: " + << status.description(); + + native_handle_close(handle); + native_handle_delete(handle); +} + +// Make sure toggling device logging doesn't crash. +TEST_P(DumpstateHidl1_1Test, TestEnableDeviceLogging) { + Return status = dumpstate->setDeviceLoggingEnabled(true); + + ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description(); +} + +TEST_P(DumpstateHidl1_1Test, TestDisableDeviceLogging) { + Return status = dumpstate->setDeviceLoggingEnabled(false); + + ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description(); +} + +INSTANTIATE_TEST_SUITE_P( + PerInstance, DumpstateHidl1_1Test, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IDumpstateDevice::descriptor)), + android::hardware::PrintInstanceNameToString); From fc4c08698aaccb4e18f79a4b66942bd02698cd00 Mon Sep 17 00:00:00 2001 From: Nick Chalko Date: Thu, 16 Jan 2020 14:25:45 -0800 Subject: [PATCH 0483/1022] Add test mapping for Tuner HAL Run HAL VTS Change-Id: Ie1b62a6e7a8ab54df013cf59655d689e4a662170 Test: atest Bug: 135705719 --- tv/tuner/1.0/TEST_MAPPING | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tv/tuner/1.0/TEST_MAPPING diff --git a/tv/tuner/1.0/TEST_MAPPING b/tv/tuner/1.0/TEST_MAPPING new file mode 100644 index 0000000000..1979887eea --- /dev/null +++ b/tv/tuner/1.0/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "VtsHalTvTunerV1_0TargetTest" + } + ] +} \ No newline at end of file From ebebc9c26611c0f29a88e44b49bacd7ce3f5e4e7 Mon Sep 17 00:00:00 2001 From: Hayden Gomes Date: Fri, 10 Jan 2020 08:49:23 -0800 Subject: [PATCH 0484/1022] Adding v2 of audiocontrol hal - Removes deprecated getBusForContext - Adds APIs for enabling HAL to request and abandon audio focus Bug: 148098383 Test: vts-tradefed -module VtsHalAudioControlV2_0TargetTest Change-Id: I353bbd8ea7708ffb59831a8e1008951146798034 --- automotive/audiocontrol/2.0/Android.bp | 20 +++ automotive/audiocontrol/2.0/IAudioControl.hal | 78 +++++++++ automotive/audiocontrol/2.0/ICloseHandle.hal | 34 ++++ .../audiocontrol/2.0/IFocusListener.hal | 55 +++++++ .../audiocontrol/2.0/default/Android.bp | 39 +++++ .../audiocontrol/2.0/default/AudioControl.cpp | 60 +++++++ .../audiocontrol/2.0/default/AudioControl.h | 49 ++++++ .../audiocontrol/2.0/default/CloseHandle.cpp | 35 ++++ .../audiocontrol/2.0/default/CloseHandle.h | 48 ++++++ ...are.automotive.audiocontrol@2.0-service.rc | 4 + .../2.0/default/audiocontrol2_manifest.xml | 11 ++ .../audiocontrol/2.0/default/service.cpp | 52 ++++++ automotive/audiocontrol/2.0/types.hal | 31 ++++ .../2.0/vts/functional/Android.bp | 29 ++++ .../VtsHalAudioControlV2_0TargetTest.cpp | 155 ++++++++++++++++++ 15 files changed, 700 insertions(+) create mode 100644 automotive/audiocontrol/2.0/Android.bp create mode 100644 automotive/audiocontrol/2.0/IAudioControl.hal create mode 100644 automotive/audiocontrol/2.0/ICloseHandle.hal create mode 100644 automotive/audiocontrol/2.0/IFocusListener.hal create mode 100644 automotive/audiocontrol/2.0/default/Android.bp create mode 100644 automotive/audiocontrol/2.0/default/AudioControl.cpp create mode 100644 automotive/audiocontrol/2.0/default/AudioControl.h create mode 100644 automotive/audiocontrol/2.0/default/CloseHandle.cpp create mode 100644 automotive/audiocontrol/2.0/default/CloseHandle.h create mode 100644 automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc create mode 100644 automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml create mode 100644 automotive/audiocontrol/2.0/default/service.cpp create mode 100644 automotive/audiocontrol/2.0/types.hal create mode 100644 automotive/audiocontrol/2.0/vts/functional/Android.bp create mode 100644 automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp diff --git a/automotive/audiocontrol/2.0/Android.bp b/automotive/audiocontrol/2.0/Android.bp new file mode 100644 index 0000000000..2a9f8499e3 --- /dev/null +++ b/automotive/audiocontrol/2.0/Android.bp @@ -0,0 +1,20 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.automotive.audiocontrol@2.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IAudioControl.hal", + "ICloseHandle.hal", + "IFocusListener.hal", + ], + interfaces: [ + "android.hidl.base@1.0", + "android.hardware.audio.common@6.0", + ], + gen_java: true, +} diff --git a/automotive/audiocontrol/2.0/IAudioControl.hal b/automotive/audiocontrol/2.0/IAudioControl.hal new file mode 100644 index 0000000000..1073498f61 --- /dev/null +++ b/automotive/audiocontrol/2.0/IAudioControl.hal @@ -0,0 +1,78 @@ +/* + * 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. + */ + +package android.hardware.automotive.audiocontrol@2.0; + +import ICloseHandle; +import IFocusListener; +import android.hardware.audio.common@6.0::AudioUsage; + +/** + * Interacts with the car's audio subsystem to manage audio sources and volumes + */ +interface IAudioControl { + /** + * Registers focus listener to be used by HAL for requesting and abandoning audio focus. + * + * It is expected that there will only ever be a single focus listener registered. If the + * observer dies, the HAL implementation must unregister observer automatically. If called when + * a listener is already registered, the existing one should be unregistered and replaced with + * the new listener. + * + * @param listener the listener interface + * @return closeHandle A handle to unregister observer. + */ + registerFocusListener(IFocusListener listener) generates (ICloseHandle closeHandle); + + /** + * Notifies HAL of changes in audio focus status for focuses requested or abandoned by the HAL. + * + * This will be called in response to IFocusListener's requestAudioFocus and + * abandonAudioFocus, as well as part of any change in focus being held by the HAL due focus + * request from other activities or services. + * + * The HAL is not required to wait for an callback of AUDIOFOCUS_GAIN before playing audio, nor + * is it required to stop playing audio in the event of a AUDIOFOCUS_LOSS callback is received. + * + * @param usage The audio usage associated with the focus change {@code AttributeUsage} + * @param zoneId The identifier for the audio zone that the HAL is playing the stream in + * @param focusChange the AudioFocusChange that has occurred + */ + oneway onAudioFocusChange(bitfield usage, int32_t zoneId, + bitfield focusChange); + + /** + * Control the right/left balance setting of the car speakers. + * + * This is intended to shift the speaker volume toward the right (+) or left (-) side of + * the car. 0.0 means "centered". +1.0 means fully right. -1.0 means fully left. + * + * A value outside the range -1 to 1 must be clamped by the implementation to the -1 to 1 + * range. + */ + oneway setBalanceTowardRight(float value); + + /** + * Control the fore/aft fade setting of the car speakers. + * + * This is intended to shift the speaker volume toward the front (+) or back (-) of the car. + * 0.0 means "centered". +1.0 means fully forward. -1.0 means fully rearward. + * + * A value outside the range -1 to 1 must be clamped by the implementation to the -1 to 1 + * range. + */ + oneway setFadeTowardFront(float value); +}; diff --git a/automotive/audiocontrol/2.0/ICloseHandle.hal b/automotive/audiocontrol/2.0/ICloseHandle.hal new file mode 100644 index 0000000000..537af6d635 --- /dev/null +++ b/automotive/audiocontrol/2.0/ICloseHandle.hal @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package android.hardware.automotive.audiocontrol@2.0; + +/** + * Represents a generic close handle to remove a callback that doesn't need + * active interface. + * + * When close() is called OR when the interface is released, the underlying + * resources must be freed. + */ +interface ICloseHandle { + /** + * Closes the handle. + * + * The call must not fail and must be issued by the client at most once. + * Otherwise, the server must ignore subsequent calls. + */ + close(); +}; diff --git a/automotive/audiocontrol/2.0/IFocusListener.hal b/automotive/audiocontrol/2.0/IFocusListener.hal new file mode 100644 index 0000000000..4fd5ef0425 --- /dev/null +++ b/automotive/audiocontrol/2.0/IFocusListener.hal @@ -0,0 +1,55 @@ +/* + * 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. + */ + +package android.hardware.automotive.audiocontrol@2.0; + +import android.hardware.audio.common@6.0::AudioUsage; + +/** + * Callback interface for audio focus listener. + * + * For typical configuration, the listener the car audio service. + */ +interface IFocusListener { + /** + * Called whenever HAL is requesting focus as it is starting to play audio of a given usage in a + * specified zone. + * + * In response, IAudioControl#onAudioFocusChange will be called with focusChange status. This + * interaction is oneway to avoid blocking HAL so that it is not required to wait for a response + * before playing audio. + * + * @param usage The audio usage associated with the focus request {@code AttributeUsage} + * @param zoneId The identifier for the audio zone where the HAL is requesting focus + * @param focusGain The AudioFocusChange associated with this request. Should be one of the + * following: GAIN, GAIN_TRANSIENT, GAIN_TRANSIENT_MAY_DUCK, GAIN_TRANSIENT_EXCLUSIVE. + */ + oneway requestAudioFocus(bitfield usage, int32_t zoneId, + bitfield focusGain); + + /** + * Called whenever HAL is abandoning focus as it is finished playing audio of a given usage in a + * specific zone. + * + * In response, IAudioControl#onAudioFocusChange will be called with focusChange status. This + * interaction is oneway to avoid blocking HAL so that it is not required to wait for a response + * before stopping audio playback. + * + * @param usage The audio usage for which the HAL is abandoning focus {@code AttributeUsage} + * @param zoneId The identifier for the audio zone that the HAL abandoning focus + */ + oneway abandonAudioFocus(bitfield usage, int32_t zoneId); +}; diff --git a/automotive/audiocontrol/2.0/default/Android.bp b/automotive/audiocontrol/2.0/default/Android.bp new file mode 100644 index 0000000000..44ad0281fe --- /dev/null +++ b/automotive/audiocontrol/2.0/default/Android.bp @@ -0,0 +1,39 @@ +// 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. + +cc_binary { + name: "android.hardware.automotive.audiocontrol@2.0-service", + defaults: ["hidl_defaults"], + vendor: true, + relative_install_path: "hw", + srcs: [ + "AudioControl.cpp", + "service.cpp", + "CloseHandle.cpp", + ], + init_rc: ["android.hardware.automotive.audiocontrol@2.0-service.rc"], + + shared_libs: [ + "android.hardware.automotive.audiocontrol@2.0", + "libbase", + "libhidlbase", + "liblog", + "libutils", + ], + vintf_fragments: ["audiocontrol2_manifest.xml"], + cflags: [ + "-O0", + "-g", + ], +} diff --git a/automotive/audiocontrol/2.0/default/AudioControl.cpp b/automotive/audiocontrol/2.0/default/AudioControl.cpp new file mode 100644 index 0000000000..6505e34765 --- /dev/null +++ b/automotive/audiocontrol/2.0/default/AudioControl.cpp @@ -0,0 +1,60 @@ +#include "AudioControl.h" + +#include +#include + +#include "CloseHandle.h" + +namespace android::hardware::automotive::audiocontrol::V2_0::implementation { + +AudioControl::AudioControl() {} + +Return> AudioControl::registerFocusListener(const sp& listener) { + LOG(DEBUG) << "registering focus listener"; + sp closeHandle(nullptr); + + if (listener) { + mFocusListener = listener; + + closeHandle = new CloseHandle([this, listener]() { + if (mFocusListener == listener) { + mFocusListener = nullptr; + } + }); + } else { + LOG(ERROR) << "Unexpected nullptr for listener resulting in no-op."; + } + + return closeHandle; +} + +Return AudioControl::setBalanceTowardRight(float value) { + // For completeness, lets bounds check the input... + if (isValidValue(value)) { + LOG(ERROR) << "Balance value out of range -1 to 1 at " << value; + } else { + // Just log in this default mock implementation + LOG(INFO) << "Balance set to " << value; + } + return Void(); +} + +Return AudioControl::setFadeTowardFront(float value) { + // For completeness, lets bounds check the input... + if (isValidValue(value)) { + LOG(ERROR) << "Fader value out of range -1 to 1 at " << value; + } else { + // Just log in this default mock implementation + LOG(INFO) << "Fader set to " << value; + } + return Void(); +} + +Return AudioControl::onAudioFocusChange(hidl_bitfield usage, int zoneId, + hidl_bitfield focusChange) { + LOG(INFO) << "Focus changed: " << static_cast(focusChange) << " for usage " + << static_cast(usage) << " in zone " << zoneId; + return Void(); +} + +} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation diff --git a/automotive/audiocontrol/2.0/default/AudioControl.h b/automotive/audiocontrol/2.0/default/AudioControl.h new file mode 100644 index 0000000000..475a693cb7 --- /dev/null +++ b/automotive/audiocontrol/2.0/default/AudioControl.h @@ -0,0 +1,49 @@ +/* + * 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_AUTOMOTIVE_AUDIOCONTROL_V2_0_AUDIOCONTROL_H +#define ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V2_0_AUDIOCONTROL_H + +#include +#include +#include +#include +#include + +using android::hardware::audio::common::V6_0::AudioUsage; + +namespace android::hardware::automotive::audiocontrol::V2_0::implementation { + +class AudioControl : public IAudioControl { + public: + // Methods from ::android::hardware::automotive::audiocontrol::V2_0::IAudioControl follow. + Return> registerFocusListener(const sp& listener); + Return onAudioFocusChange(hidl_bitfield usage, int zoneId, + hidl_bitfield focusChange); + Return setBalanceTowardRight(float value) override; + Return setFadeTowardFront(float value) override; + + // Implementation details + AudioControl(); + + private: + sp mFocusListener; + static bool isValidValue(float value) { return (value > 1.0f) || (value < -1.0f); } +}; + +} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation + +#endif // ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V2_0_AUDIOCONTROL_H diff --git a/automotive/audiocontrol/2.0/default/CloseHandle.cpp b/automotive/audiocontrol/2.0/default/CloseHandle.cpp new file mode 100644 index 0000000000..bc47931535 --- /dev/null +++ b/automotive/audiocontrol/2.0/default/CloseHandle.cpp @@ -0,0 +1,35 @@ +/* + * 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 "CloseHandle.h" + +namespace android::hardware::automotive::audiocontrol::V2_0::implementation { + +CloseHandle::CloseHandle(Callback callback) : mCallback(callback) {} + +CloseHandle::~CloseHandle() { + close(); +} + +Return CloseHandle::close() { + const auto wasClosed = mIsClosed.exchange(true); + if (wasClosed) return {}; + + if (mCallback) mCallback(); + return {}; +} + +} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation diff --git a/automotive/audiocontrol/2.0/default/CloseHandle.h b/automotive/audiocontrol/2.0/default/CloseHandle.h new file mode 100644 index 0000000000..6caf0bfa7e --- /dev/null +++ b/automotive/audiocontrol/2.0/default/CloseHandle.h @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +namespace android::hardware::automotive::audiocontrol::V2_0::implementation { + +/** Generic ICloseHandle implementation ignoring double-close events. */ +class CloseHandle : public ICloseHandle { + public: + using Callback = std::function; + + /** + * Create a handle with a callback. + * + * The callback is guaranteed to be called exactly once. + * + * \param callback Called on the first close() call, or on destruction of the handle + */ + CloseHandle(Callback callback = nullptr); + virtual ~CloseHandle(); + + Return close() override; + + private: + const Callback mCallback; + std::atomic mIsClosed = false; + + DISALLOW_COPY_AND_ASSIGN(CloseHandle); +}; + +} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation diff --git a/automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc b/automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc new file mode 100644 index 0000000000..81c9be4460 --- /dev/null +++ b/automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc @@ -0,0 +1,4 @@ +service vendor.audiocontrol-hal-2.0 /vendor/bin/hw/android.hardware.automotive.audiocontrol@2.0-service + class hal + user audioserver + group system diff --git a/automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml b/automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml new file mode 100644 index 0000000000..42d23ed62e --- /dev/null +++ b/automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml @@ -0,0 +1,11 @@ + + + android.hardware.automotive.audiocontrol + hwbinder + 2.0 + + IAudioControl + default + + + \ No newline at end of file diff --git a/automotive/audiocontrol/2.0/default/service.cpp b/automotive/audiocontrol/2.0/default/service.cpp new file mode 100644 index 0000000000..dcc46c31aa --- /dev/null +++ b/automotive/audiocontrol/2.0/default/service.cpp @@ -0,0 +1,52 @@ +/* + * 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 +#include +#include +#include + +#include "AudioControl.h" + +// libhidl: +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; + +// Generated HIDL files +using android::hardware::automotive::audiocontrol::V2_0::IAudioControl; + +// The namespace in which all our implementation code lives +using namespace android::hardware::automotive::audiocontrol::V2_0::implementation; +using namespace android; + +// Main service entry point +int main() { + // Create an instance of our service class + android::sp service = new AudioControl(); + configureRpcThreadpool(1, true /*callerWillJoin*/); + + if (service->registerAsService() != OK) { + LOG(ERROR) << "registerAsService failed"; + return 1; + } + + // Join (forever) the thread pool we created for the service above + joinRpcThreadpool(); + + // We don't ever actually expect to return, so return an error if we do get here + return 2; +} \ No newline at end of file diff --git a/automotive/audiocontrol/2.0/types.hal b/automotive/audiocontrol/2.0/types.hal new file mode 100644 index 0000000000..65b0988487 --- /dev/null +++ b/automotive/audiocontrol/2.0/types.hal @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package android.hardware.automotive.audiocontrol@2.0; + +/** + * Changes in audio focus that can be experienced + */ +enum AudioFocusChange : uint32_t { + NONE = 0, + GAIN = 1, + GAIN_TRANSIENT = 2, + GAIN_TRANSIENT_MAY_DUCK = 3, + GAIN_TRANSIENT_EXCLUSIVE = 4, + LOSS = -1 * GAIN, + LOSS_TRANSIENT = -1 * GAIN_TRANSIENT, + LOSS_TRANSIENT_CAN_DUCK = -1 * GAIN_TRANSIENT_MAY_DUCK, +}; diff --git a/automotive/audiocontrol/2.0/vts/functional/Android.bp b/automotive/audiocontrol/2.0/vts/functional/Android.bp new file mode 100644 index 0000000000..520b042e37 --- /dev/null +++ b/automotive/audiocontrol/2.0/vts/functional/Android.bp @@ -0,0 +1,29 @@ +// +// 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. +// + +cc_test { + name: "VtsHalAudioControlV2_0TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalAudioControlV2_0TargetTest.cpp"], + static_libs: [ + "android.hardware.automotive.audiocontrol@2.0", + "libgmock", + ], + test_suites: [ + "general-tests", + "vts-core", + ], +} diff --git a/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp b/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp new file mode 100644 index 0000000000..0c106647c5 --- /dev/null +++ b/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp @@ -0,0 +1,155 @@ +/* + * 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. + */ + +#define LOG_TAG "VtsHalAudioControlTest" + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace ::android::hardware::automotive::audiocontrol::V2_0; +using ::android::sp; +using ::android::hardware::hidl_bitfield; +using ::android::hardware::hidl_enum_range; +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::audio::common::V6_0::AudioUsage; + +// The main test class for the automotive AudioControl HAL +class CarAudioControlHidlTest : public testing::TestWithParam { + public: + virtual void SetUp() override { + // Make sure we can connect to the driver + pAudioControl = IAudioControl::getService(GetParam()); + ASSERT_NE(pAudioControl.get(), nullptr); + } + + virtual void TearDown() override {} + + protected: + sp pAudioControl; // Every test needs access to the service +}; + +// +// Tests start here... +// + +/* + * Fader exercise test. Note that only a subjective observer could determine if the + * fader actually works. The only thing we can do is exercise the HAL and if the HAL crashes, + * we _might_ get a test failure if that breaks the connection to the driver. + */ +TEST_P(CarAudioControlHidlTest, FaderExercise) { + ALOGI("Fader exercise test (silent)"); + + // Set the fader all the way to the back + pAudioControl->setFadeTowardFront(-1.0f); + + // Set the fader all the way to the front + pAudioControl->setFadeTowardFront(1.0f); + + // Set the fader part way toward the back + pAudioControl->setFadeTowardFront(-0.333f); + + // Set the fader to a out of bounds value (driver should clamp) + pAudioControl->setFadeTowardFront(99999.9f); + + // Set the fader back to the middle + pAudioControl->setFadeTowardFront(0.0f); +} + +/* + * Balance exercise test. + */ +TEST_P(CarAudioControlHidlTest, BalanceExercise) { + ALOGI("Balance exercise test (silent)"); + + // Set the balance all the way to the left + pAudioControl->setBalanceTowardRight(-1.0f); + + // Set the balance all the way to the right + pAudioControl->setBalanceTowardRight(1.0f); + + // Set the balance part way toward the left + pAudioControl->setBalanceTowardRight(-0.333f); + + // Set the balance to a out of bounds value (driver should clamp) + pAudioControl->setBalanceTowardRight(99999.9f); + + // Set the balance back to the middle + pAudioControl->setBalanceTowardRight(0.0f); +} + +struct FocusListenerMock : public IFocusListener { + MOCK_METHOD(Return, requestAudioFocus, + (hidl_bitfield usage, int zoneId, + hidl_bitfield focusGain)); + MOCK_METHOD(Return, abandonAudioFocus, (hidl_bitfield usage, int zoneId)); +}; + +/* + * Test focus listener registration. + * + * Verifies that: + * - registerFocusListener succeeds; + * - registering a second listener succeeds in replacing the first; + * - closing handle does not crash; + */ +TEST_P(CarAudioControlHidlTest, FocusListenerRegistration) { + ALOGI("Focus listener test"); + + sp listener = new FocusListenerMock(); + + auto hidlResult = pAudioControl->registerFocusListener(listener); + ASSERT_TRUE(hidlResult.isOk()); + + sp listener2 = new FocusListenerMock(); + + auto hidlResult2 = pAudioControl->registerFocusListener(listener2); + ASSERT_TRUE(hidlResult2.isOk()); + + const sp& closeHandle = hidlResult2; + closeHandle->close(); +}; + +TEST_P(CarAudioControlHidlTest, FocusChangeExercise) { + ALOGI("Focus Change test"); + + pAudioControl->onAudioFocusChange(AudioUsage::MEDIA | 0, 0, + AudioFocusChange::GAIN_TRANSIENT | 0); +}; + +INSTANTIATE_TEST_SUITE_P( + PerInstance, CarAudioControlHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAudioControl::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file From 0a00c8d8c3d01d1787937de5e9337a41b7771777 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 22 Jan 2020 15:16:40 -0800 Subject: [PATCH 0485/1022] Added multi-band support One cell could have multiple bands assigned. One frequency could be shared by multiple bands because they have overlapping. Test: Telephony sanity tests. Bug: 131061889 Change-Id: I6018b9df8b8bd0745c3736df764f4569bea28baa --- current.txt | 2 +- radio/1.5/types.hal | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/current.txt b/current.txt index 3af2d957e7..b64e65a876 100644 --- a/current.txt +++ b/current.txt @@ -667,7 +667,7 @@ def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardwar ## # BEGIN Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present ## -616456d7ce4435d88995f9fe0025a76bca14bd70799e4ca3ff4bae74d54d1166 android.hardware.radio@1.5::types +430f8449ddb24c02284da561bfd24bb5a2a226d9ed2aec38e876e323e2b7eeee android.hardware.radio@1.5::types c68f5bd87f747f8e7968ff66ecc548b2d26f8e186b7bb805c11d6c883a838fc6 android.hardware.radio@1.5::IRadio e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication 9e962eff568dc8c712d83846f8c27460de5005ed9b836d3e08390e8aa56b5a46 android.hardware.radio@1.5::IRadioResponse diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index 5482acaf27..c0fa8af782 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -600,6 +600,9 @@ struct CellIdentityLte { /** Information about any closed subscriber group ID for this cell */ OptionalCsgInfo optionalCsgInfo; + + /** Bands used by the cell. */ + vec bands; }; /** @@ -615,8 +618,8 @@ struct CellIdentityNr { /** Additional PLMN-IDs beyond the primary PLMN broadcast for this cell */ vec additionalPlmns; - /** Band used by the cell */ - NgranBands band; + /** Bands used by the cell. */ + vec bands; }; struct CellInfoGsm { From 671c59917d89e66c20ef1549522b3ac8502a9dc3 Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Tue, 21 Jan 2020 15:44:10 -0800 Subject: [PATCH 0486/1022] Define biometrics.fingerprint@2.2 This interface allows to pass a hardware window ID to the enroll and authenticate methods. Also, FingerprintAcquiredInfo::START is introduced to make latency measurements possible. Bug: 139317981 Test: hidl-gen -L check android.hardware.biometrics.fingerprint@2.2 Change-Id: Ie044764984776d32ab52ca941cfa008202eca2c6 --- biometrics/fingerprint/2.2/Android.bp | 19 ++++++ .../2.2/IBiometricsFingerprint.hal | 58 +++++++++++++++++++ .../IBiometricsFingerprintClientCallback.hal | 35 +++++++++++ biometrics/fingerprint/2.2/types.hal | 42 ++++++++++++++ 4 files changed, 154 insertions(+) create mode 100644 biometrics/fingerprint/2.2/Android.bp create mode 100644 biometrics/fingerprint/2.2/IBiometricsFingerprint.hal create mode 100644 biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.hal create mode 100644 biometrics/fingerprint/2.2/types.hal diff --git a/biometrics/fingerprint/2.2/Android.bp b/biometrics/fingerprint/2.2/Android.bp new file mode 100644 index 0000000000..6c769ac22e --- /dev/null +++ b/biometrics/fingerprint/2.2/Android.bp @@ -0,0 +1,19 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.biometrics.fingerprint@2.2", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IBiometricsFingerprint.hal", + "IBiometricsFingerprintClientCallback.hal", + ], + interfaces: [ + "android.hardware.biometrics.fingerprint@2.1", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal b/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal new file mode 100644 index 0000000000..06510344ef --- /dev/null +++ b/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal @@ -0,0 +1,58 @@ +/* + * Copyright 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. + */ + +package android.hardware.biometrics.fingerprint@2.2; + +import @2.1::IBiometricsFingerprint; +import @2.1::RequestStatus; + +interface IBiometricsFingerprint extends @2.1::IBiometricsFingerprint { + /** + * Fingerprint enroll request: + * Switches the HAL state machine to collect and store a new fingerprint + * template. Switches back as soon as enroll is complete, signalled by + * (fingerprintMsg.type == FINGERPRINT_TEMPLATE_ENROLLING && + * fingerprintMsg.data.enroll.samplesRemaining == 0) + * or after timeoutSec seconds. + * The fingerprint template must be assigned to the group gid. + * + * @param hat a valid Hardware Authentication Token (HAT), generated + * as a result of a preEnroll() call. + * @param gid a framework defined fingerprint set (group) id. + * @param timeoutSec a timeout in seconds. + * @param windowId optional ID of an illumination window for optical under + * display fingerprint sensors. Must contain a null pointer if not used. + * + * @return debugErrno is a value the framework logs in case it is not 0. + * + * A notify() function may be called with a more detailed error structure. + */ + enroll_2_2(vec hat, uint32_t gid, uint32_t timeoutSec, handle windowId) + generates (RequestStatus debugErrno); + + /** + * Authenticates an operation identified by operationId + * + * @param operationId operation id. + * @param gid fingerprint group id. + * @param windowId optional ID of an illumination window for optical under + * display fingerprint sensors. Must contain a null pointer if not used. + * + * @return debugErrno is a value the framework logs in case it is not 0. + */ + authenticate_2_2(uint64_t operationId, uint32_t gid, handle windowId) + generates (RequestStatus debugErrno); +}; diff --git a/biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.hal b/biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.hal new file mode 100644 index 0000000000..14c2b12b76 --- /dev/null +++ b/biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.hal @@ -0,0 +1,35 @@ +/* + * Copyright 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. + */ + +package android.hardware.biometrics.fingerprint@2.2; + +import @2.1::IBiometricsFingerprintClientCallback; + +/* + * This HAL interface communicates asynchronous results from the + * fingerprint driver in response to user actions on the fingerprint sensor + */ +interface IBiometricsFingerprintClientCallback extends @2.1::IBiometricsFingerprintClientCallback { + /** + * Sent when a fingerprint image is acquired by the sensor + * @param deviceId the instance of this fingerprint device + * @param acquiredInfo a message about the quality of the acquired image + * @param vendorCode a vendor-specific message about the quality of the image. Only + * valid when acquiredInfo == ACQUIRED_VENDOR + */ + oneway onAcquired_2_2(uint64_t deviceId, FingerprintAcquiredInfo acquiredInfo, + int32_t vendorCode); +}; diff --git a/biometrics/fingerprint/2.2/types.hal b/biometrics/fingerprint/2.2/types.hal new file mode 100644 index 0000000000..2c1d3f374c --- /dev/null +++ b/biometrics/fingerprint/2.2/types.hal @@ -0,0 +1,42 @@ +/* + * Copyright 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. + */ + +package android.hardware.biometrics.fingerprint@2.2; + +import @2.1::FingerprintAcquiredInfo; + +/** + * Fingerprint acquisition info is meant as feedback for the current operation. + * Anything but START and ACQUIRED_GOOD must be shown to the user as feedback on + * how to take action on the current operation. For example, + * ACQUIRED_IMAGER_DIRTY may be used to tell the user to clean the sensor if it + * is detected to be dirty. + * If this causes the current operation to fail, an additional ERROR_CANCELED + * must be sent to stop the operation in progress (e.g. enrollment). + * In general, these messages will result in a "Try again" message. + */ +enum FingerprintAcquiredInfo : @2.1::FingerprintAcquiredInfo { + /** + * This message represents the earliest message sent at the beginning of the + * authentication pipeline. It is expected to be used to measure latency. For + * example, in a camera-based authentication system it's expected to be sent + * prior to camera initialization. Note this should be sent whenever + * authentication is restarted (see IBiometricsFace#userActivity). + * The framework will measure latency based on the time between the last START + * message and the onAuthenticated callback. + */ + START = 7, +}; From b05fa96baae63a105a08271855c6a9c06481f75e Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Wed, 22 Jan 2020 16:57:55 -0800 Subject: [PATCH 0487/1022] Add VTS tests for biometrics.fingerprint@2.2 Bug: 139317981 Test: m vts -j Test: vts-tradefed run commandAndExit vts -m VtsHalBiometricsFingerprintV2_2Target Change-Id: I9119de5e690163fbb9ddbb38b117206e8c95a279 --- .../fingerprint/2.2/vts/functional/Android.bp | 29 +++ ...HalBiometricsFingerprintV2_2TargetTest.cpp | 166 ++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 biometrics/fingerprint/2.2/vts/functional/Android.bp create mode 100644 biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp diff --git a/biometrics/fingerprint/2.2/vts/functional/Android.bp b/biometrics/fingerprint/2.2/vts/functional/Android.bp new file mode 100644 index 0000000000..496570c64c --- /dev/null +++ b/biometrics/fingerprint/2.2/vts/functional/Android.bp @@ -0,0 +1,29 @@ +/* + * Copyright 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. + */ + +cc_test { + name: "VtsHalBiometricsFingerprintV2_2TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalBiometricsFingerprintV2_2TargetTest.cpp"], + static_libs: [ + "android.hardware.biometrics.fingerprint@2.1", + "android.hardware.biometrics.fingerprint@2.2", + ], + test_suites: [ + "general-tests", + "vts-core", + ], +} diff --git a/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp new file mode 100644 index 0000000000..50bd4ab5e0 --- /dev/null +++ b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp @@ -0,0 +1,166 @@ +/* + * 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. + */ + +#define LOG_TAG "fingerprint_hidl_hal_test" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using android::sp; +using android::base::GetUintProperty; +using android::hardware::hidl_handle; +using android::hardware::hidl_vec; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::biometrics::fingerprint::V2_1::FingerprintAcquiredInfo; +using android::hardware::biometrics::fingerprint::V2_1::FingerprintError; +using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback; +using android::hardware::biometrics::fingerprint::V2_1::RequestStatus; +using android::hardware::biometrics::fingerprint::V2_2::IBiometricsFingerprint; + +namespace { + +constexpr uint32_t kTimeoutSec = 3; +constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec); +constexpr uint32_t kGroupId = 99; +constexpr char kCallbackNameOnError[] = "onError"; + +// Callback arguments that need to be captured for the tests. +struct FingerprintCallbackArgs { + // The error passed to the last onError() callback. + FingerprintError error; + + // The deviceId passed to the last callback. + uint64_t deviceId; +}; + +// Test callback class for the BiometricsFingerprint HAL. +// The HAL will call these callback methods to notify about completed operations +// or encountered errors. +class FingerprintCallback : public ::testing::VtsHalHidlTargetCallbackBase, + public IBiometricsFingerprintClientCallback { + public: + Return onEnrollResult(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); } + + Return onAcquired(uint64_t, FingerprintAcquiredInfo, int32_t) override { return Void(); } + + Return onAuthenticated(uint64_t, uint32_t, uint32_t, const hidl_vec&) override { + return Void(); + } + + Return onError(uint64_t deviceId, FingerprintError error, int32_t) override { + FingerprintCallbackArgs args = {}; + args.error = error; + args.deviceId = deviceId; + NotifyFromCallback(kCallbackNameOnError, args); + return Void(); + } + + Return onRemoved(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); } + + Return onEnumerate(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); } +}; + +class FingerprintHidlTest : public ::testing::TestWithParam { + public: + void SetUp() override { + mService = IBiometricsFingerprint::getService(GetParam()); + ASSERT_NE(mService, nullptr); + mCallback = new FingerprintCallback(); + mCallback->SetWaitTimeoutDefault(kTimeout); + Return ret1 = mService->setNotify(mCallback); + ASSERT_NE(0UL, static_cast(ret1)); + + /* + * Devices shipped from now on will instead store + * fingerprint data under /data/vendor_de//fpdata. + * Support for /data/vendor_de and /data/vendor_ce has been added to vold. + */ + + auto api_level = GetUintProperty("ro.product.first_api_level", 0); + if (api_level == 0) { + api_level = GetUintProperty("ro.build.version.sdk", 0); + } + ASSERT_NE(api_level, 0); + + // 27 is the API number for O-MR1 + string tmpDir; + if (api_level <= 27) { + tmpDir = "/data/system/users/0/fpdata/"; + } else { + tmpDir = "/data/vendor_de/0/fpdata/"; + } + + Return res = mService->setActiveGroup(kGroupId, tmpDir); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast(res)); + } + + sp mService; + sp mCallback; +}; + +// Enroll with an invalid (all zeroes) HAT should fail. +TEST_P(FingerprintHidlTest, EnrollZeroHatTest) { + // Filling HAT with zeros + hidl_vec token(69); + for (size_t i = 0; i < 69; i++) { + token[i] = 0; + } + + hidl_handle windowId = nullptr; + Return ret = mService->enroll_2_2(token, kGroupId, kTimeoutSec, windowId); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast(ret)); + + // At least one call to onError should occur + auto res = mCallback->WaitForCallback(kCallbackNameOnError); + ASSERT_NE(FingerprintError::ERROR_NO_ERROR, res.args->error); +} + +// Enroll with an invalid (null) HAT should fail. +TEST_P(FingerprintHidlTest, EnrollGarbageHatTest) { + // Filling HAT with pseudorandom invalid data. + // Using default seed to make the test reproducible. + std::mt19937 gen(std::mt19937::default_seed); + std::uniform_int_distribution dist; + hidl_vec token(69); + for (size_t i = 0; i < 69; ++i) { + token[i] = dist(gen); + } + + hidl_handle windowId = nullptr; + Return ret = mService->enroll_2_2(token, kGroupId, kTimeoutSec, windowId); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast(ret)); + + // At least one call to onError should occur + auto res = mCallback->WaitForCallback(kCallbackNameOnError); + ASSERT_NE(FingerprintError::ERROR_NO_ERROR, res.args->error); +} + +} // anonymous namespace + +INSTANTIATE_TEST_SUITE_P(PerInstance, FingerprintHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + IBiometricsFingerprint::descriptor)), + android::hardware::PrintInstanceNameToString); From 2c4e02329b6bcc33e3d520f3cc4e80ab7b83cf4a Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Thu, 26 Dec 2019 18:03:56 -0800 Subject: [PATCH 0488/1022] Add VTS tests for NNAPI IPreparedModel::executeFenced - Validation tests - Generated tests to exercise executeFenced path Bug: 142778241 Test: mm Change-Id: I509f0b5713fc86885d597940aae5ade0502c97ad --- neuralnetworks/1.3/vts/functional/Android.bp | 1 + .../vts/functional/GeneratedTestHarness.cpp | 46 +++++++++++++++++-- .../1.3/vts/functional/ValidateRequest.cpp | 18 ++++++++ .../vts/functional/VtsHalNeuralnetworks.cpp | 30 ++++++++++++ 4 files changed, 92 insertions(+), 3 deletions(-) diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp index ce2d3a917a..8e7e9b9d62 100644 --- a/neuralnetworks/1.3/vts/functional/Android.bp +++ b/neuralnetworks/1.3/vts/functional/Android.bp @@ -65,6 +65,7 @@ cc_test { "libhidlmemory", "libneuralnetworks_generated_test_harness", "libneuralnetworks_utils", + "libsync", ], whole_static_libs: [ "neuralnetworks_generated_V1_0_example", diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index a2c0c4efa0..dec931bd42 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -29,11 +29,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include @@ -70,7 +72,7 @@ using HidlToken = hidl_array(Constant::BYTE_SIZE_ namespace { -enum class Executor { ASYNC, SYNC, BURST }; +enum class Executor { ASYNC, SYNC, BURST, FENCED }; enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; @@ -562,6 +564,43 @@ void EvaluatePreparedModel(const sp& device, const sp& break; } + case Executor::FENCED: { + SCOPED_TRACE("fenced"); + ErrorStatus result; + hidl_handle sync_fence_handle; + sp fenced_callback; + Return ret = preparedModel->executeFenced( + request, {}, testConfig.measureTiming, + [&result, &sync_fence_handle, &fenced_callback]( + ErrorStatus error, const hidl_handle& handle, + const sp& callback) { + result = error; + sync_fence_handle = handle; + fenced_callback = callback; + }); + ASSERT_TRUE(ret.isOk()); + if (result != ErrorStatus::NONE) { + ASSERT_EQ(sync_fence_handle.getNativeHandle(), nullptr); + ASSERT_EQ(fenced_callback, nullptr); + executionStatus = ErrorStatus::GENERAL_FAILURE; + } else if (sync_fence_handle.getNativeHandle()) { + constexpr int kInfiniteTimeout = -1; + int sync_fd = sync_fence_handle.getNativeHandle()->data[0]; + ASSERT_GT(sync_fd, 0); + int r = sync_wait(sync_fd, kInfiniteTimeout); + ASSERT_GE(r, 0); + } + if (result == ErrorStatus::NONE) { + ASSERT_NE(fenced_callback, nullptr); + Return ret = fenced_callback->getExecutionInfo( + [&executionStatus, &timing](ErrorStatus error, Timing t) { + executionStatus = error; + timing = t; + }); + ASSERT_TRUE(ret.isOk()); + } + break; + } } if (testConfig.outputType != OutputType::FULLY_SPECIFIED && @@ -635,7 +674,7 @@ void EvaluatePreparedModel(const sp& device, const sp& case TestKind::GENERAL: { outputTypesList = {OutputType::FULLY_SPECIFIED}; measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; - executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; + executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST, Executor::FENCED}; } break; case TestKind::DYNAMIC_SHAPE: { outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT}; @@ -671,7 +710,8 @@ void EvaluatePreparedCoupledModels(const sp& device, const TestModel& coupledModel) { const std::vector outputTypesList = {OutputType::FULLY_SPECIFIED}; const std::vector measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; - const std::vector executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; + const std::vector executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST, + Executor::FENCED}; for (const OutputType outputType : outputTypesList) { for (const MeasureTiming measureTiming : measureTimingList) { diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index be4112ac2d..1ddd09c033 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -16,7 +16,9 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" +#include #include + #include "1.0/Utils.h" #include "1.3/Callbacks.h" #include "ExecutionBurstController.h" @@ -136,6 +138,22 @@ static void validate(const sp& preparedModel, const std::string& burst->freeMemory(keys.front()); } } + + // dispatch + { + SCOPED_TRACE(message + " [executeFenced]"); + Return ret = preparedModel->executeFenced( + request, {}, MeasureTiming::NO, + [](ErrorStatus error, const hidl_handle& handle, + const sp& callback) { + if (error != ErrorStatus::DEVICE_UNAVAILABLE) { + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); + } + ASSERT_EQ(handle.getNativeHandle(), nullptr); + ASSERT_EQ(callback, nullptr); + }); + ASSERT_TRUE(ret.isOk()); + } } ///////////////////////// REMOVE INPUT //////////////////////////////////// diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index 93c8f13c17..28cc8ffe65 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -133,6 +133,35 @@ void validateRequestFailure(const sp& preparedModel, const Reque // Forward declaration from ValidateBurst.cpp void validateBurst(const sp& preparedModel, const V1_0::Request& request); +// Validate sync_fence handles for dispatch with valid input +void validateExecuteFenced(const sp& preparedModel, const Request& request) { + SCOPED_TRACE("Expecting request to fail [executeFenced]"); + Return ret_null = + preparedModel->executeFenced(request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO, + [](ErrorStatus error, const hidl_handle& handle, + const sp& callback) { + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); + ASSERT_EQ(handle.getNativeHandle(), nullptr); + ASSERT_EQ(callback, nullptr); + }); + ASSERT_TRUE(ret_null.isOk()); + + native_handle_t* nativeHandle = native_handle_create(1, 0); + ASSERT_NE(nullptr, nativeHandle); + nativeHandle->data[0] = -1; + hidl_handle hidlHandle; + hidlHandle.setTo(nativeHandle, /*shouldOwn=*/true); + Return ret_invalid = + preparedModel->executeFenced(request, {hidlHandle}, V1_2::MeasureTiming::NO, + [](ErrorStatus error, const hidl_handle& handle, + const sp& callback) { + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); + ASSERT_EQ(handle.getNativeHandle(), nullptr); + ASSERT_EQ(callback, nullptr); + }); + ASSERT_TRUE(ret_invalid.isOk()); +} + void validateEverything(const sp& device, const Model& model, const Request& request, std::pair supportsDeadlines) { const auto [prepareModelDeadlineSupported, executionDeadlineSupported] = supportsDeadlines; @@ -144,6 +173,7 @@ void validateEverything(const sp& device, const Model& model, const Req if (preparedModel == nullptr) return; validateRequest(preparedModel, request, executionDeadlineSupported); + validateExecuteFenced(preparedModel, request); // TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2. ASSERT_TRUE(nn::compliantWithV1_0(request)); From 5fe14fa9ec6bcc89018875fa1f25d6e94002fecd Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Tue, 3 Dec 2019 20:54:53 -0800 Subject: [PATCH 0489/1022] Add Inter-Signal Bias fields Bug: 147500886 Test: on cuttlefish Change-Id: Id50d1f6a60e758e8c02b7a1c4bbdfd73f62ffeb7 --- current.txt | 3 +- gnss/2.1/Android.bp | 1 + gnss/2.1/IGnssMeasurementCallback.hal | 113 +++++++++++++++++- gnss/2.1/types.hal | 46 +++++++ .../vts/functional/gnss_hal_test_cases.cpp | 28 +++++ gnss/common/utils/default/Utils.cpp | 27 ++++- 6 files changed, 210 insertions(+), 8 deletions(-) create mode 100644 gnss/2.1/types.hal diff --git a/current.txt b/current.txt index 2d041e1135..71185c66a3 100644 --- a/current.txt +++ b/current.txt @@ -635,11 +635,12 @@ f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardwar 994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory 881aa8720fb1d69aa9843bfab69d810ab7654a61d2f5ab5e2626cbf240f24eaf android.hardware.dumpstate@1.1::types 13b33f623521ded51a6c0f7ea5b77e97066d0aa1e38a83c2873f08ad67294f89 android.hardware.dumpstate@1.1::IDumpstateDevice +769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types 3dacec7801968e1e4479724dc0180442d9e915466bff051f80996266b1a51c2c android.hardware.gnss@2.1::IGnss ba62e1e8993bfb9f27fa04816fa0f2241ae2d01edfa3d0c04182e2e5de80045c android.hardware.gnss@2.1::IGnssCallback ccdf3c0fb2c02a6d4dc57afb276c3497ae8172b80b00ebc0bf8a0238dd38b01d android.hardware.gnss@2.1::IGnssConfiguration 5a125c49ca83629e22afc8c39e865509343bfa2c38f0baea9a186bbac103492d android.hardware.gnss@2.1::IGnssMeasurement -0bfb291708dd4a7c6ec6b9883e2b8592357edde8d7e962ef83918e4a2154ce69 android.hardware.gnss@2.1::IGnssMeasurementCallback +d7bf37660a0946de9599dcbae997b077ee3e604fc2044534d40d3da04297a5d3 android.hardware.gnss@2.1::IGnssMeasurementCallback ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types diff --git a/gnss/2.1/Android.bp b/gnss/2.1/Android.bp index 8b0c374469..c615f1da23 100644 --- a/gnss/2.1/Android.bp +++ b/gnss/2.1/Android.bp @@ -7,6 +7,7 @@ hidl_interface { enabled: true, }, srcs: [ + "types.hal", "IGnss.hal", "IGnssCallback.hal", "IGnssMeasurement.hal", diff --git a/gnss/2.1/IGnssMeasurementCallback.hal b/gnss/2.1/IGnssMeasurementCallback.hal index ca6175f508..0385abd467 100644 --- a/gnss/2.1/IGnssMeasurementCallback.hal +++ b/gnss/2.1/IGnssMeasurementCallback.hal @@ -17,23 +17,114 @@ package android.hardware.gnss@2.1; import @1.0::IGnssMeasurementCallback; -import @1.1::IGnssMeasurementCallback; import @2.0::IGnssMeasurementCallback; import @2.0::ElapsedRealtime; +import GnssSignalType; /** The callback interface to report measurements from the HAL. */ interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback { /** - * Extends a GNSS Measurement, adding a basebandCN0DbHz. + * Flags to indicate what fields in GnssMeasurement are valid. + */ + enum GnssMeasurementFlags : uint32_t { + /** A valid 'snr' is stored in the data structure. */ + HAS_SNR = 1 << 0, + /** A valid 'carrier frequency' is stored in the data structure. */ + HAS_CARRIER_FREQUENCY = 1 << 9, + /** A valid 'carrier cycles' is stored in the data structure. */ + HAS_CARRIER_CYCLES = 1 << 10, + /** A valid 'carrier phase' is stored in the data structure. */ + HAS_CARRIER_PHASE = 1 << 11, + /** A valid 'carrier phase uncertainty' is stored in the data structure. */ + HAS_CARRIER_PHASE_UNCERTAINTY = 1 << 12, + /** A valid automatic gain control is stored in the data structure. */ + HAS_AUTOMATIC_GAIN_CONTROL = 1 << 13, + /** A valid receiver inter-signal bias is stored in the data structure. */ + HAS_RECEIVER_ISB = 1 << 16, + /** A valid receiver inter-signal bias uncertainty is stored in the data structure. */ + HAS_RECEIVER_ISB_UNCERTAINTY = 1 << 17, + /** A valid satellite inter-signal bias is stored in the data structure. */ + HAS_SATELLITE_ISB = 1 << 18, + /** A valid satellite inter-signal bias uncertainty is stored in the data structure. */ + HAS_SATELLITE_ISB_UNCERTAINTY = 1 << 19 + }; + + + /** + * Extends a GNSS Measurement, adding basebandCN0DbHz, GnssMeasurementFlags, + * receiverInterSignalBiasNs, receiverInterSignalBiasUncertaintyNs, satelliteInterSignalBiasNs + * and satelliteInterSignalBiasUncertaintyNs. */ struct GnssMeasurement { /** * GNSS measurement information for a single satellite and frequency, as in the 2.0 version * of the HAL. + * + * In this version of the HAL, the field 'flags' in the v2_0.v1_1.v1_0 struct is deprecated, + * and is no longer used by the framework. The GNSS measurement flags are instead reported + * in @2.1::IGnssMeasurementCallback.GnssMeasurement.flags. + * */ @2.0::IGnssMeasurementCallback.GnssMeasurement v2_0; + /** + * A set of flags indicating the validity of the fields in this data + * structure. + * + * Fields for which there is no corresponding flag must be filled in + * with a valid value. For convenience, these are marked as mandatory. + * + * Others fields may have invalid information in them, if not marked as + * valid by the corresponding bit in flags. + */ + bitfield flags; + + /** + * The receiver inter-signal bias (ISB) in nanoseconds. + * + * This value is the estimated receiver-side inter-system (different from the constellation + * in GnssClock.referenceSignalForIsb) bias and inter-frequency (different from the carrier + * frequency in GnssClock.referenceSignalForIsb) bias. The reported receiver ISB + * must include signal delays caused by + * + * - Receiver inter-constellation bias + * - Receiver inter-frequency bias + * - Receiver inter-code bias + * + * The value does not include the inter-frequency Ionospheric bias. + * + * The receiver ISB of GnssClock.referenceSignalForIsb is defined to be 0.0 nanoseconds. + */ + double receiverInterSignalBiasNs; + + /** + * 1-sigma uncertainty associated with the receiver inter-signal bias in nanoseconds. + */ + double receiverInterSignalBiasUncertaintyNs; + + /** + * The satellite inter-signal bias in nanoseconds. + * + * This value is the satellite-and-control-segment-side inter-system (different from the + * constellation in GnssClock.referenceSignalForIsb) bias and inter-frequency (different + * from the carrier frequency in GnssClock.referenceSignalForIsb) bias, including: + * + * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPT-UTC Time Offset (TauGps), + * BDS-GLO Time Offset (BGTO)) + * - Group delay (e.g., Total Group Delay (TGD)) + * - Satellite inter-signal bias, which includes satellite inter-frequency bias (GLO only), + * and satellite inter-code bias (e.g., Differential Code Bias (DCB)). + * + * The receiver ISB of GnssClock.referenceSignalForIsb is defined to be 0.0 nanoseconds. + */ + double satelliteInterSignalBiasNs; + + /** + * 1-sigma uncertainty associated with the satellite inter-signal bias in nanoseconds. + */ + double satelliteInterSignalBiasUncertaintyNs; + /** * Baseband Carrier-to-noise density in dB-Hz, typically in the range [0, 63]. It contains * the measured C/N0 value for the signal measured at the baseband. @@ -51,8 +142,22 @@ interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback { }; /** - * Complete set of GNSS Measurement data, same as 2.0 with additional double (i.e., - * basebandCN0DbHz) in measurements. + * Extends a GNSS clock time, adding a referenceSignalTypeForIsb. + */ + struct GnssClock { + /** + * GNSS clock time information, as in the 1.0 version of the HAL. + */ + @1.0::IGnssMeasurementCallback.GnssClock v1_0; + + /** + * Reference GNSS signal type for inter-signal bias. + */ + GnssSignalType referenceSignalTypeForIsb; + }; + + /** + * Complete set of GNSS Measurement data, same as 2.0 with additional fields in measurements. */ struct GnssData { /** The full set of satellite measurement observations. */ diff --git a/gnss/2.1/types.hal b/gnss/2.1/types.hal new file mode 100644 index 0000000000..e4484c15f3 --- /dev/null +++ b/gnss/2.1/types.hal @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.1; + +import @2.0::GnssConstellationType; + +/** + * Represents a GNSS signal type. + */ +struct GnssSignalType { + /** + * Constellation type of the SV that transmits the signal. + */ + GnssConstellationType constellation; + + /** + * Carrier frequency in Hz of the signal. + */ + double carrierFrequencyHz; + + /** + * The type of code of the GNSS signal. + * + * This is used to specify the observation descriptor defined in GNSS Observation Data File + * Header Section Description in the RINEX standard (Version 3.XX). In RINEX Version 3.03, + * in Appendix Table A2 Attributes are listed as uppercase letters (for instance, "A" for + * "A channel"). + * + * See the comment of @2.0::IGnssMeasurementCallback.GnssMeasurement.codeType for more details. + */ + string codeType; +}; diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp index 2c51717665..9a7bd77bfe 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "GnssHalTestCases" #include +#include #include "Utils.h" #include @@ -30,6 +31,7 @@ using IGnssMeasurement_2_1 = android::hardware::gnss::V2_1::IGnssMeasurement; using IGnssMeasurement_2_0 = android::hardware::gnss::V2_0::IGnssMeasurement; using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement; using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement; + using IGnssConfiguration_2_1 = android::hardware::gnss::V2_1::IGnssConfiguration; using IGnssConfiguration_2_0 = android::hardware::gnss::V2_0::IGnssConfiguration; using IGnssConfiguration_1_1 = android::hardware::gnss::V1_1::IGnssConfiguration; @@ -38,6 +40,8 @@ using IGnssConfiguration_1_0 = android::hardware::gnss::V1_0::IGnssConfiguration using android::hardware::gnss::V2_0::GnssConstellationType; using android::hardware::gnss::V2_1::IGnssConfiguration; +using GnssMeasurementFlags = IGnssMeasurementCallback_2_1::GnssMeasurementFlags; + /* * SetupTeardownCreateCleanup: * Requests the gnss HAL then calls cleanup @@ -92,6 +96,7 @@ TEST_P(GnssHalTest, TestGnssConfigurationExtension) { * TestGnssMeasurementFields: * Sets a GnssMeasurementCallback, waits for a measurement, and verifies * 1. basebandCN0DbHz is valid + * 2. ISB fields are valid if HAS_INTER_SIGNAL_BIAS is true. */ TEST_P(GnssHalTest, TestGnssMeasurementFields) { const int kFirstGnssMeasurementTimeoutSeconds = 10; @@ -118,6 +123,29 @@ TEST_P(GnssHalTest, TestGnssMeasurementFields) { for (auto measurement : lastMeasurement.measurements) { // Verify basebandCn0DbHz is valid. ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0); + + if (((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_RECEIVER_ISB) > 0) && + ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_RECEIVER_ISB_UNCERTAINTY) > + 0) && + ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_SATELLITE_ISB) > 0) && + ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_SATELLITE_ISB_UNCERTAINTY) > + 0)) { + GnssConstellationType referenceConstellation = + lastMeasurement.clock.referenceSignalTypeForIsb.constellation; + double carrierFrequencyHz = + lastMeasurement.clock.referenceSignalTypeForIsb.carrierFrequencyHz; + std::string codeType = lastMeasurement.clock.referenceSignalTypeForIsb.codeType; + + ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN && + referenceConstellation >= GnssConstellationType::IRNSS); + ASSERT_TRUE(carrierFrequencyHz > 0); + ASSERT_TRUE(codeType != ""); + + ASSERT_TRUE(std::abs(measurement.receiverInterSignalBiasNs) < 1.0e6); + ASSERT_TRUE(measurement.receiverInterSignalBiasUncertaintyNs >= 0); + ASSERT_TRUE(std::abs(measurement.satelliteInterSignalBiasNs) < 1.0e6); + ASSERT_TRUE(measurement.satelliteInterSignalBiasUncertaintyNs >= 0); + } } iGnssMeasurement->close(); diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp index ccb91b100f..0cdc865849 100644 --- a/gnss/common/utils/default/Utils.cpp +++ b/gnss/common/utils/default/Utils.cpp @@ -24,24 +24,45 @@ namespace gnss { namespace common { using GnssSvFlags = V1_0::IGnssCallback::GnssSvFlags; -using GnssMeasurementFlags = V1_0::IGnssMeasurementCallback::GnssMeasurementFlags; +using GnssMeasurementFlagsV1_0 = V1_0::IGnssMeasurementCallback::GnssMeasurementFlags; +using GnssMeasurementFlagsV2_1 = V2_1::IGnssMeasurementCallback::GnssMeasurementFlags; using GnssMeasurementStateV2_0 = V2_0::IGnssMeasurementCallback::GnssMeasurementState; using ElapsedRealtime = V2_0::ElapsedRealtime; using ElapsedRealtimeFlags = V2_0::ElapsedRealtimeFlags; using GnssConstellationTypeV2_0 = V2_0::GnssConstellationType; using IGnssMeasurementCallbackV2_0 = V2_0::IGnssMeasurementCallback; +using GnssSignalType = V2_1::GnssSignalType; GnssDataV2_1 Utils::getMockMeasurementV2_1() { GnssDataV2_0 gnssDataV2_0 = Utils::getMockMeasurementV2_0(); V2_1::IGnssMeasurementCallback::GnssMeasurement gnssMeasurementV2_1 = { .v2_0 = gnssDataV2_0.measurements[0], + .flags = (uint32_t)(GnssMeasurementFlagsV2_1::HAS_CARRIER_FREQUENCY | + GnssMeasurementFlagsV2_1::HAS_CARRIER_PHASE | + GnssMeasurementFlagsV2_1::HAS_RECEIVER_ISB | + GnssMeasurementFlagsV2_1::HAS_RECEIVER_ISB_UNCERTAINTY | + GnssMeasurementFlagsV2_1::HAS_SATELLITE_ISB | + GnssMeasurementFlagsV2_1::HAS_SATELLITE_ISB_UNCERTAINTY), + .receiverInterSignalBiasNs = 10.0, + .receiverInterSignalBiasUncertaintyNs = 100.0, + .satelliteInterSignalBiasNs = 20.0, + .satelliteInterSignalBiasUncertaintyNs = 150.0, .basebandCN0DbHz = 25.0, }; + GnssSignalType referenceSignalTypeForIsb = { + .constellation = GnssConstellationTypeV2_0::GPS, + .carrierFrequencyHz = 1.59975e+09, + .codeType = "C", + }; + V2_1::IGnssMeasurementCallback::GnssClock gnssClockV2_1 = { + .v1_0 = gnssDataV2_0.clock, + .referenceSignalTypeForIsb = referenceSignalTypeForIsb, + }; hidl_vec measurements(1); measurements[0] = gnssMeasurementV2_1; GnssDataV2_1 gnssDataV2_1 = { .measurements = measurements, - .clock = gnssDataV2_0.clock, + .clock = gnssClockV2_1, .elapsedRealtime = gnssDataV2_0.elapsedRealtime, }; return gnssDataV2_1; @@ -49,7 +70,7 @@ GnssDataV2_1 Utils::getMockMeasurementV2_1() { GnssDataV2_0 Utils::getMockMeasurementV2_0() { V1_0::IGnssMeasurementCallback::GnssMeasurement measurement_1_0 = { - .flags = (uint32_t)GnssMeasurementFlags::HAS_CARRIER_FREQUENCY, + .flags = (uint32_t)GnssMeasurementFlagsV1_0::HAS_CARRIER_FREQUENCY, .svid = (int16_t)6, .constellation = V1_0::GnssConstellationType::UNKNOWN, .timeOffsetNs = 0.0, From 9e62926f251cc7137a0d74b7dcc39b0095323d9b Mon Sep 17 00:00:00 2001 From: Jaideep Sharma Date: Thu, 23 Jan 2020 16:26:02 +0530 Subject: [PATCH 0490/1022] audiohal : add support for call_screen mode Bug: 140384450 Test: make Change-Id: Iea7816ba35538e5ee966dae4f57abf147d203bd0 --- audio/core/all-versions/default/PrimaryDevice.cpp | 3 +++ .../vts/functional/4.0/AudioPrimaryHidlHalTest.cpp | 12 +++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/audio/core/all-versions/default/PrimaryDevice.cpp b/audio/core/all-versions/default/PrimaryDevice.cpp index 679f85dad3..11c1c5a4df 100644 --- a/audio/core/all-versions/default/PrimaryDevice.cpp +++ b/audio/core/all-versions/default/PrimaryDevice.cpp @@ -203,6 +203,9 @@ Return PrimaryDevice::setMode(AudioMode mode) { case AudioMode::RINGTONE: case AudioMode::IN_CALL: case AudioMode::IN_COMMUNICATION: +#if MAJOR_VERSION >= 6 + case AudioMode::CALL_SCREEN: +#endif break; // Valid values default: return Result::INVALID_ARGUMENTS; diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp index 709b7cd369..b0eb2e0cfb 100644 --- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp @@ -244,7 +244,13 @@ TEST_P(OutputStreamTest, updateSourceMetadata) { TEST_P(AudioPrimaryHidlTest, setMode) { doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise"); // Test Invalid values - for (int mode : {-2, -1, int(AudioMode::IN_COMMUNICATION) + 1}) { +#if MAJOR_VERSION >= 6 + int maxMode = int(AudioMode::CALL_SCREEN); +#else + int maxMode = int(AudioMode::IN_COMMUNICATION); +#endif + + for (int mode : {-2, -1, maxMode + 1}) { ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(AudioMode(mode))) << "mode=" << mode; } @@ -253,6 +259,10 @@ TEST_P(AudioPrimaryHidlTest, setMode) { AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) { ASSERT_OK(getDevice()->setMode(mode)) << "mode=" << toString(mode); } + // AudioMode::CALL_SCREEN as support is optional +#if MAJOR_VERSION >= 6 + ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, getDevice()->setMode(AudioMode::CALL_SCREEN)); +#endif } TEST_P(AudioPrimaryHidlTest, setBtHfpSampleRate) { From 05066109ff0fb2e6c67c9c978655bb589dfe8018 Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Fri, 10 Jan 2020 12:43:08 -0800 Subject: [PATCH 0491/1022] Camera: Add ICameraProviderCallback version 2.6 The new version adds callback for physical sub-camera status callback. Test: VtsHalCameraProviderV2_4TargetTest --hal_service_instance=android.hardware.camera.provider@2.6::ICameraProvider/internal/1 Bug: 119325027 Change-Id: I8148f6c55f80d7f4092d2fe5ccf92509bb8c069d --- camera/provider/2.4/ICameraProvider.hal | 2 +- .../provider/2.4/ICameraProviderCallback.hal | 4 +- camera/provider/2.4/vts/functional/Android.bp | 1 + .../VtsHalCameraProviderV2_4TargetTest.cpp | 66 ++++++++++++++++--- camera/provider/2.6/Android.bp | 25 +++++++ camera/provider/2.6/ICameraProvider.hal | 30 +++++++++ .../provider/2.6/ICameraProviderCallback.hal | 54 +++++++++++++++ .../compatibility_matrix.current.xml | 2 +- current.txt | 2 + 9 files changed, 173 insertions(+), 13 deletions(-) create mode 100644 camera/provider/2.6/Android.bp create mode 100644 camera/provider/2.6/ICameraProvider.hal create mode 100644 camera/provider/2.6/ICameraProviderCallback.hal diff --git a/camera/provider/2.4/ICameraProvider.hal b/camera/provider/2.4/ICameraProvider.hal index 74c3ff1693..105629dec3 100644 --- a/camera/provider/2.4/ICameraProvider.hal +++ b/camera/provider/2.4/ICameraProvider.hal @@ -115,7 +115,7 @@ interface ICameraProvider { * INTERNAL_ERROR: * A camera ID list cannot be created. This may be due to * a failure to initialize the camera subsystem, for example. - * @return cameraDeviceServiceNames The vector of internal camera device + * @return cameraDeviceNames The vector of internal camera device * names known to this provider. */ getCameraIdList() diff --git a/camera/provider/2.4/ICameraProviderCallback.hal b/camera/provider/2.4/ICameraProviderCallback.hal index 63dd3c516f..8822305c3a 100644 --- a/camera/provider/2.4/ICameraProviderCallback.hal +++ b/camera/provider/2.4/ICameraProviderCallback.hal @@ -39,7 +39,7 @@ interface ICameraProviderCallback { * are already present, as soon as the callbacks are available through * setCallback. * - * @param cameraDeviceServiceName The name of the camera device that has a + * @param cameraDeviceName The name of the camera device that has a * new status. * @param newStatus The new status that device is in. * @@ -57,7 +57,7 @@ interface ICameraProviderCallback { * android.flash.info.available is reported as true via the * ICameraDevice::getCameraCharacteristics call. * - * @param cameraDeviceServiceName The name of the camera device that has a + * @param cameraDeviceName The name of the camera device that has a * new status. * @param newStatus The new status that device is in. * diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp index d14ccfaf2e..15f5c9ad4b 100644 --- a/camera/provider/2.4/vts/functional/Android.bp +++ b/camera/provider/2.4/vts/functional/Android.bp @@ -41,6 +41,7 @@ cc_test { "android.hardware.camera.metadata@3.4", "android.hardware.camera.provider@2.4", "android.hardware.camera.provider@2.5", + "android.hardware.camera.provider@2.6", "android.hardware.graphics.common@1.0", "android.hidl.allocator@1.0", "libgrallocusage", diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index c9f9bf6856..b4092ca211 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -40,15 +40,17 @@ #include #include #include +#include +#include #include #include #include #include #include +#include #include #include #include -#include #include #include #include @@ -537,7 +539,7 @@ public: uint32_t id; ASSERT_TRUE(parseProviderName(service_name, &mProviderType, &id)); - castProvider(mProvider, &mProvider2_5); + castProvider(mProvider, &mProvider2_5, &mProvider2_6); notifyDeviceState(provider::V2_5::DeviceState::NORMAL); } virtual void TearDown() override {} @@ -709,8 +711,9 @@ public: sp *session /*out*/, camera_metadata_t **staticMeta /*out*/, ::android::sp *device = nullptr/*out*/); - void castProvider(const sp &provider, - sp *provider2_5 /*out*/); + void castProvider(const sp& provider, + sp* provider2_5 /*out*/, + sp* provider2_6 /*out*/); void castSession(const sp &session, int32_t deviceVersion, sp *session3_3 /*out*/, sp *session3_4 /*out*/, @@ -937,6 +940,7 @@ protected: // Camera provider service sp mProvider; sp<::android::hardware::camera::provider::V2_5::ICameraProvider> mProvider2_5; + sp<::android::hardware::camera::provider::V2_6::ICameraProvider> mProvider2_6; // Camera provider type. std::string mProviderType; @@ -1649,6 +1653,33 @@ TEST_P(CameraHidlTest, setCallback) { return Void(); } }; + + struct ProviderCb2_6 + : public ::android::hardware::camera::provider::V2_6::ICameraProviderCallback { + virtual Return cameraDeviceStatusChange(const hidl_string& cameraDeviceName, + CameraDeviceStatus newStatus) override { + ALOGI("camera device status callback name %s, status %d", cameraDeviceName.c_str(), + (int)newStatus); + return Void(); + } + + virtual Return torchModeStatusChange(const hidl_string& cameraDeviceName, + TorchModeStatus newStatus) override { + ALOGI("Torch mode status callback name %s, status %d", cameraDeviceName.c_str(), + (int)newStatus); + return Void(); + } + + virtual Return physicalCameraDeviceStatusChange( + const hidl_string& cameraDeviceName, const hidl_string& physicalCameraDeviceName, + CameraDeviceStatus newStatus) override { + ALOGI("physical camera device status callback name %s, physical camera name %s," + " status %d", + cameraDeviceName.c_str(), physicalCameraDeviceName.c_str(), (int)newStatus); + return Void(); + } + }; + sp cb = new ProviderCb; auto status = mProvider->setCallback(cb); ASSERT_TRUE(status.isOk()); @@ -1656,6 +1687,16 @@ TEST_P(CameraHidlTest, setCallback) { status = mProvider->setCallback(nullptr); ASSERT_TRUE(status.isOk()); ASSERT_EQ(Status::OK, status); + + if (mProvider2_6.get() != nullptr) { + sp cb = new ProviderCb2_6; + auto status = mProvider2_6->setCallback(cb); + ASSERT_TRUE(status.isOk()); + ASSERT_EQ(Status::OK, status); + status = mProvider2_6->setCallback(nullptr); + ASSERT_TRUE(status.isOk()); + ASSERT_EQ(Status::OK, status); + } } // Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device @@ -5596,12 +5637,19 @@ void CameraHidlTest::castDevice(const sp &device, } //Cast camera provider to corresponding version if available -void CameraHidlTest::castProvider(const sp &provider, - sp *provider2_5 /*out*/) { +void CameraHidlTest::castProvider(const sp& provider, + sp* provider2_5 /*out*/, + sp* provider2_6 /*out*/) { ASSERT_NE(nullptr, provider2_5); - auto castResult = provider::V2_5::ICameraProvider::castFrom(provider); - if (castResult.isOk()) { - *provider2_5 = castResult; + auto castResult2_5 = provider::V2_5::ICameraProvider::castFrom(provider); + if (castResult2_5.isOk()) { + *provider2_5 = castResult2_5; + } + + ASSERT_NE(nullptr, provider2_6); + auto castResult2_6 = provider::V2_6::ICameraProvider::castFrom(provider); + if (castResult2_6.isOk()) { + *provider2_6 = castResult2_6; } } diff --git a/camera/provider/2.6/Android.bp b/camera/provider/2.6/Android.bp new file mode 100644 index 0000000000..16bd7927ac --- /dev/null +++ b/camera/provider/2.6/Android.bp @@ -0,0 +1,25 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.camera.provider@2.6", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "ICameraProvider.hal", + "ICameraProviderCallback.hal", + ], + interfaces: [ + "android.hardware.camera.common@1.0", + "android.hardware.camera.device@1.0", + "android.hardware.camera.device@3.2", + "android.hardware.camera.device@3.3", + "android.hardware.camera.device@3.4", + "android.hardware.camera.provider@2.4", + "android.hardware.camera.provider@2.5", + "android.hardware.graphics.common@1.0", + "android.hidl.base@1.0", + ], + gen_java: false, +} diff --git a/camera/provider/2.6/ICameraProvider.hal b/camera/provider/2.6/ICameraProvider.hal new file mode 100644 index 0000000000..60b59a3ae7 --- /dev/null +++ b/camera/provider/2.6/ICameraProvider.hal @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package android.hardware.camera.provider@2.6; + +import @2.5::ICameraProvider; + +/** + * Camera provider HAL + */ +interface ICameraProvider extends @2.5::ICameraProvider { + /** + * @2.4::ICameraProvider::setCallback can be passed a + * @2.6::ICameraProviderCallback to receive physical camera availability + * callbacks for logical multi-cameras. + */ +}; diff --git a/camera/provider/2.6/ICameraProviderCallback.hal b/camera/provider/2.6/ICameraProviderCallback.hal new file mode 100644 index 0000000000..42c1092676 --- /dev/null +++ b/camera/provider/2.6/ICameraProviderCallback.hal @@ -0,0 +1,54 @@ +/* + * 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. + */ + +package android.hardware.camera.provider@2.6; + +import android.hardware.camera.common@1.0::types; +import android.hardware.camera.provider@2.4::ICameraProviderCallback; + +/** + * Callback functions for a camera provider HAL to use to inform the camera + * service of changes to the camera subsystem. + * + * Version 2.6 adds support for physical camera device status callback for + * multi-camera. + */ +interface ICameraProviderCallback extends @2.4::ICameraProviderCallback { + + /** + * cameraPhysicalDeviceStatusChange: + * + * Callback to the camera service to indicate that the state of a physical + * camera device of a logical multi-camera has changed. + * + * On camera service startup, when ICameraProvider::setCallback is invoked, + * the camera service must assume that all physical devices backing internal + * multi-camera devices are in the CAMERA_DEVICE_STATUS_PRESENT state. + * + * The provider must call this method to inform the camera service of any + * initially NOT_PRESENT physical devices, as soon as the callbacks are available + * through setCallback. + * + * @param cameraDeviceName The name of the logical multi-camera whose + * physical camera has a new status. + * @param physicalCameraDeviceName The name of the physical camera device + * that has a new status. + * @param newStatus The new status that device is in. + * + */ + physicalCameraDeviceStatusChange(string cameraDeviceName, + string physicalCameraDeviceName, CameraDeviceStatus newStatus); +}; diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index da10ef8702..c10ca271f6 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -122,7 +122,7 @@ android.hardware.camera.provider - 2.4-5 + 2.4-6 ICameraProvider [^/]+/[0-9]+ diff --git a/current.txt b/current.txt index 441b3fd663..6d6ee489be 100644 --- a/current.txt +++ b/current.txt @@ -588,6 +588,8 @@ d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardwar cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types a05277065c28ebecd58118bd240fb8c55757361e8648c01f7c4dacdb7f2a95dc android.hardware.camera.metadata@3.3::types 9cb3df2bde2c6cd5fd96b7c41555420cacd7e276a556c684af91b7461c86460f android.hardware.gnss@1.0::IGnssCallback +bceee81ec1b59324abd05932b5620fda5a6589597c9cb3953ba7f3ea02cccd3e android.hardware.camera.provider@2.4::ICameraProvider +2ce820dc4f3c6d85721b65150ed2157c6e2e2055f866fb6c6ba4790f14408d66 android.hardware.camera.provider@2.4::ICameraProviderCallback b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel 8eac60e1f724d141c71c69f06d4544acb720a55dfbbcd97fa01bb3d25ee4e2f5 android.hardware.neuralnetworks@1.0::types From de0f476284b151e3606e20bea4361f4db31d5c7c Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 23 Jan 2020 11:19:25 -0800 Subject: [PATCH 0492/1022] graphics/common: fix typo Bug: 141632767 Test: Compiles Change-Id: I6a6fd7f808a896d78ca641cbb4cd8aea9ce63875 --- .../android/hardware/graphics/common/StandardMetadataType.aidl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl index 43cf6722dd..7b46688d9f 100644 --- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl +++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl @@ -280,7 +280,7 @@ enum StandardMetadataType { * * The default blend mode is INVALID. If the BlendMode is set to any * valid value other than INVALID, this BlendMode overrides all other - * dataspaces. For a longer description of this behavior see MetadataType::DATASPACE. + * blend modes. For a longer description of this behavior see MetadataType::DATASPACE. * * The blend mode is a stable aidl android.hardware.graphics.common.BlendMode. * From 46df8f5909280331b9ac0423b244869f116f54ad Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Thu, 12 Dec 2019 19:46:02 -0800 Subject: [PATCH 0493/1022] Grpc Vehicle Connectors Test: Build; test with ag/9869095 Bug: b/141493212 Change-Id: Ia4c0b0b5b358b1c67aae43d8c64f781b83725329 --- .../impl/vhal_v2_0/proto/VehicleServer.proto | 14 +- .../virtualization/GrpcVehicleClient.cpp | 162 +++++++++++++ .../virtualization/GrpcVehicleClient.h | 40 +++ .../virtualization/GrpcVehicleServer.cpp | 229 ++++++++++++++++++ .../virtualization/GrpcVehicleServer.h | 49 ++++ 5 files changed, 492 insertions(+), 2 deletions(-) create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto index 2cc6595248..6f71d654a7 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto @@ -35,13 +35,23 @@ message VehicleHalCallStatus { VehicleHalStatusCode status_code = 1; } +message WrappedVehiclePropValue { + VehiclePropValue value = 1; + // An indicator on whether we should update the status of the property + // - true: if the value is generated by (emulated/real) car, or; + // if the value is injected to 'fake' a on car event (for debugging purpose) + // - false: if the value is set by VHal (public interface), since Android + // cannot change status of property on a real car + bool update_status = 2; +} + service VehicleServer { rpc GetAllPropertyConfig(google.protobuf.Empty) returns (stream VehiclePropConfig) {} // Change the property value of the vehicle - rpc SetProperty(VehiclePropValue) returns (VehicleHalCallStatus) {} + rpc SetProperty(WrappedVehiclePropValue) returns (VehicleHalCallStatus) {} // Start a vehicle property value stream - rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream VehiclePropValue) {} + rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream WrappedVehiclePropValue) {} } diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp new file mode 100644 index 0000000000..e329c5be01 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp @@ -0,0 +1,162 @@ +/* + * 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. + */ +#include "GrpcVehicleClient.h" + +#include +#include + +#include +#include + +#include "VehicleServer.grpc.pb.h" +#include "VehicleServer.pb.h" +#include "vhal_v2_0/ProtoMessageConverter.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +static std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() { + // TODO(chenhaosjtuacm): get secured credentials here + return ::grpc::InsecureChannelCredentials(); +} + +class GrpcVehicleClientImpl : public EmulatedVehicleClient { + public: + GrpcVehicleClientImpl(const std::string& addr) + : mServiceAddr(addr), + mGrpcChannel(::grpc::CreateChannel(mServiceAddr, getChannelCredentials())), + mGrpcStub(vhal_proto::VehicleServer::NewStub(mGrpcChannel)) { + StartValuePollingThread(); + } + + ~GrpcVehicleClientImpl() { + mShuttingDownFlag.store(true); + mShutdownCV.notify_all(); + if (mPollingThread.joinable()) { + mPollingThread.join(); + } + } + + // methods from IVehicleClient + + std::vector getAllPropertyConfig() const override; + + StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) override; + + private: + void StartValuePollingThread(); + + // private data members + + std::string mServiceAddr; + std::shared_ptr<::grpc::Channel> mGrpcChannel; + std::unique_ptr mGrpcStub; + std::thread mPollingThread; + + std::mutex mShutdownMutex; + std::condition_variable mShutdownCV; + std::atomic mShuttingDownFlag{false}; +}; + +std::unique_ptr makeGrpcVehicleClient(const std::string& addr) { + return std::make_unique(addr); +} + +std::vector GrpcVehicleClientImpl::getAllPropertyConfig() const { + std::vector configs; + ::grpc::ClientContext context; + auto config_stream = mGrpcStub->GetAllPropertyConfig(&context, ::google::protobuf::Empty()); + vhal_proto::VehiclePropConfig protoConfig; + while (config_stream->Read(&protoConfig)) { + VehiclePropConfig config; + proto_msg_converter::fromProto(&config, protoConfig); + configs.emplace_back(std::move(config)); + } + auto grpc_status = config_stream->Finish(); + if (!grpc_status.ok()) { + LOG(ERROR) << __func__ + << ": GRPC GetAllPropertyConfig Failed: " << grpc_status.error_message(); + configs.clear(); + } + + return configs; +} + +StatusCode GrpcVehicleClientImpl::setProperty(const VehiclePropValue& value, bool updateStatus) { + ::grpc::ClientContext context; + vhal_proto::WrappedVehiclePropValue wrappedProtoValue; + vhal_proto::VehicleHalCallStatus vhal_status; + proto_msg_converter::toProto(wrappedProtoValue.mutable_value(), value); + wrappedProtoValue.set_update_status(updateStatus); + + auto grpc_status = mGrpcStub->SetProperty(&context, wrappedProtoValue, &vhal_status); + if (!grpc_status.ok()) { + LOG(ERROR) << __func__ << ": GRPC SetProperty Failed: " << grpc_status.error_message(); + return StatusCode::INTERNAL_ERROR; + } + + return static_cast(vhal_status.status_code()); +} + +void GrpcVehicleClientImpl::StartValuePollingThread() { + mPollingThread = std::thread([this]() { + while (!mShuttingDownFlag.load()) { + ::grpc::ClientContext context; + + std::atomic rpc_ok{true}; + std::thread shuttingdown_watcher([this, &rpc_ok, &context]() { + std::unique_lock shutdownLock(mShutdownMutex); + mShutdownCV.wait(shutdownLock, [this, &rpc_ok]() { + return !rpc_ok.load() || mShuttingDownFlag.load(); + }); + context.TryCancel(); + }); + + auto value_stream = + mGrpcStub->StartPropertyValuesStream(&context, ::google::protobuf::Empty()); + vhal_proto::WrappedVehiclePropValue wrappedProtoValue; + while (!mShuttingDownFlag.load() && value_stream->Read(&wrappedProtoValue)) { + VehiclePropValue value; + proto_msg_converter::fromProto(&value, wrappedProtoValue.value()); + onPropertyValue(value, wrappedProtoValue.update_status()); + } + + rpc_ok.store(false); + mShutdownCV.notify_all(); + shuttingdown_watcher.join(); + + auto grpc_status = value_stream->Finish(); + // never reach here until connection lost + LOG(ERROR) << __func__ + << ": GRPC Value Streaming Failed: " << grpc_status.error_message(); + + // try to reconnect + } + }); +} + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h new file mode 100644 index 0000000000..14eae7f057 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleClient_H_ +#define android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleClient_H_ + +#include "vhal_v2_0/EmulatedVehicleConnector.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +std::unique_ptr makeGrpcVehicleClient(const std::string& addr); + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleClient_H_ diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp new file mode 100644 index 0000000000..e30b3bec54 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp @@ -0,0 +1,229 @@ +/* + * 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. + */ +#include "GrpcVehicleServer.h" + +#include +#include +#include + +#include +#include + +#include "VehicleServer.grpc.pb.h" +#include "VehicleServer.pb.h" +#include "vhal_v2_0/ProtoMessageConverter.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +class GrpcVehicleServerImpl : public GrpcVehicleServer, public vhal_proto::VehicleServer::Service { + public: + GrpcVehicleServerImpl(const std::string& addr) : mServiceAddr(addr) { + setValuePool(&mValueObjectPool); + } + + // method from GrpcVehicleServer + void Start() override; + + // method from IVehicleServer + void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) override; + + // methods from vhal_proto::VehicleServer::Service + + ::grpc::Status GetAllPropertyConfig( + ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, + ::grpc::ServerWriter* stream) override; + + ::grpc::Status SetProperty(::grpc::ServerContext* context, + const vhal_proto::WrappedVehiclePropValue* wrappedPropValue, + vhal_proto::VehicleHalCallStatus* status) override; + + ::grpc::Status StartPropertyValuesStream( + ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, + ::grpc::ServerWriter* stream) override; + + private: + // We keep long-lasting connection for streaming the prop values. + // For us, each connection can be represented as a function to send the new value, and + // an ID to identify this connection + struct ConnectionDescriptor { + using ValueWriterType = std::function; + + ConnectionDescriptor(ValueWriterType&& value_writer) + : mValueWriter(std::move(value_writer)), + mConnectionID(CONNECTION_ID_COUNTER.fetch_add(1)) {} + + ConnectionDescriptor(const ConnectionDescriptor&) = delete; + + ConnectionDescriptor& operator=(const ConnectionDescriptor&) = delete; + + // This move constructor is NOT THREAD-SAFE, which means it cannot be moved + // while using. Since the connection descriptors are pretected by mConnectionMutex + // then we are fine here + ConnectionDescriptor(ConnectionDescriptor&& cd) + : mValueWriter(std::move(cd.mValueWriter)), + mConnectionID(cd.mConnectionID), + mIsAlive(cd.mIsAlive.load()) { + cd.mIsAlive.store(false); + } + + ValueWriterType mValueWriter; + uint64_t mConnectionID; + std::atomic mIsAlive{true}; + + static std::atomic CONNECTION_ID_COUNTER; + }; + + std::string mServiceAddr; + VehiclePropValuePool mValueObjectPool; + mutable std::shared_mutex mConnectionMutex; + mutable std::shared_mutex mWriterMutex; + std::list mValueStreamingConnections; +}; + +std::atomic GrpcVehicleServerImpl::ConnectionDescriptor::CONNECTION_ID_COUNTER = 0; + +static std::shared_ptr<::grpc::ServerCredentials> getServerCredentials() { + // TODO(chenhaosjtuacm): get secured credentials here + return ::grpc::InsecureServerCredentials(); +} + +GrpcVehicleServerPtr makeGrpcVehicleServer(const std::string& addr) { + return std::make_unique(addr); +} + +void GrpcVehicleServerImpl::Start() { + ::grpc::ServerBuilder builder; + builder.RegisterService(this); + builder.AddListeningPort(mServiceAddr, getServerCredentials()); + std::unique_ptr<::grpc::Server> server(builder.BuildAndStart()); + + server->Wait(); +} + +void GrpcVehicleServerImpl::onPropertyValueFromCar(const VehiclePropValue& value, + bool updateStatus) { + vhal_proto::WrappedVehiclePropValue wrappedPropValue; + proto_msg_converter::toProto(wrappedPropValue.mutable_value(), value); + wrappedPropValue.set_update_status(updateStatus); + std::shared_lock read_lock(mConnectionMutex); + + bool has_terminated_connections = 0; + + for (auto& connection : mValueStreamingConnections) { + auto writeOK = connection.mValueWriter(wrappedPropValue); + if (!writeOK) { + LOG(ERROR) << __func__ << ": Server Write failed, connection lost. ID: " + << connection.mConnectionID; + has_terminated_connections = true; + connection.mIsAlive.store(false); + } + } + + if (!has_terminated_connections) { + return; + } + + read_lock.unlock(); + + std::unique_lock write_lock(mConnectionMutex); + + for (auto itr = mValueStreamingConnections.begin(); itr != mValueStreamingConnections.end();) { + if (!itr->mIsAlive.load()) { + itr = mValueStreamingConnections.erase(itr); + } else { + ++itr; + } + } +} + +::grpc::Status GrpcVehicleServerImpl::GetAllPropertyConfig( + ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, + ::grpc::ServerWriter* stream) { + auto configs = onGetAllPropertyConfig(); + for (auto& config : configs) { + vhal_proto::VehiclePropConfig protoConfig; + proto_msg_converter::toProto(&protoConfig, config); + if (!stream->Write(protoConfig)) { + return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost."); + } + } + + return ::grpc::Status::OK; +} + +::grpc::Status GrpcVehicleServerImpl::SetProperty( + ::grpc::ServerContext* context, const vhal_proto::WrappedVehiclePropValue* wrappedPropValue, + vhal_proto::VehicleHalCallStatus* status) { + VehiclePropValue value; + proto_msg_converter::fromProto(&value, wrappedPropValue->value()); + + auto set_status = static_cast(onSetProperty(value, wrappedPropValue->update_status())); + if (!vhal_proto::VehicleHalStatusCode_IsValid(set_status)) { + return ::grpc::Status(::grpc::StatusCode::INTERNAL, "Unknown status code"); + } + + status->set_status_code(static_cast(set_status)); + + return ::grpc::Status::OK; +} + +::grpc::Status GrpcVehicleServerImpl::StartPropertyValuesStream( + ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, + ::grpc::ServerWriter* stream) { + std::mutex terminateMutex; + std::condition_variable terminateCV; + std::unique_lock terminateLock(terminateMutex); + bool terminated{false}; + + auto callBack = [stream, &terminateMutex, &terminateCV, &terminated, + this](const vhal_proto::WrappedVehiclePropValue& value) { + std::unique_lock lock(mWriterMutex); + if (!stream->Write(value)) { + std::unique_lock terminateLock(terminateMutex); + terminated = true; + terminateLock.unlock(); + terminateCV.notify_all(); + return false; + } + return true; + }; + + // Register connection + std::unique_lock lock(mConnectionMutex); + auto& conn = mValueStreamingConnections.emplace_back(std::move(callBack)); + lock.unlock(); + + // Never stop until connection lost + terminateCV.wait(terminateLock, [&terminated]() { return terminated; }); + + LOG(ERROR) << __func__ << ": Stream lost, ID : " << conn.mConnectionID; + + return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost."); +} + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h new file mode 100644 index 0000000000..32f4eb203a --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleServer_H_ +#define android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleServer_H_ + +#include "vhal_v2_0/EmulatedVehicleConnector.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +// Connect to the Vehicle Client via GRPC +class GrpcVehicleServer : public EmulatedVehicleServer { + public: + // Start listening incoming calls, should never return if working normally + virtual void Start() = 0; +}; + +using GrpcVehicleServerPtr = std::unique_ptr; + +GrpcVehicleServerPtr makeGrpcVehicleServer(const std::string& addr); + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleServer_H_ From 5a97c389e95d24a15828aee1032e6eb59a285b56 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Thu, 5 Dec 2019 15:53:05 -0800 Subject: [PATCH 0494/1022] Apply Grpc Client to current VHal Implementation Test: tested on Cuttlefish VM - Use virtualization HAL implementation, device/google/cuttlefish/shared/auto/device.mk, PRODUCT_PACKAGES: remove android.hardware.automotive.vehicle@2.0-service add: android.hardware.automotive.vehicle@2.0-virtualization-service android.hardware.automotive.vehicle@2.0-virtualization-grpc-server - configure the server CID and port, add the following device/google/cuttlefish/shared/config/init.vendor.rc: setprop ro.vendor.vehiclehal.server.cid 3 setprop ro.vendor.vehiclehal.server.port 9210 - Build and Launch cuttlefish VM m && acloud create --boot-timeout 3600 -vv --local-instance --local-image - VHAL should work as normal, see tests in ag/9693857 Bug: b/141493212 Change-Id: I97df02dd26b89f60d3d87b2c32c4f4f8919b1294 --- automotive/vehicle/2.0/default/Android.bp | 70 ++++++++++++++++++ .../2.0/default/VirtualizationGrpcServer.cpp | 49 ++++++++++++ .../2.0/default/VirtualizedVehicleService.cpp | 74 +++++++++++++++++++ ....vehicle@2.0-virtualization-grpc-server.rc | 10 +++ ...tive.vehicle@2.0-virtualization-service.rc | 4 + .../impl/vhal_v2_0/virtualization/Utils.cpp | 39 ++++++++++ .../impl/vhal_v2_0/virtualization/Utils.h | 43 +++++++++++ 7 files changed, 289 insertions(+) create mode 100644 automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp create mode 100644 automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp create mode 100644 automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc create mode 100644 automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp index 2050038d62..a94a37e0f1 100644 --- a/automotive/vehicle/2.0/default/Android.bp +++ b/automotive/vehicle/2.0/default/Android.bp @@ -82,6 +82,20 @@ cc_library_static { ], } +// VHal virtualization utils +cc_library_static { + name: "android.hardware.automotive.vehicle@2.0-virtualization-utils", + vendor: true, + defaults: ["vhal_v2_0_defaults"], + srcs: [ + "impl/vhal_v2_0/virtualization/Utils.cpp", + ], + export_include_dirs: ["impl"], + shared_libs: [ + "libbase", + ], +} + cc_test { name: "android.hardware.automotive.vehicle@2.0-manager-unit-tests", vendor: true, @@ -133,3 +147,59 @@ cc_binary { "libqemu_pipe", ], } + +cc_binary { + name: "android.hardware.automotive.vehicle@2.0-virtualization-service", + defaults: ["vhal_v2_0_defaults"], + init_rc: ["android.hardware.automotive.vehicle@2.0-virtualization-service.rc"], + vendor: true, + relative_install_path: "hw", + srcs: [ + "impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp", + "VirtualizedVehicleService.cpp", + ], + shared_libs: [ + "libbase", + "libcutils", + "libjsoncpp", + "libprotobuf-cpp-full", + "libgrpc++", + ], + static_libs: [ + "android.hardware.automotive.vehicle@2.0-manager-lib", + "android.hardware.automotive.vehicle@2.0-default-impl-lib", + "android.hardware.automotive.vehicle@2.0-grpc", + "android.hardware.automotive.vehicle@2.0-virtualization-utils", + "libqemu_pipe", + ], + cflags: [ + "-Wno-unused-parameter" + ], +} + +cc_binary { + name: "android.hardware.automotive.vehicle@2.0-virtualization-grpc-server", + init_rc: ["android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc"], + defaults: ["vhal_v2_0_defaults"], + vendor: true, + relative_install_path: "hw", + srcs: [ + "impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp", + "VirtualizationGrpcServer.cpp", + ], + shared_libs: [ + "libbase", + "libjsoncpp", + "libprotobuf-cpp-full", + "libgrpc++", + ], + static_libs: [ + "android.hardware.automotive.vehicle@2.0-manager-lib", + "android.hardware.automotive.vehicle@2.0-default-impl-lib", + "android.hardware.automotive.vehicle@2.0-grpc", + "android.hardware.automotive.vehicle@2.0-virtualization-utils", + ], + cflags: [ + "-Wno-unused-parameter" + ], +} diff --git a/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp b/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp new file mode 100644 index 0000000000..cca65d9f76 --- /dev/null +++ b/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp @@ -0,0 +1,49 @@ +#include +#include +#include + +#include "vhal_v2_0/virtualization/GrpcVehicleServer.h" +#include "vhal_v2_0/virtualization/Utils.h" + +int main(int argc, char* argv[]) { + namespace vhal_impl = android::hardware::automotive::vehicle::V2_0::impl; + + vhal_impl::VsockServerInfo serverInfo; + + // unique values to identify the options + constexpr int OPT_VHAL_SERVER_CID = 1001; + constexpr int OPT_VHAL_SERVER_PORT_NUMBER = 1002; + + struct option longOptions[] = { + {"server_cid", 1, 0, OPT_VHAL_SERVER_CID}, + {"server_port", 1, 0, OPT_VHAL_SERVER_PORT_NUMBER}, + {nullptr, 0, nullptr, 0}, + }; + + int optValue; + while ((optValue = getopt_long_only(argc, argv, ":", longOptions, 0)) != -1) { + switch (optValue) { + case OPT_VHAL_SERVER_CID: + serverInfo.serverCid = std::atoi(optarg); + LOG(DEBUG) << "Vehicle HAL server CID: " << serverInfo.serverCid; + break; + case OPT_VHAL_SERVER_PORT_NUMBER: + serverInfo.serverPort = std::atoi(optarg); + LOG(DEBUG) << "Vehicle HAL server port: " << serverInfo.serverPort; + break; + default: + // ignore other options + break; + } + } + + if (serverInfo.serverCid == 0 || serverInfo.serverPort == 0) { + LOG(FATAL) << "Invalid server information, CID: " << serverInfo.serverCid + << "; port: " << serverInfo.serverPort; + // Will abort after logging + } + + auto server = vhal_impl::makeGrpcVehicleServer(vhal_impl::getVsockUri(serverInfo)); + server->Start(); + return 0; +} diff --git a/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp b/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp new file mode 100644 index 0000000000..1de81ae844 --- /dev/null +++ b/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp @@ -0,0 +1,74 @@ +/* + * 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. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace android; +using namespace android::hardware; +using namespace android::hardware::automotive::vehicle::V2_0; + +int main(int argc, char* argv[]) { + constexpr const char* VHAL_SERVER_CID_PROPERTY_KEY = "ro.vendor.vehiclehal.server.cid"; + constexpr const char* VHAL_SERVER_PORT_PROPERTY_KEY = "ro.vendor.vehiclehal.server.port"; + + auto property_get_uint = [](const char* key, unsigned int default_value) { + auto value = property_get_int64(key, default_value); + if (value < 0 || value > UINT_MAX) { + LOG(DEBUG) << key << ": " << value << " is out of bound, using default value '" + << default_value << "' instead"; + return default_value; + } + return static_cast(value); + }; + + impl::VsockServerInfo serverInfo{property_get_uint(VHAL_SERVER_CID_PROPERTY_KEY, 0), + property_get_uint(VHAL_SERVER_PORT_PROPERTY_KEY, 0)}; + + if (serverInfo.serverCid == 0 || serverInfo.serverPort == 0) { + LOG(FATAL) << "Invalid server information, CID: " << serverInfo.serverCid + << "; port: " << serverInfo.serverPort; + // Will abort after logging + } + + auto store = std::make_unique(); + auto connector = impl::makeGrpcVehicleClient(impl::getVsockUri(serverInfo)); + auto hal = std::make_unique(store.get(), connector.get()); + auto emulator = std::make_unique(hal.get()); + auto service = std::make_unique(hal.get()); + + configureRpcThreadpool(4, true /* callerWillJoin */); + + LOG(INFO) << "Registering as service..."; + status_t status = service->registerAsService(); + + if (status != OK) { + LOG(ERROR) << "Unable to register vehicle service (" << status << ")"; + return 1; + } + + LOG(INFO) << "Ready"; + joinRpcThreadpool(); + + return 1; +} diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc new file mode 100644 index 0000000000..29147ad6e3 --- /dev/null +++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc @@ -0,0 +1,10 @@ +# It is an interim state to run GRPC server as an Android service. +# Eventually it will run outside of Android (e.g., AGL), +# so the command line arguments are expected, though not conventionally used in Android +service vendor.vehicle-hal-2.0-server \ + /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server \ + -server_cid ${ro.vendor.vehiclehal.server.cid:-0} \ + -server_port ${ro.vendor.vehiclehal.server.port:-0} + class hal + user vehicle_network + group system inet diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc new file mode 100644 index 0000000000..234de591cc --- /dev/null +++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc @@ -0,0 +1,4 @@ +service vendor.vehicle-hal-2.0 /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-virtualization-service + class hal + user vehicle_network + group system inet diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp new file mode 100644 index 0000000000..41d4827621 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#include "Utils.h" + +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { +namespace impl { + +std::string getVsockUri(const VsockServerInfo& serverInfo) { + std::stringstream uri_stream; + uri_stream << "vsock:" << serverInfo.serverCid << ":" << serverInfo.serverPort; + return uri_stream.str(); +} + +} // namespace impl +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h new file mode 100644 index 0000000000..6b1049c42b --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h @@ -0,0 +1,43 @@ +/* + * 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_ +#define android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_ + +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { +namespace impl { + +struct VsockServerInfo { + unsigned int serverCid{0}; + unsigned int serverPort{0}; +}; + +std::string getVsockUri(const VsockServerInfo& serverInfo); + +} // namespace impl +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_ From f2747e04efdc079cc9f91f42b87ab2267bc0d814 Mon Sep 17 00:00:00 2001 From: Kumar Anand Date: Fri, 10 Jan 2020 16:49:13 -0800 Subject: [PATCH 0495/1022] wifi: thermal hal api Use global handle instead of interface handle as thermal mitigation is not interface specific. Bug: 112471991 Test: atest FrameworksWifiTests Change-Id: Ia8aadec7794bd2dbd5954ec0225caa349b31070c --- wifi/1.4/default/wifi_legacy_hal.cpp | 7 +++---- wifi/1.4/default/wifi_legacy_hal.h | 3 +-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp index 6f088d73e3..3ca3226bd9 100644 --- a/wifi/1.4/default/wifi_legacy_hal.cpp +++ b/wifi/1.4/default/wifi_legacy_hal.cpp @@ -824,11 +824,10 @@ wifi_error WifiLegacyHal::setLatencyMode(const std::string& iface_name, mode); } -wifi_error WifiLegacyHal::setThermalMitigationMode( - const std::string& iface_name, wifi_thermal_mode mode, - uint32_t completion_window) { +wifi_error WifiLegacyHal::setThermalMitigationMode(wifi_thermal_mode mode, + uint32_t completion_window) { return global_func_table_.wifi_set_thermal_mitigation_mode( - getIfaceHandle(iface_name), mode, completion_window); + global_handle_, mode, completion_window); } std::pair WifiLegacyHal::getLoggerSupportedFeatureSet( diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h index 74cc84be30..a7b40a05cc 100644 --- a/wifi/1.4/default/wifi_legacy_hal.h +++ b/wifi/1.4/default/wifi_legacy_hal.h @@ -259,8 +259,7 @@ class WifiLegacyHal { virtual wifi_error resetTxPowerScenario(const std::string& iface_name); wifi_error setLatencyMode(const std::string& iface_name, wifi_latency_mode mode); - wifi_error setThermalMitigationMode(const std::string& iface_name, - wifi_thermal_mode mode, + wifi_error setThermalMitigationMode(wifi_thermal_mode mode, uint32_t completion_window); // Logger/debug functions. std::pair getLoggerSupportedFeatureSet( From 31eea85fafd9fd91870c553369e30cb1c19caa27 Mon Sep 17 00:00:00 2001 From: Sasha Kuznetsov Date: Fri, 3 Jan 2020 13:06:38 -0800 Subject: [PATCH 0496/1022] Create measurement corrections 1.1 with eBearing Test: matest VtsHalGnssV2_1TargetTesti and manually injected dummy measurement corrections in GnssLocationProvider and verified that cuttlefish implementation properly recieved them below the HAL Bug: 145963440 Change-Id: Ib5eb4f8c759c91b9fa2217ce6658319edd11bb27 --- current.txt | 4 +- gnss/1.1/vts/functional/Android.bp | 6 +- .../vts/functional/gnss_hal_test_cases.cpp | 6 ++ gnss/2.1/Android.bp | 1 + gnss/2.1/IGnss.hal | 11 ++++ gnss/2.1/default/Android.bp | 1 + gnss/2.1/default/Gnss.cpp | 8 ++- gnss/2.1/default/Gnss.h | 2 + .../default/GnssMeasurementCorrections.cpp | 39 ++++++++++++- gnss/2.1/default/GnssMeasurementCorrections.h | 11 ++-- gnss/2.1/vts/functional/Android.bp | 6 +- gnss/2.1/vts/functional/gnss_hal_test.cpp | 7 +++ gnss/2.1/vts/functional/gnss_hal_test.h | 14 +++++ .../vts/functional/gnss_hal_test_cases.cpp | 34 +++++++++++ gnss/common/utils/vts/Android.bp | 1 + gnss/common/utils/vts/Utils.cpp | 16 ++++- gnss/common/utils/vts/include/Utils.h | 9 ++- gnss/measurement_corrections/1.1/Android.bp | 19 ++++++ .../1.1/IMeasurementCorrections.hal | 40 +++++++++++++ gnss/measurement_corrections/1.1/types.hal | 58 +++++++++++++++++++ 20 files changed, 279 insertions(+), 14 deletions(-) create mode 100644 gnss/measurement_corrections/1.1/Android.bp create mode 100644 gnss/measurement_corrections/1.1/IMeasurementCorrections.hal create mode 100644 gnss/measurement_corrections/1.1/types.hal diff --git a/current.txt b/current.txt index d9e1a76693..0575c65cbd 100644 --- a/current.txt +++ b/current.txt @@ -639,11 +639,13 @@ f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardwar 881aa8720fb1d69aa9843bfab69d810ab7654a61d2f5ab5e2626cbf240f24eaf android.hardware.dumpstate@1.1::types 13b33f623521ded51a6c0f7ea5b77e97066d0aa1e38a83c2873f08ad67294f89 android.hardware.dumpstate@1.1::IDumpstateDevice 769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types -3dacec7801968e1e4479724dc0180442d9e915466bff051f80996266b1a51c2c android.hardware.gnss@2.1::IGnss +88371e0edf69a1f72bfc45ecb2335e9b145e87339d3eecc92664a1fb200213ba android.hardware.gnss@2.1::IGnss ba62e1e8993bfb9f27fa04816fa0f2241ae2d01edfa3d0c04182e2e5de80045c android.hardware.gnss@2.1::IGnssCallback ccdf3c0fb2c02a6d4dc57afb276c3497ae8172b80b00ebc0bf8a0238dd38b01d android.hardware.gnss@2.1::IGnssConfiguration 5a125c49ca83629e22afc8c39e865509343bfa2c38f0baea9a186bbac103492d android.hardware.gnss@2.1::IGnssMeasurement d7bf37660a0946de9599dcbae997b077ee3e604fc2044534d40d3da04297a5d3 android.hardware.gnss@2.1::IGnssMeasurementCallback +6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections +a3f439b782a6a92aaf3c0250f3526e94e8bf8844c3d578f0815e21b12c431346 android.hardware.gnss.measurement_corrections@1.1::types ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp index bdd02d2e6e..369a89da39 100644 --- a/gnss/1.1/vts/functional/Android.bp +++ b/gnss/1.1/vts/functional/Android.bp @@ -29,6 +29,10 @@ cc_test { ], shared_libs: [ "android.hardware.gnss.measurement_corrections@1.0", + "android.hardware.gnss.measurement_corrections@1.1", + ], + test_suites: [ + "general-tests", + "vts-core", ], - test_suites: ["general-tests", "vts-core"], } 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 0fa08b903e..53f5b9e283 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp @@ -296,6 +296,12 @@ TEST_P(GnssHalTest, TestGnssVisibilityControlExtension) { * capability flag is set. */ TEST_P(GnssHalTest, TestGnssMeasurementCorrectionsCapabilities) { + if (!IsGnssHalVersion_2_0()) { + ALOGI("Test GnssMeasurementCorrectionsCapabilities skipped. GNSS HAL version is greater " + "than 2.0."); + return; + } + if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) { return; } diff --git a/gnss/2.1/Android.bp b/gnss/2.1/Android.bp index c615f1da23..7efc4a60aa 100644 --- a/gnss/2.1/Android.bp +++ b/gnss/2.1/Android.bp @@ -15,6 +15,7 @@ hidl_interface { "IGnssConfiguration.hal", ], interfaces: [ + "android.hardware.gnss.measurement_corrections@1.1", "android.hardware.gnss.measurement_corrections@1.0", "android.hardware.gnss.visibility_control@1.0", "android.hardware.gnss@1.0", diff --git a/gnss/2.1/IGnss.hal b/gnss/2.1/IGnss.hal index 2d633928dd..ce37647868 100644 --- a/gnss/2.1/IGnss.hal +++ b/gnss/2.1/IGnss.hal @@ -16,6 +16,7 @@ package android.hardware.gnss@2.1; +import android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections; import @2.0::IGnss; import IGnssCallback; @@ -62,4 +63,14 @@ interface IGnss extends @2.0::IGnss { * @return gnssConfigurationIface Handle to the IGnssConfiguration interface. */ getExtensionGnssConfiguration_2_1() generates (IGnssConfiguration gnssConfigurationIface); + + /** + * This method returns the IMeasurementCorrections interface. + * + * Both getExtensionMeasurementCorrections and getExtensionMeasurementCorrections_1_1 must + * return non-null. Both methods can return the same V1.1 IMeasurementCorrections object. + * + * @return measurementCorrectionsIface Handle to the IMeasurementCorrections interface. + */ + getExtensionMeasurementCorrections_1_1() generates (IMeasurementCorrections measurementCorrectionsIface); }; \ No newline at end of file diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp index 834847e91e..1f1078e398 100644 --- a/gnss/2.1/default/Android.bp +++ b/gnss/2.1/default/Android.bp @@ -32,6 +32,7 @@ cc_binary { "libhidlbase", "libutils", "liblog", + "android.hardware.gnss.measurement_corrections@1.1", "android.hardware.gnss.measurement_corrections@1.0", "android.hardware.gnss.visibility_control@1.0", "android.hardware.gnss@2.1", diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp index 7db86897f9..679eb35804 100644 --- a/gnss/2.1/default/Gnss.cpp +++ b/gnss/2.1/default/Gnss.cpp @@ -25,7 +25,7 @@ #include using ::android::hardware::gnss::common::Utils; -using ::android::hardware::gnss::measurement_corrections::V1_0::implementation:: +using ::android::hardware::gnss::measurement_corrections::V1_1::implementation:: GnssMeasurementCorrections; namespace android { @@ -368,6 +368,12 @@ Return> Gnss::getExtensionGnssConfiguration_2_1() { return mGnssConfiguration; } +Return> +Gnss::getExtensionMeasurementCorrections_1_1() { + ALOGD("Gnss::getExtensionMeasurementCorrections_1_1()"); + return new GnssMeasurementCorrections(); +} + void Gnss::reportSvStatus(const hidl_vec& svInfoList) const { std::unique_lock lock(mMutex); // TODO(skz): update this to call 2_0 callback if non-null diff --git a/gnss/2.1/default/Gnss.h b/gnss/2.1/default/Gnss.h index 7a2a2c953a..c47206a7a4 100644 --- a/gnss/2.1/default/Gnss.h +++ b/gnss/2.1/default/Gnss.h @@ -89,6 +89,8 @@ struct Gnss : public IGnss { Return setCallback_2_1(const sp& callback) override; Return> getExtensionGnssMeasurement_2_1() override; Return> getExtensionGnssConfiguration_2_1() override; + Return> + getExtensionMeasurementCorrections_1_1() override; private: void reportLocation(const V2_0::GnssLocation&) const; diff --git a/gnss/2.1/default/GnssMeasurementCorrections.cpp b/gnss/2.1/default/GnssMeasurementCorrections.cpp index 2bf5601820..9dedbf6747 100644 --- a/gnss/2.1/default/GnssMeasurementCorrections.cpp +++ b/gnss/2.1/default/GnssMeasurementCorrections.cpp @@ -23,11 +23,12 @@ namespace android { namespace hardware { namespace gnss { namespace measurement_corrections { -namespace V1_0 { +namespace V1_1 { namespace implementation { // Methods from V1_0::IMeasurementCorrections follow. -Return GnssMeasurementCorrections::setCorrections(const MeasurementCorrections& corrections) { +Return GnssMeasurementCorrections::setCorrections( + const V1_0::MeasurementCorrections& corrections) { ALOGD("setCorrections"); ALOGD("corrections = lat: %f, lng: %f, alt: %f, hUnc: %f, vUnc: %f, toa: %llu, " "satCorrections.size: %d", @@ -67,8 +68,40 @@ Return GnssMeasurementCorrections::setCallback( return true; } +// Methods from V1_1::IMeasurementCorrections follow. +Return GnssMeasurementCorrections::setCorrections_1_1( + const V1_1::MeasurementCorrections& corrections) { + ALOGD("setCorrections_1_1"); + ALOGD("corrections = lat: %f, lng: %f, alt: %f, hUnc: %f, vUnc: %f, toa: %llu," + "satCorrections.size: %d, hasEnvironmentBearing: %d, environmentBearingDeg: %f," + "environmentBearingUncDeg: %f", + corrections.v1_0.latitudeDegrees, corrections.v1_0.longitudeDegrees, + corrections.v1_0.altitudeMeters, corrections.v1_0.horizontalPositionUncertaintyMeters, + corrections.v1_0.verticalPositionUncertaintyMeters, + static_cast(corrections.v1_0.toaGpsNanosecondsOfWeek), + static_cast(corrections.v1_0.satCorrections.size()), + corrections.hasEnvironmentBearing, corrections.environmentBearingDegrees, + corrections.environmentBearingUncertaintyDegrees); + for (auto singleSatCorrection : corrections.v1_0.satCorrections) { + ALOGD("singleSatCorrection = flags: %d, constellation: %d, svid: %d, cfHz: %f, probLos: %f," + " epl: %f, eplUnc: %f", + static_cast(singleSatCorrection.singleSatCorrectionFlags), + static_cast(singleSatCorrection.constellation), + static_cast(singleSatCorrection.svid), singleSatCorrection.carrierFrequencyHz, + singleSatCorrection.probSatIsLos, singleSatCorrection.excessPathLengthMeters, + singleSatCorrection.excessPathLengthUncertaintyMeters); + ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f", + singleSatCorrection.reflectingPlane.latitudeDegrees, + singleSatCorrection.reflectingPlane.longitudeDegrees, + singleSatCorrection.reflectingPlane.altitudeMeters, + singleSatCorrection.reflectingPlane.azimuthDegrees); + } + + return true; +} + } // namespace implementation -} // namespace V1_0 +} // namespace V1_1 } // namespace measurement_corrections } // namespace gnss } // namespace hardware diff --git a/gnss/2.1/default/GnssMeasurementCorrections.h b/gnss/2.1/default/GnssMeasurementCorrections.h index 4339bed55d..036e855586 100644 --- a/gnss/2.1/default/GnssMeasurementCorrections.h +++ b/gnss/2.1/default/GnssMeasurementCorrections.h @@ -16,7 +16,7 @@ #pragma once -#include +#include #include #include @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace gnss { namespace measurement_corrections { -namespace V1_0 { +namespace V1_1 { namespace implementation { using ::android::sp; @@ -37,12 +37,15 @@ using ::android::hardware::Void; struct GnssMeasurementCorrections : public IMeasurementCorrections { // Methods from V1_0::IMeasurementCorrections follow. - Return setCorrections(const MeasurementCorrections& corrections) override; + Return setCorrections(const V1_0::MeasurementCorrections& corrections) override; Return setCallback(const sp& callback) override; + + // Methods from V1_1::IMeasurementCorrections follow. + Return setCorrections_1_1(const V1_1::MeasurementCorrections& corrections) override; }; } // namespace implementation -} // namespace V1_0 +} // namespace V1_1 } // namespace measurement_corrections } // namespace gnss } // namespace hardware diff --git a/gnss/2.1/vts/functional/Android.bp b/gnss/2.1/vts/functional/Android.bp index 83404992de..f008a26f1f 100644 --- a/gnss/2.1/vts/functional/Android.bp +++ b/gnss/2.1/vts/functional/Android.bp @@ -24,6 +24,7 @@ cc_test { ], static_libs: [ "android.hardware.gnss.measurement_corrections@1.0", + "android.hardware.gnss.measurement_corrections@1.1", "android.hardware.gnss.visibility_control@1.0", "android.hardware.gnss@1.0", "android.hardware.gnss@1.1", @@ -31,5 +32,8 @@ cc_test { "android.hardware.gnss@2.1", "android.hardware.gnss@common-vts-lib", ], - test_suites: ["general-tests", "vts-core"], + test_suites: [ + "general-tests", + "vts-core", + ], } diff --git a/gnss/2.1/vts/functional/gnss_hal_test.cpp b/gnss/2.1/vts/functional/gnss_hal_test.cpp index 22268f676d..93f89f54e0 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test.cpp +++ b/gnss/2.1/vts/functional/gnss_hal_test.cpp @@ -256,3 +256,10 @@ Return GnssHalTest::GnssMeasurementCallback::gnssMeasurementCb_2_1( measurement_cbq_.store(data); return Void(); } + +Return GnssHalTest::GnssMeasurementCorrectionsCallback::setCapabilitiesCb( + uint32_t capabilities) { + ALOGI("GnssMeasurementCorrectionsCallback capabilities received %d", capabilities); + capabilities_cbq_.store(capabilities); + return Void(); +} \ No newline at end of file diff --git a/gnss/2.1/vts/functional/gnss_hal_test.h b/gnss/2.1/vts/functional/gnss_hal_test.h index 6b67e139c3..b99cf2322a 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test.h +++ b/gnss/2.1/vts/functional/gnss_hal_test.h @@ -27,6 +27,7 @@ using android::hardware::Return; using android::hardware::Void; using android::hardware::gnss::common::GnssCallbackEventQueue; +using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback; using android::hardware::gnss::V1_0::GnssLocationFlags; using android::hardware::gnss::V2_0::GnssConstellationType; using android::hardware::gnss::V2_1::IGnss; @@ -138,6 +139,19 @@ class GnssHalTest : public testing::TestWithParam { Return gnssMeasurementCb_2_1(const IGnssMeasurementCallback_2_1::GnssData&) override; }; + /* Callback class for GnssMeasurementCorrections. */ + class GnssMeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback { + public: + uint32_t last_capabilities_; + GnssCallbackEventQueue capabilities_cbq_; + + GnssMeasurementCorrectionsCallback() : capabilities_cbq_("capabilities"){}; + virtual ~GnssMeasurementCorrectionsCallback() = default; + + // Methods from V1_0::IMeasurementCorrectionsCallback follow. + Return setCapabilitiesCb(uint32_t capabilities) override; + }; + /* * SetUpGnssCallback: * Set GnssCallback and verify the result. diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp index 9a7bd77bfe..9ac9436b0d 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp @@ -41,6 +41,8 @@ using android::hardware::gnss::V2_0::GnssConstellationType; using android::hardware::gnss::V2_1::IGnssConfiguration; using GnssMeasurementFlags = IGnssMeasurementCallback_2_1::GnssMeasurementFlags; +using IMeasurementCorrections_1_1 = + android::hardware::gnss::measurement_corrections::V1_1::IMeasurementCorrections; /* * SetupTeardownCreateCleanup: @@ -561,4 +563,36 @@ TEST_P(GnssHalTest, BlacklistConstellationLocationOn) { result = gnss_configuration_hal->setBlacklist_2_1(sources); ASSERT_TRUE(result.isOk()); EXPECT_TRUE(result); +} + +/* + * TestGnssMeasurementCorrections: + * If measurement corrections capability is supported, verifies that it supports the + * gnss.measurement_corrections@1.1::IMeasurementCorrections interface by invoking a method. + */ +TEST_P(GnssHalTest, TestGnssMeasurementCorrections) { + if (!(gnss_cb_->last_capabilities_ & + IGnssCallback_2_1::Capabilities::MEASUREMENT_CORRECTIONS)) { + return; + } + + // Verify IMeasurementCorrections is supported. + auto measurementCorrections = gnss_hal_->getExtensionMeasurementCorrections_1_1(); + ASSERT_TRUE(measurementCorrections.isOk()); + sp iMeasurementCorrections = measurementCorrections; + ASSERT_NE(iMeasurementCorrections, nullptr); + + sp callback = new GnssMeasurementCorrectionsCallback(); + iMeasurementCorrections->setCallback(callback); + + const int kMeasurementCorrectionsCapabilitiesTimeoutSeconds = 5; + callback->capabilities_cbq_.retrieve(callback->last_capabilities_, + kMeasurementCorrectionsCapabilitiesTimeoutSeconds); + ASSERT_TRUE(callback->capabilities_cbq_.calledCount() > 0); + + // Set a mock MeasurementCorrections. + auto result = + iMeasurementCorrections->setCorrections_1_1(Utils::getMockMeasurementCorrections_1_1()); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); } \ No newline at end of file diff --git a/gnss/common/utils/vts/Android.bp b/gnss/common/utils/vts/Android.bp index 1988171979..fd9613b02a 100644 --- a/gnss/common/utils/vts/Android.bp +++ b/gnss/common/utils/vts/Android.bp @@ -30,6 +30,7 @@ cc_library_static { shared_libs: [ "android.hardware.gnss@1.0", "android.hardware.gnss.measurement_corrections@1.0", + "android.hardware.gnss.measurement_corrections@1.1", ], static_libs: [ "libgtest", diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp index 51d3ea18d5..b6c3f5eccf 100644 --- a/gnss/common/utils/vts/Utils.cpp +++ b/gnss/common/utils/vts/Utils.cpp @@ -92,7 +92,7 @@ void Utils::checkLocation(const GnssLocation& location, bool check_speed, EXPECT_GT(location.timestamp, 1.48e12); } -const MeasurementCorrections Utils::getMockMeasurementCorrections() { +const MeasurementCorrections_1_0 Utils::getMockMeasurementCorrections() { ReflectingPlane reflectingPlane = { .latitudeDegrees = 37.4220039, .longitudeDegrees = -122.0840991, @@ -127,7 +127,7 @@ const MeasurementCorrections Utils::getMockMeasurementCorrections() { hidl_vec singleSatCorrections = {singleSatCorrection1, singleSatCorrection2}; - MeasurementCorrections mockCorrections = { + MeasurementCorrections_1_0 mockCorrections = { .latitudeDegrees = 37.4219999, .longitudeDegrees = -122.0840575, .altitudeMeters = 30.60062531, @@ -139,6 +139,18 @@ const MeasurementCorrections Utils::getMockMeasurementCorrections() { return mockCorrections; } +const MeasurementCorrections_1_1 Utils::getMockMeasurementCorrections_1_1() { + MeasurementCorrections_1_0 mockCorrections_1_0 = getMockMeasurementCorrections(); + + MeasurementCorrections_1_1 mockCorrections_1_1 = { + .v1_0 = mockCorrections_1_0, + .hasEnvironmentBearing = true, + .environmentBearingDegrees = 45.0, + .environmentBearingUncertaintyDegrees = 4.0, + }; + return mockCorrections_1_1; +} + } // 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 dce4c7b323..781ad428eb 100644 --- a/gnss/common/utils/vts/include/Utils.h +++ b/gnss/common/utils/vts/include/Utils.h @@ -19,10 +19,16 @@ #include #include +#include using GnssLocation = ::android::hardware::gnss::V1_0::GnssLocation; using namespace android::hardware::gnss::measurement_corrections::V1_0; +using MeasurementCorrections_1_0 = + android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections; +using MeasurementCorrections_1_1 = + android::hardware::gnss::measurement_corrections::V1_1::MeasurementCorrections; + namespace android { namespace hardware { namespace gnss { @@ -31,7 +37,8 @@ namespace common { struct Utils { static void checkLocation(const GnssLocation& location, bool check_speed, bool check_more_accuracies); - static const MeasurementCorrections getMockMeasurementCorrections(); + static const MeasurementCorrections_1_0 getMockMeasurementCorrections(); + static const MeasurementCorrections_1_1 getMockMeasurementCorrections_1_1(); }; } // namespace common diff --git a/gnss/measurement_corrections/1.1/Android.bp b/gnss/measurement_corrections/1.1/Android.bp new file mode 100644 index 0000000000..1d69f20866 --- /dev/null +++ b/gnss/measurement_corrections/1.1/Android.bp @@ -0,0 +1,19 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.gnss.measurement_corrections@1.1", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IMeasurementCorrections.hal", + ], + interfaces: [ + "android.hardware.gnss.measurement_corrections@1.0", + "android.hardware.gnss@1.0", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/gnss/measurement_corrections/1.1/IMeasurementCorrections.hal b/gnss/measurement_corrections/1.1/IMeasurementCorrections.hal new file mode 100644 index 0000000000..9461a5e445 --- /dev/null +++ b/gnss/measurement_corrections/1.1/IMeasurementCorrections.hal @@ -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. + */ + +package android.hardware.gnss.measurement_corrections@1.1; + +import @1.0::IMeasurementCorrections; + +/** + * Interface for measurement corrections support. + */ +interface IMeasurementCorrections extends @1.0::IMeasurementCorrections { + /** + * Injects measurement corrections to be used by the HAL to improve the GNSS location output. + * + * These are NOT to be used to adjust the IGnssMeasurementCallback output values - + * those remain raw, uncorrected measurements. + * + * In general, these are injected when conditions defined by the platform are met, such as when + * GNSS Location is being requested at a sufficiently high accuracy, based on the capabilities + * of the GNSS chipset as reported in the IGnssCallback. + * + * @param corrections The computed corrections to be used by the HAL. + * + * @return success Whether the HAL can accept & use these corrections. + */ + setCorrections_1_1(MeasurementCorrections corrections) generates (bool success); +}; \ No newline at end of file diff --git a/gnss/measurement_corrections/1.1/types.hal b/gnss/measurement_corrections/1.1/types.hal new file mode 100644 index 0000000000..40b6f52b7d --- /dev/null +++ b/gnss/measurement_corrections/1.1/types.hal @@ -0,0 +1,58 @@ +/* + * 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. + */ + +package android.hardware.gnss.measurement_corrections@1.1; + +import @1.0::MeasurementCorrections; + +/** + * A struct containing a set of measurement corrections for all used GNSS satellites at the location + * specified by latitudeDegrees, longitudeDegrees, altitudeMeters and at the time of week specified + * toaGpsNanosecondsOfWeek + */ +struct MeasurementCorrections { + @1.0::MeasurementCorrections v1_0; + + /** + * Boolean indicating if environment bearing is available. + */ + bool hasEnvironmentBearing; + + /** + * Environment bearing in degrees clockwise from true North (0.0 to 360.0], in direction of + * user motion. Environment bearing is provided when it is known with high probability that + * velocity is aligned with an environment feature, such as a building or road. + * + * If user speed is zero, environmentBearingDegrees represents bearing of most recent speed + * that was > 0. + * + * As position approaches another road, environmentBearingUncertaintyDegrees will grow, and at + * some stage hasEnvironmentBearing = false. + * + * As position moves towards an open area, environmentBearingUncertaintyDegrees will grow, and + * at some stage hasEnvironmentBearing = false. + * + * If the road is curved in the vicinity of the user location, then + * environmentBearingUncertaintyDegrees will include the amount by which the road direction + * changes in the area of position uncertainty. + */ + float environmentBearingDegrees; + + /** + * Bearing uncertainty [0 to 180]. + */ + float environmentBearingUncertaintyDegrees; +}; \ No newline at end of file From ba2f83002d85d5cd570f838a410dc5871c5bf0ce Mon Sep 17 00:00:00 2001 From: Nazish Tabassum Date: Tue, 10 Dec 2019 14:35:09 +0530 Subject: [PATCH 0497/1022] CDMA MO SMS follow on DC feature Add new API in @1.5 IRadio and IRadioResponse interfaces to send MO CDMA SMS with expectMore option Test: make Bug: 72613248 Change-Id: I9aec3a58b531c17ec55db290d0e82bc7d34afa84 --- current.txt | 4 +- radio/1.5/IRadio.hal | 14 +++++- radio/1.5/IRadioResponse.hal | 34 +++++++++++++- .../1.5/vts/functional/radio_hidl_hal_api.cpp | 44 +++++++++++++++++++ .../functional/radio_hidl_hal_utils_v1_5.h | 3 ++ radio/1.5/vts/functional/radio_response.cpp | 5 +++ 6 files changed, 100 insertions(+), 4 deletions(-) diff --git a/current.txt b/current.txt index d9e1a76693..ebb2c61a1d 100644 --- a/current.txt +++ b/current.txt @@ -675,9 +675,9 @@ def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardwar # BEGIN Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present ## 430f8449ddb24c02284da561bfd24bb5a2a226d9ed2aec38e876e323e2b7eeee android.hardware.radio@1.5::types -c68f5bd87f747f8e7968ff66ecc548b2d26f8e186b7bb805c11d6c883a838fc6 android.hardware.radio@1.5::IRadio +26216f3566aff76d8a29ee95f74bcb099a05f65ead8d6d4fadafee6967889b93 android.hardware.radio@1.5::IRadio e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication -9e962eff568dc8c712d83846f8c27460de5005ed9b836d3e08390e8aa56b5a46 android.hardware.radio@1.5::IRadioResponse +1a3324125cae8f4ca9984225d2f14bafeb835b8d9a1717fc9ed794de701f197c android.hardware.radio@1.5::IRadioResponse 2fd107f3de1b7e36825e241a88dfae8edf3a77c166cb746f00ddf6440ab78db1 android.hardware.radio.config@1.3::types a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal index ee4438d08d..bea0454aa3 100644 --- a/radio/1.5/IRadio.hal +++ b/radio/1.5/IRadio.hal @@ -16,9 +16,10 @@ package android.hardware.radio@1.5; +import @1.0::CdmaSmsMessage; import @1.2::DataRequestReason; -import @1.4::IRadio; import @1.4::DataProfileInfo; +import @1.4::IRadio; import @1.5::AccessNetwork; import @1.5::BarringInfo; import @1.5::DataProfileInfo; @@ -282,4 +283,15 @@ interface IRadio extends @1.4::IRadio { */ oneway setNetworkSelectionModeManual_1_5(int32_t serial, string operatorNumeric, RadioAccessNetworks ran); + + /** + * Send an SMS message. Identical to sendCdmaSms, + * except that more messages are expected to be sent soon. + * + * @param serial Serial number of request. + * @param sms Cdma Sms to be sent described by CdmaSmsMessage in types.hal + * + * Response callback is IRadioResponse.sendCdmaSMSExpectMoreResponse() + */ + oneway sendCdmaSmsExpectMore(int32_t serial, CdmaSmsMessage sms); }; diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal index e66e00b1ea..9fa521e792 100644 --- a/radio/1.5/IRadioResponse.hal +++ b/radio/1.5/IRadioResponse.hal @@ -17,11 +17,12 @@ package android.hardware.radio@1.5; import @1.0::RadioResponseInfo; +import @1.0::SendSmsResult; import @1.4::IRadioResponse; import @1.5::BarringInfo; import @1.5::CellInfo; -import @1.5::SetupDataCallResult; import @1.5::RegStateResult; +import @1.5::SetupDataCallResult; /** * Interface declaring response functions to solicited radio requests. @@ -236,4 +237,35 @@ interface IRadioResponse extends @1.4::IRadioResponse { * no retries needed, such as illegal SIM or ME. */ oneway setNetworkSelectionModeManualResponse_1_5(RadioResponseInfo info); + + /** + * @param info Response info struct containing response type, serial no. and error + * @param sms Response to sms sent as defined by SendSmsResult in types.hal + * + * Valid errors returned: + * RadioError:NONE + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:SMS_SEND_FAIL_RETRY + * RadioError:NETWORK_REJECT + * RadioError:INVALID_STATE + * RadioError:INVALID_ARGUMENTS + * RadioError:NO_MEMORY + * RadioError:REQUEST_RATE_LIMITED + * RadioError:INVALID_SMS_FORMAT + * RadioError:SYSTEM_ERR + * RadioError:FDN_CHECK_FAILURE + * RadioError:ENCODING_ERR + * RadioError:INVALID_SMSC_ADDRESS + * RadioError:MODEM_ERR + * RadioError:NETWORK_ERR + * RadioError:INTERNAL_ERR + * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:INVALID_MODEM_STATE + * RadioError:NETWORK_NOT_READY + * RadioError:OPERATION_NOT_ALLOWED + * RadioError:NO_RESOURCES + * RadioError:CANCELLED + * RadioError:SIM_ABSENT + */ + oneway sendCdmaSmsExpectMoreResponse(RadioResponseInfo info, SendSmsResult sms); }; diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp index a4095b7a91..09305de703 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp @@ -1022,3 +1022,47 @@ TEST_F(RadioHidlTest_v1_5, setNetworkSelectionModeManual_1_5) { CHECK_GENERAL_ERROR)); } } + +/* + * Test IRadio.sendCdmaSmsExpectMore() for the response returned. + */ +TEST_F(RadioHidlTest_v1_5, sendCdmaSmsExpectMore) { + serial = GetRandomSerialNumber(); + + // Create a CdmaSmsAddress + CdmaSmsAddress cdmaSmsAddress; + cdmaSmsAddress.digitMode = CdmaSmsDigitMode::FOUR_BIT; + cdmaSmsAddress.numberMode = CdmaSmsNumberMode::NOT_DATA_NETWORK; + cdmaSmsAddress.numberType = CdmaSmsNumberType::UNKNOWN; + cdmaSmsAddress.numberPlan = CdmaSmsNumberPlan::UNKNOWN; + cdmaSmsAddress.digits = (std::vector){11, 1, 6, 5, 10, 7, 7, 2, 10, 3, 10, 3}; + + // Create a CdmaSmsSubAddress + CdmaSmsSubaddress cdmaSmsSubaddress; + cdmaSmsSubaddress.subaddressType = CdmaSmsSubaddressType::NSAP; + cdmaSmsSubaddress.odd = false; + cdmaSmsSubaddress.digits = (std::vector){}; + + // Create a CdmaSmsMessage + android::hardware::radio::V1_0::CdmaSmsMessage cdmaSmsMessage; + cdmaSmsMessage.teleserviceId = 4098; + cdmaSmsMessage.isServicePresent = false; + cdmaSmsMessage.serviceCategory = 0; + cdmaSmsMessage.address = cdmaSmsAddress; + cdmaSmsMessage.subAddress = cdmaSmsSubaddress; + cdmaSmsMessage.bearerData = + (std::vector){15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0}; + + radio_v1_5->sendCdmaSmsExpectMore(serial, cdmaSmsMessage); + + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + if (cardStatus.base.base.cardState == CardState::ABSENT) { + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_v1_5->rspInfo.error, + {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT}, + CHECK_GENERAL_ERROR)); + } +} diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index abab452915..6e6576e4b4 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -573,6 +573,9 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon cellInfo); Return setNetworkSelectionModeManualResponse_1_5(const RadioResponseInfo& info); + + Return sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& info, + const SendSmsResult& sms); }; /* Callback class for radio indication */ diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp index d7197d5eb1..223acd0aa3 100644 --- a/radio/1.5/vts/functional/radio_response.cpp +++ b/radio/1.5/vts/functional/radio_response.cpp @@ -999,3 +999,8 @@ Return RadioResponse_v1_5::setNetworkSelectionModeManualResponse_1_5( parent_v1_5.notify(info.serial); return Void(); } + +Return RadioResponse_v1_5::sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& /*info*/, + const SendSmsResult& /*sms*/) { + return Void(); +} From 5910241fe913aab9ced08799a6a39310e6b34d04 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 21 Jan 2020 21:26:16 -0800 Subject: [PATCH 0498/1022] Fixed the comment and time name To match the API in LinkAddress. Test: Telephony sanity tests Bug: 135717900 Change-Id: I06559044c8015bc577d9e4ca489a4924f69093b2 --- current.txt | 2 +- radio/1.5/types.hal | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/current.txt b/current.txt index ebb2c61a1d..f6a3a87e5e 100644 --- a/current.txt +++ b/current.txt @@ -674,7 +674,7 @@ def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardwar ## # BEGIN Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present ## -430f8449ddb24c02284da561bfd24bb5a2a226d9ed2aec38e876e323e2b7eeee android.hardware.radio@1.5::types +3a303604d6c99a36c3d2a819b7908b3681b8488f89c26ea525768522c45f7f17 android.hardware.radio@1.5::types 26216f3566aff76d8a29ee95f74bcb099a05f65ead8d6d4fadafee6967889b93 android.hardware.radio@1.5::IRadio e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication 1a3324125cae8f4ca9984225d2f14bafeb835b8d9a1717fc9ed794de701f197c android.hardware.radio@1.5::IRadioResponse diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index c0fa8af782..82feced37d 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -427,16 +427,20 @@ struct LinkAddress { bitfield properties; /** - * The UTC time that this link address will be deprecated. 0 indicates this information is not - * available. + * The time, as reported by SystemClock.elapsedRealtime(), when this link address will be or + * was deprecated. -1 indicates this information is not available. At the time existing + * connections can still use this address until it expires, but new connections should use the + * new address. LONG_MAX(0x7FFFFFFFFFFFFFFF) indicates this link address will never be + * deprecated. */ - uint64_t deprecatedTime; + uint64_t deprecationTime; /** - * The UTC time that this link address will expire and no longer valid. 0 indicates this - * information is not available. + * The time, as reported by SystemClock.elapsedRealtime(), when this link address will expire + * and be removed from the interface. -1 indicates this information is not available. + * LONG_MAX(0x7FFFFFFFFFFFFFFF) indicates this link address will never expire. */ - uint64_t expiredTime; + uint64_t expirationTime; }; /** From 33173a3e685c212b86706dd242e14804bee130f6 Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Thu, 23 Jan 2020 13:53:21 -0800 Subject: [PATCH 0499/1022] Fix the NNAPI vts tests about validateExecuteFenced - Skip the test if the driver reject executeFenced. - remove the -1 fd for hidl_handle as it causes error before reaching the driver. Test: mm Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: Idc3f815040efccbbfa95b70d5d437441d0bd8682 --- .../vts/functional/GeneratedTestHarness.cpp | 24 ++++++++++++++++--- .../1.3/vts/functional/GeneratedTestHarness.h | 2 ++ .../vts/functional/VtsHalNeuralnetworks.cpp | 20 ++++------------ 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index b8111492f0..88837db349 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -603,7 +603,9 @@ void EvaluatePreparedModel(const sp& device, const sp& } } - if (testConfig.outputType != OutputType::FULLY_SPECIFIED && + // The driver is allowed to reject executeFenced, and if they do, we should skip. + if ((testConfig.outputType != OutputType::FULLY_SPECIFIED || + testConfig.executor == Executor::FENCED) && executionStatus == ErrorStatus::GENERAL_FAILURE) { if (skipped != nullptr) { *skipped = true; @@ -674,7 +676,7 @@ void EvaluatePreparedModel(const sp& device, const sp& case TestKind::GENERAL: { outputTypesList = {OutputType::FULLY_SPECIFIED}; measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; - executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST, Executor::FENCED}; + executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; } break; case TestKind::DYNAMIC_SHAPE: { outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT}; @@ -687,6 +689,11 @@ void EvaluatePreparedModel(const sp& device, const sp& executorList = {Executor::ASYNC, Executor::SYNC}; memoryType = MemoryType::DEVICE; } break; + case TestKind::FENCED_COMPUTE: { + outputTypesList = {OutputType::FULLY_SPECIFIED}; + measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; + executorList = {Executor::FENCED}; + } break; case TestKind::QUANTIZATION_COUPLING: { LOG(FATAL) << "Wrong TestKind for EvaluatePreparedModel"; return; @@ -748,7 +755,8 @@ void Execute(const sp& device, const TestModel& testModel, TestKind tes switch (testKind) { case TestKind::GENERAL: case TestKind::DYNAMIC_SHAPE: - case TestKind::MEMORY_DOMAIN: { + case TestKind::MEMORY_DOMAIN: + case TestKind::FENCED_COMPUTE: { createPreparedModel(device, model, &preparedModel); if (preparedModel == nullptr) return; EvaluatePreparedModel(device, preparedModel, testModel, testKind); @@ -811,6 +819,9 @@ class DynamicOutputShapeTest : public GeneratedTest {}; // Tag for the memory domain tests class MemoryDomainTest : public GeneratedTest {}; +// Tag for the fenced compute tests +class FencedComputeTest : public GeneratedTest {}; + // Tag for the dynamic output shape tests class QuantizationCouplingTest : public GeneratedTest {}; @@ -826,6 +837,10 @@ TEST_P(MemoryDomainTest, Test) { Execute(kDevice, kTestModel, /*testKind=*/TestKind::MEMORY_DOMAIN); } +TEST_P(FencedComputeTest, Test) { + Execute(kDevice, kTestModel, /*testKind=*/TestKind::FENCED_COMPUTE); +} + TEST_P(QuantizationCouplingTest, Test) { Execute(kDevice, kTestModel, /*testKind=*/TestKind::QUANTIZATION_COUPLING); } @@ -840,6 +855,9 @@ INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, [](const TestModel& testModel INSTANTIATE_GENERATED_TEST(MemoryDomainTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); +INSTANTIATE_GENERATED_TEST(FencedComputeTest, + [](const TestModel& testModel) { return !testModel.expectFailure; }); + INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) { return testModel.hasQuant8CoupledOperands() && testModel.operations.size() == 1; }); diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h index fe695b471d..e597fac7cf 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h @@ -65,6 +65,8 @@ enum class TestKind { DYNAMIC_SHAPE, // Same as GENERAL but use device memories for inputs and outputs MEMORY_DOMAIN, + // Same as GENERAL but use executeFenced for exeuction + FENCED_COMPUTE, // Tests if quantized model with TENSOR_QUANT8_ASYMM produces the same result // (OK/SKIPPED/FAILED) as the model with all such tensors converted to // TENSOR_QUANT8_ASYMM_SIGNED. diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index 28cc8ffe65..c84f5b70e7 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -140,26 +140,14 @@ void validateExecuteFenced(const sp& preparedModel, const Reques preparedModel->executeFenced(request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO, [](ErrorStatus error, const hidl_handle& handle, const sp& callback) { - ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); + // TODO: fix this once sample driver impl is merged. + if (error != ErrorStatus::DEVICE_UNAVAILABLE) { + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); + } ASSERT_EQ(handle.getNativeHandle(), nullptr); ASSERT_EQ(callback, nullptr); }); ASSERT_TRUE(ret_null.isOk()); - - native_handle_t* nativeHandle = native_handle_create(1, 0); - ASSERT_NE(nullptr, nativeHandle); - nativeHandle->data[0] = -1; - hidl_handle hidlHandle; - hidlHandle.setTo(nativeHandle, /*shouldOwn=*/true); - Return ret_invalid = - preparedModel->executeFenced(request, {hidlHandle}, V1_2::MeasureTiming::NO, - [](ErrorStatus error, const hidl_handle& handle, - const sp& callback) { - ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); - ASSERT_EQ(handle.getNativeHandle(), nullptr); - ASSERT_EQ(callback, nullptr); - }); - ASSERT_TRUE(ret_invalid.isOk()); } void validateEverything(const sp& device, const Model& model, const Request& request, From 76369ea5cde58f6f43bf1c2d044737c1b3ab4c64 Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Thu, 23 Jan 2020 13:34:38 -0800 Subject: [PATCH 0500/1022] Add biometrics.fingerprint@2.2 to current.txt Bug: 139317981 Test: atest vts_treble_vintf_vendor_test Change-Id: I673036bbcc8444380543d08034bacee736e53f89 --- current.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/current.txt b/current.txt index d9e1a76693..608e1ccf14 100644 --- a/current.txt +++ b/current.txt @@ -626,6 +626,9 @@ dd377f404a8e71f6191d295e10067db629b0f0c28e594af906f2bea5d87fe2cc android.hardwar 5237c42d3913ef569f07bec802568084b615155d05a7951e75085da54856508c android.hardware.audio.effect@6.0::IPresetReverbEffect 282193799d60bff27a84c65a36218c1e7d8f582f5828e2e059383d1b90aa56bd android.hardware.audio.effect@6.0::IVirtualizerEffect 0868e00f7c5ee16723bda1a8f57099763d04100ae7126a1c2d3a9a87c844a7e8 android.hardware.audio.effect@6.0::IVisualizerEffect +ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types +6828bbf18dc5d0f00c73341a10c8e4d574346c1abb1c2ed682ba5e9f8a3240d9 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprint +82cad99f5feb2ea9bcd4579055edf4af8feb9fc602a6e4827ddd727d254d4991 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprintClientCallback 79e115c8f8970b8b914bafc66df5425e065fda4dcda97222966ef12451d2a1cc android.hardware.bluetooth@1.1::IBluetoothHci 40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl From 15cc8fffe865ca5554cc35f049c1e2a7a32966e1 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 23 Jan 2020 15:12:56 -0800 Subject: [PATCH 0501/1022] AIDL light required for launching devices. Deprecating light HIDL for launching devices so that we can remove HIDL support after ~3+ years. Bug: 142715294 Test: passes on cuttlefish (TH check) Change-Id: I61c9c89c8c53050a959f4a1c432d880c7989d6b2 --- compatibility_matrices/compatibility_matrix.current.xml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index c10ca271f6..beb92ebc73 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -281,14 +281,6 @@ strongbox - - android.hardware.light - 2.0 - - ILight - default - - android.hardware.light From 366cc5371401070753150e685e07e100f837dbe4 Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Fri, 17 Jan 2020 22:45:44 -0800 Subject: [PATCH 0502/1022] Add default implementation for biometrics.face@1.1 Bug: 145027036 Test: vts-tradefed run commandAndExit vts-hal -m VtsHalBiometricsFaceV1_0Target Test: vts-tradefed run commandAndExit vts-hal -m VtsHalBiometricsFaceV1_1Target Change-Id: I1aa682644b9b60705a1a8bf40867414b9fc99cd6 --- biometrics/face/1.1/default/Android.bp | 36 ++++++ .../face/1.1/default/BiometricsFace.cpp | 121 ++++++++++++++++++ biometrics/face/1.1/default/BiometricsFace.h | 84 ++++++++++++ ...id.hardware.biometrics.face@1.1-service.rc | 10 ++ .../1.1/default/manifest_face_default.xml | 11 ++ biometrics/face/1.1/default/service.cpp | 50 ++++++++ .../compatibility_matrix.current.xml | 2 +- 7 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 biometrics/face/1.1/default/Android.bp create mode 100644 biometrics/face/1.1/default/BiometricsFace.cpp create mode 100644 biometrics/face/1.1/default/BiometricsFace.h create mode 100644 biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc create mode 100644 biometrics/face/1.1/default/manifest_face_default.xml create mode 100644 biometrics/face/1.1/default/service.cpp diff --git a/biometrics/face/1.1/default/Android.bp b/biometrics/face/1.1/default/Android.bp new file mode 100644 index 0000000000..360071f3dd --- /dev/null +++ b/biometrics/face/1.1/default/Android.bp @@ -0,0 +1,36 @@ +/* + * Copyright 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. + */ + +cc_binary { + name: "android.hardware.biometrics.face@1.1-service.example", + defaults: ["hidl_defaults"], + vendor: true, + init_rc: ["android.hardware.biometrics.face@1.1-service.rc"], + vintf_fragments: ["manifest_face_default.xml"], + relative_install_path: "hw", + proprietary: true, + srcs: [ + "BiometricsFace.cpp", + "service.cpp", + ], + shared_libs: [ + "libhidlbase", + "libutils", + "liblog", + "android.hardware.biometrics.face@1.0", + "android.hardware.biometrics.face@1.1", + ], +} diff --git a/biometrics/face/1.1/default/BiometricsFace.cpp b/biometrics/face/1.1/default/BiometricsFace.cpp new file mode 100644 index 0000000000..7bda57fb7f --- /dev/null +++ b/biometrics/face/1.1/default/BiometricsFace.cpp @@ -0,0 +1,121 @@ +/* + * Copyright 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 "BiometricsFace.h" + +namespace android::hardware::biometrics::face::implementation { +using android::hardware::biometrics::face::V1_0::FaceError; +using android::hardware::biometrics::face::V1_0::OptionalUint64; + +// Arbitrary value. +constexpr uint64_t kDeviceId = 123; +// Arbitrary value. +constexpr uint64_t kAuthenticatorId = 987; +// Arbitrary value. +constexpr uint64_t kLockoutDuration = 555; + +BiometricsFace::BiometricsFace() : mRandom(std::mt19937::default_seed) {} + +// Methods from IBiometricsFace follow. +Return BiometricsFace::setCallback(const sp& clientCallback, + setCallback_cb _hidl_cb) { + mClientCallback = clientCallback; + _hidl_cb({Status::OK, kDeviceId}); + return Void(); +} + +Return BiometricsFace::setActiveUser(int32_t userId, const hidl_string& storePath) { + if (userId < 0 || storePath.empty() || std::string(storePath).find("/data") != 0) { + return Status::ILLEGAL_ARGUMENT; + } + mUserId = userId; + mClientCallback->onLockoutChanged(kLockoutDuration); + return Status::OK; +} + +Return BiometricsFace::generateChallenge(uint32_t /* challengeTimeoutSec */, + generateChallenge_cb _hidl_cb) { + std::uniform_int_distribution dist; + _hidl_cb({Status::OK, dist(mRandom)}); + return Void(); +} + +Return BiometricsFace::enroll(const hidl_vec& /* hat */, uint32_t /* timeoutSec */, + const hidl_vec& /* disabledFeatures */) { + // hat can never be valid in this implementation. + mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */); + return Status::OK; +} + +Return BiometricsFace::revokeChallenge() { + return Status::OK; +} + +Return BiometricsFace::setFeature(Feature /* feature */, bool /* enabled */, + const hidl_vec& /* hat */, + uint32_t /* faceId */) { + // hat can never be valid in this implementation. + return Status::ILLEGAL_ARGUMENT; +} + +Return BiometricsFace::getFeature(Feature /* feature */, uint32_t /* faceId */, + getFeature_cb _hidl_cb) { + // hat can never be valid in this implementation. + _hidl_cb({Status::ILLEGAL_ARGUMENT, false}); + return Void(); +} + +Return BiometricsFace::getAuthenticatorId(getAuthenticatorId_cb _hidl_cb) { + _hidl_cb({Status::OK, kAuthenticatorId}); + return Void(); +} + +Return BiometricsFace::cancel() { + mClientCallback->onError(kDeviceId, mUserId, FaceError::CANCELED, 0 /* vendorCode */); + return Status::OK; +} + +Return BiometricsFace::enumerate() { + mClientCallback->onEnumerate(kDeviceId, {}, mUserId); + return Status::OK; +} + +Return BiometricsFace::remove(uint32_t /* faceId */) { + return Status::OK; +} + +Return BiometricsFace::authenticate(uint64_t /* operationId */) { + mClientCallback->onError(kDeviceId, mUserId, FaceError::HW_UNAVAILABLE, 0 /* vendorCode */); + return Status::OK; +} + +Return BiometricsFace::userActivity() { + return Status::OK; +} + +Return BiometricsFace::resetLockout(const hidl_vec& /* hat */) { + return Status::OK; +} + +// Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow. +Return BiometricsFace::enrollRemotely(const hidl_vec& /* hat */, + uint32_t /* timeoutSec */, + const hidl_vec& /* disabledFeatures */) { + mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */); + return Status::OK; +} + +} // namespace android::hardware::biometrics::face::implementation diff --git a/biometrics/face/1.1/default/BiometricsFace.h b/biometrics/face/1.1/default/BiometricsFace.h new file mode 100644 index 0000000000..5620b45a43 --- /dev/null +++ b/biometrics/face/1.1/default/BiometricsFace.h @@ -0,0 +1,84 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include +#include +#include +#include + +namespace android::hardware::biometrics::face::implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::biometrics::face::V1_0::Feature; +using ::android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback; +using ::android::hardware::biometrics::face::V1_0::Status; + +class BiometricsFace : public V1_1::IBiometricsFace { + public: + BiometricsFace(); + + // Methods from ::android::hardware::biometrics::face::V1_0::IBiometricsFace follow. + Return setCallback(const sp& clientCallback, + setCallback_cb _hidl_cb) override; + + Return setActiveUser(int32_t userId, const hidl_string& storePath) override; + + Return generateChallenge(uint32_t challengeTimeoutSec, + generateChallenge_cb _hidl_cb) override; + + Return enroll(const hidl_vec& hat, uint32_t timeoutSec, + const hidl_vec& disabledFeatures) override; + + Return revokeChallenge() override; + + Return setFeature(Feature feature, bool enabled, const hidl_vec& hat, + uint32_t faceId) override; + + Return getFeature(Feature feature, uint32_t faceId, getFeature_cb _hidl_cb) override; + + Return getAuthenticatorId(getAuthenticatorId_cb _hidl_cb) override; + + Return cancel() override; + + Return enumerate() override; + + Return remove(uint32_t faceId) override; + + Return authenticate(uint64_t operationId) override; + + Return userActivity() override; + + Return resetLockout(const hidl_vec& hat) override; + + // Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow. + Return enrollRemotely(const hidl_vec& hat, uint32_t timeoutSec, + const hidl_vec& disabledFeatures) override; + + private: + std::mt19937 mRandom; + int32_t mUserId; + sp mClientCallback; +}; + +} // namespace android::hardware::biometrics::face::implementation diff --git a/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc b/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc new file mode 100644 index 0000000000..687e2d8c86 --- /dev/null +++ b/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc @@ -0,0 +1,10 @@ +service vendor.face-hal-1-1-default /vendor/bin/hw/android.hardware.biometrics.face@1.1-service.example + # "class hal" causes a race condition on some devices due to files created + # in /data. As a workaround, postpone startup until later in boot once + # /data is mounted. + class late_start + user system + group system + writepid /dev/cpuset/foreground/tasks + capabilities SYS_NICE + rlimit rtprio 10 10 diff --git a/biometrics/face/1.1/default/manifest_face_default.xml b/biometrics/face/1.1/default/manifest_face_default.xml new file mode 100644 index 0000000000..ec71d9c92b --- /dev/null +++ b/biometrics/face/1.1/default/manifest_face_default.xml @@ -0,0 +1,11 @@ + + + android.hardware.biometrics.face + hwbinder + 1.1 + + IBiometricsFace + default + + + diff --git a/biometrics/face/1.1/default/service.cpp b/biometrics/face/1.1/default/service.cpp new file mode 100644 index 0000000000..344bdb99b4 --- /dev/null +++ b/biometrics/face/1.1/default/service.cpp @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#define LOG_TAG "android.hardware.biometrics.face@1.1-service" + +#include +#include +#include +#include +#include +#include "BiometricsFace.h" + +using android::sp; +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::biometrics::face::implementation::BiometricsFace; +using android::hardware::biometrics::face::V1_1::IBiometricsFace; + +int main() { + ALOGI("BiometricsFace HAL is being started."); + + configureRpcThreadpool(1, true /*callerWillJoin*/); + + android::sp face = new BiometricsFace(); + const android::status_t status = face->registerAsService(); + + if (status != android::OK) { + ALOGE("Error starting the BiometricsFace HAL."); + return 1; + } + + ALOGI("BiometricsFace HAL has started successfully."); + joinRpcThreadpool(); + + ALOGI("BiometricsFace HAL is terminating."); + return 1; // should never get here +} diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index c10ca271f6..646b14808d 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -66,7 +66,7 @@ android.hardware.biometrics.face - 1.0 + 1.0-1 IBiometricsFace default From 7ab5ab85d0df1f565a265ec0b75e01310ef9b5ba Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Wed, 22 Jan 2020 18:59:11 -0800 Subject: [PATCH 0503/1022] Add enroll_1_1 with preview window id Bug: 145562442 Test: vts-tradefed run commandAndExit vts-hal -m VtsHalBiometricsFaceV1_0Target Test: vts-tradefed run commandAndExit vts-hal -m VtsHalBiometricsFaceV1_1Target Change-Id: I7839fe162dc31c71cc33ae226a23a2239a2093a1 --- biometrics/face/1.1/IBiometricsFace.hal | 39 ++++++++++++++++- .../face/1.1/default/BiometricsFace.cpp | 8 ++++ biometrics/face/1.1/default/BiometricsFace.h | 4 ++ .../VtsHalBiometricsFaceV1_1TargetTest.cpp | 42 +++++++++++++++++++ 4 files changed, 91 insertions(+), 2 deletions(-) diff --git a/biometrics/face/1.1/IBiometricsFace.hal b/biometrics/face/1.1/IBiometricsFace.hal index 975001f30b..84e7443c9c 100644 --- a/biometrics/face/1.1/IBiometricsFace.hal +++ b/biometrics/face/1.1/IBiometricsFace.hal @@ -15,6 +15,7 @@ */ package android.hardware.biometrics.face@1.1; + import @1.0::IBiometricsFace; import @1.0::Status; import @1.0::Feature; @@ -77,6 +78,40 @@ interface IBiometricsFace extends @1.0::IBiometricsFace { * enrollment. Note that all features are enabled by default. * @return status The status of this method call. */ - enrollRemotely(vec hat, uint32_t timeoutSec, - vec disabledFeatures) generates (Status status); + enrollRemotely(vec hat, uint32_t timeoutSec, vec disabledFeatures) + generates (Status status); + + /** + * Enrolls a user's face. + * + * Note that the Hardware Authentication Token must be valid for the + * duration of enrollment and thus should be explicitly invalidated by a + * call to revokeChallenge() when enrollment is complete, to reduce the + * window of opportunity to re-use the challenge and HAT. For example, + * Settings calls generateChallenge() once to allow the user to enroll one + * or more faces or toggle secure settings without having to re-enter the + * PIN/pattern/password. Once the user completes the operation, Settings + * invokes revokeChallenge() to close the transaction. If the HAT is expired, + * the implementation must invoke onError with UNABLE_TO_PROCESS. + * + * This method triggers the IBiometricsFaceClientCallback#onEnrollResult() + * method. + * + * @param hat A valid Hardware Authentication Token, generated as a result + * of a generateChallenge() challenge being wrapped by the gatekeeper + * after a successful strong authentication request. + * @param timeoutSec A timeout in seconds, after which this enroll + * attempt is cancelled. Note that the framework can continue + * enrollment by calling this again with a valid HAT. This timeout is + * expected to be used to limit power usage if the device becomes idle + * during enrollment. The implementation is expected to send + * ERROR_TIMEOUT if this happens. + * @param disabledFeatures A list of features to be disabled during + * enrollment. Note that all features are enabled by default. + * @param windowId optional ID of a camera preview window for a + * single-camera device. Must be null if not used. + * @return status The status of this method call. + */ + enroll_1_1(vec hat, uint32_t timeoutSec, vec disabledFeatures, + handle windowId) generates (Status status); }; diff --git a/biometrics/face/1.1/default/BiometricsFace.cpp b/biometrics/face/1.1/default/BiometricsFace.cpp index 7bda57fb7f..2143880514 100644 --- a/biometrics/face/1.1/default/BiometricsFace.cpp +++ b/biometrics/face/1.1/default/BiometricsFace.cpp @@ -111,6 +111,14 @@ Return BiometricsFace::resetLockout(const hidl_vec& /* hat */) } // Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow. +Return BiometricsFace::enroll_1_1(const hidl_vec& /* hat */, + uint32_t /* timeoutSec */, + const hidl_vec& /* disabledFeatures */, + const hidl_handle& /* windowId */) { + mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */); + return Status::OK; +} + Return BiometricsFace::enrollRemotely(const hidl_vec& /* hat */, uint32_t /* timeoutSec */, const hidl_vec& /* disabledFeatures */) { diff --git a/biometrics/face/1.1/default/BiometricsFace.h b/biometrics/face/1.1/default/BiometricsFace.h index 5620b45a43..5ce5771eae 100644 --- a/biometrics/face/1.1/default/BiometricsFace.h +++ b/biometrics/face/1.1/default/BiometricsFace.h @@ -72,6 +72,10 @@ class BiometricsFace : public V1_1::IBiometricsFace { Return resetLockout(const hidl_vec& hat) override; // Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow. + Return enroll_1_1(const hidl_vec& hat, uint32_t timeoutSec, + const hidl_vec& disabledFeatures, + const hidl_handle& windowId) override; + Return enrollRemotely(const hidl_vec& hat, uint32_t timeoutSec, const hidl_vec& disabledFeatures) override; diff --git a/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp index c2431c6727..6ada44231f 100644 --- a/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp +++ b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp @@ -30,6 +30,7 @@ #include using android::sp; +using android::hardware::hidl_handle; using android::hardware::hidl_vec; using android::hardware::Return; using android::hardware::Void; @@ -116,6 +117,47 @@ class FaceHidlTest : public ::testing::TestWithParam { sp mCallback; }; +// enroll with an invalid (all zeroes) HAT should fail. +TEST_P(FaceHidlTest, Enroll2_2ZeroHatTest) { + // Filling HAT with zeros + hidl_vec token(69); + for (size_t i = 0; i < 69; i++) { + token[i] = 0; + } + + hidl_handle windowId = nullptr; + Return ret = mService->enroll_1_1(token, kTimeoutSec, {}, windowId); + ASSERT_EQ(Status::OK, static_cast(ret)); + + // onError should be called with a meaningful (nonzero) error. + auto res = mCallback->WaitForCallback(kCallbackNameOnError); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kUserId, res.args->userId); + EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error); +} + +// enroll with an invalid HAT should fail. +TEST_P(FaceHidlTest, Enroll2_2GarbageHatTest) { + // Filling HAT with pseudorandom invalid data. + // Using default seed to make the test reproducible. + std::mt19937 gen(std::mt19937::default_seed); + std::uniform_int_distribution dist; + hidl_vec token(69); + for (size_t i = 0; i < 69; ++i) { + token[i] = dist(gen); + } + + hidl_handle windowId = nullptr; + Return ret = mService->enroll_1_1(token, kTimeoutSec, {}, windowId); + ASSERT_EQ(Status::OK, static_cast(ret)); + + // onError should be called with a meaningful (nonzero) error. + auto res = mCallback->WaitForCallback(kCallbackNameOnError); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kUserId, res.args->userId); + EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error); +} + // enroll with an invalid (all zeroes) HAT should fail. TEST_P(FaceHidlTest, EnrollRemotelyZeroHatTest) { // Filling HAT with zeros From 7b8a5c99d6b017d206458aaaa34ab204c3afdfb9 Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Thu, 23 Jan 2020 13:29:36 -0800 Subject: [PATCH 0504/1022] Add biometrics.face@1.1 to current.txt Bug: 145027036 Test: atest vts_treble_vintf_vendor_test Change-Id: I5d2ed34a30dead76d3adfbd4e103a1c348e67a04 --- current.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/current.txt b/current.txt index f337c8e157..82940d0d74 100644 --- a/current.txt +++ b/current.txt @@ -451,9 +451,9 @@ ca15a738dedc2f4981925f7d7ff29c22bc3f8a848403dcf0c592c167de09d9af android.hardwar 443659bb9e27221e5da0d16c7a0ecb2dc3a9a03acc8a0b2196b47c50735e2d2e android.hardware.audio.effect@5.0::IVirtualizerEffect 78fed26a781cdca1b3bcb37520bff705d7764ee81db9cfd37014953c7ad2596e android.hardware.audio.effect@5.0::IVisualizerEffect 6385b6accab8a544e2ee54ba7bf5aa55dff6153bcedd80fdaae16fe9e0be7050 android.hardware.audio.effect@5.0::types +95aa2f59e29e2f84d8e84320ace9b6682b426a16e897b4bd241375cbee0e07f3 android.hardware.biometrics.face@1.0::types e18ff318f3fc43db37f554696dc4e551abb9b119bde53950f73e28ce33a97a40 android.hardware.biometrics.face@1.0::IBiometricsFace b6e55d7795bbafd011fb95a3b6d3954bf66c349e14cf107f3b72032ce3ceb448 android.hardware.biometrics.face@1.0::IBiometricsFaceClientCallback -95aa2f59e29e2f84d8e84320ace9b6682b426a16e897b4bd241375cbee0e07f3 android.hardware.biometrics.face@1.0::types ecedc58dbcdb13503c19c0ab160ac1dd0530bb1471164149282dd1463c684185 android.hardware.bluetooth.audio@2.0::IBluetoothAudioPort fb9c40e4deab40be5476477078fe3d8a4a4495fd9deef4321878d169d675c633 android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvider f7431f3e3e4e3387fc6f27a6cf423eddcd824a395dc4349d302c995ab44a9895 android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvidersFactory @@ -626,6 +626,7 @@ dd377f404a8e71f6191d295e10067db629b0f0c28e594af906f2bea5d87fe2cc android.hardwar 5237c42d3913ef569f07bec802568084b615155d05a7951e75085da54856508c android.hardware.audio.effect@6.0::IPresetReverbEffect 282193799d60bff27a84c65a36218c1e7d8f582f5828e2e059383d1b90aa56bd android.hardware.audio.effect@6.0::IVirtualizerEffect 0868e00f7c5ee16723bda1a8f57099763d04100ae7126a1c2d3a9a87c844a7e8 android.hardware.audio.effect@6.0::IVisualizerEffect +7e8e1c3d0173c5d503dd01cecff8e3864478557ca6b9e8cc2291598b1a4aea62 android.hardware.biometrics.face@1.1::IBiometricsFace ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types 6828bbf18dc5d0f00c73341a10c8e4d574346c1abb1c2ed682ba5e9f8a3240d9 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprint 82cad99f5feb2ea9bcd4579055edf4af8feb9fc602a6e4827ddd727d254d4991 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprintClientCallback From 6248100ed66341928d120b000bf53ac35a0277b5 Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Thu, 9 Jan 2020 15:39:27 -0800 Subject: [PATCH 0505/1022] camera: Add ICameraProvider@2.6. ICameraProvider@2.6 adds the following new apis: - getConcurrentStreamingCameraIds() tells the camera framework which combinations of camera ids may stream concurrently with guaranteed stream combinations - isConcurrentSessionConfigurationSupported() in order to assist the camera framework in knowing which camera ids may stream concurrently and whether certain concurrent session configurations will be supported by the camera HAL. Bug: 77960042 Test: builds Change-Id: I47caddb7ae5c7b1b2e926f7b877f53a367564d2a Signed-off-by: Jayant Chowdhary --- camera/provider/2.6/Android.bp | 1 + camera/provider/2.6/ICameraProvider.hal | 86 ++++++++++++++++++++++++- camera/provider/2.6/types.hal | 30 +++++++++ 3 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 camera/provider/2.6/types.hal diff --git a/camera/provider/2.6/Android.bp b/camera/provider/2.6/Android.bp index 16bd7927ac..e69819c863 100644 --- a/camera/provider/2.6/Android.bp +++ b/camera/provider/2.6/Android.bp @@ -7,6 +7,7 @@ hidl_interface { enabled: true, }, srcs: [ + "types.hal", "ICameraProvider.hal", "ICameraProviderCallback.hal", ], diff --git a/camera/provider/2.6/ICameraProvider.hal b/camera/provider/2.6/ICameraProvider.hal index 60b59a3ae7..0948db6ea3 100644 --- a/camera/provider/2.6/ICameraProvider.hal +++ b/camera/provider/2.6/ICameraProvider.hal @@ -17,14 +17,94 @@ package android.hardware.camera.provider@2.6; import @2.5::ICameraProvider; +import android.hardware.camera.common@1.0::Status; +import android.hardware.camera.device@3.4::StreamConfiguration; /** * Camera provider HAL + * + * @2.6::adds support for the getConcurrentStreamingCameraIds() and + * isConcurrentStreamCombinationSupported() + * @2.6::ICameraProviderCallback to receive physical camera availability + * callbacks for logical multi-cameras. */ interface ICameraProvider extends @2.5::ICameraProvider { /** - * @2.4::ICameraProvider::setCallback can be passed a - * @2.6::ICameraProviderCallback to receive physical camera availability - * callbacks for logical multi-cameras. + * getConcurrentStreamingCameraIds + * + * Get a vector of combinations of camera device ids that are able to + * configure streams concurrently. Each camera device advertised in a + * combination MUST at the very least support the following streams while + * streaming concurrently with the other camera ids in the combination. + * + * Target 1 Target 2 + * --------------------------------------------- + * | Type | Size | Type | Size | + * --------------------------------------------- + * | YUV | 1280 X 720 | | + * --------------------------------------------- + * | PRIV | 1280 X 720 | | + * --------------------------------------------- + * | YUV | 1280 X 720 | YUV |1280 X 720| + * --------------------------------------------- + * | PRIV | 1280 X 720 | PRIV |1280 X 720| + * --------------------------------------------- + * | PRIV | 1280 X 720 | YUV |1280 X 720| + * --------------------------------------------- + + * @return status Status code for the operation + * @return cameraIds a list of camera id combinations that support + * concurrent stream configurations with the minimum guarantees + * specified. */ + getConcurrentStreamingCameraIds() generates (Status status, vec> cameraIds); + + /** + * isConcurrentStreamCombinationSupported: + * + * Check for device support of specific camera stream combinations while + * streaming concurrently with other devices. + * + * The per device streamList must contain at least one output-capable stream, and may + * not contain more than one input-capable stream. + * In contrast to regular stream configuration the framework does not create + * or initialize any actual streams. This means that Hal must not use or + * consider the stream "id" value. + * + * ------------------------------------------------------------------------ + * + * Preconditions: + * + * The framework can call this method at any time before, during and + * after active session configuration per device. This means that calls must not + * impact the performance of pending camera requests in any way. In + * particular there must not be any glitches or delays during normal + * camera streaming. + * + * The framework must not call this method with any combination of camera + * ids that is not a subset of the camera ids advertised by getConcurrentStreamingCameraIds of + * the same provider. + * + * Performance requirements: + * This call is expected to be significantly faster than stream + * configuration. In general HW and SW camera settings must not be + * changed and there must not be a user-visible impact on camera performance. + * + * @param configs a vector of camera ids and their corresponding stream + * configurations that need to be queried for support. + * + * @return status Status code for the operation, one of: + * OK: + * On successful stream combination query. + * METHOD_NOT_SUPPORTED: + * The camera provider does not support stream combination query. + * INTERNAL_ERROR: + * The stream combination query cannot complete due to internal + * error. + * @return true in case the stream combination is supported, false otherwise. + * + * + */ + isConcurrentStreamCombinationSupported(vec configs) + generates (Status status, bool queryStatus); }; diff --git a/camera/provider/2.6/types.hal b/camera/provider/2.6/types.hal new file mode 100644 index 0000000000..24c62aa24d --- /dev/null +++ b/camera/provider/2.6/types.hal @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package android.hardware.camera.provider@2.6; + +import android.hardware.camera.device@3.4::StreamConfiguration; + +/** + * CameraIdAndStreamCombination: + * Pairs the cameraId and the StreamConfiguration to be + * tested with other concurrent camera id and StreamConfigurations + */ +struct CameraIdAndStreamCombination { + string cameraId; + + @3.4::StreamConfiguration streamConfiguration; +}; From 21e45434ef7ff0fcf91bc995101b99b50face098 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Mon, 27 Jan 2020 08:58:17 -0800 Subject: [PATCH 0506/1022] Resume-on-Reboot: use uevent to chown We now allow this device to change names to accomodate other board types that use pmem. Setting this in the HAL .rc file now causes SELinux errors on those platforms. Switch to using the ueventd.rc method to avoid this SELinux problem. Bug: 63928581 Bug: 146400078 Test: atest VtsHalRebootEscrowTargetTest Change-Id: If5b83c087810f52fef4039748e9015a5f95f2f2a --- rebootescrow/aidl/default/rebootescrow-default.rc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/rebootescrow/aidl/default/rebootescrow-default.rc b/rebootescrow/aidl/default/rebootescrow-default.rc index e7a9cfcb70..ad90465aa3 100644 --- a/rebootescrow/aidl/default/rebootescrow-default.rc +++ b/rebootescrow/aidl/default/rebootescrow-default.rc @@ -3,7 +3,3 @@ service vendor.rebootescrow-default /vendor/bin/hw/android.hardware.rebootescrow class hal user system group system - -on boot - chmod 770 /dev/access-kregistry - chown system system /dev/access-kregistry From 7e6f5f97c2cb49cd1498d301a749d98d978714ef Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Fri, 24 Jan 2020 17:36:47 -0800 Subject: [PATCH 0507/1022] rebootescrow: use property to find device To allow vendors to have different names for their devices, read the device name from a system property. Test: atest VtsHalRebootEscrowTargetTest Bug: 146400078 Change-Id: I93f37e14139532ab192795dcad27c586545a1bc4 --- rebootescrow/aidl/default/RebootEscrow.cpp | 4 ++-- .../aidl/default/include/rebootescrow-impl/RebootEscrow.h | 7 +++++-- rebootescrow/aidl/default/service.cpp | 8 +++++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/rebootescrow/aidl/default/RebootEscrow.cpp b/rebootescrow/aidl/default/RebootEscrow.cpp index 94d09010d9..5ae96f6086 100644 --- a/rebootescrow/aidl/default/RebootEscrow.cpp +++ b/rebootescrow/aidl/default/RebootEscrow.cpp @@ -29,7 +29,7 @@ namespace rebootescrow { using ::android::base::unique_fd; ndk::ScopedAStatus RebootEscrow::storeKey(const std::vector& kek) { - int rawFd = TEMP_FAILURE_RETRY(::open(REBOOT_ESCROW_DEVICE, O_WRONLY | O_NOFOLLOW | O_CLOEXEC)); + int rawFd = TEMP_FAILURE_RETRY(::open(devicePath_.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC)); unique_fd fd(rawFd); if (fd.get() < 0) { LOG(WARNING) << "Could not open reboot escrow device"; @@ -48,7 +48,7 @@ ndk::ScopedAStatus RebootEscrow::storeKey(const std::vector& kek) { } ndk::ScopedAStatus RebootEscrow::retrieveKey(std::vector* _aidl_return) { - int rawFd = TEMP_FAILURE_RETRY(::open(REBOOT_ESCROW_DEVICE, O_RDONLY | O_NOFOLLOW | O_CLOEXEC)); + int rawFd = TEMP_FAILURE_RETRY(::open(devicePath_.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)); unique_fd fd(rawFd); if (fd.get() < 0) { LOG(WARNING) << "Could not open reboot escrow device"; diff --git a/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h index 1ed73978d9..00ff16b2ea 100644 --- a/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h +++ b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h @@ -23,11 +23,14 @@ namespace android { namespace hardware { namespace rebootescrow { -static const char* REBOOT_ESCROW_DEVICE = "/dev/access-kregistry"; - class RebootEscrow : public BnRebootEscrow { + public: + explicit RebootEscrow(const std::string& devicePath) : devicePath_(devicePath) {} ndk::ScopedAStatus storeKey(const std::vector& kek) override; ndk::ScopedAStatus retrieveKey(std::vector* _aidl_return) override; + + private: + const std::string devicePath_; }; } // namespace rebootescrow diff --git a/rebootescrow/aidl/default/service.cpp b/rebootescrow/aidl/default/service.cpp index bd2378e513..8a8086b498 100644 --- a/rebootescrow/aidl/default/service.cpp +++ b/rebootescrow/aidl/default/service.cpp @@ -17,15 +17,21 @@ #include "rebootescrow-impl/RebootEscrow.h" #include +#include #include #include using aidl::android::hardware::rebootescrow::RebootEscrow; +constexpr auto kRebootEscrowDeviceProperty = "ro.rebootescrow.device"; +constexpr auto kRebootEscrowDeviceDefault = "/dev/access-kregistry"; + int main() { ABinderProcess_setThreadPoolMaxThreadCount(0); - auto re = ndk::SharedRefBase::make(); + auto rebootEscrowDevicePath = + android::base::GetProperty(kRebootEscrowDeviceProperty, kRebootEscrowDeviceDefault); + auto re = ndk::SharedRefBase::make(rebootEscrowDevicePath); const std::string instance = std::string() + RebootEscrow::descriptor + "/default"; binder_status_t status = AServiceManager_addService(re->asBinder().get(), instance.c_str()); CHECK(status == STATUS_OK); From 3fd70b020ea4393e84d4bfc1c1c35418b5a59752 Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Tue, 21 Jan 2020 13:15:09 -0800 Subject: [PATCH 0508/1022] Update sync fence related API for NNAPI - Allow IPreparedModel::executeFenced to measure gated durations. - Allow IPreparedModel::executeFenced to specify an optional deadline and aa optional post-gate-release maximum duration. Bug: 142778241 Bug: 141363565 Test: mm Change-Id: I1687ec5543f93ed9bb5d7fcf14dbe15ed5b5cd0d --- current.txt | 6 +- .../1.3/IFencedExecutionCallback.hal | 25 ++++-- neuralnetworks/1.3/IPreparedModel.hal | 78 ++++++++++++------- neuralnetworks/1.3/types.hal | 13 ++++ .../vts/functional/GeneratedTestHarness.cpp | 37 +++++---- .../1.3/vts/functional/ValidateRequest.cpp | 2 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 22 +++--- 7 files changed, 118 insertions(+), 65 deletions(-) diff --git a/current.txt b/current.txt index 75975f2626..74c0cbbb5b 100644 --- a/current.txt +++ b/current.txt @@ -665,10 +665,10 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer d1f382d14e1384b907d5bb5780df7f01934650d556fedbed2f15a90773c657d6 android.hardware.neuralnetworks@1.3::IDevice 4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback -29e26e83399b69c7998b787bd30426dd5baa2da350effca76bbee1ba877355c9 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback -384fd9fd6e4d43ea11d407e52ea81da5242c3c5f4b458b8707d8feb652a13e36 android.hardware.neuralnetworks@1.3::IPreparedModel +2fa3679ad7c94b5e88724adcd560c561041068a4ca565c63830e68101988746a android.hardware.neuralnetworks@1.3::IFencedExecutionCallback +237b23b126a66f3432658020fed78cdd06ba6297459436fe6bae0ba753370833 android.hardware.neuralnetworks@1.3::IPreparedModel 0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback -5f1a4e0c29fc686ed476f9f04eed35e4405d21288cb2746b978d6891de5cc37d android.hardware.neuralnetworks@1.3::types +3646950b10f7cacdafca13609b0e18496cea942f3bdfe920494661856eff48bb android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.3/IFencedExecutionCallback.hal b/neuralnetworks/1.3/IFencedExecutionCallback.hal index 39076b9a16..6030809406 100644 --- a/neuralnetworks/1.3/IFencedExecutionCallback.hal +++ b/neuralnetworks/1.3/IFencedExecutionCallback.hal @@ -38,11 +38,24 @@ interface IFencedExecutionCallback { * - DEVICE_UNAVAILABLE if driver is offline or busy * - GENERAL_FAILURE if the asynchronous task resulted in an * unspecified error - * @return timing Duration of execution. Unless MeasureTiming::YES was passed when - * launching the execution and status is NONE, all times must - * be reported as UINT64_MAX. A driver may choose to report - * any time as UINT64_MAX, indicating that particular measurement is - * not available. + * - MISSED_DEADLINE_* if the deadline for executing a model + * cannot be met + * - RESOURCE_EXHAUSTED_* if the task was aborted by the + * driver + * @return timingLaunched The duration starts when executeFenced is called and ends when + * executeFenced signals the returned syncFence. + * Unless MeasureTiming::YES was passed when + * launching the execution and status is NONE, all times + * must be reported as UINT64_MAX. A driver may choose to + * report any time as UINT64_MAX, indicating that particular + * measurement is not available. + * @return timingFenced The duration starts when all waitFor sync fences have been signaled + * and ends when executeFenced signals the returned syncFence. + * Unless MeasureTiming::YES was passed when + * launching the execution and status is NONE, all times + * must be reported as UINT64_MAX. A driver may choose to + * report any time as UINT64_MAX, indicating that particular + * measurement is not available. */ - getExecutionInfo() generates (ErrorStatus status, Timing timing); + getExecutionInfo() generates (ErrorStatus status, Timing timingLaunched, Timing timingFenced); }; diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal index f84bcf4ffc..d645de789c 100644 --- a/neuralnetworks/1.3/IPreparedModel.hal +++ b/neuralnetworks/1.3/IPreparedModel.hal @@ -21,6 +21,7 @@ import @1.2::MeasureTiming; import @1.2::OutputShape; import @1.2::Timing; import ErrorStatus; +import OptionalTimeoutDuration; import OptionalTimePoint; import Request; import IExecutionCallback; @@ -68,7 +69,7 @@ interface IPreparedModel extends @1.2::IPreparedModel { * There must be no failure unless the device itself is in a bad state. * * execute_1_3 can be called with an optional deadline. If the execution - * is not able to completed before the provided deadline, the execution + * is not able to be completed before the provided deadline, the execution * must be aborted, and either {@link * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due @@ -88,7 +89,7 @@ interface IPreparedModel extends @1.2::IPreparedModel { * The duration runs from the time the driver sees the call * to the execute_1_3 function to the time the driver invokes * the callback. - * @param deadline The time by which execution must complete. If the + * @param deadline The time by which the execution must complete. If the * execution cannot be finished by the deadline, the * execution must be aborted. * @param callback A callback object used to return the error status of @@ -139,7 +140,7 @@ interface IPreparedModel extends @1.2::IPreparedModel { * in a bad state. * * executeSynchronously_1_3 can be called with an optional deadline. If the - * execution is not able to completed before the provided deadline, the + * execution is not able to be completed before the provided deadline, the * execution must be aborted, and either {@link * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due @@ -159,7 +160,7 @@ interface IPreparedModel extends @1.2::IPreparedModel { * The duration runs from the time the driver sees the call * to the executeSynchronously_1_3 function to the time the driver * returns from the function. - * @param deadline The time by which execution must complete. If the + * @param deadline The time by which the execution must complete. If the * execution cannot be finished by the deadline, the * execution must be aborted. * @return status Error status of the execution, must be: @@ -194,52 +195,75 @@ interface IPreparedModel extends @1.2::IPreparedModel { * Launch a fenced asynchronous execution on a prepared model. * * The execution is performed asynchronously with respect to the caller. - * executeFenced must fully validate the request, and only accept one that is - * guaranteed to be completed, unless a hardware failure or kernel panic happens on the device. - * If there is an error during validation, executeFenced must immediately return with - * the corresponding ErrorStatus. If the request is valid and there is no error launching, - * executeFenced must dispatch an asynchronous task to perform the execution in the - * background, and immediately return with ErrorStatus::NONE, a sync_fence that will be - * signaled once the execution is completed, and a callback that can be used by the client - * to query the duration and runtime error status. If the task has finished - * before the call returns, empty handle may be returned for the sync fence. If the - * asynchronous task fails to launch, executeFenced must immediately return with - * ErrorStatus::GENERAL_FAILURE, and empty handle for the sync fence and nullptr - * for callback. The execution must wait for all the sync fences (if any) in wait_for to be - * signaled before starting the actual execution. - * - * If any of sync fences in wait_for changes to error status after the executeFenced - * call succeeds, the driver must immediately set the returned sync fence to error status. + * executeFenced must verify the inputs to the function are correct, and the usages + * of memory pools allocated by IDevice::allocate are valid. If there is an error, + * executeFenced must immediately return with the corresponding ErrorStatus, an empty + * handle for syncFence, and nullptr for callback. If the inputs to the function + * are valid and there is no error, executeFenced must dispatch an asynchronous task + * to perform the execution in the background, and immediately return with + * ErrorStatus::NONE, a sync fence that will be signaled once the execution is completed, + * and a callback that can be used by the client to query the duration and runtime error + * status. If the task has finished before the call returns, an empty handle may be returned + * for syncFence. The execution must wait for all the sync fences (if any) in waitFor + * to be signaled before starting the actual execution. * * When the asynchronous task has finished its execution, it must - * immediately signal the sync_fence created when dispatching. After - * the sync_fence is signaled, the task must not modify the content of + * immediately signal the syncFence returned from the executeFenced call. After + * the syncFence is signaled, the task must not modify the content of * any data object referenced by 'request' (described by the * {@link @1.0::DataLocation} of a {@link @1.0::RequestArgument}). * + * executeFenced can be called with an optional deadline and an optional duration. + * If the execution is not able to be completed before the provided deadline or + * within the timeout duration (measured from when all sync fences in waitFor are + * signaled), whichever comes earlier, the execution must be aborted, and either + * {@link ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link + * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due + * to an abort must be sent the same way as other errors, described above. + * If the service reports that it does not support execution deadlines via + * IDevice::supportsDeadlines, and executeFenced is called with a + * deadline or duration, then the argument is invalid, and + * {@link ErrorStatus::INVALID_ARGUMENT} must be returned. + * + * If any of the sync fences in waitFor changes to error status after the executeFenced + * call succeeds, or the execution is aborted because it cannot finish before the deadline + * has been reached or the duration has elapsed, the driver must immediately set the returned + * syncFence to error status. + * * Any number of calls to the executeFenced, execute* and executeSynchronously* * functions, in any combination, may be made concurrently, even on the same * IPreparedModel object. * * @param request The input and output information on which the prepared - * model is to be executed. + * model is to be executed. The outputs in the request must have + * fully specified dimensions. * @param waitFor A vector of sync fence file descriptors. * Execution must not start until all sync fences have been signaled. * @param measure Specifies whether or not to measure duration of the execution. - * The duration runs from the time the driver sees the call - * to the executeFenced function to the time sync_fence is triggered. + * @param deadline The time by which the execution must complete. If the + * execution cannot be finished by the deadline, the + * execution must be aborted. + * @param duration The length of time within which the execution must + * complete after all sync fences in waitFor are signaled. If the + * execution cannot be finished within the duration, the execution + * must be aborted. * @return status Error status of the call, must be: * - NONE if task is successfully launched * - DEVICE_UNAVAILABLE if driver is offline or busy * - GENERAL_FAILURE if there is an unspecified error * - INVALID_ARGUMENT if one of the input arguments is invalid, including * fences in error states. - * @return syncFence The sync fence that will be triggered when the task is completed. + * - MISSED_DEADLINE_* if the deadline for executing a model + * cannot be met + * - RESOURCE_EXHAUSTED_* if the task was aborted by the + * driver + * @return syncFence The sync fence that will be signaled when the task is completed. * The sync fence will be set to error if a critical error, * e.g. hardware failure or kernel panic, occurs when doing execution. * @return callback The IFencedExecutionCallback can be used to query information like duration * and error status when the execution is completed. */ - executeFenced(Request request, vec waitFor, MeasureTiming measure) + executeFenced(Request request, vec waitFor, MeasureTiming measure, + OptionalTimePoint deadline, OptionalTimeoutDuration duration) generates (ErrorStatus status, handle syncFence, IFencedExecutionCallback callback); }; diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index abc33e77d3..ed577e4d9d 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -5576,6 +5576,19 @@ safe_union OptionalTimePoint { uint64_t nanoseconds; }; +/** + * Optional timeout duration measured in nanoseconds. + */ +safe_union OptionalTimeoutDuration { + /** No time point provided. */ + Monostate none; + + /** + * Timeout duration measured in nanoseconds. + */ + uint64_t nanoseconds; +}; + /** * Return status of a function. */ diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 88837db349..8ea0b7eb47 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -80,6 +80,13 @@ enum class MemoryType { SHARED, DEVICE }; enum class IOType { INPUT, OUTPUT }; +static void waitForSyncFence(int syncFd) { + constexpr int kInfiniteTimeout = -1; + ASSERT_GT(syncFd, 0); + int r = sync_wait(syncFd, kInfiniteTimeout); + ASSERT_GE(r, 0); +} + struct TestConfig { Executor executor; MeasureTiming measureTiming; @@ -567,33 +574,29 @@ void EvaluatePreparedModel(const sp& device, const sp& case Executor::FENCED: { SCOPED_TRACE("fenced"); ErrorStatus result; - hidl_handle sync_fence_handle; - sp fenced_callback; + hidl_handle syncFenceHandle; + sp fencedCallback; Return ret = preparedModel->executeFenced( - request, {}, testConfig.measureTiming, - [&result, &sync_fence_handle, &fenced_callback]( + request, {}, testConfig.measureTiming, {}, {}, + [&result, &syncFenceHandle, &fencedCallback]( ErrorStatus error, const hidl_handle& handle, const sp& callback) { result = error; - sync_fence_handle = handle; - fenced_callback = callback; + syncFenceHandle = handle; + fencedCallback = callback; }); ASSERT_TRUE(ret.isOk()); if (result != ErrorStatus::NONE) { - ASSERT_EQ(sync_fence_handle.getNativeHandle(), nullptr); - ASSERT_EQ(fenced_callback, nullptr); + ASSERT_EQ(syncFenceHandle.getNativeHandle(), nullptr); + ASSERT_EQ(fencedCallback, nullptr); executionStatus = ErrorStatus::GENERAL_FAILURE; - } else if (sync_fence_handle.getNativeHandle()) { - constexpr int kInfiniteTimeout = -1; - int sync_fd = sync_fence_handle.getNativeHandle()->data[0]; - ASSERT_GT(sync_fd, 0); - int r = sync_wait(sync_fd, kInfiniteTimeout); - ASSERT_GE(r, 0); + } else if (syncFenceHandle.getNativeHandle()) { + waitForSyncFence(syncFenceHandle.getNativeHandle()->data[0]); } if (result == ErrorStatus::NONE) { - ASSERT_NE(fenced_callback, nullptr); - Return ret = fenced_callback->getExecutionInfo( - [&executionStatus, &timing](ErrorStatus error, Timing t) { + ASSERT_NE(fencedCallback, nullptr); + Return ret = fencedCallback->getExecutionInfo( + [&executionStatus, &timing](ErrorStatus error, Timing t, Timing) { executionStatus = error; timing = t; }); diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index 1ddd09c033..2fd9b647f1 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -143,7 +143,7 @@ static void validate(const sp& preparedModel, const std::string& { SCOPED_TRACE(message + " [executeFenced]"); Return ret = preparedModel->executeFenced( - request, {}, MeasureTiming::NO, + request, {}, MeasureTiming::NO, {}, {}, [](ErrorStatus error, const hidl_handle& handle, const sp& callback) { if (error != ErrorStatus::DEVICE_UNAVAILABLE) { diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index c84f5b70e7..896ace65b9 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -136,17 +136,17 @@ void validateBurst(const sp& preparedModel, const V1_0::Request& // Validate sync_fence handles for dispatch with valid input void validateExecuteFenced(const sp& preparedModel, const Request& request) { SCOPED_TRACE("Expecting request to fail [executeFenced]"); - Return ret_null = - preparedModel->executeFenced(request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO, - [](ErrorStatus error, const hidl_handle& handle, - const sp& callback) { - // TODO: fix this once sample driver impl is merged. - if (error != ErrorStatus::DEVICE_UNAVAILABLE) { - ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); - } - ASSERT_EQ(handle.getNativeHandle(), nullptr); - ASSERT_EQ(callback, nullptr); - }); + Return ret_null = preparedModel->executeFenced( + request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO, {}, {}, + [](ErrorStatus error, const hidl_handle& handle, + const sp& callback) { + // TODO: fix this once sample driver impl is merged. + if (error != ErrorStatus::DEVICE_UNAVAILABLE) { + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); + } + ASSERT_EQ(handle.getNativeHandle(), nullptr); + ASSERT_EQ(callback, nullptr); + }); ASSERT_TRUE(ret_null.isOk()); } From f2e21c27fd3505988168eb927a1d35721be4b242 Mon Sep 17 00:00:00 2001 From: Kyounghan Lee Date: Wed, 29 Jan 2020 14:56:15 +0900 Subject: [PATCH 0509/1022] wifi(implementation): Clear wifi event callback objects while stopping This fixes a deadlock between WifiNative and HalDeviceManager because it removes about 30 times callbacks of IWifiEventCallback#onFailure() or onStop(). Such excessive callbacks within a short period tend to make high probabilities of the deadlock. Note: This is a side effect of how the framework is registering multiple callbacks. But, unfortunately there is no HAL API to unregister callback. So, this is somewhat of a workaround fix. Bug: 144137870 Test: Verified that the HAL no longer accumulates callbacks from framework. Test: Device boots up and connects to wifi networks. Change-Id: I441e2f815a0a49c3936615f06a65a6ed5366a628 --- wifi/1.4/default/wifi.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wifi/1.4/default/wifi.cpp b/wifi/1.4/default/wifi.cpp index 4f48d7e7a6..9c6b0f0f16 100644 --- a/wifi/1.4/default/wifi.cpp +++ b/wifi/1.4/default/wifi.cpp @@ -124,6 +124,8 @@ WifiStatus Wifi::startInternal() { } } LOG(ERROR) << "Wifi HAL start failed"; + // Clear the event callback objects since the HAL start failed. + event_cb_handler_.invalidate(); } return wifi_status; } @@ -158,6 +160,8 @@ WifiStatus Wifi::stopInternal( } LOG(ERROR) << "Wifi HAL stop failed"; } + // Clear the event callback objects since the HAL is now stopped. + event_cb_handler_.invalidate(); return wifi_status; } From 4da7c6c9974b4c0fa7cdd33225f621d4d5cfb50d Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Thu, 16 Jan 2020 17:06:36 -0800 Subject: [PATCH 0510/1022] Camera: add webcam HAL@3.6 support First CL to setup webcam HAL to support HIDL camera device 3.6. Follow up CL will add actual offline processing capability. Test: TestingCamera.apk Bug: 135142453 Change-Id: Ifcd1b22f42d08b0fa5dc6039125c1d979b8104c2 --- .../ExternalCameraDevice_3_4.h | 2 +- camera/device/3.6/default/Android.bp | 66 ++++++ .../3.6/default/ExternalCameraDevice.cpp | 91 +++++++++ .../default/ExternalCameraDeviceSession.cpp | 100 +++++++++ camera/device/3.6/default/OWNERS | 1 + .../ExternalCameraDeviceSession.h | 191 ++++++++++++++++++ .../ExternalCameraDevice_3_6.h | 77 +++++++ camera/provider/2.4/default/Android.bp | 5 +- .../ExternalCameraProviderImpl_2_4.cpp | 16 +- 9 files changed, 545 insertions(+), 4 deletions(-) create mode 100644 camera/device/3.6/default/Android.bp create mode 100644 camera/device/3.6/default/ExternalCameraDevice.cpp create mode 100644 camera/device/3.6/default/ExternalCameraDeviceSession.cpp create mode 100644 camera/device/3.6/default/OWNERS create mode 100644 camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h create mode 100644 camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h index bd7980780b..1958fcbab5 100644 --- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h +++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h @@ -105,7 +105,7 @@ protected: // Calls into virtual member function. Do not use it in constructor status_t initCameraCharacteristics(); // Init available capabilities keys - status_t initAvailableCapabilities( + virtual status_t initAvailableCapabilities( ::android::hardware::camera::common::V1_0::helper::CameraMetadata*); // Init non-device dependent keys virtual status_t initDefaultCharsKeys( diff --git a/camera/device/3.6/default/Android.bp b/camera/device/3.6/default/Android.bp new file mode 100644 index 0000000000..ce51185193 --- /dev/null +++ b/camera/device/3.6/default/Android.bp @@ -0,0 +1,66 @@ +// +// 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. +// + +cc_library_headers { + name: "camera.device@3.6-external-impl_headers", + vendor: true, + export_include_dirs: ["include/ext_device_v3_6_impl"] +} + +cc_library_shared { + name: "camera.device@3.6-external-impl", + defaults: ["hidl_defaults"], + proprietary: true, + vendor: true, + srcs: [ + "ExternalCameraDevice.cpp", + "ExternalCameraDeviceSession.cpp", + ], + shared_libs: [ + "libhidlbase", + "libutils", + "libcutils", + "camera.device@3.2-impl", + "camera.device@3.3-impl", + "camera.device@3.4-external-impl", + "camera.device@3.5-external-impl", + "android.hardware.camera.device@3.2", + "android.hardware.camera.device@3.3", + "android.hardware.camera.device@3.4", + "android.hardware.camera.device@3.5", + "android.hardware.camera.device@3.6", + "android.hardware.camera.provider@2.4", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", + "liblog", + "libhardware", + "libcamera_metadata", + "libfmq", + "libsync", + "libyuv", + "libjpeg", + "libexif", + "libtinyxml2" + ], + static_libs: [ + "android.hardware.camera.common@1.0-helper", + ], + local_include_dirs: ["include/ext_device_v3_6_impl"], + export_shared_lib_headers: [ + "libfmq", + ], +} diff --git a/camera/device/3.6/default/ExternalCameraDevice.cpp b/camera/device/3.6/default/ExternalCameraDevice.cpp new file mode 100644 index 0000000000..244c7dd460 --- /dev/null +++ b/camera/device/3.6/default/ExternalCameraDevice.cpp @@ -0,0 +1,91 @@ +/* + * 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. + */ + +#define LOG_TAG "ExtCamDev@3.6" +//#define LOG_NDEBUG 0 +#include + +#include "ExternalCameraDevice_3_6.h" + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_6 { +namespace implementation { + +ExternalCameraDevice::ExternalCameraDevice( + const std::string& cameraId, const ExternalCameraConfig& cfg) : + V3_5::implementation::ExternalCameraDevice(cameraId, cfg) {} + +ExternalCameraDevice::~ExternalCameraDevice() {} + +sp ExternalCameraDevice::createSession( + const sp& cb, + const ExternalCameraConfig& cfg, + const std::vector& sortedFormats, + const CroppingType& croppingType, + const common::V1_0::helper::CameraMetadata& chars, + const std::string& cameraId, + unique_fd v4l2Fd) { + return new ExternalCameraDeviceSession( + cb, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd)); +} + +#define UPDATE(tag, data, size) \ +do { \ + if (metadata->update((tag), (data), (size))) { \ + ALOGE("Update " #tag " failed!"); \ + return -EINVAL; \ + } \ +} while (0) + +status_t ExternalCameraDevice::initAvailableCapabilities( + ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) { + status_t res = + V3_4::implementation::ExternalCameraDevice::initAvailableCapabilities(metadata); + + if (res != OK) { + return res; + } + + camera_metadata_entry caps = metadata->find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES); + std::vector availableCapabilities; + + for (size_t i = 0; i < caps.count; i++) { + uint8_t capability = caps.data.u8[i]; + availableCapabilities.push_back(capability); + } + + // Add OFFLINE_PROCESSING capability to device 3.6 + availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING); + + UPDATE(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, + availableCapabilities.data(), + availableCapabilities.size()); + + return OK; +} + +#undef UPDATE + +} // namespace implementation +} // namespace V3_6 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + diff --git a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp new file mode 100644 index 0000000000..e14ae992b8 --- /dev/null +++ b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp @@ -0,0 +1,100 @@ +/* + * 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. + */ + +#define LOG_TAG "ExtCamDevSsn@3.6" +#include + +#include +#include "ExternalCameraDeviceSession.h" + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_6 { +namespace implementation { + +ExternalCameraDeviceSession::ExternalCameraDeviceSession( + const sp& callback, + const ExternalCameraConfig& cfg, + const std::vector& sortedFormats, + const CroppingType& croppingType, + const common::V1_0::helper::CameraMetadata& chars, + const std::string& cameraId, + unique_fd v4l2Fd) : + V3_5::implementation::ExternalCameraDeviceSession( + callback, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd)) { +} + +ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {} + + +Return ExternalCameraDeviceSession::configureStreams_3_6( + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_3_6_cb _hidl_cb) { + V3_2::StreamConfiguration config_v32; + V3_3::HalStreamConfiguration outStreams_v33; + V3_6::HalStreamConfiguration outStreams; + const V3_4::StreamConfiguration& requestedConfiguration_3_4 = requestedConfiguration.v3_4; + Mutex::Autolock _il(mInterfaceLock); + + config_v32.operationMode = requestedConfiguration_3_4.operationMode; + config_v32.streams.resize(requestedConfiguration_3_4.streams.size()); + uint32_t blobBufferSize = 0; + int numStallStream = 0; + for (size_t i = 0; i < config_v32.streams.size(); i++) { + config_v32.streams[i] = requestedConfiguration_3_4.streams[i].v3_2; + if (config_v32.streams[i].format == PixelFormat::BLOB) { + blobBufferSize = requestedConfiguration_3_4.streams[i].bufferSize; + numStallStream++; + } + } + + // Fail early if there are multiple BLOB streams + if (numStallStream > kMaxStallStream) { + ALOGE("%s: too many stall streams (expect <= %d, got %d)", __FUNCTION__, + kMaxStallStream, numStallStream); + _hidl_cb(Status::ILLEGAL_ARGUMENT, outStreams); + return Void(); + } + + Status status = configureStreams(config_v32, &outStreams_v33, blobBufferSize); + + outStreams.streams.resize(outStreams_v33.streams.size()); + for (size_t i = 0; i < outStreams.streams.size(); i++) { + outStreams.streams[i].v3_4.v3_3 = outStreams_v33.streams[i]; + // TODO: implement it later + outStreams.streams[i].supportOffline = false; + } + _hidl_cb(status, outStreams); + return Void(); +} + +Return ExternalCameraDeviceSession::switchToOffline( + const hidl_vec& streamsToKeep, + ICameraDeviceSession::switchToOffline_cb _hidl_cb) { + // TODO: implement this + (void) streamsToKeep; + (void) _hidl_cb; + return Void(); +} + +} // namespace implementation +} // namespace V3_6 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android diff --git a/camera/device/3.6/default/OWNERS b/camera/device/3.6/default/OWNERS new file mode 100644 index 0000000000..f48a95c5b3 --- /dev/null +++ b/camera/device/3.6/default/OWNERS @@ -0,0 +1 @@ +include platform/frameworks/av:/camera/OWNERS diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h new file mode 100644 index 0000000000..0e57c4c243 --- /dev/null +++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h @@ -0,0 +1,191 @@ +/* + * 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_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE3SESSION_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE3SESSION_H + +#include +#include +#include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h> + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_6 { +namespace implementation { + +using ::android::hardware::camera::device::V3_2::BufferCache; +using ::android::hardware::camera::device::V3_2::CameraMetadata; +using ::android::hardware::camera::device::V3_2::CaptureRequest; +using ::android::hardware::camera::device::V3_2::CaptureResult; +using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback; +using ::android::hardware::camera::device::V3_2::RequestTemplate; +using ::android::hardware::camera::device::V3_2::Stream; +using ::android::hardware::camera::device::V3_5::StreamConfiguration; +using ::android::hardware::camera::device::V3_6::ICameraDeviceSession; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::external::common::ExternalCameraConfig; +using ::android::hardware::graphics::common::V1_0::PixelFormat; +using ::android::hardware::MQDescriptorSync; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; +using ::android::Mutex; +using ::android::base::unique_fd; + +using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format; +using ::android::hardware::camera::device::V3_4::implementation::CroppingType; + +struct ExternalCameraDeviceSession : public V3_5::implementation::ExternalCameraDeviceSession { + + ExternalCameraDeviceSession(const sp&, + const ExternalCameraConfig& cfg, + const std::vector& sortedFormats, + const CroppingType& croppingType, + const common::V1_0::helper::CameraMetadata& chars, + const std::string& cameraId, + unique_fd v4l2Fd); + virtual ~ExternalCameraDeviceSession(); + + // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when + // dealing with minor version revs and simultaneous implementation and interface inheritance + virtual sp getInterface() override { + return new TrampolineSessionInterface_3_6(this); + } + + static Status isStreamCombinationSupported(const V3_2::StreamConfiguration& config, + const std::vector& supportedFormats, + const ExternalCameraConfig& devCfg) { + return V3_4::implementation::ExternalCameraDeviceSession::isStreamCombinationSupported( + config, supportedFormats, devCfg); + } + +protected: + // Methods from v3.5 and earlier will trampoline to inherited implementation + Return configureStreams_3_6( + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_3_6_cb _hidl_cb); + + Return switchToOffline( + const hidl_vec& streamsToKeep, + ICameraDeviceSession::switchToOffline_cb _hidl_cb); + +private: + + struct TrampolineSessionInterface_3_6 : public ICameraDeviceSession { + TrampolineSessionInterface_3_6(sp parent) : + mParent(parent) {} + + virtual Return constructDefaultRequestSettings( + RequestTemplate type, + V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override { + return mParent->constructDefaultRequestSettings(type, _hidl_cb); + } + + virtual Return configureStreams( + const V3_2::StreamConfiguration& requestedConfiguration, + V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override { + return mParent->configureStreams(requestedConfiguration, _hidl_cb); + } + + virtual Return processCaptureRequest(const hidl_vec& requests, + const hidl_vec& cachesToRemove, + V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override { + return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb); + } + + virtual Return getCaptureRequestMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override { + return mParent->getCaptureRequestMetadataQueue(_hidl_cb); + } + + virtual Return getCaptureResultMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override { + return mParent->getCaptureResultMetadataQueue(_hidl_cb); + } + + virtual Return flush() override { + return mParent->flush(); + } + + virtual Return close() override { + return mParent->close(); + } + + virtual Return configureStreams_3_3( + const V3_2::StreamConfiguration& requestedConfiguration, + configureStreams_3_3_cb _hidl_cb) override { + return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb); + } + + virtual Return configureStreams_3_4( + const V3_4::StreamConfiguration& requestedConfiguration, + configureStreams_3_4_cb _hidl_cb) override { + return mParent->configureStreams_3_4(requestedConfiguration, _hidl_cb); + } + + virtual Return processCaptureRequest_3_4(const hidl_vec& requests, + const hidl_vec& cachesToRemove, + ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override { + return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb); + } + + virtual Return configureStreams_3_5( + const StreamConfiguration& requestedConfiguration, + configureStreams_3_5_cb _hidl_cb) override { + return mParent->configureStreams_3_5(requestedConfiguration, _hidl_cb); + } + + virtual Return signalStreamFlush( + const hidl_vec& requests, + uint32_t streamConfigCounter) override { + return mParent->signalStreamFlush(requests, streamConfigCounter); + } + + virtual Return isReconfigurationRequired(const V3_2::CameraMetadata& oldSessionParams, + const V3_2::CameraMetadata& newSessionParams, + ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb) override { + return mParent->isReconfigurationRequired(oldSessionParams, newSessionParams, _hidl_cb); + } + + virtual Return configureStreams_3_6( + const StreamConfiguration& requestedConfiguration, + configureStreams_3_6_cb _hidl_cb) override { + return mParent->configureStreams_3_6(requestedConfiguration, _hidl_cb); + } + + virtual Return switchToOffline( + const hidl_vec& streamsToKeep, + switchToOffline_cb _hidl_cb) override { + return mParent->switchToOffline(streamsToKeep, _hidl_cb); + } + + private: + sp mParent; + }; +}; + +} // namespace implementation +} // namespace V3_6 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE3SESSION_H diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h new file mode 100644 index 0000000000..046c9d817e --- /dev/null +++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h @@ -0,0 +1,77 @@ +/* + * 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_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H + +#include "ExternalCameraDeviceSession.h" +#include <../../../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h> + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_6 { +namespace implementation { + +using namespace ::android::hardware::camera::device; +using ::android::hardware::camera::device::V3_5::ICameraDevice; +using ::android::hardware::camera::common::V1_0::CameraResourceCost; +using ::android::hardware::camera::common::V1_0::TorchMode; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::external::common::ExternalCameraConfig; +using ::android::hardware::camera::external::common::Size; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +/* + * The camera device HAL implementation is opened lazily (via the open call) + */ +struct ExternalCameraDevice : public V3_5::implementation::ExternalCameraDevice { + + // Called by external camera provider HAL. + // Provider HAL must ensure the uniqueness of CameraDevice object per cameraId, or there could + // be multiple CameraDevice trying to access the same physical camera. Also, provider will have + // to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying + // camera is detached. + ExternalCameraDevice(const std::string& cameraId, const ExternalCameraConfig& cfg); + virtual ~ExternalCameraDevice(); + +protected: + virtual sp createSession( + const sp&, + const ExternalCameraConfig& cfg, + const std::vector& sortedFormats, + const CroppingType& croppingType, + const common::V1_0::helper::CameraMetadata& chars, + const std::string& cameraId, + unique_fd v4l2Fd) override; + + virtual status_t initAvailableCapabilities( + ::android::hardware::camera::common::V1_0::helper::CameraMetadata*) override; +}; + +} // namespace implementation +} // namespace V3_6 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp index 9203b8d585..627ddf40bc 100644 --- a/camera/provider/2.4/default/Android.bp +++ b/camera/provider/2.4/default/Android.bp @@ -49,6 +49,7 @@ cc_library_shared { "android.hardware.camera.device@3.3", "android.hardware.camera.device@3.4", "android.hardware.camera.device@3.5", + "android.hardware.camera.device@3.6", "android.hardware.camera.provider@2.4", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", @@ -60,6 +61,7 @@ cc_library_shared { "camera.device@3.4-impl", "camera.device@3.5-external-impl", "camera.device@3.5-impl", + "camera.device@3.6-external-impl", "libcamera_metadata", "libcutils", "libhardware", @@ -73,7 +75,8 @@ cc_library_shared { ], header_libs: [ "camera.device@3.4-external-impl_headers", - "camera.device@3.5-external-impl_headers" + "camera.device@3.5-external-impl_headers", + "camera.device@3.6-external-impl_headers" ], export_include_dirs: ["."], } diff --git a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp index a6fd288125..2bfced2c62 100644 --- a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp +++ b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp @@ -26,6 +26,7 @@ #include "ExternalCameraProviderImpl_2_4.h" #include "ExternalCameraDevice_3_4.h" #include "ExternalCameraDevice_3_5.h" +#include "ExternalCameraDevice_3_6.h" namespace android { namespace hardware { @@ -73,6 +74,7 @@ ExternalCameraProviderImpl_2_4::ExternalCameraProviderImpl_2_4() : switch(mPreferredHal3MinorVersion) { case 4: case 5: + case 6: // OK break; default: @@ -171,6 +173,12 @@ Return ExternalCameraProviderImpl_2_4::getCameraDeviceInterface_V3_x( cameraId, mCfg); break; } + case 6: { + ALOGV("Constructing v3.6 external camera device"); + deviceImpl = new device::V3_6::implementation::ExternalCameraDevice( + cameraId, mCfg); + break; + } default: ALOGE("%s: Unknown HAL minor version %d!", __FUNCTION__, mPreferredHal3MinorVersion); _hidl_cb(Status::INTERNAL_ERROR, nullptr); @@ -202,7 +210,9 @@ void ExternalCameraProviderImpl_2_4::addExternalCamera(const char* devName) { ALOGI("ExtCam: adding %s to External Camera HAL!", devName); Mutex::Autolock _l(mLock); std::string deviceName; - if (mPreferredHal3MinorVersion == 5) { + if (mPreferredHal3MinorVersion == 6) { + deviceName = std::string("device@3.6/external/") + devName; + } else if (mPreferredHal3MinorVersion == 5) { deviceName = std::string("device@3.5/external/") + devName; } else { deviceName = std::string("device@3.4/external/") + devName; @@ -249,7 +259,9 @@ void ExternalCameraProviderImpl_2_4::deviceAdded(const char* devName) { void ExternalCameraProviderImpl_2_4::deviceRemoved(const char* devName) { Mutex::Autolock _l(mLock); std::string deviceName; - if (mPreferredHal3MinorVersion == 5) { + if (mPreferredHal3MinorVersion == 6) { + deviceName = std::string("device@3.6/external/") + devName; + } else if (mPreferredHal3MinorVersion == 5) { deviceName = std::string("device@3.5/external/") + devName; } else { deviceName = std::string("device@3.4/external/") + devName; From fc16668e86c277b30a162502aa57b3fbcea9d52f Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 29 Jan 2020 11:02:09 -0800 Subject: [PATCH 0511/1022] Cleanup IRadio/IRadioConfig HAL Removed unused import statements. Consistent between internal and AOSP. More accurate names for ModemFeatures. Test: make Change-Id: Icbfe35d472ab3f7fd6cd50b4888e3c478dd29fd2 --- current.txt | 8 ++-- radio/1.5/IRadio.hal | 20 ++++----- radio/1.5/IRadioResponse.hal | 5 +-- radio/1.5/types.hal | 42 +++++++++---------- .../1.5/vts/functional/radio_hidl_hal_api.cpp | 5 ++- .../functional/radio_hidl_hal_utils_v1_5.h | 7 ++-- radio/1.5/vts/functional/radio_response.cpp | 14 +++---- radio/config/1.3/types.hal | 18 ++++---- 8 files changed, 58 insertions(+), 61 deletions(-) diff --git a/current.txt b/current.txt index 75975f2626..0e47f24842 100644 --- a/current.txt +++ b/current.txt @@ -677,11 +677,11 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback 62cf050c593c1ec34b49178b5bdde72dd9b80d9bad3eb184e4f0cd564d28678c android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types -50e22cd55ad5499e68e81541bbc67bd10e59c1b9f3ff8cc7ba70dcb0d2918381 android.hardware.radio@1.5::types -8cc3306e8cd755d04521d1611b217b9d13a2a76d2af57cbea8f875333b3363f7 android.hardware.radio@1.5::IRadio +88fb40d98b89cfaafad33b06c95e5dcd51c4470962e8fbe80ed22884407f98a1 android.hardware.radio@1.5::types +8062d0a1a03594dd8b448adcf6f08856b5720f7e33f9b785a21d3ef74a4f211d android.hardware.radio@1.5::IRadio e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication -7b77721a7716e163f5cc5f2830ed5616b953fcf0e5406f69de0fde5ce95e4184 android.hardware.radio@1.5::IRadioResponse -2fd107f3de1b7e36825e241a88dfae8edf3a77c166cb746f00ddf6440ab78db1 android.hardware.radio.config@1.3::types +7f2439b48bda2961c6d629d0415eee66d519142cf9537f05e9d285153c70ca85 android.hardware.radio@1.5::IRadioResponse +dcc8872337f0135e81970e1d8d5fd7139160dc80e9be76f0ae05290fa7e472b8 android.hardware.radio.config@1.3::types a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication 0006ab8e8b0910cbd3bbb08d5f17d5fac7d65a2bdad5f2334e4851db9d1e6fa8 android.hardware.radio.config@1.3::IRadioConfigResponse diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal index bc405008a0..2ec92e54d1 100644 --- a/radio/1.5/IRadio.hal +++ b/radio/1.5/IRadio.hal @@ -18,10 +18,8 @@ package android.hardware.radio@1.5; import @1.0::CdmaSmsMessage; import @1.2::DataRequestReason; -import @1.4::DataProfileInfo; import @1.4::IRadio; import @1.5::AccessNetwork; -import @1.5::BarringInfo; import @1.5::DataProfileInfo; import @1.5::IndicationFilter; import @1.5::LinkAddress; @@ -118,13 +116,13 @@ interface IRadio extends @1.4::IRadio { vec specifiers); /** - * Starts a network scan + * Starts a network scan. * * @param serial Serial number of request. * @param request Defines the radio networks/bands/channels which need to be scanned. * - * Same API as @1.4::IRadio.startNetworkScan_1_4, except using - * 1.5 version of NetworkScanRequest + * Same API as @1.4::IRadio.startNetworkScan_1_4, except using the + * 1.5 NetworkScanRequest as the input param. */ oneway startNetworkScan_1_5(int32_t serial, NetworkScanRequest request); @@ -166,14 +164,14 @@ interface IRadio extends @1.4::IRadio { * Response function is IRadioResponse.setupDataCallResponse_1_5() * * Note this API is the same as the 1.4 version except using the - * 1.5 AccessNetwork, DataProfileInto, and link addresses as the input param. + * 1.5 AccessNetwork, DataProfileInto, and LinkAddress as the input param. */ oneway setupDataCall_1_5(int32_t serial, AccessNetwork accessNetwork, DataProfileInfo dataProfileInfo, bool roamingAllowed, DataRequestReason reason, vec addresses, vec dnses); /** - * Set an apn to initial attach network + * Set an APN to initial attach network. * * @param serial Serial number of request. * @param dataProfileInfo data profile containing APN settings @@ -189,7 +187,7 @@ interface IRadio extends @1.4::IRadio { * Send data profiles of the current carrier to the modem. * * @param serial Serial number of request. - * @param profiles Array of DataProfile to set. + * @param profiles Array of DataProfileInfo to set. * * Response callback is IRadioResponse.setDataProfileResponse_1_5() * @@ -230,7 +228,7 @@ interface IRadio extends @1.4::IRadio { * * Prevents the reporting of specified unsolicited indications from the radio. This is used * for power saving in instances when those indications are not needed. If unset, defaults to - * @1.2::IndicationFilter:ALL. + * @1.5::IndicationFilter:ALL. * * @param serial Serial number of request. * @param indicationFilter 32-bit bitmap of IndicationFilter. Bits set to 1 indicate the @@ -250,7 +248,7 @@ interface IRadio extends @1.4::IRadio { oneway getBarringInfo(int32_t serial); /** - * Request current voice registration state + * Request current voice registration state. * * @param serial Serial number of request. * @@ -259,7 +257,7 @@ interface IRadio extends @1.4::IRadio { oneway getVoiceRegistrationState_1_5(int32_t serial); /** - * Request current data registration state + * Request current data registration state. * * @param serial Serial number of request. * diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal index 6a2187f69d..aa8b526ffa 100644 --- a/radio/1.5/IRadioResponse.hal +++ b/radio/1.5/IRadioResponse.hal @@ -21,10 +21,9 @@ import @1.0::SendSmsResult; import @1.4::IRadioResponse; import @1.5::BarringInfo; import @1.5::CellInfo; +import @1.5::PersoSubstate; import @1.5::RegStateResult; import @1.5::SetupDataCallResult; -import @1.4::SetupDataCallResult; -import @1.5::PersoSubstate; /** * Interface declaring response functions to solicited radio requests. @@ -177,6 +176,7 @@ interface IRadioResponse extends @1.4::IRadioResponse { oneway getBarringInfoResponse(RadioResponseInfo info, vec barringInfos); /** + * @param info Response info struct containing response type, serial no. and error * @param voiceRegResponse Current Voice registration response as defined by RegStateResult * in types.hal * @@ -215,7 +215,6 @@ interface IRadioResponse extends @1.4::IRadioResponse { */ oneway getCellInfoListResponse_1_5(RadioResponseInfo info, vec cellInfo); - /** * @param info Response info struct containing response type, serial no. and error * diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index cf195ccb0a..a0868337dd 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -19,19 +19,15 @@ package android.hardware.radio@1.5; import @1.0::ApnAuthType; import @1.0::DataProfileId; import @1.0::DataProfileInfoType; -import @1.0::CdmaSignalStrength; -import @1.0::EvdoSignalStrength; import @1.0::GsmSignalStrength; import @1.0::LteSignalStrength; import @1.0::PersoSubstate; -import @1.0::RadioAccessFamily; import @1.0::RadioError; import @1.0::RegState; import @1.0::TimeStampType; import @1.1::EutranBands; import @1.1::GeranBands; import @1.1::RadioAccessNetworks; -import @1.1::RadioAccessSpecifier; import @1.1::ScanStatus; import @1.1::ScanType; import @1.1::UtranBands; @@ -43,7 +39,6 @@ import @1.2::CellIdentityTdscdma; import @1.2::CellIdentityLte; import @1.2::CellInfoCdma; import @1.2::IndicationFilter; -import @1.2::NetworkScanRequest; import @1.2::TdscdmaSignalStrength; import @1.2::WcdmaSignalStrength; import @1.4::AccessNetwork; @@ -51,11 +46,11 @@ import @1.4::ApnTypes; import @1.4::CellIdentityNr; import @1.4::DataCallFailCause; import @1.4::DataConnActiveStatus; -import @1.4::DataProfileInfo; import @1.4::LteVopsInfo; import @1.4::NrIndicators; import @1.4::NrSignalStrength; import @1.4::PdpProtocolType; +import @1.4::RadioAccessFamily; import @1.4::RadioTechnology; import android.hidl.safe_union@1.0::Monostate; @@ -131,7 +126,7 @@ struct SignalThresholdInfo { /** Signal Measurement Type */ SignalMeasurementType signalMeasurement; - /** A hysteresis time in milliseconds to prevent flapping. A value of 0 disables hysteresis */ + /** A hysteresis time in milliseconds to prevent flapping. A value of 0 disables hysteresis. */ int32_t hysteresisMs; /** @@ -175,7 +170,7 @@ enum RadioAccessNetworks : @1.1::RadioAccessNetworks { }; /** - * Overwritten from @1.1::RadioAccessSpecifier to add NGRAN and NgranBands + * Overwritten from @1.1::RadioAccessSpecifier to add NGRAN and NgranBands. */ struct RadioAccessSpecifier { /** @@ -264,8 +259,7 @@ enum UtranBands : @1.1::UtranBands { }; /** - * Overwritten from @1.2::NetworkScanRequest to update - * RadioAccessSpecifier to 1.5 version + * Overwritten from @1.2::NetworkScanRequest to update RadioAccessSpecifier to 1.5 version. */ struct NetworkScanRequest { ScanType type; @@ -328,11 +322,10 @@ enum ApnTypes : @1.4::ApnTypes { }; /** - * Extended from @1.4::DataProfileInfo to update ApnTypes to 1.5 version and replace mtu with + * Overwritten from @1.4::DataProfileInfo to update ApnTypes to 1.5 version and replace mtu with * mtuV4 and mtuV6. In the future, this must be extended instead of overwritten. */ struct DataProfileInfo { - /** ID of the data profile. */ DataProfileId profileId; @@ -445,8 +438,8 @@ struct LinkAddress { }; /** - * Overwritten from @1.4::SetupDataCallResult in order to update the addresses to 1.5 - * version. In 1.5 the type of addresses changes to vector of LinkAddress, and mtu is replaced by + * Overwritten from @1.4::SetupDataCallResult in order to update the addresses to 1.5 version. + * In 1.5 the type of addresses changes to vector of LinkAddress, and mtu is replaced by * mtuV4 and mtuV6. */ struct SetupDataCallResult { @@ -687,7 +680,7 @@ struct CellInfo { } ratSpecificInfo; }; -/** A union representing the CellIdentity of a single cell */ +/** A union representing the CellIdentity of a single cell. */ safe_union CellIdentity { Monostate noinit; @@ -708,7 +701,7 @@ safe_union CellIdentity { * -NGRAN - 3gpp 38.331 Sec 6.3.2 UAC-BarringInfo and 22.261 Sec 6.22.2.[2-3] */ enum BarringServiceType : int32_t { - /** Applicabe to UTRAN */ + /** Applicable to UTRAN */ /** Barring for all CS services, including registration */ CS_SERVICE, /** Barring for all PS services, including registration */ @@ -963,14 +956,14 @@ struct RegStateResult { string registeredPlmn; /** - * Access-technology-specific registration information, such as for Cdma2000. + * Access-technology-specific registration information, such as for CDMA2000. */ safe_union AccessTechnologySpecificInfo { Monostate noinit; struct Cdma2000RegistrationInfo { /** - * concurrent services support indicator. if registered on a CDMA system. + * Concurrent services support indicator. if registered on a CDMA system. * false - Concurrent services not supported, * true - Concurrent services supported */ @@ -999,10 +992,10 @@ struct RegStateResult { struct EutranRegistrationInfo { /** * Network capabilities for voice over PS services. This info is valid only on LTE - * network and must be present when device is camped on LTE. vopsInfo must be empty when + * network and must be present when device is camped on LTE. VopsInfo must be empty when * device is camped only on 2G/3G. */ - LteVopsInfo lteVopsInfo; // LTE network capability + LteVopsInfo lteVopsInfo; /** * The parameters of NR 5G Non-Standalone. This value is only valid on E-UTRAN, @@ -1032,17 +1025,20 @@ struct NetworkScanResult { }; /** - * Additional personalization categories in addition to those specified in 3GPP TS 22.022 and 3GPP2 C.S0068-0. + * Additional personalization categories in addition to those specified in 3GPP TS 22.022 and + * 3GPP2 C.S0068-0. */ enum PersoSubstate : @1.0::PersoSubstate { SIM_SPN, SIM_SPN_PUK, - SIM_SP_EHPLMN, // Equivalent Home PLMN + /** Equivalent Home PLMN */ + SIM_SP_EHPLMN, SIM_SP_EHPLMN_PUK, SIM_ICCID, SIM_ICCID_PUK, SIM_IMPI, SIM_IMPI_PUK, - SIM_NS_SP, // Network subset service provider + /** Network subset service provider */ + SIM_NS_SP, SIM_NS_SP_PUK, }; diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp index 09305de703..621825fa52 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp @@ -969,7 +969,10 @@ TEST_F(RadioHidlTest_v1_5, setDataProfile_1_5) { } } -TEST_F(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancalled) { +/* + * Test IRadio.setRadioPower_1_5() for the response returned. + */ +TEST_F(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancelled) { // Set radio power to off. serial = GetRandomSerialNumber(); radio_v1_5->setRadioPower_1_5(serial, false, false, false); diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index d1c17e6fab..ce7b1ab8e7 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -114,9 +114,6 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon Return supplyNetworkDepersonalizationResponse(const RadioResponseInfo& info, int32_t remainingRetries); - Return supplySimDepersonalizationResponse(const RadioResponseInfo& info, - ::android::hardware::radio::V1_5::PersoSubstate persoType, int32_t remainingRetries); - Return getCurrentCallsResponse( const RadioResponseInfo& info, const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& calls); @@ -579,6 +576,10 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon Return sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& info, const SendSmsResult& sms); + + Return supplySimDepersonalizationResponse( + const RadioResponseInfo& info, + ::android::hardware::radio::V1_5::PersoSubstate persoType, int32_t remainingRetries); }; /* Callback class for radio indication */ diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp index a62d086d80..26401eb800 100644 --- a/radio/1.5/vts/functional/radio_response.cpp +++ b/radio/1.5/vts/functional/radio_response.cpp @@ -62,13 +62,6 @@ Return RadioResponse_v1_5::supplyNetworkDepersonalizationResponse( return Void(); } -Return RadioResponse_v1_5::supplySimDepersonalizationResponse( - const RadioResponseInfo& /*info*/, - ::android::hardware::radio::V1_5::PersoSubstate /*persoType*/, - int32_t /*remainingRetries*/) { - return Void(); -} - Return RadioResponse_v1_5::getCurrentCallsResponse( const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& /*calls*/) { @@ -1011,3 +1004,10 @@ Return RadioResponse_v1_5::sendCdmaSmsExpectMoreResponse(const RadioRespon const SendSmsResult& /*sms*/) { return Void(); } + +Return RadioResponse_v1_5::supplySimDepersonalizationResponse( + const RadioResponseInfo& /*info*/, + ::android::hardware::radio::V1_5::PersoSubstate /*persoType*/, + int32_t /*remainingRetries*/) { + return Void(); +} diff --git a/radio/config/1.3/types.hal b/radio/config/1.3/types.hal index 7860006707..aef0ff8a21 100644 --- a/radio/config/1.3/types.hal +++ b/radio/config/1.3/types.hal @@ -50,17 +50,17 @@ enum ModemFeatures : int32_t { /** 3GPP capability. */ THREE_GPP_REG = 1 << 1, /** CDMA 2000 with EHRPD capability. */ - CDMA2000_EHRPD_REG = 1 << 2, - /** GSM capability. */ - GERAN_REG = 1 << 3, + CDMA2000_EHRPD = 1 << 2, + /** GSM/EDGE capability. */ + GERAN = 1 << 3, /** UMTS capability. */ - UTRAN_REG = 1 << 4, + UTRAN = 1 << 4, /** LTE capability. */ - EUTRAN_REG = 1 << 5, + EUTRAN = 1 << 5, /** 5G capability. */ - NGRAN_REG = 1 << 6, - /** Dual Connectivity capability. */ - EN_DC_REG = 1 << 7, + NGRAN = 1 << 6, + /** 5G dual connectivity capability. */ + EN_DC = 1 << 7, /** VoLTE capability (IMS registered). */ PS_VOICE_REG = 1 << 8, /** CS voice call capability. */ @@ -72,7 +72,7 @@ enum ModemFeatures : int32_t { /** Network scanning capability. */ NETWORK_SCAN = 1 << 12, /** CDMA capability for SIM associated with modem. */ - CSIM = 1 << 13, + CSIM_APP = 1 << 13, }; struct ConcurrentModemFeatures { From f3e4d217ee0696f465456703e36384497524fb8b Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Wed, 29 Jan 2020 15:32:24 -0800 Subject: [PATCH 0512/1022] audio: Remove dynamic dependency on HIDL interface libs from service This is intended to reduce memory footprint of the default HAL service. The inteface libraries were only used to retrieve interface descriptors and use generated code to register as service. This code was replaced with static code from HIDL transport library. Bug: 148115870 Test: check audio on devices Change-Id: Ie8713d513cfbde64120546ba0db1cf80fd366138 --- .../all-versions/default/service/Android.bp | 18 ---- .../all-versions/default/service/service.cpp | 102 ++++++++++-------- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp index f58a599024..3e8b715706 100644 --- a/audio/common/all-versions/default/service/Android.bp +++ b/audio/common/all-versions/default/service/Android.bp @@ -24,24 +24,6 @@ cc_binary { "liblog", "libutils", "libhardware", - "android.hardware.audio@2.0", - "android.hardware.audio@4.0", - "android.hardware.audio@5.0", - "android.hardware.audio@6.0", - "android.hardware.audio.common@2.0", - "android.hardware.audio.common@4.0", - "android.hardware.audio.common@5.0", - "android.hardware.audio.common@6.0", - "android.hardware.audio.effect@2.0", - "android.hardware.audio.effect@4.0", - "android.hardware.audio.effect@5.0", - "android.hardware.audio.effect@6.0", - "android.hardware.bluetooth.a2dp@1.0", - "android.hardware.bluetooth.audio@2.0", - "android.hardware.soundtrigger@2.0", - "android.hardware.soundtrigger@2.1", - "android.hardware.soundtrigger@2.2", - "android.hardware.soundtrigger@2.3", ], } diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp index 00bcb19c2f..8fa4918c05 100644 --- a/audio/common/all-versions/default/service/service.cpp +++ b/audio/common/all-versions/default/service/service.cpp @@ -16,20 +16,9 @@ #define LOG_TAG "audiohalservice" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include + #include #include #include @@ -39,13 +28,20 @@ using namespace android::hardware; using android::OK; +using InterfacesList = std::vector; + /** Try to register the provided factories in the provided order. * If any registers successfully, do not register any other and return true. * If all fail, return false. */ -template -bool registerPassthroughServiceImplementations() { - return ((registerPassthroughServiceImplementation() != OK) && ...); +template +static bool registerPassthroughServiceImplementations(Iter first, Iter last) { + for (; first != last; ++first) { + if (registerPassthroughServiceImplementation(*first) == OK) { + return true; + } + } + return false; } int main(int /* argc */, char* /* argv */ []) { @@ -62,36 +58,58 @@ int main(int /* argc */, char* /* argv */ []) { } configureRpcThreadpool(16, true /*callerWillJoin*/); - // Keep versions on a separate line for easier parsing + // Automatic formatting tries to compact the lines, making them less readable // clang-format off - LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations< - audio::V6_0::IDevicesFactory, - audio::V5_0::IDevicesFactory, - audio::V4_0::IDevicesFactory, - audio::V2_0::IDevicesFactory>()), - "Could not register audio core API"); + const std::vector mandatoryInterfaces = { + { + "Audio Core API", + "android.hardware.audio@6.0::IDevicesFactory", + "android.hardware.audio@5.0::IDevicesFactory", + "android.hardware.audio@4.0::IDevicesFactory", + "android.hardware.audio@2.0::IDevicesFactory" + }, + { + "Audio Effect API", + "android.hardware.audio.effect@6.0::IEffectsFactory", + "android.hardware.audio.effect@5.0::IEffectsFactory", + "android.hardware.audio.effect@4.0::IEffectsFactory", + "android.hardware.audio.effect@2.0::IEffectsFactory", + } + }; - LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations< - audio::effect::V6_0::IEffectsFactory, - audio::effect::V5_0::IEffectsFactory, - audio::effect::V4_0::IEffectsFactory, - audio::effect::V2_0::IEffectsFactory>()), - "Could not register audio effect API"); + const std::vector optionalInterfaces = { + { + "Soundtrigger API", + "android.hardware.soundtrigger@2.3::ISoundTriggerHw", + "android.hardware.soundtrigger@2.2::ISoundTriggerHw", + "android.hardware.soundtrigger@2.1::ISoundTriggerHw", + "android.hardware.soundtrigger@2.0::ISoundTriggerHw", + }, + { + "Bluetooth Audio API", + "android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvidersFactory" + }, + // remove the old HIDL when Bluetooth Audio Hal V2 has offloading supported + { + "Bluetooth Audio Offload API", + "android.hardware.a2dp@1.0::IBluetoothAudioOffload" + } + }; // clang-format on - ALOGW_IF((registerPassthroughServiceImplementations< - soundtrigger::V2_3::ISoundTriggerHw, soundtrigger::V2_2::ISoundTriggerHw, - soundtrigger::V2_1::ISoundTriggerHw, soundtrigger::V2_0::ISoundTriggerHw>()), - "Could not register soundtrigger API"); + for (const auto& listIter : mandatoryInterfaces) { + auto iter = listIter.begin(); + const std::string& interfaceFamilyName = *iter++; + LOG_ALWAYS_FATAL_IF(!registerPassthroughServiceImplementations(iter, listIter.end()), + "Could not register %s", interfaceFamilyName.c_str()); + } - ALOGW_IF(registerPassthroughServiceImplementations< - bluetooth::audio::V2_0::IBluetoothAudioProvidersFactory>(), - "Could not register Bluetooth audio API"); - - // remove the old HIDL when Bluetooth Audio Hal V2 has offloading supported - ALOGW_IF(registerPassthroughServiceImplementations< - bluetooth::a2dp::V1_0::IBluetoothAudioOffload>(), - "Could not register Bluetooth audio offload API"); + for (const auto& listIter : optionalInterfaces) { + auto iter = listIter.begin(); + const std::string& interfaceFamilyName = *iter++; + ALOGW_IF(!registerPassthroughServiceImplementations(iter, listIter.end()), + "Could not register %s", interfaceFamilyName.c_str()); + } joinRpcThreadpool(); } From 8bcb49230914b5ced2c8b76de38d283000fc597c Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Wed, 15 Jan 2020 19:34:50 -0800 Subject: [PATCH 0513/1022] Use regex names for EVS HAL implementations This change deprecates EvsEnumeratorHw, which has been a name for EVS HAL Enumerator implementations, and uses regex names for them. New method, isHardware(), is added to IEvsEnumerator and the clients should use this method to tell whether current service is EVS manager or driver. Bug: 147010694 Test: m -j Test: atest VtsHalEvsV1_1TargetTest Change-Id: I89441936734fde0f0cc2f0151ee9b6622f61814d Signed-off-by: Changyeon Jo --- automotive/evs/1.1/IEvsEnumerator.hal | 7 +++++++ automotive/evs/1.1/default/EvsEnumerator.h | 1 + automotive/evs/1.1/default/ServiceNames.h | 2 +- .../evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp | 2 +- compatibility_matrices/compatibility_matrix.current.xml | 1 + 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/automotive/evs/1.1/IEvsEnumerator.hal b/automotive/evs/1.1/IEvsEnumerator.hal index 1695821baa..7752b0e330 100644 --- a/automotive/evs/1.1/IEvsEnumerator.hal +++ b/automotive/evs/1.1/IEvsEnumerator.hal @@ -47,4 +47,11 @@ interface IEvsEnumerator extends @1.0::IEvsEnumerator { * configured differently by another client. */ openCamera_1_1(string cameraId, Stream streamCfg) generates (IEvsCamera evsCamera); + + /** + * Tells whether this is EVS manager or HAL implementation. + * + * @return result False for EVS manager implementations and true for all others. + */ + isHardware() generates (bool result); }; diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h index 475ec76b93..ca35dc6f8a 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.h +++ b/automotive/evs/1.1/default/EvsEnumerator.h @@ -59,6 +59,7 @@ public: Return getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) override; Return> openCamera_1_1(const hidl_string& cameraId, const Stream& streamCfg) override; + Return isHardware() override { return true; } // Implementation details EvsEnumerator(); diff --git a/automotive/evs/1.1/default/ServiceNames.h b/automotive/evs/1.1/default/ServiceNames.h index 1178da5a9c..84b1697d0f 100644 --- a/automotive/evs/1.1/default/ServiceNames.h +++ b/automotive/evs/1.1/default/ServiceNames.h @@ -14,4 +14,4 @@ * limitations under the License. */ -const static char kEnumeratorServiceName[] = "EvsEnumeratorHw"; +const static char kEnumeratorServiceName[] = "hw/0"; diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index 4fc4e4c144..1a622452da 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -117,7 +117,7 @@ public: pEnumerator = getService(service_name); ASSERT_NE(pEnumerator.get(), nullptr); - mIsHwModule = !service_name.compare(kEnumeratorName); + mIsHwModule = pEnumerator->isHardware(); } virtual void TearDown() override { diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index b9d300126f..c2566e918f 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -45,6 +45,7 @@ IEvsEnumerator default + [a-z]+/[0-9]+ From b0e72927dcba484561a0906491c0f60bf845838f Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Thu, 30 Jan 2020 09:00:35 -0800 Subject: [PATCH 0514/1022] Change the location of a configuration file Move a configuration xml file from /system/etc to /vendor/etc. Bug: 148424402 Test: m -j selinux_policy Test: check violations while EVS service is running. Change-Id: I17c74798564bb0f5684157c483b45857b39ab6bd Signed-off-by: Changyeon Jo --- automotive/evs/1.1/default/Android.bp | 2 +- automotive/evs/1.1/default/EvsEnumerator.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp index 88fd6575ad..a7c7b4282b 100644 --- a/automotive/evs/1.1/default/Android.bp +++ b/automotive/evs/1.1/default/Android.bp @@ -41,7 +41,7 @@ cc_binary { prebuilt_etc { name: "evs_default_configuration.xml", - + soc_specific: true, src: "resources/evs_default_configuration.xml", sub_dir: "automotive/evs", } diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp index a010729ce6..cb7403a7da 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.cpp +++ b/automotive/evs/1.1/default/EvsEnumerator.cpp @@ -42,7 +42,7 @@ EvsEnumerator::EvsEnumerator() { // Add sample camera data to our list of cameras // In a real driver, this would be expected to can the available hardware sConfigManager = - ConfigManager::Create("/etc/automotive/evs/evs_sample_configuration.xml"); + ConfigManager::Create("/vendor/etc/automotive/evs/evs_default_configuration.xml"); for (auto v : sConfigManager->getCameraList()) { sCameraList.emplace_back(v.c_str()); } From 7f2ce25f647ed236921a82504ef05267f1e1a4a3 Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Tue, 21 Jan 2020 10:08:12 -0800 Subject: [PATCH 0515/1022] Camera: add webcam offline processing support Test: CTS/VTS in follow up change Bug: 135142453 Change-Id: I3e4dc201ac495e0966e47d45494a0db6c1c3b24a --- .../default/ExternalCameraDeviceSession.cpp | 596 +++--------------- .../3.4/default/ExternalCameraUtils.cpp | 547 +++++++++++++++- .../ExternalCameraDeviceSession.h | 225 +++---- .../ExternalCameraUtils.h | 147 ++++- .../default/ExternalCameraDeviceSession.cpp | 10 +- .../ExternalCameraDeviceSession.h | 118 ++-- camera/device/3.6/default/Android.bp | 1 + .../default/ExternalCameraDeviceSession.cpp | 275 +++++++- .../default/ExternalCameraOfflineSession.cpp | 554 ++++++++++++++++ .../ExternalCameraDeviceSession.h | 37 +- .../ExternalCameraOfflineSession.h | 232 +++++++ camera/provider/2.5/default/Android.bp | 5 +- 12 files changed, 2033 insertions(+), 714 deletions(-) create mode 100644 camera/device/3.6/default/ExternalCameraOfflineSession.cpp create mode 100644 camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp index 9ff0d74687..5f8674219c 100644 --- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp +++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp @@ -81,8 +81,6 @@ bool tryLock(std::mutex& mutex) return locked; } -buffer_handle_t sEmptyBuffer = nullptr; - } // Anonymous namespace // Static instances @@ -119,8 +117,8 @@ bool ExternalCameraDeviceSession::initialize() { std::string make, model; if (ret < 0) { ALOGW("%s v4l2 QUERYCAP failed", __FUNCTION__); - make = "Generic UVC webcam"; - model = "Generic UVC webcam"; + mExifMake = "Generic UVC webcam"; + mExifModel = "Generic UVC webcam"; } else { // capability.card is UTF-8 encoded char card[32]; @@ -134,11 +132,11 @@ bool ExternalCameraDeviceSession::initialize() { } } if (j == 0 || card[j - 1] != '\0') { - make = "Generic UVC webcam"; - model = "Generic UVC webcam"; + mExifMake = "Generic UVC webcam"; + mExifModel = "Generic UVC webcam"; } else { - make = card; - model = card; + mExifMake = card; + mExifModel = card; } } @@ -147,7 +145,7 @@ bool ExternalCameraDeviceSession::initialize() { ALOGE("%s: init OutputThread failed!", __FUNCTION__); return true; } - mOutputThread->setExifMakeModel(make, model); + mOutputThread->setExifMakeModel(mExifMake, mExifModel); status_t status = initDefaultRequests(); if (status != OK) { @@ -161,7 +159,7 @@ bool ExternalCameraDeviceSession::initialize() { ALOGE("%s: invalid request fmq", __FUNCTION__); return true; } - mResultMetadataQueue = std::make_shared( + mResultMetadataQueue = std::make_shared( kMetadataMsgQueueSize, false /* non blocking */); if (!mResultMetadataQueue->isValid()) { ALOGE("%s: invalid result fmq", __FUNCTION__); @@ -183,7 +181,7 @@ bool ExternalCameraDeviceSession::isInitFailed() { } void ExternalCameraDeviceSession::initOutputThread() { - mOutputThread = new OutputThread(this, mCroppingType); + mOutputThread = new OutputThread(this, mCroppingType, mCameraCharacteristics); } void ExternalCameraDeviceSession::closeOutputThread() { @@ -518,35 +516,9 @@ Status ExternalCameraDeviceSession::importBufferLocked(int32_t streamId, uint64_t bufId, buffer_handle_t buf, /*out*/buffer_handle_t** outBufPtr, bool allowEmptyBuf) { - - if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) { - if (allowEmptyBuf) { - *outBufPtr = &sEmptyBuffer; - return Status::OK; - } else { - ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); - return Status::ILLEGAL_ARGUMENT; - } - } - - CirculatingBuffers& cbs = mCirculatingBuffers[streamId]; - if (cbs.count(bufId) == 0) { - if (buf == nullptr) { - ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); - return Status::ILLEGAL_ARGUMENT; - } - // Register a newly seen buffer - buffer_handle_t importedBuf = buf; - sHandleImporter.importBuffer(importedBuf); - if (importedBuf == nullptr) { - ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId); - return Status::INTERNAL_ERROR; - } else { - cbs[bufId] = importedBuf; - } - } - *outBufPtr = &cbs[bufId]; - return Status::OK; + return importBufferImpl( + mCirculatingBuffers, sHandleImporter, streamId, + bufId, buf, outBufPtr, allowEmptyBuf); } Status ExternalCameraDeviceSession::importRequestLockedImpl( @@ -791,15 +763,32 @@ void ExternalCameraDeviceSession::notifyError( //TODO: refactor with processCaptureResult Status ExternalCameraDeviceSession::processCaptureRequestError( - const std::shared_ptr& req) { + const std::shared_ptr& req, + /*out*/std::vector* outMsgs, + /*out*/std::vector* outResults) { ATRACE_CALL(); // Return V4L2 buffer to V4L2 buffer queue - enqueueV4l2Frame(req->frameIn); + sp v4l2Frame = + static_cast(req->frameIn.get()); + enqueueV4l2Frame(v4l2Frame); - // NotifyShutter - notifyShutter(req->frameNumber, req->shutterTs); + if (outMsgs == nullptr) { + notifyShutter(req->frameNumber, req->shutterTs); + notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST); + } else { + NotifyMsg shutter; + shutter.type = MsgType::SHUTTER; + shutter.msg.shutter.frameNumber = req->frameNumber; + shutter.msg.shutter.timestamp = req->shutterTs; - notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST); + NotifyMsg error; + error.type = MsgType::ERROR; + error.msg.error.frameNumber = req->frameNumber; + error.msg.error.errorStreamId = -1; + error.msg.error.errorCode = ErrorCode::ERROR_REQUEST; + outMsgs->push_back(shutter); + outMsgs->push_back(error); + } // Fill output buffers hidl_vec results; @@ -826,16 +815,22 @@ Status ExternalCameraDeviceSession::processCaptureRequestError( mInflightFrames.erase(req->frameNumber); } - // Callback into framework - invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true); - freeReleaseFences(results); + if (outResults == nullptr) { + // Callback into framework + invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true); + freeReleaseFences(results); + } else { + outResults->push_back(result); + } return Status::OK; } Status ExternalCameraDeviceSession::processCaptureResult(std::shared_ptr& req) { ATRACE_CALL(); // Return V4L2 buffer to V4L2 buffer queue - enqueueV4l2Frame(req->frameIn); + sp v4l2Frame = + static_cast(req->frameIn.get()); + enqueueV4l2Frame(v4l2Frame); // NotifyShutter notifyShutter(req->frameNumber, req->shutterTs); @@ -923,29 +918,10 @@ void ExternalCameraDeviceSession::invokeProcessCaptureResultCallback( mProcessCaptureResultLock.unlock(); } -void ExternalCameraDeviceSession::freeReleaseFences(hidl_vec& results) { - for (auto& result : results) { - if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) { - native_handle_t* handle = const_cast( - result.inputBuffer.releaseFence.getNativeHandle()); - native_handle_close(handle); - native_handle_delete(handle); - } - for (auto& buf : result.outputBuffers) { - if (buf.releaseFence.getNativeHandle() != nullptr) { - native_handle_t* handle = const_cast( - buf.releaseFence.getNativeHandle()); - native_handle_close(handle); - native_handle_delete(handle); - } - } - } - return; -} - ExternalCameraDeviceSession::OutputThread::OutputThread( - wp parent, - CroppingType ct) : mParent(parent), mCroppingType(ct) {} + wp parent, CroppingType ct, + const common::V1_0::helper::CameraMetadata& chars) : + mParent(parent), mCroppingType(ct), mCameraCharacteristics(chars) {} ExternalCameraDeviceSession::OutputThread::~OutputThread() {} @@ -955,88 +931,6 @@ void ExternalCameraDeviceSession::OutputThread::setExifMakeModel( mExifModel = model; } -uint32_t ExternalCameraDeviceSession::OutputThread::getFourCcFromLayout( - const YCbCrLayout& layout) { - intptr_t cb = reinterpret_cast(layout.cb); - intptr_t cr = reinterpret_cast(layout.cr); - if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) { - // Interleaved format - if (layout.cb > layout.cr) { - return V4L2_PIX_FMT_NV21; - } else { - return V4L2_PIX_FMT_NV12; - } - } else if (layout.chromaStep == 1) { - // Planar format - if (layout.cb > layout.cr) { - return V4L2_PIX_FMT_YVU420; // YV12 - } else { - return V4L2_PIX_FMT_YUV420; // YU12 - } - } else { - return FLEX_YUV_GENERIC; - } -} - -int ExternalCameraDeviceSession::OutputThread::getCropRect( - CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) { - if (out == nullptr) { - ALOGE("%s: out is null", __FUNCTION__); - return -1; - } - - uint32_t inW = inSize.width; - uint32_t inH = inSize.height; - uint32_t outW = outSize.width; - uint32_t outH = outSize.height; - - // Handle special case where aspect ratio is close to input but scaled - // dimension is slightly larger than input - float arIn = ASPECT_RATIO(inSize); - float arOut = ASPECT_RATIO(outSize); - if (isAspectRatioClose(arIn, arOut)) { - out->left = 0; - out->top = 0; - out->width = inW; - out->height = inH; - return 0; - } - - if (ct == VERTICAL) { - uint64_t scaledOutH = static_cast(outH) * inW / outW; - if (scaledOutH > inH) { - ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d", - __FUNCTION__, outW, outH, inW, inH); - return -1; - } - scaledOutH = scaledOutH & ~0x1; // make it multiple of 2 - - out->left = 0; - out->top = ((inH - scaledOutH) / 2) & ~0x1; - out->width = inW; - out->height = static_cast(scaledOutH); - ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d", - __FUNCTION__, inW, inH, outW, outH, out->top, static_cast(scaledOutH)); - } else { - uint64_t scaledOutW = static_cast(outW) * inH / outH; - if (scaledOutW > inW) { - ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d", - __FUNCTION__, outW, outH, inW, inH); - return -1; - } - scaledOutW = scaledOutW & ~0x1; // make it multiple of 2 - - out->left = ((inW - scaledOutW) / 2) & ~0x1; - out->top = 0; - out->width = static_cast(scaledOutW); - out->height = inH; - ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d", - __FUNCTION__, inW, inH, outW, outH, out->top, static_cast(scaledOutW)); - } - - return 0; -} - int ExternalCameraDeviceSession::OutputThread::cropAndScaleLocked( sp& in, const Size& outSz, YCbCrLayout* out) { Size inSz = {in->mWidth, in->mHeight}; @@ -1274,265 +1168,6 @@ int ExternalCameraDeviceSession::OutputThread::cropAndScaleThumbLocked( return 0; } -int ExternalCameraDeviceSession::OutputThread::formatConvertLocked( - const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) { - int ret = 0; - switch (format) { - case V4L2_PIX_FMT_NV21: - ret = libyuv::I420ToNV21( - static_cast(in.y), - in.yStride, - static_cast(in.cb), - in.cStride, - static_cast(in.cr), - in.cStride, - static_cast(out.y), - out.yStride, - static_cast(out.cr), - out.cStride, - sz.width, - sz.height); - if (ret != 0) { - ALOGE("%s: convert to NV21 buffer failed! ret %d", - __FUNCTION__, ret); - return ret; - } - break; - case V4L2_PIX_FMT_NV12: - ret = libyuv::I420ToNV12( - static_cast(in.y), - in.yStride, - static_cast(in.cb), - in.cStride, - static_cast(in.cr), - in.cStride, - static_cast(out.y), - out.yStride, - static_cast(out.cb), - out.cStride, - sz.width, - sz.height); - if (ret != 0) { - ALOGE("%s: convert to NV12 buffer failed! ret %d", - __FUNCTION__, ret); - return ret; - } - break; - case V4L2_PIX_FMT_YVU420: // YV12 - case V4L2_PIX_FMT_YUV420: // YU12 - // TODO: maybe we can speed up here by somehow save this copy? - ret = libyuv::I420Copy( - static_cast(in.y), - in.yStride, - static_cast(in.cb), - in.cStride, - static_cast(in.cr), - in.cStride, - static_cast(out.y), - out.yStride, - static_cast(out.cb), - out.cStride, - static_cast(out.cr), - out.cStride, - sz.width, - sz.height); - if (ret != 0) { - ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d", - __FUNCTION__, ret); - return ret; - } - break; - case FLEX_YUV_GENERIC: - // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow. - ALOGE("%s: unsupported flexible yuv layout" - " y %p cb %p cr %p y_str %d c_str %d c_step %d", - __FUNCTION__, out.y, out.cb, out.cr, - out.yStride, out.cStride, out.chromaStep); - return -1; - default: - ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format); - return -1; - } - return 0; -} - -int ExternalCameraDeviceSession::OutputThread::encodeJpegYU12( - const Size & inSz, const YCbCrLayout& inLayout, - int jpegQuality, const void *app1Buffer, size_t app1Size, - void *out, const size_t maxOutSize, size_t &actualCodeSize) -{ - /* libjpeg is a C library so we use C-style "inheritance" by - * putting libjpeg's jpeg_destination_mgr first in our custom - * struct. This allows us to cast jpeg_destination_mgr* to - * CustomJpegDestMgr* when we get it passed to us in a callback */ - struct CustomJpegDestMgr { - struct jpeg_destination_mgr mgr; - JOCTET *mBuffer; - size_t mBufferSize; - size_t mEncodedSize; - bool mSuccess; - } dmgr; - - jpeg_compress_struct cinfo = {}; - jpeg_error_mgr jerr; - - /* Initialize error handling with standard callbacks, but - * then override output_message (to print to ALOG) and - * error_exit to set a flag and print a message instead - * of killing the whole process */ - cinfo.err = jpeg_std_error(&jerr); - - cinfo.err->output_message = [](j_common_ptr cinfo) { - char buffer[JMSG_LENGTH_MAX]; - - /* Create the message */ - (*cinfo->err->format_message)(cinfo, buffer); - ALOGE("libjpeg error: %s", buffer); - }; - cinfo.err->error_exit = [](j_common_ptr cinfo) { - (*cinfo->err->output_message)(cinfo); - if(cinfo->client_data) { - auto & dmgr = - *reinterpret_cast(cinfo->client_data); - dmgr.mSuccess = false; - } - }; - /* Now that we initialized some callbacks, let's create our compressor */ - jpeg_create_compress(&cinfo); - - /* Initialize our destination manager */ - dmgr.mBuffer = static_cast(out); - dmgr.mBufferSize = maxOutSize; - dmgr.mEncodedSize = 0; - dmgr.mSuccess = true; - cinfo.client_data = static_cast(&dmgr); - - /* These lambdas become C-style function pointers and as per C++11 spec - * may not capture anything */ - dmgr.mgr.init_destination = [](j_compress_ptr cinfo) { - auto & dmgr = reinterpret_cast(*cinfo->dest); - dmgr.mgr.next_output_byte = dmgr.mBuffer; - dmgr.mgr.free_in_buffer = dmgr.mBufferSize; - ALOGV("%s:%d jpeg start: %p [%zu]", - __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize); - }; - - dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) { - ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__); - return 0; - }; - - dmgr.mgr.term_destination = [](j_compress_ptr cinfo) { - auto & dmgr = reinterpret_cast(*cinfo->dest); - dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer; - ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize); - }; - cinfo.dest = reinterpret_cast(&dmgr); - - /* We are going to be using JPEG in raw data mode, so we are passing - * straight subsampled planar YCbCr and it will not touch our pixel - * data or do any scaling or anything */ - cinfo.image_width = inSz.width; - cinfo.image_height = inSz.height; - cinfo.input_components = 3; - cinfo.in_color_space = JCS_YCbCr; - - /* Initialize defaults and then override what we want */ - jpeg_set_defaults(&cinfo); - - jpeg_set_quality(&cinfo, jpegQuality, 1); - jpeg_set_colorspace(&cinfo, JCS_YCbCr); - cinfo.raw_data_in = 1; - cinfo.dct_method = JDCT_IFAST; - - /* Configure sampling factors. The sampling factor is JPEG subsampling 420 - * because the source format is YUV420. Note that libjpeg sampling factors - * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and - * 1 V value for each 2 Y values */ - cinfo.comp_info[0].h_samp_factor = 2; - cinfo.comp_info[0].v_samp_factor = 2; - cinfo.comp_info[1].h_samp_factor = 1; - cinfo.comp_info[1].v_samp_factor = 1; - cinfo.comp_info[2].h_samp_factor = 1; - cinfo.comp_info[2].v_samp_factor = 1; - - /* Let's not hardcode YUV420 in 6 places... 5 was enough */ - int maxVSampFactor = std::max( { - cinfo.comp_info[0].v_samp_factor, - cinfo.comp_info[1].v_samp_factor, - cinfo.comp_info[2].v_samp_factor - }); - int cVSubSampling = cinfo.comp_info[0].v_samp_factor / - cinfo.comp_info[1].v_samp_factor; - - /* Start the compressor */ - jpeg_start_compress(&cinfo, TRUE); - - /* Compute our macroblock height, so we can pad our input to be vertically - * macroblock aligned. - * TODO: Does it need to be horizontally MCU aligned too? */ - - size_t mcuV = DCTSIZE*maxVSampFactor; - size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV); - - /* libjpeg uses arrays of row pointers, which makes it really easy to pad - * data vertically (unfortunately doesn't help horizontally) */ - std::vector yLines (paddedHeight); - std::vector cbLines(paddedHeight/cVSubSampling); - std::vector crLines(paddedHeight/cVSubSampling); - - uint8_t *py = static_cast(inLayout.y); - uint8_t *pcr = static_cast(inLayout.cr); - uint8_t *pcb = static_cast(inLayout.cb); - - for(uint32_t i = 0; i < paddedHeight; i++) - { - /* Once we are in the padding territory we still point to the last line - * effectively replicating it several times ~ CLAMP_TO_EDGE */ - int li = std::min(i, inSz.height - 1); - yLines[i] = static_cast(py + li * inLayout.yStride); - if(i < paddedHeight / cVSubSampling) - { - crLines[i] = static_cast(pcr + li * inLayout.cStride); - cbLines[i] = static_cast(pcb + li * inLayout.cStride); - } - } - - /* If APP1 data was passed in, use it */ - if(app1Buffer && app1Size) - { - jpeg_write_marker(&cinfo, JPEG_APP0 + 1, - static_cast(app1Buffer), app1Size); - } - - /* While we still have padded height left to go, keep giving it one - * macroblock at a time. */ - while (cinfo.next_scanline < cinfo.image_height) { - const uint32_t batchSize = DCTSIZE * maxVSampFactor; - const uint32_t nl = cinfo.next_scanline; - JSAMPARRAY planes[3]{ &yLines[nl], - &cbLines[nl/cVSubSampling], - &crLines[nl/cVSubSampling] }; - - uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize); - - if (done != batchSize) { - ALOGE("%s: compressed %u lines, expected %u (total %u/%u)", - __FUNCTION__, done, batchSize, cinfo.next_scanline, - cinfo.image_height); - return -1; - } - } - - /* This will flush everything */ - jpeg_finish_compress(&cinfo); - - /* Grab the actual code size and set it */ - actualCodeSize = dmgr.mEncodedSize; - - return 0; -} - /* * TODO: There needs to be a mechanism to discover allocated buffer size * in the HAL. @@ -1555,25 +1190,9 @@ Size ExternalCameraDeviceSession::getMaxJpegResolution() const { } Size ExternalCameraDeviceSession::getMaxThumbResolution() const { - Size thumbSize { 0, 0 }; - camera_metadata_ro_entry entry = - mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES); - for(uint32_t i = 0; i < entry.count; i += 2) { - Size sz { static_cast(entry.data.i32[i]), - static_cast(entry.data.i32[i+1]) }; - if(sz.width * sz.height > thumbSize.width * thumbSize.height) { - thumbSize = sz; - } - } - - if (thumbSize.width * thumbSize.height == 0) { - ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__); - } - - return thumbSize; + return getMaxThumbnailResolution(mCameraCharacteristics); } - ssize_t ExternalCameraDeviceSession::getJpegBufferSize( uint32_t width, uint32_t height) const { // Constant from camera3.h @@ -1616,7 +1235,7 @@ ssize_t ExternalCameraDeviceSession::getJpegBufferSize( int ExternalCameraDeviceSession::OutputThread::createJpegLocked( HalStreamBuffer &halBuf, - const std::shared_ptr& req) + const common::V1_0::helper::CameraMetadata& setting) { ATRACE_CALL(); int ret; @@ -1645,17 +1264,17 @@ int ExternalCameraDeviceSession::OutputThread::createJpegLocked( Size thumbSize; bool outputThumbnail = true; - if (req->setting.exists(ANDROID_JPEG_QUALITY)) { - camera_metadata_entry entry = - req->setting.find(ANDROID_JPEG_QUALITY); + if (setting.exists(ANDROID_JPEG_QUALITY)) { + camera_metadata_ro_entry entry = + setting.find(ANDROID_JPEG_QUALITY); jpegQuality = entry.data.u8[0]; } else { return lfail("%s: ANDROID_JPEG_QUALITY not set",__FUNCTION__); } - if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) { - camera_metadata_entry entry = - req->setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY); + if (setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) { + camera_metadata_ro_entry entry = + setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY); thumbQuality = entry.data.u8[0]; } else { return lfail( @@ -1663,9 +1282,9 @@ int ExternalCameraDeviceSession::OutputThread::createJpegLocked( __FUNCTION__); } - if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) { - camera_metadata_entry entry = - req->setting.find(ANDROID_JPEG_THUMBNAIL_SIZE); + if (setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) { + camera_metadata_ro_entry entry = + setting.find(ANDROID_JPEG_THUMBNAIL_SIZE); thumbSize = Size { static_cast(entry.data.i32[0]), static_cast(entry.data.i32[1]) }; @@ -1732,8 +1351,8 @@ int ExternalCameraDeviceSession::OutputThread::createJpegLocked( /* Combine camera characteristics with request settings to form EXIF * metadata */ - common::V1_0::helper::CameraMetadata meta(parent->mCameraCharacteristics); - meta.append(req->setting); + common::V1_0::helper::CameraMetadata meta(mCameraCharacteristics); + meta.append(setting); /* Generate EXIF object */ std::unique_ptr utils(ExifUtils::create()); @@ -1838,7 +1457,7 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { // TODO: see if we can save some computation by converting to YV12 here uint8_t* inData; size_t inDataSize; - if (req->frameIn->map(&inData, &inDataSize) != 0) { + if (req->frameIn->getData(&inData, &inDataSize) != 0) { lk.unlock(); return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__); } @@ -1899,7 +1518,7 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { // Gralloc lockYCbCr the buffer switch (halBuf.format) { case PixelFormat::BLOB: { - int ret = createJpegLocked(halBuf, req); + int ret = createJpegLocked(halBuf, req->setting); if(ret != 0) { lk.unlock(); @@ -1949,8 +1568,8 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { } Size sz {halBuf.width, halBuf.height}; - ATRACE_BEGIN("formatConvertLocked"); - ret = formatConvertLocked(cropAndScaled, outLayout, sz, outputFourcc); + ATRACE_BEGIN("formatConvert"); + ret = formatConvert(cropAndScaled, outLayout, sz, outputFourcc); ATRACE_END(); if (ret != 0) { lk.unlock(); @@ -2055,6 +1674,14 @@ Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers( return Status::OK; } +void ExternalCameraDeviceSession::OutputThread::clearIntermediateBuffers() { + std::lock_guard lk(mBufferLock); + mYu12Frame.clear(); + mYu12ThumbFrame.clear(); + mIntermediateBuffers.clear(); + mBlobBufferSize = 0; +} + Status ExternalCameraDeviceSession::OutputThread::submitRequest( const std::shared_ptr& req) { std::unique_lock lk(mRequestListLock); @@ -2090,6 +1717,32 @@ void ExternalCameraDeviceSession::OutputThread::flush() { } } +std::list> +ExternalCameraDeviceSession::OutputThread::switchToOffline() { + ATRACE_CALL(); + std::list> emptyList; + auto parent = mParent.promote(); + if (parent == nullptr) { + ALOGE("%s: session has been disconnected!", __FUNCTION__); + return emptyList; + } + + std::unique_lock lk(mRequestListLock); + std::list> reqs = std::move(mRequestList); + mRequestList.clear(); + if (mProcessingRequest) { + std::chrono::seconds timeout = std::chrono::seconds(kFlushWaitTimeoutSec); + auto st = mRequestDoneCond.wait_for(lk, timeout); + if (st == std::cv_status::timeout) { + ALOGE("%s: wait for inflight request finish timeout!", __FUNCTION__); + } + } + lk.unlock(); + clearIntermediateBuffers(); + ALOGV("%s: returning %zu request for offline processing", __FUNCTION__, reqs.size()); + return reqs; +} + void ExternalCameraDeviceSession::OutputThread::waitForNextRequest( std::shared_ptr* out) { ATRACE_CALL(); @@ -2733,6 +2386,7 @@ Status ExternalCameraDeviceSession::configureStreams( return Status::INTERNAL_ERROR; } + mBlobBufferSize = blobBufferSize; status = mOutputThread->allocateIntermediateBuffers(v4lSize, mMaxThumbResolution, config.streams, blobBufferSize); if (status != Status::OK) { @@ -2916,16 +2570,6 @@ status_t ExternalCameraDeviceSession::initDefaultRequests() { status_t ExternalCameraDeviceSession::fillCaptureResult( common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) { - // android.control - // For USB camera, we don't know the AE state. Set the state to converged to - // indicate the frame should be good to use. Then apps don't have to wait the - // AE state. - const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED; - UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1); - - const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF; - UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1); - bool afTrigger = false; { std::lock_guard lk(mAfTriggerLock); @@ -2951,46 +2595,10 @@ status_t ExternalCameraDeviceSession::fillCaptureResult( } UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1); - // Set AWB state to converged to indicate the frame should be good to use. - const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED; - UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1); + camera_metadata_ro_entry activeArraySize = + mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE); - const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF; - UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1); - - camera_metadata_ro_entry active_array_size = - mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE); - - if (active_array_size.count == 0) { - ALOGE("%s: cannot find active array size!", __FUNCTION__); - return -EINVAL; - } - - const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE; - UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1); - - // This means pipeline latency of X frame intervals. The maximum number is 4. - const uint8_t requestPipelineMaxDepth = 4; - UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1); - - // android.scaler - const int32_t crop_region[] = { - active_array_size.data.i32[0], active_array_size.data.i32[1], - active_array_size.data.i32[2], active_array_size.data.i32[3], - }; - UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region)); - - // android.sensor - UPDATE(md, ANDROID_SENSOR_TIMESTAMP, ×tamp, 1); - - // android.statistics - const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF; - UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1); - - const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE; - UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1); - - return OK; + return fillCaptureResultCommon(md, timestamp, activeArraySize); } #undef ARRAY_SIZE diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp index e25deff797..4a6381ea7b 100644 --- a/camera/device/3.4/default/ExternalCameraUtils.cpp +++ b/camera/device/3.4/default/ExternalCameraUtils.cpp @@ -18,10 +18,23 @@ #include #include +#include #include #include + +#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs +#include + +#include + #include "ExternalCameraUtils.h" +namespace { + +buffer_handle_t sEmptyBuffer = nullptr; + +} // Anonymous namespace + namespace android { namespace hardware { namespace camera { @@ -29,10 +42,13 @@ namespace device { namespace V3_4 { namespace implementation { +Frame::Frame(uint32_t width, uint32_t height, uint32_t fourcc) : + mWidth(width), mHeight(height), mFourcc(fourcc) {} + V4L2Frame::V4L2Frame( uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd, uint32_t dataSize, uint64_t offset) : - mWidth(w), mHeight(h), mFourcc(fourcc), + Frame(w, h, fourcc), mBufferIndex(bufIdx), mFd(fd), mDataSize(dataSize), mOffset(offset) {} int V4L2Frame::map(uint8_t** data, size_t* dataSize) { @@ -75,9 +91,13 @@ V4L2Frame::~V4L2Frame() { unmap(); } +int V4L2Frame::getData(uint8_t** outData, size_t* dataSize) { + return map(outData, dataSize); +} + AllocatedFrame::AllocatedFrame( uint32_t w, uint32_t h) : - mWidth(w), mHeight(h), mFourcc(V4L2_PIX_FMT_YUV420) {}; + Frame(w, h, V4L2_PIX_FMT_YUV420) {}; AllocatedFrame::~AllocatedFrame() {} @@ -106,6 +126,17 @@ int AllocatedFrame::allocate(YCbCrLayout* out) { return 0; } +int AllocatedFrame::getData(uint8_t** outData, size_t* dataSize) { + YCbCrLayout layout; + int ret = allocate(&layout); + if (ret != 0) { + return ret; + } + *outData = mData.data(); + *dataSize = mData.size(); + return 0; +} + int AllocatedFrame::getLayout(YCbCrLayout* out) { IMapper::Rect noCrop = {0, 0, static_cast(mWidth), @@ -150,8 +181,520 @@ double SupportedV4L2Format::FrameRate::getDouble() const { return durationDenominator / static_cast(durationNumerator); } +::android::hardware::camera::common::V1_0::Status importBufferImpl( + /*inout*/std::map& circulatingBuffers, + /*inout*/HandleImporter& handleImporter, + int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf) { + using ::android::hardware::camera::common::V1_0::Status; + if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) { + if (allowEmptyBuf) { + *outBufPtr = &sEmptyBuffer; + return Status::OK; + } else { + ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); + return Status::ILLEGAL_ARGUMENT; + } + } + + CirculatingBuffers& cbs = circulatingBuffers[streamId]; + if (cbs.count(bufId) == 0) { + if (buf == nullptr) { + ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); + return Status::ILLEGAL_ARGUMENT; + } + // Register a newly seen buffer + buffer_handle_t importedBuf = buf; + handleImporter.importBuffer(importedBuf); + if (importedBuf == nullptr) { + ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId); + return Status::INTERNAL_ERROR; + } else { + cbs[bufId] = importedBuf; + } + } + *outBufPtr = &cbs[bufId]; + return Status::OK; +} + +uint32_t getFourCcFromLayout(const YCbCrLayout& layout) { + intptr_t cb = reinterpret_cast(layout.cb); + intptr_t cr = reinterpret_cast(layout.cr); + if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) { + // Interleaved format + if (layout.cb > layout.cr) { + return V4L2_PIX_FMT_NV21; + } else { + return V4L2_PIX_FMT_NV12; + } + } else if (layout.chromaStep == 1) { + // Planar format + if (layout.cb > layout.cr) { + return V4L2_PIX_FMT_YVU420; // YV12 + } else { + return V4L2_PIX_FMT_YUV420; // YU12 + } + } else { + return FLEX_YUV_GENERIC; + } +} + +int getCropRect( + CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) { + if (out == nullptr) { + ALOGE("%s: out is null", __FUNCTION__); + return -1; + } + + uint32_t inW = inSize.width; + uint32_t inH = inSize.height; + uint32_t outW = outSize.width; + uint32_t outH = outSize.height; + + // Handle special case where aspect ratio is close to input but scaled + // dimension is slightly larger than input + float arIn = ASPECT_RATIO(inSize); + float arOut = ASPECT_RATIO(outSize); + if (isAspectRatioClose(arIn, arOut)) { + out->left = 0; + out->top = 0; + out->width = inW; + out->height = inH; + return 0; + } + + if (ct == VERTICAL) { + uint64_t scaledOutH = static_cast(outH) * inW / outW; + if (scaledOutH > inH) { + ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d", + __FUNCTION__, outW, outH, inW, inH); + return -1; + } + scaledOutH = scaledOutH & ~0x1; // make it multiple of 2 + + out->left = 0; + out->top = ((inH - scaledOutH) / 2) & ~0x1; + out->width = inW; + out->height = static_cast(scaledOutH); + ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d", + __FUNCTION__, inW, inH, outW, outH, out->top, static_cast(scaledOutH)); + } else { + uint64_t scaledOutW = static_cast(outW) * inH / outH; + if (scaledOutW > inW) { + ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d", + __FUNCTION__, outW, outH, inW, inH); + return -1; + } + scaledOutW = scaledOutW & ~0x1; // make it multiple of 2 + + out->left = ((inW - scaledOutW) / 2) & ~0x1; + out->top = 0; + out->width = static_cast(scaledOutW); + out->height = inH; + ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d", + __FUNCTION__, inW, inH, outW, outH, out->top, static_cast(scaledOutW)); + } + + return 0; +} + +int formatConvert( + const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) { + int ret = 0; + switch (format) { + case V4L2_PIX_FMT_NV21: + ret = libyuv::I420ToNV21( + static_cast(in.y), + in.yStride, + static_cast(in.cb), + in.cStride, + static_cast(in.cr), + in.cStride, + static_cast(out.y), + out.yStride, + static_cast(out.cr), + out.cStride, + sz.width, + sz.height); + if (ret != 0) { + ALOGE("%s: convert to NV21 buffer failed! ret %d", + __FUNCTION__, ret); + return ret; + } + break; + case V4L2_PIX_FMT_NV12: + ret = libyuv::I420ToNV12( + static_cast(in.y), + in.yStride, + static_cast(in.cb), + in.cStride, + static_cast(in.cr), + in.cStride, + static_cast(out.y), + out.yStride, + static_cast(out.cb), + out.cStride, + sz.width, + sz.height); + if (ret != 0) { + ALOGE("%s: convert to NV12 buffer failed! ret %d", + __FUNCTION__, ret); + return ret; + } + break; + case V4L2_PIX_FMT_YVU420: // YV12 + case V4L2_PIX_FMT_YUV420: // YU12 + // TODO: maybe we can speed up here by somehow save this copy? + ret = libyuv::I420Copy( + static_cast(in.y), + in.yStride, + static_cast(in.cb), + in.cStride, + static_cast(in.cr), + in.cStride, + static_cast(out.y), + out.yStride, + static_cast(out.cb), + out.cStride, + static_cast(out.cr), + out.cStride, + sz.width, + sz.height); + if (ret != 0) { + ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d", + __FUNCTION__, ret); + return ret; + } + break; + case FLEX_YUV_GENERIC: + // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow. + ALOGE("%s: unsupported flexible yuv layout" + " y %p cb %p cr %p y_str %d c_str %d c_step %d", + __FUNCTION__, out.y, out.cb, out.cr, + out.yStride, out.cStride, out.chromaStep); + return -1; + default: + ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format); + return -1; + } + return 0; +} + +int encodeJpegYU12( + const Size & inSz, const YCbCrLayout& inLayout, + int jpegQuality, const void *app1Buffer, size_t app1Size, + void *out, const size_t maxOutSize, size_t &actualCodeSize) +{ + /* libjpeg is a C library so we use C-style "inheritance" by + * putting libjpeg's jpeg_destination_mgr first in our custom + * struct. This allows us to cast jpeg_destination_mgr* to + * CustomJpegDestMgr* when we get it passed to us in a callback */ + struct CustomJpegDestMgr { + struct jpeg_destination_mgr mgr; + JOCTET *mBuffer; + size_t mBufferSize; + size_t mEncodedSize; + bool mSuccess; + } dmgr; + + jpeg_compress_struct cinfo = {}; + jpeg_error_mgr jerr; + + /* Initialize error handling with standard callbacks, but + * then override output_message (to print to ALOG) and + * error_exit to set a flag and print a message instead + * of killing the whole process */ + cinfo.err = jpeg_std_error(&jerr); + + cinfo.err->output_message = [](j_common_ptr cinfo) { + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message)(cinfo, buffer); + ALOGE("libjpeg error: %s", buffer); + }; + cinfo.err->error_exit = [](j_common_ptr cinfo) { + (*cinfo->err->output_message)(cinfo); + if(cinfo->client_data) { + auto & dmgr = + *reinterpret_cast(cinfo->client_data); + dmgr.mSuccess = false; + } + }; + /* Now that we initialized some callbacks, let's create our compressor */ + jpeg_create_compress(&cinfo); + + /* Initialize our destination manager */ + dmgr.mBuffer = static_cast(out); + dmgr.mBufferSize = maxOutSize; + dmgr.mEncodedSize = 0; + dmgr.mSuccess = true; + cinfo.client_data = static_cast(&dmgr); + + /* These lambdas become C-style function pointers and as per C++11 spec + * may not capture anything */ + dmgr.mgr.init_destination = [](j_compress_ptr cinfo) { + auto & dmgr = reinterpret_cast(*cinfo->dest); + dmgr.mgr.next_output_byte = dmgr.mBuffer; + dmgr.mgr.free_in_buffer = dmgr.mBufferSize; + ALOGV("%s:%d jpeg start: %p [%zu]", + __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize); + }; + + dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) { + ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__); + return 0; + }; + + dmgr.mgr.term_destination = [](j_compress_ptr cinfo) { + auto & dmgr = reinterpret_cast(*cinfo->dest); + dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer; + ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize); + }; + cinfo.dest = reinterpret_cast(&dmgr); + + /* We are going to be using JPEG in raw data mode, so we are passing + * straight subsampled planar YCbCr and it will not touch our pixel + * data or do any scaling or anything */ + cinfo.image_width = inSz.width; + cinfo.image_height = inSz.height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_YCbCr; + + /* Initialize defaults and then override what we want */ + jpeg_set_defaults(&cinfo); + + jpeg_set_quality(&cinfo, jpegQuality, 1); + jpeg_set_colorspace(&cinfo, JCS_YCbCr); + cinfo.raw_data_in = 1; + cinfo.dct_method = JDCT_IFAST; + + /* Configure sampling factors. The sampling factor is JPEG subsampling 420 + * because the source format is YUV420. Note that libjpeg sampling factors + * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and + * 1 V value for each 2 Y values */ + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 2; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + + /* Let's not hardcode YUV420 in 6 places... 5 was enough */ + int maxVSampFactor = std::max( { + cinfo.comp_info[0].v_samp_factor, + cinfo.comp_info[1].v_samp_factor, + cinfo.comp_info[2].v_samp_factor + }); + int cVSubSampling = cinfo.comp_info[0].v_samp_factor / + cinfo.comp_info[1].v_samp_factor; + + /* Start the compressor */ + jpeg_start_compress(&cinfo, TRUE); + + /* Compute our macroblock height, so we can pad our input to be vertically + * macroblock aligned. + * TODO: Does it need to be horizontally MCU aligned too? */ + + size_t mcuV = DCTSIZE*maxVSampFactor; + size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV); + + /* libjpeg uses arrays of row pointers, which makes it really easy to pad + * data vertically (unfortunately doesn't help horizontally) */ + std::vector yLines (paddedHeight); + std::vector cbLines(paddedHeight/cVSubSampling); + std::vector crLines(paddedHeight/cVSubSampling); + + uint8_t *py = static_cast(inLayout.y); + uint8_t *pcr = static_cast(inLayout.cr); + uint8_t *pcb = static_cast(inLayout.cb); + + for(uint32_t i = 0; i < paddedHeight; i++) + { + /* Once we are in the padding territory we still point to the last line + * effectively replicating it several times ~ CLAMP_TO_EDGE */ + int li = std::min(i, inSz.height - 1); + yLines[i] = static_cast(py + li * inLayout.yStride); + if(i < paddedHeight / cVSubSampling) + { + crLines[i] = static_cast(pcr + li * inLayout.cStride); + cbLines[i] = static_cast(pcb + li * inLayout.cStride); + } + } + + /* If APP1 data was passed in, use it */ + if(app1Buffer && app1Size) + { + jpeg_write_marker(&cinfo, JPEG_APP0 + 1, + static_cast(app1Buffer), app1Size); + } + + /* While we still have padded height left to go, keep giving it one + * macroblock at a time. */ + while (cinfo.next_scanline < cinfo.image_height) { + const uint32_t batchSize = DCTSIZE * maxVSampFactor; + const uint32_t nl = cinfo.next_scanline; + JSAMPARRAY planes[3]{ &yLines[nl], + &cbLines[nl/cVSubSampling], + &crLines[nl/cVSubSampling] }; + + uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize); + + if (done != batchSize) { + ALOGE("%s: compressed %u lines, expected %u (total %u/%u)", + __FUNCTION__, done, batchSize, cinfo.next_scanline, + cinfo.image_height); + return -1; + } + } + + /* This will flush everything */ + jpeg_finish_compress(&cinfo); + + /* Grab the actual code size and set it */ + actualCodeSize = dmgr.mEncodedSize; + + return 0; +} + +Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata& chars) { + Size thumbSize { 0, 0 }; + camera_metadata_ro_entry entry = + chars.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES); + for(uint32_t i = 0; i < entry.count; i += 2) { + Size sz { static_cast(entry.data.i32[i]), + static_cast(entry.data.i32[i+1]) }; + if(sz.width * sz.height > thumbSize.width * thumbSize.height) { + thumbSize = sz; + } + } + + if (thumbSize.width * thumbSize.height == 0) { + ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__); + } + + return thumbSize; +} + +void freeReleaseFences(hidl_vec& results) { + for (auto& result : results) { + if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) { + native_handle_t* handle = const_cast( + result.inputBuffer.releaseFence.getNativeHandle()); + native_handle_close(handle); + native_handle_delete(handle); + } + for (auto& buf : result.outputBuffers) { + if (buf.releaseFence.getNativeHandle() != nullptr) { + native_handle_t* handle = const_cast( + buf.releaseFence.getNativeHandle()); + native_handle_close(handle); + native_handle_delete(handle); + } + } + } + return; +} + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) +#define UPDATE(md, tag, data, size) \ +do { \ + if ((md).update((tag), (data), (size))) { \ + ALOGE("Update " #tag " failed!"); \ + return BAD_VALUE; \ + } \ +} while (0) + +status_t fillCaptureResultCommon( + common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp, + camera_metadata_ro_entry& activeArraySize) { + if (activeArraySize.count < 4) { + ALOGE("%s: cannot find active array size!", __FUNCTION__); + return -EINVAL; + } + // android.control + // For USB camera, we don't know the AE state. Set the state to converged to + // indicate the frame should be good to use. Then apps don't have to wait the + // AE state. + const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED; + UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1); + + const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF; + UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1); + + // Set AWB state to converged to indicate the frame should be good to use. + const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED; + UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1); + + const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF; + UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1); + + const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE; + UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1); + + // This means pipeline latency of X frame intervals. The maximum number is 4. + const uint8_t requestPipelineMaxDepth = 4; + UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1); + + // android.scaler + const int32_t crop_region[] = { + activeArraySize.data.i32[0], activeArraySize.data.i32[1], + activeArraySize.data.i32[2], activeArraySize.data.i32[3], + }; + UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region)); + + // android.sensor + UPDATE(md, ANDROID_SENSOR_TIMESTAMP, ×tamp, 1); + + // android.statistics + const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF; + UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1); + + const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE; + UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1); + + return OK; +} + +#undef ARRAY_SIZE +#undef UPDATE + } // namespace implementation } // namespace V3_4 + +namespace V3_6 { +namespace implementation { + +AllocatedV4L2Frame::AllocatedV4L2Frame(sp frameIn) : + Frame(frameIn->mWidth, frameIn->mHeight, frameIn->mFourcc) { + uint8_t* dataIn; + size_t dataSize; + if (frameIn->getData(&dataIn, &dataSize) != 0) { + ALOGE("%s: map input V4L2 frame failed!", __FUNCTION__); + return; + } + + mData.resize(dataSize); + std::memcpy(mData.data(), dataIn, dataSize); +} + +int AllocatedV4L2Frame::getData(uint8_t** outData, size_t* dataSize) { + if (outData == nullptr || dataSize == nullptr) { + ALOGE("%s: outData(%p)/dataSize(%p) must not be null", __FUNCTION__, outData, dataSize); + return -1; + } + + *outData = mData.data(); + *dataSize = mData.size(); + return 0; +} + +AllocatedV4L2Frame::~AllocatedV4L2Frame() {} + +} // namespace implementation +} // namespace V3_6 } // namespace device diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h index 71b7c17dd6..ecab9cfa03 100644 --- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h +++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H -#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H +#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H #include #include @@ -84,7 +84,8 @@ using ::android::sp; using ::android::Mutex; using ::android::base::unique_fd; -struct ExternalCameraDeviceSession : public virtual RefBase { +struct ExternalCameraDeviceSession : public virtual RefBase, + public virtual OutputThreadInterface { ExternalCameraDeviceSession(const sp&, const ExternalCameraConfig& cfg, @@ -110,6 +111,82 @@ struct ExternalCameraDeviceSession : public virtual RefBase { static const int kMaxStallStream = 1; static const uint32_t kMaxBytesPerPixel = 2; + class OutputThread : public android::Thread { + public: + OutputThread(wp parent, CroppingType, + const common::V1_0::helper::CameraMetadata&); + virtual ~OutputThread(); + + Status allocateIntermediateBuffers( + const Size& v4lSize, const Size& thumbSize, + const hidl_vec& streams, + uint32_t blobBufferSize); + Status submitRequest(const std::shared_ptr&); + void flush(); + void dump(int fd); + virtual bool threadLoop() override; + + void setExifMakeModel(const std::string& make, const std::string& model); + + // The remaining request list is returned for offline processing + std::list> switchToOffline(); + + protected: + // Methods to request output buffer in parallel + // No-op for device@3.4. Implemented in device@3.5 + virtual int requestBufferStart(const std::vector&) { return 0; } + virtual int waitForBufferRequestDone( + /*out*/std::vector*) { return 0; } + + static const int kFlushWaitTimeoutSec = 3; // 3 sec + static const int kReqWaitTimeoutMs = 33; // 33ms + static const int kReqWaitTimesMax = 90; // 33ms * 90 ~= 3 sec + + void waitForNextRequest(std::shared_ptr* out); + void signalRequestDone(); + + int cropAndScaleLocked( + sp& in, const Size& outSize, + YCbCrLayout* out); + + int cropAndScaleThumbLocked( + sp& in, const Size& outSize, + YCbCrLayout* out); + + int createJpegLocked(HalStreamBuffer &halBuf, + const common::V1_0::helper::CameraMetadata& settings); + + void clearIntermediateBuffers(); + + const wp mParent; + const CroppingType mCroppingType; + const common::V1_0::helper::CameraMetadata mCameraCharacteristics; + + mutable std::mutex mRequestListLock; // Protect acccess to mRequestList, + // mProcessingRequest and mProcessingFrameNumer + std::condition_variable mRequestCond; // signaled when a new request is submitted + std::condition_variable mRequestDoneCond; // signaled when a request is done processing + std::list> mRequestList; + bool mProcessingRequest = false; + uint32_t mProcessingFrameNumer = 0; + + // V4L2 frameIn + // (MJPG decode)-> mYu12Frame + // (Scale)-> mScaledYu12Frames + // (Format convert) -> output gralloc frames + mutable std::mutex mBufferLock; // Protect access to intermediate buffers + sp mYu12Frame; + sp mYu12ThumbFrame; + std::unordered_map, SizeHasher> mIntermediateBuffers; + std::unordered_map, SizeHasher> mScaledYu12Frames; + YCbCrLayout mYu12FrameLayout; + YCbCrLayout mYu12ThumbFrameLayout; + uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size + + std::string mExifMake; + std::string mExifModel; + }; + protected: // Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow @@ -150,27 +227,22 @@ protected: ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb); protected: - struct HalStreamBuffer { - int32_t streamId; - uint64_t bufferId; - uint32_t width; - uint32_t height; - PixelFormat format; - V3_2::BufferUsageFlags usage; - buffer_handle_t* bufPtr; - int acquireFence; - bool fenceTimeout; - }; + // Methods from OutputThreadInterface + virtual Status importBuffer(int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf) override; - struct HalRequest { - uint32_t frameNumber; - common::V1_0::helper::CameraMetadata setting; - sp frameIn; - nsecs_t shutterTs; - std::vector buffers; - }; + virtual Status processCaptureResult(std::shared_ptr&) override; - static const uint64_t BUFFER_ID_NO_BUFFER = 0; + virtual Status processCaptureRequestError(const std::shared_ptr&, + /*out*/std::vector* msgs = nullptr, + /*out*/std::vector* results = nullptr) override; + + virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override; + + virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override; + // End of OutputThreadInterface methods Status constructDefaultRequestSettingsRaw(RequestTemplate type, V3_2::CameraMetadata *outMetadata); @@ -219,11 +291,6 @@ protected: // Optional argument for ICameraDeviceSession@3.5 impl bool allowEmptyBuf = false); - Status importBuffer(int32_t streamId, - uint64_t bufId, buffer_handle_t buf, - /*out*/buffer_handle_t** outBufPtr, - bool allowEmptyBuf); - Status importBufferLocked(int32_t streamId, uint64_t bufId, buffer_handle_t buf, /*out*/buffer_handle_t** outBufPtr, @@ -236,106 +303,15 @@ protected: Status processOneCaptureRequest(const CaptureRequest& request); - Status processCaptureResult(std::shared_ptr&); - Status processCaptureRequestError(const std::shared_ptr&); void notifyShutter(uint32_t frameNumber, nsecs_t shutterTs); - void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec); void invokeProcessCaptureResultCallback( hidl_vec &results, bool tryWriteFmq); - static void freeReleaseFences(hidl_vec&); Size getMaxJpegResolution() const; Size getMaxThumbResolution() const; - ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const; - int waitForV4L2BufferReturnLocked(std::unique_lock& lk); - class OutputThread : public android::Thread { - public: - OutputThread(wp parent, CroppingType); - virtual ~OutputThread(); - - Status allocateIntermediateBuffers( - const Size& v4lSize, const Size& thumbSize, - const hidl_vec& streams, - uint32_t blobBufferSize); - Status submitRequest(const std::shared_ptr&); - void flush(); - void dump(int fd); - virtual bool threadLoop() override; - - void setExifMakeModel(const std::string& make, const std::string& model); - - protected: - // Methods to request output buffer in parallel - // No-op for device@3.4. Implemented in device@3.5 - virtual int requestBufferStart(const std::vector&) { return 0; } - virtual int waitForBufferRequestDone( - /*out*/std::vector*) { return 0; } - - static const uint32_t FLEX_YUV_GENERIC = static_cast('F') | - static_cast('L') << 8 | static_cast('E') << 16 | - static_cast('X') << 24; - // returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21 - static uint32_t getFourCcFromLayout(const YCbCrLayout&); - static int getCropRect( - CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out); - - static const int kFlushWaitTimeoutSec = 3; // 3 sec - static const int kReqWaitTimeoutMs = 33; // 33ms - static const int kReqWaitTimesMax = 90; // 33ms * 90 ~= 3 sec - - void waitForNextRequest(std::shared_ptr* out); - void signalRequestDone(); - - int cropAndScaleLocked( - sp& in, const Size& outSize, - YCbCrLayout* out); - - int cropAndScaleThumbLocked( - sp& in, const Size& outSize, - YCbCrLayout* out); - - int formatConvertLocked(const YCbCrLayout& in, const YCbCrLayout& out, - Size sz, uint32_t format); - - static int encodeJpegYU12(const Size &inSz, - const YCbCrLayout& inLayout, int jpegQuality, - const void *app1Buffer, size_t app1Size, - void *out, size_t maxOutSize, - size_t &actualCodeSize); - - int createJpegLocked(HalStreamBuffer &halBuf, const std::shared_ptr& req); - - const wp mParent; - const CroppingType mCroppingType; - - mutable std::mutex mRequestListLock; // Protect acccess to mRequestList, - // mProcessingRequest and mProcessingFrameNumer - std::condition_variable mRequestCond; // signaled when a new request is submitted - std::condition_variable mRequestDoneCond; // signaled when a request is done processing - std::list> mRequestList; - bool mProcessingRequest = false; - uint32_t mProcessingFrameNumer = 0; - - // V4L2 frameIn - // (MJPG decode)-> mYu12Frame - // (Scale)-> mScaledYu12Frames - // (Format convert) -> output gralloc frames - mutable std::mutex mBufferLock; // Protect access to intermediate buffers - sp mYu12Frame; - sp mYu12ThumbFrame; - std::unordered_map, SizeHasher> mIntermediateBuffers; - std::unordered_map, SizeHasher> mScaledYu12Frames; - YCbCrLayout mYu12FrameLayout; - YCbCrLayout mYu12ThumbFrameLayout; - uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size - - std::string mExifMake; - std::string mExifModel; - }; - // Protect (most of) HIDL interface methods from synchronized-entering mutable Mutex mInterfaceLock; @@ -381,12 +357,6 @@ protected: std::mutex mInflightFramesLock; // protect mInflightFrames std::unordered_set mInflightFrames; - // buffers currently circulating between HAL and camera service - // key: bufferId sent via HIDL interface - // value: imported buffer_handle_t - // Buffer will be imported during processCaptureRequest and will be freed - // when the its stream is deleted or camera device session is closed - typedef std::unordered_map CirculatingBuffers; // Stream ID -> circulating buffers map std::map mCirculatingBuffers; // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock @@ -395,6 +365,8 @@ protected: std::mutex mAfTriggerLock; // protect mAfTrigger bool mAfTrigger = false; + uint32_t mBlobBufferSize = 0; + static HandleImporter sHandleImporter; /* Beginning of members not changed after initialize() */ @@ -410,6 +382,9 @@ protected: const Size mMaxThumbResolution; const Size mMaxJpegResolution; + + std::string mExifMake; + std::string mExifModel; /* End of members not changed after initialize() */ private: @@ -484,4 +459,4 @@ private: } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h index 341c62218d..74f75eb246 100644 --- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h +++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h @@ -17,16 +17,27 @@ #ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H #define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H +#include +#include +#include #include #include #include +#include #include #include #include "tinyxml2.h" // XML parsing #include "utils/LightRefBase.h" +#include "utils/Timers.h" +#include +#include -using android::hardware::graphics::mapper::V2_0::IMapper; -using android::hardware::graphics::mapper::V2_0::YCbCrLayout; + +using ::android::hardware::graphics::mapper::V2_0::IMapper; +using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout; +using ::android::hardware::camera::common::V1_0::helper::HandleImporter; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::device::V3_2::ErrorCode; namespace android { namespace hardware { @@ -113,16 +124,28 @@ struct SupportedV4L2Format { std::vector frameRates; }; +// A Base class with basic information about a frame +struct Frame : public VirtualLightRefBase { +public: + Frame(uint32_t width, uint32_t height, uint32_t fourcc); + const uint32_t mWidth; + const uint32_t mHeight; + const uint32_t mFourcc; + + // getData might involve map/allocation + virtual int getData(uint8_t** outData, size_t* dataSize) = 0; +}; + // A class provide access to a dequeued V4L2 frame buffer (mostly in MJPG format) // Also contains necessary information to enqueue the buffer back to V4L2 buffer queue -class V4L2Frame : public virtual VirtualLightRefBase { +class V4L2Frame : public Frame { public: V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd, uint32_t dataSize, uint64_t offset); ~V4L2Frame() override; - const uint32_t mWidth; - const uint32_t mHeight; - const uint32_t mFourcc; + + virtual int getData(uint8_t** outData, size_t* dataSize) override; + const int mBufferIndex; // for later enqueue int map(uint8_t** data, size_t* dataSize); int unmap(); @@ -137,13 +160,13 @@ private: // A RAII class representing a CPU allocated YUV frame used as intermeidate buffers // when generating output images. -class AllocatedFrame : public virtual VirtualLightRefBase { +class AllocatedFrame : public Frame { public: - AllocatedFrame(uint32_t w, uint32_t h); // TODO: use Size? + AllocatedFrame(uint32_t w, uint32_t h); // only support V4L2_PIX_FMT_YUV420 for now ~AllocatedFrame() override; - const uint32_t mWidth; - const uint32_t mHeight; - const uint32_t mFourcc; // Only support YU12 format for now + + virtual int getData(uint8_t** outData, size_t* dataSize) override; + int allocate(YCbCrLayout* out = nullptr); int getLayout(YCbCrLayout* out); int getCroppedLayout(const IMapper::Rect&, YCbCrLayout* out); // return non-zero for bad input @@ -165,8 +188,110 @@ const float kMinAspectRatio = 1.f; bool isAspectRatioClose(float ar1, float ar2); +struct HalStreamBuffer { + int32_t streamId; + uint64_t bufferId; + uint32_t width; + uint32_t height; + ::android::hardware::graphics::common::V1_0::PixelFormat format; + ::android::hardware::camera::device::V3_2::BufferUsageFlags usage; + buffer_handle_t* bufPtr; + int acquireFence; + bool fenceTimeout; +}; + +struct HalRequest { + uint32_t frameNumber; + common::V1_0::helper::CameraMetadata setting; + sp frameIn; + nsecs_t shutterTs; + std::vector buffers; +}; + +static const uint64_t BUFFER_ID_NO_BUFFER = 0; + +// buffers currently circulating between HAL and camera service +// key: bufferId sent via HIDL interface +// value: imported buffer_handle_t +// Buffer will be imported during processCaptureRequest (or requestStreamBuffer +// in the case of HAL buffer manager is enabled) and will be freed +// when the stream is deleted or camera device session is closed +typedef std::unordered_map CirculatingBuffers; + +::android::hardware::camera::common::V1_0::Status importBufferImpl( + /*inout*/std::map& circulatingBuffers, + /*inout*/HandleImporter& handleImporter, + int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf); + +static const uint32_t FLEX_YUV_GENERIC = static_cast('F') | + static_cast('L') << 8 | static_cast('E') << 16 | + static_cast('X') << 24; + +// returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21 +uint32_t getFourCcFromLayout(const YCbCrLayout&); + +using ::android::hardware::camera::external::common::Size; +int getCropRect(CroppingType ct, const Size& inSize, + const Size& outSize, IMapper::Rect* out); + +int formatConvert(const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format); + +int encodeJpegYU12(const Size &inSz, + const YCbCrLayout& inLayout, int jpegQuality, + const void *app1Buffer, size_t app1Size, + void *out, size_t maxOutSize, + size_t &actualCodeSize); + +Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata&); + +void freeReleaseFences(hidl_vec&); + +status_t fillCaptureResultCommon(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp, + camera_metadata_ro_entry& activeArraySize); + +// Interface for OutputThread calling back to parent +struct OutputThreadInterface : public virtual RefBase { + virtual ::android::hardware::camera::common::V1_0::Status importBuffer( + int32_t streamId, uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, bool allowEmptyBuf) = 0; + + virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) = 0; + + // Callbacks are fired within the method if msgs/results are nullptr. + // Otherwise the callbacks will be returned and caller is responsible to + // fire the callback later + virtual ::android::hardware::camera::common::V1_0::Status processCaptureRequestError( + const std::shared_ptr&, + /*out*/std::vector* msgs = nullptr, + /*out*/std::vector* results = nullptr) = 0; + + virtual ::android::hardware::camera::common::V1_0::Status processCaptureResult( + std::shared_ptr&) = 0; + + virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const = 0; +}; + } // namespace implementation } // namespace V3_4 + +namespace V3_6 { +namespace implementation { + +// A CPU copy of a mapped V4L2Frame. Will map the input V4L2 frame. +class AllocatedV4L2Frame : public V3_4::implementation::Frame { +public: + AllocatedV4L2Frame(sp frameIn); + ~AllocatedV4L2Frame() override; + virtual int getData(uint8_t** outData, size_t* dataSize) override; +private: + std::vector mData; +}; + +} // namespace implementation +} // namespace V3_6 } // namespace device } // namespace camera } // namespace hardware diff --git a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp index 00c1d0de39..287ac324ec 100644 --- a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp +++ b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp @@ -80,7 +80,7 @@ Status ExternalCameraDeviceSession::importRequestLocked( ExternalCameraDeviceSession::BufferRequestThread::BufferRequestThread( - wp parent, + wp parent, sp callbacks) : mParent(parent), mCallbacks(callbacks) {} @@ -254,7 +254,8 @@ void ExternalCameraDeviceSession::initOutputThread() { mBufferRequestThread = new BufferRequestThread(this, mCallback_3_5); mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY); } - mOutputThread = new OutputThread(this, mCroppingType, mBufferRequestThread); + mOutputThread = new OutputThread( + this, mCroppingType, mCameraCharacteristics, mBufferRequestThread); } void ExternalCameraDeviceSession::closeOutputThreadImpl() { @@ -271,10 +272,11 @@ void ExternalCameraDeviceSession::closeOutputThread() { } ExternalCameraDeviceSession::OutputThread::OutputThread( - wp parent, + wp parent, CroppingType ct, + const common::V1_0::helper::CameraMetadata& chars, sp bufReqThread) : - V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct), + V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct, chars), mBufferRequestThread(bufReqThread) {} ExternalCameraDeviceSession::OutputThread::~OutputThread() {} diff --git a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h index 281f93a13b..e89ef45f52 100644 --- a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h +++ b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H -#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H +#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H #include #include @@ -72,6 +72,7 @@ using ::android::base::unique_fd; using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format; using ::android::hardware::camera::device::V3_4::implementation::CroppingType; +using ::android::hardware::camera::device::V3_4::implementation::HalStreamBuffer; struct ExternalCameraDeviceSession : public V3_4::implementation::ExternalCameraDeviceSession { @@ -97,6 +98,62 @@ struct ExternalCameraDeviceSession : public V3_4::implementation::ExternalCamera config, supportedFormats, devCfg); } + class BufferRequestThread : public android::Thread { + public: + BufferRequestThread( + wp parent, + sp callbacks); + + int requestBufferStart(const std::vector&); + int waitForBufferRequestDone( + /*out*/std::vector*); + + virtual bool threadLoop() override; + + private: + void waitForNextRequest(); + + const wp mParent; + const sp mCallbacks; + + std::mutex mLock; + bool mRequestingBuffer = false; + + std::vector mBufferReqs; + std::vector mPendingReturnBufferReqs; + // mHalBufferReqs is not under mLock protection during the HIDL transaction + hidl_vec mHalBufferReqs; + + // request buffers takes much less time in steady state, but can take much longer + // when requesting 1st buffer from a stream. + // TODO: consider a separate timeout for new vs. steady state? + // TODO: or make sure framework is warming up the pipeline during configure new stream? + static const int kReqProcTimeoutMs = 66; + + static const int kReqWaitTimeoutMs = 33; + static const int kReqWaitTimesWarn = 90; // 33ms * 90 ~= 3 sec + std::condition_variable mRequestCond; // signaled when a new buffer request incoming + std::condition_variable mRequestDoneCond; // signaled when a request is done + }; + + class OutputThread : + public V3_4::implementation::ExternalCameraDeviceSession::OutputThread { + public: + // TODO: pass buffer request thread to OutputThread ctor + OutputThread(wp parent, CroppingType, + const common::V1_0::helper::CameraMetadata&, + sp bufReqThread); + virtual ~OutputThread(); + + protected: + // Methods to request output buffer in parallel + virtual int requestBufferStart(const std::vector&) override; + virtual int waitForBufferRequestDone( + /*out*/std::vector*) override; + + const sp mBufferRequestThread; + }; + protected: // Methods from v3.4 and earlier will trampoline to inherited implementation Return configureStreams_3_5( @@ -120,63 +177,8 @@ protected: hidl_vec& allBufPtrs, hidl_vec& allFences) override; - class BufferRequestThread : public android::Thread { - public: - BufferRequestThread( - wp parent, - sp callbacks); - - int requestBufferStart(const std::vector&); - int waitForBufferRequestDone( - /*out*/std::vector*); - - virtual bool threadLoop() override; - - private: - void waitForNextRequest(); - - const wp mParent; - const sp mCallbacks; - - std::mutex mLock; - bool mRequestingBuffer = false; - - std::vector mBufferReqs; - std::vector mPendingReturnBufferReqs; - // mHalBufferReqs is not under mLock protection during the HIDL transaction - hidl_vec mHalBufferReqs; - - // request buffers takes much less time in steady state, but can take much longer - // when requesting 1st buffer from a stream. - // TODO: consider a separate timeout for new vs. steady state? - // TODO: or make sure framework is warming up the pipeline during configure new stream? - static const int kReqProcTimeoutMs = 66; - - static const int kReqWaitTimeoutMs = 33; - static const int kReqWaitTimesWarn = 90; // 33ms * 90 ~= 3 sec - std::condition_variable mRequestCond; // signaled when a new buffer request incoming - std::condition_variable mRequestDoneCond; // signaled when a request is done - }; - sp mBufferRequestThread; - class OutputThread : - public V3_4::implementation::ExternalCameraDeviceSession::OutputThread { - public: - // TODO: pass buffer request thread to OutputThread ctor - OutputThread(wp parent, CroppingType, - sp bufReqThread); - virtual ~OutputThread(); - - protected: - // Methods to request output buffer in parallel - virtual int requestBufferStart(const std::vector&) override; - virtual int waitForBufferRequestDone( - /*out*/std::vector*) override; - - const sp mBufferRequestThread; - }; - sp mCallback_3_5; bool mSupportBufMgr; @@ -270,4 +272,4 @@ private: } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H diff --git a/camera/device/3.6/default/Android.bp b/camera/device/3.6/default/Android.bp index ce51185193..a2ddebdd24 100644 --- a/camera/device/3.6/default/Android.bp +++ b/camera/device/3.6/default/Android.bp @@ -28,6 +28,7 @@ cc_library_shared { srcs: [ "ExternalCameraDevice.cpp", "ExternalCameraDeviceSession.cpp", + "ExternalCameraOfflineSession.cpp", ], shared_libs: [ "libhidlbase", diff --git a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp index e14ae992b8..0cc81bbe9e 100644 --- a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp +++ b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp @@ -73,12 +73,8 @@ Return ExternalCameraDeviceSession::configureStreams_3_6( Status status = configureStreams(config_v32, &outStreams_v33, blobBufferSize); - outStreams.streams.resize(outStreams_v33.streams.size()); - for (size_t i = 0; i < outStreams.streams.size(); i++) { - outStreams.streams[i].v3_4.v3_3 = outStreams_v33.streams[i]; - // TODO: implement it later - outStreams.streams[i].supportOffline = false; - } + fillOutputStream3_6(outStreams_v33, &outStreams); + _hidl_cb(status, outStreams); return Void(); } @@ -86,12 +82,273 @@ Return ExternalCameraDeviceSession::configureStreams_3_6( Return ExternalCameraDeviceSession::switchToOffline( const hidl_vec& streamsToKeep, ICameraDeviceSession::switchToOffline_cb _hidl_cb) { - // TODO: implement this - (void) streamsToKeep; - (void) _hidl_cb; + std::vector msgs; + std::vector results; + CameraOfflineSessionInfo info; + sp session; + + Status st = switchToOffline(streamsToKeep, &msgs, &results, &info, &session); + + mCallback->notify(msgs); + hidl_vec hidlResults(std::move(results)); + invokeProcessCaptureResultCallback(hidlResults, /* tryWriteFmq */true); + V3_4::implementation::freeReleaseFences(hidlResults); + + _hidl_cb(st, info, session); return Void(); } +void ExternalCameraDeviceSession::fillOutputStream3_6( + const V3_3::HalStreamConfiguration& outStreams_v33, + /*out*/V3_6::HalStreamConfiguration* outStreams_v36) { + if (outStreams_v36 == nullptr) { + ALOGE("%s: outStreams_v36 must not be null!", __FUNCTION__); + return; + } + Mutex::Autolock _l(mLock); + outStreams_v36->streams.resize(outStreams_v33.streams.size()); + for (size_t i = 0; i < outStreams_v36->streams.size(); i++) { + outStreams_v36->streams[i].v3_4.v3_3 = outStreams_v33.streams[i]; + outStreams_v36->streams[i].supportOffline = + supportOfflineLocked(outStreams_v33.streams[i].v3_2.id); + } +} + +bool ExternalCameraDeviceSession::supportOfflineLocked(int32_t streamId) { + const Stream& stream = mStreamMap[streamId]; + if (stream.format == PixelFormat::BLOB && + stream.dataSpace == static_cast(Dataspace::V0_JFIF)) { + return true; + } + // TODO: support YUV output stream? + return false; +} + +bool ExternalCameraDeviceSession::canDropRequest(const hidl_vec& offlineStreams, + std::shared_ptr halReq) { + for (const auto& buffer : halReq->buffers) { + for (auto offlineStreamId : offlineStreams) { + if (buffer.streamId == offlineStreamId) { + return false; + } + } + } + // Only drop a request completely if it has no offline output + return true; +} + +void ExternalCameraDeviceSession::fillOfflineSessionInfo(const hidl_vec& offlineStreams, + std::deque>& offlineReqs, + const std::map& circulatingBuffers, + /*out*/CameraOfflineSessionInfo* info) { + if (info == nullptr) { + ALOGE("%s: output info must not be null!", __FUNCTION__); + return; + } + + info->offlineStreams.resize(offlineStreams.size()); + info->offlineRequests.resize(offlineReqs.size()); + + std::unordered_map outstandingBufs(offlineStreams.size()); + for (const auto streamId : offlineStreams) { + outstandingBufs.insert({streamId, 0}); + } + // Fill in offline reqs and count outstanding buffers + for (size_t i = 0; i < offlineReqs.size(); i++) { + info->offlineRequests[i].frameNumber = offlineReqs[i]->frameNumber; + info->offlineRequests[i].pendingStreams.resize(offlineReqs[i]->buffers.size()); + for (size_t bIdx = 0; bIdx < offlineReqs[i]->buffers.size(); bIdx++) { + int32_t streamId = offlineReqs[i]->buffers[bIdx].streamId; + info->offlineRequests[i].pendingStreams[bIdx] = streamId; + outstandingBufs[streamId]++; + } + } + + for (size_t i = 0; i < offlineStreams.size(); i++) { + int32_t streamId = offlineStreams[i]; + info->offlineStreams[i].id = streamId; + info->offlineStreams[i].numOutstandingBuffers = outstandingBufs[streamId]; + const CirculatingBuffers& bufIdMap = circulatingBuffers.at(streamId); + info->offlineStreams[i].circulatingBufferIds.resize(bufIdMap.size()); + size_t bIdx = 0; + for (const auto& pair : bufIdMap) { + // Fill in bufferId + info->offlineStreams[i].circulatingBufferIds[bIdx++] = pair.first; + } + + } +} + +Status ExternalCameraDeviceSession::switchToOffline(const hidl_vec& offlineStreams, + /*out*/std::vector* msgs, + /*out*/std::vector* results, + /*out*/CameraOfflineSessionInfo* info, + /*out*/sp* session) { + ATRACE_CALL(); + if (offlineStreams.size() > 1) { + ALOGE("%s: more than one offline stream is not supported", __FUNCTION__); + return Status::ILLEGAL_ARGUMENT; + } + + if (msgs == nullptr || results == nullptr || info == nullptr || session == nullptr) { + ALOGE("%s: output arguments (%p, %p, %p, %p) must not be null", __FUNCTION__, + msgs, results, info, session); + return Status::ILLEGAL_ARGUMENT; + } + + msgs->clear(); + results->clear(); + + Mutex::Autolock _il(mInterfaceLock); + Status status = initStatus(); + if (status != Status::OK) { + return status; + } + + Mutex::Autolock _l(mLock); + for (auto streamId : offlineStreams) { + if (!supportOfflineLocked(streamId)) { + return Status::ILLEGAL_ARGUMENT; + } + } + + // pause output thread and get all remaining inflight requests + auto remainingReqs = mOutputThread->switchToOffline(); + std::vector> halReqs; + + // Send out buffer/request error for remaining requests and filter requests + // to be handled in offline mode + for (auto& halReq : remainingReqs) { + bool dropReq = canDropRequest(offlineStreams, halReq); + if (dropReq) { + // Request is dropped completely. Just send request error and + // there is no need to send the request to offline session + processCaptureRequestError(halReq, msgs, results); + continue; + } + + // All requests reach here must have at least one offline stream output + NotifyMsg shutter; + shutter.type = MsgType::SHUTTER; + shutter.msg.shutter.frameNumber = halReq->frameNumber; + shutter.msg.shutter.timestamp = halReq->shutterTs; + msgs->push_back(shutter); + + std::vector offlineBuffers; + for (const auto& buffer : halReq->buffers) { + bool dropBuffer = true; + for (auto offlineStreamId : offlineStreams) { + if (buffer.streamId == offlineStreamId) { + dropBuffer = false; + break; + } + } + if (dropBuffer) { + NotifyMsg error; + error.type = MsgType::ERROR; + error.msg.error.frameNumber = halReq->frameNumber; + error.msg.error.errorStreamId = buffer.streamId; + error.msg.error.errorCode = ErrorCode::ERROR_BUFFER; + msgs->push_back(error); + + CaptureResult result; + result.frameNumber = halReq->frameNumber; + result.partialResult = 0; // buffer only result + result.inputBuffer.streamId = -1; + result.outputBuffers.resize(1); + result.outputBuffers[0].streamId = buffer.streamId; + result.outputBuffers[0].bufferId = buffer.bufferId; + result.outputBuffers[0].status = BufferStatus::ERROR; + if (buffer.acquireFence >= 0) { + native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0); + handle->data[0] = buffer.acquireFence; + result.outputBuffers[0].releaseFence.setTo(handle, /*shouldOwn*/false); + } + results->push_back(result); + } else { + offlineBuffers.push_back(buffer); + } + } + halReq->buffers = offlineBuffers; + halReqs.push_back(halReq); + } + + // convert hal requests to offline request + std::deque> offlineReqs(halReqs.size()); + for (auto& v4lReq : halReqs) { + std::shared_ptr halReq = std::make_shared(); + halReq->frameNumber = v4lReq->frameNumber; + halReq->setting = v4lReq->setting; + halReq->shutterTs = v4lReq->shutterTs; + halReq->buffers = v4lReq->buffers; + sp v4l2Frame = + static_cast(v4lReq->frameIn.get()); + halReq->frameIn = new AllocatedV4L2Frame(v4l2Frame); + offlineReqs.push_back(halReq); + // enqueue V4L2 frame + enqueueV4l2Frame(v4l2Frame); + } + + // Collect buffer caches/streams + hidl_vec streamInfos; + streamInfos.resize(offlineStreams.size()); + std::map circulatingBuffers; + { + Mutex::Autolock _l(mCbsLock); + size_t idx = 0; + for(auto streamId : offlineStreams) { + circulatingBuffers[streamId] = mCirculatingBuffers.at(streamId); + mCirculatingBuffers.erase(streamId); + streamInfos[idx++] = mStreamMap.at(streamId); + mStreamMap.erase(streamId); + } + } + + fillOfflineSessionInfo(offlineStreams, offlineReqs, circulatingBuffers, info); + + // create the offline session object + bool afTrigger; + { + std::lock_guard lk(mAfTriggerLock); + afTrigger = mAfTrigger; + } + sp sessionImpl = new ExternalCameraOfflineSession( + mCroppingType, mCameraCharacteristics, mCameraId, + mExifMake, mExifModel, mBlobBufferSize, afTrigger, + streamInfos, offlineReqs, circulatingBuffers); + + bool initFailed = sessionImpl->initialize(); + if (initFailed) { + ALOGE("%s: offline session initialize failed!", __FUNCTION__); + return Status::INTERNAL_ERROR; + } + + // cleanup stream and buffer caches + { + Mutex::Autolock _l(mCbsLock); + for(auto pair : mStreamMap) { + cleanupBuffersLocked(/*Stream ID*/pair.first); + } + mCirculatingBuffers.clear(); + } + mStreamMap.clear(); + + // update inflight records + { + std::lock_guard lk(mInflightFramesLock); + mInflightFrames.clear(); + } + + // stop v4l2 streaming + if (v4l2StreamOffLocked() !=0) { + ALOGE("%s: stop V4L2 streaming failed!", __FUNCTION__); + return Status::INTERNAL_ERROR; + } + + *session = sessionImpl->getInterface(); + return Status::OK; +} + } // namespace implementation } // namespace V3_6 } // namespace device diff --git a/camera/device/3.6/default/ExternalCameraOfflineSession.cpp b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp new file mode 100644 index 0000000000..e606fda832 --- /dev/null +++ b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp @@ -0,0 +1,554 @@ +/* + * 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. + */ + +#define LOG_TAG "ExtCamOfflnSsn@3.6" +#define ATRACE_TAG ATRACE_TAG_CAMERA +#include + +#include +#include + +#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs +#include + +#include +#include "ExternalCameraOfflineSession.h" + +namespace { + +// Size of request/result metadata fast message queue. Change to 0 to always use hwbinder buffer. +static constexpr size_t kMetadataMsgQueueSize = 1 << 18 /* 256kB */; + +} // anonymous namespace + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_6 { +namespace implementation { + +// static instance +HandleImporter ExternalCameraOfflineSession::sHandleImporter; + +using V3_5::implementation::ExternalCameraDeviceSession; + +ExternalCameraOfflineSession::ExternalCameraOfflineSession( + const CroppingType& croppingType, + const common::V1_0::helper::CameraMetadata& chars, + const std::string& cameraId, + const std::string& exifMake, + const std::string& exifModel, + const uint32_t blobBufferSize, + const bool afTrigger, + const hidl_vec& offlineStreams, + std::deque>& offlineReqs, + const std::map& circulatingBuffers) : + mCroppingType(croppingType), mChars(chars), mCameraId(cameraId), + mExifMake(exifMake), mExifModel(exifModel), mBlobBufferSize(blobBufferSize), + mAfTrigger(afTrigger), mOfflineStreams(offlineStreams), mOfflineReqs(offlineReqs), + mCirculatingBuffers(circulatingBuffers) {} + +ExternalCameraOfflineSession::~ExternalCameraOfflineSession() { + close(); +} + +bool ExternalCameraOfflineSession::initialize() { + mResultMetadataQueue = std::make_shared( + kMetadataMsgQueueSize, false /* non blocking */); + if (!mResultMetadataQueue->isValid()) { + ALOGE("%s: invalid result fmq", __FUNCTION__); + return true; + } + return false; +} + +void ExternalCameraOfflineSession::initOutputThread() { + if (mOutputThread != nullptr) { + ALOGE("%s: OutputThread already exist!", __FUNCTION__); + return; + } + + mBufferRequestThread = new ExternalCameraDeviceSession::BufferRequestThread( + this, mCallback); + mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY); + + mOutputThread = new OutputThread(this, mCroppingType, mChars, + mBufferRequestThread, mOfflineReqs); + + mOutputThread->setExifMakeModel(mExifMake, mExifModel); + + Size inputSize = { mOfflineReqs[0]->frameIn->mWidth, mOfflineReqs[0]->frameIn->mHeight}; + Size maxThumbSize = V3_4::implementation::getMaxThumbnailResolution(mChars); + mOutputThread->allocateIntermediateBuffers( + inputSize, maxThumbSize, mOfflineStreams, mBlobBufferSize); + + mOutputThread->run("ExtCamOfflnOut", PRIORITY_DISPLAY); +} + +bool ExternalCameraOfflineSession::OutputThread::threadLoop() { + auto parent = mParent.promote(); + if (parent == nullptr) { + ALOGE("%s: session has been disconnected!", __FUNCTION__); + return false; + } + + if (mOfflineReqs.empty()) { + ALOGI("%s: all offline requests are processed. Stopping.", __FUNCTION__); + return false; + } + + std::shared_ptr req = mOfflineReqs.front(); + mOfflineReqs.pop_front(); + + auto onDeviceError = [&](auto... args) { + ALOGE(args...); + parent->notifyError( + req->frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE); + signalRequestDone(); + return false; + }; + + if (req->frameIn->mFourcc != V4L2_PIX_FMT_MJPEG && req->frameIn->mFourcc != V4L2_PIX_FMT_Z16) { + return onDeviceError("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__, + req->frameIn->mFourcc & 0xFF, + (req->frameIn->mFourcc >> 8) & 0xFF, + (req->frameIn->mFourcc >> 16) & 0xFF, + (req->frameIn->mFourcc >> 24) & 0xFF); + } + + int res = requestBufferStart(req->buffers); + if (res != 0) { + ALOGE("%s: send BufferRequest failed! res %d", __FUNCTION__, res); + return onDeviceError("%s: failed to send buffer request!", __FUNCTION__); + } + + std::unique_lock lk(mBufferLock); + // Convert input V4L2 frame to YU12 of the same size + // TODO: see if we can save some computation by converting to YV12 here + uint8_t* inData; + size_t inDataSize; + if (req->frameIn->getData(&inData, &inDataSize) != 0) { + lk.unlock(); + return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__); + } + + // TODO: in some special case maybe we can decode jpg directly to gralloc output? + if (req->frameIn->mFourcc == V4L2_PIX_FMT_MJPEG) { + ATRACE_BEGIN("MJPGtoI420"); + int res = libyuv::MJPGToI420( + inData, inDataSize, static_cast(mYu12FrameLayout.y), mYu12FrameLayout.yStride, + static_cast(mYu12FrameLayout.cb), mYu12FrameLayout.cStride, + static_cast(mYu12FrameLayout.cr), mYu12FrameLayout.cStride, + mYu12Frame->mWidth, mYu12Frame->mHeight, mYu12Frame->mWidth, mYu12Frame->mHeight); + ATRACE_END(); + + if (res != 0) { + // For some webcam, the first few V4L2 frames might be malformed... + ALOGE("%s: Convert V4L2 frame to YU12 failed! res %d", __FUNCTION__, res); + lk.unlock(); + Status st = parent->processCaptureRequestError(req); + if (st != Status::OK) { + return onDeviceError("%s: failed to process capture request error!", __FUNCTION__); + } + signalRequestDone(); + return true; + } + } + + ATRACE_BEGIN("Wait for BufferRequest done"); + res = waitForBufferRequestDone(&req->buffers); + ATRACE_END(); + + if (res != 0) { + ALOGE("%s: wait for BufferRequest done failed! res %d", __FUNCTION__, res); + lk.unlock(); + return onDeviceError("%s: failed to process buffer request error!", __FUNCTION__); + } + + ALOGV("%s processing new request", __FUNCTION__); + const int kSyncWaitTimeoutMs = 500; + for (auto& halBuf : req->buffers) { + if (*(halBuf.bufPtr) == nullptr) { + ALOGW("%s: buffer for stream %d missing", __FUNCTION__, halBuf.streamId); + halBuf.fenceTimeout = true; + } else if (halBuf.acquireFence >= 0) { + int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs); + if (ret) { + halBuf.fenceTimeout = true; + } else { + ::close(halBuf.acquireFence); + halBuf.acquireFence = -1; + } + } + + if (halBuf.fenceTimeout) { + continue; + } + + // Gralloc lockYCbCr the buffer + switch (halBuf.format) { + case PixelFormat::BLOB: { + int ret = createJpegLocked(halBuf, req->setting); + + if(ret != 0) { + lk.unlock(); + return onDeviceError("%s: createJpegLocked failed with %d", + __FUNCTION__, ret); + } + } break; + case PixelFormat::Y16: { + void* outLayout = sHandleImporter.lock(*(halBuf.bufPtr), halBuf.usage, inDataSize); + + std::memcpy(outLayout, inData, inDataSize); + + int relFence = sHandleImporter.unlock(*(halBuf.bufPtr)); + if (relFence >= 0) { + halBuf.acquireFence = relFence; + } + } break; + case PixelFormat::YCBCR_420_888: + case PixelFormat::YV12: { + IMapper::Rect outRect {0, 0, + static_cast(halBuf.width), + static_cast(halBuf.height)}; + YCbCrLayout outLayout = sHandleImporter.lockYCbCr( + *(halBuf.bufPtr), halBuf.usage, outRect); + ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d", + __FUNCTION__, outLayout.y, outLayout.cb, outLayout.cr, + outLayout.yStride, outLayout.cStride, outLayout.chromaStep); + + // Convert to output buffer size/format + uint32_t outputFourcc = V3_4::implementation::getFourCcFromLayout(outLayout); + ALOGV("%s: converting to format %c%c%c%c", __FUNCTION__, + outputFourcc & 0xFF, + (outputFourcc >> 8) & 0xFF, + (outputFourcc >> 16) & 0xFF, + (outputFourcc >> 24) & 0xFF); + + YCbCrLayout cropAndScaled; + ATRACE_BEGIN("cropAndScaleLocked"); + int ret = cropAndScaleLocked( + mYu12Frame, + Size { halBuf.width, halBuf.height }, + &cropAndScaled); + ATRACE_END(); + if (ret != 0) { + lk.unlock(); + return onDeviceError("%s: crop and scale failed!", __FUNCTION__); + } + + Size sz {halBuf.width, halBuf.height}; + ATRACE_BEGIN("formatConvert"); + ret = V3_4::implementation::formatConvert(cropAndScaled, outLayout, sz, outputFourcc); + ATRACE_END(); + if (ret != 0) { + lk.unlock(); + return onDeviceError("%s: format coversion failed!", __FUNCTION__); + } + int relFence = sHandleImporter.unlock(*(halBuf.bufPtr)); + if (relFence >= 0) { + halBuf.acquireFence = relFence; + } + } break; + default: + lk.unlock(); + return onDeviceError("%s: unknown output format %x", __FUNCTION__, halBuf.format); + } + } // for each buffer + mScaledYu12Frames.clear(); + + // Don't hold the lock while calling back to parent + lk.unlock(); + Status st = parent->processCaptureResult(req); + if (st != Status::OK) { + return onDeviceError("%s: failed to process capture result!", __FUNCTION__); + } + signalRequestDone(); + return true; +} + +Status ExternalCameraOfflineSession::importBuffer(int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf) { + Mutex::Autolock _l(mCbsLock); + return V3_4::implementation::importBufferImpl( + mCirculatingBuffers, sHandleImporter, streamId, + bufId, buf, outBufPtr, allowEmptyBuf); + return Status::OK; +}; + +#define UPDATE(md, tag, data, size) \ +do { \ + if ((md).update((tag), (data), (size))) { \ + ALOGE("Update " #tag " failed!"); \ + return BAD_VALUE; \ + } \ +} while (0) + +status_t ExternalCameraOfflineSession::fillCaptureResult( + common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) { + bool afTrigger = false; + { + std::lock_guard lk(mAfTriggerLock); + afTrigger = mAfTrigger; + if (md.exists(ANDROID_CONTROL_AF_TRIGGER)) { + camera_metadata_entry entry = md.find(ANDROID_CONTROL_AF_TRIGGER); + if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) { + mAfTrigger = afTrigger = true; + } else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) { + mAfTrigger = afTrigger = false; + } + } + } + + // For USB camera, the USB camera handles everything and we don't have control + // over AF. We only simply fake the AF metadata based on the request + // received here. + uint8_t afState; + if (afTrigger) { + afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED; + } else { + afState = ANDROID_CONTROL_AF_STATE_INACTIVE; + } + UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1); + + camera_metadata_ro_entry activeArraySize = + mChars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE); + + return V3_4::implementation::fillCaptureResultCommon(md, timestamp, activeArraySize); +} + +#undef UPDATE + +Status ExternalCameraOfflineSession::processCaptureResult(std::shared_ptr& req) { + ATRACE_CALL(); + // Fill output buffers + hidl_vec results; + results.resize(1); + CaptureResult& result = results[0]; + result.frameNumber = req->frameNumber; + result.partialResult = 1; + result.inputBuffer.streamId = -1; + result.outputBuffers.resize(req->buffers.size()); + for (size_t i = 0; i < req->buffers.size(); i++) { + result.outputBuffers[i].streamId = req->buffers[i].streamId; + result.outputBuffers[i].bufferId = req->buffers[i].bufferId; + if (req->buffers[i].fenceTimeout) { + result.outputBuffers[i].status = BufferStatus::ERROR; + if (req->buffers[i].acquireFence >= 0) { + native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0); + handle->data[0] = req->buffers[i].acquireFence; + result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false); + } + notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER); + } else { + result.outputBuffers[i].status = BufferStatus::OK; + // TODO: refactor + if (req->buffers[i].acquireFence >= 0) { + native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0); + handle->data[0] = req->buffers[i].acquireFence; + result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false); + } + } + } + + // Fill capture result metadata + fillCaptureResult(req->setting, req->shutterTs); + const camera_metadata_t *rawResult = req->setting.getAndLock(); + V3_2::implementation::convertToHidl(rawResult, &result.result); + req->setting.unlock(rawResult); + + // Callback into framework + invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true); + V3_4::implementation::freeReleaseFences(results); + return Status::OK; +}; + +void ExternalCameraOfflineSession::invokeProcessCaptureResultCallback( + hidl_vec &results, bool tryWriteFmq) { + if (mProcessCaptureResultLock.tryLock() != OK) { + const nsecs_t NS_TO_SECOND = 1000000000; + ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__); + if (mProcessCaptureResultLock.timedLock(/* 1s */NS_TO_SECOND) != OK) { + ALOGE("%s: cannot acquire lock in 1s, cannot proceed", + __FUNCTION__); + return; + } + } + if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) { + for (CaptureResult &result : results) { + if (result.result.size() > 0) { + if (mResultMetadataQueue->write(result.result.data(), result.result.size())) { + result.fmqResultSize = result.result.size(); + result.result.resize(0); + } else { + ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__); + result.fmqResultSize = 0; + } + } else { + result.fmqResultSize = 0; + } + } + } + auto status = mCallback->processCaptureResult(results); + if (!status.isOk()) { + ALOGE("%s: processCaptureResult ERROR : %s", __FUNCTION__, + status.description().c_str()); + } + + mProcessCaptureResultLock.unlock(); +} + +Status ExternalCameraOfflineSession::processCaptureRequestError( + const std::shared_ptr& req, + /*out*/std::vector* outMsgs, + /*out*/std::vector* outResults) { + ATRACE_CALL(); + + if (outMsgs == nullptr) { + notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST); + } else { + NotifyMsg shutter; + shutter.type = MsgType::SHUTTER; + shutter.msg.shutter.frameNumber = req->frameNumber; + shutter.msg.shutter.timestamp = req->shutterTs; + + NotifyMsg error; + error.type = MsgType::ERROR; + error.msg.error.frameNumber = req->frameNumber; + error.msg.error.errorStreamId = -1; + error.msg.error.errorCode = ErrorCode::ERROR_REQUEST; + outMsgs->push_back(shutter); + outMsgs->push_back(error); + } + + // Fill output buffers + hidl_vec results; + results.resize(1); + CaptureResult& result = results[0]; + result.frameNumber = req->frameNumber; + result.partialResult = 1; + result.inputBuffer.streamId = -1; + result.outputBuffers.resize(req->buffers.size()); + for (size_t i = 0; i < req->buffers.size(); i++) { + result.outputBuffers[i].streamId = req->buffers[i].streamId; + result.outputBuffers[i].bufferId = req->buffers[i].bufferId; + result.outputBuffers[i].status = BufferStatus::ERROR; + if (req->buffers[i].acquireFence >= 0) { + native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0); + handle->data[0] = req->buffers[i].acquireFence; + result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false); + } + } + + if (outResults == nullptr) { + // Callback into framework + invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true); + V3_4::implementation::freeReleaseFences(results); + } else { + outResults->push_back(result); + } + return Status::OK; +}; + +ssize_t ExternalCameraOfflineSession::getJpegBufferSize( + uint32_t /*width*/, uint32_t /*height*/) const { + // Empty implementation here as the jpeg buffer size is passed in by ctor + return 0; +}; + +void ExternalCameraOfflineSession::notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) { + NotifyMsg msg; + msg.type = MsgType::ERROR; + msg.msg.error.frameNumber = frameNumber; + msg.msg.error.errorStreamId = streamId; + msg.msg.error.errorCode = ec; + mCallback->notify({msg}); +}; + +Return ExternalCameraOfflineSession::setCallback(const sp& cb) { + Mutex::Autolock _il(mInterfaceLock); + if (mCallback != nullptr && cb != nullptr) { + ALOGE("%s: callback must not be set twice!", __FUNCTION__); + return Void(); + } + mCallback = cb; + + initOutputThread(); + + if (mOutputThread == nullptr) { + ALOGE("%s: init OutputThread failed!", __FUNCTION__); + } + return Void(); +} + +Return ExternalCameraOfflineSession::getCaptureResultMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) { + Mutex::Autolock _il(mInterfaceLock); + _hidl_cb(*mResultMetadataQueue->getDesc()); + return Void(); +} + +void ExternalCameraOfflineSession::cleanupBuffersLocked(int id) { + for (auto& pair : mCirculatingBuffers.at(id)) { + sHandleImporter.freeBuffer(pair.second); + } + mCirculatingBuffers[id].clear(); + mCirculatingBuffers.erase(id); +} + +Return ExternalCameraOfflineSession::close() { + Mutex::Autolock _il(mInterfaceLock); + { + Mutex::Autolock _l(mLock); + if (mClosed) { + ALOGW("%s: offline session already closed!", __FUNCTION__); + return Void(); + } + } + if (mBufferRequestThread) { + mBufferRequestThread->requestExit(); + mBufferRequestThread->join(); + mBufferRequestThread.clear(); + } + if (mOutputThread) { + mOutputThread->flush(); + mOutputThread->requestExit(); + mOutputThread->join(); + mOutputThread.clear(); + } + + Mutex::Autolock _l(mLock); + // free all buffers + { + Mutex::Autolock _cbl(mCbsLock); + for(auto stream : mOfflineStreams) { + cleanupBuffersLocked(stream.id); + } + } + mCallback.clear(); + mClosed = true; + return Void(); +} + +} // namespace implementation +} // namespace V3_6 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h index 0e57c4c243..db0d9a548b 100644 --- a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h +++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h @@ -14,12 +14,13 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE3SESSION_H -#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE3SESSION_H +#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H #include #include #include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h> +#include "ExternalCameraOfflineSession.h" namespace android { namespace hardware { @@ -37,6 +38,7 @@ using ::android::hardware::camera::device::V3_2::RequestTemplate; using ::android::hardware::camera::device::V3_2::Stream; using ::android::hardware::camera::device::V3_5::StreamConfiguration; using ::android::hardware::camera::device::V3_6::ICameraDeviceSession; +using ::android::hardware::camera::device::V3_6::ICameraOfflineSession; using ::android::hardware::camera::common::V1_0::Status; using ::android::hardware::camera::external::common::ExternalCameraConfig; using ::android::hardware::graphics::common::V1_0::PixelFormat; @@ -69,13 +71,6 @@ struct ExternalCameraDeviceSession : public V3_5::implementation::ExternalCamera return new TrampolineSessionInterface_3_6(this); } - static Status isStreamCombinationSupported(const V3_2::StreamConfiguration& config, - const std::vector& supportedFormats, - const ExternalCameraConfig& devCfg) { - return V3_4::implementation::ExternalCameraDeviceSession::isStreamCombinationSupported( - config, supportedFormats, devCfg); - } - protected: // Methods from v3.5 and earlier will trampoline to inherited implementation Return configureStreams_3_6( @@ -86,6 +81,28 @@ protected: const hidl_vec& streamsToKeep, ICameraDeviceSession::switchToOffline_cb _hidl_cb); + void fillOutputStream3_6(const V3_3::HalStreamConfiguration& outStreams_v33, + /*out*/V3_6::HalStreamConfiguration* outStreams_v36); + bool supportOfflineLocked(int32_t streamId); + + // Main body of switchToOffline. This method does not invoke any callbacks + // but instead returns the necessary callbacks in output arguments so callers + // can callback later without holding any locks + Status switchToOffline(const hidl_vec& offlineStreams, + /*out*/std::vector* msgs, + /*out*/std::vector* results, + /*out*/CameraOfflineSessionInfo* info, + /*out*/sp* session); + + // Whether a request can be completely dropped when switching to offline + bool canDropRequest(const hidl_vec& offlineStreams, + std::shared_ptr halReq); + + void fillOfflineSessionInfo(const hidl_vec& offlineStreams, + std::deque>& offlineReqs, + const std::map& circulatingBuffers, + /*out*/CameraOfflineSessionInfo* info); + private: struct TrampolineSessionInterface_3_6 : public ICameraDeviceSession { @@ -188,4 +205,4 @@ private: } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE3SESSION_H +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h new file mode 100644 index 0000000000..230b67c43c --- /dev/null +++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h @@ -0,0 +1,232 @@ +/* + * 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_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H + +#include +#include +#include +#include +#include +#include +#include +#include <../../3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h> +#include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h> +#include +#include +#include + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_6 { +namespace implementation { + +using ::android::hardware::camera::device::V3_2::BufferCache; +using ::android::hardware::camera::device::V3_5::BufferRequest; +using ::android::hardware::camera::device::V3_5::BufferRequestStatus; +using ::android::hardware::camera::device::V3_2::BufferStatus; +using ::android::hardware::camera::device::V3_2::CameraMetadata; +using ::android::hardware::camera::device::V3_2::CaptureRequest; +using ::android::hardware::camera::device::V3_2::CaptureResult; +using ::android::hardware::camera::device::V3_2::ErrorCode; +using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback; +using ::android::hardware::camera::device::V3_2::MsgType; +using ::android::hardware::camera::device::V3_2::NotifyMsg; +using ::android::hardware::camera::device::V3_2::RequestTemplate; +using ::android::hardware::camera::device::V3_2::Stream; +using ::android::hardware::camera::device::V3_5::StreamConfiguration; +using ::android::hardware::camera::device::V3_2::StreamConfigurationMode; +using ::android::hardware::camera::device::V3_2::StreamRotation; +using ::android::hardware::camera::device::V3_2::StreamType; +using ::android::hardware::camera::device::V3_2::DataspaceFlags; +using ::android::hardware::camera::device::V3_2::CameraBlob; +using ::android::hardware::camera::device::V3_2::CameraBlobId; +using ::android::hardware::camera::device::V3_4::HalStreamConfiguration; +using ::android::hardware::camera::device::V3_6::ICameraOfflineSession; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::common::V1_0::helper::HandleImporter; +using ::android::hardware::camera::common::V1_0::helper::ExifUtils; +using ::android::hardware::camera::external::common::ExternalCameraConfig; +using ::android::hardware::camera::external::common::Size; +using ::android::hardware::camera::external::common::SizeHasher; +using ::android::hardware::graphics::common::V1_0::BufferUsage; +using ::android::hardware::graphics::common::V1_0::Dataspace; +using ::android::hardware::graphics::common::V1_0::PixelFormat; +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; +using ::android::hardware::MQDescriptorSync; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; +using ::android::Mutex; +using ::android::base::unique_fd; + +using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format; +using ::android::hardware::camera::device::V3_4::implementation::CroppingType; +using ::android::hardware::camera::device::V3_4::implementation::CirculatingBuffers; +using ::android::hardware::camera::device::V3_4::implementation::HalRequest; +using ::android::hardware::camera::device::V3_4::implementation::OutputThreadInterface; + +struct ExternalCameraOfflineSession : public virtual RefBase, + public virtual OutputThreadInterface { + + ExternalCameraOfflineSession( + const CroppingType& croppingType, + const common::V1_0::helper::CameraMetadata& chars, + const std::string& cameraId, + const std::string& exifMake, + const std::string& exifModel, + uint32_t blobBufferSize, + bool afTrigger, + const hidl_vec& offlineStreams, + std::deque>& offlineReqs, + const std::map& circulatingBuffers); + + bool initialize(); + + virtual ~ExternalCameraOfflineSession(); + + // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when + // dealing with minor version revs and simultaneous implementation and interface inheritance + virtual sp getInterface() { + return new TrampolineSessionInterface_3_6(this); + } + +protected: + + // Methods from OutputThreadInterface + virtual Status importBuffer(int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf) override; + + virtual Status processCaptureResult(std::shared_ptr&) override; + + virtual Status processCaptureRequestError(const std::shared_ptr&, + /*out*/std::vector* msgs = nullptr, + /*out*/std::vector* results = nullptr) override; + + virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override; + + virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override; + // End of OutputThreadInterface methods + + class OutputThread : public V3_5::implementation::ExternalCameraDeviceSession::OutputThread { + public: + OutputThread( + wp parent, CroppingType ct, + const common::V1_0::helper::CameraMetadata& chars, + sp bufReqThread, + std::deque>& offlineReqs) : + V3_5::implementation::ExternalCameraDeviceSession::OutputThread( + parent, ct, chars, bufReqThread), + mOfflineReqs(offlineReqs) {} + + virtual bool threadLoop() override; + + protected: + std::deque> mOfflineReqs; + }; // OutputThread + + + Return setCallback(const sp& cb); + + Return getCaptureResultMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb); + + Return close(); + + void initOutputThread(); + + void invokeProcessCaptureResultCallback( + hidl_vec &results, bool tryWriteFmq); + + status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp); + + void cleanupBuffersLocked(int id); + + // Protect (most of) HIDL interface methods from synchronized-entering + mutable Mutex mInterfaceLock; + + mutable Mutex mLock; // Protect all data members except otherwise noted + + bool mClosed = false; + const CroppingType mCroppingType; + const common::V1_0::helper::CameraMetadata mChars; + const std::string mCameraId; + const std::string mExifMake; + const std::string mExifModel; + const uint32_t mBlobBufferSize; + + std::mutex mAfTriggerLock; // protect mAfTrigger + bool mAfTrigger; + + const hidl_vec mOfflineStreams; + std::deque> mOfflineReqs; + + // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock + mutable Mutex mCbsLock; + std::map mCirculatingBuffers; + + static HandleImporter sHandleImporter; + + using ResultMetadataQueue = MessageQueue; + std::shared_ptr mResultMetadataQueue; + + // Protect against invokeProcessCaptureResultCallback() + Mutex mProcessCaptureResultLock; + + sp mCallback; + + sp mBufferRequestThread; + sp mOutputThread; +private: + + struct TrampolineSessionInterface_3_6 : public ICameraOfflineSession { + TrampolineSessionInterface_3_6(sp parent) : + mParent(parent) {} + + virtual Return setCallback(const sp& cb) override { + return mParent->setCallback(cb); + } + + virtual Return getCaptureResultMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override { + return mParent->getCaptureResultMetadataQueue(_hidl_cb); + } + + virtual Return close() override { + return mParent->close(); + } + + private: + sp mParent; + }; +}; + +} // namespace implementation +} // namespace V3_6 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H diff --git a/camera/provider/2.5/default/Android.bp b/camera/provider/2.5/default/Android.bp index 4563362ddb..67eb7caafd 100644 --- a/camera/provider/2.5/default/Android.bp +++ b/camera/provider/2.5/default/Android.bp @@ -52,6 +52,8 @@ cc_library_shared { "android.hardware.camera.provider@2.4-external", "android.hardware.camera.provider@2.5", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "camera.device@3.3-impl", @@ -72,7 +74,8 @@ cc_library_shared { ], header_libs: [ "camera.device@3.4-external-impl_headers", - "camera.device@3.5-external-impl_headers" + "camera.device@3.5-external-impl_headers", + "camera.device@3.6-external-impl_headers" ], export_include_dirs: ["."], } From 838c4c19d3ba483df833ee134f3d15648945d75f Mon Sep 17 00:00:00 2001 From: Zhaoming Yin Date: Thu, 16 Jan 2020 10:29:12 -0800 Subject: [PATCH 0516/1022] Add fuzzer for EVS HAL Bug: 147513710 Test: Follow go/android-fuzzing to build and test Change-Id: Ia2a64f73d3928bc529a1785e999ed7f032446f8a --- automotive/evs/1.1/vts/fuzzing/Android.bp | 50 +++++++++++ .../fuzzing/VtsHalEvsV1_1CameraOpenFuzz.cpp | 84 +++++++++++++++++++ automotive/evs/1.1/vts/fuzzing/common.h | 57 +++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 automotive/evs/1.1/vts/fuzzing/Android.bp create mode 100644 automotive/evs/1.1/vts/fuzzing/VtsHalEvsV1_1CameraOpenFuzz.cpp create mode 100644 automotive/evs/1.1/vts/fuzzing/common.h diff --git a/automotive/evs/1.1/vts/fuzzing/Android.bp b/automotive/evs/1.1/vts/fuzzing/Android.bp new file mode 100644 index 0000000000..48427ee532 --- /dev/null +++ b/automotive/evs/1.1/vts/fuzzing/Android.bp @@ -0,0 +1,50 @@ +// +// Copyright 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. +// + +cc_defaults { + name: "android.hardware.automotive.evs@fuzz-defaults", + defaults: ["VtsHalTargetTestDefaults"], + shared_libs: [ + "libui", + "libcamera_metadata", + ], + static_libs: [ + "android.hardware.automotive.evs@1.0", + "android.hardware.automotive.evs@1.1", + "android.hardware.automotive.evs@common-default-lib", + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + "android.hardware.camera.device@3.2", + ], + cflags: [ + "-O0", + "-g", + ], +} + +cc_fuzz { + name: "VtsHalEvsV1_1CameraOpenFuzz", + defaults: ["android.hardware.automotive.evs@fuzz-defaults"], + srcs: [ + "VtsHalEvsV1_1CameraOpenFuzz.cpp", + ], + fuzz_config: { + // wait for Haiku device ready + fuzz_on_haiku_device: false, + fuzz_on_haiku_host: false, + }, +} diff --git a/automotive/evs/1.1/vts/fuzzing/VtsHalEvsV1_1CameraOpenFuzz.cpp b/automotive/evs/1.1/vts/fuzzing/VtsHalEvsV1_1CameraOpenFuzz.cpp new file mode 100644 index 0000000000..4f05d21e69 --- /dev/null +++ b/automotive/evs/1.1/vts/fuzzing/VtsHalEvsV1_1CameraOpenFuzz.cpp @@ -0,0 +1,84 @@ +/* + * Copyright 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 "common.h" + +using ::android::hardware::automotive::evs::V1_0::DisplayDesc; +using ::android::hardware::camera::device::V3_2::Stream; +using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera; + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { + UNUSED(argc); + UNUSED(argv); + pEnumerator = IEvsEnumerator::getService(kEnumeratorName); + sp dr = new EvsDeathRecipient(); + + pEnumerator->linkToDeath(dr, 0); + + loadCameraList(); + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + FuzzedDataProvider fdp(data, size); + + std::vector> camList; + Stream nullCfg = {}; + + while (fdp.remaining_bytes() > 4) { + switch (fdp.ConsumeIntegralInRange(0, 3)) { + case 0: // open camera + { + uint32_t whichCam = fdp.ConsumeIntegralInRange(0, cameraInfo.size() - 1); + sp pCam = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1( + cameraInfo[whichCam].v1.cameraId, nullCfg)) + .withDefault(nullptr); + camList.emplace_back(pCam); + break; + } + case 1: // close camera + { + if (!camList.empty()) { + uint32_t whichCam = fdp.ConsumeIntegralInRange(0, camList.size() - 1); + pEnumerator->closeCamera(camList[whichCam]); + } + break; + } + case 2: // get camera info + { + if (!camList.empty()) { + uint32_t whichCam = fdp.ConsumeIntegralInRange(0, camList.size() - 1); + camList[whichCam]->getCameraInfo_1_1([](CameraDesc desc) { UNUSED(desc); }); + } + break; + } + case 3: // setMaxFramesInFlight + { + if (!camList.empty()) { + uint32_t whichCam = fdp.ConsumeIntegralInRange(0, camList.size() - 1); + int32_t numFrames = fdp.ConsumeIntegral(); + camList[whichCam]->setMaxFramesInFlight(numFrames); + } + break; + } + default: + break; + } + } + + return 0; +} diff --git a/automotive/evs/1.1/vts/fuzzing/common.h b/automotive/evs/1.1/vts/fuzzing/common.h new file mode 100644 index 0000000000..af6fd545ea --- /dev/null +++ b/automotive/evs/1.1/vts/fuzzing/common.h @@ -0,0 +1,57 @@ +/* + * Copyright 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. + */ + +#define LOG_TAG "VtsHalEvsTest" +#define UNUSED(x) (void)(x) + +const static char kEnumeratorName[] = "EvsEnumeratorHw"; + +#include +#include +#include +#include + +using namespace ::android::hardware::automotive::evs::V1_1; + +using ::android::sp; +using ::android::hardware::hidl_death_recipient; +using ::android::hardware::hidl_vec; + +static sp pEnumerator; +static std::vector cameraInfo; + +class EvsDeathRecipient : public hidl_death_recipient { + public: + void serviceDied(uint64_t /*cookie*/, + const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) override { + abort(); + } +}; + +void loadCameraList() { + // SetUp() must run first! + assert(pEnumerator != nullptr); + + // Get the camera list + pEnumerator->getCameraList_1_1([](hidl_vec cameraList) { + ALOGI("Camera list callback received %zu cameras", cameraList.size()); + cameraInfo.reserve(cameraList.size()); + for (auto&& cam : cameraList) { + ALOGI("Found camera %s", cam.v1.cameraId.c_str()); + cameraInfo.push_back(cam); + } + }); +} From 17859d49aad3d682af0bd1772e6de6d7f6f5c7cd Mon Sep 17 00:00:00 2001 From: Paul Chen Date: Fri, 31 Jan 2020 06:10:58 +0000 Subject: [PATCH 0517/1022] Revert "Camera: add webcam offline processing support" This reverts commit 7f2ce25f647ed236921a82504ef05267f1e1a4a3. Reason for revert: aosp_x86-userdebug build break Change-Id: Ie8ad10066ae5c473e183d930ab03e63b61a2dd75 --- .../default/ExternalCameraDeviceSession.cpp | 596 +++++++++++++++--- .../3.4/default/ExternalCameraUtils.cpp | 547 +--------------- .../ExternalCameraDeviceSession.h | 225 ++++--- .../ExternalCameraUtils.h | 147 +---- .../default/ExternalCameraDeviceSession.cpp | 10 +- .../ExternalCameraDeviceSession.h | 118 ++-- camera/device/3.6/default/Android.bp | 1 - .../default/ExternalCameraDeviceSession.cpp | 275 +------- .../default/ExternalCameraOfflineSession.cpp | 554 ---------------- .../ExternalCameraDeviceSession.h | 37 +- .../ExternalCameraOfflineSession.h | 232 ------- camera/provider/2.5/default/Android.bp | 5 +- 12 files changed, 714 insertions(+), 2033 deletions(-) delete mode 100644 camera/device/3.6/default/ExternalCameraOfflineSession.cpp delete mode 100644 camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp index 5f8674219c..9ff0d74687 100644 --- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp +++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp @@ -81,6 +81,8 @@ bool tryLock(std::mutex& mutex) return locked; } +buffer_handle_t sEmptyBuffer = nullptr; + } // Anonymous namespace // Static instances @@ -117,8 +119,8 @@ bool ExternalCameraDeviceSession::initialize() { std::string make, model; if (ret < 0) { ALOGW("%s v4l2 QUERYCAP failed", __FUNCTION__); - mExifMake = "Generic UVC webcam"; - mExifModel = "Generic UVC webcam"; + make = "Generic UVC webcam"; + model = "Generic UVC webcam"; } else { // capability.card is UTF-8 encoded char card[32]; @@ -132,11 +134,11 @@ bool ExternalCameraDeviceSession::initialize() { } } if (j == 0 || card[j - 1] != '\0') { - mExifMake = "Generic UVC webcam"; - mExifModel = "Generic UVC webcam"; + make = "Generic UVC webcam"; + model = "Generic UVC webcam"; } else { - mExifMake = card; - mExifModel = card; + make = card; + model = card; } } @@ -145,7 +147,7 @@ bool ExternalCameraDeviceSession::initialize() { ALOGE("%s: init OutputThread failed!", __FUNCTION__); return true; } - mOutputThread->setExifMakeModel(mExifMake, mExifModel); + mOutputThread->setExifMakeModel(make, model); status_t status = initDefaultRequests(); if (status != OK) { @@ -159,7 +161,7 @@ bool ExternalCameraDeviceSession::initialize() { ALOGE("%s: invalid request fmq", __FUNCTION__); return true; } - mResultMetadataQueue = std::make_shared( + mResultMetadataQueue = std::make_shared( kMetadataMsgQueueSize, false /* non blocking */); if (!mResultMetadataQueue->isValid()) { ALOGE("%s: invalid result fmq", __FUNCTION__); @@ -181,7 +183,7 @@ bool ExternalCameraDeviceSession::isInitFailed() { } void ExternalCameraDeviceSession::initOutputThread() { - mOutputThread = new OutputThread(this, mCroppingType, mCameraCharacteristics); + mOutputThread = new OutputThread(this, mCroppingType); } void ExternalCameraDeviceSession::closeOutputThread() { @@ -516,9 +518,35 @@ Status ExternalCameraDeviceSession::importBufferLocked(int32_t streamId, uint64_t bufId, buffer_handle_t buf, /*out*/buffer_handle_t** outBufPtr, bool allowEmptyBuf) { - return importBufferImpl( - mCirculatingBuffers, sHandleImporter, streamId, - bufId, buf, outBufPtr, allowEmptyBuf); + + if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) { + if (allowEmptyBuf) { + *outBufPtr = &sEmptyBuffer; + return Status::OK; + } else { + ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); + return Status::ILLEGAL_ARGUMENT; + } + } + + CirculatingBuffers& cbs = mCirculatingBuffers[streamId]; + if (cbs.count(bufId) == 0) { + if (buf == nullptr) { + ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); + return Status::ILLEGAL_ARGUMENT; + } + // Register a newly seen buffer + buffer_handle_t importedBuf = buf; + sHandleImporter.importBuffer(importedBuf); + if (importedBuf == nullptr) { + ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId); + return Status::INTERNAL_ERROR; + } else { + cbs[bufId] = importedBuf; + } + } + *outBufPtr = &cbs[bufId]; + return Status::OK; } Status ExternalCameraDeviceSession::importRequestLockedImpl( @@ -763,32 +791,15 @@ void ExternalCameraDeviceSession::notifyError( //TODO: refactor with processCaptureResult Status ExternalCameraDeviceSession::processCaptureRequestError( - const std::shared_ptr& req, - /*out*/std::vector* outMsgs, - /*out*/std::vector* outResults) { + const std::shared_ptr& req) { ATRACE_CALL(); // Return V4L2 buffer to V4L2 buffer queue - sp v4l2Frame = - static_cast(req->frameIn.get()); - enqueueV4l2Frame(v4l2Frame); + enqueueV4l2Frame(req->frameIn); - if (outMsgs == nullptr) { - notifyShutter(req->frameNumber, req->shutterTs); - notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST); - } else { - NotifyMsg shutter; - shutter.type = MsgType::SHUTTER; - shutter.msg.shutter.frameNumber = req->frameNumber; - shutter.msg.shutter.timestamp = req->shutterTs; + // NotifyShutter + notifyShutter(req->frameNumber, req->shutterTs); - NotifyMsg error; - error.type = MsgType::ERROR; - error.msg.error.frameNumber = req->frameNumber; - error.msg.error.errorStreamId = -1; - error.msg.error.errorCode = ErrorCode::ERROR_REQUEST; - outMsgs->push_back(shutter); - outMsgs->push_back(error); - } + notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST); // Fill output buffers hidl_vec results; @@ -815,22 +826,16 @@ Status ExternalCameraDeviceSession::processCaptureRequestError( mInflightFrames.erase(req->frameNumber); } - if (outResults == nullptr) { - // Callback into framework - invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true); - freeReleaseFences(results); - } else { - outResults->push_back(result); - } + // Callback into framework + invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true); + freeReleaseFences(results); return Status::OK; } Status ExternalCameraDeviceSession::processCaptureResult(std::shared_ptr& req) { ATRACE_CALL(); // Return V4L2 buffer to V4L2 buffer queue - sp v4l2Frame = - static_cast(req->frameIn.get()); - enqueueV4l2Frame(v4l2Frame); + enqueueV4l2Frame(req->frameIn); // NotifyShutter notifyShutter(req->frameNumber, req->shutterTs); @@ -918,10 +923,29 @@ void ExternalCameraDeviceSession::invokeProcessCaptureResultCallback( mProcessCaptureResultLock.unlock(); } +void ExternalCameraDeviceSession::freeReleaseFences(hidl_vec& results) { + for (auto& result : results) { + if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) { + native_handle_t* handle = const_cast( + result.inputBuffer.releaseFence.getNativeHandle()); + native_handle_close(handle); + native_handle_delete(handle); + } + for (auto& buf : result.outputBuffers) { + if (buf.releaseFence.getNativeHandle() != nullptr) { + native_handle_t* handle = const_cast( + buf.releaseFence.getNativeHandle()); + native_handle_close(handle); + native_handle_delete(handle); + } + } + } + return; +} + ExternalCameraDeviceSession::OutputThread::OutputThread( - wp parent, CroppingType ct, - const common::V1_0::helper::CameraMetadata& chars) : - mParent(parent), mCroppingType(ct), mCameraCharacteristics(chars) {} + wp parent, + CroppingType ct) : mParent(parent), mCroppingType(ct) {} ExternalCameraDeviceSession::OutputThread::~OutputThread() {} @@ -931,6 +955,88 @@ void ExternalCameraDeviceSession::OutputThread::setExifMakeModel( mExifModel = model; } +uint32_t ExternalCameraDeviceSession::OutputThread::getFourCcFromLayout( + const YCbCrLayout& layout) { + intptr_t cb = reinterpret_cast(layout.cb); + intptr_t cr = reinterpret_cast(layout.cr); + if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) { + // Interleaved format + if (layout.cb > layout.cr) { + return V4L2_PIX_FMT_NV21; + } else { + return V4L2_PIX_FMT_NV12; + } + } else if (layout.chromaStep == 1) { + // Planar format + if (layout.cb > layout.cr) { + return V4L2_PIX_FMT_YVU420; // YV12 + } else { + return V4L2_PIX_FMT_YUV420; // YU12 + } + } else { + return FLEX_YUV_GENERIC; + } +} + +int ExternalCameraDeviceSession::OutputThread::getCropRect( + CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) { + if (out == nullptr) { + ALOGE("%s: out is null", __FUNCTION__); + return -1; + } + + uint32_t inW = inSize.width; + uint32_t inH = inSize.height; + uint32_t outW = outSize.width; + uint32_t outH = outSize.height; + + // Handle special case where aspect ratio is close to input but scaled + // dimension is slightly larger than input + float arIn = ASPECT_RATIO(inSize); + float arOut = ASPECT_RATIO(outSize); + if (isAspectRatioClose(arIn, arOut)) { + out->left = 0; + out->top = 0; + out->width = inW; + out->height = inH; + return 0; + } + + if (ct == VERTICAL) { + uint64_t scaledOutH = static_cast(outH) * inW / outW; + if (scaledOutH > inH) { + ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d", + __FUNCTION__, outW, outH, inW, inH); + return -1; + } + scaledOutH = scaledOutH & ~0x1; // make it multiple of 2 + + out->left = 0; + out->top = ((inH - scaledOutH) / 2) & ~0x1; + out->width = inW; + out->height = static_cast(scaledOutH); + ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d", + __FUNCTION__, inW, inH, outW, outH, out->top, static_cast(scaledOutH)); + } else { + uint64_t scaledOutW = static_cast(outW) * inH / outH; + if (scaledOutW > inW) { + ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d", + __FUNCTION__, outW, outH, inW, inH); + return -1; + } + scaledOutW = scaledOutW & ~0x1; // make it multiple of 2 + + out->left = ((inW - scaledOutW) / 2) & ~0x1; + out->top = 0; + out->width = static_cast(scaledOutW); + out->height = inH; + ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d", + __FUNCTION__, inW, inH, outW, outH, out->top, static_cast(scaledOutW)); + } + + return 0; +} + int ExternalCameraDeviceSession::OutputThread::cropAndScaleLocked( sp& in, const Size& outSz, YCbCrLayout* out) { Size inSz = {in->mWidth, in->mHeight}; @@ -1168,6 +1274,265 @@ int ExternalCameraDeviceSession::OutputThread::cropAndScaleThumbLocked( return 0; } +int ExternalCameraDeviceSession::OutputThread::formatConvertLocked( + const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) { + int ret = 0; + switch (format) { + case V4L2_PIX_FMT_NV21: + ret = libyuv::I420ToNV21( + static_cast(in.y), + in.yStride, + static_cast(in.cb), + in.cStride, + static_cast(in.cr), + in.cStride, + static_cast(out.y), + out.yStride, + static_cast(out.cr), + out.cStride, + sz.width, + sz.height); + if (ret != 0) { + ALOGE("%s: convert to NV21 buffer failed! ret %d", + __FUNCTION__, ret); + return ret; + } + break; + case V4L2_PIX_FMT_NV12: + ret = libyuv::I420ToNV12( + static_cast(in.y), + in.yStride, + static_cast(in.cb), + in.cStride, + static_cast(in.cr), + in.cStride, + static_cast(out.y), + out.yStride, + static_cast(out.cb), + out.cStride, + sz.width, + sz.height); + if (ret != 0) { + ALOGE("%s: convert to NV12 buffer failed! ret %d", + __FUNCTION__, ret); + return ret; + } + break; + case V4L2_PIX_FMT_YVU420: // YV12 + case V4L2_PIX_FMT_YUV420: // YU12 + // TODO: maybe we can speed up here by somehow save this copy? + ret = libyuv::I420Copy( + static_cast(in.y), + in.yStride, + static_cast(in.cb), + in.cStride, + static_cast(in.cr), + in.cStride, + static_cast(out.y), + out.yStride, + static_cast(out.cb), + out.cStride, + static_cast(out.cr), + out.cStride, + sz.width, + sz.height); + if (ret != 0) { + ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d", + __FUNCTION__, ret); + return ret; + } + break; + case FLEX_YUV_GENERIC: + // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow. + ALOGE("%s: unsupported flexible yuv layout" + " y %p cb %p cr %p y_str %d c_str %d c_step %d", + __FUNCTION__, out.y, out.cb, out.cr, + out.yStride, out.cStride, out.chromaStep); + return -1; + default: + ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format); + return -1; + } + return 0; +} + +int ExternalCameraDeviceSession::OutputThread::encodeJpegYU12( + const Size & inSz, const YCbCrLayout& inLayout, + int jpegQuality, const void *app1Buffer, size_t app1Size, + void *out, const size_t maxOutSize, size_t &actualCodeSize) +{ + /* libjpeg is a C library so we use C-style "inheritance" by + * putting libjpeg's jpeg_destination_mgr first in our custom + * struct. This allows us to cast jpeg_destination_mgr* to + * CustomJpegDestMgr* when we get it passed to us in a callback */ + struct CustomJpegDestMgr { + struct jpeg_destination_mgr mgr; + JOCTET *mBuffer; + size_t mBufferSize; + size_t mEncodedSize; + bool mSuccess; + } dmgr; + + jpeg_compress_struct cinfo = {}; + jpeg_error_mgr jerr; + + /* Initialize error handling with standard callbacks, but + * then override output_message (to print to ALOG) and + * error_exit to set a flag and print a message instead + * of killing the whole process */ + cinfo.err = jpeg_std_error(&jerr); + + cinfo.err->output_message = [](j_common_ptr cinfo) { + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message)(cinfo, buffer); + ALOGE("libjpeg error: %s", buffer); + }; + cinfo.err->error_exit = [](j_common_ptr cinfo) { + (*cinfo->err->output_message)(cinfo); + if(cinfo->client_data) { + auto & dmgr = + *reinterpret_cast(cinfo->client_data); + dmgr.mSuccess = false; + } + }; + /* Now that we initialized some callbacks, let's create our compressor */ + jpeg_create_compress(&cinfo); + + /* Initialize our destination manager */ + dmgr.mBuffer = static_cast(out); + dmgr.mBufferSize = maxOutSize; + dmgr.mEncodedSize = 0; + dmgr.mSuccess = true; + cinfo.client_data = static_cast(&dmgr); + + /* These lambdas become C-style function pointers and as per C++11 spec + * may not capture anything */ + dmgr.mgr.init_destination = [](j_compress_ptr cinfo) { + auto & dmgr = reinterpret_cast(*cinfo->dest); + dmgr.mgr.next_output_byte = dmgr.mBuffer; + dmgr.mgr.free_in_buffer = dmgr.mBufferSize; + ALOGV("%s:%d jpeg start: %p [%zu]", + __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize); + }; + + dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) { + ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__); + return 0; + }; + + dmgr.mgr.term_destination = [](j_compress_ptr cinfo) { + auto & dmgr = reinterpret_cast(*cinfo->dest); + dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer; + ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize); + }; + cinfo.dest = reinterpret_cast(&dmgr); + + /* We are going to be using JPEG in raw data mode, so we are passing + * straight subsampled planar YCbCr and it will not touch our pixel + * data or do any scaling or anything */ + cinfo.image_width = inSz.width; + cinfo.image_height = inSz.height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_YCbCr; + + /* Initialize defaults and then override what we want */ + jpeg_set_defaults(&cinfo); + + jpeg_set_quality(&cinfo, jpegQuality, 1); + jpeg_set_colorspace(&cinfo, JCS_YCbCr); + cinfo.raw_data_in = 1; + cinfo.dct_method = JDCT_IFAST; + + /* Configure sampling factors. The sampling factor is JPEG subsampling 420 + * because the source format is YUV420. Note that libjpeg sampling factors + * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and + * 1 V value for each 2 Y values */ + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 2; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + + /* Let's not hardcode YUV420 in 6 places... 5 was enough */ + int maxVSampFactor = std::max( { + cinfo.comp_info[0].v_samp_factor, + cinfo.comp_info[1].v_samp_factor, + cinfo.comp_info[2].v_samp_factor + }); + int cVSubSampling = cinfo.comp_info[0].v_samp_factor / + cinfo.comp_info[1].v_samp_factor; + + /* Start the compressor */ + jpeg_start_compress(&cinfo, TRUE); + + /* Compute our macroblock height, so we can pad our input to be vertically + * macroblock aligned. + * TODO: Does it need to be horizontally MCU aligned too? */ + + size_t mcuV = DCTSIZE*maxVSampFactor; + size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV); + + /* libjpeg uses arrays of row pointers, which makes it really easy to pad + * data vertically (unfortunately doesn't help horizontally) */ + std::vector yLines (paddedHeight); + std::vector cbLines(paddedHeight/cVSubSampling); + std::vector crLines(paddedHeight/cVSubSampling); + + uint8_t *py = static_cast(inLayout.y); + uint8_t *pcr = static_cast(inLayout.cr); + uint8_t *pcb = static_cast(inLayout.cb); + + for(uint32_t i = 0; i < paddedHeight; i++) + { + /* Once we are in the padding territory we still point to the last line + * effectively replicating it several times ~ CLAMP_TO_EDGE */ + int li = std::min(i, inSz.height - 1); + yLines[i] = static_cast(py + li * inLayout.yStride); + if(i < paddedHeight / cVSubSampling) + { + crLines[i] = static_cast(pcr + li * inLayout.cStride); + cbLines[i] = static_cast(pcb + li * inLayout.cStride); + } + } + + /* If APP1 data was passed in, use it */ + if(app1Buffer && app1Size) + { + jpeg_write_marker(&cinfo, JPEG_APP0 + 1, + static_cast(app1Buffer), app1Size); + } + + /* While we still have padded height left to go, keep giving it one + * macroblock at a time. */ + while (cinfo.next_scanline < cinfo.image_height) { + const uint32_t batchSize = DCTSIZE * maxVSampFactor; + const uint32_t nl = cinfo.next_scanline; + JSAMPARRAY planes[3]{ &yLines[nl], + &cbLines[nl/cVSubSampling], + &crLines[nl/cVSubSampling] }; + + uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize); + + if (done != batchSize) { + ALOGE("%s: compressed %u lines, expected %u (total %u/%u)", + __FUNCTION__, done, batchSize, cinfo.next_scanline, + cinfo.image_height); + return -1; + } + } + + /* This will flush everything */ + jpeg_finish_compress(&cinfo); + + /* Grab the actual code size and set it */ + actualCodeSize = dmgr.mEncodedSize; + + return 0; +} + /* * TODO: There needs to be a mechanism to discover allocated buffer size * in the HAL. @@ -1190,9 +1555,25 @@ Size ExternalCameraDeviceSession::getMaxJpegResolution() const { } Size ExternalCameraDeviceSession::getMaxThumbResolution() const { - return getMaxThumbnailResolution(mCameraCharacteristics); + Size thumbSize { 0, 0 }; + camera_metadata_ro_entry entry = + mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES); + for(uint32_t i = 0; i < entry.count; i += 2) { + Size sz { static_cast(entry.data.i32[i]), + static_cast(entry.data.i32[i+1]) }; + if(sz.width * sz.height > thumbSize.width * thumbSize.height) { + thumbSize = sz; + } + } + + if (thumbSize.width * thumbSize.height == 0) { + ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__); + } + + return thumbSize; } + ssize_t ExternalCameraDeviceSession::getJpegBufferSize( uint32_t width, uint32_t height) const { // Constant from camera3.h @@ -1235,7 +1616,7 @@ ssize_t ExternalCameraDeviceSession::getJpegBufferSize( int ExternalCameraDeviceSession::OutputThread::createJpegLocked( HalStreamBuffer &halBuf, - const common::V1_0::helper::CameraMetadata& setting) + const std::shared_ptr& req) { ATRACE_CALL(); int ret; @@ -1264,17 +1645,17 @@ int ExternalCameraDeviceSession::OutputThread::createJpegLocked( Size thumbSize; bool outputThumbnail = true; - if (setting.exists(ANDROID_JPEG_QUALITY)) { - camera_metadata_ro_entry entry = - setting.find(ANDROID_JPEG_QUALITY); + if (req->setting.exists(ANDROID_JPEG_QUALITY)) { + camera_metadata_entry entry = + req->setting.find(ANDROID_JPEG_QUALITY); jpegQuality = entry.data.u8[0]; } else { return lfail("%s: ANDROID_JPEG_QUALITY not set",__FUNCTION__); } - if (setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) { - camera_metadata_ro_entry entry = - setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY); + if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) { + camera_metadata_entry entry = + req->setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY); thumbQuality = entry.data.u8[0]; } else { return lfail( @@ -1282,9 +1663,9 @@ int ExternalCameraDeviceSession::OutputThread::createJpegLocked( __FUNCTION__); } - if (setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) { - camera_metadata_ro_entry entry = - setting.find(ANDROID_JPEG_THUMBNAIL_SIZE); + if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) { + camera_metadata_entry entry = + req->setting.find(ANDROID_JPEG_THUMBNAIL_SIZE); thumbSize = Size { static_cast(entry.data.i32[0]), static_cast(entry.data.i32[1]) }; @@ -1351,8 +1732,8 @@ int ExternalCameraDeviceSession::OutputThread::createJpegLocked( /* Combine camera characteristics with request settings to form EXIF * metadata */ - common::V1_0::helper::CameraMetadata meta(mCameraCharacteristics); - meta.append(setting); + common::V1_0::helper::CameraMetadata meta(parent->mCameraCharacteristics); + meta.append(req->setting); /* Generate EXIF object */ std::unique_ptr utils(ExifUtils::create()); @@ -1457,7 +1838,7 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { // TODO: see if we can save some computation by converting to YV12 here uint8_t* inData; size_t inDataSize; - if (req->frameIn->getData(&inData, &inDataSize) != 0) { + if (req->frameIn->map(&inData, &inDataSize) != 0) { lk.unlock(); return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__); } @@ -1518,7 +1899,7 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { // Gralloc lockYCbCr the buffer switch (halBuf.format) { case PixelFormat::BLOB: { - int ret = createJpegLocked(halBuf, req->setting); + int ret = createJpegLocked(halBuf, req); if(ret != 0) { lk.unlock(); @@ -1568,8 +1949,8 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { } Size sz {halBuf.width, halBuf.height}; - ATRACE_BEGIN("formatConvert"); - ret = formatConvert(cropAndScaled, outLayout, sz, outputFourcc); + ATRACE_BEGIN("formatConvertLocked"); + ret = formatConvertLocked(cropAndScaled, outLayout, sz, outputFourcc); ATRACE_END(); if (ret != 0) { lk.unlock(); @@ -1674,14 +2055,6 @@ Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers( return Status::OK; } -void ExternalCameraDeviceSession::OutputThread::clearIntermediateBuffers() { - std::lock_guard lk(mBufferLock); - mYu12Frame.clear(); - mYu12ThumbFrame.clear(); - mIntermediateBuffers.clear(); - mBlobBufferSize = 0; -} - Status ExternalCameraDeviceSession::OutputThread::submitRequest( const std::shared_ptr& req) { std::unique_lock lk(mRequestListLock); @@ -1717,32 +2090,6 @@ void ExternalCameraDeviceSession::OutputThread::flush() { } } -std::list> -ExternalCameraDeviceSession::OutputThread::switchToOffline() { - ATRACE_CALL(); - std::list> emptyList; - auto parent = mParent.promote(); - if (parent == nullptr) { - ALOGE("%s: session has been disconnected!", __FUNCTION__); - return emptyList; - } - - std::unique_lock lk(mRequestListLock); - std::list> reqs = std::move(mRequestList); - mRequestList.clear(); - if (mProcessingRequest) { - std::chrono::seconds timeout = std::chrono::seconds(kFlushWaitTimeoutSec); - auto st = mRequestDoneCond.wait_for(lk, timeout); - if (st == std::cv_status::timeout) { - ALOGE("%s: wait for inflight request finish timeout!", __FUNCTION__); - } - } - lk.unlock(); - clearIntermediateBuffers(); - ALOGV("%s: returning %zu request for offline processing", __FUNCTION__, reqs.size()); - return reqs; -} - void ExternalCameraDeviceSession::OutputThread::waitForNextRequest( std::shared_ptr* out) { ATRACE_CALL(); @@ -2386,7 +2733,6 @@ Status ExternalCameraDeviceSession::configureStreams( return Status::INTERNAL_ERROR; } - mBlobBufferSize = blobBufferSize; status = mOutputThread->allocateIntermediateBuffers(v4lSize, mMaxThumbResolution, config.streams, blobBufferSize); if (status != Status::OK) { @@ -2570,6 +2916,16 @@ status_t ExternalCameraDeviceSession::initDefaultRequests() { status_t ExternalCameraDeviceSession::fillCaptureResult( common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) { + // android.control + // For USB camera, we don't know the AE state. Set the state to converged to + // indicate the frame should be good to use. Then apps don't have to wait the + // AE state. + const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED; + UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1); + + const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF; + UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1); + bool afTrigger = false; { std::lock_guard lk(mAfTriggerLock); @@ -2595,10 +2951,46 @@ status_t ExternalCameraDeviceSession::fillCaptureResult( } UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1); - camera_metadata_ro_entry activeArraySize = - mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE); + // Set AWB state to converged to indicate the frame should be good to use. + const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED; + UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1); - return fillCaptureResultCommon(md, timestamp, activeArraySize); + const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF; + UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1); + + camera_metadata_ro_entry active_array_size = + mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE); + + if (active_array_size.count == 0) { + ALOGE("%s: cannot find active array size!", __FUNCTION__); + return -EINVAL; + } + + const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE; + UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1); + + // This means pipeline latency of X frame intervals. The maximum number is 4. + const uint8_t requestPipelineMaxDepth = 4; + UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1); + + // android.scaler + const int32_t crop_region[] = { + active_array_size.data.i32[0], active_array_size.data.i32[1], + active_array_size.data.i32[2], active_array_size.data.i32[3], + }; + UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region)); + + // android.sensor + UPDATE(md, ANDROID_SENSOR_TIMESTAMP, ×tamp, 1); + + // android.statistics + const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF; + UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1); + + const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE; + UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1); + + return OK; } #undef ARRAY_SIZE diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp index 4a6381ea7b..e25deff797 100644 --- a/camera/device/3.4/default/ExternalCameraUtils.cpp +++ b/camera/device/3.4/default/ExternalCameraUtils.cpp @@ -18,23 +18,10 @@ #include #include -#include #include #include - -#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs -#include - -#include - #include "ExternalCameraUtils.h" -namespace { - -buffer_handle_t sEmptyBuffer = nullptr; - -} // Anonymous namespace - namespace android { namespace hardware { namespace camera { @@ -42,13 +29,10 @@ namespace device { namespace V3_4 { namespace implementation { -Frame::Frame(uint32_t width, uint32_t height, uint32_t fourcc) : - mWidth(width), mHeight(height), mFourcc(fourcc) {} - V4L2Frame::V4L2Frame( uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd, uint32_t dataSize, uint64_t offset) : - Frame(w, h, fourcc), + mWidth(w), mHeight(h), mFourcc(fourcc), mBufferIndex(bufIdx), mFd(fd), mDataSize(dataSize), mOffset(offset) {} int V4L2Frame::map(uint8_t** data, size_t* dataSize) { @@ -91,13 +75,9 @@ V4L2Frame::~V4L2Frame() { unmap(); } -int V4L2Frame::getData(uint8_t** outData, size_t* dataSize) { - return map(outData, dataSize); -} - AllocatedFrame::AllocatedFrame( uint32_t w, uint32_t h) : - Frame(w, h, V4L2_PIX_FMT_YUV420) {}; + mWidth(w), mHeight(h), mFourcc(V4L2_PIX_FMT_YUV420) {}; AllocatedFrame::~AllocatedFrame() {} @@ -126,17 +106,6 @@ int AllocatedFrame::allocate(YCbCrLayout* out) { return 0; } -int AllocatedFrame::getData(uint8_t** outData, size_t* dataSize) { - YCbCrLayout layout; - int ret = allocate(&layout); - if (ret != 0) { - return ret; - } - *outData = mData.data(); - *dataSize = mData.size(); - return 0; -} - int AllocatedFrame::getLayout(YCbCrLayout* out) { IMapper::Rect noCrop = {0, 0, static_cast(mWidth), @@ -181,520 +150,8 @@ double SupportedV4L2Format::FrameRate::getDouble() const { return durationDenominator / static_cast(durationNumerator); } -::android::hardware::camera::common::V1_0::Status importBufferImpl( - /*inout*/std::map& circulatingBuffers, - /*inout*/HandleImporter& handleImporter, - int32_t streamId, - uint64_t bufId, buffer_handle_t buf, - /*out*/buffer_handle_t** outBufPtr, - bool allowEmptyBuf) { - using ::android::hardware::camera::common::V1_0::Status; - if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) { - if (allowEmptyBuf) { - *outBufPtr = &sEmptyBuffer; - return Status::OK; - } else { - ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); - return Status::ILLEGAL_ARGUMENT; - } - } - - CirculatingBuffers& cbs = circulatingBuffers[streamId]; - if (cbs.count(bufId) == 0) { - if (buf == nullptr) { - ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); - return Status::ILLEGAL_ARGUMENT; - } - // Register a newly seen buffer - buffer_handle_t importedBuf = buf; - handleImporter.importBuffer(importedBuf); - if (importedBuf == nullptr) { - ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId); - return Status::INTERNAL_ERROR; - } else { - cbs[bufId] = importedBuf; - } - } - *outBufPtr = &cbs[bufId]; - return Status::OK; -} - -uint32_t getFourCcFromLayout(const YCbCrLayout& layout) { - intptr_t cb = reinterpret_cast(layout.cb); - intptr_t cr = reinterpret_cast(layout.cr); - if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) { - // Interleaved format - if (layout.cb > layout.cr) { - return V4L2_PIX_FMT_NV21; - } else { - return V4L2_PIX_FMT_NV12; - } - } else if (layout.chromaStep == 1) { - // Planar format - if (layout.cb > layout.cr) { - return V4L2_PIX_FMT_YVU420; // YV12 - } else { - return V4L2_PIX_FMT_YUV420; // YU12 - } - } else { - return FLEX_YUV_GENERIC; - } -} - -int getCropRect( - CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) { - if (out == nullptr) { - ALOGE("%s: out is null", __FUNCTION__); - return -1; - } - - uint32_t inW = inSize.width; - uint32_t inH = inSize.height; - uint32_t outW = outSize.width; - uint32_t outH = outSize.height; - - // Handle special case where aspect ratio is close to input but scaled - // dimension is slightly larger than input - float arIn = ASPECT_RATIO(inSize); - float arOut = ASPECT_RATIO(outSize); - if (isAspectRatioClose(arIn, arOut)) { - out->left = 0; - out->top = 0; - out->width = inW; - out->height = inH; - return 0; - } - - if (ct == VERTICAL) { - uint64_t scaledOutH = static_cast(outH) * inW / outW; - if (scaledOutH > inH) { - ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d", - __FUNCTION__, outW, outH, inW, inH); - return -1; - } - scaledOutH = scaledOutH & ~0x1; // make it multiple of 2 - - out->left = 0; - out->top = ((inH - scaledOutH) / 2) & ~0x1; - out->width = inW; - out->height = static_cast(scaledOutH); - ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d", - __FUNCTION__, inW, inH, outW, outH, out->top, static_cast(scaledOutH)); - } else { - uint64_t scaledOutW = static_cast(outW) * inH / outH; - if (scaledOutW > inW) { - ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d", - __FUNCTION__, outW, outH, inW, inH); - return -1; - } - scaledOutW = scaledOutW & ~0x1; // make it multiple of 2 - - out->left = ((inW - scaledOutW) / 2) & ~0x1; - out->top = 0; - out->width = static_cast(scaledOutW); - out->height = inH; - ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d", - __FUNCTION__, inW, inH, outW, outH, out->top, static_cast(scaledOutW)); - } - - return 0; -} - -int formatConvert( - const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) { - int ret = 0; - switch (format) { - case V4L2_PIX_FMT_NV21: - ret = libyuv::I420ToNV21( - static_cast(in.y), - in.yStride, - static_cast(in.cb), - in.cStride, - static_cast(in.cr), - in.cStride, - static_cast(out.y), - out.yStride, - static_cast(out.cr), - out.cStride, - sz.width, - sz.height); - if (ret != 0) { - ALOGE("%s: convert to NV21 buffer failed! ret %d", - __FUNCTION__, ret); - return ret; - } - break; - case V4L2_PIX_FMT_NV12: - ret = libyuv::I420ToNV12( - static_cast(in.y), - in.yStride, - static_cast(in.cb), - in.cStride, - static_cast(in.cr), - in.cStride, - static_cast(out.y), - out.yStride, - static_cast(out.cb), - out.cStride, - sz.width, - sz.height); - if (ret != 0) { - ALOGE("%s: convert to NV12 buffer failed! ret %d", - __FUNCTION__, ret); - return ret; - } - break; - case V4L2_PIX_FMT_YVU420: // YV12 - case V4L2_PIX_FMT_YUV420: // YU12 - // TODO: maybe we can speed up here by somehow save this copy? - ret = libyuv::I420Copy( - static_cast(in.y), - in.yStride, - static_cast(in.cb), - in.cStride, - static_cast(in.cr), - in.cStride, - static_cast(out.y), - out.yStride, - static_cast(out.cb), - out.cStride, - static_cast(out.cr), - out.cStride, - sz.width, - sz.height); - if (ret != 0) { - ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d", - __FUNCTION__, ret); - return ret; - } - break; - case FLEX_YUV_GENERIC: - // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow. - ALOGE("%s: unsupported flexible yuv layout" - " y %p cb %p cr %p y_str %d c_str %d c_step %d", - __FUNCTION__, out.y, out.cb, out.cr, - out.yStride, out.cStride, out.chromaStep); - return -1; - default: - ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format); - return -1; - } - return 0; -} - -int encodeJpegYU12( - const Size & inSz, const YCbCrLayout& inLayout, - int jpegQuality, const void *app1Buffer, size_t app1Size, - void *out, const size_t maxOutSize, size_t &actualCodeSize) -{ - /* libjpeg is a C library so we use C-style "inheritance" by - * putting libjpeg's jpeg_destination_mgr first in our custom - * struct. This allows us to cast jpeg_destination_mgr* to - * CustomJpegDestMgr* when we get it passed to us in a callback */ - struct CustomJpegDestMgr { - struct jpeg_destination_mgr mgr; - JOCTET *mBuffer; - size_t mBufferSize; - size_t mEncodedSize; - bool mSuccess; - } dmgr; - - jpeg_compress_struct cinfo = {}; - jpeg_error_mgr jerr; - - /* Initialize error handling with standard callbacks, but - * then override output_message (to print to ALOG) and - * error_exit to set a flag and print a message instead - * of killing the whole process */ - cinfo.err = jpeg_std_error(&jerr); - - cinfo.err->output_message = [](j_common_ptr cinfo) { - char buffer[JMSG_LENGTH_MAX]; - - /* Create the message */ - (*cinfo->err->format_message)(cinfo, buffer); - ALOGE("libjpeg error: %s", buffer); - }; - cinfo.err->error_exit = [](j_common_ptr cinfo) { - (*cinfo->err->output_message)(cinfo); - if(cinfo->client_data) { - auto & dmgr = - *reinterpret_cast(cinfo->client_data); - dmgr.mSuccess = false; - } - }; - /* Now that we initialized some callbacks, let's create our compressor */ - jpeg_create_compress(&cinfo); - - /* Initialize our destination manager */ - dmgr.mBuffer = static_cast(out); - dmgr.mBufferSize = maxOutSize; - dmgr.mEncodedSize = 0; - dmgr.mSuccess = true; - cinfo.client_data = static_cast(&dmgr); - - /* These lambdas become C-style function pointers and as per C++11 spec - * may not capture anything */ - dmgr.mgr.init_destination = [](j_compress_ptr cinfo) { - auto & dmgr = reinterpret_cast(*cinfo->dest); - dmgr.mgr.next_output_byte = dmgr.mBuffer; - dmgr.mgr.free_in_buffer = dmgr.mBufferSize; - ALOGV("%s:%d jpeg start: %p [%zu]", - __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize); - }; - - dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) { - ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__); - return 0; - }; - - dmgr.mgr.term_destination = [](j_compress_ptr cinfo) { - auto & dmgr = reinterpret_cast(*cinfo->dest); - dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer; - ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize); - }; - cinfo.dest = reinterpret_cast(&dmgr); - - /* We are going to be using JPEG in raw data mode, so we are passing - * straight subsampled planar YCbCr and it will not touch our pixel - * data or do any scaling or anything */ - cinfo.image_width = inSz.width; - cinfo.image_height = inSz.height; - cinfo.input_components = 3; - cinfo.in_color_space = JCS_YCbCr; - - /* Initialize defaults and then override what we want */ - jpeg_set_defaults(&cinfo); - - jpeg_set_quality(&cinfo, jpegQuality, 1); - jpeg_set_colorspace(&cinfo, JCS_YCbCr); - cinfo.raw_data_in = 1; - cinfo.dct_method = JDCT_IFAST; - - /* Configure sampling factors. The sampling factor is JPEG subsampling 420 - * because the source format is YUV420. Note that libjpeg sampling factors - * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and - * 1 V value for each 2 Y values */ - cinfo.comp_info[0].h_samp_factor = 2; - cinfo.comp_info[0].v_samp_factor = 2; - cinfo.comp_info[1].h_samp_factor = 1; - cinfo.comp_info[1].v_samp_factor = 1; - cinfo.comp_info[2].h_samp_factor = 1; - cinfo.comp_info[2].v_samp_factor = 1; - - /* Let's not hardcode YUV420 in 6 places... 5 was enough */ - int maxVSampFactor = std::max( { - cinfo.comp_info[0].v_samp_factor, - cinfo.comp_info[1].v_samp_factor, - cinfo.comp_info[2].v_samp_factor - }); - int cVSubSampling = cinfo.comp_info[0].v_samp_factor / - cinfo.comp_info[1].v_samp_factor; - - /* Start the compressor */ - jpeg_start_compress(&cinfo, TRUE); - - /* Compute our macroblock height, so we can pad our input to be vertically - * macroblock aligned. - * TODO: Does it need to be horizontally MCU aligned too? */ - - size_t mcuV = DCTSIZE*maxVSampFactor; - size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV); - - /* libjpeg uses arrays of row pointers, which makes it really easy to pad - * data vertically (unfortunately doesn't help horizontally) */ - std::vector yLines (paddedHeight); - std::vector cbLines(paddedHeight/cVSubSampling); - std::vector crLines(paddedHeight/cVSubSampling); - - uint8_t *py = static_cast(inLayout.y); - uint8_t *pcr = static_cast(inLayout.cr); - uint8_t *pcb = static_cast(inLayout.cb); - - for(uint32_t i = 0; i < paddedHeight; i++) - { - /* Once we are in the padding territory we still point to the last line - * effectively replicating it several times ~ CLAMP_TO_EDGE */ - int li = std::min(i, inSz.height - 1); - yLines[i] = static_cast(py + li * inLayout.yStride); - if(i < paddedHeight / cVSubSampling) - { - crLines[i] = static_cast(pcr + li * inLayout.cStride); - cbLines[i] = static_cast(pcb + li * inLayout.cStride); - } - } - - /* If APP1 data was passed in, use it */ - if(app1Buffer && app1Size) - { - jpeg_write_marker(&cinfo, JPEG_APP0 + 1, - static_cast(app1Buffer), app1Size); - } - - /* While we still have padded height left to go, keep giving it one - * macroblock at a time. */ - while (cinfo.next_scanline < cinfo.image_height) { - const uint32_t batchSize = DCTSIZE * maxVSampFactor; - const uint32_t nl = cinfo.next_scanline; - JSAMPARRAY planes[3]{ &yLines[nl], - &cbLines[nl/cVSubSampling], - &crLines[nl/cVSubSampling] }; - - uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize); - - if (done != batchSize) { - ALOGE("%s: compressed %u lines, expected %u (total %u/%u)", - __FUNCTION__, done, batchSize, cinfo.next_scanline, - cinfo.image_height); - return -1; - } - } - - /* This will flush everything */ - jpeg_finish_compress(&cinfo); - - /* Grab the actual code size and set it */ - actualCodeSize = dmgr.mEncodedSize; - - return 0; -} - -Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata& chars) { - Size thumbSize { 0, 0 }; - camera_metadata_ro_entry entry = - chars.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES); - for(uint32_t i = 0; i < entry.count; i += 2) { - Size sz { static_cast(entry.data.i32[i]), - static_cast(entry.data.i32[i+1]) }; - if(sz.width * sz.height > thumbSize.width * thumbSize.height) { - thumbSize = sz; - } - } - - if (thumbSize.width * thumbSize.height == 0) { - ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__); - } - - return thumbSize; -} - -void freeReleaseFences(hidl_vec& results) { - for (auto& result : results) { - if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) { - native_handle_t* handle = const_cast( - result.inputBuffer.releaseFence.getNativeHandle()); - native_handle_close(handle); - native_handle_delete(handle); - } - for (auto& buf : result.outputBuffers) { - if (buf.releaseFence.getNativeHandle() != nullptr) { - native_handle_t* handle = const_cast( - buf.releaseFence.getNativeHandle()); - native_handle_close(handle); - native_handle_delete(handle); - } - } - } - return; -} - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) -#define UPDATE(md, tag, data, size) \ -do { \ - if ((md).update((tag), (data), (size))) { \ - ALOGE("Update " #tag " failed!"); \ - return BAD_VALUE; \ - } \ -} while (0) - -status_t fillCaptureResultCommon( - common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp, - camera_metadata_ro_entry& activeArraySize) { - if (activeArraySize.count < 4) { - ALOGE("%s: cannot find active array size!", __FUNCTION__); - return -EINVAL; - } - // android.control - // For USB camera, we don't know the AE state. Set the state to converged to - // indicate the frame should be good to use. Then apps don't have to wait the - // AE state. - const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED; - UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1); - - const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF; - UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1); - - // Set AWB state to converged to indicate the frame should be good to use. - const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED; - UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1); - - const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF; - UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1); - - const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE; - UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1); - - // This means pipeline latency of X frame intervals. The maximum number is 4. - const uint8_t requestPipelineMaxDepth = 4; - UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1); - - // android.scaler - const int32_t crop_region[] = { - activeArraySize.data.i32[0], activeArraySize.data.i32[1], - activeArraySize.data.i32[2], activeArraySize.data.i32[3], - }; - UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region)); - - // android.sensor - UPDATE(md, ANDROID_SENSOR_TIMESTAMP, ×tamp, 1); - - // android.statistics - const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF; - UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1); - - const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE; - UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1); - - return OK; -} - -#undef ARRAY_SIZE -#undef UPDATE - } // namespace implementation } // namespace V3_4 - -namespace V3_6 { -namespace implementation { - -AllocatedV4L2Frame::AllocatedV4L2Frame(sp frameIn) : - Frame(frameIn->mWidth, frameIn->mHeight, frameIn->mFourcc) { - uint8_t* dataIn; - size_t dataSize; - if (frameIn->getData(&dataIn, &dataSize) != 0) { - ALOGE("%s: map input V4L2 frame failed!", __FUNCTION__); - return; - } - - mData.resize(dataSize); - std::memcpy(mData.data(), dataIn, dataSize); -} - -int AllocatedV4L2Frame::getData(uint8_t** outData, size_t* dataSize) { - if (outData == nullptr || dataSize == nullptr) { - ALOGE("%s: outData(%p)/dataSize(%p) must not be null", __FUNCTION__, outData, dataSize); - return -1; - } - - *outData = mData.data(); - *dataSize = mData.size(); - return 0; -} - -AllocatedV4L2Frame::~AllocatedV4L2Frame() {} - -} // namespace implementation -} // namespace V3_6 } // namespace device diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h index ecab9cfa03..71b7c17dd6 100644 --- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h +++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H -#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H +#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H #include #include @@ -84,8 +84,7 @@ using ::android::sp; using ::android::Mutex; using ::android::base::unique_fd; -struct ExternalCameraDeviceSession : public virtual RefBase, - public virtual OutputThreadInterface { +struct ExternalCameraDeviceSession : public virtual RefBase { ExternalCameraDeviceSession(const sp&, const ExternalCameraConfig& cfg, @@ -111,82 +110,6 @@ struct ExternalCameraDeviceSession : public virtual RefBase, static const int kMaxStallStream = 1; static const uint32_t kMaxBytesPerPixel = 2; - class OutputThread : public android::Thread { - public: - OutputThread(wp parent, CroppingType, - const common::V1_0::helper::CameraMetadata&); - virtual ~OutputThread(); - - Status allocateIntermediateBuffers( - const Size& v4lSize, const Size& thumbSize, - const hidl_vec& streams, - uint32_t blobBufferSize); - Status submitRequest(const std::shared_ptr&); - void flush(); - void dump(int fd); - virtual bool threadLoop() override; - - void setExifMakeModel(const std::string& make, const std::string& model); - - // The remaining request list is returned for offline processing - std::list> switchToOffline(); - - protected: - // Methods to request output buffer in parallel - // No-op for device@3.4. Implemented in device@3.5 - virtual int requestBufferStart(const std::vector&) { return 0; } - virtual int waitForBufferRequestDone( - /*out*/std::vector*) { return 0; } - - static const int kFlushWaitTimeoutSec = 3; // 3 sec - static const int kReqWaitTimeoutMs = 33; // 33ms - static const int kReqWaitTimesMax = 90; // 33ms * 90 ~= 3 sec - - void waitForNextRequest(std::shared_ptr* out); - void signalRequestDone(); - - int cropAndScaleLocked( - sp& in, const Size& outSize, - YCbCrLayout* out); - - int cropAndScaleThumbLocked( - sp& in, const Size& outSize, - YCbCrLayout* out); - - int createJpegLocked(HalStreamBuffer &halBuf, - const common::V1_0::helper::CameraMetadata& settings); - - void clearIntermediateBuffers(); - - const wp mParent; - const CroppingType mCroppingType; - const common::V1_0::helper::CameraMetadata mCameraCharacteristics; - - mutable std::mutex mRequestListLock; // Protect acccess to mRequestList, - // mProcessingRequest and mProcessingFrameNumer - std::condition_variable mRequestCond; // signaled when a new request is submitted - std::condition_variable mRequestDoneCond; // signaled when a request is done processing - std::list> mRequestList; - bool mProcessingRequest = false; - uint32_t mProcessingFrameNumer = 0; - - // V4L2 frameIn - // (MJPG decode)-> mYu12Frame - // (Scale)-> mScaledYu12Frames - // (Format convert) -> output gralloc frames - mutable std::mutex mBufferLock; // Protect access to intermediate buffers - sp mYu12Frame; - sp mYu12ThumbFrame; - std::unordered_map, SizeHasher> mIntermediateBuffers; - std::unordered_map, SizeHasher> mScaledYu12Frames; - YCbCrLayout mYu12FrameLayout; - YCbCrLayout mYu12ThumbFrameLayout; - uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size - - std::string mExifMake; - std::string mExifModel; - }; - protected: // Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow @@ -227,22 +150,27 @@ protected: ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb); protected: - // Methods from OutputThreadInterface - virtual Status importBuffer(int32_t streamId, - uint64_t bufId, buffer_handle_t buf, - /*out*/buffer_handle_t** outBufPtr, - bool allowEmptyBuf) override; + struct HalStreamBuffer { + int32_t streamId; + uint64_t bufferId; + uint32_t width; + uint32_t height; + PixelFormat format; + V3_2::BufferUsageFlags usage; + buffer_handle_t* bufPtr; + int acquireFence; + bool fenceTimeout; + }; - virtual Status processCaptureResult(std::shared_ptr&) override; + struct HalRequest { + uint32_t frameNumber; + common::V1_0::helper::CameraMetadata setting; + sp frameIn; + nsecs_t shutterTs; + std::vector buffers; + }; - virtual Status processCaptureRequestError(const std::shared_ptr&, - /*out*/std::vector* msgs = nullptr, - /*out*/std::vector* results = nullptr) override; - - virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override; - - virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override; - // End of OutputThreadInterface methods + static const uint64_t BUFFER_ID_NO_BUFFER = 0; Status constructDefaultRequestSettingsRaw(RequestTemplate type, V3_2::CameraMetadata *outMetadata); @@ -291,6 +219,11 @@ protected: // Optional argument for ICameraDeviceSession@3.5 impl bool allowEmptyBuf = false); + Status importBuffer(int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf); + Status importBufferLocked(int32_t streamId, uint64_t bufId, buffer_handle_t buf, /*out*/buffer_handle_t** outBufPtr, @@ -303,15 +236,106 @@ protected: Status processOneCaptureRequest(const CaptureRequest& request); + Status processCaptureResult(std::shared_ptr&); + Status processCaptureRequestError(const std::shared_ptr&); void notifyShutter(uint32_t frameNumber, nsecs_t shutterTs); + void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec); void invokeProcessCaptureResultCallback( hidl_vec &results, bool tryWriteFmq); + static void freeReleaseFences(hidl_vec&); Size getMaxJpegResolution() const; Size getMaxThumbResolution() const; + ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const; + int waitForV4L2BufferReturnLocked(std::unique_lock& lk); + class OutputThread : public android::Thread { + public: + OutputThread(wp parent, CroppingType); + virtual ~OutputThread(); + + Status allocateIntermediateBuffers( + const Size& v4lSize, const Size& thumbSize, + const hidl_vec& streams, + uint32_t blobBufferSize); + Status submitRequest(const std::shared_ptr&); + void flush(); + void dump(int fd); + virtual bool threadLoop() override; + + void setExifMakeModel(const std::string& make, const std::string& model); + + protected: + // Methods to request output buffer in parallel + // No-op for device@3.4. Implemented in device@3.5 + virtual int requestBufferStart(const std::vector&) { return 0; } + virtual int waitForBufferRequestDone( + /*out*/std::vector*) { return 0; } + + static const uint32_t FLEX_YUV_GENERIC = static_cast('F') | + static_cast('L') << 8 | static_cast('E') << 16 | + static_cast('X') << 24; + // returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21 + static uint32_t getFourCcFromLayout(const YCbCrLayout&); + static int getCropRect( + CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out); + + static const int kFlushWaitTimeoutSec = 3; // 3 sec + static const int kReqWaitTimeoutMs = 33; // 33ms + static const int kReqWaitTimesMax = 90; // 33ms * 90 ~= 3 sec + + void waitForNextRequest(std::shared_ptr* out); + void signalRequestDone(); + + int cropAndScaleLocked( + sp& in, const Size& outSize, + YCbCrLayout* out); + + int cropAndScaleThumbLocked( + sp& in, const Size& outSize, + YCbCrLayout* out); + + int formatConvertLocked(const YCbCrLayout& in, const YCbCrLayout& out, + Size sz, uint32_t format); + + static int encodeJpegYU12(const Size &inSz, + const YCbCrLayout& inLayout, int jpegQuality, + const void *app1Buffer, size_t app1Size, + void *out, size_t maxOutSize, + size_t &actualCodeSize); + + int createJpegLocked(HalStreamBuffer &halBuf, const std::shared_ptr& req); + + const wp mParent; + const CroppingType mCroppingType; + + mutable std::mutex mRequestListLock; // Protect acccess to mRequestList, + // mProcessingRequest and mProcessingFrameNumer + std::condition_variable mRequestCond; // signaled when a new request is submitted + std::condition_variable mRequestDoneCond; // signaled when a request is done processing + std::list> mRequestList; + bool mProcessingRequest = false; + uint32_t mProcessingFrameNumer = 0; + + // V4L2 frameIn + // (MJPG decode)-> mYu12Frame + // (Scale)-> mScaledYu12Frames + // (Format convert) -> output gralloc frames + mutable std::mutex mBufferLock; // Protect access to intermediate buffers + sp mYu12Frame; + sp mYu12ThumbFrame; + std::unordered_map, SizeHasher> mIntermediateBuffers; + std::unordered_map, SizeHasher> mScaledYu12Frames; + YCbCrLayout mYu12FrameLayout; + YCbCrLayout mYu12ThumbFrameLayout; + uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size + + std::string mExifMake; + std::string mExifModel; + }; + // Protect (most of) HIDL interface methods from synchronized-entering mutable Mutex mInterfaceLock; @@ -357,6 +381,12 @@ protected: std::mutex mInflightFramesLock; // protect mInflightFrames std::unordered_set mInflightFrames; + // buffers currently circulating between HAL and camera service + // key: bufferId sent via HIDL interface + // value: imported buffer_handle_t + // Buffer will be imported during processCaptureRequest and will be freed + // when the its stream is deleted or camera device session is closed + typedef std::unordered_map CirculatingBuffers; // Stream ID -> circulating buffers map std::map mCirculatingBuffers; // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock @@ -365,8 +395,6 @@ protected: std::mutex mAfTriggerLock; // protect mAfTrigger bool mAfTrigger = false; - uint32_t mBlobBufferSize = 0; - static HandleImporter sHandleImporter; /* Beginning of members not changed after initialize() */ @@ -382,9 +410,6 @@ protected: const Size mMaxThumbResolution; const Size mMaxJpegResolution; - - std::string mExifMake; - std::string mExifModel; /* End of members not changed after initialize() */ private: @@ -459,4 +484,4 @@ private: } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h index 74f75eb246..341c62218d 100644 --- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h +++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h @@ -17,27 +17,16 @@ #ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H #define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H -#include -#include -#include #include #include #include -#include #include #include #include "tinyxml2.h" // XML parsing #include "utils/LightRefBase.h" -#include "utils/Timers.h" -#include -#include - -using ::android::hardware::graphics::mapper::V2_0::IMapper; -using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout; -using ::android::hardware::camera::common::V1_0::helper::HandleImporter; -using ::android::hardware::camera::common::V1_0::Status; -using ::android::hardware::camera::device::V3_2::ErrorCode; +using android::hardware::graphics::mapper::V2_0::IMapper; +using android::hardware::graphics::mapper::V2_0::YCbCrLayout; namespace android { namespace hardware { @@ -124,28 +113,16 @@ struct SupportedV4L2Format { std::vector frameRates; }; -// A Base class with basic information about a frame -struct Frame : public VirtualLightRefBase { -public: - Frame(uint32_t width, uint32_t height, uint32_t fourcc); - const uint32_t mWidth; - const uint32_t mHeight; - const uint32_t mFourcc; - - // getData might involve map/allocation - virtual int getData(uint8_t** outData, size_t* dataSize) = 0; -}; - // A class provide access to a dequeued V4L2 frame buffer (mostly in MJPG format) // Also contains necessary information to enqueue the buffer back to V4L2 buffer queue -class V4L2Frame : public Frame { +class V4L2Frame : public virtual VirtualLightRefBase { public: V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd, uint32_t dataSize, uint64_t offset); ~V4L2Frame() override; - - virtual int getData(uint8_t** outData, size_t* dataSize) override; - + const uint32_t mWidth; + const uint32_t mHeight; + const uint32_t mFourcc; const int mBufferIndex; // for later enqueue int map(uint8_t** data, size_t* dataSize); int unmap(); @@ -160,13 +137,13 @@ private: // A RAII class representing a CPU allocated YUV frame used as intermeidate buffers // when generating output images. -class AllocatedFrame : public Frame { +class AllocatedFrame : public virtual VirtualLightRefBase { public: - AllocatedFrame(uint32_t w, uint32_t h); // only support V4L2_PIX_FMT_YUV420 for now + AllocatedFrame(uint32_t w, uint32_t h); // TODO: use Size? ~AllocatedFrame() override; - - virtual int getData(uint8_t** outData, size_t* dataSize) override; - + const uint32_t mWidth; + const uint32_t mHeight; + const uint32_t mFourcc; // Only support YU12 format for now int allocate(YCbCrLayout* out = nullptr); int getLayout(YCbCrLayout* out); int getCroppedLayout(const IMapper::Rect&, YCbCrLayout* out); // return non-zero for bad input @@ -188,110 +165,8 @@ const float kMinAspectRatio = 1.f; bool isAspectRatioClose(float ar1, float ar2); -struct HalStreamBuffer { - int32_t streamId; - uint64_t bufferId; - uint32_t width; - uint32_t height; - ::android::hardware::graphics::common::V1_0::PixelFormat format; - ::android::hardware::camera::device::V3_2::BufferUsageFlags usage; - buffer_handle_t* bufPtr; - int acquireFence; - bool fenceTimeout; -}; - -struct HalRequest { - uint32_t frameNumber; - common::V1_0::helper::CameraMetadata setting; - sp frameIn; - nsecs_t shutterTs; - std::vector buffers; -}; - -static const uint64_t BUFFER_ID_NO_BUFFER = 0; - -// buffers currently circulating between HAL and camera service -// key: bufferId sent via HIDL interface -// value: imported buffer_handle_t -// Buffer will be imported during processCaptureRequest (or requestStreamBuffer -// in the case of HAL buffer manager is enabled) and will be freed -// when the stream is deleted or camera device session is closed -typedef std::unordered_map CirculatingBuffers; - -::android::hardware::camera::common::V1_0::Status importBufferImpl( - /*inout*/std::map& circulatingBuffers, - /*inout*/HandleImporter& handleImporter, - int32_t streamId, - uint64_t bufId, buffer_handle_t buf, - /*out*/buffer_handle_t** outBufPtr, - bool allowEmptyBuf); - -static const uint32_t FLEX_YUV_GENERIC = static_cast('F') | - static_cast('L') << 8 | static_cast('E') << 16 | - static_cast('X') << 24; - -// returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21 -uint32_t getFourCcFromLayout(const YCbCrLayout&); - -using ::android::hardware::camera::external::common::Size; -int getCropRect(CroppingType ct, const Size& inSize, - const Size& outSize, IMapper::Rect* out); - -int formatConvert(const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format); - -int encodeJpegYU12(const Size &inSz, - const YCbCrLayout& inLayout, int jpegQuality, - const void *app1Buffer, size_t app1Size, - void *out, size_t maxOutSize, - size_t &actualCodeSize); - -Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata&); - -void freeReleaseFences(hidl_vec&); - -status_t fillCaptureResultCommon(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp, - camera_metadata_ro_entry& activeArraySize); - -// Interface for OutputThread calling back to parent -struct OutputThreadInterface : public virtual RefBase { - virtual ::android::hardware::camera::common::V1_0::Status importBuffer( - int32_t streamId, uint64_t bufId, buffer_handle_t buf, - /*out*/buffer_handle_t** outBufPtr, bool allowEmptyBuf) = 0; - - virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) = 0; - - // Callbacks are fired within the method if msgs/results are nullptr. - // Otherwise the callbacks will be returned and caller is responsible to - // fire the callback later - virtual ::android::hardware::camera::common::V1_0::Status processCaptureRequestError( - const std::shared_ptr&, - /*out*/std::vector* msgs = nullptr, - /*out*/std::vector* results = nullptr) = 0; - - virtual ::android::hardware::camera::common::V1_0::Status processCaptureResult( - std::shared_ptr&) = 0; - - virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const = 0; -}; - } // namespace implementation } // namespace V3_4 - -namespace V3_6 { -namespace implementation { - -// A CPU copy of a mapped V4L2Frame. Will map the input V4L2 frame. -class AllocatedV4L2Frame : public V3_4::implementation::Frame { -public: - AllocatedV4L2Frame(sp frameIn); - ~AllocatedV4L2Frame() override; - virtual int getData(uint8_t** outData, size_t* dataSize) override; -private: - std::vector mData; -}; - -} // namespace implementation -} // namespace V3_6 } // namespace device } // namespace camera } // namespace hardware diff --git a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp index 287ac324ec..00c1d0de39 100644 --- a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp +++ b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp @@ -80,7 +80,7 @@ Status ExternalCameraDeviceSession::importRequestLocked( ExternalCameraDeviceSession::BufferRequestThread::BufferRequestThread( - wp parent, + wp parent, sp callbacks) : mParent(parent), mCallbacks(callbacks) {} @@ -254,8 +254,7 @@ void ExternalCameraDeviceSession::initOutputThread() { mBufferRequestThread = new BufferRequestThread(this, mCallback_3_5); mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY); } - mOutputThread = new OutputThread( - this, mCroppingType, mCameraCharacteristics, mBufferRequestThread); + mOutputThread = new OutputThread(this, mCroppingType, mBufferRequestThread); } void ExternalCameraDeviceSession::closeOutputThreadImpl() { @@ -272,11 +271,10 @@ void ExternalCameraDeviceSession::closeOutputThread() { } ExternalCameraDeviceSession::OutputThread::OutputThread( - wp parent, + wp parent, CroppingType ct, - const common::V1_0::helper::CameraMetadata& chars, sp bufReqThread) : - V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct, chars), + V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct), mBufferRequestThread(bufReqThread) {} ExternalCameraDeviceSession::OutputThread::~OutputThread() {} diff --git a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h index e89ef45f52..281f93a13b 100644 --- a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h +++ b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H -#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H +#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H #include #include @@ -72,7 +72,6 @@ using ::android::base::unique_fd; using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format; using ::android::hardware::camera::device::V3_4::implementation::CroppingType; -using ::android::hardware::camera::device::V3_4::implementation::HalStreamBuffer; struct ExternalCameraDeviceSession : public V3_4::implementation::ExternalCameraDeviceSession { @@ -98,62 +97,6 @@ struct ExternalCameraDeviceSession : public V3_4::implementation::ExternalCamera config, supportedFormats, devCfg); } - class BufferRequestThread : public android::Thread { - public: - BufferRequestThread( - wp parent, - sp callbacks); - - int requestBufferStart(const std::vector&); - int waitForBufferRequestDone( - /*out*/std::vector*); - - virtual bool threadLoop() override; - - private: - void waitForNextRequest(); - - const wp mParent; - const sp mCallbacks; - - std::mutex mLock; - bool mRequestingBuffer = false; - - std::vector mBufferReqs; - std::vector mPendingReturnBufferReqs; - // mHalBufferReqs is not under mLock protection during the HIDL transaction - hidl_vec mHalBufferReqs; - - // request buffers takes much less time in steady state, but can take much longer - // when requesting 1st buffer from a stream. - // TODO: consider a separate timeout for new vs. steady state? - // TODO: or make sure framework is warming up the pipeline during configure new stream? - static const int kReqProcTimeoutMs = 66; - - static const int kReqWaitTimeoutMs = 33; - static const int kReqWaitTimesWarn = 90; // 33ms * 90 ~= 3 sec - std::condition_variable mRequestCond; // signaled when a new buffer request incoming - std::condition_variable mRequestDoneCond; // signaled when a request is done - }; - - class OutputThread : - public V3_4::implementation::ExternalCameraDeviceSession::OutputThread { - public: - // TODO: pass buffer request thread to OutputThread ctor - OutputThread(wp parent, CroppingType, - const common::V1_0::helper::CameraMetadata&, - sp bufReqThread); - virtual ~OutputThread(); - - protected: - // Methods to request output buffer in parallel - virtual int requestBufferStart(const std::vector&) override; - virtual int waitForBufferRequestDone( - /*out*/std::vector*) override; - - const sp mBufferRequestThread; - }; - protected: // Methods from v3.4 and earlier will trampoline to inherited implementation Return configureStreams_3_5( @@ -177,8 +120,63 @@ protected: hidl_vec& allBufPtrs, hidl_vec& allFences) override; + class BufferRequestThread : public android::Thread { + public: + BufferRequestThread( + wp parent, + sp callbacks); + + int requestBufferStart(const std::vector&); + int waitForBufferRequestDone( + /*out*/std::vector*); + + virtual bool threadLoop() override; + + private: + void waitForNextRequest(); + + const wp mParent; + const sp mCallbacks; + + std::mutex mLock; + bool mRequestingBuffer = false; + + std::vector mBufferReqs; + std::vector mPendingReturnBufferReqs; + // mHalBufferReqs is not under mLock protection during the HIDL transaction + hidl_vec mHalBufferReqs; + + // request buffers takes much less time in steady state, but can take much longer + // when requesting 1st buffer from a stream. + // TODO: consider a separate timeout for new vs. steady state? + // TODO: or make sure framework is warming up the pipeline during configure new stream? + static const int kReqProcTimeoutMs = 66; + + static const int kReqWaitTimeoutMs = 33; + static const int kReqWaitTimesWarn = 90; // 33ms * 90 ~= 3 sec + std::condition_variable mRequestCond; // signaled when a new buffer request incoming + std::condition_variable mRequestDoneCond; // signaled when a request is done + }; + sp mBufferRequestThread; + class OutputThread : + public V3_4::implementation::ExternalCameraDeviceSession::OutputThread { + public: + // TODO: pass buffer request thread to OutputThread ctor + OutputThread(wp parent, CroppingType, + sp bufReqThread); + virtual ~OutputThread(); + + protected: + // Methods to request output buffer in parallel + virtual int requestBufferStart(const std::vector&) override; + virtual int waitForBufferRequestDone( + /*out*/std::vector*) override; + + const sp mBufferRequestThread; + }; + sp mCallback_3_5; bool mSupportBufMgr; @@ -272,4 +270,4 @@ private: } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H diff --git a/camera/device/3.6/default/Android.bp b/camera/device/3.6/default/Android.bp index a2ddebdd24..ce51185193 100644 --- a/camera/device/3.6/default/Android.bp +++ b/camera/device/3.6/default/Android.bp @@ -28,7 +28,6 @@ cc_library_shared { srcs: [ "ExternalCameraDevice.cpp", "ExternalCameraDeviceSession.cpp", - "ExternalCameraOfflineSession.cpp", ], shared_libs: [ "libhidlbase", diff --git a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp index 0cc81bbe9e..e14ae992b8 100644 --- a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp +++ b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp @@ -73,8 +73,12 @@ Return ExternalCameraDeviceSession::configureStreams_3_6( Status status = configureStreams(config_v32, &outStreams_v33, blobBufferSize); - fillOutputStream3_6(outStreams_v33, &outStreams); - + outStreams.streams.resize(outStreams_v33.streams.size()); + for (size_t i = 0; i < outStreams.streams.size(); i++) { + outStreams.streams[i].v3_4.v3_3 = outStreams_v33.streams[i]; + // TODO: implement it later + outStreams.streams[i].supportOffline = false; + } _hidl_cb(status, outStreams); return Void(); } @@ -82,273 +86,12 @@ Return ExternalCameraDeviceSession::configureStreams_3_6( Return ExternalCameraDeviceSession::switchToOffline( const hidl_vec& streamsToKeep, ICameraDeviceSession::switchToOffline_cb _hidl_cb) { - std::vector msgs; - std::vector results; - CameraOfflineSessionInfo info; - sp session; - - Status st = switchToOffline(streamsToKeep, &msgs, &results, &info, &session); - - mCallback->notify(msgs); - hidl_vec hidlResults(std::move(results)); - invokeProcessCaptureResultCallback(hidlResults, /* tryWriteFmq */true); - V3_4::implementation::freeReleaseFences(hidlResults); - - _hidl_cb(st, info, session); + // TODO: implement this + (void) streamsToKeep; + (void) _hidl_cb; return Void(); } -void ExternalCameraDeviceSession::fillOutputStream3_6( - const V3_3::HalStreamConfiguration& outStreams_v33, - /*out*/V3_6::HalStreamConfiguration* outStreams_v36) { - if (outStreams_v36 == nullptr) { - ALOGE("%s: outStreams_v36 must not be null!", __FUNCTION__); - return; - } - Mutex::Autolock _l(mLock); - outStreams_v36->streams.resize(outStreams_v33.streams.size()); - for (size_t i = 0; i < outStreams_v36->streams.size(); i++) { - outStreams_v36->streams[i].v3_4.v3_3 = outStreams_v33.streams[i]; - outStreams_v36->streams[i].supportOffline = - supportOfflineLocked(outStreams_v33.streams[i].v3_2.id); - } -} - -bool ExternalCameraDeviceSession::supportOfflineLocked(int32_t streamId) { - const Stream& stream = mStreamMap[streamId]; - if (stream.format == PixelFormat::BLOB && - stream.dataSpace == static_cast(Dataspace::V0_JFIF)) { - return true; - } - // TODO: support YUV output stream? - return false; -} - -bool ExternalCameraDeviceSession::canDropRequest(const hidl_vec& offlineStreams, - std::shared_ptr halReq) { - for (const auto& buffer : halReq->buffers) { - for (auto offlineStreamId : offlineStreams) { - if (buffer.streamId == offlineStreamId) { - return false; - } - } - } - // Only drop a request completely if it has no offline output - return true; -} - -void ExternalCameraDeviceSession::fillOfflineSessionInfo(const hidl_vec& offlineStreams, - std::deque>& offlineReqs, - const std::map& circulatingBuffers, - /*out*/CameraOfflineSessionInfo* info) { - if (info == nullptr) { - ALOGE("%s: output info must not be null!", __FUNCTION__); - return; - } - - info->offlineStreams.resize(offlineStreams.size()); - info->offlineRequests.resize(offlineReqs.size()); - - std::unordered_map outstandingBufs(offlineStreams.size()); - for (const auto streamId : offlineStreams) { - outstandingBufs.insert({streamId, 0}); - } - // Fill in offline reqs and count outstanding buffers - for (size_t i = 0; i < offlineReqs.size(); i++) { - info->offlineRequests[i].frameNumber = offlineReqs[i]->frameNumber; - info->offlineRequests[i].pendingStreams.resize(offlineReqs[i]->buffers.size()); - for (size_t bIdx = 0; bIdx < offlineReqs[i]->buffers.size(); bIdx++) { - int32_t streamId = offlineReqs[i]->buffers[bIdx].streamId; - info->offlineRequests[i].pendingStreams[bIdx] = streamId; - outstandingBufs[streamId]++; - } - } - - for (size_t i = 0; i < offlineStreams.size(); i++) { - int32_t streamId = offlineStreams[i]; - info->offlineStreams[i].id = streamId; - info->offlineStreams[i].numOutstandingBuffers = outstandingBufs[streamId]; - const CirculatingBuffers& bufIdMap = circulatingBuffers.at(streamId); - info->offlineStreams[i].circulatingBufferIds.resize(bufIdMap.size()); - size_t bIdx = 0; - for (const auto& pair : bufIdMap) { - // Fill in bufferId - info->offlineStreams[i].circulatingBufferIds[bIdx++] = pair.first; - } - - } -} - -Status ExternalCameraDeviceSession::switchToOffline(const hidl_vec& offlineStreams, - /*out*/std::vector* msgs, - /*out*/std::vector* results, - /*out*/CameraOfflineSessionInfo* info, - /*out*/sp* session) { - ATRACE_CALL(); - if (offlineStreams.size() > 1) { - ALOGE("%s: more than one offline stream is not supported", __FUNCTION__); - return Status::ILLEGAL_ARGUMENT; - } - - if (msgs == nullptr || results == nullptr || info == nullptr || session == nullptr) { - ALOGE("%s: output arguments (%p, %p, %p, %p) must not be null", __FUNCTION__, - msgs, results, info, session); - return Status::ILLEGAL_ARGUMENT; - } - - msgs->clear(); - results->clear(); - - Mutex::Autolock _il(mInterfaceLock); - Status status = initStatus(); - if (status != Status::OK) { - return status; - } - - Mutex::Autolock _l(mLock); - for (auto streamId : offlineStreams) { - if (!supportOfflineLocked(streamId)) { - return Status::ILLEGAL_ARGUMENT; - } - } - - // pause output thread and get all remaining inflight requests - auto remainingReqs = mOutputThread->switchToOffline(); - std::vector> halReqs; - - // Send out buffer/request error for remaining requests and filter requests - // to be handled in offline mode - for (auto& halReq : remainingReqs) { - bool dropReq = canDropRequest(offlineStreams, halReq); - if (dropReq) { - // Request is dropped completely. Just send request error and - // there is no need to send the request to offline session - processCaptureRequestError(halReq, msgs, results); - continue; - } - - // All requests reach here must have at least one offline stream output - NotifyMsg shutter; - shutter.type = MsgType::SHUTTER; - shutter.msg.shutter.frameNumber = halReq->frameNumber; - shutter.msg.shutter.timestamp = halReq->shutterTs; - msgs->push_back(shutter); - - std::vector offlineBuffers; - for (const auto& buffer : halReq->buffers) { - bool dropBuffer = true; - for (auto offlineStreamId : offlineStreams) { - if (buffer.streamId == offlineStreamId) { - dropBuffer = false; - break; - } - } - if (dropBuffer) { - NotifyMsg error; - error.type = MsgType::ERROR; - error.msg.error.frameNumber = halReq->frameNumber; - error.msg.error.errorStreamId = buffer.streamId; - error.msg.error.errorCode = ErrorCode::ERROR_BUFFER; - msgs->push_back(error); - - CaptureResult result; - result.frameNumber = halReq->frameNumber; - result.partialResult = 0; // buffer only result - result.inputBuffer.streamId = -1; - result.outputBuffers.resize(1); - result.outputBuffers[0].streamId = buffer.streamId; - result.outputBuffers[0].bufferId = buffer.bufferId; - result.outputBuffers[0].status = BufferStatus::ERROR; - if (buffer.acquireFence >= 0) { - native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0); - handle->data[0] = buffer.acquireFence; - result.outputBuffers[0].releaseFence.setTo(handle, /*shouldOwn*/false); - } - results->push_back(result); - } else { - offlineBuffers.push_back(buffer); - } - } - halReq->buffers = offlineBuffers; - halReqs.push_back(halReq); - } - - // convert hal requests to offline request - std::deque> offlineReqs(halReqs.size()); - for (auto& v4lReq : halReqs) { - std::shared_ptr halReq = std::make_shared(); - halReq->frameNumber = v4lReq->frameNumber; - halReq->setting = v4lReq->setting; - halReq->shutterTs = v4lReq->shutterTs; - halReq->buffers = v4lReq->buffers; - sp v4l2Frame = - static_cast(v4lReq->frameIn.get()); - halReq->frameIn = new AllocatedV4L2Frame(v4l2Frame); - offlineReqs.push_back(halReq); - // enqueue V4L2 frame - enqueueV4l2Frame(v4l2Frame); - } - - // Collect buffer caches/streams - hidl_vec streamInfos; - streamInfos.resize(offlineStreams.size()); - std::map circulatingBuffers; - { - Mutex::Autolock _l(mCbsLock); - size_t idx = 0; - for(auto streamId : offlineStreams) { - circulatingBuffers[streamId] = mCirculatingBuffers.at(streamId); - mCirculatingBuffers.erase(streamId); - streamInfos[idx++] = mStreamMap.at(streamId); - mStreamMap.erase(streamId); - } - } - - fillOfflineSessionInfo(offlineStreams, offlineReqs, circulatingBuffers, info); - - // create the offline session object - bool afTrigger; - { - std::lock_guard lk(mAfTriggerLock); - afTrigger = mAfTrigger; - } - sp sessionImpl = new ExternalCameraOfflineSession( - mCroppingType, mCameraCharacteristics, mCameraId, - mExifMake, mExifModel, mBlobBufferSize, afTrigger, - streamInfos, offlineReqs, circulatingBuffers); - - bool initFailed = sessionImpl->initialize(); - if (initFailed) { - ALOGE("%s: offline session initialize failed!", __FUNCTION__); - return Status::INTERNAL_ERROR; - } - - // cleanup stream and buffer caches - { - Mutex::Autolock _l(mCbsLock); - for(auto pair : mStreamMap) { - cleanupBuffersLocked(/*Stream ID*/pair.first); - } - mCirculatingBuffers.clear(); - } - mStreamMap.clear(); - - // update inflight records - { - std::lock_guard lk(mInflightFramesLock); - mInflightFrames.clear(); - } - - // stop v4l2 streaming - if (v4l2StreamOffLocked() !=0) { - ALOGE("%s: stop V4L2 streaming failed!", __FUNCTION__); - return Status::INTERNAL_ERROR; - } - - *session = sessionImpl->getInterface(); - return Status::OK; -} - } // namespace implementation } // namespace V3_6 } // namespace device diff --git a/camera/device/3.6/default/ExternalCameraOfflineSession.cpp b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp deleted file mode 100644 index e606fda832..0000000000 --- a/camera/device/3.6/default/ExternalCameraOfflineSession.cpp +++ /dev/null @@ -1,554 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "ExtCamOfflnSsn@3.6" -#define ATRACE_TAG ATRACE_TAG_CAMERA -#include - -#include -#include - -#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs -#include - -#include -#include "ExternalCameraOfflineSession.h" - -namespace { - -// Size of request/result metadata fast message queue. Change to 0 to always use hwbinder buffer. -static constexpr size_t kMetadataMsgQueueSize = 1 << 18 /* 256kB */; - -} // anonymous namespace - -namespace android { -namespace hardware { -namespace camera { -namespace device { -namespace V3_6 { -namespace implementation { - -// static instance -HandleImporter ExternalCameraOfflineSession::sHandleImporter; - -using V3_5::implementation::ExternalCameraDeviceSession; - -ExternalCameraOfflineSession::ExternalCameraOfflineSession( - const CroppingType& croppingType, - const common::V1_0::helper::CameraMetadata& chars, - const std::string& cameraId, - const std::string& exifMake, - const std::string& exifModel, - const uint32_t blobBufferSize, - const bool afTrigger, - const hidl_vec& offlineStreams, - std::deque>& offlineReqs, - const std::map& circulatingBuffers) : - mCroppingType(croppingType), mChars(chars), mCameraId(cameraId), - mExifMake(exifMake), mExifModel(exifModel), mBlobBufferSize(blobBufferSize), - mAfTrigger(afTrigger), mOfflineStreams(offlineStreams), mOfflineReqs(offlineReqs), - mCirculatingBuffers(circulatingBuffers) {} - -ExternalCameraOfflineSession::~ExternalCameraOfflineSession() { - close(); -} - -bool ExternalCameraOfflineSession::initialize() { - mResultMetadataQueue = std::make_shared( - kMetadataMsgQueueSize, false /* non blocking */); - if (!mResultMetadataQueue->isValid()) { - ALOGE("%s: invalid result fmq", __FUNCTION__); - return true; - } - return false; -} - -void ExternalCameraOfflineSession::initOutputThread() { - if (mOutputThread != nullptr) { - ALOGE("%s: OutputThread already exist!", __FUNCTION__); - return; - } - - mBufferRequestThread = new ExternalCameraDeviceSession::BufferRequestThread( - this, mCallback); - mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY); - - mOutputThread = new OutputThread(this, mCroppingType, mChars, - mBufferRequestThread, mOfflineReqs); - - mOutputThread->setExifMakeModel(mExifMake, mExifModel); - - Size inputSize = { mOfflineReqs[0]->frameIn->mWidth, mOfflineReqs[0]->frameIn->mHeight}; - Size maxThumbSize = V3_4::implementation::getMaxThumbnailResolution(mChars); - mOutputThread->allocateIntermediateBuffers( - inputSize, maxThumbSize, mOfflineStreams, mBlobBufferSize); - - mOutputThread->run("ExtCamOfflnOut", PRIORITY_DISPLAY); -} - -bool ExternalCameraOfflineSession::OutputThread::threadLoop() { - auto parent = mParent.promote(); - if (parent == nullptr) { - ALOGE("%s: session has been disconnected!", __FUNCTION__); - return false; - } - - if (mOfflineReqs.empty()) { - ALOGI("%s: all offline requests are processed. Stopping.", __FUNCTION__); - return false; - } - - std::shared_ptr req = mOfflineReqs.front(); - mOfflineReqs.pop_front(); - - auto onDeviceError = [&](auto... args) { - ALOGE(args...); - parent->notifyError( - req->frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE); - signalRequestDone(); - return false; - }; - - if (req->frameIn->mFourcc != V4L2_PIX_FMT_MJPEG && req->frameIn->mFourcc != V4L2_PIX_FMT_Z16) { - return onDeviceError("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__, - req->frameIn->mFourcc & 0xFF, - (req->frameIn->mFourcc >> 8) & 0xFF, - (req->frameIn->mFourcc >> 16) & 0xFF, - (req->frameIn->mFourcc >> 24) & 0xFF); - } - - int res = requestBufferStart(req->buffers); - if (res != 0) { - ALOGE("%s: send BufferRequest failed! res %d", __FUNCTION__, res); - return onDeviceError("%s: failed to send buffer request!", __FUNCTION__); - } - - std::unique_lock lk(mBufferLock); - // Convert input V4L2 frame to YU12 of the same size - // TODO: see if we can save some computation by converting to YV12 here - uint8_t* inData; - size_t inDataSize; - if (req->frameIn->getData(&inData, &inDataSize) != 0) { - lk.unlock(); - return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__); - } - - // TODO: in some special case maybe we can decode jpg directly to gralloc output? - if (req->frameIn->mFourcc == V4L2_PIX_FMT_MJPEG) { - ATRACE_BEGIN("MJPGtoI420"); - int res = libyuv::MJPGToI420( - inData, inDataSize, static_cast(mYu12FrameLayout.y), mYu12FrameLayout.yStride, - static_cast(mYu12FrameLayout.cb), mYu12FrameLayout.cStride, - static_cast(mYu12FrameLayout.cr), mYu12FrameLayout.cStride, - mYu12Frame->mWidth, mYu12Frame->mHeight, mYu12Frame->mWidth, mYu12Frame->mHeight); - ATRACE_END(); - - if (res != 0) { - // For some webcam, the first few V4L2 frames might be malformed... - ALOGE("%s: Convert V4L2 frame to YU12 failed! res %d", __FUNCTION__, res); - lk.unlock(); - Status st = parent->processCaptureRequestError(req); - if (st != Status::OK) { - return onDeviceError("%s: failed to process capture request error!", __FUNCTION__); - } - signalRequestDone(); - return true; - } - } - - ATRACE_BEGIN("Wait for BufferRequest done"); - res = waitForBufferRequestDone(&req->buffers); - ATRACE_END(); - - if (res != 0) { - ALOGE("%s: wait for BufferRequest done failed! res %d", __FUNCTION__, res); - lk.unlock(); - return onDeviceError("%s: failed to process buffer request error!", __FUNCTION__); - } - - ALOGV("%s processing new request", __FUNCTION__); - const int kSyncWaitTimeoutMs = 500; - for (auto& halBuf : req->buffers) { - if (*(halBuf.bufPtr) == nullptr) { - ALOGW("%s: buffer for stream %d missing", __FUNCTION__, halBuf.streamId); - halBuf.fenceTimeout = true; - } else if (halBuf.acquireFence >= 0) { - int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs); - if (ret) { - halBuf.fenceTimeout = true; - } else { - ::close(halBuf.acquireFence); - halBuf.acquireFence = -1; - } - } - - if (halBuf.fenceTimeout) { - continue; - } - - // Gralloc lockYCbCr the buffer - switch (halBuf.format) { - case PixelFormat::BLOB: { - int ret = createJpegLocked(halBuf, req->setting); - - if(ret != 0) { - lk.unlock(); - return onDeviceError("%s: createJpegLocked failed with %d", - __FUNCTION__, ret); - } - } break; - case PixelFormat::Y16: { - void* outLayout = sHandleImporter.lock(*(halBuf.bufPtr), halBuf.usage, inDataSize); - - std::memcpy(outLayout, inData, inDataSize); - - int relFence = sHandleImporter.unlock(*(halBuf.bufPtr)); - if (relFence >= 0) { - halBuf.acquireFence = relFence; - } - } break; - case PixelFormat::YCBCR_420_888: - case PixelFormat::YV12: { - IMapper::Rect outRect {0, 0, - static_cast(halBuf.width), - static_cast(halBuf.height)}; - YCbCrLayout outLayout = sHandleImporter.lockYCbCr( - *(halBuf.bufPtr), halBuf.usage, outRect); - ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d", - __FUNCTION__, outLayout.y, outLayout.cb, outLayout.cr, - outLayout.yStride, outLayout.cStride, outLayout.chromaStep); - - // Convert to output buffer size/format - uint32_t outputFourcc = V3_4::implementation::getFourCcFromLayout(outLayout); - ALOGV("%s: converting to format %c%c%c%c", __FUNCTION__, - outputFourcc & 0xFF, - (outputFourcc >> 8) & 0xFF, - (outputFourcc >> 16) & 0xFF, - (outputFourcc >> 24) & 0xFF); - - YCbCrLayout cropAndScaled; - ATRACE_BEGIN("cropAndScaleLocked"); - int ret = cropAndScaleLocked( - mYu12Frame, - Size { halBuf.width, halBuf.height }, - &cropAndScaled); - ATRACE_END(); - if (ret != 0) { - lk.unlock(); - return onDeviceError("%s: crop and scale failed!", __FUNCTION__); - } - - Size sz {halBuf.width, halBuf.height}; - ATRACE_BEGIN("formatConvert"); - ret = V3_4::implementation::formatConvert(cropAndScaled, outLayout, sz, outputFourcc); - ATRACE_END(); - if (ret != 0) { - lk.unlock(); - return onDeviceError("%s: format coversion failed!", __FUNCTION__); - } - int relFence = sHandleImporter.unlock(*(halBuf.bufPtr)); - if (relFence >= 0) { - halBuf.acquireFence = relFence; - } - } break; - default: - lk.unlock(); - return onDeviceError("%s: unknown output format %x", __FUNCTION__, halBuf.format); - } - } // for each buffer - mScaledYu12Frames.clear(); - - // Don't hold the lock while calling back to parent - lk.unlock(); - Status st = parent->processCaptureResult(req); - if (st != Status::OK) { - return onDeviceError("%s: failed to process capture result!", __FUNCTION__); - } - signalRequestDone(); - return true; -} - -Status ExternalCameraOfflineSession::importBuffer(int32_t streamId, - uint64_t bufId, buffer_handle_t buf, - /*out*/buffer_handle_t** outBufPtr, - bool allowEmptyBuf) { - Mutex::Autolock _l(mCbsLock); - return V3_4::implementation::importBufferImpl( - mCirculatingBuffers, sHandleImporter, streamId, - bufId, buf, outBufPtr, allowEmptyBuf); - return Status::OK; -}; - -#define UPDATE(md, tag, data, size) \ -do { \ - if ((md).update((tag), (data), (size))) { \ - ALOGE("Update " #tag " failed!"); \ - return BAD_VALUE; \ - } \ -} while (0) - -status_t ExternalCameraOfflineSession::fillCaptureResult( - common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) { - bool afTrigger = false; - { - std::lock_guard lk(mAfTriggerLock); - afTrigger = mAfTrigger; - if (md.exists(ANDROID_CONTROL_AF_TRIGGER)) { - camera_metadata_entry entry = md.find(ANDROID_CONTROL_AF_TRIGGER); - if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) { - mAfTrigger = afTrigger = true; - } else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) { - mAfTrigger = afTrigger = false; - } - } - } - - // For USB camera, the USB camera handles everything and we don't have control - // over AF. We only simply fake the AF metadata based on the request - // received here. - uint8_t afState; - if (afTrigger) { - afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED; - } else { - afState = ANDROID_CONTROL_AF_STATE_INACTIVE; - } - UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1); - - camera_metadata_ro_entry activeArraySize = - mChars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE); - - return V3_4::implementation::fillCaptureResultCommon(md, timestamp, activeArraySize); -} - -#undef UPDATE - -Status ExternalCameraOfflineSession::processCaptureResult(std::shared_ptr& req) { - ATRACE_CALL(); - // Fill output buffers - hidl_vec results; - results.resize(1); - CaptureResult& result = results[0]; - result.frameNumber = req->frameNumber; - result.partialResult = 1; - result.inputBuffer.streamId = -1; - result.outputBuffers.resize(req->buffers.size()); - for (size_t i = 0; i < req->buffers.size(); i++) { - result.outputBuffers[i].streamId = req->buffers[i].streamId; - result.outputBuffers[i].bufferId = req->buffers[i].bufferId; - if (req->buffers[i].fenceTimeout) { - result.outputBuffers[i].status = BufferStatus::ERROR; - if (req->buffers[i].acquireFence >= 0) { - native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0); - handle->data[0] = req->buffers[i].acquireFence; - result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false); - } - notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER); - } else { - result.outputBuffers[i].status = BufferStatus::OK; - // TODO: refactor - if (req->buffers[i].acquireFence >= 0) { - native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0); - handle->data[0] = req->buffers[i].acquireFence; - result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false); - } - } - } - - // Fill capture result metadata - fillCaptureResult(req->setting, req->shutterTs); - const camera_metadata_t *rawResult = req->setting.getAndLock(); - V3_2::implementation::convertToHidl(rawResult, &result.result); - req->setting.unlock(rawResult); - - // Callback into framework - invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true); - V3_4::implementation::freeReleaseFences(results); - return Status::OK; -}; - -void ExternalCameraOfflineSession::invokeProcessCaptureResultCallback( - hidl_vec &results, bool tryWriteFmq) { - if (mProcessCaptureResultLock.tryLock() != OK) { - const nsecs_t NS_TO_SECOND = 1000000000; - ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__); - if (mProcessCaptureResultLock.timedLock(/* 1s */NS_TO_SECOND) != OK) { - ALOGE("%s: cannot acquire lock in 1s, cannot proceed", - __FUNCTION__); - return; - } - } - if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) { - for (CaptureResult &result : results) { - if (result.result.size() > 0) { - if (mResultMetadataQueue->write(result.result.data(), result.result.size())) { - result.fmqResultSize = result.result.size(); - result.result.resize(0); - } else { - ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__); - result.fmqResultSize = 0; - } - } else { - result.fmqResultSize = 0; - } - } - } - auto status = mCallback->processCaptureResult(results); - if (!status.isOk()) { - ALOGE("%s: processCaptureResult ERROR : %s", __FUNCTION__, - status.description().c_str()); - } - - mProcessCaptureResultLock.unlock(); -} - -Status ExternalCameraOfflineSession::processCaptureRequestError( - const std::shared_ptr& req, - /*out*/std::vector* outMsgs, - /*out*/std::vector* outResults) { - ATRACE_CALL(); - - if (outMsgs == nullptr) { - notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST); - } else { - NotifyMsg shutter; - shutter.type = MsgType::SHUTTER; - shutter.msg.shutter.frameNumber = req->frameNumber; - shutter.msg.shutter.timestamp = req->shutterTs; - - NotifyMsg error; - error.type = MsgType::ERROR; - error.msg.error.frameNumber = req->frameNumber; - error.msg.error.errorStreamId = -1; - error.msg.error.errorCode = ErrorCode::ERROR_REQUEST; - outMsgs->push_back(shutter); - outMsgs->push_back(error); - } - - // Fill output buffers - hidl_vec results; - results.resize(1); - CaptureResult& result = results[0]; - result.frameNumber = req->frameNumber; - result.partialResult = 1; - result.inputBuffer.streamId = -1; - result.outputBuffers.resize(req->buffers.size()); - for (size_t i = 0; i < req->buffers.size(); i++) { - result.outputBuffers[i].streamId = req->buffers[i].streamId; - result.outputBuffers[i].bufferId = req->buffers[i].bufferId; - result.outputBuffers[i].status = BufferStatus::ERROR; - if (req->buffers[i].acquireFence >= 0) { - native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0); - handle->data[0] = req->buffers[i].acquireFence; - result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false); - } - } - - if (outResults == nullptr) { - // Callback into framework - invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true); - V3_4::implementation::freeReleaseFences(results); - } else { - outResults->push_back(result); - } - return Status::OK; -}; - -ssize_t ExternalCameraOfflineSession::getJpegBufferSize( - uint32_t /*width*/, uint32_t /*height*/) const { - // Empty implementation here as the jpeg buffer size is passed in by ctor - return 0; -}; - -void ExternalCameraOfflineSession::notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) { - NotifyMsg msg; - msg.type = MsgType::ERROR; - msg.msg.error.frameNumber = frameNumber; - msg.msg.error.errorStreamId = streamId; - msg.msg.error.errorCode = ec; - mCallback->notify({msg}); -}; - -Return ExternalCameraOfflineSession::setCallback(const sp& cb) { - Mutex::Autolock _il(mInterfaceLock); - if (mCallback != nullptr && cb != nullptr) { - ALOGE("%s: callback must not be set twice!", __FUNCTION__); - return Void(); - } - mCallback = cb; - - initOutputThread(); - - if (mOutputThread == nullptr) { - ALOGE("%s: init OutputThread failed!", __FUNCTION__); - } - return Void(); -} - -Return ExternalCameraOfflineSession::getCaptureResultMetadataQueue( - V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) { - Mutex::Autolock _il(mInterfaceLock); - _hidl_cb(*mResultMetadataQueue->getDesc()); - return Void(); -} - -void ExternalCameraOfflineSession::cleanupBuffersLocked(int id) { - for (auto& pair : mCirculatingBuffers.at(id)) { - sHandleImporter.freeBuffer(pair.second); - } - mCirculatingBuffers[id].clear(); - mCirculatingBuffers.erase(id); -} - -Return ExternalCameraOfflineSession::close() { - Mutex::Autolock _il(mInterfaceLock); - { - Mutex::Autolock _l(mLock); - if (mClosed) { - ALOGW("%s: offline session already closed!", __FUNCTION__); - return Void(); - } - } - if (mBufferRequestThread) { - mBufferRequestThread->requestExit(); - mBufferRequestThread->join(); - mBufferRequestThread.clear(); - } - if (mOutputThread) { - mOutputThread->flush(); - mOutputThread->requestExit(); - mOutputThread->join(); - mOutputThread.clear(); - } - - Mutex::Autolock _l(mLock); - // free all buffers - { - Mutex::Autolock _cbl(mCbsLock); - for(auto stream : mOfflineStreams) { - cleanupBuffersLocked(stream.id); - } - } - mCallback.clear(); - mClosed = true; - return Void(); -} - -} // namespace implementation -} // namespace V3_6 -} // namespace device -} // namespace camera -} // namespace hardware -} // namespace android diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h index db0d9a548b..0e57c4c243 100644 --- a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h +++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h @@ -14,13 +14,12 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H -#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H +#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE3SESSION_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE3SESSION_H #include #include #include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h> -#include "ExternalCameraOfflineSession.h" namespace android { namespace hardware { @@ -38,7 +37,6 @@ using ::android::hardware::camera::device::V3_2::RequestTemplate; using ::android::hardware::camera::device::V3_2::Stream; using ::android::hardware::camera::device::V3_5::StreamConfiguration; using ::android::hardware::camera::device::V3_6::ICameraDeviceSession; -using ::android::hardware::camera::device::V3_6::ICameraOfflineSession; using ::android::hardware::camera::common::V1_0::Status; using ::android::hardware::camera::external::common::ExternalCameraConfig; using ::android::hardware::graphics::common::V1_0::PixelFormat; @@ -71,6 +69,13 @@ struct ExternalCameraDeviceSession : public V3_5::implementation::ExternalCamera return new TrampolineSessionInterface_3_6(this); } + static Status isStreamCombinationSupported(const V3_2::StreamConfiguration& config, + const std::vector& supportedFormats, + const ExternalCameraConfig& devCfg) { + return V3_4::implementation::ExternalCameraDeviceSession::isStreamCombinationSupported( + config, supportedFormats, devCfg); + } + protected: // Methods from v3.5 and earlier will trampoline to inherited implementation Return configureStreams_3_6( @@ -81,28 +86,6 @@ protected: const hidl_vec& streamsToKeep, ICameraDeviceSession::switchToOffline_cb _hidl_cb); - void fillOutputStream3_6(const V3_3::HalStreamConfiguration& outStreams_v33, - /*out*/V3_6::HalStreamConfiguration* outStreams_v36); - bool supportOfflineLocked(int32_t streamId); - - // Main body of switchToOffline. This method does not invoke any callbacks - // but instead returns the necessary callbacks in output arguments so callers - // can callback later without holding any locks - Status switchToOffline(const hidl_vec& offlineStreams, - /*out*/std::vector* msgs, - /*out*/std::vector* results, - /*out*/CameraOfflineSessionInfo* info, - /*out*/sp* session); - - // Whether a request can be completely dropped when switching to offline - bool canDropRequest(const hidl_vec& offlineStreams, - std::shared_ptr halReq); - - void fillOfflineSessionInfo(const hidl_vec& offlineStreams, - std::deque>& offlineReqs, - const std::map& circulatingBuffers, - /*out*/CameraOfflineSessionInfo* info); - private: struct TrampolineSessionInterface_3_6 : public ICameraDeviceSession { @@ -205,4 +188,4 @@ private: } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE3SESSION_H diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h deleted file mode 100644 index 230b67c43c..0000000000 --- a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * 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_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H -#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H - -#include -#include -#include -#include -#include -#include -#include -#include <../../3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h> -#include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h> -#include -#include -#include - -namespace android { -namespace hardware { -namespace camera { -namespace device { -namespace V3_6 { -namespace implementation { - -using ::android::hardware::camera::device::V3_2::BufferCache; -using ::android::hardware::camera::device::V3_5::BufferRequest; -using ::android::hardware::camera::device::V3_5::BufferRequestStatus; -using ::android::hardware::camera::device::V3_2::BufferStatus; -using ::android::hardware::camera::device::V3_2::CameraMetadata; -using ::android::hardware::camera::device::V3_2::CaptureRequest; -using ::android::hardware::camera::device::V3_2::CaptureResult; -using ::android::hardware::camera::device::V3_2::ErrorCode; -using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback; -using ::android::hardware::camera::device::V3_2::MsgType; -using ::android::hardware::camera::device::V3_2::NotifyMsg; -using ::android::hardware::camera::device::V3_2::RequestTemplate; -using ::android::hardware::camera::device::V3_2::Stream; -using ::android::hardware::camera::device::V3_5::StreamConfiguration; -using ::android::hardware::camera::device::V3_2::StreamConfigurationMode; -using ::android::hardware::camera::device::V3_2::StreamRotation; -using ::android::hardware::camera::device::V3_2::StreamType; -using ::android::hardware::camera::device::V3_2::DataspaceFlags; -using ::android::hardware::camera::device::V3_2::CameraBlob; -using ::android::hardware::camera::device::V3_2::CameraBlobId; -using ::android::hardware::camera::device::V3_4::HalStreamConfiguration; -using ::android::hardware::camera::device::V3_6::ICameraOfflineSession; -using ::android::hardware::camera::common::V1_0::Status; -using ::android::hardware::camera::common::V1_0::helper::HandleImporter; -using ::android::hardware::camera::common::V1_0::helper::ExifUtils; -using ::android::hardware::camera::external::common::ExternalCameraConfig; -using ::android::hardware::camera::external::common::Size; -using ::android::hardware::camera::external::common::SizeHasher; -using ::android::hardware::graphics::common::V1_0::BufferUsage; -using ::android::hardware::graphics::common::V1_0::Dataspace; -using ::android::hardware::graphics::common::V1_0::PixelFormat; -using ::android::hardware::kSynchronizedReadWrite; -using ::android::hardware::MessageQueue; -using ::android::hardware::MQDescriptorSync; -using ::android::hardware::Return; -using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; -using ::android::Mutex; -using ::android::base::unique_fd; - -using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format; -using ::android::hardware::camera::device::V3_4::implementation::CroppingType; -using ::android::hardware::camera::device::V3_4::implementation::CirculatingBuffers; -using ::android::hardware::camera::device::V3_4::implementation::HalRequest; -using ::android::hardware::camera::device::V3_4::implementation::OutputThreadInterface; - -struct ExternalCameraOfflineSession : public virtual RefBase, - public virtual OutputThreadInterface { - - ExternalCameraOfflineSession( - const CroppingType& croppingType, - const common::V1_0::helper::CameraMetadata& chars, - const std::string& cameraId, - const std::string& exifMake, - const std::string& exifModel, - uint32_t blobBufferSize, - bool afTrigger, - const hidl_vec& offlineStreams, - std::deque>& offlineReqs, - const std::map& circulatingBuffers); - - bool initialize(); - - virtual ~ExternalCameraOfflineSession(); - - // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when - // dealing with minor version revs and simultaneous implementation and interface inheritance - virtual sp getInterface() { - return new TrampolineSessionInterface_3_6(this); - } - -protected: - - // Methods from OutputThreadInterface - virtual Status importBuffer(int32_t streamId, - uint64_t bufId, buffer_handle_t buf, - /*out*/buffer_handle_t** outBufPtr, - bool allowEmptyBuf) override; - - virtual Status processCaptureResult(std::shared_ptr&) override; - - virtual Status processCaptureRequestError(const std::shared_ptr&, - /*out*/std::vector* msgs = nullptr, - /*out*/std::vector* results = nullptr) override; - - virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override; - - virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override; - // End of OutputThreadInterface methods - - class OutputThread : public V3_5::implementation::ExternalCameraDeviceSession::OutputThread { - public: - OutputThread( - wp parent, CroppingType ct, - const common::V1_0::helper::CameraMetadata& chars, - sp bufReqThread, - std::deque>& offlineReqs) : - V3_5::implementation::ExternalCameraDeviceSession::OutputThread( - parent, ct, chars, bufReqThread), - mOfflineReqs(offlineReqs) {} - - virtual bool threadLoop() override; - - protected: - std::deque> mOfflineReqs; - }; // OutputThread - - - Return setCallback(const sp& cb); - - Return getCaptureResultMetadataQueue( - V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb); - - Return close(); - - void initOutputThread(); - - void invokeProcessCaptureResultCallback( - hidl_vec &results, bool tryWriteFmq); - - status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp); - - void cleanupBuffersLocked(int id); - - // Protect (most of) HIDL interface methods from synchronized-entering - mutable Mutex mInterfaceLock; - - mutable Mutex mLock; // Protect all data members except otherwise noted - - bool mClosed = false; - const CroppingType mCroppingType; - const common::V1_0::helper::CameraMetadata mChars; - const std::string mCameraId; - const std::string mExifMake; - const std::string mExifModel; - const uint32_t mBlobBufferSize; - - std::mutex mAfTriggerLock; // protect mAfTrigger - bool mAfTrigger; - - const hidl_vec mOfflineStreams; - std::deque> mOfflineReqs; - - // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock - mutable Mutex mCbsLock; - std::map mCirculatingBuffers; - - static HandleImporter sHandleImporter; - - using ResultMetadataQueue = MessageQueue; - std::shared_ptr mResultMetadataQueue; - - // Protect against invokeProcessCaptureResultCallback() - Mutex mProcessCaptureResultLock; - - sp mCallback; - - sp mBufferRequestThread; - sp mOutputThread; -private: - - struct TrampolineSessionInterface_3_6 : public ICameraOfflineSession { - TrampolineSessionInterface_3_6(sp parent) : - mParent(parent) {} - - virtual Return setCallback(const sp& cb) override { - return mParent->setCallback(cb); - } - - virtual Return getCaptureResultMetadataQueue( - V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override { - return mParent->getCaptureResultMetadataQueue(_hidl_cb); - } - - virtual Return close() override { - return mParent->close(); - } - - private: - sp mParent; - }; -}; - -} // namespace implementation -} // namespace V3_6 -} // namespace device -} // namespace camera -} // namespace hardware -} // namespace android - -#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H diff --git a/camera/provider/2.5/default/Android.bp b/camera/provider/2.5/default/Android.bp index 67eb7caafd..4563362ddb 100644 --- a/camera/provider/2.5/default/Android.bp +++ b/camera/provider/2.5/default/Android.bp @@ -52,8 +52,6 @@ cc_library_shared { "android.hardware.camera.provider@2.4-external", "android.hardware.camera.provider@2.5", "android.hardware.graphics.mapper@2.0", - "android.hardware.graphics.mapper@3.0", - "android.hardware.graphics.mapper@4.0", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "camera.device@3.3-impl", @@ -74,8 +72,7 @@ cc_library_shared { ], header_libs: [ "camera.device@3.4-external-impl_headers", - "camera.device@3.5-external-impl_headers", - "camera.device@3.6-external-impl_headers" + "camera.device@3.5-external-impl_headers" ], export_include_dirs: ["."], } From a9c097abec1b3ebb909638e36b37c2a908a88c47 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Fri, 31 Jan 2020 14:18:03 +0000 Subject: [PATCH 0518/1022] NNAPI: Add OptionalTimeoutDuration to 1.3/types.t To sync 1.3/types.t with 1.3/types.hal Test: generate_api.sh Change-Id: I6a6e46ec82b4f25d77f7e1af18cc9d6f9478e5b7 --- neuralnetworks/1.3/types.t | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t index a973923d8d..d4351ec8d7 100644 --- a/neuralnetworks/1.3/types.t +++ b/neuralnetworks/1.3/types.t @@ -552,6 +552,19 @@ safe_union OptionalTimePoint { uint64_t nanoseconds; }; +/** + * Optional timeout duration measured in nanoseconds. + */ +safe_union OptionalTimeoutDuration { + /** No time point provided. */ + Monostate none; + + /** + * Timeout duration measured in nanoseconds. + */ + uint64_t nanoseconds; +}; + /** * Return status of a function. */ From c5afe480bda3c35b58c5b85867f2eb2ff649343b Mon Sep 17 00:00:00 2001 From: felipeal Date: Fri, 24 Jan 2020 18:36:25 -0800 Subject: [PATCH 0519/1022] Added new properties on Vehicle HAL to support user management. These initial properties are: - INITIAL_USER_INFO: gets information about the initial user, it will replace the android.car.systemuser.bootuseroverrideid system property approach. - SWITCH_USER_REQUEST: used to communicate a user switch request from Android to HAL, or vice versa. This CL only defines the new types, they're not implemented or used yet. Test: m -j android.hardware.automotive.vehicle@2.0-service Bug: 146207078 Change-Id: I25055f8adc90aaebaf3a3faa9a9b73c284440624 --- automotive/vehicle/2.0/types.hal | 466 +++++++++++++++++++++++++++++++ 1 file changed, 466 insertions(+) diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index 6145ea2710..a91bd885b3 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -2438,6 +2438,217 @@ enum VehicleProperty : int32_t { | VehiclePropertyType:STRING | VehicleArea:GLOBAL), + /** + * Defines the initial Android user to be used during initialization. + * + * This property is called by the Android system when it initializes and it lets the HAL + * define which Android user should be started. + * + * This request is made by setting a VehiclePropValue (defined by InitialUserInfoRequest), + * and the HAL must respond with a property change event (defined by InitialUserInfoResponse). + * If the HAL doesn't respond after some time (defined by the Android system), the Android + * system will proceed as if HAL returned a response of action + * InitialUserInfoResponseAction:DEFAULT. + * + * For example, on first boot, the request could be: + * + * int32[0]: 42 // request id (arbitrary number set by Android system) + * int32[1]: 1 // InitialUserInfoRequestType::FIRST_BOOT + * int32[2]: 0 // id of current user (usersInfo.currentUser.userId) + * int32[3]: 1 // flag of current user (usersInfo.currentUser.flags = SYSTEM) + * int32[4]: 1 // number of existing users (usersInfo.numberUsers); + * int32[5]: 0 // user #0 (usersInfo.existingUsers[0].userId) + * int32[6]: 1 // flags of user #0 (usersInfo.existingUsers[0].flags) + * + * And if the HAL want to respond with the creation of an admin user called "Admin", the + * response would be: + * + * 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[3]: 8 // userToSwitchOrCreate.flags = ADMIN + * string: "Admin" // userNameToCreate + * + * 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, TODO(b/146207078):others). + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + INITIAL_USER_INFO = ( + 0x0F07 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:MIXED + | VehicleArea:GLOBAL), + + /** + * Defines a request to switch the foreground Android user. + * + * This property is used primarily by the Android System to inform the HAL that the + * current foreground Android user is switching, but it could also be used by the HAL to request + * the Android system to switch users - the + * + * When the request is made by Android, it sets a VehiclePropValue and the HAL must responde + * with a property change event; when the HAL is making the request, it must also do it through + * a property change event (the main difference is that the request id will be positive in the + * former case, and negative in the latter; the SwitchUserMessageType will also be different). + * + * The format of both request is defined by SwitchUserRequest and the format of the response + * (when needed) is defined by SwitchUserResponse. How the HAL (or Android System) should + * proceed depends on the message type (which is defined by the SwitchUserMessageType + * parameter), as defined below. + * + * 1.LEGACY_ANDROID_SWITCH + * ----------------------- + * + * Called by the Android System to indicate the Android user is about to change, when the change + * request was made in a way that is not integrated with the HAL (for example, through + * adb shell am switch-user). + * + * The HAL can switch its internal user once it receives this request, but it doesn't need to + * reply back to the Android System. If its internal user cannot be changed for some reason, + * then it must wait for the SWITCH_USER(type=ANDROID_POST_SWITCH) call to recover + * (for example, it could issue a SWITCH_USER(type=VEHICLE_REQUEST) to switch back to + * the previous user), but ideally it should never fail (as switching back could result in a + * confusing experience for the end user). + * + * For example, if the system have users (0, 10, 11) and it's switching from 0 to 11 (where none + * of them have any special flag), the request would be: + * + * int32[0]: 42 // request id + * int32[1]: 1 // SwitchUserMessageType::LEGACY_ANDROID_SWITCH + * int32[2]: 11 // target user id + * int32[3]: 0 // target user flags (none) + * int32[4]: 10 // current user + * int32[5]: 0 // current user flags (none) + * int32[6]: 3 // number of users + * int32[7]: 0 // user #0 (Android user id 0) + * int32[8]: 0 // flags of user #0 (none) + * int32[9]: 10 // user #1 (Android user id 10) + * int32[10]: 0 // flags of user #1 (none) + * int32[11]: 11 // user #2 (Android user id 11) + * int32[12]: 0 // flags of user #2 (none) + * + * 2.ANDROID_SWITCH + * ---------------- + * Called by the Android System to indicate the Android user is about to change, but Android + * will wait for the HAL's response (up to some time) before proceeding. + * + * The HAL must switch its internal user once it receives this request, then respond back to + * Android with a SWITCH_USER(type=VEHICLE_RESPONSE) indicating whether its internal + * user was switched or not (through the SwitchUserStatus enum). + * + * For example, if Android has users (0, 10, 11) and it's switching from 10 to 11 (where + * none of them have any special flag), the request would be: + * + * int32[0]: 42 // request id + * int32[1]: 2 // SwitchUserMessageType::ANDROID_SWITCH + * int32[2]: 11 // target user id + * int32[3]: 0 // target user flags (none) + * int32[4]: 10 // current user + * 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[9]: 10 // 2nd user (user 10) + * int32[10]: 0 // 2nd user flags (none) + * int32[11]: 11 // 3rd user (user 11) + * int32[12]: 0 // 3rd user flags (none) + * + * If the request succeeded, the HAL must update the propery with: + * + * int32[0]: 42 // request id + * int32[1]: 3 // messageType = SwitchUserMessageType::VEHICLE_RESPONSE + * int32[2]: 1 // status = SwitchUserStatus::SUCCESS + * + * But if it failed, the response would be something like: + * + * int32[0]: 42 // request id + * int32[1]: 3 // messageType = SwitchUserMessageType::VEHICLE_RESPONSE + * int32[2]: 2 // status = SwitchUserStatus::FAILURE + * string: "108-D'OH!" // OEM-spefic error message + * + * 3.VEHICLE_RESPONSE + * ------------------ + * Called by the HAL to indicate whether a request of type ANDROID_SWITCH should proceed or + * abort - see the ANDROID_SWITCH section above for more info. + * + * 4.VEHICLE_REQUEST + * ------------------ + * Called by the HAL to request that the current foreground Android user is switched. + * + * This is useful in situations where Android started as one user, but the vehicle identified + * the driver as another user. For example, user A unlocked the car using the key fob of user B; + * the INITIAL_USER_INFO request returned user B, but then a face recognition subsubsystem + * 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 + * request id. + * + * For example, if the current foreground Android user is 10 and the HAL asked it to switch to + * 11, the request would be: + * + * int32[0]: -108 // request id + * int32[1]: 4 // messageType = SwitchUserMessageType::VEHICLE_REQUEST + * int32[2]: 11 // Android user id + * + * If the request succeeded and Android has 3 users (0, 10, 11), the response would be: + * + * int32[0]: -108 // request id + * int32[1]: 5 // messageType = SwitchUserMessageType::ANDROID_SWITCH + * int32[2]: 11 // target user id + * int32[3]: 11 // target user id flags (none) + * int32[4]: 11 // current user + * 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[9]: 10 // 2nd user (user 10) + * int32[10]: 4 // 2nd user flags (none) + * int32[11]: 11 // 3rd user (user 11) + * int32[12]: 3 // 3rd user flags (none) + * + * Notice that both the current and target user ids are the same - if the request failed, then + * they would be different (i.e, target user would be 11, but current user would still be 10). + * + * 5.ANDROID_POST_SWITCH + * --------------------- + * Called by the Android System after a request to switch a user was made + * + * This property is called after switch requests of any type (i.e., LEGACY_ANDROID_SWITCH, + * ANDROID_SWITCH, or VEHICLE_REQUEST) and can be used to determine if the request succeeded or + * failed: + * + * 1. When it succeeded, it's called when the Android user is in the boot locked state and the + * value of the current and target users ids in the response are different. This would be + * equivalent to receiving an Intent.ACTION_LOCKED_BOOT_COMPLETED in an Android app. + * 2. When it failed it's called right away and the value of the current and target users ids + * in the response are the same. + * + * The HAL can update its internal state once it receives this request, but it doesn't need to + * reply back to the Android System. + * + * Request: the first N values as defined by INITIAL_USER_INFO (where the request-specific + * value at index 1 is SwitchUserMessageType::ANDROID_POST_SWITCH), then 2 more values for the + * target user id (i.e., the Android user id that was requested to be switched to) and its flags + * (as defined by UserFlags). + * + * Response: none. + * + * Example: see VEHICLE_REQUEST section above. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SWITCH_USER = ( + 0x0F08 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:MIXED + | VehicleArea:GLOBAL), }; /** @@ -3733,3 +3944,258 @@ enum VmsAvailabilityStateIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex { enum VmsPublisherInformationIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex { PUBLISHER_ID = 1, }; + +/** + * Information about a specific Android user. + */ +struct UserInfo { + + UserId userId; + + UserFlags flags; +}; + +/** + * Id of an Android user. + * + * Must be > 0 for valid ids, or -1 when it's not used. + */ +typedef int32_t UserId; + +/** + * Flags used to define the characteristics of an Android user. + */ +enum UserFlags: int32_t { + /** + * No flags. + */ + NONE = 0x0, + + /** + * System user. + * On automotive, that user is always running, although never on foreground (except during + * boot or exceptional circumstances). + */ + SYSTEM = 0x01, + + /** + * Guest users have restrictions. + */ + GUEST = 0x02, + + /** + * Ephemeral users have non-persistent state. + */ + EPHEMERAL = 0x04, + + /** + * Admin users have additional privileges such as permission to create other users. + */ + ADMIN = 0x08, +}; + +/** + * Information about all Android users. + * + * NOTE: this struct is not used in the HAL properties directly, it's part of other structs, which + * in turn are converted to a VehiclePropValue.RawValue through libraries provided by the default + * Vehicle HAL implementation. + */ +struct UsersInfo { + + /** The current foreground user. */ + UserInfo currentUser; + + /** Number of existing users (includes the current user). */ + int32_t numberUsers; + + /** List of existing users (includes the current user). */ + vec existingUsers; + }; + +/** + * Id of a request related to user management. + * + * This id can be used by the Android system to map responses sent by the HAL, and vice-versa. + * + * For requests originated by Android, the value is positive (> 0), while for requests originated by + * the HAL it must be negative (< 0). + */ +typedef int32_t UserRequestId; + +/** + * Defines the format of a INITIAL_USER_INFO request made by the Android system. + * + * NOTE: this struct is not used in the HAL properties directly, it must be converted to + * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation. + */ +struct InitialUserInfoRequest { + /** + * Arbitrary id used to map the HAL response to the request. + */ + UserRequestId requestId; + + /** + * Type of request. + */ + InitialUserInfoRequestType requestType; + + /** + * Information about the current state of the Android system. + */ + UsersInfo usersInfo; +}; + +/** + * Defines when a INITIAL_USER_INFO request was made. + */ +enum InitialUserInfoRequestType : int32_t { + /** At the first time Android was booted (or after a factory reset). */ + FIRST_BOOT = 1, + + /** At the first time Android was booted after the system was updated. */ + FIRST_BOOT_AFTER_OTA = 2, + + /** When Android was booted "from scratch". */ + COLD_BOOT = 3, + + /** When Android was resumed after the system was suspended to memory. */ + RESUME = 4, +}; + +/** + * Defines the format of a HAL response to a INITIAL_USER_INFO request. + * + * NOTE: this struct is not used in the HAL properties directly, it must be converted to + * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation. + */ +struct InitialUserInfoResponse { + /** + * Id of the request being responded. + */ + UserRequestId requestId; + + /** + * which action the Android system should take. + */ + InitialUserInfoResponseAction action; + + /** + * Information about the user that should be switched to or created. + */ + UserInfo userToSwitchOrCreate; + + /** + * Name of the user that should be created. + */ + string userNameToCreate; +}; + +/** + * Defines which action the Android system should take in an INITIAL_USER_INFO request. + */ +enum InitialUserInfoResponseAction : int32_t { + /** + * Let the Android System decide what to do. + * + * For example, it might create a new user on first boot, and switch to the last + * active user afterwards. + */ + DEFAULT = 0, + + /** + * Switch to an existing Android user. + */ + SWITCH = 1, + + /** + * Create a new Android user (and switch to it). + */ + CREATE = 2, +}; + +/** + * Defines the format of a SWITCH_USER property. + * + * NOTE: this struct is not used in the HAL properties directly, it must be converted to + * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation. + */ +struct SwitchUserRequest { + /** + * Arbitrary id used to map the response to the request. + */ + UserRequestId requestId; + + /** + * Type of message. + */ + SwitchUserMessageType messageType; + + /** + * Information about the Android user being switched to. + * + * Only the user id (but not the flags) should be set when the request is made by HAL. + */ + UserInfo targetUser; + + /** + * Information about the current state of the Android system. + * + * Should not be set when the request is made by HAL. + */ + UsersInfo usersInfo; +}; + +/** + * Defines the reason a SWITCH_USER call was made. + * + * The meaning of each constant is explained in that property. + */ +enum SwitchUserMessageType: int32_t { + LEGACY_ANDROID_SWITCH = 1, + ANDROID_SWITCH = 2, + VEHICLE_RESPONSE = 3, + VEHICLE_REQUEST = 4, + ANDROID_POST_SWITCH = 5, +}; + +/** + * Defines the result of a SwitchUserRequest. + * + * NOTE: this struct is not used in the HAL properties directly, it must be converted to + * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation. + */ +struct SwitchUserResponse { + /** + * Id of the request being responded. + */ + UserRequestId requestId; + + /** + * Type of message. + */ + SwitchUserMessageType messageType; + + /** + * Status of the request. + */ + SwitchUserStatus status; + + /** + * HAL-specific error message. + * + * This argument is optional, and when defined (and the status is FAILURE), it's passed "as-is" + * to the caller. It could be used to show custom error messages to the end user. + */ + string failureMessage; +}; + +/** + * Status of the response to a SwitchUserRequest. + */ +enum SwitchUserStatus : int32_t { + /** The request succeeded and the HAL user was switched. */ + SUCCESS = 1, + /** The request failed and the HAL user remained the same. */ + FAILURE = 2, +}; From b0bb8de6142a8be052fc2916a7d9d71528b58ea4 Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Thu, 30 Jan 2020 23:01:34 -0800 Subject: [PATCH 0520/1022] Camera: Add @2.6::ICameraProvider to current.txt Test: Build Bug: 148181647 Change-Id: I2809a299d02fc5b5c4d8a54d10ebad67c0547d4c --- current.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/current.txt b/current.txt index 74c0cbbb5b..a71ec713f4 100644 --- a/current.txt +++ b/current.txt @@ -634,6 +634,8 @@ ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardwar 40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types +e88840e0558439cb54837514ddccd43877094951758f367e9c638084eb7455a6 android.hardware.camera.provider@2.6::ICameraProvider +8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas 9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardware.cas@1.2::IMediaCasService From c8d278d18d9560e43e410ead4480aa0c43e89b42 Mon Sep 17 00:00:00 2001 From: Nicholas Ambur Date: Fri, 31 Jan 2020 11:00:03 -0800 Subject: [PATCH 0521/1022] ISoundTriggerHw.RecognitionConfig to bitfield Bug: 148236002 Test: atest SoundTriggerMiddlewareImplTest Change-Id: I512dd5265d433ecd6873a98c460b3e9ffb57063c --- current.txt | 2 +- soundtrigger/2.3/types.hal | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/current.txt b/current.txt index ad9c1d1d76..df1a188937 100644 --- a/current.txt +++ b/current.txt @@ -682,6 +682,6 @@ e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardwar a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication 0006ab8e8b0910cbd3bbb08d5f17d5fac7d65a2bdad5f2334e4851db9d1e6fa8 android.hardware.radio.config@1.3::IRadioConfigResponse -51d1c8d285e0456da2a3fdfbf4700c6277165d5e83219894d651c8ea0e39aa8b android.hardware.soundtrigger@2.3::types +4a6517ea4ad807855428b0101d8e1a486497bd88ab4300ba3b2be43d46d32580 android.hardware.soundtrigger@2.3::types 12d7533ff0754f45bf59ab300799074570a99a676545652c2c23abc73cb4515d android.hardware.soundtrigger@2.3::ISoundTriggerHw 7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget diff --git a/soundtrigger/2.3/types.hal b/soundtrigger/2.3/types.hal index 730f9695af..10fc34e312 100644 --- a/soundtrigger/2.3/types.hal +++ b/soundtrigger/2.3/types.hal @@ -66,7 +66,7 @@ struct RecognitionConfig { * Bit field encoding of the AudioCapabilities * supported by the firmware. */ - uint32_t audioCapabilities; + bitfield audioCapabilities; }; /** From 3dfa6059070be4caa988a29b5391355146752983 Mon Sep 17 00:00:00 2001 From: Malcolm Chen Date: Thu, 30 Jan 2020 20:17:13 -0800 Subject: [PATCH 0522/1022] Remove setSystemSelectionChannels vts test. This HAL API was not enforced in IRadio 1.3. The vts was disabled. Now we have new API setSystemSelectionChannels_1_5 in IRadio 1.5 and corresponding vts test. We no longer need this old disabled vts. Bug: 146062695 Test: vts Change-Id: Ie81cb38c4848118318b9df5eef799469ff362f16 --- .../1.3/vts/functional/radio_hidl_hal_api.cpp | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/radio/1.3/vts/functional/radio_hidl_hal_api.cpp b/radio/1.3/vts/functional/radio_hidl_hal_api.cpp index 4e4814103d..ca64305bfe 100644 --- a/radio/1.3/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.3/vts/functional/radio_hidl_hal_api.cpp @@ -75,38 +75,3 @@ TEST_P(RadioHidlTest_v1_3, getModemStackStatus) { radioRsp_v1_3->rspInfo.error, {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR})); } - -/* - * Test IRadio.setSystemSelectionChannels() for the response returned. - * - * This test is excluded from manifest, due to non-implementation in Q. Tracked by b/130254624. - */ -TEST_P(RadioHidlTest_v1_3, setSystemSelectionChannels) { - serial = GetRandomSerialNumber(); - - RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN, - .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480}, - .channels = {1, 2}}; - - Return res = radio_v1_3->setSystemSelectionChannels(serial, true, {specifier}); - ASSERT_OK(res); - EXPECT_EQ(std::cv_status::no_timeout, wait()); - EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_3->rspInfo.type); - EXPECT_EQ(serial, radioRsp_v1_3->rspInfo.serial); - ALOGI("setSystemSelectionChannels, rspInfo.error = %s\n", - toString(radioRsp_v1_3->rspInfo.error).c_str()); - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_v1_3->rspInfo.error, - {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR})); - - if (radioRsp_v1_3->rspInfo.error == RadioError::NONE) { - Return res = radio_v1_3->setSystemSelectionChannels(serial, false, {specifier}); - ASSERT_OK(res); - EXPECT_EQ(std::cv_status::no_timeout, wait()); - EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_3->rspInfo.type); - EXPECT_EQ(serial, radioRsp_v1_3->rspInfo.serial); - ALOGI("setSystemSelectionChannels, rspInfo.error = %s\n", - toString(radioRsp_v1_3->rspInfo.error).c_str()); - EXPECT_EQ(RadioError::NONE, radioRsp_v1_3->rspInfo.error); - } -} \ No newline at end of file From 2801b037cda7614851a9a650d02f5dc833cfe0e7 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 31 Jan 2020 14:48:23 -0800 Subject: [PATCH 0523/1022] audio: Fix invalid BT A2DP interface name The correct name is: android.hardware.bluetooth.a2dp@1.0::IBluetoothAudioOffload Bug: 148648456 Bug: 148648729 Bug: 148648469 Bug: 148648355 Test: DeviceBootTest.DeviceBootTest#SELinuxUncheckedDenialBootTest Change-Id: I50d3486159f17697b06e9680b85586b1935a9ccc --- audio/common/all-versions/default/service/service.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp index 8fa4918c05..147d062204 100644 --- a/audio/common/all-versions/default/service/service.cpp +++ b/audio/common/all-versions/default/service/service.cpp @@ -92,7 +92,7 @@ int main(int /* argc */, char* /* argv */ []) { // remove the old HIDL when Bluetooth Audio Hal V2 has offloading supported { "Bluetooth Audio Offload API", - "android.hardware.a2dp@1.0::IBluetoothAudioOffload" + "android.hardware.bluetooth.a2dp@1.0::IBluetoothAudioOffload" } }; // clang-format on From 1845b8e5556a9f82060f15168e5f8d3a02a4b437 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Fri, 31 Jan 2020 16:53:04 -0800 Subject: [PATCH 0524/1022] Wifi: Improve documentation for some hidl APIs This commit improves some of the comments for the Wifi Hidl APIs. Bug: 148236141 Test: No test is done Change-Id: Iff6b191c8b258615ddaacad570b81f0ada968ed4 --- current.txt | 2 ++ wifi/1.2/IWifiStaIface.hal | 2 +- wifi/1.3/IWifiStaIface.hal | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/current.txt b/current.txt index 74c0cbbb5b..898a298f63 100644 --- a/current.txt +++ b/current.txt @@ -600,6 +600,8 @@ fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardwar a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface +ff5dd821c2c7a9c78607159c4d788960b725487263c49d956ca5fa3d37008b45 android.hardware.wifi@1.2::IWifiStaIface +5751f230e86a36111e7c5b995577cbf89d8df76c8e6c7641199198f3db3a93f7 android.hardware.wifi@1.3::IWifiStaIface # HALs released in Android R e966a3437d6a98d9d9e14e9d672088771716031900c0deb55a0946c751a03a44 android.hardware.audio@6.0::types diff --git a/wifi/1.2/IWifiStaIface.hal b/wifi/1.2/IWifiStaIface.hal index 3a7f7772c8..d65b33bb2b 100644 --- a/wifi/1.2/IWifiStaIface.hal +++ b/wifi/1.2/IWifiStaIface.hal @@ -23,7 +23,7 @@ import @1.0::IWifiStaIface; /** * Interface used to represent a single STA iface. * - * IWifiChip.createStaIface() may return a @1.2::IWifiStaIface when supported. + * IWifiChip.createStaIface() must return a @1.2::IWifiStaIface when supported. */ interface IWifiStaIface extends @1.0::IWifiStaIface { /** diff --git a/wifi/1.3/IWifiStaIface.hal b/wifi/1.3/IWifiStaIface.hal index 81c0c3869b..3a755090ae 100644 --- a/wifi/1.3/IWifiStaIface.hal +++ b/wifi/1.3/IWifiStaIface.hal @@ -23,7 +23,7 @@ import @1.2::IWifiStaIface; /** * Interface used to represent a single STA iface. * - * IWifiChip.createStaIface() may return a @1.3::IWifiStaIface when supported. + * IWifiChip.createStaIface() must return a @1.3::IWifiStaIface when supported. */ interface IWifiStaIface extends @1.2::IWifiStaIface { /** From 3559eb0e8bd345a3622dfb7608b04d7880329ba5 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Mon, 20 Jan 2020 12:27:27 -0800 Subject: [PATCH 0525/1022] drm: add 1.3 vts Bug: 139313724 Bug: 139134043 Change-Id: I54af955790e76dc364e7ff9f9d6984d9b6abbb68 --- drm/1.3/vts/OWNERS | 9 ++ drm/1.3/vts/functional/Android.bp | 78 ++++++++++ drm/1.3/vts/functional/drm_hal_test.cpp | 60 ++++++++ drm/1.3/vts/functional/drm_hal_test_main.cpp | 134 ++++++++++++++++++ .../hardware/drm/1.3/vts/drm_hal_test.h | 86 +++++++++++ 5 files changed, 367 insertions(+) create mode 100644 drm/1.3/vts/OWNERS create mode 100644 drm/1.3/vts/functional/Android.bp create mode 100644 drm/1.3/vts/functional/drm_hal_test.cpp create mode 100644 drm/1.3/vts/functional/drm_hal_test_main.cpp create mode 100644 drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h diff --git a/drm/1.3/vts/OWNERS b/drm/1.3/vts/OWNERS new file mode 100644 index 0000000000..3a0672e5c6 --- /dev/null +++ b/drm/1.3/vts/OWNERS @@ -0,0 +1,9 @@ +conglin@google.com +edwinwong@google.com +fredgc@google.com +jtinker@google.com +juce@google.com +kylealexander@google.com +rfrias@google.com +robertshih@google.com +sigquit@google.com diff --git a/drm/1.3/vts/functional/Android.bp b/drm/1.3/vts/functional/Android.bp new file mode 100644 index 0000000000..4be157584b --- /dev/null +++ b/drm/1.3/vts/functional/Android.bp @@ -0,0 +1,78 @@ +// +// 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. +// + +cc_library_static { + name: "android.hardware.drm@1.3-vts", + defaults: ["VtsHalTargetTestDefaults"], + local_include_dirs: [ + "include", + ], + srcs: [ + "drm_hal_test.cpp", + ], + shared_libs: [ + "android.hardware.drm@1.0", + "android.hardware.drm@1.1", + "android.hardware.drm@1.2", + "android.hardware.drm@1.3", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "libhidlmemory", + "libnativehelper", + ], + static_libs: [ + "android.hardware.drm@1.0-helper", + "libcrypto_static", + "libdrmvtshelper", + ], + export_include_dirs: [ + "include", + ], +} + +cc_test { + name: "VtsHalDrmV1_3TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + include_dirs: ["hardware/interfaces/drm/1.0/vts/functional"], + srcs: [ + "drm_hal_test_main.cpp", + ], + whole_static_libs: [ + "android.hardware.drm@1.0-vts", + "android.hardware.drm@1.1-vts", + "android.hardware.drm@1.2-vts", + "android.hardware.drm@1.3-vts", + ], + shared_libs: [ + "android.hardware.drm@1.0", + "android.hardware.drm@1.1", + "android.hardware.drm@1.2", + "android.hardware.drm@1.3", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "libhidlmemory", + "libnativehelper", + ], + static_libs: [ + "android.hardware.drm@1.0-helper", + "libcrypto_static", + "libdrmvtshelper", + ], + test_suites: [ + "general-tests", + "vts-core", + ], +} diff --git a/drm/1.3/vts/functional/drm_hal_test.cpp b/drm/1.3/vts/functional/drm_hal_test.cpp new file mode 100644 index 0000000000..738f5b28f6 --- /dev/null +++ b/drm/1.3/vts/functional/drm_hal_test.cpp @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#define LOG_TAG "drm_hal_test@1.3" + +#include "android/hardware/drm/1.3/vts/drm_hal_test.h" + +namespace android { +namespace hardware { +namespace drm { +namespace V1_3 { +namespace vts { + +TEST_P(DrmHalTestV1_3, SchemeSupported) { + EXPECT_TRUE(drmFactory_->isCryptoSchemeSupported(GetParam().scheme_)); +} + +TEST_P(DrmHalTestV1_3, SignRsaNotAllowed) { + hidl_array kWidevineUUID ({ + 0xED,0xEF,0x8B,0xA9,0x79,0xD6,0x4A,0xCE, + 0xA3,0xC8,0x27,0xDC,0xD5,0x1D,0x21,0xED + }); + + if (!drmFactory_->isCryptoSchemeSupported(kWidevineUUID)) { + GTEST_SKIP() << "Widevine only test"; + } + + // signRSA + const hidl_vec& sessionId{}; + const hidl_string& algorithm{}; + const hidl_vec& message{}; + const hidl_vec& wrappedKey{}; + auto res = drmPlugin_->signRSA( + sessionId, algorithm, message, wrappedKey, + [&](StatusV1_0 status, const hidl_vec& signature) { + EXPECT_EQ(status, StatusV1_0::ERROR_DRM_UNKNOWN); + EXPECT_EQ(signature.size(), 0); + } + ); + EXPECT_TRUE(res.isOk()); +} + +} // namespace vts +} // namespace V1_3 +} // namespace drm +} // namespace hardware +} // namespace android diff --git a/drm/1.3/vts/functional/drm_hal_test_main.cpp b/drm/1.3/vts/functional/drm_hal_test_main.cpp new file mode 100644 index 0000000000..02b45ea6b9 --- /dev/null +++ b/drm/1.3/vts/functional/drm_hal_test_main.cpp @@ -0,0 +1,134 @@ +/* + * 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. + */ + +/** + * Instantiate the set of test cases for each vendor module + */ + +#define LOG_TAG "drm_hal_test@1.3" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h" // V1_0 tests +#include "android/hardware/drm/1.0/vts/drm_hal_vendor_test.h" // V1_0 tests +#include "android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h" // V1_1 tests +#include "android/hardware/drm/1.2/vts/drm_hal_common.h" // V1_2 tests +#include "android/hardware/drm/1.3/vts/drm_hal_test.h" // V1_3 tests + +using drm_vts::DrmHalTestParam; +using drm_vts::PrintParamInstanceToString; + +using android::hardware::drm::V1_0::vts::DrmHalVendorFactoryTest; +using android::hardware::drm::V1_0::vts::DrmHalVendorPluginTest; +using android::hardware::drm::V1_0::vts::DrmHalVendorDecryptTest; +using android::hardware::drm::V1_0::vts::DrmHalClearkeyFactoryTest; +using android::hardware::drm::V1_0::vts::DrmHalClearkeyPluginTest; +using android::hardware::drm::V1_0::vts::DrmHalClearkeyDecryptTest; +using android::hardware::drm::V1_1::vts::DrmHalClearkeyTest; +using android::hardware::drm::V1_2::vts::DrmHalTest; +using android::hardware::drm::V1_2::vts::DrmHalClearkeyTestV1_2; +using android::hardware::drm::V1_3::vts::DrmHalTestV1_3; + +static const std::vector kAllInstances = [] { + using ::android::hardware::drm::V1_3::ICryptoFactory; + using ::android::hardware::drm::V1_3::IDrmFactory; + + std::vector drmInstances = + android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor); + std::vector cryptoInstances = + android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor); + std::set allInstances; + allInstances.insert(drmInstances.begin(), drmInstances.end()); + allInstances.insert(cryptoInstances.begin(), cryptoInstances.end()); + + std::vector allInstanceUuidCombos; + for (const auto &instance : allInstances) { + auto drmFactory = IDrmFactory::getService(instance); + if (drmFactory == nullptr) { + continue; + } + drmFactory->getSupportedCryptoSchemes( + [&](const hidl_vec>& schemes) { + for (const auto &scheme : schemes) { + allInstanceUuidCombos.push_back(DrmHalTestParam(instance, scheme)); + } + }); + } + return allInstanceUuidCombos; +}(); + +INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorFactoryTest, + testing::ValuesIn(kAllInstances), + drm_vts::PrintParamInstanceToString); +INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorPluginTest, + testing::ValuesIn(kAllInstances), + drm_vts::PrintParamInstanceToString); +INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorDecryptTest, + testing::ValuesIn(kAllInstances), + drm_vts::PrintParamInstanceToString); + +INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyFactoryTest, + testing::ValuesIn(kAllInstances), + drm_vts::PrintParamInstanceToString); +INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyPluginTest, + testing::ValuesIn(kAllInstances), + drm_vts::PrintParamInstanceToString); +INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyDecryptTest, + testing::ValuesIn(kAllInstances), + drm_vts::PrintParamInstanceToString); + +INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_1, DrmHalClearkeyTest, + testing::ValuesIn(kAllInstances), + PrintParamInstanceToString); + +INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_2, DrmHalTest, + testing::ValuesIn(kAllInstances), + PrintParamInstanceToString); +INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_2, DrmHalClearkeyTestV1_2, + testing::ValuesIn(kAllInstances), + PrintParamInstanceToString); + +INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_3, DrmHalTestV1_3, + testing::ValuesIn(kAllInstances), + PrintParamInstanceToString); + +int main(int argc, char** argv) { +#if defined(__LP64__) + const char* kModulePath = "/data/local/tmp/64/lib"; +#else + const char* kModulePath = "/data/local/tmp/32/lib"; +#endif + DrmHalTest::gVendorModules = new drm_vts::VendorModules(kModulePath); + if (DrmHalTest::gVendorModules->getPathList().size() == 0) { + std::cerr << "WARNING: No vendor modules found in " << kModulePath << + ", all vendor tests will be skipped" << std::endl; + } + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +} diff --git a/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h b/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h new file mode 100644 index 0000000000..d8f527764b --- /dev/null +++ b/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h @@ -0,0 +1,86 @@ +/* + * 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 DRM_HAL_TEST_V1_3_H +#define DRM_HAL_TEST_V1_3_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "drm_hal_vendor_module_api.h" +#include "drm_vts_helper.h" +#include "vendor_modules.h" +#include "VtsHalHidlTargetCallbackBase.h" + +namespace android { +namespace hardware { +namespace drm { +namespace V1_3 { +namespace vts { + +using android::hardware::hidl_array; +using android::hardware::hidl_string; + +using drm_vts::DrmHalTestParam; + +using IDrmFactoryV1_3 = android::hardware::drm::V1_3::IDrmFactory; +using IDrmPluginV1_0 = android::hardware::drm::V1_0::IDrmPlugin; +using StatusV1_0 = android::hardware::drm::V1_0::Status; + +class DrmHalTestV1_3 : public ::testing::TestWithParam { +public: + DrmHalTestV1_3() + : drmFactory_(IDrmFactoryV1_3::getService(GetParam().instance_)) {} + + virtual void SetUp() override { + ASSERT_NE(drmFactory_, nullptr); + + // create plugin + hidl_string packageName("android.hardware.drm.V1_3.vts"); + auto res = drmFactory_->createPlugin( + GetParam().scheme_, packageName, + [&](StatusV1_0 status, const sp& pluginV1_0) { + EXPECT_EQ(StatusV1_0::OK, status); + drmPlugin_ = pluginV1_0; + }); + EXPECT_TRUE(res.isOk()); + ASSERT_NE(drmPlugin_, nullptr); + } + + virtual void TearDown() override {} + +protected: + sp drmFactory_; + sp drmPlugin_; +}; + +} // namespace vts +} // namespace V1_3 +} // namespace drm +} // namespace hardware +} // namespace android + +#endif // DRM_HAL_TEST_V1_3_H From 08018dd92565e74c46e58aae91895edad761cc84 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Sat, 1 Feb 2020 11:29:20 -0800 Subject: [PATCH 0526/1022] rebootescrow: eliminate copy during read Instead of reading into a std::string, read directly into the std::vector of bytes This saves a copy and reduces memory overhead slightly. Test: atest VtsHalRebootEscrowTargetTest Bug: 148177693 Change-Id: I4dfe552f21394fb0891858b34a481b489dc3c684 --- rebootescrow/aidl/default/RebootEscrow.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rebootescrow/aidl/default/RebootEscrow.cpp b/rebootescrow/aidl/default/RebootEscrow.cpp index 5ae96f6086..dbc09215b3 100644 --- a/rebootescrow/aidl/default/RebootEscrow.cpp +++ b/rebootescrow/aidl/default/RebootEscrow.cpp @@ -55,13 +55,12 @@ ndk::ScopedAStatus RebootEscrow::retrieveKey(std::vector* _aidl_return) return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); } - std::string encodedString; - if (!::android::base::ReadFdToString(fd, &encodedString)) { - LOG(WARNING) << "Could not read device to string"; + std::vector encodedBytes(hadamard::OUTPUT_SIZE_BYTES); + if (!::android::base::ReadFully(fd, &encodedBytes[0], encodedBytes.size())) { + LOG(WARNING) << "Could not read device"; return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); } - std::vector encodedBytes(encodedString.begin(), encodedString.end()); auto keyBytes = hadamard::DecodeKey(encodedBytes); std::vector signedKeyBytes(keyBytes.begin(), keyBytes.end()); From b5fd31a128640a7309a45f2b03d9dbf33b4016d5 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Fri, 31 Jan 2020 14:08:05 -0800 Subject: [PATCH 0527/1022] Remove reference of VtsHalHidlTargetTestBase All grahpics composer HAL tests have been converted to parameterized gtest. Bug: 147894326 Test: atest VtsHalGraphicsComposerV2_1TargetTest \ VtsHalGraphicsComposerV2_2TargetTest \ VtsHalGraphicsComposerV2_3TargetTest \ VtsHalGraphicsComposerV2_4TargetTest Change-Id: I84515a5698035d7ceb299a5cc140ecd7bb28fe84 --- graphics/composer/2.1/utils/vts/Android.bp | 3 +-- graphics/composer/2.1/utils/vts/ComposerVts.cpp | 7 ------- graphics/composer/2.2/utils/vts/Android.bp | 3 +-- graphics/composer/2.2/utils/vts/ComposerVts.cpp | 1 - .../utils/vts/include/composer-vts/2.2/ComposerVts.h | 1 - .../utils/vts/include/composer-vts/2.2/ReadbackVts.h | 2 +- .../vts/include/composer-vts/2.2/RenderEngineVts.h | 2 -- graphics/composer/2.2/vts/functional/Android.bp | 10 +++++++--- .../VtsHalGraphicsComposerV2_2ReadbackTest.cpp | 2 +- graphics/composer/2.3/utils/vts/Android.bp | 1 + graphics/composer/2.3/utils/vts/ComposerVts.cpp | 7 ------- .../utils/vts/include/composer-vts/2.3/ComposerVts.h | 1 - graphics/composer/2.4/utils/vts/Android.bp | 2 +- graphics/composer/2.4/utils/vts/ComposerVts.cpp | 7 ------- .../utils/vts/include/composer-vts/2.4/ComposerVts.h | 1 - .../VtsHalGraphicsComposerV2_4TargetTest.cpp | 8 +++++--- 16 files changed, 18 insertions(+), 40 deletions(-) diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp index cdc0f35a41..3b0911f923 100644 --- a/graphics/composer/2.1/utils/vts/Android.bp +++ b/graphics/composer/2.1/utils/vts/Android.bp @@ -23,14 +23,13 @@ cc_library_static { "TestCommandReader.cpp", ], static_libs: [ - "VtsHalHidlTargetTestBase", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.mapper@2.0-vts", "android.hardware.graphics.mapper@3.0-vts", "android.hardware.graphics.mapper@4.0-vts", + "libgtest", ], export_static_lib_headers: [ - "VtsHalHidlTargetTestBase", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.mapper@2.0-vts", "android.hardware.graphics.mapper@3.0-vts", diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp index a8e1480d4f..4b6b7c86b8 100644 --- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp @@ -16,8 +16,6 @@ #include -#include - namespace android { namespace hardware { namespace graphics { @@ -25,11 +23,6 @@ namespace composer { namespace V2_1 { namespace vts { -Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService()) {} - -Composer::Composer(const std::string& name) - : Composer(::testing::VtsHalHidlTargetTestBase::getService(name)) {} - Composer::Composer(const sp& composer) : mComposer(composer) { // ASSERT_* can only be used in functions returning void. [this] { diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp index 5432882bea..a8bb1a22cb 100644 --- a/graphics/composer/2.2/utils/vts/Android.bp +++ b/graphics/composer/2.2/utils/vts/Android.bp @@ -26,11 +26,11 @@ cc_library_static { "libui", ], static_libs: [ - "VtsHalHidlTargetTestBase", "android.hardware.graphics.composer@2.1-vts", "android.hardware.graphics.composer@2.2", "android.hardware.graphics.mapper@2.1-vts", "libarect", + "libgtest", "libmath", "libnativewindow", "librenderengine", @@ -40,7 +40,6 @@ cc_library_static { "android.hardware.graphics.mapper@4.0-vts", ], export_static_lib_headers: [ - "VtsHalHidlTargetTestBase", "android.hardware.graphics.composer@2.1-vts", "android.hardware.graphics.composer@2.2", "android.hardware.graphics.mapper@2.1-vts", diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp index 93b67f0fcc..a526137c41 100644 --- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp @@ -16,7 +16,6 @@ #include -#include #include #include diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h index 5d22305020..6bc2732d7d 100644 --- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h +++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h index 7519a64b4f..d5eedf122c 100644 --- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h +++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h @@ -142,7 +142,7 @@ class TestBufferLayer : public TestLayer { const native_handle_t* mBufferHandle = nullptr; }; -class ReadbackHelper : public ::testing::VtsHalHidlTargetTestBase { +class ReadbackHelper { public: static std::string getColorModeString(ColorMode mode); diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h index b936cabb1e..4eb4bb7179 100644 --- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h +++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h @@ -24,8 +24,6 @@ #include #include -#include - namespace android { namespace hardware { namespace graphics { diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp index f987516a33..e38af00a38 100644 --- a/graphics/composer/2.2/vts/functional/Android.bp +++ b/graphics/composer/2.2/vts/functional/Android.bp @@ -19,7 +19,7 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: [ "VtsHalGraphicsComposerV2_2ReadbackTest.cpp", - "VtsHalGraphicsComposerV2_2TargetTest.cpp" + "VtsHalGraphicsComposerV2_2TargetTest.cpp", ], // TODO(b/64437680): Assume these libs are always available on the device. @@ -51,12 +51,16 @@ cc_test { "android.hardware.graphics.mapper@3.0-vts", "android.hardware.graphics.mapper@4.0", "android.hardware.graphics.mapper@4.0-vts", - "librenderengine" + "libgtest", + "librenderengine", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", "android.hardware.graphics.composer@2.2-command-buffer", ], disable_framework: true, - test_suites: ["general-tests", "vts-core"], + test_suites: [ + "general-tests", + "vts-core", + ], } diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp index 044bd9640e..cb43e64c81 100644 --- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp @@ -932,7 +932,7 @@ TEST_P(GraphicsCompositionTest, SetLayerZOrder) { class GraphicsBlendModeCompositionTest : public GraphicsCompositionTestBase, - public testing::WithParamInterface> { + public testing::WithParamInterface> { public: void SetUp() override { SetUpBase(std::get<0>(GetParam())); diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp index f65a9c41ae..3d81e8f647 100644 --- a/graphics/composer/2.3/utils/vts/Android.bp +++ b/graphics/composer/2.3/utils/vts/Android.bp @@ -23,6 +23,7 @@ cc_library_static { static_libs: [ "android.hardware.graphics.composer@2.2-vts", "android.hardware.graphics.composer@2.3", + "libgtest", ], export_static_lib_headers: [ "android.hardware.graphics.composer@2.2-vts", diff --git a/graphics/composer/2.3/utils/vts/ComposerVts.cpp b/graphics/composer/2.3/utils/vts/ComposerVts.cpp index d4f5b3a4de..d73a3b08b9 100644 --- a/graphics/composer/2.3/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.3/utils/vts/ComposerVts.cpp @@ -16,8 +16,6 @@ #include -#include - namespace android { namespace hardware { namespace graphics { @@ -27,11 +25,6 @@ namespace vts { using V2_1::Error; -Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService()) {} - -Composer::Composer(const std::string& name) - : Composer(::testing::VtsHalHidlTargetTestBase::getService(name)) {} - Composer::Composer(const sp& composer) : V2_2::vts::Composer(composer), mComposer(composer) {} diff --git a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h index e5ac842262..dae9ab42a2 100644 --- a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h +++ b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h @@ -19,7 +19,6 @@ #include #include -#include #include #include #include diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp index 673c15eb28..e42223d6eb 100644 --- a/graphics/composer/2.4/utils/vts/Android.bp +++ b/graphics/composer/2.4/utils/vts/Android.bp @@ -22,12 +22,12 @@ cc_library_static { "GraphicsComposerCallback.cpp", ], static_libs: [ - "VtsHalHidlTargetTestBase", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3-vts", "android.hardware.graphics.composer@2.3", "android.hardware.graphics.composer@2.4", + "libgtest", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp index 8cdc452be3..c5f3b5ed2f 100644 --- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp @@ -16,8 +16,6 @@ #include -#include - namespace android { namespace hardware { namespace graphics { @@ -27,11 +25,6 @@ namespace vts { using V2_4::Error; -Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService()) {} - -Composer::Composer(const std::string& name) - : Composer(::testing::VtsHalHidlTargetTestBase::getService(name)) {} - Composer::Composer(const sp& composer) : V2_3::vts::Composer(composer), mComposer(composer) {} diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h index 3dd8e500d6..fd59eb93cd 100644 --- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h @@ -19,7 +19,6 @@ #include #include -#include #include #include #include diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index f6b46ffd74..a7c3fd7b0c 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -42,6 +42,8 @@ namespace V2_4 { namespace vts { namespace { +using namespace std::chrono_literals; + using common::V1_0::BufferUsage; using common::V1_1::RenderIntent; using common::V1_2::ColorMode; @@ -526,7 +528,7 @@ TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyMode) { EXPECT_EQ(Error::UNSUPPORTED, mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false)); GTEST_SUCCEED() << "Auto Low Latency Mode is not supported on display " - << to_string(display) << ", skipping test"; + << std::to_string(display) << ", skipping test"; return; } @@ -580,7 +582,7 @@ void GraphicsComposerHidlTest::Test_setContentTypeForDisplay( if (!contentTypeSupport) { EXPECT_EQ(Error::UNSUPPORTED, mComposerClient->setContentType(display, contentType)); GTEST_SUCCEED() << contentTypeStr << " content type is not supported on display " - << to_string(display) << ", skipping test"; + << std::to_string(display) << ", skipping test"; return; } @@ -626,7 +628,7 @@ INSTANTIATE_TEST_SUITE_P( testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), android::hardware::PrintInstanceNameToString); -TEST_F(GraphicsComposerHidlCommandTest, getLayerGenericMetadataKeys) { +TEST_P(GraphicsComposerHidlCommandTest, getLayerGenericMetadataKeys) { std::vector keys; mComposerClient->getLayerGenericMetadataKeys(&keys); From 5dab7280b3758caff6252115a804be072792daa2 Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Tue, 21 Jan 2020 10:08:12 -0800 Subject: [PATCH 0528/1022] Camera: add webcam offline processing support Test: CTS/VTS in follow up changes Bug: 135142453 Change-Id: Ie95f22795f4807ed384443de0fffc65c5dde16d1 --- .../default/ExternalCameraDeviceSession.cpp | 596 +++--------------- .../3.4/default/ExternalCameraUtils.cpp | 547 +++++++++++++++- .../ExternalCameraDeviceSession.h | 225 +++---- .../ExternalCameraUtils.h | 147 ++++- .../default/ExternalCameraDeviceSession.cpp | 10 +- .../ExternalCameraDeviceSession.h | 118 ++-- camera/device/3.6/default/Android.bp | 1 + .../default/ExternalCameraDeviceSession.cpp | 275 +++++++- .../default/ExternalCameraOfflineSession.cpp | 554 ++++++++++++++++ .../ExternalCameraDeviceSession.h | 37 +- .../ExternalCameraOfflineSession.h | 232 +++++++ camera/provider/2.5/default/Android.bp | 9 +- 12 files changed, 2037 insertions(+), 714 deletions(-) create mode 100644 camera/device/3.6/default/ExternalCameraOfflineSession.cpp create mode 100644 camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp index 9ff0d74687..5f8674219c 100644 --- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp +++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp @@ -81,8 +81,6 @@ bool tryLock(std::mutex& mutex) return locked; } -buffer_handle_t sEmptyBuffer = nullptr; - } // Anonymous namespace // Static instances @@ -119,8 +117,8 @@ bool ExternalCameraDeviceSession::initialize() { std::string make, model; if (ret < 0) { ALOGW("%s v4l2 QUERYCAP failed", __FUNCTION__); - make = "Generic UVC webcam"; - model = "Generic UVC webcam"; + mExifMake = "Generic UVC webcam"; + mExifModel = "Generic UVC webcam"; } else { // capability.card is UTF-8 encoded char card[32]; @@ -134,11 +132,11 @@ bool ExternalCameraDeviceSession::initialize() { } } if (j == 0 || card[j - 1] != '\0') { - make = "Generic UVC webcam"; - model = "Generic UVC webcam"; + mExifMake = "Generic UVC webcam"; + mExifModel = "Generic UVC webcam"; } else { - make = card; - model = card; + mExifMake = card; + mExifModel = card; } } @@ -147,7 +145,7 @@ bool ExternalCameraDeviceSession::initialize() { ALOGE("%s: init OutputThread failed!", __FUNCTION__); return true; } - mOutputThread->setExifMakeModel(make, model); + mOutputThread->setExifMakeModel(mExifMake, mExifModel); status_t status = initDefaultRequests(); if (status != OK) { @@ -161,7 +159,7 @@ bool ExternalCameraDeviceSession::initialize() { ALOGE("%s: invalid request fmq", __FUNCTION__); return true; } - mResultMetadataQueue = std::make_shared( + mResultMetadataQueue = std::make_shared( kMetadataMsgQueueSize, false /* non blocking */); if (!mResultMetadataQueue->isValid()) { ALOGE("%s: invalid result fmq", __FUNCTION__); @@ -183,7 +181,7 @@ bool ExternalCameraDeviceSession::isInitFailed() { } void ExternalCameraDeviceSession::initOutputThread() { - mOutputThread = new OutputThread(this, mCroppingType); + mOutputThread = new OutputThread(this, mCroppingType, mCameraCharacteristics); } void ExternalCameraDeviceSession::closeOutputThread() { @@ -518,35 +516,9 @@ Status ExternalCameraDeviceSession::importBufferLocked(int32_t streamId, uint64_t bufId, buffer_handle_t buf, /*out*/buffer_handle_t** outBufPtr, bool allowEmptyBuf) { - - if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) { - if (allowEmptyBuf) { - *outBufPtr = &sEmptyBuffer; - return Status::OK; - } else { - ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); - return Status::ILLEGAL_ARGUMENT; - } - } - - CirculatingBuffers& cbs = mCirculatingBuffers[streamId]; - if (cbs.count(bufId) == 0) { - if (buf == nullptr) { - ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); - return Status::ILLEGAL_ARGUMENT; - } - // Register a newly seen buffer - buffer_handle_t importedBuf = buf; - sHandleImporter.importBuffer(importedBuf); - if (importedBuf == nullptr) { - ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId); - return Status::INTERNAL_ERROR; - } else { - cbs[bufId] = importedBuf; - } - } - *outBufPtr = &cbs[bufId]; - return Status::OK; + return importBufferImpl( + mCirculatingBuffers, sHandleImporter, streamId, + bufId, buf, outBufPtr, allowEmptyBuf); } Status ExternalCameraDeviceSession::importRequestLockedImpl( @@ -791,15 +763,32 @@ void ExternalCameraDeviceSession::notifyError( //TODO: refactor with processCaptureResult Status ExternalCameraDeviceSession::processCaptureRequestError( - const std::shared_ptr& req) { + const std::shared_ptr& req, + /*out*/std::vector* outMsgs, + /*out*/std::vector* outResults) { ATRACE_CALL(); // Return V4L2 buffer to V4L2 buffer queue - enqueueV4l2Frame(req->frameIn); + sp v4l2Frame = + static_cast(req->frameIn.get()); + enqueueV4l2Frame(v4l2Frame); - // NotifyShutter - notifyShutter(req->frameNumber, req->shutterTs); + if (outMsgs == nullptr) { + notifyShutter(req->frameNumber, req->shutterTs); + notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST); + } else { + NotifyMsg shutter; + shutter.type = MsgType::SHUTTER; + shutter.msg.shutter.frameNumber = req->frameNumber; + shutter.msg.shutter.timestamp = req->shutterTs; - notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST); + NotifyMsg error; + error.type = MsgType::ERROR; + error.msg.error.frameNumber = req->frameNumber; + error.msg.error.errorStreamId = -1; + error.msg.error.errorCode = ErrorCode::ERROR_REQUEST; + outMsgs->push_back(shutter); + outMsgs->push_back(error); + } // Fill output buffers hidl_vec results; @@ -826,16 +815,22 @@ Status ExternalCameraDeviceSession::processCaptureRequestError( mInflightFrames.erase(req->frameNumber); } - // Callback into framework - invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true); - freeReleaseFences(results); + if (outResults == nullptr) { + // Callback into framework + invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true); + freeReleaseFences(results); + } else { + outResults->push_back(result); + } return Status::OK; } Status ExternalCameraDeviceSession::processCaptureResult(std::shared_ptr& req) { ATRACE_CALL(); // Return V4L2 buffer to V4L2 buffer queue - enqueueV4l2Frame(req->frameIn); + sp v4l2Frame = + static_cast(req->frameIn.get()); + enqueueV4l2Frame(v4l2Frame); // NotifyShutter notifyShutter(req->frameNumber, req->shutterTs); @@ -923,29 +918,10 @@ void ExternalCameraDeviceSession::invokeProcessCaptureResultCallback( mProcessCaptureResultLock.unlock(); } -void ExternalCameraDeviceSession::freeReleaseFences(hidl_vec& results) { - for (auto& result : results) { - if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) { - native_handle_t* handle = const_cast( - result.inputBuffer.releaseFence.getNativeHandle()); - native_handle_close(handle); - native_handle_delete(handle); - } - for (auto& buf : result.outputBuffers) { - if (buf.releaseFence.getNativeHandle() != nullptr) { - native_handle_t* handle = const_cast( - buf.releaseFence.getNativeHandle()); - native_handle_close(handle); - native_handle_delete(handle); - } - } - } - return; -} - ExternalCameraDeviceSession::OutputThread::OutputThread( - wp parent, - CroppingType ct) : mParent(parent), mCroppingType(ct) {} + wp parent, CroppingType ct, + const common::V1_0::helper::CameraMetadata& chars) : + mParent(parent), mCroppingType(ct), mCameraCharacteristics(chars) {} ExternalCameraDeviceSession::OutputThread::~OutputThread() {} @@ -955,88 +931,6 @@ void ExternalCameraDeviceSession::OutputThread::setExifMakeModel( mExifModel = model; } -uint32_t ExternalCameraDeviceSession::OutputThread::getFourCcFromLayout( - const YCbCrLayout& layout) { - intptr_t cb = reinterpret_cast(layout.cb); - intptr_t cr = reinterpret_cast(layout.cr); - if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) { - // Interleaved format - if (layout.cb > layout.cr) { - return V4L2_PIX_FMT_NV21; - } else { - return V4L2_PIX_FMT_NV12; - } - } else if (layout.chromaStep == 1) { - // Planar format - if (layout.cb > layout.cr) { - return V4L2_PIX_FMT_YVU420; // YV12 - } else { - return V4L2_PIX_FMT_YUV420; // YU12 - } - } else { - return FLEX_YUV_GENERIC; - } -} - -int ExternalCameraDeviceSession::OutputThread::getCropRect( - CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) { - if (out == nullptr) { - ALOGE("%s: out is null", __FUNCTION__); - return -1; - } - - uint32_t inW = inSize.width; - uint32_t inH = inSize.height; - uint32_t outW = outSize.width; - uint32_t outH = outSize.height; - - // Handle special case where aspect ratio is close to input but scaled - // dimension is slightly larger than input - float arIn = ASPECT_RATIO(inSize); - float arOut = ASPECT_RATIO(outSize); - if (isAspectRatioClose(arIn, arOut)) { - out->left = 0; - out->top = 0; - out->width = inW; - out->height = inH; - return 0; - } - - if (ct == VERTICAL) { - uint64_t scaledOutH = static_cast(outH) * inW / outW; - if (scaledOutH > inH) { - ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d", - __FUNCTION__, outW, outH, inW, inH); - return -1; - } - scaledOutH = scaledOutH & ~0x1; // make it multiple of 2 - - out->left = 0; - out->top = ((inH - scaledOutH) / 2) & ~0x1; - out->width = inW; - out->height = static_cast(scaledOutH); - ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d", - __FUNCTION__, inW, inH, outW, outH, out->top, static_cast(scaledOutH)); - } else { - uint64_t scaledOutW = static_cast(outW) * inH / outH; - if (scaledOutW > inW) { - ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d", - __FUNCTION__, outW, outH, inW, inH); - return -1; - } - scaledOutW = scaledOutW & ~0x1; // make it multiple of 2 - - out->left = ((inW - scaledOutW) / 2) & ~0x1; - out->top = 0; - out->width = static_cast(scaledOutW); - out->height = inH; - ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d", - __FUNCTION__, inW, inH, outW, outH, out->top, static_cast(scaledOutW)); - } - - return 0; -} - int ExternalCameraDeviceSession::OutputThread::cropAndScaleLocked( sp& in, const Size& outSz, YCbCrLayout* out) { Size inSz = {in->mWidth, in->mHeight}; @@ -1274,265 +1168,6 @@ int ExternalCameraDeviceSession::OutputThread::cropAndScaleThumbLocked( return 0; } -int ExternalCameraDeviceSession::OutputThread::formatConvertLocked( - const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) { - int ret = 0; - switch (format) { - case V4L2_PIX_FMT_NV21: - ret = libyuv::I420ToNV21( - static_cast(in.y), - in.yStride, - static_cast(in.cb), - in.cStride, - static_cast(in.cr), - in.cStride, - static_cast(out.y), - out.yStride, - static_cast(out.cr), - out.cStride, - sz.width, - sz.height); - if (ret != 0) { - ALOGE("%s: convert to NV21 buffer failed! ret %d", - __FUNCTION__, ret); - return ret; - } - break; - case V4L2_PIX_FMT_NV12: - ret = libyuv::I420ToNV12( - static_cast(in.y), - in.yStride, - static_cast(in.cb), - in.cStride, - static_cast(in.cr), - in.cStride, - static_cast(out.y), - out.yStride, - static_cast(out.cb), - out.cStride, - sz.width, - sz.height); - if (ret != 0) { - ALOGE("%s: convert to NV12 buffer failed! ret %d", - __FUNCTION__, ret); - return ret; - } - break; - case V4L2_PIX_FMT_YVU420: // YV12 - case V4L2_PIX_FMT_YUV420: // YU12 - // TODO: maybe we can speed up here by somehow save this copy? - ret = libyuv::I420Copy( - static_cast(in.y), - in.yStride, - static_cast(in.cb), - in.cStride, - static_cast(in.cr), - in.cStride, - static_cast(out.y), - out.yStride, - static_cast(out.cb), - out.cStride, - static_cast(out.cr), - out.cStride, - sz.width, - sz.height); - if (ret != 0) { - ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d", - __FUNCTION__, ret); - return ret; - } - break; - case FLEX_YUV_GENERIC: - // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow. - ALOGE("%s: unsupported flexible yuv layout" - " y %p cb %p cr %p y_str %d c_str %d c_step %d", - __FUNCTION__, out.y, out.cb, out.cr, - out.yStride, out.cStride, out.chromaStep); - return -1; - default: - ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format); - return -1; - } - return 0; -} - -int ExternalCameraDeviceSession::OutputThread::encodeJpegYU12( - const Size & inSz, const YCbCrLayout& inLayout, - int jpegQuality, const void *app1Buffer, size_t app1Size, - void *out, const size_t maxOutSize, size_t &actualCodeSize) -{ - /* libjpeg is a C library so we use C-style "inheritance" by - * putting libjpeg's jpeg_destination_mgr first in our custom - * struct. This allows us to cast jpeg_destination_mgr* to - * CustomJpegDestMgr* when we get it passed to us in a callback */ - struct CustomJpegDestMgr { - struct jpeg_destination_mgr mgr; - JOCTET *mBuffer; - size_t mBufferSize; - size_t mEncodedSize; - bool mSuccess; - } dmgr; - - jpeg_compress_struct cinfo = {}; - jpeg_error_mgr jerr; - - /* Initialize error handling with standard callbacks, but - * then override output_message (to print to ALOG) and - * error_exit to set a flag and print a message instead - * of killing the whole process */ - cinfo.err = jpeg_std_error(&jerr); - - cinfo.err->output_message = [](j_common_ptr cinfo) { - char buffer[JMSG_LENGTH_MAX]; - - /* Create the message */ - (*cinfo->err->format_message)(cinfo, buffer); - ALOGE("libjpeg error: %s", buffer); - }; - cinfo.err->error_exit = [](j_common_ptr cinfo) { - (*cinfo->err->output_message)(cinfo); - if(cinfo->client_data) { - auto & dmgr = - *reinterpret_cast(cinfo->client_data); - dmgr.mSuccess = false; - } - }; - /* Now that we initialized some callbacks, let's create our compressor */ - jpeg_create_compress(&cinfo); - - /* Initialize our destination manager */ - dmgr.mBuffer = static_cast(out); - dmgr.mBufferSize = maxOutSize; - dmgr.mEncodedSize = 0; - dmgr.mSuccess = true; - cinfo.client_data = static_cast(&dmgr); - - /* These lambdas become C-style function pointers and as per C++11 spec - * may not capture anything */ - dmgr.mgr.init_destination = [](j_compress_ptr cinfo) { - auto & dmgr = reinterpret_cast(*cinfo->dest); - dmgr.mgr.next_output_byte = dmgr.mBuffer; - dmgr.mgr.free_in_buffer = dmgr.mBufferSize; - ALOGV("%s:%d jpeg start: %p [%zu]", - __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize); - }; - - dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) { - ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__); - return 0; - }; - - dmgr.mgr.term_destination = [](j_compress_ptr cinfo) { - auto & dmgr = reinterpret_cast(*cinfo->dest); - dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer; - ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize); - }; - cinfo.dest = reinterpret_cast(&dmgr); - - /* We are going to be using JPEG in raw data mode, so we are passing - * straight subsampled planar YCbCr and it will not touch our pixel - * data or do any scaling or anything */ - cinfo.image_width = inSz.width; - cinfo.image_height = inSz.height; - cinfo.input_components = 3; - cinfo.in_color_space = JCS_YCbCr; - - /* Initialize defaults and then override what we want */ - jpeg_set_defaults(&cinfo); - - jpeg_set_quality(&cinfo, jpegQuality, 1); - jpeg_set_colorspace(&cinfo, JCS_YCbCr); - cinfo.raw_data_in = 1; - cinfo.dct_method = JDCT_IFAST; - - /* Configure sampling factors. The sampling factor is JPEG subsampling 420 - * because the source format is YUV420. Note that libjpeg sampling factors - * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and - * 1 V value for each 2 Y values */ - cinfo.comp_info[0].h_samp_factor = 2; - cinfo.comp_info[0].v_samp_factor = 2; - cinfo.comp_info[1].h_samp_factor = 1; - cinfo.comp_info[1].v_samp_factor = 1; - cinfo.comp_info[2].h_samp_factor = 1; - cinfo.comp_info[2].v_samp_factor = 1; - - /* Let's not hardcode YUV420 in 6 places... 5 was enough */ - int maxVSampFactor = std::max( { - cinfo.comp_info[0].v_samp_factor, - cinfo.comp_info[1].v_samp_factor, - cinfo.comp_info[2].v_samp_factor - }); - int cVSubSampling = cinfo.comp_info[0].v_samp_factor / - cinfo.comp_info[1].v_samp_factor; - - /* Start the compressor */ - jpeg_start_compress(&cinfo, TRUE); - - /* Compute our macroblock height, so we can pad our input to be vertically - * macroblock aligned. - * TODO: Does it need to be horizontally MCU aligned too? */ - - size_t mcuV = DCTSIZE*maxVSampFactor; - size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV); - - /* libjpeg uses arrays of row pointers, which makes it really easy to pad - * data vertically (unfortunately doesn't help horizontally) */ - std::vector yLines (paddedHeight); - std::vector cbLines(paddedHeight/cVSubSampling); - std::vector crLines(paddedHeight/cVSubSampling); - - uint8_t *py = static_cast(inLayout.y); - uint8_t *pcr = static_cast(inLayout.cr); - uint8_t *pcb = static_cast(inLayout.cb); - - for(uint32_t i = 0; i < paddedHeight; i++) - { - /* Once we are in the padding territory we still point to the last line - * effectively replicating it several times ~ CLAMP_TO_EDGE */ - int li = std::min(i, inSz.height - 1); - yLines[i] = static_cast(py + li * inLayout.yStride); - if(i < paddedHeight / cVSubSampling) - { - crLines[i] = static_cast(pcr + li * inLayout.cStride); - cbLines[i] = static_cast(pcb + li * inLayout.cStride); - } - } - - /* If APP1 data was passed in, use it */ - if(app1Buffer && app1Size) - { - jpeg_write_marker(&cinfo, JPEG_APP0 + 1, - static_cast(app1Buffer), app1Size); - } - - /* While we still have padded height left to go, keep giving it one - * macroblock at a time. */ - while (cinfo.next_scanline < cinfo.image_height) { - const uint32_t batchSize = DCTSIZE * maxVSampFactor; - const uint32_t nl = cinfo.next_scanline; - JSAMPARRAY planes[3]{ &yLines[nl], - &cbLines[nl/cVSubSampling], - &crLines[nl/cVSubSampling] }; - - uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize); - - if (done != batchSize) { - ALOGE("%s: compressed %u lines, expected %u (total %u/%u)", - __FUNCTION__, done, batchSize, cinfo.next_scanline, - cinfo.image_height); - return -1; - } - } - - /* This will flush everything */ - jpeg_finish_compress(&cinfo); - - /* Grab the actual code size and set it */ - actualCodeSize = dmgr.mEncodedSize; - - return 0; -} - /* * TODO: There needs to be a mechanism to discover allocated buffer size * in the HAL. @@ -1555,25 +1190,9 @@ Size ExternalCameraDeviceSession::getMaxJpegResolution() const { } Size ExternalCameraDeviceSession::getMaxThumbResolution() const { - Size thumbSize { 0, 0 }; - camera_metadata_ro_entry entry = - mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES); - for(uint32_t i = 0; i < entry.count; i += 2) { - Size sz { static_cast(entry.data.i32[i]), - static_cast(entry.data.i32[i+1]) }; - if(sz.width * sz.height > thumbSize.width * thumbSize.height) { - thumbSize = sz; - } - } - - if (thumbSize.width * thumbSize.height == 0) { - ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__); - } - - return thumbSize; + return getMaxThumbnailResolution(mCameraCharacteristics); } - ssize_t ExternalCameraDeviceSession::getJpegBufferSize( uint32_t width, uint32_t height) const { // Constant from camera3.h @@ -1616,7 +1235,7 @@ ssize_t ExternalCameraDeviceSession::getJpegBufferSize( int ExternalCameraDeviceSession::OutputThread::createJpegLocked( HalStreamBuffer &halBuf, - const std::shared_ptr& req) + const common::V1_0::helper::CameraMetadata& setting) { ATRACE_CALL(); int ret; @@ -1645,17 +1264,17 @@ int ExternalCameraDeviceSession::OutputThread::createJpegLocked( Size thumbSize; bool outputThumbnail = true; - if (req->setting.exists(ANDROID_JPEG_QUALITY)) { - camera_metadata_entry entry = - req->setting.find(ANDROID_JPEG_QUALITY); + if (setting.exists(ANDROID_JPEG_QUALITY)) { + camera_metadata_ro_entry entry = + setting.find(ANDROID_JPEG_QUALITY); jpegQuality = entry.data.u8[0]; } else { return lfail("%s: ANDROID_JPEG_QUALITY not set",__FUNCTION__); } - if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) { - camera_metadata_entry entry = - req->setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY); + if (setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) { + camera_metadata_ro_entry entry = + setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY); thumbQuality = entry.data.u8[0]; } else { return lfail( @@ -1663,9 +1282,9 @@ int ExternalCameraDeviceSession::OutputThread::createJpegLocked( __FUNCTION__); } - if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) { - camera_metadata_entry entry = - req->setting.find(ANDROID_JPEG_THUMBNAIL_SIZE); + if (setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) { + camera_metadata_ro_entry entry = + setting.find(ANDROID_JPEG_THUMBNAIL_SIZE); thumbSize = Size { static_cast(entry.data.i32[0]), static_cast(entry.data.i32[1]) }; @@ -1732,8 +1351,8 @@ int ExternalCameraDeviceSession::OutputThread::createJpegLocked( /* Combine camera characteristics with request settings to form EXIF * metadata */ - common::V1_0::helper::CameraMetadata meta(parent->mCameraCharacteristics); - meta.append(req->setting); + common::V1_0::helper::CameraMetadata meta(mCameraCharacteristics); + meta.append(setting); /* Generate EXIF object */ std::unique_ptr utils(ExifUtils::create()); @@ -1838,7 +1457,7 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { // TODO: see if we can save some computation by converting to YV12 here uint8_t* inData; size_t inDataSize; - if (req->frameIn->map(&inData, &inDataSize) != 0) { + if (req->frameIn->getData(&inData, &inDataSize) != 0) { lk.unlock(); return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__); } @@ -1899,7 +1518,7 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { // Gralloc lockYCbCr the buffer switch (halBuf.format) { case PixelFormat::BLOB: { - int ret = createJpegLocked(halBuf, req); + int ret = createJpegLocked(halBuf, req->setting); if(ret != 0) { lk.unlock(); @@ -1949,8 +1568,8 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { } Size sz {halBuf.width, halBuf.height}; - ATRACE_BEGIN("formatConvertLocked"); - ret = formatConvertLocked(cropAndScaled, outLayout, sz, outputFourcc); + ATRACE_BEGIN("formatConvert"); + ret = formatConvert(cropAndScaled, outLayout, sz, outputFourcc); ATRACE_END(); if (ret != 0) { lk.unlock(); @@ -2055,6 +1674,14 @@ Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers( return Status::OK; } +void ExternalCameraDeviceSession::OutputThread::clearIntermediateBuffers() { + std::lock_guard lk(mBufferLock); + mYu12Frame.clear(); + mYu12ThumbFrame.clear(); + mIntermediateBuffers.clear(); + mBlobBufferSize = 0; +} + Status ExternalCameraDeviceSession::OutputThread::submitRequest( const std::shared_ptr& req) { std::unique_lock lk(mRequestListLock); @@ -2090,6 +1717,32 @@ void ExternalCameraDeviceSession::OutputThread::flush() { } } +std::list> +ExternalCameraDeviceSession::OutputThread::switchToOffline() { + ATRACE_CALL(); + std::list> emptyList; + auto parent = mParent.promote(); + if (parent == nullptr) { + ALOGE("%s: session has been disconnected!", __FUNCTION__); + return emptyList; + } + + std::unique_lock lk(mRequestListLock); + std::list> reqs = std::move(mRequestList); + mRequestList.clear(); + if (mProcessingRequest) { + std::chrono::seconds timeout = std::chrono::seconds(kFlushWaitTimeoutSec); + auto st = mRequestDoneCond.wait_for(lk, timeout); + if (st == std::cv_status::timeout) { + ALOGE("%s: wait for inflight request finish timeout!", __FUNCTION__); + } + } + lk.unlock(); + clearIntermediateBuffers(); + ALOGV("%s: returning %zu request for offline processing", __FUNCTION__, reqs.size()); + return reqs; +} + void ExternalCameraDeviceSession::OutputThread::waitForNextRequest( std::shared_ptr* out) { ATRACE_CALL(); @@ -2733,6 +2386,7 @@ Status ExternalCameraDeviceSession::configureStreams( return Status::INTERNAL_ERROR; } + mBlobBufferSize = blobBufferSize; status = mOutputThread->allocateIntermediateBuffers(v4lSize, mMaxThumbResolution, config.streams, blobBufferSize); if (status != Status::OK) { @@ -2916,16 +2570,6 @@ status_t ExternalCameraDeviceSession::initDefaultRequests() { status_t ExternalCameraDeviceSession::fillCaptureResult( common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) { - // android.control - // For USB camera, we don't know the AE state. Set the state to converged to - // indicate the frame should be good to use. Then apps don't have to wait the - // AE state. - const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED; - UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1); - - const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF; - UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1); - bool afTrigger = false; { std::lock_guard lk(mAfTriggerLock); @@ -2951,46 +2595,10 @@ status_t ExternalCameraDeviceSession::fillCaptureResult( } UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1); - // Set AWB state to converged to indicate the frame should be good to use. - const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED; - UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1); + camera_metadata_ro_entry activeArraySize = + mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE); - const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF; - UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1); - - camera_metadata_ro_entry active_array_size = - mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE); - - if (active_array_size.count == 0) { - ALOGE("%s: cannot find active array size!", __FUNCTION__); - return -EINVAL; - } - - const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE; - UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1); - - // This means pipeline latency of X frame intervals. The maximum number is 4. - const uint8_t requestPipelineMaxDepth = 4; - UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1); - - // android.scaler - const int32_t crop_region[] = { - active_array_size.data.i32[0], active_array_size.data.i32[1], - active_array_size.data.i32[2], active_array_size.data.i32[3], - }; - UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region)); - - // android.sensor - UPDATE(md, ANDROID_SENSOR_TIMESTAMP, ×tamp, 1); - - // android.statistics - const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF; - UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1); - - const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE; - UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1); - - return OK; + return fillCaptureResultCommon(md, timestamp, activeArraySize); } #undef ARRAY_SIZE diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp index e25deff797..4a6381ea7b 100644 --- a/camera/device/3.4/default/ExternalCameraUtils.cpp +++ b/camera/device/3.4/default/ExternalCameraUtils.cpp @@ -18,10 +18,23 @@ #include #include +#include #include #include + +#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs +#include + +#include + #include "ExternalCameraUtils.h" +namespace { + +buffer_handle_t sEmptyBuffer = nullptr; + +} // Anonymous namespace + namespace android { namespace hardware { namespace camera { @@ -29,10 +42,13 @@ namespace device { namespace V3_4 { namespace implementation { +Frame::Frame(uint32_t width, uint32_t height, uint32_t fourcc) : + mWidth(width), mHeight(height), mFourcc(fourcc) {} + V4L2Frame::V4L2Frame( uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd, uint32_t dataSize, uint64_t offset) : - mWidth(w), mHeight(h), mFourcc(fourcc), + Frame(w, h, fourcc), mBufferIndex(bufIdx), mFd(fd), mDataSize(dataSize), mOffset(offset) {} int V4L2Frame::map(uint8_t** data, size_t* dataSize) { @@ -75,9 +91,13 @@ V4L2Frame::~V4L2Frame() { unmap(); } +int V4L2Frame::getData(uint8_t** outData, size_t* dataSize) { + return map(outData, dataSize); +} + AllocatedFrame::AllocatedFrame( uint32_t w, uint32_t h) : - mWidth(w), mHeight(h), mFourcc(V4L2_PIX_FMT_YUV420) {}; + Frame(w, h, V4L2_PIX_FMT_YUV420) {}; AllocatedFrame::~AllocatedFrame() {} @@ -106,6 +126,17 @@ int AllocatedFrame::allocate(YCbCrLayout* out) { return 0; } +int AllocatedFrame::getData(uint8_t** outData, size_t* dataSize) { + YCbCrLayout layout; + int ret = allocate(&layout); + if (ret != 0) { + return ret; + } + *outData = mData.data(); + *dataSize = mData.size(); + return 0; +} + int AllocatedFrame::getLayout(YCbCrLayout* out) { IMapper::Rect noCrop = {0, 0, static_cast(mWidth), @@ -150,8 +181,520 @@ double SupportedV4L2Format::FrameRate::getDouble() const { return durationDenominator / static_cast(durationNumerator); } +::android::hardware::camera::common::V1_0::Status importBufferImpl( + /*inout*/std::map& circulatingBuffers, + /*inout*/HandleImporter& handleImporter, + int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf) { + using ::android::hardware::camera::common::V1_0::Status; + if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) { + if (allowEmptyBuf) { + *outBufPtr = &sEmptyBuffer; + return Status::OK; + } else { + ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); + return Status::ILLEGAL_ARGUMENT; + } + } + + CirculatingBuffers& cbs = circulatingBuffers[streamId]; + if (cbs.count(bufId) == 0) { + if (buf == nullptr) { + ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); + return Status::ILLEGAL_ARGUMENT; + } + // Register a newly seen buffer + buffer_handle_t importedBuf = buf; + handleImporter.importBuffer(importedBuf); + if (importedBuf == nullptr) { + ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId); + return Status::INTERNAL_ERROR; + } else { + cbs[bufId] = importedBuf; + } + } + *outBufPtr = &cbs[bufId]; + return Status::OK; +} + +uint32_t getFourCcFromLayout(const YCbCrLayout& layout) { + intptr_t cb = reinterpret_cast(layout.cb); + intptr_t cr = reinterpret_cast(layout.cr); + if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) { + // Interleaved format + if (layout.cb > layout.cr) { + return V4L2_PIX_FMT_NV21; + } else { + return V4L2_PIX_FMT_NV12; + } + } else if (layout.chromaStep == 1) { + // Planar format + if (layout.cb > layout.cr) { + return V4L2_PIX_FMT_YVU420; // YV12 + } else { + return V4L2_PIX_FMT_YUV420; // YU12 + } + } else { + return FLEX_YUV_GENERIC; + } +} + +int getCropRect( + CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) { + if (out == nullptr) { + ALOGE("%s: out is null", __FUNCTION__); + return -1; + } + + uint32_t inW = inSize.width; + uint32_t inH = inSize.height; + uint32_t outW = outSize.width; + uint32_t outH = outSize.height; + + // Handle special case where aspect ratio is close to input but scaled + // dimension is slightly larger than input + float arIn = ASPECT_RATIO(inSize); + float arOut = ASPECT_RATIO(outSize); + if (isAspectRatioClose(arIn, arOut)) { + out->left = 0; + out->top = 0; + out->width = inW; + out->height = inH; + return 0; + } + + if (ct == VERTICAL) { + uint64_t scaledOutH = static_cast(outH) * inW / outW; + if (scaledOutH > inH) { + ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d", + __FUNCTION__, outW, outH, inW, inH); + return -1; + } + scaledOutH = scaledOutH & ~0x1; // make it multiple of 2 + + out->left = 0; + out->top = ((inH - scaledOutH) / 2) & ~0x1; + out->width = inW; + out->height = static_cast(scaledOutH); + ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d", + __FUNCTION__, inW, inH, outW, outH, out->top, static_cast(scaledOutH)); + } else { + uint64_t scaledOutW = static_cast(outW) * inH / outH; + if (scaledOutW > inW) { + ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d", + __FUNCTION__, outW, outH, inW, inH); + return -1; + } + scaledOutW = scaledOutW & ~0x1; // make it multiple of 2 + + out->left = ((inW - scaledOutW) / 2) & ~0x1; + out->top = 0; + out->width = static_cast(scaledOutW); + out->height = inH; + ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d", + __FUNCTION__, inW, inH, outW, outH, out->top, static_cast(scaledOutW)); + } + + return 0; +} + +int formatConvert( + const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) { + int ret = 0; + switch (format) { + case V4L2_PIX_FMT_NV21: + ret = libyuv::I420ToNV21( + static_cast(in.y), + in.yStride, + static_cast(in.cb), + in.cStride, + static_cast(in.cr), + in.cStride, + static_cast(out.y), + out.yStride, + static_cast(out.cr), + out.cStride, + sz.width, + sz.height); + if (ret != 0) { + ALOGE("%s: convert to NV21 buffer failed! ret %d", + __FUNCTION__, ret); + return ret; + } + break; + case V4L2_PIX_FMT_NV12: + ret = libyuv::I420ToNV12( + static_cast(in.y), + in.yStride, + static_cast(in.cb), + in.cStride, + static_cast(in.cr), + in.cStride, + static_cast(out.y), + out.yStride, + static_cast(out.cb), + out.cStride, + sz.width, + sz.height); + if (ret != 0) { + ALOGE("%s: convert to NV12 buffer failed! ret %d", + __FUNCTION__, ret); + return ret; + } + break; + case V4L2_PIX_FMT_YVU420: // YV12 + case V4L2_PIX_FMT_YUV420: // YU12 + // TODO: maybe we can speed up here by somehow save this copy? + ret = libyuv::I420Copy( + static_cast(in.y), + in.yStride, + static_cast(in.cb), + in.cStride, + static_cast(in.cr), + in.cStride, + static_cast(out.y), + out.yStride, + static_cast(out.cb), + out.cStride, + static_cast(out.cr), + out.cStride, + sz.width, + sz.height); + if (ret != 0) { + ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d", + __FUNCTION__, ret); + return ret; + } + break; + case FLEX_YUV_GENERIC: + // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow. + ALOGE("%s: unsupported flexible yuv layout" + " y %p cb %p cr %p y_str %d c_str %d c_step %d", + __FUNCTION__, out.y, out.cb, out.cr, + out.yStride, out.cStride, out.chromaStep); + return -1; + default: + ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format); + return -1; + } + return 0; +} + +int encodeJpegYU12( + const Size & inSz, const YCbCrLayout& inLayout, + int jpegQuality, const void *app1Buffer, size_t app1Size, + void *out, const size_t maxOutSize, size_t &actualCodeSize) +{ + /* libjpeg is a C library so we use C-style "inheritance" by + * putting libjpeg's jpeg_destination_mgr first in our custom + * struct. This allows us to cast jpeg_destination_mgr* to + * CustomJpegDestMgr* when we get it passed to us in a callback */ + struct CustomJpegDestMgr { + struct jpeg_destination_mgr mgr; + JOCTET *mBuffer; + size_t mBufferSize; + size_t mEncodedSize; + bool mSuccess; + } dmgr; + + jpeg_compress_struct cinfo = {}; + jpeg_error_mgr jerr; + + /* Initialize error handling with standard callbacks, but + * then override output_message (to print to ALOG) and + * error_exit to set a flag and print a message instead + * of killing the whole process */ + cinfo.err = jpeg_std_error(&jerr); + + cinfo.err->output_message = [](j_common_ptr cinfo) { + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message)(cinfo, buffer); + ALOGE("libjpeg error: %s", buffer); + }; + cinfo.err->error_exit = [](j_common_ptr cinfo) { + (*cinfo->err->output_message)(cinfo); + if(cinfo->client_data) { + auto & dmgr = + *reinterpret_cast(cinfo->client_data); + dmgr.mSuccess = false; + } + }; + /* Now that we initialized some callbacks, let's create our compressor */ + jpeg_create_compress(&cinfo); + + /* Initialize our destination manager */ + dmgr.mBuffer = static_cast(out); + dmgr.mBufferSize = maxOutSize; + dmgr.mEncodedSize = 0; + dmgr.mSuccess = true; + cinfo.client_data = static_cast(&dmgr); + + /* These lambdas become C-style function pointers and as per C++11 spec + * may not capture anything */ + dmgr.mgr.init_destination = [](j_compress_ptr cinfo) { + auto & dmgr = reinterpret_cast(*cinfo->dest); + dmgr.mgr.next_output_byte = dmgr.mBuffer; + dmgr.mgr.free_in_buffer = dmgr.mBufferSize; + ALOGV("%s:%d jpeg start: %p [%zu]", + __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize); + }; + + dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) { + ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__); + return 0; + }; + + dmgr.mgr.term_destination = [](j_compress_ptr cinfo) { + auto & dmgr = reinterpret_cast(*cinfo->dest); + dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer; + ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize); + }; + cinfo.dest = reinterpret_cast(&dmgr); + + /* We are going to be using JPEG in raw data mode, so we are passing + * straight subsampled planar YCbCr and it will not touch our pixel + * data or do any scaling or anything */ + cinfo.image_width = inSz.width; + cinfo.image_height = inSz.height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_YCbCr; + + /* Initialize defaults and then override what we want */ + jpeg_set_defaults(&cinfo); + + jpeg_set_quality(&cinfo, jpegQuality, 1); + jpeg_set_colorspace(&cinfo, JCS_YCbCr); + cinfo.raw_data_in = 1; + cinfo.dct_method = JDCT_IFAST; + + /* Configure sampling factors. The sampling factor is JPEG subsampling 420 + * because the source format is YUV420. Note that libjpeg sampling factors + * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and + * 1 V value for each 2 Y values */ + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 2; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + + /* Let's not hardcode YUV420 in 6 places... 5 was enough */ + int maxVSampFactor = std::max( { + cinfo.comp_info[0].v_samp_factor, + cinfo.comp_info[1].v_samp_factor, + cinfo.comp_info[2].v_samp_factor + }); + int cVSubSampling = cinfo.comp_info[0].v_samp_factor / + cinfo.comp_info[1].v_samp_factor; + + /* Start the compressor */ + jpeg_start_compress(&cinfo, TRUE); + + /* Compute our macroblock height, so we can pad our input to be vertically + * macroblock aligned. + * TODO: Does it need to be horizontally MCU aligned too? */ + + size_t mcuV = DCTSIZE*maxVSampFactor; + size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV); + + /* libjpeg uses arrays of row pointers, which makes it really easy to pad + * data vertically (unfortunately doesn't help horizontally) */ + std::vector yLines (paddedHeight); + std::vector cbLines(paddedHeight/cVSubSampling); + std::vector crLines(paddedHeight/cVSubSampling); + + uint8_t *py = static_cast(inLayout.y); + uint8_t *pcr = static_cast(inLayout.cr); + uint8_t *pcb = static_cast(inLayout.cb); + + for(uint32_t i = 0; i < paddedHeight; i++) + { + /* Once we are in the padding territory we still point to the last line + * effectively replicating it several times ~ CLAMP_TO_EDGE */ + int li = std::min(i, inSz.height - 1); + yLines[i] = static_cast(py + li * inLayout.yStride); + if(i < paddedHeight / cVSubSampling) + { + crLines[i] = static_cast(pcr + li * inLayout.cStride); + cbLines[i] = static_cast(pcb + li * inLayout.cStride); + } + } + + /* If APP1 data was passed in, use it */ + if(app1Buffer && app1Size) + { + jpeg_write_marker(&cinfo, JPEG_APP0 + 1, + static_cast(app1Buffer), app1Size); + } + + /* While we still have padded height left to go, keep giving it one + * macroblock at a time. */ + while (cinfo.next_scanline < cinfo.image_height) { + const uint32_t batchSize = DCTSIZE * maxVSampFactor; + const uint32_t nl = cinfo.next_scanline; + JSAMPARRAY planes[3]{ &yLines[nl], + &cbLines[nl/cVSubSampling], + &crLines[nl/cVSubSampling] }; + + uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize); + + if (done != batchSize) { + ALOGE("%s: compressed %u lines, expected %u (total %u/%u)", + __FUNCTION__, done, batchSize, cinfo.next_scanline, + cinfo.image_height); + return -1; + } + } + + /* This will flush everything */ + jpeg_finish_compress(&cinfo); + + /* Grab the actual code size and set it */ + actualCodeSize = dmgr.mEncodedSize; + + return 0; +} + +Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata& chars) { + Size thumbSize { 0, 0 }; + camera_metadata_ro_entry entry = + chars.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES); + for(uint32_t i = 0; i < entry.count; i += 2) { + Size sz { static_cast(entry.data.i32[i]), + static_cast(entry.data.i32[i+1]) }; + if(sz.width * sz.height > thumbSize.width * thumbSize.height) { + thumbSize = sz; + } + } + + if (thumbSize.width * thumbSize.height == 0) { + ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__); + } + + return thumbSize; +} + +void freeReleaseFences(hidl_vec& results) { + for (auto& result : results) { + if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) { + native_handle_t* handle = const_cast( + result.inputBuffer.releaseFence.getNativeHandle()); + native_handle_close(handle); + native_handle_delete(handle); + } + for (auto& buf : result.outputBuffers) { + if (buf.releaseFence.getNativeHandle() != nullptr) { + native_handle_t* handle = const_cast( + buf.releaseFence.getNativeHandle()); + native_handle_close(handle); + native_handle_delete(handle); + } + } + } + return; +} + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) +#define UPDATE(md, tag, data, size) \ +do { \ + if ((md).update((tag), (data), (size))) { \ + ALOGE("Update " #tag " failed!"); \ + return BAD_VALUE; \ + } \ +} while (0) + +status_t fillCaptureResultCommon( + common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp, + camera_metadata_ro_entry& activeArraySize) { + if (activeArraySize.count < 4) { + ALOGE("%s: cannot find active array size!", __FUNCTION__); + return -EINVAL; + } + // android.control + // For USB camera, we don't know the AE state. Set the state to converged to + // indicate the frame should be good to use. Then apps don't have to wait the + // AE state. + const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED; + UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1); + + const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF; + UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1); + + // Set AWB state to converged to indicate the frame should be good to use. + const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED; + UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1); + + const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF; + UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1); + + const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE; + UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1); + + // This means pipeline latency of X frame intervals. The maximum number is 4. + const uint8_t requestPipelineMaxDepth = 4; + UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1); + + // android.scaler + const int32_t crop_region[] = { + activeArraySize.data.i32[0], activeArraySize.data.i32[1], + activeArraySize.data.i32[2], activeArraySize.data.i32[3], + }; + UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region)); + + // android.sensor + UPDATE(md, ANDROID_SENSOR_TIMESTAMP, ×tamp, 1); + + // android.statistics + const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF; + UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1); + + const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE; + UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1); + + return OK; +} + +#undef ARRAY_SIZE +#undef UPDATE + } // namespace implementation } // namespace V3_4 + +namespace V3_6 { +namespace implementation { + +AllocatedV4L2Frame::AllocatedV4L2Frame(sp frameIn) : + Frame(frameIn->mWidth, frameIn->mHeight, frameIn->mFourcc) { + uint8_t* dataIn; + size_t dataSize; + if (frameIn->getData(&dataIn, &dataSize) != 0) { + ALOGE("%s: map input V4L2 frame failed!", __FUNCTION__); + return; + } + + mData.resize(dataSize); + std::memcpy(mData.data(), dataIn, dataSize); +} + +int AllocatedV4L2Frame::getData(uint8_t** outData, size_t* dataSize) { + if (outData == nullptr || dataSize == nullptr) { + ALOGE("%s: outData(%p)/dataSize(%p) must not be null", __FUNCTION__, outData, dataSize); + return -1; + } + + *outData = mData.data(); + *dataSize = mData.size(); + return 0; +} + +AllocatedV4L2Frame::~AllocatedV4L2Frame() {} + +} // namespace implementation +} // namespace V3_6 } // namespace device diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h index 71b7c17dd6..ecab9cfa03 100644 --- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h +++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H -#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H +#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H #include #include @@ -84,7 +84,8 @@ using ::android::sp; using ::android::Mutex; using ::android::base::unique_fd; -struct ExternalCameraDeviceSession : public virtual RefBase { +struct ExternalCameraDeviceSession : public virtual RefBase, + public virtual OutputThreadInterface { ExternalCameraDeviceSession(const sp&, const ExternalCameraConfig& cfg, @@ -110,6 +111,82 @@ struct ExternalCameraDeviceSession : public virtual RefBase { static const int kMaxStallStream = 1; static const uint32_t kMaxBytesPerPixel = 2; + class OutputThread : public android::Thread { + public: + OutputThread(wp parent, CroppingType, + const common::V1_0::helper::CameraMetadata&); + virtual ~OutputThread(); + + Status allocateIntermediateBuffers( + const Size& v4lSize, const Size& thumbSize, + const hidl_vec& streams, + uint32_t blobBufferSize); + Status submitRequest(const std::shared_ptr&); + void flush(); + void dump(int fd); + virtual bool threadLoop() override; + + void setExifMakeModel(const std::string& make, const std::string& model); + + // The remaining request list is returned for offline processing + std::list> switchToOffline(); + + protected: + // Methods to request output buffer in parallel + // No-op for device@3.4. Implemented in device@3.5 + virtual int requestBufferStart(const std::vector&) { return 0; } + virtual int waitForBufferRequestDone( + /*out*/std::vector*) { return 0; } + + static const int kFlushWaitTimeoutSec = 3; // 3 sec + static const int kReqWaitTimeoutMs = 33; // 33ms + static const int kReqWaitTimesMax = 90; // 33ms * 90 ~= 3 sec + + void waitForNextRequest(std::shared_ptr* out); + void signalRequestDone(); + + int cropAndScaleLocked( + sp& in, const Size& outSize, + YCbCrLayout* out); + + int cropAndScaleThumbLocked( + sp& in, const Size& outSize, + YCbCrLayout* out); + + int createJpegLocked(HalStreamBuffer &halBuf, + const common::V1_0::helper::CameraMetadata& settings); + + void clearIntermediateBuffers(); + + const wp mParent; + const CroppingType mCroppingType; + const common::V1_0::helper::CameraMetadata mCameraCharacteristics; + + mutable std::mutex mRequestListLock; // Protect acccess to mRequestList, + // mProcessingRequest and mProcessingFrameNumer + std::condition_variable mRequestCond; // signaled when a new request is submitted + std::condition_variable mRequestDoneCond; // signaled when a request is done processing + std::list> mRequestList; + bool mProcessingRequest = false; + uint32_t mProcessingFrameNumer = 0; + + // V4L2 frameIn + // (MJPG decode)-> mYu12Frame + // (Scale)-> mScaledYu12Frames + // (Format convert) -> output gralloc frames + mutable std::mutex mBufferLock; // Protect access to intermediate buffers + sp mYu12Frame; + sp mYu12ThumbFrame; + std::unordered_map, SizeHasher> mIntermediateBuffers; + std::unordered_map, SizeHasher> mScaledYu12Frames; + YCbCrLayout mYu12FrameLayout; + YCbCrLayout mYu12ThumbFrameLayout; + uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size + + std::string mExifMake; + std::string mExifModel; + }; + protected: // Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow @@ -150,27 +227,22 @@ protected: ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb); protected: - struct HalStreamBuffer { - int32_t streamId; - uint64_t bufferId; - uint32_t width; - uint32_t height; - PixelFormat format; - V3_2::BufferUsageFlags usage; - buffer_handle_t* bufPtr; - int acquireFence; - bool fenceTimeout; - }; + // Methods from OutputThreadInterface + virtual Status importBuffer(int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf) override; - struct HalRequest { - uint32_t frameNumber; - common::V1_0::helper::CameraMetadata setting; - sp frameIn; - nsecs_t shutterTs; - std::vector buffers; - }; + virtual Status processCaptureResult(std::shared_ptr&) override; - static const uint64_t BUFFER_ID_NO_BUFFER = 0; + virtual Status processCaptureRequestError(const std::shared_ptr&, + /*out*/std::vector* msgs = nullptr, + /*out*/std::vector* results = nullptr) override; + + virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override; + + virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override; + // End of OutputThreadInterface methods Status constructDefaultRequestSettingsRaw(RequestTemplate type, V3_2::CameraMetadata *outMetadata); @@ -219,11 +291,6 @@ protected: // Optional argument for ICameraDeviceSession@3.5 impl bool allowEmptyBuf = false); - Status importBuffer(int32_t streamId, - uint64_t bufId, buffer_handle_t buf, - /*out*/buffer_handle_t** outBufPtr, - bool allowEmptyBuf); - Status importBufferLocked(int32_t streamId, uint64_t bufId, buffer_handle_t buf, /*out*/buffer_handle_t** outBufPtr, @@ -236,106 +303,15 @@ protected: Status processOneCaptureRequest(const CaptureRequest& request); - Status processCaptureResult(std::shared_ptr&); - Status processCaptureRequestError(const std::shared_ptr&); void notifyShutter(uint32_t frameNumber, nsecs_t shutterTs); - void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec); void invokeProcessCaptureResultCallback( hidl_vec &results, bool tryWriteFmq); - static void freeReleaseFences(hidl_vec&); Size getMaxJpegResolution() const; Size getMaxThumbResolution() const; - ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const; - int waitForV4L2BufferReturnLocked(std::unique_lock& lk); - class OutputThread : public android::Thread { - public: - OutputThread(wp parent, CroppingType); - virtual ~OutputThread(); - - Status allocateIntermediateBuffers( - const Size& v4lSize, const Size& thumbSize, - const hidl_vec& streams, - uint32_t blobBufferSize); - Status submitRequest(const std::shared_ptr&); - void flush(); - void dump(int fd); - virtual bool threadLoop() override; - - void setExifMakeModel(const std::string& make, const std::string& model); - - protected: - // Methods to request output buffer in parallel - // No-op for device@3.4. Implemented in device@3.5 - virtual int requestBufferStart(const std::vector&) { return 0; } - virtual int waitForBufferRequestDone( - /*out*/std::vector*) { return 0; } - - static const uint32_t FLEX_YUV_GENERIC = static_cast('F') | - static_cast('L') << 8 | static_cast('E') << 16 | - static_cast('X') << 24; - // returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21 - static uint32_t getFourCcFromLayout(const YCbCrLayout&); - static int getCropRect( - CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out); - - static const int kFlushWaitTimeoutSec = 3; // 3 sec - static const int kReqWaitTimeoutMs = 33; // 33ms - static const int kReqWaitTimesMax = 90; // 33ms * 90 ~= 3 sec - - void waitForNextRequest(std::shared_ptr* out); - void signalRequestDone(); - - int cropAndScaleLocked( - sp& in, const Size& outSize, - YCbCrLayout* out); - - int cropAndScaleThumbLocked( - sp& in, const Size& outSize, - YCbCrLayout* out); - - int formatConvertLocked(const YCbCrLayout& in, const YCbCrLayout& out, - Size sz, uint32_t format); - - static int encodeJpegYU12(const Size &inSz, - const YCbCrLayout& inLayout, int jpegQuality, - const void *app1Buffer, size_t app1Size, - void *out, size_t maxOutSize, - size_t &actualCodeSize); - - int createJpegLocked(HalStreamBuffer &halBuf, const std::shared_ptr& req); - - const wp mParent; - const CroppingType mCroppingType; - - mutable std::mutex mRequestListLock; // Protect acccess to mRequestList, - // mProcessingRequest and mProcessingFrameNumer - std::condition_variable mRequestCond; // signaled when a new request is submitted - std::condition_variable mRequestDoneCond; // signaled when a request is done processing - std::list> mRequestList; - bool mProcessingRequest = false; - uint32_t mProcessingFrameNumer = 0; - - // V4L2 frameIn - // (MJPG decode)-> mYu12Frame - // (Scale)-> mScaledYu12Frames - // (Format convert) -> output gralloc frames - mutable std::mutex mBufferLock; // Protect access to intermediate buffers - sp mYu12Frame; - sp mYu12ThumbFrame; - std::unordered_map, SizeHasher> mIntermediateBuffers; - std::unordered_map, SizeHasher> mScaledYu12Frames; - YCbCrLayout mYu12FrameLayout; - YCbCrLayout mYu12ThumbFrameLayout; - uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size - - std::string mExifMake; - std::string mExifModel; - }; - // Protect (most of) HIDL interface methods from synchronized-entering mutable Mutex mInterfaceLock; @@ -381,12 +357,6 @@ protected: std::mutex mInflightFramesLock; // protect mInflightFrames std::unordered_set mInflightFrames; - // buffers currently circulating between HAL and camera service - // key: bufferId sent via HIDL interface - // value: imported buffer_handle_t - // Buffer will be imported during processCaptureRequest and will be freed - // when the its stream is deleted or camera device session is closed - typedef std::unordered_map CirculatingBuffers; // Stream ID -> circulating buffers map std::map mCirculatingBuffers; // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock @@ -395,6 +365,8 @@ protected: std::mutex mAfTriggerLock; // protect mAfTrigger bool mAfTrigger = false; + uint32_t mBlobBufferSize = 0; + static HandleImporter sHandleImporter; /* Beginning of members not changed after initialize() */ @@ -410,6 +382,9 @@ protected: const Size mMaxThumbResolution; const Size mMaxJpegResolution; + + std::string mExifMake; + std::string mExifModel; /* End of members not changed after initialize() */ private: @@ -484,4 +459,4 @@ private: } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h index 341c62218d..74f75eb246 100644 --- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h +++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h @@ -17,16 +17,27 @@ #ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H #define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H +#include +#include +#include #include #include #include +#include #include #include #include "tinyxml2.h" // XML parsing #include "utils/LightRefBase.h" +#include "utils/Timers.h" +#include +#include -using android::hardware::graphics::mapper::V2_0::IMapper; -using android::hardware::graphics::mapper::V2_0::YCbCrLayout; + +using ::android::hardware::graphics::mapper::V2_0::IMapper; +using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout; +using ::android::hardware::camera::common::V1_0::helper::HandleImporter; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::device::V3_2::ErrorCode; namespace android { namespace hardware { @@ -113,16 +124,28 @@ struct SupportedV4L2Format { std::vector frameRates; }; +// A Base class with basic information about a frame +struct Frame : public VirtualLightRefBase { +public: + Frame(uint32_t width, uint32_t height, uint32_t fourcc); + const uint32_t mWidth; + const uint32_t mHeight; + const uint32_t mFourcc; + + // getData might involve map/allocation + virtual int getData(uint8_t** outData, size_t* dataSize) = 0; +}; + // A class provide access to a dequeued V4L2 frame buffer (mostly in MJPG format) // Also contains necessary information to enqueue the buffer back to V4L2 buffer queue -class V4L2Frame : public virtual VirtualLightRefBase { +class V4L2Frame : public Frame { public: V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd, uint32_t dataSize, uint64_t offset); ~V4L2Frame() override; - const uint32_t mWidth; - const uint32_t mHeight; - const uint32_t mFourcc; + + virtual int getData(uint8_t** outData, size_t* dataSize) override; + const int mBufferIndex; // for later enqueue int map(uint8_t** data, size_t* dataSize); int unmap(); @@ -137,13 +160,13 @@ private: // A RAII class representing a CPU allocated YUV frame used as intermeidate buffers // when generating output images. -class AllocatedFrame : public virtual VirtualLightRefBase { +class AllocatedFrame : public Frame { public: - AllocatedFrame(uint32_t w, uint32_t h); // TODO: use Size? + AllocatedFrame(uint32_t w, uint32_t h); // only support V4L2_PIX_FMT_YUV420 for now ~AllocatedFrame() override; - const uint32_t mWidth; - const uint32_t mHeight; - const uint32_t mFourcc; // Only support YU12 format for now + + virtual int getData(uint8_t** outData, size_t* dataSize) override; + int allocate(YCbCrLayout* out = nullptr); int getLayout(YCbCrLayout* out); int getCroppedLayout(const IMapper::Rect&, YCbCrLayout* out); // return non-zero for bad input @@ -165,8 +188,110 @@ const float kMinAspectRatio = 1.f; bool isAspectRatioClose(float ar1, float ar2); +struct HalStreamBuffer { + int32_t streamId; + uint64_t bufferId; + uint32_t width; + uint32_t height; + ::android::hardware::graphics::common::V1_0::PixelFormat format; + ::android::hardware::camera::device::V3_2::BufferUsageFlags usage; + buffer_handle_t* bufPtr; + int acquireFence; + bool fenceTimeout; +}; + +struct HalRequest { + uint32_t frameNumber; + common::V1_0::helper::CameraMetadata setting; + sp frameIn; + nsecs_t shutterTs; + std::vector buffers; +}; + +static const uint64_t BUFFER_ID_NO_BUFFER = 0; + +// buffers currently circulating between HAL and camera service +// key: bufferId sent via HIDL interface +// value: imported buffer_handle_t +// Buffer will be imported during processCaptureRequest (or requestStreamBuffer +// in the case of HAL buffer manager is enabled) and will be freed +// when the stream is deleted or camera device session is closed +typedef std::unordered_map CirculatingBuffers; + +::android::hardware::camera::common::V1_0::Status importBufferImpl( + /*inout*/std::map& circulatingBuffers, + /*inout*/HandleImporter& handleImporter, + int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf); + +static const uint32_t FLEX_YUV_GENERIC = static_cast('F') | + static_cast('L') << 8 | static_cast('E') << 16 | + static_cast('X') << 24; + +// returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21 +uint32_t getFourCcFromLayout(const YCbCrLayout&); + +using ::android::hardware::camera::external::common::Size; +int getCropRect(CroppingType ct, const Size& inSize, + const Size& outSize, IMapper::Rect* out); + +int formatConvert(const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format); + +int encodeJpegYU12(const Size &inSz, + const YCbCrLayout& inLayout, int jpegQuality, + const void *app1Buffer, size_t app1Size, + void *out, size_t maxOutSize, + size_t &actualCodeSize); + +Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata&); + +void freeReleaseFences(hidl_vec&); + +status_t fillCaptureResultCommon(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp, + camera_metadata_ro_entry& activeArraySize); + +// Interface for OutputThread calling back to parent +struct OutputThreadInterface : public virtual RefBase { + virtual ::android::hardware::camera::common::V1_0::Status importBuffer( + int32_t streamId, uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, bool allowEmptyBuf) = 0; + + virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) = 0; + + // Callbacks are fired within the method if msgs/results are nullptr. + // Otherwise the callbacks will be returned and caller is responsible to + // fire the callback later + virtual ::android::hardware::camera::common::V1_0::Status processCaptureRequestError( + const std::shared_ptr&, + /*out*/std::vector* msgs = nullptr, + /*out*/std::vector* results = nullptr) = 0; + + virtual ::android::hardware::camera::common::V1_0::Status processCaptureResult( + std::shared_ptr&) = 0; + + virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const = 0; +}; + } // namespace implementation } // namespace V3_4 + +namespace V3_6 { +namespace implementation { + +// A CPU copy of a mapped V4L2Frame. Will map the input V4L2 frame. +class AllocatedV4L2Frame : public V3_4::implementation::Frame { +public: + AllocatedV4L2Frame(sp frameIn); + ~AllocatedV4L2Frame() override; + virtual int getData(uint8_t** outData, size_t* dataSize) override; +private: + std::vector mData; +}; + +} // namespace implementation +} // namespace V3_6 } // namespace device } // namespace camera } // namespace hardware diff --git a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp index 00c1d0de39..287ac324ec 100644 --- a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp +++ b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp @@ -80,7 +80,7 @@ Status ExternalCameraDeviceSession::importRequestLocked( ExternalCameraDeviceSession::BufferRequestThread::BufferRequestThread( - wp parent, + wp parent, sp callbacks) : mParent(parent), mCallbacks(callbacks) {} @@ -254,7 +254,8 @@ void ExternalCameraDeviceSession::initOutputThread() { mBufferRequestThread = new BufferRequestThread(this, mCallback_3_5); mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY); } - mOutputThread = new OutputThread(this, mCroppingType, mBufferRequestThread); + mOutputThread = new OutputThread( + this, mCroppingType, mCameraCharacteristics, mBufferRequestThread); } void ExternalCameraDeviceSession::closeOutputThreadImpl() { @@ -271,10 +272,11 @@ void ExternalCameraDeviceSession::closeOutputThread() { } ExternalCameraDeviceSession::OutputThread::OutputThread( - wp parent, + wp parent, CroppingType ct, + const common::V1_0::helper::CameraMetadata& chars, sp bufReqThread) : - V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct), + V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct, chars), mBufferRequestThread(bufReqThread) {} ExternalCameraDeviceSession::OutputThread::~OutputThread() {} diff --git a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h index 281f93a13b..e89ef45f52 100644 --- a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h +++ b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H -#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H +#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H #include #include @@ -72,6 +72,7 @@ using ::android::base::unique_fd; using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format; using ::android::hardware::camera::device::V3_4::implementation::CroppingType; +using ::android::hardware::camera::device::V3_4::implementation::HalStreamBuffer; struct ExternalCameraDeviceSession : public V3_4::implementation::ExternalCameraDeviceSession { @@ -97,6 +98,62 @@ struct ExternalCameraDeviceSession : public V3_4::implementation::ExternalCamera config, supportedFormats, devCfg); } + class BufferRequestThread : public android::Thread { + public: + BufferRequestThread( + wp parent, + sp callbacks); + + int requestBufferStart(const std::vector&); + int waitForBufferRequestDone( + /*out*/std::vector*); + + virtual bool threadLoop() override; + + private: + void waitForNextRequest(); + + const wp mParent; + const sp mCallbacks; + + std::mutex mLock; + bool mRequestingBuffer = false; + + std::vector mBufferReqs; + std::vector mPendingReturnBufferReqs; + // mHalBufferReqs is not under mLock protection during the HIDL transaction + hidl_vec mHalBufferReqs; + + // request buffers takes much less time in steady state, but can take much longer + // when requesting 1st buffer from a stream. + // TODO: consider a separate timeout for new vs. steady state? + // TODO: or make sure framework is warming up the pipeline during configure new stream? + static const int kReqProcTimeoutMs = 66; + + static const int kReqWaitTimeoutMs = 33; + static const int kReqWaitTimesWarn = 90; // 33ms * 90 ~= 3 sec + std::condition_variable mRequestCond; // signaled when a new buffer request incoming + std::condition_variable mRequestDoneCond; // signaled when a request is done + }; + + class OutputThread : + public V3_4::implementation::ExternalCameraDeviceSession::OutputThread { + public: + // TODO: pass buffer request thread to OutputThread ctor + OutputThread(wp parent, CroppingType, + const common::V1_0::helper::CameraMetadata&, + sp bufReqThread); + virtual ~OutputThread(); + + protected: + // Methods to request output buffer in parallel + virtual int requestBufferStart(const std::vector&) override; + virtual int waitForBufferRequestDone( + /*out*/std::vector*) override; + + const sp mBufferRequestThread; + }; + protected: // Methods from v3.4 and earlier will trampoline to inherited implementation Return configureStreams_3_5( @@ -120,63 +177,8 @@ protected: hidl_vec& allBufPtrs, hidl_vec& allFences) override; - class BufferRequestThread : public android::Thread { - public: - BufferRequestThread( - wp parent, - sp callbacks); - - int requestBufferStart(const std::vector&); - int waitForBufferRequestDone( - /*out*/std::vector*); - - virtual bool threadLoop() override; - - private: - void waitForNextRequest(); - - const wp mParent; - const sp mCallbacks; - - std::mutex mLock; - bool mRequestingBuffer = false; - - std::vector mBufferReqs; - std::vector mPendingReturnBufferReqs; - // mHalBufferReqs is not under mLock protection during the HIDL transaction - hidl_vec mHalBufferReqs; - - // request buffers takes much less time in steady state, but can take much longer - // when requesting 1st buffer from a stream. - // TODO: consider a separate timeout for new vs. steady state? - // TODO: or make sure framework is warming up the pipeline during configure new stream? - static const int kReqProcTimeoutMs = 66; - - static const int kReqWaitTimeoutMs = 33; - static const int kReqWaitTimesWarn = 90; // 33ms * 90 ~= 3 sec - std::condition_variable mRequestCond; // signaled when a new buffer request incoming - std::condition_variable mRequestDoneCond; // signaled when a request is done - }; - sp mBufferRequestThread; - class OutputThread : - public V3_4::implementation::ExternalCameraDeviceSession::OutputThread { - public: - // TODO: pass buffer request thread to OutputThread ctor - OutputThread(wp parent, CroppingType, - sp bufReqThread); - virtual ~OutputThread(); - - protected: - // Methods to request output buffer in parallel - virtual int requestBufferStart(const std::vector&) override; - virtual int waitForBufferRequestDone( - /*out*/std::vector*) override; - - const sp mBufferRequestThread; - }; - sp mCallback_3_5; bool mSupportBufMgr; @@ -270,4 +272,4 @@ private: } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H diff --git a/camera/device/3.6/default/Android.bp b/camera/device/3.6/default/Android.bp index ce51185193..a2ddebdd24 100644 --- a/camera/device/3.6/default/Android.bp +++ b/camera/device/3.6/default/Android.bp @@ -28,6 +28,7 @@ cc_library_shared { srcs: [ "ExternalCameraDevice.cpp", "ExternalCameraDeviceSession.cpp", + "ExternalCameraOfflineSession.cpp", ], shared_libs: [ "libhidlbase", diff --git a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp index e14ae992b8..0cc81bbe9e 100644 --- a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp +++ b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp @@ -73,12 +73,8 @@ Return ExternalCameraDeviceSession::configureStreams_3_6( Status status = configureStreams(config_v32, &outStreams_v33, blobBufferSize); - outStreams.streams.resize(outStreams_v33.streams.size()); - for (size_t i = 0; i < outStreams.streams.size(); i++) { - outStreams.streams[i].v3_4.v3_3 = outStreams_v33.streams[i]; - // TODO: implement it later - outStreams.streams[i].supportOffline = false; - } + fillOutputStream3_6(outStreams_v33, &outStreams); + _hidl_cb(status, outStreams); return Void(); } @@ -86,12 +82,273 @@ Return ExternalCameraDeviceSession::configureStreams_3_6( Return ExternalCameraDeviceSession::switchToOffline( const hidl_vec& streamsToKeep, ICameraDeviceSession::switchToOffline_cb _hidl_cb) { - // TODO: implement this - (void) streamsToKeep; - (void) _hidl_cb; + std::vector msgs; + std::vector results; + CameraOfflineSessionInfo info; + sp session; + + Status st = switchToOffline(streamsToKeep, &msgs, &results, &info, &session); + + mCallback->notify(msgs); + hidl_vec hidlResults(std::move(results)); + invokeProcessCaptureResultCallback(hidlResults, /* tryWriteFmq */true); + V3_4::implementation::freeReleaseFences(hidlResults); + + _hidl_cb(st, info, session); return Void(); } +void ExternalCameraDeviceSession::fillOutputStream3_6( + const V3_3::HalStreamConfiguration& outStreams_v33, + /*out*/V3_6::HalStreamConfiguration* outStreams_v36) { + if (outStreams_v36 == nullptr) { + ALOGE("%s: outStreams_v36 must not be null!", __FUNCTION__); + return; + } + Mutex::Autolock _l(mLock); + outStreams_v36->streams.resize(outStreams_v33.streams.size()); + for (size_t i = 0; i < outStreams_v36->streams.size(); i++) { + outStreams_v36->streams[i].v3_4.v3_3 = outStreams_v33.streams[i]; + outStreams_v36->streams[i].supportOffline = + supportOfflineLocked(outStreams_v33.streams[i].v3_2.id); + } +} + +bool ExternalCameraDeviceSession::supportOfflineLocked(int32_t streamId) { + const Stream& stream = mStreamMap[streamId]; + if (stream.format == PixelFormat::BLOB && + stream.dataSpace == static_cast(Dataspace::V0_JFIF)) { + return true; + } + // TODO: support YUV output stream? + return false; +} + +bool ExternalCameraDeviceSession::canDropRequest(const hidl_vec& offlineStreams, + std::shared_ptr halReq) { + for (const auto& buffer : halReq->buffers) { + for (auto offlineStreamId : offlineStreams) { + if (buffer.streamId == offlineStreamId) { + return false; + } + } + } + // Only drop a request completely if it has no offline output + return true; +} + +void ExternalCameraDeviceSession::fillOfflineSessionInfo(const hidl_vec& offlineStreams, + std::deque>& offlineReqs, + const std::map& circulatingBuffers, + /*out*/CameraOfflineSessionInfo* info) { + if (info == nullptr) { + ALOGE("%s: output info must not be null!", __FUNCTION__); + return; + } + + info->offlineStreams.resize(offlineStreams.size()); + info->offlineRequests.resize(offlineReqs.size()); + + std::unordered_map outstandingBufs(offlineStreams.size()); + for (const auto streamId : offlineStreams) { + outstandingBufs.insert({streamId, 0}); + } + // Fill in offline reqs and count outstanding buffers + for (size_t i = 0; i < offlineReqs.size(); i++) { + info->offlineRequests[i].frameNumber = offlineReqs[i]->frameNumber; + info->offlineRequests[i].pendingStreams.resize(offlineReqs[i]->buffers.size()); + for (size_t bIdx = 0; bIdx < offlineReqs[i]->buffers.size(); bIdx++) { + int32_t streamId = offlineReqs[i]->buffers[bIdx].streamId; + info->offlineRequests[i].pendingStreams[bIdx] = streamId; + outstandingBufs[streamId]++; + } + } + + for (size_t i = 0; i < offlineStreams.size(); i++) { + int32_t streamId = offlineStreams[i]; + info->offlineStreams[i].id = streamId; + info->offlineStreams[i].numOutstandingBuffers = outstandingBufs[streamId]; + const CirculatingBuffers& bufIdMap = circulatingBuffers.at(streamId); + info->offlineStreams[i].circulatingBufferIds.resize(bufIdMap.size()); + size_t bIdx = 0; + for (const auto& pair : bufIdMap) { + // Fill in bufferId + info->offlineStreams[i].circulatingBufferIds[bIdx++] = pair.first; + } + + } +} + +Status ExternalCameraDeviceSession::switchToOffline(const hidl_vec& offlineStreams, + /*out*/std::vector* msgs, + /*out*/std::vector* results, + /*out*/CameraOfflineSessionInfo* info, + /*out*/sp* session) { + ATRACE_CALL(); + if (offlineStreams.size() > 1) { + ALOGE("%s: more than one offline stream is not supported", __FUNCTION__); + return Status::ILLEGAL_ARGUMENT; + } + + if (msgs == nullptr || results == nullptr || info == nullptr || session == nullptr) { + ALOGE("%s: output arguments (%p, %p, %p, %p) must not be null", __FUNCTION__, + msgs, results, info, session); + return Status::ILLEGAL_ARGUMENT; + } + + msgs->clear(); + results->clear(); + + Mutex::Autolock _il(mInterfaceLock); + Status status = initStatus(); + if (status != Status::OK) { + return status; + } + + Mutex::Autolock _l(mLock); + for (auto streamId : offlineStreams) { + if (!supportOfflineLocked(streamId)) { + return Status::ILLEGAL_ARGUMENT; + } + } + + // pause output thread and get all remaining inflight requests + auto remainingReqs = mOutputThread->switchToOffline(); + std::vector> halReqs; + + // Send out buffer/request error for remaining requests and filter requests + // to be handled in offline mode + for (auto& halReq : remainingReqs) { + bool dropReq = canDropRequest(offlineStreams, halReq); + if (dropReq) { + // Request is dropped completely. Just send request error and + // there is no need to send the request to offline session + processCaptureRequestError(halReq, msgs, results); + continue; + } + + // All requests reach here must have at least one offline stream output + NotifyMsg shutter; + shutter.type = MsgType::SHUTTER; + shutter.msg.shutter.frameNumber = halReq->frameNumber; + shutter.msg.shutter.timestamp = halReq->shutterTs; + msgs->push_back(shutter); + + std::vector offlineBuffers; + for (const auto& buffer : halReq->buffers) { + bool dropBuffer = true; + for (auto offlineStreamId : offlineStreams) { + if (buffer.streamId == offlineStreamId) { + dropBuffer = false; + break; + } + } + if (dropBuffer) { + NotifyMsg error; + error.type = MsgType::ERROR; + error.msg.error.frameNumber = halReq->frameNumber; + error.msg.error.errorStreamId = buffer.streamId; + error.msg.error.errorCode = ErrorCode::ERROR_BUFFER; + msgs->push_back(error); + + CaptureResult result; + result.frameNumber = halReq->frameNumber; + result.partialResult = 0; // buffer only result + result.inputBuffer.streamId = -1; + result.outputBuffers.resize(1); + result.outputBuffers[0].streamId = buffer.streamId; + result.outputBuffers[0].bufferId = buffer.bufferId; + result.outputBuffers[0].status = BufferStatus::ERROR; + if (buffer.acquireFence >= 0) { + native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0); + handle->data[0] = buffer.acquireFence; + result.outputBuffers[0].releaseFence.setTo(handle, /*shouldOwn*/false); + } + results->push_back(result); + } else { + offlineBuffers.push_back(buffer); + } + } + halReq->buffers = offlineBuffers; + halReqs.push_back(halReq); + } + + // convert hal requests to offline request + std::deque> offlineReqs(halReqs.size()); + for (auto& v4lReq : halReqs) { + std::shared_ptr halReq = std::make_shared(); + halReq->frameNumber = v4lReq->frameNumber; + halReq->setting = v4lReq->setting; + halReq->shutterTs = v4lReq->shutterTs; + halReq->buffers = v4lReq->buffers; + sp v4l2Frame = + static_cast(v4lReq->frameIn.get()); + halReq->frameIn = new AllocatedV4L2Frame(v4l2Frame); + offlineReqs.push_back(halReq); + // enqueue V4L2 frame + enqueueV4l2Frame(v4l2Frame); + } + + // Collect buffer caches/streams + hidl_vec streamInfos; + streamInfos.resize(offlineStreams.size()); + std::map circulatingBuffers; + { + Mutex::Autolock _l(mCbsLock); + size_t idx = 0; + for(auto streamId : offlineStreams) { + circulatingBuffers[streamId] = mCirculatingBuffers.at(streamId); + mCirculatingBuffers.erase(streamId); + streamInfos[idx++] = mStreamMap.at(streamId); + mStreamMap.erase(streamId); + } + } + + fillOfflineSessionInfo(offlineStreams, offlineReqs, circulatingBuffers, info); + + // create the offline session object + bool afTrigger; + { + std::lock_guard lk(mAfTriggerLock); + afTrigger = mAfTrigger; + } + sp sessionImpl = new ExternalCameraOfflineSession( + mCroppingType, mCameraCharacteristics, mCameraId, + mExifMake, mExifModel, mBlobBufferSize, afTrigger, + streamInfos, offlineReqs, circulatingBuffers); + + bool initFailed = sessionImpl->initialize(); + if (initFailed) { + ALOGE("%s: offline session initialize failed!", __FUNCTION__); + return Status::INTERNAL_ERROR; + } + + // cleanup stream and buffer caches + { + Mutex::Autolock _l(mCbsLock); + for(auto pair : mStreamMap) { + cleanupBuffersLocked(/*Stream ID*/pair.first); + } + mCirculatingBuffers.clear(); + } + mStreamMap.clear(); + + // update inflight records + { + std::lock_guard lk(mInflightFramesLock); + mInflightFrames.clear(); + } + + // stop v4l2 streaming + if (v4l2StreamOffLocked() !=0) { + ALOGE("%s: stop V4L2 streaming failed!", __FUNCTION__); + return Status::INTERNAL_ERROR; + } + + *session = sessionImpl->getInterface(); + return Status::OK; +} + } // namespace implementation } // namespace V3_6 } // namespace device diff --git a/camera/device/3.6/default/ExternalCameraOfflineSession.cpp b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp new file mode 100644 index 0000000000..e606fda832 --- /dev/null +++ b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp @@ -0,0 +1,554 @@ +/* + * 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. + */ + +#define LOG_TAG "ExtCamOfflnSsn@3.6" +#define ATRACE_TAG ATRACE_TAG_CAMERA +#include + +#include +#include + +#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs +#include + +#include +#include "ExternalCameraOfflineSession.h" + +namespace { + +// Size of request/result metadata fast message queue. Change to 0 to always use hwbinder buffer. +static constexpr size_t kMetadataMsgQueueSize = 1 << 18 /* 256kB */; + +} // anonymous namespace + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_6 { +namespace implementation { + +// static instance +HandleImporter ExternalCameraOfflineSession::sHandleImporter; + +using V3_5::implementation::ExternalCameraDeviceSession; + +ExternalCameraOfflineSession::ExternalCameraOfflineSession( + const CroppingType& croppingType, + const common::V1_0::helper::CameraMetadata& chars, + const std::string& cameraId, + const std::string& exifMake, + const std::string& exifModel, + const uint32_t blobBufferSize, + const bool afTrigger, + const hidl_vec& offlineStreams, + std::deque>& offlineReqs, + const std::map& circulatingBuffers) : + mCroppingType(croppingType), mChars(chars), mCameraId(cameraId), + mExifMake(exifMake), mExifModel(exifModel), mBlobBufferSize(blobBufferSize), + mAfTrigger(afTrigger), mOfflineStreams(offlineStreams), mOfflineReqs(offlineReqs), + mCirculatingBuffers(circulatingBuffers) {} + +ExternalCameraOfflineSession::~ExternalCameraOfflineSession() { + close(); +} + +bool ExternalCameraOfflineSession::initialize() { + mResultMetadataQueue = std::make_shared( + kMetadataMsgQueueSize, false /* non blocking */); + if (!mResultMetadataQueue->isValid()) { + ALOGE("%s: invalid result fmq", __FUNCTION__); + return true; + } + return false; +} + +void ExternalCameraOfflineSession::initOutputThread() { + if (mOutputThread != nullptr) { + ALOGE("%s: OutputThread already exist!", __FUNCTION__); + return; + } + + mBufferRequestThread = new ExternalCameraDeviceSession::BufferRequestThread( + this, mCallback); + mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY); + + mOutputThread = new OutputThread(this, mCroppingType, mChars, + mBufferRequestThread, mOfflineReqs); + + mOutputThread->setExifMakeModel(mExifMake, mExifModel); + + Size inputSize = { mOfflineReqs[0]->frameIn->mWidth, mOfflineReqs[0]->frameIn->mHeight}; + Size maxThumbSize = V3_4::implementation::getMaxThumbnailResolution(mChars); + mOutputThread->allocateIntermediateBuffers( + inputSize, maxThumbSize, mOfflineStreams, mBlobBufferSize); + + mOutputThread->run("ExtCamOfflnOut", PRIORITY_DISPLAY); +} + +bool ExternalCameraOfflineSession::OutputThread::threadLoop() { + auto parent = mParent.promote(); + if (parent == nullptr) { + ALOGE("%s: session has been disconnected!", __FUNCTION__); + return false; + } + + if (mOfflineReqs.empty()) { + ALOGI("%s: all offline requests are processed. Stopping.", __FUNCTION__); + return false; + } + + std::shared_ptr req = mOfflineReqs.front(); + mOfflineReqs.pop_front(); + + auto onDeviceError = [&](auto... args) { + ALOGE(args...); + parent->notifyError( + req->frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE); + signalRequestDone(); + return false; + }; + + if (req->frameIn->mFourcc != V4L2_PIX_FMT_MJPEG && req->frameIn->mFourcc != V4L2_PIX_FMT_Z16) { + return onDeviceError("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__, + req->frameIn->mFourcc & 0xFF, + (req->frameIn->mFourcc >> 8) & 0xFF, + (req->frameIn->mFourcc >> 16) & 0xFF, + (req->frameIn->mFourcc >> 24) & 0xFF); + } + + int res = requestBufferStart(req->buffers); + if (res != 0) { + ALOGE("%s: send BufferRequest failed! res %d", __FUNCTION__, res); + return onDeviceError("%s: failed to send buffer request!", __FUNCTION__); + } + + std::unique_lock lk(mBufferLock); + // Convert input V4L2 frame to YU12 of the same size + // TODO: see if we can save some computation by converting to YV12 here + uint8_t* inData; + size_t inDataSize; + if (req->frameIn->getData(&inData, &inDataSize) != 0) { + lk.unlock(); + return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__); + } + + // TODO: in some special case maybe we can decode jpg directly to gralloc output? + if (req->frameIn->mFourcc == V4L2_PIX_FMT_MJPEG) { + ATRACE_BEGIN("MJPGtoI420"); + int res = libyuv::MJPGToI420( + inData, inDataSize, static_cast(mYu12FrameLayout.y), mYu12FrameLayout.yStride, + static_cast(mYu12FrameLayout.cb), mYu12FrameLayout.cStride, + static_cast(mYu12FrameLayout.cr), mYu12FrameLayout.cStride, + mYu12Frame->mWidth, mYu12Frame->mHeight, mYu12Frame->mWidth, mYu12Frame->mHeight); + ATRACE_END(); + + if (res != 0) { + // For some webcam, the first few V4L2 frames might be malformed... + ALOGE("%s: Convert V4L2 frame to YU12 failed! res %d", __FUNCTION__, res); + lk.unlock(); + Status st = parent->processCaptureRequestError(req); + if (st != Status::OK) { + return onDeviceError("%s: failed to process capture request error!", __FUNCTION__); + } + signalRequestDone(); + return true; + } + } + + ATRACE_BEGIN("Wait for BufferRequest done"); + res = waitForBufferRequestDone(&req->buffers); + ATRACE_END(); + + if (res != 0) { + ALOGE("%s: wait for BufferRequest done failed! res %d", __FUNCTION__, res); + lk.unlock(); + return onDeviceError("%s: failed to process buffer request error!", __FUNCTION__); + } + + ALOGV("%s processing new request", __FUNCTION__); + const int kSyncWaitTimeoutMs = 500; + for (auto& halBuf : req->buffers) { + if (*(halBuf.bufPtr) == nullptr) { + ALOGW("%s: buffer for stream %d missing", __FUNCTION__, halBuf.streamId); + halBuf.fenceTimeout = true; + } else if (halBuf.acquireFence >= 0) { + int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs); + if (ret) { + halBuf.fenceTimeout = true; + } else { + ::close(halBuf.acquireFence); + halBuf.acquireFence = -1; + } + } + + if (halBuf.fenceTimeout) { + continue; + } + + // Gralloc lockYCbCr the buffer + switch (halBuf.format) { + case PixelFormat::BLOB: { + int ret = createJpegLocked(halBuf, req->setting); + + if(ret != 0) { + lk.unlock(); + return onDeviceError("%s: createJpegLocked failed with %d", + __FUNCTION__, ret); + } + } break; + case PixelFormat::Y16: { + void* outLayout = sHandleImporter.lock(*(halBuf.bufPtr), halBuf.usage, inDataSize); + + std::memcpy(outLayout, inData, inDataSize); + + int relFence = sHandleImporter.unlock(*(halBuf.bufPtr)); + if (relFence >= 0) { + halBuf.acquireFence = relFence; + } + } break; + case PixelFormat::YCBCR_420_888: + case PixelFormat::YV12: { + IMapper::Rect outRect {0, 0, + static_cast(halBuf.width), + static_cast(halBuf.height)}; + YCbCrLayout outLayout = sHandleImporter.lockYCbCr( + *(halBuf.bufPtr), halBuf.usage, outRect); + ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d", + __FUNCTION__, outLayout.y, outLayout.cb, outLayout.cr, + outLayout.yStride, outLayout.cStride, outLayout.chromaStep); + + // Convert to output buffer size/format + uint32_t outputFourcc = V3_4::implementation::getFourCcFromLayout(outLayout); + ALOGV("%s: converting to format %c%c%c%c", __FUNCTION__, + outputFourcc & 0xFF, + (outputFourcc >> 8) & 0xFF, + (outputFourcc >> 16) & 0xFF, + (outputFourcc >> 24) & 0xFF); + + YCbCrLayout cropAndScaled; + ATRACE_BEGIN("cropAndScaleLocked"); + int ret = cropAndScaleLocked( + mYu12Frame, + Size { halBuf.width, halBuf.height }, + &cropAndScaled); + ATRACE_END(); + if (ret != 0) { + lk.unlock(); + return onDeviceError("%s: crop and scale failed!", __FUNCTION__); + } + + Size sz {halBuf.width, halBuf.height}; + ATRACE_BEGIN("formatConvert"); + ret = V3_4::implementation::formatConvert(cropAndScaled, outLayout, sz, outputFourcc); + ATRACE_END(); + if (ret != 0) { + lk.unlock(); + return onDeviceError("%s: format coversion failed!", __FUNCTION__); + } + int relFence = sHandleImporter.unlock(*(halBuf.bufPtr)); + if (relFence >= 0) { + halBuf.acquireFence = relFence; + } + } break; + default: + lk.unlock(); + return onDeviceError("%s: unknown output format %x", __FUNCTION__, halBuf.format); + } + } // for each buffer + mScaledYu12Frames.clear(); + + // Don't hold the lock while calling back to parent + lk.unlock(); + Status st = parent->processCaptureResult(req); + if (st != Status::OK) { + return onDeviceError("%s: failed to process capture result!", __FUNCTION__); + } + signalRequestDone(); + return true; +} + +Status ExternalCameraOfflineSession::importBuffer(int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf) { + Mutex::Autolock _l(mCbsLock); + return V3_4::implementation::importBufferImpl( + mCirculatingBuffers, sHandleImporter, streamId, + bufId, buf, outBufPtr, allowEmptyBuf); + return Status::OK; +}; + +#define UPDATE(md, tag, data, size) \ +do { \ + if ((md).update((tag), (data), (size))) { \ + ALOGE("Update " #tag " failed!"); \ + return BAD_VALUE; \ + } \ +} while (0) + +status_t ExternalCameraOfflineSession::fillCaptureResult( + common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) { + bool afTrigger = false; + { + std::lock_guard lk(mAfTriggerLock); + afTrigger = mAfTrigger; + if (md.exists(ANDROID_CONTROL_AF_TRIGGER)) { + camera_metadata_entry entry = md.find(ANDROID_CONTROL_AF_TRIGGER); + if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) { + mAfTrigger = afTrigger = true; + } else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) { + mAfTrigger = afTrigger = false; + } + } + } + + // For USB camera, the USB camera handles everything and we don't have control + // over AF. We only simply fake the AF metadata based on the request + // received here. + uint8_t afState; + if (afTrigger) { + afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED; + } else { + afState = ANDROID_CONTROL_AF_STATE_INACTIVE; + } + UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1); + + camera_metadata_ro_entry activeArraySize = + mChars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE); + + return V3_4::implementation::fillCaptureResultCommon(md, timestamp, activeArraySize); +} + +#undef UPDATE + +Status ExternalCameraOfflineSession::processCaptureResult(std::shared_ptr& req) { + ATRACE_CALL(); + // Fill output buffers + hidl_vec results; + results.resize(1); + CaptureResult& result = results[0]; + result.frameNumber = req->frameNumber; + result.partialResult = 1; + result.inputBuffer.streamId = -1; + result.outputBuffers.resize(req->buffers.size()); + for (size_t i = 0; i < req->buffers.size(); i++) { + result.outputBuffers[i].streamId = req->buffers[i].streamId; + result.outputBuffers[i].bufferId = req->buffers[i].bufferId; + if (req->buffers[i].fenceTimeout) { + result.outputBuffers[i].status = BufferStatus::ERROR; + if (req->buffers[i].acquireFence >= 0) { + native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0); + handle->data[0] = req->buffers[i].acquireFence; + result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false); + } + notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER); + } else { + result.outputBuffers[i].status = BufferStatus::OK; + // TODO: refactor + if (req->buffers[i].acquireFence >= 0) { + native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0); + handle->data[0] = req->buffers[i].acquireFence; + result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false); + } + } + } + + // Fill capture result metadata + fillCaptureResult(req->setting, req->shutterTs); + const camera_metadata_t *rawResult = req->setting.getAndLock(); + V3_2::implementation::convertToHidl(rawResult, &result.result); + req->setting.unlock(rawResult); + + // Callback into framework + invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true); + V3_4::implementation::freeReleaseFences(results); + return Status::OK; +}; + +void ExternalCameraOfflineSession::invokeProcessCaptureResultCallback( + hidl_vec &results, bool tryWriteFmq) { + if (mProcessCaptureResultLock.tryLock() != OK) { + const nsecs_t NS_TO_SECOND = 1000000000; + ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__); + if (mProcessCaptureResultLock.timedLock(/* 1s */NS_TO_SECOND) != OK) { + ALOGE("%s: cannot acquire lock in 1s, cannot proceed", + __FUNCTION__); + return; + } + } + if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) { + for (CaptureResult &result : results) { + if (result.result.size() > 0) { + if (mResultMetadataQueue->write(result.result.data(), result.result.size())) { + result.fmqResultSize = result.result.size(); + result.result.resize(0); + } else { + ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__); + result.fmqResultSize = 0; + } + } else { + result.fmqResultSize = 0; + } + } + } + auto status = mCallback->processCaptureResult(results); + if (!status.isOk()) { + ALOGE("%s: processCaptureResult ERROR : %s", __FUNCTION__, + status.description().c_str()); + } + + mProcessCaptureResultLock.unlock(); +} + +Status ExternalCameraOfflineSession::processCaptureRequestError( + const std::shared_ptr& req, + /*out*/std::vector* outMsgs, + /*out*/std::vector* outResults) { + ATRACE_CALL(); + + if (outMsgs == nullptr) { + notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST); + } else { + NotifyMsg shutter; + shutter.type = MsgType::SHUTTER; + shutter.msg.shutter.frameNumber = req->frameNumber; + shutter.msg.shutter.timestamp = req->shutterTs; + + NotifyMsg error; + error.type = MsgType::ERROR; + error.msg.error.frameNumber = req->frameNumber; + error.msg.error.errorStreamId = -1; + error.msg.error.errorCode = ErrorCode::ERROR_REQUEST; + outMsgs->push_back(shutter); + outMsgs->push_back(error); + } + + // Fill output buffers + hidl_vec results; + results.resize(1); + CaptureResult& result = results[0]; + result.frameNumber = req->frameNumber; + result.partialResult = 1; + result.inputBuffer.streamId = -1; + result.outputBuffers.resize(req->buffers.size()); + for (size_t i = 0; i < req->buffers.size(); i++) { + result.outputBuffers[i].streamId = req->buffers[i].streamId; + result.outputBuffers[i].bufferId = req->buffers[i].bufferId; + result.outputBuffers[i].status = BufferStatus::ERROR; + if (req->buffers[i].acquireFence >= 0) { + native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0); + handle->data[0] = req->buffers[i].acquireFence; + result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false); + } + } + + if (outResults == nullptr) { + // Callback into framework + invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true); + V3_4::implementation::freeReleaseFences(results); + } else { + outResults->push_back(result); + } + return Status::OK; +}; + +ssize_t ExternalCameraOfflineSession::getJpegBufferSize( + uint32_t /*width*/, uint32_t /*height*/) const { + // Empty implementation here as the jpeg buffer size is passed in by ctor + return 0; +}; + +void ExternalCameraOfflineSession::notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) { + NotifyMsg msg; + msg.type = MsgType::ERROR; + msg.msg.error.frameNumber = frameNumber; + msg.msg.error.errorStreamId = streamId; + msg.msg.error.errorCode = ec; + mCallback->notify({msg}); +}; + +Return ExternalCameraOfflineSession::setCallback(const sp& cb) { + Mutex::Autolock _il(mInterfaceLock); + if (mCallback != nullptr && cb != nullptr) { + ALOGE("%s: callback must not be set twice!", __FUNCTION__); + return Void(); + } + mCallback = cb; + + initOutputThread(); + + if (mOutputThread == nullptr) { + ALOGE("%s: init OutputThread failed!", __FUNCTION__); + } + return Void(); +} + +Return ExternalCameraOfflineSession::getCaptureResultMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) { + Mutex::Autolock _il(mInterfaceLock); + _hidl_cb(*mResultMetadataQueue->getDesc()); + return Void(); +} + +void ExternalCameraOfflineSession::cleanupBuffersLocked(int id) { + for (auto& pair : mCirculatingBuffers.at(id)) { + sHandleImporter.freeBuffer(pair.second); + } + mCirculatingBuffers[id].clear(); + mCirculatingBuffers.erase(id); +} + +Return ExternalCameraOfflineSession::close() { + Mutex::Autolock _il(mInterfaceLock); + { + Mutex::Autolock _l(mLock); + if (mClosed) { + ALOGW("%s: offline session already closed!", __FUNCTION__); + return Void(); + } + } + if (mBufferRequestThread) { + mBufferRequestThread->requestExit(); + mBufferRequestThread->join(); + mBufferRequestThread.clear(); + } + if (mOutputThread) { + mOutputThread->flush(); + mOutputThread->requestExit(); + mOutputThread->join(); + mOutputThread.clear(); + } + + Mutex::Autolock _l(mLock); + // free all buffers + { + Mutex::Autolock _cbl(mCbsLock); + for(auto stream : mOfflineStreams) { + cleanupBuffersLocked(stream.id); + } + } + mCallback.clear(); + mClosed = true; + return Void(); +} + +} // namespace implementation +} // namespace V3_6 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h index 0e57c4c243..db0d9a548b 100644 --- a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h +++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h @@ -14,12 +14,13 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE3SESSION_H -#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE3SESSION_H +#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H #include #include #include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h> +#include "ExternalCameraOfflineSession.h" namespace android { namespace hardware { @@ -37,6 +38,7 @@ using ::android::hardware::camera::device::V3_2::RequestTemplate; using ::android::hardware::camera::device::V3_2::Stream; using ::android::hardware::camera::device::V3_5::StreamConfiguration; using ::android::hardware::camera::device::V3_6::ICameraDeviceSession; +using ::android::hardware::camera::device::V3_6::ICameraOfflineSession; using ::android::hardware::camera::common::V1_0::Status; using ::android::hardware::camera::external::common::ExternalCameraConfig; using ::android::hardware::graphics::common::V1_0::PixelFormat; @@ -69,13 +71,6 @@ struct ExternalCameraDeviceSession : public V3_5::implementation::ExternalCamera return new TrampolineSessionInterface_3_6(this); } - static Status isStreamCombinationSupported(const V3_2::StreamConfiguration& config, - const std::vector& supportedFormats, - const ExternalCameraConfig& devCfg) { - return V3_4::implementation::ExternalCameraDeviceSession::isStreamCombinationSupported( - config, supportedFormats, devCfg); - } - protected: // Methods from v3.5 and earlier will trampoline to inherited implementation Return configureStreams_3_6( @@ -86,6 +81,28 @@ protected: const hidl_vec& streamsToKeep, ICameraDeviceSession::switchToOffline_cb _hidl_cb); + void fillOutputStream3_6(const V3_3::HalStreamConfiguration& outStreams_v33, + /*out*/V3_6::HalStreamConfiguration* outStreams_v36); + bool supportOfflineLocked(int32_t streamId); + + // Main body of switchToOffline. This method does not invoke any callbacks + // but instead returns the necessary callbacks in output arguments so callers + // can callback later without holding any locks + Status switchToOffline(const hidl_vec& offlineStreams, + /*out*/std::vector* msgs, + /*out*/std::vector* results, + /*out*/CameraOfflineSessionInfo* info, + /*out*/sp* session); + + // Whether a request can be completely dropped when switching to offline + bool canDropRequest(const hidl_vec& offlineStreams, + std::shared_ptr halReq); + + void fillOfflineSessionInfo(const hidl_vec& offlineStreams, + std::deque>& offlineReqs, + const std::map& circulatingBuffers, + /*out*/CameraOfflineSessionInfo* info); + private: struct TrampolineSessionInterface_3_6 : public ICameraDeviceSession { @@ -188,4 +205,4 @@ private: } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE3SESSION_H +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h new file mode 100644 index 0000000000..230b67c43c --- /dev/null +++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h @@ -0,0 +1,232 @@ +/* + * 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_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H + +#include +#include +#include +#include +#include +#include +#include +#include <../../3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h> +#include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h> +#include +#include +#include + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_6 { +namespace implementation { + +using ::android::hardware::camera::device::V3_2::BufferCache; +using ::android::hardware::camera::device::V3_5::BufferRequest; +using ::android::hardware::camera::device::V3_5::BufferRequestStatus; +using ::android::hardware::camera::device::V3_2::BufferStatus; +using ::android::hardware::camera::device::V3_2::CameraMetadata; +using ::android::hardware::camera::device::V3_2::CaptureRequest; +using ::android::hardware::camera::device::V3_2::CaptureResult; +using ::android::hardware::camera::device::V3_2::ErrorCode; +using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback; +using ::android::hardware::camera::device::V3_2::MsgType; +using ::android::hardware::camera::device::V3_2::NotifyMsg; +using ::android::hardware::camera::device::V3_2::RequestTemplate; +using ::android::hardware::camera::device::V3_2::Stream; +using ::android::hardware::camera::device::V3_5::StreamConfiguration; +using ::android::hardware::camera::device::V3_2::StreamConfigurationMode; +using ::android::hardware::camera::device::V3_2::StreamRotation; +using ::android::hardware::camera::device::V3_2::StreamType; +using ::android::hardware::camera::device::V3_2::DataspaceFlags; +using ::android::hardware::camera::device::V3_2::CameraBlob; +using ::android::hardware::camera::device::V3_2::CameraBlobId; +using ::android::hardware::camera::device::V3_4::HalStreamConfiguration; +using ::android::hardware::camera::device::V3_6::ICameraOfflineSession; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::common::V1_0::helper::HandleImporter; +using ::android::hardware::camera::common::V1_0::helper::ExifUtils; +using ::android::hardware::camera::external::common::ExternalCameraConfig; +using ::android::hardware::camera::external::common::Size; +using ::android::hardware::camera::external::common::SizeHasher; +using ::android::hardware::graphics::common::V1_0::BufferUsage; +using ::android::hardware::graphics::common::V1_0::Dataspace; +using ::android::hardware::graphics::common::V1_0::PixelFormat; +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; +using ::android::hardware::MQDescriptorSync; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; +using ::android::Mutex; +using ::android::base::unique_fd; + +using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format; +using ::android::hardware::camera::device::V3_4::implementation::CroppingType; +using ::android::hardware::camera::device::V3_4::implementation::CirculatingBuffers; +using ::android::hardware::camera::device::V3_4::implementation::HalRequest; +using ::android::hardware::camera::device::V3_4::implementation::OutputThreadInterface; + +struct ExternalCameraOfflineSession : public virtual RefBase, + public virtual OutputThreadInterface { + + ExternalCameraOfflineSession( + const CroppingType& croppingType, + const common::V1_0::helper::CameraMetadata& chars, + const std::string& cameraId, + const std::string& exifMake, + const std::string& exifModel, + uint32_t blobBufferSize, + bool afTrigger, + const hidl_vec& offlineStreams, + std::deque>& offlineReqs, + const std::map& circulatingBuffers); + + bool initialize(); + + virtual ~ExternalCameraOfflineSession(); + + // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when + // dealing with minor version revs and simultaneous implementation and interface inheritance + virtual sp getInterface() { + return new TrampolineSessionInterface_3_6(this); + } + +protected: + + // Methods from OutputThreadInterface + virtual Status importBuffer(int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf) override; + + virtual Status processCaptureResult(std::shared_ptr&) override; + + virtual Status processCaptureRequestError(const std::shared_ptr&, + /*out*/std::vector* msgs = nullptr, + /*out*/std::vector* results = nullptr) override; + + virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override; + + virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override; + // End of OutputThreadInterface methods + + class OutputThread : public V3_5::implementation::ExternalCameraDeviceSession::OutputThread { + public: + OutputThread( + wp parent, CroppingType ct, + const common::V1_0::helper::CameraMetadata& chars, + sp bufReqThread, + std::deque>& offlineReqs) : + V3_5::implementation::ExternalCameraDeviceSession::OutputThread( + parent, ct, chars, bufReqThread), + mOfflineReqs(offlineReqs) {} + + virtual bool threadLoop() override; + + protected: + std::deque> mOfflineReqs; + }; // OutputThread + + + Return setCallback(const sp& cb); + + Return getCaptureResultMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb); + + Return close(); + + void initOutputThread(); + + void invokeProcessCaptureResultCallback( + hidl_vec &results, bool tryWriteFmq); + + status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp); + + void cleanupBuffersLocked(int id); + + // Protect (most of) HIDL interface methods from synchronized-entering + mutable Mutex mInterfaceLock; + + mutable Mutex mLock; // Protect all data members except otherwise noted + + bool mClosed = false; + const CroppingType mCroppingType; + const common::V1_0::helper::CameraMetadata mChars; + const std::string mCameraId; + const std::string mExifMake; + const std::string mExifModel; + const uint32_t mBlobBufferSize; + + std::mutex mAfTriggerLock; // protect mAfTrigger + bool mAfTrigger; + + const hidl_vec mOfflineStreams; + std::deque> mOfflineReqs; + + // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock + mutable Mutex mCbsLock; + std::map mCirculatingBuffers; + + static HandleImporter sHandleImporter; + + using ResultMetadataQueue = MessageQueue; + std::shared_ptr mResultMetadataQueue; + + // Protect against invokeProcessCaptureResultCallback() + Mutex mProcessCaptureResultLock; + + sp mCallback; + + sp mBufferRequestThread; + sp mOutputThread; +private: + + struct TrampolineSessionInterface_3_6 : public ICameraOfflineSession { + TrampolineSessionInterface_3_6(sp parent) : + mParent(parent) {} + + virtual Return setCallback(const sp& cb) override { + return mParent->setCallback(cb); + } + + virtual Return getCaptureResultMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override { + return mParent->getCaptureResultMetadataQueue(_hidl_cb); + } + + virtual Return close() override { + return mParent->close(); + } + + private: + sp mParent; + }; +}; + +} // namespace implementation +} // namespace V3_6 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H diff --git a/camera/provider/2.5/default/Android.bp b/camera/provider/2.5/default/Android.bp index 4563362ddb..9ddf651440 100644 --- a/camera/provider/2.5/default/Android.bp +++ b/camera/provider/2.5/default/Android.bp @@ -52,6 +52,8 @@ cc_library_shared { "android.hardware.camera.provider@2.4-external", "android.hardware.camera.provider@2.5", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "camera.device@3.3-impl", @@ -72,7 +74,8 @@ cc_library_shared { ], header_libs: [ "camera.device@3.4-external-impl_headers", - "camera.device@3.5-external-impl_headers" + "camera.device@3.5-external-impl_headers", + "camera.device@3.6-external-impl_headers" ], export_include_dirs: ["."], } @@ -165,7 +168,10 @@ cc_binary { "android.hardware.camera.provider@2.5", "android.hardware.camera.provider@2.5-external", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "libbinder", + "libcamera_metadata", "libhidlbase", "liblog", "libtinyxml2", @@ -179,5 +185,6 @@ cc_binary { "camera.device@3.4-impl_headers", "camera.device@3.5-external-impl_headers", "camera.device@3.5-impl_headers", + "camera.device@3.6-external-impl_headers", ], } From 9ab6b3eb3e975375521520f9e25d4c41bc423332 Mon Sep 17 00:00:00 2001 From: Emilian Peev Date: Tue, 14 Jan 2020 15:48:07 -0800 Subject: [PATCH 0529/1022] Camera: Verify offline session behavior in VTS Camera offline sessions can be used as way to free up and share camera resources. Check that the corresponding HIDL API behaves as per documentation. Bug: 135142453 Test: adb shell /system/bin/VtsHalCameraProviderV2_4TargetTest --hal_service_instance=android.hardware.camera.provider@2.4::ICameraProvider/internal/0 Change-Id: I5b714061894eb2b0179a44dcedf81b0155fb4b54 --- camera/provider/2.4/vts/functional/Android.bp | 3 +- .../VtsHalCameraProviderV2_4TargetTest.cpp | 286 ++++++++++++++++++ 2 files changed, 288 insertions(+), 1 deletion(-) diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp index d14ccfaf2e..450516c5f8 100644 --- a/camera/provider/2.4/vts/functional/Android.bp +++ b/camera/provider/2.4/vts/functional/Android.bp @@ -38,7 +38,8 @@ cc_test { "android.hardware.camera.device@3.3", "android.hardware.camera.device@3.4", "android.hardware.camera.device@3.5", - "android.hardware.camera.metadata@3.4", + "android.hardware.camera.device@3.6", + "android.hardware.camera.metadata@3.4", "android.hardware.camera.provider@2.4", "android.hardware.camera.provider@2.5", "android.hardware.graphics.common@1.0", diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 650ec8b81d..3a3ad4ab66 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -724,6 +725,15 @@ public: ::android::hardware::camera::device::V3_5::StreamConfiguration *config3_5, uint32_t jpegBufferSize = 0); + void configureOfflinePreviewStream(const std::string &name, + sp provider, + const AvailableStream *previewThreshold, + sp *session/*out*/, + V3_2::Stream *previewStream /*out*/, + device::V3_6::HalStreamConfiguration *halStreamConfig /*out*/, + bool *supportsPartialResults /*out*/, + uint32_t *partialResultCount /*out*/, + sp *outCb /*out*/); void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion, sp provider, const AvailableStream *previewThreshold, @@ -789,6 +799,7 @@ public: uint32_t* outBufSize); static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta); static Status isLogicalMultiCamera(const camera_metadata_t *staticMeta); + static Status isOfflineSessionSupported(const camera_metadata_t *staticMeta); static Status getPhysicalCameraIds(const camera_metadata_t *staticMeta, std::unordered_set *physicalIds/*out*/); static Status getSupportedKeys(camera_metadata_t *staticMeta, @@ -4572,6 +4583,157 @@ TEST_P(CameraHidlTest, processCaptureRequestInvalidSinglePreview) { } } +// Verify camera offline session behavior +TEST_P(CameraHidlTest, switchToOffline) { + hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); + AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, + static_cast(PixelFormat::IMPLEMENTATION_DEFINED)}; + uint64_t bufferId = 1; + uint32_t frameNumber = 1; + ::android::hardware::hidl_vec settings; + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) { + continue; + } else if (deviceVersion <= 0) { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + return; + } + + camera_metadata_t* staticMetaBuffer; + { + Return ret; + sp session; + openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/); + ::android::hardware::camera::common::V1_0::helper::CameraMetadata staticMeta( + staticMetaBuffer); + + if (isOfflineSessionSupported(staticMetaBuffer) != Status::OK) { + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + continue; + } + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + } + + bool supportsPartialResults = false; + uint32_t partialResultCount = 0; + V3_2::Stream previewStream; + V3_6::HalStreamConfiguration halStreamConfig; + sp session; + sp cb; + configureOfflinePreviewStream(name, mProvider, &previewThreshold, + &session /*out*/, &previewStream /*out*/, &halStreamConfig /*out*/, + &supportsPartialResults /*out*/, &partialResultCount /*out*/, &cb /*out*/); + + auto ret = session->constructDefaultRequestSettings(RequestTemplate::PREVIEW, + [&](auto status, const auto& req) { + ASSERT_EQ(Status::OK, status); + settings = req; }); + ASSERT_TRUE(ret.isOk()); + + ::android::hardware::camera::common::V1_0::helper::CameraMetadata requestMeta; + StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr}; + hidl_handle buffers[kBurstFrameCount]; + StreamBuffer outputBuffers[kBurstFrameCount]; + CaptureRequest requests[kBurstFrameCount]; + InFlightRequest inflightReqs[kBurstFrameCount]; + hidl_vec requestSettings[kBurstFrameCount]; + auto halStreamConfig3_2 = halStreamConfig.streams[0].v3_4.v3_3.v3_2; + for (uint32_t i = 0; i < kBurstFrameCount; i++) { + std::unique_lock l(mLock); + + allocateGraphicBuffer(previewStream.width, previewStream.height, + android_convertGralloc1To0Usage(halStreamConfig3_2.producerUsage, + halStreamConfig3_2.consumerUsage), + halStreamConfig3_2.overrideFormat, &buffers[i]); + outputBuffers[i] = {halStreamConfig3_2.id, bufferId + i, + buffers[i], BufferStatus::OK, nullptr, nullptr}; + + requestMeta.clear(); + requestMeta.append(reinterpret_cast (settings.data())); + + camera_metadata_t *metaBuffer = requestMeta.release(); + requestSettings[i].setToExternal(reinterpret_cast (metaBuffer), + get_camera_metadata_size(metaBuffer), true); + + requests[i] = {frameNumber + i, 0 /* fmqSettingsSize */, requestSettings[i], + emptyInputBuffer, {outputBuffers[i]}}; + + inflightReqs[i] = {1, false, supportsPartialResults, partialResultCount, + nullptr /*resultQueue*/}; + mInflightMap.add(frameNumber + i, &inflightReqs[i]); + } + + Status status = Status::INTERNAL_ERROR; + hidl_vec cachesToRemove; + hidl_vec burstRequest; + burstRequest.setToExternal(requests, kBurstFrameCount); + Return returnStatus = session->processCaptureRequest(burstRequest, cachesToRemove, + [] (auto , uint32_t ) {}); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, status); + + hidl_vec offlineStreamIds = {halStreamConfig3_2.id}; + V3_6::CameraOfflineSessionInfo offlineSessionInfo; + sp offlineSession; + returnStatus = session->switchToOffline(offlineStreamIds, + [&status, &offlineSessionInfo, &offlineSession] (auto stat, auto info, + auto offSession) { + status = stat; + offlineSessionInfo = info; + offlineSession = offSession; + }); + ASSERT_TRUE(returnStatus.isOk()); + + if (!halStreamConfig.streams[0].supportOffline) { + ASSERT_EQ(status, Status::ILLEGAL_ARGUMENT); + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + continue; + } + + ASSERT_EQ(status, Status::OK); + // Hal might be unable to find any requests qualified for offline mode. + if (offlineSession == nullptr) { + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + continue; + } + + ASSERT_EQ(offlineSessionInfo.offlineStreams.size(), 1u); + ASSERT_EQ(offlineSessionInfo.offlineStreams[0].id, halStreamConfig3_2.id); + ASSERT_NE(offlineSessionInfo.offlineRequests.size(), 0u); + + ret = offlineSession->setCallback(cb); + ASSERT_TRUE(ret.isOk()); + + for (size_t i = 0; i < kBurstFrameCount; i++) { + std::unique_lock l(mLock); + while (!inflightReqs[i].errorCodeValid && ((0 < inflightReqs[i].numBuffersLeft) || + (!inflightReqs[i].haveResultMetadata))) { + auto timeout = std::chrono::system_clock::now() + + std::chrono::seconds(kStreamBufferTimeoutSec); + ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout)); + } + + ASSERT_FALSE(inflightReqs[i].errorCodeValid); + ASSERT_NE(inflightReqs[i].resultOutputBuffers.size(), 0u); + ASSERT_EQ(previewStream.id, inflightReqs[i].resultOutputBuffers[0].streamId); + ASSERT_FALSE(inflightReqs[i].collectedResult.isEmpty()); + } + + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + + ret = offlineSession->close(); + ASSERT_TRUE(ret.isOk()); + } +} + // Check whether an invalid capture request with missing output buffers // will be reported correctly. TEST_P(CameraHidlTest, processCaptureRequestInvalidBuffer) { @@ -4931,6 +5093,30 @@ Status CameraHidlTest::isLogicalMultiCamera(const camera_metadata_t *staticMeta) return ret; } +// Check if the camera device has logical multi-camera capability. +Status CameraHidlTest::isOfflineSessionSupported(const camera_metadata_t *staticMeta) { + Status ret = Status::METHOD_NOT_SUPPORTED; + if (nullptr == staticMeta) { + return Status::ILLEGAL_ARGUMENT; + } + + camera_metadata_ro_entry entry; + int rc = find_camera_metadata_ro_entry(staticMeta, + ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry); + if (0 != rc) { + return Status::ILLEGAL_ARGUMENT; + } + + for (size_t i = 0; i < entry.count; i++) { + if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING == entry.data.u8[i]) { + ret = Status::OK; + break; + } + } + + return ret; +} + // Generate a list of physical camera ids backing a logical multi-camera. Status CameraHidlTest::getPhysicalCameraIds(const camera_metadata_t *staticMeta, std::unordered_set *physicalIds) { @@ -5382,6 +5568,106 @@ void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t ASSERT_TRUE(ret.isOk()); } +// Configure preview stream with possible offline session support +void CameraHidlTest::configureOfflinePreviewStream(const std::string &name, + sp provider, + const AvailableStream *previewThreshold, + sp *session/*out*/, + V3_2::Stream *previewStream /*out*/, + device::V3_6::HalStreamConfiguration *halStreamConfig /*out*/, + bool *supportsPartialResults /*out*/, + uint32_t *partialResultCount /*out*/, + sp *outCb /*out*/) { + ASSERT_NE(nullptr, session); + ASSERT_NE(nullptr, halStreamConfig); + ASSERT_NE(nullptr, previewStream); + ASSERT_NE(nullptr, supportsPartialResults); + ASSERT_NE(nullptr, partialResultCount); + ASSERT_NE(nullptr, outCb); + + std::vector outputPreviewStreams; + ::android::sp cameraDevice; + ALOGI("configureStreams: Testing camera device %s", name.c_str()); + Return ret; + ret = provider->getCameraDeviceInterface_V3_x( + name, + [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", + (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + cameraDevice = device; + }); + ASSERT_TRUE(ret.isOk()); + + camera_metadata_t *staticMeta; + ret = cameraDevice->getCameraCharacteristics([&] (Status s, + CameraMetadata metadata) { + ASSERT_EQ(Status::OK, s); + staticMeta = clone_camera_metadata( + reinterpret_cast(metadata.data())); + ASSERT_NE(nullptr, staticMeta); + }); + ASSERT_TRUE(ret.isOk()); + + camera_metadata_ro_entry entry; + auto status = find_camera_metadata_ro_entry(staticMeta, + ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry); + if ((0 == status) && (entry.count > 0)) { + *partialResultCount = entry.data.i32[0]; + *supportsPartialResults = (*partialResultCount > 1); + } + + ret = cameraDevice->open(*outCb, [&session](auto status, const auto& newSession) { + ALOGI("device::open returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(newSession, nullptr); + auto castResult = device::V3_6::ICameraDeviceSession::castFrom(newSession); + ASSERT_TRUE(castResult.isOk()); + *session = castResult; + }); + ASSERT_TRUE(ret.isOk()); + + outputPreviewStreams.clear(); + auto rc = getAvailableOutputStreams(staticMeta, + outputPreviewStreams, previewThreshold); + free_camera_metadata(staticMeta); + ASSERT_EQ(Status::OK, rc); + ASSERT_FALSE(outputPreviewStreams.empty()); + + V3_2::DataspaceFlags dataspaceFlag = 0; + switch (static_cast(outputPreviewStreams[0].format)) { + case PixelFormat::Y16: + dataspaceFlag = static_cast(Dataspace::DEPTH); + break; + default: + dataspaceFlag = static_cast(Dataspace::UNKNOWN); + } + + ::android::hardware::hidl_vec streams3_4; + V3_4::Stream stream3_4 = {{ 0 /*streamId*/, StreamType::OUTPUT, + static_cast (outputPreviewStreams[0].width), + static_cast (outputPreviewStreams[0].height), + static_cast (outputPreviewStreams[0].format), + GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, dataspaceFlag, StreamRotation::ROTATION_0}, + nullptr /*physicalId*/, /*bufferSize*/ 0}; + streams3_4[0] = stream3_4; + + ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4; + ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5; + config3_4 = {streams3_4, StreamConfigurationMode::NORMAL_MODE, {}}; + + config3_5.v3_4 = config3_4; + config3_5.streamConfigCounter = 0; + ret = (*session)->configureStreams_3_6(config3_5, + [&] (Status s, device::V3_6::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + *halStreamConfig = halConfig; + }); + *previewStream = streams3_4[0].v3_2; + ASSERT_TRUE(ret.isOk()); +} + bool CameraHidlTest::isDepthOnly(camera_metadata_t* staticMeta) { camera_metadata_ro_entry scalarEntry; camera_metadata_ro_entry depthEntry; From 97978fbe32a20431c7899d15eadaacd9c09490da Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Sat, 25 Jan 2020 18:15:00 -0800 Subject: [PATCH 0530/1022] Camera: fix offline processing VTS/CTS Test: camera VTS test + add manual delay to webcam HAL output thread so there will be some requests left for offline processing camera CTS OfflineSessionTest Bug: 135142453 Change-Id: If5718350707ef051f96b96da75f934089b10467d --- camera/common/1.0/default/HandleImporter.cpp | 5 +- .../3.4/default/ExternalCameraUtils.cpp | 1 + .../ExternalCameraDeviceSession.h | 2 +- .../default/ExternalCameraDeviceSession.cpp | 16 +- .../VtsHalCameraProviderV2_4TargetTest.cpp | 253 ++++++++++++++---- 5 files changed, 210 insertions(+), 67 deletions(-) diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp index ac32c954c4..7792b31880 100644 --- a/camera/common/1.0/default/HandleImporter.cpp +++ b/camera/common/1.0/default/HandleImporter.cpp @@ -182,9 +182,8 @@ void HandleImporter::freeBuffer(buffer_handle_t handle) { } Mutex::Autolock lock(mLock); - if (mMapperV4 == nullptr && mMapperV3 == nullptr && mMapperV2 == nullptr) { - ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__); - return; + if (!mInitialized) { + initializeLocked(); } if (mMapperV4 != nullptr) { diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp index 4a6381ea7b..62a4c87af5 100644 --- a/camera/device/3.4/default/ExternalCameraUtils.cpp +++ b/camera/device/3.4/default/ExternalCameraUtils.cpp @@ -519,6 +519,7 @@ int encodeJpegYU12( yLines[i] = static_cast(py + li * inLayout.yStride); if(i < paddedHeight / cVSubSampling) { + li = std::min(i, (inSz.height - 1) / cVSubSampling); crLines[i] = static_cast(pcr + li * inLayout.cStride); cbLines[i] = static_cast(pcb + li * inLayout.cStride); } diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h index ecab9cfa03..180f0c155a 100644 --- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h +++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h @@ -321,7 +321,7 @@ protected: const common::V1_0::helper::CameraMetadata mCameraCharacteristics; const std::vector mSupportedFormats; const CroppingType mCroppingType; - const std::string& mCameraId; + const std::string mCameraId; // Not protected by mLock, this is almost a const. // Setup in constructor, reset in close() after OutputThread is joined diff --git a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp index 0cc81bbe9e..60a1a1019c 100644 --- a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp +++ b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp @@ -149,10 +149,6 @@ void ExternalCameraDeviceSession::fillOfflineSessionInfo(const hidl_vec info->offlineStreams.resize(offlineStreams.size()); info->offlineRequests.resize(offlineReqs.size()); - std::unordered_map outstandingBufs(offlineStreams.size()); - for (const auto streamId : offlineStreams) { - outstandingBufs.insert({streamId, 0}); - } // Fill in offline reqs and count outstanding buffers for (size_t i = 0; i < offlineReqs.size(); i++) { info->offlineRequests[i].frameNumber = offlineReqs[i]->frameNumber; @@ -160,14 +156,15 @@ void ExternalCameraDeviceSession::fillOfflineSessionInfo(const hidl_vec for (size_t bIdx = 0; bIdx < offlineReqs[i]->buffers.size(); bIdx++) { int32_t streamId = offlineReqs[i]->buffers[bIdx].streamId; info->offlineRequests[i].pendingStreams[bIdx] = streamId; - outstandingBufs[streamId]++; } } for (size_t i = 0; i < offlineStreams.size(); i++) { int32_t streamId = offlineStreams[i]; info->offlineStreams[i].id = streamId; - info->offlineStreams[i].numOutstandingBuffers = outstandingBufs[streamId]; + // outstanding buffers are 0 since we are doing hal buffer management and + // offline session will ask for those buffers later + info->offlineStreams[i].numOutstandingBuffers = 0; const CirculatingBuffers& bufIdMap = circulatingBuffers.at(streamId); info->offlineStreams[i].circulatingBufferIds.resize(bufIdMap.size()); size_t bIdx = 0; @@ -345,7 +342,12 @@ Status ExternalCameraDeviceSession::switchToOffline(const hidl_vec& off return Status::INTERNAL_ERROR; } - *session = sessionImpl->getInterface(); + // No need to return session if there is no offline requests left + if (offlineReqs.size() != 0) { + *session = sessionImpl->getInterface(); + } else { + *session = nullptr; + } return Status::OK; } diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 3a3ad4ab66..75b1f5075c 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -132,6 +132,8 @@ using namespace ::android::hardware::camera; const uint32_t kMaxPreviewWidth = 1920; const uint32_t kMaxPreviewHeight = 1080; +const uint32_t kMaxStillWidth = 2048; +const uint32_t kMaxStillHeight = 1536; const uint32_t kMaxVideoWidth = 4096; const uint32_t kMaxVideoHeight = 2160; const int64_t kStreamBufferTimeoutSec = 3; @@ -161,11 +163,13 @@ enum ReprocessType { namespace { // "device@/legacy/" const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)"; + const int CAMERA_DEVICE_API_VERSION_3_6 = 0x306; const int CAMERA_DEVICE_API_VERSION_3_5 = 0x305; const int CAMERA_DEVICE_API_VERSION_3_4 = 0x304; const int CAMERA_DEVICE_API_VERSION_3_3 = 0x303; const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302; const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100; + const char *kHAL3_6 = "3.6"; const char *kHAL3_5 = "3.5"; const char *kHAL3_4 = "3.4"; const char *kHAL3_3 = "3.3"; @@ -201,7 +205,9 @@ namespace { return -1; } - if (version.compare(kHAL3_5) == 0) { + if (version.compare(kHAL3_6) == 0) { + return CAMERA_DEVICE_API_VERSION_3_6; + } else if (version.compare(kHAL3_5) == 0) { return CAMERA_DEVICE_API_VERSION_3_5; } else if (version.compare(kHAL3_4) == 0) { return CAMERA_DEVICE_API_VERSION_3_4; @@ -715,7 +721,8 @@ public: void castSession(const sp &session, int32_t deviceVersion, sp *session3_3 /*out*/, sp *session3_4 /*out*/, - sp *session3_5 /*out*/); + sp *session3_5 /*out*/, + sp *session3_6 /*out*/); void castDevice(const sp &device, int32_t deviceVersion, sp *device3_5/*out*/); void createStreamConfiguration(const ::android::hardware::hidl_vec& streams3_2, @@ -725,15 +732,17 @@ public: ::android::hardware::camera::device::V3_5::StreamConfiguration *config3_5, uint32_t jpegBufferSize = 0); - void configureOfflinePreviewStream(const std::string &name, + void configureOfflineStillStream(const std::string &name, int32_t deviceVersion, sp provider, - const AvailableStream *previewThreshold, + const AvailableStream *threshold, sp *session/*out*/, - V3_2::Stream *previewStream /*out*/, + V3_2::Stream *stream /*out*/, device::V3_6::HalStreamConfiguration *halStreamConfig /*out*/, bool *supportsPartialResults /*out*/, uint32_t *partialResultCount /*out*/, - sp *outCb /*out*/); + sp *outCb /*out*/, + uint32_t *jpegBufferSize /*out*/, + bool *useHalBufManager /*out*/); void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion, sp provider, const AvailableStream *previewThreshold, @@ -826,6 +835,9 @@ public: CameraParameters &cameraParams, const char *mode) ; static Status isMonochromeCamera(const camera_metadata_t *staticMeta); + // Used by switchToOffline where a new result queue is created for offline reqs + void updateInflightResultQueue(std::shared_ptr resultQueue); + protected: // In-flight queue for tracking completion of capture requests. @@ -1449,7 +1461,13 @@ Return CameraHidlTest::DeviceCb::requestStreamBuffers( hidl_vec tmpRetBuffers(bufReq.numBuffersRequested); for (size_t j = 0; j < bufReq.numBuffersRequested; j++) { hidl_handle buffer_handle; - mParent->allocateGraphicBuffer(stream.v3_2.width, stream.v3_2.height, + uint32_t w = stream.v3_2.width; + uint32_t h = stream.v3_2.height; + if (stream.v3_2.format == PixelFormat::BLOB) { + w = stream.bufferSize; + h = 1; + } + mParent->allocateGraphicBuffer(w, h, android_convertGralloc1To0Usage( halStream.producerUsage, halStream.consumerUsage), halStream.overrideFormat, &buffer_handle); @@ -1676,6 +1694,7 @@ TEST_P(CameraHidlTest, getCameraDeviceInterface) { for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_6: case CAMERA_DEVICE_API_VERSION_3_5: case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_3: @@ -1718,6 +1737,7 @@ TEST_P(CameraHidlTest, getResourceCost) { for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_6: case CAMERA_DEVICE_API_VERSION_3_5: case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_3: @@ -2459,6 +2479,7 @@ TEST_P(CameraHidlTest, getCameraCharacteristics) { for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_6: case CAMERA_DEVICE_API_VERSION_3_5: case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_3: @@ -2538,6 +2559,7 @@ TEST_P(CameraHidlTest, setTorchMode) { for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_6: case CAMERA_DEVICE_API_VERSION_3_5: case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_3: @@ -2664,6 +2686,7 @@ TEST_P(CameraHidlTest, dumpState) { for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_6: case CAMERA_DEVICE_API_VERSION_3_5: case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_3: @@ -2729,6 +2752,7 @@ TEST_P(CameraHidlTest, openClose) { for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_6: case CAMERA_DEVICE_API_VERSION_3_5: case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_3: @@ -2758,8 +2782,12 @@ TEST_P(CameraHidlTest, openClose) { sp sessionV3_3; sp sessionV3_4; sp sessionV3_5; - castSession(session, deviceVersion, &sessionV3_3, &sessionV3_4, &sessionV3_5); - if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) { + sp sessionV3_6; + castSession(session, deviceVersion, &sessionV3_3, + &sessionV3_4, &sessionV3_5, &sessionV3_6); + if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_6) { + ASSERT_TRUE(sessionV3_6.get() != nullptr); + } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) { ASSERT_TRUE(sessionV3_5.get() != nullptr); } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) { ASSERT_TRUE(sessionV3_4.get() != nullptr); @@ -2821,6 +2849,7 @@ TEST_P(CameraHidlTest, constructDefaultRequestSettings) { for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_6: case CAMERA_DEVICE_API_VERSION_3_5: case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_3: @@ -2919,11 +2948,12 @@ TEST_P(CameraHidlTest, configureStreamsAvailableOutputs) { sp session3_3; sp session3_4; sp session3_5; + sp session3_6; sp cameraDevice; sp cameraDevice3_5; openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/, &cameraDevice /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6); castDevice(cameraDevice, deviceVersion, &cameraDevice3_5); outputStreams.clear(); @@ -3027,11 +3057,12 @@ TEST_P(CameraHidlTest, configureStreamsInvalidOutputs) { sp session3_3; sp session3_4; sp session3_5; + sp session3_6; sp cameraDevice; sp cameraDevice3_5; openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/, &cameraDevice /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6); castDevice(cameraDevice, deviceVersion, &cameraDevice3_5); outputStreams.clear(); @@ -3224,11 +3255,12 @@ TEST_P(CameraHidlTest, configureStreamsZSLInputOutputs) { sp session3_3; sp session3_4; sp session3_5; + sp session3_6; sp cameraDevice; sp cameraDevice3_5; openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/, &cameraDevice /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6); castDevice(cameraDevice, deviceVersion, &cameraDevice3_5); Status rc = isZSLModeAvailable(staticMeta); @@ -3391,8 +3423,9 @@ TEST_P(CameraHidlTest, configureStreamsWithSessionParameters) { sp session3_3; sp session3_4; sp session3_5; + sp session3_6; openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6); if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) { ASSERT_NE(session3_4, nullptr); } else { @@ -3513,11 +3546,12 @@ TEST_P(CameraHidlTest, configureStreamsPreviewStillOutputs) { sp session3_3; sp session3_4; sp session3_5; + sp session3_6; sp cameraDevice; sp cameraDevice3_5; openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/, &cameraDevice /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6); castDevice(cameraDevice, deviceVersion, &cameraDevice3_5); // Check if camera support depth only @@ -3630,11 +3664,12 @@ TEST_P(CameraHidlTest, configureStreamsConstrainedOutputs) { sp session3_3; sp session3_4; sp session3_5; + sp session3_6; sp cameraDevice; sp cameraDevice3_5; openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/, &cameraDevice /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6); castDevice(cameraDevice, deviceVersion, &cameraDevice3_5); Status rc = isConstrainedModeAvailable(staticMeta); @@ -3841,11 +3876,12 @@ TEST_P(CameraHidlTest, configureStreamsVideoStillOutputs) { sp session3_3; sp session3_4; sp session3_5; + sp session3_6; sp cameraDevice; sp cameraDevice3_5; openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/, &cameraDevice /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6); castDevice(cameraDevice, deviceVersion, &cameraDevice3_5); // Check if camera support depth only @@ -4586,8 +4622,8 @@ TEST_P(CameraHidlTest, processCaptureRequestInvalidSinglePreview) { // Verify camera offline session behavior TEST_P(CameraHidlTest, switchToOffline) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); - AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, - static_cast(PixelFormat::IMPLEMENTATION_DEFINED)}; + AvailableStream threshold = {kMaxStillWidth, kMaxStillHeight, + static_cast(PixelFormat::BLOB)}; uint64_t bufferId = 1; uint32_t frameNumber = 1; ::android::hardware::hidl_vec settings; @@ -4621,20 +4657,39 @@ TEST_P(CameraHidlTest, switchToOffline) { bool supportsPartialResults = false; uint32_t partialResultCount = 0; - V3_2::Stream previewStream; + V3_2::Stream stream; V3_6::HalStreamConfiguration halStreamConfig; sp session; sp cb; - configureOfflinePreviewStream(name, mProvider, &previewThreshold, - &session /*out*/, &previewStream /*out*/, &halStreamConfig /*out*/, - &supportsPartialResults /*out*/, &partialResultCount /*out*/, &cb /*out*/); + uint32_t jpegBufferSize; + bool useHalBufManager; + configureOfflineStillStream(name, deviceVersion, mProvider, &threshold, + &session /*out*/, &stream /*out*/, &halStreamConfig /*out*/, + &supportsPartialResults /*out*/, &partialResultCount /*out*/, &cb /*out*/, + &jpegBufferSize /*out*/, &useHalBufManager /*out*/); - auto ret = session->constructDefaultRequestSettings(RequestTemplate::PREVIEW, + auto ret = session->constructDefaultRequestSettings(RequestTemplate::STILL_CAPTURE, [&](auto status, const auto& req) { ASSERT_EQ(Status::OK, status); settings = req; }); ASSERT_TRUE(ret.isOk()); + std::shared_ptr resultQueue; + auto resultQueueRet = + session->getCaptureResultMetadataQueue( + [&resultQueue](const auto& descriptor) { + resultQueue = std::make_shared( + descriptor); + if (!resultQueue->isValid() || + resultQueue->availableToWrite() <= 0) { + ALOGE("%s: HAL returns empty result metadata fmq," + " not use it", __func__); + resultQueue = nullptr; + // Don't use the queue onwards. + } + }); + ASSERT_TRUE(resultQueueRet.isOk()); + ::android::hardware::camera::common::V1_0::helper::CameraMetadata requestMeta; StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr}; hidl_handle buffers[kBurstFrameCount]; @@ -4646,12 +4701,18 @@ TEST_P(CameraHidlTest, switchToOffline) { for (uint32_t i = 0; i < kBurstFrameCount; i++) { std::unique_lock l(mLock); - allocateGraphicBuffer(previewStream.width, previewStream.height, - android_convertGralloc1To0Usage(halStreamConfig3_2.producerUsage, - halStreamConfig3_2.consumerUsage), - halStreamConfig3_2.overrideFormat, &buffers[i]); - outputBuffers[i] = {halStreamConfig3_2.id, bufferId + i, - buffers[i], BufferStatus::OK, nullptr, nullptr}; + if (useHalBufManager) { + outputBuffers[i] = {halStreamConfig3_2.id, /*bufferId*/ 0, + buffers[i], BufferStatus::OK, nullptr, nullptr}; + } else { + // jpeg buffer (w,h) = (blobLen, 1) + allocateGraphicBuffer(jpegBufferSize, /*height*/1, + android_convertGralloc1To0Usage(halStreamConfig3_2.producerUsage, + halStreamConfig3_2.consumerUsage), + halStreamConfig3_2.overrideFormat, &buffers[i]); + outputBuffers[i] = {halStreamConfig3_2.id, bufferId + i, + buffers[i], BufferStatus::OK, nullptr, nullptr}; + } requestMeta.clear(); requestMeta.append(reinterpret_cast (settings.data())); @@ -4664,18 +4725,23 @@ TEST_P(CameraHidlTest, switchToOffline) { emptyInputBuffer, {outputBuffers[i]}}; inflightReqs[i] = {1, false, supportsPartialResults, partialResultCount, - nullptr /*resultQueue*/}; + resultQueue}; mInflightMap.add(frameNumber + i, &inflightReqs[i]); } Status status = Status::INTERNAL_ERROR; + uint32_t numRequestProcessed = 0; hidl_vec cachesToRemove; hidl_vec burstRequest; burstRequest.setToExternal(requests, kBurstFrameCount); Return returnStatus = session->processCaptureRequest(burstRequest, cachesToRemove, - [] (auto , uint32_t ) {}); + [&status, &numRequestProcessed] (auto s, uint32_t n) { + status = s; + numRequestProcessed = n; + }); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, status); + ASSERT_EQ(numRequestProcessed, kBurstFrameCount); hidl_vec offlineStreamIds = {halStreamConfig3_2.id}; V3_6::CameraOfflineSessionInfo offlineSessionInfo; @@ -4708,6 +4774,28 @@ TEST_P(CameraHidlTest, switchToOffline) { ASSERT_EQ(offlineSessionInfo.offlineStreams[0].id, halStreamConfig3_2.id); ASSERT_NE(offlineSessionInfo.offlineRequests.size(), 0u); + // close device session to make sure offline session does not rely on it + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + + std::shared_ptr offlineResultQueue; + auto offlineResultQueueRet = + offlineSession->getCaptureResultMetadataQueue( + [&offlineResultQueue](const auto& descriptor) { + offlineResultQueue = std::make_shared( + descriptor); + if (!offlineResultQueue->isValid() || + offlineResultQueue->availableToWrite() <= 0) { + ALOGE("%s: offline session returns empty result metadata fmq," + " not use it", __func__); + offlineResultQueue = nullptr; + // Don't use the queue onwards. + } + }); + ASSERT_TRUE(offlineResultQueueRet.isOk()); + + updateInflightResultQueue(offlineResultQueue); + ret = offlineSession->setCallback(cb); ASSERT_TRUE(ret.isOk()); @@ -4722,12 +4810,10 @@ TEST_P(CameraHidlTest, switchToOffline) { ASSERT_FALSE(inflightReqs[i].errorCodeValid); ASSERT_NE(inflightReqs[i].resultOutputBuffers.size(), 0u); - ASSERT_EQ(previewStream.id, inflightReqs[i].resultOutputBuffers[0].streamId); + ASSERT_EQ(stream.id, inflightReqs[i].resultOutputBuffers[0].streamId); ASSERT_FALSE(inflightReqs[i].collectedResult.isEmpty()); } - ret = session->close(); - ASSERT_TRUE(ret.isOk()); ret = offlineSession->close(); ASSERT_TRUE(ret.isOk()); @@ -5475,7 +5561,8 @@ void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t *outCb = cb; sp session3_3; - castSession(session, deviceVersion, &session3_3, session3_4, session3_5); + sp session3_6; + castSession(session, deviceVersion, &session3_3, session3_4, session3_5, &session3_6); ASSERT_NE(nullptr, (*session3_4).get()); *useHalBufManager = false; @@ -5569,23 +5656,28 @@ void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t } // Configure preview stream with possible offline session support -void CameraHidlTest::configureOfflinePreviewStream(const std::string &name, +void CameraHidlTest::configureOfflineStillStream(const std::string &name, + int32_t deviceVersion, sp provider, - const AvailableStream *previewThreshold, + const AvailableStream *threshold, sp *session/*out*/, - V3_2::Stream *previewStream /*out*/, + V3_2::Stream *stream /*out*/, device::V3_6::HalStreamConfiguration *halStreamConfig /*out*/, bool *supportsPartialResults /*out*/, uint32_t *partialResultCount /*out*/, - sp *outCb /*out*/) { + sp *outCb /*out*/, + uint32_t *jpegBufferSize /*out*/, + bool *useHalBufManager /*out*/) { ASSERT_NE(nullptr, session); ASSERT_NE(nullptr, halStreamConfig); - ASSERT_NE(nullptr, previewStream); + ASSERT_NE(nullptr, stream); ASSERT_NE(nullptr, supportsPartialResults); ASSERT_NE(nullptr, partialResultCount); ASSERT_NE(nullptr, outCb); + ASSERT_NE(nullptr, jpegBufferSize); + ASSERT_NE(nullptr, useHalBufManager); - std::vector outputPreviewStreams; + std::vector outputStreams; ::android::sp cameraDevice; ALOGI("configureStreams: Testing camera device %s", name.c_str()); Return ret; @@ -5618,7 +5710,19 @@ void CameraHidlTest::configureOfflinePreviewStream(const std::string &name, *supportsPartialResults = (*partialResultCount > 1); } - ret = cameraDevice->open(*outCb, [&session](auto status, const auto& newSession) { + *useHalBufManager = false; + status = find_camera_metadata_ro_entry(staticMeta, + ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry); + if ((0 == status) && (entry.count == 1)) { + *useHalBufManager = (entry.data.u8[0] == + ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5); + } + + auto st = getJpegBufferSize(staticMeta, jpegBufferSize); + ASSERT_EQ(st, Status::OK); + + sp cb = new DeviceCb(this, deviceVersion, staticMeta); + ret = cameraDevice->open(cb, [&session](auto status, const auto& newSession) { ALOGI("device::open returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(newSession, nullptr); @@ -5627,16 +5731,29 @@ void CameraHidlTest::configureOfflinePreviewStream(const std::string &name, *session = castResult; }); ASSERT_TRUE(ret.isOk()); + *outCb = cb; - outputPreviewStreams.clear(); + outputStreams.clear(); auto rc = getAvailableOutputStreams(staticMeta, - outputPreviewStreams, previewThreshold); + outputStreams, threshold); + size_t idx = 0; + int currLargest = outputStreams[0].width * outputStreams[0].height; + for (size_t i = 0; i < outputStreams.size(); i++) { + int area = outputStreams[i].width * outputStreams[i].height; + if (area > currLargest) { + idx = i; + currLargest = area; + } + } free_camera_metadata(staticMeta); ASSERT_EQ(Status::OK, rc); - ASSERT_FALSE(outputPreviewStreams.empty()); + ASSERT_FALSE(outputStreams.empty()); V3_2::DataspaceFlags dataspaceFlag = 0; - switch (static_cast(outputPreviewStreams[0].format)) { + switch (static_cast(outputStreams[idx].format)) { + case PixelFormat::BLOB: + dataspaceFlag = static_cast(Dataspace::V0_JFIF); + break; case PixelFormat::Y16: dataspaceFlag = static_cast(Dataspace::DEPTH); break; @@ -5644,13 +5761,13 @@ void CameraHidlTest::configureOfflinePreviewStream(const std::string &name, dataspaceFlag = static_cast(Dataspace::UNKNOWN); } - ::android::hardware::hidl_vec streams3_4; + ::android::hardware::hidl_vec streams3_4(/*size*/1); V3_4::Stream stream3_4 = {{ 0 /*streamId*/, StreamType::OUTPUT, - static_cast (outputPreviewStreams[0].width), - static_cast (outputPreviewStreams[0].height), - static_cast (outputPreviewStreams[0].format), - GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, dataspaceFlag, StreamRotation::ROTATION_0}, - nullptr /*physicalId*/, /*bufferSize*/ 0}; + static_cast (outputStreams[idx].width), + static_cast (outputStreams[idx].height), + static_cast (outputStreams[idx].format), + GRALLOC1_CONSUMER_USAGE_CPU_READ, dataspaceFlag, StreamRotation::ROTATION_0}, + nullptr /*physicalId*/, /*bufferSize*/ *jpegBufferSize}; streams3_4[0] = stream3_4; ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4; @@ -5663,8 +5780,14 @@ void CameraHidlTest::configureOfflinePreviewStream(const std::string &name, [&] (Status s, device::V3_6::HalStreamConfiguration halConfig) { ASSERT_EQ(Status::OK, s); *halStreamConfig = halConfig; + + if (*useHalBufManager) { + hidl_vec halStreams3_2(1); + halStreams3_2[0] = halConfig.streams[0].v3_4.v3_3.v3_2; + cb->setCurrentStreamConfig(streams3_4, halStreams3_2); + } }); - *previewStream = streams3_4[0].v3_2; + *stream = streams3_4[0].v3_2; ASSERT_TRUE(ret.isOk()); } @@ -5699,6 +5822,14 @@ bool CameraHidlTest::isDepthOnly(camera_metadata_t* staticMeta) { return false; } +void CameraHidlTest::updateInflightResultQueue(std::shared_ptr resultQueue) { + std::unique_lock l(mLock); + for (size_t i = 0; i < mInflightMap.size(); i++) { + auto& req = mInflightMap.editValueAt(i); + req->resultQueue = resultQueue; + } +} + // Open a device session and configure a preview stream. void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t deviceVersion, sp provider, @@ -5767,7 +5898,8 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t dev sp session3_3; sp session3_4; sp session3_5; - castSession(*session, deviceVersion, &session3_3, &session3_4, &session3_5); + sp session3_6; + castSession(*session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6); *useHalBufManager = false; status = find_camera_metadata_ro_entry(staticMeta, @@ -5895,12 +6027,20 @@ void CameraHidlTest::castProvider(const sp &provider, void CameraHidlTest::castSession(const sp &session, int32_t deviceVersion, sp *session3_3 /*out*/, sp *session3_4 /*out*/, - sp *session3_5 /*out*/) { + sp *session3_5 /*out*/, + sp *session3_6 /*out*/) { ASSERT_NE(nullptr, session3_3); ASSERT_NE(nullptr, session3_4); ASSERT_NE(nullptr, session3_5); + ASSERT_NE(nullptr, session3_6); switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_6: { + auto castResult = device::V3_6::ICameraDeviceSession::castFrom(session); + ASSERT_TRUE(castResult.isOk()); + *session3_6 = castResult; + } + [[fallthrough]]; case CAMERA_DEVICE_API_VERSION_3_5: { auto castResult = device::V3_5::ICameraDeviceSession::castFrom(session); ASSERT_TRUE(castResult.isOk()); @@ -6491,7 +6631,8 @@ void CameraHidlTest::verifyBuffersReturned( sp session3_3; sp session3_4; sp session3_5; - castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + sp session3_6; + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6); ASSERT_NE(nullptr, session3_5.get()); hidl_vec streamIds(1); From ba232e44af46e2d5b2806a3f985209242082de89 Mon Sep 17 00:00:00 2001 From: shubang Date: Wed, 29 Jan 2020 10:49:10 -0800 Subject: [PATCH 0531/1022] Add getFrontendInfo/status default impl Test: make; acloud create; Change-Id: Ie1a81a8e571d430d7e464dc631bdfd2ba51077cc --- tv/tuner/1.0/default/Frontend.cpp | 57 ++++++++++++++++++++++++++++++- tv/tuner/1.0/default/Tuner.cpp | 32 ++++++++++++++++- 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp index 1e07eddbfe..dd2f8a68d5 100644 --- a/tv/tuner/1.0/default/Frontend.cpp +++ b/tv/tuner/1.0/default/Frontend.cpp @@ -90,11 +90,66 @@ Return Frontend::stopScan() { return Result::SUCCESS; } -Return Frontend::getStatus(const hidl_vec& /* statusTypes */, +Return Frontend::getStatus(const hidl_vec& statusTypes, getStatus_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); vector statuses; + for (int i = 0; i < statusTypes.size(); i++) { + FrontendStatusType type = statusTypes[i]; + FrontendStatus status; + // assign randomly selected values for testing. + switch (type) { + case FrontendStatusType::DEMOD_LOCK: { + status.isDemodLocked(true); + break; + } + case FrontendStatusType::SNR: { + status.snr(221); + break; + } + case FrontendStatusType::FEC: { + status.innerFec(FrontendInnerFec::FEC_2_9); // value = 1 << 7 + break; + } + case FrontendStatusType::MODULATION: { + FrontendModulationStatus modulationStatus; + modulationStatus.isdbt(FrontendIsdbtModulation::MOD_16QAM); // value = 1 << 3 + status.modulation(modulationStatus); + break; + } + case FrontendStatusType::PLP_ID: { + status.plpId(101); // type uint8_t + break; + } + case FrontendStatusType::LAYER_ERROR: { + vector v = {false, true, true}; + status.isLayerError(v); + break; + } + case FrontendStatusType::ATSC3_PLP_INFO: { + vector v; + FrontendStatusAtsc3PlpInfo info1{ + .plpId = 3, + .isLocked = false, + .uec = 313, + }; + FrontendStatusAtsc3PlpInfo info2{ + .plpId = 5, + .isLocked = true, + .uec = 515, + }; + v.push_back(info1); + v.push_back(info2); + status.plpInfo(v); + break; + } + default: { + continue; + } + } + statuses.push_back(status); + } _hidl_cb(Result::SUCCESS, statuses); return Void(); diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp index c6017f0c76..4fd33559cc 100644 --- a/tv/tuner/1.0/default/Tuner.cpp +++ b/tv/tuner/1.0/default/Tuner.cpp @@ -109,7 +109,37 @@ Return Tuner::openDescrambler(openDescrambler_cb _hidl_cb) { Return Tuner::getFrontendInfo(FrontendId /* frontendId */, getFrontendInfo_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); - FrontendInfo info; + vector statusCaps = { + FrontendStatusType::DEMOD_LOCK, + FrontendStatusType::SNR, + FrontendStatusType::FEC, + FrontendStatusType::MODULATION, + FrontendStatusType::PLP_ID, + FrontendStatusType::LAYER_ERROR, + FrontendStatusType::ATSC3_PLP_INFO, + }; + FrontendInfo::FrontendCapabilities frontendCaps; + FrontendIsdbtCapabilities isdbtCaps{ + .modeCap = FrontendIsdbtMode::MODE_1 | FrontendIsdbtMode::MODE_2, + .bandwidthCap = (unsigned int)FrontendIsdbtBandwidth::BANDWIDTH_6MHZ, + .modulationCap = (unsigned int)FrontendIsdbtModulation::MOD_16QAM, + // ISDBT shares coderate and guard interval with DVBT + .coderateCap = FrontendDvbtCoderate::CODERATE_4_5 | FrontendDvbtCoderate::CODERATE_6_7, + .guardIntervalCap = (unsigned int)FrontendDvbtGuardInterval::INTERVAL_1_128, + }; + frontendCaps.isdbtCaps(isdbtCaps); + // assign randomly selected values for testing. + FrontendInfo info{ + .type = FrontendType::ISDBT, + .minFrequency = 139, + .maxFrequency = 1139, + .minSymbolRate = 45, + .maxSymbolRate = 1145, + .acquireRange = 30, + .exclusiveGroupId = 57, + .statusCaps = statusCaps, + .frontendCaps = frontendCaps, + }; _hidl_cb(Result::SUCCESS, info); return Void(); From 2452ee5a80ffc0d94c7da34e45b9e1db33c2dcd5 Mon Sep 17 00:00:00 2001 From: David Gross Date: Fri, 20 Dec 2019 14:22:15 -0800 Subject: [PATCH 0532/1022] redefine _Float16 as __fp16 for x86[_64] to allow removing workaround from inhouse clang At present, the tests might not actually use _Float16 (the generated tests that are incorporated into the functional tests are built in frameworks/ml rather than in hardware/interfaces); but the makefiles are changed anyway, in case _Float16 is added in the future. Bug: 138709788 Test: for (walleye, aosp_x86 [on emulator], aosp_x86_64 [on emulator]) Use clang where _Float16 is disabled for x86[_64] $ cd $ANDROID_BUILD_TOP/neuralnetworks/1.0/vts/functional inspect build commands for tests as to whether or not expected options related to redefinition are present $ cd $ANDROID_BUILD_TOP/neuralnetworks/1.1/vts/functional inspect build commands for tests as to whether or not expected options related to redefinition are present Change-Id: I9225b228947696d249771b3a35b1f82de9c26b6e --- neuralnetworks/1.0/vts/functional/Android.bp | 21 ++++++++++++++++++-- neuralnetworks/1.1/vts/functional/Android.bp | 2 +- neuralnetworks/1.2/vts/functional/Android.bp | 4 ++-- neuralnetworks/1.3/vts/functional/Android.bp | 4 ++-- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp index ba9fb4584e..03af671086 100644 --- a/neuralnetworks/1.0/vts/functional/Android.bp +++ b/neuralnetworks/1.0/vts/functional/Android.bp @@ -14,13 +14,30 @@ // limitations under the License. // +cc_defaults { + name: "neuralnetworks_vts_functional_defaults", + defaults: ["VtsHalTargetTestDefaults"], + arch: { + x86: { + cflags: [ "-D_Float16=__fp16", + "-Xclang", "-fnative-half-type", + "-Xclang", "-fallow-half-arguments-and-returns" ], + }, + x86_64: { + cflags: [ "-D_Float16=__fp16", + "-Xclang", "-fnative-half-type", + "-Xclang", "-fallow-half-arguments-and-returns" ], + }, + }, +} + cc_library_static { name: "VtsHalNeuralNetworksV1_0_utils", srcs: [ "Callbacks.cpp", "Utils.cpp", ], - defaults: ["VtsHalTargetTestDefaults"], + defaults: ["neuralnetworks_vts_functional_defaults"], export_include_dirs: ["include"], shared_libs: [ "libfmq", @@ -42,7 +59,7 @@ cc_library_static { cc_test { name: "VtsHalNeuralnetworksV1_0TargetTest", - defaults: ["VtsHalTargetTestDefaults"], + defaults: ["neuralnetworks_vts_functional_defaults"], srcs: [ "BasicTests.cpp", "TestAssertions.cpp", diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp index 69e1761ec6..9ba192518a 100644 --- a/neuralnetworks/1.1/vts/functional/Android.bp +++ b/neuralnetworks/1.1/vts/functional/Android.bp @@ -16,7 +16,7 @@ cc_test { name: "VtsHalNeuralnetworksV1_1TargetTest", - defaults: ["VtsHalTargetTestDefaults"], + defaults: ["neuralnetworks_vts_functional_defaults"], srcs: [ "BasicTests.cpp", "TestAssertions.cpp", diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index fc727b74f4..7886910dd2 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -16,7 +16,7 @@ cc_library_static { name: "VtsHalNeuralNetworksV1_2Callbacks", - defaults: ["VtsHalTargetTestDefaults"], + defaults: ["neuralnetworks_vts_functional_defaults"], export_include_dirs: ["include"], srcs: [ "Callbacks.cpp", @@ -33,7 +33,7 @@ cc_library_static { cc_test { name: "VtsHalNeuralnetworksV1_2TargetTest", - defaults: ["VtsHalTargetTestDefaults"], + defaults: ["neuralnetworks_vts_functional_defaults"], srcs: [ "BasicTests.cpp", "CompilationCachingTests.cpp", diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp index 8e7e9b9d62..f9362676ec 100644 --- a/neuralnetworks/1.3/vts/functional/Android.bp +++ b/neuralnetworks/1.3/vts/functional/Android.bp @@ -16,7 +16,7 @@ cc_library_static { name: "VtsHalNeuralNetworksV1_3_utils", - defaults: ["VtsHalTargetTestDefaults"], + defaults: ["neuralnetworks_vts_functional_defaults"], export_include_dirs: ["include"], srcs: [ "Callbacks.cpp", @@ -35,7 +35,7 @@ cc_library_static { cc_test { name: "VtsHalNeuralnetworksV1_3TargetTest", - defaults: ["VtsHalTargetTestDefaults"], + defaults: ["neuralnetworks_vts_functional_defaults"], srcs: [ "BasicTests.cpp", "CompilationCachingTests.cpp", From 8d343bdfc06a30f2c3d1925a0cdede466a409984 Mon Sep 17 00:00:00 2001 From: Sunil Ravi Date: Wed, 29 Jan 2020 20:45:09 -0800 Subject: [PATCH 0533/1022] wifi: Fix for VtsHalWifiSupplicantV1_2TargetTest failures Check the return value of deprecated APIs and if it's FAILURE_UNKNOWN, don't proceed and consider it as pass. Bug: 147434122 Test: atest VtsHalWifiSupplicantV1_2TargetTest Change-Id: Ib6cfb70c514f10faa54ca11011657528374175e6 --- .../supplicant_sta_iface_hidl_test.cpp | 22 ++++++--- .../supplicant_sta_network_hidl_test.cpp | 48 +++++++++++++++---- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp index 8116c3f21a..f38dda4caf 100644 --- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp +++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp @@ -111,9 +111,14 @@ class SupplicantStaIfaceHidlTest : public SupplicantHidlTestBase { // If DPP is not supported, we just pass the test. sta_iface_->getKeyMgmtCapabilities( [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) { - EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + // Since getKeyMgmtCapabilities() is overridden by an + // upgraded API in newer HAL versions, allow for + // FAILURE_UNKNOWN and return DPP is not supported. + if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); - keyMgmtMask = keyMgmtMaskInternal; + keyMgmtMask = keyMgmtMaskInternal; + } }); if (!(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::DPP)) { @@ -268,8 +273,12 @@ TEST_P(SupplicantStaIfaceHidlTest, RegisterCallback_1_2) { * GetKeyMgmtCapabilities */ TEST_P(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities) { - sta_iface_->getKeyMgmtCapabilities( - [&](const SupplicantStatus& status, uint32_t keyMgmtMask) { + sta_iface_->getKeyMgmtCapabilities([&](const SupplicantStatus& status, + uint32_t keyMgmtMask) { + // Since this API is overridden by an upgraded API in newer HAL + // versions, allow FAILURE_UNKNOWN to indicate that the test is no + // longer supported on newer HAL. + if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); // Even though capabilities vary, these two are always set in HAL @@ -277,7 +286,8 @@ TEST_P(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities) { EXPECT_TRUE(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::NONE); EXPECT_TRUE(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X); - }); + } + }); } /* @@ -455,4 +465,4 @@ INSTANTIATE_TEST_CASE_P( testing::ValuesIn(android::hardware::getAllHalInstanceNames( android::hardware::wifi::supplicant::V1_2::ISupplicant:: descriptor))), - android::hardware::PrintInstanceTupleNameToString<>); \ No newline at end of file + android::hardware::PrintInstanceTupleNameToString<>); diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp index 4c3d808627..54ceb20211 100644 --- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp +++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp @@ -112,13 +112,23 @@ TEST_P(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_2) { uint32_t keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::SAE; sta_network_->setKeyMgmt_1_2(keyMgmt, [](const SupplicantStatus &status) { - EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + // Since this API is overridden by an upgraded API in newer HAL + // versions, allow FAILURE_UNKNOWN to indicate that the test is no + // longer supported on newer HALs. + if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + } }); sta_network_->getKeyMgmt_1_2( [&keyMgmt](const SupplicantStatus &status, uint32_t keyMgmtOut) { - EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); - EXPECT_EQ(keyMgmtOut, keyMgmt); + // Since this API is overridden by an upgraded API in newer HAL + // versions, allow FAILURE_UNKNOWN to indicate that the test is no + // longer supported on newer HALs. + if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + EXPECT_EQ(keyMgmtOut, keyMgmt); + } }); } @@ -131,14 +141,24 @@ TEST_P(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_2) { sta_network_->setGroupCipher_1_2( groupCipher, [](const SupplicantStatus &status) { - EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + // Since this API is overridden by an upgraded API in newer HAL + // versions, allow FAILURE_UNKNOWN to indicate that the test is no + // longer supported on newer HALs. + if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + } }); sta_network_->getGroupCipher_1_2( [&groupCipher](const SupplicantStatus &status, uint32_t groupCipherOut) { - EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); - EXPECT_EQ(groupCipherOut, groupCipher); + // Since this API is overridden by an upgraded API in newer HAL + // versions, allow FAILURE_UNKNOWN to indicate that the test is no + // longer supported on newer HALs. + if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + EXPECT_EQ(groupCipherOut, groupCipher); + } }); } @@ -151,14 +171,24 @@ TEST_P(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_2) { sta_network_->setPairwiseCipher_1_2( pairwiseCipher, [](const SupplicantStatus &status) { - EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + // Since this API is overridden by an upgraded API in newer HAL + // versions, allow FAILURE_UNKNOWN to indicate that the test is no + // longer supported on newer HALs. + if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + } }); sta_network_->getPairwiseCipher_1_2( [&pairwiseCipher](const SupplicantStatus &status, uint32_t pairwiseCipherOut) { - EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); - EXPECT_EQ(pairwiseCipherOut, pairwiseCipher); + // Since this API is overridden by an upgraded API in newer HAL + // versions, allow FAILURE_UNKNOWN to indicate that the test is no + // longer supported on newer HALs. + if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + EXPECT_EQ(pairwiseCipherOut, pairwiseCipher); + } }); } From 24c3416b4fcb0ecac9db420e981de62ffbb47f72 Mon Sep 17 00:00:00 2001 From: Rambo Wang Date: Mon, 3 Feb 2020 13:44:47 -0800 Subject: [PATCH 0534/1022] Update Barring HAL Structures to nest single-use unions/structs Bug: 148102466 Test: compilation for both cuttlefish and sargo Change-Id: I8a8e734011909b038c0d735c2bfde7ea773b71e6 --- current.txt | 2 +- radio/1.5/types.hal | 219 +++++++++++++++++++++----------------------- 2 files changed, 106 insertions(+), 115 deletions(-) diff --git a/current.txt b/current.txt index 4bb0781b14..99aef787ec 100644 --- a/current.txt +++ b/current.txt @@ -679,7 +679,7 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback 62cf050c593c1ec34b49178b5bdde72dd9b80d9bad3eb184e4f0cd564d28678c android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types -88fb40d98b89cfaafad33b06c95e5dcd51c4470962e8fbe80ed22884407f98a1 android.hardware.radio@1.5::types +e1d34b83188a8ef3c507ec53c0ebcf714863c746da7f4a05460453f7c4c09389 android.hardware.radio@1.5::types 8062d0a1a03594dd8b448adcf6f08856b5720f7e33f9b785a21d3ef74a4f211d android.hardware.radio@1.5::IRadio e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication 7f2439b48bda2961c6d629d0415eee66d519142cf9537f05e9d285153c70ca85 android.hardware.radio@1.5::IRadioResponse diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index a0868337dd..448e5c830e 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -692,125 +692,116 @@ safe_union CellIdentity { CellIdentityNr nr; }; -/** - * Combined list of barring services for UTRAN, EUTRAN, and NGRAN. - * - * Barring information is defined in: - * -UTRAN - 3gpp 25.331 Sec 10.2.48.8.6. - * -EUTRAN - 3gpp 36.331 Sec 6.3.1 SystemInformationBlockType2 - * -NGRAN - 3gpp 38.331 Sec 6.3.2 UAC-BarringInfo and 22.261 Sec 6.22.2.[2-3] - */ -enum BarringServiceType : int32_t { - /** Applicable to UTRAN */ - /** Barring for all CS services, including registration */ - CS_SERVICE, - /** Barring for all PS services, including registration */ - PS_SERVICE, - /** Barring for mobile-originated circuit-switched voice calls */ - CS_VOICE, - - /** Applicable to EUTRAN, NGRAN */ - /** Barring for mobile-originated signalling for any purpose */ - MO_SIGNALLING, - /** Barring for mobile-originated internet or other interactive data */ - MO_DATA, - /** Barring for circuit-switched fallback calling */ - CS_FALLBACK, - /** Barring for IMS voice calling */ - MMTEL_VOICE, - /** Barring for IMS video calling */ - MMTEL_VIDEO, - - /** Applicable to UTRAN, EUTRAN, NGRAN */ - /** Barring for emergency services, either CS or emergency MMTEL */ - EMERGENCY, - /** Barring for short message services */ - SMS, - - /** Operator-specific barring codes; applicable to NGRAN */ - OPERATOR_1 = 1001, - OPERATOR_2 = 1002, - OPERATOR_3 = 1003, - OPERATOR_4 = 1004, - OPERATOR_5 = 1005, - OPERATOR_6 = 1006, - OPERATOR_7 = 1007, - OPERATOR_8 = 1008, - OPERATOR_9 = 1009, - OPERATOR_10 = 1010, - OPERATOR_11 = 1011, - OPERATOR_12 = 1012, - OPERATOR_13 = 1013, - OPERATOR_14 = 1014, - OPERATOR_15 = 1015, - OPERATOR_16 = 1016, - OPERATOR_17 = 1017, - OPERATOR_18 = 1018, - OPERATOR_19 = 1019, - OPERATOR_20 = 1020, - OPERATOR_21 = 1021, - OPERATOR_22 = 1022, - OPERATOR_23 = 1023, - OPERATOR_24 = 1024, - OPERATOR_25 = 1025, - OPERATOR_26 = 1026, - OPERATOR_27 = 1027, - OPERATOR_28 = 1028, - OPERATOR_29 = 1029, - OPERATOR_30 = 1030, - OPERATOR_31 = 1031, - OPERATOR_32 = 1032, -}; - -enum BarringType : int32_t { - /** Device is not barred for the given service */ - NONE, - /** Device may be barred based on time and probability factors */ - CONDITIONAL, - /* Device is unconditionally barred */ - UNCONDITIONAL, -}; - -struct ConditionalBarringInfo { - /** The barring factor as a percentage 0-100 */ - int32_t barringFactor; - - /** The number of seconds between re-evaluations of barring */ - int32_t barringTimeSeconds; - - /** - * Indicates whether barring is currently being applied. - * - *

    True if the UE applies barring to a conditionally barred - * service based on the conditional barring parameters. - * - *

    False if the service is conditionally barred but barring - * is not currently applied, which could be due to either the - * barring criteria not having been evaluated (if the UE has not - * attempted to use the service) or due to the criteria being - * evaluated and the UE being permitted to use the service - * despite conditional barring. - */ - bool isBarred; -}; - -safe_union BarringTypeSpecificInfo { - /** Barring type is either none or unconditional */ - Monostate noinit; - - /** Must be included if barring is conditional */ - ConditionalBarringInfo conditionalBarringInfo; -}; - struct BarringInfo { - /** Barring service */ - BarringServiceType service; + /** + * Combined list of barring services for UTRAN, EUTRAN, and NGRAN. + * + * Barring information is defined in: + * -UTRAN - 3gpp 25.331 Sec 10.2.48.8.6. + * -EUTRAN - 3gpp 36.331 Sec 6.3.1 SystemInformationBlockType2 + * -NGRAN - 3gpp 38.331 Sec 6.3.2 UAC-BarringInfo and 22.261 Sec 6.22.2.[2-3] + */ + enum ServiceType : int32_t { + /** Applicable to UTRAN */ + /** Barring for all CS services, including registration */ + CS_SERVICE, + /** Barring for all PS services, including registration */ + PS_SERVICE, + /** Barring for mobile-originated circuit-switched voice calls */ + CS_VOICE, + + /** Applicable to EUTRAN, NGRAN */ + /** Barring for mobile-originated signalling for any purpose */ + MO_SIGNALLING, + /** Barring for mobile-originated internet or other interactive data */ + MO_DATA, + /** Barring for circuit-switched fallback calling */ + CS_FALLBACK, + /** Barring for IMS voice calling */ + MMTEL_VOICE, + /** Barring for IMS video calling */ + MMTEL_VIDEO, + + /** Applicable to UTRAN, EUTRAN, NGRAN */ + /** Barring for emergency services, either CS or emergency MMTEL */ + EMERGENCY, + /** Barring for short message services */ + SMS, + + /** Operator-specific barring codes; applicable to NGRAN */ + OPERATOR_1 = 1001, + OPERATOR_2 = 1002, + OPERATOR_3 = 1003, + OPERATOR_4 = 1004, + OPERATOR_5 = 1005, + OPERATOR_6 = 1006, + OPERATOR_7 = 1007, + OPERATOR_8 = 1008, + OPERATOR_9 = 1009, + OPERATOR_10 = 1010, + OPERATOR_11 = 1011, + OPERATOR_12 = 1012, + OPERATOR_13 = 1013, + OPERATOR_14 = 1014, + OPERATOR_15 = 1015, + OPERATOR_16 = 1016, + OPERATOR_17 = 1017, + OPERATOR_18 = 1018, + OPERATOR_19 = 1019, + OPERATOR_20 = 1020, + OPERATOR_21 = 1021, + OPERATOR_22 = 1022, + OPERATOR_23 = 1023, + OPERATOR_24 = 1024, + OPERATOR_25 = 1025, + OPERATOR_26 = 1026, + OPERATOR_27 = 1027, + OPERATOR_28 = 1028, + OPERATOR_29 = 1029, + OPERATOR_30 = 1030, + OPERATOR_31 = 1031, + OPERATOR_32 = 1032, + } serviceType; /** The type of barring applied to the service */ - BarringType type; + enum BarringType : int32_t { + /** Device is not barred for the given service */ + NONE, + /** Device may be barred based on time and probability factors */ + CONDITIONAL, + /* Device is unconditionally barred */ + UNCONDITIONAL, + } barringType; /** Type-specific barring info if applicable */ - BarringTypeSpecificInfo typeSpecificInfo; + safe_union BarringTypeSpecificInfo { + /** Barring type is either none or unconditional */ + Monostate noinit; + + /** Must be included if barring is conditional */ + struct Conditional { + /** The barring factor as a percentage 0-100 */ + int32_t factor; + + /** The number of seconds between re-evaluations of barring */ + int32_t timeSeconds; + + /** + * Indicates whether barring is currently being applied. + * + *

    True if the UE applies barring to a conditionally barred + * service based on the conditional barring parameters. + * + *

    False if the service is conditionally barred but barring + * is not currently applied, which could be due to either the + * barring criteria not having been evaluated (if the UE has not + * attempted to use the service) or due to the criteria being + * evaluated and the UE being permitted to use the service + * despite conditional barring. + */ + bool isBarred; + } conditional; + } barringTypeSpecificInfo; }; enum IndicationFilter : @1.2::IndicationFilter { From c44909ded80bbc1bc0517043de668bd3a254a13f Mon Sep 17 00:00:00 2001 From: Enrico Granata Date: Fri, 24 Jan 2020 14:13:52 -0800 Subject: [PATCH 0535/1022] Centralize creation and error handling for VsockServerInfo Provide helper functions that create VsockServerInfo objects from either the command line or the property storage, and have them return optional instead of relying on default values. Also, avoid atoi() since it has the potential for undefined behavior. Test: build Change-Id: I0aab6b7d84e5084580e25217ac5ba4f5a1db6e2a --- .../2.0/default/VirtualizationGrpcServer.cpp | 40 +--------- .../2.0/default/VirtualizedVehicleService.cpp | 26 +----- ....vehicle@2.0-virtualization-grpc-server.rc | 4 +- .../impl/vhal_v2_0/virtualization/Utils.cpp | 80 ++++++++++++++++++- .../impl/vhal_v2_0/virtualization/Utils.h | 10 ++- 5 files changed, 95 insertions(+), 65 deletions(-) diff --git a/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp b/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp index cca65d9f76..fb02c58952 100644 --- a/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp +++ b/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp @@ -1,6 +1,4 @@ #include -#include -#include #include "vhal_v2_0/virtualization/GrpcVehicleServer.h" #include "vhal_v2_0/virtualization/Utils.h" @@ -8,42 +6,10 @@ int main(int argc, char* argv[]) { namespace vhal_impl = android::hardware::automotive::vehicle::V2_0::impl; - vhal_impl::VsockServerInfo serverInfo; + auto serverInfo = vhal_impl::VsockServerInfo::fromCommandLine(argc, argv); + CHECK(serverInfo.has_value()) << "Invalid server CID/port combination"; - // unique values to identify the options - constexpr int OPT_VHAL_SERVER_CID = 1001; - constexpr int OPT_VHAL_SERVER_PORT_NUMBER = 1002; - - struct option longOptions[] = { - {"server_cid", 1, 0, OPT_VHAL_SERVER_CID}, - {"server_port", 1, 0, OPT_VHAL_SERVER_PORT_NUMBER}, - {nullptr, 0, nullptr, 0}, - }; - - int optValue; - while ((optValue = getopt_long_only(argc, argv, ":", longOptions, 0)) != -1) { - switch (optValue) { - case OPT_VHAL_SERVER_CID: - serverInfo.serverCid = std::atoi(optarg); - LOG(DEBUG) << "Vehicle HAL server CID: " << serverInfo.serverCid; - break; - case OPT_VHAL_SERVER_PORT_NUMBER: - serverInfo.serverPort = std::atoi(optarg); - LOG(DEBUG) << "Vehicle HAL server port: " << serverInfo.serverPort; - break; - default: - // ignore other options - break; - } - } - - if (serverInfo.serverCid == 0 || serverInfo.serverPort == 0) { - LOG(FATAL) << "Invalid server information, CID: " << serverInfo.serverCid - << "; port: " << serverInfo.serverPort; - // Will abort after logging - } - - auto server = vhal_impl::makeGrpcVehicleServer(vhal_impl::getVsockUri(serverInfo)); + auto server = vhal_impl::makeGrpcVehicleServer(serverInfo->toUri()); server->Start(); return 0; } diff --git a/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp b/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp index 1de81ae844..68813c9035 100644 --- a/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp +++ b/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp @@ -15,7 +15,6 @@ */ #include -#include #include #include @@ -29,30 +28,13 @@ using namespace android::hardware; using namespace android::hardware::automotive::vehicle::V2_0; int main(int argc, char* argv[]) { - constexpr const char* VHAL_SERVER_CID_PROPERTY_KEY = "ro.vendor.vehiclehal.server.cid"; - constexpr const char* VHAL_SERVER_PORT_PROPERTY_KEY = "ro.vendor.vehiclehal.server.port"; + namespace vhal_impl = android::hardware::automotive::vehicle::V2_0::impl; - auto property_get_uint = [](const char* key, unsigned int default_value) { - auto value = property_get_int64(key, default_value); - if (value < 0 || value > UINT_MAX) { - LOG(DEBUG) << key << ": " << value << " is out of bound, using default value '" - << default_value << "' instead"; - return default_value; - } - return static_cast(value); - }; - - impl::VsockServerInfo serverInfo{property_get_uint(VHAL_SERVER_CID_PROPERTY_KEY, 0), - property_get_uint(VHAL_SERVER_PORT_PROPERTY_KEY, 0)}; - - if (serverInfo.serverCid == 0 || serverInfo.serverPort == 0) { - LOG(FATAL) << "Invalid server information, CID: " << serverInfo.serverCid - << "; port: " << serverInfo.serverPort; - // Will abort after logging - } + auto serverInfo = vhal_impl::VsockServerInfo::fromRoPropertyStore(); + CHECK(serverInfo.has_value()) << "Invalid server CID/port combination"; auto store = std::make_unique(); - auto connector = impl::makeGrpcVehicleClient(impl::getVsockUri(serverInfo)); + auto connector = impl::makeGrpcVehicleClient(serverInfo->toUri()); auto hal = std::make_unique(store.get(), connector.get()); auto emulator = std::make_unique(hal.get()); auto service = std::make_unique(hal.get()); diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc index 29147ad6e3..1101b087eb 100644 --- a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc +++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc @@ -3,8 +3,8 @@ # so the command line arguments are expected, though not conventionally used in Android service vendor.vehicle-hal-2.0-server \ /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server \ - -server_cid ${ro.vendor.vehiclehal.server.cid:-0} \ - -server_port ${ro.vendor.vehiclehal.server.port:-0} + -server_cid ${ro.vendor.vehiclehal.server.cid:-pleaseconfigurethis} \ + -server_port ${ro.vendor.vehiclehal.server.port:-pleaseconfigurethis} class hal user vehicle_network group system inet diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp index 41d4827621..184d8a47f7 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp @@ -16,6 +16,11 @@ #include "Utils.h" +#include + +#include +#include +#include #include namespace android { @@ -25,12 +30,83 @@ namespace vehicle { namespace V2_0 { namespace impl { -std::string getVsockUri(const VsockServerInfo& serverInfo) { +std::string VsockServerInfo::toUri() { std::stringstream uri_stream; - uri_stream << "vsock:" << serverInfo.serverCid << ":" << serverInfo.serverPort; + uri_stream << "vsock:" << serverCid << ":" << serverPort; return uri_stream.str(); } +static std::optional parseUnsignedIntFromString(const char* optarg, const char* name) { + auto v = strtoul(optarg, nullptr, 0); + if (((v == ULONG_MAX) && (errno == ERANGE)) || (v > UINT_MAX)) { + LOG(WARNING) << name << " value is out of range: " << optarg; + } else if (v != 0) { + return v; + } else { + LOG(WARNING) << name << " value is invalid or missing: " << optarg; + } + + return std::nullopt; +} + +static std::optional getNumberFromProperty(const char* key) { + auto value = property_get_int64(key, -1); + if ((value <= 0) || (value > UINT_MAX)) { + LOG(WARNING) << key << " is missing or out of bounds"; + return std::nullopt; + } + + return static_cast(value); +}; + +std::optional VsockServerInfo::fromCommandLine(int argc, char* argv[]) { + std::optional cid; + std::optional port; + + // unique values to identify the options + constexpr int OPT_VHAL_SERVER_CID = 1001; + constexpr int OPT_VHAL_SERVER_PORT_NUMBER = 1002; + + struct option longOptions[] = { + {"server_cid", 1, 0, OPT_VHAL_SERVER_CID}, + {"server_port", 1, 0, OPT_VHAL_SERVER_PORT_NUMBER}, + {}, + }; + + int optValue; + while ((optValue = getopt_long_only(argc, argv, ":", longOptions, 0)) != -1) { + switch (optValue) { + case OPT_VHAL_SERVER_CID: + cid = parseUnsignedIntFromString(optarg, "cid"); + break; + case OPT_VHAL_SERVER_PORT_NUMBER: + port = parseUnsignedIntFromString(optarg, "port"); + break; + default: + // ignore other options + break; + } + } + + if (cid && port) { + return VsockServerInfo{*cid, *port}; + } + return std::nullopt; +} + +std::optional VsockServerInfo::fromRoPropertyStore() { + constexpr const char* VHAL_SERVER_CID_PROPERTY_KEY = "ro.vendor.vehiclehal.server.cid"; + constexpr const char* VHAL_SERVER_PORT_PROPERTY_KEY = "ro.vendor.vehiclehal.server.port"; + + const auto cid = getNumberFromProperty(VHAL_SERVER_CID_PROPERTY_KEY); + const auto port = getNumberFromProperty(VHAL_SERVER_PORT_PROPERTY_KEY); + + if (cid && port) { + return VsockServerInfo{*cid, *port}; + } + return std::nullopt; +} + } // namespace impl } // namespace V2_0 } // namespace vehicle diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h index 6b1049c42b..8a8bce7c7a 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h @@ -17,8 +17,11 @@ #ifndef android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_ #define android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_ +#include #include +#include + namespace android { namespace hardware { namespace automotive { @@ -29,9 +32,12 @@ namespace impl { struct VsockServerInfo { unsigned int serverCid{0}; unsigned int serverPort{0}; -}; -std::string getVsockUri(const VsockServerInfo& serverInfo); + static std::optional fromCommandLine(int argc, char* argv[]); + static std::optional fromRoPropertyStore(); + + std::string toUri(); +}; } // namespace impl } // namespace V2_0 From c90250ff57cfd41a7aefa5c03b5982319f58a11d Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Fri, 31 Jan 2020 18:39:22 -0800 Subject: [PATCH 0536/1022] NNAPI HAL: Remove priority from prepareModelFromCache_1_3 prepareModelFromCache_1_3 uses model cache and data cache that represent a prepared model. Any argument that contributes in a meaningful way to the prepared model is implicitly included in this model cache and data cache. For example, "model" and "executionPreference" appear in prepareModel_1_3 but not in prepareModelFromCache_1_3 because they are implicitly included in the model cache and data cache. In a similar way, because it could affect the resulting model, "priority" should be removed from prepareModelFromCache_1_3. Fixes: 148802784 Test: mma Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: I518e493ead8aa97220b16370cce8523b425c378c --- current.txt | 2 +- neuralnetworks/1.3/IDevice.hal | 9 +-------- .../1.3/vts/functional/CompilationCachingTests.cpp | 2 +- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/current.txt b/current.txt index 74c0cbbb5b..f1c588d156 100644 --- a/current.txt +++ b/current.txt @@ -663,7 +663,7 @@ ddcf89cd8ee2df0d32aee55050826446fb64f7aafde0a7cd946c64f61b1a364c android.hardwar df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore 65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer -d1f382d14e1384b907d5bb5780df7f01934650d556fedbed2f15a90773c657d6 android.hardware.neuralnetworks@1.3::IDevice +9b41dd49e2dcc2ecb4243d03f8421d72494ada5cf2945bff88f0019eeca56923 android.hardware.neuralnetworks@1.3::IDevice 4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback 2fa3679ad7c94b5e88724adcd560c561041068a4ca565c63830e68101988746a android.hardware.neuralnetworks@1.3::IFencedExecutionCallback 237b23b126a66f3432658020fed78cdd06ba6297459436fe6bae0ba753370833 android.hardware.neuralnetworks@1.3::IPreparedModel diff --git a/neuralnetworks/1.3/IDevice.hal b/neuralnetworks/1.3/IDevice.hal index 610db79456..493153950a 100644 --- a/neuralnetworks/1.3/IDevice.hal +++ b/neuralnetworks/1.3/IDevice.hal @@ -260,11 +260,6 @@ interface IDevice extends @1.2::IDevice { * the model, the callback object must be invoked with the appropriate * ErrorStatus value and nullptr for the IPreparedModel. * - * The model is prepared with a priority. This priority is relative to other - * prepared models owned by the same client. Higher priority executions may - * use more compute resources than lower priority executions, and may - * preempt or starve lower priority executions. - * * prepareModelFromCache_1_3 can be called with an optional deadline. If the * model is not able to prepared before the provided deadline, the model * preparation must be aborted, and either {@link @@ -284,8 +279,6 @@ interface IDevice extends @1.2::IDevice { * used with different shapes of inputs on different (possibly concurrent) * executions. * - * @param priority The priority of the prepared model relative to other - * prepared models owned by the client. * @param deadline The time by which the model must be prepared. If the * model cannot be prepared by the deadline, the preparation must be * aborted. @@ -318,7 +311,7 @@ interface IDevice extends @1.2::IDevice { * met * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver */ - prepareModelFromCache_1_3(Priority priority, OptionalTimePoint deadline, + prepareModelFromCache_1_3(OptionalTimePoint deadline, vec modelCache, vec dataCache, uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token, IPreparedModelCallback callback) diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp index 576e5240b0..0bd24daec0 100644 --- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp @@ -370,7 +370,7 @@ class CompilationCachingTestBase : public testing::Test { sp preparedModelCallback = new PreparedModelCallback(); hidl_array cacheToken(mToken); Return prepareLaunchStatus = kDevice->prepareModelFromCache_1_3( - kDefaultPriority, {}, modelCache, dataCache, cacheToken, preparedModelCallback); + {}, modelCache, dataCache, cacheToken, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); if (static_cast(prepareLaunchStatus) != ErrorStatus::NONE) { *preparedModel = nullptr; From c8d863fd29cd8f19201756bf023df61ab8df6f31 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Mon, 3 Feb 2020 15:56:59 -0800 Subject: [PATCH 0537/1022] Wifi: Add documentation for MacAddress This commit adds documentation for MacAddress type definition. Bug: 148617829 Test: Build successful Change-Id: I535b78ac6826a478e8bbe10c2eced30e64f05724 --- current.txt | 2 +- wifi/hostapd/1.2/types.hal | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/current.txt b/current.txt index 3be26c2f74..fae8d62abe 100644 --- a/current.txt +++ b/current.txt @@ -675,7 +675,7 @@ d1f382d14e1384b907d5bb5780df7f01934650d556fedbed2f15a90773c657d6 android.hardwar 3646950b10f7cacdafca13609b0e18496cea942f3bdfe920494661856eff48bb android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd -11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types +2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant 8aed0a8e03e7a67bfdfb78ad7529a9ae95bea36e6060473b204c89d772522126 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback diff --git a/wifi/hostapd/1.2/types.hal b/wifi/hostapd/1.2/types.hal index 54e6529852..9c187fa0f6 100644 --- a/wifi/hostapd/1.2/types.hal +++ b/wifi/hostapd/1.2/types.hal @@ -38,6 +38,9 @@ enum Ieee80211ReasonCode : uint16_t { WLAN_REASON_DISASSOC_AP_BUSY = 5, }; +/** + * Mac Address type. 6 octets representing physical address of a device. + */ typedef uint8_t[6] MacAddress; /** From ea83307a5e93f6d6b46e5b7136b99040d2fa994a Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Mon, 3 Feb 2020 15:52:54 -0800 Subject: [PATCH 0538/1022] Remove reference of VtsHalHidlTargetTestBase Bug: 147894326 Test: m -j VtsHalCasV1_1TargetTest \ VtsHalWifiSupplicantV1_3TargetTest Change-Id: I9a45a522edd03b6aba3ab5772a259fad7b706a23 --- cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp | 2 -- .../1.3/vts/functional/supplicant_sta_network_hidl_test.cpp | 1 - 2 files changed, 3 deletions(-) diff --git a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp index 7e5a61a6ff..1b5797b845 100644 --- a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp +++ b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp @@ -16,8 +16,6 @@ #define LOG_TAG "mediacas_hidl_hal_test" -#include -#include #include #include #include diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp index 13f33661b2..93eabd6d0b 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include #include From ddab4bbd9cc529db8a7ff52246b5daf6f6ec2475 Mon Sep 17 00:00:00 2001 From: Sunil Ravi Date: Mon, 3 Feb 2020 22:45:19 -0800 Subject: [PATCH 0539/1022] wifi: Add provision to create/delete dynamic interface(s) This commit does following: create/delete softap interface at runtime, if needed. create/delete station interface at runtime, if needed. Bug: 146539882 Bug: 121156971 Test: Manual - Basic wifi sanity test. Change-Id: I6ab9c9e134d2f09e27283c9e60df885392834de4 Signed-off-by: Vinay Gannevaram --- wifi/1.4/default/hidl_struct_util.cpp | 15 ++++++++++ wifi/1.4/default/hidl_struct_util.h | 2 ++ wifi/1.4/default/wifi_chip.cpp | 30 +++++++++++++++++++ wifi/1.4/default/wifi_legacy_hal.cpp | 35 ++++++++++++++++++++++ wifi/1.4/default/wifi_legacy_hal.h | 8 +++++ wifi/1.4/default/wifi_legacy_hal_stubs.cpp | 2 ++ 6 files changed, 92 insertions(+) diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp index 4996e358b2..fd1d5b1121 100644 --- a/wifi/1.4/default/hidl_struct_util.cpp +++ b/wifi/1.4/default/hidl_struct_util.cpp @@ -2715,6 +2715,21 @@ bool convertLegacyVectorOfRttResultToHidl( } return true; } + +legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy( + IfaceType hidl_interface_type) { + switch (hidl_interface_type) { + case IfaceType::STA: + return legacy_hal::WIFI_INTERFACE_TYPE_STA; + case IfaceType::AP: + return legacy_hal::WIFI_INTERFACE_TYPE_AP; + case IfaceType::P2P: + return legacy_hal::WIFI_INTERFACE_TYPE_P2P; + case IfaceType::NAN: + return legacy_hal::WIFI_INTERFACE_TYPE_NAN; + } + CHECK(false); +} } // namespace hidl_struct_util } // namespace implementation } // namespace V1_4 diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h index d040c1fd2e..929f877d96 100644 --- a/wifi/1.4/default/hidl_struct_util.h +++ b/wifi/1.4/default/hidl_struct_util.h @@ -65,6 +65,8 @@ legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2( bool convertLegacyWifiMacInfosToHidl( const std::vector& legacy_mac_infos, std::vector* hidl_radio_mode_infos); +legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy( + IfaceType hidl_interface_type); // STA iface conversion methods. bool convertLegacyFeaturesToHidlStaCapabilities( diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp index 3498510e2e..4c9fad17bb 100644 --- a/wifi/1.4/default/wifi_chip.cpp +++ b/wifi/1.4/default/wifi_chip.cpp @@ -797,6 +797,15 @@ std::pair> WifiChip::createApIfaceInternal() { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } std::string ifname = allocateApIfaceName(); + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->createVirtualInterface( + ifname, + hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::AP)); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to add interface: " << ifname << " " + << legacyErrorToString(legacy_status); + return {createWifiStatusFromLegacyError(legacy_status), {}}; + } sp iface = new WifiApIface(ifname, legacy_hal_, iface_util_); ap_ifaces_.push_back(iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { @@ -835,6 +844,12 @@ WifiStatus WifiChip::removeApIfaceInternal(const std::string& ifname) { // nan/rtt objects over AP iface. But, there is no harm to do it // here and not make that assumption all over the place. invalidateAndRemoveDependencies(ifname); + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->deleteVirtualInterface(ifname); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to remove interface: " << ifname << " " + << legacyErrorToString(legacy_status); + } invalidateAndClear(ap_ifaces_, iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) { @@ -944,6 +959,15 @@ WifiChip::createStaIfaceInternal() { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } std::string ifname = allocateStaIfaceName(); + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->createVirtualInterface( + ifname, + hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::STA)); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to add interface: " << ifname << " " + << legacyErrorToString(legacy_status); + return {createWifiStatusFromLegacyError(legacy_status), {}}; + } sp iface = new WifiStaIface(ifname, legacy_hal_, iface_util_); sta_ifaces_.push_back(iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { @@ -979,6 +1003,12 @@ WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) { } // Invalidate & remove any dependent objects first. invalidateAndRemoveDependencies(ifname); + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->deleteVirtualInterface(ifname); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to remove interface: " << ifname << " " + << legacyErrorToString(legacy_status); + } invalidateAndClear(sta_ifaces_, iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) { diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp index 3ca3226bd9..a040c89a30 100644 --- a/wifi/1.4/default/wifi_legacy_hal.cpp +++ b/wifi/1.4/default/wifi_legacy_hal.cpp @@ -19,6 +19,7 @@ #include #include +#include #include "hidl_sync_util.h" #include "wifi_legacy_hal.h" @@ -1355,6 +1356,7 @@ wifi_error WifiLegacyHal::retrieveIfaceHandles() { LOG(ERROR) << "Failed to enumerate interface handles"; return status; } + iface_name_to_handle_.clear(); for (int i = 0; i < num_iface_handles; ++i) { std::array iface_name_arr = {}; status = global_func_table_.wifi_get_iface_name( @@ -1421,6 +1423,39 @@ WifiLegacyHal::getGscanCachedResults(const std::string& iface_name) { return {status, std::move(cached_scan_results)}; } +wifi_error WifiLegacyHal::createVirtualInterface(const std::string& ifname, + wifi_interface_type iftype) { + // Create the interface if it doesn't exist. If interface already exist, + // Vendor Hal should return WIFI_SUCCESS. + wifi_error status = global_func_table_.wifi_virtual_interface_create( + global_handle_, ifname.c_str(), iftype); + return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status); +} + +wifi_error WifiLegacyHal::deleteVirtualInterface(const std::string& ifname) { + // Delete the interface if it was created dynamically. + wifi_error status = global_func_table_.wifi_virtual_interface_delete( + global_handle_, ifname.c_str()); + return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status); +} + +wifi_error WifiLegacyHal::handleVirtualInterfaceCreateOrDeleteStatus( + const std::string& ifname, wifi_error status) { + if (status == WIFI_SUCCESS) { + // refresh list of handlers now. + status = retrieveIfaceHandles(); + } else if (status == WIFI_ERROR_NOT_SUPPORTED) { + // Vendor hal does not implement this API. Such vendor implementations + // are expected to create / delete interface by other means. + + // check if interface exists. + if (if_nametoindex(ifname.c_str())) { + status = retrieveIfaceHandles(); + } + } + return status; +} + void WifiLegacyHal::invalidate() { global_handle_ = nullptr; iface_name_to_handle_.clear(); diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h index a7b40a05cc..72cf197539 100644 --- a/wifi/1.4/default/wifi_legacy_hal.h +++ b/wifi/1.4/default/wifi_legacy_hal.h @@ -369,6 +369,11 @@ class WifiLegacyHal { wifi_error setCountryCode(const std::string& iface_name, std::array code); + // interface functions. + wifi_error createVirtualInterface(const std::string& ifname, + wifi_interface_type iftype); + wifi_error deleteVirtualInterface(const std::string& ifname); + private: // Retrieve interface handles for all the available interfaces. wifi_error retrieveIfaceHandles(); @@ -380,6 +385,9 @@ class WifiLegacyHal { std::pair> getGscanCachedResults(const std::string& iface_name); void invalidate(); + // Handles wifi (error) status of Virtual interface create/delete + wifi_error handleVirtualInterfaceCreateOrDeleteStatus( + const std::string& ifname, wifi_error status); // Global function table of legacy HAL. wifi_hal_fn global_func_table_; diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp index bbe470e580..6945b4ca01 100644 --- a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp +++ b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp @@ -139,6 +139,8 @@ bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) { populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler); populateStubFor(&hal_fn->wifi_set_latency_mode); populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode); + populateStubFor(&hal_fn->wifi_virtual_interface_create); + populateStubFor(&hal_fn->wifi_virtual_interface_delete); return true; } } // namespace legacy_hal From f0aa3f01074af96678646028f17d289f901be4b5 Mon Sep 17 00:00:00 2001 From: Emilian Peev Date: Mon, 3 Feb 2020 14:17:06 -0800 Subject: [PATCH 0540/1022] Camera: Add ICameraDevice@3.6 subinterface Camera device subinterface version 3.6 must inherit from the previous version 3.5 and continue to support device sessions with versions 3.2, 3.5 as well as the most recent 3.6. Bug: 148235329 Test: VtsHalCameraProviderV2_4TargetTest --gtest_filter=PerInstance/CameraHidlTest.switchToOffline/0_external_0 Change-Id: Ia46cbd771eb1d2624cc0cee808a3eb074fc775b6 --- camera/device/3.6/Android.bp | 1 + camera/device/3.6/ICameraDevice.hal | 31 +++++++++++ .../ExternalCameraDevice_3_6.h | 51 ++++++++++++++++++- .../VtsHalCameraProviderV2_4TargetTest.cpp | 9 ++-- current.txt | 1 + 5 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 camera/device/3.6/ICameraDevice.hal diff --git a/camera/device/3.6/Android.bp b/camera/device/3.6/Android.bp index 8766b931f4..19adb3472d 100644 --- a/camera/device/3.6/Android.bp +++ b/camera/device/3.6/Android.bp @@ -8,6 +8,7 @@ hidl_interface { }, srcs: [ "types.hal", + "ICameraDevice.hal", "ICameraDeviceSession.hal", "ICameraOfflineSession.hal", ], diff --git a/camera/device/3.6/ICameraDevice.hal b/camera/device/3.6/ICameraDevice.hal new file mode 100644 index 0000000000..e859606376 --- /dev/null +++ b/camera/device/3.6/ICameraDevice.hal @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package android.hardware.camera.device@3.6; + +import @3.5::ICameraDevice; + +/** + * Camera device interface + * + * Supports the android.hardware.Camera API, and the android.hardware.camera2 + * API at LIMITED or better hardware level. + * + * ICameraDevice.open() must return @3.2::ICameraDeviceSession or + * @3.5::ICameraDeviceSession or @3.6::ICameraDeviceSession. + */ +interface ICameraDevice extends @3.5::ICameraDevice { +}; diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h index 046c9d817e..020bec4a92 100644 --- a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h +++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h @@ -17,6 +17,8 @@ #ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H #define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H +#include + #include "ExternalCameraDeviceSession.h" #include <../../../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h> @@ -28,7 +30,7 @@ namespace V3_6 { namespace implementation { using namespace ::android::hardware::camera::device; -using ::android::hardware::camera::device::V3_5::ICameraDevice; +using ::android::hardware::camera::device::V3_6::ICameraDevice; using ::android::hardware::camera::common::V1_0::CameraResourceCost; using ::android::hardware::camera::common::V1_0::TorchMode; using ::android::hardware::camera::common::V1_0::Status; @@ -53,6 +55,10 @@ struct ExternalCameraDevice : public V3_5::implementation::ExternalCameraDevice ExternalCameraDevice(const std::string& cameraId, const ExternalCameraConfig& cfg); virtual ~ExternalCameraDevice(); + virtual sp getInterface() override { + return new TrampolineDeviceInterface_3_6(this); + } + protected: virtual sp createSession( const sp&, @@ -65,6 +71,49 @@ protected: virtual status_t initAvailableCapabilities( ::android::hardware::camera::common::V1_0::helper::CameraMetadata*) override; + +private: + struct TrampolineDeviceInterface_3_6 : public ICameraDevice { + TrampolineDeviceInterface_3_6(sp parent) : + mParent(parent) {} + + virtual Return getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb) + override { + return mParent->getResourceCost(_hidl_cb); + } + + virtual Return getCameraCharacteristics( + V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override { + return mParent->getCameraCharacteristics(_hidl_cb); + } + + virtual Return setTorchMode(TorchMode mode) override { + return mParent->setTorchMode(mode); + } + + virtual Return open(const sp& callback, + V3_2::ICameraDevice::open_cb _hidl_cb) override { + return mParent->open(callback, _hidl_cb); + } + + virtual Return dumpState(const hidl_handle& fd) override { + return mParent->dumpState(fd); + } + + virtual Return getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId, + V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) override { + return mParent->getPhysicalCameraCharacteristics(physicalCameraId, _hidl_cb); + } + + virtual Return isStreamCombinationSupported( + const V3_4::StreamConfiguration& streams, + V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb) override { + return mParent->isStreamCombinationSupported(streams, _hidl_cb); + } + + private: + sp mParent; + }; }; } // namespace implementation diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index e3e53dd4b0..5c73aa2ab7 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -5719,17 +5720,19 @@ void CameraHidlTest::configureOfflineStillStream(const std::string &name, ASSERT_NE(nullptr, useHalBufManager); std::vector outputStreams; - ::android::sp cameraDevice; + ::android::sp cameraDevice; ALOGI("configureStreams: Testing camera device %s", name.c_str()); Return ret; ret = provider->getCameraDeviceInterface_V3_x( name, - [&](auto status, const auto& device) { + [&cameraDevice](auto status, const auto& device) { ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(device, nullptr); - cameraDevice = device; + auto castResult = device::V3_6::ICameraDevice::castFrom(device); + ASSERT_TRUE(castResult.isOk()); + cameraDevice = castResult; }); ASSERT_TRUE(ret.isOk()); diff --git a/current.txt b/current.txt index b4a30a0b61..71e9f0565b 100644 --- a/current.txt +++ b/current.txt @@ -636,6 +636,7 @@ ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardwar 40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types +b8c63679e1a3874b356f3e691aecce1191d38f59063cf2ed2dce8a9d4cabf00e android.hardware.camera.device@3.6::ICameraDevice e88840e0558439cb54837514ddccd43877094951758f367e9c638084eb7455a6 android.hardware.camera.provider@2.6::ICameraProvider 8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas From d884ff25bc9e16924a4907cde5e8254e35489200 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Sat, 1 Feb 2020 20:52:44 -0800 Subject: [PATCH 0541/1022] compatibility_matrix: deprecate pre-1.3 drm Bug: 139313724 Change-Id: Ie120bc46746489618c6b846c037da1336950930a --- compatibility_matrices/compatibility_matrix.current.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 9a8f336ff3..8eb7587b6e 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -161,7 +161,7 @@ android.hardware.drm - 1.0-3 + 1.3 ICryptoFactory .* From 40549fae50811a57efedc7e9a3563df7933af0cd Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Tue, 4 Feb 2020 18:42:09 -0800 Subject: [PATCH 0542/1022] audio: Provide documentation for enums in 'common' package Bug: 148617378 Test: N/A Change-Id: Ia28c9217527509430f2daf274e14380bfe79f145 --- audio/common/6.0/types.hal | 139 ++++++++++++++++++++++++++++++++++--- current.txt | 2 +- 2 files changed, 132 insertions(+), 9 deletions(-) diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal index 26e8acbfe4..b2806c7eeb 100644 --- a/audio/common/6.0/types.hal +++ b/audio/common/6.0/types.hal @@ -91,37 +91,76 @@ struct Uuid { enum AudioStreamType : int32_t { // These values must kept in sync with // frameworks/base/media/java/android/media/AudioSystem.java + /** Used to identify the default audio stream volume. */ DEFAULT = -1, + /** Specifies the minimum value for use in checks and loops. */ MIN = 0, + /** Used to identify the volume of audio streams for phone calls. */ VOICE_CALL = 0, + /** Used to identify the volume of audio streams for system sounds. */ SYSTEM = 1, + /** + * Used to identify the volume of audio streams for the phone ring + * and message alerts. + */ RING = 2, + /** Used to identify the volume of audio streams for music playback. */ MUSIC = 3, + /** Used to identify the volume of audio streams for alarms. */ ALARM = 4, + /** Used to identify the volume of audio streams for notifications. */ NOTIFICATION = 5, + /** + * Used to identify the volume of audio streams for phone calls + * when connected on bluetooth. + */ BLUETOOTH_SCO = 6, - ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be - // routed to speaker + /** + * Used to identify the volume of audio streams for enforced system + * sounds in certain countries (e.g camera in Japan). */ + ENFORCED_AUDIBLE = 7, + /** Used to identify the volume of audio streams for DTMF tones. */ DTMF = 8, - TTS = 9, // Transmitted Through Speaker. Plays over speaker - // only, silent on other devices - ACCESSIBILITY = 10, // For accessibility talk back prompts - ASSISTANT = 11, // For virtual assistant service + /** + * Used to identify the volume of audio streams exclusively transmitted + * through the speaker (TTS) of the device. + */ + TTS = 9, + /** + * Used to identify the volume of audio streams for accessibility prompts. + */ + ACCESSIBILITY = 10, + /** Used to identify the volume of audio streams for virtual assistant. */ + ASSISTANT = 11, }; @export(name="audio_source_t", value_prefix="AUDIO_SOURCE_") enum AudioSource : int32_t { // These values must kept in sync with // frameworks/base/media/java/android/media/MediaRecorder.java, - // frameworks/av/services/audiopolicy/AudioPolicyService.cpp, // system/media/audio_effects/include/audio_effects/audio_effects_conf.h + /** Default audio source. */ DEFAULT = 0, + /** Microphone audio source. */ MIC = 1, + /** Voice call uplink (Tx) audio source. */ VOICE_UPLINK = 2, + /** Voice call downlink (Rx) audio source. */ VOICE_DOWNLINK = 3, + /** Voice call uplink + downlink audio source. */ VOICE_CALL = 4, + /** + * Microphone audio source tuned for video recording, with the same + * orientation as the camera if available. + */ CAMCORDER = 5, + /** Microphone audio source tuned for voice recognition. */ VOICE_RECOGNITION = 6, + /** + * Microphone audio source tuned for voice communications such as VoIP. It + * will for instance take advantage of echo cancellation or automatic gain + * control if available. + */ VOICE_COMMUNICATION = 7, /** * Source for the mix to be presented remotely. An example of remote @@ -146,7 +185,9 @@ enum AudioSource : int32_t { * to include all post processing applied to the playback path. */ ECHO_REFERENCE = 1997, + /** Virtual source for the built-in FM tuner. */ FM_TUNER = 1998, + /** Virtual source for the last captured hotword. */ HOTWORD = 1999, }; @@ -562,7 +603,7 @@ enum AudioMode : int32_t { IN_CALL = 2, /** Calls handled by apps (Eg: Hangout). */ IN_COMMUNICATION = 3, - /** Call screening in progress */ + /** Call screening in progress. */ CALL_SCREEN = 4, }; @@ -748,23 +789,85 @@ enum AudioUsage : int32_t { // These values must kept in sync with // frameworks/base/media/java/android/media/AudioAttributes.java // Note that not all framework values are exposed + /** + * Usage value to use when the usage is unknown. + */ UNKNOWN = 0, + /** + * Usage value to use when the usage is media, such as music, or movie + * soundtracks. + */ MEDIA = 1, + /** + * Usage value to use when the usage is voice communications, such as + * telephony or VoIP. + */ VOICE_COMMUNICATION = 2, + /** + * Usage value to use when the usage is in-call signalling, such as with + * a "busy" beep, or DTMF tones. + */ VOICE_COMMUNICATION_SIGNALLING = 3, + /** + * Usage value to use when the usage is an alarm (e.g. wake-up alarm). + */ ALARM = 4, + /** + * Usage value to use when the usage is a generic notification. + */ NOTIFICATION = 5, + /** + * Usage value to use when the usage is telephony ringtone. + */ NOTIFICATION_TELEPHONY_RINGTONE = 6, + /** + * Usage value to use when the usage is for accessibility, such as with + * a screen reader. + */ ASSISTANCE_ACCESSIBILITY = 11, + /** + * Usage value to use when the usage is driving or navigation directions. + */ ASSISTANCE_NAVIGATION_GUIDANCE = 12, + /** + * Usage value to use when the usage is sonification, such as with user + * interface sounds. + */ ASSISTANCE_SONIFICATION = 13, + /** + * Usage value to use when the usage is for game audio. + */ GAME = 14, + /** + * Usage value to use when feeding audio to the platform and replacing + * "traditional" audio source, such as audio capture devices. + */ VIRTUAL_SOURCE = 15, + /** + * Usage value to use for audio responses to user queries, audio + * instructions or help utterances. + */ ASSISTANT = 16, + /** + * Usage value to use for assistant voice interaction with remote caller + * on Cell and VoIP calls. + */ CALL_ASSISTANT = 17, + /** + * Usage value to use when the usage is an emergency. + */ EMERGENCY = 1000, + /** + * Usage value to use when the usage is a safety sound. + */ SAFETY = 1001, + /** + * Usage value to use when the usage is a vehicle status. + */ VEHICLE_STATUS = 1002, + /** + * Usage value to use when the usage is an announcement. + */ ANNOUNCEMENT = 1003, }; @@ -773,10 +876,30 @@ enum AudioUsage : int32_t { enum AudioContentType : uint32_t { // Do not change these values without updating their counterparts // in frameworks/base/media/java/android/media/AudioAttributes.java + /** + * Content type value to use when the content type is unknown, or other than + * the ones defined. + */ UNKNOWN = 0, + /** + * Content type value to use when the content type is speech. + */ SPEECH = 1, + /** + * Content type value to use when the content type is music. + */ MUSIC = 2, + /** + * Content type value to use when the content type is a soundtrack, + * typically accompanying a movie or TV program. + */ MOVIE = 3, + /** + * Content type value to use when the content type is a sound used to + * accompany a user action, such as a beep or sound effect expressing a key + * click, or event, such as the type of a sound for a bonus being received + * in a game. These sounds are mostly synthesized or short Foley sounds. + */ SONIFICATION = 4, }; diff --git a/current.txt b/current.txt index 8d068d0e89..f3b66eb055 100644 --- a/current.txt +++ b/current.txt @@ -612,7 +612,7 @@ fd1f1b29f26b42e886220f04a08086c00e5ade9d7b53f095438e578ab9d42a93 android.hardwar 2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn 78e4138cc8307c11fc777c3bd376e581ba4ba48196b05ca1d7cdfa515c87b48a android.hardware.audio@6.0::IStreamOut 997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback -43a3303378f5b9852c2da9ac2c1d440965aab7ba02a800229e7b3c84e2167e06 android.hardware.audio.common@6.0::types +167ed5cfb7d91db2e2bf20f1320c1a9004eeb768e26f535e0f7db94a21867d21 android.hardware.audio.common@6.0::types 817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types 525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect 8d76bbe3719d051a8e9a1dcf9244f37f5b0a491feb249fa48391edf7cb4f3131 android.hardware.audio.effect@6.0::IAutomaticGainControlEffect From 8edc5b83268f42aad4ad75c55ecc698c548af21d Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 29 Jan 2020 14:04:51 -0800 Subject: [PATCH 0543/1022] Added more properties associated with user management: - CREATE_USER: called after an Android user is created. - REMOVE_USER: called after an Android user is removed. - USER_IDENTIFICATION_ASSOCIATION: associates an Android user with vehicle artifacts like a key FOB. This CL only defines the new types, they're not implemented or used yet. Test: m -j android.hardware.automotive.vehicle@2.0-service Bug: 146207078 Change-Id: Idb399df55567402edb1b954b1c4b25f69e810a81 --- automotive/vehicle/2.0/types.hal | 414 ++++++++++++++++++++++++++++++- 1 file changed, 410 insertions(+), 4 deletions(-) diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index a91bd885b3..7a5f2d2e9b 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -2473,7 +2473,8 @@ enum VehicleProperty : int32_t { * 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, TODO(b/146207078):others). + * user-related properties (INITIAL_USER_INFO, SWITCH_USER, CREATE_USER, REMOVE_USER, + * and USER_IDENTIFICATION_ASSOCIATION). * * @change_mode VehiclePropertyChangeMode:ON_CHANGE * @access VehiclePropertyAccess:READ_WRITE @@ -2649,6 +2650,161 @@ enum VehicleProperty : int32_t { | VehiclePropertyGroup:SYSTEM | VehiclePropertyType:MIXED | VehicleArea:GLOBAL), + + /** + * Called by the Android System after an Android user was created. + * + * The HAL can use this property to create its equivalent user. + * + * This is an async request: Android makes the request by setting a VehiclePropValue, and HAL + * must respond with a property change indicating whether the request succeeded or failed. If + * it failed, the Android system will remove the user. + * + * The format of the request is defined by CreateUserRequest and the format of the response by + * CreateUserResponse. + * + * For example, if system had 2 users (0 and 10) and a 3rd one (which is an ephemeral guest) was + * created, the request would be: + * + * int32[0]: 42 // request id + * int32[1]: 11 // Android id of the created user + * int32[2]: 3 // Android flags (ephemeral guest) of the created user + * int32[3]: 10 // current user + * int32[4]: 0 // current user flags (none) + * int32[5]: 3 // number of users + * int32[6]: 0 // 1st user (user 0) + * int32[7]: 0 // 1st user flags (none) + * int32[8]: 10 // 2nd user (user 10) + * int32[9]: 0 // 2nd user flags (none) + * int32[19]: 11 // 3rd user (user 11) + * int32[11]: 3 // 3rd user flags (ephemeral guest) + * string: "ElGuesto" // name of the new user + * + * Then if the request succeeded, the HAL would return: + * + * int32[0]: 42 // request id + * int32[1]: 1 // CreateUserStatus::SUCCESS + * + * But if it failed: + * + * int32[0]: 42 // request id + * int32[1]: 2 // CreateUserStatus::FAILURE + * string: "D'OH!" // The meaning is a blackbox - it's passed to the caller (like Settings UI), + * // which in turn can take the proper action. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + CREATE_USER = ( + 0x0F09 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:MIXED + | VehicleArea:GLOBAL), + + /** + * Called by the Android System after an Android user was removed. + * + * The HAL can use this property to remove its equivalent user. + * + * This is write-only call - the Android System is not expecting a reply from the HAL. Hence, + * this request should not fail - if the equivalent HAL user cannot be removed, then HAL should + * mark it as inactive or recover in some other way. + * + * The request is made by setting the VehiclePropValue with the contents defined by + * RemoveUserRequest. + * + * For example, if system had 3 users (0, 10, and 11) and user 11 was removed, the request + * would be: + * + * int32[0]: 42 // request id + * int32[1]: 11 // (Android user id of the removed user) + * int32[2]: 0 // (Android user flags of the removed user) + * int32[3]: 10 // current user + * int32[4]: 0 // current user flags (none) + * int32[5]: 2 // number of users + * int32[6]: 0 // 1st user (user 0) + * int32[7]: 0 // 1st user flags (none) + * int32[8]: 10 // 2nd user (user 10) + * int32[9]: 0 // 2nd user flags (none) + * + * @change_mode VehiclePropertyChangeMode:STATIC + * @access VehiclePropertyAccess:WRITE + */ + REMOVE_USER = ( + 0x0F0A + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:MIXED + | VehicleArea:GLOBAL), + + /** + * Property used to associate (or query the association) the current user with vehicle-specific + * identification mechanisms (such as key FOB). + * + * To query the association, the Android system gets the property, passing a VehiclePropValue + * containing the types of associations are being queried, as defined by + * UserIdentificationGetRequest. The HAL must return right away, updating the VehiclePropValue + * with a UserIdentificationResponse. Notice that user identification should have already + * happened while system is booting up and the VHAL implementation should only return the + * already identified association (like the key FOB used to unlock the car), instead of starting + * a new association from the get call. + * + * To associate types, the Android system sets the property, passing a VehiclePropValue + * containing the types and values of associations being set, as defined by the + * UserIdentificationSetRequest. The HAL will then use a property change event (whose + * VehiclePropValue is defined by UserIdentificationResponse) indicating the current status of + * the types after the request. + * + * For example, to query if the current user (10) is associated with the FOB that unlocked the + * car and a custom mechanism provided by the OEM, the request would be: + * + * int32[0]: 10 (Android user id) + * int32[1]: 0 (Android user flags) + * int32[2]: 2 (number of types queried) + * int32[3]: 1 (1st type queried, UserIdentificationAssociationType::KEY_FOB) + * int32[4]: 101 (2nd type queried, UserIdentificationAssociationType::CUSTOM_1) + * + * If the user is associated with the FOB but not with the custom mechanism, the response would + * be: + * + * int32[9]: 2 (number of associations in the response) + * int32[1]: 1 (1st type: UserIdentificationAssociationType::KEY_FOB) + * int32[2]: 2 (1st value: UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER) + * int32[3]: 101 (2st type: UserIdentificationAssociationType::CUSTOM_1) + * int32[4]: 4 (2nd value: UserIdentificationAssociationValue::NOT_ASSOCIATED_ANY_USER) + * + * Then to associate the user with the custom mechanism, a set request would be made: + * + * int32[0]: 10 (Android user id) + * int32[0]: 0 (Android user flags) + * int32[1]: 1 (number of associations being set) + * int32[2]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1) + * int32[3]: 1 (1st value: UserIdentificationAssociationSETValue::ASSOCIATE_CURRENT_USER) + * + * If the request succeeded, the response would be simply: + * + * int32[0]: 2 (number of associations in the response) + * int32[1]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1) + * int32[2]: 1 (1st value: UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER) + * + * Notice that the set request adds associations, but doesn't remove the existing ones. In the + * example above, the end state would be 2 associations (FOB and CUSTOM_1). If we wanted to + * associate the user with just CUSTOM_1 but not FOB, then the request should have been: + * + * int32[0]: 10 (Android user id) + * int32[1]: 2 (number of types set) + * int32[2]: 1 (1st type: UserIdentificationAssociationType::KEY_FOB) + * int32[3]: 2 (1st value: UserIdentificationAssociationValue::DISASSOCIATE_CURRENT_USER) + * int32[3]: 101 (2nd type: UserIdentificationAssociationType::CUSTOM_1) + * int32[5]: 1 (2nd value: UserIdentificationAssociationValue::ASSOCIATE_CURRENT_USER) + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + USER_IDENTIFICATION_ASSOCIATION = ( + 0x0F0B + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:MIXED + | VehicleArea:GLOBAL), }; /** @@ -4184,10 +4340,10 @@ struct SwitchUserResponse { /** * HAL-specific error message. * - * This argument is optional, and when defined (and the status is FAILURE), it's passed "as-is" - * to the caller. It could be used to show custom error messages to the end user. + * This argument is optional, and when defined, it's passed "as-is" to the caller. It could be + * used to show custom error messages to the end user. */ - string failureMessage; + string errorMessage; }; /** @@ -4199,3 +4355,253 @@ enum SwitchUserStatus : int32_t { /** The request failed and the HAL user remained the same. */ FAILURE = 2, }; + +/** + * Defines the format of a CREATE_USER property. + * + * NOTE: this struct is not used in the HAL properties directly, it must be converted to + * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation. + */ +struct CreateUserRequest { + /** + * Arbitrary id used to map the response to the request. + */ + UserRequestId requestId; + + /** + * Basic information about Android user that was created. + */ + UserInfo newUserInfo; + + /** + * Name of the new Android user. + */ + string newUserName; + + /** + * Information about the current state of the Android system. + */ + UsersInfo usersInfo; +}; + +/** + * Defines the result of a CreateUserRequest. + * + * NOTE: this struct is not used in the HAL properties directly, it must be converted to + * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation. + */ +struct CreateUserResponse { + /** + * Id of the request being responded. + */ + UserRequestId requestId; + + /** + * Status of the request. + */ + CreateUserStatus status; + + /** + * HAL-specific error message. + * + * This argument is optional, and when defined, it's passed "as-is" to the caller. It could be + * used to show custom error messages to the end user. + */ + string errorMessage; +}; + +/** + * Status of the response to a CreateUserRequest. + */ +enum CreateUserStatus : int32_t { + /** + * The request succeeded (for example, HAL created a new internal user, or associated the + * Android user to an existing internal user). + */ + SUCCESS = 1, + + /** + * The request failed (and Android will remove the Android user). + */ + FAILURE = 2, +}; + +/** + * Defines the format of a REMOVE_USER property. + * + * NOTE: this struct is not used in the HAL properties directly, it must be converted to + * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation. + */ +struct RemoveUserRequest { + /** + * Arbitrary id used to map the response to the request. + */ + UserRequestId requestId; + + /** + * Information about the Android user that was removed. + */ + UserInfo removedUserInfo; + + /** + * Information about the current state of the Android system. + */ + UsersInfo usersInfo; +}; + +/** + * Types of mechanisms used to identify an Android user. + * + * See USER_IDENTIFICATION_ASSOCIATION for more details and example. + */ +enum UserIdentificationAssociationType: int32_t { + /** Key used to unlock the car. */ + KEY_FOB = 1, + /** Custom mechanism defined by the OEM. */ + CUSTOM_1 = 101, + /** Custom mechanism defined by the OEM. */ + CUSTOM_2 = 102, + /** Custom mechanism defined by the OEM. */ + CUSTOM_3 = 103, + /** Custom mechanism defined by the OEM. */ + CUSTOM_4 = 104, +}; + +/** + * Whether a UserIdentificationAssociationType is associate with an Android user. + */ +enum UserIdentificationAssociationValue : int32_t { + /** + * Used when the status of an association could not be determined. + * + * For example, in a set() request, it would indicate a failure to set the given type. + */ + UNKNOWN = 1, + + /** + * The identification type is associated with the current foreground Android user. + */ + ASSOCIATED_CURRENT_USER = 2, + + /** + * The identification type is associated with another Android user. + */ + ASSOCIATED_ANOTHER_USER = 3, + + /** + * The identification type is not associated with any Android user. + */ + NOT_ASSOCIATED_ANY_USER = 4, +}; + +/** + * Used to set a UserIdentificationAssociationType with an Android user. + */ +enum UserIdentificationAssociationSetValue : int32_t { + /** + * Associate the identification type with the current foreground Android user. + */ + ASSOCIATE_CURRENT_USER = 1, + + /** + * Disassociate the identification type from the current foreground Android user. + */ + DISASSOCIATE_CURRENT_USER = 2, + + /** + * Disassociate the identification type from all Android users. + */ + DISASSOCIATE_ALL_USERS = 3, +}; + +/** + * Defines the format of a get() call to USER_IDENTIFICATION_ASSOCIATION. + * + * NOTE: this struct is not used in the HAL properties directly, it must be converted to + * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation. + */ +struct UserIdentificationGetRequest { + /** + * Information about the current foreground Android user. + */ + UserInfo userInfo; + + /** + * Number of association being queried. + */ + int32_t numberAssociationTypes; + + /** + * Types of association being queried. + */ + vec associationTypes; +}; + +/** + * Defines the format of a set() call to USER_IDENTIFICATION_ASSOCIATION. + * + * NOTE: this struct is not used in the HAL properties directly, it must be converted to + * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation. + */ +struct UserIdentificationSetRequest { + /** + * Information about the current foreground Android user. + */ + UserInfo userInfo; + + /** + * Number of association being set. + */ + int32_t numberAssociations; + + /** + * Associations being set. + */ + vec associations; +}; + +/** + * Defines the result of a USER_IDENTIFICATION_ASSOCIATION - both for get() and set(). + * + * NOTE: this struct is not used in the HAL properties directly, it must be converted to + * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation. + */ +struct UserIdentificationResponse { + /** + * Number of associations being returned. + */ + int32_t numberAssociation; + + /** + * Values associated with the user. + */ + vec associations; + + /** + * HAL-specific error message. + * + * This argument is optional, and when defined, it's passed "as-is" to the caller. It could be + * used to show custom error messages to the end user. + */ + string errorMessage; +}; + +/** + * Helper struct used when getting a user/identification association type. + */ +struct UserIdentificationAssociation { + + UserIdentificationAssociationType type; + + UserIdentificationAssociationValue value; +}; + +/** + * Helper struct used when setting a user/identification association type. + */ +struct UserIdentificationSetAssociation { + + UserIdentificationAssociationType type; + + UserIdentificationAssociationSetValue value; +}; From 33e0578cdd71564dc7920b9586d3a7e28b12f8a8 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Tue, 4 Feb 2020 18:51:47 -0800 Subject: [PATCH 0544/1022] audio: Clarify documentation for some methods - explain the meaning of "audio patch" in IDevice.supportsAudioPatches method; - clarify effect insertion order in IDevice.addDeviceEffect Bug: 148617378 Test: N/A Change-Id: Ifd7ec3dc9a53c949be0c8c823df499e4b20db4bd --- audio/6.0/IDevice.hal | 9 +++++++-- current.txt | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal index c2e310ce69..2026d8ff8b 100644 --- a/audio/6.0/IDevice.hal +++ b/audio/6.0/IDevice.hal @@ -149,7 +149,10 @@ interface IDevice { AudioConfig suggestedConfig); /** - * Returns whether HAL supports audio patches. + * Returns whether HAL supports audio patches. Patch represents a connection + * between signal source(s) and signal sink(s). If HAL doesn't support + * patches natively (in hardware) then audio system will need to establish + * them in software. * * @return supports true if audio patches are supported. */ @@ -316,7 +319,9 @@ interface IDevice { close() generates (Result retval); /** - * Applies an audio effect to an audio device. + * Applies an audio effect to an audio device. The effect is inserted + * according to its insertion preference specified by INSERT_... EffectFlags + * in the EffectDescriptor. * * @param device identifies the sink or source device this effect must be applied to. * "device" is the AudioPortHandle indicated for the device when the audio diff --git a/current.txt b/current.txt index f3b66eb055..b0b9529b6d 100644 --- a/current.txt +++ b/current.txt @@ -605,7 +605,7 @@ ff5dd821c2c7a9c78607159c4d788960b725487263c49d956ca5fa3d37008b45 android.hardwar # HALs released in Android R e966a3437d6a98d9d9e14e9d672088771716031900c0deb55a0946c751a03a44 android.hardware.audio@6.0::types -dd3e9280be60a5e042331c1046d13938e2cc323dc4b267cc74d544bf62fc0314 android.hardware.audio@6.0::IDevice +7241bd4596a927cd46d4b82f5e29e2cbe57f194aa1b25555f1d1d352e8b15c61 android.hardware.audio@6.0::IDevice 2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice fd1f1b29f26b42e886220f04a08086c00e5ade9d7b53f095438e578ab9d42a93 android.hardware.audio@6.0::IStream From 6a4172cd3dd503af20685fa6fd35e62c538b309e Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Tue, 4 Feb 2020 16:15:04 -0800 Subject: [PATCH 0545/1022] NN 1.3 HAL: ANAPIC review follow up This CL makes the following three interface changes: * Removes @1.3::Operand.ExtraParams, because it was the same as @1.2::Operand.ExtraParams * Changes int32_t token to uint32_t for IDevice::allocate and for @1.3::Request.MemoryPool * Renames OptionalTimePoint::nanoseconds to OptionalTimePoint::nanosecondsSinceEpoch This CL also makes test changes in response to the interface changes, and fixes a minor comment issue in @1.2::types.hal and @1.3::types.hal. Bug: 148617339 Test: mma Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: I95b49ab34b0b79f587dda035ede700b73dc44a38 --- current.txt | 6 ++-- neuralnetworks/1.2/types.hal | 2 +- neuralnetworks/1.3/IDevice.hal | 2 +- neuralnetworks/1.3/types.hal | 30 ++++--------------- neuralnetworks/1.3/types.t | 28 +++-------------- .../vts/functional/GeneratedTestHarness.cpp | 26 ++++++++-------- .../vts/functional/QualityOfServiceTests.cpp | 4 +-- .../1.3/vts/functional/ValidateModel.cpp | 2 +- .../1.3/vts/functional/ValidateRequest.cpp | 2 +- 9 files changed, 31 insertions(+), 71 deletions(-) diff --git a/current.txt b/current.txt index bb48cd3f4f..4c22540d70 100644 --- a/current.txt +++ b/current.txt @@ -596,7 +596,7 @@ eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardwar 5f6d3097ba84cb63c430787123f4de1b31c11f90b531b98eae9a8623a5ae962a android.hardware.neuralnetworks@1.1::types fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice 40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel -7f7ef383268c95a1b8fe4e55c662bc806bb0ac11a154f6b049a113a44b0f024f android.hardware.neuralnetworks@1.2::types +6c29d6fdd5445911df5456b3b84b949cdd59fca0c0b5507662f26a5cac0cf5e5 android.hardware.neuralnetworks@1.2::types a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface @@ -667,12 +667,12 @@ ddcf89cd8ee2df0d32aee55050826446fb64f7aafde0a7cd946c64f61b1a364c android.hardwar df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore 65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer -9b41dd49e2dcc2ecb4243d03f8421d72494ada5cf2945bff88f0019eeca56923 android.hardware.neuralnetworks@1.3::IDevice +9db064ee44268a876be0367ff771e618362d39ec603b6ecab17e1575725fcd87 android.hardware.neuralnetworks@1.3::IDevice 4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback 2fa3679ad7c94b5e88724adcd560c561041068a4ca565c63830e68101988746a android.hardware.neuralnetworks@1.3::IFencedExecutionCallback 237b23b126a66f3432658020fed78cdd06ba6297459436fe6bae0ba753370833 android.hardware.neuralnetworks@1.3::IPreparedModel 0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback -3646950b10f7cacdafca13609b0e18496cea942f3bdfe920494661856eff48bb android.hardware.neuralnetworks@1.3::types +abbc4e1a969881c9f8ab587add5b5e75b08df834c9c969c013ae38cb4bb16f6a android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal index e867120906..993a10513f 100644 --- a/neuralnetworks/1.2/types.hal +++ b/neuralnetworks/1.2/types.hal @@ -3165,7 +3165,7 @@ enum OperationType : int32_t { * * 8: An {@link OperandType::INT32} scalar, specifying the stride when * walking through input in the ‘height’ dimension. * * 9: An {@link OperandType::INT32} scalar, specifying the number of - groups. + * groups. * * 10: An {@link OperandType::INT32} scalar, and has to be one of the * {@link FusedActivationFunc} values. Specifies the activation to * invoke on the result. diff --git a/neuralnetworks/1.3/IDevice.hal b/neuralnetworks/1.3/IDevice.hal index 493153950a..79f9c325ac 100644 --- a/neuralnetworks/1.3/IDevice.hal +++ b/neuralnetworks/1.3/IDevice.hal @@ -372,5 +372,5 @@ interface IDevice extends @1.2::IDevice { */ allocate(BufferDesc desc, vec preparedModels, vec inputRoles, vec outputRoles) - generates (ErrorStatus status, IBuffer buffer, int32_t token); + generates (ErrorStatus status, IBuffer buffer, uint32_t token); }; diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index ed577e4d9d..c5dc08c338 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -22,9 +22,9 @@ import @1.0::PerformanceInfo; import @1.0::RequestArgument; import @1.2::Model.ExtensionNameAndPrefix; import @1.2::Model.ExtensionTypeEncoding; +import @1.2::Operand.ExtraParams; import @1.2::OperandType; import @1.2::OperationType; -import @1.2::SymmPerChannelQuantParams; import android.hidl.safe_union@1.0::Monostate; @@ -3253,7 +3253,7 @@ enum OperationType : int32_t { * * 8: An {@link OperandType::INT32} scalar, specifying the stride when * walking through input in the ‘height’ dimension. * * 9: An {@link OperandType::INT32} scalar, specifying the number of - groups. + * groups. * * 10: An {@link OperandType::INT32} scalar, and has to be one of the * {@link FusedActivationFunc} values. Specifies the activation to * invoke on the result. @@ -5343,27 +5343,7 @@ struct Operand { /** * Additional parameters specific to a particular operand type. */ - safe_union ExtraParams { - /** - * No additional parameters. - */ - Monostate none; - - /** - * Symmetric per-channel quantization parameters. - * - * Only applicable to operands of type TENSOR_QUANT8_SYMM_PER_CHANNEL. - */ - SymmPerChannelQuantParams channelQuant; - - /** - * Extension operand parameters. - * - * The framework treats this as an opaque data blob. - * The format is up to individual extensions. - */ - vec extension; - } extraParams; + @1.2::Operand.ExtraParams extraParams; }; /** @@ -5551,7 +5531,7 @@ struct Request { * Specifies a driver-managed buffer. It is the token returned from IDevice::allocate, * and is specific to the IDevice object. */ - int32_t token; + uint32_t token; }; /** @@ -5573,7 +5553,7 @@ safe_union OptionalTimePoint { * Time point of the steady clock (as from std::chrono::steady_clock) * measured in nanoseconds. */ - uint64_t nanoseconds; + uint64_t nanosecondsSinceEpoch; }; /** diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t index d4351ec8d7..3d0d02df46 100644 --- a/neuralnetworks/1.3/types.t +++ b/neuralnetworks/1.3/types.t @@ -24,9 +24,9 @@ import @1.0::PerformanceInfo; import @1.0::RequestArgument; import @1.2::Model.ExtensionNameAndPrefix; import @1.2::Model.ExtensionTypeEncoding; +import @1.2::Operand.ExtraParams; import @1.2::OperandType; import @1.2::OperationType; -import @1.2::SymmPerChannelQuantParams; import android.hidl.safe_union@1.0::Monostate; @@ -319,27 +319,7 @@ struct Operand { /** * Additional parameters specific to a particular operand type. */ - safe_union ExtraParams { - /** - * No additional parameters. - */ - Monostate none; - - /** - * Symmetric per-channel quantization parameters. - * - * Only applicable to operands of type TENSOR_QUANT8_SYMM_PER_CHANNEL. - */ - SymmPerChannelQuantParams channelQuant; - - /** - * Extension operand parameters. - * - * The framework treats this as an opaque data blob. - * The format is up to individual extensions. - */ - vec extension; - } extraParams; + @1.2::Operand.ExtraParams extraParams; }; /** @@ -527,7 +507,7 @@ struct Request { * Specifies a driver-managed buffer. It is the token returned from IDevice::allocate, * and is specific to the IDevice object. */ - int32_t token; + uint32_t token; }; /** @@ -549,7 +529,7 @@ safe_union OptionalTimePoint { * Time point of the steady clock (as from std::chrono::steady_clock) * measured in nanoseconds. */ - uint64_t nanoseconds; + uint64_t nanosecondsSinceEpoch; }; /** diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 8ea0b7eb47..82f34ff779 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -122,15 +122,15 @@ class DeviceMemoryAllocator { // Return {IBuffer object, token} if successful. // Return {nullptr, 0} if device memory is not supported. template - std::pair, int32_t> allocate(uint32_t index) { - std::pair, int32_t> buffer; + std::pair, uint32_t> allocate(uint32_t index) { + std::pair, uint32_t> buffer; allocateInternal(index, &buffer); return buffer; } private: template - void allocateInternal(uint32_t index, std::pair, int32_t>* result) { + void allocateInternal(uint32_t index, std::pair, uint32_t>* result) { ASSERT_NE(result, nullptr); // Prepare arguments. @@ -145,14 +145,14 @@ class DeviceMemoryAllocator { // Allocate device memory. ErrorStatus status; sp buffer; - int32_t token; - const auto ret = kDevice->allocate( - {}, {kPreparedModel}, inputRoles, outputRoles, - [&status, &buffer, &token](ErrorStatus error, const sp& buf, int32_t tok) { - status = error; - buffer = buf; - token = tok; - }); + uint32_t token; + auto cb = [&status, &buffer, &token](ErrorStatus error, const sp& buf, + uint32_t tok) { + status = error; + buffer = buf; + token = tok; + }; + const auto ret = kDevice->allocate({}, {kPreparedModel}, inputRoles, outputRoles, cb); // Check allocation results. ASSERT_TRUE(ret.isOk()); @@ -217,7 +217,7 @@ Model createModel(const TestModel& testModel) { constRefSize += op.data.alignedSize(); } - Operand::ExtraParams extraParams; + V1_2::Operand::ExtraParams extraParams; if (op.type == TestOperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) { extraParams.channelQuant(SymmPerChannelQuantParams{ .scales = op.channelQuant.scales, .channelDim = op.channelQuant.channelDim}); @@ -317,7 +317,7 @@ static std::pair>> createRequest( // - [2+i, 2+i+o): Output device memories DeviceMemoryAllocator allocator(device, preparedModel, testModel); std::vector> buffers; - std::vector tokens; + std::vector tokens; // Model inputs. hidl_vec inputs(testModel.inputIndexes.size()); diff --git a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp index 62ffcda036..2f1e05c5c6 100644 --- a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp +++ b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp @@ -64,11 +64,11 @@ static OptionalTimePoint makeOptionalTimePoint(DeadlineBoundType deadlineBoundTy std::chrono::time_point_cast(currentTime); const uint64_t nanosecondsSinceEpoch = currentTimeInNanoseconds.time_since_epoch().count(); - deadline.nanoseconds(nanosecondsSinceEpoch); + deadline.nanosecondsSinceEpoch(nanosecondsSinceEpoch); } break; case DeadlineBoundType::UNLIMITED: { uint64_t unlimited = std::numeric_limits::max(); - deadline.nanoseconds(unlimited); + deadline.nanosecondsSinceEpoch(unlimited); } break; } return deadline; diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 1245432307..0a35e2d233 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -50,7 +50,7 @@ static void validatePrepareModel(const sp& device, const std::string& m OptionalTimePoint deadline; if (testDeadline) { - deadline.nanoseconds(std::numeric_limits::max()); + deadline.nanosecondsSinceEpoch(std::numeric_limits::max()); } sp preparedModelCallback = new PreparedModelCallback(); diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index 2fd9b647f1..71fe97f831 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -61,7 +61,7 @@ static void validate(const sp& preparedModel, const std::string& OptionalTimePoint deadline; if (testDeadline) { - deadline.nanoseconds(std::numeric_limits::max()); + deadline.nanosecondsSinceEpoch(std::numeric_limits::max()); } // asynchronous From 9be5a79afe8a5b7d6d40b4d72ab1d408d5d43594 Mon Sep 17 00:00:00 2001 From: lesl Date: Tue, 14 Jan 2020 19:48:50 +0800 Subject: [PATCH 0546/1022] vts: Use shell command to get softap feature We should only run the vts which claim is supported. Bug: 140172237 Test: atest VtsHalWifiHostapdV1_2TargetTest Change-Id: If0b1d9f0a73bd171621299dab7828a9caf928a7a --- .../1.2/vts/functional/hostapd_hidl_test.cpp | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp index 9f57934a34..2715891b92 100644 --- a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp +++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #include #include @@ -62,11 +64,19 @@ class HostapdHidlTest hostapd_instance_name_); hostapd_ = IHostapd::getService(hostapd_instance_name_); ASSERT_NE(hostapd_.get(), nullptr); + isAcsSupport_ = testing::checkSubstringInCommandOutput( + "/system/bin/cmd wifi get-softap-supported-features", + "wifi_softap_acs_supported"); + isWpa3SaeSupport_ = testing::checkSubstringInCommandOutput( + "/system/bin/cmd wifi get-softap-supported-features", + "wifi_softap_wpa3_sae_supported"); } virtual void TearDown() override { stopHostapd(hostapd_instance_name_); } protected: + bool isWpa3SaeSupport_ = false; + bool isAcsSupport_ = false; std::string getPrimaryWlanIfaceName() { std::array buffer; auto res = property_get("ro.vendor.wifi.sap.interface", buffer.data(), @@ -208,10 +218,10 @@ class HostapdHidlTest * Access point creation should pass. */ TEST_P(HostapdHidlTest, AddPskAccessPointWithAcs) { + if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support"; auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithAcs(), getPskNwParams()); - // TODO: b/140172237, fix this in R. - // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); } /** @@ -219,11 +229,11 @@ TEST_P(HostapdHidlTest, AddPskAccessPointWithAcs) { * Access point creation should pass. */ TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndFreqRange) { + if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support"; auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithAcsAndFreqRange(), getPskNwParams()); - // TODO: b/140172237, fix this in R - // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); } /** @@ -231,11 +241,11 @@ TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndFreqRange) { * Access point creation should fail. */ TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidFreqRange) { + if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support"; auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithAcsAndInvalidFreqRange(), getPskNwParams()); - // TODO: b/140172237, fix this in R - // EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); + EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); } /** @@ -243,10 +253,10 @@ TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidFreqRange) { * Access point creation should pass. */ TEST_P(HostapdHidlTest, AddOpenAccessPointWithAcs) { + if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support"; auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithAcs(), getOpenNwParams()); - // TODO: b/140172237, fix this in R - // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); } /** @@ -274,6 +284,7 @@ TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) { * Access point creation should pass. */ TEST_P(HostapdHidlTest, AddSaeTransitionAccessPointWithoutAcs) { + if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support"; auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(), getSaeTransitionNwParams()); @@ -285,6 +296,7 @@ TEST_P(HostapdHidlTest, AddSaeTransitionAccessPointWithoutAcs) { * Access point creation should pass. */ TEST_P(HostapdHidlTest, AddSAEAccessPointWithoutAcs) { + if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support"; auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(), getSaeNwParams()); EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); @@ -295,16 +307,15 @@ TEST_P(HostapdHidlTest, AddSAEAccessPointWithoutAcs) { * Access point creation & removal should pass. */ TEST_P(HostapdHidlTest, RemoveAccessPointWithAcs) { + if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support"; auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithAcs(), getPskNwParams()); - // TODO: b/140172237, fix this in R - /* EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code); auto status = HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); - EXPECT_EQ(android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS, - status.code); - */ + EXPECT_EQ( + android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS, + status.code); } /** @@ -349,6 +360,7 @@ TEST_P(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) { * Access point creation should fail. */ TEST_P(HostapdHidlTest, AddInvalidSaeTransitionAccessPointWithoutAcs) { + if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support"; auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(), getInvalidSaeTransitionNwParams()); @@ -360,6 +372,7 @@ TEST_P(HostapdHidlTest, AddInvalidSaeTransitionAccessPointWithoutAcs) { * Access point creation should fail. */ TEST_P(HostapdHidlTest, AddInvalidSaeAccessPointWithoutAcs) { + if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support"; auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(), getInvalidSaeNwParams()); From 75a27f8b372df1c3957cf7f9a78710c5051c63d4 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Fri, 31 Jan 2020 15:25:55 -0800 Subject: [PATCH 0547/1022] Implemented IVehicle::debug() on default Vehicle HAL implementation. This function allows developer to drive (no pun intend) the VHAL behaviour using lshal, which is useful when implementing new CarService functionalities that depend on VHAL properties. Examples: $ adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default --help Usage: [no args]: dumps (id and value) all supported properties --help: shows this help --list: lists the ids of all supported properties --get [PROP2] [PROPN]: dumps the value of specific properties --set : sets the value of property PROP, using an arbitrary number of key/value parameters (i for int32, s for string) $ adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default | head -2 dumping 87 properties 1: {.timestamp = 0, .areaId = 0, .prop = 299896583, .status = AVAILABLE, .value = {.int32Values = [3]{42, 1, 10}, .floatValues = [0]{}, .int64Values = [0]{}, .bytes = [0]{}, .stringValue = ""}} $ adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default \ --set 299896583 s Numbers i 4 i 8 i 15 i 16 i 23 i 42 Set property {.timestamp = 0, .areaId = 0, .prop = 299896583, .status = AVAILABLE, .value = {.int32Values = [6]{4, 8, 15, 16, 23, 42}, .floatValues = [0]{}, .int64Values = [0]{}, .bytes = [0]{}, .stringValue = "Numbers"}} $ adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default \ --get 299896583 {.timestamp = 102372810363603, .areaId = 0, .prop = 299896583, .status = AVAILABLE, .value = {.int32Values = [6]{4, 8, 15, 16, 23, 42}, .floatValues = [0]{}, .int64Values = [0]{}, .bytes = [0]{}, .stringValue = "Numbers"}} Bug: 146207078 Test: see examples above Test: atest android.hardware.automotive.vehicle@2.0-manager-unit-tests \ android.hardware.automotive.vehicle@2.0-default-impl-unit-tests Change-Id: I2a9bd6f39f2938653a404cab43bdae9e45476529 --- automotive/vehicle/2.0/default/Android.bp | 10 +- .../include/vhal_v2_0/VehicleHalManager.h | 20 +- .../default/common/src/VehicleHalManager.cpp | 238 +++++++++++++++++- 3 files changed, 264 insertions(+), 4 deletions(-) diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp index a94a37e0f1..e325889517 100644 --- a/automotive/vehicle/2.0/default/Android.bp +++ b/automotive/vehicle/2.0/default/Android.bp @@ -47,6 +47,9 @@ cc_library { "common/src/VehicleUtils.cpp", "common/src/VmsUtils.cpp", ], + shared_libs: [ + "libbase", + ], local_include_dirs: ["common/include/vhal_v2_0"], export_include_dirs: ["common/include"], } @@ -109,6 +112,9 @@ cc_test { "tests/VehiclePropConfigIndex_test.cpp", "tests/VmsUtils_test.cpp", ], + shared_libs: [ + "libbase", + ], header_libs: ["libbase_headers"], test_suites: ["general-tests"], } @@ -173,7 +179,7 @@ cc_binary { "libqemu_pipe", ], cflags: [ - "-Wno-unused-parameter" + "-Wno-unused-parameter", ], } @@ -200,6 +206,6 @@ cc_binary { "android.hardware.automotive.vehicle@2.0-virtualization-utils", ], cflags: [ - "-Wno-unused-parameter" + "-Wno-unused-parameter", ], } diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h index c1e9e88609..fcfe7612ac 100644 --- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h @@ -73,7 +73,9 @@ public: int32_t propId) override; Return debugDump(debugDump_cb _hidl_cb = nullptr) override; -private: + Return debug(const hidl_handle& fd, const hidl_vec& options) override; + + private: using VehiclePropValuePtr = VehicleHal::VehiclePropValuePtr; // Returns true if needs to call again shortly. using RetriableAction = std::function; @@ -96,6 +98,22 @@ private: bool checkReadPermission(const VehiclePropConfig &config) const; void onAllClientsUnsubscribed(int32_t propertyId); + // Dump and commands + // TODO: most functions below (exception dump() and cmdSetOne()) should be const, but they rely + // on IVehicle.get(), which isn't... + void cmdDump(int fd, const hidl_vec& options); + void cmdDumpOneProperty(int fd, int32_t prop, int32_t areaId); + void cmdDumpOneProperty(int fd, int rowNumber, const VehiclePropConfig& config); + + static bool checkArgumentsSize(int fd, const hidl_vec& options, size_t minSize); + static bool checkCallerHasWritePermissions(int fd); + static bool safelyParseInt(int fd, int index, std::string s, int* out); + void cmdHelp(int fd) const; + void cmdListAllProperties(int fd) const; + void cmdDumpAllProperties(int fd); + void cmdDumpSpecificProperties(int fd, const hidl_vec& options); + void cmdSetOneProperty(int fd, const hidl_vec& options); + static bool isSubscribable(const VehiclePropConfig& config, SubscribeFlags flags); static bool isSampleRateFixed(VehiclePropertyChangeMode mode); diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp index 393d3ecc5e..4249a61107 100644 --- a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp +++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp @@ -21,11 +21,18 @@ #include #include -#include +#include +#include #include +#include + +#include #include "VehicleUtils.h" +// TODO: figure out how to include private/android_filesystem_config.h instead... +#define AID_ROOT 0 /* traditional unix root user */ + namespace android { namespace hardware { namespace automotive { @@ -34,6 +41,10 @@ namespace V2_0 { using namespace std::placeholders; +using ::android::base::EqualsIgnoreCase; +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_string; + constexpr std::chrono::milliseconds kHalEventBatchingTimeWindow(10); const VehiclePropValue kEmptyValue{}; @@ -172,6 +183,231 @@ Return VehicleHalManager::debugDump(IVehicle::debugDump_cb _hidl_cb) { return Void(); } +Return VehicleHalManager::debug(const hidl_handle& fd, const hidl_vec& options) { + if (fd.getNativeHandle() != nullptr && fd->numFds > 0) { + cmdDump(fd->data[0], options); + } else { + ALOGE("Invalid parameters passed to debug()"); + } + return Void(); +} + +void VehicleHalManager::cmdDump(int fd, const hidl_vec& options) { + if (options.size() == 0) { + cmdDumpAllProperties(fd); + return; + } + std::string option = options[0]; + if (EqualsIgnoreCase(option, "--help")) { + cmdHelp(fd); + } else if (EqualsIgnoreCase(option, "--list")) { + cmdListAllProperties(fd); + } else if (EqualsIgnoreCase(option, "--get")) { + cmdDumpSpecificProperties(fd, options); + } else if (EqualsIgnoreCase(option, "--set")) { + cmdSetOneProperty(fd, options); + } else { + dprintf(fd, "Invalid option: %s\n", option.c_str()); + } +} + +bool VehicleHalManager::checkCallerHasWritePermissions(int fd) { + // Double check that's only called by root - it should be be blocked at the HIDL debug() level, + // but it doesn't hurt to make sure... + if (hardware::IPCThreadState::self()->getCallingUid() != AID_ROOT) { + dprintf(fd, "Must be root\n"); + return false; + } + return true; +} + +bool VehicleHalManager::checkArgumentsSize(int fd, const hidl_vec& options, + size_t minSize) { + size_t size = options.size(); + if (size >= minSize) { + return true; + } + dprintf(fd, "Invalid number of arguments: required at least %zu, got %zu\n", minSize, size); + return false; +} + +bool VehicleHalManager::safelyParseInt(int fd, int index, std::string s, int* out) { + if (!android::base::ParseInt(s, out)) { + dprintf(fd, "non-integer argument at index %d: %s\n", index, s.c_str()); + return false; + } + return true; +} + +void VehicleHalManager::cmdHelp(int fd) const { + dprintf(fd, "Usage: \n\n"); + dprintf(fd, "[no args]: dumps (id and value) all supported properties \n"); + dprintf(fd, "--help: shows this help\n"); + dprintf(fd, "--list: lists the ids of all supported properties\n"); + dprintf(fd, "--get [PROP2] [PROPN]: dumps the value of specific properties \n"); + // TODO: support other formats (int64, float, bytes) + dprintf(fd, + "--set [ ]: sets the value of property PROP, using" + " arbitrary number of key/value parameters (i for int32, s for string). Notice that " + "the string value can be set just once, while the other can have multiple values " + "(so they're used in the respective array)\n"); +} + +void VehicleHalManager::cmdListAllProperties(int fd) const { + auto& halConfig = mConfigIndex->getAllConfigs(); + size_t size = halConfig.size(); + if (size == 0) { + dprintf(fd, "no properties to list\n"); + return; + } + int i = 0; + dprintf(fd, "listing %zu properties\n", size); + for (const auto& config : halConfig) { + dprintf(fd, "%d: %d\n", ++i, config.prop); + } +} + +void VehicleHalManager::cmdDumpAllProperties(int fd) { + auto& halConfig = mConfigIndex->getAllConfigs(); + size_t size = halConfig.size(); + if (size == 0) { + dprintf(fd, "no properties to dump\n"); + return; + } + int rowNumber = 0; + dprintf(fd, "dumping %zu properties\n", size); + for (auto& config : halConfig) { + cmdDumpOneProperty(fd, ++rowNumber, config); + } +} + +void VehicleHalManager::cmdDumpOneProperty(int fd, int rowNumber, const VehiclePropConfig& config) { + size_t numberAreas = config.areaConfigs.size(); + if (numberAreas == 0) { + if (rowNumber > 0) { + dprintf(fd, "%d: ", rowNumber); + } + cmdDumpOneProperty(fd, config.prop, /* areaId= */ 0); + return; + } + for (size_t j = 0; j < numberAreas; ++j) { + if (rowNumber > 0) { + if (numberAreas > 1) { + dprintf(fd, "%d/%zu: ", rowNumber, j); + } else { + dprintf(fd, "%d: ", rowNumber); + } + } + cmdDumpOneProperty(fd, config.prop, config.areaConfigs[j].areaId); + } +} + +void VehicleHalManager::cmdDumpSpecificProperties(int fd, const hidl_vec& options) { + if (!checkArgumentsSize(fd, options, 2)) return; + + // options[0] is the command itself... + int rowNumber = 0; + size_t size = options.size(); + for (size_t i = 1; i < size; ++i) { + int prop; + if (!safelyParseInt(fd, i, options[i], &prop)) return; + const auto* config = getPropConfigOrNull(prop); + if (config == nullptr) { + dprintf(fd, "No property %d\n", prop); + continue; + } + if (size > 2) { + // Only show row number if there's more than 1 + rowNumber++; + } + cmdDumpOneProperty(fd, rowNumber, *config); + } +} + +void VehicleHalManager::cmdDumpOneProperty(int fd, int32_t prop, int32_t areaId) { + VehiclePropValue input; + input.prop = prop; + input.areaId = areaId; + auto callback = [&](StatusCode status, const VehiclePropValue& output) { + if (status == StatusCode::OK) { + dprintf(fd, "%s\n", toString(output).c_str()); + } else { + dprintf(fd, "Could not get property %d. Error: %s\n", prop, toString(status).c_str()); + } + }; + get(input, callback); +} + +void VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec& options) { + if (!checkCallerHasWritePermissions(fd) || !checkArgumentsSize(fd, options, 3)) return; + + size_t size = options.size(); + + // Syntax is --set PROP Type1 Value1 TypeN ValueN, so number of arguments must be even + if (size % 2 != 0) { + dprintf(fd, "must pass even number of arguments (passed %zu)\n", size); + return; + } + int numberValues = (size - 2) / 2; + + VehiclePropValue prop; + if (!safelyParseInt(fd, 1, options[1], &prop.prop)) return; + prop.timestamp = 0; + prop.areaId = 0; // TODO: add option to pass areaId as parameter + prop.status = VehiclePropertyStatus::AVAILABLE; + + // First pass calculate sizes + int sizeInt32 = 0; + int stringIndex = 0; + for (int i = 2, kv = 1; kv <= numberValues; kv++) { + // iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step + std::string type = options[i]; + std::string value = options[i + 1]; + if (EqualsIgnoreCase(type, "i")) { + sizeInt32++; + } else if (EqualsIgnoreCase(type, "s")) { + if (stringIndex != 0) { + dprintf(fd, + "defining string value (%s) again at index %d (already defined at %d=%s" + ")\n", + value.c_str(), i, stringIndex, options[stringIndex + 1].c_str()); + return; + } + stringIndex = i; + } else { + dprintf(fd, "invalid (%s) type at index %d\n", type.c_str(), i); + return; + } + i += 2; + } + prop.value.int32Values.resize(sizeInt32); + + // Second pass: populate it + int indexInt32 = 0; + for (int i = 2, kv = 1; kv <= numberValues; kv++) { + // iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step + int valueIndex = i + 1; + std::string type = options[i]; + std::string value = options[valueIndex]; + if (EqualsIgnoreCase(type, "i")) { + int safeInt; + if (!safelyParseInt(fd, valueIndex, value, &safeInt)) return; + prop.value.int32Values[indexInt32++] = safeInt; + } else if (EqualsIgnoreCase(type, "s")) { + prop.value.stringValue = value; + } + i += 2; + } + ALOGD("Setting prop %s", toString(prop).c_str()); + auto status = set(prop); + if (status == StatusCode::OK) { + dprintf(fd, "Set property %s\n", toString(prop).c_str()); + } else { + dprintf(fd, "Failed to set property %s: %s\n", toString(prop).c_str(), + toString(status).c_str()); + } +} + void VehicleHalManager::init() { ALOGI("VehicleHalManager::init"); From 6542f01ef2d1bbf28d460815322ba158582beab7 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 5 Feb 2020 15:56:13 -0800 Subject: [PATCH 0548/1022] Fixed typo (vehcile -> vehicle). Test: rgrep -i vehcile . || echo NOT_FOUND Bug: 146207078 Change-Id: I3ab9ffe25b6bf58a4ff18a70e94bf910b5302e72 --- .../2.0/default/impl/vhal_v2_0/DefaultConfig.h | 14 +++++++------- .../impl/vhal_v2_0/EmulatedVehicleConnector.cpp | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) 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 bf85da231c..e19987c31c 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 @@ -87,23 +87,23 @@ const int32_t kGenerateFakeDataControllingProperty = /** * This property is used for test purpose to set properties' value from vehicle. * For example: Mocking hard button press triggering a HVAC fan speed change. - * Android set kSetPropertyFromVehcileForTest with an array of integer {HVAC_FAN_SPEED, value of + * Android set kSetPropertyFromVehicleForTest with an array of integer {HVAC_FAN_SPEED, value of * fan speed} and a long value indicates the timestamp of the events . * It only works with integer type properties. */ -const int32_t kSetIntPropertyFromVehcileForTest = +const int32_t kSetIntPropertyFromVehicleForTest = 0x1112 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED; /** * This property is used for test purpose to set properties' value from vehicle. * It only works with float type properties. */ -const int32_t kSetFloatPropertyFromVehcileForTest = +const int32_t kSetFloatPropertyFromVehicleForTest = 0x1113 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED; /** * This property is used for test purpose to set properties' value from vehicle. * It only works with boolean type properties. */ -const int32_t kSetBooleanPropertyFromVehcileForTest = +const int32_t kSetBooleanPropertyFromVehicleForTest = 0x1114 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED; /** @@ -695,7 +695,7 @@ const ConfigDeclaration kVehicleProperties[]{ { .config = { - .prop = kSetIntPropertyFromVehcileForTest, + .prop = kSetIntPropertyFromVehicleForTest, .access = VehiclePropertyAccess::WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, .configArray = {0, 0, 0, 2, 1, 0, 0, 0, 0}, @@ -705,7 +705,7 @@ const ConfigDeclaration kVehicleProperties[]{ { .config = { - .prop = kSetFloatPropertyFromVehcileForTest, + .prop = kSetFloatPropertyFromVehicleForTest, .access = VehiclePropertyAccess::WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, .configArray = {0, 0, 1, 0, 1, 0, 1, 0, 0}, @@ -715,7 +715,7 @@ const ConfigDeclaration kVehicleProperties[]{ { .config = { - .prop = kSetBooleanPropertyFromVehcileForTest, + .prop = kSetBooleanPropertyFromVehicleForTest, .access = VehiclePropertyAccess::WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, .configArray = {0, 1, 1, 0, 1, 0, 0, 0, 0}, diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp index 222fe5e21f..d9867bd39e 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp @@ -202,8 +202,8 @@ StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, b case kGenerateFakeDataControllingProperty: return handleGenerateFakeDataRequest(value); - // set the value from vehcile side, used in end to end test. - case kSetIntPropertyFromVehcileForTest: { + // set the value from vehicle side, used in end to end test. + case kSetIntPropertyFromVehicleForTest: { auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1); updatedPropValue->prop = value.value.int32Values[0]; updatedPropValue->value.int32Values[0] = value.value.int32Values[1]; @@ -212,7 +212,7 @@ StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, b onPropertyValueFromCar(*updatedPropValue, updateStatus); return StatusCode::OK; } - case kSetFloatPropertyFromVehcileForTest: { + case kSetFloatPropertyFromVehicleForTest: { auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1); updatedPropValue->prop = value.value.int32Values[0]; updatedPropValue->value.floatValues[0] = value.value.floatValues[0]; @@ -221,7 +221,7 @@ StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, b onPropertyValueFromCar(*updatedPropValue, updateStatus); return StatusCode::OK; } - case kSetBooleanPropertyFromVehcileForTest: { + case kSetBooleanPropertyFromVehicleForTest: { auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1); updatedPropValue->prop = value.value.int32Values[1]; updatedPropValue->value.int32Values[0] = value.value.int32Values[0]; From 6e278a379841d2aca907300ee8ed60034eac730e Mon Sep 17 00:00:00 2001 From: Hunter Knepshield Date: Mon, 3 Feb 2020 16:25:57 -0800 Subject: [PATCH 0549/1022] IDumpstateDevice@1.1 polish - Return a DumpstateStatus from dumpstateBoard_1_1 - Better toggle API surface: set/getDeviceLoggingEnabled - Improved testing to allow for unsupported DumpstateMode values Bug: 143183758 Bug: 143184495 Test: atest VtsHalDumpstateV1_1TargetTest Change-Id: I505c2a790dc28ddce9b6f5b674394ef65b31c80c --- current.txt | 4 +- dumpstate/1.1/IDumpstateDevice.hal | 24 ++- dumpstate/1.1/types.hal | 33 ++- .../VtsHalDumpstateV1_1TargetTest.cpp | 200 +++++++++++++++--- 4 files changed, 221 insertions(+), 40 deletions(-) diff --git a/current.txt b/current.txt index 8d068d0e89..c88af5c1d8 100644 --- a/current.txt +++ b/current.txt @@ -645,8 +645,8 @@ f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardwar 4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types 66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory 994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory -881aa8720fb1d69aa9843bfab69d810ab7654a61d2f5ab5e2626cbf240f24eaf android.hardware.dumpstate@1.1::types -13b33f623521ded51a6c0f7ea5b77e97066d0aa1e38a83c2873f08ad67294f89 android.hardware.dumpstate@1.1::IDumpstateDevice +446287268831f4ddfac4a51bb1c32ae1e48e47bccd535fccc2c4546d0e7c4013 android.hardware.dumpstate@1.1::types +f284ffde7cadf5a1364b75ab313baf22401eeca289bdde2a2dc7a27ea4ab98d7 android.hardware.dumpstate@1.1::IDumpstateDevice 769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types 88371e0edf69a1f72bfc45ecb2335e9b145e87339d3eecc92664a1fb200213ba android.hardware.gnss@2.1::IGnss ba62e1e8993bfb9f27fa04816fa0f2241ae2d01edfa3d0c04182e2e5de80045c android.hardware.gnss@2.1::IGnssCallback diff --git a/dumpstate/1.1/IDumpstateDevice.hal b/dumpstate/1.1/IDumpstateDevice.hal index 24831b37b2..502c460998 100644 --- a/dumpstate/1.1/IDumpstateDevice.hal +++ b/dumpstate/1.1/IDumpstateDevice.hal @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package android.hardware.dumpstate@1.1; import @1.0::IDumpstateDevice; @@ -28,14 +29,19 @@ interface IDumpstateDevice extends @1.0::IDumpstateDevice { * The 1.0 version of #dumpstateBoard(handle) should just delegate to this new method and pass * DumpstateMode::DEFAULT and a timeout of 30,000ms (30 seconds). * + * This method may still be called by the dumpstate routine even if getDeviceLoggingEnabled + * returns false. In this case, it must return DumpstateStatus::DEVICE_LOGGING_NOT_ENABLED. + * * @param h A native handle with one or two valid file descriptors. The first FD is for text * output, the second (if present) is for binary output. * @param mode A mode value to restrict dumped content. * @param timeoutMillis An approximate "budget" for how much time this call has been allotted. * If execution runs longer than this, the IDumpstateDevice service may be killed and only * partial information will be included in the report. + * @return status A DumpstateStatus value indicating the final result. */ - dumpstateBoard_1_1(handle h, DumpstateMode mode, uint64_t timeoutMillis); + dumpstateBoard_1_1(handle h, DumpstateMode mode, uint64_t timeoutMillis) + generates (DumpstateStatus status); /** * Turns device vendor logging on or off. @@ -46,8 +52,20 @@ interface IDumpstateDevice extends @1.0::IDumpstateDevice { * memory/storage/battery impacts, calling this method on a user build should only be done after * user consent has been obtained, e.g. from a toggle in developer settings. * + * Even if device logging has been disabled, dumpstateBoard may still be called by the dumpstate + * routine. In this case, it must return DumpstateStatus::DEVICE_LOGGING_NOT_ENABLED. + * * @param enable Whether to enable or disable device vendor logging. - * @return success Whether or not the change took effect. */ - setDeviceLoggingEnabled(bool enable) generates (bool success); + setDeviceLoggingEnabled(bool enable); + + /** + * Queries the current state of device logging. Primarily for UI and informative purposes. + * + * Even if device logging has been disabled, dumpstateBoard may still be called by the dumpstate + * routine. In this case, it must return DumpstateStatus::DEVICE_LOGGING_NOT_ENABLED. + * + * @return enabled Whether or not vendor logging is currently enabled. + */ + getDeviceLoggingEnabled() generates (bool enabled); }; diff --git a/dumpstate/1.1/types.hal b/dumpstate/1.1/types.hal index a6f391aded..f5cbade151 100644 --- a/dumpstate/1.1/types.hal +++ b/dumpstate/1.1/types.hal @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package android.hardware.dumpstate@1.1; /** @@ -23,22 +24,18 @@ enum DumpstateMode : uint32_t { * Takes a bug report without user interference. */ FULL = 0, - /** * Interactive bug report, i.e. triggered by the user. */ INTERACTIVE = 1, - /** * Remote bug report triggered by DevicePolicyManager, for example. */ REMOTE = 2, - /** * Bug report triggered on a wear device. */ WEAR = 3, - /** * Bug report limited to only connectivity info (cellular, wifi, and networking). Sometimes * called "telephony" in legacy contexts. @@ -49,14 +46,34 @@ enum DumpstateMode : uint32_t { * user application traffic. */ CONNECTIVITY = 4, - /** * Bug report limited to only wifi info. */ WIFI = 5, - /** - * Default mode. + * Default mode, essentially analogous to calling @1.0::IDumpstateDevice.dumpstateBoard(handle). + * This mode MUST be supported if the dumpstate HAL is implemented. */ - DEFAULT = 6 + DEFAULT = 6, +}; + +/** + * A simple return enum for use with dumpstateBoard_1_1. + */ +enum DumpstateStatus : uint32_t { + OK = 0, + /** + * Returned for cases where the device doesn't support the given DumpstateMode (e.g. a phone + * trying to use DumpstateMode::WEAR). + */ + UNSUPPORTED_MODE = 1, + /** + * Returned for cases where an IllegalArgumentException is typically appropriate, e.g. missing + * file descriptors. + */ + ILLEGAL_ARGUMENT = 2, + /** + * Returned when device logging is not enabled. + */ + DEVICE_LOGGING_NOT_ENABLED = 3, }; diff --git a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp index 583efbf722..089b039c2c 100644 --- a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp +++ b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -34,21 +35,56 @@ namespace { using ::android::sp; using ::android::hardware::Return; using ::android::hardware::dumpstate::V1_1::DumpstateMode; +using ::android::hardware::dumpstate::V1_1::DumpstateStatus; using ::android::hardware::dumpstate::V1_1::IDumpstateDevice; +using ::android::hardware::dumpstate::V1_1::toString; class DumpstateHidl1_1Test : public ::testing::TestWithParam { - public: - virtual void SetUp() override { + protected: + virtual void SetUp() override { GetService(); } + + void GetService() { dumpstate = IDumpstateDevice::getService(GetParam()); ASSERT_NE(dumpstate, nullptr) << "Could not get HIDL instance"; } + void ToggleDeviceLogging(bool enable) { + Return status = dumpstate->setDeviceLoggingEnabled(enable); + ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description(); + + if (!dumpstate->ping().isOk()) { + ALOGW("IDumpstateDevice service appears to have exited lazily, attempting to get " + "again"); + GetService(); + } + + Return logging_enabled = dumpstate->getDeviceLoggingEnabled(); + ASSERT_TRUE(logging_enabled.isOk()) + << "Status should be ok: " << logging_enabled.description(); + ASSERT_EQ(logging_enabled, enable) + << "Device logging should now be " << (enable ? "enabled" : "disabled"); + + if (!dumpstate->ping().isOk()) { + ALOGW("IDumpstateDevice service appears to have exited lazily, attempting to get " + "again"); + GetService(); + } + } + + void EnableDeviceLogging() { ToggleDeviceLogging(true); } + + void DisableDeviceLogging() { ToggleDeviceLogging(false); } + sp dumpstate; }; #define TEST_FOR_DUMPSTATE_MODE(name, body, mode) \ TEST_P(DumpstateHidl1_1Test, name##_##mode) { body(DumpstateMode::mode); } +// We use a macro to define individual test cases instead of hidl_enum_range<> because some HAL +// implementations are lazy and may call exit() at the end of dumpstateBoard(), which would cause +// DEAD_OBJECT errors after the first iteration. Separate cases re-get the service each time as part +// of SetUp(), and also provide better separation of concerns when specific modes are problematic. #define TEST_FOR_ALL_DUMPSTATE_MODES(name, body) \ TEST_FOR_DUMPSTATE_MODE(name, body, FULL); \ TEST_FOR_DUMPSTATE_MODE(name, body, INTERACTIVE); \ @@ -60,21 +96,51 @@ class DumpstateHidl1_1Test : public ::testing::TestWithParam { constexpr uint64_t kDefaultTimeoutMillis = 30 * 1000; // 30 seconds +// Will only execute additional_assertions when status == expected. +void AssertStatusForMode(const DumpstateMode mode, const Return& status, + const DumpstateStatus expected, + std::function additional_assertions = nullptr) { + ASSERT_TRUE(status.isOk()) << "Status should be ok and return a more specific DumpstateStatus: " + << status.description(); + if (mode == DumpstateMode::DEFAULT) { + ASSERT_EQ(expected, status) << "Required mode (DumpstateMode::" << toString(mode) + << "): status should be DumpstateStatus::" << toString(expected) + << ", but got DumpstateStatus::" << toString(status); + } else { + // The rest of the modes are optional to support, but they MUST return either the expected + // value or UNSUPPORTED_MODE. + ASSERT_TRUE(status == expected || status == DumpstateStatus::UNSUPPORTED_MODE) + << "Optional mode (DumpstateMode::" << toString(mode) + << "): status should be DumpstateStatus::" << toString(expected) + << " or DumpstateStatus::UNSUPPORTED_MODE, but got DumpstateStatus::" + << toString(status); + } + if (status == expected && additional_assertions != nullptr) { + additional_assertions(); + } +} + // Negative test: make sure dumpstateBoard() doesn't crash when passed a null pointer. TEST_FOR_ALL_DUMPSTATE_MODES(TestNullHandle, [this](DumpstateMode mode) { - Return status = dumpstate->dumpstateBoard_1_1(nullptr, mode, kDefaultTimeoutMillis); + EnableDeviceLogging(); - ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description(); + Return status = + dumpstate->dumpstateBoard_1_1(nullptr, mode, kDefaultTimeoutMillis); + + AssertStatusForMode(mode, status, DumpstateStatus::ILLEGAL_ARGUMENT); }); // Negative test: make sure dumpstateBoard() ignores a handle with no FD. TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithNoFd, [this](DumpstateMode mode) { + EnableDeviceLogging(); + native_handle_t* handle = native_handle_create(0, 0); ASSERT_NE(handle, nullptr) << "Could not create native_handle"; - Return status = dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis); + Return status = + dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis); - ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description(); + AssertStatusForMode(mode, status, DumpstateStatus::ILLEGAL_ARGUMENT); native_handle_close(handle); native_handle_delete(handle); @@ -82,6 +148,8 @@ TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithNoFd, [this](DumpstateMode mode) { // Positive test: make sure dumpstateBoard() writes something to the FD. TEST_FOR_ALL_DUMPSTATE_MODES(TestOk, [this](DumpstateMode mode) { + EnableDeviceLogging(); + // Index 0 corresponds to the read end of the pipe; 1 to the write end. int fds[2]; ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno; @@ -90,12 +158,14 @@ TEST_FOR_ALL_DUMPSTATE_MODES(TestOk, [this](DumpstateMode mode) { ASSERT_NE(handle, nullptr) << "Could not create native_handle"; handle->data[0] = fds[1]; - Return status = dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis); - ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description(); + Return status = + dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis); - // Check that at least one byte was written - char buff; - ASSERT_EQ(1, read(fds[0], &buff, 1)) << "dumped nothing"; + AssertStatusForMode(mode, status, DumpstateStatus::OK, [&fds]() { + // Check that at least one byte was written. + char buff; + ASSERT_EQ(1, read(fds[0], &buff, 1)) << "Dumped nothing"; + }); native_handle_close(handle); native_handle_delete(handle); @@ -103,6 +173,8 @@ TEST_FOR_ALL_DUMPSTATE_MODES(TestOk, [this](DumpstateMode mode) { // Positive test: make sure dumpstateBoard() doesn't crash with two FDs. TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithTwoFds, [this](DumpstateMode mode) { + EnableDeviceLogging(); + int fds1[2]; int fds2[2]; ASSERT_EQ(0, pipe2(fds1, O_NONBLOCK)) << errno; @@ -113,8 +185,17 @@ TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithTwoFds, [this](DumpstateMode mode) { handle->data[0] = fds1[1]; handle->data[1] = fds2[1]; - Return status = dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis); - ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description(); + Return status = + dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis); + + AssertStatusForMode(mode, status, DumpstateStatus::OK, [&fds1, &fds2]() { + // Check that at least one byte was written to one of the FDs. + char buff; + size_t read1 = read(fds1[0], &buff, 1); + size_t read2 = read(fds2[0], &buff, 1); + // Sometimes read returns -1, so we can't just add them together and expect >= 1. + ASSERT_TRUE(read1 == 1 || read2 == 1) << "Dumped nothing"; + }); native_handle_close(handle); native_handle_delete(handle); @@ -122,6 +203,8 @@ TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithTwoFds, [this](DumpstateMode mode) { // Make sure dumpstateBoard_1_1 actually validates its arguments. TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Negative) { + EnableDeviceLogging(); + int fds[2]; ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno; @@ -129,16 +212,21 @@ TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Negative) { ASSERT_NE(handle, nullptr) << "Could not create native_handle"; handle->data[0] = fds[1]; - Return status = dumpstate->dumpstateBoard_1_1(handle, static_cast(-100), - kDefaultTimeoutMillis); - ASSERT_FALSE(status.isOk()) << "Status should not be ok with invalid mode param: " - << status.description(); + Return status = dumpstate->dumpstateBoard_1_1( + handle, static_cast(-100), kDefaultTimeoutMillis); + + ASSERT_TRUE(status.isOk()) << "Status should be ok and return a more specific DumpstateStatus: " + << status.description(); + ASSERT_EQ(status, DumpstateStatus::ILLEGAL_ARGUMENT) + << "Should return DumpstateStatus::ILLEGAL_ARGUMENT for invalid mode param"; native_handle_close(handle); native_handle_delete(handle); } TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Undefined) { + EnableDeviceLogging(); + int fds[2]; ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno; @@ -146,26 +234,84 @@ TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Undefined) { ASSERT_NE(handle, nullptr) << "Could not create native_handle"; handle->data[0] = fds[1]; - Return status = dumpstate->dumpstateBoard_1_1(handle, static_cast(9001), - kDefaultTimeoutMillis); - ASSERT_FALSE(status.isOk()) << "Status should not be ok with invalid mode param: " - << status.description(); + Return status = dumpstate->dumpstateBoard_1_1( + handle, static_cast(9001), kDefaultTimeoutMillis); + + ASSERT_TRUE(status.isOk()) << "Status should be ok and return a more specific DumpstateStatus: " + << status.description(); + ASSERT_EQ(status, DumpstateStatus::ILLEGAL_ARGUMENT) + << "Should return DumpstateStatus::ILLEGAL_ARGUMENT for invalid mode param"; native_handle_close(handle); native_handle_delete(handle); } -// Make sure toggling device logging doesn't crash. -TEST_P(DumpstateHidl1_1Test, TestEnableDeviceLogging) { - Return status = dumpstate->setDeviceLoggingEnabled(true); +// Positive test: make sure dumpstateBoard() from 1.0 doesn't fail. +TEST_P(DumpstateHidl1_1Test, Test1_0MethodOk) { + EnableDeviceLogging(); + + int fds[2]; + ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno; + + native_handle_t* handle = native_handle_create(1, 0); + ASSERT_NE(handle, nullptr) << "Could not create native_handle"; + handle->data[0] = fds[1]; + + Return status = dumpstate->dumpstateBoard(handle); ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description(); + + // Check that at least one byte was written. + char buff; + ASSERT_EQ(1, read(fds[0], &buff, 1)) << "Dumped nothing"; + + native_handle_close(handle); + native_handle_delete(handle); } -TEST_P(DumpstateHidl1_1Test, TestDisableDeviceLogging) { - Return status = dumpstate->setDeviceLoggingEnabled(false); +// Make sure disabling device logging behaves correctly. +TEST_FOR_ALL_DUMPSTATE_MODES(TestDeviceLoggingDisabled, [this](DumpstateMode mode) { + DisableDeviceLogging(); - ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description(); + // Index 0 corresponds to the read end of the pipe; 1 to the write end. + int fds[2]; + ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno; + + native_handle_t* handle = native_handle_create(1, 0); + ASSERT_NE(handle, nullptr) << "Could not create native_handle"; + handle->data[0] = fds[1]; + + Return status = + dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis); + + AssertStatusForMode(mode, status, DumpstateStatus::DEVICE_LOGGING_NOT_ENABLED, [&fds]() { + // Check that nothing was written. Could return 0 or -1. + char buff; + ASSERT_NE(1, read(fds[0], &buff, 1)) << "Dumped something when device logging is disabled"; + }); + + native_handle_close(handle); + native_handle_delete(handle); +}); + +// Double-enable is perfectly valid, but the second call shouldn't do anything. +TEST_P(DumpstateHidl1_1Test, TestRepeatedEnable) { + EnableDeviceLogging(); + EnableDeviceLogging(); +} + +// Double-disable is perfectly valid, but the second call shouldn't do anything. +TEST_P(DumpstateHidl1_1Test, TestRepeatedDisable) { + DisableDeviceLogging(); + DisableDeviceLogging(); +} + +// Toggling in short order is perfectly valid. +TEST_P(DumpstateHidl1_1Test, TestRepeatedToggle) { + EnableDeviceLogging(); + DisableDeviceLogging(); + EnableDeviceLogging(); + DisableDeviceLogging(); } INSTANTIATE_TEST_SUITE_P( From 2729d825cb208f7870df221239d871ba413d36d4 Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Wed, 5 Feb 2020 16:26:37 -0800 Subject: [PATCH 0550/1022] Add a VTS test to validate NNAPI driver name string. Bug: 134755158 Test: VtsHalNeuralnetworksV1_2TargetTest Change-Id: Iead93f0a251fdbbf94df6dfdf27919d3f6fd71a8 --- neuralnetworks/1.2/vts/functional/BasicTests.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/neuralnetworks/1.2/vts/functional/BasicTests.cpp b/neuralnetworks/1.2/vts/functional/BasicTests.cpp index 8e82c5376e..58d3c4a403 100644 --- a/neuralnetworks/1.2/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.2/vts/functional/BasicTests.cpp @@ -79,6 +79,18 @@ TEST_P(NeuralnetworksHidlTest, GetDeviceTypeTest) { EXPECT_TRUE(ret.isOk()); } +// device name test +TEST_P(NeuralnetworksHidlTest, GetDeviceNameTest) { + const std::string deviceName = getName(GetParam()); + auto pos = deviceName.find('-'); + EXPECT_NE(pos, std::string::npos); + // The separator should not be the first or last character. + EXPECT_NE(pos, 0); + EXPECT_NE(pos, deviceName.length() - 1); + // There should only be 1 separator. + EXPECT_EQ(std::string::npos, deviceName.find('-', pos + 1)); +} + // device supported extensions test TEST_P(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) { Return ret = kDevice->getSupportedExtensions( From 5a53659077ee29b5a5c338bd3c209081f25b6369 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Thu, 6 Feb 2020 08:47:11 -0800 Subject: [PATCH 0551/1022] Add a metadata field to BufferDesc This change adds a variable-length metadata field to BufferDesc. This new data is owned by EVS Camera HAL implementations and opaque to EVS manager. Change-Id: If9b25093afa55ea0782af776a3f67923664e0058 Fix: 142891952 Bug: 142888671 Test: Build successful Signed-off-by: Changyeon Jo --- automotive/evs/1.1/types.hal | 2 ++ 1 file changed, 2 insertions(+) diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal index f88d2232b7..aafdb70db3 100644 --- a/automotive/evs/1.1/types.hal +++ b/automotive/evs/1.1/types.hal @@ -69,6 +69,8 @@ struct BufferDesc { * Time that this buffer is being filled. */ int64_t timestamp; + + vec metadata; }; /** From 875cd25c07775f2e032dcd86bf3ba5e8216251ce Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Thu, 6 Feb 2020 15:29:16 -0800 Subject: [PATCH 0552/1022] Remove vberCn, lberCn, xerCn These values are specific to phase modulation in ISDB-S. It's not general use case. bug: 148110220 Test: Manual Change-Id: If847ca6c31681b1fe9dd94512c41b194dba41127 --- tv/tuner/1.0/types.hal | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index 2eaab36778..e4874f4e69 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -1424,18 +1424,6 @@ enum FrontendStatusType : uint32_t { * Error status by layer. */ LAYER_ERROR, - /** - * CN value by VBER. - */ - VBER_CN, - /** - * CN value by LBER. - */ - LBER_CN, - /** - * CN value by XER. - */ - XER_CN, /** * Moduration Error Ratio. */ @@ -1558,21 +1546,6 @@ safe_union FrontendStatus { vec isLayerError; - /** - * CN value by VBER measured by 0.001 dB - */ - int32_t vberCn; - - /** - * CN value by LBER measured by 0.001 dB - */ - int32_t lberCn; - - /** - * CN value by XER measured by 0.001 dB - */ - int32_t xerCn; - /** * MER value measured by 0.001 dB */ From 15a25f6ec1bb6a59b8620763f84cc91b66e2228d Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Thu, 6 Feb 2020 15:36:41 -0800 Subject: [PATCH 0553/1022] Update VTS tests for executeFenced - Remove the DEVICE_UNAVAILABLE check - Pass deadline down to the driver. Bug: 148979873 Test: mm Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: If90a0dce8c8907a2f8f806455074fa27e3f397ef --- .../1.3/vts/functional/ValidateRequest.cpp | 18 ++++++++---------- .../vts/functional/VtsHalNeuralnetworks.cpp | 5 +---- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index 2fd9b647f1..a29d158e7d 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -142,16 +142,14 @@ static void validate(const sp& preparedModel, const std::string& // dispatch { SCOPED_TRACE(message + " [executeFenced]"); - Return ret = preparedModel->executeFenced( - request, {}, MeasureTiming::NO, {}, {}, - [](ErrorStatus error, const hidl_handle& handle, - const sp& callback) { - if (error != ErrorStatus::DEVICE_UNAVAILABLE) { - ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); - } - ASSERT_EQ(handle.getNativeHandle(), nullptr); - ASSERT_EQ(callback, nullptr); - }); + Return ret = + preparedModel->executeFenced(request, {}, MeasureTiming::NO, deadline, {}, + [](ErrorStatus error, const hidl_handle& handle, + const sp& callback) { + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); + ASSERT_EQ(handle.getNativeHandle(), nullptr); + ASSERT_EQ(callback, nullptr); + }); ASSERT_TRUE(ret.isOk()); } } diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index 896ace65b9..9a87569b46 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -140,10 +140,7 @@ void validateExecuteFenced(const sp& preparedModel, const Reques request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO, {}, {}, [](ErrorStatus error, const hidl_handle& handle, const sp& callback) { - // TODO: fix this once sample driver impl is merged. - if (error != ErrorStatus::DEVICE_UNAVAILABLE) { - ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); - } + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); ASSERT_EQ(handle.getNativeHandle(), nullptr); ASSERT_EQ(callback, nullptr); }); From 6894f89fd88dab3b56531c06e8f5d2ae0316f47f Mon Sep 17 00:00:00 2001 From: Rambo Wang Date: Wed, 5 Feb 2020 21:31:53 -0800 Subject: [PATCH 0554/1022] Add CellIdentity to getBarringInfoResponse Add CellIdentity to getBarringInfoResponse to make the req/resp method match the existing indication. The CellIdentity is used to prevent races where barring is attributed to the wrong cell based on the timing of separate polled or unsolicited inputs to the framework. Because the CellIdentity is already in IRadioIndication the information to provide CID with BarringInfo is already present and available. This just makes the unsol and the polled APIs match. Matching indication is IRadioIndication@1.5::barringInfoChanged Bug: 148992393 Test: make && VtsHalRadioV1_5TargetTest Change-Id: I74e6ab9ca9e0dd49846af774fd73773ff3737df7 --- current.txt | 2 +- radio/1.5/IRadioResponse.hal | 5 ++++- radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h | 1 + radio/1.5/vts/functional/radio_response.cpp | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/current.txt b/current.txt index 9765f81f42..2faeab2aaf 100644 --- a/current.txt +++ b/current.txt @@ -685,7 +685,7 @@ def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardwar e1d34b83188a8ef3c507ec53c0ebcf714863c746da7f4a05460453f7c4c09389 android.hardware.radio@1.5::types 8062d0a1a03594dd8b448adcf6f08856b5720f7e33f9b785a21d3ef74a4f211d android.hardware.radio@1.5::IRadio e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication -7f2439b48bda2961c6d629d0415eee66d519142cf9537f05e9d285153c70ca85 android.hardware.radio@1.5::IRadioResponse +c8a8e4c3998ebdf1c71ece2d3ecb033ae17798830bed4b30a53e5991aa219e3a android.hardware.radio@1.5::IRadioResponse dcc8872337f0135e81970e1d8d5fd7139160dc80e9be76f0ae05290fa7e472b8 android.hardware.radio.config@1.3::types a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal index aa8b526ffa..543f9b59b2 100644 --- a/radio/1.5/IRadioResponse.hal +++ b/radio/1.5/IRadioResponse.hal @@ -20,6 +20,7 @@ import @1.0::RadioResponseInfo; import @1.0::SendSmsResult; import @1.4::IRadioResponse; import @1.5::BarringInfo; +import @1.5::CellIdentity; import @1.5::CellInfo; import @1.5::PersoSubstate; import @1.5::RegStateResult; @@ -165,6 +166,7 @@ interface IRadioResponse extends @1.4::IRadioResponse { /** * @param info Response info struct containing response type, serial no. and error + * @param cellIdentity CellIdentity for the barring infos. * @param barringInfos a vector of barring info for all barring service types * * Valid errors returned: @@ -173,7 +175,8 @@ interface IRadioResponse extends @1.4::IRadioResponse { * RadioError:INTERNAL_ERR * RadioError:MODEM_ERR */ - oneway getBarringInfoResponse(RadioResponseInfo info, vec barringInfos); + oneway getBarringInfoResponse(RadioResponseInfo info, CellIdentity cellIdentity, + vec barringInfos); /** * @param info Response info struct containing response type, serial no. and error diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index ce7b1ab8e7..6f65cbbdf2 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -556,6 +556,7 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon Return getBarringInfoResponse( const RadioResponseInfo& info, + const ::android::hardware::radio::V1_5::CellIdentity& cellIdentity, const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo>& barringInfos); diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp index 26401eb800..17b294bbcd 100644 --- a/radio/1.5/vts/functional/radio_response.cpp +++ b/radio/1.5/vts/functional/radio_response.cpp @@ -963,6 +963,7 @@ Return RadioResponse_v1_5::setIndicationFilterResponse_1_5(const RadioResp Return RadioResponse_v1_5::getBarringInfoResponse( const RadioResponseInfo& info, + const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/, const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo>& /*barringInfos*/) { rspInfo = info; From 72083ba9cdafa955d66d0c67b9f536e956c56ac1 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Wed, 5 Feb 2020 19:07:12 -0800 Subject: [PATCH 0555/1022] Add a VTS test for BarringInfo Add a VTS that verifies polled BarringInfo is sanely constructed. Bug: 148646258 Test: make VtsHalRadioV1_5TargetTest Change-Id: Idf8d110efe8fa2289fbcc8ed7f0959f0bd51999e --- .../1.5/vts/functional/radio_hidl_hal_api.cpp | 107 ++++++++++++++++++ .../functional/radio_hidl_hal_utils_v1_5.h | 4 + radio/1.5/vts/functional/radio_response.cpp | 6 +- 3 files changed, 115 insertions(+), 2 deletions(-) diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp index 621825fa52..55a0a3228f 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp @@ -1069,3 +1069,110 @@ TEST_F(RadioHidlTest_v1_5, sendCdmaSmsExpectMore) { CHECK_GENERAL_ERROR)); } } + +/* + * Test IRadio.getBarringInfo() for the response returned. + */ +TEST_F(RadioHidlTest_v1_5, getBarringInfo) { + serial = GetRandomSerialNumber(); + + Return res = radio_v1_5->getBarringInfo(serial); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + ASSERT_TRUE(radioRsp_v1_5->barringInfos.size() > 0); + + std::set reportedServices; + + // validate that the service types are in range + for (const auto& info : radioRsp_v1_5->barringInfos) { + ASSERT_TRUE((info.serviceType >= BarringInfo::ServiceType::CS_SERVICE && + info.serviceType <= BarringInfo::ServiceType::SMS) || + (info.serviceType >= BarringInfo::ServiceType::OPERATOR_1 && + info.serviceType <= BarringInfo::ServiceType::OPERATOR_32)); + reportedServices.insert(info.serviceType); + + // Any type that is "conditional" must have sane values for conditional barring + // factor and time. + switch (info.barringType) { + case BarringInfo::BarringType::NONE: // fall through + case BarringInfo::BarringType::UNCONDITIONAL: + break; + case BarringInfo::BarringType::CONDITIONAL: { + const int32_t barringFactor = info.barringTypeSpecificInfo.conditional().factor; + ASSERT_TRUE(barringFactor >= 0 && barringFactor <= 100); + ASSERT_TRUE(info.barringTypeSpecificInfo.conditional().timeSeconds > 0); + break; + } + default: + FAIL(); + } + } + + // Certain types of barring are relevant for certain RANs. Ensure that only the right + // types are reported. Note that no types are required, simply that for a given technology + // only certain types are valid. This is one way to sanity check that implementations are + // not providing information that they don't have. + static const std::set UTRA_SERVICES{ + BarringInfo::ServiceType::CS_SERVICE, BarringInfo::ServiceType::PS_SERVICE, + BarringInfo::ServiceType::CS_VOICE, BarringInfo::ServiceType::EMERGENCY, + BarringInfo::ServiceType::SMS, + }; + + static const std::set EUTRA_SERVICES{ + BarringInfo::ServiceType::MO_SIGNALLING, BarringInfo::ServiceType::MO_DATA, + BarringInfo::ServiceType::CS_FALLBACK, BarringInfo::ServiceType::MMTEL_VOICE, + BarringInfo::ServiceType::MMTEL_VIDEO, BarringInfo::ServiceType::EMERGENCY, + BarringInfo::ServiceType::SMS, + }; + + static const std::set NGRA_SERVICES = { + BarringInfo::ServiceType::MO_SIGNALLING, BarringInfo::ServiceType::MO_DATA, + BarringInfo::ServiceType::CS_FALLBACK, BarringInfo::ServiceType::MMTEL_VOICE, + BarringInfo::ServiceType::MMTEL_VIDEO, BarringInfo::ServiceType::EMERGENCY, + BarringInfo::ServiceType::SMS, BarringInfo::ServiceType::OPERATOR_1, + BarringInfo::ServiceType::OPERATOR_2, BarringInfo::ServiceType::OPERATOR_3, + BarringInfo::ServiceType::OPERATOR_4, BarringInfo::ServiceType::OPERATOR_5, + BarringInfo::ServiceType::OPERATOR_6, BarringInfo::ServiceType::OPERATOR_7, + BarringInfo::ServiceType::OPERATOR_8, BarringInfo::ServiceType::OPERATOR_9, + BarringInfo::ServiceType::OPERATOR_10, BarringInfo::ServiceType::OPERATOR_11, + BarringInfo::ServiceType::OPERATOR_12, BarringInfo::ServiceType::OPERATOR_13, + BarringInfo::ServiceType::OPERATOR_14, BarringInfo::ServiceType::OPERATOR_15, + BarringInfo::ServiceType::OPERATOR_16, BarringInfo::ServiceType::OPERATOR_17, + BarringInfo::ServiceType::OPERATOR_18, BarringInfo::ServiceType::OPERATOR_19, + BarringInfo::ServiceType::OPERATOR_20, BarringInfo::ServiceType::OPERATOR_21, + BarringInfo::ServiceType::OPERATOR_22, BarringInfo::ServiceType::OPERATOR_23, + BarringInfo::ServiceType::OPERATOR_24, BarringInfo::ServiceType::OPERATOR_25, + BarringInfo::ServiceType::OPERATOR_26, BarringInfo::ServiceType::OPERATOR_27, + BarringInfo::ServiceType::OPERATOR_28, BarringInfo::ServiceType::OPERATOR_29, + BarringInfo::ServiceType::OPERATOR_30, BarringInfo::ServiceType::OPERATOR_31, + }; + + const std::set* compareTo = nullptr; + + switch (radioRsp_v1_5->barringCellIdentity.getDiscriminator()) { + case android::hardware::radio::V1_5::CellIdentity::hidl_discriminator::wcdma: + // fall through + case android::hardware::radio::V1_5::CellIdentity::hidl_discriminator::tdscdma: + compareTo = &UTRA_SERVICES; + break; + case android::hardware::radio::V1_5::CellIdentity::hidl_discriminator::lte: + compareTo = &EUTRA_SERVICES; + break; + case android::hardware::radio::V1_5::CellIdentity::hidl_discriminator::nr: + compareTo = &NGRA_SERVICES; + break; + + case android::hardware::radio::V1_5::CellIdentity::hidl_discriminator::cdma: + // fall through + default: + FAIL(); + break; + } + + std::set diff; + + std::set_difference(reportedServices.begin(), reportedServices.end(), compareTo->begin(), + compareTo->end(), std::inserter(diff, diff.begin())); +} diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index 6f65cbbdf2..caca7774bc 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -86,6 +86,10 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon // Whether Uicc applications are enabled or not. bool areUiccApplicationsEnabled; + // Barring Info Response + ::android::hardware::radio::V1_5::CellIdentity barringCellIdentity; + ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo> barringInfos; + RadioResponse_v1_5(RadioHidlTest_v1_5& parent_v1_5); virtual ~RadioResponse_v1_5() = default; diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp index 17b294bbcd..7ad51caf04 100644 --- a/radio/1.5/vts/functional/radio_response.cpp +++ b/radio/1.5/vts/functional/radio_response.cpp @@ -963,9 +963,11 @@ Return RadioResponse_v1_5::setIndicationFilterResponse_1_5(const RadioResp Return RadioResponse_v1_5::getBarringInfoResponse( const RadioResponseInfo& info, - const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/, + const ::android::hardware::radio::V1_5::CellIdentity& cellIdentity, const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo>& - /*barringInfos*/) { + barringInfos) { + this->barringCellIdentity = cellIdentity; + this->barringInfos = barringInfos; rspInfo = info; parent_v1_5.notify(info.serial); return Void(); From 019164c4b9100ae6a5691248357e315523c25533 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Fri, 7 Feb 2020 09:59:50 +0800 Subject: [PATCH 0556/1022] wifi: fix uninitialized variable Bug: 149042449 Test: atest VtsHalWifiSupplicantV1_3TargetTest Change-Id: Ie583d1db3697891c96c9186526ae47f40751b822 --- .../1.3/vts/functional/supplicant_sta_network_hidl_test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp index 93eabd6d0b..6be24bc0cc 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp @@ -56,6 +56,8 @@ class SupplicantStaNetworkHidlTest supplicant_ = getSupplicant_1_3(supplicant_v1_3_instance_name_, isP2pOn_); EXPECT_TRUE(turnOnExcessiveLogging(supplicant_)); + sta_iface_ = getSupplicantStaIface_1_3(supplicant_); + ASSERT_NE(nullptr, sta_iface_.get()); sta_network_ = createSupplicantStaNetwork_1_3(supplicant_); ASSERT_NE(sta_network_.get(), nullptr); } From 003fe685c2a520cb992fef0fcb2fb8f43f96750d Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 5 Feb 2020 15:56:13 -0800 Subject: [PATCH 0557/1022] Implemented INITIAL_USER_INFO. This property is called by Android when it starts, and it's expecting a property change indicating what the initial user should be. During normal circumstances, the emulator will reply right away, passing a response if InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which user to boot). But during development / testing, the behavior can be changed using lshal dump, so the following scenarios can be tested: - property timeout - HAL response using a different request id - user switch - user creation Bug: 146207078 Test: manual tests with lshal and a modified CarServiceHelper Test: atest android.hardware.automotive.vehicle@2.0-manager-unit-tests \ android.hardware.automotive.vehicle@2.0-default-impl-unit-tests Change-Id: Ia5be62c8b19a168c0c6da5307169fc14bf3069c9 --- .../default/common/src/VehicleHalManager.cpp | 28 ++++-- .../default/impl/vhal_v2_0/DefaultConfig.h | 11 +++ .../vhal_v2_0/EmulatedVehicleConnector.cpp | 96 +++++++++++++++++++ .../impl/vhal_v2_0/EmulatedVehicleConnector.h | 4 + 4 files changed, 132 insertions(+), 7 deletions(-) diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp index 4249a61107..4f42e630f7 100644 --- a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp +++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp @@ -28,6 +28,8 @@ #include +#include + #include "VehicleUtils.h" // TODO: figure out how to include private/android_filesystem_config.h instead... @@ -247,10 +249,11 @@ void VehicleHalManager::cmdHelp(int fd) const { dprintf(fd, "--get [PROP2] [PROPN]: dumps the value of specific properties \n"); // TODO: support other formats (int64, float, bytes) dprintf(fd, - "--set [ ]: sets the value of property PROP, using" - " arbitrary number of key/value parameters (i for int32, s for string). Notice that " - "the string value can be set just once, while the other can have multiple values " - "(so they're used in the respective array)\n"); + "--set [ ] [a AREA_ID] : sets the value of " + "property PROP, using arbitrary number of key/value parameters (i for int32, " + "s for string) and an optional area.\n" + "Notice that the string value can be set just once, while the other can have multiple " + "values (so they're used in the respective array)\n"); } void VehicleHalManager::cmdListAllProperties(int fd) const { @@ -352,13 +355,13 @@ void VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec& o VehiclePropValue prop; if (!safelyParseInt(fd, 1, options[1], &prop.prop)) return; - prop.timestamp = 0; - prop.areaId = 0; // TODO: add option to pass areaId as parameter + prop.timestamp = elapsedRealtimeNano(); prop.status = VehiclePropertyStatus::AVAILABLE; - // First pass calculate sizes + // First pass: calculate sizes int sizeInt32 = 0; int stringIndex = 0; + int areaIndex = 0; for (int i = 2, kv = 1; kv <= numberValues; kv++) { // iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step std::string type = options[i]; @@ -374,6 +377,15 @@ void VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec& o return; } stringIndex = i; + } else if (EqualsIgnoreCase(type, "a")) { + if (areaIndex != 0) { + dprintf(fd, + "defining area value (%s) again at index %d (already defined at %d=%s" + ")\n", + value.c_str(), i, areaIndex, options[areaIndex + 1].c_str()); + return; + } + areaIndex = i; } else { dprintf(fd, "invalid (%s) type at index %d\n", type.c_str(), i); return; @@ -395,6 +407,8 @@ void VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec& o prop.value.int32Values[indexInt32++] = safeInt; } else if (EqualsIgnoreCase(type, "s")) { prop.value.stringValue = value; + } else if (EqualsIgnoreCase(type, "a")) { + if (!safelyParseInt(fd, valueIndex, value, &prop.areaId)) return; } i += 2; } 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 e19987c31c..785f0e0724 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 @@ -76,6 +76,7 @@ constexpr int WHEEL_FRONT_LEFT = (int)VehicleAreaWheel::LEFT_FRONT; constexpr int WHEEL_FRONT_RIGHT = (int)VehicleAreaWheel::RIGHT_FRONT; constexpr int WHEEL_REAR_LEFT = (int)VehicleAreaWheel::LEFT_REAR; constexpr int WHEEL_REAR_RIGHT = (int)VehicleAreaWheel::RIGHT_REAR; +constexpr int INITIAL_USER_INFO = (int)VehicleProperty::INITIAL_USER_INFO; /** * This property is used for test purpose to generate fake events. Here is the test package that @@ -990,6 +991,16 @@ const ConfigDeclaration kVehicleProperties[]{ (int)VehicleVendorPermission::PERMISSION_DEFAULT}, }, .initialValue = {.int32Values = {1}}}, + + { + .config = + { + .prop = toInt(VehicleProperty::INITIAL_USER_INFO), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + }, + }; } // impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp index d9867bd39e..197c6dbedb 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp @@ -13,6 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +#define LOG_TAG "automotive.vehicle@2.0-connector" + #include #include @@ -261,6 +264,8 @@ StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, b break; } break; + case INITIAL_USER_INFO: + return onSetInitialUserInfo(value, updateStatus); default: break; } @@ -274,6 +279,97 @@ StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, b return StatusCode::OK; } +/** + * INITIAL_USER_INFO is called by Android when it starts, and it's expecting a property change + * indicating what the initial user should be. + * + * During normal circumstances, the emulator will reply right away, passing a response if + * InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which user + * to boot). + * + * But during development / testing, the behavior can be changed using lshal dump, which must use + * the areaId to indicate what should happen next. + * + * So, the behavior of set(INITIAL_USER_INFO) is: + * + * - if it has an areaId, store the property into mInitialUserResponseFromCmd (as it was called by + * lshal). + * - else if mInitialUserResponseFromCmd is not set, return a response with the same request id and + * InitialUserInfoResponseAction::DEFAULT + * - else the behavior is defined by the areaId on mInitialUserResponseFromCmd: + * - if it's 1, reply with mInitialUserResponseFromCmd and the right request id + * - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can test + * this error scenario) + * - if it's 3, then don't send a property change (so Android can emulate a timeout) + * + */ +StatusCode EmulatedVehicleServer::onSetInitialUserInfo(const VehiclePropValue& value, + bool updateStatus) { + // TODO: LOG calls below might be more suited to be DEBUG, but those are not being logged + // (even when explicitly calling setprop log.tag. As this class should be using ALOG instead of + // LOG, it's not worth investigating why... + + if (value.areaId != 0) { + LOG(INFO) << "set(INITIAL_USER_INFO) called from lshal; storing it: " << toString(value); + mInitialUserResponseFromCmd.reset(new VehiclePropValue(value)); + return StatusCode::OK; + } + LOG(INFO) << "set(INITIAL_USER_INFO) called from Android: " << toString(value); + + if (value.value.int32Values.size() == 0) { + LOG(ERROR) << "invalid request (no requestId): " << toString(value); + return StatusCode::INVALID_ARG; + } + int32_t requestId = value.value.int32Values[0]; + + // Create the update property and set common values + auto updatedValue = createVehiclePropValue(VehiclePropertyType::MIXED, 0); + updatedValue->prop = INITIAL_USER_INFO; + updatedValue->timestamp = elapsedRealtimeNano(); + + if (mInitialUserResponseFromCmd == nullptr) { + updatedValue->value.int32Values.resize(2); + updatedValue->value.int32Values[0] = requestId; + updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT; + LOG(INFO) << "no lshal response; returning InitialUserInfoResponseAction::DEFAULT: " + << toString(*updatedValue); + onPropertyValueFromCar(*updatedValue, updateStatus); + return StatusCode::OK; + } + + // mInitialUserResponseFromCmd is used for just one request + std::unique_ptr response = std::move(mInitialUserResponseFromCmd); + + // TODO(b/138709788): rather than populate the raw values directly, it should use the + // libraries that convert a InitialUserInfoResponse into a VehiclePropValue) + + switch (response->areaId) { + case 1: + LOG(INFO) << "returning response with right request id"; + *updatedValue = *response; + updatedValue->areaId = 0; + updatedValue->value.int32Values[0] = requestId; + break; + case 2: + LOG(INFO) << "returning response with wrong request id"; + *updatedValue = *response; + updatedValue->areaId = 0; + updatedValue->value.int32Values[0] = -requestId; + break; + case 3: + LOG(INFO) << "not generating a property change event because of lshal prop: " + << toString(*response); + return StatusCode::OK; + default: + LOG(ERROR) << "invalid action on lshal response: " << toString(*response); + return StatusCode::INTERNAL_ERROR; + } + + LOG(INFO) << "updating property to: " << toString(*updatedValue); + onPropertyValueFromCar(*updatedValue, updateStatus); + return StatusCode::OK; +} + EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() { return std::make_unique(); } diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h index 5fc6493ba5..6d927b06e2 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h @@ -77,6 +77,10 @@ class EmulatedVehicleServer : public IVehicleServer { std::bind(&EmulatedVehicleServer::onFakeValueGenerated, this, std::placeholders::_1)}; VehiclePropValuePool* mValuePool{nullptr}; + + // TODO(b/146207078): it might be clearer to move members below to an EmulatedUserHal class + std::unique_ptr mInitialUserResponseFromCmd; + StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus); }; // Helper functions From 2acb9a7e0d3813864fcce842cbd216af7fa02e75 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 6 Feb 2020 14:52:41 -0800 Subject: [PATCH 0558/1022] Added VehicleHal.dump() This (optional) function allows the HAL implementation customize lshal debug; for example, it could: - augment dump() by dumping its own state - disable dump() - dump specific state based on arguments - run custom commands based on arguments This CL also implements this method in the emulated vehicle HAL, where it adds options to dump the user-related state. Bug: 146207078 Test: adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default --user-hal Test: atest android.hardware.automotive.vehicle@2.0-manager-unit-tests \ android.hardware.automotive.vehicle@2.0-default-impl-unit-tests Change-Id: If04e8222a31448f170ab2b54552051196b6ab958 --- .../include/vhal_v2_0/VehicleConnector.h | 17 ++++++++ .../common/include/vhal_v2_0/VehicleHal.h | 20 ++++++++++ .../default/common/src/VehicleHalManager.cpp | 14 +++++-- .../vhal_v2_0/EmulatedVehicleConnector.cpp | 39 +++++++++++++++++++ .../impl/vhal_v2_0/EmulatedVehicleConnector.h | 3 ++ .../impl/vhal_v2_0/EmulatedVehicleHal.cpp | 4 ++ .../impl/vhal_v2_0/EmulatedVehicleHal.h | 1 + 7 files changed, 95 insertions(+), 3 deletions(-) diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h index d40f122741..00b5afe217 100644 --- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h @@ -65,6 +65,12 @@ class IVehicleClient { // updateStatus is true if and only if the value is // generated by car (ECU/fake generator/injected) virtual void onPropertyValue(const VehiclePropValue& value, bool updateStatus) = 0; + + // Dump method forwarded from HIDL's debug() + // If implemented, it must return whether the caller should dump its state. + virtual bool dump(const hidl_handle& /* handle */, const hidl_vec& /* options */) { + return true; + } }; /** @@ -97,6 +103,13 @@ class IVehicleServer { // updateStatus is true if and only if the value is // generated by car (ECU/fake generator/injected) virtual void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) = 0; + + // Dump method forwarded from HIDL's debug() + // If implemented, it must return whether the caller should dump its state. + virtual bool onDump(const hidl_handle& /* handle */, + const hidl_vec& /* options */) { + return true; + } }; /** @@ -134,6 +147,10 @@ class IPassThroughConnector : public VehicleClientType, public VehicleServerType return this->onPropertyValue(value, updateStatus); } + bool dump(const hidl_handle& handle, const hidl_vec& options) override { + return this->onDump(handle, options); + } + // To be implemented: // virtual std::vector onGetAllPropertyConfig() = 0; // virtual void onPropertyValue(const VehiclePropValue& value) = 0; diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h index fd28483a4e..fe01867611 100644 --- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h @@ -70,6 +70,26 @@ public: */ virtual void onCreate() {} + /** + * Dump method forwarded from HIDL's debug(). + * + * By default it doesn't dump anything and let caller dump its properties, but it could be + * override to change the behavior. For example: + * + * - To augment caller's dump, it should dump its state and return true. + * - To not dump anything at all, it should just return false. + * - To provide custom dump (like dumping just specific state or executing a custom command), + * it should check if options is not empty, handle the options accordingly, then return false. + * + * @param handle handle used to dump the contents. + * @param options options passed to dump. + * + * @return whether the caller should dump its state. + */ + virtual bool dump(const hidl_handle& /* handle */, const hidl_vec& /* options */) { + return true; + } + void init( VehiclePropValuePool* valueObjectPool, const HalEventFunction& onHalEvent, diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp index 4f42e630f7..5bebd1e6a4 100644 --- a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp +++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp @@ -186,11 +186,19 @@ Return VehicleHalManager::debugDump(IVehicle::debugDump_cb _hidl_cb) { } Return VehicleHalManager::debug(const hidl_handle& fd, const hidl_vec& options) { - if (fd.getNativeHandle() != nullptr && fd->numFds > 0) { - cmdDump(fd->data[0], options); - } else { + if (fd.getNativeHandle() == nullptr || fd->numFds == 0) { ALOGE("Invalid parameters passed to debug()"); + return Void(); } + + bool shouldContinue = mHal->dump(fd, options); + if (!shouldContinue) { + ALOGI("Dumped HAL only"); + return Void(); + } + + // Do our dump + cmdDump(fd->data[0], options); return Void(); } diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp index 197c6dbedb..63ad93c375 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp @@ -16,6 +16,8 @@ #define LOG_TAG "automotive.vehicle@2.0-connector" +#include + #include #include @@ -370,6 +372,43 @@ StatusCode EmulatedVehicleServer::onSetInitialUserInfo(const VehiclePropValue& v return StatusCode::OK; } +bool EmulatedVehicleServer::onDump(const hidl_handle& handle, + const hidl_vec& options) { + int fd = handle->data[0]; + + if (options.size() > 0) { + if (options[0] == "--help") { + dprintf(fd, "Emulator-specific usage:\n"); + dprintf(fd, "--user-hal: dumps state used for user management \n"); + dprintf(fd, "\n"); + // Include caller's help options + return true; + } else if (options[0] == "--user-hal") { + dumpUserHal(fd, ""); + return false; + + } else { + // Let caller handle the options... + return true; + } + } + + dprintf(fd, "Emulator-specific state:\n"); + dumpUserHal(fd, " "); + dprintf(fd, "\n"); + + return true; +} + +void EmulatedVehicleServer::dumpUserHal(int fd, std::string indent) { + if (mInitialUserResponseFromCmd != nullptr) { + dprintf(fd, "%sInitial User Info: %s\n", indent.c_str(), + toString(*mInitialUserResponseFromCmd).c_str()); + } else { + dprintf(fd, "%sNo Initial User Info\n", indent.c_str()); + } +} + EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() { return std::make_unique(); } diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h index 6d927b06e2..4850d32d94 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h @@ -54,6 +54,8 @@ class EmulatedVehicleServer : public IVehicleServer { StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override; + bool onDump(const hidl_handle& fd, const hidl_vec& options) override; + // Set the Property Value Pool used in this server void setValuePool(VehiclePropValuePool* valuePool); @@ -81,6 +83,7 @@ class EmulatedVehicleServer : public IVehicleServer { // TODO(b/146207078): it might be clearer to move members below to an EmulatedUserHal class std::unique_ptr mInitialUserResponseFromCmd; StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus); + void dumpUserHal(int fd, std::string indent); }; // Helper functions 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 5c16bf75c1..692c7f791f 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 @@ -131,6 +131,10 @@ VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get( return v; } +bool EmulatedVehicleHal::dump(const hidl_handle& fd, const hidl_vec& options) { + return mVehicleClient->dump(fd, options); +} + StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { constexpr bool updateStatus = false; diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h index a8378da623..ebc405e04a 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h @@ -57,6 +57,7 @@ public: StatusCode set(const VehiclePropValue& propValue) override; StatusCode subscribe(int32_t property, float sampleRate) override; StatusCode unsubscribe(int32_t property) override; + bool dump(const hidl_handle& fd, const hidl_vec& options) override; // Methods from EmulatedVehicleHalIface bool setPropertyFromVehicle(const VehiclePropValue& propValue) override; From f6820b2b44e9fcc025f8d98790a01484a5ab8faa Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 7 Feb 2020 17:39:56 -0800 Subject: [PATCH 0559/1022] composer: add TestCommandReader to 2.4 Add a TestCommandReader to composer 2.4 VTS to parse correctly the new commands introduced in 2.4. Test: adb shell /data/nativetest64/VtsHalGraphicsComposerV2_4TargetTest/VtsHalGraphicsComposerV2_4TargetTest Bug: 149124892 Change-Id: Ide4f98fa3bfc771e4095cc672f59b87e1aa03427 --- .../2.1/utils/vts/TestCommandReader.cpp | 103 +++++++++--------- .../composer-vts/2.1/TestCommandReader.h | 14 ++- graphics/composer/2.4/utils/vts/Android.bp | 2 + .../composer/2.4/utils/vts/ComposerVts.cpp | 32 ++++++ .../2.4/utils/vts/TestCommandReader.cpp | 38 +++++++ .../include/composer-vts/2.4/ComposerVts.h | 3 + .../composer-vts/2.4/TestCommandReader.h | 32 ++++++ .../VtsHalGraphicsComposerV2_4TargetTest.cpp | 10 +- 8 files changed, 175 insertions(+), 59 deletions(-) create mode 100644 graphics/composer/2.4/utils/vts/TestCommandReader.cpp create mode 100644 graphics/composer/2.4/utils/vts/include/composer-vts/2.4/TestCommandReader.h diff --git a/graphics/composer/2.1/utils/vts/TestCommandReader.cpp b/graphics/composer/2.1/utils/vts/TestCommandReader.cpp index 454a89ccdc..0506f3ad88 100644 --- a/graphics/composer/2.1/utils/vts/TestCommandReader.cpp +++ b/graphics/composer/2.1/utils/vts/TestCommandReader.cpp @@ -29,63 +29,68 @@ void TestCommandReader::parse() { mErrors.clear(); mCompositionChanges.clear(); while (!isEmpty()) { - IComposerClient::Command command; + int32_t command; uint16_t length; ASSERT_TRUE(beginCommand(&command, &length)); - switch (command) { - case IComposerClient::Command::SELECT_DISPLAY: - ASSERT_EQ(2, length); - read64(); // display - break; - case IComposerClient::Command::SET_ERROR: { - ASSERT_EQ(2, length); - auto loc = read(); - auto err = readSigned(); - std::pair error(loc, err); - mErrors.push_back(error); - } break; - case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES: - ASSERT_EQ(0, length % 3); - for (uint16_t count = 0; count < length / 3; ++count) { - uint64_t layerId = read64(); - uint32_t composition = read(); - - std::pair compositionChange(layerId, composition); - mCompositionChanges.push_back(compositionChange); - } - break; - case IComposerClient::Command::SET_DISPLAY_REQUESTS: - ASSERT_EQ(1, length % 3); - read(); // displayRequests, ignored for now - for (uint16_t count = 0; count < (length - 1) / 3; ++count) { - read64(); // layer - // silently eat requests to clear the client target, since we won't be testing - // client composition anyway - ASSERT_EQ(1u, read()); - } - break; - case IComposerClient::Command::SET_PRESENT_FENCE: - ASSERT_EQ(1, length); - close(readFence()); - break; - case IComposerClient::Command::SET_RELEASE_FENCES: - ASSERT_EQ(0, length % 3); - for (uint16_t count = 0; count < length / 3; ++count) { - read64(); - close(readFence()); - } - break; - default: - GTEST_FAIL() << "unexpected return command " << std::hex - << static_cast(command); - break; - } + parseSingleCommand(command, length); endCommand(); } } +void TestCommandReader::parseSingleCommand(int32_t commandRaw, uint16_t length) { + IComposerClient::Command command = static_cast(commandRaw); + + switch (command) { + case IComposerClient::Command::SELECT_DISPLAY: + ASSERT_EQ(2, length); + read64(); // display + break; + case IComposerClient::Command::SET_ERROR: { + ASSERT_EQ(2, length); + auto loc = read(); + auto err = readSigned(); + std::pair error(loc, err); + mErrors.push_back(error); + } break; + case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES: + ASSERT_EQ(0, length % 3); + for (uint16_t count = 0; count < length / 3; ++count) { + uint64_t layerId = read64(); + uint32_t composition = read(); + + std::pair compositionChange(layerId, composition); + mCompositionChanges.push_back(compositionChange); + } + break; + case IComposerClient::Command::SET_DISPLAY_REQUESTS: + ASSERT_EQ(1, length % 3); + read(); // displayRequests, ignored for now + for (uint16_t count = 0; count < (length - 1) / 3; ++count) { + read64(); // layer + // silently eat requests to clear the client target, since we won't be testing + // client composition anyway + ASSERT_EQ(1u, read()); + } + break; + case IComposerClient::Command::SET_PRESENT_FENCE: + ASSERT_EQ(1, length); + close(readFence()); + break; + case IComposerClient::Command::SET_RELEASE_FENCES: + ASSERT_EQ(0, length % 3); + for (uint16_t count = 0; count < length / 3; ++count) { + read64(); + close(readFence()); + } + break; + default: + GTEST_FAIL() << "unexpected return command " << std::hex << static_cast(command); + break; + } +} + } // namespace vts } // namespace V2_1 } // namespace composer diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h index c12debe066..40d347afc3 100644 --- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h +++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h @@ -29,12 +29,16 @@ namespace vts { // returned. class TestCommandReader : public CommandReaderBase { public: - // Parse all commands in the return command queue. Call GTEST_FAIL() for - // unexpected errors or commands. - void parse(); + virtual ~TestCommandReader() = default; + // Parse all commands in the return command queue. Call GTEST_FAIL() for + // unexpected errors or commands. + void parse(); - std::vector> mErrors; - std::vector> mCompositionChanges; + std::vector> mErrors; + std::vector> mCompositionChanges; + + protected: + virtual void parseSingleCommand(int32_t commandRaw, uint16_t length); }; } // namespace vts diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp index e42223d6eb..fc13c2a79c 100644 --- a/graphics/composer/2.4/utils/vts/Android.bp +++ b/graphics/composer/2.4/utils/vts/Android.bp @@ -20,6 +20,7 @@ cc_library_static { srcs: [ "ComposerVts.cpp", "GraphicsComposerCallback.cpp", + "TestCommandReader.cpp", ], static_libs: [ "android.hardware.graphics.composer@2.1", @@ -33,6 +34,7 @@ cc_library_static { "android.hardware.graphics.composer@2.1-command-buffer", "android.hardware.graphics.composer@2.2-command-buffer", "android.hardware.graphics.composer@2.3-command-buffer", + "android.hardware.graphics.composer@2.4-command-buffer", ], cflags: [ "-O0", diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp index c5f3b5ed2f..b3f3374dae 100644 --- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp @@ -132,6 +132,38 @@ Error ComposerClient::getLayerGenericMetadataKeys( return error; } +void ComposerClient::execute(TestCommandReader* reader, CommandWriterBase* writer) { + bool queueChanged = false; + uint32_t commandLength = 0; + hidl_vec commandHandles; + ASSERT_TRUE(writer->writeQueue(&queueChanged, &commandLength, &commandHandles)); + + if (queueChanged) { + auto ret = mClient->setInputCommandQueue(*writer->getMQDescriptor()); + ASSERT_EQ(V2_1::Error::NONE, ret); + } + + mClient->executeCommands_2_3( + commandLength, commandHandles, + [&](const auto& tmpError, const auto& tmpOutQueueChanged, const auto& tmpOutLength, + const auto& tmpOutHandles) { + ASSERT_EQ(V2_1::Error::NONE, tmpError); + + if (tmpOutQueueChanged) { + mClient->getOutputCommandQueue( + [&](const auto& tmpError, const auto& tmpDescriptor) { + ASSERT_EQ(V2_3::Error::NONE, tmpError); + reader->setMQDescriptor(tmpDescriptor); + }); + } + + ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles)); + reader->parse(); + }); + reader->reset(); + writer->reset(); +} + } // namespace vts } // namespace V2_4 } // namespace composer diff --git a/graphics/composer/2.4/utils/vts/TestCommandReader.cpp b/graphics/composer/2.4/utils/vts/TestCommandReader.cpp new file mode 100644 index 0000000000..a1ca62878a --- /dev/null +++ b/graphics/composer/2.4/utils/vts/TestCommandReader.cpp @@ -0,0 +1,38 @@ +/* + * Copyright 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 + +namespace android::hardware::graphics::composer::V2_4::vts { + +void TestCommandReader::parseSingleCommand(int32_t commandRaw, uint16_t length) { + IComposerClient::Command command = static_cast(commandRaw); + + switch (command) { + case IComposerClient::Command::SET_CLIENT_TARGET_PROPERTY: + ASSERT_EQ(2, length); + read(); + close(readFence()); + break; + default: + return android::hardware::graphics::composer::V2_1::vts::TestCommandReader:: + parseSingleCommand(commandRaw, length); + } +} + +} // namespace android::hardware::graphics::composer::V2_4::vts diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h index fd59eb93cd..28e17b410d 100644 --- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h @@ -22,6 +22,7 @@ #include #include #include +#include #include namespace android { @@ -92,6 +93,8 @@ class ComposerClient : public V2_3::vts::ComposerClient { Error setContentType(Display display, IComposerClient::ContentType contentType); + void execute(TestCommandReader* reader, CommandWriterBase* writer); + Error getLayerGenericMetadataKeys( std::vector* outKeys); diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/TestCommandReader.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/TestCommandReader.h new file mode 100644 index 0000000000..5736fa675a --- /dev/null +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/TestCommandReader.h @@ -0,0 +1,32 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include +#include + +namespace android::hardware::graphics::composer::V2_4::vts { + +// A command parser that checks that no error nor unexpected commands are +// returned. +class TestCommandReader + : public android::hardware::graphics::composer::V2_1::vts::TestCommandReader { + protected: + void parseSingleCommand(int32_t commandRaw, uint16_t length) override; +}; + +} // namespace android::hardware::graphics::composer::V2_4::vts diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index a7c3fd7b0c..b6343d335a 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -23,9 +23,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -77,7 +77,7 @@ class GraphicsComposerHidlTest : public ::testing::TestWithParam { mComposerCallback->setVsyncAllowed(false); mWriter = std::make_unique(1024); - mReader = std::make_unique(); + mReader = std::make_unique(); } void TearDown() override { @@ -153,7 +153,7 @@ class GraphicsComposerHidlTest : public ::testing::TestWithParam { Display mPrimaryDisplay; Display mInvalidDisplayId; std::unique_ptr mWriter; - std::unique_ptr mReader; + std::unique_ptr mReader; private: Display waitForFirstDisplay() { @@ -184,7 +184,7 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT); mWriter = std::make_unique(1024); - mReader = std::make_unique(); + mReader = std::make_unique(); } void TearDown() override { @@ -211,7 +211,7 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { int64_t newPeriodNanos); std::unique_ptr mWriter; - std::unique_ptr mReader; + std::unique_ptr mReader; int32_t mDisplayWidth; int32_t mDisplayHeight; From b0923641d689cfd6bcb8715d11ea06502db47a35 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Fri, 7 Feb 2020 09:51:58 -0800 Subject: [PATCH 0560/1022] gralloc4: move crop to seperate metadata type Move crop out of PlaneLayout so it can be set and get independently from PlaneLayout. Bug: 141632767 Test: atest VtsHalGraphicsMapperV4_0 Change-Id: Ib685c0a065754e3e3bd697d3518b03b4c76d447e --- .../hardware/graphics/common/PlaneLayout.aidl | 15 ---- .../graphics/common/StandardMetadataType.aidl | 36 +++++++-- .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 75 ++++++++++++++----- 3 files changed, 88 insertions(+), 38 deletions(-) diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl index 168028ddcc..ccb0690e82 100644 --- a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl +++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl @@ -107,19 +107,4 @@ parcelable PlaneLayout { */ long horizontalSubsampling; long verticalSubsampling; - - /** - * Some buffer producers require extra padding to their output buffer; therefore the - * physical size of the native buffer will be larger than its logical size. - * The crop rectangle determines the offset and logical size of the buffer that should be - * read by consumers. - * - * The crop rectangle is measured in samples and is relative to the offset of the - * plane. Valid crop rectangles are within the boundaries of the plane: - * [0, 0, widthInSamples, heightInSamples]. - * - * The default crop rectangle is a rectangle the same size as the plane: - * [0, 0, widthInSamples, heightInSamples]. - */ - Rect crop; } diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl index 7b46688d9f..af6045e31d 100644 --- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl +++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl @@ -259,6 +259,32 @@ enum StandardMetadataType { */ PLANE_LAYOUTS = 15, + /** + * Can be used to get the crop of the buffer. + * + * Some buffer producers require extra padding to their output buffer; therefore the + * physical size of the native buffer will be larger than its logical size. + * The crop rectangle(s) determine the offset and logical size of the buffer that should be + * read by consumers. + * + * The crop is defined per plane. The crop(s) are represented by an array of + * android.hardware.graphics.common.Rects. The array must be the same length and in the same + * order as the array of PlaneLayouts. Eg. the first crop in the array is the crop for the + * first PlaneLayout in the PlaneLayout array. + * + * Each crop Rect is measured in samples and is relative to the offset of the plane. Valid crop + * rectangles are within the boundaries of the plane: [0, 0, widthInSamples, heightInSamples]. + * The default crop rectangle of each plane is a rectangle the same size as the plane: + * [0, 0, widthInSamples, heightInSamples]. + * + * When it is encoded into a byte stream, the total number of Rects is written using + * 8 bytes in little endian. It is followed by each Rect. + * + * To encode a Rect, write the following fields in this order each as 8 bytes in little endian: + * left, top, right and bottom. + */ + CROP = 16, + /** * Can be used to get or set the dataspace of the buffer. The framework may attempt to set * this value. @@ -273,7 +299,7 @@ enum StandardMetadataType { * When it is encoded into a byte stream, it is first cast to a int32_t and then represented in * the byte stream by 4 bytes written in little endian. */ - DATASPACE = 16, + DATASPACE = 17, /** * Can be used to get or set the BlendMode. The framework may attempt to set this value. @@ -287,7 +313,7 @@ enum StandardMetadataType { * When it is encoded into a byte stream, it is first cast to a int32_t and then represented by * 4 bytes written in little endian. */ - BLEND_MODE = 17, + BLEND_MODE = 18, /** * Can be used to get or set static HDR metadata specified by SMPTE ST 2086. @@ -300,7 +326,7 @@ enum StandardMetadataType { * little endian. The ordering of float values follows the definition of Smpte2086 and XyColor. * If this is unset when encoded into a byte stream, the byte stream is empty. */ - SMPTE2086 = 18, + SMPTE2086 = 19, /** * Can be used to get or set static HDR metadata specified by CTA 861.3. @@ -313,7 +339,7 @@ enum StandardMetadataType { * little endian. The ordering of float values follows the definition of Cta861_3. * If this is unset when encoded into a byte stream, the byte stream is empty. */ - CTA861_3 = 19, + CTA861_3 = 20, /** * Can be used to get or set dynamic HDR metadata specified by SMPTE ST 2094-40:2016. @@ -326,5 +352,5 @@ enum StandardMetadataType { * using 8 bytes in little endian. It is followed by the uint8_t byte array. * If this is unset when encoded into a byte stream, the byte stream is empty. */ - SMPTE2094_40 = 20, + SMPTE2094_40 = 21, } diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 2aad24245e..7ee94ba1f4 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -151,11 +151,6 @@ class GraphicsMapperHidlTest planeLayout.totalSizeInBytes); EXPECT_EQ(1, planeLayout.horizontalSubsampling); EXPECT_EQ(1, planeLayout.verticalSubsampling); - - EXPECT_EQ(0, planeLayout.crop.left); - EXPECT_EQ(0, planeLayout.crop.top); - EXPECT_EQ(planeLayout.widthInSamples, planeLayout.crop.right); - EXPECT_EQ(planeLayout.heightInSamples, planeLayout.crop.bottom); } void verifyBufferDump(const IMapper::BufferDump& bufferDump, @@ -997,6 +992,22 @@ TEST_P(GraphicsMapperHidlTest, GetPlaneLayouts) { ASSERT_NO_FATAL_FAILURE(verifyDummyDescriptorInfoPlaneLayouts(planeLayouts)); } +/** + * Test IMapper::get(Crop) + */ +TEST_P(GraphicsMapperHidlTest, GetCrop) { + auto info = mDummyDescriptorInfo; + info.format = PixelFormat::RGBA_8888; + info.usage = static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); + + testGet(info, gralloc4::MetadataType_Crop, + [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + std::vector crops; + ASSERT_EQ(NO_ERROR, gralloc4::decodeCrop(vec, &crops)); + EXPECT_EQ(1, crops.size()); + }); +} + /** * Test IMapper::get(Dataspace) */ @@ -1104,6 +1115,8 @@ TEST_P(GraphicsMapperHidlTest, GetMetadataBadValue) { ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec)); ASSERT_EQ(0, vec.size()); + ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Crop, &vec)); + ASSERT_EQ(0, vec.size()); ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Dataspace, &vec)); ASSERT_EQ(0, vec.size()); @@ -1362,10 +1375,6 @@ TEST_P(GraphicsMapperHidlTest, SetPlaneLayouts) { planeLayoutA.totalSizeInBytes = planeLayoutA.strideInBytes * info.height; planeLayoutA.horizontalSubsampling = 1; planeLayoutA.verticalSubsampling = 1; - planeLayoutA.crop.left = 0; - planeLayoutA.crop.top = 0; - planeLayoutA.crop.right = info.width; - planeLayoutA.crop.bottom = info.height; component.type = gralloc4::PlaneLayoutComponentType_A; component.offsetInBits = 0; @@ -1382,10 +1391,6 @@ TEST_P(GraphicsMapperHidlTest, SetPlaneLayouts) { planeLayoutRGB.totalSizeInBytes = planeLayoutRGB.strideInBytes * info.height; planeLayoutRGB.horizontalSubsampling = 1; planeLayoutRGB.verticalSubsampling = 1; - planeLayoutRGB.crop.left = 0; - planeLayoutRGB.crop.top = 0; - planeLayoutRGB.crop.right = info.width; - planeLayoutRGB.crop.bottom = info.height; component.type = gralloc4::PlaneLayoutComponentType_R; planeLayoutRGB.components.push_back(component); @@ -1423,11 +1428,6 @@ TEST_P(GraphicsMapperHidlTest, SetPlaneLayouts) { EXPECT_EQ(planeLayout.horizontalSubsampling, realPlaneLayout.horizontalSubsampling); EXPECT_EQ(planeLayout.verticalSubsampling, realPlaneLayout.verticalSubsampling); - EXPECT_EQ(planeLayout.crop.left, realPlaneLayout.crop.left); - EXPECT_EQ(planeLayout.crop.top, realPlaneLayout.crop.top); - EXPECT_EQ(planeLayout.crop.right, realPlaneLayout.crop.right); - EXPECT_EQ(planeLayout.crop.bottom, realPlaneLayout.crop.bottom); - ASSERT_EQ(planeLayout.components.size(), realPlaneLayout.components.size()); for (int j = 0; j < realPlaneLayout.components.size(); j++) { @@ -1442,6 +1442,26 @@ TEST_P(GraphicsMapperHidlTest, SetPlaneLayouts) { } } +/** + * Test IMapper::set(Crop) + */ +TEST_P(GraphicsMapperHidlTest, SetCrop) { + std::vector crops{{0, 0, 32, 32}}; + hidl_vec vec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeCrop(crops, &vec)); + + testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Crop, vec, + [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { + std::vector realCrops; + ASSERT_EQ(NO_ERROR, gralloc4::decodeCrop(vec, &realCrops)); + ASSERT_EQ(1, realCrops.size()); + ASSERT_EQ(crops.front().left, realCrops.front().left); + ASSERT_EQ(crops.front().top, realCrops.front().top); + ASSERT_EQ(crops.front().right, realCrops.front().right); + ASSERT_EQ(crops.front().bottom, realCrops.front().bottom); + }); +} + /** * Test IMapper::set(Dataspace) */ @@ -1589,6 +1609,7 @@ TEST_P(GraphicsMapperHidlTest, SetMetadataNullBuffer) { mGralloc->set(bufferHandle, gralloc4::MetadataType_ChromaSiting, vec)); ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_PlaneLayouts, vec)); + ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Crop, vec)); ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec)); ASSERT_EQ(Error::BAD_BUFFER, @@ -1653,6 +1674,7 @@ TEST_P(GraphicsMapperHidlTest, SetBadMetadata) { mGralloc->set(bufferHandle, gralloc4::MetadataType_ChromaSiting, vec)); ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_PlaneLayouts, vec)); + ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Crop, vec)); ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec)); ASSERT_EQ(Error::UNSUPPORTED, @@ -1866,6 +1888,23 @@ TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPlaneLayouts) { ASSERT_NO_FATAL_FAILURE(verifyDummyDescriptorInfoPlaneLayouts(planeLayouts)); } +/** + * Test IMapper::getFromBufferDescriptorInfo(Crop) + */ +TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCrop) { + auto info = mDummyDescriptorInfo; + info.format = PixelFormat::RGBA_8888; + info.usage = static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); + + hidl_vec vec; + ASSERT_EQ(Error::NONE, + mGralloc->getFromBufferDescriptorInfo(info, gralloc4::MetadataType_Crop, &vec)); + + std::vector crops; + ASSERT_EQ(NO_ERROR, gralloc4::decodeCrop(vec, &crops)); + EXPECT_EQ(1, crops.size()); +} + /** * Test IMapper::getFromBufferDescriptorInfo(Dataspace) */ From 44d2b0a75ba1cc637cc0d448401d889297e1788c Mon Sep 17 00:00:00 2001 From: Sasha Kuznetsov Date: Thu, 16 Jan 2020 18:41:39 -0800 Subject: [PATCH 0561/1022] Add GnssAntennaInfo to HAL Test: End to end test: run "atest GnssAntennaInfoRegistrationTest" on cuttlefish and watch "adb logcat | grep -i GnssAntennaInfo". Other tests: atest GnssAntennaInfoTest, atest GnssAntennaInfoProviderTest, atest GnssManagerServiceTest, atest VtsHalGnssV2_1TargetTest, atest LocationManagerFineTest. Bug: 124556515 Change-Id: Ia63a1f5022efdda52ed583a56a50f32807e83130 --- current.txt | 12 +- gnss/2.1/Android.bp | 2 + gnss/2.1/IGnss.hal | 16 ++- gnss/2.1/IGnssAntennaInfo.hal | 46 ++++++ gnss/2.1/IGnssAntennaInfoCallback.hal | 136 ++++++++++++++++++ gnss/2.1/IGnssCallback.hal | 14 +- gnss/2.1/IGnssConfiguration.hal | 2 +- gnss/2.1/IGnssMeasurement.hal | 3 +- gnss/2.1/IGnssMeasurementCallback.hal | 74 ++++++---- gnss/2.1/default/Android.bp | 1 + gnss/2.1/default/Gnss.cpp | 11 +- gnss/2.1/default/Gnss.h | 2 + gnss/2.1/default/GnssAntennaInfo.cpp | 109 ++++++++++++++ gnss/2.1/default/GnssAntennaInfo.h | 63 ++++++++ gnss/2.1/vts/functional/gnss_hal_test.cpp | 7 + gnss/2.1/vts/functional/gnss_hal_test.h | 16 +++ .../vts/functional/gnss_hal_test_cases.cpp | 81 ++++++++++- gnss/common/utils/default/Utils.cpp | 52 +++++++ gnss/common/utils/default/include/Utils.h | 4 + 19 files changed, 611 insertions(+), 40 deletions(-) create mode 100644 gnss/2.1/IGnssAntennaInfo.hal create mode 100644 gnss/2.1/IGnssAntennaInfoCallback.hal create mode 100644 gnss/2.1/default/GnssAntennaInfo.cpp create mode 100644 gnss/2.1/default/GnssAntennaInfo.h diff --git a/current.txt b/current.txt index b0b9529b6d..665977d85f 100644 --- a/current.txt +++ b/current.txt @@ -648,11 +648,13 @@ f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardwar 881aa8720fb1d69aa9843bfab69d810ab7654a61d2f5ab5e2626cbf240f24eaf android.hardware.dumpstate@1.1::types 13b33f623521ded51a6c0f7ea5b77e97066d0aa1e38a83c2873f08ad67294f89 android.hardware.dumpstate@1.1::IDumpstateDevice 769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types -88371e0edf69a1f72bfc45ecb2335e9b145e87339d3eecc92664a1fb200213ba android.hardware.gnss@2.1::IGnss -ba62e1e8993bfb9f27fa04816fa0f2241ae2d01edfa3d0c04182e2e5de80045c android.hardware.gnss@2.1::IGnssCallback -ccdf3c0fb2c02a6d4dc57afb276c3497ae8172b80b00ebc0bf8a0238dd38b01d android.hardware.gnss@2.1::IGnssConfiguration -5a125c49ca83629e22afc8c39e865509343bfa2c38f0baea9a186bbac103492d android.hardware.gnss@2.1::IGnssMeasurement -d7bf37660a0946de9599dcbae997b077ee3e604fc2044534d40d3da04297a5d3 android.hardware.gnss@2.1::IGnssMeasurementCallback +626db710bf917ecf551a0b0b1f25be10bf52758f43e0fc808b148b6aae2ef73e android.hardware.gnss@2.1::IGnss +ba5ac712b2a656dc07c83ab4a7a2c2f3bee1bbcb752e8b8ffa9b672f3b5b0728 android.hardware.gnss@2.1::IGnssAntennaInfo +0bc3ed97cbc3f6abc89c68f4e9f4d124f9f723431997dc88c2186cf4d2ad47ee android.hardware.gnss@2.1::IGnssAntennaInfoCallback +50c5d009af76d65b3023a9d94ee519545e72cb7c59bc7166d768d6f00923774d android.hardware.gnss@2.1::IGnssCallback +737d750017738f0753d13ba01a3310e0161f294b8ae80b3fd63eaa227e9d9c66 android.hardware.gnss@2.1::IGnssConfiguration +7913a11206a577b12ade86a7cf3f95c2639cb514d086673f279bf99238c9917e android.hardware.gnss@2.1::IGnssMeasurement +9999f2484f35ebfacdd433dfeae459f2a582334315959653ec8efde7699ec556 android.hardware.gnss@2.1::IGnssMeasurementCallback 6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections a3f439b782a6a92aaf3c0250f3526e94e8bf8844c3d578f0815e21b12c431346 android.hardware.gnss.measurement_corrections@1.1::types ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth diff --git a/gnss/2.1/Android.bp b/gnss/2.1/Android.bp index 7efc4a60aa..21223997b3 100644 --- a/gnss/2.1/Android.bp +++ b/gnss/2.1/Android.bp @@ -9,6 +9,8 @@ hidl_interface { srcs: [ "types.hal", "IGnss.hal", + "IGnssAntennaInfo.hal", + "IGnssAntennaInfoCallback.hal", "IGnssCallback.hal", "IGnssMeasurement.hal", "IGnssMeasurementCallback.hal", diff --git a/gnss/2.1/IGnss.hal b/gnss/2.1/IGnss.hal index ce37647868..e4da5078ee 100644 --- a/gnss/2.1/IGnss.hal +++ b/gnss/2.1/IGnss.hal @@ -18,10 +18,10 @@ package android.hardware.gnss@2.1; import android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections; import @2.0::IGnss; - import IGnssCallback; import IGnssMeasurement; import IGnssConfiguration; +import IGnssAntennaInfo; /** * Represents the standard GNSS (Global Navigation Satellite System) interface. @@ -72,5 +72,15 @@ interface IGnss extends @2.0::IGnss { * * @return measurementCorrectionsIface Handle to the IMeasurementCorrections interface. */ - getExtensionMeasurementCorrections_1_1() generates (IMeasurementCorrections measurementCorrectionsIface); -}; \ No newline at end of file + getExtensionMeasurementCorrections_1_1() + generates (IMeasurementCorrections measurementCorrectionsIface); + + /** + * This method returns the IGnssAntennaInfo interface. + * + * This method must return non-null. + * + * @return gnssAntennaInfoIface Handle to the IGnssAntennaInfo interface. + */ + getExtensionGnssAntennaInfo() generates (IGnssAntennaInfo gnssAntennaInfoIface); +}; diff --git a/gnss/2.1/IGnssAntennaInfo.hal b/gnss/2.1/IGnssAntennaInfo.hal new file mode 100644 index 0000000000..f77d874c08 --- /dev/null +++ b/gnss/2.1/IGnssAntennaInfo.hal @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.1; + +import IGnssAntennaInfoCallback; + +/** + * Extended interface for GNSS antenna information support. + */ +interface IGnssAntennaInfo { + enum GnssAntennaInfoStatus : int32_t { + SUCCESS = 0, + ERROR_ALREADY_INIT = -100, + ERROR_GENERIC = -101, + }; + + /** + * Registers the callback routines with the HAL. + * + * @param callback Handle to the GnssAntennaInfo callback interface. + */ + setCallback(IGnssAntennaInfoCallback callback) generates (GnssAntennaInfoStatus initRet); + + /** + * Stops updates from the HAL, and unregisters the callback routines. + * After a call to close(), the previously registered callbacks must be + * considered invalid by the HAL. + * If close() is invoked without a previous setCallback, this function must perform + * no work. + */ + close(); +}; diff --git a/gnss/2.1/IGnssAntennaInfoCallback.hal b/gnss/2.1/IGnssAntennaInfoCallback.hal new file mode 100644 index 0000000000..883111e9c8 --- /dev/null +++ b/gnss/2.1/IGnssAntennaInfoCallback.hal @@ -0,0 +1,136 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.1; + +/** + * The callback interface to report GNSS antenna information from the HAL. + */ +interface IGnssAntennaInfoCallback { + /** + * A row of doubles. This is used to represent a row in a 2D array, which are used to + * characterize the phase center variation corrections and signal gain corrections. + */ + struct Row { + vec row; + }; + + /** + * A point in 3D space, with associated uncertainty. + */ + struct Coord { + double x; + + double xUncertainty; + + double y; + + double yUncertainty; + + double z; + + double zUncertainty; + }; + + struct GnssAntennaInfo { + /** + * The carrier frequency in MHz. + */ + double carrierFrequencyMHz; + + /** + * Phase center offset (PCO) with associated 1-sigma uncertainty. PCO is defined with + * respect to the origin of the Android sensor coordinate system, e.g., center of primary + * screen for mobiles - see sensor or form factor documents for details. + */ + Coord phaseCenterOffsetCoordinateMillimeters; + + /** + * 2D vectors representing the phase center variation (PCV) corrections, in + * millimeters, at regularly spaced azimuthal angle (theta) and zenith angle + * (phi). The PCV correction is added to the phase measurement to obtain the + * corrected value. + * + * The azimuthal angle, theta, is defined with respect to the X axis of the + * Android sensor coordinate system, increasing toward the Y axis. The zenith + * angle, phi, is defined with respect to the Z axis of the Android Sensor + * coordinate system, increasing toward the X-Y plane. + * + * Each row vector (outer vectors) represents a fixed theta. The first row + * corresponds to a theta angle of 0 degrees. The last row corresponds to a + * theta angle of (360 - deltaTheta) degrees, where deltaTheta is the regular + * spacing between azimuthal angles, i.e., deltaTheta = 360 / (number of rows). + * + * The columns (inner vectors) represent fixed zenith angles, beginning at 0 + * degrees and ending at 180 degrees. They are separated by deltaPhi, the regular + * spacing between zenith angles, i.e., deltaPhi = 180 / (number of columns - 1). + * + * This field is optional, i.e., an empty vector. + */ + vec phaseCenterVariationCorrectionMillimeters; + + /** + * 2D vectors of 1-sigma uncertainty in millimeters associated with the PCV + * correction values. + * + * This field is optional, i.e., an empty vector. + */ + vec phaseCenterVariationCorrectionUncertaintyMillimeters; + + /** + * 2D vectors representing the signal gain corrections at regularly spaced + * azimuthal angle (theta) and zenith angle (phi). The values are calculated or + * measured at the antenna feed point without considering the radio and receiver + * noise figure and path loss contribution, in dBi, i.e., decibel over isotropic + * antenna with the same total power. The signal gain correction is added the + * signal gain measurement to obtain the corrected value. + * + * The azimuthal angle, theta, is defined with respect to the X axis of the + * Android sensor coordinate system, increasing toward the Y axis. The zenith + * angle, phi, is defined with respect to the Z axis of the Android Sensor + * coordinate system, increasing toward the X-Y plane. + * + * Each row vector (outer vectors) represents a fixed theta. The first row + * corresponds to a theta angle of 0 degrees. The last row corresponds to a + * theta angle of (360 - deltaTheta) degrees, where deltaTheta is the regular + * spacing between azimuthal angles, i.e., deltaTheta = 360 / (number of rows). + * + * The columns (inner vectors) represent fixed zenith angles, beginning at 0 + * degrees and ending at 180 degrees. They are separated by deltaPhi, the regular + * spacing between zenith angles, i.e., deltaPhi = 180 / (number of columns - 1). + * + * This field is optional, i.e., an empty vector. + */ + vec signalGainCorrectionDbi; + + /** + * 2D vectors of 1-sigma uncertainty in dBi associated with the signal + * gain correction values. + * + * This field is optional, i.e., an empty vector. + */ + vec signalGainCorrectionUncertaintyDbi; + }; + + /** + * Called when on connection, and on known-change to these values, such as upon a known + * GNSS RF antenna tuning change, or a foldable device state change. + * + * This is optional. It can never be called if the GNSS antenna information is not + * available. + */ + gnssAntennaInfoCb(vec gnssAntennaInfos); +}; diff --git a/gnss/2.1/IGnssCallback.hal b/gnss/2.1/IGnssCallback.hal index da7074263c..f7b7477ad0 100644 --- a/gnss/2.1/IGnssCallback.hal +++ b/gnss/2.1/IGnssCallback.hal @@ -24,8 +24,20 @@ import @2.0::IGnssCallback; * the interfaces and passes a handle to the HAL. */ interface IGnssCallback extends @2.0::IGnssCallback { + /** + * Flags for the gnssSetCapabilities callback. + */ + @export(name = "", value_prefix = "GPS_CAPABILITY_") + enum Capabilities : @2.0::IGnssCallback.Capabilities { + /** + * GNSS supports measurement corrections + */ + ANTENNA_INFO = 1 << 11, + }; - /** Extends a GnssSvInfo, adding a basebandCN0DbHz. */ + /** + * Extends a GnssSvInfo, adding a basebandCN0DbHz. + */ struct GnssSvInfo { /** * GNSS satellite information for a single satellite and frequency. diff --git a/gnss/2.1/IGnssConfiguration.hal b/gnss/2.1/IGnssConfiguration.hal index 8360ba9953..550f3251df 100644 --- a/gnss/2.1/IGnssConfiguration.hal +++ b/gnss/2.1/IGnssConfiguration.hal @@ -65,4 +65,4 @@ interface IGnssConfiguration extends @2.0::IGnssConfiguration { * @return success Whether the HAL accepts and abides by the provided blacklist. */ setBlacklist_2_1(vec blacklist) generates (bool success); -}; \ No newline at end of file +}; diff --git a/gnss/2.1/IGnssMeasurement.hal b/gnss/2.1/IGnssMeasurement.hal index d2c76e6989..49ba7ebd2a 100644 --- a/gnss/2.1/IGnssMeasurement.hal +++ b/gnss/2.1/IGnssMeasurement.hal @@ -25,7 +25,6 @@ import IGnssMeasurementCallback; * Extended interface for GNSS Measurements support. */ interface IGnssMeasurement extends @2.0::IGnssMeasurement { - /** * Initializes the interface and registers the callback routines with the HAL. After a * successful call to 'setCallback_2_1' the HAL must begin to provide updates at an average @@ -47,5 +46,5 @@ interface IGnssMeasurement extends @2.0::IGnssMeasurement { * error code. */ setCallback_2_1(IGnssMeasurementCallback callback, bool enableFullTracking) - generates (GnssMeasurementStatus initRet); + generates (GnssMeasurementStatus initRet); }; diff --git a/gnss/2.1/IGnssMeasurementCallback.hal b/gnss/2.1/IGnssMeasurementCallback.hal index 0385abd467..1aee272fde 100644 --- a/gnss/2.1/IGnssMeasurementCallback.hal +++ b/gnss/2.1/IGnssMeasurementCallback.hal @@ -21,36 +21,56 @@ import @2.0::IGnssMeasurementCallback; import @2.0::ElapsedRealtime; import GnssSignalType; -/** The callback interface to report measurements from the HAL. */ +/** + * The callback interface to report measurements from the HAL. + */ interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback { - /** * Flags to indicate what fields in GnssMeasurement are valid. */ enum GnssMeasurementFlags : uint32_t { - /** A valid 'snr' is stored in the data structure. */ - HAS_SNR = 1 << 0, - /** A valid 'carrier frequency' is stored in the data structure. */ - HAS_CARRIER_FREQUENCY = 1 << 9, - /** A valid 'carrier cycles' is stored in the data structure. */ - HAS_CARRIER_CYCLES = 1 << 10, - /** A valid 'carrier phase' is stored in the data structure. */ - HAS_CARRIER_PHASE = 1 << 11, - /** A valid 'carrier phase uncertainty' is stored in the data structure. */ - HAS_CARRIER_PHASE_UNCERTAINTY = 1 << 12, - /** A valid automatic gain control is stored in the data structure. */ - HAS_AUTOMATIC_GAIN_CONTROL = 1 << 13, - /** A valid receiver inter-signal bias is stored in the data structure. */ - HAS_RECEIVER_ISB = 1 << 16, - /** A valid receiver inter-signal bias uncertainty is stored in the data structure. */ - HAS_RECEIVER_ISB_UNCERTAINTY = 1 << 17, - /** A valid satellite inter-signal bias is stored in the data structure. */ - HAS_SATELLITE_ISB = 1 << 18, - /** A valid satellite inter-signal bias uncertainty is stored in the data structure. */ - HAS_SATELLITE_ISB_UNCERTAINTY = 1 << 19 + /** + * A valid 'snr' is stored in the data structure. + */ + HAS_SNR = 1 << 0, + /** + * A valid 'carrier frequency' is stored in the data structure. + */ + HAS_CARRIER_FREQUENCY = 1 << 9, + /** + * A valid 'carrier cycles' is stored in the data structure. + */ + HAS_CARRIER_CYCLES = 1 << 10, + /** + * A valid 'carrier phase' is stored in the data structure. + */ + HAS_CARRIER_PHASE = 1 << 11, + /** + * A valid 'carrier phase uncertainty' is stored in the data structure. + */ + HAS_CARRIER_PHASE_UNCERTAINTY = 1 << 12, + /** + * A valid automatic gain control is stored in the data structure. + */ + HAS_AUTOMATIC_GAIN_CONTROL = 1 << 13, + /** + * A valid receiver inter-signal bias is stored in the data structure. + */ + HAS_RECEIVER_ISB = 1 << 16, + /** + * A valid receiver inter-signal bias uncertainty is stored in the data structure. + */ + HAS_RECEIVER_ISB_UNCERTAINTY = 1 << 17, + /** + * A valid satellite inter-signal bias is stored in the data structure. + */ + HAS_SATELLITE_ISB = 1 << 18, + /** + * A valid satellite inter-signal bias uncertainty is stored in the data structure. + */ + HAS_SATELLITE_ISB_UNCERTAINTY = 1 << 19, }; - /** * Extends a GNSS Measurement, adding basebandCN0DbHz, GnssMeasurementFlags, * receiverInterSignalBiasNs, receiverInterSignalBiasUncertaintyNs, satelliteInterSignalBiasNs @@ -160,10 +180,14 @@ interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback { * Complete set of GNSS Measurement data, same as 2.0 with additional fields in measurements. */ struct GnssData { - /** The full set of satellite measurement observations. */ + /** + * The full set of satellite measurement observations. + */ vec measurements; - /** The GNSS clock time reading. */ + /** + * The GNSS clock time reading. + */ GnssClock clock; /** diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp index 1f1078e398..c4dc8fd55d 100644 --- a/gnss/2.1/default/Android.bp +++ b/gnss/2.1/default/Android.bp @@ -22,6 +22,7 @@ cc_binary { vintf_fragments: ["android.hardware.gnss@2.1-service.xml"], srcs: [ "Gnss.cpp", + "GnssAntennaInfo.cpp", "GnssDebug.cpp", "GnssMeasurement.cpp", "GnssMeasurementCorrections.cpp", diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp index 679eb35804..c1af103f36 100644 --- a/gnss/2.1/default/Gnss.cpp +++ b/gnss/2.1/default/Gnss.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "Gnss" #include "Gnss.h" +#include "GnssAntennaInfo.h" #include "GnssDebug.h" #include "GnssMeasurement.h" #include "GnssMeasurementCorrections.h" @@ -334,9 +335,10 @@ Return Gnss::setCallback_2_1(const sp& callback) { sGnssCallback_2_1 = callback; - using Capabilities = V2_0::IGnssCallback::Capabilities; + using Capabilities = V2_1::IGnssCallback::Capabilities; const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS | - Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST; + Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST | + Capabilities::ANTENNA_INFO; auto ret = sGnssCallback_2_1->gnssSetCapabilitiesCb_2_0(capabilities); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); @@ -374,6 +376,11 @@ Gnss::getExtensionMeasurementCorrections_1_1() { return new GnssMeasurementCorrections(); } +Return> Gnss::getExtensionGnssAntennaInfo() { + ALOGD("Gnss::getExtensionGnssAntennaInfo"); + return new GnssAntennaInfo(); +} + void Gnss::reportSvStatus(const hidl_vec& svInfoList) const { std::unique_lock lock(mMutex); // TODO(skz): update this to call 2_0 callback if non-null diff --git a/gnss/2.1/default/Gnss.h b/gnss/2.1/default/Gnss.h index c47206a7a4..bd5e6e852c 100644 --- a/gnss/2.1/default/Gnss.h +++ b/gnss/2.1/default/Gnss.h @@ -22,6 +22,7 @@ #include #include #include +#include "GnssAntennaInfo.h" #include "GnssConfiguration.h" namespace android { @@ -91,6 +92,7 @@ struct Gnss : public IGnss { Return> getExtensionGnssConfiguration_2_1() override; Return> getExtensionMeasurementCorrections_1_1() override; + Return> getExtensionGnssAntennaInfo() override; private: void reportLocation(const V2_0::GnssLocation&) const; diff --git a/gnss/2.1/default/GnssAntennaInfo.cpp b/gnss/2.1/default/GnssAntennaInfo.cpp new file mode 100644 index 0000000000..d32a0afc48 --- /dev/null +++ b/gnss/2.1/default/GnssAntennaInfo.cpp @@ -0,0 +1,109 @@ +/* + * 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. + */ + +#define LOG_TAG "GnssAntennaInfo" + +#include "GnssAntennaInfo.h" +#include "Utils.h" + +#include + +using ::android::hardware::gnss::common::Utils; + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_1 { +namespace implementation { + +sp GnssAntennaInfo::sCallback = nullptr; + +GnssAntennaInfo::GnssAntennaInfo() : mMinIntervalMillis(1000) {} + +GnssAntennaInfo::~GnssAntennaInfo() { + stop(); +} + +// Methods from ::android::hardware::gnss::V2_1::IGnssAntennaInfo follow. +Return GnssAntennaInfo::setCallback( + const sp& callback) { + ALOGD("setCallback"); + std::unique_lock lock(mMutex); + sCallback = callback; + + if (mIsActive) { + ALOGW("GnssAntennaInfo callback already set. Resetting the callback..."); + stop(); + } + start(); + + return GnssAntennaInfoStatus::SUCCESS; +} + +Return GnssAntennaInfo::close() { + ALOGD("close"); + std::unique_lock lock(mMutex); + stop(); + sCallback = nullptr; + return Void(); +} + +// Private methods +void GnssAntennaInfo::start() { + ALOGD("start"); + mIsActive = true; + mThread = std::thread([this]() { + while (mIsActive == true) { + if (sCallback != nullptr) { + auto antennaInfos = Utils::getMockAntennaInfos(); + this->reportAntennaInfo(antennaInfos); + } + + /** For mock implementation this is good. On real device, we should only report + antennaInfo at start and when there is a configuration change. **/ + std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis)); + } + }); +} + +void GnssAntennaInfo::stop() { + ALOGD("stop"); + mIsActive = false; + if (mThread.joinable()) { + mThread.join(); + } +} + +void GnssAntennaInfo::reportAntennaInfo( + const hidl_vec& antennaInfo) const { + std::unique_lock lock(mMutex); + + if (sCallback == nullptr) { + ALOGE("%s: No non-null callback", __func__); + return; + } + + auto ret = sCallback->gnssAntennaInfoCb(antennaInfo); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +} // namespace implementation +} // namespace V2_1 +} // namespace gnss +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/gnss/2.1/default/GnssAntennaInfo.h b/gnss/2.1/default/GnssAntennaInfo.h new file mode 100644 index 0000000000..f4bfd24367 --- /dev/null +++ b/gnss/2.1/default/GnssAntennaInfo.h @@ -0,0 +1,63 @@ +/* + * 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_GNSS_V2_1_GNSSANTENNAINFO_H +#define ANDROID_HARDWARE_GNSS_V2_1_GNSSANTENNAINFO_H + +#include + +#include +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_1 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::Return; +using ::android::hardware::Void; + +struct GnssAntennaInfo : public IGnssAntennaInfo { + GnssAntennaInfo(); + ~GnssAntennaInfo(); + + // Methods from ::android::hardware::gnss::V2_1::IGnssAntennaInfo follow. + Return setCallback( + const sp& callback) override; + Return close() override; + + private: + void start(); + void stop(); + void reportAntennaInfo( + const hidl_vec& antennaInfo) const; + + static sp sCallback; + std::atomic mMinIntervalMillis; + std::atomic mIsActive; + std::thread mThread; + mutable std::mutex mMutex; +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H \ No newline at end of file diff --git a/gnss/2.1/vts/functional/gnss_hal_test.cpp b/gnss/2.1/vts/functional/gnss_hal_test.cpp index 93f89f54e0..83c4c3cd10 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test.cpp +++ b/gnss/2.1/vts/functional/gnss_hal_test.cpp @@ -262,4 +262,11 @@ Return GnssHalTest::GnssMeasurementCorrectionsCallback::setCapabilitiesCb( ALOGI("GnssMeasurementCorrectionsCallback capabilities received %d", capabilities); capabilities_cbq_.store(capabilities); return Void(); +} + +Return GnssHalTest::GnssAntennaInfoCallback::gnssAntennaInfoCb( + const hidl_vec& gnssAntennaInfos) { + ALOGD("GnssAntennaInfo v2.1 received. Size = %d", (int)gnssAntennaInfos.size()); + antenna_info_cbq_.store(gnssAntennaInfos); + return Void(); } \ No newline at end of file diff --git a/gnss/2.1/vts/functional/gnss_hal_test.h b/gnss/2.1/vts/functional/gnss_hal_test.h index b99cf2322a..3472edb907 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test.h +++ b/gnss/2.1/vts/functional/gnss_hal_test.h @@ -31,6 +31,8 @@ using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrec using android::hardware::gnss::V1_0::GnssLocationFlags; using android::hardware::gnss::V2_0::GnssConstellationType; using android::hardware::gnss::V2_1::IGnss; +using android::hardware::gnss::V2_1::IGnssAntennaInfo; +using android::hardware::gnss::V2_1::IGnssAntennaInfoCallback; using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation; using GnssLocation_2_0 = android::hardware::gnss::V2_0::GnssLocation; @@ -152,6 +154,20 @@ class GnssHalTest : public testing::TestWithParam { Return setCapabilitiesCb(uint32_t capabilities) override; }; + /* Callback class for GnssAntennaInfo. */ + class GnssAntennaInfoCallback : public IGnssAntennaInfoCallback { + public: + GnssCallbackEventQueue> + antenna_info_cbq_; + + GnssAntennaInfoCallback() : antenna_info_cbq_("info"){}; + virtual ~GnssAntennaInfoCallback() = default; + + // Methods from V2_1::GnssAntennaInfoCallback follow. + Return gnssAntennaInfoCb( + const hidl_vec& gnssAntennaInfos); + }; + /* * SetUpGnssCallback: * Set GnssCallback and verify the result. diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp index 9ac9436b0d..7b054c0033 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp @@ -139,7 +139,7 @@ TEST_P(GnssHalTest, TestGnssMeasurementFields) { std::string codeType = lastMeasurement.clock.referenceSignalTypeForIsb.codeType; ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN && - referenceConstellation >= GnssConstellationType::IRNSS); + referenceConstellation <= GnssConstellationType::IRNSS); ASSERT_TRUE(carrierFrequencyHz > 0); ASSERT_TRUE(codeType != ""); @@ -153,6 +153,85 @@ TEST_P(GnssHalTest, TestGnssMeasurementFields) { iGnssMeasurement->close(); } +/* + * TestGnssAntennaInfo: + * Sets a GnssAntennaInfoCallback, waits for report, and verifies + * 1. phaseCenterOffsetCoordinateMillimeters is valid + * 2. phaseCenterOffsetCoordinateUncertaintyMillimeters is valid. + * PhaseCenterVariationCorrections and SignalGainCorrections are optional. + */ +TEST_P(GnssHalTest, TestGnssAntennaInfo) { + const int kAntennaInfoTimeoutSeconds = 2; + + auto gnssAntennaInfo = gnss_hal_->getExtensionGnssAntennaInfo(); + ASSERT_TRUE(gnssAntennaInfo.isOk()); + + // Skip test if GnssAntennaInfo v2.1 is not supported + sp iGnssAntennaInfo = gnssAntennaInfo; + if (!(gnss_cb_->last_capabilities_ & IGnssCallback_2_1::Capabilities::ANTENNA_INFO) || + iGnssAntennaInfo == nullptr) { + ALOGD("GnssAntennaInfo v2.1 is not supported."); + return; + } + + sp callback = new GnssAntennaInfoCallback(); + auto result = iGnssAntennaInfo->setCallback(callback); + ASSERT_TRUE(result.isOk()); + EXPECT_EQ(result, IGnssAntennaInfo::GnssAntennaInfoStatus::SUCCESS); + + hidl_vec antennaInfos; + ASSERT_TRUE(callback->antenna_info_cbq_.retrieve(antennaInfos, kAntennaInfoTimeoutSeconds)); + EXPECT_EQ(callback->antenna_info_cbq_.calledCount(), 1); + ASSERT_TRUE(antennaInfos.size() > 0); + + for (auto antennaInfo : antennaInfos) { + // Remaining fields are optional + if (antennaInfo.phaseCenterVariationCorrectionMillimeters != NULL) { + int numRows = antennaInfo.phaseCenterVariationCorrectionMillimeters.size(); + int numColumns = antennaInfo.phaseCenterVariationCorrectionMillimeters[0].row.size(); + // Must have at least 1 row and 2 columns + ASSERT_TRUE(numRows >= 1 && numColumns >= 2); + + // Corrections and uncertainties must have same dimensions + ASSERT_TRUE(antennaInfo.phaseCenterVariationCorrectionMillimeters.size() == + antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters.size()); + ASSERT_TRUE( + antennaInfo.phaseCenterVariationCorrectionMillimeters[0].row.size() == + antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters[0].row.size()); + + // Must be rectangular + for (auto row : antennaInfo.phaseCenterVariationCorrectionMillimeters) { + ASSERT_TRUE(row.row.size() == numColumns); + } + for (auto row : antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters) { + ASSERT_TRUE(row.row.size() == numColumns); + } + } + if (antennaInfo.signalGainCorrectionDbi != NULL) { + int numRows = antennaInfo.signalGainCorrectionDbi.size(); + int numColumns = antennaInfo.signalGainCorrectionUncertaintyDbi[0].row.size(); + // Must have at least 1 row and 2 columns + ASSERT_TRUE(numRows >= 1 && numColumns >= 2); + + // Corrections and uncertainties must have same dimensions + ASSERT_TRUE(antennaInfo.signalGainCorrectionDbi.size() == + antennaInfo.signalGainCorrectionUncertaintyDbi.size()); + ASSERT_TRUE(antennaInfo.signalGainCorrectionDbi[0].row.size() == + antennaInfo.signalGainCorrectionUncertaintyDbi[0].row.size()); + + // Must be rectangular + for (auto row : antennaInfo.signalGainCorrectionDbi) { + ASSERT_TRUE(row.row.size() == numColumns); + } + for (auto row : antennaInfo.signalGainCorrectionUncertaintyDbi) { + ASSERT_TRUE(row.row.size() == numColumns); + } + } + } + + iGnssAntennaInfo->close(); +} + /* * TestGnssSvInfoFields: * Gets 1 location and a GnssSvInfo, and verifies diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp index 0cdc865849..2e5b87330f 100644 --- a/gnss/common/utils/default/Utils.cpp +++ b/gnss/common/utils/default/Utils.cpp @@ -235,6 +235,58 @@ GnssSvInfoV1_0 Utils::getMockSvInfoV1_0(int16_t svid, V1_0::GnssConstellationTyp return svInfo; } +hidl_vec Utils::getMockAntennaInfos() { + GnssAntennaInfo mockAntennaInfo_1 = { + .carrierFrequencyMHz = 123412.12, + .phaseCenterOffsetCoordinateMillimeters = Coord{.x = 1, + .xUncertainty = 0.1, + .y = 2, + .yUncertainty = 0.1, + .z = 3, + .zUncertainty = 0.1}, + .phaseCenterVariationCorrectionMillimeters = + { + Row{hidl_vec{1, -1, 5, -2, 3, -1}}, + Row{hidl_vec{-2, 3, 2, 0, 1, 2}}, + Row{hidl_vec{1, 3, 2, -1, -3, 5}}, + }, + .phaseCenterVariationCorrectionUncertaintyMillimeters = + { + Row{hidl_vec{0.1, 0.2, 0.4, 0.1, 0.2, 0.3}}, + Row{hidl_vec{0.3, 0.2, 0.3, 0.6, 0.1, 0.1}}, + Row{hidl_vec{0.1, 0.1, 0.4, 0.2, 0.5, 0.3}}, + }, + .signalGainCorrectionDbi = + { + Row{hidl_vec{2, -3, 1, -3, 0, -4}}, + Row{hidl_vec{1, 0, -4, 1, 3, -2}}, + Row{hidl_vec{3, -2, 0, -2, 3, 0}}, + }, + .signalGainCorrectionUncertaintyDbi = + { + Row{hidl_vec{0.3, 0.1, 0.2, 0.6, 0.1, 0.3}}, + Row{hidl_vec{0.1, 0.1, 0.5, 0.2, 0.3, 0.1}}, + Row{hidl_vec{0.2, 0.4, 0.2, 0.1, 0.1, 0.2}}, + }, + }; + + GnssAntennaInfo mockAntennaInfo_2 = { + .carrierFrequencyMHz = 532324.23, + .phaseCenterOffsetCoordinateMillimeters = Coord{.x = 5, + .xUncertainty = 0.1, + .y = 6, + .yUncertainty = 0.1, + .z = 7, + .zUncertainty = 0.1}, + }; + + hidl_vec mockAntennaInfos = { + mockAntennaInfo_1, + mockAntennaInfo_2, + }; + return mockAntennaInfos; +} + } // namespace common } // namespace gnss } // namespace hardware diff --git a/gnss/common/utils/default/include/Utils.h b/gnss/common/utils/default/include/Utils.h index e0c61a41e1..d9ad5a5a66 100644 --- a/gnss/common/utils/default/include/Utils.h +++ b/gnss/common/utils/default/include/Utils.h @@ -33,6 +33,9 @@ using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData; using GnssSvInfoV1_0 = V1_0::IGnssCallback::GnssSvInfo; using GnssSvInfoV2_0 = V2_0::IGnssCallback::GnssSvInfo; using GnssSvInfoV2_1 = V2_1::IGnssCallback::GnssSvInfo; +using GnssAntennaInfo = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo; +using Row = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::Row; +using Coord = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::Coord; struct Utils { static GnssDataV2_0 getMockMeasurementV2_0(); @@ -46,6 +49,7 @@ struct Utils { static GnssSvInfoV1_0 getMockSvInfoV1_0(int16_t svid, V1_0::GnssConstellationType type, float cN0DbHz, float elevationDegrees, float azimuthDegrees); + static hidl_vec getMockAntennaInfos(); }; } // namespace common From 8d056449898ae26568a8673910e7f3e34208a78a Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Mon, 10 Feb 2020 12:33:41 -0800 Subject: [PATCH 0562/1022] gralloc4: fix SetConstantMetadata and SetBadMetadata SetConstantMetadata was trying to set constant metadata with bad values. SetBadMetadata was also trying to set constant metadata with bad values. Update SetConstantMetadata to set constant metadata with good values. Remove constant metadata from the SetBadMetadata test. Bug: 149004202 Test: VtsHalGraphicsMapperV4_0 Change-Id: I6816fca64c7ac89e457628e94bc06bc1b05c916f --- .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 58 +++++++++++++------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 7ee94ba1f4..aa45e3bb8b 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -1628,16 +1628,48 @@ TEST_P(GraphicsMapperHidlTest, SetConstantMetadata) { const native_handle_t* bufferHandle = nullptr; ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); - hidl_vec vec; - ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, vec)); - ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, vec)); - ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, vec)); - ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, vec)); + uint64_t bufferId = 2; + hidl_vec bufferIdVec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeBufferId(bufferId, &bufferIdVec)); ASSERT_EQ(Error::BAD_VALUE, - mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, vec)); + mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, bufferIdVec)); + + std::string name{"new name"}; + hidl_vec nameVec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeName(name, &nameVec)); + ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, nameVec)); + + uint64_t width = 32; + hidl_vec widthVec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeWidth(width, &widthVec)); ASSERT_EQ(Error::BAD_VALUE, - mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, vec)); - ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec)); + mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, widthVec)); + + uint64_t height = 32; + hidl_vec heightVec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeHeight(height, &heightVec)); + ASSERT_EQ(Error::BAD_VALUE, + mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, heightVec)); + + uint64_t layerCount = 2; + hidl_vec layerCountVec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeLayerCount(layerCount, &layerCountVec)); + ASSERT_EQ(Error::BAD_VALUE, + mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, layerCountVec)); + + hardware::graphics::common::V1_2::PixelFormat pixelFormatRequested = PixelFormat::BLOB; + hidl_vec pixelFormatRequestedVec; + ASSERT_EQ(NO_ERROR, + gralloc4::encodePixelFormatRequested(pixelFormatRequested, &pixelFormatRequestedVec)); + ASSERT_EQ(Error::BAD_VALUE, + mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, + pixelFormatRequestedVec)); + + uint64_t usage = 0; + hidl_vec usageVec; + ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &usageVec)); + ASSERT_EQ(Error::BAD_VALUE, + mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, usageVec)); } /** @@ -1648,20 +1680,10 @@ TEST_P(GraphicsMapperHidlTest, SetBadMetadata) { ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); hidl_vec vec; - ASSERT_EQ(Error::UNSUPPORTED, - mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, vec)); - ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, vec)); - ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, vec)); - ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, vec)); - ASSERT_EQ(Error::UNSUPPORTED, - mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, vec)); - ASSERT_EQ(Error::UNSUPPORTED, - mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, vec)); ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatFourCC, vec)); ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatModifier, vec)); - ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec)); ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_AllocationSize, vec)); ASSERT_EQ(Error::UNSUPPORTED, From 52d6e032af7399608a48ffa8a63207a2d27f3167 Mon Sep 17 00:00:00 2001 From: Enrico Granata Date: Mon, 10 Feb 2020 17:42:53 -0800 Subject: [PATCH 0563/1022] Move the virtualized vehicle hal code into the trout tree AAOS virtualization work is happening under the trout tree, and we should be building reference HAL implementations for the virtualized deployment under that tree Bug: 148816426 Test: build Change-Id: I90fd2bc4191f8076475e034c7feb07b2664e63c8 --- automotive/vehicle/2.0/default/Android.bp | 70 ------ .../2.0/default/VirtualizationGrpcServer.cpp | 15 -- .../2.0/default/VirtualizedVehicleService.cpp | 56 ----- ....vehicle@2.0-virtualization-grpc-server.rc | 10 - ...tive.vehicle@2.0-virtualization-service.rc | 4 - .../virtualization/GrpcVehicleClient.cpp | 162 ------------- .../virtualization/GrpcVehicleClient.h | 40 --- .../virtualization/GrpcVehicleServer.cpp | 229 ------------------ .../virtualization/GrpcVehicleServer.h | 49 ---- .../impl/vhal_v2_0/virtualization/Utils.cpp | 115 --------- .../impl/vhal_v2_0/virtualization/Utils.h | 49 ---- 11 files changed, 799 deletions(-) delete mode 100644 automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp delete mode 100644 automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp delete mode 100644 automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc delete mode 100644 automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc delete mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp delete mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h delete mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp delete mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h delete mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp delete mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp index e325889517..8e579012cd 100644 --- a/automotive/vehicle/2.0/default/Android.bp +++ b/automotive/vehicle/2.0/default/Android.bp @@ -85,20 +85,6 @@ cc_library_static { ], } -// VHal virtualization utils -cc_library_static { - name: "android.hardware.automotive.vehicle@2.0-virtualization-utils", - vendor: true, - defaults: ["vhal_v2_0_defaults"], - srcs: [ - "impl/vhal_v2_0/virtualization/Utils.cpp", - ], - export_include_dirs: ["impl"], - shared_libs: [ - "libbase", - ], -} - cc_test { name: "android.hardware.automotive.vehicle@2.0-manager-unit-tests", vendor: true, @@ -153,59 +139,3 @@ cc_binary { "libqemu_pipe", ], } - -cc_binary { - name: "android.hardware.automotive.vehicle@2.0-virtualization-service", - defaults: ["vhal_v2_0_defaults"], - init_rc: ["android.hardware.automotive.vehicle@2.0-virtualization-service.rc"], - vendor: true, - relative_install_path: "hw", - srcs: [ - "impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp", - "VirtualizedVehicleService.cpp", - ], - shared_libs: [ - "libbase", - "libcutils", - "libjsoncpp", - "libprotobuf-cpp-full", - "libgrpc++", - ], - static_libs: [ - "android.hardware.automotive.vehicle@2.0-manager-lib", - "android.hardware.automotive.vehicle@2.0-default-impl-lib", - "android.hardware.automotive.vehicle@2.0-grpc", - "android.hardware.automotive.vehicle@2.0-virtualization-utils", - "libqemu_pipe", - ], - cflags: [ - "-Wno-unused-parameter", - ], -} - -cc_binary { - name: "android.hardware.automotive.vehicle@2.0-virtualization-grpc-server", - init_rc: ["android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc"], - defaults: ["vhal_v2_0_defaults"], - vendor: true, - relative_install_path: "hw", - srcs: [ - "impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp", - "VirtualizationGrpcServer.cpp", - ], - shared_libs: [ - "libbase", - "libjsoncpp", - "libprotobuf-cpp-full", - "libgrpc++", - ], - static_libs: [ - "android.hardware.automotive.vehicle@2.0-manager-lib", - "android.hardware.automotive.vehicle@2.0-default-impl-lib", - "android.hardware.automotive.vehicle@2.0-grpc", - "android.hardware.automotive.vehicle@2.0-virtualization-utils", - ], - cflags: [ - "-Wno-unused-parameter", - ], -} diff --git a/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp b/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp deleted file mode 100644 index fb02c58952..0000000000 --- a/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "vhal_v2_0/virtualization/GrpcVehicleServer.h" -#include "vhal_v2_0/virtualization/Utils.h" - -int main(int argc, char* argv[]) { - namespace vhal_impl = android::hardware::automotive::vehicle::V2_0::impl; - - auto serverInfo = vhal_impl::VsockServerInfo::fromCommandLine(argc, argv); - CHECK(serverInfo.has_value()) << "Invalid server CID/port combination"; - - auto server = vhal_impl::makeGrpcVehicleServer(serverInfo->toUri()); - server->Start(); - return 0; -} diff --git a/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp b/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp deleted file mode 100644 index 68813c9035..0000000000 --- a/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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. - */ - -#include -#include - -#include -#include -#include -#include -#include - -using namespace android; -using namespace android::hardware; -using namespace android::hardware::automotive::vehicle::V2_0; - -int main(int argc, char* argv[]) { - namespace vhal_impl = android::hardware::automotive::vehicle::V2_0::impl; - - auto serverInfo = vhal_impl::VsockServerInfo::fromRoPropertyStore(); - CHECK(serverInfo.has_value()) << "Invalid server CID/port combination"; - - auto store = std::make_unique(); - auto connector = impl::makeGrpcVehicleClient(serverInfo->toUri()); - auto hal = std::make_unique(store.get(), connector.get()); - auto emulator = std::make_unique(hal.get()); - auto service = std::make_unique(hal.get()); - - configureRpcThreadpool(4, true /* callerWillJoin */); - - LOG(INFO) << "Registering as service..."; - status_t status = service->registerAsService(); - - if (status != OK) { - LOG(ERROR) << "Unable to register vehicle service (" << status << ")"; - return 1; - } - - LOG(INFO) << "Ready"; - joinRpcThreadpool(); - - return 1; -} diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc deleted file mode 100644 index 1101b087eb..0000000000 --- a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc +++ /dev/null @@ -1,10 +0,0 @@ -# It is an interim state to run GRPC server as an Android service. -# Eventually it will run outside of Android (e.g., AGL), -# so the command line arguments are expected, though not conventionally used in Android -service vendor.vehicle-hal-2.0-server \ - /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server \ - -server_cid ${ro.vendor.vehiclehal.server.cid:-pleaseconfigurethis} \ - -server_port ${ro.vendor.vehiclehal.server.port:-pleaseconfigurethis} - class hal - user vehicle_network - group system inet diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc deleted file mode 100644 index 234de591cc..0000000000 --- a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc +++ /dev/null @@ -1,4 +0,0 @@ -service vendor.vehicle-hal-2.0 /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-virtualization-service - class hal - user vehicle_network - group system inet diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp deleted file mode 100644 index e329c5be01..0000000000 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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. - */ -#include "GrpcVehicleClient.h" - -#include -#include - -#include -#include - -#include "VehicleServer.grpc.pb.h" -#include "VehicleServer.pb.h" -#include "vhal_v2_0/ProtoMessageConverter.h" - -namespace android { -namespace hardware { -namespace automotive { -namespace vehicle { -namespace V2_0 { - -namespace impl { - -static std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() { - // TODO(chenhaosjtuacm): get secured credentials here - return ::grpc::InsecureChannelCredentials(); -} - -class GrpcVehicleClientImpl : public EmulatedVehicleClient { - public: - GrpcVehicleClientImpl(const std::string& addr) - : mServiceAddr(addr), - mGrpcChannel(::grpc::CreateChannel(mServiceAddr, getChannelCredentials())), - mGrpcStub(vhal_proto::VehicleServer::NewStub(mGrpcChannel)) { - StartValuePollingThread(); - } - - ~GrpcVehicleClientImpl() { - mShuttingDownFlag.store(true); - mShutdownCV.notify_all(); - if (mPollingThread.joinable()) { - mPollingThread.join(); - } - } - - // methods from IVehicleClient - - std::vector getAllPropertyConfig() const override; - - StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) override; - - private: - void StartValuePollingThread(); - - // private data members - - std::string mServiceAddr; - std::shared_ptr<::grpc::Channel> mGrpcChannel; - std::unique_ptr mGrpcStub; - std::thread mPollingThread; - - std::mutex mShutdownMutex; - std::condition_variable mShutdownCV; - std::atomic mShuttingDownFlag{false}; -}; - -std::unique_ptr makeGrpcVehicleClient(const std::string& addr) { - return std::make_unique(addr); -} - -std::vector GrpcVehicleClientImpl::getAllPropertyConfig() const { - std::vector configs; - ::grpc::ClientContext context; - auto config_stream = mGrpcStub->GetAllPropertyConfig(&context, ::google::protobuf::Empty()); - vhal_proto::VehiclePropConfig protoConfig; - while (config_stream->Read(&protoConfig)) { - VehiclePropConfig config; - proto_msg_converter::fromProto(&config, protoConfig); - configs.emplace_back(std::move(config)); - } - auto grpc_status = config_stream->Finish(); - if (!grpc_status.ok()) { - LOG(ERROR) << __func__ - << ": GRPC GetAllPropertyConfig Failed: " << grpc_status.error_message(); - configs.clear(); - } - - return configs; -} - -StatusCode GrpcVehicleClientImpl::setProperty(const VehiclePropValue& value, bool updateStatus) { - ::grpc::ClientContext context; - vhal_proto::WrappedVehiclePropValue wrappedProtoValue; - vhal_proto::VehicleHalCallStatus vhal_status; - proto_msg_converter::toProto(wrappedProtoValue.mutable_value(), value); - wrappedProtoValue.set_update_status(updateStatus); - - auto grpc_status = mGrpcStub->SetProperty(&context, wrappedProtoValue, &vhal_status); - if (!grpc_status.ok()) { - LOG(ERROR) << __func__ << ": GRPC SetProperty Failed: " << grpc_status.error_message(); - return StatusCode::INTERNAL_ERROR; - } - - return static_cast(vhal_status.status_code()); -} - -void GrpcVehicleClientImpl::StartValuePollingThread() { - mPollingThread = std::thread([this]() { - while (!mShuttingDownFlag.load()) { - ::grpc::ClientContext context; - - std::atomic rpc_ok{true}; - std::thread shuttingdown_watcher([this, &rpc_ok, &context]() { - std::unique_lock shutdownLock(mShutdownMutex); - mShutdownCV.wait(shutdownLock, [this, &rpc_ok]() { - return !rpc_ok.load() || mShuttingDownFlag.load(); - }); - context.TryCancel(); - }); - - auto value_stream = - mGrpcStub->StartPropertyValuesStream(&context, ::google::protobuf::Empty()); - vhal_proto::WrappedVehiclePropValue wrappedProtoValue; - while (!mShuttingDownFlag.load() && value_stream->Read(&wrappedProtoValue)) { - VehiclePropValue value; - proto_msg_converter::fromProto(&value, wrappedProtoValue.value()); - onPropertyValue(value, wrappedProtoValue.update_status()); - } - - rpc_ok.store(false); - mShutdownCV.notify_all(); - shuttingdown_watcher.join(); - - auto grpc_status = value_stream->Finish(); - // never reach here until connection lost - LOG(ERROR) << __func__ - << ": GRPC Value Streaming Failed: " << grpc_status.error_message(); - - // try to reconnect - } - }); -} - -} // namespace impl - -} // namespace V2_0 -} // namespace vehicle -} // namespace automotive -} // namespace hardware -} // namespace android diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h deleted file mode 100644 index 14eae7f057..0000000000 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - */ - -#ifndef android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleClient_H_ -#define android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleClient_H_ - -#include "vhal_v2_0/EmulatedVehicleConnector.h" - -namespace android { -namespace hardware { -namespace automotive { -namespace vehicle { -namespace V2_0 { - -namespace impl { - -std::unique_ptr makeGrpcVehicleClient(const std::string& addr); - -} // namespace impl - -} // namespace V2_0 -} // namespace vehicle -} // namespace automotive -} // namespace hardware -} // namespace android - -#endif // android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleClient_H_ diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp deleted file mode 100644 index e30b3bec54..0000000000 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - * 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. - */ -#include "GrpcVehicleServer.h" - -#include -#include -#include - -#include -#include - -#include "VehicleServer.grpc.pb.h" -#include "VehicleServer.pb.h" -#include "vhal_v2_0/ProtoMessageConverter.h" - -namespace android { -namespace hardware { -namespace automotive { -namespace vehicle { -namespace V2_0 { - -namespace impl { - -class GrpcVehicleServerImpl : public GrpcVehicleServer, public vhal_proto::VehicleServer::Service { - public: - GrpcVehicleServerImpl(const std::string& addr) : mServiceAddr(addr) { - setValuePool(&mValueObjectPool); - } - - // method from GrpcVehicleServer - void Start() override; - - // method from IVehicleServer - void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) override; - - // methods from vhal_proto::VehicleServer::Service - - ::grpc::Status GetAllPropertyConfig( - ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, - ::grpc::ServerWriter* stream) override; - - ::grpc::Status SetProperty(::grpc::ServerContext* context, - const vhal_proto::WrappedVehiclePropValue* wrappedPropValue, - vhal_proto::VehicleHalCallStatus* status) override; - - ::grpc::Status StartPropertyValuesStream( - ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, - ::grpc::ServerWriter* stream) override; - - private: - // We keep long-lasting connection for streaming the prop values. - // For us, each connection can be represented as a function to send the new value, and - // an ID to identify this connection - struct ConnectionDescriptor { - using ValueWriterType = std::function; - - ConnectionDescriptor(ValueWriterType&& value_writer) - : mValueWriter(std::move(value_writer)), - mConnectionID(CONNECTION_ID_COUNTER.fetch_add(1)) {} - - ConnectionDescriptor(const ConnectionDescriptor&) = delete; - - ConnectionDescriptor& operator=(const ConnectionDescriptor&) = delete; - - // This move constructor is NOT THREAD-SAFE, which means it cannot be moved - // while using. Since the connection descriptors are pretected by mConnectionMutex - // then we are fine here - ConnectionDescriptor(ConnectionDescriptor&& cd) - : mValueWriter(std::move(cd.mValueWriter)), - mConnectionID(cd.mConnectionID), - mIsAlive(cd.mIsAlive.load()) { - cd.mIsAlive.store(false); - } - - ValueWriterType mValueWriter; - uint64_t mConnectionID; - std::atomic mIsAlive{true}; - - static std::atomic CONNECTION_ID_COUNTER; - }; - - std::string mServiceAddr; - VehiclePropValuePool mValueObjectPool; - mutable std::shared_mutex mConnectionMutex; - mutable std::shared_mutex mWriterMutex; - std::list mValueStreamingConnections; -}; - -std::atomic GrpcVehicleServerImpl::ConnectionDescriptor::CONNECTION_ID_COUNTER = 0; - -static std::shared_ptr<::grpc::ServerCredentials> getServerCredentials() { - // TODO(chenhaosjtuacm): get secured credentials here - return ::grpc::InsecureServerCredentials(); -} - -GrpcVehicleServerPtr makeGrpcVehicleServer(const std::string& addr) { - return std::make_unique(addr); -} - -void GrpcVehicleServerImpl::Start() { - ::grpc::ServerBuilder builder; - builder.RegisterService(this); - builder.AddListeningPort(mServiceAddr, getServerCredentials()); - std::unique_ptr<::grpc::Server> server(builder.BuildAndStart()); - - server->Wait(); -} - -void GrpcVehicleServerImpl::onPropertyValueFromCar(const VehiclePropValue& value, - bool updateStatus) { - vhal_proto::WrappedVehiclePropValue wrappedPropValue; - proto_msg_converter::toProto(wrappedPropValue.mutable_value(), value); - wrappedPropValue.set_update_status(updateStatus); - std::shared_lock read_lock(mConnectionMutex); - - bool has_terminated_connections = 0; - - for (auto& connection : mValueStreamingConnections) { - auto writeOK = connection.mValueWriter(wrappedPropValue); - if (!writeOK) { - LOG(ERROR) << __func__ << ": Server Write failed, connection lost. ID: " - << connection.mConnectionID; - has_terminated_connections = true; - connection.mIsAlive.store(false); - } - } - - if (!has_terminated_connections) { - return; - } - - read_lock.unlock(); - - std::unique_lock write_lock(mConnectionMutex); - - for (auto itr = mValueStreamingConnections.begin(); itr != mValueStreamingConnections.end();) { - if (!itr->mIsAlive.load()) { - itr = mValueStreamingConnections.erase(itr); - } else { - ++itr; - } - } -} - -::grpc::Status GrpcVehicleServerImpl::GetAllPropertyConfig( - ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, - ::grpc::ServerWriter* stream) { - auto configs = onGetAllPropertyConfig(); - for (auto& config : configs) { - vhal_proto::VehiclePropConfig protoConfig; - proto_msg_converter::toProto(&protoConfig, config); - if (!stream->Write(protoConfig)) { - return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost."); - } - } - - return ::grpc::Status::OK; -} - -::grpc::Status GrpcVehicleServerImpl::SetProperty( - ::grpc::ServerContext* context, const vhal_proto::WrappedVehiclePropValue* wrappedPropValue, - vhal_proto::VehicleHalCallStatus* status) { - VehiclePropValue value; - proto_msg_converter::fromProto(&value, wrappedPropValue->value()); - - auto set_status = static_cast(onSetProperty(value, wrappedPropValue->update_status())); - if (!vhal_proto::VehicleHalStatusCode_IsValid(set_status)) { - return ::grpc::Status(::grpc::StatusCode::INTERNAL, "Unknown status code"); - } - - status->set_status_code(static_cast(set_status)); - - return ::grpc::Status::OK; -} - -::grpc::Status GrpcVehicleServerImpl::StartPropertyValuesStream( - ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, - ::grpc::ServerWriter* stream) { - std::mutex terminateMutex; - std::condition_variable terminateCV; - std::unique_lock terminateLock(terminateMutex); - bool terminated{false}; - - auto callBack = [stream, &terminateMutex, &terminateCV, &terminated, - this](const vhal_proto::WrappedVehiclePropValue& value) { - std::unique_lock lock(mWriterMutex); - if (!stream->Write(value)) { - std::unique_lock terminateLock(terminateMutex); - terminated = true; - terminateLock.unlock(); - terminateCV.notify_all(); - return false; - } - return true; - }; - - // Register connection - std::unique_lock lock(mConnectionMutex); - auto& conn = mValueStreamingConnections.emplace_back(std::move(callBack)); - lock.unlock(); - - // Never stop until connection lost - terminateCV.wait(terminateLock, [&terminated]() { return terminated; }); - - LOG(ERROR) << __func__ << ": Stream lost, ID : " << conn.mConnectionID; - - return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost."); -} - -} // namespace impl - -} // namespace V2_0 -} // namespace vehicle -} // namespace automotive -} // namespace hardware -} // namespace android diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h deleted file mode 100644 index 32f4eb203a..0000000000 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - */ - -#ifndef android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleServer_H_ -#define android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleServer_H_ - -#include "vhal_v2_0/EmulatedVehicleConnector.h" - -namespace android { -namespace hardware { -namespace automotive { -namespace vehicle { -namespace V2_0 { - -namespace impl { - -// Connect to the Vehicle Client via GRPC -class GrpcVehicleServer : public EmulatedVehicleServer { - public: - // Start listening incoming calls, should never return if working normally - virtual void Start() = 0; -}; - -using GrpcVehicleServerPtr = std::unique_ptr; - -GrpcVehicleServerPtr makeGrpcVehicleServer(const std::string& addr); - -} // namespace impl - -} // namespace V2_0 -} // namespace vehicle -} // namespace automotive -} // namespace hardware -} // namespace android - -#endif // android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleServer_H_ diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp deleted file mode 100644 index 184d8a47f7..0000000000 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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. - */ - -#include "Utils.h" - -#include - -#include -#include -#include -#include - -namespace android { -namespace hardware { -namespace automotive { -namespace vehicle { -namespace V2_0 { -namespace impl { - -std::string VsockServerInfo::toUri() { - std::stringstream uri_stream; - uri_stream << "vsock:" << serverCid << ":" << serverPort; - return uri_stream.str(); -} - -static std::optional parseUnsignedIntFromString(const char* optarg, const char* name) { - auto v = strtoul(optarg, nullptr, 0); - if (((v == ULONG_MAX) && (errno == ERANGE)) || (v > UINT_MAX)) { - LOG(WARNING) << name << " value is out of range: " << optarg; - } else if (v != 0) { - return v; - } else { - LOG(WARNING) << name << " value is invalid or missing: " << optarg; - } - - return std::nullopt; -} - -static std::optional getNumberFromProperty(const char* key) { - auto value = property_get_int64(key, -1); - if ((value <= 0) || (value > UINT_MAX)) { - LOG(WARNING) << key << " is missing or out of bounds"; - return std::nullopt; - } - - return static_cast(value); -}; - -std::optional VsockServerInfo::fromCommandLine(int argc, char* argv[]) { - std::optional cid; - std::optional port; - - // unique values to identify the options - constexpr int OPT_VHAL_SERVER_CID = 1001; - constexpr int OPT_VHAL_SERVER_PORT_NUMBER = 1002; - - struct option longOptions[] = { - {"server_cid", 1, 0, OPT_VHAL_SERVER_CID}, - {"server_port", 1, 0, OPT_VHAL_SERVER_PORT_NUMBER}, - {}, - }; - - int optValue; - while ((optValue = getopt_long_only(argc, argv, ":", longOptions, 0)) != -1) { - switch (optValue) { - case OPT_VHAL_SERVER_CID: - cid = parseUnsignedIntFromString(optarg, "cid"); - break; - case OPT_VHAL_SERVER_PORT_NUMBER: - port = parseUnsignedIntFromString(optarg, "port"); - break; - default: - // ignore other options - break; - } - } - - if (cid && port) { - return VsockServerInfo{*cid, *port}; - } - return std::nullopt; -} - -std::optional VsockServerInfo::fromRoPropertyStore() { - constexpr const char* VHAL_SERVER_CID_PROPERTY_KEY = "ro.vendor.vehiclehal.server.cid"; - constexpr const char* VHAL_SERVER_PORT_PROPERTY_KEY = "ro.vendor.vehiclehal.server.port"; - - const auto cid = getNumberFromProperty(VHAL_SERVER_CID_PROPERTY_KEY); - const auto port = getNumberFromProperty(VHAL_SERVER_PORT_PROPERTY_KEY); - - if (cid && port) { - return VsockServerInfo{*cid, *port}; - } - return std::nullopt; -} - -} // namespace impl -} // namespace V2_0 -} // namespace vehicle -} // namespace automotive -} // namespace hardware -} // namespace android diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h deleted file mode 100644 index 8a8bce7c7a..0000000000 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - */ - -#ifndef android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_ -#define android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_ - -#include -#include - -#include - -namespace android { -namespace hardware { -namespace automotive { -namespace vehicle { -namespace V2_0 { -namespace impl { - -struct VsockServerInfo { - unsigned int serverCid{0}; - unsigned int serverPort{0}; - - static std::optional fromCommandLine(int argc, char* argv[]); - static std::optional fromRoPropertyStore(); - - std::string toUri(); -}; - -} // namespace impl -} // namespace V2_0 -} // namespace vehicle -} // namespace automotive -} // namespace hardware -} // namespace android - -#endif // android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_ From cd92c8328ea2a4e6d51d4105567383c08d497648 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Fri, 7 Feb 2020 18:16:53 +0800 Subject: [PATCH 0564/1022] wifi: skip p2p vts tests if p2p is not supported Bug: 149053982 Test: * remove wifi direct featuer in device.mk * flash build * atest VtsHalWifiSupplicantP2pV1_2Target Change-Id: I9d8a41e4d1f2cde9d311481d285be448583b8d9e --- wifi/supplicant/1.2/vts/functional/Android.bp | 2 +- .../VtsHalWifiSupplicantP2pV1_2TargetTest.cpp | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantP2pV1_2TargetTest.cpp diff --git a/wifi/supplicant/1.2/vts/functional/Android.bp b/wifi/supplicant/1.2/vts/functional/Android.bp index 9781074a69..22dec84123 100644 --- a/wifi/supplicant/1.2/vts/functional/Android.bp +++ b/wifi/supplicant/1.2/vts/functional/Android.bp @@ -68,7 +68,7 @@ cc_test { name: "VtsHalWifiSupplicantP2pV1_2TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiSupplicantV1_2TargetTest.cpp", + "VtsHalWifiSupplicantP2pV1_2TargetTest.cpp", "supplicant_p2p_iface_hidl_test.cpp", ], static_libs: [ diff --git a/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantP2pV1_2TargetTest.cpp b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantP2pV1_2TargetTest.cpp new file mode 100644 index 0000000000..22bf1db45c --- /dev/null +++ b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantP2pV1_2TargetTest.cpp @@ -0,0 +1,30 @@ +/* + * 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 "supplicant_hidl_test_utils.h" + +// TODO(b/143892896): Remove this line after wifi_hidl_test_utils.cpp is +// updated. +WifiSupplicantHidlEnvironment* gEnv = nullptr; + +int main(int argc, char** argv) { + if (!::testing::deviceSupportsFeature("android.hardware.wifi.direct")) + return 0; + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From 00e6671d5ae9d7879410488f1badf96f417ccfaa Mon Sep 17 00:00:00 2001 From: Amy Date: Fri, 7 Feb 2020 19:28:10 -0800 Subject: [PATCH 0565/1022] Add an xsd and a sample xml to take vendor Tuner Resource Manager use case priority hint Test: xmllint --noout --schema tunerResourceManagerUseCaseConfig.xsd tunerResourceManagerUseCaseConfigSample.xml Bug: Change-Id: If32019a96a4b0e84f91d628e0e95158d7330037e --- .../tunerResourceManagerUseCaseConfig.xsd | 111 ++++++++++++++++++ ...unerResourceManagerUseCaseConfigSample.xml | 47 ++++++++ 2 files changed, 158 insertions(+) create mode 100644 tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd create mode 100644 tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml diff --git a/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd b/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd new file mode 100644 index 0000000000..45c01c1277 --- /dev/null +++ b/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + useCaseDefault section: + Default value for predefined use cases priority hint. + "fgPriority": priority when the use case is in foreground. + "bgPriority": priority when the use case is in background. + + + + + + + + + + useCasePreDefined section: + A list of predefined use cases and their foreground/background priority hint. + Each use case has the following attributes: + "type": type of the use case. Pre-defined use cases start with "USE_CASE_" + and have been predefined in "predefinedUseCaseType". + "fgPriority": priority when the use case is in foreground. + "bgPriority": priority when the use case is in background. + + + + + + + + + + + useCaseVendor section: + A list of vendor defined use cases and their foreground/background priority hint. + Each use case has the following attributes: + "type": type of the use case. Vendor defined use cases start with "VENDOR_USE_CASE_". + "fgPriority": priority when the use case is in foreground. + "bgPriority": priority when the use case is in background. + "id": Vendor defined use case must have an id greater than 1000 to be associated with. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml b/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml new file mode 100644 index 0000000000..938faebbed --- /dev/null +++ b/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + From ce414351c5d42f5084ff7015b255587b3c384fca Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Tue, 11 Feb 2020 04:02:18 +0000 Subject: [PATCH 0566/1022] Revert "Add GnssAntennaInfo to HAL" Revert "Add GnssAntennaInfo framework APIs" Revert "Add GnssAntennaInfo tests" Revert submission 10111057-pco_pcv Reason for revert: Build breakage Reverted Changes: I70e4014dd:Add GnssAntennaInfo framework APIs I072958ecb:Add GnssAntennaInfo tests Ia63a1f502:Add GnssAntennaInfo to HAL Change-Id: I567fb52ca6c881f2e4c3c95c589bb4288f82becf --- current.txt | 12 +- gnss/2.1/Android.bp | 2 - gnss/2.1/IGnss.hal | 16 +-- gnss/2.1/IGnssAntennaInfo.hal | 46 ------ gnss/2.1/IGnssAntennaInfoCallback.hal | 136 ------------------ gnss/2.1/IGnssCallback.hal | 14 +- gnss/2.1/IGnssConfiguration.hal | 2 +- gnss/2.1/IGnssMeasurement.hal | 3 +- gnss/2.1/IGnssMeasurementCallback.hal | 74 ++++------ gnss/2.1/default/Android.bp | 1 - gnss/2.1/default/Gnss.cpp | 11 +- gnss/2.1/default/Gnss.h | 2 - gnss/2.1/default/GnssAntennaInfo.cpp | 109 -------------- gnss/2.1/default/GnssAntennaInfo.h | 63 -------- gnss/2.1/vts/functional/gnss_hal_test.cpp | 7 - gnss/2.1/vts/functional/gnss_hal_test.h | 16 --- .../vts/functional/gnss_hal_test_cases.cpp | 81 +---------- gnss/common/utils/default/Utils.cpp | 52 ------- gnss/common/utils/default/include/Utils.h | 4 - 19 files changed, 40 insertions(+), 611 deletions(-) delete mode 100644 gnss/2.1/IGnssAntennaInfo.hal delete mode 100644 gnss/2.1/IGnssAntennaInfoCallback.hal delete mode 100644 gnss/2.1/default/GnssAntennaInfo.cpp delete mode 100644 gnss/2.1/default/GnssAntennaInfo.h diff --git a/current.txt b/current.txt index 665977d85f..b0b9529b6d 100644 --- a/current.txt +++ b/current.txt @@ -648,13 +648,11 @@ f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardwar 881aa8720fb1d69aa9843bfab69d810ab7654a61d2f5ab5e2626cbf240f24eaf android.hardware.dumpstate@1.1::types 13b33f623521ded51a6c0f7ea5b77e97066d0aa1e38a83c2873f08ad67294f89 android.hardware.dumpstate@1.1::IDumpstateDevice 769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types -626db710bf917ecf551a0b0b1f25be10bf52758f43e0fc808b148b6aae2ef73e android.hardware.gnss@2.1::IGnss -ba5ac712b2a656dc07c83ab4a7a2c2f3bee1bbcb752e8b8ffa9b672f3b5b0728 android.hardware.gnss@2.1::IGnssAntennaInfo -0bc3ed97cbc3f6abc89c68f4e9f4d124f9f723431997dc88c2186cf4d2ad47ee android.hardware.gnss@2.1::IGnssAntennaInfoCallback -50c5d009af76d65b3023a9d94ee519545e72cb7c59bc7166d768d6f00923774d android.hardware.gnss@2.1::IGnssCallback -737d750017738f0753d13ba01a3310e0161f294b8ae80b3fd63eaa227e9d9c66 android.hardware.gnss@2.1::IGnssConfiguration -7913a11206a577b12ade86a7cf3f95c2639cb514d086673f279bf99238c9917e android.hardware.gnss@2.1::IGnssMeasurement -9999f2484f35ebfacdd433dfeae459f2a582334315959653ec8efde7699ec556 android.hardware.gnss@2.1::IGnssMeasurementCallback +88371e0edf69a1f72bfc45ecb2335e9b145e87339d3eecc92664a1fb200213ba android.hardware.gnss@2.1::IGnss +ba62e1e8993bfb9f27fa04816fa0f2241ae2d01edfa3d0c04182e2e5de80045c android.hardware.gnss@2.1::IGnssCallback +ccdf3c0fb2c02a6d4dc57afb276c3497ae8172b80b00ebc0bf8a0238dd38b01d android.hardware.gnss@2.1::IGnssConfiguration +5a125c49ca83629e22afc8c39e865509343bfa2c38f0baea9a186bbac103492d android.hardware.gnss@2.1::IGnssMeasurement +d7bf37660a0946de9599dcbae997b077ee3e604fc2044534d40d3da04297a5d3 android.hardware.gnss@2.1::IGnssMeasurementCallback 6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections a3f439b782a6a92aaf3c0250f3526e94e8bf8844c3d578f0815e21b12c431346 android.hardware.gnss.measurement_corrections@1.1::types ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth diff --git a/gnss/2.1/Android.bp b/gnss/2.1/Android.bp index 21223997b3..7efc4a60aa 100644 --- a/gnss/2.1/Android.bp +++ b/gnss/2.1/Android.bp @@ -9,8 +9,6 @@ hidl_interface { srcs: [ "types.hal", "IGnss.hal", - "IGnssAntennaInfo.hal", - "IGnssAntennaInfoCallback.hal", "IGnssCallback.hal", "IGnssMeasurement.hal", "IGnssMeasurementCallback.hal", diff --git a/gnss/2.1/IGnss.hal b/gnss/2.1/IGnss.hal index e4da5078ee..ce37647868 100644 --- a/gnss/2.1/IGnss.hal +++ b/gnss/2.1/IGnss.hal @@ -18,10 +18,10 @@ package android.hardware.gnss@2.1; import android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections; import @2.0::IGnss; + import IGnssCallback; import IGnssMeasurement; import IGnssConfiguration; -import IGnssAntennaInfo; /** * Represents the standard GNSS (Global Navigation Satellite System) interface. @@ -72,15 +72,5 @@ interface IGnss extends @2.0::IGnss { * * @return measurementCorrectionsIface Handle to the IMeasurementCorrections interface. */ - getExtensionMeasurementCorrections_1_1() - generates (IMeasurementCorrections measurementCorrectionsIface); - - /** - * This method returns the IGnssAntennaInfo interface. - * - * This method must return non-null. - * - * @return gnssAntennaInfoIface Handle to the IGnssAntennaInfo interface. - */ - getExtensionGnssAntennaInfo() generates (IGnssAntennaInfo gnssAntennaInfoIface); -}; + getExtensionMeasurementCorrections_1_1() generates (IMeasurementCorrections measurementCorrectionsIface); +}; \ No newline at end of file diff --git a/gnss/2.1/IGnssAntennaInfo.hal b/gnss/2.1/IGnssAntennaInfo.hal deleted file mode 100644 index f77d874c08..0000000000 --- a/gnss/2.1/IGnssAntennaInfo.hal +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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. - */ - -package android.hardware.gnss@2.1; - -import IGnssAntennaInfoCallback; - -/** - * Extended interface for GNSS antenna information support. - */ -interface IGnssAntennaInfo { - enum GnssAntennaInfoStatus : int32_t { - SUCCESS = 0, - ERROR_ALREADY_INIT = -100, - ERROR_GENERIC = -101, - }; - - /** - * Registers the callback routines with the HAL. - * - * @param callback Handle to the GnssAntennaInfo callback interface. - */ - setCallback(IGnssAntennaInfoCallback callback) generates (GnssAntennaInfoStatus initRet); - - /** - * Stops updates from the HAL, and unregisters the callback routines. - * After a call to close(), the previously registered callbacks must be - * considered invalid by the HAL. - * If close() is invoked without a previous setCallback, this function must perform - * no work. - */ - close(); -}; diff --git a/gnss/2.1/IGnssAntennaInfoCallback.hal b/gnss/2.1/IGnssAntennaInfoCallback.hal deleted file mode 100644 index 883111e9c8..0000000000 --- a/gnss/2.1/IGnssAntennaInfoCallback.hal +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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. - */ - -package android.hardware.gnss@2.1; - -/** - * The callback interface to report GNSS antenna information from the HAL. - */ -interface IGnssAntennaInfoCallback { - /** - * A row of doubles. This is used to represent a row in a 2D array, which are used to - * characterize the phase center variation corrections and signal gain corrections. - */ - struct Row { - vec row; - }; - - /** - * A point in 3D space, with associated uncertainty. - */ - struct Coord { - double x; - - double xUncertainty; - - double y; - - double yUncertainty; - - double z; - - double zUncertainty; - }; - - struct GnssAntennaInfo { - /** - * The carrier frequency in MHz. - */ - double carrierFrequencyMHz; - - /** - * Phase center offset (PCO) with associated 1-sigma uncertainty. PCO is defined with - * respect to the origin of the Android sensor coordinate system, e.g., center of primary - * screen for mobiles - see sensor or form factor documents for details. - */ - Coord phaseCenterOffsetCoordinateMillimeters; - - /** - * 2D vectors representing the phase center variation (PCV) corrections, in - * millimeters, at regularly spaced azimuthal angle (theta) and zenith angle - * (phi). The PCV correction is added to the phase measurement to obtain the - * corrected value. - * - * The azimuthal angle, theta, is defined with respect to the X axis of the - * Android sensor coordinate system, increasing toward the Y axis. The zenith - * angle, phi, is defined with respect to the Z axis of the Android Sensor - * coordinate system, increasing toward the X-Y plane. - * - * Each row vector (outer vectors) represents a fixed theta. The first row - * corresponds to a theta angle of 0 degrees. The last row corresponds to a - * theta angle of (360 - deltaTheta) degrees, where deltaTheta is the regular - * spacing between azimuthal angles, i.e., deltaTheta = 360 / (number of rows). - * - * The columns (inner vectors) represent fixed zenith angles, beginning at 0 - * degrees and ending at 180 degrees. They are separated by deltaPhi, the regular - * spacing between zenith angles, i.e., deltaPhi = 180 / (number of columns - 1). - * - * This field is optional, i.e., an empty vector. - */ - vec phaseCenterVariationCorrectionMillimeters; - - /** - * 2D vectors of 1-sigma uncertainty in millimeters associated with the PCV - * correction values. - * - * This field is optional, i.e., an empty vector. - */ - vec phaseCenterVariationCorrectionUncertaintyMillimeters; - - /** - * 2D vectors representing the signal gain corrections at regularly spaced - * azimuthal angle (theta) and zenith angle (phi). The values are calculated or - * measured at the antenna feed point without considering the radio and receiver - * noise figure and path loss contribution, in dBi, i.e., decibel over isotropic - * antenna with the same total power. The signal gain correction is added the - * signal gain measurement to obtain the corrected value. - * - * The azimuthal angle, theta, is defined with respect to the X axis of the - * Android sensor coordinate system, increasing toward the Y axis. The zenith - * angle, phi, is defined with respect to the Z axis of the Android Sensor - * coordinate system, increasing toward the X-Y plane. - * - * Each row vector (outer vectors) represents a fixed theta. The first row - * corresponds to a theta angle of 0 degrees. The last row corresponds to a - * theta angle of (360 - deltaTheta) degrees, where deltaTheta is the regular - * spacing between azimuthal angles, i.e., deltaTheta = 360 / (number of rows). - * - * The columns (inner vectors) represent fixed zenith angles, beginning at 0 - * degrees and ending at 180 degrees. They are separated by deltaPhi, the regular - * spacing between zenith angles, i.e., deltaPhi = 180 / (number of columns - 1). - * - * This field is optional, i.e., an empty vector. - */ - vec signalGainCorrectionDbi; - - /** - * 2D vectors of 1-sigma uncertainty in dBi associated with the signal - * gain correction values. - * - * This field is optional, i.e., an empty vector. - */ - vec signalGainCorrectionUncertaintyDbi; - }; - - /** - * Called when on connection, and on known-change to these values, such as upon a known - * GNSS RF antenna tuning change, or a foldable device state change. - * - * This is optional. It can never be called if the GNSS antenna information is not - * available. - */ - gnssAntennaInfoCb(vec gnssAntennaInfos); -}; diff --git a/gnss/2.1/IGnssCallback.hal b/gnss/2.1/IGnssCallback.hal index f7b7477ad0..da7074263c 100644 --- a/gnss/2.1/IGnssCallback.hal +++ b/gnss/2.1/IGnssCallback.hal @@ -24,20 +24,8 @@ import @2.0::IGnssCallback; * the interfaces and passes a handle to the HAL. */ interface IGnssCallback extends @2.0::IGnssCallback { - /** - * Flags for the gnssSetCapabilities callback. - */ - @export(name = "", value_prefix = "GPS_CAPABILITY_") - enum Capabilities : @2.0::IGnssCallback.Capabilities { - /** - * GNSS supports measurement corrections - */ - ANTENNA_INFO = 1 << 11, - }; - /** - * Extends a GnssSvInfo, adding a basebandCN0DbHz. - */ + /** Extends a GnssSvInfo, adding a basebandCN0DbHz. */ struct GnssSvInfo { /** * GNSS satellite information for a single satellite and frequency. diff --git a/gnss/2.1/IGnssConfiguration.hal b/gnss/2.1/IGnssConfiguration.hal index 550f3251df..8360ba9953 100644 --- a/gnss/2.1/IGnssConfiguration.hal +++ b/gnss/2.1/IGnssConfiguration.hal @@ -65,4 +65,4 @@ interface IGnssConfiguration extends @2.0::IGnssConfiguration { * @return success Whether the HAL accepts and abides by the provided blacklist. */ setBlacklist_2_1(vec blacklist) generates (bool success); -}; +}; \ No newline at end of file diff --git a/gnss/2.1/IGnssMeasurement.hal b/gnss/2.1/IGnssMeasurement.hal index 49ba7ebd2a..d2c76e6989 100644 --- a/gnss/2.1/IGnssMeasurement.hal +++ b/gnss/2.1/IGnssMeasurement.hal @@ -25,6 +25,7 @@ import IGnssMeasurementCallback; * Extended interface for GNSS Measurements support. */ interface IGnssMeasurement extends @2.0::IGnssMeasurement { + /** * Initializes the interface and registers the callback routines with the HAL. After a * successful call to 'setCallback_2_1' the HAL must begin to provide updates at an average @@ -46,5 +47,5 @@ interface IGnssMeasurement extends @2.0::IGnssMeasurement { * error code. */ setCallback_2_1(IGnssMeasurementCallback callback, bool enableFullTracking) - generates (GnssMeasurementStatus initRet); + generates (GnssMeasurementStatus initRet); }; diff --git a/gnss/2.1/IGnssMeasurementCallback.hal b/gnss/2.1/IGnssMeasurementCallback.hal index 1aee272fde..0385abd467 100644 --- a/gnss/2.1/IGnssMeasurementCallback.hal +++ b/gnss/2.1/IGnssMeasurementCallback.hal @@ -21,56 +21,36 @@ import @2.0::IGnssMeasurementCallback; import @2.0::ElapsedRealtime; import GnssSignalType; -/** - * The callback interface to report measurements from the HAL. - */ +/** The callback interface to report measurements from the HAL. */ interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback { + /** * Flags to indicate what fields in GnssMeasurement are valid. */ enum GnssMeasurementFlags : uint32_t { - /** - * A valid 'snr' is stored in the data structure. - */ - HAS_SNR = 1 << 0, - /** - * A valid 'carrier frequency' is stored in the data structure. - */ - HAS_CARRIER_FREQUENCY = 1 << 9, - /** - * A valid 'carrier cycles' is stored in the data structure. - */ - HAS_CARRIER_CYCLES = 1 << 10, - /** - * A valid 'carrier phase' is stored in the data structure. - */ - HAS_CARRIER_PHASE = 1 << 11, - /** - * A valid 'carrier phase uncertainty' is stored in the data structure. - */ - HAS_CARRIER_PHASE_UNCERTAINTY = 1 << 12, - /** - * A valid automatic gain control is stored in the data structure. - */ - HAS_AUTOMATIC_GAIN_CONTROL = 1 << 13, - /** - * A valid receiver inter-signal bias is stored in the data structure. - */ - HAS_RECEIVER_ISB = 1 << 16, - /** - * A valid receiver inter-signal bias uncertainty is stored in the data structure. - */ - HAS_RECEIVER_ISB_UNCERTAINTY = 1 << 17, - /** - * A valid satellite inter-signal bias is stored in the data structure. - */ - HAS_SATELLITE_ISB = 1 << 18, - /** - * A valid satellite inter-signal bias uncertainty is stored in the data structure. - */ - HAS_SATELLITE_ISB_UNCERTAINTY = 1 << 19, + /** A valid 'snr' is stored in the data structure. */ + HAS_SNR = 1 << 0, + /** A valid 'carrier frequency' is stored in the data structure. */ + HAS_CARRIER_FREQUENCY = 1 << 9, + /** A valid 'carrier cycles' is stored in the data structure. */ + HAS_CARRIER_CYCLES = 1 << 10, + /** A valid 'carrier phase' is stored in the data structure. */ + HAS_CARRIER_PHASE = 1 << 11, + /** A valid 'carrier phase uncertainty' is stored in the data structure. */ + HAS_CARRIER_PHASE_UNCERTAINTY = 1 << 12, + /** A valid automatic gain control is stored in the data structure. */ + HAS_AUTOMATIC_GAIN_CONTROL = 1 << 13, + /** A valid receiver inter-signal bias is stored in the data structure. */ + HAS_RECEIVER_ISB = 1 << 16, + /** A valid receiver inter-signal bias uncertainty is stored in the data structure. */ + HAS_RECEIVER_ISB_UNCERTAINTY = 1 << 17, + /** A valid satellite inter-signal bias is stored in the data structure. */ + HAS_SATELLITE_ISB = 1 << 18, + /** A valid satellite inter-signal bias uncertainty is stored in the data structure. */ + HAS_SATELLITE_ISB_UNCERTAINTY = 1 << 19 }; + /** * Extends a GNSS Measurement, adding basebandCN0DbHz, GnssMeasurementFlags, * receiverInterSignalBiasNs, receiverInterSignalBiasUncertaintyNs, satelliteInterSignalBiasNs @@ -180,14 +160,10 @@ interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback { * Complete set of GNSS Measurement data, same as 2.0 with additional fields in measurements. */ struct GnssData { - /** - * The full set of satellite measurement observations. - */ + /** The full set of satellite measurement observations. */ vec measurements; - /** - * The GNSS clock time reading. - */ + /** The GNSS clock time reading. */ GnssClock clock; /** diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp index c4dc8fd55d..1f1078e398 100644 --- a/gnss/2.1/default/Android.bp +++ b/gnss/2.1/default/Android.bp @@ -22,7 +22,6 @@ cc_binary { vintf_fragments: ["android.hardware.gnss@2.1-service.xml"], srcs: [ "Gnss.cpp", - "GnssAntennaInfo.cpp", "GnssDebug.cpp", "GnssMeasurement.cpp", "GnssMeasurementCorrections.cpp", diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp index c1af103f36..679eb35804 100644 --- a/gnss/2.1/default/Gnss.cpp +++ b/gnss/2.1/default/Gnss.cpp @@ -17,7 +17,6 @@ #define LOG_TAG "Gnss" #include "Gnss.h" -#include "GnssAntennaInfo.h" #include "GnssDebug.h" #include "GnssMeasurement.h" #include "GnssMeasurementCorrections.h" @@ -335,10 +334,9 @@ Return Gnss::setCallback_2_1(const sp& callback) { sGnssCallback_2_1 = callback; - using Capabilities = V2_1::IGnssCallback::Capabilities; + using Capabilities = V2_0::IGnssCallback::Capabilities; const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS | - Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST | - Capabilities::ANTENNA_INFO; + Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST; auto ret = sGnssCallback_2_1->gnssSetCapabilitiesCb_2_0(capabilities); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); @@ -376,11 +374,6 @@ Gnss::getExtensionMeasurementCorrections_1_1() { return new GnssMeasurementCorrections(); } -Return> Gnss::getExtensionGnssAntennaInfo() { - ALOGD("Gnss::getExtensionGnssAntennaInfo"); - return new GnssAntennaInfo(); -} - void Gnss::reportSvStatus(const hidl_vec& svInfoList) const { std::unique_lock lock(mMutex); // TODO(skz): update this to call 2_0 callback if non-null diff --git a/gnss/2.1/default/Gnss.h b/gnss/2.1/default/Gnss.h index bd5e6e852c..c47206a7a4 100644 --- a/gnss/2.1/default/Gnss.h +++ b/gnss/2.1/default/Gnss.h @@ -22,7 +22,6 @@ #include #include #include -#include "GnssAntennaInfo.h" #include "GnssConfiguration.h" namespace android { @@ -92,7 +91,6 @@ struct Gnss : public IGnss { Return> getExtensionGnssConfiguration_2_1() override; Return> getExtensionMeasurementCorrections_1_1() override; - Return> getExtensionGnssAntennaInfo() override; private: void reportLocation(const V2_0::GnssLocation&) const; diff --git a/gnss/2.1/default/GnssAntennaInfo.cpp b/gnss/2.1/default/GnssAntennaInfo.cpp deleted file mode 100644 index d32a0afc48..0000000000 --- a/gnss/2.1/default/GnssAntennaInfo.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "GnssAntennaInfo" - -#include "GnssAntennaInfo.h" -#include "Utils.h" - -#include - -using ::android::hardware::gnss::common::Utils; - -namespace android { -namespace hardware { -namespace gnss { -namespace V2_1 { -namespace implementation { - -sp GnssAntennaInfo::sCallback = nullptr; - -GnssAntennaInfo::GnssAntennaInfo() : mMinIntervalMillis(1000) {} - -GnssAntennaInfo::~GnssAntennaInfo() { - stop(); -} - -// Methods from ::android::hardware::gnss::V2_1::IGnssAntennaInfo follow. -Return GnssAntennaInfo::setCallback( - const sp& callback) { - ALOGD("setCallback"); - std::unique_lock lock(mMutex); - sCallback = callback; - - if (mIsActive) { - ALOGW("GnssAntennaInfo callback already set. Resetting the callback..."); - stop(); - } - start(); - - return GnssAntennaInfoStatus::SUCCESS; -} - -Return GnssAntennaInfo::close() { - ALOGD("close"); - std::unique_lock lock(mMutex); - stop(); - sCallback = nullptr; - return Void(); -} - -// Private methods -void GnssAntennaInfo::start() { - ALOGD("start"); - mIsActive = true; - mThread = std::thread([this]() { - while (mIsActive == true) { - if (sCallback != nullptr) { - auto antennaInfos = Utils::getMockAntennaInfos(); - this->reportAntennaInfo(antennaInfos); - } - - /** For mock implementation this is good. On real device, we should only report - antennaInfo at start and when there is a configuration change. **/ - std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis)); - } - }); -} - -void GnssAntennaInfo::stop() { - ALOGD("stop"); - mIsActive = false; - if (mThread.joinable()) { - mThread.join(); - } -} - -void GnssAntennaInfo::reportAntennaInfo( - const hidl_vec& antennaInfo) const { - std::unique_lock lock(mMutex); - - if (sCallback == nullptr) { - ALOGE("%s: No non-null callback", __func__); - return; - } - - auto ret = sCallback->gnssAntennaInfoCb(antennaInfo); - if (!ret.isOk()) { - ALOGE("%s: Unable to invoke callback", __func__); - } -} - -} // namespace implementation -} // namespace V2_1 -} // namespace gnss -} // namespace hardware -} // namespace android \ No newline at end of file diff --git a/gnss/2.1/default/GnssAntennaInfo.h b/gnss/2.1/default/GnssAntennaInfo.h deleted file mode 100644 index f4bfd24367..0000000000 --- a/gnss/2.1/default/GnssAntennaInfo.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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_GNSS_V2_1_GNSSANTENNAINFO_H -#define ANDROID_HARDWARE_GNSS_V2_1_GNSSANTENNAINFO_H - -#include - -#include -#include - -namespace android { -namespace hardware { -namespace gnss { -namespace V2_1 { -namespace implementation { - -using ::android::sp; -using ::android::hardware::Return; -using ::android::hardware::Void; - -struct GnssAntennaInfo : public IGnssAntennaInfo { - GnssAntennaInfo(); - ~GnssAntennaInfo(); - - // Methods from ::android::hardware::gnss::V2_1::IGnssAntennaInfo follow. - Return setCallback( - const sp& callback) override; - Return close() override; - - private: - void start(); - void stop(); - void reportAntennaInfo( - const hidl_vec& antennaInfo) const; - - static sp sCallback; - std::atomic mMinIntervalMillis; - std::atomic mIsActive; - std::thread mThread; - mutable std::mutex mMutex; -}; - -} // namespace implementation -} // namespace V2_1 -} // namespace gnss -} // namespace hardware -} // namespace android - -#endif // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H \ No newline at end of file diff --git a/gnss/2.1/vts/functional/gnss_hal_test.cpp b/gnss/2.1/vts/functional/gnss_hal_test.cpp index 83c4c3cd10..93f89f54e0 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test.cpp +++ b/gnss/2.1/vts/functional/gnss_hal_test.cpp @@ -262,11 +262,4 @@ Return GnssHalTest::GnssMeasurementCorrectionsCallback::setCapabilitiesCb( ALOGI("GnssMeasurementCorrectionsCallback capabilities received %d", capabilities); capabilities_cbq_.store(capabilities); return Void(); -} - -Return GnssHalTest::GnssAntennaInfoCallback::gnssAntennaInfoCb( - const hidl_vec& gnssAntennaInfos) { - ALOGD("GnssAntennaInfo v2.1 received. Size = %d", (int)gnssAntennaInfos.size()); - antenna_info_cbq_.store(gnssAntennaInfos); - return Void(); } \ No newline at end of file diff --git a/gnss/2.1/vts/functional/gnss_hal_test.h b/gnss/2.1/vts/functional/gnss_hal_test.h index 3472edb907..b99cf2322a 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test.h +++ b/gnss/2.1/vts/functional/gnss_hal_test.h @@ -31,8 +31,6 @@ using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrec using android::hardware::gnss::V1_0::GnssLocationFlags; using android::hardware::gnss::V2_0::GnssConstellationType; using android::hardware::gnss::V2_1::IGnss; -using android::hardware::gnss::V2_1::IGnssAntennaInfo; -using android::hardware::gnss::V2_1::IGnssAntennaInfoCallback; using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation; using GnssLocation_2_0 = android::hardware::gnss::V2_0::GnssLocation; @@ -154,20 +152,6 @@ class GnssHalTest : public testing::TestWithParam { Return setCapabilitiesCb(uint32_t capabilities) override; }; - /* Callback class for GnssAntennaInfo. */ - class GnssAntennaInfoCallback : public IGnssAntennaInfoCallback { - public: - GnssCallbackEventQueue> - antenna_info_cbq_; - - GnssAntennaInfoCallback() : antenna_info_cbq_("info"){}; - virtual ~GnssAntennaInfoCallback() = default; - - // Methods from V2_1::GnssAntennaInfoCallback follow. - Return gnssAntennaInfoCb( - const hidl_vec& gnssAntennaInfos); - }; - /* * SetUpGnssCallback: * Set GnssCallback and verify the result. diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp index 7b054c0033..9ac9436b0d 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp @@ -139,7 +139,7 @@ TEST_P(GnssHalTest, TestGnssMeasurementFields) { std::string codeType = lastMeasurement.clock.referenceSignalTypeForIsb.codeType; ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN && - referenceConstellation <= GnssConstellationType::IRNSS); + referenceConstellation >= GnssConstellationType::IRNSS); ASSERT_TRUE(carrierFrequencyHz > 0); ASSERT_TRUE(codeType != ""); @@ -153,85 +153,6 @@ TEST_P(GnssHalTest, TestGnssMeasurementFields) { iGnssMeasurement->close(); } -/* - * TestGnssAntennaInfo: - * Sets a GnssAntennaInfoCallback, waits for report, and verifies - * 1. phaseCenterOffsetCoordinateMillimeters is valid - * 2. phaseCenterOffsetCoordinateUncertaintyMillimeters is valid. - * PhaseCenterVariationCorrections and SignalGainCorrections are optional. - */ -TEST_P(GnssHalTest, TestGnssAntennaInfo) { - const int kAntennaInfoTimeoutSeconds = 2; - - auto gnssAntennaInfo = gnss_hal_->getExtensionGnssAntennaInfo(); - ASSERT_TRUE(gnssAntennaInfo.isOk()); - - // Skip test if GnssAntennaInfo v2.1 is not supported - sp iGnssAntennaInfo = gnssAntennaInfo; - if (!(gnss_cb_->last_capabilities_ & IGnssCallback_2_1::Capabilities::ANTENNA_INFO) || - iGnssAntennaInfo == nullptr) { - ALOGD("GnssAntennaInfo v2.1 is not supported."); - return; - } - - sp callback = new GnssAntennaInfoCallback(); - auto result = iGnssAntennaInfo->setCallback(callback); - ASSERT_TRUE(result.isOk()); - EXPECT_EQ(result, IGnssAntennaInfo::GnssAntennaInfoStatus::SUCCESS); - - hidl_vec antennaInfos; - ASSERT_TRUE(callback->antenna_info_cbq_.retrieve(antennaInfos, kAntennaInfoTimeoutSeconds)); - EXPECT_EQ(callback->antenna_info_cbq_.calledCount(), 1); - ASSERT_TRUE(antennaInfos.size() > 0); - - for (auto antennaInfo : antennaInfos) { - // Remaining fields are optional - if (antennaInfo.phaseCenterVariationCorrectionMillimeters != NULL) { - int numRows = antennaInfo.phaseCenterVariationCorrectionMillimeters.size(); - int numColumns = antennaInfo.phaseCenterVariationCorrectionMillimeters[0].row.size(); - // Must have at least 1 row and 2 columns - ASSERT_TRUE(numRows >= 1 && numColumns >= 2); - - // Corrections and uncertainties must have same dimensions - ASSERT_TRUE(antennaInfo.phaseCenterVariationCorrectionMillimeters.size() == - antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters.size()); - ASSERT_TRUE( - antennaInfo.phaseCenterVariationCorrectionMillimeters[0].row.size() == - antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters[0].row.size()); - - // Must be rectangular - for (auto row : antennaInfo.phaseCenterVariationCorrectionMillimeters) { - ASSERT_TRUE(row.row.size() == numColumns); - } - for (auto row : antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters) { - ASSERT_TRUE(row.row.size() == numColumns); - } - } - if (antennaInfo.signalGainCorrectionDbi != NULL) { - int numRows = antennaInfo.signalGainCorrectionDbi.size(); - int numColumns = antennaInfo.signalGainCorrectionUncertaintyDbi[0].row.size(); - // Must have at least 1 row and 2 columns - ASSERT_TRUE(numRows >= 1 && numColumns >= 2); - - // Corrections and uncertainties must have same dimensions - ASSERT_TRUE(antennaInfo.signalGainCorrectionDbi.size() == - antennaInfo.signalGainCorrectionUncertaintyDbi.size()); - ASSERT_TRUE(antennaInfo.signalGainCorrectionDbi[0].row.size() == - antennaInfo.signalGainCorrectionUncertaintyDbi[0].row.size()); - - // Must be rectangular - for (auto row : antennaInfo.signalGainCorrectionDbi) { - ASSERT_TRUE(row.row.size() == numColumns); - } - for (auto row : antennaInfo.signalGainCorrectionUncertaintyDbi) { - ASSERT_TRUE(row.row.size() == numColumns); - } - } - } - - iGnssAntennaInfo->close(); -} - /* * TestGnssSvInfoFields: * Gets 1 location and a GnssSvInfo, and verifies diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp index 2e5b87330f..0cdc865849 100644 --- a/gnss/common/utils/default/Utils.cpp +++ b/gnss/common/utils/default/Utils.cpp @@ -235,58 +235,6 @@ GnssSvInfoV1_0 Utils::getMockSvInfoV1_0(int16_t svid, V1_0::GnssConstellationTyp return svInfo; } -hidl_vec Utils::getMockAntennaInfos() { - GnssAntennaInfo mockAntennaInfo_1 = { - .carrierFrequencyMHz = 123412.12, - .phaseCenterOffsetCoordinateMillimeters = Coord{.x = 1, - .xUncertainty = 0.1, - .y = 2, - .yUncertainty = 0.1, - .z = 3, - .zUncertainty = 0.1}, - .phaseCenterVariationCorrectionMillimeters = - { - Row{hidl_vec{1, -1, 5, -2, 3, -1}}, - Row{hidl_vec{-2, 3, 2, 0, 1, 2}}, - Row{hidl_vec{1, 3, 2, -1, -3, 5}}, - }, - .phaseCenterVariationCorrectionUncertaintyMillimeters = - { - Row{hidl_vec{0.1, 0.2, 0.4, 0.1, 0.2, 0.3}}, - Row{hidl_vec{0.3, 0.2, 0.3, 0.6, 0.1, 0.1}}, - Row{hidl_vec{0.1, 0.1, 0.4, 0.2, 0.5, 0.3}}, - }, - .signalGainCorrectionDbi = - { - Row{hidl_vec{2, -3, 1, -3, 0, -4}}, - Row{hidl_vec{1, 0, -4, 1, 3, -2}}, - Row{hidl_vec{3, -2, 0, -2, 3, 0}}, - }, - .signalGainCorrectionUncertaintyDbi = - { - Row{hidl_vec{0.3, 0.1, 0.2, 0.6, 0.1, 0.3}}, - Row{hidl_vec{0.1, 0.1, 0.5, 0.2, 0.3, 0.1}}, - Row{hidl_vec{0.2, 0.4, 0.2, 0.1, 0.1, 0.2}}, - }, - }; - - GnssAntennaInfo mockAntennaInfo_2 = { - .carrierFrequencyMHz = 532324.23, - .phaseCenterOffsetCoordinateMillimeters = Coord{.x = 5, - .xUncertainty = 0.1, - .y = 6, - .yUncertainty = 0.1, - .z = 7, - .zUncertainty = 0.1}, - }; - - hidl_vec mockAntennaInfos = { - mockAntennaInfo_1, - mockAntennaInfo_2, - }; - return mockAntennaInfos; -} - } // namespace common } // namespace gnss } // namespace hardware diff --git a/gnss/common/utils/default/include/Utils.h b/gnss/common/utils/default/include/Utils.h index d9ad5a5a66..e0c61a41e1 100644 --- a/gnss/common/utils/default/include/Utils.h +++ b/gnss/common/utils/default/include/Utils.h @@ -33,9 +33,6 @@ using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData; using GnssSvInfoV1_0 = V1_0::IGnssCallback::GnssSvInfo; using GnssSvInfoV2_0 = V2_0::IGnssCallback::GnssSvInfo; using GnssSvInfoV2_1 = V2_1::IGnssCallback::GnssSvInfo; -using GnssAntennaInfo = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo; -using Row = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::Row; -using Coord = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::Coord; struct Utils { static GnssDataV2_0 getMockMeasurementV2_0(); @@ -49,7 +46,6 @@ struct Utils { static GnssSvInfoV1_0 getMockSvInfoV1_0(int16_t svid, V1_0::GnssConstellationType type, float cN0DbHz, float elevationDegrees, float azimuthDegrees); - static hidl_vec getMockAntennaInfos(); }; } // namespace common From 768de57e4cccd461686493b526a1760cbb59c513 Mon Sep 17 00:00:00 2001 From: Sasha Kuznetsov Date: Tue, 11 Feb 2020 06:00:10 +0000 Subject: [PATCH 0567/1022] Revert^2 "Add GnssAntennaInfo to HAL" ce414351c5d42f5084ff7015b255587b3c384fca Change-Id: I791dcf8c26f3ed51c07987e79752ff3ce165fcbf --- current.txt | 12 +- gnss/2.1/Android.bp | 2 + gnss/2.1/IGnss.hal | 16 ++- gnss/2.1/IGnssAntennaInfo.hal | 46 ++++++ gnss/2.1/IGnssAntennaInfoCallback.hal | 136 ++++++++++++++++++ gnss/2.1/IGnssCallback.hal | 14 +- gnss/2.1/IGnssConfiguration.hal | 2 +- gnss/2.1/IGnssMeasurement.hal | 3 +- gnss/2.1/IGnssMeasurementCallback.hal | 74 ++++++---- gnss/2.1/default/Android.bp | 1 + gnss/2.1/default/Gnss.cpp | 11 +- gnss/2.1/default/Gnss.h | 2 + gnss/2.1/default/GnssAntennaInfo.cpp | 109 ++++++++++++++ gnss/2.1/default/GnssAntennaInfo.h | 63 ++++++++ gnss/2.1/vts/functional/gnss_hal_test.cpp | 7 + gnss/2.1/vts/functional/gnss_hal_test.h | 16 +++ .../vts/functional/gnss_hal_test_cases.cpp | 81 ++++++++++- gnss/common/utils/default/Utils.cpp | 52 +++++++ gnss/common/utils/default/include/Utils.h | 4 + 19 files changed, 611 insertions(+), 40 deletions(-) create mode 100644 gnss/2.1/IGnssAntennaInfo.hal create mode 100644 gnss/2.1/IGnssAntennaInfoCallback.hal create mode 100644 gnss/2.1/default/GnssAntennaInfo.cpp create mode 100644 gnss/2.1/default/GnssAntennaInfo.h diff --git a/current.txt b/current.txt index b0b9529b6d..665977d85f 100644 --- a/current.txt +++ b/current.txt @@ -648,11 +648,13 @@ f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardwar 881aa8720fb1d69aa9843bfab69d810ab7654a61d2f5ab5e2626cbf240f24eaf android.hardware.dumpstate@1.1::types 13b33f623521ded51a6c0f7ea5b77e97066d0aa1e38a83c2873f08ad67294f89 android.hardware.dumpstate@1.1::IDumpstateDevice 769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types -88371e0edf69a1f72bfc45ecb2335e9b145e87339d3eecc92664a1fb200213ba android.hardware.gnss@2.1::IGnss -ba62e1e8993bfb9f27fa04816fa0f2241ae2d01edfa3d0c04182e2e5de80045c android.hardware.gnss@2.1::IGnssCallback -ccdf3c0fb2c02a6d4dc57afb276c3497ae8172b80b00ebc0bf8a0238dd38b01d android.hardware.gnss@2.1::IGnssConfiguration -5a125c49ca83629e22afc8c39e865509343bfa2c38f0baea9a186bbac103492d android.hardware.gnss@2.1::IGnssMeasurement -d7bf37660a0946de9599dcbae997b077ee3e604fc2044534d40d3da04297a5d3 android.hardware.gnss@2.1::IGnssMeasurementCallback +626db710bf917ecf551a0b0b1f25be10bf52758f43e0fc808b148b6aae2ef73e android.hardware.gnss@2.1::IGnss +ba5ac712b2a656dc07c83ab4a7a2c2f3bee1bbcb752e8b8ffa9b672f3b5b0728 android.hardware.gnss@2.1::IGnssAntennaInfo +0bc3ed97cbc3f6abc89c68f4e9f4d124f9f723431997dc88c2186cf4d2ad47ee android.hardware.gnss@2.1::IGnssAntennaInfoCallback +50c5d009af76d65b3023a9d94ee519545e72cb7c59bc7166d768d6f00923774d android.hardware.gnss@2.1::IGnssCallback +737d750017738f0753d13ba01a3310e0161f294b8ae80b3fd63eaa227e9d9c66 android.hardware.gnss@2.1::IGnssConfiguration +7913a11206a577b12ade86a7cf3f95c2639cb514d086673f279bf99238c9917e android.hardware.gnss@2.1::IGnssMeasurement +9999f2484f35ebfacdd433dfeae459f2a582334315959653ec8efde7699ec556 android.hardware.gnss@2.1::IGnssMeasurementCallback 6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections a3f439b782a6a92aaf3c0250f3526e94e8bf8844c3d578f0815e21b12c431346 android.hardware.gnss.measurement_corrections@1.1::types ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth diff --git a/gnss/2.1/Android.bp b/gnss/2.1/Android.bp index 7efc4a60aa..21223997b3 100644 --- a/gnss/2.1/Android.bp +++ b/gnss/2.1/Android.bp @@ -9,6 +9,8 @@ hidl_interface { srcs: [ "types.hal", "IGnss.hal", + "IGnssAntennaInfo.hal", + "IGnssAntennaInfoCallback.hal", "IGnssCallback.hal", "IGnssMeasurement.hal", "IGnssMeasurementCallback.hal", diff --git a/gnss/2.1/IGnss.hal b/gnss/2.1/IGnss.hal index ce37647868..e4da5078ee 100644 --- a/gnss/2.1/IGnss.hal +++ b/gnss/2.1/IGnss.hal @@ -18,10 +18,10 @@ package android.hardware.gnss@2.1; import android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections; import @2.0::IGnss; - import IGnssCallback; import IGnssMeasurement; import IGnssConfiguration; +import IGnssAntennaInfo; /** * Represents the standard GNSS (Global Navigation Satellite System) interface. @@ -72,5 +72,15 @@ interface IGnss extends @2.0::IGnss { * * @return measurementCorrectionsIface Handle to the IMeasurementCorrections interface. */ - getExtensionMeasurementCorrections_1_1() generates (IMeasurementCorrections measurementCorrectionsIface); -}; \ No newline at end of file + getExtensionMeasurementCorrections_1_1() + generates (IMeasurementCorrections measurementCorrectionsIface); + + /** + * This method returns the IGnssAntennaInfo interface. + * + * This method must return non-null. + * + * @return gnssAntennaInfoIface Handle to the IGnssAntennaInfo interface. + */ + getExtensionGnssAntennaInfo() generates (IGnssAntennaInfo gnssAntennaInfoIface); +}; diff --git a/gnss/2.1/IGnssAntennaInfo.hal b/gnss/2.1/IGnssAntennaInfo.hal new file mode 100644 index 0000000000..f77d874c08 --- /dev/null +++ b/gnss/2.1/IGnssAntennaInfo.hal @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.1; + +import IGnssAntennaInfoCallback; + +/** + * Extended interface for GNSS antenna information support. + */ +interface IGnssAntennaInfo { + enum GnssAntennaInfoStatus : int32_t { + SUCCESS = 0, + ERROR_ALREADY_INIT = -100, + ERROR_GENERIC = -101, + }; + + /** + * Registers the callback routines with the HAL. + * + * @param callback Handle to the GnssAntennaInfo callback interface. + */ + setCallback(IGnssAntennaInfoCallback callback) generates (GnssAntennaInfoStatus initRet); + + /** + * Stops updates from the HAL, and unregisters the callback routines. + * After a call to close(), the previously registered callbacks must be + * considered invalid by the HAL. + * If close() is invoked without a previous setCallback, this function must perform + * no work. + */ + close(); +}; diff --git a/gnss/2.1/IGnssAntennaInfoCallback.hal b/gnss/2.1/IGnssAntennaInfoCallback.hal new file mode 100644 index 0000000000..883111e9c8 --- /dev/null +++ b/gnss/2.1/IGnssAntennaInfoCallback.hal @@ -0,0 +1,136 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.1; + +/** + * The callback interface to report GNSS antenna information from the HAL. + */ +interface IGnssAntennaInfoCallback { + /** + * A row of doubles. This is used to represent a row in a 2D array, which are used to + * characterize the phase center variation corrections and signal gain corrections. + */ + struct Row { + vec row; + }; + + /** + * A point in 3D space, with associated uncertainty. + */ + struct Coord { + double x; + + double xUncertainty; + + double y; + + double yUncertainty; + + double z; + + double zUncertainty; + }; + + struct GnssAntennaInfo { + /** + * The carrier frequency in MHz. + */ + double carrierFrequencyMHz; + + /** + * Phase center offset (PCO) with associated 1-sigma uncertainty. PCO is defined with + * respect to the origin of the Android sensor coordinate system, e.g., center of primary + * screen for mobiles - see sensor or form factor documents for details. + */ + Coord phaseCenterOffsetCoordinateMillimeters; + + /** + * 2D vectors representing the phase center variation (PCV) corrections, in + * millimeters, at regularly spaced azimuthal angle (theta) and zenith angle + * (phi). The PCV correction is added to the phase measurement to obtain the + * corrected value. + * + * The azimuthal angle, theta, is defined with respect to the X axis of the + * Android sensor coordinate system, increasing toward the Y axis. The zenith + * angle, phi, is defined with respect to the Z axis of the Android Sensor + * coordinate system, increasing toward the X-Y plane. + * + * Each row vector (outer vectors) represents a fixed theta. The first row + * corresponds to a theta angle of 0 degrees. The last row corresponds to a + * theta angle of (360 - deltaTheta) degrees, where deltaTheta is the regular + * spacing between azimuthal angles, i.e., deltaTheta = 360 / (number of rows). + * + * The columns (inner vectors) represent fixed zenith angles, beginning at 0 + * degrees and ending at 180 degrees. They are separated by deltaPhi, the regular + * spacing between zenith angles, i.e., deltaPhi = 180 / (number of columns - 1). + * + * This field is optional, i.e., an empty vector. + */ + vec phaseCenterVariationCorrectionMillimeters; + + /** + * 2D vectors of 1-sigma uncertainty in millimeters associated with the PCV + * correction values. + * + * This field is optional, i.e., an empty vector. + */ + vec phaseCenterVariationCorrectionUncertaintyMillimeters; + + /** + * 2D vectors representing the signal gain corrections at regularly spaced + * azimuthal angle (theta) and zenith angle (phi). The values are calculated or + * measured at the antenna feed point without considering the radio and receiver + * noise figure and path loss contribution, in dBi, i.e., decibel over isotropic + * antenna with the same total power. The signal gain correction is added the + * signal gain measurement to obtain the corrected value. + * + * The azimuthal angle, theta, is defined with respect to the X axis of the + * Android sensor coordinate system, increasing toward the Y axis. The zenith + * angle, phi, is defined with respect to the Z axis of the Android Sensor + * coordinate system, increasing toward the X-Y plane. + * + * Each row vector (outer vectors) represents a fixed theta. The first row + * corresponds to a theta angle of 0 degrees. The last row corresponds to a + * theta angle of (360 - deltaTheta) degrees, where deltaTheta is the regular + * spacing between azimuthal angles, i.e., deltaTheta = 360 / (number of rows). + * + * The columns (inner vectors) represent fixed zenith angles, beginning at 0 + * degrees and ending at 180 degrees. They are separated by deltaPhi, the regular + * spacing between zenith angles, i.e., deltaPhi = 180 / (number of columns - 1). + * + * This field is optional, i.e., an empty vector. + */ + vec signalGainCorrectionDbi; + + /** + * 2D vectors of 1-sigma uncertainty in dBi associated with the signal + * gain correction values. + * + * This field is optional, i.e., an empty vector. + */ + vec signalGainCorrectionUncertaintyDbi; + }; + + /** + * Called when on connection, and on known-change to these values, such as upon a known + * GNSS RF antenna tuning change, or a foldable device state change. + * + * This is optional. It can never be called if the GNSS antenna information is not + * available. + */ + gnssAntennaInfoCb(vec gnssAntennaInfos); +}; diff --git a/gnss/2.1/IGnssCallback.hal b/gnss/2.1/IGnssCallback.hal index da7074263c..f7b7477ad0 100644 --- a/gnss/2.1/IGnssCallback.hal +++ b/gnss/2.1/IGnssCallback.hal @@ -24,8 +24,20 @@ import @2.0::IGnssCallback; * the interfaces and passes a handle to the HAL. */ interface IGnssCallback extends @2.0::IGnssCallback { + /** + * Flags for the gnssSetCapabilities callback. + */ + @export(name = "", value_prefix = "GPS_CAPABILITY_") + enum Capabilities : @2.0::IGnssCallback.Capabilities { + /** + * GNSS supports measurement corrections + */ + ANTENNA_INFO = 1 << 11, + }; - /** Extends a GnssSvInfo, adding a basebandCN0DbHz. */ + /** + * Extends a GnssSvInfo, adding a basebandCN0DbHz. + */ struct GnssSvInfo { /** * GNSS satellite information for a single satellite and frequency. diff --git a/gnss/2.1/IGnssConfiguration.hal b/gnss/2.1/IGnssConfiguration.hal index 8360ba9953..550f3251df 100644 --- a/gnss/2.1/IGnssConfiguration.hal +++ b/gnss/2.1/IGnssConfiguration.hal @@ -65,4 +65,4 @@ interface IGnssConfiguration extends @2.0::IGnssConfiguration { * @return success Whether the HAL accepts and abides by the provided blacklist. */ setBlacklist_2_1(vec blacklist) generates (bool success); -}; \ No newline at end of file +}; diff --git a/gnss/2.1/IGnssMeasurement.hal b/gnss/2.1/IGnssMeasurement.hal index d2c76e6989..49ba7ebd2a 100644 --- a/gnss/2.1/IGnssMeasurement.hal +++ b/gnss/2.1/IGnssMeasurement.hal @@ -25,7 +25,6 @@ import IGnssMeasurementCallback; * Extended interface for GNSS Measurements support. */ interface IGnssMeasurement extends @2.0::IGnssMeasurement { - /** * Initializes the interface and registers the callback routines with the HAL. After a * successful call to 'setCallback_2_1' the HAL must begin to provide updates at an average @@ -47,5 +46,5 @@ interface IGnssMeasurement extends @2.0::IGnssMeasurement { * error code. */ setCallback_2_1(IGnssMeasurementCallback callback, bool enableFullTracking) - generates (GnssMeasurementStatus initRet); + generates (GnssMeasurementStatus initRet); }; diff --git a/gnss/2.1/IGnssMeasurementCallback.hal b/gnss/2.1/IGnssMeasurementCallback.hal index 0385abd467..1aee272fde 100644 --- a/gnss/2.1/IGnssMeasurementCallback.hal +++ b/gnss/2.1/IGnssMeasurementCallback.hal @@ -21,36 +21,56 @@ import @2.0::IGnssMeasurementCallback; import @2.0::ElapsedRealtime; import GnssSignalType; -/** The callback interface to report measurements from the HAL. */ +/** + * The callback interface to report measurements from the HAL. + */ interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback { - /** * Flags to indicate what fields in GnssMeasurement are valid. */ enum GnssMeasurementFlags : uint32_t { - /** A valid 'snr' is stored in the data structure. */ - HAS_SNR = 1 << 0, - /** A valid 'carrier frequency' is stored in the data structure. */ - HAS_CARRIER_FREQUENCY = 1 << 9, - /** A valid 'carrier cycles' is stored in the data structure. */ - HAS_CARRIER_CYCLES = 1 << 10, - /** A valid 'carrier phase' is stored in the data structure. */ - HAS_CARRIER_PHASE = 1 << 11, - /** A valid 'carrier phase uncertainty' is stored in the data structure. */ - HAS_CARRIER_PHASE_UNCERTAINTY = 1 << 12, - /** A valid automatic gain control is stored in the data structure. */ - HAS_AUTOMATIC_GAIN_CONTROL = 1 << 13, - /** A valid receiver inter-signal bias is stored in the data structure. */ - HAS_RECEIVER_ISB = 1 << 16, - /** A valid receiver inter-signal bias uncertainty is stored in the data structure. */ - HAS_RECEIVER_ISB_UNCERTAINTY = 1 << 17, - /** A valid satellite inter-signal bias is stored in the data structure. */ - HAS_SATELLITE_ISB = 1 << 18, - /** A valid satellite inter-signal bias uncertainty is stored in the data structure. */ - HAS_SATELLITE_ISB_UNCERTAINTY = 1 << 19 + /** + * A valid 'snr' is stored in the data structure. + */ + HAS_SNR = 1 << 0, + /** + * A valid 'carrier frequency' is stored in the data structure. + */ + HAS_CARRIER_FREQUENCY = 1 << 9, + /** + * A valid 'carrier cycles' is stored in the data structure. + */ + HAS_CARRIER_CYCLES = 1 << 10, + /** + * A valid 'carrier phase' is stored in the data structure. + */ + HAS_CARRIER_PHASE = 1 << 11, + /** + * A valid 'carrier phase uncertainty' is stored in the data structure. + */ + HAS_CARRIER_PHASE_UNCERTAINTY = 1 << 12, + /** + * A valid automatic gain control is stored in the data structure. + */ + HAS_AUTOMATIC_GAIN_CONTROL = 1 << 13, + /** + * A valid receiver inter-signal bias is stored in the data structure. + */ + HAS_RECEIVER_ISB = 1 << 16, + /** + * A valid receiver inter-signal bias uncertainty is stored in the data structure. + */ + HAS_RECEIVER_ISB_UNCERTAINTY = 1 << 17, + /** + * A valid satellite inter-signal bias is stored in the data structure. + */ + HAS_SATELLITE_ISB = 1 << 18, + /** + * A valid satellite inter-signal bias uncertainty is stored in the data structure. + */ + HAS_SATELLITE_ISB_UNCERTAINTY = 1 << 19, }; - /** * Extends a GNSS Measurement, adding basebandCN0DbHz, GnssMeasurementFlags, * receiverInterSignalBiasNs, receiverInterSignalBiasUncertaintyNs, satelliteInterSignalBiasNs @@ -160,10 +180,14 @@ interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback { * Complete set of GNSS Measurement data, same as 2.0 with additional fields in measurements. */ struct GnssData { - /** The full set of satellite measurement observations. */ + /** + * The full set of satellite measurement observations. + */ vec measurements; - /** The GNSS clock time reading. */ + /** + * The GNSS clock time reading. + */ GnssClock clock; /** diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp index 1f1078e398..c4dc8fd55d 100644 --- a/gnss/2.1/default/Android.bp +++ b/gnss/2.1/default/Android.bp @@ -22,6 +22,7 @@ cc_binary { vintf_fragments: ["android.hardware.gnss@2.1-service.xml"], srcs: [ "Gnss.cpp", + "GnssAntennaInfo.cpp", "GnssDebug.cpp", "GnssMeasurement.cpp", "GnssMeasurementCorrections.cpp", diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp index 679eb35804..c1af103f36 100644 --- a/gnss/2.1/default/Gnss.cpp +++ b/gnss/2.1/default/Gnss.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "Gnss" #include "Gnss.h" +#include "GnssAntennaInfo.h" #include "GnssDebug.h" #include "GnssMeasurement.h" #include "GnssMeasurementCorrections.h" @@ -334,9 +335,10 @@ Return Gnss::setCallback_2_1(const sp& callback) { sGnssCallback_2_1 = callback; - using Capabilities = V2_0::IGnssCallback::Capabilities; + using Capabilities = V2_1::IGnssCallback::Capabilities; const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS | - Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST; + Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST | + Capabilities::ANTENNA_INFO; auto ret = sGnssCallback_2_1->gnssSetCapabilitiesCb_2_0(capabilities); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); @@ -374,6 +376,11 @@ Gnss::getExtensionMeasurementCorrections_1_1() { return new GnssMeasurementCorrections(); } +Return> Gnss::getExtensionGnssAntennaInfo() { + ALOGD("Gnss::getExtensionGnssAntennaInfo"); + return new GnssAntennaInfo(); +} + void Gnss::reportSvStatus(const hidl_vec& svInfoList) const { std::unique_lock lock(mMutex); // TODO(skz): update this to call 2_0 callback if non-null diff --git a/gnss/2.1/default/Gnss.h b/gnss/2.1/default/Gnss.h index c47206a7a4..bd5e6e852c 100644 --- a/gnss/2.1/default/Gnss.h +++ b/gnss/2.1/default/Gnss.h @@ -22,6 +22,7 @@ #include #include #include +#include "GnssAntennaInfo.h" #include "GnssConfiguration.h" namespace android { @@ -91,6 +92,7 @@ struct Gnss : public IGnss { Return> getExtensionGnssConfiguration_2_1() override; Return> getExtensionMeasurementCorrections_1_1() override; + Return> getExtensionGnssAntennaInfo() override; private: void reportLocation(const V2_0::GnssLocation&) const; diff --git a/gnss/2.1/default/GnssAntennaInfo.cpp b/gnss/2.1/default/GnssAntennaInfo.cpp new file mode 100644 index 0000000000..d32a0afc48 --- /dev/null +++ b/gnss/2.1/default/GnssAntennaInfo.cpp @@ -0,0 +1,109 @@ +/* + * 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. + */ + +#define LOG_TAG "GnssAntennaInfo" + +#include "GnssAntennaInfo.h" +#include "Utils.h" + +#include + +using ::android::hardware::gnss::common::Utils; + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_1 { +namespace implementation { + +sp GnssAntennaInfo::sCallback = nullptr; + +GnssAntennaInfo::GnssAntennaInfo() : mMinIntervalMillis(1000) {} + +GnssAntennaInfo::~GnssAntennaInfo() { + stop(); +} + +// Methods from ::android::hardware::gnss::V2_1::IGnssAntennaInfo follow. +Return GnssAntennaInfo::setCallback( + const sp& callback) { + ALOGD("setCallback"); + std::unique_lock lock(mMutex); + sCallback = callback; + + if (mIsActive) { + ALOGW("GnssAntennaInfo callback already set. Resetting the callback..."); + stop(); + } + start(); + + return GnssAntennaInfoStatus::SUCCESS; +} + +Return GnssAntennaInfo::close() { + ALOGD("close"); + std::unique_lock lock(mMutex); + stop(); + sCallback = nullptr; + return Void(); +} + +// Private methods +void GnssAntennaInfo::start() { + ALOGD("start"); + mIsActive = true; + mThread = std::thread([this]() { + while (mIsActive == true) { + if (sCallback != nullptr) { + auto antennaInfos = Utils::getMockAntennaInfos(); + this->reportAntennaInfo(antennaInfos); + } + + /** For mock implementation this is good. On real device, we should only report + antennaInfo at start and when there is a configuration change. **/ + std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis)); + } + }); +} + +void GnssAntennaInfo::stop() { + ALOGD("stop"); + mIsActive = false; + if (mThread.joinable()) { + mThread.join(); + } +} + +void GnssAntennaInfo::reportAntennaInfo( + const hidl_vec& antennaInfo) const { + std::unique_lock lock(mMutex); + + if (sCallback == nullptr) { + ALOGE("%s: No non-null callback", __func__); + return; + } + + auto ret = sCallback->gnssAntennaInfoCb(antennaInfo); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +} // namespace implementation +} // namespace V2_1 +} // namespace gnss +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/gnss/2.1/default/GnssAntennaInfo.h b/gnss/2.1/default/GnssAntennaInfo.h new file mode 100644 index 0000000000..f4bfd24367 --- /dev/null +++ b/gnss/2.1/default/GnssAntennaInfo.h @@ -0,0 +1,63 @@ +/* + * 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_GNSS_V2_1_GNSSANTENNAINFO_H +#define ANDROID_HARDWARE_GNSS_V2_1_GNSSANTENNAINFO_H + +#include + +#include +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_1 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::Return; +using ::android::hardware::Void; + +struct GnssAntennaInfo : public IGnssAntennaInfo { + GnssAntennaInfo(); + ~GnssAntennaInfo(); + + // Methods from ::android::hardware::gnss::V2_1::IGnssAntennaInfo follow. + Return setCallback( + const sp& callback) override; + Return close() override; + + private: + void start(); + void stop(); + void reportAntennaInfo( + const hidl_vec& antennaInfo) const; + + static sp sCallback; + std::atomic mMinIntervalMillis; + std::atomic mIsActive; + std::thread mThread; + mutable std::mutex mMutex; +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H \ No newline at end of file diff --git a/gnss/2.1/vts/functional/gnss_hal_test.cpp b/gnss/2.1/vts/functional/gnss_hal_test.cpp index 93f89f54e0..83c4c3cd10 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test.cpp +++ b/gnss/2.1/vts/functional/gnss_hal_test.cpp @@ -262,4 +262,11 @@ Return GnssHalTest::GnssMeasurementCorrectionsCallback::setCapabilitiesCb( ALOGI("GnssMeasurementCorrectionsCallback capabilities received %d", capabilities); capabilities_cbq_.store(capabilities); return Void(); +} + +Return GnssHalTest::GnssAntennaInfoCallback::gnssAntennaInfoCb( + const hidl_vec& gnssAntennaInfos) { + ALOGD("GnssAntennaInfo v2.1 received. Size = %d", (int)gnssAntennaInfos.size()); + antenna_info_cbq_.store(gnssAntennaInfos); + return Void(); } \ No newline at end of file diff --git a/gnss/2.1/vts/functional/gnss_hal_test.h b/gnss/2.1/vts/functional/gnss_hal_test.h index b99cf2322a..3472edb907 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test.h +++ b/gnss/2.1/vts/functional/gnss_hal_test.h @@ -31,6 +31,8 @@ using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrec using android::hardware::gnss::V1_0::GnssLocationFlags; using android::hardware::gnss::V2_0::GnssConstellationType; using android::hardware::gnss::V2_1::IGnss; +using android::hardware::gnss::V2_1::IGnssAntennaInfo; +using android::hardware::gnss::V2_1::IGnssAntennaInfoCallback; using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation; using GnssLocation_2_0 = android::hardware::gnss::V2_0::GnssLocation; @@ -152,6 +154,20 @@ class GnssHalTest : public testing::TestWithParam { Return setCapabilitiesCb(uint32_t capabilities) override; }; + /* Callback class for GnssAntennaInfo. */ + class GnssAntennaInfoCallback : public IGnssAntennaInfoCallback { + public: + GnssCallbackEventQueue> + antenna_info_cbq_; + + GnssAntennaInfoCallback() : antenna_info_cbq_("info"){}; + virtual ~GnssAntennaInfoCallback() = default; + + // Methods from V2_1::GnssAntennaInfoCallback follow. + Return gnssAntennaInfoCb( + const hidl_vec& gnssAntennaInfos); + }; + /* * SetUpGnssCallback: * Set GnssCallback and verify the result. diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp index 9ac9436b0d..7b054c0033 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp @@ -139,7 +139,7 @@ TEST_P(GnssHalTest, TestGnssMeasurementFields) { std::string codeType = lastMeasurement.clock.referenceSignalTypeForIsb.codeType; ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN && - referenceConstellation >= GnssConstellationType::IRNSS); + referenceConstellation <= GnssConstellationType::IRNSS); ASSERT_TRUE(carrierFrequencyHz > 0); ASSERT_TRUE(codeType != ""); @@ -153,6 +153,85 @@ TEST_P(GnssHalTest, TestGnssMeasurementFields) { iGnssMeasurement->close(); } +/* + * TestGnssAntennaInfo: + * Sets a GnssAntennaInfoCallback, waits for report, and verifies + * 1. phaseCenterOffsetCoordinateMillimeters is valid + * 2. phaseCenterOffsetCoordinateUncertaintyMillimeters is valid. + * PhaseCenterVariationCorrections and SignalGainCorrections are optional. + */ +TEST_P(GnssHalTest, TestGnssAntennaInfo) { + const int kAntennaInfoTimeoutSeconds = 2; + + auto gnssAntennaInfo = gnss_hal_->getExtensionGnssAntennaInfo(); + ASSERT_TRUE(gnssAntennaInfo.isOk()); + + // Skip test if GnssAntennaInfo v2.1 is not supported + sp iGnssAntennaInfo = gnssAntennaInfo; + if (!(gnss_cb_->last_capabilities_ & IGnssCallback_2_1::Capabilities::ANTENNA_INFO) || + iGnssAntennaInfo == nullptr) { + ALOGD("GnssAntennaInfo v2.1 is not supported."); + return; + } + + sp callback = new GnssAntennaInfoCallback(); + auto result = iGnssAntennaInfo->setCallback(callback); + ASSERT_TRUE(result.isOk()); + EXPECT_EQ(result, IGnssAntennaInfo::GnssAntennaInfoStatus::SUCCESS); + + hidl_vec antennaInfos; + ASSERT_TRUE(callback->antenna_info_cbq_.retrieve(antennaInfos, kAntennaInfoTimeoutSeconds)); + EXPECT_EQ(callback->antenna_info_cbq_.calledCount(), 1); + ASSERT_TRUE(antennaInfos.size() > 0); + + for (auto antennaInfo : antennaInfos) { + // Remaining fields are optional + if (antennaInfo.phaseCenterVariationCorrectionMillimeters != NULL) { + int numRows = antennaInfo.phaseCenterVariationCorrectionMillimeters.size(); + int numColumns = antennaInfo.phaseCenterVariationCorrectionMillimeters[0].row.size(); + // Must have at least 1 row and 2 columns + ASSERT_TRUE(numRows >= 1 && numColumns >= 2); + + // Corrections and uncertainties must have same dimensions + ASSERT_TRUE(antennaInfo.phaseCenterVariationCorrectionMillimeters.size() == + antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters.size()); + ASSERT_TRUE( + antennaInfo.phaseCenterVariationCorrectionMillimeters[0].row.size() == + antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters[0].row.size()); + + // Must be rectangular + for (auto row : antennaInfo.phaseCenterVariationCorrectionMillimeters) { + ASSERT_TRUE(row.row.size() == numColumns); + } + for (auto row : antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters) { + ASSERT_TRUE(row.row.size() == numColumns); + } + } + if (antennaInfo.signalGainCorrectionDbi != NULL) { + int numRows = antennaInfo.signalGainCorrectionDbi.size(); + int numColumns = antennaInfo.signalGainCorrectionUncertaintyDbi[0].row.size(); + // Must have at least 1 row and 2 columns + ASSERT_TRUE(numRows >= 1 && numColumns >= 2); + + // Corrections and uncertainties must have same dimensions + ASSERT_TRUE(antennaInfo.signalGainCorrectionDbi.size() == + antennaInfo.signalGainCorrectionUncertaintyDbi.size()); + ASSERT_TRUE(antennaInfo.signalGainCorrectionDbi[0].row.size() == + antennaInfo.signalGainCorrectionUncertaintyDbi[0].row.size()); + + // Must be rectangular + for (auto row : antennaInfo.signalGainCorrectionDbi) { + ASSERT_TRUE(row.row.size() == numColumns); + } + for (auto row : antennaInfo.signalGainCorrectionUncertaintyDbi) { + ASSERT_TRUE(row.row.size() == numColumns); + } + } + } + + iGnssAntennaInfo->close(); +} + /* * TestGnssSvInfoFields: * Gets 1 location and a GnssSvInfo, and verifies diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp index 0cdc865849..2e5b87330f 100644 --- a/gnss/common/utils/default/Utils.cpp +++ b/gnss/common/utils/default/Utils.cpp @@ -235,6 +235,58 @@ GnssSvInfoV1_0 Utils::getMockSvInfoV1_0(int16_t svid, V1_0::GnssConstellationTyp return svInfo; } +hidl_vec Utils::getMockAntennaInfos() { + GnssAntennaInfo mockAntennaInfo_1 = { + .carrierFrequencyMHz = 123412.12, + .phaseCenterOffsetCoordinateMillimeters = Coord{.x = 1, + .xUncertainty = 0.1, + .y = 2, + .yUncertainty = 0.1, + .z = 3, + .zUncertainty = 0.1}, + .phaseCenterVariationCorrectionMillimeters = + { + Row{hidl_vec{1, -1, 5, -2, 3, -1}}, + Row{hidl_vec{-2, 3, 2, 0, 1, 2}}, + Row{hidl_vec{1, 3, 2, -1, -3, 5}}, + }, + .phaseCenterVariationCorrectionUncertaintyMillimeters = + { + Row{hidl_vec{0.1, 0.2, 0.4, 0.1, 0.2, 0.3}}, + Row{hidl_vec{0.3, 0.2, 0.3, 0.6, 0.1, 0.1}}, + Row{hidl_vec{0.1, 0.1, 0.4, 0.2, 0.5, 0.3}}, + }, + .signalGainCorrectionDbi = + { + Row{hidl_vec{2, -3, 1, -3, 0, -4}}, + Row{hidl_vec{1, 0, -4, 1, 3, -2}}, + Row{hidl_vec{3, -2, 0, -2, 3, 0}}, + }, + .signalGainCorrectionUncertaintyDbi = + { + Row{hidl_vec{0.3, 0.1, 0.2, 0.6, 0.1, 0.3}}, + Row{hidl_vec{0.1, 0.1, 0.5, 0.2, 0.3, 0.1}}, + Row{hidl_vec{0.2, 0.4, 0.2, 0.1, 0.1, 0.2}}, + }, + }; + + GnssAntennaInfo mockAntennaInfo_2 = { + .carrierFrequencyMHz = 532324.23, + .phaseCenterOffsetCoordinateMillimeters = Coord{.x = 5, + .xUncertainty = 0.1, + .y = 6, + .yUncertainty = 0.1, + .z = 7, + .zUncertainty = 0.1}, + }; + + hidl_vec mockAntennaInfos = { + mockAntennaInfo_1, + mockAntennaInfo_2, + }; + return mockAntennaInfos; +} + } // namespace common } // namespace gnss } // namespace hardware diff --git a/gnss/common/utils/default/include/Utils.h b/gnss/common/utils/default/include/Utils.h index e0c61a41e1..d9ad5a5a66 100644 --- a/gnss/common/utils/default/include/Utils.h +++ b/gnss/common/utils/default/include/Utils.h @@ -33,6 +33,9 @@ using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData; using GnssSvInfoV1_0 = V1_0::IGnssCallback::GnssSvInfo; using GnssSvInfoV2_0 = V2_0::IGnssCallback::GnssSvInfo; using GnssSvInfoV2_1 = V2_1::IGnssCallback::GnssSvInfo; +using GnssAntennaInfo = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo; +using Row = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::Row; +using Coord = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::Coord; struct Utils { static GnssDataV2_0 getMockMeasurementV2_0(); @@ -46,6 +49,7 @@ struct Utils { static GnssSvInfoV1_0 getMockSvInfoV1_0(int16_t svid, V1_0::GnssConstellationType type, float cN0DbHz, float elevationDegrees, float azimuthDegrees); + static hidl_vec getMockAntennaInfos(); }; } // namespace common From 188a8f90f0626d88490fcdf0476839212b7aa55f Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Thu, 30 Jan 2020 17:40:13 +0000 Subject: [PATCH 0568/1022] NNAPI: Add state outputs for {UNI|BI}DIRECTIONAL_SEQUENCE_{RNN|LSTM} Fix: 138443991 Test: NNTest_static and VtsHalNeuralnetworksV1_3TargetTest Change-Id: I0a3af22826d438f6f38de1f64042a50f98265e2d --- current.txt | 2 +- neuralnetworks/1.3/types.hal | 49 +++++++++++++++++++ .../1.3/vts/functional/ValidateModel.cpp | 12 +++-- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/current.txt b/current.txt index 62b9877829..f841866fc9 100644 --- a/current.txt +++ b/current.txt @@ -673,7 +673,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 2fa3679ad7c94b5e88724adcd560c561041068a4ca565c63830e68101988746a android.hardware.neuralnetworks@1.3::IFencedExecutionCallback 237b23b126a66f3432658020fed78cdd06ba6297459436fe6bae0ba753370833 android.hardware.neuralnetworks@1.3::IPreparedModel 0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback -abbc4e1a969881c9f8ab587add5b5e75b08df834c9c969c013ae38cb4bb16f6a android.hardware.neuralnetworks@1.3::types +2fabd246f985d94a0172dacefb0d6cf19e2aeb2d5f17752653988ef39570a52d android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index c5dc08c338..530f9849fa 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -2556,6 +2556,30 @@ enum OperationType : int32_t { * A 3-D tensor of shape: * If time-major: [max_time, batch_size, bw_output_size] * If batch-major: [batch_size, max_time, bw_output_size] + * * 2: The forward activation state output. + * A 2-D tensor of shape [batch_size, fw_output_size] containing an + * activation state from the last time step in the sequence. This + * output is optional and can be omitted. If this output is present + * then outputs 3-5 must be present as well. + * Available since HAL version 1.3. + * * 3: The forward cell state output. + * A tensor of shape [batch_size, fw_cell_size] containing a cell state + * from the last time step in the sequence. This output is optional + * and can be omitted. If this output is present + * then outputs 2, 4, 5 must be present as well. + * Available since HAL version 1.3. + * * 4: The backward activation state output. + * A 2-D tensor of shape [batch_size, bw_output_size] containing an + * activation state from the last time step in the sequence. This + * output is optional and can be omitted. If this output is present + * then outputs 2, 3, 5 must be present as well. + * Available since HAL version 1.3. + * * 5: The backward cell state output. + * A tensor of shape [batch_size, bw_cell_size] containing a cell state + * from the last time step in the sequence. This output is optional + * and can be omitted. If this output is present + * then outputs 2-4 must be present as well. + * Available since HAL version 1.3. */ BIDIRECTIONAL_SEQUENCE_LSTM = @1.2::OperationType:BIDIRECTIONAL_SEQUENCE_LSTM, @@ -2673,6 +2697,18 @@ enum OperationType : int32_t { * (timeMajor). If it is set to true, then the shape is set to * [maxTime, batchSize, bwNumUnits], otherwise the shape is set to * [batchSize, maxTime, bwNumUnits]. + * * 2: The forward hidden state output. + * A 2-D tensor of shape [batchSize, fwNumUnits] containing a hidden + * state from the last time step in the sequence. This output is + * optional and can be omitted. If this output is present then output + * 3 must be present as well. + * Available since HAL version 1.3. + * * 3: The backward hidden state output. + * A 2-D tensor of shape [batchSize, bwNumUnits] containing a hidden + * state from the last time step in the sequence. This output is + * optional and can be omitted. If this output is present then output + * 2 must be present as well. + * Available since HAL version 1.3. */ BIDIRECTIONAL_SEQUENCE_RNN = @1.2::OperationType:BIDIRECTIONAL_SEQUENCE_RNN, @@ -4656,6 +4692,15 @@ enum OperationType : int32_t { * A 3-D tensor of shape: * If time-major: [max_time, batch_size, output_size] * If batch-major: [batch_size, max_time, output_size] + * * 1: A tensor of shape [batch_size, output_size] containing a hidden + * state from the last time step in the sequence. This output is + * optional and can be omitted. If this output is present then + * output #2 must be present as well. + * Available since HAL version 1.3. + * * 2: A tensor of shape [batch_size, cell_size] containing a cell state + * from the last time step in the sequence. This output is optional + * and can be omitted. + * Available since HAL version 1.3. */ UNIDIRECTIONAL_SEQUENCE_LSTM = @1.2::OperationType:UNIDIRECTIONAL_SEQUENCE_LSTM, @@ -4711,6 +4756,10 @@ enum OperationType : int32_t { * it is set to 1, then the output has a shape [maxTime, batchSize, * numUnits], otherwise the output has a shape [batchSize, maxTime, * numUnits]. + * * 1: A tensor of shape [batchSize, numUnits] containing hidden state + * from the last time step in the sequence. This output is optional + * and can be omitted. + * Available since HAL version 1.3. */ UNIDIRECTIONAL_SEQUENCE_RNN = @1.2::OperationType:UNIDIRECTIONAL_SEQUENCE_RNN, diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 0a35e2d233..b9ea430694 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -527,9 +527,15 @@ static bool removeOperandSkip(size_t operand, const Model& model) { } } } - // BIDIRECTIONAL_SEQUENCE_LSTM and BIDIRECTIONAL_SEQUENCE_RNN can have either one or two - // outputs depending on their mergeOutputs parameter. - if (operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_LSTM || + // BIDIRECTIONAL_SEQUENCE_LSTM and BIDIRECTIONAL_SEQUENCE_RNN can have + // either one, two, three or four outputs depending on their + // mergeOutputs parameter and if state outputs are provided. + // UNIDIRECTIONAL_SEQUENCE_LSTM and UNIDIRECTIONAL_SEQUENCE_RNN can have + // either one or three outputs depending on whether state outputs are + // provided. + if (operation.type == OperationType::UNIDIRECTIONAL_SEQUENCE_LSTM || + operation.type == OperationType::UNIDIRECTIONAL_SEQUENCE_RNN || + operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_LSTM || operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_RNN) { for (const size_t outOprand : operation.outputs) { if (operand == outOprand) { From fec7c4e0a054dc5c2a5732ca907d77e7edb2e236 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Tue, 11 Feb 2020 12:05:46 -0800 Subject: [PATCH 0569/1022] HAL changes for 1.5 setLinkCapacityReportingCriteria Add to IRadio, IRadioResponse, and VTS Test: make cf_x86_phone-userdebug && mm Bug: 149112073 Change-Id: I330d5be6bf531c93439f8f1d55718f71ec46c1c3 --- current.txt | 6 +- radio/1.5/IRadio.hal | 29 ++++++ radio/1.5/IRadioResponse.hal | 11 +++ radio/1.5/types.hal | 3 +- .../1.5/vts/functional/radio_hidl_hal_api.cpp | 93 +++++++++++++++++++ .../functional/radio_hidl_hal_utils_v1_5.h | 2 + radio/1.5/vts/functional/radio_response.cpp | 7 ++ 7 files changed, 147 insertions(+), 4 deletions(-) diff --git a/current.txt b/current.txt index 62b9877829..8deeca56bd 100644 --- a/current.txt +++ b/current.txt @@ -682,10 +682,10 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback 62cf050c593c1ec34b49178b5bdde72dd9b80d9bad3eb184e4f0cd564d28678c android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types -e1d34b83188a8ef3c507ec53c0ebcf714863c746da7f4a05460453f7c4c09389 android.hardware.radio@1.5::types -8062d0a1a03594dd8b448adcf6f08856b5720f7e33f9b785a21d3ef74a4f211d android.hardware.radio@1.5::IRadio +99f5c26b952271d1246c957e1d0271fa39445ee65cc93aa7c187834f98914a33 android.hardware.radio@1.5::types +7fefa2cc5b3b3be10b5cff5c5dc195385f491d4bf23ca65f9c6b3c30c8753a33 android.hardware.radio@1.5::IRadio e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication -c8a8e4c3998ebdf1c71ece2d3ecb033ae17798830bed4b30a53e5991aa219e3a android.hardware.radio@1.5::IRadioResponse +829d3827eeb5a8f563e80fe627419b3231012fc02bc2e79782ec5e9ad9f799a4 android.hardware.radio@1.5::IRadioResponse dcc8872337f0135e81970e1d8d5fd7139160dc80e9be76f0ae05290fa7e472b8 android.hardware.radio.config@1.3::types a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal index 2ec92e54d1..0b50436ff9 100644 --- a/radio/1.5/IRadio.hal +++ b/radio/1.5/IRadio.hal @@ -68,6 +68,35 @@ interface IRadio extends @1.4::IRadio { oneway setSignalStrengthReportingCriteria_1_5(int32_t serial, SignalThresholdInfo signalThresholdInfo, AccessNetwork accessNetwork); + /** + * Sets the link capacity reporting criteria. + * + * The resulting reporting criteria are the AND of all the supplied criteria. + * + * Note: Reporting criteria must be individually set for each RAN. If unset, reporting criteria + * for that RAN are implementation-defined. + * + * Response callback is IRadioResponse.setLinkCapacityReportingCriteriaResponse_1_5(). + * + * @param serial Serial number of request. + * @param hysteresisMs A hysteresis time in milliseconds to prevent flapping. A value of 0 + * disables hysteresis. + * @param hysteresisDlKbps An interval in kbps defining the required magnitude change between DL + * reports. hysteresisDlKbps must be smaller than the smallest threshold delta. A value of 0 + * disables hysteresis. + * @param hysteresisUlKbps An interval in kbps defining the required magnitude change between UL + * reports. hysteresisUlKbps must be smaller than the smallest threshold delta. A value of 0 + * disables hysteresis. + * @param thresholdsDownlinkKbps A vector of trigger thresholds in kbps for downlink reports. A + * vector size of 0 disables the use of DL thresholds for reporting. + * @param thresholdsUplinkKbps A vector of trigger thresholds in kbps for uplink reports. A + * vector size of 0 disables the use of UL thresholds for reporting. + * @param accessNetwork The type of network for which to apply these thresholds. + */ + oneway setLinkCapacityReportingCriteria_1_5(int32_t serial, int32_t hysteresisMs, + int32_t hysteresisDlKbps, int32_t hysteresisUlKbps, vec thresholdsDownlinkKbps, + vec thresholdsUplinkKbps, AccessNetwork accessNetwork); + /** * Enable or disable UiccApplications on the SIM. If disabled: * - Modem will not register on any network. diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal index 543f9b59b2..e87cad25fc 100644 --- a/radio/1.5/IRadioResponse.hal +++ b/radio/1.5/IRadioResponse.hal @@ -40,6 +40,17 @@ interface IRadioResponse extends @1.4::IRadioResponse { */ oneway setSignalStrengthReportingCriteriaResponse_1_5(RadioResponseInfo info); + /** + * @param info Response info struct containing response type, serial no. and error + * + * Valid errors returned: + * RadioError:NONE + * RadioError:INVALID_ARGUMENTS + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:INTERNAL_ERR + */ + oneway setLinkCapacityReportingCriteriaResponse_1_5(RadioResponseInfo info); + /** * @param info Response info struct containing response type, serial no. and error * diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index 448e5c830e..4d3c2d550c 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -156,7 +156,8 @@ struct SignalThresholdInfo { enum AccessNetwork : @1.4::AccessNetwork { /** - * Next-Generation Radio Access Network (NGRAN) + * Next-Generation Radio Access Network (NGRAN). + * Note NGRAN is only for standalone mode. Non-standalone mode uses AccessNetwork EUTRAN. */ NGRAN = 6, }; diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp index 621825fa52..3678aefa9b 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp @@ -309,6 +309,99 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR) ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE})); } +/* + * Test IRadio.setLinkCapacityReportingCriteria_1_5() invalid hysteresisDlKbps + */ +TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_invalidHysteresisDlKbps) { + serial = GetRandomSerialNumber(); + + Return res = radio_v1_5->setLinkCapacityReportingCriteria_1_5( + serial, 5000, + 5000, // hysteresisDlKbps too big for thresholds delta + 100, {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, + ::android::hardware::radio::V1_5::AccessNetwork::GERAN); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + ALOGI("setLinkCapacityReportingCriteria_1_5_invalidHysteresisDlKbps, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria_1_5() may not be supported + // for GERAN + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); +} + +/* + * Test IRadio.setLinkCapacityReportingCriteria_1_5() invalid hysteresisUlKbps + */ +TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_invalidHysteresisUlKbps) { + serial = GetRandomSerialNumber(); + + Return res = radio_v1_5->setLinkCapacityReportingCriteria_1_5( + serial, 5000, 500, + 1000, // hysteresisUlKbps too big for thresholds delta + {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, + ::android::hardware::radio::V1_5::AccessNetwork::GERAN); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + ALOGI("setLinkCapacityReportingCriteria_1_5_invalidHysteresisUlKbps, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria_1_5() may not be supported + // for GERAN + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); +} + +/* + * Test IRadio.setLinkCapacityReportingCriteria_1_5() empty params + */ +TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_emptyParams) { + serial = GetRandomSerialNumber(); + + Return res = radio_v1_5->setLinkCapacityReportingCriteria_1_5( + serial, 0, 0, 0, {}, {}, ::android::hardware::radio::V1_5::AccessNetwork::GERAN); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + ALOGI("setLinkCapacityReportingCriteria_1_5_emptyParams, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria_1_5() may not be supported + // for GERAN + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED})); +} + +/* + * Test IRadio.setLinkCapacityReportingCriteria_1_5() for GERAN + */ +TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_Geran) { + serial = GetRandomSerialNumber(); + + Return res = radio_v1_5->setLinkCapacityReportingCriteria_1_5( + serial, 5000, 500, 100, {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, + ::android::hardware::radio::V1_5::AccessNetwork::GERAN); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); + + ALOGI("setLinkCapacityReportingCriteria_1_5_Geran, rspInfo.error = %s\n", + toString(radioRsp_v1_5->rspInfo.error).c_str()); + // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria_1_5() may not be supported + // for GERAN + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, + {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED})); +} + /* * Test IRadio.enableUiccApplications() for the response returned. * For SIM ABSENT case. diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index 6f65cbbdf2..5ce9767345 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -531,6 +531,8 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon /* 1.5 Api */ Return setSignalStrengthReportingCriteriaResponse_1_5(const RadioResponseInfo& info); + Return setLinkCapacityReportingCriteriaResponse_1_5(const RadioResponseInfo& info); + Return enableUiccApplicationsResponse(const RadioResponseInfo& info); Return areUiccApplicationsEnabledResponse(const RadioResponseInfo& info, bool enabled); diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp index 17b294bbcd..1ab106a474 100644 --- a/radio/1.5/vts/functional/radio_response.cpp +++ b/radio/1.5/vts/functional/radio_response.cpp @@ -894,6 +894,13 @@ Return RadioResponse_v1_5::setSignalStrengthReportingCriteriaResponse_1_5( return Void(); } +Return RadioResponse_v1_5::setLinkCapacityReportingCriteriaResponse_1_5( + const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + Return RadioResponse_v1_5::enableUiccApplicationsResponse(const RadioResponseInfo& info) { rspInfo = info; parent_v1_5.notify(info.serial); From 8a9b3065711c7493d9144c6e196a792c4cc01267 Mon Sep 17 00:00:00 2001 From: Slava Shklyaev Date: Tue, 21 Jan 2020 11:38:47 +0000 Subject: [PATCH 0570/1022] Add control flow performance to NNAPI Capabilities Bug: 139181916 Test: m Change-Id: I62696a6519191e33568c9664c0047fb57426b99f --- current.txt | 2 +- neuralnetworks/1.3/types.hal | 29 +++++++++++++++++-- neuralnetworks/1.3/types.t | 29 +++++++++++++++++-- .../1.3/vts/functional/BasicTests.cpp | 5 ++++ 4 files changed, 58 insertions(+), 7 deletions(-) diff --git a/current.txt b/current.txt index f6659e3273..c74c46290d 100644 --- a/current.txt +++ b/current.txt @@ -675,7 +675,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 2fa3679ad7c94b5e88724adcd560c561041068a4ca565c63830e68101988746a android.hardware.neuralnetworks@1.3::IFencedExecutionCallback 237b23b126a66f3432658020fed78cdd06ba6297459436fe6bae0ba753370833 android.hardware.neuralnetworks@1.3::IPreparedModel 0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback -2fabd246f985d94a0172dacefb0d6cf19e2aeb2d5f17752653988ef39570a52d android.hardware.neuralnetworks@1.3::types +5e2a14b40dc11da9d478185838f4401b652739922d14cecea0a0ce4c1359fe21 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index 530f9849fa..8ee867c676 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -5176,8 +5176,10 @@ enum Priority : int32_t { /** * The capabilities of a driver. * - * Performance of an operation comes from the type of its first operand. - * This represents performance for non extension operand types. + * This represents performance of non-extension operations. + * + * Performance of an operation other than {@link OperationType::IF} and + * {@link OperationType::WHILE} comes from the type of its first operand. */ struct Capabilities { /** @@ -5200,11 +5202,32 @@ struct Capabilities { /** * Performance by operand type. Must be sorted by OperandType. - * If a particular OperandType is not present in operandPerformance, + * + * If a particular {@link OperandType} is not present in operandPerformance, * its performance is treated as * { .execTime = FLT_MAX, .powerUsage = FLT_MAX }. + * + * Performance does not apply to {@link OperandType::SUBGRAPH}, and a driver + * must not report operand performance for {@link OperandType::SUBGRAPH}. */ vec operandPerformance; + + /** + * Performance of an {@link OperationType::IF} operation is the sum of + * {@link Capabilities::ifPerformance} and the mean of performance for the + * two branch subgraphs, where performance for a subgraph is the sum of the + * performance of all operations within the subgraph. + */ + PerformanceInfo ifPerformance; + + /** + * Performance of a {@link OperationType::WHILE} operation is the sum of + * {@link Capabilities::whilePerformance}, performance for the condition + * subgraph and performance for the body subgraph, where performance for a + * subgraph is the sum of the performance of all operations within the + * subgraph. + */ + PerformanceInfo whilePerformance; }; /** diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t index 3d0d02df46..c663a60dee 100644 --- a/neuralnetworks/1.3/types.t +++ b/neuralnetworks/1.3/types.t @@ -103,8 +103,10 @@ enum Priority : int32_t { /** * The capabilities of a driver. * - * Performance of an operation comes from the type of its first operand. - * This represents performance for non extension operand types. + * This represents performance of non-extension operations. + * + * Performance of an operation other than {@link OperationType::IF} and + * {@link OperationType::WHILE} comes from the type of its first operand. */ struct Capabilities { /** @@ -127,11 +129,32 @@ struct Capabilities { /** * Performance by operand type. Must be sorted by OperandType. - * If a particular OperandType is not present in operandPerformance, + * + * If a particular {@link OperandType} is not present in operandPerformance, * its performance is treated as * { .execTime = FLT_MAX, .powerUsage = FLT_MAX }. + * + * Performance does not apply to {@link OperandType::SUBGRAPH}, and a driver + * must not report operand performance for {@link OperandType::SUBGRAPH}. */ vec operandPerformance; + + /** + * Performance of an {@link OperationType::IF} operation is the sum of + * {@link Capabilities::ifPerformance} and the mean of performance for the + * two branch subgraphs, where performance for a subgraph is the sum of the + * performance of all operations within the subgraph. + */ + PerformanceInfo ifPerformance; + + /** + * Performance of a {@link OperationType::WHILE} operation is the sum of + * {@link Capabilities::whilePerformance}, performance for the condition + * subgraph and performance for the body subgraph, where performance for a + * subgraph is the sum of the performance of all operations within the + * subgraph. + */ + PerformanceInfo whilePerformance; }; /** diff --git a/neuralnetworks/1.3/vts/functional/BasicTests.cpp b/neuralnetworks/1.3/vts/functional/BasicTests.cpp index 891850cfa4..1c2536983e 100644 --- a/neuralnetworks/1.3/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.3/vts/functional/BasicTests.cpp @@ -57,6 +57,11 @@ TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) { [](const OperandPerformance& a, const OperandPerformance& b) { return a.type < b.type; })); + EXPECT_TRUE(std::all_of(opPerf.begin(), opPerf.end(), [](const OperandPerformance& a) { + return a.type != OperandType::SUBGRAPH; + })); + EXPECT_TRUE(isPositive(capabilities.ifPerformance)); + EXPECT_TRUE(isPositive(capabilities.whilePerformance)); }); EXPECT_TRUE(ret.isOk()); } From 1f98e2e9292faf4c2a28a4558a303492d4f7eefe Mon Sep 17 00:00:00 2001 From: Slava Shklyaev Date: Fri, 31 Jan 2020 15:14:24 +0000 Subject: [PATCH 0571/1022] Add control flow support to NNAPI VTS tests See change I98a3edd1. Bug: 148077633 Bug: 148601177 Bug: 136735929 Test: VtsHalNeuralnetworksV1_0TargetTest Test: VtsHalNeuralnetworksV1_1TargetTest Test: VtsHalNeuralnetworksV1_2TargetTest Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: I1e436cdba404b68026a45797ac4fb3a34f8be76a --- .../vts/functional/GeneratedTestHarness.cpp | 25 +-- neuralnetworks/1.0/vts/functional/Utils.cpp | 16 +- .../vts/functional/GeneratedTestHarness.cpp | 25 +-- .../functional/CompilationCachingTests.cpp | 8 +- .../vts/functional/GeneratedTestHarness.cpp | 35 +++-- .../functional/CompilationCachingTests.cpp | 8 +- .../vts/functional/GeneratedTestHarness.cpp | 145 +++++++++++------- .../vts/functional/QualityOfServiceTests.cpp | 5 +- .../1.3/vts/functional/ValidateModel.cpp | 2 + 9 files changed, 155 insertions(+), 114 deletions(-) diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp index 595ad85633..e28605dca2 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp @@ -42,10 +42,11 @@ using implementation::PreparedModelCallback; Model createModel(const TestModel& testModel) { // Model operands. - hidl_vec operands(testModel.operands.size()); + CHECK_EQ(testModel.referenced.size(), 0u); // Not supported in 1.0. + hidl_vec operands(testModel.main.operands.size()); size_t constCopySize = 0, constRefSize = 0; - for (uint32_t i = 0; i < testModel.operands.size(); i++) { - const auto& op = testModel.operands[i]; + for (uint32_t i = 0; i < testModel.main.operands.size(); i++) { + const auto& op = testModel.main.operands[i]; DataLocation loc = {}; if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { @@ -70,9 +71,9 @@ Model createModel(const TestModel& testModel) { } // Model operations. - hidl_vec operations(testModel.operations.size()); - std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(), - [](const TestOperation& op) -> Operation { + hidl_vec operations(testModel.main.operations.size()); + std::transform(testModel.main.operations.begin(), testModel.main.operations.end(), + operations.begin(), [](const TestOperation& op) -> Operation { return {.type = static_cast(op.type), .inputs = op.inputs, .outputs = op.outputs}; @@ -80,8 +81,8 @@ Model createModel(const TestModel& testModel) { // Constant copies. hidl_vec operandValues(constCopySize); - for (uint32_t i = 0; i < testModel.operands.size(); i++) { - const auto& op = testModel.operands[i]; + for (uint32_t i = 0; i < testModel.main.operands.size(); i++) { + const auto& op = testModel.main.operands[i]; if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { const uint8_t* begin = op.data.get(); const uint8_t* end = begin + op.data.size(); @@ -102,8 +103,8 @@ Model createModel(const TestModel& testModel) { reinterpret_cast(static_cast(mappedMemory->getPointer())); CHECK(mappedPtr != nullptr); - for (uint32_t i = 0; i < testModel.operands.size(); i++) { - const auto& op = testModel.operands[i]; + for (uint32_t i = 0; i < testModel.main.operands.size(); i++) { + const auto& op = testModel.main.operands[i]; if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) { const uint8_t* begin = op.data.get(); const uint8_t* end = begin + op.data.size(); @@ -114,8 +115,8 @@ Model createModel(const TestModel& testModel) { return {.operands = std::move(operands), .operations = std::move(operations), - .inputIndexes = testModel.inputIndexes, - .outputIndexes = testModel.outputIndexes, + .inputIndexes = testModel.main.inputIndexes, + .outputIndexes = testModel.main.outputIndexes, .operandValues = std::move(operandValues), .pools = std::move(pools)}; } diff --git a/neuralnetworks/1.0/vts/functional/Utils.cpp b/neuralnetworks/1.0/vts/functional/Utils.cpp index 5b630fd7a6..0dba85acd9 100644 --- a/neuralnetworks/1.0/vts/functional/Utils.cpp +++ b/neuralnetworks/1.0/vts/functional/Utils.cpp @@ -42,10 +42,10 @@ constexpr uint32_t kOutputPoolIndex = 1; Request createRequest(const TestModel& testModel) { // Model inputs. - hidl_vec inputs(testModel.inputIndexes.size()); + hidl_vec inputs(testModel.main.inputIndexes.size()); size_t inputSize = 0; - for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) { - const auto& op = testModel.operands[testModel.inputIndexes[i]]; + for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) { + const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]]; if (op.data.size() == 0) { // Omitted input. inputs[i] = {.hasNoValue = true}; @@ -59,10 +59,10 @@ Request createRequest(const TestModel& testModel) { } // Model outputs. - hidl_vec outputs(testModel.outputIndexes.size()); + hidl_vec outputs(testModel.main.outputIndexes.size()); size_t outputSize = 0; - for (uint32_t i = 0; i < testModel.outputIndexes.size(); i++) { - const auto& op = testModel.operands[testModel.outputIndexes[i]]; + for (uint32_t i = 0; i < testModel.main.outputIndexes.size(); i++) { + const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]]; // In the case of zero-sized output, we should at least provide a one-byte buffer. // This is because zero-sized tensors are only supported internally to the driver, or @@ -90,8 +90,8 @@ Request createRequest(const TestModel& testModel) { CHECK(inputPtr != nullptr); // Copy input data to the memory pool. - for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) { - const auto& op = testModel.operands[testModel.inputIndexes[i]]; + for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) { + const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]]; if (op.data.size() > 0) { const uint8_t* begin = op.data.get(); const uint8_t* end = begin + op.data.size(); diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp index 7a929d6063..cee15a35a1 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp @@ -49,10 +49,11 @@ using V1_0::implementation::PreparedModelCallback; Model createModel(const TestModel& testModel) { // Model operands. - hidl_vec operands(testModel.operands.size()); + CHECK_EQ(testModel.referenced.size(), 0u); // Not supported in 1.1. + hidl_vec operands(testModel.main.operands.size()); size_t constCopySize = 0, constRefSize = 0; - for (uint32_t i = 0; i < testModel.operands.size(); i++) { - const auto& op = testModel.operands[i]; + for (uint32_t i = 0; i < testModel.main.operands.size(); i++) { + const auto& op = testModel.main.operands[i]; DataLocation loc = {}; if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { @@ -77,9 +78,9 @@ Model createModel(const TestModel& testModel) { } // Model operations. - hidl_vec operations(testModel.operations.size()); - std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(), - [](const TestOperation& op) -> Operation { + hidl_vec operations(testModel.main.operations.size()); + std::transform(testModel.main.operations.begin(), testModel.main.operations.end(), + operations.begin(), [](const TestOperation& op) -> Operation { return {.type = static_cast(op.type), .inputs = op.inputs, .outputs = op.outputs}; @@ -87,8 +88,8 @@ Model createModel(const TestModel& testModel) { // Constant copies. hidl_vec operandValues(constCopySize); - for (uint32_t i = 0; i < testModel.operands.size(); i++) { - const auto& op = testModel.operands[i]; + for (uint32_t i = 0; i < testModel.main.operands.size(); i++) { + const auto& op = testModel.main.operands[i]; if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { const uint8_t* begin = op.data.get(); const uint8_t* end = begin + op.data.size(); @@ -109,8 +110,8 @@ Model createModel(const TestModel& testModel) { reinterpret_cast(static_cast(mappedMemory->getPointer())); CHECK(mappedPtr != nullptr); - for (uint32_t i = 0; i < testModel.operands.size(); i++) { - const auto& op = testModel.operands[i]; + for (uint32_t i = 0; i < testModel.main.operands.size(); i++) { + const auto& op = testModel.main.operands[i]; if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) { const uint8_t* begin = op.data.get(); const uint8_t* end = begin + op.data.size(); @@ -121,8 +122,8 @@ Model createModel(const TestModel& testModel) { return {.operands = std::move(operands), .operations = std::move(operations), - .inputIndexes = testModel.inputIndexes, - .outputIndexes = testModel.outputIndexes, + .inputIndexes = testModel.main.inputIndexes, + .outputIndexes = testModel.main.outputIndexes, .operandValues = std::move(operandValues), .pools = std::move(pools), .relaxComputationFloat32toFloat16 = testModel.isRelaxed}; diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp index 2130a76b75..10dec791cf 100644 --- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp @@ -207,10 +207,10 @@ TestModel createLargeTestModelImpl(TestOperationType op, uint32_t len) { }; return { - .operands = std::move(operands), - .operations = std::move(operations), - .inputIndexes = {1}, - .outputIndexes = {len * 2 + 1}, + .main = {.operands = std::move(operands), + .operations = std::move(operations), + .inputIndexes = {1}, + .outputIndexes = {len * 2 + 1}}, .isRelaxed = false, }; } diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp index 599fd1d9be..4c8fede8b2 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp @@ -75,10 +75,11 @@ struct TestConfig { Model createModel(const TestModel& testModel) { // Model operands. - hidl_vec operands(testModel.operands.size()); + CHECK_EQ(testModel.referenced.size(), 0u); // Not supported in 1.1. + hidl_vec operands(testModel.main.operands.size()); size_t constCopySize = 0, constRefSize = 0; - for (uint32_t i = 0; i < testModel.operands.size(); i++) { - const auto& op = testModel.operands[i]; + for (uint32_t i = 0; i < testModel.main.operands.size(); i++) { + const auto& op = testModel.main.operands[i]; DataLocation loc = {}; if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { @@ -110,9 +111,9 @@ Model createModel(const TestModel& testModel) { } // Model operations. - hidl_vec operations(testModel.operations.size()); - std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(), - [](const TestOperation& op) -> Operation { + hidl_vec operations(testModel.main.operations.size()); + std::transform(testModel.main.operations.begin(), testModel.main.operations.end(), + operations.begin(), [](const TestOperation& op) -> Operation { return {.type = static_cast(op.type), .inputs = op.inputs, .outputs = op.outputs}; @@ -120,8 +121,8 @@ Model createModel(const TestModel& testModel) { // Constant copies. hidl_vec operandValues(constCopySize); - for (uint32_t i = 0; i < testModel.operands.size(); i++) { - const auto& op = testModel.operands[i]; + for (uint32_t i = 0; i < testModel.main.operands.size(); i++) { + const auto& op = testModel.main.operands[i]; if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { const uint8_t* begin = op.data.get(); const uint8_t* end = begin + op.data.size(); @@ -142,8 +143,8 @@ Model createModel(const TestModel& testModel) { reinterpret_cast(static_cast(mappedMemory->getPointer())); CHECK(mappedPtr != nullptr); - for (uint32_t i = 0; i < testModel.operands.size(); i++) { - const auto& op = testModel.operands[i]; + for (uint32_t i = 0; i < testModel.main.operands.size(); i++) { + const auto& op = testModel.main.operands[i]; if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) { const uint8_t* begin = op.data.get(); const uint8_t* end = begin + op.data.size(); @@ -154,15 +155,15 @@ Model createModel(const TestModel& testModel) { return {.operands = std::move(operands), .operations = std::move(operations), - .inputIndexes = testModel.inputIndexes, - .outputIndexes = testModel.outputIndexes, + .inputIndexes = testModel.main.inputIndexes, + .outputIndexes = testModel.main.outputIndexes, .operandValues = std::move(operandValues), .pools = std::move(pools), .relaxComputationFloat32toFloat16 = testModel.isRelaxed}; } static bool isOutputSizeGreaterThanOne(const TestModel& testModel, uint32_t index) { - const auto byteSize = testModel.operands[testModel.outputIndexes[index]].data.size(); + const auto byteSize = testModel.main.operands[testModel.main.outputIndexes[index]].data.size(); return byteSize > 1u; } @@ -302,17 +303,17 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo // either empty, or have the same number of elements as the number of outputs. ASSERT_EQ(ErrorStatus::NONE, executionStatus); ASSERT_TRUE(outputShapes.size() == 0 || - outputShapes.size() == testModel.outputIndexes.size()); + outputShapes.size() == testModel.main.outputIndexes.size()); break; case OutputType::UNSPECIFIED: // If the model output operands are not fully specified, outputShapes must have // the same number of elements as the number of outputs. ASSERT_EQ(ErrorStatus::NONE, executionStatus); - ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size()); + ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size()); break; case OutputType::INSUFFICIENT: ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus); - ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size()); + ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size()); ASSERT_FALSE(outputShapes[0].isSufficient); return; } @@ -320,7 +321,7 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo // Go through all outputs, check returned output shapes. for (uint32_t i = 0; i < outputShapes.size(); i++) { EXPECT_TRUE(outputShapes[i].isSufficient); - const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions; + const auto& expect = testModel.main.operands[testModel.main.outputIndexes[i]].dimensions; const std::vector actual = outputShapes[i].dimensions; EXPECT_EQ(expect, actual); } diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp index 0bd24daec0..ac18c8ffcc 100644 --- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp @@ -209,10 +209,10 @@ TestModel createLargeTestModelImpl(TestOperationType op, uint32_t len) { }; return { - .operands = std::move(operands), - .operations = std::move(operations), - .inputIndexes = {1}, - .outputIndexes = {len * 2 + 1}, + .main = {.operands = std::move(operands), + .operations = std::move(operations), + .inputIndexes = {1}, + .outputIndexes = {len * 2 + 1}}, .isRelaxed = false, }; } diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 82f34ff779..404c2a1e03 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -169,7 +169,8 @@ class DeviceMemoryAllocator { if constexpr (ioType == IOType::INPUT) { if (buffer != nullptr) { // TestBuffer -> Shared memory. - const auto& testBuffer = kTestModel.operands[kTestModel.inputIndexes[index]].data; + const auto& testBuffer = + kTestModel.main.operands[kTestModel.main.inputIndexes[index]].data; ASSERT_GT(testBuffer.size(), 0); hidl_memory tmp = nn::allocateSharedMemory(testBuffer.size()); sp inputMemory = mapMemory(tmp); @@ -195,26 +196,42 @@ class DeviceMemoryAllocator { const TestModel& kTestModel; }; -} // namespace +Subgraph createSubgraph(const TestSubgraph& testSubgraph, uint32_t* constCopySize, + std::vector* constCopies, uint32_t* constRefSize, + std::vector* constReferences) { + CHECK(constCopySize != nullptr); + CHECK(constCopies != nullptr); + CHECK(constRefSize != nullptr); + CHECK(constReferences != nullptr); -Model createModel(const TestModel& testModel) { - // Model operands. - hidl_vec operands(testModel.operands.size()); - size_t constCopySize = 0, constRefSize = 0; - for (uint32_t i = 0; i < testModel.operands.size(); i++) { - const auto& op = testModel.operands[i]; + // Operands. + hidl_vec operands(testSubgraph.operands.size()); + for (uint32_t i = 0; i < testSubgraph.operands.size(); i++) { + const auto& op = testSubgraph.operands[i]; DataLocation loc = {}; if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { - loc = {.poolIndex = 0, - .offset = static_cast(constCopySize), - .length = static_cast(op.data.size())}; - constCopySize += op.data.alignedSize(); + loc = { + .poolIndex = 0, + .offset = *constCopySize, + .length = static_cast(op.data.size()), + }; + constCopies->push_back(&op.data); + *constCopySize += op.data.alignedSize(); } else if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) { - loc = {.poolIndex = 0, - .offset = static_cast(constRefSize), - .length = static_cast(op.data.size())}; - constRefSize += op.data.alignedSize(); + loc = { + .poolIndex = 0, + .offset = *constRefSize, + .length = static_cast(op.data.size()), + }; + constReferences->push_back(&op.data); + *constRefSize += op.data.alignedSize(); + } else if (op.lifetime == TestOperandLifeTime::SUBGRAPH) { + loc = { + .poolIndex = 0, + .offset = *op.data.get(), + .length = 0, + }; } V1_2::Operand::ExtraParams extraParams; @@ -233,25 +250,52 @@ Model createModel(const TestModel& testModel) { .extraParams = std::move(extraParams)}; } - // Model operations. - hidl_vec operations(testModel.operations.size()); - std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(), - [](const TestOperation& op) -> Operation { + // Operations. + hidl_vec operations(testSubgraph.operations.size()); + std::transform(testSubgraph.operations.begin(), testSubgraph.operations.end(), + operations.begin(), [](const TestOperation& op) -> Operation { return {.type = static_cast(op.type), .inputs = op.inputs, .outputs = op.outputs}; }); + return {.operands = std::move(operands), + .operations = std::move(operations), + .inputIndexes = testSubgraph.inputIndexes, + .outputIndexes = testSubgraph.outputIndexes}; +} + +void copyTestBuffers(const std::vector& buffers, uint8_t* output) { + uint32_t offset = 0; + for (const TestBuffer* buffer : buffers) { + const uint8_t* begin = buffer->get(); + const uint8_t* end = begin + buffer->size(); + std::copy(begin, end, output + offset); + offset += buffer->alignedSize(); + } +} + +} // namespace + +Model createModel(const TestModel& testModel) { + uint32_t constCopySize = 0; + uint32_t constRefSize = 0; + std::vector constCopies; + std::vector constReferences; + + Subgraph mainSubgraph = createSubgraph(testModel.main, &constCopySize, &constCopies, + &constRefSize, &constReferences); + hidl_vec refSubgraphs(testModel.referenced.size()); + std::transform(testModel.referenced.begin(), testModel.referenced.end(), refSubgraphs.begin(), + [&constCopySize, &constCopies, &constRefSize, + &constReferences](const TestSubgraph& testSubgraph) { + return createSubgraph(testSubgraph, &constCopySize, &constCopies, + &constRefSize, &constReferences); + }); + // Constant copies. hidl_vec operandValues(constCopySize); - for (uint32_t i = 0; i < testModel.operands.size(); i++) { - const auto& op = testModel.operands[i]; - if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) { - const uint8_t* begin = op.data.get(); - const uint8_t* end = begin + op.data.size(); - std::copy(begin, end, operandValues.data() + operands[i].location.offset); - } - } + copyTestBuffers(constCopies, operandValues.data()); // Shared memory. hidl_vec pools = {}; @@ -266,27 +310,18 @@ Model createModel(const TestModel& testModel) { reinterpret_cast(static_cast(mappedMemory->getPointer())); CHECK(mappedPtr != nullptr); - for (uint32_t i = 0; i < testModel.operands.size(); i++) { - const auto& op = testModel.operands[i]; - if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) { - const uint8_t* begin = op.data.get(); - const uint8_t* end = begin + op.data.size(); - std::copy(begin, end, mappedPtr + operands[i].location.offset); - } - } + copyTestBuffers(constReferences, mappedPtr); } - return {.main = {.operands = std::move(operands), - .operations = std::move(operations), - .inputIndexes = testModel.inputIndexes, - .outputIndexes = testModel.outputIndexes}, + return {.main = std::move(mainSubgraph), + .referenced = std::move(refSubgraphs), .operandValues = std::move(operandValues), .pools = std::move(pools), .relaxComputationFloat32toFloat16 = testModel.isRelaxed}; } static bool isOutputSizeGreaterThanOne(const TestModel& testModel, uint32_t index) { - const auto byteSize = testModel.operands[testModel.outputIndexes[index]].data.size(); + const auto byteSize = testModel.main.operands[testModel.main.outputIndexes[index]].data.size(); return byteSize > 1u; } @@ -320,10 +355,10 @@ static std::pair>> createRequest( std::vector tokens; // Model inputs. - hidl_vec inputs(testModel.inputIndexes.size()); + hidl_vec inputs(testModel.main.inputIndexes.size()); size_t inputSize = 0; - for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) { - const auto& op = testModel.operands[testModel.inputIndexes[i]]; + for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) { + const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]]; if (op.data.size() == 0) { // Omitted input. inputs[i] = {.hasNoValue = true}; @@ -350,10 +385,10 @@ static std::pair>> createRequest( } // Model outputs. - hidl_vec outputs(testModel.outputIndexes.size()); + hidl_vec outputs(testModel.main.outputIndexes.size()); size_t outputSize = 0; - for (uint32_t i = 0; i < testModel.outputIndexes.size(); i++) { - const auto& op = testModel.operands[testModel.outputIndexes[i]]; + for (uint32_t i = 0; i < testModel.main.outputIndexes.size(); i++) { + const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]]; if (preferDeviceMemory) { SCOPED_TRACE("Output index = " + std::to_string(i)); auto [buffer, token] = allocator.allocate(i); @@ -398,9 +433,9 @@ static std::pair>> createRequest( CHECK(inputMemory.get() != nullptr); uint8_t* inputPtr = static_cast(static_cast(inputMemory->getPointer())); CHECK(inputPtr != nullptr); - for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) { + for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) { if (!inputs[i].hasNoValue && inputs[i].location.poolIndex == kInputPoolIndex) { - const auto& op = testModel.operands[testModel.inputIndexes[i]]; + const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]]; const uint8_t* begin = op.data.get(); const uint8_t* end = begin + op.data.size(); std::copy(begin, end, inputPtr + inputs[i].location.offset); @@ -443,7 +478,7 @@ static std::vector getOutputBuffers(const TestModel& testModel, cons if (outputLoc.poolIndex == kOutputPoolIndex) { outputBuffers.emplace_back(outputLoc.length, outputPtr + outputLoc.offset); } else { - const auto& op = testModel.operands[testModel.outputIndexes[i]]; + const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]]; if (op.data.size() == 0) { outputBuffers.emplace_back(); } else { @@ -638,17 +673,17 @@ void EvaluatePreparedModel(const sp& device, const sp& // either empty, or have the same number of elements as the number of outputs. ASSERT_EQ(ErrorStatus::NONE, executionStatus); ASSERT_TRUE(outputShapes.size() == 0 || - outputShapes.size() == testModel.outputIndexes.size()); + outputShapes.size() == testModel.main.outputIndexes.size()); break; case OutputType::UNSPECIFIED: // If the model output operands are not fully specified, outputShapes must have // the same number of elements as the number of outputs. ASSERT_EQ(ErrorStatus::NONE, executionStatus); - ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size()); + ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size()); break; case OutputType::INSUFFICIENT: ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus); - ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size()); + ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size()); ASSERT_FALSE(outputShapes[0].isSufficient); return; } @@ -656,7 +691,7 @@ void EvaluatePreparedModel(const sp& device, const sp& // Go through all outputs, check returned output shapes. for (uint32_t i = 0; i < outputShapes.size(); i++) { EXPECT_TRUE(outputShapes[i].isSufficient); - const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions; + const auto& expect = testModel.main.operands[testModel.main.outputIndexes[i]].dimensions; const std::vector actual = outputShapes[i].dimensions; EXPECT_EQ(expect, actual); } @@ -862,7 +897,7 @@ INSTANTIATE_GENERATED_TEST(FencedComputeTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) { - return testModel.hasQuant8CoupledOperands() && testModel.operations.size() == 1; + return testModel.hasQuant8CoupledOperands() && testModel.main.operations.size() == 1; }); } // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp index 2f1e05c5c6..e07eb4750e 100644 --- a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp +++ b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp @@ -237,12 +237,13 @@ void runExecutionTest(const sp& preparedModel, const TestModel& // If the model output operands are fully specified, outputShapes must be either // either empty, or have the same number of elements as the number of outputs. - ASSERT_TRUE(outputShapes.size() == 0 || outputShapes.size() == testModel.outputIndexes.size()); + ASSERT_TRUE(outputShapes.size() == 0 || + outputShapes.size() == testModel.main.outputIndexes.size()); // Go through all outputs, check returned output shapes. for (uint32_t i = 0; i < outputShapes.size(); i++) { EXPECT_TRUE(outputShapes[i].isSufficient); - const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions; + const auto& expect = testModel.main.operands[testModel.main.outputIndexes[i]].dimensions; const std::vector actual = outputShapes[i].dimensions; EXPECT_EQ(expect, actual); } diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index b9ea430694..09e9922a23 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -182,6 +182,7 @@ static float getInvalidScale(OperandType type) { case OperandType::TENSOR_FLOAT16: case OperandType::TENSOR_FLOAT32: case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: + case OperandType::SUBGRAPH: return 1.0f; case OperandType::TENSOR_INT32: return -1.0f; @@ -220,6 +221,7 @@ static std::vector getInvalidZeroPoints(OperandType type) { case OperandType::TENSOR_FLOAT32: case OperandType::TENSOR_INT32: case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: + case OperandType::SUBGRAPH: return {1}; case OperandType::TENSOR_QUANT8_ASYMM: return {-1, 256}; From 6e58a649e8a9e9e6e919ec4f9600d92464ce4f05 Mon Sep 17 00:00:00 2001 From: Sunil Ravi Date: Fri, 7 Feb 2020 12:01:16 -0800 Subject: [PATCH 0572/1022] wifi: Fix for VtsHalWifiSupplicantV1_0TargetTest failures Since some of the APIs are overridden by an upgraded API in newer HAL, Check the return value of such deprecated APIs and if it's FAILURE_UNKNOWN, don't proceed and consider it as pass. Bug: 147821406 Bug: 146991831 Bug: 149045565 Test: atest VtsHalWifiSupplicantV1_0TargetTest Test: atest VtsHalWifiSupplicantV1_1TargetTest Test: atest VtsHalWifiSupplicantV1_2TargetTest Change-Id: I28c4431bfeaaa7a628be71f41f8299a85fed7eed --- wifi/supplicant/1.0/vts/functional/Android.bp | 2 ++ .../supplicant_sta_network_hidl_test.cpp | 34 ++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/wifi/supplicant/1.0/vts/functional/Android.bp b/wifi/supplicant/1.0/vts/functional/Android.bp index 332ee4aff3..80139060f1 100644 --- a/wifi/supplicant/1.0/vts/functional/Android.bp +++ b/wifi/supplicant/1.0/vts/functional/Android.bp @@ -46,6 +46,8 @@ cc_test { "VtsHalWifiSupplicantV1_0TargetTestUtil", "android.hardware.wifi.supplicant@1.0", "android.hardware.wifi.supplicant@1.1", + "android.hardware.wifi.supplicant@1.2", + "android.hardware.wifi.supplicant@1.3", "android.hardware.wifi@1.0", "libgmock", "libwifi-system", diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp index 52f77a1002..5467e02799 100644 --- a/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp +++ b/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -93,6 +94,11 @@ class SupplicantStaNetworkHidlTest EXPECT_TRUE(turnOnExcessiveLogging(supplicant_)); sta_network_ = createSupplicantStaNetwork(supplicant_); ASSERT_NE(sta_network_.get(), nullptr); + /* variable used to check if the underlying HAL version is 1.3 or + * higher. This is to skip tests which are using deprecated methods. + */ + v1_3 = ::android::hardware::wifi::supplicant::V1_3:: + ISupplicantStaNetwork::castFrom(sta_network_); ssid_.assign(kTestSsidStr, kTestSsidStr + strlen(kTestSsidStr)); } @@ -114,6 +120,8 @@ class SupplicantStaNetworkHidlTest }); } + sp<::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork> + v1_3 = nullptr; bool isP2pOn_ = false; sp supplicant_; // ISupplicantStaNetwork object used for all tests in this fixture. @@ -221,6 +229,9 @@ TEST_P(SupplicantStaNetworkHidlTest, SetGetBssid) { * SetGetKeyMgmt */ TEST_P(SupplicantStaNetworkHidlTest, SetGetKeyMgmt) { + if (v1_3 != nullptr) { + GTEST_SKIP() << "Skipping test since HAL is 1.3 or higher"; + } sta_network_->setKeyMgmt(kTestKeyMgmt, [](const SupplicantStatus& status) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); }); @@ -235,6 +246,9 @@ TEST_P(SupplicantStaNetworkHidlTest, SetGetKeyMgmt) { * SetGetProto */ TEST_P(SupplicantStaNetworkHidlTest, SetGetProto) { + if (v1_3 != nullptr) { + GTEST_SKIP() << "Skipping test since HAL is 1.3 or higher"; + } sta_network_->setProto(kTestProto, [](const SupplicantStatus& status) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); }); @@ -262,6 +276,9 @@ TEST_P(SupplicantStaNetworkHidlTest, SetGetAuthAlg) { * SetGetGroupCipher */ TEST_P(SupplicantStaNetworkHidlTest, SetGetGroupCipher) { + if (v1_3 != nullptr) { + GTEST_SKIP() << "Skipping test since HAL is 1.3 or higher"; + } sta_network_->setGroupCipher( kTestGroupCipher, [](const SupplicantStatus& status) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); @@ -277,6 +294,9 @@ TEST_P(SupplicantStaNetworkHidlTest, SetGetGroupCipher) { * SetGetPairwiseCipher */ TEST_P(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher) { + if (v1_3 != nullptr) { + GTEST_SKIP() << "Skipping test since HAL is 1.3 or higher"; + } sta_network_->setPairwiseCipher( kTestPairwiseCipher, [](const SupplicantStatus& status) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); @@ -627,6 +647,9 @@ TEST_P(SupplicantStaNetworkHidlTest, SetGetEapEngineID) { * Enable */ TEST_P(SupplicantStaNetworkHidlTest, Enable) { + if (v1_3 != nullptr) { + GTEST_SKIP() << "Skipping test since HAL is 1.3 or higher"; + } // wpa_supplicant doesn't perform any connection initiation // unless atleast the Ssid and Ket mgmt params are set. sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) { @@ -654,6 +677,9 @@ TEST_P(SupplicantStaNetworkHidlTest, Enable) { * Disable */ TEST_P(SupplicantStaNetworkHidlTest, Disable) { + if (v1_3 != nullptr) { + GTEST_SKIP() << "Skipping test since HAL is 1.3 or higher"; + } // wpa_supplicant doesn't perform any connection initiation // unless atleast the Ssid and Ket mgmt params are set. sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) { @@ -677,6 +703,9 @@ TEST_P(SupplicantStaNetworkHidlTest, Disable) { * Select. */ TEST_P(SupplicantStaNetworkHidlTest, Select) { + if (v1_3 != nullptr) { + GTEST_SKIP() << "Skipping test since HAL is 1.3 or higher"; + } // wpa_supplicant doesn't perform any connection initiation // unless atleast the Ssid and Ket mgmt params are set. sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) { @@ -788,6 +817,9 @@ TEST_P(SupplicantStaNetworkHidlTest, SetProactiveKeyCaching) { * GetWpsNfcConfigurationToken */ TEST_P(SupplicantStaNetworkHidlTest, GetWpsNfcConfigurationToken) { + if (v1_3 != nullptr) { + GTEST_SKIP() << "Skipping test since HAL is 1.3 or higher"; + } ASSERT_EQ(SupplicantStatusCode::SUCCESS, HIDL_INVOKE(sta_network_, setSsid, ssid_).code); ASSERT_EQ(SupplicantStatusCode::SUCCESS, @@ -808,4 +840,4 @@ INSTANTIATE_TEST_CASE_P( android::hardware::getAllHalInstanceNames(IWifi::descriptor)), testing::ValuesIn(android::hardware::getAllHalInstanceNames( ISupplicant::descriptor))), - android::hardware::PrintInstanceTupleNameToString<>); \ No newline at end of file + android::hardware::PrintInstanceTupleNameToString<>); From 31a6216561245f10db74ec00b74e14282fdfb05c Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 12 Feb 2020 11:28:45 -0800 Subject: [PATCH 0573/1022] Changed value of "no user id" to -10000 (same as UserHandle.USER_NULL). Test: no, thanks Bug: 146207078 Change-Id: I8bdab48caa8cff98ac8795e6aa20a2b295363fda --- automotive/vehicle/2.0/types.hal | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index 7a5f2d2e9b..bce42b9fca 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -4114,7 +4114,8 @@ struct UserInfo { /** * Id of an Android user. * - * Must be > 0 for valid ids, or -1 when it's not used. + * Must be > 0 for valid ids, or -10000 (which is the same as Android.UserHandle.USER_NULL) when + * it's not used. */ typedef int32_t UserId; From 7778389b1a059ce9a3992985f7ea1bfa946d17a9 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 12 Feb 2020 09:32:04 -0800 Subject: [PATCH 0574/1022] Fixed User HAL dump. It was not validating the input before storing the response form lshal, which would crash it later. Test: adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default --set 299896583 a 2 Bug: 146207078 Change-Id: I49a38041e2881224c61e3c645db7c9103d024040 --- .../default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp index 63ad93c375..7f90914302 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp @@ -311,6 +311,11 @@ StatusCode EmulatedVehicleServer::onSetInitialUserInfo(const VehiclePropValue& v // (even when explicitly calling setprop log.tag. As this class should be using ALOG instead of // LOG, it's not worth investigating why... + if (value.value.int32Values.size() == 0) { + LOG(ERROR) << "set(INITIAL_USER_INFO): no int32values, ignoring it: " << toString(value); + return StatusCode::INVALID_ARG; + } + if (value.areaId != 0) { LOG(INFO) << "set(INITIAL_USER_INFO) called from lshal; storing it: " << toString(value); mInitialUserResponseFromCmd.reset(new VehiclePropValue(value)); @@ -318,10 +323,6 @@ StatusCode EmulatedVehicleServer::onSetInitialUserInfo(const VehiclePropValue& v } LOG(INFO) << "set(INITIAL_USER_INFO) called from Android: " << toString(value); - if (value.value.int32Values.size() == 0) { - LOG(ERROR) << "invalid request (no requestId): " << toString(value); - return StatusCode::INVALID_ARG; - } int32_t requestId = value.value.int32Values[0]; // Create the update property and set common values From c8c0064e990056631be92225715771f189f87a59 Mon Sep 17 00:00:00 2001 From: Sunil Ravi Date: Sat, 8 Feb 2020 18:45:20 -0800 Subject: [PATCH 0575/1022] wifi: Improve documentation of hidl APIs. Added changes as per ANAPIC review to improve documentation of few hidl APIs. Bug: 148617258 Test: Not tested as there is no code change. Change-Id: I3f91c6b8aad3f34807534a3fbc3cf5a3c3233cd7 --- current.txt | 6 +++--- wifi/supplicant/1.3/ISupplicantStaIface.hal | 15 +++++++++------ .../1.3/ISupplicantStaIfaceCallback.hal | 5 ++++- wifi/supplicant/1.3/ISupplicantStaNetwork.hal | 8 ++++---- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/current.txt b/current.txt index 8d068d0e89..1789e770da 100644 --- a/current.txt +++ b/current.txt @@ -678,9 +678,9 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant -8aed0a8e03e7a67bfdfb78ad7529a9ae95bea36e6060473b204c89d772522126 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface -def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback -62cf050c593c1ec34b49178b5bdde72dd9b80d9bad3eb184e4f0cd564d28678c android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork +159d48c9efb881f44d5deda8917b89fb4da26837f019446d6d73b73ea5010eca android.hardware.wifi.supplicant@1.3::ISupplicantStaIface +2ce1f7fb52e49f80b13a9b153d491bce530552f02357ea729acae922a8659f93 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback +77531c8d048f8f8ae532babd0ca86332a865ec9aace1b051226ef2b21123e645 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types e1d34b83188a8ef3c507ec53c0ebcf714863c746da7f4a05460453f7c4c09389 android.hardware.radio@1.5::types 8062d0a1a03594dd8b448adcf6f08856b5720f7e33f9b785a21d3ef74a4f211d android.hardware.radio@1.5::IRadio diff --git a/wifi/supplicant/1.3/ISupplicantStaIface.hal b/wifi/supplicant/1.3/ISupplicantStaIface.hal index b501a95805..4506f377e8 100644 --- a/wifi/supplicant/1.3/ISupplicantStaIface.hal +++ b/wifi/supplicant/1.3/ISupplicantStaIface.hal @@ -69,7 +69,7 @@ interface ISupplicantStaIface extends @1.2::ISupplicantStaIface { bitfield driverCapabilitiesMask); /** - * Set MBO cellular data status. + * Set Wi-Fi Alliance Agile Multiband (MBO) cellular data status. * * @param available true means cellular data available, false otherwise. * @return status Status of the operation. @@ -93,8 +93,10 @@ interface ISupplicantStaIface extends @1.2::ISupplicantStaIface { generates (SupplicantStatus status, bitfield keyMgmtMask); /** - * Flush FILS HLP IEs - * Use this to flush all the HLP IEs in wpa_supplicant + * Flush fast initial link setup (IEEE 802.11ai FILS) HLP packets. + * Use this to flush all the higher layer protocol (HLP) packets added in + * wpa_supplicant to send in FILS (Re)Association Request frame + * (Eg: DHCP discover packet). * * @return status Status of the operation. * Possible status codes: @@ -106,11 +108,12 @@ interface ISupplicantStaIface extends @1.2::ISupplicantStaIface { filsHlpFlushRequest() generates (SupplicantStatus status); /** - * Add FILS HLP IEs - * Use this to add a HLP IE to wpa_supplicant + * Add fast initial link setup (IEEE 802.11ai FILS) HLP packets. + * Use this to add higher layer protocol (HLP) packet in FILS (Re)Association Request frame + * (Eg: DHCP discover packet). * * @param dst_mac MAC address of the destination - * @param pkt The contents of the HLP IE starting from ethertype + * @param pkt The contents of the HLP packet starting from ethertype * @return status Status of the operation. * Possible status codes: * |SupplicantStatusCode.SUCCESS|, diff --git a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal index 6828dcdf38..c5da29c174 100644 --- a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal +++ b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal @@ -147,7 +147,7 @@ interface ISupplicantStaIfaceCallback extends @1.2::ISupplicantStaIfaceCallback }; /** - * Indicates PMK cache added event. + * Indicates pairwise master key (PMK) cache added event. * * @param expirationTimeInSec expiration time in seconds * @param serializedEntry is serialized PMK cache entry, the content is @@ -192,6 +192,9 @@ interface ISupplicantStaIfaceCallback extends @1.2::ISupplicantStaIfaceCallback /** * Indicates an EAP authentication failure. + * @param errorCode Error code for EAP authentication failure. + * Either standard error code (enum EapErrorCode) or + * private error code defined by network provider. */ oneway onEapFailure_1_3(uint32_t errorCode); diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal index 0566a217c9..2505912cfb 100644 --- a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal +++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal @@ -214,7 +214,7 @@ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { generates (SupplicantStatus status, bitfield groupCipherMask); /** - * Set WAPI certificate suite for this network. + * Set WAPI certificate suite name for this network. * * @param suite value to set. * @return status Status of the operation. @@ -227,7 +227,7 @@ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { setWapiCertSuite(string suite) generates (SupplicantStatus status); /** - * Get WAPI certificate suite set for this network. + * Get WAPI certificate suite name set for this network. * * @return status Status of the operation. * Possible status codes: @@ -239,7 +239,7 @@ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { getWapiCertSuite() generates (SupplicantStatus status, string suite); /** - * Add a PMK into supplicant PMK cache. + * Add a pairwise master key (PMK) into supplicant PMK cache. * * @param serializedEntry is serialized PMK cache entry, the content is * opaque for the framework and depends on the native implementation. @@ -278,7 +278,7 @@ interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork { getAuthAlg_1_3() generates (SupplicantStatus status, bitfield authAlgMask); /** - * Enable EAP ERP for this network. + * Enable Extensible Authentication (EAP) - Re-authentication Protocol (ERP) for this network. * * @param enable true to set, false otherwise. * @return status Status of the operation. From 79d6bb1ad23bfee4922d7c216ce8fbaed6d0dece Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Wed, 12 Feb 2020 18:54:07 -0800 Subject: [PATCH 0576/1022] NNAPI VTS: use max time point instead of uint64_t max Bug: 149441015 Test: mma Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: Ic74f83242cbe04a4cec47adbfc51002fdf8bb47d --- neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp index 2f1e05c5c6..76d133a436 100644 --- a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp +++ b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp @@ -67,8 +67,10 @@ static OptionalTimePoint makeOptionalTimePoint(DeadlineBoundType deadlineBoundTy deadline.nanosecondsSinceEpoch(nanosecondsSinceEpoch); } break; case DeadlineBoundType::UNLIMITED: { - uint64_t unlimited = std::numeric_limits::max(); - deadline.nanosecondsSinceEpoch(unlimited); + const auto maxTime = std::chrono::time_point::max(); + const uint64_t nanosecondsSinceEpoch = maxTime.time_since_epoch().count(); + deadline.nanosecondsSinceEpoch(nanosecondsSinceEpoch); } break; } return deadline; From 09c8b5ba5955162f90b105f8364528b2e18e79f9 Mon Sep 17 00:00:00 2001 From: Hunter Knepshield Date: Wed, 12 Feb 2020 18:55:28 -0800 Subject: [PATCH 0577/1022] IDumpstateDevice 1.1 tweak: "device" -> "verbose" Pixel has been dumping some non-sensitive information in bug reports using IDumpstateDevice for a long time, and requiring nothing to be dumped on user builds by default suddenly changes behavior. To account for this use case, we instead change the meaning of the toggle to control *verbose* logging, specifically anything with privacy, storage, or battery impact. VTS tests are updated appropriately. Bug: 143183758 Bug: 143184495 Test: atest VtsHalDumpstateV1_1TargetTest Change-Id: Ib71ce43e9168d82fd9ee0564db813c5a3538c459 --- current.txt | 2 +- dumpstate/1.1/IDumpstateDevice.hal | 26 +++++---- .../VtsHalDumpstateV1_1TargetTest.cpp | 58 +++++++++---------- 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/current.txt b/current.txt index 7d67361b66..459044f4e2 100644 --- a/current.txt +++ b/current.txt @@ -646,7 +646,7 @@ f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardwar 66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory 994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory 446287268831f4ddfac4a51bb1c32ae1e48e47bccd535fccc2c4546d0e7c4013 android.hardware.dumpstate@1.1::types -f284ffde7cadf5a1364b75ab313baf22401eeca289bdde2a2dc7a27ea4ab98d7 android.hardware.dumpstate@1.1::IDumpstateDevice +186bc152ae189ab48f3a761a44ddf5edd0d483073c5b6ca1f802f8b50488b754 android.hardware.dumpstate@1.1::IDumpstateDevice 769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types 626db710bf917ecf551a0b0b1f25be10bf52758f43e0fc808b148b6aae2ef73e android.hardware.gnss@2.1::IGnss ba5ac712b2a656dc07c83ab4a7a2c2f3bee1bbcb752e8b8ffa9b672f3b5b0728 android.hardware.gnss@2.1::IGnssAntennaInfo diff --git a/dumpstate/1.1/IDumpstateDevice.hal b/dumpstate/1.1/IDumpstateDevice.hal index 502c460998..183404dd68 100644 --- a/dumpstate/1.1/IDumpstateDevice.hal +++ b/dumpstate/1.1/IDumpstateDevice.hal @@ -29,8 +29,9 @@ interface IDumpstateDevice extends @1.0::IDumpstateDevice { * The 1.0 version of #dumpstateBoard(handle) should just delegate to this new method and pass * DumpstateMode::DEFAULT and a timeout of 30,000ms (30 seconds). * - * This method may still be called by the dumpstate routine even if getDeviceLoggingEnabled - * returns false. In this case, it must return DumpstateStatus::DEVICE_LOGGING_NOT_ENABLED. + * This method may still be called by the dumpstate routine even if getVerboseLoggingEnabled + * returns false. In this case, it may include essential information but must not include + * information that identifies the user. * * @param h A native handle with one or two valid file descriptors. The first FD is for text * output, the second (if present) is for binary output. @@ -44,7 +45,7 @@ interface IDumpstateDevice extends @1.0::IDumpstateDevice { generates (DumpstateStatus status); /** - * Turns device vendor logging on or off. + * Turns verbose device vendor logging on or off. * * The setting should be persistent across reboots. Underlying implementations may need to start * vendor logging daemons, set system properties, or change logging masks, for example. Given @@ -52,20 +53,21 @@ interface IDumpstateDevice extends @1.0::IDumpstateDevice { * memory/storage/battery impacts, calling this method on a user build should only be done after * user consent has been obtained, e.g. from a toggle in developer settings. * - * Even if device logging has been disabled, dumpstateBoard may still be called by the dumpstate - * routine. In this case, it must return DumpstateStatus::DEVICE_LOGGING_NOT_ENABLED. + * Even if verbose logging has been disabled, dumpstateBoard may still be called by the + * dumpstate routine, and essential information that does not identify the user may be included. * - * @param enable Whether to enable or disable device vendor logging. + * @param enable Whether to enable or disable verbose vendor logging. */ - setDeviceLoggingEnabled(bool enable); + setVerboseLoggingEnabled(bool enable); /** - * Queries the current state of device logging. Primarily for UI and informative purposes. + * Queries the current state of verbose device logging. Primarily for UI and informative + * purposes. * - * Even if device logging has been disabled, dumpstateBoard may still be called by the dumpstate - * routine. In this case, it must return DumpstateStatus::DEVICE_LOGGING_NOT_ENABLED. + * Even if verbose logging has been disabled, dumpstateBoard may still be called by the + * dumpstate routine, and essential information that does not identify the user may be included. * - * @return enabled Whether or not vendor logging is currently enabled. + * @return enabled Whether or not verbose vendor logging is currently enabled. */ - getDeviceLoggingEnabled() generates (bool enabled); + getVerboseLoggingEnabled() generates (bool enabled); }; diff --git a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp index 089b039c2c..51dce5e345 100644 --- a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp +++ b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp @@ -48,8 +48,8 @@ class DumpstateHidl1_1Test : public ::testing::TestWithParam { ASSERT_NE(dumpstate, nullptr) << "Could not get HIDL instance"; } - void ToggleDeviceLogging(bool enable) { - Return status = dumpstate->setDeviceLoggingEnabled(enable); + void ToggleVerboseLogging(bool enable) { + Return status = dumpstate->setVerboseLoggingEnabled(enable); ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description(); if (!dumpstate->ping().isOk()) { @@ -58,11 +58,11 @@ class DumpstateHidl1_1Test : public ::testing::TestWithParam { GetService(); } - Return logging_enabled = dumpstate->getDeviceLoggingEnabled(); + Return logging_enabled = dumpstate->getVerboseLoggingEnabled(); ASSERT_TRUE(logging_enabled.isOk()) << "Status should be ok: " << logging_enabled.description(); ASSERT_EQ(logging_enabled, enable) - << "Device logging should now be " << (enable ? "enabled" : "disabled"); + << "Verbose logging should now be " << (enable ? "enabled" : "disabled"); if (!dumpstate->ping().isOk()) { ALOGW("IDumpstateDevice service appears to have exited lazily, attempting to get " @@ -71,9 +71,9 @@ class DumpstateHidl1_1Test : public ::testing::TestWithParam { } } - void EnableDeviceLogging() { ToggleDeviceLogging(true); } + void EnableVerboseLogging() { ToggleVerboseLogging(true); } - void DisableDeviceLogging() { ToggleDeviceLogging(false); } + void DisableVerboseLogging() { ToggleVerboseLogging(false); } sp dumpstate; }; @@ -122,7 +122,7 @@ void AssertStatusForMode(const DumpstateMode mode, const Return // Negative test: make sure dumpstateBoard() doesn't crash when passed a null pointer. TEST_FOR_ALL_DUMPSTATE_MODES(TestNullHandle, [this](DumpstateMode mode) { - EnableDeviceLogging(); + EnableVerboseLogging(); Return status = dumpstate->dumpstateBoard_1_1(nullptr, mode, kDefaultTimeoutMillis); @@ -132,7 +132,7 @@ TEST_FOR_ALL_DUMPSTATE_MODES(TestNullHandle, [this](DumpstateMode mode) { // Negative test: make sure dumpstateBoard() ignores a handle with no FD. TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithNoFd, [this](DumpstateMode mode) { - EnableDeviceLogging(); + EnableVerboseLogging(); native_handle_t* handle = native_handle_create(0, 0); ASSERT_NE(handle, nullptr) << "Could not create native_handle"; @@ -148,7 +148,7 @@ TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithNoFd, [this](DumpstateMode mode) { // Positive test: make sure dumpstateBoard() writes something to the FD. TEST_FOR_ALL_DUMPSTATE_MODES(TestOk, [this](DumpstateMode mode) { - EnableDeviceLogging(); + EnableVerboseLogging(); // Index 0 corresponds to the read end of the pipe; 1 to the write end. int fds[2]; @@ -173,7 +173,7 @@ TEST_FOR_ALL_DUMPSTATE_MODES(TestOk, [this](DumpstateMode mode) { // Positive test: make sure dumpstateBoard() doesn't crash with two FDs. TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithTwoFds, [this](DumpstateMode mode) { - EnableDeviceLogging(); + EnableVerboseLogging(); int fds1[2]; int fds2[2]; @@ -203,7 +203,7 @@ TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithTwoFds, [this](DumpstateMode mode) { // Make sure dumpstateBoard_1_1 actually validates its arguments. TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Negative) { - EnableDeviceLogging(); + EnableVerboseLogging(); int fds[2]; ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno; @@ -225,7 +225,7 @@ TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Negative) { } TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Undefined) { - EnableDeviceLogging(); + EnableVerboseLogging(); int fds[2]; ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno; @@ -248,7 +248,7 @@ TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Undefined) { // Positive test: make sure dumpstateBoard() from 1.0 doesn't fail. TEST_P(DumpstateHidl1_1Test, Test1_0MethodOk) { - EnableDeviceLogging(); + EnableVerboseLogging(); int fds[2]; ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno; @@ -269,9 +269,10 @@ TEST_P(DumpstateHidl1_1Test, Test1_0MethodOk) { native_handle_delete(handle); } -// Make sure disabling device logging behaves correctly. -TEST_FOR_ALL_DUMPSTATE_MODES(TestDeviceLoggingDisabled, [this](DumpstateMode mode) { - DisableDeviceLogging(); +// Make sure disabling verbose logging behaves correctly. Some info is still allowed to be emitted, +// but it can't have privacy/storage/battery impacts. +TEST_FOR_ALL_DUMPSTATE_MODES(TestVerboseLoggingDisabled, [this](DumpstateMode mode) { + DisableVerboseLogging(); // Index 0 corresponds to the read end of the pipe; 1 to the write end. int fds[2]; @@ -284,11 +285,10 @@ TEST_FOR_ALL_DUMPSTATE_MODES(TestDeviceLoggingDisabled, [this](DumpstateMode mod Return status = dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis); - AssertStatusForMode(mode, status, DumpstateStatus::DEVICE_LOGGING_NOT_ENABLED, [&fds]() { - // Check that nothing was written. Could return 0 or -1. - char buff; - ASSERT_NE(1, read(fds[0], &buff, 1)) << "Dumped something when device logging is disabled"; - }); + // We don't include additional assertions here about the file passed in. If verbose logging is + // disabled, the OEM may choose to include nothing at all, but it is allowed to include some + // essential information based on the mode as long as it isn't private user information. + AssertStatusForMode(mode, status, DumpstateStatus::OK); native_handle_close(handle); native_handle_delete(handle); @@ -296,22 +296,22 @@ TEST_FOR_ALL_DUMPSTATE_MODES(TestDeviceLoggingDisabled, [this](DumpstateMode mod // Double-enable is perfectly valid, but the second call shouldn't do anything. TEST_P(DumpstateHidl1_1Test, TestRepeatedEnable) { - EnableDeviceLogging(); - EnableDeviceLogging(); + EnableVerboseLogging(); + EnableVerboseLogging(); } // Double-disable is perfectly valid, but the second call shouldn't do anything. TEST_P(DumpstateHidl1_1Test, TestRepeatedDisable) { - DisableDeviceLogging(); - DisableDeviceLogging(); + DisableVerboseLogging(); + DisableVerboseLogging(); } // Toggling in short order is perfectly valid. TEST_P(DumpstateHidl1_1Test, TestRepeatedToggle) { - EnableDeviceLogging(); - DisableDeviceLogging(); - EnableDeviceLogging(); - DisableDeviceLogging(); + EnableVerboseLogging(); + DisableVerboseLogging(); + EnableVerboseLogging(); + DisableVerboseLogging(); } INSTANTIATE_TEST_SUITE_P( From b6809a06ad090807d1b0fe2e44d6aef06eb5d79d Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 13 Feb 2020 11:41:26 -0800 Subject: [PATCH 0578/1022] gralloc4-vts: update sampleIncrementInBits sampleIncrementInBits is per sample not per component. An RGBA sample is 32 bits not 8. Test: VtsHalGraphicsMapperV4_0 Bug: 149310539 Change-Id: If4bd5aac87cada7040f52ee40159a72fa72a97be --- .../4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index aa45e3bb8b..726df9357d 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -143,7 +143,7 @@ class GraphicsMapperHidlTest EXPECT_EQ(24, offsetInBitsA); EXPECT_EQ(0, planeLayout.offsetInBytes); - EXPECT_EQ(8, planeLayout.sampleIncrementInBits); + EXPECT_EQ(32, planeLayout.sampleIncrementInBits); // Skip testing stride because any stride is valid EXPECT_EQ(mDummyDescriptorInfo.width, planeLayout.widthInSamples); EXPECT_EQ(mDummyDescriptorInfo.height, planeLayout.heightInSamples); @@ -1384,7 +1384,7 @@ TEST_P(GraphicsMapperHidlTest, SetPlaneLayouts) { planeLayouts.push_back(planeLayoutA); planeLayoutRGB.offsetInBytes = 0; - planeLayoutRGB.sampleIncrementInBits = 32; + planeLayoutRGB.sampleIncrementInBits = 24; planeLayoutRGB.strideInBytes = info.width + 20; planeLayoutRGB.widthInSamples = info.width; planeLayoutRGB.heightInSamples = info.height; From 66d459ce8770315d9c2ec2f2e9e18c58b8eb3996 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 13 Feb 2020 11:44:32 -0800 Subject: [PATCH 0579/1022] gralloc4-vts: return after GTEST_SUCCEED GTEST_SUCCEED() does not cause a GTEST to return. Insert a return after every GTEST_SUCCEED(). Test: VtsHalGraphicsMapperV4_0 Bug: 149008032 Change-Id: I65637e7a0ac9a9ac8d69c9d8ccbb427543d82428 --- .../vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 726df9357d..58b7ed3688 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -97,6 +97,7 @@ class GraphicsMapperHidlTest Error err = mGralloc->set(bufferHandle, metadataType, metadata); if (err == Error::UNSUPPORTED) { GTEST_SUCCEED() << "setting this metadata is unsupported"; + return; } ASSERT_EQ(err, Error::NONE); @@ -920,6 +921,7 @@ TEST_P(GraphicsMapperHidlTest, GetProtectedContent) { bufferHandle = mGralloc->allocate(info, true, true); if (bufferHandle) { GTEST_SUCCEED() << "unable to allocate protected content"; + return; } hidl_vec vec; @@ -1237,6 +1239,7 @@ TEST_P(GraphicsMapperHidlTest, SetUsageProtected) { bufferHandle = mGralloc->allocate(info, true, true); if (bufferHandle) { GTEST_SUCCEED() << "unable to allocate protected content"; + return; } uint64_t usage = static_cast(BufferUsage::COMPOSER_OVERLAY); @@ -1280,6 +1283,7 @@ TEST_P(GraphicsMapperHidlTest, SetProtectedContent) { bufferHandle = mGralloc->allocate(info, true, true); if (bufferHandle) { GTEST_SUCCEED() << "unable to allocate protected content"; + return; } uint64_t protectedContent = 0; @@ -1407,6 +1411,7 @@ TEST_P(GraphicsMapperHidlTest, SetPlaneLayouts) { Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_PlaneLayouts, vec); if (err == Error::UNSUPPORTED) { GTEST_SUCCEED() << "setting this metadata is unsupported"; + return; } ASSERT_EQ(err, Error::NONE); @@ -1779,6 +1784,7 @@ TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatFourCC) { mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC, &vec); if (err == Error::UNSUPPORTED) { GTEST_SUCCEED() << "setting this metadata is unsupported"; + return; } ASSERT_EQ(err, Error::NONE); @@ -1795,6 +1801,7 @@ TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatModifier) { mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier, &vec); if (err == Error::UNSUPPORTED) { GTEST_SUCCEED() << "setting this metadata is unsupported"; + return; } ASSERT_EQ(err, Error::NONE); @@ -1824,6 +1831,7 @@ TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoAllocationSize) { gralloc4::MetadataType_AllocationSize, &vec); if (err == Error::UNSUPPORTED) { GTEST_SUCCEED() << "setting this metadata is unsupported"; + return; } ASSERT_EQ(err, Error::NONE); From 2b43a5debe88c7845d63488e7526990cac856fda Mon Sep 17 00:00:00 2001 From: Nicholas Ambur Date: Wed, 12 Feb 2020 11:19:48 -0800 Subject: [PATCH 0580/1022] update SoundTrigger queryParameter Update the documentation and usage when HAL implementation wants to convey the parameter ID is not supported. Bug: 141929369 Test: build and boot smoke test && verify unsupported parameter use case with test app Change-Id: I2124d8e5e9b136bd0797c16e71aa0b4049c9ed58 --- current.txt | 2 +- soundtrigger/2.3/ISoundTriggerHw.hal | 6 ++++-- soundtrigger/2.3/default/SoundTriggerHw.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/current.txt b/current.txt index 2fa5dcabab..75d2dda241 100644 --- a/current.txt +++ b/current.txt @@ -693,5 +693,5 @@ a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardwar 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication 0006ab8e8b0910cbd3bbb08d5f17d5fac7d65a2bdad5f2334e4851db9d1e6fa8 android.hardware.radio.config@1.3::IRadioConfigResponse 4a6517ea4ad807855428b0101d8e1a486497bd88ab4300ba3b2be43d46d32580 android.hardware.soundtrigger@2.3::types -12d7533ff0754f45bf59ab300799074570a99a676545652c2c23abc73cb4515d android.hardware.soundtrigger@2.3::ISoundTriggerHw +b37f78e3fdc79af8b32a545b2b426f1fd1355b359d9e7835f3bf1ed0aa4518d8 android.hardware.soundtrigger@2.3::ISoundTriggerHw 7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget diff --git a/soundtrigger/2.3/ISoundTriggerHw.hal b/soundtrigger/2.3/ISoundTriggerHw.hal index 270b00e44f..3e761e59b5 100644 --- a/soundtrigger/2.3/ISoundTriggerHw.hal +++ b/soundtrigger/2.3/ISoundTriggerHw.hal @@ -114,8 +114,10 @@ interface ISoundTriggerHw extends @2.2::ISoundTriggerHw { * @return status Operation completion status: 0 in case of success * -ENODEV if the native service cannot be reached * -EINVAL invalid input parameter - * @return retval ModelParameter structure indicating supported attributes - * of the parameter for the given model handle + * @return retval OptionalModelParameterRange safe union structure wrapping + * ModelParameterRange. This structure indicates supported attributes + * of the parameter for the given model handle. If the parameter is not + * supported the Monostate of the union is used. */ queryParameter(SoundModelHandle modelHandle, ModelParameter modelParam) generates (int32_t status, OptionalModelParameterRange retval); diff --git a/soundtrigger/2.3/default/SoundTriggerHw.cpp b/soundtrigger/2.3/default/SoundTriggerHw.cpp index d3136b9a63..8fe310803b 100644 --- a/soundtrigger/2.3/default/SoundTriggerHw.cpp +++ b/soundtrigger/2.3/default/SoundTriggerHw.cpp @@ -889,7 +889,7 @@ Return SoundTriggerHw::queryParameter(V2_0::SoundModelHandle modelHandle, int32_t status = mHwDevice->query_parameter( mHwDevice, client->getHalHandle(), convertModelParameterToHal(modelParam), ¶mRange); - if (status == 0) { + if (status == 0 && paramRange.is_supported) { optionalParamRange.range({.start = paramRange.start, .end = paramRange.end}); } _hidl_cb(status, optionalParamRange); From cee6a6759ae52de4069c5be4768a4ea5b50ccbce Mon Sep 17 00:00:00 2001 From: Sasha Kuznetsov Date: Tue, 11 Feb 2020 23:17:11 -0800 Subject: [PATCH 0581/1022] Clarify environment bearing docs in HAL Bug: 149299473 Test: build cuttlefish Change-Id: Ie565d7ec96282985505b41961321998e58554aff --- current.txt | 2 +- gnss/measurement_corrections/1.1/types.hal | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/current.txt b/current.txt index f6659e3273..bf7123e23d 100644 --- a/current.txt +++ b/current.txt @@ -656,7 +656,7 @@ ba5ac712b2a656dc07c83ab4a7a2c2f3bee1bbcb752e8b8ffa9b672f3b5b0728 android.hardwar 7913a11206a577b12ade86a7cf3f95c2639cb514d086673f279bf99238c9917e android.hardware.gnss@2.1::IGnssMeasurement 9999f2484f35ebfacdd433dfeae459f2a582334315959653ec8efde7699ec556 android.hardware.gnss@2.1::IGnssMeasurementCallback 6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections -a3f439b782a6a92aaf3c0250f3526e94e8bf8844c3d578f0815e21b12c431346 android.hardware.gnss.measurement_corrections@1.1::types +a28d6c29a7e36976acffb018208e65b3496d9152d57d864038556cdd83b35744 android.hardware.gnss.measurement_corrections@1.1::types ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types diff --git a/gnss/measurement_corrections/1.1/types.hal b/gnss/measurement_corrections/1.1/types.hal index 40b6f52b7d..f945c5785a 100644 --- a/gnss/measurement_corrections/1.1/types.hal +++ b/gnss/measurement_corrections/1.1/types.hal @@ -48,11 +48,20 @@ struct MeasurementCorrections { * If the road is curved in the vicinity of the user location, then * environmentBearingUncertaintyDegrees will include the amount by which the road direction * changes in the area of position uncertainty. + * + * hasEnvironmentBearing should be checked to verify the environment bearing is available + * before calling this method. The value is undefined if hasEnvironmentBearing is false. */ float environmentBearingDegrees; /** - * Bearing uncertainty [0 to 180]. + * Environment bearing uncertainty [0 to 180]. It represents the standard deviation of the + * physical structure in the circle of position uncertainty. hasEnvironmentBearing becomes false + * as the uncertainty value passes a predefined threshold depending on the physical structure + * around the user. + * + * hasEnvironmentBearing should be checked to verify the environment bearing is available + * before calling this method. The value is undefined if hasEnvironmentBearing is false. */ float environmentBearingUncertaintyDegrees; -}; \ No newline at end of file +}; From 99b6d96736f966c45377229909166cda4e2d4c34 Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Thu, 13 Feb 2020 14:19:09 -0800 Subject: [PATCH 0582/1022] Address ANAPIC review comments - GnssMeasurementFlags extends v1.0 - add gnssSetCapabilitiesCb_2_1 Fixes: 149501257 Test: VTS tests pass on cuttlefish Change-Id: I21dd284297d5f458945e7b5fa5e6ed0dab6a5dde --- current.txt | 4 +-- gnss/2.1/IGnssCallback.hal | 7 +++++ gnss/2.1/IGnssMeasurementCallback.hal | 38 +++++------------------ gnss/2.1/default/Gnss.cpp | 2 +- gnss/2.1/vts/functional/gnss_hal_test.cpp | 6 ++++ gnss/2.1/vts/functional/gnss_hal_test.h | 1 + 6 files changed, 24 insertions(+), 34 deletions(-) diff --git a/current.txt b/current.txt index 2fa5dcabab..1fcaa30ad1 100644 --- a/current.txt +++ b/current.txt @@ -651,10 +651,10 @@ f284ffde7cadf5a1364b75ab313baf22401eeca289bdde2a2dc7a27ea4ab98d7 android.hardwar 626db710bf917ecf551a0b0b1f25be10bf52758f43e0fc808b148b6aae2ef73e android.hardware.gnss@2.1::IGnss ba5ac712b2a656dc07c83ab4a7a2c2f3bee1bbcb752e8b8ffa9b672f3b5b0728 android.hardware.gnss@2.1::IGnssAntennaInfo 0bc3ed97cbc3f6abc89c68f4e9f4d124f9f723431997dc88c2186cf4d2ad47ee android.hardware.gnss@2.1::IGnssAntennaInfoCallback -50c5d009af76d65b3023a9d94ee519545e72cb7c59bc7166d768d6f00923774d android.hardware.gnss@2.1::IGnssCallback +3541d83adfeac16ee3e45d183a58dffe06012ccb5aa5bcd2e4f6eeae269f69cd android.hardware.gnss@2.1::IGnssCallback 737d750017738f0753d13ba01a3310e0161f294b8ae80b3fd63eaa227e9d9c66 android.hardware.gnss@2.1::IGnssConfiguration 7913a11206a577b12ade86a7cf3f95c2639cb514d086673f279bf99238c9917e android.hardware.gnss@2.1::IGnssMeasurement -9999f2484f35ebfacdd433dfeae459f2a582334315959653ec8efde7699ec556 android.hardware.gnss@2.1::IGnssMeasurementCallback +0a16e5913e94d995cfcf959a1c6f10b0b8e9dfdb5f45ac6e7244711ddd740272 android.hardware.gnss@2.1::IGnssMeasurementCallback 6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections a3f439b782a6a92aaf3c0250f3526e94e8bf8844c3d578f0815e21b12c431346 android.hardware.gnss.measurement_corrections@1.1::types ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth diff --git a/gnss/2.1/IGnssCallback.hal b/gnss/2.1/IGnssCallback.hal index f7b7477ad0..94be915fd6 100644 --- a/gnss/2.1/IGnssCallback.hal +++ b/gnss/2.1/IGnssCallback.hal @@ -35,6 +35,13 @@ interface IGnssCallback extends @2.0::IGnssCallback { ANTENNA_INFO = 1 << 11, }; + /** + * Callback to inform framework of the GNSS HAL implementation's capabilities. + * + * @param capabilities Capability parameter is a bit field of the Capabilities enum. + */ + gnssSetCapabilitiesCb_2_1(bitfield capabilities); + /** * Extends a GnssSvInfo, adding a basebandCN0DbHz. */ diff --git a/gnss/2.1/IGnssMeasurementCallback.hal b/gnss/2.1/IGnssMeasurementCallback.hal index 1aee272fde..0e6abbd5e5 100644 --- a/gnss/2.1/IGnssMeasurementCallback.hal +++ b/gnss/2.1/IGnssMeasurementCallback.hal @@ -28,31 +28,7 @@ interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback { /** * Flags to indicate what fields in GnssMeasurement are valid. */ - enum GnssMeasurementFlags : uint32_t { - /** - * A valid 'snr' is stored in the data structure. - */ - HAS_SNR = 1 << 0, - /** - * A valid 'carrier frequency' is stored in the data structure. - */ - HAS_CARRIER_FREQUENCY = 1 << 9, - /** - * A valid 'carrier cycles' is stored in the data structure. - */ - HAS_CARRIER_CYCLES = 1 << 10, - /** - * A valid 'carrier phase' is stored in the data structure. - */ - HAS_CARRIER_PHASE = 1 << 11, - /** - * A valid 'carrier phase uncertainty' is stored in the data structure. - */ - HAS_CARRIER_PHASE_UNCERTAINTY = 1 << 12, - /** - * A valid automatic gain control is stored in the data structure. - */ - HAS_AUTOMATIC_GAIN_CONTROL = 1 << 13, + enum GnssMeasurementFlags : @1.0::IGnssMeasurementCallback.GnssMeasurementFlags { /** * A valid receiver inter-signal bias is stored in the data structure. */ @@ -104,8 +80,8 @@ interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback { * The receiver inter-signal bias (ISB) in nanoseconds. * * This value is the estimated receiver-side inter-system (different from the constellation - * in GnssClock.referenceSignalForIsb) bias and inter-frequency (different from the carrier - * frequency in GnssClock.referenceSignalForIsb) bias. The reported receiver ISB + * in GnssClock.referenceSignalTypeForIsb) bias and inter-frequency (different from the + * carrier frequency in GnssClock.referenceSignalTypeForIsb) bias. The reported receiver ISB * must include signal delays caused by * * - Receiver inter-constellation bias @@ -114,7 +90,7 @@ interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback { * * The value does not include the inter-frequency Ionospheric bias. * - * The receiver ISB of GnssClock.referenceSignalForIsb is defined to be 0.0 nanoseconds. + * The receiver ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds. */ double receiverInterSignalBiasNs; @@ -127,8 +103,8 @@ interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback { * The satellite inter-signal bias in nanoseconds. * * This value is the satellite-and-control-segment-side inter-system (different from the - * constellation in GnssClock.referenceSignalForIsb) bias and inter-frequency (different - * from the carrier frequency in GnssClock.referenceSignalForIsb) bias, including: + * constellation in GnssClock.referenceSignalTypeForIsb) bias and inter-frequency (different + * from the carrier frequency in GnssClock.referenceSignalTypeForIsb) bias, including: * * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPT-UTC Time Offset (TauGps), * BDS-GLO Time Offset (BGTO)) @@ -136,7 +112,7 @@ interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback { * - Satellite inter-signal bias, which includes satellite inter-frequency bias (GLO only), * and satellite inter-code bias (e.g., Differential Code Bias (DCB)). * - * The receiver ISB of GnssClock.referenceSignalForIsb is defined to be 0.0 nanoseconds. + * The receiver ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds. */ double satelliteInterSignalBiasNs; diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp index c1af103f36..2b327a9916 100644 --- a/gnss/2.1/default/Gnss.cpp +++ b/gnss/2.1/default/Gnss.cpp @@ -339,7 +339,7 @@ Return Gnss::setCallback_2_1(const sp& callback) { const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS | Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST | Capabilities::ANTENNA_INFO; - auto ret = sGnssCallback_2_1->gnssSetCapabilitiesCb_2_0(capabilities); + auto ret = sGnssCallback_2_1->gnssSetCapabilitiesCb_2_1(capabilities); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); } diff --git a/gnss/2.1/vts/functional/gnss_hal_test.cpp b/gnss/2.1/vts/functional/gnss_hal_test.cpp index 83c4c3cd10..da7a62b4bd 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test.cpp +++ b/gnss/2.1/vts/functional/gnss_hal_test.cpp @@ -215,6 +215,12 @@ Return GnssHalTest::GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capab return Void(); } +Return GnssHalTest::GnssCallback::gnssSetCapabilitiesCb_2_1(uint32_t capabilities) { + ALOGI("Capabilities (v2.1) received %d", capabilities); + capabilities_cbq_.store(capabilities); + return Void(); +} + Return GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) { ALOGI("Name received: %s", name.c_str()); name_cbq_.store(name); diff --git a/gnss/2.1/vts/functional/gnss_hal_test.h b/gnss/2.1/vts/functional/gnss_hal_test.h index 3472edb907..9e6e162a13 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test.h +++ b/gnss/2.1/vts/functional/gnss_hal_test.h @@ -109,6 +109,7 @@ class GnssHalTest : public testing::TestWithParam { // New in v2.1 Return gnssSvStatusCb_2_1( const hidl_vec& svInfoList) override; + Return gnssSetCapabilitiesCb_2_1(uint32_t capabilities) override; private: Return gnssLocationCbImpl(const GnssLocation_2_0& location); From 428d25abfdef88d9eb7d1df565c99eb0557763e8 Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Fri, 14 Feb 2020 11:15:48 -0800 Subject: [PATCH 0583/1022] Update measurement_correction reported accuracy HAL doc Fixes: 144817918 Test: doc only and builds Change-Id: I5aed4a17b5dea8949904f08809d3df9ec250fbeb --- current.txt | 1 + gnss/measurement_corrections/1.0/types.hal | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/current.txt b/current.txt index 2fa5dcabab..5cbb406ad4 100644 --- a/current.txt +++ b/current.txt @@ -588,6 +588,7 @@ d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardwar cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types a05277065c28ebecd58118bd240fb8c55757361e8648c01f7c4dacdb7f2a95dc android.hardware.camera.metadata@3.3::types 9cb3df2bde2c6cd5fd96b7c41555420cacd7e276a556c684af91b7461c86460f android.hardware.gnss@1.0::IGnssCallback +af334f1fc85c62b343f84b74d0495eed6f495f7fecedb53463db10c202310058 android.hardware.gnss.measurement_corrections@1.0::types bceee81ec1b59324abd05932b5620fda5a6589597c9cb3953ba7f3ea02cccd3e android.hardware.camera.provider@2.4::ICameraProvider 2ce820dc4f3c6d85721b65150ed2157c6e2e2055f866fb6c6ba4790f14408d66 android.hardware.camera.provider@2.4::ICameraProviderCallback b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice diff --git a/gnss/measurement_corrections/1.0/types.hal b/gnss/measurement_corrections/1.0/types.hal index edf26bf7c0..3d7ab0f09c 100644 --- a/gnss/measurement_corrections/1.0/types.hal +++ b/gnss/measurement_corrections/1.0/types.hal @@ -92,16 +92,16 @@ struct MeasurementCorrections { double altitudeMeters; /** - * Represents the horizontal uncertainty (68% confidence) in meters on the device position at - * which the corrections are provided. + * Represents the horizontal uncertainty (63% to 68% confidence) in meters on the device + * position at which the corrections are provided. * * This value is useful for example to judge how accurate the provided corrections are. */ double horizontalPositionUncertaintyMeters; /** - * Represents the vertical uncertainty (68% confidence) in meters on the device position at - * which the corrections are provided. + * Represents the vertical uncertainty (63% to 68% confidence) in meters on the device position + * at which the corrections are provided. * * This value is useful for example to judge how accurate the provided corrections are. */ From afb6d8fdf4318aa185f996c8d09ab55425cd7b1a Mon Sep 17 00:00:00 2001 From: Jim Kaye Date: Wed, 12 Feb 2020 12:55:14 -0800 Subject: [PATCH 0584/1022] Clean up descriptions of power states Clarify the descriptions of VehicleApPowerStateReq and VehicleApPowerStateReport. Fixes: 128841180 Test: None. Documentation only. Change-Id: Icbe86e2e6a761e37adf2689596eb81bb68295fa7 --- automotive/vehicle/2.0/types.hal | 121 +++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 38 deletions(-) diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index bce42b9fca..cbd9e2883a 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -65,8 +65,8 @@ enum VehiclePropertyType : int32_t { * particular door, thus this property must be marked with * VehicleArea:DOOR flag. * - * Other properties may not be associated with particular vehicle area, - * these kind of properties must have VehicleArea:GLOBAL flag. + * Other properties may not be associated with particular vehicle area. + * These kinds of properties must have VehicleArea:GLOBAL flag. * * [Definition] Area: An area represents a unique element of an AreaType. * For instance, if AreaType is WINDOW, then an area may be FRONT_WINDSHIELD. @@ -79,9 +79,9 @@ enum VehiclePropertyType : int32_t { * Rules for mapping a zoned property to AreaIDs: * - A property must be mapped to an array of AreaIDs that are impacted when * the property value changes. - * - Each element in the array must represent an AreaID, in which, the + * - Each element in the array must represent an AreaID, in which the * property value can only be changed together in all the areas within - * an AreaID and never independently. That is, when the property value + * the AreaID and never independently. That is, when the property value * changes in one of the areas in an AreaID in the array, then it must * automatically change in all other areas in the AreaID. * - The property value must be independently controllable in any two @@ -140,7 +140,7 @@ enum VehiclePropertyGroup : int32_t { * - vehicle area (VehicleArea) * * Vendors are allowed to extend this enum with their own properties. In this - * case they must use VehiclePropertyGroup:VENDOR flag when property is + * case they must use VehiclePropertyGroup:VENDOR flag when the property is * declared. * * When a property's status field is not set to AVAILABLE: @@ -3041,26 +3041,52 @@ enum VehicleApPowerStateConfigFlag : int32_t { }; enum VehicleApPowerStateReq : int32_t { - /** Transition Android from WAIT_FOR_VHAL to ON state */ + /** + * This requests Android to enter its normal operating state. + * This may be sent after the AP has reported + * VehicleApPowerStateReport#DEEP_SLEEP_EXIT, + * VehicleApPowerStateReport#SHUTDOWN_CANCELLED, or + * VehicleApPowerStateReport#WAIT_FOR_VHAL. + */ ON = 0, /** - * The power controller has requested AP to shutdown. AP can either enter - * sleep state or start full shutdown. AP can also request postponing - * shutdown by sending VehicleApPowerSetState#SHUTDOWN_POSTPONE message. The - * power controller must change power state to this state to shutdown - * system. + * The power controller issues this request to shutdown the system. + * This may be sent after the AP has reported + * VehicleApPowerStateReport#DEEP_SLEEP_EXIT, + * VehicleApPowerStateReport#ON, + * VehicleApPowerStateReport#SHUTDOWN_CANCELLED, + * VehicleApPowerStateReport#SHUTDOWN_POSTPONE, + * VehicleApPowerStateReport#SHUTDOWN_PREPARE, or + * VehicleApPowerStateReport#WAIT_FOR_VHAL. * - * int32Values[1] : one of VehicleApPowerStateShutdownParam - * - * SHUTDOWN_PRPARE may be requested from either WAIT_FOR_VHAL or ON states. + * int32Values[1] : One of VehicleApPowerStateShutdownParam. + * This parameter indicates if the AP should shut + * down fully or sleep. This parameter also + * indicates if the shutdown should be immediate + * or if it can be postponed. If the shutdown can + * be postponed, AP requests postponing by sending + * VehicleApPowerStateReport#SHUTDOWN_POSTPONE. */ SHUTDOWN_PREPARE = 1, - /** Cancel the shutdown and transition from SHUTDOWN_PREPARE to WAIT_FOR_VHAL state */ + /** + * Cancel the shutdown. + * This may be sent after the AP has reported + * VehicleApPowerStateReport#SHUTDOWN_POSTPONE or + * VehicleApPowerStateReport#SHUTDOWN_PREPARE. + * After receiving this request, the AP will report + * VehicleApPowerStateReport#WAIT_FOR_VHAL in preparation to going ON. + */ CANCEL_SHUTDOWN = 2, - /** VHAL is finished with shutdown procedures and ready for Android to suspend/shutdown */ + /** + * Completes the shutdown process. + * This may be sent after the AP has reported + * VehicleApPowerStateReport#DEEP_SLEEP_ENTRY or + * VehicleApPowerStateReport#SHUTDOWN_START. The AP will not report new + * state information after receiving this request. + */ FINISHED = 3, }; @@ -3092,61 +3118,80 @@ enum VehicleApPowerStateShutdownParam : int32_t { enum VehicleApPowerStateReport : int32_t { /** - * Device has booted, CarService has initialized and is ready to accept commands from VHAL. - * Device starts in WAIT_FOR_VHAL state. The user is not logged in, and vendor apps/services - * are expected to control the display and audio. + * The device has booted. CarService has initialized and is ready to accept commands + * from VHAL. The user is not logged in, and vendor apps and services are expected to + * control the display and audio. + * After reporting this state, AP will accept VehicleApPowerStateReq#ON or + * VehicleApPowerStateReq#SHUTDOWN_PREPARE. Other power state requests are ignored. */ WAIT_FOR_VHAL = 0x1, /** - * AP is ready to suspend and has entered WAIT_FOR_FINISHED state. + * AP is ready to suspend. + * The AP will not send any more state reports after this. + * After reporting this state, AP will accept VehicleApPowerStateReq#FINISHED. + * Other power state requests are ignored. * - * int32Values[1]: Time to turn on AP in secs. Power controller may turn on - * AP after specified time so that AP can run tasks like - * update. If it is set to 0, there is no wake up, and power - * controller may not necessarily support wake-up. + * int32Values[1]: Time to turn AP back on, in seconds. Power controller should turn on + * AP after the specified time has elapsed, so AP can run tasks like + * update. If this value is 0, no wake up is requested. The power + * controller may not necessarily support timed wake-up. */ DEEP_SLEEP_ENTRY = 0x2, /** - * AP is exiting from deep sleep state, and is in WAIT_FOR_VHAL state. + * AP is exiting from deep sleep state. + * After reporting this state, AP will accept VehicleApPowerStateReq#ON or + * VehicleApPowerStateReq#SHUTDOWN_PREPARE. Other power state requests are ignored. */ DEEP_SLEEP_EXIT = 0x3, /** - * AP remains in SHUTDOWN_PREPARE state as idle and cleanup tasks execute. + * AP sends this message repeatedly while cleanup and idle tasks execute. + * After reporting this state, AP will accept VehicleApPowerStateReq#SHUTDOWN_PREPARE + * requesting immediate shutdown or VehicleApPowerStateReq#CANCEL_SHUTDOWN. Other + * power state requests are ignored. * - * int32Values[1]: Time to postpone shutdown in ms. Maximum value can be + * int32Values[1]: Time to postpone shutdown in ms. Maximum value is * 5000 ms. - * If AP needs more time, it will send another POSTPONE + * If AP needs more time, it will send another SHUTDOWN_POSTPONE * message before the previous one expires. */ SHUTDOWN_POSTPONE = 0x4, /** - * AP is ready to shutdown and has entered WAIT_FOR_FINISHED state. + * AP is ready to shutdown. + * The AP will not send any more state reports after this. + * After reporting this state, AP will accept VehicleApPowerStateReq#FINISHED. + * Other power state requests are ignored. * - * int32Values[1]: Time to turn on AP in secs. Power controller may turn on - * AP after specified time so that AP can run tasks like - * update. If it is set to 0, there is no wake up, and power - * controller may not necessarily support wake-up. + * int32Values[1]: Time to turn AP back on, in seconds. Power controller should turn on + * AP after the specified time has elapsed so AP can run tasks like + * update. If this value is 0, no wake up is specified. The power + * controller may not necessarily support timed wake-up. */ SHUTDOWN_START = 0x5, /** - * AP has transitioned from WAIT_FOR_VHAL state to ON. + * AP is entering its normal operating state. + * After reporting this state, AP will accept VehicleApPowerStateReq#SHUTDOWN_PREPARE. + * Other power state requests are ignored. */ ON = 0x6, /** - * AP has transitions to SHUTDOWN_PREPARE state. In this state, Garage Mode will execute idle - * tasks, and other services that have registered for this state transition may execute - * cleanup activities. + * AP is preparing to shut down. In this state, Garage Mode is active and idle + * tasks are allowed to run. + * After reporting this state, AP will accept VehicleApPowerStateReq#SHUTDOWN_PREPARE + * requesting immediate shutdown or VehicleApPowerStateReq#CANCEL_SHUTDOWN. Other + * power state requests are ignored. */ SHUTDOWN_PREPARE = 0x7, /** - * AP has transitioned from SHUTDOWN_PREPARE state to WAIT_FOR_VHAL. + * AP has stopped preparing to shut down. + * After reporting this state, AP will accept VehicleApPowerStateReq#ON or + * VehicleApPowerStateReq#SHUTDOWN_PREPARE. Other power state requests are ignored. */ SHUTDOWN_CANCELLED = 0x8, }; From 460b9610bf3665f3d42d1cd67228ec799695259b Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Thu, 13 Feb 2020 17:02:29 -0800 Subject: [PATCH 0585/1022] Add comments for invalid IP/port and add Invalid filterID/avSyncId To allow client to identify and specify invalid value bug: 148110220 Test: Manual Change-Id: Ib5e88a13cdcca0b62f55fab992293ed17e0ed708 --- tv/tuner/1.0/types.hal | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index e4874f4e69..dd2b48facb 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -1924,7 +1924,7 @@ safe_union DemuxPid { }; @export -enum Constant : uint16_t { +enum Constant : uint32_t { /** * An invalid packet ID in transport stream according to ISO/IEC 13818-1. */ @@ -1933,6 +1933,14 @@ enum Constant : uint16_t { * An invalid Stream ID. */ INVALID_STREAM_ID = 0xFFFF, + /** + * An invalid Filter ID. + */ + INVALID_FILTER_ID = 0xFFFFFFFF, + /** + * An invalid AV sync hardware ID. + */ + INVALID_AV_SYNC_ID = 0xFFFFFFFF, }; /** @@ -2151,19 +2159,37 @@ struct DemuxFilterDownloadSettings { */ struct DemuxIpAddress { safe_union SrcIpAddress { + /** + * 0.0.0.0 is invalid. should be ignored. + */ uint8_t[4] v4; + /** + * 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 is invalid. should be ignored. + */ uint8_t[16] v6; } srcIpAddress; safe_union DstIpAddress { + /** + * 0.0.0.0 is invalid. should be ignored. + */ uint8_t[4] v4; + /** + * 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 is invalid. should be ignored. + */ uint8_t[16] v6; } dstIpAddress; + /** + * 0 is invalid. should be ignored. + */ uint16_t srcPort; + /** + * 0 is invalid. should be ignored. + */ uint16_t dstPort; }; From 043a7a027f1b9e3663c7c4147a1b1609a3e6eb81 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Thu, 2 Jan 2020 17:55:55 -0800 Subject: [PATCH 0586/1022] Add a method to support multi-display usages - Add getDisplayIdList() and openDisplay_1_1() to IEvsEnumerator. - Add getDisplayInfo_1_1() to IEvsDisplay. - Update CameraToDisplayRountTrip test case to use new methods. - Update default implementation. Bug: 141886260 Bug: 146567078 Bug: 147553536 Test: VtsHalEvsV1_1TargetTest Change-Id: I3c17aecc482770074159f7ccaf8e00cadf711e76 Signed-off-by: Changyeon Jo --- automotive/evs/1.1/Android.bp | 2 + automotive/evs/1.1/IEvsDisplay.hal | 35 +++++++++++ automotive/evs/1.1/IEvsEnumerator.hal | 22 +++++++ automotive/evs/1.1/default/Android.bp | 4 ++ automotive/evs/1.1/default/EvsCamera.cpp | 2 +- automotive/evs/1.1/default/EvsCamera.h | 7 ++- automotive/evs/1.1/default/EvsDisplay.cpp | 21 +++++++ automotive/evs/1.1/default/EvsDisplay.h | 12 +++- automotive/evs/1.1/default/EvsEnumerator.cpp | 61 ++++++++++++++++++- automotive/evs/1.1/default/EvsEnumerator.h | 19 ++++-- automotive/evs/1.1/default/service.cpp | 1 - .../functional/VtsHalEvsV1_1TargetTest.cpp | 35 +++++++++-- 12 files changed, 201 insertions(+), 20 deletions(-) create mode 100644 automotive/evs/1.1/IEvsDisplay.hal diff --git a/automotive/evs/1.1/Android.bp b/automotive/evs/1.1/Android.bp index c850c91b21..17f31e4dd0 100644 --- a/automotive/evs/1.1/Android.bp +++ b/automotive/evs/1.1/Android.bp @@ -10,9 +10,11 @@ hidl_interface { "types.hal", "IEvsCamera.hal", "IEvsCameraStream.hal", + "IEvsDisplay.hal", "IEvsEnumerator.hal", ], interfaces: [ + "android.frameworks.automotive.display@1.0", "android.hardware.automotive.evs@1.0", "android.hardware.camera.device@3.2", "android.hardware.graphics.common@1.0", diff --git a/automotive/evs/1.1/IEvsDisplay.hal b/automotive/evs/1.1/IEvsDisplay.hal new file mode 100644 index 0000000000..38da536189 --- /dev/null +++ b/automotive/evs/1.1/IEvsDisplay.hal @@ -0,0 +1,35 @@ +/* + * Copyright 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. + */ + +package android.hardware.automotive.evs@1.1; + +import @1.0::IEvsDisplay; +import @1.0::EvsResult; +import android.frameworks.automotive.display@1.0::HwDisplayConfig; +import android.frameworks.automotive.display@1.0::HwDisplayState; + +/** + * Represents a single display. + */ +interface IEvsDisplay extends @1.0::IEvsDisplay { + /** + * Returns the description of this display. + * + * @return cfg Current configuration of this display. + * @return state Current state of this display. + */ + getDisplayInfo_1_1() generates (HwDisplayConfig cfg, HwDisplayState state); +}; diff --git a/automotive/evs/1.1/IEvsEnumerator.hal b/automotive/evs/1.1/IEvsEnumerator.hal index 7752b0e330..84dd21f92a 100644 --- a/automotive/evs/1.1/IEvsEnumerator.hal +++ b/automotive/evs/1.1/IEvsEnumerator.hal @@ -17,6 +17,7 @@ package android.hardware.automotive.evs@1.1; import IEvsCamera; +import IEvsDisplay; import @1.0::IEvsEnumerator; import @1.0::EvsResult; import android.hardware.camera.device@3.2::Stream; @@ -54,4 +55,25 @@ interface IEvsEnumerator extends @1.0::IEvsEnumerator { * @return result False for EVS manager implementations and true for all others. */ isHardware() generates (bool result); + + /** + * Returns a list of all EVS displays available to the system + * + * @return displayIds Identifiers of available displays. + */ + getDisplayIdList() generates (vec displayIds); + + /** + * Get exclusive access to IEvsDisplay for the system + * + * There can be more than one EVS display objects for the system and this function + * requests access to the display identified by a given ID. If the target EVS display + * is not available or is already in use the old instance shall be closed and give + * the new caller exclusive access. + * When done using the display, the caller may release it by calling closeDisplay(). + * + * @param id Target display identifier. + * @return display EvsDisplay object to be used. + */ + openDisplay_1_1(uint8_t id) generates (IEvsDisplay display); }; diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp index a7c7b4282b..a35c9db254 100644 --- a/automotive/evs/1.1/default/Android.bp +++ b/automotive/evs/1.1/default/Android.bp @@ -27,6 +27,10 @@ cc_binary { "libutils", "libcamera_metadata", "libtinyxml2", + "android.hidl.token@1.0-utils", + "android.frameworks.automotive.display@1.0", + "android.hardware.graphics.bufferqueue@1.0", + "android.hardware.graphics.bufferqueue@2.0", ], cflags: [ diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp index b7e4efac02..f9cdb881d8 100644 --- a/automotive/evs/1.1/default/EvsCamera.cpp +++ b/automotive/evs/1.1/default/EvsCamera.cpp @@ -280,7 +280,7 @@ Return EvsCamera::setMaster() { return EvsResult::OK; } -Return EvsCamera::forceMaster(const sp& ) { +Return EvsCamera::forceMaster(const sp& ) { // Default implementation does not expect multiple subscribers and therefore // return a success code always. return EvsResult::OK; diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h index 72a1b5776b..a49db46521 100644 --- a/automotive/evs/1.1/default/EvsCamera.h +++ b/automotive/evs/1.1/default/EvsCamera.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include @@ -33,7 +33,8 @@ using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCam using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream; using ::android::hardware::automotive::evs::V1_0::EvsResult; using ::android::hardware::automotive::evs::V1_0::CameraDesc; -using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; +using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay; +using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay; namespace android { @@ -68,7 +69,7 @@ public: Return resumeVideoStream() override; Return doneWithFrame_1_1(const hidl_vec& buffer) override; Return setMaster() override; - Return forceMaster(const sp& display) override; + Return forceMaster(const sp& display) override; Return unsetMaster() override; Return getParameterList(getParameterList_cb _hidl_cb) override; Return getIntParameterRange(CameraParam id, diff --git a/automotive/evs/1.1/default/EvsDisplay.cpp b/automotive/evs/1.1/default/EvsDisplay.cpp index 74c099ac30..2b5a4a977c 100644 --- a/automotive/evs/1.1/default/EvsDisplay.cpp +++ b/automotive/evs/1.1/default/EvsDisplay.cpp @@ -21,6 +21,8 @@ #include #include +using ::android::frameworks::automotive::display::V1_0::HwDisplayConfig; +using ::android::frameworks::automotive::display::V1_0::HwDisplayState; namespace android { namespace hardware { @@ -31,6 +33,13 @@ namespace implementation { EvsDisplay::EvsDisplay() { + EvsDisplay(nullptr, 0); +} + + +EvsDisplay::EvsDisplay(sp pDisplayProxy, uint64_t displayId) + : mDisplayProxy(pDisplayProxy), + mDisplayId(displayId) { ALOGD("EvsDisplay instantiated"); // Set up our self description @@ -327,6 +336,18 @@ Return EvsDisplay::returnTargetBufferForDisplay(const BufferDesc_1_0& } +Return EvsDisplay::getDisplayInfo_1_1(getDisplayInfo_1_1_cb _info_cb) { + if (mDisplayProxy != nullptr) { + return mDisplayProxy->getDisplayInfo(mDisplayId, _info_cb); + } else { + HwDisplayConfig nullConfig; + HwDisplayState nullState; + _info_cb(nullConfig, nullState); + return Void(); + } +} + + } // namespace implementation } // namespace V1_1 } // namespace evs diff --git a/automotive/evs/1.1/default/EvsDisplay.h b/automotive/evs/1.1/default/EvsDisplay.h index 2a5653500f..9b2ed90128 100644 --- a/automotive/evs/1.1/default/EvsDisplay.h +++ b/automotive/evs/1.1/default/EvsDisplay.h @@ -17,14 +17,16 @@ #ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSDISPLAY_H #define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSDISPLAY_H -#include +#include +#include #include -using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; +using ::android::hardware::automotive::evs::V1_1::IEvsDisplay; using ::android::hardware::automotive::evs::V1_0::DisplayDesc; using ::android::hardware::automotive::evs::V1_0::DisplayState; using ::android::hardware::automotive::evs::V1_0::EvsResult; using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc; +using android::frameworks::automotive::display::V1_0::IAutomotiveDisplayProxyService; namespace android { namespace hardware { @@ -43,9 +45,12 @@ public: Return getTargetBuffer(getTargetBuffer_cb _hidl_cb) override; Return returnTargetBufferForDisplay(const BufferDesc_1_0& buffer) override; + // Methods from ::android::hardware::automotive::evs::V1_1::IEvsDisplay follow. + Return getDisplayInfo_1_1(getDisplayInfo_1_1_cb _info_cb) override; // Implementation details EvsDisplay(); + EvsDisplay(sp pDisplayProxy, uint64_t displayId); virtual ~EvsDisplay() override; void forceShutdown(); // This gets called if another caller "steals" ownership of the display @@ -60,6 +65,9 @@ private: DisplayState mRequestedState = DisplayState::NOT_VISIBLE; std::mutex mAccessLock; + + sp mDisplayProxy; + uint64_t mDisplayId; }; } // namespace implementation diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp index cb7403a7da..0319560ee6 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.cpp +++ b/automotive/evs/1.1/default/EvsEnumerator.cpp @@ -34,18 +34,38 @@ namespace implementation { std::list EvsEnumerator::sCameraList; wp EvsEnumerator::sActiveDisplay; unique_ptr EvsEnumerator::sConfigManager; +sp EvsEnumerator::sDisplayProxyService; +std::unordered_map EvsEnumerator::sDisplayPortList; -EvsEnumerator::EvsEnumerator() { +EvsEnumerator::EvsEnumerator(sp windowService) { ALOGD("EvsEnumerator created"); // Add sample camera data to our list of cameras // In a real driver, this would be expected to can the available hardware sConfigManager = ConfigManager::Create("/vendor/etc/automotive/evs/evs_default_configuration.xml"); + + // Add available cameras for (auto v : sConfigManager->getCameraList()) { sCameraList.emplace_back(v.c_str()); } + + if (sDisplayProxyService == nullptr) { + /* sets a car-window service handle */ + sDisplayProxyService = windowService; + } + + // Add available displays + if (sDisplayProxyService != nullptr) { + // Get a display ID list. + sDisplayProxyService->getDisplayIdList([](const auto& displayIds) { + for (const auto& id : displayIds) { + const auto port = id & 0xF; + sDisplayPortList.insert_or_assign(port, id); + } + }); + } } @@ -165,7 +185,7 @@ Return EvsEnumerator::closeCamera(const ::android::sp& pCa } -Return> EvsEnumerator::openDisplay() { +Return> EvsEnumerator::openDisplay() { ALOGD("openDisplay"); // If we already have a display active, then we need to shut it down so we can @@ -185,7 +205,42 @@ Return> EvsEnumerator::openDisplay() { } -Return EvsEnumerator::closeDisplay(const ::android::sp& pDisplay) { +Return EvsEnumerator::getDisplayIdList(getDisplayIdList_cb _list_cb) { + hidl_vec ids; + + ids.resize(sDisplayPortList.size()); + unsigned i = 0; + for (const auto& [port, id] : sDisplayPortList) { + ids[i++] = port; + } + + _list_cb(ids); + return Void(); +} + + +Return> EvsEnumerator::openDisplay_1_1(uint8_t port) { + ALOGD("%s", __FUNCTION__); + + // If we already have a display active, then we need to shut it down so we can + // give exclusive access to the new caller. + sp pActiveDisplay = sActiveDisplay.promote(); + if (pActiveDisplay != nullptr) { + ALOGW("Killing previous display because of new caller"); + closeDisplay(pActiveDisplay); + } + + // Create a new display interface and return it + pActiveDisplay = new EvsDisplay(sDisplayProxyService, sDisplayPortList[port]); + sActiveDisplay = pActiveDisplay; + + ALOGD("Returning new EvsDisplay object %p", pActiveDisplay.get()); + return pActiveDisplay; +} + + + +Return EvsEnumerator::closeDisplay(const ::android::sp& pDisplay) { ALOGD("closeDisplay"); // Do we still have a display object we think should be active? diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h index ca35dc6f8a..9415953a27 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.h +++ b/automotive/evs/1.1/default/EvsEnumerator.h @@ -19,19 +19,22 @@ #include #include +#include +#include #include #include "ConfigManager.h" using ::android::hardware::automotive::evs::V1_0::EvsResult; -using ::android::hardware::automotive::evs::V1_0::IEvsDisplay; using ::android::hardware::automotive::evs::V1_0::DisplayState; using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera; using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera; using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc; using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc; - +using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay; +using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay; +using android::frameworks::automotive::display::V1_0::IAutomotiveDisplayProxyService; namespace android { namespace hardware { @@ -51,8 +54,8 @@ public: Return getCameraList(getCameraList_cb _hidl_cb) override; Return> openCamera(const hidl_string& cameraId) override; Return closeCamera(const ::android::sp& carCamera) override; - Return> openDisplay() override; - Return closeDisplay(const ::android::sp& display) override; + Return> openDisplay() override; + Return closeDisplay(const ::android::sp& display) override; Return getDisplayState() override; // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow. @@ -60,9 +63,11 @@ public: Return> openCamera_1_1(const hidl_string& cameraId, const Stream& streamCfg) override; Return isHardware() override { return true; } + Return getDisplayIdList(getDisplayIdList_cb _list_cb) override; + Return> openDisplay_1_1(uint8_t port) override; // Implementation details - EvsEnumerator(); + EvsEnumerator(sp windowService = nullptr); private: // NOTE: All members values are static so that all clients operate on the same state @@ -83,6 +88,10 @@ private: static wp sActiveDisplay; static unique_ptr sConfigManager; + + static sp sDisplayProxyService; + static std::unordered_map sDisplayPortList; }; } // namespace implementation diff --git a/automotive/evs/1.1/default/service.cpp b/automotive/evs/1.1/default/service.cpp index 5135864e88..374b646812 100644 --- a/automotive/evs/1.1/default/service.cpp +++ b/automotive/evs/1.1/default/service.cpp @@ -34,7 +34,6 @@ using android::hardware::joinRpcThreadpool; // Generated HIDL files using android::hardware::automotive::evs::V1_1::IEvsEnumerator; -using android::hardware::automotive::evs::V1_0::IEvsDisplay; // The namespace in which all our implementation code lives using namespace android::hardware::automotive::evs::V1_1::implementation; diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index 1a622452da..ce02973ac2 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -54,9 +54,11 @@ static const float kNanoToSeconds = 0.000000001f; #include #include #include -#include +#include #include #include +#include +#include #include #include @@ -76,6 +78,8 @@ using ::android::hardware::automotive::evs::V1_0::DisplayState; using ::android::hardware::graphics::common::V1_0::PixelFormat; using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera; using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera; +using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay; +using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay; /* * Plese note that this is different from what is defined in @@ -567,9 +571,30 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { // output format. Stream nullCfg = {}; - // Request exclusive access to the EVS display - sp pDisplay = pEnumerator->openDisplay(); + // Request available display IDs + uint8_t targetDisplayId = 0; + pEnumerator->getDisplayIdList([&targetDisplayId](auto ids) { + ASSERT_GT(ids.size(), 0); + targetDisplayId = ids[0]; + }); + + // Request exclusive access to the first EVS display + sp pDisplay = pEnumerator->openDisplay_1_1(targetDisplayId); ASSERT_NE(pDisplay, nullptr); + ALOGI("Display %d is in use.", targetDisplayId); + + // Get the display descriptor + pDisplay->getDisplayInfo_1_1([](const auto& config, const auto& state) { + android::DisplayConfig* pConfig = (android::DisplayConfig*)config.data(); + const auto width = pConfig->resolution.getWidth(); + const auto height = pConfig->resolution.getHeight(); + ALOGI(" Resolution: %dx%d", width, height); + ASSERT_GT(width, 0); + ASSERT_GT(height, 0); + + android::ui::DisplayState* pState = (android::ui::DisplayState*)state.data(); + ASSERT_NE(pState->layerStack, -1); + }); // Test each reported camera for (auto&& cam: cameraInfo) { @@ -1556,7 +1581,7 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { Stream nullCfg = {}; // Request exclusive access to the EVS display - sp pDisplay = pEnumerator->openDisplay(); + sp pDisplay = pEnumerator->openDisplay(); ASSERT_NE(pDisplay, nullptr); // Test each reported camera @@ -1920,7 +1945,7 @@ TEST_F(EvsHidlTest, CameraUseStreamConfigToDisplay) { loadCameraList(); // Request exclusive access to the EVS display - sp pDisplay = pEnumerator->openDisplay(); + sp pDisplay = pEnumerator->openDisplay(); ASSERT_NE(pDisplay, nullptr); // Test each reported camera From 93594abef30dc2bf17ce0478c01d5585f1272ca3 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Mon, 17 Feb 2020 13:28:56 -0800 Subject: [PATCH 0587/1022] Add the camera extended info getter/setter methods This change declares and implement newer version of methods to manage vendor-defined camera extended information. Bug: 142888670 Test: m -j android.hardware.automotive.evs@1.1-service Change-Id: If6baf9cea7eefd13fd269ca8bb5af715cc3a8bab Signed-off-by: Changyeon Jo --- automotive/evs/1.1/IEvsCamera.hal | 37 +++++++++++++++++++ automotive/evs/1.1/default/EvsCamera.cpp | 21 +++++++++++ automotive/evs/1.1/default/EvsCamera.h | 4 ++ .../functional/VtsHalEvsV1_1TargetTest.cpp | 11 ++++++ 4 files changed, 73 insertions(+) diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal index fc68e60a1e..38e6c4242c 100644 --- a/automotive/evs/1.1/IEvsCamera.hal +++ b/automotive/evs/1.1/IEvsCamera.hal @@ -178,4 +178,41 @@ interface IEvsCamera extends @1.0::IEvsCamera { * values as backing camera devices. */ getIntParameter(CameraParam id) generates(EvsResult result, vec value); + + /** + * Request driver specific information from the HAL implementation. + * + * The values allowed for opaqueIdentifier are driver specific, + * but no value passed in may crash the driver. The driver should + * return EvsResult::INVALID_ARG for any unrecognized opaqueIdentifier. + * + * @param opaqueIdentifier An unique identifier of the information to + * request. + * @return result EvsResult::OK if the driver recognizes a given + * identifier. + * EvsResult::INVALID_ARG, otherwise. + * @return value Requested information. Zero-size vector is + * returned if the driver does not recognize a + * given identifier. + */ + getExtendedInfo_1_1(uint32_t opaqueIdentifier) + generates (EvsResult result, vec value); + + /** + * Send a driver specific value to the HAL implementation. + * + * This extension is provided to facilitate car specific + * extensions, but no HAL implementation may require this call + * in order to function in a default state. + * INVALID_ARG is returned if the opaqueValue is not meaningful to + * the driver implementation. + * + * @param opaqueIdentifier An unique identifier of the information to + * program. + * opaqueValue A value to program. + * @return result EvsResult::OK is returned if this call is successful. + * EvsResult::INVALID_ARG, otherwise. + */ + setExtendedInfo_1_1(uint32_t opaqueIdentifier, vec opaqueValue) + generates (EvsResult result); }; diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp index f9cdb881d8..5196c9532b 100644 --- a/automotive/evs/1.1/default/EvsCamera.cpp +++ b/automotive/evs/1.1/default/EvsCamera.cpp @@ -334,6 +334,27 @@ Return EvsCamera::getIntParameter(CameraParam id, } +Return EvsCamera::setExtendedInfo_1_1(uint32_t opaqueIdentifier, + const hidl_vec& opaqueValue) { + // Default implementation does not use an extended info. + (void)opaqueIdentifier; + (void)opaqueValue; + return EvsResult::INVALID_ARG; +} + + +Return EvsCamera::getExtendedInfo_1_1(uint32_t opaqueIdentifier, + getExtendedInfo_1_1_cb _hidl_cb) { + // Default implementation does not use an extended info. + (void)opaqueIdentifier; + + hidl_vec value; + _hidl_cb(EvsResult::INVALID_ARG, value); + return Void(); +} + + + bool EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) { if (bufferCount < 1) { ALOGE("Ignoring request to set buffer count to zero"); diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h index a49db46521..0fa83b428d 100644 --- a/automotive/evs/1.1/default/EvsCamera.h +++ b/automotive/evs/1.1/default/EvsCamera.h @@ -78,6 +78,10 @@ public: setIntParameter_cb _hidl_cb) override; Return getIntParameter(CameraParam id, getIntParameter_cb _hidl_cb) override; + Return setExtendedInfo_1_1(uint32_t opaqueIdentifier, + const hidl_vec& opaqueValue) override; + Return getExtendedInfo_1_1(uint32_t opaqueIdentifier, + getExtendedInfo_1_1_cb _hidl_cb) override; static sp Create(const char *deviceName); static sp Create(const char *deviceName, diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index ce02973ac2..2c8c1e1d15 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -296,6 +296,17 @@ TEST_F(EvsHidlTest, CameraOpenClean) { } ); + // Verify methods for extended info + const auto id = 0xFFFFFFFF; // meaningless id + hidl_vec values; + auto err = pCam->setExtendedInfo_1_1(id, values); + ASSERT_EQ(EvsResult::INVALID_ARG, err); + + pCam->getExtendedInfo_1_1(id, [](const auto& result, const auto& data) { + ASSERT_EQ(EvsResult::INVALID_ARG, result); + ASSERT_EQ(0, data.size()); + }); + // Explicitly close the camera so resources are released right away pEnumerator->closeCamera(pCam); } From 82e3c6bb60302abf0fd1527db0ae556ea743e50d Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Mon, 17 Feb 2020 16:21:36 -0800 Subject: [PATCH 0588/1022] Add missing instantiation code for Vts tests Instantiation script is missing from the wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp Bug: 149709807 Test: atest VtsHalWifiApV1_4TargetTest Change-Id: Ifd4ac0adbdffa77381a60f48f830ebccb6535dfe --- wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp | 6 ++++++ wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp index 7896067d3a..e03c776db6 100644 --- a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp @@ -136,3 +136,9 @@ TEST_P(WifiChipHidlTest, registerEventCallback_1_4) { return; } } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiChipHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + ::android::hardware::wifi::V1_4::IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); diff --git a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp index 688faf1b2a..782088f4cf 100644 --- a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp +++ b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp @@ -545,3 +545,9 @@ TEST_P(WifiNanIfaceHidlTest, configRequest_1_4ShimInvalidArgs) { nanConfigRequest, nanConfigRequestSupp) .code); } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiNanIfaceHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + ::android::hardware::wifi::V1_4::IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); From 98eab1d10cb0ac5195c2640a23f5fba29a1cfa5d Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Mon, 17 Feb 2020 16:35:19 -0800 Subject: [PATCH 0589/1022] Add VTS tests to RTT impact of support of 11ax This commit adds missing VTS tests for the support of 80211ax and its impact to RTT. Bug: 139354972 Test: atest VtsHalWifiApV1_4TargetTest Change-Id: Ib13b65b5b76d1d940ac784a4a3b4899af88e541a --- wifi/1.4/vts/functional/Android.bp | 10 +- .../vts/functional/wifi_chip_hidl_test.cpp | 35 +++ .../wifi_rtt_controller_hidl_test.cpp | 224 ++++++++++++++++++ 3 files changed, 266 insertions(+), 3 deletions(-) create mode 100644 wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp index 46ac3ee5a5..d857be10ed 100644 --- a/wifi/1.4/vts/functional/Android.bp +++ b/wifi/1.4/vts/functional/Android.bp @@ -22,7 +22,8 @@ cc_test { "VtsHalWifiV1_4TargetTest.cpp", "wifi_ap_iface_hidl_test.cpp", "wifi_chip_hidl_test.cpp", - "wifi_nan_iface_hidl_test.cpp" + "wifi_nan_iface_hidl_test.cpp", + "wifi_rtt_controller_hidl_test.cpp", ], static_libs: [ "VtsHalWifiV1_0TargetTestUtil", @@ -31,7 +32,10 @@ cc_test { "android.hardware.wifi@1.2", "android.hardware.wifi@1.3", "android.hardware.wifi@1.4", - "libwifi-system-iface" + "libwifi-system-iface", + ], + test_suites: [ + "general-tests", + "vts-core", ], - test_suites: ["general-tests", "vts-core"], } diff --git a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp index e03c776db6..1c395500a0 100644 --- a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp @@ -19,6 +19,7 @@ #undef NAN // NAN is defined in bionic/libc/include/math.h:38 +#include #include #include #include @@ -34,10 +35,12 @@ using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; +using ::android::hardware::wifi::V1_0::ChipModeId; using ::android::hardware::wifi::V1_0::IfaceType; using ::android::hardware::wifi::V1_0::WifiDebugRingBufferStatus; using ::android::hardware::wifi::V1_0::WifiStatus; using ::android::hardware::wifi::V1_0::WifiStatusCode; +using ::android::hardware::wifi::V1_3::IWifiStaIface; using ::android::hardware::wifi::V1_4::IWifiChip; using ::android::hardware::wifi::V1_4::IWifiChipEventCallback; @@ -110,6 +113,16 @@ class WifiChipHidlTest : public ::testing::TestWithParam { }; protected: + // Helper function to configure the Chip in one of the supported modes. + // Most of the non-mode-configuration-related methods require chip + // to be first configured. + ChipModeId configureChipForIfaceType(IfaceType type, bool expectSuccess) { + ChipModeId mode_id; + EXPECT_EQ(expectSuccess, + configureChipToSupportIfaceType(wifi_chip_, type, &mode_id)); + return mode_id; + } + sp wifi_chip_; private: @@ -137,6 +150,28 @@ TEST_P(WifiChipHidlTest, registerEventCallback_1_4) { } } +/* + * createRttController_1_4 + * Ensures that an instance of the IWifiRttController proxy object is + * successfully created. + */ +TEST_P(WifiChipHidlTest, createRttController_1_4) { + configureChipForIfaceType(IfaceType::STA, true); + + const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createStaIface); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface.first.code); + sp iface = IWifiStaIface::castFrom(status_and_iface.second); + EXPECT_NE(nullptr, iface.get()); + + const auto& status_and_controller = + HIDL_INVOKE(wifi_chip_, createRttController_1_4, iface); + if (status_and_controller.first.code != + WifiStatusCode::ERROR_NOT_SUPPORTED) { + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_controller.first.code); + EXPECT_NE(nullptr, status_and_controller.second.get()); + } +} + INSTANTIATE_TEST_SUITE_P( PerInstance, WifiChipHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames( diff --git a/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp new file mode 100644 index 0000000000..726470cf3b --- /dev/null +++ b/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp @@ -0,0 +1,224 @@ +/* + * 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 + +#undef NAN // NAN is defined in bionic/libc/include/math.h:38 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wifi_hidl_call_util.h" +#include "wifi_hidl_test_utils.h" + +using ::android::sp; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::wifi::V1_0::CommandId; +using ::android::hardware::wifi::V1_0::RttBw; +using ::android::hardware::wifi::V1_0::RttPeerType; +using ::android::hardware::wifi::V1_0::RttType; +using ::android::hardware::wifi::V1_0::WifiChannelInfo; +using ::android::hardware::wifi::V1_0::WifiChannelWidthInMhz; +using ::android::hardware::wifi::V1_0::WifiStatus; +using ::android::hardware::wifi::V1_0::WifiStatusCode; +using ::android::hardware::wifi::V1_3::IWifiStaIface; +using ::android::hardware::wifi::V1_4::IWifiChip; +using ::android::hardware::wifi::V1_4::IWifiRttController; +using ::android::hardware::wifi::V1_4::IWifiRttControllerEventCallback; +using ::android::hardware::wifi::V1_4::RttCapabilities; +using ::android::hardware::wifi::V1_4::RttConfig; +using ::android::hardware::wifi::V1_4::RttPreamble; +using ::android::hardware::wifi::V1_4::RttResponder; +using ::android::hardware::wifi::V1_4::RttResult; + +/** + * Fixture to use for all RTT controller HIDL interface tests. + */ +class WifiRttControllerHidlTest : public ::testing::TestWithParam { + public: + virtual void SetUp() override { + // Make sure to start with a clean state + stopWifi(GetInstanceName()); + + wifi_rtt_controller_ = getWifiRttController(); + ASSERT_NE(nullptr, wifi_rtt_controller_.get()); + } + + virtual void TearDown() override { stopWifi(GetInstanceName()); } + + // A simple test implementation of WifiChipEventCallback. + class WifiRttControllerEventCallback + : public ::testing::VtsHalHidlTargetCallbackBase< + WifiRttControllerHidlTest>, + public IWifiRttControllerEventCallback { + public: + WifiRttControllerEventCallback(){}; + + virtual ~WifiRttControllerEventCallback() = default; + + Return onResults( + CommandId cmdId __unused, + const hidl_vec<::android::hardware::wifi::V1_0::RttResult>& results + __unused) { + return Void(); + }; + + Return onResults_1_4(CommandId cmdId __unused, + const hidl_vec& results + __unused) { + return Void(); + }; + }; + + protected: + sp wifi_rtt_controller_; + + private: + std::string GetInstanceName() { return GetParam(); } + + sp getWifiRttController() { + const std::string& instance_name = GetInstanceName(); + + sp wifi_chip = + IWifiChip::castFrom(getWifiChip(instance_name)); + EXPECT_NE(nullptr, wifi_chip.get()); + + sp wifi_sta_iface = + IWifiStaIface::castFrom(getWifiStaIface(instance_name)); + EXPECT_NE(nullptr, wifi_sta_iface.get()); + + const auto& status_and_controller = + HIDL_INVOKE(wifi_chip, createRttController_1_4, wifi_sta_iface); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_controller.first.code); + EXPECT_NE(nullptr, status_and_controller.second.get()); + + return status_and_controller.second.get(); + } +}; + +/* + * registerEventCallback_1_4 + * This test case tests the registerEventCallback_1_4() API which registers + * a call back function with the hal implementation + * + * Note: it is not feasible to test the invocation of the call back function + * since event is triggered internally in the HAL implementation, and can not be + * triggered from the test case + */ +TEST_P(WifiRttControllerHidlTest, RegisterEventCallback_1_4) { + sp wifiRttControllerEventCallback = + new WifiRttControllerEventCallback(); + const auto& status = + HIDL_INVOKE(wifi_rtt_controller_, registerEventCallback_1_4, + wifiRttControllerEventCallback); + EXPECT_EQ(WifiStatusCode::SUCCESS, status.code); +} + +/* + * rangeRequest_1_4 + */ +TEST_P(WifiRttControllerHidlTest, RangeRequest_1_4) { + std::vector configs; + RttConfig config; + int cmdId = 55; + // Set the config with test data + for (int i = 0; i < 6; i++) { + config.addr[i] = i; + } + config.type = RttType::ONE_SIDED; + config.peer = RttPeerType::STA; + config.channel.width = WifiChannelWidthInMhz::WIDTH_80; + config.channel.centerFreq = 5765; + config.channel.centerFreq0 = 5775; + config.channel.centerFreq1 = 0; + config.bw = RttBw::BW_80MHZ; + config.preamble = RttPreamble::HE; + config.mustRequestLci = false; + config.mustRequestLcr = false; + config.burstPeriod = 0; + config.numBurst = 0; + config.numFramesPerBurst = 8; + config.numRetriesPerRttFrame = 3; + config.numRetriesPerFtmr = 3; + config.burstDuration = 9; + // Insert config in the vector + configs.push_back(config); + + // Invoke the call + const auto& status = + HIDL_INVOKE(wifi_rtt_controller_, rangeRequest_1_4, cmdId, configs); + EXPECT_EQ(WifiStatusCode::SUCCESS, status.code); +} + +/* + * getCapabilities_1_4 + */ +TEST_P(WifiRttControllerHidlTest, GetCapabilities_1_4) { + std::pair status_and_caps; + + // Invoke the call + status_and_caps = HIDL_INVOKE(wifi_rtt_controller_, getCapabilities_1_4); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code); +} + +/* + * getResponderInfo_1_4 + */ +TEST_P(WifiRttControllerHidlTest, GetResponderInfo_1_4) { + std::pair status_and_info; + + // Invoke the call + status_and_info = HIDL_INVOKE(wifi_rtt_controller_, getResponderInfo_1_4); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_info.first.code); +} + +/* + * enableResponder_1_4 + */ +TEST_P(WifiRttControllerHidlTest, EnableResponder_1_4) { + std::pair status_and_info; + int cmdId = 55; + WifiChannelInfo channelInfo; + channelInfo.width = WifiChannelWidthInMhz::WIDTH_80; + channelInfo.centerFreq = 5690; + channelInfo.centerFreq0 = 5690; + channelInfo.centerFreq1 = 0; + + // Get the responder first + status_and_info = HIDL_INVOKE(wifi_rtt_controller_, getResponderInfo_1_4); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_info.first.code); + + // Invoke the call + const auto& status = + HIDL_INVOKE(wifi_rtt_controller_, enableResponder_1_4, cmdId, + channelInfo, 10, status_and_info.second); + EXPECT_EQ(WifiStatusCode::SUCCESS, status.code); +} + +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiRttControllerHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + ::android::hardware::wifi::V1_4::IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); From f034bf9c9225cb82dab9dc7e3398915e88133df6 Mon Sep 17 00:00:00 2001 From: Slava Shklyaev Date: Tue, 11 Feb 2020 14:27:02 +0000 Subject: [PATCH 0590/1022] Add NNAPI loop timeout API Bug: 145906499 Bug: 136735929 Test: NNT_static Change-Id: Ie40c248b174964676985403f9f1a5127b408a00a --- current.txt | 4 +- neuralnetworks/1.3/IPreparedModel.hal | 41 +++++++++++++++++-- neuralnetworks/1.3/types.hal | 11 +++++ neuralnetworks/1.3/types.t | 11 +++++ .../vts/functional/GeneratedTestHarness.cpp | 6 +-- .../vts/functional/QualityOfServiceTests.cpp | 4 +- .../1.3/vts/functional/ValidateRequest.cpp | 8 ++-- .../vts/functional/VtsHalNeuralnetworks.cpp | 2 +- 8 files changed, 72 insertions(+), 15 deletions(-) diff --git a/current.txt b/current.txt index 29e95fe7ab..67e2818c0f 100644 --- a/current.txt +++ b/current.txt @@ -674,9 +674,9 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 9db064ee44268a876be0367ff771e618362d39ec603b6ecab17e1575725fcd87 android.hardware.neuralnetworks@1.3::IDevice 4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback 2fa3679ad7c94b5e88724adcd560c561041068a4ca565c63830e68101988746a android.hardware.neuralnetworks@1.3::IFencedExecutionCallback -237b23b126a66f3432658020fed78cdd06ba6297459436fe6bae0ba753370833 android.hardware.neuralnetworks@1.3::IPreparedModel +43088ffc71945b463a7279262cfe2e290f6ed2f15d3fd6032798a3be299fb08f android.hardware.neuralnetworks@1.3::IPreparedModel 0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback -5e2a14b40dc11da9d478185838f4401b652739922d14cecea0a0ce4c1359fe21 android.hardware.neuralnetworks@1.3::types +306fda32ac969fd51d75d066352cadcb769944ec4823be4cdd3f86fdb9e97511 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal index d645de789c..4ce3691d14 100644 --- a/neuralnetworks/1.3/IPreparedModel.hal +++ b/neuralnetworks/1.3/IPreparedModel.hal @@ -92,6 +92,17 @@ interface IPreparedModel extends @1.2::IPreparedModel { * @param deadline The time by which the execution must complete. If the * execution cannot be finished by the deadline, the * execution must be aborted. + * @param loopTimeoutDuration The maximum amount of time that should be spent + * executing a {@link OperationType::WHILE} + * operation. If a loop condition model does not + * output false within this duration, the + * execution must be aborted. If the model + * contains a {@link OperationType::WHILE} + * operation and no loop timeout duration is + * provided, the maximum amount of time is {@link + * LoopTimeoutDurationNs::DEFAULT}. When + * provided, the duration must not exceed {@link + * LoopTimeoutDurationNs::MAXIMUM}. * @param callback A callback object used to return the error status of * the execution, shape information of model output operands, and * duration of execution. The callback object's notify function must @@ -111,7 +122,7 @@ interface IPreparedModel extends @1.2::IPreparedModel { * driver */ execute_1_3(Request request, MeasureTiming measure, OptionalTimePoint deadline, - IExecutionCallback callback) + OptionalTimeoutDuration loopTimeoutDuration, IExecutionCallback callback) generates (ErrorStatus status); /** @@ -163,6 +174,17 @@ interface IPreparedModel extends @1.2::IPreparedModel { * @param deadline The time by which the execution must complete. If the * execution cannot be finished by the deadline, the * execution must be aborted. + * @param loopTimeoutDuration The maximum amount of time that should be spent + * executing a {@link OperationType::WHILE} + * operation. If a loop condition model does not + * output false within this duration, the + * execution must be aborted. If the model + * contains a {@link OperationType::WHILE} + * operation and no loop timeout duration is + * provided, the maximum amount of time is {@link + * LoopTimeoutDurationNs::DEFAULT}. When + * provided, the duration must not exceed {@link + * LoopTimeoutDurationNs::MAXIMUM}. * @return status Error status of the execution, must be: * - NONE if execution is performed successfully * - DEVICE_UNAVAILABLE if driver is offline or busy @@ -187,7 +209,8 @@ interface IPreparedModel extends @1.2::IPreparedModel { * measurement is not available. */ executeSynchronously_1_3(Request request, MeasureTiming measure, - OptionalTimePoint deadline) + OptionalTimePoint deadline, + OptionalTimeoutDuration loopTimeoutDuration) generates (ErrorStatus status, vec outputShapes, Timing timing); @@ -243,6 +266,17 @@ interface IPreparedModel extends @1.2::IPreparedModel { * @param deadline The time by which the execution must complete. If the * execution cannot be finished by the deadline, the * execution must be aborted. + * @param loopTimeoutDuration The maximum amount of time that should be spent + * executing a {@link OperationType::WHILE} + * operation. If a loop condition model does not + * output false within this duration, the + * execution must be aborted. If the model + * contains a {@link OperationType::WHILE} + * operation and no loop timeout duration is + * provided, the maximum amount of time is {@link + * LoopTimeoutDurationNs::DEFAULT}. When + * provided, the duration must not exceed {@link + * LoopTimeoutDurationNs::MAXIMUM}. * @param duration The length of time within which the execution must * complete after all sync fences in waitFor are signaled. If the * execution cannot be finished within the duration, the execution @@ -264,6 +298,7 @@ interface IPreparedModel extends @1.2::IPreparedModel { * and error status when the execution is completed. */ executeFenced(Request request, vec waitFor, MeasureTiming measure, - OptionalTimePoint deadline, OptionalTimeoutDuration duration) + OptionalTimePoint deadline, OptionalTimeoutDuration loopTimeoutDuration, + OptionalTimeoutDuration duration) generates (ErrorStatus status, handle syncFence, IFencedExecutionCallback callback); }; diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index 8ee867c676..a808a2e512 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -5671,3 +5671,14 @@ enum ErrorStatus : @1.0::ErrorStatus { */ RESOURCE_EXHAUSTED_PERSISTENT, }; + +/** + * Each {@link OperationType::WHILE} operation in the model has an implicit + * execution timeout duration associated with it ("loop timeout duration"). + * This duration is configurable on a per-execution basis and must not exceed + * 15 seconds. The default value is 2 seconds. + */ +enum LoopTimeoutDurationNs : uint64_t { + DEFAULT = 2000000000, + MAXIMUM = 15000000000, +}; diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t index c663a60dee..0a6e45e487 100644 --- a/neuralnetworks/1.3/types.t +++ b/neuralnetworks/1.3/types.t @@ -598,3 +598,14 @@ enum ErrorStatus : @1.0::ErrorStatus { */ RESOURCE_EXHAUSTED_PERSISTENT, }; + +/** + * Each {@link OperationType::WHILE} operation in the model has an implicit + * execution timeout duration associated with it ("loop timeout duration"). + * This duration is configurable on a per-execution basis and must not exceed + * 15 seconds. The default value is 2 seconds. + */ +enum LoopTimeoutDurationNs : uint64_t { + DEFAULT = 2000000000, + MAXIMUM = 15000000000, +}; diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 404c2a1e03..89edfb713c 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -496,7 +496,7 @@ static std::vector getOutputBuffers(const TestModel& testModel, cons static Return ExecutePreparedModel(const sp& preparedModel, const Request& request, MeasureTiming measure, sp& callback) { - return preparedModel->execute_1_3(request, measure, {}, callback); + return preparedModel->execute_1_3(request, measure, {}, {}, callback); } static Return ExecutePreparedModel(const sp& preparedModel, const Request& request, MeasureTiming measure, @@ -504,7 +504,7 @@ static Return ExecutePreparedModel(const sp& prepar Timing* timing) { ErrorStatus result; Return ret = preparedModel->executeSynchronously_1_3( - request, measure, {}, + request, measure, {}, {}, [&result, outputShapes, timing](ErrorStatus error, const hidl_vec& shapes, const Timing& time) { result = error; @@ -612,7 +612,7 @@ void EvaluatePreparedModel(const sp& device, const sp& hidl_handle syncFenceHandle; sp fencedCallback; Return ret = preparedModel->executeFenced( - request, {}, testConfig.measureTiming, {}, {}, + request, {}, testConfig.measureTiming, {}, {}, {}, [&result, &syncFenceHandle, &fencedCallback]( ErrorStatus error, const hidl_handle& handle, const sp& callback) { diff --git a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp index 8271135344..fccc612574 100644 --- a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp +++ b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp @@ -171,7 +171,7 @@ static MaybeResults executeAsynchronously(const sp& preparedMode // launch execution const sp callback = new ExecutionCallback(); - Return ret = preparedModel->execute_1_3(request, measure, deadline, callback); + Return ret = preparedModel->execute_1_3(request, measure, deadline, {}, callback); EXPECT_TRUE(ret.isOk()); EXPECT_EQ(ErrorStatus::NONE, ret.withDefault(ErrorStatus::GENERAL_FAILURE)); if (!ret.isOk() || ret != ErrorStatus::NONE) return std::nullopt; @@ -198,7 +198,7 @@ static MaybeResults executeSynchronously(const sp& preparedModel // run execution const Return ret = - preparedModel->executeSynchronously_1_3(request, measure, deadline, cb); + preparedModel->executeSynchronously_1_3(request, measure, deadline, {}, cb); EXPECT_TRUE(ret.isOk()); if (!ret.isOk()) return std::nullopt; diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index 2a4269f3d4..20f4fe2c00 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -70,7 +70,7 @@ static void validate(const sp& preparedModel, const std::string& sp executionCallback = new ExecutionCallback(); Return executeLaunchStatus = - preparedModel->execute_1_3(request, measure, deadline, executionCallback); + preparedModel->execute_1_3(request, measure, deadline, {}, executionCallback); ASSERT_TRUE(executeLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(executeLaunchStatus)); @@ -88,7 +88,7 @@ static void validate(const sp& preparedModel, const std::string& SCOPED_TRACE(message + " [executeSynchronously_1_3]"); Return executeStatus = preparedModel->executeSynchronously_1_3( - request, measure, deadline, + request, measure, deadline, {}, [](ErrorStatus error, const hidl_vec& outputShapes, const Timing& timing) { ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); @@ -143,7 +143,7 @@ static void validate(const sp& preparedModel, const std::string& { SCOPED_TRACE(message + " [executeFenced]"); Return ret = - preparedModel->executeFenced(request, {}, MeasureTiming::NO, deadline, {}, + preparedModel->executeFenced(request, {}, MeasureTiming::NO, deadline, {}, {}, [](ErrorStatus error, const hidl_handle& handle, const sp& callback) { ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); @@ -196,7 +196,7 @@ void validateRequest(const sp& preparedModel, const Request& req void validateRequestFailure(const sp& preparedModel, const Request& request) { SCOPED_TRACE("Expecting request to fail [executeSynchronously_1_3]"); Return executeStatus = preparedModel->executeSynchronously_1_3( - request, MeasureTiming::NO, {}, + request, MeasureTiming::NO, {}, {}, [](ErrorStatus error, const hidl_vec& outputShapes, const Timing& timing) { ASSERT_NE(ErrorStatus::NONE, error); EXPECT_EQ(outputShapes.size(), 0); diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index 9a87569b46..16341dafc7 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -137,7 +137,7 @@ void validateBurst(const sp& preparedModel, const V1_0::Request& void validateExecuteFenced(const sp& preparedModel, const Request& request) { SCOPED_TRACE("Expecting request to fail [executeFenced]"); Return ret_null = preparedModel->executeFenced( - request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO, {}, {}, + request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO, {}, {}, {}, [](ErrorStatus error, const hidl_handle& handle, const sp& callback) { ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); From 7a04231aaa03572d74fdc2cf89ff45a703ef471f Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Tue, 4 Feb 2020 18:46:55 -0500 Subject: [PATCH 0591/1022] Create Contexthub HAL 1.1 The HAL 1.1 update allows the contexthub framework to notify the HAL of any settings changes the user makes. Bug: 135951924 Test: compile Change-Id: Ia523c89b2e546ec169eb4997a0af7f471c8185b5 --- contexthub/1.1/Android.bp | 18 ++++++++++++++++++ contexthub/1.1/IContexthub.hal | 31 +++++++++++++++++++++++++++++++ contexthub/1.1/types.hal | 32 ++++++++++++++++++++++++++++++++ current.txt | 2 ++ 4 files changed, 83 insertions(+) create mode 100644 contexthub/1.1/Android.bp create mode 100644 contexthub/1.1/IContexthub.hal create mode 100644 contexthub/1.1/types.hal diff --git a/contexthub/1.1/Android.bp b/contexthub/1.1/Android.bp new file mode 100644 index 0000000000..649f1db4c7 --- /dev/null +++ b/contexthub/1.1/Android.bp @@ -0,0 +1,18 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.contexthub@1.1", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IContexthub.hal", + ], + interfaces: [ + "android.hardware.contexthub@1.0", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/contexthub/1.1/IContexthub.hal b/contexthub/1.1/IContexthub.hal new file mode 100644 index 0000000000..842d4b79ef --- /dev/null +++ b/contexthub/1.1/IContexthub.hal @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package android.hardware.contexthub@1.1; + +import @1.0::IContexthub; +import @1.0::Result; + +interface IContexthub extends @1.0::IContexthub { + /** + * Notification sent by the framework to indicate that the user + * has changed a setting. + * + * @param setting User setting that has been modified. + * @param newValue The update value of the user setting. + */ + oneway onSettingChanged(Setting setting, SettingValue newValue); +}; \ No newline at end of file diff --git a/contexthub/1.1/types.hal b/contexthub/1.1/types.hal new file mode 100644 index 0000000000..885cf32d6e --- /dev/null +++ b/contexthub/1.1/types.hal @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package android.hardware.contexthub@1.1; + +/** + * Used to indicate the type of user setting that has changed. + */ +enum Setting : uint8_t { + LOCATION, +}; + +/** + * Used to indicate the value of a user setting. + */ +enum SettingValue : uint8_t { + DISABLED, + ENABLED, +}; \ No newline at end of file diff --git a/current.txt b/current.txt index 29e95fe7ab..3f908a32e5 100644 --- a/current.txt +++ b/current.txt @@ -644,6 +644,8 @@ c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardwar 9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardware.cas@1.2::IMediaCasService 4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types +2a6b1a1202493f0a7c88d716da6e2cdd66bfd77a170621791fdf14997fdfcaf9 android.hardware.contexthub@1.1::IContexthub +3581d0ba61663cdd45807494dcd697d01c074f27587df9140655f94346969cfe android.hardware.contexthub@1.1::types 66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory 994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory 446287268831f4ddfac4a51bb1c32ae1e48e47bccd535fccc2c4546d0e7c4013 android.hardware.dumpstate@1.1::types From a7bf0d20d3ce9f8e8d2d089249f2e919fa99bb62 Mon Sep 17 00:00:00 2001 From: Brian Duddie Date: Fri, 14 Feb 2020 14:24:39 -0800 Subject: [PATCH 0592/1022] Add default (mock) Contexthub HAL 1.1 impl Current implementation exposes a mock context hub, but with no nanoapps. Bug: 135951924 Test: compile only (will be covered by VTS in a follow-up) Change-Id: I7a13527f303ce1bcacac8c6be9f081b0838cdc68 --- contexthub/1.1/default/Android.bp | 42 +++++++ contexthub/1.1/default/Contexthub.cpp | 109 ++++++++++++++++++ contexthub/1.1/default/Contexthub.h | 56 +++++++++ contexthub/1.1/default/OWNERS | 3 + ...android.hardware.contexthub@1.1-service.rc | 6 + .../android.hardware.contexthub@1.1.xml | 11 ++ contexthub/1.1/default/service.cpp | 42 +++++++ 7 files changed, 269 insertions(+) create mode 100644 contexthub/1.1/default/Android.bp create mode 100644 contexthub/1.1/default/Contexthub.cpp create mode 100644 contexthub/1.1/default/Contexthub.h create mode 100644 contexthub/1.1/default/OWNERS create mode 100644 contexthub/1.1/default/android.hardware.contexthub@1.1-service.rc create mode 100644 contexthub/1.1/default/android.hardware.contexthub@1.1.xml create mode 100644 contexthub/1.1/default/service.cpp diff --git a/contexthub/1.1/default/Android.bp b/contexthub/1.1/default/Android.bp new file mode 100644 index 0000000000..86858c0377 --- /dev/null +++ b/contexthub/1.1/default/Android.bp @@ -0,0 +1,42 @@ +/* + * 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. + */ + +cc_binary { + name: "android.hardware.contexthub@1.1-service.mock", + defaults: ["hidl_defaults"], + vendor: true, + relative_install_path: "hw", + init_rc: ["android.hardware.contexthub@1.1-service.rc"], + srcs: [ + "Contexthub.cpp", + "service.cpp", + ], + cflags: [ + "-Wall", + "-Werror", + ], + shared_libs: [ + "android.hardware.contexthub@1.0", + "android.hardware.contexthub@1.1", + "libbase", + "libcutils", + "libhardware", + "libhidlbase", + "liblog", + "libutils", + ], + vintf_fragments: ["android.hardware.contexthub@1.1.xml"], +} diff --git a/contexthub/1.1/default/Contexthub.cpp b/contexthub/1.1/default/Contexthub.cpp new file mode 100644 index 0000000000..19cc2628d7 --- /dev/null +++ b/contexthub/1.1/default/Contexthub.cpp @@ -0,0 +1,109 @@ +/* + * 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 "Contexthub.h" + +#include + +namespace android { +namespace hardware { +namespace contexthub { +namespace V1_1 { +namespace implementation { + +using ::android::hardware::contexthub::V1_0::ContextHub; +using ::android::hardware::contexthub::V1_0::HubAppInfo; +using ::android::hardware::contexthub::V1_0::Result; + +namespace { + +constexpr uint32_t kMockHubId = 0; + +} // anonymous namespace + +Return Contexthub::getHubs(getHubs_cb _hidl_cb) { + ContextHub hub = {}; + hub.name = "Mock Context Hub"; + hub.vendor = "AOSP"; + hub.toolchain = "n/a"; + hub.platformVersion = 1; + hub.toolchainVersion = 1; + hub.hubId = kMockHubId; + hub.peakMips = 1; + hub.peakPowerDrawMw = 1; + hub.maxSupportedMsgLen = 4096; + hub.chrePlatformId = UINT64_C(0x476f6f6754000000); + hub.chreApiMajorVersion = 1; + hub.chreApiMinorVersion = 4; + + // Report a single mock hub + std::vector hubs; + hubs.push_back(hub); + + _hidl_cb(hubs); + return Void(); +} + +Return Contexthub::registerCallback(uint32_t hubId, const sp& cb) { + if (hubId == kMockHubId) { + mCallback = cb; + return Result::OK; + } + return Result::BAD_PARAMS; +} + +// We don't expose any nanoapps, therefore all nanoapp-related API calls return with BAD_PARAMS +Return Contexthub::sendMessageToHub(uint32_t /*hubId*/, const ContextHubMsg& /*msg*/) { + return Result::BAD_PARAMS; +} + +Return Contexthub::loadNanoApp(uint32_t /*hubId*/, const NanoAppBinary& /*appBinary*/, + uint32_t /*transactionId*/) { + return Result::BAD_PARAMS; +} + +Return Contexthub::unloadNanoApp(uint32_t /*hubId*/, uint64_t /*appId*/, + uint32_t /*transactionId*/) { + return Result::BAD_PARAMS; +} + +Return Contexthub::enableNanoApp(uint32_t /*hubId*/, uint64_t /*appId*/, + uint32_t /*transactionId*/) { + return Result::BAD_PARAMS; +} + +Return Contexthub::disableNanoApp(uint32_t /*hubId*/, uint64_t /*appId*/, + uint32_t /*transactionId*/) { + return Result::BAD_PARAMS; +} + +Return Contexthub::queryApps(uint32_t hubId) { + if (hubId == kMockHubId && mCallback != nullptr) { + std::vector nanoapps; + mCallback->handleAppsInfo(nanoapps); + return Result::OK; + } + return Result::BAD_PARAMS; +} + +Return Contexthub::onSettingChanged(Setting /*setting*/, SettingValue /*newValue*/) { + return Void(); +} + +} // namespace implementation +} // namespace V1_1 +} // namespace contexthub +} // namespace hardware +} // namespace android diff --git a/contexthub/1.1/default/Contexthub.h b/contexthub/1.1/default/Contexthub.h new file mode 100644 index 0000000000..0da61d1464 --- /dev/null +++ b/contexthub/1.1/default/Contexthub.h @@ -0,0 +1,56 @@ +/* + * 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. + */ +#pragma once + +#include + +namespace android { +namespace hardware { +namespace contexthub { +namespace V1_1 { +namespace implementation { + +class Contexthub : public V1_1::IContexthub { + using ContextHubMsg = ::android::hardware::contexthub::V1_0::ContextHubMsg; + using IContexthubCallback = ::android::hardware::contexthub::V1_0::IContexthubCallback; + using NanoAppBinary = ::android::hardware::contexthub::V1_0::NanoAppBinary; + using Result = ::android::hardware::contexthub::V1_0::Result; + + public: + // Methods from V1_0::IContexthub + Return getHubs(getHubs_cb _hidl_cb) override; + Return registerCallback(uint32_t hubId, + const ::android::sp& cb) override; + Return sendMessageToHub(uint32_t hubId, const ContextHubMsg& msg) override; + Return loadNanoApp(uint32_t hubId, const NanoAppBinary& appBinary, + uint32_t transactionId) override; + Return unloadNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) override; + Return enableNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) override; + Return disableNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) override; + Return queryApps(uint32_t hubId) override; + + // Methods from V1_1::IContexthub + Return onSettingChanged(Setting setting, SettingValue newValue) override; + + private: + sp mCallback; +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace contexthub +} // namespace hardware +} // namespace android diff --git a/contexthub/1.1/default/OWNERS b/contexthub/1.1/default/OWNERS new file mode 100644 index 0000000000..90c233030e --- /dev/null +++ b/contexthub/1.1/default/OWNERS @@ -0,0 +1,3 @@ +arthuri@google.com +bduddie@google.com +stange@google.com diff --git a/contexthub/1.1/default/android.hardware.contexthub@1.1-service.rc b/contexthub/1.1/default/android.hardware.contexthub@1.1-service.rc new file mode 100644 index 0000000000..9db00f9bf0 --- /dev/null +++ b/contexthub/1.1/default/android.hardware.contexthub@1.1-service.rc @@ -0,0 +1,6 @@ +service vendor.contexthub-hal-1-1-mock /vendor/bin/hw/android.hardware.contexthub@1.1-service.mock + interface android.hardware.contexthub@1.0::IContexthub default + interface android.hardware.contexthub@1.1::IContexthub default + class hal + user system + group system diff --git a/contexthub/1.1/default/android.hardware.contexthub@1.1.xml b/contexthub/1.1/default/android.hardware.contexthub@1.1.xml new file mode 100644 index 0000000000..388f7815f8 --- /dev/null +++ b/contexthub/1.1/default/android.hardware.contexthub@1.1.xml @@ -0,0 +1,11 @@ + + + android.hardware.contexthub + hwbinder + 1.1 + + IContexthub + default + + + diff --git a/contexthub/1.1/default/service.cpp b/contexthub/1.1/default/service.cpp new file mode 100644 index 0000000000..c5643f16df --- /dev/null +++ b/contexthub/1.1/default/service.cpp @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#define LOG_TAG "android.hardware.contexthub@1.1-service" + +#include +#include +#include +#include +#include "Contexthub.h" + +using ::android::hardware::configureRpcThreadpool; +using ::android::hardware::joinRpcThreadpool; +using ::android::hardware::contexthub::V1_1::IContexthub; +using ::android::hardware::contexthub::V1_1::implementation::Contexthub; + +int main() { + configureRpcThreadpool(1, true /* callerWillJoin */); + + ::android::sp contexthub = new Contexthub(); + if (contexthub->registerAsService() != ::android::OK) { + ALOGE("Failed to register Contexthub HAL instance"); + return 1; + } + + joinRpcThreadpool(); + ALOGE("Service exited"); + return 1; +} From af8a2f9394e8c5a2125a342a77f8d86d0f3e56bc Mon Sep 17 00:00:00 2001 From: Brian Duddie Date: Fri, 14 Feb 2020 15:39:19 -0800 Subject: [PATCH 0593/1022] Run clang-format on context hub 1.0 VTS Test: n/a Change-Id: I80eb0a7c0b722ede4ed84087a7b5e4ed318e5fd5 --- .../VtsHalContexthubV1_0TargetTest.cpp | 310 +++++++++--------- 1 file changed, 146 insertions(+), 164 deletions(-) diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp index a1d173bc32..83e12aed3a 100644 --- a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp +++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp @@ -30,10 +30,11 @@ #include #include -using ::android::hardware::Return; -using ::android::hardware::Void; +using ::android::sp; using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; using ::android::hardware::contexthub::V1_0::AsyncEventType; using ::android::hardware::contexthub::V1_0::ContextHub; using ::android::hardware::contexthub::V1_0::ContextHubMsg; @@ -43,7 +44,6 @@ using ::android::hardware::contexthub::V1_0::IContexthubCallback; using ::android::hardware::contexthub::V1_0::NanoAppBinary; using ::android::hardware::contexthub::V1_0::Result; using ::android::hardware::contexthub::V1_0::TransactionResult; -using ::android::sp; #define ASSERT_OK(result) ASSERT_EQ(result, Result::OK) #define EXPECT_OK(result) EXPECT_EQ(result, Result::OK) @@ -56,24 +56,23 @@ constexpr uint64_t kNonExistentAppId = 0x476f6f6754555555; // Helper that does explicit conversion of an enum class to its underlying/base // type. Useful for stream output of enum values. -template -constexpr typename std::underlying_type::type asBaseType( - EnumType value) { - return static_cast::type>(value); +template +constexpr typename std::underlying_type::type asBaseType(EnumType value) { + return static_cast::type>(value); } // Synchronously queries IContexthub::getHubs() and returns the result hidl_vec getHubsSync(sp hubApi) { - hidl_vec hubList; - std::promise barrier; + hidl_vec hubList; + std::promise barrier; - hubApi->getHubs([&hubList, &barrier](const hidl_vec& hubs) { - hubList = hubs; - barrier.set_value(); - }); - barrier.get_future().wait_for(std::chrono::seconds(1)); + hubApi->getHubs([&hubList, &barrier](const hidl_vec& hubs) { + hubList = hubs; + barrier.set_value(); + }); + barrier.get_future().wait_for(std::chrono::seconds(1)); - return hubList; + return hubList; } // Gets a list of valid hub IDs in the system @@ -119,62 +118,58 @@ class ContexthubHidlTest : public ::testing::TestWithParam handleClientMsg(const ContextHubMsg& /*msg*/) override { - ALOGD("Got client message callback"); - return Void(); - } + public: + virtual Return handleClientMsg(const ContextHubMsg& /*msg*/) override { + ALOGD("Got client message callback"); + return Void(); + } - virtual Return handleTxnResult( - uint32_t txnId, TransactionResult result) override { - ALOGD("Got transaction result callback for txnId %" PRIu32 " with result %" - PRId32, txnId, result); - return Void(); - } + virtual Return handleTxnResult(uint32_t txnId, TransactionResult result) override { + ALOGD("Got transaction result callback for txnId %" PRIu32 " with result %" PRId32, txnId, + result); + return Void(); + } - virtual Return handleHubEvent(AsyncEventType evt) override { - ALOGD("Got hub event callback for event type %" PRIu32, evt); - return Void(); - } + virtual Return handleHubEvent(AsyncEventType evt) override { + ALOGD("Got hub event callback for event type %" PRIu32, evt); + return Void(); + } - virtual Return handleAppAbort(uint64_t appId, uint32_t abortCode) - override { - ALOGD("Got app abort notification for appId 0x%" PRIx64 " with abort code " - "0x%" PRIx32, appId, abortCode); - return Void(); - } + virtual Return handleAppAbort(uint64_t appId, uint32_t abortCode) override { + ALOGD("Got app abort notification for appId 0x%" PRIx64 + " with abort code " + "0x%" PRIx32, + appId, abortCode); + return Void(); + } - virtual Return handleAppsInfo(const hidl_vec& /*appInfo*/) - override { - ALOGD("Got app info callback"); - return Void(); - } + virtual Return handleAppsInfo(const hidl_vec& /*appInfo*/) override { + ALOGD("Got app info callback"); + return Void(); + } }; // 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 // within the given time, returns false. -template -bool waitForCallback( - std::future future, - ReturnType *result, - std::chrono::milliseconds timeout = std::chrono::seconds(5)) { - auto expiration = std::chrono::system_clock::now() + timeout; +template +bool waitForCallback(std::future future, ReturnType* result, + std::chrono::milliseconds timeout = std::chrono::seconds(5)) { + auto expiration = std::chrono::system_clock::now() + timeout; - EXPECT_NE(result, nullptr); - EXPECT_TRUE(future.valid()); - if (result != nullptr && future.valid()) { - std::future_status status = future.wait_until(expiration); - EXPECT_NE(status, std::future_status::timeout) - << "Timed out waiting for callback"; + EXPECT_NE(result, nullptr); + EXPECT_TRUE(future.valid()); + if (result != nullptr && future.valid()) { + std::future_status status = future.wait_until(expiration); + EXPECT_NE(status, std::future_status::timeout) << "Timed out waiting for callback"; - if (status == std::future_status::ready) { - *result = future.get(); - return true; + if (status == std::future_status::ready) { + *result = future.get(); + return true; + } } - } - return false; + return false; } // Ensures that the metadata reported in getHubs() is sane @@ -199,169 +194,156 @@ TEST_P(ContexthubHidlTest, TestGetHubs) { } TEST_P(ContexthubHidlTest, TestRegisterCallback) { - ALOGD("TestRegisterCallback called, hubId %" PRIu32, getHubId()); - ASSERT_OK(registerCallback(new ContexthubCallbackBase())); + ALOGD("TestRegisterCallback called, hubId %" PRIu32, getHubId()); + ASSERT_OK(registerCallback(new ContexthubCallbackBase())); } TEST_P(ContexthubHidlTest, TestRegisterNullCallback) { - ALOGD("TestRegisterNullCallback called, hubId %" PRIu32, getHubId()); - ASSERT_OK(registerCallback(nullptr)); + ALOGD("TestRegisterNullCallback called, hubId %" PRIu32, getHubId()); + ASSERT_OK(registerCallback(nullptr)); } // Helper callback that puts the async appInfo callback data into a promise class QueryAppsCallback : public ContexthubCallbackBase { - public: - virtual Return handleAppsInfo(const hidl_vec& appInfo) - override { - ALOGD("Got app info callback with %zu apps", appInfo.size()); - promise.set_value(appInfo); - return Void(); - } + public: + virtual Return handleAppsInfo(const hidl_vec& appInfo) override { + ALOGD("Got app info callback with %zu apps", appInfo.size()); + promise.set_value(appInfo); + return Void(); + } - std::promise> promise; + std::promise> promise; }; // Calls queryApps() and checks the returned metadata TEST_P(ContexthubHidlTest, TestQueryApps) { - ALOGD("TestQueryApps called, hubId %u", getHubId()); - sp cb = new QueryAppsCallback(); - ASSERT_OK(registerCallback(cb)); + ALOGD("TestQueryApps called, hubId %u", getHubId()); + sp cb = new QueryAppsCallback(); + ASSERT_OK(registerCallback(cb)); - Result result = hubApi->queryApps(getHubId()); - ASSERT_OK(result); + Result result = hubApi->queryApps(getHubId()); + ASSERT_OK(result); - ALOGD("Waiting for app info callback"); - hidl_vec appList; - ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &appList)); - for (const HubAppInfo &appInfo : appList) { - EXPECT_NE(appInfo.appId, UINT64_C(0)); - EXPECT_NE(appInfo.appId, kNonExistentAppId); - } + ALOGD("Waiting for app info callback"); + hidl_vec appList; + ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &appList)); + for (const HubAppInfo& appInfo : appList) { + EXPECT_NE(appInfo.appId, UINT64_C(0)); + EXPECT_NE(appInfo.appId, kNonExistentAppId); + } } // Helper callback that puts the TransactionResult for the expectedTxnId into a // promise class TxnResultCallback : public ContexthubCallbackBase { - public: - virtual Return handleTxnResult( - uint32_t txnId, TransactionResult result) override { - ALOGD("Got transaction result callback for txnId %" PRIu32 " (expecting %" - PRIu32 ") with result %" PRId32, txnId, expectedTxnId, result); - if (txnId == expectedTxnId) { - promise.set_value(result); + public: + virtual Return handleTxnResult(uint32_t txnId, TransactionResult result) override { + ALOGD("Got transaction result callback for txnId %" PRIu32 " (expecting %" PRIu32 + ") with result %" PRId32, + txnId, expectedTxnId, result); + if (txnId == expectedTxnId) { + promise.set_value(result); + } + return Void(); } - return Void(); - } - uint32_t expectedTxnId = 0; - std::promise promise; + uint32_t expectedTxnId = 0; + std::promise promise; }; // Parameterized fixture that sets the callback to TxnResultCallback class ContexthubTxnTest : public ContexthubHidlTest { - public: - virtual void SetUp() override { - ContexthubHidlTest::SetUp(); - ASSERT_OK(registerCallback(cb)); - } + public: + virtual void SetUp() override { + ContexthubHidlTest::SetUp(); + ASSERT_OK(registerCallback(cb)); + } - sp cb = new TxnResultCallback(); + sp cb = new TxnResultCallback(); }; - // Checks cases where the hub implementation is expected to return an error, but // that error can be returned either synchronously or in the asynchronous // transaction callback. Returns an AssertionResult that can be used in // ASSERT/EXPECT_TRUE. Allows checking the sync result against 1 additional // allowed error code apart from OK and TRANSACTION_FAILED, which are always // allowed. -::testing::AssertionResult checkFailureSyncOrAsync( - Result result, Result allowedSyncResult, - std::future&& future) { - if (result == Result::OK) { - // No error reported synchronously - this is OK, but then we should get an - // async callback with a failure status - TransactionResult asyncResult; - if (!waitForCallback(std::forward>(future), - &asyncResult)) { - return ::testing::AssertionFailure() - << "Got successful sync result, then failed to receive async cb"; - } else if (asyncResult == TransactionResult::SUCCESS) { - return ::testing::AssertionFailure() - << "Got successful sync result, then unexpected successful async " - "result"; +::testing::AssertionResult checkFailureSyncOrAsync(Result result, Result allowedSyncResult, + std::future&& future) { + if (result == Result::OK) { + // No error reported synchronously - this is OK, but then we should get an + // async callback with a failure status + TransactionResult asyncResult; + if (!waitForCallback(std::forward>(future), &asyncResult)) { + return ::testing::AssertionFailure() + << "Got successful sync result, then failed to receive async cb"; + } else if (asyncResult == TransactionResult::SUCCESS) { + return ::testing::AssertionFailure() + << "Got successful sync result, then unexpected successful async " + "result"; + } + } else if (result != allowedSyncResult && result != Result::TRANSACTION_FAILED) { + return ::testing::AssertionFailure() + << "Got sync result " << asBaseType(result) << ", expected TRANSACTION_FAILED or " + << asBaseType(allowedSyncResult); } - } else if (result != allowedSyncResult && - result != Result::TRANSACTION_FAILED) { - return ::testing::AssertionFailure() << "Got sync result " - << asBaseType(result) << ", expected TRANSACTION_FAILED or " - << asBaseType(allowedSyncResult); - } - return ::testing::AssertionSuccess(); + return ::testing::AssertionSuccess(); } TEST_P(ContexthubTxnTest, TestSendMessageToNonExistentNanoApp) { - ContextHubMsg msg; - msg.appName = kNonExistentAppId; - msg.msgType = 1; - msg.msg.resize(4); - std::fill(msg.msg.begin(), msg.msg.end(), 0); + ContextHubMsg msg; + msg.appName = kNonExistentAppId; + msg.msgType = 1; + msg.msg.resize(4); + std::fill(msg.msg.begin(), msg.msg.end(), 0); - ALOGD("Sending message to non-existent nanoapp"); - Result result = hubApi->sendMessageToHub(getHubId(), msg); - if (result != Result::OK && - result != Result::BAD_PARAMS && - result != Result::TRANSACTION_FAILED) { - FAIL() << "Got result " << asBaseType(result) << ", expected OK, BAD_PARAMS" - << ", or TRANSACTION_FAILED"; - } + ALOGD("Sending message to non-existent nanoapp"); + Result result = hubApi->sendMessageToHub(getHubId(), msg); + if (result != Result::OK && result != Result::BAD_PARAMS && + result != Result::TRANSACTION_FAILED) { + FAIL() << "Got result " << asBaseType(result) << ", expected OK, BAD_PARAMS" + << ", or TRANSACTION_FAILED"; + } } TEST_P(ContexthubTxnTest, TestLoadEmptyNanoApp) { - cb->expectedTxnId = 0123; - NanoAppBinary emptyApp; + cb->expectedTxnId = 0123; + NanoAppBinary emptyApp; - emptyApp.appId = kNonExistentAppId; - emptyApp.appVersion = 1; - emptyApp.flags = 0; - emptyApp.targetChreApiMajorVersion = 1; - emptyApp.targetChreApiMinorVersion = 0; + emptyApp.appId = kNonExistentAppId; + emptyApp.appVersion = 1; + emptyApp.flags = 0; + emptyApp.targetChreApiMajorVersion = 1; + emptyApp.targetChreApiMinorVersion = 0; - ALOGD("Loading empty nanoapp"); - Result result = hubApi->loadNanoApp(getHubId(), emptyApp, cb->expectedTxnId); - EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, - cb->promise.get_future())); + ALOGD("Loading empty nanoapp"); + Result result = hubApi->loadNanoApp(getHubId(), emptyApp, cb->expectedTxnId); + EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future())); } TEST_P(ContexthubTxnTest, TestUnloadNonexistentNanoApp) { - cb->expectedTxnId = 1234; + cb->expectedTxnId = 1234; - ALOGD("Unloading nonexistent nanoapp"); - Result result = hubApi->unloadNanoApp(getHubId(), kNonExistentAppId, - cb->expectedTxnId); - EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, - cb->promise.get_future())); + ALOGD("Unloading nonexistent nanoapp"); + Result result = hubApi->unloadNanoApp(getHubId(), kNonExistentAppId, cb->expectedTxnId); + EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future())); } TEST_P(ContexthubTxnTest, TestEnableNonexistentNanoApp) { - cb->expectedTxnId = 2345; + cb->expectedTxnId = 2345; - ALOGD("Enabling nonexistent nanoapp"); - Result result = hubApi->enableNanoApp(getHubId(), kNonExistentAppId, - cb->expectedTxnId); - EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, - cb->promise.get_future())); + ALOGD("Enabling nonexistent nanoapp"); + Result result = hubApi->enableNanoApp(getHubId(), kNonExistentAppId, cb->expectedTxnId); + EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future())); } TEST_P(ContexthubTxnTest, TestDisableNonexistentNanoApp) { - cb->expectedTxnId = 3456; + cb->expectedTxnId = 3456; - ALOGD("Disabling nonexistent nanoapp"); - Result result = hubApi->disableNanoApp(getHubId(), kNonExistentAppId, - cb->expectedTxnId); - EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, - cb->promise.get_future())); + ALOGD("Disabling nonexistent nanoapp"); + Result result = hubApi->disableNanoApp(getHubId(), kNonExistentAppId, cb->expectedTxnId); + EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future())); } // Return the test parameters of a vecter of tuples for all IContexthub services and each of its hub From 01eb01a230f58f985119733118b0d6f06835cd63 Mon Sep 17 00:00:00 2001 From: Brian Duddie Date: Fri, 14 Feb 2020 15:35:57 -0800 Subject: [PATCH 0594/1022] Add VTS tests for Context Hub HAL 1.1 Extract some common functionality and add a new test for the newly-added method in HAL v1.1. Bug: 135951924 Test: atest VtsHalContexthubV1_0TargetTest \ VtsHalContexthubV1_1TargetTest Change-Id: I1cd335d4972bc3242245b2379a7cfa42d1c683a6 --- .../compatibility_matrix.current.xml | 2 +- contexthub/1.0/vts/functional/Android.bp | 5 +- .../VtsHalContexthubV1_0TargetTest.cpp | 129 ++---------------- contexthub/1.1/vts/functional/Android.bp | 30 ++++ contexthub/1.1/vts/functional/OWNERS | 8 ++ .../VtsHalContexthubV1_1TargetTest.cpp | 60 ++++++++ contexthub/common/vts/Android.bp | 30 ++++ .../common/vts/ContexthubCallbackBase.h | 63 +++++++++ .../common/vts/ContexthubHidlTestBase.h | 53 +++++++ contexthub/common/vts/OWNERS | 8 ++ .../common/vts/VtsHalContexthubUtils.cpp | 47 +++++++ contexthub/common/vts/VtsHalContexthubUtils.h | 70 ++++++++++ 12 files changed, 387 insertions(+), 118 deletions(-) create mode 100644 contexthub/1.1/vts/functional/Android.bp create mode 100644 contexthub/1.1/vts/functional/OWNERS create mode 100644 contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp create mode 100644 contexthub/common/vts/Android.bp create mode 100644 contexthub/common/vts/ContexthubCallbackBase.h create mode 100644 contexthub/common/vts/ContexthubHidlTestBase.h create mode 100644 contexthub/common/vts/OWNERS create mode 100644 contexthub/common/vts/VtsHalContexthubUtils.cpp create mode 100644 contexthub/common/vts/VtsHalContexthubUtils.h diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index f8cec640cc..9100f18765 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -153,7 +153,7 @@ android.hardware.contexthub - 1.0 + 1.0-1 IContexthub default diff --git a/contexthub/1.0/vts/functional/Android.bp b/contexthub/1.0/vts/functional/Android.bp index 9e99c334bc..d51c9669c8 100644 --- a/contexthub/1.0/vts/functional/Android.bp +++ b/contexthub/1.0/vts/functional/Android.bp @@ -18,7 +18,10 @@ cc_test { name: "VtsHalContexthubV1_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalContexthubV1_0TargetTest.cpp"], - static_libs: ["android.hardware.contexthub@1.0"], + static_libs: [ + "android.hardware.contexthub@1.0", + "VtsHalContexthubUtils", + ], test_suites: [ "general-tests", "vts-core", diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp index 83e12aed3a..ada232b9fc 100644 --- a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp +++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp @@ -16,6 +16,10 @@ #define LOG_TAG "contexthub_hidl_hal_test" +#include "ContexthubCallbackBase.h" +#include "ContexthubHidlTestBase.h" +#include "VtsHalContexthubUtils.h" + #include #include #include @@ -23,7 +27,6 @@ #include #include #include -#include #include #include @@ -44,9 +47,11 @@ using ::android::hardware::contexthub::V1_0::IContexthubCallback; using ::android::hardware::contexthub::V1_0::NanoAppBinary; using ::android::hardware::contexthub::V1_0::Result; using ::android::hardware::contexthub::V1_0::TransactionResult; - -#define ASSERT_OK(result) ASSERT_EQ(result, Result::OK) -#define EXPECT_OK(result) EXPECT_EQ(result, Result::OK) +using ::android::hardware::contexthub::vts_utils::asBaseType; +using ::android::hardware::contexthub::vts_utils::ContexthubCallbackBase; +using ::android::hardware::contexthub::vts_utils::ContexthubHidlTestBase; +using ::android::hardware::contexthub::vts_utils::getHalAndHubIdList; +using ::android::hardware::contexthub::vts_utils::getHubsSync; namespace { @@ -54,100 +59,10 @@ namespace { // app ID is reserved and must never appear in the list of loaded apps. constexpr uint64_t kNonExistentAppId = 0x476f6f6754555555; -// Helper that does explicit conversion of an enum class to its underlying/base -// type. Useful for stream output of enum values. -template -constexpr typename std::underlying_type::type asBaseType(EnumType value) { - return static_cast::type>(value); -} +const std::vector> kTestParameters = + getHalAndHubIdList(); -// Synchronously queries IContexthub::getHubs() and returns the result -hidl_vec getHubsSync(sp hubApi) { - hidl_vec hubList; - std::promise barrier; - - hubApi->getHubs([&hubList, &barrier](const hidl_vec& hubs) { - hubList = hubs; - barrier.set_value(); - }); - barrier.get_future().wait_for(std::chrono::seconds(1)); - - return hubList; -} - -// Gets a list of valid hub IDs in the system -std::vector getHubIds(const std::string& service_name) { - std::vector hubIds; - - sp hubApi = IContexthub::getService(service_name); - - if (hubApi != nullptr) { - for (const ContextHub& hub : getHubsSync(hubApi)) { - hubIds.push_back(std::to_string(hub.hubId)); - } - } - - ALOGD("Running tests against all %zu reported hubs for service %s", hubIds.size(), - service_name.c_str()); - return hubIds; -} - -// Test fixture parameterized by hub ID, initializes the HAL and makes the context hub API handle -// available. -class ContexthubHidlTest : public ::testing::TestWithParam> { - public: - virtual void SetUp() override { - hubApi = IContexthub::getService(std::get<0>(GetParam())); - ASSERT_NE(hubApi, nullptr); - - // getHubs() must be called at least once for proper initialization of the - // HAL implementation - getHubsSync(hubApi); - } - - uint32_t getHubId() { return std::stoi(std::get<1>(GetParam())); } - - Result registerCallback(sp cb) { - Result result = hubApi->registerCallback(getHubId(), cb); - ALOGD("Registered callback, result %" PRIu32, result); - return result; - } - - sp hubApi; -}; - -// Base callback implementation that just logs all callbacks by default -class ContexthubCallbackBase : public IContexthubCallback { - public: - virtual Return handleClientMsg(const ContextHubMsg& /*msg*/) override { - ALOGD("Got client message callback"); - return Void(); - } - - virtual Return handleTxnResult(uint32_t txnId, TransactionResult result) override { - ALOGD("Got transaction result callback for txnId %" PRIu32 " with result %" PRId32, txnId, - result); - return Void(); - } - - virtual Return handleHubEvent(AsyncEventType evt) override { - ALOGD("Got hub event callback for event type %" PRIu32, evt); - return Void(); - } - - virtual Return handleAppAbort(uint64_t appId, uint32_t abortCode) override { - ALOGD("Got app abort notification for appId 0x%" PRIx64 - " with abort code " - "0x%" PRIx32, - appId, abortCode); - return Void(); - } - - virtual Return handleAppsInfo(const hidl_vec& /*appInfo*/) override { - ALOGD("Got app info callback"); - return Void(); - } -}; +class ContexthubHidlTest : public ContexthubHidlTestBase {}; // 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 @@ -174,7 +89,7 @@ bool waitForCallback(std::future future, ReturnType* result, // Ensures that the metadata reported in getHubs() is sane TEST_P(ContexthubHidlTest, TestGetHubs) { - hidl_vec hubs = getHubsSync(hubApi); + hidl_vec hubs = getHubsSync(hubApi.get()); ALOGD("System reports %zu hubs", hubs.size()); for (const ContextHub& hub : hubs) { @@ -346,24 +261,6 @@ TEST_P(ContexthubTxnTest, TestDisableNonexistentNanoApp) { EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future())); } -// Return the test parameters of a vecter of tuples for all IContexthub services and each of its hub -// id: -static std::vector> get_parameters() { - std::vector> parameters; - std::vector service_names = - android::hardware::getAllHalInstanceNames(IContexthub::descriptor); - for (const std::string& service_name : service_names) { - std::vector ids = getHubIds(service_name); - for (const std::string& id : ids) { - parameters.push_back(std::make_tuple(service_name, id)); - } - } - - return parameters; -} - -static std::vector> kTestParameters = get_parameters(); - INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubHidlTest, testing::ValuesIn(kTestParameters), android::hardware::PrintInstanceTupleNameToString<>); diff --git a/contexthub/1.1/vts/functional/Android.bp b/contexthub/1.1/vts/functional/Android.bp new file mode 100644 index 0000000000..f1625a6b6b --- /dev/null +++ b/contexthub/1.1/vts/functional/Android.bp @@ -0,0 +1,30 @@ +// +// 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. +// + +cc_test { + name: "VtsHalContexthubV1_1TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalContexthubV1_1TargetTest.cpp"], + static_libs: [ + "android.hardware.contexthub@1.0", + "android.hardware.contexthub@1.1", + "VtsHalContexthubUtils", + ], + test_suites: [ + "general-tests", + "vts-core", + ], +} diff --git a/contexthub/1.1/vts/functional/OWNERS b/contexthub/1.1/vts/functional/OWNERS new file mode 100644 index 0000000000..161b2f069d --- /dev/null +++ b/contexthub/1.1/vts/functional/OWNERS @@ -0,0 +1,8 @@ +#Context Hub team +arthuri@google.com +bduddie@google.com +stange@google.com + +#VTS team +dshi@google.com +trong@google.com diff --git a/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp b/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp new file mode 100644 index 0000000000..f2fcdfca48 --- /dev/null +++ b/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#define LOG_TAG "contexthub_hidl_hal_test" + +#include "ContexthubCallbackBase.h" +#include "ContexthubHidlTestBase.h" +#include "VtsHalContexthubUtils.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using ::android::hardware::contexthub::V1_1::IContexthub; +using ::android::hardware::contexthub::V1_1::Setting; +using ::android::hardware::contexthub::V1_1::SettingValue; +using ::android::hardware::contexthub::vts_utils::ContexthubCallbackBase; +using ::android::hardware::contexthub::vts_utils::ContexthubHidlTestBase; +using ::android::hardware::contexthub::vts_utils::getHalAndHubIdList; + +namespace { + +const std::vector> kTestParameters = + getHalAndHubIdList(); + +class ContexthubHidlTest : public ContexthubHidlTestBase {}; + +TEST_P(ContexthubHidlTest, TestOnSettingChanged) { + // In VTS, we only test that sending the values doesn't cause things to blow up - other test + // suites verify the expected E2E behavior in CHRE + ASSERT_OK(registerCallback(new ContexthubCallbackBase())); + hubApi->onSettingChanged(Setting::LOCATION, SettingValue::DISABLED); + hubApi->onSettingChanged(Setting::LOCATION, SettingValue::ENABLED); + ASSERT_OK(registerCallback(nullptr)); +} + +INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubHidlTest, testing::ValuesIn(kTestParameters), + android::hardware::PrintInstanceTupleNameToString<>); + +} // anonymous namespace diff --git a/contexthub/common/vts/Android.bp b/contexthub/common/vts/Android.bp new file mode 100644 index 0000000000..3d5196a70e --- /dev/null +++ b/contexthub/common/vts/Android.bp @@ -0,0 +1,30 @@ +/* + * 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. + */ + +cc_test_library { + name: "VtsHalContexthubUtils", + srcs: [ + "VtsHalContexthubUtils.cpp", + ], + export_include_dirs: ["."], + shared_libs: [ + "android.hardware.contexthub@1.0", + "libhardware", + "libhidlbase", + "liblog", + "libutils", + ], +} diff --git a/contexthub/common/vts/ContexthubCallbackBase.h b/contexthub/common/vts/ContexthubCallbackBase.h new file mode 100644 index 0000000000..124a11601a --- /dev/null +++ b/contexthub/common/vts/ContexthubCallbackBase.h @@ -0,0 +1,63 @@ +/* + * 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. + */ +#pragma once + +#include +#include + +#include + +namespace android { +namespace hardware { +namespace contexthub { +namespace vts_utils { + +// Base callback implementation that just logs all callbacks by default, but +// records a failure if +class ContexthubCallbackBase : public V1_0::IContexthubCallback { + public: + virtual Return handleClientMsg(const V1_0::ContextHubMsg& /*msg*/) override { + ALOGD("Got client message callback"); + return Void(); + } + + virtual Return handleTxnResult(uint32_t txnId, V1_0::TransactionResult result) override { + ALOGD("Got transaction result callback for txnId %" PRIu32 " with result %" PRId32, txnId, + result); + return Void(); + } + + virtual Return handleHubEvent(V1_0::AsyncEventType evt) override { + ALOGD("Got hub event callback for event type %" PRIu32, evt); + return Void(); + } + + virtual Return handleAppAbort(uint64_t appId, uint32_t abortCode) override { + ALOGD("Got app abort notification for appId 0x%" PRIx64 " with abort code 0x%" PRIx32, + appId, abortCode); + return Void(); + } + + virtual Return handleAppsInfo(const hidl_vec& /*appInfo*/) override { + ALOGD("Got app info callback"); + return Void(); + } +}; + +} // namespace vts_utils +} // namespace contexthub +} // namespace hardware +} // namespace android diff --git a/contexthub/common/vts/ContexthubHidlTestBase.h b/contexthub/common/vts/ContexthubHidlTestBase.h new file mode 100644 index 0000000000..ee5b7d3cd5 --- /dev/null +++ b/contexthub/common/vts/ContexthubHidlTestBase.h @@ -0,0 +1,53 @@ +/* + * 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. + */ +#pragma once + +#include +#include + +#include +#include + +namespace android { +namespace hardware { +namespace contexthub { +namespace vts_utils { + +// Base fixture for Context Hub HAL tests. Parameterized by service name and hub ID. +template +class ContexthubHidlTestBase + : public ::testing::TestWithParam> { + public: + virtual void SetUp() override { fetchHubApi(); } + + void fetchHubApi() { + hubApi = IContexthubVersion::getService(std::get<0>(GetParam())); + ASSERT_NE(hubApi, nullptr); + } + + uint32_t getHubId() { return std::stoi(std::get<1>(GetParam())); } + + V1_0::Result registerCallback(sp cb) { + return hubApi->registerCallback(getHubId(), cb); + } + + sp hubApi; +}; + +} // namespace vts_utils +} // namespace contexthub +} // namespace hardware +} // namespace android diff --git a/contexthub/common/vts/OWNERS b/contexthub/common/vts/OWNERS new file mode 100644 index 0000000000..161b2f069d --- /dev/null +++ b/contexthub/common/vts/OWNERS @@ -0,0 +1,8 @@ +#Context Hub team +arthuri@google.com +bduddie@google.com +stange@google.com + +#VTS team +dshi@google.com +trong@google.com diff --git a/contexthub/common/vts/VtsHalContexthubUtils.cpp b/contexthub/common/vts/VtsHalContexthubUtils.cpp new file mode 100644 index 0000000000..5033b416c9 --- /dev/null +++ b/contexthub/common/vts/VtsHalContexthubUtils.cpp @@ -0,0 +1,47 @@ +/* + * 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 "VtsHalContexthubUtils.h" + +#include +#include + +namespace android { +namespace hardware { +namespace contexthub { +namespace vts_utils { + +using ::android::hardware::contexthub::V1_0::ContextHub; +using ::android::hardware::contexthub::V1_0::IContexthub; + +// Synchronously queries IContexthub::getHubs() and returns the result +hidl_vec getHubsSync(IContexthub* hubApi) { + hidl_vec hubList; + std::promise barrier; + + hubApi->getHubs([&hubList, &barrier](const hidl_vec& hubs) { + hubList = hubs; + barrier.set_value(); + }); + barrier.get_future().wait_for(std::chrono::seconds(1)); + + return hubList; +} + +} // namespace vts_utils +} // namespace contexthub +} // namespace hardware +} // namespace android diff --git a/contexthub/common/vts/VtsHalContexthubUtils.h b/contexthub/common/vts/VtsHalContexthubUtils.h new file mode 100644 index 0000000000..8f9b6946d9 --- /dev/null +++ b/contexthub/common/vts/VtsHalContexthubUtils.h @@ -0,0 +1,70 @@ +/* + * 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. + */ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace android { +namespace hardware { +namespace contexthub { +namespace vts_utils { + +#define ASSERT_OK(result) ASSERT_EQ(result, ::android::hardware::contexthub::V1_0::Result::OK) +#define EXPECT_OK(result) EXPECT_EQ(result, ::android::hardware::contexthub::V1_0::Result::OK) + +// Helper that does explicit conversion of an enum class to its underlying/base +// type. Useful for stream output of enum values. +template +inline constexpr typename std::underlying_type::type asBaseType(EnumType value) { + return static_cast::type>(value); +} + +// Synchronously queries IContexthub::getHubs() and returns the result +hidl_vec getHubsSync(V1_0::IContexthub* hubApi); + +// Create a vector of tuples that include each IContexthub service paired with each hub ID it +// exposes via getHubs(). Each tuple represents a test target that we should run the VTS suite +// against. +template +static std::vector> getHalAndHubIdList() { + std::vector> parameters; + std::vector serviceNames = + ::android::hardware::getAllHalInstanceNames(IContexthubVersion::descriptor); + for (const std::string& serviceName : serviceNames) { + sp hubApi = IContexthubVersion::getService(serviceName); + if (hubApi != nullptr) { + hidl_vec hubs = getHubsSync(hubApi.get()); + for (const V1_0::ContextHub& hub : hubs) { + parameters.push_back(std::make_tuple(serviceName, std::to_string(hub.hubId))); + } + } + } + + return parameters; +} + +} // namespace vts_utils +} // namespace contexthub +} // namespace hardware +} // namespace android From d8cafdbdfd089dd8215767a58c98d48700a920ab Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Wed, 5 Feb 2020 17:47:23 -0500 Subject: [PATCH 0595/1022] Add Sensors HAL 2.1 Creates Sensors HAL 2.1 to support the addition of a new sensor type for hinge angle sensors. Bug: 144139857 Test: mma Change-Id: Id78fb16324d28f2291b3ad1950197bfd2632d6f4 --- current.txt | 3 + sensors/2.1/Android.bp | 21 ++++ sensors/2.1/ISensors.hal | 148 ++++++++++++++++++++++++++++ sensors/2.1/ISensorsCallback.hal | 33 +++++++ sensors/2.1/types.hal | 160 +++++++++++++++++++++++++++++++ 5 files changed, 365 insertions(+) create mode 100644 sensors/2.1/Android.bp create mode 100644 sensors/2.1/ISensors.hal create mode 100644 sensors/2.1/ISensorsCallback.hal create mode 100644 sensors/2.1/types.hal diff --git a/current.txt b/current.txt index 29e95fe7ab..73a18ff5aa 100644 --- a/current.txt +++ b/current.txt @@ -693,6 +693,9 @@ dcc8872337f0135e81970e1d8d5fd7139160dc80e9be76f0ae05290fa7e472b8 android.hardwar a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication 0006ab8e8b0910cbd3bbb08d5f17d5fac7d65a2bdad5f2334e4851db9d1e6fa8 android.hardware.radio.config@1.3::IRadioConfigResponse +3ca6616381080bdd6c08141ad12775a94ae868c58b02b1274ae3326f7de724ab android.hardware.sensors@2.1::ISensors +3d4141c6373cd9ca02fe221a7d12343840de2255d032c38248fe8e35816b58b2 android.hardware.sensors@2.1::ISensorsCallback +8051cc50fc90ed447f058a8b15d81f35a65f1bd9004b1de4f127edeb89b47978 android.hardware.sensors@2.1::types 4a6517ea4ad807855428b0101d8e1a486497bd88ab4300ba3b2be43d46d32580 android.hardware.soundtrigger@2.3::types 12d7533ff0754f45bf59ab300799074570a99a676545652c2c23abc73cb4515d android.hardware.soundtrigger@2.3::ISoundTriggerHw 7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget diff --git a/sensors/2.1/Android.bp b/sensors/2.1/Android.bp new file mode 100644 index 0000000000..8e80e1fb5d --- /dev/null +++ b/sensors/2.1/Android.bp @@ -0,0 +1,21 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.sensors@2.1", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "ISensors.hal", + "ISensorsCallback.hal", + ], + interfaces: [ + "android.hardware.sensors@1.0", + "android.hardware.sensors@2.0", + "android.hidl.base@1.0", + ], + gen_java: false, + gen_java_constants: true, +} diff --git a/sensors/2.1/ISensors.hal b/sensors/2.1/ISensors.hal new file mode 100644 index 0000000000..d401fa56b2 --- /dev/null +++ b/sensors/2.1/ISensors.hal @@ -0,0 +1,148 @@ +/* + * 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. + */ + +package android.hardware.sensors@2.1; + +import @1.0::Result; +import @2.0::ISensors; +import @2.1::ISensorsCallback; + +interface ISensors extends @2.0::ISensors { + /** + * Enumerate all available (static) sensors. + * + * The SensorInfo for each sensor returned by getSensorsList must be stable + * from the initial call to getSensorsList after a device boot until the + * entire system restarts. The SensorInfo for each sensor must not change + * between subsequent calls to getSensorsList, even across restarts of the + * HAL and its dependencies (for example, the sensor handle for a given + * sensor must not change across HAL restarts). + */ + getSensorsList_2_1() generates (vec list); + + /** + * Initialize the Sensors HAL's Fast Message Queues (FMQ) and callback. + * + * The Fast Message Queues (FMQ) that are used to send data between the + * framework and the HAL. The callback is used by the HAL to notify the + * framework of asynchronous events, such as a dynamic sensor connection. + * + * The Event FMQ is used to transport sensor events from the HAL to the + * framework. The Event FMQ is created using the eventQueueDescriptor. + * Data may only be written to the Event FMQ. Data must not be read from + * the Event FMQ since the framework is the only reader. Upon receiving + * sensor events, the HAL writes the sensor events to the Event FMQ. + * + * Once the HAL is finished writing sensor events to the Event FMQ, the HAL + * must notify the framework that sensor events are available to be read and + * processed. This is accomplished by either: + * 1) Calling the Event FMQ’s EventFlag::wake() function with + EventQueueFlagBits::READ_AND_PROCESS + * 2) Setting the write notification in the Event FMQ’s writeBlocking() + * function to EventQueueFlagBits::READ_AND_PROCESS. + * + * If the Event FMQ’s writeBlocking() function is used, the read + * notification must be set to EventQueueFlagBits::EVENTS_READ in order to + * be notified and unblocked when the framework has successfully read events + * from the Event FMQ. + * + * The Wake Lock FMQ is used by the framework to notify the HAL when it is + * safe to release its wake_lock. When the framework receives WAKE_UP events + * from the Event FMQ and the framework has acquired a wake_lock, the + * framework must write the number of WAKE_UP events processed to the Wake + * Lock FMQ. When the HAL reads the data from the Wake Lock FMQ, the HAL + * decrements its current count of unprocessed WAKE_UP events and releases + * its wake_lock if the current count of unprocessed WAKE_UP events is + * zero. It is important to note that the HAL must acquire the wake lock and + * update its internal state regarding the number of outstanding WAKE_UP + * events _before_ posting the event to the Wake Lock FMQ, in order to avoid + * a race condition that can lead to loss of wake lock synchronization with + * the framework. + * + * The framework must use the WakeLockQueueFlagBits::DATA_WRITTEN value to + * notify the HAL that data has been written to the Wake Lock FMQ and must + * be read by HAL. + * + * The ISensorsCallback is used by the HAL to notify the framework of + * asynchronous events, such as a dynamic sensor connection. + * + * The name of any wake_lock acquired by the Sensors HAL for WAKE_UP events + * must begin with "SensorsHAL_WAKEUP". + * + * If WAKE_LOCK_TIMEOUT_SECONDS has elapsed since the most recent WAKE_UP + * event was written to the Event FMQ without receiving a message on the + * Wake Lock FMQ, then any held wake_lock for WAKE_UP events must be + * released. + * + * If either the Event FMQ or the Wake Lock FMQ is already initialized when + * initialize is invoked, then both existing FMQs must be discarded and the + * new descriptors must be used to create new FMQs within the HAL. The + * number of outstanding WAKE_UP events should also be reset to zero, and + * any outstanding wake_locks held as a result of WAKE_UP events should be + * released. + * + * All active sensor requests and direct channels must be closed and + * properly cleaned up when initialize is called in order to ensure that the + * HAL and framework's state is consistent (e.g. after a runtime restart). + * + * initialize must be thread safe and prevent concurrent calls + * to initialize from simultaneously modifying state. + * + * @param eventQueueDescriptor Fast Message Queue descriptor that is used to + * create the Event FMQ which is where sensor events are written. The + * descriptor is obtained from the framework's FMQ that is used to read + * sensor events. + * @param wakeLockDescriptor Fast Message Queue descriptor that is used to + * create the Wake Lock FMQ which is where wake_lock events are read + * from. The descriptor is obtained from the framework's FMQ that is + * used to write wake_lock events. + * @param sensorsCallback sensors callback that receives asynchronous data + * from the Sensors HAL. + * @return result OK on success; BAD_VALUE if descriptor is invalid (such + * as null) + */ + @entry + @callflow(next = {"getSensorsList"}) + initialize_2_1(fmq_sync eventQueueDescriptor, + fmq_sync wakeLockDescriptor, + ISensorsCallback sensorsCallback) + generates + (Result result); + + /** + * Inject a single sensor event or push operation environment parameters to + * device. + * + * When device is in NORMAL mode, this function is called to push operation + * environment data to device. In this operation, Event is always of + * SensorType::AdditionalInfo type. See operation evironment parameters + * section in AdditionalInfoType. + * + * When device is in DATA_INJECTION mode, this function is also used for + * injecting sensor events. + * + * Regardless of OperationMode, injected SensorType::ADDITIONAL_INFO + * type events should not be routed back to the sensor event queue. + * + * @see AdditionalInfoType + * @see OperationMode + * @param event sensor event to be injected + * @return result OK on success; PERMISSION_DENIED if operation is not + * allowed; INVALID_OPERATION, if this functionality is unsupported; + * BAD_VALUE if sensor event cannot be injected. + */ + injectSensorData_2_1(Event event) generates (Result result); +}; diff --git a/sensors/2.1/ISensorsCallback.hal b/sensors/2.1/ISensorsCallback.hal new file mode 100644 index 0000000000..de521d5328 --- /dev/null +++ b/sensors/2.1/ISensorsCallback.hal @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package android.hardware.sensors@2.1; + +import @2.0::ISensorsCallback; +import @2.1::SensorInfo; + +interface ISensorsCallback extends @2.0::ISensorsCallback { + /** + * Notify the framework that new dynamic sensors have been connected. + * + * If a dynamic sensor was previously connected and has not been + * disconnected, then that sensor must not be included in sensorInfos. + * + * @param sensorInfos vector of SensorInfo for each dynamic sensor that + * was connected. + */ + oneway onDynamicSensorsConnected_2_1(vec sensorInfos); +}; diff --git a/sensors/2.1/types.hal b/sensors/2.1/types.hal new file mode 100644 index 0000000000..503bece912 --- /dev/null +++ b/sensors/2.1/types.hal @@ -0,0 +1,160 @@ +/* + * 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. + */ + +package android.hardware.sensors@2.1; + +import @1.0::EventPayload; +import @1.0::SensorType; +import @1.0::SensorFlagBits; + +@export(name="", value_prefix="SENSOR_TYPE_") +enum SensorType : @1.0::SensorType { + /** + * HINGE_ANGLE + * reporting-mode: on-change + * wake-up sensor: yes + * + * A sensor of this type measures the angle, in degrees, between two + * integral parts of the device. Movement of a hinge measured by this sensor + * type is expected to alter the ways in which the user may interact with + * the device, for example by unfolding or revealing a display. + * + * Sensor data is output using @1.0::EventPayload.scalar. + * + * Implement wake-up proximity sensor before implementing a non wake-up + * proximity sensor. + */ + HINGE_ANGLE = 36, +}; + +struct Event { + /** Time measured in nanoseconds, in "elapsedRealtimeNano()'s" timebase. */ + int64_t timestamp; + + /** sensor identifier */ + int32_t sensorHandle; + + @2.1::SensorType sensorType; + + /** Union discriminated on sensorType */ + EventPayload u; +}; + +struct SensorInfo { + /** + * handle that identifies this sensors. This handle is used to reference + * this sensor throughout the HAL API. + */ + int32_t sensorHandle; + + /** + * Name of this sensor. + * All sensors of the same "type" must have a different "name". + */ + string name; + + /** vendor of the hardware part */ + string vendor; + + /** + * version of the hardware part + driver. The value of this field + * must increase when the driver is updated in a way that changes the + * output of this sensor. This is important for fused sensors when the + * fusion algorithm is updated. + */ + int32_t version; + + /** this sensor's type. */ + @2.1::SensorType type; + + /** + * type of this sensor as a string. + * + * When defining an OEM specific sensor or sensor manufacturer specific + * sensor, use your reserve domain name as a prefix. + * e.g. com.google.glass.onheaddetector + * + * For sensors of known type defined in SensorType (value < + * SensorType::DEVICE_PRIVATE_BASE), this can be an empty string. + */ + string typeAsString; + + /** maximum range of this sensor's value in SI units */ + float maxRange; + + /** smallest difference between two values reported by this sensor */ + float resolution; + + /** rough estimate of this sensor's power consumption in mA */ + float power; + + /** + * this value depends on the reporting mode: + * + * continuous: minimum sample period allowed in microseconds + * on-change : 0 + * one-shot :-1 + * special : 0, unless otherwise noted + */ + int32_t minDelay; + + /** + * number of events reserved for this sensor in the batch mode FIFO. + * If there is a dedicated FIFO for this sensor, then this is the + * size of this FIFO. If the FIFO is shared with other sensors, + * this is the size reserved for that sensor and it can be zero. + */ + uint32_t fifoReservedEventCount; + + /** + * maximum number of events of this sensor that could be batched. + * This is especially relevant when the FIFO is shared between + * several sensors; this value is then set to the size of that FIFO. + */ + uint32_t fifoMaxEventCount; + + /** + * permission required to see this sensor, register to it and receive data. + * Set to "" if no permission is required. Some sensor types like the + * heart rate monitor have a mandatory require_permission. + * For sensors that always require a specific permission, like the heart + * rate monitor, the android framework might overwrite this string + * automatically. + */ + string requiredPermission; + + /** + * This value is defined only for continuous mode and on-change sensors. + * It is the delay between two sensor events corresponding to the lowest + * frequency that this sensor supports. When lower frequencies are requested + * through batch()/setDelay() the events will be generated at this frequency + * instead. + * It can be used by the framework or applications to estimate when the + * batch FIFO may be full. + * + * NOTE: periodNs is in nanoseconds where as maxDelay/minDelay are in + * microseconds. + * + * continuous, on-change: maximum sampling period allowed in + * microseconds. + * + * one-shot, special : 0 + */ + int32_t maxDelay; + + /** Bitmask of SensorFlagBits */ + bitfield flags; +}; \ No newline at end of file From c002dd9ecaa5f2dc29e1f488ed6d0b14adbdedb7 Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Wed, 12 Feb 2020 14:41:41 -0500 Subject: [PATCH 0596/1022] Create wrapper for 2.0/2.1 sensor HALs Creates a wrapper that makes a 2.0 sensor HAL appear to look like a 2.1 sensor HAL so that various pieces of code can be shared between the two implementations. Bug: 144139857 Test: Run VTS Change-Id: I4ee4fd2b900e5d4ca744f420f69e150ba38f7949 --- sensors/common/utils/Android.bp | 36 +++ .../common/utils/EventMessageQueueWrapper.h | 109 +++++++++ sensors/common/utils/ISensorsWrapper.h | 209 ++++++++++++++++++ sensors/common/utils/OWNERS | 3 + sensors/common/utils/convertV2_1.h | 122 ++++++++++ 5 files changed, 479 insertions(+) create mode 100644 sensors/common/utils/Android.bp create mode 100644 sensors/common/utils/EventMessageQueueWrapper.h create mode 100644 sensors/common/utils/ISensorsWrapper.h create mode 100644 sensors/common/utils/OWNERS create mode 100644 sensors/common/utils/convertV2_1.h diff --git a/sensors/common/utils/Android.bp b/sensors/common/utils/Android.bp new file mode 100644 index 0000000000..aec6c4b58b --- /dev/null +++ b/sensors/common/utils/Android.bp @@ -0,0 +1,36 @@ +// +// 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. + +cc_library_headers { + name: "android.hardware.sensors@2.X-shared-utils", + vendor_available: true, + defaults: ["hidl_defaults"], + export_include_dirs: ["."], + shared_libs: [ + "android.hardware.sensors@1.0", + "android.hardware.sensors@2.0", + "android.hardware.sensors@2.1", + "libbinder", + "libcutils", + "libfmq", + "libhidlbase", + "liblog", + "libpower", + "libutils", + ], + static_libs: [ + "android.hardware.sensors@1.0-convert", + ], +} diff --git a/sensors/common/utils/EventMessageQueueWrapper.h b/sensors/common/utils/EventMessageQueueWrapper.h new file mode 100644 index 0000000000..bf3261ffbc --- /dev/null +++ b/sensors/common/utils/EventMessageQueueWrapper.h @@ -0,0 +1,109 @@ +/* + * 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_SENSORS_V2_1_EVENTMESSAGEQUEUEWRAPPER_H +#define ANDROID_HARDWARE_SENSORS_V2_1_EVENTMESSAGEQUEUEWRAPPER_H + +#include "convertV2_1.h" + +#include +#include +#include +#include +#include + +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_1 { +namespace implementation { + +class EventMessageQueueWrapperBase : public RefBase { + public: + virtual ~EventMessageQueueWrapperBase() {} + + virtual std::atomic* getEventFlagWord() = 0; + virtual size_t availableToRead() = 0; + virtual bool read(V2_1::Event* events, size_t numToRead) = 0; + virtual bool write(const std::vector& events) = 0; +}; + +class EventMessageQueueWrapperV1_0 : public EventMessageQueueWrapperBase { + public: + using EventMessageQueue = MessageQueue; + + EventMessageQueueWrapperV1_0(std::unique_ptr& queue) + : mQueue(std::move(queue)) {} + + const ::android::hardware::MQDescriptorSync* getDesc() { + return mQueue->getDesc(); + } + + virtual std::atomic* getEventFlagWord() override { + return mQueue->getEventFlagWord(); + } + + virtual size_t availableToRead() override { return mQueue->availableToRead(); } + + virtual bool read(V2_1::Event* events, size_t numToRead) override { + return mQueue->read(reinterpret_cast(events), numToRead); + } + + virtual bool write(const std::vector& events) override { + const std::vector& oldEvents = convertToOldEvents(events); + return mQueue->write(oldEvents.data(), oldEvents.size()); + } + + private: + std::unique_ptr mQueue; +}; + +class EventMessageQueueWrapperV2_1 : public EventMessageQueueWrapperBase { + public: + using EventMessageQueue = MessageQueue; + + EventMessageQueueWrapperV2_1(std::unique_ptr& queue) + : mQueue(std::move(queue)) {} + + const ::android::hardware::MQDescriptorSync* getDesc() { + return mQueue->getDesc(); + } + + std::atomic* getEventFlagWord() override { return mQueue->getEventFlagWord(); } + + virtual size_t availableToRead() override { return mQueue->availableToRead(); } + + virtual bool read(V2_1::Event* events, size_t numToRead) override { + return mQueue->read(events, numToRead); + } + + bool write(const std::vector& events) override { + return mQueue->write(events.data(), events.size()); + } + + private: + std::unique_ptr mQueue; +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace sensors +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SENSORS_V2_1_EVENTMESSAGEQUEUEWRAPPER_H \ No newline at end of file diff --git a/sensors/common/utils/ISensorsWrapper.h b/sensors/common/utils/ISensorsWrapper.h new file mode 100644 index 0000000000..4c8b442396 --- /dev/null +++ b/sensors/common/utils/ISensorsWrapper.h @@ -0,0 +1,209 @@ +/* + * 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_SENSORS_V2_1_ISENSORSWRAPPER_H +#define ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSWRAPPER_H + +#include "EventMessageQueueWrapper.h" +#include "convertV2_1.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +/** + * ISensorsWrapperBase wraps around the V2_1::ISensors APIs to make any HAL 2.0/2.1 interface + * appear as a HAL 2.1 implementation. This ensures the maximum amount of code can be shared + * between VTS, default implementations, and the sensors framework. + */ + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_1 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::sensors::V1_0::OperationMode; +using ::android::hardware::sensors::V1_0::RateLevel; +using ::android::hardware::sensors::V1_0::Result; +using ::android::hardware::sensors::V1_0::SharedMemInfo; + +// TODO: Look into providing this as a param if it needs to be a different value +// than the framework. +static constexpr size_t MAX_RECEIVE_BUFFER_EVENT_COUNT = 256; + +class ISensorsWrapperBase : public RefBase { + public: + virtual ~ISensorsWrapperBase() {} + + virtual EventMessageQueueWrapperBase& getEventQueue() = 0; + virtual Return getSensorsList(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) = 0; + virtual Return injectSensorData(const V2_1::Event& event) = 0; + virtual Return initialize( + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) = 0; + + // V2_0::ISensors implementation + void linkToDeath(android::sp deathRecipient, + uint64_t cookie) { + getSensors()->linkToDeath(deathRecipient, cookie); + } + + Return activate(int32_t sensorHandle, bool enabled) { + return getSensors()->activate(sensorHandle, enabled); + } + + Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) { + return getSensors()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); + } + + Return flush(int32_t sensorHandle) { return getSensors()->flush(sensorHandle); } + + Return registerDirectChannel(const SharedMemInfo& mem, + V2_0::ISensors::registerDirectChannel_cb _hidl_cb) { + return getSensors()->registerDirectChannel(mem, _hidl_cb); + } + + Return unregisterDirectChannel(int32_t channelHandle) { + return getSensors()->unregisterDirectChannel(channelHandle); + } + + Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + V2_0::ISensors::configDirectReport_cb _hidl_cb) { + return getSensors()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); + } + + Return setOperationMode(OperationMode mode) { + return getSensors()->setOperationMode(mode); + } + + private: + virtual V2_0::ISensors* getSensors() = 0; +}; + +class ISensorsWrapperV2_0 : public ISensorsWrapperBase { + public: + typedef MessageQueue + EventMessageQueue; + + ISensorsWrapperV2_0(sp& sensors) : mSensors(sensors) { + auto eventQueue = std::make_unique(MAX_RECEIVE_BUFFER_EVENT_COUNT, + true /* configureEventFlagWord */); + mEventQueue = std::make_unique(eventQueue); + } + + EventMessageQueueWrapperBase& getEventQueue() override { return *mEventQueue; } + + Return initialize( + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) override { + return mSensors->initialize(*mEventQueue->getDesc(), wakeLockDescriptor, sensorsCallback); + } + + Return getSensorsList(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override { + return getSensors()->getSensorsList( + [&](const auto& list) { _hidl_cb(convertToNewSensorInfos(list)); }); + } + + Return injectSensorData(const V2_1::Event& event) override { + return mSensors->injectSensorData(convertToOldEvent(event)); + } + + private: + V2_0::ISensors* getSensors() override { return mSensors.get(); } + + sp mSensors; + std::unique_ptr mEventQueue; +}; + +class ISensorsWrapperV2_1 : public ISensorsWrapperBase { + public: + typedef MessageQueue + EventMessageQueue; + + ISensorsWrapperV2_1(sp& sensors) : mSensors(sensors) { + auto eventQueue = std::make_unique(MAX_RECEIVE_BUFFER_EVENT_COUNT, + true /* configureEventFlagWord */); + mEventQueue = std::make_unique(eventQueue); + } + + EventMessageQueueWrapperBase& getEventQueue() override { return *mEventQueue; } + + Return initialize( + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) override { + return mSensors->initialize_2_1(*mEventQueue->getDesc(), wakeLockDescriptor, + sensorsCallback); + } + + Return getSensorsList(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override { + return mSensors->getSensorsList_2_1(_hidl_cb); + } + + Return injectSensorData(const V2_1::Event& event) override { + return mSensors->injectSensorData_2_1(event); + } + + private: + V2_0::ISensors* getSensors() override { return mSensors.get(); } + + sp mSensors; + std::unique_ptr mEventQueue; +}; + +inline sp wrapISensors(sp sensors) { + return new ISensorsWrapperV2_0(sensors); +} + +inline sp wrapISensors(sp sensors) { + return new ISensorsWrapperV2_1(sensors); +} + +class NoOpSensorsCallback : public ISensorsCallback { + public: + Return onDynamicSensorsConnected( + const hidl_vec& /* sensorInfos */) override { + return Return(); + } + + Return onDynamicSensorsDisconnected( + const hidl_vec& /* sensorHandles */) override { + return Return(); + } + + Return onDynamicSensorsConnected_2_1( + const hidl_vec& /* sensorInfos */) override { + return Return(); + } +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace sensors +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSWRAPPER_H diff --git a/sensors/common/utils/OWNERS b/sensors/common/utils/OWNERS new file mode 100644 index 0000000000..90c233030e --- /dev/null +++ b/sensors/common/utils/OWNERS @@ -0,0 +1,3 @@ +arthuri@google.com +bduddie@google.com +stange@google.com diff --git a/sensors/common/utils/convertV2_1.h b/sensors/common/utils/convertV2_1.h new file mode 100644 index 0000000000..9231011f3d --- /dev/null +++ b/sensors/common/utils/convertV2_1.h @@ -0,0 +1,122 @@ +/* + * 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_SENSORS_V2_1_CONVERT_H +#define ANDROID_HARDWARE_SENSORS_V2_1_CONVERT_H + +#include +#include +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_1 { +namespace implementation { + +static_assert(sizeof(V1_0::Event) == sizeof(V2_1::Event), + "New and old Event types must have the same size"); +static_assert(sizeof(V1_0::SensorInfo) == sizeof(V2_1::SensorInfo), + "New and old SensorInfo types must have the same size"); + +// The following conversion methods are safe as the only difference between +// V1_0 and V2_1 for these types is an added enum value to SensorType which doesn't +// change the memory layout of the types. +inline const V1_0::Event& convertToOldEvent(const V2_1::Event& event) { + return reinterpret_cast(event); +} + +inline const std::vector& convertToOldEvents(const std::vector& events) { + return reinterpret_cast&>(events); +} + +inline V1_0::Event* convertToOldEvent(V2_1::Event* event) { + return reinterpret_cast(event); +} + +inline const V2_1::SensorInfo& convertToNewSensorInfo(const V1_0::SensorInfo& info) { + return reinterpret_cast(info); +} + +inline const V1_0::SensorInfo& convertToOldSensorInfo(const V2_1::SensorInfo& info) { + return reinterpret_cast(info); +} + +inline const V2_1::Event& convertToNewEvent(const V1_0::Event& event) { + return reinterpret_cast(event); +} + +inline const std::vector& convertToNewEvents(const std::vector& events) { + return reinterpret_cast&>(events); +} + +inline const hidl_vec& convertToNewEvents(const hidl_vec& events) { + return reinterpret_cast&>(events); +} + +inline const hidl_vec& convertToNewSensorInfos( + const hidl_vec& infos) { + return reinterpret_cast&>(infos); +} + +inline const hidl_vec& convertToOldSensorInfos( + const hidl_vec& infos) { + return reinterpret_cast&>(infos); +} + +inline void convertFromSensorEvent(const sensors_event_t& src, V2_1::Event* dst) { + switch ((SensorType)src.type) { + case SensorType::HINGE_ANGLE: + // Only fill in values for hinge angle as other sensors + // will have it filled in by legacy code. + *dst = { + .timestamp = src.timestamp, + .sensorHandle = src.sensor, + .sensorType = (SensorType)src.type, + }; + dst->u.scalar = src.data[0]; + break; + default: + V1_0::implementation::convertFromSensorEvent(src, convertToOldEvent(dst)); + break; + } +} + +inline void convertToSensorEvent(const V2_1::Event& src, sensors_event_t* dst) { + switch (src.sensorType) { + case SensorType::HINGE_ANGLE: + // Only fill in values for hinge angle as other sensors + // will have it filled in by legacy code. + *dst = {.version = sizeof(sensors_event_t), + .sensor = src.sensorHandle, + .type = (int32_t)src.sensorType, + .reserved0 = 0, + .timestamp = src.timestamp}; + dst->data[0] = src.u.scalar; + break; + default: + V1_0::implementation::convertToSensorEvent(convertToOldEvent(src), dst); + break; + } +} + +} // namespace implementation +} // namespace V2_1 +} // namespace sensors +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SENSORS_V2_1_CONVERT_H From 8908d6fd517f2b9ce6b571dfbc598638d8e505bc Mon Sep 17 00:00:00 2001 From: Mike Ma Date: Thu, 13 Feb 2020 13:11:00 -0800 Subject: [PATCH 0597/1022] Add proto dumpstate mode Add a "PROTO" dumpstate mode to request a protobuf dump from IDumpstateDevice HAL, primarily used by incidentd to get device-specific state as a proto for automated issue reporting and debugging. Since the format of these states can vary across vendors and devices, the proto schema will not be defined in AOSP. Bug: 140521164 Test: VtsHalDumpstateV1_1TargetTest Change-Id: I1d586c99b654471db5028039792c3d9e6e2184bb --- current.txt | 2 +- dumpstate/1.1/types.hal | 7 +++++++ .../1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/current.txt b/current.txt index adffc8d868..d3dee6212a 100644 --- a/current.txt +++ b/current.txt @@ -645,7 +645,7 @@ f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardwar 4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types 66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory 994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory -446287268831f4ddfac4a51bb1c32ae1e48e47bccd535fccc2c4546d0e7c4013 android.hardware.dumpstate@1.1::types +d9df99be0f59d8f33a9699fe316c67bfd11818aa69440bb1123ba43e717cea85 android.hardware.dumpstate@1.1::types 186bc152ae189ab48f3a761a44ddf5edd0d483073c5b6ca1f802f8b50488b754 android.hardware.dumpstate@1.1::IDumpstateDevice 769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types 626db710bf917ecf551a0b0b1f25be10bf52758f43e0fc808b148b6aae2ef73e android.hardware.gnss@2.1::IGnss diff --git a/dumpstate/1.1/types.hal b/dumpstate/1.1/types.hal index f5cbade151..c522f7cb8b 100644 --- a/dumpstate/1.1/types.hal +++ b/dumpstate/1.1/types.hal @@ -55,6 +55,13 @@ enum DumpstateMode : uint32_t { * This mode MUST be supported if the dumpstate HAL is implemented. */ DEFAULT = 6, + /** + * Takes a report in protobuf. + * + * The content, if implemented, must be a binary protobuf message written to the first file + * descriptor of the native handle. The protobuf schema shall be defined by the vendor. + */ + PROTO = 7, }; /** diff --git a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp index 51dce5e345..cbdd87bc78 100644 --- a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp +++ b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp @@ -92,7 +92,8 @@ class DumpstateHidl1_1Test : public ::testing::TestWithParam { TEST_FOR_DUMPSTATE_MODE(name, body, WEAR); \ TEST_FOR_DUMPSTATE_MODE(name, body, CONNECTIVITY); \ TEST_FOR_DUMPSTATE_MODE(name, body, WIFI); \ - TEST_FOR_DUMPSTATE_MODE(name, body, DEFAULT); + TEST_FOR_DUMPSTATE_MODE(name, body, DEFAULT); \ + TEST_FOR_DUMPSTATE_MODE(name, body, PROTO); constexpr uint64_t kDefaultTimeoutMillis = 30 * 1000; // 30 seconds From 1d71acc129331cca3bedbfd6c1b350682f0d2fae Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Wed, 5 Feb 2020 19:27:16 -0500 Subject: [PATCH 0598/1022] Add default impl of Sensors HAL 2.1 Create a default implementation of HAL 2.1 that shares 90% of the underlying code with HAL 2.0 since the interfaces are very similar. Bug: 144139857 Test: compile Change-Id: Ic6b139df98ddb1f92833b1f2d65e1cecc297fd41 --- sensors/2.0/default/Android.bp | 12 +- sensors/2.0/default/Sensors.cpp | 259 ------------ sensors/2.0/default/Sensors.h | 191 --------- sensors/2.0/default/SensorsV2_0.h | 39 ++ sensors/2.0/default/service.cpp | 6 +- sensors/2.1/default/Android.bp | 45 +++ sensors/2.1/default/OWNERS | 3 + sensors/2.1/default/SensorsV2_1.cpp | 58 +++ sensors/2.1/default/SensorsV2_1.h | 72 ++++ ...droid.hardware.sensors@2.1-service-mock.rc | 7 + .../default/android.hardware.sensors@2.1.xml | 11 + sensors/2.1/default/service.cpp | 41 ++ sensors/common/default/2.X/Android.bp | 36 ++ sensors/common/default/2.X/OWNERS | 3 + .../default => common/default/2.X}/Sensor.cpp | 27 +- .../default => common/default/2.X}/Sensor.h | 54 +-- sensors/common/default/2.X/Sensors.h | 376 ++++++++++++++++++ 17 files changed, 748 insertions(+), 492 deletions(-) delete mode 100644 sensors/2.0/default/Sensors.cpp delete mode 100644 sensors/2.0/default/Sensors.h create mode 100644 sensors/2.0/default/SensorsV2_0.h create mode 100644 sensors/2.1/default/Android.bp create mode 100644 sensors/2.1/default/OWNERS create mode 100644 sensors/2.1/default/SensorsV2_1.cpp create mode 100644 sensors/2.1/default/SensorsV2_1.h create mode 100644 sensors/2.1/default/android.hardware.sensors@2.1-service-mock.rc create mode 100644 sensors/2.1/default/android.hardware.sensors@2.1.xml create mode 100644 sensors/2.1/default/service.cpp create mode 100644 sensors/common/default/2.X/Android.bp create mode 100644 sensors/common/default/2.X/OWNERS rename sensors/{2.0/default => common/default/2.X}/Sensor.cpp (94%) rename sensors/{2.0/default => common/default/2.X}/Sensor.h (81%) create mode 100644 sensors/common/default/2.X/Sensors.h diff --git a/sensors/2.0/default/Android.bp b/sensors/2.0/default/Android.bp index 62c9487319..bb383273a6 100644 --- a/sensors/2.0/default/Android.bp +++ b/sensors/2.0/default/Android.bp @@ -20,13 +20,17 @@ cc_binary { relative_install_path: "hw", srcs: [ "service.cpp", - "Sensor.cpp", - "Sensors.cpp", ], init_rc: ["android.hardware.sensors@2.0-service-mock.rc"], + header_libs: [ + "android.hardware.sensors@2.X-shared-utils", + ], shared_libs: [ "android.hardware.sensors@1.0", "android.hardware.sensors@2.0", + // Needed to compile some shared utilities for both 2.0/2.1 impls, but + // isn't normally needed for a HAL that only supports 2.0. + "android.hardware.sensors@2.1", "libcutils", "libfmq", "libhidlbase", @@ -34,5 +38,9 @@ cc_binary { "libpower", "libutils", ], + static_libs: [ + "android.hardware.sensors@1.0-convert", + "android.hardware.sensors@2.X-shared-impl", + ], vintf_fragments: ["android.hardware.sensors@2.0.xml"], } diff --git a/sensors/2.0/default/Sensors.cpp b/sensors/2.0/default/Sensors.cpp deleted file mode 100644 index 23dd26bccb..0000000000 --- a/sensors/2.0/default/Sensors.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (C) 2018 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 "Sensors.h" - -#include -#include - -namespace android { -namespace hardware { -namespace sensors { -namespace V2_0 { -namespace implementation { - -using ::android::hardware::sensors::V1_0::Event; -using ::android::hardware::sensors::V1_0::OperationMode; -using ::android::hardware::sensors::V1_0::RateLevel; -using ::android::hardware::sensors::V1_0::Result; -using ::android::hardware::sensors::V1_0::SharedMemInfo; -using ::android::hardware::sensors::V2_0::SensorTimeout; -using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; - -constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP"; - -Sensors::Sensors() - : mEventQueueFlag(nullptr), - mNextHandle(1), - mOutstandingWakeUpEvents(0), - mReadWakeLockQueueRun(false), - mAutoReleaseWakeLockTime(0), - mHasWakeLock(false) { - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); -} - -Sensors::~Sensors() { - deleteEventFlag(); - mReadWakeLockQueueRun = false; - mWakeLockThread.join(); -} - -// Methods from ::android::hardware::sensors::V2_0::ISensors follow. -Return Sensors::getSensorsList(getSensorsList_cb _hidl_cb) { - std::vector sensors; - for (const auto& sensor : mSensors) { - sensors.push_back(sensor.second->getSensorInfo()); - } - - // Call the HIDL callback with the SensorInfo - _hidl_cb(sensors); - - return Void(); -} - -Return Sensors::setOperationMode(OperationMode mode) { - for (auto sensor : mSensors) { - sensor.second->setOperationMode(mode); - } - return Result::OK; -} - -Return Sensors::activate(int32_t sensorHandle, bool enabled) { - auto sensor = mSensors.find(sensorHandle); - if (sensor != mSensors.end()) { - sensor->second->activate(enabled); - return Result::OK; - } - return Result::BAD_VALUE; -} - -Return Sensors::initialize( - const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, - const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback) { - Result result = Result::OK; - - // Ensure that all sensors are disabled - for (auto sensor : mSensors) { - sensor.second->activate(false /* enable */); - } - - // Stop the Wake Lock thread if it is currently running - if (mReadWakeLockQueueRun.load()) { - mReadWakeLockQueueRun = false; - mWakeLockThread.join(); - } - - // Save a reference to the callback - mCallback = sensorsCallback; - - // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions. - mEventQueue = - std::make_unique(eventQueueDescriptor, true /* resetPointers */); - - // Ensure that any existing EventFlag is properly deleted - deleteEventFlag(); - - // Create the EventFlag that is used to signal to the framework that sensor events have been - // written to the Event FMQ - if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) { - result = Result::BAD_VALUE; - } - - // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP - // events have been successfully read and handled by the framework. - mWakeLockQueue = - std::make_unique(wakeLockDescriptor, true /* resetPointers */); - - if (!mCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) { - result = Result::BAD_VALUE; - } - - // Start the thread to read events from the Wake Lock FMQ - mReadWakeLockQueueRun = true; - mWakeLockThread = std::thread(startReadWakeLockThread, this); - - return result; -} - -Return Sensors::batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t /* maxReportLatencyNs */) { - auto sensor = mSensors.find(sensorHandle); - if (sensor != mSensors.end()) { - sensor->second->batch(samplingPeriodNs); - return Result::OK; - } - return Result::BAD_VALUE; -} - -Return Sensors::flush(int32_t sensorHandle) { - auto sensor = mSensors.find(sensorHandle); - if (sensor != mSensors.end()) { - return sensor->second->flush(); - } - return Result::BAD_VALUE; -} - -Return Sensors::injectSensorData(const Event& event) { - auto sensor = mSensors.find(event.sensorHandle); - if (sensor != mSensors.end()) { - return sensor->second->injectEvent(event); - } - - return Result::BAD_VALUE; -} - -Return Sensors::registerDirectChannel(const SharedMemInfo& /* mem */, - registerDirectChannel_cb _hidl_cb) { - _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */); - return Return(); -} - -Return Sensors::unregisterDirectChannel(int32_t /* channelHandle */) { - return Result::INVALID_OPERATION; -} - -Return Sensors::configDirectReport(int32_t /* sensorHandle */, int32_t /* channelHandle */, - RateLevel /* rate */, configDirectReport_cb _hidl_cb) { - _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */); - return Return(); -} - -void Sensors::postEvents(const std::vector& events, bool wakeup) { - std::lock_guard lock(mWriteLock); - if (mEventQueue->write(events.data(), events.size())) { - mEventQueueFlag->wake(static_cast(EventQueueFlagBits::READ_AND_PROCESS)); - - if (wakeup) { - // Keep track of the number of outstanding WAKE_UP events in order to properly hold - // a wake lock until the framework has secured a wake lock - updateWakeLock(events.size(), 0 /* eventsHandled */); - } - } -} - -void Sensors::updateWakeLock(int32_t eventsWritten, int32_t eventsHandled) { - std::lock_guard lock(mWakeLockLock); - int32_t newVal = mOutstandingWakeUpEvents + eventsWritten - eventsHandled; - if (newVal < 0) { - mOutstandingWakeUpEvents = 0; - } else { - mOutstandingWakeUpEvents = newVal; - } - - if (eventsWritten > 0) { - // Update the time at which the last WAKE_UP event was sent - mAutoReleaseWakeLockTime = ::android::uptimeMillis() + - static_cast(SensorTimeout::WAKE_LOCK_SECONDS) * 1000; - } - - if (!mHasWakeLock && mOutstandingWakeUpEvents > 0 && - acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLockName) == 0) { - mHasWakeLock = true; - } else if (mHasWakeLock) { - // Check if the wake lock should be released automatically if - // SensorTimeout::WAKE_LOCK_SECONDS has elapsed since the last WAKE_UP event was written to - // the Wake Lock FMQ. - if (::android::uptimeMillis() > mAutoReleaseWakeLockTime) { - ALOGD("No events read from wake lock FMQ for %d seconds, auto releasing wake lock", - SensorTimeout::WAKE_LOCK_SECONDS); - mOutstandingWakeUpEvents = 0; - } - - if (mOutstandingWakeUpEvents == 0 && release_wake_lock(kWakeLockName) == 0) { - mHasWakeLock = false; - } - } -} - -void Sensors::readWakeLockFMQ() { - while (mReadWakeLockQueueRun.load()) { - constexpr int64_t kReadTimeoutNs = 500 * 1000 * 1000; // 500 ms - uint32_t eventsHandled = 0; - - // Read events from the Wake Lock FMQ. Timeout after a reasonable amount of time to ensure - // that any held wake lock is able to be released if it is held for too long. - mWakeLockQueue->readBlocking(&eventsHandled, 1 /* count */, 0 /* readNotification */, - static_cast(WakeLockQueueFlagBits::DATA_WRITTEN), - kReadTimeoutNs); - updateWakeLock(0 /* eventsWritten */, eventsHandled); - } -} - -void Sensors::startReadWakeLockThread(Sensors* sensors) { - sensors->readWakeLockFMQ(); -} - -void Sensors::deleteEventFlag() { - status_t status = EventFlag::deleteEventFlag(&mEventQueueFlag); - if (status != OK) { - ALOGI("Failed to delete event flag: %d", status); - } -} - -} // namespace implementation -} // namespace V2_0 -} // namespace sensors -} // namespace hardware -} // namespace android diff --git a/sensors/2.0/default/Sensors.h b/sensors/2.0/default/Sensors.h deleted file mode 100644 index d06dd78dad..0000000000 --- a/sensors/2.0/default/Sensors.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (C) 2018 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_SENSORS_V2_0_SENSORS_H -#define ANDROID_HARDWARE_SENSORS_V2_0_SENSORS_H - -#include "Sensor.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace android { -namespace hardware { -namespace sensors { -namespace V2_0 { -namespace implementation { - -using ::android::sp; -using ::android::hardware::EventFlag; -using ::android::hardware::hidl_array; -using ::android::hardware::hidl_memory; -using ::android::hardware::hidl_string; -using ::android::hardware::hidl_vec; -using ::android::hardware::MessageQueue; -using ::android::hardware::MQDescriptor; -using ::android::hardware::Return; -using ::android::hardware::Void; - -struct Sensors : public ISensors, public ISensorsEventCallback { - using Event = ::android::hardware::sensors::V1_0::Event; - using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; - using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; - using Result = ::android::hardware::sensors::V1_0::Result; - using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; - - Sensors(); - virtual ~Sensors(); - - // Methods from ::android::hardware::sensors::V2_0::ISensors follow. - Return getSensorsList(getSensorsList_cb _hidl_cb) override; - - Return setOperationMode(OperationMode mode) override; - - Return activate(int32_t sensorHandle, bool enabled) override; - - Return initialize( - const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, - const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback) override; - - Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) override; - - Return flush(int32_t sensorHandle) override; - - Return injectSensorData(const Event& event) override; - - Return registerDirectChannel(const SharedMemInfo& mem, - registerDirectChannel_cb _hidl_cb) override; - - Return unregisterDirectChannel(int32_t channelHandle) override; - - Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, - configDirectReport_cb _hidl_cb) override; - - void postEvents(const std::vector& events, bool wakeup) override; - - private: - /** - * Add a new sensor - */ - template - void AddSensor() { - std::shared_ptr sensor = - std::make_shared(mNextHandle++ /* sensorHandle */, this /* callback */); - mSensors[sensor->getSensorInfo().sensorHandle] = sensor; - } - - /** - * Utility function to delete the Event Flag - */ - void deleteEventFlag(); - - /** - * Function to read the Wake Lock FMQ and release the wake lock when appropriate - */ - void readWakeLockFMQ(); - - static void startReadWakeLockThread(Sensors* sensors); - - /** - * Responsible for acquiring and releasing a wake lock when there are unhandled WAKE_UP events - */ - void updateWakeLock(int32_t eventsWritten, int32_t eventsHandled); - - using EventMessageQueue = MessageQueue; - using WakeLockMessageQueue = MessageQueue; - - /** - * The Event FMQ where sensor events are written - */ - std::unique_ptr mEventQueue; - - /** - * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events - */ - std::unique_ptr mWakeLockQueue; - - /** - * Event Flag to signal to the framework when sensor events are available to be read - */ - EventFlag* mEventQueueFlag; - - /** - * Callback for asynchronous events, such as dynamic sensor connections. - */ - sp mCallback; - - /** - * A map of the available sensors - */ - std::map> mSensors; - - /** - * The next available sensor handle - */ - int32_t mNextHandle; - - /** - * Lock to protect writes to the FMQs - */ - std::mutex mWriteLock; - - /** - * Lock to protect acquiring and releasing the wake lock - */ - std::mutex mWakeLockLock; - - /** - * Track the number of WAKE_UP events that have not been handled by the framework - */ - uint32_t mOutstandingWakeUpEvents; - - /** - * A thread to read the Wake Lock FMQ - */ - std::thread mWakeLockThread; - - /** - * Flag to indicate that the Wake Lock Thread should continue to run - */ - std::atomic_bool mReadWakeLockQueueRun; - - /** - * Track the time when the wake lock should automatically be released - */ - int64_t mAutoReleaseWakeLockTime; - - /** - * Flag to indicate if a wake lock has been acquired - */ - bool mHasWakeLock; -}; - -} // namespace implementation -} // namespace V2_0 -} // namespace sensors -} // namespace hardware -} // namespace android - -#endif // ANDROID_HARDWARE_SENSORS_V2_0_SENSORS_H diff --git a/sensors/2.0/default/SensorsV2_0.h b/sensors/2.0/default/SensorsV2_0.h new file mode 100644 index 0000000000..345835a186 --- /dev/null +++ b/sensors/2.0/default/SensorsV2_0.h @@ -0,0 +1,39 @@ +/* + * 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_SENSORS_V2_0_H +#define ANDROID_HARDWARE_SENSORS_V2_0_H + +#include "Sensors.h" + +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace implementation { + +struct SensorsV2_0 : public ::android::hardware::sensors::V2_X::implementation::Sensors { +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SENSORS_V2_0_H \ No newline at end of file diff --git a/sensors/2.0/default/service.cpp b/sensors/2.0/default/service.cpp index 5c13e331d0..e20bf85df3 100644 --- a/sensors/2.0/default/service.cpp +++ b/sensors/2.0/default/service.cpp @@ -20,17 +20,17 @@ #include #include #include -#include "Sensors.h" +#include "SensorsV2_0.h" using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; using android::hardware::sensors::V2_0::ISensors; -using android::hardware::sensors::V2_0::implementation::Sensors; +using android::hardware::sensors::V2_0::implementation::SensorsV2_0; int main(int /* argc */, char** /* argv */) { configureRpcThreadpool(1, true); - android::sp sensors = new Sensors(); + android::sp sensors = new SensorsV2_0(); if (sensors->registerAsService() != ::android::OK) { ALOGE("Failed to register Sensors HAL instance"); return -1; diff --git a/sensors/2.1/default/Android.bp b/sensors/2.1/default/Android.bp new file mode 100644 index 0000000000..27b439d422 --- /dev/null +++ b/sensors/2.1/default/Android.bp @@ -0,0 +1,45 @@ +// +// Copyright (C) 2018 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. + +cc_binary { + name: "android.hardware.sensors@2.1-service.mock", + defaults: ["hidl_defaults"], + vendor: true, + relative_install_path: "hw", + srcs: [ + "SensorsV2_1.cpp", + "service.cpp", + ], + init_rc: ["android.hardware.sensors@2.1-service-mock.rc"], + header_libs: [ + "android.hardware.sensors@2.X-shared-utils", + ], + shared_libs: [ + "android.hardware.sensors@1.0", + "android.hardware.sensors@2.0", + "android.hardware.sensors@2.1", + "libcutils", + "libfmq", + "libhidlbase", + "liblog", + "libpower", + "libutils", + ], + static_libs: [ + "android.hardware.sensors@1.0-convert", + "android.hardware.sensors@2.X-shared-impl", + ], + vintf_fragments: ["android.hardware.sensors@2.1.xml"], +} diff --git a/sensors/2.1/default/OWNERS b/sensors/2.1/default/OWNERS new file mode 100644 index 0000000000..90c233030e --- /dev/null +++ b/sensors/2.1/default/OWNERS @@ -0,0 +1,3 @@ +arthuri@google.com +bduddie@google.com +stange@google.com diff --git a/sensors/2.1/default/SensorsV2_1.cpp b/sensors/2.1/default/SensorsV2_1.cpp new file mode 100644 index 0000000000..adf874ebac --- /dev/null +++ b/sensors/2.1/default/SensorsV2_1.cpp @@ -0,0 +1,58 @@ +/* + * 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 "SensorsV2_1.h" + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_1 { +namespace implementation { + +// Methods from ::android::hardware::sensors::V2_1::ISensors follow. +Return SensorsV2_1::getSensorsList_2_1(ISensors::getSensorsList_2_1_cb _hidl_cb) { + std::vector sensors; + for (const auto& sensor : mSensors) { + sensors.push_back(convertToNewSensorInfo(sensor.second->getSensorInfo())); + } + + // Call the HIDL callback with the SensorInfo + _hidl_cb(sensors); + + return Void(); +} + +Return SensorsV2_1::initialize_2_1( + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) { + auto eventQueue = std::make_unique>( + eventQueueDescriptor, true /* resetPointers */); + std::unique_ptr wrapper = + std::make_unique(eventQueue); + mCallbackWrapper = new ISensorsCallbackWrapper(sensorsCallback); + return initializeBase(wrapper, wakeLockDescriptor, mCallbackWrapper); +} + +Return SensorsV2_1::injectSensorData_2_1(const V2_1::Event& event) { + return injectSensorData(convertToOldEvent(event)); +} + +} // namespace implementation +} // namespace V2_1 +} // namespace sensors +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/sensors/2.1/default/SensorsV2_1.h b/sensors/2.1/default/SensorsV2_1.h new file mode 100644 index 0000000000..9cd16a7ec3 --- /dev/null +++ b/sensors/2.1/default/SensorsV2_1.h @@ -0,0 +1,72 @@ +/* + * 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_SENSORS_V2_1_H +#define ANDROID_HARDWARE_SENSORS_V2_1_H + +#include "Sensors.h" + +#include "EventMessageQueueWrapper.h" + +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_1 { +namespace implementation { + +using Result = ::android::hardware::sensors::V1_0::Result; +using Sensors = ::android::hardware::sensors::V2_X::implementation::Sensors; + +class ISensorsCallbackWrapper : public V2_0::ISensorsCallback { + public: + ISensorsCallbackWrapper(const sp& callback) : mCallback(callback) {} + + Return onDynamicSensorsConnected(const hidl_vec& sensorInfos) override { + return mCallback->onDynamicSensorsConnected_2_1(convertToNewSensorInfos(sensorInfos)); + } + + Return onDynamicSensorsDisconnected(const hidl_vec& sensorHandles) override { + return mCallback->onDynamicSensorsDisconnected(sensorHandles); + } + + private: + sp mCallback; +}; + +struct SensorsV2_1 : public Sensors { + // Methods from ::android::hardware::sensors::V2_1::ISensors follow. + Return getSensorsList_2_1(ISensors::getSensorsList_2_1_cb _hidl_cb) override; + + Return initialize_2_1( + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) override; + + Return injectSensorData_2_1(const V2_1::Event& event) override; + + private: + sp mCallbackWrapper; +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace sensors +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SENSORS_V2_1_H \ No newline at end of file diff --git a/sensors/2.1/default/android.hardware.sensors@2.1-service-mock.rc b/sensors/2.1/default/android.hardware.sensors@2.1-service-mock.rc new file mode 100644 index 0000000000..d4147e75da --- /dev/null +++ b/sensors/2.1/default/android.hardware.sensors@2.1-service-mock.rc @@ -0,0 +1,7 @@ +service vendor.sensors-hal-2-1-mock /vendor/bin/hw/android.hardware.sensors@2.1-service.mock + interface android.hardware.sensors@2.0::ISensors default + interface android.hardware.sensors@2.1::ISensors default + class hal + user system + group system + rlimit rtprio 10 10 diff --git a/sensors/2.1/default/android.hardware.sensors@2.1.xml b/sensors/2.1/default/android.hardware.sensors@2.1.xml new file mode 100644 index 0000000000..18bd3ae83b --- /dev/null +++ b/sensors/2.1/default/android.hardware.sensors@2.1.xml @@ -0,0 +1,11 @@ + + + android.hardware.sensors + hwbinder + 2.1 + + ISensors + default + + + diff --git a/sensors/2.1/default/service.cpp b/sensors/2.1/default/service.cpp new file mode 100644 index 0000000000..1f3087c1fd --- /dev/null +++ b/sensors/2.1/default/service.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 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 "android.hardware.sensors@2.1-service" + +#include +#include +#include +#include +#include "SensorsV2_1.h" + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::sensors::V2_1::ISensors; +using android::hardware::sensors::V2_1::implementation::SensorsV2_1; + +int main(int /* argc */, char** /* argv */) { + configureRpcThreadpool(1, true); + + android::sp sensors = new SensorsV2_1(); + if (sensors->registerAsService() != ::android::OK) { + ALOGE("Failed to register Sensors HAL instance"); + return -1; + } + + joinRpcThreadpool(); + return 1; // joinRpcThreadpool shouldn't exit +} diff --git a/sensors/common/default/2.X/Android.bp b/sensors/common/default/2.X/Android.bp new file mode 100644 index 0000000000..ea75a104bd --- /dev/null +++ b/sensors/common/default/2.X/Android.bp @@ -0,0 +1,36 @@ +// +// 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. + +cc_library_static { + name: "android.hardware.sensors@2.X-shared-impl", + vendor: true, + export_include_dirs: ["."], + srcs: [ + "Sensor.cpp", + ], + header_libs: [ + "android.hardware.sensors@2.X-shared-utils", + ], + shared_libs: [ + "android.hardware.sensors@1.0", + "android.hardware.sensors@2.0", + "libcutils", + "libfmq", + "libhidlbase", + "liblog", + "libpower", + "libutils", + ], +} diff --git a/sensors/common/default/2.X/OWNERS b/sensors/common/default/2.X/OWNERS new file mode 100644 index 0000000000..90c233030e --- /dev/null +++ b/sensors/common/default/2.X/OWNERS @@ -0,0 +1,3 @@ +arthuri@google.com +bduddie@google.com +stange@google.com diff --git a/sensors/2.0/default/Sensor.cpp b/sensors/common/default/2.X/Sensor.cpp similarity index 94% rename from sensors/2.0/default/Sensor.cpp rename to sensors/common/default/2.X/Sensor.cpp index c09173f7ce..4c40d1f33b 100644 --- a/sensors/2.0/default/Sensor.cpp +++ b/sensors/common/default/2.X/Sensor.cpp @@ -23,12 +23,17 @@ namespace android { namespace hardware { namespace sensors { -namespace V2_0 { +namespace V2_X { namespace implementation { +using ::android::hardware::sensors::V1_0::Event; using ::android::hardware::sensors::V1_0::MetaDataEventType; +using ::android::hardware::sensors::V1_0::OperationMode; +using ::android::hardware::sensors::V1_0::Result; using ::android::hardware::sensors::V1_0::SensorFlagBits; +using ::android::hardware::sensors::V1_0::SensorInfo; using ::android::hardware::sensors::V1_0::SensorStatus; +using ::android::hardware::sensors::V1_0::SensorType; static constexpr float kDefaultMaxDelayUs = 10 * 1000 * 1000; @@ -204,8 +209,8 @@ AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback) mSensorInfo.typeAsString = ""; mSensorInfo.maxRange = 78.4f; // +/- 8g mSensorInfo.resolution = 1.52e-5; - mSensorInfo.power = 0.001f; // mA - mSensorInfo.minDelay = 20 * 1000; // microseconds + mSensorInfo.power = 0.001f; // mA + mSensorInfo.minDelay = 20 * 1000; // microseconds mSensorInfo.maxDelay = kDefaultMaxDelayUs; mSensorInfo.fifoReservedEventCount = 0; mSensorInfo.fifoMaxEventCount = 0; @@ -221,9 +226,9 @@ PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* call mSensorInfo.version = 1; mSensorInfo.type = SensorType::PRESSURE; mSensorInfo.typeAsString = ""; - mSensorInfo.maxRange = 1100.0f; // hPa - mSensorInfo.resolution = 0.005f; // hPa - mSensorInfo.power = 0.001f; // mA + mSensorInfo.maxRange = 1100.0f; // hPa + mSensorInfo.resolution = 0.005f; // hPa + mSensorInfo.power = 0.001f; // mA mSensorInfo.minDelay = 100 * 1000; // microseconds mSensorInfo.maxDelay = kDefaultMaxDelayUs; mSensorInfo.fifoReservedEventCount = 0; @@ -242,7 +247,7 @@ MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallba mSensorInfo.typeAsString = ""; mSensorInfo.maxRange = 1300.0f; mSensorInfo.resolution = 0.01f; - mSensorInfo.power = 0.001f; // mA + mSensorInfo.power = 0.001f; // mA mSensorInfo.minDelay = 20 * 1000; // microseconds mSensorInfo.maxDelay = kDefaultMaxDelayUs; mSensorInfo.fifoReservedEventCount = 0; @@ -261,8 +266,8 @@ LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback) mSensorInfo.typeAsString = ""; mSensorInfo.maxRange = 43000.0f; mSensorInfo.resolution = 10.0f; - mSensorInfo.power = 0.001f; // mA - mSensorInfo.minDelay = 200 * 1000; // microseconds + mSensorInfo.power = 0.001f; // mA + mSensorInfo.minDelay = 200 * 1000; // microseconds mSensorInfo.maxDelay = kDefaultMaxDelayUs; mSensorInfo.fifoReservedEventCount = 0; mSensorInfo.fifoMaxEventCount = 0; @@ -280,7 +285,7 @@ ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* ca mSensorInfo.typeAsString = ""; mSensorInfo.maxRange = 5.0f; mSensorInfo.resolution = 1.0f; - mSensorInfo.power = 0.012f; // mA + mSensorInfo.power = 0.012f; // mA mSensorInfo.minDelay = 200 * 1000; // microseconds mSensorInfo.maxDelay = kDefaultMaxDelayUs; mSensorInfo.fifoReservedEventCount = 0; @@ -367,7 +372,7 @@ RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle, } } // namespace implementation -} // namespace V2_0 +} // namespace V2_X } // namespace sensors } // namespace hardware } // namespace android diff --git a/sensors/2.0/default/Sensor.h b/sensors/common/default/2.X/Sensor.h similarity index 81% rename from sensors/2.0/default/Sensor.h rename to sensors/common/default/2.X/Sensor.h index 61900fa436..8592c412a4 100644 --- a/sensors/2.0/default/Sensor.h +++ b/sensors/common/default/2.X/Sensor.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_SENSORS_V2_0_SENSOR_H -#define ANDROID_HARDWARE_SENSORS_V2_0_SENSOR_H +#ifndef ANDROID_HARDWARE_SENSORS_V2_X_SENSOR_H +#define ANDROID_HARDWARE_SENSORS_V2_X_SENSOR_H #include @@ -25,26 +25,28 @@ #include #include -using ::android::hardware::sensors::V1_0::Event; -using ::android::hardware::sensors::V1_0::OperationMode; -using ::android::hardware::sensors::V1_0::Result; -using ::android::hardware::sensors::V1_0::SensorInfo; -using ::android::hardware::sensors::V1_0::SensorType; - namespace android { namespace hardware { namespace sensors { -namespace V2_0 { +namespace V2_X { namespace implementation { class ISensorsEventCallback { - public: + public: + using Event = ::android::hardware::sensors::V1_0::Event; + virtual ~ISensorsEventCallback(){}; virtual void postEvents(const std::vector& events, bool wakeup) = 0; }; class Sensor { - public: + public: + using Event = ::android::hardware::sensors::V1_0::Event; + using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; + using Result = ::android::hardware::sensors::V1_0::Result; + using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo; + using SensorType = ::android::hardware::sensors::V1_0::SensorType; + Sensor(ISensorsEventCallback* callback); virtual ~Sensor(); @@ -57,7 +59,7 @@ class Sensor { bool supportsDataInjection() const; Result injectEvent(const Event& event); - protected: + protected: void run(); virtual std::vector readEvents(); static void startThread(Sensor* sensor); @@ -80,68 +82,68 @@ class Sensor { }; class OnChangeSensor : public Sensor { - public: + public: OnChangeSensor(ISensorsEventCallback* callback); virtual void activate(bool enable) override; - protected: + protected: virtual std::vector readEvents() override; - protected: + protected: Event mPreviousEvent; bool mPreviousEventSet; }; class AccelSensor : public Sensor { - public: + public: AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback); }; class GyroSensor : public Sensor { - public: + public: GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback); }; class AmbientTempSensor : public OnChangeSensor { - public: + public: AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback); }; class DeviceTempSensor : public OnChangeSensor { - public: + public: DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback); }; class PressureSensor : public Sensor { - public: + public: PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback); }; class MagnetometerSensor : public Sensor { - public: + public: MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback); }; class LightSensor : public OnChangeSensor { - public: + public: LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback); }; class ProximitySensor : public OnChangeSensor { - public: + public: ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback); }; class RelativeHumiditySensor : public OnChangeSensor { - public: + public: RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback); }; } // namespace implementation -} // namespace V2_0 +} // namespace V2_X } // namespace sensors } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_SENSORS_V2_0_SENSOR_H +#endif // ANDROID_HARDWARE_SENSORS_V2_X_SENSOR_H diff --git a/sensors/common/default/2.X/Sensors.h b/sensors/common/default/2.X/Sensors.h new file mode 100644 index 0000000000..de998ebb05 --- /dev/null +++ b/sensors/common/default/2.X/Sensors.h @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2018 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_SENSORS_V2_X_SENSORS_H +#define ANDROID_HARDWARE_SENSORS_V2_X_SENSORS_H + +#include "EventMessageQueueWrapper.h" +#include "Sensor.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_X { +namespace implementation { + +template +struct Sensors : public ISensorsInterface, public ISensorsEventCallback { + using Event = ::android::hardware::sensors::V1_0::Event; + using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; + using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; + using Result = ::android::hardware::sensors::V1_0::Result; + using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; + using EventQueueFlagBits = ::android::hardware::sensors::V2_0::EventQueueFlagBits; + using SensorTimeout = ::android::hardware::sensors::V2_0::SensorTimeout; + using WakeLockQueueFlagBits = ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; + using ISensorsCallback = ::android::hardware::sensors::V2_0::ISensorsCallback; + using EventMessageQueue = MessageQueue; + using WakeLockMessageQueue = MessageQueue; + + static constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP"; + + Sensors() + : mEventQueueFlag(nullptr), + mNextHandle(1), + mOutstandingWakeUpEvents(0), + mReadWakeLockQueueRun(false), + mAutoReleaseWakeLockTime(0), + mHasWakeLock(false) { + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + } + + virtual ~Sensors() { + deleteEventFlag(); + mReadWakeLockQueueRun = false; + mWakeLockThread.join(); + } + + // Methods from ::android::hardware::sensors::V2_0::ISensors follow. + Return getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override { + std::vector sensors; + for (const auto& sensor : mSensors) { + sensors.push_back(sensor.second->getSensorInfo()); + } + + // Call the HIDL callback with the SensorInfo + _hidl_cb(sensors); + + return Void(); + } + + Return setOperationMode(OperationMode mode) override { + for (auto sensor : mSensors) { + sensor.second->setOperationMode(mode); + } + return Result::OK; + } + + Return activate(int32_t sensorHandle, bool enabled) override { + auto sensor = mSensors.find(sensorHandle); + if (sensor != mSensors.end()) { + sensor->second->activate(enabled); + return Result::OK; + } + return Result::BAD_VALUE; + } + + Return initialize( + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) override { + auto eventQueue = + std::make_unique(eventQueueDescriptor, true /* resetPointers */); + std::unique_ptr wrapper = + std::make_unique(eventQueue); + return initializeBase(wrapper, wakeLockDescriptor, sensorsCallback); + } + + Return initializeBase( + std::unique_ptr& eventQueue, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) { + Result result = Result::OK; + + // Ensure that all sensors are disabled + for (auto sensor : mSensors) { + sensor.second->activate(false /* enable */); + } + + // Stop the Wake Lock thread if it is currently running + if (mReadWakeLockQueueRun.load()) { + mReadWakeLockQueueRun = false; + mWakeLockThread.join(); + } + + // Save a reference to the callback + mCallback = sensorsCallback; + + // Save the event queue. + mEventQueue = std::move(eventQueue); + + // Ensure that any existing EventFlag is properly deleted + deleteEventFlag(); + + // Create the EventFlag that is used to signal to the framework that sensor events have been + // written to the Event FMQ + if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) { + result = Result::BAD_VALUE; + } + + // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP + // events have been successfully read and handled by the framework. + mWakeLockQueue = std::make_unique(wakeLockDescriptor, + true /* resetPointers */); + + if (!mCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) { + result = Result::BAD_VALUE; + } + + // Start the thread to read events from the Wake Lock FMQ + mReadWakeLockQueueRun = true; + mWakeLockThread = std::thread(startReadWakeLockThread, this); + + return result; + } + + Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t /* maxReportLatencyNs */) override { + auto sensor = mSensors.find(sensorHandle); + if (sensor != mSensors.end()) { + sensor->second->batch(samplingPeriodNs); + return Result::OK; + } + return Result::BAD_VALUE; + } + + Return flush(int32_t sensorHandle) override { + auto sensor = mSensors.find(sensorHandle); + if (sensor != mSensors.end()) { + return sensor->second->flush(); + } + return Result::BAD_VALUE; + } + + Return injectSensorData(const Event& event) override { + auto sensor = mSensors.find(event.sensorHandle); + if (sensor != mSensors.end()) { + return sensor->second->injectEvent(event); + } + + return Result::BAD_VALUE; + } + + Return registerDirectChannel(const SharedMemInfo& /* mem */, + V2_0::ISensors::registerDirectChannel_cb _hidl_cb) override { + _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */); + return Return(); + } + + Return unregisterDirectChannel(int32_t /* channelHandle */) override { + return Result::INVALID_OPERATION; + } + + Return configDirectReport(int32_t /* sensorHandle */, int32_t /* channelHandle */, + RateLevel /* rate */, + V2_0::ISensors::configDirectReport_cb _hidl_cb) override { + _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */); + return Return(); + } + + void postEvents(const std::vector& events, bool wakeup) override { + std::lock_guard lock(mWriteLock); + if (mEventQueue->write(V2_1::implementation::convertToNewEvents(events))) { + mEventQueueFlag->wake(static_cast(EventQueueFlagBits::READ_AND_PROCESS)); + + if (wakeup) { + // Keep track of the number of outstanding WAKE_UP events in order to properly hold + // a wake lock until the framework has secured a wake lock + updateWakeLock(events.size(), 0 /* eventsHandled */); + } + } + } + + protected: + /** + * Add a new sensor + */ + template + void AddSensor() { + std::shared_ptr sensor = + std::make_shared(mNextHandle++ /* sensorHandle */, this /* callback */); + mSensors[sensor->getSensorInfo().sensorHandle] = sensor; + } + + /** + * Utility function to delete the Event Flag + */ + void deleteEventFlag() { + status_t status = EventFlag::deleteEventFlag(&mEventQueueFlag); + if (status != OK) { + ALOGI("Failed to delete event flag: %d", status); + } + } + + static void startReadWakeLockThread(Sensors* sensors) { sensors->readWakeLockFMQ(); } + + /** + * Function to read the Wake Lock FMQ and release the wake lock when appropriate + */ + void readWakeLockFMQ() { + while (mReadWakeLockQueueRun.load()) { + constexpr int64_t kReadTimeoutNs = 500 * 1000 * 1000; // 500 ms + uint32_t eventsHandled = 0; + + // Read events from the Wake Lock FMQ. Timeout after a reasonable amount of time to + // ensure that any held wake lock is able to be released if it is held for too long. + mWakeLockQueue->readBlocking(&eventsHandled, 1 /* count */, 0 /* readNotification */, + static_cast(WakeLockQueueFlagBits::DATA_WRITTEN), + kReadTimeoutNs); + updateWakeLock(0 /* eventsWritten */, eventsHandled); + } + } + + /** + * Responsible for acquiring and releasing a wake lock when there are unhandled WAKE_UP events + */ + void updateWakeLock(int32_t eventsWritten, int32_t eventsHandled) { + std::lock_guard lock(mWakeLockLock); + int32_t newVal = mOutstandingWakeUpEvents + eventsWritten - eventsHandled; + if (newVal < 0) { + mOutstandingWakeUpEvents = 0; + } else { + mOutstandingWakeUpEvents = newVal; + } + + if (eventsWritten > 0) { + // Update the time at which the last WAKE_UP event was sent + mAutoReleaseWakeLockTime = + ::android::uptimeMillis() + + static_cast(SensorTimeout::WAKE_LOCK_SECONDS) * 1000; + } + + if (!mHasWakeLock && mOutstandingWakeUpEvents > 0 && + acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLockName) == 0) { + mHasWakeLock = true; + } else if (mHasWakeLock) { + // Check if the wake lock should be released automatically if + // SensorTimeout::WAKE_LOCK_SECONDS has elapsed since the last WAKE_UP event was written + // to the Wake Lock FMQ. + if (::android::uptimeMillis() > mAutoReleaseWakeLockTime) { + ALOGD("No events read from wake lock FMQ for %d seconds, auto releasing wake lock", + SensorTimeout::WAKE_LOCK_SECONDS); + mOutstandingWakeUpEvents = 0; + } + + if (mOutstandingWakeUpEvents == 0 && release_wake_lock(kWakeLockName) == 0) { + mHasWakeLock = false; + } + } + } + + /** + * The Event FMQ where sensor events are written + */ + std::unique_ptr mEventQueue; + + /** + * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events + */ + std::unique_ptr mWakeLockQueue; + + /** + * Event Flag to signal to the framework when sensor events are available to be read + */ + EventFlag* mEventQueueFlag; + + /** + * Callback for asynchronous events, such as dynamic sensor connections. + */ + sp mCallback; + + /** + * A map of the available sensors + */ + std::map> mSensors; + + /** + * The next available sensor handle + */ + int32_t mNextHandle; + + /** + * Lock to protect writes to the FMQs + */ + std::mutex mWriteLock; + + /** + * Lock to protect acquiring and releasing the wake lock + */ + std::mutex mWakeLockLock; + + /** + * Track the number of WAKE_UP events that have not been handled by the framework + */ + uint32_t mOutstandingWakeUpEvents; + + /** + * A thread to read the Wake Lock FMQ + */ + std::thread mWakeLockThread; + + /** + * Flag to indicate that the Wake Lock Thread should continue to run + */ + std::atomic_bool mReadWakeLockQueueRun; + + /** + * Track the time when the wake lock should automatically be released + */ + int64_t mAutoReleaseWakeLockTime; + + /** + * Flag to indicate if a wake lock has been acquired + */ + bool mHasWakeLock; +}; + +} // namespace implementation +} // namespace V2_X +} // namespace sensors +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SENSORS_V2_X_SENSORS_H From 535c63e672c8aa2ba0ba21e899dc6e72b09ca4f8 Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Fri, 14 Feb 2020 17:46:18 -0500 Subject: [PATCH 0599/1022] Add Hinge Angle Sensor to default impl for HAL 2.1 Bug: 144139857 Test: Verify this type is exposed when VTS is run Change-Id: I994f1b4c77729b76760b7cafc19b825c98ca97ca --- sensors/2.1/default/SensorsV2_1.cpp | 33 ++++++++++++++++++++++++++- sensors/2.1/default/SensorsV2_1.h | 2 ++ sensors/common/default/2.X/Android.bp | 1 + sensors/common/default/2.X/Sensor.cpp | 8 +++---- sensors/common/default/2.X/Sensor.h | 11 +++++---- sensors/common/default/2.X/Sensors.h | 9 ++++---- 6 files changed, 50 insertions(+), 14 deletions(-) diff --git a/sensors/2.1/default/SensorsV2_1.cpp b/sensors/2.1/default/SensorsV2_1.cpp index adf874ebac..2e3d315e64 100644 --- a/sensors/2.1/default/SensorsV2_1.cpp +++ b/sensors/2.1/default/SensorsV2_1.cpp @@ -16,17 +16,48 @@ #include "SensorsV2_1.h" +#include "Sensor.h" + namespace android { namespace hardware { namespace sensors { namespace V2_1 { namespace implementation { +using V2_X::implementation::ISensorsEventCallback; +using V2_X::implementation::OnChangeSensor; + +class HingeAngleSensor : public OnChangeSensor { + public: + HingeAngleSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : OnChangeSensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Hinge Angle Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::HINGE_ANGLE; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 360.0f; + mSensorInfo.resolution = 1.0f; + mSensorInfo.power = 0.001f; + mSensorInfo.minDelay = 40 * 1000; // microseconds + mSensorInfo.maxDelay = V2_X::implementation::kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = static_cast(V1_0::SensorFlagBits::ON_CHANGE_MODE); + } +}; + +SensorsV2_1::SensorsV2_1() { + AddSensor(); +} + // Methods from ::android::hardware::sensors::V2_1::ISensors follow. Return SensorsV2_1::getSensorsList_2_1(ISensors::getSensorsList_2_1_cb _hidl_cb) { std::vector sensors; for (const auto& sensor : mSensors) { - sensors.push_back(convertToNewSensorInfo(sensor.second->getSensorInfo())); + sensors.push_back(sensor.second->getSensorInfo()); } // Call the HIDL callback with the SensorInfo diff --git a/sensors/2.1/default/SensorsV2_1.h b/sensors/2.1/default/SensorsV2_1.h index 9cd16a7ec3..9f7fe04ff7 100644 --- a/sensors/2.1/default/SensorsV2_1.h +++ b/sensors/2.1/default/SensorsV2_1.h @@ -49,6 +49,8 @@ class ISensorsCallbackWrapper : public V2_0::ISensorsCallback { }; struct SensorsV2_1 : public Sensors { + SensorsV2_1(); + // Methods from ::android::hardware::sensors::V2_1::ISensors follow. Return getSensorsList_2_1(ISensors::getSensorsList_2_1_cb _hidl_cb) override; diff --git a/sensors/common/default/2.X/Android.bp b/sensors/common/default/2.X/Android.bp index ea75a104bd..8b0d52f06a 100644 --- a/sensors/common/default/2.X/Android.bp +++ b/sensors/common/default/2.X/Android.bp @@ -26,6 +26,7 @@ cc_library_static { shared_libs: [ "android.hardware.sensors@1.0", "android.hardware.sensors@2.0", + "android.hardware.sensors@2.1", "libcutils", "libfmq", "libhidlbase", diff --git a/sensors/common/default/2.X/Sensor.cpp b/sensors/common/default/2.X/Sensor.cpp index 4c40d1f33b..1841dffe2e 100644 --- a/sensors/common/default/2.X/Sensor.cpp +++ b/sensors/common/default/2.X/Sensor.cpp @@ -26,16 +26,14 @@ namespace sensors { namespace V2_X { namespace implementation { -using ::android::hardware::sensors::V1_0::Event; using ::android::hardware::sensors::V1_0::MetaDataEventType; using ::android::hardware::sensors::V1_0::OperationMode; using ::android::hardware::sensors::V1_0::Result; using ::android::hardware::sensors::V1_0::SensorFlagBits; -using ::android::hardware::sensors::V1_0::SensorInfo; using ::android::hardware::sensors::V1_0::SensorStatus; -using ::android::hardware::sensors::V1_0::SensorType; - -static constexpr float kDefaultMaxDelayUs = 10 * 1000 * 1000; +using ::android::hardware::sensors::V2_1::Event; +using ::android::hardware::sensors::V2_1::SensorInfo; +using ::android::hardware::sensors::V2_1::SensorType; Sensor::Sensor(ISensorsEventCallback* callback) : mIsEnabled(false), diff --git a/sensors/common/default/2.X/Sensor.h b/sensors/common/default/2.X/Sensor.h index 8592c412a4..2f8a143764 100644 --- a/sensors/common/default/2.X/Sensor.h +++ b/sensors/common/default/2.X/Sensor.h @@ -18,6 +18,7 @@ #define ANDROID_HARDWARE_SENSORS_V2_X_SENSOR_H #include +#include #include #include @@ -31,9 +32,11 @@ namespace sensors { namespace V2_X { namespace implementation { +static constexpr float kDefaultMaxDelayUs = 10 * 1000 * 1000; + class ISensorsEventCallback { public: - using Event = ::android::hardware::sensors::V1_0::Event; + using Event = ::android::hardware::sensors::V2_1::Event; virtual ~ISensorsEventCallback(){}; virtual void postEvents(const std::vector& events, bool wakeup) = 0; @@ -41,11 +44,11 @@ class ISensorsEventCallback { class Sensor { public: - using Event = ::android::hardware::sensors::V1_0::Event; using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; using Result = ::android::hardware::sensors::V1_0::Result; - using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo; - using SensorType = ::android::hardware::sensors::V1_0::SensorType; + using Event = ::android::hardware::sensors::V2_1::Event; + using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo; + using SensorType = ::android::hardware::sensors::V2_1::SensorType; Sensor(ISensorsEventCallback* callback); virtual ~Sensor(); diff --git a/sensors/common/default/2.X/Sensors.h b/sensors/common/default/2.X/Sensors.h index de998ebb05..ee8240d11c 100644 --- a/sensors/common/default/2.X/Sensors.h +++ b/sensors/common/default/2.X/Sensors.h @@ -82,7 +82,8 @@ struct Sensors : public ISensorsInterface, public ISensorsEventCallback { Return getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override { std::vector sensors; for (const auto& sensor : mSensors) { - sensors.push_back(sensor.second->getSensorInfo()); + sensors.push_back( + V2_1::implementation::convertToOldSensorInfo(sensor.second->getSensorInfo())); } // Call the HIDL callback with the SensorInfo @@ -187,7 +188,7 @@ struct Sensors : public ISensorsInterface, public ISensorsEventCallback { Return injectSensorData(const Event& event) override { auto sensor = mSensors.find(event.sensorHandle); if (sensor != mSensors.end()) { - return sensor->second->injectEvent(event); + return sensor->second->injectEvent(V2_1::implementation::convertToNewEvent(event)); } return Result::BAD_VALUE; @@ -210,9 +211,9 @@ struct Sensors : public ISensorsInterface, public ISensorsEventCallback { return Return(); } - void postEvents(const std::vector& events, bool wakeup) override { + void postEvents(const std::vector& events, bool wakeup) override { std::lock_guard lock(mWriteLock); - if (mEventQueue->write(V2_1::implementation::convertToNewEvents(events))) { + if (mEventQueue->write(events)) { mEventQueueFlag->wake(static_cast(EventQueueFlagBits::READ_AND_PROCESS)); if (wakeup) { From 13c43c00596ce05cafe58771761680220c4fa24b Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Mon, 17 Feb 2020 13:41:37 +0000 Subject: [PATCH 0600/1022] Add parallel linking support for BIDIRECTIONAL_SEQUENCE_{LSTM|RNN} Change-Id: I51396f82de8dd7282db85a26b0a1be84b236b8c1 Fix: 138653129 Test: NNTest_static and VtsHalNeuralnetworksV1_3TargetTest --- current.txt | 4 +- neuralnetworks/1.2/types.hal | 49 ++++++++++--- neuralnetworks/1.3/types.hal | 136 +++++++++++++++++++++++++++-------- 3 files changed, 149 insertions(+), 40 deletions(-) diff --git a/current.txt b/current.txt index 67e2818c0f..4a4d3791f9 100644 --- a/current.txt +++ b/current.txt @@ -597,7 +597,7 @@ eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardwar 5f6d3097ba84cb63c430787123f4de1b31c11f90b531b98eae9a8623a5ae962a android.hardware.neuralnetworks@1.1::types fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice 40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel -6c29d6fdd5445911df5456b3b84b949cdd59fca0c0b5507662f26a5cac0cf5e5 android.hardware.neuralnetworks@1.2::types +00649d29680f2c47edf60000c3ae7ae906ba638f0616947147e3676a83cf36fa android.hardware.neuralnetworks@1.2::types a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface @@ -676,7 +676,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 2fa3679ad7c94b5e88724adcd560c561041068a4ca565c63830e68101988746a android.hardware.neuralnetworks@1.3::IFencedExecutionCallback 43088ffc71945b463a7279262cfe2e290f6ed2f15d3fd6032798a3be299fb08f android.hardware.neuralnetworks@1.3::IPreparedModel 0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback -306fda32ac969fd51d75d066352cadcb769944ec4823be4cdd3f86fdb9e97511 android.hardware.neuralnetworks@1.3::types +dd39887aa4fb60ce60ea9cc043edeadbbae6e922d09d3946311b0b410024ae14 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal index 993a10513f..f0fd7690ba 100644 --- a/neuralnetworks/1.2/types.hal +++ b/neuralnetworks/1.2/types.hal @@ -2314,7 +2314,38 @@ enum OperationType : int32_t { AXIS_ALIGNED_BBOX_TRANSFORM = 41, /** - * Performs a forward LSTM on the input followed by a backward LSTM. + * A recurrent neural network layer that applies an LSTM cell to a + * sequence of inputs in forward and backward directions. + * + * The op supports cross-linking via an auxiliary input. Regular cell feeds + * one input into the two RNN cells in the following way: + * + * INPUT (INPUT_REVERSED) + * | | + * --------------------- + * | FW_LSTM BW_LSTM | + * --------------------- + * | | + * FW_OUT BW_OUT + * + * An op with cross-linking takes two inputs and feeds them into the RNN + * cells in the following way: + * + * AUX_INPUT (AUX_INPUT_REVERSED) + * | | + * INPUT | (INPUT_R'D.)| + * | | | | + * ----------------------- + * | \ / \ / | + * | FW_LSTM BW_LSTM | + * ----------------------- + * | | + * FW_OUT BW_OUT + * + * The cross-linking mode is enabled iff auxiliary input and auxiliary + * weights are present. While stacking this op on top of itself, this + * allows to connect both forward and backward outputs from previous cell + * to the next cell's input. * * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT16} @@ -2324,7 +2355,6 @@ enum OperationType : int32_t { * * All input and output tensors must be of the same type. * - * * Inputs: * * 0: The input. * A 3-D tensor of shape: @@ -2533,8 +2563,8 @@ enum OperationType : int32_t { * * “activation” is the function passed as the “fused_activation_function” * argument (if not “NONE”). * - * The op also supports an auxiliary input. Regular cell feeds one input - * into the two RNN cells in the following way: + * The op supports cross-linking via an auxiliary input. Regular cell feeds + * one input into the two RNN cells in the following way: * * INPUT (INPUT_REVERSED) * | | @@ -2544,8 +2574,8 @@ enum OperationType : int32_t { * | | * FW_OUT BW_OUT * - * An op with an auxiliary input takes two inputs and feeds them into the - * RNN cells in the following way: + * An op with cross-linking takes two inputs and feeds them into the RNN + * cells in the following way: * * AUX_INPUT (AUX_INPUT_REVERSED) * | | @@ -2558,9 +2588,10 @@ enum OperationType : int32_t { * | | * FW_OUT BW_OUT * - * While stacking this op on top of itself, this allows to connect both - * forward and backward outputs from previous cell to the next cell's - * inputs. + * The cross-linking mode is enabled iff auxiliary input and auxiliary + * weights are present. While stacking this op on top of itself, this + * allows to connect both forward and backward outputs from previous cell + * to the next cell's input. * * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT16} diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index a808a2e512..08d8e6b158 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -2364,7 +2364,54 @@ enum OperationType : int32_t { AXIS_ALIGNED_BBOX_TRANSFORM = @1.2::OperationType:AXIS_ALIGNED_BBOX_TRANSFORM, /** - * Performs a forward LSTM on the input followed by a backward LSTM. + * A recurrent neural network layer that applies an LSTM cell to a + * sequence of inputs in forward and backward directions. + * + * The op supports cross-linking via an auxiliary input. Regular cell feeds + * one input into the two RNN cells in the following way: + * + * INPUT (INPUT_REVERSED) + * | | + * --------------------- + * | FW_LSTM BW_LSTM | + * --------------------- + * | | + * FW_OUT BW_OUT + * + * An op with cross-linking takes two inputs and feeds them into the RNN + * cells in the following way: + * + * AUX_INPUT (AUX_INPUT_REVERSED) + * | | + * INPUT | (INPUT_R'D.)| + * | | | | + * ----------------------- + * | \ / \ / | + * | FW_LSTM BW_LSTM | + * ----------------------- + * | | + * FW_OUT BW_OUT + * + * The cross-linking mode is enabled iff auxiliary input and auxiliary + * weights are present. While stacking this op on top of itself, this + * allows to connect both forward and backward outputs from previous cell + * to the next cell's input. + * + * Since HAL version 1.3 parallel linking mode is supported. The mode is + * enabled if auxiliary input is present but auxiliary weights are omitted. + * In this case, the cell feeds inputs into the RNN in the following way: + * + * INPUT (AUX_INPUT_REVERSED) + * | | + * --------------------- + * | FW_LSTM BW_LSTM | + * --------------------- + * | | + * FW_OUT BW_OUT + * + * While stacking this op on top of itself, this allows to connect both + * forward and backward outputs from previous cell to the next cell's + * corresponding inputs. * * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT16} @@ -2374,7 +2421,6 @@ enum OperationType : int32_t { * * All input and output tensors must be of the same type. * - * * Inputs: * * 0: The input. * A 3-D tensor of shape: @@ -2466,25 +2512,34 @@ enum OperationType : int32_t { * * 38: The backward input cell state. * A 2-D tensor of shape [batch_size, bw_num_units]. * * 39: The auxiliary input. Optional. - * A 3-D tensor of shape [max_time, batch_size, input_size], where “batch_size” - * corresponds to the batching dimension, and “input_size” is the size - * of the input. - * * 40: The forward auxiliary input-to-input weights. Optional. - * A 2-D tensor of shape [fw_num_units, input_size]. - * * 41: The forward auxiliary input-to-forget weights. Optional. - * A 2-D tensor of shape [fw_num_units, input_size]. - * * 42: The forward auxiliary input-to-cell weights. Optional. - * A 2-D tensor of shape [fw_num_units, input_size]. - * * 43: The forward auxiliary input-to-output weights. Optional. - * A 2-D tensor of shape [fw_num_units, input_size]. - * * 44: The backward auxiliary input-to-input weights. Optional. - * A 2-D tensor of shape [bw_num_units, input_size]. - * * 45: The backward auxiliary input-to-forget weights. Optional. - * A 2-D tensor of shape [bw_num_units, input_size]. - * * 46: The backward auxiliary input-to-cell weights. Optional. - * A 2-D tensor of shape [bw_num_units, input_size]. - * * 47: The backward auxiliary input-to-output weights. Optional. - * A 2-D tensor of shape [bw_num_units, input_size]. + * A 3-D tensor of shape [max_time, batch_size, aux_input_size], + * where “batch_size” corresponds to the batching dimension, and + * “aux_input_size” is the size of the auxiliary input. Optional. See + * the docs above for the usage modes explanation. + * * 40: The forward auxiliary input-to-input weights. + * Optional. See the docs above for the usage modes explanation. + * A 2-D tensor of shape [fw_num_units, aux_input_size]. + * * 41: The forward auxiliary input-to-forget weights. + * Optional. See the docs above for the usage modes explanation. + * A 2-D tensor of shape [fw_num_units, aux_input_size]. + * * 42: The forward auxiliary input-to-cell weights. + * Optional. See the docs above for the usage modes explanation. + * A 2-D tensor of shape [fw_num_units, aux_input_size]. + * * 43: The forward auxiliary input-to-output weights. + * Optional. See the docs above for the usage modes explanation. + * A 2-D tensor of shape [fw_num_units, aux_input_size]. + * * 44: The backward auxiliary input-to-input weights. + * Optional. See the docs above for the usage modes explanation. + * A 2-D tensor of shape [bw_num_units, aux_input_size]. + * * 45: The backward auxiliary input-to-forget weights. + * Optional. See the docs above for the usage modes explanation. + * A 2-D tensor of shape [bw_num_units, aux_input_size]. + * * 46: The backward auxiliary input-to-cell weights. + * Optional. See the docs above for the usage modes explanation. + * A 2-D tensor of shape [bw_num_units, aux_input_size]. + * * 47: The backward auxiliary input-to-output weights. + * Optional. See the docs above for the usage modes explanation. + * A 2-D tensor of shape [bw_num_units, aux_input_size]. * * 48: The activation function. * A value indicating the activation function: *

      @@ -2607,8 +2662,8 @@ enum OperationType : int32_t { * * “activation” is the function passed as the “fused_activation_function” * argument (if not “NONE”). * - * The op also supports an auxiliary input. Regular cell feeds one input - * into the two RNN cells in the following way: + * The op supports cross-linking via an auxiliary input. Regular cell feeds + * one input into the two RNN cells in the following way: * * INPUT (INPUT_REVERSED) * | | @@ -2618,8 +2673,8 @@ enum OperationType : int32_t { * | | * FW_OUT BW_OUT * - * An op with an auxiliary input takes two inputs and feeds them into the - * RNN cells in the following way: + * An op with cross-linking takes two inputs and feeds them into the RNN + * cells in the following way: * * AUX_INPUT (AUX_INPUT_REVERSED) * | | @@ -2632,9 +2687,26 @@ enum OperationType : int32_t { * | | * FW_OUT BW_OUT * + * The cross-linking mode is enabled iff auxiliary input and auxiliary + * weights are present. While stacking this op on top of itself, this + * allows to connect both forward and backward outputs from previous cell + * to the next cell's input. + * + * Since HAL version 1.3 parallel linking mode is supported. The mode is + * enabled if auxiliary input is present but auxiliary weights are omitted. + * In this case, the cell feeds inputs into the RNN in the following way: + * + * INPUT (AUX_INPUT_REVERSED) + * | | + * --------------------- + * | FW_RNN BW_RNN | + * --------------------- + * | | + * FW_OUT BW_OUT + * * While stacking this op on top of itself, this allows to connect both * forward and backward outputs from previous cell to the next cell's - * inputs. + * corresponding inputs. * * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT16} @@ -2667,11 +2739,17 @@ enum OperationType : int32_t { * A 2-D tensor of shape [batchSize, bwNumUnits]. Specifies a hidden * state input for the first time step of the computation. * * 9: auxInput. - * A 3-D tensor. The shape is the same as of the input 0. + * A 3-D tensor. The shape is defined by the input 6 (timeMajor). If + * it is set to true, then the input has a shape [maxTime, batchSize, + * auxInputSize], otherwise the input has a shape [batchSize, maxTime, + * auxInputSize]. Can be omitted. See the docs above for the usage + * modes explanation. * * 10:fwAuxWeights. - * A 2-D tensor of shape [fwNumUnits, inputSize]. + * A 2-D tensor of shape [fwNumUnits, auxInputSize]. Can be omitted. + * See the docs above for the usage modes explanation. * * 11:bwAuxWeights. - * A 2-D tensor of shape [bwNumUnits, inputSize]. + * A 2-D tensor of shape [bwNumUnits, auxInputSize]. Can be omitted. + * See the docs above for the usage modes explanation. * * 12:fusedActivationFunction. * A {@link FusedActivationFunc} value indicating the activation function. If * “NONE” is specified then it results in a linear activation. From 6c3929cc33e1204a14e295d6da124440d99faf3e Mon Sep 17 00:00:00 2001 From: Adam Bodnar Date: Tue, 18 Feb 2020 13:21:26 -0800 Subject: [PATCH 0601/1022] Explicitly destroy render engine in RenderEngineVts The GLES driver appears to be left in a bad state without destroying the render engine instance explicitly after every test case. Bug: 149043811 Test: build, adb push out/target/product//testcases/VtsHalGraphicsComposerV2_2TargetTest//VtsHalGraphicsComposerV2_2TargetTest /data/local/tmp && adb shell /data/local/tmp/VtsHalGraphicsComposerV2_2TargetTest Change-Id: I8e3c4e30eaa2ef3b9831da7b335b9a830be4b4ed --- graphics/composer/2.2/utils/vts/RenderEngineVts.cpp | 4 ++++ .../2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp index a23d72c949..c78c358857 100644 --- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp +++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp @@ -33,6 +33,10 @@ TestRenderEngine::TestRenderEngine(const RenderEngineCreationArgs& args) { mRenderEngine = renderengine::RenderEngine::create(args); } +TestRenderEngine::~TestRenderEngine() { + mRenderEngine.release(); +} + void TestRenderEngine::setRenderLayers(std::vector> layers) { sort(layers.begin(), layers.end(), [](const std::shared_ptr& lhs, const std::shared_ptr& rhs) -> bool { diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h index 4eb4bb7179..f2d5f1933f 100644 --- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h +++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h @@ -41,7 +41,7 @@ class TestRenderEngine { static constexpr uint32_t sMaxFrameBufferAcquireBuffers = 2; TestRenderEngine(const RenderEngineCreationArgs& args); - ~TestRenderEngine() = default; + ~TestRenderEngine(); void setRenderLayers(std::vector> layers); void initGraphicBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint64_t usage); From a9a5eb411ea8f41d7e929ca1ddc46d762ce1e81b Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Wed, 5 Feb 2020 19:49:59 -0500 Subject: [PATCH 0602/1022] Add VTS tests for Sensors HAL 2.1 Bug: 144139857 Test: atest VtsHalSensorsV2_0TargetTest VtsHalSensorsV2_1TargetTest Change-Id: If2b751929b8d89c9d381032f5e8424a24719b6bd --- .../compatibility_matrix.current.xml | 2 +- sensors/1.0/vts/functional/Android.bp | 8 +- .../functional/SensorsHidlEnvironmentV1_0.h | 5 +- .../VtsHalSensorsV1_0TargetTest.cpp | 59 +- sensors/2.0/vts/functional/Android.bp | 14 +- .../VtsHalSensorsV2_0TargetTest.cpp | 1119 +--------------- sensors/2.1/vts/functional/Android.bp | 48 + sensors/2.1/vts/functional/AndroidTest.xml | 39 + sensors/2.1/vts/functional/OWNERS | 8 + .../VtsHalSensorsV2_1TargetTest.cpp | 22 + sensors/common/vts/2_X/Android.bp | 44 + .../vts/2_X/SensorsHidlEnvironmentV2_X.cpp} | 54 +- .../vts/2_X/SensorsHidlEnvironmentV2_X.h} | 51 +- .../vts/2_X/VtsHalSensorsV2_XTargetTest.h | 1186 +++++++++++++++++ sensors/common/vts/utils/Android.bp | 8 +- .../vts/utils/SensorsHidlEnvironmentBase.cpp | 69 - .../common/vts/utils/SensorsHidlTestBase.cpp | 584 -------- .../vts/utils/SensorsTestSharedMemory.cpp | 189 --- .../sensors-vts-utils/SensorEventsChecker.h | 35 +- .../SensorsHidlEnvironmentBase.h | 66 +- .../sensors-vts-utils/SensorsHidlTestBase.h | 608 ++++++++- .../SensorsTestSharedMemory.h | 178 ++- 22 files changed, 2255 insertions(+), 2141 deletions(-) create mode 100644 sensors/2.1/vts/functional/Android.bp create mode 100644 sensors/2.1/vts/functional/AndroidTest.xml create mode 100644 sensors/2.1/vts/functional/OWNERS create mode 100644 sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp create mode 100644 sensors/common/vts/2_X/Android.bp rename sensors/{2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp => common/vts/2_X/SensorsHidlEnvironmentV2_X.cpp} (70%) rename sensors/{2.0/vts/functional/SensorsHidlEnvironmentV2_0.h => common/vts/2_X/SensorsHidlEnvironmentV2_X.h} (68%) create mode 100644 sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h delete mode 100644 sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp delete mode 100644 sensors/common/vts/utils/SensorsHidlTestBase.cpp delete mode 100644 sensors/common/vts/utils/SensorsTestSharedMemory.cpp diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index f8cec640cc..c5466c91ac 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -416,7 +416,7 @@ android.hardware.sensors 1.0 - 2.0 + 2.0-1 ISensors default diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp index 1167fd4e0c..aaefccbe19 100644 --- a/sensors/1.0/vts/functional/Android.bp +++ b/sensors/1.0/vts/functional/Android.bp @@ -20,7 +20,7 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: [ "SensorsHidlEnvironmentV1_0.cpp", - "VtsHalSensorsV1_0TargetTest.cpp" + "VtsHalSensorsV1_0TargetTest.cpp", ], static_libs: [ "android.hardware.graphics.allocator@2.0", @@ -31,6 +31,8 @@ cc_test { "android.hardware.sensors@1.0", "VtsHalSensorsTargetTestUtils", ], - test_suites: ["general-tests", "vts-core"], + test_suites: [ + "general-tests", + "vts-core", + ], } - diff --git a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h index 29bfa507d9..485ed1ed87 100644 --- a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h +++ b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h @@ -29,8 +29,9 @@ using ::android::sp; class SensorsHidlTest; -class SensorsHidlEnvironmentV1_0 : public SensorsHidlEnvironmentBase { - public: +class SensorsHidlEnvironmentV1_0 + : public SensorsHidlEnvironmentBase<::android::hardware::sensors::V1_0::Event> { + public: using Event = ::android::hardware::sensors::V1_0::Event; SensorsHidlEnvironmentV1_0(const std::string& service_name) : SensorsHidlEnvironmentBase(service_name) {} diff --git a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp index 2cad54d1ba..e298651419 100644 --- a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp +++ b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp @@ -33,8 +33,7 @@ using ::android::sp; using namespace ::android::hardware::sensors::V1_0; // The main test class for SENSORS HIDL HAL. - -class SensorsHidlTest : public SensorsHidlTestBase { +class SensorsHidlTest : public SensorsHidlTestBase { public: virtual void SetUp() override { mEnvironment = new SensorsHidlEnvironmentV1_0(GetParam()); @@ -80,7 +79,7 @@ class SensorsHidlTest : public SensorsHidlTestBase { inline sp& S() { return mEnvironment->sensors; } - SensorsHidlEnvironmentBase* getEnvironment() override { return mEnvironment; } + SensorsHidlEnvironmentBase* getEnvironment() override { return mEnvironment; } private: // Test environment for sensors HAL. @@ -257,55 +256,55 @@ TEST_P(SensorsHidlTest, InjectSensorEventData) { // Test if sensor hal can do UI speed accelerometer streaming properly TEST_P(SensorsHidlTest, AccelerometerStreamingOperationSlow) { testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(200), - std::chrono::seconds(5), sAccelNormChecker); + std::chrono::seconds(5), mAccelNormChecker); } // Test if sensor hal can do normal speed accelerometer streaming properly TEST_P(SensorsHidlTest, AccelerometerStreamingOperationNormal) { testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(20), - std::chrono::seconds(5), sAccelNormChecker); + std::chrono::seconds(5), mAccelNormChecker); } // Test if sensor hal can do game speed accelerometer streaming properly TEST_P(SensorsHidlTest, AccelerometerStreamingOperationFast) { testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(5), - std::chrono::seconds(5), sAccelNormChecker); + std::chrono::seconds(5), mAccelNormChecker); } // Test if sensor hal can do UI speed gyroscope streaming properly TEST_P(SensorsHidlTest, GyroscopeStreamingOperationSlow) { testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(200), - std::chrono::seconds(5), sGyroNormChecker); + std::chrono::seconds(5), mGyroNormChecker); } // Test if sensor hal can do normal speed gyroscope streaming properly TEST_P(SensorsHidlTest, GyroscopeStreamingOperationNormal) { testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(20), - std::chrono::seconds(5), sGyroNormChecker); + std::chrono::seconds(5), mGyroNormChecker); } // Test if sensor hal can do game speed gyroscope streaming properly TEST_P(SensorsHidlTest, GyroscopeStreamingOperationFast) { testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(5), - std::chrono::seconds(5), sGyroNormChecker); + std::chrono::seconds(5), mGyroNormChecker); } // Test if sensor hal can do UI speed magnetometer streaming properly TEST_P(SensorsHidlTest, MagnetometerStreamingOperationSlow) { testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(200), - std::chrono::seconds(5), NullChecker()); + std::chrono::seconds(5), NullChecker()); } // Test if sensor hal can do normal speed magnetometer streaming properly TEST_P(SensorsHidlTest, MagnetometerStreamingOperationNormal) { testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(20), - std::chrono::seconds(5), NullChecker()); + std::chrono::seconds(5), NullChecker()); } // Test if sensor hal can do game speed magnetometer streaming properly TEST_P(SensorsHidlTest, MagnetometerStreamingOperationFast) { testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(5), - std::chrono::seconds(5), NullChecker()); + std::chrono::seconds(5), NullChecker()); } // Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active @@ -344,109 +343,109 @@ TEST_P(SensorsHidlTest, MagnetometerBatchingOperation) { // Test sensor event direct report with ashmem for accel sensor at normal rate TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) { testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL, - sAccelNormChecker); + mAccelNormChecker); } // Test sensor event direct report with ashmem for accel sensor at fast rate TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) { testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST, - sAccelNormChecker); + mAccelNormChecker); } // Test sensor event direct report with ashmem for accel sensor at very fast rate TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) { testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, - RateLevel::VERY_FAST, sAccelNormChecker); + RateLevel::VERY_FAST, mAccelNormChecker); } // Test sensor event direct report with ashmem for gyro sensor at normal rate TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) { testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL, - sGyroNormChecker); + mGyroNormChecker); } // Test sensor event direct report with ashmem for gyro sensor at fast rate TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) { testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST, - sGyroNormChecker); + mGyroNormChecker); } // Test sensor event direct report with ashmem for gyro sensor at very fast rate TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) { testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST, - sGyroNormChecker); + mGyroNormChecker); } // Test sensor event direct report with ashmem for mag sensor at normal rate TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) { testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL, - NullChecker()); + NullChecker()); } // Test sensor event direct report with ashmem for mag sensor at fast rate TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) { testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST, - NullChecker()); + NullChecker()); } // Test sensor event direct report with ashmem for mag sensor at very fast rate TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) { testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, - RateLevel::VERY_FAST, NullChecker()); + RateLevel::VERY_FAST, NullChecker()); } // Test sensor event direct report with gralloc for accel sensor at normal rate TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) { testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::NORMAL, - sAccelNormChecker); + mAccelNormChecker); } // Test sensor event direct report with gralloc for accel sensor at fast rate TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) { testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::FAST, - sAccelNormChecker); + mAccelNormChecker); } // Test sensor event direct report with gralloc for accel sensor at very fast rate TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) { testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, - RateLevel::VERY_FAST, sAccelNormChecker); + RateLevel::VERY_FAST, mAccelNormChecker); } // Test sensor event direct report with gralloc for gyro sensor at normal rate TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) { testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::NORMAL, - sGyroNormChecker); + mGyroNormChecker); } // Test sensor event direct report with gralloc for gyro sensor at fast rate TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) { testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST, - sGyroNormChecker); + mGyroNormChecker); } // Test sensor event direct report with gralloc for gyro sensor at very fast rate TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) { testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::VERY_FAST, - sGyroNormChecker); + mGyroNormChecker); } // Test sensor event direct report with gralloc for mag sensor at normal rate TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) { testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::NORMAL, - NullChecker()); + NullChecker()); } // Test sensor event direct report with gralloc for mag sensor at fast rate TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) { testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::FAST, - NullChecker()); + NullChecker()); } // Test sensor event direct report with gralloc for mag sensor at very fast rate TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) { testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, - RateLevel::VERY_FAST, NullChecker()); + RateLevel::VERY_FAST, NullChecker()); } INSTANTIATE_TEST_SUITE_P( diff --git a/sensors/2.0/vts/functional/Android.bp b/sensors/2.0/vts/functional/Android.bp index 4765fa2797..22a5091a67 100644 --- a/sensors/2.0/vts/functional/Android.bp +++ b/sensors/2.0/vts/functional/Android.bp @@ -19,8 +19,10 @@ cc_test { cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""], defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "SensorsHidlEnvironmentV2_0.cpp", - "VtsHalSensorsV2_0TargetTest.cpp" + "VtsHalSensorsV2_0TargetTest.cpp", + ], + header_libs: [ + "android.hardware.sensors@2.X-shared-utils", ], static_libs: [ "android.hardware.graphics.allocator@2.0", @@ -29,9 +31,15 @@ cc_test { "android.hardware.graphics.mapper@2.1", "android.hardware.graphics.mapper@3.0", "android.hardware.sensors@1.0", + "android.hardware.sensors@1.0-convert", "android.hardware.sensors@2.0", + "android.hardware.sensors@2.1", "libfmq", "VtsHalSensorsTargetTestUtils", + "VtsHalSensorsV2_XTargetTest", + ], + test_suites: [ + "general-tests", + "vts-core", ], } - diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp index 540529d8eb..889535005e 100644 --- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp +++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp @@ -14,1130 +14,19 @@ * limitations under the License. */ -#include "SensorsHidlEnvironmentV2_0.h" -#include "sensors-vts-utils/SensorsHidlTestBase.h" -#include "sensors-vts-utils/SensorsTestSharedMemory.h" +#include "VtsHalSensorsV2_XTargetTest.h" -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -using ::android::sp; -using ::android::hardware::Return; -using ::android::hardware::Void; -using ::android::hardware::sensors::V1_0::MetaDataEventType; -using ::android::hardware::sensors::V1_0::OperationMode; -using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset; -using ::android::hardware::sensors::V1_0::SensorStatus; -using ::android::hardware::sensors::V1_0::SharedMemType; -using ::android::hardware::sensors::V1_0::Vec3; -using std::chrono::duration_cast; -using std::chrono::microseconds; -using std::chrono::milliseconds; -using std::chrono::nanoseconds; - -constexpr size_t kEventSize = static_cast(SensorsEventFormatOffset::TOTAL_LENGTH); - -class EventCallback : public IEventCallback { - public: - void reset() { - mFlushMap.clear(); - mEventMap.clear(); - } - - void onEvent(const ::android::hardware::sensors::V1_0::Event& event) override { - if (event.sensorType == SensorType::META_DATA && - event.u.meta.what == MetaDataEventType::META_DATA_FLUSH_COMPLETE) { - std::unique_lock lock(mFlushMutex); - mFlushMap[event.sensorHandle]++; - mFlushCV.notify_all(); - } else if (event.sensorType != SensorType::ADDITIONAL_INFO) { - std::unique_lock lock(mEventMutex); - mEventMap[event.sensorHandle].push_back(event); - mEventCV.notify_all(); - } - } - - int32_t getFlushCount(int32_t sensorHandle) { - std::unique_lock lock(mFlushMutex); - return mFlushMap[sensorHandle]; - } - - void waitForFlushEvents(const std::vector& sensorsToWaitFor, - int32_t numCallsToFlush, milliseconds timeout) { - std::unique_lock lock(mFlushMutex); - mFlushCV.wait_for(lock, timeout, - [&] { return flushesReceived(sensorsToWaitFor, numCallsToFlush); }); - } - - const std::vector getEvents(int32_t sensorHandle) { - std::unique_lock lock(mEventMutex); - return mEventMap[sensorHandle]; - } - - void waitForEvents(const std::vector& sensorsToWaitFor, milliseconds timeout) { - std::unique_lock lock(mEventMutex); - mEventCV.wait_for(lock, timeout, [&] { return eventsReceived(sensorsToWaitFor); }); - } - - protected: - bool flushesReceived(const std::vector& sensorsToWaitFor, int32_t numCallsToFlush) { - for (const SensorInfo& sensor : sensorsToWaitFor) { - if (getFlushCount(sensor.sensorHandle) < numCallsToFlush) { - return false; - } - } - return true; - } - - bool eventsReceived(const std::vector& sensorsToWaitFor) { - for (const SensorInfo& sensor : sensorsToWaitFor) { - if (getEvents(sensor.sensorHandle).size() == 0) { - return false; - } - } - return true; - } - - std::map mFlushMap; - std::recursive_mutex mFlushMutex; - std::condition_variable_any mFlushCV; - - std::map> mEventMap; - std::recursive_mutex mEventMutex; - std::condition_variable_any mEventCV; -}; - -// The main test class for SENSORS HIDL HAL. - -class SensorsHidlTest : public SensorsHidlTestBase { - public: - virtual void SetUp() override { - mEnvironment = new SensorsHidlEnvironmentV2_0(GetParam()); - mEnvironment->HidlSetUp(); - // Ensure that we have a valid environment before performing tests - ASSERT_NE(getSensors(), nullptr); - } - - virtual void TearDown() override { mEnvironment->HidlTearDown(); } - - protected: - SensorInfo defaultSensorByType(SensorType type) override; - std::vector getSensorsList(); - // implementation wrapper - Return getSensorsList(ISensors::getSensorsList_cb _hidl_cb) override { - return getSensors()->getSensorsList(_hidl_cb); - } - - Return activate(int32_t sensorHandle, bool enabled) override; - - Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) override { - return getSensors()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); - } - - Return flush(int32_t sensorHandle) override { - return getSensors()->flush(sensorHandle); - } - - Return injectSensorData(const Event& event) override { - return getSensors()->injectSensorData(event); - } - - Return registerDirectChannel(const SharedMemInfo& mem, - ISensors::registerDirectChannel_cb _hidl_cb) override; - - Return unregisterDirectChannel(int32_t channelHandle) override { - return getSensors()->unregisterDirectChannel(channelHandle); - } - - Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, - ISensors::configDirectReport_cb _hidl_cb) override { - return getSensors()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); - } - - inline sp<::android::hardware::sensors::V2_0::ISensors>& getSensors() { - return mEnvironment->mSensors; - } - - SensorsHidlEnvironmentBase* getEnvironment() override { return mEnvironment; } - - // Test helpers - void runSingleFlushTest(const std::vector& sensors, bool activateSensor, - int32_t expectedFlushCount, Result expectedResponse); - void runFlushTest(const std::vector& sensors, bool activateSensor, - int32_t flushCalls, int32_t expectedFlushCount, Result expectedResponse); - - // Helper functions - void activateAllSensors(bool enable); - std::vector getNonOneShotSensors(); - std::vector getNonOneShotAndNonSpecialSensors(); - std::vector getOneShotSensors(); - std::vector getInjectEventSensors(); - int32_t getInvalidSensorHandle(); - bool getDirectChannelSensor(SensorInfo* sensor, SharedMemType* memType, RateLevel* rate); - void verifyDirectChannel(SharedMemType memType); - void verifyRegisterDirectChannel(std::shared_ptr mem, - int32_t* directChannelHandle, bool supportsSharedMemType, - bool supportsAnyDirectChannel); - void verifyConfigure(const SensorInfo& sensor, SharedMemType memType, - int32_t directChannelHandle, bool directChannelSupported); - void verifyUnregisterDirectChannel(int32_t directChannelHandle, bool directChannelSupported); - void checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle, RateLevel rateLevel); - void queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType, - bool* supportsAnyDirectChannel); - - private: - // Test environment for sensors HAL. - SensorsHidlEnvironmentV2_0* mEnvironment; -}; - -Return SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) { - // If activating a sensor, add the handle in a set so that when test fails it can be turned off. - // The handle is not removed when it is deactivating on purpose so that it is not necessary to - // check the return value of deactivation. Deactivating a sensor more than once does not have - // negative effect. - if (enabled) { - mSensorHandles.insert(sensorHandle); - } - return getSensors()->activate(sensorHandle, enabled); -} - -Return SensorsHidlTest::registerDirectChannel(const SharedMemInfo& mem, - ISensors::registerDirectChannel_cb cb) { - // If registeration of a channel succeeds, add the handle of channel to a set so that it can be - // unregistered when test fails. Unregister a channel does not remove the handle on purpose. - // Unregistering a channel more than once should not have negative effect. - getSensors()->registerDirectChannel(mem, [&](auto result, auto channelHandle) { - if (result == Result::OK) { - mDirectChannelHandles.insert(channelHandle); - } - cb(result, channelHandle); - }); - return Void(); -} - -SensorInfo SensorsHidlTest::defaultSensorByType(SensorType type) { - SensorInfo ret; - - ret.type = (SensorType)-1; - getSensors()->getSensorsList([&](const auto& list) { - const size_t count = list.size(); - for (size_t i = 0; i < count; ++i) { - if (list[i].type == type) { - ret = list[i]; - return; - } - } - }); - - return ret; -} - -std::vector SensorsHidlTest::getSensorsList() { - std::vector ret; - - getSensors()->getSensorsList([&](const auto& list) { - const size_t count = list.size(); - ret.reserve(list.size()); - for (size_t i = 0; i < count; ++i) { - ret.push_back(list[i]); - } - }); - - return ret; -} - -std::vector SensorsHidlTest::getNonOneShotSensors() { - std::vector sensors; - for (const SensorInfo& info : getSensorsList()) { - if (extractReportMode(info.flags) != SensorFlagBits::ONE_SHOT_MODE) { - sensors.push_back(info); - } - } - return sensors; -} - -std::vector SensorsHidlTest::getNonOneShotAndNonSpecialSensors() { - std::vector sensors; - for (const SensorInfo& info : getSensorsList()) { - SensorFlagBits reportMode = extractReportMode(info.flags); - if (reportMode != SensorFlagBits::ONE_SHOT_MODE && - reportMode != SensorFlagBits::SPECIAL_REPORTING_MODE) { - sensors.push_back(info); - } - } - return sensors; -} - -std::vector SensorsHidlTest::getOneShotSensors() { - std::vector sensors; - for (const SensorInfo& info : getSensorsList()) { - if (extractReportMode(info.flags) == SensorFlagBits::ONE_SHOT_MODE) { - sensors.push_back(info); - } - } - return sensors; -} - -std::vector SensorsHidlTest::getInjectEventSensors() { - std::vector sensors; - for (const SensorInfo& info : getSensorsList()) { - if (info.flags & static_cast(SensorFlagBits::DATA_INJECTION)) { - sensors.push_back(info); - } - } - return sensors; -} - -int32_t SensorsHidlTest::getInvalidSensorHandle() { - // Find a sensor handle that does not exist in the sensor list - int32_t maxHandle = 0; - for (const SensorInfo& sensor : getSensorsList()) { - maxHandle = std::max(maxHandle, sensor.sensorHandle); - } - return maxHandle + 1; -} - -// Test if sensor list returned is valid -TEST_P(SensorsHidlTest, SensorListValid) { +TEST_P(SensorsHidlTest, SensorListDoesntContainInvalidType) { getSensors()->getSensorsList([&](const auto& list) { const size_t count = list.size(); for (size_t i = 0; i < count; ++i) { const auto& s = list[i]; - SCOPED_TRACE(::testing::Message() - << i << "/" << count << ": " - << " handle=0x" << std::hex << std::setw(8) << std::setfill('0') - << s.sensorHandle << std::dec << " type=" << static_cast(s.type) - << " name=" << s.name); - - // Test non-empty type string - EXPECT_FALSE(s.typeAsString.empty()); - - // Test defined type matches defined string type - EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString)); - - // Test if all sensor has name and vendor - EXPECT_FALSE(s.name.empty()); - EXPECT_FALSE(s.vendor.empty()); - - // Test power > 0, maxRange > 0 - EXPECT_LE(0, s.power); - EXPECT_LT(0, s.maxRange); - - // Info type, should have no sensor - EXPECT_FALSE(s.type == SensorType::ADDITIONAL_INFO || s.type == SensorType::META_DATA); - - // Test fifoMax >= fifoReserved - EXPECT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount) - << "max=" << s.fifoMaxEventCount << " reserved=" << s.fifoReservedEventCount; - - // Test Reporting mode valid - EXPECT_NO_FATAL_FAILURE(assertTypeMatchReportMode(s.type, extractReportMode(s.flags))); - - // Test min max are in the right order - EXPECT_LE(s.minDelay, s.maxDelay); - // Test min/max delay matches reporting mode - EXPECT_NO_FATAL_FAILURE( - assertDelayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags))); + EXPECT_FALSE(s.type == ::android::hardware::sensors::V2_1::SensorType::HINGE_ANGLE); } }); } -// Test that SetOperationMode returns the expected value -TEST_P(SensorsHidlTest, SetOperationMode) { - std::vector sensors = getInjectEventSensors(); - if (getInjectEventSensors().size() > 0) { - ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL)); - ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION)); - ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL)); - } else { - ASSERT_EQ(Result::BAD_VALUE, getSensors()->setOperationMode(OperationMode::DATA_INJECTION)); - } -} - -// Test that an injected event is written back to the Event FMQ -TEST_P(SensorsHidlTest, InjectSensorEventData) { - std::vector sensors = getInjectEventSensors(); - if (sensors.size() == 0) { - return; - } - - ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION)); - - EventCallback callback; - getEnvironment()->registerCallback(&callback); - - // AdditionalInfo event should not be sent to Event FMQ - Event additionalInfoEvent; - additionalInfoEvent.sensorType = SensorType::ADDITIONAL_INFO; - additionalInfoEvent.timestamp = android::elapsedRealtimeNano(); - - Event injectedEvent; - injectedEvent.timestamp = android::elapsedRealtimeNano(); - Vec3 data = {1, 2, 3, SensorStatus::ACCURACY_HIGH}; - injectedEvent.u.vec3 = data; - - for (const auto& s : sensors) { - additionalInfoEvent.sensorHandle = s.sensorHandle; - EXPECT_EQ(Result::OK, getSensors()->injectSensorData(additionalInfoEvent)); - - injectedEvent.sensorType = s.type; - injectedEvent.sensorHandle = s.sensorHandle; - EXPECT_EQ(Result::OK, getSensors()->injectSensorData(injectedEvent)); - } - - // Wait for events to be written back to the Event FMQ - callback.waitForEvents(sensors, milliseconds(1000) /* timeout */); - - for (const auto& s : sensors) { - auto events = callback.getEvents(s.sensorHandle); - auto lastEvent = events.back(); - - // Verify that only a single event has been received - ASSERT_EQ(events.size(), 1); - - // Verify that the event received matches the event injected and is not the additional - // info event - ASSERT_EQ(lastEvent.sensorType, s.type); - ASSERT_EQ(lastEvent.sensorType, s.type); - ASSERT_EQ(lastEvent.timestamp, injectedEvent.timestamp); - ASSERT_EQ(lastEvent.u.vec3.x, injectedEvent.u.vec3.x); - ASSERT_EQ(lastEvent.u.vec3.y, injectedEvent.u.vec3.y); - ASSERT_EQ(lastEvent.u.vec3.z, injectedEvent.u.vec3.z); - ASSERT_EQ(lastEvent.u.vec3.status, injectedEvent.u.vec3.status); - } - - getEnvironment()->unregisterCallback(); - ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL)); -} - -// Test if sensor hal can do UI speed accelerometer streaming properly -TEST_P(SensorsHidlTest, AccelerometerStreamingOperationSlow) { - testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(200), - std::chrono::seconds(5), sAccelNormChecker); -} - -// Test if sensor hal can do normal speed accelerometer streaming properly -TEST_P(SensorsHidlTest, AccelerometerStreamingOperationNormal) { - testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(20), - std::chrono::seconds(5), sAccelNormChecker); -} - -// Test if sensor hal can do game speed accelerometer streaming properly -TEST_P(SensorsHidlTest, AccelerometerStreamingOperationFast) { - testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(5), - std::chrono::seconds(5), sAccelNormChecker); -} - -// Test if sensor hal can do UI speed gyroscope streaming properly -TEST_P(SensorsHidlTest, GyroscopeStreamingOperationSlow) { - testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(200), - std::chrono::seconds(5), sGyroNormChecker); -} - -// Test if sensor hal can do normal speed gyroscope streaming properly -TEST_P(SensorsHidlTest, GyroscopeStreamingOperationNormal) { - testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(20), - std::chrono::seconds(5), sGyroNormChecker); -} - -// Test if sensor hal can do game speed gyroscope streaming properly -TEST_P(SensorsHidlTest, GyroscopeStreamingOperationFast) { - testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(5), - std::chrono::seconds(5), sGyroNormChecker); -} - -// Test if sensor hal can do UI speed magnetometer streaming properly -TEST_P(SensorsHidlTest, MagnetometerStreamingOperationSlow) { - testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(200), - std::chrono::seconds(5), NullChecker()); -} - -// Test if sensor hal can do normal speed magnetometer streaming properly -TEST_P(SensorsHidlTest, MagnetometerStreamingOperationNormal) { - testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(20), - std::chrono::seconds(5), NullChecker()); -} - -// Test if sensor hal can do game speed magnetometer streaming properly -TEST_P(SensorsHidlTest, MagnetometerStreamingOperationFast) { - testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(5), - std::chrono::seconds(5), NullChecker()); -} - -// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active -TEST_P(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) { - testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER); - testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER, false /*fastToSlow*/); -} - -// Test if sensor hal can do gyroscope sampling rate switch properly when sensor is active -TEST_P(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) { - testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE); - testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE, false /*fastToSlow*/); -} - -// Test if sensor hal can do magnetometer sampling rate switch properly when sensor is active -TEST_P(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) { - testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD); - testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD, false /*fastToSlow*/); -} - -// Test if sensor hal can do accelerometer batching properly -TEST_P(SensorsHidlTest, AccelerometerBatchingOperation) { - testBatchingOperation(SensorType::ACCELEROMETER); -} - -// Test if sensor hal can do gyroscope batching properly -TEST_P(SensorsHidlTest, GyroscopeBatchingOperation) { - testBatchingOperation(SensorType::GYROSCOPE); -} - -// Test if sensor hal can do magnetometer batching properly -TEST_P(SensorsHidlTest, MagnetometerBatchingOperation) { - testBatchingOperation(SensorType::MAGNETIC_FIELD); -} - -// Test sensor event direct report with ashmem for accel sensor at normal rate -TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) { - testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL, - sAccelNormChecker); -} - -// Test sensor event direct report with ashmem for accel sensor at fast rate -TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) { - testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST, - sAccelNormChecker); -} - -// Test sensor event direct report with ashmem for accel sensor at very fast rate -TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) { - testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, - RateLevel::VERY_FAST, sAccelNormChecker); -} - -// Test sensor event direct report with ashmem for gyro sensor at normal rate -TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) { - testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL, - sGyroNormChecker); -} - -// Test sensor event direct report with ashmem for gyro sensor at fast rate -TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) { - testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST, - sGyroNormChecker); -} - -// Test sensor event direct report with ashmem for gyro sensor at very fast rate -TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) { - testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST, - sGyroNormChecker); -} - -// Test sensor event direct report with ashmem for mag sensor at normal rate -TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) { - testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL, - NullChecker()); -} - -// Test sensor event direct report with ashmem for mag sensor at fast rate -TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) { - testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST, - NullChecker()); -} - -// Test sensor event direct report with ashmem for mag sensor at very fast rate -TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) { - testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, - RateLevel::VERY_FAST, NullChecker()); -} - -// Test sensor event direct report with gralloc for accel sensor at normal rate -TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) { - testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::NORMAL, - sAccelNormChecker); -} - -// Test sensor event direct report with gralloc for accel sensor at fast rate -TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) { - testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::FAST, - sAccelNormChecker); -} - -// Test sensor event direct report with gralloc for accel sensor at very fast rate -TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) { - testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, - RateLevel::VERY_FAST, sAccelNormChecker); -} - -// Test sensor event direct report with gralloc for gyro sensor at normal rate -TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) { - testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::NORMAL, - sGyroNormChecker); -} - -// Test sensor event direct report with gralloc for gyro sensor at fast rate -TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) { - testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST, - sGyroNormChecker); -} - -// Test sensor event direct report with gralloc for gyro sensor at very fast rate -TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) { - testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::VERY_FAST, - sGyroNormChecker); -} - -// Test sensor event direct report with gralloc for mag sensor at normal rate -TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) { - testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::NORMAL, - NullChecker()); -} - -// Test sensor event direct report with gralloc for mag sensor at fast rate -TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) { - testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::FAST, - NullChecker()); -} - -// Test sensor event direct report with gralloc for mag sensor at very fast rate -TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) { - testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, - RateLevel::VERY_FAST, NullChecker()); -} - -void SensorsHidlTest::activateAllSensors(bool enable) { - for (const SensorInfo& sensorInfo : getSensorsList()) { - if (isValidType(sensorInfo.type)) { - batch(sensorInfo.sensorHandle, sensorInfo.minDelay, 0 /* maxReportLatencyNs */); - activate(sensorInfo.sensorHandle, enable); - } - } -} - -// Test that if initialize is called twice, then the HAL writes events to the FMQs from the second -// call to the function. -TEST_P(SensorsHidlTest, CallInitializeTwice) { - // Create a helper class so that a second environment is able to be instantiated - class SensorsHidlEnvironmentTest : public SensorsHidlEnvironmentV2_0 { - public: - SensorsHidlEnvironmentTest(const std::string& service_name) - : SensorsHidlEnvironmentV2_0(service_name) {} - }; - - if (getSensorsList().size() == 0) { - // No sensors - return; - } - - constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000; // 1s - constexpr int32_t kNumEvents = 1; - - // Create a new environment that calls initialize() - std::unique_ptr newEnv = - std::make_unique(GetParam()); - newEnv->HidlSetUp(); - if (HasFatalFailure()) { - return; // Exit early if setting up the new environment failed - } - - activateAllSensors(true); - // Verify that the old environment does not receive any events - ASSERT_EQ(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), 0); - // Verify that the new event queue receives sensor events - ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, newEnv.get()).size(), kNumEvents); - activateAllSensors(false); - - // Cleanup the test environment - newEnv->HidlTearDown(); - - // Restore the test environment for future tests - getEnvironment()->HidlTearDown(); - getEnvironment()->HidlSetUp(); - if (HasFatalFailure()) { - return; // Exit early if resetting the environment failed - } - - // Ensure that the original environment is receiving events - activateAllSensors(true); - ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents); - activateAllSensors(false); -} - -TEST_P(SensorsHidlTest, CleanupConnectionsOnInitialize) { - activateAllSensors(true); - - // Verify that events are received - constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000; // 1s - constexpr int32_t kNumEvents = 1; - ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), kNumEvents); - - // Clear the active sensor handles so they are not disabled during TearDown - auto handles = mSensorHandles; - mSensorHandles.clear(); - getEnvironment()->HidlTearDown(); - getEnvironment()->HidlSetUp(); - if (HasFatalFailure()) { - return; // Exit early if resetting the environment failed - } - - // Verify no events are received until sensors are re-activated - ASSERT_EQ(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), 0); - activateAllSensors(true); - ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), kNumEvents); - - // Disable sensors - activateAllSensors(false); - - // Restore active sensors prior to clearing the environment - mSensorHandles = handles; -} - -void SensorsHidlTest::runSingleFlushTest(const std::vector& sensors, - bool activateSensor, int32_t expectedFlushCount, - Result expectedResponse) { - runFlushTest(sensors, activateSensor, 1 /* flushCalls */, expectedFlushCount, expectedResponse); -} - -void SensorsHidlTest::runFlushTest(const std::vector& sensors, bool activateSensor, - int32_t flushCalls, int32_t expectedFlushCount, - Result expectedResponse) { - EventCallback callback; - getEnvironment()->registerCallback(&callback); - - for (const SensorInfo& sensor : sensors) { - // Configure and activate the sensor - batch(sensor.sensorHandle, sensor.maxDelay, 0 /* maxReportLatencyNs */); - activate(sensor.sensorHandle, activateSensor); - - // Flush the sensor - for (int32_t i = 0; i < flushCalls; i++) { - Result flushResult = flush(sensor.sensorHandle); - ASSERT_EQ(flushResult, expectedResponse); - } - } - - // Wait up to one second for the flush events - callback.waitForFlushEvents(sensors, flushCalls, milliseconds(1000) /* timeout */); - - // Deactivate all sensors after waiting for flush events so pending flush events are not - // abandoned by the HAL. - for (const SensorInfo& sensor : sensors) { - activate(sensor.sensorHandle, false); - } - getEnvironment()->unregisterCallback(); - - // Check that the correct number of flushes are present for each sensor - for (const SensorInfo& sensor : sensors) { - ASSERT_EQ(callback.getFlushCount(sensor.sensorHandle), expectedFlushCount); - } -} - -TEST_P(SensorsHidlTest, FlushSensor) { - // Find a sensor that is not a one-shot sensor - std::vector sensors = getNonOneShotSensors(); - if (sensors.size() == 0) { - return; - } - - constexpr int32_t kFlushes = 5; - runSingleFlushTest(sensors, true /* activateSensor */, 1 /* expectedFlushCount */, Result::OK); - runFlushTest(sensors, true /* activateSensor */, kFlushes, kFlushes, Result::OK); -} - -TEST_P(SensorsHidlTest, FlushOneShotSensor) { - // Find a sensor that is a one-shot sensor - std::vector sensors = getOneShotSensors(); - if (sensors.size() == 0) { - return; - } - - runSingleFlushTest(sensors, true /* activateSensor */, 0 /* expectedFlushCount */, - Result::BAD_VALUE); -} - -TEST_P(SensorsHidlTest, FlushInactiveSensor) { - // Attempt to find a non-one shot sensor, then a one-shot sensor if necessary - std::vector sensors = getNonOneShotSensors(); - if (sensors.size() == 0) { - sensors = getOneShotSensors(); - if (sensors.size() == 0) { - return; - } - } - - runSingleFlushTest(sensors, false /* activateSensor */, 0 /* expectedFlushCount */, - Result::BAD_VALUE); -} - -TEST_P(SensorsHidlTest, FlushNonexistentSensor) { - SensorInfo sensor; - std::vector sensors = getNonOneShotSensors(); - if (sensors.size() == 0) { - sensors = getOneShotSensors(); - if (sensors.size() == 0) { - return; - } - } - sensor = sensors.front(); - sensor.sensorHandle = getInvalidSensorHandle(); - runSingleFlushTest(std::vector{sensor}, false /* activateSensor */, - 0 /* expectedFlushCount */, Result::BAD_VALUE); -} - -TEST_P(SensorsHidlTest, Batch) { - if (getSensorsList().size() == 0) { - return; - } - - activateAllSensors(false /* enable */); - for (const SensorInfo& sensor : getSensorsList()) { - // Call batch on inactive sensor - // One shot sensors have minDelay set to -1 which is an invalid - // parameter. Use 0 instead to avoid errors. - int64_t samplingPeriodNs = extractReportMode(sensor.flags) == SensorFlagBits::ONE_SHOT_MODE - ? 0 - : sensor.minDelay; - ASSERT_EQ(batch(sensor.sensorHandle, samplingPeriodNs, 0 /* maxReportLatencyNs */), - Result::OK); - - // Activate the sensor - activate(sensor.sensorHandle, true /* enabled */); - - // Call batch on an active sensor - ASSERT_EQ(batch(sensor.sensorHandle, sensor.maxDelay, 0 /* maxReportLatencyNs */), - Result::OK); - } - activateAllSensors(false /* enable */); - - // Call batch on an invalid sensor - SensorInfo sensor = getSensorsList().front(); - sensor.sensorHandle = getInvalidSensorHandle(); - ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */), - Result::BAD_VALUE); -} - -TEST_P(SensorsHidlTest, Activate) { - if (getSensorsList().size() == 0) { - return; - } - - // Verify that sensor events are generated when activate is called - for (const SensorInfo& sensor : getSensorsList()) { - batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */); - ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK); - - // Call activate on a sensor that is already activated - ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK); - - // Deactivate the sensor - ASSERT_EQ(activate(sensor.sensorHandle, false), Result::OK); - - // Call deactivate on a sensor that is already deactivated - ASSERT_EQ(activate(sensor.sensorHandle, false), Result::OK); - } - - // Attempt to activate an invalid sensor - int32_t invalidHandle = getInvalidSensorHandle(); - ASSERT_EQ(activate(invalidHandle, true), Result::BAD_VALUE); - ASSERT_EQ(activate(invalidHandle, false), Result::BAD_VALUE); -} - -TEST_P(SensorsHidlTest, NoStaleEvents) { - constexpr milliseconds kFiveHundredMs(500); - constexpr milliseconds kOneSecond(1000); - - // Register the callback to receive sensor events - EventCallback callback; - getEnvironment()->registerCallback(&callback); - - // This test is not valid for one-shot or special-report-mode sensors - const std::vector sensors = getNonOneShotAndNonSpecialSensors(); - milliseconds maxMinDelay(0); - for (const SensorInfo& sensor : sensors) { - milliseconds minDelay = duration_cast(microseconds(sensor.minDelay)); - maxMinDelay = milliseconds(std::max(maxMinDelay.count(), minDelay.count())); - } - - // Activate the sensors so that they start generating events - activateAllSensors(true); - - // According to the CDD, the first sample must be generated within 400ms + 2 * sample_time - // and the maximum reporting latency is 100ms + 2 * sample_time. Wait a sufficient amount - // of time to guarantee that a sample has arrived. - callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay)); - activateAllSensors(false); - - // Save the last received event for each sensor - std::map lastEventTimestampMap; - for (const SensorInfo& sensor : sensors) { - // Some on-change sensors may not report an event without stimulus - if (extractReportMode(sensor.flags) != SensorFlagBits::ON_CHANGE_MODE) { - ASSERT_GE(callback.getEvents(sensor.sensorHandle).size(), 1); - } - if (callback.getEvents(sensor.sensorHandle).size() >= 1) { - lastEventTimestampMap[sensor.sensorHandle] = - callback.getEvents(sensor.sensorHandle).back().timestamp; - } - } - - // Allow some time to pass, reset the callback, then reactivate the sensors - usleep(duration_cast(kOneSecond + (5 * maxMinDelay)).count()); - callback.reset(); - activateAllSensors(true); - callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay)); - activateAllSensors(false); - - for (const SensorInfo& sensor : sensors) { - // Skip sensors that did not previously report an event - if (lastEventTimestampMap.find(sensor.sensorHandle) == lastEventTimestampMap.end()) { - continue; - } - // Skip on-change sensors that do not consistently report an initial event - if (callback.getEvents(sensor.sensorHandle).size() < 1) { - continue; - } - // Ensure that the first event received is not stale by ensuring that its timestamp is - // sufficiently different from the previous event - const Event newEvent = callback.getEvents(sensor.sensorHandle).front(); - milliseconds delta = duration_cast( - nanoseconds(newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle])); - milliseconds sensorMinDelay = duration_cast(microseconds(sensor.minDelay)); - ASSERT_GE(delta, kFiveHundredMs + (3 * sensorMinDelay)); - } -} - -void SensorsHidlTest::checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle, - RateLevel rateLevel) { - configDirectReport(sensor.sensorHandle, directChannelHandle, rateLevel, - [&](Result result, int32_t reportToken) { - if (isDirectReportRateSupported(sensor, rateLevel)) { - ASSERT_EQ(result, Result::OK); - if (rateLevel != RateLevel::STOP) { - ASSERT_GT(reportToken, 0); - } - } else { - ASSERT_EQ(result, Result::BAD_VALUE); - } - }); -} - -void SensorsHidlTest::queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType, - bool* supportsAnyDirectChannel) { - *supportsSharedMemType = false; - *supportsAnyDirectChannel = false; - for (const SensorInfo& curSensor : getSensorsList()) { - if (isDirectChannelTypeSupported(curSensor, memType)) { - *supportsSharedMemType = true; - } - if (isDirectChannelTypeSupported(curSensor, SharedMemType::ASHMEM) || - isDirectChannelTypeSupported(curSensor, SharedMemType::GRALLOC)) { - *supportsAnyDirectChannel = true; - } - - if (*supportsSharedMemType && *supportsAnyDirectChannel) { - break; - } - } -} - -void SensorsHidlTest::verifyRegisterDirectChannel(std::shared_ptr mem, - int32_t* directChannelHandle, - bool supportsSharedMemType, - bool supportsAnyDirectChannel) { - char* buffer = mem->getBuffer(); - memset(buffer, 0xff, mem->getSize()); - - registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) { - if (supportsSharedMemType) { - ASSERT_EQ(result, Result::OK); - ASSERT_GT(channelHandle, 0); - - // Verify that the memory has been zeroed - for (size_t i = 0; i < mem->getSize(); i++) { - ASSERT_EQ(buffer[i], 0x00); - } - } else { - Result expectedResult = - supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION; - ASSERT_EQ(result, expectedResult); - ASSERT_EQ(channelHandle, -1); - } - *directChannelHandle = channelHandle; - }); -} - -void SensorsHidlTest::verifyConfigure(const SensorInfo& sensor, SharedMemType memType, - int32_t directChannelHandle, bool supportsAnyDirectChannel) { - if (isDirectChannelTypeSupported(sensor, memType)) { - // Verify that each rate level is properly supported - checkRateLevel(sensor, directChannelHandle, RateLevel::NORMAL); - checkRateLevel(sensor, directChannelHandle, RateLevel::FAST); - checkRateLevel(sensor, directChannelHandle, RateLevel::VERY_FAST); - checkRateLevel(sensor, directChannelHandle, RateLevel::STOP); - - // Verify that a sensor handle of -1 is only acceptable when using RateLevel::STOP - configDirectReport( - -1 /* sensorHandle */, directChannelHandle, RateLevel::NORMAL, - [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::BAD_VALUE); }); - configDirectReport( - -1 /* sensorHandle */, directChannelHandle, RateLevel::STOP, - [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); }); - } else { - // directChannelHandle will be -1 here, HAL should either reject it as a bad value if there - // is some level of direct channel report, otherwise return INVALID_OPERATION if direct - // channel is not supported at all - Result expectedResult = - supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION; - configDirectReport(sensor.sensorHandle, directChannelHandle, RateLevel::NORMAL, - [expectedResult](Result result, int32_t /* reportToken */) { - ASSERT_EQ(result, expectedResult); - }); - } -} - -void SensorsHidlTest::verifyUnregisterDirectChannel(int32_t directChannelHandle, - bool supportsAnyDirectChannel) { - Result expectedResult = supportsAnyDirectChannel ? Result::OK : Result::INVALID_OPERATION; - ASSERT_EQ(unregisterDirectChannel(directChannelHandle), expectedResult); -} - -void SensorsHidlTest::verifyDirectChannel(SharedMemType memType) { - constexpr size_t kNumEvents = 1; - constexpr size_t kMemSize = kNumEvents * kEventSize; - - std::shared_ptr mem( - SensorsTestSharedMemory::create(memType, kMemSize)); - ASSERT_NE(mem, nullptr); - - bool supportsSharedMemType; - bool supportsAnyDirectChannel; - queryDirectChannelSupport(memType, &supportsSharedMemType, &supportsAnyDirectChannel); - - for (const SensorInfo& sensor : getSensorsList()) { - int32_t directChannelHandle = 0; - verifyRegisterDirectChannel(mem, &directChannelHandle, supportsSharedMemType, - supportsAnyDirectChannel); - verifyConfigure(sensor, memType, directChannelHandle, supportsAnyDirectChannel); - verifyUnregisterDirectChannel(directChannelHandle, supportsAnyDirectChannel); - } -} - -TEST_P(SensorsHidlTest, DirectChannelAshmem) { - verifyDirectChannel(SharedMemType::ASHMEM); -} - -TEST_P(SensorsHidlTest, DirectChannelGralloc) { - verifyDirectChannel(SharedMemType::GRALLOC); -} - -bool SensorsHidlTest::getDirectChannelSensor(SensorInfo* sensor, SharedMemType* memType, - RateLevel* rate) { - bool found = false; - for (const SensorInfo& curSensor : getSensorsList()) { - if (isDirectChannelTypeSupported(curSensor, SharedMemType::ASHMEM)) { - *memType = SharedMemType::ASHMEM; - *sensor = curSensor; - found = true; - break; - } else if (isDirectChannelTypeSupported(curSensor, SharedMemType::GRALLOC)) { - *memType = SharedMemType::GRALLOC; - *sensor = curSensor; - found = true; - break; - } - } - - if (found) { - // Find a supported rate level - constexpr int kNumRateLevels = 3; - RateLevel rates[kNumRateLevels] = {RateLevel::NORMAL, RateLevel::FAST, - RateLevel::VERY_FAST}; - *rate = RateLevel::STOP; - for (int i = 0; i < kNumRateLevels; i++) { - if (isDirectReportRateSupported(*sensor, rates[i])) { - *rate = rates[i]; - } - } - - // At least one rate level must be supported - EXPECT_NE(*rate, RateLevel::STOP); - } - return found; -} - -TEST_P(SensorsHidlTest, ConfigureDirectChannelWithInvalidHandle) { - SensorInfo sensor; - SharedMemType memType; - RateLevel rate; - if (!getDirectChannelSensor(&sensor, &memType, &rate)) { - return; - } - - // Verify that an invalid channel handle produces a BAD_VALUE result - configDirectReport(sensor.sensorHandle, -1, rate, [](Result result, int32_t /* reportToken */) { - ASSERT_EQ(result, Result::BAD_VALUE); - }); -} - -TEST_P(SensorsHidlTest, CleanupDirectConnectionOnInitialize) { - constexpr size_t kNumEvents = 1; - constexpr size_t kMemSize = kNumEvents * kEventSize; - - SensorInfo sensor; - SharedMemType memType; - RateLevel rate; - - if (!getDirectChannelSensor(&sensor, &memType, &rate)) { - return; - } - - std::shared_ptr mem( - SensorsTestSharedMemory::create(memType, kMemSize)); - ASSERT_NE(mem, nullptr); - - int32_t directChannelHandle = 0; - registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) { - ASSERT_EQ(result, Result::OK); - directChannelHandle = channelHandle; - }); - - // Configure the channel and expect success - configDirectReport( - sensor.sensorHandle, directChannelHandle, rate, - [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); }); - - // Call initialize() via the environment setup to cause the HAL to re-initialize - // Clear the active direct connections so they are not stopped during TearDown - auto handles = mDirectChannelHandles; - mDirectChannelHandles.clear(); - getEnvironment()->HidlTearDown(); - getEnvironment()->HidlSetUp(); - if (HasFatalFailure()) { - return; // Exit early if resetting the environment failed - } - - // Attempt to configure the direct channel and expect it to fail - configDirectReport( - sensor.sensorHandle, directChannelHandle, rate, - [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::BAD_VALUE); }); - - // Restore original handles, though they should already be deactivated - mDirectChannelHandles = handles; -} - INSTANTIATE_TEST_SUITE_P(PerInstance, SensorsHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames( android::hardware::sensors::V2_0::ISensors::descriptor)), - android::hardware::PrintInstanceNameToString); -// vim: set ts=2 sw=2 + android::hardware::PrintInstanceNameToString); \ No newline at end of file diff --git a/sensors/2.1/vts/functional/Android.bp b/sensors/2.1/vts/functional/Android.bp new file mode 100644 index 0000000000..c92bab3373 --- /dev/null +++ b/sensors/2.1/vts/functional/Android.bp @@ -0,0 +1,48 @@ +// +// Copyright (C) 2018 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. +// + +cc_test { + name: "VtsHalSensorsV2_1TargetTest", + cflags: [ + "-DLOG_TAG=\"sensors_hidl_hal_test\"", + "-DSENSORS_HAL_2_1", + ], + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "VtsHalSensorsV2_1TargetTest.cpp", + ], + header_libs: [ + "android.hardware.sensors@2.X-shared-utils", + ], + static_libs: [ + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.allocator@3.0", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@2.1", + "android.hardware.graphics.mapper@3.0", + "android.hardware.sensors@1.0", + "android.hardware.sensors@1.0-convert", + "android.hardware.sensors@2.0", + "android.hardware.sensors@2.1", + "libfmq", + "VtsHalSensorsTargetTestUtils", + "VtsHalSensorsV2_XTargetTest", + ], + test_suites: [ + "general-tests", + "vts-core", + ], +} diff --git a/sensors/2.1/vts/functional/AndroidTest.xml b/sensors/2.1/vts/functional/AndroidTest.xml new file mode 100644 index 0000000000..0d8593e51d --- /dev/null +++ b/sensors/2.1/vts/functional/AndroidTest.xml @@ -0,0 +1,39 @@ + + + + diff --git a/sensors/2.1/vts/functional/OWNERS b/sensors/2.1/vts/functional/OWNERS new file mode 100644 index 0000000000..892da1548c --- /dev/null +++ b/sensors/2.1/vts/functional/OWNERS @@ -0,0 +1,8 @@ +# Sensors team +arthuri@google.com +bduddie@google.com +stange@google.com + +# VTS team +trong@google.com +yim@google.com diff --git a/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp b/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp new file mode 100644 index 0000000000..230bb6c2f1 --- /dev/null +++ b/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp @@ -0,0 +1,22 @@ +/* + * 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 "VtsHalSensorsV2_XTargetTest.h" + +INSTANTIATE_TEST_SUITE_P(PerInstance, SensorsHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::sensors::V2_1::ISensors::descriptor)), + android::hardware::PrintInstanceNameToString); diff --git a/sensors/common/vts/2_X/Android.bp b/sensors/common/vts/2_X/Android.bp new file mode 100644 index 0000000000..8cf14866c5 --- /dev/null +++ b/sensors/common/vts/2_X/Android.bp @@ -0,0 +1,44 @@ +// +// Copyright (C) 2018 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. +// + +cc_test_library { + name: "VtsHalSensorsV2_XTargetTest", + cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""], + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "SensorsHidlEnvironmentV2_X.cpp", + ], + export_include_dirs: ["."], + header_libs: [ + "android.hardware.sensors@2.X-shared-utils", + ], + shared_libs: [ + "libbinder", + ], + static_libs: [ + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.allocator@3.0", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@2.1", + "android.hardware.graphics.mapper@3.0", + "android.hardware.sensors@1.0", + "android.hardware.sensors@1.0-convert", + "android.hardware.sensors@2.0", + "android.hardware.sensors@2.1", + "libfmq", + "VtsHalSensorsTargetTestUtils", + ], +} diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp b/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.cpp similarity index 70% rename from sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp rename to sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.cpp index 81db5a040c..2771d976df 100644 --- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp +++ b/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.cpp @@ -14,9 +14,11 @@ * limitations under the License. */ -#include "SensorsHidlEnvironmentV2_0.h" +#include "SensorsHidlEnvironmentV2_X.h" #include +#include + #include #include @@ -26,18 +28,20 @@ using ::android::hardware::EventFlag; using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::sensors::V1_0::Result; -using ::android::hardware::sensors::V1_0::SensorInfo; using ::android::hardware::sensors::V2_0::EventQueueFlagBits; +using ::android::hardware::sensors::V2_1::SensorInfo; +#ifdef SENSORS_HAL_2_1 +using ::android::hardware::sensors::V2_1::ISensors; +#else using ::android::hardware::sensors::V2_0::ISensors; -using ::android::hardware::sensors::V2_0::ISensorsCallback; +#endif +using ::android::hardware::sensors::V2_1::ISensorsCallback; template constexpr typename std::underlying_type::type asBaseType(EnumType value) { return static_cast::type>(value); } -constexpr size_t SensorsHidlEnvironmentV2_0::MAX_RECEIVE_BUFFER_EVENT_COUNT; - void SensorsHalDeathRecipient::serviceDied( uint64_t /* cookie */, const ::android::wp<::android::hidl::base::V1_0::IBase>& /* service */) { @@ -45,48 +49,34 @@ void SensorsHalDeathRecipient::serviceDied( FAIL() << "Sensors HAL died during test"; } -struct SensorsCallback : ISensorsCallback { - Return onDynamicSensorsConnected(const hidl_vec& /* sensorInfos */) { - return Return(); - } - - Return onDynamicSensorsDisconnected(const hidl_vec& /* sensorHandles */) { - return Return(); - } -}; - -bool SensorsHidlEnvironmentV2_0::resetHal() { +bool SensorsHidlEnvironmentV2_X::resetHal() { bool succeed = false; do { - mSensors = ISensors::getService(mServiceName); + mSensors = wrapISensors(ISensors::getService(mServiceName)); if (mSensors == nullptr) { break; } mSensors->linkToDeath(mDeathRecipient, 0 /* cookie */); // Initialize FMQs - mEventQueue = std::make_unique(MAX_RECEIVE_BUFFER_EVENT_COUNT, - true /* configureEventFlagWord */); - mWakeLockQueue = std::make_unique(MAX_RECEIVE_BUFFER_EVENT_COUNT, true /* configureEventFlagWord */); - if (mEventQueue == nullptr || mWakeLockQueue == nullptr) { + if (mWakeLockQueue == nullptr) { break; } EventFlag::deleteEventFlag(&mEventQueueFlag); - EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag); + EventFlag::createEventFlag(mSensors->getEventQueue().getEventFlagWord(), &mEventQueueFlag); if (mEventQueueFlag == nullptr) { break; } - mSensors->initialize(*mEventQueue->getDesc(), *mWakeLockQueue->getDesc(), - new SensorsCallback()); + mSensors->initialize(*mWakeLockQueue->getDesc(), new NoOpSensorsCallback()); std::vector sensorList; if (!mSensors->getSensorsList([&](const hidl_vec& list) { sensorList = list; }) - .isOk()) { + .isOk()) { break; } @@ -113,7 +103,7 @@ bool SensorsHidlEnvironmentV2_0::resetHal() { return succeed; } -void SensorsHidlEnvironmentV2_0::HidlTearDown() { +void SensorsHidlEnvironmentV2_X::HidlTearDown() { mStopThread = true; if (mEventQueueFlag != nullptr) { @@ -127,25 +117,25 @@ void SensorsHidlEnvironmentV2_0::HidlTearDown() { } } -void SensorsHidlEnvironmentV2_0::startPollingThread() { +void SensorsHidlEnvironmentV2_X::startPollingThread() { mStopThread = false; mEvents.reserve(MAX_RECEIVE_BUFFER_EVENT_COUNT); mPollThread = std::thread(pollingThread, this); } -void SensorsHidlEnvironmentV2_0::readEvents() { - size_t availableEvents = mEventQueue->availableToRead(); +void SensorsHidlEnvironmentV2_X::readEvents() { + size_t availableEvents = mSensors->getEventQueue().availableToRead(); if (availableEvents == 0) { uint32_t eventFlagState = 0; mEventQueueFlag->wait(asBaseType(EventQueueFlagBits::READ_AND_PROCESS), &eventFlagState); - availableEvents = mEventQueue->availableToRead(); + availableEvents = mSensors->getEventQueue().availableToRead(); } size_t eventsToRead = std::min(availableEvents, mEventBuffer.size()); if (eventsToRead > 0) { - if (mEventQueue->read(mEventBuffer.data(), eventsToRead)) { + if (mSensors->getEventQueue().read(mEventBuffer.data(), eventsToRead)) { mEventQueueFlag->wake(asBaseType(EventQueueFlagBits::EVENTS_READ)); for (size_t i = 0; i < eventsToRead; i++) { addEvent(mEventBuffer[i]); @@ -154,7 +144,7 @@ void SensorsHidlEnvironmentV2_0::readEvents() { } } -void SensorsHidlEnvironmentV2_0::pollingThread(SensorsHidlEnvironmentV2_0* env) { +void SensorsHidlEnvironmentV2_X::pollingThread(SensorsHidlEnvironmentV2_X* env) { ALOGD("polling thread start"); while (!env->mStopThread.load()) { diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h b/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.h similarity index 68% rename from sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h rename to sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.h index 819cdd45ab..01f451f5ad 100644 --- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h +++ b/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.h @@ -14,13 +14,15 @@ * limitations under the License. */ -#ifndef ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H -#define ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H +#ifndef ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_X_H +#define ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_X_H +#include "ISensorsWrapper.h" #include "sensors-vts-utils/SensorsHidlEnvironmentBase.h" -#include -#include +#include +#include + #include #include @@ -30,6 +32,10 @@ using ::android::sp; using ::android::hardware::MessageQueue; +using ::android::hardware::sensors::V2_1::implementation::ISensorsWrapperBase; +using ::android::hardware::sensors::V2_1::implementation::MAX_RECEIVE_BUFFER_EVENT_COUNT; +using ::android::hardware::sensors::V2_1::implementation::NoOpSensorsCallback; +using ::android::hardware::sensors::V2_1::implementation::wrapISensors; class SensorsHidlTest; @@ -39,14 +45,14 @@ class SensorsHalDeathRecipient : public ::android::hardware::hidl_death_recipien const ::android::wp<::android::hidl::base::V1_0::IBase>& service) override; }; -class SensorsHidlEnvironmentV2_0 : public SensorsHidlEnvironmentBase { - public: - using Event = ::android::hardware::sensors::V1_0::Event; +class SensorsHidlEnvironmentV2_X + : public SensorsHidlEnvironmentBase<::android::hardware::sensors::V2_1::Event> { + public: virtual void HidlTearDown() override; - protected: + protected: friend SensorsHidlTest; - SensorsHidlEnvironmentV2_0(const std::string& service_name) + SensorsHidlEnvironmentV2_X(const std::string& service_name) : SensorsHidlEnvironmentBase(service_name), mEventQueueFlag(nullptr) {} /** @@ -66,41 +72,30 @@ class SensorsHidlEnvironmentV2_0 : public SensorsHidlEnvironmentBase { * * @param env SensorEnvironment to being polling for events on */ - static void pollingThread(SensorsHidlEnvironmentV2_0* env); + static void pollingThread(SensorsHidlEnvironmentV2_X* env); /** * Reads and saves sensor events from the Event FMQ */ void readEvents(); - GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentV2_0); + GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentV2_X); /** * Pointer to the Sensors HAL Interface that allows the test to call HAL functions. */ - sp mSensors; + sp mSensors; /** * Monitors the HAL for crashes, triggering test failure if seen */ sp mDeathRecipient = new SensorsHalDeathRecipient(); - /** - * Type used to simplify the creation of the Event FMQ - */ - typedef MessageQueue EventMessageQueue; - /** * Type used to simplify the creation of the Wake Lock FMQ */ typedef MessageQueue WakeLockQueue; - /** - * The Event FMQ where the test framework is able to read sensor events that the Sensors HAL - * has written. - */ - std::unique_ptr mEventQueue; - /** * The Wake Lock FMQ is used by the test to notify the Sensors HAL whenever it has processed * WAKE_UP sensor events. @@ -113,15 +108,11 @@ class SensorsHidlEnvironmentV2_0 : public SensorsHidlEnvironmentBase { */ ::android::hardware::EventFlag* mEventQueueFlag; - /** - * The maximum number of sensor events that can be read from the Event FMQ at one time. - */ - static constexpr size_t MAX_RECEIVE_BUFFER_EVENT_COUNT = 128; - /** * An array that is used to store sensor events read from the Event FMQ */ - std::array mEventBuffer; + std::array<::android::hardware::sensors::V2_1::Event, MAX_RECEIVE_BUFFER_EVENT_COUNT> + mEventBuffer; }; -#endif // ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H +#endif // ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_X_H diff --git a/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h new file mode 100644 index 0000000000..53ed259948 --- /dev/null +++ b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h @@ -0,0 +1,1186 @@ +/* + * Copyright (C) 2018 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 "SensorsHidlEnvironmentV2_X.h" +#include "convertV2_1.h" +#include "sensors-vts-utils/SensorsHidlTestBase.h" +#include "sensors-vts-utils/SensorsTestSharedMemory.h" + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/** + * This file contains the core tests and test logic for both sensors HAL 2.0 + * and 2.1. To make it easier to share the code between both VTS test suites, + * this is defined as a header so they can both include and use all pieces of + * code. + */ + +using ::android::sp; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::sensors::V1_0::MetaDataEventType; +using ::android::hardware::sensors::V1_0::OperationMode; +using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset; +using ::android::hardware::sensors::V1_0::SensorStatus; +using ::android::hardware::sensors::V1_0::SharedMemType; +using ::android::hardware::sensors::V1_0::Vec3; +using ::android::hardware::sensors::V2_1::implementation::convertToOldSensorInfos; +using std::chrono::duration_cast; +using std::chrono::microseconds; +using std::chrono::milliseconds; +using std::chrono::nanoseconds; + +using EventV1_0 = ::android::hardware::sensors::V1_0::Event; +using ISensorsType = ::android::hardware::sensors::V2_1::ISensors; +using SensorTypeVersion = ::android::hardware::sensors::V2_1::SensorType; +using EventType = ::android::hardware::sensors::V2_1::Event; +using SensorInfoType = ::android::hardware::sensors::V2_1::SensorInfo; +using SensorsHidlTestBaseV2_X = SensorsHidlTestBase; + +constexpr size_t kEventSize = static_cast(SensorsEventFormatOffset::TOTAL_LENGTH); + +class EventCallback : public IEventCallback { + public: + void reset() { + mFlushMap.clear(); + mEventMap.clear(); + } + + void onEvent(const EventType& event) override { + if (event.sensorType == SensorTypeVersion::META_DATA && + event.u.meta.what == MetaDataEventType::META_DATA_FLUSH_COMPLETE) { + std::unique_lock lock(mFlushMutex); + mFlushMap[event.sensorHandle]++; + mFlushCV.notify_all(); + } else if (event.sensorType != SensorTypeVersion::ADDITIONAL_INFO) { + std::unique_lock lock(mEventMutex); + mEventMap[event.sensorHandle].push_back(event); + mEventCV.notify_all(); + } + } + + int32_t getFlushCount(int32_t sensorHandle) { + std::unique_lock lock(mFlushMutex); + return mFlushMap[sensorHandle]; + } + + void waitForFlushEvents(const std::vector& sensorsToWaitFor, + int32_t numCallsToFlush, milliseconds timeout) { + std::unique_lock lock(mFlushMutex); + mFlushCV.wait_for(lock, timeout, + [&] { return flushesReceived(sensorsToWaitFor, numCallsToFlush); }); + } + + const std::vector getEvents(int32_t sensorHandle) { + std::unique_lock lock(mEventMutex); + return mEventMap[sensorHandle]; + } + + void waitForEvents(const std::vector& sensorsToWaitFor, milliseconds timeout) { + std::unique_lock lock(mEventMutex); + mEventCV.wait_for(lock, timeout, [&] { return eventsReceived(sensorsToWaitFor); }); + } + + protected: + bool flushesReceived(const std::vector& sensorsToWaitFor, + int32_t numCallsToFlush) { + for (const SensorInfoType& sensor : sensorsToWaitFor) { + if (getFlushCount(sensor.sensorHandle) < numCallsToFlush) { + return false; + } + } + return true; + } + + bool eventsReceived(const std::vector& sensorsToWaitFor) { + for (const SensorInfoType& sensor : sensorsToWaitFor) { + if (getEvents(sensor.sensorHandle).size() == 0) { + return false; + } + } + return true; + } + + std::map mFlushMap; + std::recursive_mutex mFlushMutex; + std::condition_variable_any mFlushCV; + + std::map> mEventMap; + std::recursive_mutex mEventMutex; + std::condition_variable_any mEventCV; +}; + +/** + * Define the template specific versions of the static helper methods in + * SensorsHidlTestBase used to test that hinge angle is exposed properly. + */ +template <> +SensorFlagBits expectedReportModeForType(::android::hardware::sensors::V2_1::SensorType type) { + switch (type) { + case ::android::hardware::sensors::V2_1::SensorType::HINGE_ANGLE: + return SensorFlagBits::ON_CHANGE_MODE; + default: + return expectedReportModeForType( + static_cast<::android::hardware::sensors::V1_0::SensorType>(type)); + } +} + +template <> +void assertTypeMatchStringType(::android::hardware::sensors::V2_1::SensorType type, + const hidl_string& stringType) { + switch (type) { + case (::android::hardware::sensors::V2_1::SensorType::HINGE_ANGLE): + ASSERT_STREQ(SENSOR_STRING_TYPE_HINGE_ANGLE, stringType.c_str()); + break; + default: + assertTypeMatchStringType( + static_cast<::android::hardware::sensors::V1_0::SensorType>(type), stringType); + break; + } +} + +// The main test class for SENSORS HIDL HAL. +class SensorsHidlTest : public SensorsHidlTestBaseV2_X { + public: + virtual void SetUp() override { + mEnvironment = new SensorsHidlEnvironmentV2_X(GetParam()); + mEnvironment->HidlSetUp(); + // Ensure that we have a valid environment before performing tests + ASSERT_NE(getSensors(), nullptr); + } + + virtual void TearDown() override { mEnvironment->HidlTearDown(); } + + protected: + SensorInfoType defaultSensorByType(SensorTypeVersion type) override; + std::vector getSensorsList(); + // implementation wrapper + + Return getSensorsList(ISensorsType::getSensorsList_cb _hidl_cb) override { + return getSensors()->getSensorsList( + [&](const auto& list) { _hidl_cb(convertToOldSensorInfos(list)); }); + } + + Return activate(int32_t sensorHandle, bool enabled) override; + + Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) override { + return getSensors()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); + } + + Return flush(int32_t sensorHandle) override { + return getSensors()->flush(sensorHandle); + } + + Return injectSensorData(const EventType& event) override { + return getSensors()->injectSensorData(event); + } + + Return registerDirectChannel(const SharedMemInfo& mem, + ISensorsType::registerDirectChannel_cb _hidl_cb) override; + + Return unregisterDirectChannel(int32_t channelHandle) override { + return getSensors()->unregisterDirectChannel(channelHandle); + } + + Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + ISensorsType::configDirectReport_cb _hidl_cb) override { + return getSensors()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); + } + + inline sp& getSensors() { return mEnvironment->mSensors; } + + SensorsHidlEnvironmentBase* getEnvironment() override { return mEnvironment; } + + // Test helpers + void runSingleFlushTest(const std::vector& sensors, bool activateSensor, + int32_t expectedFlushCount, Result expectedResponse); + void runFlushTest(const std::vector& sensors, bool activateSensor, + int32_t flushCalls, int32_t expectedFlushCount, Result expectedResponse); + + // Helper functions + void activateAllSensors(bool enable); + std::vector getNonOneShotSensors(); + std::vector getNonOneShotAndNonSpecialSensors(); + std::vector getOneShotSensors(); + std::vector getInjectEventSensors(); + int32_t getInvalidSensorHandle(); + bool getDirectChannelSensor(SensorInfoType* sensor, SharedMemType* memType, RateLevel* rate); + void verifyDirectChannel(SharedMemType memType); + void verifyRegisterDirectChannel( + std::shared_ptr> mem, + int32_t* directChannelHandle, bool supportsSharedMemType, + bool supportsAnyDirectChannel); + void verifyConfigure(const SensorInfoType& sensor, SharedMemType memType, + int32_t directChannelHandle, bool directChannelSupported); + void verifyUnregisterDirectChannel(int32_t directChannelHandle, bool directChannelSupported); + void checkRateLevel(const SensorInfoType& sensor, int32_t directChannelHandle, + RateLevel rateLevel); + void queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType, + bool* supportsAnyDirectChannel); + + private: + // Test environment for sensors HAL. + SensorsHidlEnvironmentV2_X* mEnvironment; +}; + +Return SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) { + // If activating a sensor, add the handle in a set so that when test fails it can be turned off. + // The handle is not removed when it is deactivating on purpose so that it is not necessary to + // check the return value of deactivation. Deactivating a sensor more than once does not have + // negative effect. + if (enabled) { + mSensorHandles.insert(sensorHandle); + } + return getSensors()->activate(sensorHandle, enabled); +} + +Return SensorsHidlTest::registerDirectChannel(const SharedMemInfo& mem, + ISensors::registerDirectChannel_cb cb) { + // If registeration of a channel succeeds, add the handle of channel to a set so that it can be + // unregistered when test fails. Unregister a channel does not remove the handle on purpose. + // Unregistering a channel more than once should not have negative effect. + getSensors()->registerDirectChannel(mem, [&](auto result, auto channelHandle) { + if (result == Result::OK) { + mDirectChannelHandles.insert(channelHandle); + } + cb(result, channelHandle); + }); + return Void(); +} + +SensorInfoType SensorsHidlTest::defaultSensorByType(SensorTypeVersion type) { + SensorInfoType ret; + + ret.type = (SensorTypeVersion)-1; + getSensors()->getSensorsList([&](const auto& list) { + const size_t count = list.size(); + for (size_t i = 0; i < count; ++i) { + if (list[i].type == type) { + ret = list[i]; + return; + } + } + }); + + return ret; +} + +std::vector SensorsHidlTest::getSensorsList() { + std::vector ret; + + getSensors()->getSensorsList([&](const auto& list) { + const size_t count = list.size(); + ret.reserve(list.size()); + for (size_t i = 0; i < count; ++i) { + ret.push_back(list[i]); + } + }); + + return ret; +} + +std::vector SensorsHidlTest::getNonOneShotSensors() { + std::vector sensors; + for (const SensorInfoType& info : getSensorsList()) { + if (extractReportMode(info.flags) != SensorFlagBits::ONE_SHOT_MODE) { + sensors.push_back(info); + } + } + return sensors; +} + +std::vector SensorsHidlTest::getNonOneShotAndNonSpecialSensors() { + std::vector sensors; + for (const SensorInfoType& info : getSensorsList()) { + SensorFlagBits reportMode = extractReportMode(info.flags); + if (reportMode != SensorFlagBits::ONE_SHOT_MODE && + reportMode != SensorFlagBits::SPECIAL_REPORTING_MODE) { + sensors.push_back(info); + } + } + return sensors; +} + +std::vector SensorsHidlTest::getOneShotSensors() { + std::vector sensors; + for (const SensorInfoType& info : getSensorsList()) { + if (extractReportMode(info.flags) == SensorFlagBits::ONE_SHOT_MODE) { + sensors.push_back(info); + } + } + return sensors; +} + +std::vector SensorsHidlTest::getInjectEventSensors() { + std::vector sensors; + for (const SensorInfoType& info : getSensorsList()) { + if (info.flags & static_cast(SensorFlagBits::DATA_INJECTION)) { + sensors.push_back(info); + } + } + return sensors; +} + +int32_t SensorsHidlTest::getInvalidSensorHandle() { + // Find a sensor handle that does not exist in the sensor list + int32_t maxHandle = 0; + for (const SensorInfoType& sensor : getSensorsList()) { + maxHandle = std::max(maxHandle, sensor.sensorHandle); + } + return maxHandle + 1; +} + +// Test if sensor list returned is valid +TEST_P(SensorsHidlTest, SensorListValid) { + getSensors()->getSensorsList([&](const auto& list) { + const size_t count = list.size(); + for (size_t i = 0; i < count; ++i) { + const auto& s = list[i]; + SCOPED_TRACE(::testing::Message() + << i << "/" << count << ": " + << " handle=0x" << std::hex << std::setw(8) << std::setfill('0') + << s.sensorHandle << std::dec << " type=" << static_cast(s.type) + << " name=" << s.name); + + // Test non-empty type string + EXPECT_FALSE(s.typeAsString.empty()); + + // Test defined type matches defined string type + EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString)); + + // Test if all sensor has name and vendor + EXPECT_FALSE(s.name.empty()); + EXPECT_FALSE(s.vendor.empty()); + + // Test power > 0, maxRange > 0 + EXPECT_LE(0, s.power); + EXPECT_LT(0, s.maxRange); + + // Info type, should have no sensor + EXPECT_FALSE(s.type == SensorTypeVersion::ADDITIONAL_INFO || + s.type == SensorTypeVersion::META_DATA); + + // Test fifoMax >= fifoReserved + EXPECT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount) + << "max=" << s.fifoMaxEventCount << " reserved=" << s.fifoReservedEventCount; + + // Test Reporting mode valid + EXPECT_NO_FATAL_FAILURE(assertTypeMatchReportMode(s.type, extractReportMode(s.flags))); + + // Test min max are in the right order + EXPECT_LE(s.minDelay, s.maxDelay); + // Test min/max delay matches reporting mode + EXPECT_NO_FATAL_FAILURE( + assertDelayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags))); + } + }); +} + +// Test that SetOperationMode returns the expected value +TEST_P(SensorsHidlTest, SetOperationMode) { + std::vector sensors = getInjectEventSensors(); + if (getInjectEventSensors().size() > 0) { + ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL)); + ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION)); + ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL)); + } else { + ASSERT_EQ(Result::BAD_VALUE, getSensors()->setOperationMode(OperationMode::DATA_INJECTION)); + } +} + +// Test that an injected event is written back to the Event FMQ +TEST_P(SensorsHidlTest, InjectSensorEventData) { + std::vector sensors = getInjectEventSensors(); + if (sensors.size() == 0) { + return; + } + + ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION)); + + EventCallback callback; + getEnvironment()->registerCallback(&callback); + + // AdditionalInfo event should not be sent to Event FMQ + EventType additionalInfoEvent; + additionalInfoEvent.sensorType = SensorTypeVersion::ADDITIONAL_INFO; + additionalInfoEvent.timestamp = android::elapsedRealtimeNano(); + + EventType injectedEvent; + injectedEvent.timestamp = android::elapsedRealtimeNano(); + Vec3 data = {1, 2, 3, SensorStatus::ACCURACY_HIGH}; + injectedEvent.u.vec3 = data; + + for (const auto& s : sensors) { + additionalInfoEvent.sensorHandle = s.sensorHandle; + EXPECT_EQ(Result::OK, getSensors()->injectSensorData(additionalInfoEvent)); + + injectedEvent.sensorType = s.type; + injectedEvent.sensorHandle = s.sensorHandle; + EXPECT_EQ(Result::OK, getSensors()->injectSensorData(injectedEvent)); + } + + // Wait for events to be written back to the Event FMQ + callback.waitForEvents(sensors, milliseconds(1000) /* timeout */); + + for (const auto& s : sensors) { + auto events = callback.getEvents(s.sensorHandle); + auto lastEvent = events.back(); + + // Verify that only a single event has been received + ASSERT_EQ(events.size(), 1); + + // Verify that the event received matches the event injected and is not the additional + // info event + ASSERT_EQ(lastEvent.sensorType, s.type); + ASSERT_EQ(lastEvent.sensorType, s.type); + ASSERT_EQ(lastEvent.timestamp, injectedEvent.timestamp); + ASSERT_EQ(lastEvent.u.vec3.x, injectedEvent.u.vec3.x); + ASSERT_EQ(lastEvent.u.vec3.y, injectedEvent.u.vec3.y); + ASSERT_EQ(lastEvent.u.vec3.z, injectedEvent.u.vec3.z); + ASSERT_EQ(lastEvent.u.vec3.status, injectedEvent.u.vec3.status); + } + + getEnvironment()->unregisterCallback(); + ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL)); +} + +// Test if sensor hal can do UI speed accelerometer streaming properly +TEST_P(SensorsHidlTest, AccelerometerStreamingOperationSlow) { + testStreamingOperation(SensorTypeVersion::ACCELEROMETER, std::chrono::milliseconds(200), + std::chrono::seconds(5), mAccelNormChecker); +} + +// Test if sensor hal can do normal speed accelerometer streaming properly +TEST_P(SensorsHidlTest, AccelerometerStreamingOperationNormal) { + testStreamingOperation(SensorTypeVersion::ACCELEROMETER, std::chrono::milliseconds(20), + std::chrono::seconds(5), mAccelNormChecker); +} + +// Test if sensor hal can do game speed accelerometer streaming properly +TEST_P(SensorsHidlTest, AccelerometerStreamingOperationFast) { + testStreamingOperation(SensorTypeVersion::ACCELEROMETER, std::chrono::milliseconds(5), + std::chrono::seconds(5), mAccelNormChecker); +} + +// Test if sensor hal can do UI speed gyroscope streaming properly +TEST_P(SensorsHidlTest, GyroscopeStreamingOperationSlow) { + testStreamingOperation(SensorTypeVersion::GYROSCOPE, std::chrono::milliseconds(200), + std::chrono::seconds(5), mGyroNormChecker); +} + +// Test if sensor hal can do normal speed gyroscope streaming properly +TEST_P(SensorsHidlTest, GyroscopeStreamingOperationNormal) { + testStreamingOperation(SensorTypeVersion::GYROSCOPE, std::chrono::milliseconds(20), + std::chrono::seconds(5), mGyroNormChecker); +} + +// Test if sensor hal can do game speed gyroscope streaming properly +TEST_P(SensorsHidlTest, GyroscopeStreamingOperationFast) { + testStreamingOperation(SensorTypeVersion::GYROSCOPE, std::chrono::milliseconds(5), + std::chrono::seconds(5), mGyroNormChecker); +} + +// Test if sensor hal can do UI speed magnetometer streaming properly +TEST_P(SensorsHidlTest, MagnetometerStreamingOperationSlow) { + testStreamingOperation(SensorTypeVersion::MAGNETIC_FIELD, std::chrono::milliseconds(200), + std::chrono::seconds(5), NullChecker()); +} + +// Test if sensor hal can do normal speed magnetometer streaming properly +TEST_P(SensorsHidlTest, MagnetometerStreamingOperationNormal) { + testStreamingOperation(SensorTypeVersion::MAGNETIC_FIELD, std::chrono::milliseconds(20), + std::chrono::seconds(5), NullChecker()); +} + +// Test if sensor hal can do game speed magnetometer streaming properly +TEST_P(SensorsHidlTest, MagnetometerStreamingOperationFast) { + testStreamingOperation(SensorTypeVersion::MAGNETIC_FIELD, std::chrono::milliseconds(5), + std::chrono::seconds(5), NullChecker()); +} + +// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active +TEST_P(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) { + testSamplingRateHotSwitchOperation(SensorTypeVersion::ACCELEROMETER); + testSamplingRateHotSwitchOperation(SensorTypeVersion::ACCELEROMETER, false /*fastToSlow*/); +} + +// Test if sensor hal can do gyroscope sampling rate switch properly when sensor is active +TEST_P(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) { + testSamplingRateHotSwitchOperation(SensorTypeVersion::GYROSCOPE); + testSamplingRateHotSwitchOperation(SensorTypeVersion::GYROSCOPE, false /*fastToSlow*/); +} + +// Test if sensor hal can do magnetometer sampling rate switch properly when sensor is active +TEST_P(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) { + testSamplingRateHotSwitchOperation(SensorTypeVersion::MAGNETIC_FIELD); + testSamplingRateHotSwitchOperation(SensorTypeVersion::MAGNETIC_FIELD, false /*fastToSlow*/); +} + +// Test if sensor hal can do accelerometer batching properly +TEST_P(SensorsHidlTest, AccelerometerBatchingOperation) { + testBatchingOperation(SensorTypeVersion::ACCELEROMETER); +} + +// Test if sensor hal can do gyroscope batching properly +TEST_P(SensorsHidlTest, GyroscopeBatchingOperation) { + testBatchingOperation(SensorTypeVersion::GYROSCOPE); +} + +// Test if sensor hal can do magnetometer batching properly +TEST_P(SensorsHidlTest, MagnetometerBatchingOperation) { + testBatchingOperation(SensorTypeVersion::MAGNETIC_FIELD); +} + +// Test sensor event direct report with ashmem for accel sensor at normal rate +TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) { + testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::ASHMEM, + RateLevel::NORMAL, mAccelNormChecker); +} + +// Test sensor event direct report with ashmem for accel sensor at fast rate +TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) { + testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::ASHMEM, + RateLevel::FAST, mAccelNormChecker); +} + +// Test sensor event direct report with ashmem for accel sensor at very fast rate +TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) { + testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::ASHMEM, + RateLevel::VERY_FAST, mAccelNormChecker); +} + +// Test sensor event direct report with ashmem for gyro sensor at normal rate +TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) { + testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::ASHMEM, + RateLevel::NORMAL, mGyroNormChecker); +} + +// Test sensor event direct report with ashmem for gyro sensor at fast rate +TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) { + testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST, + mGyroNormChecker); +} + +// Test sensor event direct report with ashmem for gyro sensor at very fast rate +TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) { + testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::ASHMEM, + RateLevel::VERY_FAST, mGyroNormChecker); +} + +// Test sensor event direct report with ashmem for mag sensor at normal rate +TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) { + testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::ASHMEM, + RateLevel::NORMAL, NullChecker()); +} + +// Test sensor event direct report with ashmem for mag sensor at fast rate +TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) { + testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::ASHMEM, + RateLevel::FAST, NullChecker()); +} + +// Test sensor event direct report with ashmem for mag sensor at very fast rate +TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) { + testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::ASHMEM, + RateLevel::VERY_FAST, NullChecker()); +} + +// Test sensor event direct report with gralloc for accel sensor at normal rate +TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) { + testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::GRALLOC, + RateLevel::NORMAL, mAccelNormChecker); +} + +// Test sensor event direct report with gralloc for accel sensor at fast rate +TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) { + testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::GRALLOC, + RateLevel::FAST, mAccelNormChecker); +} + +// Test sensor event direct report with gralloc for accel sensor at very fast rate +TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) { + testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::GRALLOC, + RateLevel::VERY_FAST, mAccelNormChecker); +} + +// Test sensor event direct report with gralloc for gyro sensor at normal rate +TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) { + testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::GRALLOC, + RateLevel::NORMAL, mGyroNormChecker); +} + +// Test sensor event direct report with gralloc for gyro sensor at fast rate +TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) { + testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST, + mGyroNormChecker); +} + +// Test sensor event direct report with gralloc for gyro sensor at very fast rate +TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) { + testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::GRALLOC, + RateLevel::VERY_FAST, mGyroNormChecker); +} + +// Test sensor event direct report with gralloc for mag sensor at normal rate +TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) { + testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::GRALLOC, + RateLevel::NORMAL, NullChecker()); +} + +// Test sensor event direct report with gralloc for mag sensor at fast rate +TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) { + testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::GRALLOC, + RateLevel::FAST, NullChecker()); +} + +// Test sensor event direct report with gralloc for mag sensor at very fast rate +TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) { + testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::GRALLOC, + RateLevel::VERY_FAST, NullChecker()); +} + +void SensorsHidlTest::activateAllSensors(bool enable) { + for (const SensorInfoType& sensorInfo : getSensorsList()) { + if (isValidType(sensorInfo.type)) { + batch(sensorInfo.sensorHandle, sensorInfo.minDelay, 0 /* maxReportLatencyNs */); + activate(sensorInfo.sensorHandle, enable); + } + } +} + +// Test that if initialize is called twice, then the HAL writes events to the FMQs from the second +// call to the function. +TEST_P(SensorsHidlTest, CallInitializeTwice) { + // Create a helper class so that a second environment is able to be instantiated + class SensorsHidlEnvironmentTest : public SensorsHidlEnvironmentV2_X { + public: + SensorsHidlEnvironmentTest(const std::string& service_name) + : SensorsHidlEnvironmentV2_X(service_name) {} + }; + + if (getSensorsList().size() == 0) { + // No sensors + return; + } + + constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000; // 1s + constexpr int32_t kNumEvents = 1; + + // Create a new environment that calls initialize() + std::unique_ptr newEnv = + std::make_unique(GetParam()); + newEnv->HidlSetUp(); + if (HasFatalFailure()) { + return; // Exit early if setting up the new environment failed + } + + activateAllSensors(true); + // Verify that the old environment does not receive any events + EXPECT_EQ(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), 0); + // Verify that the new event queue receives sensor events + EXPECT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, newEnv.get(), newEnv.get()).size(), + kNumEvents); + activateAllSensors(false); + + // Cleanup the test environment + newEnv->HidlTearDown(); + + // Restore the test environment for future tests + getEnvironment()->HidlTearDown(); + getEnvironment()->HidlSetUp(); + if (HasFatalFailure()) { + return; // Exit early if resetting the environment failed + } + + // Ensure that the original environment is receiving events + activateAllSensors(true); + EXPECT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents); + activateAllSensors(false); +} + +TEST_P(SensorsHidlTest, CleanupConnectionsOnInitialize) { + activateAllSensors(true); + + // Verify that events are received + constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000; // 1s + constexpr int32_t kNumEvents = 1; + ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), kNumEvents); + + // Clear the active sensor handles so they are not disabled during TearDown + auto handles = mSensorHandles; + mSensorHandles.clear(); + getEnvironment()->HidlTearDown(); + getEnvironment()->HidlSetUp(); + if (HasFatalFailure()) { + return; // Exit early if resetting the environment failed + } + + // Verify no events are received until sensors are re-activated + ASSERT_EQ(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), 0); + activateAllSensors(true); + ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), kNumEvents); + + // Disable sensors + activateAllSensors(false); + + // Restore active sensors prior to clearing the environment + mSensorHandles = handles; +} + +void SensorsHidlTest::runSingleFlushTest(const std::vector& sensors, + bool activateSensor, int32_t expectedFlushCount, + Result expectedResponse) { + runFlushTest(sensors, activateSensor, 1 /* flushCalls */, expectedFlushCount, expectedResponse); +} + +void SensorsHidlTest::runFlushTest(const std::vector& sensors, bool activateSensor, + int32_t flushCalls, int32_t expectedFlushCount, + Result expectedResponse) { + EventCallback callback; + getEnvironment()->registerCallback(&callback); + + for (const SensorInfoType& sensor : sensors) { + // Configure and activate the sensor + batch(sensor.sensorHandle, sensor.maxDelay, 0 /* maxReportLatencyNs */); + activate(sensor.sensorHandle, activateSensor); + + // Flush the sensor + for (int32_t i = 0; i < flushCalls; i++) { + Result flushResult = flush(sensor.sensorHandle); + ASSERT_EQ(flushResult, expectedResponse); + } + } + + // Wait up to one second for the flush events + callback.waitForFlushEvents(sensors, flushCalls, milliseconds(1000) /* timeout */); + + // Deactivate all sensors after waiting for flush events so pending flush events are not + // abandoned by the HAL. + for (const SensorInfoType& sensor : sensors) { + activate(sensor.sensorHandle, false); + } + getEnvironment()->unregisterCallback(); + + // Check that the correct number of flushes are present for each sensor + for (const SensorInfoType& sensor : sensors) { + ASSERT_EQ(callback.getFlushCount(sensor.sensorHandle), expectedFlushCount); + } +} + +TEST_P(SensorsHidlTest, FlushSensor) { + // Find a sensor that is not a one-shot sensor + std::vector sensors = getNonOneShotSensors(); + if (sensors.size() == 0) { + return; + } + + constexpr int32_t kFlushes = 5; + runSingleFlushTest(sensors, true /* activateSensor */, 1 /* expectedFlushCount */, Result::OK); + runFlushTest(sensors, true /* activateSensor */, kFlushes, kFlushes, Result::OK); +} + +TEST_P(SensorsHidlTest, FlushOneShotSensor) { + // Find a sensor that is a one-shot sensor + std::vector sensors = getOneShotSensors(); + if (sensors.size() == 0) { + return; + } + + runSingleFlushTest(sensors, true /* activateSensor */, 0 /* expectedFlushCount */, + Result::BAD_VALUE); +} + +TEST_P(SensorsHidlTest, FlushInactiveSensor) { + // Attempt to find a non-one shot sensor, then a one-shot sensor if necessary + std::vector sensors = getNonOneShotSensors(); + if (sensors.size() == 0) { + sensors = getOneShotSensors(); + if (sensors.size() == 0) { + return; + } + } + + runSingleFlushTest(sensors, false /* activateSensor */, 0 /* expectedFlushCount */, + Result::BAD_VALUE); +} + +TEST_P(SensorsHidlTest, FlushNonexistentSensor) { + SensorInfoType sensor; + std::vector sensors = getNonOneShotSensors(); + if (sensors.size() == 0) { + sensors = getOneShotSensors(); + if (sensors.size() == 0) { + return; + } + } + sensor = sensors.front(); + sensor.sensorHandle = getInvalidSensorHandle(); + runSingleFlushTest(std::vector{sensor}, false /* activateSensor */, + 0 /* expectedFlushCount */, Result::BAD_VALUE); +} + +TEST_P(SensorsHidlTest, Batch) { + if (getSensorsList().size() == 0) { + return; + } + + activateAllSensors(false /* enable */); + for (const SensorInfoType& sensor : getSensorsList()) { + // Call batch on inactive sensor + // One shot sensors have minDelay set to -1 which is an invalid + // parameter. Use 0 instead to avoid errors. + int64_t samplingPeriodNs = extractReportMode(sensor.flags) == SensorFlagBits::ONE_SHOT_MODE + ? 0 + : sensor.minDelay; + ASSERT_EQ(batch(sensor.sensorHandle, samplingPeriodNs, 0 /* maxReportLatencyNs */), + Result::OK); + + // Activate the sensor + activate(sensor.sensorHandle, true /* enabled */); + + // Call batch on an active sensor + ASSERT_EQ(batch(sensor.sensorHandle, sensor.maxDelay, 0 /* maxReportLatencyNs */), + Result::OK); + } + activateAllSensors(false /* enable */); + + // Call batch on an invalid sensor + SensorInfoType sensor = getSensorsList().front(); + sensor.sensorHandle = getInvalidSensorHandle(); + ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */), + Result::BAD_VALUE); +} + +TEST_P(SensorsHidlTest, Activate) { + if (getSensorsList().size() == 0) { + return; + } + + // Verify that sensor events are generated when activate is called + for (const SensorInfoType& sensor : getSensorsList()) { + batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */); + ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK); + + // Call activate on a sensor that is already activated + ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK); + + // Deactivate the sensor + ASSERT_EQ(activate(sensor.sensorHandle, false), Result::OK); + + // Call deactivate on a sensor that is already deactivated + ASSERT_EQ(activate(sensor.sensorHandle, false), Result::OK); + } + + // Attempt to activate an invalid sensor + int32_t invalidHandle = getInvalidSensorHandle(); + ASSERT_EQ(activate(invalidHandle, true), Result::BAD_VALUE); + ASSERT_EQ(activate(invalidHandle, false), Result::BAD_VALUE); +} + +TEST_P(SensorsHidlTest, NoStaleEvents) { + constexpr milliseconds kFiveHundredMs(500); + constexpr milliseconds kOneSecond(1000); + + // Register the callback to receive sensor events + EventCallback callback; + getEnvironment()->registerCallback(&callback); + + // This test is not valid for one-shot or special-report-mode sensors + const std::vector sensors = getNonOneShotAndNonSpecialSensors(); + milliseconds maxMinDelay(0); + for (const SensorInfoType& sensor : sensors) { + milliseconds minDelay = duration_cast(microseconds(sensor.minDelay)); + maxMinDelay = milliseconds(std::max(maxMinDelay.count(), minDelay.count())); + } + + // Activate the sensors so that they start generating events + activateAllSensors(true); + + // According to the CDD, the first sample must be generated within 400ms + 2 * sample_time + // and the maximum reporting latency is 100ms + 2 * sample_time. Wait a sufficient amount + // of time to guarantee that a sample has arrived. + callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay)); + activateAllSensors(false); + + // Save the last received event for each sensor + std::map lastEventTimestampMap; + for (const SensorInfoType& sensor : sensors) { + // Some on-change sensors may not report an event without stimulus + if (extractReportMode(sensor.flags) != SensorFlagBits::ON_CHANGE_MODE) { + ASSERT_GE(callback.getEvents(sensor.sensorHandle).size(), 1); + } + if (callback.getEvents(sensor.sensorHandle).size() >= 1) { + lastEventTimestampMap[sensor.sensorHandle] = + callback.getEvents(sensor.sensorHandle).back().timestamp; + } + } + + // Allow some time to pass, reset the callback, then reactivate the sensors + usleep(duration_cast(kOneSecond + (5 * maxMinDelay)).count()); + callback.reset(); + activateAllSensors(true); + callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay)); + activateAllSensors(false); + + for (const SensorInfoType& sensor : sensors) { + // Skip sensors that did not previously report an event + if (lastEventTimestampMap.find(sensor.sensorHandle) == lastEventTimestampMap.end()) { + continue; + } + // Skip on-change sensors that do not consistently report an initial event + if (callback.getEvents(sensor.sensorHandle).size() < 1) { + continue; + } + // Ensure that the first event received is not stale by ensuring that its timestamp is + // sufficiently different from the previous event + const EventType newEvent = callback.getEvents(sensor.sensorHandle).front(); + milliseconds delta = duration_cast( + nanoseconds(newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle])); + milliseconds sensorMinDelay = duration_cast(microseconds(sensor.minDelay)); + ASSERT_GE(delta, kFiveHundredMs + (3 * sensorMinDelay)); + } +} + +void SensorsHidlTest::checkRateLevel(const SensorInfoType& sensor, int32_t directChannelHandle, + RateLevel rateLevel) { + configDirectReport(sensor.sensorHandle, directChannelHandle, rateLevel, + [&](Result result, int32_t reportToken) { + if (isDirectReportRateSupported(sensor, rateLevel)) { + ASSERT_EQ(result, Result::OK); + if (rateLevel != RateLevel::STOP) { + ASSERT_GT(reportToken, 0); + } + } else { + ASSERT_EQ(result, Result::BAD_VALUE); + } + }); +} + +void SensorsHidlTest::queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType, + bool* supportsAnyDirectChannel) { + *supportsSharedMemType = false; + *supportsAnyDirectChannel = false; + for (const SensorInfoType& curSensor : getSensorsList()) { + if (isDirectChannelTypeSupported(curSensor, memType)) { + *supportsSharedMemType = true; + } + if (isDirectChannelTypeSupported(curSensor, SharedMemType::ASHMEM) || + isDirectChannelTypeSupported(curSensor, SharedMemType::GRALLOC)) { + *supportsAnyDirectChannel = true; + } + + if (*supportsSharedMemType && *supportsAnyDirectChannel) { + break; + } + } +} + +void SensorsHidlTest::verifyRegisterDirectChannel( + std::shared_ptr> mem, + int32_t* directChannelHandle, bool supportsSharedMemType, bool supportsAnyDirectChannel) { + char* buffer = mem->getBuffer(); + memset(buffer, 0xff, mem->getSize()); + + registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) { + if (supportsSharedMemType) { + ASSERT_EQ(result, Result::OK); + ASSERT_GT(channelHandle, 0); + + // Verify that the memory has been zeroed + for (size_t i = 0; i < mem->getSize(); i++) { + ASSERT_EQ(buffer[i], 0x00); + } + } else { + Result expectedResult = + supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION; + ASSERT_EQ(result, expectedResult); + ASSERT_EQ(channelHandle, -1); + } + *directChannelHandle = channelHandle; + }); +} + +void SensorsHidlTest::verifyConfigure(const SensorInfoType& sensor, SharedMemType memType, + int32_t directChannelHandle, bool supportsAnyDirectChannel) { + if (isDirectChannelTypeSupported(sensor, memType)) { + // Verify that each rate level is properly supported + checkRateLevel(sensor, directChannelHandle, RateLevel::NORMAL); + checkRateLevel(sensor, directChannelHandle, RateLevel::FAST); + checkRateLevel(sensor, directChannelHandle, RateLevel::VERY_FAST); + checkRateLevel(sensor, directChannelHandle, RateLevel::STOP); + + // Verify that a sensor handle of -1 is only acceptable when using RateLevel::STOP + configDirectReport(-1 /* sensorHandle */, directChannelHandle, RateLevel::NORMAL, + [](Result result, int32_t /* reportToken */) { + ASSERT_EQ(result, Result::BAD_VALUE); + }); + configDirectReport( + -1 /* sensorHandle */, directChannelHandle, RateLevel::STOP, + [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); }); + } else { + // directChannelHandle will be -1 here, HAL should either reject it as a bad value if there + // is some level of direct channel report, otherwise return INVALID_OPERATION if direct + // channel is not supported at all + Result expectedResult = + supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION; + configDirectReport(sensor.sensorHandle, directChannelHandle, RateLevel::NORMAL, + [expectedResult](Result result, int32_t /* reportToken */) { + ASSERT_EQ(result, expectedResult); + }); + } +} + +void SensorsHidlTest::verifyUnregisterDirectChannel(int32_t directChannelHandle, + bool supportsAnyDirectChannel) { + Result expectedResult = supportsAnyDirectChannel ? Result::OK : Result::INVALID_OPERATION; + ASSERT_EQ(unregisterDirectChannel(directChannelHandle), expectedResult); +} + +void SensorsHidlTest::verifyDirectChannel(SharedMemType memType) { + constexpr size_t kNumEvents = 1; + constexpr size_t kMemSize = kNumEvents * kEventSize; + + std::shared_ptr> mem( + SensorsTestSharedMemory::create(memType, kMemSize)); + ASSERT_NE(mem, nullptr); + + bool supportsSharedMemType; + bool supportsAnyDirectChannel; + queryDirectChannelSupport(memType, &supportsSharedMemType, &supportsAnyDirectChannel); + + for (const SensorInfoType& sensor : getSensorsList()) { + int32_t directChannelHandle = 0; + verifyRegisterDirectChannel(mem, &directChannelHandle, supportsSharedMemType, + supportsAnyDirectChannel); + verifyConfigure(sensor, memType, directChannelHandle, supportsAnyDirectChannel); + verifyUnregisterDirectChannel(directChannelHandle, supportsAnyDirectChannel); + } +} + +TEST_P(SensorsHidlTest, DirectChannelAshmem) { + verifyDirectChannel(SharedMemType::ASHMEM); +} + +TEST_P(SensorsHidlTest, DirectChannelGralloc) { + verifyDirectChannel(SharedMemType::GRALLOC); +} + +bool SensorsHidlTest::getDirectChannelSensor(SensorInfoType* sensor, SharedMemType* memType, + RateLevel* rate) { + bool found = false; + for (const SensorInfoType& curSensor : getSensorsList()) { + if (isDirectChannelTypeSupported(curSensor, SharedMemType::ASHMEM)) { + *memType = SharedMemType::ASHMEM; + *sensor = curSensor; + found = true; + break; + } else if (isDirectChannelTypeSupported(curSensor, SharedMemType::GRALLOC)) { + *memType = SharedMemType::GRALLOC; + *sensor = curSensor; + found = true; + break; + } + } + + if (found) { + // Find a supported rate level + constexpr int kNumRateLevels = 3; + RateLevel rates[kNumRateLevels] = {RateLevel::NORMAL, RateLevel::FAST, + RateLevel::VERY_FAST}; + *rate = RateLevel::STOP; + for (int i = 0; i < kNumRateLevels; i++) { + if (isDirectReportRateSupported(*sensor, rates[i])) { + *rate = rates[i]; + } + } + + // At least one rate level must be supported + EXPECT_NE(*rate, RateLevel::STOP); + } + return found; +} + +TEST_P(SensorsHidlTest, ConfigureDirectChannelWithInvalidHandle) { + SensorInfoType sensor; + SharedMemType memType; + RateLevel rate; + if (!getDirectChannelSensor(&sensor, &memType, &rate)) { + return; + } + + // Verify that an invalid channel handle produces a BAD_VALUE result + configDirectReport(sensor.sensorHandle, -1, rate, [](Result result, int32_t /* reportToken */) { + ASSERT_EQ(result, Result::BAD_VALUE); + }); +} + +TEST_P(SensorsHidlTest, CleanupDirectConnectionOnInitialize) { + constexpr size_t kNumEvents = 1; + constexpr size_t kMemSize = kNumEvents * kEventSize; + + SensorInfoType sensor; + SharedMemType memType; + RateLevel rate; + + if (!getDirectChannelSensor(&sensor, &memType, &rate)) { + return; + } + + std::shared_ptr> mem( + SensorsTestSharedMemory::create(memType, kMemSize)); + ASSERT_NE(mem, nullptr); + + int32_t directChannelHandle = 0; + registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) { + ASSERT_EQ(result, Result::OK); + directChannelHandle = channelHandle; + }); + + // Configure the channel and expect success + configDirectReport( + sensor.sensorHandle, directChannelHandle, rate, + [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); }); + + // Call initialize() via the environment setup to cause the HAL to re-initialize + // Clear the active direct connections so they are not stopped during TearDown + auto handles = mDirectChannelHandles; + mDirectChannelHandles.clear(); + getEnvironment()->HidlTearDown(); + getEnvironment()->HidlSetUp(); + if (HasFatalFailure()) { + return; // Exit early if resetting the environment failed + } + + // Attempt to configure the direct channel and expect it to fail + configDirectReport( + sensor.sensorHandle, directChannelHandle, rate, + [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::BAD_VALUE); }); + + // Restore original handles, though they should already be deactivated + mDirectChannelHandles = handles; +} diff --git a/sensors/common/vts/utils/Android.bp b/sensors/common/vts/utils/Android.bp index bb4d329fba..ca4346a963 100644 --- a/sensors/common/vts/utils/Android.bp +++ b/sensors/common/vts/utils/Android.bp @@ -20,9 +20,6 @@ cc_library_static { cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""], srcs: [ "GrallocWrapper.cpp", - "SensorsHidlEnvironmentBase.cpp", - "SensorsHidlTestBase.cpp", - "SensorsTestSharedMemory.cpp", ], export_include_dirs: [ "include", @@ -30,6 +27,9 @@ cc_library_static { local_include_dirs: [ "include/sensors-vts-utils", ], + shared_libs: [ + "libutils", + ], static_libs: [ "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.allocator@3.0", @@ -37,5 +37,7 @@ cc_library_static { "android.hardware.graphics.mapper@2.1", "android.hardware.graphics.mapper@3.0", "android.hardware.sensors@1.0", + "android.hardware.sensors@2.0", + "android.hardware.sensors@2.1", ], } diff --git a/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp b/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp deleted file mode 100644 index fa0e2e9bf0..0000000000 --- a/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2018 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 "SensorsHidlEnvironmentBase.h" - -void SensorsHidlEnvironmentBase::HidlSetUp() { - ASSERT_TRUE(resetHal()) << "could not get hidl service"; - - mCollectionEnabled = false; - startPollingThread(); - - // In case framework just stopped for test and there is sensor events in the pipe, - // wait some time for those events to be cleared to avoid them messing up the test. - std::this_thread::sleep_for(std::chrono::seconds(3)); -} - -void SensorsHidlEnvironmentBase::HidlTearDown() { - mStopThread = true; - if (mPollThread.joinable()) { - mPollThread.detach(); - } -} - -void SensorsHidlEnvironmentBase::catEvents(std::vector* output) { - std::lock_guard lock(mEventsMutex); - if (output) { - output->insert(output->end(), mEvents.begin(), mEvents.end()); - } - mEvents.clear(); -} - -void SensorsHidlEnvironmentBase::setCollection(bool enable) { - std::lock_guard lock(mEventsMutex); - mCollectionEnabled = enable; -} - -void SensorsHidlEnvironmentBase::addEvent(const Event& ev) { - std::lock_guard lock(mEventsMutex); - if (mCollectionEnabled) { - mEvents.push_back(ev); - } - - if (mCallback != nullptr) { - mCallback->onEvent(ev); - } -} - -void SensorsHidlEnvironmentBase::registerCallback(IEventCallback* callback) { - std::lock_guard lock(mEventsMutex); - mCallback = callback; -} - -void SensorsHidlEnvironmentBase::unregisterCallback() { - std::lock_guard lock(mEventsMutex); - mCallback = nullptr; -} \ No newline at end of file diff --git a/sensors/common/vts/utils/SensorsHidlTestBase.cpp b/sensors/common/vts/utils/SensorsHidlTestBase.cpp deleted file mode 100644 index 18549dfb17..0000000000 --- a/sensors/common/vts/utils/SensorsHidlTestBase.cpp +++ /dev/null @@ -1,584 +0,0 @@ -/* - * Copyright (C) 2018 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 "SensorsHidlTestBase.h" - -#include "sensors-vts-utils/GrallocWrapper.h" -#include "sensors-vts-utils/SensorsTestSharedMemory.h" - -#include // for sensor type strings -#include -#include - -#include - -using ::android::sp; -using ::android::hardware::hidl_string; -using ::android::hardware::Return; -using ::android::hardware::Void; -using ::android::hardware::sensors::V1_0::SensorFlagShift; -using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset; - -const Vec3NormChecker SensorsHidlTestBase::sAccelNormChecker( - Vec3NormChecker::byNominal(GRAVITY_EARTH, 1.0f /*m/s^2*/)); -const Vec3NormChecker SensorsHidlTestBase::sGyroNormChecker( - Vec3NormChecker::byNominal(0.f, 0.1f /*rad/s*/)); - -std::vector SensorsHidlTestBase::collectEvents(useconds_t timeLimitUs, size_t nEventLimit, - bool clearBeforeStart, - bool changeCollection) { - return collectEvents(timeLimitUs, nEventLimit, getEnvironment(), clearBeforeStart, - changeCollection); -} - -std::vector SensorsHidlTestBase::collectEvents(useconds_t timeLimitUs, size_t nEventLimit, - SensorsHidlEnvironmentBase* environment, - bool clearBeforeStart, - bool changeCollection) { - std::vector events; - constexpr useconds_t SLEEP_GRANULARITY = 100 * 1000; // granularity 100 ms - - ALOGI("collect max of %zu events for %d us, clearBeforeStart %d", nEventLimit, timeLimitUs, - clearBeforeStart); - - if (changeCollection) { - environment->setCollection(true); - } - if (clearBeforeStart) { - environment->catEvents(nullptr); - } - - while (timeLimitUs > 0) { - useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs); - usleep(duration); - timeLimitUs -= duration; - - environment->catEvents(&events); - if (events.size() >= nEventLimit) { - break; - } - ALOGV("time to go = %d, events to go = %d", (int)timeLimitUs, - (int)(nEventLimit - events.size())); - } - - if (changeCollection) { - environment->setCollection(false); - } - return events; -} - -void SensorsHidlTestBase::assertTypeMatchStringType(SensorType type, - const hidl_string& stringType) { - if (type >= SensorType::DEVICE_PRIVATE_BASE) { - return; - } - - switch (type) { -#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type) \ - case SensorType::type: \ - ASSERT_STREQ(SENSOR_STRING_TYPE_##type, stringType.c_str()); \ - break; - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER_UNCALIBRATED); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TEMPERATURE); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TILT_DETECTOR); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WAKE_GESTURE); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WRIST_TILT_GESTURE); - default: - FAIL() << "Type " << static_cast(type) - << " in android defined range is not checked, " - << "stringType = " << stringType; -#undef CHECK_TYPE_STRING_FOR_SENSOR_TYPE - } -} - -void SensorsHidlTestBase::assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode) { - if (type >= SensorType::DEVICE_PRIVATE_BASE) { - return; - } - - SensorFlagBits expected = expectedReportModeForType(type); - - ASSERT_TRUE(expected == (SensorFlagBits)-1 || expected == reportMode) - << "reportMode=" << static_cast(reportMode) - << "expected=" << static_cast(expected); -} - -void SensorsHidlTestBase::assertDelayMatchReportMode(int32_t minDelay, int32_t maxDelay, - SensorFlagBits reportMode) { - switch (reportMode) { - case SensorFlagBits::CONTINUOUS_MODE: - ASSERT_LT(0, minDelay); - ASSERT_LE(0, maxDelay); - break; - case SensorFlagBits::ON_CHANGE_MODE: - ASSERT_LE(0, minDelay); - ASSERT_LE(0, maxDelay); - break; - case SensorFlagBits::ONE_SHOT_MODE: - ASSERT_EQ(-1, minDelay); - ASSERT_EQ(0, maxDelay); - break; - case SensorFlagBits::SPECIAL_REPORTING_MODE: - // do not enforce anything for special reporting mode - break; - default: - FAIL() << "Report mode " << static_cast(reportMode) << " not checked"; - } -} - -// return -1 means no expectation for this type -SensorFlagBits SensorsHidlTestBase::expectedReportModeForType(SensorType type) { - switch (type) { - case SensorType::ACCELEROMETER: - case SensorType::ACCELEROMETER_UNCALIBRATED: - case SensorType::GYROSCOPE: - case SensorType::MAGNETIC_FIELD: - case SensorType::ORIENTATION: - case SensorType::PRESSURE: - case SensorType::TEMPERATURE: - case SensorType::GRAVITY: - case SensorType::LINEAR_ACCELERATION: - case SensorType::ROTATION_VECTOR: - case SensorType::MAGNETIC_FIELD_UNCALIBRATED: - case SensorType::GAME_ROTATION_VECTOR: - case SensorType::GYROSCOPE_UNCALIBRATED: - case SensorType::GEOMAGNETIC_ROTATION_VECTOR: - case SensorType::POSE_6DOF: - case SensorType::HEART_BEAT: - return SensorFlagBits::CONTINUOUS_MODE; - - case SensorType::LIGHT: - case SensorType::PROXIMITY: - case SensorType::RELATIVE_HUMIDITY: - case SensorType::AMBIENT_TEMPERATURE: - case SensorType::HEART_RATE: - case SensorType::DEVICE_ORIENTATION: - case SensorType::STEP_COUNTER: - case SensorType::LOW_LATENCY_OFFBODY_DETECT: - return SensorFlagBits::ON_CHANGE_MODE; - - case SensorType::SIGNIFICANT_MOTION: - case SensorType::WAKE_GESTURE: - case SensorType::GLANCE_GESTURE: - case SensorType::PICK_UP_GESTURE: - case SensorType::MOTION_DETECT: - case SensorType::STATIONARY_DETECT: - return SensorFlagBits::ONE_SHOT_MODE; - - case SensorType::STEP_DETECTOR: - case SensorType::TILT_DETECTOR: - case SensorType::WRIST_TILT_GESTURE: - case SensorType::DYNAMIC_SENSOR_META: - return SensorFlagBits::SPECIAL_REPORTING_MODE; - - default: - ALOGW("Type %d is not implemented in expectedReportModeForType", (int)type); - return (SensorFlagBits)-1; - } -} - -bool SensorsHidlTestBase::isDirectReportRateSupported(SensorInfo sensor, RateLevel rate) { - unsigned int r = static_cast(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT) >> - static_cast(SensorFlagShift::DIRECT_REPORT); - return r >= static_cast(rate); -} - -bool SensorsHidlTestBase::isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type) { - switch (type) { - case SharedMemType::ASHMEM: - return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_ASHMEM) != 0; - case SharedMemType::GRALLOC: - return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_GRALLOC) != 0; - default: - return false; - } -} - -void SensorsHidlTestBase::testDirectReportOperation(SensorType type, SharedMemType memType, - RateLevel rate, - const SensorEventsChecker& checker) { - constexpr size_t kEventSize = static_cast(SensorsEventFormatOffset::TOTAL_LENGTH); - constexpr size_t kNEvent = 4096; - constexpr size_t kMemSize = kEventSize * kNEvent; - - constexpr float kNormalNominal = 50; - constexpr float kFastNominal = 200; - constexpr float kVeryFastNominal = 800; - - constexpr float kNominalTestTimeSec = 1.f; - constexpr float kMaxTestTimeSec = kNominalTestTimeSec + 0.5f; // 0.5 second for initialization - - SensorInfo sensor = defaultSensorByType(type); - - if (!isValidType(sensor.type)) { - // no default sensor of this type - return; - } - - if (!isDirectReportRateSupported(sensor, rate)) { - return; - } - - if (!isDirectChannelTypeSupported(sensor, memType)) { - return; - } - - std::unique_ptr mem( - SensorsTestSharedMemory::create(memType, kMemSize)); - ASSERT_NE(mem, nullptr); - - char* buffer = mem->getBuffer(); - // fill memory with data - for (size_t i = 0; i < kMemSize; ++i) { - buffer[i] = '\xcc'; - } - - int32_t channelHandle; - registerDirectChannel(mem->getSharedMemInfo(), - [&channelHandle](auto result, auto channelHandle_) { - ASSERT_EQ(result, Result::OK); - channelHandle = channelHandle_; - }); - - // check memory is zeroed - for (size_t i = 0; i < kMemSize; ++i) { - ASSERT_EQ(buffer[i], '\0'); - } - - int32_t eventToken; - configDirectReport(sensor.sensorHandle, channelHandle, rate, - [&eventToken](auto result, auto token) { - ASSERT_EQ(result, Result::OK); - eventToken = token; - }); - - usleep(static_cast(kMaxTestTimeSec * 1e6f)); - auto events = mem->parseEvents(); - - // find norminal rate - float nominalFreq = 0.f; - switch (rate) { - case RateLevel::NORMAL: - nominalFreq = kNormalNominal; - break; - case RateLevel::FAST: - nominalFreq = kFastNominal; - break; - case RateLevel::VERY_FAST: - nominalFreq = kVeryFastNominal; - break; - case RateLevel::STOP: - FAIL(); - } - - // allowed to be between 55% and 220% of nominal freq - ASSERT_GT(events.size(), static_cast(nominalFreq * 0.55f * kNominalTestTimeSec)); - ASSERT_LT(events.size(), static_cast(nominalFreq * 2.2f * kMaxTestTimeSec)); - - int64_t lastTimestamp = 0; - bool typeErrorReported = false; - bool tokenErrorReported = false; - bool timestampErrorReported = false; - std::vector sensorEvents; - for (auto& e : events) { - if (!tokenErrorReported) { - EXPECT_EQ(eventToken, e.sensorHandle) - << (tokenErrorReported = true, - "Event token does not match that retured from configDirectReport"); - } - - if (isMetaSensorType(e.sensorType)) { - continue; - } - sensorEvents.push_back(e); - - if (!typeErrorReported) { - EXPECT_EQ(type, e.sensorType) - << (typeErrorReported = true, - "Type in event does not match type of sensor registered."); - } - if (!timestampErrorReported) { - EXPECT_GT(e.timestamp, lastTimestamp) - << (timestampErrorReported = true, "Timestamp not monotonically increasing"); - } - lastTimestamp = e.timestamp; - } - - std::string s; - EXPECT_TRUE(checker.check(sensorEvents, &s)) << s; - - // stop sensor and unregister channel - configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::STOP, - [](auto result, auto) { EXPECT_EQ(result, Result::OK); }); - EXPECT_EQ(unregisterDirectChannel(channelHandle), Result::OK); -} - -void SensorsHidlTestBase::testStreamingOperation(SensorType type, - std::chrono::nanoseconds samplingPeriod, - std::chrono::seconds duration, - const SensorEventsChecker& checker) { - std::vector events; - std::vector sensorEvents; - - const int64_t samplingPeriodInNs = samplingPeriod.count(); - const int64_t batchingPeriodInNs = 0; // no batching - const useconds_t minTimeUs = std::chrono::microseconds(duration).count(); - const size_t minNEvent = duration / samplingPeriod; - - SensorInfo sensor = defaultSensorByType(type); - - if (!isValidType(sensor.type)) { - // no default sensor of this type - return; - } - - if (std::chrono::microseconds(sensor.minDelay) > samplingPeriod) { - // rate not supported - return; - } - - int32_t handle = sensor.sensorHandle; - - ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK); - ASSERT_EQ(activate(handle, 1), Result::OK); - events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/); - ASSERT_EQ(activate(handle, 0), Result::OK); - - ALOGI("Collected %zu samples", events.size()); - - ASSERT_GT(events.size(), 0u); - - bool handleMismatchReported = false; - bool metaSensorTypeErrorReported = false; - for (auto& e : events) { - if (e.sensorType == type) { - // avoid generating hundreds of error - if (!handleMismatchReported) { - EXPECT_EQ(e.sensorHandle, handle) - << (handleMismatchReported = true, - "Event of the same type must come from the sensor registered"); - } - sensorEvents.push_back(e); - } else { - // avoid generating hundreds of error - if (!metaSensorTypeErrorReported) { - EXPECT_TRUE(isMetaSensorType(e.sensorType)) - << (metaSensorTypeErrorReported = true, - "Only meta types are allowed besides the type registered"); - } - } - } - - std::string s; - EXPECT_TRUE(checker.check(sensorEvents, &s)) << s; - - EXPECT_GE(sensorEvents.size(), - minNEvent / 2); // make sure returned events are not all meta -} - -void SensorsHidlTestBase::testSamplingRateHotSwitchOperation(SensorType type, bool fastToSlow) { - std::vector events1, events2; - - constexpr int64_t batchingPeriodInNs = 0; // no batching - constexpr int64_t collectionTimeoutUs = 60000000; // 60s - constexpr size_t minNEvent = 50; - - SensorInfo sensor = defaultSensorByType(type); - - if (!isValidType(sensor.type)) { - // no default sensor of this type - return; - } - - int32_t handle = sensor.sensorHandle; - int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll; - int64_t maxSamplingPeriodInNs = sensor.maxDelay * 1000ll; - - if (minSamplingPeriodInNs == maxSamplingPeriodInNs) { - // only support single rate - return; - } - - int64_t firstCollectionPeriod = fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs; - int64_t secondCollectionPeriod = !fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs; - - // first collection - ASSERT_EQ(batch(handle, firstCollectionPeriod, batchingPeriodInNs), Result::OK); - ASSERT_EQ(activate(handle, 1), Result::OK); - - usleep(500000); // sleep 0.5 sec to wait for change rate to happen - events1 = collectEvents(collectionTimeoutUs, minNEvent); - - // second collection, without stop sensor - ASSERT_EQ(batch(handle, secondCollectionPeriod, batchingPeriodInNs), Result::OK); - - usleep(500000); // sleep 0.5 sec to wait for change rate to happen - events2 = collectEvents(collectionTimeoutUs, minNEvent); - - // end of collection, stop sensor - ASSERT_EQ(activate(handle, 0), Result::OK); - - ALOGI("Collected %zu fast samples and %zu slow samples", events1.size(), events2.size()); - - ASSERT_GT(events1.size(), 0u); - ASSERT_GT(events2.size(), 0u); - - int64_t minDelayAverageInterval, maxDelayAverageInterval; - std::vector& minDelayEvents(fastToSlow ? events1 : events2); - std::vector& maxDelayEvents(fastToSlow ? events2 : events1); - - size_t nEvent = 0; - int64_t prevTimestamp = -1; - int64_t timestampInterval = 0; - for (auto& e : minDelayEvents) { - if (e.sensorType == type) { - ASSERT_EQ(e.sensorHandle, handle); - if (prevTimestamp > 0) { - timestampInterval += e.timestamp - prevTimestamp; - } - prevTimestamp = e.timestamp; - ++nEvent; - } - } - ASSERT_GT(nEvent, 2u); - minDelayAverageInterval = timestampInterval / (nEvent - 1); - - nEvent = 0; - prevTimestamp = -1; - timestampInterval = 0; - for (auto& e : maxDelayEvents) { - if (e.sensorType == type) { - ASSERT_EQ(e.sensorHandle, handle); - if (prevTimestamp > 0) { - timestampInterval += e.timestamp - prevTimestamp; - } - prevTimestamp = e.timestamp; - ++nEvent; - } - } - ASSERT_GT(nEvent, 2u); - maxDelayAverageInterval = timestampInterval / (nEvent - 1); - - // change of rate is significant. - ALOGI("min/maxDelayAverageInterval = %" PRId64 " %" PRId64, minDelayAverageInterval, - maxDelayAverageInterval); - EXPECT_GT((maxDelayAverageInterval - minDelayAverageInterval), minDelayAverageInterval / 10); - - // fastest rate sampling time is close to spec - EXPECT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs), - minSamplingPeriodInNs / 10); - - // slowest rate sampling time is close to spec - EXPECT_LT(std::abs(maxDelayAverageInterval - maxSamplingPeriodInNs), - maxSamplingPeriodInNs / 10); -} - -void SensorsHidlTestBase::testBatchingOperation(SensorType type) { - std::vector events; - - constexpr int64_t maxBatchingTestTimeNs = 30ull * 1000 * 1000 * 1000; - constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000; - - SensorInfo sensor = defaultSensorByType(type); - - if (!isValidType(sensor.type)) { - // no default sensor of this type - return; - } - - int32_t handle = sensor.sensorHandle; - int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll; - uint32_t minFifoCount = sensor.fifoReservedEventCount; - int64_t batchingPeriodInNs = minFifoCount * minSamplingPeriodInNs; - - if (batchingPeriodInNs < oneSecondInNs) { - // batching size too small to test reliably - return; - } - - batchingPeriodInNs = std::min(batchingPeriodInNs, maxBatchingTestTimeNs); - - ALOGI("Test batching for %d ms", (int)(batchingPeriodInNs / 1000 / 1000)); - - int64_t allowedBatchDeliverTimeNs = std::max(oneSecondInNs, batchingPeriodInNs / 10); - - ASSERT_EQ(batch(handle, minSamplingPeriodInNs, INT64_MAX), Result::OK); - ASSERT_EQ(activate(handle, 1), Result::OK); - - usleep(500000); // sleep 0.5 sec to wait for initialization - ASSERT_EQ(flush(handle), Result::OK); - - // wait for 80% of the reserved batching period - // there should not be any significant amount of events - // since collection is not enabled all events will go down the drain - usleep(batchingPeriodInNs / 1000 * 8 / 10); - - getEnvironment()->setCollection(true); - // clean existing collections - collectEvents(0 /*timeLimitUs*/, 0 /*nEventLimit*/, true /*clearBeforeStart*/, - false /*change collection*/); - - // 0.8 + 0.2 times the batching period - usleep(batchingPeriodInNs / 1000 * 8 / 10); - ASSERT_EQ(flush(handle), Result::OK); - - // plus some time for the event to deliver - events = collectEvents(allowedBatchDeliverTimeNs / 1000, minFifoCount, - false /*clearBeforeStart*/, false /*change collection*/); - - getEnvironment()->setCollection(false); - ASSERT_EQ(activate(handle, 0), Result::OK); - - size_t nEvent = 0; - for (auto& e : events) { - if (e.sensorType == type && e.sensorHandle == handle) { - ++nEvent; - } - } - - // at least reach 90% of advertised capacity - ASSERT_GT(nEvent, (size_t)(minFifoCount * 9 / 10)); -} diff --git a/sensors/common/vts/utils/SensorsTestSharedMemory.cpp b/sensors/common/vts/utils/SensorsTestSharedMemory.cpp deleted file mode 100644 index 3b068bd5c5..0000000000 --- a/sensors/common/vts/utils/SensorsTestSharedMemory.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (C) 2018 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 "SensorsTestSharedMemory.h" - -#include - -#include -#include - -using namespace ::android::hardware::sensors::V1_0; - -SharedMemInfo SensorsTestSharedMemory::getSharedMemInfo() const { - SharedMemInfo mem = {.type = mType, - .format = SharedMemFormat::SENSORS_EVENT, - .size = static_cast(mSize), - .memoryHandle = mNativeHandle}; - return mem; -} - -char* SensorsTestSharedMemory::getBuffer() const { - return mBuffer; -} - -size_t SensorsTestSharedMemory::getSize() const { - return mSize; -} - -std::vector SensorsTestSharedMemory::parseEvents(int64_t lastCounter, size_t offset) const { - constexpr size_t kEventSize = static_cast(SensorsEventFormatOffset::TOTAL_LENGTH); - constexpr size_t kOffsetSize = static_cast(SensorsEventFormatOffset::SIZE_FIELD); - constexpr size_t kOffsetToken = static_cast(SensorsEventFormatOffset::REPORT_TOKEN); - constexpr size_t kOffsetType = static_cast(SensorsEventFormatOffset::SENSOR_TYPE); - constexpr size_t kOffsetAtomicCounter = - static_cast(SensorsEventFormatOffset::ATOMIC_COUNTER); - constexpr size_t kOffsetTimestamp = static_cast(SensorsEventFormatOffset::TIMESTAMP); - constexpr size_t kOffsetData = static_cast(SensorsEventFormatOffset::DATA); - - std::vector events; - std::vector data(16); - - while (offset + kEventSize <= mSize) { - int64_t atomicCounter = - *reinterpret_cast(mBuffer + offset + kOffsetAtomicCounter); - if (atomicCounter <= lastCounter) { - ALOGV("atomicCounter = %" PRId64 ", lastCounter = %" PRId64, atomicCounter, - lastCounter); - break; - } - - int32_t size = *reinterpret_cast(mBuffer + offset + kOffsetSize); - if (size != kEventSize) { - // unknown error, events parsed may be wrong, remove all - events.clear(); - break; - } - - int32_t token = *reinterpret_cast(mBuffer + offset + kOffsetToken); - int32_t type = *reinterpret_cast(mBuffer + offset + kOffsetType); - int64_t timestamp = *reinterpret_cast(mBuffer + offset + kOffsetTimestamp); - - ALOGV("offset = %zu, cnt %" PRId64 ", token %" PRId32 ", type %" PRId32 - ", timestamp %" PRId64, - offset, atomicCounter, token, type, timestamp); - - Event event = { - .timestamp = timestamp, - .sensorHandle = token, - .sensorType = static_cast(type), - }; - event.u.data = android::hardware::hidl_array( - reinterpret_cast(mBuffer + offset + kOffsetData)); - - events.push_back(event); - - lastCounter = atomicCounter; - offset += kEventSize; - } - - return events; -} - -SensorsTestSharedMemory::SensorsTestSharedMemory(SharedMemType type, size_t size) - : mType(type), mSize(0), mBuffer(nullptr) { - native_handle_t* handle = nullptr; - char* buffer = nullptr; - switch (type) { - case SharedMemType::ASHMEM: { - int fd; - handle = ::native_handle_create(1 /*nFds*/, 0 /*nInts*/); - if (handle != nullptr) { - handle->data[0] = fd = ::ashmem_create_region("SensorsTestSharedMemory", size); - if (handle->data[0] > 0) { - // memory is pinned by default - buffer = static_cast( - ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); - if (buffer != reinterpret_cast(MAP_FAILED)) { - break; - } - ::native_handle_close(handle); - } - ::native_handle_delete(handle); - handle = nullptr; - } - break; - } - case SharedMemType::GRALLOC: { - mGrallocWrapper = std::make_unique<::android::GrallocWrapper>(); - if (!mGrallocWrapper->isInitialized()) { - break; - } - - std::pair buf = mGrallocWrapper->allocate(size); - handle = buf.first; - buffer = static_cast(buf.second); - break; - } - default: - break; - } - - if (buffer != nullptr) { - mNativeHandle = handle; - mSize = size; - mBuffer = buffer; - } -} - -SensorsTestSharedMemory::~SensorsTestSharedMemory() { - switch (mType) { - case SharedMemType::ASHMEM: { - if (mSize != 0) { - ::munmap(mBuffer, mSize); - mBuffer = nullptr; - - ::native_handle_close(mNativeHandle); - ::native_handle_delete(mNativeHandle); - - mNativeHandle = nullptr; - mSize = 0; - } - break; - } - case SharedMemType::GRALLOC: { - if (mSize != 0) { - mGrallocWrapper->freeBuffer(mNativeHandle); - mNativeHandle = nullptr; - mSize = 0; - } - break; - } - default: { - if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) { - ALOGE( - "SensorsTestSharedMemory %p not properly destructed: " - "type %d, native handle %p, size %zu, buffer %p", - this, static_cast(mType), mNativeHandle, mSize, mBuffer); - } - break; - } - } -} - -SensorsTestSharedMemory* SensorsTestSharedMemory::create(SharedMemType type, size_t size) { - constexpr size_t kMaxSize = 128 * 1024 * 1024; // sensor test should not need more than 128M - if (size == 0 || size >= kMaxSize) { - return nullptr; - } - - auto m = new SensorsTestSharedMemory(type, size); - if (m->mSize != size || m->mBuffer == nullptr) { - delete m; - m = nullptr; - } - return m; -} diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorEventsChecker.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorEventsChecker.h index b5daccc987..d6d3227be5 100644 --- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorEventsChecker.h +++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorEventsChecker.h @@ -17,26 +17,26 @@ #ifndef ANDROID_SENSOR_EVENTS_CHECKER_H #define ANDROID_SENSOR_EVENTS_CHECKER_H -#include - #include +template class SensorEventsChecker { - public: - using Event = ::android::hardware::sensors::V1_0::Event; - virtual bool check(const std::vector& events, std::string* out) const = 0; + public: + virtual bool check(const std::vector& events, std::string* out) const = 0; virtual ~SensorEventsChecker() {} }; -class NullChecker : public SensorEventsChecker { - public: - virtual bool check(const std::vector&, std::string*) const { return true; } +template +class NullChecker : public SensorEventsChecker { + public: + virtual bool check(const std::vector&, std::string*) const { return true; } }; -class SensorEventPerEventChecker : public SensorEventsChecker { - public: - virtual bool checkEvent(const Event& event, std::string* out) const = 0; - virtual bool check(const std::vector& events, std::string* out) const { +template +class SensorEventPerEventChecker : public SensorEventsChecker { + public: + virtual bool checkEvent(const EventType& event, std::string* out) const = 0; + virtual bool check(const std::vector& events, std::string* out) const { for (const auto& e : events) { if (!checkEvent(e, out)) { return false; @@ -46,14 +46,15 @@ class SensorEventPerEventChecker : public SensorEventsChecker { } }; -class Vec3NormChecker : public SensorEventPerEventChecker { - public: +template +class Vec3NormChecker : public SensorEventPerEventChecker { + public: Vec3NormChecker(float min, float max) : mLowerLimit(min), mUpperLimit(max) {} - static Vec3NormChecker byNominal(float nominal, float allowedError) { - return Vec3NormChecker(nominal - allowedError, nominal + allowedError); + static Vec3NormChecker byNominal(float nominal, float allowedError) { + return Vec3NormChecker(nominal - allowedError, nominal + allowedError); } - virtual bool checkEvent(const Event& event, std::string* out) const { + virtual bool checkEvent(const EventType& event, std::string* out) const { android::hardware::sensors::V1_0::Vec3 v = event.u.vec3; float norm = std::sqrt(v.x * v.x + v.y * v.y + v.z * v.z); if (norm < mLowerLimit || norm > mUpperLimit) { diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h index dbc9392ade..781427d827 100644 --- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h +++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h @@ -17,7 +17,6 @@ #ifndef ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H #define ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H -#include #include #include @@ -26,27 +25,59 @@ #include #include +template class IEventCallback { - public: + public: virtual ~IEventCallback() = default; - virtual void onEvent(const ::android::hardware::sensors::V1_0::Event& event) = 0; + virtual void onEvent(const Event& event) = 0; }; +template class SensorsHidlEnvironmentBase { public: - using Event = ::android::hardware::sensors::V1_0::Event; - virtual void HidlSetUp(); - virtual void HidlTearDown(); + virtual void HidlSetUp() { + ASSERT_TRUE(resetHal()) << "could not get hidl service"; + + mCollectionEnabled = false; + startPollingThread(); + + // In case framework just stopped for test and there is sensor events in the pipe, + // wait some time for those events to be cleared to avoid them messing up the test. + std::this_thread::sleep_for(std::chrono::seconds(3)); + } + + virtual void HidlTearDown() { + mStopThread = true; + if (mPollThread.joinable()) { + mPollThread.join(); + } + } // Get and clear all events collected so far (like "cat" shell command). // If output is nullptr, it clears all collected events. - void catEvents(std::vector* output); + void catEvents(std::vector* output) { + std::lock_guard lock(mEventsMutex); + if (output) { + output->insert(output->end(), mEvents.begin(), mEvents.end()); + } + mEvents.clear(); + } // set sensor event collection status - void setCollection(bool enable); + void setCollection(bool enable) { + std::lock_guard lock(mEventsMutex); + mCollectionEnabled = enable; + } - void registerCallback(IEventCallback* callback); - void unregisterCallback(); + void registerCallback(IEventCallback* callback) { + std::lock_guard lock(mEventsMutex); + mCallback = callback; + } + + void unregisterCallback() { + std::lock_guard lock(mEventsMutex); + mCallback = nullptr; + } protected: SensorsHidlEnvironmentBase(const std::string& service_name) @@ -55,7 +86,16 @@ class SensorsHidlEnvironmentBase { } virtual ~SensorsHidlEnvironmentBase(){}; - void addEvent(const Event& ev); + void addEvent(const Event& ev) { + std::lock_guard lock(mEventsMutex); + if (mCollectionEnabled) { + mEvents.push_back(ev); + } + + if (mCallback != nullptr) { + mCallback->onEvent(ev); + } + } virtual void startPollingThread() = 0; virtual bool resetHal() = 0; @@ -67,9 +107,9 @@ class SensorsHidlEnvironmentBase { std::vector mEvents; std::mutex mEventsMutex; - IEventCallback* mCallback; + IEventCallback* mCallback; - GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentBase); + GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentBase); }; #endif // ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H \ No newline at end of file diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h index 54e899b900..03bec87d0c 100644 --- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h +++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h @@ -19,11 +19,15 @@ #include "sensors-vts-utils/SensorEventsChecker.h" #include "sensors-vts-utils/SensorsHidlEnvironmentBase.h" +#include "sensors-vts-utils/SensorsTestSharedMemory.h" #include #include #include +#include +#include +#include #include #include @@ -34,19 +38,130 @@ using ::android::hardware::Void; using ::android::sp; using ::android::hardware::hidl_string; -using ::android::hardware::sensors::V1_0::Event; -using ::android::hardware::sensors::V1_0::ISensors; using ::android::hardware::sensors::V1_0::RateLevel; using ::android::hardware::sensors::V1_0::Result; using ::android::hardware::sensors::V1_0::SensorFlagBits; -using ::android::hardware::sensors::V1_0::SensorInfo; -using ::android::hardware::sensors::V1_0::SensorType; +using ::android::hardware::sensors::V1_0::SensorFlagShift; +using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset; using ::android::hardware::sensors::V1_0::SharedMemInfo; using ::android::hardware::sensors::V1_0::SharedMemType; +template +static void assertTypeMatchStringType(SensorTypeT type, const hidl_string& stringType) { + if (type >= SensorTypeT::DEVICE_PRIVATE_BASE) { + return; + } + + switch (type) { +#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type) \ + case SensorTypeT::type: \ + ASSERT_STREQ(SENSOR_STRING_TYPE_##type, stringType.c_str()); \ + break; + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER_UNCALIBRATED); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TEMPERATURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TILT_DETECTOR); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WAKE_GESTURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WRIST_TILT_GESTURE); + default: + FAIL() << "Type " << static_cast(type) + << " in android defined range is not checked, " + << "stringType = " << stringType; +#undef CHECK_TYPE_STRING_FOR_SENSOR_TYPE + } +} + +template +static SensorFlagBits expectedReportModeForType(SensorTypeT type) { + switch (type) { + case SensorTypeT::ACCELEROMETER: + case SensorTypeT::ACCELEROMETER_UNCALIBRATED: + case SensorTypeT::GYROSCOPE: + case SensorTypeT::MAGNETIC_FIELD: + case SensorTypeT::ORIENTATION: + case SensorTypeT::PRESSURE: + case SensorTypeT::TEMPERATURE: + case SensorTypeT::GRAVITY: + case SensorTypeT::LINEAR_ACCELERATION: + case SensorTypeT::ROTATION_VECTOR: + case SensorTypeT::MAGNETIC_FIELD_UNCALIBRATED: + case SensorTypeT::GAME_ROTATION_VECTOR: + case SensorTypeT::GYROSCOPE_UNCALIBRATED: + case SensorTypeT::GEOMAGNETIC_ROTATION_VECTOR: + case SensorTypeT::POSE_6DOF: + case SensorTypeT::HEART_BEAT: + return SensorFlagBits::CONTINUOUS_MODE; + + case SensorTypeT::LIGHT: + case SensorTypeT::PROXIMITY: + case SensorTypeT::RELATIVE_HUMIDITY: + case SensorTypeT::AMBIENT_TEMPERATURE: + case SensorTypeT::HEART_RATE: + case SensorTypeT::DEVICE_ORIENTATION: + case SensorTypeT::STEP_COUNTER: + case SensorTypeT::LOW_LATENCY_OFFBODY_DETECT: + return SensorFlagBits::ON_CHANGE_MODE; + + case SensorTypeT::SIGNIFICANT_MOTION: + case SensorTypeT::WAKE_GESTURE: + case SensorTypeT::GLANCE_GESTURE: + case SensorTypeT::PICK_UP_GESTURE: + case SensorTypeT::MOTION_DETECT: + case SensorTypeT::STATIONARY_DETECT: + return SensorFlagBits::ONE_SHOT_MODE; + + case SensorTypeT::STEP_DETECTOR: + case SensorTypeT::TILT_DETECTOR: + case SensorTypeT::WRIST_TILT_GESTURE: + case SensorTypeT::DYNAMIC_SENSOR_META: + return SensorFlagBits::SPECIAL_REPORTING_MODE; + + default: + ALOGW("Type %d is not implemented in expectedReportModeForType", (int)type); + return (SensorFlagBits)-1; + } +} + +template class SensorsHidlTestBase : public testing::TestWithParam { public: - virtual SensorsHidlEnvironmentBase* getEnvironment() = 0; + using ISensors = ::android::hardware::sensors::V1_0::ISensors; + + SensorsHidlTestBase() + : mAccelNormChecker(Vec3NormChecker::byNominal(GRAVITY_EARTH, 1.0f /*m/s^2*/)), + mGyroNormChecker(Vec3NormChecker::byNominal(0.f, 0.1f /*rad/s*/)) {} + + virtual SensorsHidlEnvironmentBase* getEnvironment() = 0; + virtual void SetUp() override {} virtual void TearDown() override { @@ -66,16 +181,13 @@ class SensorsHidlTestBase : public testing::TestWithParam { } // implementation wrapper - virtual SensorInfo defaultSensorByType(SensorType type) = 0; + virtual SensorInfoType defaultSensorByType(SensorTypeVersion type) = 0; virtual Return getSensorsList(ISensors::getSensorsList_cb _hidl_cb) = 0; - + virtual Return injectSensorData(const EventType& event) = 0; virtual Return activate(int32_t sensorHandle, bool enabled) = 0; - virtual Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, int64_t maxReportLatencyNs) = 0; - virtual Return flush(int32_t sensorHandle) = 0; - virtual Return injectSensorData(const Event& event) = 0; virtual Return registerDirectChannel(const SharedMemInfo& mem, ISensors::registerDirectChannel_cb _hidl_cb) = 0; virtual Return unregisterDirectChannel(int32_t channelHandle) = 0; @@ -83,12 +195,395 @@ class SensorsHidlTestBase : public testing::TestWithParam { RateLevel rate, ISensors::configDirectReport_cb _hidl_cb) = 0; - std::vector collectEvents(useconds_t timeLimitUs, size_t nEventLimit, - bool clearBeforeStart = true, bool changeCollection = true); - static std::vector collectEvents(useconds_t timeLimitUs, size_t nEventLimit, - SensorsHidlEnvironmentBase* environment, - bool clearBeforeStart = true, - bool changeCollection = true); + std::vector collectEvents(useconds_t timeLimitUs, size_t nEventLimit, + bool clearBeforeStart = true, + bool changeCollection = true) { + return collectEvents(timeLimitUs, nEventLimit, getEnvironment(), clearBeforeStart, + changeCollection); + } + + std::vector collectEvents(useconds_t timeLimitUs, size_t nEventLimit, + SensorsHidlEnvironmentBase* environment, + bool clearBeforeStart = true, + bool changeCollection = true) { + std::vector events; + constexpr useconds_t SLEEP_GRANULARITY = 100 * 1000; // granularity 100 ms + + ALOGI("collect max of %zu events for %d us, clearBeforeStart %d", nEventLimit, timeLimitUs, + clearBeforeStart); + + if (changeCollection) { + environment->setCollection(true); + } + if (clearBeforeStart) { + environment->catEvents(nullptr); + } + + while (timeLimitUs > 0) { + useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs); + usleep(duration); + timeLimitUs -= duration; + + environment->catEvents(&events); + if (events.size() >= nEventLimit) { + break; + } + ALOGV("time to go = %d, events to go = %d", (int)timeLimitUs, + (int)(nEventLimit - events.size())); + } + + if (changeCollection) { + environment->setCollection(false); + } + return events; + } + + void testStreamingOperation(SensorTypeVersion type, std::chrono::nanoseconds samplingPeriod, + std::chrono::seconds duration, + const SensorEventsChecker& checker) { + std::vector events; + std::vector sensorEvents; + + const int64_t samplingPeriodInNs = samplingPeriod.count(); + const int64_t batchingPeriodInNs = 0; // no batching + const useconds_t minTimeUs = std::chrono::microseconds(duration).count(); + const size_t minNEvent = duration / samplingPeriod; + + SensorInfoType sensor = defaultSensorByType(type); + + if (!isValidType(sensor.type)) { + // no default sensor of this type + return; + } + + if (std::chrono::microseconds(sensor.minDelay) > samplingPeriod) { + // rate not supported + return; + } + + int32_t handle = sensor.sensorHandle; + + ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK); + ASSERT_EQ(activate(handle, 1), Result::OK); + events = collectEvents(minTimeUs, minNEvent, getEnvironment(), true /*clearBeforeStart*/); + ASSERT_EQ(activate(handle, 0), Result::OK); + + ALOGI("Collected %zu samples", events.size()); + + ASSERT_GT(events.size(), 0u); + + bool handleMismatchReported = false; + bool metaSensorTypeErrorReported = false; + for (auto& e : events) { + if (e.sensorType == type) { + // avoid generating hundreds of error + if (!handleMismatchReported) { + EXPECT_EQ(e.sensorHandle, handle) + << (handleMismatchReported = true, + "Event of the same type must come from the sensor registered"); + } + sensorEvents.push_back(e); + } else { + // avoid generating hundreds of error + if (!metaSensorTypeErrorReported) { + EXPECT_TRUE(isMetaSensorType(e.sensorType)) + << (metaSensorTypeErrorReported = true, + "Only meta types are allowed besides the type registered"); + } + } + } + + std::string s; + EXPECT_TRUE(checker.check(sensorEvents, &s)) << s; + + EXPECT_GE(sensorEvents.size(), + minNEvent / 2); // make sure returned events are not all meta + } + + void testSamplingRateHotSwitchOperation(SensorTypeVersion type, bool fastToSlow = true) { + std::vector events1, events2; + + constexpr int64_t batchingPeriodInNs = 0; // no batching + constexpr int64_t collectionTimeoutUs = 60000000; // 60s + constexpr size_t minNEvent = 50; + + SensorInfoType sensor = defaultSensorByType(type); + + if (!isValidType(sensor.type)) { + // no default sensor of this type + return; + } + + int32_t handle = sensor.sensorHandle; + int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll; + int64_t maxSamplingPeriodInNs = sensor.maxDelay * 1000ll; + + if (minSamplingPeriodInNs == maxSamplingPeriodInNs) { + // only support single rate + return; + } + + int64_t firstCollectionPeriod = fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs; + int64_t secondCollectionPeriod = + !fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs; + + // first collection + ASSERT_EQ(batch(handle, firstCollectionPeriod, batchingPeriodInNs), Result::OK); + ASSERT_EQ(activate(handle, 1), Result::OK); + + usleep(500000); // sleep 0.5 sec to wait for change rate to happen + events1 = collectEvents(collectionTimeoutUs, minNEvent, getEnvironment()); + + // second collection, without stop sensor + ASSERT_EQ(batch(handle, secondCollectionPeriod, batchingPeriodInNs), Result::OK); + + usleep(500000); // sleep 0.5 sec to wait for change rate to happen + events2 = collectEvents(collectionTimeoutUs, minNEvent, getEnvironment()); + + // end of collection, stop sensor + ASSERT_EQ(activate(handle, 0), Result::OK); + + ALOGI("Collected %zu fast samples and %zu slow samples", events1.size(), events2.size()); + + ASSERT_GT(events1.size(), 0u); + ASSERT_GT(events2.size(), 0u); + + int64_t minDelayAverageInterval, maxDelayAverageInterval; + std::vector& minDelayEvents(fastToSlow ? events1 : events2); + std::vector& maxDelayEvents(fastToSlow ? events2 : events1); + + size_t nEvent = 0; + int64_t prevTimestamp = -1; + int64_t timestampInterval = 0; + for (auto& e : minDelayEvents) { + if (e.sensorType == type) { + ASSERT_EQ(e.sensorHandle, handle); + if (prevTimestamp > 0) { + timestampInterval += e.timestamp - prevTimestamp; + } + prevTimestamp = e.timestamp; + ++nEvent; + } + } + ASSERT_GT(nEvent, 2u); + minDelayAverageInterval = timestampInterval / (nEvent - 1); + + nEvent = 0; + prevTimestamp = -1; + timestampInterval = 0; + for (auto& e : maxDelayEvents) { + if (e.sensorType == type) { + ASSERT_EQ(e.sensorHandle, handle); + if (prevTimestamp > 0) { + timestampInterval += e.timestamp - prevTimestamp; + } + prevTimestamp = e.timestamp; + ++nEvent; + } + } + ASSERT_GT(nEvent, 2u); + maxDelayAverageInterval = timestampInterval / (nEvent - 1); + + // change of rate is significant. + ALOGI("min/maxDelayAverageInterval = %" PRId64 " %" PRId64, minDelayAverageInterval, + maxDelayAverageInterval); + EXPECT_GT((maxDelayAverageInterval - minDelayAverageInterval), + minDelayAverageInterval / 10); + + // fastest rate sampling time is close to spec + EXPECT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs), + minSamplingPeriodInNs / 10); + + // slowest rate sampling time is close to spec + EXPECT_LT(std::abs(maxDelayAverageInterval - maxSamplingPeriodInNs), + maxSamplingPeriodInNs / 10); + } + + void testBatchingOperation(SensorTypeVersion type) { + std::vector events; + + constexpr int64_t maxBatchingTestTimeNs = 30ull * 1000 * 1000 * 1000; + constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000; + + SensorInfoType sensor = defaultSensorByType(type); + + if (!isValidType(sensor.type)) { + // no default sensor of this type + return; + } + + int32_t handle = sensor.sensorHandle; + int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll; + uint32_t minFifoCount = sensor.fifoReservedEventCount; + int64_t batchingPeriodInNs = minFifoCount * minSamplingPeriodInNs; + + if (batchingPeriodInNs < oneSecondInNs) { + // batching size too small to test reliably + return; + } + + batchingPeriodInNs = std::min(batchingPeriodInNs, maxBatchingTestTimeNs); + + ALOGI("Test batching for %d ms", (int)(batchingPeriodInNs / 1000 / 1000)); + + int64_t allowedBatchDeliverTimeNs = std::max(oneSecondInNs, batchingPeriodInNs / 10); + + ASSERT_EQ(batch(handle, minSamplingPeriodInNs, INT64_MAX), Result::OK); + ASSERT_EQ(activate(handle, 1), Result::OK); + + usleep(500000); // sleep 0.5 sec to wait for initialization + ASSERT_EQ(flush(handle), Result::OK); + + // wait for 80% of the reserved batching period + // there should not be any significant amount of events + // since collection is not enabled all events will go down the drain + usleep(batchingPeriodInNs / 1000 * 8 / 10); + + getEnvironment()->setCollection(true); + // clean existing collections + collectEvents(0 /*timeLimitUs*/, 0 /*nEventLimit*/, true /*clearBeforeStart*/, + false /*change collection*/); + + // 0.8 + 0.2 times the batching period + usleep(batchingPeriodInNs / 1000 * 8 / 10); + ASSERT_EQ(flush(handle), Result::OK); + + // plus some time for the event to deliver + events = collectEvents(allowedBatchDeliverTimeNs / 1000, minFifoCount, + false /*clearBeforeStart*/, false /*change collection*/); + + getEnvironment()->setCollection(false); + ASSERT_EQ(activate(handle, 0), Result::OK); + + size_t nEvent = 0; + for (auto& e : events) { + if (e.sensorType == type && e.sensorHandle == handle) { + ++nEvent; + } + } + + // at least reach 90% of advertised capacity + ASSERT_GT(nEvent, (size_t)(minFifoCount * 9 / 10)); + } + + void testDirectReportOperation(SensorTypeVersion type, SharedMemType memType, RateLevel rate, + const SensorEventsChecker& checker) { + constexpr size_t kEventSize = static_cast(SensorsEventFormatOffset::TOTAL_LENGTH); + constexpr size_t kNEvent = 4096; + constexpr size_t kMemSize = kEventSize * kNEvent; + + constexpr float kNormalNominal = 50; + constexpr float kFastNominal = 200; + constexpr float kVeryFastNominal = 800; + + constexpr float kNominalTestTimeSec = 1.f; + constexpr float kMaxTestTimeSec = + kNominalTestTimeSec + 0.5f; // 0.5 second for initialization + + SensorInfoType sensor = defaultSensorByType(type); + + if (!isValidType(sensor.type)) { + // no default sensor of this type + return; + } + + if (!isDirectReportRateSupported(sensor, rate)) { + return; + } + + if (!isDirectChannelTypeSupported(sensor, memType)) { + return; + } + + std::unique_ptr> mem( + SensorsTestSharedMemory::create(memType, kMemSize)); + ASSERT_NE(mem, nullptr); + + char* buffer = mem->getBuffer(); + // fill memory with data + for (size_t i = 0; i < kMemSize; ++i) { + buffer[i] = '\xcc'; + } + + int32_t channelHandle; + registerDirectChannel(mem->getSharedMemInfo(), + [&channelHandle](auto result, auto channelHandle_) { + ASSERT_EQ(result, Result::OK); + channelHandle = channelHandle_; + }); + + // check memory is zeroed + for (size_t i = 0; i < kMemSize; ++i) { + ASSERT_EQ(buffer[i], '\0'); + } + + int32_t eventToken; + configDirectReport(sensor.sensorHandle, channelHandle, rate, + [&eventToken](auto result, auto token) { + ASSERT_EQ(result, Result::OK); + eventToken = token; + }); + + usleep(static_cast(kMaxTestTimeSec * 1e6f)); + auto events = mem->parseEvents(); + + // find norminal rate + float nominalFreq = 0.f; + switch (rate) { + case RateLevel::NORMAL: + nominalFreq = kNormalNominal; + break; + case RateLevel::FAST: + nominalFreq = kFastNominal; + break; + case RateLevel::VERY_FAST: + nominalFreq = kVeryFastNominal; + break; + case RateLevel::STOP: + FAIL(); + } + + // allowed to be between 55% and 220% of nominal freq + ASSERT_GT(events.size(), static_cast(nominalFreq * 0.55f * kNominalTestTimeSec)); + ASSERT_LT(events.size(), static_cast(nominalFreq * 2.2f * kMaxTestTimeSec)); + + int64_t lastTimestamp = 0; + bool typeErrorReported = false; + bool tokenErrorReported = false; + bool timestampErrorReported = false; + std::vector sensorEvents; + for (auto& e : events) { + if (!tokenErrorReported) { + EXPECT_EQ(eventToken, e.sensorHandle) + << (tokenErrorReported = true, + "Event token does not match that retured from configDirectReport"); + } + + if (isMetaSensorType(e.sensorType)) { + continue; + } + sensorEvents.push_back(e); + + if (!typeErrorReported) { + EXPECT_EQ(type, e.sensorType) + << (typeErrorReported = true, + "Type in event does not match type of sensor registered."); + } + if (!timestampErrorReported) { + EXPECT_GT(e.timestamp, lastTimestamp) << (timestampErrorReported = true, + "Timestamp not monotonically increasing"); + } + lastTimestamp = e.timestamp; + } + + std::string s; + EXPECT_TRUE(checker.check(sensorEvents, &s)) << s; + + // stop sensor and unregister channel + configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::STOP, + [](auto result, auto) { EXPECT_EQ(result, Result::OK); }); + EXPECT_EQ(unregisterDirectChannel(channelHandle), Result::OK); + } inline static SensorFlagBits extractReportMode(uint64_t flag) { return (SensorFlagBits)(flag & ((uint64_t)SensorFlagBits::CONTINUOUS_MODE | @@ -97,32 +592,71 @@ class SensorsHidlTestBase : public testing::TestWithParam { (uint64_t)SensorFlagBits::SPECIAL_REPORTING_MODE)); } - inline static bool isMetaSensorType(SensorType type) { - return (type == SensorType::META_DATA || type == SensorType::DYNAMIC_SENSOR_META || - type == SensorType::ADDITIONAL_INFO); + inline static bool isMetaSensorType(SensorTypeVersion type) { + return (type == SensorTypeVersion::META_DATA || + type == SensorTypeVersion::DYNAMIC_SENSOR_META || + type == SensorTypeVersion::ADDITIONAL_INFO); } - inline static bool isValidType(SensorType type) { return (int32_t)type > 0; } + inline static bool isValidType(SensorTypeVersion type) { return (int32_t)type > 0; } - void testStreamingOperation(SensorType type, std::chrono::nanoseconds samplingPeriod, - std::chrono::seconds duration, const SensorEventsChecker& checker); - void testSamplingRateHotSwitchOperation(SensorType type, bool fastToSlow = true); - void testBatchingOperation(SensorType type); - void testDirectReportOperation(SensorType type, SharedMemType memType, RateLevel rate, - const SensorEventsChecker& checker); - - static void assertTypeMatchStringType(SensorType type, const hidl_string& stringType); - static void assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode); static void assertDelayMatchReportMode(int32_t minDelay, int32_t maxDelay, - SensorFlagBits reportMode); - static SensorFlagBits expectedReportModeForType(SensorType type); - static bool isDirectReportRateSupported(SensorInfo sensor, RateLevel rate); - static bool isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type); + SensorFlagBits reportMode) { + switch (reportMode) { + case SensorFlagBits::CONTINUOUS_MODE: + ASSERT_LT(0, minDelay); + ASSERT_LE(0, maxDelay); + break; + case SensorFlagBits::ON_CHANGE_MODE: + ASSERT_LE(0, minDelay); + ASSERT_LE(0, maxDelay); + break; + case SensorFlagBits::ONE_SHOT_MODE: + ASSERT_EQ(-1, minDelay); + ASSERT_EQ(0, maxDelay); + break; + case SensorFlagBits::SPECIAL_REPORTING_MODE: + // do not enforce anything for special reporting mode + break; + default: + FAIL() << "Report mode " << static_cast(reportMode) << " not checked"; + } + } - protected: - // checkers - static const Vec3NormChecker sAccelNormChecker; - static const Vec3NormChecker sGyroNormChecker; + protected: + static void assertTypeMatchReportMode(SensorTypeVersion type, SensorFlagBits reportMode) { + if (type >= SensorTypeVersion::DEVICE_PRIVATE_BASE) { + return; + } + + SensorFlagBits expected = expectedReportModeForType(type); + + ASSERT_TRUE(expected == (SensorFlagBits)-1 || expected == reportMode) + << "reportMode=" << static_cast(reportMode) + << "expected=" << static_cast(expected); + } + + static bool isDirectReportRateSupported(SensorInfoType sensor, RateLevel rate) { + unsigned int r = + static_cast(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT) >> + static_cast(SensorFlagShift::DIRECT_REPORT); + return r >= static_cast(rate); + } + + static bool isDirectChannelTypeSupported(SensorInfoType sensor, SharedMemType type) { + switch (type) { + case SharedMemType::ASHMEM: + return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_ASHMEM) != 0; + case SharedMemType::GRALLOC: + return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_GRALLOC) != 0; + default: + return false; + } + } + + // Checkers + Vec3NormChecker mAccelNormChecker; + Vec3NormChecker mGyroNormChecker; // all sensors and direct channnels used std::unordered_set mSensorHandles; diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h index 002f42c112..39084a45e6 100644 --- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h +++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h @@ -20,25 +20,177 @@ #include "GrallocWrapper.h" #include -#include +#include + +#include +#include #include +using namespace ::android::hardware::sensors::V1_0; + +template class SensorsTestSharedMemory { - using SharedMemType = ::android::hardware::sensors::V1_0::SharedMemType; - using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; - using Event = ::android::hardware::sensors::V1_0::Event; + public: + static SensorsTestSharedMemory* create(SharedMemType type, size_t size) { + constexpr size_t kMaxSize = + 128 * 1024 * 1024; // sensor test should not need more than 128M + if (size == 0 || size >= kMaxSize) { + return nullptr; + } - public: - static SensorsTestSharedMemory* create(SharedMemType type, size_t size); - SharedMemInfo getSharedMemInfo() const; - char* getBuffer() const; - size_t getSize() const; - std::vector parseEvents(int64_t lastCounter = -1, size_t offset = 0) const; - virtual ~SensorsTestSharedMemory(); + auto m = new SensorsTestSharedMemory(type, size); + if (m->mSize != size || m->mBuffer == nullptr) { + delete m; + m = nullptr; + } + return m; + } - private: - SensorsTestSharedMemory(SharedMemType type, size_t size); + SharedMemInfo getSharedMemInfo() const { + SharedMemInfo mem = {.type = mType, + .format = SharedMemFormat::SENSORS_EVENT, + .size = static_cast(mSize), + .memoryHandle = mNativeHandle}; + return mem; + } + char* getBuffer() const { return mBuffer; } + size_t getSize() const { return mSize; } + std::vector parseEvents(int64_t lastCounter = -1, size_t offset = 0) const { + constexpr size_t kEventSize = static_cast(SensorsEventFormatOffset::TOTAL_LENGTH); + constexpr size_t kOffsetSize = static_cast(SensorsEventFormatOffset::SIZE_FIELD); + constexpr size_t kOffsetToken = static_cast(SensorsEventFormatOffset::REPORT_TOKEN); + constexpr size_t kOffsetType = static_cast(SensorsEventFormatOffset::SENSOR_TYPE); + constexpr size_t kOffsetAtomicCounter = + static_cast(SensorsEventFormatOffset::ATOMIC_COUNTER); + constexpr size_t kOffsetTimestamp = + static_cast(SensorsEventFormatOffset::TIMESTAMP); + constexpr size_t kOffsetData = static_cast(SensorsEventFormatOffset::DATA); + + std::vector events; + std::vector data(16); + + while (offset + kEventSize <= mSize) { + int64_t atomicCounter = + *reinterpret_cast(mBuffer + offset + kOffsetAtomicCounter); + if (atomicCounter <= lastCounter) { + ALOGV("atomicCounter = %" PRId64 ", lastCounter = %" PRId64, atomicCounter, + lastCounter); + break; + } + + int32_t size = *reinterpret_cast(mBuffer + offset + kOffsetSize); + if (size != kEventSize) { + // unknown error, events parsed may be wrong, remove all + events.clear(); + break; + } + + int32_t token = *reinterpret_cast(mBuffer + offset + kOffsetToken); + int32_t type = *reinterpret_cast(mBuffer + offset + kOffsetType); + int64_t timestamp = *reinterpret_cast(mBuffer + offset + kOffsetTimestamp); + + ALOGV("offset = %zu, cnt %" PRId64 ", token %" PRId32 ", type %" PRId32 + ", timestamp %" PRId64, + offset, atomicCounter, token, type, timestamp); + + EventType event = { + .timestamp = timestamp, + .sensorHandle = token, + .sensorType = static_cast(type), + }; + event.u.data = android::hardware::hidl_array( + reinterpret_cast(mBuffer + offset + kOffsetData)); + + events.push_back(event); + + lastCounter = atomicCounter; + offset += kEventSize; + } + + return events; + } + + virtual ~SensorsTestSharedMemory() { + switch (mType) { + case SharedMemType::ASHMEM: { + if (mSize != 0) { + ::munmap(mBuffer, mSize); + mBuffer = nullptr; + + ::native_handle_close(mNativeHandle); + ::native_handle_delete(mNativeHandle); + + mNativeHandle = nullptr; + mSize = 0; + } + break; + } + case SharedMemType::GRALLOC: { + if (mSize != 0) { + mGrallocWrapper->freeBuffer(mNativeHandle); + mNativeHandle = nullptr; + mSize = 0; + } + break; + } + default: { + if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) { + ALOGE("SensorsTestSharedMemory %p not properly destructed: " + "type %d, native handle %p, size %zu, buffer %p", + this, static_cast(mType), mNativeHandle, mSize, mBuffer); + } + break; + } + } + } + + private: + SensorsTestSharedMemory(SharedMemType type, size_t size) + : mType(type), mSize(0), mBuffer(nullptr) { + native_handle_t* handle = nullptr; + char* buffer = nullptr; + switch (type) { + case SharedMemType::ASHMEM: { + int fd; + handle = ::native_handle_create(1 /*nFds*/, 0 /*nInts*/); + if (handle != nullptr) { + handle->data[0] = fd = ::ashmem_create_region("SensorsTestSharedMemory", size); + if (handle->data[0] > 0) { + // memory is pinned by default + buffer = static_cast( + ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); + if (buffer != reinterpret_cast(MAP_FAILED)) { + break; + } + ::native_handle_close(handle); + } + ::native_handle_delete(handle); + handle = nullptr; + } + break; + } + case SharedMemType::GRALLOC: { + mGrallocWrapper = std::make_unique<::android::GrallocWrapper>(); + if (!mGrallocWrapper->isInitialized()) { + break; + } + + std::pair buf = mGrallocWrapper->allocate(size); + handle = buf.first; + buffer = static_cast(buf.second); + break; + } + default: + break; + } + + if (buffer != nullptr) { + mNativeHandle = handle; + mSize = size; + mBuffer = buffer; + } + } SharedMemType mType; native_handle_t* mNativeHandle; From 32895908b9da68639506a4df5b743d2964c8c2a1 Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Fri, 14 Feb 2020 08:56:07 -0500 Subject: [PATCH 0603/1022] Prep ISensorsWrapper to be used by the framework Bug: 144139857 Test: Load sensors framework and verify it can receive data Change-Id: I08bdb23779a1ec716cd99e3bc9ded4371fe9c89a --- sensors/common/utils/ISensorsWrapper.h | 271 +++++++++++------- .../vts/2_X/SensorsHidlEnvironmentV2_X.cpp | 8 +- 2 files changed, 176 insertions(+), 103 deletions(-) diff --git a/sensors/common/utils/ISensorsWrapper.h b/sensors/common/utils/ISensorsWrapper.h index 4c8b442396..e9c22b15ac 100644 --- a/sensors/common/utils/ISensorsWrapper.h +++ b/sensors/common/utils/ISensorsWrapper.h @@ -18,23 +18,19 @@ #define ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSWRAPPER_H #include "EventMessageQueueWrapper.h" -#include "convertV2_1.h" +#include "ISensorsWrapper.h" -#include -#include -#include -#include -#include -#include -#include +#include "android/hardware/sensors/1.0/ISensors.h" +#include "android/hardware/sensors/1.0/types.h" +#include "android/hardware/sensors/2.0/ISensors.h" +#include "android/hardware/sensors/2.0/ISensorsCallback.h" +#include "android/hardware/sensors/2.1/ISensors.h" +#include "android/hardware/sensors/2.1/ISensorsCallback.h" +#include "android/hardware/sensors/2.1/types.h" -#include +#include -/** - * ISensorsWrapperBase wraps around the V2_1::ISensors APIs to make any HAL 2.0/2.1 interface - * appear as a HAL 2.1 implementation. This ensures the maximum amount of code can be shared - * between VTS, default implementations, and the sensors framework. - */ +#include namespace android { namespace hardware { @@ -42,135 +38,212 @@ namespace sensors { namespace V2_1 { namespace implementation { -using ::android::sp; +using ::android::hardware::MessageQueue; +using ::android::hardware::MQDescriptorSync; using ::android::hardware::Return; -using ::android::hardware::Void; +using ::android::hardware::sensors::V1_0::ISensors; using ::android::hardware::sensors::V1_0::OperationMode; using ::android::hardware::sensors::V1_0::RateLevel; using ::android::hardware::sensors::V1_0::Result; using ::android::hardware::sensors::V1_0::SharedMemInfo; +using ::android::hardware::sensors::V2_1::Event; +using ::android::hardware::sensors::V2_1::ISensorsCallback; // TODO: Look into providing this as a param if it needs to be a different value // than the framework. static constexpr size_t MAX_RECEIVE_BUFFER_EVENT_COUNT = 256; -class ISensorsWrapperBase : public RefBase { +/* + * The ISensorsWrapper interface includes all function from supported Sensors HAL versions. This + * allows for the SensorDevice to use the ISensorsWrapper interface to interact with the Sensors + * HAL regardless of the current version of the Sensors HAL that is loaded. Each concrete + * instantiation of ISensorsWrapper must correspond to a specific Sensors HAL version. This design + * is beneficial because only the functions that change between Sensors HAL versions must be newly + * implemented, any previously implemented function that does not change may remain the same. + * + * Functions that exist across all versions of the Sensors HAL should be implemented as pure + * virtual functions which forces the concrete instantiations to implement the functions. + * + * Functions that do not exist across all versions of the Sensors HAL should include a default + * implementation that generates an error if called. The default implementation should never + * be called and must be overridden by Sensors HAL versions that support the function. + */ +class ISensorsWrapperBase : public VirtualLightRefBase { public: - virtual ~ISensorsWrapperBase() {} + virtual bool supportsPolling() const = 0; - virtual EventMessageQueueWrapperBase& getEventQueue() = 0; - virtual Return getSensorsList(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) = 0; - virtual Return injectSensorData(const V2_1::Event& event) = 0; - virtual Return initialize( - const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback) = 0; + virtual bool supportsMessageQueues() const = 0; - // V2_0::ISensors implementation - void linkToDeath(android::sp deathRecipient, - uint64_t cookie) { - getSensors()->linkToDeath(deathRecipient, cookie); + virtual void linkToDeath(android::sp deathRecipient, + uint64_t cookie) = 0; + + virtual Return getSensorsList( + ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) = 0; + + virtual Return setOperationMode(OperationMode mode) = 0; + + virtual Return activate(int32_t sensorHandle, bool enabled) = 0; + + virtual Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) = 0; + + virtual Return flush(int32_t sensorHandle) = 0; + + virtual Return injectSensorData(const Event& event) = 0; + + virtual Return registerDirectChannel(const SharedMemInfo& mem, + ISensors::registerDirectChannel_cb _hidl_cb) = 0; + + virtual Return unregisterDirectChannel(int32_t channelHandle) = 0; + + virtual Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, + RateLevel rate, + ISensors::configDirectReport_cb _hidl_cb) = 0; + + virtual Return poll(int32_t /* maxCount */, ISensors::poll_cb /* _hidl_cb */) { + // Enforce this method is never invoked as it should be overridden if it's meant to be used. + assert(false); + return Return(); } - Return activate(int32_t sensorHandle, bool enabled) { - return getSensors()->activate(sensorHandle, enabled); + virtual EventMessageQueueWrapperBase* getEventQueue() { return nullptr; } + + virtual Return initialize(const MQDescriptorSync& /* wakeLockDesc */, + const ::android::sp& /* callback */) { + // Enforce this method is never invoked as it should be overridden if it's meant to be used. + assert(false); + return Result::INVALID_OPERATION; } - - Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) { - return getSensors()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); - } - - Return flush(int32_t sensorHandle) { return getSensors()->flush(sensorHandle); } - - Return registerDirectChannel(const SharedMemInfo& mem, - V2_0::ISensors::registerDirectChannel_cb _hidl_cb) { - return getSensors()->registerDirectChannel(mem, _hidl_cb); - } - - Return unregisterDirectChannel(int32_t channelHandle) { - return getSensors()->unregisterDirectChannel(channelHandle); - } - - Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, - V2_0::ISensors::configDirectReport_cb _hidl_cb) { - return getSensors()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); - } - - Return setOperationMode(OperationMode mode) { - return getSensors()->setOperationMode(mode); - } - - private: - virtual V2_0::ISensors* getSensors() = 0; }; -class ISensorsWrapperV2_0 : public ISensorsWrapperBase { +template +class SensorsWrapperBase : public ISensorsWrapperBase { public: - typedef MessageQueue - EventMessageQueue; + SensorsWrapperBase(sp sensors) : mSensors(sensors){}; - ISensorsWrapperV2_0(sp& sensors) : mSensors(sensors) { - auto eventQueue = std::make_unique(MAX_RECEIVE_BUFFER_EVENT_COUNT, - true /* configureEventFlagWord */); - mEventQueue = std::make_unique(eventQueue); + void linkToDeath(android::sp deathRecipient, + uint64_t cookie) override { + mSensors->linkToDeath(deathRecipient, cookie); } - EventMessageQueueWrapperBase& getEventQueue() override { return *mEventQueue; } - - Return initialize( - const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback) override { - return mSensors->initialize(*mEventQueue->getDesc(), wakeLockDescriptor, sensorsCallback); - } - - Return getSensorsList(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override { - return getSensors()->getSensorsList( + virtual Return getSensorsList( + ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override { + return mSensors->getSensorsList( [&](const auto& list) { _hidl_cb(convertToNewSensorInfos(list)); }); } - Return injectSensorData(const V2_1::Event& event) override { + Return setOperationMode(OperationMode mode) override { + return mSensors->setOperationMode(mode); + } + + Return activate(int32_t sensorHandle, bool enabled) override { + return mSensors->activate(sensorHandle, enabled); + } + + Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) override { + return mSensors->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); + } + + Return flush(int32_t sensorHandle) override { return mSensors->flush(sensorHandle); } + + virtual Return injectSensorData(const Event& event) override { return mSensors->injectSensorData(convertToOldEvent(event)); } - private: - V2_0::ISensors* getSensors() override { return mSensors.get(); } + Return registerDirectChannel(const SharedMemInfo& mem, + ISensors::registerDirectChannel_cb _hidl_cb) override { + return mSensors->registerDirectChannel(mem, _hidl_cb); + } - sp mSensors; + Return unregisterDirectChannel(int32_t channelHandle) override { + return mSensors->unregisterDirectChannel(channelHandle); + } + + Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + ISensors::configDirectReport_cb _hidl_cb) override { + return mSensors->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); + } + + protected: + sp mSensors; +}; + +class ISensorsWrapperV1_0 : public SensorsWrapperBase { + public: + ISensorsWrapperV1_0(sp sensors) + : SensorsWrapperBase(sensors){}; + + bool supportsPolling() const override { return true; } + + bool supportsMessageQueues() const override { return false; } + + Return poll(int32_t maxCount, + hardware::sensors::V1_0::ISensors::poll_cb _hidl_cb) override { + return mSensors->poll(maxCount, _hidl_cb); + } +}; + +class ISensorsWrapperV2_0 : public SensorsWrapperBase { + public: + typedef MessageQueue<::android::hardware::sensors::V1_0::Event, + ::android::hardware::kSynchronizedReadWrite> + EventMessageQueue; + + ISensorsWrapperV2_0(sp sensors) + : SensorsWrapperBase(sensors) { + auto eventQueue = std::make_unique(MAX_RECEIVE_BUFFER_EVENT_COUNT, + true /* configureEventFlagWord */); + mEventQueue = std::make_unique(eventQueue); + }; + + bool supportsPolling() const override { return false; } + + bool supportsMessageQueues() const override { return true; } + + EventMessageQueueWrapperBase* getEventQueue() override { return mEventQueue.get(); } + + Return initialize(const MQDescriptorSync& wakeLockDesc, + const ::android::sp& callback) override { + return mSensors->initialize(*mEventQueue->getDesc(), wakeLockDesc, callback); + } + + private: std::unique_ptr mEventQueue; }; -class ISensorsWrapperV2_1 : public ISensorsWrapperBase { +class ISensorsWrapperV2_1 : public SensorsWrapperBase { public: - typedef MessageQueue - EventMessageQueue; + typedef MessageQueue EventMessageQueueV2_1; - ISensorsWrapperV2_1(sp& sensors) : mSensors(sensors) { - auto eventQueue = std::make_unique(MAX_RECEIVE_BUFFER_EVENT_COUNT, - true /* configureEventFlagWord */); + ISensorsWrapperV2_1(sp sensors) + : SensorsWrapperBase(sensors) { + auto eventQueue = std::make_unique( + MAX_RECEIVE_BUFFER_EVENT_COUNT, true /* configureEventFlagWord */); mEventQueue = std::make_unique(eventQueue); - } + }; - EventMessageQueueWrapperBase& getEventQueue() override { return *mEventQueue; } + bool supportsPolling() const override { return false; } - Return initialize( - const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback) override { - return mSensors->initialize_2_1(*mEventQueue->getDesc(), wakeLockDescriptor, - sensorsCallback); - } + bool supportsMessageQueues() const override { return true; } - Return getSensorsList(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override { + EventMessageQueueWrapperBase* getEventQueue() override { return mEventQueue.get(); } + + Return getSensorsList( + ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override { return mSensors->getSensorsList_2_1(_hidl_cb); } - Return injectSensorData(const V2_1::Event& event) override { + Return injectSensorData(const Event& event) override { return mSensors->injectSensorData_2_1(event); } - private: - V2_0::ISensors* getSensors() override { return mSensors.get(); } + Return initialize(const MQDescriptorSync& wakeLockDesc, + const ::android::sp& callback) override { + return mSensors->initialize_2_1(*mEventQueue->getDesc(), wakeLockDesc, callback); + } - sp mSensors; + private: std::unique_ptr mEventQueue; }; @@ -206,4 +279,4 @@ class NoOpSensorsCallback : public ISensorsCallback { } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSWRAPPER_H +#endif // ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSWRAPPER_H \ No newline at end of file diff --git a/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.cpp b/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.cpp index 2771d976df..a8c2513e9f 100644 --- a/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.cpp +++ b/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.cpp @@ -67,7 +67,7 @@ bool SensorsHidlEnvironmentV2_X::resetHal() { } EventFlag::deleteEventFlag(&mEventQueueFlag); - EventFlag::createEventFlag(mSensors->getEventQueue().getEventFlagWord(), &mEventQueueFlag); + EventFlag::createEventFlag(mSensors->getEventQueue()->getEventFlagWord(), &mEventQueueFlag); if (mEventQueueFlag == nullptr) { break; } @@ -124,18 +124,18 @@ void SensorsHidlEnvironmentV2_X::startPollingThread() { } void SensorsHidlEnvironmentV2_X::readEvents() { - size_t availableEvents = mSensors->getEventQueue().availableToRead(); + size_t availableEvents = mSensors->getEventQueue()->availableToRead(); if (availableEvents == 0) { uint32_t eventFlagState = 0; mEventQueueFlag->wait(asBaseType(EventQueueFlagBits::READ_AND_PROCESS), &eventFlagState); - availableEvents = mSensors->getEventQueue().availableToRead(); + availableEvents = mSensors->getEventQueue()->availableToRead(); } size_t eventsToRead = std::min(availableEvents, mEventBuffer.size()); if (eventsToRead > 0) { - if (mSensors->getEventQueue().read(mEventBuffer.data(), eventsToRead)) { + if (mSensors->getEventQueue()->read(mEventBuffer.data(), eventsToRead)) { mEventQueueFlag->wake(asBaseType(EventQueueFlagBits::EVENTS_READ)); for (size_t i = 0; i < eventsToRead; i++) { addEvent(mEventBuffer[i]); From 0a675fcc88fcaf1aee56e5dba32853782316ac94 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 14 Feb 2020 17:13:52 -0800 Subject: [PATCH 0604/1022] audio: Add Dual Mono Mode and Audio Description Mix Level to IStreamOut These properties are mainly used on TV platforms. Bug: 133526565 Test: atest VtsHalAudioV6_0TargetTest Change-Id: I5dd2fe9cb987bf8435b8e5da96f8590288e5707c --- audio/6.0/IStreamOut.hal | 57 +++++++++++++++++++ audio/6.0/types.hal | 50 ++++++++++++++++ audio/core/all-versions/default/StreamOut.cpp | 20 +++++++ .../default/include/core/default/StreamOut.h | 6 ++ .../6.0/AudioPrimaryHidlHalTest.cpp | 27 +++++++++ .../vts/functional/AudioPrimaryHidlHalTest.h | 41 ++++++++----- current.txt | 4 +- 7 files changed, 190 insertions(+), 15 deletions(-) diff --git a/audio/6.0/IStreamOut.hal b/audio/6.0/IStreamOut.hal index 941ba61006..91668ba452 100644 --- a/audio/6.0/IStreamOut.hal +++ b/audio/6.0/IStreamOut.hal @@ -276,4 +276,61 @@ interface IStreamOut extends IStream { */ selectPresentation(int32_t presentationId, int32_t programId) generates (Result retval); + + /** + * Returns the Dual Mono mode presentation setting. + * + * Optional method + * + * @return retval operation completion status. + * @return mode current setting of Dual Mono mode. + */ + getDualMonoMode() generates (Result retval, DualMonoMode mode); + + /** + * Sets the Dual Mono mode presentation on the output device. + * + * The Dual Mono mode is generally applied to stereo audio streams + * where the left and right channels come from separate sources. + * + * Optional method + * + * @param mode selected Dual Mono mode. + * @return retval operation completion status. + */ + setDualMonoMode(DualMonoMode mode) generates (Result retval); + + /** + * Returns the Audio Description Mix level in dB. + * + * The level is applied to streams incorporating a secondary Audio + * Description stream. It specifies the relative level of mixing for + * the Audio Description with a reference to the Main Audio. + * + * Optional method + * + * The value of the relative level is in the range from negative infinity + * to +48. + * + * @return retval operation completion status. + * @return leveldB the current Audio Description Mix Level in dB. + */ + getAudioDescriptionMixLevel() generates (Result retval, float leveldB); + + /** + * Sets the Audio Description Mix level in dB. + * + * For streams incorporating a secondary Audio Description stream + * the relative level of mixing of the Audio Description to the Main Audio + * is controlled by this method. + * + * Optional method + * + * The value of the relative level must be in the range from negative + * infinity to +48. + * + * @param leveldB Audio Description Mix Level in dB + * @return retval operation completion status. + */ + setAudioDescriptionMixLevel(float leveldB) generates (Result retval); }; diff --git a/audio/6.0/types.hal b/audio/6.0/types.hal index 1a704f8b32..efc3ea5750 100644 --- a/audio/6.0/types.hal +++ b/audio/6.0/types.hal @@ -247,3 +247,53 @@ enum MicrophoneDirection : int32_t { */ EXTERNAL = 3, }; + + +/* Dual Mono handling is used when a stereo audio stream + * contains separate audio content on the left and right channels. + * Such information about the content of the stream may be found, for example, + * in ITU T-REC-J.94-201610 A.6.2.3 Component descriptor. + */ +@export(name="audio_dual_mono_mode_t", value_prefix="AUDIO_DUAL_MONO_MODE_") +enum DualMonoMode : int32_t { + // Need to be in sync with DUAL_MONO_MODE* constants in + // frameworks/base/media/java/android/media/AudioTrack.java + /** + * Disable any Dual Mono presentation effect. + * + */ + OFF = 0, + /** + * This mode indicates that a stereo stream should be presented + * with the left and right audio channels blended together + * and delivered to both channels. + * + * Behavior for non-stereo streams is implementation defined. + * A suggested guideline is that the left-right stereo symmetric + * channels are pairwise blended, the other channels such as center + * are left alone. + */ + LR = 1, + /** + * This mode indicates that a stereo stream should be presented + * with the left audio channel replicated into the right audio channel. + * + * Behavior for non-stereo streams is implementation defined. + * A suggested guideline is that all channels with left-right + * stereo symmetry will have the left channel position replicated + * into the right channel position. The center channels (with no + * left/right symmetry) or unbalanced channels are left alone. + */ + LL = 2, + /** + * This mode indicates that a stereo stream should be presented + * with the right audio channel replicated into the left audio channel. + * + * Behavior for non-stereo streams is implementation defined. + * A suggested guideline is that all channels with left-right + * stereo symmetry will have the right channel position replicated + * into the left channel position. The center channels (with no + * left/right symmetry) or unbalanced channels are left alone. + */ + RR = 3, +}; diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp index 1a2a764297..cfbee34299 100644 --- a/audio/core/all-versions/default/StreamOut.cpp +++ b/audio/core/all-versions/default/StreamOut.cpp @@ -582,6 +582,26 @@ Return StreamOut::selectPresentation(int32_t /*presentationId*/, int32_t } #endif +#if MAJOR_VERSION >= 6 +Return StreamOut::getDualMonoMode(getDualMonoMode_cb _hidl_cb) { + _hidl_cb(Result::NOT_SUPPORTED, DualMonoMode::OFF); + return Void(); +} + +Return StreamOut::setDualMonoMode(DualMonoMode /*mode*/) { + return Result::NOT_SUPPORTED; +} + +Return StreamOut::getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb) { + _hidl_cb(Result::NOT_SUPPORTED, -std::numeric_limits::infinity()); + return Void(); +} + +Return StreamOut::setAudioDescriptionMixLevel(float /*leveldB*/) { + return Result::NOT_SUPPORTED; +} +#endif + } // namespace implementation } // namespace CPP_VERSION } // namespace audio diff --git a/audio/core/all-versions/default/include/core/default/StreamOut.h b/audio/core/all-versions/default/include/core/default/StreamOut.h index 6334785a03..294867c9ed 100644 --- a/audio/core/all-versions/default/include/core/default/StreamOut.h +++ b/audio/core/all-versions/default/include/core/default/StreamOut.h @@ -121,6 +121,12 @@ struct StreamOut : public IStreamOut { Return updateSourceMetadata(const SourceMetadata& sourceMetadata) override; Return selectPresentation(int32_t presentationId, int32_t programId) override; #endif +#if MAJOR_VERSION >= 6 + Return getDualMonoMode(getDualMonoMode_cb _hidl_cb) override; + Return setDualMonoMode(DualMonoMode mode) override; + Return getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb) override; + Return setAudioDescriptionMixLevel(float leveldB) override; +#endif static Result getPresentationPositionImpl(audio_stream_out_t* stream, uint64_t* frames, TimeSpec* timeStamp); diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp index 09ef330be6..c9ba509d30 100644 --- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp @@ -190,3 +190,30 @@ TEST_P(AudioPatchHidlTest, UpdatePatchInvalidHandle) { hidl_vec(), hidl_vec(), returnIn(res, ignored))); ASSERT_RESULT(Result::INVALID_ARGUMENTS, res); } + +using DualMonoModeAccessorHidlTest = AccessorHidlTest; +TEST_P(DualMonoModeAccessorHidlTest, DualMonoModeTest) { + doc::test("Check that dual mono mode can be set and retrieved"); + testAccessors(&OutputStreamTest::getStream, "dual mono mode", + Initial{DualMonoMode::OFF}, + {DualMonoMode::LR, DualMonoMode::LL, DualMonoMode::RR}, + &IStreamOut::setDualMonoMode, &IStreamOut::getDualMonoMode); +} + +INSTANTIATE_TEST_CASE_P(DualMonoModeHidl, DualMonoModeAccessorHidlTest, + ::testing::ValuesIn(getOutputDeviceConfigParameters()), + &DeviceConfigParameterToString); + +using AudioDescriptionMixLevelHidlTest = AccessorHidlTest; +TEST_P(AudioDescriptionMixLevelHidlTest, AudioDescriptionMixLevelTest) { + doc::test("Check that audio description mix level can be set and retrieved"); + testAccessors( + &OutputStreamTest::getStream, "audio description mix level", + Initial{-std::numeric_limits::infinity()}, {-48.0f, -1.0f, 0.0f, 1.0f, 48.0f}, + &IStreamOut::setAudioDescriptionMixLevel, &IStreamOut::getAudioDescriptionMixLevel, + {48.5f, 1000.0f, std::numeric_limits::infinity()}); +} + +INSTANTIATE_TEST_CASE_P(AudioDescriptionMixLevelHidl, AudioDescriptionMixLevelHidlTest, + ::testing::ValuesIn(getOutputDeviceConfigParameters()), + &DeviceConfigParameterToString); diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h index d0d39e8683..b77aec9208 100644 --- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -140,6 +140,11 @@ using HidlTestBase = ::testing::Test; class HidlTest : public HidlTestBase { public: virtual ~HidlTest() = default; + // public access to avoid annoyances when using this method in template classes + // derived from test classes + sp getDevice() const { + return DeviceManager::getInstance().get(getFactoryName(), getDeviceName()); + } protected: // Factory and device name getters to be overridden in subclasses. @@ -149,9 +154,6 @@ class HidlTest : public HidlTestBase { sp getDevicesFactory() const { return DevicesFactoryManager::getInstance().get(getFactoryName()); } - sp getDevice() const { - return DeviceManager::getInstance().get(getFactoryName(), getDeviceName()); - } bool resetDevice() const { return DeviceManager::getInstance().reset(getFactoryName(), getDeviceName()); } @@ -419,7 +421,8 @@ class AudioPrimaryHidlTest : public AudioHidlDeviceTest { ASSERT_TRUE(getDevice() != nullptr); } - protected: + // public access to avoid annoyances when using this method in template classes + // derived from test classes sp getDevice() const { return DeviceManager::getInstance().getPrimary(getFactoryName()); } @@ -450,15 +453,15 @@ class AccessorHidlTest : public BaseTestClass { /** Test a property getter and setter. * The getter and/or the setter may return NOT_SUPPORTED if optionality == OPTIONAL. */ - template - void testAccessors(const string& propertyName, const Initial expectedInitial, - list valuesToTest, Setter setter, Getter getter, - const vector& invalidValues = {}) { + template + void testAccessors(IUTGetter iutGetter, const string& propertyName, + const Initial expectedInitial, list valuesToTest, Setter setter, + Getter getter, const vector& invalidValues = {}) { const auto expectedResults = {Result::OK, optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK}; Property initialValue = expectedInitial.value; - ASSERT_OK((BaseTestClass::getDevice().get()->*getter)(returnIn(res, initialValue))); + ASSERT_OK(((this->*iutGetter)().get()->*getter)(returnIn(res, initialValue))); ASSERT_RESULT(expectedResults, res); if (res == Result::OK && expectedInitial.check == REQUIRED) { EXPECT_EQ(expectedInitial.value, initialValue); @@ -469,7 +472,7 @@ class AccessorHidlTest : public BaseTestClass { for (Property setValue : valuesToTest) { SCOPED_TRACE("Test " + propertyName + " getter and setter for " + testing::PrintToString(setValue)); - auto ret = (BaseTestClass::getDevice().get()->*setter)(setValue); + auto ret = ((this->*iutGetter)().get()->*setter)(setValue); ASSERT_RESULT(expectedResults, ret); if (ret == Result::NOT_SUPPORTED) { doc::partialTest(propertyName + " setter is not supported"); @@ -477,7 +480,7 @@ class AccessorHidlTest : public BaseTestClass { } Property getValue; // Make sure the getter returns the same value just set - ASSERT_OK((BaseTestClass::getDevice().get()->*getter)(returnIn(res, getValue))); + ASSERT_OK(((this->*iutGetter)().get()->*getter)(returnIn(res, getValue))); ASSERT_RESULT(expectedResults, res); if (res == Result::NOT_SUPPORTED) { doc::partialTest(propertyName + " getter is not supported"); @@ -490,11 +493,18 @@ class AccessorHidlTest : public BaseTestClass { SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " + testing::PrintToString(invalidValue)); EXPECT_RESULT(invalidArgsOrNotSupported, - (BaseTestClass::getDevice().get()->*setter)(invalidValue)); + ((this->*iutGetter)().get()->*setter)(invalidValue)); } // Restore initial value - EXPECT_RESULT(expectedResults, (BaseTestClass::getDevice().get()->*setter)(initialValue)); + EXPECT_RESULT(expectedResults, ((this->*iutGetter)().get()->*setter)(initialValue)); + } + template + void testAccessors(const string& propertyName, const Initial expectedInitial, + list valuesToTest, Setter setter, Getter getter, + const vector& invalidValues = {}) { + testAccessors(&BaseTestClass::getDevice, propertyName, expectedInitial, + valuesToTest, setter, getter, invalidValues); } }; @@ -872,6 +882,11 @@ class StreamHelper { template class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter { + public: + // public access to avoid annoyances when using this method in template classes + // derived from test classes + sp getStream() const { return stream; } + protected: OpenStreamTest() : AudioHidlTestWithDeviceConfigParameter(), helper(stream) {} template diff --git a/current.txt b/current.txt index 29e95fe7ab..f1245c2a92 100644 --- a/current.txt +++ b/current.txt @@ -605,13 +605,13 @@ ff5dd821c2c7a9c78607159c4d788960b725487263c49d956ca5fa3d37008b45 android.hardwar 5751f230e86a36111e7c5b995577cbf89d8df76c8e6c7641199198f3db3a93f7 android.hardware.wifi@1.3::IWifiStaIface # HALs released in Android R -e966a3437d6a98d9d9e14e9d672088771716031900c0deb55a0946c751a03a44 android.hardware.audio@6.0::types +6cc7fee7bbb7b34e3b8fe75526600400e51d18fe948419d88f294d76b6a4d921 android.hardware.audio@6.0::types 7241bd4596a927cd46d4b82f5e29e2cbe57f194aa1b25555f1d1d352e8b15c61 android.hardware.audio@6.0::IDevice 2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice fd1f1b29f26b42e886220f04a08086c00e5ade9d7b53f095438e578ab9d42a93 android.hardware.audio@6.0::IStream 2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn -78e4138cc8307c11fc777c3bd376e581ba4ba48196b05ca1d7cdfa515c87b48a android.hardware.audio@6.0::IStreamOut +0d0bbac03e90b18cbf0d1930b89d0c64e41dd2f0d68b652f7ed08347cf5f5f77 android.hardware.audio@6.0::IStreamOut 997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback 167ed5cfb7d91db2e2bf20f1320c1a9004eeb768e26f535e0f7db94a21867d21 android.hardware.audio.common@6.0::types 817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types From 935047e1375a475e3e4db077e73f5becaa18fee0 Mon Sep 17 00:00:00 2001 From: Sasha Kuznetsov Date: Tue, 18 Feb 2020 22:30:16 -0800 Subject: [PATCH 0605/1022] Update getExtensionX HAL docs Test: hidl-gen -Lcheck android.hardware.gnss@2.1 Bug:147614118 Change-Id: Icc2453847519e449f753dc68bedc00c1c92e6744 --- current.txt | 2 +- gnss/2.1/IGnss.hal | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/current.txt b/current.txt index f6659e3273..d4a1e87d9e 100644 --- a/current.txt +++ b/current.txt @@ -648,7 +648,7 @@ f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardwar 446287268831f4ddfac4a51bb1c32ae1e48e47bccd535fccc2c4546d0e7c4013 android.hardware.dumpstate@1.1::types f284ffde7cadf5a1364b75ab313baf22401eeca289bdde2a2dc7a27ea4ab98d7 android.hardware.dumpstate@1.1::IDumpstateDevice 769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types -626db710bf917ecf551a0b0b1f25be10bf52758f43e0fc808b148b6aae2ef73e android.hardware.gnss@2.1::IGnss +c319e68b03829958404402c2d9c682019678087d60495807c0a7444e0a6af981 android.hardware.gnss@2.1::IGnss ba5ac712b2a656dc07c83ab4a7a2c2f3bee1bbcb752e8b8ffa9b672f3b5b0728 android.hardware.gnss@2.1::IGnssAntennaInfo 0bc3ed97cbc3f6abc89c68f4e9f4d124f9f723431997dc88c2186cf4d2ad47ee android.hardware.gnss@2.1::IGnssAntennaInfoCallback 50c5d009af76d65b3023a9d94ee519545e72cb7c59bc7166d768d6f00923774d android.hardware.gnss@2.1::IGnssCallback diff --git a/gnss/2.1/IGnss.hal b/gnss/2.1/IGnss.hal index e4da5078ee..a880b3fd2a 100644 --- a/gnss/2.1/IGnss.hal +++ b/gnss/2.1/IGnss.hal @@ -45,9 +45,9 @@ interface IGnss extends @2.0::IGnss { /** * This method returns the IGnssMeasurement interface. * - * At least one of getExtensionGnssMeasurement(), getExtensionGnssMeasurement_1_1(), + * getExtensionGnssMeasurement(), getExtensionGnssMeasurement_1_1(), * getExtensionGnssMeasurement_2_0(), and getExtensionGnssMeasurement_2_1() methods must return - * a non-null handle, and the other methods must return nullptr. + * non-null. They can all return the same, latest version of IGnssMeasurement. * * @return gnssMeasurementIface Handle to the IGnssMeasurement interface. */ @@ -56,9 +56,9 @@ interface IGnss extends @2.0::IGnss { /** * This method returns the IGnssConfiguration interface. * - * At least one of getExtensionGnssConfiguration(), getExtensionGnssConfiguration_1_1(), + * getExtensionGnssConfiguration(), getExtensionGnssConfiguration_1_1(), * getExtensionGnssConfiguration_2_0(), and getExtensionGnssConfiguration_2_1() methods must - * return a non-null handle, and the other methods must return nullptr. + * return non-null. They can all return the same, latest version of IGnssConfiguration. * * @return gnssConfigurationIface Handle to the IGnssConfiguration interface. */ From cc873aee8fb7921aa56e8528e9fe8cb0cdc3a0ba Mon Sep 17 00:00:00 2001 From: Slava Shklyaev Date: Tue, 18 Feb 2020 16:11:32 +0000 Subject: [PATCH 0606/1022] Add NNAPI loop timeout VTS test Fix: 149554639 Bug: 145906499 Bug: 136735929 Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: I642772d3c00c12d72380598d9d86743706179d72 --- .../vts/functional/GeneratedTestHarness.cpp | 66 +++++++++++++++---- .../1.3/vts/functional/GeneratedTestHarness.h | 4 +- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 89edfb713c..b04abe219b 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -74,7 +74,7 @@ namespace { enum class Executor { ASYNC, SYNC, BURST, FENCED }; -enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; +enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT, MISSED_DEADLINE }; enum class MemoryType { SHARED, DEVICE }; @@ -495,16 +495,18 @@ static std::vector getOutputBuffers(const TestModel& testModel, cons static Return ExecutePreparedModel(const sp& preparedModel, const Request& request, MeasureTiming measure, + const OptionalTimeoutDuration& loopTimeoutDuration, sp& callback) { - return preparedModel->execute_1_3(request, measure, {}, {}, callback); + return preparedModel->execute_1_3(request, measure, {}, loopTimeoutDuration, callback); } static Return ExecutePreparedModel(const sp& preparedModel, const Request& request, MeasureTiming measure, + const OptionalTimeoutDuration& loopTimeoutDuration, hidl_vec* outputShapes, Timing* timing) { ErrorStatus result; Return ret = preparedModel->executeSynchronously_1_3( - request, measure, {}, {}, + request, measure, {}, loopTimeoutDuration, [&result, outputShapes, timing](ErrorStatus error, const hidl_vec& shapes, const Timing& time) { result = error; @@ -545,6 +547,17 @@ void EvaluatePreparedModel(const sp& device, const sp& makeOutputInsufficientSize(/*outputIndex=*/0, &request); } + OptionalTimeoutDuration loopTimeoutDuration; + // OutputType::MISSED_DEADLINE is only used by + // TestKind::INTINITE_LOOP_TIMEOUT tests to verify that an infinite loop is + // aborted after a timeout. + if (testConfig.outputType == OutputType::MISSED_DEADLINE) { + // Override the default loop timeout duration with a small value to + // speed up test execution. + constexpr uint64_t kMillisecond = 1'000'000; + loopTimeoutDuration.nanoseconds(1 * kMillisecond); + } + ErrorStatus executionStatus; hidl_vec outputShapes; Timing timing; @@ -554,8 +567,9 @@ void EvaluatePreparedModel(const sp& device, const sp& // launch execution sp executionCallback = new ExecutionCallback(); - Return executionLaunchStatus = ExecutePreparedModel( - preparedModel, request, testConfig.measureTiming, executionCallback); + Return executionLaunchStatus = + ExecutePreparedModel(preparedModel, request, testConfig.measureTiming, + loopTimeoutDuration, executionCallback); ASSERT_TRUE(executionLaunchStatus.isOk()); EXPECT_EQ(ErrorStatus::NONE, static_cast(executionLaunchStatus)); @@ -571,8 +585,9 @@ void EvaluatePreparedModel(const sp& device, const sp& SCOPED_TRACE("synchronous"); // execute - Return executionReturnStatus = ExecutePreparedModel( - preparedModel, request, testConfig.measureTiming, &outputShapes, &timing); + Return executionReturnStatus = + ExecutePreparedModel(preparedModel, request, testConfig.measureTiming, + loopTimeoutDuration, &outputShapes, &timing); ASSERT_TRUE(executionReturnStatus.isOk()); executionStatus = static_cast(executionReturnStatus); @@ -612,7 +627,7 @@ void EvaluatePreparedModel(const sp& device, const sp& hidl_handle syncFenceHandle; sp fencedCallback; Return ret = preparedModel->executeFenced( - request, {}, testConfig.measureTiming, {}, {}, {}, + request, {}, testConfig.measureTiming, {}, loopTimeoutDuration, {}, [&result, &syncFenceHandle, &fencedCallback]( ErrorStatus error, const hidl_handle& handle, const sp& callback) { @@ -686,6 +701,11 @@ void EvaluatePreparedModel(const sp& device, const sp& ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size()); ASSERT_FALSE(outputShapes[0].isSufficient); return; + case OutputType::MISSED_DEADLINE: + ASSERT_TRUE(executionStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT || + executionStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT) + << "executionStatus = " << executionStatus; + return; } // Go through all outputs, check returned output shapes. @@ -736,6 +756,12 @@ void EvaluatePreparedModel(const sp& device, const sp& LOG(FATAL) << "Wrong TestKind for EvaluatePreparedModel"; return; } break; + case TestKind::INTINITE_LOOP_TIMEOUT: { + outputTypesList = {OutputType::MISSED_DEADLINE}; + measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; + // Burst does not support V1_3 loop timeout. + executorList = {Executor::ASYNC, Executor::SYNC, Executor::FENCED}; + } break; } for (const OutputType outputType : outputTypesList) { @@ -794,7 +820,8 @@ void Execute(const sp& device, const TestModel& testModel, TestKind tes case TestKind::GENERAL: case TestKind::DYNAMIC_SHAPE: case TestKind::MEMORY_DOMAIN: - case TestKind::FENCED_COMPUTE: { + case TestKind::FENCED_COMPUTE: + case TestKind::INTINITE_LOOP_TIMEOUT: { createPreparedModel(device, model, &preparedModel); if (preparedModel == nullptr) return; EvaluatePreparedModel(device, preparedModel, testModel, testKind); @@ -863,24 +890,31 @@ class FencedComputeTest : public GeneratedTest {}; // Tag for the dynamic output shape tests class QuantizationCouplingTest : public GeneratedTest {}; +// Tag for the loop timeout tests +class InfiniteLoopTimeoutTest : public GeneratedTest {}; + TEST_P(GeneratedTest, Test) { - Execute(kDevice, kTestModel, /*testKind=*/TestKind::GENERAL); + Execute(kDevice, kTestModel, TestKind::GENERAL); } TEST_P(DynamicOutputShapeTest, Test) { - Execute(kDevice, kTestModel, /*testKind=*/TestKind::DYNAMIC_SHAPE); + Execute(kDevice, kTestModel, TestKind::DYNAMIC_SHAPE); } TEST_P(MemoryDomainTest, Test) { - Execute(kDevice, kTestModel, /*testKind=*/TestKind::MEMORY_DOMAIN); + Execute(kDevice, kTestModel, TestKind::MEMORY_DOMAIN); } TEST_P(FencedComputeTest, Test) { - Execute(kDevice, kTestModel, /*testKind=*/TestKind::FENCED_COMPUTE); + Execute(kDevice, kTestModel, TestKind::FENCED_COMPUTE); } TEST_P(QuantizationCouplingTest, Test) { - Execute(kDevice, kTestModel, /*testKind=*/TestKind::QUANTIZATION_COUPLING); + Execute(kDevice, kTestModel, TestKind::QUANTIZATION_COUPLING); +} + +TEST_P(InfiniteLoopTimeoutTest, Test) { + Execute(kDevice, kTestModel, TestKind::INTINITE_LOOP_TIMEOUT); } INSTANTIATE_GENERATED_TEST(GeneratedTest, @@ -900,4 +934,8 @@ INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testMod return testModel.hasQuant8CoupledOperands() && testModel.main.operations.size() == 1; }); +INSTANTIATE_GENERATED_TEST(InfiniteLoopTimeoutTest, [](const TestModel& testModel) { + return testModel.isInfiniteLoopTimeoutTest(); +}); + } // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h index e597fac7cf..a8db5155b5 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h @@ -70,7 +70,9 @@ enum class TestKind { // Tests if quantized model with TENSOR_QUANT8_ASYMM produces the same result // (OK/SKIPPED/FAILED) as the model with all such tensors converted to // TENSOR_QUANT8_ASYMM_SIGNED. - QUANTIZATION_COUPLING + QUANTIZATION_COUPLING, + // Runs a test model and verifies that MISSED_DEADLINE_* is returned. + INTINITE_LOOP_TIMEOUT }; void EvaluatePreparedModel(const sp& device, const sp& preparedModel, From aef69c9538c7e7101604e042be947e31217844ef Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Wed, 19 Feb 2020 12:43:57 -0500 Subject: [PATCH 0607/1022] Create separate VTS target for Sensors HAL 2.1 Dependencies don't use cflags set by code that depends on them so the VTS test for HAL 2.1 wasn't properly pulling the 2.1 interface when present on the device (it was using the 2.0 interface). Modify the Android.bp files to define the right flags depending on whether we're testing HAL 2.0 or 2.1. Bug: 149759782 Test: atest VtsHalSensorsV2_0TargetTest VtsHalSensorsV2_1TargetTest Change-Id: I3533b6c244e767a8defe0a44a14025fdeb8eeeba --- sensors/2.0/vts/functional/Android.bp | 2 +- sensors/2.1/vts/functional/Android.bp | 3 +-- sensors/common/vts/2_X/Android.bp | 15 +++++++++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/sensors/2.0/vts/functional/Android.bp b/sensors/2.0/vts/functional/Android.bp index 22a5091a67..08c59b6378 100644 --- a/sensors/2.0/vts/functional/Android.bp +++ b/sensors/2.0/vts/functional/Android.bp @@ -36,7 +36,7 @@ cc_test { "android.hardware.sensors@2.1", "libfmq", "VtsHalSensorsTargetTestUtils", - "VtsHalSensorsV2_XTargetTest", + "VtsHalSensorsV2_0TargetTest-lib", ], test_suites: [ "general-tests", diff --git a/sensors/2.1/vts/functional/Android.bp b/sensors/2.1/vts/functional/Android.bp index c92bab3373..c4f5e9d2d7 100644 --- a/sensors/2.1/vts/functional/Android.bp +++ b/sensors/2.1/vts/functional/Android.bp @@ -18,7 +18,6 @@ cc_test { name: "VtsHalSensorsV2_1TargetTest", cflags: [ "-DLOG_TAG=\"sensors_hidl_hal_test\"", - "-DSENSORS_HAL_2_1", ], defaults: ["VtsHalTargetTestDefaults"], srcs: [ @@ -39,7 +38,7 @@ cc_test { "android.hardware.sensors@2.1", "libfmq", "VtsHalSensorsTargetTestUtils", - "VtsHalSensorsV2_XTargetTest", + "VtsHalSensorsV2_1TargetTest-lib", ], test_suites: [ "general-tests", diff --git a/sensors/common/vts/2_X/Android.bp b/sensors/common/vts/2_X/Android.bp index 8cf14866c5..8cdb5d181a 100644 --- a/sensors/common/vts/2_X/Android.bp +++ b/sensors/common/vts/2_X/Android.bp @@ -14,8 +14,8 @@ // limitations under the License. // -cc_test_library { - name: "VtsHalSensorsV2_XTargetTest", +cc_defaults { + name: "VtsHalSensorsV2_XTargetTest-defaults", cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""], defaults: ["VtsHalTargetTestDefaults"], srcs: [ @@ -42,3 +42,14 @@ cc_test_library { "VtsHalSensorsTargetTestUtils", ], } + +cc_test_library { + name: "VtsHalSensorsV2_0TargetTest-lib", + defaults: ["VtsHalSensorsV2_XTargetTest-defaults"], +} + +cc_test_library { + name: "VtsHalSensorsV2_1TargetTest-lib", + cflags: ["-DSENSORS_HAL_2_1"], + defaults: ["VtsHalSensorsV2_XTargetTest-defaults"], +} From 9b9a804fe4c3394e04025d3646328c1f975e26bd Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Thu, 13 Feb 2020 16:37:22 -0800 Subject: [PATCH 0608/1022] Relax NNAPI QoS deadline parameter Prior to this CL, the NNAPI QoS deadline is a strict deadline: a task with a deadline must either complete or abort by the deadline. To avoid as much overhead as possible, it is requested for Android R to have a relaxed deadline, where the task *may* be aborted after the deadline has passed or when the task is estimated to take too long. Because the deadline is now relaxed, the querying method IDevice::supportsDeadlines can be removed. Bug: 149766387 Test: mma Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: Ib9937b5bb95646c2fd82e1aa17f2b0b639e2c420 --- current.txt | 10 +- neuralnetworks/1.3/IDevice.hal | 50 +++----- neuralnetworks/1.3/IExecutionCallback.hal | 3 +- .../1.3/IFencedExecutionCallback.hal | 4 +- neuralnetworks/1.3/IPreparedModel.hal | 66 ++++------ neuralnetworks/1.3/IPreparedModelCallback.hal | 4 +- .../vts/functional/GeneratedTestHarness.cpp | 6 - .../1.3/vts/functional/GeneratedTestHarness.h | 1 - .../vts/functional/QualityOfServiceTests.cpp | 116 ++++++++++-------- .../1.3/vts/functional/ValidateModel.cpp | 32 +---- .../1.3/vts/functional/ValidateRequest.cpp | 30 +---- .../vts/functional/VtsHalNeuralnetworks.cpp | 24 ++-- 12 files changed, 140 insertions(+), 206 deletions(-) diff --git a/current.txt b/current.txt index 8d14fa3609..8dfe34e685 100644 --- a/current.txt +++ b/current.txt @@ -673,11 +673,11 @@ ddcf89cd8ee2df0d32aee55050826446fb64f7aafde0a7cd946c64f61b1a364c android.hardwar df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore 65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer -9db064ee44268a876be0367ff771e618362d39ec603b6ecab17e1575725fcd87 android.hardware.neuralnetworks@1.3::IDevice -4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback -2fa3679ad7c94b5e88724adcd560c561041068a4ca565c63830e68101988746a android.hardware.neuralnetworks@1.3::IFencedExecutionCallback -43088ffc71945b463a7279262cfe2e290f6ed2f15d3fd6032798a3be299fb08f android.hardware.neuralnetworks@1.3::IPreparedModel -0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback +278817920bfd5292a7713f97f1832cca53de3de640f7670e413d97c6e7fd581c android.hardware.neuralnetworks@1.3::IDevice +127ba11efb8220dc3aec9a8f441b59eaf1c68d7f03f577833e1824de75a36b17 android.hardware.neuralnetworks@1.3::IExecutionCallback +6e904be0ddca5ae1de8eba020e6c38ed935ea7d80cd08f47787f137a0ca58555 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback +2b0b10d2ea7a18a4048cd0eb83d35c19a817aeee95f65807fc31f4ef21381397 android.hardware.neuralnetworks@1.3::IPreparedModel +eee3430cc86c97c7b407495863d8fb61da6f1a64b7721e77b9b4909b11b174e9 android.hardware.neuralnetworks@1.3::IPreparedModelCallback dd39887aa4fb60ce60ea9cc043edeadbbae6e922d09d3946311b0b410024ae14 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd diff --git a/neuralnetworks/1.3/IDevice.hal b/neuralnetworks/1.3/IDevice.hal index 79f9c325ac..e0b04a8b62 100644 --- a/neuralnetworks/1.3/IDevice.hal +++ b/neuralnetworks/1.3/IDevice.hal @@ -47,19 +47,6 @@ interface IDevice extends @1.2::IDevice { */ getCapabilities_1_3() generates (ErrorStatus status, Capabilities capabilities); - /** - * Returns whether the device is able to complete or abort a task within a - * specified duration. - * - * @return prepareModelDeadline 'true' if the device supports completing or - * aborting model preparation by the deadline when the deadline is supplied, - * 'false' otherwise. - * @return executionDeadline 'true' if the device supports completing or - * aborting an execution by the deadline when the deadline is supplied, - * 'false' otherwise. - */ - supportsDeadlines() generates (bool prepareModelDeadline, bool executionDeadline); - /** * Gets the supported operations in a model. * @@ -140,14 +127,10 @@ interface IDevice extends @1.2::IDevice { * * prepareModel_1_3 can be called with an optional deadline. If the model * is not able to be prepared before the provided deadline, the model - * preparation must be aborted, and either {@link + * preparation may be aborted, and either {@link * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link - * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due + * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due * to an abort must be sent the same way as other errors, described above. - * If the service reports that it does not support preparation deadlines via - * IDevice::supportsDeadlines, and prepareModel_1_3 is called with a - * deadline, then the argument is invalid, and {@link - * ErrorStatus::INVALID_ARGUMENT} must be returned. * * Optionally, the driver may save the prepared model to cache during the * asynchronous preparation. Any error that occurs when saving to cache must @@ -172,9 +155,9 @@ interface IDevice extends @1.2::IDevice { * model. * @param priority The priority of the prepared model relative to other * prepared models owned by the client. - * @param deadline The time by which the model must be prepared. If the - * model cannot be prepared by the deadline, the preparation must be - * aborted. + * @param deadline The time by which the model is expected to be prepared. + * If the model cannot be prepared by the deadline, the preparation may + * be aborted. * @param modelCache A vector of handles with each entry holding exactly one * cache file descriptor for the security-sensitive cache. The length of * the vector must either be 0 indicating that caching information is @@ -209,8 +192,8 @@ interface IDevice extends @1.2::IDevice { * - GENERAL_FAILURE if there is an unspecified error * - INVALID_ARGUMENT if one of the input arguments related to preparing * the model is invalid - * - MISSED_DEADLINE_* if the deadline for preparing a model cannot be - * met + * - MISSED_DEADLINE_* if the preparation is aborted because the model + * cannot be prepared by the deadline * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver */ prepareModel_1_3(Model model, ExecutionPreference preference, @@ -262,14 +245,11 @@ interface IDevice extends @1.2::IDevice { * * prepareModelFromCache_1_3 can be called with an optional deadline. If the * model is not able to prepared before the provided deadline, the model - * preparation must be aborted, and either {@link + * preparation may be aborted, and either {@link * ErrorStatus::MISSED_DEADLINE_TRANSIENT} - * or {@link ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The + * or {@link ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The * error due to an abort must be sent the same way as other errors, - * described above. If the service reports that it does not support - * preparation deadlines via IDevice::supportsDeadlines, and - * prepareModelFromCache_1_3 is called with a deadline, then the argument is - * invalid, and {@link ErrorStatus::INVALID_ARGUMENT} must be returned. + * described above. * * The only information that may be unknown to the model at this stage is * the shape of the tensors, which may only be known at execution time. As @@ -279,9 +259,9 @@ interface IDevice extends @1.2::IDevice { * used with different shapes of inputs on different (possibly concurrent) * executions. * - * @param deadline The time by which the model must be prepared. If the - * model cannot be prepared by the deadline, the preparation must be - * aborted. + * @param deadline The time by which the model is expected to be prepared. + * If the model cannot be prepared by the deadline, the preparation may + * be aborted. * @param modelCache A vector of handles with each entry holding exactly one * cache file descriptor for the security-sensitive cache. The length of * the vector must match the numModelCache returned from getNumberOfCacheFilesNeeded. @@ -307,8 +287,8 @@ interface IDevice extends @1.2::IDevice { * - GENERAL_FAILURE if caching is not supported or if there is an * unspecified error * - INVALID_ARGUMENT if one of the input arguments is invalid - * - MISSED_DEADLINE_* if the deadline for preparing a model cannot be - * met + * - MISSED_DEADLINE_* if the preparation is aborted because the model + * cannot be prepared by the deadline * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver */ prepareModelFromCache_1_3(OptionalTimePoint deadline, diff --git a/neuralnetworks/1.3/IExecutionCallback.hal b/neuralnetworks/1.3/IExecutionCallback.hal index 439428a5aa..ea11b17c49 100644 --- a/neuralnetworks/1.3/IExecutionCallback.hal +++ b/neuralnetworks/1.3/IExecutionCallback.hal @@ -47,7 +47,8 @@ interface IExecutionCallback extends @1.2::IExecutionCallback { * corresponding output * - INVALID_ARGUMENT if one of the input arguments to * prepareModel is invalid - * - MISSED_DEADLINE_* if the deadline could not be met + * - MISSED_DEADLINE_* if the execution is aborted because it + * cannot be completed by the deadline * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver * @param outputShapes A list of shape information of model output operands. * The index into "outputShapes" corresponds with to index diff --git a/neuralnetworks/1.3/IFencedExecutionCallback.hal b/neuralnetworks/1.3/IFencedExecutionCallback.hal index 6030809406..949438e148 100644 --- a/neuralnetworks/1.3/IFencedExecutionCallback.hal +++ b/neuralnetworks/1.3/IFencedExecutionCallback.hal @@ -38,8 +38,8 @@ interface IFencedExecutionCallback { * - DEVICE_UNAVAILABLE if driver is offline or busy * - GENERAL_FAILURE if the asynchronous task resulted in an * unspecified error - * - MISSED_DEADLINE_* if the deadline for executing a model - * cannot be met + * - MISSED_DEADLINE_* if the execution is aborted because it + * cannot be completed by the deadline * - RESOURCE_EXHAUSTED_* if the task was aborted by the * driver * @return timingLaunched The duration starts when executeFenced is called and ends when diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal index 4ce3691d14..a1814b5156 100644 --- a/neuralnetworks/1.3/IPreparedModel.hal +++ b/neuralnetworks/1.3/IPreparedModel.hal @@ -70,14 +70,10 @@ interface IPreparedModel extends @1.2::IPreparedModel { * * execute_1_3 can be called with an optional deadline. If the execution * is not able to be completed before the provided deadline, the execution - * must be aborted, and either {@link + * may be aborted, and either {@link * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link - * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due + * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due * to an abort must be sent the same way as other errors, described above. - * If the service reports that it does not support execution deadlines via - * IDevice::supportsDeadlines, and execute_1_3 is called with a deadline, - * then the argument is invalid, and {@link ErrorStatus::INVALID_ARGUMENT} - * must be returned. * * Any number of calls to the execute* and executeSynchronously* functions, * in any combination, may be made concurrently, even on the same @@ -89,9 +85,9 @@ interface IPreparedModel extends @1.2::IPreparedModel { * The duration runs from the time the driver sees the call * to the execute_1_3 function to the time the driver invokes * the callback. - * @param deadline The time by which the execution must complete. If the - * execution cannot be finished by the deadline, the - * execution must be aborted. + * @param deadline The time by which the execution is expected to complete. + * If the execution cannot be completed by the deadline, the + * execution may be aborted. * @param loopTimeoutDuration The maximum amount of time that should be spent * executing a {@link OperationType::WHILE} * operation. If a loop condition model does not @@ -116,8 +112,8 @@ interface IPreparedModel extends @1.2::IPreparedModel { * not large enough to store the resultant values * - INVALID_ARGUMENT if one of the input arguments is * invalid - * - MISSED_DEADLINE_* if the deadline for executing a model - * cannot be met + * - MISSED_DEADLINE_* if the execution is aborted because it + * cannot be completed by the deadline * - RESOURCE_EXHAUSTED_* if the task was aborted by the * driver */ @@ -150,16 +146,12 @@ interface IPreparedModel extends @1.2::IPreparedModel { * (ErrorStatus::NONE): There must be no failure unless the device itself is * in a bad state. * - * executeSynchronously_1_3 can be called with an optional deadline. If the + * executeSynchronously_1_3 may be called with an optional deadline. If the * execution is not able to be completed before the provided deadline, the - * execution must be aborted, and either {@link + * execution may be aborted, and either {@link * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link - * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due + * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due * to an abort must be sent the same way as other errors, described above. - * If the service reports that it does not support execution deadlines via - * IDevice::supportsDeadlines, and executeSynchronously_1_3 is called with a - * deadline, then the argument is invalid, and - * {@link ErrorStatus::INVALID_ARGUMENT} must be returned. * * Any number of calls to the execute* and executeSynchronously* functions, * in any combination, may be made concurrently, even on the same @@ -171,9 +163,9 @@ interface IPreparedModel extends @1.2::IPreparedModel { * The duration runs from the time the driver sees the call * to the executeSynchronously_1_3 function to the time the driver * returns from the function. - * @param deadline The time by which the execution must complete. If the - * execution cannot be finished by the deadline, the - * execution must be aborted. + * @param deadline The time by which the execution is expected to complete. + * If the execution cannot be finished by the deadline, the + * execution may be aborted. * @param loopTimeoutDuration The maximum amount of time that should be spent * executing a {@link OperationType::WHILE} * operation. If a loop condition model does not @@ -194,8 +186,8 @@ interface IPreparedModel extends @1.2::IPreparedModel { * corresponding output * - INVALID_ARGUMENT if one of the input arguments is * invalid - * - MISSED_DEADLINE_* if the deadline for executing a model - * cannot be met + * - MISSED_DEADLINE_* if the execution is aborted because it + * cannot be completed by the deadline * - RESOURCE_EXHAUSTED_* if the task was aborted by the * driver * @return outputShapes A list of shape information of model output operands. @@ -236,17 +228,13 @@ interface IPreparedModel extends @1.2::IPreparedModel { * any data object referenced by 'request' (described by the * {@link @1.0::DataLocation} of a {@link @1.0::RequestArgument}). * - * executeFenced can be called with an optional deadline and an optional duration. + * executeFenced may be called with an optional deadline and an optional duration. * If the execution is not able to be completed before the provided deadline or * within the timeout duration (measured from when all sync fences in waitFor are - * signaled), whichever comes earlier, the execution must be aborted, and either + * signaled), whichever comes earlier, the execution may be aborted, and either * {@link ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link - * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due + * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due * to an abort must be sent the same way as other errors, described above. - * If the service reports that it does not support execution deadlines via - * IDevice::supportsDeadlines, and executeFenced is called with a - * deadline or duration, then the argument is invalid, and - * {@link ErrorStatus::INVALID_ARGUMENT} must be returned. * * If any of the sync fences in waitFor changes to error status after the executeFenced * call succeeds, or the execution is aborted because it cannot finish before the deadline @@ -263,9 +251,9 @@ interface IPreparedModel extends @1.2::IPreparedModel { * @param waitFor A vector of sync fence file descriptors. * Execution must not start until all sync fences have been signaled. * @param measure Specifies whether or not to measure duration of the execution. - * @param deadline The time by which the execution must complete. If the - * execution cannot be finished by the deadline, the - * execution must be aborted. + * @param deadline The time by which the execution is expected to complete. + * If the execution cannot be finished by the deadline, the + * execution may be aborted. * @param loopTimeoutDuration The maximum amount of time that should be spent * executing a {@link OperationType::WHILE} * operation. If a loop condition model does not @@ -277,18 +265,18 @@ interface IPreparedModel extends @1.2::IPreparedModel { * LoopTimeoutDurationNs::DEFAULT}. When * provided, the duration must not exceed {@link * LoopTimeoutDurationNs::MAXIMUM}. - * @param duration The length of time within which the execution must - * complete after all sync fences in waitFor are signaled. If the - * execution cannot be finished within the duration, the execution - * must be aborted. + * @param duration The length of time within which the execution is expected + * to complete after all sync fences in waitFor are signaled. + * If the execution cannot be finished within the duration, + * the execution may be aborted. * @return status Error status of the call, must be: * - NONE if task is successfully launched * - DEVICE_UNAVAILABLE if driver is offline or busy * - GENERAL_FAILURE if there is an unspecified error * - INVALID_ARGUMENT if one of the input arguments is invalid, including * fences in error states. - * - MISSED_DEADLINE_* if the deadline for executing a model - * cannot be met + * - MISSED_DEADLINE_* if the execution is aborted because it + * cannot be completed by the deadline * - RESOURCE_EXHAUSTED_* if the task was aborted by the * driver * @return syncFence The sync fence that will be signaled when the task is completed. diff --git a/neuralnetworks/1.3/IPreparedModelCallback.hal b/neuralnetworks/1.3/IPreparedModelCallback.hal index 11ebbf4ab3..c0d3416439 100644 --- a/neuralnetworks/1.3/IPreparedModelCallback.hal +++ b/neuralnetworks/1.3/IPreparedModelCallback.hal @@ -47,8 +47,8 @@ interface IPreparedModelCallback extends @1.2::IPreparedModelCallback { * unspecified error * - INVALID_ARGUMENT if one of the input arguments to * prepareModel is invalid - * - MISSED_DEADLINE_* if the deadline for executing a model - * cannot be met + * - MISSED_DEADLINE_* if the preparation is aborted because + * the model cannot be prepared by the deadline * - RESOURCE_EXHAUSTED_* if the task was aborted by the * driver * @param preparedModel A model that has been asynchronously prepared for diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index b04abe219b..8c9393b030 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -858,12 +858,6 @@ void Execute(const sp& device, const TestModel& testModel, TestKind tes void GeneratedTestBase::SetUp() { testing::TestWithParam::SetUp(); ASSERT_NE(kDevice, nullptr); - - const Return ret = - kDevice->supportsDeadlines([this](bool prepareModelDeadline, bool executionDeadline) { - mSupportsDeadlines = {prepareModelDeadline, executionDeadline}; - }); - ASSERT_TRUE(ret.isOk()); } std::vector getNamedModels(const FilterFn& filter) { diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h index a8db5155b5..834d335f50 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h @@ -36,7 +36,6 @@ class GeneratedTestBase : public testing::TestWithParam { void SetUp() override; const sp kDevice = getData(std::get(GetParam())); const test_helper::TestModel& kTestModel = *getData(std::get(GetParam())); - std::pair mSupportsDeadlines; }; using FilterFn = std::function; diff --git a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp index fccc612574..2663500708 100644 --- a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp +++ b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp @@ -34,45 +34,52 @@ using V1_2::Timing; using HidlToken = hidl_array(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; -enum class DeadlineBoundType { NOW, UNLIMITED }; -constexpr std::array deadlineBounds = {DeadlineBoundType::NOW, - DeadlineBoundType::UNLIMITED}; +enum class DeadlineBoundType { NOW, UNLIMITED, SHORT }; +constexpr std::array deadlineBounds = { + DeadlineBoundType::NOW, DeadlineBoundType::UNLIMITED, DeadlineBoundType::SHORT}; std::string toString(DeadlineBoundType type) { switch (type) { case DeadlineBoundType::NOW: return "NOW"; case DeadlineBoundType::UNLIMITED: return "UNLIMITED"; + case DeadlineBoundType::SHORT: + return "SHORT"; } LOG(FATAL) << "Unrecognized DeadlineBoundType: " << static_cast(type); return {}; } +constexpr auto kShortDuration = std::chrono::milliseconds{5}; + using Results = std::tuple, Timing>; using MaybeResults = std::optional; using ExecutionFunction = std::function& preparedModel, const Request& request, - DeadlineBoundType deadlineBound)>; + const OptionalTimePoint& deadline)>; -static OptionalTimePoint makeOptionalTimePoint(DeadlineBoundType deadlineBoundType) { - OptionalTimePoint deadline; +static OptionalTimePoint makeDeadline(DeadlineBoundType deadlineBoundType) { + const auto getNanosecondsSinceEpoch = [](const auto& time) -> uint64_t { + const auto timeSinceEpoch = time.time_since_epoch(); + return std::chrono::duration_cast(timeSinceEpoch).count(); + }; + + std::chrono::steady_clock::time_point timePoint; switch (deadlineBoundType) { - case DeadlineBoundType::NOW: { - const auto currentTime = std::chrono::steady_clock::now(); - const auto currentTimeInNanoseconds = - std::chrono::time_point_cast(currentTime); - const uint64_t nanosecondsSinceEpoch = - currentTimeInNanoseconds.time_since_epoch().count(); - deadline.nanosecondsSinceEpoch(nanosecondsSinceEpoch); - } break; - case DeadlineBoundType::UNLIMITED: { - const auto maxTime = std::chrono::time_point::max(); - const uint64_t nanosecondsSinceEpoch = maxTime.time_since_epoch().count(); - deadline.nanosecondsSinceEpoch(nanosecondsSinceEpoch); - } break; + case DeadlineBoundType::NOW: + timePoint = std::chrono::steady_clock::now(); + break; + case DeadlineBoundType::UNLIMITED: + timePoint = std::chrono::steady_clock::time_point::max(); + break; + case DeadlineBoundType::SHORT: + timePoint = std::chrono::steady_clock::now() + kShortDuration; + break; } + + OptionalTimePoint deadline; + deadline.nanosecondsSinceEpoch(getNanosecondsSinceEpoch(timePoint)); return deadline; } @@ -80,7 +87,7 @@ void runPrepareModelTest(const sp& device, const Model& model, Priority std::optional deadlineBound) { OptionalTimePoint deadline; if (deadlineBound.has_value()) { - deadline = makeOptionalTimePoint(deadlineBound.value()); + deadline = makeDeadline(deadlineBound.value()); } // see if service can handle model @@ -131,7 +138,8 @@ void runPrepareModelTest(const sp& device, const Model& model, Priority // deadline has already passed when the driver would launch the // execution. In this case, the driver must return // MISSED_DEADLINE_*. - EXPECT_TRUE(prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT || + EXPECT_TRUE(prepareReturnStatus == ErrorStatus::NONE || + prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT || prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT); break; case DeadlineBoundType::UNLIMITED: @@ -140,13 +148,19 @@ void runPrepareModelTest(const sp& device, const Model& model, Priority // of the switch statement. EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); break; + case DeadlineBoundType::SHORT: + // Either the driver successfully completed the task in time or + // it aborted within the compliance time. + EXPECT_TRUE(prepareReturnStatus == ErrorStatus::NONE || + prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT || + prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT); + break; } } ASSERT_EQ(prepareReturnStatus == ErrorStatus::NONE, preparedModel.get() != nullptr); } -void runPrepareModelTests(const sp& device, const Model& model, - bool supportsPrepareModelDeadline) { +void runPrepareModelTests(const sp& device, const Model& model) { // test priority for (auto priority : hidl_enum_range{}) { SCOPED_TRACE("priority: " + toString(priority)); @@ -155,19 +169,17 @@ void runPrepareModelTests(const sp& device, const Model& model, } // test deadline - if (supportsPrepareModelDeadline) { - for (auto deadlineBound : deadlineBounds) { - SCOPED_TRACE("deadlineBound: " + toString(deadlineBound)); - runPrepareModelTest(device, model, kDefaultPriority, deadlineBound); - } + for (auto deadlineBound : deadlineBounds) { + SCOPED_TRACE("deadlineBound: " + toString(deadlineBound)); + runPrepareModelTest(device, model, kDefaultPriority, deadlineBound); } } static MaybeResults executeAsynchronously(const sp& preparedModel, - const Request& request, DeadlineBoundType deadlineBound) { + const Request& request, + const OptionalTimePoint& deadline) { SCOPED_TRACE("asynchronous"); const MeasureTiming measure = MeasureTiming::NO; - const OptionalTimePoint deadline = makeOptionalTimePoint(deadlineBound); // launch execution const sp callback = new ExecutionCallback(); @@ -187,10 +199,10 @@ static MaybeResults executeAsynchronously(const sp& preparedMode } static MaybeResults executeSynchronously(const sp& preparedModel, - const Request& request, DeadlineBoundType deadlineBound) { + const Request& request, + const OptionalTimePoint& deadline) { SCOPED_TRACE("synchronous"); const MeasureTiming measure = MeasureTiming::NO; - const OptionalTimePoint deadline = makeOptionalTimePoint(deadlineBound); // configure results callback MaybeResults results; @@ -209,9 +221,10 @@ static MaybeResults executeSynchronously(const sp& preparedModel void runExecutionTest(const sp& preparedModel, const TestModel& testModel, const Request& request, bool synchronous, DeadlineBoundType deadlineBound) { const ExecutionFunction execute = synchronous ? executeSynchronously : executeAsynchronously; + const auto deadline = makeDeadline(deadlineBound); // Perform execution and unpack results. - const auto results = execute(preparedModel, request, deadlineBound); + const auto results = execute(preparedModel, request, deadline); if (!results.has_value()) return; const auto& [status, outputShapes, timing] = results.value(); @@ -226,7 +239,8 @@ void runExecutionTest(const sp& preparedModel, const TestModel& // deadline has already passed when the driver would launch the // execution. In this case, the driver must return // MISSED_DEADLINE_*. - ASSERT_TRUE(status == ErrorStatus::MISSED_DEADLINE_TRANSIENT || + ASSERT_TRUE(status == ErrorStatus::NONE || + status == ErrorStatus::MISSED_DEADLINE_TRANSIENT || status == ErrorStatus::MISSED_DEADLINE_PERSISTENT); return; case DeadlineBoundType::UNLIMITED: @@ -235,6 +249,13 @@ void runExecutionTest(const sp& preparedModel, const TestModel& // of the switch statement. ASSERT_EQ(ErrorStatus::NONE, status); break; + case DeadlineBoundType::SHORT: + // Either the driver successfully completed the task in time or + // it aborted within the compliance time. + EXPECT_TRUE(status == ErrorStatus::NONE || + status == ErrorStatus::MISSED_DEADLINE_TRANSIENT || + status == ErrorStatus::MISSED_DEADLINE_PERSISTENT); + break; } // If the model output operands are fully specified, outputShapes must be either @@ -268,32 +289,27 @@ void runExecutionTests(const sp& preparedModel, const TestModel& } } -void runTests(const sp& device, const TestModel& testModel, - std::pair supportsDeadlines) { +void runTests(const sp& device, const TestModel& testModel) { // setup - const auto [supportsPrepareModelDeadline, supportsExecutionDeadline] = supportsDeadlines; - if (!supportsPrepareModelDeadline && !supportsExecutionDeadline) return; const Model model = createModel(testModel); // run prepare model tests - runPrepareModelTests(device, model, supportsPrepareModelDeadline); + runPrepareModelTests(device, model); - if (supportsExecutionDeadline) { - // prepare model - sp preparedModel; - createPreparedModel(device, model, &preparedModel); - if (preparedModel == nullptr) return; + // prepare model + sp preparedModel; + createPreparedModel(device, model, &preparedModel); + if (preparedModel == nullptr) return; - // run execution tests - const Request request = nn::convertToV1_3(createRequest(testModel)); - runExecutionTests(preparedModel, testModel, request); - } + // run execution tests + const Request request = nn::convertToV1_3(createRequest(testModel)); + runExecutionTests(preparedModel, testModel, request); } class DeadlineTest : public GeneratedTestBase {}; TEST_P(DeadlineTest, Test) { - runTests(kDevice, kTestModel, mSupportsDeadlines); + runTests(kDevice, kTestModel); } INSTANTIATE_GENERATED_TEST(DeadlineTest, diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 09e9922a23..8f2d4b7f19 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -44,18 +44,12 @@ static void validateGetSupportedOperations(const sp& device, const std: } static void validatePrepareModel(const sp& device, const std::string& message, - const Model& model, ExecutionPreference preference, - bool testDeadline) { + const Model& model, ExecutionPreference preference) { SCOPED_TRACE(message + " [prepareModel_1_3]"); - OptionalTimePoint deadline; - if (testDeadline) { - deadline.nanosecondsSinceEpoch(std::numeric_limits::max()); - } - sp preparedModelCallback = new PreparedModelCallback(); Return prepareLaunchStatus = device->prepareModel_1_3( - model, preference, kDefaultPriority, deadline, hidl_vec(), + model, preference, kDefaultPriority, {}, hidl_vec(), hidl_vec(), HidlToken(), preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(prepareLaunchStatus)); @@ -79,13 +73,12 @@ static bool validExecutionPreference(ExecutionPreference preference) { // to the model does not leave this function. static void validate(const sp& device, const std::string& message, Model model, const std::function& mutation, - ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER, - bool testDeadline = false) { + ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) { mutation(&model); - if (validExecutionPreference(preference) && !testDeadline) { + if (validExecutionPreference(preference)) { validateGetSupportedOperations(device, message, model); } - validatePrepareModel(device, message, model, preference, testDeadline); + validatePrepareModel(device, message, model, preference); } static uint32_t addOperand(Model* model) { @@ -744,19 +737,9 @@ static void mutateExecutionPreferenceTest(const sp& device, const Model } } -///////////////////////// DEADLINE ///////////////////////// - -static void deadlineTest(const sp& device, const Model& model) { - const std::string message = "deadlineTest: deadline not supported"; - const auto noop = [](Model*) {}; - validate(device, message, model, noop, ExecutionPreference::FAST_SINGLE_ANSWER, - /*testDeadline=*/true); -} - ////////////////////////// ENTRY POINT ////////////////////////////// -void validateModel(const sp& device, const Model& model, - bool prepareModelDeadlineSupported) { +void validateModel(const sp& device, const Model& model) { mutateOperandTypeTest(device, model); mutateOperandRankTest(device, model); mutateOperandScaleTest(device, model); @@ -772,9 +755,6 @@ void validateModel(const sp& device, const Model& model, addOperationInputTest(device, model); addOperationOutputTest(device, model); mutateExecutionPreferenceTest(device, model); - if (!prepareModelDeadlineSupported) { - deadlineTest(device, model); - } } } // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index 20f4fe2c00..5e806e5c9b 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -45,8 +45,7 @@ static bool badTiming(Timing timing) { // that use the request. Note that the request here is passed by value, and any // mutation to the request does not leave this function. static void validate(const sp& preparedModel, const std::string& message, - Request request, const std::function& mutation, - bool testDeadline = false) { + Request request, const std::function& mutation) { mutation(&request); // We'd like to test both with timing requested and without timing @@ -59,18 +58,13 @@ static void validate(const sp& preparedModel, const std::string& }; MeasureTiming measure = (hash & 1) ? MeasureTiming::YES : MeasureTiming::NO; - OptionalTimePoint deadline; - if (testDeadline) { - deadline.nanosecondsSinceEpoch(std::numeric_limits::max()); - } - // asynchronous { SCOPED_TRACE(message + " [execute_1_3]"); sp executionCallback = new ExecutionCallback(); Return executeLaunchStatus = - preparedModel->execute_1_3(request, measure, deadline, {}, executionCallback); + preparedModel->execute_1_3(request, measure, {}, {}, executionCallback); ASSERT_TRUE(executeLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(executeLaunchStatus)); @@ -88,7 +82,7 @@ static void validate(const sp& preparedModel, const std::string& SCOPED_TRACE(message + " [executeSynchronously_1_3]"); Return executeStatus = preparedModel->executeSynchronously_1_3( - request, measure, deadline, {}, + request, measure, {}, {}, [](ErrorStatus error, const hidl_vec& outputShapes, const Timing& timing) { ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); @@ -100,7 +94,7 @@ static void validate(const sp& preparedModel, const std::string& // burst // TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2. - if (!testDeadline) { + { SCOPED_TRACE(message + " [burst]"); ASSERT_TRUE(nn::compliantWithV1_0(request)); @@ -143,7 +137,7 @@ static void validate(const sp& preparedModel, const std::string& { SCOPED_TRACE(message + " [executeFenced]"); Return ret = - preparedModel->executeFenced(request, {}, MeasureTiming::NO, deadline, {}, {}, + preparedModel->executeFenced(request, {}, MeasureTiming::NO, {}, {}, {}, [](ErrorStatus error, const hidl_handle& handle, const sp& callback) { ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); @@ -174,23 +168,11 @@ static void removeOutputTest(const sp& preparedModel, const Requ } } -///////////////////////// DEADLINE //////////////////////////////////// - -static void deadlineTest(const sp& preparedModel, const Request& request) { - const std::string message = "deadlineTest: deadline not supported"; - const auto noop = [](Request*) {}; - validate(preparedModel, message, request, noop, /*testDeadline=*/true); -} - ///////////////////////////// ENTRY POINT ////////////////////////////////// -void validateRequest(const sp& preparedModel, const Request& request, - bool executionDeadlineSupported) { +void validateRequest(const sp& preparedModel, const Request& request) { removeInputTest(preparedModel, request); removeOutputTest(preparedModel, request); - if (!executionDeadlineSupported) { - deadlineTest(preparedModel, request); - } } void validateRequestFailure(const sp& preparedModel, const Request& request) { diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index 16341dafc7..5b07034296 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -123,11 +123,9 @@ std::string printNeuralnetworksHidlTest( INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest); // Forward declaration from ValidateModel.cpp -void validateModel(const sp& device, const Model& model, - bool prepareModelDeadlineSupported); +void validateModel(const sp& device, const Model& model); // Forward declaration from ValidateRequest.cpp -void validateRequest(const sp& preparedModel, const Request& request, - bool executionDeadlineSupported); +void validateRequest(const sp& preparedModel, const Request& request); // Forward declaration from ValidateRequest.cpp void validateRequestFailure(const sp& preparedModel, const Request& request); // Forward declaration from ValidateBurst.cpp @@ -147,17 +145,15 @@ void validateExecuteFenced(const sp& preparedModel, const Reques ASSERT_TRUE(ret_null.isOk()); } -void validateEverything(const sp& device, const Model& model, const Request& request, - std::pair supportsDeadlines) { - const auto [prepareModelDeadlineSupported, executionDeadlineSupported] = supportsDeadlines; - validateModel(device, model, prepareModelDeadlineSupported); +void validateEverything(const sp& device, const Model& model, const Request& request) { + validateModel(device, model); // Create IPreparedModel. sp preparedModel; createPreparedModel(device, model, &preparedModel); if (preparedModel == nullptr) return; - validateRequest(preparedModel, request, executionDeadlineSupported); + validateRequest(preparedModel, request); validateExecuteFenced(preparedModel, request); // TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2. @@ -166,12 +162,10 @@ void validateEverything(const sp& device, const Model& model, const Req validateBurst(preparedModel, request10); } -void validateFailure(const sp& device, const Model& model, const Request& request, - std::pair supportsDeadlines) { - const bool prepareModelDeadlineSupported = supportsDeadlines.first; +void validateFailure(const sp& device, const Model& model, const Request& request) { // TODO: Should this always succeed? // What if the invalid input is part of the model (i.e., a parameter). - validateModel(device, model, prepareModelDeadlineSupported); + validateModel(device, model); // Create IPreparedModel. sp preparedModel; @@ -185,9 +179,9 @@ TEST_P(ValidationTest, Test) { const Model model = createModel(kTestModel); const Request request = nn::convertToV1_3(createRequest(kTestModel)); if (kTestModel.expectFailure) { - validateFailure(kDevice, model, request, mSupportsDeadlines); + validateFailure(kDevice, model, request); } else { - validateEverything(kDevice, model, request, mSupportsDeadlines); + validateEverything(kDevice, model, request); } } From c7327c57f91dcf53f8281d4468101dca7820033c Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Tue, 18 Feb 2020 18:38:37 -0800 Subject: [PATCH 0609/1022] Fix NNAPI QoS Deadline test The Deadline test was directly loading into the field of a std::optional instead of emplacing, which is undefined behavior. This has been corrected to emplace. Additionally, previously the deadline test always checked the tensor results of the execution. This is changed to only check the results when the driver reports that the execution completed successfully. Finally, this CL merges similar switch case statements. Bug: 149766387 Test: mma Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: I1068fe70e74a12006dea3cdf4ae9da50004ad24b --- .../vts/functional/QualityOfServiceTests.cpp | 39 +++++++------------ 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp index 2663500708..879989ea2a 100644 --- a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp +++ b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp @@ -134,10 +134,9 @@ void runPrepareModelTest(const sp& device, const Model& model, Priority } else { switch (deadlineBound.value()) { case DeadlineBoundType::NOW: - // If the execution was launched with a deadline of NOW, the - // deadline has already passed when the driver would launch the - // execution. In this case, the driver must return - // MISSED_DEADLINE_*. + case DeadlineBoundType::SHORT: + // Either the driver successfully completed the task or it + // aborted and returned MISSED_DEADLINE_*. EXPECT_TRUE(prepareReturnStatus == ErrorStatus::NONE || prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT || prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT); @@ -148,13 +147,6 @@ void runPrepareModelTest(const sp& device, const Model& model, Priority // of the switch statement. EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); break; - case DeadlineBoundType::SHORT: - // Either the driver successfully completed the task in time or - // it aborted within the compliance time. - EXPECT_TRUE(prepareReturnStatus == ErrorStatus::NONE || - prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT || - prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT); - break; } } ASSERT_EQ(prepareReturnStatus == ErrorStatus::NONE, preparedModel.get() != nullptr); @@ -206,7 +198,10 @@ static MaybeResults executeSynchronously(const sp& preparedModel // configure results callback MaybeResults results; - const auto cb = [&results](const auto&... args) { *results = {args...}; }; + const auto cb = [&results](ErrorStatus status, const hidl_vec& outputShapes, + const Timing& timing) { + results.emplace(status, outputShapes, timing); + }; // run execution const Return ret = @@ -235,27 +230,19 @@ void runExecutionTest(const sp& preparedModel, const TestModel& // Validate deadline information if applicable. switch (deadlineBound) { case DeadlineBoundType::NOW: - // If the execution was launched with a deadline of NOW, the - // deadline has already passed when the driver would launch the - // execution. In this case, the driver must return - // MISSED_DEADLINE_*. + case DeadlineBoundType::SHORT: + // Either the driver successfully completed the task or it + // aborted and returned MISSED_DEADLINE_*. ASSERT_TRUE(status == ErrorStatus::NONE || status == ErrorStatus::MISSED_DEADLINE_TRANSIENT || status == ErrorStatus::MISSED_DEADLINE_PERSISTENT); - return; + break; case DeadlineBoundType::UNLIMITED: // If an unlimited deadline is supplied, we expect the execution to // proceed normally. In this case, check it normally by breaking out // of the switch statement. ASSERT_EQ(ErrorStatus::NONE, status); break; - case DeadlineBoundType::SHORT: - // Either the driver successfully completed the task in time or - // it aborted within the compliance time. - EXPECT_TRUE(status == ErrorStatus::NONE || - status == ErrorStatus::MISSED_DEADLINE_TRANSIENT || - status == ErrorStatus::MISSED_DEADLINE_PERSISTENT); - break; } // If the model output operands are fully specified, outputShapes must be either @@ -277,7 +264,9 @@ void runExecutionTest(const sp& preparedModel, const TestModel& const std::vector outputs = getOutputBuffers(request10); // We want "close-enough" results. - checkResults(testModel, outputs); + if (status == ErrorStatus::NONE) { + checkResults(testModel, outputs); + } } void runExecutionTests(const sp& preparedModel, const TestModel& testModel, From c64065c557cba39f577c3280b42fd2a6ae0c5072 Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Wed, 19 Feb 2020 08:44:17 -0500 Subject: [PATCH 0610/1022] Remove oneway designator on contexthub HAL 1.1 According to the linter, the oneway designator should only be used on an interface that only has oneway methods as it can have implications on the threading model (among other things). Bug: 149758462 Test: atest VtsHalContexthubV1_0TargetTest VtsHalContexthubV1_1TargetTest Change-Id: I969ab2ead1e30f7f4cfa62e292a22833ec5e8471 --- contexthub/1.1/IContexthub.hal | 2 +- current.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contexthub/1.1/IContexthub.hal b/contexthub/1.1/IContexthub.hal index 842d4b79ef..a3b4bd4640 100644 --- a/contexthub/1.1/IContexthub.hal +++ b/contexthub/1.1/IContexthub.hal @@ -27,5 +27,5 @@ interface IContexthub extends @1.0::IContexthub { * @param setting User setting that has been modified. * @param newValue The update value of the user setting. */ - oneway onSettingChanged(Setting setting, SettingValue newValue); + onSettingChanged(Setting setting, SettingValue newValue); }; \ No newline at end of file diff --git a/current.txt b/current.txt index 8d14fa3609..eb7e58227d 100644 --- a/current.txt +++ b/current.txt @@ -644,7 +644,7 @@ c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardwar 9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardware.cas@1.2::IMediaCasService 4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types -2a6b1a1202493f0a7c88d716da6e2cdd66bfd77a170621791fdf14997fdfcaf9 android.hardware.contexthub@1.1::IContexthub +8351cc01eed4c0b4482d9572b5c7ddfd17874d8edb51d6761d348116fc91dd18 android.hardware.contexthub@1.1::IContexthub 3581d0ba61663cdd45807494dcd697d01c074f27587df9140655f94346969cfe android.hardware.contexthub@1.1::types 66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory 994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory From af09f9de949d58f2d6eb6b0d8707a59ff64f6cfc Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Tue, 18 Feb 2020 20:46:04 +0000 Subject: [PATCH 0611/1022] Revert "Update PhoneCapability to use 1.5 UTRAN bands" Revert "PhoneCapability cleanup" Revert "Test PhoneCapability API" Revert "PhoneCapability cleanup" Revert submission 10153355-dev_cap Reason for revert: Change not supported by modem Reverted Changes: Id86ad81d8: Update PhoneCapability to use 1.5 UTRAN bands Ia44398852: Test PhoneCapability API I2510de0ab: PhoneCapability cleanup I29dfb51bf: PhoneCapability cleanup Change-Id: Ief5c5325f51a9bb3921bd2eb6e0ea8c9e7111581 --- current.txt | 2 +- radio/config/1.3/types.hal | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/current.txt b/current.txt index 8d14fa3609..bc97519f22 100644 --- a/current.txt +++ b/current.txt @@ -691,7 +691,7 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar 7fefa2cc5b3b3be10b5cff5c5dc195385f491d4bf23ca65f9c6b3c30c8753a33 android.hardware.radio@1.5::IRadio e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication 829d3827eeb5a8f563e80fe627419b3231012fc02bc2e79782ec5e9ad9f799a4 android.hardware.radio@1.5::IRadioResponse -dcc8872337f0135e81970e1d8d5fd7139160dc80e9be76f0ae05290fa7e472b8 android.hardware.radio.config@1.3::types +4c4ce691df02faa28c0729e2a033ec464e1d72699be8bcde4dfb141313dbeba8 android.hardware.radio.config@1.3::types a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication 0006ab8e8b0910cbd3bbb08d5f17d5fac7d65a2bdad5f2334e4851db9d1e6fa8 android.hardware.radio.config@1.3::IRadioConfigResponse diff --git a/radio/config/1.3/types.hal b/radio/config/1.3/types.hal index aef0ff8a21..7acc6c1146 100644 --- a/radio/config/1.3/types.hal +++ b/radio/config/1.3/types.hal @@ -17,10 +17,10 @@ package android.hardware.radio.config@1.3; import android.hardware.radio@1.1::GeranBands; +import android.hardware.radio@1.1::UtranBands; import android.hardware.radio@1.1::EutranBands; import android.hardware.radio@1.4::RadioAccessFamily; import android.hardware.radio@1.5::NgranBands; -import android.hardware.radio@1.5::UtranBands; /** Type for the SIM slot. */ enum SlotType : int32_t { From 80a755fa0bf6e90bd17a92c8729890ee473d4a3e Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Tue, 18 Feb 2020 13:26:36 -0800 Subject: [PATCH 0612/1022] Revert "PhoneCapabilities changes for device capabilities" Reston for revert: Change not supported by modem This reverts commit 322c4cc2860f8c1dc8c456635df81cd0f64a7140. Change-Id: I9b268f41614149b5cd55caf3d730b25bb1f885e9 --- radio/1.5/vts/functional/Android.bp | 1 - .../vts/functional/radio_hidl_hal_test.cpp | 4 +- .../functional/radio_hidl_hal_utils_v1_5.h | 2 +- radio/config/1.3/Android.bp | 3 - radio/config/1.3/IRadioConfig.hal | 10 +- radio/config/1.3/IRadioConfigResponse.hal | 13 +- radio/config/1.3/default/RadioConfig.cpp | 9 +- radio/config/1.3/default/RadioConfig.h | 3 - .../1.3/default/RadioConfigIndication.cpp | 4 + .../1.3/default/RadioConfigIndication.h | 4 + .../1.3/default/RadioConfigResponse.cpp | 12 +- .../config/1.3/default/RadioConfigResponse.h | 43 +++-- radio/config/1.3/types.hal | 178 ------------------ .../functional/radio_config_hidl_hal_api.cpp | 31 --- .../functional/radio_config_hidl_hal_test.cpp | 2 +- .../functional/radio_config_hidl_hal_utils.h | 37 ++-- .../vts/functional/radio_config_response.cpp | 28 +-- 17 files changed, 72 insertions(+), 312 deletions(-) diff --git a/radio/1.5/vts/functional/Android.bp b/radio/1.5/vts/functional/Android.bp index 182985e68f..85c4f99db4 100644 --- a/radio/1.5/vts/functional/Android.bp +++ b/radio/1.5/vts/functional/Android.bp @@ -34,7 +34,6 @@ cc_test { "android.hardware.radio@1.0", "android.hardware.radio.config@1.0", "android.hardware.radio.config@1.1", - "android.hardware.radio.config@1.3", ], header_libs: ["radio.util.header@1.0"], test_suites: ["general-tests"] diff --git a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp index c29ebf940a..a5d236d47f 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp @@ -47,9 +47,9 @@ void RadioHidlTest_v1_5::SetUp() { EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); - sp<::android::hardware::radio::config::V1_3::IRadioConfig> radioConfig = + sp<::android::hardware::radio::config::V1_1::IRadioConfig> radioConfig = ::testing::VtsHalHidlTargetTestBase::getService< - ::android::hardware::radio::config::V1_3::IRadioConfig>(); + ::android::hardware::radio::config::V1_1::IRadioConfig>(); /* Enforce Vts tesing with RadioConfig is existed. */ ASSERT_NE(nullptr, radioConfig.get()); diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index 01cf40a196..a7c1cdc12f 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include diff --git a/radio/config/1.3/Android.bp b/radio/config/1.3/Android.bp index 7360270310..88de666618 100644 --- a/radio/config/1.3/Android.bp +++ b/radio/config/1.3/Android.bp @@ -17,9 +17,6 @@ hidl_interface { "android.hardware.radio.config@1.1", "android.hardware.radio.config@1.2", "android.hardware.radio@1.0", - "android.hardware.radio@1.1", - "android.hardware.radio@1.4", - "android.hardware.radio@1.5", "android.hidl.base@1.0", ], gen_java: true, diff --git a/radio/config/1.3/IRadioConfig.hal b/radio/config/1.3/IRadioConfig.hal index d01f54b041..a0ce6e089d 100644 --- a/radio/config/1.3/IRadioConfig.hal +++ b/radio/config/1.3/IRadioConfig.hal @@ -27,13 +27,5 @@ import @1.1::IRadioConfig; * serial to different methods), multiple responses (one for each method call) must still be served. */ interface IRadioConfig extends @1.1::IRadioConfig { - /** - * Request current phone capability. - * - * @param serial Serial number of request. - * - * Response callback is IRadioResponse.getPhoneCapabilityResponse_1_3() which - * will return <@1.3::PhoneCapability>. - */ - oneway getPhoneCapability_1_3(int32_t serial); + }; diff --git a/radio/config/1.3/IRadioConfigResponse.hal b/radio/config/1.3/IRadioConfigResponse.hal index e13aa1efb6..9c4c971f9f 100644 --- a/radio/config/1.3/IRadioConfigResponse.hal +++ b/radio/config/1.3/IRadioConfigResponse.hal @@ -16,22 +16,11 @@ package android.hardware.radio.config@1.3; -import android.hardware.radio@1.0::RadioResponseInfo; import @1.2::IRadioConfigResponse; -import @1.3::PhoneCapability; /** * Interface declaring response functions to solicited radio config requests. */ interface IRadioConfigResponse extends @1.2::IRadioConfigResponse { - /** - * @param info Response info struct containing response type, serial no. and error - * @param phoneCapability <@1.3::PhoneCapability> it defines modem's capability for example - * how many logical modems it has, how many data connections it supports. - * - * Valid errors returned: - * RadioError:NONE - * RadioError:RADIO_NOT_AVAILABLE - */ - oneway getPhoneCapabilityResponse_1_3(RadioResponseInfo info, PhoneCapability phoneCapability); + }; diff --git a/radio/config/1.3/default/RadioConfig.cpp b/radio/config/1.3/default/RadioConfig.cpp index 01e98f1dd6..c28119c311 100644 --- a/radio/config/1.3/default/RadioConfig.cpp +++ b/radio/config/1.3/default/RadioConfig.cpp @@ -24,6 +24,7 @@ namespace V1_3 { namespace implementation { using namespace ::android::hardware::radio::V1_0; +using namespace ::android::hardware::radio::config; // Methods from ::android::hardware::radio::config::V1_0::IRadioConfig follow. Return RadioConfig::setResponseFunctions( @@ -104,14 +105,6 @@ Return RadioConfig::getModemsConfig(int32_t /* serial */) { return Void(); } -// Methods from ::android::hardware::radio::config::V1_3::IRadioConfig follow. -Return RadioConfig::getPhoneCapability_1_3(int32_t /* serial */) { - V1_3::PhoneCapability phoneCapability; - RadioResponseInfo info; - mRadioConfigResponseV1_3->getPhoneCapabilityResponse_1_3(info, phoneCapability); - return Void(); -} - } // namespace implementation } // namespace V1_3 } // namespace config diff --git a/radio/config/1.3/default/RadioConfig.h b/radio/config/1.3/default/RadioConfig.h index 57ff3689eb..00585e6df2 100644 --- a/radio/config/1.3/default/RadioConfig.h +++ b/radio/config/1.3/default/RadioConfig.h @@ -62,9 +62,6 @@ struct RadioConfig : public V1_3::IRadioConfig { Return setPreferredDataModem(int32_t serial, uint8_t modemId); Return setModemsConfig(int32_t serial, const V1_1::ModemsConfig& modemsConfig); Return getModemsConfig(int32_t serial); - - // Methods from ::android::hardware::radio::config::V1_3::IRadioConfig follow. - Return getPhoneCapability_1_3(int32_t serial); }; } // namespace implementation diff --git a/radio/config/1.3/default/RadioConfigIndication.cpp b/radio/config/1.3/default/RadioConfigIndication.cpp index 608fa1c258..eb77a48ec1 100644 --- a/radio/config/1.3/default/RadioConfigIndication.cpp +++ b/radio/config/1.3/default/RadioConfigIndication.cpp @@ -23,6 +23,10 @@ namespace config { namespace V1_3 { namespace implementation { +using namespace ::android::hardware::radio::V1_0; +using namespace ::android::hardware::radio::config::V1_0; +using namespace ::android::hardware::radio::config::V1_2; + // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigIndication follow. Return RadioConfigIndication::simSlotsStatusChanged( RadioIndicationType /* type */, const hidl_vec& /* slotStatus */) { diff --git a/radio/config/1.3/default/RadioConfigIndication.h b/radio/config/1.3/default/RadioConfigIndication.h index c92446cbe2..3697492375 100644 --- a/radio/config/1.3/default/RadioConfigIndication.h +++ b/radio/config/1.3/default/RadioConfigIndication.h @@ -31,6 +31,10 @@ namespace implementation { using namespace ::android::hardware::radio::V1_0; using namespace ::android::hardware::radio::config; +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; diff --git a/radio/config/1.3/default/RadioConfigResponse.cpp b/radio/config/1.3/default/RadioConfigResponse.cpp index 1d48a13e37..48e81dade3 100644 --- a/radio/config/1.3/default/RadioConfigResponse.cpp +++ b/radio/config/1.3/default/RadioConfigResponse.cpp @@ -23,6 +23,11 @@ namespace config { namespace V1_3 { namespace implementation { +using namespace ::android::hardware::radio::V1_0; +using namespace ::android::hardware::radio::config::V1_0; +using namespace ::android::hardware::radio::config::V1_1; +using namespace ::android::hardware::radio::config::V1_2; + // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow. Return RadioConfigResponse::getSimSlotsStatusResponse( const RadioResponseInfo& /* info */, @@ -68,13 +73,6 @@ Return RadioConfigResponse::getSimSlotsStatusResponse_1_2( return Void(); } -// Methods from ::android::hardware::radio::config::V1_3::IRadioConfigResponse follow. -Return RadioConfigResponse::getPhoneCapabilityResponse_1_3( - const RadioResponseInfo& /* info */, const V1_3::PhoneCapability& /* phoneCapability */) { - // TODO implement - return Void(); -} - } // namespace implementation } // namespace V1_3 } // namespace config diff --git a/radio/config/1.3/default/RadioConfigResponse.h b/radio/config/1.3/default/RadioConfigResponse.h index dc169bb635..0f0033fa6a 100644 --- a/radio/config/1.3/default/RadioConfigResponse.h +++ b/radio/config/1.3/default/RadioConfigResponse.h @@ -28,36 +28,43 @@ namespace config { namespace V1_3 { namespace implementation { -using namespace ::android::hardware::radio::config; - +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::Return; - -using ::android::hardware::radio::V1_0::RadioResponseInfo; +using ::android::hardware::Void; struct RadioConfigResponse : public IRadioConfigResponse { // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow. Return getSimSlotsStatusResponse( - const RadioResponseInfo& info, - const hidl_vec& slotStatus) override; - Return setSimSlotsMappingResponse(const RadioResponseInfo& info) override; + const ::android::hardware::radio::V1_0::RadioResponseInfo& info, + const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus) + override; + Return setSimSlotsMappingResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override; // Methods from ::android::hardware::radio::config::V1_1::IRadioConfigResponse follow. - Return getPhoneCapabilityResponse(const RadioResponseInfo& info, - const V1_1::PhoneCapability& phoneCapability) override; - Return setPreferredDataModemResponse(const RadioResponseInfo& info) override; - Return setModemsConfigResponse(const RadioResponseInfo& info) override; - Return getModemsConfigResponse(const RadioResponseInfo& info, - const V1_1::ModemsConfig& modemsConfig) override; + Return getPhoneCapabilityResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& info, + const ::android::hardware::radio::config::V1_1::PhoneCapability& phoneCapability) + override; + Return setPreferredDataModemResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override; + Return setModemsConfigResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override; + Return getModemsConfigResponse( + const ::android::hardware::radio::V1_0::RadioResponseInfo& info, + const ::android::hardware::radio::config::V1_1::ModemsConfig& modemsConfig) override; // Methods from ::android::hardware::radio::config::V1_2::IRadioConfigResponse follow. Return getSimSlotsStatusResponse_1_2( - const RadioResponseInfo& info, - const hidl_vec& slotStatus) override; + const ::android::hardware::radio::V1_0::RadioResponseInfo& info, + const hidl_vec<::android::hardware::radio::config::V1_2::SimSlotStatus>& slotStatus) + override; - // Methods from ::android::hardware::radio::config::V1_3::IRadioConfigResponse follow. - Return getPhoneCapabilityResponse_1_3( - const RadioResponseInfo& info, const V1_3::PhoneCapability& phoneCapability) override; + // Methods from ::android::hidl::base::V1_0::IBase follow. }; } // namespace implementation diff --git a/radio/config/1.3/types.hal b/radio/config/1.3/types.hal index 7acc6c1146..866002acad 100644 --- a/radio/config/1.3/types.hal +++ b/radio/config/1.3/types.hal @@ -15,181 +15,3 @@ */ package android.hardware.radio.config@1.3; - -import android.hardware.radio@1.1::GeranBands; -import android.hardware.radio@1.1::UtranBands; -import android.hardware.radio@1.1::EutranBands; -import android.hardware.radio@1.4::RadioAccessFamily; -import android.hardware.radio@1.5::NgranBands; - -/** Type for the SIM slot. */ -enum SlotType : int32_t { - /** Slot type for UICC/pSIM (physical SIM). */ - UICC = 1, - /** Slot type for iUICC/iSIM (integrated SIM). */ - IUICC = 2, - /** Slot type for eUICC/eSIM (embedded SIM). */ - EUICC = 3, - /** Slot type for soft SIM (no physical SIM). */ - SOFT_SIM = 4, -}; - -/** A field in PhoneCapability that holds information about the SIM slot. */ -struct SimSlotCapability { - /** Corresponds to physicalSlotId in Radio@1.2::CardStatus. */ - uint32_t physicalSlotId; - - /** Type of slot. */ - SlotType slotType; -}; - -/** Bitmask of features that can be supported by a single modem. */ -enum ModemFeatures : int32_t { - /** 3GPP2 capability. */ - THREE_GPP2_REG = 1 << 0, - /** 3GPP capability. */ - THREE_GPP_REG = 1 << 1, - /** CDMA 2000 with EHRPD capability. */ - CDMA2000_EHRPD = 1 << 2, - /** GSM/EDGE capability. */ - GERAN = 1 << 3, - /** UMTS capability. */ - UTRAN = 1 << 4, - /** LTE capability. */ - EUTRAN = 1 << 5, - /** 5G capability. */ - NGRAN = 1 << 6, - /** 5G dual connectivity capability. */ - EN_DC = 1 << 7, - /** VoLTE capability (IMS registered). */ - PS_VOICE_REG = 1 << 8, - /** CS voice call capability. */ - CS_VOICE_SESSION = 1 << 9, - /** Internet connection capability. */ - INTERACTIVE_DATA_SESSION = 1 << 10, - /** Dedicated bearer capability. */ - DEDICATED_BEARER = 1 << 11, - /** Network scanning capability. */ - NETWORK_SCAN = 1 << 12, - /** CDMA capability for SIM associated with modem. */ - CSIM_APP = 1 << 13, -}; - -struct ConcurrentModemFeatures { - /** - * A vector of concurrently supportable modem features across all modems. - * Each entry in the vector is a bitfield of ModemFeatures that can be used - * concurrently with the other ModemFeatures in that list. - * Each bitfield must be the full set of features for a single modem. - * - * On a Dual-SIM device, each entry will be a vector of length 2. - * The examples below depict the modemFeatures for four Dual-SIM setups: - * 1. Only one modem can PS attach (IMS registered). - * { - * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG | - * CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER), - * (GERAN_REG | UTRAN_REG) - * } - * or - * { - * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG | - * INTERACTIVE_DATA_SESSION), - * (GERAN_REG | UTRAN_REG | CS_VOICE_SESSION) - * } - * 2. Both modems can PS attach (dual VoLTE). - * { - * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG | - * CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER), - * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG) - * } - * 3. Both modems can maintain an Internet connection, but they share - * one RF hardware. - * { - * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG | - * CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER), - * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG | - * INTERACTIVE_DATA_SESSION) - * } - * 4. Both modems can maintain an Internet connection, and they have - * their own RF hardware. - * { - * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG | - * CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER), - * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG | - * INTERACTIVE_DATA_SESSION | DEDICATED_BEARER) - * } - */ - vec> modemFeatures; -}; - -/** - * Overwritten from @1.1::PhoneCapability to add new capabilities and deprecate - * maxActiveData, maxActiveInternetData, isInternetLingeringSupported, logicalModemList. - * Replaces RadioConfig@1.1::ModemInfo and should replace Radio@1.4::RadioCapabilities - * in the next major version upgrade. In the future, this should be extended instead of overwritten. - */ -struct PhoneCapability { - /** - * 3GPP UE category for UTRAN downlink direction. - * 25.306 Table 5.1a - */ - uint8_t utranUeCategoryDl; - /** - * 3GPP UE category for UTRAN uplink direction. - * 25.306 Table 5.1g - */ - uint8_t utranUeCategoryUl; - /** - * 3GPP UE category for EUTRAN downlink direction. - * 25.306 Table 4.1a - */ - uint8_t eutranUeCategoryDl; - /** - * 3GPP UE category for EUTRAN uplink direction. - * 25.306 Table 4.1a-2 - */ - uint8_t eutranUeCategoryUl; - - /** - * Length of grace period for switching between logical modems, in milliseconds. - * Used only when the number of logical modems is greater than the number of - * Internet connections the device can support, otherwise must be 0. - */ - uint64_t psDataConnectionLingerTimeMillis; - - vec geranBands; - vec utranBands; - vec eutranBands; - vec ngranBands; - - /** - * 32-bit bitmap of supported Radio@1.4::RadioAccessFamily types. - * Note that RadioAccessFamily is actually the radio access technologies, so it should be - * renamed in the next major version upgrade. - */ - bitfield supportedRats; - - /** - * List of unique logical modem UUIDs from Radio@1.4::RadioCapabilities. - * A UUID is typically "com.xxxx.lmX" where X is the logical modem ID. - * Must be equal to the number of logical modems in the device. - * Radio@1.2::RadioConst::MAX_UUID_LENGTH is the max length of each UUID. - */ - vec logicalModemUuids; - - /** - * List of SIM slot capabilities. The order of physical slot IDs must correspond to - * the order of modems in logicalModemUuids. - */ - vec simSlotCapabilities; - - /** - * A vector of all sets of concurrently supportable modem feature sets. The order of modems - * in modemFeatures must correspond to the order of modems in logicalModemUuids. - * Each entry in concurrentFeatureSupport is independent of others in the list - * and represents a set of concurrently supportable features across all modems. - * Each entry in ConcurrentModemFeatures::modemFeatures is a bitfield of - * concurrently supported ModemFeatures for one modem. - */ - vec concurrentFeatureSupport; -}; diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp index 7f90023b89..07e9eded5a 100644 --- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp +++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp @@ -17,34 +17,3 @@ #include #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) - -/* - * Test IRadioConfig.getPhoneCapability_1_3() - */ -TEST_P(RadioConfigHidlTest, getPhoneCapability_1_3) { - serial = GetRandomSerialNumber(); - Return res = radioConfig->getPhoneCapability_1_3(serial); - ASSERT_OK(res); - EXPECT_EQ(std::cv_status::no_timeout, wait()); - EXPECT_EQ(RadioResponseType::SOLICITED, radioConfigRsp->rspInfo.type); - EXPECT_EQ(serial, radioConfigRsp->rspInfo.serial); - ALOGI("getPhoneCapability_1_3, rspInfo.error = %s\n", - toString(radioConfigRsp->rspInfo.error).c_str()); - - ASSERT_TRUE(CheckAnyOfErrors( - radioConfigRsp->rspInfo.error, - {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR})); - - if (radioConfigRsp->rspInfo.error == RadioError ::NONE) { - int numModems = radioConfigRsp->phoneCap_1_3.logicalModemUuids.size(); - EXPECT_GE(numModems, 0); - // length of simSlotCapabilities should be equal to length of logicalModemUuids. - EXPECT_EQ(numModems, radioConfigRsp->phoneCap_1_3.simSlotCapabilities.size()); - // length of modemFeatures in each ConcurrentModemFeatures should be - // equal to length of logicalModemUuids. - for (V1_3::ConcurrentModemFeatures cmf : - radioConfigRsp->phoneCap_1_3.concurrentFeatureSupport) { - EXPECT_EQ(numModems, cmf.modemFeatures.size()); - } - } -} diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp index cd48b25fac..dbb4bf44e3 100644 --- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp +++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp @@ -17,7 +17,7 @@ #include void RadioConfigHidlTest::SetUp() { - radioConfig = V1_3::IRadioConfig::getService(GetParam()); + radioConfig = ::android::hardware::radio::config::V1_3::IRadioConfig::getService(GetParam()); ASSERT_NE(nullptr, radioConfig.get()); radioConfigRsp = new (std::nothrow) RadioConfigResponse(*this); diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h index b21c7c0b84..9b78c04944 100644 --- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h +++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h @@ -28,18 +28,19 @@ #include #include #include -#include #include "vts_test_util.h" -using namespace ::android::hardware::radio::config; +using namespace ::android::hardware::radio::config::V1_1; +using namespace ::android::hardware::radio::config::V1_2; +using namespace ::android::hardware::radio::config::V1_3; using ::android::sp; +using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::radio::V1_0::RadioIndicationType; using ::android::hardware::radio::V1_0::RadioResponseInfo; using ::android::hardware::radio::V1_0::RadioResponseType; @@ -48,46 +49,43 @@ using ::android::hardware::radio::V1_0::RadioResponseType; class RadioConfigHidlTest; /* Callback class for radio config response */ -class RadioConfigResponse : public V1_3::IRadioConfigResponse { +class RadioConfigResponse : public ::android::hardware::radio::config::V1_3::IRadioConfigResponse { protected: RadioConfigHidlTest& parent; public: RadioResponseInfo rspInfo; - V1_1::PhoneCapability phoneCap_1_1; - V1_3::PhoneCapability phoneCap_1_3; + PhoneCapability phoneCap; RadioConfigResponse(RadioConfigHidlTest& parent); virtual ~RadioConfigResponse() = default; /* 1.0 Api */ - Return getSimSlotsStatusResponse(const RadioResponseInfo& info, - const hidl_vec& slotStatus); + Return getSimSlotsStatusResponse( + const RadioResponseInfo& info, + const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus); Return setSimSlotsMappingResponse(const RadioResponseInfo& info); /* 1.1 Api */ Return getPhoneCapabilityResponse(const RadioResponseInfo& info, - const V1_1::PhoneCapability& phoneCapability); + const PhoneCapability& phoneCapability); Return setPreferredDataModemResponse(const RadioResponseInfo& info); Return getModemsConfigResponse(const RadioResponseInfo& info, - const V1_1::ModemsConfig& mConfig); + const ModemsConfig& mConfig); Return setModemsConfigResponse(const RadioResponseInfo& info); /* 1.2 Api */ Return getSimSlotsStatusResponse_1_2(const RadioResponseInfo& info, - const hidl_vec& slotStatus); - - /* 1.3 Api */ - Return getPhoneCapabilityResponse_1_3(const RadioResponseInfo& info, - const V1_3::PhoneCapability& phoneCapability); + const hidl_vec& slotStatus); }; /* Callback class for radio config indication */ -class RadioConfigIndication : public V1_3::IRadioConfigIndication { +class RadioConfigIndication + : public ::android::hardware::radio::config::V1_3::IRadioConfigIndication { protected: RadioConfigHidlTest& parent; @@ -96,8 +94,9 @@ class RadioConfigIndication : public V1_3::IRadioConfigIndication { virtual ~RadioConfigIndication() = default; /* 1.2 Api */ - Return simSlotsStatusChanged_1_2(RadioIndicationType type, - const hidl_vec& slotStatus); + Return simSlotsStatusChanged_1_2( + ::android::hardware::radio::V1_0::RadioIndicationType type, + const hidl_vec& slotStatus); }; // The main test class for Radio config HIDL. @@ -122,7 +121,7 @@ class RadioConfigHidlTest : public ::testing::TestWithParam { int serial; /* radio config service handle */ - sp radioConfig; + sp<::android::hardware::radio::config::V1_3::IRadioConfig> radioConfig; /* radio config response handle */ sp radioConfigRsp; diff --git a/radio/config/1.3/vts/functional/radio_config_response.cpp b/radio/config/1.3/vts/functional/radio_config_response.cpp index 22098d3d93..1ca960eae9 100644 --- a/radio/config/1.3/vts/functional/radio_config_response.cpp +++ b/radio/config/1.3/vts/functional/radio_config_response.cpp @@ -16,18 +16,17 @@ #include -using namespace ::android::hardware::radio::config; - -using ::android::hardware::hidl_vec; - using ::android::hardware::radio::V1_0::RadioResponseInfo; +// SimSlotStatus slotStatus; + RadioConfigResponse::RadioConfigResponse(RadioConfigHidlTest& parent) : parent(parent) {} /* 1.0 Apis */ Return RadioConfigResponse::getSimSlotsStatusResponse( const RadioResponseInfo& /* info */, - const hidl_vec& /* slotStatus */) { + const ::android::hardware::hidl_vec< + ::android::hardware::radio::config::V1_0::SimSlotStatus>& /* slotStatus */) { return Void(); } @@ -37,9 +36,9 @@ Return RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponse /* 1.1 Apis */ Return RadioConfigResponse::getPhoneCapabilityResponse( - const RadioResponseInfo& info, const V1_1::PhoneCapability& phoneCapability) { + const RadioResponseInfo& info, const PhoneCapability& phoneCapability) { rspInfo = info; - phoneCap_1_1 = phoneCapability; + phoneCap = phoneCapability; parent.notify(info.serial); return Void(); } @@ -50,7 +49,7 @@ Return RadioConfigResponse::setPreferredDataModemResponse( } Return RadioConfigResponse::getModemsConfigResponse(const RadioResponseInfo& /* info */, - const V1_1::ModemsConfig& /* mConfig */) { + const ModemsConfig& /* mConfig */) { return Void(); } @@ -61,15 +60,6 @@ Return RadioConfigResponse::setModemsConfigResponse(const RadioResponseInf /* 1.2 Apis */ Return RadioConfigResponse::getSimSlotsStatusResponse_1_2( const RadioResponseInfo& /* info */, - const hidl_vec& /* slotStatus */) { + const ::android::hardware::hidl_vec& /* slotStatus */) { return Void(); -} - -/* 1.3 Apis */ -Return RadioConfigResponse::getPhoneCapabilityResponse_1_3( - const RadioResponseInfo& info, const V1_3::PhoneCapability& phoneCapability) { - rspInfo = info; - phoneCap_1_3 = phoneCapability; - parent.notify(info.serial); - return Void(); -} +} \ No newline at end of file From 3639471c93752f3103354f9d4d6f15f3f94d96ba Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Tue, 18 Feb 2020 23:12:24 +0000 Subject: [PATCH 0613/1022] Revert "Set up IRadioConfig 1.3 skeleton" This reverts commit 83e3ca82e6398603df98c4697360e2d66b6efdae. Reason for revert: Change will not be supported by modem, so HAL for RadioConfig is no longer necessary. Change-Id: I2eb83fd2356134ef45a782d99174fdd65f8c5a13 --- .../compatibility_matrix.current.xml | 5 +- radio/config/1.3/Android.bp | 23 ---- radio/config/1.3/IRadioConfig.hal | 31 ----- radio/config/1.3/IRadioConfigIndication.hal | 26 ---- radio/config/1.3/IRadioConfigResponse.hal | 26 ---- radio/config/1.3/default/Android.bp | 28 ---- radio/config/1.3/default/RadioConfig.cpp | 113 ---------------- radio/config/1.3/default/RadioConfig.h | 74 ---------- .../1.3/default/RadioConfigIndication.cpp | 49 ------- .../1.3/default/RadioConfigIndication.h | 59 -------- .../1.3/default/RadioConfigResponse.cpp | 81 ----------- .../config/1.3/default/RadioConfigResponse.h | 77 ----------- ...droid.hardware.radio.config@1.3-service.rc | 7 - .../1.3/default/radio-config-default.xml | 29 ---- radio/config/1.3/default/service.cpp | 41 ------ radio/config/1.3/types.hal | 17 --- radio/config/1.3/vts/functional/Android.bp | 35 ----- .../VtsHalRadioConfigV1_3TargetTest.cpp | 23 ---- .../functional/radio_config_hidl_hal_api.cpp | 19 --- .../functional/radio_config_hidl_hal_test.cpp | 58 -------- .../functional/radio_config_hidl_hal_utils.h | 128 ------------------ .../vts/functional/radio_config_response.cpp | 65 --------- 22 files changed, 4 insertions(+), 1010 deletions(-) delete mode 100644 radio/config/1.3/Android.bp delete mode 100644 radio/config/1.3/IRadioConfig.hal delete mode 100644 radio/config/1.3/IRadioConfigIndication.hal delete mode 100644 radio/config/1.3/IRadioConfigResponse.hal delete mode 100644 radio/config/1.3/default/Android.bp delete mode 100644 radio/config/1.3/default/RadioConfig.cpp delete mode 100644 radio/config/1.3/default/RadioConfig.h delete mode 100644 radio/config/1.3/default/RadioConfigIndication.cpp delete mode 100644 radio/config/1.3/default/RadioConfigIndication.h delete mode 100644 radio/config/1.3/default/RadioConfigResponse.cpp delete mode 100644 radio/config/1.3/default/RadioConfigResponse.h delete mode 100644 radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc delete mode 100644 radio/config/1.3/default/radio-config-default.xml delete mode 100644 radio/config/1.3/default/service.cpp delete mode 100644 radio/config/1.3/types.hal delete mode 100644 radio/config/1.3/vts/functional/Android.bp delete mode 100644 radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp delete mode 100644 radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp delete mode 100644 radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp delete mode 100644 radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h delete mode 100644 radio/config/1.3/vts/functional/radio_config_response.cpp diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 3c1a8101fd..f1db89dcba 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -375,7 +375,10 @@ android.hardware.radio.config - 1.3 + + 1.1 IRadioConfig default diff --git a/radio/config/1.3/Android.bp b/radio/config/1.3/Android.bp deleted file mode 100644 index 88de666618..0000000000 --- a/radio/config/1.3/Android.bp +++ /dev/null @@ -1,23 +0,0 @@ -// This file is autogenerated by hidl-gen -Landroidbp. - -hidl_interface { - name: "android.hardware.radio.config@1.3", - root: "android.hardware", - vndk: { - enabled: true, - }, - srcs: [ - "types.hal", - "IRadioConfig.hal", - "IRadioConfigIndication.hal", - "IRadioConfigResponse.hal", - ], - interfaces: [ - "android.hardware.radio.config@1.0", - "android.hardware.radio.config@1.1", - "android.hardware.radio.config@1.2", - "android.hardware.radio@1.0", - "android.hidl.base@1.0", - ], - gen_java: true, -} diff --git a/radio/config/1.3/IRadioConfig.hal b/radio/config/1.3/IRadioConfig.hal deleted file mode 100644 index a0ce6e089d..0000000000 --- a/radio/config/1.3/IRadioConfig.hal +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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. - */ - -package android.hardware.radio.config@1.3; - -import @1.1::IRadioConfig; - -/** - * This interface is used by telephony and telecom to talk to cellular radio for the purpose of - * radio configuration, and it is not associated with any specific modem or slot. - * All the functions have minimum one parameter: - * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the - * duration of a method call. If clients provide colliding serials (including passing the same - * serial to different methods), multiple responses (one for each method call) must still be served. - */ -interface IRadioConfig extends @1.1::IRadioConfig { - -}; diff --git a/radio/config/1.3/IRadioConfigIndication.hal b/radio/config/1.3/IRadioConfigIndication.hal deleted file mode 100644 index 9ef496c4ba..0000000000 --- a/radio/config/1.3/IRadioConfigIndication.hal +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ - -package android.hardware.radio.config@1.3; - -import @1.2::IRadioConfigIndication; - -/** - * Interface declaring unsolicited radio config indications. - */ -interface IRadioConfigIndication extends @1.2::IRadioConfigIndication { - -}; diff --git a/radio/config/1.3/IRadioConfigResponse.hal b/radio/config/1.3/IRadioConfigResponse.hal deleted file mode 100644 index 9c4c971f9f..0000000000 --- a/radio/config/1.3/IRadioConfigResponse.hal +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ - -package android.hardware.radio.config@1.3; - -import @1.2::IRadioConfigResponse; - -/** - * Interface declaring response functions to solicited radio config requests. - */ -interface IRadioConfigResponse extends @1.2::IRadioConfigResponse { - -}; diff --git a/radio/config/1.3/default/Android.bp b/radio/config/1.3/default/Android.bp deleted file mode 100644 index 163c5c5d63..0000000000 --- a/radio/config/1.3/default/Android.bp +++ /dev/null @@ -1,28 +0,0 @@ -cc_binary { - name: "android.hardware.radio.config@1.3-service", - init_rc: ["android.hardware.radio.config@1.3-service.rc"], - relative_install_path: "hw", - vintf_fragments: ["radio-config-default.xml"], - vendor: true, - srcs: [ - "RadioConfig.cpp", - "RadioConfigIndication.cpp", - "RadioConfigResponse.cpp", - "service.cpp", - ], - shared_libs: [ - "libhidlbase", - "liblog", - "libutils", - "android.hardware.radio.config@1.0", - "android.hardware.radio.config@1.1", - "android.hardware.radio.config@1.2", - "android.hardware.radio.config@1.3", - "android.hardware.radio@1.0", - "android.hardware.radio@1.1", - "android.hardware.radio@1.2", - "android.hardware.radio@1.3", - "android.hardware.radio@1.4", - "android.hardware.radio@1.5", - ], -} diff --git a/radio/config/1.3/default/RadioConfig.cpp b/radio/config/1.3/default/RadioConfig.cpp deleted file mode 100644 index c28119c311..0000000000 --- a/radio/config/1.3/default/RadioConfig.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.1 (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.1 - * - * 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 "RadioConfig.h" - -namespace android { -namespace hardware { -namespace radio { -namespace config { -namespace V1_3 { -namespace implementation { - -using namespace ::android::hardware::radio::V1_0; -using namespace ::android::hardware::radio::config; - -// Methods from ::android::hardware::radio::config::V1_0::IRadioConfig follow. -Return RadioConfig::setResponseFunctions( - const sp& radioConfigResponse, - const sp& radioConfigIndication) { - mRadioConfigResponse = radioConfigResponse; - mRadioConfigIndication = radioConfigIndication; - - mRadioConfigResponseV1_3 = - V1_3::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr); - mRadioConfigIndicationV1_3 = - V1_3::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr); - if (mRadioConfigResponseV1_3 == nullptr || mRadioConfigIndicationV1_3 == nullptr) { - mRadioConfigResponseV1_3 = nullptr; - mRadioConfigIndicationV1_3 = nullptr; - } - - mRadioConfigResponseV1_2 = - V1_2::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr); - mRadioConfigIndicationV1_2 = - V1_2::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr); - if (mRadioConfigResponseV1_2 == nullptr || mRadioConfigIndicationV1_2 == nullptr) { - mRadioConfigResponseV1_2 = nullptr; - mRadioConfigIndicationV1_2 = nullptr; - } - - mRadioConfigResponseV1_1 = - V1_1::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr); - mRadioConfigIndicationV1_1 = - V1_1::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr); - if (mRadioConfigResponseV1_1 == nullptr || mRadioConfigIndicationV1_1 == nullptr) { - mRadioConfigResponseV1_1 = nullptr; - mRadioConfigIndicationV1_1 = nullptr; - } - - return Void(); -} - -Return RadioConfig::getSimSlotsStatus(int32_t /* serial */) { - hidl_vec slotStatus; - RadioResponseInfo info; - mRadioConfigResponse->getSimSlotsStatusResponse(info, slotStatus); - return Void(); -} - -Return RadioConfig::setSimSlotsMapping(int32_t /* serial */, - const hidl_vec& /* slotMap */) { - RadioResponseInfo info; - mRadioConfigResponse->setSimSlotsMappingResponse(info); - return Void(); -} - -// Methods from ::android::hardware::radio::config::V1_1::IRadioConfig follow. -Return RadioConfig::getPhoneCapability(int32_t /* serial */) { - V1_1::PhoneCapability phoneCapability; - RadioResponseInfo info; - mRadioConfigResponseV1_1->getPhoneCapabilityResponse(info, phoneCapability); - return Void(); -} - -Return RadioConfig::setPreferredDataModem(int32_t /* serial */, uint8_t /* modemId */) { - RadioResponseInfo info; - mRadioConfigResponseV1_1->setPreferredDataModemResponse(info); - return Void(); -} - -Return RadioConfig::setModemsConfig(int32_t /* serial */, - const V1_1::ModemsConfig& /* modemsConfig */) { - RadioResponseInfo info; - mRadioConfigResponseV1_1->setModemsConfigResponse(info); - return Void(); -} - -Return RadioConfig::getModemsConfig(int32_t /* serial */) { - V1_1::ModemsConfig modemsConfig; - RadioResponseInfo info; - mRadioConfigResponseV1_1->getModemsConfigResponse(info, modemsConfig); - return Void(); -} - -} // namespace implementation -} // namespace V1_3 -} // namespace config -} // namespace radio -} // namespace hardware -} // namespace android diff --git a/radio/config/1.3/default/RadioConfig.h b/radio/config/1.3/default/RadioConfig.h deleted file mode 100644 index 00585e6df2..0000000000 --- a/radio/config/1.3/default/RadioConfig.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.1 (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.1 - * - * 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_RADIO_CONFIG_V1_3_RADIOCONFIG_H -#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIG_H - -#include -#include -#include -#include -#include - -namespace android { -namespace hardware { -namespace radio { -namespace config { -namespace V1_3 { -namespace implementation { - -using namespace ::android::hardware::radio::config; - -using ::android::sp; -using ::android::hardware::hidl_array; -using ::android::hardware::hidl_memory; -using ::android::hardware::hidl_string; -using ::android::hardware::hidl_vec; -using ::android::hardware::Return; -using ::android::hardware::Void; - -struct RadioConfig : public V1_3::IRadioConfig { - sp mRadioConfigResponse; - sp mRadioConfigIndication; - sp mRadioConfigResponseV1_1; - sp mRadioConfigIndicationV1_1; - sp mRadioConfigResponseV1_2; - sp mRadioConfigIndicationV1_2; - sp mRadioConfigResponseV1_3; - sp mRadioConfigIndicationV1_3; - - // Methods from ::android::hardware::radio::config::V1_0::IRadioConfig follow. - Return setResponseFunctions( - const sp& radioConfigResponse, - const sp& radioConfigIndication); - Return getSimSlotsStatus(int32_t serial); - Return setSimSlotsMapping(int32_t serial, const hidl_vec& slotMap); - - // Methods from ::android::hardware::radio::config::V1_1::IRadioConfig follow. - Return getPhoneCapability(int32_t serial); - Return setPreferredDataModem(int32_t serial, uint8_t modemId); - Return setModemsConfig(int32_t serial, const V1_1::ModemsConfig& modemsConfig); - Return getModemsConfig(int32_t serial); -}; - -} // namespace implementation -} // namespace V1_3 -} // namespace config -} // namespace radio -} // namespace hardware -} // namespace android - -#endif // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIG_H diff --git a/radio/config/1.3/default/RadioConfigIndication.cpp b/radio/config/1.3/default/RadioConfigIndication.cpp deleted file mode 100644 index eb77a48ec1..0000000000 --- a/radio/config/1.3/default/RadioConfigIndication.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.1 (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.1 - * - * 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 "RadioConfigIndication.h" - -namespace android { -namespace hardware { -namespace radio { -namespace config { -namespace V1_3 { -namespace implementation { - -using namespace ::android::hardware::radio::V1_0; -using namespace ::android::hardware::radio::config::V1_0; -using namespace ::android::hardware::radio::config::V1_2; - -// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigIndication follow. -Return RadioConfigIndication::simSlotsStatusChanged( - RadioIndicationType /* type */, const hidl_vec& /* slotStatus */) { - // TODO implement - return Void(); -} - -// Methods from ::android::hardware::radio::config::V1_2::IRadioConfigIndication follow. -Return RadioConfigIndication::simSlotsStatusChanged_1_2( - RadioIndicationType /* type */, const hidl_vec& /* slotStatus */) { - // TODO implement - return Void(); -} - -} // namespace implementation -} // namespace V1_3 -} // namespace config -} // namespace radio -} // namespace hardware -} // namespace android diff --git a/radio/config/1.3/default/RadioConfigIndication.h b/radio/config/1.3/default/RadioConfigIndication.h deleted file mode 100644 index 3697492375..0000000000 --- a/radio/config/1.3/default/RadioConfigIndication.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.1 (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.1 - * - * 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_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H -#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H - -#include -#include -#include - -namespace android { -namespace hardware { -namespace radio { -namespace config { -namespace V1_3 { -namespace implementation { - -using namespace ::android::hardware::radio::V1_0; -using namespace ::android::hardware::radio::config; - -using ::android::sp; -using ::android::hardware::hidl_array; -using ::android::hardware::hidl_memory; -using ::android::hardware::hidl_string; -using ::android::hardware::hidl_vec; -using ::android::hardware::Return; -using ::android::hardware::Void; - -struct RadioConfigIndication : public IRadioConfigIndication { - // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigIndication follow. - Return simSlotsStatusChanged(RadioIndicationType type, - const hidl_vec& slotStatus) override; - - // Methods from ::android::hardware::radio::config::V1_2::IRadioConfigIndication follow. - Return simSlotsStatusChanged_1_2( - RadioIndicationType type, const hidl_vec& slotStatus) override; -}; - -} // namespace implementation -} // namespace V1_3 -} // namespace config -} // namespace radio -} // namespace hardware -} // namespace android - -#endif // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H diff --git a/radio/config/1.3/default/RadioConfigResponse.cpp b/radio/config/1.3/default/RadioConfigResponse.cpp deleted file mode 100644 index 48e81dade3..0000000000 --- a/radio/config/1.3/default/RadioConfigResponse.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.1 (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.1 - * - * 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 "RadioConfigResponse.h" - -namespace android { -namespace hardware { -namespace radio { -namespace config { -namespace V1_3 { -namespace implementation { - -using namespace ::android::hardware::radio::V1_0; -using namespace ::android::hardware::radio::config::V1_0; -using namespace ::android::hardware::radio::config::V1_1; -using namespace ::android::hardware::radio::config::V1_2; - -// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow. -Return RadioConfigResponse::getSimSlotsStatusResponse( - const RadioResponseInfo& /* info */, - const hidl_vec& /* slotStatus */) { - // TODO implement - return Void(); -} - -Return RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponseInfo& /* info */) { - // TODO implement - return Void(); -} - -// Methods from ::android::hardware::radio::config::V1_1::IRadioConfigResponse follow. -Return RadioConfigResponse::getPhoneCapabilityResponse( - const RadioResponseInfo& /* info */, const V1_1::PhoneCapability& /* phoneCapability */) { - // TODO implement - return Void(); -} - -Return RadioConfigResponse::setPreferredDataModemResponse( - const RadioResponseInfo& /* info */) { - // TODO implement - return Void(); -} - -Return RadioConfigResponse::setModemsConfigResponse(const RadioResponseInfo& /* info */) { - // TODO implement - return Void(); -} - -Return RadioConfigResponse::getModemsConfigResponse( - const RadioResponseInfo& /* info */, const V1_1::ModemsConfig& /* modemsConfig */) { - // TODO implement - return Void(); -} - -// Methods from ::android::hardware::radio::config::V1_2::IRadioConfigResponse follow. -Return RadioConfigResponse::getSimSlotsStatusResponse_1_2( - const RadioResponseInfo& /* info */, - const hidl_vec& /* slotStatus */) { - // TODO implement - return Void(); -} - -} // namespace implementation -} // namespace V1_3 -} // namespace config -} // namespace radio -} // namespace hardware -} // namespace android diff --git a/radio/config/1.3/default/RadioConfigResponse.h b/radio/config/1.3/default/RadioConfigResponse.h deleted file mode 100644 index 0f0033fa6a..0000000000 --- a/radio/config/1.3/default/RadioConfigResponse.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.1 (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.1 - * - * 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_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H -#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H - -#include -#include -#include - -namespace android { -namespace hardware { -namespace radio { -namespace config { -namespace V1_3 { -namespace implementation { - -using ::android::sp; -using ::android::hardware::hidl_array; -using ::android::hardware::hidl_memory; -using ::android::hardware::hidl_string; -using ::android::hardware::hidl_vec; -using ::android::hardware::Return; -using ::android::hardware::Void; - -struct RadioConfigResponse : public IRadioConfigResponse { - // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow. - Return getSimSlotsStatusResponse( - const ::android::hardware::radio::V1_0::RadioResponseInfo& info, - const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus) - override; - Return setSimSlotsMappingResponse( - const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override; - - // Methods from ::android::hardware::radio::config::V1_1::IRadioConfigResponse follow. - Return getPhoneCapabilityResponse( - const ::android::hardware::radio::V1_0::RadioResponseInfo& info, - const ::android::hardware::radio::config::V1_1::PhoneCapability& phoneCapability) - override; - Return setPreferredDataModemResponse( - const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override; - Return setModemsConfigResponse( - const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override; - Return getModemsConfigResponse( - const ::android::hardware::radio::V1_0::RadioResponseInfo& info, - const ::android::hardware::radio::config::V1_1::ModemsConfig& modemsConfig) override; - - // Methods from ::android::hardware::radio::config::V1_2::IRadioConfigResponse follow. - Return getSimSlotsStatusResponse_1_2( - const ::android::hardware::radio::V1_0::RadioResponseInfo& info, - const hidl_vec<::android::hardware::radio::config::V1_2::SimSlotStatus>& slotStatus) - override; - - // Methods from ::android::hidl::base::V1_0::IBase follow. -}; - -} // namespace implementation -} // namespace V1_3 -} // namespace config -} // namespace radio -} // namespace hardware -} // namespace android - -#endif // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H diff --git a/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc b/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc deleted file mode 100644 index 6df9b52ba5..0000000000 --- a/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc +++ /dev/null @@ -1,7 +0,0 @@ -service vendor.radio-config-hal-1-3 /vendor/bin/hw/android.hardware.radio.config@1.3-service - interface android.hardware.radio.config@1.0::IRadioConfig default - interface android.hardware.radio.config@1.1::IRadioConfig default - interface android.hardware.radio.config@1.3::IRadioConfig default - class hal - user system - group system diff --git a/radio/config/1.3/default/radio-config-default.xml b/radio/config/1.3/default/radio-config-default.xml deleted file mode 100644 index 72f363e30f..0000000000 --- a/radio/config/1.3/default/radio-config-default.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - android.hardware.radio.config - hwbinder - 1.3 - - IRadioConfig - default - - - diff --git a/radio/config/1.3/default/service.cpp b/radio/config/1.3/default/service.cpp deleted file mode 100644 index b1e67366e9..0000000000 --- a/radio/config/1.3/default/service.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.1 (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.1 - * - * 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 "android.hardware.radio.config@1.3-service" - -#include -#include - -#include "RadioConfig.h" - -using android::OK; -using android::sp; -using android::status_t; -using android::hardware::configureRpcThreadpool; -using android::hardware::joinRpcThreadpool; -using android::hardware::radio::config::V1_3::IRadioConfig; -using android::hardware::radio::config::V1_3::implementation::RadioConfig; - -int main() { - configureRpcThreadpool(1, true); - sp radioConfig = new RadioConfig; - const status_t status = radioConfig->registerAsService(); - ALOGW_IF(status != OK, "Could not register IRadioConfig 1.3"); - ALOGD("Default service is ready."); - - joinRpcThreadpool(); - return 1; -} diff --git a/radio/config/1.3/types.hal b/radio/config/1.3/types.hal deleted file mode 100644 index 866002acad..0000000000 --- a/radio/config/1.3/types.hal +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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. - */ - -package android.hardware.radio.config@1.3; diff --git a/radio/config/1.3/vts/functional/Android.bp b/radio/config/1.3/vts/functional/Android.bp deleted file mode 100644 index 6b28faf7a0..0000000000 --- a/radio/config/1.3/vts/functional/Android.bp +++ /dev/null @@ -1,35 +0,0 @@ -// -// 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. -// - -cc_test { - name: "VtsHalRadioConfigV1_3TargetTest", - defaults: ["VtsHalTargetTestDefaults"], - srcs: [ - "radio_config_hidl_hal_api.cpp", - "radio_config_hidl_hal_test.cpp", - "radio_config_response.cpp", - "VtsHalRadioConfigV1_3TargetTest.cpp", - ], - static_libs: [ - "RadioVtsTestUtilBase", - "android.hardware.radio.config@1.0", - "android.hardware.radio.config@1.1", - "android.hardware.radio.config@1.2", - "android.hardware.radio.config@1.3", - ], - header_libs: ["radio.util.header@1.0"], - test_suites: ["general-tests", "vts-core"], -} diff --git a/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp b/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp deleted file mode 100644 index 3bacacf63c..0000000000 --- a/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#include - -INSTANTIATE_TEST_SUITE_P( - PerInstance, RadioConfigHidlTest, - testing::ValuesIn(android::hardware::getAllHalInstanceNames( - ::android::hardware::radio::config::V1_3::IRadioConfig::descriptor)), - android::hardware::PrintInstanceNameToString); diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp deleted file mode 100644 index 07e9eded5a..0000000000 --- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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. - */ - -#include - -#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp deleted file mode 100644 index dbb4bf44e3..0000000000 --- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ - -#include - -void RadioConfigHidlTest::SetUp() { - radioConfig = ::android::hardware::radio::config::V1_3::IRadioConfig::getService(GetParam()); - ASSERT_NE(nullptr, radioConfig.get()); - - radioConfigRsp = new (std::nothrow) RadioConfigResponse(*this); - ASSERT_NE(nullptr, radioConfigRsp.get()); - - count_ = 0; - - radioConfig->setResponseFunctions(radioConfigRsp, nullptr); -} - -/* - * Notify that the response message is received. - */ -void RadioConfigHidlTest::notify(int receivedSerial) { - std::unique_lock lock(mtx_); - if (serial == receivedSerial) { - count_++; - cv_.notify_one(); - } -} - -/* - * Wait till the response message is notified or till TIMEOUT_PERIOD. - */ -std::cv_status RadioConfigHidlTest::wait() { - std::unique_lock lock(mtx_); - - std::cv_status status = std::cv_status::no_timeout; - auto now = std::chrono::system_clock::now(); - while (count_ == 0) { - status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD)); - if (status == std::cv_status::timeout) { - return status; - } - } - count_--; - return status; -} diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h deleted file mode 100644 index 9b78c04944..0000000000 --- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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. - */ - -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "vts_test_util.h" - -using namespace ::android::hardware::radio::config::V1_1; -using namespace ::android::hardware::radio::config::V1_2; -using namespace ::android::hardware::radio::config::V1_3; - -using ::android::sp; -using ::android::hardware::hidl_string; -using ::android::hardware::hidl_vec; -using ::android::hardware::Return; -using ::android::hardware::Void; - -using ::android::hardware::radio::V1_0::RadioResponseInfo; -using ::android::hardware::radio::V1_0::RadioResponseType; - -#define TIMEOUT_PERIOD 75 - -class RadioConfigHidlTest; - -/* Callback class for radio config response */ -class RadioConfigResponse : public ::android::hardware::radio::config::V1_3::IRadioConfigResponse { - protected: - RadioConfigHidlTest& parent; - - public: - RadioResponseInfo rspInfo; - PhoneCapability phoneCap; - - RadioConfigResponse(RadioConfigHidlTest& parent); - virtual ~RadioConfigResponse() = default; - - /* 1.0 Api */ - Return getSimSlotsStatusResponse( - const RadioResponseInfo& info, - const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus); - - Return setSimSlotsMappingResponse(const RadioResponseInfo& info); - - /* 1.1 Api */ - Return getPhoneCapabilityResponse(const RadioResponseInfo& info, - const PhoneCapability& phoneCapability); - - Return setPreferredDataModemResponse(const RadioResponseInfo& info); - - Return getModemsConfigResponse(const RadioResponseInfo& info, - const ModemsConfig& mConfig); - - Return setModemsConfigResponse(const RadioResponseInfo& info); - - /* 1.2 Api */ - Return getSimSlotsStatusResponse_1_2(const RadioResponseInfo& info, - const hidl_vec& slotStatus); -}; - -/* Callback class for radio config indication */ -class RadioConfigIndication - : public ::android::hardware::radio::config::V1_3::IRadioConfigIndication { - protected: - RadioConfigHidlTest& parent; - - public: - RadioConfigIndication(RadioConfigHidlTest& parent); - virtual ~RadioConfigIndication() = default; - - /* 1.2 Api */ - Return simSlotsStatusChanged_1_2( - ::android::hardware::radio::V1_0::RadioIndicationType type, - const hidl_vec& slotStatus); -}; - -// The main test class for Radio config HIDL. -class RadioConfigHidlTest : public ::testing::TestWithParam { - protected: - std::mutex mtx_; - std::condition_variable cv_; - int count_; - - public: - virtual void SetUp() override; - - /* Used as a mechanism to inform the test about data/event callback */ - void notify(int receivedSerial); - - /* Test code calls this function to wait for response */ - std::cv_status wait(); - - void updateSimCardStatus(); - - /* Serial number for radio request */ - int serial; - - /* radio config service handle */ - sp<::android::hardware::radio::config::V1_3::IRadioConfig> radioConfig; - - /* radio config response handle */ - sp radioConfigRsp; -}; diff --git a/radio/config/1.3/vts/functional/radio_config_response.cpp b/radio/config/1.3/vts/functional/radio_config_response.cpp deleted file mode 100644 index 1ca960eae9..0000000000 --- a/radio/config/1.3/vts/functional/radio_config_response.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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. - */ - -#include - -using ::android::hardware::radio::V1_0::RadioResponseInfo; - -// SimSlotStatus slotStatus; - -RadioConfigResponse::RadioConfigResponse(RadioConfigHidlTest& parent) : parent(parent) {} - -/* 1.0 Apis */ -Return RadioConfigResponse::getSimSlotsStatusResponse( - const RadioResponseInfo& /* info */, - const ::android::hardware::hidl_vec< - ::android::hardware::radio::config::V1_0::SimSlotStatus>& /* slotStatus */) { - return Void(); -} - -Return RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponseInfo& /* info */) { - return Void(); -} - -/* 1.1 Apis */ -Return RadioConfigResponse::getPhoneCapabilityResponse( - const RadioResponseInfo& info, const PhoneCapability& phoneCapability) { - rspInfo = info; - phoneCap = phoneCapability; - parent.notify(info.serial); - return Void(); -} - -Return RadioConfigResponse::setPreferredDataModemResponse( - const RadioResponseInfo& /* info */) { - return Void(); -} - -Return RadioConfigResponse::getModemsConfigResponse(const RadioResponseInfo& /* info */, - const ModemsConfig& /* mConfig */) { - return Void(); -} - -Return RadioConfigResponse::setModemsConfigResponse(const RadioResponseInfo& /* info */) { - return Void(); -} - -/* 1.2 Apis */ -Return RadioConfigResponse::getSimSlotsStatusResponse_1_2( - const RadioResponseInfo& /* info */, - const ::android::hardware::hidl_vec& /* slotStatus */) { - return Void(); -} \ No newline at end of file From 496b86ccbb957357a794f08d62d643ce950da3f6 Mon Sep 17 00:00:00 2001 From: Tanmay Patil Date: Tue, 7 Jan 2020 17:50:23 -0800 Subject: [PATCH 0614/1022] Adds HAL for ultrasonics to EVS 1.1 - Adds new structs in types.h - Adds two new .hal IEvsUltrasonicsArray and IEvsUltrasonicsArrayStream - Adds new APIs calls in IEvsEnumerator - Adds empty default implementation for all Bug: 148619310 Test: Build and functionality tested with demo app. Change-Id: I8b501c7328d4c02cc694b5a2c73a519ca6d87710 --- automotive/evs/1.1/Android.bp | 2 + automotive/evs/1.1/IEvsEnumerator.hal | 32 ++- automotive/evs/1.1/IEvsUltrasonicsArray.hal | 81 ++++++++ .../evs/1.1/IEvsUltrasonicsArrayStream.hal | 40 ++++ automotive/evs/1.1/default/EvsEnumerator.cpp | 22 ++ automotive/evs/1.1/default/EvsEnumerator.h | 5 + automotive/evs/1.1/types.hal | 191 ++++++++++++++++++ 7 files changed, 372 insertions(+), 1 deletion(-) create mode 100644 automotive/evs/1.1/IEvsUltrasonicsArray.hal create mode 100644 automotive/evs/1.1/IEvsUltrasonicsArrayStream.hal diff --git a/automotive/evs/1.1/Android.bp b/automotive/evs/1.1/Android.bp index 17f31e4dd0..f9bccef5fe 100644 --- a/automotive/evs/1.1/Android.bp +++ b/automotive/evs/1.1/Android.bp @@ -12,6 +12,8 @@ hidl_interface { "IEvsCameraStream.hal", "IEvsDisplay.hal", "IEvsEnumerator.hal", + "IEvsUltrasonicsArray.hal", + "IEvsUltrasonicsArrayStream.hal", ], interfaces: [ "android.frameworks.automotive.display@1.0", diff --git a/automotive/evs/1.1/IEvsEnumerator.hal b/automotive/evs/1.1/IEvsEnumerator.hal index 84dd21f92a..d604e4f1f6 100644 --- a/automotive/evs/1.1/IEvsEnumerator.hal +++ b/automotive/evs/1.1/IEvsEnumerator.hal @@ -18,12 +18,13 @@ package android.hardware.automotive.evs@1.1; import IEvsCamera; import IEvsDisplay; +import IEvsUltrasonicsArray; import @1.0::IEvsEnumerator; import @1.0::EvsResult; import android.hardware.camera.device@3.2::Stream; /** - * Provides the mechanism for EVS camera discovery + * Provides the mechanism for EVS camera and ultrasonics array discovery */ interface IEvsEnumerator extends @1.0::IEvsEnumerator { /** @@ -76,4 +77,33 @@ interface IEvsEnumerator extends @1.0::IEvsEnumerator { * @return display EvsDisplay object to be used. */ openDisplay_1_1(uint8_t id) generates (IEvsDisplay display); + + /** + * Returns a list of all ultrasonics array available to the system. + * Will return an empty vector if ultrasonics is not supported. + * + * @return ultrasonicsArrays A list of ultrasonics available for EVS service. + */ + getUltrasonicsArrayList() generates (vec ultrasonicsArrays); + + /** + * Gets the IEvsUltrasonicsArray associated with a ultrasonicsArrayId from a + * UltrasonicsDataDesc + * + * @param ultrasonicsArrayId A unique identifier of the ultrasonic array. + * @return evsUltrasonicsArray IEvsUltrasonicsArray object associated with a + * given ultrasonicsArrayId. + */ + openUltrasonicsArray(string ultrasonicsArrayId) generates ( + IEvsUltrasonicsArray evsUltrasonicsArray); + + /** + * Return the specified IEvsUltrasonicsArray interface as no longer in use + * + * When the IEvsUltrasonicsArray object is no longer required, it must be released. + * NOTE: Data streaming must be cleanly stopped before making this call. + * + * @param evsUltrasonicsArray EvsUltrasonics array object to be closed. + */ + closeUltrasonicsArray(IEvsUltrasonicsArray evsUltrasonicsArray); }; diff --git a/automotive/evs/1.1/IEvsUltrasonicsArray.hal b/automotive/evs/1.1/IEvsUltrasonicsArray.hal new file mode 100644 index 0000000000..ae4f94144c --- /dev/null +++ b/automotive/evs/1.1/IEvsUltrasonicsArray.hal @@ -0,0 +1,81 @@ +/* + * Copyright 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. + */ + +package android.hardware.automotive.evs@1.1; + +import @1.0::EvsResult; +import UltrasonicsArrayDesc; +import UltrasonicsDataFrameDesc; +import IEvsUltrasonicsArrayStream; + +/** + * HAL interface for ultrasonics sensor array. + */ +interface IEvsUltrasonicsArray { + /** + * Returns the ultrasonic sensor array information. + * + * @return info The description of this ultrasonic array. This must be the + * same value as reported by IEvsEnumerator::getUltrasonicsArrayList(). + */ + getUltrasonicArrayInfo() generates (UltrasonicsArrayDesc info); + + /** + * Specifies the depth of the buffer chain the ultrasonic sensors is + * asked to support. + * + * Up to this many data frames may be held concurrently by the client of IEvsUltrasonicsArray. + * If this many frames have been delivered to the receiver without being returned + * by doneWithFrame, the stream must skip frames until a buffer is returned for reuse. + * It is legal for this call to come at any time, even while streams are already running, + * in which case buffers should be added or removed from the chain as appropriate. + * If no call is made to this entry point, the IEvsUltrasonicsArray must support at least one + * data frame by default. More is acceptable. + * + * @param bufferCount Number of buffers the client of + * IEvsUltrasonicsArray may hold concurrently. + * @return result EvsResult::OK is returned if this call is successful. + * Will return EvsResult::INVALID_ARG on invalid bufferCount. + */ + setMaxFramesInFlight(uint32_t bufferCount) generates (EvsResult result); + + /** + * Requests to start the stream. + * + * @param stream Implementation of IEvsUltrasonicsArrayStream. + * @return result EvsResult::OK is returned if this call is successful. Returns + * EvsResult::STREAM_ALREADY_RUNNING if stream is already running. + */ + startStream(IEvsUltrasonicsArrayStream stream) generates (EvsResult result); + + /** + * Requests to stop the delivery of the ultrasonic array data frames. + * + * Because delivery is asynchronous, frames may continue to arrive for + * some time after this call returns. Each must be returned until the + * closure of the stream is signaled to the IEvsCameraStream. + * This function cannot fail and is ignored if the stream isn't running. + */ + stopStream(); + + /** + * Notifies the UltrasonicsDataDesc is consumed that was received from + * IEvsUltrasonicsArrayStream. + * + * @param dataFrameDesc Ultrasonics data descriptor. + */ + doneWithDataFrame(UltrasonicsDataFrameDesc dataFrameDesc); +}; diff --git a/automotive/evs/1.1/IEvsUltrasonicsArrayStream.hal b/automotive/evs/1.1/IEvsUltrasonicsArrayStream.hal new file mode 100644 index 0000000000..f95209fe68 --- /dev/null +++ b/automotive/evs/1.1/IEvsUltrasonicsArrayStream.hal @@ -0,0 +1,40 @@ +/* + * Copyright 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. + */ + +package android.hardware.automotive.evs@1.1; + +import UltrasonicsDataFrameDesc; +import @1.1::EvsEventDesc; + +/** + * Implemented on client side to receive asynchronous ultrasonic data + * deliveries. + */ +interface IEvsUltrasonicsArrayStream { + /** + * Receives calls from the HAL each time a data frame is ready. + * + * @param dataFrameDesc Ultrasonic array data frame descriptor. + */ + oneway deliverDataFrame(UltrasonicsDataFrameDesc dataFrameDesc); + + /** + * Receives calls from the HAL each time an event happens. + * + * @param event Event EVS event with possible event information. + */ + oneway notify(EvsEventDesc event); +}; diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp index 0319560ee6..415841cc80 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.cpp +++ b/automotive/evs/1.1/default/EvsEnumerator.cpp @@ -355,6 +355,28 @@ EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& ca return pRecord; } +// TODO(b/148608401): Add default implementation with dummy data. +Return EvsEnumerator::getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) { + hidl_vec ultrasonicsArrayDesc; + _hidl_cb(ultrasonicsArrayDesc); + return Void(); +} + +// TODO(b/148608401): Add default implementation with dummy data. +Return> EvsEnumerator::openUltrasonicsArray( + const hidl_string& ultrasonicsArrayId) { + (void)ultrasonicsArrayId; + sp pEvsUltrasonicsArray; + return pEvsUltrasonicsArray; +} + +// TODO(b/148608401): Add default implementation with dummy data. +Return EvsEnumerator::closeUltrasonicsArray( + const ::android::sp& evsUltrasonicsArray) { + (void)evsUltrasonicsArray; + return Void(); +} + } // namespace implementation } // namespace V1_1 } // namespace evs diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h index 9415953a27..12fd0189de 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.h +++ b/automotive/evs/1.1/default/EvsEnumerator.h @@ -65,6 +65,11 @@ public: Return isHardware() override { return true; } Return getDisplayIdList(getDisplayIdList_cb _list_cb) override; Return> openDisplay_1_1(uint8_t port) override; + Return getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) override; + Return> openUltrasonicsArray( + const hidl_string& ultrasonicsArrayId) override; + Return closeUltrasonicsArray( + const ::android::sp& evsUltrasonicsArray) override; // Implementation details EvsEnumerator(sp windowService = nullptr); diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal index aafdb70db3..b34e7e7d65 100644 --- a/automotive/evs/1.1/types.hal +++ b/automotive/evs/1.1/types.hal @@ -177,3 +177,194 @@ enum CameraParam : uint32_t { */ ABSOLUTE_ZOOM, }; + +/** + * Structure identifies and describes an ultrasonics array in the car. + * + * A ultrasonics array represents a group of ultrasonic sensors within the + * car. These may be sensors that are physically connected to the same hardware + * control unit or represent a logical group of sensors like front and back. + * The HAL is responsible for filling out this structure for each Ultrasonics + * Array. + */ +struct UltrasonicsArrayDesc { + /** + * Unique identifier for the ultrasonic array. This may be a path or name of the + * physical control device or a string identifying a logical group of sensors forming an array + * such as "front_array" and "back_array". + */ + string ultrasonicsArrayId; + + /** + * Maximum number of readings (points on waveform) provided per sensor in + * each data frame. Used by client to pre-allocate required memory buffer for + * incoming data. + */ + uint32_t maxReadingsPerSensorCount; + + /** + * Maximum number of receiver sensors in a data frame. Must be between 1 + * and sensorCount. Used by client to pre-allocate required memory buffer for + * incoming data. + */ + uint32_t maxReceiversCount; + + /** + * The order of sensors specified should preferably be in clockwise order + * around the car, starting from front left-most sensor. + */ + vec sensors; +}; + +/** + * Structure for rotation expressed as quaternions. + * Convention used: Unit quaternion with hamilton convention. + */ +struct RotationQuat { + float x; + float y; + float z; + float w; +}; + +/** Structure for translation with x, y and z units. */ +struct Translation { + float x; + float y; + float z; +}; + +/** + * Provides the orientation and location of a car sensor relative to the android automotive + * coordinate system: + * https://source.android.com/devices/sensors/sensor-types#auto_axes + * The sensor pose defines the transformation to be applied to the android automotive axes to + * obtain the sensor local axes. + * The pose consists of rotation, (specified as a quaternions) and translation + * (vector with x, y, z). + * This rotation and translation applied to the sensor data in the sensor's local coordinate + * system transform the data to the automotive coordinate system. + * i.e Pcar = ( Rot * Psensor ) + Trans + * Here Pcar is a point in automotive coordinate system and Psensor is a point in the sensor's + * coordinate system. + * Example: + * For a sensor on the front bumper and on the left corner of the car with its X axis pointing to + * the front, the sensor is located at (-2, 4, 0) meters w.r.t android automotive axes and the + * sensor local axes has a rotation of 90 degrees counter-clockwise w.r.t android automotive axes + * when viewing the car from top on the +Z axis side: + * + * ↑X sensor + * Y←∘______ + * | | front + * | car | + * | ↑Y | + * | ∘→X | rear + * |______| + * + * For this example the rotation and translation will be: + * Rotation = + 90 degrees around Z axis = (0.7071, 0, 0, 0.7071) as a unit quaternion. + * Translation = (-2, 4, 0) in meters = (-2000, 4000, 0) in milli-meters. + * Note: Every sensor type must specify its own pose. + */ +struct SensorPose { + /** + * Rotation part of the sensor pose, expressed as a unit quaternion. + */ + RotationQuat rotation; + + /** + * Translation part of the sensor pose, in (x, y, z) format with milli-meter units. + */ + Translation translation; +}; + +/** + * Structure that contains all information of an ultrasonic sensor. + */ +struct UltrasonicSensor { + /** + * Pose provides the orientation and location of the ultrasonic sensor within the car. + * The +Y axis points along the center of the beam spread the X axis to the right and the Z + * axis in the up direction. + */ + SensorPose pose; + + /** + * Maximum range of the sensor in milli-metres. + */ + float maxRange; + + /** + * Half-angle of the angle of measurement of the sensor, relative to the + * sensor’s x axis, in radians. + */ + float angleOfMeasurement; +}; + +/** + * Structure that describes the data frame received from an ultrasonics array. + * + * Each data frame returned consists of received waveform signals from a subset + * of sensors in an array as indicated by the receiversIdList. The signal is + * transmitted at a particular time instant indicated by timestampNs from a + * subset of sensors in the array as provided in the transmittersIdList. + */ +struct UltrasonicsDataFrameDesc { + /** + * Timestamp of the start of the transmit signal for this data frame. + * Timestamp unit is nanoseconds and is obtained from android elapsed realtime clock which is + * the time since system was booted and includes deep sleep. + * timeOfFlight readings are future-deltas to this timestamp. + */ + uint64_t timestampNs; + + /** + * Identifier of data frame. Used by implementation for managing multiple frames in flight. + */ + uint32_t dataFrameId; + + /** + * List of indexes of sensors in range [0, sensorCount - 1] that + * transmitted the signal for this data frame. + */ + vec transmittersIdList; + + /** + * List of indexes of sensors in range [0, sensorCount - 1] that received + * the signal. The order of ids must match the order of the waveforms in the + * waveformsData. + * Size of list is upper bound by maxReceiversCount. + */ + vec receiversIdList; + + /** + * List of the number of readings corresponding to each ultrasonics sensor in + * the receiversIdList. Order of the readings count must match the order in + * receiversIdList. + * Size of list is upper bound by maxReadingsPerSensorCount. + */ + vec receiversReadingsCountList; + + /** + * Shared memory object containing the waveforms data. Contains one waveform + * for each sensor specified in receiversIdList, in order. + * Each waveform is represented by a number of readings, which are sample + * points on the waveform. The number of readings for each waveform is as + * specified in the receiversReadingsCountList. + * Each reading is a pair of time Of flight and resonance. + * Time of flight (float): Time between transmit and receive signal in nanoseconds. + * Resonance (float): Resonance at time on waveform in range [0.0, 1.0]. + * + * The structure of shared memory (example with 2 waveforms, each with 2 readings): + * + * Byte: | 0 | 1-4 | 5-8 | 9-12 | 13-16 || 17 | 18-21 | 22-25 | 26-29 | 30-33 | + * Data: | RecId1 | TOF1 | RES1 | TOF2 | RES2 || RecId2 | TOF1 | RES1 | TOF2 | RES2 | + * | Waveform1 || Waveform2 | + * Here: + * RecId : Receiver's Id. Order matches the receiversIdList, type uint8_t + * TOF : Time of flight, type float (4 bytes) + * RES : Resonance, type float (4 bytes) + * Note: All readings and waveforms are contigious with no padding. + */ + memory waveformsData; +}; From 6678ffd8c5206f8022c4e0987359b778be1700d5 Mon Sep 17 00:00:00 2001 From: Sasha Kuznetsov Date: Wed, 19 Feb 2020 11:55:26 -0800 Subject: [PATCH 0615/1022] Update constellation types in measurement corrections Bug: 147504090 Test: atest VtsHalGnssV2_1TargetTest and manually injecting dummy measurement corrections from GnssLocationProvider and verifying that they are received below the HAL (on a cuttlefish implementation) Change-Id: Ie6df224d63429193b39f06a6b60517f804fccbae --- current.txt | 2 +- .../default/GnssMeasurementCorrections.cpp | 19 +++++------ gnss/common/utils/vts/Utils.cpp | 32 +++++++++++++++---- gnss/common/utils/vts/include/Utils.h | 5 +++ gnss/measurement_corrections/1.1/Android.bp | 1 + gnss/measurement_corrections/1.1/types.hal | 26 ++++++++++++++- 6 files changed, 67 insertions(+), 18 deletions(-) diff --git a/current.txt b/current.txt index 8d14fa3609..609e5ef08c 100644 --- a/current.txt +++ b/current.txt @@ -659,7 +659,7 @@ ba5ac712b2a656dc07c83ab4a7a2c2f3bee1bbcb752e8b8ffa9b672f3b5b0728 android.hardwar 7913a11206a577b12ade86a7cf3f95c2639cb514d086673f279bf99238c9917e android.hardware.gnss@2.1::IGnssMeasurement 0a16e5913e94d995cfcf959a1c6f10b0b8e9dfdb5f45ac6e7244711ddd740272 android.hardware.gnss@2.1::IGnssMeasurementCallback 6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections -a28d6c29a7e36976acffb018208e65b3496d9152d57d864038556cdd83b35744 android.hardware.gnss.measurement_corrections@1.1::types +956c1576ca0d6f11b42980ef59052062836b6763fe973af6cb709da50787f710 android.hardware.gnss.measurement_corrections@1.1::types ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback 3a4e7462a12589bd219599de59663d0ba9915313f45150774780d09f4e114f74 android.hardware.health@2.1::types diff --git a/gnss/2.1/default/GnssMeasurementCorrections.cpp b/gnss/2.1/default/GnssMeasurementCorrections.cpp index 9dedbf6747..accf62b733 100644 --- a/gnss/2.1/default/GnssMeasurementCorrections.cpp +++ b/gnss/2.1/default/GnssMeasurementCorrections.cpp @@ -82,19 +82,20 @@ Return GnssMeasurementCorrections::setCorrections_1_1( static_cast(corrections.v1_0.satCorrections.size()), corrections.hasEnvironmentBearing, corrections.environmentBearingDegrees, corrections.environmentBearingUncertaintyDegrees); - for (auto singleSatCorrection : corrections.v1_0.satCorrections) { + for (auto singleSatCorrection : corrections.satCorrections) { ALOGD("singleSatCorrection = flags: %d, constellation: %d, svid: %d, cfHz: %f, probLos: %f," " epl: %f, eplUnc: %f", - static_cast(singleSatCorrection.singleSatCorrectionFlags), + static_cast(singleSatCorrection.v1_0.singleSatCorrectionFlags), static_cast(singleSatCorrection.constellation), - static_cast(singleSatCorrection.svid), singleSatCorrection.carrierFrequencyHz, - singleSatCorrection.probSatIsLos, singleSatCorrection.excessPathLengthMeters, - singleSatCorrection.excessPathLengthUncertaintyMeters); + static_cast(singleSatCorrection.v1_0.svid), + singleSatCorrection.v1_0.carrierFrequencyHz, singleSatCorrection.v1_0.probSatIsLos, + singleSatCorrection.v1_0.excessPathLengthMeters, + singleSatCorrection.v1_0.excessPathLengthUncertaintyMeters); ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f", - singleSatCorrection.reflectingPlane.latitudeDegrees, - singleSatCorrection.reflectingPlane.longitudeDegrees, - singleSatCorrection.reflectingPlane.altitudeMeters, - singleSatCorrection.reflectingPlane.azimuthDegrees); + singleSatCorrection.v1_0.reflectingPlane.latitudeDegrees, + singleSatCorrection.v1_0.reflectingPlane.longitudeDegrees, + singleSatCorrection.v1_0.reflectingPlane.altitudeMeters, + singleSatCorrection.v1_0.reflectingPlane.azimuthDegrees); } return true; diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp index b6c3f5eccf..4b5a50f5bd 100644 --- a/gnss/common/utils/vts/Utils.cpp +++ b/gnss/common/utils/vts/Utils.cpp @@ -22,7 +22,9 @@ namespace hardware { namespace gnss { namespace common { -using V1_0::GnssConstellationType; +using GnssConstellationType_V1_0 = V1_0::GnssConstellationType; +using GnssConstellationType_V2_0 = V2_0::GnssConstellationType; + using V1_0::GnssLocationFlags; void Utils::checkLocation(const GnssLocation& location, bool check_speed, @@ -100,12 +102,12 @@ const MeasurementCorrections_1_0 Utils::getMockMeasurementCorrections() { .azimuthDegrees = 203.0, }; - SingleSatCorrection singleSatCorrection1 = { + SingleSatCorrection_V1_0 singleSatCorrection1 = { .singleSatCorrectionFlags = GnssSingleSatCorrectionFlags::HAS_SAT_IS_LOS_PROBABILITY | GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH | GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH_UNC | GnssSingleSatCorrectionFlags::HAS_REFLECTING_PLANE, - .constellation = GnssConstellationType::GPS, + .constellation = GnssConstellationType_V1_0::GPS, .svid = 12, .carrierFrequencyHz = 1.59975e+09, .probSatIsLos = 0.50001, @@ -113,11 +115,11 @@ const MeasurementCorrections_1_0 Utils::getMockMeasurementCorrections() { .excessPathLengthUncertaintyMeters = 25.5, .reflectingPlane = reflectingPlane, }; - SingleSatCorrection singleSatCorrection2 = { + SingleSatCorrection_V1_0 singleSatCorrection2 = { .singleSatCorrectionFlags = GnssSingleSatCorrectionFlags::HAS_SAT_IS_LOS_PROBABILITY | GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH | GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH_UNC, - .constellation = GnssConstellationType::GPS, + .constellation = GnssConstellationType_V1_0::GPS, .svid = 9, .carrierFrequencyHz = 1.59975e+09, .probSatIsLos = 0.873, @@ -125,8 +127,8 @@ const MeasurementCorrections_1_0 Utils::getMockMeasurementCorrections() { .excessPathLengthUncertaintyMeters = 10.0, }; - hidl_vec singleSatCorrections = {singleSatCorrection1, - singleSatCorrection2}; + hidl_vec singleSatCorrections = {singleSatCorrection1, + singleSatCorrection2}; MeasurementCorrections_1_0 mockCorrections = { .latitudeDegrees = 37.4219999, .longitudeDegrees = -122.0840575, @@ -142,11 +144,27 @@ const MeasurementCorrections_1_0 Utils::getMockMeasurementCorrections() { const MeasurementCorrections_1_1 Utils::getMockMeasurementCorrections_1_1() { MeasurementCorrections_1_0 mockCorrections_1_0 = getMockMeasurementCorrections(); + SingleSatCorrection_V1_1 singleSatCorrection1 = { + .v1_0 = mockCorrections_1_0.satCorrections[0], + .constellation = GnssConstellationType_V2_0::IRNSS, + }; + SingleSatCorrection_V1_1 singleSatCorrection2 = { + .v1_0 = mockCorrections_1_0.satCorrections[1], + .constellation = GnssConstellationType_V2_0::IRNSS, + }; + + mockCorrections_1_0.satCorrections[0].constellation = GnssConstellationType_V1_0::UNKNOWN; + mockCorrections_1_0.satCorrections[1].constellation = GnssConstellationType_V1_0::UNKNOWN; + + hidl_vec singleSatCorrections = {singleSatCorrection1, + singleSatCorrection2}; + MeasurementCorrections_1_1 mockCorrections_1_1 = { .v1_0 = mockCorrections_1_0, .hasEnvironmentBearing = true, .environmentBearingDegrees = 45.0, .environmentBearingUncertaintyDegrees = 4.0, + .satCorrections = singleSatCorrections, }; return mockCorrections_1_1; } diff --git a/gnss/common/utils/vts/include/Utils.h b/gnss/common/utils/vts/include/Utils.h index 781ad428eb..c3cdd18b77 100644 --- a/gnss/common/utils/vts/include/Utils.h +++ b/gnss/common/utils/vts/include/Utils.h @@ -29,6 +29,11 @@ using MeasurementCorrections_1_0 = using MeasurementCorrections_1_1 = android::hardware::gnss::measurement_corrections::V1_1::MeasurementCorrections; +using SingleSatCorrection_V1_0 = + android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection; +using SingleSatCorrection_V1_1 = + android::hardware::gnss::measurement_corrections::V1_1::SingleSatCorrection; + namespace android { namespace hardware { namespace gnss { diff --git a/gnss/measurement_corrections/1.1/Android.bp b/gnss/measurement_corrections/1.1/Android.bp index 1d69f20866..d279af6cd2 100644 --- a/gnss/measurement_corrections/1.1/Android.bp +++ b/gnss/measurement_corrections/1.1/Android.bp @@ -12,6 +12,7 @@ hidl_interface { ], interfaces: [ "android.hardware.gnss.measurement_corrections@1.0", + "android.hardware.gnss@2.0", "android.hardware.gnss@1.0", "android.hidl.base@1.0", ], diff --git a/gnss/measurement_corrections/1.1/types.hal b/gnss/measurement_corrections/1.1/types.hal index f945c5785a..e98be1364f 100644 --- a/gnss/measurement_corrections/1.1/types.hal +++ b/gnss/measurement_corrections/1.1/types.hal @@ -17,11 +17,14 @@ package android.hardware.gnss.measurement_corrections@1.1; import @1.0::MeasurementCorrections; +import @1.0::SingleSatCorrection; +import android.hardware.gnss@2.0::GnssConstellationType; /** * A struct containing a set of measurement corrections for all used GNSS satellites at the location * specified by latitudeDegrees, longitudeDegrees, altitudeMeters and at the time of week specified - * toaGpsNanosecondsOfWeek + * toaGpsNanosecondsOfWeek. The v1_0.satCorrections field is deprecated and is no longer used by + * framework. */ struct MeasurementCorrections { @1.0::MeasurementCorrections v1_0; @@ -64,4 +67,25 @@ struct MeasurementCorrections { * before calling this method. The value is undefined if hasEnvironmentBearing is false. */ float environmentBearingUncertaintyDegrees; + + /** + * A set of SingleSatCorrection each containing measurement corrections for a satellite in view + */ + vec satCorrections; +}; + +/** + * A struct with measurement corrections for a single visible satellites, updating the + * GnssConstellationType to 2.0, which supports IRNSS. The v1_0.constellation is deprecated and is + * no longer used by framework. + * + * The bit mask singleSatCorrectionFlags indicates which correction values are valid in the struct + */ +struct SingleSatCorrection { + @1.0::SingleSatCorrection v1_0; + + /** + * Defines the constellation of the given satellite. + */ + GnssConstellationType constellation; }; From 653ea6c3233d20a25c9842da22b55b252c35882d Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Mon, 10 Feb 2020 16:11:54 -0800 Subject: [PATCH 0616/1022] ICameraProvider@2.6: Update mandatory concurrent stream combinations. Bug: 77960042 Test: builds Change-Id: Ic56d6a10ee3521901aae5d8e7289dead7c20b086 Signed-off-by: Jayant Chowdhary --- camera/provider/2.6/ICameraProvider.hal | 32 ++++++++++++++----------- current.txt | 2 +- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/camera/provider/2.6/ICameraProvider.hal b/camera/provider/2.6/ICameraProvider.hal index 0948db6ea3..2c79c279d3 100644 --- a/camera/provider/2.6/ICameraProvider.hal +++ b/camera/provider/2.6/ICameraProvider.hal @@ -38,20 +38,24 @@ interface ICameraProvider extends @2.5::ICameraProvider { * streaming concurrently with the other camera ids in the combination. * * Target 1 Target 2 - * --------------------------------------------- - * | Type | Size | Type | Size | - * --------------------------------------------- - * | YUV | 1280 X 720 | | - * --------------------------------------------- - * | PRIV | 1280 X 720 | | - * --------------------------------------------- - * | YUV | 1280 X 720 | YUV |1280 X 720| - * --------------------------------------------- - * | PRIV | 1280 X 720 | PRIV |1280 X 720| - * --------------------------------------------- - * | PRIV | 1280 X 720 | YUV |1280 X 720| - * --------------------------------------------- - + * ----------------------------------------------------- + * | Type | Size | Type | Size | + * ----------------------------------------------------- + * | YUV | s1440p | | + * ----------------------------------------------------- + * | JPEG | s1440p | | + * ----------------------------------------------------- + * | PRIV | s1440p | | + * ----------------------------------------------------- + * | YUV / PRIV | s720p | YUV / PRIV | s1440p | + * ----------------------------------------------------- + * | YUV / PRIV | s720p | JPEG | s1440p | + * ----------------------------------------------------- + * + * where: + * s720p - min (max output resolution for the given format, 1280 X 720) + * s1440p - min (max output resolution for the given format, 1920 X 1440) + * * @return status Status code for the operation * @return cameraIds a list of camera id combinations that support * concurrent stream configurations with the minimum guarantees diff --git a/current.txt b/current.txt index 29e95fe7ab..aa961a152b 100644 --- a/current.txt +++ b/current.txt @@ -638,7 +638,7 @@ ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardwar 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types b8c63679e1a3874b356f3e691aecce1191d38f59063cf2ed2dce8a9d4cabf00e android.hardware.camera.device@3.6::ICameraDevice -e88840e0558439cb54837514ddccd43877094951758f367e9c638084eb7455a6 android.hardware.camera.provider@2.6::ICameraProvider +5d544a22e5a54568e64f32010eb001fcfbe5547b66cff7f3330da59a23bd4f48 android.hardware.camera.provider@2.6::ICameraProvider 8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas 9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener From 3a0030faabd90a32c3b258094401d25b2eb23544 Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Tue, 18 Feb 2020 11:18:12 -0800 Subject: [PATCH 0617/1022] ICameraProvider@2.6 : Update documentation for getConcurrentStreamingCameraIds. Bug: 148995918 Test: builds Change-Id: I89df3be9e15881e081b76d6c0312bc54da931dea Signed-off-by: Jayant Chowdhary --- camera/provider/2.6/ICameraProvider.hal | 5 +++++ current.txt | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/camera/provider/2.6/ICameraProvider.hal b/camera/provider/2.6/ICameraProvider.hal index 2c79c279d3..9c46ba06f5 100644 --- a/camera/provider/2.6/ICameraProvider.hal +++ b/camera/provider/2.6/ICameraProvider.hal @@ -56,6 +56,11 @@ interface ICameraProvider extends @2.5::ICameraProvider { * s720p - min (max output resolution for the given format, 1280 X 720) * s1440p - min (max output resolution for the given format, 1920 X 1440) * + * 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 + * of camera ids that can stream concurrently, that might have potentially appeared. + * * @return status Status code for the operation * @return cameraIds a list of camera id combinations that support * concurrent stream configurations with the minimum guarantees diff --git a/current.txt b/current.txt index aa961a152b..10129473ca 100644 --- a/current.txt +++ b/current.txt @@ -638,7 +638,7 @@ ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardwar 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types b8c63679e1a3874b356f3e691aecce1191d38f59063cf2ed2dce8a9d4cabf00e android.hardware.camera.device@3.6::ICameraDevice -5d544a22e5a54568e64f32010eb001fcfbe5547b66cff7f3330da59a23bd4f48 android.hardware.camera.provider@2.6::ICameraProvider +daad72a2f482d8a1f660d0e99ac1b78fedb414a4cfbe3fa56b2cd480e5d6f0cb android.hardware.camera.provider@2.6::ICameraProvider 8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas 9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener From f3da9b6c1b5ca2f4dfe1e49d3d122e065a9bceba Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 14 Feb 2020 10:54:28 -0800 Subject: [PATCH 0618/1022] Simplify bus configuration. Previous bus configuration struct was meant for flexibility, but it turned out that the only dimension that flexibility would go was a serial number parameter. Let's rotate that configuration matrix by 90 degrees and just go a straightforward route of discriminating against interface type. Test: VTS Bug: 135918744 Change-Id: I08967d0f78c998b0582958eb51bd387f9dbe15fe --- automotive/can/1.0/ICanController.hal | 149 +++++++++--------- automotive/can/1.0/default/CanBus.cpp | 2 +- automotive/can/1.0/default/CanBusNative.cpp | 2 +- automotive/can/1.0/default/CanBusSlcan.cpp | 2 +- automotive/can/1.0/default/CanController.cpp | 35 ++-- automotive/can/1.0/default/CanController.h | 3 +- automotive/can/1.0/tools/canhalctrl.cpp | 26 ++- .../VtsHalCanBusVirtualV1_0TargetTest.cpp | 8 +- .../VtsHalCanControllerV1_0TargetTest.cpp | 140 ++++++++++------ .../include/can-vts-utils/can-hal-printers.h | 3 +- 10 files changed, 214 insertions(+), 156 deletions(-) diff --git a/automotive/can/1.0/ICanController.hal b/automotive/can/1.0/ICanController.hal index 0c6f53eff3..e32e593655 100644 --- a/automotive/can/1.0/ICanController.hal +++ b/automotive/can/1.0/ICanController.hal @@ -27,51 +27,22 @@ package android.hardware.automotive.can@1.0; */ interface ICanController { /** - * Type of an interface, a mean to express the domain of device address. + * Type of an interface, an equivalent to BusConfig::InterfaceId + * union discriminator. Defines a number of specific standard hardware + * families and a generic catch-all type of {@see INDEXED}. */ enum InterfaceType : uint8_t { - /** - * Virtual SocketCAN interface. - * - * The address is an interface name, such as vcan0. If the interface - * doesn't exist, HAL server must create it. - * - * Valid InterfaceIdentifier types: - * - address. - */ + /** Virtual SocketCAN interface. */ VIRTUAL, - /** - * Native SocketCAN interface. - * - * The address is an interface name, such as can0. - * - * Valid InterfaceIdentifier types: - * - address; - * - serialno. - */ + /** Native SocketCAN interface. */ SOCKETCAN, - /** - * Serial-based interface. - * - * The address is a patch to a device, such as /dev/ttyUSB0. - * - * Valid InterfaceIdentifier types: - * - address; - * - serialno. - */ + /** Serial line CAN interface. */ SLCAN, - /** - * Proprietary interface, specific to the hardware system Android - * is running on. Instead of using address field, the interface is - * addressed with 0-based index. - * - * Valid InterfaceIdentifier types: - * - index - */ - INDEXED + /** Proprietary, device-specific interface. */ + INDEXED, }; enum Result : uint8_t { @@ -92,10 +63,10 @@ interface ICanController { NOT_SUPPORTED, /** - * Provided address (interface name, device path) doesn't exist or there - * is no device with a given serial no. + * Provided interface ID (index, name, device path) doesn't exist or + * there is no device with a given serial number. */ - BAD_ADDRESS, + BAD_INTERFACE_ID, /** Provided bit rate is not supported by the hardware. */ BAD_BITRATE, @@ -106,49 +77,76 @@ interface ICanController { * * ISO TP and CAN FD are currently not supported. */ - struct BusConfiguration { + struct BusConfig { /** * Name under which ICanBus HIDL service should be published. * * It must consist of only alphanumeric characters and underscore * (a-z, A-Z, 0-9, '_'), at least 1 and at most 32 characters long. + * + * This field is *not* meant to distinguish between hardware interfaces + * nor preselect parameters like bitrate. The only intended side-effect + * of changing it should be a different ICanBus HIDL service name and + * the HIDL service should make no assumptions on its contents. */ string name; /** - * Type of the hardware (or virtual) CAN interface. + * Hardware interface configuration. + * + * This union's discriminator has an equivalent enum + * {@see InterfaceType} to express compatibility via + * getSupportedInterfaceTypes(). */ - InterfaceType iftype; + safe_union InterfaceId { + /** Virtual SocketCAN interface. */ + struct Virtual { + /** Interface name, such as vcan0. If the interface doesn't + * exist, HAL server must create it. + */ + string ifname; + } virtualif; - /** - * Identification of hardware interface to configure. - */ - safe_union InterfaceIdentifier { - /** - * Interface name or other mean of identification of the specific - * interface port. Syntax depends on {@see iftype}, for details - * {@see InterfaceType}. - */ - string address; + /** Native SocketCAN interface. */ + safe_union Socketcan { + /** Interface name, such as can0. */ + string ifname; + /** + * Alternatively to providing {@see ifname}, one may provide a + * list of interface serial number suffixes. If there happens to + * be a device (like USB2CAN) with a matching serial number + * suffix, the HAL service will have to select it. + * + * Client may utilize this in two ways: by matching against the + * entire serial number, or the last few characters (usually + * one). The former is better for small-scale test deployments + * (with just a handful of vehicles), the latter is good for + * larger scale (where a small suffix list may support large + * test fleet). + */ + vec serialno; + } socketcan; + + /** Serial line CAN interface. */ + safe_union Slcan { + /** Path to a device, such as /dev/ttyUSB0. */ + string ttyname; + /** + * List of interface serial number suffixes. + * {@see Socketcan::serialno} + */ + vec serialno; + } slcan; /** - * Numerical identifier of interface, used for InterfaceType#INDEXED. - */ - uint8_t index; - - /** - * Alternatively to providing {@see address}, one may provide a list - * of interface serial number suffixes. If there happens to be - * a device (like USB2CAN) with a matching serial number suffix, - * it gets selected. + * Proprietary, device-specific interface. * - * Client may utilize this in two ways: by matching against the - * entire serial number, or the last few characters (usually one). - * The former is better for small-scale test deployments (with just - * a handful of vehicles), the latter is good for larger scale - * (where a small suffix list may support large test fleet). + * Non-SocketCAN interfaces should use this variant. */ - vec serialno; + struct Indexed { + /** Interface number, 0-based. */ + uint8_t index; + } indexed; } interfaceId; /** @@ -156,7 +154,8 @@ interface ICanController { * * Typical bit rates are: 100000, 125000, 250000, 500000. * - * For virtual interfaces this value is ignored. + * For {@see interfaceId#virtual} and pre-configured + * {@see interfaceId#indexed} interfaces this value is ignored. */ uint32_t bitrate; }; @@ -164,17 +163,17 @@ interface ICanController { /** * Fetches the list of interface types supported by this HAL server. * - * @return iftypes The list of supported interface types + * @return iftypes The list of supported interface types. */ getSupportedInterfaceTypes() generates (vec iftypes); /** * Bring up the CAN interface and publish ICanBus server instance. * - * @param config Configuration of the CAN interface + * @param config Configuration of the CAN interface. * @return result OK if the operation succeeded; error code otherwise. */ - upInterface(BusConfiguration config) generates (Result result); + upInterface(BusConfig config) generates (Result result); /** * Unpublish ICanBus server instance and bring down the CAN interface. @@ -182,9 +181,9 @@ interface ICanController { * In case of failure, at least the ICanBus server instance must be * unpublished and resources freed on best-effort basis. * - * @param name Name of the interface (@see BusConfiguration#name} to - * bring down - * @return success true in case of success, false otherwise + * @param name Name of the interface (@see BusConfig#name} to + * bring down. + * @return success true in case of success, false otherwise. */ downInterface(string name) generates (bool success); }; diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp index 8fb09eb10c..9f704c1ebd 100644 --- a/automotive/can/1.0/default/CanBus.cpp +++ b/automotive/can/1.0/default/CanBus.cpp @@ -124,7 +124,7 @@ ICanController::Result CanBus::up() { if (!isUp.has_value()) { // preUp() should prepare the interface (either create or make sure it's there) LOG(ERROR) << "Interface " << mIfname << " didn't get prepared"; - return ICanController::Result::BAD_ADDRESS; + return ICanController::Result::BAD_INTERFACE_ID; } if (!*isUp && !netdevice::up(mIfname)) { diff --git a/automotive/can/1.0/default/CanBusNative.cpp b/automotive/can/1.0/default/CanBusNative.cpp index ef04d01832..aafbeccdb8 100644 --- a/automotive/can/1.0/default/CanBusNative.cpp +++ b/automotive/can/1.0/default/CanBusNative.cpp @@ -28,7 +28,7 @@ CanBusNative::CanBusNative(const std::string& ifname, uint32_t bitrate) ICanController::Result CanBusNative::preUp() { if (!netdevice::exists(mIfname)) { LOG(ERROR) << "Interface " << mIfname << " doesn't exist"; - return ICanController::Result::BAD_ADDRESS; + return ICanController::Result::BAD_INTERFACE_ID; } if (mBitrate == 0) { diff --git a/automotive/can/1.0/default/CanBusSlcan.cpp b/automotive/can/1.0/default/CanBusSlcan.cpp index 0feee8f51a..d15905da53 100644 --- a/automotive/can/1.0/default/CanBusSlcan.cpp +++ b/automotive/can/1.0/default/CanBusSlcan.cpp @@ -81,7 +81,7 @@ ICanController::Result CanBusSlcan::preUp() { mFd = base::unique_fd(open(mUartName.c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY)); if (!mFd.ok()) { LOG(ERROR) << "SLCAN Failed to open " << mUartName << ": " << strerror(errno); - return ICanController::Result::BAD_ADDRESS; + return ICanController::Result::BAD_INTERFACE_ID; } // If the device is already up, update the iface name in our CanBusSlcan object diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp index fb648c1d80..dd8040233e 100644 --- a/automotive/can/1.0/default/CanController.cpp +++ b/automotive/can/1.0/default/CanController.cpp @@ -27,7 +27,8 @@ namespace android::hardware::automotive::can::V1_0::implementation { -using IfaceIdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator; +using IfId = ICanController::BusConfig::InterfaceId; +using IfIdDisc = ICanController::BusConfig::InterfaceId::hidl_discriminator; Return CanController::getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) { _hidl_cb({ICanController::InterfaceType::VIRTUAL, ICanController::InterfaceType::SOCKETCAN, @@ -40,8 +41,7 @@ static bool isValidName(const std::string& name) { return std::regex_match(name, nameRE); } -Return CanController::upInterface( - const ICanController::BusConfiguration& config) { +Return CanController::upInterface(const ICanController::BusConfig& config) { LOG(VERBOSE) << "Attempting to bring interface up: " << toString(config); std::lock_guard lck(mCanBusesGuard); @@ -58,24 +58,23 @@ Return CanController::upInterface( sp busService; - if (config.iftype == ICanController::InterfaceType::SOCKETCAN) { - // TODO(b/135918744): support serialno - if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) { - busService = new CanBusNative(config.interfaceId.address(), config.bitrate); + if (config.interfaceId.getDiscriminator() == IfIdDisc::socketcan) { + // TODO(b/142654031): support serialno + auto& socketcan = config.interfaceId.socketcan(); + if (socketcan.getDiscriminator() == IfId::Socketcan::hidl_discriminator::ifname) { + busService = new CanBusNative(socketcan.ifname(), config.bitrate); } else { - return ICanController::Result::BAD_ADDRESS; + return ICanController::Result::BAD_INTERFACE_ID; } - } else if (config.iftype == ICanController::InterfaceType::VIRTUAL) { - if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) { - busService = new CanBusVirtual(config.interfaceId.address()); + } else if (config.interfaceId.getDiscriminator() == IfIdDisc::virtualif) { + busService = new CanBusVirtual(config.interfaceId.virtualif().ifname); + } else if (config.interfaceId.getDiscriminator() == IfIdDisc::slcan) { + // TODO(b/142654031): support serialno + auto& slcan = config.interfaceId.slcan(); + if (slcan.getDiscriminator() == IfId::Slcan::hidl_discriminator::ttyname) { + busService = new CanBusSlcan(slcan.ttyname(), config.bitrate); } else { - return ICanController::Result::BAD_ADDRESS; - } - } else if (config.iftype == ICanController::InterfaceType::SLCAN) { - if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) { - busService = new CanBusSlcan(config.interfaceId.address(), config.bitrate); - } else { - return ICanController::Result::BAD_ADDRESS; + return ICanController::Result::BAD_INTERFACE_ID; } } else { return ICanController::Result::NOT_SUPPORTED; diff --git a/automotive/can/1.0/default/CanController.h b/automotive/can/1.0/default/CanController.h index 99a551af77..27e82f3f3f 100644 --- a/automotive/can/1.0/default/CanController.h +++ b/automotive/can/1.0/default/CanController.h @@ -25,8 +25,7 @@ namespace android::hardware::automotive::can::V1_0::implementation { struct CanController : public ICanController { Return getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) override; - Return upInterface( - const ICanController::BusConfiguration& config) override; + Return upInterface(const ICanController::BusConfig& config) override; Return downInterface(const hidl_string& name) override; private: diff --git a/automotive/can/1.0/tools/canhalctrl.cpp b/automotive/can/1.0/tools/canhalctrl.cpp index 5494ba31a3..33755bfffd 100644 --- a/automotive/can/1.0/tools/canhalctrl.cpp +++ b/automotive/can/1.0/tools/canhalctrl.cpp @@ -71,15 +71,31 @@ static int up(const std::string& busName, ICanController::InterfaceType type, if (!isSupported(ctrl, type)) continue; anySupported = true; - ICanController::BusConfiguration config = {}; + ICanController::BusConfig config = {}; config.name = busName; - config.iftype = type; config.bitrate = bitrate; - if (type == ICanController::InterfaceType::INDEXED) { - config.interfaceId.index(std::stol(interface)); + // TODO(b/146214370): move interfaceId constructors to a library + using IfCfg = ICanController::BusConfig::InterfaceId; + if (type == ICanController::InterfaceType::VIRTUAL) { + config.interfaceId.virtualif({interface}); + } else if (type == ICanController::InterfaceType::SOCKETCAN) { + IfCfg::Socketcan socketcan = {}; + socketcan.ifname(interface); + config.interfaceId.socketcan(socketcan); + } else if (type == ICanController::InterfaceType::SLCAN) { + IfCfg::Slcan slcan = {}; + slcan.ttyname(interface); + config.interfaceId.slcan(slcan); + } else if (type == ICanController::InterfaceType::INDEXED) { + auto idx = std::stol(interface); + if (idx < 0 || idx > UINT8_MAX) { + std::cerr << "Interface index out of range: " << idx; + return -1; + } + config.interfaceId.indexed({uint8_t(idx)}); } else { - config.interfaceId.address(interface); + CHECK(false) << "Unexpected interface type: " << toString(type); } const auto upresult = ctrl->upInterface(config); diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp index efaad53a78..68d555dd20 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp @@ -81,7 +81,7 @@ struct CanMessageListener : public can::V1_0::ICanMessageListener { struct Bus { DISALLOW_COPY_AND_ASSIGN(Bus); - Bus(sp controller, const ICanController::BusConfiguration& config) + Bus(sp controller, const ICanController::BusConfig& config) : mIfname(config.name), mController(controller) { const auto result = controller->upInterface(config); EXPECT_EQ(ICanController::Result::OK, result); @@ -122,6 +122,7 @@ struct Bus { void send(const CanMessage& msg) { EXPECT_NE(mBus, nullptr); + if (!mBus) return; const auto result = mBus->send(msg); EXPECT_EQ(Result::OK, result); } @@ -196,10 +197,9 @@ Bus CanBusVirtualHalTest::makeBus() { const auto idx = mLastIface++; EXPECT_LT(idx, mBusNames.size()); - ICanController::BusConfiguration config = {}; + ICanController::BusConfig config = {}; config.name = mBusNames[idx]; - config.iftype = InterfaceType::VIRTUAL; - config.interfaceId.address("vcan50"); + config.interfaceId.virtualif({"vcan50"}); return Bus(mCanController, config); } diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp index b2edd78391..0c5d976053 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp @@ -31,6 +31,7 @@ namespace android::hardware::automotive::can::V1_0::vts { using hardware::hidl_vec; using InterfaceType = ICanController::InterfaceType; +using IfId = ICanController::BusConfig::InterfaceId; static utils::SimpleHidlEnvironment* gEnv = nullptr; @@ -89,10 +90,23 @@ bool CanControllerHalTest::isSupported(InterfaceType iftype) { bool CanControllerHalTest::up(InterfaceType iftype, std::string srvname, std::string ifname, ICanController::Result expected) { - ICanController::BusConfiguration config = {}; + ICanController::BusConfig config = {}; config.name = srvname; - config.iftype = iftype; - config.interfaceId.address(ifname); + + // TODO(b/146214370): move interfaceId constructors to a library + if (iftype == InterfaceType::SOCKETCAN) { + IfId::Socketcan socketcan = {}; + socketcan.ifname(ifname); + config.interfaceId.socketcan(socketcan); + } else if (iftype == InterfaceType::SLCAN) { + IfId::Slcan slcan = {}; + slcan.ttyname(ifname); + config.interfaceId.slcan(slcan); + } else if (iftype == InterfaceType::VIRTUAL) { + config.interfaceId.virtualif({ifname}); + } else { + EXPECT_TRUE(false) << "Unexpected iftype: " << toString(iftype); + } const auto upresult = mCanController->upInterface(config); @@ -155,54 +169,64 @@ TEST_F(CanControllerHalTest, UpTwice) { assertRegistered(name, false); } -TEST_F(CanControllerHalTest, IdentifierCompatibility) { - using IdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator; - static const std::map> compatMatrix = { - {InterfaceType::VIRTUAL, {IdDisc::address}}, - {InterfaceType::SOCKETCAN, {IdDisc::address, IdDisc::serialno}}, - {InterfaceType::SLCAN, {IdDisc::address, IdDisc::serialno}}, - {InterfaceType::INDEXED, {IdDisc::index}}, +TEST_F(CanControllerHalTest, ConfigCompatibility) { + // using random-ish addresses, which may not be valid - we can't test the success case + // TODO(b/146214370): move interfaceId constructors to a library + IfId virtualCfg = {}; + virtualCfg.virtualif({"vcan70"}); + + IfId::Socketcan socketcanIfname = {}; + socketcanIfname.ifname("can0"); + IfId socketcanIfnameCfg = {}; + socketcanIfnameCfg.socketcan(socketcanIfname); + + IfId::Socketcan socketcanSerial = {}; + socketcanSerial.serialno({"1234", "2345"}); + IfId socketcanSerialCfg = {}; + socketcanSerialCfg.socketcan(socketcanSerial); + + IfId::Slcan slcanTtyname = {}; + slcanTtyname.ttyname("/dev/ttyUSB0"); + IfId slcanTtynameCfg = {}; + slcanTtynameCfg.slcan(slcanTtyname); + + IfId::Slcan slcanSerial = {}; + slcanSerial.serialno({"dead", "beef"}); + IfId slcanSerialCfg = {}; + slcanSerialCfg.slcan(slcanSerial); + + IfId indexedCfg = {}; + indexedCfg.indexed({0}); + + static const std::vector> compatMatrix = { + {InterfaceType::VIRTUAL, virtualCfg}, + {InterfaceType::SOCKETCAN, socketcanIfnameCfg}, + {InterfaceType::SOCKETCAN, socketcanSerialCfg}, + {InterfaceType::SLCAN, slcanTtynameCfg}, + {InterfaceType::SLCAN, slcanSerialCfg}, + {InterfaceType::INDEXED, indexedCfg}, }; - static const std::vector allDisc = {IdDisc::address, IdDisc::index, IdDisc::serialno}; - for (const auto [iftype, supported] : compatMatrix) { - for (const auto iddisc : allDisc) { - LOG(INFO) << "Compatibility testing: " << iftype << " / " << iddisc; + for (const auto [iftype, cfg] : compatMatrix) { + LOG(INFO) << "Compatibility testing: " << iftype << " / " << cfg; - ICanController::BusConfiguration config = {}; - config.name = "compattestsrv"; - config.iftype = iftype; - config.bitrate = 125000; + ICanController::BusConfig config = {}; + config.name = "compattestsrv"; + config.bitrate = 125000; + config.interfaceId = cfg; - // using random-ish addresses, which may not be valid - we can't test the success case - if (iddisc == IdDisc::address) { - config.interfaceId.address("can0"); - } else if (iddisc == IdDisc::index) { - config.interfaceId.index(0); - } else if (iddisc == IdDisc::serialno) { - config.interfaceId.serialno({"dummy", "dummier"}); - } + const auto upresult = mCanController->upInterface(config); - const auto upresult = mCanController->upInterface(config); + if (!isSupported(iftype)) { + ASSERT_EQ(ICanController::Result::NOT_SUPPORTED, upresult); + continue; + } + ASSERT_NE(ICanController::Result::NOT_SUPPORTED, upresult); - if (!isSupported(iftype)) { - ASSERT_EQ(ICanController::Result::NOT_SUPPORTED, upresult); - continue; - } - ASSERT_NE(ICanController::Result::NOT_SUPPORTED, upresult); - - bool isSupportedDisc = - std::find(supported.begin(), supported.end(), iddisc) != supported.end(); - if (!isSupportedDisc) { - ASSERT_EQ(ICanController::Result::BAD_ADDRESS, upresult); - continue; - } - - if (upresult == ICanController::Result::OK) { - const auto dnresult = mCanController->downInterface(config.name); - ASSERT_TRUE(dnresult); - continue; - } + if (upresult == ICanController::Result::OK) { + const auto dnresult = mCanController->downInterface(config.name); + ASSERT_TRUE(dnresult); + continue; } } } @@ -232,7 +256,9 @@ TEST_F(CanControllerHalTest, FailBadVirtualAddress) { const std::string name = mBusNames[0]; assertRegistered(name, false); - if (!up(InterfaceType::VIRTUAL, name, "", ICanController::Result::BAD_ADDRESS)) GTEST_SKIP(); + if (!up(InterfaceType::VIRTUAL, name, "", ICanController::Result::BAD_INTERFACE_ID)) { + GTEST_SKIP(); + } assertRegistered(name, false); } @@ -240,10 +266,30 @@ TEST_F(CanControllerHalTest, FailBadSocketcanAddress) { const std::string name = mBusNames[0]; assertRegistered(name, false); - if (!up(InterfaceType::SOCKETCAN, name, "can87", ICanController::Result::BAD_ADDRESS)) { + if (!up(InterfaceType::SOCKETCAN, name, "can87", ICanController::Result::BAD_INTERFACE_ID)) { GTEST_SKIP(); } assertRegistered(name, false); + + auto supported = + up(InterfaceType::SOCKETCAN, name, "", ICanController::Result::BAD_INTERFACE_ID); + ASSERT_TRUE(supported); + assertRegistered(name, false); +} + +TEST_F(CanControllerHalTest, FailBadSlcanAddress) { + const std::string name = mBusNames[0]; + + assertRegistered(name, false); + if (!up(InterfaceType::SLCAN, name, "/dev/shouldnotexist123", + ICanController::Result::BAD_INTERFACE_ID)) { + GTEST_SKIP(); + } + assertRegistered(name, false); + + auto supported = up(InterfaceType::SLCAN, name, "", ICanController::Result::BAD_INTERFACE_ID); + ASSERT_TRUE(supported); + assertRegistered(name, false); } } // namespace android::hardware::automotive::can::V1_0::vts diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h index 3c30744802..383b54cae5 100644 --- a/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h +++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h @@ -35,8 +35,7 @@ namespace android::hardware::automotive::can::V1_0 { DEFINE_CAN_HAL_PRINTER(CanMessage, toString) DEFINE_CAN_HAL_PRINTER(ErrorEvent, toString) -DEFINE_CAN_HAL_PRINTER_SIMPLE( - ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator, int) +DEFINE_CAN_HAL_PRINTER(ICanController::BusConfig::InterfaceId, toString); DEFINE_CAN_HAL_PRINTER(ICanController::InterfaceType, toString) DEFINE_CAN_HAL_PRINTER(ICanController::Result, toString) DEFINE_CAN_HAL_PRINTER(Result, toString) From a1d1365ed3deb57490409492ab8577f8e2aabc8f Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Wed, 29 Jan 2020 09:22:28 -0800 Subject: [PATCH 0619/1022] Wifi: Add support for mapping DSCP to Wifi AC This commit adds the needed enum and methods to handle the mapping of DSCP into wifi access categories. Bug: 141500691 Bug: 141550272 Test: Builds successfully Change-Id: I3a85c211057907c2363f7f349d0075e6b4a1b152 --- wifi/1.4/default/wifi_legacy_hal.cpp | 10 ++++++++++ wifi/1.4/default/wifi_legacy_hal.h | 3 +++ wifi/1.4/default/wifi_legacy_hal_stubs.cpp | 2 ++ 3 files changed, 15 insertions(+) diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp index a040c89a30..f5961954df 100644 --- a/wifi/1.4/default/wifi_legacy_hal.cpp +++ b/wifi/1.4/default/wifi_legacy_hal.cpp @@ -831,6 +831,16 @@ wifi_error WifiLegacyHal::setThermalMitigationMode(wifi_thermal_mode mode, global_handle_, mode, completion_window); } +wifi_error WifiLegacyHal::setDscpToAccessCategoryMapping( + uint32_t start, uint32_t end, uint32_t access_category) { + return global_func_table_.wifi_map_dscp_access_category( + global_handle_, start, end, access_category); +} + +wifi_error WifiLegacyHal::resetDscpToAccessCategoryMapping() { + return global_func_table_.wifi_reset_dscp_mapping(global_handle_); +} + std::pair WifiLegacyHal::getLoggerSupportedFeatureSet( const std::string& iface_name) { uint32_t supported_feature_flags; diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h index 72cf197539..c21563ee92 100644 --- a/wifi/1.4/default/wifi_legacy_hal.h +++ b/wifi/1.4/default/wifi_legacy_hal.h @@ -261,6 +261,9 @@ class WifiLegacyHal { wifi_latency_mode mode); wifi_error setThermalMitigationMode(wifi_thermal_mode mode, uint32_t completion_window); + wifi_error setDscpToAccessCategoryMapping(uint32_t start, uint32_t end, + uint32_t access_category); + wifi_error resetDscpToAccessCategoryMapping(); // Logger/debug functions. std::pair getLoggerSupportedFeatureSet( const std::string& iface_name); diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp index 6945b4ca01..153a68520f 100644 --- a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp +++ b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp @@ -141,6 +141,8 @@ bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) { populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode); populateStubFor(&hal_fn->wifi_virtual_interface_create); populateStubFor(&hal_fn->wifi_virtual_interface_delete); + populateStubFor(&hal_fn->wifi_map_dscp_access_category); + populateStubFor(&hal_fn->wifi_reset_dscp_mapping); return true; } } // namespace legacy_hal From a075122fcabca1daba34ead5877d216782ede2f0 Mon Sep 17 00:00:00 2001 From: "Nate(Qiang) Jiang" Date: Wed, 19 Feb 2020 17:30:55 -0800 Subject: [PATCH 0620/1022] Fix nan Vts test count shoule be initialize to 0 before test. Bug: 149709834 Test: atest VtsHalWifiApV1_4TargetTest Change-Id: I47c43571bc3ff91f389a4c9f41e050cc13c104a2 --- wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp | 2 +- wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp index 6e55664d9b..96656f3c73 100644 --- a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp +++ b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp @@ -439,7 +439,7 @@ class WifiNanIfaceHidlTest : public ::testing::TestWithParam { // synchronization objects std::mutex mtx_; std::condition_variable cv_; - int count_; + int count_ = 0; protected: android::sp<::android::hardware::wifi::V1_2::IWifiNanIface> iwifiNanIface; diff --git a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp index 782088f4cf..24daee69f3 100644 --- a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp +++ b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp @@ -440,7 +440,7 @@ class WifiNanIfaceHidlTest : public ::testing::TestWithParam { // synchronization objects std::mutex mtx_; std::condition_variable cv_; - int count_; + int count_ = 0; protected: android::sp<::android::hardware::wifi::V1_4::IWifiNanIface> iwifiNanIface; From 3ab17d6b02300a5673ad4a3c575d323013f6dc22 Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Tue, 18 Feb 2020 12:53:00 +0000 Subject: [PATCH 0621/1022] Add align_corners and half_pixel_centers parameters to resize ops Fix: 135147454 Test: NNTest_static Change-Id: I4115120c8b6261c5518d561c043cda913d47dd45 --- current.txt | 2 +- neuralnetworks/1.3/types.hal | 44 +++++++++++++++++++ .../1.3/vts/functional/ValidateModel.cpp | 13 +++++- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/current.txt b/current.txt index 42f073b293..0a8a42e239 100644 --- a/current.txt +++ b/current.txt @@ -678,7 +678,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 6e904be0ddca5ae1de8eba020e6c38ed935ea7d80cd08f47787f137a0ca58555 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback 2b0b10d2ea7a18a4048cd0eb83d35c19a817aeee95f65807fc31f4ef21381397 android.hardware.neuralnetworks@1.3::IPreparedModel eee3430cc86c97c7b407495863d8fb61da6f1a64b7721e77b9b4909b11b174e9 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -dd39887aa4fb60ce60ea9cc043edeadbbae6e922d09d3946311b0b410024ae14 android.hardware.neuralnetworks@1.3::types +c9320b04ec302624985180a02d591bea5e435601fc411a6cabb58878e4e1ad68 android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index 08d8e6b158..daaf22eddb 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -1584,6 +1584,17 @@ enum OperationType : int32_t { * * 3: An optional {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. * Available since HAL version 1.2. + * * 4: Align corners. An optional {@link OperandType::BOOL} + * scalar, default to false. If True, the centers of the 4 corner + * pixels of the input and output tensors are aligned, preserving the + * values at the corner pixels. + * Available since HAL version 1.3. + * * 5: Half pixel centers. An optional {@link OperandType::BOOL} + * scalar, default to false. If True, the pixel centers are assumed to + * be at (0.5, 0.5). This is the default behavior of image.resize in + * TF 2.0. If this parameter is True, then align_corners parameter + * must be False. + * Available since HAL version 1.3. * * Inputs (resizing by scale, since HAL version 1.2): * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying @@ -1602,6 +1613,17 @@ enum OperationType : int32_t { * {@link OperandType::FLOAT32} otherwise. * * 3: An optional {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. + * * 4: Align corners. An optional {@link OperandType::BOOL} + * scalar, default to false. If True, the centers of the 4 corner + * pixels of the input and output tensors are aligned, preserving the + * values at the corner pixels. + * Available since HAL version 1.3. + * * 5: Half pixel centers. An optional {@link OperandType::BOOL} + * scalar, default to false. If True, the pixel centers are assumed to + * be at (0.5, 0.5). This is the default behavior of image.resize in + * TF 2.0. If this parameter is True, then align_corners parameter + * must be False. + * Available since HAL version 1.3. * * Outputs: * * 0: The output 4-D tensor, of shape @@ -4870,6 +4892,17 @@ enum OperationType : int32_t { * height of the output tensor. * * 3: An {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. + * * 4: Align corners. An optional {@link OperandType::BOOL} + * scalar, default to false. If True, the centers of the 4 corner + * pixels of the input and output tensors are aligned, preserving the + * values at the corner pixels. + * Available since HAL version 1.3. + * * 5: Half pixel centers. An optional {@link OperandType::BOOL} + * scalar, default to false. If True, the pixel centers are assumed to + * be at (0.5, 0.5). This is the default behavior of image.resize in + * TF 2.0. If this parameter is True, then align_corners parameter + * must be False. + * Available since HAL version 1.3. * * Inputs (resizing by scale): * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying @@ -4888,6 +4921,17 @@ enum OperationType : int32_t { * {@link OperandType::FLOAT32} otherwise. * * 3: An {@link OperandType::BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. + * * 4: Align corners. An optional {@link OperandType::BOOL} + * scalar, default to false. If True, the centers of the 4 corner + * pixels of the input and output tensors are aligned, preserving the + * values at the corner pixels. + * Available since HAL version 1.3. + * * 5: Half pixel centers. An optional {@link OperandType::BOOL} + * scalar, default to false. If True, the pixel centers are assumed to + * be at (0.5, 0.5). This is the default behavior of image.resize in + * TF 2.0. If this parameter is True, then align_corners parameter + * must be False. + * Available since HAL version 1.3. * * Outputs: * * 0: The output 4-D tensor, of shape diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 8f2d4b7f19..7da2da980b 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -578,6 +578,8 @@ static bool removeOperationInputSkip(const Operation& op, size_t input) { // - CONV_2D, DEPTHWISE_CONV_2D, MAX_POOL_2D, AVERAGE_POOL_2D, L2_POOL_2D, RESIZE_BILINEAR, // SPACE_TO_DEPTH, SPACE_TO_DEPTH, SPACE_TO_BATCH_ND, BATCH_TO_SPACE_ND can have an optional // layout parameter. + // RESIZE_BILINEAR and RESIZE_NEAREST_NEIGHBOR can have optional + // align_corners and half_pixel_centers parameters. // - L2_NORMALIZATION, LOCAL_RESPONSE_NORMALIZATION, SOFTMAX can have an optional axis // parameter. switch (op.type) { @@ -600,7 +602,12 @@ static bool removeOperationInputSkip(const Operation& op, size_t input) { } } break; case OperationType::RESIZE_BILINEAR: { - if (op.inputs.size() == 4 && input == 3) { + if (op.inputs.size() >= 4 && input >= 3) { + return true; + } + } break; + case OperationType::RESIZE_NEAREST_NEIGHBOR: { + if (op.inputs.size() >= 5 && input >= 3) { return true; } } break; @@ -686,7 +693,9 @@ static bool addOperationInputSkip(const Operation& op) { // parameter. if ((op.type == OperationType::L2_NORMALIZATION && op.inputs.size() == 1) || (op.type == OperationType::LOCAL_RESPONSE_NORMALIZATION && op.inputs.size() == 5) || - (op.type == OperationType::SOFTMAX && op.inputs.size() == 2)) { + (op.type == OperationType::SOFTMAX && op.inputs.size() == 2) || + (op.type == OperationType::RESIZE_BILINEAR && op.inputs.size() < 6) || + (op.type == OperationType::RESIZE_NEAREST_NEIGHBOR && op.inputs.size() < 6)) { return true; } return false; From 793fab0b07fdec2acc5117367aa3e0a8f66f5dca Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Tue, 18 Feb 2020 15:19:35 -0800 Subject: [PATCH 0622/1022] Add ICanController BAD_SERVICE_NAME error Bug: 137798319 Test: VTS Change-Id: I4722346239728f3ab359688658c23441e83671a8 --- automotive/can/1.0/ICanController.hal | 6 ++++++ automotive/can/1.0/default/CanController.cpp | 4 ++-- .../vts/functional/VtsHalCanControllerV1_0TargetTest.cpp | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/automotive/can/1.0/ICanController.hal b/automotive/can/1.0/ICanController.hal index e32e593655..aaf85e94c9 100644 --- a/automotive/can/1.0/ICanController.hal +++ b/automotive/can/1.0/ICanController.hal @@ -70,6 +70,12 @@ interface ICanController { /** Provided bit rate is not supported by the hardware. */ BAD_BITRATE, + + /** + * Provided service name ({@see BusConfig#name}) either has invalid + * format or is not listed in device manifest file. + */ + BAD_SERVICE_NAME, }; /** diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp index dd8040233e..0700c77513 100644 --- a/automotive/can/1.0/default/CanController.cpp +++ b/automotive/can/1.0/default/CanController.cpp @@ -48,7 +48,7 @@ Return CanController::upInterface(const ICanController:: if (!isValidName(config.name)) { LOG(ERROR) << "Bus name " << config.name << " is invalid"; - return ICanController::Result::UNKNOWN_ERROR; + return ICanController::Result::BAD_SERVICE_NAME; } if (mCanBuses.find(config.name) != mCanBuses.end()) { @@ -90,7 +90,7 @@ Return CanController::upInterface(const ICanController:: if (!busService->down()) { LOG(WARNING) << "Failed to bring down CAN bus that failed to register"; } - return ICanController::Result::UNKNOWN_ERROR; + return ICanController::Result::BAD_SERVICE_NAME; } mCanBuses[config.name] = busService; diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp index 0c5d976053..83972153c2 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp @@ -235,7 +235,7 @@ TEST_F(CanControllerHalTest, FailEmptyName) { const std::string name = ""; assertRegistered(name, false); - if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::UNKNOWN_ERROR)) { + if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::BAD_SERVICE_NAME)) { GTEST_SKIP(); } assertRegistered(name, false); @@ -246,7 +246,7 @@ TEST_F(CanControllerHalTest, FailBadName) { const std::string name = "ab012345678901234567890123456789c"; assertRegistered(name, false); - if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::UNKNOWN_ERROR)) { + if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::BAD_SERVICE_NAME)) { GTEST_SKIP(); } assertRegistered(name, false); From 2e9bf64c5eb24f1980c153dda562317db89e5f41 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 20 Feb 2020 10:06:16 -0800 Subject: [PATCH 0623/1022] gralloc4-vts: setting USAGE is always BAD_VALUE Usage cannot be change after allocation. Mapper must return BAD_VALUE. SetConstantMetadata already tests this. Remove the tests that attempted to set USAGE and expected it could succeed. Test: VtsHalGraphicsMapperV4_0 Bug: 149830560 Change-Id: I730dd3f3c0c48946c436e8fb60256365e0d9ab1e --- .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 59 ------------------- 1 file changed, 59 deletions(-) diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 58b7ed3688..1416fcc239 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -1197,65 +1197,6 @@ TEST_P(GraphicsMapperHidlTest, SetPixelFormatModifier) { }); } -/** - * Test IMapper::set(Usage) remove flag - */ -TEST_P(GraphicsMapperHidlTest, SetUsageRemoveBit) { - uint64_t usage = static_cast(BufferUsage::CPU_WRITE_OFTEN); - hidl_vec vec; - ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec)); - - testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage, vec, - [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { - uint64_t realUsage = 0; - ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage)); - EXPECT_EQ(usage, realUsage); - }); -} -/** - * Test IMapper::set(Usage) add flag - */ -TEST_P(GraphicsMapperHidlTest, SetUsageAddBit) { - uint64_t usage = mDummyDescriptorInfo.usage | static_cast(BufferUsage::GPU_TEXTURE); - hidl_vec vec; - ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec)); - - testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage, vec, - [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec& vec) { - uint64_t realUsage = 0; - ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage)); - EXPECT_EQ(usage, realUsage); - }); -} - -/** - * Test IMapper::set(Usage) to test protected content - */ -TEST_P(GraphicsMapperHidlTest, SetUsageProtected) { - const native_handle_t* bufferHandle = nullptr; - auto info = mDummyDescriptorInfo; - info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY; - - bufferHandle = mGralloc->allocate(info, true, true); - if (bufferHandle) { - GTEST_SUCCEED() << "unable to allocate protected content"; - return; - } - - uint64_t usage = static_cast(BufferUsage::COMPOSER_OVERLAY); - hidl_vec vec; - ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec)); - - Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec); - ASSERT_EQ(err, Error::UNSUPPORTED); - vec.resize(0); - - uint64_t realUsage = 0; - ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_Usage, &vec)); - ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage)); - EXPECT_EQ(info.usage, realUsage); -} - /** * Test IMapper::set(AllocationSize) */ From 71e543a61f8606b31be37c94cbeb526e6842c051 Mon Sep 17 00:00:00 2001 From: Danny Epstein Date: Wed, 19 Feb 2020 16:00:43 -0800 Subject: [PATCH 0624/1022] Add rotary interface to VHAL. Adds a new property for rotary knobs that can spin indefinitely. Test: Changed Hawk VHAL to use new property for volume Change-Id: I74eb664e243b5796f7bccb2debd9c440bf430f7d --- .../default/impl/vhal_v2_0/DefaultConfig.h | 8 ++++ automotive/vehicle/2.0/types.hal | 42 +++++++++++++++++++ 2 files changed, 50 insertions(+) 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 785f0e0724..51b9a888be 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 @@ -457,6 +457,14 @@ const ConfigDeclaration kVehicleProperties[]{ }, .initialValue = {.int32Values = {0, 0, 0}}}, + {.config = + { + .prop = toInt(VehicleProperty::HW_ROTARY_INPUT), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {0, 0, 0}}}, + {.config = {.prop = toInt(VehicleProperty::HVAC_POWER_ON), .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index cbd9e2883a..95cfe05642 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -1413,6 +1413,33 @@ enum VehicleProperty : int32_t { | VehiclePropertyType:INT32_VEC | VehicleArea:GLOBAL), + /** + * Property to feed H/W rotary events to android + * + * int32Values[0] : RotaryInputType identifying which rotary knob rotated + * int32Values[1] : number of detents (clicks), positive for clockwise, + * negative for counterclockwise + * int32Values[2] : target display defined in VehicleDisplay. Events not + * tied to specific display must be sent to + * VehicleDisplay#MAIN. + * int32values[3 .. 3 + abs(number of detents) - 2]: + * nanosecond deltas between pairs of consecutive detents, + * if the number of detents is > 1 or < -1 + * + * VehiclePropValue.timestamp: when the rotation occurred. If the number of + * detents is > 1 or < -1, this is when the + * first detent of rotation occurred. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @data_enum RotaryInputType + * @access VehiclePropertyAccess:READ + */ + HW_ROTARY_INPUT = ( + 0x0A20 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32_VEC + | VehicleArea:GLOBAL), + /*************************************************************************** * Most Car Cabin properties have both a POSition and MOVE parameter. These * are used to control the various movements for seats, doors, and windows @@ -4651,3 +4678,18 @@ struct UserIdentificationSetAssociation { UserIdentificationAssociationSetValue value; }; + +/** + * A rotary control which can rotate without limits. These controls use HW_ROTARY_INPUT to report + * relative clockwise or counterclockwise motion. They have no absolute position. + */ +enum RotaryInputType : int32_t { + /** + * Main rotary control, typically in the center console, used to navigate the user interface. + */ + ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION = 0, + + /** Volume control for adjusting audio volume. */ + ROTARY_INPUT_TYPE_AUDIO_VOLUME = 1, +}; + From d0bc0bc57b386fb90650b7d127b4862ae28f67f3 Mon Sep 17 00:00:00 2001 From: Kai Date: Tue, 18 Feb 2020 18:05:36 -0800 Subject: [PATCH 0625/1022] Add property for multiple ev port locations Some cars have multiple ev ports. Bug: 117599455 Test: google VHAL and kitchenSink app Change-Id: I630b60f773867d1e3a85786403ee28852d497f7e --- .../default/impl/vhal_v2_0/DefaultConfig.h | 9 +++++++++ automotive/vehicle/2.0/types.hal | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+) 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 785f0e0724..019e04811f 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 @@ -70,6 +70,7 @@ constexpr int VENDOR_EXTENSION_STRING_PROPERTY = (int)(0x104 | VehiclePropertyGroup::VENDOR | VehiclePropertyType::STRING | VehicleArea::GLOBAL); constexpr int FUEL_DOOR_REAR_LEFT = (int)PortLocationType::REAR_LEFT; constexpr int CHARGE_PORT_FRONT_LEFT = (int)PortLocationType::FRONT_LEFT; +constexpr int CHARGE_PORT_REAR_LEFT = (int)PortLocationType::REAR_LEFT; constexpr int LIGHT_STATE_ON = (int)VehicleLightState::ON; constexpr int LIGHT_SWITCH_AUTO = (int)VehicleLightSwitch::AUTOMATIC; constexpr int WHEEL_FRONT_LEFT = (int)VehicleAreaWheel::LEFT_FRONT; @@ -247,6 +248,14 @@ const ConfigDeclaration kVehicleProperties[]{ }, .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT}}}, + {.config = + { + .prop = toInt(VehicleProperty::INFO_MULTI_EV_PORT_LOCATIONS), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + }, + .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT, CHARGE_PORT_REAR_LEFT}}}, + {.config = { .prop = toInt(VehicleProperty::INFO_MAKE), diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index cbd9e2883a..ab5af08d89 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -319,6 +319,25 @@ enum VehicleProperty : int32_t { | VehiclePropertyType:INT32_VEC | VehicleArea:GLOBAL), + /** + * Multiple EV port locations + * + * Implement this property if the vehicle has multiple EV ports. + * Port locations are defined in PortLocationType. + * For example, a car has one port in front left and one port in rear left: + * int32Values[0] = PortLocationType::FRONT_LEFT + * int32Values[0] = PortLocationType::REAR_LEFT + * + * @change_mode VehiclePropertyChangeMode:STATIC + * @access VehiclePropertyAccess:READ + * @data_enum PortLocationType + */ + INFO_MULTI_EV_PORT_LOCATIONS = ( + 0x010C + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32_VEC + | VehicleArea:GLOBAL), + /** * Current odometer value of the vehicle * From 973e4d33b56197a5fd70cd4f7d52c757cdfc83e3 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Wed, 19 Feb 2020 10:50:50 -0800 Subject: [PATCH 0626/1022] audio: Add playback rate parameters to IStreamOut Playback rate parameters allow changing the playback speed of audio streams optionally preserving the pitch (this is often referred to as "timestretch"). HALs can apply these parameters when decoding of streams is done in hardware. Bug: 133526565 Test: atest VtsHalAudioV6_0TargetTest Change-Id: Ie78cd924bd034b57bf5b6a74affd62641ffc0aba --- audio/6.0/IStreamOut.hal | 29 ++++++++++ audio/6.0/types.hal | 58 +++++++++++++++++++ audio/core/all-versions/default/StreamOut.cpp | 12 ++++ .../default/include/core/default/StreamOut.h | 2 + .../6.0/AudioPrimaryHidlHalTest.cpp | 34 +++++++++++ current.txt | 4 +- 6 files changed, 137 insertions(+), 2 deletions(-) diff --git a/audio/6.0/IStreamOut.hal b/audio/6.0/IStreamOut.hal index 91668ba452..13a86ec4d3 100644 --- a/audio/6.0/IStreamOut.hal +++ b/audio/6.0/IStreamOut.hal @@ -333,4 +333,33 @@ interface IStreamOut extends IStream { * @return retval operation completion status. */ setAudioDescriptionMixLevel(float leveldB) generates (Result retval); + + /** + * Retrieves current playback rate parameters. + * + * Optional method + * + * @return retval operation completion status. + * @return playbackRate current playback parameters + */ + getPlaybackRateParameters() + generates (Result retval, PlaybackRate playbackRate); + + /** + * Sets the playback rate parameters that control playback behavior. + * This is normally used when playing encoded content and decoding + * is performed in hardware. Otherwise, the framework can apply + * necessary transformations. + * + * Optional method + * + * If the HAL supports setting the playback rate, it is recommended + * to support speed and pitch values at least in the range + * from 0.5f to 2.0f, inclusive (see the definition of PlaybackRate struct). + * + * @param playbackRate playback parameters + * @return retval operation completion status. + */ + setPlaybackRateParameters(PlaybackRate playbackRate) + generates (Result retval); }; diff --git a/audio/6.0/types.hal b/audio/6.0/types.hal index efc3ea5750..8ff618e58b 100644 --- a/audio/6.0/types.hal +++ b/audio/6.0/types.hal @@ -297,3 +297,61 @@ enum DualMonoMode : int32_t { */ RR = 3, }; + +/** + * Algorithms used for timestretching (preserving pitch while playing audio + * content at different speed). + */ +@export(name="audio_timestretch_stretch_mode_t", value_prefix="AUDIO_TIMESTRETCH_STRETCH_") +enum TimestretchMode : int32_t { + // Need to be in sync with AUDIO_STRETCH_MODE_* constants in + // frameworks/base/media/java/android/media/PlaybackParams.java + DEFAULT = 0, + /** Selects timestretch algorithm best suitable for voice (speech) content. */ + VOICE = 1, +}; + +/** + * Behavior when the values for speed and / or pitch are out + * of applicable range. + */ +@export(name="audio_timestretch_fallback_mode_t", value_prefix="AUDIO_TIMESTRETCH_FALLBACK_") +enum TimestretchFallbackMode : int32_t { + // Need to be in sync with AUDIO_FALLBACK_MODE_* constants in + // frameworks/base/media/java/android/media/PlaybackParams.java + /** Play silence for parameter values that are out of range. */ + MUTE = 1, + /** Return an error while trying to set the parameters. */ + FAIL = 2, +}; + +/** + * Parameters determining playback behavior. They are used to speed up or + * slow down playback and / or change the tonal frequency of the audio content + * (pitch). + */ +struct PlaybackRate { + /** + * Speed factor (multiplier). Normal speed has the value of 1.0f. + * Values less than 1.0f slow down playback, value greater than 1.0f + * speed it up. + */ + float speed; + /** + * Pitch factor (multiplier). Setting pitch value to 1.0f together + * with changing playback speed preserves the pitch, this is often + * called "timestretching." Setting the pitch value equal to speed produces + * the same effect as playing audio content at different sampling rate. + */ + float pitch; + /** + * Selects the algorithm used for timestretching (preserving pitch while + * playing audio at different speed). + */ + TimestretchMode timestretchMode; + /** + * Selects the behavior when the specified values for speed and / or pitch + * are out of applicable range. + */ + TimestretchFallbackMode fallbackMode; +}; diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp index cfbee34299..7a4d72bd15 100644 --- a/audio/core/all-versions/default/StreamOut.cpp +++ b/audio/core/all-versions/default/StreamOut.cpp @@ -600,6 +600,18 @@ Return StreamOut::getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_ Return StreamOut::setAudioDescriptionMixLevel(float /*leveldB*/) { return Result::NOT_SUPPORTED; } + +Return StreamOut::getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb) { + _hidl_cb(Result::NOT_SUPPORTED, + // Same as AUDIO_PLAYBACK_RATE_INITIALIZER + PlaybackRate{1.0f, 1.0f, TimestretchMode::DEFAULT, TimestretchFallbackMode::FAIL}); + return Void(); +} + +Return StreamOut::setPlaybackRateParameters(const PlaybackRate& /*playbackRate*/) { + return Result::NOT_SUPPORTED; +} + #endif } // namespace implementation diff --git a/audio/core/all-versions/default/include/core/default/StreamOut.h b/audio/core/all-versions/default/include/core/default/StreamOut.h index 294867c9ed..5db8626909 100644 --- a/audio/core/all-versions/default/include/core/default/StreamOut.h +++ b/audio/core/all-versions/default/include/core/default/StreamOut.h @@ -126,6 +126,8 @@ struct StreamOut : public IStreamOut { Return setDualMonoMode(DualMonoMode mode) override; Return getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb) override; Return setAudioDescriptionMixLevel(float leveldB) override; + Return getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb) override; + Return setPlaybackRateParameters(const PlaybackRate& playbackRate) override; #endif static Result getPresentationPositionImpl(audio_stream_out_t* stream, uint64_t* frames, diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp index c9ba509d30..9e2a0505f7 100644 --- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp @@ -217,3 +217,37 @@ TEST_P(AudioDescriptionMixLevelHidlTest, AudioDescriptionMixLevelTest) { INSTANTIATE_TEST_CASE_P(AudioDescriptionMixLevelHidl, AudioDescriptionMixLevelHidlTest, ::testing::ValuesIn(getOutputDeviceConfigParameters()), &DeviceConfigParameterToString); + +using PlaybackRateParametersHidlTest = AccessorHidlTest; +TEST_P(PlaybackRateParametersHidlTest, PlaybackRateParametersTest) { + doc::test("Check that playback rate parameters can be set and retrieved"); + testAccessors( + &OutputStreamTest::getStream, "playback rate parameters", + Initial{PlaybackRate{1.0f, 1.0f, TimestretchMode::DEFAULT, + TimestretchFallbackMode::FAIL}}, + {// Speed and pitch values in the range from 0.5f to 2.0f must be supported + // (see the definition of IStreamOut::setPlaybackRateParameters). + PlaybackRate{1.0f, 1.0f, TimestretchMode::DEFAULT, TimestretchFallbackMode::MUTE}, + PlaybackRate{2.0f, 2.0f, TimestretchMode::DEFAULT, TimestretchFallbackMode::MUTE}, + PlaybackRate{0.5f, 0.5f, TimestretchMode::DEFAULT, TimestretchFallbackMode::MUTE}, + // Gross speed / pitch values must not be rejected if the fallback mode is "mute" + PlaybackRate{1000.0f, 1000.0f, TimestretchMode::DEFAULT, + TimestretchFallbackMode::MUTE}, + // Default speed / pitch values must not be rejected in "fail" fallback mode + PlaybackRate{1.0f, 1.0f, TimestretchMode::DEFAULT, TimestretchFallbackMode::FAIL}, + // Same for "voice" mode + PlaybackRate{1.0f, 1.0f, TimestretchMode::VOICE, TimestretchFallbackMode::MUTE}, + PlaybackRate{2.0f, 2.0f, TimestretchMode::VOICE, TimestretchFallbackMode::MUTE}, + PlaybackRate{0.5f, 0.5f, TimestretchMode::VOICE, TimestretchFallbackMode::MUTE}, + PlaybackRate{1000.0f, 1000.0f, TimestretchMode::VOICE, TimestretchFallbackMode::MUTE}, + PlaybackRate{1.0f, 1.0f, TimestretchMode::VOICE, TimestretchFallbackMode::FAIL}}, + &IStreamOut::setPlaybackRateParameters, &IStreamOut::getPlaybackRateParameters, + {PlaybackRate{1000.0f, 1000.0f, TimestretchMode::DEFAULT, + TimestretchFallbackMode::FAIL}, + PlaybackRate{1000.0f, 1000.0f, TimestretchMode::VOICE, + TimestretchFallbackMode::FAIL}}); +} + +INSTANTIATE_TEST_CASE_P(PlaybackRateParametersHidl, PlaybackRateParametersHidlTest, + ::testing::ValuesIn(getOutputDeviceConfigParameters()), + &DeviceConfigParameterToString); diff --git a/current.txt b/current.txt index f1245c2a92..0a7bf747d5 100644 --- a/current.txt +++ b/current.txt @@ -605,13 +605,13 @@ ff5dd821c2c7a9c78607159c4d788960b725487263c49d956ca5fa3d37008b45 android.hardwar 5751f230e86a36111e7c5b995577cbf89d8df76c8e6c7641199198f3db3a93f7 android.hardware.wifi@1.3::IWifiStaIface # HALs released in Android R -6cc7fee7bbb7b34e3b8fe75526600400e51d18fe948419d88f294d76b6a4d921 android.hardware.audio@6.0::types +822369cf4dc16a6f6b9622bcf86cbdc0b692dc82193fc15e967767175cbfdd8f android.hardware.audio@6.0::types 7241bd4596a927cd46d4b82f5e29e2cbe57f194aa1b25555f1d1d352e8b15c61 android.hardware.audio@6.0::IDevice 2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice fd1f1b29f26b42e886220f04a08086c00e5ade9d7b53f095438e578ab9d42a93 android.hardware.audio@6.0::IStream 2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn -0d0bbac03e90b18cbf0d1930b89d0c64e41dd2f0d68b652f7ed08347cf5f5f77 android.hardware.audio@6.0::IStreamOut +e6cd2b7c1a86b6ca683c0224ffde3b73aa14f6487de9f46833e539d26d1b3b5c android.hardware.audio@6.0::IStreamOut 997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback 167ed5cfb7d91db2e2bf20f1320c1a9004eeb768e26f535e0f7db94a21867d21 android.hardware.audio.common@6.0::types 817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types From 6e082e85818f36f3c0df70dc56341fd1eff1e5d2 Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Tue, 18 Feb 2020 17:18:19 -0800 Subject: [PATCH 0627/1022] Camera: clarify depth camera requirement for OFFLINE_PROCESSING Test: build (doc only change) Bug: 135142453 Change-Id: I48589e6f7fad6ff291a57de305b4a549dbb843b2 --- camera/device/3.6/types.hal | 22 ++++++++++++++-------- current.txt | 1 + 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/camera/device/3.6/types.hal b/camera/device/3.6/types.hal index 743b139877..f4c50ed1d0 100644 --- a/camera/device/3.6/types.hal +++ b/camera/device/3.6/types.hal @@ -119,14 +119,20 @@ struct HalStream { * For devices that does not support the OFFLINE_PROCESSING capability, this * fields will always be false. * - * For devices support the OFFLINE_PROCESSING capability: any input stream - * and any output stream that can be output of the input stream must set - * this field to true. Also any stream of YUV420_888 format or JPEG format, - * with CPU_READ usage flag, must set this field to true. All other streams - * are up to camera HAL to advertise support or not, though it is not - * recommended to list support for streams with hardware composer or video - * encoder usage flags as these streams tend to be targeted continuously and - * can lead to long latency when trying to switch to offline. + * For backward compatible camera devices that support the + * OFFLINE_PROCESSING capability: any input stream and any output stream + * that can be output of the input stream must set this field to true. Also + * any stream of YUV420_888 format or JPEG format, with CPU_READ usage flag, + * must set this field to true. + * + * For depth only camera devices that support the OFFLINE_PROCESSING + * capability: any DEPTH16 output stream must set this field to true. + * + * All other streams are up to camera HAL to advertise support or not, + * though it is not recommended to list support for streams with + * hardware composer or video encoder usage flags as these streams tend + * to be targeted continuously and can lead to long latency when trying to + * switch to offline. * */ bool supportOffline; diff --git a/current.txt b/current.txt index 09fdd69e63..97d20ab3cc 100644 --- a/current.txt +++ b/current.txt @@ -640,6 +640,7 @@ ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardwar b8c63679e1a3874b356f3e691aecce1191d38f59063cf2ed2dce8a9d4cabf00e android.hardware.camera.device@3.6::ICameraDevice daad72a2f482d8a1f660d0e99ac1b78fedb414a4cfbe3fa56b2cd480e5d6f0cb android.hardware.camera.provider@2.6::ICameraProvider 8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback +a35d5151b48505f06a775b38c0e2e265f80a845d92802324c643565807f81c53 android.hardware.camera.device@3.6::types c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas 9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardware.cas@1.2::IMediaCasService From b97cceb495717f4f9ad2f83f9df763453c7e1a3c Mon Sep 17 00:00:00 2001 From: Tanmay Patil Date: Fri, 7 Feb 2020 16:48:39 -0800 Subject: [PATCH 0628/1022] Adds default implementation for ultrasonics HAL - Replicates logic from camera for default impl. Bug: 148619310 Fixes: b/148608401 Test: Builds, VTS passes. Change-Id: I5c1b4c615f98cb7405a9a233a7853daba09cc63d --- automotive/evs/1.1/default/Android.bp | 4 + automotive/evs/1.1/default/EvsEnumerator.cpp | 111 +++- automotive/evs/1.1/default/EvsEnumerator.h | 13 + .../evs/1.1/default/EvsUltrasonicsArray.cpp | 551 ++++++++++++++++++ .../evs/1.1/default/EvsUltrasonicsArray.h | 134 +++++ 5 files changed, 797 insertions(+), 16 deletions(-) create mode 100644 automotive/evs/1.1/default/EvsUltrasonicsArray.cpp create mode 100644 automotive/evs/1.1/default/EvsUltrasonicsArray.h diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp index a35c9db254..d843167954 100644 --- a/automotive/evs/1.1/default/Android.bp +++ b/automotive/evs/1.1/default/Android.bp @@ -10,6 +10,7 @@ cc_binary { "EvsDisplay.cpp", "ConfigManager.cpp", "ConfigManagerUtil.cpp", + "EvsUltrasonicsArray.cpp", ], init_rc: ["android.hardware.automotive.evs@1.1-service.rc"], @@ -17,11 +18,14 @@ cc_binary { "android.hardware.automotive.evs@1.0", "android.hardware.automotive.evs@1.1", "android.hardware.camera.device@3.3", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", "libbase", "libbinder", "liblog", "libhardware", "libhidlbase", + "libhidlmemory", "liblog", "libui", "libutils", diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp index 415841cc80..117ee7aec4 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.cpp +++ b/automotive/evs/1.1/default/EvsEnumerator.cpp @@ -19,6 +19,7 @@ #include "EvsEnumerator.h" #include "EvsCamera.h" #include "EvsDisplay.h" +#include "EvsUltrasonicsArray.h" namespace android { namespace hardware { @@ -31,12 +32,12 @@ namespace implementation { // NOTE: All members values are static so that all clients operate on the same state // That is to say, this is effectively a singleton despite the fact that HIDL // constructs a new instance for each client. -std::list EvsEnumerator::sCameraList; -wp EvsEnumerator::sActiveDisplay; -unique_ptr EvsEnumerator::sConfigManager; -sp EvsEnumerator::sDisplayProxyService; -std::unordered_map EvsEnumerator::sDisplayPortList; - +std::list EvsEnumerator::sCameraList; +wp EvsEnumerator::sActiveDisplay; +unique_ptr EvsEnumerator::sConfigManager; +sp EvsEnumerator::sDisplayProxyService; +std::unordered_map EvsEnumerator::sDisplayPortList; +std::list EvsEnumerator::sUltrasonicsArrayRecordList; EvsEnumerator::EvsEnumerator(sp windowService) { ALOGD("EvsEnumerator created"); @@ -66,6 +67,10 @@ EvsEnumerator::EvsEnumerator(sp windowService) { } }); } + + // Add ultrasonics array desc. + sUltrasonicsArrayRecordList.emplace_back( + EvsUltrasonicsArray::GetDummyArrayDesc("front_array")); } @@ -355,25 +360,99 @@ EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& ca return pRecord; } -// TODO(b/148608401): Add default implementation with dummy data. +EvsEnumerator::UltrasonicsArrayRecord* EvsEnumerator::findUltrasonicsArrayById( + const std::string& ultrasonicsArrayId) { + auto recordIt = std::find_if( + sUltrasonicsArrayRecordList.begin(), sUltrasonicsArrayRecordList.end(), + [&ultrasonicsArrayId](const UltrasonicsArrayRecord& record) { + return ultrasonicsArrayId == record.desc.ultrasonicsArrayId;}); + + return (recordIt != sUltrasonicsArrayRecordList.end()) ? &*recordIt : nullptr; +} + Return EvsEnumerator::getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) { - hidl_vec ultrasonicsArrayDesc; - _hidl_cb(ultrasonicsArrayDesc); + hidl_vec desc; + desc.resize(sUltrasonicsArrayRecordList.size()); + + // Copy over desc from sUltrasonicsArrayRecordList. + for (auto p = std::make_pair(sUltrasonicsArrayRecordList.begin(), desc.begin()); + p.first != sUltrasonicsArrayRecordList.end(); p.first++, p.second++) { + *p.second = p.first->desc; + } + + // Send back the results + ALOGD("reporting %zu ultrasonics arrays available", desc.size()); + _hidl_cb(desc); + + // HIDL convention says we return Void if we sent our result back via callback return Void(); } -// TODO(b/148608401): Add default implementation with dummy data. Return> EvsEnumerator::openUltrasonicsArray( const hidl_string& ultrasonicsArrayId) { - (void)ultrasonicsArrayId; - sp pEvsUltrasonicsArray; - return pEvsUltrasonicsArray; + // Find the named ultrasonic array. + UltrasonicsArrayRecord* pRecord = findUltrasonicsArrayById(ultrasonicsArrayId); + + // Is this a recognized ultrasonic array id? + if (!pRecord) { + ALOGE("Requested ultrasonics array %s not found", ultrasonicsArrayId.c_str()); + return nullptr; + } + + // Has this ultrasonic array already been instantiated by another caller? + sp pActiveUltrasonicsArray = pRecord->activeInstance.promote(); + if (pActiveUltrasonicsArray != nullptr) { + ALOGW("Killing previous ultrasonics array because of new caller"); + closeUltrasonicsArray(pActiveUltrasonicsArray); + } + + // Construct a ultrasonic array instance for the caller + pActiveUltrasonicsArray = EvsUltrasonicsArray::Create(ultrasonicsArrayId.c_str()); + pRecord->activeInstance = pActiveUltrasonicsArray; + if (pActiveUltrasonicsArray == nullptr) { + ALOGE("Failed to allocate new EvsUltrasonicsArray object for %s\n", + ultrasonicsArrayId.c_str()); + } + + return pActiveUltrasonicsArray; } -// TODO(b/148608401): Add default implementation with dummy data. Return EvsEnumerator::closeUltrasonicsArray( - const ::android::sp& evsUltrasonicsArray) { - (void)evsUltrasonicsArray; + const sp& pEvsUltrasonicsArray) { + + if (pEvsUltrasonicsArray.get() == nullptr) { + ALOGE("Ignoring call to closeUltrasonicsArray with null ultrasonics array"); + return Void(); + } + + // Get the ultrasonics array id so we can find it in our list. + std::string ultrasonicsArrayId; + pEvsUltrasonicsArray->getUltrasonicArrayInfo([&ultrasonicsArrayId](UltrasonicsArrayDesc desc) { + ultrasonicsArrayId.assign(desc.ultrasonicsArrayId); + }); + + // Find the named ultrasonics array + UltrasonicsArrayRecord* pRecord = findUltrasonicsArrayById(ultrasonicsArrayId); + if (!pRecord) { + ALOGE("Asked to close a ultrasonics array whose name isnt not found"); + return Void(); + } + + sp pActiveUltrasonicsArray = pRecord->activeInstance.promote(); + + if (pActiveUltrasonicsArray.get() == nullptr) { + ALOGE("Somehow a ultrasonics array is being destroyed when the enumerator didn't know " + "one existed"); + } else if (pActiveUltrasonicsArray != pEvsUltrasonicsArray) { + // This can happen if the ultrasonics array was aggressively reopened, + // orphaning this previous instance + ALOGW("Ignoring close of previously orphaned ultrasonics array - why did a client steal?"); + } else { + // Drop the active ultrasonics array + pActiveUltrasonicsArray->forceShutdown(); + pRecord->activeInstance = nullptr; + } + return Void(); } diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h index 12fd0189de..d80124b94e 100644 --- a/automotive/evs/1.1/default/EvsEnumerator.h +++ b/automotive/evs/1.1/default/EvsEnumerator.h @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -46,6 +47,7 @@ namespace implementation { class EvsCamera; // from EvsCamera.h class EvsDisplay; // from EvsDisplay.h +class EvsUltrasonicsArray; // from EvsUltrasonicsArray.h class EvsEnumerator : public IEvsEnumerator { @@ -85,10 +87,21 @@ private: CameraRecord(const char *cameraId) : desc() { desc.v1.cameraId = cameraId; } }; + struct UltrasonicsArrayRecord { + UltrasonicsArrayDesc desc; + wp activeInstance; + + UltrasonicsArrayRecord(const UltrasonicsArrayDesc& arrayDesc) : desc(arrayDesc) {}; + }; + static CameraRecord* findCameraById(const std::string& cameraId); static std::list sCameraList; + static UltrasonicsArrayRecord* findUltrasonicsArrayById(const std::string& ultrasonicsArrayId); + + static std::list sUltrasonicsArrayRecordList; + // Weak pointer. Object destructs if client dies. static wp sActiveDisplay; diff --git a/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp b/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp new file mode 100644 index 0000000000..bc69aa4156 --- /dev/null +++ b/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp @@ -0,0 +1,551 @@ +/* + * Copyright 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 "EvsUltrasonicsArray.h" + +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace evs { +namespace V1_1 { +namespace implementation { + +// Arbitrary limit on number of data frames allowed to be allocated +// Safeguards against unreasonable resource consumption and provides a testable limit +const unsigned int kMaximumDataFramesInFlight = 100; + +const uint32_t kMaxReadingsPerSensor = 5; +const uint32_t kMaxReceiversCount = 3; + +const unsigned int kSharedMemoryMaxSize = + kMaxReadingsPerSensor * kMaxReceiversCount * 2 * sizeof(float); + +// Target frame rate in frames per second. +const int kTargetFrameRate = 10; + +namespace { + +void fillDummyArrayDesc(UltrasonicsArrayDesc& arrayDesc) { + arrayDesc.maxReadingsPerSensorCount = kMaxReadingsPerSensor; + arrayDesc.maxReceiversCount = kMaxReceiversCount; + + const int kSensorCount = 3; + const float kMaxRange = 4000; // 4 metres. + const float kAngleOfMeasurement = 0.261799; // 15 degrees. + + std::vector sensors(kSensorCount); + + // Sensor pointing forward on left side of front bumper. + sensors[0].maxRange = kMaxRange; + sensors[0].angleOfMeasurement = kAngleOfMeasurement; + sensors[0].pose = {{1, 0, 0, 0}, {-1000, 2000, 200}}; + + // Sensor pointing forward on center of front bumper. + sensors[1].maxRange = kMaxRange; + sensors[1].angleOfMeasurement = kAngleOfMeasurement; + sensors[1].pose = {{1, 0, 0, 0}, {0, 2000, 200}}; + + // Sensor pointing forward on right side of front bumper. + sensors[2].maxRange = kMaxRange; + sensors[2].angleOfMeasurement = kAngleOfMeasurement; + sensors[2].pose = {{1, 0, 0, 0}, {1000, 2000, 200}}; + + arrayDesc.sensors = sensors; +} + +// Struct used by SerializeWaveformData(). +struct WaveformData { + uint8_t receiverId; + std::vector> readings; +}; + +// Serializes data provided in waveformDataList to a shared memory data pointer. +// TODO(b/149950362): Add a common library for serialiazing and deserializing waveform data. +void SerializeWaveformData(const std::vector& waveformDataList, uint8_t* pData) { + for (auto& waveformData : waveformDataList) { + // Set Id + memcpy(pData, &waveformData.receiverId, sizeof(uint8_t)); + pData += sizeof(uint8_t); + + for (auto& reading : waveformData.readings) { + // Set the time of flight. + memcpy(pData, &reading.first, sizeof(float)); + pData += sizeof(float); + + // Set the resonance. + memcpy(pData, &reading.second, sizeof(float)); + pData += sizeof(float); + } + } +} + +// Fills dataFrameDesc with dummy data. +bool fillDummyDataFrame(UltrasonicsDataFrameDesc& dataFrameDesc, sp pIMemory) { + dataFrameDesc.timestampNs = elapsedRealtimeNano(); + + const std::vector transmittersIdList = {0}; + dataFrameDesc.transmittersIdList = transmittersIdList; + + const std::vector recvIdList = {0, 1, 2}; + dataFrameDesc.receiversIdList = recvIdList; + + const std::vector receiversReadingsCountList = {2, 2, 4}; + dataFrameDesc.receiversReadingsCountList = receiversReadingsCountList; + + const std::vector waveformDataList = { + {recvIdList[0], { {1000, 0.1f}, {2000, 0.8f} }}, + {recvIdList[1], { {1000, 0.1f}, {2000, 1.0f} }}, + {recvIdList[2], { {1000, 0.1f}, {2000, 0.2f}, {4000, 0.2f}, {5000, 0.1f} }} + }; + + if (pIMemory.get() == nullptr) { + return false; + } + + uint8_t* pData = (uint8_t*)((void*)pIMemory->getPointer()); + + pIMemory->update(); + SerializeWaveformData(waveformDataList, pData); + pIMemory->commit(); + + return true; +} + +} // namespace + +EvsUltrasonicsArray::EvsUltrasonicsArray(const char* deviceName) + : mFramesAllowed(0), mFramesInUse(0), mStreamState(STOPPED) { + LOG(DEBUG) << "EvsUltrasonicsArray instantiated"; + + // Set up dummy data for description. + mArrayDesc.ultrasonicsArrayId = deviceName; + fillDummyArrayDesc(mArrayDesc); + + // Assign allocator. + mShmemAllocator = IAllocator::getService("ashmem"); + if (mShmemAllocator.get() == nullptr) { + LOG(ERROR) << "SurroundViewHidlTest getService ashmem failed"; + } +} + +sp EvsUltrasonicsArray::Create(const char* deviceName) { + return sp(new EvsUltrasonicsArray(deviceName)); +} + +EvsUltrasonicsArray::~EvsUltrasonicsArray() { + LOG(DEBUG) << "EvsUltrasonicsArray being destroyed"; + forceShutdown(); +} + +// This gets called if another caller "steals" ownership of the ultrasonic array. +void EvsUltrasonicsArray::forceShutdown() { + LOG(DEBUG) << "EvsUltrasonicsArray forceShutdown"; + + // Make sure our output stream is cleaned up + // (It really should be already) + stopStream(); + + // Claim the lock while we work on internal state + std::lock_guard lock(mAccessLock); + + // Drop all the data frames we've been using + for (auto&& dataFrame : mDataFrames) { + if (dataFrame.inUse) { + LOG(ERROR) << "Error - releasing data frame despite remote ownership"; + } + dataFrame.sharedMemory.clear(); + } + mDataFrames.clear(); + + // Put this object into an unrecoverable error state since somebody else + // is going to own the underlying ultrasonic array now + mStreamState = DEAD; +} + +UltrasonicsArrayDesc EvsUltrasonicsArray::GetDummyArrayDesc(const char* deviceName) { + UltrasonicsArrayDesc ultrasonicsArrayDesc; + ultrasonicsArrayDesc.ultrasonicsArrayId = deviceName; + fillDummyArrayDesc(ultrasonicsArrayDesc); + return ultrasonicsArrayDesc; +} + +Return EvsUltrasonicsArray::getUltrasonicArrayInfo(getUltrasonicArrayInfo_cb _get_info_cb) { + LOG(DEBUG) << "EvsUltrasonicsArray getUltrasonicsArrayInfo"; + + // Return the description for the get info callback. + _get_info_cb(mArrayDesc); + + return Void(); +} + +Return EvsUltrasonicsArray::setMaxFramesInFlight(uint32_t bufferCount) { + LOG(DEBUG) << "EvsUltrasonicsArray setMaxFramesInFlight"; + + // Lock mutex for performing changes to available frames. + std::lock_guard lock(mAccessLock); + + // We cannot function without at least one buffer to send data. + if (bufferCount < 1) { + LOG(ERROR) << "Ignoring setMaxFramesInFlight with less than one buffer requested"; + return EvsResult::INVALID_ARG; + } + + // Update our internal state of buffer count. + if (setAvailableFrames_Locked(bufferCount)) { + return EvsResult::OK; + } else { + return EvsResult::BUFFER_NOT_AVAILABLE; + } + + return EvsResult::OK; +} + +Return EvsUltrasonicsArray::doneWithDataFrame(const UltrasonicsDataFrameDesc& dataFrameDesc) { + LOG(DEBUG) << "EvsUltrasonicsArray doneWithFrame"; + + std::lock_guard lock(mAccessLock); + + if (dataFrameDesc.dataFrameId >= mDataFrames.size()) { + LOG(ERROR) << "ignoring doneWithFrame called with invalid dataFrameId " + << dataFrameDesc.dataFrameId << "(max is " << mDataFrames.size() - 1 << ")"; + return Void(); + } + + if (!mDataFrames[dataFrameDesc.dataFrameId].inUse) { + LOG(ERROR) << "ignoring doneWithFrame called on frame " << dataFrameDesc.dataFrameId + << "which is already free"; + return Void(); + } + + // Mark the frame as available + mDataFrames[dataFrameDesc.dataFrameId].inUse = false; + mFramesInUse--; + + // If this frame's index is high in the array, try to move it down + // to improve locality after mFramesAllowed has been reduced. + if (dataFrameDesc.dataFrameId >= mFramesAllowed) { + // Find an empty slot lower in the array (which should always exist in this case) + for (auto&& dataFrame : mDataFrames) { + if (!dataFrame.sharedMemory.IsValid()) { + dataFrame.sharedMemory = mDataFrames[dataFrameDesc.dataFrameId].sharedMemory; + mDataFrames[dataFrameDesc.dataFrameId].sharedMemory.clear(); + return Void(); + } + } + } + + return Void(); +} + +Return EvsUltrasonicsArray::startStream( + const ::android::sp& stream) { + LOG(DEBUG) << "EvsUltrasonicsArray startStream"; + + std::lock_guard lock(mAccessLock); + + if (mStreamState != STOPPED) { + LOG(ERROR) << "ignoring startStream call when a stream is already running."; + return EvsResult::STREAM_ALREADY_RUNNING; + } + + // If the client never indicated otherwise, configure ourselves for a single streaming buffer + if (mFramesAllowed < 1) { + if (!setAvailableFrames_Locked(1)) { + LOG(ERROR) + << "Failed to start stream because we couldn't get shared memory data buffer"; + return EvsResult::BUFFER_NOT_AVAILABLE; + } + } + + // Record the user's callback for use when we have a frame ready + mStream = stream; + + // Start the frame generation thread + mStreamState = RUNNING; + mCaptureThread = std::thread([this]() { generateDataFrames(); }); + + return EvsResult::OK; +} + +Return EvsUltrasonicsArray::stopStream() { + LOG(DEBUG) << "EvsUltrasonicsArray stopStream"; + + bool streamStateStopping = false; + { + std::lock_guard lock(mAccessLock); + if (mStreamState == RUNNING) { + // Tell the GenerateFrames loop we want it to stop + mStreamState = STOPPING; + streamStateStopping = true; + } + } + + if (streamStateStopping) { + // Block outside the mutex until the "stop" flag has been acknowledged + // We won't send any more frames, but the client might still get some already in flight + LOG(DEBUG) << "Waiting for stream thread to end..."; + mCaptureThread.join(); + } + + { + std::lock_guard lock(mAccessLock); + mStreamState = STOPPED; + mStream = nullptr; + LOG(DEBUG) << "Stream marked STOPPED."; + } + + return Void(); +} + +bool EvsUltrasonicsArray::setAvailableFrames_Locked(unsigned bufferCount) { + if (bufferCount < 1) { + LOG(ERROR) << "Ignoring request to set buffer count to zero"; + return false; + } + if (bufferCount > kMaximumDataFramesInFlight) { + LOG(ERROR) << "Rejecting buffer request in excess of internal limit"; + return false; + } + + // Is an increase required? + if (mFramesAllowed < bufferCount) { + // An increase is required + unsigned needed = bufferCount - mFramesAllowed; + LOG(INFO) << "Number of data frame buffers to add: " << needed; + + unsigned added = increaseAvailableFrames_Locked(needed); + if (added != needed) { + // If we didn't add all the frames we needed, then roll back to the previous state + LOG(ERROR) << "Rolling back to previous frame queue size"; + decreaseAvailableFrames_Locked(added); + return false; + } + } else if (mFramesAllowed > bufferCount) { + // A decrease is required + unsigned framesToRelease = mFramesAllowed - bufferCount; + LOG(INFO) << "Number of data frame buffers to reduce: " << framesToRelease; + + unsigned released = decreaseAvailableFrames_Locked(framesToRelease); + if (released != framesToRelease) { + // This shouldn't happen with a properly behaving client because the client + // should only make this call after returning sufficient outstanding buffers + // to allow a clean resize. + LOG(ERROR) << "Buffer queue shrink failed -- too many buffers currently in use?"; + } + } + + return true; +} + +EvsUltrasonicsArray::SharedMemory EvsUltrasonicsArray::allocateAndMapSharedMemory() { + SharedMemory sharedMemory; + + // Check shared memory allocator is valid. + if (mShmemAllocator.get() == nullptr) { + LOG(ERROR) << "Shared memory allocator not initialized."; + return SharedMemory(); + } + + // Allocate memory. + bool allocateSuccess = false; + Return result = mShmemAllocator->allocate(kSharedMemoryMaxSize, + [&](bool success, const hidl_memory& hidlMem) { + if (!success) { + return; + } + allocateSuccess = success; + sharedMemory.hidlMemory = hidlMem; + }); + + // Check result of allocated memory. + if (!result.isOk() || !allocateSuccess) { + LOG(ERROR) << "Shared memory allocation failed."; + return SharedMemory(); + } + + // Map shared memory. + sharedMemory.pIMemory = mapMemory(sharedMemory.hidlMemory); + if (sharedMemory.pIMemory.get() == nullptr) { + LOG(ERROR) << "Shared memory mapping failed."; + return SharedMemory(); + } + + // Return success. + return sharedMemory; +} + +unsigned EvsUltrasonicsArray::increaseAvailableFrames_Locked(unsigned numToAdd) { + unsigned added = 0; + + while (added < numToAdd) { + SharedMemory sharedMemory = allocateAndMapSharedMemory(); + + // If allocate and map fails, break. + if (!sharedMemory.IsValid()) { + break; + } + + // Find a place to store the new buffer + bool stored = false; + for (auto&& dataFrame : mDataFrames) { + if (!dataFrame.sharedMemory.IsValid()) { + // Use this existing entry + dataFrame.sharedMemory = sharedMemory; + dataFrame.inUse = false; + stored = true; + break; + } + } + + if (!stored) { + // Add a BufferRecord wrapping this handle to our set of available buffers + mDataFrames.emplace_back(sharedMemory); + } + + mFramesAllowed++; + added++; + } + + return added; +} + +unsigned EvsUltrasonicsArray::decreaseAvailableFrames_Locked(unsigned numToRemove) { + unsigned removed = 0; + + for (auto&& dataFrame : mDataFrames) { + // Is this record not in use, but holding a buffer that we can free? + if (!dataFrame.inUse && dataFrame.sharedMemory.IsValid()) { + // Release buffer and update the record so we can recognize it as "empty" + dataFrame.sharedMemory.clear(); + + mFramesAllowed--; + removed++; + + if (removed == numToRemove) { + break; + } + } + } + + return removed; +} + +// This is the asynchronous data frame generation thread that runs in parallel with the +// main serving thread. There is one for each active ultrasonic array instance. +void EvsUltrasonicsArray::generateDataFrames() { + LOG(DEBUG) << "Data frame generation loop started"; + + unsigned idx = 0; + + while (true) { + bool timeForFrame = false; + + nsecs_t startTime = elapsedRealtimeNano(); + + // Lock scope for updating shared state + { + std::lock_guard lock(mAccessLock); + + if (mStreamState != RUNNING) { + // Break out of our main thread loop + break; + } + + // Are we allowed to issue another buffer? + if (mFramesInUse >= mFramesAllowed) { + // Can't do anything right now -- skip this frame + LOG(WARNING) << "Skipped a frame because too many are in flight"; + } else { + // Identify an available buffer to fill + for (idx = 0; idx < mDataFrames.size(); idx++) { + if (!mDataFrames[idx].inUse && mDataFrames[idx].sharedMemory.IsValid()) { + // Found an available record, so stop looking + break; + } + } + if (idx >= mDataFrames.size()) { + // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed + LOG(ERROR) << "Failed to find an available buffer slot"; + } else { + // We're going to make the frame busy + mDataFrames[idx].inUse = true; + mFramesInUse++; + timeForFrame = true; + } + } + } + + if (timeForFrame) { + // Assemble the buffer description we'll transmit below + UltrasonicsDataFrameDesc dummyDataFrameDesc; + dummyDataFrameDesc.dataFrameId = idx; + dummyDataFrameDesc.waveformsData = mDataFrames[idx].sharedMemory.hidlMemory; + + // Fill dummy waveform data. + fillDummyDataFrame(dummyDataFrameDesc, mDataFrames[idx].sharedMemory.pIMemory); + + // Issue the (asynchronous) callback to the client -- can't be holding the lock + auto result = mStream->deliverDataFrame(dummyDataFrameDesc); + if (result.isOk()) { + LOG(DEBUG) << "Delivered data frame id: " << dummyDataFrameDesc.dataFrameId; + } else { + // This can happen if the client dies and is likely unrecoverable. + // To avoid consuming resources generating failing calls, we stop sending + // frames. Note, however, that the stream remains in the "STREAMING" state + // until cleaned up on the main thread. + LOG(ERROR) << "Frame delivery call failed in the transport layer."; + + // Since we didn't actually deliver it, mark the frame as available + std::lock_guard lock(mAccessLock); + mDataFrames[idx].inUse = false; + mFramesInUse--; + + break; + } + } + + // Sleep to generate frames at kTargetFrameRate. + static const nsecs_t kTargetFrameTimeUs = 1000 * 1000 / kTargetFrameRate; + const nsecs_t now = elapsedRealtimeNano(); + const nsecs_t workTimeUs = (now - startTime) / 1000; + const nsecs_t sleepDurationUs = kTargetFrameTimeUs - workTimeUs; + if (sleepDurationUs > 0) { + usleep(sleepDurationUs); + } + } + + // If we've been asked to stop, send an event to signal the actual end of stream + EvsEventDesc event; + event.aType = EvsEventType::STREAM_STOPPED; + auto result = mStream->notify(event); + if (!result.isOk()) { + LOG(ERROR) << "Error delivering end of stream marker"; + } +} + +} // namespace implementation +} // namespace V1_1 +} // namespace evs +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/evs/1.1/default/EvsUltrasonicsArray.h b/automotive/evs/1.1/default/EvsUltrasonicsArray.h new file mode 100644 index 0000000000..7a4101290e --- /dev/null +++ b/automotive/evs/1.1/default/EvsUltrasonicsArray.h @@ -0,0 +1,134 @@ +/* + * Copyright 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_AUTOMOTIVE_EVS_V1_1_EVSULTRASONICSARRAY_H +#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSULTRASONICSARRAY_H + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +using ::android::hardware::hidl_memory; +using ::android::hardware::automotive::evs::V1_0::EvsResult; +using ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArray; +using ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArrayStream; +using ::android::hardware::automotive::evs::V1_1::UltrasonicsArrayDesc; +using ::android::hardware::automotive::evs::V1_1::UltrasonicsDataFrameDesc; +using ::android::hidl::allocator::V1_0::IAllocator; +using ::android::hidl::memory::V1_0::IMemory; + +namespace android { +namespace hardware { +namespace automotive { +namespace evs { +namespace V1_1 { +namespace implementation { + +class EvsUltrasonicsArray : public IEvsUltrasonicsArray { + public: + // Methods from ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArray follow. + Return getUltrasonicArrayInfo(getUltrasonicArrayInfo_cb _get_info_cb) override; + Return setMaxFramesInFlight(uint32_t bufferCount) override; + Return doneWithDataFrame(const UltrasonicsDataFrameDesc& dataFrameDesc) override; + Return startStream(const ::android::sp& stream) override; + Return stopStream() override; + + // Factory function to create a array. + static sp Create(const char* deviceName); + + // Returns a ultrasonics array descriptor filled with sample data. + static UltrasonicsArrayDesc GetDummyArrayDesc(const char* id); + + DISALLOW_COPY_AND_ASSIGN(EvsUltrasonicsArray); + virtual ~EvsUltrasonicsArray() override; + void forceShutdown(); // This gets called if another caller "steals" ownership + + private: + // Structure holding the hidl memory struct and the interface to a shared memory. + struct SharedMemory { + hidl_memory hidlMemory; + sp pIMemory; + + SharedMemory() : hidlMemory(hidl_memory()), pIMemory(nullptr){}; + + SharedMemory(hidl_memory hidlMem, sp pIMem) + : hidlMemory(hidlMem), pIMemory(pIMem) {} + + bool IsValid() { return (pIMemory.get() != nullptr && hidlMemory.valid()); } + + void clear() { + hidlMemory = hidl_memory(); + pIMemory.clear(); + } + }; + + // Struct for a data frame record. + struct DataFrameRecord { + SharedMemory sharedMemory; + bool inUse; + explicit DataFrameRecord(SharedMemory shMem) : sharedMemory(shMem), inUse(false){}; + }; + + enum StreamStateValues { + STOPPED, + RUNNING, + STOPPING, + DEAD, + }; + + EvsUltrasonicsArray(const char* deviceName); + + // These three functions are expected to be called while mAccessLock is held + bool setAvailableFrames_Locked(unsigned bufferCount); + unsigned increaseAvailableFrames_Locked(unsigned numToAdd); + unsigned decreaseAvailableFrames_Locked(unsigned numToRemove); + + void generateDataFrames(); + + SharedMemory allocateAndMapSharedMemory(); + + UltrasonicsArrayDesc mArrayDesc = {}; // The properties of this ultrasonic array. + + std::thread mCaptureThread; // The thread we'll use to synthesize frames + + sp mStream = nullptr; // The callback used to deliver each frame + + sp mShmemAllocator = nullptr; // Shared memory allocator. + + std::mutex mAccessLock; + std::vector mDataFrames GUARDED_BY(mAccessLock); // Shared memory buffers. + unsigned mFramesAllowed GUARDED_BY(mAccessLock); // How many buffers are we currently using. + unsigned mFramesInUse GUARDED_BY(mAccessLock); // How many buffers are currently outstanding. + + StreamStateValues mStreamState GUARDED_BY(mAccessLock); +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace evs +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSULTRASONICSARRAY_H From d91f1c3e97d40073d487ae3e63a312f43f2c6dbe Mon Sep 17 00:00:00 2001 From: Tanmay Patil Date: Tue, 11 Feb 2020 17:28:14 -0800 Subject: [PATCH 0629/1022] Add VTS for Ultrasonics to EVS 1.1 Bug: 148619310 Test: atest VtsHalEvsV1_1TargetTest Change-Id: If91bce64cf06fd374b3829b0f01804bdc375197d --- automotive/evs/1.1/vts/functional/Android.bp | 6 +- .../functional/FrameHandlerUltrasonics.cpp | 169 ++++++++++++++++++ .../vts/functional/FrameHandlerUltrasonics.h | 53 ++++++ .../functional/VtsHalEvsV1_1TargetTest.cpp | 126 ++++++++++++- 4 files changed, 351 insertions(+), 3 deletions(-) create mode 100644 automotive/evs/1.1/vts/functional/FrameHandlerUltrasonics.cpp create mode 100644 automotive/evs/1.1/vts/functional/FrameHandlerUltrasonics.h diff --git a/automotive/evs/1.1/vts/functional/Android.bp b/automotive/evs/1.1/vts/functional/Android.bp index 4753933f7f..086a199ca5 100644 --- a/automotive/evs/1.1/vts/functional/Android.bp +++ b/automotive/evs/1.1/vts/functional/Android.bp @@ -18,12 +18,16 @@ cc_test { name: "VtsHalEvsV1_1TargetTest", srcs: [ "FrameHandler.cpp", + "FrameHandlerUltrasonics.cpp", "VtsHalEvsV1_1TargetTest.cpp", ], defaults: ["VtsHalTargetTestDefaults"], shared_libs: [ "libui", "libcamera_metadata", + "libhidlmemory", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", ], static_libs: [ "android.hardware.automotive.evs@1.0", @@ -34,7 +38,7 @@ cc_test { "android.hardware.graphics.common@1.2", "android.hardware.camera.device@3.2", ], - test_suites: ["general-tests"], + test_suites: ["vts-core"], cflags: [ "-O0", "-g", diff --git a/automotive/evs/1.1/vts/functional/FrameHandlerUltrasonics.cpp b/automotive/evs/1.1/vts/functional/FrameHandlerUltrasonics.cpp new file mode 100644 index 0000000000..22522ced67 --- /dev/null +++ b/automotive/evs/1.1/vts/functional/FrameHandlerUltrasonics.cpp @@ -0,0 +1,169 @@ +/* + * Copyright 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 "FrameHandlerUltrasonics.h" + +#include +#include +#include + +using ::android::hidl::memory::V1_0::IMemory; +using ::android::hardware::Return; +using ::android::sp; + +using ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArrayStream; +using ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArray; +using ::android::hardware::automotive::evs::V1_1::UltrasonicsDataFrameDesc; +using ::android::hardware::automotive::evs::V1_1::EvsEventDesc; +using ::android::hardware::automotive::evs::V1_1::EvsEventType; + +FrameHandlerUltrasonics::FrameHandlerUltrasonics(sp pEvsUltrasonicsArray) : + mEvsUltrasonicsArray(pEvsUltrasonicsArray), mReceiveFramesCount(0) { + // Nothing but member initialization +} + +Return FrameHandlerUltrasonics::notify(const EvsEventDesc& evsEvent) { + switch (evsEvent.aType) { + case EvsEventType::STREAM_STARTED: + case EvsEventType::STREAM_STOPPED: + case EvsEventType::FRAME_DROPPED: + case EvsEventType::TIMEOUT: + mReceivedEvents.emplace_back(evsEvent); + break; + default: + LOG(ERROR) << "Received unexpected event"; + } + + return android::hardware::Void(); +} + +// Struct used by SerializeWaveformData(). +struct WaveformData { + uint8_t receiverId; + std::vector> readings; +}; + +// De-serializes shared memory to vector of WaveformData. +// TODO(b/149950362): Add a common library for serialiazing and deserializing waveform data. +std::vector DeSerializeWaveformData(std::vector recvReadingsCountList, + uint8_t* pData) { + std::vector waveformDataList(recvReadingsCountList.size()); + + for (int i = 0; i < waveformDataList.size(); i++) { + // Set Id + memcpy(&waveformDataList[i].receiverId, pData, sizeof(uint8_t)); + pData += sizeof(uint8_t); + + waveformDataList[i].readings.resize(recvReadingsCountList[i]); + + for (auto& reading : waveformDataList[i].readings) { + // Set the time of flight. + memcpy(&reading.first, pData, sizeof(float)); + pData += sizeof(float); + + // Set the resonance. + memcpy(&reading.second, pData, sizeof(float)); + pData += sizeof(float); + } + } + return waveformDataList; +} + +bool DataFrameValidator(const UltrasonicsDataFrameDesc& dataFrameDesc) { + + if (dataFrameDesc.receiversIdList.size() != dataFrameDesc.receiversReadingsCountList.size()) { + LOG(ERROR) << "Size mismatch of receiversIdList and receiversReadingsCountList"; + return false; + } + + if(!dataFrameDesc.waveformsData.valid()) { + LOG(ERROR) << "Data frame does not valid hidl memory"; + return false; + } + + // Check total bytes from dataFrameDesc are within the shared memory size. + int totalWaveformDataBytesSize = 0; + for (int i = 0; i < dataFrameDesc.receiversIdList.size(); i++) { + totalWaveformDataBytesSize = 1 + (4 * 2 * dataFrameDesc.receiversReadingsCountList[i]); + } + if (totalWaveformDataBytesSize > dataFrameDesc.waveformsData.size()) { + LOG(ERROR) << "Total waveform data bytes in desc exceed shared memory size"; + return false; + } + + sp pIMemory = mapMemory(dataFrameDesc.waveformsData); + if(pIMemory.get() == nullptr) { + LOG(ERROR) << "Failed to map hidl memory"; + return false; + } + + uint8_t* pData = (uint8_t*)((void*)pIMemory->getPointer()); + if(pData == nullptr) { + LOG(ERROR) << "Failed getPointer from mapped shared memory"; + return false; + } + + const std::vector waveformDataList = DeSerializeWaveformData( + dataFrameDesc.receiversReadingsCountList, pData); + + // Verify the waveforms data. + for(int i = 0; i < waveformDataList.size(); i++) { + if (waveformDataList[i].receiverId != dataFrameDesc.receiversIdList[i]) { + LOG(ERROR) << "Receiver Id mismatch"; + return false; + } + for(auto& reading : waveformDataList[i].readings) { + if (reading.second < 0.0f || reading.second > 1.0f) { + LOG(ERROR) << "Resonance reading is not in range [0, 1]"; + return false; + } + } + } + return true; +} + +Return FrameHandlerUltrasonics::deliverDataFrame( + const UltrasonicsDataFrameDesc& dataFrameDesc) { + LOG(DEBUG) << "FrameHandlerUltrasonics::receiveFrames"; + + mReceiveFramesCount++; + mLastReceivedFrames = dataFrameDesc; + + if(!DataFrameValidator(dataFrameDesc)) { + mAllFramesValid = false; + } + + // Send done with data frame. + mEvsUltrasonicsArray->doneWithDataFrame(dataFrameDesc); + + return android::hardware::Void(); +} + +bool FrameHandlerUltrasonics::checkEventReceived(EvsEventDesc evsEvent) { + LOG(DEBUG) << "FrameHandlerUltrasonics::checkEventReceived"; + int size = mReceivedEvents.size(); // work around + LOG(DEBUG) << "Received event number: " << size; + auto iter = find(mReceivedEvents.begin(), mReceivedEvents.end(), evsEvent); + return iter != mReceivedEvents.end(); +} + +int FrameHandlerUltrasonics::getReceiveFramesCount() { + return mReceiveFramesCount; +} + +bool FrameHandlerUltrasonics::areAllFramesValid() { + return mAllFramesValid; +} diff --git a/automotive/evs/1.1/vts/functional/FrameHandlerUltrasonics.h b/automotive/evs/1.1/vts/functional/FrameHandlerUltrasonics.h new file mode 100644 index 0000000000..1fc2143605 --- /dev/null +++ b/automotive/evs/1.1/vts/functional/FrameHandlerUltrasonics.h @@ -0,0 +1,53 @@ +/* + * Copyright 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 FRAME_HANDLER_ULTRASONICS_H +#define FRAME_HANDLER_ULTRASONICS_H + +#include +#include +#include + +#include + +class FrameHandlerUltrasonics : public + android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArrayStream { +public: + FrameHandlerUltrasonics( + android::sp + pEvsUltrasonicsArray); + + // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArrayStream + android::hardware::Return notify( + const android::hardware::automotive::evs::V1_1::EvsEventDesc& evsEvent) override; + android::hardware::Return deliverDataFrame( + const android::hardware::automotive::evs::V1_1::UltrasonicsDataFrameDesc& + dataFrameDesc) override; + + bool checkEventReceived(android::hardware::automotive::evs::V1_1::EvsEventDesc evsEvent); + int getReceiveFramesCount(); + bool areAllFramesValid(); + +private: + android::sp + mEvsUltrasonicsArray; + android::hardware::automotive::evs::V1_1::UltrasonicsDataFrameDesc mLastReceivedFrames; + std::vector mReceivedEvents; + int mReceiveFramesCount; + bool mAllFramesValid = true; +}; + +#endif //FRAME_HANDLER_ULTRASONICS_H diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index ce02973ac2..85c3d68493 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -37,6 +37,7 @@ static const float kNanoToSeconds = 0.000000001f; #include "FrameHandler.h" +#include "FrameHandlerUltrasonics.h" #include #include @@ -151,9 +152,21 @@ protected: } } ); + } - // We insist on at least one camera for EVS to pass any camera tests - ASSERT_GE(cameraInfo.size(), 1u); + void loadUltrasonicsArrayList() { + // SetUp() must run first! + assert(pEnumerator != nullptr); + + // Get the ultrasonics array list + pEnumerator->getUltrasonicsArrayList([this](hidl_vec ultraList) { + ALOGI("Ultrasonics array list callback received %zu arrays", ultraList.size()); + ultrasonicsArraysInfo.reserve(ultraList.size()); + for (auto&& ultraArray : ultraList) { + ALOGI("Found ultrasonics array %s", ultraArray.ultrasonicsArrayId.c_str()); + ultrasonicsArraysInfo.push_back(ultraArray); + } + }); } bool isLogicalCamera(const camera_metadata_t *metadata) { @@ -240,6 +253,11 @@ protected: // is HW module implementation. std::deque> activeCameras; // A list of active camera handles that are // needed to be cleaned up. + std::vector + ultrasonicsArraysInfo; // Empty unless/until + // loadUltrasonicsArrayList() is called + std::deque> activeUltrasonicsArrays; // A list of active ultrasonic array + // handles that are to be cleaned up. }; @@ -2209,6 +2227,110 @@ TEST_F(EvsHidlTest, LogicalCameraMetadata) { } +/* + * UltrasonicsArrayOpenClean: + * Opens each ultrasonics arrays reported by the enumerator and then explicitly closes it via a + * call to closeUltrasonicsArray. Then repeats the test to ensure all ultrasonics arrays + * can be reopened. + */ +TEST_F(EvsHidlTest, UltrasonicsArrayOpenClean) { + ALOGI("Starting UltrasonicsArrayOpenClean test"); + + // Get the ultrasonics array list + loadUltrasonicsArrayList(); + + // Open and close each ultrasonics array twice + for (auto&& ultraInfo : ultrasonicsArraysInfo) { + for (int pass = 0; pass < 2; pass++) { + sp pUltrasonicsArray = + pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId); + ASSERT_NE(pUltrasonicsArray, nullptr); + + // Verify that this ultrasonics array self-identifies correctly + pUltrasonicsArray->getUltrasonicArrayInfo([&ultraInfo](UltrasonicsArrayDesc desc) { + ALOGD("Found ultrasonics array %s", ultraInfo.ultrasonicsArrayId.c_str()); + EXPECT_EQ(ultraInfo.ultrasonicsArrayId, desc.ultrasonicsArrayId); + }); + + // Explicitly close the ultrasonics array so resources are released right away + pEnumerator->closeUltrasonicsArray(pUltrasonicsArray); + } + } +} + + +// Starts a stream and verifies all data received is valid. +TEST_F(EvsHidlTest, UltrasonicsVerifyStreamData) { + ALOGI("Starting UltrasonicsVerifyStreamData"); + + // Get the ultrasonics array list + loadUltrasonicsArrayList(); + + // For each ultrasonics array. + for (auto&& ultraInfo : ultrasonicsArraysInfo) { + ALOGD("Testing ultrasonics array: %s", ultraInfo.ultrasonicsArrayId.c_str()); + + sp pUltrasonicsArray = + pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId); + ASSERT_NE(pUltrasonicsArray, nullptr); + + sp frameHandler = new FrameHandlerUltrasonics(pUltrasonicsArray); + + // Start stream. + EvsResult result = pUltrasonicsArray->startStream(frameHandler); + ASSERT_EQ(result, EvsResult::OK); + + // Wait 5 seconds to receive frames. + sleep(5); + + // Stop stream. + pUltrasonicsArray->stopStream(); + + EXPECT_GT(frameHandler->getReceiveFramesCount(), 0); + EXPECT_TRUE(frameHandler->areAllFramesValid()); + + // Explicitly close the ultrasonics array so resources are released right away + pEnumerator->closeUltrasonicsArray(pUltrasonicsArray); + } +} + + +// Sets frames in flight before and after start of stream and verfies success. +TEST_F(EvsHidlTest, UltrasonicsSetFramesInFlight) { + ALOGI("Starting UltrasonicsSetFramesInFlight"); + + // Get the ultrasonics array list + loadUltrasonicsArrayList(); + + // For each ultrasonics array. + for (auto&& ultraInfo : ultrasonicsArraysInfo) { + ALOGD("Testing ultrasonics array: %s", ultraInfo.ultrasonicsArrayId.c_str()); + + sp pUltrasonicsArray = + pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId); + ASSERT_NE(pUltrasonicsArray, nullptr); + + EvsResult result = pUltrasonicsArray->setMaxFramesInFlight(10); + EXPECT_EQ(result, EvsResult::OK); + + sp frameHandler = new FrameHandlerUltrasonics(pUltrasonicsArray); + + // Start stream. + result = pUltrasonicsArray->startStream(frameHandler); + ASSERT_EQ(result, EvsResult::OK); + + result = pUltrasonicsArray->setMaxFramesInFlight(5); + EXPECT_EQ(result, EvsResult::OK); + + // Stop stream. + pUltrasonicsArray->stopStream(); + + // Explicitly close the ultrasonics array so resources are released right away + pEnumerator->closeUltrasonicsArray(pUltrasonicsArray); + } +} + + int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance()); ::testing::InitGoogleTest(&argc, argv); From 6bdb811fa7720a3c422d16c515eda0a1d8dff62e Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Mon, 23 Dec 2019 16:10:31 -0800 Subject: [PATCH 0630/1022] [SV HIDL] Adds HAL interfaces for surround view. Bug: 148618804 Test: Build passed. Change-Id: Ie5d8540258d456408394e9ac4256db764f6b3cd7 --- automotive/sv/1.0/Android.bp | 24 ++ automotive/sv/1.0/ISurroundView2dSession.hal | 84 +++++ automotive/sv/1.0/ISurroundView3dSession.hal | 113 ++++++ automotive/sv/1.0/ISurroundViewService.hal | 71 ++++ automotive/sv/1.0/ISurroundViewSession.hal | 51 +++ automotive/sv/1.0/ISurroundViewStream.hal | 38 ++ automotive/sv/1.0/types.hal | 351 ++++++++++++++++++ .../compatibility_matrix.current.xml | 8 + 8 files changed, 740 insertions(+) create mode 100644 automotive/sv/1.0/Android.bp create mode 100644 automotive/sv/1.0/ISurroundView2dSession.hal create mode 100644 automotive/sv/1.0/ISurroundView3dSession.hal create mode 100644 automotive/sv/1.0/ISurroundViewService.hal create mode 100644 automotive/sv/1.0/ISurroundViewSession.hal create mode 100644 automotive/sv/1.0/ISurroundViewStream.hal create mode 100644 automotive/sv/1.0/types.hal diff --git a/automotive/sv/1.0/Android.bp b/automotive/sv/1.0/Android.bp new file mode 100644 index 0000000000..769bdc62d8 --- /dev/null +++ b/automotive/sv/1.0/Android.bp @@ -0,0 +1,24 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.automotive.sv@1.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "ISurroundViewStream.hal", + "ISurroundViewSession.hal", + "ISurroundView2dSession.hal", + "ISurroundView3dSession.hal", + "ISurroundViewService.hal", + ], + interfaces: [ + "android.hidl.base@1.0", + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + ], + gen_java: true, +} diff --git a/automotive/sv/1.0/ISurroundView2dSession.hal b/automotive/sv/1.0/ISurroundView2dSession.hal new file mode 100644 index 0000000000..fa4967465e --- /dev/null +++ b/automotive/sv/1.0/ISurroundView2dSession.hal @@ -0,0 +1,84 @@ +/* + * Copyright 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. + */ + +package android.hardware.automotive.sv@1.0; + +import ISurroundViewSession; + +/** + * Interface representing a surround view 2d session. + * + * Surround view 2d provides a top/bird's eye view of the car and its surroundings. + */ +interface ISurroundView2dSession extends ISurroundViewSession { + + /** + * Gets mapping information for 2d surround view. + * + * Mapping information maps the output frame of 2d surround view to actual dimensions + * covered on the ground. Mapping information is fixed for a car and is based upon its camera + * coverage. Mapping information can be used for doing overlays of objects in 3d space + * onto the surround view 2d output frame. + * + * @param sv2dConfig Configuration to set. + * @return sv2dMappingInfo mapping information of the 2d surround view. + */ + get2dMappingInfo() generates (Sv2dMappingInfo sv2dMappingInfo); + + /** + * Sets the configuration of 2d surround view. + * + * Configuration is used for supported different target use-cases of the surround view eg. + * fullscreen or preview. Default configuration is FULLSCREEN. + * A set config call can be performed at any time (before or after startStream) of the session. + * Once config change is complete, a CONFIG_CHANGED event is sent, after which + * all frames received will be of the updated config. + * + * @param sv2dConfig Configuration to set. + * @return svResult Returns OK if successful, appropriate error result otherwise. + */ + set2dConfig(Sv2dConfig sv2dConfig) generates (SvResult svResult); + + /** + * Gets the current configuration of the 2d surround view. + * + * Configuration is used for supported different target use-cases of the surround view eg. + * fullscreen view or preview. Use setConfig call to set a configuration. + * + * @return sv2dConfig the active current configuration of the 2d session. + */ + get2dConfig() generates (Sv2dConfig sv2dConfig); + + /** + * Projects points on camera image to surround view 2d image. + * + * Useful for mapping points detected on individual camera frames onto the surround view 2d + * output frame. + * + * @param cameraPoints List of camera pixel points to be projected in range including (0, 0) + * and (width - 1, height -1) of camera frame. If point is outside camera + frame INVALID_ARG error is returned. + * @param cameraId Id of the EvsCamera to use for projecting points. Id must be one of the + * cameras as returned by getCameraIds() else INVALID_ARG error is returned + * @return points2d Returns a list of 2d pixel points projecting into surround view 2d + * frame in the same order as cameraPoints. Point projected maybe outside + * surround view frame i.e. outside (0, 0) and + * (sv_width - 1, sv_height - 1). Points that do not project to ground + * plane are set with inValid true. + */ + projectCameraPoints(vec cameraPoints, string cameraId) generates ( + vec points2d); +}; diff --git a/automotive/sv/1.0/ISurroundView3dSession.hal b/automotive/sv/1.0/ISurroundView3dSession.hal new file mode 100644 index 0000000000..d2b0c53106 --- /dev/null +++ b/automotive/sv/1.0/ISurroundView3dSession.hal @@ -0,0 +1,113 @@ +/* + * Copyright 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. + */ + +package android.hardware.automotive.sv@1.0; + +import ISurroundViewSession; + +/** + * Interface representing a surround view 3d session. + * + * Surround view 3d provides a virtual view from any desired position in the 3d space around the + * car. Surround view 3d creates an approximate 3d surface around the car to match the surrounds + * and provides a virtual view as seen on this surface. + */ +interface ISurroundView3dSession extends ISurroundViewSession { + + /** + * Sets the desired views of surround view 3d. + * + * Surround view 3d takes a list of desired virtual view points and provides an output frame + * for each view. Default view list is a single view from behind the car front facing in the + * front direction. + * A call to setViews() results in the views set by a previous call to be discarded. + * Each view set is identified by an Id which is returned with the corresponding output frame + * of that view. + * Clients can call setViews() at any stage of the session (before/after startStream). Client + * may continue to receive frames of previous views after setViews() call for a while and can + * identify updated set of views once effective using the view Id provided in the updated + * views frames. + * + * @param views List of desired views to generate output frames. + * @return svResult Returns OK if successful, appropriate error result otherwise. + */ + setViews(vec views) generates (SvResult svResult); + + /** + * Sets the configuration of 3d surround view. + * + * Configuration is used for supported different target use-cases of the surround view eg. + * fullscreen view or preview. A set config call can be performed at anytime (before or after + * startStream) of the session. + * Once config change is complete, a CONFIG_CHANGED event is sent, after which + * all frames received will be of the updated config. + * + * @param sv3dConfig Configuration to set. + * @return svResult Returns OK if successful, appropriate error result otherwise. + */ + set3dConfig(Sv3dConfig sv3dConfig) generates (SvResult svResult); + + /** + * Gets the current configuration of the 3d surround view. + * + * Configuration is used for supported different target use-cases of the surround view eg. + * fullscreen view or preview. Use setConfig call to set a configuration. + * + * @return sv3dConfig The current active configuration of the 3d session. + */ + get3dConfig() generates (Sv3dConfig sv3dConfig); + + /** + * Updates 3d overlays in scene. + * + * updateOverlays() provides a way to set a 3d overlay object in the scene. An overlay is an + * 3d object in the scene which can be a visual indicator to provide additional information eg. + * parking sensor distance indicators or overlays for objects in scene. + * + * An overlay object is defined by a set of points (forming triangles) with some color and + * transparency values and each overlay is identified by an overlay Id. + * When an overlay with a new Id is passed, a new overlay is added to the scene. + * When an overlay with previous id is passed, its vertices/color are updated with passed data. + * If the overlay data is empty, the overlay is removed from the scene. + * + * @param overlaysData Object with shared memory containing overlays to add/update in the + * scene. Refer to OverlaysData structure for layout in shared memory. + * @return svResult Returns OK if successful, appropriate error result otherwise. + */ + updateOverlays(OverlaysData overlaysData) generates (SvResult svResult); + + /** + * Projects points on camera image to surround view 3D surface. + * + * Useful for mapping points detected on individual camera frames onto the surround view 3D + * surface, these 3d points can then be used to set overlays using the updateOverlays() for + * the detected objects in the scene. + * Note: + * 3d points returned are projected on an approximate 3d surface and do not provide the exact + * 3d location. + * + * @param cameraPoints List of camera pixel points to be projected in range including (0, 0) + * and (width - 1, height -1) of camera frame. If point is outside camera + frame INVALID_ARG error is returned. + * @param cameraId Id of the EvsCamera to use for projecting points. Id must be one of the + * cameras as returned by getCameraIds() else INVALID_ARG error is returned + * @return points3d Returns a list of 3d points on the approximate 3d surface in the + * automotive coordinate system in the same order as cameraPoints. + * Points that do not project to 3d surface are set with inValid true. + */ + projectCameraPointsTo3dSurface(vec cameraPoints, string cameraId) generates ( + vec points3d); +}; diff --git a/automotive/sv/1.0/ISurroundViewService.hal b/automotive/sv/1.0/ISurroundViewService.hal new file mode 100644 index 0000000000..7de0bd13f8 --- /dev/null +++ b/automotive/sv/1.0/ISurroundViewService.hal @@ -0,0 +1,71 @@ +/* + * Copyright 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. + */ + +package android.hardware.automotive.sv@1.0; + +import ISurroundView2dSession; +import ISurroundView3dSession; + +/** + * Interface representing entry point for surround view. + * + * Surround view service has two types of sessions 2d and 3d. Refer to their respective interface + * for more details. + */ +interface ISurroundViewService { + + /** + * Gets a list of camera ids that are used for generating surround view. + * For 4 camera configuration, the cameras ids are ordered in clockwise direction + * when viewed from top of the car starting with the front camera. i.e. FRONT, RIGHT, REAR and + * LEFT. All other configurations must follow clockwise order. + * + * @result cameraIds List of camera ids that matching the Id of EVS Cameras used by service. + */ + getCameraIds() generates (vec cameraIds); + + /** + * Starts a surround view 2d session. + * + * @result sv2dSession Returns a new 2d session that was created. + * result Returns OK if successful, appropriate error result otherwise. + */ + start2dSession() generates (ISurroundView2dSession sv2dSession, SvResult result); + + /** + * Stops a surround view 2d session. + * + * @param sv2dSession Valid 2d session to be stopped. + * @return svResult Returns OK if successful, appropriate error result otherwise. + */ + stop2dSession(ISurroundView2dSession sv2dSession) generates (SvResult result); + + /** + * Starts a surround view 3d session. + * + * @result sv3dSession Returns a new 3d session that was created. + * result Returns OK if successful, appropriate error result otherwise. + */ + start3dSession() generates (ISurroundView3dSession sv3dSession, SvResult result); + + /** + * Stops a surround view 2d session. + * + * @param sv2dSession Valid 2d session to be stopped. + * @return svResult Returns OK if successful, appropriate error result otherwise. + */ + stop3dSession(ISurroundView3dSession sv3dSession) generates (SvResult result); +}; diff --git a/automotive/sv/1.0/ISurroundViewSession.hal b/automotive/sv/1.0/ISurroundViewSession.hal new file mode 100644 index 0000000000..62cfac0ab8 --- /dev/null +++ b/automotive/sv/1.0/ISurroundViewSession.hal @@ -0,0 +1,51 @@ +/* + * Copyright 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. + */ + +package android.hardware.automotive.sv@1.0; + +import ISurroundViewStream; + +/** + * Common interface for surround view session extended by surround view 2d and 3d + * session. + */ +interface ISurroundViewSession { + /** + * Requests to start receiving surround view frames. + * + * For surround view 3d, setViews() must be set before calling startStream(). + * + * @param stream Stream to receiving callbacks for the session. + * @return svResult Returns OK if successful, returns VIEW_NOT_SET if setViews() is not + * called for surround view 3d, appropriate error results otherwise. + */ + startStream(ISurroundViewStream stream) generates (SvResult svResult); + + /** + * Requests to stop stream. + * + * Frames may continue to arrive after call returns. Each must be returned until + * the closure of the stream is signaled by the ISurroundViewStream. + */ + stopStream(); + + /** + * Signal from client that a frame, which was delivered by the stream, has been consumed. + * + * @param svFramesDesc Descriptor to signal done with frame. + */ + oneway doneWithFrames(SvFramesDesc svFramesDesc); +}; diff --git a/automotive/sv/1.0/ISurroundViewStream.hal b/automotive/sv/1.0/ISurroundViewStream.hal new file mode 100644 index 0000000000..22d610f842 --- /dev/null +++ b/automotive/sv/1.0/ISurroundViewStream.hal @@ -0,0 +1,38 @@ +/* + * Copyright 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. + */ + +package android.hardware.automotive.sv@1.0; + +/** + * Interface representing a surround view stream. + * + * This interface is to be implemented by client to receive callback for output frames and events. + */ +interface ISurroundViewStream { + /** + * Receives callback of surround view 2d/3d frames. + * + * @param svFramesDesc Frames descriptor containing the output frames. + */ + oneway receiveFrames(SvFramesDesc svFramesDesc); + + /** + * Receives callback for surround view events. + * + * @param svEvent Surround view event. + */ + oneway notify(SvEvent svEvent); +}; diff --git a/automotive/sv/1.0/types.hal b/automotive/sv/1.0/types.hal new file mode 100644 index 0000000000..573bf11322 --- /dev/null +++ b/automotive/sv/1.0/types.hal @@ -0,0 +1,351 @@ +/* + * Copyright 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. + */ + +package android.hardware.automotive.sv@1.0; + +import android.hardware.graphics.common@1.2::HardwareBuffer; + +/** Structure for translation with x, y and z units. */ +struct Translation { + float x; + float y; + float z; +}; + +/** + * Structure for rotation expressed as quaternions. + * Convention used: Unit quaternion with hamilton convention. + */ +struct RotationQuat { + float x; + float y; + float z; + float w; +}; + +/** Structure representing a 2D point with integers. Units are pixels. */ +struct Point2dInt { + uint32_t x; + uint32_t y; +}; + +/** Structure representing a 2D point with floats. */ +struct Point2dFloat { + /** Boolean flag to indicate the (x, y) data is valid. */ + bool isValid; + + /** (x, y) data is only valid if isValid is true. Units are pixels or milli-meters. */ + float x; + float y; +}; + +/** Structure representing a 3D point with floats. */ +struct Point3dFloat { + /** Boolean flag to indicate the (x, y, z) data is valid. */ + bool isValid; + + /** + * (x, y, z) data is only valid if isValid is true. Units are milli-meters. + */ + float x; + float y; + float z; +}; + +/** + * Structure defining the pose in 3D space. + */ +struct Pose { + /** + * Rotation part of the pose, expressed as a unit quaternion. + */ + RotationQuat rotation; + + /** + * Translation part of the pose, in (x, y, z) format with milli-meter units. + */ + Translation translation; +}; + +/** + * Struct defining a virtual view in the 3d space around the car. + */ +struct View3d { + /** + * Id to identify each custom view, this is passed along in each result SvBuffer. + * Recommend client to have a unique id for each different view. + */ + uint32_t viewId; + + /** + * Pose of the view. Describes the orientation and location of a virtual view relative to the + * android automotive coordinate system: + * https://source.android.com/devices/sensors/sensor-types#auto_axes + * The virtual view axes are defined as +Y as look-at direction, +X as right direction and + * +Z as up direction. + * The rotation and translation of the virtual view axes w.r.t the android automotive axes is + * specified by the rotation and tranlation component of the pose respectively. + * Example: A virtual view points to the right face of the car, located on right side of + * the car at (4, 2, 0) and is upright w.r.t the ground : + * ______ + * front | | + * | car | ↑X + * | ↑Y | Y←∘ view + * rear | ∘→X | (4,2) + * |(0,0) | + * |______| + * + * Here the view axes are rotated by 90 counter-clockwise w.r.t android automotive axes. + * For this example the rotation and translation will be: + * Rotation = + 90 degrees around Z axis = (0.7071, 0, 0, 0.7071) as a unit quaternion. + * Translation = (4, 2, 0) in meters = (2000, 4000, 0) in milli-meters. + */ + Pose pose; + + /** + * Horizontal field of view of the virtual view in degrees. Vertical fov is scaled accordingly + * to maintain the aspect ratio of the output frame. Must be in range (20, + */ + float horizontalFov; +}; + +/** + * Memory Buffer that stores the output of a single view from 2d/3d surround view. + */ +struct SvBuffer { + /** + * viewId identifying the view as passed by the client in setViews() call for + * surround view 3d. Id value is 0 for 2d surround view frame. + */ + uint32_t viewId; + + /** Hardware buffer containing the surround view 2d/3d result. */ + HardwareBuffer hardwareBuffer; +}; + +/** + * Structure describing a set of frames to be returned as output from 2d/3d surround view. + */ +struct SvFramesDesc { + /** + * Elapsed real-time nanoseconds of earliest camera frame from the set of camera + * frames used to generate the view. + */ + uint64_t timestampNs; + + /** + * Incremental counter for client to keep track of frames. + */ + uint32_t sequenceId; + + /** + * Frames generated with different views. + * 2d surround view has only a single svBuffer with Id 0. + */ + vec svBuffers; +}; + +/** + * Enumerator for list of result returns by surround view . + */ +enum SvResult : uint32_t { + /** Operation was successful. */ + OK = 0, + + /** Invalid argument to function was provided. */ + INVALID_ARG, + + /** Error indicating the particular operation is not supported. */ + NOT_SUPPORTED, + + /** Error indicating view not set before starting stream. */ + VIEW_NOT_SET, + + /** + * Error indicating system does not currently have enough resources to + * allocate for a new requested session. + * Clients may retry request for session if resources become available. + */ + NO_RESOURCE, + + /** Internal error in surround view service. */ + INTERNAL_ERROR, +}; + +/** + * Enumerator listing events for surround view. + */ +enum SvEvent : uint32_t { + STREAM_STARTED = 1, + + STREAM_STOPPED, + + /** + * Event sent after service switches to an updated config, all frames + * streamed after this event are of the updated config. + */ + CONFIG_UPDATED, + + /** Each frame dropped will be notified with this event. */ + FRAME_DROPPED, + + /** + * Timeout event occurs if any individual camera stream has a timeout. + * Frames will not be delivered and clients must stop the stream. + */ + TIMEOUT, +}; + +/** + * Structure defining the mapping information for 2d surround view. + * + * Mapping information provides the area on ground (width and height) and + * position w.r.t the car that the surround view 2d covers. This can be used for + * mapping (linear transformation) with other sensors whose data is available in + * the car coordinate system (eg. Ultrasonics). + * Axes and origin are as per the android automotive axes: + * https://source.android.com/devices/sensors/sensor-types#auto_axes + */ +struct Sv2dMappingInfo { + /** Width in milli-meters of the 2d surround view along the ground plane. */ + float width; + + /** Height in milli-meters of the 2d surround view along the ground plane. */ + float height; + + /** + * Coordinates (x, y) of the center of the view in android automotive coordinate system on the + * ground plane. Units are milli-meters. + */ + Point2dFloat center; +}; + +/** + * Enumerator for quality presets for 2d/3d surround view. + * Details of each preset are specified in the respective 2d/3d config structures. + */ +enum SvQuality : uint32_t { + HIGH = 0, + LOW, +}; + +/** Structure for surround view 2d configuration. */ +struct Sv2dConfig { + /** + * Desired output width in pixels. Must be in range (0, 4096]. + * Height is computed keeping the aspect ratio of the mapping info, + * Example: If width = 1080 px and mapping_width = 5000 mm, mapping_height = 10000 mm. + * then, height = width * (mapping_height / mapping_width) = 2160 px. + * Height is set to the floor value in case of (mapping_height / mapping_width) is not integer. + * Mapping width, height is fixed for a car and is based on camera parameters and their ground + * coverage. + */ + uint32_t width; + + /** + * Blending quality preset to use. + * HIGH: High quality blending (eg. multiband blending) that consumes more resources. + * LOW: Low quality blending (eg. alpha blending) that consumes less resources. + */ + SvQuality blending; +}; + +/** Structure for surround view 3d configuration. */ +struct Sv3dConfig { + /** Desired output width in pixels. Must be in range (0, 4096]. */ + uint32_t width; + + /** Desired output height in pixels. Must be in range (0, 4096]. */ + uint32_t height; + + /** + * Car model rendering details level. + * HIGH: Rendering includes shadows and reflections. Default option. + * LOW: Rendering with no shadows and reflections. + */ + SvQuality carDetails; +}; + +/** + * Enumerator for a list of overlay primitives. + * + * Given a list of vertices for an overlay, a primitive type defines which vertices are used to form + * the surfaces of the overlay object. + */ +enum OverlayPrimitive : uint32_t { + /** + * Consecutive vertices picked in order 3 at a time form a triangle. + * Eg: In a list of vertices (V1, V2, V3, V4, V5, V6) + * (V1, V2, V3) form a triangle and (V4, V5, V6) form a triangle. + */ + TRIANGLES = 0, + + /** + * Every 3 consecutive vertices form a triangle. + * Example in a list of vertices V1, V2, V3, V4, V5, V6 + * (V1, V2, V3), (V2, V3, V4), (V3, V4, V5) and (V4, V5, V6) form triangles. + */ + TRIANGLES_STRIP, +}; + +/** + * Structure identifying an overlay and describing the size and arrangement of its data in + * shared memory. + */ +struct OverlayMemoryDesc { + /** Identifier of the overlay. */ + uint16_t id; + + /** Number of vertices in the overlay. */ + uint32_t verticesCount; + + /** Primitive for the overlay. */ + OverlayPrimitive overlayPrimitive; +}; + +/** + * Structure containing the overlays data in shared memory. + */ +struct OverlaysData { + /** List of overlay memory descriptors, describing the data in the shared memory */ + vec overlaysMemoryDesc; + + /** + * Shared memory object containing a list of vertices for each overlay as described by + * overlaysMemoryDesc. + * + * Each vertex comprises of: + * | PositionX | PositionY | PositionZ | RGBA | + * | float | float | float | 4 * uint8_t | + * + * Each vertex is of 3 floats and 4 bytes = 16 bytes. + * + * Layout of vertices in shared memory is in order: + * + * Bytes: | 0-1 | 2-18 | 19-34 | 35-50 | 51-66 | 67-68 | 69-84 | 85-100 | 101-116 |... + * Data: | id1 | V1 | V2 | V3 | V4 | id2 | V1 | V2 | V3 |... + * | overlay1 | overlay 2 | + * + * The order of overlays must match the order as specified in the overlaysMemoryDesc. + * The number of vertices each overlay has must match the verticesCount in overlaysMemoryDesc. + * The id must match the id specificed in the OverlayMemoryDesc. This is used for verification. + * For each overlay the number of vertices must be 3 or greater. + * For TRIANGLES primitive the number of vertices must be a multiple of 3. + * The overlay vertices are grouped as per the overlayPrimitive specified in overlaysMemoryDesc, + * eg: If primitive is TRIANGLES, (V1, V2, V3) and (V4, V5, V6) form a triangle. + */ + memory overlaysMemory; +}; diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index f1db89dcba..de1ee8445c 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -55,6 +55,14 @@ default + + android.hardware.automotive.sv + 1.0 + + ISurroundView + default + + android.hardware.automotive.vehicle 2.0 From a4a81e3829553eb3fe7be4a77ba5419562e99a50 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Tue, 11 Feb 2020 00:32:33 -0800 Subject: [PATCH 0631/1022] [SV HIDL] Default implementation for Surround View Bug: 148618804 Test: atest -c VtsHalSurroundViewV1_0TargetTest (tested together with Change-id I1c6bfa77adb699ab80337497aac4582861315bcd) Change-Id: Ibc9e32d9cc6c93ca71f34bc54e3bdecdf2c4dba2 --- automotive/sv/1.0/default/Android.bp | 47 +++ .../sv/1.0/default/SurroundView2dSession.cpp | 240 ++++++++++++++ .../sv/1.0/default/SurroundView2dSession.h | 98 ++++++ .../sv/1.0/default/SurroundView3dSession.cpp | 310 ++++++++++++++++++ .../sv/1.0/default/SurroundView3dSession.h | 100 ++++++ .../sv/1.0/default/SurroundViewService.cpp | 91 +++++ .../sv/1.0/default/SurroundViewService.h | 64 ++++ ...roid.hardware.automotive.sv@1.0-service.rc | 5 + ...oid.hardware.automotive.sv@1.0-service.xml | 11 + automotive/sv/1.0/default/service.cpp | 57 ++++ 10 files changed, 1023 insertions(+) create mode 100644 automotive/sv/1.0/default/Android.bp create mode 100644 automotive/sv/1.0/default/SurroundView2dSession.cpp create mode 100644 automotive/sv/1.0/default/SurroundView2dSession.h create mode 100644 automotive/sv/1.0/default/SurroundView3dSession.cpp create mode 100644 automotive/sv/1.0/default/SurroundView3dSession.h create mode 100644 automotive/sv/1.0/default/SurroundViewService.cpp create mode 100644 automotive/sv/1.0/default/SurroundViewService.h create mode 100644 automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc create mode 100644 automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml create mode 100644 automotive/sv/1.0/default/service.cpp diff --git a/automotive/sv/1.0/default/Android.bp b/automotive/sv/1.0/default/Android.bp new file mode 100644 index 0000000000..8417949eba --- /dev/null +++ b/automotive/sv/1.0/default/Android.bp @@ -0,0 +1,47 @@ +// +// 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. +// + +cc_binary { + name: "android.hardware.automotive.sv@1.0-service", + vendor: true, + relative_install_path: "hw", + srcs: [ + "service.cpp", + "SurroundViewService.cpp", + "SurroundView2dSession.cpp", + "SurroundView3dSession.cpp", + ], + init_rc: ["android.hardware.automotive.sv@1.0-service.rc"], + vintf_fragments: ["android.hardware.automotive.sv@1.0-service.xml"], + shared_libs: [ + "android.hardware.automotive.sv@1.0", + "android.hidl.memory@1.0", + "libbase", + "libbinder", + "libcutils", + "libhardware", + "libhidlbase", + "liblog", + "libui", + "libutils", + "libhidlmemory", + ], + + cflags: [ + "-O0", + "-g", + ], +} diff --git a/automotive/sv/1.0/default/SurroundView2dSession.cpp b/automotive/sv/1.0/default/SurroundView2dSession.cpp new file mode 100644 index 0000000000..4f975987be --- /dev/null +++ b/automotive/sv/1.0/default/SurroundView2dSession.cpp @@ -0,0 +1,240 @@ +/* + * 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 "SurroundView2dSession.h" + +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace sv { +namespace V1_0 { +namespace implementation { + +SurroundView2dSession::SurroundView2dSession() : + mStreamState(STOPPED) { + mEvsCameraIds = {"0" , "1", "2", "3"}; + + mConfig.width = 640; + mConfig.blending = SvQuality::HIGH; + + framesRecord.frames.svBuffers.resize(1); + framesRecord.frames.svBuffers[0].viewId = 0; + framesRecord.frames.svBuffers[0].hardwareBuffer.nativeHandle = + new native_handle_t(); + framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] = + mConfig.width; + framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] = + mConfig.width * 3 / 4; +} + +// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession +Return SurroundView2dSession::startStream( + const sp& stream) { + ALOGD("SurroundView2dSession::startStream"); + std::lock_guard lock(mAccessLock); + + if (mStreamState != STOPPED) { + ALOGE("ignoring startVideoStream call" + "when a stream is already running."); + return SvResult::INTERNAL_ERROR; + } + + mStream = stream; + + ALOGD("Notify SvEvent::STREAM_STARTED"); + mStream->notify(SvEvent::STREAM_STARTED); + + // Start the frame generation thread + mStreamState = RUNNING; + mCaptureThread = std::thread([this](){ generateFrames(); }); + + return SvResult::OK; +} + +Return SurroundView2dSession::stopStream() { + ALOGD("SurroundView2dSession::stopStream"); + std::unique_lock lock(mAccessLock); + + if (mStreamState == RUNNING) { + // Tell the GenerateFrames loop we want it to stop + mStreamState = STOPPING; + + // Block outside the mutex until the "stop" flag has been acknowledged + // We won't send any more frames, but the client might still get some + // already in flight + ALOGD("Waiting for stream thread to end..."); + lock.unlock(); + mCaptureThread.join(); + lock.lock(); + + mStreamState = STOPPED; + mStream = nullptr; + ALOGD("Stream marked STOPPED."); + } + + return android::hardware::Void(); +} + +Return SurroundView2dSession::doneWithFrames( + const SvFramesDesc& svFramesDesc){ + ALOGD("SurroundView2dSession::doneWithFrames"); + std::unique_lock lock(mAccessLock); + + framesRecord.inUse = false; + + (void)svFramesDesc; + return android::hardware::Void(); +} + +// Methods from ISurroundView2dSession follow. +Return SurroundView2dSession::get2dMappingInfo( + get2dMappingInfo_cb _hidl_cb) { + ALOGD("SurroundView2dSession::get2dMappingInfo"); + std::unique_lock lock(mAccessLock); + + Sv2dMappingInfo info; + info.width = 8; // keeps ratio to 4:3 + info.height = 6; + info.center.isValid = true; + info.center.x = 0; + info.center.y = 0; + _hidl_cb(info); + return android::hardware::Void(); +} + +Return SurroundView2dSession::set2dConfig( + const Sv2dConfig& sv2dConfig) { + ALOGD("SurroundView2dSession::setConfig"); + std::unique_lock lock(mAccessLock); + + mConfig.width = sv2dConfig.width; + mConfig.blending = sv2dConfig.blending; + ALOGD("Notify SvEvent::CONFIG_UPDATED"); + mStream->notify(SvEvent::CONFIG_UPDATED); + + return SvResult::OK; +} + +Return SurroundView2dSession::get2dConfig(get2dConfig_cb _hidl_cb) { + ALOGD("SurroundView2dSession::getConfig"); + std::unique_lock lock(mAccessLock); + + _hidl_cb(mConfig); + return android::hardware::Void(); +} + +Return SurroundView2dSession::projectCameraPoints( + const hidl_vec& points2dCamera, + const hidl_string& cameraId, + projectCameraPoints_cb _hidl_cb) { + ALOGD("SurroundView2dSession::projectCameraPoints"); + std::unique_lock lock(mAccessLock); + + bool cameraIdFound = false; + for (auto evsCameraId : mEvsCameraIds) { + if (cameraId == evsCameraId) { + cameraIdFound = true; + ALOGI("Camera id found."); + break; + } + } + + if (!cameraIdFound) { + ALOGE("Camera id not found."); + _hidl_cb(hidl_vec()); + return android::hardware::Void(); + } + + hidl_vec outPoints; + outPoints.resize(points2dCamera.size()); + + int width = mConfig.width; + int height = mConfig.width * 3 / 4; + for (int i=0; i width-1 || + points2dCamera[i].x < 0 || points2dCamera[i].y > height-1) { + ALOGW("SurroundView2dSession::projectCameraPoints " + "gets invalid 2d camera points. Ignored"); + outPoints[i].isValid = false; + outPoints[i].x = 10000; + outPoints[i].y = 10000; + } else { + outPoints[i].isValid = true; + outPoints[i].x = 0; + outPoints[i].y = 0; + } + } + + _hidl_cb(outPoints); + return android::hardware::Void(); +} + +void SurroundView2dSession::generateFrames() { + ALOGD("SurroundView2dSession::generateFrames"); + + int sequenceId = 0; + + while(true) { + { + std::lock_guard lock(mAccessLock); + + if (mStreamState != RUNNING) { + // Break out of our main thread loop + break; + } + + framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] = + mConfig.width; + framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] = + mConfig.width * 3 / 4; + } + + usleep(100 * 1000); + + framesRecord.frames.timestampNs = elapsedRealtimeNano(); + framesRecord.frames.sequenceId = sequenceId++; + + { + std::lock_guard lock(mAccessLock); + + if (framesRecord.inUse) { + ALOGD("Notify SvEvent::FRAME_DROPPED"); + mStream->notify(SvEvent::FRAME_DROPPED); + } else { + framesRecord.inUse = true; + mStream->receiveFrames(framesRecord.frames); + } + } + } + + // If we've been asked to stop, send an event to signal the actual + // end of stream + ALOGD("Notify SvEvent::STREAM_STOPPED"); + mStream->notify(SvEvent::STREAM_STOPPED); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace sv +} // namespace automotive +} // namespace hardware +} // namespace android + diff --git a/automotive/sv/1.0/default/SurroundView2dSession.h b/automotive/sv/1.0/default/SurroundView2dSession.h new file mode 100644 index 0000000000..ee751e7d78 --- /dev/null +++ b/automotive/sv/1.0/default/SurroundView2dSession.h @@ -0,0 +1,98 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +using namespace ::android::hardware::automotive::sv::V1_0; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::sp; +using ::std::mutex; + +namespace android { +namespace hardware { +namespace automotive { +namespace sv { +namespace V1_0 { +namespace implementation { + +class SurroundView2dSession : public ISurroundView2dSession { +public: + SurroundView2dSession(); + + // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession. + Return startStream( + const sp& stream) override; + Return stopStream() override; + Return doneWithFrames(const SvFramesDesc& svFramesDesc) override; + + // Methods from ISurroundView2dSession follow. + Return get2dMappingInfo(get2dMappingInfo_cb _hidl_cb) override; + Return set2dConfig(const Sv2dConfig& sv2dConfig) override; + Return get2dConfig(get2dConfig_cb _hidl_cb) override; + Return projectCameraPoints( + const hidl_vec& points2dCamera, + const hidl_string& cameraId, + projectCameraPoints_cb _hidl_cb) override; + + // TODO(tanmayp): Make private and add set/get method. + // Stream subscribed for the session. + sp mStream; + +private: + void generateFrames(); + + enum StreamStateValues { + STOPPED, + RUNNING, + STOPPING, + DEAD, + }; + StreamStateValues mStreamState; + + Sv2dConfig mConfig; + + std::thread mCaptureThread; // The thread we'll use to synthesize frames + + struct FramesRecord { + SvFramesDesc frames; + bool inUse = false; + }; + + FramesRecord framesRecord; + + // Synchronization necessary to deconflict mCaptureThread from the main service thread + std::mutex mAccessLock; + + std::vector mEvsCameraIds; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace sv +} // namespace automotive +} // namespace hardware +} // namespace android + diff --git a/automotive/sv/1.0/default/SurroundView3dSession.cpp b/automotive/sv/1.0/default/SurroundView3dSession.cpp new file mode 100644 index 0000000000..da36f329aa --- /dev/null +++ b/automotive/sv/1.0/default/SurroundView3dSession.cpp @@ -0,0 +1,310 @@ +/* + * 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 "SurroundView3dSession.h" + +#include + +#include +#include + +#include +#include + +using ::android::hidl::memory::V1_0::IMemory; +using ::android::hardware::hidl_memory; + +namespace android { +namespace hardware { +namespace automotive { +namespace sv { +namespace V1_0 { +namespace implementation { + +SurroundView3dSession::SurroundView3dSession() : + mStreamState(STOPPED){ + + mEvsCameraIds = {"0" , "1", "2", "3"}; + + mConfig.width = 640; + mConfig.height = 480; + mConfig.carDetails = SvQuality::HIGH; + + framesRecord.frames.svBuffers.resize(1); + framesRecord.frames.svBuffers[0].viewId = 0; + framesRecord.frames.svBuffers[0].hardwareBuffer.nativeHandle = new native_handle_t(); + framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] = mConfig.width; + framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] = mConfig.height; +} + +// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession. +Return SurroundView3dSession::startStream( + const sp& stream) { + ALOGD("SurroundView3dSession::startStream"); + std::lock_guard lock(mAccessLock); + + if (mStreamState != STOPPED) { + ALOGE("ignoring startVideoStream call when a stream is already running."); + return SvResult::INTERNAL_ERROR; + } + + if (mViews.empty()) { + ALOGE("No views have been set for current Surround View 3d Session. " + "Please call setViews before starting the stream."); + return SvResult::VIEW_NOT_SET; + } + + mStream = stream; + + ALOGD("Notify SvEvent::STREAM_STARTED"); + mStream->notify(SvEvent::STREAM_STARTED); + + // Start the frame generation thread + mStreamState = RUNNING; + mCaptureThread = std::thread([this](){ generateFrames(); }); + + return SvResult::OK; +} + +Return SurroundView3dSession::stopStream() { + ALOGD("SurroundView3dSession::stopStream"); + std::unique_lock lock(mAccessLock); + + if (mStreamState == RUNNING) { + // Tell the GenerateFrames loop we want it to stop + mStreamState = STOPPING; + + // Block outside the mutex until the "stop" flag has been acknowledged + // We won't send any more frames, but the client might still get some already in flight + ALOGD("Waiting for stream thread to end..."); + lock.unlock(); + mCaptureThread.join(); + lock.lock(); + + mStreamState = STOPPED; + mStream = nullptr; + ALOGD("Stream marked STOPPED."); + } + + return android::hardware::Void(); +} + +Return SurroundView3dSession::doneWithFrames( + const SvFramesDesc& svFramesDesc){ + ALOGD("SurroundView3dSession::doneWithFrames"); + std::unique_lock lock(mAccessLock); + + framesRecord.inUse = false; + + (void)svFramesDesc; + return android::hardware::Void(); +} + +// Methods from ISurroundView3dSession follow. +Return SurroundView3dSession::setViews(const hidl_vec& views) { + ALOGD("SurroundView3dSession::stopStream"); + std::unique_lock lock(mAccessLock); + + mViews.resize(views.size()); + for (int i=0; i SurroundView3dSession::set3dConfig(const Sv3dConfig& sv3dConfig) { + ALOGD("SurroundView3dSession::set3dConfig"); + std::unique_lock lock(mAccessLock); + + mConfig.width = sv3dConfig.width; + mConfig.height = sv3dConfig.height; + mConfig.carDetails = sv3dConfig.carDetails; + ALOGD("Notify SvEvent::CONFIG_UPDATED"); + mStream->notify(SvEvent::CONFIG_UPDATED); + + return SvResult::OK; +} + +Return SurroundView3dSession::get3dConfig(get3dConfig_cb _hidl_cb) { + ALOGD("SurroundView3dSession::get3dConfig"); + std::unique_lock lock(mAccessLock); + + _hidl_cb(mConfig); + return android::hardware::Void(); +} + +bool VerifyOverlayData(const OverlaysData& overlaysData) { + // Check size of shared memory matches overlaysMemoryDesc. + const int kVertexSize = 16; + const int kIdSize = 2; + int memDescSize = 0; + for (auto overlayMemDesc : overlaysData.overlaysMemoryDesc) { + memDescSize += kIdSize + kVertexSize * overlayMemDesc.verticesCount; + } + if (memDescSize != overlaysData.overlaysMemory.size()) { + ALOGE("shared memory and overlaysMemoryDesc size mismatch."); + return false; + } + + // Map memory. + sp pSharedMemory = mapMemory(overlaysData.overlaysMemory); + if(pSharedMemory.get() == nullptr) { + ALOGE("mapMemory failed."); + return false; + } + + // Get Data pointer. + uint8_t* pData = (uint8_t*)((void*)pSharedMemory->getPointer()); + if (pData == nullptr) { + ALOGE("Shared memory getPointer() failed."); + return false; + } + + int idOffset = 0; + std::set overlayIdSet; + for (auto overlayMemDesc : overlaysData.overlaysMemoryDesc) { + + if (overlayIdSet.find(overlayMemDesc.id) != overlayIdSet.end()) { + ALOGE("Duplicate id within memory descriptor."); + return false; + } + overlayIdSet.insert(overlayMemDesc.id); + + if(overlayMemDesc.verticesCount < 3) { + ALOGE("Less than 3 vertices."); + return false; + } + + if (overlayMemDesc.overlayPrimitive == OverlayPrimitive::TRIANGLES && + overlayMemDesc.verticesCount % 3 != 0) { + ALOGE("Triangles primitive does not have vertices multiple of 3."); + return false; + } + + uint16_t overlayId = *((uint16_t*)(pData + idOffset)); + + if (overlayId != overlayMemDesc.id) { + ALOGE("Overlay id mismatch %d , %d", overlayId, overlayMemDesc.id); + return false; + } + + idOffset += kIdSize + (kVertexSize * overlayMemDesc.verticesCount); + } + + return true; +} + +Return SurroundView3dSession::updateOverlays( + const OverlaysData& overlaysData) { + + if(!VerifyOverlayData(overlaysData)) { + ALOGE("VerifyOverlayData failed."); + return SvResult::INVALID_ARG; + } + + return SvResult::OK; +} + +Return SurroundView3dSession::projectCameraPointsTo3dSurface( + const hidl_vec& cameraPoints, + const hidl_string& cameraId, + projectCameraPointsTo3dSurface_cb _hidl_cb) { + + std::vector points3d; + bool cameraIdFound = false; + for (auto evsCameraId : mEvsCameraIds) { + if (cameraId == evsCameraId) { + cameraIdFound = true; + ALOGI("Camera id found."); + break; + } + } + + if (!cameraIdFound) { + ALOGE("Camera id not found."); + _hidl_cb(points3d); + return android::hardware::Void(); + } + + for (const auto cameraPoint : cameraPoints) { + Point3dFloat point3d; + point3d.isValid = true; + + if (cameraPoint.x < 0 || cameraPoint.x >= mConfig.width-1 || + cameraPoint.y < 0 || cameraPoint.y >= mConfig.height-1) { + ALOGE("Camera point out of bounds."); + point3d.isValid = false; + } + points3d.push_back(point3d); + } + _hidl_cb(points3d); + return android::hardware::Void(); +} + +void SurroundView3dSession::generateFrames() { + ALOGD("SurroundView3dSession::generateFrames"); + + int sequenceId = 0; + + while(true) { + { + std::lock_guard lock(mAccessLock); + + if (mStreamState != RUNNING) { + // Break out of our main thread loop + break; + } + } + + usleep(100 * 1000); + + framesRecord.frames.timestampNs = elapsedRealtimeNano(); + framesRecord.frames.sequenceId = sequenceId++; + + framesRecord.frames.svBuffers.resize(mViews.size()); + for (int i=0; i lock(mAccessLock); + + if (framesRecord.inUse) { + ALOGD("Notify SvEvent::FRAME_DROPPED"); + mStream->notify(SvEvent::FRAME_DROPPED); + } else { + framesRecord.inUse = true; + mStream->receiveFrames(framesRecord.frames); + } + } + } + + // If we've been asked to stop, send an event to signal the actual end of stream + ALOGD("Notify SvEvent::STREAM_STOPPED"); + mStream->notify(SvEvent::STREAM_STOPPED); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace sv +} // namespace automotive +} // namespace hardware +} // namespace android + diff --git a/automotive/sv/1.0/default/SurroundView3dSession.h b/automotive/sv/1.0/default/SurroundView3dSession.h new file mode 100644 index 0000000000..5c638dbb9a --- /dev/null +++ b/automotive/sv/1.0/default/SurroundView3dSession.h @@ -0,0 +1,100 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +using namespace ::android::hardware::automotive::sv::V1_0; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::sp; +using ::std::mutex; + +namespace android { +namespace hardware { +namespace automotive { +namespace sv { +namespace V1_0 { +namespace implementation { + +class SurroundView3dSession : public ISurroundView3dSession { +public: + SurroundView3dSession(); + + // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession. + Return startStream( + const sp& stream) override; + Return stopStream() override; + Return doneWithFrames(const SvFramesDesc& svFramesDesc) override; + + // Methods from ISurroundView3dSession follow. + Return setViews(const hidl_vec& views) override; + Return set3dConfig(const Sv3dConfig& sv3dConfig) override; + Return get3dConfig(get3dConfig_cb _hidl_cb) override; + Return updateOverlays(const OverlaysData& overlaysData); + Return projectCameraPointsTo3dSurface( + const hidl_vec& cameraPoints, + const hidl_string& cameraId, + projectCameraPointsTo3dSurface_cb _hidl_cb); + + // Stream subscribed for the session. + // TODO(tanmayp): Make private and add set/get method. + sp mStream; + +private: + void generateFrames(); + + enum StreamStateValues { + STOPPED, + RUNNING, + STOPPING, + DEAD, + }; + StreamStateValues mStreamState; + + std::thread mCaptureThread; // The thread we'll use to synthesize frames + + struct FramesRecord { + SvFramesDesc frames; + bool inUse = false; + }; + + FramesRecord framesRecord; + + // Synchronization necessary to deconflict mCaptureThread from the main service thread + std::mutex mAccessLock; + + std::vector mViews; + + Sv3dConfig mConfig; + + std::vector mEvsCameraIds; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace sv +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/sv/1.0/default/SurroundViewService.cpp b/automotive/sv/1.0/default/SurroundViewService.cpp new file mode 100644 index 0000000000..fe89dd5ee4 --- /dev/null +++ b/automotive/sv/1.0/default/SurroundViewService.cpp @@ -0,0 +1,91 @@ +/* + * 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 "SurroundViewService.h" + +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace sv { +namespace V1_0 { +namespace implementation { + +const std::string kCameraIds[] = {"0", "1", "2", "3"}; + +Return SurroundViewService::getCameraIds(getCameraIds_cb _hidl_cb) { + std::vector cameraIds = {kCameraIds[0], kCameraIds[1], + kCameraIds[2], kCameraIds[3]}; + _hidl_cb(cameraIds); + return android::hardware::Void(); +} + +Return SurroundViewService::start2dSession(start2dSession_cb _hidl_cb) { + ALOGD("SurroundViewService::start2dSession"); + if (mSurroundView2dSession != nullptr) { + ALOGW("Only one 2d session is supported at the same time"); + _hidl_cb(nullptr, SvResult::INTERNAL_ERROR); + } else { + mSurroundView2dSession = new SurroundView2dSession(); + _hidl_cb(mSurroundView2dSession, SvResult::OK); + } + return android::hardware::Void(); +} + +Return SurroundViewService::stop2dSession( + const sp& sv2dSession) { + ALOGD("SurroundViewService::stop2dSession"); + if (sv2dSession != nullptr && sv2dSession == mSurroundView2dSession) { + mSurroundView2dSession = nullptr; + return SvResult::OK; + } else { + ALOGE("Invalid arg for stop2dSession"); + return SvResult::INVALID_ARG; + } +} + +Return SurroundViewService::start3dSession(start3dSession_cb _hidl_cb) { + ALOGD("SurroundViewService::start3dSession"); + if (mSurroundView3dSession != nullptr) { + ALOGW("Only one 3d session is supported at the same time"); + _hidl_cb(nullptr, SvResult::INTERNAL_ERROR); + } else { + mSurroundView3dSession = new SurroundView3dSession(); + _hidl_cb(mSurroundView3dSession, SvResult::OK); + } + return android::hardware::Void(); +} + +Return SurroundViewService::stop3dSession( + const sp& sv3dSession) { + ALOGD("SurroundViewService::stop3dSession"); + if (sv3dSession != nullptr && sv3dSession == mSurroundView3dSession) { + mSurroundView3dSession = nullptr; + return SvResult::OK; + } else { + ALOGE("Invalid arg for stop3dSession"); + return SvResult::INVALID_ARG; + } +} + +} // namespace implementation +} // namespace V1_0 +} // namespace sv +} // namespace automotive +} // namespace hardware +} // namespace android + diff --git a/automotive/sv/1.0/default/SurroundViewService.h b/automotive/sv/1.0/default/SurroundViewService.h new file mode 100644 index 0000000000..9e0e151308 --- /dev/null +++ b/automotive/sv/1.0/default/SurroundViewService.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#pragma once + +#include "SurroundView2dSession.h" +#include "SurroundView3dSession.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace ::android::hardware::automotive::sv::V1_0; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +namespace android { +namespace hardware { +namespace automotive { +namespace sv { +namespace V1_0 { +namespace implementation { + +class SurroundViewService : public ISurroundViewService { +public: + // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewService follow. + Return getCameraIds(getCameraIds_cb _hidl_cb) override; + Return start2dSession(start2dSession_cb _hidl_cb) override; + Return stop2dSession( + const sp& sv2dSession) override; + + Return start3dSession(start3dSession_cb _hidl_cb) override; + Return stop3dSession( + const sp& sv3dSession) override; + +private: + sp mSurroundView2dSession; + sp mSurroundView3dSession; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace sv +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc new file mode 100644 index 0000000000..e822017cf9 --- /dev/null +++ b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc @@ -0,0 +1,5 @@ +service sv_service /vendor/bin/hw/android.hardware.automotive.sv@1.0-service + class hal + user automotive_evs + group automotive_evs + disabled diff --git a/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml new file mode 100644 index 0000000000..ba8e5ac93f --- /dev/null +++ b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml @@ -0,0 +1,11 @@ + + + android.hardware.automotive.sv + hwbinder + 1.0 + + ISurroundViewService + default + + + diff --git a/automotive/sv/1.0/default/service.cpp b/automotive/sv/1.0/default/service.cpp new file mode 100644 index 0000000000..fae7425176 --- /dev/null +++ b/automotive/sv/1.0/default/service.cpp @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#define LOG_TAG "android.hardware.automotive.sv@1.0-service" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "SurroundViewService.h" + +// libhidl: +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; + +// implementation: +using android::hardware::automotive::sv::V1_0::implementation::SurroundViewService; + +int main() { + ALOGI("ISurroundViewService default implementation is starting"); + android::sp service = new SurroundViewService(); + + configureRpcThreadpool(1, true /* callerWillJoin */); + + // Register our service -- if somebody is already registered by our name, + // they will be killed (their thread pool will throw an exception). + android::status_t status = service->registerAsService(); + + LOG_ALWAYS_FATAL_IF(status != android::OK, + "Could not register default Surround View Service (%d)", + status); + + joinRpcThreadpool(); + + // In normal operation, we don't expect the thread pool to exit + ALOGE("Surround View Service is shutting down"); + return 1; +} From 4f5188ae506fae4f8afbcf3ecc65f9c92f3da940 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Wed, 12 Feb 2020 13:23:28 -0800 Subject: [PATCH 0632/1022] [SV HIDL] VTS Test for Surround View Bug: 148618804 Test: atest -c VtsHalSurroundViewV1_0TargetTest Change-Id: I1c6bfa77adb699ab80337497aac4582861315bcd --- automotive/sv/1.0/vts/functional/Android.bp | 41 + .../functional/SurroundViewStreamHandler.cpp | 113 ++ .../functional/SurroundViewStreamHandler.h | 57 + .../VtsHalSurroundViewV1_0TargetTest.cpp | 1137 +++++++++++++++++ 4 files changed, 1348 insertions(+) create mode 100644 automotive/sv/1.0/vts/functional/Android.bp create mode 100644 automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.cpp create mode 100644 automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.h create mode 100644 automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp diff --git a/automotive/sv/1.0/vts/functional/Android.bp b/automotive/sv/1.0/vts/functional/Android.bp new file mode 100644 index 0000000000..0e5d3df9a7 --- /dev/null +++ b/automotive/sv/1.0/vts/functional/Android.bp @@ -0,0 +1,41 @@ +// +// 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. +// + +cc_test { + name: "VtsHalSurroundViewV1_0TargetTest", + srcs: [ + "VtsHalSurroundViewV1_0TargetTest.cpp", + "SurroundViewStreamHandler.cpp", + ], + defaults: ["VtsHalTargetTestDefaults"], + static_libs: [ + "libnativewindow", + "android.hardware.automotive.sv@1.0", + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + ], + shared_libs: [ + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "libhidlmemory", + ], + test_suites: ["general-tests", "vts-core"], + cflags: [ + "-O0", + "-g", + ], +} diff --git a/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.cpp b/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.cpp new file mode 100644 index 0000000000..cb45caab59 --- /dev/null +++ b/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.cpp @@ -0,0 +1,113 @@ +/* + * 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 "SurroundViewStreamHandler.h" + +#include + +using std::lock_guard; + +SurroundViewServiceHandler::SurroundViewServiceHandler(sp pSession) : + mSession(pSession), + mReceiveFramesCount(0), + mDoNotReturnFrames(false) { + // Nothing but member initialization +} + +Return SurroundViewServiceHandler::notify(SvEvent svEvent) { + ALOGD("SurroundViewServiceHandler::notify %d", svEvent); + + lock_guard lock(mLock); + switch (svEvent) { + case SvEvent::STREAM_STARTED: + case SvEvent::CONFIG_UPDATED: + case SvEvent::STREAM_STOPPED: + case SvEvent::FRAME_DROPPED: + case SvEvent::TIMEOUT: + mReceivedEvents.emplace_back(svEvent); + break; + default: + ALOGI("[SurroundViewLog] Received other event"); + } + + return android::hardware::Void(); +} + +Return SurroundViewServiceHandler::receiveFrames(const SvFramesDesc& svFramesDesc) { + ALOGD("SurroundViewServiceHandler::receiveFrames"); + + lock_guard lock(mLock); + unsigned long timestampNs = svFramesDesc.timestampNs; + unsigned sequenceId = svFramesDesc.sequenceId; + ALOGD("receiveFrames count: %d", mReceiveFramesCount); + ALOGD("timestampNs: %lu, sequenceId: %u", timestampNs, sequenceId); + if (mReceiveFramesCount != 0 + && (mLastReceivedFrames.timestampNs >= svFramesDesc.timestampNs + || mLastReceivedFrames.sequenceId >= svFramesDesc.sequenceId)) { + mAllFramesValid = false; + ALOGD("The incoming frames are with invalid timestamp or sequenceId!"); + } + + for (int i=0; idoneWithFrames(svFramesDesc); + } + + return android::hardware::Void(); +} + +bool SurroundViewServiceHandler::checkEventReceived(SvEvent svEvent) { + ALOGD("SurroundViewServiceHandler::checkEventReceived"); + int size = mReceivedEvents.size(); // work around + ALOGD("Received event number: %d", size); + auto iter = find(mReceivedEvents.begin(), mReceivedEvents.end(), svEvent); + return iter != mReceivedEvents.end(); +} + +SvFramesDesc SurroundViewServiceHandler::getLastReceivedFrames() { + return mLastReceivedFrames; +} + +int SurroundViewServiceHandler::getReceiveFramesCount() { + return mReceiveFramesCount; +} + +bool SurroundViewServiceHandler::areAllFramesValid() { + return mAllFramesValid; +} + +void SurroundViewServiceHandler::setDoNotReturnFrames(bool flag) { + mDoNotReturnFrames = flag; +} diff --git a/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.h b/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.h new file mode 100644 index 0000000000..7d3f61d47c --- /dev/null +++ b/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.h @@ -0,0 +1,57 @@ +/* + * 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 SURROUND_VIEW_STREAM_HANDLER_H +#define SURROUND_VIEW_STREAM_HANDLER_H + +#include +#include +#include + +#include +#include + +using std::vector; +using std::mutex; +using android::hardware::Return; +using android::sp; +using namespace ::android::hardware::automotive::sv::V1_0; + +class SurroundViewServiceHandler : public ISurroundViewStream { +public: + SurroundViewServiceHandler(sp session); + + Return notify(SvEvent svEvent) override; + Return receiveFrames(const SvFramesDesc& svFramesDesc) override; + + bool checkEventReceived(SvEvent svEvent); + SvFramesDesc getLastReceivedFrames(); + int getReceiveFramesCount(); + bool areAllFramesValid(); + void setDoNotReturnFrames(bool flag); + +private: + mutex mLock; + + vector mReceivedEvents; + sp mSession; + SvFramesDesc mLastReceivedFrames; // only use timestampNs and sequenceId + int mReceiveFramesCount; // TODO(haoxiangl): figure out a better name + bool mAllFramesValid = true; + bool mDoNotReturnFrames; +}; + +#endif //SURROUND_VIEW_STREAM_HANDLER_H diff --git a/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp b/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp new file mode 100644 index 0000000000..b1b9d16bc2 --- /dev/null +++ b/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp @@ -0,0 +1,1137 @@ +// +// 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. +// + +#define LOG_TAG "VtsHalSurroundViewTest" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "SurroundViewStreamHandler.h" + +using namespace ::android::hardware::automotive::sv::V1_0; +using ::android::sp; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::hidl::allocator::V1_0::IAllocator; +using ::android::hidl::memory::V1_0::IMemory; +using ::android::hardware::hidl_memory; + +const int kVertexByteSize = (3 * sizeof(float)) + 4; +const int kIdByteSize = 2; + +// The main test class for Surround View Service +class SurroundViewHidlTest : public ::testing::TestWithParam { +public: + virtual void SetUp() override { + mSurroundViewService = ISurroundViewService::getService(GetParam()); + ASSERT_NE(mSurroundViewService.get(), nullptr); + } + + virtual void TearDown() override {} + + sp mSurroundViewService; // Every test needs access to the service +}; + +TEST_P(SurroundViewHidlTest, startAndStop2dSession) { + ALOGD("SurroundViewHidlTest::startAndStop2dSession"); + sp surroundView2dSession; + mSurroundViewService->start2dSession( + [&surroundView2dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView2dSession = session; + }); + + SvResult result = mSurroundViewService->stop2dSession(surroundView2dSession); + ASSERT_EQ(result, SvResult::OK); +} + +TEST_P(SurroundViewHidlTest, stopInvalid2dSession) { + ALOGD("SurroundViewHidlTest::stopInvalid2dSession"); + sp surroundView2dSession; + SvResult result = mSurroundViewService->stop2dSession(surroundView2dSession); + ASSERT_NE(result, SvResult::OK); +} + +TEST_P(SurroundViewHidlTest, startAndStop2dStream) { + ALOGD("SurroundViewHidlTest::startAndStop2dStream"); + sp surroundView2dSession; + mSurroundViewService->start2dSession( + [&surroundView2dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView2dSession = session; + }); + + sp handler = + new SurroundViewServiceHandler(surroundView2dSession); + + SvResult result = surroundView2dSession->startStream(handler); + EXPECT_EQ(result, SvResult::OK); + + sleep(5); + + EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STARTED)); + EXPECT_GT(handler->getReceiveFramesCount(), 0); + + surroundView2dSession->stopStream(); + + sleep(1); + EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STOPPED)); + + result = mSurroundViewService->stop2dSession(surroundView2dSession); + EXPECT_EQ(result, SvResult::OK); +} + +TEST_P(SurroundViewHidlTest, start2dStreamWithoutReturningFrames) { + ALOGD("SurroundViewHidlTest::start2dStreamWithoutReturningFrames"); + sp surroundView2dSession; + mSurroundViewService->start2dSession( + [&surroundView2dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView2dSession = session; + }); + + sp handler = + new SurroundViewServiceHandler(surroundView2dSession); + handler->setDoNotReturnFrames(true); + + SvResult result = surroundView2dSession->startStream(handler); + EXPECT_EQ(result, SvResult::OK); + + sleep(5); + + EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STARTED)); + EXPECT_TRUE(handler->checkEventReceived(SvEvent::FRAME_DROPPED)); + EXPECT_GT(handler->getReceiveFramesCount(), 0); + + surroundView2dSession->stopStream(); + + sleep(1); + EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STOPPED)); + + result = mSurroundViewService->stop2dSession(surroundView2dSession); + EXPECT_EQ(result, SvResult::OK); +} + +TEST_P(SurroundViewHidlTest, duplicateStart2dStream) { + ALOGD("SurroundViewHidlTest, duplicateStart2dStream"); + sp surroundView2dSession; + mSurroundViewService->start2dSession( + [&surroundView2dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView2dSession = session; + }); + + sp handler = + new SurroundViewServiceHandler(surroundView2dSession); + + SvResult result = surroundView2dSession->startStream(handler); + EXPECT_EQ(result, SvResult::OK); + + result = surroundView2dSession->startStream(handler); + EXPECT_NE(result, SvResult::OK); + + surroundView2dSession->stopStream(); + mSurroundViewService->stop2dSession(surroundView2dSession); +} + +TEST_P(SurroundViewHidlTest, stopInvalid2dStream) { + ALOGD("SurroundViewHidlTest, stopInvalid2dStream"); + sp surroundView2dSession; + mSurroundViewService->start2dSession( + [&surroundView2dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView2dSession = session; + }); + + sp handler = + new SurroundViewServiceHandler(surroundView2dSession); + + surroundView2dSession->stopStream(); + mSurroundViewService->stop2dSession(surroundView2dSession); +} + +TEST_P(SurroundViewHidlTest, validate2dSvFramesDesc) { + ALOGD("SurroundViewHidlTest, validate2dSvFramesDesc"); + sp surroundView2dSession; + mSurroundViewService->start2dSession( + [&surroundView2dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView2dSession = session; + }); + + sp handler = + new SurroundViewServiceHandler(surroundView2dSession); + + SvResult result = surroundView2dSession->startStream(handler); + EXPECT_EQ(result, SvResult::OK); + + sleep(5); + + // Validate timestampNs and sequenceId + EXPECT_GT(handler->getReceiveFramesCount(), 0); + EXPECT_TRUE(handler->areAllFramesValid()); + + // Validate 2d SvFramesDesc. Do not compare nativeHandle since it is not + // stored and already verified on the fly. + SvFramesDesc frames = handler->getLastReceivedFrames(); + EXPECT_EQ(frames.svBuffers.size(), 1); + + SvBuffer svBuffer2d = frames.svBuffers[0]; + EXPECT_EQ(svBuffer2d.viewId, 0); + + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&svBuffer2d.hardwareBuffer.description); + float mapWidth, mapHeight; + surroundView2dSession->get2dMappingInfo([&mapWidth, &mapHeight] (Sv2dMappingInfo info) { + mapWidth = info.width; + mapHeight = info.height; + }); + EXPECT_EQ(pDesc->height, floor(pDesc->width * (mapHeight / mapWidth))); + + // Clean up + surroundView2dSession->stopStream(); + result = mSurroundViewService->stop2dSession(surroundView2dSession); +} + +TEST_P(SurroundViewHidlTest, get2dMappingInfo) { + ALOGD("SurroundViewHidlTest, get2dMappingInfo"); + sp surroundView2dSession; + mSurroundViewService->start2dSession( + [&surroundView2dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView2dSession = session; + }); + + surroundView2dSession->get2dMappingInfo([] (Sv2dMappingInfo info) { + EXPECT_GT(info.width, 0); + EXPECT_GT(info.height, 0); + }); + + mSurroundViewService->stop2dSession(surroundView2dSession); +} + +TEST_P(SurroundViewHidlTest, set2dConfigResolution) { + ALOGD("SurroundViewHidlTest, set2dConfigResolution"); + sp surroundView2dSession; + mSurroundViewService->start2dSession( + [&surroundView2dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView2dSession = session; + }); + + sp handler = + new SurroundViewServiceHandler(surroundView2dSession); + + SvResult result = surroundView2dSession->startStream(handler); + EXPECT_EQ(result, SvResult::OK); + + sleep(1); + + // Change config + Sv2dConfig config; + config.width = 1920; + config.blending = SvQuality::HIGH; + surroundView2dSession->set2dConfig(config); + + sleep(1); + + EXPECT_TRUE(handler->checkEventReceived(SvEvent::CONFIG_UPDATED)); + + // Check width has been changed but not the ratio + SvFramesDesc frames = handler->getLastReceivedFrames(); + EXPECT_EQ(frames.svBuffers.size(), 1); + SvBuffer svBuffer2d = frames.svBuffers[0]; + EXPECT_EQ(svBuffer2d.viewId, 0); + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&svBuffer2d.hardwareBuffer.description); + EXPECT_EQ(pDesc->width, config.width); + + float mapWidth, mapHeight; + surroundView2dSession->get2dMappingInfo([&mapWidth, &mapHeight] (Sv2dMappingInfo info) { + mapWidth = info.width; + mapHeight = info.height; + }); + EXPECT_EQ(pDesc->height, floor (pDesc->width * (mapHeight / mapWidth))); + + // Clean up + surroundView2dSession->stopStream(); + mSurroundViewService->stop2dSession(surroundView2dSession); +} + +TEST_P(SurroundViewHidlTest, set2dConfigBlending) { + ALOGD("SurroundViewHidlTest, set2dConfigBlending"); + sp surroundView2dSession; + mSurroundViewService->start2dSession( + [&surroundView2dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView2dSession = session; + }); + + sp handler = + new SurroundViewServiceHandler(surroundView2dSession); + + SvResult result = surroundView2dSession->startStream(handler); + EXPECT_EQ(result, SvResult::OK); + + sleep(1); + + // Get the width before config changed + int oldWidth; + SvFramesDesc frames = handler->getLastReceivedFrames(); + EXPECT_EQ(frames.svBuffers.size(), 1); + SvBuffer svBuffer2d = frames.svBuffers[0]; + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&svBuffer2d.hardwareBuffer.description); + oldWidth = pDesc->width; + + // Change config + Sv2dConfig config; + config.width = oldWidth; + config.blending = SvQuality::LOW; + surroundView2dSession->set2dConfig(config); + + sleep(1); + + EXPECT_TRUE(handler->checkEventReceived(SvEvent::CONFIG_UPDATED)); + + Sv2dConfig retConfig; + surroundView2dSession->get2dConfig([&retConfig] (Sv2dConfig config) { + retConfig.width = config.width; + retConfig.blending = config.blending; + }); + + // Check config blending has been changed but not the width + EXPECT_EQ(retConfig.blending, config.blending); + EXPECT_EQ(retConfig.width, oldWidth); + + // Clean up + surroundView2dSession->stopStream(); + mSurroundViewService->stop2dSession(surroundView2dSession); +} + +TEST_P(SurroundViewHidlTest, projectCameraPointsWithValidCameraId) { + ALOGD("SurroundViewHidlTest, projectCameraPointsWithValidCameraId"); + sp surroundView2dSession; + mSurroundViewService->start2dSession( + [&surroundView2dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView2dSession = session; + }); + + hidl_vec cameraIds; + mSurroundViewService->getCameraIds([&cameraIds]( + const hidl_vec& camIds) { + cameraIds = camIds; + }); + + sp handler = + new SurroundViewServiceHandler(surroundView2dSession); + + SvResult result = surroundView2dSession->startStream(handler); + EXPECT_EQ(result, SvResult::OK); + + sleep(1); + + // Get the width and height of the frame + int width, height; + SvFramesDesc frames = handler->getLastReceivedFrames(); + EXPECT_EQ(frames.svBuffers.size(), 1); + SvBuffer svBuffer2d = frames.svBuffers[0]; + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&svBuffer2d.hardwareBuffer.description); + width = pDesc->width; + height = pDesc->height; + + float mapWidth, mapHeight, mapCenter[2]; + surroundView2dSession->get2dMappingInfo( + [&mapWidth, &mapHeight, &mapCenter] (Sv2dMappingInfo info) { + mapWidth = info.width; + mapHeight = info.height; + mapCenter[0] = info.center.x; + mapCenter[1] = info.center.y; + }); + + // Set one valid point and one invalid point + hidl_vec points2dCamera; + points2dCamera.resize(2); + points2dCamera[0].x = 0; + points2dCamera[0].y = 0; + points2dCamera[1].x = width * 2; + points2dCamera[1].y = height * 2; + + surroundView2dSession->projectCameraPoints( + points2dCamera, + cameraIds[0], + [&mapWidth, &mapHeight, &mapCenter] ( + const hidl_vec& outPoints) { + // Make sure point[0] is valid. + EXPECT_TRUE(outPoints[0].isValid); + EXPECT_GE(outPoints[0].x, mapCenter[0] - mapWidth); + EXPECT_LE(outPoints[0].x, mapCenter[0] + mapWidth); + EXPECT_GE(outPoints[0].y, mapCenter[1] - mapHeight); + EXPECT_LE(outPoints[0].y, mapCenter[1] + mapHeight); + + // Make sure point[1] is invalid. + EXPECT_FALSE(outPoints[1].isValid); + }); + + // Clean up + surroundView2dSession->stopStream(); + mSurroundViewService->stop2dSession(surroundView2dSession); +} + +TEST_P(SurroundViewHidlTest, projectCameraPointsWithInvalidCameraId) { + ALOGD("SurroundViewHidlTest, projectCameraPointsWithInvalidCameraId"); + sp surroundView2dSession; + mSurroundViewService->start2dSession( + [&surroundView2dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView2dSession = session; + }); + + hidl_vec cameraIds; + mSurroundViewService->getCameraIds([&cameraIds]( + const hidl_vec& camIds) { + cameraIds = camIds; + }); + + hidl_string invalidCameraId = "INVALID_CAMERA_ID"; + + // In case one of the camera id happens to be identical to + // the invalid camera id. + for (auto cameraId : cameraIds) { + ASSERT_NE(cameraId, invalidCameraId); + } + + // Set one valid point + hidl_vec points2dCamera; + points2dCamera.resize(1); + points2dCamera[0].x = 0; + points2dCamera[0].y = 0; + + surroundView2dSession->projectCameraPoints( + points2dCamera, + invalidCameraId, + [] (const hidl_vec& outPoints) { + // No points are return due to invalid camera id + EXPECT_EQ(outPoints.size(), 0); + }); + + // Clean up + surroundView2dSession->stopStream(); + mSurroundViewService->stop2dSession(surroundView2dSession); +} + +TEST_P(SurroundViewHidlTest, startAndStop3dSession) { + ALOGD("SurroundViewHidlTest, startAndStop3dSession"); + sp surroundView3dSession; + mSurroundViewService->start3dSession( + [&surroundView3dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView3dSession = session; + }); + + SvResult result = mSurroundViewService->stop3dSession(surroundView3dSession); + EXPECT_EQ(result, SvResult::OK); +} + +TEST_P(SurroundViewHidlTest, stopInvalid3dSession) { + ALOGD("SurroundViewHidlTest, stopInvalid3dSession"); + sp surroundView3dSession; + SvResult result = mSurroundViewService->stop3dSession(surroundView3dSession); + EXPECT_NE(result, SvResult::OK); +} + +TEST_P(SurroundViewHidlTest, startAndStop3dStream) { + ALOGD("SurroundViewHidlTest::startAndStop3dStream"); + sp surroundView3dSession; + mSurroundViewService->start3dSession( + [&surroundView3dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView3dSession = session; + }); + + std::vector views(1); + SvResult setViewResult = surroundView3dSession->setViews(views); + EXPECT_EQ(setViewResult, SvResult::OK); + + sp handler = + new SurroundViewServiceHandler(surroundView3dSession); + + SvResult result = surroundView3dSession->startStream(handler); + EXPECT_EQ(result, SvResult::OK); + + sleep(5); + + EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STARTED)); + EXPECT_GT(handler->getReceiveFramesCount(), 0); + + surroundView3dSession->stopStream(); + + sleep(1); + EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STOPPED)); + + result = mSurroundViewService->stop3dSession(surroundView3dSession); + EXPECT_EQ(result, SvResult::OK); +} + +TEST_P(SurroundViewHidlTest, start3dStreamWithoutReturningFrames) { + ALOGD("SurroundViewHidlTest::start3dStreamWithoutReturningFrames"); + sp surroundView3dSession; + mSurroundViewService->start3dSession( + [&surroundView3dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView3dSession = session; + }); + + std::vector views(1); + SvResult setViewResult = surroundView3dSession->setViews(views); + EXPECT_EQ(setViewResult, SvResult::OK); + + sp handler = + new SurroundViewServiceHandler(surroundView3dSession); + handler->setDoNotReturnFrames(true); + + SvResult result = surroundView3dSession->startStream(handler); + EXPECT_EQ(result, SvResult::OK); + + sleep(5); + + EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STARTED)); + EXPECT_TRUE(handler->checkEventReceived(SvEvent::FRAME_DROPPED)); + EXPECT_GT(handler->getReceiveFramesCount(), 0); + + surroundView3dSession->stopStream(); + + sleep(1); + EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STOPPED)); + + result = mSurroundViewService->stop3dSession(surroundView3dSession); + EXPECT_EQ(result, SvResult::OK); +} + +TEST_P(SurroundViewHidlTest, duplicateStart3dStream) { + ALOGD("SurroundViewHidlTest, duplicateStart3dStream"); + sp surroundView3dSession; + mSurroundViewService->start3dSession( + [&surroundView3dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView3dSession = session; + }); + + std::vector views(1); + SvResult setViewResult = surroundView3dSession->setViews(views); + EXPECT_EQ(setViewResult, SvResult::OK); + + sp handler = + new SurroundViewServiceHandler(surroundView3dSession); + + SvResult result = surroundView3dSession->startStream(handler); + EXPECT_EQ(result, SvResult::OK); + + result = surroundView3dSession->startStream(handler); + EXPECT_NE(result, SvResult::OK); + + surroundView3dSession->stopStream(); + mSurroundViewService->stop3dSession(surroundView3dSession); +} + +TEST_P(SurroundViewHidlTest, start3dStreamNoViewSetFail) { + ALOGD("SurroundViewHidlTest, start3dStreamNoViewSetFail"); + sp surroundView3dSession; + mSurroundViewService->start3dSession( + [&surroundView3dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView3dSession = session; + }); + + sp handler = + new SurroundViewServiceHandler(surroundView3dSession); + + SvResult result = surroundView3dSession->startStream(handler); + EXPECT_EQ(result, SvResult::VIEW_NOT_SET); + + mSurroundViewService->stop3dSession(surroundView3dSession); +} + +TEST_P(SurroundViewHidlTest, validate3dSvFramesDesc) { + ALOGD("SurroundViewHidlTest, validate3dSvFramesDesc"); + sp surroundView3dSession; + mSurroundViewService->start3dSession( + [&surroundView3dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView3dSession = session; + }); + + sp handler = + new SurroundViewServiceHandler(surroundView3dSession); + + std::vector views(1); + views[0].viewId = 0; + SvResult setViewResult = surroundView3dSession->setViews(views); + EXPECT_EQ(setViewResult, SvResult::OK); + + SvResult result = surroundView3dSession->startStream(handler); + EXPECT_EQ(result, SvResult::OK); + + sleep(5); + + EXPECT_GT(handler->getReceiveFramesCount(), 0); + EXPECT_TRUE(handler->areAllFramesValid()); + + // Validate 3d SvFramesDesc when only one view is set. + SvFramesDesc frames = handler->getLastReceivedFrames(); + EXPECT_EQ(frames.svBuffers.size(), 1); + EXPECT_EQ(frames.svBuffers[0].viewId, 0); + + views.resize(3); + views[0].viewId = 0; + views[1].viewId = 1; + views[2].viewId = 2; + setViewResult = surroundView3dSession->setViews(views); + EXPECT_EQ(setViewResult, SvResult::OK); + + sleep(1); + + // Validate 3d SvFramesDesc when multiple views are set. + EXPECT_TRUE(handler->areAllFramesValid()); + frames = handler->getLastReceivedFrames(); + EXPECT_EQ(frames.svBuffers.size(), 3); + EXPECT_EQ(frames.svBuffers[0].viewId, 0); + EXPECT_EQ(frames.svBuffers[1].viewId, 1); + EXPECT_EQ(frames.svBuffers[2].viewId, 2); + EXPECT_EQ(frames.svBuffers[0].hardwareBuffer.description[0], + frames.svBuffers[1].hardwareBuffer.description[0]); + EXPECT_EQ(frames.svBuffers[0].hardwareBuffer.description[1], + frames.svBuffers[1].hardwareBuffer.description[1]); + EXPECT_EQ(frames.svBuffers[1].hardwareBuffer.description[0], + frames.svBuffers[2].hardwareBuffer.description[0]); + EXPECT_EQ(frames.svBuffers[1].hardwareBuffer.description[1], + frames.svBuffers[2].hardwareBuffer.description[1]); + + // Clean up + surroundView3dSession->stopStream(); + result = mSurroundViewService->stop3dSession(surroundView3dSession); +} + +TEST_P(SurroundViewHidlTest, set3dConfigResolution) { + ALOGD("SurroundViewHidlTest, set3dConfigResolution"); + sp surroundView3dSession; + mSurroundViewService->start3dSession( + [&surroundView3dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView3dSession = session; + }); + + sp handler = + new SurroundViewServiceHandler(surroundView3dSession); + + std::vector views(1); + views[0].viewId = 0; + SvResult setViewResult = surroundView3dSession->setViews(views); + EXPECT_EQ(setViewResult, SvResult::OK); + SvResult result = surroundView3dSession->startStream(handler); + EXPECT_EQ(result, SvResult::OK); + + sleep(1); + + // Change config + Sv3dConfig config; + config.width = 1920; + config.height = 1080; + config.carDetails = SvQuality::HIGH; + surroundView3dSession->set3dConfig(config); + + sleep(1); + + EXPECT_TRUE(handler->checkEventReceived(SvEvent::CONFIG_UPDATED)); + + // Check width has been changed but not the ratio + SvFramesDesc frames = handler->getLastReceivedFrames(); + EXPECT_EQ(frames.svBuffers.size(), 1); + SvBuffer svBuffer3d = frames.svBuffers[0]; + EXPECT_EQ(svBuffer3d.viewId, 0); + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&svBuffer3d.hardwareBuffer.description); + EXPECT_EQ(pDesc->width, config.width); + EXPECT_EQ(pDesc->height, config.height); + + // Clean up + surroundView3dSession->stopStream(); + mSurroundViewService->stop3dSession(surroundView3dSession); +} + +TEST_P(SurroundViewHidlTest, set3dConfigCarDetails) { + ALOGD("SurroundViewHidlTest, set3dConfigCarDetails"); + sp surroundView3dSession; + mSurroundViewService->start3dSession( + [&surroundView3dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView3dSession = session; + }); + + sp handler = + new SurroundViewServiceHandler(surroundView3dSession); + + std::vector views(1); + views[0].viewId = 0; + SvResult setViewResult = surroundView3dSession->setViews(views); + EXPECT_EQ(setViewResult, SvResult::OK); + SvResult result = surroundView3dSession->startStream(handler); + EXPECT_EQ(result, SvResult::OK); + + sleep(1); + + // Get the width before config changed + int oldWidth, oldHeight; + SvFramesDesc frames = handler->getLastReceivedFrames(); + EXPECT_EQ(frames.svBuffers.size(), 1); + SvBuffer svBuffer3d = frames.svBuffers[0]; + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&svBuffer3d.hardwareBuffer.description); + oldWidth = pDesc->width; + oldHeight = pDesc->height; + + // Change config + Sv3dConfig config; + config.width = oldWidth; + config.height = oldHeight; + config.carDetails = SvQuality::LOW; + surroundView3dSession->set3dConfig(config); + + sleep(1); + + EXPECT_TRUE(handler->checkEventReceived(SvEvent::CONFIG_UPDATED)); + + Sv3dConfig retConfig; + surroundView3dSession->get3dConfig([&retConfig] (Sv3dConfig config) { + retConfig.width = config.width; + retConfig.height = config.height; + retConfig.carDetails = config.carDetails; + }); + + // Check config blending has been changed but not the width + EXPECT_EQ(retConfig.carDetails, config.carDetails); + EXPECT_EQ(retConfig.width, oldWidth); + EXPECT_EQ(retConfig.height, oldHeight); + + // Clean up + surroundView3dSession->stopStream(); + mSurroundViewService->stop3dSession(surroundView3dSession); +} + +std::pair> GetMappedSharedMemory(int bytesSize) { + + const auto nullResult = std::make_pair(hidl_memory(), nullptr); + + sp ashmemAllocator = IAllocator::getService("ashmem"); + if (ashmemAllocator.get() == nullptr) { + ALOGE("SurroundViewHidlTest getService ashmem failed"); + return nullResult; + } + + // Allocate shared memory. + hidl_memory hidlMemory; + bool allocateSuccess = false; + Return result = ashmemAllocator->allocate(bytesSize, + [&](bool success, const hidl_memory& hidlMem) { + if (!success) { + return; + } + allocateSuccess = success; + hidlMemory = hidlMem; + }); + + // Check result of allocated memory. + if (!result.isOk() || !allocateSuccess) { + ALOGE("SurroundViewHidlTest allocate shared memory failed"); + return nullResult; + } + + // Map shared memory. + sp pIMemory = mapMemory(hidlMemory); + if (pIMemory.get() == nullptr) { + ALOGE("SurroundViewHidlTest map shared memory failed"); + return nullResult; + } + + return std::make_pair(hidlMemory, pIMemory); +} + +void SetIndexOfOverlaysMemory( + const std::vector& overlaysMemDesc, + sp pIMemory, int indexPosition, uint16_t indexValue) { + + // Count the number of vertices until the index. + int totalVerticesCount = 0; + for (int i = 0; i < indexPosition; i++) { + totalVerticesCount += overlaysMemDesc[i].verticesCount; + } + + const int indexBytePosition = (indexPosition * kIdByteSize) + + (kVertexByteSize * totalVerticesCount); + + uint8_t* pSharedMemoryData = (uint8_t*)((void*)pIMemory->getPointer()); + pSharedMemoryData += indexBytePosition; + uint16_t* pIndex16bit = (uint16_t*)pSharedMemoryData; + + ALOGD("Setting index at pos %d", indexBytePosition); + + // Modify shared memory. + pIMemory->update(); + *pIndex16bit = indexValue; + pIMemory->commit(); +} + +std::pair> GetSampleOverlaysData() { + OverlaysData overlaysData; + overlaysData.overlaysMemoryDesc.resize(2); + + int sharedMemBytesSize = 0; + OverlayMemoryDesc overlayMemDesc1, overlayMemDesc2; + overlayMemDesc1.id = 0; + overlayMemDesc1.verticesCount = 6; + overlayMemDesc1.overlayPrimitive = OverlayPrimitive::TRIANGLES; + overlaysData.overlaysMemoryDesc[0] = overlayMemDesc1; + sharedMemBytesSize += kIdByteSize + + kVertexByteSize * overlayMemDesc1.verticesCount; + + overlayMemDesc2.id = 1; + overlayMemDesc2.verticesCount = 4; + overlayMemDesc2.overlayPrimitive = OverlayPrimitive::TRIANGLES_STRIP; + overlaysData.overlaysMemoryDesc[1] = overlayMemDesc2; + sharedMemBytesSize += kIdByteSize + + kVertexByteSize * overlayMemDesc2.verticesCount; + + std::pair> sharedMem = + GetMappedSharedMemory(sharedMemBytesSize); + sp pIMemory = sharedMem.second; + if (pIMemory.get() == nullptr) { + return std::make_pair(OverlaysData(), nullptr); + } + + // Get pointer to shared memory data and set all bytes to 0. + uint8_t* pSharedMemoryData = (uint8_t*)((void*)pIMemory->getPointer()); + pIMemory->update(); + memset(pSharedMemoryData, 0, sharedMemBytesSize); + pIMemory->commit(); + + std::vector overlaysDesc = {overlayMemDesc1, + overlayMemDesc2}; + + // Set indexes in shared memory. + SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 0, overlayMemDesc1.id); + SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 1, overlayMemDesc2.id); + + overlaysData.overlaysMemoryDesc = overlaysDesc; + overlaysData.overlaysMemory = sharedMem.first; + + return std::make_pair(overlaysData, pIMemory); +} + +TEST_P(SurroundViewHidlTest, updateOverlaysSuccess) { + ALOGD("SurroundViewHidlTest, updateOverlaysSuccess"); + + sp surroundView3dSession; + mSurroundViewService->start3dSession( + [&surroundView3dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView3dSession = session; + }); + + std::pair> overlaysData = GetSampleOverlaysData(); + ASSERT_NE(overlaysData.second, nullptr); + + SvResult result = surroundView3dSession->updateOverlays(overlaysData.first); + EXPECT_EQ(result, SvResult::OK); + + mSurroundViewService->stop3dSession(surroundView3dSession); +} + +TEST_P(SurroundViewHidlTest, overlaysDataMismatchIdFail) { + ALOGD("SurroundViewHidlTest, overlaysDataMismatchIdFail"); + + sp surroundView3dSession; + mSurroundViewService->start3dSession( + [&surroundView3dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView3dSession = session; + }); + + std::pair> overlaysDataMismatchId + = GetSampleOverlaysData(); + ASSERT_NE(overlaysDataMismatchId.second, nullptr); + + // Set id of second overlay in shared memory to 2 (expected is 1). + auto& overlaysDesc = overlaysDataMismatchId.first.overlaysMemoryDesc; + auto& pIMemory = overlaysDataMismatchId.second; + SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 1, 2); + + SvResult result = surroundView3dSession->updateOverlays( + overlaysDataMismatchId.first); + EXPECT_EQ(result, SvResult::INVALID_ARG); + + mSurroundViewService->stop3dSession(surroundView3dSession); +} + +TEST_P(SurroundViewHidlTest, overlaysDataNullMemoryFail) { + ALOGD("SurroundViewHidlTest, overlaysDataNullMemoryFail"); + + sp surroundView3dSession; + mSurroundViewService->start3dSession( + [&surroundView3dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView3dSession = session; + }); + + std::pair> overlaysDataNullMemory + = GetSampleOverlaysData(); + + // Set shared memory to null. + overlaysDataNullMemory.first.overlaysMemory = hidl_memory(); + + SvResult result = surroundView3dSession->updateOverlays( + overlaysDataNullMemory.first); + EXPECT_EQ(result, SvResult::INVALID_ARG); + + mSurroundViewService->stop3dSession(surroundView3dSession); +} + +TEST_P(SurroundViewHidlTest, overlaysDataLessThan3VerticesFail) { + ALOGD("SurroundViewHidlTest, overlaysDataLessThan3VerticesFail"); + + sp surroundView3dSession; + mSurroundViewService->start3dSession( + [&surroundView3dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView3dSession = session; + }); + + std::pair> overlaysData2Vertices + = GetSampleOverlaysData(); + + // Set vertices count of second overlay to 2. + overlaysData2Vertices.first.overlaysMemoryDesc[1].verticesCount = 2; + + SvResult result = surroundView3dSession->updateOverlays( + overlaysData2Vertices.first); + EXPECT_EQ(result, SvResult::INVALID_ARG); + + mSurroundViewService->stop3dSession(surroundView3dSession); +} + +TEST_P(SurroundViewHidlTest, overlaysDataVerticesCountFail) { + ALOGD("SurroundViewHidlTest, overlaysDataVerticesNotMultipleOf3Fail"); + + sp surroundView3dSession; + mSurroundViewService->start3dSession( + [&surroundView3dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView3dSession = session; + }); + + OverlaysData overlaysData; + overlaysData.overlaysMemoryDesc.resize(1); + + OverlayMemoryDesc overlayMemDesc1; + overlayMemDesc1.id = 0; + overlayMemDesc1.verticesCount = 4; // Invalid count for TRIANGLES primitive. + overlayMemDesc1.overlayPrimitive = OverlayPrimitive::TRIANGLES; + overlaysData.overlaysMemoryDesc[0] = overlayMemDesc1; + + const int sharedMemBytesSize = + 2 + sizeof(float) * overlayMemDesc1.verticesCount; + auto sharedMem = GetMappedSharedMemory(sharedMemBytesSize); + + // Set index in shared memory. + auto& overlaysDesc = overlaysData.overlaysMemoryDesc; + auto& pIMemory = sharedMem.second; + SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 0, overlayMemDesc1.id); + + SvResult result = surroundView3dSession->updateOverlays(overlaysData); + EXPECT_EQ(result, SvResult::INVALID_ARG); + + mSurroundViewService->stop3dSession(surroundView3dSession); +} + +TEST_P(SurroundViewHidlTest, overlaysDataSameIdFail) { + ALOGD("SurroundViewHidlTest, overlaysDataSameIdFail"); + + sp surroundView3dSession; + mSurroundViewService->start3dSession( + [&surroundView3dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView3dSession = session; + }); + + std::pair> overlaysDataSameId + = GetSampleOverlaysData(); + ASSERT_NE(overlaysDataSameId.second, nullptr); + + // Set id of second overlay as id of first. + auto& overlaysDesc = overlaysDataSameId.first.overlaysMemoryDesc; + auto& pIMemory = overlaysDataSameId.second; + SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 1, overlaysDesc[0].id); + + SvResult result = surroundView3dSession->updateOverlays( + overlaysDataSameId.first); + EXPECT_EQ(result, SvResult::INVALID_ARG); + + mSurroundViewService->stop3dSession(surroundView3dSession); +} + +TEST_P(SurroundViewHidlTest, projectPointsIncorrectCameraIdFail) { + ALOGD("SurroundViewHidlTest, projectPointsIncorrectCameraIdFail"); + + hidl_vec cameraIds; + mSurroundViewService->getCameraIds([&cameraIds]( + const hidl_vec& camIds) { + cameraIds = camIds; + }); + EXPECT_GT(cameraIds.size(), 0); + + sp surroundView3dSession; + mSurroundViewService->start3dSession( + [&surroundView3dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView3dSession = session; + }); + + Point2dInt cameraPoint; + cameraPoint.x = 0; + cameraPoint.y = 0; + std::vector cameraPoints = {cameraPoint}; + + hidl_string invalidCameraId = "INVALID_CAMERA_ID"; + + std::vector points3d; + surroundView3dSession->projectCameraPointsTo3dSurface( + cameraPoints, invalidCameraId, + [&points3d](const hidl_vec& points3dproj) { + points3d = points3dproj; + }); + + EXPECT_TRUE(points3d.empty()); + + mSurroundViewService->stop3dSession(surroundView3dSession); +} + +TEST_P(SurroundViewHidlTest, projectPointsInvalidPointsFail) { + ALOGD("SurroundViewHidlTest, projectPointsInvalidPointsFail"); + + hidl_vec cameraIds; + mSurroundViewService->getCameraIds([&cameraIds]( + const hidl_vec& camIds) { + cameraIds = camIds; + }); + + EXPECT_GT(cameraIds.size(), 0); + + sp surroundView3dSession; + mSurroundViewService->start3dSession( + [&surroundView3dSession]( + const sp& session, SvResult result) { + ASSERT_EQ(result, SvResult::OK); + surroundView3dSession = session; + }); + + sp handler = + new SurroundViewServiceHandler(surroundView3dSession); + + std::vector views(1); + views[0].viewId = 0; + SvResult setViewResult = surroundView3dSession->setViews(views); + EXPECT_EQ(setViewResult, SvResult::OK); + SvResult result = surroundView3dSession->startStream(handler); + EXPECT_EQ(result, SvResult::OK); + + sleep(1); + + // Get the width and height of the frame + int width, height; + SvFramesDesc frames = handler->getLastReceivedFrames(); + EXPECT_EQ(frames.svBuffers.size(), 1); + SvBuffer svBuffer2d = frames.svBuffers[0]; + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&svBuffer2d.hardwareBuffer.description); + width = pDesc->width; + height = pDesc->height; + + Point2dInt cameraPoint; + cameraPoint.x = width * 2; + cameraPoint.y = height * 2; + std::vector cameraPoints = {cameraPoint}; + + std::vector points3d; + surroundView3dSession->projectCameraPointsTo3dSurface( + cameraPoints, cameraIds[0], + [&points3d](const hidl_vec& points3dproj) { + points3d = points3dproj; + }); + + EXPECT_FALSE(points3d[0].isValid); + + surroundView3dSession->stopStream(); + mSurroundViewService->stop3dSession(surroundView3dSession); +} + +INSTANTIATE_TEST_SUITE_P( + PerInstance, + SurroundViewHidlTest, + testing::ValuesIn( + android::hardware::getAllHalInstanceNames(ISurroundViewService::descriptor) + ), + android::hardware::PrintInstanceNameToString +); From b7a0685c9c1b925ab1590d0cf3851c9ac182a783 Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Fri, 21 Feb 2020 13:01:55 -0800 Subject: [PATCH 0633/1022] Add hash value for the interfaces in Tuner HAL bug: 148110220 Test: Manual Change-Id: If73f5fc2cd17e6c784b5386b025003b716658dd2 --- current.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/current.txt b/current.txt index fde9d539f2..357ff4e552 100644 --- a/current.txt +++ b/current.txt @@ -679,6 +679,19 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 2b0b10d2ea7a18a4048cd0eb83d35c19a817aeee95f65807fc31f4ef21381397 android.hardware.neuralnetworks@1.3::IPreparedModel eee3430cc86c97c7b407495863d8fb61da6f1a64b7721e77b9b4909b11b174e9 android.hardware.neuralnetworks@1.3::IPreparedModelCallback c9320b04ec302624985180a02d591bea5e435601fc411a6cabb58878e4e1ad68 android.hardware.neuralnetworks@1.3::types +b335c3c732c799b299fa61c6de6260ab4d20cbd0ec21acd6db14d8156c745d0b android.hardware.tv.tuner@1.0::types +adab52e647d1a1ccfbdabdfc9c73352f8e834b61322e505bc6e3d3a0d3acc259 android.hardware.tv.tuner@1.0::IDemux +548e1a16fc4f779346e14968a63cd6f160e1e2c8b8c99256b2bac24a24b52a9a android.hardware.tv.tuner@1.0::IDescrambler +b84597d59f0f1d03c9997d60eb15280f3950c287d46016240d89859789db4d47 android.hardware.tv.tuner@1.0::IDvr +e512a8b4ddef0d0c29d9f68101363dca7616033a24bab86bfca0829661e7484c android.hardware.tv.tuner@1.0::IDvrCallback +c113b5bed45b3a67ee3f15de1482742a8fd8d96e45ec72e628ee9be6301d51d7 android.hardware.tv.tuner@1.0::IFilter +8bbc6bde44573edf800cda2b457852175786a3c73f36666bfb2d3afdce3d0dfa android.hardware.tv.tuner@1.0::IFilterCallback +ccd985e820ed92a5cb55f524b3549462483d21824ca2df0276f5bc2f42878ea3 android.hardware.tv.tuner@1.0::IFrontend +818587bab10f2534b5a1ef70ed9bae99019f7d453b2fcb2dda01c6db91c3a805 android.hardware.tv.tuner@1.0::IFrontendCallback +83de3964a800a0e707731adcbcbfbaa56868549233e4c8dcccc8969fab727d38 android.hardware.tv.tuner@1.0::ILnb +b2310785bdb55f97bbbb2176e2ee73ed8d2a7ce5895bd20c997b90c5f2868ad8 android.hardware.tv.tuner@1.0::ILnbCallback +4788787e662293d526ff7789fc24e82533e7f6ff99a967ebc3e3ec6b17628796 android.hardware.tv.tuner@1.0::ITimeFilter +c350c7783843e0c7cf30f90c918770b0d3c09fc0fe5e532e2f2e7210fcfe71c9 android.hardware.tv.tuner@1.0::ITuner 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types From 2056c2da3b331de226d1e78ad15be21fdbba846c Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Tue, 10 Dec 2019 14:23:42 -0800 Subject: [PATCH 0634/1022] Parameterize VtsEvsHalV1_1TargetTest Bug: 142397658 Bug: 142275664 Test: VtsHalEvsV1_1Target Change-Id: I5e0a65e6200626c606c1c015942274d2098ee7ed Signed-off-by: Changyeon Jo --- .../functional/VtsHalEvsV1_1TargetTest.cpp | 85 +++++++------------ 1 file changed, 30 insertions(+), 55 deletions(-) diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index 8580500328..cde80482cb 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -17,15 +17,6 @@ #define LOG_TAG "VtsHalEvsTest" -// Note: We have't got a great way to indicate which target -// should be tested, so we'll leave the interface served by the -// default (mock) EVS driver here for easy reference. All -// actual EVS drivers should serve on the EvsEnumeratorHw name, -// however, so the code is checked in that way. -//const static char kEnumeratorName[] = "EvsEnumeratorHw-Mock"; -const static char kEnumeratorName[] = "EvsEnumeratorHw"; - - // These values are called out in the EVS design doc (as of Mar 8, 2017) static const int kMaxStreamStartMilliseconds = 500; static const int kMinimumFramesPerSecond = 10; @@ -61,10 +52,12 @@ static const float kNanoToSeconds = 0.000000001f; #include #include -#include -#include +#include +#include +#include using namespace ::android::hardware::automotive::evs::V1_1; +using namespace std::chrono_literals; using ::android::hardware::Return; using ::android::hardware::Void; @@ -97,29 +90,13 @@ typedef struct { } RawStreamConfig; -// Test environment for Evs HIDL HAL. -class EvsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static EvsHidlEnvironment* Instance() { - static EvsHidlEnvironment* instance = new EvsHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { registerTestService(); } - - private: - EvsHidlEnvironment() {} -}; - // The main test class for EVS -class EvsHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class EvsHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { // Make sure we can connect to the enumerator - string service_name = - EvsHidlEnvironment::Instance()->getServiceName(kEnumeratorName); - pEnumerator = getService(service_name); + std::string service_name = GetParam(); + pEnumerator = IEvsEnumerator::getService(service_name); ASSERT_NE(pEnumerator.get(), nullptr); mIsHwModule = pEnumerator->isHardware(); @@ -269,7 +246,7 @@ protected: * Opens each camera reported by the enumerator and then explicitly closes it via a * call to closeCamera. Then repeats the test to ensure all cameras can be reopened. */ -TEST_F(EvsHidlTest, CameraOpenClean) { +TEST_P(EvsHidlTest, CameraOpenClean) { ALOGI("Starting CameraOpenClean test"); // Get the camera list @@ -338,7 +315,7 @@ TEST_F(EvsHidlTest, CameraOpenClean) { * call. This ensures that the intended "aggressive open" behavior works. This is necessary for * the system to be tolerant of shutdown/restart race conditions. */ -TEST_F(EvsHidlTest, CameraOpenAggressive) { +TEST_P(EvsHidlTest, CameraOpenAggressive) { ALOGI("Starting CameraOpenAggressive test"); // Get the camera list @@ -415,7 +392,7 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { * CameraStreamPerformance: * Measure and qualify the stream start up time and streaming frame rate of each reported camera */ -TEST_F(EvsHidlTest, CameraStreamPerformance) { +TEST_P(EvsHidlTest, CameraStreamPerformance) { ALOGI("Starting CameraStreamPerformance test"); // Get the camera list @@ -505,7 +482,7 @@ TEST_F(EvsHidlTest, CameraStreamPerformance) { * Ensure the camera implementation behaves properly when the client holds onto buffers for more * than one frame time. The camera must cleanly skip frames until the client is ready again. */ -TEST_F(EvsHidlTest, CameraStreamBuffering) { +TEST_P(EvsHidlTest, CameraStreamBuffering) { ALOGI("Starting CameraStreamBuffering test"); // Arbitrary constant (should be > 1 and less than crazy) @@ -590,7 +567,7 @@ TEST_F(EvsHidlTest, CameraStreamBuffering) { * imagery is simply copied to the display buffer and presented on screen. This is the one test * which a human could observe to see the operation of the system on the physical display. */ -TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { +TEST_P(EvsHidlTest, CameraToDisplayRoundTrip) { ALOGI("Starting CameraToDisplayRoundTrip test"); // Get the camera list @@ -689,7 +666,7 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { * Verify that each client can start and stop video streams on the same * underlying camera. */ -TEST_F(EvsHidlTest, MultiCameraStream) { +TEST_P(EvsHidlTest, MultiCameraStream) { ALOGI("Starting MultiCameraStream test"); if (mIsHwModule) { @@ -796,7 +773,7 @@ TEST_F(EvsHidlTest, MultiCameraStream) { * CameraParameter: * Verify that a client can adjust a camera parameter. */ -TEST_F(EvsHidlTest, CameraParameter) { +TEST_P(EvsHidlTest, CameraParameter) { ALOGI("Starting CameraParameter test"); // Get the camera list @@ -940,7 +917,7 @@ TEST_F(EvsHidlTest, CameraParameter) { * Verify that non-master client gets notified when the master client either * terminates or releases a role. */ -TEST_F(EvsHidlTest, CameraMasterRelease) { +TEST_P(EvsHidlTest, CameraMasterRelease) { ALOGI("Starting CameraMasterRelease test"); if (mIsHwModule) { @@ -1121,7 +1098,7 @@ TEST_F(EvsHidlTest, CameraMasterRelease) { * Verify that master and non-master clients behave as expected when they try to adjust * camera parameters. */ -TEST_F(EvsHidlTest, MultiCameraParameter) { +TEST_P(EvsHidlTest, MultiCameraParameter) { ALOGI("Starting MultiCameraParameter test"); if (mIsHwModule) { @@ -1404,7 +1381,7 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { std::mutex eventLock; auto timer = std::chrono::system_clock::now(); - unique_lock lock(eventLock); + std::unique_lock lock(eventLock); while (!listening) { eventCond.wait_until(lock, timer + 1s); } @@ -1594,7 +1571,7 @@ TEST_F(EvsHidlTest, MultiCameraParameter) { * EVS client, which owns the display, is priortized and therefore can take over * a master role from other EVS clients without the display. */ -TEST_F(EvsHidlTest, HighPriorityCameraClient) { +TEST_P(EvsHidlTest, HighPriorityCameraClient) { ALOGI("Starting HighPriorityCameraClient test"); if (mIsHwModule) { @@ -1967,7 +1944,7 @@ TEST_F(EvsHidlTest, HighPriorityCameraClient) { * CameraToDisplayRoundTrip test case but this case retrieves available stream * configurations from EVS and uses one of them to start a video stream. */ -TEST_F(EvsHidlTest, CameraUseStreamConfigToDisplay) { +TEST_P(EvsHidlTest, CameraUseStreamConfigToDisplay) { ALOGI("Starting CameraUseStreamConfigToDisplay test"); // Get the camera list @@ -2071,7 +2048,7 @@ TEST_F(EvsHidlTest, CameraUseStreamConfigToDisplay) { * Verify that each client can start and stop video streams on the same * underlying camera with same configuration. */ -TEST_F(EvsHidlTest, MultiCameraStreamUseConfig) { +TEST_P(EvsHidlTest, MultiCameraStreamUseConfig) { ALOGI("Starting MultiCameraStream test"); if (mIsHwModule) { @@ -2220,7 +2197,7 @@ TEST_F(EvsHidlTest, MultiCameraStreamUseConfig) { * checking its capability and locating supporting physical camera device * identifiers. */ -TEST_F(EvsHidlTest, LogicalCameraMetadata) { +TEST_P(EvsHidlTest, LogicalCameraMetadata) { ALOGI("Starting LogicalCameraMetadata test"); // Get the camera list @@ -2244,7 +2221,7 @@ TEST_F(EvsHidlTest, LogicalCameraMetadata) { * call to closeUltrasonicsArray. Then repeats the test to ensure all ultrasonics arrays * can be reopened. */ -TEST_F(EvsHidlTest, UltrasonicsArrayOpenClean) { +TEST_P(EvsHidlTest, UltrasonicsArrayOpenClean) { ALOGI("Starting UltrasonicsArrayOpenClean test"); // Get the ultrasonics array list @@ -2271,7 +2248,7 @@ TEST_F(EvsHidlTest, UltrasonicsArrayOpenClean) { // Starts a stream and verifies all data received is valid. -TEST_F(EvsHidlTest, UltrasonicsVerifyStreamData) { +TEST_P(EvsHidlTest, UltrasonicsVerifyStreamData) { ALOGI("Starting UltrasonicsVerifyStreamData"); // Get the ultrasonics array list @@ -2307,7 +2284,7 @@ TEST_F(EvsHidlTest, UltrasonicsVerifyStreamData) { // Sets frames in flight before and after start of stream and verfies success. -TEST_F(EvsHidlTest, UltrasonicsSetFramesInFlight) { +TEST_P(EvsHidlTest, UltrasonicsSetFramesInFlight) { ALOGI("Starting UltrasonicsSetFramesInFlight"); // Get the ultrasonics array list @@ -2342,11 +2319,9 @@ TEST_F(EvsHidlTest, UltrasonicsSetFramesInFlight) { } -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - EvsHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); - return status; -} +INSTANTIATE_TEST_SUITE_P( + PerInstance, + EvsHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEvsEnumerator::descriptor)), + android::hardware::PrintInstanceNameToString); + From 92747ce5d1bd4318d98ae9def157eb9efc3f8b90 Mon Sep 17 00:00:00 2001 From: Brad Ebinger Date: Thu, 20 Feb 2020 13:57:31 -0800 Subject: [PATCH 0635/1022] Clarify new setRadioPower documentation There were some questions on how the new IRadio 1.5 setRadioPower command should be implemented based on vendor feedback. This CL clarifies this behavior. Test: manual Bug: 143683674 Bug: 147496715 Merged-In: If08741f0ea156a5c2656a47e46f7e1f98bf54ec4 Change-Id: If08741f0ea156a5c2656a47e46f7e1f98bf54ec4 (cherry picked from commit 0eac27ccf30b4d04be3796818b08b830dfab649f) --- current.txt | 2 +- radio/1.5/IRadio.hal | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/current.txt b/current.txt index e7face5d96..b4893bdcee 100644 --- a/current.txt +++ b/current.txt @@ -702,7 +702,7 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar 77531c8d048f8f8ae532babd0ca86332a865ec9aace1b051226ef2b21123e645 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types 99f5c26b952271d1246c957e1d0271fa39445ee65cc93aa7c187834f98914a33 android.hardware.radio@1.5::types -7fefa2cc5b3b3be10b5cff5c5dc195385f491d4bf23ca65f9c6b3c30c8753a33 android.hardware.radio@1.5::IRadio +890ecacaaa6660802bac01bbbe5f16b1eb1d6a3a3f0e5b398be5cec76a5ab673 android.hardware.radio@1.5::IRadio e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication 829d3827eeb5a8f563e80fe627419b3231012fc02bc2e79782ec5e9ad9f799a4 android.hardware.radio@1.5::IRadioResponse 4c4ce691df02faa28c0729e2a033ec464e1d72699be8bcde4dfb141313dbeba8 android.hardware.radio.config@1.3::types diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal index 0b50436ff9..87824e2ea8 100644 --- a/radio/1.5/IRadio.hal +++ b/radio/1.5/IRadio.hal @@ -238,7 +238,8 @@ interface IRadio extends @1.4::IRadio { * 1) Emergency call is completed; or * 2) Another setRadioPower_1_5 is issued with forEmergencyCall being false or * preferredForEmergencyCall being false; or - * 3) Timeout after a long period of time. + * 3) Timeout after 30 seconds if dial or emergencyDial is not called. + * Once one of these conditions is reached, the modem should move into normal operation. * * @param serial Serial number of request. * @param powerOn To turn on radio -> on = true, to turn off radio -> on = false. From 8f4e79a64630e8976c3df6f9d61b76daa6e3940c Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Mon, 24 Feb 2020 17:18:00 -0800 Subject: [PATCH 0636/1022] Remove IRadioConfig 1.3 hash Bad merge conflict resolution when removing IRadioConfig 1.3 Bug: 149522248 Test: mm cf_x86_phone-userdebug Change-Id: I055b94a2bf275d9ed5ecff6f271e8204e6ee7c0b --- current.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/current.txt b/current.txt index e7face5d96..cb7455dc39 100644 --- a/current.txt +++ b/current.txt @@ -705,10 +705,6 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar 7fefa2cc5b3b3be10b5cff5c5dc195385f491d4bf23ca65f9c6b3c30c8753a33 android.hardware.radio@1.5::IRadio e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication 829d3827eeb5a8f563e80fe627419b3231012fc02bc2e79782ec5e9ad9f799a4 android.hardware.radio@1.5::IRadioResponse -4c4ce691df02faa28c0729e2a033ec464e1d72699be8bcde4dfb141313dbeba8 android.hardware.radio.config@1.3::types -a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig -742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication -0006ab8e8b0910cbd3bbb08d5f17d5fac7d65a2bdad5f2334e4851db9d1e6fa8 android.hardware.radio.config@1.3::IRadioConfigResponse 3ca6616381080bdd6c08141ad12775a94ae868c58b02b1274ae3326f7de724ab android.hardware.sensors@2.1::ISensors 3d4141c6373cd9ca02fe221a7d12343840de2255d032c38248fe8e35816b58b2 android.hardware.sensors@2.1::ISensorsCallback 8051cc50fc90ed447f058a8b15d81f35a65f1bd9004b1de4f127edeb89b47978 android.hardware.sensors@2.1::types From 7aab1010d4c58c13187fa0684c38264de8aead17 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Fri, 14 Feb 2020 15:39:55 -0800 Subject: [PATCH 0637/1022] audio hal: Update offload configuration Test: no regression with offloaded Play Music Bug: 133526565 Merged-In: Ie655a96503be5a4ad1660d4b2183b01e514452fd Change-Id: Ie655a96503be5a4ad1660d4b2183b01e514452fd (cherry picked from commit c91b679ac1ae75ac60a277be7d4a6f573e4c22bf) --- audio/common/6.0/types.hal | 22 +++++++++++ .../common/all-versions/default/HidlUtils.cpp | 37 +++++++++++++++++-- audio/common/all-versions/default/HidlUtils.h | 15 +++++--- audio/core/all-versions/default/Device.cpp | 6 ++- current.txt | 2 +- 5 files changed, 70 insertions(+), 12 deletions(-) diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal index b2806c7eeb..67217ab503 100644 --- a/audio/common/6.0/types.hal +++ b/audio/common/6.0/types.hal @@ -903,6 +903,25 @@ enum AudioContentType : uint32_t { SONIFICATION = 4, }; +/** Encapsulation mode used for sending audio compressed data. */ +@export(name="audio_encapsulation_mode_t", value_prefix="AUDIO_ENCAPSULATION_MODE_") +enum AudioEncapsulationMode : int32_t { + // Do not change these values without updating their counterparts + // in frameworks/base/media/java/android/media/AudioTrack.java + /** + * No encapsulation mode for metadata. + */ + NONE = 0, + /** + * Elementary stream payload with metadata + */ + ELEMENTARY_STREAM = 1, + /** + * Handle-based payload with metadata + */ + HANDLE = 2, +}; + /** * Additional information about the stream passed to hardware decoders. */ @@ -918,6 +937,9 @@ struct AudioOffloadInfo { uint32_t bitWidth; uint32_t bufferSize; AudioUsage usage; + AudioEncapsulationMode encapsulationMode; + int32_t contentId; + int32_t syncId; }; /** diff --git a/audio/common/all-versions/default/HidlUtils.cpp b/audio/common/all-versions/default/HidlUtils.cpp index 08002c8788..a470c9cb78 100644 --- a/audio/common/all-versions/default/HidlUtils.cpp +++ b/audio/common/all-versions/default/HidlUtils.cpp @@ -28,12 +28,13 @@ namespace common { namespace CPP_VERSION { namespace implementation { -void HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config) { +status_t HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config) { config->sampleRateHz = halConfig.sample_rate; config->channelMask = EnumBitfield(halConfig.channel_mask); config->format = AudioFormat(halConfig.format); - audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo); + status_t status = audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo); config->frameCount = halConfig.frame_count; + return status; } void HidlUtils::audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig) { @@ -106,8 +107,8 @@ audio_usage_t HidlUtils::audioUsageToHal(const AudioUsage usage) { return static_cast(usage); } -void HidlUtils::audioOffloadInfoFromHal(const audio_offload_info_t& halOffload, - AudioOffloadInfo* offload) { +status_t HidlUtils::audioOffloadInfoFromHal(const audio_offload_info_t& halOffload, + AudioOffloadInfo* offload) { offload->sampleRateHz = halOffload.sample_rate; offload->channelMask = EnumBitfield(halOffload.channel_mask); offload->format = AudioFormat(halOffload.format); @@ -119,6 +120,26 @@ void HidlUtils::audioOffloadInfoFromHal(const audio_offload_info_t& halOffload, offload->bitWidth = halOffload.bit_width; offload->bufferSize = halOffload.offload_buffer_size; offload->usage = audioUsageFromHal(halOffload.usage); +#if MAJOR_VERSION >= 6 + if (halOffload.version >= AUDIO_OFFLOAD_INFO_VERSION_0_2) { + offload->encapsulationMode = + static_cast(halOffload.encapsulation_mode); + offload->contentId = halOffload.content_id; + offload->syncId = halOffload.sync_id; + } else { + offload->encapsulationMode = AudioEncapsulationMode::NONE; + offload->contentId = 0; + offload->syncId = 0; + } +#else + // nonzero values here are not compatible with HAL versions below 6. + if (halOffload.version >= AUDIO_OFFLOAD_INFO_VERSION_0_2 && + (halOffload.encapsulation_mode != AUDIO_ENCAPSULATION_MODE_NONE || + halOffload.content_id != 0 || halOffload.sync_id != 0)) { + return BAD_VALUE; + } +#endif + return OK; } void HidlUtils::audioOffloadInfoToHal(const AudioOffloadInfo& offload, @@ -135,6 +156,14 @@ void HidlUtils::audioOffloadInfoToHal(const AudioOffloadInfo& offload, halOffload->bit_width = offload.bitWidth; halOffload->offload_buffer_size = offload.bufferSize; halOffload->usage = audioUsageToHal(offload.usage); +#if MAJOR_VERSION >= 6 + halOffload->encapsulation_mode = + static_cast(offload.encapsulationMode); + halOffload->content_id = offload.contentId; + halOffload->sync_id = offload.syncId; +#else + // offload doesn't contain encapsulationMode, contentId, syncId, so this is OK. +#endif } void HidlUtils::audioPortConfigFromHal(const struct audio_port_config& halConfig, diff --git a/audio/common/all-versions/default/HidlUtils.h b/audio/common/all-versions/default/HidlUtils.h index 758a7f43d1..ef6dee3706 100644 --- a/audio/common/all-versions/default/HidlUtils.h +++ b/audio/common/all-versions/default/HidlUtils.h @@ -35,8 +35,11 @@ namespace implementation { using namespace ::android::hardware::audio::common::CPP_VERSION; class HidlUtils { - public: - static void audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config); + public: + // A failure here indicates a platform config that is incompatible with + // the compiled HIDL interface version. + static status_t audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config); + static void audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig); static void audioGainConfigFromHal(const struct audio_gain_config& halConfig, AudioGainConfig* config); @@ -46,8 +49,10 @@ class HidlUtils { static void audioGainToHal(const AudioGain& gain, struct audio_gain* halGain); static AudioUsage audioUsageFromHal(const audio_usage_t halUsage); static audio_usage_t audioUsageToHal(const AudioUsage usage); - static void audioOffloadInfoFromHal(const audio_offload_info_t& halOffload, - AudioOffloadInfo* offload); + // A failure here indicates a platform offload info that is incompatible with + // the compiled HIDL interface version. + static status_t audioOffloadInfoFromHal(const audio_offload_info_t& halOffload, + AudioOffloadInfo* offload); static void audioOffloadInfoToHal(const AudioOffloadInfo& offload, audio_offload_info_t* halOffload); static void audioPortConfigFromHal(const struct audio_port_config& halConfig, @@ -58,7 +63,7 @@ class HidlUtils { const struct audio_port_config* halConfigs, hidl_vec* configs); static std::unique_ptr audioPortConfigsToHal( - const hidl_vec& configs); + const hidl_vec& configs); static void audioPortFromHal(const struct audio_port& halPort, AudioPort* port); static void audioPortToHal(const AudioPort& port, struct audio_port* halPort); static void uuidFromHal(const audio_uuid_t& halUuid, Uuid* uuid); diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp index 47e31c1801..6260ba1979 100644 --- a/audio/core/all-versions/default/Device.cpp +++ b/audio/core/all-versions/default/Device.cpp @@ -171,7 +171,8 @@ std::tuple> Device::openOutputStreamImpl(int32_t ioHandle streamOut = new StreamOut(this, halStream); ++mOpenedStreamsCount; } - HidlUtils::audioConfigFromHal(halConfig, suggestedConfig); + status_t convertStatus = HidlUtils::audioConfigFromHal(halConfig, suggestedConfig); + ALOGW_IF(convertStatus != OK, "%s: suggested config with incompatible fields", __func__); return {analyzeStatus("open_output_stream", status, {EINVAL} /*ignore*/), streamOut}; } @@ -198,7 +199,8 @@ std::tuple> Device::openInputStreamImpl( streamIn = new StreamIn(this, halStream); ++mOpenedStreamsCount; } - HidlUtils::audioConfigFromHal(halConfig, suggestedConfig); + status_t convertStatus = HidlUtils::audioConfigFromHal(halConfig, suggestedConfig); + ALOGW_IF(convertStatus != OK, "%s: suggested config with incompatible fields", __func__); return {analyzeStatus("open_input_stream", status, {EINVAL} /*ignore*/), streamIn}; } diff --git a/current.txt b/current.txt index e7face5d96..d4984c2c8e 100644 --- a/current.txt +++ b/current.txt @@ -613,7 +613,7 @@ fd1f1b29f26b42e886220f04a08086c00e5ade9d7b53f095438e578ab9d42a93 android.hardwar 2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn e6cd2b7c1a86b6ca683c0224ffde3b73aa14f6487de9f46833e539d26d1b3b5c android.hardware.audio@6.0::IStreamOut 997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback -167ed5cfb7d91db2e2bf20f1320c1a9004eeb768e26f535e0f7db94a21867d21 android.hardware.audio.common@6.0::types +bee662c62d997d8065e2bcb5c1e7a9578931f22ce28fd02c219fdb4d0630abf7 android.hardware.audio.common@6.0::types 817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types 525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect 8d76bbe3719d051a8e9a1dcf9244f37f5b0a491feb249fa48391edf7cb4f3131 android.hardware.audio.effect@6.0::IAutomaticGainControlEffect From 5d116126946542cd34f68b5be4b1d7bb1ac4ca90 Mon Sep 17 00:00:00 2001 From: jiabin Date: Wed, 12 Feb 2020 13:05:44 -0800 Subject: [PATCH 0638/1022] Add callback for output stream. The callback is targeted for events related to an output stream. Currently, there is one callback event defined, which is codec format changed event. Bug: 133526565 Test: manual Test: atest VtsHalAudioV6_0TargetTest Change-Id: I73a4914c1ffc30e1c88b8fedd61a031e24a069f6 --- audio/6.0/Android.bp | 1 + audio/6.0/IStreamOut.hal | 13 +++++++ audio/6.0/IStreamOutEventCallback.hal | 35 +++++++++++++++++++ audio/core/all-versions/default/StreamOut.cpp | 29 +++++++++++++++ .../default/include/core/default/StreamOut.h | 15 ++++++-- .../6.0/AudioPrimaryHidlHalTest.cpp | 18 ++++++++++ current.txt | 3 +- 7 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 audio/6.0/IStreamOutEventCallback.hal diff --git a/audio/6.0/Android.bp b/audio/6.0/Android.bp index dc6bb98a53..16abc521e2 100644 --- a/audio/6.0/Android.bp +++ b/audio/6.0/Android.bp @@ -15,6 +15,7 @@ hidl_interface { "IStreamIn.hal", "IStreamOut.hal", "IStreamOutCallback.hal", + "IStreamOutEventCallback.hal", ], interfaces: [ "android.hardware.audio.common@6.0", diff --git a/audio/6.0/IStreamOut.hal b/audio/6.0/IStreamOut.hal index 13a86ec4d3..9da48fe02f 100644 --- a/audio/6.0/IStreamOut.hal +++ b/audio/6.0/IStreamOut.hal @@ -19,6 +19,7 @@ package android.hardware.audio@6.0; import android.hardware.audio.common@6.0; import IStream; import IStreamOutCallback; +import IStreamOutEventCallback; interface IStreamOut extends IStream { /** @@ -167,6 +168,18 @@ interface IStreamOut extends IStream { */ clearCallback() generates (Result retval); + /** + * Set the callback interface for notifying about an output stream event. + * + * Calling this method with a null pointer will result in releasing + * the local callback proxy on the server side and thus dereference + * the callback implementation on the client side. + * + * @return retval operation completion status. + */ + setEventCallback(IStreamOutEventCallback callback) + generates (Result retval); + /** * Returns whether HAL supports pausing and resuming of streams. * diff --git a/audio/6.0/IStreamOutEventCallback.hal b/audio/6.0/IStreamOutEventCallback.hal new file mode 100644 index 0000000000..de17d735de --- /dev/null +++ b/audio/6.0/IStreamOutEventCallback.hal @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package android.hardware.audio@6.0; + +/** + * Asynchronous stream out event callback interface. The interface provides + * a way for the HAL to notify platform when there are changes, e.g. codec + * format change, from the lower layer. + */ +interface IStreamOutEventCallback { + /** + * Codec format changed. + * + * @param audioMetadata is a buffer containing decoded format changes + * reported by codec. The buffer contains data that can be transformed + * to audio metadata, which is a C++ object based map. See + * `system/media/audio_utils/include/audio_utils/Metadata.h` for + * more details. + */ + oneway onCodecFormatChanged(vec audioMetadata); +}; diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp index 7a4d72bd15..150d641cd0 100644 --- a/audio/core/all-versions/default/StreamOut.cpp +++ b/audio/core/all-versions/default/StreamOut.cpp @@ -22,6 +22,8 @@ //#define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_AUDIO +#include + #include #include @@ -612,6 +614,33 @@ Return StreamOut::setPlaybackRateParameters(const PlaybackRate& /*playba return Result::NOT_SUPPORTED; } +Return StreamOut::setEventCallback(const sp& callback) { + if (mStream->set_event_callback == nullptr) return Result::NOT_SUPPORTED; + int result = mStream->set_event_callback(mStream, StreamOut::asyncEventCallback, this); + if (result == 0) { + mEventCallback = callback; + } + return Stream::analyzeStatus("set_stream_out_callback", result, {ENOSYS} /*ignore*/); +} + +// static +int StreamOut::asyncEventCallback(stream_event_callback_type_t event, void* param, void* cookie) { + StreamOut* self = reinterpret_cast(cookie); + sp eventCallback = self->mEventCallback; + if (eventCallback.get() == nullptr) return 0; + ALOGV("%s event %d", __func__, event); + switch (event) { + case STREAM_EVENT_CBK_TYPE_CODEC_FORMAT_CHANGED: { + hidl_vec audioMetadata; + audioMetadata.setToExternal((uint8_t*)param, strlen((char*)param)); + eventCallback->onCodecFormatChanged(audioMetadata); + } break; + default: + ALOGW("%s unknown event %d", __func__, event); + break; + } + return 0; +} #endif } // namespace implementation diff --git a/audio/core/all-versions/default/include/core/default/StreamOut.h b/audio/core/all-versions/default/include/core/default/StreamOut.h index 5db8626909..e647da9b96 100644 --- a/audio/core/all-versions/default/include/core/default/StreamOut.h +++ b/audio/core/all-versions/default/include/core/default/StreamOut.h @@ -133,12 +133,19 @@ struct StreamOut : public IStreamOut { static Result getPresentationPositionImpl(audio_stream_out_t* stream, uint64_t* frames, TimeSpec* timeStamp); - private: +#if MAJOR_VERSION >= 6 + Return setEventCallback(const sp& callback) override; +#endif + + private: const sp mDevice; audio_stream_out_t* mStream; const sp mStreamCommon; const sp> mStreamMmap; - sp mCallback; + sp mCallback; // Callback for non-blocking write and drain +#if MAJOR_VERSION >= 6 + sp mEventCallback; +#endif std::unique_ptr mCommandMQ; std::unique_ptr mDataMQ; std::unique_ptr mStatusMQ; @@ -149,6 +156,10 @@ struct StreamOut : public IStreamOut { virtual ~StreamOut(); static int asyncCallback(stream_callback_event_t event, void* param, void* cookie); + +#if MAJOR_VERSION >= 6 + static int asyncEventCallback(stream_event_callback_type_t event, void* param, void* cookie); +#endif }; } // namespace implementation diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp index 9e2a0505f7..b40a329ee0 100644 --- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp @@ -251,3 +251,21 @@ TEST_P(PlaybackRateParametersHidlTest, PlaybackRateParametersTest) { INSTANTIATE_TEST_CASE_P(PlaybackRateParametersHidl, PlaybackRateParametersHidlTest, ::testing::ValuesIn(getOutputDeviceConfigParameters()), &DeviceConfigParameterToString); + +/** Stub implementation of IStreamOutEventCallback **/ +class MockOutEventCallbacks : public IStreamOutEventCallback { + Return onCodecFormatChanged(const hidl_vec& audioMetadata __unused) override { + return {}; + } +}; + +TEST_P(OutputStreamTest, SetEventCallback) { + doc::test("If supported, set event callback for output stream should never fail"); + auto res = stream->setEventCallback(new MockOutEventCallbacks); + EXPECT_RESULT(okOrNotSupported, res); + if (res == Result::OK) { + ASSERT_OK(stream->setEventCallback(nullptr)); + } else { + doc::partialTest("The stream does not support event callback"); + } +} diff --git a/current.txt b/current.txt index d4984c2c8e..ddf4764dba 100644 --- a/current.txt +++ b/current.txt @@ -611,8 +611,9 @@ ff5dd821c2c7a9c78607159c4d788960b725487263c49d956ca5fa3d37008b45 android.hardwar bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice fd1f1b29f26b42e886220f04a08086c00e5ade9d7b53f095438e578ab9d42a93 android.hardware.audio@6.0::IStream 2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn -e6cd2b7c1a86b6ca683c0224ffde3b73aa14f6487de9f46833e539d26d1b3b5c android.hardware.audio@6.0::IStreamOut +164826a380f4c1700183003f62d7532e367b67381c30ea44f946c0cf00008f85 android.hardware.audio@6.0::IStreamOut 997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback +e7ca0db9a1098210f327a9b152fa6afe6bf019c41e5264c64829d04d50c0a526 android.hardware.audio@6.0::IStreamOutEventCallback bee662c62d997d8065e2bcb5c1e7a9578931f22ce28fd02c219fdb4d0630abf7 android.hardware.audio.common@6.0::types 817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types 525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect From 3a7515065b9f039565b5e234d71cdae8b6ddb964 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 20 Feb 2020 10:41:47 -0800 Subject: [PATCH 0639/1022] gralloc4-vts: fix bad comparisions in VTS The parameter order of a couple checks is wrong. For example: EXPECT_GT(val1, val2) is EXPECT_TRUE(val1 > val2) so EXPECT_GT(0, X) can never be true. Update the tests to be correct. Test: VtsHalGraphicsMapperV4_0 Bug: 149739702 Change-Id: I21070a912b6014acc5feb63b6b19912b45fe8f5f --- .../vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 1416fcc239..71e6debcba 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -1990,7 +1990,7 @@ TEST_P(GraphicsMapperHidlTest, ListSupportedMetadataTypes) { const auto& metadataType = description.metadataType; if (!gralloc4::isStandardMetadataType(metadataType)) { - EXPECT_GT(0, description.description.size()); + EXPECT_GT(description.description.size(), 0); continue; } @@ -2074,7 +2074,7 @@ TEST_P(GraphicsMapperHidlTest, GetReservedRegion) { auto info = mDummyDescriptorInfo; const int pageSize = getpagesize(); - ASSERT_GE(0, pageSize); + ASSERT_GE(pageSize, 0); std::vector requestedReservedSizes{1, 10, 333, static_cast(pageSize) / 2, static_cast(pageSize)}; @@ -2106,7 +2106,7 @@ TEST_P(GraphicsMapperHidlTest, GetLargeReservedRegion) { auto info = mDummyDescriptorInfo; const int pageSize = getpagesize(); - ASSERT_GE(0, pageSize); + ASSERT_GE(pageSize, 0); std::vector requestedReservedSizes{static_cast(pageSize) * 2, static_cast(pageSize) * 10, static_cast(pageSize) * 1000}; @@ -2144,7 +2144,7 @@ TEST_P(GraphicsMapperHidlTest, GetReservedRegionMultiple) { auto info = mDummyDescriptorInfo; const int pageSize = getpagesize(); - ASSERT_GE(0, pageSize); + ASSERT_GE(pageSize, 0); info.reservedSize = pageSize; ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true)); From e2127863fb4b8e31e8c6b56f5ee85a7c2ef9a6a6 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 20 Feb 2020 11:41:39 -0800 Subject: [PATCH 0640/1022] gralloc4-vts: correctly instantiate std::optional std::optional defaults to containing std::nullopt_t. Using "->" or "." on an std::optional object that does not contain a value is undefined. Clang seems to ignore the whole line. SetSmpte2086 and SetCta861_3 both incorrectly instantiate their std::optional types. The std::optional types contain std::nullopt_t when they are passed into encode. When mapper decodes the fields, they are empty. Update std::optionals to be instantiated correctly. Bug: 149931805 Test: VtsHalGraphicsMapperV4_0 Change-Id: I046242f8261a5378228231b89b2eedec242667cb --- .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 1416fcc239..ecf08dccc7 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -278,6 +278,8 @@ class GraphicsMapperHidlTest } } + bool isEqual(float a, float b) { return abs(a - b) < 0.0001; } + std::unique_ptr mGralloc; IMapper::BufferDescriptorInfo mDummyDescriptorInfo{}; static const std::set sRequiredMetadataTypes; @@ -1455,17 +1457,17 @@ TEST_P(GraphicsMapperHidlTest, SetSmpte2086) { * red 0.680 0.320 * white (D65) 0.3127 0.3290 */ - std::optional smpte2086; - smpte2086->primaryRed.x = 0.680; - smpte2086->primaryRed.y = 0.320; - smpte2086->primaryGreen.x = 0.265; - smpte2086->primaryGreen.y = 0.690; - smpte2086->primaryBlue.x = 0.150; - smpte2086->primaryBlue.y = 0.060; - smpte2086->whitePoint.x = 0.3127; - smpte2086->whitePoint.y = 0.3290; - smpte2086->maxLuminance = 100.0; - smpte2086->minLuminance = 0.1; + Smpte2086 smpte2086; + smpte2086.primaryRed.x = 0.680; + smpte2086.primaryRed.y = 0.320; + smpte2086.primaryGreen.x = 0.265; + smpte2086.primaryGreen.y = 0.690; + smpte2086.primaryBlue.x = 0.150; + smpte2086.primaryBlue.y = 0.060; + smpte2086.whitePoint.x = 0.3127; + smpte2086.whitePoint.y = 0.3290; + smpte2086.maxLuminance = 100.0; + smpte2086.minLuminance = 0.1; hidl_vec vec; ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2086(smpte2086, &vec)); @@ -1475,16 +1477,16 @@ TEST_P(GraphicsMapperHidlTest, SetSmpte2086) { std::optional realSmpte2086; ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &realSmpte2086)); ASSERT_TRUE(realSmpte2086.has_value()); - EXPECT_EQ(smpte2086->primaryRed.x, realSmpte2086->primaryRed.x); - EXPECT_EQ(smpte2086->primaryRed.y, realSmpte2086->primaryRed.y); - EXPECT_EQ(smpte2086->primaryGreen.x, realSmpte2086->primaryGreen.x); - EXPECT_EQ(smpte2086->primaryGreen.y, realSmpte2086->primaryGreen.y); - EXPECT_EQ(smpte2086->primaryBlue.x, realSmpte2086->primaryBlue.x); - EXPECT_EQ(smpte2086->primaryBlue.y, realSmpte2086->primaryBlue.y); - EXPECT_EQ(smpte2086->whitePoint.x, realSmpte2086->whitePoint.x); - EXPECT_EQ(smpte2086->whitePoint.y, realSmpte2086->whitePoint.y); - EXPECT_EQ(smpte2086->maxLuminance, realSmpte2086->maxLuminance); - EXPECT_EQ(smpte2086->minLuminance, realSmpte2086->minLuminance); + EXPECT_TRUE(isEqual(smpte2086.primaryRed.x, realSmpte2086->primaryRed.x)); + EXPECT_TRUE(isEqual(smpte2086.primaryRed.y, realSmpte2086->primaryRed.y)); + EXPECT_TRUE(isEqual(smpte2086.primaryGreen.x, realSmpte2086->primaryGreen.x)); + EXPECT_TRUE(isEqual(smpte2086.primaryGreen.y, realSmpte2086->primaryGreen.y)); + EXPECT_TRUE(isEqual(smpte2086.primaryBlue.x, realSmpte2086->primaryBlue.x)); + EXPECT_TRUE(isEqual(smpte2086.primaryBlue.y, realSmpte2086->primaryBlue.y)); + EXPECT_TRUE(isEqual(smpte2086.whitePoint.x, realSmpte2086->whitePoint.x)); + EXPECT_TRUE(isEqual(smpte2086.whitePoint.y, realSmpte2086->whitePoint.y)); + EXPECT_TRUE(isEqual(smpte2086.maxLuminance, realSmpte2086->maxLuminance)); + EXPECT_TRUE(isEqual(smpte2086.minLuminance, realSmpte2086->minLuminance)); }); } @@ -1492,9 +1494,9 @@ TEST_P(GraphicsMapperHidlTest, SetSmpte2086) { * Test IMapper::set(Cta8613) */ TEST_P(GraphicsMapperHidlTest, SetCta861_3) { - std::optional cta861_3; - cta861_3->maxContentLightLevel = 78.0; - cta861_3->maxFrameAverageLightLevel = 62.0; + Cta861_3 cta861_3; + cta861_3.maxContentLightLevel = 78.0; + cta861_3.maxFrameAverageLightLevel = 62.0; hidl_vec vec; ASSERT_EQ(NO_ERROR, gralloc4::encodeCta861_3(cta861_3, &vec)); @@ -1504,9 +1506,10 @@ TEST_P(GraphicsMapperHidlTest, SetCta861_3) { std::optional realCta861_3; ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &realCta861_3)); ASSERT_TRUE(realCta861_3.has_value()); - EXPECT_EQ(cta861_3->maxContentLightLevel, realCta861_3->maxContentLightLevel); - EXPECT_EQ(cta861_3->maxFrameAverageLightLevel, - realCta861_3->maxFrameAverageLightLevel); + EXPECT_TRUE( + isEqual(cta861_3.maxContentLightLevel, realCta861_3->maxContentLightLevel)); + EXPECT_TRUE(isEqual(cta861_3.maxFrameAverageLightLevel, + realCta861_3->maxFrameAverageLightLevel)); }); } From e6e1b684490570a170b6dedcd861a7355b349035 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 20 Feb 2020 10:23:06 -0800 Subject: [PATCH 0641/1022] gralloc4: Add RAW PlaneLayoutComponentType RAW12 and RAW16 buffers need a PlaneLayoutComponentType. Add a RAW type so vendors don't have to add private RAW types. Test: VtsHalGraphicsMapperV4_0 Bug: 149869426 Change-Id: Idf1fa609e3a1506c3c87af22d4c548cf1218fad1 --- .../hardware/graphics/common/PlaneLayoutComponentType.aidl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl index 18c4a2e154..ce083966fe 100644 --- a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl +++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl @@ -41,6 +41,9 @@ enum PlaneLayoutComponentType { /* Blue */ B = 1 << 12, + /* Raw */ + RAW = 1 << 20, + /* Alpha */ A = 1 << 30, } From de19a7e614ed4479d5154195ccec5857a13c327e Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Tue, 25 Feb 2020 09:33:44 -0800 Subject: [PATCH 0642/1022] gralloc4-vts: don't wait on invalid sync fence Sync fences can be invalid if the buffer is already ready. If the fence is invalid, we do not need to wait. Test: VtsHalGraphicsMapperV4_0 Bug: 150213134 Change-Id: I8326d5f8b358c466ee9a686fd299daed1d4b4aa8 --- .../vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 1416fcc239..5912c3eb44 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -725,8 +725,10 @@ TEST_P(GraphicsMapperHidlTest, FlushRereadBasic) { int fence; ASSERT_NO_FATAL_FAILURE(fence = mGralloc->flushLockedBuffer(writeBufferHandle)); - ASSERT_EQ(0, sync_wait(fence, 3500)); - close(fence); + if (fence >= 0) { + ASSERT_EQ(0, sync_wait(fence, 3500)); + close(fence); + } ASSERT_NO_FATAL_FAILURE(mGralloc->rereadLockedBuffer(readBufferHandle)); From 3d6fafbf006c1b83c90ad38bd4b50640f176ef99 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 5 Feb 2020 11:22:10 -0800 Subject: [PATCH 0643/1022] Convert VtsHalRadioV1_5TargetTest to parameterized gtest Test: make cf_x86_phone-userdebug, mm Test: atest VtsHalRadioV1_5Target Bug: 148816663 Change-Id: I708cc7335f539379d4e676dc0a6541a6c98d43bb --- radio/1.5/vts/functional/Android.bp | 2 +- .../functional/VtsHalRadioV1_5TargetTest.cpp | 12 +-- .../1.5/vts/functional/radio_hidl_hal_api.cpp | 74 +++++++++---------- .../vts/functional/radio_hidl_hal_test.cpp | 20 +---- .../functional/radio_hidl_hal_utils_v1_5.h | 26 ++----- 5 files changed, 52 insertions(+), 82 deletions(-) diff --git a/radio/1.5/vts/functional/Android.bp b/radio/1.5/vts/functional/Android.bp index 85c4f99db4..cd30f7dd39 100644 --- a/radio/1.5/vts/functional/Android.bp +++ b/radio/1.5/vts/functional/Android.bp @@ -36,5 +36,5 @@ cc_test { "android.hardware.radio.config@1.1", ], header_libs: ["radio.util.header@1.0"], - test_suites: ["general-tests"] + test_suites: ["general-tests", "vts-core"] } diff --git a/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp b/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp index 5f11d19520..31466c5408 100644 --- a/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp +++ b/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp @@ -16,11 +16,7 @@ #include -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(RadioHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - RadioHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; -} +INSTANTIATE_TEST_SUITE_P(PerInstance, RadioHidlTest_v1_5, + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + android::hardware::radio::V1_5::IRadio::descriptor)), + android::hardware::PrintInstanceNameToString); diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp index 435bd23adf..003f58e7a5 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp @@ -21,7 +21,7 @@ /* * Test IRadio.setSignalStrengthReportingCriteria_1_5() with invalid hysteresisDb */ -TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_invalidHysteresisDb) { +TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_invalidHysteresisDb) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; @@ -46,7 +46,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_invalidHystere /* * Test IRadio.setSignalStrengthReportingCriteria_1_5() with empty thresholds */ -TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_EmptyThresholds) { +TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_EmptyThresholds) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; @@ -70,7 +70,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_EmptyThreshold /* * Test IRadio.setSignalStrengthReportingCriteria_1_5() for GERAN */ -TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Geran) { +TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Geran) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; @@ -95,7 +95,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Geran) { /* * Test IRadio.setSignalStrengthReportingCriteria_1_5() for UTRAN */ -TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Utran) { +TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Utran) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; @@ -120,7 +120,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Utran) { /* * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN */ -TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRP) { +TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRP) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; @@ -145,7 +145,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRP) { /* * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN */ -TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRQ) { +TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRQ) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; @@ -170,7 +170,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRQ) { /* * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN */ -TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSSNR) { +TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSSNR) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; @@ -191,7 +191,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSSNR) /* * Test IRadio.setSignalStrengthReportingCriteria_1_5() for CDMA2000 */ -TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Cdma2000) { +TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Cdma2000) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; @@ -216,7 +216,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Cdma2000) { /* * Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSRSRP */ -TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRP) { +TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRP) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; @@ -241,7 +241,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRP) /* * Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSRSRQ */ -TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRQ) { +TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRQ) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; @@ -266,7 +266,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRQ) /* * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN */ -TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Disable_RSSNR) { +TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Disable_RSSNR) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; @@ -287,7 +287,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Disable_RSSNR) /* * Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSSINR */ -TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR) { +TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo; @@ -312,7 +312,7 @@ TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR) /* * Test IRadio.setLinkCapacityReportingCriteria_1_5() invalid hysteresisDlKbps */ -TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_invalidHysteresisDlKbps) { +TEST_P(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_invalidHysteresisDlKbps) { serial = GetRandomSerialNumber(); Return res = radio_v1_5->setLinkCapacityReportingCriteria_1_5( @@ -337,7 +337,7 @@ TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_invalidHysteresi /* * Test IRadio.setLinkCapacityReportingCriteria_1_5() invalid hysteresisUlKbps */ -TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_invalidHysteresisUlKbps) { +TEST_P(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_invalidHysteresisUlKbps) { serial = GetRandomSerialNumber(); Return res = radio_v1_5->setLinkCapacityReportingCriteria_1_5( @@ -362,7 +362,7 @@ TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_invalidHysteresi /* * Test IRadio.setLinkCapacityReportingCriteria_1_5() empty params */ -TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_emptyParams) { +TEST_P(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_emptyParams) { serial = GetRandomSerialNumber(); Return res = radio_v1_5->setLinkCapacityReportingCriteria_1_5( @@ -383,7 +383,7 @@ TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_emptyParams) { /* * Test IRadio.setLinkCapacityReportingCriteria_1_5() for GERAN */ -TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_Geran) { +TEST_P(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_Geran) { serial = GetRandomSerialNumber(); Return res = radio_v1_5->setLinkCapacityReportingCriteria_1_5( @@ -406,7 +406,7 @@ TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_Geran) { * Test IRadio.enableUiccApplications() for the response returned. * For SIM ABSENT case. */ -TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsSimAbsent) { +TEST_P(RadioHidlTest_v1_5, togglingUiccApplicationsSimAbsent) { // This test case only test SIM ABSENT case. if (cardStatus.base.base.cardState != CardState::ABSENT) return; @@ -433,7 +433,7 @@ TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsSimAbsent) { * Test IRadio.enableUiccApplications() for the response returned. * For SIM PRESENT case. */ -TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsSimPresent) { +TEST_P(RadioHidlTest_v1_5, togglingUiccApplicationsSimPresent) { // This test case only test SIM ABSENT case. if (cardStatus.base.base.cardState != CardState::PRESENT) return; @@ -479,7 +479,7 @@ TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsSimPresent) { /* * Test IRadio.areUiccApplicationsEnabled() for the response returned. */ -TEST_F(RadioHidlTest_v1_5, areUiccApplicationsEnabled) { +TEST_P(RadioHidlTest_v1_5, areUiccApplicationsEnabled) { // Disable Uicc applications. serial = GetRandomSerialNumber(); radio_v1_5->areUiccApplicationsEnabled(serial); @@ -499,7 +499,7 @@ TEST_F(RadioHidlTest_v1_5, areUiccApplicationsEnabled) { /* * Test IRadio.setSystemSelectionChannels_1_5() for the response returned. */ -TEST_F(RadioHidlTest_v1_5, setSystemSelectionChannels_1_5) { +TEST_P(RadioHidlTest_v1_5, setSystemSelectionChannels_1_5) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; @@ -537,7 +537,7 @@ TEST_F(RadioHidlTest_v1_5, setSystemSelectionChannels_1_5) { /* * Test IRadio.startNetworkScan_1_5() for the response returned. */ -TEST_F(RadioHidlTest_v1_5, startNetworkScan) { +TEST_P(RadioHidlTest_v1_5, startNetworkScan) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; @@ -578,7 +578,7 @@ TEST_F(RadioHidlTest_v1_5, startNetworkScan) { /* * Test IRadio.startNetworkScan_1_5() with invalid specifier. */ -TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidArgument) { +TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidArgument) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::NetworkScanRequest request = {.type = ScanType::ONE_SHOT, @@ -605,7 +605,7 @@ TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidArgument) { /* * Test IRadio.startNetworkScan_1_5() with invalid interval (lower boundary). */ -TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidInterval1) { +TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidInterval1) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; @@ -644,7 +644,7 @@ TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidInterval1) { /* * Test IRadio.startNetworkScan_1_5() with invalid interval (upper boundary). */ -TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidInterval2) { +TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidInterval2) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; @@ -683,7 +683,7 @@ TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidInterval2) { /* * Test IRadio.startNetworkScan_1_5() with invalid max search time (lower boundary). */ -TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidMaxSearchTime1) { +TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidMaxSearchTime1) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; @@ -722,7 +722,7 @@ TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidMaxSearchTime1) { /* * Test IRadio.startNetworkScan_1_5() with invalid max search time (upper boundary). */ -TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidMaxSearchTime2) { +TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidMaxSearchTime2) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; @@ -761,7 +761,7 @@ TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidMaxSearchTime2) { /* * Test IRadio.startNetworkScan_1_5() with invalid periodicity (lower boundary). */ -TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidPeriodicity1) { +TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidPeriodicity1) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; @@ -800,7 +800,7 @@ TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidPeriodicity1) { /* * Test IRadio.startNetworkScan_1_5() with invalid periodicity (upper boundary). */ -TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidPeriodicity2) { +TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidPeriodicity2) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; @@ -839,7 +839,7 @@ TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidPeriodicity2) { /* * Test IRadio.startNetworkScan_1_5() with valid periodicity */ -TEST_F(RadioHidlTest_v1_5, startNetworkScan_GoodRequest1) { +TEST_P(RadioHidlTest_v1_5, startNetworkScan_GoodRequest1) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; @@ -878,7 +878,7 @@ TEST_F(RadioHidlTest_v1_5, startNetworkScan_GoodRequest1) { /* * Test IRadio.startNetworkScan_1_5() with valid periodicity and plmns */ -TEST_F(RadioHidlTest_v1_5, startNetworkScan_GoodRequest2) { +TEST_P(RadioHidlTest_v1_5, startNetworkScan_GoodRequest2) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands; @@ -918,7 +918,7 @@ TEST_F(RadioHidlTest_v1_5, startNetworkScan_GoodRequest2) { /* * Test IRadio.setupDataCall_1_5() for the response returned. */ -TEST_F(RadioHidlTest_v1_5, setupDataCall_1_5) { +TEST_P(RadioHidlTest_v1_5, setupDataCall_1_5) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_5::AccessNetwork accessNetwork = @@ -975,7 +975,7 @@ TEST_F(RadioHidlTest_v1_5, setupDataCall_1_5) { /* * Test IRadio.setInitialAttachApn_1_5() for the response returned. */ -TEST_F(RadioHidlTest_v1_5, setInitialAttachApn_1_5) { +TEST_P(RadioHidlTest_v1_5, setInitialAttachApn_1_5) { serial = GetRandomSerialNumber(); // Create a dataProfileInfo @@ -1018,7 +1018,7 @@ TEST_F(RadioHidlTest_v1_5, setInitialAttachApn_1_5) { /* * Test IRadio.setDataProfile_1_5() for the response returned. */ -TEST_F(RadioHidlTest_v1_5, setDataProfile_1_5) { +TEST_P(RadioHidlTest_v1_5, setDataProfile_1_5) { serial = GetRandomSerialNumber(); // Create a dataProfileInfo @@ -1065,7 +1065,7 @@ TEST_F(RadioHidlTest_v1_5, setDataProfile_1_5) { /* * Test IRadio.setRadioPower_1_5() for the response returned. */ -TEST_F(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancelled) { +TEST_P(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancelled) { // Set radio power to off. serial = GetRandomSerialNumber(); radio_v1_5->setRadioPower_1_5(serial, false, false, false); @@ -1096,7 +1096,7 @@ TEST_F(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancelled) { /* * Test IRadio.setNetworkSelectionModeManual_1_5() for the response returned. */ -TEST_F(RadioHidlTest_v1_5, setNetworkSelectionModeManual_1_5) { +TEST_P(RadioHidlTest_v1_5, setNetworkSelectionModeManual_1_5) { serial = GetRandomSerialNumber(); // can't camp on nonexistent MCCMNC, so we expect this to fail. @@ -1122,7 +1122,7 @@ TEST_F(RadioHidlTest_v1_5, setNetworkSelectionModeManual_1_5) { /* * Test IRadio.sendCdmaSmsExpectMore() for the response returned. */ -TEST_F(RadioHidlTest_v1_5, sendCdmaSmsExpectMore) { +TEST_P(RadioHidlTest_v1_5, sendCdmaSmsExpectMore) { serial = GetRandomSerialNumber(); // Create a CdmaSmsAddress @@ -1166,7 +1166,7 @@ TEST_F(RadioHidlTest_v1_5, sendCdmaSmsExpectMore) { /* * Test IRadio.getBarringInfo() for the response returned. */ -TEST_F(RadioHidlTest_v1_5, getBarringInfo) { +TEST_P(RadioHidlTest_v1_5, getBarringInfo) { serial = GetRandomSerialNumber(); Return res = radio_v1_5->getBarringInfo(serial); diff --git a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp index a5d236d47f..ca6bbeb6b7 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp @@ -17,19 +17,7 @@ #include void RadioHidlTest_v1_5::SetUp() { - radio_v1_5 = ::testing::VtsHalHidlTargetTestBase::getService< - ::android::hardware::radio::V1_5::IRadio>( - RadioHidlEnvironment::Instance() - ->getServiceName<::android::hardware::radio::V1_5::IRadio>( - hidl_string(RADIO_SERVICE_NAME))); - if (radio_v1_5 == NULL) { - sleep(60); - radio_v1_5 = ::testing::VtsHalHidlTargetTestBase::getService< - ::android::hardware::radio::V1_5::IRadio>( - RadioHidlEnvironment::Instance() - ->getServiceName<::android::hardware::radio::V1_5::IRadio>( - hidl_string(RADIO_SERVICE_NAME))); - } + radio_v1_5 = android::hardware::radio::V1_5::IRadio::getService(GetParam()); ASSERT_NE(nullptr, radio_v1_5.get()); radioRsp_v1_5 = new (std::nothrow) RadioResponse_v1_5(*this); @@ -48,10 +36,8 @@ void RadioHidlTest_v1_5::SetUp() { EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); sp<::android::hardware::radio::config::V1_1::IRadioConfig> radioConfig = - ::testing::VtsHalHidlTargetTestBase::getService< - ::android::hardware::radio::config::V1_1::IRadioConfig>(); - - /* Enforce Vts tesing with RadioConfig is existed. */ + ::android::hardware::radio::config::V1_1::IRadioConfig::getService(); + /* Enforce Vts testing with RadioConfig is existed. */ ASSERT_NE(nullptr, radioConfig.get()); /* Enforce Vts Testing with Sim Status Present only. */ diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index a7c1cdc12f..6488609f49 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -14,10 +14,14 @@ * limitations under the License. */ +#pragma once + #include -#include -#include +#include +#include +#include +#include #include #include #include @@ -799,24 +803,8 @@ class RadioIndication_v1_5 : public ::android::hardware::radio::V1_5::IRadioIndi /*barringInfos*/); }; -// Test environment for Radio HIDL HAL. -class RadioHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static RadioHidlEnvironment* Instance() { - static RadioHidlEnvironment* instance = new RadioHidlEnvironment; - return instance; - } - virtual void registerTestServices() override { - registerTestService<::android::hardware::radio::V1_5::IRadio>(); - } - - private: - RadioHidlEnvironment() {} -}; - // The main test class for Radio HIDL. -class RadioHidlTest_v1_5 : public ::testing::VtsHalHidlTargetTestBase { +class RadioHidlTest_v1_5 : public ::testing::TestWithParam { protected: std::mutex mtx_; std::condition_variable cv_; From 9c1d0adb3f2a1832d0b46bc9808a6cc8a28e2f7e Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 17 Jan 2020 11:39:37 -0800 Subject: [PATCH 0644/1022] composer: vts: check that refresh rate stays the same on inactivity Bug: 147890947 Test: adb shell data/nativetest64/VtsHalGraphicsComposerV2_4TargetTest/VtsHalGraphicsComposerV2_4TargetTest Change-Id: I9e1bc1325701ca1603251cc499712f11aa86d30e --- .../VtsHalGraphicsComposerV2_4TargetTest.cpp | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index b6343d335a..7a00ed23ac 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -279,23 +279,48 @@ TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod_BadDisplay) { mComposerClient->getDisplayVsyncPeriod(mInvalidDisplayId, &vsyncPeriodNanos)); } -TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod) { +TEST_P(GraphicsComposerHidlCommandTest, getDisplayVsyncPeriod) { for (Display display : mComposerCallback->getDisplays()) { for (Config config : mComposerClient->getDisplayConfigs(display)) { VsyncPeriodNanos expectedVsyncPeriodNanos = mComposerClient->getDisplayAttribute_2_4( display, config, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD); - mComposerClient->setActiveConfig(display, config); + VsyncPeriodChangeTimeline timeline; + IComposerClient::VsyncPeriodChangeConstraints constraints; + + constraints.desiredTimeNanos = systemTime(); + constraints.seamlessRequired = false; + EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigWithConstraints( + display, config, constraints, &timeline)); + + if (timeline.refreshRequired) { + sendRefreshFrame(timeline); + } + waitForVsyncPeriodChange(display, timeline, constraints.desiredTimeNanos, 0, + expectedVsyncPeriodNanos); + VsyncPeriodNanos vsyncPeriodNanos; int retryCount = 100; do { std::this_thread::sleep_for(10ms); + vsyncPeriodNanos = 0; EXPECT_EQ(Error::NONE, mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); --retryCount; } while (vsyncPeriodNanos != expectedVsyncPeriodNanos && retryCount > 0); EXPECT_EQ(vsyncPeriodNanos, expectedVsyncPeriodNanos); + + // Make sure that the vsync period stays the same if the active config is not changed. + auto timeout = 1ms; + for (int i = 0; i < 10; i++) { + std::this_thread::sleep_for(timeout); + timeout *= 2; + vsyncPeriodNanos = 0; + EXPECT_EQ(Error::NONE, + mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); + EXPECT_EQ(vsyncPeriodNanos, expectedVsyncPeriodNanos); + } } } } From 85c4ad2351eb34fd7feba60f3aaa2d8ca77cdeec Mon Sep 17 00:00:00 2001 From: Arthur Ishiguro Date: Tue, 25 Feb 2020 07:53:46 -0800 Subject: [PATCH 0645/1022] Starts default Context Hub HAL in context_hub group Also adds group to default sensors HAL. Bug: 149981913 Test: Compile Change-Id: Ib9178dd9ad0a92821cfebe82f09e8819b42a42f7 --- .../1.0/default/android.hardware.contexthub@1.0-service.rc | 4 ++-- .../1.1/default/android.hardware.contexthub@1.1-service.rc | 4 ++-- sensors/1.0/default/android.hardware.sensors@1.0-service.rc | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc b/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc index b659be8098..fc2893f071 100644 --- a/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc +++ b/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc @@ -1,5 +1,5 @@ service vendor.contexthub-hal-1-0 /vendor/bin/hw/android.hardware.contexthub@1.0-service interface android.hardware.contexthub@1.0::IContexthub default class hal - user system - group system + user context_hub + group context_hub diff --git a/contexthub/1.1/default/android.hardware.contexthub@1.1-service.rc b/contexthub/1.1/default/android.hardware.contexthub@1.1-service.rc index 9db00f9bf0..b00b1bd142 100644 --- a/contexthub/1.1/default/android.hardware.contexthub@1.1-service.rc +++ b/contexthub/1.1/default/android.hardware.contexthub@1.1-service.rc @@ -2,5 +2,5 @@ service vendor.contexthub-hal-1-1-mock /vendor/bin/hw/android.hardware.contexthu interface android.hardware.contexthub@1.0::IContexthub default interface android.hardware.contexthub@1.1::IContexthub default class hal - user system - group system + user context_hub + group context_hub diff --git a/sensors/1.0/default/android.hardware.sensors@1.0-service.rc b/sensors/1.0/default/android.hardware.sensors@1.0-service.rc index b41730b942..1af6d0b08c 100644 --- a/sensors/1.0/default/android.hardware.sensors@1.0-service.rc +++ b/sensors/1.0/default/android.hardware.sensors@1.0-service.rc @@ -2,6 +2,6 @@ service vendor.sensors-hal-1-0 /vendor/bin/hw/android.hardware.sensors@1.0-servi interface android.hardware.sensors@1.0::ISensors default class hal user system - group system wakelock uhid + group system wakelock uhid context_hub capabilities BLOCK_SUSPEND rlimit rtprio 10 10 From 23f890c47470aebe906bb022475b0a43419ff27d Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Mon, 16 Dec 2019 16:09:53 -0800 Subject: [PATCH 0646/1022] Move libboot_control to boot_control 1.1 It should belong to the default /misc implementation of boot control 1.1. Right now, the library as well as the bootloader_message_ab are only used by cuttlefish. So move it over to reduce the confusion in libbootloader_message. Bug: 131775112 Test: build Change-Id: I599678bf90d19718de811b9e34d82cf8fe1571a4 (cherry picked from commit c971ea8d5d1ddc672da497de5ce21f835446cfdb) --- boot/1.1/default/boot_control/Android.bp | 61 +++ .../include/libboot_control/libboot_control.h | 89 ++++ .../include/private/boot_control_definition.h | 111 +++++ .../boot_control/legacy_boot_control.cpp | 115 +++++ .../default/boot_control/libboot_control.cpp | 425 ++++++++++++++++++ 5 files changed, 801 insertions(+) create mode 100644 boot/1.1/default/boot_control/Android.bp create mode 100644 boot/1.1/default/boot_control/include/libboot_control/libboot_control.h create mode 100644 boot/1.1/default/boot_control/include/private/boot_control_definition.h create mode 100644 boot/1.1/default/boot_control/legacy_boot_control.cpp create mode 100644 boot/1.1/default/boot_control/libboot_control.cpp diff --git a/boot/1.1/default/boot_control/Android.bp b/boot/1.1/default/boot_control/Android.bp new file mode 100644 index 0000000000..b2e68dfd41 --- /dev/null +++ b/boot/1.1/default/boot_control/Android.bp @@ -0,0 +1,61 @@ +// +// Copyright (C) 2018 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. +// + +cc_defaults { + name: "libboot_control_defaults", + vendor: true, + recovery_available: true, + relative_install_path: "hw", + + cflags: [ + "-D_FILE_OFFSET_BITS=64", + "-Werror", + "-Wall", + "-Wextra", + ], + + shared_libs: [ + "android.hardware.boot@1.1", + "libbase", + "liblog", + ], + static_libs: [ + "libbootloader_message_vendor", + "libfstab", + ], +} + +cc_library_static { + name: "libboot_control", + defaults: ["libboot_control_defaults"], + export_include_dirs: ["include"], + + srcs: ["libboot_control.cpp"], +} + +cc_library_shared { + name: "bootctrl.default", + defaults: ["libboot_control_defaults"], + + srcs: ["legacy_boot_control.cpp"], + + static_libs: [ + "libboot_control", + ], + shared_libs: [ + "libhardware", + ], +} diff --git a/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h b/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h new file mode 100644 index 0000000000..546865887f --- /dev/null +++ b/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h @@ -0,0 +1,89 @@ +// +// 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. +// + +#pragma once + +#include + +#include + +namespace android { +namespace bootable { + +// Helper library to implement the IBootControl HAL using the misc partition. +class BootControl { + using MergeStatus = ::android::hardware::boot::V1_1::MergeStatus; + + public: + bool Init(); + unsigned int GetNumberSlots(); + unsigned int GetCurrentSlot(); + bool MarkBootSuccessful(); + bool SetActiveBootSlot(unsigned int slot); + bool SetSlotAsUnbootable(unsigned int slot); + bool SetSlotBootable(unsigned int slot); + bool IsSlotBootable(unsigned int slot); + const char* GetSuffix(unsigned int slot); + bool IsSlotMarkedSuccessful(unsigned int slot); + bool SetSnapshotMergeStatus(MergeStatus status); + MergeStatus GetSnapshotMergeStatus(); + + bool IsValidSlot(unsigned int slot); + + const std::string& misc_device() const { + return misc_device_; + } + + private: + // Whether this object was initialized with data from the bootloader message + // that doesn't change until next reboot. + bool initialized_ = false; + + // The path to the misc_device as reported in the fstab. + std::string misc_device_; + + // The number of slots present on the device. + unsigned int num_slots_ = 0; + + // The slot where we are running from. + unsigned int current_slot_ = 0; +}; + +// Helper functions to write the Virtual A/B merge status message. These are +// separate because BootControl uses bootloader_control_ab in vendor space, +// whereas the Virtual A/B merge status is in system space. A HAL might not +// use bootloader_control_ab, but may want to use the AOSP method of maintaining +// the merge status. + +// If the Virtual A/B message has not yet been initialized, then initialize it. +// This should be called when the BootControl HAL first loads. +// +// If the Virtual A/B message in misc was already initialized, true is returned. +// If initialization was attempted, but failed, false is returned, and the HAL +// should fail to load. +bool InitMiscVirtualAbMessageIfNeeded(); + +// Save the current merge status as well as the current slot. +bool SetMiscVirtualAbMergeStatus(unsigned int current_slot, + android::hardware::boot::V1_1::MergeStatus status); + +// Return the current merge status. If the saved status is SNAPSHOTTED but the +// slot hasn't changed, the status returned will be NONE. +bool GetMiscVirtualAbMergeStatus(unsigned int current_slot, + android::hardware::boot::V1_1::MergeStatus* status); + +} // namespace bootable +} // namespace android diff --git a/boot/1.1/default/boot_control/include/private/boot_control_definition.h b/boot/1.1/default/boot_control/include/private/boot_control_definition.h new file mode 100644 index 0000000000..8f021117ee --- /dev/null +++ b/boot/1.1/default/boot_control/include/private/boot_control_definition.h @@ -0,0 +1,111 @@ +/* + * 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. + */ + + +/** + * The A/B-specific bootloader message structure (4-KiB). + * + * We separate A/B boot control metadata from the regular bootloader + * message struct and keep it here. Everything that's A/B-specific + * stays after struct bootloader_message, which belongs to the vendor + * space of /misc partition. Also, the A/B-specific contents should be + * managed by the A/B-bootloader or boot control HAL. + * + * The slot_suffix field is used for A/B implementations where the + * bootloader does not set the androidboot.ro.boot.slot_suffix kernel + * commandline parameter. This is used by fs_mgr to mount /system and + * other partitions with the slotselect flag set in fstab. A/B + * implementations are free to use all 32 bytes and may store private + * data past the first NUL-byte in this field. It is encouraged, but + * not mandatory, to use 'struct bootloader_control' described below. + * + * The update_channel field is used to store the Omaha update channel + * if update_engine is compiled with Omaha support. + */ +struct bootloader_message_ab { + struct bootloader_message message; + char slot_suffix[32]; + char update_channel[128]; + + // Round up the entire struct to 4096-byte. + char reserved[1888]; +}; + +/** + * Be cautious about the struct size change, in case we put anything post + * bootloader_message_ab struct (b/29159185). + */ +#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus) +static_assert(sizeof(struct bootloader_message_ab) == 4096, + "struct bootloader_message_ab size changes"); +#endif + +#define BOOT_CTRL_MAGIC 0x42414342 /* Bootloader Control AB */ +#define BOOT_CTRL_VERSION 1 + +struct slot_metadata { + // Slot priority with 15 meaning highest priority, 1 lowest + // priority and 0 the slot is unbootable. + uint8_t priority : 4; + // Number of times left attempting to boot this slot. + uint8_t tries_remaining : 3; + // 1 if this slot has booted successfully, 0 otherwise. + uint8_t successful_boot : 1; + // 1 if this slot is corrupted from a dm-verity corruption, 0 + // otherwise. + uint8_t verity_corrupted : 1; + // Reserved for further use. + uint8_t reserved : 7; +} __attribute__((packed)); + +/* Bootloader Control AB + * + * This struct can be used to manage A/B metadata. It is designed to + * be put in the 'slot_suffix' field of the 'bootloader_message' + * structure described above. It is encouraged to use the + * 'bootloader_control' structure to store the A/B metadata, but not + * mandatory. + */ +struct bootloader_control { + // NUL terminated active slot suffix. + char slot_suffix[4]; + // Bootloader Control AB magic number (see BOOT_CTRL_MAGIC). + uint32_t magic; + // Version of struct being used (see BOOT_CTRL_VERSION). + uint8_t version; + // Number of slots being managed. + uint8_t nb_slot : 3; + // Number of times left attempting to boot recovery. + uint8_t recovery_tries_remaining : 3; + // Status of any pending snapshot merge of dynamic partitions. + uint8_t merge_status : 3; + // Ensure 4-bytes alignment for slot_info field. + uint8_t reserved0[1]; + // Per-slot information. Up to 4 slots. + struct slot_metadata slot_info[4]; + // Reserved for further use. + uint8_t reserved1[8]; + // CRC32 of all 28 bytes preceding this field (little endian + // format). + uint32_t crc32_le; +} __attribute__((packed)); + +#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus) +static_assert(sizeof(struct bootloader_control) == + sizeof(((struct bootloader_message_ab *)0)->slot_suffix), + "struct bootloader_control has wrong size"); +#endif + diff --git a/boot/1.1/default/boot_control/legacy_boot_control.cpp b/boot/1.1/default/boot_control/legacy_boot_control.cpp new file mode 100644 index 0000000000..73d3a58418 --- /dev/null +++ b/boot/1.1/default/boot_control/legacy_boot_control.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2015 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 +#include + +#include + +using android::bootable::BootControl; + +struct boot_control_private_t { + // The base struct needs to be first in the list. + boot_control_module_t base; + + BootControl impl; +}; + +namespace { + +void BootControl_init(boot_control_module_t* module) { + auto& impl = reinterpret_cast(module)->impl; + impl.Init(); +} + +unsigned int BootControl_getNumberSlots(boot_control_module_t* module) { + auto& impl = reinterpret_cast(module)->impl; + return impl.GetNumberSlots(); +} + +unsigned int BootControl_getCurrentSlot(boot_control_module_t* module) { + auto& impl = reinterpret_cast(module)->impl; + return impl.GetCurrentSlot(); +} + +int BootControl_markBootSuccessful(boot_control_module_t* module) { + auto& impl = reinterpret_cast(module)->impl; + return impl.MarkBootSuccessful() ? 0 : -1; +} + +int BootControl_setActiveBootSlot(boot_control_module_t* module, unsigned int slot) { + auto& impl = reinterpret_cast(module)->impl; + return impl.SetActiveBootSlot(slot) ? 0 : -1; +} + +int BootControl_setSlotAsUnbootable(struct boot_control_module* module, unsigned int slot) { + auto& impl = reinterpret_cast(module)->impl; + return impl.SetSlotAsUnbootable(slot) ? 0 : -1; +} + +int BootControl_isSlotBootable(struct boot_control_module* module, unsigned int slot) { + auto& impl = reinterpret_cast(module)->impl; + return impl.IsSlotBootable(slot) ? 0 : -1; +} + +int BootControl_isSlotMarkedSuccessful(struct boot_control_module* module, unsigned int slot) { + auto& impl = reinterpret_cast(module)->impl; + return impl.IsSlotMarkedSuccessful(slot) ? 0 : -1; +} + +const char* BootControl_getSuffix(boot_control_module_t* module, unsigned int slot) { + auto& impl = reinterpret_cast(module)->impl; + return impl.GetSuffix(slot); +} + +static int BootControl_open(const hw_module_t* module __unused, const char* id __unused, + hw_device_t** device __unused) { + /* Nothing to do currently. */ + return 0; +} + +struct hw_module_methods_t BootControl_methods = { + .open = BootControl_open, +}; + +} // namespace + +boot_control_private_t HAL_MODULE_INFO_SYM = { + .base = + { + .common = + { + .tag = HARDWARE_MODULE_TAG, + .module_api_version = BOOT_CONTROL_MODULE_API_VERSION_0_1, + .hal_api_version = HARDWARE_HAL_API_VERSION, + .id = BOOT_CONTROL_HARDWARE_MODULE_ID, + .name = "AOSP reference bootctrl HAL", + .author = "The Android Open Source Project", + .methods = &BootControl_methods, + }, + .init = BootControl_init, + .getNumberSlots = BootControl_getNumberSlots, + .getCurrentSlot = BootControl_getCurrentSlot, + .markBootSuccessful = BootControl_markBootSuccessful, + .setActiveBootSlot = BootControl_setActiveBootSlot, + .setSlotAsUnbootable = BootControl_setSlotAsUnbootable, + .isSlotBootable = BootControl_isSlotBootable, + .getSuffix = BootControl_getSuffix, + .isSlotMarkedSuccessful = BootControl_isSlotMarkedSuccessful, + }, +}; diff --git a/boot/1.1/default/boot_control/libboot_control.cpp b/boot/1.1/default/boot_control/libboot_control.cpp new file mode 100644 index 0000000000..2c6ccafd7d --- /dev/null +++ b/boot/1.1/default/boot_control/libboot_control.cpp @@ -0,0 +1,425 @@ +/* + * Copyright (C) 2015 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 +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "private/boot_control_definition.h" + +namespace android { +namespace bootable { + +using ::android::hardware::boot::V1_1::MergeStatus; + +// The number of boot attempts that should be made from a new slot before +// rolling back to the previous slot. +constexpr unsigned int kDefaultBootAttempts = 7; +static_assert(kDefaultBootAttempts < 8, "tries_remaining field only has 3 bits"); + +constexpr unsigned int kMaxNumSlots = + sizeof(bootloader_control::slot_info) / sizeof(bootloader_control::slot_info[0]); +constexpr const char* kSlotSuffixes[kMaxNumSlots] = { "_a", "_b", "_c", "_d" }; +constexpr off_t kBootloaderControlOffset = offsetof(bootloader_message_ab, slot_suffix); + +static uint32_t CRC32(const uint8_t* buf, size_t size) { + static uint32_t crc_table[256]; + + // Compute the CRC-32 table only once. + if (!crc_table[1]) { + for (uint32_t i = 0; i < 256; ++i) { + uint32_t crc = i; + for (uint32_t j = 0; j < 8; ++j) { + uint32_t mask = -(crc & 1); + crc = (crc >> 1) ^ (0xEDB88320 & mask); + } + crc_table[i] = crc; + } + } + + uint32_t ret = -1; + for (size_t i = 0; i < size; ++i) { + ret = (ret >> 8) ^ crc_table[(ret ^ buf[i]) & 0xFF]; + } + + return ~ret; +} + +// Return the little-endian representation of the CRC-32 of the first fields +// in |boot_ctrl| up to the crc32_le field. +uint32_t BootloaderControlLECRC(const bootloader_control* boot_ctrl) { + return htole32( + CRC32(reinterpret_cast(boot_ctrl), offsetof(bootloader_control, crc32_le))); +} + +bool LoadBootloaderControl(const std::string& misc_device, bootloader_control* buffer) { + android::base::unique_fd fd(open(misc_device.c_str(), O_RDONLY)); + if (fd.get() == -1) { + PLOG(ERROR) << "failed to open " << misc_device; + return false; + } + if (lseek(fd, kBootloaderControlOffset, SEEK_SET) != kBootloaderControlOffset) { + PLOG(ERROR) << "failed to lseek " << misc_device; + return false; + } + if (!android::base::ReadFully(fd.get(), buffer, sizeof(bootloader_control))) { + PLOG(ERROR) << "failed to read " << misc_device; + return false; + } + return true; +} + +bool UpdateAndSaveBootloaderControl(const std::string& misc_device, bootloader_control* buffer) { + buffer->crc32_le = BootloaderControlLECRC(buffer); + android::base::unique_fd fd(open(misc_device.c_str(), O_WRONLY | O_SYNC)); + if (fd.get() == -1) { + PLOG(ERROR) << "failed to open " << misc_device; + return false; + } + if (lseek(fd.get(), kBootloaderControlOffset, SEEK_SET) != kBootloaderControlOffset) { + PLOG(ERROR) << "failed to lseek " << misc_device; + return false; + } + if (!android::base::WriteFully(fd.get(), buffer, sizeof(bootloader_control))) { + PLOG(ERROR) << "failed to write " << misc_device; + return false; + } + return true; +} + +void InitDefaultBootloaderControl(BootControl* control, bootloader_control* boot_ctrl) { + memset(boot_ctrl, 0, sizeof(*boot_ctrl)); + + unsigned int current_slot = control->GetCurrentSlot(); + if (current_slot < kMaxNumSlots) { + strlcpy(boot_ctrl->slot_suffix, kSlotSuffixes[current_slot], sizeof(boot_ctrl->slot_suffix)); + } + boot_ctrl->magic = BOOT_CTRL_MAGIC; + boot_ctrl->version = BOOT_CTRL_VERSION; + + // Figure out the number of slots by checking if the partitions exist, + // otherwise assume the maximum supported by the header. + boot_ctrl->nb_slot = kMaxNumSlots; + std::string base_path = control->misc_device(); + size_t last_path_sep = base_path.rfind('/'); + if (last_path_sep != std::string::npos) { + // We test the existence of the "boot" partition on each possible slot, + // which is a partition required by Android Bootloader Requirements. + base_path = base_path.substr(0, last_path_sep + 1) + "boot"; + int last_existing_slot = -1; + int first_missing_slot = -1; + for (unsigned int slot = 0; slot < kMaxNumSlots; ++slot) { + std::string partition_path = base_path + kSlotSuffixes[slot]; + struct stat part_stat; + int err = stat(partition_path.c_str(), &part_stat); + if (!err) { + last_existing_slot = slot; + LOG(INFO) << "Found slot: " << kSlotSuffixes[slot]; + } else if (err < 0 && errno == ENOENT && first_missing_slot == -1) { + first_missing_slot = slot; + } + } + // We only declare that we found the actual number of slots if we found all + // the boot partitions up to the number of slots, and no boot partition + // after that. Not finding any of the boot partitions implies a problem so + // we just leave the number of slots in the maximum value. + if ((last_existing_slot != -1 && last_existing_slot + 1 == first_missing_slot) || + (first_missing_slot == -1 && last_existing_slot + 1 == kMaxNumSlots)) { + boot_ctrl->nb_slot = last_existing_slot + 1; + LOG(INFO) << "Found a system with " << last_existing_slot + 1 << " slots."; + } + } + + for (unsigned int slot = 0; slot < kMaxNumSlots; ++slot) { + slot_metadata entry = {}; + + if (slot < boot_ctrl->nb_slot) { + entry.priority = 7; + entry.tries_remaining = kDefaultBootAttempts; + entry.successful_boot = 0; + } else { + entry.priority = 0; // Unbootable + } + + // When the boot_control stored on disk is invalid, we assume that the + // current slot is successful. The bootloader should repair this situation + // before booting and write a valid boot_control slot, so if we reach this + // stage it means that the misc partition was corrupted since boot. + if (current_slot == slot) { + entry.successful_boot = 1; + } + + boot_ctrl->slot_info[slot] = entry; + } + boot_ctrl->recovery_tries_remaining = 0; + + boot_ctrl->crc32_le = BootloaderControlLECRC(boot_ctrl); +} + +// Return the index of the slot suffix passed or -1 if not a valid slot suffix. +int SlotSuffixToIndex(const char* suffix) { + for (unsigned int slot = 0; slot < kMaxNumSlots; ++slot) { + if (!strcmp(kSlotSuffixes[slot], suffix)) return slot; + } + return -1; +} + +// Initialize the boot_control_private struct with the information from +// the bootloader_message buffer stored in |boot_ctrl|. Returns whether the +// initialization succeeded. +bool BootControl::Init() { + if (initialized_) return true; + + // Initialize the current_slot from the read-only property. If the property + // was not set (from either the command line or the device tree), we can later + // initialize it from the bootloader_control struct. + std::string suffix_prop = android::base::GetProperty("ro.boot.slot_suffix", ""); + if (suffix_prop.empty()) { + LOG(ERROR) << "Slot suffix property is not set"; + return false; + } + current_slot_ = SlotSuffixToIndex(suffix_prop.c_str()); + + std::string err; + std::string device = get_bootloader_message_blk_device(&err); + if (device.empty()) { + LOG(ERROR) << "Could not find bootloader message block device: " << err; + return false; + } + + bootloader_control boot_ctrl; + if (!LoadBootloaderControl(device.c_str(), &boot_ctrl)) { + LOG(ERROR) << "Failed to load bootloader control block"; + return false; + } + + // Note that since there isn't a module unload function this memory is leaked. + // We use `device` below sometimes, so it's not moved out of here. + misc_device_ = device; + initialized_ = true; + + // Validate the loaded data, otherwise we will destroy it and re-initialize it + // with the current information. + uint32_t computed_crc32 = BootloaderControlLECRC(&boot_ctrl); + if (boot_ctrl.crc32_le != computed_crc32) { + LOG(WARNING) << "Invalid boot control found, expected CRC-32 0x" << std::hex << computed_crc32 + << " but found 0x" << std::hex << boot_ctrl.crc32_le << ". Re-initializing."; + InitDefaultBootloaderControl(this, &boot_ctrl); + UpdateAndSaveBootloaderControl(device.c_str(), &boot_ctrl); + } + + if (!InitMiscVirtualAbMessageIfNeeded()) { + return false; + } + + num_slots_ = boot_ctrl.nb_slot; + return true; +} + +unsigned int BootControl::GetNumberSlots() { + return num_slots_; +} + +unsigned int BootControl::GetCurrentSlot() { + return current_slot_; +} + +bool BootControl::MarkBootSuccessful() { + bootloader_control bootctrl; + if (!LoadBootloaderControl(misc_device_, &bootctrl)) return false; + + bootctrl.slot_info[current_slot_].successful_boot = 1; + // tries_remaining == 0 means that the slot is not bootable anymore, make + // sure we mark the current slot as bootable if it succeeds in the last + // attempt. + bootctrl.slot_info[current_slot_].tries_remaining = 1; + return UpdateAndSaveBootloaderControl(misc_device_, &bootctrl); +} + +bool BootControl::SetActiveBootSlot(unsigned int slot) { + if (slot >= kMaxNumSlots || slot >= num_slots_) { + // Invalid slot number. + return false; + } + + bootloader_control bootctrl; + if (!LoadBootloaderControl(misc_device_, &bootctrl)) return false; + + // Set every other slot with a lower priority than the new "active" slot. + const unsigned int kActivePriority = 15; + const unsigned int kActiveTries = 6; + for (unsigned int i = 0; i < num_slots_; ++i) { + if (i != slot) { + if (bootctrl.slot_info[i].priority >= kActivePriority) + bootctrl.slot_info[i].priority = kActivePriority - 1; + } + } + + // Note that setting a slot as active doesn't change the successful bit. + // The successful bit will only be changed by setSlotAsUnbootable(). + bootctrl.slot_info[slot].priority = kActivePriority; + bootctrl.slot_info[slot].tries_remaining = kActiveTries; + + // Setting the current slot as active is a way to revert the operation that + // set *another* slot as active at the end of an updater. This is commonly + // used to cancel the pending update. We should only reset the verity_corrpted + // bit when attempting a new slot, otherwise the verity bit on the current + // slot would be flip. + if (slot != current_slot_) bootctrl.slot_info[slot].verity_corrupted = 0; + + return UpdateAndSaveBootloaderControl(misc_device_, &bootctrl); +} + +bool BootControl::SetSlotAsUnbootable(unsigned int slot) { + if (slot >= kMaxNumSlots || slot >= num_slots_) { + // Invalid slot number. + return false; + } + + bootloader_control bootctrl; + if (!LoadBootloaderControl(misc_device_, &bootctrl)) return false; + + // The only way to mark a slot as unbootable, regardless of the priority is to + // set the tries_remaining to 0. + bootctrl.slot_info[slot].successful_boot = 0; + bootctrl.slot_info[slot].tries_remaining = 0; + return UpdateAndSaveBootloaderControl(misc_device_, &bootctrl); +} + +bool BootControl::IsSlotBootable(unsigned int slot) { + if (slot >= kMaxNumSlots || slot >= num_slots_) { + // Invalid slot number. + return false; + } + + bootloader_control bootctrl; + if (!LoadBootloaderControl(misc_device_, &bootctrl)) return false; + + return bootctrl.slot_info[slot].tries_remaining != 0; +} + +bool BootControl::IsSlotMarkedSuccessful(unsigned int slot) { + if (slot >= kMaxNumSlots || slot >= num_slots_) { + // Invalid slot number. + return false; + } + + bootloader_control bootctrl; + if (!LoadBootloaderControl(misc_device_, &bootctrl)) return false; + + return bootctrl.slot_info[slot].successful_boot && bootctrl.slot_info[slot].tries_remaining; +} + +bool BootControl::IsValidSlot(unsigned int slot) { + return slot < kMaxNumSlots && slot < num_slots_; +} + +bool BootControl::SetSnapshotMergeStatus(MergeStatus status) { + return SetMiscVirtualAbMergeStatus(current_slot_, status); +} + +MergeStatus BootControl::GetSnapshotMergeStatus() { + MergeStatus status; + if (!GetMiscVirtualAbMergeStatus(current_slot_, &status)) { + return MergeStatus::UNKNOWN; + } + return status; +} + +const char* BootControl::GetSuffix(unsigned int slot) { + if (slot >= kMaxNumSlots || slot >= num_slots_) { + return nullptr; + } + return kSlotSuffixes[slot]; +} + +bool InitMiscVirtualAbMessageIfNeeded() { + std::string err; + misc_virtual_ab_message message; + if (!ReadMiscVirtualAbMessage(&message, &err)) { + LOG(ERROR) << "Could not read merge status: " << err; + return false; + } + + if (message.version == MISC_VIRTUAL_AB_MESSAGE_VERSION && + message.magic == MISC_VIRTUAL_AB_MAGIC_HEADER) { + // Already initialized. + return true; + } + + message = {}; + message.version = MISC_VIRTUAL_AB_MESSAGE_VERSION; + message.magic = MISC_VIRTUAL_AB_MAGIC_HEADER; + if (!WriteMiscVirtualAbMessage(message, &err)) { + LOG(ERROR) << "Could not write merge status: " << err; + return false; + } + return true; +} + +bool SetMiscVirtualAbMergeStatus(unsigned int current_slot, + android::hardware::boot::V1_1::MergeStatus status) { + std::string err; + misc_virtual_ab_message message; + + if (!ReadMiscVirtualAbMessage(&message, &err)) { + LOG(ERROR) << "Could not read merge status: " << err; + return false; + } + + message.merge_status = static_cast(status); + message.source_slot = current_slot; + if (!WriteMiscVirtualAbMessage(message, &err)) { + LOG(ERROR) << "Could not write merge status: " << err; + return false; + } + return true; +} + +bool GetMiscVirtualAbMergeStatus(unsigned int current_slot, + android::hardware::boot::V1_1::MergeStatus* status) { + std::string err; + misc_virtual_ab_message message; + + if (!ReadMiscVirtualAbMessage(&message, &err)) { + LOG(ERROR) << "Could not read merge status: " << err; + return false; + } + + // If the slot reverted after having created a snapshot, then the snapshot will + // be thrown away at boot. Thus we don't count this as being in a snapshotted + // state. + *status = static_cast(message.merge_status); + if (*status == MergeStatus::SNAPSHOTTED && current_slot == message.source_slot) { + *status = MergeStatus::NONE; + } + return true; +} + +} // namespace bootable +} // namespace android From 34dfa2f74cf79ce66afd08b681bb2bb3a136c5d9 Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Tue, 25 Feb 2020 15:54:08 -0800 Subject: [PATCH 0647/1022] Add more tests exercising IPreparedModel::executeFenced API - executeFenced with device memory - executeFenced with depending sync fences Bug: 148979873 Test: mm Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: I772c5c85f75cee56e2af06470c2de5b810f8078d --- .../vts/functional/GeneratedTestHarness.cpp | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 8c9393b030..3e2be8a346 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -626,21 +626,28 @@ void EvaluatePreparedModel(const sp& device, const sp& ErrorStatus result; hidl_handle syncFenceHandle; sp fencedCallback; - Return ret = preparedModel->executeFenced( - request, {}, testConfig.measureTiming, {}, loopTimeoutDuration, {}, - [&result, &syncFenceHandle, &fencedCallback]( - ErrorStatus error, const hidl_handle& handle, - const sp& callback) { - result = error; - syncFenceHandle = handle; - fencedCallback = callback; - }); + auto callbackFunc = [&result, &syncFenceHandle, &fencedCallback]( + ErrorStatus error, const hidl_handle& handle, + const sp& callback) { + result = error; + syncFenceHandle = handle; + fencedCallback = callback; + }; + Return ret = + preparedModel->executeFenced(request, {}, testConfig.measureTiming, {}, + loopTimeoutDuration, {}, callbackFunc); ASSERT_TRUE(ret.isOk()); if (result != ErrorStatus::NONE) { ASSERT_EQ(syncFenceHandle.getNativeHandle(), nullptr); ASSERT_EQ(fencedCallback, nullptr); executionStatus = ErrorStatus::GENERAL_FAILURE; } else if (syncFenceHandle.getNativeHandle()) { + // If a sync fence is returned, try start another run waiting for the sync fence. + ret = preparedModel->executeFenced(request, {syncFenceHandle}, + testConfig.measureTiming, {}, + loopTimeoutDuration, {}, callbackFunc); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(result, ErrorStatus::NONE); waitForSyncFence(syncFenceHandle.getNativeHandle()->data[0]); } if (result == ErrorStatus::NONE) { @@ -744,7 +751,7 @@ void EvaluatePreparedModel(const sp& device, const sp& case TestKind::MEMORY_DOMAIN: { outputTypesList = {OutputType::FULLY_SPECIFIED}; measureTimingList = {MeasureTiming::NO}; - executorList = {Executor::ASYNC, Executor::SYNC}; + executorList = {Executor::ASYNC, Executor::SYNC, Executor::FENCED}; memoryType = MemoryType::DEVICE; } break; case TestKind::FENCED_COMPUTE: { From 6ae828b6f041c7882a1a984451f4b2be549492db Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Tue, 25 Feb 2020 11:45:59 -0800 Subject: [PATCH 0648/1022] ICameraProvider@2.6: Add documentation about resource cost constraints for concurrent camera combinations. - Also clarify requirements for MONOCHROME devices supporting Y8 outputs. Bug: 150225538 Test: builds (doc change only) Change-Id: I992f1bcee4bf266b6e66ddb32ece8291381c8e56 Signed-off-by: Jayant Chowdhary --- camera/provider/2.6/ICameraProvider.hal | 15 +++++++++++++++ current.txt | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/camera/provider/2.6/ICameraProvider.hal b/camera/provider/2.6/ICameraProvider.hal index 9c46ba06f5..5651550e2d 100644 --- a/camera/provider/2.6/ICameraProvider.hal +++ b/camera/provider/2.6/ICameraProvider.hal @@ -56,11 +56,26 @@ interface ICameraProvider extends @2.5::ICameraProvider { * s720p - min (max output resolution for the given format, 1280 X 720) * s1440p - min (max output resolution for the given format, 1920 X 1440) * + * If a device has MONOCHROME capability (device's capabilities include + * ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) and therefore supports Y8 + * outputs, stream combinations mentioned above, where YUV is substituted by + * Y8 must be also supported. + * * 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 * of camera ids that can stream concurrently, that might have potentially appeared. * + * For each combination (and their subsets) of camera device ids returned by + * getConcurrentStreamingCameraIds(): If only the mandatory combinations can + * be supported concurrently by each device, then the resource costs must + * sum up to > 100 for the concurrent set, to ensure arbitration between + * camera applications work as expected. Only if resources are sufficient + * to run a set of cameras at full capability (maximally + * resource-consuming framerate and stream size settings available in the + * configuration settings exposed through camera metadata), should the sum + * of resource costs for the combination be <= 100. + * * @return status Status code for the operation * @return cameraIds a list of camera id combinations that support * concurrent stream configurations with the minimum guarantees diff --git a/current.txt b/current.txt index 8e2016de2e..5cc7e850a8 100644 --- a/current.txt +++ b/current.txt @@ -639,7 +639,7 @@ ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardwar 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types b8c63679e1a3874b356f3e691aecce1191d38f59063cf2ed2dce8a9d4cabf00e android.hardware.camera.device@3.6::ICameraDevice -daad72a2f482d8a1f660d0e99ac1b78fedb414a4cfbe3fa56b2cd480e5d6f0cb android.hardware.camera.provider@2.6::ICameraProvider +99aae72ae75a8ddf63ccffbc585f3a55f4d0847b4adff3d7a0f8bd9e2305bec1 android.hardware.camera.provider@2.6::ICameraProvider 8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback a35d5151b48505f06a775b38c0e2e265f80a845d92802324c643565807f81c53 android.hardware.camera.device@3.6::types c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas From f154585376be55d9f30740beec377de995dbe91e Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Wed, 26 Feb 2020 15:20:26 -0800 Subject: [PATCH 0649/1022] Convert CAN bus HAL VTS to parametrized gtest Test: VTS Bug: 150312861 Change-Id: Ib106a5d075d3189a57306f2b7283293e448a147d --- .../functional/VtsHalCanBusV1_0TargetTest.cpp | 62 +++++++--------- .../VtsHalCanBusVirtualV1_0TargetTest.cpp | 74 ++++++++----------- .../VtsHalCanControllerV1_0TargetTest.cpp | 56 ++++++-------- .../include/can-vts-utils/environment-utils.h | 60 --------------- 4 files changed, 76 insertions(+), 176 deletions(-) delete mode 100644 automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp index cdea8b6eec..a8e7c0b633 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp @@ -14,22 +14,20 @@ * limitations under the License. */ -#include #include #include #include #include #include -#include #include #include +#include +#include namespace android::hardware::automotive::can::V1_0::vts { using hardware::hidl_vec; -static utils::SimpleHidlEnvironment* gEnv = nullptr; - struct CanMessageListener : public can::V1_0::ICanMessageListener { virtual Return onReceive(const can::V1_0::CanMessage&) override { return {}; } }; @@ -38,7 +36,7 @@ struct CanErrorListener : public can::V1_0::ICanErrorListener { virtual Return onError(ErrorEvent, bool) override { return {}; } }; -class CanBusHalTest : public ::testing::VtsHalHidlTargetTestBase { +class CanBusHalTest : public ::testing::TestWithParam { protected: virtual void SetUp() override; virtual void TearDown() override; @@ -51,9 +49,8 @@ class CanBusHalTest : public ::testing::VtsHalHidlTargetTestBase { }; void CanBusHalTest::SetUp() { - const auto serviceName = gEnv->getServiceName(); - mCanBus = getService(serviceName); - ASSERT_TRUE(mCanBus) << "Couldn't open CAN Bus: " << serviceName; + mCanBus = ICanBus::getService(GetParam()); + ASSERT_TRUE(mCanBus) << "Couldn't open CAN Bus: " << GetParam(); } void CanBusHalTest::TearDown() { @@ -75,7 +72,7 @@ sp CanBusHalTest::listenForErrors(const sp& lis return res; } -TEST_F(CanBusHalTest, SendNoPayload) { +TEST_P(CanBusHalTest, SendNoPayload) { CanMessage msg = {}; msg.id = 0x123; ASSERT_NE(mCanBus, nullptr); @@ -83,7 +80,7 @@ TEST_F(CanBusHalTest, SendNoPayload) { ASSERT_EQ(Result::OK, result); } -TEST_F(CanBusHalTest, Send8B) { +TEST_P(CanBusHalTest, Send8B) { CanMessage msg = {}; msg.id = 0x234; msg.payload = {1, 2, 3, 4, 5, 6, 7, 8}; @@ -92,7 +89,7 @@ TEST_F(CanBusHalTest, Send8B) { ASSERT_EQ(Result::OK, result); } -TEST_F(CanBusHalTest, SendZeroId) { +TEST_P(CanBusHalTest, SendZeroId) { CanMessage msg = {}; msg.payload = {1, 2, 3}; @@ -100,7 +97,7 @@ TEST_F(CanBusHalTest, SendZeroId) { ASSERT_EQ(Result::OK, result); } -TEST_F(CanBusHalTest, SendTooLong) { +TEST_P(CanBusHalTest, SendTooLong) { CanMessage msg = {}; msg.id = 0x123; msg.payload = hidl_vec(102400); // 100kiB @@ -109,14 +106,14 @@ TEST_F(CanBusHalTest, SendTooLong) { ASSERT_EQ(Result::PAYLOAD_TOO_LONG, result); } -TEST_F(CanBusHalTest, ListenNoFilter) { +TEST_P(CanBusHalTest, ListenNoFilter) { const auto [result, closeHandle] = listen({}, new CanMessageListener()); ASSERT_EQ(Result::OK, result); closeHandle->close().assertOk(); } -TEST_F(CanBusHalTest, ListenSomeFilter) { +TEST_P(CanBusHalTest, ListenSomeFilter) { hidl_vec filters = { {0x123, 0x1FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false}, {0x001, 0x00F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true}, @@ -129,12 +126,12 @@ TEST_F(CanBusHalTest, ListenSomeFilter) { closeHandle->close().assertOk(); } -TEST_F(CanBusHalTest, ListenNull) { +TEST_P(CanBusHalTest, ListenNull) { const auto [result, closeHandle] = listen({}, nullptr); ASSERT_EQ(Result::INVALID_ARGUMENTS, result); } -TEST_F(CanBusHalTest, DoubleCloseListener) { +TEST_P(CanBusHalTest, DoubleCloseListener) { const auto [result, closeHandle] = listen({}, new CanMessageListener()); ASSERT_EQ(Result::OK, result); @@ -142,12 +139,12 @@ TEST_F(CanBusHalTest, DoubleCloseListener) { closeHandle->close().assertOk(); } -TEST_F(CanBusHalTest, DontCloseListener) { +TEST_P(CanBusHalTest, DontCloseListener) { const auto [result, closeHandle] = listen({}, new CanMessageListener()); ASSERT_EQ(Result::OK, result); } -TEST_F(CanBusHalTest, DoubleCloseErrorListener) { +TEST_P(CanBusHalTest, DoubleCloseErrorListener) { auto closeHandle = listenForErrors(new CanErrorListener()); ASSERT_NE(nullptr, closeHandle.get()); @@ -155,7 +152,7 @@ TEST_F(CanBusHalTest, DoubleCloseErrorListener) { closeHandle->close().assertOk(); } -TEST_F(CanBusHalTest, DoubleCloseNullErrorListener) { +TEST_P(CanBusHalTest, DoubleCloseNullErrorListener) { auto closeHandle = listenForErrors(nullptr); ASSERT_NE(nullptr, closeHandle.get()); @@ -163,13 +160,11 @@ TEST_F(CanBusHalTest, DoubleCloseNullErrorListener) { closeHandle->close().assertOk(); } -TEST_F(CanBusHalTest, DontCloseErrorListener) { +TEST_P(CanBusHalTest, DontCloseErrorListener) { auto closeHandle = listenForErrors(new CanErrorListener()); ASSERT_NE(nullptr, closeHandle.get()); } -} // namespace android::hardware::automotive::can::V1_0::vts - /** * This test requires that you bring up a valid bus first. * @@ -177,19 +172,12 @@ TEST_F(CanBusHalTest, DontCloseErrorListener) { * mma -j && adb root && adb remount && adb sync * * Example manual invocation: - * adb shell /data/nativetest64/VtsHalCanBusV1_0TargetTest/VtsHalCanBusV1_0TargetTest \ - * --hal_service_instance=android.hardware.automotive.can@1.0::ICanBus/ + * adb shell canhalctrl up socketcan can0 125000 + * adb shell /data/nativetest64/VtsHalCanBusV1_0TargetTest/VtsHalCanBusV1_0TargetTest\ + * --gtest_filter=*_ */ -int main(int argc, char** argv) { - using android::hardware::automotive::can::V1_0::ICanBus; - using android::hardware::automotive::can::V1_0::vts::gEnv; - using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment; - setenv("TREBLE_TESTING_OVERRIDE", "true", true); - android::base::SetDefaultTag("CanBusVts"); - android::base::SetMinimumLogSeverity(android::base::VERBOSE); - gEnv = new SimpleHidlEnvironment; - ::testing::AddGlobalTestEnvironment(gEnv); - ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - return RUN_ALL_TESTS(); -} +INSTANTIATE_TEST_SUITE_P( // + PerInstance, CanBusHalTest, testing::ValuesIn(getAllHalInstanceNames(ICanBus::descriptor)), + PrintInstanceNameToString); + +} // namespace android::hardware::automotive::can::V1_0::vts diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp index 68d555dd20..9039435458 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include #include @@ -23,9 +22,11 @@ #include #include #include -#include #include +#include #include +#include +#include #include #include @@ -39,8 +40,6 @@ using namespace std::chrono_literals; using hardware::hidl_vec; using InterfaceType = ICanController::InterfaceType; -static utils::SimpleHidlEnvironment* gEnv = nullptr; - struct CanMessageListener : public can::V1_0::ICanMessageListener { DISALLOW_COPY_AND_ASSIGN(CanMessageListener); @@ -133,12 +132,11 @@ struct Bus { sp mBus; }; -class CanBusVirtualHalTest : public ::testing::VtsHalHidlTargetTestBase { +class CanBusVirtualHalTest : public ::testing::TestWithParam { protected: virtual void SetUp() override; - + virtual void TearDown() override; static void SetUpTestCase(); - static void TearDownTestCase(); Bus makeBus(); @@ -147,13 +145,10 @@ class CanBusVirtualHalTest : public ::testing::VtsHalHidlTargetTestBase { private: unsigned mLastIface = 0; - static sp mCanController; - static bool mVirtualSupported; + sp mCanController = nullptr; static bool mTestCaseInitialized; }; -sp CanBusVirtualHalTest::mCanController = nullptr; -bool CanBusVirtualHalTest::mVirtualSupported; hidl_vec CanBusVirtualHalTest::mBusNames; bool CanBusVirtualHalTest::mTestCaseInitialized = false; @@ -170,29 +165,27 @@ static void clearTimestamps(std::vector& messages) { } void CanBusVirtualHalTest::SetUp() { - if (!mVirtualSupported) GTEST_SKIP(); ASSERT_TRUE(mTestCaseInitialized); -} -void CanBusVirtualHalTest::SetUpTestCase() { - const auto serviceName = gEnv->getServiceName(); - mCanController = getService(serviceName); - ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << serviceName; + mCanController = ICanController::getService(GetParam()); + ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << GetParam(); hidl_vec supported; mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).assertOk(); - mVirtualSupported = supported.contains(InterfaceType::VIRTUAL); + if (!supported.contains(InterfaceType::VIRTUAL)) GTEST_SKIP(); +} +void CanBusVirtualHalTest::TearDown() { + mCanController.clear(); +} + +void CanBusVirtualHalTest::SetUpTestCase() { mBusNames = utils::getBusNames(); ASSERT_NE(0u, mBusNames.size()) << "No ICanBus HALs defined in device manifest"; mTestCaseInitialized = true; } -void CanBusVirtualHalTest::TearDownTestCase() { - mCanController.clear(); -} - Bus CanBusVirtualHalTest::makeBus() { const auto idx = mLastIface++; EXPECT_LT(idx, mBusNames.size()); @@ -204,7 +197,7 @@ Bus CanBusVirtualHalTest::makeBus() { return Bus(mCanController, config); } -TEST_F(CanBusVirtualHalTest, Send) { +TEST_P(CanBusVirtualHalTest, Send) { auto bus = makeBus(); CanMessage msg = {}; @@ -214,7 +207,7 @@ TEST_F(CanBusVirtualHalTest, Send) { bus.send(msg); } -TEST_F(CanBusVirtualHalTest, SendAfterClose) { +TEST_P(CanBusVirtualHalTest, SendAfterClose) { auto bus = makeBus(); auto zombie = bus.get(); bus.reset(); @@ -223,7 +216,7 @@ TEST_F(CanBusVirtualHalTest, SendAfterClose) { ASSERT_EQ(Result::INTERFACE_DOWN, result); } -TEST_F(CanBusVirtualHalTest, SendAndRecv) { +TEST_P(CanBusVirtualHalTest, SendAndRecv) { if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses."; auto bus1 = makeBus(); auto bus2 = makeBus(); @@ -243,7 +236,7 @@ TEST_F(CanBusVirtualHalTest, SendAndRecv) { ASSERT_EQ(msg, messages[0]); } -TEST_F(CanBusVirtualHalTest, DownOneOfTwo) { +TEST_P(CanBusVirtualHalTest, DownOneOfTwo) { if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses."; auto bus1 = makeBus(); @@ -254,7 +247,7 @@ TEST_F(CanBusVirtualHalTest, DownOneOfTwo) { bus1.send({}); } -TEST_F(CanBusVirtualHalTest, FilterPositive) { +TEST_P(CanBusVirtualHalTest, FilterPositive) { if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses."; auto bus1 = makeBus(); auto bus2 = makeBus(); @@ -418,7 +411,7 @@ TEST_F(CanBusVirtualHalTest, FilterPositive) { ASSERT_EQ(expectedPositive, messagesPositive); } -TEST_F(CanBusVirtualHalTest, FilterNegative) { +TEST_P(CanBusVirtualHalTest, FilterNegative) { if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses."; auto bus1 = makeBus(); auto bus2 = makeBus(); @@ -612,7 +605,7 @@ TEST_F(CanBusVirtualHalTest, FilterNegative) { ASSERT_EQ(expectedNegative, messagesNegative); } -TEST_F(CanBusVirtualHalTest, FilterMixed) { +TEST_P(CanBusVirtualHalTest, FilterMixed) { if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses."; auto bus1 = makeBus(); auto bus2 = makeBus(); @@ -871,22 +864,13 @@ TEST_F(CanBusVirtualHalTest, FilterMixed) { ASSERT_EQ(expectedMixed, messagesMixed); } -} // namespace android::hardware::automotive::can::V1_0::vts - /** * Example manual invocation: - * adb shell /data/nativetest64/VtsHalCanBusVirtualV1_0TargetTest/VtsHalCanBusVirtualV1_0TargetTest\ - * --hal_service_instance=android.hardware.automotive.can@1.0::ICanController/socketcan + * adb shell /data/nativetest64/VtsHalCanBusVirtualV1_0TargetTest/VtsHalCanBusVirtualV1_0TargetTest */ -int main(int argc, char** argv) { - using android::hardware::automotive::can::V1_0::ICanController; - using android::hardware::automotive::can::V1_0::vts::gEnv; - using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment; - android::base::SetDefaultTag("CanBusVirtualVts"); - android::base::SetMinimumLogSeverity(android::base::VERBOSE); - gEnv = new SimpleHidlEnvironment; - ::testing::AddGlobalTestEnvironment(gEnv); - ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - return RUN_ALL_TESTS(); -} +INSTANTIATE_TEST_SUITE_P( // + PerInstance, CanBusVirtualHalTest, + testing::ValuesIn(getAllHalInstanceNames(ICanController::descriptor)), + PrintInstanceNameToString); + +} // namespace android::hardware::automotive::can::V1_0::vts diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp index 83972153c2..8ef57589cd 100644 --- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp +++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include #include @@ -23,9 +22,10 @@ #include #include #include -#include #include #include +#include +#include namespace android::hardware::automotive::can::V1_0::vts { @@ -33,9 +33,7 @@ using hardware::hidl_vec; using InterfaceType = ICanController::InterfaceType; using IfId = ICanController::BusConfig::InterfaceId; -static utils::SimpleHidlEnvironment* gEnv = nullptr; - -class CanControllerHalTest : public ::testing::VtsHalHidlTargetTestBase { +class CanControllerHalTest : public ::testing::TestWithParam { protected: virtual void SetUp() override; virtual void TearDown() override; @@ -61,9 +59,8 @@ bool CanControllerHalTest::mTestCaseInitialized = false; void CanControllerHalTest::SetUp() { ASSERT_TRUE(mTestCaseInitialized); - const auto serviceName = gEnv->getServiceName(); - mCanController = getService(serviceName); - ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << serviceName; + mCanController = ICanController::getService(GetParam()); + ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << GetParam(); } void CanControllerHalTest::TearDown() { @@ -130,12 +127,12 @@ void CanControllerHalTest::assertRegistered(std::string srvname, bool expectRegi << " (should be otherwise)"; } -TEST_F(CanControllerHalTest, SupportsSomething) { +TEST_P(CanControllerHalTest, SupportsSomething) { const auto supported = getSupportedInterfaceTypes(); ASSERT_GT(supported.size(), 0u); } -TEST_F(CanControllerHalTest, BringUpDown) { +TEST_P(CanControllerHalTest, BringUpDown) { const std::string name = mBusNames[0]; assertRegistered(name, false); @@ -148,12 +145,12 @@ TEST_F(CanControllerHalTest, BringUpDown) { assertRegistered(name, false); } -TEST_F(CanControllerHalTest, DownDummy) { +TEST_P(CanControllerHalTest, DownDummy) { const auto result = mCanController->downInterface("imnotup"); ASSERT_FALSE(result); } -TEST_F(CanControllerHalTest, UpTwice) { +TEST_P(CanControllerHalTest, UpTwice) { const std::string name = mBusNames[0]; assertRegistered(name, false); @@ -169,7 +166,7 @@ TEST_F(CanControllerHalTest, UpTwice) { assertRegistered(name, false); } -TEST_F(CanControllerHalTest, ConfigCompatibility) { +TEST_P(CanControllerHalTest, ConfigCompatibility) { // using random-ish addresses, which may not be valid - we can't test the success case // TODO(b/146214370): move interfaceId constructors to a library IfId virtualCfg = {}; @@ -231,7 +228,7 @@ TEST_F(CanControllerHalTest, ConfigCompatibility) { } } -TEST_F(CanControllerHalTest, FailEmptyName) { +TEST_P(CanControllerHalTest, FailEmptyName) { const std::string name = ""; assertRegistered(name, false); @@ -241,7 +238,7 @@ TEST_F(CanControllerHalTest, FailEmptyName) { assertRegistered(name, false); } -TEST_F(CanControllerHalTest, FailBadName) { +TEST_P(CanControllerHalTest, FailBadName) { // 33 characters (name can be at most 32 characters long) const std::string name = "ab012345678901234567890123456789c"; @@ -252,7 +249,7 @@ TEST_F(CanControllerHalTest, FailBadName) { assertRegistered(name, false); } -TEST_F(CanControllerHalTest, FailBadVirtualAddress) { +TEST_P(CanControllerHalTest, FailBadVirtualAddress) { const std::string name = mBusNames[0]; assertRegistered(name, false); @@ -262,7 +259,7 @@ TEST_F(CanControllerHalTest, FailBadVirtualAddress) { assertRegistered(name, false); } -TEST_F(CanControllerHalTest, FailBadSocketcanAddress) { +TEST_P(CanControllerHalTest, FailBadSocketcanAddress) { const std::string name = mBusNames[0]; assertRegistered(name, false); @@ -277,7 +274,7 @@ TEST_F(CanControllerHalTest, FailBadSocketcanAddress) { assertRegistered(name, false); } -TEST_F(CanControllerHalTest, FailBadSlcanAddress) { +TEST_P(CanControllerHalTest, FailBadSlcanAddress) { const std::string name = mBusNames[0]; assertRegistered(name, false); @@ -292,22 +289,13 @@ TEST_F(CanControllerHalTest, FailBadSlcanAddress) { assertRegistered(name, false); } -} // namespace android::hardware::automotive::can::V1_0::vts - /** * Example manual invocation: - * adb shell /data/nativetest64/VtsHalCanControllerV1_0TargetTest/VtsHalCanControllerV1_0TargetTest\ - * --hal_service_instance=android.hardware.automotive.can@1.0::ICanController/socketcan + * adb shell /data/nativetest64/VtsHalCanControllerV1_0TargetTest/VtsHalCanControllerV1_0TargetTest */ -int main(int argc, char** argv) { - using android::hardware::automotive::can::V1_0::ICanController; - using android::hardware::automotive::can::V1_0::vts::gEnv; - using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment; - android::base::SetDefaultTag("CanControllerVts"); - android::base::SetMinimumLogSeverity(android::base::VERBOSE); - gEnv = new SimpleHidlEnvironment; - ::testing::AddGlobalTestEnvironment(gEnv); - ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - return RUN_ALL_TESTS(); -} +INSTANTIATE_TEST_SUITE_P( // + PerInstance, CanControllerHalTest, + testing::ValuesIn(getAllHalInstanceNames(ICanController::descriptor)), + PrintInstanceNameToString); + +} // namespace android::hardware::automotive::can::V1_0::vts diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h deleted file mode 100644 index 3eb9cc1b83..0000000000 --- a/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace android::hardware::automotive::can::V1_0::vts::utils { - -/** - * Simple test environment. - * - * This is a helper class to instantiate a test environment without boilerplate code for cases where - * there is no need to pass more parameters than just HIDL service instance name. - * - * The class implements registerTestServices() by calling registerTestService() on every HIDL - * interface provided as parameter to this template. - * - * Example usage: - * static utils::SimpleHidlEnvironment* gEnv = nullptr; - * - * void CanBusHalTest::SetUp() { - * const auto serviceName = gEnv->getServiceName(); - * (...) - * } - * - * int main(int argc, char** argv) { - * gEnv = new SimpleHidlEnvironment; - * ::testing::AddGlobalTestEnvironment(gEnv); - * ::testing::InitGoogleTest(&argc, argv); - * gEnv->init(&argc, argv); - * return RUN_ALL_TESTS(); - * } - * - * \param T... HIDL interface names to register for a test service - */ -template -class SimpleHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - virtual void registerTestServices() override { - // Call registerTestService() for every HIDL interface using this template. - using expander = int[]; - (void)expander{0, (registerTestService(), 0)...}; - } -}; - -} // namespace android::hardware::automotive::can::V1_0::vts::utils From 36aa827f70fa4634740e67b40ea58abd27c29441 Mon Sep 17 00:00:00 2001 From: Emilian Peev Date: Wed, 26 Feb 2020 16:31:47 -0800 Subject: [PATCH 0650/1022] Camera: Avoid adding uninitialized hal requests The offline requests deque is constructed with specific amount of entries. Initialize the the already allocated entries before pushing new ones. Bug: 149346795 Test: Camera CTS Change-Id: I6db8d48949caf753429702b60c48698c95ecf4ad --- .../3.6/default/ExternalCameraDeviceSession.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp index 60a1a1019c..8fd8e5897b 100644 --- a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp +++ b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp @@ -272,16 +272,17 @@ Status ExternalCameraDeviceSession::switchToOffline(const hidl_vec& off // convert hal requests to offline request std::deque> offlineReqs(halReqs.size()); + size_t i = 0; for (auto& v4lReq : halReqs) { - std::shared_ptr halReq = std::make_shared(); - halReq->frameNumber = v4lReq->frameNumber; - halReq->setting = v4lReq->setting; - halReq->shutterTs = v4lReq->shutterTs; - halReq->buffers = v4lReq->buffers; + offlineReqs[i] = std::make_shared(); + offlineReqs[i]->frameNumber = v4lReq->frameNumber; + offlineReqs[i]->setting = v4lReq->setting; + offlineReqs[i]->shutterTs = v4lReq->shutterTs; + offlineReqs[i]->buffers = v4lReq->buffers; sp v4l2Frame = static_cast(v4lReq->frameIn.get()); - halReq->frameIn = new AllocatedV4L2Frame(v4l2Frame); - offlineReqs.push_back(halReq); + offlineReqs[i]->frameIn = new AllocatedV4L2Frame(v4l2Frame); + i++; // enqueue V4L2 frame enqueueV4l2Frame(v4l2Frame); } From 0c217577e32b5dc6b42bfce4bdbd890e496460fa Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 24 Feb 2020 17:39:51 -0800 Subject: [PATCH 0651/1022] Remove String8(StaticLinkage) references. These are a legacy holdover from when libutils String8 couldn't be used at static time. Bug: 150325737 # fixing GSI breakage Test: N/A Change-Id: I009b2ca53631509072b4085f3f53c0b94e71b13e (cherry picked from commit 15f04b8af90ade954c45aab571fa4b625a43b872) Merged-In: I009b2ca53631509072b4085f3f53c0b94e71b13e --- health/2.0/default/HealthImplDefault.cpp | 12 ------------ health/utils/libhealthloop/utils.cpp | 15 --------------- 2 files changed, 27 deletions(-) diff --git a/health/2.0/default/HealthImplDefault.cpp b/health/2.0/default/HealthImplDefault.cpp index e3cbefdbeb..08fee9ea71 100644 --- a/health/2.0/default/HealthImplDefault.cpp +++ b/health/2.0/default/HealthImplDefault.cpp @@ -21,18 +21,6 @@ using android::hardware::health::V2_0::IHealth; using android::hardware::health::V2_0::implementation::Health; static struct healthd_config gHealthdConfig = { - .batteryStatusPath = android::String8(android::String8::kEmptyString), - .batteryHealthPath = android::String8(android::String8::kEmptyString), - .batteryPresentPath = android::String8(android::String8::kEmptyString), - .batteryCapacityPath = android::String8(android::String8::kEmptyString), - .batteryVoltagePath = android::String8(android::String8::kEmptyString), - .batteryTemperaturePath = android::String8(android::String8::kEmptyString), - .batteryTechnologyPath = android::String8(android::String8::kEmptyString), - .batteryCurrentNowPath = android::String8(android::String8::kEmptyString), - .batteryCurrentAvgPath = android::String8(android::String8::kEmptyString), - .batteryChargeCounterPath = android::String8(android::String8::kEmptyString), - .batteryFullChargePath = android::String8(android::String8::kEmptyString), - .batteryCycleCountPath = android::String8(android::String8::kEmptyString), .energyCounter = nullptr, .boot_min_cap = 0, .screen_on = nullptr}; diff --git a/health/utils/libhealthloop/utils.cpp b/health/utils/libhealthloop/utils.cpp index 053fd19fe2..cd8c7a9ce4 100644 --- a/health/utils/libhealthloop/utils.cpp +++ b/health/utils/libhealthloop/utils.cpp @@ -28,21 +28,6 @@ void InitHealthdConfig(struct healthd_config* healthd_config) { *healthd_config = { .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST, .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW, - .batteryStatusPath = String8(String8::kEmptyString), - .batteryHealthPath = String8(String8::kEmptyString), - .batteryPresentPath = String8(String8::kEmptyString), - .batteryCapacityPath = String8(String8::kEmptyString), - .batteryVoltagePath = String8(String8::kEmptyString), - .batteryTemperaturePath = String8(String8::kEmptyString), - .batteryTechnologyPath = String8(String8::kEmptyString), - .batteryCurrentNowPath = String8(String8::kEmptyString), - .batteryCurrentAvgPath = String8(String8::kEmptyString), - .batteryChargeCounterPath = String8(String8::kEmptyString), - .batteryFullChargePath = String8(String8::kEmptyString), - .batteryCycleCountPath = String8(String8::kEmptyString), - .batteryCapacityLevelPath = String8(String8::kEmptyString), - .batteryChargeTimeToFullNowPath = String8(String8::kEmptyString), - .batteryFullChargeDesignCapacityUahPath = String8(String8::kEmptyString), .energyCounter = NULL, .boot_min_cap = 0, .screen_on = NULL, From 76b2cf3501c9017481f18a8ed14fd973ec371d58 Mon Sep 17 00:00:00 2001 From: Jordan Liu Date: Fri, 21 Feb 2020 14:46:22 -0800 Subject: [PATCH 0652/1022] Add more info on control key param Bug: 149957303 Test: no change to behavior Change-Id: Id9d0e0e9cb2eb1eda83d7b5f1bd72be63216d976 (cherry picked from commit 8c2a986ee9ee1cab3ed5c8ba89615438aaf7b40e) --- current.txt | 2 +- radio/1.5/IRadio.hal | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/current.txt b/current.txt index 5cc7e850a8..42981ade22 100644 --- a/current.txt +++ b/current.txt @@ -703,7 +703,7 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar 77531c8d048f8f8ae532babd0ca86332a865ec9aace1b051226ef2b21123e645 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types 99f5c26b952271d1246c957e1d0271fa39445ee65cc93aa7c187834f98914a33 android.hardware.radio@1.5::types -890ecacaaa6660802bac01bbbe5f16b1eb1d6a3a3f0e5b398be5cec76a5ab673 android.hardware.radio@1.5::IRadio +b454df853441c12f6e425e8a60dd29fda20f5e6e39b93d1103e4b37495db38aa android.hardware.radio@1.5::IRadio e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication 829d3827eeb5a8f563e80fe627419b3231012fc02bc2e79782ec5e9ad9f799a4 android.hardware.radio@1.5::IRadioResponse 3ca6616381080bdd6c08141ad12775a94ae868c58b02b1274ae3326f7de724ab android.hardware.sensors@2.1::ISensors diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal index 87824e2ea8..956f9bd0a1 100644 --- a/radio/1.5/IRadio.hal +++ b/radio/1.5/IRadio.hal @@ -325,11 +325,15 @@ interface IRadio extends @1.4::IRadio { oneway sendCdmaSmsExpectMore(int32_t serial, CdmaSmsMessage sms); /** - * Requests that deactivates one category of the device personalization. + * Request that deactivates one category of device personalization. Device personalization + * generally binds the device so it can only be used on one carrier or even one carrier subnet + * (See TS 22.022). When the user has gained the rights to unbind the device (at the end of a + * contract period or other event), the controlKey will be delivered to either the user for + * manual entry or to a carrier app on the device for automatic entry. * * @param serial Serial number of request. * @param persoType SIM personalization type. - * @param controlKey depersonalization code corresponding to persoType + * @param controlKey the unlock code for removing persoType personalization from this device * * Response function is IRadioResponse.supplySimDepersonalizationResponse() */ From c830cfb3452ae1a234bf2194ef49e39a6c20a4df Mon Sep 17 00:00:00 2001 From: Amy Date: Thu, 6 Feb 2020 15:47:20 -0800 Subject: [PATCH 0653/1022] Refactoring Tuner VTS frontend test part Note that other interface tests are comment out in this CL and will be refactored and uncomment in the CL chains. Test: cuttlefish atest + vendor device test Bug: 135708935 Change-Id: If831219fc588827c9367a506ba7fe7c96bea0286 (cherry picked from commit a5d00e6498f9916cee31785e00a9aee7f3f63caf) --- tv/tuner/1.0/default/Frontend.cpp | 4 + .../VtsHalTvTunerV1_0TargetTest.cpp | 355 +++++++++++------- .../VtsHalTvTunerV1_0TestConfigurations.h | 137 +++++++ 3 files changed, 360 insertions(+), 136 deletions(-) create mode 100644 tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp index dd2f8a68d5..7e206a76cb 100644 --- a/tv/tuner/1.0/default/Frontend.cpp +++ b/tv/tuner/1.0/default/Frontend.cpp @@ -81,6 +81,10 @@ Return Frontend::stopTune() { Return Frontend::scan(const FrontendSettings& /* settings */, FrontendScanType /* type */) { ALOGV("%s", __FUNCTION__); + FrontendScanMessage msg; + msg.isLocked(true); + mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg); + return Result::SUCCESS; } diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 820c58c4ce..1b4929b37e 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright 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. @@ -44,6 +44,8 @@ #include #include +#include "VtsHalTvTunerV1_0TestConfigurations.h" + #define WAIT_TIMEOUT 3000000000 #define WAIT_TIMEOUT_data_ready 3000000000 * 4 @@ -84,9 +86,11 @@ using android::hardware::tv::tuner::V1_0::FrontendAtscSettings; using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings; using android::hardware::tv::tuner::V1_0::FrontendEventType; using android::hardware::tv::tuner::V1_0::FrontendId; +using android::hardware::tv::tuner::V1_0::FrontendInfo; using android::hardware::tv::tuner::V1_0::FrontendInnerFec; using android::hardware::tv::tuner::V1_0::FrontendScanMessage; using android::hardware::tv::tuner::V1_0::FrontendScanMessageType; +using android::hardware::tv::tuner::V1_0::FrontendScanType; using android::hardware::tv::tuner::V1_0::FrontendSettings; using android::hardware::tv::tuner::V1_0::IDemux; using android::hardware::tv::tuner::V1_0::IDescrambler; @@ -103,6 +107,8 @@ using android::hardware::tv::tuner::V1_0::RecordSettings; using android::hardware::tv::tuner::V1_0::RecordStatus; using android::hardware::tv::tuner::V1_0::Result; +using ::testing::AssertionResult; + namespace { using FilterMQ = MessageQueue; @@ -148,8 +154,9 @@ const std::vector goldenDataOutputBuffer{ }; // const uint16_t FMQ_SIZE_4K = 0x1000; -const uint32_t FMQ_SIZE_1M = 0x100000; -const uint32_t FMQ_SIZE_16M = 0x1000000; +// const uint32_t FMQ_SIZE_1M = 0x100000; +// const uint32_t FMQ_SIZE_16M = 0x1000000; +const uint8_t FRONTEND_EVENT_CALLBACK_WAIT_COUNT = 4; struct FilterConf { DemuxFilterType type; @@ -172,6 +179,7 @@ struct PlaybackConf { PlaybackSettings setting; }; +/******************************** Start FrontendCallback **********************************/ class FrontendCallback : public IFrontendCallback { public: virtual Return onEvent(FrontendEventType frontendEventType) override { @@ -182,28 +190,38 @@ class FrontendCallback : public IFrontendCallback { return Void(); } - virtual Return onScanMessage(FrontendScanMessageType /* type */, - const FrontendScanMessage& /* message */) override { + virtual Return onScanMessage(FrontendScanMessageType type, + const FrontendScanMessage& message) override { android::Mutex::Autolock autoLock(mMsgLock); + ALOGD("[vts] scan message. Type: %d", mScanMessageType); mScanMessageReceived = true; + mScanMessageType = type; + mScanLockMessageReceived = + mScanLockMessageReceived | (type == FrontendScanMessageType::LOCKED); + mScanMessage = message; mMsgCondition.signal(); return Void(); }; - void testOnEvent(sp& frontend, FrontendSettings settings); - void testOnDiseqcMessage(sp& frontend, FrontendSettings settings); + void tuneTestOnEventReceive(sp& frontend, FrontendSettings settings); + void tuneTestOnLock(sp& frontend, FrontendSettings settings); + void scanTestOnMessageLock(sp& frontend, FrontendSettings settings, + FrontendScanType type); private: bool mEventReceived = false; - bool mDiseqcMessageReceived = false; bool mScanMessageReceived = false; + bool mScanLockMessageReceived = false; FrontendEventType mEventType; + FrontendScanMessageType mScanMessageType; + FrontendScanMessage mScanMessage; hidl_vec mEventMessage; android::Mutex mMsgLock; android::Condition mMsgCondition; + uint8_t mOnEvenRetry = 0; }; -void FrontendCallback::testOnEvent(sp& frontend, FrontendSettings settings) { +void FrontendCallback::tuneTestOnEventReceive(sp& frontend, FrontendSettings settings) { Result result = frontend->tune(settings); EXPECT_TRUE(result == Result::SUCCESS); @@ -215,22 +233,70 @@ void FrontendCallback::testOnEvent(sp& frontend, FrontendSettings set return; } } + mEventReceived = false; } -void FrontendCallback::testOnDiseqcMessage(sp& frontend, FrontendSettings settings) { +void FrontendCallback::tuneTestOnLock(sp& frontend, FrontendSettings settings) { Result result = frontend->tune(settings); EXPECT_TRUE(result == Result::SUCCESS); android::Mutex::Autolock autoLock(mMsgLock); - while (!mDiseqcMessageReceived) { +wait: + while (!mEventReceived) { if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { - EXPECT_TRUE(false) << "diseqc message not received within timeout"; + EXPECT_TRUE(false) << "event not received within timeout"; return; } } + if (mEventType != FrontendEventType::LOCKED) { + ALOGD("[vts] frontend callback event received. Type: %d", mEventType); + mEventReceived = false; + if (mOnEvenRetry++ < FRONTEND_EVENT_CALLBACK_WAIT_COUNT) { + goto wait; + } + } + EXPECT_TRUE(mEventType == FrontendEventType::LOCKED) << "LOCK event not received"; + mEventReceived = false; + mOnEvenRetry = 0; } +void FrontendCallback::scanTestOnMessageLock(sp& frontend, FrontendSettings settings, + FrontendScanType type) { + Result result = frontend->scan(settings, type); + EXPECT_TRUE(result == Result::SUCCESS); + android::Mutex::Autolock autoLock(mMsgLock); + int messagesCount = 0; + +wait: + int count = 0; + while (!mScanMessageReceived) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + ALOGD("[vts] waiting for scan message callback..."); + if (count++ > 10) { + EXPECT_TRUE(false) << "WAITING TOO LONG!!"; + return; + } + } + } + + if (mScanMessageType != FrontendScanMessageType::END) { + ALOGD("[vts] frontend scan message received. Type: %d", mScanMessageType); + mScanMessageReceived = false; + if (messagesCount++ > 3) { + EXPECT_TRUE(false) << "WAITING ON TOO MANY MSGS!!"; + return; + } + goto wait; + } + + EXPECT_TRUE(mScanLockMessageReceived) << "scan lock message not received before scan ended"; + mScanMessageReceived = false; + mScanLockMessageReceived = false; +} +/******************************** End FrontendCallback **********************************/ + +/******************************** Start FilterCallback **********************************/ class FilterCallback : public IFilterCallback { public: virtual Return onFilterEvent(const DemuxFilterEvent& filterEvent) override { @@ -381,7 +447,9 @@ bool FilterCallback::readFilterEventData() { mFilterIdToMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); return result; } +/******************************** End FilterCallback **********************************/ +/******************************** Start DvrCallback **********************************/ class DvrCallback : public IDvrCallback { public: virtual Return onRecordStatus(DemuxFilterStatus status) override { @@ -635,22 +703,32 @@ void DvrCallback::stopRecordThread() { mRecordThreadRunning = false; android::Mutex::Autolock autoLock(mRecordThreadLock); } +/******************************** End DvrCallback **********************************/ +/******************************** Start Test Implementation**********************************/ class TunerHidlTest : public testing::TestWithParam { public: virtual void SetUp() override { mService = ITuner::getService(GetParam()); ASSERT_NE(mService, nullptr); + initFrontendConfig(); + initFrontendScanConfig(); + initFilterConfig(); } sp mService; protected: + static AssertionResult failure() { return ::testing::AssertionFailure(); } + + static AssertionResult success() { return ::testing::AssertionSuccess(); } + static void description(const std::string& description) { RecordProperty("description", description); } sp mFrontend; + FrontendInfo mFrontendInfo; sp mFrontendCallback; sp mDescrambler; sp mDemux; @@ -664,6 +742,7 @@ class TunerHidlTest : public testing::TestWithParam { MQDesc mPlaybackMQDescriptor; MQDesc mRecordMQDescriptor; vector mUsedFilterIds; + hidl_vec mFeIds; uint32_t mDemuxId; uint32_t mFilterId; @@ -671,10 +750,16 @@ class TunerHidlTest : public testing::TestWithParam { pthread_t mPlaybackshread; bool mPlaybackThreadRunning; - ::testing::AssertionResult createFrontend(int32_t frontendId); - ::testing::AssertionResult tuneFrontend(int32_t frontendId); - ::testing::AssertionResult stopTuneFrontend(int32_t frontendId); - ::testing::AssertionResult closeFrontend(int32_t frontendId); + AssertionResult getFrontendIds(); + AssertionResult getFrontendInfo(uint32_t frontendId); + AssertionResult openFrontend(uint32_t frontendId); + AssertionResult setFrontendCallback(); + AssertionResult scanFrontend(FrontendConfig config, FrontendScanType type); + AssertionResult stopScanFrontend(); + AssertionResult tuneFrontend(FrontendConfig config); + AssertionResult stopTuneFrontend(); + AssertionResult closeFrontend(); + ::testing::AssertionResult createDemux(); ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId, FrontendSettings settings); @@ -698,68 +783,88 @@ class TunerHidlTest : public testing::TestWithParam { vector goldenOutputFiles); }; -::testing::AssertionResult TunerHidlTest::createFrontend(int32_t frontendId) { +/*============================Start Frontend APIs Tests Implementation============================*/ +AssertionResult TunerHidlTest::getFrontendIds() { Result status; + mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { + status = result; + mFeIds = frontendIds; + }); + return AssertionResult(status == Result::SUCCESS); +} +AssertionResult TunerHidlTest::getFrontendInfo(uint32_t frontendId) { + Result status; + mService->getFrontendInfo(frontendId, [&](Result result, const FrontendInfo& frontendInfo) { + mFrontendInfo = frontendInfo; + status = result; + }); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult TunerHidlTest::openFrontend(uint32_t frontendId) { + Result status; mService->openFrontendById(frontendId, [&](Result result, const sp& frontend) { mFrontend = frontend; status = result; }); - if (status != Result::SUCCESS) { - return ::testing::AssertionFailure(); - } + return AssertionResult(status == Result::SUCCESS); +} +AssertionResult TunerHidlTest::setFrontendCallback() { + EXPECT_TRUE(mFrontend) << "Test with openFrontend first."; mFrontendCallback = new FrontendCallback(); auto callbackStatus = mFrontend->setCallback(mFrontendCallback); - - return ::testing::AssertionResult(callbackStatus.isOk()); + return AssertionResult(callbackStatus.isOk()); } -::testing::AssertionResult TunerHidlTest::tuneFrontend(int32_t frontendId) { - if (createFrontend(frontendId) == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); - } +AssertionResult TunerHidlTest::scanFrontend(FrontendConfig config, FrontendScanType type) { + EXPECT_TRUE(mFrontendCallback) + << "test with openFrontend/setFrontendCallback/getFrontendInfo first."; - // Frontend Settings for testing - FrontendSettings frontendSettings; - FrontendAtscSettings frontendAtscSettings{ - .frequency = 0, - .modulation = FrontendAtscModulation::UNDEFINED, - }; - frontendSettings.atsc(frontendAtscSettings); - mFrontendCallback->testOnEvent(mFrontend, frontendSettings); + EXPECT_TRUE(mFrontendInfo.type == config.type) + << "FrontendConfig does not match the frontend info of the given id."; - FrontendDvbtSettings frontendDvbtSettings{ - .frequency = 0, - }; - frontendSettings.dvbt(frontendDvbtSettings); - mFrontendCallback->testOnEvent(mFrontend, frontendSettings); - - return ::testing::AssertionResult(true); + mFrontendCallback->scanTestOnMessageLock(mFrontend, config.settings, type); + return AssertionResult(true); } -::testing::AssertionResult TunerHidlTest::stopTuneFrontend(int32_t frontendId) { +AssertionResult TunerHidlTest::stopScanFrontend() { + EXPECT_TRUE(mFrontend) << "Test with openFrontend first."; Result status; - if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); - } + status = mFrontend->stopScan(); + return AssertionResult(status == Result::SUCCESS); +} +AssertionResult TunerHidlTest::tuneFrontend(FrontendConfig config) { + EXPECT_TRUE(mFrontendCallback) + << "test with openFrontend/setFrontendCallback/getFrontendInfo first."; + + EXPECT_TRUE(mFrontendInfo.type == config.type) + << "FrontendConfig does not match the frontend info of the given id."; + + mFrontendCallback->tuneTestOnLock(mFrontend, config.settings); + return AssertionResult(true); +} + +AssertionResult TunerHidlTest::stopTuneFrontend() { + EXPECT_TRUE(mFrontend) << "Test with openFrontend first."; + Result status; status = mFrontend->stopTune(); - return ::testing::AssertionResult(status == Result::SUCCESS); + return AssertionResult(status == Result::SUCCESS); } -::testing::AssertionResult TunerHidlTest::closeFrontend(int32_t frontendId) { +AssertionResult TunerHidlTest::closeFrontend() { + EXPECT_TRUE(mFrontend) << "Test with openFrontend first."; Result status; - if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); - } - status = mFrontend->close(); mFrontend = nullptr; - return ::testing::AssertionResult(status == Result::SUCCESS); + mFrontendCallback = nullptr; + return AssertionResult(status == Result::SUCCESS); } +/*============================End Frontend APIs Tests Implementation============================*/ -::testing::AssertionResult TunerHidlTest::createDemux() { +/*::testing::AssertionResult TunerHidlTest::createDemux() { Result status; mService->openDemux([&](Result result, uint32_t demuxId, const sp& demux) { @@ -984,16 +1089,16 @@ class TunerHidlTest : public testing::TestWithParam { } break; case DemuxFilterMainType::MMTP: - /*mmtpSettings*/ + \/\*mmtpSettings\*\/ break; case DemuxFilterMainType::IP: - /*ipSettings*/ + \/\*ipSettings\*\/ break; case DemuxFilterMainType::TLV: - /*tlvSettings*/ + \/\*tlvSettings\*\/ break; case DemuxFilterMainType::ALP: - /*alpSettings*/ + \/\*alpSettings\*\/ break; default: break; @@ -1023,7 +1128,7 @@ class TunerHidlTest : public testing::TestWithParam { ::testing::AssertionResult TunerHidlTest::playbackDataFlowTest( vector filterConf, PlaybackConf playbackConf, - vector /*goldenOutputFiles*/) { + vector \/\*goldenOutputFiles\*\/) { Result status; int filterIdsSize; // Filter Configuration Module @@ -1087,7 +1192,7 @@ class TunerHidlTest : public testing::TestWithParam { } ::testing::AssertionResult TunerHidlTest::broadcastDataFlowTest( - vector filterConf, vector /*goldenOutputFiles*/) { + vector filterConf, vector \/\*goldenOutputFiles\*\/) { Result status; hidl_vec feIds; @@ -1155,9 +1260,8 @@ class TunerHidlTest : public testing::TestWithParam { ::testing::AssertionResult TunerHidlTest::recordDataFlowTest(vector filterConf, RecordSettings recordSetting, - vector /*goldenOutputFiles*/) { - Result status; - hidl_vec feIds; + vector +\/\*goldenOutputFiles\*\/) { Result status; hidl_vec feIds; mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { status = result; @@ -1227,92 +1331,71 @@ class TunerHidlTest : public testing::TestWithParam { mFilterCallbacks.clear(); mFilters.clear(); return closeDemux(); +}*/ +/******************************** End Test Implementation**********************************/ + +/******************************** Start Test Entry**********************************/ +/*============================Start Frontend Tests============================*/ +TEST_P(TunerHidlTest, getFrontendIds) { + description("Get Frontend ids and verify frontends exist"); + ASSERT_TRUE(getFrontendIds()); + ASSERT_TRUE(mFeIds.size() > 0); } -/* - * API STATUS TESTS - */ -TEST_P(TunerHidlTest, CreateFrontend) { - Result status; - hidl_vec feIds; +TEST_P(TunerHidlTest, openFrontend) { + description("Open all the existing Frontends and close them"); + ASSERT_TRUE(getFrontendIds()); + ASSERT_TRUE(mFeIds.size() > 0); - description("Create Frontends"); - mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { - status = result; - feIds = frontendIds; - }); - - if (feIds.size() == 0) { - ALOGW("[ WARN ] Frontend isn't available"); - return; - } - - for (size_t i = 0; i < feIds.size(); i++) { - ASSERT_TRUE(createFrontend(feIds[i])); + for (size_t i = 0; i < mFeIds.size(); i++) { + ASSERT_TRUE(openFrontend(mFeIds[i])); + ASSERT_TRUE(closeFrontend()); } } TEST_P(TunerHidlTest, TuneFrontend) { - Result status; - hidl_vec feIds; - - description("Tune Frontends and check callback onEvent"); - mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { - status = result; - feIds = frontendIds; - }); - - if (feIds.size() == 0) { - ALOGW("[ WARN ] Frontend isn't available"); - return; - } - - for (size_t i = 0; i < feIds.size(); i++) { - ASSERT_TRUE(tuneFrontend(feIds[i])); + description("Tune one Frontend with specific setting and check Lock event"); + ASSERT_TRUE(getFrontendIds()); + ASSERT_TRUE(mFeIds.size() > 0); + ALOGW("[vts] expected Frontend type is %d", frontendArray[0].type); + for (size_t i = 0; i < mFeIds.size(); i++) { + ASSERT_TRUE(getFrontendInfo(mFeIds[i])); + ALOGW("[vts] Frontend type is %d", mFrontendInfo.type); + if (mFrontendInfo.type != frontendArray[0].type) { + continue; + } + ASSERT_TRUE(openFrontend(mFeIds[i])); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(stopTuneFrontend()); + ASSERT_TRUE(tuneFrontend(frontendArray[0])); + ASSERT_TRUE(stopTuneFrontend()); + ASSERT_TRUE(closeFrontend()); + break; } } -TEST_P(TunerHidlTest, StopTuneFrontend) { - Result status; - hidl_vec feIds; +TEST_P(TunerHidlTest, AutoScanFrontend) { + description("Run an auto frontend scan with specific setting and check lock scanMessage"); + ASSERT_TRUE(getFrontendIds()); + ASSERT_TRUE(mFeIds.size() > 0); - description("stopTune Frontends"); - mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { - status = result; - feIds = frontendIds; - }); - - if (feIds.size() == 0) { - ALOGW("[ WARN ] Frontend isn't available"); - return; - } - - for (size_t i = 0; i < feIds.size(); i++) { - ASSERT_TRUE(stopTuneFrontend(feIds[i])); + for (size_t i = 0; i < mFeIds.size(); i++) { + ASSERT_TRUE(getFrontendInfo(mFeIds[i])); + if (mFrontendInfo.type != frontendArray[0].type) { + continue; + } + ASSERT_TRUE(openFrontend(mFeIds[i])); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(stopScanFrontend()); + ASSERT_TRUE(scanFrontend(frontendScanArray[0], FrontendScanType::SCAN_AUTO)); + ASSERT_TRUE(stopScanFrontend()); + ASSERT_TRUE(closeFrontend()); + break; } } +/*============================End Frontend Tests============================*/ -TEST_P(TunerHidlTest, CloseFrontend) { - Result status; - hidl_vec feIds; - - description("Close Frontends"); - mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { - status = result; - feIds = frontendIds; - }); - - if (feIds.size() == 0) { - ALOGW("[ WARN ] Frontend isn't available"); - return; - } - - for (size_t i = 0; i < feIds.size(); i++) { - ASSERT_TRUE(closeFrontend(feIds[i])); - } -} - -TEST_P(TunerHidlTest, CreateDemuxWithFrontend) { +/*TEST_P(TunerHidlTest, CreateDemuxWithFrontend) { Result status; hidl_vec feIds; @@ -1357,7 +1440,7 @@ TEST_P(TunerHidlTest, CreateDescrambler) { TEST_P(TunerHidlTest, CloseDescrambler) { description("Close Descrambler"); ASSERT_TRUE(closeDescrambler()); -} +}*/ /* * DATA FLOW TESTS @@ -1474,7 +1557,7 @@ TEST_P(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) { ASSERT_TRUE(recordDataFlowTest(filterConf, recordSetting, goldenOutputFiles)); }*/ - +/******************************** End Test Entry**********************************/ } // namespace INSTANTIATE_TEST_SUITE_P( diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h new file mode 100644 index 0000000000..55ca8579fb --- /dev/null +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h @@ -0,0 +1,137 @@ +/* + * Copyright 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterMainType; +using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterStatus; +using android::hardware::tv::tuner::V1_0::DemuxFilterType; +using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; +using android::hardware::tv::tuner::V1_0::DemuxTpid; +using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings; +using android::hardware::tv::tuner::V1_0::DemuxTsFilterType; +using android::hardware::tv::tuner::V1_0::FrontendDvbtBandwidth; +using android::hardware::tv::tuner::V1_0::FrontendDvbtCoderate; +using android::hardware::tv::tuner::V1_0::FrontendDvbtConstellation; +using android::hardware::tv::tuner::V1_0::FrontendDvbtGuardInterval; +using android::hardware::tv::tuner::V1_0::FrontendDvbtHierarchy; +using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings; +using android::hardware::tv::tuner::V1_0::FrontendDvbtStandard; +using android::hardware::tv::tuner::V1_0::FrontendDvbtTransmissionMode; +using android::hardware::tv::tuner::V1_0::FrontendSettings; +using android::hardware::tv::tuner::V1_0::FrontendType; + +namespace { + +#define frontend_transponders_count 1 +#define channels_count 1 +#define frontend_scan_count 1 +#define filter_count 2 + +struct FilterConfig { + DemuxFilterType type; + DemuxFilterSettings setting; +}; + +struct FrontendConfig { + FrontendType type; + FrontendSettings settings; +}; + +struct ChannelConfig { + int32_t frontendId; + int32_t channelId; + std::string channelName; + DemuxTpid videoPid; + DemuxTpid audioPid; +}; + +static FrontendConfig frontendArray[frontend_transponders_count]; +static FrontendConfig frontendScanArray[channels_count]; +static ChannelConfig channelArray[frontend_scan_count]; +static FilterConfig filterArray[filter_count]; +static vector goldenOutputFiles; + +/** Configuration array for the frontend tune test */ +inline void initFrontendConfig() { + FrontendDvbtSettings dvbtSettings{ + .frequency = 578000, + .transmissionMode = FrontendDvbtTransmissionMode::AUTO, + .bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ, + .constellation = FrontendDvbtConstellation::AUTO, + .hierarchy = FrontendDvbtHierarchy::AUTO, + .hpCoderate = FrontendDvbtCoderate::AUTO, + .lpCoderate = FrontendDvbtCoderate::AUTO, + .guardInterval = FrontendDvbtGuardInterval::AUTO, + .isHighPriority = true, + .standard = FrontendDvbtStandard::T, + }; + frontendArray[0].type = FrontendType::DVBT, frontendArray[0].settings.dvbt(dvbtSettings); +}; + +/** Configuration array for the frontend scan test */ +inline void initFrontendScanConfig() { + frontendScanArray[0].type = FrontendType::DVBT, frontendScanArray[0].settings.dvbt({ + .frequency = 577000, + }); +}; + +/** Configuration array for the filter test */ +inline void initFilterConfig() { + // TS Video filter setting + filterArray[0].type.mainType = DemuxFilterMainType::TS; + filterArray[0].type.subType.tsFilterType(DemuxTsFilterType::VIDEO); + filterArray[0].setting.ts().tpid = 49; + filterArray[0].setting.ts().filterSettings.av({.isPassthrough = false}); + // TS PES filter setting + filterArray[1].type.mainType = DemuxFilterMainType::TS; + filterArray[1].type.subType.tsFilterType(DemuxTsFilterType::PES); + filterArray[1].setting.ts().tpid = 256; + filterArray[1].setting.ts().filterSettings.pesData({ + .isRaw = true, + .streamId = 0xbd, + }); +}; + +} // namespace \ No newline at end of file From 3c95a93b48324496d224b9134a1b284ae871f26e Mon Sep 17 00:00:00 2001 From: Amy Date: Thu, 6 Feb 2020 16:19:04 -0800 Subject: [PATCH 0654/1022] Refactor Tuner vts test Demux part Test: cuttlefish + vendor device test Bug: 135708935 Change-Id: I7e8e14809975854d6c88819a40819227a187a5a1 (cherry picked from commit dd08190510627e08b745809d2efea72ed9a84c9e) --- .../VtsHalTvTunerV1_0TargetTest.cpp | 104 +++++++----------- 1 file changed, 37 insertions(+), 67 deletions(-) diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 1b4929b37e..53ab2ce3d2 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -760,16 +760,16 @@ class TunerHidlTest : public testing::TestWithParam { AssertionResult stopTuneFrontend(); AssertionResult closeFrontend(); - ::testing::AssertionResult createDemux(); - ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId, - FrontendSettings settings); + AssertionResult openDemux(); + AssertionResult setDemuxFrontendDataSource(uint32_t frontendId); + AssertionResult closeDemux(); + ::testing::AssertionResult getPlaybackMQDescriptor(); ::testing::AssertionResult addPlaybackToDemux(PlaybackSettings setting); ::testing::AssertionResult getRecordMQDescriptor(); ::testing::AssertionResult addRecordToDemux(RecordSettings setting); ::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting); ::testing::AssertionResult getFilterMQDescriptor(); - ::testing::AssertionResult closeDemux(); ::testing::AssertionResult createDescrambler(); ::testing::AssertionResult closeDescrambler(); @@ -864,48 +864,33 @@ AssertionResult TunerHidlTest::closeFrontend() { } /*============================End Frontend APIs Tests Implementation============================*/ -/*::testing::AssertionResult TunerHidlTest::createDemux() { +/*============================Start Demux APIs Tests Implementation============================*/ +AssertionResult TunerHidlTest::openDemux() { Result status; - mService->openDemux([&](Result result, uint32_t demuxId, const sp& demux) { mDemux = demux; mDemuxId = demuxId; status = result; }); - return ::testing::AssertionResult(status == Result::SUCCESS); + return AssertionResult(status == Result::SUCCESS); } -::testing::AssertionResult TunerHidlTest::createDemuxWithFrontend(int32_t frontendId, - FrontendSettings settings) { - Result status; - - if (!mDemux && createDemux() == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); - } - - if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); - } - - mFrontendCallback->testOnEvent(mFrontend, settings); - - status = mDemux->setFrontendDataSource(frontendId); - - return ::testing::AssertionResult(status == Result::SUCCESS); +AssertionResult TunerHidlTest::setDemuxFrontendDataSource(uint32_t frontendId) { + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + EXPECT_TRUE(mFrontend) << "Test with openFrontend first."; + auto status = mDemux->setFrontendDataSource(frontendId); + return AssertionResult(status.isOk()); } -::testing::AssertionResult TunerHidlTest::closeDemux() { - Result status; - if (!mDemux && createDemux() == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); - } - - status = mDemux->close(); +AssertionResult TunerHidlTest::closeDemux() { + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + auto status = mDemux->close(); mDemux = nullptr; - return ::testing::AssertionResult(status == Result::SUCCESS); + return AssertionResult(status.isOk()); } +/*============================End Demux APIs Tests Implementation============================*/ -::testing::AssertionResult TunerHidlTest::createDescrambler() { +/*::testing::AssertionResult TunerHidlTest::createDescrambler() { Result status; mService->openDescrambler([&](Result result, const sp& descrambler) { @@ -1395,44 +1380,29 @@ TEST_P(TunerHidlTest, AutoScanFrontend) { } /*============================End Frontend Tests============================*/ -/*TEST_P(TunerHidlTest, CreateDemuxWithFrontend) { - Result status; - hidl_vec feIds; +/*============================Start Demux Tests============================*/ +TEST_P(TunerHidlTest, OpenDemuxWithFrontendDataSource) { + description("Open Demux with a Frontend as its data source."); + ASSERT_TRUE(getFrontendIds()); + ASSERT_TRUE(mFeIds.size() > 0); - description("Create Demux with Frontend"); - mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { - status = result; - feIds = frontendIds; - }); - - if (feIds.size() == 0) { - ALOGW("[ WARN ] Frontend isn't available"); - return; - } - - FrontendDvbtSettings dvbt{ - .frequency = 1000, - }; - FrontendSettings settings; - settings.dvbt(dvbt); - - for (size_t i = 0; i < feIds.size(); i++) { - ASSERT_TRUE(createDemuxWithFrontend(feIds[i], settings)); - mFrontend->stopTune(); + for (size_t i = 0; i < mFeIds.size(); i++) { + ASSERT_TRUE(getFrontendInfo(mFeIds[i])); + if (mFrontendInfo.type != frontendArray[0].type) { + continue; + } + ASSERT_TRUE(openFrontend(mFeIds[i])); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(openDemux()); + ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i])); + ASSERT_TRUE(closeDemux()); + ASSERT_TRUE(closeFrontend()); + break; } } +/*============================End Demux Tests============================*/ -TEST_P(TunerHidlTest, CreateDemux) { - description("Create Demux"); - ASSERT_TRUE(createDemux()); -} - -TEST_P(TunerHidlTest, CloseDemux) { - description("Close Demux"); - ASSERT_TRUE(closeDemux()); -} - -TEST_P(TunerHidlTest, CreateDescrambler) { +/*TEST_P(TunerHidlTest, CreateDescrambler) { description("Create Descrambler"); ASSERT_TRUE(createDescrambler()); } From d2ee30021fa90c144d6456aa3a9583f783724fb7 Mon Sep 17 00:00:00 2001 From: Amy Date: Thu, 6 Feb 2020 18:09:31 -0800 Subject: [PATCH 0655/1022] Refactor Tuner VTS filter part Test: cuttlefish + vendor device Bug: 135708935 Change-Id: I77b86da48720fa117d5afd273c3b157ddd650e10 (cherry picked from commit 6fbe5d77d744e83b3abd5819a73bc6412efd0458) --- .../VtsHalTvTunerV1_0TargetTest.cpp | 360 +++++++++++------- 1 file changed, 232 insertions(+), 128 deletions(-) diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 53ab2ce3d2..5fb817eecd 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -155,14 +155,9 @@ const std::vector goldenDataOutputBuffer{ // const uint16_t FMQ_SIZE_4K = 0x1000; // const uint32_t FMQ_SIZE_1M = 0x100000; -// const uint32_t FMQ_SIZE_16M = 0x1000000; +const uint32_t FMQ_SIZE_16M = 0x1000000; const uint8_t FRONTEND_EVENT_CALLBACK_WAIT_COUNT = 4; -struct FilterConf { - DemuxFilterType type; - DemuxFilterSettings setting; -}; - enum FilterEventType : uint8_t { UNDEFINED, SECTION, @@ -303,7 +298,7 @@ class FilterCallback : public IFilterCallback { android::Mutex::Autolock autoLock(mMsgLock); // Temprarily we treat the first coming back filter data on the matching pid a success // once all of the MQ are cleared, means we got all the expected output - mFilterIdToEvent = filterEvent; + mFilterEvent = filterEvent; readFilterEventData(); mPidFilterOutputCount++; // mFilterIdToMQ.erase(filterEvent.filterId); @@ -342,9 +337,9 @@ class FilterCallback : public IFilterCallback { uint32_t mFilterId; FilterEventType mFilterEventType; - std::unique_ptr mFilterIdToMQ; - EventFlag* mFilterIdToMQEventFlag; - DemuxFilterEvent mFilterIdToEvent; + std::unique_ptr mFilterMQ; + EventFlag* mFilterMQEventFlag; + DemuxFilterEvent mFilterEvent; android::Mutex mMsgLock; android::Mutex mFilterOutputLock; @@ -379,10 +374,10 @@ void FilterCallback::testFilterDataOutput() { } void FilterCallback::updateFilterMQ(MQDesc& filterMQDescriptor) { - mFilterIdToMQ = std::make_unique(filterMQDescriptor, true /* resetPointers */); - EXPECT_TRUE(mFilterIdToMQ); - EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ->getEventFlagWord(), - &mFilterIdToMQEventFlag) == android::OK); + mFilterMQ = std::make_unique(filterMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(mFilterMQ); + EXPECT_TRUE(EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag) == + android::OK); } void FilterCallback::updateGoldenOutputMap(string goldenOutputFile) { @@ -398,7 +393,7 @@ void* FilterCallback::__threadLoopFilter(void* threadArgs) { void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) { android::Mutex::Autolock autoLock(mFilterOutputLock); - // Read from mFilterIdToMQ[event.filterId] per event and filter type + // Read from mFilterMQ[event.filterId] per event and filter type // Assemble to filterOutput[filterId] @@ -411,7 +406,7 @@ void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) { bool FilterCallback::readFilterEventData() { bool result = false; - DemuxFilterEvent filterEvent = mFilterIdToEvent; + DemuxFilterEvent filterEvent = mFilterEvent; ALOGW("[vts] reading from filter FMQ %d", mFilterId); // todo separate filter handlers for (int i = 0; i < filterEvent.events.size(); i++) { @@ -423,6 +418,7 @@ bool FilterCallback::readFilterEventData() { mDataLength = filterEvent.events[i].pes().dataLength; break; case FilterEventType::MEDIA: + mDataLength = filterEvent.events[i].media().dataLength; break; case FilterEventType::RECORD: break; @@ -437,14 +433,14 @@ bool FilterCallback::readFilterEventData() { // match"; mDataOutputBuffer.resize(mDataLength); - result = mFilterIdToMQ->read(mDataOutputBuffer.data(), mDataLength); + result = mFilterMQ->read(mDataOutputBuffer.data(), mDataLength); EXPECT_TRUE(result) << "can't read from Filter MQ"; /*for (int i = 0; i < mDataLength; i++) { EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match"; }*/ } - mFilterIdToMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); + mFilterMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); return result; } /******************************** End FilterCallback **********************************/ @@ -513,11 +509,10 @@ class DvrCallback : public IDvrCallback { uint16_t mDataLength = 0; std::vector mDataOutputBuffer; - std::map> mFilterIdToMQ; + std::map> mFilterMQ; std::unique_ptr mPlaybackMQ; std::unique_ptr mRecordMQ; - std::map mFilterIdToMQEventFlag; - std::map mFilterIdToEvent; + std::map mFilterMQEventFlag; android::Mutex mMsgLock; android::Mutex mPlaybackThreadLock; @@ -745,7 +740,7 @@ class TunerHidlTest : public testing::TestWithParam { hidl_vec mFeIds; uint32_t mDemuxId; - uint32_t mFilterId; + uint32_t mFilterId = -1; pthread_t mPlaybackshread; bool mPlaybackThreadRunning; @@ -764,23 +759,31 @@ class TunerHidlTest : public testing::TestWithParam { AssertionResult setDemuxFrontendDataSource(uint32_t frontendId); AssertionResult closeDemux(); + AssertionResult openFilterInDemux(DemuxFilterType type); + AssertionResult getNewlyOpenedFilterId(uint32_t& filterId); + AssertionResult configFilter(DemuxFilterSettings setting, uint32_t filterId); + AssertionResult getFilterMQDescriptor(uint32_t filterId); + AssertionResult startFilter(uint32_t filterId); + AssertionResult stopFilter(uint32_t filterId); + AssertionResult closeFilter(uint32_t filterId); + ::testing::AssertionResult getPlaybackMQDescriptor(); ::testing::AssertionResult addPlaybackToDemux(PlaybackSettings setting); ::testing::AssertionResult getRecordMQDescriptor(); ::testing::AssertionResult addRecordToDemux(RecordSettings setting); - ::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting); - ::testing::AssertionResult getFilterMQDescriptor(); ::testing::AssertionResult createDescrambler(); ::testing::AssertionResult closeDescrambler(); - ::testing::AssertionResult playbackDataFlowTest(vector filterConf, + ::testing::AssertionResult playbackDataFlowTest(vector filterConf, PlaybackConf playbackConf, vector goldenOutputFiles); - ::testing::AssertionResult recordDataFlowTest(vector filterConf, + ::testing::AssertionResult recordDataFlowTest(vector filterConf, RecordSettings recordSetting, vector goldenOutputFiles); - ::testing::AssertionResult broadcastDataFlowTest(vector filterConf, + ::testing::AssertionResult broadcastDataFlowTest(vector filterConf, vector goldenOutputFiles); + + FilterEventType getFilterEventType(DemuxFilterType type); }; /*============================Start Frontend APIs Tests Implementation============================*/ @@ -888,8 +891,106 @@ AssertionResult TunerHidlTest::closeDemux() { mDemux = nullptr; return AssertionResult(status.isOk()); } + +AssertionResult TunerHidlTest::openFilterInDemux(DemuxFilterType type) { + Result status; + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + + // Create demux callback + mFilterCallback = new FilterCallback(); + + // Add filter to the local demux + mDemux->openFilter(type, FMQ_SIZE_16M, mFilterCallback, + [&](Result result, const sp& filter) { + mFilter = filter; + status = result; + }); + + if (status == Result::SUCCESS) { + mFilterCallback->setFilterEventType(getFilterEventType(type)); + } + + return AssertionResult(status == Result::SUCCESS); +} /*============================End Demux APIs Tests Implementation============================*/ +/*============================Start Filter APIs Tests Implementation============================*/ +AssertionResult TunerHidlTest::getNewlyOpenedFilterId(uint32_t& filterId) { + Result status; + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + EXPECT_TRUE(mFilter) << "Test with openFilterInDemux first."; + EXPECT_TRUE(mFilterCallback) << "Test with openFilterInDemux first."; + + mFilter->getId([&](Result result, uint32_t filterId) { + mFilterId = filterId; + status = result; + }); + + if (status == Result::SUCCESS) { + mFilterCallback->setFilterId(mFilterId); + mUsedFilterIds.insert(mUsedFilterIds.end(), mFilterId); + mFilters[mFilterId] = mFilter; + mFilterCallbacks[mFilterId] = mFilterCallback; + filterId = mFilterId; + } + + return AssertionResult(status == Result::SUCCESS || status == Result::UNAVAILABLE); +} + +AssertionResult TunerHidlTest::configFilter(DemuxFilterSettings setting, uint32_t filterId) { + Result status; + EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; + status = mFilters[filterId]->configure(setting); + + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult TunerHidlTest::getFilterMQDescriptor(uint32_t filterId) { + Result status; + EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; + EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first."; + + mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) { + mFilterMQDescriptor = filterMQDesc; + status = result; + }); + + if (status == Result::SUCCESS) { + mFilterCallbacks[filterId]->updateFilterMQ(mFilterMQDescriptor); + } + + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult TunerHidlTest::startFilter(uint32_t filterId) { + EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; + Result status = mFilters[filterId]->start(); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult TunerHidlTest::stopFilter(uint32_t filterId) { + EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; + Result status = mFilters[filterId]->stop(); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult TunerHidlTest::closeFilter(uint32_t filterId) { + EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; + Result status = mFilters[filterId]->close(); + if (status == Result::SUCCESS) { + for (int i = 0; i < mUsedFilterIds.size(); i++) { + if (mUsedFilterIds[i] == filterId) { + mUsedFilterIds.erase(mUsedFilterIds.begin() + i); + break; + } + } + mFilterCallbacks.erase(filterId); + mFilters.erase(filterId); + } + return AssertionResult(status == Result::SUCCESS); +} +/*============================End Filter APIs Tests Implementation============================*/ + /*::testing::AssertionResult TunerHidlTest::createDescrambler() { Result status; @@ -1012,105 +1113,6 @@ AssertionResult TunerHidlTest::closeDemux() { return ::testing::AssertionResult(status == Result::SUCCESS); } -::testing::AssertionResult TunerHidlTest::addFilterToDemux(DemuxFilterType type, - DemuxFilterSettings setting) { - Result status; - - if (!mDemux && createDemux() == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); - } - - // Create demux callback - mFilterCallback = new FilterCallback(); - - // Add filter to the local demux - mDemux->openFilter(type, FMQ_SIZE_16M, mFilterCallback, - [&](Result result, const sp& filter) { - mFilter = filter; - status = result; - }); - - if (status != Result::SUCCESS) { - return ::testing::AssertionFailure(); - } - - mFilter->getId([&](Result result, uint32_t filterId) { - mFilterId = filterId; - status = result; - }); - - if (status != Result::SUCCESS) { - return ::testing::AssertionFailure(); - } - - mFilterCallback->setFilterId(mFilterId); - - FilterEventType eventType = FilterEventType::UNDEFINED; - switch (type.mainType) { - case DemuxFilterMainType::TS: - switch (type.subType.tsFilterType()) { - case DemuxTsFilterType::UNDEFINED: - break; - case DemuxTsFilterType::SECTION: - eventType = FilterEventType::SECTION; - break; - case DemuxTsFilterType::PES: - eventType = FilterEventType::PES; - break; - case DemuxTsFilterType::TS: - break; - case DemuxTsFilterType::AUDIO: - case DemuxTsFilterType::VIDEO: - eventType = FilterEventType::MEDIA; - break; - case DemuxTsFilterType::PCR: - break; - case DemuxTsFilterType::RECORD: - eventType = FilterEventType::RECORD; - break; - case DemuxTsFilterType::TEMI: - eventType = FilterEventType::TEMI; - break; - } - break; - case DemuxFilterMainType::MMTP: - \/\*mmtpSettings\*\/ - break; - case DemuxFilterMainType::IP: - \/\*ipSettings\*\/ - break; - case DemuxFilterMainType::TLV: - \/\*tlvSettings\*\/ - break; - case DemuxFilterMainType::ALP: - \/\*alpSettings\*\/ - break; - default: - break; - } - mFilterCallback->setFilterEventType(eventType); - - // Configure the filter - status = mFilter->configure(setting); - - return ::testing::AssertionResult(status == Result::SUCCESS); -} - -::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor() { - Result status; - - if (!mDemux || !mFilter) { - return ::testing::AssertionFailure(); - } - - mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) { - mFilterMQDescriptor = filterMQDesc; - status = result; - }); - - return ::testing::AssertionResult(status == Result::SUCCESS); -} - ::testing::AssertionResult TunerHidlTest::playbackDataFlowTest( vector filterConf, PlaybackConf playbackConf, vector \/\*goldenOutputFiles\*\/) { @@ -1317,6 +1319,56 @@ AssertionResult TunerHidlTest::closeDemux() { mFilters.clear(); return closeDemux(); }*/ +/*============================End Data Flow Tests Implementation============================*/ + +/*============================Start Helper Functions============================*/ +FilterEventType TunerHidlTest::getFilterEventType(DemuxFilterType type) { + FilterEventType eventType = FilterEventType::UNDEFINED; + switch (type.mainType) { + case DemuxFilterMainType::TS: + switch (type.subType.tsFilterType()) { + case DemuxTsFilterType::UNDEFINED: + break; + case DemuxTsFilterType::SECTION: + eventType = FilterEventType::SECTION; + break; + case DemuxTsFilterType::PES: + eventType = FilterEventType::PES; + break; + case DemuxTsFilterType::TS: + break; + case DemuxTsFilterType::AUDIO: + case DemuxTsFilterType::VIDEO: + eventType = FilterEventType::MEDIA; + break; + case DemuxTsFilterType::PCR: + break; + case DemuxTsFilterType::RECORD: + eventType = FilterEventType::RECORD; + break; + case DemuxTsFilterType::TEMI: + eventType = FilterEventType::TEMI; + break; + } + break; + case DemuxFilterMainType::MMTP: + /*mmtpSettings*/ + break; + case DemuxFilterMainType::IP: + /*ipSettings*/ + break; + case DemuxFilterMainType::TLV: + /*tlvSettings*/ + break; + case DemuxFilterMainType::ALP: + /*alpSettings*/ + break; + default: + break; + } + return eventType; +} +/*============================End Helper Functions============================*/ /******************************** End Test Implementation**********************************/ /******************************** Start Test Entry**********************************/ @@ -1380,7 +1432,7 @@ TEST_P(TunerHidlTest, AutoScanFrontend) { } /*============================End Frontend Tests============================*/ -/*============================Start Demux Tests============================*/ +/*============================Start Demux/Filter Tests============================*/ TEST_P(TunerHidlTest, OpenDemuxWithFrontendDataSource) { description("Open Demux with a Frontend as its data source."); ASSERT_TRUE(getFrontendIds()); @@ -1400,7 +1452,59 @@ TEST_P(TunerHidlTest, OpenDemuxWithFrontendDataSource) { break; } } -/*============================End Demux Tests============================*/ + +TEST_P(TunerHidlTest, OpenFilterInDemux) { + description("Open a filter in Demux."); + ASSERT_TRUE(getFrontendIds()); + ASSERT_TRUE(mFeIds.size() > 0); + + for (size_t i = 0; i < mFeIds.size(); i++) { + ASSERT_TRUE(getFrontendInfo(mFeIds[i])); + if (mFrontendInfo.type != frontendArray[0].type) { + continue; + } + ASSERT_TRUE(openFrontend(mFeIds[i])); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(openDemux()); + ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i])); + ASSERT_TRUE(openFilterInDemux(filterArray[0].type)); + uint32_t filterId; + ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); + ASSERT_TRUE(closeFilter(filterId)); + ASSERT_TRUE(closeDemux()); + ASSERT_TRUE(closeFrontend()); + break; + } +} + +TEST_P(TunerHidlTest, StartFilterInDemux) { + description("Open and start a filter in Demux."); + ASSERT_TRUE(getFrontendIds()); + ASSERT_TRUE(mFeIds.size() > 0); + + for (size_t i = 0; i < mFeIds.size(); i++) { + ASSERT_TRUE(getFrontendInfo(mFeIds[i])); + if (mFrontendInfo.type != frontendArray[0].type) { + continue; + } + ASSERT_TRUE(openFrontend(mFeIds[i])); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(openDemux()); + ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i])); + ASSERT_TRUE(openFilterInDemux(filterArray[0].type)); + uint32_t filterId; + ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); + ASSERT_TRUE(configFilter(filterArray[0].setting, filterId)); + ASSERT_TRUE(getFilterMQDescriptor(filterId)); + ASSERT_TRUE(startFilter(filterId)); + ASSERT_TRUE(stopFilter(filterId)); + ASSERT_TRUE(closeFilter(filterId)); + ASSERT_TRUE(closeDemux()); + ASSERT_TRUE(closeFrontend()); + break; + } +} +/*============================End Demux/Filter Tests============================*/ /*TEST_P(TunerHidlTest, CreateDescrambler) { description("Create Descrambler"); From c1353fced660b2a4df66e962eb753fd8e3b3832f Mon Sep 17 00:00:00 2001 From: Amy Date: Thu, 6 Feb 2020 19:00:29 -0800 Subject: [PATCH 0656/1022] Refactor Tuner VTS broadcast data flow test Test: cuttlefish + vendor device test Bug: 135708935 Change-Id: Ia7b6bf76c1f98202fb93ddf5d4f09c742e3f7c8b (cherry picked from commit 46f46cd931ac5270ebc5c12c526aa5c91202b337) --- .../VtsHalTvTunerV1_0TargetTest.cpp | 156 ++++++------------ 1 file changed, 54 insertions(+), 102 deletions(-) diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 5fb817eecd..e8c80101ed 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -767,6 +767,8 @@ class TunerHidlTest : public testing::TestWithParam { AssertionResult stopFilter(uint32_t filterId); AssertionResult closeFilter(uint32_t filterId); + AssertionResult broadcastDataFlowTest(vector goldenOutputFiles); + ::testing::AssertionResult getPlaybackMQDescriptor(); ::testing::AssertionResult addPlaybackToDemux(PlaybackSettings setting); ::testing::AssertionResult getRecordMQDescriptor(); @@ -780,8 +782,6 @@ class TunerHidlTest : public testing::TestWithParam { ::testing::AssertionResult recordDataFlowTest(vector filterConf, RecordSettings recordSetting, vector goldenOutputFiles); - ::testing::AssertionResult broadcastDataFlowTest(vector filterConf, - vector goldenOutputFiles); FilterEventType getFilterEventType(DemuxFilterType type); }; @@ -1111,9 +1111,26 @@ AssertionResult TunerHidlTest::closeFilter(uint32_t filterId) { }); return ::testing::AssertionResult(status == Result::SUCCESS); +}*/ + +/*============================Start Data Flow Tests Implementation============================*/ +AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutputFiles*/) { + EXPECT_TRUE(mFrontend) << "Test with openFilterInDemux first."; + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + EXPECT_TRUE(mFilterCallback) << "Test with getFilterMQDescriptor first."; + + // Data Verify Module + std::map>::iterator it; + for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) { + it->second->testFilterDataOutput(); + } + return success(); } -::testing::AssertionResult TunerHidlTest::playbackDataFlowTest( +/* + * TODO: re-enable the tests after finalizing the test refactoring. + */ +/*::testing::AssertionResult TunerHidlTest::playbackDataFlowTest( vector filterConf, PlaybackConf playbackConf, vector \/\*goldenOutputFiles\*\/) { Result status; @@ -1178,73 +1195,6 @@ AssertionResult TunerHidlTest::closeFilter(uint32_t filterId) { return closeDemux(); } -::testing::AssertionResult TunerHidlTest::broadcastDataFlowTest( - vector filterConf, vector \/\*goldenOutputFiles\*\/) { - Result status; - hidl_vec feIds; - - mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { - status = result; - feIds = frontendIds; - }); - - if (feIds.size() == 0) { - ALOGW("[ WARN ] Frontend isn't available"); - return ::testing::AssertionFailure(); - } - - FrontendDvbtSettings dvbt{ - .frequency = 1000, - }; - FrontendSettings settings; - settings.dvbt(dvbt); - - if (createDemuxWithFrontend(feIds[0], settings) != ::testing::AssertionSuccess()) { - return ::testing::AssertionFailure(); - } - - int filterIdsSize; - // Filter Configuration Module - for (int i = 0; i < filterConf.size(); i++) { - if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) == - ::testing::AssertionFailure() || - // TODO use a map to save the FMQs/EvenFlags and pass to callback - getFilterMQDescriptor() == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); - } - filterIdsSize = mUsedFilterIds.size(); - mUsedFilterIds.resize(filterIdsSize + 1); - mUsedFilterIds[filterIdsSize] = mFilterId; - mFilters[mFilterId] = mFilter; - mFilterCallbacks[mFilterId] = mFilterCallback; - mFilterCallback->updateFilterMQ(mFilterMQDescriptor); - status = mFilter->start(); - if (status != Result::SUCCESS) { - return ::testing::AssertionFailure(); - } - } - - // Data Verify Module - std::map>::iterator it; - for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) { - it->second->testFilterDataOutput(); - } - - // Clean Up Module - for (int i = 0; i <= filterIdsSize; i++) { - if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) { - return ::testing::AssertionFailure(); - } - } - if (mFrontend->stopTune() != Result::SUCCESS) { - return ::testing::AssertionFailure(); - } - mUsedFilterIds.clear(); - mFilterCallbacks.clear(); - mFilters.clear(); - return closeDemux(); -} - ::testing::AssertionResult TunerHidlTest::recordDataFlowTest(vector filterConf, RecordSettings recordSetting, vector @@ -1516,9 +1466,41 @@ TEST_P(TunerHidlTest, CloseDescrambler) { ASSERT_TRUE(closeDescrambler()); }*/ +/*============================Start Data Flow Tests============================*/ +TEST_P(TunerHidlTest, BroadcastDataFlowWithAudioFilterTest) { + description("Open Demux with a Frontend as its data source."); + ASSERT_TRUE(getFrontendIds()); + ASSERT_TRUE(mFeIds.size() > 0); + + for (size_t i = 0; i < mFeIds.size(); i++) { + ASSERT_TRUE(getFrontendInfo(mFeIds[i])); + if (mFrontendInfo.type != frontendArray[0].type) { + continue; + } + ASSERT_TRUE(openFrontend(mFeIds[i])); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(openDemux()); + ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i])); + ASSERT_TRUE(openFilterInDemux(filterArray[0].type)); + uint32_t filterId; + ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); + ASSERT_TRUE(configFilter(filterArray[0].setting, filterId)); + ASSERT_TRUE(getFilterMQDescriptor(filterId)); + ASSERT_TRUE(startFilter(filterId)); + // tune test + ASSERT_TRUE(tuneFrontend(frontendArray[0])); + // broadcast data flow test + ASSERT_TRUE(broadcastDataFlowTest(goldenOutputFiles)); + ASSERT_TRUE(stopTuneFrontend()); + ASSERT_TRUE(stopFilter(filterId)); + ASSERT_TRUE(closeFilter(filterId)); + ASSERT_TRUE(closeDemux()); + ASSERT_TRUE(closeFrontend()); + break; + } +} + /* - * DATA FLOW TESTS - * * TODO: re-enable the tests after finalizing the testing stream. */ /*TEST_P(TunerHidlTest, PlaybackDataFlowWithSectionFilterTest) { @@ -1564,36 +1546,6 @@ TEST_P(TunerHidlTest, CloseDescrambler) { ASSERT_TRUE(playbackDataFlowTest(filterConf, playbackConf, goldenOutputFiles)); } -TEST_P(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) { - description("Feed ts data from frontend and test with PES filter"); - - // todo modulize the filter conf parser - vector filterConf; - filterConf.resize(1); - - DemuxFilterSettings filterSetting; - DemuxTsFilterSettings tsFilterSetting{ - .tpid = 119, - }; - DemuxFilterPesDataSettings pesFilterSetting; - tsFilterSetting.filterSettings.pesData(pesFilterSetting); - filterSetting.ts(tsFilterSetting); - - DemuxFilterType type{ - .mainType = DemuxFilterMainType::TS, - }; - type.subType.tsFilterType(DemuxTsFilterType::PES); - FilterConf pesFilterConf{ - .type = type, - .setting = filterSetting, - }; - filterConf[0] = pesFilterConf; - - vector goldenOutputFiles; - - ASSERT_TRUE(broadcastDataFlowTest(filterConf, goldenOutputFiles)); -} - TEST_P(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) { description("Feed ts data from frontend to recording and test with ts record filter"); From 0f15956fb53c1142b52d49b1abdc86fae3d4d6c3 Mon Sep 17 00:00:00 2001 From: Amy Date: Thu, 6 Feb 2020 19:14:28 -0800 Subject: [PATCH 0657/1022] Refactor Tuner VTS dvr and descrambler test implementation Note that we are not testing them right now Test entry will be implemented or uncomment in next Tuner develop phase Test: cuttlefish + vendor device Bug: 135708935 Change-Id: Iea72bd54c85105f74133c67433bd51f8fd07f28d (cherry picked from commit fc7cc15ebb604022c935ccedde9613dcb1c7070a) --- .../VtsHalTvTunerV1_0TargetTest.cpp | 241 +++++++----------- 1 file changed, 97 insertions(+), 144 deletions(-) diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index e8c80101ed..f693e7cff9 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -154,7 +154,7 @@ const std::vector goldenDataOutputBuffer{ }; // const uint16_t FMQ_SIZE_4K = 0x1000; -// const uint32_t FMQ_SIZE_1M = 0x100000; +const uint32_t FMQ_SIZE_1M = 0x100000; const uint32_t FMQ_SIZE_16M = 0x1000000; const uint8_t FRONTEND_EVENT_CALLBACK_WAIT_COUNT = 4; @@ -698,9 +698,9 @@ void DvrCallback::stopRecordThread() { mRecordThreadRunning = false; android::Mutex::Autolock autoLock(mRecordThreadLock); } -/******************************** End DvrCallback **********************************/ +/********************************** End DvrCallback ************************************/ -/******************************** Start Test Implementation**********************************/ +/***************************** Start Test Implementation ******************************/ class TunerHidlTest : public testing::TestWithParam { public: virtual void SetUp() override { @@ -734,7 +734,7 @@ class TunerHidlTest : public testing::TestWithParam { sp mFilterCallback; sp mDvrCallback; MQDesc mFilterMQDescriptor; - MQDesc mPlaybackMQDescriptor; + MQDesc mDvrMQDescriptor; MQDesc mRecordMQDescriptor; vector mUsedFilterIds; hidl_vec mFeIds; @@ -759,6 +759,10 @@ class TunerHidlTest : public testing::TestWithParam { AssertionResult setDemuxFrontendDataSource(uint32_t frontendId); AssertionResult closeDemux(); + AssertionResult openDvrInDemux(DvrType type); + AssertionResult configDvr(DvrSettings setting); + AssertionResult getDvrMQDescriptor(); + AssertionResult openFilterInDemux(DemuxFilterType type); AssertionResult getNewlyOpenedFilterId(uint32_t& filterId); AssertionResult configFilter(DemuxFilterSettings setting, uint32_t filterId); @@ -767,26 +771,20 @@ class TunerHidlTest : public testing::TestWithParam { AssertionResult stopFilter(uint32_t filterId); AssertionResult closeFilter(uint32_t filterId); + AssertionResult createDescrambler(); + AssertionResult closeDescrambler(); + + AssertionResult playbackDataFlowTest(vector filterConf, PlaybackConf playbackConf, + vector goldenOutputFiles); + AssertionResult recordDataFlowTest(vector filterConf, + RecordSettings recordSetting, + vector goldenOutputFiles); AssertionResult broadcastDataFlowTest(vector goldenOutputFiles); - ::testing::AssertionResult getPlaybackMQDescriptor(); - ::testing::AssertionResult addPlaybackToDemux(PlaybackSettings setting); - ::testing::AssertionResult getRecordMQDescriptor(); - ::testing::AssertionResult addRecordToDemux(RecordSettings setting); - ::testing::AssertionResult createDescrambler(); - ::testing::AssertionResult closeDescrambler(); - - ::testing::AssertionResult playbackDataFlowTest(vector filterConf, - PlaybackConf playbackConf, - vector goldenOutputFiles); - ::testing::AssertionResult recordDataFlowTest(vector filterConf, - RecordSettings recordSetting, - vector goldenOutputFiles); - FilterEventType getFilterEventType(DemuxFilterType type); }; -/*============================Start Frontend APIs Tests Implementation============================*/ +/*========================== Start Frontend APIs Tests Implementation ==========================*/ AssertionResult TunerHidlTest::getFrontendIds() { Result status; mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { @@ -865,9 +863,9 @@ AssertionResult TunerHidlTest::closeFrontend() { mFrontendCallback = nullptr; return AssertionResult(status == Result::SUCCESS); } -/*============================End Frontend APIs Tests Implementation============================*/ +/*=========================== End Frontend APIs Tests Implementation ===========================*/ -/*============================Start Demux APIs Tests Implementation============================*/ +/*============================ Start Demux APIs Tests Implementation ============================*/ AssertionResult TunerHidlTest::openDemux() { Result status; mService->openDemux([&](Result result, uint32_t demuxId, const sp& demux) { @@ -912,9 +910,9 @@ AssertionResult TunerHidlTest::openFilterInDemux(DemuxFilterType type) { return AssertionResult(status == Result::SUCCESS); } -/*============================End Demux APIs Tests Implementation============================*/ +/*============================ End Demux APIs Tests Implementation ============================*/ -/*============================Start Filter APIs Tests Implementation============================*/ +/*=========================== Start Filter APIs Tests Implementation ===========================*/ AssertionResult TunerHidlTest::getNewlyOpenedFilterId(uint32_t& filterId) { Result status; EXPECT_TRUE(mDemux) << "Test with openDemux first."; @@ -989,131 +987,79 @@ AssertionResult TunerHidlTest::closeFilter(uint32_t filterId) { } return AssertionResult(status == Result::SUCCESS); } -/*============================End Filter APIs Tests Implementation============================*/ +/*=========================== End Filter APIs Tests Implementation ===========================*/ -/*::testing::AssertionResult TunerHidlTest::createDescrambler() { +/*======================== Start Descrambler APIs Tests Implementation ========================*/ +AssertionResult TunerHidlTest::createDescrambler() { Result status; - + EXPECT_TRUE(mDemux) << "Test with openDemux first."; mService->openDescrambler([&](Result result, const sp& descrambler) { mDescrambler = descrambler; status = result; }); if (status != Result::SUCCESS) { - return ::testing::AssertionFailure(); - } - - if (!mDemux && createDemux() == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); + return failure(); } status = mDescrambler->setDemuxSource(mDemuxId); if (status != Result::SUCCESS) { - return ::testing::AssertionFailure(); + return failure(); } // Test if demux source can be set more than once. status = mDescrambler->setDemuxSource(mDemuxId); - return ::testing::AssertionResult(status == Result::INVALID_STATE); + return AssertionResult(status == Result::INVALID_STATE); } -::testing::AssertionResult TunerHidlTest::closeDescrambler() { +AssertionResult TunerHidlTest::closeDescrambler() { Result status; - if (!mDescrambler && createDescrambler() == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); + if (!mDescrambler && createDescrambler() == failure()) { + return failure(); } status = mDescrambler->close(); mDescrambler = nullptr; - return ::testing::AssertionResult(status == Result::SUCCESS); + return AssertionResult(status == Result::SUCCESS); } +/*========================= End Descrambler APIs Tests Implementation =========================*/ -::testing::AssertionResult TunerHidlTest::addPlaybackToDemux(PlaybackSettings setting) { +/*============================ Start Dvr APIs Tests Implementation ============================*/ +AssertionResult TunerHidlTest::openDvrInDemux(DvrType type) { Result status; - - if (!mDemux && createDemux() == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); - } + EXPECT_TRUE(mDemux) << "Test with openDemux first."; // Create dvr callback mDvrCallback = new DvrCallback(); - // Add playback input to the local demux - mDemux->openDvr(DvrType::PLAYBACK, FMQ_SIZE_1M, mDvrCallback, - [&](Result result, const sp& dvr) { - mDvr = dvr; - status = result; - }); - - if (status != Result::SUCCESS) { - return ::testing::AssertionFailure(); - } - - DvrSettings dvrSetting; - dvrSetting.playback(setting); - status = mDvr->configure(dvrSetting); - - return ::testing::AssertionResult(status == Result::SUCCESS); -} - -::testing::AssertionResult TunerHidlTest::getPlaybackMQDescriptor() { - Result status; - - if ((!mDemux && createDemux() == ::testing::AssertionFailure()) || !mDvr) { - return ::testing::AssertionFailure(); - } - - mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) { - mPlaybackMQDescriptor = dvrMQDesc; + mDemux->openDvr(type, FMQ_SIZE_1M, mDvrCallback, [&](Result result, const sp& dvr) { + mDvr = dvr; status = result; }); - return ::testing::AssertionResult(status == Result::SUCCESS); + return AssertionResult(status == Result::SUCCESS); } -::testing::AssertionResult TunerHidlTest::addRecordToDemux(RecordSettings setting) { - Result status; +AssertionResult TunerHidlTest::configDvr(DvrSettings setting) { + Result status = mDvr->configure(setting); - if (!mDemux && createDemux() == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); - } - - // Create dvr callback - mDvrCallback = new DvrCallback(); - - // Add playback input to the local demux - mDemux->openDvr(DvrType::RECORD, FMQ_SIZE_1M, mDvrCallback, - [&](Result result, const sp& dvr) { - mDvr = dvr; - status = result; - }); - - if (status != Result::SUCCESS) { - return ::testing::AssertionFailure(); - } - - DvrSettings dvrSetting; - dvrSetting.record(setting); - status = mDvr->configure(dvrSetting); - - return ::testing::AssertionResult(status == Result::SUCCESS); + return AssertionResult(status == Result::SUCCESS); } -::testing::AssertionResult TunerHidlTest::getRecordMQDescriptor() { +AssertionResult TunerHidlTest::getDvrMQDescriptor() { Result status; - - if ((!mDemux && createDemux() == ::testing::AssertionFailure()) || !mDvr) { - return ::testing::AssertionFailure(); - } + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + EXPECT_TRUE(mDvr) << "Test with openDvr first."; mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) { - mRecordMQDescriptor = dvrMQDesc; + mDvrMQDescriptor = dvrMQDesc; status = result; }); - return ::testing::AssertionResult(status == Result::SUCCESS); -}*/ + return AssertionResult(status == Result::SUCCESS); +} +/*============================ End Dvr APIs Tests Implementation ============================*/ -/*============================Start Data Flow Tests Implementation============================*/ +/*========================== Start Data Flow Tests Implementation ==========================*/ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutputFiles*/) { EXPECT_TRUE(mFrontend) << "Test with openFilterInDemux first."; EXPECT_TRUE(mDemux) << "Test with openDemux first."; @@ -1130,7 +1076,7 @@ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutp /* * TODO: re-enable the tests after finalizing the test refactoring. */ -/*::testing::AssertionResult TunerHidlTest::playbackDataFlowTest( +/*AssertionResult TunerHidlTest::playbackDataFlowTest( vector filterConf, PlaybackConf playbackConf, vector \/\*goldenOutputFiles\*\/) { Result status; @@ -1138,10 +1084,10 @@ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutp // Filter Configuration Module for (int i = 0; i < filterConf.size(); i++) { if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) == - ::testing::AssertionFailure() || + failure() || // TODO use a map to save the FMQs/EvenFlags and pass to callback - getFilterMQDescriptor() == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); + getFilterMQDescriptor() == failure()) { + return failure(); } filterIdsSize = mUsedFilterIds.size(); mUsedFilterIds.resize(filterIdsSize + 1); @@ -1152,25 +1098,25 @@ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutp // mDemuxCallback->updateGoldenOutputMap(goldenOutputFiles[i]); status = mFilter->start(); if (status != Result::SUCCESS) { - return ::testing::AssertionFailure(); + return failure(); } } // Playback Input Module PlaybackSettings playbackSetting = playbackConf.setting; - if (addPlaybackToDemux(playbackSetting) == ::testing::AssertionFailure() || - getPlaybackMQDescriptor() == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); + if (addPlaybackToDemux(playbackSetting) == failure() || + getPlaybackMQDescriptor() == failure()) { + return failure(); } for (int i = 0; i <= filterIdsSize; i++) { if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) { - return ::testing::AssertionFailure(); + return failure(); } } mDvrCallback->startPlaybackInputThread(playbackConf, mPlaybackMQDescriptor); status = mDvr->start(); if (status != Result::SUCCESS) { - return ::testing::AssertionFailure(); + return failure(); } // Data Verify Module @@ -1183,11 +1129,11 @@ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutp // Clean Up Module for (int i = 0; i <= filterIdsSize; i++) { if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) { - return ::testing::AssertionFailure(); + return failure(); } } if (mDvr->stop() != Result::SUCCESS) { - return ::testing::AssertionFailure(); + return failure(); } mUsedFilterIds.clear(); mFilterCallbacks.clear(); @@ -1195,10 +1141,11 @@ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutp return closeDemux(); } -::testing::AssertionResult TunerHidlTest::recordDataFlowTest(vector filterConf, - RecordSettings recordSetting, - vector -\/\*goldenOutputFiles\*\/) { Result status; hidl_vec feIds; +AssertionResult TunerHidlTest::recordDataFlowTest(vector filterConf, + RecordSettings recordSetting, + vector goldenOutputFiles) { + Result status; + hidl_vec feIds; mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { status = result; @@ -1207,7 +1154,7 @@ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutp if (feIds.size() == 0) { ALOGW("[ WARN ] Frontend isn't available"); - return ::testing::AssertionFailure(); + return failure(); } FrontendDvbtSettings dvbt{ @@ -1220,10 +1167,10 @@ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutp // Filter Configuration Module for (int i = 0; i < filterConf.size(); i++) { if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) == - ::testing::AssertionFailure() || + failure() || // TODO use a map to save the FMQs/EvenFlags and pass to callback - getFilterMQDescriptor() == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); + getFilterMQDescriptor() == failure()) { + return failure(); } filterIdsSize = mUsedFilterIds.size(); mUsedFilterIds.resize(filterIdsSize + 1); @@ -1232,24 +1179,24 @@ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutp } // Record Config Module - if (addRecordToDemux(recordSetting) == ::testing::AssertionFailure() || - getRecordMQDescriptor() == ::testing::AssertionFailure()) { - return ::testing::AssertionFailure(); + if (addRecordToDemux(recordSetting) == failure() || + getRecordMQDescriptor() == failure()) { + return failure(); } for (int i = 0; i <= filterIdsSize; i++) { if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) { - return ::testing::AssertionFailure(); + return failure(); } } mDvrCallback->startRecordOutputThread(recordSetting, mRecordMQDescriptor); status = mDvr->start(); if (status != Result::SUCCESS) { - return ::testing::AssertionFailure(); + return failure(); } - if (createDemuxWithFrontend(feIds[0], settings) != ::testing::AssertionSuccess()) { - return ::testing::AssertionFailure(); + if (setDemuxFrontendDataSource(feIds[0]) != success()) { + return failure(); } // Data Verify Module @@ -1258,20 +1205,20 @@ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutp // Clean Up Module for (int i = 0; i <= filterIdsSize; i++) { if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) { - return ::testing::AssertionFailure(); + return failure(); } } if (mFrontend->stopTune() != Result::SUCCESS) { - return ::testing::AssertionFailure(); + return failure(); } mUsedFilterIds.clear(); mFilterCallbacks.clear(); mFilters.clear(); return closeDemux(); }*/ -/*============================End Data Flow Tests Implementation============================*/ +/*========================= End Data Flow Tests Implementation =========================*/ -/*============================Start Helper Functions============================*/ +/*=============================== Start Helper Functions ===============================*/ FilterEventType TunerHidlTest::getFilterEventType(DemuxFilterType type) { FilterEventType eventType = FilterEventType::UNDEFINED; switch (type.mainType) { @@ -1318,11 +1265,11 @@ FilterEventType TunerHidlTest::getFilterEventType(DemuxFilterType type) { } return eventType; } -/*============================End Helper Functions============================*/ -/******************************** End Test Implementation**********************************/ +/*============================== End Helper Functions ==============================*/ +/***************************** End Test Implementation *****************************/ -/******************************** Start Test Entry**********************************/ -/*============================Start Frontend Tests============================*/ +/******************************** Start Test Entry **********************************/ +/*============================== Start Frontend Tests ==============================*/ TEST_P(TunerHidlTest, getFrontendIds) { description("Get Frontend ids and verify frontends exist"); ASSERT_TRUE(getFrontendIds()); @@ -1380,9 +1327,9 @@ TEST_P(TunerHidlTest, AutoScanFrontend) { break; } } -/*============================End Frontend Tests============================*/ +/*=============================== End Frontend Tests ===============================*/ -/*============================Start Demux/Filter Tests============================*/ +/*============================ Start Demux/Filter Tests ============================*/ TEST_P(TunerHidlTest, OpenDemuxWithFrontendDataSource) { description("Open Demux with a Frontend as its data source."); ASSERT_TRUE(getFrontendIds()); @@ -1454,8 +1401,12 @@ TEST_P(TunerHidlTest, StartFilterInDemux) { break; } } -/*============================End Demux/Filter Tests============================*/ +/*============================ End Demux/Filter Tests ============================*/ +/*============================ Start Descrambler Tests ============================*/ +/* + * TODO: re-enable the tests after finalizing the test refactoring. + */ /*TEST_P(TunerHidlTest, CreateDescrambler) { description("Create Descrambler"); ASSERT_TRUE(createDescrambler()); @@ -1465,8 +1416,9 @@ TEST_P(TunerHidlTest, CloseDescrambler) { description("Close Descrambler"); ASSERT_TRUE(closeDescrambler()); }*/ +/*============================== End Descrambler Tests ==============================*/ -/*============================Start Data Flow Tests============================*/ +/*============================== Start Data Flow Tests ==============================*/ TEST_P(TunerHidlTest, BroadcastDataFlowWithAudioFilterTest) { description("Open Demux with a Frontend as its data source."); ASSERT_TRUE(getFrontendIds()); @@ -1583,7 +1535,8 @@ TEST_P(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) { ASSERT_TRUE(recordDataFlowTest(filterConf, recordSetting, goldenOutputFiles)); }*/ -/******************************** End Test Entry**********************************/ +/*============================== End Data Flow Tests ==============================*/ +/******************************** End Test Entry **********************************/ } // namespace INSTANTIATE_TEST_SUITE_P( From 67829613c08b3ee3fd1d85f818fa9fca1fc43d61 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Fri, 28 Feb 2020 09:37:17 -0800 Subject: [PATCH 0658/1022] gralloc4-vts: RGBA_8888 sampleIncrementInBits should be 32 SampleIncrementInBits is the delta between samples not components. It should be 32 for RGBA_8888. Test: VtsHalGraphicsMapperV4_0 Bug: 150461327 Change-Id: Idf283b93cd0243fa33eabac23185c513825d83ca --- .../4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 295ba3668b..6cc5e34326 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -221,7 +221,7 @@ class GraphicsMapperHidlTest case PlaneLayoutComponentType::Y: ASSERT_EQ(nullptr, outYCbCr->y); ASSERT_EQ(8, planeLayoutComponent.sizeInBits); - ASSERT_EQ(8, planeLayout.sampleIncrementInBits); + ASSERT_EQ(32, planeLayout.sampleIncrementInBits); outYCbCr->y = tmpData; outYCbCr->ystride = planeLayout.strideInBytes; break; From 4c23d2faaf1615aa4ce37aa1b22ad35372358301 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Fri, 28 Feb 2020 09:51:21 -0800 Subject: [PATCH 0659/1022] graphics-common: fix documentation typo Bug: 149049926 Test: Compiles Change-Id: I21d264376c09bcfd4394819245aa8284d0710633 --- .../android/hardware/graphics/common/PlaneLayoutComponent.aidl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl index 3fca53b937..c04cef021b 100644 --- a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl +++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl @@ -39,7 +39,7 @@ parcelable PlaneLayoutComponent { /** * The type of this plane layout component. * - * android.hardware.graphics.common.PlaneLayoutComponent defines the standard + * android.hardware.graphics.common.PlaneLayoutComponentType defines the standard * plane layout component types. Vendors may extend this type to include any * non-standard plane layout component types. For instructions on how to * create a vendor extension, refer to ExtendableType.aidl. From 59ef89defbb4a001a5b00b6c995c6ad525b610a7 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Thu, 27 Feb 2020 10:51:04 -0800 Subject: [PATCH 0660/1022] Parameterize VtsHalEvsV1_0TargetTest Bug: 142397658 Test: VtsHalEvsV1_0Target Signed-off-by: Changyeon Jo Change-Id: Ide6f4f58b60936ca766feb3090645afedde37a4d (cherry picked from commit b46adc9493b90aa7ec306715b11a1be7944c32ff) --- automotive/evs/1.0/vts/functional/Android.bp | 2 +- .../functional/VtsHalEvsV1_0TargetTest.cpp | 70 ++++++------------- 2 files changed, 24 insertions(+), 48 deletions(-) diff --git a/automotive/evs/1.0/vts/functional/Android.bp b/automotive/evs/1.0/vts/functional/Android.bp index 8988bfd8b1..9f7cd3f02a 100644 --- a/automotive/evs/1.0/vts/functional/Android.bp +++ b/automotive/evs/1.0/vts/functional/Android.bp @@ -28,7 +28,7 @@ cc_test { "android.hardware.automotive.evs@1.0", "android.hardware.automotive.evs@common-default-lib", ], - test_suites: ["general-tests"], + test_suites: ["vts-core"], cflags: [ "-O0", "-g", diff --git a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp index f7580f02a8..54862a2ccb 100644 --- a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp +++ b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp @@ -17,15 +17,6 @@ #define LOG_TAG "VtsHalEvsTest" -// Note: We have't got a great way to indicate which target -// should be tested, so we'll leave the interface served by the -// default (mock) EVS driver here for easy reference. All -// actual EVS drivers should serve on the EvsEnumeratorHw name, -// however, so the code is checked in that way. -//const static char kEnumeratorName[] = "EvsEnumeratorHw-Mock"; -const static char kEnumeratorName[] = "EvsEnumeratorHw"; - - // These values are called out in the EVS design doc (as of Mar 8, 2017) static const int kMaxStreamStartMilliseconds = 500; static const int kMinimumFramesPerSecond = 10; @@ -53,8 +44,9 @@ static const float kNanoToSeconds = 0.000000001f; #include #include -#include -#include +#include +#include +#include using namespace ::android::hardware::automotive::evs::V1_0; using ::android::hardware::Return; @@ -64,32 +56,19 @@ using ::android::hardware::hidl_handle; using ::android::hardware::hidl_string; using ::android::sp; -// Test environment for Evs HIDL HAL. -class EvsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static EvsHidlEnvironment* Instance() { - static EvsHidlEnvironment* instance = new EvsHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { registerTestService(); } - - private: - EvsHidlEnvironment() {} -}; - // The main test class for EVS -class EvsHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class EvsHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { // Make sure we can connect to the enumerator - string service_name = - EvsHidlEnvironment::Instance()->getServiceName(kEnumeratorName); - pEnumerator = getService(service_name); + std::string service_name = GetParam(); + pEnumerator = IEvsEnumerator::getService(service_name); + ASSERT_NE(pEnumerator.get(), nullptr); - mIsHwModule = !service_name.compare(kEnumeratorName); + // "default" is reserved for EVS manager. + constexpr static char kEvsManagerName[] = "default"; + mIsHwModule = service_name.compare(kEvsManagerName); } virtual void TearDown() override {} @@ -130,7 +109,7 @@ protected: * Opens each camera reported by the enumerator and then explicitly closes it via a * call to closeCamera. Then repeats the test to ensure all cameras can be reopened. */ -TEST_F(EvsHidlTest, CameraOpenClean) { +TEST_P(EvsHidlTest, CameraOpenClean) { ALOGI("Starting CameraOpenClean test"); // Get the camera list @@ -162,7 +141,7 @@ TEST_F(EvsHidlTest, CameraOpenClean) { * call. This ensures that the intended "aggressive open" behavior works. This is necessary for * the system to be tolerant of shutdown/restart race conditions. */ -TEST_F(EvsHidlTest, CameraOpenAggressive) { +TEST_P(EvsHidlTest, CameraOpenAggressive) { ALOGI("Starting CameraOpenAggressive test"); // Get the camera list @@ -216,7 +195,7 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { * DisplayOpen: * Test both clean shut down and "aggressive open" device stealing behavior. */ -TEST_F(EvsHidlTest, DisplayOpen) { +TEST_P(EvsHidlTest, DisplayOpen) { ALOGI("Starting DisplayOpen test"); // Request exclusive access to the EVS display, then let it go @@ -264,7 +243,7 @@ TEST_F(EvsHidlTest, DisplayOpen) { * Validate that display states transition as expected and can be queried from either the display * object itself or the owning enumerator. */ -TEST_F(EvsHidlTest, DisplayStates) { +TEST_P(EvsHidlTest, DisplayStates) { ALOGI("Starting DisplayStates test"); // Ensure the display starts in the expected state @@ -324,7 +303,7 @@ TEST_F(EvsHidlTest, DisplayStates) { * CameraStreamPerformance: * Measure and qualify the stream start up time and streaming frame rate of each reported camera */ -TEST_F(EvsHidlTest, CameraStreamPerformance) { +TEST_P(EvsHidlTest, CameraStreamPerformance) { ALOGI("Starting CameraStreamPerformance test"); // Get the camera list @@ -387,7 +366,7 @@ TEST_F(EvsHidlTest, CameraStreamPerformance) { * Ensure the camera implementation behaves properly when the client holds onto buffers for more * than one frame time. The camera must cleanly skip frames until the client is ready again. */ -TEST_F(EvsHidlTest, CameraStreamBuffering) { +TEST_P(EvsHidlTest, CameraStreamBuffering) { ALOGI("Starting CameraStreamBuffering test"); // Arbitrary constant (should be > 1 and less than crazy) @@ -456,7 +435,7 @@ TEST_F(EvsHidlTest, CameraStreamBuffering) { * imagery is simply copied to the display buffer and presented on screen. This is the one test * which a human could observe to see the operation of the system on the physical display. */ -TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { +TEST_P(EvsHidlTest, CameraToDisplayRoundTrip) { ALOGI("Starting CameraToDisplayRoundTrip test"); // Get the camera list @@ -517,7 +496,7 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { * Verify that each client can start and stop video streams on the same * underlying camera. */ -TEST_F(EvsHidlTest, MultiCameraStream) { +TEST_P(EvsHidlTest, MultiCameraStream) { ALOGI("Starting MultiCameraStream test"); if (mIsHwModule) { @@ -601,11 +580,8 @@ TEST_F(EvsHidlTest, MultiCameraStream) { } -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - EvsHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); - return status; -} +INSTANTIATE_TEST_SUITE_P( + PerInstance, + EvsHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEvsEnumerator::descriptor)), + android::hardware::PrintInstanceNameToString); From 70cf2268a4b2c5e9c5f6394479276ba91e24180e Mon Sep 17 00:00:00 2001 From: "Harpreet \\\"Eli\\\" Sangha" Date: Tue, 4 Feb 2020 12:10:45 +0900 Subject: [PATCH 0661/1022] vibrator: Document the source of always-on source IDs. Bug: 148617686 Test: N/A: Documentation change. Change-Id: I471d394e0c0258fbdaaea27a50ed21c4c10123a7 Signed-off-by: Harpreet \"Eli\" Sangha --- .../aidl/android/hardware/vibrator/IVibrator.aidl | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl index 06a8bf5c17..6489c1d600 100644 --- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl +++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl @@ -202,6 +202,12 @@ interface IVibrator { * once enabled and assigned an effect to play. This may not be supported * and this support is reflected in getCapabilities (CAP_ALWAYS_ON_CONTROL). * + * The always-on source ID is conveyed directly to clients through + * device/board configuration files ensuring that no ID is assigned to + * multiple clients. No client should use this API unless explicitly + * assigned an always-on source ID. Clients must develop their own way to + * get IDs from vendor in a stable way. + * * @param id The device-specific always-on source ID to enable. * @param effect The type of haptic event to trigger. * @param strength The intensity of haptic event to trigger. @@ -212,6 +218,12 @@ interface IVibrator { * Disable an always-on haptic source. This may not be supported and this * support is reflected in getCapabilities (CAP_ALWAYS_ON_CONTROL). * + * The always-on source ID is conveyed directly to clients through + * device/board configuration files ensuring that no ID is assigned to + * multiple clients. No client should use this API unless explicitly + * assigned an always-on source ID. Clients must develop their own way to + * get IDs from vendor in a stable way. + * * @param id The device-specific always-on source ID to disable. */ void alwaysOnDisable(in int id); From dafc9a99e9e65d7c7f28ee282b595278929d22d3 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Tue, 25 Feb 2020 16:21:44 -0800 Subject: [PATCH 0662/1022] Update 1.5 IRadio interface with missing structs/functions Structs: AppStatus, CardStatus Responses: getDataCallListResponse_1_5, getIccCardStatusResponse_1_5 Indications: dataCallListChanged_1_5 Update VTS tests to use 1.5 CardStatus Test: build cf_x86_phone-userdebug Bug: 150246280 Change-Id: Ib26c6df804d99f2487e2bfa7b302a98fa25f55e1 --- current.txt | 6 +- radio/1.5/IRadioIndication.hal | 17 +++++ radio/1.5/IRadioResponse.hal | 30 +++++++- radio/1.5/types.hal | 19 +++++ .../1.5/vts/functional/radio_hidl_hal_api.cpp | 66 ++++++++-------- .../vts/functional/radio_hidl_hal_test.cpp | 2 +- .../functional/radio_hidl_hal_utils_v1_5.h | 14 +++- radio/1.5/vts/functional/radio_indication.cpp | 75 ++++++++++--------- radio/1.5/vts/functional/radio_response.cpp | 22 +++++- 9 files changed, 174 insertions(+), 77 deletions(-) diff --git a/current.txt b/current.txt index 42981ade22..a6f35ba95f 100644 --- a/current.txt +++ b/current.txt @@ -702,10 +702,10 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar 2ce1f7fb52e49f80b13a9b153d491bce530552f02357ea729acae922a8659f93 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback 77531c8d048f8f8ae532babd0ca86332a865ec9aace1b051226ef2b21123e645 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types -99f5c26b952271d1246c957e1d0271fa39445ee65cc93aa7c187834f98914a33 android.hardware.radio@1.5::types +e7669bddacbdaee2cd9a87762a13fb7648639eead54bf4d767dc06eaaeb35736 android.hardware.radio@1.5::types b454df853441c12f6e425e8a60dd29fda20f5e6e39b93d1103e4b37495db38aa android.hardware.radio@1.5::IRadio -e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication -829d3827eeb5a8f563e80fe627419b3231012fc02bc2e79782ec5e9ad9f799a4 android.hardware.radio@1.5::IRadioResponse +fcbb0742a88215ee7a6d7ce0825d253eb2b50391fc6c8c48667f9fd7f6d4549e android.hardware.radio@1.5::IRadioIndication +b809193970a91ca637a4b0184767315601d32e3ef3d5992ffbc7a8d14a14f015 android.hardware.radio@1.5::IRadioResponse 3ca6616381080bdd6c08141ad12775a94ae868c58b02b1274ae3326f7de724ab android.hardware.sensors@2.1::ISensors 3d4141c6373cd9ca02fe221a7d12343840de2255d032c38248fe8e35816b58b2 android.hardware.sensors@2.1::ISensorsCallback 8051cc50fc90ed447f058a8b15d81f35a65f1bd9004b1de4f127edeb89b47978 android.hardware.sensors@2.1::types diff --git a/radio/1.5/IRadioIndication.hal b/radio/1.5/IRadioIndication.hal index c40b473765..58e988f7dd 100644 --- a/radio/1.5/IRadioIndication.hal +++ b/radio/1.5/IRadioIndication.hal @@ -95,4 +95,21 @@ interface IRadioIndication extends @1.4::IRadioIndication { * CellInfo. */ oneway networkScanResult_1_5(RadioIndicationType type, NetworkScanResult result); + + /** + * Indicates data call contexts have changed. + * + * This indication is updated from IRadioIndication@1.4 to report the @1.5 version of + * SetupDataCallResult. + * + * @param type Type of radio indication + * @param dcList Array of SetupDataCallResult identical to that returned by + * IRadio.getDataCallList(). It is the complete list of current data contexts including + * new contexts that have been activated. A data call is only removed from this list + * when below conditions matched. + * 1. The framework sends a IRadio.deactivateDataCall(). + * 2. The radio is powered off/on. + * 3. Unsolicited disconnect from either modem or network side. + */ + oneway dataCallListChanged_1_5(RadioIndicationType type, vec dcList); }; diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal index e87cad25fc..1380da32a9 100644 --- a/radio/1.5/IRadioResponse.hal +++ b/radio/1.5/IRadioResponse.hal @@ -20,6 +20,7 @@ import @1.0::RadioResponseInfo; import @1.0::SendSmsResult; import @1.4::IRadioResponse; import @1.5::BarringInfo; +import @1.5::CardStatus; import @1.5::CellIdentity; import @1.5::CellInfo; import @1.5::PersoSubstate; @@ -118,6 +119,20 @@ interface IRadioResponse extends @1.4::IRadioResponse { */ oneway setupDataCallResponse_1_5(RadioResponseInfo info, SetupDataCallResult dcResponse); + /** + * @param info Response info struct containing response type, serial no. and error + * @param dcResponse List of SetupDataCallResult as defined in types.hal + * + * Valid errors returned: + * RadioError:NONE + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:INTERNAL_ERR + * RadioError:NO_RESOURCES + * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:SIM_ABSENT + */ + oneway getDataCallListResponse_1_5(RadioResponseInfo info, vec dcResponse); + /** * @param info Response info struct containing response type, serial no. and error * @@ -303,5 +318,18 @@ interface IRadioResponse extends @1.4::IRadioResponse { * RadioError:REQUEST_NOT_SUPPORTED */ oneway supplySimDepersonalizationResponse(RadioResponseInfo info, - PersoSubstate persoType, int32_t remainingRetries); + PersoSubstate persoType, int32_t remainingRetries); + + /** + * @param info Response info struct containing response type, serial no. and error + * @param cardStatus ICC card status as defined by CardStatus in types.hal + * + * Valid errors returned: + * RadioError:NONE + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:INTERNAL_ERR + * RadioError:NO_RESOURCES + * RadioError:REQUEST_NOT_SUPPORTED + */ + oneway getIccCardStatusResponse_1_5(RadioResponseInfo info, CardStatus cardStatus); }; diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index 4d3c2d550c..45f3b9074f 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -17,6 +17,7 @@ package android.hardware.radio@1.5; import @1.0::ApnAuthType; +import @1.0::AppStatus; import @1.0::DataProfileId; import @1.0::DataProfileInfoType; import @1.0::GsmSignalStrength; @@ -43,6 +44,7 @@ import @1.2::TdscdmaSignalStrength; import @1.2::WcdmaSignalStrength; import @1.4::AccessNetwork; import @1.4::ApnTypes; +import @1.4::CardStatus; import @1.4::CellIdentityNr; import @1.4::DataCallFailCause; import @1.4::DataConnActiveStatus; @@ -1034,3 +1036,20 @@ enum PersoSubstate : @1.0::PersoSubstate { SIM_NS_SP, SIM_NS_SP_PUK, }; + +/** Extended from @1.0::AppStatus to update PersoSubstate to 1.5 version. */ +struct AppStatus { + @1.0::AppStatus base; + + /** Applicable only if appState == SUBSCRIPTION_PERSO */ + PersoSubstate persoSubstate; +}; + + +/** Extended from @1.4::CardStatus to use 1.5 version of AppStatus. */ +struct CardStatus { + @1.4::CardStatus base; + + /** size <= RadioConst::CARD_MAX_APPS */ + vec applications; +}; diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp index 003f58e7a5..32c02cb137 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp @@ -408,7 +408,7 @@ TEST_P(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_Geran) { */ TEST_P(RadioHidlTest_v1_5, togglingUiccApplicationsSimAbsent) { // This test case only test SIM ABSENT case. - if (cardStatus.base.base.cardState != CardState::ABSENT) return; + if (cardStatus.base.base.base.cardState != CardState::ABSENT) return; // Disable Uicc applications. serial = GetRandomSerialNumber(); @@ -435,7 +435,7 @@ TEST_P(RadioHidlTest_v1_5, togglingUiccApplicationsSimAbsent) { */ TEST_P(RadioHidlTest_v1_5, togglingUiccApplicationsSimPresent) { // This test case only test SIM ABSENT case. - if (cardStatus.base.base.cardState != CardState::PRESENT) return; + if (cardStatus.base.base.base.cardState != CardState::PRESENT) return; // Disable Uicc applications. serial = GetRandomSerialNumber(); @@ -489,9 +489,9 @@ TEST_P(RadioHidlTest_v1_5, areUiccApplicationsEnabled) { // If SIM is absent, RadioError::SIM_ABSENT should be thrown. Otherwise there shouldn't be any // error. - if (cardStatus.base.base.cardState == CardState::ABSENT) { + if (cardStatus.base.base.base.cardState == CardState::ABSENT) { EXPECT_EQ(RadioError::SIM_ABSENT, radioRsp_v1_5->rspInfo.error); - } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) { EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error); } } @@ -563,9 +563,9 @@ TEST_P(RadioHidlTest_v1_5, startNetworkScan) { EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); ALOGI("startNetworkScan, rspInfo.error = %s\n", toString(radioRsp_v1_5->rspInfo.error).c_str()); - if (cardStatus.base.base.cardState == CardState::ABSENT) { + if (cardStatus.base.base.base.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::SIM_ABSENT})); - } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) { // OPERATION_NOT_ALLOWED should not be allowed; however, some vendors do // not support the required manual GSM search functionality. This is // tracked in b/112206766. Modems have "GSM" rat scan need to @@ -592,10 +592,10 @@ TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidArgument) { ALOGI("startNetworkScan_InvalidArgument, rspInfo.error = %s\n", toString(radioRsp_v1_5->rspInfo.error).c_str()); - if (cardStatus.base.base.cardState == CardState::ABSENT) { + if (cardStatus.base.base.base.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); - } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_v1_5->rspInfo.error, {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); @@ -631,10 +631,10 @@ TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidInterval1) { EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); ALOGI("startNetworkScan_InvalidInterval1, rspInfo.error = %s\n", toString(radioRsp_v1_5->rspInfo.error).c_str()); - if (cardStatus.base.base.cardState == CardState::ABSENT) { + if (cardStatus.base.base.base.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); - } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_v1_5->rspInfo.error, {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); @@ -670,10 +670,10 @@ TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidInterval2) { EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); ALOGI("startNetworkScan_InvalidInterval2, rspInfo.error = %s\n", toString(radioRsp_v1_5->rspInfo.error).c_str()); - if (cardStatus.base.base.cardState == CardState::ABSENT) { + if (cardStatus.base.base.base.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); - } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_v1_5->rspInfo.error, {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); @@ -709,10 +709,10 @@ TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidMaxSearchTime1) { EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); ALOGI("startNetworkScan_InvalidMaxSearchTime1, rspInfo.error = %s\n", toString(radioRsp_v1_5->rspInfo.error).c_str()); - if (cardStatus.base.base.cardState == CardState::ABSENT) { + if (cardStatus.base.base.base.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); - } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_v1_5->rspInfo.error, {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); @@ -748,10 +748,10 @@ TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidMaxSearchTime2) { EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); ALOGI("startNetworkScan_InvalidMaxSearchTime2, rspInfo.error = %s\n", toString(radioRsp_v1_5->rspInfo.error).c_str()); - if (cardStatus.base.base.cardState == CardState::ABSENT) { + if (cardStatus.base.base.base.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); - } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_v1_5->rspInfo.error, {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); @@ -787,10 +787,10 @@ TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidPeriodicity1) { EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); ALOGI("startNetworkScan_InvalidPeriodicity1, rspInfo.error = %s\n", toString(radioRsp_v1_5->rspInfo.error).c_str()); - if (cardStatus.base.base.cardState == CardState::ABSENT) { + if (cardStatus.base.base.base.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); - } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_v1_5->rspInfo.error, {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); @@ -826,10 +826,10 @@ TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidPeriodicity2) { EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); ALOGI("startNetworkScan_InvalidPeriodicity2, rspInfo.error = %s\n", toString(radioRsp_v1_5->rspInfo.error).c_str()); - if (cardStatus.base.base.cardState == CardState::ABSENT) { + if (cardStatus.base.base.base.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); - } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_v1_5->rspInfo.error, {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); @@ -865,10 +865,10 @@ TEST_P(RadioHidlTest_v1_5, startNetworkScan_GoodRequest1) { EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); ALOGI("startNetworkScan_GoodRequest1, rspInfo.error = %s\n", toString(radioRsp_v1_5->rspInfo.error).c_str()); - if (cardStatus.base.base.cardState == CardState::ABSENT) { + if (cardStatus.base.base.base.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE, RadioError::SIM_ABSENT})); - } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE, RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); @@ -905,10 +905,10 @@ TEST_P(RadioHidlTest_v1_5, startNetworkScan_GoodRequest2) { EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); ALOGI("startNetworkScan_GoodRequest2, rspInfo.error = %s\n", toString(radioRsp_v1_5->rspInfo.error).c_str()); - if (cardStatus.base.base.cardState == CardState::ABSENT) { + if (cardStatus.base.base.base.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE, RadioError::SIM_ABSENT})); - } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE, RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); @@ -961,11 +961,11 @@ TEST_P(RadioHidlTest_v1_5, setupDataCall_1_5) { EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); - if (cardStatus.base.base.cardState == CardState::ABSENT) { + if (cardStatus.base.base.base.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE, RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW})); - } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW})); @@ -1006,10 +1006,10 @@ TEST_P(RadioHidlTest_v1_5, setInitialAttachApn_1_5) { EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); - if (cardStatus.base.base.cardState == CardState::ABSENT) { + if (cardStatus.base.base.base.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE})); - } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE})); } @@ -1053,10 +1053,10 @@ TEST_P(RadioHidlTest_v1_5, setDataProfile_1_5) { EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); - if (cardStatus.base.base.cardState == CardState::ABSENT) { + if (cardStatus.base.base.base.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE})); - } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE})); } @@ -1106,12 +1106,12 @@ TEST_P(RadioHidlTest_v1_5, setNetworkSelectionModeManual_1_5) { EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); - if (cardStatus.base.base.cardState == CardState::ABSENT) { + if (cardStatus.base.base.base.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME, RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE}, CHECK_GENERAL_ERROR)); - } else if (cardStatus.base.base.cardState == CardState::PRESENT) { + } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE}, @@ -1155,7 +1155,7 @@ TEST_P(RadioHidlTest_v1_5, sendCdmaSmsExpectMore) { EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type); EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial); - if (cardStatus.base.base.cardState == CardState::ABSENT) { + if (cardStatus.base.base.base.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_v1_5->rspInfo.error, {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT}, diff --git a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp index ca6bbeb6b7..7313de4ede 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp +++ b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp @@ -41,7 +41,7 @@ void RadioHidlTest_v1_5::SetUp() { ASSERT_NE(nullptr, radioConfig.get()); /* Enforce Vts Testing with Sim Status Present only. */ - EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.cardState); + EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.base.cardState); } /* diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h index 6488609f49..6a369cc2e2 100644 --- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h +++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h @@ -55,7 +55,7 @@ using ::android::hardware::Void; #define RADIO_SERVICE_NAME "slot1" class RadioHidlTest_v1_5; -extern ::android::hardware::radio::V1_4::CardStatus cardStatus; +extern ::android::hardware::radio::V1_5::CardStatus cardStatus; /* Callback class for radio response v1_5 */ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioResponse { @@ -556,6 +556,10 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon const RadioResponseInfo& info, const android::hardware::radio::V1_5::SetupDataCallResult& dcResponse); + Return getDataCallListResponse_1_5( + const RadioResponseInfo& info, + const hidl_vec<::android::hardware::radio::V1_5::SetupDataCallResult>& dcResponse); + Return setInitialAttachApnResponse_1_5(const RadioResponseInfo& info); Return setDataProfileResponse_1_5(const RadioResponseInfo& info); @@ -591,6 +595,10 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon Return supplySimDepersonalizationResponse( const RadioResponseInfo& info, ::android::hardware::radio::V1_5::PersoSubstate persoType, int32_t remainingRetries); + + Return getIccCardStatusResponse_1_5( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_5::CardStatus& card_status); }; /* Callback class for radio indication */ @@ -614,6 +622,10 @@ class RadioIndication_v1_5 : public ::android::hardware::radio::V1_5::IRadioIndi const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::CellInfo>& records); + Return dataCallListChanged_1_5( + RadioIndicationType type, + const hidl_vec<::android::hardware::radio::V1_5::SetupDataCallResult>& dcList); + /* 1.4 Api */ Return currentEmergencyNumberList( RadioIndicationType type, diff --git a/radio/1.5/vts/functional/radio_indication.cpp b/radio/1.5/vts/functional/radio_indication.cpp index d448a226db..1e5ce167d1 100644 --- a/radio/1.5/vts/functional/radio_indication.cpp +++ b/radio/1.5/vts/functional/radio_indication.cpp @@ -18,6 +18,46 @@ RadioIndication_v1_5::RadioIndication_v1_5(RadioHidlTest_v1_5& parent) : parent_v1_5(parent) {} +/* 1.5 Apis */ +Return RadioIndication_v1_5::uiccApplicationsEnablementChanged(RadioIndicationType /*type*/, + bool /*enabled*/) { + return Void(); +} + +Return RadioIndication_v1_5::registrationFailed( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/, + const hidl_string& /*chosenPlmn*/, + ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_5::Domain> /*domain*/, + int32_t /*causeCode*/, int32_t /*additionalCauseCode*/) { + return Void(); +} + +Return RadioIndication_v1_5::barringInfoChanged( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/, + const hidl_vec<::android::hardware::radio::V1_5::BarringInfo>& /*barringInfos*/) { + return Void(); +} + +Return RadioIndication_v1_5::networkScanResult_1_5( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_5::NetworkScanResult& /*result*/) { + return Void(); +} + +Return RadioIndication_v1_5::cellInfoList_1_5( + RadioIndicationType /*type*/, + const hidl_vec<::android::hardware::radio::V1_5::CellInfo>& /*records*/) { + return Void(); +} + +Return RadioIndication_v1_5::dataCallListChanged_1_5( + RadioIndicationType /*type*/, + const hidl_vec& /*dcList*/) { + return Void(); +} + /* 1.4 Apis */ Return RadioIndication_v1_5::currentPhysicalChannelConfigs_1_4( RadioIndicationType /*type*/, @@ -328,38 +368,3 @@ Return RadioIndication_v1_5::modemReset(RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*reason*/) { return Void(); } - -Return RadioIndication_v1_5::uiccApplicationsEnablementChanged(RadioIndicationType /*type*/, - bool /*enabled*/) { - return Void(); -} - -Return RadioIndication_v1_5::registrationFailed( - RadioIndicationType /*type*/, - const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/, - const ::android::hardware::hidl_string& /*chosenPlmn*/, - ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_5::Domain> /*domain*/, - int32_t /*causeCode*/, int32_t /*additionalCauseCode*/) { - return Void(); -} - -Return RadioIndication_v1_5::barringInfoChanged( - RadioIndicationType /*type*/, - const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/, - const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo>& - /*barringInfos*/) { - return Void(); -} - -Return RadioIndication_v1_5::networkScanResult_1_5( - RadioIndicationType /*type*/, - const ::android::hardware::radio::V1_5::NetworkScanResult& /*result*/) { - return Void(); -} - -Return RadioIndication_v1_5::cellInfoList_1_5( - RadioIndicationType /*type*/, - const ::android::hardware::hidl_vec< - ::android::hardware::radio::V1_5::CellInfo>& /*records*/) { - return Void(); -} diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp index e4f9ce8dab..8cbb2d0cce 100644 --- a/radio/1.5/vts/functional/radio_response.cpp +++ b/radio/1.5/vts/functional/radio_response.cpp @@ -16,7 +16,7 @@ #include -::android::hardware::radio::V1_4::CardStatus cardStatus; +::android::hardware::radio::V1_5::CardStatus cardStatus; RadioResponse_v1_5::RadioResponse_v1_5(RadioHidlTest_v1_5& parent) : parent_v1_5(parent) {} @@ -829,9 +829,8 @@ Return RadioResponse_v1_5::getCellInfoListResponse_1_4( Return RadioResponse_v1_5::getIccCardStatusResponse_1_4( const RadioResponseInfo& info, - const ::android::hardware::radio::V1_4::CardStatus& card_status) { + const ::android::hardware::radio::V1_4::CardStatus& /*card_status*/) { rspInfo = info; - cardStatus = card_status; parent_v1_5.notify(info.serial); return Void(); } @@ -944,6 +943,14 @@ Return RadioResponse_v1_5::setupDataCallResponse_1_5( return Void(); } +Return RadioResponse_v1_5::getDataCallListResponse_1_5( + const RadioResponseInfo& info, + const hidl_vec<::android::hardware::radio::V1_5::SetupDataCallResult>& /* dcResponse */) { + rspInfo = info; + parent_v1_5.notify(info.serial); + return Void(); +} + Return RadioResponse_v1_5::setInitialAttachApnResponse_1_5(const RadioResponseInfo& info) { rspInfo = info; parent_v1_5.notify(info.serial); @@ -1021,3 +1028,12 @@ Return RadioResponse_v1_5::supplySimDepersonalizationResponse( int32_t /*remainingRetries*/) { return Void(); } + +Return RadioResponse_v1_5::getIccCardStatusResponse_1_5( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_5::CardStatus& card_status) { + rspInfo = info; + cardStatus = card_status; + parent_v1_5.notify(info.serial); + return Void(); +} From 7d69fc8ffadb58c23ed81261c083499a9ec2d11b Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Fri, 21 Feb 2020 15:50:35 -0800 Subject: [PATCH 0663/1022] camera: Add more VTS tests for ICameraProvider@2.6 Add initial test exercising getConcurrentStreamingCameraIds() and isConcurrentSessionConfigurationSupported() Bug : 148180006 Test: VtsHalCameraProviderV2_4TargetTest --gtest_filter=PerInstance/CameraHidlTest.configureConc* on cuttlefish Change-Id: If3821ba5452d487e9a0d83d01e2da86ddf509b50 Signed-off-by: Jayant Chowdhary --- .../VtsHalCameraProviderV2_4TargetTest.cpp | 342 +++++++++++++++--- 1 file changed, 297 insertions(+), 45 deletions(-) diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 5c73aa2ab7..c9d76da2ca 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -69,65 +69,67 @@ #include using namespace ::android::hardware::camera::device; -using ::android::hardware::Return; -using ::android::hardware::Void; +using ::android::BufferItemConsumer; +using ::android::BufferQueue; +using ::android::GraphicBuffer; +using ::android::IGraphicBufferConsumer; +using ::android::IGraphicBufferProducer; +using ::android::sp; +using ::android::Surface; +using ::android::wp; using ::android::hardware::hidl_bitfield; using ::android::hardware::hidl_handle; using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; -using ::android::sp; -using ::android::wp; -using ::android::GraphicBuffer; -using ::android::IGraphicBufferProducer; -using ::android::IGraphicBufferConsumer; -using ::android::BufferQueue; -using ::android::BufferItemConsumer; -using ::android::Surface; -using ::android::hardware::graphics::common::V1_0::BufferUsage; -using ::android::hardware::graphics::common::V1_0::Dataspace; -using ::android::hardware::graphics::common::V1_0::PixelFormat; -using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; +using ::android::hardware::Return; +using ::android::hardware::Void; using ::android::hardware::camera::common::V1_0::CameraDeviceStatus; +using ::android::hardware::camera::common::V1_0::Status; using ::android::hardware::camera::common::V1_0::TorchMode; using ::android::hardware::camera::common::V1_0::TorchModeStatus; using ::android::hardware::camera::common::V1_0::helper::CameraParameters; using ::android::hardware::camera::common::V1_0::helper::Size; -using ::android::hardware::camera::provider::V2_4::ICameraProvider; -using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback; -using ::android::hardware::camera::device::V3_2::ICameraDevice; -using ::android::hardware::camera::device::V3_2::BufferCache; -using ::android::hardware::camera::device::V3_2::CaptureRequest; -using ::android::hardware::camera::device::V3_2::CaptureResult; -using ::android::hardware::camera::device::V3_2::ICameraDeviceSession; -using ::android::hardware::camera::device::V3_2::NotifyMsg; -using ::android::hardware::camera::device::V3_2::RequestTemplate; -using ::android::hardware::camera::device::V3_2::StreamType; -using ::android::hardware::camera::device::V3_2::StreamRotation; -using ::android::hardware::camera::device::V3_2::StreamConfiguration; -using ::android::hardware::camera::device::V3_2::StreamConfigurationMode; -using ::android::hardware::camera::device::V3_2::CameraMetadata; -using ::android::hardware::camera::device::V3_2::HalStreamConfiguration; -using ::android::hardware::camera::device::V3_2::BufferStatus; -using ::android::hardware::camera::device::V3_2::StreamBuffer; -using ::android::hardware::camera::device::V3_2::MsgType; -using ::android::hardware::camera::device::V3_2::ErrorMsg; -using ::android::hardware::camera::device::V3_2::ErrorCode; using ::android::hardware::camera::device::V1_0::CameraFacing; -using ::android::hardware::camera::device::V1_0::NotifyCallbackMsg; +using ::android::hardware::camera::device::V1_0::CameraFrameMetadata; using ::android::hardware::camera::device::V1_0::CommandType; using ::android::hardware::camera::device::V1_0::DataCallbackMsg; -using ::android::hardware::camera::device::V1_0::CameraFrameMetadata; -using ::android::hardware::camera::device::V1_0::ICameraDevicePreviewCallback; using ::android::hardware::camera::device::V1_0::FrameCallbackFlag; using ::android::hardware::camera::device::V1_0::HandleTimestampMessage; -using ::android::hardware::camera::metadata::V3_4::CameraMetadataEnumAndroidSensorInfoColorFilterArrangement; -using ::android::hardware::camera::metadata::V3_4::CameraMetadataTag; +using ::android::hardware::camera::device::V1_0::ICameraDevicePreviewCallback; +using ::android::hardware::camera::device::V1_0::NotifyCallbackMsg; +using ::android::hardware::camera::device::V3_2::BufferCache; +using ::android::hardware::camera::device::V3_2::BufferStatus; +using ::android::hardware::camera::device::V3_2::CameraMetadata; +using ::android::hardware::camera::device::V3_2::CaptureRequest; +using ::android::hardware::camera::device::V3_2::CaptureResult; +using ::android::hardware::camera::device::V3_2::ErrorCode; +using ::android::hardware::camera::device::V3_2::ErrorMsg; +using ::android::hardware::camera::device::V3_2::HalStreamConfiguration; +using ::android::hardware::camera::device::V3_2::ICameraDevice; +using ::android::hardware::camera::device::V3_2::ICameraDeviceSession; +using ::android::hardware::camera::device::V3_2::MsgType; +using ::android::hardware::camera::device::V3_2::NotifyMsg; +using ::android::hardware::camera::device::V3_2::RequestTemplate; +using ::android::hardware::camera::device::V3_2::StreamBuffer; +using ::android::hardware::camera::device::V3_2::StreamConfiguration; +using ::android::hardware::camera::device::V3_2::StreamConfigurationMode; +using ::android::hardware::camera::device::V3_2::StreamRotation; +using ::android::hardware::camera::device::V3_2::StreamType; using ::android::hardware::camera::device::V3_4::PhysicalCameraMetadata; -using ::android::hardware::MessageQueue; -using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::camera::metadata::V3_4:: + CameraMetadataEnumAndroidSensorInfoColorFilterArrangement; +using ::android::hardware::camera::metadata::V3_4::CameraMetadataTag; +using ::android::hardware::camera::provider::V2_4::ICameraProvider; +using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback; +using ::android::hardware::camera::provider::V2_6::CameraIdAndStreamCombination; +using ::android::hardware::graphics::common::V1_0::BufferUsage; +using ::android::hardware::graphics::common::V1_0::Dataspace; +using ::android::hardware::graphics::common::V1_0::PixelFormat; using ::android::hidl::allocator::V1_0::IAllocator; -using ::android::hidl::memory::V1_0::IMemory; using ::android::hidl::memory::V1_0::IMapper; +using ::android::hidl::memory::V1_0::IMemory; using ResultMetadataQueue = MessageQueue; using ::android::hidl::manager::V1_0::IServiceManager; @@ -554,7 +556,12 @@ public: hidl_vec getCameraDeviceNames(sp provider); - struct EmptyDeviceCb : public V3_5::ICameraDeviceCallback { + std::map getCameraDeviceIdToNameMap(sp provider); + + hidl_vec> getConcurrentDeviceCombinations( + sp<::android::hardware::camera::provider::V2_6::ICameraProvider>&); + + struct EmptyDeviceCb : public V3_5::ICameraDeviceCallback { virtual Return processCaptureResult( const hidl_vec& /*results*/) override { ALOGI("processCaptureResult callback"); @@ -591,8 +598,7 @@ public: ADD_FAILURE(); // Empty callback should not reach here return Void(); } - - }; + }; struct DeviceCb : public V3_5::ICameraDeviceCallback { DeviceCb(CameraHidlTest *parent, int deviceVersion, const camera_metadata_t *staticMeta) : @@ -808,6 +814,13 @@ public: static Status getAvailableOutputStreams(const camera_metadata_t *staticMeta, std::vector &outputStreams, const AvailableStream *threshold = nullptr); + + static Status getMaxOutputSizeForFormat(const camera_metadata_t* staticMeta, PixelFormat format, + Size* size); + + static Status getMandatoryConcurrentStreams(const camera_metadata_t* staticMeta, + std::vector* outputStreams); + static Status getJpegBufferSize(camera_metadata_t *staticMeta, uint32_t* outBufSize); static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta); @@ -1535,6 +1548,20 @@ Return CameraHidlTest::DeviceCb::returnStreamBuffers( return Void(); } +std::map CameraHidlTest::getCameraDeviceIdToNameMap( + sp provider) { + hidl_vec cameraDeviceNames = getCameraDeviceNames(provider); + std::map idToNameMap; + for (auto& name : cameraDeviceNames) { + std::string version, cameraId; + if (!matchDeviceName(name, mProviderType, &version, &cameraId)) { + ADD_FAILURE(); + } + idToNameMap.insert(std::make_pair(hidl_string(cameraId), name)); + } + return idToNameMap; +} + hidl_vec CameraHidlTest::getCameraDeviceNames(sp provider) { std::vector cameraDeviceNames; Return ret; @@ -1591,6 +1618,21 @@ hidl_vec CameraHidlTest::getCameraDeviceNames(sp p return retList; } +hidl_vec> CameraHidlTest::getConcurrentDeviceCombinations( + sp<::android::hardware::camera::provider::V2_6::ICameraProvider>& provider2_6) { + hidl_vec> combinations; + Return ret = provider2_6->getConcurrentStreamingCameraIds( + [&combinations](Status concurrentIdStatus, + const hidl_vec>& cameraDeviceIdCombinations) { + ASSERT_EQ(concurrentIdStatus, Status::OK); + combinations = cameraDeviceIdCombinations; + }); + if (!ret.isOk()) { + ADD_FAILURE(); + } + return combinations; +} + // Test devices with first_api_level >= P does not advertise device@1.0 TEST_P(CameraHidlTest, noHal1AfterP) { constexpr int32_t HAL1_PHASE_OUT_API_LEVEL = 28; @@ -3078,6 +3120,157 @@ TEST_P(CameraHidlTest, configureStreamsAvailableOutputs) { } } +// Verify that mandatory concurrent streams and outputs are supported. +TEST_P(CameraHidlTest, configureConcurrentStreamsAvailableOutputs) { + struct CameraTestInfo { + camera_metadata_t* staticMeta = nullptr; + sp session; + sp session3_3; + sp session3_4; + sp session3_5; + sp session3_6; + sp cameraDevice; + sp cameraDevice3_5; + ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5; + ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4; + ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2; + }; + if (mProvider2_6 == nullptr) { + // This test is provider@2.6 specific + ALOGW("%s provider not 2_6, skipping", __func__); + return; + } + + std::map idToNameMap = getCameraDeviceIdToNameMap(mProvider2_6); + hidl_vec> concurrentDeviceCombinations = + getConcurrentDeviceCombinations(mProvider2_6); + std::vector outputStreams; + for (const auto& cameraDeviceIds : concurrentDeviceCombinations) { + std::vector cameraIdsAndStreamCombinations; + std::vector cameraTestInfos; + size_t i = 0; + for (const auto& id : cameraDeviceIds) { + CameraTestInfo cti; + Return ret; + auto it = idToNameMap.find(id); + ASSERT_TRUE(idToNameMap.end() != it); + hidl_string name = it->second; + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) { + continue; + } else if (deviceVersion <= 0) { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + return; + } + openEmptyDeviceSession(name, mProvider2_6, &cti.session /*out*/, + &cti.staticMeta /*out*/, &cti.cameraDevice /*out*/); + castSession(cti.session, deviceVersion, &cti.session3_3, &cti.session3_4, + &cti.session3_5, &cti.session3_6); + castDevice(cti.cameraDevice, deviceVersion, &cti.cameraDevice3_5); + + outputStreams.clear(); + ASSERT_EQ(Status::OK, getMandatoryConcurrentStreams(cti.staticMeta, &outputStreams)); + ASSERT_NE(0u, outputStreams.size()); + + uint32_t jpegBufferSize = 0; + ASSERT_EQ(Status::OK, getJpegBufferSize(cti.staticMeta, &jpegBufferSize)); + ASSERT_NE(0u, jpegBufferSize); + + int32_t streamId = 0; + ::android::hardware::hidl_vec streams3_2(outputStreams.size()); + size_t j = 0; + for (const auto& it : outputStreams) { + V3_2::Stream stream3_2; + V3_2::DataspaceFlags dataspaceFlag = 0; + switch (static_cast(it.format)) { + case PixelFormat::BLOB: + dataspaceFlag = static_cast(Dataspace::V0_JFIF); + break; + case PixelFormat::Y16: + dataspaceFlag = static_cast(Dataspace::DEPTH); + break; + default: + dataspaceFlag = static_cast(Dataspace::UNKNOWN); + } + stream3_2 = {streamId++, + StreamType::OUTPUT, + static_cast(it.width), + static_cast(it.height), + static_cast(it.format), + GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, + dataspaceFlag, + StreamRotation::ROTATION_0}; + streams3_2[j] = stream3_2; + j++; + } + + // Add the created stream configs to cameraIdsAndStreamCombinations + createStreamConfiguration(streams3_2, StreamConfigurationMode::NORMAL_MODE, + &cti.config3_2, &cti.config3_4, &cti.config3_5, + jpegBufferSize); + + cti.config3_5.streamConfigCounter = outputStreams.size(); + CameraIdAndStreamCombination cameraIdAndStreamCombination; + cameraIdAndStreamCombination.cameraId = id; + cameraIdAndStreamCombination.streamConfiguration = cti.config3_4; + cameraIdsAndStreamCombinations.push_back(cameraIdAndStreamCombination); + i++; + cameraTestInfos.push_back(cti); + } + // Now verify that concurrent streams are supported + auto cb = [](Status s, bool supported) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(supported, true); + }; + + auto ret = mProvider2_6->isConcurrentStreamCombinationSupported( + cameraIdsAndStreamCombinations, cb); + + // Test the stream can actually be configured + for (const auto& cti : cameraTestInfos) { + if (cti.session3_5 != nullptr) { + bool expectStreamCombQuery = (isLogicalMultiCamera(cti.staticMeta) == Status::OK); + verifyStreamCombination(cti.cameraDevice3_5, cti.config3_4, + /*expectedStatus*/ true, expectStreamCombQuery); + ret = cti.session3_5->configureStreams_3_5( + cti.config3_5, + [&cti](Status s, device::V3_4::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(cti.config3_5.v3_4.streams.size(), halConfig.streams.size()); + }); + } else if (cti.session3_4 != nullptr) { + ret = cti.session3_4->configureStreams_3_4( + cti.config3_4, + [&cti](Status s, device::V3_4::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(cti.config3_4.streams.size(), halConfig.streams.size()); + }); + } else if (cti.session3_3 != nullptr) { + ret = cti.session3_3->configureStreams_3_3( + cti.config3_2, + [&cti](Status s, device::V3_3::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(cti.config3_2.streams.size(), halConfig.streams.size()); + }); + } else { + ret = cti.session->configureStreams( + cti.config3_2, [&cti](Status s, HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(cti.config3_2.streams.size(), halConfig.streams.size()); + }); + } + ASSERT_TRUE(ret.isOk()); + } + + for (const auto& cti : cameraTestInfos) { + free_camera_metadata(cti.staticMeta); + ret = cti.session->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + // Check for correct handling of invalid/incorrect configuration parameters. TEST_P(CameraHidlTest, configureStreamsInvalidOutputs) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); @@ -5158,6 +5351,65 @@ Status CameraHidlTest::getAvailableOutputStreams(const camera_metadata_t *static return Status::OK; } +static Size getMinSize(Size a, Size b) { + if (a.width * a.height < b.width * b.height) { + return a; + } + return b; +} + +// TODO: Add more combinations +Status CameraHidlTest::getMandatoryConcurrentStreams(const camera_metadata_t* staticMeta, + std::vector* outputStreams) { + if (nullptr == staticMeta) { + return Status::ILLEGAL_ARGUMENT; + } + Size yuvMaxSize(1280, 720); + Size jpegMaxSize(1920, 1440); + Size maxAvailableYuvSize; + Size maxAvailableJpegSize; + getMaxOutputSizeForFormat(staticMeta, PixelFormat::YCBCR_420_888, &maxAvailableYuvSize); + getMaxOutputSizeForFormat(staticMeta, PixelFormat::BLOB, &maxAvailableJpegSize); + Size yuvChosenSize = getMinSize(yuvMaxSize, maxAvailableYuvSize); + Size jpegChosenSize = getMinSize(jpegMaxSize, maxAvailableJpegSize); + + AvailableStream yuvStream = {.width = yuvChosenSize.width, + .height = yuvChosenSize.height, + .format = static_cast(PixelFormat::YCBCR_420_888)}; + + AvailableStream jpegStream = {.width = jpegChosenSize.width, + .height = jpegChosenSize.height, + .format = static_cast(PixelFormat::BLOB)}; + outputStreams->push_back(yuvStream); + outputStreams->push_back(jpegStream); + + return Status::OK; +} + +Status CameraHidlTest::getMaxOutputSizeForFormat(const camera_metadata_t* staticMeta, + PixelFormat format, Size* size) { + std::vector outputStreams; + if (size == nullptr || getAvailableOutputStreams(staticMeta, outputStreams) != Status::OK) { + return Status::ILLEGAL_ARGUMENT; + } + Size maxSize; + bool found = false; + for (auto& outputStream : outputStreams) { + if (static_cast(format) == outputStream.format && + (outputStream.width * outputStream.height > maxSize.width * maxSize.height)) { + maxSize.width = outputStream.width; + maxSize.height = outputStream.height; + found = true; + } + } + if (!found) { + ALOGE("%s :chosen format %d not found", __FUNCTION__, static_cast(format)); + return Status::ILLEGAL_ARGUMENT; + } + *size = maxSize; + return Status::OK; +} + void CameraHidlTest::fillOutputStreams(camera_metadata_ro_entry_t* entry, std::vector& outputStreams, const AvailableStream* threshold, const int32_t availableConfigOutputTag) { From e49ee681b0fe61e64fa471dbc0e9a7eb01c1a109 Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Mon, 2 Mar 2020 15:18:12 -0500 Subject: [PATCH 0664/1022] Move common tests into SensorsV2_0 VTS only Since Sensors HAL 2.1 implementations need to run VTS for both HAL 2.0 and 2.1, move tests that don't differ in logic between the two HAL implementations to the VTS for 2.0 only to minimize the total run time for both suites. Bug: 149927057 Test: atest VtsHalSensorsV2_0Target VtsHalSensorsV2_1Target Change-Id: I5213cdf05bafb2d4014078a03b22d98b96b7c5ee --- .../VtsHalSensorsV2_0TargetTest.cpp | 270 ++++++++++++++++++ .../vts/2_X/VtsHalSensorsV2_XTargetTest.h | 270 ------------------ 2 files changed, 270 insertions(+), 270 deletions(-) diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp index 889535005e..a0d436f3f9 100644 --- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp +++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp @@ -16,6 +16,261 @@ #include "VtsHalSensorsV2_XTargetTest.h" +// Test if sensor hal can do UI speed accelerometer streaming properly +TEST_P(SensorsHidlTest, AccelerometerStreamingOperationSlow) { + testStreamingOperation(SensorTypeVersion::ACCELEROMETER, std::chrono::milliseconds(200), + std::chrono::seconds(5), mAccelNormChecker); +} + +// Test if sensor hal can do normal speed accelerometer streaming properly +TEST_P(SensorsHidlTest, AccelerometerStreamingOperationNormal) { + testStreamingOperation(SensorTypeVersion::ACCELEROMETER, std::chrono::milliseconds(20), + std::chrono::seconds(5), mAccelNormChecker); +} + +// Test if sensor hal can do game speed accelerometer streaming properly +TEST_P(SensorsHidlTest, AccelerometerStreamingOperationFast) { + testStreamingOperation(SensorTypeVersion::ACCELEROMETER, std::chrono::milliseconds(5), + std::chrono::seconds(5), mAccelNormChecker); +} + +// Test if sensor hal can do UI speed gyroscope streaming properly +TEST_P(SensorsHidlTest, GyroscopeStreamingOperationSlow) { + testStreamingOperation(SensorTypeVersion::GYROSCOPE, std::chrono::milliseconds(200), + std::chrono::seconds(5), mGyroNormChecker); +} + +// Test if sensor hal can do normal speed gyroscope streaming properly +TEST_P(SensorsHidlTest, GyroscopeStreamingOperationNormal) { + testStreamingOperation(SensorTypeVersion::GYROSCOPE, std::chrono::milliseconds(20), + std::chrono::seconds(5), mGyroNormChecker); +} + +// Test if sensor hal can do game speed gyroscope streaming properly +TEST_P(SensorsHidlTest, GyroscopeStreamingOperationFast) { + testStreamingOperation(SensorTypeVersion::GYROSCOPE, std::chrono::milliseconds(5), + std::chrono::seconds(5), mGyroNormChecker); +} + +// Test if sensor hal can do UI speed magnetometer streaming properly +TEST_P(SensorsHidlTest, MagnetometerStreamingOperationSlow) { + testStreamingOperation(SensorTypeVersion::MAGNETIC_FIELD, std::chrono::milliseconds(200), + std::chrono::seconds(5), NullChecker()); +} + +// Test if sensor hal can do normal speed magnetometer streaming properly +TEST_P(SensorsHidlTest, MagnetometerStreamingOperationNormal) { + testStreamingOperation(SensorTypeVersion::MAGNETIC_FIELD, std::chrono::milliseconds(20), + std::chrono::seconds(5), NullChecker()); +} + +// Test if sensor hal can do game speed magnetometer streaming properly +TEST_P(SensorsHidlTest, MagnetometerStreamingOperationFast) { + testStreamingOperation(SensorTypeVersion::MAGNETIC_FIELD, std::chrono::milliseconds(5), + std::chrono::seconds(5), NullChecker()); +} + +// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active +TEST_P(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) { + testSamplingRateHotSwitchOperation(SensorTypeVersion::ACCELEROMETER); + testSamplingRateHotSwitchOperation(SensorTypeVersion::ACCELEROMETER, false /*fastToSlow*/); +} + +// Test if sensor hal can do gyroscope sampling rate switch properly when sensor is active +TEST_P(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) { + testSamplingRateHotSwitchOperation(SensorTypeVersion::GYROSCOPE); + testSamplingRateHotSwitchOperation(SensorTypeVersion::GYROSCOPE, false /*fastToSlow*/); +} + +// Test if sensor hal can do magnetometer sampling rate switch properly when sensor is active +TEST_P(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) { + testSamplingRateHotSwitchOperation(SensorTypeVersion::MAGNETIC_FIELD); + testSamplingRateHotSwitchOperation(SensorTypeVersion::MAGNETIC_FIELD, false /*fastToSlow*/); +} + +// Test if sensor hal can do accelerometer batching properly +TEST_P(SensorsHidlTest, AccelerometerBatchingOperation) { + testBatchingOperation(SensorTypeVersion::ACCELEROMETER); +} + +// Test if sensor hal can do gyroscope batching properly +TEST_P(SensorsHidlTest, GyroscopeBatchingOperation) { + testBatchingOperation(SensorTypeVersion::GYROSCOPE); +} + +// Test if sensor hal can do magnetometer batching properly +TEST_P(SensorsHidlTest, MagnetometerBatchingOperation) { + testBatchingOperation(SensorTypeVersion::MAGNETIC_FIELD); +} + +// Test sensor event direct report with ashmem for accel sensor at normal rate +TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) { + testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::ASHMEM, + RateLevel::NORMAL, mAccelNormChecker); +} + +// Test sensor event direct report with ashmem for accel sensor at fast rate +TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) { + testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::ASHMEM, + RateLevel::FAST, mAccelNormChecker); +} + +// Test sensor event direct report with ashmem for accel sensor at very fast rate +TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) { + testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::ASHMEM, + RateLevel::VERY_FAST, mAccelNormChecker); +} + +// Test sensor event direct report with ashmem for gyro sensor at normal rate +TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) { + testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::ASHMEM, + RateLevel::NORMAL, mGyroNormChecker); +} + +// Test sensor event direct report with ashmem for gyro sensor at fast rate +TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) { + testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST, + mGyroNormChecker); +} + +// Test sensor event direct report with ashmem for gyro sensor at very fast rate +TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) { + testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::ASHMEM, + RateLevel::VERY_FAST, mGyroNormChecker); +} + +// Test sensor event direct report with ashmem for mag sensor at normal rate +TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) { + testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::ASHMEM, + RateLevel::NORMAL, NullChecker()); +} + +// Test sensor event direct report with ashmem for mag sensor at fast rate +TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) { + testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::ASHMEM, + RateLevel::FAST, NullChecker()); +} + +// Test sensor event direct report with ashmem for mag sensor at very fast rate +TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) { + testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::ASHMEM, + RateLevel::VERY_FAST, NullChecker()); +} + +// Test sensor event direct report with gralloc for accel sensor at normal rate +TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) { + testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::GRALLOC, + RateLevel::NORMAL, mAccelNormChecker); +} + +// Test sensor event direct report with gralloc for accel sensor at fast rate +TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) { + testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::GRALLOC, + RateLevel::FAST, mAccelNormChecker); +} + +// Test sensor event direct report with gralloc for accel sensor at very fast rate +TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) { + testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::GRALLOC, + RateLevel::VERY_FAST, mAccelNormChecker); +} + +// Test sensor event direct report with gralloc for gyro sensor at normal rate +TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) { + testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::GRALLOC, + RateLevel::NORMAL, mGyroNormChecker); +} + +// Test sensor event direct report with gralloc for gyro sensor at fast rate +TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) { + testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST, + mGyroNormChecker); +} + +// Test sensor event direct report with gralloc for gyro sensor at very fast rate +TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) { + testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::GRALLOC, + RateLevel::VERY_FAST, mGyroNormChecker); +} + +// Test sensor event direct report with gralloc for mag sensor at normal rate +TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) { + testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::GRALLOC, + RateLevel::NORMAL, NullChecker()); +} + +// Test sensor event direct report with gralloc for mag sensor at fast rate +TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) { + testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::GRALLOC, + RateLevel::FAST, NullChecker()); +} + +// Test sensor event direct report with gralloc for mag sensor at very fast rate +TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) { + testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::GRALLOC, + RateLevel::VERY_FAST, NullChecker()); +} + +TEST_P(SensorsHidlTest, ConfigureDirectChannelWithInvalidHandle) { + SensorInfoType sensor; + SharedMemType memType; + RateLevel rate; + if (!getDirectChannelSensor(&sensor, &memType, &rate)) { + return; + } + + // Verify that an invalid channel handle produces a BAD_VALUE result + configDirectReport(sensor.sensorHandle, -1, rate, [](Result result, int32_t /* reportToken */) { + ASSERT_EQ(result, Result::BAD_VALUE); + }); +} + +TEST_P(SensorsHidlTest, CleanupDirectConnectionOnInitialize) { + constexpr size_t kNumEvents = 1; + constexpr size_t kMemSize = kNumEvents * kEventSize; + + SensorInfoType sensor; + SharedMemType memType; + RateLevel rate; + + if (!getDirectChannelSensor(&sensor, &memType, &rate)) { + return; + } + + std::shared_ptr> mem( + SensorsTestSharedMemory::create(memType, kMemSize)); + ASSERT_NE(mem, nullptr); + + int32_t directChannelHandle = 0; + registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) { + ASSERT_EQ(result, Result::OK); + directChannelHandle = channelHandle; + }); + + // Configure the channel and expect success + configDirectReport( + sensor.sensorHandle, directChannelHandle, rate, + [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); }); + + // Call initialize() via the environment setup to cause the HAL to re-initialize + // Clear the active direct connections so they are not stopped during TearDown + auto handles = mDirectChannelHandles; + mDirectChannelHandles.clear(); + getEnvironment()->HidlTearDown(); + getEnvironment()->HidlSetUp(); + if (HasFatalFailure()) { + return; // Exit early if resetting the environment failed + } + + // Attempt to configure the direct channel and expect it to fail + configDirectReport( + sensor.sensorHandle, directChannelHandle, rate, + [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::BAD_VALUE); }); + + // Restore original handles, though they should already be deactivated + mDirectChannelHandles = handles; +} + TEST_P(SensorsHidlTest, SensorListDoesntContainInvalidType) { getSensors()->getSensorsList([&](const auto& list) { const size_t count = list.size(); @@ -26,6 +281,21 @@ TEST_P(SensorsHidlTest, SensorListDoesntContainInvalidType) { }); } +TEST_P(SensorsHidlTest, FlushNonexistentSensor) { + SensorInfoType sensor; + std::vector sensors = getNonOneShotSensors(); + if (sensors.size() == 0) { + sensors = getOneShotSensors(); + if (sensors.size() == 0) { + return; + } + } + sensor = sensors.front(); + sensor.sensorHandle = getInvalidSensorHandle(); + runSingleFlushTest(std::vector{sensor}, false /* activateSensor */, + 0 /* expectedFlushCount */, Result::BAD_VALUE); +} + INSTANTIATE_TEST_SUITE_P(PerInstance, SensorsHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames( android::hardware::sensors::V2_0::ISensors::descriptor)), diff --git a/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h index 53ed259948..745ab2d0d9 100644 --- a/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h +++ b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h @@ -469,201 +469,6 @@ TEST_P(SensorsHidlTest, InjectSensorEventData) { ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL)); } -// Test if sensor hal can do UI speed accelerometer streaming properly -TEST_P(SensorsHidlTest, AccelerometerStreamingOperationSlow) { - testStreamingOperation(SensorTypeVersion::ACCELEROMETER, std::chrono::milliseconds(200), - std::chrono::seconds(5), mAccelNormChecker); -} - -// Test if sensor hal can do normal speed accelerometer streaming properly -TEST_P(SensorsHidlTest, AccelerometerStreamingOperationNormal) { - testStreamingOperation(SensorTypeVersion::ACCELEROMETER, std::chrono::milliseconds(20), - std::chrono::seconds(5), mAccelNormChecker); -} - -// Test if sensor hal can do game speed accelerometer streaming properly -TEST_P(SensorsHidlTest, AccelerometerStreamingOperationFast) { - testStreamingOperation(SensorTypeVersion::ACCELEROMETER, std::chrono::milliseconds(5), - std::chrono::seconds(5), mAccelNormChecker); -} - -// Test if sensor hal can do UI speed gyroscope streaming properly -TEST_P(SensorsHidlTest, GyroscopeStreamingOperationSlow) { - testStreamingOperation(SensorTypeVersion::GYROSCOPE, std::chrono::milliseconds(200), - std::chrono::seconds(5), mGyroNormChecker); -} - -// Test if sensor hal can do normal speed gyroscope streaming properly -TEST_P(SensorsHidlTest, GyroscopeStreamingOperationNormal) { - testStreamingOperation(SensorTypeVersion::GYROSCOPE, std::chrono::milliseconds(20), - std::chrono::seconds(5), mGyroNormChecker); -} - -// Test if sensor hal can do game speed gyroscope streaming properly -TEST_P(SensorsHidlTest, GyroscopeStreamingOperationFast) { - testStreamingOperation(SensorTypeVersion::GYROSCOPE, std::chrono::milliseconds(5), - std::chrono::seconds(5), mGyroNormChecker); -} - -// Test if sensor hal can do UI speed magnetometer streaming properly -TEST_P(SensorsHidlTest, MagnetometerStreamingOperationSlow) { - testStreamingOperation(SensorTypeVersion::MAGNETIC_FIELD, std::chrono::milliseconds(200), - std::chrono::seconds(5), NullChecker()); -} - -// Test if sensor hal can do normal speed magnetometer streaming properly -TEST_P(SensorsHidlTest, MagnetometerStreamingOperationNormal) { - testStreamingOperation(SensorTypeVersion::MAGNETIC_FIELD, std::chrono::milliseconds(20), - std::chrono::seconds(5), NullChecker()); -} - -// Test if sensor hal can do game speed magnetometer streaming properly -TEST_P(SensorsHidlTest, MagnetometerStreamingOperationFast) { - testStreamingOperation(SensorTypeVersion::MAGNETIC_FIELD, std::chrono::milliseconds(5), - std::chrono::seconds(5), NullChecker()); -} - -// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active -TEST_P(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) { - testSamplingRateHotSwitchOperation(SensorTypeVersion::ACCELEROMETER); - testSamplingRateHotSwitchOperation(SensorTypeVersion::ACCELEROMETER, false /*fastToSlow*/); -} - -// Test if sensor hal can do gyroscope sampling rate switch properly when sensor is active -TEST_P(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) { - testSamplingRateHotSwitchOperation(SensorTypeVersion::GYROSCOPE); - testSamplingRateHotSwitchOperation(SensorTypeVersion::GYROSCOPE, false /*fastToSlow*/); -} - -// Test if sensor hal can do magnetometer sampling rate switch properly when sensor is active -TEST_P(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) { - testSamplingRateHotSwitchOperation(SensorTypeVersion::MAGNETIC_FIELD); - testSamplingRateHotSwitchOperation(SensorTypeVersion::MAGNETIC_FIELD, false /*fastToSlow*/); -} - -// Test if sensor hal can do accelerometer batching properly -TEST_P(SensorsHidlTest, AccelerometerBatchingOperation) { - testBatchingOperation(SensorTypeVersion::ACCELEROMETER); -} - -// Test if sensor hal can do gyroscope batching properly -TEST_P(SensorsHidlTest, GyroscopeBatchingOperation) { - testBatchingOperation(SensorTypeVersion::GYROSCOPE); -} - -// Test if sensor hal can do magnetometer batching properly -TEST_P(SensorsHidlTest, MagnetometerBatchingOperation) { - testBatchingOperation(SensorTypeVersion::MAGNETIC_FIELD); -} - -// Test sensor event direct report with ashmem for accel sensor at normal rate -TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) { - testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::ASHMEM, - RateLevel::NORMAL, mAccelNormChecker); -} - -// Test sensor event direct report with ashmem for accel sensor at fast rate -TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) { - testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::ASHMEM, - RateLevel::FAST, mAccelNormChecker); -} - -// Test sensor event direct report with ashmem for accel sensor at very fast rate -TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) { - testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::ASHMEM, - RateLevel::VERY_FAST, mAccelNormChecker); -} - -// Test sensor event direct report with ashmem for gyro sensor at normal rate -TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) { - testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::ASHMEM, - RateLevel::NORMAL, mGyroNormChecker); -} - -// Test sensor event direct report with ashmem for gyro sensor at fast rate -TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) { - testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST, - mGyroNormChecker); -} - -// Test sensor event direct report with ashmem for gyro sensor at very fast rate -TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) { - testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::ASHMEM, - RateLevel::VERY_FAST, mGyroNormChecker); -} - -// Test sensor event direct report with ashmem for mag sensor at normal rate -TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) { - testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::ASHMEM, - RateLevel::NORMAL, NullChecker()); -} - -// Test sensor event direct report with ashmem for mag sensor at fast rate -TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) { - testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::ASHMEM, - RateLevel::FAST, NullChecker()); -} - -// Test sensor event direct report with ashmem for mag sensor at very fast rate -TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) { - testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::ASHMEM, - RateLevel::VERY_FAST, NullChecker()); -} - -// Test sensor event direct report with gralloc for accel sensor at normal rate -TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) { - testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::GRALLOC, - RateLevel::NORMAL, mAccelNormChecker); -} - -// Test sensor event direct report with gralloc for accel sensor at fast rate -TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) { - testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::GRALLOC, - RateLevel::FAST, mAccelNormChecker); -} - -// Test sensor event direct report with gralloc for accel sensor at very fast rate -TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) { - testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::GRALLOC, - RateLevel::VERY_FAST, mAccelNormChecker); -} - -// Test sensor event direct report with gralloc for gyro sensor at normal rate -TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) { - testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::GRALLOC, - RateLevel::NORMAL, mGyroNormChecker); -} - -// Test sensor event direct report with gralloc for gyro sensor at fast rate -TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) { - testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST, - mGyroNormChecker); -} - -// Test sensor event direct report with gralloc for gyro sensor at very fast rate -TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) { - testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::GRALLOC, - RateLevel::VERY_FAST, mGyroNormChecker); -} - -// Test sensor event direct report with gralloc for mag sensor at normal rate -TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) { - testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::GRALLOC, - RateLevel::NORMAL, NullChecker()); -} - -// Test sensor event direct report with gralloc for mag sensor at fast rate -TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) { - testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::GRALLOC, - RateLevel::FAST, NullChecker()); -} - -// Test sensor event direct report with gralloc for mag sensor at very fast rate -TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) { - testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::GRALLOC, - RateLevel::VERY_FAST, NullChecker()); -} - void SensorsHidlTest::activateAllSensors(bool enable) { for (const SensorInfoType& sensorInfo : getSensorsList()) { if (isValidType(sensorInfo.type)) { @@ -829,21 +634,6 @@ TEST_P(SensorsHidlTest, FlushInactiveSensor) { Result::BAD_VALUE); } -TEST_P(SensorsHidlTest, FlushNonexistentSensor) { - SensorInfoType sensor; - std::vector sensors = getNonOneShotSensors(); - if (sensors.size() == 0) { - sensors = getOneShotSensors(); - if (sensors.size() == 0) { - return; - } - } - sensor = sensors.front(); - sensor.sensorHandle = getInvalidSensorHandle(); - runSingleFlushTest(std::vector{sensor}, false /* activateSensor */, - 0 /* expectedFlushCount */, Result::BAD_VALUE); -} - TEST_P(SensorsHidlTest, Batch) { if (getSensorsList().size() == 0) { return; @@ -1124,63 +914,3 @@ bool SensorsHidlTest::getDirectChannelSensor(SensorInfoType* sensor, SharedMemTy } return found; } - -TEST_P(SensorsHidlTest, ConfigureDirectChannelWithInvalidHandle) { - SensorInfoType sensor; - SharedMemType memType; - RateLevel rate; - if (!getDirectChannelSensor(&sensor, &memType, &rate)) { - return; - } - - // Verify that an invalid channel handle produces a BAD_VALUE result - configDirectReport(sensor.sensorHandle, -1, rate, [](Result result, int32_t /* reportToken */) { - ASSERT_EQ(result, Result::BAD_VALUE); - }); -} - -TEST_P(SensorsHidlTest, CleanupDirectConnectionOnInitialize) { - constexpr size_t kNumEvents = 1; - constexpr size_t kMemSize = kNumEvents * kEventSize; - - SensorInfoType sensor; - SharedMemType memType; - RateLevel rate; - - if (!getDirectChannelSensor(&sensor, &memType, &rate)) { - return; - } - - std::shared_ptr> mem( - SensorsTestSharedMemory::create(memType, kMemSize)); - ASSERT_NE(mem, nullptr); - - int32_t directChannelHandle = 0; - registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) { - ASSERT_EQ(result, Result::OK); - directChannelHandle = channelHandle; - }); - - // Configure the channel and expect success - configDirectReport( - sensor.sensorHandle, directChannelHandle, rate, - [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); }); - - // Call initialize() via the environment setup to cause the HAL to re-initialize - // Clear the active direct connections so they are not stopped during TearDown - auto handles = mDirectChannelHandles; - mDirectChannelHandles.clear(); - getEnvironment()->HidlTearDown(); - getEnvironment()->HidlSetUp(); - if (HasFatalFailure()) { - return; // Exit early if resetting the environment failed - } - - // Attempt to configure the direct channel and expect it to fail - configDirectReport( - sensor.sensorHandle, directChannelHandle, rate, - [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::BAD_VALUE); }); - - // Restore original handles, though they should already be deactivated - mDirectChannelHandles = handles; -} From 65f6b95b6d957baf0621836da42ab5c155b0ef45 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 26 Feb 2020 15:25:51 -0800 Subject: [PATCH 0665/1022] drm@1.3 vts: link dynamic libcrypto.so to pass FIPS Bug: 149035295 Test: VtsHalDrmV1_3TargetTest Change-Id: I34d3537d1008c2d03db78b33687879b9fe24e8ad --- drm/1.3/vts/functional/Android.bp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drm/1.3/vts/functional/Android.bp b/drm/1.3/vts/functional/Android.bp index 4be157584b..ac1f912c08 100644 --- a/drm/1.3/vts/functional/Android.bp +++ b/drm/1.3/vts/functional/Android.bp @@ -30,12 +30,12 @@ cc_library_static { "android.hardware.drm@1.3", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", + "libcrypto", "libhidlmemory", "libnativehelper", ], static_libs: [ "android.hardware.drm@1.0-helper", - "libcrypto_static", "libdrmvtshelper", ], export_include_dirs: [ @@ -63,12 +63,12 @@ cc_test { "android.hardware.drm@1.3", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", + "libcrypto", "libhidlmemory", "libnativehelper", ], static_libs: [ "android.hardware.drm@1.0-helper", - "libcrypto_static", "libdrmvtshelper", ], test_suites: [ From 54cae11b79229afc47486e4703da13e553d286ce Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Mon, 2 Mar 2020 16:19:20 +0800 Subject: [PATCH 0666/1022] Wifi: omit FILS related vts tests if not supported Supplicant FILS operation is independent from driver key management driver support, i.e. even FILS is not supported in driver, these APIs still could be used. These APIs are controlled by supplicant CONFIG_FILS directly. To avoid inconsistent capability check, omit FILS vts tests if any of driver and supplicant does not support it. Bug: 149042449 Test: atest VtsHalWifiSupplicantV1_3TargetTest Change-Id: Ia0cdaac282f9ec6e9450d72795ed6461433bdf3b --- .../supplicant_hidl_test_utils_1_3.cpp | 14 ++++++ .../supplicant_hidl_test_utils_1_3.h | 3 ++ .../supplicant_sta_iface_hidl_test.cpp | 45 ++++++------------- .../supplicant_sta_network_hidl_test.cpp | 23 +++------- 4 files changed, 37 insertions(+), 48 deletions(-) diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp index 7ea54620da..dbf2b91fe7 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp @@ -21,6 +21,8 @@ #include "supplicant_hidl_test_utils_1_3.h" using ::android::sp; +using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus; +using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; using ::android::hardware::wifi::supplicant::V1_3::ISupplicant; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface; using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork; @@ -43,3 +45,15 @@ sp getSupplicant_1_3(const std::string& supplicant_instance_name, return ISupplicant::castFrom( getSupplicant(supplicant_instance_name, isP2pOn)); } + +bool isFilsSupported(sp sta_iface) { + uint32_t keyMgmtMask = 0; + sta_iface->getKeyMgmtCapabilities_1_3( + [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + keyMgmtMask = keyMgmtMaskInternal; + }); + + return (keyMgmtMask & (ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA256 | + ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA384)); +} diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h index f8dca138fd..69fc598593 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h +++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h @@ -31,4 +31,7 @@ createSupplicantStaNetwork_1_3( supplicant); android::sp getSupplicant_1_3(const std::string& supplicant_instance_name, bool isP2pOn); +bool isFilsSupported( + android::sp + sta_iface); #endif /* SUPPLICANT_HIDL_TEST_UTILS_1_3_H */ diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp index f7019d27f5..3754520eeb 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp @@ -517,7 +517,10 @@ TEST_P(SupplicantStaIfaceHidlTest, StartDppConfiguratorInitiator) { * FilsHlpAddRequest */ TEST_P(SupplicantStaIfaceHidlTest, FilsHlpAddRequest) { - uint32_t keyMgmtMask = 0; + if (!isFilsSupported(sta_iface_)) { + GTEST_SKIP() + << "Skipping test since driver/supplicant doesn't support FILS"; + } uint8_t destMacAddr[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; std::vector pktBuffer = { 0x08, 0x00, 0x45, 0x10, 0x01, 0x3a, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11, @@ -548,22 +551,9 @@ TEST_P(SupplicantStaIfaceHidlTest, FilsHlpAddRequest) { 0x63, 0x70, 0x2d, 0x52, 0x37, 0x0a, 0x01, 0x03, 0x06, 0x0f, 0x1a, 0x1c, 0x33, 0x3a, 0x3b, 0x2b, 0xff, 0x00}; - sta_iface_->getKeyMgmtCapabilities_1_3( - [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) { - EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); - keyMgmtMask = keyMgmtMaskInternal; - }); - - SupplicantStatusCode expectedStatusCode = - (keyMgmtMask & (ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA256 | - ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA384)) - ? SupplicantStatusCode::SUCCESS - : SupplicantStatusCode::FAILURE_UNKNOWN; - sta_iface_->filsHlpAddRequest( - destMacAddr, pktBuffer, - [expectedStatusCode](const SupplicantStatus& status) { - EXPECT_EQ(expectedStatusCode, status.code); + destMacAddr, pktBuffer, [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); }); } @@ -571,23 +561,14 @@ TEST_P(SupplicantStaIfaceHidlTest, FilsHlpAddRequest) { * FilsHlpFlushRequest */ TEST_P(SupplicantStaIfaceHidlTest, FilsHlpFlushRequest) { - uint32_t keyMgmtMask = 0; - sta_iface_->getKeyMgmtCapabilities_1_3( - [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) { - EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); - keyMgmtMask = keyMgmtMaskInternal; - }); + if (!isFilsSupported(sta_iface_)) { + GTEST_SKIP() + << "Skipping test since driver/supplicant doesn't support FILS"; + } - SupplicantStatusCode expectedStatusCode = - (keyMgmtMask & (ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA256 | - ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA384)) - ? SupplicantStatusCode::SUCCESS - : SupplicantStatusCode::FAILURE_UNKNOWN; - - sta_iface_->filsHlpFlushRequest( - [expectedStatusCode](const SupplicantStatus& status) { - EXPECT_EQ(expectedStatusCode, status.code); - }); + sta_iface_->filsHlpFlushRequest([](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); } INSTANTIATE_TEST_CASE_P( PerInstance, SupplicantStaIfaceHidlTest, diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp index 6be24bc0cc..9c40de1cb3 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp @@ -290,23 +290,14 @@ TEST_P(SupplicantStaNetworkHidlTest, SetGetWapiCertSuite) { * SetEapErp */ TEST_P(SupplicantStaNetworkHidlTest, SetEapErp) { - uint32_t keyMgmtMask = 0; - sta_iface_->getKeyMgmtCapabilities_1_3( - [&](const SupplicantStatus &status, uint32_t keyMgmtMaskInternal) { - EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); - keyMgmtMask = keyMgmtMaskInternal; - }); + if (!isFilsSupported(sta_iface_)) { + GTEST_SKIP() + << "Skipping test since driver/supplicant doesn't support FILS"; + } - SupplicantStatusCode expectedStatusCode = - (keyMgmtMask & (ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA256 | - ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA384)) - ? SupplicantStatusCode::SUCCESS - : SupplicantStatusCode::FAILURE_UNKNOWN; - - sta_network_->setEapErp( - true, [expectedStatusCode](const SupplicantStatus &status) { - EXPECT_EQ(expectedStatusCode, status.code); - }); + sta_network_->setEapErp(true, [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); } INSTANTIATE_TEST_CASE_P( PerInstance, SupplicantStaNetworkHidlTest, From b78beb5996d595daff80b81c0592cbcc74780a03 Mon Sep 17 00:00:00 2001 From: Janis Danisevskis Date: Thu, 27 Feb 2020 16:31:24 -0800 Subject: [PATCH 0667/1022] Convert VtsHalConfirmationUIV1_0TargetTest to parameterized test Convert VtsHalConfirmationUIV1_0TargetTest to parameterized test. Bug: 150382633 Test: VtsHalConfirmationUIV1_0TargetTest Change-Id: I19d02418d0ef01e6493906ea0bebfbd181e25815 --- confirmationui/1.0/vts/functional/Android.bp | 2 +- .../VtsHalConfirmationUIV1_0TargetTest.cpp | 124 +++++++----------- 2 files changed, 51 insertions(+), 75 deletions(-) diff --git a/confirmationui/1.0/vts/functional/Android.bp b/confirmationui/1.0/vts/functional/Android.bp index fd088cd360..c8b522c119 100644 --- a/confirmationui/1.0/vts/functional/Android.bp +++ b/confirmationui/1.0/vts/functional/Android.bp @@ -27,5 +27,5 @@ cc_test { "libcn-cbor", "android.hardware.confirmationui-support-lib", ], - test_suites: ["general-tests"], + test_suites: ["general-tests", "vts-core"], } diff --git a/confirmationui/1.0/vts/functional/VtsHalConfirmationUIV1_0TargetTest.cpp b/confirmationui/1.0/vts/functional/VtsHalConfirmationUIV1_0TargetTest.cpp index fb01ad065b..d953ab0fb2 100644 --- a/confirmationui/1.0/vts/functional/VtsHalConfirmationUIV1_0TargetTest.cpp +++ b/confirmationui/1.0/vts/functional/VtsHalConfirmationUIV1_0TargetTest.cpp @@ -26,8 +26,12 @@ #include #include +#include + #include -#include + +#include +#include #include #include @@ -199,43 +203,18 @@ class ConfirmationTestCallback : public ::testing::VtsHalHidlTargetCallbackBase< } }; -class ConfirmationUIHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static ConfirmationUIHidlEnvironment* Instance() { - static ConfirmationUIHidlEnvironment* instance = new ConfirmationUIHidlEnvironment; - return instance; - } - - void registerTestServices() override { registerTestService(); } - - private: - ConfirmationUIHidlEnvironment(){}; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ConfirmationUIHidlEnvironment); -}; - -class ConfirmationUIHidlTest : public ::testing::VtsHalHidlTargetTestBase { - public: - void TearDown() override { confirmator().abort(); } - - static void SetUpTestCase() { - string service_name = - ConfirmationUIHidlEnvironment::Instance()->getServiceName(); - confirmator_ = IConfirmationUI::getService(service_name); +class ConfirmationUIHidlTest : public ::testing::TestWithParam { + public: + void TearDown() override { confirmator_->abort(); } + void SetUp() override { + confirmator_ = IConfirmationUI::getService(GetParam()); ASSERT_NE(nullptr, confirmator_.get()); } - static void TearDownTestCase() { confirmator_.clear(); } - - static IConfirmationUI& confirmator() { return *confirmator_; } - - private: - static sp confirmator_; + protected: + sp confirmator_; }; -sp ConfirmationUIHidlTest::confirmator_; - #define ASSERT_HAL_CALL(expected, call) \ { \ auto result = call; \ @@ -250,17 +229,17 @@ struct CnCborDeleter { typedef std::unique_ptr CnCborPtr; // Simulates the User taping Ok -TEST_F(ConfirmationUIHidlTest, UserOkTest) { +TEST_P(ConfirmationUIHidlTest, UserOkTest) { static constexpr char test_prompt[] = "Me first, gimme gimme!"; static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3}; sp conf_cb = new ConfirmationTestCallback; hidl_string prompt_text(test_prompt); hidl_vec extra(test_extra, test_extra + 3); ASSERT_HAL_CALL(ResponseCode::OK, - confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); + confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); - ASSERT_HAL_CALL(ResponseCode::OK, confirmator().deliverSecureInputEvent( - makeTestToken(TestModeCommands::OK_EVENT))); + ASSERT_HAL_CALL(ResponseCode::OK, confirmator_->deliverSecureInputEvent( + makeTestToken(TestModeCommands::OK_EVENT))); auto result = conf_cb->WaitForCallback(); ASSERT_EQ(ResponseCode::OK, result.args->error_); @@ -294,40 +273,40 @@ TEST_F(ConfirmationUIHidlTest, UserOkTest) { } // Initiates a confirmation prompt with a message that is too long -TEST_F(ConfirmationUIHidlTest, MessageTooLongTest) { +TEST_P(ConfirmationUIHidlTest, MessageTooLongTest) { static constexpr uint8_t test_extra[static_cast(MessageSize::MAX)] = {}; static constexpr char test_prompt[] = "D\'oh!"; sp conf_cb = new ConfirmationTestCallback; hidl_string prompt_text(test_prompt); hidl_vec extra(test_extra, test_extra + sizeof(test_extra)); ASSERT_HAL_CALL(ResponseCode::UIErrorMessageTooLong, - confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); + confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); } // If the message gets very long some HAL implementations might fail even before the message // reaches the trusted app implementation. But the HAL must still diagnose the correct error. -TEST_F(ConfirmationUIHidlTest, MessageWayTooLongTest) { +TEST_P(ConfirmationUIHidlTest, MessageWayTooLongTest) { static constexpr uint8_t test_extra[static_cast(MessageSize::MAX) * 10] = {}; static constexpr char test_prompt[] = "D\'oh!"; sp conf_cb = new ConfirmationTestCallback; hidl_string prompt_text(test_prompt); hidl_vec extra(test_extra, test_extra + sizeof(test_extra)); ASSERT_HAL_CALL(ResponseCode::UIErrorMessageTooLong, - confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); + confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); } // Simulates the User tapping the Cancel -TEST_F(ConfirmationUIHidlTest, UserCancelTest) { +TEST_P(ConfirmationUIHidlTest, UserCancelTest) { static constexpr char test_prompt[] = "Me first, gimme gimme!"; static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3}; sp conf_cb = new ConfirmationTestCallback; hidl_string prompt_text(test_prompt); hidl_vec extra(test_extra, test_extra + 3); ASSERT_HAL_CALL(ResponseCode::OK, - confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); + confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); - ASSERT_HAL_CALL(ResponseCode::OK, confirmator().deliverSecureInputEvent( - makeTestToken(TestModeCommands::CANCEL_EVENT))); + ASSERT_HAL_CALL(ResponseCode::OK, confirmator_->deliverSecureInputEvent( + makeTestToken(TestModeCommands::CANCEL_EVENT))); auto result = conf_cb->WaitForCallback(); ASSERT_EQ(ResponseCode::Canceled, result.args->error_); @@ -337,16 +316,16 @@ TEST_F(ConfirmationUIHidlTest, UserCancelTest) { } // Simulates the framework cancelling an ongoing prompt -TEST_F(ConfirmationUIHidlTest, AbortTest) { +TEST_P(ConfirmationUIHidlTest, AbortTest) { static constexpr char test_prompt[] = "Me first, gimme gimme!"; static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3}; sp conf_cb = new ConfirmationTestCallback; hidl_string prompt_text(test_prompt); hidl_vec extra(test_extra, test_extra + 3); ASSERT_HAL_CALL(ResponseCode::OK, - confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); + confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); - confirmator().abort(); + confirmator_->abort(); auto result = conf_cb->WaitForCallback(); ASSERT_EQ(ResponseCode::Aborted, result.args->error_); @@ -356,7 +335,7 @@ TEST_F(ConfirmationUIHidlTest, AbortTest) { // Tests if the confirmation dialog can successfully render 100 'W' characters as required by // the design guidelines. -TEST_F(ConfirmationUIHidlTest, PortableMessageTest1) { +TEST_P(ConfirmationUIHidlTest, PortableMessageTest1) { static constexpr char test_prompt[] = "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW" "WWWWWWWWWWWWWW"; @@ -365,9 +344,9 @@ TEST_F(ConfirmationUIHidlTest, PortableMessageTest1) { hidl_string prompt_text(test_prompt); hidl_vec extra(test_extra, test_extra + 3); ASSERT_HAL_CALL(ResponseCode::OK, - confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); + confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); - confirmator().abort(); + confirmator_->abort(); auto result = conf_cb->WaitForCallback(); ASSERT_EQ(ResponseCode::Aborted, result.args->error_); @@ -377,7 +356,7 @@ TEST_F(ConfirmationUIHidlTest, PortableMessageTest1) { // Tests if the confirmation dialog can successfully render 100 'W' characters as required by // the design guidelines in magnified mode. -TEST_F(ConfirmationUIHidlTest, PortableMessageTest1Magnified) { +TEST_P(ConfirmationUIHidlTest, PortableMessageTest1Magnified) { static constexpr char test_prompt[] = "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW" "WWWWWWWWWWWWWW"; @@ -386,10 +365,10 @@ TEST_F(ConfirmationUIHidlTest, PortableMessageTest1Magnified) { hidl_string prompt_text(test_prompt); hidl_vec extra(test_extra, test_extra + 3); ASSERT_HAL_CALL(ResponseCode::OK, - confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", + confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {UIOption::AccessibilityMagnified})); - confirmator().abort(); + confirmator_->abort(); auto result = conf_cb->WaitForCallback(); ASSERT_EQ(ResponseCode::Aborted, result.args->error_); @@ -399,7 +378,7 @@ TEST_F(ConfirmationUIHidlTest, PortableMessageTest1Magnified) { // Tests if the confirmation dialog can successfully render 8 groups of 12 'W' characters as // required by the design guidelines. -TEST_F(ConfirmationUIHidlTest, PortableMessageTest2) { +TEST_P(ConfirmationUIHidlTest, PortableMessageTest2) { static constexpr char test_prompt[] = "WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW " "WWWWWWWWWWWW WWWWWWWWWWWW"; @@ -408,9 +387,9 @@ TEST_F(ConfirmationUIHidlTest, PortableMessageTest2) { hidl_string prompt_text(test_prompt); hidl_vec extra(test_extra, test_extra + 3); ASSERT_HAL_CALL(ResponseCode::OK, - confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); + confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); - confirmator().abort(); + confirmator_->abort(); auto result = conf_cb->WaitForCallback(); ASSERT_EQ(ResponseCode::Aborted, result.args->error_); @@ -420,7 +399,7 @@ TEST_F(ConfirmationUIHidlTest, PortableMessageTest2) { // Tests if the confirmation dialog can successfully render 8 groups of 12 'W' characters as // required by the design guidelines in magnified mode. -TEST_F(ConfirmationUIHidlTest, PortableMessageTest2Magnified) { +TEST_P(ConfirmationUIHidlTest, PortableMessageTest2Magnified) { static constexpr char test_prompt[] = "WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW " "WWWWWWWWWWWW WWWWWWWWWWWW"; @@ -429,10 +408,10 @@ TEST_F(ConfirmationUIHidlTest, PortableMessageTest2Magnified) { hidl_string prompt_text(test_prompt); hidl_vec extra(test_extra, test_extra + 3); ASSERT_HAL_CALL(ResponseCode::OK, - confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", + confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {UIOption::AccessibilityMagnified})); - confirmator().abort(); + confirmator_->abort(); auto result = conf_cb->WaitForCallback(); ASSERT_EQ(ResponseCode::Aborted, result.args->error_); @@ -442,19 +421,19 @@ TEST_F(ConfirmationUIHidlTest, PortableMessageTest2Magnified) { // Passing malformed UTF-8 to the confirmation UI // This test passes a string that ends in the middle of a multibyte character -TEST_F(ConfirmationUIHidlTest, MalformedUTF8Test1) { +TEST_P(ConfirmationUIHidlTest, MalformedUTF8Test1) { static constexpr char test_prompt[] = {char(0xc0), 0}; static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3}; sp conf_cb = new ConfirmationTestCallback; hidl_string prompt_text(test_prompt); hidl_vec extra(test_extra, test_extra + 3); ASSERT_HAL_CALL(ResponseCode::UIErrorMalformedUTF8Encoding, - confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); + confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); } // Passing malformed UTF-8 to the confirmation UI // This test passes a string with a 5-byte character. -TEST_F(ConfirmationUIHidlTest, MalformedUTF8Test2) { +TEST_P(ConfirmationUIHidlTest, MalformedUTF8Test2) { static constexpr char test_prompt[] = {char(0xf8), char(0x82), char(0x82), char(0x82), char(0x82), 0}; static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3}; @@ -462,19 +441,19 @@ TEST_F(ConfirmationUIHidlTest, MalformedUTF8Test2) { hidl_string prompt_text(test_prompt); hidl_vec extra(test_extra, test_extra + 3); ASSERT_HAL_CALL(ResponseCode::UIErrorMalformedUTF8Encoding, - confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); + confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); } // Passing malformed UTF-8 to the confirmation UI // This test passes a string with a 2-byte character followed by a stray non UTF-8 character. -TEST_F(ConfirmationUIHidlTest, MalformedUTF8Test3) { +TEST_P(ConfirmationUIHidlTest, MalformedUTF8Test3) { static constexpr char test_prompt[] = {char(0xc0), char(0x82), char(0x83), 0}; static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3}; sp conf_cb = new ConfirmationTestCallback; hidl_string prompt_text(test_prompt); hidl_vec extra(test_extra, test_extra + 3); ASSERT_HAL_CALL(ResponseCode::UIErrorMalformedUTF8Encoding, - confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); + confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {})); } // Test the implementation of HMAC SHA 256 against a golden blob. @@ -494,16 +473,13 @@ TEST(ConfirmationUITestSelfTest, HMAC256SelfTest) { ASSERT_EQ(expected, result.value()); } +INSTANTIATE_TEST_SUITE_P( + PerInstance, ConfirmationUIHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IConfirmationUI::descriptor)), + android::hardware::PrintInstanceNameToString); + } // namespace test } // namespace V1_0 } // namespace confirmationui } // namespace hardware } // namespace android - -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - std::vector positional_args; - int status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); - return status; -} From e969e81bee10d2d5b6b64b9b0d48af69c3f8b5fe Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Wed, 4 Mar 2020 13:34:14 -0500 Subject: [PATCH 0668/1022] Fix Sensors HAL 1.0 VTS tests HAL 1.0 VTS tests need to detach the polling thread or it will never exit on its own. Additionally, the poll() methods return status needs to be checked or HIDL will assert and cause the program to crash. Bug: 150475314 Test: atest VtsHalSensorsV1_0TargetTest VtsHalSensorsV2_0TargetTest Change-Id: I626b7aa064a1f258c968d1787872b9c67786dede --- .../functional/SensorsHidlEnvironmentV1_0.cpp | 34 +++++++++++++------ .../functional/SensorsHidlEnvironmentV1_0.h | 2 ++ .../SensorsHidlEnvironmentBase.h | 7 +--- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp index 1e5e886288..aca6961e0d 100644 --- a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp +++ b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp @@ -25,6 +25,13 @@ using ::android::hardware::sensors::V1_0::ISensors; using ::android::hardware::sensors::V1_0::Result; using ::android::hardware::sensors::V1_0::SensorInfo; +void SensorsHidlEnvironmentV1_0::HidlTearDown() { + mStopThread = true; + if (mPollThread.joinable()) { + mPollThread.detach(); + } +} + bool SensorsHidlEnvironmentV1_0::resetHal() { // wait upto 100ms * 10 = 1s for hidl service. constexpr auto RETRY_DELAY = std::chrono::milliseconds(100); @@ -103,18 +110,23 @@ void SensorsHidlEnvironmentV1_0::pollingThread(SensorsHidlEnvironmentV1_0* env, ALOGD("polling thread start"); while (!stop) { - env->sensors->poll( - 64, [&](auto result, const auto& events, const auto& dynamicSensorsAdded) { - if (result != Result::OK || - (events.size() == 0 && dynamicSensorsAdded.size() == 0) || stop) { - stop = true; - return; - } + if (!env->sensors + ->poll(64, + [&](auto result, const auto& events, const auto& dynamicSensorsAdded) { + if (result != Result::OK || + (events.size() == 0 && dynamicSensorsAdded.size() == 0) || + stop) { + stop = true; + return; + } - for (const auto& e : events) { - env->addEvent(e); - } - }); + for (const auto& e : events) { + env->addEvent(e); + } + }) + .isOk()) { + break; + } } ALOGD("polling thread end"); } \ No newline at end of file diff --git a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h index 485ed1ed87..168777d8be 100644 --- a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h +++ b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h @@ -32,6 +32,8 @@ class SensorsHidlTest; class SensorsHidlEnvironmentV1_0 : public SensorsHidlEnvironmentBase<::android::hardware::sensors::V1_0::Event> { public: + void HidlTearDown() override; + using Event = ::android::hardware::sensors::V1_0::Event; SensorsHidlEnvironmentV1_0(const std::string& service_name) : SensorsHidlEnvironmentBase(service_name) {} diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h index 781427d827..19dfbe55e4 100644 --- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h +++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h @@ -46,12 +46,7 @@ class SensorsHidlEnvironmentBase { std::this_thread::sleep_for(std::chrono::seconds(3)); } - virtual void HidlTearDown() { - mStopThread = true; - if (mPollThread.joinable()) { - mPollThread.join(); - } - } + virtual void HidlTearDown() = 0; // Get and clear all events collected so far (like "cat" shell command). // If output is nullptr, it clears all collected events. From d5d021b380890e1b9f922b2334ebec9f9b1423d9 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Tue, 4 Feb 2020 11:25:38 -0800 Subject: [PATCH 0669/1022] Build HalProxy unit tests with a test library ScopedWakelock Unit tests do not currently build because they cannot find the ScopedWakelock shared object. Make a test library version of ScopedWakelock for them. Bug: 147912609 Test: Build and run atest android.hardware.sensors@2.0-halproxy-unit-tests Merged-In: Ie8d3eb606ccba3825be2c8102b9a7bc6ea033f65 Change-Id: Ie8d3eb606ccba3825be2c8102b9a7bc6ea033f65 --- sensors/2.0/multihal/Android.bp | 15 +++++++++++++++ sensors/2.0/multihal/tests/Android.bp | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp index 24c475cb8c..b7fa15a3df 100644 --- a/sensors/2.0/multihal/Android.bp +++ b/sensors/2.0/multihal/Android.bp @@ -92,3 +92,18 @@ cc_test_library { "android.hardware.sensors@2.0-ScopedWakelock", ], } + +cc_test_library { + name: "android.hardware.sensors@2.0-ScopedWakelock.testlib", + defaults: [ + "hidl_defaults", + "android.hardware.sensors@2.0-multihal-defaults", + ], + srcs: [ + "ScopedWakelock.cpp", + ], + vendor_available: true, + export_header_lib_headers: [ + "android.hardware.sensors@2.0-multihal.header", + ], +} diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp index a9feaf7b21..472f3f3509 100644 --- a/sensors/2.0/multihal/tests/Android.bp +++ b/sensors/2.0/multihal/tests/Android.bp @@ -80,11 +80,11 @@ cc_test { static_libs: [ "android.hardware.sensors@2.0-HalProxy", "android.hardware.sensors@2.0-fakesubhal-unittest", + "android.hardware.sensors@2.0-ScopedWakelock.testlib", ], shared_libs: [ "android.hardware.sensors@1.0", "android.hardware.sensors@2.0", - "android.hardware.sensors@2.0-ScopedWakelock", "libbase", "libcutils", "libfmq", From 14499028cf166dc1187eb3dc4bef478ad7416871 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Tue, 4 Feb 2020 11:27:41 -0800 Subject: [PATCH 0670/1022] HalProxy unit test to expose incorrect numEventsOnPendingQueue Bug: 147912609 Test: run unit test Merged-In: Ia6fe3cafc1c2adb02463c28481bcf4c723551860 Change-Id: Ia6fe3cafc1c2adb02463c28481bcf4c723551860 --- sensors/2.0/multihal/tests/HalProxy_test.cpp | 39 ++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp index 1fd35d1afb..4633a7508a 100644 --- a/sensors/2.0/multihal/tests/HalProxy_test.cpp +++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp @@ -724,6 +724,45 @@ TEST(HalProxyTest, PostedEventSensorHandleSubHalIndexValid) { EXPECT_EQ(eventOut.sensorHandle, (subhal2Index << 24) | sensorHandleToPost); } +TEST(HalProxyTest, FillAndDrainPendingQueueTest) { + constexpr size_t kQueueSize = 5; + // TODO: Make this constant linked to same limit in HalProxy.h + constexpr size_t kMaxPendingQueueSize = 100000; + AllSensorsSubHal subhal; + std::vector subHals{&subhal}; + + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); + ::android::sp callback = new SensorsCallback(); + EventFlag* eventQueueFlag; + EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag); + HalProxy proxy(subHals); + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + + // Fill pending queue + std::vector events = makeMultipleAccelerometerEvents(kQueueSize); + subhal.postEvents(events, false); + events = makeMultipleAccelerometerEvents(kMaxPendingQueueSize); + subhal.postEvents(events, false); + + // Drain pending queue + for (int i = 0; i < kMaxPendingQueueSize + kQueueSize; i += kQueueSize) { + ASSERT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag)); + } + + // Put one event on pending queue + events = makeMultipleAccelerometerEvents(kQueueSize); + subhal.postEvents(events, false); + events = {makeAccelerometerEvent()}; + subhal.postEvents(events, false); + + // Read out to make room for one event on pending queue to write to FMQ + ASSERT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag)); + + // Should be able to read that last event off queue + EXPECT_TRUE(readEventsOutOfQueue(1, eventQueue, eventQueueFlag)); +} + // Helper implementations follow void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, const std::vector& subHalSensorsList) { From 05d7496e4cbffc6cd06816174be254f7763fef0d Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Tue, 3 Mar 2020 13:19:27 -0500 Subject: [PATCH 0671/1022] Move Multi-HAL 2.0 to the common directory Sensors Multi-HAL 2.0 will soon have a shared implementation for both Sensors HAL 2.0 and 2.1 and moving the files to the common directory first will minimize the diff in upcoming CLs. Bug: 149758467 Test: compile Change-Id: I15f84a7aaa302d83d4f4b1ffe357f515e36d6382 --- sensors/2.0/multihal/Android.bp | 95 +++---------------- .../common/default/2.X/multihal/Android.bp | 84 ++++++++++++++++ .../default/2.X}/multihal/HalProxy.cpp | 0 .../default/2.X}/multihal/ScopedWakelock.cpp | 0 .../default/2.X}/multihal/include/HalProxy.h | 0 .../2.X}/multihal/include/ScopedWakelock.h | 0 .../default/2.X}/multihal/include/SubHal.h | 0 .../default/2.X}/multihal/tests/Android.bp | 22 ++--- .../2.X}/multihal/tests/HalProxy_test.cpp | 0 .../2.X}/multihal/tests/fake_subhal/README | 0 .../multihal/tests/fake_subhal/Sensor.cpp | 0 .../2.X}/multihal/tests/fake_subhal/Sensor.h | 0 .../tests/fake_subhal/SensorsSubHal.cpp | 0 .../tests/fake_subhal/SensorsSubHal.h | 0 14 files changed, 108 insertions(+), 93 deletions(-) create mode 100644 sensors/common/default/2.X/multihal/Android.bp rename sensors/{2.0 => common/default/2.X}/multihal/HalProxy.cpp (100%) rename sensors/{2.0 => common/default/2.X}/multihal/ScopedWakelock.cpp (100%) rename sensors/{2.0 => common/default/2.X}/multihal/include/HalProxy.h (100%) rename sensors/{2.0 => common/default/2.X}/multihal/include/ScopedWakelock.h (100%) rename sensors/{2.0 => common/default/2.X}/multihal/include/SubHal.h (100%) rename sensors/{2.0 => common/default/2.X}/multihal/tests/Android.bp (77%) rename sensors/{2.0 => common/default/2.X}/multihal/tests/HalProxy_test.cpp (100%) rename sensors/{2.0 => common/default/2.X}/multihal/tests/fake_subhal/README (100%) rename sensors/{2.0 => common/default/2.X}/multihal/tests/fake_subhal/Sensor.cpp (100%) rename sensors/{2.0 => common/default/2.X}/multihal/tests/fake_subhal/Sensor.h (100%) rename sensors/{2.0 => common/default/2.X}/multihal/tests/fake_subhal/SensorsSubHal.cpp (100%) rename sensors/{2.0 => common/default/2.X}/multihal/tests/fake_subhal/SensorsSubHal.h (100%) diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp index b7fa15a3df..7213b448b4 100644 --- a/sensors/2.0/multihal/Android.bp +++ b/sensors/2.0/multihal/Android.bp @@ -13,14 +13,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -cc_defaults { - name: "android.hardware.sensors@2.0-multihal-defaults", - header_libs: [ - "android.hardware.sensors@2.0-multihal.header", +cc_binary { + name: "android.hardware.sensors@2.0-service.multihal", + defaults: [ + "hidl_defaults", ], + vendor: true, + relative_install_path: "hw", + srcs: [ + "service.cpp", + ], + init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"], + vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"], shared_libs: [ - "android.hardware.sensors@1.0", "android.hardware.sensors@2.0", + "android.hardware.sensors@2.0-ScopedWakelock", "libbase", "libcutils", "libfmq", @@ -29,81 +36,5 @@ cc_defaults { "libpower", "libutils", ], - cflags: ["-DLOG_TAG=\"SensorsMultiHal\""], -} - -cc_binary { - name: "android.hardware.sensors@2.0-service.multihal", - defaults: [ - "hidl_defaults", - "android.hardware.sensors@2.0-multihal-defaults", - ], - vendor: true, - relative_install_path: "hw", - srcs: [ - "service.cpp", - "HalProxy.cpp", - ], - init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"], - vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"], - shared_libs: ["android.hardware.sensors@2.0-ScopedWakelock"], -} - -cc_library_headers { - name: "android.hardware.sensors@2.0-multihal.header", - vendor_available: true, - export_include_dirs: ["include"], -} - -cc_library_shared { - name: "android.hardware.sensors@2.0-ScopedWakelock", - defaults: [ - "hidl_defaults", - "android.hardware.sensors@2.0-multihal-defaults", - ], - srcs: [ - "ScopedWakelock.cpp", - ], - vendor_available: true, - export_header_lib_headers: [ - "android.hardware.sensors@2.0-multihal.header", - ], -} - -// The below targets should only be used for testing. -cc_test_library { - name: "android.hardware.sensors@2.0-HalProxy", - defaults: [ - "hidl_defaults", - "android.hardware.sensors@2.0-multihal-defaults", - ], - vendor_available: true, - srcs: [ - "HalProxy.cpp", - ], - export_header_lib_headers: [ - "android.hardware.sensors@2.0-multihal.header", - ], - export_shared_lib_headers: [ - "android.hardware.sensors@2.0-ScopedWakelock", - ], - shared_libs: [ - "libutils", - "android.hardware.sensors@2.0-ScopedWakelock", - ], -} - -cc_test_library { - name: "android.hardware.sensors@2.0-ScopedWakelock.testlib", - defaults: [ - "hidl_defaults", - "android.hardware.sensors@2.0-multihal-defaults", - ], - srcs: [ - "ScopedWakelock.cpp", - ], - vendor_available: true, - export_header_lib_headers: [ - "android.hardware.sensors@2.0-multihal.header", - ], + static_libs: ["android.hardware.sensors@2.X-multihal"], } diff --git a/sensors/common/default/2.X/multihal/Android.bp b/sensors/common/default/2.X/multihal/Android.bp new file mode 100644 index 0000000000..2b4b3bfffa --- /dev/null +++ b/sensors/common/default/2.X/multihal/Android.bp @@ -0,0 +1,84 @@ +// +// 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. + +cc_defaults { + name: "android.hardware.sensors@2.X-multihal-defaults", + header_libs: [ + "android.hardware.sensors@2.0-multihal.header", + ], + shared_libs: [ + "android.hardware.sensors@1.0", + "android.hardware.sensors@2.0", + "libbase", + "libcutils", + "libfmq", + "libhidlbase", + "liblog", + "libpower", + "libutils", + ], + cflags: ["-DLOG_TAG=\"SensorsMultiHal\""], +} + +cc_library_headers { + name: "android.hardware.sensors@2.0-multihal.header", + vendor_available: true, + export_include_dirs: ["include"], +} + +cc_library_static { + name: "android.hardware.sensors@2.X-multihal", + defaults: [ + "hidl_defaults", + "android.hardware.sensors@2.X-multihal-defaults", + ], + srcs: [ + "HalProxy.cpp", + ], + vendor_available: true, + export_header_lib_headers: [ + "android.hardware.sensors@2.0-multihal.header", + ], +} + +cc_library_shared { + name: "android.hardware.sensors@2.0-ScopedWakelock", + defaults: [ + "hidl_defaults", + "android.hardware.sensors@2.X-multihal-defaults", + ], + srcs: [ + "ScopedWakelock.cpp", + ], + vendor_available: true, + export_header_lib_headers: [ + "android.hardware.sensors@2.0-multihal.header", + ], +} + +cc_test_library { + name: "android.hardware.sensors@2.0-ScopedWakelock.testlib", + defaults: [ + "hidl_defaults", + "android.hardware.sensors@2.X-multihal-defaults", + ], + srcs: [ + "ScopedWakelock.cpp", + ], + vendor_available: true, + export_header_lib_headers: [ + "android.hardware.sensors@2.0-multihal.header", + ], +} diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/common/default/2.X/multihal/HalProxy.cpp similarity index 100% rename from sensors/2.0/multihal/HalProxy.cpp rename to sensors/common/default/2.X/multihal/HalProxy.cpp diff --git a/sensors/2.0/multihal/ScopedWakelock.cpp b/sensors/common/default/2.X/multihal/ScopedWakelock.cpp similarity index 100% rename from sensors/2.0/multihal/ScopedWakelock.cpp rename to sensors/common/default/2.X/multihal/ScopedWakelock.cpp diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/common/default/2.X/multihal/include/HalProxy.h similarity index 100% rename from sensors/2.0/multihal/include/HalProxy.h rename to sensors/common/default/2.X/multihal/include/HalProxy.h diff --git a/sensors/2.0/multihal/include/ScopedWakelock.h b/sensors/common/default/2.X/multihal/include/ScopedWakelock.h similarity index 100% rename from sensors/2.0/multihal/include/ScopedWakelock.h rename to sensors/common/default/2.X/multihal/include/ScopedWakelock.h diff --git a/sensors/2.0/multihal/include/SubHal.h b/sensors/common/default/2.X/multihal/include/SubHal.h similarity index 100% rename from sensors/2.0/multihal/include/SubHal.h rename to sensors/common/default/2.X/multihal/include/SubHal.h diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/common/default/2.X/multihal/tests/Android.bp similarity index 77% rename from sensors/2.0/multihal/tests/Android.bp rename to sensors/common/default/2.X/multihal/tests/Android.bp index 472f3f3509..afb63cc22f 100644 --- a/sensors/2.0/multihal/tests/Android.bp +++ b/sensors/common/default/2.X/multihal/tests/Android.bp @@ -14,7 +14,7 @@ // limitations under the License. cc_defaults { - name: "android.hardware.sensors@2.0-fakesubhal-defaults", + name: "android.hardware.sensors@2.X-fakesubhal-defaults", srcs: [ "fake_subhal/*.cpp", ], @@ -35,7 +35,7 @@ cc_defaults { "libutils", ], static_libs: [ - "android.hardware.sensors@2.0-HalProxy", + "android.hardware.sensors@2.X-multihal", ], cflags: [ "-DLOG_TAG=\"FakeSubHal\"", @@ -43,9 +43,9 @@ cc_defaults { } cc_library { - name: "android.hardware.sensors@2.0-fakesubhal-config1", + name: "android.hardware.sensors@2.X-fakesubhal-config1", vendor: true, - defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"], + defaults: ["android.hardware.sensors@2.X-fakesubhal-defaults"], cflags: [ "-DSUPPORT_CONTINUOUS_SENSORS", "-DSUB_HAL_NAME=\"FakeSubHal-Continuous\"", @@ -53,9 +53,9 @@ cc_library { } cc_library { - name: "android.hardware.sensors@2.0-fakesubhal-config2", + name: "android.hardware.sensors@2.X-fakesubhal-config2", vendor: true, - defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"], + defaults: ["android.hardware.sensors@2.X-fakesubhal-defaults"], cflags: [ "-DSUPPORT_ON_CHANGE_SENSORS", "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"", @@ -63,9 +63,9 @@ cc_library { } cc_test_library { - name: "android.hardware.sensors@2.0-fakesubhal-unittest", + name: "android.hardware.sensors@2.X-fakesubhal-unittest", vendor_available: true, - defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"], + defaults: ["android.hardware.sensors@2.X-fakesubhal-defaults"], cflags: [ "-DSUPPORT_ON_CHANGE_SENSORS", "-DSUPPORT_CONTINUOUS_SENSORS", @@ -74,13 +74,13 @@ cc_test_library { } cc_test { - name: "android.hardware.sensors@2.0-halproxy-unit-tests", + name: "android.hardware.sensors@2.X-halproxy-unit-tests", srcs: ["HalProxy_test.cpp"], vendor: true, static_libs: [ - "android.hardware.sensors@2.0-HalProxy", - "android.hardware.sensors@2.0-fakesubhal-unittest", "android.hardware.sensors@2.0-ScopedWakelock.testlib", + "android.hardware.sensors@2.X-multihal", + "android.hardware.sensors@2.X-fakesubhal-unittest", ], shared_libs: [ "android.hardware.sensors@1.0", diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp similarity index 100% rename from sensors/2.0/multihal/tests/HalProxy_test.cpp rename to sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp diff --git a/sensors/2.0/multihal/tests/fake_subhal/README b/sensors/common/default/2.X/multihal/tests/fake_subhal/README similarity index 100% rename from sensors/2.0/multihal/tests/fake_subhal/README rename to sensors/common/default/2.X/multihal/tests/fake_subhal/README diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp similarity index 100% rename from sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp rename to sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h similarity index 100% rename from sensors/2.0/multihal/tests/fake_subhal/Sensor.h rename to sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp similarity index 100% rename from sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp rename to sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h similarity index 100% rename from sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h rename to sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h From d599096596a3332cb855552df1d1fe1a4ba5a5ad Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Thu, 13 Feb 2020 16:37:33 -0800 Subject: [PATCH 0672/1022] Add headers and macros for building VHAL server for AGL It won't change the logic of Android codes. Bug: 148877226 Bug: 150791171 Test: Android build won't break Change-Id: I07006a4a3e20900a2fa90b84167d114f9ac45cfe (cherry picked from commit 080963546aabc1ee9c06b5309f2d1dc1aec218f0) Merged-In: I07006a4a3e20900a2fa90b84167d114f9ac45cfe --- .../include/vhal_v2_0/VehicleObjectPool.h | 1 + .../common/include/vhal_v2_0/VehicleUtils.h | 6 ++++++ .../default/common/src/VehicleObjectPool.cpp | 2 +- .../2.0/default/common/src/VehicleUtils.cpp | 19 +++++++++++-------- .../default/impl/vhal_v2_0/DefaultConfig.h | 5 +++-- .../impl/vhal_v2_0/FakeValueGenerator.h | 2 ++ .../vhal_v2_0/LinearFakeValueGenerator.cpp | 3 ++- 7 files changed, 26 insertions(+), 12 deletions(-) diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h index 946e74ddda..e3cbf2e7cd 100644 --- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h @@ -21,6 +21,7 @@ #include #include #include +#include #include diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h index f97dfa1bba..955341504c 100644 --- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h @@ -19,7 +19,9 @@ #include +#ifdef __ANDROID__ #include +#endif #include @@ -69,6 +71,8 @@ size_t getVehicleRawValueVectorSize( void copyVehicleRawValue(VehiclePropValue::RawValue* dest, const VehiclePropValue::RawValue& src); +#ifdef __ANDROID__ + template void shallowCopyHidlVec(hidl_vec* dest, const hidl_vec& src); @@ -76,6 +80,8 @@ void shallowCopyHidlStr(hidl_string* dest, const hidl_string& src); void shallowCopy(VehiclePropValue* dest, const VehiclePropValue& src); +#endif // __ANDROID__ + } // namespace V2_0 } // namespace vehicle } // namespace automotive diff --git a/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp index 40dd56e73d..0947c9fe8c 100644 --- a/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp +++ b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp @@ -131,7 +131,7 @@ void VehiclePropValuePool::InternalPool::recycle(VehiclePropValue* o) { ALOGE("Discarding value for prop 0x%x because it contains " "data that is not consistent with this pool. " "Expected type: %d, vector size: %zu", - o->prop, mPropType, mVectorSize); + o->prop, toInt(mPropType), mVectorSize); delete o; } else { ObjectPool::recycle(o); diff --git a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp index 5b6816ee21..c16b29a2e7 100644 --- a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp +++ b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp @@ -52,7 +52,7 @@ std::unique_ptr createVehiclePropValue( case VehiclePropertyType::MIXED: break; // Valid, but nothing to do. default: - ALOGE("createVehiclePropValue: unknown type: %d", type); + ALOGE("createVehiclePropValue: unknown type: %d", toInt(type)); val.reset(nullptr); } return val; @@ -78,13 +78,6 @@ size_t getVehicleRawValueVectorSize( } } -template -inline void copyHidlVec(hidl_vec * dest, const hidl_vec & src) { - for (size_t i = 0; i < std::min(dest->size(), src.size()); i++) { - (*dest)[i] = src[i]; - } -} - void copyVehicleRawValue(VehiclePropValue::RawValue* dest, const VehiclePropValue::RawValue& src) { dest->int32Values = src.int32Values; @@ -94,6 +87,15 @@ void copyVehicleRawValue(VehiclePropValue::RawValue* dest, dest->stringValue = src.stringValue; } +#ifdef __ANDROID__ + +template +inline void copyHidlVec(hidl_vec * dest, const hidl_vec & src) { + for (size_t i = 0; i < std::min(dest->size(), src.size()); i++) { + (*dest)[i] = src[i]; + } +} + template void shallowCopyHidlVec(hidl_vec * dest, const hidl_vec & src) { if (src.size() > 0) { @@ -123,6 +125,7 @@ void shallowCopy(VehiclePropValue* dest, const VehiclePropValue& src) { shallowCopyHidlStr(&dest->value.stringValue, src.value.stringValue); } +#endif // __ANDROID__ //} // namespace utils 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 4b9480030e..53c9ffb99f 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 @@ -17,9 +17,11 @@ #ifndef android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_ #define android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_ -#include +#include #include +#include + namespace android { namespace hardware { namespace automotive { @@ -1017,7 +1019,6 @@ const ConfigDeclaration kVehicleProperties[]{ .changeMode = VehiclePropertyChangeMode::ON_CHANGE, }, }, - }; } // impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h index d6ad77df73..2dc502b9e0 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h @@ -19,6 +19,8 @@ #include +#include + namespace android { namespace hardware { namespace automotive { diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp index 7bdc97cd2b..96aaafe0b0 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp @@ -46,7 +46,8 @@ VehiclePropValue LinearFakeValueGenerator::nextEvent() { if (mGenCfg.currentValue > mGenCfg.initialValue + mGenCfg.dispersion) { mGenCfg.currentValue = mGenCfg.initialValue - mGenCfg.dispersion; } - VehiclePropValue event = {.prop = mGenCfg.propId}; + // TODO: (chenhaosjtuacm) remove "{}" if AGL compiler updated + VehiclePropValue event = {.timestamp = {}, .areaId = {}, .prop = mGenCfg.propId}; auto& value = event.value; switch (getPropType(event.prop)) { case VehiclePropertyType::INT32: From 2f2b3bbef6abf45ef1eb122f19afdb2f82832781 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Fri, 14 Feb 2020 11:26:03 -0800 Subject: [PATCH 0673/1022] Split vehicle client and server interface header Since vehicle client may contains some Android-specific types/headers that may not exist on AGL, we split the header into "client" and "server". It won't change the logic of Android codes. Bug: 148877226 Bug: 150791171 Test: build Change-Id: I550034b071ca6a7ca322fb26b61d76ed4a7307ee (cherry picked from commit 8dfac92fee6e1543f03687ff85cebb0247256766) Merged-In: I550034b071ca6a7ca322fb26b61d76ed4a7307ee --- .../common/include/vhal_v2_0/VehicleClient.h | 73 +++++++++++++++++ .../include/vhal_v2_0/VehicleConnector.h | 82 +------------------ .../common/include/vhal_v2_0/VehicleServer.h | 76 +++++++++++++++++ 3 files changed, 152 insertions(+), 79 deletions(-) create mode 100644 automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h create mode 100644 automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h new file mode 100644 index 0000000000..1e2f3add17 --- /dev/null +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h @@ -0,0 +1,73 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +/** + * Vehicle HAL talks to the vehicle through a client, instead of accessing + * the car bus directly, to give us more flexibility on the implementation. + * Android OS do not need direct access to the vehicle, and the communication + * channel is also customizable. + * + * Client lives on the Android (HAL) side to talk to the vehicle + */ +class IVehicleClient { + public: + IVehicleClient() = default; + + IVehicleClient(const IVehicleClient&) = delete; + + IVehicleClient& operator=(const IVehicleClient&) = delete; + + IVehicleClient(IVehicleClient&&) = default; + + virtual ~IVehicleClient() = default; + + // Get configuration of all properties from server + virtual std::vector getAllPropertyConfig() const = 0; + + // Send the set property request to server + // updateStatus indicate if VHal should change the status of the value + // it should be false except injecting values for e2e tests + virtual StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) = 0; + + // Receive a new property value from server + // updateStatus is true if and only if the value is + // generated by car (ECU/fake generator/injected) + virtual void onPropertyValue(const VehiclePropValue& value, bool updateStatus) = 0; + + // Dump method forwarded from HIDL's debug() + // If implemented, it must return whether the caller should dump its state. + virtual bool dump(const hidl_handle& /* handle */, const hidl_vec& /* options */) { + return true; + } +}; + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h index 00b5afe217..2908a55c25 100644 --- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h @@ -21,6 +21,9 @@ #include +#include "VehicleClient.h" +#include "VehicleServer.h" + namespace android { namespace hardware { namespace automotive { @@ -33,85 +36,6 @@ namespace V2_0 { * regardless of the underlying communication channels. */ -/** - * Vehicle HAL talks to the vehicle through a client, instead of accessing - * the car bus directly, to give us more flexibility on the implementation. - * Android OS do not need direct access to the vehicle, and the communication - * channel is also customizable. - * - * Client lives on the Android (HAL) side to talk to the vehicle - */ -class IVehicleClient { - public: - IVehicleClient() = default; - - IVehicleClient(const IVehicleClient&) = delete; - - IVehicleClient& operator=(const IVehicleClient&) = delete; - - IVehicleClient(IVehicleClient&&) = default; - - virtual ~IVehicleClient() = default; - - // Get configuration of all properties from server - virtual std::vector getAllPropertyConfig() const = 0; - - // Send the set property request to server - // updateStatus indicate if VHal should change the status of the value - // it should be false except injecting values for e2e tests - virtual StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) = 0; - - // Receive a new property value from server - // updateStatus is true if and only if the value is - // generated by car (ECU/fake generator/injected) - virtual void onPropertyValue(const VehiclePropValue& value, bool updateStatus) = 0; - - // Dump method forwarded from HIDL's debug() - // If implemented, it must return whether the caller should dump its state. - virtual bool dump(const hidl_handle& /* handle */, const hidl_vec& /* options */) { - return true; - } -}; - -/** - * Server lives on the vehicle side to talk to Android HAL - */ -class IVehicleServer { - public: - IVehicleServer() = default; - - IVehicleServer(const IVehicleServer&) = delete; - - IVehicleServer& operator=(const IVehicleServer&) = delete; - - IVehicleServer(IVehicleServer&&) = default; - - virtual ~IVehicleServer() = default; - - // Receive the get property configuration request from HAL. - // Return a list of all property config - virtual std::vector onGetAllPropertyConfig() const = 0; - - // Receive the set property request from HAL. - // Process the setting and return the status code - // updateStatus indicate if VHal should change the status of the value - // it should be false except injecting values for e2e tests - virtual StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) = 0; - - // Receive a new property value from car (via direct connection to the car bus or the emulator) - // and forward the value to HAL - // updateStatus is true if and only if the value is - // generated by car (ECU/fake generator/injected) - virtual void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) = 0; - - // Dump method forwarded from HIDL's debug() - // If implemented, it must return whether the caller should dump its state. - virtual bool onDump(const hidl_handle& /* handle */, - const hidl_vec& /* options */) { - return true; - } -}; - /** * If Android has direct access to the vehicle, then the client and * the server may act in passthrough mode to avoid extra IPC diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h new file mode 100644 index 0000000000..27ebbeef55 --- /dev/null +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +/** + * Server lives on the vehicle side to talk to Android HAL. + * Note that the server may not be run on Android + */ +class IVehicleServer { + public: + IVehicleServer() = default; + + IVehicleServer(const IVehicleServer&) = delete; + + IVehicleServer& operator=(const IVehicleServer&) = delete; + + IVehicleServer(IVehicleServer&&) = default; + + virtual ~IVehicleServer() = default; + + // Receive the get property configuration request from HAL. + // Return a list of all property config + virtual std::vector onGetAllPropertyConfig() const = 0; + + // Receive the set property request from HAL. + // Process the setting and return the status code + // updateStatus indicate if VHal should change the status of the value + // it should be false except injecting values for e2e tests + virtual StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) = 0; + + // Receive a new property value from car (via direct connection to the car bus or the emulator) + // and forward the value to HAL + // updateStatus is true if and only if the value is + // generated by car (ECU/fake generator/injected) + virtual void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) = 0; + + // TODO (chenhaosjtuacm): fix this since there are no HIDL in non-Android OS +#ifdef __ANDROID__ + // Dump method forwarded from HIDL's debug() + // If implemented, it must return whether the caller should dump its state. + virtual bool onDump(const hidl_handle& /* handle */, + const hidl_vec& /* options */) { + return true; + } +#endif // __ANDROID__ +}; + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android From a6d6fa3d9d5e3c27f08f52c4f70a39b6d4f05c88 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Fri, 14 Feb 2020 11:51:26 -0800 Subject: [PATCH 0674/1022] Split client and server impl Some of the code in VHAL client implementation contains Android-specific code, and some of the server operations only works in the native case. So we split them up so that the AGL VHAL server can selectivly pick the parts it needs. It won't change the logic of native VHAL. Bug: 148877226 Bug: 150791171 Test: Build Change-Id: Ie142b19a5c435a0b4252ffd297504bde69eb44b0 (cherry picked from commit 7e9e37fa0a6278f1af454229cafc0707c27cd4c3) Merged-In: Ie142b19a5c435a0b4252ffd297504bde69eb44b0 --- automotive/vehicle/2.0/default/Android.bp | 2 + .../vhal_v2_0/EmulatedVehicleConnector.cpp | 350 +---------------- .../impl/vhal_v2_0/EmulatedVehicleConnector.h | 69 +--- .../impl/vhal_v2_0/EmulatedVehicleHal.cpp | 7 +- .../impl/vhal_v2_0/EmulatedVehicleHal.h | 4 +- .../impl/vhal_v2_0/VehicleHalClient.cpp | 39 ++ .../default/impl/vhal_v2_0/VehicleHalClient.h | 39 ++ .../impl/vhal_v2_0/VehicleHalServer.cpp | 353 ++++++++++++++++++ .../default/impl/vhal_v2_0/VehicleHalServer.h | 71 ++++ 9 files changed, 524 insertions(+), 410 deletions(-) create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp index 8e579012cd..e529675203 100644 --- a/automotive/vehicle/2.0/default/Android.bp +++ b/automotive/vehicle/2.0/default/Android.bp @@ -63,6 +63,8 @@ cc_library_static { "impl/vhal_v2_0/CommConn.cpp", "impl/vhal_v2_0/EmulatedVehicleConnector.cpp", "impl/vhal_v2_0/EmulatedVehicleHal.cpp", + "impl/vhal_v2_0/VehicleHalClient.cpp", + "impl/vhal_v2_0/VehicleHalServer.cpp", "impl/vhal_v2_0/VehicleEmulator.cpp", "impl/vhal_v2_0/PipeComm.cpp", "impl/vhal_v2_0/ProtoMessageConverter.cpp", diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp index 7f90914302..9c3c95facd 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp @@ -35,346 +35,16 @@ namespace V2_0 { namespace impl { -void EmulatedVehicleClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) { - if (!mPropCallback) { - LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!"; - return; - } - return mPropCallback(value, updateStatus); -} +class EmulatedPassthroughConnector : public PassthroughConnector { + public: + bool onDump(const hidl_handle& fd, const hidl_vec& options) override; -void EmulatedVehicleClient::registerPropertyValueCallback(PropertyCallBackType&& callback) { - if (mPropCallback) { - LOG(ERROR) << __func__ << ": Cannot register multiple callbacks!"; - return; - } - mPropCallback = std::move(callback); -} + private: + void dumpUserHal(int fd, std::string indent); +}; -GeneratorHub* EmulatedVehicleServer::getGenerator() { - return &mGeneratorHub; -} - -VehiclePropValuePool* EmulatedVehicleServer::getValuePool() const { - if (!mValuePool) { - LOG(WARNING) << __func__ << ": Value pool not set!"; - } - return mValuePool; -} - -void EmulatedVehicleServer::setValuePool(VehiclePropValuePool* valuePool) { - if (!valuePool) { - LOG(WARNING) << __func__ << ": Setting value pool to nullptr!"; - } - mValuePool = valuePool; -} - -void EmulatedVehicleServer::onFakeValueGenerated(const VehiclePropValue& value) { - constexpr bool updateStatus = true; - LOG(DEBUG) << __func__ << ": " << toString(value); - auto updatedPropValue = getValuePool()->obtain(value); - if (updatedPropValue) { - updatedPropValue->timestamp = value.timestamp; - updatedPropValue->status = VehiclePropertyStatus::AVAILABLE; - onPropertyValueFromCar(*updatedPropValue, updateStatus); - } -} - -std::vector EmulatedVehicleServer::onGetAllPropertyConfig() const { - std::vector vehiclePropConfigs; - constexpr size_t numOfVehiclePropConfigs = - sizeof(kVehicleProperties) / sizeof(kVehicleProperties[0]); - vehiclePropConfigs.reserve(numOfVehiclePropConfigs); - for (auto& it : kVehicleProperties) { - vehiclePropConfigs.emplace_back(it.config); - } - return vehiclePropConfigs; -} - -StatusCode EmulatedVehicleServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) { - constexpr bool updateStatus = true; - - LOG(INFO) << __func__; - const auto& v = request.value; - if (!v.int32Values.size()) { - LOG(ERROR) << __func__ << ": expected at least \"command\" field in int32Values"; - return StatusCode::INVALID_ARG; - } - - FakeDataCommand command = static_cast(v.int32Values[0]); - - switch (command) { - case FakeDataCommand::StartLinear: { - LOG(INFO) << __func__ << ", FakeDataCommand::StartLinear"; - if (v.int32Values.size() < 2) { - LOG(ERROR) << __func__ << ": expected property ID in int32Values"; - return StatusCode::INVALID_ARG; - } - if (!v.int64Values.size()) { - LOG(ERROR) << __func__ << ": interval is not provided in int64Values"; - return StatusCode::INVALID_ARG; - } - if (v.floatValues.size() < 3) { - LOG(ERROR) << __func__ << ": expected at least 3 elements in floatValues, got: " - << v.floatValues.size(); - return StatusCode::INVALID_ARG; - } - int32_t cookie = v.int32Values[1]; - getGenerator()->registerGenerator(cookie, - std::make_unique(request)); - break; - } - case FakeDataCommand::StartJson: { - LOG(INFO) << __func__ << ", FakeDataCommand::StartJson"; - if (v.stringValue.empty()) { - LOG(ERROR) << __func__ << ": path to JSON file is missing"; - return StatusCode::INVALID_ARG; - } - int32_t cookie = std::hash()(v.stringValue); - getGenerator()->registerGenerator(cookie, - std::make_unique(request)); - break; - } - case FakeDataCommand::StopLinear: { - LOG(INFO) << __func__ << ", FakeDataCommand::StopLinear"; - if (v.int32Values.size() < 2) { - LOG(ERROR) << __func__ << ": expected property ID in int32Values"; - return StatusCode::INVALID_ARG; - } - int32_t cookie = v.int32Values[1]; - getGenerator()->unregisterGenerator(cookie); - break; - } - case FakeDataCommand::StopJson: { - LOG(INFO) << __func__ << ", FakeDataCommand::StopJson"; - if (v.stringValue.empty()) { - LOG(ERROR) << __func__ << ": path to JSON file is missing"; - return StatusCode::INVALID_ARG; - } - int32_t cookie = std::hash()(v.stringValue); - getGenerator()->unregisterGenerator(cookie); - break; - } - case FakeDataCommand::KeyPress: { - LOG(INFO) << __func__ << ", FakeDataCommand::KeyPress"; - int32_t keyCode = request.value.int32Values[2]; - int32_t display = request.value.int32Values[3]; - // Send back to HAL - onPropertyValueFromCar( - *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display), - updateStatus); - onPropertyValueFromCar( - *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display), - updateStatus); - break; - } - default: { - LOG(ERROR) << __func__ << ": unexpected command: " << toInt(command); - return StatusCode::INVALID_ARG; - } - } - return StatusCode::OK; -} - -VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createApPowerStateReq( - VehicleApPowerStateReq state, int32_t param) { - auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2); - req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ); - req->areaId = 0; - req->timestamp = elapsedRealtimeNano(); - req->status = VehiclePropertyStatus::AVAILABLE; - req->value.int32Values[0] = toInt(state); - req->value.int32Values[1] = param; - return req; -} - -VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createHwInputKeyProp( - VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) { - auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3); - keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT); - keyEvent->areaId = 0; - keyEvent->timestamp = elapsedRealtimeNano(); - keyEvent->status = VehiclePropertyStatus::AVAILABLE; - keyEvent->value.int32Values[0] = toInt(action); - keyEvent->value.int32Values[1] = keyCode; - keyEvent->value.int32Values[2] = targetDisplay; - return keyEvent; -} - -StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, bool updateStatus) { - // Some properties need to be treated non-trivially - switch (value.prop) { - case kGenerateFakeDataControllingProperty: - return handleGenerateFakeDataRequest(value); - - // set the value from vehicle side, used in end to end test. - case kSetIntPropertyFromVehicleForTest: { - auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1); - updatedPropValue->prop = value.value.int32Values[0]; - updatedPropValue->value.int32Values[0] = value.value.int32Values[1]; - updatedPropValue->timestamp = value.value.int64Values[0]; - updatedPropValue->areaId = value.areaId; - onPropertyValueFromCar(*updatedPropValue, updateStatus); - return StatusCode::OK; - } - case kSetFloatPropertyFromVehicleForTest: { - auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1); - updatedPropValue->prop = value.value.int32Values[0]; - updatedPropValue->value.floatValues[0] = value.value.floatValues[0]; - updatedPropValue->timestamp = value.value.int64Values[0]; - updatedPropValue->areaId = value.areaId; - onPropertyValueFromCar(*updatedPropValue, updateStatus); - return StatusCode::OK; - } - case kSetBooleanPropertyFromVehicleForTest: { - auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1); - updatedPropValue->prop = value.value.int32Values[1]; - updatedPropValue->value.int32Values[0] = value.value.int32Values[0]; - updatedPropValue->timestamp = value.value.int64Values[0]; - updatedPropValue->areaId = value.areaId; - onPropertyValueFromCar(*updatedPropValue, updateStatus); - return StatusCode::OK; - } - - case AP_POWER_STATE_REPORT: - switch (value.value.int32Values[0]) { - case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT): - case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED): - case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL): - // CPMS is in WAIT_FOR_VHAL state, simply move to ON - // Send back to HAL - // ALWAYS update status for generated property value - onPropertyValueFromCar(*createApPowerStateReq(VehicleApPowerStateReq::ON, 0), - true /* updateStatus */); - break; - case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY): - case toInt(VehicleApPowerStateReport::SHUTDOWN_START): - // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command - // Send back to HAL - // ALWAYS update status for generated property value - onPropertyValueFromCar( - *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0), - true /* updateStatus */); - break; - case toInt(VehicleApPowerStateReport::ON): - case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE): - case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE): - // Do nothing - break; - default: - // Unknown state - break; - } - break; - case INITIAL_USER_INFO: - return onSetInitialUserInfo(value, updateStatus); - default: - break; - } - - // In the real vhal, the value will be sent to Car ECU. - // We just pretend it is done here and send back to HAL - auto updatedPropValue = getValuePool()->obtain(value); - updatedPropValue->timestamp = elapsedRealtimeNano(); - - onPropertyValueFromCar(*updatedPropValue, updateStatus); - return StatusCode::OK; -} - -/** - * INITIAL_USER_INFO is called by Android when it starts, and it's expecting a property change - * indicating what the initial user should be. - * - * During normal circumstances, the emulator will reply right away, passing a response if - * InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which user - * to boot). - * - * But during development / testing, the behavior can be changed using lshal dump, which must use - * the areaId to indicate what should happen next. - * - * So, the behavior of set(INITIAL_USER_INFO) is: - * - * - if it has an areaId, store the property into mInitialUserResponseFromCmd (as it was called by - * lshal). - * - else if mInitialUserResponseFromCmd is not set, return a response with the same request id and - * InitialUserInfoResponseAction::DEFAULT - * - else the behavior is defined by the areaId on mInitialUserResponseFromCmd: - * - if it's 1, reply with mInitialUserResponseFromCmd and the right request id - * - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can test - * this error scenario) - * - if it's 3, then don't send a property change (so Android can emulate a timeout) - * - */ -StatusCode EmulatedVehicleServer::onSetInitialUserInfo(const VehiclePropValue& value, - bool updateStatus) { - // TODO: LOG calls below might be more suited to be DEBUG, but those are not being logged - // (even when explicitly calling setprop log.tag. As this class should be using ALOG instead of - // LOG, it's not worth investigating why... - - if (value.value.int32Values.size() == 0) { - LOG(ERROR) << "set(INITIAL_USER_INFO): no int32values, ignoring it: " << toString(value); - return StatusCode::INVALID_ARG; - } - - if (value.areaId != 0) { - LOG(INFO) << "set(INITIAL_USER_INFO) called from lshal; storing it: " << toString(value); - mInitialUserResponseFromCmd.reset(new VehiclePropValue(value)); - return StatusCode::OK; - } - LOG(INFO) << "set(INITIAL_USER_INFO) called from Android: " << toString(value); - - int32_t requestId = value.value.int32Values[0]; - - // Create the update property and set common values - auto updatedValue = createVehiclePropValue(VehiclePropertyType::MIXED, 0); - updatedValue->prop = INITIAL_USER_INFO; - updatedValue->timestamp = elapsedRealtimeNano(); - - if (mInitialUserResponseFromCmd == nullptr) { - updatedValue->value.int32Values.resize(2); - updatedValue->value.int32Values[0] = requestId; - updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT; - LOG(INFO) << "no lshal response; returning InitialUserInfoResponseAction::DEFAULT: " - << toString(*updatedValue); - onPropertyValueFromCar(*updatedValue, updateStatus); - return StatusCode::OK; - } - - // mInitialUserResponseFromCmd is used for just one request - std::unique_ptr response = std::move(mInitialUserResponseFromCmd); - - // TODO(b/138709788): rather than populate the raw values directly, it should use the - // libraries that convert a InitialUserInfoResponse into a VehiclePropValue) - - switch (response->areaId) { - case 1: - LOG(INFO) << "returning response with right request id"; - *updatedValue = *response; - updatedValue->areaId = 0; - updatedValue->value.int32Values[0] = requestId; - break; - case 2: - LOG(INFO) << "returning response with wrong request id"; - *updatedValue = *response; - updatedValue->areaId = 0; - updatedValue->value.int32Values[0] = -requestId; - break; - case 3: - LOG(INFO) << "not generating a property change event because of lshal prop: " - << toString(*response); - return StatusCode::OK; - default: - LOG(ERROR) << "invalid action on lshal response: " << toString(*response); - return StatusCode::INTERNAL_ERROR; - } - - LOG(INFO) << "updating property to: " << toString(*updatedValue); - onPropertyValueFromCar(*updatedValue, updateStatus); - return StatusCode::OK; -} - -bool EmulatedVehicleServer::onDump(const hidl_handle& handle, - const hidl_vec& options) { +bool EmulatedPassthroughConnector::onDump(const hidl_handle& handle, + const hidl_vec& options) { int fd = handle->data[0]; if (options.size() > 0) { @@ -401,7 +71,7 @@ bool EmulatedVehicleServer::onDump(const hidl_handle& handle, return true; } -void EmulatedVehicleServer::dumpUserHal(int fd, std::string indent) { +void EmulatedPassthroughConnector::dumpUserHal(int fd, std::string indent) { if (mInitialUserResponseFromCmd != nullptr) { dprintf(fd, "%sInitial User Info: %s\n", indent.c_str(), toString(*mInitialUserResponseFromCmd).c_str()); @@ -410,7 +80,7 @@ void EmulatedVehicleServer::dumpUserHal(int fd, std::string indent) { } } -EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() { +PassthroughConnectorPtr makeEmulatedPassthroughConnector() { return std::make_unique(); } diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h index 4850d32d94..57cbb8b893 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h @@ -18,9 +18,9 @@ #define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_ #include -#include -#include "GeneratorHub.h" +#include "VehicleHalClient.h" +#include "VehicleHalServer.h" namespace android { namespace hardware { @@ -30,69 +30,10 @@ namespace V2_0 { namespace impl { -// Extension of the client/server interfaces for emulated vehicle +using PassthroughConnector = IPassThroughConnector; +using PassthroughConnectorPtr = std::unique_ptr; -class EmulatedVehicleClient : public IVehicleClient { - public: - // Type of callback function for handling the new property values - using PropertyCallBackType = std::function; - - // Method from IVehicleClient - void onPropertyValue(const VehiclePropValue& value, bool updateStatus) override; - - void registerPropertyValueCallback(PropertyCallBackType&& callback); - - private: - PropertyCallBackType mPropCallback; -}; - -class EmulatedVehicleServer : public IVehicleServer { - public: - // Methods from IVehicleServer - - std::vector onGetAllPropertyConfig() const override; - - StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override; - - bool onDump(const hidl_handle& fd, const hidl_vec& options) override; - - // Set the Property Value Pool used in this server - void setValuePool(VehiclePropValuePool* valuePool); - - private: - GeneratorHub* getGenerator(); - - VehiclePropValuePool* getValuePool() const; - - void onFakeValueGenerated(const VehiclePropValue& value); - - StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request); - - VehicleHal::VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param); - - VehicleHal::VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, - int32_t keyCode, int32_t targetDisplay); - - // private data members - - GeneratorHub mGeneratorHub{ - std::bind(&EmulatedVehicleServer::onFakeValueGenerated, this, std::placeholders::_1)}; - - VehiclePropValuePool* mValuePool{nullptr}; - - // TODO(b/146207078): it might be clearer to move members below to an EmulatedUserHal class - std::unique_ptr mInitialUserResponseFromCmd; - StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus); - void dumpUserHal(int fd, std::string indent); -}; - -// Helper functions - -using EmulatedPassthroughConnector = - IPassThroughConnector; -using EmulatedPassthroughConnectorPtr = std::unique_ptr; - -EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector(); +PassthroughConnectorPtr makeEmulatedPassthroughConnector(); } // namespace impl 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 692c7f791f..6d5f23f7fc 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 @@ -87,12 +87,11 @@ static std::unique_ptr fillDefaultObd2Frame(size_t numVendorInt return sensorStore; } -EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, - EmulatedVehicleClient* client) +EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client) : mPropStore(propStore), mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)), - mRecurrentTimer( - std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)), + mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, + std::placeholders::_1)), mVehicleClient(client) { initStaticConfig(); for (size_t i = 0; i < arraysize(kVehicleProperties); i++) { diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h index ebc405e04a..ebf19951b3 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h @@ -46,7 +46,7 @@ namespace impl { class EmulatedVehicleHal : public EmulatedVehicleHalIface { public: EmulatedVehicleHal(VehiclePropertyStore* propStore, - EmulatedVehicleClient* client); + VehicleHalClient* client); ~EmulatedVehicleHal() = default; // Methods from VehicleHal @@ -85,7 +85,7 @@ private: VehiclePropertyStore* mPropStore; std::unordered_set mHvacPowerProps; RecurrentTimer mRecurrentTimer; - EmulatedVehicleClient* mVehicleClient; + VehicleHalClient* mVehicleClient; }; } // impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp new file mode 100644 index 0000000000..25ffc6d70d --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp @@ -0,0 +1,39 @@ +/* + * 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 "VehicleHalClient.h" + +#include + +namespace android::hardware::automotive::vehicle::V2_0::impl { + +void VehicleHalClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) { + if (!mPropCallback) { + LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!"; + return; + } + return mPropCallback(value, updateStatus); +} + +void VehicleHalClient::registerPropertyValueCallback(PropertyCallBackType&& callback) { + if (mPropCallback) { + LOG(ERROR) << __func__ << ": Cannot register multiple callbacks!"; + return; + } + mPropCallback = std::move(callback); +} + +} // namespace android::hardware::automotive::vehicle::V2_0::impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h new file mode 100644 index 0000000000..6559e2aa84 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace android::hardware::automotive::vehicle::V2_0::impl { + +// The common client operations that may be used by both native and +// virtualized VHAL clients. +class VehicleHalClient : public IVehicleClient { + public: + // Type of callback function for handling the new property values + using PropertyCallBackType = std::function; + + // Method from IVehicleClient + void onPropertyValue(const VehiclePropValue& value, bool updateStatus) override; + + void registerPropertyValueCallback(PropertyCallBackType&& callback); + + private: + PropertyCallBackType mPropCallback; +}; + +} // namespace android::hardware::automotive::vehicle::V2_0::impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp new file mode 100644 index 0000000000..a91ca8e770 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp @@ -0,0 +1,353 @@ +/* + * 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 "VehicleHalServer.h" + +#include + +#include +#include + +#include "DefaultConfig.h" +#include "JsonFakeValueGenerator.h" +#include "LinearFakeValueGenerator.h" +#include "Obd2SensorStore.h" + +namespace android::hardware::automotive::vehicle::V2_0::impl { + +GeneratorHub* VehicleHalServer::getGenerator() { + return &mGeneratorHub; +} + +VehiclePropValuePool* VehicleHalServer::getValuePool() const { + if (!mValuePool) { + LOG(WARNING) << __func__ << ": Value pool not set!"; + } + return mValuePool; +} + +void VehicleHalServer::setValuePool(VehiclePropValuePool* valuePool) { + if (!valuePool) { + LOG(WARNING) << __func__ << ": Setting value pool to nullptr!"; + } + mValuePool = valuePool; +} + +void VehicleHalServer::onFakeValueGenerated(const VehiclePropValue& value) { + constexpr bool updateStatus = true; + LOG(DEBUG) << __func__ << ": " << toString(value); + auto updatedPropValue = getValuePool()->obtain(value); + if (updatedPropValue) { + updatedPropValue->timestamp = value.timestamp; + updatedPropValue->status = VehiclePropertyStatus::AVAILABLE; + onPropertyValueFromCar(*updatedPropValue, updateStatus); + } +} + +std::vector VehicleHalServer::onGetAllPropertyConfig() const { + std::vector vehiclePropConfigs; + constexpr size_t numOfVehiclePropConfigs = + sizeof(kVehicleProperties) / sizeof(kVehicleProperties[0]); + vehiclePropConfigs.reserve(numOfVehiclePropConfigs); + for (auto& it : kVehicleProperties) { + vehiclePropConfigs.emplace_back(it.config); + } + return vehiclePropConfigs; +} + +StatusCode VehicleHalServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) { + constexpr bool updateStatus = true; + + LOG(INFO) << __func__; + const auto& v = request.value; + if (!v.int32Values.size()) { + LOG(ERROR) << __func__ << ": expected at least \"command\" field in int32Values"; + return StatusCode::INVALID_ARG; + } + + FakeDataCommand command = static_cast(v.int32Values[0]); + + switch (command) { + case FakeDataCommand::StartLinear: { + LOG(INFO) << __func__ << ", FakeDataCommand::StartLinear"; + if (v.int32Values.size() < 2) { + LOG(ERROR) << __func__ << ": expected property ID in int32Values"; + return StatusCode::INVALID_ARG; + } + if (!v.int64Values.size()) { + LOG(ERROR) << __func__ << ": interval is not provided in int64Values"; + return StatusCode::INVALID_ARG; + } + if (v.floatValues.size() < 3) { + LOG(ERROR) << __func__ << ": expected at least 3 elements in floatValues, got: " + << v.floatValues.size(); + return StatusCode::INVALID_ARG; + } + int32_t cookie = v.int32Values[1]; + getGenerator()->registerGenerator(cookie, + std::make_unique(request)); + break; + } + case FakeDataCommand::StartJson: { + LOG(INFO) << __func__ << ", FakeDataCommand::StartJson"; + if (v.stringValue.empty()) { + LOG(ERROR) << __func__ << ": path to JSON file is missing"; + return StatusCode::INVALID_ARG; + } + int32_t cookie = std::hash()(v.stringValue); + getGenerator()->registerGenerator(cookie, + std::make_unique(request)); + break; + } + case FakeDataCommand::StopLinear: { + LOG(INFO) << __func__ << ", FakeDataCommand::StopLinear"; + if (v.int32Values.size() < 2) { + LOG(ERROR) << __func__ << ": expected property ID in int32Values"; + return StatusCode::INVALID_ARG; + } + int32_t cookie = v.int32Values[1]; + getGenerator()->unregisterGenerator(cookie); + break; + } + case FakeDataCommand::StopJson: { + LOG(INFO) << __func__ << ", FakeDataCommand::StopJson"; + if (v.stringValue.empty()) { + LOG(ERROR) << __func__ << ": path to JSON file is missing"; + return StatusCode::INVALID_ARG; + } + int32_t cookie = std::hash()(v.stringValue); + getGenerator()->unregisterGenerator(cookie); + break; + } + case FakeDataCommand::KeyPress: { + LOG(INFO) << __func__ << ", FakeDataCommand::KeyPress"; + int32_t keyCode = request.value.int32Values[2]; + int32_t display = request.value.int32Values[3]; + // Send back to HAL + onPropertyValueFromCar( + *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display), + updateStatus); + onPropertyValueFromCar( + *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display), + updateStatus); + break; + } + default: { + LOG(ERROR) << __func__ << ": unexpected command: " << toInt(command); + return StatusCode::INVALID_ARG; + } + } + return StatusCode::OK; +} + +VehicleHalServer::VehiclePropValuePtr VehicleHalServer::createApPowerStateReq( + VehicleApPowerStateReq state, int32_t param) { + auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2); + req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ); + req->areaId = 0; + req->timestamp = elapsedRealtimeNano(); + req->status = VehiclePropertyStatus::AVAILABLE; + req->value.int32Values[0] = toInt(state); + req->value.int32Values[1] = param; + return req; +} + +VehicleHalServer::VehiclePropValuePtr VehicleHalServer::createHwInputKeyProp( + VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) { + auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3); + keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT); + keyEvent->areaId = 0; + keyEvent->timestamp = elapsedRealtimeNano(); + keyEvent->status = VehiclePropertyStatus::AVAILABLE; + keyEvent->value.int32Values[0] = toInt(action); + keyEvent->value.int32Values[1] = keyCode; + keyEvent->value.int32Values[2] = targetDisplay; + return keyEvent; +} + +StatusCode VehicleHalServer::onSetProperty(const VehiclePropValue& value, bool updateStatus) { + // Some properties need to be treated non-trivially + switch (value.prop) { + case kGenerateFakeDataControllingProperty: + return handleGenerateFakeDataRequest(value); + + // set the value from vehicle side, used in end to end test. + case kSetIntPropertyFromVehicleForTest: { + auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1); + updatedPropValue->prop = value.value.int32Values[0]; + updatedPropValue->value.int32Values[0] = value.value.int32Values[1]; + updatedPropValue->timestamp = value.value.int64Values[0]; + updatedPropValue->areaId = value.areaId; + onPropertyValueFromCar(*updatedPropValue, updateStatus); + return StatusCode::OK; + } + case kSetFloatPropertyFromVehicleForTest: { + auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1); + updatedPropValue->prop = value.value.int32Values[0]; + updatedPropValue->value.floatValues[0] = value.value.floatValues[0]; + updatedPropValue->timestamp = value.value.int64Values[0]; + updatedPropValue->areaId = value.areaId; + onPropertyValueFromCar(*updatedPropValue, updateStatus); + return StatusCode::OK; + } + case kSetBooleanPropertyFromVehicleForTest: { + auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1); + updatedPropValue->prop = value.value.int32Values[1]; + updatedPropValue->value.int32Values[0] = value.value.int32Values[0]; + updatedPropValue->timestamp = value.value.int64Values[0]; + updatedPropValue->areaId = value.areaId; + onPropertyValueFromCar(*updatedPropValue, updateStatus); + return StatusCode::OK; + } + + case AP_POWER_STATE_REPORT: + switch (value.value.int32Values[0]) { + case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT): + case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED): + case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL): + // CPMS is in WAIT_FOR_VHAL state, simply move to ON + // Send back to HAL + // ALWAYS update status for generated property value + onPropertyValueFromCar(*createApPowerStateReq(VehicleApPowerStateReq::ON, 0), + true /* updateStatus */); + break; + case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY): + case toInt(VehicleApPowerStateReport::SHUTDOWN_START): + // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command + // Send back to HAL + // ALWAYS update status for generated property value + onPropertyValueFromCar( + *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0), + true /* updateStatus */); + break; + case toInt(VehicleApPowerStateReport::ON): + case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE): + case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE): + // Do nothing + break; + default: + // Unknown state + break; + } + break; + case INITIAL_USER_INFO: + return onSetInitialUserInfo(value, updateStatus); + default: + break; + } + + // In the real vhal, the value will be sent to Car ECU. + // We just pretend it is done here and send back to HAL + auto updatedPropValue = getValuePool()->obtain(value); + updatedPropValue->timestamp = elapsedRealtimeNano(); + + onPropertyValueFromCar(*updatedPropValue, updateStatus); + return StatusCode::OK; +} + +/** + * INITIAL_USER_INFO is called by Android when it starts, and it's expecting a property change + * indicating what the initial user should be. + * + * During normal circumstances, the emulator will reply right away, passing a response if + * InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which user + * to boot). + * + * But during development / testing, the behavior can be changed using lshal dump, which must use + * the areaId to indicate what should happen next. + * + * So, the behavior of set(INITIAL_USER_INFO) is: + * + * - if it has an areaId, store the property into mInitialUserResponseFromCmd (as it was called by + * lshal). + * - else if mInitialUserResponseFromCmd is not set, return a response with the same request id and + * InitialUserInfoResponseAction::DEFAULT + * - else the behavior is defined by the areaId on mInitialUserResponseFromCmd: + * - if it's 1, reply with mInitialUserResponseFromCmd and the right request id + * - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can test + * this error scenario) + * - if it's 3, then don't send a property change (so Android can emulate a timeout) + * + */ +StatusCode VehicleHalServer::onSetInitialUserInfo(const VehiclePropValue& value, + bool updateStatus) { + // TODO: LOG calls below might be more suited to be DEBUG, but those are not being logged + // (even when explicitly calling setprop log.tag. As this class should be using ALOG instead of + // LOG, it's not worth investigating why... + + if (value.value.int32Values.size() == 0) { + LOG(ERROR) << "set(INITIAL_USER_INFO): no int32values, ignoring it: " << toString(value); + return StatusCode::INVALID_ARG; + } + + if (value.areaId != 0) { + LOG(INFO) << "set(INITIAL_USER_INFO) called from lshal; storing it: " << toString(value); + mInitialUserResponseFromCmd.reset(new VehiclePropValue(value)); + return StatusCode::OK; + } + LOG(INFO) << "set(INITIAL_USER_INFO) called from Android: " << toString(value); + + int32_t requestId = value.value.int32Values[0]; + + // Create the update property and set common values + auto updatedValue = createVehiclePropValue(VehiclePropertyType::MIXED, 0); + updatedValue->prop = INITIAL_USER_INFO; + updatedValue->timestamp = elapsedRealtimeNano(); + + if (mInitialUserResponseFromCmd == nullptr) { + updatedValue->value.int32Values.resize(2); + updatedValue->value.int32Values[0] = requestId; + updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT; + LOG(INFO) << "no lshal response; returning InitialUserInfoResponseAction::DEFAULT: " + << toString(*updatedValue); + onPropertyValueFromCar(*updatedValue, updateStatus); + return StatusCode::OK; + } + + // mInitialUserResponseFromCmd is used for just one request + std::unique_ptr response = std::move(mInitialUserResponseFromCmd); + + // TODO(b/138709788): rather than populate the raw values directly, it should use the + // libraries that convert a InitialUserInfoResponse into a VehiclePropValue) + + switch (response->areaId) { + case 1: + LOG(INFO) << "returning response with right request id"; + *updatedValue = *response; + updatedValue->areaId = 0; + updatedValue->value.int32Values[0] = requestId; + break; + case 2: + LOG(INFO) << "returning response with wrong request id"; + *updatedValue = *response; + updatedValue->areaId = 0; + updatedValue->value.int32Values[0] = -requestId; + break; + case 3: + LOG(INFO) << "not generating a property change event because of lshal prop: " + << toString(*response); + return StatusCode::OK; + default: + LOG(ERROR) << "invalid action on lshal response: " << toString(*response); + return StatusCode::INTERNAL_ERROR; + } + + LOG(INFO) << "updating property to: " << toString(*updatedValue); + onPropertyValueFromCar(*updatedValue, updateStatus); + return StatusCode::OK; +} + +} // namespace android::hardware::automotive::vehicle::V2_0::impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h new file mode 100644 index 0000000000..b1ae106331 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include "GeneratorHub.h" + +namespace android::hardware::automotive::vehicle::V2_0::impl { + +// This contains the common server operations that will be used by +// both native and virtualized VHAL server. Notice that in the virtualized +// scenario, the server may be run on a different OS than Android. +class VehicleHalServer : public IVehicleServer { + public: + // Methods from IVehicleServer + + std::vector onGetAllPropertyConfig() const override; + + StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override; + + // Set the Property Value Pool used in this server + void setValuePool(VehiclePropValuePool* valuePool); + + private: + using VehiclePropValuePtr = recyclable_ptr; + + GeneratorHub* getGenerator(); + + VehiclePropValuePool* getValuePool() const; + + void onFakeValueGenerated(const VehiclePropValue& value); + + StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request); + + VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param); + + VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode, + int32_t targetDisplay); + + StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus); + + // data members + + protected: + // TODO(b/146207078): it might be clearer to move members below to an EmulatedUserHal class + std::unique_ptr mInitialUserResponseFromCmd; + + private: + GeneratorHub mGeneratorHub{ + std::bind(&VehicleHalServer::onFakeValueGenerated, this, std::placeholders::_1)}; + + VehiclePropValuePool* mValuePool{nullptr}; +}; + +} // namespace android::hardware::automotive::vehicle::V2_0::impl From f724a227b057ad8fdf6b33082c00923901bd710b Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Tue, 25 Feb 2020 13:20:41 -0800 Subject: [PATCH 0675/1022] Merge nested namesapces fix the nits in ag/10318156 Bug: 150791171 Test: build Change-Id: I44609f8c7cbeffcb02cb9f2e2f56f3a829de17f6 Merged-In: I44609f8c7cbeffcb02cb9f2e2f56f3a829de17f6 --- .../default/common/include/vhal_v2_0/VehicleClient.h | 12 ++---------- .../default/common/include/vhal_v2_0/VehicleServer.h | 12 ++---------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h index 1e2f3add17..5e4bf27d6b 100644 --- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h @@ -20,11 +20,7 @@ #include -namespace android { -namespace hardware { -namespace automotive { -namespace vehicle { -namespace V2_0 { +namespace android::hardware::automotive::vehicle::V2_0 { /** * Vehicle HAL talks to the vehicle through a client, instead of accessing @@ -66,8 +62,4 @@ class IVehicleClient { } }; -} // namespace V2_0 -} // namespace vehicle -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::vehicle::V2_0 diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h index 27ebbeef55..ba9799af1b 100644 --- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h @@ -20,11 +20,7 @@ #include -namespace android { -namespace hardware { -namespace automotive { -namespace vehicle { -namespace V2_0 { +namespace android::hardware::automotive::vehicle::V2_0 { /** * Server lives on the vehicle side to talk to Android HAL. @@ -69,8 +65,4 @@ class IVehicleServer { #endif // __ANDROID__ }; -} // namespace V2_0 -} // namespace vehicle -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::vehicle::V2_0 From fa161c7a0a2d1719680248ccc6d8978209a13d19 Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Tue, 25 Feb 2020 16:57:53 -0800 Subject: [PATCH 0676/1022] Add tests to make sure executeFenced validate unspecified output shapes Bug: 148979873 Test: mm Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: Ib4960c71ca46ca034777cc7b02d7d2885a98691d --- .../vts/functional/GeneratedTestHarness.cpp | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 3e2be8a346..83a8d94ba5 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -640,7 +640,7 @@ void EvaluatePreparedModel(const sp& device, const sp& if (result != ErrorStatus::NONE) { ASSERT_EQ(syncFenceHandle.getNativeHandle(), nullptr); ASSERT_EQ(fencedCallback, nullptr); - executionStatus = ErrorStatus::GENERAL_FAILURE; + executionStatus = result; } else if (syncFenceHandle.getNativeHandle()) { // If a sync fence is returned, try start another run waiting for the sync fence. ret = preparedModel->executeFenced(request, {syncFenceHandle}, @@ -663,9 +663,7 @@ void EvaluatePreparedModel(const sp& device, const sp& } } - // The driver is allowed to reject executeFenced, and if they do, we should skip. - if ((testConfig.outputType != OutputType::FULLY_SPECIFIED || - testConfig.executor == Executor::FENCED) && + if (testConfig.outputType != OutputType::FULLY_SPECIFIED && executionStatus == ErrorStatus::GENERAL_FAILURE) { if (skipped != nullptr) { *skipped = true; @@ -698,12 +696,22 @@ void EvaluatePreparedModel(const sp& device, const sp& outputShapes.size() == testModel.main.outputIndexes.size()); break; case OutputType::UNSPECIFIED: + if (testConfig.executor == Executor::FENCED) { + // For Executor::FENCED, the output shape must be fully specified. + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus); + return; + } // If the model output operands are not fully specified, outputShapes must have // the same number of elements as the number of outputs. ASSERT_EQ(ErrorStatus::NONE, executionStatus); ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size()); break; case OutputType::INSUFFICIENT: + if (testConfig.executor == Executor::FENCED) { + // For Executor::FENCED, the output shape must be fully specified. + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus); + return; + } ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus); ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size()); ASSERT_FALSE(outputShapes[0].isSufficient); @@ -746,7 +754,7 @@ void EvaluatePreparedModel(const sp& device, const sp& case TestKind::DYNAMIC_SHAPE: { outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT}; measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; - executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; + executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST, Executor::FENCED}; } break; case TestKind::MEMORY_DOMAIN: { outputTypesList = {OutputType::FULLY_SPECIFIED}; @@ -928,8 +936,13 @@ INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, [](const TestModel& testModel INSTANTIATE_GENERATED_TEST(MemoryDomainTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); -INSTANTIATE_GENERATED_TEST(FencedComputeTest, - [](const TestModel& testModel) { return !testModel.expectFailure; }); +INSTANTIATE_GENERATED_TEST(FencedComputeTest, [](const TestModel& testModel) { + return !testModel.expectFailure && + std::all_of(testModel.main.outputIndexes.begin(), testModel.main.outputIndexes.end(), + [&testModel](uint32_t index) { + return testModel.main.operands[index].data.size() > 0; + }); +}); INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) { return testModel.hasQuant8CoupledOperands() && testModel.main.operations.size() == 1; From e6477dc808ab7b2d734ee95a20c77d65721caa7b Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Thu, 5 Mar 2020 17:01:26 -0800 Subject: [PATCH 0677/1022] Use Google-style C++ loggers This change replaces ALOG* usages in VtsHalEvsV1_1 with Google-style C++ loggers. Bug: 150893461 Test: Run VtsHalEvsV1_1TargetTest Change-Id: Ia93c5a00d580bae99d15a7a893e57e0f1e2397d5 --- .../functional/VtsHalEvsV1_1TargetTest.cpp | 138 ++++++++++-------- 1 file changed, 76 insertions(+), 62 deletions(-) diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index cde80482cb..b31795bcb5 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -38,16 +38,15 @@ static const float kNanoToSeconds = 0.000000001f; #include #include -#include #include #include -#include #include #include #include #include #include +#include #include #include #include @@ -120,11 +119,12 @@ protected: // Get the camera list pEnumerator->getCameraList_1_1( [this](hidl_vec cameraList) { - ALOGI("Camera list callback received %zu cameras", - cameraList.size()); + LOG(INFO) << "Camera list callback received " + << cameraList.size() + << " cameras"; cameraInfo.reserve(cameraList.size()); for (auto&& cam: cameraList) { - ALOGI("Found camera %s", cam.v1.cameraId.c_str()); + LOG(INFO) << "Found camera " << cam.v1.cameraId; cameraInfo.push_back(cam); } } @@ -137,10 +137,12 @@ protected: // Get the ultrasonics array list pEnumerator->getUltrasonicsArrayList([this](hidl_vec ultraList) { - ALOGI("Ultrasonics array list callback received %zu arrays", ultraList.size()); + LOG(INFO) << "Ultrasonics array list callback received " + << ultraList.size() + << " arrays"; ultrasonicsArraysInfo.reserve(ultraList.size()); for (auto&& ultraArray : ultraList) { - ALOGI("Found ultrasonics array %s", ultraArray.ultrasonicsArrayId.c_str()); + LOG(INFO) << "Found ultrasonics array " << ultraArray.ultrasonicsArrayId; ultrasonicsArraysInfo.push_back(ultraArray); } }); @@ -195,7 +197,7 @@ protected: if (!flag) { // EVS assumes that the device w/o a valid metadata is a physical // device. - ALOGI("%s is not a logical camera device.", id.c_str()); + LOG(INFO) << id << " is not a logical camera device."; physicalCameras.emplace(id); return physicalCameras; } @@ -205,7 +207,9 @@ protected: int rc = find_camera_metadata_ro_entry(metadata, ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS, &entry); - ALOGE_IF(rc, "No physical camera ID is found for a logical camera device"); + if (rc != 0) { + LOG(ERROR) << "No physical camera ID is found for a logical camera device"; + } const uint8_t *ids = entry.data.u8; size_t start = 0; @@ -219,7 +223,10 @@ protected: } } - ALOGI("%s consists of %d physical camera devices.", id.c_str(), (int)physicalCameras.size()); + LOG(INFO) << id + << " consists of " + << physicalCameras.size() + << " physical camera devices"; return physicalCameras; } @@ -247,7 +254,7 @@ protected: * call to closeCamera. Then repeats the test to ensure all cameras can be reopened. */ TEST_P(EvsHidlTest, CameraOpenClean) { - ALOGI("Starting CameraOpenClean test"); + LOG(INFO) << "Starting CameraOpenClean test"; // Get the camera list loadCameraList(); @@ -261,7 +268,7 @@ TEST_P(EvsHidlTest, CameraOpenClean) { bool isLogicalCam = false; auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); if (mIsHwModule && isLogicalCam) { - ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str()); + LOG(INFO) << "Skip a logical device, " << cam.v1.cameraId << " for HW target."; continue; } @@ -286,7 +293,7 @@ TEST_P(EvsHidlTest, CameraOpenClean) { // Verify that this camera self-identifies correctly pCam->getCameraInfo_1_1([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.v1.cameraId.c_str()); + LOG(DEBUG) << "Found camera " << desc.v1.cameraId; EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); } ); @@ -316,7 +323,7 @@ TEST_P(EvsHidlTest, CameraOpenClean) { * the system to be tolerant of shutdown/restart race conditions. */ TEST_P(EvsHidlTest, CameraOpenAggressive) { - ALOGI("Starting CameraOpenAggressive test"); + LOG(INFO) << "Starting CameraOpenAggressive test"; // Get the camera list loadCameraList(); @@ -330,7 +337,7 @@ TEST_P(EvsHidlTest, CameraOpenAggressive) { bool isLogicalCam = false; getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); if (mIsHwModule && isLogicalCam) { - ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str()); + LOG(INFO) << "Skip a logical device, " << cam.v1.cameraId << " for HW target."; continue; } @@ -345,7 +352,7 @@ TEST_P(EvsHidlTest, CameraOpenAggressive) { // Verify that this camera self-identifies correctly pCam->getCameraInfo_1_1([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.v1.cameraId.c_str()); + LOG(DEBUG) << "Found camera " << desc.v1.cameraId; EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); } ); @@ -374,7 +381,7 @@ TEST_P(EvsHidlTest, CameraOpenAggressive) { // Verify that the second camera instance self-identifies correctly pCam2->getCameraInfo_1_1([&cam](CameraDesc desc) { - ALOGD("Found camera %s", desc.v1.cameraId.c_str()); + LOG(DEBUG) << "Found camera " << desc.v1.cameraId; EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId); } ); @@ -393,7 +400,7 @@ TEST_P(EvsHidlTest, CameraOpenAggressive) { * Measure and qualify the stream start up time and streaming frame rate of each reported camera */ TEST_P(EvsHidlTest, CameraStreamPerformance) { - ALOGI("Starting CameraStreamPerformance test"); + LOG(INFO) << "Starting CameraStreamPerformance test"; // Get the camera list loadCameraList(); @@ -407,7 +414,7 @@ TEST_P(EvsHidlTest, CameraStreamPerformance) { bool isLogicalCam = false; auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); if (mIsHwModule && isLogicalCam) { - ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str()); + LOG(INFO) << "Skip a logical device " << cam.v1.cameraId; continue; } @@ -444,8 +451,10 @@ TEST_P(EvsHidlTest, CameraStreamPerformance) { kMaxStreamStartMilliseconds * devices.size()); printf("%s: Measured time to first frame %0.2f ms\n", cam.v1.cameraId.c_str(), timeToFirstFrame * kNanoToMilliseconds); - ALOGI("%s: Measured time to first frame %0.2f ms", - cam.v1.cameraId.c_str(), timeToFirstFrame * kNanoToMilliseconds); + LOG(INFO) << cam.v1.cameraId + << ": Measured time to first frame " + << std::scientific << timeToFirstFrame * kNanoToMilliseconds + << " ms."; // Check aspect ratio unsigned width = 0, height = 0; @@ -468,7 +477,9 @@ TEST_P(EvsHidlTest, CameraStreamPerformance) { nsecs_t runTime = end - firstFrame; float framesPerSecond = framesReceived / (runTime * kNanoToSeconds); printf("Measured camera rate %3.2f fps\n", framesPerSecond); - ALOGI("Measured camera rate %3.2f fps", framesPerSecond); + LOG(INFO) << "Measured camera rate " + << std::scientific << framesPerSecond + << " fps."; EXPECT_GE(framesPerSecond, kMinimumFramesPerSecond); // Explicitly release the camera @@ -483,7 +494,7 @@ TEST_P(EvsHidlTest, CameraStreamPerformance) { * than one frame time. The camera must cleanly skip frames until the client is ready again. */ TEST_P(EvsHidlTest, CameraStreamBuffering) { - ALOGI("Starting CameraStreamBuffering test"); + LOG(INFO) << "Starting CameraStreamBuffering test"; // Arbitrary constant (should be > 1 and less than crazy) static const unsigned int kBuffersToHold = 6; @@ -500,7 +511,7 @@ TEST_P(EvsHidlTest, CameraStreamBuffering) { bool isLogicalCam = false; getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); if (mIsHwModule && isLogicalCam) { - ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str()); + LOG(INFO) << "Skip a logical device " << cam.v1.cameraId << " for HW target."; continue; } @@ -568,7 +579,7 @@ TEST_P(EvsHidlTest, CameraStreamBuffering) { * which a human could observe to see the operation of the system on the physical display. */ TEST_P(EvsHidlTest, CameraToDisplayRoundTrip) { - ALOGI("Starting CameraToDisplayRoundTrip test"); + LOG(INFO) << "Starting CameraToDisplayRoundTrip test"; // Get the camera list loadCameraList(); @@ -587,14 +598,14 @@ TEST_P(EvsHidlTest, CameraToDisplayRoundTrip) { // Request exclusive access to the first EVS display sp pDisplay = pEnumerator->openDisplay_1_1(targetDisplayId); ASSERT_NE(pDisplay, nullptr); - ALOGI("Display %d is in use.", targetDisplayId); + LOG(INFO) << "Display " << targetDisplayId << " is alreay in use."; // Get the display descriptor pDisplay->getDisplayInfo_1_1([](const auto& config, const auto& state) { android::DisplayConfig* pConfig = (android::DisplayConfig*)config.data(); const auto width = pConfig->resolution.getWidth(); const auto height = pConfig->resolution.getHeight(); - ALOGI(" Resolution: %dx%d", width, height); + LOG(INFO) << " Resolution: " << width << "x" << height; ASSERT_GT(width, 0); ASSERT_GT(height, 0); @@ -607,7 +618,7 @@ TEST_P(EvsHidlTest, CameraToDisplayRoundTrip) { bool isLogicalCam = false; getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); if (mIsHwModule && isLogicalCam) { - ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str()); + LOG(INFO) << "Skip a logical device " << cam.v1.cameraId << " for HW target."; continue; } @@ -667,7 +678,7 @@ TEST_P(EvsHidlTest, CameraToDisplayRoundTrip) { * underlying camera. */ TEST_P(EvsHidlTest, MultiCameraStream) { - ALOGI("Starting MultiCameraStream test"); + LOG(INFO) << "Starting MultiCameraStream test"; if (mIsHwModule) { // This test is not for HW module implementation. @@ -735,7 +746,9 @@ TEST_P(EvsHidlTest, MultiCameraStream) { nsecs_t runTime = end - firstFrame; float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds); float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds); - ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1); + LOG(INFO) << "Measured camera rate " + << std::scientific << framesPerSecond0 << " fps and " + << framesPerSecond1 << " fps"; EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond); EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond); @@ -774,7 +787,7 @@ TEST_P(EvsHidlTest, MultiCameraStream) { * Verify that a client can adjust a camera parameter. */ TEST_P(EvsHidlTest, CameraParameter) { - ALOGI("Starting CameraParameter test"); + LOG(INFO) << "Starting CameraParameter test"; // Get the camera list loadCameraList(); @@ -791,7 +804,7 @@ TEST_P(EvsHidlTest, CameraParameter) { if (isLogicalCam) { // TODO(b/145465724): Support camera parameter programming on // logical devices. - ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str()); + LOG(INFO) << "Skip a logical device " << cam.v1.cameraId; continue; } @@ -918,7 +931,7 @@ TEST_P(EvsHidlTest, CameraParameter) { * terminates or releases a role. */ TEST_P(EvsHidlTest, CameraMasterRelease) { - ALOGI("Starting CameraMasterRelease test"); + LOG(INFO) << "Starting CameraMasterRelease test"; if (mIsHwModule) { // This test is not for HW module implementation. @@ -939,7 +952,7 @@ TEST_P(EvsHidlTest, CameraMasterRelease) { if (isLogicalCam) { // TODO(b/145465724): Support camera parameter programming on // logical devices. - ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str()); + LOG(INFO) << "Skip a logical device " << cam.v1.cameraId; continue; } @@ -1012,7 +1025,7 @@ TEST_P(EvsHidlTest, CameraMasterRelease) { EvsEventDesc aTargetEvent; aTargetEvent.aType = EvsEventType::MASTER_RELEASED; if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification, true)) { - ALOGW("A timer is expired before a target event is fired."); + LOG(WARNING) << "A timer is expired before a target event is fired."; } } @@ -1057,7 +1070,7 @@ TEST_P(EvsHidlTest, CameraMasterRelease) { EvsEventDesc aTargetEvent; aTargetEvent.aType = EvsEventType::MASTER_RELEASED; if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification, true)) { - ALOGW("A timer is expired before a target event is fired."); + LOG(WARNING) << "A timer is expired before a target event is fired."; } } @@ -1099,7 +1112,7 @@ TEST_P(EvsHidlTest, CameraMasterRelease) { * camera parameters. */ TEST_P(EvsHidlTest, MultiCameraParameter) { - ALOGI("Starting MultiCameraParameter test"); + LOG(INFO) << "Starting MultiCameraParameter test"; if (mIsHwModule) { // This test is not for HW module implementation. @@ -1120,7 +1133,7 @@ TEST_P(EvsHidlTest, MultiCameraParameter) { if (isLogicalCam) { // TODO(b/145465724): Support camera parameter programming on // logical devices. - ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str()); + LOG(INFO) << "Skip a logical device " << cam.v1.cameraId; continue; } @@ -1256,7 +1269,7 @@ TEST_P(EvsHidlTest, MultiCameraParameter) { aTargetEvent.payload[0] = static_cast(cmd); aTargetEvent.payload[1] = val0; if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) { - ALOGW("A timer is expired before a target event is fired."); + LOG(WARNING) << "A timer is expired before a target event is fired."; } } ); @@ -1273,7 +1286,7 @@ TEST_P(EvsHidlTest, MultiCameraParameter) { aTargetEvent.payload[0] = static_cast(cmd); aTargetEvent.payload[1] = val0; if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) { - ALOGW("A timer is expired before a target event is fired."); + LOG(WARNING) << "A timer is expired before a target event is fired."; } } ); @@ -1374,7 +1387,7 @@ TEST_P(EvsHidlTest, MultiCameraParameter) { EvsEventDesc aTargetEvent; aTargetEvent.aType = EvsEventType::MASTER_RELEASED; if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification0, true)) { - ALOGW("A timer is expired before a target event is fired."); + LOG(WARNING) << "A timer is expired before a target event is fired."; } } ); @@ -1466,7 +1479,7 @@ TEST_P(EvsHidlTest, MultiCameraParameter) { aTargetEvent.payload[0] = static_cast(cmd); aTargetEvent.payload[1] = val0; if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) { - ALOGW("A timer is expired before a target event is fired."); + LOG(WARNING) << "A timer is expired before a target event is fired."; } } ); @@ -1482,7 +1495,7 @@ TEST_P(EvsHidlTest, MultiCameraParameter) { aTargetEvent.payload[0] = static_cast(cmd); aTargetEvent.payload[1] = val0; if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) { - ALOGW("A timer is expired before a target event is fired."); + LOG(WARNING) << "A timer is expired before a target event is fired."; } } ); @@ -1572,7 +1585,7 @@ TEST_P(EvsHidlTest, MultiCameraParameter) { * a master role from other EVS clients without the display. */ TEST_P(EvsHidlTest, HighPriorityCameraClient) { - ALOGI("Starting HighPriorityCameraClient test"); + LOG(INFO) << "Starting HighPriorityCameraClient test"; if (mIsHwModule) { // This test is not for HW module implementation. @@ -1687,7 +1700,7 @@ TEST_P(EvsHidlTest, HighPriorityCameraClient) { aTargetEvent.payload[0] = static_cast(CameraParam::AUTO_FOCUS); aTargetEvent.payload[1] = 0; if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) { - ALOGW("A timer is expired before a target event is fired."); + LOG(WARNING) << "A timer is expired before a target event is fired."; } } ); @@ -1740,7 +1753,7 @@ TEST_P(EvsHidlTest, HighPriorityCameraClient) { aTargetEvent.payload[0] = static_cast(cam1Cmds[0]); aTargetEvent.payload[1] = val0; if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) { - ALOGW("A timer is expired before a target event is fired."); + LOG(WARNING) << "A timer is expired before a target event is fired."; } } ); @@ -1791,7 +1804,7 @@ TEST_P(EvsHidlTest, HighPriorityCameraClient) { EvsEventDesc aTargetEvent; aTargetEvent.aType = EvsEventType::MASTER_RELEASED; if (!frameHandler1->waitForEvent(aTargetEvent, aNotification, true)) { - ALOGW("A timer is expired before a target event is fired."); + LOG(WARNING) << "A timer is expired before a target event is fired."; } } ); @@ -1833,7 +1846,7 @@ TEST_P(EvsHidlTest, HighPriorityCameraClient) { aTargetEvent.payload[0] = static_cast(CameraParam::AUTO_FOCUS); aTargetEvent.payload[1] = 0; if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) { - ALOGW("A timer is expired before a target event is fired."); + LOG(WARNING) << "A timer is expired before a target event is fired."; } } ); @@ -1882,7 +1895,7 @@ TEST_P(EvsHidlTest, HighPriorityCameraClient) { aTargetEvent.payload[0] = static_cast(cam0Cmds[0]); aTargetEvent.payload[1] = val0; if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) { - ALOGW("A timer is expired before a target event is fired."); + LOG(WARNING) << "A timer is expired before a target event is fired."; } } ); @@ -1945,7 +1958,7 @@ TEST_P(EvsHidlTest, HighPriorityCameraClient) { * configurations from EVS and uses one of them to start a video stream. */ TEST_P(EvsHidlTest, CameraUseStreamConfigToDisplay) { - ALOGI("Starting CameraUseStreamConfigToDisplay test"); + LOG(INFO) << "Starting CameraUseStreamConfigToDisplay test"; // Get the camera list loadCameraList(); @@ -2049,7 +2062,7 @@ TEST_P(EvsHidlTest, CameraUseStreamConfigToDisplay) { * underlying camera with same configuration. */ TEST_P(EvsHidlTest, MultiCameraStreamUseConfig) { - ALOGI("Starting MultiCameraStream test"); + LOG(INFO) << "Starting MultiCameraStream test"; if (mIsHwModule) { // This test is not for HW module implementation. @@ -2094,9 +2107,8 @@ TEST_P(EvsHidlTest, MultiCameraStreamUseConfig) { static_cast(HAL_PIXEL_FORMAT_RGBA_8888); if (!foundCfg) { - ALOGI("Device %s does not provide a list of supported stream configurations, skipped", - cam.v1.cameraId.c_str()); - + LOG(INFO) << "Device " << cam.v1.cameraId + << " does not provide a list of supported stream configurations, skipped"; continue; } @@ -2162,7 +2174,9 @@ TEST_P(EvsHidlTest, MultiCameraStreamUseConfig) { nsecs_t runTime = end - firstFrame; float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds); float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds); - ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1); + LOG(INFO) << "Measured camera rate " + << std::scientific << framesPerSecond0 << " fps and " + << framesPerSecond1 << " fps"; EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond); EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond); @@ -2198,7 +2212,7 @@ TEST_P(EvsHidlTest, MultiCameraStreamUseConfig) { * identifiers. */ TEST_P(EvsHidlTest, LogicalCameraMetadata) { - ALOGI("Starting LogicalCameraMetadata test"); + LOG(INFO) << "Starting LogicalCameraMetadata test"; // Get the camera list loadCameraList(); @@ -2222,7 +2236,7 @@ TEST_P(EvsHidlTest, LogicalCameraMetadata) { * can be reopened. */ TEST_P(EvsHidlTest, UltrasonicsArrayOpenClean) { - ALOGI("Starting UltrasonicsArrayOpenClean test"); + LOG(INFO) << "Starting UltrasonicsArrayOpenClean test"; // Get the ultrasonics array list loadUltrasonicsArrayList(); @@ -2236,7 +2250,7 @@ TEST_P(EvsHidlTest, UltrasonicsArrayOpenClean) { // Verify that this ultrasonics array self-identifies correctly pUltrasonicsArray->getUltrasonicArrayInfo([&ultraInfo](UltrasonicsArrayDesc desc) { - ALOGD("Found ultrasonics array %s", ultraInfo.ultrasonicsArrayId.c_str()); + LOG(DEBUG) << "Found ultrasonics array " << ultraInfo.ultrasonicsArrayId; EXPECT_EQ(ultraInfo.ultrasonicsArrayId, desc.ultrasonicsArrayId); }); @@ -2249,14 +2263,14 @@ TEST_P(EvsHidlTest, UltrasonicsArrayOpenClean) { // Starts a stream and verifies all data received is valid. TEST_P(EvsHidlTest, UltrasonicsVerifyStreamData) { - ALOGI("Starting UltrasonicsVerifyStreamData"); + LOG(INFO) << "Starting UltrasonicsVerifyStreamData"; // Get the ultrasonics array list loadUltrasonicsArrayList(); // For each ultrasonics array. for (auto&& ultraInfo : ultrasonicsArraysInfo) { - ALOGD("Testing ultrasonics array: %s", ultraInfo.ultrasonicsArrayId.c_str()); + LOG(DEBUG) << "Testing ultrasonics array: " << ultraInfo.ultrasonicsArrayId; sp pUltrasonicsArray = pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId); @@ -2285,14 +2299,14 @@ TEST_P(EvsHidlTest, UltrasonicsVerifyStreamData) { // Sets frames in flight before and after start of stream and verfies success. TEST_P(EvsHidlTest, UltrasonicsSetFramesInFlight) { - ALOGI("Starting UltrasonicsSetFramesInFlight"); + LOG(INFO) << "Starting UltrasonicsSetFramesInFlight"; // Get the ultrasonics array list loadUltrasonicsArrayList(); // For each ultrasonics array. for (auto&& ultraInfo : ultrasonicsArraysInfo) { - ALOGD("Testing ultrasonics array: %s", ultraInfo.ultrasonicsArrayId.c_str()); + LOG(DEBUG) << "Testing ultrasonics array: " << ultraInfo.ultrasonicsArrayId; sp pUltrasonicsArray = pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId); From fae91b1bb93226cf131a680b08fc7ccfc584c1b2 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Thu, 5 Mar 2020 17:15:28 -0800 Subject: [PATCH 0678/1022] Fix a resource clean-up routine When a test case is being terminated, VTS framework calls TearDown() to clean up all resources. VtsHalEvsV1_1TargetTest stores weak references to opened hardware cameras for this and tries to close them explicitly when it can promote them. However, it was observed that VirtualCamera's destructor is not called yet even it fails to promote. Therefore, this change modifies a container to hold a strong pointer and explictly removes it after a test case calls closeCamera(). Also, this change corrects a bug in checking setExtendedInfo_1_1() results. Bug: 150893461 Test: vts-trafed VtsHalEvsV1_1_TargetTest Change-Id: I23b55b2f2282834fb5a9d364f4eb176060027de1 --- .../functional/VtsHalEvsV1_1TargetTest.cpp | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index b31795bcb5..368a6d4d2d 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -97,18 +97,19 @@ public: std::string service_name = GetParam(); pEnumerator = IEvsEnumerator::getService(service_name); ASSERT_NE(pEnumerator.get(), nullptr); + LOG(INFO) << "Test target service: " << service_name; mIsHwModule = pEnumerator->isHardware(); } virtual void TearDown() override { // Attempt to close any active camera - for (auto &&c : activeCameras) { - sp cam = c.promote(); + for (auto &&cam : activeCameras) { if (cam != nullptr) { pEnumerator->closeCamera(cam); } } + activeCameras.clear(); } protected: @@ -235,7 +236,7 @@ protected: std::vector cameraInfo; // Empty unless/until loadCameraList() is called bool mIsHwModule; // boolean to tell current module under testing // is HW module implementation. - std::deque> activeCameras; // A list of active camera handles that are + std::deque> activeCameras; // A list of active camera handles that are // needed to be cleaned up. std::vector ultrasonicsArraysInfo; // Empty unless/until @@ -273,10 +274,7 @@ TEST_P(EvsHidlTest, CameraOpenClean) { } for (int pass = 0; pass < 2; pass++) { - activeCameras.clear(); - sp pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) - .withDefault(nullptr); + sp pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg); ASSERT_NE(pCam, nullptr); for (auto&& devName : devices) { @@ -302,15 +300,16 @@ TEST_P(EvsHidlTest, CameraOpenClean) { const auto id = 0xFFFFFFFF; // meaningless id hidl_vec values; auto err = pCam->setExtendedInfo_1_1(id, values); - ASSERT_EQ(EvsResult::INVALID_ARG, err); + ASSERT_NE(EvsResult::INVALID_ARG, err); pCam->getExtendedInfo_1_1(id, [](const auto& result, const auto& data) { - ASSERT_EQ(EvsResult::INVALID_ARG, result); + ASSERT_NE(EvsResult::INVALID_ARG, result); ASSERT_EQ(0, data.size()); }); // Explicitly close the camera so resources are released right away pEnumerator->closeCamera(pCam); + activeCameras.clear(); } } } @@ -378,6 +377,7 @@ TEST_P(EvsHidlTest, CameraOpenAggressive) { // Close the superceded camera pEnumerator->closeCamera(pCam); + activeCameras.pop_front(); // Verify that the second camera instance self-identifies correctly pCam2->getCameraInfo_1_1([&cam](CameraDesc desc) { @@ -388,6 +388,7 @@ TEST_P(EvsHidlTest, CameraOpenAggressive) { // Close the second camera instance pEnumerator->closeCamera(pCam2); + activeCameras.pop_front(); } // Sleep here to ensure the destructor cleanup has time to run so we don't break follow on tests @@ -418,7 +419,6 @@ TEST_P(EvsHidlTest, CameraStreamPerformance) { continue; } - activeCameras.clear(); sp pCam = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); @@ -484,6 +484,7 @@ TEST_P(EvsHidlTest, CameraStreamPerformance) { // Explicitly release the camera pEnumerator->closeCamera(pCam); + activeCameras.clear(); } } @@ -515,7 +516,6 @@ TEST_P(EvsHidlTest, CameraStreamBuffering) { continue; } - activeCameras.clear(); sp pCam = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); @@ -568,6 +568,7 @@ TEST_P(EvsHidlTest, CameraStreamBuffering) { // Explicitly release the camera pEnumerator->closeCamera(pCam); + activeCameras.clear(); } } @@ -622,7 +623,6 @@ TEST_P(EvsHidlTest, CameraToDisplayRoundTrip) { continue; } - activeCameras.clear(); sp pCam = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) .withDefault(nullptr); @@ -665,6 +665,7 @@ TEST_P(EvsHidlTest, CameraToDisplayRoundTrip) { // Explicitly release the camera pEnumerator->closeCamera(pCam); + activeCameras.clear(); } // Explicitly release the display @@ -694,7 +695,6 @@ TEST_P(EvsHidlTest, MultiCameraStream) { // Test each reported camera for (auto&& cam: cameraInfo) { - activeCameras.clear(); // Create two camera clients. sp pCam0 = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) @@ -773,6 +773,7 @@ TEST_P(EvsHidlTest, MultiCameraStream) { // Explicitly release the camera pEnumerator->closeCamera(pCam0); pEnumerator->closeCamera(pCam1); + activeCameras.clear(); // TODO(b/145459970, b/145457727): below sleep() is added to ensure the // destruction of active camera objects; this may be related with two @@ -808,7 +809,6 @@ TEST_P(EvsHidlTest, CameraParameter) { continue; } - activeCameras.clear(); // Create a camera client sp pCam = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) @@ -921,6 +921,7 @@ TEST_P(EvsHidlTest, CameraParameter) { // Explicitly release the camera pEnumerator->closeCamera(pCam); + activeCameras.clear(); } } @@ -956,7 +957,6 @@ TEST_P(EvsHidlTest, CameraMasterRelease) { continue; } - activeCameras.clear(); // Create two camera clients. sp pCamMaster = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) @@ -1102,6 +1102,7 @@ TEST_P(EvsHidlTest, CameraMasterRelease) { // Explicitly release the camera pEnumerator->closeCamera(pCamMaster); pEnumerator->closeCamera(pCamNonMaster); + activeCameras.clear(); } } @@ -1137,7 +1138,6 @@ TEST_P(EvsHidlTest, MultiCameraParameter) { continue; } - activeCameras.clear(); // Create two camera clients. sp pCamMaster = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) @@ -1575,6 +1575,7 @@ TEST_P(EvsHidlTest, MultiCameraParameter) { // Explicitly release the camera pEnumerator->closeCamera(pCamMaster); pEnumerator->closeCamera(pCamNonMaster); + activeCameras.clear(); } } @@ -1605,8 +1606,6 @@ TEST_P(EvsHidlTest, HighPriorityCameraClient) { // Test each reported camera for (auto&& cam: cameraInfo) { - activeCameras.clear(); - // Create two clients sp pCam0 = IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) @@ -1944,6 +1943,8 @@ TEST_P(EvsHidlTest, HighPriorityCameraClient) { // Explicitly release the camera pEnumerator->closeCamera(pCam0); pEnumerator->closeCamera(pCam1); + activeCameras.clear(); + } // Explicitly release the display @@ -1969,7 +1970,6 @@ TEST_P(EvsHidlTest, CameraUseStreamConfigToDisplay) { // Test each reported camera for (auto&& cam: cameraInfo) { - activeCameras.clear(); // choose a configuration that has a frame rate faster than minReqFps. Stream targetCfg = {}; const int32_t minReqFps = 15; @@ -2049,6 +2049,7 @@ TEST_P(EvsHidlTest, CameraUseStreamConfigToDisplay) { // Explicitly release the camera pEnumerator->closeCamera(pCam); + activeCameras.clear(); } // Explicitly release the display @@ -2074,7 +2075,6 @@ TEST_P(EvsHidlTest, MultiCameraStreamUseConfig) { // Test each reported camera for (auto&& cam: cameraInfo) { - activeCameras.clear(); // choose a configuration that has a frame rate faster than minReqFps. Stream targetCfg = {}; const int32_t minReqFps = 15; @@ -2201,6 +2201,7 @@ TEST_P(EvsHidlTest, MultiCameraStreamUseConfig) { // Explicitly release the camera pEnumerator->closeCamera(pCam0); pEnumerator->closeCamera(pCam1); + activeCameras.clear(); } } From f3cb5562b22f587c8ec238bcc4331b82f4370d53 Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Thu, 5 Mar 2020 22:41:23 -0800 Subject: [PATCH 0679/1022] Fix deadlock in cuttlefish/default implementation Bug: 150830099 Test: atest LocationManagerFineTest#testRegisterGnssMeasurementsCallback -c --iterations 100 Change-Id: I70aec19a481781d924ed3008765ca624a7eeb950 Merged-In: I70aec19a481781d924ed3008765ca624a7eeb950 (cherry picked from commit 3d652709ed40f8070c990bb275d3709d603d318e) --- gnss/2.0/default/GnssMeasurement.cpp | 2 +- gnss/2.0/default/GnssMeasurement.h | 4 ++++ gnss/2.1/default/GnssAntennaInfo.cpp | 2 +- gnss/2.1/default/GnssAntennaInfo.h | 6 +++++- gnss/2.1/default/GnssMeasurement.cpp | 2 +- gnss/2.1/default/GnssMeasurement.h | 6 ++++++ 6 files changed, 18 insertions(+), 4 deletions(-) diff --git a/gnss/2.0/default/GnssMeasurement.cpp b/gnss/2.0/default/GnssMeasurement.cpp index d778d508cd..a3ea807729 100644 --- a/gnss/2.0/default/GnssMeasurement.cpp +++ b/gnss/2.0/default/GnssMeasurement.cpp @@ -49,8 +49,8 @@ Return GnssMeasurement::setCallba Return GnssMeasurement::close() { ALOGD("close"); - std::unique_lock lock(mMutex); stop(); + std::unique_lock lock(mMutex); sCallback = nullptr; return Void(); } diff --git a/gnss/2.0/default/GnssMeasurement.h b/gnss/2.0/default/GnssMeasurement.h index d8ffd59305..73eaa1320a 100644 --- a/gnss/2.0/default/GnssMeasurement.h +++ b/gnss/2.0/default/GnssMeasurement.h @@ -61,10 +61,14 @@ struct GnssMeasurement : public IGnssMeasurement { void stop(); void reportMeasurement(const GnssData&); + // Guarded by mMutex static sp sCallback; + std::atomic mMinIntervalMillis; std::atomic mIsActive; std::thread mThread; + + // Synchronization lock for sCallback mutable std::mutex mMutex; }; diff --git a/gnss/2.1/default/GnssAntennaInfo.cpp b/gnss/2.1/default/GnssAntennaInfo.cpp index d32a0afc48..ed183a9383 100644 --- a/gnss/2.1/default/GnssAntennaInfo.cpp +++ b/gnss/2.1/default/GnssAntennaInfo.cpp @@ -55,8 +55,8 @@ Return GnssAntennaInfo::setCallback( Return GnssAntennaInfo::close() { ALOGD("close"); - std::unique_lock lock(mMutex); stop(); + std::unique_lock lock(mMutex); sCallback = nullptr; return Void(); } diff --git a/gnss/2.1/default/GnssAntennaInfo.h b/gnss/2.1/default/GnssAntennaInfo.h index f4bfd24367..94b2111d06 100644 --- a/gnss/2.1/default/GnssAntennaInfo.h +++ b/gnss/2.1/default/GnssAntennaInfo.h @@ -47,10 +47,14 @@ struct GnssAntennaInfo : public IGnssAntennaInfo { void reportAntennaInfo( const hidl_vec& antennaInfo) const; + // Guarded by mMutex static sp sCallback; + std::atomic mMinIntervalMillis; std::atomic mIsActive; std::thread mThread; + + // Synchronization lock for sCallback mutable std::mutex mMutex; }; @@ -60,4 +64,4 @@ struct GnssAntennaInfo : public IGnssAntennaInfo { } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H \ No newline at end of file +#endif // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H diff --git a/gnss/2.1/default/GnssMeasurement.cpp b/gnss/2.1/default/GnssMeasurement.cpp index 34e20e5790..63bbc0a399 100644 --- a/gnss/2.1/default/GnssMeasurement.cpp +++ b/gnss/2.1/default/GnssMeasurement.cpp @@ -47,8 +47,8 @@ Return GnssMeasurement::setCallba Return GnssMeasurement::close() { ALOGD("close"); - std::unique_lock lock(mMutex); stop(); + std::unique_lock lock(mMutex); sCallback_2_1 = nullptr; sCallback_2_0 = nullptr; return Void(); diff --git a/gnss/2.1/default/GnssMeasurement.h b/gnss/2.1/default/GnssMeasurement.h index 3ed7bc597d..d44641978f 100644 --- a/gnss/2.1/default/GnssMeasurement.h +++ b/gnss/2.1/default/GnssMeasurement.h @@ -66,11 +66,17 @@ struct GnssMeasurement : public IGnssMeasurement { void reportMeasurement(const GnssDataV2_0&); void reportMeasurement(const GnssDataV2_1&); + // Guarded by mMutex static sp sCallback_2_1; + + // Guarded by mMutex static sp sCallback_2_0; + std::atomic mMinIntervalMillis; std::atomic mIsActive; std::thread mThread; + + // Synchronization lock for sCallback_2_1 and sCallback_2_0 mutable std::mutex mMutex; }; From e344d058186eff8a3466d31ffc058c87c8eb6417 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Fri, 6 Mar 2020 17:47:27 -0800 Subject: [PATCH 0680/1022] Configstore is optional on updating devices. Dropping requirement of configstore on devices launching before or at P. Test: pass Bug: 150981985 Change-Id: I1c08bd7b18fe6006ee1555c39072e75ec4fb3210 Merged-In: I1c08bd7b18fe6006ee1555c39072e75ec4fb3210 --- compatibility_matrices/compatibility_matrix.1.xml | 2 +- compatibility_matrices/compatibility_matrix.2.xml | 2 +- compatibility_matrices/compatibility_matrix.3.xml | 2 +- compatibility_matrices/compatibility_matrix.legacy.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compatibility_matrices/compatibility_matrix.1.xml b/compatibility_matrices/compatibility_matrix.1.xml index d82829d091..cccf24ff99 100644 --- a/compatibility_matrices/compatibility_matrix.1.xml +++ b/compatibility_matrices/compatibility_matrix.1.xml @@ -71,7 +71,7 @@ legacy/0 - + android.hardware.configstore 1.0 diff --git a/compatibility_matrices/compatibility_matrix.2.xml b/compatibility_matrices/compatibility_matrix.2.xml index 98e6cfae8e..d4f9809b7e 100644 --- a/compatibility_matrices/compatibility_matrix.2.xml +++ b/compatibility_matrices/compatibility_matrix.2.xml @@ -79,7 +79,7 @@ default - + android.hardware.configstore 1.0 diff --git a/compatibility_matrices/compatibility_matrix.3.xml b/compatibility_matrices/compatibility_matrix.3.xml index 9933b337bd..5888ab9d86 100644 --- a/compatibility_matrices/compatibility_matrix.3.xml +++ b/compatibility_matrices/compatibility_matrix.3.xml @@ -111,7 +111,7 @@ default - + android.hardware.configstore 1.0-1 diff --git a/compatibility_matrices/compatibility_matrix.legacy.xml b/compatibility_matrices/compatibility_matrix.legacy.xml index 224811f4e0..8a4d2ee60d 100644 --- a/compatibility_matrices/compatibility_matrix.legacy.xml +++ b/compatibility_matrices/compatibility_matrix.legacy.xml @@ -71,7 +71,7 @@ legacy/0 - + android.hardware.configstore 1.0 From 6e8b33a127b569e6d2d9f3e72a115f0df3a101b2 Mon Sep 17 00:00:00 2001 From: Hsiaoan Hsu Date: Mon, 9 Mar 2020 12:12:33 +0800 Subject: [PATCH 0681/1022] VTS: Fix IRadio.nvResetConfig - IRadio.nvResetConfig: IRadio.nvResetConfig with ResetNvType ERASE cause radio restart. The subsuquent test cases fail with RADIO_NOT_AVAILABLE. Fix to use ResetNvType FACTORY_RESET which does not restart the radio. Test: run vts -m VtsHalRadioV1_0Target Bug: 147831226 Change-Id: I45e5cbcf9144c3ace987ac8e047e40fbee403734 --- radio/1.0/vts/functional/radio_hidl_hal_misc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 d04cb36f5c..9b6cc96cf0 100644 --- a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp +++ b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp @@ -578,7 +578,7 @@ TEST_P(RadioHidlTest, nvWriteCdmaPrl) { TEST_P(RadioHidlTest, nvResetConfig) { serial = GetRandomSerialNumber(); - radio->nvResetConfig(serial, ResetNvType::ERASE); + radio->nvResetConfig(serial, ResetNvType::FACTORY_RESET); EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type); EXPECT_EQ(serial, radioRsp->rspInfo.serial); From ee37ee9252dc2f15b5e5335ef2da72cc24d1cdb9 Mon Sep 17 00:00:00 2001 From: Selene Huang Date: Wed, 8 Jan 2020 22:59:02 -0800 Subject: [PATCH 0682/1022] Add attestation certificate generation and identity credential tags. Bug: 149908474 Test: atest android.security.identity.cts.AttestationTest Test: atest VtsHalIdentityCredentialTargetTest Test: atest android.hardware.identity-support-lib-test Merged-In: I18c5d05d806d4157c9dce42a398cc89421e26907 Change-Id: Ifaffef3606a6398613e33982ff5db81ade1af0b2 --- .../default/WritableIdentityCredential.cpp | 117 +++++---------- .../aidl/default/WritableIdentityCredential.h | 5 +- identity/support/Android.bp | 4 + .../support/IdentityCredentialSupport.h | 12 ++ .../support/src/IdentityCredentialSupport.cpp | 139 ++++++++++++++++++ .../include/keymasterV4_1/keymaster_tags.h | 1 + 6 files changed, 194 insertions(+), 84 deletions(-) diff --git a/identity/aidl/default/WritableIdentityCredential.cpp b/identity/aidl/default/WritableIdentityCredential.cpp index ba2062d7c0..89f7f35696 100644 --- a/identity/aidl/default/WritableIdentityCredential.cpp +++ b/identity/aidl/default/WritableIdentityCredential.cpp @@ -16,6 +16,9 @@ #define LOG_TAG "WritableIdentityCredential" +#include "WritableIdentityCredential.h" +#include "IdentityCredentialStore.h" + #include #include @@ -23,6 +26,8 @@ #include #include +#include + #include "IdentityCredentialStore.h" #include "Util.h" #include "WritableIdentityCredential.h" @@ -33,26 +38,6 @@ using ::std::optional; using namespace ::android::hardware::identity; bool WritableIdentityCredential::initialize() { - optional> keyPair = support::createEcKeyPair(); - if (!keyPair) { - LOG(ERROR) << "Error creating credentialKey"; - return false; - } - - optional> pubKey = support::ecKeyPairGetPublicKey(keyPair.value()); - if (!pubKey) { - LOG(ERROR) << "Error getting public part of credentialKey"; - return false; - } - credentialPubKey_ = pubKey.value(); - - optional> privKey = support::ecKeyPairGetPrivateKey(keyPair.value()); - if (!privKey) { - LOG(ERROR) << "Error getting private part of credentialKey"; - return false; - } - credentialPrivKey_ = privKey.value(); - optional> random = support::getRandom(16); if (!random) { LOG(ERROR) << "Error creating storageKey"; @@ -63,88 +48,54 @@ bool WritableIdentityCredential::initialize() { return true; } -// TODO: use |attestationApplicationId| and |attestationChallenge| and also -// ensure the returned certificate chain satisfy the requirements listed in -// the docs for IWritableIdentityCredential::getAttestationCertificate() -// +// This function generates the attestation certificate using the passed in +// |attestationApplicationId| and |attestationChallenge|. It will generate an +// attestation certificate with current time and expires one year from now. The +// certificate shall contain all values as specified in hal. ndk::ScopedAStatus WritableIdentityCredential::getAttestationCertificate( - const vector& /*attestationApplicationId*/, - const vector& /*attestationChallenge*/, vector* outCertificateChain) { - // For now, we dynamically generate an attestion key on each and every - // request and use that to sign CredentialKey. In a real implementation this - // would look very differently. - optional> attestationKeyPair = support::createEcKeyPair(); - if (!attestationKeyPair) { - return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( - IIdentityCredentialStore::STATUS_FAILED, "Error creating attestationKey")); - } - - optional> attestationPubKey = - support::ecKeyPairGetPublicKey(attestationKeyPair.value()); - if (!attestationPubKey) { + const vector& attestationApplicationId, // + const vector& attestationChallenge, // + vector* outCertificateChain) { + if (!credentialPrivKey_.empty() || !credentialPubKey_.empty() || !certificateChain_.empty()) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, - "Error getting public part of attestationKey")); + "Error attestation certificate previously generated")); } - optional> attestationPrivKey = - support::ecKeyPairGetPrivateKey(attestationKeyPair.value()); - if (!attestationPrivKey) { + vector challenge(attestationChallenge.begin(), attestationChallenge.end()); + vector appId(attestationApplicationId.begin(), attestationApplicationId.end()); + + optional, vector>>> keyAttestationPair = + support::createEcKeyPairAndAttestation(challenge, appId); + if (!keyAttestationPair) { + LOG(ERROR) << "Error creating credentialKey and attestation"; return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, - "Error getting private part of attestationKey")); + "Error creating credentialKey and attestation")); } - string serialDecimal; - string issuer; - string subject; - time_t validityNotBefore = time(nullptr); - time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600; + vector keyPair = keyAttestationPair.value().first; + certificateChain_ = keyAttestationPair.value().second; - // First create a certificate for |credentialPubKey| which is signed by - // |attestationPrivKey|. - // - serialDecimal = "0"; // TODO: set serial to |attestationChallenge| - issuer = "Android Open Source Project"; - subject = "Android IdentityCredential CredentialKey"; - optional> credentialPubKeyCertificate = support::ecPublicKeyGenerateCertificate( - credentialPubKey_, attestationPrivKey.value(), serialDecimal, issuer, subject, - validityNotBefore, validityNotAfter); - if (!credentialPubKeyCertificate) { + optional> pubKey = support::ecKeyPairGetPublicKey(keyPair); + if (!pubKey) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, - "Error creating certificate for credentialPubKey")); + "Error getting public part of credentialKey")); } + credentialPubKey_ = pubKey.value(); - // This is followed by a certificate for |attestationPubKey| self-signed by - // |attestationPrivKey|. - serialDecimal = "0"; // TODO: set serial - issuer = "Android Open Source Project"; - subject = "Android IdentityCredential AttestationKey"; - optional> attestationKeyCertificate = support::ecPublicKeyGenerateCertificate( - attestationPubKey.value(), attestationPrivKey.value(), serialDecimal, issuer, subject, - validityNotBefore, validityNotAfter); - if (!attestationKeyCertificate) { + optional> privKey = support::ecKeyPairGetPrivateKey(keyPair); + if (!privKey) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, - "Error creating certificate for attestationPubKey")); + "Error getting private part of credentialKey")); } + credentialPrivKey_ = privKey.value(); - // Concatenate the certificates to form the chain. - vector certificateChain; - certificateChain.insert(certificateChain.end(), credentialPubKeyCertificate.value().begin(), - credentialPubKeyCertificate.value().end()); - certificateChain.insert(certificateChain.end(), attestationKeyCertificate.value().begin(), - attestationKeyCertificate.value().end()); - - optional>> splitCertChain = - support::certificateChainSplit(certificateChain); - if (!splitCertChain) { - return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( - IIdentityCredentialStore::STATUS_FAILED, "Error splitting certificate chain")); - } + // convert from vector>> to vector* *outCertificateChain = vector(); - for (const vector& cert : splitCertChain.value()) { + for (const vector& cert : certificateChain_) { Certificate c = Certificate(); c.encodedCertificate = byteStringToSigned(cert); outCertificateChain->push_back(std::move(c)); diff --git a/identity/aidl/default/WritableIdentityCredential.h b/identity/aidl/default/WritableIdentityCredential.h index b380f897a1..b182862862 100644 --- a/identity/aidl/default/WritableIdentityCredential.h +++ b/identity/aidl/default/WritableIdentityCredential.h @@ -64,10 +64,13 @@ class WritableIdentityCredential : public BnWritableIdentityCredential { string docType_; bool testCredential_; - // These are set in initialize(). + // This is set in initialize(). vector storageKey_; + + // These are set in getAttestationCertificate(). vector credentialPrivKey_; vector credentialPubKey_; + vector> certificateChain_; // These fields are initialized during startPersonalization() size_t numAccessControlProfileRemaining_; diff --git a/identity/support/Android.bp b/identity/support/Android.bp index 7b4546b20f..2b6c695442 100644 --- a/identity/support/Android.bp +++ b/identity/support/Android.bp @@ -23,10 +23,14 @@ cc_library { "include", ], shared_libs: [ + "android.hardware.keymaster@4.0", "libcrypto", "libbase", "libhidlbase", "libhardware", + "libkeymaster_portable", + "libsoft_attestation_cert", + "libpuresoftkeymasterdevice", ], static_libs: [ "libcppbor", diff --git a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h index 4533ad946c..507e914fa3 100644 --- a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h +++ b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h @@ -21,6 +21,7 @@ #include #include #include +#include #include namespace android { @@ -106,6 +107,17 @@ optional> encryptAes128Gcm(const vector& key, const vec // --------------------------------------------------------------------------- // EC crypto functionality / abstraction (only supports P-256). // --------------------------------------------------------------------------- +// Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the +// PKCS#8 encoded key-pair. Also generates an attestation +// certificate using the |challenge| and |applicationId|, and returns the generated +// certificate in X.509 certificate chain format. +// +// The attestation time fields used will be the current time, and expires in one year. +// +// The first parameter of the return value is the keyPair generated, second return in +// the pair is the attestation certificate generated. +optional, vector>>> createEcKeyPairAndAttestation( + 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. diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp index e2828bf2bd..bf6a5c3c45 100644 --- a/identity/support/src/IdentityCredentialSupport.cpp +++ b/identity/support/src/IdentityCredentialSupport.cpp @@ -47,6 +47,13 @@ #include #include +#include +#include +#include +#include +#include +#include + namespace android { namespace hardware { namespace identity { @@ -816,6 +823,138 @@ optional> hmacSha256(const vector& key, const vector>> createAttestation(const EVP_PKEY* key, + const vector& applicationId, + const vector& challenge, + uint64_t activeTimeMilliSeconds, + uint64_t expireTimeMilliSeconds) { + ::keymaster::AuthorizationSet auth_set( + ::keymaster::AuthorizationSetBuilder() + .Authorization(::keymaster::TAG_ATTESTATION_CHALLENGE, challenge.data(), + challenge.size()) + .Authorization(::keymaster::TAG_ACTIVE_DATETIME, activeTimeMilliSeconds) + // Even though identity attestation hal said the application + // id should be in software enforced authentication set, + // keymaster portable lib expect the input in this + // parameter because the software enforced in input to keymaster + // refers to the key software enforced properties. And this + // parameter refers to properties of the attestation which + // includes app id. + .Authorization(::keymaster::TAG_ATTESTATION_APPLICATION_ID, + applicationId.data(), applicationId.size()) + .Authorization(::keymaster::TAG_USAGE_EXPIRE_DATETIME, expireTimeMilliSeconds)); + + // Unique id and device id is not applicable for identity credential attestation, + // so we don't need to set those or application id. + ::keymaster::AuthorizationSet swEnforced(::keymaster::AuthorizationSetBuilder().Authorization( + ::keymaster::TAG_CREATION_DATETIME, activeTimeMilliSeconds)); + + ::keymaster::AuthorizationSet hwEnforced( + ::keymaster::AuthorizationSetBuilder() + .Authorization(::keymaster::TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(::keymaster::TAG_KEY_SIZE, 256) + .Authorization(::keymaster::TAG_ALGORITHM, KM_ALGORITHM_EC) + .Authorization(::keymaster::TAG_NO_AUTH_REQUIRED) + .Authorization(::keymaster::TAG_DIGEST, KM_DIGEST_SHA_2_256) + .Authorization(::keymaster::TAG_EC_CURVE, KM_EC_CURVE_P_256) + .Authorization(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY)); + + const keymaster_cert_chain_t* attestation_chain = + ::keymaster::getAttestationChain(KM_ALGORITHM_EC, nullptr); + + if (attestation_chain == nullptr) { + LOG(ERROR) << "Error getting attestation chain"; + return {}; + } + + const keymaster_key_blob_t* attestation_signing_key = + ::keymaster::getAttestationKey(KM_ALGORITHM_EC, nullptr); + if (attestation_signing_key == nullptr) { + LOG(ERROR) << "Error getting attestation key"; + return {}; + } + + keymaster_error_t error; + ::keymaster::CertChainPtr cert_chain_out; + ::keymaster::PureSoftKeymasterContext context; + + // set identity version to 10 per hal requirements specified in IWriteableCredential.hal + // For now, the identity version in the attestation is set in the keymaster + // version field in the portable keymaster lib, which is a bit misleading. + uint identity_version = 10; + error = generate_attestation_from_EVP(key, swEnforced, hwEnforced, auth_set, context, + identity_version, *attestation_chain, + *attestation_signing_key, &cert_chain_out); + + if (KM_ERROR_OK != error || !cert_chain_out) { + LOG(ERROR) << "Error generate attestation from EVP key" << error; + return {}; + } + + // translate certificate format from keymaster_cert_chain_t to vector. + vector> attestationCertificate; + for (int i = 0; i < cert_chain_out->entry_count; i++) { + attestationCertificate.insert( + attestationCertificate.end(), + vector( + cert_chain_out->entries[i].data, + cert_chain_out->entries[i].data + cert_chain_out->entries[i].data_length)); + } + + return attestationCertificate; +} + +optional, vector>>> createEcKeyPairAndAttestation( + const vector& challenge, const vector& applicationId) { + auto ec_key = ::keymaster::EC_KEY_Ptr(EC_KEY_new()); + auto pkey = ::keymaster::EVP_PKEY_Ptr(EVP_PKEY_new()); + auto group = ::keymaster::EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); + + if (ec_key.get() == nullptr || pkey.get() == nullptr) { + LOG(ERROR) << "Memory allocation failed"; + return {}; + } + + if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 || + EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) { + LOG(ERROR) << "Error generating key"; + return {}; + } + + if (EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()) != 1) { + LOG(ERROR) << "Error getting private key"; + return {}; + } + + uint64_t now = time(nullptr); + 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 {}; + } + + int size = i2d_PrivateKey(pkey.get(), nullptr); + if (size == 0) { + LOG(ERROR) << "Error generating public key encoding"; + return {}; + } + + vector keyPair(size); + unsigned char* p = keyPair.data(); + i2d_PrivateKey(pkey.get(), &p); + + return make_pair(keyPair, attestationCert.value()); +} + optional> createEcKeyPair() { auto ec_key = EC_KEY_Ptr(EC_KEY_new()); auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new()); diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h index 6c186f6429..40eb1426ef 100644 --- a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h +++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h @@ -101,6 +101,7 @@ using V4_0::TAG_VENDOR_PATCHLEVEL; DECLARE_KM_4_1_TYPED_TAG(EARLY_BOOT_ONLY); DECLARE_KM_4_1_TYPED_TAG(DEVICE_UNIQUE_ATTESTATION); DECLARE_KM_4_1_TYPED_TAG(STORAGE_KEY); +DECLARE_KM_4_1_TYPED_TAG(IDENTITY_CREDENTIAL_KEY); } // namespace android::hardware::keymaster::V4_1 From e8286f04b8e90ff77f8700a84789a9b920216b0d Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Mon, 9 Mar 2020 10:49:23 -0700 Subject: [PATCH 0683/1022] Update doc of proxyAppPackageName Fixes: 151088537 Test: doc only and builds Change-Id: If0c4c6d879a1a35293739838702a33ec770b0ed3 --- current.txt | 1 + .../1.0/IGnssVisibilityControlCallback.hal | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/current.txt b/current.txt index 5f5758ca13..e001e66833 100644 --- a/current.txt +++ b/current.txt @@ -589,6 +589,7 @@ cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardwar a05277065c28ebecd58118bd240fb8c55757361e8648c01f7c4dacdb7f2a95dc android.hardware.camera.metadata@3.3::types 9cb3df2bde2c6cd5fd96b7c41555420cacd7e276a556c684af91b7461c86460f android.hardware.gnss@1.0::IGnssCallback af334f1fc85c62b343f84b74d0495eed6f495f7fecedb53463db10c202310058 android.hardware.gnss.measurement_corrections@1.0::types +33a6b20c43af00fdfb305df891bc5911c06d9a9130b912759649932e5a4a6e6d android.hardware.gnss.visibility_control@1.0::IGnssVisibilityControlCallback bceee81ec1b59324abd05932b5620fda5a6589597c9cb3953ba7f3ea02cccd3e android.hardware.camera.provider@2.4::ICameraProvider 2ce820dc4f3c6d85721b65150ed2157c6e2e2055f866fb6c6ba4790f14408d66 android.hardware.camera.provider@2.4::ICameraProviderCallback b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice diff --git a/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal b/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal index 5a582c23de..5ee2923367 100644 --- a/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal +++ b/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal @@ -82,6 +82,9 @@ interface IGnssVisibilityControlCallback { /** * Package name of the Android proxy application representing the non-framework * entity that requested location. Set to empty string if unknown. + * + * For user-initiated emergency use cases, this field must be set to empty string + * and the inEmergencyMode field must be set to true. */ string proxyAppPackageName; @@ -157,4 +160,4 @@ interface IGnssVisibilityControlCallback { * @return success True if the framework determines that the device is in emergency session. */ isInEmergencySession() generates (bool success); -}; \ No newline at end of file +}; From b790d97f45a36b53ea726d8fa717a927d6658bd4 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Thu, 27 Feb 2020 14:25:54 -0500 Subject: [PATCH 0684/1022] Identity: Move signingKeyBlob from finishRetrieval() to startRetrieval(). The implementation of the Identity Credential TA in constrained environments may need to incrementally update the HMAC-SHA256 of DeviceAuthencation CBOR to avoid keeping the entire CBOR structure in memory. To do this they need to calculate the derived key before starting to build the CBOR so they need access to the signingKey earlier on. Bug: 150390415 Test: atest android.security.identity.cts Test: VtsHalIdentityTargetTest Merged-In: I72ad30ec3ccec0b8161cbea360ef8c9212f8cbbc Change-Id: I95e28dd46b35bc31dec8d77ee14b5a1b3b5c0391 --- .../hardware/identity/IIdentityCredential.aidl | 13 ++++++------- identity/aidl/default/IdentityCredential.cpp | 15 +++++++-------- identity/aidl/default/IdentityCredential.h | 7 ++++--- identity/aidl/vts/VtsHalIdentityTargetTest.cpp | 16 ++++++++-------- 4 files changed, 25 insertions(+), 26 deletions(-) diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl index 10ce4c2867..cc142713cd 100644 --- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl +++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl @@ -176,6 +176,10 @@ interface IIdentityCredential { * @param itemsRequest * If non-empty, contains request data that is signed by the reader. See above. * + * @param signingKeyBlob is either empty or a signingKeyBlob (see generateSigningKeyPair(), + * below) containing the signing key to use to sign the data retrieved. If this + * is not in the right format the call fails with STATUS_INVALID_DATA. + * * @param sessionTranscript * Either empty or the CBOR of the SessionTranscript. See above. * @@ -195,8 +199,7 @@ interface IIdentityCredential { * and remove the corresponding requests from the counts. */ void startRetrieval(in SecureAccessControlProfile[] accessControlProfiles, - in HardwareAuthToken authToken, - in byte[] itemsRequest, + in HardwareAuthToken authToken, in byte[] itemsRequest, in byte[] signingKeyBlob, in byte[] sessionTranscript, in byte[] readerSignature, in int[] requestCounts); /** @@ -254,10 +257,6 @@ interface IIdentityCredential { * If signingKeyBlob or the sessionTranscript parameter passed to startRetrieval() is * empty then the returned MAC will be empty. * - * @param signingKeyBlob is either empty or a signingKeyBlob (see generateSigningKeyPair(), - * below) containing the signing key to use to sign the data retrieved. If this - * is not in the right format the call fails with STATUS_INVALID_DATA. - * * @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. @@ -304,7 +303,7 @@ interface IIdentityCredential { * * @param out deviceNameSpaces the bytes of DeviceNameSpaces. */ - void finishRetrieval(in byte[] signingKeyBlob, out byte[] mac, out byte[] deviceNameSpaces); + void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces); /** * Generate a key pair to be used for signing session data and retrieved data items. diff --git a/identity/aidl/default/IdentityCredential.cpp b/identity/aidl/default/IdentityCredential.cpp index d5b3a0ffee..341fae6e93 100644 --- a/identity/aidl/default/IdentityCredential.cpp +++ b/identity/aidl/default/IdentityCredential.cpp @@ -256,8 +256,8 @@ bool checkUserAuthentication(const SecureAccessControlProfile& profile, ndk::ScopedAStatus IdentityCredential::startRetrieval( const vector& accessControlProfiles, const HardwareAuthToken& authToken, const vector& itemsRequestS, - const vector& sessionTranscriptS, const vector& readerSignatureS, - const vector& requestCounts) { + const vector& signingKeyBlobS, const vector& sessionTranscriptS, + const vector& readerSignatureS, const vector& requestCounts) { auto sessionTranscript = byteStringToUnsigned(sessionTranscriptS); auto itemsRequest = byteStringToUnsigned(itemsRequestS); auto readerSignature = byteStringToUnsigned(readerSignatureS); @@ -498,6 +498,7 @@ ndk::ScopedAStatus IdentityCredential::startRetrieval( currentNameSpace_ = ""; itemsRequest_ = itemsRequest; + signingKeyBlob_ = byteStringToUnsigned(signingKeyBlobS); numStartRetrievalCalls_ += 1; return ndk::ScopedAStatus::ok(); @@ -650,11 +651,8 @@ ndk::ScopedAStatus IdentityCredential::retrieveEntryValue(const vector& return ndk::ScopedAStatus::ok(); } -ndk::ScopedAStatus IdentityCredential::finishRetrieval(const vector& signingKeyBlobS, - vector* outMac, +ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector* outMac, vector* outDeviceNameSpaces) { - auto signingKeyBlob = byteStringToUnsigned(signingKeyBlobS); - if (currentNameSpaceDeviceNameSpacesMap_.size() > 0) { deviceNameSpacesMap_.add(currentNameSpace_, std::move(currentNameSpaceDeviceNameSpacesMap_)); @@ -664,7 +662,8 @@ ndk::ScopedAStatus IdentityCredential::finishRetrieval(const vector& sig // If there's no signing key or no sessionTranscript or no reader ephemeral // public key, we return the empty MAC. optional> mac; - if (signingKeyBlob.size() > 0 && sessionTranscript_.size() > 0 && readerPublicKey_.size() > 0) { + if (signingKeyBlob_.size() > 0 && sessionTranscript_.size() > 0 && + readerPublicKey_.size() > 0) { cppbor::Array array; array.add("DeviceAuthentication"); array.add(sessionTranscriptItem_->clone()); @@ -674,7 +673,7 @@ ndk::ScopedAStatus IdentityCredential::finishRetrieval(const vector& sig vector docTypeAsBlob(docType_.begin(), docType_.end()); optional> signingKey = - support::decryptAes128Gcm(storageKey_, signingKeyBlob, docTypeAsBlob); + support::decryptAes128Gcm(storageKey_, signingKeyBlob_, docTypeAsBlob); if (!signingKey) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_INVALID_DATA, diff --git a/identity/aidl/default/IdentityCredential.h b/identity/aidl/default/IdentityCredential.h index 49ed0d45b8..fc29254f4b 100644 --- a/identity/aidl/default/IdentityCredential.h +++ b/identity/aidl/default/IdentityCredential.h @@ -54,14 +54,14 @@ class IdentityCredential : public BnIdentityCredential { ndk::ScopedAStatus startRetrieval( const vector& accessControlProfiles, const HardwareAuthToken& authToken, const vector& itemsRequest, - const vector& sessionTranscript, const vector& readerSignature, - const vector& requestCounts) override; + const vector& signingKeyBlob, const vector& sessionTranscript, + const vector& readerSignature, const vector& requestCounts) override; ndk::ScopedAStatus startRetrieveEntryValue( const string& nameSpace, const string& name, int32_t entrySize, const vector& accessControlProfileIds) override; ndk::ScopedAStatus retrieveEntryValue(const vector& encryptedContent, vector* outContent) override; - ndk::ScopedAStatus finishRetrieval(const vector& signingKeyBlob, vector* outMac, + ndk::ScopedAStatus finishRetrieval(vector* outMac, vector* outDeviceNameSpaces) override; ndk::ScopedAStatus generateSigningKeyPair(vector* outSigningKeyBlob, Certificate* outSigningKeyCertificate) override; @@ -88,6 +88,7 @@ class IdentityCredential : public BnIdentityCredential { // Set at startRetrieval() time. map profileIdToAccessCheckResult_; + vector signingKeyBlob_; vector sessionTranscript_; std::unique_ptr sessionTranscriptItem_; vector itemsRequest_; diff --git a/identity/aidl/vts/VtsHalIdentityTargetTest.cpp b/identity/aidl/vts/VtsHalIdentityTargetTest.cpp index 5abe5a2f66..ea37fdc7a5 100644 --- a/identity/aidl/vts/VtsHalIdentityTargetTest.cpp +++ b/identity/aidl/vts/VtsHalIdentityTargetTest.cpp @@ -352,10 +352,15 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { readerCertificate.value()); ASSERT_TRUE(readerSignature); + // Generate the key that will be used to sign AuthenticatedData. + vector signingKeyBlob; + Certificate signingKeyCertificate; + ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk()); + ASSERT_TRUE(credential ->startRetrieval(returnedSecureProfiles, authToken, itemsRequestBytes, - sessionTranscriptBytes, readerSignature.value(), - testEntriesEntryCounts) + signingKeyBlob, sessionTranscriptBytes, + readerSignature.value(), testEntriesEntryCounts) .isOk()); for (const auto& entry : testEntries) { @@ -377,14 +382,9 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { EXPECT_EQ(content, entry.valueCbor); } - // Generate the key that will be used to sign AuthenticatedData. - vector signingKeyBlob; - Certificate signingKeyCertificate; - ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk()); - vector mac; vector deviceNameSpacesBytes; - ASSERT_TRUE(credential->finishRetrieval(signingKeyBlob, &mac, &deviceNameSpacesBytes).isOk()); + ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk()); cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {}); ASSERT_EQ( "{\n" From 18be965c7e7d155930b182b41d8d1c1fb8405bf9 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Mon, 2 Mar 2020 10:24:23 -0500 Subject: [PATCH 0685/1022] Identity: Statically link additional libraries in VtsHalIdentityTargetTest. The problem was that VtsHalIdentityTargetTest was dynamically linking libraries that (currently) only are pulled in by the default IC HAL implementaiton. This caused linking problems when copying VtsHalIdentityTargetTest onto a device a running it. Fix this by only dynamically linking libbinder and libcrypto. Bug: 150475275 Test: VtsHalIdentityTargetTest runs on a device without Identity Credential. Merged-In: I4162cc81ade0373c31c96008f3a2bc95684fd2c2 Change-Id: I7a55a6e602b9902bd725190aa5631644f7639b95 --- identity/aidl/vts/Android.bp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp index 21ff440075..cecc814fdc 100644 --- a/identity/aidl/vts/Android.bp +++ b/identity/aidl/vts/Android.bp @@ -7,10 +7,11 @@ cc_test { srcs: ["VtsHalIdentityTargetTest.cpp"], shared_libs: [ "libbinder", - "libcppbor", - "android.hardware.identity-support-lib", + "libcrypto", ], static_libs: [ + "libcppbor", + "android.hardware.identity-support-lib", "android.hardware.identity-cpp", "android.hardware.keymaster-cpp", ], From 25cf3b5b9c76bcf17ec38b9878eca9ebd976e00d Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Thu, 5 Mar 2020 15:23:28 -0800 Subject: [PATCH 0686/1022] Bugfix: add "override" explicitly to make the compiler happy Test: build Bug: 148877226 Change-Id: I90806ee2c2302ce9cc5dc8f82754aa807c2ec7ef --- .../2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h index e3cbf2e7cd..f2d3c1361e 100644 --- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h @@ -206,7 +206,7 @@ private: InternalPool(VehiclePropertyType type, size_t vectorSize) : mPropType(type), mVectorSize(vectorSize) {} - RecyclableType obtain() { + RecyclableType obtain() override { return ObjectPool::obtain(); } protected: From b19aac8c962cee542ea3cae8b7c504e2e328eeee Mon Sep 17 00:00:00 2001 From: Alain Michaud Date: Tue, 3 Mar 2020 20:45:04 +0000 Subject: [PATCH 0687/1022] bluetooth: Reference Bluetooth core specification 5.2 Test: None Bug: 151089119 Change-Id: I5c4ade22cda7bb8592625c6d0b7ec4aaf481aadd --- bluetooth/1.1/IBluetoothHci.hal | 4 ++-- current.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bluetooth/1.1/IBluetoothHci.hal b/bluetooth/1.1/IBluetoothHci.hal index 0f69c6eadd..2a520c1cbc 100644 --- a/bluetooth/1.1/IBluetoothHci.hal +++ b/bluetooth/1.1/IBluetoothHci.hal @@ -35,8 +35,8 @@ interface IBluetoothHci extends @1.0::IBluetoothHci { initialize_1_1(@1.1::IBluetoothHciCallbacks callback); /** - * Send an ISO data packet (as specified in the Bluetooth Specification - * V6.0) to the Bluetooth controller. + * Send an ISO data packet (as specified in the Bluetooth Core + * Specification v5.2) to the Bluetooth controller. * Packets must be processed in order. * @param data HCI data packet to be sent */ diff --git a/current.txt b/current.txt index a6f35ba95f..394c37a575 100644 --- a/current.txt +++ b/current.txt @@ -634,7 +634,7 @@ dd377f404a8e71f6191d295e10067db629b0f0c28e594af906f2bea5d87fe2cc android.hardwar ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types 6828bbf18dc5d0f00c73341a10c8e4d574346c1abb1c2ed682ba5e9f8a3240d9 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprint 82cad99f5feb2ea9bcd4579055edf4af8feb9fc602a6e4827ddd727d254d4991 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprintClientCallback -79e115c8f8970b8b914bafc66df5425e065fda4dcda97222966ef12451d2a1cc android.hardware.bluetooth@1.1::IBluetoothHci +362fd1c21641c2224f3b80c30d9797b988fa3f344243d531ba73c553779a5763 android.hardware.bluetooth@1.1::IBluetoothHci 40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types From 20a3e395bf61a216d26ef9403a856a85c1007003 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Mon, 9 Mar 2020 23:31:29 +0000 Subject: [PATCH 0688/1022] Update audio VTS source code to match the change in AudioPolicyConfig Use getInputDevices instead of getAvailableInputDevices. Bug: 149854039 Test: atest VtsHalAudioV5_0TargetTest Change-Id: I0fed71eba8d031465ef98da2bf6be16c2fbfb5ff --- audio/core/all-versions/vts/functional/ConfigHelper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/audio/core/all-versions/vts/functional/ConfigHelper.h b/audio/core/all-versions/vts/functional/ConfigHelper.h index a2f4116baa..8ef2b436bb 100644 --- a/audio/core/all-versions/vts/functional/ConfigHelper.h +++ b/audio/core/all-versions/vts/functional/ConfigHelper.h @@ -40,7 +40,7 @@ struct ConfigHelper { return devs.getDevice(AUDIO_DEVICE_IN_BUILTIN_MIC, {}, AUDIO_FORMAT_DEFAULT); }; auto primaryMic = getMic(policyConfig.getPrimaryModule()->getDeclaredDevices()); - auto availableMic = getMic(policyConfig.getAvailableInputDevices()); + auto availableMic = getMic(policyConfig.getInputDevices()); return primaryMic != nullptr && primaryMic->equals(availableMic); } From 9894812dd107840120bbe9a02fa796abc2ac62e4 Mon Sep 17 00:00:00 2001 From: Pierre Couillaud Date: Thu, 27 Feb 2020 11:48:01 -0800 Subject: [PATCH 0689/1022] vts: VtsHalGraphicsMapperV2_1TargetTest fixup's 1) handles allocated through 'allocate' should be removed through 'freeBuffer'. 2) make use of intended buffer handle in GetTransportSizeBadBuffer. Bug: 146444563 Test: build, boot, VtsHalGraphicsMapperV2_1TargetTest Change-Id: I6c1a67fc36dbc653ec2ada6a335d685d21e82800 Signed-off-by: Pierre Couillaud --- .../VtsHalGraphicsMapperV2_1TargetTest.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp b/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp index 1185945775..3d792f9f8e 100644 --- a/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp +++ b/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp @@ -94,7 +94,7 @@ TEST_P(GraphicsMapperHidlTest, ValidateBufferSizeBadBuffer) { mDummyDescriptorInfo.width); ASSERT_EQ(Error::BAD_BUFFER, ret) << "validateBufferSize with raw buffer handle did not fail with BAD_BUFFER"; - native_handle_delete(rawBufferHandle); + ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(rawBufferHandle)); } /** @@ -179,11 +179,11 @@ TEST_P(GraphicsMapperHidlTest, GetTransportSizeBadBuffer) { ASSERT_NO_FATAL_FAILURE(rawBufferHandle = const_cast( mGralloc->allocate(mDummyDescriptorInfo, false))); mGralloc->getMapper()->getTransportSize( - invalidHandle, [&](const auto& tmpError, const auto&, const auto&) { - ASSERT_EQ(Error::BAD_BUFFER, tmpError) - << "getTransportSize with raw buffer handle did not fail with BAD_BUFFER"; - }); - native_handle_delete(rawBufferHandle); + rawBufferHandle, [&](const auto& tmpError, const auto&, const auto&) { + ASSERT_EQ(Error::BAD_BUFFER, tmpError) + << "getTransportSize with raw buffer handle did not fail with BAD_BUFFER"; + }); + ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(rawBufferHandle)); } /** From b3c511d51d54126661aecce464066b7132f7e505 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Mon, 2 Mar 2020 15:49:11 -0800 Subject: [PATCH 0690/1022] Remove duplicated comment section The comment section about vendor extensions is already on lines 330-336 and should not appear inside the comment about a specific non-vendor extension format. Bug: b/151105493 Test: n/a Change-Id: I0559b3157f21e2ab23d8c4a53d2a0d74ebb40561 --- .../aidl/android/hardware/graphics/common/PixelFormat.aidl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl index 49424622c2..4e0c5ef8d9 100644 --- a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl +++ b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl @@ -403,10 +403,6 @@ enum PixelFormat { * cr_offset = y_size * cb_offset = y_size + c_size * - * This range is reserved for vendor extensions. Formats in this range - * must support BufferUsage::GPU_TEXTURE. Clients must assume they do not - * have an alpha component. - * * This format must be accepted by the allocator when used with the * following usage flags: * From c1b5b52c70e0a2bb31b85b31b302bf3fa9091693 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Thu, 5 Mar 2020 10:07:47 -0800 Subject: [PATCH 0691/1022] gralloc4-vts: fix GetLargeReservedRegion test The existing test never assigns a handle to bufferHandle so mGralloc->getReservedRegion() will always be called with nullptr and will always return with BAD_BUFFER. Bug: b/146515640 Test: VtsHalGraphicsMapperV4_0Target Change-Id: I85dac94956c6b9db5b4a19faeb16fc947f7457e1 --- .../functional/VtsHalGraphicsMapperV4_0TargetTest.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 6cc5e34326..a783eaa7a4 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -2124,8 +2124,14 @@ TEST_P(GraphicsMapperHidlTest, GetLargeReservedRegion) { Error err; mGralloc->getAllocator()->allocate( - descriptor, 1, - [&](const auto& tmpError, const auto&, const auto&) { err = tmpError; }); + descriptor, 1, [&](const auto& tmpError, const auto&, const auto& tmpBuffers) { + err = tmpError; + if (err == Error::NONE) { + ASSERT_EQ(1, tmpBuffers.size()); + ASSERT_NO_FATAL_FAILURE(bufferHandle = + mGralloc->importBuffer(tmpBuffers[0])); + } + }); if (err == Error::UNSUPPORTED) { continue; } From 9347054f3c91f14559e7a3fd5ea1b0b3a88ecf35 Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Tue, 10 Mar 2020 14:29:36 -0700 Subject: [PATCH 0692/1022] Convert VtsHalCasV1_2TargetTest to parameterized gtest bug: 148815882 Test: Manual Change-Id: I9f8de920867d8eb78819ad6efbe0f0d559c99c60 --- cas/1.2/vts/functional/Android.bp | 6 ++- .../functional/VtsHalCasV1_2TargetTest.cpp | 38 ++++++------------- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/cas/1.2/vts/functional/Android.bp b/cas/1.2/vts/functional/Android.bp index 9bc372c3a7..2d6517f0b0 100644 --- a/cas/1.2/vts/functional/Android.bp +++ b/cas/1.2/vts/functional/Android.bp @@ -31,6 +31,8 @@ cc_test { shared_libs: [ "libbinder", ], - test_suites: ["general-tests"], + test_suites: [ + "general-tests", + "vts-core", + ], } - diff --git a/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp index 8439ceb6fa..58e0f2e0a8 100644 --- a/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp +++ b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp @@ -16,8 +16,6 @@ #define LOG_TAG "mediacas_hidl_hal_test" -#include -#include #include #include #include @@ -28,8 +26,11 @@ #include #include #include +#include +#include #include #include +#include #include #include #include @@ -293,27 +294,14 @@ void MediaCasListener::testStatusUpdate(sp& mediaCas, std::vector EXPECT_EQ(mEventArg, static_cast(mode)); } -// Test environment for Cas HIDL HAL. -class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static CasHidlEnvironment* Instance() { - static CasHidlEnvironment* instance = new CasHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { registerTestService(); } -}; - -class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class MediaCasHidlTest : public testing::TestWithParam { public: virtual void SetUp() override { - mService = ::testing::VtsHalHidlTargetTestBase::getService( - CasHidlEnvironment::Instance()->getServiceName()); + mService = IMediaCasService::getService(GetParam()); ASSERT_NE(mService, nullptr); } - sp mService; + sp mService = nullptr; protected: static void description(const std::string& description) { @@ -497,7 +485,7 @@ class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionResult(returnVoid.isOk()); } -TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) { +TEST_P(MediaCasHidlTest, TestClearKeyApisWithSession) { description("Test that valid call sequences with SessionEvent send and receive"); ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID)); @@ -609,11 +597,7 @@ TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) { } // anonymous namespace -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - CasHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; -} +INSTANTIATE_TEST_SUITE_P( + PerInstance, MediaCasHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)), + android::hardware::PrintInstanceNameToString); From 8922e560881840bf156cbae2721814dee9cd3d31 Mon Sep 17 00:00:00 2001 From: "Harpreet \\\"Eli\\\" Sangha" Date: Wed, 11 Mar 2020 06:48:57 +0900 Subject: [PATCH 0693/1022] vibrator: aidl: Remove Output Checks on Error VTS tests should treat output values as uninitialized when the returns status is not OK. Bug: 151174217 Test: Ran on Flame and Walleye Signed-off-by: Harpreet \"Eli\" Sangha Change-Id: I8a3fa77d35265b6dd371caace18ffb810e83a72f --- vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp index 411fe7a2fe..8b16025b5d 100644 --- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp +++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp @@ -128,7 +128,6 @@ TEST_P(VibratorAidl, ValidateEffect) { } else { EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION) << toString(effect) << " " << toString(strength); - EXPECT_EQ(lengthMs, 0); } } } @@ -157,7 +156,6 @@ TEST_P(VibratorAidl, ValidateEffectWithCallback) { EXPECT_GT(lengthMs, 0); } else { EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION); - EXPECT_EQ(lengthMs, 0); } if (!status.isOk()) continue; @@ -177,7 +175,6 @@ TEST_P(VibratorAidl, ValidateEffectWithCallbackNotSupported) { int lengthMs; Status status = vibrator->perform(effect, strength, callback, &lengthMs); EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode()); - EXPECT_EQ(lengthMs, 0); } } } From 7aec50208c94406d5e91bdbafe37e34b0e53d0f8 Mon Sep 17 00:00:00 2001 From: "Harpreet \\\"Eli\\\" Sangha" Date: Wed, 11 Mar 2020 06:00:55 +0900 Subject: [PATCH 0694/1022] vibrator: aidl: Apply Compose API Feedback - Make Thud and Spin optional due to complexity. - Make "scale" inclusive of zero, which represents minimum "feelable" intensity. - Update VTS tests appropriately. - Fix typo in VTS test names. Bug: 151084263 Test: VTS on Flame, Walleye, and Cuttlefish Signed-off-by: Harpreet \"Eli\" Sangha Change-Id: Ib0d046be83ee79ab38e0b9c3fb87a41f23879f8b --- .../hardware/vibrator/CompositeEffect.aidl | 5 +- .../hardware/vibrator/CompositePrimitive.aidl | 16 ++++ .../android/hardware/vibrator/IVibrator.aidl | 4 +- vibrator/aidl/default/Vibrator.cpp | 2 +- .../aidl/vts/VtsHalVibratorTargetTest.cpp | 84 ++++++++++++++++--- 5 files changed, 97 insertions(+), 14 deletions(-) diff --git a/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl b/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl index 84556b57bb..406a899823 100644 --- a/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl +++ b/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl @@ -23,6 +23,9 @@ parcelable CompositeEffect { /* Period of silence preceding primitive. */ int delayMs; CompositePrimitive primitive; - /* 0.0 (exclusive) - 1.0 (inclusive) */ + /* + * 0.0 (inclusive) - 1.0 (inclusive), + * where 0.0 is minimum "feelable" amplitude. + */ float scale; } diff --git a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl index 0fdfa5d5c2..8e82db076b 100644 --- a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl +++ b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl @@ -21,37 +21,53 @@ package android.hardware.vibrator; enum CompositePrimitive { /** * No haptic effect. Used to generate extended delays between primitives. + * + * Support is required. */ NOOP, /** * This effect should produce a sharp, crisp click sensation. + * + * Support is required. */ CLICK, /** * A haptic effect that simulates downwards movement with gravity. Often * followed by extra energy of hitting and reverberation to augment * physicality. + * + * Support is optional. */ THUD, /** * A haptic effect that simulates spinning momentum. + * + * Support is optional. */ SPIN, /** * A haptic effect that simulates quick upward movement against gravity. + * + * Support is required. */ QUICK_RISE, /** * A haptic effect that simulates slow upward movement against gravity. + * + * Support is required. */ SLOW_RISE, /** * A haptic effect that simulates quick downwards movement with gravity. + * + * Support is required. */ QUICK_FALL, /** * This very short effect should produce a light crisp sensation intended * to be used repetitively for dynamic feedback. + * + * Support is required. */ LIGHT_TICK, } diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl index 6489c1d600..0b21248220 100644 --- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl +++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl @@ -161,8 +161,8 @@ interface IVibrator { * List of supported effect primitive. * * Return the effect primitives which are supported by the compose API. - * Implementations are expected to support all primitives of the interface - * version that they implement. + * Implementations are expected to support all required primitives of the + * interface version that they implement (see primitive definitions). */ CompositePrimitive[] getSupportedPrimitives(); diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp index 9236b95ddc..b359100d1a 100644 --- a/vibrator/aidl/default/Vibrator.cpp +++ b/vibrator/aidl/default/Vibrator.cpp @@ -146,7 +146,7 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector& composi if (e.delayMs > kComposeDelayMaxMs) { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } - if (e.scale <= 0.0f || e.scale > 1.0f) { + if (e.scale < 0.0f || e.scale > 1.0f) { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } if (std::find(supported.begin(), supported.end(), e.primitive) == supported.end()) { diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp index 8b16025b5d..8340517de6 100644 --- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp +++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp @@ -21,6 +21,7 @@ #include #include +#include #include using android::ProcessState; @@ -53,6 +54,11 @@ const std::vector kCompositePrimitives{ android::enum_range().begin(), android::enum_range().end()}; +const std::vector kOptionalPrimitives = { + CompositePrimitive::THUD, + CompositePrimitive::SPIN, +}; + const std::vector kInvalidPrimitives = { static_cast(static_cast(kCompositePrimitives.front()) - 1), static_cast(static_cast(kCompositePrimitives.back()) + 1), @@ -264,38 +270,56 @@ TEST_P(VibratorAidl, GetSupportedPrimitives) { EXPECT_EQ(Status::EX_NONE, vibrator->getSupportedPrimitives(&supported).exceptionCode()); - std::sort(supported.begin(), supported.end()); + for (auto primitive : kCompositePrimitives) { + bool isPrimitiveSupported = + std::find(supported.begin(), supported.end(), primitive) != supported.end(); + bool isPrimitiveOptional = + std::find(kOptionalPrimitives.begin(), kOptionalPrimitives.end(), primitive) != + kOptionalPrimitives.end(); - EXPECT_EQ(kCompositePrimitives, supported); + EXPECT_TRUE(isPrimitiveSupported || isPrimitiveOptional) << toString(primitive); + } } } TEST_P(VibratorAidl, GetPrimitiveDuration) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { - int32_t duration; + std::vector supported; + ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk()); for (auto primitive : kCompositePrimitives) { - EXPECT_EQ(Status::EX_NONE, - vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode()); + bool isPrimitiveSupported = + std::find(supported.begin(), supported.end(), primitive) != supported.end(); + int32_t duration; + + Status status = vibrator->getPrimitiveDuration(primitive, &duration); + + if (isPrimitiveSupported) { + EXPECT_EQ(Status::EX_NONE, status.exceptionCode()); + } else { + EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode()); + } } } } TEST_P(VibratorAidl, ComposeValidPrimitives) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { + std::vector supported; int32_t maxDelay, maxSize; + ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk()); EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode()); EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode()); std::vector composite; - for (auto primitive : kCompositePrimitives) { + for (auto primitive : supported) { CompositeEffect effect; effect.delayMs = std::rand() % (maxDelay + 1); effect.primitive = primitive; - effect.scale = static_cast(std::rand()) / RAND_MAX ?: 1.0f; + effect.scale = static_cast(std::rand()) / RAND_MAX; composite.emplace_back(effect); if (composite.size() == maxSize) { @@ -314,7 +338,21 @@ TEST_P(VibratorAidl, ComposeValidPrimitives) { TEST_P(VibratorAidl, ComposeUnsupportedPrimitives) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { - for (auto primitive : kInvalidPrimitives) { + auto unsupported = kInvalidPrimitives; + std::vector supported; + + ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk()); + + for (auto primitive : kCompositePrimitives) { + bool isPrimitiveSupported = + std::find(supported.begin(), supported.end(), primitive) != supported.end(); + + if (!isPrimitiveSupported) { + unsupported.push_back(primitive); + } + } + + for (auto primitive : unsupported) { std::vector composite(1); for (auto& effect : composite) { @@ -329,7 +367,33 @@ TEST_P(VibratorAidl, ComposeUnsupportedPrimitives) { } } -TEST_P(VibratorAidl, CompseDelayBoundary) { +TEST_P(VibratorAidl, ComposeScaleBoundary) { + if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { + std::vector composite(1); + CompositeEffect& effect = composite[0]; + + effect.delayMs = 0; + effect.primitive = CompositePrimitive::CLICK; + + effect.scale = std::nextafter(0.0f, -1.0f); + EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, + vibrator->compose(composite, nullptr).exceptionCode()); + + effect.scale = 0.0f; + EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode()); + + effect.scale = 1.0f; + EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode()); + + effect.scale = std::nextafter(1.0f, 2.0f); + EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, + vibrator->compose(composite, nullptr).exceptionCode()); + + vibrator->off(); + } +} + +TEST_P(VibratorAidl, ComposeDelayBoundary) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { int32_t maxDelay; @@ -354,7 +418,7 @@ TEST_P(VibratorAidl, CompseDelayBoundary) { } } -TEST_P(VibratorAidl, CompseSizeBoundary) { +TEST_P(VibratorAidl, ComposeSizeBoundary) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { int32_t maxSize; From 034c9bc96e624f13388970c91c3bd322cf57a51a Mon Sep 17 00:00:00 2001 From: Huihong Luo Date: Thu, 6 Feb 2020 18:39:56 -0800 Subject: [PATCH 0695/1022] Don't send brightness to car service inside Emulator This fixes this cts test: android.cts.statsd.atom.UidAtomTests#testScreenBrightness Bug: 139959479 Test: atest android.cts.statsd.atom.UidAtomTests#testScreenBrightness Change-Id: I66f858ce7686a90cd395f4e646133e8ea4604be4 Merged-In: I66f858ce7686a90cd395f4e646133e8ea4604be4 (cherry picked from commit 1322465c48d0c3dfa5953573b80a89460b8e7e95) (cherry picked from commit 5d463fdaaa02189d500f189fe1e9401c07a42046) --- .../impl/vhal_v2_0/EmulatedVehicleHal.cpp | 24 ++++++++++++++++++- .../impl/vhal_v2_0/EmulatedVehicleHal.h | 1 + 2 files changed, 24 insertions(+), 1 deletion(-) 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 6d5f23f7fc..b76aff9421 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 @@ -15,8 +15,9 @@ */ #define LOG_TAG "DefaultVehicleHal_v2_0" -#include #include +#include +#include #include "EmulatedVehicleHal.h" #include "JsonFakeValueGenerator.h" @@ -186,6 +187,14 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { return StatusCode::NOT_AVAILABLE; } + if (mInEmulator && propValue.prop == toInt(VehicleProperty::DISPLAY_BRIGHTNESS)) { + // Emulator does not support remote brightness control, b/139959479 + // do not send it down so that it does not bring unnecessary property change event + // return other error code, such NOT_AVAILABLE, causes Emulator to be freezing + // TODO: return StatusCode::NOT_AVAILABLE once the above issue is fixed + return StatusCode::OK; + } + /** * After checking all conditions, such as the property is available, a real vhal will * sent the events to Car ECU to take actions. @@ -211,6 +220,17 @@ static bool isDiagnosticProperty(VehiclePropConfig propConfig) { return false; } +// determine if it's running inside Android Emulator +static bool isInEmulator() { + char propValue[PROP_VALUE_MAX]; + bool isEmulator = (__system_property_get("ro.kernel.qemu", propValue) != 0); + if (!isEmulator) { + isEmulator = (__system_property_get("ro.hardware", propValue) != 0) && + (!strcmp(propValue, "ranchu") || !strcmp(propValue, "goldfish")); + } + return isEmulator; +} + // Parse supported properties list and generate vector of property values to hold current values. void EmulatedVehicleHal::onCreate() { static constexpr bool shouldUpdateStatus = true; @@ -261,6 +281,8 @@ void EmulatedVehicleHal::onCreate() { } initObd2LiveFrame(*mPropStore->getConfigOrDie(OBD2_LIVE_FRAME)); initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME)); + mInEmulator = isInEmulator(); + ALOGD("mInEmulator=%s", mInEmulator ? "true" : "false"); } std::vector EmulatedVehicleHal::listProperties() { diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h index ebf19951b3..dc05145cd7 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h @@ -86,6 +86,7 @@ private: std::unordered_set mHvacPowerProps; RecurrentTimer mRecurrentTimer; VehicleHalClient* mVehicleClient; + bool mInEmulator; }; } // impl From f161cc74a11b7468f5adc51cdfbbc3d5dd87f51a Mon Sep 17 00:00:00 2001 From: Lev Proleev Date: Thu, 12 Mar 2020 13:34:18 +0000 Subject: [PATCH 0696/1022] Clarify supported ranks for new ops in R Fix: 151108533 Test: mma Change-Id: I85b66ab5940d09b2786ecb14bff5bc1c1dee894a --- current.txt | 2 +- neuralnetworks/1.3/types.hal | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/current.txt b/current.txt index 873e2f6061..d8f9c08708 100644 --- a/current.txt +++ b/current.txt @@ -681,7 +681,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 6e904be0ddca5ae1de8eba020e6c38ed935ea7d80cd08f47787f137a0ca58555 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback 2b0b10d2ea7a18a4048cd0eb83d35c19a817aeee95f65807fc31f4ef21381397 android.hardware.neuralnetworks@1.3::IPreparedModel eee3430cc86c97c7b407495863d8fb61da6f1a64b7721e77b9b4909b11b174e9 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -c9320b04ec302624985180a02d591bea5e435601fc411a6cabb58878e4e1ad68 android.hardware.neuralnetworks@1.3::types +e442ab1b440327fe4e8a3b0b8ac6874e9bc6342e91fe976eb9fea77c63961ec8 android.hardware.neuralnetworks@1.3::types b335c3c732c799b299fa61c6de6260ab4d20cbd0ec21acd6db14d8156c745d0b android.hardware.tv.tuner@1.0::types adab52e647d1a1ccfbdabdfc9c73352f8e834b61322e505bc6e3d3a0d3acc259 android.hardware.tv.tuner@1.0::IDemux 548e1a16fc4f779346e14968a63cd6f160e1e2c8b8c99256b2bac24a24b52a9a android.hardware.tv.tuner@1.0::IDescrambler diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index daaf22eddb..25ec915a8a 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -5168,6 +5168,8 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT16} * * {@link OperandType::TENSOR_FLOAT32} * + * Supported tensor rank: from 1. + * * Inputs: * * 0: A tensor, specifying the input. May be zero-sized. * * 1: A scalar, specifying the alpha parameter. @@ -5197,6 +5199,8 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_QUANT8_ASYMM} * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} * + * Supported tensor rank: from 1. + * * Inputs: * * 0: A tensor, specifying the input. May be zero-sized. * @@ -5215,6 +5219,8 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_FLOAT32} * * {@link OperandType::TENSOR_INT32} * + * Supported tensor rank: from 1. + * * Inputs: * * 0: A 1-D tensor, specifying the desired output tensor shape. * * 1: A scalar, specifying the value to fill the output tensors with. @@ -5248,6 +5254,8 @@ enum OperationType : int32_t { * * {@link OperandType::TENSOR_QUANT8_SYMM} * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} * + * Supported tensor rank: from 1. + * * Inputs: * * 0: The input tensor. * From da1a69288054dcbe9e91943d408a65b3c59c4a09 Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Wed, 11 Mar 2020 18:45:45 -0700 Subject: [PATCH 0697/1022] NNAPI VTS: Add validation for Priority This CL also cleans up the validation framework code. Bug: 67828197 Test: mma Test: VtsHalNeuralnetworksV1_*TargetTest Change-Id: I84661fb2b8204148788d10425ca0ac986158b15f --- .../1.0/vts/functional/ValidateModel.cpp | 15 +- .../1.0/vts/functional/ValidateRequest.cpp | 10 +- .../1.1/vts/functional/ValidateModel.cpp | 118 +++++++----- .../1.1/vts/functional/ValidateRequest.cpp | 10 +- .../1.2/vts/functional/ValidateBurst.cpp | 14 +- .../1.2/vts/functional/ValidateModel.cpp | 118 +++++++----- .../1.2/vts/functional/ValidateRequest.cpp | 10 +- .../1.3/vts/functional/ValidateBurst.cpp | 14 +- .../1.3/vts/functional/ValidateModel.cpp | 179 +++++++++++------- .../1.3/vts/functional/ValidateRequest.cpp | 10 +- 10 files changed, 300 insertions(+), 198 deletions(-) diff --git a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp index cc15263ae2..79d85943b1 100644 --- a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp @@ -24,6 +24,8 @@ namespace android::hardware::neuralnetworks::V1_0::vts::functional { using implementation::PreparedModelCallback; +using PrepareModelMutation = std::function; + ///////////////////////// UTILITY FUNCTIONS ///////////////////////// static void validateGetSupportedOperations(const sp& device, const std::string& message, @@ -54,12 +56,13 @@ static void validatePrepareModel(const sp& device, const std::string& m } // Primary validation function. This function will take a valid model, apply a -// mutation to it to invalidate the model, then pass it to interface calls that -// use the model. Note that the model here is passed by value, and any mutation -// to the model does not leave this function. -static void validate(const sp& device, const std::string& message, Model model, - const std::function& mutation) { - mutation(&model); +// mutation to invalidate the model, then pass these to supportedOperations and +// prepareModel. +static void validate(const sp& device, const std::string& message, + const Model& originalModel, const PrepareModelMutation& mutate) { + Model model = originalModel; + mutate(&model); + validateGetSupportedOperations(device, message, model); validatePrepareModel(device, message, model); } diff --git a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp index 05eefd13d8..0baa85bc8e 100644 --- a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp @@ -24,15 +24,17 @@ namespace android::hardware::neuralnetworks::V1_0::vts::functional { using implementation::ExecutionCallback; +using ExecutionMutation = std::function; + ///////////////////////// UTILITY FUNCTIONS ///////////////////////// // Primary validation function. This function will take a valid request, apply a // mutation to it to invalidate the request, then pass it to interface calls -// that use the request. Note that the request here is passed by value, and any -// mutation to the request does not leave this function. +// that use the request. static void validate(const sp& preparedModel, const std::string& message, - Request request, const std::function& mutation) { - mutation(&request); + const Request& originalRequest, const ExecutionMutation& mutate) { + Request request = originalRequest; + mutate(&request); SCOPED_TRACE(message + " [execute]"); sp executionCallback = new ExecutionCallback(); diff --git a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp index 0629a1edf9..3b6f0f8300 100644 --- a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp @@ -30,6 +30,8 @@ using V1_0::OperandLifeTime; using V1_0::OperandType; using V1_0::implementation::PreparedModelCallback; +using PrepareModelMutation = std::function; + ///////////////////////// UTILITY FUNCTIONS ///////////////////////// static void validateGetSupportedOperations(const sp& device, const std::string& message, @@ -67,16 +69,19 @@ static bool validExecutionPreference(ExecutionPreference preference) { } // Primary validation function. This function will take a valid model, apply a -// mutation to it to invalidate the model, then pass it to interface calls that -// use the model. Note that the model here is passed by value, and any mutation -// to the model does not leave this function. -static void validate(const sp& device, const std::string& message, Model model, - const std::function& mutation, - ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) { - mutation(&model); +// mutation to invalidate either the model or the execution preference, then +// pass these to supportedOperations and/or prepareModel if that method is +// called with an invalid argument. +static void validate(const sp& device, const std::string& message, + const Model& originalModel, const PrepareModelMutation& mutate) { + Model model = originalModel; + ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER; + mutate(&model, &preference); + if (validExecutionPreference(preference)) { validateGetSupportedOperations(device, message, model); } + validatePrepareModel(device, message, model, preference); } @@ -115,9 +120,11 @@ static void mutateOperandTypeTest(const sp& device, const Model& model) const std::string message = "mutateOperandTypeTest: operand " + std::to_string(operand) + " set to value " + std::to_string(invalidOperandType); - validate(device, message, model, [operand, invalidOperandType](Model* model) { - model->operands[operand].type = static_cast(invalidOperandType); - }); + validate(device, message, model, + [operand, invalidOperandType](Model* model, ExecutionPreference*) { + model->operands[operand].type = + static_cast(invalidOperandType); + }); } } } @@ -144,9 +151,10 @@ static void mutateOperandRankTest(const sp& device, const Model& model) const uint32_t invalidRank = getInvalidRank(model.operands[operand].type); const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) + " has rank of " + std::to_string(invalidRank); - validate(device, message, model, [operand, invalidRank](Model* model) { - model->operands[operand].dimensions = std::vector(invalidRank, 0); - }); + validate(device, message, model, + [operand, invalidRank](Model* model, ExecutionPreference*) { + model->operands[operand].dimensions = std::vector(invalidRank, 0); + }); } } @@ -173,9 +181,10 @@ static void mutateOperandScaleTest(const sp& device, const Model& model const float invalidScale = getInvalidScale(model.operands[operand].type); const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) + " has scale of " + std::to_string(invalidScale); - validate(device, message, model, [operand, invalidScale](Model* model) { - model->operands[operand].scale = invalidScale; - }); + validate(device, message, model, + [operand, invalidScale](Model* model, ExecutionPreference*) { + model->operands[operand].scale = invalidScale; + }); } } @@ -204,9 +213,10 @@ static void mutateOperandZeroPointTest(const sp& device, const Model& m const std::string message = "mutateOperandZeroPointTest: operand " + std::to_string(operand) + " has zero point of " + std::to_string(invalidZeroPoint); - validate(device, message, model, [operand, invalidZeroPoint](Model* model) { - model->operands[operand].zeroPoint = invalidZeroPoint; - }); + validate(device, message, model, + [operand, invalidZeroPoint](Model* model, ExecutionPreference*) { + model->operands[operand].zeroPoint = invalidZeroPoint; + }); } } } @@ -282,9 +292,10 @@ static void mutateOperationOperandTypeTest(const sp& device, const Mode const std::string message = "mutateOperationOperandTypeTest: operand " + std::to_string(operand) + " set to type " + toString(invalidOperandType); - validate(device, message, model, [operand, invalidOperandType](Model* model) { - mutateOperand(&model->operands[operand], invalidOperandType); - }); + validate(device, message, model, + [operand, invalidOperandType](Model* model, ExecutionPreference*) { + mutateOperand(&model->operands[operand], invalidOperandType); + }); } } } @@ -304,10 +315,11 @@ static void mutateOperationTypeTest(const sp& device, const Model& mode const std::string message = "mutateOperationTypeTest: operation " + std::to_string(operation) + " set to value " + std::to_string(invalidOperationType); - validate(device, message, model, [operation, invalidOperationType](Model* model) { - model->operations[operation].type = - static_cast(invalidOperationType); - }); + validate(device, message, model, + [operation, invalidOperationType](Model* model, ExecutionPreference*) { + model->operations[operation].type = + static_cast(invalidOperationType); + }); } } } @@ -321,9 +333,10 @@ static void mutateOperationInputOperandIndexTest(const sp& device, cons const std::string message = "mutateOperationInputOperandIndexTest: operation " + std::to_string(operation) + " input " + std::to_string(input); - validate(device, message, model, [operation, input, invalidOperand](Model* model) { - model->operations[operation].inputs[input] = invalidOperand; - }); + validate(device, message, model, + [operation, input, invalidOperand](Model* model, ExecutionPreference*) { + model->operations[operation].inputs[input] = invalidOperand; + }); } } } @@ -337,9 +350,10 @@ static void mutateOperationOutputOperandIndexTest(const sp& device, con const std::string message = "mutateOperationOutputOperandIndexTest: operation " + std::to_string(operation) + " output " + std::to_string(output); - validate(device, message, model, [operation, output, invalidOperand](Model* model) { - model->operations[operation].outputs[output] = invalidOperand; - }); + validate(device, message, model, + [operation, output, invalidOperand](Model* model, ExecutionPreference*) { + model->operations[operation].outputs[output] = invalidOperand; + }); } } } @@ -372,7 +386,7 @@ static void removeOperandTest(const sp& device, const Model& model) { for (size_t operand = 0; operand < model.operands.size(); ++operand) { const std::string message = "removeOperandTest: operand " + std::to_string(operand); validate(device, message, model, - [operand](Model* model) { removeOperand(model, operand); }); + [operand](Model* model, ExecutionPreference*) { removeOperand(model, operand); }); } } @@ -388,8 +402,9 @@ static void removeOperation(Model* model, uint32_t index) { static void removeOperationTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { const std::string message = "removeOperationTest: operation " + std::to_string(operation); - validate(device, message, model, - [operation](Model* model) { removeOperation(model, operation); }); + validate(device, message, model, [operation](Model* model, ExecutionPreference*) { + removeOperation(model, operation); + }); } } @@ -409,11 +424,12 @@ static void removeOperationInputTest(const sp& device, const Model& mod const std::string message = "removeOperationInputTest: operation " + std::to_string(operation) + ", input " + std::to_string(input); - validate(device, message, model, [operation, input](Model* model) { - uint32_t operand = model->operations[operation].inputs[input]; - model->operands[operand].numberOfConsumers--; - hidl_vec_removeAt(&model->operations[operation].inputs, input); - }); + validate(device, message, model, + [operation, input](Model* model, ExecutionPreference*) { + uint32_t operand = model->operations[operation].inputs[input]; + model->operands[operand].numberOfConsumers--; + hidl_vec_removeAt(&model->operations[operation].inputs, input); + }); } } } @@ -426,9 +442,10 @@ static void removeOperationOutputTest(const sp& device, const Model& mo const std::string message = "removeOperationOutputTest: operation " + std::to_string(operation) + ", output " + std::to_string(output); - validate(device, message, model, [operation, output](Model* model) { - hidl_vec_removeAt(&model->operations[operation].outputs, output); - }); + validate(device, message, model, + [operation, output](Model* model, ExecutionPreference*) { + hidl_vec_removeAt(&model->operations[operation].outputs, output); + }); } } } @@ -444,7 +461,7 @@ static void removeOperationOutputTest(const sp& device, const Model& mo static void addOperationInputTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { const std::string message = "addOperationInputTest: operation " + std::to_string(operation); - validate(device, message, model, [operation](Model* model) { + validate(device, message, model, [operation](Model* model, ExecutionPreference*) { uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT); hidl_vec_push_back(&model->operations[operation].inputs, index); hidl_vec_push_back(&model->inputIndexes, index); @@ -458,7 +475,7 @@ static void addOperationOutputTest(const sp& device, const Model& model for (size_t operation = 0; operation < model.operations.size(); ++operation) { const std::string message = "addOperationOutputTest: operation " + std::to_string(operation); - validate(device, message, model, [operation](Model* model) { + validate(device, message, model, [operation](Model* model, ExecutionPreference*) { uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT); hidl_vec_push_back(&model->operations[operation].outputs, index); hidl_vec_push_back(&model->outputIndexes, index); @@ -474,12 +491,13 @@ static const int32_t invalidExecutionPreferences[] = { }; static void mutateExecutionPreferenceTest(const sp& device, const Model& model) { - for (int32_t preference : invalidExecutionPreferences) { + for (int32_t invalidPreference : invalidExecutionPreferences) { const std::string message = - "mutateExecutionPreferenceTest: preference " + std::to_string(preference); - validate( - device, message, model, [](Model*) {}, - static_cast(preference)); + "mutateExecutionPreferenceTest: preference " + std::to_string(invalidPreference); + validate(device, message, model, + [invalidPreference](Model*, ExecutionPreference* preference) { + *preference = static_cast(invalidPreference); + }); } } diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp index 9684eb2b30..291433519e 100644 --- a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp @@ -28,15 +28,17 @@ using V1_0::IPreparedModel; using V1_0::Request; using V1_0::implementation::ExecutionCallback; +using ExecutionMutation = std::function; + ///////////////////////// UTILITY FUNCTIONS ///////////////////////// // Primary validation function. This function will take a valid request, apply a // mutation to it to invalidate the request, then pass it to interface calls -// that use the request. Note that the request here is passed by value, and any -// mutation to the request does not leave this function. +// that use the request. static void validate(const sp& preparedModel, const std::string& message, - Request request, const std::function& mutation) { - mutation(&request); + const Request& originalRequest, const ExecutionMutation& mutate) { + Request request = originalRequest; + mutate(&request); SCOPED_TRACE(message + " [execute]"); sp executionCallback = new ExecutionCallback(); diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp index ec9629bccb..9a22490383 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp @@ -38,6 +38,8 @@ using V1_0::ErrorStatus; using V1_0::Request; using ExecutionBurstCallback = ExecutionBurstController::ExecutionBurstCallback; +using BurstExecutionMutation = std::function*)>; + // This constant value represents the length of an FMQ that is large enough to // return a result from a burst execution for all of the generated test cases. constexpr size_t kExecutionBurstChannelLength = 1024; @@ -116,13 +118,13 @@ static void createBurstWithResultChannelLength( // Primary validation function. This function will take a valid serialized // request, apply a mutation to it to invalidate the serialized request, then -// pass it to interface calls that use the serialized request. Note that the -// serialized request here is passed by value, and any mutation to the -// serialized request does not leave this function. +// pass it to interface calls that use the serialized request. static void validate(RequestChannelSender* sender, ResultChannelReceiver* receiver, - const std::string& message, std::vector serialized, - const std::function*)>& mutation) { - mutation(&serialized); + const std::string& message, + const std::vector& originalSerialized, + const BurstExecutionMutation& mutate) { + std::vector serialized = originalSerialized; + mutate(&serialized); // skip if packet is too large to send if (serialized.size() > kExecutionBurstChannelLength) { diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp index 30530beacc..7451f095bf 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp @@ -29,6 +29,8 @@ using V1_0::OperandLifeTime; using V1_1::ExecutionPreference; using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; +using PrepareModelMutation = std::function; + ///////////////////////// UTILITY FUNCTIONS ///////////////////////// static void validateGetSupportedOperations(const sp& device, const std::string& message, @@ -67,16 +69,19 @@ static bool validExecutionPreference(ExecutionPreference preference) { } // Primary validation function. This function will take a valid model, apply a -// mutation to it to invalidate the model, then pass it to interface calls that -// use the model. Note that the model here is passed by value, and any mutation -// to the model does not leave this function. -static void validate(const sp& device, const std::string& message, Model model, - const std::function& mutation, - ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) { - mutation(&model); +// mutation to invalidate either the model or the execution preference, then +// pass these to supportedOperations and/or prepareModel if that method is +// called with an invalid argument. +static void validate(const sp& device, const std::string& message, + const Model& originalModel, const PrepareModelMutation& mutate) { + Model model = originalModel; + ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER; + mutate(&model, &preference); + if (validExecutionPreference(preference)) { validateGetSupportedOperations(device, message, model); } + validatePrepareModel(device, message, model, preference); } @@ -115,9 +120,11 @@ static void mutateOperandTypeTest(const sp& device, const Model& model) const std::string message = "mutateOperandTypeTest: operand " + std::to_string(operand) + " set to value " + std::to_string(invalidOperandType); - validate(device, message, model, [operand, invalidOperandType](Model* model) { - model->operands[operand].type = static_cast(invalidOperandType); - }); + validate(device, message, model, + [operand, invalidOperandType](Model* model, ExecutionPreference*) { + model->operands[operand].type = + static_cast(invalidOperandType); + }); } } } @@ -155,9 +162,10 @@ static void mutateOperandRankTest(const sp& device, const Model& model) } const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) + " has rank of " + std::to_string(invalidRank); - validate(device, message, model, [operand, invalidRank](Model* model) { - model->operands[operand].dimensions = std::vector(invalidRank, 0); - }); + validate(device, message, model, + [operand, invalidRank](Model* model, ExecutionPreference*) { + model->operands[operand].dimensions = std::vector(invalidRank, 0); + }); } } @@ -192,9 +200,10 @@ static void mutateOperandScaleTest(const sp& device, const Model& model const float invalidScale = getInvalidScale(model.operands[operand].type); const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) + " has scale of " + std::to_string(invalidScale); - validate(device, message, model, [operand, invalidScale](Model* model) { - model->operands[operand].scale = invalidScale; - }); + validate(device, message, model, + [operand, invalidScale](Model* model, ExecutionPreference*) { + model->operands[operand].scale = invalidScale; + }); } } @@ -234,9 +243,10 @@ static void mutateOperandZeroPointTest(const sp& device, const Model& m const std::string message = "mutateOperandZeroPointTest: operand " + std::to_string(operand) + " has zero point of " + std::to_string(invalidZeroPoint); - validate(device, message, model, [operand, invalidZeroPoint](Model* model) { - model->operands[operand].zeroPoint = invalidZeroPoint; - }); + validate(device, message, model, + [operand, invalidZeroPoint](Model* model, ExecutionPreference*) { + model->operands[operand].zeroPoint = invalidZeroPoint; + }); } } } @@ -386,9 +396,10 @@ static void mutateOperationOperandTypeTest(const sp& device, const Mode const std::string message = "mutateOperationOperandTypeTest: operand " + std::to_string(operand) + " set to type " + toString(invalidOperandType); - validate(device, message, model, [operand, invalidOperandType](Model* model) { - mutateOperand(&model->operands[operand], invalidOperandType); - }); + validate(device, message, model, + [operand, invalidOperandType](Model* model, ExecutionPreference*) { + mutateOperand(&model->operands[operand], invalidOperandType); + }); } } } @@ -407,10 +418,11 @@ static void mutateOperationTypeTest(const sp& device, const Model& mode const std::string message = "mutateOperationTypeTest: operation " + std::to_string(operation) + " set to value " + std::to_string(invalidOperationType); - validate(device, message, model, [operation, invalidOperationType](Model* model) { - model->operations[operation].type = - static_cast(invalidOperationType); - }); + validate(device, message, model, + [operation, invalidOperationType](Model* model, ExecutionPreference*) { + model->operations[operation].type = + static_cast(invalidOperationType); + }); } } } @@ -424,9 +436,10 @@ static void mutateOperationInputOperandIndexTest(const sp& device, cons const std::string message = "mutateOperationInputOperandIndexTest: operation " + std::to_string(operation) + " input " + std::to_string(input); - validate(device, message, model, [operation, input, invalidOperand](Model* model) { - model->operations[operation].inputs[input] = invalidOperand; - }); + validate(device, message, model, + [operation, input, invalidOperand](Model* model, ExecutionPreference*) { + model->operations[operation].inputs[input] = invalidOperand; + }); } } } @@ -440,9 +453,10 @@ static void mutateOperationOutputOperandIndexTest(const sp& device, con const std::string message = "mutateOperationOutputOperandIndexTest: operation " + std::to_string(operation) + " output " + std::to_string(output); - validate(device, message, model, [operation, output, invalidOperand](Model* model) { - model->operations[operation].outputs[output] = invalidOperand; - }); + validate(device, message, model, + [operation, output, invalidOperand](Model* model, ExecutionPreference*) { + model->operations[operation].outputs[output] = invalidOperand; + }); } } } @@ -503,7 +517,7 @@ static void removeOperandTest(const sp& device, const Model& model) { } const std::string message = "removeOperandTest: operand " + std::to_string(operand); validate(device, message, model, - [operand](Model* model) { removeOperand(model, operand); }); + [operand](Model* model, ExecutionPreference*) { removeOperand(model, operand); }); } } @@ -519,8 +533,9 @@ static void removeOperation(Model* model, uint32_t index) { static void removeOperationTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.operations.size(); ++operation) { const std::string message = "removeOperationTest: operation " + std::to_string(operation); - validate(device, message, model, - [operation](Model* model) { removeOperation(model, operation); }); + validate(device, message, model, [operation](Model* model, ExecutionPreference*) { + removeOperation(model, operation); + }); } } @@ -601,11 +616,12 @@ static void removeOperationInputTest(const sp& device, const Model& mod const std::string message = "removeOperationInputTest: operation " + std::to_string(operation) + ", input " + std::to_string(input); - validate(device, message, model, [operation, input](Model* model) { - uint32_t operand = model->operations[operation].inputs[input]; - model->operands[operand].numberOfConsumers--; - hidl_vec_removeAt(&model->operations[operation].inputs, input); - }); + validate(device, message, model, + [operation, input](Model* model, ExecutionPreference*) { + uint32_t operand = model->operations[operation].inputs[input]; + model->operands[operand].numberOfConsumers--; + hidl_vec_removeAt(&model->operations[operation].inputs, input); + }); } } } @@ -618,9 +634,10 @@ static void removeOperationOutputTest(const sp& device, const Model& mo const std::string message = "removeOperationOutputTest: operation " + std::to_string(operation) + ", output " + std::to_string(output); - validate(device, message, model, [operation, output](Model* model) { - hidl_vec_removeAt(&model->operations[operation].outputs, output); - }); + validate(device, message, model, + [operation, output](Model* model, ExecutionPreference*) { + hidl_vec_removeAt(&model->operations[operation].outputs, output); + }); } } } @@ -651,7 +668,7 @@ static void addOperationInputTest(const sp& device, const Model& model) continue; } const std::string message = "addOperationInputTest: operation " + std::to_string(operation); - validate(device, message, model, [operation](Model* model) { + validate(device, message, model, [operation](Model* model, ExecutionPreference*) { uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT); hidl_vec_push_back(&model->operations[operation].inputs, index); hidl_vec_push_back(&model->inputIndexes, index); @@ -665,7 +682,7 @@ static void addOperationOutputTest(const sp& device, const Model& model for (size_t operation = 0; operation < model.operations.size(); ++operation) { const std::string message = "addOperationOutputTest: operation " + std::to_string(operation); - validate(device, message, model, [operation](Model* model) { + validate(device, message, model, [operation](Model* model, ExecutionPreference*) { uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT); hidl_vec_push_back(&model->operations[operation].outputs, index); hidl_vec_push_back(&model->outputIndexes, index); @@ -681,12 +698,13 @@ static const int32_t invalidExecutionPreferences[] = { }; static void mutateExecutionPreferenceTest(const sp& device, const Model& model) { - for (int32_t preference : invalidExecutionPreferences) { + for (int32_t invalidPreference : invalidExecutionPreferences) { const std::string message = - "mutateExecutionPreferenceTest: preference " + std::to_string(preference); - validate( - device, message, model, [](Model*) {}, - static_cast(preference)); + "mutateExecutionPreferenceTest: preference " + std::to_string(invalidPreference); + validate(device, message, model, + [invalidPreference](Model*, ExecutionPreference* preference) { + *preference = static_cast(invalidPreference); + }); } } diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp index 7b5ff9b8e4..7a23c13fe0 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp @@ -31,6 +31,8 @@ using implementation::ExecutionCallback; using V1_0::ErrorStatus; using V1_0::Request; +using ExecutionMutation = std::function; + ///////////////////////// UTILITY FUNCTIONS ///////////////////////// static bool badTiming(Timing timing) { @@ -39,11 +41,11 @@ static bool badTiming(Timing timing) { // Primary validation function. This function will take a valid request, apply a // mutation to it to invalidate the request, then pass it to interface calls -// that use the request. Note that the request here is passed by value, and any -// mutation to the request does not leave this function. +// that use the request. static void validate(const sp& preparedModel, const std::string& message, - Request request, const std::function& mutation) { - mutation(&request); + const Request& originalRequest, const ExecutionMutation& mutate) { + Request request = originalRequest; + mutate(&request); // We'd like to test both with timing requested and without timing // requested. Rather than running each test both ways, we'll decide whether diff --git a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp index 6ff9dfd3a8..6ee7b1c534 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp @@ -43,6 +43,8 @@ using V1_2::MeasureTiming; using V1_2::Timing; using ExecutionBurstCallback = ExecutionBurstController::ExecutionBurstCallback; +using BurstExecutionMutation = std::function*)>; + // This constant value represents the length of an FMQ that is large enough to // return a result from a burst execution for all of the generated test cases. constexpr size_t kExecutionBurstChannelLength = 1024; @@ -122,13 +124,13 @@ static void createBurstWithResultChannelLength( // Primary validation function. This function will take a valid serialized // request, apply a mutation to it to invalidate the serialized request, then -// pass it to interface calls that use the serialized request. Note that the -// serialized request here is passed by value, and any mutation to the -// serialized request does not leave this function. +// pass it to interface calls that use the serialized request. static void validate(RequestChannelSender* sender, ResultChannelReceiver* receiver, - const std::string& message, std::vector serialized, - const std::function*)>& mutation) { - mutation(&serialized); + const std::string& message, + const std::vector& originalSerialized, + const BurstExecutionMutation& mutate) { + std::vector serialized = originalSerialized; + mutate(&serialized); // skip if packet is too large to send if (serialized.size() > kExecutionBurstChannelLength) { diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 7da2da980b..4c0100e219 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -30,6 +30,8 @@ using V1_2::SymmPerChannelQuantParams; using HidlToken = hidl_array(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; +using PrepareModelMutation = std::function; + ///////////////////////// UTILITY FUNCTIONS ///////////////////////// static void validateGetSupportedOperations(const sp& device, const std::string& message, @@ -44,13 +46,14 @@ static void validateGetSupportedOperations(const sp& device, const std: } static void validatePrepareModel(const sp& device, const std::string& message, - const Model& model, ExecutionPreference preference) { + const Model& model, ExecutionPreference preference, + Priority priority) { SCOPED_TRACE(message + " [prepareModel_1_3]"); sp preparedModelCallback = new PreparedModelCallback(); - Return prepareLaunchStatus = device->prepareModel_1_3( - model, preference, kDefaultPriority, {}, hidl_vec(), - hidl_vec(), HidlToken(), preparedModelCallback); + Return prepareLaunchStatus = + device->prepareModel_1_3(model, preference, priority, {}, hidl_vec(), + hidl_vec(), HidlToken(), preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast(prepareLaunchStatus)); @@ -67,18 +70,26 @@ static bool validExecutionPreference(ExecutionPreference preference) { preference == ExecutionPreference::SUSTAINED_SPEED; } +static bool validExecutionPriority(Priority priority) { + return priority == Priority::LOW || priority == Priority::MEDIUM || priority == Priority::HIGH; +} + // Primary validation function. This function will take a valid model, apply a -// mutation to it to invalidate the model, then pass it to interface calls that -// use the model. Note that the model here is passed by value, and any mutation -// to the model does not leave this function. -static void validate(const sp& device, const std::string& message, Model model, - const std::function& mutation, - ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) { - mutation(&model); - if (validExecutionPreference(preference)) { +// mutation to invalidate the model, the execution preference, or the priority, +// then pass these to supportedOperations and/or prepareModel if that method is +// called with an invalid argument. +static void validate(const sp& device, const std::string& message, + const Model& originalModel, const PrepareModelMutation& mutate) { + Model model = originalModel; + ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER; + Priority priority = kDefaultPriority; + mutate(&model, &preference, &priority); + + if (validExecutionPreference(preference) && validExecutionPriority(priority)) { validateGetSupportedOperations(device, message, model); } - validatePrepareModel(device, message, model, preference); + + validatePrepareModel(device, message, model, preference, priority); } static uint32_t addOperand(Model* model) { @@ -116,9 +127,11 @@ static void mutateOperandTypeTest(const sp& device, const Model& model) const std::string message = "mutateOperandTypeTest: operand " + std::to_string(operand) + " set to value " + std::to_string(invalidOperandType); - validate(device, message, model, [operand, invalidOperandType](Model* model) { - model->main.operands[operand].type = static_cast(invalidOperandType); - }); + validate(device, message, model, + [operand, invalidOperandType](Model* model, ExecutionPreference*, Priority*) { + model->main.operands[operand].type = + static_cast(invalidOperandType); + }); } } } @@ -156,9 +169,11 @@ static void mutateOperandRankTest(const sp& device, const Model& model) } const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) + " has rank of " + std::to_string(invalidRank); - validate(device, message, model, [operand, invalidRank](Model* model) { - model->main.operands[operand].dimensions = std::vector(invalidRank, 0); - }); + validate(device, message, model, + [operand, invalidRank](Model* model, ExecutionPreference*, Priority*) { + model->main.operands[operand].dimensions = + std::vector(invalidRank, 0); + }); } } @@ -194,9 +209,10 @@ static void mutateOperandScaleTest(const sp& device, const Model& model const float invalidScale = getInvalidScale(model.main.operands[operand].type); const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) + " has scale of " + std::to_string(invalidScale); - validate(device, message, model, [operand, invalidScale](Model* model) { - model->main.operands[operand].scale = invalidScale; - }); + validate(device, message, model, + [operand, invalidScale](Model* model, ExecutionPreference*, Priority*) { + model->main.operands[operand].scale = invalidScale; + }); } } @@ -237,9 +253,10 @@ static void mutateOperandZeroPointTest(const sp& device, const Model& m const std::string message = "mutateOperandZeroPointTest: operand " + std::to_string(operand) + " has zero point of " + std::to_string(invalidZeroPoint); - validate(device, message, model, [operand, invalidZeroPoint](Model* model) { - model->main.operands[operand].zeroPoint = invalidZeroPoint; - }); + validate(device, message, model, + [operand, invalidZeroPoint](Model* model, ExecutionPreference*, Priority*) { + model->main.operands[operand].zeroPoint = invalidZeroPoint; + }); } } } @@ -425,9 +442,10 @@ static void mutateOperationOperandTypeTest(const sp& device, const Mode const std::string message = "mutateOperationOperandTypeTest: operand " + std::to_string(operand) + " set to type " + toString(invalidOperandType); - validate(device, message, model, [operand, invalidOperandType](Model* model) { - mutateOperand(&model->main.operands[operand], invalidOperandType); - }); + validate(device, message, model, + [operand, invalidOperandType](Model* model, ExecutionPreference*, Priority*) { + mutateOperand(&model->main.operands[operand], invalidOperandType); + }); } } } @@ -446,10 +464,12 @@ static void mutateOperationTypeTest(const sp& device, const Model& mode const std::string message = "mutateOperationTypeTest: operation " + std::to_string(operation) + " set to value " + std::to_string(invalidOperationType); - validate(device, message, model, [operation, invalidOperationType](Model* model) { - model->main.operations[operation].type = - static_cast(invalidOperationType); - }); + validate(device, message, model, + [operation, invalidOperationType](Model* model, ExecutionPreference*, + Priority*) { + model->main.operations[operation].type = + static_cast(invalidOperationType); + }); } } } @@ -463,9 +483,11 @@ static void mutateOperationInputOperandIndexTest(const sp& device, cons const std::string message = "mutateOperationInputOperandIndexTest: operation " + std::to_string(operation) + " input " + std::to_string(input); - validate(device, message, model, [operation, input, invalidOperand](Model* model) { - model->main.operations[operation].inputs[input] = invalidOperand; - }); + validate(device, message, model, + [operation, input, invalidOperand](Model* model, ExecutionPreference*, + Priority*) { + model->main.operations[operation].inputs[input] = invalidOperand; + }); } } } @@ -480,9 +502,11 @@ static void mutateOperationOutputOperandIndexTest(const sp& device, con const std::string message = "mutateOperationOutputOperandIndexTest: operation " + std::to_string(operation) + " output " + std::to_string(output); - validate(device, message, model, [operation, output, invalidOperand](Model* model) { - model->main.operations[operation].outputs[output] = invalidOperand; - }); + validate(device, message, model, + [operation, output, invalidOperand](Model* model, ExecutionPreference*, + Priority*) { + model->main.operations[operation].outputs[output] = invalidOperand; + }); } } } @@ -548,8 +572,9 @@ static void removeOperandTest(const sp& device, const Model& model) { continue; } const std::string message = "removeOperandTest: operand " + std::to_string(operand); - validate(device, message, model, - [operand](Model* model) { removeOperand(model, operand); }); + validate(device, message, model, [operand](Model* model, ExecutionPreference*, Priority*) { + removeOperand(model, operand); + }); } } @@ -566,7 +591,9 @@ static void removeOperationTest(const sp& device, const Model& model) { for (size_t operation = 0; operation < model.main.operations.size(); ++operation) { const std::string message = "removeOperationTest: operation " + std::to_string(operation); validate(device, message, model, - [operation](Model* model) { removeOperation(model, operation); }); + [operation](Model* model, ExecutionPreference*, Priority*) { + removeOperation(model, operation); + }); } } @@ -654,11 +681,12 @@ static void removeOperationInputTest(const sp& device, const Model& mod const std::string message = "removeOperationInputTest: operation " + std::to_string(operation) + ", input " + std::to_string(input); - validate(device, message, model, [operation, input](Model* model) { - uint32_t operand = model->main.operations[operation].inputs[input]; - model->main.operands[operand].numberOfConsumers--; - hidl_vec_removeAt(&model->main.operations[operation].inputs, input); - }); + validate(device, message, model, + [operation, input](Model* model, ExecutionPreference*, Priority*) { + uint32_t operand = model->main.operations[operation].inputs[input]; + model->main.operands[operand].numberOfConsumers--; + hidl_vec_removeAt(&model->main.operations[operation].inputs, input); + }); } } } @@ -672,9 +700,10 @@ static void removeOperationOutputTest(const sp& device, const Model& mo const std::string message = "removeOperationOutputTest: operation " + std::to_string(operation) + ", output " + std::to_string(output); - validate(device, message, model, [operation, output](Model* model) { - hidl_vec_removeAt(&model->main.operations[operation].outputs, output); - }); + validate(device, message, model, + [operation, output](Model* model, ExecutionPreference*, Priority*) { + hidl_vec_removeAt(&model->main.operations[operation].outputs, output); + }); } } } @@ -707,11 +736,12 @@ static void addOperationInputTest(const sp& device, const Model& model) continue; } const std::string message = "addOperationInputTest: operation " + std::to_string(operation); - validate(device, message, model, [operation](Model* model) { - uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_INPUT); - hidl_vec_push_back(&model->main.operations[operation].inputs, index); - hidl_vec_push_back(&model->main.inputIndexes, index); - }); + validate(device, message, model, + [operation](Model* model, ExecutionPreference*, Priority*) { + uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_INPUT); + hidl_vec_push_back(&model->main.operations[operation].inputs, index); + hidl_vec_push_back(&model->main.inputIndexes, index); + }); } } @@ -721,11 +751,12 @@ static void addOperationOutputTest(const sp& device, const Model& model for (size_t operation = 0; operation < model.main.operations.size(); ++operation) { const std::string message = "addOperationOutputTest: operation " + std::to_string(operation); - validate(device, message, model, [operation](Model* model) { - uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_OUTPUT); - hidl_vec_push_back(&model->main.operations[operation].outputs, index); - hidl_vec_push_back(&model->main.outputIndexes, index); - }); + validate(device, message, model, + [operation](Model* model, ExecutionPreference*, Priority*) { + uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_OUTPUT); + hidl_vec_push_back(&model->main.operations[operation].outputs, index); + hidl_vec_push_back(&model->main.outputIndexes, index); + }); } } @@ -737,12 +768,31 @@ static const int32_t invalidExecutionPreferences[] = { }; static void mutateExecutionPreferenceTest(const sp& device, const Model& model) { - for (int32_t preference : invalidExecutionPreferences) { + for (int32_t invalidPreference : invalidExecutionPreferences) { const std::string message = - "mutateExecutionPreferenceTest: preference " + std::to_string(preference); - validate( - device, message, model, [](Model*) {}, - static_cast(preference)); + "mutateExecutionPreferenceTest: preference " + std::to_string(invalidPreference); + validate(device, message, model, + [invalidPreference](Model*, ExecutionPreference* preference, Priority*) { + *preference = static_cast(invalidPreference); + }); + } +} + +///////////////////////// VALIDATE PRIORITY ///////////////////////// + +static const int32_t invalidPriorities[] = { + static_cast(Priority::LOW) - 1, // lower bound + static_cast(Priority::HIGH) + 1, // upper bound +}; + +static void mutateExecutionPriorityTest(const sp& device, const Model& model) { + for (int32_t invalidPriority : invalidPriorities) { + const std::string message = + "mutatePriorityTest: priority " + std::to_string(invalidPriority); + validate(device, message, model, + [invalidPriority](Model*, ExecutionPreference*, Priority* priority) { + *priority = static_cast(invalidPriority); + }); } } @@ -764,6 +814,7 @@ void validateModel(const sp& device, const Model& model) { addOperationInputTest(device, model); addOperationOutputTest(device, model); mutateExecutionPreferenceTest(device, model); + mutateExecutionPriorityTest(device, model); } } // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index 5e806e5c9b..1ae8b3f21d 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -34,6 +34,8 @@ using V1_2::MeasureTiming; using V1_2::OutputShape; using V1_2::Timing; +using ExecutionMutation = std::function; + ///////////////////////// UTILITY FUNCTIONS ///////////////////////// static bool badTiming(Timing timing) { @@ -42,11 +44,11 @@ static bool badTiming(Timing timing) { // Primary validation function. This function will take a valid request, apply a // mutation to it to invalidate the request, then pass it to interface calls -// that use the request. Note that the request here is passed by value, and any -// mutation to the request does not leave this function. +// that use the request. static void validate(const sp& preparedModel, const std::string& message, - Request request, const std::function& mutation) { - mutation(&request); + const Request& originalRequest, const ExecutionMutation& mutate) { + Request request = originalRequest; + mutate(&request); // We'd like to test both with timing requested and without timing // requested. Rather than running each test both ways, we'll decide whether From 34cdbcde5096aa8d822626d953f9a493a6fa835f Mon Sep 17 00:00:00 2001 From: "Anton D. Kachalov" Date: Mon, 10 Feb 2020 20:37:08 +0100 Subject: [PATCH 0698/1022] Camera: Advertise numbered string ID for external cameras With current implementation cameraId is part of something like: device@3.5/external//dev/video0 This doesn't work well with Camera2 API based apps. Adding CameraIdOffset tag to Provider as a base offset. Test: presubmit builds Bug: 151350336 Merged-In: I6309d16be565616f048fb24a70e9be5b2f5ed480 Change-Id: I6309d16be565616f048fb24a70e9be5b2f5ed480 (cherry picked from commit 4f6022ae5de718c2892a9371c7a75fabacc9b837) --- .../3.4/default/ExternalCameraDevice.cpp | 29 +++++++++----- .../3.4/default/ExternalCameraUtils.cpp | 7 ++++ .../ExternalCameraDevice_3_4.h | 1 + .../ExternalCameraUtils.h | 3 ++ .../ExternalCameraProviderImpl_2_4.cpp | 39 +++++++++++-------- 5 files changed, 54 insertions(+), 25 deletions(-) diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp index f518a155a7..677b496324 100644 --- a/camera/device/3.4/default/ExternalCameraDevice.cpp +++ b/camera/device/3.4/default/ExternalCameraDevice.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include "android-base/macros.h" #include "CameraMetadata.h" @@ -46,10 +47,20 @@ constexpr int OPEN_RETRY_SLEEP_US = 100000; // 100ms * MAX_RETRY = 0.5 seconds } // anonymous namespace +const std::regex kDevicePathRE("/dev/video([0-9]+)"); + ExternalCameraDevice::ExternalCameraDevice( - const std::string& cameraId, const ExternalCameraConfig& cfg) : - mCameraId(cameraId), - mCfg(cfg) {} + const std::string& devicePath, const ExternalCameraConfig& cfg) : + mCameraId("-1"), + mDevicePath(devicePath), + mCfg(cfg) { + std::smatch sm; + if (std::regex_match(mDevicePath, sm, kDevicePathRE)) { + mCameraId = std::to_string(mCfg.cameraIdOffset + std::stoi(sm[1])); + } else { + ALOGE("%s: device path match failed for %s", __FUNCTION__, mDevicePath.c_str()); + } +} ExternalCameraDevice::~ExternalCameraDevice() {} @@ -129,20 +140,20 @@ Return ExternalCameraDevice::open( return Void(); } - unique_fd fd(::open(mCameraId.c_str(), O_RDWR)); + unique_fd fd(::open(mDevicePath.c_str(), O_RDWR)); if (fd.get() < 0) { int numAttempt = 0; do { ALOGW("%s: v4l2 device %s open failed, wait 33ms and try again", - __FUNCTION__, mCameraId.c_str()); + __FUNCTION__, mDevicePath.c_str()); usleep(OPEN_RETRY_SLEEP_US); // sleep and try again - fd.reset(::open(mCameraId.c_str(), O_RDWR)); + fd.reset(::open(mDevicePath.c_str(), O_RDWR)); numAttempt++; } while (fd.get() < 0 && numAttempt <= MAX_RETRY); if (fd.get() < 0) { ALOGE("%s: v4l2 device open %s failed: %s", - __FUNCTION__, mCameraId.c_str(), strerror(errno)); + __FUNCTION__, mDevicePath.c_str(), strerror(errno)); mLock.unlock(); _hidl_cb(Status::INTERNAL_ERROR, nullptr); return Void(); @@ -203,9 +214,9 @@ Return ExternalCameraDevice::dumpState(const ::android::hardware::hidl_han status_t ExternalCameraDevice::initCameraCharacteristics() { if (mCameraCharacteristics.isEmpty()) { // init camera characteristics - unique_fd fd(::open(mCameraId.c_str(), O_RDWR)); + unique_fd fd(::open(mDevicePath.c_str(), O_RDWR)); if (fd.get() < 0) { - ALOGE("%s: v4l2 device open %s failed", __FUNCTION__, mCameraId.c_str()); + ALOGE("%s: v4l2 device open %s failed", __FUNCTION__, mDevicePath.c_str()); return DEAD_OBJECT; } diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp index 62a4c87af5..8f4626c56d 100644 --- a/camera/device/3.4/default/ExternalCameraUtils.cpp +++ b/camera/device/3.4/default/ExternalCameraUtils.cpp @@ -703,6 +703,7 @@ namespace external { namespace common { namespace { + const int kDefaultCameraIdOffset = 100; const int kDefaultJpegBufSize = 5 << 20; // 5MB const int kDefaultNumVideoBuffer = 4; const int kDefaultNumStillBuffer = 2; @@ -738,6 +739,11 @@ ExternalCameraConfig ExternalCameraConfig::loadFromCfg(const char* cfgPath) { return ret; } + XMLElement *cameraIdOffset = providerCfg->FirstChildElement("CameraIdOffset"); + if (cameraIdOffset != nullptr) { + ret.cameraIdOffset = std::atoi(cameraIdOffset->GetText()); + } + XMLElement *ignore = providerCfg->FirstChildElement("ignore"); if (ignore == nullptr) { ALOGI("%s: no internal ignored device specified", __FUNCTION__); @@ -874,6 +880,7 @@ bool ExternalCameraConfig::updateFpsList(tinyxml2::XMLElement* fpsList, } ExternalCameraConfig::ExternalCameraConfig() : + cameraIdOffset(kDefaultCameraIdOffset), maxJpegBufSize(kDefaultJpegBufSize), numVideoBuffers(kDefaultNumVideoBuffer), numStillBuffers(kDefaultNumStillBuffer), diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h index 1958fcbab5..88726f4969 100644 --- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h +++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h @@ -149,6 +149,7 @@ protected: bool mInitialized = false; bool mInitFailed = false; std::string mCameraId; + std::string mDevicePath; const ExternalCameraConfig& mCfg; std::vector mSupportedFormats; CroppingType mCroppingType; diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h index 74f75eb246..b354406a5b 100644 --- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h +++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h @@ -68,6 +68,9 @@ struct ExternalCameraConfig { static const char* kDefaultCfgPath; static ExternalCameraConfig loadFromCfg(const char* cfgPath = kDefaultCfgPath); + // CameraId base offset for numerical representation + uint32_t cameraIdOffset; + // List of internal V4L2 video nodes external camera HAL must ignore. std::unordered_set mInternalDevices; diff --git a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp index 2bfced2c62..64a51f6141 100644 --- a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp +++ b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp @@ -44,17 +44,19 @@ const int kMaxDevicePathLen = 256; const char* kDevicePath = "/dev/"; constexpr char kPrefix[] = "video"; constexpr int kPrefixLen = sizeof(kPrefix) - 1; +constexpr int kDevicePrefixLen = sizeof(kDevicePath) + kPrefixLen + 1; -bool matchDeviceName(const hidl_string& deviceName, std::string* deviceVersion, - std::string* cameraId) { +bool matchDeviceName(int cameraIdOffset, + const hidl_string& deviceName, std::string* deviceVersion, + std::string* cameraDevicePath) { std::string deviceNameStd(deviceName.c_str()); std::smatch sm; if (std::regex_match(deviceNameStd, sm, kDeviceNameRE)) { if (deviceVersion != nullptr) { *deviceVersion = sm[1]; } - if (cameraId != nullptr) { - *cameraId = sm[2]; + if (cameraDevicePath != nullptr) { + *cameraDevicePath = "/dev/video" + std::to_string(std::stoi(sm[2]) - cameraIdOffset); } return true; } @@ -146,8 +148,9 @@ Return ExternalCameraProviderImpl_2_4::getCameraDeviceInterface_V3_x( const hidl_string& cameraDeviceName, ICameraProvider::getCameraDeviceInterface_V3_x_cb _hidl_cb) { - std::string cameraId, deviceVersion; - bool match = matchDeviceName(cameraDeviceName, &deviceVersion, &cameraId); + std::string cameraDevicePath, deviceVersion; + bool match = matchDeviceName(mCfg.cameraIdOffset, cameraDeviceName, + &deviceVersion, &cameraDevicePath); if (!match) { _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr); return Void(); @@ -164,19 +167,19 @@ Return ExternalCameraProviderImpl_2_4::getCameraDeviceInterface_V3_x( case 4: { ALOGV("Constructing v3.4 external camera device"); deviceImpl = new device::V3_4::implementation::ExternalCameraDevice( - cameraId, mCfg); + cameraDevicePath, mCfg); break; } case 5: { ALOGV("Constructing v3.5 external camera device"); deviceImpl = new device::V3_5::implementation::ExternalCameraDevice( - cameraId, mCfg); + cameraDevicePath, mCfg); break; } case 6: { ALOGV("Constructing v3.6 external camera device"); deviceImpl = new device::V3_6::implementation::ExternalCameraDevice( - cameraId, mCfg); + cameraDevicePath, mCfg); break; } default: @@ -186,7 +189,7 @@ Return ExternalCameraProviderImpl_2_4::getCameraDeviceInterface_V3_x( } if (deviceImpl == nullptr || deviceImpl->isInitFailed()) { - ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str()); + ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraDevicePath.c_str()); _hidl_cb(Status::INTERNAL_ERROR, nullptr); return Void(); } @@ -210,12 +213,14 @@ void ExternalCameraProviderImpl_2_4::addExternalCamera(const char* devName) { ALOGI("ExtCam: adding %s to External Camera HAL!", devName); Mutex::Autolock _l(mLock); std::string deviceName; + std::string cameraId = std::to_string(mCfg.cameraIdOffset + + std::atoi(devName + kDevicePrefixLen)); if (mPreferredHal3MinorVersion == 6) { - deviceName = std::string("device@3.6/external/") + devName; + deviceName = std::string("device@3.6/external/") + cameraId; } else if (mPreferredHal3MinorVersion == 5) { - deviceName = std::string("device@3.5/external/") + devName; + deviceName = std::string("device@3.5/external/") + cameraId; } else { - deviceName = std::string("device@3.4/external/") + devName; + deviceName = std::string("device@3.4/external/") + cameraId; } mCameraStatusMap[deviceName] = CameraDeviceStatus::PRESENT; if (mCallbacks != nullptr) { @@ -259,12 +264,14 @@ void ExternalCameraProviderImpl_2_4::deviceAdded(const char* devName) { void ExternalCameraProviderImpl_2_4::deviceRemoved(const char* devName) { Mutex::Autolock _l(mLock); std::string deviceName; + std::string cameraId = std::to_string(mCfg.cameraIdOffset + + std::atoi(devName + kDevicePrefixLen)); if (mPreferredHal3MinorVersion == 6) { - deviceName = std::string("device@3.6/external/") + devName; + deviceName = std::string("device@3.6/external/") + cameraId; } else if (mPreferredHal3MinorVersion == 5) { - deviceName = std::string("device@3.5/external/") + devName; + deviceName = std::string("device@3.5/external/") + cameraId; } else { - deviceName = std::string("device@3.4/external/") + devName; + deviceName = std::string("device@3.4/external/") + cameraId; } if (mCameraStatusMap.find(deviceName) != mCameraStatusMap.end()) { mCameraStatusMap.erase(deviceName); From f06684acab023197c84ee6ae7886c7335992315d Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Wed, 11 Mar 2020 16:30:18 -0700 Subject: [PATCH 0699/1022] Use a constant-time MAX function Bug: 146520538 Test: atest HadamardTest Change-Id: Ife1012c14d697141e6ee0c583dc32eaacdb72b73 Merged-In: Ife1012c14d697141e6ee0c583dc32eaacdb72b73 (cherry picked from commit b0d2062abebee358ac9d4fa66b8124ec37a916c8) --- rebootescrow/aidl/default/HadamardUtils.cpp | 46 ++++++++++++++------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/rebootescrow/aidl/default/HadamardUtils.cpp b/rebootescrow/aidl/default/HadamardUtils.cpp index d2422b9cd5..adb2010ae6 100644 --- a/rebootescrow/aidl/default/HadamardUtils.cpp +++ b/rebootescrow/aidl/default/HadamardUtils.cpp @@ -16,8 +16,6 @@ #include -#include - #include namespace aidl { @@ -92,6 +90,31 @@ std::vector EncodeKey(const std::vector& input) { return result; } +// Constant-time conditional copy, to fix b/146520538 +// ctl must be 0 or 1; we do the copy if it's 1. +static void CondCopy(uint32_t ctl, void* dest, const void* src, size_t len) { + const auto cdest = reinterpret_cast(dest); + const auto csrc = reinterpret_cast(src); + for (size_t i = 0; i < len; i++) { + const uint32_t d = cdest[i]; + const uint32_t s = csrc[i]; + cdest[i] = d ^ (-ctl & (s ^ d)); + } +} + +struct CodewordWinner { + uint16_t codeword; + int32_t score; +}; + +// Replace dest with src if it has a higher score +static void CopyWinner(CodewordWinner* dest, const CodewordWinner& src) { + // Scores are between - 2^15 and 2^15, so taking the difference won't + // overflow; we use the sign bit of the difference here. + CondCopy(static_cast(dest->score - src.score) >> 31, dest, &src, + sizeof(CodewordWinner)); +} + // Decode a single codeword. Because of the way codewords are striped together // this takes the entire input, plus an offset telling it which word to decode. static uint16_t DecodeWord(size_t word, const std::vector& encoded) { @@ -118,20 +141,15 @@ static uint16_t DecodeWord(size_t word, const std::vector& encoded) { } } } - auto hiscore = std::numeric_limits::min(); - uint16_t winner; - // TODO(b/146520538): this needs to be constant time + // -ENCODE_LENGTH is least possible score, so start one less than that + auto best = CodewordWinner{0, -static_cast(ENCODE_LENGTH + 1)}; + // For every possible codeword value, look at its score, and replace best if it's higher, + // in constant time. for (size_t i = 0; i < ENCODE_LENGTH; i++) { - if (scores[i] > hiscore) { - winner = i; - hiscore = scores[i]; - - } else if (-scores[i] > hiscore) { - winner = i | (1 << CODE_K); - hiscore = -scores[i]; - } + CopyWinner(&best, CodewordWinner{static_cast(i), scores[i]}); + CopyWinner(&best, CodewordWinner{static_cast(i | (1 << CODE_K)), -scores[i]}); } - return winner; + return best.codeword; } std::vector DecodeKey(const std::vector& shuffled) { From 4876af1ba1983bd1b102ba35928051820279faa3 Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Thu, 12 Mar 2020 15:12:23 -0700 Subject: [PATCH 0700/1022] NNAPI VTS: decouple 1.2 tests from 1.3 types Bug: 141718368 Test: mma Test: VtsHalNeuralnetworksV1_*TargetTest Change-Id: Ied7b95e146e4d2d95622642bfbb959cf134b5a7a --- neuralnetworks/1.2/vts/functional/Android.bp | 14 ++++++++------ .../1.2/vts/functional/CompilationCachingTests.cpp | 1 - .../1.2/vts/functional/GeneratedTestHarness.cpp | 3 +-- .../1.2/vts/functional/ValidateBurst.cpp | 6 ++---- .../1.2/vts/functional/ValidateRequest.cpp | 3 +-- .../1.3/vts/functional/ValidateBurst.cpp | 7 ++----- 6 files changed, 14 insertions(+), 20 deletions(-) diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index 31a1a819ee..7c1faeef68 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -28,7 +28,7 @@ cc_library_static { ], header_libs: [ "libbase_headers", - ] + ], } cc_test { @@ -39,9 +39,9 @@ cc_test { "CompilationCachingTests.cpp", "GeneratedTestHarness.cpp", "TestAssertions.cpp", + "ValidateBurst.cpp", "ValidateModel.cpp", "ValidateRequest.cpp", - "ValidateBurst.cpp", "VtsHalNeuralnetworks.cpp", ], local_include_dirs: ["include"], @@ -50,18 +50,17 @@ cc_test { "libnativewindow", ], static_libs: [ + "VtsHalNeuralNetworksV1_0_utils", + "VtsHalNeuralNetworksV1_2Callbacks", "android.hardware.neuralnetworks@1.0", "android.hardware.neuralnetworks@1.1", "android.hardware.neuralnetworks@1.2", - "android.hardware.neuralnetworks@1.3", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "libgmock", "libhidlmemory", "libneuralnetworks_generated_test_harness", "libneuralnetworks_utils", - "VtsHalNeuralNetworksV1_0_utils", - "VtsHalNeuralNetworksV1_2Callbacks", ], whole_static_libs: [ "neuralnetworks_generated_V1_0_example", @@ -71,5 +70,8 @@ cc_test { header_libs: [ "libneuralnetworks_headers", ], - test_suites: ["general-tests", "vts-core"], + test_suites: [ + "general-tests", + "vts-core", + ], } diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp index 10dec791cf..449b8f369d 100644 --- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp @@ -32,7 +32,6 @@ #include "GeneratedTestHarness.h" #include "MemoryUtils.h" #include "TestHarness.h" -#include "Utils.h" #include "VtsHalNeuralnetworks.h" // Forward declaration of the mobilenet generated test models in diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp index 4c8fede8b2..3ab01351e9 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp @@ -43,7 +43,6 @@ #include "ExecutionBurstController.h" #include "MemoryUtils.h" #include "TestHarness.h" -#include "Utils.h" #include "VtsHalNeuralnetworks.h" namespace android::hardware::neuralnetworks::V1_2::vts::functional { @@ -273,7 +272,7 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo int n; std::tie(n, outputShapes, timing, std::ignore) = controller->compute(request, testConfig.measureTiming, keys); - executionStatus = nn::convertToV1_0(nn::convertResultCodeToErrorStatus(n)); + executionStatus = nn::legacyConvertResultCodeToErrorStatus(n); break; } diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp index ec9629bccb..cc9d8048d0 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp @@ -23,7 +23,6 @@ #include "ExecutionBurstServer.h" #include "GeneratedTestHarness.h" #include "TestHarness.h" -#include "Utils.h" #include #include @@ -296,8 +295,7 @@ static void validateBurstFmqLength(const sp& preparedModel, // collect serialized result by running regular burst const auto [nRegular, outputShapesRegular, timingRegular, fallbackRegular] = controllerRegular->compute(request, MeasureTiming::NO, keys); - const ErrorStatus statusRegular = - nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nRegular)); + const ErrorStatus statusRegular = nn::legacyConvertResultCodeToErrorStatus(nRegular); EXPECT_FALSE(fallbackRegular); // skip test if regular burst output isn't useful for testing a failure @@ -313,7 +311,7 @@ static void validateBurstFmqLength(const sp& preparedModel, // large enough to return the serialized result const auto [nSmall, outputShapesSmall, timingSmall, fallbackSmall] = controllerSmall->compute(request, MeasureTiming::NO, keys); - const ErrorStatus statusSmall = nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nSmall)); + const ErrorStatus statusSmall = nn::legacyConvertResultCodeToErrorStatus(nSmall); EXPECT_NE(ErrorStatus::NONE, statusSmall); EXPECT_EQ(0u, outputShapesSmall.size()); EXPECT_TRUE(badTiming(timingSmall)); diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp index 7b5ff9b8e4..8498cb041b 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp @@ -22,7 +22,6 @@ #include "ExecutionBurstController.h" #include "GeneratedTestHarness.h" #include "TestHarness.h" -#include "Utils.h" #include "VtsHalNeuralnetworks.h" namespace android::hardware::neuralnetworks::V1_2::vts::functional { @@ -107,7 +106,7 @@ static void validate(const sp& preparedModel, const std::string& // execute and verify const auto [n, outputShapes, timing, fallback] = burst->compute(request, measure, keys); - const ErrorStatus status = nn::convertToV1_0(nn::convertResultCodeToErrorStatus(n)); + const ErrorStatus status = nn::legacyConvertResultCodeToErrorStatus(n); EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); EXPECT_EQ(outputShapes.size(), 0); EXPECT_TRUE(badTiming(timing)); diff --git a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp index 6ff9dfd3a8..aecb7b79c4 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp @@ -23,7 +23,6 @@ #include "ExecutionBurstServer.h" #include "GeneratedTestHarness.h" #include "TestHarness.h" -#include "Utils.h" #include #include @@ -302,8 +301,7 @@ static void validateBurstFmqLength(const sp& preparedModel, // collect serialized result by running regular burst const auto [nRegular, outputShapesRegular, timingRegular, fallbackRegular] = controllerRegular->compute(request, MeasureTiming::NO, keys); - const V1_0::ErrorStatus statusRegular = - nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nRegular)); + const V1_0::ErrorStatus statusRegular = nn::legacyConvertResultCodeToErrorStatus(nRegular); EXPECT_FALSE(fallbackRegular); // skip test if regular burst output isn't useful for testing a failure @@ -319,8 +317,7 @@ static void validateBurstFmqLength(const sp& preparedModel, // large enough to return the serialized result const auto [nSmall, outputShapesSmall, timingSmall, fallbackSmall] = controllerSmall->compute(request, MeasureTiming::NO, keys); - const V1_0::ErrorStatus statusSmall = - nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nSmall)); + const V1_0::ErrorStatus statusSmall = nn::legacyConvertResultCodeToErrorStatus(nSmall); EXPECT_NE(V1_0::ErrorStatus::NONE, statusSmall); EXPECT_EQ(0u, outputShapesSmall.size()); EXPECT_TRUE(badTiming(timingSmall)); From 5882d6d9116c3de166fb5eb8d8594306f71a1fcc Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Fri, 13 Mar 2020 10:02:36 -0700 Subject: [PATCH 0701/1022] Fix VTS of fenced execution with zero-sized output. Fixes: 151441390 Test: 1.3 VTS Change-Id: I100329e18c34c377d217af155c2abc8e67078778 Merged-In: I100329e18c34c377d217af155c2abc8e67078778 (cherry picked from commit 9fcccf8b85b3ecde96a1b0810a61b2156e083885) --- .../vts/functional/GeneratedTestHarness.cpp | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 83a8d94ba5..aae58bfb3e 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -493,6 +493,13 @@ static std::vector getOutputBuffers(const TestModel& testModel, cons return outputBuffers; } +static bool hasZeroSizedOutput(const TestModel& testModel) { + return std::any_of(testModel.main.outputIndexes.begin(), testModel.main.outputIndexes.end(), + [&testModel](uint32_t index) { + return testModel.main.operands[index].data.size() == 0; + }); +} + static Return ExecutePreparedModel(const sp& preparedModel, const Request& request, MeasureTiming measure, const OptionalTimeoutDuration& loopTimeoutDuration, @@ -689,6 +696,11 @@ void EvaluatePreparedModel(const sp& device, const sp& switch (testConfig.outputType) { case OutputType::FULLY_SPECIFIED: + if (testConfig.executor == Executor::FENCED && hasZeroSizedOutput(testModel)) { + // Executor::FENCED does not support zero-sized output. + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus); + return; + } // If the model output operands are fully specified, outputShapes must be either // either empty, or have the same number of elements as the number of outputs. ASSERT_EQ(ErrorStatus::NONE, executionStatus); @@ -936,13 +948,8 @@ INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, [](const TestModel& testModel INSTANTIATE_GENERATED_TEST(MemoryDomainTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); -INSTANTIATE_GENERATED_TEST(FencedComputeTest, [](const TestModel& testModel) { - return !testModel.expectFailure && - std::all_of(testModel.main.outputIndexes.begin(), testModel.main.outputIndexes.end(), - [&testModel](uint32_t index) { - return testModel.main.operands[index].data.size() > 0; - }); -}); +INSTANTIATE_GENERATED_TEST(FencedComputeTest, + [](const TestModel& testModel) { return !testModel.expectFailure; }); INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) { return testModel.hasQuant8CoupledOperands() && testModel.main.operations.size() == 1; From dbadfe396b07b6fb812f7862be63a57c000c5d20 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Thu, 12 Mar 2020 22:25:56 -0700 Subject: [PATCH 0702/1022] Drop GNSS1.1 and Thermal1.0 These two are added because checkUnusedHals does not check for inheritance. These two HALs are considered deprecated and are dropped from the current matrix. They are dropped from matrix.4.xml too because GnssHalVersionCompatibility and ThermalHalVersionCompatibility ensures devices with target FCM version 4 must implement GNSS2.0 and thermal 2.0. Bug: 131717099 Test: m check-vintf-all Change-Id: I2c7cbf8f51925e55026a9f85382c8a22897eabaa Merged-In: I2c7cbf8f51925e55026a9f85382c8a22897eabaa --- compatibility_matrices/compatibility_matrix.4.xml | 7 ------- compatibility_matrices/compatibility_matrix.current.xml | 7 ------- 2 files changed, 14 deletions(-) diff --git a/compatibility_matrices/compatibility_matrix.4.xml b/compatibility_matrices/compatibility_matrix.4.xml index 01ec172d89..e5e012cbb3 100644 --- a/compatibility_matrices/compatibility_matrix.4.xml +++ b/compatibility_matrices/compatibility_matrix.4.xml @@ -181,12 +181,6 @@ android.hardware.gnss - - 1.1 2.0 IGnss @@ -429,7 +423,6 @@ android.hardware.thermal - 1.0-1 2.0 IThermal diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index de1ee8445c..1861b1cd8d 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -197,12 +197,6 @@ android.hardware.gnss - - 1.1 2.0-1 IGnss @@ -451,7 +445,6 @@ android.hardware.thermal - 1.0 2.0 IThermal From 41adc5bc115d558cecfdb933d8dae7b17f707b20 Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Tue, 25 Feb 2020 11:43:10 -0800 Subject: [PATCH 0703/1022] Add BLOB AHWB tests in VTS. Bug: 149847930 Test: 1.3 VTS Change-Id: I9c795dcb7696c843afd12551927463c5529a4b60 --- .../vts/functional/GeneratedTestHarness.cpp | 6 +- neuralnetworks/1.0/vts/functional/Utils.cpp | 91 ++++++++-- .../vts/functional/VtsHalNeuralnetworks.cpp | 3 +- .../1.0/vts/functional/include/1.0/Utils.h | 72 +++++++- .../vts/functional/GeneratedTestHarness.cpp | 6 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 3 +- .../vts/functional/GeneratedTestHarness.cpp | 20 ++- .../vts/functional/VtsHalNeuralnetworks.cpp | 3 +- .../vts/functional/GeneratedTestHarness.cpp | 164 ++++++++++-------- .../vts/functional/QualityOfServiceTests.cpp | 15 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 3 +- 11 files changed, 275 insertions(+), 111 deletions(-) diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp index e28605dca2..4ab228f85b 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp @@ -125,7 +125,9 @@ Model createModel(const TestModel& testModel) { // Test driver for those generated from ml/nn/runtime/test/spec void Execute(const sp& device, const TestModel& testModel) { const Model model = createModel(testModel); - const Request request = createRequest(testModel); + + ExecutionContext context; + const Request request = context.createRequest(testModel); // Create IPreparedModel. sp preparedModel; @@ -143,7 +145,7 @@ void Execute(const sp& device, const TestModel& testModel) { ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus()); // Retrieve execution results. - const std::vector outputs = getOutputBuffers(request); + const std::vector outputs = context.getOutputBuffers(request); // We want "close-enough" results. checkResults(testModel, outputs); diff --git a/neuralnetworks/1.0/vts/functional/Utils.cpp b/neuralnetworks/1.0/vts/functional/Utils.cpp index 0dba85acd9..3613e69088 100644 --- a/neuralnetworks/1.0/vts/functional/Utils.cpp +++ b/neuralnetworks/1.0/vts/functional/Utils.cpp @@ -21,10 +21,13 @@ #include #include +#include #include #include #include +#include +#include #include #include #include @@ -37,10 +40,64 @@ using V1_0::DataLocation; using V1_0::Request; using V1_0::RequestArgument; -constexpr uint32_t kInputPoolIndex = 0; -constexpr uint32_t kOutputPoolIndex = 1; +std::unique_ptr TestAshmem::create(uint32_t size) { + auto ashmem = std::make_unique(size); + return ashmem->mIsValid ? std::move(ashmem) : nullptr; +} + +void TestAshmem::initialize(uint32_t size) { + mIsValid = false; + ASSERT_GT(size, 0); + mHidlMemory = nn::allocateSharedMemory(size); + ASSERT_TRUE(mHidlMemory.valid()); + mMappedMemory = mapMemory(mHidlMemory); + ASSERT_NE(mMappedMemory, nullptr); + mPtr = static_cast(static_cast(mMappedMemory->getPointer())); + ASSERT_NE(mPtr, nullptr); + mIsValid = true; +} + +std::unique_ptr TestBlobAHWB::create(uint32_t size) { + auto ahwb = std::make_unique(size); + return ahwb->mIsValid ? std::move(ahwb) : nullptr; +} + +void TestBlobAHWB::initialize(uint32_t size) { + mIsValid = false; + ASSERT_GT(size, 0); + const auto usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN; + const AHardwareBuffer_Desc desc = { + .width = size, + .height = 1, + .layers = 1, + .format = AHARDWAREBUFFER_FORMAT_BLOB, + .usage = usage, + .stride = size, + }; + ASSERT_EQ(AHardwareBuffer_allocate(&desc, &mAhwb), 0); + ASSERT_NE(mAhwb, nullptr); + + void* buffer = nullptr; + ASSERT_EQ(AHardwareBuffer_lock(mAhwb, usage, -1, nullptr, &buffer), 0); + ASSERT_NE(buffer, nullptr); + mPtr = static_cast(buffer); + + const native_handle_t* handle = AHardwareBuffer_getNativeHandle(mAhwb); + ASSERT_NE(handle, nullptr); + mHidlMemory = hidl_memory("hardware_buffer_blob", handle, desc.width); + mIsValid = true; +} + +TestBlobAHWB::~TestBlobAHWB() { + if (mAhwb) { + AHardwareBuffer_unlock(mAhwb, nullptr); + AHardwareBuffer_release(mAhwb); + } +} + +Request ExecutionContext::createRequest(const TestModel& testModel, MemoryType memoryType) { + CHECK(memoryType == MemoryType::ASHMEM || memoryType == MemoryType::BLOB_AHWB); -Request createRequest(const TestModel& testModel) { // Model inputs. hidl_vec inputs(testModel.main.inputIndexes.size()); size_t inputSize = 0; @@ -80,16 +137,19 @@ Request createRequest(const TestModel& testModel) { } // Allocate memory pools. - hidl_vec pools = {nn::allocateSharedMemory(inputSize), - nn::allocateSharedMemory(outputSize)}; - CHECK_NE(pools[kInputPoolIndex].size(), 0u); - CHECK_NE(pools[kOutputPoolIndex].size(), 0u); - sp inputMemory = mapMemory(pools[kInputPoolIndex]); - CHECK(inputMemory.get() != nullptr); - uint8_t* inputPtr = static_cast(static_cast(inputMemory->getPointer())); - CHECK(inputPtr != nullptr); + if (memoryType == MemoryType::ASHMEM) { + mInputMemory = TestAshmem::create(inputSize); + mOutputMemory = TestAshmem::create(outputSize); + } else { + mInputMemory = TestBlobAHWB::create(inputSize); + mOutputMemory = TestBlobAHWB::create(outputSize); + } + EXPECT_NE(mInputMemory, nullptr); + EXPECT_NE(mOutputMemory, nullptr); + hidl_vec pools = {mInputMemory->getHidlMemory(), mOutputMemory->getHidlMemory()}; // Copy input data to the memory pool. + uint8_t* inputPtr = mInputMemory->getPointer(); for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) { const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]]; if (op.data.size() > 0) { @@ -102,18 +162,13 @@ Request createRequest(const TestModel& testModel) { return {.inputs = std::move(inputs), .outputs = std::move(outputs), .pools = std::move(pools)}; } -std::vector getOutputBuffers(const Request& request) { - sp outputMemory = mapMemory(request.pools[kOutputPoolIndex]); - CHECK(outputMemory.get() != nullptr); - uint8_t* outputPtr = static_cast(static_cast(outputMemory->getPointer())); - CHECK(outputPtr != nullptr); - +std::vector ExecutionContext::getOutputBuffers(const Request& request) const { // Copy out output results. + uint8_t* outputPtr = mOutputMemory->getPointer(); std::vector outputBuffers; for (const auto& output : request.outputs) { outputBuffers.emplace_back(output.location.length, outputPtr + output.location.offset); } - return outputBuffers; } diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp index cb2225025b..7f7dac056b 100644 --- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp @@ -129,7 +129,8 @@ void validateEverything(const sp& device, const Model& model, const Req TEST_P(ValidationTest, Test) { const Model model = createModel(kTestModel); - const Request request = createRequest(kTestModel); + ExecutionContext context; + const Request request = context.createRequest(kTestModel); ASSERT_FALSE(kTestModel.expectFailure); validateEverything(kDevice, model, request); } diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h index 6d4534cb4e..3292f79b1a 100644 --- a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h +++ b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include #include @@ -28,11 +30,73 @@ namespace android::hardware::neuralnetworks { -// Create HIDL Request from the TestModel struct. -V1_0::Request createRequest(const test_helper::TestModel& testModel); +// Convenience class to manage the lifetime of memory resources. +class TestMemoryBase { + DISALLOW_COPY_AND_ASSIGN(TestMemoryBase); -// After execution, copy out output results from the output memory pool. -std::vector<::test_helper::TestBuffer> getOutputBuffers(const V1_0::Request& request); + public: + TestMemoryBase() = default; + virtual ~TestMemoryBase() = default; + uint8_t* getPointer() const { return mPtr; } + hidl_memory getHidlMemory() const { return mHidlMemory; } + + protected: + uint8_t* mPtr = nullptr; + hidl_memory mHidlMemory; + bool mIsValid = false; +}; + +class TestAshmem : public TestMemoryBase { + public: + static std::unique_ptr create(uint32_t size); + + // Prefer TestAshmem::create. + // The constructor calls initialize, which constructs the memory resources. This is a workaround + // that gtest macros cannot be used directly in a constructor. + TestAshmem(uint32_t size) { initialize(size); } + + private: + void initialize(uint32_t size); + sp mMappedMemory; +}; + +class TestBlobAHWB : public TestMemoryBase { + public: + static std::unique_ptr create(uint32_t size); + + // Prefer TestBlobAHWB::create. + // The constructor calls initialize, which constructs the memory resources. This is a + // workaround that gtest macros cannot be used directly in a constructor. + TestBlobAHWB(uint32_t size) { initialize(size); } + ~TestBlobAHWB(); + + private: + void initialize(uint32_t size); + AHardwareBuffer* mAhwb = nullptr; +}; + +enum class MemoryType { ASHMEM, BLOB_AHWB, DEVICE }; + +// Manages the lifetime of memory resources used in an execution. +class ExecutionContext { + DISALLOW_COPY_AND_ASSIGN(ExecutionContext); + + public: + static constexpr uint32_t kInputPoolIndex = 0; + static constexpr uint32_t kOutputPoolIndex = 1; + + ExecutionContext() = default; + + // Create HIDL Request from the TestModel struct. + V1_0::Request createRequest(const test_helper::TestModel& testModel, + MemoryType memoryType = MemoryType::ASHMEM); + + // After execution, copy out output results from the output memory pool. + std::vector getOutputBuffers(const V1_0::Request& request) const; + + private: + std::unique_ptr mInputMemory, mOutputMemory; +}; // Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation, // so this is efficiently accomplished by moving the element to the end and diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp index cee15a35a1..14d300db71 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp @@ -133,7 +133,9 @@ Model createModel(const TestModel& testModel) { // Test driver for those generated from ml/nn/runtime/test/spec void Execute(const sp& device, const TestModel& testModel) { const Model model = createModel(testModel); - const Request request = createRequest(testModel); + + ExecutionContext context; + const Request request = context.createRequest(testModel); // Create IPreparedModel. sp preparedModel; @@ -151,7 +153,7 @@ void Execute(const sp& device, const TestModel& testModel) { ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus()); // Retrieve execution results. - const std::vector outputs = getOutputBuffers(request); + const std::vector outputs = context.getOutputBuffers(request); // We want "close-enough" results. checkResults(testModel, outputs); diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp index d56d40b2ba..04af6ec704 100644 --- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp @@ -132,7 +132,8 @@ void validateEverything(const sp& device, const Model& model, const Req TEST_P(ValidationTest, Test) { const Model model = createModel(kTestModel); - const Request request = createRequest(kTestModel); + ExecutionContext context; + const Request request = context.createRequest(kTestModel); ASSERT_FALSE(kTestModel.expectFailure); validateEverything(kDevice, model, request); } diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp index 3ab01351e9..aaaafc7b72 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp @@ -68,6 +68,7 @@ struct TestConfig { Executor executor; MeasureTiming measureTiming; OutputType outputType; + MemoryType memoryType; }; } // namespace @@ -216,7 +217,8 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo return; } - Request request = createRequest(testModel); + ExecutionContext context; + Request request = context.createRequest(testModel, testConfig.memoryType); if (testConfig.outputType == OutputType::INSUFFICIENT) { makeOutputInsufficientSize(/*outputIndex=*/0, &request); } @@ -326,7 +328,7 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo } // Retrieve execution results. - const std::vector outputs = getOutputBuffers(request); + const std::vector outputs = context.getOutputBuffers(request); // We want "close-enough" results. checkResults(testModel, outputs); @@ -337,24 +339,30 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo std::vector outputTypesList; std::vector measureTimingList; std::vector executorList; + std::vector memoryTypeList; if (testDynamicOutputShape) { outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT}; measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; + memoryTypeList = {MemoryType::ASHMEM}; } else { outputTypesList = {OutputType::FULLY_SPECIFIED}; measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; + memoryTypeList = {MemoryType::ASHMEM, MemoryType::BLOB_AHWB}; } for (const OutputType outputType : outputTypesList) { for (const MeasureTiming measureTiming : measureTimingList) { for (const Executor executor : executorList) { - const TestConfig testConfig = {.executor = executor, - .measureTiming = measureTiming, - .outputType = outputType}; - EvaluatePreparedModel(preparedModel, testModel, testConfig); + for (const MemoryType memoryType : memoryTypeList) { + const TestConfig testConfig = {.executor = executor, + .measureTiming = measureTiming, + .outputType = outputType, + .memoryType = memoryType}; + EvaluatePreparedModel(preparedModel, testModel, testConfig); + } } } } diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp index 4fbd0e270f..5853fa49f6 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp @@ -153,7 +153,8 @@ void validateFailure(const sp& device, const Model& model, const Reques TEST_P(ValidationTest, Test) { const Model model = createModel(kTestModel); - const Request request = createRequest(kTestModel); + ExecutionContext context; + const Request request = context.createRequest(kTestModel); if (kTestModel.expectFailure) { validateFailure(kDevice, model, request); } else { diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index aae58bfb3e..45e0f827c0 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -76,8 +76,6 @@ enum class Executor { ASYNC, SYNC, BURST, FENCED }; enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT, MISSED_DEADLINE }; -enum class MemoryType { SHARED, DEVICE }; - enum class IOType { INPUT, OUTPUT }; static void waitForSyncFence(int syncFd) { @@ -338,21 +336,39 @@ static void makeOutputDimensionsUnspecified(Model* model) { } } -constexpr uint32_t kInputPoolIndex = 0; -constexpr uint32_t kOutputPoolIndex = 1; -constexpr uint32_t kDeviceMemoryBeginIndex = 2; +class ExecutionContextV1_3 { + public: + ExecutionContextV1_3(sp device, sp preparedModel) + : kDevice(std::move(device)), kPreparedModel(std::move(preparedModel)) {} -static std::pair>> createRequest( - const sp& device, const sp& preparedModel, - const TestModel& testModel, bool preferDeviceMemory) { + std::optional createRequest(const TestModel& testModel, MemoryType memoryType); + std::vector getOutputBuffers(const TestModel& testModel, + const Request& request) const; + + private: + // Get a TestBuffer with data copied from an IBuffer object. + void getBuffer(const sp& buffer, size_t size, TestBuffer* testBuffer) const; + + static constexpr uint32_t kInputPoolIndex = 0; + static constexpr uint32_t kOutputPoolIndex = 1; + static constexpr uint32_t kDeviceMemoryBeginIndex = 2; + + const sp kDevice; + const sp kPreparedModel; + std::unique_ptr mInputMemory, mOutputMemory; + std::vector> mBuffers; +}; + +std::optional ExecutionContextV1_3::createRequest(const TestModel& testModel, + MemoryType memoryType) { // Memory pools are organized as: // - 0: Input shared memory pool // - 1: Output shared memory pool // - [2, 2+i): Input device memories // - [2+i, 2+i+o): Output device memories - DeviceMemoryAllocator allocator(device, preparedModel, testModel); - std::vector> buffers; + DeviceMemoryAllocator allocator(kDevice, kPreparedModel, testModel); std::vector tokens; + mBuffers.clear(); // Model inputs. hidl_vec inputs(testModel.main.inputIndexes.size()); @@ -363,13 +379,13 @@ static std::pair>> createRequest( // Omitted input. inputs[i] = {.hasNoValue = true}; continue; - } else if (preferDeviceMemory) { + } else if (memoryType == MemoryType::DEVICE) { SCOPED_TRACE("Input index = " + std::to_string(i)); auto [buffer, token] = allocator.allocate(i); if (buffer != nullptr) { - DataLocation loc = {.poolIndex = static_cast(buffers.size() + + DataLocation loc = {.poolIndex = static_cast(mBuffers.size() + kDeviceMemoryBeginIndex)}; - buffers.push_back(std::move(buffer)); + mBuffers.push_back(std::move(buffer)); tokens.push_back(token); inputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}}; continue; @@ -389,13 +405,13 @@ static std::pair>> createRequest( size_t outputSize = 0; for (uint32_t i = 0; i < testModel.main.outputIndexes.size(); i++) { const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]]; - if (preferDeviceMemory) { + if (memoryType == MemoryType::DEVICE) { SCOPED_TRACE("Output index = " + std::to_string(i)); auto [buffer, token] = allocator.allocate(i); if (buffer != nullptr) { - DataLocation loc = {.poolIndex = static_cast(buffers.size() + + DataLocation loc = {.poolIndex = static_cast(mBuffers.size() + kDeviceMemoryBeginIndex)}; - buffers.push_back(std::move(buffer)); + mBuffers.push_back(std::move(buffer)); tokens.push_back(token); outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}}; continue; @@ -418,21 +434,29 @@ static std::pair>> createRequest( outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}}; } + if (memoryType == MemoryType::DEVICE && mBuffers.empty()) { + return std::nullopt; + } + // Memory pools. - hidl_vec pools(kDeviceMemoryBeginIndex + buffers.size()); - pools[kInputPoolIndex].hidlMemory(nn::allocateSharedMemory(std::max(inputSize, 1))); - pools[kOutputPoolIndex].hidlMemory(nn::allocateSharedMemory(std::max(outputSize, 1))); - CHECK_NE(pools[kInputPoolIndex].hidlMemory().size(), 0u); - CHECK_NE(pools[kOutputPoolIndex].hidlMemory().size(), 0u); - for (uint32_t i = 0; i < buffers.size(); i++) { + hidl_vec pools(kDeviceMemoryBeginIndex + mBuffers.size()); + if (memoryType == MemoryType::BLOB_AHWB) { + mInputMemory = TestBlobAHWB::create(std::max(inputSize, 1)); + mOutputMemory = TestBlobAHWB::create(std::max(outputSize, 1)); + } else { + mInputMemory = TestAshmem::create(std::max(inputSize, 1)); + mOutputMemory = TestAshmem::create(std::max(outputSize, 1)); + } + EXPECT_NE(mInputMemory, nullptr); + EXPECT_NE(mOutputMemory, nullptr); + pools[kInputPoolIndex].hidlMemory(mInputMemory->getHidlMemory()); + pools[kOutputPoolIndex].hidlMemory(mOutputMemory->getHidlMemory()); + for (uint32_t i = 0; i < mBuffers.size(); i++) { pools[kDeviceMemoryBeginIndex + i].token(tokens[i]); } // Copy input data to the input shared memory pool. - sp inputMemory = mapMemory(pools[kInputPoolIndex].hidlMemory()); - CHECK(inputMemory.get() != nullptr); - uint8_t* inputPtr = static_cast(static_cast(inputMemory->getPointer())); - CHECK(inputPtr != nullptr); + uint8_t* inputPtr = mInputMemory->getPointer(); for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) { if (!inputs[i].hasNoValue && inputs[i].location.poolIndex == kInputPoolIndex) { const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]]; @@ -441,14 +465,38 @@ static std::pair>> createRequest( std::copy(begin, end, inputPtr + inputs[i].location.offset); } } - - Request request = { + return Request{ .inputs = std::move(inputs), .outputs = std::move(outputs), .pools = std::move(pools)}; - return {std::move(request), std::move(buffers)}; +} + +std::vector ExecutionContextV1_3::getOutputBuffers(const TestModel& testModel, + const Request& request) const { + // Copy out output results. + uint8_t* outputPtr = mOutputMemory->getPointer(); + std::vector outputBuffers; + for (uint32_t i = 0; i < request.outputs.size(); i++) { + const auto& outputLoc = request.outputs[i].location; + if (outputLoc.poolIndex == kOutputPoolIndex) { + outputBuffers.emplace_back(outputLoc.length, outputPtr + outputLoc.offset); + } else { + const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]]; + if (op.data.size() == 0) { + outputBuffers.emplace_back(0, nullptr); + } else { + SCOPED_TRACE("Output index = " + std::to_string(i)); + const uint32_t bufferIndex = outputLoc.poolIndex - kDeviceMemoryBeginIndex; + TestBuffer buffer; + getBuffer(mBuffers[bufferIndex], op.data.size(), &buffer); + outputBuffers.push_back(std::move(buffer)); + } + } + } + return outputBuffers; } // Get a TestBuffer with data copied from an IBuffer object. -static void getBuffer(const sp& buffer, size_t size, TestBuffer* testBuffer) { +void ExecutionContextV1_3::getBuffer(const sp& buffer, size_t size, + TestBuffer* testBuffer) const { // IBuffer -> Shared memory. hidl_memory tmp = nn::allocateSharedMemory(size); const auto ret = buffer->copyTo(tmp); @@ -464,35 +512,6 @@ static void getBuffer(const sp& buffer, size_t size, TestBuffer* testBu *testBuffer = TestBuffer(size, outputPtr); } -static std::vector getOutputBuffers(const TestModel& testModel, const Request& request, - const std::vector>& buffers) { - sp outputMemory = mapMemory(request.pools[kOutputPoolIndex].hidlMemory()); - CHECK(outputMemory.get() != nullptr); - uint8_t* outputPtr = static_cast(static_cast(outputMemory->getPointer())); - CHECK(outputPtr != nullptr); - - // Copy out output results. - std::vector outputBuffers; - for (uint32_t i = 0; i < request.outputs.size(); i++) { - const auto& outputLoc = request.outputs[i].location; - if (outputLoc.poolIndex == kOutputPoolIndex) { - outputBuffers.emplace_back(outputLoc.length, outputPtr + outputLoc.offset); - } else { - const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]]; - if (op.data.size() == 0) { - outputBuffers.emplace_back(); - } else { - SCOPED_TRACE("Output index = " + std::to_string(i)); - const uint32_t bufferIndex = outputLoc.poolIndex - kDeviceMemoryBeginIndex; - TestBuffer buffer; - getBuffer(buffers[bufferIndex], op.data.size(), &buffer); - outputBuffers.push_back(std::move(buffer)); - } - } - } - return outputBuffers; -} - static bool hasZeroSizedOutput(const TestModel& testModel) { return std::any_of(testModel.main.outputIndexes.begin(), testModel.main.outputIndexes.end(), [&testModel](uint32_t index) { @@ -543,13 +562,14 @@ void EvaluatePreparedModel(const sp& device, const sp& return; } - auto [request, buffers] = - createRequest(device, preparedModel, testModel, - /*preferDeviceMemory=*/testConfig.memoryType == MemoryType::DEVICE); + ExecutionContextV1_3 context(device, preparedModel); + auto maybeRequest = context.createRequest(testModel, testConfig.memoryType); // Skip if testing memory domain but no device memory has been allocated. - if (testConfig.memoryType == MemoryType::DEVICE && buffers.empty()) { + if (!maybeRequest.has_value()) { return; } + + Request request = std::move(maybeRequest.value()); if (testConfig.outputType == OutputType::INSUFFICIENT) { makeOutputInsufficientSize(/*outputIndex=*/0, &request); } @@ -744,7 +764,7 @@ void EvaluatePreparedModel(const sp& device, const sp& } // Retrieve execution results. - const std::vector outputs = getOutputBuffers(testModel, request, buffers); + const std::vector outputs = context.getOutputBuffers(testModel, request); // We want "close-enough" results. checkResults(testModel, outputs); @@ -755,29 +775,32 @@ void EvaluatePreparedModel(const sp& device, const sp& std::vector outputTypesList; std::vector measureTimingList; std::vector executorList; - MemoryType memoryType = MemoryType::SHARED; + std::vector memoryTypeList; switch (testKind) { case TestKind::GENERAL: { outputTypesList = {OutputType::FULLY_SPECIFIED}; measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; + memoryTypeList = {MemoryType::ASHMEM}; } break; case TestKind::DYNAMIC_SHAPE: { outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT}; measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST, Executor::FENCED}; + memoryTypeList = {MemoryType::ASHMEM}; } break; case TestKind::MEMORY_DOMAIN: { outputTypesList = {OutputType::FULLY_SPECIFIED}; measureTimingList = {MeasureTiming::NO}; executorList = {Executor::ASYNC, Executor::SYNC, Executor::FENCED}; - memoryType = MemoryType::DEVICE; + memoryTypeList = {MemoryType::BLOB_AHWB, MemoryType::DEVICE}; } break; case TestKind::FENCED_COMPUTE: { outputTypesList = {OutputType::FULLY_SPECIFIED}; measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; executorList = {Executor::FENCED}; + memoryTypeList = {MemoryType::ASHMEM}; } break; case TestKind::QUANTIZATION_COUPLING: { LOG(FATAL) << "Wrong TestKind for EvaluatePreparedModel"; @@ -788,14 +811,17 @@ void EvaluatePreparedModel(const sp& device, const sp& measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; // Burst does not support V1_3 loop timeout. executorList = {Executor::ASYNC, Executor::SYNC, Executor::FENCED}; + memoryTypeList = {MemoryType::ASHMEM}; } break; } for (const OutputType outputType : outputTypesList) { for (const MeasureTiming measureTiming : measureTimingList) { for (const Executor executor : executorList) { - const TestConfig testConfig(executor, measureTiming, outputType, memoryType); - EvaluatePreparedModel(device, preparedModel, testModel, testConfig); + for (const MemoryType memoryType : memoryTypeList) { + const TestConfig testConfig(executor, measureTiming, outputType, memoryType); + EvaluatePreparedModel(device, preparedModel, testModel, testConfig); + } } } } @@ -814,7 +840,7 @@ void EvaluatePreparedCoupledModels(const sp& device, for (const OutputType outputType : outputTypesList) { for (const MeasureTiming measureTiming : measureTimingList) { for (const Executor executor : executorList) { - const TestConfig testConfig(executor, measureTiming, outputType, MemoryType::SHARED, + const TestConfig testConfig(executor, measureTiming, outputType, MemoryType::ASHMEM, /*reportSkipping=*/false); bool baseSkipped = false; EvaluatePreparedModel(device, preparedModel, testModel, testConfig, &baseSkipped); diff --git a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp index 879989ea2a..2ef1e8f6bd 100644 --- a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp +++ b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp @@ -214,7 +214,8 @@ static MaybeResults executeSynchronously(const sp& preparedModel } void runExecutionTest(const sp& preparedModel, const TestModel& testModel, - const Request& request, bool synchronous, DeadlineBoundType deadlineBound) { + const Request& request, const ExecutionContext& context, bool synchronous, + DeadlineBoundType deadlineBound) { const ExecutionFunction execute = synchronous ? executeSynchronously : executeAsynchronously; const auto deadline = makeDeadline(deadlineBound); @@ -261,7 +262,7 @@ void runExecutionTest(const sp& preparedModel, const TestModel& // Retrieve execution results. ASSERT_TRUE(nn::compliantWithV1_0(request)); const V1_0::Request request10 = nn::convertToV1_0(request); - const std::vector outputs = getOutputBuffers(request10); + const std::vector outputs = context.getOutputBuffers(request10); // We want "close-enough" results. if (status == ErrorStatus::NONE) { @@ -270,10 +271,11 @@ void runExecutionTest(const sp& preparedModel, const TestModel& } void runExecutionTests(const sp& preparedModel, const TestModel& testModel, - const Request& request) { + const Request& request, const ExecutionContext& context) { for (bool synchronous : {false, true}) { for (auto deadlineBound : deadlineBounds) { - runExecutionTest(preparedModel, testModel, request, synchronous, deadlineBound); + runExecutionTest(preparedModel, testModel, request, context, synchronous, + deadlineBound); } } } @@ -291,8 +293,9 @@ void runTests(const sp& device, const TestModel& testModel) { if (preparedModel == nullptr) return; // run execution tests - const Request request = nn::convertToV1_3(createRequest(testModel)); - runExecutionTests(preparedModel, testModel, request); + ExecutionContext context; + const Request request = nn::convertToV1_3(context.createRequest(testModel)); + runExecutionTests(preparedModel, testModel, request, context); } class DeadlineTest : public GeneratedTestBase {}; diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index 5b07034296..703a2f5345 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -177,7 +177,8 @@ void validateFailure(const sp& device, const Model& model, const Reques TEST_P(ValidationTest, Test) { const Model model = createModel(kTestModel); - const Request request = nn::convertToV1_3(createRequest(kTestModel)); + ExecutionContext context; + const Request request = nn::convertToV1_3(context.createRequest(kTestModel)); if (kTestModel.expectFailure) { validateFailure(kDevice, model, request); } else { From 43cc37d88f4d29ca2565ba2e6bbabb815461fde0 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Fri, 13 Mar 2020 14:49:54 -0700 Subject: [PATCH 0704/1022] Add identity HAL to current matrix. Test: m check-vintf-all Bug: 131717099 Change-Id: I91c68af8c8456105f35ee701ed9f08135e56e6f5 Merged-In: I91c68af8c8456105f35ee701ed9f08135e56e6f5 --- compatibility_matrices/compatibility_matrix.current.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index de1ee8445c..3efdb3f165 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -255,6 +255,13 @@ default + + android.hardware.identity + + IIdentityCredentialStore + default + + android.hardware.ir 1.0 From 0e781cf922acb1a43a5d08851475d8128649acb2 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Fri, 13 Mar 2020 19:09:03 -0700 Subject: [PATCH 0705/1022] Add automotive.can to current matrix. ICanBus/.* ICanController/.* Bug: 131717099 Test: pass Change-Id: Id9fe289af7e45752eddb45d07deac6352e4710fb --- .../compatibility_matrix.current.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index de1ee8445c..1ff17467c4 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -39,6 +39,18 @@ default + + android.hardware.automotive.can + 1.0 + + ICanBus + .* + + + ICanController + .* + + android.hardware.automotive.evs 1.0 From 962fdb26ca3f7fea5ea66a8368965f87aa87e8ee Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Mon, 16 Mar 2020 17:13:41 -0700 Subject: [PATCH 0706/1022] Exclude invalid test models from QuantizationCouplingTest. Bug: 151674996 Test: 1.3 VTS Change-Id: I381eb6d39926054279f1791bd71d28a963acc0b9 --- neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index aae58bfb3e..5689a39e1b 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -952,7 +952,8 @@ INSTANTIATE_GENERATED_TEST(FencedComputeTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) { - return testModel.hasQuant8CoupledOperands() && testModel.main.operations.size() == 1; + return !testModel.expectFailure && testModel.hasQuant8CoupledOperands() && + testModel.main.operations.size() == 1; }); INSTANTIATE_GENERATED_TEST(InfiniteLoopTimeoutTest, [](const TestModel& testModel) { From 6668eab9dc850e53fecd6fe3d93d44b53fbd0fa3 Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Tue, 3 Mar 2020 15:23:50 -0800 Subject: [PATCH 0707/1022] Update inter-signal bias (HAL) - Rename recieverInterSignalBiasNs into interSignalBiasNs, which refers to the sum of receiver ISB and satellite ISB. Bug: 150724332 Test: atest VtsHalGnssV2_1TargetTest Change-Id: Ifae15cb482bc12e793a481fec7847c817ef3c34d --- current.txt | 2 +- gnss/2.1/IGnssMeasurementCallback.hal | 64 ++++++++++++------- .../vts/functional/gnss_hal_test_cases.cpp | 11 ++-- gnss/common/utils/default/Utils.cpp | 8 +-- 4 files changed, 50 insertions(+), 35 deletions(-) diff --git a/current.txt b/current.txt index d8f9c08708..c9cba7090b 100644 --- a/current.txt +++ b/current.txt @@ -660,7 +660,7 @@ ba5ac712b2a656dc07c83ab4a7a2c2f3bee1bbcb752e8b8ffa9b672f3b5b0728 android.hardwar 3541d83adfeac16ee3e45d183a58dffe06012ccb5aa5bcd2e4f6eeae269f69cd android.hardware.gnss@2.1::IGnssCallback 737d750017738f0753d13ba01a3310e0161f294b8ae80b3fd63eaa227e9d9c66 android.hardware.gnss@2.1::IGnssConfiguration 7913a11206a577b12ade86a7cf3f95c2639cb514d086673f279bf99238c9917e android.hardware.gnss@2.1::IGnssMeasurement -0a16e5913e94d995cfcf959a1c6f10b0b8e9dfdb5f45ac6e7244711ddd740272 android.hardware.gnss@2.1::IGnssMeasurementCallback +df52e2c39ed701a355b5e0fdbf83fe5fa7d04bfecd715116b39373d46dc3c682 android.hardware.gnss@2.1::IGnssMeasurementCallback 6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections 956c1576ca0d6f11b42980ef59052062836b6763fe973af6cb709da50787f710 android.hardware.gnss.measurement_corrections@1.1::types ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth diff --git a/gnss/2.1/IGnssMeasurementCallback.hal b/gnss/2.1/IGnssMeasurementCallback.hal index 0e6abbd5e5..60a542330d 100644 --- a/gnss/2.1/IGnssMeasurementCallback.hal +++ b/gnss/2.1/IGnssMeasurementCallback.hal @@ -30,13 +30,13 @@ interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback { */ enum GnssMeasurementFlags : @1.0::IGnssMeasurementCallback.GnssMeasurementFlags { /** - * A valid receiver inter-signal bias is stored in the data structure. + * A valid full inter-signal bias is stored in the data structure. */ - HAS_RECEIVER_ISB = 1 << 16, + HAS_FULL_ISB = 1 << 16, /** - * A valid receiver inter-signal bias uncertainty is stored in the data structure. + * A valid full inter-signal bias uncertainty is stored in the data structure. */ - HAS_RECEIVER_ISB_UNCERTAINTY = 1 << 17, + HAS_FULL_ISB_UNCERTAINTY = 1 << 17, /** * A valid satellite inter-signal bias is stored in the data structure. */ @@ -77,42 +77,58 @@ interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback { bitfield flags; /** - * The receiver inter-signal bias (ISB) in nanoseconds. + * The full inter-signal bias (ISB) in nanoseconds. * - * This value is the estimated receiver-side inter-system (different from the constellation - * in GnssClock.referenceSignalTypeForIsb) bias and inter-frequency (different from the - * carrier frequency in GnssClock.referenceSignalTypeForIsb) bias. The reported receiver ISB - * must include signal delays caused by + * This value is the sum of the estimated receiver-side and the space-segment-side + * inter-system bias, inter-frequency bias and inter-code bias, including * - * - Receiver inter-constellation bias - * - Receiver inter-frequency bias - * - Receiver inter-code bias + * - Receiver inter-constellation bias (with respect to the constellation in + * GnssClock.referenceSignalTypeForIsb) + * - Receiver inter-frequency bias (with respect to the carrier frequency in + * GnssClock.referenceSignalTypeForIsb) + * - Receiver inter-code bias (with respect to the code type in + * GnssClock.referenceSignalTypeForIsb) + * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPS-UTC Time Offset + * (TauGps), BDS-GLO Time Offset (BGTO)) (with respect to the constellation in + * GnssClock.referenceSignalTypeForIsb) + * - Group delay (e.g., Total Group Delay (TGD)) + * - Satellite inter-frequency bias (GLO only) (with respect to the carrier frequency in + * GnssClock.referenceSignalTypeForIsb) + * - Satellite inter-code bias (e.g., Differential Code Bias (DCB)) (with respect to the + * code type in GnssClock.referenceSignalTypeForIsb) + * + * If a component of the above is already compensated in the provided + * GnssMeasurement.receivedSvTimeInNs, then it must not be included in the reported full + * ISB. * * The value does not include the inter-frequency Ionospheric bias. * - * The receiver ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds. + * The full ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds. */ - double receiverInterSignalBiasNs; + double fullInterSignalBiasNs; /** - * 1-sigma uncertainty associated with the receiver inter-signal bias in nanoseconds. + * 1-sigma uncertainty associated with the full inter-signal bias in nanoseconds. */ - double receiverInterSignalBiasUncertaintyNs; + double fullInterSignalBiasUncertaintyNs; /** * The satellite inter-signal bias in nanoseconds. * - * This value is the satellite-and-control-segment-side inter-system (different from the - * constellation in GnssClock.referenceSignalTypeForIsb) bias and inter-frequency (different - * from the carrier frequency in GnssClock.referenceSignalTypeForIsb) bias, including: + * This value is the sum of the space-segment-side inter-system bias, inter-frequency bias + * and inter-code bias, including * - * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPT-UTC Time Offset (TauGps), - * BDS-GLO Time Offset (BGTO)) + * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPS-UTC Time Offset + * (TauGps), BDS-GLO Time Offset (BGTO)) (with respect to the constellation in + * GnssClock.referenceSignalTypeForIsb) * - Group delay (e.g., Total Group Delay (TGD)) - * - Satellite inter-signal bias, which includes satellite inter-frequency bias (GLO only), - * and satellite inter-code bias (e.g., Differential Code Bias (DCB)). + * - Satellite inter-frequency bias (GLO only) (with respect to the carrier frequency in + * GnssClock.referenceSignalTypeForIsb) + * - Satellite inter-code bias (e.g., Differential Code Bias (DCB)) (with respect to the + * code type in GnssClock.referenceSignalTypeForIsb) * - * The receiver ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds. + * The satellite ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 + * nanoseconds. */ double satelliteInterSignalBiasNs; diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp index 7b054c0033..33feb5e5f0 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp @@ -98,7 +98,7 @@ TEST_P(GnssHalTest, TestGnssConfigurationExtension) { * TestGnssMeasurementFields: * Sets a GnssMeasurementCallback, waits for a measurement, and verifies * 1. basebandCN0DbHz is valid - * 2. ISB fields are valid if HAS_INTER_SIGNAL_BIAS is true. + * 2. ISB fields are valid */ TEST_P(GnssHalTest, TestGnssMeasurementFields) { const int kFirstGnssMeasurementTimeoutSeconds = 10; @@ -126,9 +126,8 @@ TEST_P(GnssHalTest, TestGnssMeasurementFields) { // Verify basebandCn0DbHz is valid. ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0); - if (((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_RECEIVER_ISB) > 0) && - ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_RECEIVER_ISB_UNCERTAINTY) > - 0) && + if (((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_FULL_ISB) > 0) && + ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_FULL_ISB_UNCERTAINTY) > 0) && ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_SATELLITE_ISB) > 0) && ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_SATELLITE_ISB_UNCERTAINTY) > 0)) { @@ -143,8 +142,8 @@ TEST_P(GnssHalTest, TestGnssMeasurementFields) { ASSERT_TRUE(carrierFrequencyHz > 0); ASSERT_TRUE(codeType != ""); - ASSERT_TRUE(std::abs(measurement.receiverInterSignalBiasNs) < 1.0e6); - ASSERT_TRUE(measurement.receiverInterSignalBiasUncertaintyNs >= 0); + ASSERT_TRUE(std::abs(measurement.fullInterSignalBiasNs) < 1.0e6); + ASSERT_TRUE(measurement.fullInterSignalBiasUncertaintyNs >= 0); ASSERT_TRUE(std::abs(measurement.satelliteInterSignalBiasNs) < 1.0e6); ASSERT_TRUE(measurement.satelliteInterSignalBiasUncertaintyNs >= 0); } diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp index 2e5b87330f..386090e486 100644 --- a/gnss/common/utils/default/Utils.cpp +++ b/gnss/common/utils/default/Utils.cpp @@ -39,12 +39,12 @@ GnssDataV2_1 Utils::getMockMeasurementV2_1() { .v2_0 = gnssDataV2_0.measurements[0], .flags = (uint32_t)(GnssMeasurementFlagsV2_1::HAS_CARRIER_FREQUENCY | GnssMeasurementFlagsV2_1::HAS_CARRIER_PHASE | - GnssMeasurementFlagsV2_1::HAS_RECEIVER_ISB | - GnssMeasurementFlagsV2_1::HAS_RECEIVER_ISB_UNCERTAINTY | + GnssMeasurementFlagsV2_1::HAS_FULL_ISB | + GnssMeasurementFlagsV2_1::HAS_FULL_ISB_UNCERTAINTY | GnssMeasurementFlagsV2_1::HAS_SATELLITE_ISB | GnssMeasurementFlagsV2_1::HAS_SATELLITE_ISB_UNCERTAINTY), - .receiverInterSignalBiasNs = 10.0, - .receiverInterSignalBiasUncertaintyNs = 100.0, + .fullInterSignalBiasNs = 30.0, + .fullInterSignalBiasUncertaintyNs = 250.0, .satelliteInterSignalBiasNs = 20.0, .satelliteInterSignalBiasUncertaintyNs = 150.0, .basebandCN0DbHz = 25.0, From 47a9378d4decf802a1715653f1aef8b8a97d5aa5 Mon Sep 17 00:00:00 2001 From: Kai Date: Wed, 26 Feb 2020 13:00:16 -0800 Subject: [PATCH 0708/1022] Add timestamp for continuously property. Bug: 148960132 Test: 1. apply google vhal to device 2. atest CtsCarTestCases:CarPropertyManagerTest Change-Id: Ib6690b5e242287958017c87632f56a546d418674 --- .../vehicle/2.0/default/common/src/VehiclePropertyStore.cpp | 2 ++ .../2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp index 24b777c75f..6087bfa526 100644 --- a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp +++ b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp @@ -58,6 +58,8 @@ bool VehiclePropertyStore::writeValue(const VehiclePropValue& propValue, return false; } // update the propertyValue. + // The timestamp in propertyStore should only be updated by the server side. It indicates + // the time when the event is generated by the server. valueToUpdate->timestamp = propValue.timestamp; valueToUpdate->value = propValue.value; if (updateStatus) { 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 692c7f791f..7ffa8bad08 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 @@ -127,7 +127,9 @@ VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get( *outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG; break; } - + if (v.get()) { + v->timestamp = elapsedRealtimeNano(); + } return v; } @@ -284,6 +286,7 @@ void EmulatedVehicleHal::onContinuousPropertyTimer(const std::vector& p } if (v.get()) { + v->timestamp = elapsedRealtimeNano(); doHalEvent(std::move(v)); } } From 11a113a67e87a8da9a9bf0a73883f2325de90934 Mon Sep 17 00:00:00 2001 From: Sundong Ahn Date: Fri, 13 Mar 2020 17:51:26 +0900 Subject: [PATCH 0709/1022] Add disable_configstore The disable_configstore is added to disable configstore when API level is less than or equal to 29. Bug: 150761042 Test: Add disable_configstore to PRODUCT_PACKAGES && build && check configstore service Change-Id: Iac01bb375a5c4080c0e110213c64041ea823ed68 Merged-In: Iac01bb375a5c4080c0e110213c64041ea823ed68 (cherry picked from commit d864334675e83a75c0343510cff3fc90ffb14c51) --- configstore/1.1/default/Android.mk | 11 +++++++++++ .../1.1/default/disable_configstore.cpp | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 configstore/1.1/default/disable_configstore.cpp diff --git a/configstore/1.1/default/Android.mk b/configstore/1.1/default/Android.mk index e7edc34150..6b7bb004e3 100644 --- a/configstore/1.1/default/Android.mk +++ b/configstore/1.1/default/Android.mk @@ -35,3 +35,14 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/seccomp_policy LOCAL_SRC_FILES := seccomp_policy/configstore@1.1-$(TARGET_ARCH).policy include $(BUILD_PREBUILT) endif + +# disable configstore +include $(CLEAR_VARS) +LOCAL_MODULE := disable_configstore +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_SRC_FILES:= disable_configstore.cpp +LOCAL_OVERRIDES_MODULES := android.hardware.configstore@1.1-service +LOCAL_VENDOR_MODULE := true +LOCAL_UNINSTALLABLE_MODULE := true + +include $(BUILD_EXECUTABLE) diff --git a/configstore/1.1/default/disable_configstore.cpp b/configstore/1.1/default/disable_configstore.cpp new file mode 100644 index 0000000000..b727ddb293 --- /dev/null +++ b/configstore/1.1/default/disable_configstore.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.1 (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.1 + * + * 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. + */ + +int main() { + return 1; +} From acf026ec783359f3a8387d099fe017215f8ec2ba Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Mon, 16 Mar 2020 17:48:34 -0700 Subject: [PATCH 0710/1022] Camera: Migrate BOKEH_MODE to EXTENDED_SCENE_MODE Migrate BOKEH_MODE_STILL_CAPTURE and BOKEH_MODE_CONTINUOUS to be 2 enums of CONTROL_EXTENDED_SCENE_MODE. Test: VtsHalCameraProviderV2_4TargetTest Bug: 151759402 Change-Id: I4ee88ab550902edadbd8dc446677c5a02ea582cb --- camera/metadata/3.5/types.hal | 46 ++++--- .../VtsHalCameraProviderV2_4TargetTest.cpp | 114 +++++++++++------- 2 files changed, 98 insertions(+), 62 deletions(-) diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal index 4e2252cc5c..d32bc91968 100644 --- a/camera/metadata/3.5/types.hal +++ b/camera/metadata/3.5/types.hal @@ -35,28 +35,29 @@ import android.hardware.camera.metadata@3.4; * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.

      */ enum CameraMetadataTag : @3.4::CameraMetadataTag { - /** android.control.availableBokehMaxSizes [static, int32[], ndk_public] + /** android.control.availableExtendedSceneModeMaxSizes [static, int32[], ndk_public] * - *

      The list of bokeh modes for ANDROID_CONTROL_BOKEH_MODE that are supported by this camera - * device, and each bokeh mode's maximum streaming (non-stall) size with bokeh effect.

      + *

      The list of extended scene modes for ANDROID_CONTROL_EXTENDED_SCENE_MODE that are supported + * by this camera device, and each extended scene mode's maximum streaming (non-stall) size + * with effect.

      * - * @see ANDROID_CONTROL_BOKEH_MODE + * @see ANDROID_CONTROL_EXTENDED_SCENE_MODE */ - ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3, + ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3, - /** android.control.availableBokehZoomRatioRanges [static, float[], ndk_public] + /** android.control.availableExtendedSceneModeZoomRatioRanges [static, float[], ndk_public] * - *

      The ranges of supported zoom ratio for non-OFF ANDROID_CONTROL_BOKEH_MODE.

      + *

      The ranges of supported zoom ratio for non-DISABLED ANDROID_CONTROL_EXTENDED_SCENE_MODE.

      * - * @see ANDROID_CONTROL_BOKEH_MODE + * @see ANDROID_CONTROL_EXTENDED_SCENE_MODE */ - ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES, + ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES, - /** android.control.bokehMode [dynamic, enum, public] + /** android.control.extendedSceneMode [dynamic, enum, public] * - *

      Whether bokeh mode is enabled for a particular capture request.

      + *

      Whether extended scene mode is enabled for a particular capture request.

      */ - ANDROID_CONTROL_BOKEH_MODE, + ANDROID_CONTROL_EXTENDED_SCENE_MODE, /** android.control.zoomRatioRange [static, float[], public] * @@ -95,13 +96,22 @@ enum CameraMetadataTag : @3.4::CameraMetadataTag { * Enumeration definitions for the various entries that need them */ -/** android.control.bokehMode enumeration values - * @see ANDROID_CONTROL_BOKEH_MODE +/** android.control.mode enumeration values added since v3.2 + * @see ANDROID_CONTROL_MODE */ -enum CameraMetadataEnumAndroidControlBokehMode : uint32_t { - ANDROID_CONTROL_BOKEH_MODE_OFF, - ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE, - ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS, +enum CameraMetadataEnumAndroidControlMode : + @3.2::CameraMetadataEnumAndroidControlMode { + ANDROID_CONTROL_MODE_USE_EXTENDED_SCENE_MODE, +}; + +/** android.control.extendedSceneMode enumeration values + * @see ANDROID_CONTROL_EXTENDED_SCENE_MODE + */ +enum CameraMetadataEnumAndroidControlExtendedSceneMode : uint32_t { + ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED = 0, + ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_STILL_CAPTURE, + ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_CONTINUOUS, + ANDROID_CONTROL_EXTENDED_SCENE_MODE_VENDOR_START = 0x40, }; /** android.lens.poseReference enumeration values added since v3.3 diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index c9d76da2ca..05b8b47caa 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -784,7 +784,7 @@ public: const CameraMetadata& chars, int deviceVersion, const hidl_vec& deviceNames); void verifyCameraCharacteristics(Status status, const CameraMetadata& chars); - void verifyBokehCharacteristics(const camera_metadata_t* metadata); + void verifyExtendedSceneModeCharacteristics(const camera_metadata_t* metadata); void verifyZoomCharacteristics(const camera_metadata_t* metadata); void verifyRecommendedConfigs(const CameraMetadata& metadata); void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion); @@ -6588,77 +6588,98 @@ void CameraHidlTest::verifyCameraCharacteristics(Status status, const CameraMeta poseReference >= ANDROID_LENS_POSE_REFERENCE_PRIMARY_CAMERA); } - verifyBokehCharacteristics(metadata); + verifyExtendedSceneModeCharacteristics(metadata); verifyZoomCharacteristics(metadata); } -void CameraHidlTest::verifyBokehCharacteristics(const camera_metadata_t* metadata) { +void CameraHidlTest::verifyExtendedSceneModeCharacteristics(const camera_metadata_t* metadata) { camera_metadata_ro_entry entry; int retcode = 0; + retcode = find_camera_metadata_ro_entry(metadata, ANDROID_CONTROL_AVAILABLE_MODES, &entry); + if ((0 == retcode) && (entry.count > 0)) { + for (auto i = 0; i < entry.count; i++) { + ASSERT_TRUE(entry.data.u8[i] >= ANDROID_CONTROL_MODE_OFF && + entry.data.u8[i] <= ANDROID_CONTROL_MODE_USE_EXTENDED_SCENE_MODE); + } + } else { + ADD_FAILURE() << "Get camera controlAvailableModes failed!"; + } + // Check key availability in capabilities, request and result. retcode = find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry); - bool hasBokehRequestKey = false; + bool hasExtendedSceneModeRequestKey = false; if ((0 == retcode) && (entry.count > 0)) { - hasBokehRequestKey = std::find(entry.data.i32, entry.data.i32+entry.count, - ANDROID_CONTROL_BOKEH_MODE) != entry.data.i32+entry.count; + hasExtendedSceneModeRequestKey = + std::find(entry.data.i32, entry.data.i32 + entry.count, + ANDROID_CONTROL_EXTENDED_SCENE_MODE) != entry.data.i32 + entry.count; } else { ADD_FAILURE() << "Get camera availableRequestKeys failed!"; } retcode = find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry); - bool hasBokehResultKey = false; + bool hasExtendedSceneModeResultKey = false; if ((0 == retcode) && (entry.count > 0)) { - hasBokehResultKey = std::find(entry.data.i32, entry.data.i32+entry.count, - ANDROID_CONTROL_BOKEH_MODE) != entry.data.i32+entry.count; + hasExtendedSceneModeResultKey = + std::find(entry.data.i32, entry.data.i32 + entry.count, + ANDROID_CONTROL_EXTENDED_SCENE_MODE) != entry.data.i32 + entry.count; } else { ADD_FAILURE() << "Get camera availableResultKeys failed!"; } retcode = find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry); - bool hasBokehMaxSizesKey = false; - bool hasBokehZoomRatioRangesKey = false; + bool hasExtendedSceneModeMaxSizesKey = false; + bool hasExtendedSceneModeZoomRatioRangesKey = false; if ((0 == retcode) && (entry.count > 0)) { - hasBokehMaxSizesKey = std::find(entry.data.i32, entry.data.i32+entry.count, - ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES) != entry.data.i32+entry.count; - hasBokehZoomRatioRangesKey = std::find(entry.data.i32, entry.data.i32+entry.count, - ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES) != entry.data.i32+entry.count; + hasExtendedSceneModeMaxSizesKey = + std::find(entry.data.i32, entry.data.i32 + entry.count, + ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES) != + entry.data.i32 + entry.count; + hasExtendedSceneModeZoomRatioRangesKey = + std::find(entry.data.i32, entry.data.i32 + entry.count, + ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES) != + entry.data.i32 + entry.count; } else { ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!"; } camera_metadata_ro_entry maxSizesEntry; - retcode = find_camera_metadata_ro_entry(metadata, - ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES, &maxSizesEntry); - bool hasBokehMaxSizes = (0 == retcode && maxSizesEntry.count > 0); + retcode = find_camera_metadata_ro_entry( + metadata, ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES, &maxSizesEntry); + bool hasExtendedSceneModeMaxSizes = (0 == retcode && maxSizesEntry.count > 0); camera_metadata_ro_entry zoomRatioRangesEntry; - retcode = find_camera_metadata_ro_entry(metadata, - ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES, &zoomRatioRangesEntry); - bool hasBokehZoomRatioRanges = (0 == retcode && zoomRatioRangesEntry.count > 0); + retcode = find_camera_metadata_ro_entry( + metadata, ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES, + &zoomRatioRangesEntry); + bool hasExtendedSceneModeZoomRatioRanges = (0 == retcode && zoomRatioRangesEntry.count > 0); - // Bokeh keys must all be available, or all be unavailable. - bool noBokeh = !hasBokehRequestKey && !hasBokehResultKey && !hasBokehMaxSizesKey && - !hasBokehZoomRatioRangesKey && !hasBokehMaxSizes && !hasBokehZoomRatioRanges; - if (noBokeh) { + // Extended scene mode keys must all be available, or all be unavailable. + bool noExtendedSceneMode = + !hasExtendedSceneModeRequestKey && !hasExtendedSceneModeResultKey && + !hasExtendedSceneModeMaxSizesKey && !hasExtendedSceneModeZoomRatioRangesKey && + !hasExtendedSceneModeMaxSizes && !hasExtendedSceneModeZoomRatioRanges; + if (noExtendedSceneMode) { return; } - bool hasBokeh = hasBokehRequestKey && hasBokehResultKey && hasBokehMaxSizesKey && - hasBokehZoomRatioRangesKey && hasBokehMaxSizes && hasBokehZoomRatioRanges; - ASSERT_TRUE(hasBokeh); + bool hasExtendedSceneMode = hasExtendedSceneModeRequestKey && hasExtendedSceneModeResultKey && + hasExtendedSceneModeMaxSizesKey && + hasExtendedSceneModeZoomRatioRangesKey && + hasExtendedSceneModeMaxSizes && hasExtendedSceneModeZoomRatioRanges; + ASSERT_TRUE(hasExtendedSceneMode); - // Must have OFF, and must have one of STILL_CAPTURE and CONTINUOUS. - // Only valid combinations: {OFF, CONTINUOUS}, {OFF, STILL_CAPTURE}, and - // {OFF, CONTINUOUS, STILL_CAPTURE}. + // Must have DISABLED, and must have one of BOKEH_STILL_CAPTURE, BOKEH_CONTINUOUS, or a VENDOR + // mode. ASSERT_TRUE((maxSizesEntry.count == 6 && zoomRatioRangesEntry.count == 2) || (maxSizesEntry.count == 9 && zoomRatioRangesEntry.count == 4)); - bool hasOffMode = false; - bool hasStillCaptureMode = false; - bool hasContinuousMode = false; + bool hasDisabledMode = false; + bool hasBokehStillCaptureMode = false; + bool hasBokehContinuousMode = false; + bool hasVendorMode = false; std::vector outputStreams; ASSERT_EQ(Status::OK, getAvailableOutputStreams(metadata, outputStreams)); for (int i = 0, j = 0; i < maxSizesEntry.count && j < zoomRatioRangesEntry.count; i += 3) { @@ -6666,24 +6687,29 @@ void CameraHidlTest::verifyBokehCharacteristics(const camera_metadata_t* metadat int32_t maxWidth = maxSizesEntry.data.i32[i+1]; int32_t maxHeight = maxSizesEntry.data.i32[i+2]; switch (mode) { - case ANDROID_CONTROL_BOKEH_MODE_OFF: - hasOffMode = true; + case ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED: + hasDisabledMode = true; ASSERT_TRUE(maxWidth == 0 && maxHeight == 0); break; - case ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE: - hasStillCaptureMode = true; + case ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_STILL_CAPTURE: + hasBokehStillCaptureMode = true; j += 2; break; - case ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS: - hasContinuousMode = true; + case ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_CONTINUOUS: + hasBokehContinuousMode = true; j += 2; break; default: - ADD_FAILURE() << "Invalid bokehMode advertised: " << mode; + if (mode < ANDROID_CONTROL_EXTENDED_SCENE_MODE_VENDOR_START) { + ADD_FAILURE() << "Invalid extended scene mode advertised: " << mode; + } else { + hasVendorMode = true; + j += 2; + } break; } - if (mode != ANDROID_CONTROL_BOKEH_MODE_OFF) { + if (mode != ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED) { // Make sure size is supported. bool sizeSupported = false; for (const auto& stream : outputStreams) { @@ -6703,8 +6729,8 @@ void CameraHidlTest::verifyBokehCharacteristics(const camera_metadata_t* metadat ASSERT_LE(minZoomRatio, maxZoomRatio); } } - ASSERT_TRUE(hasOffMode); - ASSERT_TRUE(hasStillCaptureMode || hasContinuousMode); + ASSERT_TRUE(hasDisabledMode); + ASSERT_TRUE(hasBokehStillCaptureMode || hasBokehContinuousMode || hasVendorMode); } void CameraHidlTest::verifyZoomCharacteristics(const camera_metadata_t* metadata) { From c2a724ef5f41d0b074067620940bf26ed9e40ab1 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 19 Mar 2020 11:35:39 -0700 Subject: [PATCH 0711/1022] Remove identity@1.0 from current.txt It does not exist. Fixes: 151954406 Test: aosp-changes-report no longer shows identity as being incorrectly added Change-Id: I878f8719175188c718d249251d051ff616def891 --- current.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/current.txt b/current.txt index c9cba7090b..815a21238f 100644 --- a/current.txt +++ b/current.txt @@ -666,10 +666,6 @@ df52e2c39ed701a355b5e0fdbf83fe5fa7d04bfecd715116b39373d46dc3c682 android.hardwar ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback e2f8bc1868fd4a3fd587c172773ea5a8c2f5a3deaf7958394102ca455252b255 android.hardware.health@2.1::types -0589e410f519e36514e7ece18f283f022df0f70efd2c12821d822f67f74aba98 android.hardware.identity@1.0::types -bbeee9604128ede83ee755b67e73b5ad29e6e1dbac9ec41fea6ffe2745b0c50a android.hardware.identity@1.0::IIdentityCredential -96ce8aad80f4c476f25261f790d357c117e79e18474c7dadd850dac704bbe65e android.hardware.identity@1.0::IIdentityCredentialStore -8da9c938e58f7d636ddd2f92c646f99d9a9e79612e6441b6380ab12744251873 android.hardware.identity@1.0::IWritableIdentityCredential 27ae3724053940462114228872b3ffaf0b8e6177d5ba97f5a76339d12b8a99dd android.hardware.keymaster@4.1::IKeymasterDevice adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardware.keymaster@4.1::IOperation ddcf89cd8ee2df0d32aee55050826446fb64f7aafde0a7cd946c64f61b1a364c android.hardware.keymaster@4.1::types From 891b8389258a7a49a32c79db8aaf9ebc7c64e38b Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 19 Mar 2020 12:09:15 -0700 Subject: [PATCH 0712/1022] sort 'HALs released in Android R' For this section 'sort -k2'. Bug: 147496715 Test: continues to compile (checks hashes) Change-Id: I4dfcb24e5e864d1271e5e2a7e06619ef8ab9bb35 --- current.txt | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/current.txt b/current.txt index 815a21238f..5d862d833b 100644 --- a/current.txt +++ b/current.txt @@ -606,7 +606,6 @@ ff5dd821c2c7a9c78607159c4d788960b725487263c49d956ca5fa3d37008b45 android.hardwar 5751f230e86a36111e7c5b995577cbf89d8df76c8e6c7641199198f3db3a93f7 android.hardware.wifi@1.3::IWifiStaIface # HALs released in Android R -822369cf4dc16a6f6b9622bcf86cbdc0b692dc82193fc15e967767175cbfdd8f android.hardware.audio@6.0::types 7241bd4596a927cd46d4b82f5e29e2cbe57f194aa1b25555f1d1d352e8b15c61 android.hardware.audio@6.0::IDevice 2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice @@ -615,8 +614,8 @@ fd1f1b29f26b42e886220f04a08086c00e5ade9d7b53f095438e578ab9d42a93 android.hardwar 164826a380f4c1700183003f62d7532e367b67381c30ea44f946c0cf00008f85 android.hardware.audio@6.0::IStreamOut 997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback e7ca0db9a1098210f327a9b152fa6afe6bf019c41e5264c64829d04d50c0a526 android.hardware.audio@6.0::IStreamOutEventCallback +822369cf4dc16a6f6b9622bcf86cbdc0b692dc82193fc15e967767175cbfdd8f android.hardware.audio@6.0::types bee662c62d997d8065e2bcb5c1e7a9578931f22ce28fd02c219fdb4d0630abf7 android.hardware.audio.common@6.0::types -817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types 525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect 8d76bbe3719d051a8e9a1dcf9244f37f5b0a491feb249fa48391edf7cb4f3131 android.hardware.audio.effect@6.0::IAutomaticGainControlEffect 461b1114cb35d89f87e5694e0792ba53c112a7fa9a14d9b95188cf9c4764be23 android.hardware.audio.effect@6.0::IBassBoostEffect @@ -631,18 +630,19 @@ dd377f404a8e71f6191d295e10067db629b0f0c28e594af906f2bea5d87fe2cc android.hardwar 5237c42d3913ef569f07bec802568084b615155d05a7951e75085da54856508c android.hardware.audio.effect@6.0::IPresetReverbEffect 282193799d60bff27a84c65a36218c1e7d8f582f5828e2e059383d1b90aa56bd android.hardware.audio.effect@6.0::IVirtualizerEffect 0868e00f7c5ee16723bda1a8f57099763d04100ae7126a1c2d3a9a87c844a7e8 android.hardware.audio.effect@6.0::IVisualizerEffect +817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types 7e8e1c3d0173c5d503dd01cecff8e3864478557ca6b9e8cc2291598b1a4aea62 android.hardware.biometrics.face@1.1::IBiometricsFace -ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types 6828bbf18dc5d0f00c73341a10c8e4d574346c1abb1c2ed682ba5e9f8a3240d9 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprint 82cad99f5feb2ea9bcd4579055edf4af8feb9fc602a6e4827ddd727d254d4991 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprintClientCallback +ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types 362fd1c21641c2224f3b80c30d9797b988fa3f344243d531ba73c553779a5763 android.hardware.bluetooth@1.1::IBluetoothHci 40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types b8c63679e1a3874b356f3e691aecce1191d38f59063cf2ed2dce8a9d4cabf00e android.hardware.camera.device@3.6::ICameraDevice +a35d5151b48505f06a775b38c0e2e265f80a845d92802324c643565807f81c53 android.hardware.camera.device@3.6::types 99aae72ae75a8ddf63ccffbc585f3a55f4d0847b4adff3d7a0f8bd9e2305bec1 android.hardware.camera.provider@2.6::ICameraProvider 8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback -a35d5151b48505f06a775b38c0e2e265f80a845d92802324c643565807f81c53 android.hardware.camera.device@3.6::types c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas 9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardware.cas@1.2::IMediaCasService @@ -651,9 +651,8 @@ f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardwar 3581d0ba61663cdd45807494dcd697d01c074f27587df9140655f94346969cfe android.hardware.contexthub@1.1::types 66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory 994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory -d9df99be0f59d8f33a9699fe316c67bfd11818aa69440bb1123ba43e717cea85 android.hardware.dumpstate@1.1::types 186bc152ae189ab48f3a761a44ddf5edd0d483073c5b6ca1f802f8b50488b754 android.hardware.dumpstate@1.1::IDumpstateDevice -769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types +d9df99be0f59d8f33a9699fe316c67bfd11818aa69440bb1123ba43e717cea85 android.hardware.dumpstate@1.1::types c319e68b03829958404402c2d9c682019678087d60495807c0a7444e0a6af981 android.hardware.gnss@2.1::IGnss ba5ac712b2a656dc07c83ab4a7a2c2f3bee1bbcb752e8b8ffa9b672f3b5b0728 android.hardware.gnss@2.1::IGnssAntennaInfo 0bc3ed97cbc3f6abc89c68f4e9f4d124f9f723431997dc88c2186cf4d2ad47ee android.hardware.gnss@2.1::IGnssAntennaInfoCallback @@ -661,6 +660,7 @@ ba5ac712b2a656dc07c83ab4a7a2c2f3bee1bbcb752e8b8ffa9b672f3b5b0728 android.hardwar 737d750017738f0753d13ba01a3310e0161f294b8ae80b3fd63eaa227e9d9c66 android.hardware.gnss@2.1::IGnssConfiguration 7913a11206a577b12ade86a7cf3f95c2639cb514d086673f279bf99238c9917e android.hardware.gnss@2.1::IGnssMeasurement df52e2c39ed701a355b5e0fdbf83fe5fa7d04bfecd715116b39373d46dc3c682 android.hardware.gnss@2.1::IGnssMeasurementCallback +769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types 6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections 956c1576ca0d6f11b42980ef59052062836b6763fe973af6cb709da50787f710 android.hardware.gnss.measurement_corrections@1.1::types ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth @@ -678,7 +678,15 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 2b0b10d2ea7a18a4048cd0eb83d35c19a817aeee95f65807fc31f4ef21381397 android.hardware.neuralnetworks@1.3::IPreparedModel eee3430cc86c97c7b407495863d8fb61da6f1a64b7721e77b9b4909b11b174e9 android.hardware.neuralnetworks@1.3::IPreparedModelCallback e442ab1b440327fe4e8a3b0b8ac6874e9bc6342e91fe976eb9fea77c63961ec8 android.hardware.neuralnetworks@1.3::types -b335c3c732c799b299fa61c6de6260ab4d20cbd0ec21acd6db14d8156c745d0b android.hardware.tv.tuner@1.0::types +b454df853441c12f6e425e8a60dd29fda20f5e6e39b93d1103e4b37495db38aa android.hardware.radio@1.5::IRadio +fcbb0742a88215ee7a6d7ce0825d253eb2b50391fc6c8c48667f9fd7f6d4549e android.hardware.radio@1.5::IRadioIndication +b809193970a91ca637a4b0184767315601d32e3ef3d5992ffbc7a8d14a14f015 android.hardware.radio@1.5::IRadioResponse +e7669bddacbdaee2cd9a87762a13fb7648639eead54bf4d767dc06eaaeb35736 android.hardware.radio@1.5::types +3ca6616381080bdd6c08141ad12775a94ae868c58b02b1274ae3326f7de724ab android.hardware.sensors@2.1::ISensors +3d4141c6373cd9ca02fe221a7d12343840de2255d032c38248fe8e35816b58b2 android.hardware.sensors@2.1::ISensorsCallback +8051cc50fc90ed447f058a8b15d81f35a65f1bd9004b1de4f127edeb89b47978 android.hardware.sensors@2.1::types +b37f78e3fdc79af8b32a545b2b426f1fd1355b359d9e7835f3bf1ed0aa4518d8 android.hardware.soundtrigger@2.3::ISoundTriggerHw +4a6517ea4ad807855428b0101d8e1a486497bd88ab4300ba3b2be43d46d32580 android.hardware.soundtrigger@2.3::types adab52e647d1a1ccfbdabdfc9c73352f8e834b61322e505bc6e3d3a0d3acc259 android.hardware.tv.tuner@1.0::IDemux 548e1a16fc4f779346e14968a63cd6f160e1e2c8b8c99256b2bac24a24b52a9a android.hardware.tv.tuner@1.0::IDescrambler b84597d59f0f1d03c9997d60eb15280f3950c287d46016240d89859789db4d47 android.hardware.tv.tuner@1.0::IDvr @@ -691,6 +699,8 @@ ccd985e820ed92a5cb55f524b3549462483d21824ca2df0276f5bc2f42878ea3 android.hardwar b2310785bdb55f97bbbb2176e2ee73ed8d2a7ce5895bd20c997b90c5f2868ad8 android.hardware.tv.tuner@1.0::ILnbCallback 4788787e662293d526ff7789fc24e82533e7f6ff99a967ebc3e3ec6b17628796 android.hardware.tv.tuner@1.0::ITimeFilter c350c7783843e0c7cf30f90c918770b0d3c09fc0fe5e532e2f2e7210fcfe71c9 android.hardware.tv.tuner@1.0::ITuner +b335c3c732c799b299fa61c6de6260ab4d20cbd0ec21acd6db14d8156c745d0b android.hardware.tv.tuner@1.0::types +7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types @@ -699,13 +709,3 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar 2ce1f7fb52e49f80b13a9b153d491bce530552f02357ea729acae922a8659f93 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback 77531c8d048f8f8ae532babd0ca86332a865ec9aace1b051226ef2b21123e645 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types -e7669bddacbdaee2cd9a87762a13fb7648639eead54bf4d767dc06eaaeb35736 android.hardware.radio@1.5::types -b454df853441c12f6e425e8a60dd29fda20f5e6e39b93d1103e4b37495db38aa android.hardware.radio@1.5::IRadio -fcbb0742a88215ee7a6d7ce0825d253eb2b50391fc6c8c48667f9fd7f6d4549e android.hardware.radio@1.5::IRadioIndication -b809193970a91ca637a4b0184767315601d32e3ef3d5992ffbc7a8d14a14f015 android.hardware.radio@1.5::IRadioResponse -3ca6616381080bdd6c08141ad12775a94ae868c58b02b1274ae3326f7de724ab android.hardware.sensors@2.1::ISensors -3d4141c6373cd9ca02fe221a7d12343840de2255d032c38248fe8e35816b58b2 android.hardware.sensors@2.1::ISensorsCallback -8051cc50fc90ed447f058a8b15d81f35a65f1bd9004b1de4f127edeb89b47978 android.hardware.sensors@2.1::types -4a6517ea4ad807855428b0101d8e1a486497bd88ab4300ba3b2be43d46d32580 android.hardware.soundtrigger@2.3::types -b37f78e3fdc79af8b32a545b2b426f1fd1355b359d9e7835f3bf1ed0aa4518d8 android.hardware.soundtrigger@2.3::ISoundTriggerHw -7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget From 2adec4f116067ea8beac05fc196d173718a62d7d Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Thu, 19 Mar 2020 20:39:12 +0000 Subject: [PATCH 0713/1022] audio: Check result from oneway calls As oneway HIDL calls generate methods that return 'Result', the returned value must be checked to avoid triggering an assertion if the result was an error (e.g. due to the client death). Bug: 151900655 Test: N/A Change-Id: I4721240b5959d6f11cb4447b30928bf4c83da058 --- audio/core/all-versions/default/StreamOut.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp index 150d641cd0..1519c48e12 100644 --- a/audio/core/all-versions/default/StreamOut.cpp +++ b/audio/core/all-versions/default/StreamOut.cpp @@ -455,20 +455,22 @@ int StreamOut::asyncCallback(stream_callback_event_t event, void*, void* cookie) sp callback = self->mCallback; if (callback.get() == nullptr) return 0; ALOGV("asyncCallback() event %d", event); + Return result; switch (event) { case STREAM_CBK_EVENT_WRITE_READY: - callback->onWriteReady(); + result = callback->onWriteReady(); break; case STREAM_CBK_EVENT_DRAIN_READY: - callback->onDrainReady(); + result = callback->onDrainReady(); break; case STREAM_CBK_EVENT_ERROR: - callback->onError(); + result = callback->onError(); break; default: ALOGW("asyncCallback() unknown event %d", event); break; } + ALOGW_IF(!result.isOk(), "Client callback failed: %s", result.description().c_str()); return 0; } @@ -629,16 +631,18 @@ int StreamOut::asyncEventCallback(stream_event_callback_type_t event, void* para sp eventCallback = self->mEventCallback; if (eventCallback.get() == nullptr) return 0; ALOGV("%s event %d", __func__, event); + Return result; switch (event) { case STREAM_EVENT_CBK_TYPE_CODEC_FORMAT_CHANGED: { hidl_vec audioMetadata; audioMetadata.setToExternal((uint8_t*)param, strlen((char*)param)); - eventCallback->onCodecFormatChanged(audioMetadata); + result = eventCallback->onCodecFormatChanged(audioMetadata); } break; default: ALOGW("%s unknown event %d", __func__, event); break; } + ALOGW_IF(!result.isOk(), "Client callback failed: %s", result.description().c_str()); return 0; } #endif From f1d431f634a09e871159907f09c40c35bbb6bb8b Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Tue, 3 Mar 2020 14:14:31 -0500 Subject: [PATCH 0714/1022] Add SubHal header for Sensors HAL 2.1 Bug: 149758467 Test: compile Change-Id: Id10d20e5d24571572565ac5d968f265ef7d7070f --- sensors/2.0/multihal/Android.bp | 1 + .../common/default/2.X/multihal/Android.bp | 26 ++- .../common/default/2.X/multihal/HalProxy.cpp | 2 - .../default/2.X/multihal/ScopedWakelock.cpp | 2 +- .../default/2.X/multihal/include/HalProxy.h | 5 +- .../include/{ => V2_0}/ScopedWakelock.h | 0 .../2.X/multihal/include/{ => V2_0}/SubHal.h | 2 +- .../2.X/multihal/include/V2_1/SubHal.h | 180 ++++++++++++++++++ .../default/2.X/multihal/tests/Android.bp | 3 + .../2.X/multihal/tests/HalProxy_test.cpp | 2 +- .../tests/fake_subhal/SensorsSubHal.h | 2 +- 11 files changed, 215 insertions(+), 10 deletions(-) rename sensors/common/default/2.X/multihal/include/{ => V2_0}/ScopedWakelock.h (100%) rename sensors/common/default/2.X/multihal/include/{ => V2_0}/SubHal.h (99%) create mode 100644 sensors/common/default/2.X/multihal/include/V2_1/SubHal.h diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp index 7213b448b4..3ce33906cc 100644 --- a/sensors/2.0/multihal/Android.bp +++ b/sensors/2.0/multihal/Android.bp @@ -28,6 +28,7 @@ cc_binary { shared_libs: [ "android.hardware.sensors@2.0", "android.hardware.sensors@2.0-ScopedWakelock", + "android.hardware.sensors@2.1", "libbase", "libcutils", "libfmq", diff --git a/sensors/common/default/2.X/multihal/Android.bp b/sensors/common/default/2.X/multihal/Android.bp index 2b4b3bfffa..6122323fd8 100644 --- a/sensors/common/default/2.X/multihal/Android.bp +++ b/sensors/common/default/2.X/multihal/Android.bp @@ -16,11 +16,12 @@ cc_defaults { name: "android.hardware.sensors@2.X-multihal-defaults", header_libs: [ - "android.hardware.sensors@2.0-multihal.header", + "android.hardware.sensors@2.X-multihal.header", ], shared_libs: [ "android.hardware.sensors@1.0", "android.hardware.sensors@2.0", + "android.hardware.sensors@2.1", "libbase", "libcutils", "libfmq", @@ -32,9 +33,24 @@ cc_defaults { cflags: ["-DLOG_TAG=\"SensorsMultiHal\""], } +// Header target for sub-HALs that implement the Multi-HAL 2.0 interface cc_library_headers { name: "android.hardware.sensors@2.0-multihal.header", vendor_available: true, + export_include_dirs: ["include/V2_0"], +} + +// Header target for sub-HALs that implement the Multi-HAL 2.1 interface +cc_library_headers { + name: "android.hardware.sensors@2.1-multihal.header", + vendor_available: true, + export_include_dirs: ["include/V2_1"], +} + +// Header target for Multi-HAL so it can reference both 2.0/2.1 headers +cc_library_headers { + name: "android.hardware.sensors@2.X-multihal.header", + vendor_available: true, export_include_dirs: ["include"], } @@ -49,7 +65,7 @@ cc_library_static { ], vendor_available: true, export_header_lib_headers: [ - "android.hardware.sensors@2.0-multihal.header", + "android.hardware.sensors@2.X-multihal.header", ], } @@ -62,6 +78,9 @@ cc_library_shared { srcs: [ "ScopedWakelock.cpp", ], + header_libs: [ + "android.hardware.sensors@2.0-multihal.header", + ], vendor_available: true, export_header_lib_headers: [ "android.hardware.sensors@2.0-multihal.header", @@ -78,6 +97,9 @@ cc_test_library { "ScopedWakelock.cpp", ], vendor_available: true, + header_libs: [ + "android.hardware.sensors@2.0-multihal.header", + ], export_header_lib_headers: [ "android.hardware.sensors@2.0-multihal.header", ], diff --git a/sensors/common/default/2.X/multihal/HalProxy.cpp b/sensors/common/default/2.X/multihal/HalProxy.cpp index ac6f17a484..518e138f6a 100644 --- a/sensors/common/default/2.X/multihal/HalProxy.cpp +++ b/sensors/common/default/2.X/multihal/HalProxy.cpp @@ -16,8 +16,6 @@ #include "HalProxy.h" -#include "SubHal.h" - #include #include diff --git a/sensors/common/default/2.X/multihal/ScopedWakelock.cpp b/sensors/common/default/2.X/multihal/ScopedWakelock.cpp index d85d4a7891..bf2ad35081 100644 --- a/sensors/common/default/2.X/multihal/ScopedWakelock.cpp +++ b/sensors/common/default/2.X/multihal/ScopedWakelock.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "ScopedWakelock.h" +#include "V2_0/ScopedWakelock.h" namespace android { namespace hardware { diff --git a/sensors/common/default/2.X/multihal/include/HalProxy.h b/sensors/common/default/2.X/multihal/include/HalProxy.h index 978f7cf1ba..d7e8795903 100644 --- a/sensors/common/default/2.X/multihal/include/HalProxy.h +++ b/sensors/common/default/2.X/multihal/include/HalProxy.h @@ -16,8 +16,9 @@ #pragma once -#include "ScopedWakelock.h" -#include "SubHal.h" +#include "V2_0/ScopedWakelock.h" +#include "V2_0/SubHal.h" +#include "V2_1/SubHal.h" #include #include diff --git a/sensors/common/default/2.X/multihal/include/ScopedWakelock.h b/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h similarity index 100% rename from sensors/common/default/2.X/multihal/include/ScopedWakelock.h rename to sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h diff --git a/sensors/common/default/2.X/multihal/include/SubHal.h b/sensors/common/default/2.X/multihal/include/V2_0/SubHal.h similarity index 99% rename from sensors/common/default/2.X/multihal/include/SubHal.h rename to sensors/common/default/2.X/multihal/include/V2_0/SubHal.h index 92ae3a61df..2a80e6baea 100644 --- a/sensors/common/default/2.X/multihal/include/SubHal.h +++ b/sensors/common/default/2.X/multihal/include/V2_0/SubHal.h @@ -159,7 +159,7 @@ using ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal; * library. This function will only be invoked once at initialization time. * * NOTE: The supported sensors HAL version must match SUB_HAL_2_0_VERSION exactly or the HalProxy - * will fail to initialize. + * will fail to initialize. * * @param uint32_t when this function returns, this parameter must contain the HAL version that * this sub-HAL supports. To support this version of multi-HAL, this must be set to diff --git a/sensors/common/default/2.X/multihal/include/V2_1/SubHal.h b/sensors/common/default/2.X/multihal/include/V2_1/SubHal.h new file mode 100644 index 0000000000..cd494220ad --- /dev/null +++ b/sensors/common/default/2.X/multihal/include/V2_1/SubHal.h @@ -0,0 +1,180 @@ +/* + * 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. + */ + +#pragma once + +#include "V2_0/ScopedWakelock.h" + +#include +#include + +#include + +// Indicates the current version of the multiHAL interface formatted as (HAL major version) << 24 | +// (HAL minor version) << 16 | (multiHAL version) +#define SUB_HAL_2_1_VERSION 0x02010000 + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_1 { +namespace implementation { + +/** + * Interface that contains several callbacks into the HalProxy class to communicate dynamic sensor + * changes and sensor events to the framework and acquire wake locks. The HalProxy will ensure + * callbacks occurring at the same time from multiple sub-HALs are synchronized in a safe, efficient + * manner. + */ +class IHalProxyCallback : public ISensorsCallback { + public: + using ScopedWakelock = V2_0::implementation::ScopedWakelock; + + /** + * Thread-safe callback used to post events to the HalProxy. Sub-HALs should invoke this + * whenever new sensor events need to be delivered to the sensors framework. Once invoked, the + * HalProxy will attempt to send events to the sensors framework using a blocking write with a + * 5 second timeout. This write may be done asynchronously if the queue used to communicate + * with the framework is full to avoid blocking sub-HALs for the length of the timeout. If the + * write fails, the events will be dropped and any wake locks held will be released. + * + * The provided ScopedWakelock must be locked if the events are from wakeup sensors. If it's + * not locked accordingly, the HalProxy will crash as this indicates the sub-HAL isn't compliant + * with the sensors HAL specification. Additionally, since ScopedWakelock isn't copyable, + * the HalProxy will take ownership of the wake lock given when this method is invoked. Once the + * method returns, the HalProxy will handle holding the wake lock, if necessary, until the + * framework has successfully processed any wakeup events. + * + * No return type is used for this callback to avoid sub-HALs trying to resend events when + * writes fail. Writes should only fail when the framework is under inordinate stress which will + * likely result in a framework restart so retrying will likely only result in overloading the + * HalProxy. Sub-HALs should always assume that the write was a success and perform any + * necessary cleanup. Additionally, the HalProxy will ensure it logs any errors (through ADB and + * bug reports) it encounters during delivery to ensure it's obvious that a failure occurred. + * + * @param events the events that should be sent to the sensors framework + * @param wakelock ScopedWakelock that should be locked to send events from wake sensors and + * unlocked otherwise. + */ + virtual void postEvents(const std::vector& events, ScopedWakelock wakelock) = 0; + + /** + * Initializes a ScopedWakelock on the stack that, when locked, will increment the reference + * count for the sub-HAL's wake lock managed inside the HalProxy. See the ScopedWakelock class + * definition for how it should be used. + * + * @param lock whether the ScopedWakelock should be locked before it's returned. + * @return the created ScopedWakelock + */ + virtual ScopedWakelock createScopedWakelock(bool lock) = 0; +}; + +/** + * ISensorsSubHal is an interface that sub-HALs must implement in order to be compliant with + * multihal and in order for the HalProxy to successfully load and communicate with the sub-HAL. + * + * Any vendor wishing to implement this interface and support multihal will need to create a + * dynamic library that exposes sensorsHalGetSubHal (defined below). This library will be loaded by + * the HalProxy when the sensors HAL is initialized and then the HalProxy will retrieve the vendor's + * implementation of sensorsHalGetSubHal. + * + * With the exception of the initialize method, ISensorsSubHal will implement the ISensors.hal spec. + * Any sensor handles given to the HalProxy, either through getSensorsList() or the + * onDynamicSensors(Dis)Connected callbacks, will be translated to avoid clashing with other sub-HAL + * handles. To achieve this, the HalProxy will use the upper byte to store the sub-HAL index and + * sub-HALs can continue to use the lower 3 bytes of the handle. + */ +class ISensorsSubHal : public ISensors { + public: + // The ISensors version of initialize isn't used for multihal. Instead, sub-HALs must implement + // the version below to allow communciation logic to centralized in the HalProxy + Return initialize_2_1( + const ::android::hardware::MQDescriptorSync& /* eventQueueDescriptor */, + const ::android::hardware::MQDescriptorSync& /* wakeLockDescriptor */, + const sp& /* sensorsCallback */) final { + return V1_0::Result::INVALID_OPERATION; + } + + Return initialize( + const ::android::hardware::MQDescriptorSync& /* eventQueueDescriptor */, + const ::android::hardware::MQDescriptorSync& /* wakeLockDescriptor */, + const sp& /* sensorsCallback */) final { + return V1_0::Result::INVALID_OPERATION; + } + + // Several HAL 2.0 methods won't be invoked on HAL 2.1 so they are stubbed out below. + Return getSensorsList(getSensorsList_cb /* _hidl_cb */) final { return Void(); } + + Return injectSensorData(const V1_0::Event& /* event */) final { + return V1_0::Result::INVALID_OPERATION; + } + + /** + * Method defined in ::android::hidl::base::V1_0::IBase. + * + * This method should write debug information to hidl_handle that is useful for debugging + * issues. Suggestions include: + * - Sensor info including handle values and any other state available in the SensorInfo class + * - List of active sensors and their current sampling period and reporting latency + * - Information about pending flush requests + * - Current operating mode + * - Currently registered direct channel info + * - A history of any of the above + */ + virtual Return debug(const hidl_handle& fd, const hidl_vec& args) = 0; + + /** + * @return A human-readable name for use in wake locks and logging. + */ + virtual const std::string getName() = 0; + + /** + * This is the first method invoked on the sub-HAL after it's allocated through + * sensorsHalGetSubHal() by the HalProxy. Sub-HALs should use this to initialize any state and + * retain the callback given in order to communicate with the HalProxy. Method will be called + * anytime the sensors framework restarts. Therefore, this method will be responsible for + * reseting the state of the subhal and cleaning up and reallocating any previously allocated + * data. Initialize should ensure that the subhal has reset its operation mode to NORMAL state + * as well. + * + * @param halProxyCallback callback used to inform the HalProxy when a dynamic sensor's state + * changes, new sensor events should be sent to the framework, and when a new ScopedWakelock + * should be created. + * @return result OK on success + */ + virtual Return initialize(const sp& halProxyCallback) = 0; +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace sensors +} // namespace hardware +} // namespace android + +/** + * Function that must be exported so the HalProxy class can invoke it on the sub-HAL dynamic + * library. This function will only be invoked once at initialization time. + * + * NOTE: The supported sensors HAL version must match SUB_HAL_2_1_VERSION or the HalProxy + * will fail to initialize. + * + * @param uint32_t when this function returns, this parameter must contain the HAL version that + * this sub-HAL supports. This must be set to SUB_HAL_2_1_VERSION. + * @return A statically allocated, valid ISensorsSubHal implementation. + */ +__attribute__((visibility( + "default"))) extern "C" ::android::hardware::sensors::V2_1::implementation::ISensorsSubHal* +sensorsHalGetSubHal_2_1(uint32_t* version); diff --git a/sensors/common/default/2.X/multihal/tests/Android.bp b/sensors/common/default/2.X/multihal/tests/Android.bp index afb63cc22f..7692b51de0 100644 --- a/sensors/common/default/2.X/multihal/tests/Android.bp +++ b/sensors/common/default/2.X/multihal/tests/Android.bp @@ -26,6 +26,7 @@ cc_defaults { "android.hardware.sensors@1.0", "android.hardware.sensors@2.0", "android.hardware.sensors@2.0-ScopedWakelock", + "android.hardware.sensors@2.1", "libcutils", "libfmq", "libhardware", @@ -85,6 +86,8 @@ cc_test { shared_libs: [ "android.hardware.sensors@1.0", "android.hardware.sensors@2.0", + "android.hardware.sensors@2.0-ScopedWakelock", + "android.hardware.sensors@2.1", "libbase", "libcutils", "libfmq", diff --git a/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp index 4633a7508a..867c4a149d 100644 --- a/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp +++ b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp @@ -19,8 +19,8 @@ #include #include "HalProxy.h" -#include "ScopedWakelock.h" #include "SensorsSubHal.h" +#include "V2_0/ScopedWakelock.h" #include #include diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h index c1e36472cf..6da4404c3e 100644 --- a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h +++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h @@ -16,7 +16,7 @@ #pragma once -#include "SubHal.h" +#include "V2_0/SubHal.h" #include "Sensor.h" From 6ea14b48d875f0db914ea5b5139ad78babb682a6 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Thu, 19 Mar 2020 15:53:08 -0700 Subject: [PATCH 0715/1022] Freeze kernel configs for r. Bug: 151966896 Test: builds Change-Id: Iefad197353738410dc066531a6e14e3df96449d4 --- compatibility_matrices/Android.bp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp index 7883dd937f..33157a6fb8 100644 --- a/compatibility_matrices/Android.bp +++ b/compatibility_matrices/Android.bp @@ -83,8 +83,8 @@ vintf_compatibility_matrix { "compatibility_matrix.current.xml", ], kernel_configs: [ - "kernel_config_current_4.14", - "kernel_config_current_4.19", - "kernel_config_current_5.4", + "kernel_config_r_4.14", + "kernel_config_r_4.19", + "kernel_config_r_5.4", ] } From 678a10600c6146bde78baa925e86dc99131c5d8a Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Thu, 19 Mar 2020 17:10:34 -0700 Subject: [PATCH 0716/1022] Remove extra tests from NNAPI VTS validation tests Do not run validation on "inputs_as_internal" and "all_tensors_as_inputs" variants. Bug: 138149072 Bug: 149840439 Test: mma Test: VtsHalNeuralnetworksV1_*TargetTest Change-Id: I0699ed6703e48b6c4bc0e7a392b79c12770f04c9 --- neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp | 4 ++++ neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h | 3 +++ neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp | 7 ++++++- neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp | 4 ++++ neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h | 3 +++ neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp | 7 ++++++- neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp | 4 ++++ neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h | 3 +++ neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp | 7 ++++++- neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp | 4 ++++ neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h | 3 +++ neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp | 7 ++++++- 12 files changed, 52 insertions(+), 4 deletions(-) diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp index e28605dca2..87de9c605f 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp @@ -158,6 +158,10 @@ std::vector getNamedModels(const FilterFn& filter) { return TestModelManager::get().getTestModels(filter); } +std::vector getNamedModels(const FilterNameFn& filter) { + return TestModelManager::get().getTestModels(filter); +} + std::string printGeneratedTest(const testing::TestParamInfo& info) { const auto& [namedDevice, namedModel] = info.param; return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel)); diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h index f230a028f3..1a55c2f9c8 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h @@ -37,6 +37,9 @@ class GeneratedTestBase : public testing::TestWithParam { using FilterFn = std::function; std::vector getNamedModels(const FilterFn& filter); +using FilterNameFn = std::function; +std::vector getNamedModels(const FilterNameFn& filter); + std::string printGeneratedTest(const testing::TestParamInfo& info); #define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp index cb2225025b..70170b39ac 100644 --- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp @@ -134,6 +134,11 @@ TEST_P(ValidationTest, Test) { validateEverything(kDevice, model, request); } -INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); +INSTANTIATE_GENERATED_TEST(ValidationTest, [](const std::string& testName) { + // Skip validation for the "inputs_as_internal" and "all_tensors_as_inputs" + // generated tests. + return testName.find("inputs_as_internal") == std::string::npos && + testName.find("all_tensors_as_inputs") == std::string::npos; +}); } // namespace android::hardware::neuralnetworks::V1_0::vts::functional diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp index cee15a35a1..7353c61006 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp @@ -166,6 +166,10 @@ std::vector getNamedModels(const FilterFn& filter) { return TestModelManager::get().getTestModels(filter); } +std::vector getNamedModels(const FilterNameFn& filter) { + return TestModelManager::get().getTestModels(filter); +} + std::string printGeneratedTest(const testing::TestParamInfo& info) { const auto& [namedDevice, namedModel] = info.param; return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel)); diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h index cf449ea42d..4b1a96e00d 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h @@ -37,6 +37,9 @@ class GeneratedTestBase : public testing::TestWithParam { using FilterFn = std::function; std::vector getNamedModels(const FilterFn& filter); +using FilterNameFn = std::function; +std::vector getNamedModels(const FilterNameFn& filter); + std::string printGeneratedTest(const testing::TestParamInfo& info); #define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp index d56d40b2ba..15d2260ec0 100644 --- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp @@ -137,6 +137,11 @@ TEST_P(ValidationTest, Test) { validateEverything(kDevice, model, request); } -INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); +INSTANTIATE_GENERATED_TEST(ValidationTest, [](const std::string& testName) { + // Skip validation for the "inputs_as_internal" and "all_tensors_as_inputs" + // generated tests. + return testName.find("inputs_as_internal") == std::string::npos && + testName.find("all_tensors_as_inputs") == std::string::npos; +}); } // namespace android::hardware::neuralnetworks::V1_1::vts::functional diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp index 3ab01351e9..573545a049 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp @@ -382,6 +382,10 @@ std::vector getNamedModels(const FilterFn& filter) { return TestModelManager::get().getTestModels(filter); } +std::vector getNamedModels(const FilterNameFn& filter) { + return TestModelManager::get().getTestModels(filter); +} + std::string printGeneratedTest(const testing::TestParamInfo& info) { const auto& [namedDevice, namedModel] = info.param; return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel)); diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h index dfc980c169..98295ff64a 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h @@ -41,6 +41,9 @@ class GeneratedTestBase : public testing::TestWithParam { using FilterFn = std::function; std::vector getNamedModels(const FilterFn& filter); +using FilterNameFn = std::function; +std::vector getNamedModels(const FilterNameFn& filter); + std::string printGeneratedTest(const testing::TestParamInfo& info); #define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp index 4fbd0e270f..69bce29011 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp @@ -161,7 +161,12 @@ TEST_P(ValidationTest, Test) { } } -INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); +INSTANTIATE_GENERATED_TEST(ValidationTest, [](const std::string& testName) { + // Skip validation for the "inputs_as_internal" and "all_tensors_as_inputs" + // generated tests. + return testName.find("inputs_as_internal") == std::string::npos && + testName.find("all_tensors_as_inputs") == std::string::npos; +}); sp getPreparedModel_1_2(const sp& callback) { sp preparedModelV1_0 = callback->getPreparedModel(); diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index aae58bfb3e..9eecbc78d1 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -891,6 +891,10 @@ std::vector getNamedModels(const FilterFn& filter) { return TestModelManager::get().getTestModels(filter); } +std::vector getNamedModels(const FilterNameFn& filter) { + return TestModelManager::get().getTestModels(filter); +} + std::string printGeneratedTest(const testing::TestParamInfo& info) { const auto& [namedDevice, namedModel] = info.param; return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel)); diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h index 834d335f50..065f7ef2b8 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h @@ -41,6 +41,9 @@ class GeneratedTestBase : public testing::TestWithParam { using FilterFn = std::function; std::vector getNamedModels(const FilterFn& filter); +using FilterNameFn = std::function; +std::vector getNamedModels(const FilterNameFn& filter); + std::string printGeneratedTest(const testing::TestParamInfo& info); #define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \ diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index 5b07034296..eda867e17a 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -185,7 +185,12 @@ TEST_P(ValidationTest, Test) { } } -INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); +INSTANTIATE_GENERATED_TEST(ValidationTest, [](const std::string& testName) { + // Skip validation for the "inputs_as_internal" and "all_tensors_as_inputs" + // generated tests. + return testName.find("inputs_as_internal") == std::string::npos && + testName.find("all_tensors_as_inputs") == std::string::npos; +}); sp getPreparedModel_1_3(const sp& callback) { sp preparedModelV1_0 = callback->getPreparedModel(); From fed2f5213f1e968d31b433cde00cba6b6bbeebc6 Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Wed, 29 Jan 2020 13:24:33 -0800 Subject: [PATCH 0717/1022] Add memory domain VTS validation tests. Bug: 147777318 Test: 1.3 VTS with sample driver Change-Id: Ia2097345924726d8fb627845fd7438cc3eb35eb6 --- neuralnetworks/1.3/vts/functional/Android.bp | 1 + .../vts/functional/GeneratedTestHarness.cpp | 2 - .../1.3/vts/functional/MemoryDomainTests.cpp | 1166 +++++++++++++++++ .../vts/functional/VtsHalNeuralnetworks.cpp | 15 + .../1.3/vts/functional/VtsHalNeuralnetworks.h | 4 + 5 files changed, 1186 insertions(+), 2 deletions(-) create mode 100644 neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp index f9362676ec..545a5be74e 100644 --- a/neuralnetworks/1.3/vts/functional/Android.bp +++ b/neuralnetworks/1.3/vts/functional/Android.bp @@ -40,6 +40,7 @@ cc_test { "BasicTests.cpp", "CompilationCachingTests.cpp", "GeneratedTestHarness.cpp", + "MemoryDomainTests.cpp", "QualityOfServiceTests.cpp", "TestAssertions.cpp", "ValidateBurst.cpp", diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 5689a39e1b..ff21960e6a 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -72,8 +72,6 @@ using HidlToken = hidl_array(Constant::BYTE_SIZE_ namespace { -enum class Executor { ASYNC, SYNC, BURST, FENCED }; - enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT, MISSED_DEADLINE }; enum class MemoryType { SHARED, DEVICE }; diff --git a/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp b/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp new file mode 100644 index 0000000000..08c1b35510 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp @@ -0,0 +1,1166 @@ +/* + * 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. + */ + +#define LOG_TAG "neuralnetworks_hidl_hal_test" + +#include +#include + +#include "1.3/Callbacks.h" +#include "1.3/Utils.h" +#include "GeneratedTestHarness.h" +#include "MemoryUtils.h" +#include "TestHarness.h" +#include "Utils.h" +#include "VtsHalNeuralnetworks.h" + +namespace android::hardware::neuralnetworks::V1_3::vts::functional { + +using namespace test_helper; +using implementation::ExecutionCallback; +using implementation::PreparedModelCallback; +using V1_0::RequestArgument; +using V1_1::ExecutionPreference; +using V1_2::Constant; +using V1_2::MeasureTiming; +using V1_2::OutputShape; +using V1_2::Timing; + +namespace { + +const auto kNamedDeviceChoices = testing::ValuesIn(getNamedDevices()); + +// A 1.3 driver is likely to support at least one of the following operand types. +const std::vector kTestOperandTypeChoicesVector = { + TestOperandType::TENSOR_FLOAT32, + TestOperandType::TENSOR_FLOAT16, + TestOperandType::TENSOR_QUANT8_ASYMM, + TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED, +}; +const auto kTestOperandTypeChoices = testing::ValuesIn(kTestOperandTypeChoicesVector); + +bool isInChoices(TestOperandType type) { + return std::count(kTestOperandTypeChoicesVector.begin(), kTestOperandTypeChoicesVector.end(), + type) > 0; +} + +bool isFloat(TestOperandType type) { + CHECK(isInChoices(type)); + return type == TestOperandType::TENSOR_FLOAT32 || type == TestOperandType::TENSOR_FLOAT16; +} + +// Create dummy buffers for model constants as well as inputs and outputs. +// We only care about the size here because we will not check accuracy in validation tests. +void createDummyData(TestModel* testModel) { + for (auto& operand : testModel->main.operands) { + if (operand.data != nullptr) continue; + switch (operand.lifetime) { + case TestOperandLifeTime::SUBGRAPH_INPUT: + case TestOperandLifeTime::SUBGRAPH_OUTPUT: + case TestOperandLifeTime::CONSTANT_COPY: + case TestOperandLifeTime::CONSTANT_REFERENCE: { + const uint32_t size = nn::nonExtensionOperandSizeOfData( + static_cast(operand.type), operand.dimensions); + operand.data = TestBuffer(size); + } break; + default: + break; + } + } +} + +TestOperand createInt32Scalar(int32_t value) { + return { + .type = TestOperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = TestOperandLifeTime::CONSTANT_COPY, + .data = TestBuffer::createFromVector({value}), + }; +} + +// Construct a test model with multiple CONV_2D operations with the given operand as inputs. +// The dimensions of the filters are chosen to ensure outputs has the same dimensions as inputs. +// We choose CONV_2D operation because it is commonly supported by most drivers. +TestModel createConvModel(const TestOperand& operand, uint32_t numOperations) { + CHECK(isInChoices(operand.type)); + + TestOperand weight = {.type = operand.type, + .dimensions = {operand.dimensions[3], 3, 3, operand.dimensions[3]}, + .numberOfConsumers = 1, + .scale = isFloat(operand.type) ? 0.0f : 1.0f, + .zeroPoint = 0, + .lifetime = TestOperandLifeTime::CONSTANT_COPY}; + + TestOperand bias = { + .type = isFloat(operand.type) ? operand.type : TestOperandType::TENSOR_INT32, + .dimensions = {operand.dimensions[3]}, + .numberOfConsumers = 1, + .scale = operand.scale * weight.scale, + .zeroPoint = 0, + .lifetime = TestOperandLifeTime::CONSTANT_COPY}; + + TestOperand output = operand; + output.numberOfConsumers = 0; + output.lifetime = TestOperandLifeTime::SUBGRAPH_OUTPUT; + + const std::vector operands = { + operand, + std::move(weight), + std::move(bias), + createInt32Scalar(1), // same padding + createInt32Scalar(1), // width stride + createInt32Scalar(1), // height stride + createInt32Scalar(0), // activation = NONE + std::move(output), + }; + + TestModel model; + for (uint32_t i = 0; i < numOperations; i++) { + model.main.operands.insert(model.main.operands.end(), operands.begin(), operands.end()); + const uint32_t inputIndex = operands.size() * i; + const uint32_t outputIndex = inputIndex + operands.size() - 1; + std::vector inputs(operands.size() - 1); + std::iota(inputs.begin(), inputs.end(), inputIndex); + model.main.operations.push_back({.type = TestOperationType::CONV_2D, + .inputs = std::move(inputs), + .outputs = {outputIndex}}); + model.main.inputIndexes.push_back(inputIndex); + model.main.outputIndexes.push_back(outputIndex); + } + createDummyData(&model); + return model; +} + +// Construct a test model with a single ADD operation with the given operand as input0 and input1. +// This is to cover additional cases that the CONV_2D model does not support, e.g. arbitrary input +// operand rank, scalar input operand. We choose ADD operation because it is commonly supported by +// most drivers. +TestModel createSingleAddModel(const TestOperand& operand) { + CHECK(isInChoices(operand.type)); + + TestOperand act = { + .type = TestOperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = TestOperandLifeTime::SUBGRAPH_INPUT, + }; + + TestOperand output = operand; + output.numberOfConsumers = 0; + output.lifetime = TestOperandLifeTime::SUBGRAPH_OUTPUT; + + TestModel model = { + .main = + { + .operands = + { + operand, + operand, + std::move(act), + output, + }, + .operations = {{.type = TestOperationType::ADD, + .inputs = {0, 1, 2}, + .outputs = {3}}}, + .inputIndexes = {0, 1, 2}, + .outputIndexes = {3}, + }, + }; + createDummyData(&model); + return model; +} + +// A dummy invalid IPreparedModel class for MemoryDomainAllocateTest.InvalidPreparedModel +class InvalidPreparedModel : public IPreparedModel { + public: + Return execute(const V1_0::Request&, + const sp&) override { + return V1_0::ErrorStatus::GENERAL_FAILURE; + } + Return execute_1_2(const V1_0::Request&, V1_2::MeasureTiming, + const sp&) override { + return V1_0::ErrorStatus::GENERAL_FAILURE; + } + Return execute_1_3(const V1_3::Request&, V1_2::MeasureTiming, + const V1_3::OptionalTimePoint&, + const V1_3::OptionalTimeoutDuration&, + const sp&) override { + return V1_3::ErrorStatus::GENERAL_FAILURE; + } + Return executeSynchronously(const V1_0::Request&, V1_2::MeasureTiming, + executeSynchronously_cb) override { + return Void(); + } + Return executeSynchronously_1_3(const V1_3::Request&, V1_2::MeasureTiming, + const V1_3::OptionalTimePoint&, + const V1_3::OptionalTimeoutDuration&, + executeSynchronously_1_3_cb) override { + return Void(); + } + Return configureExecutionBurst(const sp&, + const MQDescriptorSync&, + const MQDescriptorSync&, + configureExecutionBurst_cb) override { + return Void(); + } + Return executeFenced(const V1_3::Request&, const hidl_vec&, + V1_2::MeasureTiming, const V1_3::OptionalTimePoint&, + const V1_3::OptionalTimeoutDuration&, + const V1_3::OptionalTimeoutDuration&, executeFenced_cb) override { + return Void(); + } +}; + +} // namespace + +class MemoryDomainTestBase : public testing::Test { + protected: + MemoryDomainTestBase(sp device, TestOperandType type) + : kDevice(std::move(device)), + kTestOperandType(type), + kTestOperand(kTestOperandMap.at(type)), + kTestOperandDataSize(nn::nonExtensionOperandSizeOfData(static_cast(type), + kTestOperand.dimensions)) {} + + void SetUp() override { + testing::Test::SetUp(); + ASSERT_NE(kDevice, nullptr); + } + + sp createConvPreparedModel(const TestOperand& testOperand, + uint32_t numOperations = 1) { + const TestModel testModel = createConvModel(testOperand, numOperations); + const Model model = createModel(testModel); + sp preparedModel; + createPreparedModel(kDevice, model, &preparedModel, /*reportSkipping=*/false); + return preparedModel; + } + + sp createAddPreparedModel(const TestOperand& testOperand) { + const TestModel testModel = createSingleAddModel(testOperand); + const Model model = createModel(testModel); + sp preparedModel; + createPreparedModel(kDevice, model, &preparedModel, /*reportSkipping=*/false); + return preparedModel; + } + + static const std::map kTestOperandMap; + + const sp kDevice; + const TestOperandType kTestOperandType; + const TestOperand& kTestOperand; + const uint32_t kTestOperandDataSize; +}; + +const std::map MemoryDomainTestBase::kTestOperandMap = { + {TestOperandType::TENSOR_FLOAT32, + { + .type = TestOperandType::TENSOR_FLOAT32, + .dimensions = {1, 32, 32, 8}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = TestOperandLifeTime::SUBGRAPH_INPUT, + }}, + {TestOperandType::TENSOR_FLOAT16, + { + .type = TestOperandType::TENSOR_FLOAT16, + .dimensions = {1, 32, 32, 8}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = TestOperandLifeTime::SUBGRAPH_INPUT, + }}, + {TestOperandType::TENSOR_QUANT8_ASYMM, + { + .type = TestOperandType::TENSOR_QUANT8_ASYMM, + .dimensions = {1, 32, 32, 8}, + .numberOfConsumers = 1, + .scale = 0.5f, + .zeroPoint = 0, + .lifetime = TestOperandLifeTime::SUBGRAPH_INPUT, + }}, + {TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED, + { + .type = TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED, + .dimensions = {1, 32, 32, 8}, + .numberOfConsumers = 1, + .scale = 0.5f, + .zeroPoint = 0, + .lifetime = TestOperandLifeTime::SUBGRAPH_INPUT, + }}, +}; + +using MemoryDomainAllocateTestParam = std::tuple; +class MemoryDomainAllocateTest : public MemoryDomainTestBase, + public testing::WithParamInterface { + protected: + MemoryDomainAllocateTest() + : MemoryDomainTestBase(getData(std::get(GetParam())), + std::get(GetParam())) {} + + struct AllocateTestArgs { + hidl_vec dimensions; + hidl_vec> preparedModels; + hidl_vec inputRoles; + hidl_vec outputRoles; + }; + + // Validation test for IDevice::allocate. The driver is expected to fail with INVALID_ARGUMENT, + // or GENERAL_FAILURE if memory domain is not supported. + void validateAllocate(AllocateTestArgs args) { + const auto ret = kDevice->allocate( + {.dimensions = std::move(args.dimensions)}, std::move(args.preparedModels), + std::move(args.inputRoles), std::move(args.outputRoles), + [](ErrorStatus status, const sp& buffer, uint32_t token) { + EXPECT_TRUE(status == ErrorStatus::INVALID_ARGUMENT || + status == ErrorStatus::GENERAL_FAILURE); + EXPECT_EQ(buffer, nullptr); + EXPECT_EQ(token, 0); + }); + ASSERT_TRUE(ret.isOk()); + } + + void testConflictOperands(const sp& model1, const sp& model2) { + validateAllocate({ + .preparedModels = {model1, model2}, + .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}, + {.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}}, + }); + validateAllocate({ + .preparedModels = {model1, model2}, + .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}}, + .outputRoles = {{.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}}, + }); + validateAllocate({ + .preparedModels = {model1, model2}, + .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}, + {.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}}, + }); + } +}; + +TEST_P(MemoryDomainAllocateTest, EmptyRole) { + // Test with empty prepared models and roles. + validateAllocate({}); + + auto preparedModel = createConvPreparedModel(kTestOperand); + if (preparedModel == nullptr) return; + + // Test again with non-empty prepared models but empty roles. + validateAllocate({ + .preparedModels = {preparedModel}, + }); +} + +TEST_P(MemoryDomainAllocateTest, NullptrPreparedModel) { + // Test with nullptr prepared model as input role. + validateAllocate({ + .preparedModels = {nullptr}, + .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}}, + }); + + // Test with nullptr prepared model as output role. + validateAllocate({ + .preparedModels = {nullptr}, + .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}}, + }); +} + +TEST_P(MemoryDomainAllocateTest, InvalidPreparedModel) { + sp invalidPreparedModel = new InvalidPreparedModel(); + + // Test with invalid prepared model as input role. + validateAllocate({ + .preparedModels = {invalidPreparedModel}, + .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}}, + }); + + // Test with invalid prepared model as output role. + validateAllocate({ + .preparedModels = {invalidPreparedModel}, + .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}}, + }); +} + +TEST_P(MemoryDomainAllocateTest, InvalidModelIndex) { + auto preparedModel = createConvPreparedModel(kTestOperand); + if (preparedModel == nullptr) return; + + // This should fail, because the model index is out of bound. + validateAllocate({ + .preparedModels = {preparedModel}, + .inputRoles = {{.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}}, + }); + + // This should fail, because the model index is out of bound. + validateAllocate({ + .preparedModels = {preparedModel}, + .outputRoles = {{.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}}, + }); +} + +TEST_P(MemoryDomainAllocateTest, InvalidIOIndex) { + auto preparedModel = createConvPreparedModel(kTestOperand); + if (preparedModel == nullptr) return; + + // This should fail, because the model only has one input. + validateAllocate({ + .preparedModels = {preparedModel}, + .inputRoles = {{.modelIndex = 0, .ioIndex = 1, .frequency = 1.0f}}, + }); + + // This should fail, because the model only has one output. + validateAllocate({ + .preparedModels = {preparedModel}, + .outputRoles = {{.modelIndex = 0, .ioIndex = 1, .frequency = 1.0f}}, + }); +} + +TEST_P(MemoryDomainAllocateTest, InvalidFrequency) { + auto preparedModel = createConvPreparedModel(kTestOperand); + if (preparedModel == nullptr) return; + + for (float invalidFreq : {10.0f, 0.0f, -0.5f}) { + // Test with invalid frequency for input roles. + validateAllocate({ + .preparedModels = {preparedModel}, + .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = invalidFreq}}, + }); + // Test with invalid frequency for output roles. + validateAllocate({ + .preparedModels = {preparedModel}, + .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = invalidFreq}}, + }); + } +} + +TEST_P(MemoryDomainAllocateTest, SameRoleSpecifiedTwice) { + auto preparedModel = createConvPreparedModel(kTestOperand); + if (preparedModel == nullptr) return; + + // Same role with same model index. + validateAllocate({ + .preparedModels = {preparedModel}, + .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}, + {.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}}, + }); + validateAllocate({ + .preparedModels = {preparedModel}, + .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}, + {.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}}, + }); + + // Different model indexes, but logically referring to the same role. + validateAllocate({ + .preparedModels = {preparedModel, preparedModel}, + .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}, + {.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}}, + }); + validateAllocate({ + .preparedModels = {preparedModel, preparedModel}, + .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}, + {.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}}, + }); +} + +TEST_P(MemoryDomainAllocateTest, ConflictOperandType) { + const std::map conflictTypeMap = { + {TestOperandType::TENSOR_FLOAT32, TestOperandType::TENSOR_FLOAT16}, + {TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_FLOAT32}, + {TestOperandType::TENSOR_QUANT8_ASYMM, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED}, + {TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED, TestOperandType::TENSOR_QUANT8_ASYMM}, + }; + + TestOperand conflictTestOperand = kTestOperand; + const auto it = conflictTypeMap.find(kTestOperandType); + ASSERT_FALSE(it == conflictTypeMap.end()); + conflictTestOperand.type = it->second; + + auto preparedModel = createConvPreparedModel(kTestOperand); + auto conflictPreparedModel = createConvPreparedModel(conflictTestOperand); + if (preparedModel == nullptr || conflictPreparedModel == nullptr) return; + testConflictOperands(preparedModel, conflictPreparedModel); +} + +TEST_P(MemoryDomainAllocateTest, ConflictScale) { + if (isFloat(kTestOperandType)) return; + + TestOperand conflictTestOperand = kTestOperand; + ASSERT_NE(conflictTestOperand.scale, 1.0f); + conflictTestOperand.scale = 1.0f; + + auto preparedModel = createConvPreparedModel(kTestOperand); + auto conflictPreparedModel = createConvPreparedModel(conflictTestOperand); + if (preparedModel == nullptr || conflictPreparedModel == nullptr) return; + testConflictOperands(preparedModel, conflictPreparedModel); +} + +TEST_P(MemoryDomainAllocateTest, ConflictZeroPoint) { + if (isFloat(kTestOperandType)) return; + + TestOperand conflictTestOperand = kTestOperand; + ASSERT_NE(conflictTestOperand.zeroPoint, 10); + conflictTestOperand.zeroPoint = 10; + + auto preparedModel = createConvPreparedModel(kTestOperand); + auto conflictPreparedModel = createConvPreparedModel(conflictTestOperand); + if (preparedModel == nullptr || conflictPreparedModel == nullptr) return; + testConflictOperands(preparedModel, conflictPreparedModel); +} + +TEST_P(MemoryDomainAllocateTest, ConflictRankBetweenRoles) { + TestOperand conflictTestOperand = kTestOperand; + conflictTestOperand.dimensions.pop_back(); + + auto preparedModel = createAddPreparedModel(kTestOperand); + auto conflictPreparedModel = createAddPreparedModel(conflictTestOperand); + if (preparedModel == nullptr || conflictPreparedModel == nullptr) return; + testConflictOperands(preparedModel, conflictPreparedModel); +} + +TEST_P(MemoryDomainAllocateTest, ConflictDimensionsBetweenRoles) { + TestOperand conflictTestOperand = kTestOperand; + conflictTestOperand.dimensions[0] = 4; + + auto preparedModel = createConvPreparedModel(kTestOperand); + auto conflictPreparedModel = createConvPreparedModel(conflictTestOperand); + if (preparedModel == nullptr || conflictPreparedModel == nullptr) return; + testConflictOperands(preparedModel, conflictPreparedModel); +} + +TEST_P(MemoryDomainAllocateTest, ConflictRankBetweenRoleAndDesc) { + auto preparedModel = createConvPreparedModel(kTestOperand); + if (preparedModel == nullptr) return; + + auto badDimensions = kTestOperand.dimensions; + badDimensions.pop_back(); + + validateAllocate({ + .dimensions = badDimensions, + .preparedModels = {preparedModel}, + .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}}, + }); + validateAllocate({ + .dimensions = badDimensions, + .preparedModels = {preparedModel}, + .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}}, + }); +} + +TEST_P(MemoryDomainAllocateTest, ConflictDimensionsBetweenRoleAndDesc) { + auto preparedModel = createConvPreparedModel(kTestOperand); + if (preparedModel == nullptr) return; + + auto badDimensions = kTestOperand.dimensions; + badDimensions[0] = 4; + + validateAllocate({ + .dimensions = badDimensions, + .preparedModels = {preparedModel}, + .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}}, + }); + validateAllocate({ + .dimensions = badDimensions, + .preparedModels = {preparedModel}, + .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}}, + }); +} + +TEST_P(MemoryDomainAllocateTest, ConflictRankWithScalarRole) { + auto preparedModel = createAddPreparedModel(kTestOperand); + if (preparedModel == nullptr) return; + + // This should fail, because the target operand is a scalar but a non-empty dimension is + // specified. + validateAllocate({ + .dimensions = {1}, + .preparedModels = {preparedModel}, + .inputRoles = {{.modelIndex = 0, .ioIndex = 2, .frequency = 1.0f}}, + }); +} + +std::string printMemoryDomainAllocateTest( + const testing::TestParamInfo& info) { + const auto& [namedDevice, operandType] = info.param; + const std::string type = toString(static_cast(operandType)); + return gtestCompliantName(getName(namedDevice) + "_" + type); +} + +INSTANTIATE_TEST_CASE_P(TestMemoryDomain, MemoryDomainAllocateTest, + testing::Combine(kNamedDeviceChoices, kTestOperandTypeChoices), + printMemoryDomainAllocateTest); + +class MemoryDomainCopyTestBase : public MemoryDomainTestBase { + protected: + MemoryDomainCopyTestBase(sp device, TestOperandType type) + : MemoryDomainTestBase(std::move(device), type) {} + + // Allocates device memory for roles of a single prepared model. + // Returns {IBuffer, token} if success; returns {nullptr, 0} if not supported. + std::pair, uint32_t> allocateBuffer(const sp& preparedModel, + const std::vector& inputIndexes, + const std::vector& outputIndexes, + const std::vector& dimensions) { + if (preparedModel == nullptr) { + return {nullptr, 0}; + } + + hidl_vec inputRoles(inputIndexes.size()), outputRoles(outputIndexes.size()); + auto trans = [](uint32_t ind) -> BufferRole { + return {.modelIndex = 0, .ioIndex = ind, .frequency = 1.0f}; + }; + std::transform(inputIndexes.begin(), inputIndexes.end(), inputRoles.begin(), trans); + std::transform(outputIndexes.begin(), outputIndexes.end(), outputRoles.begin(), trans); + + sp buffer; + uint32_t token = 0; + const auto ret = kDevice->allocate( + {.dimensions = dimensions}, {preparedModel}, std::move(inputRoles), + std::move(outputRoles), + [&buffer, &token](ErrorStatus err, const sp& buf, uint32_t tok) { + if (err == ErrorStatus::NONE) { + EXPECT_NE(buf, nullptr); + EXPECT_GT(tok, 0); + buffer = buf; + token = tok; + } else { + EXPECT_EQ(err, ErrorStatus::GENERAL_FAILURE); + EXPECT_EQ(buf, nullptr); + EXPECT_EQ(tok, 0); + } + }); + EXPECT_TRUE(ret.isOk()); + return {std::move(buffer), token}; + } + + std::pair, uint32_t> allocateBuffer(const sp& preparedModel, + const std::vector& inputIndexes, + const std::vector& outputIndexes) { + return allocateBuffer(preparedModel, inputIndexes, outputIndexes, {}); + } + + hidl_memory allocateSharedMemory(uint32_t size) { + hidl_memory memory = nn::allocateSharedMemory(size); + EXPECT_EQ(memory.size(), size); + return memory; + } + + void testCopyFrom(const sp& buffer, const hidl_memory& memory, + const std::vector& dimensions, ErrorStatus expectedStatus) { + const auto ret = buffer->copyFrom(memory, dimensions); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(static_cast(ret), expectedStatus); + } + + void testCopyTo(const sp& buffer, const hidl_memory& memory, + ErrorStatus expectedStatus) { + const auto ret = buffer->copyTo(memory); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(static_cast(ret), expectedStatus); + } + + void initializeDeviceMemory(const sp& buffer) { + hidl_memory memory = nn::allocateSharedMemory(kTestOperandDataSize); + ASSERT_EQ(memory.size(), kTestOperandDataSize); + testCopyFrom(buffer, memory, kTestOperand.dimensions, ErrorStatus::NONE); + } +}; + +using MemoryDomainCopyTestParam = std::tuple; +class MemoryDomainCopyTest : public MemoryDomainCopyTestBase, + public testing::WithParamInterface { + protected: + MemoryDomainCopyTest() + : MemoryDomainCopyTestBase(getData(std::get(GetParam())), + std::get(GetParam())) {} +}; + +TEST_P(MemoryDomainCopyTest, CopyFrom_InvalidMemorySize) { + auto preparedModel = createConvPreparedModel(kTestOperand); + auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0}); + if (buffer == nullptr) return; + + uint32_t badMemorySize1 = kTestOperandDataSize / 2, badMemorySize2 = kTestOperandDataSize * 2; + hidl_memory badMemory1 = allocateSharedMemory(badMemorySize1); + hidl_memory badMemory2 = allocateSharedMemory(badMemorySize2); + testCopyFrom(buffer, badMemory1, {}, ErrorStatus::INVALID_ARGUMENT); + testCopyFrom(buffer, badMemory2, {}, ErrorStatus::INVALID_ARGUMENT); +} + +TEST_P(MemoryDomainCopyTest, CopyFrom_InvalidMemorySize_DynamicShape) { + TestOperand testOperand = kTestOperand; + testOperand.dimensions[0] = 0; + auto preparedModel = createConvPreparedModel(testOperand); + auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0}); + if (buffer == nullptr) return; + + uint32_t badMemorySize1 = kTestOperandDataSize / 2, badMemorySize2 = kTestOperandDataSize * 2; + hidl_memory badMemory1 = allocateSharedMemory(badMemorySize1); + hidl_memory badMemory2 = allocateSharedMemory(badMemorySize2); + hidl_memory goodMemory = allocateSharedMemory(kTestOperandDataSize); + + auto badDimensions = kTestOperand.dimensions; + badDimensions[0] = 2; + + testCopyFrom(buffer, badMemory1, kTestOperand.dimensions, ErrorStatus::INVALID_ARGUMENT); + testCopyFrom(buffer, badMemory2, kTestOperand.dimensions, ErrorStatus::INVALID_ARGUMENT); + testCopyFrom(buffer, goodMemory, kTestOperand.dimensions, ErrorStatus::NONE); + testCopyFrom(buffer, goodMemory, badDimensions, ErrorStatus::INVALID_ARGUMENT); +} + +TEST_P(MemoryDomainCopyTest, CopyFrom_InvalidDimensions) { + auto preparedModel = createConvPreparedModel(kTestOperand); + auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0}); + if (buffer == nullptr) return; + + hidl_memory memory = allocateSharedMemory(kTestOperandDataSize); + + std::vector badDimensions; + badDimensions = kTestOperand.dimensions; + badDimensions.pop_back(); + testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT); + + badDimensions = kTestOperand.dimensions; + badDimensions[0] = 2; + testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT); + + badDimensions = kTestOperand.dimensions; + badDimensions[0] = 0; + testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT); + + testCopyFrom(buffer, memory, {}, ErrorStatus::NONE); + testCopyFrom(buffer, memory, kTestOperand.dimensions, ErrorStatus::NONE); +} + +TEST_P(MemoryDomainCopyTest, CopyFrom_InvalidDimensions_DynamicShape) { + TestOperand testOperand = kTestOperand; + testOperand.dimensions[0] = 0; + auto preparedModel = createConvPreparedModel(testOperand); + auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0}); + if (buffer == nullptr) return; + + hidl_memory memory = allocateSharedMemory(kTestOperandDataSize); + + std::vector badDimensions; + badDimensions = kTestOperand.dimensions; + badDimensions.pop_back(); + testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT); + + badDimensions = kTestOperand.dimensions; + badDimensions[0] = 2; + badDimensions[3] = 4; + testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT); + + badDimensions = kTestOperand.dimensions; + badDimensions[0] = 1; + badDimensions[3] = 0; + testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT); + + testCopyFrom(buffer, memory, {}, ErrorStatus::INVALID_ARGUMENT); + testCopyFrom(buffer, memory, kTestOperand.dimensions, ErrorStatus::NONE); +} + +TEST_P(MemoryDomainCopyTest, CopyTo_UninitializedMemory) { + auto preparedModel = createConvPreparedModel(kTestOperand); + auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0}); + if (buffer == nullptr) return; + + hidl_memory memory = allocateSharedMemory(kTestOperandDataSize); + testCopyTo(buffer, memory, ErrorStatus::GENERAL_FAILURE); +} + +TEST_P(MemoryDomainCopyTest, CopyTo_InvalidMemorySize) { + auto preparedModel = createConvPreparedModel(kTestOperand); + auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0}); + if (buffer == nullptr) return; + + uint32_t badMemorySize1 = kTestOperandDataSize / 2, badMemorySize2 = kTestOperandDataSize * 2; + hidl_memory badMemory1 = allocateSharedMemory(badMemorySize1); + hidl_memory badMemory2 = allocateSharedMemory(badMemorySize2); + hidl_memory goodMemory = allocateSharedMemory(kTestOperandDataSize); + + initializeDeviceMemory(buffer); + testCopyTo(buffer, badMemory1, ErrorStatus::INVALID_ARGUMENT); + testCopyTo(buffer, badMemory2, ErrorStatus::INVALID_ARGUMENT); + testCopyTo(buffer, goodMemory, ErrorStatus::NONE); +} + +TEST_P(MemoryDomainCopyTest, CopyTo_InvalidMemorySize_DynamicShape) { + TestOperand testOperand = kTestOperand; + testOperand.dimensions[0] = 0; + auto preparedModel = createConvPreparedModel(testOperand); + auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0}); + if (buffer == nullptr) return; + + uint32_t badMemorySize1 = kTestOperandDataSize / 2, badMemorySize2 = kTestOperandDataSize * 2; + hidl_memory badMemory1 = allocateSharedMemory(badMemorySize1); + hidl_memory badMemory2 = allocateSharedMemory(badMemorySize2); + hidl_memory goodMemory = allocateSharedMemory(kTestOperandDataSize); + + initializeDeviceMemory(buffer); + testCopyTo(buffer, badMemory1, ErrorStatus::INVALID_ARGUMENT); + testCopyTo(buffer, badMemory2, ErrorStatus::INVALID_ARGUMENT); + testCopyTo(buffer, goodMemory, ErrorStatus::NONE); +} + +std::string printMemoryDomainCopyTest( + const testing::TestParamInfo& info) { + const auto& [namedDevice, operandType] = info.param; + const std::string type = toString(static_cast(operandType)); + return gtestCompliantName(getName(namedDevice) + "_" + type); +} + +INSTANTIATE_TEST_CASE_P(TestMemoryDomain, MemoryDomainCopyTest, + testing::Combine(kNamedDeviceChoices, kTestOperandTypeChoices), + printMemoryDomainCopyTest); + +using MemoryDomainExecutionTestParam = std::tuple; +class MemoryDomainExecutionTest + : public MemoryDomainCopyTestBase, + public testing::WithParamInterface { + protected: + MemoryDomainExecutionTest() + : MemoryDomainCopyTestBase(getData(std::get(GetParam())), + std::get(GetParam())) {} + + Request::MemoryPool createSharedMemoryPool(uint32_t size) { + hidl_memory memory = allocateSharedMemory(size); + Request::MemoryPool pool; + pool.hidlMemory(memory); + return pool; + } + + Request::MemoryPool createDeviceMemoryPool(uint32_t token) { + Request::MemoryPool pool; + pool.token(token); + return pool; + } + + void testExecution(const sp& preparedModel, const Request& request, + ErrorStatus expectedStatus) { + switch (kExecutor) { + case Executor::ASYNC: + EXPECT_EQ(executeAsync(preparedModel, request), expectedStatus); + break; + case Executor::SYNC: + EXPECT_EQ(executeSync(preparedModel, request), expectedStatus); + break; + default: + ASSERT_TRUE(false); + } + } + + ErrorStatus executeAsync(const sp& preparedModel, const Request& request) { + ErrorStatus executionStatus; + + // launch execution + sp executionCallback = new ExecutionCallback(); + const auto ret = + preparedModel->execute_1_3(request, MeasureTiming::NO, {}, {}, executionCallback); + EXPECT_TRUE(ret.isOk()); + executionStatus = static_cast(ret); + + // retrieve execution status + executionCallback->wait(); + if (executionStatus == ErrorStatus::NONE) { + executionStatus = executionCallback->getStatus(); + } else { + EXPECT_EQ(executionStatus, executionCallback->getStatus()); + } + const auto timing = executionCallback->getTiming(); + EXPECT_EQ(UINT64_MAX, timing.timeOnDevice); + EXPECT_EQ(UINT64_MAX, timing.timeInDriver); + if (executionStatus != ErrorStatus::NONE) { + EXPECT_EQ(executionCallback->getOutputShapes().size(), 0); + } + return executionStatus; + } + + ErrorStatus executeSync(const sp& preparedModel, const Request& request) { + ErrorStatus executionStatus; + const auto ret = preparedModel->executeSynchronously_1_3( + request, MeasureTiming::NO, {}, {}, + [&executionStatus](ErrorStatus error, const hidl_vec& shapes, + const Timing& time) { + executionStatus = error; + EXPECT_EQ(UINT64_MAX, time.timeOnDevice); + EXPECT_EQ(UINT64_MAX, time.timeInDriver); + if (executionStatus != ErrorStatus::NONE) { + EXPECT_EQ(shapes.size(), 0); + } + }); + EXPECT_TRUE(ret.isOk()); + return executionStatus; + } + + // TODO(xusongw): Add executeFenced. + + const Executor kExecutor = std::get(GetParam()); +}; + +TEST_P(MemoryDomainExecutionTest, InvalidToken) { + auto preparedModel = createConvPreparedModel(kTestOperand); + if (preparedModel == nullptr) return; + + Request::MemoryPool sharedMemory = createSharedMemoryPool(kTestOperandDataSize); + Request::MemoryPool badDeviceMemory1 = createDeviceMemoryPool(0); // Invalid token. + Request::MemoryPool badDeviceMemory2 = createDeviceMemoryPool(100); // Unknown token. + RequestArgument sharedMemoryArg = { + .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}}; + RequestArgument deviceMemoryArg = {.location = {.poolIndex = 1}}; + + testExecution(preparedModel, + {.inputs = {deviceMemoryArg}, + .outputs = {sharedMemoryArg}, + .pools = {sharedMemory, badDeviceMemory1}}, + ErrorStatus::INVALID_ARGUMENT); + testExecution(preparedModel, + {.inputs = {deviceMemoryArg}, + .outputs = {sharedMemoryArg}, + .pools = {sharedMemory, badDeviceMemory2}}, + ErrorStatus::INVALID_ARGUMENT); + testExecution(preparedModel, + {.inputs = {sharedMemoryArg}, + .outputs = {deviceMemoryArg}, + .pools = {sharedMemory, badDeviceMemory1}}, + ErrorStatus::INVALID_ARGUMENT); + testExecution(preparedModel, + {.inputs = {sharedMemoryArg}, + .outputs = {deviceMemoryArg}, + .pools = {sharedMemory, badDeviceMemory2}}, + ErrorStatus::INVALID_ARGUMENT); +} + +TEST_P(MemoryDomainExecutionTest, InvalidPreparedModel) { + auto preparedModel = createConvPreparedModel(kTestOperand); + auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0}); + if (buffer == nullptr) return; + auto badPreparedModel = createConvPreparedModel(kTestOperand); + if (badPreparedModel == nullptr) return; + + Request::MemoryPool sharedMemory = createSharedMemoryPool(kTestOperandDataSize); + Request::MemoryPool deviceMemory = createDeviceMemoryPool(token); + RequestArgument sharedMemoryArg = { + .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}}; + RequestArgument deviceMemoryArg = {.location = {.poolIndex = 1}}; + + // This should fail, because the buffer is not allocated for badPreparedModel. + initializeDeviceMemory(buffer); + testExecution(badPreparedModel, + {.inputs = {deviceMemoryArg}, + .outputs = {sharedMemoryArg}, + .pools = {sharedMemory, deviceMemory}}, + ErrorStatus::INVALID_ARGUMENT); + testExecution(badPreparedModel, + {.inputs = {sharedMemoryArg}, + .outputs = {deviceMemoryArg}, + .pools = {sharedMemory, deviceMemory}}, + ErrorStatus::INVALID_ARGUMENT); +} + +TEST_P(MemoryDomainExecutionTest, InvalidIOIndex) { + auto preparedModel = createConvPreparedModel(kTestOperand, 2); + auto [buffer, token] = allocateBuffer(preparedModel, {0}, {}); + if (buffer == nullptr) return; + + Request::MemoryPool sharedMemory1 = createSharedMemoryPool(kTestOperandDataSize); + Request::MemoryPool sharedMemory2 = createSharedMemoryPool(kTestOperandDataSize); + Request::MemoryPool sharedMemory3 = createSharedMemoryPool(kTestOperandDataSize); + Request::MemoryPool deviceMemory = createDeviceMemoryPool(token); + RequestArgument sharedMemoryArg1 = { + .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}}; + RequestArgument sharedMemoryArg2 = { + .location = {.poolIndex = 1, .offset = 0, .length = kTestOperandDataSize}}; + RequestArgument sharedMemoryArg3 = { + .location = {.poolIndex = 2, .offset = 0, .length = kTestOperandDataSize}}; + RequestArgument deviceMemoryArg = {.location = {.poolIndex = 3}}; + + // This should fail, because the device memory is not allocated for input 1. + initializeDeviceMemory(buffer); + testExecution(preparedModel, + {.inputs = {sharedMemoryArg1, deviceMemoryArg}, + .outputs = {sharedMemoryArg2, sharedMemoryArg3}, + .pools = {sharedMemory1, sharedMemory2, sharedMemory3, deviceMemory}}, + ErrorStatus::INVALID_ARGUMENT); + + // This should fail, because the device memory is not allocated for output 1. + testExecution(preparedModel, + {.inputs = {sharedMemoryArg1, sharedMemoryArg2}, + .outputs = {sharedMemoryArg3, deviceMemoryArg}, + .pools = {sharedMemory1, sharedMemory2, sharedMemory3, deviceMemory}}, + ErrorStatus::INVALID_ARGUMENT); +} + +TEST_P(MemoryDomainExecutionTest, InvalidIOType) { + auto preparedModel = createConvPreparedModel(kTestOperand); + auto [inputBuffer, inputToken] = allocateBuffer(preparedModel, {0}, {}); + auto [outputBuffer, outputToken] = allocateBuffer(preparedModel, {}, {0}); + if (inputBuffer == nullptr || outputBuffer == nullptr) return; + + Request::MemoryPool sharedMemory = createSharedMemoryPool(kTestOperandDataSize); + Request::MemoryPool deviceMemory = createDeviceMemoryPool(inputToken); + RequestArgument sharedMemoryArg = { + .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}}; + RequestArgument deviceMemoryArg = {.location = {.poolIndex = 1}}; + + // This should fail, because the device memory is allocated for input but used as output. + testExecution(preparedModel, + {.inputs = {sharedMemoryArg}, + .outputs = {deviceMemoryArg}, + .pools = {sharedMemory, deviceMemory}}, + ErrorStatus::INVALID_ARGUMENT); + + // This should fail, because the device memory is allocated for output but used as input. + deviceMemory.token(outputToken); + initializeDeviceMemory(outputBuffer); + testExecution(preparedModel, + {.inputs = {deviceMemoryArg}, + .outputs = {sharedMemoryArg}, + .pools = {sharedMemory, deviceMemory}}, + ErrorStatus::INVALID_ARGUMENT); +} + +TEST_P(MemoryDomainExecutionTest, UninitializedMemory) { + auto preparedModel = createConvPreparedModel(kTestOperand); + auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0}); + if (buffer == nullptr) return; + + Request::MemoryPool sharedMemory = createSharedMemoryPool(kTestOperandDataSize); + Request::MemoryPool deviceMemory = createDeviceMemoryPool(token); + RequestArgument sharedMemoryArg = { + .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}}; + RequestArgument deviceMemoryArg = {.location = {.poolIndex = 1}}; + + // This should fail, because the device memory is not initialized. + testExecution(preparedModel, + {.inputs = {deviceMemoryArg}, + .outputs = {sharedMemoryArg}, + .pools = {sharedMemory, deviceMemory}}, + ErrorStatus::GENERAL_FAILURE); + + // This should initialize the device memory. + testExecution(preparedModel, + {.inputs = {sharedMemoryArg}, + .outputs = {deviceMemoryArg}, + .pools = {sharedMemory, deviceMemory}}, + ErrorStatus::NONE); + + // Test again with initialized device memory. + testExecution(preparedModel, + {.inputs = {deviceMemoryArg}, + .outputs = {sharedMemoryArg}, + .pools = {sharedMemory, deviceMemory}}, + ErrorStatus::NONE); +} + +TEST_P(MemoryDomainExecutionTest, SameRequestMultipleRoles) { + auto preparedModel = createConvPreparedModel(kTestOperand, 2); + auto [buffer, token] = allocateBuffer(preparedModel, {0, 1}, {0, 1}); + if (buffer == nullptr) return; + + Request::MemoryPool sharedMemory1 = createSharedMemoryPool(kTestOperandDataSize); + Request::MemoryPool sharedMemory2 = createSharedMemoryPool(kTestOperandDataSize); + Request::MemoryPool deviceMemory = createDeviceMemoryPool(token); + RequestArgument sharedMemoryArg1 = { + .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}}; + RequestArgument sharedMemoryArg2 = { + .location = {.poolIndex = 1, .offset = 0, .length = kTestOperandDataSize}}; + RequestArgument deviceMemoryArg = {.location = {.poolIndex = 2}}; + + // This should fail, because the same device memory cannot be used for both input and output. + initializeDeviceMemory(buffer); + testExecution(preparedModel, + {.inputs = {deviceMemoryArg, sharedMemoryArg1}, + .outputs = {deviceMemoryArg, sharedMemoryArg2}, + .pools = {sharedMemory1, sharedMemory2, deviceMemory}}, + ErrorStatus::INVALID_ARGUMENT); + + // This should fail, because the same device memory cannot be used for multiple outputs. + testExecution(preparedModel, + {.inputs = {sharedMemoryArg1, sharedMemoryArg2}, + .outputs = {deviceMemoryArg, deviceMemoryArg}, + .pools = {sharedMemory1, sharedMemory2, deviceMemory}}, + ErrorStatus::INVALID_ARGUMENT); + + // The same device memory can be used for multiple inputs. + initializeDeviceMemory(buffer); + testExecution(preparedModel, + {.inputs = {deviceMemoryArg, deviceMemoryArg}, + .outputs = {sharedMemoryArg1, sharedMemoryArg2}, + .pools = {sharedMemory1, sharedMemory2, deviceMemory}}, + ErrorStatus::NONE); +} + +TEST_P(MemoryDomainExecutionTest, InvalidDimensions) { + TestOperand testOperand = kTestOperand; + testOperand.dimensions[0] = 0; + auto preparedModel = createConvPreparedModel(testOperand); + auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0}, kTestOperand.dimensions); + if (buffer == nullptr) return; + + Request::MemoryPool sharedMemory = createSharedMemoryPool(kTestOperandDataSize); + Request::MemoryPool deviceMemory = createDeviceMemoryPool(token); + auto badDimensions = kTestOperand.dimensions; + badDimensions[0] = 2; + RequestArgument sharedMemoryArg = { + .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}, + .dimensions = badDimensions}; + RequestArgument deviceMemoryArg = {.location = {.poolIndex = 1}}; + RequestArgument deviceMemoryArgWithBadDimensions = {.location = {.poolIndex = 1}, + .dimensions = badDimensions}; + + initializeDeviceMemory(buffer); + testExecution(preparedModel, + {.inputs = {deviceMemoryArgWithBadDimensions}, + .outputs = {sharedMemoryArg}, + .pools = {sharedMemory, deviceMemory}}, + ErrorStatus::INVALID_ARGUMENT); + + testExecution(preparedModel, + {.inputs = {sharedMemoryArg}, + .outputs = {deviceMemoryArgWithBadDimensions}, + .pools = {sharedMemory, deviceMemory}}, + ErrorStatus::INVALID_ARGUMENT); + + testExecution(preparedModel, + {.inputs = {sharedMemoryArg}, + .outputs = {deviceMemoryArg}, + .pools = {sharedMemory, deviceMemory}}, + ErrorStatus::GENERAL_FAILURE); +} + +const auto kExecutorChoices = testing::Values(Executor::ASYNC, Executor::SYNC); + +std::string printMemoryDomainExecutionTest( + const testing::TestParamInfo& info) { + const auto& [namedDevice, operandType, executor] = info.param; + const std::string type = toString(static_cast(operandType)); + const std::string executorStr = toString(executor); + return gtestCompliantName(getName(namedDevice) + "_" + type + "_" + executorStr); +} + +INSTANTIATE_TEST_CASE_P(TestMemoryDomain, MemoryDomainExecutionTest, + testing::Combine(kNamedDeviceChoices, kTestOperandTypeChoices, + kExecutorChoices), + printMemoryDomainExecutionTest); + +} // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index 5b07034296..60ceb7e21e 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -192,4 +192,19 @@ sp getPreparedModel_1_3(const sp& callbac return IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr); } +std::string toString(Executor executor) { + switch (executor) { + case Executor::ASYNC: + return "ASYNC"; + case Executor::SYNC: + return "SYNC"; + case Executor::BURST: + return "BURST"; + case Executor::FENCED: + return "FENCED"; + default: + CHECK(false); + } +} + } // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h index 4e51052966..de082c39cc 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h @@ -52,6 +52,10 @@ void createPreparedModel(const sp& device, const Model& model, // Utility function to get PreparedModel from callback and downcast to V1_2. sp getPreparedModel_1_3(const sp& callback); +enum class Executor { ASYNC, SYNC, BURST, FENCED }; + +std::string toString(Executor executor); + } // namespace android::hardware::neuralnetworks::V1_3::vts::functional #endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H From 9c415917e0859f42bc4e6d020aa665c0e48fc6dc Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Fri, 20 Mar 2020 14:49:54 -0700 Subject: [PATCH 0718/1022] Add fenced compute path to memory domain validation test. Bug: 147777318 Test: 1.3 VTS Change-Id: I0b731d10384ef2024241af1d908acf3ba760d73f --- .../vts/functional/GeneratedTestHarness.cpp | 14 +++---- .../1.3/vts/functional/GeneratedTestHarness.h | 2 + .../1.3/vts/functional/MemoryDomainTests.cpp | 41 ++++++++++++++++++- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index ff21960e6a..29fdee4398 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -78,13 +78,6 @@ enum class MemoryType { SHARED, DEVICE }; enum class IOType { INPUT, OUTPUT }; -static void waitForSyncFence(int syncFd) { - constexpr int kInfiniteTimeout = -1; - ASSERT_GT(syncFd, 0); - int r = sync_wait(syncFd, kInfiniteTimeout); - ASSERT_GE(r, 0); -} - struct TestConfig { Executor executor; MeasureTiming measureTiming; @@ -275,6 +268,13 @@ void copyTestBuffers(const std::vector& buffers, uint8_t* out } // namespace +void waitForSyncFence(int syncFd) { + constexpr int kInfiniteTimeout = -1; + ASSERT_GT(syncFd, 0); + int r = sync_wait(syncFd, kInfiniteTimeout); + ASSERT_GE(r, 0); +} + Model createModel(const TestModel& testModel) { uint32_t constCopySize = 0; uint32_t constRefSize = 0; diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h index 834d335f50..38d6486478 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h @@ -77,6 +77,8 @@ enum class TestKind { void EvaluatePreparedModel(const sp& device, const sp& preparedModel, const test_helper::TestModel& testModel, TestKind testKind); +void waitForSyncFence(int syncFd); + } // namespace android::hardware::neuralnetworks::V1_3::vts::functional #endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H diff --git a/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp b/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp index 08c1b35510..3c0c8858b6 100644 --- a/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp +++ b/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp @@ -864,6 +864,9 @@ class MemoryDomainExecutionTest case Executor::SYNC: EXPECT_EQ(executeSync(preparedModel, request), expectedStatus); break; + case Executor::FENCED: + EXPECT_EQ(executeFenced(preparedModel, request), expectedStatus); + break; default: ASSERT_TRUE(false); } @@ -912,7 +915,38 @@ class MemoryDomainExecutionTest return executionStatus; } - // TODO(xusongw): Add executeFenced. + ErrorStatus executeFenced(const sp& preparedModel, const Request& request) { + ErrorStatus executionStatus; + hidl_handle syncFenceHandle; + sp fencedCallback; + const auto callbackFunc = [&executionStatus, &syncFenceHandle, &fencedCallback]( + ErrorStatus error, const hidl_handle& handle, + const sp& callback) { + executionStatus = error; + syncFenceHandle = handle; + fencedCallback = callback; + }; + Return ret = preparedModel->executeFenced(request, {}, MeasureTiming::NO, {}, {}, {}, + callbackFunc); + EXPECT_TRUE(ret.isOk()); + if (executionStatus != ErrorStatus::NONE) { + EXPECT_EQ(syncFenceHandle.getNativeHandle(), nullptr); + EXPECT_EQ(fencedCallback, nullptr); + return executionStatus; + } + if (syncFenceHandle.getNativeHandle()) { + waitForSyncFence(syncFenceHandle.getNativeHandle()->data[0]); + } + EXPECT_NE(fencedCallback, nullptr); + ret = fencedCallback->getExecutionInfo( + [&executionStatus](ErrorStatus error, Timing t, Timing) { + executionStatus = error; + EXPECT_EQ(UINT64_MAX, t.timeOnDevice); + EXPECT_EQ(UINT64_MAX, t.timeInDriver); + }); + EXPECT_TRUE(ret.isOk()); + return executionStatus; + } const Executor kExecutor = std::get(GetParam()); }; @@ -1111,6 +1145,9 @@ TEST_P(MemoryDomainExecutionTest, SameRequestMultipleRoles) { } TEST_P(MemoryDomainExecutionTest, InvalidDimensions) { + // FENCED execution does not support dynamic shape. + if (kExecutor == Executor::FENCED) return; + TestOperand testOperand = kTestOperand; testOperand.dimensions[0] = 0; auto preparedModel = createConvPreparedModel(testOperand); @@ -1148,7 +1185,7 @@ TEST_P(MemoryDomainExecutionTest, InvalidDimensions) { ErrorStatus::GENERAL_FAILURE); } -const auto kExecutorChoices = testing::Values(Executor::ASYNC, Executor::SYNC); +const auto kExecutorChoices = testing::Values(Executor::ASYNC, Executor::SYNC, Executor::FENCED); std::string printMemoryDomainExecutionTest( const testing::TestParamInfo& info) { From 4befcfdddbc2fe47c81e3d301d85736de1688fb2 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Fri, 20 Mar 2020 15:41:06 -0700 Subject: [PATCH 0719/1022] Camera: Update metadata docs to match current API Test: Builds Bug: 150036107 Change-Id: I3e5321e91458d980ad96d3665d9f11bbafb047f1 --- camera/metadata/3.5/types.hal | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal index 4e2252cc5c..60563e29d6 100644 --- a/camera/metadata/3.5/types.hal +++ b/camera/metadata/3.5/types.hal @@ -72,7 +72,7 @@ enum CameraMetadataTag : @3.4::CameraMetadataTag { ANDROID_CONTROL_END_3_5, - /** android.scaler.availableRotateAndCropModes [static, byte[], public] + /** android.scaler.availableRotateAndCropModes [static, byte[], hidden] * *

      List of rotate-and-crop modes for ANDROID_SCALER_ROTATE_AND_CROP that are supported by this camera device.

      * @@ -80,7 +80,7 @@ enum CameraMetadataTag : @3.4::CameraMetadataTag { */ ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES = android.hardware.camera.metadata@3.4::CameraMetadataTag:ANDROID_SCALER_END_3_4, - /** android.scaler.rotateAndCrop [dynamic, enum, public] + /** android.scaler.rotateAndCrop [dynamic, enum, hidden] * *

      Whether a rotation-and-crop operation is applied to processed * outputs from the camera.

      From 20c6369609607680e4933a025d087953a520a03d Mon Sep 17 00:00:00 2001 From: Nazish Tabassum Date: Sat, 14 Mar 2020 11:21:19 +0530 Subject: [PATCH 0720/1022] Documentation for enum PersoSubstate Documentation for Additional personalization categories. - SIM_SPN - SIM_SP_EHPLMN - SIM_ICCID - SIM_IMPI - SIM_NS_SP Bug: 69389695 Test: TH Change-Id: I011c4e67b4189e5db21883f3ac19bee5ea2af250 (cherry picked from commit 0b7f4669ca26249165bba61eb4c65a02fe67edc7) --- current.txt | 2 +- radio/1.5/types.hal | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/current.txt b/current.txt index 5d862d833b..5fbba07f57 100644 --- a/current.txt +++ b/current.txt @@ -681,7 +681,7 @@ e442ab1b440327fe4e8a3b0b8ac6874e9bc6342e91fe976eb9fea77c63961ec8 android.hardwar b454df853441c12f6e425e8a60dd29fda20f5e6e39b93d1103e4b37495db38aa android.hardware.radio@1.5::IRadio fcbb0742a88215ee7a6d7ce0825d253eb2b50391fc6c8c48667f9fd7f6d4549e android.hardware.radio@1.5::IRadioIndication b809193970a91ca637a4b0184767315601d32e3ef3d5992ffbc7a8d14a14f015 android.hardware.radio@1.5::IRadioResponse -e7669bddacbdaee2cd9a87762a13fb7648639eead54bf4d767dc06eaaeb35736 android.hardware.radio@1.5::types +6b8dcd5e3e33a524cc7ebb14671a76ad3a2d333467397ce82acc4024346386f8 android.hardware.radio@1.5::types 3ca6616381080bdd6c08141ad12775a94ae868c58b02b1274ae3326f7de724ab android.hardware.sensors@2.1::ISensors 3d4141c6373cd9ca02fe221a7d12343840de2255d032c38248fe8e35816b58b2 android.hardware.sensors@2.1::ISensorsCallback 8051cc50fc90ed447f058a8b15d81f35a65f1bd9004b1de4f127edeb89b47978 android.hardware.sensors@2.1::types diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index 45f3b9074f..248f56e846 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -1023,16 +1023,37 @@ struct NetworkScanResult { * 3GPP2 C.S0068-0. */ enum PersoSubstate : @1.0::PersoSubstate { + /** + * The device is personalized using the content of the Service Provider Name (SPN) in the SIM + * card. + */ SIM_SPN, SIM_SPN_PUK, - /** Equivalent Home PLMN */ + /** + * Service Provider and Equivalent Home PLMN + * The device is personalized using both the content of the GID1 (equivalent to service provider + * personalization) and the content of the Equivalent Home PLMN (EHPLMN) in the SIM card. + * If the GID1 in the SIM is absent, then just the content of the Equivalent Home PLMN + * is matched. + */ SIM_SP_EHPLMN, SIM_SP_EHPLMN_PUK, + /** + * Device is personalized using the first digits of the ICCID of the SIM card. + */ SIM_ICCID, SIM_ICCID_PUK, + /** + * Device is personalized using the content of the IMPI in the ISIM. + */ SIM_IMPI, SIM_IMPI_PUK, - /** Network subset service provider */ + /** + * Network Subset and Service Provider + * Device is personalized using both the content of GID1 (equivalent to service provider + * personalization) and the first digits of the IMSI (equivalent to network subset + * personalization). + */ SIM_NS_SP, SIM_NS_SP_PUK, }; From d9eb0d743c0c154c32600b22343cfebc466e4ac4 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 20 Mar 2020 15:53:29 -0700 Subject: [PATCH 0721/1022] graphics common: fix AIDL BufferUsage calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was hitting integer sanitization, which we are trying to turn on: Before:     VENDOR_MASK_HI = -65536L, After:     VENDOR_MASK_HI = -281474976710656L, Bug: 148149098 Test: manually check output (see above). Change-Id: I1e2d7c0225aec8bf67375eb6b0cdc919b4ece847 --- .../aidl/android/hardware/graphics/common/BufferUsage.aidl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl b/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl index 5f9888a854..d978f46345 100644 --- a/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl +++ b/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl @@ -110,5 +110,5 @@ enum BufferUsage { /** bits 32-47 must be zero and are reserved for future versions */ /** bits 48-63 are reserved for vendor extensions */ - VENDOR_MASK_HI = 0xffff << 48, + VENDOR_MASK_HI = (1L * 0xffff) << 48, } From 61c3ac2a69cefd1c5d38105fb763d8886f4760e8 Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Fri, 20 Mar 2020 16:15:47 -0700 Subject: [PATCH 0722/1022] Clarify getConcurrentStreamingCameraids may return hidden physical camera ids as well. Bug: 151891611 Test: builds Change-Id: I889065b379d9966e9cc8a225fb335685f2f065cd Signed-off-by: Jayant Chowdhary --- camera/provider/2.6/ICameraProvider.hal | 7 +++++++ current.txt | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/camera/provider/2.6/ICameraProvider.hal b/camera/provider/2.6/ICameraProvider.hal index 5651550e2d..ed1d31dd57 100644 --- a/camera/provider/2.6/ICameraProvider.hal +++ b/camera/provider/2.6/ICameraProvider.hal @@ -76,6 +76,13 @@ 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. + * * @return status Status code for the operation * @return cameraIds a list of camera id combinations that support * concurrent stream configurations with the minimum guarantees diff --git a/current.txt b/current.txt index 5d862d833b..0cb2fde1bf 100644 --- a/current.txt +++ b/current.txt @@ -641,7 +641,7 @@ ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardwar 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types b8c63679e1a3874b356f3e691aecce1191d38f59063cf2ed2dce8a9d4cabf00e android.hardware.camera.device@3.6::ICameraDevice a35d5151b48505f06a775b38c0e2e265f80a845d92802324c643565807f81c53 android.hardware.camera.device@3.6::types -99aae72ae75a8ddf63ccffbc585f3a55f4d0847b4adff3d7a0f8bd9e2305bec1 android.hardware.camera.provider@2.6::ICameraProvider +21086e1c7a2acc0ebe0ff8561b11f3c2009be687a92d79b608a5f00b16c5f598 android.hardware.camera.provider@2.6::ICameraProvider 8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas 9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener From 921e1ec2dc2ec5d92019649b9fec7b2ee14449c9 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Fri, 20 Mar 2020 22:19:35 -0700 Subject: [PATCH 0723/1022] Add EVS 1.1 to current compatibility matrix Fix: 152099395 Test: m -j Change-Id: Idd227e110490c68e98b4270cc5c12e04aceb7fbb --- compatibility_matrices/compatibility_matrix.current.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index c5a9102c33..a1705de9ec 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -53,7 +53,7 @@
      android.hardware.automotive.evs - 1.0 + 1.0-1 IEvsEnumerator default From 593dbfc1541c7905396c834a24613c93fdbe55f7 Mon Sep 17 00:00:00 2001 From: Ryanne Cheng Date: Mon, 23 Mar 2020 01:39:13 +0000 Subject: [PATCH 0724/1022] Revert "Drop GNSS1.1 and Thermal1.0" Revert "Check unused HALs when system ext matrix exists." Revert "Use HIDL metadata for deprecation check" Revert submission 10745362-check_unused Reason for revert: Droidcop: Potential culprit for Bug 152161259 Reverted Changes: I92cd7ce1c:Use HIDL metadata for deprecation check I2b9492eec:Fix check deprecation to use Hidl Metadata. I6e40a49d5:Add no unused hals test Ia352a979d:Delete unused GNSS@2.0 Thermal@2.0 checks I1c0ef715b:checkUnusedHals: use hidl metadata I44a5240e8:Check unused HALs on device with target FCM versio... I5c5ec4891:Check unused HALs when system ext matrix exists. I17894c025:Add libhidlmetadata_headers I2c7cbf8f5:Drop GNSS1.1 and Thermal1.0 Change-Id: Id1174fec4b5a8dbab2078470d89943935aa1c4be --- compatibility_matrices/compatibility_matrix.4.xml | 7 +++++++ compatibility_matrices/compatibility_matrix.current.xml | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/compatibility_matrices/compatibility_matrix.4.xml b/compatibility_matrices/compatibility_matrix.4.xml index e5e012cbb3..01ec172d89 100644 --- a/compatibility_matrices/compatibility_matrix.4.xml +++ b/compatibility_matrices/compatibility_matrix.4.xml @@ -181,6 +181,12 @@ android.hardware.gnss + + 1.1 2.0 IGnss @@ -423,6 +429,7 @@ android.hardware.thermal + 1.0-1 2.0 IThermal diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 1861b1cd8d..de1ee8445c 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -197,6 +197,12 @@ android.hardware.gnss + + 1.1 2.0-1 IGnss @@ -445,6 +451,7 @@ android.hardware.thermal + 1.0 2.0 IThermal From 229528a08fcb723af414cf5403b429b8fd617c8a Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Fri, 21 Feb 2020 21:17:06 +0900 Subject: [PATCH 0725/1022] use vector for byte[] in AIDL In native world, byte stream is typically represented in uint8_t[] or vector. C++ backend already generates that way. This change involves NDK backend. Now NDK backend also uses vector just like C++ backend. Bug: 144957764 Test: atest CtsNdkBinderTestCases Merged-In: I8de348b57cf92dd99b3ee16252f56300ce5f4683 Change-Id: I8de348b57cf92dd99b3ee16252f56300ce5f4683 (cherry picked from commit 9070318462e5e73acf1509cf7e75ac260e51e43a) Exempt-From-Owner-Approval: cp from master to avoid merge-conflict --- identity/aidl/default/IdentityCredential.cpp | 50 ++++++++----------- identity/aidl/default/IdentityCredential.h | 22 ++++---- .../aidl/default/IdentityCredentialStore.cpp | 6 +-- .../aidl/default/IdentityCredentialStore.h | 2 +- identity/aidl/default/Util.cpp | 13 +---- identity/aidl/default/Util.h | 4 -- .../default/WritableIdentityCredential.cpp | 26 +++++----- .../aidl/default/WritableIdentityCredential.h | 12 ++--- rebootescrow/aidl/default/RebootEscrow.cpp | 8 ++- .../include/rebootescrow-impl/RebootEscrow.h | 4 +- 10 files changed, 62 insertions(+), 85 deletions(-) diff --git a/identity/aidl/default/IdentityCredential.cpp b/identity/aidl/default/IdentityCredential.cpp index 341fae6e93..aaae1f6ae5 100644 --- a/identity/aidl/default/IdentityCredential.cpp +++ b/identity/aidl/default/IdentityCredential.cpp @@ -102,7 +102,7 @@ int IdentityCredential::initialize() { } ndk::ScopedAStatus IdentityCredential::deleteCredential( - vector* outProofOfDeletionSignature) { + vector* outProofOfDeletionSignature) { cppbor::Array array = {"ProofOfDeletion", docType_, testCredential_}; vector proofOfDeletion = array.encode(); @@ -115,11 +115,11 @@ ndk::ScopedAStatus IdentityCredential::deleteCredential( IIdentityCredentialStore::STATUS_FAILED, "Error signing data")); } - *outProofOfDeletionSignature = byteStringToSigned(signature.value()); + *outProofOfDeletionSignature = signature.value(); return ndk::ScopedAStatus::ok(); } -ndk::ScopedAStatus IdentityCredential::createEphemeralKeyPair(vector* outKeyPair) { +ndk::ScopedAStatus IdentityCredential::createEphemeralKeyPair(vector* outKeyPair) { optional> kp = support::createEcKeyPair(); if (!kp) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( @@ -135,13 +135,13 @@ ndk::ScopedAStatus IdentityCredential::createEphemeralKeyPair(vector* ou } ephemeralPublicKey_ = publicKey.value(); - *outKeyPair = byteStringToSigned(kp.value()); + *outKeyPair = kp.value(); return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus IdentityCredential::setReaderEphemeralPublicKey( - const vector& publicKey) { - readerPublicKey_ = byteStringToUnsigned(publicKey); + const vector& publicKey) { + readerPublicKey_ = publicKey; return ndk::ScopedAStatus::ok(); } @@ -169,8 +169,8 @@ ndk::ScopedAStatus IdentityCredential::createAuthChallenge(int64_t* outChallenge // ahead of time. bool checkReaderAuthentication(const SecureAccessControlProfile& profile, const vector& readerCertificateChain) { - optional> acpPubKey = support::certificateChainGetTopMostKey( - byteStringToUnsigned(profile.readerCertificate.encodedCertificate)); + optional> acpPubKey = + support::certificateChainGetTopMostKey(profile.readerCertificate.encodedCertificate); if (!acpPubKey) { LOG(ERROR) << "Error extracting public key from readerCertificate in profile"; return false; @@ -255,13 +255,9 @@ bool checkUserAuthentication(const SecureAccessControlProfile& profile, ndk::ScopedAStatus IdentityCredential::startRetrieval( const vector& accessControlProfiles, - const HardwareAuthToken& authToken, const vector& itemsRequestS, - const vector& signingKeyBlobS, const vector& sessionTranscriptS, - const vector& readerSignatureS, const vector& requestCounts) { - auto sessionTranscript = byteStringToUnsigned(sessionTranscriptS); - auto itemsRequest = byteStringToUnsigned(itemsRequestS); - auto readerSignature = byteStringToUnsigned(readerSignatureS); - + const HardwareAuthToken& authToken, const vector& itemsRequest, + const vector& signingKeyBlob, const vector& sessionTranscript, + const vector& readerSignature, const vector& requestCounts) { if (sessionTranscript.size() > 0) { auto [item, _, message] = cppbor::parse(sessionTranscript); if (item == nullptr) { @@ -498,7 +494,7 @@ ndk::ScopedAStatus IdentityCredential::startRetrieval( currentNameSpace_ = ""; itemsRequest_ = itemsRequest; - signingKeyBlob_ = byteStringToUnsigned(signingKeyBlobS); + signingKeyBlob_ = signingKeyBlob; numStartRetrievalCalls_ += 1; return ndk::ScopedAStatus::ok(); @@ -605,10 +601,8 @@ ndk::ScopedAStatus IdentityCredential::startRetrieveEntryValue( return ndk::ScopedAStatus::ok(); } -ndk::ScopedAStatus IdentityCredential::retrieveEntryValue(const vector& encryptedContentS, - vector* outContent) { - auto encryptedContent = byteStringToUnsigned(encryptedContentS); - +ndk::ScopedAStatus IdentityCredential::retrieveEntryValue(const vector& encryptedContent, + vector* outContent) { optional> content = support::decryptAes128Gcm(storageKey_, encryptedContent, entryAdditionalData_); if (!content) { @@ -647,12 +641,12 @@ ndk::ScopedAStatus IdentityCredential::retrieveEntryValue(const vector& currentNameSpaceDeviceNameSpacesMap_.add(currentName_, std::move(entryValueItem)); } - *outContent = byteStringToSigned(content.value()); + *outContent = content.value(); return ndk::ScopedAStatus::ok(); } -ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector* outMac, - vector* outDeviceNameSpaces) { +ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector* outMac, + vector* outDeviceNameSpaces) { if (currentNameSpaceDeviceNameSpacesMap_.size() > 0) { deviceNameSpacesMap_.add(currentNameSpace_, std::move(currentNameSpaceDeviceNameSpacesMap_)); @@ -704,13 +698,13 @@ ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector* outMac, } } - *outMac = byteStringToSigned(mac.value_or(vector({}))); - *outDeviceNameSpaces = byteStringToSigned(encodedDeviceNameSpaces); + *outMac = mac.value_or(vector({})); + *outDeviceNameSpaces = encodedDeviceNameSpaces; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus IdentityCredential::generateSigningKeyPair( - vector* outSigningKeyBlob, Certificate* outSigningKeyCertificate) { + vector* outSigningKeyBlob, Certificate* outSigningKeyCertificate) { string serialDecimal = "0"; // TODO: set serial to something unique string issuer = "Android Open Source Project"; string subject = "Android IdentityCredential Reference Implementation"; @@ -758,9 +752,9 @@ ndk::ScopedAStatus IdentityCredential::generateSigningKeyPair( return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, "Error encrypting signingKey")); } - *outSigningKeyBlob = byteStringToSigned(encryptedSigningKey.value()); + *outSigningKeyBlob = encryptedSigningKey.value(); *outSigningKeyCertificate = Certificate(); - outSigningKeyCertificate->encodedCertificate = byteStringToSigned(certificate.value()); + outSigningKeyCertificate->encodedCertificate = certificate.value(); return ndk::ScopedAStatus::ok(); } diff --git a/identity/aidl/default/IdentityCredential.h b/identity/aidl/default/IdentityCredential.h index fc29254f4b..6072afe04f 100644 --- a/identity/aidl/default/IdentityCredential.h +++ b/identity/aidl/default/IdentityCredential.h @@ -47,23 +47,23 @@ class IdentityCredential : public BnIdentityCredential { int initialize(); // Methods from IIdentityCredential follow. - ndk::ScopedAStatus deleteCredential(vector* outProofOfDeletionSignature) override; - ndk::ScopedAStatus createEphemeralKeyPair(vector* outKeyPair) override; - ndk::ScopedAStatus setReaderEphemeralPublicKey(const vector& publicKey) override; + ndk::ScopedAStatus deleteCredential(vector* outProofOfDeletionSignature) override; + ndk::ScopedAStatus createEphemeralKeyPair(vector* outKeyPair) override; + ndk::ScopedAStatus setReaderEphemeralPublicKey(const vector& publicKey) override; ndk::ScopedAStatus createAuthChallenge(int64_t* outChallenge) override; ndk::ScopedAStatus startRetrieval( const vector& accessControlProfiles, - const HardwareAuthToken& authToken, const vector& itemsRequest, - const vector& signingKeyBlob, const vector& sessionTranscript, - const vector& readerSignature, const vector& requestCounts) override; + const HardwareAuthToken& authToken, const vector& itemsRequest, + const vector& signingKeyBlob, const vector& sessionTranscript, + const vector& readerSignature, const vector& requestCounts) override; ndk::ScopedAStatus startRetrieveEntryValue( const string& nameSpace, const string& name, int32_t entrySize, const vector& accessControlProfileIds) override; - ndk::ScopedAStatus retrieveEntryValue(const vector& encryptedContent, - vector* outContent) override; - ndk::ScopedAStatus finishRetrieval(vector* outMac, - vector* outDeviceNameSpaces) override; - ndk::ScopedAStatus generateSigningKeyPair(vector* outSigningKeyBlob, + ndk::ScopedAStatus retrieveEntryValue(const vector& encryptedContent, + vector* outContent) override; + ndk::ScopedAStatus finishRetrieval(vector* outMac, + vector* outDeviceNameSpaces) override; + ndk::ScopedAStatus generateSigningKeyPair(vector* outSigningKeyBlob, Certificate* outSigningKeyCertificate) override; private: diff --git a/identity/aidl/default/IdentityCredentialStore.cpp b/identity/aidl/default/IdentityCredentialStore.cpp index 1efb4b4937..30dc6f330b 100644 --- a/identity/aidl/default/IdentityCredentialStore.cpp +++ b/identity/aidl/default/IdentityCredentialStore.cpp @@ -51,7 +51,7 @@ ndk::ScopedAStatus IdentityCredentialStore::createCredential( } ndk::ScopedAStatus IdentityCredentialStore::getCredential( - CipherSuite cipherSuite, const vector& credentialData, + CipherSuite cipherSuite, const vector& credentialData, shared_ptr* outCredential) { // We only support CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 right now. if (cipherSuite != CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256) { @@ -60,8 +60,8 @@ ndk::ScopedAStatus IdentityCredentialStore::getCredential( "Unsupported cipher suite")); } - vector data = vector(credentialData.begin(), credentialData.end()); - shared_ptr credential = ndk::SharedRefBase::make(data); + shared_ptr credential = + ndk::SharedRefBase::make(credentialData); auto ret = credential->initialize(); if (ret != IIdentityCredentialStore::STATUS_OK) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( diff --git a/identity/aidl/default/IdentityCredentialStore.h b/identity/aidl/default/IdentityCredentialStore.h index a2051130b0..4f3a42139f 100644 --- a/identity/aidl/default/IdentityCredentialStore.h +++ b/identity/aidl/default/IdentityCredentialStore.h @@ -39,7 +39,7 @@ class IdentityCredentialStore : public BnIdentityCredentialStore { const string& docType, bool testCredential, shared_ptr* outWritableCredential) override; - ndk::ScopedAStatus getCredential(CipherSuite cipherSuite, const vector& credentialData, + ndk::ScopedAStatus getCredential(CipherSuite cipherSuite, const vector& credentialData, shared_ptr* outCredential) override; }; diff --git a/identity/aidl/default/Util.cpp b/identity/aidl/default/Util.cpp index a0f86bedcd..66b9f13d89 100644 --- a/identity/aidl/default/Util.cpp +++ b/identity/aidl/default/Util.cpp @@ -39,21 +39,12 @@ const vector& getHardwareBoundKey() { return hardwareBoundKey; } -vector byteStringToUnsigned(const vector& value) { - return vector(value.begin(), value.end()); -} - -vector byteStringToSigned(const vector& value) { - return vector(value.begin(), value.end()); -} - vector secureAccessControlProfileEncodeCbor(const SecureAccessControlProfile& profile) { cppbor::Map map; map.add("id", profile.id); if (profile.readerCertificate.encodedCertificate.size() > 0) { - map.add("readerCertificate", - cppbor::Bstr(byteStringToUnsigned(profile.readerCertificate.encodedCertificate))); + map.add("readerCertificate", cppbor::Bstr(profile.readerCertificate.encodedCertificate)); } if (profile.userAuthenticationRequired) { @@ -94,7 +85,7 @@ bool secureAccessControlProfileCheckMac(const SecureAccessControlProfile& profil if (!mac) { return false; } - if (mac.value() != byteStringToUnsigned(profile.mac)) { + if (mac.value() != profile.mac) { return false; } return true; diff --git a/identity/aidl/default/Util.h b/identity/aidl/default/Util.h index ee41ad1aac..9fccba2c72 100644 --- a/identity/aidl/default/Util.h +++ b/identity/aidl/default/Util.h @@ -49,10 +49,6 @@ bool secureAccessControlProfileCheckMac(const SecureAccessControlProfile& profil vector entryCreateAdditionalData(const string& nameSpace, const string& name, const vector accessControlProfileIds); -vector byteStringToUnsigned(const vector& value); - -vector byteStringToSigned(const vector& value); - } // namespace aidl::android::hardware::identity #endif // ANDROID_HARDWARE_IDENTITY_UTIL_H diff --git a/identity/aidl/default/WritableIdentityCredential.cpp b/identity/aidl/default/WritableIdentityCredential.cpp index 89f7f35696..bce913aeec 100644 --- a/identity/aidl/default/WritableIdentityCredential.cpp +++ b/identity/aidl/default/WritableIdentityCredential.cpp @@ -53,8 +53,8 @@ bool WritableIdentityCredential::initialize() { // attestation certificate with current time and expires one year from now. The // certificate shall contain all values as specified in hal. ndk::ScopedAStatus WritableIdentityCredential::getAttestationCertificate( - const vector& attestationApplicationId, // - const vector& attestationChallenge, // + const vector& attestationApplicationId, // + const vector& attestationChallenge, // vector* outCertificateChain) { if (!credentialPrivKey_.empty() || !credentialPubKey_.empty() || !certificateChain_.empty()) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( @@ -97,7 +97,7 @@ ndk::ScopedAStatus WritableIdentityCredential::getAttestationCertificate( *outCertificateChain = vector(); for (const vector& cert : certificateChain_) { Certificate c = Certificate(); - c.encodedCertificate = byteStringToSigned(cert); + c.encodedCertificate = cert; outCertificateChain->push_back(std::move(c)); } return ndk::ScopedAStatus::ok(); @@ -146,14 +146,13 @@ ndk::ScopedAStatus WritableIdentityCredential::addAccessControlProfile( return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, "Error calculating MAC for profile")); } - profile.mac = byteStringToSigned(mac.value()); + profile.mac = mac.value(); cppbor::Map profileMap; profileMap.add("id", profile.id); if (profile.readerCertificate.encodedCertificate.size() > 0) { - profileMap.add( - "readerCertificate", - cppbor::Bstr(byteStringToUnsigned(profile.readerCertificate.encodedCertificate))); + profileMap.add("readerCertificate", + cppbor::Bstr(profile.readerCertificate.encodedCertificate)); } if (profile.userAuthenticationRequired) { profileMap.add("userAuthenticationRequired", profile.userAuthenticationRequired); @@ -223,9 +222,8 @@ ndk::ScopedAStatus WritableIdentityCredential::beginAddEntry( return ndk::ScopedAStatus::ok(); } -ndk::ScopedAStatus WritableIdentityCredential::addEntryValue(const vector& contentS, - vector* outEncryptedContent) { - auto content = byteStringToUnsigned(contentS); +ndk::ScopedAStatus WritableIdentityCredential::addEntryValue(const vector& content, + vector* outEncryptedContent) { size_t contentSize = content.size(); if (contentSize > IdentityCredentialStore::kGcmChunkSize) { @@ -280,7 +278,7 @@ ndk::ScopedAStatus WritableIdentityCredential::addEntryValue(const vector& hardwareBoundKey, const strin } ndk::ScopedAStatus WritableIdentityCredential::finishAddingEntries( - vector* outCredentialData, vector* outProofOfProvisioningSignature) { + vector* outCredentialData, vector* outProofOfProvisioningSignature) { if (signedDataCurrentNamespace_.size() > 0) { signedDataNamespaces_.add(entryNameSpace_, std::move(signedDataCurrentNamespace_)); } @@ -364,8 +362,8 @@ ndk::ScopedAStatus WritableIdentityCredential::finishAddingEntries( IIdentityCredentialStore::STATUS_FAILED, "Error generating CredentialData")); } - *outCredentialData = byteStringToSigned(credentialData); - *outProofOfProvisioningSignature = byteStringToSigned(signature.value()); + *outCredentialData = credentialData; + *outProofOfProvisioningSignature = signature.value(); return ndk::ScopedAStatus::ok(); } diff --git a/identity/aidl/default/WritableIdentityCredential.h b/identity/aidl/default/WritableIdentityCredential.h index b182862862..4b6fca8d91 100644 --- a/identity/aidl/default/WritableIdentityCredential.h +++ b/identity/aidl/default/WritableIdentityCredential.h @@ -37,8 +37,8 @@ class WritableIdentityCredential : public BnWritableIdentityCredential { bool initialize(); // Methods from IWritableIdentityCredential follow. - ndk::ScopedAStatus getAttestationCertificate(const vector& attestationApplicationId, - const vector& attestationChallenge, + ndk::ScopedAStatus getAttestationCertificate(const vector& attestationApplicationId, + const vector& attestationChallenge, vector* outCertificateChain) override; ndk::ScopedAStatus startPersonalization(int32_t accessControlProfileCount, @@ -53,12 +53,12 @@ class WritableIdentityCredential : public BnWritableIdentityCredential { const string& nameSpace, const string& name, int32_t entrySize) override; - ndk::ScopedAStatus addEntryValue(const vector& content, - vector* outEncryptedContent) override; + ndk::ScopedAStatus addEntryValue(const vector& content, + vector* outEncryptedContent) override; ndk::ScopedAStatus finishAddingEntries( - vector* outCredentialData, - vector* outProofOfProvisioningSignature) override; + vector* outCredentialData, + vector* outProofOfProvisioningSignature) override; // private: string docType_; diff --git a/rebootescrow/aidl/default/RebootEscrow.cpp b/rebootescrow/aidl/default/RebootEscrow.cpp index dbc09215b3..8e5e97c80c 100644 --- a/rebootescrow/aidl/default/RebootEscrow.cpp +++ b/rebootescrow/aidl/default/RebootEscrow.cpp @@ -28,7 +28,7 @@ namespace rebootescrow { using ::android::base::unique_fd; -ndk::ScopedAStatus RebootEscrow::storeKey(const std::vector& kek) { +ndk::ScopedAStatus RebootEscrow::storeKey(const std::vector& ukek) { int rawFd = TEMP_FAILURE_RETRY(::open(devicePath_.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC)); unique_fd fd(rawFd); if (fd.get() < 0) { @@ -36,7 +36,6 @@ ndk::ScopedAStatus RebootEscrow::storeKey(const std::vector& kek) { return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); } - std::vector ukek(kek.begin(), kek.end()); auto encoded = hadamard::EncodeKey(ukek); if (!::android::base::WriteFully(fd, encoded.data(), encoded.size())) { @@ -47,7 +46,7 @@ ndk::ScopedAStatus RebootEscrow::storeKey(const std::vector& kek) { return ndk::ScopedAStatus::ok(); } -ndk::ScopedAStatus RebootEscrow::retrieveKey(std::vector* _aidl_return) { +ndk::ScopedAStatus RebootEscrow::retrieveKey(std::vector* _aidl_return) { int rawFd = TEMP_FAILURE_RETRY(::open(devicePath_.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)); unique_fd fd(rawFd); if (fd.get() < 0) { @@ -63,8 +62,7 @@ ndk::ScopedAStatus RebootEscrow::retrieveKey(std::vector* _aidl_return) auto keyBytes = hadamard::DecodeKey(encodedBytes); - std::vector signedKeyBytes(keyBytes.begin(), keyBytes.end()); - *_aidl_return = signedKeyBytes; + *_aidl_return = keyBytes; return ndk::ScopedAStatus::ok(); } diff --git a/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h index 00ff16b2ea..cdbeb67eba 100644 --- a/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h +++ b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h @@ -26,8 +26,8 @@ namespace rebootescrow { class RebootEscrow : public BnRebootEscrow { public: explicit RebootEscrow(const std::string& devicePath) : devicePath_(devicePath) {} - ndk::ScopedAStatus storeKey(const std::vector& kek) override; - ndk::ScopedAStatus retrieveKey(std::vector* _aidl_return) override; + ndk::ScopedAStatus storeKey(const std::vector& kek) override; + ndk::ScopedAStatus retrieveKey(std::vector* _aidl_return) override; private: const std::string devicePath_; From c932298d6d9b482f9f769389c71cc7e432bf19d1 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Mon, 23 Mar 2020 09:30:27 -0700 Subject: [PATCH 0726/1022] Add tv.tuner to current compatibility matrix. Fixes build. Bug: 152161259 Test: builds Change-Id: I199d88f70505abdceba8a58a7986349b230f6353 --- compatibility_matrices/compatibility_matrix.current.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 51c65461b1..e43fbb4812 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -493,6 +493,14 @@ default + + android.hardware.tv.tuner + 1.0 + + ITuner + default + + android.hardware.usb 1.0-2 From eb5c657bc7656a1d0394ef34734409ce502b0c78 Mon Sep 17 00:00:00 2001 From: felipeal Date: Fri, 20 Mar 2020 18:30:50 -0700 Subject: [PATCH 0727/1022] Implemented SWITCH_USER in the emulated User HAL. Examples: $ adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default --user-hal No InitialUserInfo response No SwitchUser response $ adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default --set 299896584 a 1 i 666 i 3 i 1 s "D\\'OH!" Set property {.timestamp = 63698971001637, .areaId = 1, .prop = 299896584, .status = AVAILABLE, .value = {.int32Values = [3]{666, 3, 1}, .floatValues = [0]{}, .int64Values = [0]{}, .bytes = [0]{}, .stringValue = "D'OH!"}} $ adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default --user-hal No InitialUserInfo response SwitchUser response: {.timestamp = 63698971001637, .areaId = 1, .prop = 299896584, .status = AVAILABLE, .value = {.int32Values = [3]{666, 3, 1}, .floatValues = [0]{}, .int64Values = [0]{}, .bytes = [0]{}, .stringValue = "D'OH!"}} Test: see commands above Bug: 150409110 Change-Id: Id5b92774fccebbc39ed8d3f553df3f5aa30fc656 --- .../default/impl/vhal_v2_0/DefaultConfig.h | 9 +++ .../vhal_v2_0/EmulatedVehicleConnector.cpp | 10 ++- .../impl/vhal_v2_0/VehicleHalServer.cpp | 81 ++++++++++++++++++- .../default/impl/vhal_v2_0/VehicleHalServer.h | 6 +- 4 files changed, 98 insertions(+), 8 deletions(-) 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 53c9ffb99f..ea759867f2 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 @@ -80,6 +80,7 @@ constexpr int WHEEL_FRONT_RIGHT = (int)VehicleAreaWheel::RIGHT_FRONT; constexpr int WHEEL_REAR_LEFT = (int)VehicleAreaWheel::LEFT_REAR; constexpr int WHEEL_REAR_RIGHT = (int)VehicleAreaWheel::RIGHT_REAR; constexpr int INITIAL_USER_INFO = (int)VehicleProperty::INITIAL_USER_INFO; +constexpr int SWITCH_USER = (int)VehicleProperty::SWITCH_USER; /** * This property is used for test purpose to generate fake events. Here is the test package that @@ -1019,6 +1020,14 @@ const ConfigDeclaration kVehicleProperties[]{ .changeMode = VehiclePropertyChangeMode::ON_CHANGE, }, }, + { + .config = + { + .prop = toInt(VehicleProperty::SWITCH_USER), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + }, }; } // impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp index 9c3c95facd..ce7dc65127 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp @@ -73,10 +73,16 @@ bool EmulatedPassthroughConnector::onDump(const hidl_handle& handle, void EmulatedPassthroughConnector::dumpUserHal(int fd, std::string indent) { if (mInitialUserResponseFromCmd != nullptr) { - dprintf(fd, "%sInitial User Info: %s\n", indent.c_str(), + dprintf(fd, "%sInitialUserInfo response: %s\n", indent.c_str(), toString(*mInitialUserResponseFromCmd).c_str()); } else { - dprintf(fd, "%sNo Initial User Info\n", indent.c_str()); + dprintf(fd, "%sNo InitialUserInfo response\n", indent.c_str()); + } + if (mSwitchUserResponseFromCmd != nullptr) { + dprintf(fd, "%sSwitchUser response: %s\n", indent.c_str(), + toString(*mSwitchUserResponseFromCmd).c_str()); + } else { + dprintf(fd, "%sNo SwitchUser response\n", indent.c_str()); } } diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp index a91ca8e770..70e39ebdbf 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define LOG_TAG "VehicleHalServer" + #include "VehicleHalServer.h" #include @@ -244,7 +246,9 @@ StatusCode VehicleHalServer::onSetProperty(const VehiclePropValue& value, bool u } break; case INITIAL_USER_INFO: - return onSetInitialUserInfo(value, updateStatus); + return onSetInitialUserInfoResponse(value, updateStatus); + case SWITCH_USER: + return onSetSwitchUserResponse(value, updateStatus); default: break; } @@ -282,8 +286,8 @@ StatusCode VehicleHalServer::onSetProperty(const VehiclePropValue& value, bool u * - if it's 3, then don't send a property change (so Android can emulate a timeout) * */ -StatusCode VehicleHalServer::onSetInitialUserInfo(const VehiclePropValue& value, - bool updateStatus) { +StatusCode VehicleHalServer::onSetInitialUserInfoResponse(const VehiclePropValue& value, + bool updateStatus) { // TODO: LOG calls below might be more suited to be DEBUG, but those are not being logged // (even when explicitly calling setprop log.tag. As this class should be using ALOG instead of // LOG, it's not worth investigating why... @@ -320,7 +324,7 @@ StatusCode VehicleHalServer::onSetInitialUserInfo(const VehiclePropValue& value, // mInitialUserResponseFromCmd is used for just one request std::unique_ptr response = std::move(mInitialUserResponseFromCmd); - // TODO(b/138709788): rather than populate the raw values directly, it should use the + // TODO(b/150409377): rather than populate the raw values directly, it should use the // libraries that convert a InitialUserInfoResponse into a VehiclePropValue) switch (response->areaId) { @@ -350,4 +354,73 @@ StatusCode VehicleHalServer::onSetInitialUserInfo(const VehiclePropValue& value, return StatusCode::OK; } +/** + * Used to emulate SWITCH_USER - see onSetInitialUserInfoResponse() for usage. + */ +StatusCode VehicleHalServer::onSetSwitchUserResponse(const VehiclePropValue& value, + bool updateStatus) { + if (value.value.int32Values.size() == 0) { + LOG(ERROR) << "set(SWITCH_USER): no int32values, ignoring it: " << toString(value); + return StatusCode::INVALID_ARG; + } + + if (value.areaId != 0) { + LOG(INFO) << "set(SWITCH_USER) called from lshal; storing it: " << toString(value); + mSwitchUserResponseFromCmd.reset(new VehiclePropValue(value)); + return StatusCode::OK; + } + LOG(INFO) << "set(SWITCH_USER) called from Android: " << toString(value); + + int32_t requestId = value.value.int32Values[0]; + + // Create the update property and set common values + auto updatedValue = createVehiclePropValue(VehiclePropertyType::MIXED, 0); + updatedValue->prop = SWITCH_USER; + updatedValue->timestamp = elapsedRealtimeNano(); + + if (mSwitchUserResponseFromCmd == nullptr) { + updatedValue->value.int32Values.resize(3); + updatedValue->value.int32Values[0] = requestId; + updatedValue->value.int32Values[1] = (int32_t)SwitchUserMessageType::VEHICLE_RESPONSE; + updatedValue->value.int32Values[2] = (int32_t)SwitchUserStatus::SUCCESS; + LOG(INFO) << "no lshal response; returning VEHICLE_RESPONSE / SUCCESS: " + << toString(*updatedValue); + onPropertyValueFromCar(*updatedValue, updateStatus); + return StatusCode::OK; + } + + // mSwitchUserResponseFromCmd is used for just one request + std::unique_ptr response = std::move(mSwitchUserResponseFromCmd); + + // TODO(b/150409377): move code below to a local function like sendUserHalResponse(), + // as it's the same for all (like onSetInitialUserInfoResponse) + + switch (response->areaId) { + case 1: + LOG(INFO) << "returning response with right request id"; + *updatedValue = *response; + updatedValue->areaId = 0; + updatedValue->value.int32Values[0] = requestId; + break; + case 2: + LOG(INFO) << "returning response with wrong request id"; + *updatedValue = *response; + updatedValue->areaId = 0; + updatedValue->value.int32Values[0] = -requestId; + break; + case 3: + LOG(INFO) << "not generating a property change event because of lshal prop: " + << toString(*response); + return StatusCode::OK; + default: + LOG(ERROR) << "invalid action on lshal response: " << toString(*response); + return StatusCode::INTERNAL_ERROR; + } + + LOG(INFO) << "updating property to: " << toString(*updatedValue); + onPropertyValueFromCar(*updatedValue, updateStatus); + + return StatusCode::OK; +} + } // namespace android::hardware::automotive::vehicle::V2_0::impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h index b1ae106331..20e094a00f 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h @@ -53,13 +53,15 @@ class VehicleHalServer : public IVehicleServer { VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay); - StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus); + StatusCode onSetInitialUserInfoResponse(const VehiclePropValue& value, bool updateStatus); + StatusCode onSetSwitchUserResponse(const VehiclePropValue& value, bool updateStatus); - // data members + // data members protected: // TODO(b/146207078): it might be clearer to move members below to an EmulatedUserHal class std::unique_ptr mInitialUserResponseFromCmd; + std::unique_ptr mSwitchUserResponseFromCmd; private: GeneratorHub mGeneratorHub{ From 47def08db84edcda9ce67668ad4fc1cb407e0c60 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Mon, 23 Mar 2020 16:32:40 +0000 Subject: [PATCH 0728/1022] Revert^2 "Drop GNSS1.1 and Thermal1.0" 593dbfc1541c7905396c834a24613c93fdbe55f7 Bug: 131717099 Change-Id: Ie706207523b3b6183933b76b0ab24d9c21938a86 --- compatibility_matrices/compatibility_matrix.4.xml | 7 ------- compatibility_matrices/compatibility_matrix.current.xml | 7 ------- 2 files changed, 14 deletions(-) diff --git a/compatibility_matrices/compatibility_matrix.4.xml b/compatibility_matrices/compatibility_matrix.4.xml index 01ec172d89..e5e012cbb3 100644 --- a/compatibility_matrices/compatibility_matrix.4.xml +++ b/compatibility_matrices/compatibility_matrix.4.xml @@ -181,12 +181,6 @@ android.hardware.gnss - - 1.1 2.0 IGnss @@ -429,7 +423,6 @@ android.hardware.thermal - 1.0-1 2.0 IThermal diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index de1ee8445c..1861b1cd8d 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -197,12 +197,6 @@ android.hardware.gnss - - 1.1 2.0-1 IGnss @@ -451,7 +445,6 @@ android.hardware.thermal - 1.0 2.0 IThermal From ad7678c8cb77372ff58c50b9ac142e828ef3764c Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Fri, 20 Mar 2020 15:09:29 -0700 Subject: [PATCH 0729/1022] Fix the timing initialization error for failed executeFenced case Fixes: 152075771 Test: mm Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: I5829397346354ee3fc4a58b0a418197a1eee47cc --- neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 5689a39e1b..81148b425b 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -648,6 +648,7 @@ void EvaluatePreparedModel(const sp& device, const sp& ASSERT_EQ(syncFenceHandle.getNativeHandle(), nullptr); ASSERT_EQ(fencedCallback, nullptr); executionStatus = result; + timing = {UINT64_MAX, UINT64_MAX}; } else if (syncFenceHandle.getNativeHandle()) { // If a sync fence is returned, try start another run waiting for the sync fence. ret = preparedModel->executeFenced(request, {syncFenceHandle}, From 113bd8111a04b3eef9970144800b1e5db1d57776 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Wed, 18 Mar 2020 14:37:43 -0700 Subject: [PATCH 0730/1022] Audio Effects: Skip CheckConfig test for non-matching HAL versions In vts-core a test suite for version N can be called for HAL of version M. Since in the case of the Effects HAL the XSD configuration for the effects is version-dependent, the test must not validate the effects config using XSD file for other version. Thus, the configuration validity check must be skipped if no corresponding version of IEffectsFactory is found on the device. Bug: 142397658 Bug: 146015418 Test: atest VtsHalAudioEffectV6_0TargetTest on a device that uses earlier version of Audio HAL; CheckConfig#audioEffectsConfigurationValidation must be IGNORED Change-Id: I4b34cc34091447c04bf8d3e988c9bd4048dc8ef9 Merged-In: I4b34cc34091447c04bf8d3e988c9bd4048dc8ef9 --- .../functional/ValidateAudioEffectsConfiguration.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp b/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp index f9e4aa30eb..9c0135bf93 100644 --- a/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp +++ b/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp @@ -18,6 +18,12 @@ #include #include +// clang-format off +#include PATH(android/hardware/audio/effect/FILE_VERSION/IEffectsFactory.h) +// clang-format on + +#include +#include #include "utility/ValidateXml.h" @@ -29,6 +35,11 @@ TEST(CheckConfig, audioEffectsConfigurationValidation) { RecordProperty("description", "Verify that the effects configuration file is valid according to the schema"); using namespace android::effectsConfig; + if (android::hardware::getAllHalInstanceNames( + ::android::hardware::audio::effect::CPP_VERSION::IEffectsFactory::descriptor) + .size() == 0) { + GTEST_SKIP() << "No Effects HAL version " STRINGIFY(CPP_VERSION) " on this device"; + } std::vector locations(std::begin(DEFAULT_LOCATIONS), std::end(DEFAULT_LOCATIONS)); const char* xsd = "/data/local/tmp/audio_effects_conf_" STRINGIFY(CPP_VERSION) ".xsd"; From 4e1ad4cb1f9c2cf816d831d3f11cf04baec13e90 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Thu, 19 Mar 2020 10:44:06 -0700 Subject: [PATCH 0731/1022] Audio Effects: Run more tests for LoudnessEnhancerEffect Due to incorrect assumptions about test case inheritance in GTests, LoudnessEnhancerEffect wasn't running tests for methods of IEffect interface. The test code has been restructured to fix that via proper parametrization. Bug: 146149801 Test: atest VtsHalAudioEffectV5_0TargetTest Test: atest VtsHalAudioEffectV6_0TargetTest Change-Id: Ie366979880bfc3b7e95a02957451736d724f838f Merged-In: Ie366979880bfc3b7e95a02957451736d724f838f --- .../VtsHalAudioEffectTargetTest.cpp | 70 +++++++++++++------ 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp index 390d4ee418..070242fc9d 100644 --- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp +++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp @@ -155,11 +155,20 @@ static const Uuid LOUDNESS_ENHANCER_EFFECT_TYPE = { 0xfe3199be, 0xaed0, 0x413f, 0x87bb, std::array{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}}; +enum { PARAM_FACTORY_NAME, PARAM_EFFECT_UUID }; +using EffectParameter = std::tuple; + +static inline std::string EffectParameterToString( + const ::testing::TestParamInfo& info) { + return ::android::hardware::PrintInstanceNameToString(::testing::TestParamInfo{ + std::get(info.param), info.index}); +} + // The main test class for Audio Effect HIDL HAL. -class AudioEffectHidlTest : public ::testing::TestWithParam { +class AudioEffectHidlTest : public ::testing::TestWithParam { public: void SetUp() override { - effectsFactory = IEffectsFactory::getService(GetParam()); + effectsFactory = IEffectsFactory::getService(std::get(GetParam())); ASSERT_NE(nullptr, effectsFactory.get()); findAndCreateEffect(getEffectType()); @@ -180,7 +189,7 @@ class AudioEffectHidlTest : public ::testing::TestWithParam { RecordProperty("description", description); } - virtual Uuid getEffectType() { return EQUALIZER_EFFECT_TYPE; } + Uuid getEffectType() const { return std::get(GetParam()); } void findAndCreateEffect(const Uuid& type); void findEffectInstance(const Uuid& type, Uuid* uuid); @@ -369,7 +378,9 @@ TEST_P(AudioEffectHidlTest, DisableEnableDisable) { description("Verify Disable -> Enable -> Disable sequence for an effect"); Return ret = effect->disable(); EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::INVALID_ARGUMENTS, ret); + // Note: some legacy effects may return -EINVAL (INVALID_ARGUMENTS), + // more canonical is to return -ENOSYS (NOT_SUPPORTED) + EXPECT_TRUE(ret == Result::NOT_SUPPORTED || ret == Result::INVALID_ARGUMENTS); ret = effect->enable(); EXPECT_TRUE(ret.isOk()); EXPECT_EQ(Result::OK, ret); @@ -519,15 +530,19 @@ TEST_P(AudioEffectHidlTest, SetCurrentConfigForFeature) { // The main test class for Equalizer Audio Effect HIDL HAL. class EqualizerAudioEffectHidlTest : public AudioEffectHidlTest { - public: + public: void SetUp() override { AudioEffectHidlTest::SetUp(); equalizer = IEqualizerEffect::castFrom(effect); ASSERT_NE(nullptr, equalizer.get()); } - protected: - Uuid getEffectType() override { return EQUALIZER_EFFECT_TYPE; } + void TearDown() override { + equalizer.clear(); + AudioEffectHidlTest::TearDown(); + } + + protected: void getNumBands(uint16_t* numBands); void getLevelRange(int16_t* minLevel, int16_t* maxLevel); void getBandFrequencyRange(uint16_t band, uint32_t* minFreq, uint32_t* centerFreq, @@ -765,16 +780,19 @@ TEST_P(EqualizerAudioEffectHidlTest, GetSetAllProperties) { // The main test class for Equalizer Audio Effect HIDL HAL. class LoudnessEnhancerAudioEffectHidlTest : public AudioEffectHidlTest { - public: + public: void SetUp() override { AudioEffectHidlTest::SetUp(); enhancer = ILoudnessEnhancerEffect::castFrom(effect); ASSERT_NE(nullptr, enhancer.get()); } - protected: - Uuid getEffectType() override { return LOUDNESS_ENHANCER_EFFECT_TYPE; } + void TearDown() override { + enhancer.clear(); + AudioEffectHidlTest::TearDown(); + } + protected: sp enhancer; }; @@ -799,19 +817,31 @@ TEST_P(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) { EXPECT_EQ(gain, actualGain); } +INSTANTIATE_TEST_SUITE_P(EffectsFactory, AudioEffectsFactoryHidlTest, + ::testing::ValuesIn(::android::hardware::getAllHalInstanceNames( + IEffectsFactory::descriptor)), + ::android::hardware::PrintInstanceNameToString); INSTANTIATE_TEST_SUITE_P( - EffectsFactory, AudioEffectsFactoryHidlTest, - testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)), - android::hardware::PrintInstanceNameToString); + Equalizer_IEffect, AudioEffectHidlTest, + ::testing::Combine(::testing::ValuesIn(::android::hardware::getAllHalInstanceNames( + IEffectsFactory::descriptor)), + ::testing::Values(EQUALIZER_EFFECT_TYPE)), + EffectParameterToString); INSTANTIATE_TEST_SUITE_P( - Equalizer, AudioEffectHidlTest, - testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)), - android::hardware::PrintInstanceNameToString); + LoudnessEnhancer_IEffect, AudioEffectHidlTest, + ::testing::Combine(::testing::ValuesIn(::android::hardware::getAllHalInstanceNames( + IEffectsFactory::descriptor)), + ::testing::Values(LOUDNESS_ENHANCER_EFFECT_TYPE)), + EffectParameterToString); INSTANTIATE_TEST_SUITE_P( Equalizer, EqualizerAudioEffectHidlTest, - testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)), - android::hardware::PrintInstanceNameToString); + ::testing::Combine(::testing::ValuesIn(::android::hardware::getAllHalInstanceNames( + IEffectsFactory::descriptor)), + ::testing::Values(EQUALIZER_EFFECT_TYPE)), + EffectParameterToString); INSTANTIATE_TEST_SUITE_P( LoudnessEnhancer, LoudnessEnhancerAudioEffectHidlTest, - testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)), - android::hardware::PrintInstanceNameToString); + ::testing::Combine(::testing::ValuesIn(::android::hardware::getAllHalInstanceNames( + IEffectsFactory::descriptor)), + ::testing::Values(LOUDNESS_ENHANCER_EFFECT_TYPE)), + EffectParameterToString); From 740c3d53c0f5d1f4f7ca7bf1e1c24d4f9a7c7a58 Mon Sep 17 00:00:00 2001 From: chrisweir Date: Tue, 24 Mar 2020 11:01:57 -0700 Subject: [PATCH 0732/1022] Add libc++fs for auto Add a temporary version of libc++fs for a couple of auto features. This will need to be switched out when libc++fs merges, possibly in S. Bug: 152067309 Bug: 142654031 Test: Manual Change-Id: Ibb495af8140470b79e73fd104fd5061f7e3ad8a9 --- .../can/1.0/default/libc++fs/Android.bp | 83 +++++++++++++++++++ automotive/can/1.0/default/libc++fs/include | 1 + automotive/can/1.0/default/libc++fs/src | 1 + 3 files changed, 85 insertions(+) create mode 100644 automotive/can/1.0/default/libc++fs/Android.bp create mode 120000 automotive/can/1.0/default/libc++fs/include create mode 120000 automotive/can/1.0/default/libc++fs/src diff --git a/automotive/can/1.0/default/libc++fs/Android.bp b/automotive/can/1.0/default/libc++fs/Android.bp new file mode 100644 index 0000000000..1fe324ed0f --- /dev/null +++ b/automotive/can/1.0/default/libc++fs/Android.bp @@ -0,0 +1,83 @@ +// +// 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. +// + +// TODO(152067309): Stop building this yourself once it's ABI stable and has +// been made vendor available. Just use libc++fs instead of this. + +cc_defaults { + name: "android.hardware.automotive@libc++fsdefaults", + host_supported: true, + local_include_dirs: ["include"], + export_include_dirs: ["include"], + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + ], + cppflags: [ + "-std=c++14", + "-fexceptions", + "-DLIBCXX_BUILDING_LIBCXXABI", + "-D_LIBCPP_BUILDING_LIBRARY", + ], + rtti: true, + stl: "none", + target: { + linux_bionic: { + enabled: true, + }, + windows: { + enabled: true, + cflags: [ + "-D_LIBCPP_HAS_THREAD_API_WIN32", + "-D_LIBCXXABI_BUILDING_LIBRARY", + "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS", + "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", + "-UWIN32_LEAN_AND_MEAN", + ], + }, + windows_x86: { + cflags: [ + "-fsjlj-exceptions", + ], + }, + }, +} + +cc_library_static { + name: "android.hardware.automotive@libc++fs", + recovery_available: true, + vendor: true, + defaults: ["android.hardware.automotive@libc++fsdefaults"], + srcs: [ + "src/filesystem/directory_iterator.cpp", + "src/filesystem/operations.cpp", + ], + multilib: { + lib32: { + // off_t usage is constrained to within the libc++ source (not the + // headers), so we can build the filesystem library with a 64-bit + // off_t on LP32 to get large file support without needing all users + // of the library to match. + cflags: ["-D_FILE_OFFSET_BITS=64"], + }, + }, + target: { + windows: { + enabled: false, + }, + }, +} diff --git a/automotive/can/1.0/default/libc++fs/include b/automotive/can/1.0/default/libc++fs/include new file mode 120000 index 0000000000..346e65945a --- /dev/null +++ b/automotive/can/1.0/default/libc++fs/include @@ -0,0 +1 @@ +../../../../../../../external/libcxx/include/ \ No newline at end of file diff --git a/automotive/can/1.0/default/libc++fs/src b/automotive/can/1.0/default/libc++fs/src new file mode 120000 index 0000000000..7abb4ba5f9 --- /dev/null +++ b/automotive/can/1.0/default/libc++fs/src @@ -0,0 +1 @@ +../../../../../../../external/libcxx/src/ \ No newline at end of file From f17c21ac1ee4ea1b3168b38a18007e25699a117f Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Thu, 19 Mar 2020 15:42:34 -0700 Subject: [PATCH 0733/1022] Update the hash for biometrics.fingerprint@2.2 Bug: 147496715 Bug: 139317981 Bug: 149502271 Test: atest vts_treble_vintf_vendor_test Change-Id: I68d8977234a81eec2185fb57adea4fd9342863a8 --- current.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/current.txt b/current.txt index 79f5eba650..9c0a77695d 100644 --- a/current.txt +++ b/current.txt @@ -631,7 +631,7 @@ dd377f404a8e71f6191d295e10067db629b0f0c28e594af906f2bea5d87fe2cc android.hardwar 282193799d60bff27a84c65a36218c1e7d8f582f5828e2e059383d1b90aa56bd android.hardware.audio.effect@6.0::IVirtualizerEffect 0868e00f7c5ee16723bda1a8f57099763d04100ae7126a1c2d3a9a87c844a7e8 android.hardware.audio.effect@6.0::IVisualizerEffect 817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types -6828bbf18dc5d0f00c73341a10c8e4d574346c1abb1c2ed682ba5e9f8a3240d9 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprint +140f8f62100ccf9cd282ae3685a0f4ef0a9f971d77dfbc7350ccb4e04cf295ec android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprint 82cad99f5feb2ea9bcd4579055edf4af8feb9fc602a6e4827ddd727d254d4991 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprintClientCallback ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types 362fd1c21641c2224f3b80c30d9797b988fa3f344243d531ba73c553779a5763 android.hardware.bluetooth@1.1::IBluetoothHci From a69fd6ae730479ccfba6523be736c8f95e19a340 Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Thu, 19 Mar 2020 19:05:14 +0000 Subject: [PATCH 0734/1022] Revert "Add biometrics.face@1.1 to current.txt" This reverts commit 7b8a5c99d6b017d206458aaaa34ab204c3afdfb9. Reason for revert: this interface is untested in R. Bug: 151331855 Change-Id: I6e0f8096a1c9c02936d7f3fcc247566f80b37648 --- current.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/current.txt b/current.txt index 47b72065f9..79f5eba650 100644 --- a/current.txt +++ b/current.txt @@ -451,9 +451,9 @@ ca15a738dedc2f4981925f7d7ff29c22bc3f8a848403dcf0c592c167de09d9af android.hardwar 443659bb9e27221e5da0d16c7a0ecb2dc3a9a03acc8a0b2196b47c50735e2d2e android.hardware.audio.effect@5.0::IVirtualizerEffect 78fed26a781cdca1b3bcb37520bff705d7764ee81db9cfd37014953c7ad2596e android.hardware.audio.effect@5.0::IVisualizerEffect 6385b6accab8a544e2ee54ba7bf5aa55dff6153bcedd80fdaae16fe9e0be7050 android.hardware.audio.effect@5.0::types -95aa2f59e29e2f84d8e84320ace9b6682b426a16e897b4bd241375cbee0e07f3 android.hardware.biometrics.face@1.0::types e18ff318f3fc43db37f554696dc4e551abb9b119bde53950f73e28ce33a97a40 android.hardware.biometrics.face@1.0::IBiometricsFace b6e55d7795bbafd011fb95a3b6d3954bf66c349e14cf107f3b72032ce3ceb448 android.hardware.biometrics.face@1.0::IBiometricsFaceClientCallback +95aa2f59e29e2f84d8e84320ace9b6682b426a16e897b4bd241375cbee0e07f3 android.hardware.biometrics.face@1.0::types ecedc58dbcdb13503c19c0ab160ac1dd0530bb1471164149282dd1463c684185 android.hardware.bluetooth.audio@2.0::IBluetoothAudioPort fb9c40e4deab40be5476477078fe3d8a4a4495fd9deef4321878d169d675c633 android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvider f7431f3e3e4e3387fc6f27a6cf423eddcd824a395dc4349d302c995ab44a9895 android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvidersFactory @@ -631,7 +631,6 @@ dd377f404a8e71f6191d295e10067db629b0f0c28e594af906f2bea5d87fe2cc android.hardwar 282193799d60bff27a84c65a36218c1e7d8f582f5828e2e059383d1b90aa56bd android.hardware.audio.effect@6.0::IVirtualizerEffect 0868e00f7c5ee16723bda1a8f57099763d04100ae7126a1c2d3a9a87c844a7e8 android.hardware.audio.effect@6.0::IVisualizerEffect 817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types -7e8e1c3d0173c5d503dd01cecff8e3864478557ca6b9e8cc2291598b1a4aea62 android.hardware.biometrics.face@1.1::IBiometricsFace 6828bbf18dc5d0f00c73341a10c8e4d574346c1abb1c2ed682ba5e9f8a3240d9 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprint 82cad99f5feb2ea9bcd4579055edf4af8feb9fc602a6e4827ddd727d254d4991 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprintClientCallback ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types From 921df7abd29ad086a684b2820a0fa7c21bf19280 Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Thu, 12 Mar 2020 18:37:34 +0000 Subject: [PATCH 0735/1022] Revert "Add enroll_1_1 with preview window id" This reverts commit 7ab5ab85d0df1f565a265ec0b75e01310ef9b5ba. Reason for revert: this interface is untested in R. Bug: 151331855 Bug: 149502271 Change-Id: I819adb2910e70243e19e273675ad15de7736279a --- biometrics/face/1.1/IBiometricsFace.hal | 39 +---------------- .../face/1.1/default/BiometricsFace.cpp | 8 ---- biometrics/face/1.1/default/BiometricsFace.h | 4 -- .../VtsHalBiometricsFaceV1_1TargetTest.cpp | 42 ------------------- 4 files changed, 2 insertions(+), 91 deletions(-) diff --git a/biometrics/face/1.1/IBiometricsFace.hal b/biometrics/face/1.1/IBiometricsFace.hal index 84e7443c9c..975001f30b 100644 --- a/biometrics/face/1.1/IBiometricsFace.hal +++ b/biometrics/face/1.1/IBiometricsFace.hal @@ -15,7 +15,6 @@ */ package android.hardware.biometrics.face@1.1; - import @1.0::IBiometricsFace; import @1.0::Status; import @1.0::Feature; @@ -78,40 +77,6 @@ interface IBiometricsFace extends @1.0::IBiometricsFace { * enrollment. Note that all features are enabled by default. * @return status The status of this method call. */ - enrollRemotely(vec hat, uint32_t timeoutSec, vec disabledFeatures) - generates (Status status); - - /** - * Enrolls a user's face. - * - * Note that the Hardware Authentication Token must be valid for the - * duration of enrollment and thus should be explicitly invalidated by a - * call to revokeChallenge() when enrollment is complete, to reduce the - * window of opportunity to re-use the challenge and HAT. For example, - * Settings calls generateChallenge() once to allow the user to enroll one - * or more faces or toggle secure settings without having to re-enter the - * PIN/pattern/password. Once the user completes the operation, Settings - * invokes revokeChallenge() to close the transaction. If the HAT is expired, - * the implementation must invoke onError with UNABLE_TO_PROCESS. - * - * This method triggers the IBiometricsFaceClientCallback#onEnrollResult() - * method. - * - * @param hat A valid Hardware Authentication Token, generated as a result - * of a generateChallenge() challenge being wrapped by the gatekeeper - * after a successful strong authentication request. - * @param timeoutSec A timeout in seconds, after which this enroll - * attempt is cancelled. Note that the framework can continue - * enrollment by calling this again with a valid HAT. This timeout is - * expected to be used to limit power usage if the device becomes idle - * during enrollment. The implementation is expected to send - * ERROR_TIMEOUT if this happens. - * @param disabledFeatures A list of features to be disabled during - * enrollment. Note that all features are enabled by default. - * @param windowId optional ID of a camera preview window for a - * single-camera device. Must be null if not used. - * @return status The status of this method call. - */ - enroll_1_1(vec hat, uint32_t timeoutSec, vec disabledFeatures, - handle windowId) generates (Status status); + enrollRemotely(vec hat, uint32_t timeoutSec, + vec disabledFeatures) generates (Status status); }; diff --git a/biometrics/face/1.1/default/BiometricsFace.cpp b/biometrics/face/1.1/default/BiometricsFace.cpp index 2143880514..7bda57fb7f 100644 --- a/biometrics/face/1.1/default/BiometricsFace.cpp +++ b/biometrics/face/1.1/default/BiometricsFace.cpp @@ -111,14 +111,6 @@ Return BiometricsFace::resetLockout(const hidl_vec& /* hat */) } // Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow. -Return BiometricsFace::enroll_1_1(const hidl_vec& /* hat */, - uint32_t /* timeoutSec */, - const hidl_vec& /* disabledFeatures */, - const hidl_handle& /* windowId */) { - mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */); - return Status::OK; -} - Return BiometricsFace::enrollRemotely(const hidl_vec& /* hat */, uint32_t /* timeoutSec */, const hidl_vec& /* disabledFeatures */) { diff --git a/biometrics/face/1.1/default/BiometricsFace.h b/biometrics/face/1.1/default/BiometricsFace.h index 5ce5771eae..5620b45a43 100644 --- a/biometrics/face/1.1/default/BiometricsFace.h +++ b/biometrics/face/1.1/default/BiometricsFace.h @@ -72,10 +72,6 @@ class BiometricsFace : public V1_1::IBiometricsFace { Return resetLockout(const hidl_vec& hat) override; // Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow. - Return enroll_1_1(const hidl_vec& hat, uint32_t timeoutSec, - const hidl_vec& disabledFeatures, - const hidl_handle& windowId) override; - Return enrollRemotely(const hidl_vec& hat, uint32_t timeoutSec, const hidl_vec& disabledFeatures) override; diff --git a/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp index 6ada44231f..c2431c6727 100644 --- a/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp +++ b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp @@ -30,7 +30,6 @@ #include using android::sp; -using android::hardware::hidl_handle; using android::hardware::hidl_vec; using android::hardware::Return; using android::hardware::Void; @@ -117,47 +116,6 @@ class FaceHidlTest : public ::testing::TestWithParam { sp mCallback; }; -// enroll with an invalid (all zeroes) HAT should fail. -TEST_P(FaceHidlTest, Enroll2_2ZeroHatTest) { - // Filling HAT with zeros - hidl_vec token(69); - for (size_t i = 0; i < 69; i++) { - token[i] = 0; - } - - hidl_handle windowId = nullptr; - Return ret = mService->enroll_1_1(token, kTimeoutSec, {}, windowId); - ASSERT_EQ(Status::OK, static_cast(ret)); - - // onError should be called with a meaningful (nonzero) error. - auto res = mCallback->WaitForCallback(kCallbackNameOnError); - EXPECT_TRUE(res.no_timeout); - EXPECT_EQ(kUserId, res.args->userId); - EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error); -} - -// enroll with an invalid HAT should fail. -TEST_P(FaceHidlTest, Enroll2_2GarbageHatTest) { - // Filling HAT with pseudorandom invalid data. - // Using default seed to make the test reproducible. - std::mt19937 gen(std::mt19937::default_seed); - std::uniform_int_distribution dist; - hidl_vec token(69); - for (size_t i = 0; i < 69; ++i) { - token[i] = dist(gen); - } - - hidl_handle windowId = nullptr; - Return ret = mService->enroll_1_1(token, kTimeoutSec, {}, windowId); - ASSERT_EQ(Status::OK, static_cast(ret)); - - // onError should be called with a meaningful (nonzero) error. - auto res = mCallback->WaitForCallback(kCallbackNameOnError); - EXPECT_TRUE(res.no_timeout); - EXPECT_EQ(kUserId, res.args->userId); - EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error); -} - // enroll with an invalid (all zeroes) HAT should fail. TEST_P(FaceHidlTest, EnrollRemotelyZeroHatTest) { // Filling HAT with zeros From 1c0e3b7e57e2e5b1c3742a5144182ac6efc54b13 Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Thu, 19 Mar 2020 12:53:41 -0700 Subject: [PATCH 0736/1022] Move default implementation from 1.1 to 1.0 Bug: 151331855 Test: vts-tradefed run commandAndExit vts-hal -m VtsHalBiometricsFaceV1_0Target Change-Id: I4a0d136faacd427ac28970d1a30a374cb6618393 --- biometrics/face/{1.1 => 1.0}/default/Android.bp | 5 ++--- biometrics/face/{1.1 => 1.0}/default/BiometricsFace.cpp | 8 -------- biometrics/face/{1.1 => 1.0}/default/BiometricsFace.h | 8 ++------ .../android.hardware.biometrics.face@1.0-service.rc} | 2 +- .../face/{1.1 => 1.0}/default/manifest_face_default.xml | 2 +- biometrics/face/{1.1 => 1.0}/default/service.cpp | 6 +++--- 6 files changed, 9 insertions(+), 22 deletions(-) rename biometrics/face/{1.1 => 1.0}/default/Android.bp (85%) rename biometrics/face/{1.1 => 1.0}/default/BiometricsFace.cpp (89%) rename biometrics/face/{1.1 => 1.0}/default/BiometricsFace.h (87%) rename biometrics/face/{1.1/default/android.hardware.biometrics.face@1.1-service.rc => 1.0/default/android.hardware.biometrics.face@1.0-service.rc} (75%) rename biometrics/face/{1.1 => 1.0}/default/manifest_face_default.xml (90%) rename biometrics/face/{1.1 => 1.0}/default/service.cpp (88%) diff --git a/biometrics/face/1.1/default/Android.bp b/biometrics/face/1.0/default/Android.bp similarity index 85% rename from biometrics/face/1.1/default/Android.bp rename to biometrics/face/1.0/default/Android.bp index 360071f3dd..d6ff087ee6 100644 --- a/biometrics/face/1.1/default/Android.bp +++ b/biometrics/face/1.0/default/Android.bp @@ -15,10 +15,10 @@ */ cc_binary { - name: "android.hardware.biometrics.face@1.1-service.example", + name: "android.hardware.biometrics.face@1.0-service.example", defaults: ["hidl_defaults"], vendor: true, - init_rc: ["android.hardware.biometrics.face@1.1-service.rc"], + init_rc: ["android.hardware.biometrics.face@1.0-service.rc"], vintf_fragments: ["manifest_face_default.xml"], relative_install_path: "hw", proprietary: true, @@ -31,6 +31,5 @@ cc_binary { "libutils", "liblog", "android.hardware.biometrics.face@1.0", - "android.hardware.biometrics.face@1.1", ], } diff --git a/biometrics/face/1.1/default/BiometricsFace.cpp b/biometrics/face/1.0/default/BiometricsFace.cpp similarity index 89% rename from biometrics/face/1.1/default/BiometricsFace.cpp rename to biometrics/face/1.0/default/BiometricsFace.cpp index 7bda57fb7f..2dd64764bb 100644 --- a/biometrics/face/1.1/default/BiometricsFace.cpp +++ b/biometrics/face/1.0/default/BiometricsFace.cpp @@ -110,12 +110,4 @@ Return BiometricsFace::resetLockout(const hidl_vec& /* hat */) return Status::OK; } -// Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow. -Return BiometricsFace::enrollRemotely(const hidl_vec& /* hat */, - uint32_t /* timeoutSec */, - const hidl_vec& /* disabledFeatures */) { - mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */); - return Status::OK; -} - } // namespace android::hardware::biometrics::face::implementation diff --git a/biometrics/face/1.1/default/BiometricsFace.h b/biometrics/face/1.0/default/BiometricsFace.h similarity index 87% rename from biometrics/face/1.1/default/BiometricsFace.h rename to biometrics/face/1.0/default/BiometricsFace.h index 5620b45a43..1d99ed26bc 100644 --- a/biometrics/face/1.1/default/BiometricsFace.h +++ b/biometrics/face/1.0/default/BiometricsFace.h @@ -16,7 +16,7 @@ #pragma once -#include +#include #include #include #include @@ -34,7 +34,7 @@ using ::android::hardware::biometrics::face::V1_0::Feature; using ::android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback; using ::android::hardware::biometrics::face::V1_0::Status; -class BiometricsFace : public V1_1::IBiometricsFace { +class BiometricsFace : public V1_0::IBiometricsFace { public: BiometricsFace(); @@ -71,10 +71,6 @@ class BiometricsFace : public V1_1::IBiometricsFace { Return resetLockout(const hidl_vec& hat) override; - // Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow. - Return enrollRemotely(const hidl_vec& hat, uint32_t timeoutSec, - const hidl_vec& disabledFeatures) override; - private: std::mt19937 mRandom; int32_t mUserId; diff --git a/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc b/biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc similarity index 75% rename from biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc rename to biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc index 687e2d8c86..6c7362f2bb 100644 --- a/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc +++ b/biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc @@ -1,4 +1,4 @@ -service vendor.face-hal-1-1-default /vendor/bin/hw/android.hardware.biometrics.face@1.1-service.example +service vendor.face-hal-1-0-default /vendor/bin/hw/android.hardware.biometrics.face@1.0-service.example # "class hal" causes a race condition on some devices due to files created # in /data. As a workaround, postpone startup until later in boot once # /data is mounted. diff --git a/biometrics/face/1.1/default/manifest_face_default.xml b/biometrics/face/1.0/default/manifest_face_default.xml similarity index 90% rename from biometrics/face/1.1/default/manifest_face_default.xml rename to biometrics/face/1.0/default/manifest_face_default.xml index ec71d9c92b..380ae49e93 100644 --- a/biometrics/face/1.1/default/manifest_face_default.xml +++ b/biometrics/face/1.0/default/manifest_face_default.xml @@ -2,7 +2,7 @@ android.hardware.biometrics.face hwbinder - 1.1 + 1.0 IBiometricsFace default diff --git a/biometrics/face/1.1/default/service.cpp b/biometrics/face/1.0/default/service.cpp similarity index 88% rename from biometrics/face/1.1/default/service.cpp rename to biometrics/face/1.0/default/service.cpp index 344bdb99b4..9818c959d6 100644 --- a/biometrics/face/1.1/default/service.cpp +++ b/biometrics/face/1.0/default/service.cpp @@ -14,10 +14,10 @@ * limitations under the License. */ -#define LOG_TAG "android.hardware.biometrics.face@1.1-service" +#define LOG_TAG "android.hardware.biometrics.face@1.0-service" #include -#include +#include #include #include #include @@ -27,7 +27,7 @@ using android::sp; using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; using android::hardware::biometrics::face::implementation::BiometricsFace; -using android::hardware::biometrics::face::V1_1::IBiometricsFace; +using android::hardware::biometrics::face::V1_0::IBiometricsFace; int main() { ALOGI("BiometricsFace HAL is being started."); From 32142e7c419589f0fa3634425a61e122e0bc99f3 Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Thu, 19 Mar 2020 20:35:34 +0000 Subject: [PATCH 0737/1022] Revert "Add VTS tests for biometrics.face@1.1" This reverts commit f21a4f0aee6045d06b94036f4c7020f186968fe0. Reason for revert: this interface is untested in R. Bug: 151331855 Change-Id: I6fbdd846a9ea56d1595347d0321fbf9018015da7 --- biometrics/face/1.1/vts/functional/Android.bp | 29 ---- .../VtsHalBiometricsFaceV1_1TargetTest.cpp | 163 ------------------ 2 files changed, 192 deletions(-) delete mode 100644 biometrics/face/1.1/vts/functional/Android.bp delete mode 100644 biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp diff --git a/biometrics/face/1.1/vts/functional/Android.bp b/biometrics/face/1.1/vts/functional/Android.bp deleted file mode 100644 index ccbb3994e1..0000000000 --- a/biometrics/face/1.1/vts/functional/Android.bp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 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. - */ - -cc_test { - name: "VtsHalBiometricsFaceV1_1TargetTest", - defaults: ["VtsHalTargetTestDefaults"], - srcs: ["VtsHalBiometricsFaceV1_1TargetTest.cpp"], - static_libs: [ - "android.hardware.biometrics.face@1.0", - "android.hardware.biometrics.face@1.1", - ], - test_suites: [ - "general-tests", - "vts-core", - ], -} diff --git a/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp deleted file mode 100644 index c2431c6727..0000000000 --- a/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 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. - */ - -#define LOG_TAG "biometrics_face_hidl_hal_test" - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -using android::sp; -using android::hardware::hidl_vec; -using android::hardware::Return; -using android::hardware::Void; -using android::hardware::biometrics::face::V1_0::FaceAcquiredInfo; -using android::hardware::biometrics::face::V1_0::FaceError; -using android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback; -using android::hardware::biometrics::face::V1_0::OptionalUint64; -using android::hardware::biometrics::face::V1_0::Status; -using android::hardware::biometrics::face::V1_1::IBiometricsFace; - -namespace { - -// Arbitrary, nonexistent userId -constexpr uint32_t kUserId = 9; -constexpr uint32_t kTimeoutSec = 3; -constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec); -constexpr char kFacedataDir[] = "/data/vendor_de/0/facedata"; -constexpr char kCallbackNameOnError[] = "onError"; - -// Callback arguments that need to be captured for the tests. -struct FaceCallbackArgs { - // The error passed to the last onError() callback. - FaceError error; - - // The userId passed to the last callback. - int32_t userId; -}; - -// Test callback class for the BiometricsFace HAL. -// The HAL will call these callback methods to notify about completed operations -// or encountered errors. -class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase, - public IBiometricsFaceClientCallback { - public: - Return onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override { return Void(); } - - Return onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec&) override { - return Void(); - } - - Return onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override { - return Void(); - } - - Return onError(uint64_t, int32_t userId, FaceError error, int32_t) override { - FaceCallbackArgs args = {}; - args.error = error; - args.userId = userId; - NotifyFromCallback(kCallbackNameOnError, args); - return Void(); - } - - Return onRemoved(uint64_t, const hidl_vec&, int32_t) override { return Void(); } - - Return onEnumerate(uint64_t, const hidl_vec&, int32_t) override { - return Void(); - } - - Return onLockoutChanged(uint64_t) override { return Void(); } -}; - -// Test class for the BiometricsFace HAL. -class FaceHidlTest : public ::testing::TestWithParam { - public: - void SetUp() override { - mService = IBiometricsFace::getService(GetParam()); - ASSERT_NE(mService, nullptr); - mCallback = new FaceCallback(); - mCallback->SetWaitTimeoutDefault(kTimeout); - Return ret1 = mService->setCallback(mCallback, [](const OptionalUint64& res) { - ASSERT_EQ(Status::OK, res.status); - // Makes sure the "deviceId" represented by "res.value" is not 0. - // 0 would mean the HIDL is not available. - ASSERT_NE(0UL, res.value); - }); - ASSERT_TRUE(ret1.isOk()); - Return ret2 = mService->setActiveUser(kUserId, kFacedataDir); - ASSERT_EQ(Status::OK, static_cast(ret2)); - } - - void TearDown() override {} - - sp mService; - sp mCallback; -}; - -// enroll with an invalid (all zeroes) HAT should fail. -TEST_P(FaceHidlTest, EnrollRemotelyZeroHatTest) { - // Filling HAT with zeros - hidl_vec token(69); - for (size_t i = 0; i < 69; i++) { - token[i] = 0; - } - - Return ret = mService->enrollRemotely(token, kTimeoutSec, {}); - ASSERT_EQ(Status::OK, static_cast(ret)); - - // onError should be called with a meaningful (nonzero) error. - auto res = mCallback->WaitForCallback(kCallbackNameOnError); - EXPECT_TRUE(res.no_timeout); - EXPECT_EQ(kUserId, res.args->userId); - EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error); -} - -// enroll with an invalid HAT should fail. -TEST_P(FaceHidlTest, EnrollRemotelyGarbageHatTest) { - // Filling HAT with pseudorandom invalid data. - // Using default seed to make the test reproducible. - std::mt19937 gen(std::mt19937::default_seed); - std::uniform_int_distribution dist; - hidl_vec token(69); - for (size_t i = 0; i < 69; ++i) { - token[i] = dist(gen); - } - - Return ret = mService->enrollRemotely(token, kTimeoutSec, {}); - ASSERT_EQ(Status::OK, static_cast(ret)); - - // onError should be called with a meaningful (nonzero) error. - auto res = mCallback->WaitForCallback(kCallbackNameOnError); - EXPECT_TRUE(res.no_timeout); - EXPECT_EQ(kUserId, res.args->userId); - EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error); -} - -} // anonymous namespace - -INSTANTIATE_TEST_SUITE_P( - PerInstance, FaceHidlTest, - testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBiometricsFace::descriptor)), - android::hardware::PrintInstanceNameToString); From 9a471eb8be92b59ba2d97d9c7310476e38aa1d31 Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Thu, 19 Mar 2020 20:48:17 +0000 Subject: [PATCH 0738/1022] Revert "Define biometrics.face@1.1 with remote enrollment" This reverts commit ec0b6e26ea45a07ee00ca0127fdf7e3749ab515c. Reason for revert: this interface is untested in R. Bug: 151331855 Bug: 149502271 Change-Id: I5d63c6e52c540af328fe108bff1861d16990a6b4 --- biometrics/face/1.1/Android.bp | 17 ----- biometrics/face/1.1/IBiometricsFace.hal | 82 ------------------------- 2 files changed, 99 deletions(-) delete mode 100644 biometrics/face/1.1/Android.bp delete mode 100644 biometrics/face/1.1/IBiometricsFace.hal diff --git a/biometrics/face/1.1/Android.bp b/biometrics/face/1.1/Android.bp deleted file mode 100644 index 2206597dec..0000000000 --- a/biometrics/face/1.1/Android.bp +++ /dev/null @@ -1,17 +0,0 @@ -// This file is autogenerated by hidl-gen -Landroidbp. - -hidl_interface { - name: "android.hardware.biometrics.face@1.1", - root: "android.hardware", - vndk: { - enabled: true, - }, - srcs: [ - "IBiometricsFace.hal", - ], - interfaces: [ - "android.hardware.biometrics.face@1.0", - "android.hidl.base@1.0", - ], - gen_java: true, -} diff --git a/biometrics/face/1.1/IBiometricsFace.hal b/biometrics/face/1.1/IBiometricsFace.hal deleted file mode 100644 index 975001f30b..0000000000 --- a/biometrics/face/1.1/IBiometricsFace.hal +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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. - */ - -package android.hardware.biometrics.face@1.1; -import @1.0::IBiometricsFace; -import @1.0::Status; -import @1.0::Feature; - -/** - * The HAL interface for biometric face authentication. - */ -interface IBiometricsFace extends @1.0::IBiometricsFace { - /** - * Enrolls a user's face for a remote client, for example Android Auto. - * - * The HAL implementation is responsible for creating a secure communication - * channel and receiving the enrollment images from a mobile device with - * face authentication hardware. - * - * Note that the Hardware Authentication Token must be valid for the - * duration of enrollment and thus should be explicitly invalidated by a - * call to revokeChallenge() when enrollment is complete, to reduce the - * window of opportunity to re-use the challenge and HAT. For example, - * Settings calls generateChallenge() once to allow the user to enroll one - * or more faces or toggle secure settings without having to re-enter the - * PIN/pattern/password. Once the user completes the operation, Settings - * invokes revokeChallenge() to close the transaction. If the HAT is expired, - * the implementation must invoke onError with UNABLE_TO_PROCESS. - * - * Requirements for using this API: - * - Mobile devices MUST NOT delegate enrollment to another device by calling - * this API. This feature is intended only to allow enrollment on devices - * where it is impossible to enroll locally on the device. - * - The path MUST be protected by a secret key with rollback protection. - * - Synchronizing between devices MUST be accomplished by having both - * devices agree on a secret PIN entered by the user (similar to BT - * pairing procedure) and use a salted version of that PIN plus other secret - * to encrypt traffic. - * - All communication to/from the remote device MUST be encrypted and signed - * to prevent image injection and other man-in-the-middle type attacks. - * - generateChallenge() and revokeChallenge() MUST be implemented on both - * remote and local host (e.g. hash the result of the remote host with a - * local secret before responding to the API call) and any transmission of - * the challenge between hosts MUST be signed to prevent man-in-the-middle - * attacks. - * - In the event of a lost connection, the result of the last - * generateChallenge() MUST be invalidated and the process started over. - * - Both the remote and local host MUST honor the timeout and invalidate the - * challenge. - * - * This method triggers the IBiometricsFaceClientCallback#onEnrollResult() - * method. - * - * @param hat A valid Hardware Authentication Token, generated as a result - * of a generateChallenge() challenge being wrapped by the gatekeeper - * after a successful strong authentication request. - * @param timeoutSec A timeout in seconds, after which this enroll - * attempt is cancelled. Note that the framework can continue - * enrollment by calling this again with a valid HAT. This timeout is - * expected to be used to limit power usage if the device becomes idle - * during enrollment. The implementation is expected to send - * ERROR_TIMEOUT if this happens. - * @param disabledFeatures A list of features to be disabled during - * enrollment. Note that all features are enabled by default. - * @return status The status of this method call. - */ - enrollRemotely(vec hat, uint32_t timeoutSec, - vec disabledFeatures) generates (Status status); -}; From 49120d936cf8a416fe42dae59203716d8c26b9ea Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Thu, 19 Mar 2020 15:30:57 -0700 Subject: [PATCH 0739/1022] Remove enroll_2_2 and authenticate_2_2 Bug: 139317981 Bug: 149502271 Test: m vts -j Test: vts-tradefed run commandAndExit vts -m VtsHalBiometricsFingerprintV2_2Target Change-Id: I80492f324753291be4118de95e16ec370004afc8 --- .../2.2/IBiometricsFingerprint.hal | 42 ++------ ...HalBiometricsFingerprintV2_2TargetTest.cpp | 98 +++++++------------ 2 files changed, 43 insertions(+), 97 deletions(-) diff --git a/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal b/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal index 06510344ef..249830a111 100644 --- a/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal +++ b/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal @@ -17,42 +17,12 @@ package android.hardware.biometrics.fingerprint@2.2; import @2.1::IBiometricsFingerprint; -import @2.1::RequestStatus; +/** + * The HAL interface for biometric fingerprint authentication. + * + * This interface is required because all top-level interfaces need to be + * updated in a minor uprev. + */ interface IBiometricsFingerprint extends @2.1::IBiometricsFingerprint { - /** - * Fingerprint enroll request: - * Switches the HAL state machine to collect and store a new fingerprint - * template. Switches back as soon as enroll is complete, signalled by - * (fingerprintMsg.type == FINGERPRINT_TEMPLATE_ENROLLING && - * fingerprintMsg.data.enroll.samplesRemaining == 0) - * or after timeoutSec seconds. - * The fingerprint template must be assigned to the group gid. - * - * @param hat a valid Hardware Authentication Token (HAT), generated - * as a result of a preEnroll() call. - * @param gid a framework defined fingerprint set (group) id. - * @param timeoutSec a timeout in seconds. - * @param windowId optional ID of an illumination window for optical under - * display fingerprint sensors. Must contain a null pointer if not used. - * - * @return debugErrno is a value the framework logs in case it is not 0. - * - * A notify() function may be called with a more detailed error structure. - */ - enroll_2_2(vec hat, uint32_t gid, uint32_t timeoutSec, handle windowId) - generates (RequestStatus debugErrno); - - /** - * Authenticates an operation identified by operationId - * - * @param operationId operation id. - * @param gid fingerprint group id. - * @param windowId optional ID of an illumination window for optical under - * display fingerprint sensors. Must contain a null pointer if not used. - * - * @return debugErrno is a value the framework logs in case it is not 0. - */ - authenticate_2_2(uint64_t operationId, uint32_t gid, handle windowId) - generates (RequestStatus debugErrno); }; diff --git a/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp index 50bd4ab5e0..df29fd4179 100644 --- a/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp +++ b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp @@ -18,65 +18,66 @@ #include #include -#include -#include +#include +#include #include #include #include #include #include -#include + +namespace { + +namespace hidl_interface = android::hardware::biometrics::fingerprint::V2_1; +namespace hidl_interface_2_2 = android::hardware::biometrics::fingerprint::V2_2; + +using hidl_interface::FingerprintError; +using hidl_interface::IBiometricsFingerprint; +using hidl_interface::RequestStatus; using android::sp; using android::base::GetUintProperty; -using android::hardware::hidl_handle; using android::hardware::hidl_vec; using android::hardware::Return; using android::hardware::Void; -using android::hardware::biometrics::fingerprint::V2_1::FingerprintAcquiredInfo; -using android::hardware::biometrics::fingerprint::V2_1::FingerprintError; -using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback; -using android::hardware::biometrics::fingerprint::V2_1::RequestStatus; -using android::hardware::biometrics::fingerprint::V2_2::IBiometricsFingerprint; - -namespace { constexpr uint32_t kTimeoutSec = 3; constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec); constexpr uint32_t kGroupId = 99; -constexpr char kCallbackNameOnError[] = "onError"; +constexpr char kCallbackNameOnAcquired[] = "onAcquired"; // Callback arguments that need to be captured for the tests. struct FingerprintCallbackArgs { - // The error passed to the last onError() callback. - FingerprintError error; - - // The deviceId passed to the last callback. - uint64_t deviceId; + // The info passed to the last onAcquired() callback. + hidl_interface_2_2::FingerprintAcquiredInfo info; }; // Test callback class for the BiometricsFingerprint HAL. // The HAL will call these callback methods to notify about completed operations // or encountered errors. class FingerprintCallback : public ::testing::VtsHalHidlTargetCallbackBase, - public IBiometricsFingerprintClientCallback { + public hidl_interface_2_2::IBiometricsFingerprintClientCallback { public: Return onEnrollResult(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); } - Return onAcquired(uint64_t, FingerprintAcquiredInfo, int32_t) override { return Void(); } + Return onAcquired(uint64_t, hidl_interface::FingerprintAcquiredInfo, int32_t) override { + return Void(); + } + + Return onAcquired_2_2(uint64_t, hidl_interface_2_2::FingerprintAcquiredInfo info, + int32_t) override { + FingerprintCallbackArgs args = {}; + args.info = info; + NotifyFromCallback(kCallbackNameOnAcquired, args); + return Void(); + } Return onAuthenticated(uint64_t, uint32_t, uint32_t, const hidl_vec&) override { return Void(); } - Return onError(uint64_t deviceId, FingerprintError error, int32_t) override { - FingerprintCallbackArgs args = {}; - args.error = error; - args.deviceId = deviceId; - NotifyFromCallback(kCallbackNameOnError, args); - return Void(); - } + Return onError(uint64_t, FingerprintError, int32_t) override { return Void(); } Return onRemoved(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); } @@ -121,41 +122,16 @@ class FingerprintHidlTest : public ::testing::TestWithParam { sp mCallback; }; -// Enroll with an invalid (all zeroes) HAT should fail. -TEST_P(FingerprintHidlTest, EnrollZeroHatTest) { - // Filling HAT with zeros - hidl_vec token(69); - for (size_t i = 0; i < 69; i++) { - token[i] = 0; - } - - hidl_handle windowId = nullptr; - Return ret = mService->enroll_2_2(token, kGroupId, kTimeoutSec, windowId); - ASSERT_EQ(RequestStatus::SYS_OK, static_cast(ret)); - - // At least one call to onError should occur - auto res = mCallback->WaitForCallback(kCallbackNameOnError); - ASSERT_NE(FingerprintError::ERROR_NO_ERROR, res.args->error); -} - -// Enroll with an invalid (null) HAT should fail. -TEST_P(FingerprintHidlTest, EnrollGarbageHatTest) { - // Filling HAT with pseudorandom invalid data. - // Using default seed to make the test reproducible. - std::mt19937 gen(std::mt19937::default_seed); - std::uniform_int_distribution dist; - hidl_vec token(69); - for (size_t i = 0; i < 69; ++i) { - token[i] = dist(gen); - } - - hidl_handle windowId = nullptr; - Return ret = mService->enroll_2_2(token, kGroupId, kTimeoutSec, windowId); - ASSERT_EQ(RequestStatus::SYS_OK, static_cast(ret)); - - // At least one call to onError should occur - auto res = mCallback->WaitForCallback(kCallbackNameOnError); - ASSERT_NE(FingerprintError::ERROR_NO_ERROR, res.args->error); +// The START message and onAcquired_2_2 method should exist and work together correctly. +// Note, this test doesn't use the HAL. It just makes sure that the newly added constant and +// callback compile. Unfortunately, there is no way to test the usage of the constant within the +// actual HAL. +TEST_P(FingerprintHidlTest, acquiredInfoStartTest) { + mCallback->SetWaitTimeoutDefault(kTimeout); + mCallback->onAcquired_2_2(0 /* deviceId */, hidl_interface_2_2::FingerprintAcquiredInfo::START, + 0 /* vendorCode */); + auto res = mCallback->WaitForCallback(kCallbackNameOnAcquired); + ASSERT_EQ(hidl_interface_2_2::FingerprintAcquiredInfo::START, res.args->info); } } // anonymous namespace From 2ccf0825a6f2dc86df4b20e7221d4ee2bc191c58 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 23 Mar 2020 11:26:52 -0700 Subject: [PATCH 0740/1022] Add default/android.hardware.dumpstate@1.1-service.example Bug: 152067221 Test: VtsHalDumpstateV1_1TargetTest Signed-off-by: Roman Kiryanov Merged-In: I7f4e50846e2dc4393563c602145afb5617b2d48f Change-Id: I1ad44c244df3cbe7afede8d250d1c2259328c87a --- dumpstate/1.1/default/Android.bp | 26 ++++ ....hardware.dumpstate@1.1-service.example.rc | 8 ++ ...hardware.dumpstate@1.1-service.example.xml | 11 ++ dumpstate/1.1/default/main.cpp | 129 ++++++++++++++++++ 4 files changed, 174 insertions(+) create mode 100644 dumpstate/1.1/default/Android.bp create mode 100644 dumpstate/1.1/default/android.hardware.dumpstate@1.1-service.example.rc create mode 100644 dumpstate/1.1/default/android.hardware.dumpstate@1.1-service.example.xml create mode 100644 dumpstate/1.1/default/main.cpp diff --git a/dumpstate/1.1/default/Android.bp b/dumpstate/1.1/default/Android.bp new file mode 100644 index 0000000000..bd920752ba --- /dev/null +++ b/dumpstate/1.1/default/Android.bp @@ -0,0 +1,26 @@ +cc_binary { + name: "android.hardware.dumpstate@1.1-service.example", + vendor: true, + relative_install_path: "hw", + defaults: ["hidl_defaults"], + init_rc: [ + "android.hardware.dumpstate@1.1-service.example.rc", + ], + vintf_fragments: [ + "android.hardware.dumpstate@1.1-service.example.xml", + ], + srcs: ["main.cpp"], + shared_libs: [ + "android.hardware.dumpstate@1.0", + "android.hardware.dumpstate@1.1", + "libbase", + "libcutils", + "libdumpstateutil", + "libhidlbase", + "liblog", + "libutils", + ], + cflags: [ + "-DLOG_TAG=\"android.hardware.dumpstate@1.1-service.example\"", + ], +} diff --git a/dumpstate/1.1/default/android.hardware.dumpstate@1.1-service.example.rc b/dumpstate/1.1/default/android.hardware.dumpstate@1.1-service.example.rc new file mode 100644 index 0000000000..3a1e06a5dc --- /dev/null +++ b/dumpstate/1.1/default/android.hardware.dumpstate@1.1-service.example.rc @@ -0,0 +1,8 @@ +service dumpstate-1-1 /vendor/bin/hw/android.hardware.dumpstate@1.1-service.example + class hal + user nobody + group nobody + interface android.hardware.dumpstate@1.0::IDumpstateDevice default + interface android.hardware.dumpstate@1.1::IDumpstateDevice default + oneshot + disabled diff --git a/dumpstate/1.1/default/android.hardware.dumpstate@1.1-service.example.xml b/dumpstate/1.1/default/android.hardware.dumpstate@1.1-service.example.xml new file mode 100644 index 0000000000..775e8c8416 --- /dev/null +++ b/dumpstate/1.1/default/android.hardware.dumpstate@1.1-service.example.xml @@ -0,0 +1,11 @@ + + + android.hardware.dumpstate + hwbinder + 1.1 + + IDumpstateDevice + default + + + diff --git a/dumpstate/1.1/default/main.cpp b/dumpstate/1.1/default/main.cpp new file mode 100644 index 0000000000..3c17e18f43 --- /dev/null +++ b/dumpstate/1.1/default/main.cpp @@ -0,0 +1,129 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include "DumpstateUtil.h" + +namespace { +using ::android::hardware::hidl_handle; +using ::android::hardware::Return; +using ::android::hardware::Void; + +using ::android::hardware::dumpstate::V1_1::DumpstateMode; +using ::android::hardware::dumpstate::V1_1::DumpstateStatus; +using ::android::hardware::dumpstate::V1_1::IDumpstateDevice; + +using ::android::os::dumpstate::DumpFileToFd; + +const char kVerboseLoggingProperty[] = "persist.dumpstate.verbose_logging.enabled"; + +struct DumpstateDevice : public IDumpstateDevice { + // 1.1 + Return dumpstateBoard_1_1(const hidl_handle& handle, const DumpstateMode mode, + uint64_t /*timeoutMillis*/) override { + if (handle == nullptr || handle->numFds < 1) { + ALOGE("no FDs\n"); + return DumpstateStatus::ILLEGAL_ARGUMENT; + } + + int fd = handle->data[0]; + if (fd < 0) { + ALOGE("invalid FD: %d\n", fd); + return DumpstateStatus::ILLEGAL_ARGUMENT; + } + + switch (mode) { + case DumpstateMode::FULL: + return dumpstateBoardImpl(fd, true); + + case DumpstateMode::DEFAULT: + return dumpstateBoardImpl(fd, false); + + case DumpstateMode::INTERACTIVE: + case DumpstateMode::REMOTE: + case DumpstateMode::WEAR: + case DumpstateMode::CONNECTIVITY: + case DumpstateMode::WIFI: + case DumpstateMode::PROTO: + ALOGE("The requested mode is not supported: %s\n", toString(mode).c_str()); + return DumpstateStatus::UNSUPPORTED_MODE; + + default: + ALOGE("The requested mode is invalid: %s\n", toString(mode).c_str()); + return DumpstateStatus::ILLEGAL_ARGUMENT; + } + } + + Return setVerboseLoggingEnabled(bool enable) override { + ::android::base::SetProperty(kVerboseLoggingProperty, enable ? "true" : "false"); + return Void(); + } + + Return getVerboseLoggingEnabled() override { return getVerboseLoggingEnabledImpl(); } + + // 1.0 + Return dumpstateBoard(const hidl_handle& h) override { + dumpstateBoard_1_1(h, DumpstateMode::DEFAULT, 0); + return Void(); + } + + DumpstateStatus dumpstateBoardImpl(const int fd, const bool full) { + ALOGD("DumpstateDevice::dumpstateBoard() FD: %d\n", fd); + ALOGI("Dumpstate HIDL not provided by device\n"); + + dprintf(fd, "verbose logging: %s\n", + getVerboseLoggingEnabledImpl() ? "enabled" : "disabled"); + + dprintf(fd, "[%s] %s\n", (full ? "full" : "default"), "Hello, world!"); + + // Shows an example on how to use the libdumpstateutil API. + DumpFileToFd(fd, "cmdline", "/proc/self/cmdline"); + + return DumpstateStatus::OK; + } + + static bool getVerboseLoggingEnabledImpl() { + return ::android::base::GetBoolProperty(kVerboseLoggingProperty, false); + } +}; +} // namespace + +int main(int, char**) { + using ::android::sp; + using ::android::hardware::configureRpcThreadpool; + using ::android::hardware::joinRpcThreadpool; + using ::android::hardware::LazyServiceRegistrar; + + configureRpcThreadpool(1, true); + + sp dumpstate(new DumpstateDevice); + auto serviceRegistrar = LazyServiceRegistrar::getInstance(); + + if (serviceRegistrar.registerService(dumpstate) != ::android::OK) { + ALOGE("Could not register service."); + return 1; + } + + joinRpcThreadpool(); + return 0; +} From 5aa27a00c68b6726987ca157da145fb8a8fa62d5 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Tue, 24 Mar 2020 11:52:24 -0700 Subject: [PATCH 0741/1022] Fix file paths for DumpstateUtil calls in 1.0 selinux prevents access to /vendor/bin/date and /system/etc/hosts. Bug: 152067221 Test: presubmit Signed-off-by: Roman Kiryanov Merged-In: I6202878427718bc825063941377c3e91b798677f Change-Id: I47fb746e17b9a2771a8857e6c6b80abce6324de4 --- dumpstate/1.0/default/DumpstateDevice.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dumpstate/1.0/default/DumpstateDevice.cpp b/dumpstate/1.0/default/DumpstateDevice.cpp index c57bf43dbf..e3c2e0ba55 100644 --- a/dumpstate/1.0/default/DumpstateDevice.cpp +++ b/dumpstate/1.0/default/DumpstateDevice.cpp @@ -51,9 +51,8 @@ Return DumpstateDevice::dumpstateBoard(const hidl_handle& handle) { ALOGI("Dumpstate HIDL not provided by device\n"); dprintf(fd, "Dumpstate HIDL not provided by device; providing bogus data.\n"); - // Shows some examples on how to use the libdumpstateutil API. - RunCommandToFd(fd, "DATE", {"/vendor/bin/date"}); - DumpFileToFd(fd, "HOSTS", "/system/etc/hosts"); + // Shows an example on how to use the libdumpstateutil API. + DumpFileToFd(fd, "cmdline", "/proc/self/cmdline"); return Void(); } From 6b72cf0a74956ae097a9627fae669277a777464c Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 19 Mar 2020 12:12:51 -0700 Subject: [PATCH 0742/1022] Freeze HALs for Android R Bug: 147496715 Test: none Change-Id: Ied59b4ba94c8b6bb9e3ead869d8341cffa86f1e8 --- current.txt | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/current.txt b/current.txt index 9c0a77695d..f9c64bf6ca 100644 --- a/current.txt +++ b/current.txt @@ -631,6 +631,34 @@ dd377f404a8e71f6191d295e10067db629b0f0c28e594af906f2bea5d87fe2cc android.hardwar 282193799d60bff27a84c65a36218c1e7d8f582f5828e2e059383d1b90aa56bd android.hardware.audio.effect@6.0::IVirtualizerEffect 0868e00f7c5ee16723bda1a8f57099763d04100ae7126a1c2d3a9a87c844a7e8 android.hardware.audio.effect@6.0::IVisualizerEffect 817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types +ca515ff4b63c80cf5ad7b3395c997c57d6c56157361f6c367d1c96f23cc4860a android.hardware.automotive.audiocontrol@1.0::types +4bc4e8087f5c389f013370ed68bc8a1a29cb2f203237937697f35e005a5ad0b4 android.hardware.automotive.audiocontrol@2.0::IAudioControl +37ef585d6687cb31e35c67ab456140d70edba9c4333ce5a6ddd70e636e985773 android.hardware.automotive.audiocontrol@2.0::ICloseHandle +3cf3e5e48ba2642052bbccc1aa4e8bb142933ac960ff40eeedd16e4fe452e7a5 android.hardware.automotive.audiocontrol@2.0::IFocusListener +d06fc14b325beeef06bd39de8f178f490d9e9095255626866071aab42be1fc40 android.hardware.automotive.audiocontrol@2.0::types +949a2582c9efa3f6f631f56120eae3f02313f251dbf9246c327e419cdf0652a2 android.hardware.automotive.can@1.0::ICanBus +43cddb1907a30343bced68946884416ea25ab14ae2df4709357528b2bedba84c android.hardware.automotive.can@1.0::ICanController +272e826492b27b0dbdeda408e84a41ae43e98f29e57995b6452ded270aae4eee android.hardware.automotive.can@1.0::ICanErrorListener +07e387bd8bc0e4df5f372515ed960a0b1ae74ea7231d4490a0bb09b07046e4f1 android.hardware.automotive.can@1.0::ICanMessageListener +2166132d6c247630a193217b4338074f634d6691b1ed6796cb26b3812e90b46e android.hardware.automotive.can@1.0::ICloseHandle +83355471a3b6d7f777d3f129714585ffb77d9b6f8a3d0365741969631efb81b2 android.hardware.automotive.can@1.0::types +8afd93d525cf17818e3d46e72f30debeaacc6fb166a59a8e25272f2baeb0ef7a android.hardware.automotive.evs@1.1::IEvsCamera +89ff5ab18b3069f21a57f559b290caa50670f0ae1b74178f630183aef39b496b android.hardware.automotive.evs@1.1::IEvsCameraStream +4c67f768067a0aceac74381f6f62e778ab3b6a18f47db3c9b98c58190ef5619d android.hardware.automotive.evs@1.1::IEvsDisplay +87958d728d7c0ee9b9391ab4a072b097914921a7b38f7dc3df427f933a5b528e android.hardware.automotive.evs@1.1::IEvsEnumerator +f53b4e8de6209c6d0fa9036005671b34a2f98328b51423d3a5137a43bf42c84d android.hardware.automotive.evs@1.1::IEvsUltrasonicsArray +0460bacbde906a846a3d71b2b7b33d6927cac3ff072e523ffac7853577464406 android.hardware.automotive.evs@1.1::IEvsUltrasonicsArrayStream +8a156203892de3cfa47baaccabef3c45b3315cae93b332357598d60896b1ac7f 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 +7d2e77ad86766bbc213fa7377eab739f44cc0866e567e6d33c0e27e7f99e27a8 android.hardware.automotive.sv@1.0::ISurroundViewSession +d34769e55df919739bb46f25ae2e125e9c807733afa94daeca20feadd74de79c android.hardware.automotive.sv@1.0::ISurroundViewStream +affd9c591f48a69773fcf43dc4a716d292cd4bc5ba2be8649276af0aedea435d android.hardware.automotive.sv@1.0::types +b3caf524c46a47d67e6453a34419e1881942d059e146cda740502670e9a752c3 android.hardware.automotive.vehicle@2.0::IVehicle +7ce8728b27600e840cacf0a832f6942819fe535f9d3797ae052d5eef5065921c android.hardware.automotive.vehicle@2.0::IVehicleCallback +6b2564fce1d364baf9ba15a5cb00a8f08f86a5be5387c0ede795328ca536a2c7 android.hardware.automotive.vehicle@2.0::types +7e8e1c3d0173c5d503dd01cecff8e3864478557ca6b9e8cc2291598b1a4aea62 android.hardware.biometrics.face@1.1::IBiometricsFace 140f8f62100ccf9cd282ae3685a0f4ef0a9f971d77dfbc7350ccb4e04cf295ec android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprint 82cad99f5feb2ea9bcd4579055edf4af8feb9fc602a6e4827ddd727d254d4991 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprintClientCallback ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types @@ -639,9 +667,13 @@ ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardwar 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types b8c63679e1a3874b356f3e691aecce1191d38f59063cf2ed2dce8a9d4cabf00e android.hardware.camera.device@3.6::ICameraDevice +eb90c4d366f05a025d1d1a3672f8b4c3e33e420fa387f73f21b264645bfdf845 android.hardware.camera.device@3.6::ICameraDeviceSession +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 8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback +1edf7aef68ef3bd577a1175b1462fb82e3e39f01c6915dda61fba121028df283 android.hardware.camera.provider@2.6::types c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas 9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardware.cas@1.2::IMediaCasService @@ -662,6 +694,13 @@ df52e2c39ed701a355b5e0fdbf83fe5fa7d04bfecd715116b39373d46dc3c682 android.hardwar 769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types 6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections 956c1576ca0d6f11b42980ef59052062836b6763fe973af6cb709da50787f710 android.hardware.gnss.measurement_corrections@1.1::types +a2dcf188b02102d3cf80ca0a280dce05d45a8df809751b3c52347426ed58ebbe android.hardware.graphics.allocator@4.0::IAllocator +0a90c665605df3d7d7b0fcafcc4178c3345a6e4ba7e3148fefe4973629827463 android.hardware.graphics.composer@2.4::IComposer +809b815bac3d9a5ead591b5fed20f08dbd2bcf7b5c6858201fdd0d8347db9177 android.hardware.graphics.composer@2.4::IComposerCallback +8006ee6e02453443f7e79cfcd9f85d9863bed53c4cfc55519de98b64ca72edc2 android.hardware.graphics.composer@2.4::IComposerClient +fda61f0a5a56cf4e0e8697fb4899a26a4dc450ff837f3425b53932fe34583d11 android.hardware.graphics.composer@2.4::types +4d674afdc4447f614c8cc466ed45c5955a0192fa3d3c70884b11dd3c88f0b468 android.hardware.graphics.mapper@4.0::IMapper +b58a5e83a8ab04ff6e500f6afc17a1129a1f3de044b296b4b6bd34a085220f87 android.hardware.graphics.mapper@4.0::types ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback e2f8bc1868fd4a3fd587c172773ea5a8c2f5a3deaf7958394102ca455252b255 android.hardware.health@2.1::types @@ -681,11 +720,15 @@ b454df853441c12f6e425e8a60dd29fda20f5e6e39b93d1103e4b37495db38aa android.hardwar fcbb0742a88215ee7a6d7ce0825d253eb2b50391fc6c8c48667f9fd7f6d4549e android.hardware.radio@1.5::IRadioIndication b809193970a91ca637a4b0184767315601d32e3ef3d5992ffbc7a8d14a14f015 android.hardware.radio@1.5::IRadioResponse 6b8dcd5e3e33a524cc7ebb14671a76ad3a2d333467397ce82acc4024346386f8 android.hardware.radio@1.5::types +c2cc192edcc222a12b524fb0e0e7f17ef2b48d6b1c0be7b60bc114601793d7a9 android.hardware.secure_element@1.2::ISecureElement 3ca6616381080bdd6c08141ad12775a94ae868c58b02b1274ae3326f7de724ab android.hardware.sensors@2.1::ISensors 3d4141c6373cd9ca02fe221a7d12343840de2255d032c38248fe8e35816b58b2 android.hardware.sensors@2.1::ISensorsCallback 8051cc50fc90ed447f058a8b15d81f35a65f1bd9004b1de4f127edeb89b47978 android.hardware.sensors@2.1::types b37f78e3fdc79af8b32a545b2b426f1fd1355b359d9e7835f3bf1ed0aa4518d8 android.hardware.soundtrigger@2.3::ISoundTriggerHw 4a6517ea4ad807855428b0101d8e1a486497bd88ab4300ba3b2be43d46d32580 android.hardware.soundtrigger@2.3::types +b878fcad575742925690303f717e2186058a378670be6e2f85e7e503841954aa android.hardware.tv.cec@2.0::IHdmiCec +009b9a02619b14da27027cb5d424fa01f098f6b6f6fa0829049497fc3612d67d android.hardware.tv.cec@2.0::IHdmiCecCallback +af1443272c4db47dea5adc5b6c4293dd09c20466a58684c68a5d88c0e7e46261 android.hardware.tv.cec@2.0::types adab52e647d1a1ccfbdabdfc9c73352f8e834b61322e505bc6e3d3a0d3acc259 android.hardware.tv.tuner@1.0::IDemux 548e1a16fc4f779346e14968a63cd6f160e1e2c8b8c99256b2bac24a24b52a9a android.hardware.tv.tuner@1.0::IDescrambler b84597d59f0f1d03c9997d60eb15280f3950c287d46016240d89859789db4d47 android.hardware.tv.tuner@1.0::IDvr @@ -701,6 +744,13 @@ c350c7783843e0c7cf30f90c918770b0d3c09fc0fe5e532e2f2e7210fcfe71c9 android.hardwar b335c3c732c799b299fa61c6de6260ab4d20cbd0ec21acd6db14d8156c745d0b android.hardware.tv.tuner@1.0::types 7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi +84757251ff195b447dc511c0d3f055a684d4fed7847eb4d65a2455eb914059d2 android.hardware.wifi@1.4::IWifiApIface +2e07983a70a1b963bee8aece050e5ea503a3dde31e21a9f8352cf17e9113d347 android.hardware.wifi@1.4::IWifiChip +08c1912be480c08aa77f6d56bb083d66cd13eca11e01c2d3e727bcb3a1e4f79b android.hardware.wifi@1.4::IWifiChipEventCallback +ff66371a467d1f3caacea15d93f39b7b767b0d6b8cd41d040337cdabf2514b87 android.hardware.wifi@1.4::IWifiNanIface +10bd6f19198c281ee2052641048e970ad66b732e4f6ffe79a0f697ea15761e0f android.hardware.wifi@1.4::IWifiRttController +fcd92a4c898360185dd659f0a1e3001c25eb40b59c3457fd235acf3a8c407525 android.hardware.wifi@1.4::IWifiRttControllerEventCallback +d878c406d9c1cc67f9d9a3a66b16dcbd7d944e0ed520745fc9ad21d95031e839 android.hardware.wifi@1.4::types c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant From a37ed88ebba9d60ab9a23ddd66fb16d36f9ce36c Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 25 Mar 2020 15:14:21 -0700 Subject: [PATCH 0743/1022] bpfmt compat matrix Android.bp Bug: 147496715 Test: n/A Change-Id: I2748d4a74f0bfc668f6ff0f8bce22c94dd90f61f --- compatibility_matrices/Android.bp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp index 33157a6fb8..2149c0cd91 100644 --- a/compatibility_matrices/Android.bp +++ b/compatibility_matrices/Android.bp @@ -23,8 +23,9 @@ vintf_compatibility_matrix { "kernel_config_o_3.18", "kernel_config_o_4.4", "kernel_config_o_4.9", - ] + ], } + vintf_compatibility_matrix { name: "framework_compatibility_matrix.1.xml", stem: "compatibility_matrix.1.xml", @@ -35,8 +36,9 @@ vintf_compatibility_matrix { "kernel_config_o_3.18", "kernel_config_o_4.4", "kernel_config_o_4.9", - ] + ], } + vintf_compatibility_matrix { name: "framework_compatibility_matrix.2.xml", stem: "compatibility_matrix.2.xml", @@ -47,7 +49,7 @@ vintf_compatibility_matrix { "kernel_config_o_mr1_3.18", "kernel_config_o_mr1_4.4", "kernel_config_o_mr1_4.9", - ] + ], } vintf_compatibility_matrix { @@ -60,7 +62,7 @@ vintf_compatibility_matrix { "kernel_config_p_4.4", "kernel_config_p_4.9", "kernel_config_p_4.14", - ] + ], } vintf_compatibility_matrix { @@ -73,7 +75,7 @@ vintf_compatibility_matrix { "kernel_config_q_4.9", "kernel_config_q_4.14", "kernel_config_q_4.19", - ] + ], } vintf_compatibility_matrix { @@ -86,5 +88,5 @@ vintf_compatibility_matrix { "kernel_config_r_4.14", "kernel_config_r_4.19", "kernel_config_r_5.4", - ] + ], } From 077c0339d4fdf289794ee9c401f490e8793d46ca Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Wed, 25 Mar 2020 16:45:04 -0700 Subject: [PATCH 0744/1022] Update the specification for the following operations - RANDOM_MULTINOMIAL - L2_NORMALIZATION Bug: 136279892 Bug: 140177375 Test: mm Change-Id: Iab38ef29ebf6d1f5c0a408436b3d564e45e537a0 --- current.txt | 6 +++--- neuralnetworks/1.0/types.hal | 10 +++++----- neuralnetworks/1.2/types.hal | 8 ++++---- neuralnetworks/1.3/types.hal | 12 ++++++++---- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/current.txt b/current.txt index 9c0a77695d..b8196a218a 100644 --- a/current.txt +++ b/current.txt @@ -594,11 +594,11 @@ bceee81ec1b59324abd05932b5620fda5a6589597c9cb3953ba7f3ea02cccd3e android.hardwar 2ce820dc4f3c6d85721b65150ed2157c6e2e2055f866fb6c6ba4790f14408d66 android.hardware.camera.provider@2.4::ICameraProviderCallback b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel -8eac60e1f724d141c71c69f06d4544acb720a55dfbbcd97fa01bb3d25ee4e2f5 android.hardware.neuralnetworks@1.0::types +92e101b30e47bdf526a01c52cecfbe730def5997b8260ab497eb949eb2a6dcdf android.hardware.neuralnetworks@1.0::types 5f6d3097ba84cb63c430787123f4de1b31c11f90b531b98eae9a8623a5ae962a android.hardware.neuralnetworks@1.1::types fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice 40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel -00649d29680f2c47edf60000c3ae7ae906ba638f0616947147e3676a83cf36fa android.hardware.neuralnetworks@1.2::types +ee1a0dee5be00a6fe2d4d3270068c78016dcb194d768fe07ed894ea20904037f android.hardware.neuralnetworks@1.2::types a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface @@ -676,7 +676,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 6e904be0ddca5ae1de8eba020e6c38ed935ea7d80cd08f47787f137a0ca58555 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback 2b0b10d2ea7a18a4048cd0eb83d35c19a817aeee95f65807fc31f4ef21381397 android.hardware.neuralnetworks@1.3::IPreparedModel eee3430cc86c97c7b407495863d8fb61da6f1a64b7721e77b9b4909b11b174e9 android.hardware.neuralnetworks@1.3::IPreparedModelCallback -e442ab1b440327fe4e8a3b0b8ac6874e9bc6342e91fe976eb9fea77c63961ec8 android.hardware.neuralnetworks@1.3::types +acf84925f8ee0a651f2ec547ac334034de266479b93af5434f6c1f25e66aba96 android.hardware.neuralnetworks@1.3::types b454df853441c12f6e425e8a60dd29fda20f5e6e39b93d1103e4b37495db38aa android.hardware.radio@1.5::IRadio fcbb0742a88215ee7a6d7ce0825d253eb2b50391fc6c8c48667f9fd7f6d4549e android.hardware.radio@1.5::IRadioIndication b809193970a91ca637a4b0184767315601d32e3ef3d5992ffbc7a8d14a14f015 android.hardware.radio@1.5::IRadioResponse diff --git a/neuralnetworks/1.0/types.hal b/neuralnetworks/1.0/types.hal index 1175a309dd..620eefb48b 100644 --- a/neuralnetworks/1.0/types.hal +++ b/neuralnetworks/1.0/types.hal @@ -261,7 +261,7 @@ enum OperationType : int32_t { * filter. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} - * the bias must be of the same type. + * the bias must be of the same type. * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. @@ -289,7 +289,7 @@ enum OperationType : int32_t { * filter. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} - * the bias must be of the same + * the bias must be of the same * type. * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint @@ -356,7 +356,7 @@ enum OperationType : int32_t { * specifying the filter. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} - * the bias must be of the same type. + * the bias must be of the same type. * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. @@ -385,7 +385,7 @@ enum OperationType : int32_t { * specifying the filter. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link OperandType::TENSOR_FLOAT32} - * the bias must be of the same type. + * the bias must be of the same type. * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, * the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. @@ -628,7 +628,7 @@ enum OperationType : int32_t { HASHTABLE_LOOKUP = 10, /** - * Applies L2 normalization along the depth dimension. + * Applies L2 normalization along the axis dimension. * * The values in the output tensor are computed as: * diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal index f0fd7690ba..2c3c599eef 100644 --- a/neuralnetworks/1.2/types.hal +++ b/neuralnetworks/1.2/types.hal @@ -846,7 +846,7 @@ enum OperationType : int32_t { HASHTABLE_LOOKUP = @1.1::OperationType:HASHTABLE_LOOKUP, /** - * Applies L2 normalization along the depth dimension. + * Applies L2 normalization along the axis dimension. * * The values in the output tensor are computed as: * @@ -854,8 +854,7 @@ enum OperationType : int32_t { * input[batch, row, col, channel] / * sqrt(sum_{c} pow(input[batch, row, col, c], 2)) * - * For input tensor with rank less than 4, independently normalizes each - * 1-D slice along dimension dim. + * By default the axis dimension is the last dimension of the input tensor. * * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) @@ -3843,7 +3842,8 @@ enum OperationType : int32_t { * * 1: A scalar {@link OperandType::INT32}, specifying the number of * independent samples to draw for each row slice. * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor with shape [2], - * specifying seeds used to initialize the random distribution. + * specifying seeds used to initialize the random distribution. If both + * provided seeds are 0, both will be randomly generated. * Outputs: * * 0: A 2-D {@link OperandType::TENSOR_INT32} tensor with shape * [batches, samples], containing the drawn samples. diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index 25ec915a8a..56930c2445 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -833,7 +833,7 @@ enum OperationType : int32_t { HASHTABLE_LOOKUP = @1.2::OperationType:HASHTABLE_LOOKUP, /** - * Applies L2 normalization along the depth dimension. + * Applies L2 normalization along the axis dimension. * * The values in the output tensor are computed as: * @@ -841,8 +841,7 @@ enum OperationType : int32_t { * input[batch, row, col, channel] / * sqrt(sum_{c} pow(input[batch, row, col, c], 2)) * - * For input tensor with rank less than 4, independently normalizes each - * 1-D slice along dimension dim. + * By default the axis dimension is the last dimension of the input tensor. * * Supported tensor {@link OperandType}: * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2) @@ -867,6 +866,10 @@ enum OperationType : int32_t { * the scale must be 1.f / 128 and the zeroPoint must be 128. * For {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, * the scale must be 1.f / 128 and the zeroPoint must be 0. + * + * NOTE: Before HAL version 1.3, if the elements along an axis are all zeros, + * the result is undefined. Since HAL version 1.3, if the elements along an axis + * are all zeros, the result is logical zero. */ L2_NORMALIZATION = @1.2::OperationType:L2_NORMALIZATION, @@ -4063,7 +4066,8 @@ enum OperationType : int32_t { * * 1: A scalar {@link OperandType::INT32}, specifying the number of * independent samples to draw for each row slice. * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor with shape [2], - * specifying seeds used to initialize the random distribution. + * specifying seeds used to initialize the random distribution. If both + * provided seeds are 0, both will be randomly generated. * Outputs: * * 0: A 2-D {@link OperandType::TENSOR_INT32} tensor with shape * [batches, samples], containing the drawn samples. From 8c583d85b64db2fd8d72e2550cae4342724ea2ef Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 25 Mar 2020 14:59:05 -0700 Subject: [PATCH 0745/1022] Freeze 'current' matrix as '5'. To signify this as being ready for release. Bug: 147496715 Test: build & boot cf (which is at target-level 5) Change-Id: I7bb9d561506849bac2353d9356a6580f6e2393ab --- compatibility_matrices/Android.bp | 6 +++--- compatibility_matrices/Android.mk | 2 +- ...bility_matrix.current.xml => compatibility_matrix.5.xml} | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename compatibility_matrices/{compatibility_matrix.current.xml => compatibility_matrix.5.xml} (98%) diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp index 2149c0cd91..ba56832bdd 100644 --- a/compatibility_matrices/Android.bp +++ b/compatibility_matrices/Android.bp @@ -79,10 +79,10 @@ vintf_compatibility_matrix { } vintf_compatibility_matrix { - name: "framework_compatibility_matrix.current.xml", - stem: "compatibility_matrix.current.xml", + name: "framework_compatibility_matrix.5.xml", + stem: "compatibility_matrix.5.xml", srcs: [ - "compatibility_matrix.current.xml", + "compatibility_matrix.5.xml", ], kernel_configs: [ "kernel_config_r_4.14", diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk index 6d204cb952..e69fc8dbca 100644 --- a/compatibility_matrices/Android.mk +++ b/compatibility_matrices/Android.mk @@ -97,7 +97,7 @@ my_system_matrix_deps := \ framework_compatibility_matrix.2.xml \ framework_compatibility_matrix.3.xml \ framework_compatibility_matrix.4.xml \ - framework_compatibility_matrix.current.xml \ + framework_compatibility_matrix.5.xml \ framework_compatibility_matrix.device.xml \ my_framework_matrix_deps += \ diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.5.xml similarity index 98% rename from compatibility_matrices/compatibility_matrix.current.xml rename to compatibility_matrices/compatibility_matrix.5.xml index f28a8b2ef6..b5f8413058 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.5.xml @@ -217,7 +217,7 @@ android.hardware.graphics.allocator - + 2.0 3.0 4.0 @@ -236,7 +236,7 @@ android.hardware.graphics.mapper - + 2.1 3.0 4.0 From 34445d98ede19218aadd01bec0fe9f4c48ad8769 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Fri, 13 Mar 2020 12:18:08 -0700 Subject: [PATCH 0746/1022] gralloc4-vts: fix Lock_YCBCR_420_888 test Updates Cb and Cr plane indexing. The existing code seems to use chromaStep as a sub-sampling factor and seems to assume that the underlying format is tri-planar. Updates Cb and Cr value checking. The existing code would write values into the Cb and Cr planes using a value derived from even-x-value and odd-y-value full-image-coordinates (e.g. (0,1)) but then check against the values in the Cb and Cr planes using a value derived from even-x-value and even-y-value coordinates (e.g. (0,0)). Updates y-plane sample increment check to confirm that it is multiple of 8. I don't see any requirements stating this needs to be 32 bits. Bug: b/146515640 Test: VtsHalGraphicsMapperV4_0Target Change-Id: Ia9e496ae43b2d1ac9ea8d57a4d4fc55f0be7b2b6 --- .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 6cc5e34326..82dbeb9c20 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -221,7 +221,7 @@ class GraphicsMapperHidlTest case PlaneLayoutComponentType::Y: ASSERT_EQ(nullptr, outYCbCr->y); ASSERT_EQ(8, planeLayoutComponent.sizeInBits); - ASSERT_EQ(32, planeLayout.sampleIncrementInBits); + ASSERT_EQ(8, planeLayout.sampleIncrementInBits); outYCbCr->y = tmpData; outYCbCr->ystride = planeLayout.strideInBytes; break; @@ -569,15 +569,21 @@ TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_420_888) { auto cStride = yCbCr.cstride; auto chromaStep = yCbCr.chroma_step; + constexpr uint32_t kCbCrSubSampleFactor = 2; + for (uint32_t y = 0; y < info.height; y++) { for (uint32_t x = 0; x < info.width; x++) { auto val = static_cast(info.height * y + x); yData[yStride * y + x] = val; - if (y % chromaStep && x % chromaStep == 0) { - cbData[cStride * y / chromaStep + x / chromaStep] = val; - crData[cStride * y / chromaStep + x / chromaStep] = val; + if (y % kCbCrSubSampleFactor && x % kCbCrSubSampleFactor == 0) { + uint32_t subSampleX = x / kCbCrSubSampleFactor; + uint32_t subSampleY = y / kCbCrSubSampleFactor; + auto subSampleVal = static_cast(info.height * subSampleY + subSampleX); + + cbData[cStride * subSampleY + chromaStep * subSampleX] = subSampleVal; + crData[cStride * subSampleY + chromaStep * subSampleX] = subSampleVal; } } } @@ -599,9 +605,13 @@ TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_420_888) { EXPECT_EQ(val, yData[yStride * y + x]); - if (y % chromaStep == 0 && x % chromaStep == 0) { - EXPECT_EQ(val, cbData[cStride * y / chromaStep + x / chromaStep]); - EXPECT_EQ(val, crData[cStride * y / chromaStep + x / chromaStep]); + if (y % kCbCrSubSampleFactor == 0 && x % kCbCrSubSampleFactor == 0) { + uint32_t subSampleX = x / kCbCrSubSampleFactor; + uint32_t subSampleY = y / kCbCrSubSampleFactor; + auto subSampleVal = static_cast(info.height * subSampleY + subSampleX); + + EXPECT_EQ(subSampleVal, cbData[cStride * subSampleY + chromaStep * subSampleX]); + EXPECT_EQ(subSampleVal, crData[cStride * subSampleY + chromaStep * subSampleX]); } } } From 3acbd20198ecb81b471fa15caa149d823b313709 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 25 Mar 2020 15:16:45 -0700 Subject: [PATCH 0747/1022] Add compatibility_matrix.current.xml for S Bug: 152310927 Test: build only (b/150215458 for enabling this on cf) Change-Id: Id33494d8433ba58362c592deb2598fe89127561e --- compatibility_matrices/Android.bp | 13 + compatibility_matrices/Android.mk | 1 + .../compatibility_matrix.current.xml | 560 ++++++++++++++++++ 3 files changed, 574 insertions(+) create mode 100644 compatibility_matrices/compatibility_matrix.current.xml diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp index ba56832bdd..9d4e55cce0 100644 --- a/compatibility_matrices/Android.bp +++ b/compatibility_matrices/Android.bp @@ -90,3 +90,16 @@ vintf_compatibility_matrix { "kernel_config_r_5.4", ], } + +vintf_compatibility_matrix { + name: "framework_compatibility_matrix.current.xml", + stem: "compatibility_matrix.current.xml", + srcs: [ + "compatibility_matrix.current.xml", + ], + kernel_configs: [ + "kernel_config_current_4.14", + "kernel_config_current_4.19", + "kernel_config_current_5.4", + ], +} diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk index e69fc8dbca..96191c8997 100644 --- a/compatibility_matrices/Android.mk +++ b/compatibility_matrices/Android.mk @@ -98,6 +98,7 @@ my_system_matrix_deps := \ framework_compatibility_matrix.3.xml \ framework_compatibility_matrix.4.xml \ framework_compatibility_matrix.5.xml \ + framework_compatibility_matrix.current.xml \ framework_compatibility_matrix.device.xml \ my_framework_matrix_deps += \ diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml new file mode 100644 index 0000000000..8e939686a1 --- /dev/null +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -0,0 +1,560 @@ + + + android.hardware.atrace + 1.0 + + IAtraceDevice + default + + + + android.hardware.audio + 6.0 + + IDevicesFactory + default + + + + android.hardware.audio.effect + 6.0 + + IEffectsFactory + default + + + + android.hardware.authsecret + 1.0 + + IAuthSecret + default + + + + android.hardware.automotive.audiocontrol + 1.0 + + IAudioControl + default + + + + android.hardware.automotive.can + 1.0 + + ICanBus + .* + + + ICanController + .* + + + + android.hardware.automotive.evs + 1.0-1 + + IEvsEnumerator + default + [a-z]+/[0-9]+ + + + + android.hardware.automotive.occupant_awareness + + IOccupantAwareness + default + + + + android.hardware.automotive.sv + 1.0 + + ISurroundView + default + + + + android.hardware.automotive.vehicle + 2.0 + + IVehicle + default + + + + android.hardware.biometrics.face + 1.0-1 + + IBiometricsFace + default + + + + android.hardware.biometrics.fingerprint + 2.1 + + IBiometricsFingerprint + default + + + + android.hardware.bluetooth + 1.0-1 + + IBluetoothHci + default + + + + android.hardware.bluetooth.audio + 2.0 + + IBluetoothAudioProvidersFactory + default + + + + android.hardware.boot + 1.1 + + IBootControl + default + + + + android.hardware.broadcastradio + 1.0-1 + + IBroadcastRadioFactory + default + + + + android.hardware.broadcastradio + 2.0 + + IBroadcastRadio + .* + + + + android.hardware.camera.provider + 2.4-6 + + ICameraProvider + [^/]+/[0-9]+ + + + + android.hardware.cas + 1.1-2 + + IMediaCasService + default + + + + android.hardware.configstore + 1.1 + + ISurfaceFlingerConfigs + default + + + + android.hardware.confirmationui + 1.0 + + IConfirmationUI + default + + + + android.hardware.contexthub + 1.0-1 + + IContexthub + default + + + + android.hardware.drm + 1.3 + + ICryptoFactory + .* + + + IDrmFactory + .* + + + + android.hardware.dumpstate + 1.1 + + IDumpstateDevice + default + + + + android.hardware.gatekeeper + 1.0 + + IGatekeeper + default + + + + android.hardware.gnss + 2.0-1 + + IGnss + default + + + + android.hardware.graphics.allocator + + 2.0 + 3.0 + 4.0 + + IAllocator + default + + + + android.hardware.graphics.composer + 2.1-4 + + IComposer + default + + + + android.hardware.graphics.mapper + + 2.1 + 3.0 + 4.0 + + IMapper + default + + + + android.hardware.health + 2.1 + + IHealth + default + + + + android.hardware.health.storage + 1.0 + + IStorage + default + + + + android.hardware.identity + + IIdentityCredentialStore + default + + + + android.hardware.ir + 1.0 + + IConsumerIr + default + + + + android.hardware.input.classifier + 1.0 + + IInputClassifier + default + + + + android.hardware.keymaster + 3.0 + 4.0-1 + + IKeymasterDevice + default + + + + android.hardware.keymaster + 4.0-1 + + IKeymasterDevice + strongbox + + + + android.hardware.light + + ILights + default + + + + android.hardware.media.c2 + 1.0-1 + + IComponentStore + default[0-9]* + vendor[0-9]*_software + + + + android.hardware.media.omx + 1.0 + + IOmx + default + + + IOmxStore + default + + + + android.hardware.memtrack + 1.0 + + IMemtrack + default + + + + android.hardware.neuralnetworks + 1.0-3 + + IDevice + .* + + + + android.hardware.nfc + 1.2 + + INfc + default + + + + android.hardware.oemlock + 1.0 + + IOemLock + default + + + + android.hardware.power + + IPower + default + + + + android.hardware.power.stats + 1.0 + + IPowerStats + default + + + + android.hardware.radio + 1.5 + + IRadio + slot1 + slot2 + slot3 + + + + android.hardware.radio + 1.2 + + ISap + slot1 + + + + android.hardware.radio.config + + 1.1 + + IRadioConfig + default + + + + android.hardware.renderscript + 1.0 + + IDevice + default + + + + android.hardware.rebootescrow + + IRebootEscrow + default + + + + android.hardware.secure_element + 1.0-2 + + ISecureElement + eSE[1-9][0-9]* + SIM[1-9][0-9]* + + + + android.hardware.sensors + 1.0 + 2.0-1 + + ISensors + default + + + + android.hardware.soundtrigger + 2.0-3 + + ISoundTriggerHw + default + + + + android.hardware.tetheroffload.config + 1.0 + + IOffloadConfig + default + + + + android.hardware.tetheroffload.control + 1.0 + + IOffloadControl + default + + + + android.hardware.thermal + 2.0 + + IThermal + default + + + + android.hardware.tv.cec + 1.0 + + IHdmiCec + default + + + + android.hardware.tv.input + 1.0 + + ITvInput + default + + + + android.hardware.tv.tuner + 1.0 + + ITuner + default + + + + android.hardware.usb + 1.0-2 + + IUsb + default + + + + android.hardware.usb.gadget + 1.0-1 + + IUsbGadget + default + + + + android.hardware.vibrator + + IVibrator + default + + + + android.hardware.vr + 1.0 + + IVr + default + + + + android.hardware.weaver + 1.0 + + IWeaver + default + + + + android.hardware.wifi + 1.0-4 + + IWifi + default + + + + android.hardware.wifi.hostapd + 1.0-2 + + IHostapd + default + + + + android.hardware.wifi.supplicant + 1.0-3 + + ISupplicant + default + + + From 01247f9508f3ac20a0302c2f7f9d9aa211dfcb55 Mon Sep 17 00:00:00 2001 From: chrisweir Date: Thu, 9 Jan 2020 15:55:44 -0800 Subject: [PATCH 0748/1022] CAN Configurator Service Configurator service for the CAN HAL and extracting some of the CAN HAL configuration logic into a library for the various tools to share. Bug: 142653776 Test: Manual Change-Id: Id33871da851bcb442a7f851919f713ec913830ff (cherry picked from commit 33ce7505d150a39eb288f3062ee2090afc734199) --- automotive/can/1.0/tools/Android.bp | 9 ++ automotive/can/1.0/tools/canhalctrl.cpp | 24 +-- .../can/1.0/tools/configurator/Android.bp | 34 ++++ .../tools/configurator/canhalconfigurator.cpp | 103 ++++++++++++ .../tools/configurator/canhalconfigurator.rc | 3 + .../1.0/tools/configurator/canprototools.cpp | 152 ++++++++++++++++++ .../1.0/tools/configurator/canprototools.h | 49 ++++++ .../1.0/tools/configurator/proto/Android.bp | 28 ++++ .../configurator/proto/canbus_config.proto | 52 ++++++ .../can/1.0/tools/libcanhaltools/Android.bp | 32 ++++ .../include/libcanhaltools/libcanhaltools.h | 48 ++++++ .../tools/libcanhaltools/libcanhaltools.cpp | 85 ++++++++++ 12 files changed, 599 insertions(+), 20 deletions(-) create mode 100644 automotive/can/1.0/tools/configurator/Android.bp create mode 100644 automotive/can/1.0/tools/configurator/canhalconfigurator.cpp create mode 100644 automotive/can/1.0/tools/configurator/canhalconfigurator.rc create mode 100644 automotive/can/1.0/tools/configurator/canprototools.cpp create mode 100644 automotive/can/1.0/tools/configurator/canprototools.h create mode 100644 automotive/can/1.0/tools/configurator/proto/Android.bp create mode 100644 automotive/can/1.0/tools/configurator/proto/canbus_config.proto create mode 100644 automotive/can/1.0/tools/libcanhaltools/Android.bp create mode 100644 automotive/can/1.0/tools/libcanhaltools/include/libcanhaltools/libcanhaltools.h create mode 100644 automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp diff --git a/automotive/can/1.0/tools/Android.bp b/automotive/can/1.0/tools/Android.bp index 21f364b629..a6c40d933a 100644 --- a/automotive/can/1.0/tools/Android.bp +++ b/automotive/can/1.0/tools/Android.bp @@ -27,6 +27,9 @@ cc_binary { header_libs: [ "android.hardware.automotive.can@hidl-utils-lib", ], + static_libs: [ + "android.hardware.automotive.can@libcanhaltools", + ], } cc_binary { @@ -42,6 +45,9 @@ cc_binary { header_libs: [ "android.hardware.automotive.can@hidl-utils-lib", ], + static_libs: [ + "android.hardware.automotive.can@libcanhaltools", + ], } cc_binary { @@ -54,4 +60,7 @@ cc_binary { "android.hardware.automotive.can@1.0", "libhidlbase", ], + static_libs: [ + "android.hardware.automotive.can@libcanhaltools", + ], } diff --git a/automotive/can/1.0/tools/canhalctrl.cpp b/automotive/can/1.0/tools/canhalctrl.cpp index 33755bfffd..c186b74386 100644 --- a/automotive/can/1.0/tools/canhalctrl.cpp +++ b/automotive/can/1.0/tools/canhalctrl.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -41,34 +42,17 @@ static void usage() { std::cerr << " bus name - name under which ICanBus will be published" << std::endl; } -static hidl_vec getControlServices() { - auto manager = hidl::manager::V1_2::IServiceManager::getService(); - hidl_vec services; - manager->listManifestByInterface(ICanController::descriptor, hidl_utils::fill(&services)); - if (services.size() == 0) { - std::cerr << "No ICanController services registered (missing privileges?)" << std::endl; - exit(-1); - } - return services; -} - -static bool isSupported(sp ctrl, ICanController::InterfaceType iftype) { - hidl_vec supported; - if (!ctrl->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).isOk()) return false; - return supported.contains(iftype); -} - static int up(const std::string& busName, ICanController::InterfaceType type, const std::string& interface, uint32_t bitrate) { bool anySupported = false; - for (auto&& service : getControlServices()) { + for (auto&& service : libcanhaltools::getControlServices()) { auto ctrl = ICanController::getService(service); if (ctrl == nullptr) { std::cerr << "Couldn't open ICanController/" << service; continue; } - if (!isSupported(ctrl, type)) continue; + if (!libcanhaltools::isSupported(ctrl, type)) continue; anySupported = true; ICanController::BusConfig config = {}; @@ -111,7 +95,7 @@ static int up(const std::string& busName, ICanController::InterfaceType type, } static int down(const std::string& busName) { - for (auto&& service : getControlServices()) { + for (auto&& service : libcanhaltools::getControlServices()) { auto ctrl = ICanController::getService(service); if (ctrl == nullptr) continue; diff --git a/automotive/can/1.0/tools/configurator/Android.bp b/automotive/can/1.0/tools/configurator/Android.bp new file mode 100644 index 0000000000..2c4bc1d6fc --- /dev/null +++ b/automotive/can/1.0/tools/configurator/Android.bp @@ -0,0 +1,34 @@ +// +// 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. +// + +cc_binary { + name: "canhalconfigurator", + init_rc: ["canhalconfigurator.rc"], + defaults: ["android.hardware.automotive.can@defaults"], + srcs: [ + "canhalconfigurator.cpp", + "canprototools.cpp", + ], + shared_libs: [ + "android.hardware.automotive.can@1.0", + "libhidlbase", + "libprotobuf-cpp-full", + ], + static_libs: [ + "android.hardware.automotive.can@1.x-config-format", + "android.hardware.automotive.can@libcanhaltools", + ], +} diff --git a/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp b/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp new file mode 100644 index 0000000000..a100f06f1b --- /dev/null +++ b/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp @@ -0,0 +1,103 @@ +/* + * 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 "canbus_config.pb.h" +#include "canprototools.h" + +#include +#include +#include + +#include +#include + +namespace android::hardware::automotive::can { + +using ICanController = V1_0::ICanController; + +/** + * Takes output from parsed protobuf config and uses it to configure the CAN HAL. + * + * \param pb_cfg is an instance of the autogenerated protobuf object for our configuration. + * \return boolean status, true on success, false on failure. + */ +static bool processPbCfg(const config::CanBusConfig& pb_cfg) { + for (auto const& bus : pb_cfg.buses()) { + if (bus.name().empty()) { + LOG(ERROR) << "Invalid config: Bus config must have a valid name field"; + return false; + } + + LOG(INFO) << "Configure " << bus.name(); + auto bus_cfg = config::fromPbBus(bus); + if (!bus_cfg.has_value()) { + return false; + } + + // TODO(149405589): remove this sleep and associated includes. + std::this_thread::sleep_for(std::chrono::seconds(1)); + if (libcanhaltools::configureIface(*bus_cfg) != ICanController::Result::OK) { + LOG(ERROR) << "No controller supports " << bus.name() << std::endl; + // TODO(149405589): add retry logic in case a bus fails to come up. + continue; + } + LOG(INFO) << bus.name() << " has been successfully configured!"; + } + return true; +} + +/** + * This kicks off the CAN HAL configuration process. This starts the following: + * 1. Reading the config file + * 2. Setting up CAN buses + * 3. Handling services + * \param filepath is a string specifying the absolute path of the config file + * \return boolean status, true on success, false on failure + */ +static bool configuratorStart(const std::string& filepath) { + base::SetDefaultTag("CanConfigurator"); + + auto pb_cfg = config::parseConfigFile(filepath); + if (!pb_cfg.has_value()) { + return false; + } + + // process the rest of the config file data and configure the CAN buses. + if (!processPbCfg(*pb_cfg)) { + return false; + } + LOG(INFO) << "CAN HAL has been configured!"; + return true; +} + +} // namespace android::hardware::automotive::can + +int main(int argc, char* argv[]) { + std::string config_filepath = "/etc/canbus_config.pb"; + + // allow for CLI specification of a config file. + if (argc == 2) { + config_filepath = argv[1]; + } else if (argc > 2) { + std::cerr << "usage: " << argv[0] << " [optional config filepath]"; + return 1; + } + + if (!::android::hardware::automotive::can::configuratorStart(config_filepath)) { + return 1; + } + return 0; +} diff --git a/automotive/can/1.0/tools/configurator/canhalconfigurator.rc b/automotive/can/1.0/tools/configurator/canhalconfigurator.rc new file mode 100644 index 0000000000..12c24652dd --- /dev/null +++ b/automotive/can/1.0/tools/configurator/canhalconfigurator.rc @@ -0,0 +1,3 @@ +service canhalconfigurator /system/bin/canhalconfigurator + class core + oneshot diff --git a/automotive/can/1.0/tools/configurator/canprototools.cpp b/automotive/can/1.0/tools/configurator/canprototools.cpp new file mode 100644 index 0000000000..8e6b2b1d45 --- /dev/null +++ b/automotive/can/1.0/tools/configurator/canprototools.cpp @@ -0,0 +1,152 @@ +/* + * 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 "canprototools.h" + +#include +#include +#include +#include +#include + +#include + +namespace android::hardware::automotive::can::config { + +using ICanController = V1_0::ICanController; + +/** + * Helper function for parseConfigFile. readString is used to get the fist n characters (n) from an + * istream object (s) and return it as a string object. + * + * \param s istream of the file you intend to read. + * \param n streamsize object of the number of characters you'd like. + * \return optional string containing up to n characters from the stream(s) you provided. + */ +static std::optional readString(std::istream& s, std::streamsize n) { + char buff[n]; + auto got = s.read(buff, n).gcount(); + if (!s.good() && !s.eof()) return std::nullopt; + return std::string(buff, 0, std::min(n, got)); +} + +std::optional parseConfigFile(const std::string& filepath) { + std::ifstream cfg_stream(filepath); + + // text headers that would be present in a plaintext proto config file. + static const std::array text_headers = {"buses", "#", "controller"}; + auto cfg_file_snippet = readString(cfg_stream, 10); + + if (!cfg_file_snippet.has_value()) { + LOG(ERROR) << "Can't open " << filepath << " for reading"; + return std::nullopt; + } + cfg_stream.seekg(0); + + // check if any of the textHeaders are at the start of the config file. + bool text_format = false; + for (auto const& header : text_headers) { + if (cfg_file_snippet->compare(0, header.length(), header) == 0) { + text_format = true; + break; + } + } + + CanBusConfig config; + if (text_format) { + google::protobuf::io::IstreamInputStream pb_stream(&cfg_stream); + if (!google::protobuf::TextFormat::Parse(&pb_stream, &config)) { + LOG(ERROR) << "Failed to parse (text format) " << filepath; + return std::nullopt; + } + } else if (!config.ParseFromIstream(&cfg_stream)) { + LOG(ERROR) << "Failed to parse (binary format) " << filepath; + return std::nullopt; + } + return config; +} + +std::optional fromPbBus(const Bus& pb_bus) { + ICanController::BusConfig bus_cfg = {}; + bus_cfg.name = pb_bus.name(); + + switch (pb_bus.iface_type_case()) { + case Bus::kNative: { + const auto ifname = pb_bus.native().ifname(); + if (ifname.empty()) { + LOG(ERROR) << "Invalid config: native type bus must have an iface name"; + return std::nullopt; + } + bus_cfg.bitrate = pb_bus.bitrate(); + ICanController::BusConfig::InterfaceId::Socketcan socketcan = {}; + socketcan.ifname(ifname); + bus_cfg.interfaceId.socketcan(socketcan); + // TODO(b/142654031) - add support for serial number as an option instead of ifname. + break; + } + case Bus::kSlcan: { + const auto ttyname = pb_bus.slcan().ttyname(); + if (ttyname.empty()) { + LOG(ERROR) << "Invalid config: slcan type bus must have a tty name"; + return std::nullopt; + } + bus_cfg.bitrate = pb_bus.bitrate(); + ICanController::BusConfig::InterfaceId::Slcan slcan = {}; + slcan.ttyname(pb_bus.slcan().ttyname()); + bus_cfg.interfaceId.slcan(slcan); + break; + } + case Bus::kVirtual: { + // Theoretically, we could just create the next available vcan iface. + const auto ifname = pb_bus.virtual_().ifname(); + if (ifname.empty()) { + LOG(ERROR) << "Invalid config: native type bus must have an iface name"; + return std::nullopt; + } + bus_cfg.interfaceId.virtualif({ifname}); + break; + } + case Bus::kIndexed: { + const auto index = pb_bus.indexed().index(); + if (index > UINT8_MAX) { + LOG(ERROR) << "Interface index out of range: " << index; + return std::nullopt; + } + bus_cfg.interfaceId.indexed({uint8_t(index)}); + break; + } + default: + LOG(ERROR) << "Invalid config: bad interface type for " << bus_cfg.name; + return std::nullopt; + } + return bus_cfg; +} + +std::optional getHalIftype(const Bus& pb_bus) { + switch (pb_bus.iface_type_case()) { + case Bus::kNative: + return ICanController::InterfaceType::SOCKETCAN; + case Bus::kSlcan: + return ICanController::InterfaceType::SLCAN; + case Bus::kVirtual: + return ICanController::InterfaceType::VIRTUAL; + case Bus::kIndexed: + return ICanController::InterfaceType::INDEXED; + default: + return std::nullopt; + } +} + +} // namespace android::hardware::automotive::can::config diff --git a/automotive/can/1.0/tools/configurator/canprototools.h b/automotive/can/1.0/tools/configurator/canprototools.h new file mode 100644 index 0000000000..b7f2b6f0d2 --- /dev/null +++ b/automotive/can/1.0/tools/configurator/canprototools.h @@ -0,0 +1,49 @@ +/* + * 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. + */ +#pragma once + +#include "canbus_config.pb.h" + +#include + +namespace android::hardware::automotive::can::config { + +/** + * This reads the protobuf config file into a protobuf object. Both text based protobuf files as + * well as binary format protobuf files are supported. + * + * \param filepath string containing the name of the config file to read. + * \return a CanBusConfig protobuf object constructed from the config file. + */ +std::optional parseConfigFile(const std::string& filepath); + +/** + * Converts protobuf format single-bus config object to a HAL bus config object. + * + * \param pb_bus is the protobuf object representing a the configuration of one CAN bus. + * \return a converted HAL bus config object. + */ +std::optional fromPbBus(const Bus& pb_bus); + +/** + * Get the CAN HAL interface type specified by a given protobuf config object. + * + * \param pb_bus is the protobuf object representing a the configuration of one CAN bus. + * \return the CAN HAL interface type. + */ +std::optional getHalIftype(const Bus& pb_bus); + +} // namespace android::hardware::automotive::can::config diff --git a/automotive/can/1.0/tools/configurator/proto/Android.bp b/automotive/can/1.0/tools/configurator/proto/Android.bp new file mode 100644 index 0000000000..05e120524a --- /dev/null +++ b/automotive/can/1.0/tools/configurator/proto/Android.bp @@ -0,0 +1,28 @@ +// +// 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. +// + +cc_library_static { + name: "android.hardware.automotive.can@1.x-config-format", + defaults: ["android.hardware.automotive.can@defaults"], + proto: { + export_proto_headers: true, + type: "full", + }, + strip: { + keep_symbols: true, + }, + srcs: ["canbus_config.proto"], +} diff --git a/automotive/can/1.0/tools/configurator/proto/canbus_config.proto b/automotive/can/1.0/tools/configurator/proto/canbus_config.proto new file mode 100644 index 0000000000..9aa33aceb5 --- /dev/null +++ b/automotive/can/1.0/tools/configurator/proto/canbus_config.proto @@ -0,0 +1,52 @@ +/* + * 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. + */ + +syntax = "proto3"; + +package android.hardware.automotive.can.config; + +message IfaceNative { + string ifname = 1; + repeated string serialno = 2; +}; + +message IfaceSlcan { + string ttyname = 1; + repeated string serialno = 2; +}; + +message IfaceVirtual { + string ifname = 1; +}; + +message IfaceIndexed { + uint32 index = 1; +}; + +message Bus { + string name = 1; // this is the name presented in the HAL + oneof iface_type { + IfaceNative native = 2; + IfaceSlcan slcan = 3; + IfaceVirtual virtual = 4; + IfaceIndexed indexed = 5; + } + uint32 bitrate = 6; +}; + +message CanBusConfig { + repeated Bus buses = 1; +}; diff --git a/automotive/can/1.0/tools/libcanhaltools/Android.bp b/automotive/can/1.0/tools/libcanhaltools/Android.bp new file mode 100644 index 0000000000..cee9eef20d --- /dev/null +++ b/automotive/can/1.0/tools/libcanhaltools/Android.bp @@ -0,0 +1,32 @@ +// +// 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. +// + +cc_library_static { + name: "android.hardware.automotive.can@libcanhaltools", + defaults: ["android.hardware.automotive.can@defaults"], + vendor_available: true, + srcs: [ + "libcanhaltools.cpp", + ], + export_include_dirs: ["include"], + shared_libs: [ + "android.hardware.automotive.can@1.0", + "libhidlbase", + ], + header_libs: [ + "android.hardware.automotive.can@hidl-utils-lib", + ], +} diff --git a/automotive/can/1.0/tools/libcanhaltools/include/libcanhaltools/libcanhaltools.h b/automotive/can/1.0/tools/libcanhaltools/include/libcanhaltools/libcanhaltools.h new file mode 100644 index 0000000000..bbd1fe5873 --- /dev/null +++ b/automotive/can/1.0/tools/libcanhaltools/include/libcanhaltools/libcanhaltools.h @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +namespace android::hardware::automotive::can::libcanhaltools { + +/** + * Fetch the list of registered can controller services. + * + * \return list of service names identifying the registered can controllers. + */ +hidl_vec getControlServices(); + +/** + * Determine if an can controller supports a specific interface type. + * + * \param ctrl a pointer to a can controller instance to check for interface support. + * \param iftype the interface type we wish to check if ctrl supports. + * \return true if iftype is supported by ctrl, false if not supported. + */ +bool isSupported(sp ctrl, V1_0::ICanController::InterfaceType iftype); + +/** + * Configures a CAN interface through the CAN HAL and brings it up. + * + * \param can_config this holds the parameters for configuring a CAN bus. + * \return status passed back from the CAN HAL, should be OK on success. + */ +V1_0::ICanController::Result configureIface(V1_0::ICanController::BusConfig can_config); + +} // namespace android::hardware::automotive::can::libcanhaltools diff --git a/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp b/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp new file mode 100644 index 0000000000..9192e2f52d --- /dev/null +++ b/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp @@ -0,0 +1,85 @@ +/* + * 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 "libcanhaltools/libcanhaltools.h" + +#include +#include +#include +#include + +#include +#include + +namespace android::hardware::automotive::can::libcanhaltools { + +using ICanBus = V1_0::ICanBus; +using ICanController = V1_0::ICanController; +using IfIdDisc = ICanController::BusConfig::InterfaceId::hidl_discriminator; + +hidl_vec getControlServices() { + auto manager = hidl::manager::V1_2::IServiceManager::getService(); + hidl_vec services; + manager->listManifestByInterface(ICanController::descriptor, hidl_utils::fill(&services)); + CHECK(services.size() > 0) << "No ICanController services registered (missing privileges?)" + << std::endl; + return services; +} + +bool isSupported(sp ctrl, ICanController::InterfaceType iftype) { + hidl_vec supported; + if (!ctrl->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).isOk()) return false; + return supported.contains(iftype); +} + +ICanController::InterfaceType getIftype(ICanController::BusConfig can_config) { + switch (can_config.interfaceId.getDiscriminator()) { + case IfIdDisc::socketcan: + return ICanController::InterfaceType::SOCKETCAN; + case IfIdDisc::slcan: + return ICanController::InterfaceType::SLCAN; + case IfIdDisc::virtualif: + return ICanController::InterfaceType::VIRTUAL; + case IfIdDisc::indexed: + return ICanController::InterfaceType::INDEXED; + default: + CHECK(false) << "HAL returned unexpected interface type!"; + } +} + +ICanController::Result configureIface(ICanController::BusConfig can_config) { + auto iftype = getIftype(can_config); + auto can_controller_list = getControlServices(); + for (auto const& service : can_controller_list) { + auto ctrl = ICanController::getService(service); + if (ctrl == nullptr) { + LOG(ERROR) << "Couldn't open ICanController/" << service; + continue; + } + + if (!libcanhaltools::isSupported(ctrl, iftype)) continue; + + const auto up_result = ctrl->upInterface(can_config); + if (up_result != ICanController::Result::OK) { + LOG(ERROR) << "Failed to bring " << can_config.name << " up: " << toString(up_result) + << std::endl; + } + return up_result; + } + return ICanController::Result::NOT_SUPPORTED; +} + +} // namespace android::hardware::automotive::can::libcanhaltools From 8fd2a85b6d00f8678d876df250c838b4f9d89adb Mon Sep 17 00:00:00 2001 From: chrisweir Date: Fri, 21 Feb 2020 10:16:17 -0800 Subject: [PATCH 0749/1022] Clean up TODOs Squeegee supports Android now, so I'm cleaning up my TODOs. Bug: 144458917 Bug: 144775286 Test: Only changes to comments Change-Id: Ifd9907ba944759d4d5b36bce92f6bd11b5bb74e7 (cherry picked from commit 1ab35548682491d8f5ead7bb9b618c5c36a8fcf4) --- automotive/can/1.0/default/CanBus.cpp | 2 -- automotive/can/1.0/default/CanBusSlcan.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp index 9f704c1ebd..8b98e5ee2b 100644 --- a/automotive/can/1.0/default/CanBus.cpp +++ b/automotive/can/1.0/default/CanBus.cpp @@ -226,7 +226,6 @@ bool CanBus::down() { * \param flag bool object from CanMessage object */ static bool satisfiesFilterFlag(FilterFlag filterFlag, bool flag) { - // TODO(b/144458917) add testing for this to VTS tests if (filterFlag == FilterFlag::DONT_CARE) return true; if (filterFlag == FilterFlag::SET) return flag; if (filterFlag == FilterFlag::NOT_SET) return !flag; @@ -302,7 +301,6 @@ void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds ti if ((frame.can_id & CAN_ERR_FLAG) != 0) { // error bit is set LOG(WARNING) << "CAN Error frame received"; - // TODO(b/144458917) consider providing different values for isFatal, depending on error notifyErrorListeners(parseErrorFrame(frame), false); return; } diff --git a/automotive/can/1.0/default/CanBusSlcan.cpp b/automotive/can/1.0/default/CanBusSlcan.cpp index d15905da53..5005ecd642 100644 --- a/automotive/can/1.0/default/CanBusSlcan.cpp +++ b/automotive/can/1.0/default/CanBusSlcan.cpp @@ -133,7 +133,7 @@ ICanController::Result CanBusSlcan::preUp() { return ICanController::Result::UNKNOWN_ERROR; } - // set open flag TODO: also support listen only + // TODO(b/144775286): set open flag & support listen only if (write(mFd.get(), slcanprotocol::kOpenCommand.c_str(), slcanprotocol::kOpenCommand.length()) <= 0) { LOG(ERROR) << "Failed to set open flag: " << strerror(errno); From 77b837f0ad0c4c703b65b6f19b632b56851f0bd6 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Fri, 28 Feb 2020 10:07:28 -0800 Subject: [PATCH 0750/1022] graphics: update OWNERS marissaw@ is leaving. jessehall@ is on a different team. Remove them and add new owners. Test: Compiles Bug: 150462113 Change-Id: I922710de701d3923268591bcb48db3e12acb0500 (cherry picked from commit 88417a586b889eec772e3acab5dffaba18a0e678) --- graphics/allocator/2.0/default/OWNERS | 4 ++-- graphics/allocator/2.0/utils/OWNERS | 4 ++-- graphics/mapper/2.0/default/OWNERS | 4 ++-- graphics/mapper/2.0/utils/OWNERS | 4 ++-- graphics/mapper/2.0/vts/OWNERS | 4 +++- graphics/mapper/2.1/default/OWNERS | 4 ++-- graphics/mapper/2.1/utils/OWNERS | 4 ++-- graphics/mapper/2.1/vts/OWNERS | 4 +++- graphics/mapper/3.0/utils/OWNERS | 3 ++- graphics/mapper/3.0/vts/OWNERS | 3 ++- graphics/mapper/4.0/utils/OWNERS | 3 ++- graphics/mapper/4.0/vts/OWNERS | 3 ++- 12 files changed, 26 insertions(+), 18 deletions(-) diff --git a/graphics/allocator/2.0/default/OWNERS b/graphics/allocator/2.0/default/OWNERS index 273cb4c4b9..2a56b381a4 100644 --- a/graphics/allocator/2.0/default/OWNERS +++ b/graphics/allocator/2.0/default/OWNERS @@ -1,4 +1,4 @@ # Graphics team -jessehall@google.com -marissaw@google.com +chrisforbes@google.com stoza@google.com +vhau@google.com diff --git a/graphics/allocator/2.0/utils/OWNERS b/graphics/allocator/2.0/utils/OWNERS index 273cb4c4b9..2a56b381a4 100644 --- a/graphics/allocator/2.0/utils/OWNERS +++ b/graphics/allocator/2.0/utils/OWNERS @@ -1,4 +1,4 @@ # Graphics team -jessehall@google.com -marissaw@google.com +chrisforbes@google.com stoza@google.com +vhau@google.com diff --git a/graphics/mapper/2.0/default/OWNERS b/graphics/mapper/2.0/default/OWNERS index 273cb4c4b9..2a56b381a4 100644 --- a/graphics/mapper/2.0/default/OWNERS +++ b/graphics/mapper/2.0/default/OWNERS @@ -1,4 +1,4 @@ # Graphics team -jessehall@google.com -marissaw@google.com +chrisforbes@google.com stoza@google.com +vhau@google.com diff --git a/graphics/mapper/2.0/utils/OWNERS b/graphics/mapper/2.0/utils/OWNERS index 273cb4c4b9..2a56b381a4 100644 --- a/graphics/mapper/2.0/utils/OWNERS +++ b/graphics/mapper/2.0/utils/OWNERS @@ -1,4 +1,4 @@ # Graphics team -jessehall@google.com -marissaw@google.com +chrisforbes@google.com stoza@google.com +vhau@google.com diff --git a/graphics/mapper/2.0/vts/OWNERS b/graphics/mapper/2.0/vts/OWNERS index 8e86f64c9d..11b7d216ce 100644 --- a/graphics/mapper/2.0/vts/OWNERS +++ b/graphics/mapper/2.0/vts/OWNERS @@ -1,5 +1,7 @@ # Graphics team -marissaw@google.com +chrisforbes@google.com +stoza@google.com +vhau@google.com # VTS team yim@google.com diff --git a/graphics/mapper/2.1/default/OWNERS b/graphics/mapper/2.1/default/OWNERS index 273cb4c4b9..2a56b381a4 100644 --- a/graphics/mapper/2.1/default/OWNERS +++ b/graphics/mapper/2.1/default/OWNERS @@ -1,4 +1,4 @@ # Graphics team -jessehall@google.com -marissaw@google.com +chrisforbes@google.com stoza@google.com +vhau@google.com diff --git a/graphics/mapper/2.1/utils/OWNERS b/graphics/mapper/2.1/utils/OWNERS index 273cb4c4b9..2a56b381a4 100644 --- a/graphics/mapper/2.1/utils/OWNERS +++ b/graphics/mapper/2.1/utils/OWNERS @@ -1,4 +1,4 @@ # Graphics team -jessehall@google.com -marissaw@google.com +chrisforbes@google.com stoza@google.com +vhau@google.com diff --git a/graphics/mapper/2.1/vts/OWNERS b/graphics/mapper/2.1/vts/OWNERS index 8e86f64c9d..11b7d216ce 100644 --- a/graphics/mapper/2.1/vts/OWNERS +++ b/graphics/mapper/2.1/vts/OWNERS @@ -1,5 +1,7 @@ # Graphics team -marissaw@google.com +chrisforbes@google.com +stoza@google.com +vhau@google.com # VTS team yim@google.com diff --git a/graphics/mapper/3.0/utils/OWNERS b/graphics/mapper/3.0/utils/OWNERS index 96f6d51573..2a56b381a4 100644 --- a/graphics/mapper/3.0/utils/OWNERS +++ b/graphics/mapper/3.0/utils/OWNERS @@ -1,3 +1,4 @@ # Graphics team -marissaw@google.com +chrisforbes@google.com stoza@google.com +vhau@google.com diff --git a/graphics/mapper/3.0/vts/OWNERS b/graphics/mapper/3.0/vts/OWNERS index 96f6d51573..2a56b381a4 100644 --- a/graphics/mapper/3.0/vts/OWNERS +++ b/graphics/mapper/3.0/vts/OWNERS @@ -1,3 +1,4 @@ # Graphics team -marissaw@google.com +chrisforbes@google.com stoza@google.com +vhau@google.com diff --git a/graphics/mapper/4.0/utils/OWNERS b/graphics/mapper/4.0/utils/OWNERS index 96f6d51573..2a56b381a4 100644 --- a/graphics/mapper/4.0/utils/OWNERS +++ b/graphics/mapper/4.0/utils/OWNERS @@ -1,3 +1,4 @@ # Graphics team -marissaw@google.com +chrisforbes@google.com stoza@google.com +vhau@google.com diff --git a/graphics/mapper/4.0/vts/OWNERS b/graphics/mapper/4.0/vts/OWNERS index 96f6d51573..2a56b381a4 100644 --- a/graphics/mapper/4.0/vts/OWNERS +++ b/graphics/mapper/4.0/vts/OWNERS @@ -1,3 +1,4 @@ # Graphics team -marissaw@google.com +chrisforbes@google.com stoza@google.com +vhau@google.com From e0affee86b789d76cca3b0bdce25954af19bbeef Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Mon, 23 Mar 2020 13:04:53 -0600 Subject: [PATCH 0751/1022] Remove IOperation and beginOp. The way I planned for this to work doesn't work. We'll revisit in Keymaster5. For now, removing IOperation and beginOp. Bug: 152536287 Test: Build & boot Change-Id: I017d17079380cc3bacc6f05b2486e1b6e6c3f675 --- current.txt | 3 +- keymaster/4.1/Android.bp | 1 - keymaster/4.1/IKeymasterDevice.hal | 16 -------- keymaster/4.1/IOperation.hal | 31 --------------- .../include/keymasterV4_1/Keymaster3.h | 12 ------ .../include/keymasterV4_1/Keymaster4.h | 15 -------- .../support/include/keymasterV4_1/Operation.h | 38 ------------------- 7 files changed, 1 insertion(+), 115 deletions(-) delete mode 100644 keymaster/4.1/IOperation.hal delete mode 100644 keymaster/4.1/support/include/keymasterV4_1/Operation.h diff --git a/current.txt b/current.txt index f9c64bf6ca..dbe23cced8 100644 --- a/current.txt +++ b/current.txt @@ -704,8 +704,7 @@ b58a5e83a8ab04ff6e500f6afc17a1129a1f3de044b296b4b6bd34a085220f87 android.hardwar ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback e2f8bc1868fd4a3fd587c172773ea5a8c2f5a3deaf7958394102ca455252b255 android.hardware.health@2.1::types -27ae3724053940462114228872b3ffaf0b8e6177d5ba97f5a76339d12b8a99dd android.hardware.keymaster@4.1::IKeymasterDevice -adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardware.keymaster@4.1::IOperation +c5da8636c14cd30f1ae9f10c2219e35b4e29a64443103a5842352dd070afe514 android.hardware.keymaster@4.1::IKeymasterDevice ddcf89cd8ee2df0d32aee55050826446fb64f7aafde0a7cd946c64f61b1a364c android.hardware.keymaster@4.1::types df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore diff --git a/keymaster/4.1/Android.bp b/keymaster/4.1/Android.bp index 3b505d890f..f6ac6f8426 100644 --- a/keymaster/4.1/Android.bp +++ b/keymaster/4.1/Android.bp @@ -9,7 +9,6 @@ hidl_interface { srcs: [ "types.hal", "IKeymasterDevice.hal", - "IOperation.hal", ], interfaces: [ "android.hardware.keymaster@3.0", diff --git a/keymaster/4.1/IKeymasterDevice.hal b/keymaster/4.1/IKeymasterDevice.hal index 1456abe038..bbeccaaf5c 100644 --- a/keymaster/4.1/IKeymasterDevice.hal +++ b/keymaster/4.1/IKeymasterDevice.hal @@ -24,8 +24,6 @@ import @4.0::KeyPurpose; import @4.0::OperationHandle; import @4.0::VerificationToken; -import IOperation; - /** * @4.1::IKeymasterDevice is a minor extension to @4.0::IKeymasterDevice. It adds support for * @@ -78,18 +76,4 @@ interface IKeymasterDevice extends @4.0::IKeymasterDevice { * an EARLY_BOOT_ONLY key after this method is called must fail with Error::INVALID_KEY_BLOB. */ earlyBootEnded() generates (ErrorCode error); - - /** - * Begins a cryptographic operation. beginOp() is a variation on begin(). beginOp() has - * identical functionality to begin, but instead of an OperationHandle it returns an IOperation - * object. An IKeymasterDevice HAL service must call linkToDeath() on the Operation before - * returning it, and the provided hidl_death_recipient, if called, must abort() the operation. - * This is to ensure that in the event a client crashes while an operation is in progress, the - * operation slot is freed and available for use by other clients. - * - * @4.1::IKeymasterDevices must implement both beginOp() and begin(). - */ - beginOp(KeyPurpose purpose, vec keyBlob, vec inParams, - HardwareAuthToken authToken) - generates (ErrorCode error, vec outParam, IOperation operation); }; diff --git a/keymaster/4.1/IOperation.hal b/keymaster/4.1/IOperation.hal deleted file mode 100644 index 7103e9e535..0000000000 --- a/keymaster/4.1/IOperation.hal +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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. - */ - -package android.hardware.keymaster@4.1; - -import @4.0::ErrorCode; -import @4.0::OperationHandle; - -/** - * IOperation represents an in-progress IKeymasterDevice operation. It is returned by - * IKeymasterDevice.beginOp(). - */ -interface IOperation { - /** - * Returns the operation handle to be used as an authentication challenge. - */ - getOperationChallenge() generates (ErrorCode error, OperationHandle operation); -}; diff --git a/keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h index c201e8c0b2..a27f78f5ef 100644 --- a/keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h +++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h @@ -19,7 +19,6 @@ #include #include "Keymaster.h" -#include "Operation.h" namespace android::hardware::keymaster::V4_1::support { @@ -122,17 +121,6 @@ class Keymaster3 : public Keymaster { Return earlyBootEnded() override { return ErrorCode::UNIMPLEMENTED; } - Return beginOp(KeyPurpose purpose, const hidl_vec& keyBlob, - const hidl_vec& inParams, const HardwareAuthToken& authToken, - beginOp_cb _hidl_cb) override { - return begin(purpose, keyBlob, inParams, authToken, - [&_hidl_cb](V4_0::ErrorCode errorCode, const hidl_vec& outParams, - OperationHandle operationHandle) { - _hidl_cb(static_cast(errorCode), outParams, - new Operation(operationHandle)); - }); - } - private: void getVersionIfNeeded(); diff --git a/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h index 6d74d980a0..75d9139e83 100644 --- a/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h +++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h @@ -17,7 +17,6 @@ #pragma once #include "Keymaster.h" -#include "Operation.h" namespace android::hardware::keymaster::V4_1::support { @@ -171,20 +170,6 @@ class Keymaster4 : public Keymaster { return ErrorCode::UNIMPLEMENTED; } - Return beginOp(KeyPurpose purpose, const hidl_vec& keyBlob, - const hidl_vec& inParams, const HardwareAuthToken& authToken, - beginOp_cb _hidl_cb) override { - if (km4_1_dev_) return km4_1_dev_->beginOp(purpose, keyBlob, inParams, authToken, _hidl_cb); - - return km4_0_dev_->begin( - purpose, keyBlob, inParams, authToken, - [&_hidl_cb](V4_0::ErrorCode errorCode, const hidl_vec& outParams, - OperationHandle operationHandle) { - _hidl_cb(static_cast(errorCode), outParams, - new Operation(operationHandle)); - }); - } - private: void getVersionIfNeeded(); diff --git a/keymaster/4.1/support/include/keymasterV4_1/Operation.h b/keymaster/4.1/support/include/keymasterV4_1/Operation.h deleted file mode 100644 index 902d49ac20..0000000000 --- a/keymaster/4.1/support/include/keymasterV4_1/Operation.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - ** Copyright 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. - */ - -#pragma once - -#include - -#include - -namespace android::hardware::keymaster::V4_1::support { - -class Operation : public IOperation { - public: - Operation(OperationHandle handle) : handle_(handle) {} - - Return getOperationChallenge(getOperationChallenge_cb _hidl_cb) override { - _hidl_cb(V4_1::ErrorCode::OK, handle_); - return Void(); - } - - private: - OperationHandle handle_; -}; - -} // namespace android::hardware::keymaster::V4_1::support From 2aa757432a977e8e2d4126cc6d2263baab499df8 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 19 Mar 2020 15:37:42 -0700 Subject: [PATCH 0752/1022] Update HAL Bands Test: mm cf_x86_phone-userdebug Test: atest VtsHalRadioV1_5Target Bug: 151842542 Change-Id: I3d2b1328693b18cd4a51da6795228ef3b5d2b473 --- current.txt | 2 +- radio/1.5/types.hal | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/current.txt b/current.txt index f9c64bf6ca..339df2f48e 100644 --- a/current.txt +++ b/current.txt @@ -719,7 +719,7 @@ e442ab1b440327fe4e8a3b0b8ac6874e9bc6342e91fe976eb9fea77c63961ec8 android.hardwar b454df853441c12f6e425e8a60dd29fda20f5e6e39b93d1103e4b37495db38aa android.hardware.radio@1.5::IRadio fcbb0742a88215ee7a6d7ce0825d253eb2b50391fc6c8c48667f9fd7f6d4549e android.hardware.radio@1.5::IRadioIndication b809193970a91ca637a4b0184767315601d32e3ef3d5992ffbc7a8d14a14f015 android.hardware.radio@1.5::IRadioResponse -6b8dcd5e3e33a524cc7ebb14671a76ad3a2d333467397ce82acc4024346386f8 android.hardware.radio@1.5::types +a5bcd595a5108312fe2eb402e716d0b7dab8eb689a2a5f54fdef3ff71f3babd5 android.hardware.radio@1.5::types c2cc192edcc222a12b524fb0e0e7f17ef2b48d6b1c0be7b60bc114601793d7a9 android.hardware.secure_element@1.2::ISecureElement 3ca6616381080bdd6c08141ad12775a94ae868c58b02b1274ae3326f7de724ab android.hardware.sensors@2.1::ISensors 3d4141c6373cd9ca02fe221a7d12343840de2255d032c38248fe8e35816b58b2 android.hardware.sensors@2.1::ISensorsCallback diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal index 248f56e846..b061bd51c8 100644 --- a/radio/1.5/types.hal +++ b/radio/1.5/types.hal @@ -203,6 +203,9 @@ struct RadioAccessSpecifier { vec channels; }; +/** + * IRadio 1.5 supports NGRAN bands up to V16.2.0 + */ enum NgranBands : int32_t { /** 3GPP TS 38.101-1, Table 5.2-1: FR1 bands */ BAND_1 = 1, @@ -243,7 +246,13 @@ enum NgranBands : int32_t { BAND_83 = 83, BAND_84 = 84, BAND_86 = 86, + BAND_89 = 89, BAND_90 = 90, + BAND_91 = 91, + BAND_92 = 92, + BAND_93 = 93, + BAND_94 = 94, + BAND_95 = 95, /** 3GPP TS 38.101-2, Table 5.2-1: FR2 bands */ BAND_257 = 257, BAND_258 = 258, @@ -251,6 +260,10 @@ enum NgranBands : int32_t { BAND_261 = 261, }; +/** + * Extended from @1.1 UtranBands to add TD-SCDMA bands + * IRadio 1.5 supports UTRAN bands up to V15.0.0 + */ enum UtranBands : @1.1::UtranBands { /** TD-SCDMA bands. 3GPP TS 25.102, Table 5.2: Frequency bands */ BAND_A = 101, @@ -261,6 +274,25 @@ enum UtranBands : @1.1::UtranBands { BAND_F = 106, }; +/** + * Extended from @1.1 EutranBands to add more bands from 3GPP TS 36.101, Table 5.5: Operating bands + * IRadio 1.5 supports EUTRAN bands up to V16.4.0 + */ +enum EutranBands : @1.1::EutranBands { + BAND_49 = 49, + BAND_50 = 50, + BAND_51 = 51, + BAND_52 = 52, + BAND_53 = 53, + BAND_71 = 71, + BAND_72 = 72, + BAND_73 = 73, + BAND_74 = 74, + BAND_85 = 85, + BAND_87 = 87, + BAND_88 = 88, +}; + /** * Overwritten from @1.2::NetworkScanRequest to update RadioAccessSpecifier to 1.5 version. */ From 7f817f5e2387a5835f41a1c8491def51d34ba1d9 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Thu, 26 Mar 2020 21:27:59 -0700 Subject: [PATCH 0753/1022] Wifi: Fix vts tests error handling In current code, VTS tests checks on null pointer using EXPECT_NE then proceed with using the variable. This causes a null pointer exception when the test fails. This commit replaces the EXPECT_NE with ASSERT_NE to exit the test on failure. Bug: 152576797 Test: atest VtsHalWifiV1_0TargetTest Change-Id: I5e54634020216f91144a234caf2b990de5706d8c --- wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp | 14 +++++++------- .../functional/wifi_rtt_controller_hidl_test.cpp | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp index f332001711..2ea8841170 100644 --- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp @@ -377,7 +377,7 @@ TEST_P(WifiChipHidlTest, GetP2pIfaceNames) { sp iface; EXPECT_EQ(WifiStatusCode::SUCCESS, createP2pIface(&iface)); - EXPECT_NE(nullptr, iface.get()); + ASSERT_NE(nullptr, iface.get()); std::string iface_name = getIfaceName(iface); const auto& status_and_iface_names2 = @@ -404,7 +404,7 @@ TEST_P(WifiChipHidlTest, GetP2pIface) { sp p2p_iface; EXPECT_EQ(WifiStatusCode::SUCCESS, createP2pIface(&p2p_iface)); - EXPECT_NE(nullptr, p2p_iface.get()); + ASSERT_NE(nullptr, p2p_iface.get()); std::string iface_name = getIfaceName(p2p_iface); const auto& status_and_iface1 = @@ -430,7 +430,7 @@ TEST_P(WifiChipHidlTest, RemoveP2pIface) { sp p2p_iface; EXPECT_EQ(WifiStatusCode::SUCCESS, createP2pIface(&p2p_iface)); - EXPECT_NE(nullptr, p2p_iface.get()); + ASSERT_NE(nullptr, p2p_iface.get()); std::string iface_name = getIfaceName(p2p_iface); std::string invalid_name = iface_name + "0"; @@ -470,7 +470,7 @@ TEST_P(WifiChipHidlTest, GetStaIfaceNames) { sp iface; EXPECT_EQ(WifiStatusCode::SUCCESS, createStaIface(&iface)); - EXPECT_NE(nullptr, iface.get()); + ASSERT_NE(nullptr, iface.get()); std::string iface_name = getIfaceName(iface); const auto& status_and_iface_names2 = @@ -497,7 +497,7 @@ TEST_P(WifiChipHidlTest, GetStaIface) { sp sta_iface; EXPECT_EQ(WifiStatusCode::SUCCESS, createStaIface(&sta_iface)); - EXPECT_NE(nullptr, sta_iface.get()); + ASSERT_NE(nullptr, sta_iface.get()); std::string iface_name = getIfaceName(sta_iface); const auto& status_and_iface1 = @@ -523,7 +523,7 @@ TEST_P(WifiChipHidlTest, RemoveStaIface) { sp sta_iface; EXPECT_EQ(WifiStatusCode::SUCCESS, createStaIface(&sta_iface)); - EXPECT_NE(nullptr, sta_iface.get()); + ASSERT_NE(nullptr, sta_iface.get()); std::string iface_name = getIfaceName(sta_iface); std::string invalid_name = iface_name + "0"; @@ -542,7 +542,7 @@ TEST_P(WifiChipHidlTest, CreateRttController) { sp iface; EXPECT_EQ(WifiStatusCode::SUCCESS, createStaIface(&iface)); - EXPECT_NE(nullptr, iface.get()); + ASSERT_NE(nullptr, iface.get()); const auto& status_and_rtt_controller = HIDL_INVOKE(wifi_chip_, createRttController, iface); diff --git a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp index 1eb9c99149..1014c1dc68 100644 --- a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp @@ -59,10 +59,10 @@ TEST_P(WifiRttControllerHidlTest, Create) { const std::string& instance_name = GetInstanceName(); sp wifi_chip = getWifiChip(instance_name); - EXPECT_NE(nullptr, wifi_chip.get()); + ASSERT_NE(nullptr, wifi_chip.get()); sp wifi_sta_iface = getWifiStaIface(instance_name); - EXPECT_NE(nullptr, wifi_sta_iface.get()); + ASSERT_NE(nullptr, wifi_sta_iface.get()); const auto& status_and_controller = HIDL_INVOKE(wifi_chip, createRttController, wifi_sta_iface); From 75a80f6b602a3b206474dd983f27fa921897515c Mon Sep 17 00:00:00 2001 From: chrisweir Date: Wed, 26 Feb 2020 14:39:56 -0800 Subject: [PATCH 0754/1022] Clean up errno logs and sto* conversions I learned that we should be using PLOG to log errno strings, and we should be avoiding stoi, stol, etc... conversions and instead use the built in Android ParseInt/ParseUint functions. Bug: 150250606 Bug: 150245058 Test: Manual for CLI tools, VTS for everything else Merged-In: Icdd8a6af8564d5de3bedd1bc934f7928eb5e66e9 Change-Id: Icdd8a6af8564d5de3bedd1bc934f7928eb5e66e9 (cherry picked from commit 1173a7253becba2b548057112372c8a94d9b6a41) --- automotive/can/1.0/default/CanBusSlcan.cpp | 20 +++++++++---------- automotive/can/1.0/default/CanSocket.cpp | 6 +++--- .../default/libnetdevice/NetlinkSocket.cpp | 8 ++++---- .../can/1.0/default/libnetdevice/can.cpp | 2 +- .../1.0/default/libnetdevice/libnetdevice.cpp | 2 +- automotive/can/1.0/tools/canhalctrl.cpp | 13 +++++++----- automotive/can/1.0/tools/canhalsend.cpp | 11 +++++----- 7 files changed, 32 insertions(+), 30 deletions(-) diff --git a/automotive/can/1.0/default/CanBusSlcan.cpp b/automotive/can/1.0/default/CanBusSlcan.cpp index d15905da53..a1ef23e206 100644 --- a/automotive/can/1.0/default/CanBusSlcan.cpp +++ b/automotive/can/1.0/default/CanBusSlcan.cpp @@ -56,7 +56,7 @@ ICanController::Result CanBusSlcan::updateIfaceName(base::unique_fd& uartFd) { * that has already been configured and brought up. */ if (ioctl(uartFd.get(), SIOCGIFNAME, ifrequest.ifr_name) < 0) { - LOG(ERROR) << "Failed to get the name of the created device: " << strerror(errno); + PLOG(ERROR) << "Failed to get the name of the created device"; return ICanController::Result::UNKNOWN_ERROR; } @@ -80,7 +80,7 @@ ICanController::Result CanBusSlcan::preUp() { * controlling terminal */ mFd = base::unique_fd(open(mUartName.c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY)); if (!mFd.ok()) { - LOG(ERROR) << "SLCAN Failed to open " << mUartName << ": " << strerror(errno); + PLOG(ERROR) << "SLCAN Failed to open " << mUartName; return ICanController::Result::BAD_INTERFACE_ID; } @@ -92,7 +92,7 @@ ICanController::Result CanBusSlcan::preUp() { // blank terminal settings and pull them from the device struct termios terminalSettings = {}; if (tcgetattr(mFd.get(), &terminalSettings) < 0) { - LOG(ERROR) << "Failed to read attrs of" << mUartName << ": " << strerror(errno); + PLOG(ERROR) << "Failed to read attrs of" << mUartName; return ICanController::Result::UNKNOWN_ERROR; } @@ -107,42 +107,40 @@ ICanController::Result CanBusSlcan::preUp() { struct serial_struct serialSettings; // get serial settings if (ioctl(mFd.get(), TIOCGSERIAL, &serialSettings) < 0) { - LOG(ERROR) << "Failed to read serial settings from " << mUartName << ": " - << strerror(errno); + PLOG(ERROR) << "Failed to read serial settings from " << mUartName; return ICanController::Result::UNKNOWN_ERROR; } // set low latency mode serialSettings.flags |= ASYNC_LOW_LATENCY; // apply serial settings if (ioctl(mFd.get(), TIOCSSERIAL, &serialSettings) < 0) { - LOG(ERROR) << "Failed to set low latency mode on " << mUartName << ": " << strerror(errno); + PLOG(ERROR) << "Failed to set low latency mode on " << mUartName; return ICanController::Result::UNKNOWN_ERROR; } /* TCSADRAIN applies settings after we finish writing the rest of our * changes (as opposed to TCSANOW, which changes immediately) */ if (tcsetattr(mFd.get(), TCSADRAIN, &terminalSettings) < 0) { - LOG(ERROR) << "Failed to apply terminal settings to " << mUartName << ": " - << strerror(errno); + PLOG(ERROR) << "Failed to apply terminal settings to " << mUartName; return ICanController::Result::UNKNOWN_ERROR; } // apply speed setting for CAN if (write(mFd.get(), canBitrateCommand->c_str(), canBitrateCommand->length()) <= 0) { - LOG(ERROR) << "Failed to apply CAN bitrate: " << strerror(errno); + PLOG(ERROR) << "Failed to apply CAN bitrate"; return ICanController::Result::UNKNOWN_ERROR; } // set open flag TODO: also support listen only if (write(mFd.get(), slcanprotocol::kOpenCommand.c_str(), slcanprotocol::kOpenCommand.length()) <= 0) { - LOG(ERROR) << "Failed to set open flag: " << strerror(errno); + PLOG(ERROR) << "Failed to set open flag"; return ICanController::Result::UNKNOWN_ERROR; } // set line discipline to slcan if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kSlcanDiscipline) < 0) { - LOG(ERROR) << "Failed to set line discipline to slcan: " << strerror(errno); + PLOG(ERROR) << "Failed to set line discipline to slcan"; return ICanController::Result::UNKNOWN_ERROR; } diff --git a/automotive/can/1.0/default/CanSocket.cpp b/automotive/can/1.0/default/CanSocket.cpp index 86ccc0e84e..f379d5a070 100644 --- a/automotive/can/1.0/default/CanSocket.cpp +++ b/automotive/can/1.0/default/CanSocket.cpp @@ -67,7 +67,7 @@ CanSocket::~CanSocket() { bool CanSocket::send(const struct canfd_frame& frame) { const auto res = write(mSocket.get(), &frame, CAN_MTU); if (res < 0) { - LOG(DEBUG) << "CanSocket send failed: " << errno; + PLOG(DEBUG) << "CanSocket send failed"; return false; } if (res != CAN_MTU) { @@ -102,7 +102,7 @@ void CanSocket::readerThread() { const auto sel = selectRead(mSocket, kReadPooling); if (sel == 0) continue; // timeout if (sel == -1) { - LOG(ERROR) << "Select failed: " << errno; + PLOG(ERROR) << "Select failed"; break; } @@ -130,7 +130,7 @@ void CanSocket::readerThread() { if (errno == EAGAIN) continue; errnoCopy = errno; - LOG(ERROR) << "Failed to read CAN packet: " << strerror(errno) << " (" << errno << ")"; + PLOG(ERROR) << "Failed to read CAN packet"; break; } diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp index 6a7f50681d..7817169876 100644 --- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp +++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp @@ -23,7 +23,7 @@ namespace android::netdevice { NetlinkSocket::NetlinkSocket(int protocol) { mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol)); if (!mFd.ok()) { - LOG(ERROR) << "Can't open Netlink socket: " << errno; + PLOG(ERROR) << "Can't open Netlink socket"; mFailed = true; return; } @@ -32,7 +32,7 @@ NetlinkSocket::NetlinkSocket(int protocol) { sa.nl_family = AF_NETLINK; if (bind(mFd.get(), reinterpret_cast(&sa), sizeof(sa)) < 0) { - LOG(ERROR) << "Can't bind Netlink socket: " << errno; + PLOG(ERROR) << "Can't bind Netlink socket"; mFd.reset(); mFailed = true; } @@ -57,7 +57,7 @@ bool NetlinkSocket::send(struct nlmsghdr* nlmsg) { msg.msg_iovlen = 1; if (sendmsg(mFd.get(), &msg, 0) < 0) { - LOG(ERROR) << "Can't send Netlink message: " << errno; + PLOG(ERROR) << "Can't send Netlink message"; return false; } return true; @@ -79,7 +79,7 @@ bool NetlinkSocket::receiveAck() { const ssize_t status = recvmsg(mFd.get(), &msg, 0); if (status < 0) { - LOG(ERROR) << "Failed to receive Netlink message: " << errno; + PLOG(ERROR) << "Failed to receive Netlink message"; return false; } size_t remainingLen = status; diff --git a/automotive/can/1.0/default/libnetdevice/can.cpp b/automotive/can/1.0/default/libnetdevice/can.cpp index 06d45d3b7d..a2a85dcae8 100644 --- a/automotive/can/1.0/default/libnetdevice/can.cpp +++ b/automotive/can/1.0/default/libnetdevice/can.cpp @@ -48,7 +48,7 @@ base::unique_fd socket(const std::string& ifname) { } if (setsockopt(sock.get(), SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &kErrMask, sizeof(kErrMask)) < 0) { - LOG(ERROR) << "Can't receive error frames, CAN setsockpt failed: " << strerror(errno); + PLOG(ERROR) << "Can't receive error frames, CAN setsockpt failed"; return {}; } diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp index aee820573f..b05144209e 100644 --- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp +++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp @@ -41,7 +41,7 @@ static bool sendIfreq(unsigned long request, struct ifreq& ifr) { } if (ioctl(sock.get(), request, &ifr) < 0) { - LOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed: " << errno; + PLOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed"; return false; } diff --git a/automotive/can/1.0/tools/canhalctrl.cpp b/automotive/can/1.0/tools/canhalctrl.cpp index 33755bfffd..c1377e6bbd 100644 --- a/automotive/can/1.0/tools/canhalctrl.cpp +++ b/automotive/can/1.0/tools/canhalctrl.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -88,8 +89,8 @@ static int up(const std::string& busName, ICanController::InterfaceType type, slcan.ttyname(interface); config.interfaceId.slcan(slcan); } else if (type == ICanController::InterfaceType::INDEXED) { - auto idx = std::stol(interface); - if (idx < 0 || idx > UINT8_MAX) { + unsigned idx; + if (!android::base::ParseUint(interface, &idx, unsigned(UINT8_MAX))) { std::cerr << "Interface index out of range: " << idx; return -1; } @@ -162,9 +163,11 @@ static int main(int argc, char* argv[]) { return -1; } - long long bitrate = 0; - if (argc == 4) { - bitrate = std::stoll(argv[3]); + uint32_t bitrate = 0; + if (argc == 4 && !android::base::ParseUint(argv[3], &bitrate)) { + std::cerr << "Invalid bitrate!" << std::endl; + usage(); + return -1; } return up(busName, *type, interface, bitrate); diff --git a/automotive/can/1.0/tools/canhalsend.cpp b/automotive/can/1.0/tools/canhalsend.cpp index 7e6833a8a6..b22ad4d1cb 100644 --- a/automotive/can/1.0/tools/canhalsend.cpp +++ b/automotive/can/1.0/tools/canhalsend.cpp @@ -81,16 +81,17 @@ static std::optional>> parse const std::string msgidStr = msg.substr(0, hashpos); const std::string payloadStr = msg.substr(hashpos + 1); - size_t idx = 0; - V1_0::CanMessageId msgid = std::stoi(msgidStr, &idx, 16); - if (msgidStr[idx] != '\0') return std::nullopt; + V1_0::CanMessageId msgid; + // "0x" must be prepended to msgidStr, since ParseUint doesn't accept a base argument. + if (!android::base::ParseUint("0x" + msgidStr, &msgid)) return std::nullopt; std::vector payload; if (payloadStr.size() % 2 != 0) return std::nullopt; for (size_t i = 0; i < payloadStr.size(); i += 2) { std::string byteStr(payloadStr, i, 2); - payload.emplace_back(std::stoi(byteStr, &idx, 16)); - if (byteStr[idx] != '\0') return std::nullopt; + uint8_t byteBuf; + if (!android::base::ParseUint("0x" + byteStr, &byteBuf)) return std::nullopt; + payload.emplace_back(byteBuf); } return {{msgid, payload}}; From 779c6327ecbd1f34abbea4a588ea804c692da50a Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Fri, 27 Mar 2020 10:40:26 -0700 Subject: [PATCH 0755/1022] Add vintf_fragments to keymaster@4.1-service Bug: 152616625 Bug: 152554068 Test: boot emulator, lshal | grep keymaster Signed-off-by: Roman Kiryanov Merged-In: I36818fdc0f7732174fc7b2fd7619b1ae75b5b33d Change-Id: I2d7336c3f45ee7722d04ade091d50432e1fd6f99 --- keymaster/4.1/default/Android.bp | 1 + .../android.hardware.keymaster@4.1-service.xml | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 keymaster/4.1/default/android.hardware.keymaster@4.1-service.xml diff --git a/keymaster/4.1/default/Android.bp b/keymaster/4.1/default/Android.bp index 27297b9e45..3442b181bb 100644 --- a/keymaster/4.1/default/Android.bp +++ b/keymaster/4.1/default/Android.bp @@ -20,6 +20,7 @@ cc_binary { relative_install_path: "hw", vendor: true, init_rc: ["android.hardware.keymaster@4.1-service.rc"], + vintf_fragments: ["android.hardware.keymaster@4.1-service.xml"], srcs: ["service.cpp"], shared_libs: [ diff --git a/keymaster/4.1/default/android.hardware.keymaster@4.1-service.xml b/keymaster/4.1/default/android.hardware.keymaster@4.1-service.xml new file mode 100644 index 0000000000..9ba05c5540 --- /dev/null +++ b/keymaster/4.1/default/android.hardware.keymaster@4.1-service.xml @@ -0,0 +1,11 @@ + + + android.hardware.keymaster + hwbinder + 4.1 + + IKeymasterDevice + default + + + From d6afead9fc6961e1a18f9af3820ec1d15d9f6470 Mon Sep 17 00:00:00 2001 From: Amy Date: Tue, 10 Mar 2020 16:56:59 -0700 Subject: [PATCH 0756/1022] Copy filtered av data to ion buffer to test on cuttlefish Test: atest VtsHalTvTunerV1_0TargetTest Bug: 150952766 Change-Id: If007f9c021102dc95be8e9dc70be70d3945192a9 --- tv/tuner/1.0/default/Android.bp | 1 + tv/tuner/1.0/default/Filter.cpp | 166 ++++++++++++++++-- tv/tuner/1.0/default/Filter.h | 12 ++ tv/tuner/1.0/default/Frontend.cpp | 5 +- tv/tuner/1.0/default/Frontend.h | 1 - tv/tuner/1.0/default/Tuner.cpp | 2 +- .../VtsHalTvTunerV1_0TargetTest.cpp | 65 ++++++- .../VtsHalTvTunerV1_0TestConfigurations.h | 5 +- 8 files changed, 227 insertions(+), 30 deletions(-) diff --git a/tv/tuner/1.0/default/Android.bp b/tv/tuner/1.0/default/Android.bp index 989e25c6e3..5711889aa4 100644 --- a/tv/tuner/1.0/default/Android.bp +++ b/tv/tuner/1.0/default/Android.bp @@ -24,6 +24,7 @@ cc_defaults { "libfmq", "libhidlbase", "libhidlmemory", + "libion", "liblog", "libstagefright_foundation", "libutils", diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp index 54d09520e0..f610c60743 100644 --- a/tv/tuner/1.0/default/Filter.cpp +++ b/tv/tuner/1.0/default/Filter.cpp @@ -60,6 +60,8 @@ Return Filter::setDataSource(const sp& filter) { Return Filter::getQueueDesc(getQueueDesc_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); + mIsUsingFMQ = true; + _hidl_cb(Result::SUCCESS, *mFilterMQ->getDesc()); return Void(); } @@ -120,9 +122,13 @@ Return Filter::flush() { return Result::SUCCESS; } -Return Filter::releaseAvHandle(const hidl_handle& /*avMemory*/, uint64_t /*avDataId*/) { +Return Filter::releaseAvHandle(const hidl_handle& /*avMemory*/, uint64_t avDataId) { ALOGV("%s", __FUNCTION__); + if (mDataId2Avfd.find(avDataId) == mDataId2Avfd.end()) { + return Result::INVALID_ARGUMENT; + } + ::close(mDataId2Avfd[avDataId]); return Result::SUCCESS; } @@ -174,14 +180,21 @@ void Filter::filterThreadLoop() { // Event Callback without waiting for the DATA_CONSUMED to init the process. while (mFilterThreadRunning) { if (mFilterEvent.events.size() == 0) { - ALOGD("[Filter] wait for filter data output."); + if (DEBUG_FILTER) { + ALOGD("[Filter] wait for filter data output."); + } usleep(1000 * 1000); continue; } // After successfully write, send a callback and wait for the read to be done mCallback->onFilterEvent(mFilterEvent); + freeAvHandle(); mFilterEvent.events.resize(0); mFilterStatus = DemuxFilterStatus::DATA_READY; + if (mCallback == nullptr) { + ALOGD("[Filter] filter %d does not hava callback. Ending thread", mFilterId); + break; + } mCallback->onFilterStatus(mFilterStatus); break; } @@ -191,7 +204,7 @@ void Filter::filterThreadLoop() { // We do not wait for the last round of written data to be read to finish the thread // because the VTS can verify the reading itself. for (int i = 0; i < SECTION_WRITE_COUNT; i++) { - while (mFilterThreadRunning) { + while (mFilterThreadRunning && mIsUsingFMQ) { status_t status = mFilterEventFlag->wait( static_cast(DemuxQueueNotifyBits::DATA_CONSUMED), &efState, WAIT_TIMEOUT, true /* retry on spurious wake */); @@ -202,11 +215,6 @@ void Filter::filterThreadLoop() { break; } - if (mCallback == nullptr) { - ALOGD("[Filter] filter %d does not hava callback. Ending thread", mFilterId); - break; - } - maySendFilterStatusCallback(); while (mFilterThreadRunning) { @@ -232,7 +240,22 @@ void Filter::filterThreadLoop() { ALOGD("[Filter] filter thread ended."); } +void Filter::freeAvHandle() { + if (mType.mainType != DemuxFilterMainType::TS || + (mType.subType.tsFilterType() == DemuxTsFilterType::AUDIO && + mType.subType.tsFilterType() == DemuxTsFilterType::VIDEO)) { + return; + } + for (int i = 0; i < mFilterEvent.events.size(); i++) { + ::close(mFilterEvent.events[i].media().avMemory.getNativeHandle()->data[0]); + native_handle_close(mFilterEvent.events[i].media().avMemory.getNativeHandle()); + } +} + void Filter::maySendFilterStatusCallback() { + if (!mIsUsingFMQ) { + return; + } std::lock_guard lock(mFilterStatusLock); int availableToRead = mFilterMQ->availableToRead(); int availableToWrite = mFilterMQ->availableToWrite(); @@ -409,19 +432,88 @@ Result Filter::startTsFilterHandler() { } Result Filter::startMediaFilterHandler() { - DemuxFilterMediaEvent mediaEvent; - mediaEvent = { - // temp dump meta data - .pts = 0, - .dataLength = 530, - .avMemory = nullptr, - .isSecureMemory = false, - }; - mFilterEvent.events.resize(1); - mFilterEvent.events[0].media(mediaEvent); + std::lock_guard lock(mFilterEventLock); + if (mFilterOutput.empty()) { + return Result::SUCCESS; + } + + for (int i = 0; i < mFilterOutput.size(); i += 188) { + if (mPesSizeLeft == 0) { + uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) | + mFilterOutput[i + 6]; + if (DEBUG_FILTER) { + ALOGD("[Filter] prefix %d", prefix); + } + if (prefix == 0x000001) { + // TODO handle mulptiple Pes filters + mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9]; + mPesSizeLeft += 6; + if (DEBUG_FILTER) { + ALOGD("[Filter] pes data length %d", mPesSizeLeft); + } + } else { + continue; + } + } + + int endPoint = min(184, mPesSizeLeft); + // append data and check size + vector::const_iterator first = mFilterOutput.begin() + i + 4; + vector::const_iterator last = mFilterOutput.begin() + i + 4 + endPoint; + mPesOutput.insert(mPesOutput.end(), first, last); + // size does not match then continue + mPesSizeLeft -= endPoint; + if (DEBUG_FILTER) { + ALOGD("[Filter] pes data left %d", mPesSizeLeft); + } + if (mPesSizeLeft > 0 || mAvBufferCopyCount++ < 10) { + continue; + } + + int av_fd = createAvIonFd(mPesOutput.size()); + if (av_fd == -1) { + return Result::UNKNOWN_ERROR; + } + // copy the filtered data to the buffer + uint8_t* avBuffer = getIonBuffer(av_fd, mPesOutput.size()); + if (avBuffer == NULL) { + return Result::UNKNOWN_ERROR; + } + memcpy(avBuffer, mPesOutput.data(), mPesOutput.size() * sizeof(uint8_t)); + + native_handle_t* nativeHandle = createNativeHandle(av_fd); + if (nativeHandle == NULL) { + return Result::UNKNOWN_ERROR; + } + hidl_handle handle; + handle.setTo(nativeHandle, /*shouldOwn=*/true); + + // Create a dataId and add a pair into the dataId2Avfd map + uint64_t dataId = mLastUsedDataId++ /*createdUID*/; + mDataId2Avfd[dataId] = dup(av_fd); + + // Create mediaEvent and send callback + DemuxFilterMediaEvent mediaEvent; + mediaEvent = { + .avMemory = std::move(handle), + .dataLength = static_cast(mPesOutput.size()), + .avDataId = dataId, + }; + int size = mFilterEvent.events.size(); + mFilterEvent.events.resize(size + 1); + mFilterEvent.events[size].media(mediaEvent); + + // Clear and log + mPesOutput.clear(); + mAvBufferCopyCount = 0; + ::close(av_fd); + if (DEBUG_FILTER) { + ALOGD("[Filter] assembled av data length %d", mediaEvent.dataLength); + } + } mFilterOutput.clear(); - // TODO handle write FQM for media stream + return Result::SUCCESS; } @@ -493,6 +585,42 @@ void Filter::detachFilterFromRecord() { mDvr = nullptr; } +int Filter::createAvIonFd(int size) { + // Create an ion fd and allocate an av fd mapped to a buffer to it. + int ion_fd = ion_open(); + if (ion_fd == -1) { + ALOGE("[Filter] Failed to open ion fd %d", errno); + return -1; + } + int av_fd = -1; + ion_alloc_fd(dup(ion_fd), size, 0 /*align*/, ION_HEAP_SYSTEM_MASK, 0 /*flags*/, &av_fd); + if (av_fd == -1) { + ALOGE("[Filter] Failed to create av fd %d", errno); + return -1; + } + return av_fd; +} + +uint8_t* Filter::getIonBuffer(int fd, int size) { + uint8_t* avBuf = static_cast( + mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 /*offset*/)); + if (avBuf == MAP_FAILED) { + ALOGE("[Filter] fail to allocate buffer %d", errno); + return NULL; + } + return avBuf; +} + +native_handle_t* Filter::createNativeHandle(int fd) { + // Create a native handle to pass the av fd via the callback event. + native_handle_t* nativeHandle = native_handle_create(/*numFd*/ 1, 0); + if (nativeHandle == NULL) { + ALOGE("[Filter] Failed to create native_handle %d", errno); + return NULL; + } + nativeHandle->data[0] = dup(fd); + return nativeHandle; +} } // namespace implementation } // namespace V1_0 } // namespace tuner diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h index 0dc992a2ba..afed98eb0a 100644 --- a/tv/tuner/1.0/default/Filter.h +++ b/tv/tuner/1.0/default/Filter.h @@ -19,6 +19,7 @@ #include #include +#include #include #include #include "Demux.h" @@ -87,6 +88,7 @@ class Filter : public IFilter { Result startRecordFilterHandler(); void attachFilterToRecord(const sp dvr); void detachFilterFromRecord(); + void freeAvHandle(); private: // Tuner service @@ -109,6 +111,7 @@ class Filter : public IFilter { vector mFilterOutput; vector mRecordFilterOutput; unique_ptr mFilterMQ; + bool mIsUsingFMQ = false; EventFlag* mFilterEventFlag; DemuxFilterEvent mFilterEvent; @@ -160,6 +163,10 @@ class Filter : public IFilter { static void* __threadLoopFilter(void* user); void filterThreadLoop(); + int createAvIonFd(int size); + uint8_t* getIonBuffer(int fd, int size); + native_handle_t* createNativeHandle(int fd); + /** * Lock to protect writes to the FMQs */ @@ -181,6 +188,11 @@ class Filter : public IFilter { // TODO handle mulptiple Pes filters int mPesSizeLeft = 0; vector mPesOutput; + + // A map from data id to ion handle + std::map mDataId2Avfd; + uint64_t mLastUsedDataId = 1; + int mAvBufferCopyCount = 0; }; } // namespace implementation diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp index 7e206a76cb..bb0d8dcaf9 100644 --- a/tv/tuner/1.0/default/Frontend.cpp +++ b/tv/tuner/1.0/default/Frontend.cpp @@ -63,9 +63,6 @@ Return Frontend::tune(const FrontendSettings& /* settings */) { return Result::INVALID_STATE; } - // TODO dynamically allocate file to the source file - mSourceStreamFile = FRONTEND_STREAM_FILE; - mCallback->onEvent(FrontendEventType::LOCKED); return Result::SUCCESS; } @@ -180,7 +177,7 @@ FrontendId Frontend::getFrontendId() { } string Frontend::getSourceFile() { - return mSourceStreamFile; + return FRONTEND_STREAM_FILE; } } // namespace implementation diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h index eab43a39fb..b954639956 100644 --- a/tv/tuner/1.0/default/Frontend.h +++ b/tv/tuner/1.0/default/Frontend.h @@ -76,7 +76,6 @@ class Frontend : public IFrontend { FrontendId mId = 0; const string FRONTEND_STREAM_FILE = "/vendor/etc/dumpTs3.ts"; - string mSourceStreamFile; std::ifstream mFrontendData; }; diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp index 4fd33559cc..8fb506132a 100644 --- a/tv/tuner/1.0/default/Tuner.cpp +++ b/tv/tuner/1.0/default/Tuner.cpp @@ -106,7 +106,7 @@ Return Tuner::openDescrambler(openDescrambler_cb _hidl_cb) { return Void(); } -Return Tuner::getFrontendInfo(FrontendId /* frontendId */, getFrontendInfo_cb _hidl_cb) { +Return Tuner::getFrontendInfo(FrontendId /*frontendId*/, getFrontendInfo_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); vector statusCaps = { diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index f693e7cff9..bfc077fa1b 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -57,6 +57,7 @@ using android::Mutex; using android::sp; using android::hardware::EventFlag; using android::hardware::fromHeap; +using android::hardware::hidl_handle; using android::hardware::hidl_string; using android::hardware::hidl_vec; using android::hardware::HidlMemory; @@ -68,6 +69,7 @@ using android::hardware::Void; using android::hardware::tv::tuner::V1_0::DataFormat; using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; using android::hardware::tv::tuner::V1_0::DemuxFilterMainType; +using android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent; using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent; using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings; @@ -313,6 +315,7 @@ class FilterCallback : public IFilterCallback { } void setFilterId(uint32_t filterId) { mFilterId = filterId; } + void setFilterInterface(sp filter) { mFilter = filter; } void setFilterEventType(FilterEventType type) { mFilterEventType = type; } void testFilterDataOutput(); @@ -324,6 +327,7 @@ class FilterCallback : public IFilterCallback { void updateFilterMQ(MQDesc& filterMQDescriptor); void updateGoldenOutputMap(string goldenOutputFile); bool readFilterEventData(); + bool dumpAvData(DemuxFilterMediaEvent event); private: struct FilterThreadArgs { @@ -336,6 +340,7 @@ class FilterCallback : public IFilterCallback { string mFilterIdToGoldenOutput; uint32_t mFilterId; + sp mFilter; FilterEventType mFilterEventType; std::unique_ptr mFilterMQ; EventFlag* mFilterMQEventFlag; @@ -407,7 +412,7 @@ void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) { bool FilterCallback::readFilterEventData() { bool result = false; DemuxFilterEvent filterEvent = mFilterEvent; - ALOGW("[vts] reading from filter FMQ %d", mFilterId); + ALOGW("[vts] reading from filter FMQ or buffer %d", mFilterId); // todo separate filter handlers for (int i = 0; i < filterEvent.events.size(); i++) { switch (mFilterEventType) { @@ -418,8 +423,7 @@ bool FilterCallback::readFilterEventData() { mDataLength = filterEvent.events[i].pes().dataLength; break; case FilterEventType::MEDIA: - mDataLength = filterEvent.events[i].media().dataLength; - break; + return dumpAvData(filterEvent.events[i].media()); case FilterEventType::RECORD: break; case FilterEventType::MMTPRECORD: @@ -443,6 +447,26 @@ bool FilterCallback::readFilterEventData() { mFilterMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); return result; } + +bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) { + uint32_t length = event.dataLength; + uint64_t dataId = event.avDataId; + // read data from buffer pointed by a handle + hidl_handle handle = event.avMemory; + + int av_fd = handle.getNativeHandle()->data[0]; + uint8_t* buffer = static_cast( + mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0 /*offset*/)); + if (buffer == MAP_FAILED) { + ALOGE("[vts] fail to allocate av buffer, errno=%d", errno); + return false; + } + uint8_t output[length + 1]; + memcpy(output, buffer, length); + // print buffer and check with golden output. + EXPECT_TRUE(mFilter->releaseAvHandle(handle, dataId) == Result::SUCCESS); + return true; +} /******************************** End FilterCallback **********************************/ /******************************** Start DvrCallback **********************************/ @@ -731,6 +755,7 @@ class TunerHidlTest : public testing::TestWithParam { sp mFilter; std::map> mFilters; std::map> mFilterCallbacks; + sp mFilterCallback; sp mDvrCallback; MQDesc mFilterMQDescriptor; @@ -926,6 +951,7 @@ AssertionResult TunerHidlTest::getNewlyOpenedFilterId(uint32_t& filterId) { if (status == Result::SUCCESS) { mFilterCallback->setFilterId(mFilterId); + mFilterCallback->setFilterInterface(mFilter); mUsedFilterIds.insert(mUsedFilterIds.end(), mFilterId); mFilters[mFilterId] = mFilter; mFilterCallbacks[mFilterId] = mFilterCallback; @@ -1535,6 +1561,39 @@ TEST_P(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) { ASSERT_TRUE(recordDataFlowTest(filterConf, recordSetting, goldenOutputFiles)); }*/ + +TEST_P(TunerHidlTest, AvBufferTest) { + description("Test the av filter data bufferring."); + + ASSERT_TRUE(getFrontendIds()); + ASSERT_TRUE(mFeIds.size() > 0); + + for (size_t i = 0; i < mFeIds.size(); i++) { + ASSERT_TRUE(getFrontendInfo(mFeIds[i])); + if (mFrontendInfo.type != frontendArray[1].type) { + continue; + } + ASSERT_TRUE(openFrontend(mFeIds[i])); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(openDemux()); + ASSERT_TRUE(openFilterInDemux(filterArray[0].type)); + uint32_t filterId; + ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); + ASSERT_TRUE(configFilter(filterArray[0].setting, filterId)); + ASSERT_TRUE(startFilter(filterId)); + ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i])); + // tune test + ASSERT_TRUE(tuneFrontend(frontendArray[1])); + // broadcast data flow test + ASSERT_TRUE(broadcastDataFlowTest(goldenOutputFiles)); + ASSERT_TRUE(stopTuneFrontend()); + ASSERT_TRUE(stopFilter(filterId)); + ASSERT_TRUE(closeFilter(filterId)); + ASSERT_TRUE(closeDemux()); + ASSERT_TRUE(closeFrontend()); + break; + } +} /*============================== End Data Flow Tests ==============================*/ /******************************** End Test Entry **********************************/ } // namespace diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h index 55ca8579fb..25612d73f8 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h @@ -64,7 +64,7 @@ using android::hardware::tv::tuner::V1_0::FrontendType; namespace { -#define frontend_transponders_count 1 +#define frontend_transponders_count 2 #define channels_count 1 #define frontend_scan_count 1 #define filter_count 2 @@ -108,6 +108,7 @@ inline void initFrontendConfig() { .standard = FrontendDvbtStandard::T, }; frontendArray[0].type = FrontendType::DVBT, frontendArray[0].settings.dvbt(dvbtSettings); + frontendArray[1].type = FrontendType::DVBS; }; /** Configuration array for the frontend scan test */ @@ -122,7 +123,7 @@ inline void initFilterConfig() { // TS Video filter setting filterArray[0].type.mainType = DemuxFilterMainType::TS; filterArray[0].type.subType.tsFilterType(DemuxTsFilterType::VIDEO); - filterArray[0].setting.ts().tpid = 49; + filterArray[0].setting.ts().tpid = 119; filterArray[0].setting.ts().filterSettings.av({.isPassthrough = false}); // TS PES filter setting filterArray[1].type.mainType = DemuxFilterMainType::TS; From e3b052154d34c8dad24fef6220096a63330f78b8 Mon Sep 17 00:00:00 2001 From: Amy Date: Fri, 28 Feb 2020 11:13:06 -0800 Subject: [PATCH 0757/1022] Align Tuner VTS scan tests with the latest scan mechanism Test: atest VtsHalTvTunerV1_0TargetTest Bug: 135708935 Bug: 150953857 Change-Id: Ibb0a70195b1e8f89a45f3ab1a025dfaab4c76859 --- .../VtsHalTvTunerV1_0TargetTest.cpp | 207 +++++++++++++----- .../VtsHalTvTunerV1_0TestConfigurations.h | 18 +- 2 files changed, 168 insertions(+), 57 deletions(-) diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index bfc077fa1b..8b0413cec8 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -47,7 +47,6 @@ #include "VtsHalTvTunerV1_0TestConfigurations.h" #define WAIT_TIMEOUT 3000000000 -#define WAIT_TIMEOUT_data_ready 3000000000 * 4 using android::Condition; using android::IMemory; @@ -158,7 +157,6 @@ const std::vector goldenDataOutputBuffer{ // const uint16_t FMQ_SIZE_4K = 0x1000; const uint32_t FMQ_SIZE_1M = 0x100000; const uint32_t FMQ_SIZE_16M = 0x1000000; -const uint8_t FRONTEND_EVENT_CALLBACK_WAIT_COUNT = 4; enum FilterEventType : uint8_t { UNDEFINED, @@ -181,52 +179,65 @@ class FrontendCallback : public IFrontendCallback { public: virtual Return onEvent(FrontendEventType frontendEventType) override { android::Mutex::Autolock autoLock(mMsgLock); + ALOGD("[vts] frontend event received. Type: %d", frontendEventType); mEventReceived = true; - mEventType = frontendEventType; mMsgCondition.signal(); - return Void(); + switch (frontendEventType) { + case FrontendEventType::LOCKED: + mLockMsgReceived = true; + mLockMsgCondition.signal(); + return Void(); + default: + // do nothing + return Void(); + } } virtual Return onScanMessage(FrontendScanMessageType type, const FrontendScanMessage& message) override { android::Mutex::Autolock autoLock(mMsgLock); - ALOGD("[vts] scan message. Type: %d", mScanMessageType); + while (!mScanMsgProcessed) { + mMsgCondition.wait(mMsgLock); + } + ALOGD("[vts] frontend scan message. Type: %d", type); mScanMessageReceived = true; + mScanMsgProcessed = false; mScanMessageType = type; - mScanLockMessageReceived = - mScanLockMessageReceived | (type == FrontendScanMessageType::LOCKED); mScanMessage = message; mMsgCondition.signal(); return Void(); - }; + } void tuneTestOnEventReceive(sp& frontend, FrontendSettings settings); void tuneTestOnLock(sp& frontend, FrontendSettings settings); - void scanTestOnMessageLock(sp& frontend, FrontendSettings settings, - FrontendScanType type); + void scanTest(sp& frontend, FrontendConfig config, FrontendScanType type); + + // Helper methods + uint32_t getTargetFrequency(FrontendSettings settings, FrontendType type); + void resetBlindScanStartingFrequency(FrontendConfig config, uint32_t resetingFreq); private: bool mEventReceived = false; bool mScanMessageReceived = false; - bool mScanLockMessageReceived = false; - FrontendEventType mEventType; + bool mLockMsgReceived = false; + bool mScanMsgProcessed = true; FrontendScanMessageType mScanMessageType; FrontendScanMessage mScanMessage; hidl_vec mEventMessage; android::Mutex mMsgLock; android::Condition mMsgCondition; - uint8_t mOnEvenRetry = 0; + android::Condition mLockMsgCondition; }; void FrontendCallback::tuneTestOnEventReceive(sp& frontend, FrontendSettings settings) { Result result = frontend->tune(settings); - EXPECT_TRUE(result == Result::SUCCESS); android::Mutex::Autolock autoLock(mMsgLock); while (!mEventReceived) { if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { - EXPECT_TRUE(false) << "event not received within timeout"; + EXPECT_TRUE(false) << "Event not received within timeout"; + mLockMsgReceived = false; return; } } @@ -235,61 +246,134 @@ void FrontendCallback::tuneTestOnEventReceive(sp& frontend, FrontendS void FrontendCallback::tuneTestOnLock(sp& frontend, FrontendSettings settings) { Result result = frontend->tune(settings); - EXPECT_TRUE(result == Result::SUCCESS); android::Mutex::Autolock autoLock(mMsgLock); -wait: - while (!mEventReceived) { - if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { - EXPECT_TRUE(false) << "event not received within timeout"; + while (!mLockMsgReceived) { + if (-ETIMEDOUT == mLockMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "Event LOCKED not received within timeout"; + mLockMsgReceived = false; return; } } - if (mEventType != FrontendEventType::LOCKED) { - ALOGD("[vts] frontend callback event received. Type: %d", mEventType); - mEventReceived = false; - if (mOnEvenRetry++ < FRONTEND_EVENT_CALLBACK_WAIT_COUNT) { - goto wait; - } - } - EXPECT_TRUE(mEventType == FrontendEventType::LOCKED) << "LOCK event not received"; - mEventReceived = false; - mOnEvenRetry = 0; + mLockMsgReceived = false; } -void FrontendCallback::scanTestOnMessageLock(sp& frontend, FrontendSettings settings, - FrontendScanType type) { - Result result = frontend->scan(settings, type); - EXPECT_TRUE(result == Result::SUCCESS); - android::Mutex::Autolock autoLock(mMsgLock); - int messagesCount = 0; +void FrontendCallback::scanTest(sp& frontend, FrontendConfig config, + FrontendScanType type) { + uint32_t targetFrequency = getTargetFrequency(config.settings, config.type); + if (type == FrontendScanType::SCAN_BLIND) { + // reset the frequency in the scan configuration to test blind scan. The settings param of + // passed in means the real input config on the transponder connected to the DUT. + // We want the blind the test to start from lower frequency than this to check the blind + // scan implementation. + resetBlindScanStartingFrequency(config, targetFrequency - 100); + } + Result result = frontend->scan(config.settings, type); + EXPECT_TRUE(result == Result::SUCCESS); + + bool scanMsgLockedReceived = false; + bool targetFrequencyReceived = false; + + android::Mutex::Autolock autoLock(mMsgLock); wait: - int count = 0; while (!mScanMessageReceived) { if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { - ALOGD("[vts] waiting for scan message callback..."); - if (count++ > 10) { - EXPECT_TRUE(false) << "WAITING TOO LONG!!"; - return; - } + EXPECT_TRUE(false) << "Scan message not received within timeout"; + mScanMessageReceived = false; + mScanMsgProcessed = true; + return; } } if (mScanMessageType != FrontendScanMessageType::END) { - ALOGD("[vts] frontend scan message received. Type: %d", mScanMessageType); - mScanMessageReceived = false; - if (messagesCount++ > 3) { - EXPECT_TRUE(false) << "WAITING ON TOO MANY MSGS!!"; - return; + if (mScanMessageType == FrontendScanMessageType::LOCKED) { + scanMsgLockedReceived = true; + Result result = frontend->scan(config.settings, type); + EXPECT_TRUE(result == Result::SUCCESS); } + + if (mScanMessageType == FrontendScanMessageType::FREQUENCY) { + targetFrequencyReceived = mScanMessage.frequencies().size() > 0 && + mScanMessage.frequencies()[0] == targetFrequency; + } + + if (mScanMessageType == FrontendScanMessageType::PROGRESS_PERCENT) { + ALOGD("[vts] Scan in progress...[%d%%]", mScanMessage.progressPercent()); + } + + mScanMessageReceived = false; + mScanMsgProcessed = true; + mMsgCondition.signal(); goto wait; } - EXPECT_TRUE(mScanLockMessageReceived) << "scan lock message not received before scan ended"; + EXPECT_TRUE(scanMsgLockedReceived) << "Scan message LOCKED not received before END"; + EXPECT_TRUE(targetFrequencyReceived) << "frequency not received before LOCKED on blindScan"; mScanMessageReceived = false; - mScanLockMessageReceived = false; + mScanMsgProcessed = true; +} + +uint32_t FrontendCallback::getTargetFrequency(FrontendSettings settings, FrontendType type) { + switch (type) { + case FrontendType::ANALOG: + return settings.analog().frequency; + case FrontendType::ATSC: + return settings.atsc().frequency; + case FrontendType::ATSC3: + return settings.atsc3().frequency; + case FrontendType::DVBC: + return settings.dvbc().frequency; + case FrontendType::DVBS: + return settings.dvbs().frequency; + case FrontendType::DVBT: + return settings.dvbt().frequency; + case FrontendType::ISDBS: + return settings.isdbs().frequency; + case FrontendType::ISDBS3: + return settings.isdbs3().frequency; + case FrontendType::ISDBT: + return settings.isdbt().frequency; + default: + return 0; + } +} + +void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig config, + uint32_t resetingFreq) { + switch (config.type) { + case FrontendType::ANALOG: + config.settings.analog().frequency = resetingFreq; + break; + case FrontendType::ATSC: + config.settings.atsc().frequency = resetingFreq; + break; + case FrontendType::ATSC3: + config.settings.atsc3().frequency = resetingFreq; + break; + case FrontendType::DVBC: + config.settings.dvbc().frequency = resetingFreq; + break; + case FrontendType::DVBS: + config.settings.dvbs().frequency = resetingFreq; + break; + case FrontendType::DVBT: + config.settings.dvbt().frequency = resetingFreq; + break; + case FrontendType::ISDBS: + config.settings.isdbs().frequency = resetingFreq; + break; + case FrontendType::ISDBS3: + config.settings.isdbs3().frequency = resetingFreq; + break; + case FrontendType::ISDBT: + config.settings.isdbt().frequency = resetingFreq; + break; + default: + // do nothing + return; + } } /******************************** End FrontendCallback **********************************/ @@ -851,7 +935,7 @@ AssertionResult TunerHidlTest::scanFrontend(FrontendConfig config, FrontendScanT EXPECT_TRUE(mFrontendInfo.type == config.type) << "FrontendConfig does not match the frontend info of the given id."; - mFrontendCallback->scanTestOnMessageLock(mFrontend, config.settings, type); + mFrontendCallback->scanTest(mFrontend, config, type); return AssertionResult(true); } @@ -958,7 +1042,7 @@ AssertionResult TunerHidlTest::getNewlyOpenedFilterId(uint32_t& filterId) { filterId = mFilterId; } - return AssertionResult(status == Result::SUCCESS || status == Result::UNAVAILABLE); + return AssertionResult(status == Result::SUCCESS); } AssertionResult TunerHidlTest::configFilter(DemuxFilterSettings setting, uint32_t filterId) { @@ -1326,7 +1410,6 @@ TEST_P(TunerHidlTest, TuneFrontend) { } ASSERT_TRUE(openFrontend(mFeIds[i])); ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(stopTuneFrontend()); ASSERT_TRUE(tuneFrontend(frontendArray[0])); ASSERT_TRUE(stopTuneFrontend()); ASSERT_TRUE(closeFrontend()); @@ -1346,13 +1429,31 @@ TEST_P(TunerHidlTest, AutoScanFrontend) { } ASSERT_TRUE(openFrontend(mFeIds[i])); ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(stopScanFrontend()); ASSERT_TRUE(scanFrontend(frontendScanArray[0], FrontendScanType::SCAN_AUTO)); ASSERT_TRUE(stopScanFrontend()); ASSERT_TRUE(closeFrontend()); break; } } + +TEST_P(TunerHidlTest, BlindScanFrontend) { + description("Run an blind frontend scan with specific setting and check lock scanMessage"); + ASSERT_TRUE(getFrontendIds()); + ASSERT_TRUE(mFeIds.size() > 0); + + for (size_t i = 0; i < mFeIds.size(); i++) { + ASSERT_TRUE(getFrontendInfo(mFeIds[i])); + if (mFrontendInfo.type != frontendArray[0].type) { + continue; + } + ASSERT_TRUE(openFrontend(mFeIds[i])); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(scanFrontend(frontendScanArray[0], FrontendScanType::SCAN_BLIND)); + ASSERT_TRUE(stopScanFrontend()); + ASSERT_TRUE(closeFrontend()); + break; + } +} /*=============================== End Frontend Tests ===============================*/ /*============================ Start Demux/Filter Tests ============================*/ diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h index 25612d73f8..31e3b51cd7 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h @@ -113,9 +113,19 @@ inline void initFrontendConfig() { /** Configuration array for the frontend scan test */ inline void initFrontendScanConfig() { - frontendScanArray[0].type = FrontendType::DVBT, frontendScanArray[0].settings.dvbt({ - .frequency = 577000, - }); + frontendScanArray[0].type = FrontendType::DVBT; + frontendScanArray[0].settings.dvbt({ + .frequency = 578000, + .transmissionMode = FrontendDvbtTransmissionMode::MODE_8K, + .bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ, + .constellation = FrontendDvbtConstellation::AUTO, + .hierarchy = FrontendDvbtHierarchy::AUTO, + .hpCoderate = FrontendDvbtCoderate::AUTO, + .lpCoderate = FrontendDvbtCoderate::AUTO, + .guardInterval = FrontendDvbtGuardInterval::AUTO, + .isHighPriority = true, + .standard = FrontendDvbtStandard::T, + }); }; /** Configuration array for the filter test */ @@ -135,4 +145,4 @@ inline void initFilterConfig() { }); }; -} // namespace \ No newline at end of file +} // namespace From 62bbf3dca964bb98b704d65e0a543cff4bbd0cd2 Mon Sep 17 00:00:00 2001 From: chrisweir Date: Tue, 25 Feb 2020 15:15:40 -0800 Subject: [PATCH 0758/1022] DO NOT MERGE Add support for EFF/RTR to canhalsend Adding support for extended format frames and remote transmission request frames to canhalsend. Bug: 149404884 Test: Manual Merged-In: I330b9d24c34918b38612ddc1745f019e11bfd474 Change-Id: I330b9d24c34918b38612ddc1745f019e11bfd474 (cherry picked from commit 30bd3dce06e3f20f2bb20473099b8350f1d4cacc) --- automotive/can/1.0/tools/canhalsend.cpp | 52 ++++++++++++++++++------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/automotive/can/1.0/tools/canhalsend.cpp b/automotive/can/1.0/tools/canhalsend.cpp index 7e6833a8a6..18e815dd6e 100644 --- a/automotive/can/1.0/tools/canhalsend.cpp +++ b/automotive/can/1.0/tools/canhalsend.cpp @@ -15,6 +15,8 @@ */ #include +#include +#include #include #include @@ -27,13 +29,13 @@ using ICanBus = V1_0::ICanBus; using Result = V1_0::Result; static void usage() { - std::cerr << "cansend - simple command line tool to send raw CAN frames" << std::endl; + std::cerr << "canhalsend - simple command line tool to send raw CAN frames" << std::endl; std::cerr << std::endl << "usage:" << std::endl << std::endl; std::cerr << "canhalsend #" << std::endl; std::cerr << "where:" << std::endl; - std::cerr << " bus name - name under which ICanBus is be published" << std::endl; - std::cerr << " can id - such as 1a5" << std::endl; - std::cerr << " data - such as deadbeef or 010203" << std::endl; + std::cerr << " bus name - name under which ICanBus is published" << std::endl; + std::cerr << " can id - such as 1a5 or 1fab5982" << std::endl; + std::cerr << " data - such as deadbeef, 010203, or R for a remote frame" << std::endl; } // TODO(b/135918744): extract to a new library @@ -53,18 +55,13 @@ static sp tryOpen(const std::string& busname) { return ICanBus::castFrom(ret); } -static int cansend(const std::string& busname, V1_0::CanMessageId msgid, - std::vector payload) { +static int cansend(const std::string& busname, const V1_0::CanMessage& msg) { auto bus = tryOpen(busname); if (bus == nullptr) { std::cerr << "Bus " << busname << " is not available" << std::endl; return -1; } - V1_0::CanMessage msg = {}; - msg.id = msgid; - msg.payload = payload; - const auto result = bus->send(msg); if (result != Result::OK) { std::cerr << "Send call failed: " << toString(result) << std::endl; @@ -73,8 +70,7 @@ static int cansend(const std::string& busname, V1_0::CanMessageId msgid, return 0; } -static std::optional>> parseCanMessage( - const std::string& msg) { +static std::optional parseCanMessage(const std::string& msg) { const auto hashpos = msg.find("#"); if (hashpos == std::string::npos) return std::nullopt; @@ -85,6 +81,32 @@ static std::optional>> parse V1_0::CanMessageId msgid = std::stoi(msgidStr, &idx, 16); if (msgidStr[idx] != '\0') return std::nullopt; + V1_0::CanMessage canmsg = {}; + canmsg.id = msgid; + if (msgid > 0x7FF) { + canmsg.isExtendedId = true; + } + + if (android::base::StartsWith(payloadStr, "R")) { + canmsg.remoteTransmissionRequest = true; + + /* The CAN bus HAL doesn't define a data length code (DLC) field, since it is inferrred + * from the payload size. RTR messages indicate to the receiver how many bytes they are + * expecting to receive back via the DLC sent with the RTR frame. */ + if (payloadStr.size() <= 1) return canmsg; + + unsigned int dlc = 0; + + /* The maximum DLC for CAN-FD is 64 bytes and CAN 2.0 is 8 bytes. Limit the size of the DLC + * to something memory safe and let the HAL determine if the DLC is valid. */ + if (!android::base::ParseUint(payloadStr.substr(1), &dlc, 10000u)) { + std::cerr << "Invalid DLC for RTR frame!" << std::endl; + return std::nullopt; + } + canmsg.payload.resize(dlc); + return canmsg; + } + std::vector payload; if (payloadStr.size() % 2 != 0) return std::nullopt; for (size_t i = 0; i < payloadStr.size(); i += 2) { @@ -92,8 +114,9 @@ static std::optional>> parse payload.emplace_back(std::stoi(byteStr, &idx, 16)); if (byteStr[idx] != '\0') return std::nullopt; } + canmsg.payload = payload; - return {{msgid, payload}}; + return canmsg; } static int main(int argc, char* argv[]) { @@ -117,9 +140,8 @@ static int main(int argc, char* argv[]) { std::cerr << "Failed to parse CAN message argument" << std::endl; return -1; } - const auto [msgid, payload] = *canmsg; - return cansend(busname, msgid, payload); + return cansend(busname, *canmsg); } } // namespace android::hardware::automotive::can From e6c11c940761cd1bd8a4af6aea2c6d6545bfa5a8 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 27 Mar 2020 17:08:32 -0700 Subject: [PATCH 0759/1022] Add current.txt HAL sections for S. Adding these now, with a note that AIDL interfaces should be preserved, to avoid some merge conflicts. Bug: 147496715 Test: N/A Change-Id: I67f6c5d583b853516c7203edb77f3c5fa841863b --- current.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/current.txt b/current.txt index 38e1c661e3..0caec179c3 100644 --- a/current.txt +++ b/current.txt @@ -762,3 +762,8 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar 2ce1f7fb52e49f80b13a9b153d491bce530552f02357ea729acae922a8659f93 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback 77531c8d048f8f8ae532babd0ca86332a865ec9aace1b051226ef2b21123e645 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork 98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types + +# ABI preserving changes to HALs during Android S + +# HALs released in Android S +# NOTE: new HALs are recommended to be in AIDL From e6372d5cdda60eff156319ad85799db7cdca47c0 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 27 Mar 2020 17:55:29 -0700 Subject: [PATCH 0760/1022] remove face@1.1 HAL from current.txt It no longer exists. Accidentally added. Bug: 147496715 Test: n/a Change-Id: Id6f062618413d76d201aa46eb3a591adc1940cb6 --- current.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/current.txt b/current.txt index 2e3f198aa9..8d32816b43 100644 --- a/current.txt +++ b/current.txt @@ -658,7 +658,6 @@ affd9c591f48a69773fcf43dc4a716d292cd4bc5ba2be8649276af0aedea435d android.hardwar b3caf524c46a47d67e6453a34419e1881942d059e146cda740502670e9a752c3 android.hardware.automotive.vehicle@2.0::IVehicle 7ce8728b27600e840cacf0a832f6942819fe535f9d3797ae052d5eef5065921c android.hardware.automotive.vehicle@2.0::IVehicleCallback 6b2564fce1d364baf9ba15a5cb00a8f08f86a5be5387c0ede795328ca536a2c7 android.hardware.automotive.vehicle@2.0::types -7e8e1c3d0173c5d503dd01cecff8e3864478557ca6b9e8cc2291598b1a4aea62 android.hardware.biometrics.face@1.1::IBiometricsFace 140f8f62100ccf9cd282ae3685a0f4ef0a9f971d77dfbc7350ccb4e04cf295ec android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprint 82cad99f5feb2ea9bcd4579055edf4af8feb9fc602a6e4827ddd727d254d4991 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprintClientCallback ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types From 5f0bbe9324ce77da80e5952daace59451b379333 Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Wed, 26 Feb 2020 15:55:03 -0800 Subject: [PATCH 0761/1022] Make GetLocationLowPower test warning instead of failing Bug: 150222509 Bug: 152434001 Test: passing on device with GSI build Change-Id: I8af0a992d1cf4af9ef1e78095f7352534c711549 --- gnss/1.1/vts/functional/gnss_hal_test.cpp | 15 +++++++++------ gnss/1.1/vts/functional/gnss_hal_test.h | 4 +++- gnss/1.1/vts/functional/gnss_hal_test_cases.cpp | 2 +- gnss/2.0/vts/functional/gnss_hal_test.cpp | 16 +++++++++------- gnss/2.0/vts/functional/gnss_hal_test.h | 4 +++- gnss/2.0/vts/functional/gnss_hal_test_cases.cpp | 8 ++++---- 6 files changed, 29 insertions(+), 20 deletions(-) diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp index 88fbff8164..52aaa69753 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test.cpp +++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp @@ -99,7 +99,7 @@ void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_po EXPECT_TRUE(result); } -bool GnssHalTest::StartAndCheckFirstLocation() { +bool GnssHalTest::StartAndCheckFirstLocation(bool strict) { auto result = gnss_hal_->start(); EXPECT_TRUE(result.isOk()); @@ -110,11 +110,14 @@ bool GnssHalTest::StartAndCheckFirstLocation() { * so allow time to demodulate ephemeris over the air. */ const int kFirstGnssLocationTimeoutSeconds = 75; + int locationCalledCount = 0; - EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, - kFirstGnssLocationTimeoutSeconds)); - int locationCalledCount = gnss_cb_->location_cbq_.calledCount(); - EXPECT_EQ(locationCalledCount, 1); + if (strict) { + EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, + kFirstGnssLocationTimeoutSeconds)); + locationCalledCount = gnss_cb_->location_cbq_.calledCount(); + EXPECT_EQ(locationCalledCount, 1); + } if (locationCalledCount > 0) { // don't require speed on first fix @@ -138,7 +141,7 @@ void GnssHalTest::StartAndCheckLocations(int count) { SetPositionMode(kMinIntervalMsec, kLowPowerMode); - EXPECT_TRUE(StartAndCheckFirstLocation()); + EXPECT_TRUE(StartAndCheckFirstLocation(/* strict= */ true)); for (int i = 1; i < count; i++) { EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h index 88b77236ae..75c4216e4a 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test.h +++ b/gnss/1.1/vts/functional/gnss_hal_test.h @@ -102,9 +102,11 @@ class GnssHalTest : public testing::TestWithParam { *

      Note this leaves the Location request active, to enable Stop call vs. other call * reordering tests. * + *

      if 'strict' is true, the test will fail if no location is generated. + * * returns true if a location was successfully generated */ - bool StartAndCheckFirstLocation(); + bool StartAndCheckFirstLocation(bool strict); /* * CheckLocation: diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp index 8530ffb08e..e6a51eb731 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp @@ -93,7 +93,7 @@ TEST_P(GnssHalTest, GetLocationLowPower) { SetPositionMode(kMinIntervalMsec, kLowPowerMode); // Don't expect true - as without AGPS access - if (!StartAndCheckFirstLocation()) { + if (!StartAndCheckFirstLocation(/* strict= */ false)) { ALOGW("GetLocationLowPower test - no first low power location received."); } diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp index b3a3203214..59e18f3642 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test.cpp +++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp @@ -97,7 +97,7 @@ void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_po EXPECT_TRUE(result); } -bool GnssHalTest::StartAndCheckFirstLocation() { +bool GnssHalTest::StartAndCheckFirstLocation(bool strict) { const auto result = gnss_hal_->start(); EXPECT_TRUE(result.isOk()); @@ -107,12 +107,14 @@ bool GnssHalTest::StartAndCheckFirstLocation() { * so allow time to demodulate ephemeris over the air. */ const int kFirstGnssLocationTimeoutSeconds = 75; + int locationCalledCount = 0; - EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, - kFirstGnssLocationTimeoutSeconds)); - int locationCalledCount = gnss_cb_->location_cbq_.calledCount(); - EXPECT_EQ(locationCalledCount, 1); - + if (strict) { + EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, + kFirstGnssLocationTimeoutSeconds)); + locationCalledCount = gnss_cb_->location_cbq_.calledCount(); + EXPECT_EQ(locationCalledCount, 1); + } if (locationCalledCount > 0) { // don't require speed on first fix CheckLocation(gnss_cb_->last_location_, false); @@ -135,7 +137,7 @@ void GnssHalTest::StartAndCheckLocations(int count) { SetPositionMode(kMinIntervalMsec, kLowPowerMode); - EXPECT_TRUE(StartAndCheckFirstLocation()); + EXPECT_TRUE(StartAndCheckFirstLocation(/* strict= */ true)); for (int i = 1; i < count; i++) { EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h index 55dc1bc4f6..a02a9ff4a7 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test.h +++ b/gnss/2.0/vts/functional/gnss_hal_test.h @@ -152,9 +152,11 @@ class GnssHalTest : public testing::TestWithParam { *

      Note this leaves the Location request active, to enable Stop call vs. other call * reordering tests. * + *

      if 'strict' is true, the test will fail if no location is generated. + * * returns true if a location was successfully generated */ - bool StartAndCheckFirstLocation(); + bool StartAndCheckFirstLocation(bool strict); /* * CheckLocation: 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 53f5b9e283..c93e89b843 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp @@ -395,7 +395,7 @@ TEST_P(GnssHalTest, TestGnssDataElapsedRealtimeFlags) { } TEST_P(GnssHalTest, TestGnssLocationElapsedRealtime) { - StartAndCheckFirstLocation(); + StartAndCheckFirstLocation(/* strict= */ true); ASSERT_TRUE((int)gnss_cb_->last_location_.elapsedRealtime.flags <= (int)(ElapsedRealtimeFlags::HAS_TIMESTAMP_NS | @@ -411,7 +411,7 @@ TEST_P(GnssHalTest, TestGnssLocationElapsedRealtime) { // This test only verify that injectBestLocation_2_0 does not crash. TEST_P(GnssHalTest, TestInjectBestLocation_2_0) { - StartAndCheckFirstLocation(); + StartAndCheckFirstLocation(/* strict= */ true); gnss_hal_->injectBestLocation_2_0(gnss_cb_->last_location_); StopAndClearLocations(); } @@ -455,7 +455,7 @@ TEST_P(GnssHalTest, GetLocationLowPower) { SetPositionMode(kMinIntervalMsec, kLowPowerMode); // Don't expect true - as without AGPS access - if (!StartAndCheckFirstLocation()) { + if (!StartAndCheckFirstLocation(/* strict= */ false)) { ALOGW("GetLocationLowPower test - no first low power location received."); } @@ -854,4 +854,4 @@ TEST_P(GnssHalTest, BlacklistConstellation) { result = gnss_configuration_hal->setBlacklist(sources); ASSERT_TRUE(result.isOk()); EXPECT_TRUE(result); -} \ No newline at end of file +} From bafc0c0c5c0c7b32f6b3ca7a63ec660d4f187da6 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 30 Mar 2020 14:57:53 +0900 Subject: [PATCH 0762/1022] Update the current API dump All aidl_interface modules should by default considered as stable, in case it is used across system and vendor partitions, or across modules. Like other API surfaces, we need to have a dump for the current (yet-to-be-released) version and update it when there is an API change. This is done via . Then the owner of the interface can freeze the current version as a numbered version via . This change shal be rejected only when the owner is certain that the interface is not used across the updatable boundaries. Bug: 152655547 Test: m Change-Id: I6fe1185e82d248deb021d8c75b4af7d9ca330db2 --- .../occupant_awareness/ConfidenceLevel.aidl | 25 +++++++++++++ .../DriverMonitoringDetection.aidl | 24 +++++++++++++ .../occupant_awareness/GazeDetection.aidl | 28 +++++++++++++++ .../IOccupantAwareness.aidl | 31 ++++++++++++++++ .../IOccupantAwarenessClientCallback.aidl | 23 ++++++++++++ .../OccupantAwarenessStatus.aidl | 25 +++++++++++++ .../occupant_awareness/OccupantDetection.aidl | 25 +++++++++++++ .../OccupantDetections.aidl | 23 ++++++++++++ .../occupant_awareness/PresenceDetection.aidl | 23 ++++++++++++ .../automotive/occupant_awareness/Role.aidl | 35 +++++++++++++++++++ .../occupant_awareness/VehicleRegion.aidl | 31 ++++++++++++++++ 11 files changed, 293 insertions(+) create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/GazeDetection.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/Role.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl new file mode 100644 index 0000000000..6e40d79cab --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@Backing(type="byte") @VintfStability +enum ConfidenceLevel { + NONE = 0, + LOW = 1, + HIGH = 2, + MAX = 3, +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl new file mode 100644 index 0000000000..51d2149aa3 --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@VintfStability +parcelable DriverMonitoringDetection { + android.hardware.automotive.occupant_awareness.ConfidenceLevel confidenceScore; + boolean isLookingOnRoad; + long gazeDurationMillis; +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/GazeDetection.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/GazeDetection.aidl new file mode 100644 index 0000000000..5ce14df9b8 --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/GazeDetection.aidl @@ -0,0 +1,28 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@VintfStability +parcelable GazeDetection { + android.hardware.automotive.occupant_awareness.ConfidenceLevel gazeConfidence; + double[] headPosition; + double[] headAngleUnitVector; + double[] gazeAngleUnitVector; + android.hardware.automotive.occupant_awareness.VehicleRegion gazeTarget; + String customGazeTarget; + long timeOnTargetMillis; +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl new file mode 100644 index 0000000000..7faff00841 --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl @@ -0,0 +1,31 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@VintfStability +interface IOccupantAwareness { + android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus startDetection(); + android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus stopDetection(); + int getCapabilityForRole(in android.hardware.automotive.occupant_awareness.Role occupantRole); + android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus getState(in android.hardware.automotive.occupant_awareness.Role occupantRole, in int detectionCapability); + void setCallback(in android.hardware.automotive.occupant_awareness.IOccupantAwarenessClientCallback callback); + void getLatestDetection(out android.hardware.automotive.occupant_awareness.OccupantDetections detections); + const int CAP_NONE = 0; + const int CAP_PRESENCE_DETECTION = 1; + const int CAP_GAZE_DETECTION = 2; + const int CAP_DRIVER_MONITORING_DETECTION = 4; +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl new file mode 100644 index 0000000000..31b8220d5f --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@VintfStability +interface IOccupantAwarenessClientCallback { + oneway void onSystemStatusChanged(in int detectionFlags, in android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus status); + oneway void onDetectionEvent(in android.hardware.automotive.occupant_awareness.OccupantDetections detections); +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl new file mode 100644 index 0000000000..26371c9573 --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@Backing(type="byte") @VintfStability +enum OccupantAwarenessStatus { + READY = 0, + NOT_SUPPORTED = 1, + NOT_INITIALIZED = 2, + FAILURE = 3, +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl new file mode 100644 index 0000000000..42b109550e --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@VintfStability +parcelable OccupantDetection { + android.hardware.automotive.occupant_awareness.Role role; + android.hardware.automotive.occupant_awareness.PresenceDetection[] presenceData; + android.hardware.automotive.occupant_awareness.GazeDetection[] gazeData; + android.hardware.automotive.occupant_awareness.DriverMonitoringDetection[] attentionData; +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl new file mode 100644 index 0000000000..9bcad6b4fc --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@VintfStability +parcelable OccupantDetections { + long timeStampMillis; + android.hardware.automotive.occupant_awareness.OccupantDetection[] detections; +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl new file mode 100644 index 0000000000..dd6c5c8950 --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@VintfStability +parcelable PresenceDetection { + boolean isOccupantDetected; + long detectionDurationMillis; +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/Role.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/Role.aidl new file mode 100644 index 0000000000..7b2b9077e0 --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/Role.aidl @@ -0,0 +1,35 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@Backing(type="int") @VintfStability +enum Role { + INVALID = 0, + UNKNOWN = 1, + FRONT_PASSENGER = 2, + DRIVER = 4, + ROW_2_PASSENGER_LEFT = 8, + ROW_2_PASSENGER_CENTER = 16, + ROW_2_PASSENGER_RIGHT = 32, + ROW_3_PASSENGER_LEFT = 64, + ROW_3_PASSENGER_CENTER = 128, + ROW_3_PASSENGER_RIGHT = 256, + FRONT_OCCUPANTS = 6, + ROW_2_OCCUPANTS = 56, + ROW_3_OCCUPANTS = 448, + ALL_OCCUPANTS = 511, +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl new file mode 100644 index 0000000000..f96d950bf1 --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl @@ -0,0 +1,31 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@Backing(type="int") @VintfStability +enum VehicleRegion { + UNKNOWN = 0, + INSTRUMENT_CLUSTER = 1, + REAR_VIEW_MIRROR = 2, + LEFT_SIDE_MIRROR = 3, + RIGHT_SIDE_MIRROR = 4, + FORWARD_ROADWAY = 5, + LEFT_ROADWAY = 6, + RIGHT_ROADWAY = 7, + HEAD_UNIT_DISPLAY = 8, + CUSTOM_TARGET = 200, +} From aa13c7e985ea1600c7571542c0fe05cf312c2ab2 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 30 Mar 2020 14:58:16 +0900 Subject: [PATCH 0763/1022] Update the current API dump All aidl_interface modules should by default considered as stable, in case it is used across system and vendor partitions, or across modules. Like other API surfaces, we need to have a dump for the current (yet-to-be-released) version and update it when there is an API change. This is done via . Then the owner of the interface can freeze the current version as a numbered version via . This change shal be rejected only when the owner is certain that the interface is not used across the updatable boundaries. Bug: 152655547 Test: m Change-Id: If547945d3bc8c8a73e2341ff9e90025ac10ce662 --- .../hardware/graphics/common/BlendMode.aidl | 25 ++++++ .../hardware/graphics/common/BufferUsage.aidl | 47 +++++++++++ .../graphics/common/ChromaSiting.aidl | 25 ++++++ .../hardware/graphics/common/Compression.aidl | 23 ++++++ .../hardware/graphics/common/Cta861_3.aidl | 23 ++++++ .../hardware/graphics/common/Dataspace.aidl | 81 +++++++++++++++++++ .../graphics/common/ExtendableType.aidl | 23 ++++++ .../graphics/common/HardwareBuffer.aidl | 23 ++++++ .../common/HardwareBufferDescription.aidl | 27 +++++++ .../hardware/graphics/common/Interlaced.aidl | 24 ++++++ .../hardware/graphics/common/PixelFormat.aidl | 50 ++++++++++++ .../hardware/graphics/common/PlaneLayout.aidl | 30 +++++++ .../graphics/common/PlaneLayoutComponent.aidl | 24 ++++++ .../common/PlaneLayoutComponentType.aidl | 29 +++++++ .../hardware/graphics/common/Rect.aidl | 25 ++++++ .../hardware/graphics/common/Smpte2086.aidl | 27 +++++++ .../graphics/common/StandardMetadataType.aidl | 43 ++++++++++ .../hardware/graphics/common/XyColor.aidl | 23 ++++++ 18 files changed, 572 insertions(+) create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BlendMode.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BufferUsage.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ChromaSiting.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Compression.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Cta861_3.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ExtendableType.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/HardwareBuffer.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/HardwareBufferDescription.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Interlaced.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayout.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponent.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponentType.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Rect.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Smpte2086.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/XyColor.aidl diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BlendMode.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BlendMode.aidl new file mode 100644 index 0000000000..deafdfad90 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BlendMode.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="int") @VintfStability +enum BlendMode { + INVALID = 0, + NONE = 1, + PREMULTIPLIED = 2, + COVERAGE = 3, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BufferUsage.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BufferUsage.aidl new file mode 100644 index 0000000000..58eefc4e2c --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BufferUsage.aidl @@ -0,0 +1,47 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="long") @VintfStability +enum BufferUsage { + CPU_READ_MASK = 15, + CPU_READ_NEVER = 0, + CPU_READ_RARELY = 2, + CPU_READ_OFTEN = 3, + CPU_WRITE_MASK = 240, + CPU_WRITE_NEVER = 0, + CPU_WRITE_RARELY = 32, + CPU_WRITE_OFTEN = 48, + GPU_TEXTURE = 256, + GPU_RENDER_TARGET = 512, + COMPOSER_OVERLAY = 2048, + COMPOSER_CLIENT_TARGET = 4096, + PROTECTED = 16384, + COMPOSER_CURSOR = 32768, + VIDEO_ENCODER = 65536, + CAMERA_OUTPUT = 131072, + CAMERA_INPUT = 262144, + RENDERSCRIPT = 1048576, + VIDEO_DECODER = 4194304, + SENSOR_DIRECT_DATA = 8388608, + GPU_CUBE_MAP = 33554432, + GPU_MIPMAP_COMPLETE = 67108864, + HW_IMAGE_ENCODER = 134217728, + GPU_DATA_BUFFER = 16777216, + VENDOR_MASK = -268435456, + VENDOR_MASK_HI = -281474976710656, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ChromaSiting.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ChromaSiting.aidl new file mode 100644 index 0000000000..7ca4dfa531 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ChromaSiting.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="long") @VintfStability +enum ChromaSiting { + NONE = 0, + UNKNOWN = 1, + SITED_INTERSTITIAL = 2, + COSITED_HORIZONTAL = 3, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Compression.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Compression.aidl new file mode 100644 index 0000000000..06e40a0852 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Compression.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="long") @VintfStability +enum Compression { + NONE = 0, + DISPLAY_STREAM_COMPRESSION = 1, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Cta861_3.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Cta861_3.aidl new file mode 100644 index 0000000000..d4af501904 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Cta861_3.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable Cta861_3 { + float maxContentLightLevel; + float maxFrameAverageLightLevel; +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl new file mode 100644 index 0000000000..43d7f84d2d --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl @@ -0,0 +1,81 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="int") @VintfStability +enum Dataspace { + UNKNOWN = 0, + ARBITRARY = 1, + STANDARD_SHIFT = 16, + STANDARD_MASK = 4128768, + STANDARD_UNSPECIFIED = 0, + STANDARD_BT709 = 65536, + STANDARD_BT601_625 = 131072, + STANDARD_BT601_625_UNADJUSTED = 196608, + STANDARD_BT601_525 = 262144, + STANDARD_BT601_525_UNADJUSTED = 327680, + STANDARD_BT2020 = 393216, + STANDARD_BT2020_CONSTANT_LUMINANCE = 458752, + STANDARD_BT470M = 524288, + STANDARD_FILM = 589824, + STANDARD_DCI_P3 = 655360, + STANDARD_ADOBE_RGB = 720896, + TRANSFER_SHIFT = 22, + TRANSFER_MASK = 130023424, + TRANSFER_UNSPECIFIED = 0, + TRANSFER_LINEAR = 4194304, + TRANSFER_SRGB = 8388608, + TRANSFER_SMPTE_170M = 12582912, + TRANSFER_GAMMA2_2 = 16777216, + TRANSFER_GAMMA2_6 = 20971520, + TRANSFER_GAMMA2_8 = 25165824, + TRANSFER_ST2084 = 29360128, + TRANSFER_HLG = 33554432, + RANGE_SHIFT = 27, + RANGE_MASK = 939524096, + RANGE_UNSPECIFIED = 0, + RANGE_FULL = 134217728, + RANGE_LIMITED = 268435456, + RANGE_EXTENDED = 402653184, + SRGB_LINEAR = 138477568, + SCRGB_LINEAR = 406913024, + SRGB = 142671872, + SCRGB = 411107328, + JFIF = 146931712, + BT601_625 = 281149440, + BT601_525 = 281280512, + BT709 = 281083904, + DCI_P3_LINEAR = 139067392, + DCI_P3 = 155844608, + DISPLAY_P3_LINEAR = 139067392, + DISPLAY_P3 = 143261696, + ADOBE_RGB = 151715840, + BT2020_LINEAR = 138805248, + BT2020 = 147193856, + BT2020_PQ = 163971072, + DEPTH = 4096, + SENSOR = 4097, + BT2020_ITU = 281411584, + BT2020_ITU_PQ = 298188800, + BT2020_ITU_HLG = 302383104, + BT2020_HLG = 168165376, + DISPLAY_BT2020 = 142999552, + DYNAMIC_DEPTH = 4098, + JPEG_APP_SEGMENTS = 4099, + HEIF = 4100, + BT709_FULL_RANGE = 146866176, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ExtendableType.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ExtendableType.aidl new file mode 100644 index 0000000000..6fcb794efd --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ExtendableType.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable ExtendableType { + @utf8InCpp String name; + long value = 0; +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/HardwareBuffer.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/HardwareBuffer.aidl new file mode 100644 index 0000000000..72222e118d --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/HardwareBuffer.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable HardwareBuffer { + android.hardware.graphics.common.HardwareBufferDescription description; + android.hardware.common.NativeHandle handle; +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/HardwareBufferDescription.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/HardwareBufferDescription.aidl new file mode 100644 index 0000000000..8b1216948b --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/HardwareBufferDescription.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable HardwareBufferDescription { + int width; + int height; + int layers; + android.hardware.graphics.common.PixelFormat format; + android.hardware.graphics.common.BufferUsage usage; + int stride; +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Interlaced.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Interlaced.aidl new file mode 100644 index 0000000000..26674c9b1d --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Interlaced.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="long") @VintfStability +enum Interlaced { + NONE = 0, + TOP_BOTTOM = 1, + RIGHT_LEFT = 2, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl new file mode 100644 index 0000000000..e5f04700ed --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl @@ -0,0 +1,50 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="int") @VintfStability +enum PixelFormat { + UNSPECIFIED = 0, + RGBA_8888 = 1, + RGBX_8888 = 2, + RGB_888 = 3, + RGB_565 = 4, + BGRA_8888 = 5, + YCBCR_422_SP = 16, + YCRCB_420_SP = 17, + YCBCR_422_I = 20, + RGBA_FP16 = 22, + RAW16 = 32, + BLOB = 33, + IMPLEMENTATION_DEFINED = 34, + YCBCR_420_888 = 35, + RAW_OPAQUE = 36, + RAW10 = 37, + RAW12 = 38, + RGBA_1010102 = 43, + Y8 = 538982489, + Y16 = 540422489, + YV12 = 842094169, + DEPTH_16 = 48, + DEPTH_24 = 49, + DEPTH_24_STENCIL_8 = 50, + DEPTH_32F = 51, + DEPTH_32F_STENCIL_8 = 52, + STENCIL_8 = 53, + YCBCR_P010 = 54, + HSV_888 = 55, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayout.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayout.aidl new file mode 100644 index 0000000000..8bca42feb1 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayout.aidl @@ -0,0 +1,30 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable PlaneLayout { + android.hardware.graphics.common.PlaneLayoutComponent[] components; + long offsetInBytes; + long sampleIncrementInBits; + long strideInBytes; + long widthInSamples; + long heightInSamples; + long totalSizeInBytes; + long horizontalSubsampling; + long verticalSubsampling; +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponent.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponent.aidl new file mode 100644 index 0000000000..f5a649cac9 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponent.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable PlaneLayoutComponent { + android.hardware.graphics.common.ExtendableType type; + long offsetInBits; + long sizeInBits; +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponentType.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponentType.aidl new file mode 100644 index 0000000000..7ff8d76520 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponentType.aidl @@ -0,0 +1,29 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="long") @VintfStability +enum PlaneLayoutComponentType { + Y = 1, + CB = 2, + CR = 4, + R = 1024, + G = 2048, + B = 4096, + RAW = 1048576, + A = 1073741824, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Rect.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Rect.aidl new file mode 100644 index 0000000000..e0ba69bcd0 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Rect.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable Rect { + int left; + int top; + int right; + int bottom; +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Smpte2086.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Smpte2086.aidl new file mode 100644 index 0000000000..5da36f68c0 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Smpte2086.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable Smpte2086 { + android.hardware.graphics.common.XyColor primaryRed; + android.hardware.graphics.common.XyColor primaryGreen; + android.hardware.graphics.common.XyColor primaryBlue; + android.hardware.graphics.common.XyColor whitePoint; + float maxLuminance; + float minLuminance; +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl new file mode 100644 index 0000000000..34b53a2bba --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="long") @VintfStability +enum StandardMetadataType { + INVALID = 0, + BUFFER_ID = 1, + NAME = 2, + WIDTH = 3, + HEIGHT = 4, + LAYER_COUNT = 5, + PIXEL_FORMAT_REQUESTED = 6, + PIXEL_FORMAT_FOURCC = 7, + PIXEL_FORMAT_MODIFIER = 8, + USAGE = 9, + ALLOCATION_SIZE = 10, + PROTECTED_CONTENT = 11, + COMPRESSION = 12, + INTERLACED = 13, + CHROMA_SITING = 14, + PLANE_LAYOUTS = 15, + CROP = 16, + DATASPACE = 17, + BLEND_MODE = 18, + SMPTE2086 = 19, + CTA861_3 = 20, + SMPTE2094_40 = 21, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/XyColor.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/XyColor.aidl new file mode 100644 index 0000000000..d96d0ac130 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/XyColor.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable XyColor { + float x; + float y; +} From cde2dfddc2932da300e550434df569bb57489c1a Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 30 Mar 2020 14:58:46 +0900 Subject: [PATCH 0764/1022] Update the current API dump All aidl_interface modules should by default considered as stable, in case it is used across system and vendor partitions, or across modules. Like other API surfaces, we need to have a dump for the current (yet-to-be-released) version and update it when there is an API change. This is done via . Then the owner of the interface can freeze the current version as a numbered version via . This change shal be rejected only when the owner is certain that the interface is not used across the updatable boundaries. Bug: 152655547 Test: m Change-Id: Ia633e3a143b35626c59b2447c38c1710ee270f0c --- .../hardware/identity/Certificate.aidl | 22 +++++++++++ .../hardware/identity/CipherSuite.aidl | 22 +++++++++++ .../identity/HardwareInformation.aidl | 26 +++++++++++++ .../identity/IIdentityCredential.aidl | 30 +++++++++++++++ .../identity/IIdentityCredentialStore.aidl | 37 +++++++++++++++++++ .../identity/IWritableIdentityCredential.aidl | 27 ++++++++++++++ .../identity/SecureAccessControlProfile.aidl | 27 ++++++++++++++ 7 files changed, 191 insertions(+) create mode 100644 identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/Certificate.aidl create mode 100644 identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/CipherSuite.aidl create mode 100644 identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/HardwareInformation.aidl create mode 100644 identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl create mode 100644 identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredentialStore.aidl create mode 100644 identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl create mode 100644 identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/SecureAccessControlProfile.aidl diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/Certificate.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/Certificate.aidl new file mode 100644 index 0000000000..7e3002d70a --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/Certificate.aidl @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +parcelable Certificate { + byte[] encodedCertificate; +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/CipherSuite.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/CipherSuite.aidl new file mode 100644 index 0000000000..447203faa6 --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/CipherSuite.aidl @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@Backing(type="int") @VintfStability +enum CipherSuite { + CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 = 1, +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/HardwareInformation.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/HardwareInformation.aidl new file mode 100644 index 0000000000..e1296e05e8 --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/HardwareInformation.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +parcelable HardwareInformation { + @utf8InCpp String credentialStoreName; + @utf8InCpp String credentialStoreAuthorName; + int dataChunkSize; + boolean isDirectAccess; + @utf8InCpp String[] supportedDocTypes; +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl new file mode 100644 index 0000000000..58b90b54be --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl @@ -0,0 +1,30 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +interface IIdentityCredential { + byte[] deleteCredential(); + byte[] createEphemeralKeyPair(); + void setReaderEphemeralPublicKey(in byte[] publicKey); + long createAuthChallenge(); + void startRetrieval(in android.hardware.identity.SecureAccessControlProfile[] accessControlProfiles, in android.hardware.keymaster.HardwareAuthToken authToken, in byte[] itemsRequest, in byte[] signingKeyBlob, in byte[] sessionTranscript, in byte[] readerSignature, in int[] requestCounts); + void startRetrieveEntryValue(in @utf8InCpp String nameSpace, in @utf8InCpp String name, in int entrySize, in int[] accessControlProfileIds); + byte[] retrieveEntryValue(in byte[] encryptedContent); + void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces); + android.hardware.identity.Certificate generateSigningKeyPair(out byte[] signingKeyBlob); +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredentialStore.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredentialStore.aidl new file mode 100644 index 0000000000..5dafb76d1c --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredentialStore.aidl @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +interface IIdentityCredentialStore { + android.hardware.identity.HardwareInformation getHardwareInformation(); + android.hardware.identity.IWritableIdentityCredential createCredential(in @utf8InCpp String docType, in boolean testCredential); + android.hardware.identity.IIdentityCredential getCredential(in android.hardware.identity.CipherSuite cipherSuite, in byte[] credentialData); + const int STATUS_OK = 0; + const int STATUS_FAILED = 1; + const int STATUS_CIPHER_SUITE_NOT_SUPPORTED = 2; + const int STATUS_INVALID_DATA = 3; + const int STATUS_INVALID_AUTH_TOKEN = 4; + const int STATUS_INVALID_ITEMS_REQUEST_MESSAGE = 5; + const int STATUS_READER_SIGNATURE_CHECK_FAILED = 6; + const int STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND = 7; + const int STATUS_USER_AUTHENTICATION_FAILED = 8; + const int STATUS_READER_AUTHENTICATION_FAILED = 9; + const int STATUS_NO_ACCESS_CONTROL_PROFILES = 10; + const int STATUS_NOT_IN_REQUEST_MESSAGE = 11; + const int STATUS_SESSION_TRANSCRIPT_MISMATCH = 12; +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl new file mode 100644 index 0000000000..32f283cc18 --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +interface IWritableIdentityCredential { + android.hardware.identity.Certificate[] getAttestationCertificate(in byte[] attestationApplicationId, in byte[] attestationChallenge); + void startPersonalization(in int accessControlProfileCount, in int[] entryCounts); + android.hardware.identity.SecureAccessControlProfile addAccessControlProfile(in int id, in android.hardware.identity.Certificate readerCertificate, in boolean userAuthenticationRequired, in long timeoutMillis, in long secureUserId); + void beginAddEntry(in int[] accessControlProfileIds, in @utf8InCpp String nameSpace, in @utf8InCpp String name, in int entrySize); + byte[] addEntryValue(in byte[] content); + void finishAddingEntries(out byte[] credentialData, out byte[] proofOfProvisioningSignature); +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/SecureAccessControlProfile.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/SecureAccessControlProfile.aidl new file mode 100644 index 0000000000..dfc1ad0681 --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/SecureAccessControlProfile.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +parcelable SecureAccessControlProfile { + int id; + android.hardware.identity.Certificate readerCertificate; + boolean userAuthenticationRequired; + long timeoutMillis; + long secureUserId; + byte[] mac; +} From 905ebbed438d38c35211cf5eba045fe6ddb61bef Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 30 Mar 2020 14:59:06 +0900 Subject: [PATCH 0765/1022] Update the current API dump All aidl_interface modules should by default considered as stable, in case it is used across system and vendor partitions, or across modules. Like other API surfaces, we need to have a dump for the current (yet-to-be-released) version and update it when there is an API change. This is done via . Then the owner of the interface can freeze the current version as a numbered version via . This change shal be rejected only when the owner is certain that the interface is not used across the updatable boundaries. Bug: 152655547 Test: m Change-Id: Id167905590c0a596b0ed470ef668c47810966836 --- .../hardware/keymaster/HardwareAuthToken.aidl | 27 +++++++++++++++++++ .../keymaster/HardwareAuthenticatorType.aidl | 25 +++++++++++++++++ .../android/hardware/keymaster/Timestamp.aidl | 22 +++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthToken.aidl create mode 100644 keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthenticatorType.aidl create mode 100644 keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/Timestamp.aidl diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthToken.aidl new file mode 100644 index 0000000000..db1df2b050 --- /dev/null +++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthToken.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymaster; +@VintfStability +parcelable HardwareAuthToken { + long challenge; + long userId; + long authenticatorId; + android.hardware.keymaster.HardwareAuthenticatorType authenticatorType; + android.hardware.keymaster.Timestamp timestamp; + byte[] mac; +} diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthenticatorType.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthenticatorType.aidl new file mode 100644 index 0000000000..924567f95b --- /dev/null +++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthenticatorType.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymaster; +@Backing(type="int") @VintfStability +enum HardwareAuthenticatorType { + NONE = 0, + PASSWORD = 1, + FINGERPRINT = 2, + ANY = -1, +} diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/Timestamp.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/Timestamp.aidl new file mode 100644 index 0000000000..45fa1aed13 --- /dev/null +++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/Timestamp.aidl @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymaster; +@VintfStability +parcelable Timestamp { + long milliSeconds; +} From 6912b9061333ed190e63fd3b83cd70a3683674ad Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Sun, 29 Mar 2020 10:01:50 -0700 Subject: [PATCH 0766/1022] Using VINTF manifest fragment Bug: 152703657 Test: m check-vintf-all -j Change-Id: I44fd1b7c2269891d0b4447cf1be7d8d5fbb8889a --- automotive/evs/1.0/default/Android.bp | 4 +++ automotive/evs/1.0/default/ServiceNames.h | 2 +- ...id.hardware.automotive.evs@1.0-service.xml | 26 +++++++++++++++++++ automotive/evs/1.1/default/Android.bp | 4 +++ ...id.hardware.automotive.evs@1.1-service.xml | 26 +++++++++++++++++++ 5 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 automotive/evs/1.0/default/manifest_android.hardware.automotive.evs@1.0-service.xml create mode 100644 automotive/evs/1.1/default/manifest_android.hardware.automotive.evs@1.1-service.xml diff --git a/automotive/evs/1.0/default/Android.bp b/automotive/evs/1.0/default/Android.bp index 69bb721dd7..6e28ab1a54 100644 --- a/automotive/evs/1.0/default/Android.bp +++ b/automotive/evs/1.0/default/Android.bp @@ -27,4 +27,8 @@ cc_binary { "-O0", "-g", ], + + vintf_fragments: [ + "manifest_android.hardware.automotive.evs@1.0-service.xml", + ], } diff --git a/automotive/evs/1.0/default/ServiceNames.h b/automotive/evs/1.0/default/ServiceNames.h index 1178da5a9c..84b1697d0f 100644 --- a/automotive/evs/1.0/default/ServiceNames.h +++ b/automotive/evs/1.0/default/ServiceNames.h @@ -14,4 +14,4 @@ * limitations under the License. */ -const static char kEnumeratorServiceName[] = "EvsEnumeratorHw"; +const static char kEnumeratorServiceName[] = "hw/0"; diff --git a/automotive/evs/1.0/default/manifest_android.hardware.automotive.evs@1.0-service.xml b/automotive/evs/1.0/default/manifest_android.hardware.automotive.evs@1.0-service.xml new file mode 100644 index 0000000000..39aec43974 --- /dev/null +++ b/automotive/evs/1.0/default/manifest_android.hardware.automotive.evs@1.0-service.xml @@ -0,0 +1,26 @@ + + + + + android.hardware.automotive.evs + hwbinder + 1.0 + + IEvsEnumerator + hw/0 + + + diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp index d843167954..6e5695d7c4 100644 --- a/automotive/evs/1.1/default/Android.bp +++ b/automotive/evs/1.1/default/Android.bp @@ -45,6 +45,10 @@ cc_binary { required: [ "evs_default_configuration.xml", ], + + vintf_fragments: [ + "manifest_android.hardware.automotive.evs@1.1-service.xml", + ], } prebuilt_etc { diff --git a/automotive/evs/1.1/default/manifest_android.hardware.automotive.evs@1.1-service.xml b/automotive/evs/1.1/default/manifest_android.hardware.automotive.evs@1.1-service.xml new file mode 100644 index 0000000000..d4d9b17c05 --- /dev/null +++ b/automotive/evs/1.1/default/manifest_android.hardware.automotive.evs@1.1-service.xml @@ -0,0 +1,26 @@ + + + + + android.hardware.automotive.evs + hwbinder + 1.1 + + IEvsEnumerator + hw/0 + + + From 9a4af4bce5b42d368dc4a783f1adb6c6550732ef Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 30 Mar 2020 14:59:20 +0900 Subject: [PATCH 0767/1022] Update the current API dump All aidl_interface modules should by default considered as stable, in case it is used across system and vendor partitions, or across modules. Like other API surfaces, we need to have a dump for the current (yet-to-be-released) version and update it when there is an API change. This is done via . Then the owner of the interface can freeze the current version as a numbered version via . This change shal be rejected only when the owner is certain that the interface is not used across the updatable boundaries. Bug: 152655547 Test: m Change-Id: If47c5982894dc99a7f2d1767d64be60b491842c7 --- .../hardware/light/BrightnessMode.aidl | 24 +++++++++++++++ .../android/hardware/light/FlashMode.aidl | 24 +++++++++++++++ .../android/hardware/light/HwLight.aidl | 24 +++++++++++++++ .../android/hardware/light/HwLightState.aidl | 26 ++++++++++++++++ .../android/hardware/light/ILights.aidl | 23 ++++++++++++++ .../android/hardware/light/LightType.aidl | 30 +++++++++++++++++++ 6 files changed, 151 insertions(+) create mode 100644 light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/BrightnessMode.aidl create mode 100644 light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/FlashMode.aidl create mode 100644 light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/HwLight.aidl create mode 100644 light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/HwLightState.aidl create mode 100644 light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/ILights.aidl create mode 100644 light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/LightType.aidl diff --git a/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/BrightnessMode.aidl b/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/BrightnessMode.aidl new file mode 100644 index 0000000000..c4c6d64786 --- /dev/null +++ b/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/BrightnessMode.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.light; +@VintfStability +enum BrightnessMode { + USER = 0, + SENSOR = 1, + LOW_PERSISTENCE = 2, +} diff --git a/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/FlashMode.aidl b/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/FlashMode.aidl new file mode 100644 index 0000000000..349f9f321c --- /dev/null +++ b/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/FlashMode.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.light; +@VintfStability +enum FlashMode { + NONE = 0, + TIMED = 1, + HARDWARE = 2, +} diff --git a/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/HwLight.aidl b/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/HwLight.aidl new file mode 100644 index 0000000000..c397f91060 --- /dev/null +++ b/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/HwLight.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.light; +@VintfStability +parcelable HwLight { + int id; + int ordinal; + android.hardware.light.LightType type; +} diff --git a/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/HwLightState.aidl b/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/HwLightState.aidl new file mode 100644 index 0000000000..44a088234f --- /dev/null +++ b/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/HwLightState.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.light; +@VintfStability +parcelable HwLightState { + int color; + android.hardware.light.FlashMode flashMode; + int flashOnMs; + int flashOffMs; + android.hardware.light.BrightnessMode brightnessMode; +} diff --git a/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/ILights.aidl b/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/ILights.aidl new file mode 100644 index 0000000000..fc6c6265af --- /dev/null +++ b/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/ILights.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.light; +@VintfStability +interface ILights { + void setLightState(in int id, in android.hardware.light.HwLightState state); + android.hardware.light.HwLight[] getLights(); +} diff --git a/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/LightType.aidl b/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/LightType.aidl new file mode 100644 index 0000000000..77ab98c1cf --- /dev/null +++ b/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/LightType.aidl @@ -0,0 +1,30 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.light; +@VintfStability +enum LightType { + BACKLIGHT = 0, + KEYBOARD = 1, + BUTTONS = 2, + BATTERY = 3, + NOTIFICATIONS = 4, + ATTENTION = 5, + BLUETOOTH = 6, + WIFI = 7, + MICROPHONE = 8, +} From e88dca8d99c8824dfe9ba03c77ca297582ad334b Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 30 Mar 2020 14:59:40 +0900 Subject: [PATCH 0768/1022] Update the current API dump All aidl_interface modules should by default considered as stable, in case it is used across system and vendor partitions, or across modules. Like other API surfaces, we need to have a dump for the current (yet-to-be-released) version and update it when there is an API change. This is done via . Then the owner of the interface can freeze the current version as a numbered version via . This change shal be rejected only when the owner is certain that the interface is not used across the updatable boundaries. Bug: 152655547 Test: m Change-Id: Idb1c34df81674321911e4a85f9e862b539a3f30c --- .../current/android/hardware/power/Boost.aidl | 27 ++++++++++++++ .../android/hardware/power/IPower.aidl | 25 +++++++++++++ .../current/android/hardware/power/Mode.aidl | 36 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Boost.aidl create mode 100644 power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl create mode 100644 power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Boost.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Boost.aidl new file mode 100644 index 0000000000..aced215bb9 --- /dev/null +++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Boost.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.power; +@Backing(type="int") @VintfStability +enum Boost { + INTERACTION = 0, + DISPLAY_UPDATE_IMMINENT = 1, + ML_ACC = 2, + AUDIO_LAUNCH = 3, + CAMERA_LAUNCH = 4, + CAMERA_SHOT = 5, +} diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl new file mode 100644 index 0000000000..8a06623fca --- /dev/null +++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.power; +@VintfStability +interface IPower { + oneway void setMode(in android.hardware.power.Mode type, in boolean enabled); + boolean isModeSupported(in android.hardware.power.Mode type); + oneway void setBoost(in android.hardware.power.Boost type, in int durationMs); + boolean isBoostSupported(in android.hardware.power.Boost type); +} diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl new file mode 100644 index 0000000000..f7c2552c8d --- /dev/null +++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl @@ -0,0 +1,36 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.power; +@Backing(type="int") @VintfStability +enum Mode { + DOUBLE_TAP_TO_WAKE = 0, + LOW_POWER = 1, + SUSTAINED_PERFORMANCE = 2, + FIXED_PERFORMANCE = 3, + VR = 4, + LAUNCH = 5, + EXPENSIVE_RENDERING = 6, + INTERACTIVE = 7, + DEVICE_IDLE = 8, + DISPLAY_INACTIVE = 9, + AUDIO_STREAMING_LOW_LATENCY = 10, + CAMERA_STREAMING_SECURE = 11, + CAMERA_STREAMING_LOW = 12, + CAMERA_STREAMING_MID = 13, + CAMERA_STREAMING_HIGH = 14, +} From 640d9b8df4bf2da601618def12f514ccedaebcf2 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 30 Mar 2020 14:59:58 +0900 Subject: [PATCH 0769/1022] Update the current API dump All aidl_interface modules should by default considered as stable, in case it is used across system and vendor partitions, or across modules. Like other API surfaces, we need to have a dump for the current (yet-to-be-released) version and update it when there is an API change. This is done via . Then the owner of the interface can freeze the current version as a numbered version via . This change shal be rejected only when the owner is certain that the interface is not used across the updatable boundaries. Bug: 152655547 Test: m Change-Id: If899eb8ea77a20b0c097c61abe5bdab64cd6f487 --- .../hardware/rebootescrow/IRebootEscrow.aidl | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/current/android/hardware/rebootescrow/IRebootEscrow.aidl diff --git a/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/current/android/hardware/rebootescrow/IRebootEscrow.aidl b/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/current/android/hardware/rebootescrow/IRebootEscrow.aidl new file mode 100644 index 0000000000..ea669a30cc --- /dev/null +++ b/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/current/android/hardware/rebootescrow/IRebootEscrow.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.rebootescrow; +@VintfStability +interface IRebootEscrow { + void storeKey(in byte[] kek); + byte[] retrieveKey(); +} From 8f023acb78d8283c2686d780d41e95406fcf1f40 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 30 Mar 2020 15:00:27 +0900 Subject: [PATCH 0770/1022] Update the current API dump All aidl_interface modules should by default considered as stable, in case it is used across system and vendor partitions, or across modules. Like other API surfaces, we need to have a dump for the current (yet-to-be-released) version and update it when there is an API change. This is done via . Then the owner of the interface can freeze the current version as a numbered version via . This change shal be rejected only when the owner is certain that the interface is not used across the updatable boundaries. Bug: 152655547 Test: m Change-Id: I93fba2721695a14e0eb4a2173066ce132228b895 --- .../extension/vibrator/Directionality.aidl | 24 +++++++++++ .../extension/vibrator/ICustomVibrator.aidl | 25 +++++++++++ .../extension/vibrator/VendorEffect.aidl | 23 ++++++++++ .../hardware/vibrator/CompositeEffect.aidl | 24 +++++++++++ .../hardware/vibrator/CompositePrimitive.aidl | 29 +++++++++++++ .../android/hardware/vibrator/Effect.aidl | 43 +++++++++++++++++++ .../hardware/vibrator/EffectStrength.aidl | 24 +++++++++++ .../android/hardware/vibrator/IVibrator.aidl | 43 +++++++++++++++++++ .../hardware/vibrator/IVibratorCallback.aidl | 22 ++++++++++ 9 files changed, 257 insertions(+) create mode 100644 tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/Directionality.aidl create mode 100644 tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl create mode 100644 tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/VendorEffect.aidl create mode 100644 vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositeEffect.aidl create mode 100644 vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositePrimitive.aidl create mode 100644 vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Effect.aidl create mode 100644 vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/EffectStrength.aidl create mode 100644 vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl create mode 100644 vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorCallback.aidl diff --git a/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/Directionality.aidl b/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/Directionality.aidl new file mode 100644 index 0000000000..26eb1b48b4 --- /dev/null +++ b/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/Directionality.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.tests.extension.vibrator; +@Backing(type="int") @VintfStability +enum Directionality { + NONE = 0, + TRANSVERSE = 1, + LONGITUDINAL = 2, +} diff --git a/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl b/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl new file mode 100644 index 0000000000..ed9a3c665e --- /dev/null +++ b/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.tests.extension.vibrator; +@VintfStability +interface ICustomVibrator { + int getVendorCapabilities(); + void setDirectionality(android.hardware.tests.extension.vibrator.Directionality directionality); + int perform(android.hardware.tests.extension.vibrator.VendorEffect effect, android.hardware.vibrator.IVibratorCallback callback); + const int CAP_VENDOR_DIRECTIONALITY = 1; +} diff --git a/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/VendorEffect.aidl b/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/VendorEffect.aidl new file mode 100644 index 0000000000..4d03a0a09c --- /dev/null +++ b/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/VendorEffect.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.tests.extension.vibrator; +@Backing(type="int") @VintfStability +enum VendorEffect { + CRACKLE = 0, + WIGGLE = 1, +} diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositeEffect.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositeEffect.aidl new file mode 100644 index 0000000000..8cb259ffaa --- /dev/null +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositeEffect.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.vibrator; +@VintfStability +parcelable CompositeEffect { + int delayMs; + android.hardware.vibrator.CompositePrimitive primitive; + float scale; +} diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositePrimitive.aidl new file mode 100644 index 0000000000..6ab7ac5b20 --- /dev/null +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositePrimitive.aidl @@ -0,0 +1,29 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.vibrator; +@Backing(type="int") @VintfStability +enum CompositePrimitive { + NOOP = 0, + CLICK = 1, + THUD = 2, + SPIN = 3, + QUICK_RISE = 4, + SLOW_RISE = 5, + QUICK_FALL = 6, + LIGHT_TICK = 7, +} diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Effect.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Effect.aidl new file mode 100644 index 0000000000..5ed4dc5ad6 --- /dev/null +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Effect.aidl @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.vibrator; +@Backing(type="int") @VintfStability +enum Effect { + CLICK = 0, + DOUBLE_CLICK = 1, + TICK = 2, + THUD = 3, + POP = 4, + HEAVY_CLICK = 5, + RINGTONE_1 = 6, + RINGTONE_2 = 7, + RINGTONE_3 = 8, + RINGTONE_4 = 9, + RINGTONE_5 = 10, + RINGTONE_6 = 11, + RINGTONE_7 = 12, + RINGTONE_8 = 13, + RINGTONE_9 = 14, + RINGTONE_10 = 15, + RINGTONE_11 = 16, + RINGTONE_12 = 17, + RINGTONE_13 = 18, + RINGTONE_14 = 19, + RINGTONE_15 = 20, + TEXTURE_TICK = 21, +} diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/EffectStrength.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/EffectStrength.aidl new file mode 100644 index 0000000000..802d236309 --- /dev/null +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/EffectStrength.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.vibrator; +@Backing(type="byte") @VintfStability +enum EffectStrength { + LIGHT = 0, + MEDIUM = 1, + STRONG = 2, +} diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl new file mode 100644 index 0000000000..2de1d7bde7 --- /dev/null +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.vibrator; +@VintfStability +interface IVibrator { + int getCapabilities(); + void off(); + void on(in int timeoutMs, in android.hardware.vibrator.IVibratorCallback callback); + int perform(in android.hardware.vibrator.Effect effect, in android.hardware.vibrator.EffectStrength strength, in android.hardware.vibrator.IVibratorCallback callback); + android.hardware.vibrator.Effect[] getSupportedEffects(); + void setAmplitude(in float amplitude); + void setExternalControl(in boolean enabled); + int getCompositionDelayMax(); + int getCompositionSizeMax(); + android.hardware.vibrator.CompositePrimitive[] getSupportedPrimitives(); + int getPrimitiveDuration(android.hardware.vibrator.CompositePrimitive primitive); + void compose(in android.hardware.vibrator.CompositeEffect[] composite, in android.hardware.vibrator.IVibratorCallback callback); + android.hardware.vibrator.Effect[] getSupportedAlwaysOnEffects(); + void alwaysOnEnable(in int id, in android.hardware.vibrator.Effect effect, in android.hardware.vibrator.EffectStrength strength); + void alwaysOnDisable(in int id); + const int CAP_ON_CALLBACK = 1; + const int CAP_PERFORM_CALLBACK = 2; + const int CAP_AMPLITUDE_CONTROL = 4; + const int CAP_EXTERNAL_CONTROL = 8; + const int CAP_EXTERNAL_AMPLITUDE_CONTROL = 16; + const int CAP_COMPOSE_EFFECTS = 32; + const int CAP_ALWAYS_ON_CONTROL = 64; +} diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorCallback.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorCallback.aidl new file mode 100644 index 0000000000..3a1e7d865b --- /dev/null +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorCallback.aidl @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.vibrator; +@VintfStability +interface IVibratorCallback { + oneway void onComplete(); +} From f20a45e7c3b250497ade9d732e8a0c67e238ca67 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 30 Mar 2020 15:01:03 +0900 Subject: [PATCH 0771/1022] Update the current API dump All aidl_interface modules should by default considered as stable, in case it is used across system and vendor partitions, or across modules. Like other API surfaces, we need to have a dump for the current (yet-to-be-released) version and update it when there is an API change. This is done via . Then the owner of the interface can freeze the current version as a numbered version via . This change shal be rejected only when the owner is certain that the interface is not used across the updatable boundaries. Bug: 152655547 Test: m Change-Id: Icc9c32aaf7f8555e6a3792bb5e5a2b48a446c545 --- .../android/hardware/common/NativeHandle.aidl | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/NativeHandle.aidl diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/NativeHandle.aidl b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/NativeHandle.aidl new file mode 100644 index 0000000000..f37b7d506f --- /dev/null +++ b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/NativeHandle.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.common; +@VintfStability +parcelable NativeHandle { + ParcelFileDescriptor[] fds; + int[] ints; +} From a9d0e90f14c660b6ea3693d02b0721c3e0980c45 Mon Sep 17 00:00:00 2001 From: chrisweir Date: Thu, 27 Feb 2020 14:33:51 -0800 Subject: [PATCH 0772/1022] Add Support for Configuring CAN HAL by Serialno Configuration files may now specify a list of serial numbers, or serial number suffixes. These can be used to identify a USB peripheral, regardless of what order the interface names are configured by the OS. Bug: 142654031 Test: Manual Change-Id: Idcdad1159b216119eb063df8bb229172a383b9ed Merged-In: Idcdad1159b216119eb063df8bb229172a383b9ed (cherry picked from commit 442b3badc8e2458f249104df47cd58bb58c4c9e0) --- automotive/can/1.0/default/Android.bp | 1 + automotive/can/1.0/default/CanController.cpp | 213 +++++++++++++++++- .../1.0/tools/configurator/canprototools.cpp | 15 +- 3 files changed, 214 insertions(+), 15 deletions(-) diff --git a/automotive/can/1.0/default/Android.bp b/automotive/can/1.0/default/Android.bp index ee2e92bdb1..f5cf425887 100644 --- a/automotive/can/1.0/default/Android.bp +++ b/automotive/can/1.0/default/Android.bp @@ -51,5 +51,6 @@ cc_binary { ], static_libs: [ "android.hardware.automotive.can@libnetdevice", + "android.hardware.automotive@libc++fs", ], } diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp index 0700c77513..a2643afccf 100644 --- a/automotive/can/1.0/default/CanController.cpp +++ b/automotive/can/1.0/default/CanController.cpp @@ -23,6 +23,8 @@ #include #include +#include +#include #include namespace android::hardware::automotive::can::V1_0::implementation { @@ -30,6 +32,29 @@ namespace android::hardware::automotive::can::V1_0::implementation { using IfId = ICanController::BusConfig::InterfaceId; using IfIdDisc = ICanController::BusConfig::InterfaceId::hidl_discriminator; +namespace fsErrors { +static const std::error_code ok; +static const std::error_code eperm(EPERM, std::generic_category()); +static const std::error_code enoent(ENOENT, std::generic_category()); +static const std::error_code eacces(EACCES, std::generic_category()); +} // namespace fsErrors + +/* In the /sys/devices tree, there are files called "serial", which contain the serial numbers + * for various devices. The exact location inside of this directory is dependent upon the + * hardware we are running on, so we have to start from /sys/devices and work our way down. */ +static const std::filesystem::path kDevPath("/sys/devices/"); +static const std::regex kTtyRe("^tty[A-Z]+[0-9]+$"); +static constexpr auto kOpts = ~(std::filesystem::directory_options::follow_directory_symlink | + std::filesystem::directory_options::skip_permission_denied); + +/** + * A helper object to associate the interface name and type of a USB to CAN adapter. + */ +struct UsbCanIface { + ICanController::InterfaceType iftype; + std::string ifaceName; +}; + Return CanController::getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) { _hidl_cb({ICanController::InterfaceType::VIRTUAL, ICanController::InterfaceType::SOCKETCAN, ICanController::InterfaceType::SLCAN}); @@ -41,6 +66,152 @@ static bool isValidName(const std::string& name) { return std::regex_match(name, nameRE); } +/** + * Given a UsbCanIface object, get the ifaceName given the serialPath. + * + * \param serialPath - Absolute path to a "serial" file for a given device in /sys. + * \return A populated UsbCanIface. On failure, nullopt is returned. + */ +static std::optional getIfaceName(std::filesystem::path serialPath) { + std::error_code fsStatus; + // Since the path is to a file called "serial", we need to search its parent directory. + std::filesystem::recursive_directory_iterator fsItr(serialPath.parent_path(), kOpts, fsStatus); + if (fsStatus != fsErrors::ok) { + LOG(ERROR) << "Failed to open " << serialPath.parent_path(); + return std::nullopt; + } + + for (; fsStatus == fsErrors::ok && fsItr != std::filesystem::recursive_directory_iterator(); + fsItr.increment(fsStatus)) { + /* We want either a directory called "net" or a directory that looks like tty, so + * skip files. */ + bool isDir = fsItr->is_directory(fsStatus); + if (fsStatus != fsErrors::ok || !isDir) continue; + + /* path() returns an iterator that steps through directories from / to the leaf. + * end() returns one past the leaf of the path, but we want the leaf. Decrementing the + * path gives us a pointer to the leaf, which we then dereference.*/ + std::string currentDir = *(--(fsItr->path().end())); + if (currentDir == "net") { + /* This device is a SocketCAN device. The iface name is the only directory under + * net/. Multiple directories under net/ is an error.*/ + std::filesystem::directory_iterator netItr(fsItr->path(), kOpts, fsStatus); + if (fsStatus != fsErrors::ok) { + LOG(ERROR) << "Failed to open " << fsItr->path() << " to get net name!"; + return std::nullopt; + } + + // Get the leaf of the path. This is the interface name, assuming it's the only leaf. + std::string netName = *(--(netItr->path().end())); + + // Check if there is more than one item in net/ + netItr.increment(fsStatus); + if (fsStatus != fsErrors::ok) { + // It's possible we have a valid net name, but this is most likely an error. + LOG(ERROR) << "Failed to verify " << fsItr->path() << " has valid net name!"; + return std::nullopt; + } + if (netItr != std::filesystem::directory_iterator()) { + // There should never be more than one name under net/ + LOG(ERROR) << "Found more than one net name in " << fsItr->path() << "!"; + return std::nullopt; + } + return {{ICanController::InterfaceType::SOCKETCAN, netName}}; + } else if (std::regex_match(currentDir, kTtyRe)) { + // This device is a USB serial device, and currentDir is the tty name. + return {{ICanController::InterfaceType::SLCAN, "/dev/" + currentDir}}; + } + } + + // check if the loop above exited due to a c++fs error. + if (fsStatus != fsErrors::ok) { + LOG(ERROR) << "Failed search filesystem: " << fsStatus; + } + return std::nullopt; +} + +/** + * A helper function to read the serial number from a "serial" file in /sys/devices/ + * + * \param serialnoPath - path to the file to read. + * \return the serial number, or nullopt on failure. + */ +static std::optional readSerialNo(const std::string& serialnoPath) { + std::ifstream serialnoStream(serialnoPath); + std::string serialno; + if (!serialnoStream.good()) { + LOG(ERROR) << "Failed to read serial number from " << serialnoPath; + return std::nullopt; + } + std::getline(serialnoStream, serialno); + return serialno; +} + +/** + * Searches for USB devices found in /sys/devices/, and attempts to find a device matching the + * provided list of serial numbers. + * + * \param configSerialnos - a list of serial number (suffixes) from the HAL config. + * \param iftype - the type of the interface to be located. + * \return a matching USB device. On failure, std::nullopt is returned. + */ +static std::optional findUsbDevice(const hidl_vec& configSerialnos) { + std::error_code fsStatus; + std::filesystem::recursive_directory_iterator fsItr(kDevPath, kOpts, fsStatus); + if (fsStatus != fsErrors::ok) { + LOG(ERROR) << "Failed to open " << kDevPath; + return std::nullopt; + } + + for (; fsStatus == fsErrors::ok && fsItr != std::filesystem::recursive_directory_iterator(); + fsItr.increment(fsStatus)) { + // We want to find a file called "serial", which is in a directory somewhere. Skip files. + bool isDir = fsItr->is_directory(fsStatus); + if (fsStatus != fsErrors::ok) { + LOG(ERROR) << "Failed check if " << fsStatus; + return std::nullopt; + } + if (!isDir) continue; + + auto serialnoPath = fsItr->path() / "serial"; + bool isReg = std::filesystem::is_regular_file(serialnoPath, fsStatus); + + /* Make sure we have permissions to this directory, ignore enoent, since the file + * "serial" may not exist, which is ok. */ + if (fsStatus == fsErrors::eperm || fsStatus == fsErrors::eacces) { + /* This means we don't have access to this directory. If we recurse into it, this + * will cause the iterator to loose its state and we'll crash. */ + fsItr.disable_recursion_pending(); + continue; + } + if (fsStatus == fsErrors::enoent) continue; + if (fsStatus != fsErrors::ok) { + LOG(WARNING) << "An unexpected error occurred while checking for serialno: " + << fsStatus; + continue; + } + if (!isReg) continue; + + // we found a serial number + auto serialno = readSerialNo(serialnoPath); + if (!serialno.has_value()) continue; + + // see if the serial number exists in the config + for (auto&& cfgSn : configSerialnos) { + if (serialno->ends_with(std::string(cfgSn))) { + auto ifaceInfo = getIfaceName(serialnoPath); + if (!ifaceInfo.has_value()) break; + return ifaceInfo; + } + } + } + if (fsStatus != fsErrors::ok) { + LOG(ERROR) << "Error searching filesystem: " << fsStatus; + return std::nullopt; + } + return std::nullopt; +} + Return CanController::upInterface(const ICanController::BusConfig& config) { LOG(VERBOSE) << "Attempting to bring interface up: " << toString(config); @@ -58,24 +229,46 @@ Return CanController::upInterface(const ICanController:: sp busService; + // SocketCAN native type interface. if (config.interfaceId.getDiscriminator() == IfIdDisc::socketcan) { - // TODO(b/142654031): support serialno auto& socketcan = config.interfaceId.socketcan(); - if (socketcan.getDiscriminator() == IfId::Socketcan::hidl_discriminator::ifname) { - busService = new CanBusNative(socketcan.ifname(), config.bitrate); + std::string ifaceName; + if (socketcan.getDiscriminator() == IfId::Socketcan::hidl_discriminator::serialno) { + // Configure by serial number. + auto selectedDevice = findUsbDevice(socketcan.serialno()); + // verify the returned device is the correct one + if (!selectedDevice.has_value() || + selectedDevice->iftype != ICanController::InterfaceType::SOCKETCAN) { + return ICanController::Result::BAD_INTERFACE_ID; + } + ifaceName = selectedDevice->ifaceName; } else { - return ICanController::Result::BAD_INTERFACE_ID; + // configure by iface name. + ifaceName = socketcan.ifname(); } - } else if (config.interfaceId.getDiscriminator() == IfIdDisc::virtualif) { + busService = new CanBusNative(ifaceName, config.bitrate); + } + // Virtual interface. + else if (config.interfaceId.getDiscriminator() == IfIdDisc::virtualif) { busService = new CanBusVirtual(config.interfaceId.virtualif().ifname); - } else if (config.interfaceId.getDiscriminator() == IfIdDisc::slcan) { - // TODO(b/142654031): support serialno + } + // SLCAN interface. + else if (config.interfaceId.getDiscriminator() == IfIdDisc::slcan) { auto& slcan = config.interfaceId.slcan(); - if (slcan.getDiscriminator() == IfId::Slcan::hidl_discriminator::ttyname) { - busService = new CanBusSlcan(slcan.ttyname(), config.bitrate); + std::string ttyName; + if (slcan.getDiscriminator() == IfId::Slcan::hidl_discriminator::serialno) { + // Configure by serial number. + auto selectedDevice = findUsbDevice(slcan.serialno()); + if (!selectedDevice.has_value() || + selectedDevice->iftype != ICanController::InterfaceType::SLCAN) { + return ICanController::Result::BAD_INTERFACE_ID; + } + ttyName = selectedDevice->ifaceName; } else { - return ICanController::Result::BAD_INTERFACE_ID; + // Configure by tty name. + ttyName = slcan.ttyname(); } + busService = new CanBusSlcan(ttyName, config.bitrate); } else { return ICanController::Result::NOT_SUPPORTED; } diff --git a/automotive/can/1.0/tools/configurator/canprototools.cpp b/automotive/can/1.0/tools/configurator/canprototools.cpp index 8e6b2b1d45..e7e364222c 100644 --- a/automotive/can/1.0/tools/configurator/canprototools.cpp +++ b/automotive/can/1.0/tools/configurator/canprototools.cpp @@ -85,26 +85,31 @@ std::optional fromPbBus(const Bus& pb_bus) { switch (pb_bus.iface_type_case()) { case Bus::kNative: { const auto ifname = pb_bus.native().ifname(); - if (ifname.empty()) { - LOG(ERROR) << "Invalid config: native type bus must have an iface name"; + const auto serialno = pb_bus.native().serialno(); + if (ifname.empty() == serialno.empty()) { + LOG(ERROR) << "Invalid config: native type bus must have an iface name xor a " + << "serial number"; return std::nullopt; } bus_cfg.bitrate = pb_bus.bitrate(); ICanController::BusConfig::InterfaceId::Socketcan socketcan = {}; - socketcan.ifname(ifname); + if (!ifname.empty()) socketcan.ifname(ifname); + if (!serialno.empty()) socketcan.serialno({serialno.begin(), serialno.end()}); bus_cfg.interfaceId.socketcan(socketcan); // TODO(b/142654031) - add support for serial number as an option instead of ifname. break; } case Bus::kSlcan: { const auto ttyname = pb_bus.slcan().ttyname(); - if (ttyname.empty()) { + const auto serialno = pb_bus.slcan().serialno(); + if (ttyname.empty() == serialno.empty()) { LOG(ERROR) << "Invalid config: slcan type bus must have a tty name"; return std::nullopt; } bus_cfg.bitrate = pb_bus.bitrate(); ICanController::BusConfig::InterfaceId::Slcan slcan = {}; - slcan.ttyname(pb_bus.slcan().ttyname()); + if (!ttyname.empty()) slcan.ttyname(ttyname); + if (!serialno.empty()) slcan.serialno({serialno.begin(), serialno.end()}); bus_cfg.interfaceId.slcan(slcan); break; } From 31f0c96c26c70a99a1de0351529a5c5a648a3e93 Mon Sep 17 00:00:00 2001 From: Hayden Gomes Date: Mon, 30 Mar 2020 10:40:11 -0700 Subject: [PATCH 0773/1022] Adding IAudioControl@2.0 to compatibility matrix Bug: 148178269 Test: built target using V2 of IAudioControl Change-Id: I9673e35f2f9e667b66e1b9fbfa2fb13b975b7cb1 --- compatibility_matrices/compatibility_matrix.5.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/compatibility_matrices/compatibility_matrix.5.xml b/compatibility_matrices/compatibility_matrix.5.xml index b5f8413058..38f589daf0 100644 --- a/compatibility_matrices/compatibility_matrix.5.xml +++ b/compatibility_matrices/compatibility_matrix.5.xml @@ -34,6 +34,7 @@ android.hardware.automotive.audiocontrol 1.0 + 2.0 IAudioControl default From c8716aebfc4e20c134cbbd8ac168539458e01856 Mon Sep 17 00:00:00 2001 From: chrisweir Date: Mon, 30 Mar 2020 13:12:30 -0700 Subject: [PATCH 0774/1022] Remove completed TODO TODO for serial number support should be removed now that the feature is implemented and merged. Bug: 142654031 Test: Manual - comment only change Change-Id: Ib733e71840e82e5cd9c47825a53f804f9c296a3d --- automotive/can/1.0/tools/configurator/canprototools.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/automotive/can/1.0/tools/configurator/canprototools.cpp b/automotive/can/1.0/tools/configurator/canprototools.cpp index e7e364222c..0a12bd6f21 100644 --- a/automotive/can/1.0/tools/configurator/canprototools.cpp +++ b/automotive/can/1.0/tools/configurator/canprototools.cpp @@ -96,7 +96,6 @@ std::optional fromPbBus(const Bus& pb_bus) { if (!ifname.empty()) socketcan.ifname(ifname); if (!serialno.empty()) socketcan.serialno({serialno.begin(), serialno.end()}); bus_cfg.interfaceId.socketcan(socketcan); - // TODO(b/142654031) - add support for serial number as an option instead of ifname. break; } case Bus::kSlcan: { From 0d6bfdc73f0d51b8d861d930ec46f43ff0767eb1 Mon Sep 17 00:00:00 2001 From: Hayden Gomes Date: Mon, 30 Mar 2020 17:15:27 -0700 Subject: [PATCH 0775/1022] Adding IAudioControl@2.0 to current compatibility matrix - Already added to compatibility_matrix.5.xml in change-id I9673e35f2f9e667b66e1b9fbfa2fb13b975b7cb1 Bug: 148178269 Test: built target using V2 of IAudioControl Change-Id: I7a49da8823d2c5f07a1abd3bbb177d9885a65cb0 --- compatibility_matrices/compatibility_matrix.current.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 65832b08e7..2b1979322a 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -34,6 +34,7 @@ android.hardware.automotive.audiocontrol 1.0 + 2.0 IAudioControl default From 2a957061506e37ce5bde7b684c4c48de93f203fc Mon Sep 17 00:00:00 2001 From: Amy Zhang Date: Mon, 30 Mar 2020 17:56:35 -0700 Subject: [PATCH 0776/1022] Convert VtsHalTvInputV1_0TargetTest to parameterized gtest Test: atest VtsHalTvInputV1_0TargetTest Bug: 150382976 Change-Id: I6a7bd522ac10f4462d187d3d6261e523c1b73bd0 --- tv/input/1.0/vts/functional/Android.bp | 7 +- .../VtsHalTvInputV1_0TargetTest.cpp | 486 ++++++++---------- 2 files changed, 232 insertions(+), 261 deletions(-) diff --git a/tv/input/1.0/vts/functional/Android.bp b/tv/input/1.0/vts/functional/Android.bp index 29181b0c8b..5d20bceeed 100644 --- a/tv/input/1.0/vts/functional/Android.bp +++ b/tv/input/1.0/vts/functional/Android.bp @@ -19,6 +19,9 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalTvInputV1_0TargetTest.cpp"], static_libs: ["android.hardware.tv.input@1.0"], - test_suites: ["general-tests"], + test_suites: [ + "general-tests", + "vts-core", + ], + require_root: true, } - diff --git a/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp b/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp index 573a1d6cb5..59c70eb1e2 100644 --- a/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp +++ b/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp @@ -17,11 +17,12 @@ #define LOG_TAG "tv_input_hidl_hal_test" #include -#include #include #include - -#include +#include +#include +#include +#include #include #include #include @@ -42,179 +43,161 @@ using ::android::sp; #define WAIT_FOR_EVENT_TIMEOUT 5 #define DEFAULT_ID INT32_MIN -// Test environment for TvInput HIDL HAL. -class TvInputHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static TvInputHidlEnvironment* Instance() { - static TvInputHidlEnvironment* instance = new TvInputHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { registerTestService(); } - - private: - TvInputHidlEnvironment() {} -}; - /* The main test class for TV Input HIDL HAL. */ -class TvInputHidlTest : public ::testing::VtsHalHidlTargetTestBase { - public: - virtual void SetUp() override { - tv_input_ = ::testing::VtsHalHidlTargetTestBase::getService( - TvInputHidlEnvironment::Instance()->getServiceName()); - ASSERT_NE(tv_input_, nullptr); - tv_input_callback_ = new TvInputCallback(*this); - ASSERT_NE(tv_input_callback_, nullptr); - tv_input_->setCallback(tv_input_callback_); - // All events received within the timeout should be handled. - sleep(WAIT_FOR_EVENT_TIMEOUT); - } - - virtual void TearDown() override {} - - /* Called when a DEVICE_AVAILABLE event is received. */ - void onDeviceAvailable(const TvInputDeviceInfo& deviceInfo) { - device_info_.add(deviceInfo.deviceId, deviceInfo); - } - - /* Called when a DEVICE_UNAVAILABLE event is received. */ - void onDeviceUnavailable(int32_t deviceId) { - device_info_.removeItem(deviceId); - } - - /* Called when a DEVICE_CONFIGURATIONS_CHANGED event is received. */ - Result onStreamConfigurationsChanged(int32_t deviceId) { - return updateStreamConfigurations(deviceId); - } - - /* Gets and updates the stream configurations for a device. */ - Result updateStreamConfigurations(int32_t deviceId) { - stream_config_.removeItem(deviceId); - Result result = Result::UNKNOWN; - hidl_vec list; - tv_input_->getStreamConfigurations(deviceId, - [&result, &list](Result res, hidl_vec configs) { - result = res; - if (res == Result::OK) { - list = configs; - } - }); - if (result == Result::OK) { - stream_config_.add(deviceId, list); - } - return result; - } - - /* Gets and updates the stream configurations for all existing devices. */ - void updateAllStreamConfigurations() { - for (size_t i = 0; i < device_info_.size(); i++) { - int32_t device_id = device_info_.keyAt(i); - updateStreamConfigurations(device_id); - } - } - - /* Returns a list of indices of stream_config_ whose corresponding values are not empty. */ - std::vector getConfigIndices() { - std::vector indices; - for (size_t i = 0; i < stream_config_.size(); i++) { - if (stream_config_.valueAt(i).size() != 0) { - indices.push_back(i); - } - } - return indices; - } - - /* - * Returns DEFAULT_ID if there is no missing integer in the range [0, the size of nums). - * Otherwise, returns the smallest missing non-negative integer. - */ - int32_t getNumNotIn(std::vector& nums) { - int32_t result = DEFAULT_ID; - int32_t size = static_cast(nums.size()); - for (int32_t i = 0; i < size; i++) { - // Put every element to its target position, if possible. - int32_t target_pos = nums[i]; - while (target_pos >= 0 && target_pos < size && i != target_pos && nums[i] != nums[target_pos]) { - std::swap(nums[i], nums[target_pos]); - target_pos = nums[i]; - } +class TvInputHidlTest : public testing::TestWithParam { + public: + virtual void SetUp() override { + tv_input_ = ITvInput::getService(GetParam()); + tv_input_callback_ = new TvInputCallback(*this); + ASSERT_NE(tv_input_callback_, nullptr); + tv_input_->setCallback(tv_input_callback_); + // All events received within the timeout should be handled. + sleep(WAIT_FOR_EVENT_TIMEOUT); } - for (int32_t i = 0; i < size; i++) { - if (nums[i] != i) { - return i; - } + virtual void TearDown() override {} + + /* Called when a DEVICE_AVAILABLE event is received. */ + void onDeviceAvailable(const TvInputDeviceInfo& deviceInfo) { + device_info_.add(deviceInfo.deviceId, deviceInfo); } - return result; - } - /* A simple test implementation of TvInputCallback for TV Input Events. */ - class TvInputCallback : public ITvInputCallback { - public: - TvInputCallback(TvInputHidlTest& parent) : parent_(parent){}; + /* Called when a DEVICE_UNAVAILABLE event is received. */ + void onDeviceUnavailable(int32_t deviceId) { device_info_.removeItem(deviceId); } - virtual ~TvInputCallback() = default; + /* Called when a DEVICE_CONFIGURATIONS_CHANGED event is received. */ + Result onStreamConfigurationsChanged(int32_t deviceId) { + return updateStreamConfigurations(deviceId); + } - /* - * Notifies the client that an event has occured. For possible event types, - * check TvInputEventType. -      */ - Return notify(const TvInputEvent& event) override { - std::unique_lock lock(parent_.mutex_); - switch(event.type) { - case TvInputEventType::DEVICE_AVAILABLE: - parent_.onDeviceAvailable(event.deviceInfo); - break; - case TvInputEventType::DEVICE_UNAVAILABLE: - parent_.onDeviceUnavailable(event.deviceInfo.deviceId); - break; - case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED: - parent_.onStreamConfigurationsChanged(event.deviceInfo.deviceId); - break; - } - return Void(); - }; - private: - /* The test contains this callback instance. */ - TvInputHidlTest& parent_; - }; + /* Gets and updates the stream configurations for a device. */ + Result updateStreamConfigurations(int32_t deviceId) { + stream_config_.removeItem(deviceId); + Result result = Result::UNKNOWN; + hidl_vec list; + tv_input_->getStreamConfigurations( + deviceId, [&result, &list](Result res, hidl_vec configs) { + result = res; + if (res == Result::OK) { + list = configs; + } + }); + if (result == Result::OK) { + stream_config_.add(deviceId, list); + } + return result; + } - /* The TvInput used for the test. */ - sp tv_input_; + /* Gets and updates the stream configurations for all existing devices. */ + void updateAllStreamConfigurations() { + for (size_t i = 0; i < device_info_.size(); i++) { + int32_t device_id = device_info_.keyAt(i); + updateStreamConfigurations(device_id); + } + } - /* The TvInputCallback used for the test. */ - sp tv_input_callback_; + /* Returns a list of indices of stream_config_ whose corresponding values are not empty. */ + std::vector getConfigIndices() { + std::vector indices; + for (size_t i = 0; i < stream_config_.size(); i++) { + if (stream_config_.valueAt(i).size() != 0) { + indices.push_back(i); + } + } + return indices; + } - /* - * A KeyedVector stores device information of every available device. - * A key is a device ID and the corresponding value is the TvInputDeviceInfo. - */ - android::KeyedVector device_info_; + /* + * Returns DEFAULT_ID if there is no missing integer in the range [0, the size of nums). + * Otherwise, returns the smallest missing non-negative integer. + */ + int32_t getNumNotIn(std::vector& nums) { + int32_t result = DEFAULT_ID; + int32_t size = static_cast(nums.size()); + for (int32_t i = 0; i < size; i++) { + // Put every element to its target position, if possible. + int32_t target_pos = nums[i]; + while (target_pos >= 0 && target_pos < size && i != target_pos && + nums[i] != nums[target_pos]) { + std::swap(nums[i], nums[target_pos]); + target_pos = nums[i]; + } + } - /* - * A KeyedVector stores a list of stream configurations of every available device. - * A key is a device ID and the corresponding value is the stream configuration list. - */ - android::KeyedVector> stream_config_; + for (int32_t i = 0; i < size; i++) { + if (nums[i] != i) { + return i; + } + } + return result; + } - /* The mutex controls the access of shared data. */ - std::mutex mutex_; + /* A simple test implementation of TvInputCallback for TV Input Events. */ + class TvInputCallback : public ITvInputCallback { + public: + TvInputCallback(TvInputHidlTest& parent) : parent_(parent){}; + + virtual ~TvInputCallback() = default; + + /* + * Notifies the client that an event has occurred. For possible event types, + * check TvInputEventType. +      */ + Return notify(const TvInputEvent& event) override { + std::unique_lock lock(parent_.mutex_); + switch (event.type) { + case TvInputEventType::DEVICE_AVAILABLE: + parent_.onDeviceAvailable(event.deviceInfo); + break; + case TvInputEventType::DEVICE_UNAVAILABLE: + parent_.onDeviceUnavailable(event.deviceInfo.deviceId); + break; + case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED: + parent_.onStreamConfigurationsChanged(event.deviceInfo.deviceId); + break; + } + return Void(); + }; + + private: + /* The test contains this callback instance. */ + TvInputHidlTest& parent_; + }; + + /* The TvInput used for the test. */ + sp tv_input_; + + /* The TvInputCallback used for the test. */ + sp tv_input_callback_; + + /* + * A KeyedVector stores device information of every available device. + * A key is a device ID and the corresponding value is the TvInputDeviceInfo. + */ + android::KeyedVector device_info_; + + /* + * A KeyedVector stores a list of stream configurations of every available device. + * A key is a device ID and the corresponding value is the stream configuration list. + */ + android::KeyedVector> stream_config_; + + /* The mutex controls the access of shared data. */ + std::mutex mutex_; }; - /* * GetStreamConfigTest: * Calls updateStreamConfigurations() for each existing device * Checks returned results */ -TEST_F(TvInputHidlTest, GetStreamConfigTest) { - std::unique_lock lock(mutex_); - for (size_t i = 0; i < device_info_.size(); i++) { - int32_t device_id = device_info_.keyAt(i); - Result result = updateStreamConfigurations(device_id); - EXPECT_EQ(Result::OK, result); - } +TEST_P(TvInputHidlTest, GetStreamConfigTest) { + std::unique_lock lock(mutex_); + for (size_t i = 0; i < device_info_.size(); i++) { + int32_t device_id = device_info_.keyAt(i); + Result result = updateStreamConfigurations(device_id); + EXPECT_EQ(Result::OK, result); + } } /* @@ -222,26 +205,24 @@ TEST_F(TvInputHidlTest, GetStreamConfigTest) { * Calls openStream() and then closeStream() for each existing stream * Checks returned results */ -TEST_F(TvInputHidlTest, OpenAndCloseStreamTest) { - std::unique_lock lock(mutex_); - updateAllStreamConfigurations(); - for (size_t j = 0; j < stream_config_.size(); j++) { - int32_t device_id = stream_config_.keyAt(j); - hidl_vec config = stream_config_.valueAt(j); - for (size_t i = 0; i < config.size(); i++) { - Result result = Result::UNKNOWN; - int32_t stream_id = config[i].streamId; - tv_input_->openStream(device_id, stream_id, - [&result](Result res, const native_handle_t*) { - result = res; - }); - EXPECT_EQ(Result::OK, result); +TEST_P(TvInputHidlTest, OpenAndCloseStreamTest) { + std::unique_lock lock(mutex_); + updateAllStreamConfigurations(); + for (size_t j = 0; j < stream_config_.size(); j++) { + int32_t device_id = stream_config_.keyAt(j); + hidl_vec config = stream_config_.valueAt(j); + for (size_t i = 0; i < config.size(); i++) { + Result result = Result::UNKNOWN; + int32_t stream_id = config[i].streamId; + tv_input_->openStream(device_id, stream_id, + [&result](Result res, const native_handle_t*) { result = res; }); + EXPECT_EQ(Result::OK, result); - result = Result::UNKNOWN; - result = tv_input_->closeStream(device_id, stream_id); - EXPECT_EQ(Result::OK, result); + result = Result::UNKNOWN; + result = tv_input_->closeStream(device_id, stream_id); + EXPECT_EQ(Result::OK, result); + } } - } } /* @@ -251,28 +232,26 @@ TEST_F(TvInputHidlTest, OpenAndCloseStreamTest) { * Checks returned results * The results should be Result::INVALID_ARGUMENTS */ -TEST_F(TvInputHidlTest, InvalidDeviceIdTest) { - std::unique_lock lock(mutex_); +TEST_P(TvInputHidlTest, InvalidDeviceIdTest) { + std::unique_lock lock(mutex_); - std::vector device_ids; - for (size_t i = 0; i < device_info_.size(); i++) { - device_ids.push_back(device_info_.keyAt(i)); - } - // Get a non-existing device ID. - int32_t id = getNumNotIn(device_ids); - EXPECT_EQ(Result::INVALID_ARGUMENTS, updateStreamConfigurations(id)); + std::vector device_ids; + for (size_t i = 0; i < device_info_.size(); i++) { + device_ids.push_back(device_info_.keyAt(i)); + } + // Get a non-existing device ID. + int32_t id = getNumNotIn(device_ids); + EXPECT_EQ(Result::INVALID_ARGUMENTS, updateStreamConfigurations(id)); - Result result = Result::UNKNOWN; - int32_t stream_id = 0; - tv_input_->openStream(id, stream_id, - [&result](Result res, const native_handle_t*) { - result = res; - }); - EXPECT_EQ(Result::INVALID_ARGUMENTS, result); + Result result = Result::UNKNOWN; + int32_t stream_id = 0; + tv_input_->openStream(id, stream_id, + [&result](Result res, const native_handle_t*) { result = res; }); + EXPECT_EQ(Result::INVALID_ARGUMENTS, result); - result = Result::UNKNOWN; - result = tv_input_->closeStream(id, stream_id); - EXPECT_EQ(Result::INVALID_ARGUMENTS, result); + result = Result::UNKNOWN; + result = tv_input_->closeStream(id, stream_id); + EXPECT_EQ(Result::INVALID_ARGUMENTS, result); } /* @@ -281,35 +260,33 @@ TEST_F(TvInputHidlTest, InvalidDeviceIdTest) { * Checks returned results * The results should be Result::INVALID_ARGUMENTS */ -TEST_F(TvInputHidlTest, InvalidStreamIdTest) { - std::unique_lock lock(mutex_); - if (device_info_.isEmpty()) { - return; - } - updateAllStreamConfigurations(); - - int32_t device_id = device_info_.keyAt(0); - // Get a non-existing stream ID. - int32_t id = DEFAULT_ID; - if (stream_config_.indexOfKey(device_id) >= 0) { - std::vector stream_ids; - hidl_vec config = stream_config_.valueFor(device_id); - for (size_t i = 0; i < config.size(); i++) { - stream_ids.push_back(config[i].streamId); +TEST_P(TvInputHidlTest, InvalidStreamIdTest) { + std::unique_lock lock(mutex_); + if (device_info_.isEmpty()) { + return; } - id = getNumNotIn(stream_ids); - } + updateAllStreamConfigurations(); - Result result = Result::UNKNOWN; - tv_input_->openStream(device_id, id, - [&result](Result res, const native_handle_t*) { - result = res; - }); - EXPECT_EQ(Result::INVALID_ARGUMENTS, result); + int32_t device_id = device_info_.keyAt(0); + // Get a non-existing stream ID. + int32_t id = DEFAULT_ID; + if (stream_config_.indexOfKey(device_id) >= 0) { + std::vector stream_ids; + hidl_vec config = stream_config_.valueFor(device_id); + for (size_t i = 0; i < config.size(); i++) { + stream_ids.push_back(config[i].streamId); + } + id = getNumNotIn(stream_ids); + } - result = Result::UNKNOWN; - result = tv_input_->closeStream(device_id, id); - EXPECT_EQ(Result::INVALID_ARGUMENTS, result); + Result result = Result::UNKNOWN; + tv_input_->openStream(device_id, id, + [&result](Result res, const native_handle_t*) { result = res; }); + EXPECT_EQ(Result::INVALID_ARGUMENTS, result); + + result = Result::UNKNOWN; + result = tv_input_->closeStream(device_id, id); + EXPECT_EQ(Result::INVALID_ARGUMENTS, result); } /* @@ -318,28 +295,24 @@ TEST_F(TvInputHidlTest, InvalidStreamIdTest) { * Checks returned results * The result of the second call should be Result::INVALID_STATE */ -TEST_F(TvInputHidlTest, OpenAnOpenedStreamsTest) { - std::unique_lock lock(mutex_); - updateAllStreamConfigurations(); - std::vector indices = getConfigIndices(); - if (indices.empty()) { - return; - } - int32_t device_id = stream_config_.keyAt(indices[0]); - int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId; +TEST_P(TvInputHidlTest, OpenAnOpenedStreamsTest) { + std::unique_lock lock(mutex_); + updateAllStreamConfigurations(); + std::vector indices = getConfigIndices(); + if (indices.empty()) { + return; + } + int32_t device_id = stream_config_.keyAt(indices[0]); + int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId; - Result result = Result::UNKNOWN; - tv_input_->openStream(device_id, stream_id, - [&result](Result res, const native_handle_t*) { - result = res; - }); - EXPECT_EQ(Result::OK, result); + Result result = Result::UNKNOWN; + tv_input_->openStream(device_id, stream_id, + [&result](Result res, const native_handle_t*) { result = res; }); + EXPECT_EQ(Result::OK, result); - tv_input_->openStream(device_id, stream_id, - [&result](Result res, const native_handle_t*) { - result = res; - }); - EXPECT_EQ(Result::INVALID_STATE, result); + tv_input_->openStream(device_id, stream_id, + [&result](Result res, const native_handle_t*) { result = res; }); + EXPECT_EQ(Result::INVALID_STATE, result); } /* @@ -348,24 +321,19 @@ TEST_F(TvInputHidlTest, OpenAnOpenedStreamsTest) { * Checks the returned result * The result should be Result::INVALID_STATE */ -TEST_F(TvInputHidlTest, CloseStreamBeforeOpenTest) { - std::unique_lock lock(mutex_); - updateAllStreamConfigurations(); - std::vector indices = getConfigIndices(); - if (indices.empty()) { - return; - } - int32_t device_id = stream_config_.keyAt(indices[0]); - int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId; - EXPECT_EQ(Result::INVALID_STATE, tv_input_->closeStream(device_id, stream_id)); -} - -int main(int argc, char **argv) { - ::testing::AddGlobalTestEnvironment(TvInputHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - TvInputHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); - return status; +TEST_P(TvInputHidlTest, CloseStreamBeforeOpenTest) { + std::unique_lock lock(mutex_); + updateAllStreamConfigurations(); + std::vector indices = getConfigIndices(); + if (indices.empty()) { + return; + } + int32_t device_id = stream_config_.keyAt(indices[0]); + int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId; + EXPECT_EQ(Result::INVALID_STATE, tv_input_->closeStream(device_id, stream_id)); } +INSTANTIATE_TEST_SUITE_P( + PerInstance, TvInputHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITvInput::descriptor)), + android::hardware::PrintInstanceNameToString); From 0a51242abcf658f84d62bb97ccdfb4f623c03326 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 30 Mar 2020 17:17:21 -0700 Subject: [PATCH 0777/1022] Convert InputClassifierTest to parametrized test The test is currently based on old vts harness and not in vts suite. Bug: 150383004 Test: atest VtsHalInputClassifierV1_0TargetTest Change-Id: I5df4eff845fd49b8663d1589c5314d5acf4b5057 Merged-In: I5df4eff845fd49b8663d1589c5314d5acf4b5057 (cherry picked from commit 25a866eecc75058be54a837fe5c00df496e626ca) --- .../classifier/1.0/vts/functional/Android.bp | 6 ++- .../VtsHalInputClassifierV1_0TargetTest.cpp | 47 ++++++------------- 2 files changed, 18 insertions(+), 35 deletions(-) diff --git a/input/classifier/1.0/vts/functional/Android.bp b/input/classifier/1.0/vts/functional/Android.bp index ef49d70dfb..4db1398778 100644 --- a/input/classifier/1.0/vts/functional/Android.bp +++ b/input/classifier/1.0/vts/functional/Android.bp @@ -22,6 +22,8 @@ cc_test { "android.hardware.input.classifier@1.0", "android.hardware.input.common@1.0", ], - test_suites: ["general-tests"], + test_suites: [ + "general-tests", + "vts-core", + ], } - diff --git a/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp b/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp index f033c2a102..ee529c73b0 100644 --- a/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp +++ b/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp @@ -16,11 +16,12 @@ #define LOG_TAG "input_classifier_hal_test" -#include -#include #include #include #include +#include +#include +#include #include #include @@ -72,27 +73,11 @@ static MotionEvent getSimpleMotionEvent() { return event; } -// Test environment for Input Classifier HIDL HAL. -class InputClassifierHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static InputClassifierHidlEnvironment* Instance() { - static InputClassifierHidlEnvironment* instance = new InputClassifierHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { registerTestService(); } - - private: - InputClassifierHidlEnvironment() {} -}; - // The main test class for INPUT CLASSIFIER HIDL HAL 1.0. -class InputClassifierHidlTest_1_0 : public ::testing::VtsHalHidlTargetTestBase { +class InputClassifierHidlTest_1_0 : public ::testing::TestWithParam { public: virtual void SetUp() override { - classifier = ::testing::VtsHalHidlTargetTestBase::getService( - InputClassifierHidlEnvironment::Instance()->getServiceName()); + classifier = IInputClassifier::getService(GetParam()); ASSERT_NE(classifier, nullptr); } @@ -105,7 +90,7 @@ class InputClassifierHidlTest_1_0 : public ::testing::VtsHalHidlTargetTestBase { * Call resetDevice(..) for a few common device id values, and make sure that the HAL * can handle the resets gracefully. */ -TEST_F(InputClassifierHidlTest_1_0, ResetDevice) { +TEST_P(InputClassifierHidlTest_1_0, ResetDevice) { EXPECT_TRUE(classifier->resetDevice(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID).isOk()); EXPECT_TRUE(classifier->resetDevice(ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID).isOk()); EXPECT_TRUE(classifier->resetDevice(1).isOk()); @@ -115,14 +100,14 @@ TEST_F(InputClassifierHidlTest_1_0, ResetDevice) { /** * Call reset() on the HAL to ensure no fatal failure there. */ -TEST_F(InputClassifierHidlTest_1_0, ResetHal) { +TEST_P(InputClassifierHidlTest_1_0, ResetHal) { EXPECT_TRUE(classifier->reset().isOk()); } /** * Classify an event without any video frames. */ -TEST_F(InputClassifierHidlTest_1_0, Classify_NoVideoFrame) { +TEST_P(InputClassifierHidlTest_1_0, Classify_NoVideoFrame) { // Create a MotionEvent that does not have any video data MotionEvent event = getSimpleMotionEvent(); @@ -137,7 +122,7 @@ TEST_F(InputClassifierHidlTest_1_0, Classify_NoVideoFrame) { /** * Classify an event with one video frame. Should be the most common scenario. */ -TEST_F(InputClassifierHidlTest_1_0, Classify_OneVideoFrame) { +TEST_P(InputClassifierHidlTest_1_0, Classify_OneVideoFrame) { MotionEvent event = getSimpleMotionEvent(); VideoFrame frame; frame.data = {1, 2, 3, 4}; @@ -163,7 +148,7 @@ TEST_F(InputClassifierHidlTest_1_0, Classify_OneVideoFrame) { * monotonically increasing timestamps. Still, we provide consistent timestamps here since that * is the most realistic mode of operation. */ -TEST_F(InputClassifierHidlTest_1_0, Classify_TwoVideoFrames) { +TEST_P(InputClassifierHidlTest_1_0, Classify_TwoVideoFrames) { MotionEvent event = getSimpleMotionEvent(); VideoFrame frame1; frame1.data = {1, 2, 3, 4}; @@ -183,11 +168,7 @@ TEST_F(InputClassifierHidlTest_1_0, Classify_TwoVideoFrames) { classifier->reset(); } -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(InputClassifierHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - InputClassifierHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; -} +INSTANTIATE_TEST_SUITE_P( + PerInstance, InputClassifierHidlTest_1_0, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IInputClassifier::descriptor)), + android::hardware::PrintInstanceNameToString); From 8ea56db2af4d277c356c1292170ab44ca1436bd4 Mon Sep 17 00:00:00 2001 From: Nicholas Ambur Date: Mon, 30 Mar 2020 19:21:04 -0700 Subject: [PATCH 0778/1022] remove duplicate soundtrigger VTS tests SoundTrigger VTS tests were duplicated in minor version updates. This is not required and thus removed. Bug: 151281377 Test: atest VtsHalSoundtriggerV2_0TargetTest && atest VtsHalSoundtriggerV2_1TargetTest Change-Id: I60cfbe664cf7c38b2894d3e5f0df824737854c82 --- .../VtsHalSoundtriggerV2_1TargetTest.cpp | 165 ------------------ 1 file changed, 165 deletions(-) diff --git a/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp b/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp index 7f06ed9199..392679d0cb 100644 --- a/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp +++ b/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp @@ -171,61 +171,6 @@ class SoundTriggerHidlTest : public ::testing::TestWithParam { sp mCallback; }; -/** - * Test ISoundTriggerHw::getProperties() method - * - * Verifies that: - * - the implementation implements the method - * - the method returns 0 (no error) - * - the implementation supports at least one sound model and one key phrase - * - the implementation supports at least VOICE_TRIGGER recognition mode - */ -TEST_P(SoundTriggerHidlTest, GetProperties) { - ISoundTriggerHw::Properties halProperties; - Return hidlReturn; - int ret = -ENODEV; - - hidlReturn = mSoundTriggerHal->getProperties([&](int rc, auto res) { - ret = rc; - halProperties = res; - }); - - EXPECT_TRUE(hidlReturn.isOk()); - EXPECT_EQ(0, ret); - EXPECT_GT(halProperties.maxSoundModels, 0u); - EXPECT_GT(halProperties.maxKeyPhrases, 0u); - EXPECT_NE(0u, (halProperties.recognitionModes & (uint32_t)RecognitionMode::VOICE_TRIGGER)); -} - -/** - * Test ISoundTriggerHw::loadPhraseSoundModel() method - * - * Verifies that: - * - the implementation implements the method - * - the implementation returns an error when passed a malformed sound model - * - * There is no way to verify that implementation actually can load a sound model because each - * sound model is vendor specific. - */ -TEST_P(SoundTriggerHidlTest, LoadInvalidModelFail) { - Return hidlReturn; - int ret = -ENODEV; - V2_0_ISoundTriggerHw::PhraseSoundModel model; - SoundModelHandle handle; - - model.common.type = SoundModelType::UNKNOWN; - - hidlReturn = - mSoundTriggerHal->loadPhraseSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) { - ret = retval; - handle = res; - }); - - EXPECT_TRUE(hidlReturn.isOk()); - EXPECT_NE(0, ret); - EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD)); -} - /** * Test ISoundTriggerHw::loadPhraseSoundModel_2_1() method * @@ -279,34 +224,6 @@ TEST_P(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail) { EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD)); } -/** - * Test ISoundTriggerHw::loadSoundModel() method - * - * Verifies that: - * - the implementation returns error when passed a sound model with random data. - */ -TEST_P(SoundTriggerHidlTest, LoadGenericSoundModelFail) { - int ret = -ENODEV; - V2_0_ISoundTriggerHw::SoundModel model; - SoundModelHandle handle = 0; - - model.type = SoundModelType::GENERIC; - model.data.resize(100); - for (auto& d : model.data) { - d = rand(); - } - - Return loadReturn = - mSoundTriggerHal->loadSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) { - ret = retval; - handle = res; - }); - - EXPECT_TRUE(loadReturn.isOk()); - EXPECT_NE(0, ret); - EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD)); -} - /** * Test ISoundTriggerHw::loadSoundModel_2_1() method * @@ -370,54 +287,6 @@ TEST_P(SoundTriggerHidlTest, LoadGenericSoundModelFail_2_1) { EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD)); } -/** - * Test ISoundTriggerHw::unloadSoundModel() method - * - * Verifies that: - * - the implementation implements the method - * - the implementation returns an error when called without a valid loaded sound model - * - */ -TEST_P(SoundTriggerHidlTest, UnloadModelNoModelFail) { - Return hidlReturn(0); - SoundModelHandle halHandle = 0; - - hidlReturn = mSoundTriggerHal->unloadSoundModel(halHandle); - - EXPECT_TRUE(hidlReturn.isOk()); - EXPECT_NE(0, hidlReturn); -} - -/** - * Test ISoundTriggerHw::startRecognition() method - * - * Verifies that: - * - the implementation implements the method - * - the implementation returns an error when called without a valid loaded sound model - * - * There is no way to verify that implementation actually starts recognition because no model can - * be loaded. - */ -TEST_P(SoundTriggerHidlTest, StartRecognitionNoModelFail) { - Return hidlReturn(0); - SoundModelHandle handle = 0; - PhraseRecognitionExtra phrase; - V2_0_ISoundTriggerHw::RecognitionConfig config; - - config.captureHandle = 0; - config.captureDevice = AudioDevice::IN_BUILTIN_MIC; - phrase.id = 0; - phrase.recognitionModes = (uint32_t)RecognitionMode::VOICE_TRIGGER; - phrase.confidenceLevel = 0; - - config.phrases.setToExternal(&phrase, 1); - - hidlReturn = mSoundTriggerHal->startRecognition(handle, config, mCallback, 0); - - EXPECT_TRUE(hidlReturn.isOk()); - EXPECT_NE(0, hidlReturn); -} - /** * Test ISoundTriggerHw::startRecognition_2_1() method * @@ -448,40 +317,6 @@ TEST_P(SoundTriggerHidlTest, StartRecognitionNoModelFail_2_1) { EXPECT_NE(0, hidlReturn); } -/** - * Test ISoundTriggerHw::stopRecognition() method - * - * Verifies that: - * - the implementation implements the method - * - the implementation returns an error when called without an active recognition running - * - */ -TEST_P(SoundTriggerHidlTest, StopRecognitionNoAStartFail) { - Return hidlReturn(0); - SoundModelHandle handle = 0; - - hidlReturn = mSoundTriggerHal->stopRecognition(handle); - - EXPECT_TRUE(hidlReturn.isOk()); - EXPECT_NE(0, hidlReturn); -} - -/** - * Test ISoundTriggerHw::stopAllRecognitions() method - * - * Verifies that: - * - the implementation implements this optional method or indicates it is not supported by - * returning -ENOSYS - */ -TEST_P(SoundTriggerHidlTest, stopAllRecognitions) { - Return hidlReturn(0); - - hidlReturn = mSoundTriggerHal->stopAllRecognitions(); - - EXPECT_TRUE(hidlReturn.isOk()); - EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS); -} - INSTANTIATE_TEST_SUITE_P( PerInstance, SoundTriggerHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)), From 34de57d194a87a506c26b6054a05622a876e7099 Mon Sep 17 00:00:00 2001 From: Nicholas Ambur Date: Fri, 27 Mar 2020 10:57:44 -0700 Subject: [PATCH 0779/1022] remove stopAllRecognitions VTS test The stopAllRecognitions API is not used at the layers above the HAL, and it requires the HAL to own the state of all active recognitions. This API causes discontinuity with the upper layers also maintaining state information. The VTS requirement is being removed. Bug: 151281377 Test: atest VtsHalSoundtriggerV2_0TargetTest && atest VtsHalSoundtriggerV2_1TargetTest Change-Id: If14ed8177e0ff2730d2ed78ba8fbbbd058c4d57a --- .../VtsHalSoundtriggerV2_0TargetTest.cpp | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp index d7a7d08728..63edec570a 100644 --- a/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp +++ b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp @@ -293,22 +293,6 @@ TEST_P(SoundTriggerHidlTest, StopRecognitionNoAStartFail) { EXPECT_NE(0, hidlReturn); } -/** - * Test ISoundTriggerHw::stopAllRecognitions() method - * - * Verifies that: - * - the implementation implements this optional method or indicates it is not support by - * returning -ENOSYS - */ -TEST_P(SoundTriggerHidlTest, stopAllRecognitions) { - Return hidlReturn(0); - - hidlReturn = mSoundTriggerHal->stopAllRecognitions(); - - EXPECT_TRUE(hidlReturn.isOk()); - EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS); -} - INSTANTIATE_TEST_SUITE_P( PerInstance, SoundTriggerHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)), From b35f7d88c4bcb979c2fb11a1bb9fd6d48a814356 Mon Sep 17 00:00:00 2001 From: Huihong Luo Date: Thu, 6 Feb 2020 18:39:56 -0800 Subject: [PATCH 0780/1022] Don't send brightness to car service inside Emulator This fixes this cts test: android.cts.statsd.atom.UidAtomTests#testScreenBrightness Bug: 139959479 Test: atest android.cts.statsd.atom.UidAtomTests#testScreenBrightness Change-Id: I66f858ce7686a90cd395f4e646133e8ea4604be4 (cherry picked from commit 1322465c48d0c3dfa5953573b80a89460b8e7e95) (cherry picked from commit 5d463fdaaa02189d500f189fe1e9401c07a42046) --- .../impl/vhal_v2_0/EmulatedVehicleHal.cpp | 24 ++++++++++++++++++- .../impl/vhal_v2_0/EmulatedVehicleHal.h | 1 + 2 files changed, 24 insertions(+), 1 deletion(-) 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 a983c7117d..84354c15f8 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 @@ -15,8 +15,9 @@ */ #define LOG_TAG "DefaultVehicleHal_v2_0" -#include #include +#include +#include #include "EmulatedVehicleHal.h" #include "JsonFakeValueGenerator.h" @@ -188,6 +189,14 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { return StatusCode::NOT_AVAILABLE; } + if (mInEmulator && propValue.prop == toInt(VehicleProperty::DISPLAY_BRIGHTNESS)) { + // Emulator does not support remote brightness control, b/139959479 + // do not send it down so that it does not bring unnecessary property change event + // return other error code, such NOT_AVAILABLE, causes Emulator to be freezing + // TODO: return StatusCode::NOT_AVAILABLE once the above issue is fixed + return StatusCode::OK; + } + /** * After checking all conditions, such as the property is available, a real vhal will * sent the events to Car ECU to take actions. @@ -213,6 +222,17 @@ static bool isDiagnosticProperty(VehiclePropConfig propConfig) { return false; } +// determine if it's running inside Android Emulator +static bool isInEmulator() { + char propValue[PROP_VALUE_MAX]; + bool isEmulator = (__system_property_get("ro.kernel.qemu", propValue) != 0); + if (!isEmulator) { + isEmulator = (__system_property_get("ro.hardware", propValue) != 0) && + (!strcmp(propValue, "ranchu") || !strcmp(propValue, "goldfish")); + } + return isEmulator; +} + // Parse supported properties list and generate vector of property values to hold current values. void EmulatedVehicleHal::onCreate() { static constexpr bool shouldUpdateStatus = true; @@ -263,6 +283,8 @@ void EmulatedVehicleHal::onCreate() { } initObd2LiveFrame(*mPropStore->getConfigOrDie(OBD2_LIVE_FRAME)); initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME)); + mInEmulator = isInEmulator(); + ALOGD("mInEmulator=%s", mInEmulator ? "true" : "false"); } std::vector EmulatedVehicleHal::listProperties() { diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h index ebf19951b3..dc05145cd7 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h @@ -86,6 +86,7 @@ private: std::unordered_set mHvacPowerProps; RecurrentTimer mRecurrentTimer; VehicleHalClient* mVehicleClient; + bool mInEmulator; }; } // impl From 86b285465f245ffc9e109153c9b6c695063aceba Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Tue, 31 Mar 2020 00:13:36 -0700 Subject: [PATCH 0781/1022] Remove dependency on VtsHalHidlTargetTestEnvBase Bug: 143892896 Test: atest VtsHalWifiApV1_0TargetTest \ VtsHalWifiNanV1_0TargetTest \ VtsHalWifiV1_0TargetTest \ VtsHalWifiV1_1TargetTest \ VtsHalWifiV1_2TargetTest \ VtsHalWifiNanV1_2TargetTest \ VtsHalWifiV1_3TargetTest \ VtsHalWifiApV1_4TargetTest \ VtsHalWifiHostapdV1_0TargetTest \ VtsHalWifiHostapdV1_1TargetTest \ VtsHalWifiHostapdV1_2TargetTest \ VtsHalWifiSupplicantV1_0TargetTest \ VtsHalWifiSupplicantP2pV1_0TargetTest \ VtsHalWifiSupplicantV1_1TargetTest \ VtsHalWifiSupplicantV1_2TargetTest \ VtsHalWifiSupplicantP2pV1_2TargetTest Change-Id: I8a18f18f3aaa497642f380fea43517ec14554993 --- wifi/1.0/vts/functional/Android.bp | 3 - .../functional/VtsHalWifiV1_0TargetTest.cpp | 21 ------- .../vts/functional/wifi_chip_hidl_test.cpp | 2 - .../vts/functional/wifi_hidl_test_utils.cpp | 19 +----- .../1.0/vts/functional/wifi_hidl_test_utils.h | 23 ++----- wifi/1.1/vts/functional/Android.bp | 1 - .../functional/VtsHalWifiV1_1TargetTest.cpp | 21 ------- wifi/1.2/vts/functional/Android.bp | 2 - .../functional/VtsHalWifiV1_2TargetTest.cpp | 21 ------- wifi/1.3/vts/functional/Android.bp | 1 - .../functional/VtsHalWifiV1_3TargetTest.cpp | 21 ------- wifi/1.4/vts/functional/Android.bp | 1 - .../functional/VtsHalWifiV1_4TargetTest.cpp | 21 ------- .../functional/wifi_ap_iface_hidl_test.cpp | 2 - wifi/hostapd/1.0/vts/functional/Android.bp | 1 - .../VtsHalWifiHostapdV1_0TargetTest.cpp | 21 ------- wifi/hostapd/1.1/vts/functional/Android.bp | 1 - .../VtsHalWifiHostapdV1_1TargetTest.cpp | 21 ------- wifi/hostapd/1.2/vts/functional/Android.bp | 1 - .../VtsHalWifiHostapdV1_2TargetTest.cpp | 21 ------- wifi/supplicant/1.0/vts/functional/Android.bp | 1 - .../VtsHalWifiSupplicantP2pV1_0TargetTest.cpp | 4 -- .../VtsHalWifiSupplicantV1_0TargetTest.cpp | 21 ------- .../functional/supplicant_hidl_test_utils.cpp | 44 -------------- .../functional/supplicant_hidl_test_utils.h | 60 ------------------- wifi/supplicant/1.1/vts/functional/Android.bp | 1 - .../VtsHalWifiSupplicantV1_1TargetTest.cpp | 21 ------- wifi/supplicant/1.2/vts/functional/Android.bp | 2 - .../VtsHalWifiSupplicantP2pV1_2TargetTest.cpp | 4 -- .../VtsHalWifiSupplicantV1_2TargetTest.cpp | 21 ------- wifi/supplicant/1.3/vts/functional/Android.bp | 1 - .../VtsHalWifiSupplicantV1_3TargetTest.cpp | 21 ------- 32 files changed, 8 insertions(+), 418 deletions(-) delete mode 100644 wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp delete mode 100644 wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp delete mode 100644 wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp delete mode 100644 wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp delete mode 100644 wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp delete mode 100644 wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp delete mode 100644 wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.cpp delete mode 100644 wifi/hostapd/1.2/vts/functional/VtsHalWifiHostapdV1_2TargetTest.cpp delete mode 100644 wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp delete mode 100644 wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp delete mode 100644 wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp delete mode 100644 wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp index bf77503c93..2242510933 100644 --- a/wifi/1.0/vts/functional/Android.bp +++ b/wifi/1.0/vts/functional/Android.bp @@ -38,7 +38,6 @@ cc_test { name: "VtsHalWifiV1_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiV1_0TargetTest.cpp", "wifi_chip_hidl_test.cpp", "wifi_p2p_iface_hidl_test.cpp", "wifi_rtt_controller_hidl_test.cpp", @@ -61,7 +60,6 @@ cc_test { name: "VtsHalWifiNanV1_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiV1_0TargetTest.cpp", "wifi_chip_hidl_nan_test.cpp", "wifi_nan_iface_hidl_test.cpp", ], @@ -79,7 +77,6 @@ cc_test { name: "VtsHalWifiApV1_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiV1_0TargetTest.cpp", "wifi_ap_iface_hidl_test.cpp", "wifi_chip_hidl_ap_test.cpp", ], diff --git a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp deleted file mode 100644 index 128dae5a87..0000000000 --- a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2016 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 - -// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is -// updated. -::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr; \ No newline at end of file diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp index 2ea8841170..53131cee78 100644 --- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp @@ -44,8 +44,6 @@ using ::android::hardware::wifi::V1_0::WifiDebugRingBufferVerboseLevel; using ::android::hardware::wifi::V1_0::WifiStatus; using ::android::hardware::wifi::V1_0::WifiStatusCode; -extern WifiHidlEnvironment* gEnv; - namespace { constexpr WifiDebugRingBufferVerboseLevel kDebugRingBufferVerboseLvl = WifiDebugRingBufferVerboseLevel::VERBOSE; diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp index 26e4821984..c1542dcb59 100644 --- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp +++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp @@ -41,8 +41,6 @@ using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::wifi_system::InterfaceTool; -extern WifiHidlEnvironment* gEnv; - namespace { constexpr uint32_t kHalStartRetryMaxCount = 5; constexpr uint32_t kHalStartRetryIntervalInMs = 2; @@ -93,21 +91,8 @@ bool configureChipToSupportIfaceTypeInternal(const sp& wifi_chip, } } // namespace -sp getWifi(const std::string& instance_name) { - if ((!gEnv && instance_name.empty()) || (gEnv && !instance_name.empty())) { - ALOGE("instance_name and gEnv must have one and only one set."); - return nullptr; - } - if (gEnv) { - return ::testing::VtsHalHidlTargetTestBase::getService( - gEnv->getServiceName()); - } else { - return IWifi::getService(instance_name); - } -} - sp getWifiChip(const std::string& instance_name) { - sp wifi = getWifi(instance_name); + sp wifi = IWifi::getService(instance_name); if (!wifi.get()) { return nullptr; } @@ -217,7 +202,7 @@ bool configureChipToSupportIfaceType(const sp& wifi_chip, } void stopWifi(const std::string& instance_name) { - sp wifi = getWifi(instance_name); + sp wifi = IWifi::getService(instance_name); ASSERT_NE(wifi, nullptr); HIDL_INVOKE(wifi, stop); } diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h index 866013417f..d22ed77cd9 100644 --- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h +++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h @@ -31,19 +31,16 @@ // Note: We only have a single instance of each of these objects currently. // These helper functions should be modified to return vectors if we support // multiple instances. -// TODO(b/143892896): Remove the default value as part of the cleanup. -android::sp getWifi( - const std::string& instance_name = ""); android::sp getWifiChip( - const std::string& instance_name = ""); + const std::string& instance_name); android::sp getWifiApIface( - const std::string& instance_name = ""); + const std::string& instance_name); android::sp getWifiNanIface( - const std::string& instance_name = ""); + const std::string& instance_name); android::sp getWifiP2pIface( - const std::string& instance_name = ""); + const std::string& instance_name); android::sp getWifiStaIface( - const std::string& instance_name = ""); + const std::string& instance_name); // Configure the chip in a mode to support the creation of the provided // iface type. bool configureChipToSupportIfaceType( @@ -51,12 +48,4 @@ bool configureChipToSupportIfaceType( android::hardware::wifi::V1_0::IfaceType type, android::hardware::wifi::V1_0::ChipModeId* configured_mode_id); // Used to trigger IWifi.stop() at the end of every test. -void stopWifi(const std::string& instance_name = ""); - -class WifiHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - protected: - virtual void HidlSetUp() override { - stopWifi(); - sleep(5); - } -}; +void stopWifi(const std::string& instance_name); diff --git a/wifi/1.1/vts/functional/Android.bp b/wifi/1.1/vts/functional/Android.bp index 775031e683..d34ae222d9 100644 --- a/wifi/1.1/vts/functional/Android.bp +++ b/wifi/1.1/vts/functional/Android.bp @@ -18,7 +18,6 @@ cc_test { name: "VtsHalWifiV1_1TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiV1_1TargetTest.cpp", "wifi_chip_hidl_test.cpp"], static_libs: [ "VtsHalWifiV1_0TargetTestUtil", diff --git a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp deleted file mode 100644 index 4b62b15699..0000000000 --- a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2016 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 - -// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is -// updated. -::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr; diff --git a/wifi/1.2/vts/functional/Android.bp b/wifi/1.2/vts/functional/Android.bp index f43e49ef12..d3de5cfc67 100644 --- a/wifi/1.2/vts/functional/Android.bp +++ b/wifi/1.2/vts/functional/Android.bp @@ -18,7 +18,6 @@ cc_test { name: "VtsHalWifiV1_2TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiV1_2TargetTest.cpp", "wifi_chip_hidl_test.cpp", "wifi_sta_iface_hidl_test.cpp", ], @@ -38,7 +37,6 @@ cc_test { name: "VtsHalWifiNanV1_2TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiV1_2TargetTest.cpp", "wifi_nan_iface_hidl_test.cpp", ], static_libs: [ diff --git a/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp b/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp deleted file mode 100644 index 52c7a4ad0d..0000000000 --- a/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2018 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 - -// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is -// updated. -::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr; \ No newline at end of file diff --git a/wifi/1.3/vts/functional/Android.bp b/wifi/1.3/vts/functional/Android.bp index fe9c791ec8..457de2973a 100644 --- a/wifi/1.3/vts/functional/Android.bp +++ b/wifi/1.3/vts/functional/Android.bp @@ -18,7 +18,6 @@ cc_test { name: "VtsHalWifiV1_3TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiV1_3TargetTest.cpp", "wifi_chip_hidl_test.cpp", "wifi_sta_iface_hidl_test.cpp", ], diff --git a/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp b/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp deleted file mode 100644 index 52c7a4ad0d..0000000000 --- a/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2018 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 - -// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is -// updated. -::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr; \ No newline at end of file diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp index d857be10ed..7e74cbd5de 100644 --- a/wifi/1.4/vts/functional/Android.bp +++ b/wifi/1.4/vts/functional/Android.bp @@ -19,7 +19,6 @@ cc_test { name: "VtsHalWifiApV1_4TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiV1_4TargetTest.cpp", "wifi_ap_iface_hidl_test.cpp", "wifi_chip_hidl_test.cpp", "wifi_nan_iface_hidl_test.cpp", diff --git a/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp b/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp deleted file mode 100644 index 7e0f3cdc47..0000000000 --- a/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - */ - -#include - -// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is -// updated. -::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr; \ No newline at end of file diff --git a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp index 3507d3074a..aff0ef741f 100644 --- a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp +++ b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp @@ -30,8 +30,6 @@ using ::android::hardware::wifi::V1_0::WifiStatusCode; using ::android::hardware::wifi::V1_4::IWifi; using ::android::hardware::wifi::V1_4::IWifiApIface; -extern WifiHidlEnvironment* gEnv; - /** * Fixture to use for all STA Iface HIDL interface tests. */ diff --git a/wifi/hostapd/1.0/vts/functional/Android.bp b/wifi/hostapd/1.0/vts/functional/Android.bp index b53d002680..e966d7e817 100644 --- a/wifi/hostapd/1.0/vts/functional/Android.bp +++ b/wifi/hostapd/1.0/vts/functional/Android.bp @@ -36,7 +36,6 @@ cc_test { name: "VtsHalWifiHostapdV1_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiHostapdV1_0TargetTest.cpp", "hostapd_hidl_test.cpp", ], static_libs: [ diff --git a/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp b/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp deleted file mode 100644 index 4b62b15699..0000000000 --- a/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2016 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 - -// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is -// updated. -::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr; diff --git a/wifi/hostapd/1.1/vts/functional/Android.bp b/wifi/hostapd/1.1/vts/functional/Android.bp index c963fe33a3..8670f2fe97 100644 --- a/wifi/hostapd/1.1/vts/functional/Android.bp +++ b/wifi/hostapd/1.1/vts/functional/Android.bp @@ -18,7 +18,6 @@ cc_test { name: "VtsHalWifiHostapdV1_1TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiHostapdV1_1TargetTest.cpp", "hostapd_hidl_test.cpp", ], static_libs: [ diff --git a/wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.cpp b/wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.cpp deleted file mode 100644 index 7e0f3cdc47..0000000000 --- a/wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - */ - -#include - -// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is -// updated. -::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr; \ No newline at end of file diff --git a/wifi/hostapd/1.2/vts/functional/Android.bp b/wifi/hostapd/1.2/vts/functional/Android.bp index 50cfdee612..4f4a741bf3 100644 --- a/wifi/hostapd/1.2/vts/functional/Android.bp +++ b/wifi/hostapd/1.2/vts/functional/Android.bp @@ -18,7 +18,6 @@ cc_test { name: "VtsHalWifiHostapdV1_2TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiHostapdV1_2TargetTest.cpp", "hostapd_hidl_test.cpp", ], static_libs: [ diff --git a/wifi/hostapd/1.2/vts/functional/VtsHalWifiHostapdV1_2TargetTest.cpp b/wifi/hostapd/1.2/vts/functional/VtsHalWifiHostapdV1_2TargetTest.cpp deleted file mode 100644 index 7e0f3cdc47..0000000000 --- a/wifi/hostapd/1.2/vts/functional/VtsHalWifiHostapdV1_2TargetTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - */ - -#include - -// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is -// updated. -::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr; \ No newline at end of file diff --git a/wifi/supplicant/1.0/vts/functional/Android.bp b/wifi/supplicant/1.0/vts/functional/Android.bp index 80139060f1..a05cc6bfa8 100644 --- a/wifi/supplicant/1.0/vts/functional/Android.bp +++ b/wifi/supplicant/1.0/vts/functional/Android.bp @@ -36,7 +36,6 @@ cc_test { name: "VtsHalWifiSupplicantV1_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiSupplicantV1_0TargetTest.cpp", "supplicant_hidl_test.cpp", "supplicant_sta_iface_hidl_test.cpp", "supplicant_sta_network_hidl_test.cpp", diff --git a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp index a1327071bc..01840e27cf 100644 --- a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp +++ b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp @@ -17,10 +17,6 @@ #include #include "supplicant_hidl_test_utils.h" -// TODO(b/143892896): Remove this line after wifi_hidl_test_utils.cpp is -// updated. -WifiSupplicantHidlEnvironment* gEnv = nullptr; - int main(int argc, char** argv) { if (!::testing::deviceSupportsFeature("android.hardware.wifi.direct")) return 0; diff --git a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp deleted file mode 100644 index f582cc1ff6..0000000000 --- a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2016 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 "supplicant_hidl_test_utils.h" - -// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is -// updated. -WifiSupplicantHidlEnvironment* gEnv = nullptr; diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp index d0df4a42a1..6fe6fc5936 100644 --- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp +++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp @@ -50,8 +50,6 @@ using ::android::hidl::manager::V1_0::IServiceNotification; using ::android::wifi_system::InterfaceTool; using ::android::wifi_system::SupplicantManager; -extern WifiSupplicantHidlEnvironment* gEnv; - namespace { // Helper function to initialize the driver and firmware to STA mode @@ -176,12 +174,6 @@ void stopSupplicant(const std::string& wifi_instance_name) { ASSERT_FALSE(supplicant_manager.IsSupplicantRunning()); } -// TODO(b/143892896): Remove old APIs after all supplicant tests are updated. -void startSupplicantAndWaitForHidlService() { - startSupplicantAndWaitForHidlService("", - gEnv->getServiceName()); -} - void startSupplicantAndWaitForHidlService( const std::string& wifi_instance_name, const std::string& supplicant_instance_name) { @@ -240,21 +232,6 @@ void addSupplicantP2pIface_1_1(const sp& supplicant) { }); } -// TODO(b/143892896): Remove old APIs after all supplicant tests are updated. -sp getSupplicant() { - sp supplicant = - ::testing::VtsHalHidlTargetTestBase::getService( - gEnv->getServiceName()); - // For 1.1 supplicant, we need to add interfaces at initialization. - if (is_1_1(supplicant)) { - addSupplicantStaIface_1_1(supplicant); - if (gEnv->isP2pOn) { - addSupplicantP2pIface_1_1(supplicant); - } - } - return supplicant; -} - sp getSupplicant(const std::string& supplicant_instance_name, bool isP2pOn) { sp supplicant = @@ -269,12 +246,6 @@ sp getSupplicant(const std::string& supplicant_instance_name, return supplicant; } -// TODO(b/143892896): Remove old APIs after all supplicant tests are updated. -sp getSupplicantStaIface() { - sp supplicant = getSupplicant(); - return getSupplicantStaIface(supplicant); -} - sp getSupplicantStaIface( const sp& supplicant) { if (!supplicant.get()) { @@ -300,11 +271,6 @@ sp getSupplicantStaIface( return sta_iface; } -// TODO(b/143892896): Remove old APIs after all supplicant tests are updated. -sp createSupplicantStaNetwork() { - return createSupplicantStaNetwork(getSupplicant()); -} - sp createSupplicantStaNetwork( const sp& supplicant) { sp sta_iface = getSupplicantStaIface(supplicant); @@ -327,11 +293,6 @@ sp createSupplicantStaNetwork( return sta_network; } -// TODO(b/143892896): Remove old APIs after all supplicant tests are updated. -sp getSupplicantP2pIface() { - return getSupplicantP2pIface(getSupplicant()); -} - sp getSupplicantP2pIface( const sp& supplicant) { if (!supplicant.get()) { @@ -357,11 +318,6 @@ sp getSupplicantP2pIface( return p2p_iface; } -// TODO(b/143892896): Remove old APIs after all supplicant tests are updated. -bool turnOnExcessiveLogging() { - return turnOnExcessiveLogging(getSupplicant()); -} - bool turnOnExcessiveLogging(const sp& supplicant) { if (!supplicant.get()) { return false; diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h index 40ad695152..1ccf0919aa 100644 --- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h +++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h @@ -28,12 +28,9 @@ #include "wifi_hidl_test_utils.h" // Used to stop the android wifi framework before every test. -void stopWifiFramework(); void stopWifiFramework(const std::string& wifi_instance_name); -void startWifiFramework(); void startWifiFramework(const std::string& wifi_instance_name); -void stopSupplicant(); void stopSupplicant(const std::string& wifi_instance_name); // Used to configure the chip, driver and start wpa_supplicant before every // test. @@ -63,63 +60,6 @@ bool turnOnExcessiveLogging( const android::sp& supplicant); -// TODO(b/143892896): Remove old APIs after all supplicant tests are updated. -void startSupplicantAndWaitForHidlService(); -android::sp -getSupplicant(); -android::sp -getSupplicantStaIface(); -android::sp -createSupplicantStaNetwork(); -android::sp -getSupplicantP2pIface(); - bool turnOnExcessiveLogging(); -class WifiSupplicantHidlEnvironment - : public ::testing::VtsHalHidlTargetTestEnvBase { - protected: - virtual void HidlSetUp() override { stopSupplicant(); } - virtual void HidlTearDown() override { - startSupplicantAndWaitForHidlService(); - } - - public: - // Whether P2P feature is supported on the device. - bool isP2pOn = true; - - void usage(char* me, char* arg) { - fprintf(stderr, - "unrecognized option: %s\n\n" - "usage: %s \n\n" - "test options are:\n\n" - "-P, --p2p_on: Whether P2P feature is supported\n", - arg, me); - } - - int initFromOptions(int argc, char** argv) { - static struct option options[] = {{"p2p_off", no_argument, 0, 'P'}, - {0, 0, 0, 0}}; - - int c; - while ((c = getopt_long(argc, argv, "P", options, NULL)) >= 0) { - switch (c) { - case 'P': - isP2pOn = false; - break; - default: - usage(argv[0], argv[optind]); - return 2; - } - } - - if (optind < argc) { - usage(argv[0], argv[optind]); - return 2; - } - - return 0; - } -}; - #endif /* SUPPLICANT_HIDL_TEST_UTILS_H */ diff --git a/wifi/supplicant/1.1/vts/functional/Android.bp b/wifi/supplicant/1.1/vts/functional/Android.bp index 6bcfa8ab5f..90a3e872fb 100644 --- a/wifi/supplicant/1.1/vts/functional/Android.bp +++ b/wifi/supplicant/1.1/vts/functional/Android.bp @@ -37,7 +37,6 @@ cc_test { name: "VtsHalWifiSupplicantV1_1TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiSupplicantV1_1TargetTest.cpp", "supplicant_hidl_test.cpp", "supplicant_sta_iface_hidl_test.cpp", "supplicant_sta_network_hidl_test.cpp", diff --git a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp b/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp deleted file mode 100644 index f582cc1ff6..0000000000 --- a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2016 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 "supplicant_hidl_test_utils.h" - -// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is -// updated. -WifiSupplicantHidlEnvironment* gEnv = nullptr; diff --git a/wifi/supplicant/1.2/vts/functional/Android.bp b/wifi/supplicant/1.2/vts/functional/Android.bp index 22dec84123..80f3658edd 100644 --- a/wifi/supplicant/1.2/vts/functional/Android.bp +++ b/wifi/supplicant/1.2/vts/functional/Android.bp @@ -39,7 +39,6 @@ cc_test { name: "VtsHalWifiSupplicantV1_2TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiSupplicantV1_2TargetTest.cpp", "supplicant_sta_iface_hidl_test.cpp", "supplicant_sta_network_hidl_test.cpp", ], @@ -68,7 +67,6 @@ cc_test { name: "VtsHalWifiSupplicantP2pV1_2TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiSupplicantP2pV1_2TargetTest.cpp", "supplicant_p2p_iface_hidl_test.cpp", ], static_libs: [ diff --git a/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantP2pV1_2TargetTest.cpp b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantP2pV1_2TargetTest.cpp index 22bf1db45c..7edec475d7 100644 --- a/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantP2pV1_2TargetTest.cpp +++ b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantP2pV1_2TargetTest.cpp @@ -17,10 +17,6 @@ #include #include "supplicant_hidl_test_utils.h" -// TODO(b/143892896): Remove this line after wifi_hidl_test_utils.cpp is -// updated. -WifiSupplicantHidlEnvironment* gEnv = nullptr; - int main(int argc, char** argv) { if (!::testing::deviceSupportsFeature("android.hardware.wifi.direct")) return 0; diff --git a/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp deleted file mode 100644 index 9dbeee104f..0000000000 --- a/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - */ - -#include "supplicant_hidl_test_utils.h" - -// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is -// updated. -WifiSupplicantHidlEnvironment* gEnv = nullptr; diff --git a/wifi/supplicant/1.3/vts/functional/Android.bp b/wifi/supplicant/1.3/vts/functional/Android.bp index 3dabe7cd93..00a0bf7ee1 100644 --- a/wifi/supplicant/1.3/vts/functional/Android.bp +++ b/wifi/supplicant/1.3/vts/functional/Android.bp @@ -41,7 +41,6 @@ cc_test { name: "VtsHalWifiSupplicantV1_3TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalWifiSupplicantV1_3TargetTest.cpp", "supplicant_sta_iface_hidl_test.cpp", "supplicant_sta_network_hidl_test.cpp", ], diff --git a/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp b/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp deleted file mode 100644 index 9dbeee104f..0000000000 --- a/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - */ - -#include "supplicant_hidl_test_utils.h" - -// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is -// updated. -WifiSupplicantHidlEnvironment* gEnv = nullptr; From 2229623f1fb38706f7d52d28bd43f8553ad4203a Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Mon, 30 Mar 2020 15:40:12 -0700 Subject: [PATCH 0782/1022] Relax constraints on getting PlaneLayouts PlaneLayouts may only be known at allocation time. Bug: 152806713 Test: build, boot Change-Id: Ic878943b405469a70a685a895c04a1d4e2678686 --- .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 6cc5e34326..8b68e1b733 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -1855,13 +1855,15 @@ TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoChromaSiting) { */ TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPlaneLayouts) { hidl_vec vec; - ASSERT_EQ(Error::NONE, - mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, - gralloc4::MetadataType_PlaneLayouts, &vec)); - - std::vector planeLayouts; - ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts)); - ASSERT_NO_FATAL_FAILURE(verifyDummyDescriptorInfoPlaneLayouts(planeLayouts)); + const auto ret = mGralloc->getFromBufferDescriptorInfo( + mDummyDescriptorInfo, gralloc4::MetadataType_PlaneLayouts, &vec); + if (ret == Error::NONE) { + std::vector planeLayouts; + ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts)); + ASSERT_NO_FATAL_FAILURE(verifyDummyDescriptorInfoPlaneLayouts(planeLayouts)); + } else { + ASSERT_EQ(Error::UNSUPPORTED, ret); + } } /** From 3e69744f0f24c6c455fddbdcb160bdb1ee773050 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Fri, 27 Mar 2020 14:19:46 -0700 Subject: [PATCH 0783/1022] User allocated EVS camera capture buffers This change introduces a new API to import frame capture buffers allocated by the clients. Bug: 152493110 Test: m -j and run /system/bin/evs_app --test --extmem Change-Id: I679c61719e4d0e3a7d0c41110afe66e0a4ccb305 --- automotive/evs/1.1/IEvsCamera.hal | 18 ++++++++++++++++++ automotive/evs/1.1/default/EvsCamera.cpp | 8 ++++++++ automotive/evs/1.1/default/EvsCamera.h | 2 ++ automotive/evs/1.1/types.hal | 3 +++ current.txt | 4 ++-- 5 files changed, 33 insertions(+), 2 deletions(-) diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal index 38e6c4242c..3e7ac2b299 100644 --- a/automotive/evs/1.1/IEvsCamera.hal +++ b/automotive/evs/1.1/IEvsCamera.hal @@ -215,4 +215,22 @@ interface IEvsCamera extends @1.0::IEvsCamera { */ setExtendedInfo_1_1(uint32_t opaqueIdentifier, vec opaqueValue) generates (EvsResult result); + + /** + * Import external buffers to capture frames + * + * This API must be called with a physical camera device identifier. + * + * @param buffers A list of buffers allocated by the caller. EvsCamera + * will use these buffers to capture frames, in addition to + * other buffers already in its buffer pool. + * @return result EvsResult::OK if it succeeds to import buffers. + * EvsResult::UNDERLYING_SERVICE_ERROR if this is called + * for logical camera devices or EVS fails to import + * buffers. + * delta The amount of buffer pool size changes after importing + * given buffers. + */ + importExternalBuffers(vec buffers) + generates (EvsResult result, int32_t delta); }; diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp index 5196c9532b..0e69ed408b 100644 --- a/automotive/evs/1.1/default/EvsCamera.cpp +++ b/automotive/evs/1.1/default/EvsCamera.cpp @@ -354,6 +354,14 @@ Return EvsCamera::getExtendedInfo_1_1(uint32_t opaqueIdentifier, } +Return +EvsCamera::importExternalBuffers(const hidl_vec& /* buffers */, + importExternalBuffers_cb _hidl_cb) { + ALOGW("%s is not implemented yet.", __FUNCTION__); + _hidl_cb(EvsResult::UNDERLYING_SERVICE_ERROR, 0); + return {}; +} + bool EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) { if (bufferCount < 1) { diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h index 0fa83b428d..6163a34e08 100644 --- a/automotive/evs/1.1/default/EvsCamera.h +++ b/automotive/evs/1.1/default/EvsCamera.h @@ -82,6 +82,8 @@ public: const hidl_vec& opaqueValue) override; Return getExtendedInfo_1_1(uint32_t opaqueIdentifier, getExtendedInfo_1_1_cb _hidl_cb) override; + Return importExternalBuffers(const hidl_vec& buffers, + importExternalBuffers_cb _hidl_cb) override; static sp Create(const char *deviceName); static sp Create(const char *deviceName, diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal index b34e7e7d65..1f69f09b5b 100644 --- a/automotive/evs/1.1/types.hal +++ b/automotive/evs/1.1/types.hal @@ -70,6 +70,9 @@ struct BufferDesc { */ int64_t timestamp; + /** + * Frame metadata. This is opaque to EVS manager. + */ vec metadata; }; diff --git a/current.txt b/current.txt index 183d00637b..3a6946535d 100644 --- a/current.txt +++ b/current.txt @@ -642,13 +642,13 @@ d06fc14b325beeef06bd39de8f178f490d9e9095255626866071aab42be1fc40 android.hardwar 07e387bd8bc0e4df5f372515ed960a0b1ae74ea7231d4490a0bb09b07046e4f1 android.hardware.automotive.can@1.0::ICanMessageListener 2166132d6c247630a193217b4338074f634d6691b1ed6796cb26b3812e90b46e android.hardware.automotive.can@1.0::ICloseHandle 83355471a3b6d7f777d3f129714585ffb77d9b6f8a3d0365741969631efb81b2 android.hardware.automotive.can@1.0::types -8afd93d525cf17818e3d46e72f30debeaacc6fb166a59a8e25272f2baeb0ef7a android.hardware.automotive.evs@1.1::IEvsCamera +50bfbeef15d7451bd07e4ad460fbcb7ff80521b89bb8049035c0d458b4125ae4 android.hardware.automotive.evs@1.1::IEvsCamera 89ff5ab18b3069f21a57f559b290caa50670f0ae1b74178f630183aef39b496b android.hardware.automotive.evs@1.1::IEvsCameraStream 4c67f768067a0aceac74381f6f62e778ab3b6a18f47db3c9b98c58190ef5619d android.hardware.automotive.evs@1.1::IEvsDisplay 87958d728d7c0ee9b9391ab4a072b097914921a7b38f7dc3df427f933a5b528e android.hardware.automotive.evs@1.1::IEvsEnumerator f53b4e8de6209c6d0fa9036005671b34a2f98328b51423d3a5137a43bf42c84d android.hardware.automotive.evs@1.1::IEvsUltrasonicsArray 0460bacbde906a846a3d71b2b7b33d6927cac3ff072e523ffac7853577464406 android.hardware.automotive.evs@1.1::IEvsUltrasonicsArrayStream -8a156203892de3cfa47baaccabef3c45b3315cae93b332357598d60896b1ac7f android.hardware.automotive.evs@1.1::types +3e374b5c4777f959f62a320abb3b9edca8874e24e383dbb19c66d224f151b363 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 From 872ffc262f71596abdfe0d1bdf32ac6195ca0e61 Mon Sep 17 00:00:00 2001 From: Shuo Qian Date: Tue, 31 Mar 2020 15:35:57 -0700 Subject: [PATCH 0784/1022] Starting from Android 11, VTS will use "DISABLE_" prefix to disable tests instead of the .xml file. We need to migrate these things. Test: Treehugger; GoogleTest knowledge; VTS team confirmation Bug: 152813990 Change-Id: I92616557ae44c2a421ee687d0420f7b7901ba5a9 --- radio/1.0/vts/functional/radio_hidl_hal_icc.cpp | 4 +++- radio/1.0/vts/functional/radio_hidl_hal_misc.cpp | 8 ++++++-- radio/1.2/vts/functional/radio_hidl_hal_api.cpp | 8 ++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) 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 60cb2fecda..9568524f4f 100644 --- a/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp +++ b/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp @@ -177,9 +177,11 @@ TEST_P(RadioHidlTest, changeIccPin2ForApp) { } /* + * The following test is disabled due to b/109889468 + * * Test IRadio.getImsiForApp() for the response returned. */ -TEST_P(RadioHidlTest, getImsiForApp) { +TEST_P(RadioHidlTest, DISABLED_getImsiForApp) { serial = GetRandomSerialNumber(); // Check success returned while getting imsi for 3GPP and 3GPP2 apps only 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 9b6cc96cf0..7228fb086b 100644 --- a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp +++ b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp @@ -629,9 +629,11 @@ TEST_P(RadioHidlTest, getHardwareConfig) { } /* + * The following test is disabled due to b/64734869 + * * Test IRadio.requestShutdown() for the response returned. */ -TEST_P(RadioHidlTest, requestShutdown) { +TEST_P(RadioHidlTest, DISABLED_requestShutdown) { serial = GetRandomSerialNumber(); radio->requestShutdown(serial); @@ -756,9 +758,11 @@ TEST_P(RadioHidlTest, getModemActivityInfo) { } /* + * The following test is disabled due to b/79930549 + * * Test IRadio.setAllowedCarriers() for the response returned. */ -TEST_P(RadioHidlTest, setAllowedCarriers) { +TEST_P(RadioHidlTest, DISABLED_setAllowedCarriers) { serial = GetRandomSerialNumber(); CarrierRestrictions carriers; memset(&carriers, 0, sizeof(carriers)); diff --git a/radio/1.2/vts/functional/radio_hidl_hal_api.cpp b/radio/1.2/vts/functional/radio_hidl_hal_api.cpp index 7464307a98..c81a8d9795 100644 --- a/radio/1.2/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.2/vts/functional/radio_hidl_hal_api.cpp @@ -299,9 +299,11 @@ TEST_P(RadioHidlTest_v1_2, startNetworkScan_InvalidPeriodicity2) { } /* + * The following test is disabled due to b/112206766 + * * Test IRadio.startNetworkScan() with valid periodicity */ -TEST_P(RadioHidlTest_v1_2, startNetworkScan_GoodRequest1) { +TEST_P(RadioHidlTest_v1_2, DISABLED_startNetworkScan_GoodRequest1) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_2::NetworkScanRequest request = { @@ -333,9 +335,11 @@ TEST_P(RadioHidlTest_v1_2, startNetworkScan_GoodRequest1) { } /* + * The following test is disabled due to b/112206766 + * * Test IRadio.startNetworkScan() with valid periodicity and plmns */ -TEST_P(RadioHidlTest_v1_2, startNetworkScan_GoodRequest2) { +TEST_P(RadioHidlTest_v1_2, DISABLED_startNetworkScan_GoodRequest2) { serial = GetRandomSerialNumber(); ::android::hardware::radio::V1_2::NetworkScanRequest request = { From 83691500e119f33b21a794d1d758a75ba7b02416 Mon Sep 17 00:00:00 2001 From: Tommy Chiu Date: Wed, 1 Apr 2020 14:47:40 +0800 Subject: [PATCH 0785/1022] Correct UseHmacKey parameter HMAC key was created with Digest(Digest::SHA_2_256) which is missing in the UseHmacKey function Bug: 152932473 Test: VtsHalKeymasterV4_1TargetTest Change-Id: If63dd197fe12172e14be9890ab07a00c3eef4a4c --- keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h index 6332c43200..152c063951 100644 --- a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h +++ b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h @@ -115,7 +115,9 @@ class Keymaster4_1HidlTest : public V4_0::test::KeymasterHidlTest { ErrorCode UseHmacKey(const HidlBuf& hmacKeyBlob) { auto [result, mac, out_params] = ProcessMessage(hmacKeyBlob, KeyPurpose::SIGN, "1234567890123456", - AuthorizationSetBuilder().Authorization(TAG_MAC_LENGTH, 128)); + AuthorizationSetBuilder() + .Authorization(TAG_MAC_LENGTH, 128) + .Digest(Digest::SHA_2_256)); return result; } From 8b06871849c52f70b5f1b06243548a517283ae91 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Wed, 1 Apr 2020 10:51:28 -0700 Subject: [PATCH 0786/1022] Add CameraStreamExternalBuffering test case This change adds a VTS test case to validate a new IEvsCamera::importExtenralBuffers() API. New test case allocates graphic buffers and passes them via a new API call. Bug: 152493110 Test: vts-tradefed VtsHalEvsV1_1_TargetTest Change-Id: I157f3cf45092a9a4ca8bf5bf9ea54aa62d15225c --- .../functional/VtsHalEvsV1_1TargetTest.cpp | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index 368a6d4d2d..6a386c3080 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -50,6 +50,8 @@ static const float kNanoToSeconds = 0.000000001f; #include #include #include +#include +#include #include #include @@ -66,6 +68,7 @@ using ::android::hardware::hidl_string; using ::android::sp; using ::android::wp; using ::android::hardware::camera::device::V3_2::Stream; +using ::android::hardware::automotive::evs::V1_1::BufferDesc; using ::android::hardware::automotive::evs::V1_0::DisplayDesc; using ::android::hardware::automotive::evs::V1_0::DisplayState; using ::android::hardware::graphics::common::V1_0::PixelFormat; @@ -2230,6 +2233,140 @@ TEST_P(EvsHidlTest, LogicalCameraMetadata) { } +/* + * CameraStreamExternalBuffering: + * This is same with CameraStreamBuffering except frame buffers are allocated by + * the test client and then imported by EVS framework. + */ +TEST_P(EvsHidlTest, CameraStreamExternalBuffering) { + LOG(INFO) << "Starting CameraStreamExternalBuffering test"; + + // Arbitrary constant (should be > 1 and less than crazy) + static const unsigned int kBuffersToHold = 6; + + // Get the camera list + loadCameraList(); + + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + + // Acquire the graphics buffer allocator + android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get()); + const auto usage = GRALLOC_USAGE_HW_TEXTURE | + GRALLOC_USAGE_SW_READ_RARELY | + GRALLOC_USAGE_SW_WRITE_OFTEN; + const auto format = HAL_PIXEL_FORMAT_RGBA_8888; + const auto width = 640; + const auto height = 360; + + // Allocate buffers to use + hidl_vec buffers; + for (auto i = 0; i < kBuffersToHold; ++i) { + unsigned pixelsPerLine; + buffer_handle_t memHandle = nullptr; + android::status_t result = alloc.allocate(width, + height, + format, + 1, + usage, + &memHandle, + &pixelsPerLine, + 0, + "EvsApp"); + if (result != android::NO_ERROR) { + LOG(ERROR) << __FUNCTION__ << " failed to allocate memory."; + } else { + BufferDesc buf; + AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&buf.buffer.description); + pDesc->width = width; + pDesc->height = height; + pDesc->layers = 1; + pDesc->format = format; + pDesc->usage = usage; + pDesc->stride = pixelsPerLine; + buf.buffer.nativeHandle = memHandle; + buf.bufferId = i; // Unique number to identify this buffer + buffers[i] = buf; + } + } + + // Test each reported camera + for (auto&& cam: cameraInfo) { + bool isLogicalCam = false; + getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); + + sp pCam = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + .withDefault(nullptr); + ASSERT_NE(pCam, nullptr); + + // Store a camera handle for a clean-up + activeCameras.push_back(pCam); + + // Request to import buffers + EvsResult result = EvsResult::OK; + int delta = 0; + pCam->importExternalBuffers(buffers, + [&] (auto _result, auto _delta) { + result = _result; + delta = _delta; + }); + if (isLogicalCam) { + EXPECT_EQ(result, EvsResult::UNDERLYING_SERVICE_ERROR); + continue; + } + + EXPECT_EQ(result, EvsResult::OK); + EXPECT_GE(delta, 0); + + // Set up a frame receiver object which will fire up its own thread. + sp frameHandler = new FrameHandler(pCam, cam, + nullptr, + FrameHandler::eNoAutoReturn); + + // Start the camera's video stream + bool startResult = frameHandler->startStream(); + ASSERT_TRUE(startResult); + + // Check that the video stream stalls once we've gotten exactly the number of buffers + // we requested since we told the frameHandler not to return them. + sleep(1); // 1 second should be enough for at least 5 frames to be delivered worst case + unsigned framesReceived = 0; + frameHandler->getFramesCounters(&framesReceived, nullptr); + ASSERT_EQ(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit"; + + + // Give back one buffer + bool didReturnBuffer = frameHandler->returnHeldBuffer(); + EXPECT_TRUE(didReturnBuffer); + + // Once we return a buffer, it shouldn't take more than 1/10 second to get a new one + // filled since we require 10fps minimum -- but give a 10% allowance just in case. + usleep(110 * kMillisecondsToMicroseconds); + frameHandler->getFramesCounters(&framesReceived, nullptr); + EXPECT_EQ(kBuffersToHold+1, framesReceived) << "Stream should've resumed"; + + // Even when the camera pointer goes out of scope, the FrameHandler object will + // keep the stream alive unless we tell it to shutdown. + // Also note that the FrameHandle and the Camera have a mutual circular reference, so + // we have to break that cycle in order for either of them to get cleaned up. + frameHandler->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCam); + activeCameras.clear(); + } + + // Release buffers + for (auto& b : buffers) { + alloc.free(b.buffer.nativeHandle); + } + buffers.resize(0); +} + + /* * UltrasonicsArrayOpenClean: * Opens each ultrasonics arrays reported by the enumerator and then explicitly closes it via a From 664ff765af3e23d7d926f34303d76fd3e60d36b6 Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Wed, 1 Apr 2020 13:54:33 -0600 Subject: [PATCH 0787/1022] Fixed encoding of device_locked field The attestation code used boringssl's ASN.1 encoding tools incorrectly, causing it to encode incorrect values in device_locked. Bug: b/152503089 Test: Build & boot Change-Id: I3c5352523b2db37d539ad353ac8c48c1585eb08d --- keymaster/3.0/vts/functional/attestation_record.cpp | 2 +- keymaster/4.0/support/attestation_record.cpp | 2 +- keymaster/4.1/support/attestation_record.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/keymaster/3.0/vts/functional/attestation_record.cpp b/keymaster/3.0/vts/functional/attestation_record.cpp index a428989de2..bde4b57e9b 100644 --- a/keymaster/3.0/vts/functional/attestation_record.cpp +++ b/keymaster/3.0/vts/functional/attestation_record.cpp @@ -46,7 +46,7 @@ struct ASN1_TYPE_Delete { typedef struct km_root_of_trust { ASN1_OCTET_STRING* verified_boot_key; - ASN1_BOOLEAN* device_locked; + ASN1_BOOLEAN device_locked; ASN1_ENUMERATED* verified_boot_state; } KM_ROOT_OF_TRUST; diff --git a/keymaster/4.0/support/attestation_record.cpp b/keymaster/4.0/support/attestation_record.cpp index 27e00c173a..bc294bd35b 100644 --- a/keymaster/4.0/support/attestation_record.cpp +++ b/keymaster/4.0/support/attestation_record.cpp @@ -50,7 +50,7 @@ struct ASN1_TYPE_Delete { typedef struct km_root_of_trust { ASN1_OCTET_STRING* verified_boot_key; - ASN1_BOOLEAN* device_locked; + ASN1_BOOLEAN device_locked; ASN1_ENUMERATED* verified_boot_state; ASN1_OCTET_STRING* verified_boot_hash; } KM_ROOT_OF_TRUST; diff --git a/keymaster/4.1/support/attestation_record.cpp b/keymaster/4.1/support/attestation_record.cpp index 9eab1db316..63bf854f0f 100644 --- a/keymaster/4.1/support/attestation_record.cpp +++ b/keymaster/4.1/support/attestation_record.cpp @@ -58,7 +58,7 @@ struct ASN1_TYPE_Delete { typedef struct km_root_of_trust { ASN1_OCTET_STRING* verified_boot_key; - ASN1_BOOLEAN* device_locked; + ASN1_BOOLEAN device_locked; ASN1_ENUMERATED* verified_boot_state; ASN1_OCTET_STRING* verified_boot_hash; } KM_ROOT_OF_TRUST; From 23f48e01b5368b0f6bbd58c15ba987d975da1f25 Mon Sep 17 00:00:00 2001 From: Hayden Gomes Date: Thu, 2 Apr 2020 11:50:21 -0700 Subject: [PATCH 0788/1022] Fixing AudioFocusChange to be signed int AudioFocusChange is expected to have negative values, but was originally defined to be an unsigned int. Bug: 153090512 Test: make -j Change-Id: I27cd8134f9fe19fbefc788e5c2498947dc52967e --- automotive/audiocontrol/2.0/types.hal | 2 +- current.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/automotive/audiocontrol/2.0/types.hal b/automotive/audiocontrol/2.0/types.hal index 65b0988487..80d9ee1867 100644 --- a/automotive/audiocontrol/2.0/types.hal +++ b/automotive/audiocontrol/2.0/types.hal @@ -19,7 +19,7 @@ package android.hardware.automotive.audiocontrol@2.0; /** * Changes in audio focus that can be experienced */ -enum AudioFocusChange : uint32_t { +enum AudioFocusChange : int32_t { NONE = 0, GAIN = 1, GAIN_TRANSIENT = 2, diff --git a/current.txt b/current.txt index 183d00637b..e612e2ed57 100644 --- a/current.txt +++ b/current.txt @@ -635,7 +635,7 @@ ca515ff4b63c80cf5ad7b3395c997c57d6c56157361f6c367d1c96f23cc4860a android.hardwar 4bc4e8087f5c389f013370ed68bc8a1a29cb2f203237937697f35e005a5ad0b4 android.hardware.automotive.audiocontrol@2.0::IAudioControl 37ef585d6687cb31e35c67ab456140d70edba9c4333ce5a6ddd70e636e985773 android.hardware.automotive.audiocontrol@2.0::ICloseHandle 3cf3e5e48ba2642052bbccc1aa4e8bb142933ac960ff40eeedd16e4fe452e7a5 android.hardware.automotive.audiocontrol@2.0::IFocusListener -d06fc14b325beeef06bd39de8f178f490d9e9095255626866071aab42be1fc40 android.hardware.automotive.audiocontrol@2.0::types +44c03f3341939524b5f5acb6680f8a91924d02e335a32840d56597616db7f1ea android.hardware.automotive.audiocontrol@2.0::types 949a2582c9efa3f6f631f56120eae3f02313f251dbf9246c327e419cdf0652a2 android.hardware.automotive.can@1.0::ICanBus 43cddb1907a30343bced68946884416ea25ab14ae2df4709357528b2bedba84c android.hardware.automotive.can@1.0::ICanController 272e826492b27b0dbdeda408e84a41ae43e98f29e57995b6452ded270aae4eee android.hardware.automotive.can@1.0::ICanErrorListener From 003b231944cdb52f487413e9a82336b2043ae72d Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 2 Apr 2020 14:34:01 -0700 Subject: [PATCH 0789/1022] Add VtsHalBootV1_1TargetTest to VTS. Bug: 139438327 Test: N/A Change-Id: I72a6b3f60c861d4cda5f3a5fb56e15d4bbe7bc41 --- boot/1.1/vts/functional/Android.bp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/boot/1.1/vts/functional/Android.bp b/boot/1.1/vts/functional/Android.bp index 49ea09a15e..9f0c74a482 100644 --- a/boot/1.1/vts/functional/Android.bp +++ b/boot/1.1/vts/functional/Android.bp @@ -23,6 +23,8 @@ cc_test { "android.hardware.boot@1.1", "libgmock", ], - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "vts", + ], } - From 852fc3ba4ed588e43e704c45a71ea298dc362042 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 2 Apr 2020 14:37:45 -0700 Subject: [PATCH 0790/1022] Add VtsCan* to vts. Bug: 139438327 Test: N/A Change-Id: I73447a6a0b891adc9fbb0d931ae517e99f141c64 --- automotive/can/1.0/vts/functional/Android.bp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/automotive/can/1.0/vts/functional/Android.bp b/automotive/can/1.0/vts/functional/Android.bp index e3e770b047..d020750f3a 100644 --- a/automotive/can/1.0/vts/functional/Android.bp +++ b/automotive/can/1.0/vts/functional/Android.bp @@ -28,7 +28,10 @@ cc_defaults { "android.hardware.automotive.can@vts-utils-lib", "libgmock", ], - test_suites: ["general-tests"], + test_suites: [ + "general-tests", + "vts", + ], } cc_test { From 6ca8276e8b7dd5b3f7d9cf851fe892ae76d2d9a3 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 2 Apr 2020 14:43:20 -0700 Subject: [PATCH 0791/1022] Add VtsHalNeuralnetworksV1_3TargetTest to vts. Bug: 139438327 Test: N/A Change-Id: I48342f6e242735e3ee693a7f2bdbe3334a072f81 --- neuralnetworks/1.3/vts/functional/Android.bp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp index 545a5be74e..2c1be0b008 100644 --- a/neuralnetworks/1.3/vts/functional/Android.bp +++ b/neuralnetworks/1.3/vts/functional/Android.bp @@ -77,5 +77,8 @@ cc_test { header_libs: [ "libneuralnetworks_headers", ], - test_suites: ["general-tests"], + test_suites: [ + "general-tests", + "vts", + ], } From 36f210147d5554a190d613e6c74a6c2665eff1c2 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 25 Mar 2020 16:50:44 -0700 Subject: [PATCH 0792/1022] graphics.composer@2.2 rc remove interface decls Since vendors here add additional services to this service, vts_ibase_test fails on some devices. This test, for sanity, requires that if a service has any interface declaration, it has all relevant interface declarations. These interface entries are declared but unused here. Fixes: 152375928 Test: vts_ibase_test on sargo Change-Id: I2d3225b42824f0befb55d8c93a578e910a05e4a1 --- .../default/android.hardware.graphics.composer@2.2-service.rc | 2 -- 1 file changed, 2 deletions(-) diff --git a/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc b/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc index 0d7e86f91e..efe6dadbc2 100644 --- a/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc +++ b/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc @@ -1,6 +1,4 @@ service vendor.hwcomposer-2-2 /vendor/bin/hw/android.hardware.graphics.composer@2.2-service - interface android.hardware.graphics.composer@2.1::IComposer default - interface android.hardware.graphics.composer@2.2::IComposer default class hal animation user system group graphics drmrpc From b4de0a94a22b8f68abccf8100eec9a393673f4e8 Mon Sep 17 00:00:00 2001 From: Malcolm Chen Date: Thu, 2 Apr 2020 17:39:01 -0700 Subject: [PATCH 0793/1022] Skip enableModem vts if in single SIM mode. Due to modem issue, enableModem only works in dual-SIM mode. And we only use that in dual-SIM mode. So skipping testing in in single SIM mode. Bug: 152557383 Test: vts Change-Id: I41f200317eaf9be0613f92e5bff9a3ee8a98ef15 --- radio/1.3/vts/functional/radio_hidl_hal_api.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/radio/1.3/vts/functional/radio_hidl_hal_api.cpp b/radio/1.3/vts/functional/radio_hidl_hal_api.cpp index ca64305bfe..1a01b284b5 100644 --- a/radio/1.3/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.3/vts/functional/radio_hidl_hal_api.cpp @@ -16,6 +16,7 @@ #include #include +#include "VtsCoreUtil.h" #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) @@ -25,6 +26,15 @@ TEST_P(RadioHidlTest_v1_3, enableModem) { serial = GetRandomSerialNumber(); + bool isMultiSimEnabled = + testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", + "dsds") || + testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "tsts"); + if (!isMultiSimEnabled) { + ALOGI("enableModem, no need to test in single SIM mode"); + return; + } + bool responseToggle = radioRsp_v1_3->enableModemResponseToggle; Return res = radio_v1_3->enableModem(serial, true); ASSERT_OK(res); From f15bd2d959d64ff7075005cca3ce9fc98eb3293c Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Fri, 3 Apr 2020 12:57:13 -0700 Subject: [PATCH 0794/1022] Convert VtsHalUsbV1_2TargetTest to parameterized gtest Bug: 150383827 Test: atest VtsHalUsbV1_2TargetTest Change-Id: I5728bbe76b4dda32eab67535f4726131dee152c3 --- usb/1.2/vts/functional/Android.bp | 6 ++- .../functional/VtsHalUsbV1_2TargetTest.cpp | 50 +++++++------------ 2 files changed, 22 insertions(+), 34 deletions(-) diff --git a/usb/1.2/vts/functional/Android.bp b/usb/1.2/vts/functional/Android.bp index 761d37f184..d6aaf2d9aa 100644 --- a/usb/1.2/vts/functional/Android.bp +++ b/usb/1.2/vts/functional/Android.bp @@ -23,6 +23,8 @@ cc_test { "android.hardware.usb@1.1", "android.hardware.usb@1.2", ], - test_suites: ["general-tests"], + test_suites: [ + "general-tests", + "vts", + ], } - diff --git a/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp b/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp index 7b3dea938e..5f901cd4f6 100644 --- a/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp +++ b/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp @@ -22,8 +22,10 @@ #include #include -#include -#include +#include +#include +#include + #include #include #include @@ -139,24 +141,12 @@ class UsbCallback : public ::testing::VtsHalHidlTargetCallbackBase(); } -}; - // The main test class for the USB hidl HAL -class UsbHidlTest : public ::testing::VtsHalHidlTargetTestBase { - public: +class UsbHidlTest : public ::testing::TestWithParam { + public: virtual void SetUp() override { ALOGI(__FUNCTION__); - usb = ::testing::VtsHalHidlTargetTestBase::getService(); + usb = IUsb::getService(GetParam()); ASSERT_NE(usb, nullptr); usb_cb_2 = new UsbCallback(kCallbackIdentifier); @@ -182,7 +172,7 @@ class UsbHidlTest : public ::testing::VtsHalHidlTargetTestBase { * Callback oject is created and registered. * Check to see if the hidl transaction succeeded. */ -TEST_F(UsbHidlTest, setCallback) { +TEST_P(UsbHidlTest, setCallback) { usb_cb_1 = new UsbCallback(1); ASSERT_NE(usb_cb_1, nullptr); Return ret = usb->setCallback(usb_cb_1); @@ -195,7 +185,7 @@ TEST_F(UsbHidlTest, setCallback) { * HAL service should call notifyPortStatusChange_1_2 * instead of notifyPortStatusChange of V1_0/V1_1 interface */ -TEST_F(UsbHidlTest, queryPortStatus) { +TEST_P(UsbHidlTest, queryPortStatus) { Return ret = usb->queryPortStatus(); ASSERT_TRUE(ret.isOk()); auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); @@ -211,7 +201,7 @@ TEST_F(UsbHidlTest, queryPortStatus) { * Check if supportedContaminantProtectionModes changes across queryPortStatus * call. */ -TEST_F(UsbHidlTest, checkSupportedContaminantProtectionModes) { +TEST_P(UsbHidlTest, checkSupportedContaminantProtectionModes) { Return ret = usb->queryPortStatus(); ASSERT_TRUE(ret.isOk()); auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); @@ -243,7 +233,7 @@ TEST_F(UsbHidlTest, checkSupportedContaminantProtectionModes) { * enableContaminantPresenceDetection should not enable/disable * contaminantPresenceProtection. */ -TEST_F(UsbHidlTest, presenceDetectionSupportedCheck) { +TEST_P(UsbHidlTest, presenceDetectionSupportedCheck) { Return ret = usb->queryPortStatus(); ASSERT_TRUE(ret.isOk()); auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); @@ -272,7 +262,7 @@ TEST_F(UsbHidlTest, presenceDetectionSupportedCheck) { /* * enableContaminantPresenceDetection should succeed atleast 90% when supported. */ -TEST_F(UsbHidlTest, contaminantPresenceDetectionStability) { +TEST_P(UsbHidlTest, contaminantPresenceDetectionStability) { int successCount = 0; bool currentStatus; bool supported = true; @@ -309,7 +299,7 @@ TEST_F(UsbHidlTest, contaminantPresenceDetectionStability) { * enableContaminantPresenceProtection should not enable/disable * contaminantPresenceProtection. */ -TEST_F(UsbHidlTest, presenceProtectionSupportedCheck) { +TEST_P(UsbHidlTest, presenceProtectionSupportedCheck) { Return ret = usb->queryPortStatus(); ASSERT_TRUE(ret.isOk()); auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); @@ -338,7 +328,7 @@ TEST_F(UsbHidlTest, presenceProtectionSupportedCheck) { /* * enableContaminantPresenceProtection should succeed atleast 90% when supported. */ -TEST_F(UsbHidlTest, contaminantPresenceProtectionStability) { +TEST_P(UsbHidlTest, contaminantPresenceProtectionStability) { int successCount = 0; bool currentStatus; bool supported = true; @@ -370,11 +360,7 @@ TEST_F(UsbHidlTest, contaminantPresenceProtectionStability) { if (!supported) EXPECT_GE(successCount, 9); } -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(UsbHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - UsbHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); - return status; -} +INSTANTIATE_TEST_SUITE_P( + PerInstance, UsbHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IUsb::descriptor)), + android::hardware::PrintInstanceNameToString); From 131c1250cdfda0621782dc36d6f0b0f80fe7c3ef Mon Sep 17 00:00:00 2001 From: Amy Zhang Date: Fri, 3 Apr 2020 13:37:57 -0700 Subject: [PATCH 0795/1022] Add TEST_MAPPING presubmit config for VtsHalTvInputV1_0TargetTest Test: atest --test-mapping Bug: 150382976 Change-Id: Icd05fd2aaf1386ed05f8d208988291a1b61e4f35 --- TEST_MAPPING | 3 +++ 1 file changed, 3 insertions(+) diff --git a/TEST_MAPPING b/TEST_MAPPING index 543acf6db9..acae4f3a55 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -8,6 +8,9 @@ }, { "name": "hal_implementation_test" + }, + { + "name": "VtsHalTvInputV1_0TargetTest" } ] } From 5cd54b5b0dbcf9a4ee92c3e17d635705d0a55417 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Fri, 3 Apr 2020 13:19:50 -0700 Subject: [PATCH 0796/1022] Convert VtsHalAudioControlV1_0TargetTest to parameterized gtest Bug: 150383827 Bug: 150381814 Test: atest VtsHalAudioControlV1_0TargetTest Change-Id: I900f6a540c44d13f5f8a8882b573fa5669c1732f --- .../1.0/vts/functional/Android.bp | 5 ++- .../VtsHalAudioControlV1_0TargetTest.cpp | 42 +++++++------------ 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/automotive/audiocontrol/1.0/vts/functional/Android.bp b/automotive/audiocontrol/1.0/vts/functional/Android.bp index 3cb6340ee8..1bb8e88fbc 100644 --- a/automotive/audiocontrol/1.0/vts/functional/Android.bp +++ b/automotive/audiocontrol/1.0/vts/functional/Android.bp @@ -25,5 +25,8 @@ cc_test { static_libs: [ "android.hardware.automotive.audiocontrol@1.0", ], - test_suites: ["general-tests"], + test_suites: [ + "general-tests", + "vts", + ], } diff --git a/automotive/audiocontrol/1.0/vts/functional/VtsHalAudioControlV1_0TargetTest.cpp b/automotive/audiocontrol/1.0/vts/functional/VtsHalAudioControlV1_0TargetTest.cpp index fc0deb94c3..de1ec02072 100644 --- a/automotive/audiocontrol/1.0/vts/functional/VtsHalAudioControlV1_0TargetTest.cpp +++ b/automotive/audiocontrol/1.0/vts/functional/VtsHalAudioControlV1_0TargetTest.cpp @@ -25,11 +25,12 @@ #include #include -#include #include +#include #include - -#include +#include +#include +#include using namespace ::android::hardware::automotive::audiocontrol::V1_0; using ::android::hardware::Return; @@ -40,30 +41,12 @@ using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::sp; - -// Boiler plate for test harness -class CarAudioControlHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static CarAudioControlHidlEnvironment* Instance() { - static CarAudioControlHidlEnvironment* instance = new CarAudioControlHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { registerTestService(); } - private: - CarAudioControlHidlEnvironment() {} -}; - - // The main test class for the automotive AudioControl HAL -class CarAudioControlHidlTest : public ::testing::VtsHalHidlTargetTestBase { -public: +class CarAudioControlHidlTest : public ::testing::TestWithParam { + public: virtual void SetUp() override { // Make sure we can connect to the driver - pAudioControl = ::testing::VtsHalHidlTargetTestBase::getService( - CarAudioControlHidlEnvironment::Instance()-> - getServiceName()); + pAudioControl = IAudioControl::getService(GetParam()); ASSERT_NE(pAudioControl.get(), nullptr); } @@ -82,7 +65,7 @@ public: * fader actually works. The only thing we can do is exercise the HAL and if the HAL crashes, * we _might_ get a test failure if that breaks the connection to the driver. */ -TEST_F(CarAudioControlHidlTest, FaderExercise) { +TEST_P(CarAudioControlHidlTest, FaderExercise) { ALOGI("Fader exercise test (silent)"); // Set the fader all the way to the back @@ -104,7 +87,7 @@ TEST_F(CarAudioControlHidlTest, FaderExercise) { /* * Balance exercise test. */ -TEST_F(CarAudioControlHidlTest, BalanceExercise) { +TEST_P(CarAudioControlHidlTest, BalanceExercise) { ALOGI("Balance exercise test (silent)"); // Set the balance all the way to the left @@ -126,7 +109,7 @@ TEST_F(CarAudioControlHidlTest, BalanceExercise) { /* * Context mapping test. */ -TEST_F(CarAudioControlHidlTest, ContextMapping) { +TEST_P(CarAudioControlHidlTest, ContextMapping) { ALOGI("Context mapping test"); int bus = -1; @@ -156,3 +139,8 @@ TEST_F(CarAudioControlHidlTest, ContextMapping) { bus = pAudioControl->getBusForContext((ContextNumber)~0); EXPECT_EQ(bus, -1); } + +INSTANTIATE_TEST_SUITE_P( + PerInstance, CarAudioControlHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAudioControl::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file From 170a44526c6247bcf2d3d19c49de390dfc26b4b6 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Sat, 4 Apr 2020 00:59:41 -0700 Subject: [PATCH 0797/1022] Convert VtsHalBroadcastradioV1_0/1TargetTest to parameterized gtest Bug: 142397658 Test: atest VtsHalBroadcastradioV1_0TargetTest \ VtsHalBroadcastradioV1_1TargetTest Change-Id: I41329305c4c7da117cd6e76cd3950fa38d9db5c2 --- broadcastradio/1.0/vts/functional/Android.bp | 5 +- .../VtsHalBroadcastradioV1_0TargetTest.cpp | 58 +++++++++---------- broadcastradio/1.1/vts/functional/Android.bp | 5 +- .../VtsHalBroadcastradioV1_1TargetTest.cpp | 42 +++++--------- .../environment-utils.h | 41 ------------- .../hal-1.x-enum-utils.h | 38 ++++++++++++ 6 files changed, 88 insertions(+), 101 deletions(-) delete mode 100644 broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/environment-utils.h create mode 100644 broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/hal-1.x-enum-utils.h diff --git a/broadcastradio/1.0/vts/functional/Android.bp b/broadcastradio/1.0/vts/functional/Android.bp index 9ba9fbe209..2a4f9420ec 100644 --- a/broadcastradio/1.0/vts/functional/Android.bp +++ b/broadcastradio/1.0/vts/functional/Android.bp @@ -22,5 +22,8 @@ cc_test { "android.hardware.broadcastradio@1.0", "android.hardware.broadcastradio@vts-utils-lib", ], - test_suites: ["general-tests"], + test_suites: [ + "general-tests", + "vts", + ], } diff --git a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp index 90c8463755..9897ab7af5 100644 --- a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp +++ b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp @@ -15,11 +15,13 @@ */ #define LOG_TAG "BroadcastRadioHidlHalTest" -#include #include #include #include +#include +#include #include +#include #include #include @@ -27,28 +29,28 @@ #include #include #include -#include +#include -using ::android::sp; -using ::android::Mutex; using ::android::Condition; +using ::android::Mutex; +using ::android::sp; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory; -using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio; -using ::android::hardware::broadcastradio::V1_0::ITuner; -using ::android::hardware::broadcastradio::V1_0::ITunerCallback; -using ::android::hardware::broadcastradio::V1_0::Result; -using ::android::hardware::broadcastradio::V1_0::Class; -using ::android::hardware::broadcastradio::V1_0::Properties; using ::android::hardware::broadcastradio::V1_0::Band; using ::android::hardware::broadcastradio::V1_0::BandConfig; +using ::android::hardware::broadcastradio::V1_0::Class; using ::android::hardware::broadcastradio::V1_0::Direction; -using ::android::hardware::broadcastradio::V1_0::ProgramInfo; +using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio; +using ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory; +using ::android::hardware::broadcastradio::V1_0::ITuner; +using ::android::hardware::broadcastradio::V1_0::ITunerCallback; using ::android::hardware::broadcastradio::V1_0::MetaData; using ::android::hardware::broadcastradio::V1_0::MetadataKey; using ::android::hardware::broadcastradio::V1_0::MetadataType; -using ::android::hardware::broadcastradio::vts::BroadcastRadioHidlEnvironment; +using ::android::hardware::broadcastradio::V1_0::ProgramInfo; +using ::android::hardware::broadcastradio::V1_0::Properties; +using ::android::hardware::broadcastradio::V1_0::Result; +using ::android::hardware::broadcastradio::V1_0::vts::RadioClassFromString; #define RETURN_IF_SKIPPED \ if (skipped) { \ @@ -56,19 +58,19 @@ using ::android::hardware::broadcastradio::vts::BroadcastRadioHidlEnvironment; return; \ } -static BroadcastRadioHidlEnvironment* gEnv = nullptr; // The main test class for Broadcast Radio HIDL HAL. -class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetTestBase, - public ::testing::WithParamInterface { - protected: +class BroadcastRadioHidlTest + : public ::testing::TestWithParam> { + protected: virtual void SetUp() override { ASSERT_EQ(nullptr, mRadio.get()); - radioClass = GetParam(); + radioClass = RadioClassFromString(std::get<1>(GetParam())); + skipped = false; sp factory = - getService(gEnv->getServiceName()); + IBroadcastRadioFactory::getService(std::get<0>(GetParam())); ASSERT_NE(nullptr, factory.get()); Result connectResult; @@ -727,16 +729,8 @@ TEST_P(BroadcastRadioHidlTest, IbImagesOnly) { } INSTANTIATE_TEST_CASE_P( - BroadcastRadioHidlTestCases, - BroadcastRadioHidlTest, - ::testing::Values(Class::AM_FM, Class::SAT, Class::DT)); - -int main(int argc, char** argv) { - gEnv = new BroadcastRadioHidlEnvironment; - ::testing::AddGlobalTestEnvironment(gEnv); - ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - int status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); - return status; -} + PerInstance, BroadcastRadioHidlTest, + testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames( + IBroadcastRadioFactory::descriptor)), + ::testing::Values("AM_FM", "SAT", "DT")), + android::hardware::PrintInstanceTupleNameToString<>); \ No newline at end of file diff --git a/broadcastradio/1.1/vts/functional/Android.bp b/broadcastradio/1.1/vts/functional/Android.bp index 0a02a694c5..661439aa67 100644 --- a/broadcastradio/1.1/vts/functional/Android.bp +++ b/broadcastradio/1.1/vts/functional/Android.bp @@ -25,5 +25,8 @@ cc_test { "android.hardware.broadcastradio@vts-utils-lib", "libgmock", ], - test_suites: ["general-tests"], + test_suites: [ + "general-tests", + "vts", + ], } diff --git a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp index 6687731965..4833beb5bb 100644 --- a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp +++ b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp @@ -16,7 +16,6 @@ #define LOG_TAG "broadcastradio.vts" -#include #include #include #include @@ -25,13 +24,16 @@ #include #include #include -#include +#include #include #include #include #include #include +#include +#include #include +#include #include #include @@ -51,6 +53,7 @@ using testing::DoAll; using testing::Invoke; using testing::SaveArg; +using broadcastradio::V1_0::vts::RadioClassFromString; using broadcastradio::vts::CallBarrier; using V1_0::BandConfig; using V1_0::Class; @@ -59,7 +62,6 @@ using V1_0::MetadataKey; using V1_0::MetadataType; using broadcastradio::vts::clearAndWait; -using broadcastradio::vts::BroadcastRadioHidlEnvironment; static constexpr auto kConfigTimeout = 10s; static constexpr auto kConnectModuleTimeout = 1s; @@ -93,11 +95,9 @@ struct TunerCallbackMock : public ITunerCallback { MOCK_TIMEOUT_METHOD1(currentProgramInfoChanged, Return(const ProgramInfo&)); }; -static BroadcastRadioHidlEnvironment* gEnv = nullptr; - -class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase, - public ::testing::WithParamInterface { - protected: +class BroadcastRadioHalTest + : public ::testing::TestWithParam> { + protected: virtual void SetUp() override; virtual void TearDown() override; @@ -120,11 +120,10 @@ class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase, }; void BroadcastRadioHalTest::SetUp() { - radioClass = GetParam(); + radioClass = RadioClassFromString(std::get<1>(GetParam())); // lookup HIDL service - auto factory = - getService(gEnv->getServiceName()); + auto factory = IBroadcastRadioFactory::getService(std::get<0>(GetParam())); ASSERT_NE(nullptr, factory.get()); // connect radio module @@ -601,24 +600,15 @@ TEST_P(BroadcastRadioHalTest, VerifyIdentifiersFormat) { } while (nextBand()); } -INSTANTIATE_TEST_CASE_P(BroadcastRadioHalTestCases, BroadcastRadioHalTest, - ::testing::Values(Class::AM_FM, Class::SAT, Class::DT)); +INSTANTIATE_TEST_CASE_P( + PerInstance, BroadcastRadioHalTest, + testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames( + IBroadcastRadioFactory::descriptor)), + ::testing::Values("AM_FM", "SAT", "DT")), + android::hardware::PrintInstanceTupleNameToString<>); } // namespace vts } // namespace V1_1 } // namespace broadcastradio } // namespace hardware } // namespace android - -int main(int argc, char** argv) { - using android::hardware::broadcastradio::V1_1::vts::gEnv; - using android::hardware::broadcastradio::V1_1::IBroadcastRadioFactory; - using android::hardware::broadcastradio::vts::BroadcastRadioHidlEnvironment; - gEnv = new BroadcastRadioHidlEnvironment; - ::testing::AddGlobalTestEnvironment(gEnv); - ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - int status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); - return status; -} diff --git a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/environment-utils.h b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/environment-utils.h deleted file mode 100644 index 274e6322b8..0000000000 --- a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/environment-utils.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2018 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_BROADCASTRADIO_VTS_ENVIRONMENT_UTILS -#define ANDROID_HARDWARE_BROADCASTRADIO_VTS_ENVIRONMENT_UTILS - -#include - -namespace android { -namespace hardware { -namespace broadcastradio { -namespace vts { - -// Test environment for BroadcastRadio HIDL HAL. -template -class BroadcastRadioHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - virtual void registerTestServices() override { - using expander = int[]; - (void)expander{0, (registerTestService(), 0)...}; - } -}; - -} // namespace vts -} // namespace broadcastradio -} // namespace hardware -} // namespace android - -#endif // ANDROID_HARDWARE_BROADCASTRADIO_VTS_ENVIRONMENT_UTILS diff --git a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/hal-1.x-enum-utils.h b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/hal-1.x-enum-utils.h new file mode 100644 index 0000000000..6059ef8fdb --- /dev/null +++ b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/hal-1.x-enum-utils.h @@ -0,0 +1,38 @@ +/* + * 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. + */ +#pragma once + +namespace android::hardware::broadcastradio::V1_0::vts { + +using android::hardware::broadcastradio::V1_0::Class; + +/** + * Convert a string of Class name to its enum value. Fail the test if the enum + * value is not found. + * + * @param className string value of a Class enum. + * @return Class enum that matches the string value. + */ +Class RadioClassFromString(std::string className) { + if (className == "AM_FM") return Class::AM_FM; + if (className == "SAT") return Class::SAT; + if (className == "DT") return Class::DT; + // Fail the test run. + CHECK(false) << "Class name not found: " << className; + // Return some arbitrary enum. + return Class::AM_FM; +} +} // namespace android::hardware::broadcastradio::V1_0::vts From 03041993791e54a89a6b727d57676d8fb551d297 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 6 Apr 2020 14:12:18 -0700 Subject: [PATCH 0798/1022] Remove configstore from compatibility_matrix.5.xml To reflect GMS core requirements, which have already been updated. This HAL is replaced with system properties. Bug: 124531214 Bug: 149806433 Test: checked by cuttlefish build Change-Id: Ib710bf39b871365ebced845e3ccec6d333bee630 --- compatibility_matrices/compatibility_matrix.5.xml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/compatibility_matrices/compatibility_matrix.5.xml b/compatibility_matrices/compatibility_matrix.5.xml index 38f589daf0..30c15721c0 100644 --- a/compatibility_matrices/compatibility_matrix.5.xml +++ b/compatibility_matrices/compatibility_matrix.5.xml @@ -156,14 +156,6 @@ default - - android.hardware.configstore - 1.1 - - ISurfaceFlingerConfigs - default - - android.hardware.confirmationui 1.0 From efc31de2b692ced55103726da770e78a19d64655 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Mon, 6 Apr 2020 16:11:18 -0700 Subject: [PATCH 0799/1022] Add filegroup for trout project to use VehicleHalProto definition Other virtualization specific definitions and build rules will be moved to /device/google/trout in the following patches. Keep them for now so that we will not break the build. Test: build Bug: 148816426 Change-Id: I8a579346b55aa812db3dd30a34050c9515f7a68d --- .../2.0/default/impl/vhal_v2_0/proto/Android.bp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) 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 2eedecda2a..9784f751f2 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 @@ -27,7 +27,17 @@ cc_library_static { "-Wall", "-Werror", ], - srcs: ["VehicleHalProto.proto"] + srcs: ["VehicleHalProto.proto"], +} + +filegroup { + name: "vhal-proto-src", + visibility: [ + "//device/google/trout/hal/vehicle/2.0:__subpackages__", + ], + srcs: [ + "VehicleHalProto.proto", + ], } cc_library_static { @@ -49,7 +59,7 @@ cc_library_static { "libgrpc++_unsecure", ], cflags: [ - "-Wno-unused-parameter" + "-Wno-unused-parameter", ], } From bedb2d9ce3c183f6938f64f7a4a59c3827c73a3c Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Mon, 6 Apr 2020 16:51:03 -0700 Subject: [PATCH 0800/1022] drm 1.3 vts: call signRSA with non-empty args Bug: 153356263 Test: VtsHalDrmV1_3TargetTest Change-Id: If6c6e9f478458c004063cebc195e7e77084fc11d --- drm/1.3/vts/functional/drm_hal_test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drm/1.3/vts/functional/drm_hal_test.cpp b/drm/1.3/vts/functional/drm_hal_test.cpp index 738f5b28f6..0958c35869 100644 --- a/drm/1.3/vts/functional/drm_hal_test.cpp +++ b/drm/1.3/vts/functional/drm_hal_test.cpp @@ -39,10 +39,10 @@ TEST_P(DrmHalTestV1_3, SignRsaNotAllowed) { } // signRSA - const hidl_vec& sessionId{}; - const hidl_string& algorithm{}; - const hidl_vec& message{}; - const hidl_vec& wrappedKey{}; + const hidl_vec& sessionId{0}; + const hidl_string& algorithm{"RSASSA-PSS-SHA1"}; + const hidl_vec& message{0}; + const hidl_vec& wrappedKey{0}; auto res = drmPlugin_->signRSA( sessionId, algorithm, message, wrappedKey, [&](StatusV1_0 status, const hidl_vec& signature) { From d5608a2d5aac05915b589df46372ba892471935f Mon Sep 17 00:00:00 2001 From: Calvin Huang Date: Mon, 16 Mar 2020 18:52:27 -0700 Subject: [PATCH 0801/1022] Override VHAL property init value with json Bug: 150978133 Test: Manual Change-Id: Iaa45adad3712ca3cc325d52433048b3208109402 --- .../impl/vhal_v2_0/EmulatedVehicleHal.cpp | 35 +++++++++++++++++++ .../impl/vhal_v2_0/EmulatedVehicleHal.h | 3 ++ .../impl/vhal_v2_0/JsonFakeValueGenerator.cpp | 24 +++++++++++++ .../impl/vhal_v2_0/JsonFakeValueGenerator.h | 3 ++ 4 files changed, 65 insertions(+) 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 84354c15f8..bdc52448e7 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 @@ -16,8 +16,12 @@ #define LOG_TAG "DefaultVehicleHal_v2_0" #include +#include #include +#include #include +#include +#include #include "EmulatedVehicleHal.h" #include "JsonFakeValueGenerator.h" @@ -101,6 +105,30 @@ EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleH mVehicleClient->registerPropertyValueCallback(std::bind(&EmulatedVehicleHal::onPropertyValue, this, std::placeholders::_1, std::placeholders::_2)); + + mInitVhalValueOverride = + android::base::GetBoolProperty("persist.vendor.vhal_init_value_override", false); + if (mInitVhalValueOverride) { + getAllPropertiesOverride(); + } +} + +void EmulatedVehicleHal::getAllPropertiesOverride() { + if (auto dir = opendir("/vendor/etc/vhaloverride/")) { + std::regex reg_json(".*[.]json", std::regex::icase); + while (auto f = readdir(dir)) { + if (!regex_match(f->d_name, reg_json)) { + continue; + } + std::string file = "/vendor/etc/vhaloverride/" + std::string(f->d_name); + JsonFakeValueGenerator tmpGenerator(file); + + std::vector propvalues = tmpGenerator.getAllEvents(); + mVehiclePropertiesOverride.insert(std::end(mVehiclePropertiesOverride), + std::begin(propvalues), std::end(propvalues)); + } + closedir(dir); + } } VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get( @@ -277,6 +305,13 @@ void EmulatedVehicleHal::onCreate() { } } else { prop.value = it.initialValue; + if (mInitVhalValueOverride) { + for (auto& itOverride : mVehiclePropertiesOverride) { + if (itOverride.prop == cfg.prop) { + prop.value = itOverride.value; + } + } + } } mPropStore->writeValue(prop, shouldUpdateStatus); } diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h index dc05145cd7..cba4b8ae11 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h @@ -62,6 +62,7 @@ public: // Methods from EmulatedVehicleHalIface bool setPropertyFromVehicle(const VehiclePropValue& propValue) override; std::vector getAllProperties() const override; + void getAllPropertiesOverride(); private: constexpr std::chrono::nanoseconds hertzToNanoseconds(float hz) const { @@ -87,6 +88,8 @@ private: RecurrentTimer mRecurrentTimer; VehicleHalClient* mVehicleClient; bool mInEmulator; + bool mInitVhalValueOverride; + std::vector mVehiclePropertiesOverride; }; } // impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp index 8677f837f5..890eb33643 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp @@ -48,6 +48,22 @@ JsonFakeValueGenerator::JsonFakeValueGenerator(const VehiclePropValue& request) mNumOfIterations = v.int32Values.size() < 2 ? -1 : v.int32Values[1]; } +JsonFakeValueGenerator::JsonFakeValueGenerator(std::string path) { + std::ifstream ifs(path); + if (!ifs) { + ALOGE("%s: couldn't open %s for parsing.", __func__, path.c_str()); + } + mGenCfg = { + .index = 0, + .events = parseFakeValueJson(ifs), + }; + mNumOfIterations = mGenCfg.events.size(); +} + +std::vector JsonFakeValueGenerator::getAllEvents() { + return mGenCfg.events; +} + VehiclePropValue JsonFakeValueGenerator::nextEvent() { VehiclePropValue generatedValue; if (!hasNext()) { @@ -109,6 +125,7 @@ std::vector JsonFakeValueGenerator::parseFakeValueJson(std::is Json::Value rawEventValue = rawEvent["value"]; auto& value = event.value; + int32_t count; switch (getPropType(event.prop)) { case VehiclePropertyType::BOOLEAN: case VehiclePropertyType::INT32: @@ -126,6 +143,13 @@ std::vector JsonFakeValueGenerator::parseFakeValueJson(std::is case VehiclePropertyType::STRING: value.stringValue = rawEventValue.asString(); break; + case VehiclePropertyType::INT32_VEC: + value.int32Values.resize(rawEventValue.size()); + count = 0; + for (auto& it : rawEventValue) { + value.int32Values[count++] = it.asInt(); + } + break; case VehiclePropertyType::MIXED: copyMixedValueJson(value, rawEventValue); if (isDiagnosticProperty(event.prop)) { diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h index 70575f77bf..dc8ff6680c 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h @@ -41,9 +41,12 @@ private: public: JsonFakeValueGenerator(const VehiclePropValue& request); + JsonFakeValueGenerator(std::string path); + ~JsonFakeValueGenerator() = default; VehiclePropValue nextEvent(); + std::vector getAllEvents(); bool hasNext(); From eb9d19960ebbedbce613e24094853e1a7c93dc90 Mon Sep 17 00:00:00 2001 From: Nate Jiang Date: Mon, 6 Apr 2020 16:46:07 -0700 Subject: [PATCH 0802/1022] Make VTS test use the highest supported preamble VTS should use the highest supported preamble. If preamble is not support by device, LOWI will return unknow error. Bug: 152440187 Test: atest VtsHalWifiApV1_4TargetTest Change-Id: I972377a526c5d62a733878df5fd80d4af17e37ff --- .../functional/wifi_rtt_controller_hidl_test.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp index 726470cf3b..295c86e1a7 100644 --- a/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp +++ b/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp @@ -140,6 +140,18 @@ TEST_P(WifiRttControllerHidlTest, RegisterEventCallback_1_4) { * rangeRequest_1_4 */ TEST_P(WifiRttControllerHidlTest, RangeRequest_1_4) { + std::pair status_and_caps; + + // Get the Capabilities + status_and_caps = HIDL_INVOKE(wifi_rtt_controller_, getCapabilities_1_4); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code); + // Get the highest support preamble + int preamble = 1; + status_and_caps.second.preambleSupport >>= 1; + while (status_and_caps.second.preambleSupport != 0) { + status_and_caps.second.preambleSupport >>= 1; + preamble <<= 1; + } std::vector configs; RttConfig config; int cmdId = 55; @@ -148,13 +160,13 @@ TEST_P(WifiRttControllerHidlTest, RangeRequest_1_4) { config.addr[i] = i; } config.type = RttType::ONE_SIDED; - config.peer = RttPeerType::STA; + config.peer = RttPeerType::AP; config.channel.width = WifiChannelWidthInMhz::WIDTH_80; config.channel.centerFreq = 5765; config.channel.centerFreq0 = 5775; config.channel.centerFreq1 = 0; config.bw = RttBw::BW_80MHZ; - config.preamble = RttPreamble::HE; + config.preamble = (RttPreamble)preamble; config.mustRequestLci = false; config.mustRequestLcr = false; config.burstPeriod = 0; From fbf9d924a20607bea561c49c2c2531005773eb46 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Mon, 6 Apr 2020 23:00:50 -0700 Subject: [PATCH 0803/1022] Add libvtswidevine dep to VtsHalDrmV1_3TargetTest Bug: 150468341 Test: atest VtsHalDrmV1_3TargetTest Change-Id: I3885efd35c97a5451881c2f6dd8fdf86bf12d089 --- drm/1.3/vts/functional/Android.bp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drm/1.3/vts/functional/Android.bp b/drm/1.3/vts/functional/Android.bp index ac1f912c08..bd9db85251 100644 --- a/drm/1.3/vts/functional/Android.bp +++ b/drm/1.3/vts/functional/Android.bp @@ -71,6 +71,20 @@ cc_test { "android.hardware.drm@1.0-helper", "libdrmvtshelper", ], + arch: { + arm: { + data: [":libvtswidevine-arm-prebuilts"], + }, + arm64: { + data: [":libvtswidevine-arm64-prebuilts"], + }, + x86: { + data: [":libvtswidevine-x86-prebuilts"], + }, + x86_64: { + data: [":libvtswidevine-x86_64-prebuilts"], + }, + }, test_suites: [ "general-tests", "vts-core", From 6a222a3eec395ff4196675b513fa6878916c8395 Mon Sep 17 00:00:00 2001 From: Slava Shklyaev Date: Tue, 7 Apr 2020 13:20:47 +0100 Subject: [PATCH 0804/1022] Update loopTimeoutDuration documentation in NNAPI Bug: 149686804 Test: m Change-Id: I0096a2fc2e579d39a2d59a605a4217d53a381691 --- current.txt | 2 +- neuralnetworks/1.3/IPreparedModel.hal | 36 +++++++++++---------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/current.txt b/current.txt index 2677eb116a..656f5c7d61 100644 --- a/current.txt +++ b/current.txt @@ -711,7 +711,7 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 278817920bfd5292a7713f97f1832cca53de3de640f7670e413d97c6e7fd581c android.hardware.neuralnetworks@1.3::IDevice 127ba11efb8220dc3aec9a8f441b59eaf1c68d7f03f577833e1824de75a36b17 android.hardware.neuralnetworks@1.3::IExecutionCallback 6e904be0ddca5ae1de8eba020e6c38ed935ea7d80cd08f47787f137a0ca58555 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback -2b0b10d2ea7a18a4048cd0eb83d35c19a817aeee95f65807fc31f4ef21381397 android.hardware.neuralnetworks@1.3::IPreparedModel +ee9dc34b9925b8367b1111c72bd6d9d375432735e451572ca5a665d8516a7744 android.hardware.neuralnetworks@1.3::IPreparedModel eee3430cc86c97c7b407495863d8fb61da6f1a64b7721e77b9b4909b11b174e9 android.hardware.neuralnetworks@1.3::IPreparedModelCallback acf84925f8ee0a651f2ec547ac334034de266479b93af5434f6c1f25e66aba96 android.hardware.neuralnetworks@1.3::types b454df853441c12f6e425e8a60dd29fda20f5e6e39b93d1103e4b37495db38aa android.hardware.radio@1.5::IRadio diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal index a1814b5156..e7d63f4851 100644 --- a/neuralnetworks/1.3/IPreparedModel.hal +++ b/neuralnetworks/1.3/IPreparedModel.hal @@ -92,13 +92,11 @@ interface IPreparedModel extends @1.2::IPreparedModel { * executing a {@link OperationType::WHILE} * operation. If a loop condition model does not * output false within this duration, the - * execution must be aborted. If the model - * contains a {@link OperationType::WHILE} - * operation and no loop timeout duration is - * provided, the maximum amount of time is {@link - * LoopTimeoutDurationNs::DEFAULT}. When - * provided, the duration must not exceed {@link - * LoopTimeoutDurationNs::MAXIMUM}. + * execution must be aborted. If no loop timeout + * duration is provided, the maximum amount of + * time is {@link LoopTimeoutDurationNs::DEFAULT}. + * When provided, the duration must not exceed + * {@link LoopTimeoutDurationNs::MAXIMUM}. * @param callback A callback object used to return the error status of * the execution, shape information of model output operands, and * duration of execution. The callback object's notify function must @@ -170,13 +168,11 @@ interface IPreparedModel extends @1.2::IPreparedModel { * executing a {@link OperationType::WHILE} * operation. If a loop condition model does not * output false within this duration, the - * execution must be aborted. If the model - * contains a {@link OperationType::WHILE} - * operation and no loop timeout duration is - * provided, the maximum amount of time is {@link - * LoopTimeoutDurationNs::DEFAULT}. When - * provided, the duration must not exceed {@link - * LoopTimeoutDurationNs::MAXIMUM}. + * execution must be aborted. If no loop timeout + * duration is provided, the maximum amount of + * time is {@link LoopTimeoutDurationNs::DEFAULT}. + * When provided, the duration must not exceed + * {@link LoopTimeoutDurationNs::MAXIMUM}. * @return status Error status of the execution, must be: * - NONE if execution is performed successfully * - DEVICE_UNAVAILABLE if driver is offline or busy @@ -258,13 +254,11 @@ interface IPreparedModel extends @1.2::IPreparedModel { * executing a {@link OperationType::WHILE} * operation. If a loop condition model does not * output false within this duration, the - * execution must be aborted. If the model - * contains a {@link OperationType::WHILE} - * operation and no loop timeout duration is - * provided, the maximum amount of time is {@link - * LoopTimeoutDurationNs::DEFAULT}. When - * provided, the duration must not exceed {@link - * LoopTimeoutDurationNs::MAXIMUM}. + * execution must be aborted. If no loop timeout + * duration is provided, the maximum amount of + * time is {@link LoopTimeoutDurationNs::DEFAULT}. + * When provided, the duration must not exceed + * {@link LoopTimeoutDurationNs::MAXIMUM}. * @param duration The length of time within which the execution is expected * to complete after all sync fences in waitFor are signaled. * If the execution cannot be finished within the duration, From cdc9be8c7d9128173a5add095db993e2e7ded991 Mon Sep 17 00:00:00 2001 From: Rick Chen Date: Tue, 7 Apr 2020 22:51:13 +0800 Subject: [PATCH 0805/1022] Adds context_hub group to sensors HAL Bug: 152005392 Bug: 152727489 Test: Compile pass. Verify sensor function. Signed-off-by: Rick Chen Change-Id: Ifd7b9239a732619307bbb2e99d37791915fe7dc1 --- .../multihal/android.hardware.sensors@2.0-service-multihal.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc index a4da3b084b..0b3d4c2dce 100644 --- a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc +++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc @@ -1,7 +1,7 @@ service vendor.sensors-hal-2-0-multihal /vendor/bin/hw/android.hardware.sensors@2.0-service.multihal class hal user system - group system wakelock + group system wakelock context_hub writepid /dev/cpuset/system-background/tasks capabilities BLOCK_SUSPEND rlimit rtprio 10 10 From ee9f3acae3f28437998bd10b7679cda6a9932ef2 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Mon, 2 Mar 2020 13:40:17 -0800 Subject: [PATCH 0806/1022] Push prebuilt libvtswidevine to device for drm HAL test Bug: 143220441 Test: atest VtsHalDrmV1_3TargetTest Change-Id: I08af2bf9524b0bbb362c28eceef5e6642545ecc7 (cherry picked from commit d7c88e3e551f4fd434e0d055428e2f31df1502a3) --- drm/1.3/vts/functional/AndroidTest.xml | 33 ++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 drm/1.3/vts/functional/AndroidTest.xml diff --git a/drm/1.3/vts/functional/AndroidTest.xml b/drm/1.3/vts/functional/AndroidTest.xml new file mode 100644 index 0000000000..338430f010 --- /dev/null +++ b/drm/1.3/vts/functional/AndroidTest.xml @@ -0,0 +1,33 @@ + + + + From 052ccf2b6f5510323a3cf1f2807613bf7fa289c1 Mon Sep 17 00:00:00 2001 From: Hayden Gomes Date: Wed, 1 Apr 2020 15:52:55 -0700 Subject: [PATCH 0807/1022] Adding basic lshal support for AudioControl Dumps status of focus listener Bug: 148098383 Test: adb shell lshal debug android.hardware.automotive.audiocontrol@2.0::IAudioControl/default --help Change-Id: I90d9f2b41bdee704b77457262f23a39d22c38f0a --- .../audiocontrol/2.0/default/AudioControl.cpp | 80 +++++++++++++++++-- .../audiocontrol/2.0/default/AudioControl.h | 8 +- 2 files changed, 80 insertions(+), 8 deletions(-) diff --git a/automotive/audiocontrol/2.0/default/AudioControl.cpp b/automotive/audiocontrol/2.0/default/AudioControl.cpp index 6505e34765..eac3514960 100644 --- a/automotive/audiocontrol/2.0/default/AudioControl.cpp +++ b/automotive/audiocontrol/2.0/default/AudioControl.cpp @@ -1,12 +1,38 @@ +/* + * 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 "AudioControl.h" #include +#include #include +#include + #include "CloseHandle.h" namespace android::hardware::automotive::audiocontrol::V2_0::implementation { +using ::android::base::EqualsIgnoreCase; +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_string; + +static const float kLowerBound = -1.0f; +static const float kUpperBound = 1.0f; + AudioControl::AudioControl() {} Return> AudioControl::registerFocusListener(const sp& listener) { @@ -29,27 +55,29 @@ Return> AudioControl::registerFocusListener(const sp AudioControl::setBalanceTowardRight(float value) { - // For completeness, lets bounds check the input... if (isValidValue(value)) { - LOG(ERROR) << "Balance value out of range -1 to 1 at " << value; - } else { // Just log in this default mock implementation LOG(INFO) << "Balance set to " << value; + } else { + LOG(ERROR) << "Balance value out of range -1 to 1 at " << value; } return Void(); } Return AudioControl::setFadeTowardFront(float value) { - // For completeness, lets bounds check the input... - if (isValidValue(value)) { - LOG(ERROR) << "Fader value out of range -1 to 1 at " << value; - } else { + if (!isValidValue(value)) { // Just log in this default mock implementation LOG(INFO) << "Fader set to " << value; + } else { + LOG(ERROR) << "Fader value out of range -1 to 1 at " << value; } return Void(); } +bool AudioControl::isValidValue(float value) { + return (value > kLowerBound) && (value < kUpperBound); +} + Return AudioControl::onAudioFocusChange(hidl_bitfield usage, int zoneId, hidl_bitfield focusChange) { LOG(INFO) << "Focus changed: " << static_cast(focusChange) << " for usage " @@ -57,4 +85,42 @@ Return AudioControl::onAudioFocusChange(hidl_bitfield usage, i return Void(); } +Return AudioControl::debug(const hidl_handle& fd, const hidl_vec& options) { + if (fd.getNativeHandle() == nullptr || fd->numFds == 0) { + LOG(ERROR) << "Invalid parameters passed to debug()"; + return Void(); + } + + cmdDump(fd->data[0], options); + return Void(); +} + +void AudioControl::cmdDump(int fd, const hidl_vec& options) { + if (options.size() == 0) { + dump(fd); + return; + } + + std::string option = options[0]; + if (EqualsIgnoreCase(option, "--help")) { + cmdHelp(fd); + } else { + dprintf(fd, "Invalid option: %s\n", option.c_str()); + } +} + +void AudioControl::dump(int fd) { + if (mFocusListener == nullptr) { + dprintf(fd, "No focus listener registered\n"); + } else { + dprintf(fd, "Focus listener registered\n"); + } +} + +void AudioControl::cmdHelp(int fd) const { + dprintf(fd, "Usage: \n\n"); + dprintf(fd, "[no args]: dumps focus listener status\n"); + dprintf(fd, "--help: shows this help\n"); +} + } // namespace android::hardware::automotive::audiocontrol::V2_0::implementation diff --git a/automotive/audiocontrol/2.0/default/AudioControl.h b/automotive/audiocontrol/2.0/default/AudioControl.h index 475a693cb7..6a3f21b55b 100644 --- a/automotive/audiocontrol/2.0/default/AudioControl.h +++ b/automotive/audiocontrol/2.0/default/AudioControl.h @@ -35,13 +35,19 @@ class AudioControl : public IAudioControl { hidl_bitfield focusChange); Return setBalanceTowardRight(float value) override; Return setFadeTowardFront(float value) override; + Return debug(const hidl_handle& fd, const hidl_vec& options) override; // Implementation details AudioControl(); private: sp mFocusListener; - static bool isValidValue(float value) { return (value > 1.0f) || (value < -1.0f); } + + static bool isValidValue(float value); + + void cmdDump(int fd, const hidl_vec& options); + void cmdHelp(int fd) const; + void dump(int fd); }; } // namespace android::hardware::automotive::audiocontrol::V2_0::implementation From f956a7ea0a5432c5cd1c60d20c85e2fd4ef7eb1e Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Tue, 25 Feb 2020 15:42:48 -0800 Subject: [PATCH 0808/1022] Push prebuilt libvtswidevine to device for drm HAL tests Bug: 143220441 Test: atest VtsHalDrmV1_0TargetTest \ VtsHalDrmV1_1TargetTest\ VtsHalDrmV1_2TargetTest Change-Id: I4ad91c99956525120549321d227aaf6864877c76 Merged-In: I4ad91c99956525120549321d227aaf6864877c76 --- drm/1.0/vts/functional/Android.bp | 16 ++++++++++++- drm/1.0/vts/functional/AndroidTest.xml | 33 ++++++++++++++++++++++++++ drm/1.1/vts/functional/Android.bp | 16 ++++++++++++- drm/1.1/vts/functional/AndroidTest.xml | 33 ++++++++++++++++++++++++++ drm/1.2/vts/functional/Android.bp | 14 +++++++++++ drm/1.2/vts/functional/AndroidTest.xml | 33 ++++++++++++++++++++++++++ 6 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 drm/1.0/vts/functional/AndroidTest.xml create mode 100644 drm/1.1/vts/functional/AndroidTest.xml create mode 100644 drm/1.2/vts/functional/AndroidTest.xml diff --git a/drm/1.0/vts/functional/Android.bp b/drm/1.0/vts/functional/Android.bp index 235bfb406f..02d4f418f1 100644 --- a/drm/1.0/vts/functional/Android.bp +++ b/drm/1.0/vts/functional/Android.bp @@ -24,7 +24,7 @@ cc_library_static { "vendor_modules.cpp", ], static_libs: [ - "android.hardware.drm@1.0-helper", + "android.hardware.drm@1.0-helper", ], export_include_dirs: ["include"], } @@ -84,6 +84,20 @@ cc_test { "libcrypto_static", "libdrmvtshelper", ], + arch: { + arm: { + data: [":libvtswidevine-arm-prebuilts"], + }, + arm64: { + data: [":libvtswidevine-arm64-prebuilts"], + }, + x86: { + data: [":libvtswidevine-x86-prebuilts"], + }, + x86_64: { + data: [":libvtswidevine-x86_64-prebuilts"], + }, + }, test_suites: [ "general-tests", "vts-core", diff --git a/drm/1.0/vts/functional/AndroidTest.xml b/drm/1.0/vts/functional/AndroidTest.xml new file mode 100644 index 0000000000..92ea7e48dd --- /dev/null +++ b/drm/1.0/vts/functional/AndroidTest.xml @@ -0,0 +1,33 @@ + + + + diff --git a/drm/1.1/vts/functional/Android.bp b/drm/1.1/vts/functional/Android.bp index e08d760ea4..c31aee0827 100644 --- a/drm/1.1/vts/functional/Android.bp +++ b/drm/1.1/vts/functional/Android.bp @@ -60,11 +60,25 @@ cc_test { "drm_hal_test_main.cpp", ], whole_static_libs: [ - "android.hardware.drm@1.1-vts" + "android.hardware.drm@1.1-vts", ], shared_libs: [ "android.hardware.drm@1.1", ], + arch: { + arm: { + data: [":libvtswidevine-arm-prebuilts"], + }, + arm64: { + data: [":libvtswidevine-arm64-prebuilts"], + }, + x86: { + data: [":libvtswidevine-x86-prebuilts"], + }, + x86_64: { + data: [":libvtswidevine-x86_64-prebuilts"], + }, + }, test_suites: [ "general-tests", "vts-core", diff --git a/drm/1.1/vts/functional/AndroidTest.xml b/drm/1.1/vts/functional/AndroidTest.xml new file mode 100644 index 0000000000..65c45accee --- /dev/null +++ b/drm/1.1/vts/functional/AndroidTest.xml @@ -0,0 +1,33 @@ + + + + diff --git a/drm/1.2/vts/functional/Android.bp b/drm/1.2/vts/functional/Android.bp index ecc7d6c592..09727842d0 100644 --- a/drm/1.2/vts/functional/Android.bp +++ b/drm/1.2/vts/functional/Android.bp @@ -70,6 +70,20 @@ cc_test { "libcrypto_static", "libdrmvtshelper", ], + arch: { + arm: { + data: [":libvtswidevine-arm-prebuilts"], + }, + arm64: { + data: [":libvtswidevine-arm64-prebuilts"], + }, + x86: { + data: [":libvtswidevine-x86-prebuilts"], + }, + x86_64: { + data: [":libvtswidevine-x86_64-prebuilts"], + }, + }, test_suites: [ "general-tests", "vts-core", diff --git a/drm/1.2/vts/functional/AndroidTest.xml b/drm/1.2/vts/functional/AndroidTest.xml new file mode 100644 index 0000000000..5da38aefaa --- /dev/null +++ b/drm/1.2/vts/functional/AndroidTest.xml @@ -0,0 +1,33 @@ + + + + From f8c91f58553cc24483b12f0e01cfe9712adc0882 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Tue, 31 Mar 2020 21:13:59 +0000 Subject: [PATCH 0809/1022] Convert VtsHalBluetoothA2dpV1_0TargetTest to be parameterized test Bug: 142397658 Test: atest VtsHalBluetoothA2dpV1_0TargetTest Change-Id: Ib7ba41f4da12c60658e938fa14c53ba37c74bd1a Merged-In: Ib7ba41f4da12c60658e938fa14c53ba37c74bd1a --- bluetooth/a2dp/1.0/vts/functional/Android.bp | 2 +- .../VtsHalBluetoothA2dpV1_0TargetTest.cpp | 49 +++++-------------- 2 files changed, 14 insertions(+), 37 deletions(-) diff --git a/bluetooth/a2dp/1.0/vts/functional/Android.bp b/bluetooth/a2dp/1.0/vts/functional/Android.bp index e50e16730a..5b8410adc5 100644 --- a/bluetooth/a2dp/1.0/vts/functional/Android.bp +++ b/bluetooth/a2dp/1.0/vts/functional/Android.bp @@ -23,5 +23,5 @@ cc_test { "android.hardware.bluetooth.a2dp@1.0", "libbluetooth-types", ], - test_suites: ["general-tests"], + test_suites: ["general-tests", "vts-core"], } diff --git a/bluetooth/a2dp/1.0/vts/functional/VtsHalBluetoothA2dpV1_0TargetTest.cpp b/bluetooth/a2dp/1.0/vts/functional/VtsHalBluetoothA2dpV1_0TargetTest.cpp index d8d0c29828..44b138a894 100644 --- a/bluetooth/a2dp/1.0/vts/functional/VtsHalBluetoothA2dpV1_0TargetTest.cpp +++ b/bluetooth/a2dp/1.0/vts/functional/VtsHalBluetoothA2dpV1_0TargetTest.cpp @@ -19,12 +19,14 @@ #include #include #include +#include #include +#include +#include +#include #include #include -#include -#include using ::android::sp; using ::android::hardware::Return; @@ -38,34 +40,12 @@ using ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload; using ::android::hardware::bluetooth::a2dp::V1_0::SampleRate; using ::android::hardware::bluetooth::a2dp::V1_0::Status; -// Test environment for Bluetooth HIDL A2DP HAL. -class BluetoothA2dpHidlEnvironment - : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static BluetoothA2dpHidlEnvironment* Instance() { - static BluetoothA2dpHidlEnvironment* instance = - new BluetoothA2dpHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { - registerTestService(); - } - - private: - BluetoothA2dpHidlEnvironment() {} -}; - // The main test class for Bluetooth A2DP HIDL HAL. -class BluetoothA2dpHidlTest : public ::testing::VtsHalHidlTargetTestBase { +class BluetoothA2dpHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { // currently test passthrough mode only - audio_offload = - ::testing::VtsHalHidlTargetTestBase::getService( - BluetoothA2dpHidlEnvironment::Instance() - ->getServiceName()); + audio_offload = IBluetoothAudioOffload::getService(GetParam()); ASSERT_NE(audio_offload, nullptr); audio_host = new BluetoothAudioHost(*this); @@ -115,19 +95,16 @@ class BluetoothA2dpHidlTest : public ::testing::VtsHalHidlTargetTestBase { }; // Empty test: Initialize()/Close() are called in SetUp()/TearDown(). -TEST_F(BluetoothA2dpHidlTest, InitializeAndClose) {} +TEST_P(BluetoothA2dpHidlTest, InitializeAndClose) {} // Test start and end session -TEST_F(BluetoothA2dpHidlTest, StartAndEndSession) { +TEST_P(BluetoothA2dpHidlTest, StartAndEndSession) { EXPECT_EQ(Status::SUCCESS, audio_offload->startSession(audio_host, codec)); audio_offload->endSession(); } -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(BluetoothA2dpHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - BluetoothA2dpHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; -} +INSTANTIATE_TEST_SUITE_P( + PerInstance, BluetoothA2dpHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + IBluetoothAudioOffload::descriptor)), + android::hardware::PrintInstanceNameToString); \ No newline at end of file From d6fea1eaa10af7ab8a498957202b55de33ff45cb Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Mon, 23 Mar 2020 23:01:41 +0000 Subject: [PATCH 0810/1022] Convert MediaOmx tests to parameterized gtest Bug: 142950220 Test: atest VtsHalMediaOmxV1_0TargetMasterTest \ VtsHalMediaOmxV1_0TargetComponentTest \ VtsHalMediaOmxV1_0TargetAudioEncTest \ VtsHalMediaOmxV1_0TargetAudioDecTest \ VtsHalMediaOmxV1_0TargetVideoDecTest \ VtsHalMediaOmxV1_0TargetVideoEncTest Change-Id: Id1b8f6073c98db36c0ac86a881e7220ecfd0a71f Merged-In: Id1b8f6073c98db36c0ac86a881e7220ecfd0a71f --- media/Android.bp | 27 ++++ media/omx/1.0/vts/functional/README.md | 14 +- media/omx/1.0/vts/functional/audio/Android.bp | 20 ++- .../VtsHalMediaOmxV1_0TargetAudioDecTest.cpp | 133 ++++++++-------- .../VtsHalMediaOmxV1_0TargetAudioDecTest.xml | 56 +++++++ .../VtsHalMediaOmxV1_0TargetAudioEncTest.cpp | 96 ++++++------ .../VtsHalMediaOmxV1_0TargetAudioEncTest.xml | 56 +++++++ .../audio/media_audio_hidl_test_common.cpp | 1 - .../omx/1.0/vts/functional/common/Android.bp | 2 +- .../common/media_hidl_test_common.cpp | 50 +++++- .../common/media_hidl_test_common.h | 97 +++--------- .../1.0/vts/functional/component/Android.bp | 5 +- .../VtsHalMediaOmxV1_0TargetComponentTest.cpp | 137 ++++++++--------- .../omx/1.0/vts/functional/master/Android.bp | 5 +- .../VtsHalMediaOmxV1_0TargetMasterTest.cpp | 58 ++++--- media/omx/1.0/vts/functional/video/Android.bp | 18 ++- .../VtsHalMediaOmxV1_0TargetVideoDecTest.cpp | 143 +++++++++--------- .../VtsHalMediaOmxV1_0TargetVideoDecTest.xml | 56 +++++++ .../VtsHalMediaOmxV1_0TargetVideoEncTest.cpp | 117 +++++++------- .../VtsHalMediaOmxV1_0TargetVideoEncTest.xml | 56 +++++++ .../video/media_video_hidl_test_common.cpp | 1 - .../video/media_video_hidl_test_common.h | 2 + 22 files changed, 709 insertions(+), 441 deletions(-) create mode 100644 media/Android.bp create mode 100644 media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.xml create mode 100644 media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.xml create mode 100644 media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.xml create mode 100644 media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.xml diff --git a/media/Android.bp b/media/Android.bp new file mode 100644 index 0000000000..267c02bdf4 --- /dev/null +++ b/media/Android.bp @@ -0,0 +1,27 @@ +// +// 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. +// + +filegroup { + name: "media_omx_audio_res", + path: "res", + srcs: ["res/*hz*"], +} + +filegroup { + name: "media_omx_video_res", + path: "res", + srcs: ["res/*fps*"], +} diff --git a/media/omx/1.0/vts/functional/README.md b/media/omx/1.0/vts/functional/README.md index 274b30d8be..c5a686747f 100644 --- a/media/omx/1.0/vts/functional/README.md +++ b/media/omx/1.0/vts/functional/README.md @@ -6,29 +6,27 @@ The scope of the tests presented here is not restricted solely to testing omx ha #### master : Functionality of master is to enumerate all the omx components (and the roles it supports) available in android media framework. -usage: VtsHalMediaOmxV1\_0TargetMasterTest -I default +usage: atest VtsHalMediaOmxV1\_0TargetMasterTest #### component : This folder includes test fixtures that tests aspects common to all omx compatible components. For instance, port enabling/disabling, enumerating port formats, state transitions, flush, ..., stay common to all components irrespective of the service they offer. Test fixtures here are directed towards testing these (omx core). Every standard OMX compatible component is expected to pass these tests. -usage: VtsHalMediaOmxV1\_0TargetComponentTest -I default -C -R +usage: atest VtsHalMediaOmxV1\_0TargetComponentTest #### audio : This folder includes test fixtures associated with testing audio encoder and decoder components such as simple encoding of a raw clip or decoding of an elementary stream, end of stream test, timestamp deviations test, flush test and so on. These tests are aimed towards testing the plugin that connects the component to the omx core. usage: -VtsHalMediaOmxV1\_0TargetAudioDecTest -I default -C -R audio_decoder. -P /data/local/tmp/media/ +atest VtsHalMediaOmxV1\_0TargetAudioDecTest -VtsHalMediaOmxV1\_0TargetAudioEncTest -I default -C -R audio_encoder. -P /data/local/tmp/media/ +atest VtsHalMediaOmxV1\_0TargetAudioEncTest #### video : This folder includes test fixtures associated with testing video encoder and decoder components such as simple encoding of a raw clip or decoding of an elementary stream, end of stream test, timestamp deviations test, flush test and so on. These tests are aimed towards testing the plugin that connects the component to the omx core. usage: -VtsHalMediaOmxV1\_0TargetVideoDecTest -I default -C -R video_decoder. -P /data/local/tmp/media/ +atest VtsHalMediaOmxV1\_0TargetVideoDecTest -VtsHalMediaOmxV1\_0TargetVideoEncTest -I default -C -R video_encoder. -P /data/local/tmp/media/ - -While tesing audio/video encoder, decoder components, test fixtures require input files. These input are files are present in the folder 'res'. Before running the tests all the files in 'res' have to be placed in '/data/local/tmp/media' or a path of your choice and this path needs to be provided as an argument to the test application +atest VtsHalMediaOmxV1\_0TargetVideoEncTest diff --git a/media/omx/1.0/vts/functional/audio/Android.bp b/media/omx/1.0/vts/functional/audio/Android.bp index 7418bb4226..532521e0fe 100644 --- a/media/omx/1.0/vts/functional/audio/Android.bp +++ b/media/omx/1.0/vts/functional/audio/Android.bp @@ -16,22 +16,30 @@ cc_test { name: "VtsHalMediaOmxV1_0TargetAudioEncTest", + stem: "vts_hal_media_omx_v1_0_audio_enc_test", defaults: ["VtsHalMediaOmxV1_0Defaults"], srcs: [ "VtsHalMediaOmxV1_0TargetAudioEncTest.cpp", - "media_audio_hidl_test_common.cpp" + "media_audio_hidl_test_common.cpp", + ], + data: [":media_omx_audio_res"], + test_config: "VtsHalMediaOmxV1_0TargetAudioEncTest.xml", + test_suites: [ + "vts-core", ], - test_suites: ["general-tests"], } cc_test { name: "VtsHalMediaOmxV1_0TargetAudioDecTest", + stem: "vts_hal_media_omx_v1_0_audio_dec_test", defaults: ["VtsHalMediaOmxV1_0Defaults"], srcs: [ "VtsHalMediaOmxV1_0TargetAudioDecTest.cpp", - "media_audio_hidl_test_common.cpp" + "media_audio_hidl_test_common.cpp", + ], + data: [":media_omx_audio_res"], + test_config: "VtsHalMediaOmxV1_0TargetAudioDecTest.xml", + test_suites: [ + "vts-core", ], - test_suites: ["general-tests"], } - - diff --git a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp index 4543c01252..3ed567044a 100644 --- a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp +++ b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include using ::android::hardware::media::omx::V1_0::IOmx; using ::android::hardware::media::omx::V1_0::IOmxObserver; @@ -44,48 +46,45 @@ using ::android::hardware::hidl_vec; using ::android::hardware::hidl_string; using ::android::sp; -#include #include #include -#include #include -static ComponentTestEnvironment* gEnv = nullptr; +// Resource directory +std::string sResourceDir = ""; // audio decoder test fixture class -class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { - private: - typedef ::testing::VtsHalHidlTargetTestBase Super; - public: - ::std::string getTestCaseInfo() const override { - return ::std::string() + - "Component: " + gEnv->getComponent().c_str() + " | " + - "Role: " + gEnv->getRole().c_str() + " | " + - "Instance: " + gEnv->getInstance().c_str() + " | " + - "Res: " + gEnv->getRes().c_str(); +class AudioDecHidlTest + : public ::testing::TestWithParam> { + public: + ::std::string getTestCaseInfo() const { + return ::std::string() + "Component: " + component_ + " | " + "Role: " + role_ + " | " + + "Instance: " + instance_ + " | " + "Res: " + sResourceDir; } virtual void SetUp() override { - Super::SetUp(); + instance_ = std::get<0>(GetParam()); + component_ = std::get<1>(GetParam()); + role_ = std::get<2>(GetParam()); + ASSERT_NE(sResourceDir.empty(), true); + disableTest = false; android::hardware::media::omx::V1_0::Status status; - omx = Super::getService(gEnv->getInstance()); + omx = IOmx::getService(instance_); ASSERT_NE(omx, nullptr); observer = new CodecObserver([this](Message msg, const BufferInfo* buffer) { handleMessage(msg, buffer); }); ASSERT_NE(observer, nullptr); - if (strncmp(gEnv->getComponent().c_str(), "OMX.", 4) != 0) - disableTest = true; - EXPECT_TRUE(omx->allocateNode( - gEnv->getComponent(), observer, - [&](android::hardware::media::omx::V1_0::Status _s, - sp const& _nl) { - status = _s; - this->omxNode = _nl; - }) - .isOk()); + if (component_.find("OMX.") != 0) disableTest = true; + EXPECT_TRUE(omx->allocateNode(component_, observer, + [&](android::hardware::media::omx::V1_0::Status _s, + sp const& _nl) { + status = _s; + this->omxNode = _nl; + }) + .isOk()); if (status == android::hardware::media::omx::V1_0::Status::NAME_NOT_FOUND) { disableTest = true; std::cout << "[ WARN ] Test Disabled, component not present\n"; @@ -93,7 +92,7 @@ class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { } ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); ASSERT_NE(omxNode, nullptr); - ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role"; + ASSERT_NE(role_.empty(), true) << "Invalid Component Role"; struct StringToName { const char* Name; standardComp CompName; @@ -108,7 +107,7 @@ class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { sizeof(kStringToName) / sizeof(kStringToName[0]); const char* pch; char substring[OMX_MAX_STRINGNAME_SIZE]; - strcpy(substring, gEnv->getRole().c_str()); + strcpy(substring, role_.c_str()); pch = strchr(substring, '.'); ASSERT_NE(pch, nullptr); compName = unknown_comp; @@ -153,11 +152,8 @@ class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { timestampDevTest = false; isSecure = false; size_t suffixLen = strlen(".secure"); - if (strlen(gEnv->getComponent().c_str()) >= suffixLen) { - isSecure = - !strcmp(gEnv->getComponent().c_str() + - strlen(gEnv->getComponent().c_str()) - suffixLen, - ".secure"); + if (component_.rfind(".secure") == component_.length() - suffixLen) { + isSecure = true; } if (isSecure) disableTest = true; if (disableTest) std::cout << "[ WARN ] Test Disabled \n"; @@ -172,7 +168,6 @@ class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { EXPECT_TRUE((omxNode->freeNode()).isOk()); omxNode = nullptr; } - Super::TearDown(); } // callback function to process messages received by onMessages() from IL @@ -249,6 +244,10 @@ class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { unknown_comp, }; + std::string component_; + std::string role_; + std::string instance_; + sp omx; sp observer; sp omxNode; @@ -656,21 +655,21 @@ void decodeNFrames(sp omxNode, sp observer, } // set component role -TEST_F(AudioDecHidlTest, SetRole) { +TEST_P(AudioDecHidlTest, SetRole) { description("Test Set Component Role"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); } // port format enumeration -TEST_F(AudioDecHidlTest, EnumeratePortFormat) { +TEST_P(AudioDecHidlTest, EnumeratePortFormat) { description("Test Component on Mandatory Port Parameters (Port Format)"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms); @@ -687,12 +686,12 @@ TEST_F(AudioDecHidlTest, EnumeratePortFormat) { // test port settings reconfiguration, elementary stream decode and timestamp // deviation -TEST_F(AudioDecHidlTest, DecodeTest) { +TEST_P(AudioDecHidlTest, DecodeTest) { description("Tests Port Reconfiguration, Decode and timestamp deviation"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms); @@ -702,8 +701,8 @@ TEST_F(AudioDecHidlTest, DecodeTest) { kPortIndexOutput = kPortIndexInput + 1; } char mURL[512], info[512]; - strcpy(mURL, gEnv->getRes().c_str()); - strcpy(info, gEnv->getRes().c_str()); + strcpy(mURL, sResourceDir.c_str()); + strcpy(info, sResourceDir.c_str()); GetURLForComponent(compName, mURL, info); std::ifstream eleStream, eleInfo; @@ -776,12 +775,12 @@ TEST_F(AudioDecHidlTest, DecodeTest) { } // end of sequence test -TEST_F(AudioDecHidlTest, EOSTest_M) { +TEST_P(AudioDecHidlTest, EOSTest_M) { description("Test end of stream monkeying"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms); @@ -840,12 +839,12 @@ TEST_F(AudioDecHidlTest, EOSTest_M) { } // end of sequence test -TEST_F(AudioDecHidlTest, ThumbnailTest) { +TEST_P(AudioDecHidlTest, ThumbnailTest) { description("Test Request for thumbnail"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms); @@ -855,8 +854,8 @@ TEST_F(AudioDecHidlTest, ThumbnailTest) { kPortIndexOutput = kPortIndexInput + 1; } char mURL[512], info[512]; - strcpy(mURL, gEnv->getRes().c_str()); - strcpy(info, gEnv->getRes().c_str()); + strcpy(mURL, sResourceDir.c_str()); + strcpy(info, sResourceDir.c_str()); GetURLForComponent(compName, mURL, info); std::ifstream eleStream, eleInfo; @@ -954,12 +953,12 @@ TEST_F(AudioDecHidlTest, ThumbnailTest) { } // end of sequence test -TEST_F(AudioDecHidlTest, SimpleEOSTest) { +TEST_P(AudioDecHidlTest, SimpleEOSTest) { description("Test end of stream"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms); @@ -969,8 +968,8 @@ TEST_F(AudioDecHidlTest, SimpleEOSTest) { kPortIndexOutput = kPortIndexInput + 1; } char mURL[512], info[512]; - strcpy(mURL, gEnv->getRes().c_str()); - strcpy(info, gEnv->getRes().c_str()); + strcpy(mURL, sResourceDir.c_str()); + strcpy(info, sResourceDir.c_str()); GetURLForComponent(compName, mURL, info); std::ifstream eleStream, eleInfo; @@ -1046,12 +1045,12 @@ TEST_F(AudioDecHidlTest, SimpleEOSTest) { } // test input/output port flush -TEST_F(AudioDecHidlTest, FlushTest) { +TEST_P(AudioDecHidlTest, FlushTest) { description("Test Flush"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms); @@ -1061,8 +1060,8 @@ TEST_F(AudioDecHidlTest, FlushTest) { kPortIndexOutput = kPortIndexInput + 1; } char mURL[512], info[512]; - strcpy(mURL, gEnv->getRes().c_str()); - strcpy(info, gEnv->getRes().c_str()); + strcpy(mURL, sResourceDir.c_str()); + strcpy(info, sResourceDir.c_str()); GetURLForComponent(compName, mURL, info); std::ifstream eleStream, eleInfo; @@ -1153,15 +1152,21 @@ TEST_F(AudioDecHidlTest, FlushTest) { kPortIndexOutput)); } +INSTANTIATE_TEST_SUITE_P(PerInstance, AudioDecHidlTest, testing::ValuesIn(kTestParameters), + android::hardware::PrintInstanceTupleNameToString<>); + int main(int argc, char** argv) { - gEnv = new ComponentTestEnvironment(); - ::testing::AddGlobalTestEnvironment(gEnv); + kTestParameters = getTestParameters("audio_decoder"); ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - int status = gEnv->initFromOptions(argc, argv); - if (status == 0) { - status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); + + // Set the resource directory based on command line args. + // Test will fail to set up if the argument is not set. + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-P") == 0 && i < argc - 1) { + sResourceDir = argv[i + 1]; + break; + } } - return status; -} + + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.xml b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.xml new file mode 100644 index 0000000000..275fefe597 --- /dev/null +++ b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp index 0ebab886e4..32e6f4ce59 100644 --- a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp +++ b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include using ::android::hardware::media::omx::V1_0::IOmx; using ::android::hardware::media::omx::V1_0::IOmxObserver; @@ -44,48 +46,45 @@ using ::android::hardware::hidl_vec; using ::android::hardware::hidl_string; using ::android::sp; -#include #include #include -#include #include -static ComponentTestEnvironment* gEnv = nullptr; +// Resource directory +std::string sResourceDir = ""; // audio encoder test fixture class -class AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { - private: - typedef ::testing::VtsHalHidlTargetTestBase Super; - public: - ::std::string getTestCaseInfo() const override { - return ::std::string() + - "Component: " + gEnv->getComponent().c_str() + " | " + - "Role: " + gEnv->getRole().c_str() + " | " + - "Instance: " + gEnv->getInstance().c_str() + " | " + - "Res: " + gEnv->getRes().c_str(); +class AudioEncHidlTest + : public ::testing::TestWithParam> { + public: + ::std::string getTestCaseInfo() const { + return ::std::string() + "Component: " + component_ + " | " + "Role: " + role_ + " | " + + "Instance: " + instance_ + " | " + "Res: " + sResourceDir; } virtual void SetUp() override { - Super::SetUp(); + instance_ = std::get<0>(GetParam()); + component_ = std::get<1>(GetParam()); + role_ = std::get<2>(GetParam()); + ASSERT_NE(sResourceDir.empty(), true); + disableTest = false; android::hardware::media::omx::V1_0::Status status; - omx = Super::getService(gEnv->getInstance()); + omx = IOmx::getService(instance_); ASSERT_NE(omx, nullptr); observer = new CodecObserver([this](Message msg, const BufferInfo* buffer) { handleMessage(msg, buffer); }); ASSERT_NE(observer, nullptr); - if (strncmp(gEnv->getComponent().c_str(), "OMX.", 4) != 0) - disableTest = true; - EXPECT_TRUE(omx->allocateNode( - gEnv->getComponent(), observer, - [&](android::hardware::media::omx::V1_0::Status _s, - sp const& _nl) { - status = _s; - this->omxNode = _nl; - }) - .isOk()); + if (component_.find("OMX.") != 0) disableTest = true; + EXPECT_TRUE(omx->allocateNode(component_, observer, + [&](android::hardware::media::omx::V1_0::Status _s, + sp const& _nl) { + status = _s; + this->omxNode = _nl; + }) + .isOk()); if (status == android::hardware::media::omx::V1_0::Status::NAME_NOT_FOUND) { disableTest = true; std::cout << "[ WARN ] Test Disabled, component not present\n"; @@ -93,7 +92,7 @@ class AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { } ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); ASSERT_NE(omxNode, nullptr); - ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role"; + ASSERT_NE(role_.empty(), true) << "Invalid Component Role"; struct StringToName { const char* Name; standardComp CompName; @@ -105,7 +104,7 @@ class AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { sizeof(kStringToName) / sizeof(kStringToName[0]); const char* pch; char substring[OMX_MAX_STRINGNAME_SIZE]; - strcpy(substring, gEnv->getRole().c_str()); + strcpy(substring, role_.c_str()); pch = strchr(substring, '.'); ASSERT_NE(pch, nullptr); compName = unknown_comp; @@ -149,7 +148,6 @@ class AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { EXPECT_TRUE((omxNode->freeNode()).isOk()); omxNode = nullptr; } - Super::TearDown(); } // callback function to process messages received by onMessages() from IL @@ -190,6 +188,10 @@ class AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { unknown_comp, }; + std::string component_; + std::string role_; + std::string instance_; + sp omx; sp observer; sp omxNode; @@ -364,21 +366,21 @@ void encodeNFrames(sp omxNode, sp observer, } // set component role -TEST_F(AudioEncHidlTest, SetRole) { +TEST_P(AudioEncHidlTest, SetRole) { description("Test Set Component Role"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_.c_str()); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); } // port format enumeration -TEST_F(AudioEncHidlTest, EnumeratePortFormat) { +TEST_P(AudioEncHidlTest, EnumeratePortFormat) { description("Test Component on Mandatory Port Parameters (Port Format)"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms); @@ -394,12 +396,12 @@ TEST_F(AudioEncHidlTest, EnumeratePortFormat) { } // test raw stream encode -TEST_F(AudioEncHidlTest, SimpleEncodeTest) { +TEST_P(AudioEncHidlTest, SimpleEncodeTest) { description("Tests Basic encoding and EOS"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms); @@ -409,7 +411,7 @@ TEST_F(AudioEncHidlTest, SimpleEncodeTest) { kPortIndexOutput = kPortIndexInput + 1; } char mURL[512]; - strcpy(mURL, gEnv->getRes().c_str()); + strcpy(mURL, sResourceDir.c_str()); GetURLForComponent(compName, mURL); std::ifstream eleStream; @@ -484,15 +486,21 @@ TEST_F(AudioEncHidlTest, SimpleEncodeTest) { kPortIndexOutput)); } +INSTANTIATE_TEST_SUITE_P(PerInstance, AudioEncHidlTest, testing::ValuesIn(kTestParameters), + android::hardware::PrintInstanceTupleNameToString<>); + int main(int argc, char** argv) { - gEnv = new ComponentTestEnvironment(); - ::testing::AddGlobalTestEnvironment(gEnv); + kTestParameters = getTestParameters("audio_encoder"); ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - int status = gEnv->initFromOptions(argc, argv); - if (status == 0) { - status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); + + // Set the resource directory based on command line args. + // Test will fail to set up if the argument is not set. + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-P") == 0 && i < argc - 1) { + sResourceDir = argv[i + 1]; + break; + } } - return status; -} + + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.xml b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.xml new file mode 100644 index 0000000000..88b6c87d45 --- /dev/null +++ b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.cpp b/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.cpp index e7ae083012..7c3b23f097 100644 --- a/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.cpp +++ b/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.cpp @@ -44,7 +44,6 @@ using ::android::hardware::hidl_vec; using ::android::hardware::hidl_string; using ::android::sp; -#include #include #include #include diff --git a/media/omx/1.0/vts/functional/common/Android.bp b/media/omx/1.0/vts/functional/common/Android.bp index 5a79e55426..2c024a0c0c 100644 --- a/media/omx/1.0/vts/functional/common/Android.bp +++ b/media/omx/1.0/vts/functional/common/Android.bp @@ -23,7 +23,7 @@ cc_library_static { export_include_dirs: ["."], static_libs: [ - "VtsHalHidlTargetTestBase", + "libgtest", "libhidlmemory", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp index 8d4c022013..d9d11571c4 100644 --- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp +++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp @@ -56,17 +56,16 @@ using ::android::hardware::hidl_vec; using ::android::hardware::hidl_string; using ::android::sp; -#include #include #include #include #include // set component role -Return setRole( - sp omxNode, const char* role) { +Return setRole(sp omxNode, + const std::string& role) { OMX_PARAM_COMPONENTROLETYPE params; - strcpy((char*)params.cRole, role); + strcpy((char*)params.cRole, role.c_str()); return setParam(omxNode, OMX_IndexParamStandardComponentRole, ¶ms); } @@ -759,3 +758,46 @@ void testEOS(sp omxNode, sp observer, EXPECT_EQ(eosFlag, true); eosFlag = false; } + +hidl_vec getComponentInfoList(sp omx) { + android::hardware::media::omx::V1_0::Status status; + hidl_vec nodeList; + omx->listNodes([&status, &nodeList](android::hardware::media::omx::V1_0::Status _s, + hidl_vec const& _nl) { + status = _s; + nodeList = _nl; + }); + if (status != android::hardware::media::omx::V1_0::Status::OK) { + ALOGE("Failed to get ComponentInfo list for IOmx."); + } + return nodeList; +} + +// Return all test parameters, a list of tuple of +const std::vector>& getTestParameters( + const std::string& filter) { + static std::vector> parameters; + + auto instances = android::hardware::getAllHalInstanceNames(IOmx::descriptor); + for (std::string instance : instances) { + sp omx = IOmx::getService(instance); + hidl_vec componentInfos = getComponentInfoList(omx); + for (IOmx::ComponentInfo info : componentInfos) { + for (std::string role : info.mRoles) { + if (filter.empty()) { + if (kWhiteListRoles.find(role.c_str()) == kWhiteListRoles.end()) { + // This is for component test and the role is not in the white list. + continue; + } + } else if (role.find(filter) == std::string::npos) { + // The role doesn't match the given filter, e.g., video_decoder_vp8 role doesn't + // need to run for audio_decoder tests. + continue; + } + parameters.push_back(std::make_tuple(instance, info.mName.c_str(), role.c_str())); + } + } + } + + return parameters; +} \ No newline at end of file diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h index ac077a3c76..bb03dd0341 100644 --- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h +++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include #include @@ -44,8 +46,6 @@ #include #include -#include - /* TIME OUTS (Wait time in dequeueMessage()) */ /* As component is switching states (loaded<->idle<->execute), dequeueMessage() @@ -78,6 +78,20 @@ enum bufferOwner { unknown, }; +// White list audio/video roles to be tested. +static std::set kWhiteListRoles{ + "audio_encoder.aac", "audio_encoder.amrnb", "audio_encoder.amrwb", + "audio_encoder.flac", "audio_decoder.aac", "audio_decoder.amrnb", + "audio_decoder.amrwb", "audio_decoder.flac", "audio_decoder.g711alaw", + "audio_decoder.g711mlaw", "audio_decoder.gsm", "audio_decoder.mp3", + "audio_decoder.opus", "audio_decoder.raw", "audio_decoder.vorbis", + "video_encoder.avc", "video_encoder.h263", "video_encoder.mpeg4", + "video_encoder.vp8", "video_encoder.vp9", "video_decoder.avc", + "video_decoder.h263", "video_decoder.hevc", "video_decoder.mpeg4", + "video_decoder.vp8", "video_decoder.vp9"}; + +static std::vector> kTestParameters; + /* * TODO: below definitions are borrowed from Conversion.h. * This is not the ideal way to do it. Loose these definitions once you @@ -328,8 +342,8 @@ struct GrallocV3 { using Rect = IMapper::Rect; }; -Return setRole( - sp omxNode, const char* role); +Return setRole(sp omxNode, + const std::string& role); Return setPortBufferSize( sp omxNode, OMX_U32 portIndex, OMX_U32 size); @@ -400,77 +414,10 @@ void testEOS(sp omxNode, sp observer, portreconfig fptr = nullptr, OMX_U32 kPortIndexInput = 0, OMX_U32 kPortIndexOutput = 1, void* args = nullptr); -// A class for test environment setup -class ComponentTestEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - private: - typedef ::testing::VtsHalHidlTargetTestEnvBase Super; +hidl_vec getComponentInfoList(sp omx); - public: - virtual void registerTestServices() override { registerTestService(); } - - ComponentTestEnvironment() : res("/data/local/tmp/media/") {} - - void setComponent(const char* _component) { component = _component; } - - void setRole(const char* _role) { role = _role; } - - void setRes(const char* _res) { res = _res; } - - const hidl_string getInstance() { return Super::getServiceName(); } - - const hidl_string getComponent() const { return component; } - - const hidl_string getRole() const { return role; } - - const hidl_string getRes() const { return res; } - - int initFromOptions(int argc, char** argv) { - static struct option options[] = {{"component", required_argument, 0, 'C'}, - {"role", required_argument, 0, 'R'}, - {"res", required_argument, 0, 'P'}, - {0, 0, 0, 0}}; - - while (true) { - int index = 0; - int c = getopt_long(argc, argv, "C:R:P:", options, &index); - if (c == -1) { - break; - } - - switch (c) { - case 'C': - setComponent(optarg); - break; - case 'R': - setRole(optarg); - break; - case 'P': - setRes(optarg); - break; - case '?': - break; - } - } - - if (optind < argc) { - fprintf(stderr, - "unrecognized option: %s\n\n" - "usage: %s \n\n" - "test options are:\n\n" - "-C, --component: OMX component to test\n" - "-R, --role: OMX component Role\n" - "-P, --res: Resource files directory location\n", - argv[optind ?: 1], argv[0]); - return 2; - } - return 0; - } - - private: - hidl_string instance; - hidl_string component; - hidl_string role; - hidl_string res; -}; +// Return all test parameters, a list of tuple of +const std::vector>& getTestParameters( + const std::string& filter); #endif // MEDIA_HIDL_TEST_COMMON_H diff --git a/media/omx/1.0/vts/functional/component/Android.bp b/media/omx/1.0/vts/functional/component/Android.bp index 970eabe6fc..c7be2cc8d9 100644 --- a/media/omx/1.0/vts/functional/component/Android.bp +++ b/media/omx/1.0/vts/functional/component/Android.bp @@ -18,6 +18,7 @@ cc_test { name: "VtsHalMediaOmxV1_0TargetComponentTest", defaults: ["VtsHalMediaOmxV1_0Defaults"], srcs: ["VtsHalMediaOmxV1_0TargetComponentTest.cpp"], - test_suites: ["general-tests"], + test_suites: [ + "vts-core", + ], } - diff --git a/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp index 1c1d39b4e0..01cec6d9ea 100644 --- a/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp +++ b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include using ::android::hardware::media::omx::V1_0::IOmx; using ::android::hardware::media::omx::V1_0::IOmxObserver; @@ -44,42 +46,37 @@ using ::android::hardware::hidl_vec; using ::android::hardware::hidl_string; using ::android::sp; -#include #include #include -static ComponentTestEnvironment* gEnv = nullptr; - // generic component test fixture class -class ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase { - private: - typedef ::testing::VtsHalHidlTargetTestBase Super; - public: - ::std::string getTestCaseInfo() const override { - return ::std::string() + - "Component: " + gEnv->getComponent().c_str() + " | " + - "Role: " + gEnv->getRole().c_str() + " | " + - "Instance: " + gEnv->getInstance().c_str(); +class ComponentHidlTest + : public ::testing::TestWithParam> { + public: + ::std::string getTestCaseInfo() const { + return ::std::string() + "Component: " + component_ + " | " + "Role: " + role_ + " | " + + "Instance: " + instance_; } virtual void SetUp() override { - Super::SetUp(); + instance_ = std::get<0>(GetParam()); + component_ = std::get<1>(GetParam()); + role_ = std::get<2>(GetParam()); + disableTest = false; android::hardware::media::omx::V1_0::Status status; - omx = Super::getService(gEnv->getInstance()); + omx = IOmx::getService(instance_); ASSERT_NE(omx, nullptr); observer = new CodecObserver(nullptr); ASSERT_NE(observer, nullptr); - if (strncmp(gEnv->getComponent().c_str(), "OMX.", 4) != 0) - disableTest = true; - EXPECT_TRUE(omx->allocateNode( - gEnv->getComponent(), observer, - [&](android::hardware::media::omx::V1_0::Status _s, - sp const& _nl) { - status = _s; - this->omxNode = _nl; - }) - .isOk()); + if (component_.find("OMX.") != 0) disableTest = true; + EXPECT_TRUE(omx->allocateNode(component_, observer, + [&](android::hardware::media::omx::V1_0::Status _s, + sp const& _nl) { + status = _s; + this->omxNode = _nl; + }) + .isOk()); if (status == android::hardware::media::omx::V1_0::Status::NAME_NOT_FOUND) { disableTest = true; std::cout << "[ WARN ] Test Disabled, component not present\n"; @@ -87,7 +84,7 @@ class ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase { } ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); ASSERT_NE(omxNode, nullptr); - ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role"; + ASSERT_NE(role_.empty(), true) << "Invalid Component Role"; struct StringToClass { const char* Class; standardCompClass CompClass; @@ -102,7 +99,7 @@ class ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase { sizeof(kStringToClass) / sizeof(kStringToClass[0]); const char* pch; char substring[OMX_MAX_STRINGNAME_SIZE]; - strcpy(substring, gEnv->getRole().c_str()); + strcpy(substring, role_.c_str()); pch = strchr(substring, '.'); ASSERT_NE(pch, nullptr) << "Invalid Component Role"; substring[pch - substring] = '\0'; @@ -117,11 +114,8 @@ class ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase { isSecure = false; mTunnel = false; size_t suffixLen = strlen(".secure"); - if (strlen(gEnv->getComponent().c_str()) >= suffixLen) { - isSecure = - !strcmp(gEnv->getComponent().c_str() + - strlen(gEnv->getComponent().c_str()) - suffixLen, - ".secure"); + if (component_.rfind(".secure") == component_.length() - suffixLen) { + isSecure = true; } if (compClass == video_decoder) { omxNode->configureVideoTunnelMode( @@ -147,7 +141,6 @@ class ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase { EXPECT_TRUE((omxNode->freeNode()).isOk()); omxNode = nullptr; } - Super::TearDown(); } enum standardCompClass { @@ -158,6 +151,10 @@ class ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase { unknown_class, }; + std::string component_; + std::string role_; + std::string instance_; + sp omx; sp observer; sp omxNode; @@ -191,7 +188,7 @@ void initPortMode(PortMode* pm, bool isSecure, } // test dispatch message API call -TEST_F(ComponentHidlTest, dispatchMsg) { +TEST_P(ComponentHidlTest, dispatchMsg) { description("test dispatch message API call"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; @@ -216,22 +213,22 @@ TEST_F(ComponentHidlTest, dispatchMsg) { } // set component role -TEST_F(ComponentHidlTest, SetRole) { +TEST_P(ComponentHidlTest, SetRole) { description("Test Set Component Role"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); } // port indices enumeration -TEST_F(ComponentHidlTest, DISABLED_GetPortIndices) { +TEST_P(ComponentHidlTest, DISABLED_GetPortIndices) { description("Test Component on Mandatory Port Parameters (Port Indices)"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; OMX_PORT_PARAM_TYPE params; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); // Get Number of Ports and their Indices for all Domains @@ -248,13 +245,13 @@ TEST_F(ComponentHidlTest, DISABLED_GetPortIndices) { } // port format enumeration -TEST_F(ComponentHidlTest, EnumeratePortFormat) { +TEST_P(ComponentHidlTest, EnumeratePortFormat) { description("Test Component on Mandatory Port Parameters (Port Format)"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; if (compClass == audio_decoder || compClass == audio_encoder) { @@ -308,14 +305,14 @@ TEST_F(ComponentHidlTest, EnumeratePortFormat) { } // get/set default port settings of a component -TEST_F(ComponentHidlTest, DISABLED_SetDefaultPortParams) { +TEST_P(ComponentHidlTest, DISABLED_SetDefaultPortParams) { description( "Test Component on Mandatory Port Parameters (Port Definition)"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; if (compClass == audio_decoder || compClass == audio_encoder) { @@ -398,7 +395,7 @@ TEST_F(ComponentHidlTest, DISABLED_SetDefaultPortParams) { portDef = mirror; OMX_U32 nBufferSize = portDef.nBufferSize >> 1; if (nBufferSize != 0) { - if (!strncmp(gEnv->getComponent().c_str(), "OMX.google.", 11)) { + if (component_.find("OMX.google.") != 0) { portDef.nBufferSize = nBufferSize; } else { // Probable alignment requirements of vendor component @@ -438,13 +435,13 @@ TEST_F(ComponentHidlTest, DISABLED_SetDefaultPortParams) { } // populate port test -TEST_F(ComponentHidlTest, DISABLED_PopulatePort) { +TEST_P(ComponentHidlTest, DISABLED_PopulatePort) { description("Verify bPopulated field of a component port"); if (disableTest || isSecure) return; android::hardware::media::omx::V1_0::Status status; OMX_U32 portBase = 0; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; if (compClass == audio_decoder || compClass == audio_encoder) { @@ -490,14 +487,14 @@ TEST_F(ComponentHidlTest, DISABLED_PopulatePort) { } // Flush test -TEST_F(ComponentHidlTest, Flush) { +TEST_P(ComponentHidlTest, Flush) { description("Test Flush"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; Message msg; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; if (compClass == audio_decoder || compClass == audio_encoder) { @@ -561,14 +558,14 @@ TEST_F(ComponentHidlTest, Flush) { } // Flush test - monkeying -TEST_F(ComponentHidlTest, Flush_M) { +TEST_P(ComponentHidlTest, Flush_M) { description("Test Flush monkeying"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; Message msg; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; if (compClass == audio_decoder || compClass == audio_encoder) { @@ -669,14 +666,14 @@ TEST_F(ComponentHidlTest, Flush_M) { } // test port mode configuration when the component is in various states -TEST_F(ComponentHidlTest, PortModeConfig) { +TEST_P(ComponentHidlTest, PortModeConfig) { description("Test Port Mode Configuration"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; Message msg; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; if (compClass == audio_decoder || compClass == audio_encoder) { @@ -733,14 +730,14 @@ TEST_F(ComponentHidlTest, PortModeConfig) { } // state transitions test -TEST_F(ComponentHidlTest, StateTransitions) { +TEST_P(ComponentHidlTest, StateTransitions) { description("Test State Transitions Loaded<->Idle<->Execute"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; OMX_U32 portBase = 0; Message msg; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; if (compClass == audio_decoder || compClass == audio_encoder) { @@ -852,14 +849,14 @@ TEST_F(ComponentHidlTest, StateTransitions) { } // state transitions test - monkeying -TEST_F(ComponentHidlTest, DISABLED_StateTransitions_M) { +TEST_P(ComponentHidlTest, DISABLED_StateTransitions_M) { description("Test State Transitions monkeying"); if (disableTest || isSecure) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; Message msg; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; if (compClass == audio_decoder || compClass == audio_encoder) { @@ -918,13 +915,13 @@ TEST_F(ComponentHidlTest, DISABLED_StateTransitions_M) { } // port enable disable test -TEST_F(ComponentHidlTest, DISABLED_PortEnableDisable_Loaded) { +TEST_P(ComponentHidlTest, DISABLED_PortEnableDisable_Loaded) { description("Test Port Enable and Disable (Component State :: Loaded)"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; OMX_U32 portBase = 0; Message msg; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; if (compClass == audio_decoder || compClass == audio_encoder) { @@ -968,14 +965,14 @@ TEST_F(ComponentHidlTest, DISABLED_PortEnableDisable_Loaded) { } // port enable disable test -TEST_F(ComponentHidlTest, PortEnableDisable_Idle) { +TEST_P(ComponentHidlTest, PortEnableDisable_Idle) { description("Test Port Enable and Disable (Component State :: Idle)"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; OMX_U32 portBase = 0; Message msg; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; if (compClass == audio_decoder || compClass == audio_encoder) { @@ -1074,14 +1071,14 @@ TEST_F(ComponentHidlTest, PortEnableDisable_Idle) { } // port enable disable test -TEST_F(ComponentHidlTest, PortEnableDisable_Execute) { +TEST_P(ComponentHidlTest, PortEnableDisable_Execute) { description("Test Port Enable and Disable (Component State :: Execute)"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; OMX_U32 portBase = 0; Message msg; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; if (compClass == audio_decoder || compClass == audio_encoder) { @@ -1192,14 +1189,14 @@ TEST_F(ComponentHidlTest, PortEnableDisable_Execute) { } // port enable disable test - monkeying -TEST_F(ComponentHidlTest, DISABLED_PortEnableDisable_M) { +TEST_P(ComponentHidlTest, DISABLED_PortEnableDisable_M) { description( "Test Port Enable and Disable Monkeying (Component State :: Loaded)"); if (disableTest || isSecure) return; android::hardware::media::omx::V1_0::Status status; OMX_U32 portBase = 0; Message msg; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; if (compClass == audio_decoder || compClass == audio_encoder) { @@ -1267,15 +1264,11 @@ TEST_F(ComponentHidlTest, DISABLED_PortEnableDisable_M) { } } +INSTANTIATE_TEST_SUITE_P(PerInstance, ComponentHidlTest, testing::ValuesIn(kTestParameters), + android::hardware::PrintInstanceTupleNameToString<>); + int main(int argc, char** argv) { - gEnv = new ComponentTestEnvironment(); - ::testing::AddGlobalTestEnvironment(gEnv); + kTestParameters = getTestParameters(""); ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - int status = gEnv->initFromOptions(argc, argv); - if (status == 0) { - status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); - } - return status; -} + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/media/omx/1.0/vts/functional/master/Android.bp b/media/omx/1.0/vts/functional/master/Android.bp index cf3f15d530..0eb2cc998d 100644 --- a/media/omx/1.0/vts/functional/master/Android.bp +++ b/media/omx/1.0/vts/functional/master/Android.bp @@ -18,6 +18,7 @@ cc_test { name: "VtsHalMediaOmxV1_0TargetMasterTest", defaults: ["VtsHalMediaOmxV1_0Defaults"], srcs: ["VtsHalMediaOmxV1_0TargetMasterTest.cpp"], - test_suites: ["general-tests"], + test_suites: [ + "vts-core", + ], } - 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 64abe1c1b1..c14f1da8bc 100644 --- a/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp +++ b/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp @@ -29,6 +29,9 @@ #include #include #include +#include +#include +#include using ::android::hardware::media::omx::V1_0::IOmx; using ::android::hardware::media::omx::V1_0::IOmxObserver; @@ -46,30 +49,18 @@ using ::android::hardware::hidl_vec; using ::android::hardware::hidl_string; using ::android::sp; -#include #include #include -static ComponentTestEnvironment* gEnv = nullptr; - -class MasterHidlTest : public ::testing::VtsHalHidlTargetTestBase { - private: - typedef ::testing::VtsHalHidlTargetTestBase Super; - public: +class MasterHidlTest : public ::testing::TestWithParam { + public: virtual void SetUp() override { - Super::SetUp(); - omxStore = nullptr; - omxStore = Super::getService(); + omxStore = IOmxStore::getService(GetParam()); ASSERT_NE(omxStore, nullptr); - omx = nullptr; - omx = omxStore->getOmx(gEnv->getInstance()); + omx = IOmx::getService(GetParam()); ASSERT_NE(omx, nullptr); } - virtual void TearDown() override { - Super::TearDown(); - } - sp omxStore; sp omx; @@ -89,8 +80,19 @@ void displayComponentInfo(hidl_vec& nodeList) { } } +// Make sure IOmx and IOmxStore have the same set of instances. +TEST(MasterHidlTest, instanceMatchValidation) { + auto omxInstances = android::hardware::getAllHalInstanceNames(IOmx::descriptor); + auto omxStoreInstances = android::hardware::getAllHalInstanceNames(IOmxStore::descriptor); + ASSERT_EQ(omxInstances.size(), omxInstances.size()); + for (const std::string& omxInstance : omxInstances) { + EXPECT_TRUE(std::find(omxStoreInstances.begin(), omxStoreInstances.end(), omxInstance) != + omxStoreInstances.end()); + } +} + // list service attributes -TEST_F(MasterHidlTest, ListServiceAttr) { +TEST_P(MasterHidlTest, ListServiceAttr) { description("list service attributes"); android::hardware::media::omx::V1_0::Status status; hidl_vec attributes; @@ -107,7 +109,7 @@ TEST_F(MasterHidlTest, ListServiceAttr) { } // get node prefix -TEST_F(MasterHidlTest, getNodePrefix) { +TEST_P(MasterHidlTest, getNodePrefix) { description("get node prefix"); hidl_string prefix; omxStore->getNodePrefix( @@ -116,7 +118,7 @@ TEST_F(MasterHidlTest, getNodePrefix) { } // list roles -TEST_F(MasterHidlTest, ListRoles) { +TEST_P(MasterHidlTest, ListRoles) { description("list roles"); hidl_vec roleList; omxStore->listRoles([&roleList](hidl_vec const& _nl) { @@ -126,7 +128,7 @@ TEST_F(MasterHidlTest, ListRoles) { } // list components and roles. -TEST_F(MasterHidlTest, ListNodes) { +TEST_P(MasterHidlTest, ListNodes) { description("enumerate component and roles"); android::hardware::media::omx::V1_0::Status status; hidl_vec nodeList; @@ -174,15 +176,7 @@ TEST_F(MasterHidlTest, ListNodes) { EXPECT_TRUE(isPass); } -int main(int argc, char** argv) { - gEnv = new ComponentTestEnvironment(); - ::testing::AddGlobalTestEnvironment(gEnv); - ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - int status = gEnv->initFromOptions(argc, argv); - if (status == 0) { - status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); - } - return status; -} +INSTANTIATE_TEST_CASE_P( + PerInstance, MasterHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IOmxStore::descriptor)), + android::hardware::PrintInstanceNameToString); diff --git a/media/omx/1.0/vts/functional/video/Android.bp b/media/omx/1.0/vts/functional/video/Android.bp index c7e0424472..7e93faa261 100644 --- a/media/omx/1.0/vts/functional/video/Android.bp +++ b/media/omx/1.0/vts/functional/video/Android.bp @@ -16,23 +16,33 @@ cc_test { name: "VtsHalMediaOmxV1_0TargetVideoDecTest", + stem: "vts_hal_media_omx_v1_0_video_dec_test", defaults: ["VtsHalMediaOmxV1_0Defaults"], srcs: [ "VtsHalMediaOmxV1_0TargetVideoDecTest.cpp", - "media_video_hidl_test_common.cpp" + "media_video_hidl_test_common.cpp", + ], + data: [":media_omx_video_res"], + test_config: "VtsHalMediaOmxV1_0TargetVideoDecTest.xml", + test_suites: [ + "vts-core", ], - test_suites: ["general-tests"], } cc_test { name: "VtsHalMediaOmxV1_0TargetVideoEncTest", + stem: "vts_hal_media_omx_v1_0_video_enc_test", defaults: ["VtsHalMediaOmxV1_0Defaults"], srcs: [ "VtsHalMediaOmxV1_0TargetVideoEncTest.cpp", - "media_video_hidl_test_common.cpp" + "media_video_hidl_test_common.cpp", ], static_libs: [ "libnativewindow", ], - test_suites: ["general-tests"], + data: [":media_omx_video_res"], + test_config: "VtsHalMediaOmxV1_0TargetVideoEncTest.xml", + test_suites: [ + "vts-core", + ], } diff --git a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp index df048c6bf2..29a32a5d36 100644 --- a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp +++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include using ::android::hardware::media::omx::V1_0::IOmx; using ::android::hardware::media::omx::V1_0::IOmxObserver; @@ -44,49 +46,46 @@ using ::android::hardware::hidl_vec; using ::android::hardware::hidl_string; using ::android::sp; -#include #include #include -#include #include #include -static ComponentTestEnvironment* gEnv = nullptr; +// Resource directory +std::string sResourceDir = ""; // video decoder test fixture class -class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { - private: - typedef ::testing::VtsHalHidlTargetTestBase Super; - public: - ::std::string getTestCaseInfo() const override { - return ::std::string() + - "Component: " + gEnv->getComponent().c_str() + " | " + - "Role: " + gEnv->getRole().c_str() + " | " + - "Instance: " + gEnv->getInstance().c_str() + " | " + - "Res: " + gEnv->getRes().c_str(); +class VideoDecHidlTest + : public ::testing::TestWithParam> { + public: + ::std::string getTestCaseInfo() const { + return ::std::string() + "Component: " + component_ + " | " + "Role: " + role_ + " | " + + "Instance: " + instance_ + " | " + "Res: " + sResourceDir; } virtual void SetUp() override { - Super::SetUp(); + instance_ = std::get<0>(GetParam()); + component_ = std::get<1>(GetParam()); + role_ = std::get<2>(GetParam()); + ASSERT_NE(sResourceDir.empty(), true); + disableTest = false; android::hardware::media::omx::V1_0::Status status; - omx = Super::getService(gEnv->getInstance()); + omx = IOmx::getService(instance_); ASSERT_NE(omx, nullptr); observer = new CodecObserver([this](Message msg, const BufferInfo* buffer) { handleMessage(msg, buffer); }); ASSERT_NE(observer, nullptr); - if (strncmp(gEnv->getComponent().c_str(), "OMX.", 4) != 0) - disableTest = true; - EXPECT_TRUE(omx->allocateNode( - gEnv->getComponent(), observer, - [&](android::hardware::media::omx::V1_0::Status _s, - sp const& _nl) { - status = _s; - this->omxNode = _nl; - }) - .isOk()); + if (component_.find("OMX.") != 0) disableTest = true; + EXPECT_TRUE(omx->allocateNode(component_, observer, + [&](android::hardware::media::omx::V1_0::Status _s, + sp const& _nl) { + status = _s; + this->omxNode = _nl; + }) + .isOk()); if (status == android::hardware::media::omx::V1_0::Status::NAME_NOT_FOUND) { disableTest = true; std::cout << "[ WARN ] Test Disabled, component not present\n"; @@ -94,7 +93,7 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { } ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); ASSERT_NE(omxNode, nullptr); - ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role"; + ASSERT_NE(role_.empty(), true) << "Invalid Component Role"; struct StringToName { const char* Name; standardComp CompName; @@ -107,7 +106,7 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { sizeof(kStringToName) / sizeof(kStringToName[0]); const char* pch; char substring[OMX_MAX_STRINGNAME_SIZE]; - strcpy(substring, gEnv->getRole().c_str()); + strcpy(substring, role_.c_str()); pch = strchr(substring, '.'); ASSERT_NE(pch, nullptr); compName = unknown_comp; @@ -146,11 +145,8 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { isSecure = false; portSettingsChange = false; size_t suffixLen = strlen(".secure"); - if (strlen(gEnv->getComponent().c_str()) >= suffixLen) { - isSecure = - !strcmp(gEnv->getComponent().c_str() + - strlen(gEnv->getComponent().c_str()) - suffixLen, - ".secure"); + if (component_.rfind(".secure") == component_.length() - suffixLen) { + isSecure = true; } if (isSecure) disableTest = true; omxNode->configureVideoTunnelMode( @@ -175,7 +171,6 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { EXPECT_TRUE((omxNode->freeNode()).isOk()); omxNode = nullptr; } - Super::TearDown(); } // callback function to process messages received by onMessages() from IL @@ -255,6 +250,10 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { unknown_comp, }; + std::string component_; + std::string role_; + std::string instance_; + sp omx; sp observer; sp omxNode; @@ -719,23 +718,23 @@ void getDefaultColorFormat(sp omxNode, OMX_U32 kPortIndexOutput, } // set component role -TEST_F(VideoDecHidlTest, SetRole) { +TEST_P(VideoDecHidlTest, SetRole) { description("Test Set Component Role"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); } // port format enumeration -TEST_F(VideoDecHidlTest, EnumeratePortFormat) { +TEST_P(VideoDecHidlTest, EnumeratePortFormat) { description("Test Component on Mandatory Port Parameters (Port Format)"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatYUV420Planar; OMX_U32 xFramerate = (24U << 16); - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms); @@ -755,12 +754,12 @@ TEST_F(VideoDecHidlTest, EnumeratePortFormat) { // test port settings reconfiguration, elementary stream decode and timestamp // deviation -TEST_F(VideoDecHidlTest, DecodeTest) { +TEST_P(VideoDecHidlTest, DecodeTest) { description("Tests Port Reconfiguration, Decode and timestamp deviation"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms); @@ -770,8 +769,8 @@ TEST_F(VideoDecHidlTest, DecodeTest) { kPortIndexOutput = kPortIndexInput + 1; } char mURL[512], info[512]; - strcpy(mURL, gEnv->getRes().c_str()); - strcpy(info, gEnv->getRes().c_str()); + strcpy(mURL, sResourceDir.c_str()); + strcpy(info, sResourceDir.c_str()); GetURLForComponent(compName, mURL, info); std::ifstream eleStream, eleInfo; @@ -860,7 +859,7 @@ TEST_F(VideoDecHidlTest, DecodeTest) { } // Test for adaptive playback support -TEST_F(VideoDecHidlTest, AdaptivePlaybackTest) { +TEST_P(VideoDecHidlTest, AdaptivePlaybackTest) { description("Tests for Adaptive Playback support"); if (disableTest) return; if (!(compName == avc || compName == hevc || compName == vp8 || @@ -868,7 +867,7 @@ TEST_F(VideoDecHidlTest, AdaptivePlaybackTest) { return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms); @@ -895,7 +894,7 @@ TEST_F(VideoDecHidlTest, AdaptivePlaybackTest) { uint32_t adaptiveMaxHeight = 240; status = omxNode->prepareForAdaptivePlayback( kPortIndexOutput, true, adaptiveMaxWidth, adaptiveMaxHeight); - if (strncmp(gEnv->getComponent().c_str(), "OMX.google.", 11) == 0) { + if (component_.find("OMX.google.") == 0) { // SoftOMX Decoders donot support graphic buffer modes. So for them // support for adaptive play back is mandatory in Byte Buffer mode ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); @@ -944,8 +943,8 @@ TEST_F(VideoDecHidlTest, AdaptivePlaybackTest) { std::ifstream eleStream, eleInfo; char mURL[512], info[512]; android::Vector Info; - strcpy(mURL, gEnv->getRes().c_str()); - strcpy(info, gEnv->getRes().c_str()); + strcpy(mURL, sResourceDir.c_str()); + strcpy(info, sResourceDir.c_str()); GetURLForComponent(compName, mURL, info, i % STREAM_COUNT); eleInfo.open(info); ASSERT_EQ(eleInfo.is_open(), true); @@ -1008,12 +1007,12 @@ TEST_F(VideoDecHidlTest, AdaptivePlaybackTest) { } // end of sequence test -TEST_F(VideoDecHidlTest, EOSTest_M) { +TEST_P(VideoDecHidlTest, EOSTest_M) { description("Test End of stream monkeying"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms); @@ -1074,12 +1073,12 @@ TEST_F(VideoDecHidlTest, EOSTest_M) { } // end of sequence test -TEST_F(VideoDecHidlTest, ThumbnailTest) { +TEST_P(VideoDecHidlTest, ThumbnailTest) { description("Test Request for thumbnail"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms); @@ -1089,8 +1088,8 @@ TEST_F(VideoDecHidlTest, ThumbnailTest) { kPortIndexOutput = kPortIndexInput + 1; } char mURL[512], info[512]; - strcpy(mURL, gEnv->getRes().c_str()); - strcpy(info, gEnv->getRes().c_str()); + strcpy(mURL, sResourceDir.c_str()); + strcpy(info, sResourceDir.c_str()); GetURLForComponent(compName, mURL, info); std::ifstream eleStream, eleInfo; @@ -1195,12 +1194,12 @@ TEST_F(VideoDecHidlTest, ThumbnailTest) { } // end of sequence test -TEST_F(VideoDecHidlTest, SimpleEOSTest) { +TEST_P(VideoDecHidlTest, SimpleEOSTest) { description("Test End of stream"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms); @@ -1210,8 +1209,8 @@ TEST_F(VideoDecHidlTest, SimpleEOSTest) { kPortIndexOutput = kPortIndexInput + 1; } char mURL[512], info[512]; - strcpy(mURL, gEnv->getRes().c_str()); - strcpy(info, gEnv->getRes().c_str()); + strcpy(mURL, sResourceDir.c_str()); + strcpy(info, sResourceDir.c_str()); GetURLForComponent(compName, mURL, info); std::ifstream eleStream, eleInfo; @@ -1302,12 +1301,12 @@ TEST_F(VideoDecHidlTest, SimpleEOSTest) { } // test input/output port flush -TEST_F(VideoDecHidlTest, FlushTest) { +TEST_P(VideoDecHidlTest, FlushTest) { description("Test Flush"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms); @@ -1317,8 +1316,8 @@ TEST_F(VideoDecHidlTest, FlushTest) { kPortIndexOutput = kPortIndexInput + 1; } char mURL[512], info[512]; - strcpy(mURL, gEnv->getRes().c_str()); - strcpy(info, gEnv->getRes().c_str()); + strcpy(mURL, sResourceDir.c_str()); + strcpy(info, sResourceDir.c_str()); GetURLForComponent(compName, mURL, info); std::ifstream eleStream, eleInfo; @@ -1420,15 +1419,21 @@ TEST_F(VideoDecHidlTest, FlushTest) { kPortIndexOutput)); } +INSTANTIATE_TEST_SUITE_P(PerInstance, VideoDecHidlTest, testing::ValuesIn(kTestParameters), + android::hardware::PrintInstanceTupleNameToString<>); + int main(int argc, char** argv) { - gEnv = new ComponentTestEnvironment(); - ::testing::AddGlobalTestEnvironment(gEnv); + kTestParameters = getTestParameters("video_decoder"); ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - int status = gEnv->initFromOptions(argc, argv); - if (status == 0) { - status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); + + // Set the resource directory based on command line args. + // Test will fail to set up if the argument is not set. + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-P") == 0 && i < argc - 1) { + sResourceDir = argv[i + 1]; + break; + } } - return status; -} + + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.xml b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.xml new file mode 100644 index 0000000000..a2fd92ad89 --- /dev/null +++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp index 2280cee8c2..4b469e6bb1 100644 --- a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp +++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp @@ -34,6 +34,8 @@ #include #include #include +#include +#include using ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer; using ::android::hardware::graphics::bufferqueue::V1_0::IProducerListener; @@ -56,51 +58,48 @@ using ::android::hardware::hidl_vec; using ::android::hardware::hidl_string; using ::android::sp; -#include #include #include -#include #include #include #include #include -static ComponentTestEnvironment* gEnv = nullptr; +// Resource directory +std::string sResourceDir = ""; // video encoder test fixture class -class VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { - private: - typedef ::testing::VtsHalHidlTargetTestBase Super; - public: - ::std::string getTestCaseInfo() const override { - return ::std::string() + - "Component: " + gEnv->getComponent().c_str() + " | " + - "Role: " + gEnv->getRole().c_str() + " | " + - "Instance: " + gEnv->getInstance().c_str() + " | " + - "Res: " + gEnv->getRes().c_str(); +class VideoEncHidlTest + : public ::testing::TestWithParam> { + public: + ::std::string getTestCaseInfo() const { + return ::std::string() + "Component: " + component_ + " | " + "Role: " + role_ + " | " + + "Instance: " + instance_ + " | " + "Res: " + sResourceDir; } virtual void SetUp() override { - Super::SetUp(); + instance_ = std::get<0>(GetParam()); + component_ = std::get<1>(GetParam()); + role_ = std::get<2>(GetParam()); + ASSERT_NE(sResourceDir.empty(), true); + disableTest = false; android::hardware::media::omx::V1_0::Status status; - omx = Super::getService(gEnv->getInstance()); + omx = IOmx::getService(instance_); ASSERT_NE(omx, nullptr); observer = new CodecObserver([this](Message msg, const BufferInfo* buffer) { handleMessage(msg, buffer); }); ASSERT_NE(observer, nullptr); - if (strncmp(gEnv->getComponent().c_str(), "OMX.", 4) != 0) - disableTest = true; - EXPECT_TRUE(omx->allocateNode( - gEnv->getComponent(), observer, - [&](android::hardware::media::omx::V1_0::Status _s, - sp const& _nl) { - status = _s; - this->omxNode = _nl; - }) - .isOk()); + if (component_.find("OMX.") != 0) disableTest = true; + EXPECT_TRUE(omx->allocateNode(component_, observer, + [&](android::hardware::media::omx::V1_0::Status _s, + sp const& _nl) { + status = _s; + this->omxNode = _nl; + }) + .isOk()); if (status == android::hardware::media::omx::V1_0::Status::NAME_NOT_FOUND) { disableTest = true; std::cout << "[ WARN ] Test Disabled, component not present\n"; @@ -108,7 +107,7 @@ class VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { } ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); ASSERT_NE(omxNode, nullptr); - ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role"; + ASSERT_NE(role_.empty(), true) << "Invalid Component Role"; struct StringToName { const char* Name; standardComp CompName; @@ -121,7 +120,7 @@ class VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { sizeof(kStringToName) / sizeof(kStringToName[0]); const char* pch; char substring[OMX_MAX_STRINGNAME_SIZE]; - strcpy(substring, gEnv->getRole().c_str()); + strcpy(substring, role_.c_str()); pch = strchr(substring, '.'); ASSERT_NE(pch, nullptr); compName = unknown_comp; @@ -158,11 +157,8 @@ class VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { source = nullptr; isSecure = false; size_t suffixLen = strlen(".secure"); - if (strlen(gEnv->getComponent().c_str()) >= suffixLen) { - isSecure = - !strcmp(gEnv->getComponent().c_str() + - strlen(gEnv->getComponent().c_str()) - suffixLen, - ".secure"); + if (component_.rfind(".secure") == component_.length() - suffixLen) { + isSecure = true; } if (isSecure) disableTest = true; if (disableTest) std::cout << "[ WARN ] Test Disabled \n"; @@ -177,7 +173,6 @@ class VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { EXPECT_TRUE((omxNode->freeNode()).isOk()); omxNode = nullptr; } - Super::TearDown(); } // callback function to process messages received by onMessages() from IL @@ -245,6 +240,10 @@ class VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { unknown_comp, }; + std::string component_; + std::string role_; + std::string instance_; + sp omx; sp observer; sp omxNode; @@ -1085,23 +1084,23 @@ void encodeNFrames(sp omxNode, sp observer, } // set component role -TEST_F(VideoEncHidlTest, SetRole) { +TEST_P(VideoEncHidlTest, SetRole) { description("Test Set Component Role"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); } // port format enumeration -TEST_F(VideoEncHidlTest, EnumeratePortFormat) { +TEST_P(VideoEncHidlTest, EnumeratePortFormat) { description("Test Component on Mandatory Port Parameters (Port Format)"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatYUV420Planar; OMX_U32 xFramerate = (30U << 16); - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms); @@ -1121,12 +1120,12 @@ TEST_F(VideoEncHidlTest, EnumeratePortFormat) { } // Test IOmxBufferSource CallBacks -TEST_F(VideoEncHidlTest, BufferSourceCallBacks) { +TEST_P(VideoEncHidlTest, BufferSourceCallBacks) { description("Test IOmxBufferSource CallBacks"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms); @@ -1178,12 +1177,12 @@ TEST_F(VideoEncHidlTest, BufferSourceCallBacks) { } // test raw stream encode (input is byte buffers) -TEST_F(VideoEncHidlTest, EncodeTest) { +TEST_P(VideoEncHidlTest, EncodeTest) { description("Test Encode"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms); @@ -1193,7 +1192,7 @@ TEST_F(VideoEncHidlTest, EncodeTest) { kPortIndexOutput = kPortIndexInput + 1; } char mURL[512]; - strcpy(mURL, gEnv->getRes().c_str()); + strcpy(mURL, sResourceDir.c_str()); GetURLForComponent(mURL); std::ifstream eleStream; @@ -1293,12 +1292,12 @@ TEST_F(VideoEncHidlTest, EncodeTest) { } // test raw stream encode (input is ANW buffers) -TEST_F(VideoEncHidlTest, EncodeTestBufferMetaModes) { +TEST_P(VideoEncHidlTest, EncodeTestBufferMetaModes) { description("Test Encode Input buffer metamodes"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms); @@ -1383,7 +1382,7 @@ TEST_F(VideoEncHidlTest, EncodeTestBufferMetaModes) { ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); char mURL[512]; - strcpy(mURL, gEnv->getRes().c_str()); + strcpy(mURL, sResourceDir.c_str()); GetURLForComponent(mURL); uint32_t latency = 0; @@ -1460,12 +1459,12 @@ TEST_F(VideoEncHidlTest, EncodeTestBufferMetaModes) { } // Test end of stream -TEST_F(VideoEncHidlTest, EncodeTestEOS) { +TEST_P(VideoEncHidlTest, EncodeTestEOS) { description("Test EOS"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; - status = setRole(omxNode, gEnv->getRole().c_str()); + status = setRole(omxNode, role_); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); OMX_PORT_PARAM_TYPE params; status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms); @@ -1574,15 +1573,21 @@ TEST_F(VideoEncHidlTest, EncodeTestEOS) { ASSERT_EQ(returnval, 0); } +INSTANTIATE_TEST_SUITE_P(PerInstance, VideoEncHidlTest, testing::ValuesIn(kTestParameters), + android::hardware::PrintInstanceTupleNameToString<>); + int main(int argc, char** argv) { - gEnv = new ComponentTestEnvironment(); - ::testing::AddGlobalTestEnvironment(gEnv); + kTestParameters = getTestParameters("video_encoder"); ::testing::InitGoogleTest(&argc, argv); - gEnv->init(&argc, argv); - int status = gEnv->initFromOptions(argc, argv); - if (status == 0) { - status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); + + // Set the resource directory based on command line args. + // Test will fail to set up if the argument is not set. + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-P") == 0 && i < argc - 1) { + sResourceDir = argv[i + 1]; + break; + } } - return status; -} + + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.xml b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.xml new file mode 100644 index 0000000000..57ba1e4c3e --- /dev/null +++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.cpp b/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.cpp index e1b6022f9d..5e2c10733b 100644 --- a/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.cpp +++ b/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.cpp @@ -44,7 +44,6 @@ using ::android::hardware::hidl_vec; using ::android::hardware::hidl_string; using ::android::sp; -#include #include #include #include diff --git a/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.h b/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.h index 55de125877..e8f5172801 100644 --- a/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.h +++ b/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.h @@ -17,6 +17,8 @@ #ifndef MEDIA_VIDEO_HIDL_TEST_COMMON_H #define MEDIA_VIDEO_HIDL_TEST_COMMON_H +#include + /* * Common video utils */ From 67963dec8bff7616bab17a81463baf68300f7e3e Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Wed, 18 Mar 2020 00:02:32 +0000 Subject: [PATCH 0811/1022] Convert VtsHalAudioV*_0TargetTest to parameterized gtest For version 2, 4 and 5. Bug: 150299743 Test: atest VtsHalAudioV2_0TargetTest \ VtsHalAudioV4_0TargetTest \ VtsHalAudioV5_0TargetTest Change-Id: I09be1dc79b69caadd2a5468c4e6ed9c1efd76ffd Merged-In: I09be1dc79b69caadd2a5468c4e6ed9c1efd76ffd --- audio/2.0/config/Android.bp | 20 ++ .../include/utility/EnvironmentTearDown.h | 58 ----- audio/core/all-versions/default/Android.bp | 13 +- .../vts/functional/2.0/EnvironmentTearDown.h | 34 --- .../6.0/AudioPrimaryHidlHalTest.cpp | 48 ----- .../vts/functional/6.0/EnvironmentTearDown.h | 35 --- .../all-versions/vts/functional/Android.bp | 33 ++- .../vts/functional/AudioPrimaryHidlHalTest.h | 203 ++++++++---------- .../vts/functional/DeviceManager.h | 8 - .../functional/VtsHalAudioV2_0TargetTest.xml | 40 ++++ .../functional/VtsHalAudioV4_0TargetTest.xml | 40 ++++ .../functional/VtsHalAudioV5_0TargetTest.xml | 40 ++++ 12 files changed, 257 insertions(+), 315 deletions(-) create mode 100644 audio/2.0/config/Android.bp delete mode 100644 audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h delete mode 100644 audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h delete mode 100644 audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h create mode 100644 audio/core/all-versions/vts/functional/VtsHalAudioV2_0TargetTest.xml create mode 100644 audio/core/all-versions/vts/functional/VtsHalAudioV4_0TargetTest.xml create mode 100644 audio/core/all-versions/vts/functional/VtsHalAudioV5_0TargetTest.xml diff --git a/audio/2.0/config/Android.bp b/audio/2.0/config/Android.bp new file mode 100644 index 0000000000..65a32eb11d --- /dev/null +++ b/audio/2.0/config/Android.bp @@ -0,0 +1,20 @@ +// +// 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. +// + +filegroup { + name: "audio_policy_configuration_V2_0", + srcs: ["audio_policy_configuration.xsd"], +} diff --git a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h deleted file mode 100644 index 2b240ce309..0000000000 --- a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2018 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_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN_H -#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN_H - -#include -#include - -namespace android { -namespace hardware { -namespace audio { -namespace common { -namespace test { -namespace utility { - -/** Register callback for static object destruction - * Avoid destroying static objects after main return. - * Post main return destruction leads to incorrect gtest timing measurements as - * well as harder debuging if anything goes wrong during destruction. */ -class EnvironmentTearDown { - public: - using TearDownFunc = std::function; - void registerTearDown(TearDownFunc&& tearDown) { tearDowns.push_front(std::move(tearDown)); } - - protected: - void executeAllTearDowns() { - // Call the tear downs in reverse order of insertion - for (auto& tearDown : tearDowns) { - tearDown(); - } - } - - private: - std::list tearDowns; -}; - -} // namespace utility -} // namespace test -} // namespace common -} // namespace audio -} // namespace hardware -} // namespace android - -#endif // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN_H diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp index b8b7feeed0..0af81b2bd4 100644 --- a/audio/core/all-versions/default/Android.bp +++ b/audio/core/all-versions/default/Android.bp @@ -18,8 +18,11 @@ cc_defaults { export_include_dirs: ["include"], - shared_libs: [ + static_libs: [ "libaudiofoundation", + ], + + shared_libs: [ "libbase", "libcutils", "libfmq", @@ -52,7 +55,7 @@ cc_library_shared { "-DMAJOR_VERSION=2", "-DMINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", - ] + ], } cc_library_shared { @@ -68,7 +71,7 @@ cc_library_shared { "-DMAJOR_VERSION=4", "-DMINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", - ] + ], } cc_library_shared { @@ -83,7 +86,7 @@ cc_library_shared { "-DMAJOR_VERSION=5", "-DMINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", - ] + ], } cc_library_shared { @@ -98,5 +101,5 @@ cc_library_shared { "-DMAJOR_VERSION=6", "-DMINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", - ] + ], } diff --git a/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h b/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h deleted file mode 100644 index 6373e39111..0000000000 --- a/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H -#define ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H - -#include -#include - -#include "utility/EnvironmentTearDown.h" - -class Environment : public ::android::hardware::audio::common::test::utility::EnvironmentTearDown, - public ::testing::VtsHalHidlTargetTestEnvBase { - private: - void HidlTearDown() override { - executeAllTearDowns(); - VtsHalHidlTargetTestEnvBase::HidlTearDown(); - } -}; - -#endif // ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp index b40a329ee0..e09eeab4eb 100644 --- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp @@ -17,54 +17,6 @@ // pull in all the <= 5.0 tests #include "5.0/AudioPrimaryHidlHalTest.cpp" -const std::vector& getDeviceParametersForFactoryTests() { - static std::vector parameters = [] { - std::vector result; - const auto factories = - ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor); - for (const auto& factoryName : factories) { - result.emplace_back(factoryName, - DeviceManager::getInstance().getPrimary(factoryName) != nullptr - ? DeviceManager::kPrimaryDevice - : ""); - } - return result; - }(); - return parameters; -} - -const std::vector& getDeviceParametersForPrimaryDeviceTests() { - static std::vector parameters = [] { - std::vector result; - const auto primary = std::find_if( - getDeviceParameters().begin(), getDeviceParameters().end(), [](const auto& elem) { - return std::get(elem) == DeviceManager::kPrimaryDevice; - }); - if (primary != getDeviceParameters().end()) result.push_back(*primary); - return result; - }(); - return parameters; -} - -const std::vector& getDeviceParameters() { - static std::vector parameters = [] { - std::vector result; - const auto factories = - ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor); - const auto devices = getCachedPolicyConfig().getModulesWithDevicesNames(); - result.reserve(devices.size()); - for (const auto& factoryName : factories) { - for (const auto& deviceName : devices) { - if (DeviceManager::getInstance().get(factoryName, deviceName) != nullptr) { - result.emplace_back(factoryName, deviceName); - } - } - } - return result; - }(); - return parameters; -} - const std::vector& getOutputDeviceConfigParameters() { static std::vector parameters = [] { std::vector result; diff --git a/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h b/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h deleted file mode 100644 index 593759f17c..0000000000 --- a/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H -#define ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H - -#include - -#include "utility/EnvironmentTearDown.h" - -class Environment : public ::android::hardware::audio::common::test::utility::EnvironmentTearDown, - public ::testing::Environment { - public: - void init(int* /*argc*/, char** /*argv*/) {} // emulate VtsHalHidlTargetTestEnvBase - private: - void TearDown() override { executeAllTearDowns(); } -}; - -// FIXME: Will be removed while making getDeviceParameters to use the config -static constexpr const char* kDefaultServiceName = "default"; - -#endif // ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp index 715f3763b2..db52e6095f 100644 --- a/audio/core/all-versions/vts/functional/Android.bp +++ b/audio/core/all-versions/vts/functional/Android.bp @@ -31,7 +31,10 @@ cc_defaults { header_libs: [ "android.hardware.audio.common.util@all-versions", ], - test_suites: ["general-tests"], + test_suites: [ + "general-tests", + "vts-core", + ], } cc_test { @@ -49,6 +52,12 @@ cc_test { "-DMINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", ], + data: [ + ":audio_policy_configuration_V2_0", + ], + // Use test_config for vts-core suite. + // TODO(b/146104851): Add auto-gen rules and remove it. + test_config: "VtsHalAudioV2_0TargetTest.xml", } cc_test { @@ -66,6 +75,12 @@ cc_test { "-DMINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", ], + data: [ + ":audio_policy_configuration_V4_0", + ], + // Use test_config for vts-core suite. + // TODO(b/146104851): Add auto-gen rules and remove it. + test_config: "VtsHalAudioV4_0TargetTest.xml", } cc_test { @@ -83,6 +98,12 @@ cc_test { "-DMINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", ], + data: [ + ":audio_policy_configuration_V5_0", + ], + // Use test_config for vts-core suite. + // TODO(b/146104851): Add auto-gen rules and remove it. + test_config: "VtsHalAudioV5_0TargetTest.xml", } cc_test { @@ -100,14 +121,10 @@ cc_test { "-DMINOR_VERSION=0", "-include common/all-versions/VersionMacro.h", ], - // Use test_config for vts-core suite. - // TODO(b/146104851): Add auto-gen rules and remove it. - test_config: "VtsHalAudioV6_0TargetTest.xml", data: [ ":audio_policy_configuration_V6_0", ], - test_suites: [ - "general-tests", - "vts-core", - ], + // Use test_config for vts-core suite. + // TODO(b/146104851): Add auto-gen rules and remove it. + test_config: "VtsHalAudioV6_0TargetTest.xml", } diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h index b77aec9208..5d82e7bd80 100644 --- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -34,10 +34,6 @@ #include -#if MAJOR_VERSION <= 5 -#include -#endif - #include #include PATH(android/hardware/audio/FILE_VERSION/IDevice.h) @@ -49,10 +45,8 @@ #include #include #include -#if MAJOR_VERSION >= 6 #include #include -#endif #include @@ -61,12 +55,6 @@ #include "utility/ReturnIn.h" #include "utility/ValidateXml.h" -#if MAJOR_VERSION <= 5 -#include "2.0/EnvironmentTearDown.h" -#elif MAJOR_VERSION >= 6 -#include "6.0/EnvironmentTearDown.h" -#endif - /** Provide version specific functions that are used in the generic tests */ #if MAJOR_VERSION == 2 #include "2.0/AudioPrimaryHidlHalUtils.h" @@ -114,30 +102,10 @@ static auto okOrInvalidStateOrNotSupported = {Result::OK, Result::INVALID_STATE, static auto invalidArgsOrNotSupported = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED}; static auto invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUPPORTED}; -////////////////////////////////////////////////////////////////////////////// -//////////////////////////////// Environment ///////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -class AudioHidlTestEnvironment : public ::Environment { - public: -#if MAJOR_VERSION <= 5 - void registerTestServices() override { registerTestService(); } -#endif -}; - -// Instance to register global tearDown -static AudioHidlTestEnvironment* environment; - #define AUDIO_PRIMARY_HIDL_HAL_TEST #include "DeviceManager.h" -#if MAJOR_VERSION <= 5 -using HidlTestBase = ::testing::VtsHalHidlTargetTestBase; -#elif MAJOR_VERSION >= 6 -using HidlTestBase = ::testing::Test; -#endif - -class HidlTest : public HidlTestBase { +class HidlTest : public ::testing::Test { public: virtual ~HidlTest() = default; // public access to avoid annoyances when using this method in template classes @@ -174,15 +142,6 @@ static constexpr char kConfigFileName[] = "audio_policy_configuration.xml"; #define QUOTE(x) #x #define STRINGIFY(x) QUOTE(x) -TEST(CheckConfig, audioPolicyConfigurationValidation) { - RecordProperty("description", - "Verify that the audio policy configuration file " - "is valid according to the schema"); - - const char* xsd = "/data/local/tmp/audio_policy_configuration_" STRINGIFY(CPP_VERSION) ".xsd"; - EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(kConfigFileName, kConfigLocations, xsd); -} - struct PolicyConfigData { android::HwModuleCollection hwModules; android::DeviceVector availableOutputDevices; @@ -254,32 +213,11 @@ class PolicyConfig : private PolicyConfigData, public AudioPolicyConfig { const PolicyConfig& getCachedPolicyConfig() { static std::unique_ptr policyConfig = [] { auto config = std::make_unique(); - environment->registerTearDown([] { policyConfig.reset(); }); return config; }(); return *policyConfig; } -class AudioPolicyConfigTest : public HidlTestBase { - public: - void SetUp() override { - ASSERT_NO_FATAL_FAILURE(HidlTestBase::SetUp()); // setup base - auto& policyConfig = getCachedPolicyConfig(); - ASSERT_EQ(0, policyConfig.getStatus()) << policyConfig.getError(); - } -}; - -TEST_F(AudioPolicyConfigTest, LoadAudioPolicyXMLConfiguration) { - doc::test("Test parsing audio_policy_configuration.xml (called in SetUp)"); -} - -TEST_F(AudioPolicyConfigTest, HasPrimaryModule) { - auto& policyConfig = getCachedPolicyConfig(); - ASSERT_TRUE(policyConfig.getPrimaryModule() != nullptr) - << "Could not find primary module in configuration file: " - << policyConfig.getFilePath(); -} - ////////////////////////////////////////////////////////////////////////////// //////////////////// Test parameter types and definitions //////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -290,53 +228,59 @@ using DeviceParameter = std::tuple; static inline std::string DeviceParameterToString( const ::testing::TestParamInfo& info) { const auto& deviceName = std::get(info.param); -#if MAJOR_VERSION <= 5 - return !deviceName.empty() ? deviceName : std::to_string(info.index); -#elif MAJOR_VERSION >= 6 const auto factoryName = ::android::hardware::PrintInstanceNameToString(::testing::TestParamInfo{ std::get(info.param), info.index}); return !deviceName.empty() ? factoryName + "_" + deviceName : factoryName; -#endif } -#if MAJOR_VERSION <= 5 -// For V2..5 the factory is looked up using the instance name passed -// in the environment, only one factory is returned. This is because the VTS -// framework will call the test for each instance. Only the primary device of -// the default service factory can be tested. - -// Return a pair of <"default", "primary"> or <[non-default name], ""> -// This is used to parametrize device factory tests. -// The device name is used to indicate whether IPrimaryDevice is required. -const std::vector& getDeviceParametersForFactoryTests() { - static std::vector parameters = { - {environment->getServiceName(), - environment->getServiceName() == kDefaultServiceName - ? DeviceManager::kPrimaryDevice - : ""}}; - return parameters; -} -// Return a pair of <"default", "primary"> or nothing. -// This is used to parametrize primary device tests. -const std::vector& getDeviceParametersForPrimaryDeviceTests() { - static std::vector parameters = - !std::get(*getDeviceParametersForFactoryTests().begin()).empty() - ? getDeviceParametersForFactoryTests() - : std::vector{}; - return parameters; -} -// In V2..5 device tests must only test the primary device. -// No device tests are executed for non-primary devices. const std::vector& getDeviceParameters() { - return getDeviceParametersForPrimaryDeviceTests(); + static std::vector parameters = [] { + std::vector result; + const auto factories = + ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor); + const auto devices = getCachedPolicyConfig().getModulesWithDevicesNames(); + result.reserve(devices.size()); + for (const auto& factoryName : factories) { + for (const auto& deviceName : devices) { + if (DeviceManager::getInstance().get(factoryName, deviceName) != nullptr) { + result.emplace_back(factoryName, deviceName); + } + } + } + return result; + }(); + return parameters; +} + +const std::vector& getDeviceParametersForFactoryTests() { + static std::vector parameters = [] { + std::vector result; + const auto factories = + ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor); + for (const auto& factoryName : factories) { + result.emplace_back(factoryName, + DeviceManager::getInstance().getPrimary(factoryName) != nullptr + ? DeviceManager::kPrimaryDevice + : ""); + } + return result; + }(); + return parameters; +} + +const std::vector& getDeviceParametersForPrimaryDeviceTests() { + static std::vector parameters = [] { + std::vector result; + const auto primary = std::find_if( + getDeviceParameters().begin(), getDeviceParameters().end(), [](const auto& elem) { + return std::get(elem) == DeviceManager::kPrimaryDevice; + }); + if (primary != getDeviceParameters().end()) result.push_back(*primary); + return result; + }(); + return parameters; } -#elif MAJOR_VERSION >= 6 -// For V6 and above these functions are implemented in 6.0/AudioPrimaryHidlHalTest.cpp -const std::vector& getDeviceParametersForFactoryTests(); -const std::vector& getDeviceParametersForPrimaryDeviceTests(); -const std::vector& getDeviceParameters(); -#endif class AudioHidlTestWithDeviceParameter : public HidlTest, public ::testing::WithParamInterface { @@ -349,6 +293,44 @@ class AudioHidlTestWithDeviceParameter : public HidlTest, } }; +TEST(CheckConfig, audioPolicyConfigurationValidation) { + auto deviceParameters = getDeviceParametersForFactoryTests(); + if (deviceParameters.size() == 0) { + GTEST_SKIP() << "Skipping audioPolicyConfigurationValidation because no device parameter " + "is found."; + } + RecordProperty("description", + "Verify that the audio policy configuration file " + "is valid according to the schema"); + + const char* xsd = "/data/local/tmp/audio_policy_configuration_" STRINGIFY(CPP_VERSION) ".xsd"; + EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(kConfigFileName, kConfigLocations, xsd); +} + +class AudioPolicyConfigTest : public AudioHidlTestWithDeviceParameter { + public: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceParameter::SetUp()); // setup base + auto& policyConfig = getCachedPolicyConfig(); + ASSERT_EQ(0, policyConfig.getStatus()) << policyConfig.getError(); + } +}; + +TEST_P(AudioPolicyConfigTest, LoadAudioPolicyXMLConfiguration) { + doc::test("Test parsing audio_policy_configuration.xml (called in SetUp)"); +} + +TEST_P(AudioPolicyConfigTest, HasPrimaryModule) { + auto& policyConfig = getCachedPolicyConfig(); + ASSERT_TRUE(policyConfig.getPrimaryModule() != nullptr) + << "Could not find primary module in configuration file: " + << policyConfig.getFilePath(); +} + +INSTANTIATE_TEST_CASE_P(AudioHidl, AudioPolicyConfigTest, + ::testing::ValuesIn(getDeviceParametersForFactoryTests()), + &DeviceParameterToString); + ////////////////////////////////////////////////////////////////////////////// ////////////////////// getService audio_devices_factory ////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -1576,20 +1558,3 @@ TEST_P(BoolAccessorPrimaryHidlTest, setGetHac) { testAccessors("HAC", Initial{false}, {true}, &IPrimaryDevice::setHacEnabled, &IPrimaryDevice::getHacEnabled); } - -////////////////////////////////////////////////////////////////////////////// -//////////////////// Clean caches on global tear down //////////////////////// -////////////////////////////////////////////////////////////////////////////// - -int main(int argc, char** argv) { - environment = new AudioHidlTestEnvironment; - // For V2..5 it's critical to initialize environment before GTest. - // The environment parses the service name from the command line, - // then it can be used in GTest parameter generators which are - // initialized during the call to InitGoogleTest. - environment->init(&argc, argv); - ::testing::AddGlobalTestEnvironment(environment); - ::testing::InitGoogleTest(&argc, argv); - int status = RUN_ALL_TESTS(); - return status; -} diff --git a/audio/core/all-versions/vts/functional/DeviceManager.h b/audio/core/all-versions/vts/functional/DeviceManager.h index cb6584d123..0c0727f283 100644 --- a/audio/core/all-versions/vts/functional/DeviceManager.h +++ b/audio/core/all-versions/vts/functional/DeviceManager.h @@ -31,10 +31,6 @@ class InterfaceManager { auto existing = instances.find(name); if (existing != instances.end()) return existing->second; auto [inserted, _] = instances.emplace(name, Derived::createInterfaceInstance(name)); - if (inserted->second) { - environment->registerTearDown( - [name]() { (void)Derived::getInstance().reset(name, false); }); - } return inserted->second; } @@ -75,11 +71,7 @@ class DevicesFactoryManager return instance; } static sp createInterfaceInstance(const std::string& name) { -#if MAJOR_VERSION <= 5 - return ::testing::VtsHalHidlTargetTestBase::getService(name); -#elif MAJOR_VERSION >= 6 return IDevicesFactory::getService(name); -#endif } }; diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV2_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV2_0TargetTest.xml new file mode 100644 index 0000000000..67fcdb64c3 --- /dev/null +++ b/audio/core/all-versions/vts/functional/VtsHalAudioV2_0TargetTest.xml @@ -0,0 +1,40 @@ + + + + diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV4_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV4_0TargetTest.xml new file mode 100644 index 0000000000..2084060703 --- /dev/null +++ b/audio/core/all-versions/vts/functional/VtsHalAudioV4_0TargetTest.xml @@ -0,0 +1,40 @@ + + + + diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV5_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV5_0TargetTest.xml new file mode 100644 index 0000000000..8b01e41fec --- /dev/null +++ b/audio/core/all-versions/vts/functional/VtsHalAudioV5_0TargetTest.xml @@ -0,0 +1,40 @@ + + + + From e2654bfb873ad47b4d6fba89d008833d898f7120 Mon Sep 17 00:00:00 2001 From: Amy Zhang Date: Fri, 27 Mar 2020 15:58:06 -0700 Subject: [PATCH 0812/1022] Add SECTION/TS/AUDIO/VIDEO Tuner vts Broadcast tests Please expect to see a refactoring on a more robust and cleaner version of the new filter tests the child CL. Test: atest VtsHalTvTunerV1_0TargetTest on cf and vendor device Bug: 150953857 Change-Id: I34fbb193d0208d19496f360d900ae5078ece2cc5 --- .../VtsHalTvTunerV1_0TargetTest.cpp | 128 ++++++++++++------ .../VtsHalTvTunerV1_0TestConfigurations.h | 113 +++++++++------- 2 files changed, 152 insertions(+), 89 deletions(-) diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 8b0413cec8..8f83d82afe 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -889,6 +889,7 @@ class TunerHidlTest : public testing::TestWithParam { RecordSettings recordSetting, vector goldenOutputFiles); AssertionResult broadcastDataFlowTest(vector goldenOutputFiles); + void broadcastFilterTest(int selectedFilter, int feId); FilterEventType getFilterEventType(DemuxFilterType type); }; @@ -1183,6 +1184,28 @@ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutp return success(); } +void TunerHidlTest::broadcastFilterTest(int selectedFilter, int feId) { + ASSERT_TRUE(openFrontend(feId)); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(openDemux()); + ASSERT_TRUE(setDemuxFrontendDataSource(feId)); + ASSERT_TRUE(openFilterInDemux(filterArray[selectedFilter].type)); + uint32_t filterId; + ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); + ASSERT_TRUE(configFilter(filterArray[selectedFilter].setting, filterId)); + ASSERT_TRUE(getFilterMQDescriptor(filterId)); + ASSERT_TRUE(startFilter(filterId)); + // tune test + ASSERT_TRUE(tuneFrontend(frontendArray[DVBT])); + // broadcast data flow test + ASSERT_TRUE(broadcastDataFlowTest(goldenOutputFiles)); + ASSERT_TRUE(stopTuneFrontend()); + ASSERT_TRUE(stopFilter(filterId)); + ASSERT_TRUE(closeFilter(filterId)); + ASSERT_TRUE(closeDemux()); + ASSERT_TRUE(closeFrontend()); +} + /* * TODO: re-enable the tests after finalizing the test refactoring. */ @@ -1401,16 +1424,14 @@ TEST_P(TunerHidlTest, TuneFrontend) { description("Tune one Frontend with specific setting and check Lock event"); ASSERT_TRUE(getFrontendIds()); ASSERT_TRUE(mFeIds.size() > 0); - ALOGW("[vts] expected Frontend type is %d", frontendArray[0].type); for (size_t i = 0; i < mFeIds.size(); i++) { ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - ALOGW("[vts] Frontend type is %d", mFrontendInfo.type); - if (mFrontendInfo.type != frontendArray[0].type) { + if (mFrontendInfo.type != frontendArray[DVBT].type) { continue; } ASSERT_TRUE(openFrontend(mFeIds[i])); ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(tuneFrontend(frontendArray[0])); + ASSERT_TRUE(tuneFrontend(frontendArray[DVBT])); ASSERT_TRUE(stopTuneFrontend()); ASSERT_TRUE(closeFrontend()); break; @@ -1424,12 +1445,12 @@ TEST_P(TunerHidlTest, AutoScanFrontend) { for (size_t i = 0; i < mFeIds.size(); i++) { ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendArray[0].type) { + if (mFrontendInfo.type != frontendScanArray[SCAN_DVBT].type) { continue; } ASSERT_TRUE(openFrontend(mFeIds[i])); ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(scanFrontend(frontendScanArray[0], FrontendScanType::SCAN_AUTO)); + ASSERT_TRUE(scanFrontend(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_AUTO)); ASSERT_TRUE(stopScanFrontend()); ASSERT_TRUE(closeFrontend()); break; @@ -1443,12 +1464,12 @@ TEST_P(TunerHidlTest, BlindScanFrontend) { for (size_t i = 0; i < mFeIds.size(); i++) { ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendArray[0].type) { + if (mFrontendInfo.type != frontendScanArray[SCAN_DVBT].type) { continue; } ASSERT_TRUE(openFrontend(mFeIds[i])); ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(scanFrontend(frontendScanArray[0], FrontendScanType::SCAN_BLIND)); + ASSERT_TRUE(scanFrontend(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_BLIND)); ASSERT_TRUE(stopScanFrontend()); ASSERT_TRUE(closeFrontend()); break; @@ -1464,7 +1485,7 @@ TEST_P(TunerHidlTest, OpenDemuxWithFrontendDataSource) { for (size_t i = 0; i < mFeIds.size(); i++) { ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendArray[0].type) { + if (mFrontendInfo.type != frontendArray[DVBT].type) { continue; } ASSERT_TRUE(openFrontend(mFeIds[i])); @@ -1484,14 +1505,14 @@ TEST_P(TunerHidlTest, OpenFilterInDemux) { for (size_t i = 0; i < mFeIds.size(); i++) { ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendArray[0].type) { + if (mFrontendInfo.type != frontendArray[DVBT].type) { continue; } ASSERT_TRUE(openFrontend(mFeIds[i])); ASSERT_TRUE(setFrontendCallback()); ASSERT_TRUE(openDemux()); ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i])); - ASSERT_TRUE(openFilterInDemux(filterArray[0].type)); + ASSERT_TRUE(openFilterInDemux(filterArray[TS_VIDEO0].type)); uint32_t filterId; ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); ASSERT_TRUE(closeFilter(filterId)); @@ -1508,17 +1529,17 @@ TEST_P(TunerHidlTest, StartFilterInDemux) { for (size_t i = 0; i < mFeIds.size(); i++) { ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendArray[0].type) { + if (mFrontendInfo.type != frontendArray[DVBT].type) { continue; } ASSERT_TRUE(openFrontend(mFeIds[i])); ASSERT_TRUE(setFrontendCallback()); ASSERT_TRUE(openDemux()); ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i])); - ASSERT_TRUE(openFilterInDemux(filterArray[0].type)); + ASSERT_TRUE(openFilterInDemux(filterArray[TS_VIDEO0].type)); uint32_t filterId; ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); - ASSERT_TRUE(configFilter(filterArray[0].setting, filterId)); + ASSERT_TRUE(configFilter(filterArray[TS_VIDEO0].setting, filterId)); ASSERT_TRUE(getFilterMQDescriptor(filterId)); ASSERT_TRUE(startFilter(filterId)); ASSERT_TRUE(stopFilter(filterId)); @@ -1546,35 +1567,62 @@ TEST_P(TunerHidlTest, CloseDescrambler) { /*============================== End Descrambler Tests ==============================*/ /*============================== Start Data Flow Tests ==============================*/ -TEST_P(TunerHidlTest, BroadcastDataFlowWithAudioFilterTest) { - description("Open Demux with a Frontend as its data source."); +TEST_P(TunerHidlTest, BroadcastDataFlowVideoFilterTest) { + description("Test Video Filter functionality in Broadcast use case."); ASSERT_TRUE(getFrontendIds()); ASSERT_TRUE(mFeIds.size() > 0); for (size_t i = 0; i < mFeIds.size(); i++) { ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendArray[0].type) { + if (mFrontendInfo.type != frontendArray[DVBT].type) { continue; } - ASSERT_TRUE(openFrontend(mFeIds[i])); - ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(openDemux()); - ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i])); - ASSERT_TRUE(openFilterInDemux(filterArray[0].type)); - uint32_t filterId; - ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); - ASSERT_TRUE(configFilter(filterArray[0].setting, filterId)); - ASSERT_TRUE(getFilterMQDescriptor(filterId)); - ASSERT_TRUE(startFilter(filterId)); - // tune test - ASSERT_TRUE(tuneFrontend(frontendArray[0])); - // broadcast data flow test - ASSERT_TRUE(broadcastDataFlowTest(goldenOutputFiles)); - ASSERT_TRUE(stopTuneFrontend()); - ASSERT_TRUE(stopFilter(filterId)); - ASSERT_TRUE(closeFilter(filterId)); - ASSERT_TRUE(closeDemux()); - ASSERT_TRUE(closeFrontend()); + broadcastFilterTest(TS_VIDEO1, mFeIds[i]); + break; + } +} + +TEST_P(TunerHidlTest, BroadcastDataFlowAudioFilterTest) { + description("Test Audio Filter functionality in Broadcast use case."); + ASSERT_TRUE(getFrontendIds()); + ASSERT_TRUE(mFeIds.size() > 0); + + for (size_t i = 0; i < mFeIds.size(); i++) { + ASSERT_TRUE(getFrontendInfo(mFeIds[i])); + if (mFrontendInfo.type != frontendArray[DVBT].type) { + continue; + } + broadcastFilterTest(TS_AUDIO0, mFeIds[i]); + break; + } +} + +TEST_P(TunerHidlTest, BroadcastDataFlowTsFilterTest) { + description("Test TS Filter functionality in Broadcast use case."); + ASSERT_TRUE(getFrontendIds()); + ASSERT_TRUE(mFeIds.size() > 0); + + for (size_t i = 0; i < mFeIds.size(); i++) { + ASSERT_TRUE(getFrontendInfo(mFeIds[i])); + if (mFrontendInfo.type != frontendArray[DVBT].type) { + continue; + } + broadcastFilterTest(TS_TS0, mFeIds[i]); + break; + } +} + +TEST_P(TunerHidlTest, BroadcastDataFlowSectionFilterTest) { + description("Test Section Filter functionality in Broadcast use case."); + ASSERT_TRUE(getFrontendIds()); + ASSERT_TRUE(mFeIds.size() > 0); + + for (size_t i = 0; i < mFeIds.size(); i++) { + ASSERT_TRUE(getFrontendInfo(mFeIds[i])); + if (mFrontendInfo.type != frontendArray[DVBT].type) { + continue; + } + broadcastFilterTest(TS_SECTION0, mFeIds[i]); break; } } @@ -1671,20 +1719,20 @@ TEST_P(TunerHidlTest, AvBufferTest) { for (size_t i = 0; i < mFeIds.size(); i++) { ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendArray[1].type) { + if (mFrontendInfo.type != frontendArray[DVBS].type) { continue; } ASSERT_TRUE(openFrontend(mFeIds[i])); ASSERT_TRUE(setFrontendCallback()); ASSERT_TRUE(openDemux()); - ASSERT_TRUE(openFilterInDemux(filterArray[0].type)); + ASSERT_TRUE(openFilterInDemux(filterArray[TS_VIDEO0].type)); uint32_t filterId; ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); - ASSERT_TRUE(configFilter(filterArray[0].setting, filterId)); + ASSERT_TRUE(configFilter(filterArray[TS_VIDEO0].setting, filterId)); ASSERT_TRUE(startFilter(filterId)); ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i])); // tune test - ASSERT_TRUE(tuneFrontend(frontendArray[1])); + ASSERT_TRUE(tuneFrontend(frontendArray[DVBS])); // broadcast data flow test ASSERT_TRUE(broadcastDataFlowTest(goldenOutputFiles)); ASSERT_TRUE(stopTuneFrontend()); diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h index 31e3b51cd7..10c60142ba 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h @@ -14,42 +14,18 @@ * limitations under the License. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include #include #include #include #include -#include -#include -#include -#include -#include using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; using android::hardware::tv::tuner::V1_0::DemuxFilterMainType; -using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; -using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent; -using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings; -using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent; -using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; -using android::hardware::tv::tuner::V1_0::DemuxFilterStatus; using android::hardware::tv::tuner::V1_0::DemuxFilterType; -using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; using android::hardware::tv::tuner::V1_0::DemuxTpid; -using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings; using android::hardware::tv::tuner::V1_0::DemuxTsFilterType; using android::hardware::tv::tuner::V1_0::FrontendDvbtBandwidth; using android::hardware::tv::tuner::V1_0::FrontendDvbtCoderate; @@ -62,12 +38,27 @@ using android::hardware::tv::tuner::V1_0::FrontendDvbtTransmissionMode; using android::hardware::tv::tuner::V1_0::FrontendSettings; using android::hardware::tv::tuner::V1_0::FrontendType; -namespace { +typedef enum { + TS_VIDEO0, + TS_VIDEO1, + TS_AUDIO0, + TS_PES0, + TS_PCR0, + TS_SECTION0, + TS_TS0, + FILTER_MAX, +} Filter; -#define frontend_transponders_count 2 -#define channels_count 1 -#define frontend_scan_count 1 -#define filter_count 2 +typedef enum { + DVBT, + DVBS, + FRONTEND_MAX, +} Frontend; + +typedef enum { + SCAN_DVBT, + SCAN_MAX, +} FrontendScan; struct FilterConfig { DemuxFilterType type; @@ -87,10 +78,10 @@ struct ChannelConfig { DemuxTpid audioPid; }; -static FrontendConfig frontendArray[frontend_transponders_count]; -static FrontendConfig frontendScanArray[channels_count]; -static ChannelConfig channelArray[frontend_scan_count]; -static FilterConfig filterArray[filter_count]; +static FrontendConfig frontendArray[FILTER_MAX]; +static FrontendConfig frontendScanArray[SCAN_MAX]; +static ChannelConfig channelArray[FRONTEND_MAX]; +static FilterConfig filterArray[FILTER_MAX]; static vector goldenOutputFiles; /** Configuration array for the frontend tune test */ @@ -107,14 +98,14 @@ inline void initFrontendConfig() { .isHighPriority = true, .standard = FrontendDvbtStandard::T, }; - frontendArray[0].type = FrontendType::DVBT, frontendArray[0].settings.dvbt(dvbtSettings); - frontendArray[1].type = FrontendType::DVBS; + frontendArray[DVBT].type = FrontendType::DVBT, frontendArray[DVBT].settings.dvbt(dvbtSettings); + frontendArray[DVBS].type = FrontendType::DVBS; }; /** Configuration array for the frontend scan test */ inline void initFrontendScanConfig() { - frontendScanArray[0].type = FrontendType::DVBT; - frontendScanArray[0].settings.dvbt({ + frontendScanArray[SCAN_DVBT].type = FrontendType::DVBT; + frontendScanArray[SCAN_DVBT].settings.dvbt({ .frequency = 578000, .transmissionMode = FrontendDvbtTransmissionMode::MODE_8K, .bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ, @@ -130,19 +121,43 @@ inline void initFrontendScanConfig() { /** Configuration array for the filter test */ inline void initFilterConfig() { - // TS Video filter setting - filterArray[0].type.mainType = DemuxFilterMainType::TS; - filterArray[0].type.subType.tsFilterType(DemuxTsFilterType::VIDEO); - filterArray[0].setting.ts().tpid = 119; - filterArray[0].setting.ts().filterSettings.av({.isPassthrough = false}); + // TS VIDEO filter setting for default implementation testing + filterArray[TS_VIDEO0].type.mainType = DemuxFilterMainType::TS; + filterArray[TS_VIDEO0].type.subType.tsFilterType(DemuxTsFilterType::VIDEO); + filterArray[TS_VIDEO0].setting.ts().tpid = 119; + filterArray[TS_VIDEO0].setting.ts().filterSettings.av({.isPassthrough = false}); + filterArray[TS_VIDEO1].type.mainType = DemuxFilterMainType::TS; + filterArray[TS_VIDEO1].type.subType.tsFilterType(DemuxTsFilterType::VIDEO); + filterArray[TS_VIDEO1].setting.ts().tpid = 81; + filterArray[TS_VIDEO1].setting.ts().filterSettings.av({.isPassthrough = false}); + // TS AUDIO filter setting + filterArray[TS_AUDIO0].type.mainType = DemuxFilterMainType::TS; + filterArray[TS_AUDIO0].type.subType.tsFilterType(DemuxTsFilterType::AUDIO); + filterArray[TS_AUDIO0].setting.ts().tpid = 84; + filterArray[TS_AUDIO0].setting.ts().filterSettings.av({.isPassthrough = false}); // TS PES filter setting - filterArray[1].type.mainType = DemuxFilterMainType::TS; - filterArray[1].type.subType.tsFilterType(DemuxTsFilterType::PES); - filterArray[1].setting.ts().tpid = 256; - filterArray[1].setting.ts().filterSettings.pesData({ - .isRaw = true, + filterArray[TS_PES0].type.mainType = DemuxFilterMainType::TS; + filterArray[TS_PES0].type.subType.tsFilterType(DemuxTsFilterType::PES); + filterArray[TS_PES0].setting.ts().tpid = 256; + filterArray[TS_PES0].setting.ts().filterSettings.pesData({ + .isRaw = false, .streamId = 0xbd, }); + // TS PCR filter setting + filterArray[TS_PCR0].type.mainType = DemuxFilterMainType::TS; + filterArray[TS_PCR0].type.subType.tsFilterType(DemuxTsFilterType::PCR); + filterArray[TS_PCR0].setting.ts().tpid = 81; + filterArray[TS_PCR0].setting.ts().filterSettings.noinit(); + // TS filter setting + filterArray[TS_TS0].type.mainType = DemuxFilterMainType::TS; + filterArray[TS_TS0].type.subType.tsFilterType(DemuxTsFilterType::TS); + filterArray[TS_TS0].setting.ts().tpid = 48; + filterArray[TS_TS0].setting.ts().filterSettings.noinit(); + // TS SECTION filter setting + filterArray[TS_SECTION0].type.mainType = DemuxFilterMainType::TS; + filterArray[TS_SECTION0].type.subType.tsFilterType(DemuxTsFilterType::SECTION); + filterArray[TS_SECTION0].setting.ts().tpid = 48; + filterArray[TS_SECTION0].setting.ts().filterSettings.section({ + .isRaw = false, + }); }; - -} // namespace From aad51fa00017127a9b9c019e94add55ca49dc450 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Sun, 5 Apr 2020 14:34:48 -0700 Subject: [PATCH 0813/1022] Rename vts-core to vts Bug: 151896491 Test: local build Exempt-From-Owner-Approval: This CL update suite name vts-core to vts as the suite name is updated. This CL won't change test logic or behavior. Change-Id: I562b4dc50765e953800a814a8fd84a01c1b9352b Merged-In: I562b4dc50765e953800a814a8fd84a01c1b9352b --- atrace/1.0/vts/functional/Android.bp | 2 +- audio/effect/all-versions/vts/functional/Android.bp | 10 +++++----- audio/policy/1.0/vts/functional/Android.bp | 4 ++-- authsecret/1.0/vts/functional/Android.bp | 2 +- automotive/audiocontrol/2.0/vts/functional/Android.bp | 2 +- automotive/evs/1.0/vts/functional/Android.bp | 2 +- automotive/evs/1.1/vts/functional/Android.bp | 2 +- .../occupant_awareness/aidl/vts/functional/Android.bp | 2 +- automotive/sv/1.0/vts/functional/Android.bp | 2 +- biometrics/face/1.0/vts/functional/Android.bp | 2 +- biometrics/fingerprint/2.1/vts/functional/Android.bp | 2 +- biometrics/fingerprint/2.2/vts/functional/Android.bp | 2 +- bluetooth/1.0/vts/functional/Android.bp | 2 +- bluetooth/1.1/vts/functional/Android.bp | 2 +- bluetooth/audio/2.0/vts/functional/Android.bp | 2 +- boot/1.0/vts/functional/Android.bp | 2 +- broadcastradio/2.0/vts/functional/Android.bp | 2 +- camera/provider/2.4/vts/functional/Android.bp | 2 +- cas/1.0/vts/functional/Android.bp | 2 +- cas/1.1/vts/functional/Android.bp | 2 +- cas/1.2/vts/functional/Android.bp | 2 +- configstore/1.0/vts/functional/Android.bp | 2 +- confirmationui/1.0/vts/functional/Android.bp | 2 +- contexthub/1.0/vts/functional/Android.bp | 2 +- contexthub/1.1/vts/functional/Android.bp | 2 +- drm/1.0/vts/functional/Android.bp | 2 +- drm/1.1/vts/functional/Android.bp | 2 +- drm/1.2/vts/functional/Android.bp | 2 +- drm/1.3/vts/functional/Android.bp | 2 +- dumpstate/1.0/vts/functional/Android.bp | 2 +- dumpstate/1.1/vts/functional/Android.bp | 2 +- gatekeeper/1.0/vts/functional/Android.bp | 2 +- gnss/1.0/vts/functional/Android.bp | 2 +- gnss/1.1/vts/functional/Android.bp | 2 +- gnss/2.0/vts/functional/Android.bp | 2 +- gnss/2.1/vts/functional/Android.bp | 2 +- graphics/composer/2.1/vts/functional/Android.bp | 2 +- graphics/composer/2.2/vts/functional/Android.bp | 2 +- graphics/composer/2.3/vts/functional/Android.bp | 2 +- graphics/composer/2.4/vts/functional/Android.bp | 2 +- graphics/mapper/2.0/vts/functional/Android.bp | 2 +- graphics/mapper/2.1/vts/functional/Android.bp | 2 +- graphics/mapper/3.0/vts/functional/Android.bp | 2 +- graphics/mapper/4.0/vts/functional/Android.bp | 2 +- health/1.0/vts/functional/Android.bp | 2 +- health/2.0/vts/functional/Android.bp | 2 +- health/2.1/vts/functional/Android.bp | 2 +- health/storage/1.0/vts/functional/Android.bp | 2 +- identity/aidl/vts/Android.bp | 2 +- input/classifier/1.0/vts/functional/Android.bp | 2 +- ir/1.0/vts/functional/Android.bp | 2 +- keymaster/3.0/vts/functional/Android.bp | 2 +- keymaster/4.0/vts/functional/Android.bp | 2 +- keymaster/4.1/vts/functional/Android.bp | 2 +- light/2.0/vts/functional/Android.bp | 2 +- light/aidl/vts/functional/Android.bp | 2 +- memtrack/1.0/vts/functional/Android.bp | 2 +- neuralnetworks/1.0/vts/functional/Android.bp | 2 +- neuralnetworks/1.1/vts/functional/Android.bp | 2 +- neuralnetworks/1.2/vts/functional/Android.bp | 2 +- nfc/1.0/vts/functional/Android.bp | 2 +- nfc/1.1/vts/functional/Android.bp | 2 +- nfc/1.2/vts/functional/Android.bp | 2 +- oemlock/1.0/vts/functional/Android.bp | 2 +- power/1.0/vts/functional/Android.bp | 2 +- power/1.1/vts/functional/Android.bp | 2 +- power/1.2/vts/functional/Android.bp | 2 +- power/1.3/vts/functional/Android.bp | 2 +- power/aidl/vts/Android.bp | 2 +- power/stats/1.0/vts/functional/Android.bp | 2 +- radio/1.0/vts/functional/Android.bp | 4 ++-- radio/1.1/vts/functional/Android.bp | 2 +- radio/1.2/vts/functional/Android.bp | 2 +- radio/1.3/vts/functional/Android.bp | 2 +- radio/1.4/vts/functional/Android.bp | 2 +- radio/1.5/vts/functional/Android.bp | 2 +- radio/config/1.0/vts/functional/Android.bp | 2 +- radio/config/1.1/vts/functional/Android.bp | 2 +- radio/config/1.2/vts/functional/Android.bp | 2 +- rebootescrow/aidl/vts/functional/Android.bp | 2 +- renderscript/1.0/vts/functional/Android.bp | 2 +- secure_element/1.0/vts/functional/Android.bp | 2 +- secure_element/1.1/vts/functional/Android.bp | 2 +- secure_element/1.2/vts/functional/Android.bp | 2 +- sensors/1.0/vts/functional/Android.bp | 2 +- sensors/2.0/vts/functional/Android.bp | 2 +- sensors/2.1/vts/functional/Android.bp | 2 +- soundtrigger/2.0/vts/functional/Android.bp | 2 +- soundtrigger/2.1/vts/functional/Android.bp | 2 +- soundtrigger/2.2/vts/functional/Android.bp | 2 +- soundtrigger/2.3/vts/functional/Android.bp | 2 +- tetheroffload/config/1.0/vts/functional/Android.bp | 2 +- tetheroffload/control/1.0/vts/functional/Android.bp | 2 +- thermal/1.0/vts/functional/Android.bp | 2 +- thermal/1.1/vts/functional/Android.bp | 2 +- thermal/2.0/vts/functional/Android.bp | 2 +- tv/input/1.0/vts/functional/Android.bp | 2 +- tv/tuner/1.0/vts/functional/Android.bp | 2 +- usb/1.0/vts/functional/Android.bp | 2 +- usb/1.1/vts/functional/Android.bp | 2 +- vibrator/1.0/vts/functional/Android.bp | 2 +- vibrator/1.1/vts/functional/Android.bp | 2 +- vibrator/1.2/vts/functional/Android.bp | 2 +- vibrator/1.3/vts/functional/Android.bp | 2 +- vibrator/aidl/vts/Android.bp | 2 +- vr/1.0/vts/functional/Android.bp | 2 +- weaver/1.0/vts/functional/Android.bp | 2 +- wifi/1.0/vts/functional/Android.bp | 6 +++--- wifi/1.1/vts/functional/Android.bp | 2 +- wifi/1.2/vts/functional/Android.bp | 4 ++-- wifi/1.3/vts/functional/Android.bp | 2 +- wifi/1.4/vts/functional/Android.bp | 2 +- wifi/hostapd/1.0/vts/functional/Android.bp | 2 +- wifi/hostapd/1.1/vts/functional/Android.bp | 2 +- wifi/hostapd/1.2/vts/functional/Android.bp | 2 +- wifi/offload/1.0/vts/functional/Android.bp | 2 +- wifi/supplicant/1.0/vts/functional/Android.bp | 4 ++-- wifi/supplicant/1.1/vts/functional/Android.bp | 2 +- wifi/supplicant/1.2/vts/functional/Android.bp | 4 ++-- wifi/supplicant/1.3/vts/functional/Android.bp | 2 +- 120 files changed, 131 insertions(+), 131 deletions(-) diff --git a/atrace/1.0/vts/functional/Android.bp b/atrace/1.0/vts/functional/Android.bp index ae24968aba..07d3f7fedf 100644 --- a/atrace/1.0/vts/functional/Android.bp +++ b/atrace/1.0/vts/functional/Android.bp @@ -19,5 +19,5 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalAtraceV1_0TargetTest.cpp"], static_libs: ["android.hardware.atrace@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/audio/effect/all-versions/vts/functional/Android.bp b/audio/effect/all-versions/vts/functional/Android.bp index 4ab572e6ed..309aa9d27f 100644 --- a/audio/effect/all-versions/vts/functional/Android.bp +++ b/audio/effect/all-versions/vts/functional/Android.bp @@ -31,13 +31,13 @@ cc_defaults { header_libs: [ "android.hardware.audio.common.util@all-versions", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } cc_test { name: "VtsHalAudioEffectV2_0TargetTest", defaults: ["VtsHalAudioEffectTargetTest_default"], - // Use test_config for vts-core suite. + // Use test_config for vts suite. // TODO(b/146104851): Add auto-gen rules and remove it. test_config: "VtsHalAudioEffectV2_0TargetTest.xml", static_libs: [ @@ -57,7 +57,7 @@ cc_test { cc_test { name: "VtsHalAudioEffectV4_0TargetTest", defaults: ["VtsHalAudioEffectTargetTest_default"], - // Use test_config for vts-core suite. + // Use test_config for vts suite. // TODO(b/146104851): Add auto-gen rules and remove it. test_config: "VtsHalAudioEffectV4_0TargetTest.xml", static_libs: [ @@ -77,7 +77,7 @@ cc_test { cc_test { name: "VtsHalAudioEffectV5_0TargetTest", defaults: ["VtsHalAudioEffectTargetTest_default"], - // Use test_config for vts-core suite. + // Use test_config for vts suite. // TODO(b/146104851): Add auto-gen rules and remove it. test_config: "VtsHalAudioEffectV5_0TargetTest.xml", static_libs: [ @@ -97,7 +97,7 @@ cc_test { cc_test { name: "VtsHalAudioEffectV6_0TargetTest", defaults: ["VtsHalAudioEffectTargetTest_default"], - // Use test_config for vts-core suite. + // Use test_config for vts suite. // TODO(b/146104851): Add auto-gen rules and remove it. test_config: "VtsHalAudioEffectV6_0TargetTest.xml", static_libs: [ diff --git a/audio/policy/1.0/vts/functional/Android.bp b/audio/policy/1.0/vts/functional/Android.bp index b50e501d15..a5ddee51ef 100644 --- a/audio/policy/1.0/vts/functional/Android.bp +++ b/audio/policy/1.0/vts/functional/Android.bp @@ -24,7 +24,7 @@ cc_test { shared_libs: [ "libaudiofoundation", ], - // Use test_config for vts-core suite. + // Use test_config for vts suite. // TODO(b/146104851): Add auto-gen rules and remove it. test_config: "VtsHalAudioPolicyV1_0TargetTest.xml", cflags: [ @@ -54,6 +54,6 @@ cc_test { gtest: true, test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/authsecret/1.0/vts/functional/Android.bp b/authsecret/1.0/vts/functional/Android.bp index 9ce9cda2f9..c49d37492d 100644 --- a/authsecret/1.0/vts/functional/Android.bp +++ b/authsecret/1.0/vts/functional/Android.bp @@ -21,7 +21,7 @@ cc_test { static_libs: ["android.hardware.authsecret@1.0"], test_suites: [ "general-tests", - "vts-core", + "vts", ], require_root: true, } diff --git a/automotive/audiocontrol/2.0/vts/functional/Android.bp b/automotive/audiocontrol/2.0/vts/functional/Android.bp index 520b042e37..ac20509dd5 100644 --- a/automotive/audiocontrol/2.0/vts/functional/Android.bp +++ b/automotive/audiocontrol/2.0/vts/functional/Android.bp @@ -24,6 +24,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/automotive/evs/1.0/vts/functional/Android.bp b/automotive/evs/1.0/vts/functional/Android.bp index 9f7cd3f02a..74d512293b 100644 --- a/automotive/evs/1.0/vts/functional/Android.bp +++ b/automotive/evs/1.0/vts/functional/Android.bp @@ -28,7 +28,7 @@ cc_test { "android.hardware.automotive.evs@1.0", "android.hardware.automotive.evs@common-default-lib", ], - test_suites: ["vts-core"], + test_suites: ["vts"], cflags: [ "-O0", "-g", diff --git a/automotive/evs/1.1/vts/functional/Android.bp b/automotive/evs/1.1/vts/functional/Android.bp index 086a199ca5..d61f0a8f9c 100644 --- a/automotive/evs/1.1/vts/functional/Android.bp +++ b/automotive/evs/1.1/vts/functional/Android.bp @@ -38,7 +38,7 @@ cc_test { "android.hardware.graphics.common@1.2", "android.hardware.camera.device@3.2", ], - test_suites: ["vts-core"], + test_suites: ["vts"], cflags: [ "-O0", "-g", diff --git a/automotive/occupant_awareness/aidl/vts/functional/Android.bp b/automotive/occupant_awareness/aidl/vts/functional/Android.bp index 1256b69c67..514b0afc2b 100644 --- a/automotive/occupant_awareness/aidl/vts/functional/Android.bp +++ b/automotive/occupant_awareness/aidl/vts/functional/Android.bp @@ -12,6 +12,6 @@ cc_test { "android.hardware.automotive.occupant_awareness-cpp", ], test_suites: [ - "vts-core", + "vts", ], } diff --git a/automotive/sv/1.0/vts/functional/Android.bp b/automotive/sv/1.0/vts/functional/Android.bp index 0e5d3df9a7..d5d72a6c5b 100644 --- a/automotive/sv/1.0/vts/functional/Android.bp +++ b/automotive/sv/1.0/vts/functional/Android.bp @@ -33,7 +33,7 @@ cc_test { "android.hidl.memory@1.0", "libhidlmemory", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], cflags: [ "-O0", "-g", diff --git a/biometrics/face/1.0/vts/functional/Android.bp b/biometrics/face/1.0/vts/functional/Android.bp index f2598a7934..ff4a6de889 100644 --- a/biometrics/face/1.0/vts/functional/Android.bp +++ b/biometrics/face/1.0/vts/functional/Android.bp @@ -19,6 +19,6 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalBiometricsFaceV1_0TargetTest.cpp"], static_libs: ["android.hardware.biometrics.face@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/biometrics/fingerprint/2.1/vts/functional/Android.bp b/biometrics/fingerprint/2.1/vts/functional/Android.bp index c4180322b8..7e3f3406bb 100644 --- a/biometrics/fingerprint/2.1/vts/functional/Android.bp +++ b/biometrics/fingerprint/2.1/vts/functional/Android.bp @@ -19,6 +19,6 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalBiometricsFingerprintV2_1TargetTest.cpp"], static_libs: ["android.hardware.biometrics.fingerprint@2.1"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/biometrics/fingerprint/2.2/vts/functional/Android.bp b/biometrics/fingerprint/2.2/vts/functional/Android.bp index 496570c64c..5e8e7c80be 100644 --- a/biometrics/fingerprint/2.2/vts/functional/Android.bp +++ b/biometrics/fingerprint/2.2/vts/functional/Android.bp @@ -24,6 +24,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/bluetooth/1.0/vts/functional/Android.bp b/bluetooth/1.0/vts/functional/Android.bp index cf25cc8ff9..463ed849f6 100644 --- a/bluetooth/1.0/vts/functional/Android.bp +++ b/bluetooth/1.0/vts/functional/Android.bp @@ -24,6 +24,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/bluetooth/1.1/vts/functional/Android.bp b/bluetooth/1.1/vts/functional/Android.bp index 8d6d7490e3..eb4a720f95 100644 --- a/bluetooth/1.1/vts/functional/Android.bp +++ b/bluetooth/1.1/vts/functional/Android.bp @@ -23,5 +23,5 @@ cc_test { "android.hardware.bluetooth@1.0", "libbluetooth-types", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/bluetooth/audio/2.0/vts/functional/Android.bp b/bluetooth/audio/2.0/vts/functional/Android.bp index b778b97b09..0ed5da43f2 100644 --- a/bluetooth/audio/2.0/vts/functional/Android.bp +++ b/bluetooth/audio/2.0/vts/functional/Android.bp @@ -9,5 +9,5 @@ cc_test { shared_libs: [ "libfmq", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/boot/1.0/vts/functional/Android.bp b/boot/1.0/vts/functional/Android.bp index 5244b958ca..92c818c56c 100644 --- a/boot/1.0/vts/functional/Android.bp +++ b/boot/1.0/vts/functional/Android.bp @@ -19,5 +19,5 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalBootV1_0TargetTest.cpp"], static_libs: ["android.hardware.boot@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/broadcastradio/2.0/vts/functional/Android.bp b/broadcastradio/2.0/vts/functional/Android.bp index 49bb66554f..be17da32df 100644 --- a/broadcastradio/2.0/vts/functional/Android.bp +++ b/broadcastradio/2.0/vts/functional/Android.bp @@ -27,6 +27,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp index 4b9d6f125b..cd66f74571 100644 --- a/camera/provider/2.4/vts/functional/Android.bp +++ b/camera/provider/2.4/vts/functional/Android.bp @@ -49,5 +49,5 @@ cc_test { "libhidlmemory", "libgralloctypes", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/cas/1.0/vts/functional/Android.bp b/cas/1.0/vts/functional/Android.bp index ab39c0e93b..82dc568fa6 100644 --- a/cas/1.0/vts/functional/Android.bp +++ b/cas/1.0/vts/functional/Android.bp @@ -29,6 +29,6 @@ cc_test { shared_libs: [ "libbinder", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/cas/1.1/vts/functional/Android.bp b/cas/1.1/vts/functional/Android.bp index 9e8eb52efe..de223c8ce2 100644 --- a/cas/1.1/vts/functional/Android.bp +++ b/cas/1.1/vts/functional/Android.bp @@ -30,6 +30,6 @@ cc_test { shared_libs: [ "libbinder", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/cas/1.2/vts/functional/Android.bp b/cas/1.2/vts/functional/Android.bp index 2d6517f0b0..74ea85fbf2 100644 --- a/cas/1.2/vts/functional/Android.bp +++ b/cas/1.2/vts/functional/Android.bp @@ -33,6 +33,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/configstore/1.0/vts/functional/Android.bp b/configstore/1.0/vts/functional/Android.bp index 31d4b1c9d9..4e1e045dd1 100644 --- a/configstore/1.0/vts/functional/Android.bp +++ b/configstore/1.0/vts/functional/Android.bp @@ -19,6 +19,6 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalConfigstoreV1_0TargetTest.cpp"], static_libs: ["android.hardware.configstore@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/confirmationui/1.0/vts/functional/Android.bp b/confirmationui/1.0/vts/functional/Android.bp index c8b522c119..c73ee2826c 100644 --- a/confirmationui/1.0/vts/functional/Android.bp +++ b/confirmationui/1.0/vts/functional/Android.bp @@ -27,5 +27,5 @@ cc_test { "libcn-cbor", "android.hardware.confirmationui-support-lib", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/contexthub/1.0/vts/functional/Android.bp b/contexthub/1.0/vts/functional/Android.bp index d51c9669c8..091f2dc201 100644 --- a/contexthub/1.0/vts/functional/Android.bp +++ b/contexthub/1.0/vts/functional/Android.bp @@ -24,6 +24,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/contexthub/1.1/vts/functional/Android.bp b/contexthub/1.1/vts/functional/Android.bp index f1625a6b6b..034c11fb0c 100644 --- a/contexthub/1.1/vts/functional/Android.bp +++ b/contexthub/1.1/vts/functional/Android.bp @@ -25,6 +25,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/drm/1.0/vts/functional/Android.bp b/drm/1.0/vts/functional/Android.bp index 235bfb406f..476778a397 100644 --- a/drm/1.0/vts/functional/Android.bp +++ b/drm/1.0/vts/functional/Android.bp @@ -86,6 +86,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/drm/1.1/vts/functional/Android.bp b/drm/1.1/vts/functional/Android.bp index e08d760ea4..e845ea086d 100644 --- a/drm/1.1/vts/functional/Android.bp +++ b/drm/1.1/vts/functional/Android.bp @@ -67,6 +67,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/drm/1.2/vts/functional/Android.bp b/drm/1.2/vts/functional/Android.bp index ecc7d6c592..ceab75af14 100644 --- a/drm/1.2/vts/functional/Android.bp +++ b/drm/1.2/vts/functional/Android.bp @@ -72,6 +72,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/drm/1.3/vts/functional/Android.bp b/drm/1.3/vts/functional/Android.bp index ac1f912c08..4ef94ec332 100644 --- a/drm/1.3/vts/functional/Android.bp +++ b/drm/1.3/vts/functional/Android.bp @@ -73,6 +73,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/dumpstate/1.0/vts/functional/Android.bp b/dumpstate/1.0/vts/functional/Android.bp index 3bac281598..451b0536fd 100644 --- a/dumpstate/1.0/vts/functional/Android.bp +++ b/dumpstate/1.0/vts/functional/Android.bp @@ -18,5 +18,5 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalDumpstateV1_0TargetTest.cpp"], static_libs: ["android.hardware.dumpstate@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/dumpstate/1.1/vts/functional/Android.bp b/dumpstate/1.1/vts/functional/Android.bp index 5267706c0b..43a3c21b7c 100644 --- a/dumpstate/1.1/vts/functional/Android.bp +++ b/dumpstate/1.1/vts/functional/Android.bp @@ -24,6 +24,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/gatekeeper/1.0/vts/functional/Android.bp b/gatekeeper/1.0/vts/functional/Android.bp index a115285392..1ca966d20f 100644 --- a/gatekeeper/1.0/vts/functional/Android.bp +++ b/gatekeeper/1.0/vts/functional/Android.bp @@ -19,5 +19,5 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalGatekeeperV1_0TargetTest.cpp"], static_libs: ["android.hardware.gatekeeper@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/gnss/1.0/vts/functional/Android.bp b/gnss/1.0/vts/functional/Android.bp index d73b32ea8b..45755e6671 100644 --- a/gnss/1.0/vts/functional/Android.bp +++ b/gnss/1.0/vts/functional/Android.bp @@ -19,5 +19,5 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalGnssV1_0TargetTest.cpp"], static_libs: ["android.hardware.gnss@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp index 369a89da39..0d540b7250 100644 --- a/gnss/1.1/vts/functional/Android.bp +++ b/gnss/1.1/vts/functional/Android.bp @@ -33,6 +33,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/gnss/2.0/vts/functional/Android.bp b/gnss/2.0/vts/functional/Android.bp index da5289d006..d67677afe4 100644 --- a/gnss/2.0/vts/functional/Android.bp +++ b/gnss/2.0/vts/functional/Android.bp @@ -31,5 +31,5 @@ cc_test { "android.hardware.gnss@2.1", "android.hardware.gnss@common-vts-lib", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/gnss/2.1/vts/functional/Android.bp b/gnss/2.1/vts/functional/Android.bp index f008a26f1f..b3051d4b48 100644 --- a/gnss/2.1/vts/functional/Android.bp +++ b/gnss/2.1/vts/functional/Android.bp @@ -34,6 +34,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp index 5f1ed63936..dafbbf9c9e 100644 --- a/graphics/composer/2.1/vts/functional/Android.bp +++ b/graphics/composer/2.1/vts/functional/Android.bp @@ -43,5 +43,5 @@ cc_test { "android.hardware.graphics.composer@2.1-command-buffer", ], disable_framework: true, - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp index e38af00a38..e1a254dee4 100644 --- a/graphics/composer/2.2/vts/functional/Android.bp +++ b/graphics/composer/2.2/vts/functional/Android.bp @@ -61,6 +61,6 @@ cc_test { disable_framework: true, test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp index fa4823efbd..18ea2aa96c 100644 --- a/graphics/composer/2.3/vts/functional/Android.bp +++ b/graphics/composer/2.3/vts/functional/Android.bp @@ -50,5 +50,5 @@ cc_test { "android.hardware.graphics.composer@2.3-command-buffer", ], disable_framework: true, - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp index 937af3d4d2..9e7cc46c56 100644 --- a/graphics/composer/2.4/vts/functional/Android.bp +++ b/graphics/composer/2.4/vts/functional/Android.bp @@ -52,5 +52,5 @@ cc_test { "android.hardware.graphics.composer@2.4-command-buffer", ], disable_framework: true, - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/graphics/mapper/2.0/vts/functional/Android.bp b/graphics/mapper/2.0/vts/functional/Android.bp index a055b61b60..1f7ae04c15 100644 --- a/graphics/mapper/2.0/vts/functional/Android.bp +++ b/graphics/mapper/2.0/vts/functional/Android.bp @@ -24,5 +24,5 @@ cc_test { "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@2.0-vts", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/graphics/mapper/2.1/vts/functional/Android.bp b/graphics/mapper/2.1/vts/functional/Android.bp index bb76c7452a..ccbe40fd96 100644 --- a/graphics/mapper/2.1/vts/functional/Android.bp +++ b/graphics/mapper/2.1/vts/functional/Android.bp @@ -26,5 +26,5 @@ cc_test { "android.hardware.graphics.mapper@2.0-vts", "android.hardware.graphics.mapper@2.1-vts", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/graphics/mapper/3.0/vts/functional/Android.bp b/graphics/mapper/3.0/vts/functional/Android.bp index f01670e299..3f4abecdd4 100644 --- a/graphics/mapper/3.0/vts/functional/Android.bp +++ b/graphics/mapper/3.0/vts/functional/Android.bp @@ -26,5 +26,5 @@ cc_test { "android.hardware.graphics.mapper@3.0", "android.hardware.graphics.mapper@3.0-vts", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp index 3542a6ee89..03abc891c0 100644 --- a/graphics/mapper/4.0/vts/functional/Android.bp +++ b/graphics/mapper/4.0/vts/functional/Android.bp @@ -36,6 +36,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/health/1.0/vts/functional/Android.bp b/health/1.0/vts/functional/Android.bp index be2d20685a..f4a04a7308 100644 --- a/health/1.0/vts/functional/Android.bp +++ b/health/1.0/vts/functional/Android.bp @@ -19,5 +19,5 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalHealthV1_0TargetTest.cpp"], static_libs: ["android.hardware.health@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/health/2.0/vts/functional/Android.bp b/health/2.0/vts/functional/Android.bp index 43571efaef..ab14ca75c3 100644 --- a/health/2.0/vts/functional/Android.bp +++ b/health/2.0/vts/functional/Android.bp @@ -23,5 +23,5 @@ cc_test { "android.hardware.health@1.0", "android.hardware.health@2.0", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/health/2.1/vts/functional/Android.bp b/health/2.1/vts/functional/Android.bp index 17472fa2fa..7894ca24a8 100644 --- a/health/2.1/vts/functional/Android.bp +++ b/health/2.1/vts/functional/Android.bp @@ -27,6 +27,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/health/storage/1.0/vts/functional/Android.bp b/health/storage/1.0/vts/functional/Android.bp index 4c703c571f..22010319a2 100644 --- a/health/storage/1.0/vts/functional/Android.bp +++ b/health/storage/1.0/vts/functional/Android.bp @@ -24,7 +24,7 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], test_config: "VtsHalHealthStorageV1_0TargetTest.config", } diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp index cecc814fdc..ef8beb4cdf 100644 --- a/identity/aidl/vts/Android.bp +++ b/identity/aidl/vts/Android.bp @@ -17,6 +17,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/input/classifier/1.0/vts/functional/Android.bp b/input/classifier/1.0/vts/functional/Android.bp index 4db1398778..4d6c9c367e 100644 --- a/input/classifier/1.0/vts/functional/Android.bp +++ b/input/classifier/1.0/vts/functional/Android.bp @@ -24,6 +24,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/ir/1.0/vts/functional/Android.bp b/ir/1.0/vts/functional/Android.bp index f9edebdb96..160129f8c5 100644 --- a/ir/1.0/vts/functional/Android.bp +++ b/ir/1.0/vts/functional/Android.bp @@ -21,5 +21,5 @@ cc_test { static_libs: [ "android.hardware.ir@1.0", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/keymaster/3.0/vts/functional/Android.bp b/keymaster/3.0/vts/functional/Android.bp index 36a6861a7d..35b9387132 100644 --- a/keymaster/3.0/vts/functional/Android.bp +++ b/keymaster/3.0/vts/functional/Android.bp @@ -29,5 +29,5 @@ cc_test { "libcrypto_static", "libsoftkeymasterdevice", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp index db500805dc..e706c689e6 100644 --- a/keymaster/4.0/vts/functional/Android.bp +++ b/keymaster/4.0/vts/functional/Android.bp @@ -30,7 +30,7 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/keymaster/4.1/vts/functional/Android.bp b/keymaster/4.1/vts/functional/Android.bp index c2d7fa3547..5ba05ea4ef 100644 --- a/keymaster/4.1/vts/functional/Android.bp +++ b/keymaster/4.1/vts/functional/Android.bp @@ -37,6 +37,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/light/2.0/vts/functional/Android.bp b/light/2.0/vts/functional/Android.bp index 2c0a08fab4..06590c3a15 100644 --- a/light/2.0/vts/functional/Android.bp +++ b/light/2.0/vts/functional/Android.bp @@ -19,6 +19,6 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalLightV2_0TargetTest.cpp"], static_libs: ["android.hardware.light@2.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/light/aidl/vts/functional/Android.bp b/light/aidl/vts/functional/Android.bp index 3dd8cf64ce..aa4719b739 100644 --- a/light/aidl/vts/functional/Android.bp +++ b/light/aidl/vts/functional/Android.bp @@ -30,6 +30,6 @@ cc_test { "android.hardware.light-cpp", ], test_suites: [ - "vts-core", + "vts", ], } diff --git a/memtrack/1.0/vts/functional/Android.bp b/memtrack/1.0/vts/functional/Android.bp index 9e5cf6dc37..445770ad9b 100644 --- a/memtrack/1.0/vts/functional/Android.bp +++ b/memtrack/1.0/vts/functional/Android.bp @@ -19,5 +19,5 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalMemtrackV1_0TargetTest.cpp"], static_libs: ["android.hardware.memtrack@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp index 03af671086..87e851930d 100644 --- a/neuralnetworks/1.0/vts/functional/Android.bp +++ b/neuralnetworks/1.0/vts/functional/Android.bp @@ -88,5 +88,5 @@ cc_test { header_libs: [ "libneuralnetworks_headers", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp index 9ba192518a..9afa0af35b 100644 --- a/neuralnetworks/1.1/vts/functional/Android.bp +++ b/neuralnetworks/1.1/vts/functional/Android.bp @@ -47,5 +47,5 @@ cc_test { header_libs: [ "libneuralnetworks_headers", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index 7c1faeef68..481eb80258 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -72,6 +72,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/nfc/1.0/vts/functional/Android.bp b/nfc/1.0/vts/functional/Android.bp index 40b82bbf98..40ba22ee2f 100644 --- a/nfc/1.0/vts/functional/Android.bp +++ b/nfc/1.0/vts/functional/Android.bp @@ -21,5 +21,5 @@ cc_test { static_libs: [ "android.hardware.nfc@1.0", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/nfc/1.1/vts/functional/Android.bp b/nfc/1.1/vts/functional/Android.bp index 8da0ce3a78..1c18418514 100644 --- a/nfc/1.1/vts/functional/Android.bp +++ b/nfc/1.1/vts/functional/Android.bp @@ -22,5 +22,5 @@ cc_test { "android.hardware.nfc@1.0", "android.hardware.nfc@1.1", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/nfc/1.2/vts/functional/Android.bp b/nfc/1.2/vts/functional/Android.bp index 7b50a36d74..83e7a8e58e 100644 --- a/nfc/1.2/vts/functional/Android.bp +++ b/nfc/1.2/vts/functional/Android.bp @@ -23,5 +23,5 @@ cc_test { "android.hardware.nfc@1.1", "android.hardware.nfc@1.2", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/oemlock/1.0/vts/functional/Android.bp b/oemlock/1.0/vts/functional/Android.bp index 90de347562..4dd92b53d6 100644 --- a/oemlock/1.0/vts/functional/Android.bp +++ b/oemlock/1.0/vts/functional/Android.bp @@ -19,5 +19,5 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalOemLockV1_0TargetTest.cpp"], static_libs: ["android.hardware.oemlock@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/power/1.0/vts/functional/Android.bp b/power/1.0/vts/functional/Android.bp index 5d5676d36b..27b945651c 100644 --- a/power/1.0/vts/functional/Android.bp +++ b/power/1.0/vts/functional/Android.bp @@ -19,5 +19,5 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalPowerV1_0TargetTest.cpp"], static_libs: ["android.hardware.power@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/power/1.1/vts/functional/Android.bp b/power/1.1/vts/functional/Android.bp index d9a32df9ab..2860fdb10a 100644 --- a/power/1.1/vts/functional/Android.bp +++ b/power/1.1/vts/functional/Android.bp @@ -22,5 +22,5 @@ cc_test { "android.hardware.power@1.0", "android.hardware.power@1.1", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/power/1.2/vts/functional/Android.bp b/power/1.2/vts/functional/Android.bp index 5385faa8a8..5d1b2a4973 100644 --- a/power/1.2/vts/functional/Android.bp +++ b/power/1.2/vts/functional/Android.bp @@ -23,5 +23,5 @@ cc_test { "android.hardware.power@1.1", "android.hardware.power@1.2", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/power/1.3/vts/functional/Android.bp b/power/1.3/vts/functional/Android.bp index 77e86197a0..d8e1c050ad 100644 --- a/power/1.3/vts/functional/Android.bp +++ b/power/1.3/vts/functional/Android.bp @@ -24,5 +24,5 @@ cc_test { "android.hardware.power@1.2", "android.hardware.power@1.3", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/power/aidl/vts/Android.bp b/power/aidl/vts/Android.bp index 7726fd8a73..28b08c7c4e 100644 --- a/power/aidl/vts/Android.bp +++ b/power/aidl/vts/Android.bp @@ -26,6 +26,6 @@ cc_test { "android.hardware.power-cpp", ], test_suites: [ - "vts-core", + "vts", ], } diff --git a/power/stats/1.0/vts/functional/Android.bp b/power/stats/1.0/vts/functional/Android.bp index ab47061461..d5f1da2d9d 100644 --- a/power/stats/1.0/vts/functional/Android.bp +++ b/power/stats/1.0/vts/functional/Android.bp @@ -33,5 +33,5 @@ cc_test { "libfmq", "libutils", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/radio/1.0/vts/functional/Android.bp b/radio/1.0/vts/functional/Android.bp index 2351d903fa..13fc5425ac 100644 --- a/radio/1.0/vts/functional/Android.bp +++ b/radio/1.0/vts/functional/Android.bp @@ -34,7 +34,7 @@ cc_test { "android.hardware.radio@1.0", ], test_config: "vts_hal_radio_target_test.xml", - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } cc_test { @@ -49,7 +49,7 @@ cc_test { "android.hardware.radio@1.0", ], test_config: "vts_hal_sap_target_test.xml", - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } cc_library_static { diff --git a/radio/1.1/vts/functional/Android.bp b/radio/1.1/vts/functional/Android.bp index 58aa67e0f9..e1278b926a 100644 --- a/radio/1.1/vts/functional/Android.bp +++ b/radio/1.1/vts/functional/Android.bp @@ -30,5 +30,5 @@ cc_test { header_libs: [ "radio.util.header@1.0", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/radio/1.2/vts/functional/Android.bp b/radio/1.2/vts/functional/Android.bp index f7189a8cbd..56f2d5fb49 100644 --- a/radio/1.2/vts/functional/Android.bp +++ b/radio/1.2/vts/functional/Android.bp @@ -34,5 +34,5 @@ cc_test { "android.hardware.radio.config@1.1", ], header_libs: ["radio.util.header@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/radio/1.3/vts/functional/Android.bp b/radio/1.3/vts/functional/Android.bp index 2301732331..e32258f5d3 100644 --- a/radio/1.3/vts/functional/Android.bp +++ b/radio/1.3/vts/functional/Android.bp @@ -32,5 +32,5 @@ cc_test { "android.hardware.radio@1.0", ], header_libs: ["radio.util.header@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/radio/1.4/vts/functional/Android.bp b/radio/1.4/vts/functional/Android.bp index 82844048b6..369b55b7a2 100644 --- a/radio/1.4/vts/functional/Android.bp +++ b/radio/1.4/vts/functional/Android.bp @@ -35,5 +35,5 @@ cc_test { "android.hardware.radio.config@1.1", ], header_libs: ["radio.util.header@1.0"], - test_suites: ["general-tests", "vts-core"] + test_suites: ["general-tests", "vts"] } diff --git a/radio/1.5/vts/functional/Android.bp b/radio/1.5/vts/functional/Android.bp index cd30f7dd39..cd54d274fd 100644 --- a/radio/1.5/vts/functional/Android.bp +++ b/radio/1.5/vts/functional/Android.bp @@ -36,5 +36,5 @@ cc_test { "android.hardware.radio.config@1.1", ], header_libs: ["radio.util.header@1.0"], - test_suites: ["general-tests", "vts-core"] + test_suites: ["general-tests", "vts"] } diff --git a/radio/config/1.0/vts/functional/Android.bp b/radio/config/1.0/vts/functional/Android.bp index 859b24bde9..330209eed0 100644 --- a/radio/config/1.0/vts/functional/Android.bp +++ b/radio/config/1.0/vts/functional/Android.bp @@ -29,5 +29,5 @@ cc_test { "android.hardware.radio.config@1.0", ], header_libs: ["radio.util.header@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/radio/config/1.1/vts/functional/Android.bp b/radio/config/1.1/vts/functional/Android.bp index 8cf7b629a5..f60331d1c3 100644 --- a/radio/config/1.1/vts/functional/Android.bp +++ b/radio/config/1.1/vts/functional/Android.bp @@ -29,5 +29,5 @@ cc_test { "android.hardware.radio.config@1.1", ], header_libs: ["radio.util.header@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/radio/config/1.2/vts/functional/Android.bp b/radio/config/1.2/vts/functional/Android.bp index 2c2073a214..fdc83b73fc 100644 --- a/radio/config/1.2/vts/functional/Android.bp +++ b/radio/config/1.2/vts/functional/Android.bp @@ -31,5 +31,5 @@ cc_test { "android.hardware.radio.config@1.2", ], header_libs: ["radio.util.header@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/rebootescrow/aidl/vts/functional/Android.bp b/rebootescrow/aidl/vts/functional/Android.bp index 5d51a53f06..2cc00685d6 100644 --- a/rebootescrow/aidl/vts/functional/Android.bp +++ b/rebootescrow/aidl/vts/functional/Android.bp @@ -28,7 +28,7 @@ cc_test { "android.hardware.rebootescrow-cpp", ], test_suites: [ - "vts-core", + "vts", ], require_root: true, } diff --git a/renderscript/1.0/vts/functional/Android.bp b/renderscript/1.0/vts/functional/Android.bp index e3716e01b1..327c09edb5 100644 --- a/renderscript/1.0/vts/functional/Android.bp +++ b/renderscript/1.0/vts/functional/Android.bp @@ -28,5 +28,5 @@ cc_test { "android.hardware.renderscript@1.0", "libnativewindow", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/secure_element/1.0/vts/functional/Android.bp b/secure_element/1.0/vts/functional/Android.bp index 6dbd027747..d428c6f771 100644 --- a/secure_element/1.0/vts/functional/Android.bp +++ b/secure_element/1.0/vts/functional/Android.bp @@ -21,5 +21,5 @@ cc_test { static_libs: [ "android.hardware.secure_element@1.0", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/secure_element/1.1/vts/functional/Android.bp b/secure_element/1.1/vts/functional/Android.bp index a2c39dc973..200aed829d 100644 --- a/secure_element/1.1/vts/functional/Android.bp +++ b/secure_element/1.1/vts/functional/Android.bp @@ -22,5 +22,5 @@ cc_test { "android.hardware.secure_element@1.0", "android.hardware.secure_element@1.1", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/secure_element/1.2/vts/functional/Android.bp b/secure_element/1.2/vts/functional/Android.bp index a1732108ab..9a7ca45b54 100644 --- a/secure_element/1.2/vts/functional/Android.bp +++ b/secure_element/1.2/vts/functional/Android.bp @@ -23,5 +23,5 @@ cc_test { "android.hardware.secure_element@1.1", "android.hardware.secure_element@1.2", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp index aaefccbe19..31424abb79 100644 --- a/sensors/1.0/vts/functional/Android.bp +++ b/sensors/1.0/vts/functional/Android.bp @@ -33,6 +33,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/sensors/2.0/vts/functional/Android.bp b/sensors/2.0/vts/functional/Android.bp index 08c59b6378..598ad15923 100644 --- a/sensors/2.0/vts/functional/Android.bp +++ b/sensors/2.0/vts/functional/Android.bp @@ -40,6 +40,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/sensors/2.1/vts/functional/Android.bp b/sensors/2.1/vts/functional/Android.bp index c4f5e9d2d7..3f01a3ec84 100644 --- a/sensors/2.1/vts/functional/Android.bp +++ b/sensors/2.1/vts/functional/Android.bp @@ -42,6 +42,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/soundtrigger/2.0/vts/functional/Android.bp b/soundtrigger/2.0/vts/functional/Android.bp index 13dcdec69e..86697bda3d 100644 --- a/soundtrigger/2.0/vts/functional/Android.bp +++ b/soundtrigger/2.0/vts/functional/Android.bp @@ -19,5 +19,5 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalSoundtriggerV2_0TargetTest.cpp"], static_libs: ["android.hardware.soundtrigger@2.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/soundtrigger/2.1/vts/functional/Android.bp b/soundtrigger/2.1/vts/functional/Android.bp index 7830fe2602..9de913b641 100644 --- a/soundtrigger/2.1/vts/functional/Android.bp +++ b/soundtrigger/2.1/vts/functional/Android.bp @@ -25,5 +25,5 @@ cc_test { "android.hardware.soundtrigger@2.1", "libhidlmemory" ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/soundtrigger/2.2/vts/functional/Android.bp b/soundtrigger/2.2/vts/functional/Android.bp index b5d241d263..b7967d966f 100644 --- a/soundtrigger/2.2/vts/functional/Android.bp +++ b/soundtrigger/2.2/vts/functional/Android.bp @@ -23,5 +23,5 @@ cc_test { "android.hardware.soundtrigger@2.1", "android.hardware.soundtrigger@2.2", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/soundtrigger/2.3/vts/functional/Android.bp b/soundtrigger/2.3/vts/functional/Android.bp index e3855fc372..2c1b9e594e 100644 --- a/soundtrigger/2.3/vts/functional/Android.bp +++ b/soundtrigger/2.3/vts/functional/Android.bp @@ -26,6 +26,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/tetheroffload/config/1.0/vts/functional/Android.bp b/tetheroffload/config/1.0/vts/functional/Android.bp index 7b472e3e79..ad5a1b1af4 100644 --- a/tetheroffload/config/1.0/vts/functional/Android.bp +++ b/tetheroffload/config/1.0/vts/functional/Android.bp @@ -17,5 +17,5 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalTetheroffloadConfigV1_0TargetTest.cpp"], static_libs: ["android.hardware.tetheroffload.config@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/tetheroffload/control/1.0/vts/functional/Android.bp b/tetheroffload/control/1.0/vts/functional/Android.bp index 4af59b66ed..c51dd8b08d 100644 --- a/tetheroffload/control/1.0/vts/functional/Android.bp +++ b/tetheroffload/control/1.0/vts/functional/Android.bp @@ -20,5 +20,5 @@ cc_test { "android.hardware.tetheroffload.config@1.0", "android.hardware.tetheroffload.control@1.0", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/thermal/1.0/vts/functional/Android.bp b/thermal/1.0/vts/functional/Android.bp index d183bd8a0e..5ccf07af17 100644 --- a/thermal/1.0/vts/functional/Android.bp +++ b/thermal/1.0/vts/functional/Android.bp @@ -19,6 +19,6 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalThermalV1_0TargetTest.cpp"], static_libs: ["android.hardware.thermal@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/thermal/1.1/vts/functional/Android.bp b/thermal/1.1/vts/functional/Android.bp index 2c43d79766..b869ece290 100644 --- a/thermal/1.1/vts/functional/Android.bp +++ b/thermal/1.1/vts/functional/Android.bp @@ -22,5 +22,5 @@ cc_test { "android.hardware.thermal@1.0", "android.hardware.thermal@1.1", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/thermal/2.0/vts/functional/Android.bp b/thermal/2.0/vts/functional/Android.bp index 09405763a2..026cb62577 100644 --- a/thermal/2.0/vts/functional/Android.bp +++ b/thermal/2.0/vts/functional/Android.bp @@ -22,6 +22,6 @@ cc_test { "android.hardware.thermal@1.0", "android.hardware.thermal@2.0", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/tv/input/1.0/vts/functional/Android.bp b/tv/input/1.0/vts/functional/Android.bp index 5d20bceeed..29d4e21de2 100644 --- a/tv/input/1.0/vts/functional/Android.bp +++ b/tv/input/1.0/vts/functional/Android.bp @@ -21,7 +21,7 @@ cc_test { static_libs: ["android.hardware.tv.input@1.0"], test_suites: [ "general-tests", - "vts-core", + "vts", ], require_root: true, } diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp index 3637708a6a..641e16a937 100644 --- a/tv/tuner/1.0/vts/functional/Android.bp +++ b/tv/tuner/1.0/vts/functional/Android.bp @@ -32,7 +32,7 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], require_root: true, diff --git a/usb/1.0/vts/functional/Android.bp b/usb/1.0/vts/functional/Android.bp index 1a3b56b99c..ae31bd2d30 100644 --- a/usb/1.0/vts/functional/Android.bp +++ b/usb/1.0/vts/functional/Android.bp @@ -19,5 +19,5 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalUsbV1_0TargetTest.cpp"], static_libs: ["android.hardware.usb@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/usb/1.1/vts/functional/Android.bp b/usb/1.1/vts/functional/Android.bp index 32c470b096..5bec94af66 100644 --- a/usb/1.1/vts/functional/Android.bp +++ b/usb/1.1/vts/functional/Android.bp @@ -22,6 +22,6 @@ cc_test { "android.hardware.usb@1.0", "android.hardware.usb@1.1", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/vibrator/1.0/vts/functional/Android.bp b/vibrator/1.0/vts/functional/Android.bp index 10ec2cbab6..4ec1aa8064 100644 --- a/vibrator/1.0/vts/functional/Android.bp +++ b/vibrator/1.0/vts/functional/Android.bp @@ -19,6 +19,6 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalVibratorV1_0TargetTest.cpp"], static_libs: ["android.hardware.vibrator@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/vibrator/1.1/vts/functional/Android.bp b/vibrator/1.1/vts/functional/Android.bp index 4cde350e79..b291e7ce50 100644 --- a/vibrator/1.1/vts/functional/Android.bp +++ b/vibrator/1.1/vts/functional/Android.bp @@ -22,6 +22,6 @@ cc_test { "android.hardware.vibrator@1.0", "android.hardware.vibrator@1.1", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/vibrator/1.2/vts/functional/Android.bp b/vibrator/1.2/vts/functional/Android.bp index e7052f2b6d..7bf69d06d3 100644 --- a/vibrator/1.2/vts/functional/Android.bp +++ b/vibrator/1.2/vts/functional/Android.bp @@ -23,6 +23,6 @@ cc_test { "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.2", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/vibrator/1.3/vts/functional/Android.bp b/vibrator/1.3/vts/functional/Android.bp index 038dc5ca59..5215ed04cf 100644 --- a/vibrator/1.3/vts/functional/Android.bp +++ b/vibrator/1.3/vts/functional/Android.bp @@ -24,6 +24,6 @@ cc_test { "android.hardware.vibrator@1.2", "android.hardware.vibrator@1.3", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/vibrator/aidl/vts/Android.bp b/vibrator/aidl/vts/Android.bp index d1e135e4a3..28cb4d9856 100644 --- a/vibrator/aidl/vts/Android.bp +++ b/vibrator/aidl/vts/Android.bp @@ -13,6 +13,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/vr/1.0/vts/functional/Android.bp b/vr/1.0/vts/functional/Android.bp index bd0336cc15..6bfa05cad7 100644 --- a/vr/1.0/vts/functional/Android.bp +++ b/vr/1.0/vts/functional/Android.bp @@ -19,5 +19,5 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalVrV1_0TargetTest.cpp"], static_libs: ["android.hardware.vr@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/weaver/1.0/vts/functional/Android.bp b/weaver/1.0/vts/functional/Android.bp index 3942deb166..b20f127647 100644 --- a/weaver/1.0/vts/functional/Android.bp +++ b/weaver/1.0/vts/functional/Android.bp @@ -19,5 +19,5 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalWeaverV1_0TargetTest.cpp"], static_libs: ["android.hardware.weaver@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp index 2242510933..793dd8cc7c 100644 --- a/wifi/1.0/vts/functional/Android.bp +++ b/wifi/1.0/vts/functional/Android.bp @@ -51,7 +51,7 @@ cc_test { "android.hardware.wifi@1.3", "libwifi-system-iface" ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } // These tests are split out so that they can be conditioned on presence of the @@ -68,7 +68,7 @@ cc_test { "android.hardware.wifi@1.0", "libwifi-system-iface" ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } // These tests are split out so that they can be conditioned on presence of @@ -85,5 +85,5 @@ cc_test { "android.hardware.wifi@1.0", "libwifi-system-iface" ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/wifi/1.1/vts/functional/Android.bp b/wifi/1.1/vts/functional/Android.bp index d34ae222d9..eb68bc0ddc 100644 --- a/wifi/1.1/vts/functional/Android.bp +++ b/wifi/1.1/vts/functional/Android.bp @@ -27,5 +27,5 @@ cc_test { "android.hardware.wifi@1.3", "libwifi-system-iface" ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/wifi/1.2/vts/functional/Android.bp b/wifi/1.2/vts/functional/Android.bp index d3de5cfc67..90bcac1d33 100644 --- a/wifi/1.2/vts/functional/Android.bp +++ b/wifi/1.2/vts/functional/Android.bp @@ -30,7 +30,7 @@ cc_test { "libwifi-system-iface" ], disable_framework: true, - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } cc_test { @@ -47,5 +47,5 @@ cc_test { "libwifi-system-iface" ], disable_framework: true, - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/wifi/1.3/vts/functional/Android.bp b/wifi/1.3/vts/functional/Android.bp index 457de2973a..3568330845 100644 --- a/wifi/1.3/vts/functional/Android.bp +++ b/wifi/1.3/vts/functional/Android.bp @@ -30,5 +30,5 @@ cc_test { "libwifi-system-iface" ], disable_framework: true, - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp index 7e74cbd5de..3824c3aecf 100644 --- a/wifi/1.4/vts/functional/Android.bp +++ b/wifi/1.4/vts/functional/Android.bp @@ -35,6 +35,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/wifi/hostapd/1.0/vts/functional/Android.bp b/wifi/hostapd/1.0/vts/functional/Android.bp index e966d7e817..2a35f15190 100644 --- a/wifi/hostapd/1.0/vts/functional/Android.bp +++ b/wifi/hostapd/1.0/vts/functional/Android.bp @@ -48,5 +48,5 @@ cc_test { "libwifi-system", "libwifi-system-iface", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/wifi/hostapd/1.1/vts/functional/Android.bp b/wifi/hostapd/1.1/vts/functional/Android.bp index 8670f2fe97..291eceb80c 100644 --- a/wifi/hostapd/1.1/vts/functional/Android.bp +++ b/wifi/hostapd/1.1/vts/functional/Android.bp @@ -30,6 +30,6 @@ cc_test { "libwifi-system", "libwifi-system-iface", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/wifi/hostapd/1.2/vts/functional/Android.bp b/wifi/hostapd/1.2/vts/functional/Android.bp index 4f4a741bf3..cec17823fd 100644 --- a/wifi/hostapd/1.2/vts/functional/Android.bp +++ b/wifi/hostapd/1.2/vts/functional/Android.bp @@ -31,6 +31,6 @@ cc_test { "libwifi-system", "libwifi-system-iface", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/wifi/offload/1.0/vts/functional/Android.bp b/wifi/offload/1.0/vts/functional/Android.bp index 965c946764..abfefa8214 100644 --- a/wifi/offload/1.0/vts/functional/Android.bp +++ b/wifi/offload/1.0/vts/functional/Android.bp @@ -19,5 +19,5 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalWifiOffloadV1_0TargetTest.cpp"], static_libs: ["android.hardware.wifi.offload@1.0"], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/wifi/supplicant/1.0/vts/functional/Android.bp b/wifi/supplicant/1.0/vts/functional/Android.bp index a05cc6bfa8..6f282bb9d7 100644 --- a/wifi/supplicant/1.0/vts/functional/Android.bp +++ b/wifi/supplicant/1.0/vts/functional/Android.bp @@ -54,7 +54,7 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } @@ -77,6 +77,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/wifi/supplicant/1.1/vts/functional/Android.bp b/wifi/supplicant/1.1/vts/functional/Android.bp index 90a3e872fb..44b020e021 100644 --- a/wifi/supplicant/1.1/vts/functional/Android.bp +++ b/wifi/supplicant/1.1/vts/functional/Android.bp @@ -55,6 +55,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/wifi/supplicant/1.2/vts/functional/Android.bp b/wifi/supplicant/1.2/vts/functional/Android.bp index 80f3658edd..c23585aaef 100644 --- a/wifi/supplicant/1.2/vts/functional/Android.bp +++ b/wifi/supplicant/1.2/vts/functional/Android.bp @@ -59,7 +59,7 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } @@ -85,6 +85,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } diff --git a/wifi/supplicant/1.3/vts/functional/Android.bp b/wifi/supplicant/1.3/vts/functional/Android.bp index 00a0bf7ee1..8eebed0586 100644 --- a/wifi/supplicant/1.3/vts/functional/Android.bp +++ b/wifi/supplicant/1.3/vts/functional/Android.bp @@ -62,6 +62,6 @@ cc_test { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } From 49af02ff9d2653dd5b0bfa277612d7da5ffc342b Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Wed, 8 Apr 2020 00:03:59 -0700 Subject: [PATCH 0814/1022] Modify the name of the SV interface to match VTS Modify the name of the Surround View interface to match the one in VTS and the one in the default implementation. Bug: 150412555 Test: m -j Change-Id: I36c2a9187ae0973444ce441bda09c31d9b73809d --- compatibility_matrices/compatibility_matrix.5.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compatibility_matrices/compatibility_matrix.5.xml b/compatibility_matrices/compatibility_matrix.5.xml index 38f589daf0..a6d51f1d81 100644 --- a/compatibility_matrices/compatibility_matrix.5.xml +++ b/compatibility_matrices/compatibility_matrix.5.xml @@ -72,7 +72,7 @@ android.hardware.automotive.sv 1.0 - ISurroundView + ISurroundViewService default From 7e2674589f6fdaaae8d9419a3c5dd671b4fc7f74 Mon Sep 17 00:00:00 2001 From: Jeongik Cha Date: Wed, 8 Apr 2020 16:27:47 +0900 Subject: [PATCH 0815/1022] Freeze vintf aidl interfaces AIDL interfaces which are vintf-stable have to be frozen in release. But these interfaces have been never frozen, so freeze them. - android.hardware.common - android.hardware.automotive.occupant_awareness - android.hardware.rebootescrow - android.hardware.graphics.common Bug: 153510296 Bug: 153510400 Bug: 153510960 Bug: 153511702 Test: m Change-Id: I56e53209eaf00518ec83f2a322e89d6d944eb0ac --- automotive/occupant_awareness/aidl/Android.bp | 1 + .../1/.hash | 1 + .../occupant_awareness/ConfidenceLevel.aidl | 25 ++++++ .../DriverMonitoringDetection.aidl | 24 ++++++ .../occupant_awareness/GazeDetection.aidl | 28 +++++++ .../IOccupantAwareness.aidl | 31 +++++++ .../IOccupantAwarenessClientCallback.aidl | 23 ++++++ .../OccupantAwarenessStatus.aidl | 25 ++++++ .../occupant_awareness/OccupantDetection.aidl | 25 ++++++ .../OccupantDetections.aidl | 23 ++++++ .../occupant_awareness/PresenceDetection.aidl | 23 ++++++ .../automotive/occupant_awareness/Role.aidl | 35 ++++++++ .../occupant_awareness/VehicleRegion.aidl | 31 +++++++ common/aidl/Android.bp | 1 + .../aidl_api/android.hardware.common/1/.hash | 1 + .../android/hardware/common/NativeHandle.aidl | 23 ++++++ graphics/common/aidl/Android.bp | 1 + .../android.hardware.graphics.common/1/.hash | 1 + .../hardware/graphics/common/BlendMode.aidl | 25 ++++++ .../hardware/graphics/common/BufferUsage.aidl | 47 +++++++++++ .../graphics/common/ChromaSiting.aidl | 25 ++++++ .../hardware/graphics/common/Compression.aidl | 23 ++++++ .../hardware/graphics/common/Cta861_3.aidl | 23 ++++++ .../hardware/graphics/common/Dataspace.aidl | 81 +++++++++++++++++++ .../graphics/common/ExtendableType.aidl | 23 ++++++ .../graphics/common/HardwareBuffer.aidl | 23 ++++++ .../common/HardwareBufferDescription.aidl | 27 +++++++ .../hardware/graphics/common/Interlaced.aidl | 24 ++++++ .../hardware/graphics/common/PixelFormat.aidl | 50 ++++++++++++ .../hardware/graphics/common/PlaneLayout.aidl | 30 +++++++ .../graphics/common/PlaneLayoutComponent.aidl | 24 ++++++ .../common/PlaneLayoutComponentType.aidl | 29 +++++++ .../hardware/graphics/common/Rect.aidl | 25 ++++++ .../hardware/graphics/common/Smpte2086.aidl | 27 +++++++ .../graphics/common/StandardMetadataType.aidl | 43 ++++++++++ .../hardware/graphics/common/XyColor.aidl | 23 ++++++ rebootescrow/aidl/Android.bp | 1 + .../android.hardware.rebootescrow/1/.hash | 1 + .../hardware/rebootescrow/IRebootEscrow.aidl | 23 ++++++ 39 files changed, 919 insertions(+) create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/.hash create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/GazeDetection.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/Role.aidl create mode 100644 automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl create mode 100644 common/aidl/aidl_api/android.hardware.common/1/.hash create mode 100644 common/aidl/aidl_api/android.hardware.common/1/android/hardware/common/NativeHandle.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/.hash create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/BlendMode.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/BufferUsage.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/ChromaSiting.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Compression.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Cta861_3.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Dataspace.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/ExtendableType.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/HardwareBuffer.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/HardwareBufferDescription.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Interlaced.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PixelFormat.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayout.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayoutComponent.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayoutComponentType.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Rect.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Smpte2086.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/StandardMetadataType.aidl create mode 100644 graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/XyColor.aidl create mode 100644 rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/1/.hash create mode 100644 rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/1/android/hardware/rebootescrow/IRebootEscrow.aidl diff --git a/automotive/occupant_awareness/aidl/Android.bp b/automotive/occupant_awareness/aidl/Android.bp index face235a42..4127f333b3 100644 --- a/automotive/occupant_awareness/aidl/Android.bp +++ b/automotive/occupant_awareness/aidl/Android.bp @@ -15,4 +15,5 @@ aidl_interface { }, }, }, + versions: ["1"], } diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/.hash b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/.hash new file mode 100644 index 0000000000..6786231b86 --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/.hash @@ -0,0 +1 @@ +3614b1c47ed7be85c1e77554e7f04966cf35b465 diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl new file mode 100644 index 0000000000..6e40d79cab --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@Backing(type="byte") @VintfStability +enum ConfidenceLevel { + NONE = 0, + LOW = 1, + HIGH = 2, + MAX = 3, +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl new file mode 100644 index 0000000000..51d2149aa3 --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@VintfStability +parcelable DriverMonitoringDetection { + android.hardware.automotive.occupant_awareness.ConfidenceLevel confidenceScore; + boolean isLookingOnRoad; + long gazeDurationMillis; +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/GazeDetection.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/GazeDetection.aidl new file mode 100644 index 0000000000..5ce14df9b8 --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/GazeDetection.aidl @@ -0,0 +1,28 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@VintfStability +parcelable GazeDetection { + android.hardware.automotive.occupant_awareness.ConfidenceLevel gazeConfidence; + double[] headPosition; + double[] headAngleUnitVector; + double[] gazeAngleUnitVector; + android.hardware.automotive.occupant_awareness.VehicleRegion gazeTarget; + String customGazeTarget; + long timeOnTargetMillis; +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl new file mode 100644 index 0000000000..7faff00841 --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl @@ -0,0 +1,31 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@VintfStability +interface IOccupantAwareness { + android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus startDetection(); + android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus stopDetection(); + int getCapabilityForRole(in android.hardware.automotive.occupant_awareness.Role occupantRole); + android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus getState(in android.hardware.automotive.occupant_awareness.Role occupantRole, in int detectionCapability); + void setCallback(in android.hardware.automotive.occupant_awareness.IOccupantAwarenessClientCallback callback); + void getLatestDetection(out android.hardware.automotive.occupant_awareness.OccupantDetections detections); + const int CAP_NONE = 0; + const int CAP_PRESENCE_DETECTION = 1; + const int CAP_GAZE_DETECTION = 2; + const int CAP_DRIVER_MONITORING_DETECTION = 4; +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl new file mode 100644 index 0000000000..31b8220d5f --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@VintfStability +interface IOccupantAwarenessClientCallback { + oneway void onSystemStatusChanged(in int detectionFlags, in android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus status); + oneway void onDetectionEvent(in android.hardware.automotive.occupant_awareness.OccupantDetections detections); +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl new file mode 100644 index 0000000000..26371c9573 --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@Backing(type="byte") @VintfStability +enum OccupantAwarenessStatus { + READY = 0, + NOT_SUPPORTED = 1, + NOT_INITIALIZED = 2, + FAILURE = 3, +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl new file mode 100644 index 0000000000..42b109550e --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@VintfStability +parcelable OccupantDetection { + android.hardware.automotive.occupant_awareness.Role role; + android.hardware.automotive.occupant_awareness.PresenceDetection[] presenceData; + android.hardware.automotive.occupant_awareness.GazeDetection[] gazeData; + android.hardware.automotive.occupant_awareness.DriverMonitoringDetection[] attentionData; +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl new file mode 100644 index 0000000000..9bcad6b4fc --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@VintfStability +parcelable OccupantDetections { + long timeStampMillis; + android.hardware.automotive.occupant_awareness.OccupantDetection[] detections; +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl new file mode 100644 index 0000000000..dd6c5c8950 --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@VintfStability +parcelable PresenceDetection { + boolean isOccupantDetected; + long detectionDurationMillis; +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/Role.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/Role.aidl new file mode 100644 index 0000000000..7b2b9077e0 --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/Role.aidl @@ -0,0 +1,35 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@Backing(type="int") @VintfStability +enum Role { + INVALID = 0, + UNKNOWN = 1, + FRONT_PASSENGER = 2, + DRIVER = 4, + ROW_2_PASSENGER_LEFT = 8, + ROW_2_PASSENGER_CENTER = 16, + ROW_2_PASSENGER_RIGHT = 32, + ROW_3_PASSENGER_LEFT = 64, + ROW_3_PASSENGER_CENTER = 128, + ROW_3_PASSENGER_RIGHT = 256, + FRONT_OCCUPANTS = 6, + ROW_2_OCCUPANTS = 56, + ROW_3_OCCUPANTS = 448, + ALL_OCCUPANTS = 511, +} diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl new file mode 100644 index 0000000000..f96d950bf1 --- /dev/null +++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl @@ -0,0 +1,31 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.occupant_awareness; +@Backing(type="int") @VintfStability +enum VehicleRegion { + UNKNOWN = 0, + INSTRUMENT_CLUSTER = 1, + REAR_VIEW_MIRROR = 2, + LEFT_SIDE_MIRROR = 3, + RIGHT_SIDE_MIRROR = 4, + FORWARD_ROADWAY = 5, + LEFT_ROADWAY = 6, + RIGHT_ROADWAY = 7, + HEAD_UNIT_DISPLAY = 8, + CUSTOM_TARGET = 200, +} diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp index f55e799d0d..0731230412 100644 --- a/common/aidl/Android.bp +++ b/common/aidl/Android.bp @@ -18,4 +18,5 @@ aidl_interface { enabled: false, }, }, + versions: ["1"], } diff --git a/common/aidl/aidl_api/android.hardware.common/1/.hash b/common/aidl/aidl_api/android.hardware.common/1/.hash new file mode 100644 index 0000000000..ad5102ae35 --- /dev/null +++ b/common/aidl/aidl_api/android.hardware.common/1/.hash @@ -0,0 +1 @@ +59e782d6ed4c2aed3744d37fb751ee23797835dd diff --git a/common/aidl/aidl_api/android.hardware.common/1/android/hardware/common/NativeHandle.aidl b/common/aidl/aidl_api/android.hardware.common/1/android/hardware/common/NativeHandle.aidl new file mode 100644 index 0000000000..f37b7d506f --- /dev/null +++ b/common/aidl/aidl_api/android.hardware.common/1/android/hardware/common/NativeHandle.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.common; +@VintfStability +parcelable NativeHandle { + ParcelFileDescriptor[] fds; + int[] ints; +} diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp index 601cabc2e5..c089a76b4e 100644 --- a/graphics/common/aidl/Android.bp +++ b/graphics/common/aidl/Android.bp @@ -21,4 +21,5 @@ aidl_interface { enabled: false, }, }, + versions: ["1"], } diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/.hash b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/.hash new file mode 100644 index 0000000000..66b5d134c5 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/.hash @@ -0,0 +1 @@ +f5bdf5724a941dc7e5e7d0ebe9dfe028f7bcc25f diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/BlendMode.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/BlendMode.aidl new file mode 100644 index 0000000000..deafdfad90 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/BlendMode.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="int") @VintfStability +enum BlendMode { + INVALID = 0, + NONE = 1, + PREMULTIPLIED = 2, + COVERAGE = 3, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/BufferUsage.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/BufferUsage.aidl new file mode 100644 index 0000000000..58eefc4e2c --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/BufferUsage.aidl @@ -0,0 +1,47 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="long") @VintfStability +enum BufferUsage { + CPU_READ_MASK = 15, + CPU_READ_NEVER = 0, + CPU_READ_RARELY = 2, + CPU_READ_OFTEN = 3, + CPU_WRITE_MASK = 240, + CPU_WRITE_NEVER = 0, + CPU_WRITE_RARELY = 32, + CPU_WRITE_OFTEN = 48, + GPU_TEXTURE = 256, + GPU_RENDER_TARGET = 512, + COMPOSER_OVERLAY = 2048, + COMPOSER_CLIENT_TARGET = 4096, + PROTECTED = 16384, + COMPOSER_CURSOR = 32768, + VIDEO_ENCODER = 65536, + CAMERA_OUTPUT = 131072, + CAMERA_INPUT = 262144, + RENDERSCRIPT = 1048576, + VIDEO_DECODER = 4194304, + SENSOR_DIRECT_DATA = 8388608, + GPU_CUBE_MAP = 33554432, + GPU_MIPMAP_COMPLETE = 67108864, + HW_IMAGE_ENCODER = 134217728, + GPU_DATA_BUFFER = 16777216, + VENDOR_MASK = -268435456, + VENDOR_MASK_HI = -281474976710656, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/ChromaSiting.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/ChromaSiting.aidl new file mode 100644 index 0000000000..7ca4dfa531 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/ChromaSiting.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="long") @VintfStability +enum ChromaSiting { + NONE = 0, + UNKNOWN = 1, + SITED_INTERSTITIAL = 2, + COSITED_HORIZONTAL = 3, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Compression.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Compression.aidl new file mode 100644 index 0000000000..06e40a0852 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Compression.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="long") @VintfStability +enum Compression { + NONE = 0, + DISPLAY_STREAM_COMPRESSION = 1, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Cta861_3.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Cta861_3.aidl new file mode 100644 index 0000000000..d4af501904 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Cta861_3.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable Cta861_3 { + float maxContentLightLevel; + float maxFrameAverageLightLevel; +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Dataspace.aidl new file mode 100644 index 0000000000..43d7f84d2d --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Dataspace.aidl @@ -0,0 +1,81 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="int") @VintfStability +enum Dataspace { + UNKNOWN = 0, + ARBITRARY = 1, + STANDARD_SHIFT = 16, + STANDARD_MASK = 4128768, + STANDARD_UNSPECIFIED = 0, + STANDARD_BT709 = 65536, + STANDARD_BT601_625 = 131072, + STANDARD_BT601_625_UNADJUSTED = 196608, + STANDARD_BT601_525 = 262144, + STANDARD_BT601_525_UNADJUSTED = 327680, + STANDARD_BT2020 = 393216, + STANDARD_BT2020_CONSTANT_LUMINANCE = 458752, + STANDARD_BT470M = 524288, + STANDARD_FILM = 589824, + STANDARD_DCI_P3 = 655360, + STANDARD_ADOBE_RGB = 720896, + TRANSFER_SHIFT = 22, + TRANSFER_MASK = 130023424, + TRANSFER_UNSPECIFIED = 0, + TRANSFER_LINEAR = 4194304, + TRANSFER_SRGB = 8388608, + TRANSFER_SMPTE_170M = 12582912, + TRANSFER_GAMMA2_2 = 16777216, + TRANSFER_GAMMA2_6 = 20971520, + TRANSFER_GAMMA2_8 = 25165824, + TRANSFER_ST2084 = 29360128, + TRANSFER_HLG = 33554432, + RANGE_SHIFT = 27, + RANGE_MASK = 939524096, + RANGE_UNSPECIFIED = 0, + RANGE_FULL = 134217728, + RANGE_LIMITED = 268435456, + RANGE_EXTENDED = 402653184, + SRGB_LINEAR = 138477568, + SCRGB_LINEAR = 406913024, + SRGB = 142671872, + SCRGB = 411107328, + JFIF = 146931712, + BT601_625 = 281149440, + BT601_525 = 281280512, + BT709 = 281083904, + DCI_P3_LINEAR = 139067392, + DCI_P3 = 155844608, + DISPLAY_P3_LINEAR = 139067392, + DISPLAY_P3 = 143261696, + ADOBE_RGB = 151715840, + BT2020_LINEAR = 138805248, + BT2020 = 147193856, + BT2020_PQ = 163971072, + DEPTH = 4096, + SENSOR = 4097, + BT2020_ITU = 281411584, + BT2020_ITU_PQ = 298188800, + BT2020_ITU_HLG = 302383104, + BT2020_HLG = 168165376, + DISPLAY_BT2020 = 142999552, + DYNAMIC_DEPTH = 4098, + JPEG_APP_SEGMENTS = 4099, + HEIF = 4100, + BT709_FULL_RANGE = 146866176, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/ExtendableType.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/ExtendableType.aidl new file mode 100644 index 0000000000..6fcb794efd --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/ExtendableType.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable ExtendableType { + @utf8InCpp String name; + long value = 0; +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/HardwareBuffer.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/HardwareBuffer.aidl new file mode 100644 index 0000000000..72222e118d --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/HardwareBuffer.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable HardwareBuffer { + android.hardware.graphics.common.HardwareBufferDescription description; + android.hardware.common.NativeHandle handle; +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/HardwareBufferDescription.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/HardwareBufferDescription.aidl new file mode 100644 index 0000000000..8b1216948b --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/HardwareBufferDescription.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable HardwareBufferDescription { + int width; + int height; + int layers; + android.hardware.graphics.common.PixelFormat format; + android.hardware.graphics.common.BufferUsage usage; + int stride; +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Interlaced.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Interlaced.aidl new file mode 100644 index 0000000000..26674c9b1d --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Interlaced.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="long") @VintfStability +enum Interlaced { + NONE = 0, + TOP_BOTTOM = 1, + RIGHT_LEFT = 2, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PixelFormat.aidl new file mode 100644 index 0000000000..e5f04700ed --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PixelFormat.aidl @@ -0,0 +1,50 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="int") @VintfStability +enum PixelFormat { + UNSPECIFIED = 0, + RGBA_8888 = 1, + RGBX_8888 = 2, + RGB_888 = 3, + RGB_565 = 4, + BGRA_8888 = 5, + YCBCR_422_SP = 16, + YCRCB_420_SP = 17, + YCBCR_422_I = 20, + RGBA_FP16 = 22, + RAW16 = 32, + BLOB = 33, + IMPLEMENTATION_DEFINED = 34, + YCBCR_420_888 = 35, + RAW_OPAQUE = 36, + RAW10 = 37, + RAW12 = 38, + RGBA_1010102 = 43, + Y8 = 538982489, + Y16 = 540422489, + YV12 = 842094169, + DEPTH_16 = 48, + DEPTH_24 = 49, + DEPTH_24_STENCIL_8 = 50, + DEPTH_32F = 51, + DEPTH_32F_STENCIL_8 = 52, + STENCIL_8 = 53, + YCBCR_P010 = 54, + HSV_888 = 55, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayout.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayout.aidl new file mode 100644 index 0000000000..8bca42feb1 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayout.aidl @@ -0,0 +1,30 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable PlaneLayout { + android.hardware.graphics.common.PlaneLayoutComponent[] components; + long offsetInBytes; + long sampleIncrementInBits; + long strideInBytes; + long widthInSamples; + long heightInSamples; + long totalSizeInBytes; + long horizontalSubsampling; + long verticalSubsampling; +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayoutComponent.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayoutComponent.aidl new file mode 100644 index 0000000000..f5a649cac9 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayoutComponent.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable PlaneLayoutComponent { + android.hardware.graphics.common.ExtendableType type; + long offsetInBits; + long sizeInBits; +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayoutComponentType.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayoutComponentType.aidl new file mode 100644 index 0000000000..7ff8d76520 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayoutComponentType.aidl @@ -0,0 +1,29 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="long") @VintfStability +enum PlaneLayoutComponentType { + Y = 1, + CB = 2, + CR = 4, + R = 1024, + G = 2048, + B = 4096, + RAW = 1048576, + A = 1073741824, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Rect.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Rect.aidl new file mode 100644 index 0000000000..e0ba69bcd0 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Rect.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable Rect { + int left; + int top; + int right; + int bottom; +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Smpte2086.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Smpte2086.aidl new file mode 100644 index 0000000000..5da36f68c0 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Smpte2086.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable Smpte2086 { + android.hardware.graphics.common.XyColor primaryRed; + android.hardware.graphics.common.XyColor primaryGreen; + android.hardware.graphics.common.XyColor primaryBlue; + android.hardware.graphics.common.XyColor whitePoint; + float maxLuminance; + float minLuminance; +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/StandardMetadataType.aidl new file mode 100644 index 0000000000..34b53a2bba --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/StandardMetadataType.aidl @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@Backing(type="long") @VintfStability +enum StandardMetadataType { + INVALID = 0, + BUFFER_ID = 1, + NAME = 2, + WIDTH = 3, + HEIGHT = 4, + LAYER_COUNT = 5, + PIXEL_FORMAT_REQUESTED = 6, + PIXEL_FORMAT_FOURCC = 7, + PIXEL_FORMAT_MODIFIER = 8, + USAGE = 9, + ALLOCATION_SIZE = 10, + PROTECTED_CONTENT = 11, + COMPRESSION = 12, + INTERLACED = 13, + CHROMA_SITING = 14, + PLANE_LAYOUTS = 15, + CROP = 16, + DATASPACE = 17, + BLEND_MODE = 18, + SMPTE2086 = 19, + CTA861_3 = 20, + SMPTE2094_40 = 21, +} diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/XyColor.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/XyColor.aidl new file mode 100644 index 0000000000..d96d0ac130 --- /dev/null +++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/XyColor.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.common; +@VintfStability +parcelable XyColor { + float x; + float y; +} diff --git a/rebootescrow/aidl/Android.bp b/rebootescrow/aidl/Android.bp index 0742939621..75faa1a65b 100644 --- a/rebootescrow/aidl/Android.bp +++ b/rebootescrow/aidl/Android.bp @@ -15,4 +15,5 @@ aidl_interface { }, }, }, + versions: ["1"], } diff --git a/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/1/.hash b/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/1/.hash new file mode 100644 index 0000000000..dcee3cc2c5 --- /dev/null +++ b/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/1/.hash @@ -0,0 +1 @@ +ba450432e0dab8ee7bbc30013819ea8aef12054b diff --git a/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/1/android/hardware/rebootescrow/IRebootEscrow.aidl b/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/1/android/hardware/rebootescrow/IRebootEscrow.aidl new file mode 100644 index 0000000000..ea669a30cc --- /dev/null +++ b/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/1/android/hardware/rebootescrow/IRebootEscrow.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.rebootescrow; +@VintfStability +interface IRebootEscrow { + void storeKey(in byte[] kek); + byte[] retrieveKey(); +} From ecb16248c9b55983d301dff0fd159e8cd059c8dc Mon Sep 17 00:00:00 2001 From: Daniel Norman Date: Fri, 28 Feb 2020 15:43:32 -0800 Subject: [PATCH 0816/1022] Adds IWifi 1.3 and 1.4 as interfaces provided by vendor.wifi_hal_legacy. Bug: 150474819 Bug: 152173671 Test: vts_ibase_test Change-Id: Ie5462d41177ec6dd56e6de266157e7d4ac28b388 Merged-In: Ie5462d41177ec6dd56e6de266157e7d4ac28b388 (cherry picked from commit f58ff069ee8866fa7b3e931fcbd80cb1bb4f835c) Change-Id: Ie5462d41177ec6dd56e6de266157e7d4ac28b388 --- wifi/1.4/default/android.hardware.wifi@1.0-service.rc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service.rc b/wifi/1.4/default/android.hardware.wifi@1.0-service.rc index 2317bac546..64a51b0ae8 100644 --- a/wifi/1.4/default/android.hardware.wifi@1.0-service.rc +++ b/wifi/1.4/default/android.hardware.wifi@1.0-service.rc @@ -2,6 +2,8 @@ service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service interface android.hardware.wifi@1.0::IWifi default interface android.hardware.wifi@1.1::IWifi default interface android.hardware.wifi@1.2::IWifi default + interface android.hardware.wifi@1.3::IWifi default + interface android.hardware.wifi@1.4::IWifi default class hal capabilities NET_ADMIN NET_RAW SYS_MODULE user wifi From fc614a63faa49cdd5b00537ce2c78f25c0c51452 Mon Sep 17 00:00:00 2001 From: Ivan Chiang Date: Thu, 9 Apr 2020 06:07:33 +0000 Subject: [PATCH 0817/1022] Revert "Modify the name of the SV interface to match VTS" Revert submission 10975707-revert-10941635-revert-10611042-surround-view-service-IWFFCKAOZD-LNGXTQTNXI Reason for revert: bb in git_master-without-vendor aosp_x86-eng Reverted Changes: I36c2a9187:Modify the name of the SV interface to match VTS I2732f1b25:Fix the build failure for aosp_x86-eng I0e737d7fb:Revert^2 "Setup Surround View for Osprey" I27def392d:Revert^2 "Selinux policy for SV service and app." I20a2ecfcc:Revert^2 "Surround View Sample App" Ifb91b6eeb:Revert^2 "Surround View Service implementation" Change-Id: I24a09d5e0a69224e30f22595bb99b8e1e23cdafe --- compatibility_matrices/compatibility_matrix.5.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compatibility_matrices/compatibility_matrix.5.xml b/compatibility_matrices/compatibility_matrix.5.xml index a6d51f1d81..38f589daf0 100644 --- a/compatibility_matrices/compatibility_matrix.5.xml +++ b/compatibility_matrices/compatibility_matrix.5.xml @@ -72,7 +72,7 @@ android.hardware.automotive.sv 1.0 - ISurroundViewService + ISurroundView default From 8fe0c2e0ecb12839904d802ca1cb844b86bf354c Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 9 Mar 2020 12:05:29 -0700 Subject: [PATCH 0818/1022] vibrator ext: use package name as module name For consistency. Bug: 153501107 Test: N/A Change-Id: If32e8539fd8fffd5e27f0437bff480089e38f0da Merged-In: If32e8539fd8fffd5e27f0437bff480089e38f0da --- tests/extension/vibrator/aidl/Android.bp | 2 +- tests/extension/vibrator/aidl/client/Android.bp | 6 +++--- tests/extension/vibrator/aidl/default/Android.bp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/extension/vibrator/aidl/Android.bp b/tests/extension/vibrator/aidl/Android.bp index 42e0a9200b..b1cda0c9c1 100644 --- a/tests/extension/vibrator/aidl/Android.bp +++ b/tests/extension/vibrator/aidl/Android.bp @@ -1,7 +1,7 @@ aidl_interface { // This is an example test interface showing how to add functionality // with setExtension/getExtension - name: "test-android.hardware.vibrator-ext", + name: "android.hardware.tests.extension.vibrator", vendor_available: true, srcs: [ // Using android.hardware as the package because this is in diff --git a/tests/extension/vibrator/aidl/client/Android.bp b/tests/extension/vibrator/aidl/client/Android.bp index c707dbe458..b0d82382fa 100644 --- a/tests/extension/vibrator/aidl/client/Android.bp +++ b/tests/extension/vibrator/aidl/client/Android.bp @@ -3,7 +3,7 @@ // server for example. cc_test { - name: "test-android.hardware.vibrator-ext-client", + name: "android.hardware.tests.extension.vibrator-client", srcs: [ // system code has the option to use the unstable C++ libbinder API // or the NDK one. For maximum code portability, using the ndk client @@ -15,10 +15,10 @@ cc_test { "libbinder", "libutils", "android.hardware.vibrator-cpp", - "test-android.hardware.vibrator-ext-cpp", + "android.hardware.tests.extension.vibrator-cpp", "libbinder_ndk", "android.hardware.vibrator-ndk_platform", - "test-android.hardware.vibrator-ext-ndk_platform", + "android.hardware.tests.extension.vibrator-ndk_platform", ], } diff --git a/tests/extension/vibrator/aidl/default/Android.bp b/tests/extension/vibrator/aidl/default/Android.bp index 7c8fe1fc96..ed40d259ab 100644 --- a/tests/extension/vibrator/aidl/default/Android.bp +++ b/tests/extension/vibrator/aidl/default/Android.bp @@ -20,6 +20,6 @@ cc_binary { "libbase", "libbinder_ndk", "android.hardware.vibrator-ndk_platform", - "test-android.hardware.vibrator-ext-ndk_platform", + "android.hardware.tests.extension.vibrator-ndk_platform", ], } From d18fbcba304d0da9d773b2c41c94682899513311 Mon Sep 17 00:00:00 2001 From: Jeongik Cha Date: Wed, 8 Apr 2020 22:32:00 +0900 Subject: [PATCH 0819/1022] android.hardware.tests.extension.vibrator-update-api Dumping android.hardware.tests.extension.vibrator was ommited because of difference of module name across branch. Bug: 153501107 Bug: 152655547 Test: m Change-Id: Ia272ffa77add9ef0b02ee0a23fc2389ac69fa9aa Merged-In: Ia272ffa77add9ef0b02ee0a23fc2389ac69fa9aa --- .../extension/vibrator/Directionality.aidl | 24 ++++++++++++++++++ .../extension/vibrator/ICustomVibrator.aidl | 25 +++++++++++++++++++ .../extension/vibrator/VendorEffect.aidl | 23 +++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/current/android/hardware/tests/extension/vibrator/Directionality.aidl create mode 100644 tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/current/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl create mode 100644 tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/current/android/hardware/tests/extension/vibrator/VendorEffect.aidl diff --git a/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/current/android/hardware/tests/extension/vibrator/Directionality.aidl b/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/current/android/hardware/tests/extension/vibrator/Directionality.aidl new file mode 100644 index 0000000000..26eb1b48b4 --- /dev/null +++ b/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/current/android/hardware/tests/extension/vibrator/Directionality.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.tests.extension.vibrator; +@Backing(type="int") @VintfStability +enum Directionality { + NONE = 0, + TRANSVERSE = 1, + LONGITUDINAL = 2, +} diff --git a/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/current/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl b/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/current/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl new file mode 100644 index 0000000000..ed9a3c665e --- /dev/null +++ b/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/current/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.tests.extension.vibrator; +@VintfStability +interface ICustomVibrator { + int getVendorCapabilities(); + void setDirectionality(android.hardware.tests.extension.vibrator.Directionality directionality); + int perform(android.hardware.tests.extension.vibrator.VendorEffect effect, android.hardware.vibrator.IVibratorCallback callback); + const int CAP_VENDOR_DIRECTIONALITY = 1; +} diff --git a/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/current/android/hardware/tests/extension/vibrator/VendorEffect.aidl b/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/current/android/hardware/tests/extension/vibrator/VendorEffect.aidl new file mode 100644 index 0000000000..4d03a0a09c --- /dev/null +++ b/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/current/android/hardware/tests/extension/vibrator/VendorEffect.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.tests.extension.vibrator; +@Backing(type="int") @VintfStability +enum VendorEffect { + CRACKLE = 0, + WIGGLE = 1, +} From a73d6bc97e11324b1d16ff807fe9d238a20a0e49 Mon Sep 17 00:00:00 2001 From: Jeongik Cha Date: Wed, 8 Apr 2020 16:23:55 +0900 Subject: [PATCH 0820/1022] Freeze vintf aidl interfaces AIDL interfaces which are vintf-stable have to be frozen in release. But these interfaces have been never frozen, so freeze them. - android.hardware.power - android.hardware.identity - android.hardware.keymaster - android.hardware.vibrator - android.hardware.light - android.hardware.tests.extension.vibrator Bug: 153500421 Bug: 153500550 Bug: 153511407 Bug: 153500549 Bug: 153501107 Bug: 153501202 Test: m Change-Id: I643c25fc695f9d1e874dcceb327d465c49e9cab6 Merged-In: I643c25fc695f9d1e874dcceb327d465c49e9cab6 --- identity/aidl/Android.bp | 1 + .../android.hardware.identity/1/.hash | 1 + .../hardware/identity/Certificate.aidl | 22 ++++++++++ .../hardware/identity/CipherSuite.aidl | 22 ++++++++++ .../identity/HardwareInformation.aidl | 26 +++++++++++ .../identity/IIdentityCredential.aidl | 30 +++++++++++++ .../identity/IIdentityCredentialStore.aidl | 37 ++++++++++++++++ .../identity/IWritableIdentityCredential.aidl | 27 ++++++++++++ .../identity/SecureAccessControlProfile.aidl | 27 ++++++++++++ keymaster/aidl/Android.bp | 1 + .../android.hardware.keymaster/1/.hash | 1 + .../hardware/keymaster/HardwareAuthToken.aidl | 27 ++++++++++++ .../keymaster/HardwareAuthenticatorType.aidl | 25 +++++++++++ .../android/hardware/keymaster/Timestamp.aidl | 22 ++++++++++ light/aidl/Android.bp | 1 + .../aidl_api/android.hardware.light/1/.hash | 1 + .../hardware/light/BrightnessMode.aidl | 24 +++++++++++ .../1/android/hardware/light/FlashMode.aidl | 24 +++++++++++ .../1/android/hardware/light/HwLight.aidl | 24 +++++++++++ .../android/hardware/light/HwLightState.aidl | 26 +++++++++++ .../1/android/hardware/light/ILights.aidl | 23 ++++++++++ .../1/android/hardware/light/LightType.aidl | 30 +++++++++++++ power/aidl/Android.bp | 1 + .../aidl_api/android.hardware.power/1/.hash | 1 + .../1/android/hardware/power/Boost.aidl | 27 ++++++++++++ .../1/android/hardware/power/IPower.aidl | 25 +++++++++++ .../1/android/hardware/power/Mode.aidl | 36 ++++++++++++++++ tests/extension/vibrator/aidl/Android.bp | 1 + .../1/.hash | 1 + .../extension/vibrator/Directionality.aidl | 24 +++++++++++ .../extension/vibrator/ICustomVibrator.aidl | 25 +++++++++++ .../extension/vibrator/VendorEffect.aidl | 23 ++++++++++ vibrator/aidl/Android.bp | 1 + .../android.hardware.vibrator/1/.hash | 1 + .../hardware/vibrator/CompositeEffect.aidl | 24 +++++++++++ .../hardware/vibrator/CompositePrimitive.aidl | 29 +++++++++++++ .../1/android/hardware/vibrator/Effect.aidl | 43 +++++++++++++++++++ .../hardware/vibrator/EffectStrength.aidl | 24 +++++++++++ .../android/hardware/vibrator/IVibrator.aidl | 43 +++++++++++++++++++ .../hardware/vibrator/IVibratorCallback.aidl | 22 ++++++++++ 40 files changed, 773 insertions(+) create mode 100644 identity/aidl/aidl_api/android.hardware.identity/1/.hash create mode 100644 identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/Certificate.aidl create mode 100644 identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/CipherSuite.aidl create mode 100644 identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/HardwareInformation.aidl create mode 100644 identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/IIdentityCredential.aidl create mode 100644 identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/IIdentityCredentialStore.aidl create mode 100644 identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/IWritableIdentityCredential.aidl create mode 100644 identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/SecureAccessControlProfile.aidl create mode 100644 keymaster/aidl/aidl_api/android.hardware.keymaster/1/.hash create mode 100644 keymaster/aidl/aidl_api/android.hardware.keymaster/1/android/hardware/keymaster/HardwareAuthToken.aidl create mode 100644 keymaster/aidl/aidl_api/android.hardware.keymaster/1/android/hardware/keymaster/HardwareAuthenticatorType.aidl create mode 100644 keymaster/aidl/aidl_api/android.hardware.keymaster/1/android/hardware/keymaster/Timestamp.aidl create mode 100644 light/aidl/aidl_api/android.hardware.light/1/.hash create mode 100644 light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/BrightnessMode.aidl create mode 100644 light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/FlashMode.aidl create mode 100644 light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/HwLight.aidl create mode 100644 light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/HwLightState.aidl create mode 100644 light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/ILights.aidl create mode 100644 light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/LightType.aidl create mode 100644 power/aidl/aidl_api/android.hardware.power/1/.hash create mode 100644 power/aidl/aidl_api/android.hardware.power/1/android/hardware/power/Boost.aidl create mode 100644 power/aidl/aidl_api/android.hardware.power/1/android/hardware/power/IPower.aidl create mode 100644 power/aidl/aidl_api/android.hardware.power/1/android/hardware/power/Mode.aidl create mode 100644 tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/1/.hash create mode 100644 tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/1/android/hardware/tests/extension/vibrator/Directionality.aidl create mode 100644 tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/1/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl create mode 100644 tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/1/android/hardware/tests/extension/vibrator/VendorEffect.aidl create mode 100644 vibrator/aidl/aidl_api/android.hardware.vibrator/1/.hash create mode 100644 vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/CompositeEffect.aidl create mode 100644 vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/CompositePrimitive.aidl create mode 100644 vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/Effect.aidl create mode 100644 vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/EffectStrength.aidl create mode 100644 vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/IVibrator.aidl create mode 100644 vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/IVibratorCallback.aidl diff --git a/identity/aidl/Android.bp b/identity/aidl/Android.bp index 72b19a1b49..7298c7df44 100644 --- a/identity/aidl/Android.bp +++ b/identity/aidl/Android.bp @@ -18,4 +18,5 @@ aidl_interface { }, }, }, + versions: ["1"], } diff --git a/identity/aidl/aidl_api/android.hardware.identity/1/.hash b/identity/aidl/aidl_api/android.hardware.identity/1/.hash new file mode 100644 index 0000000000..1e9516fe77 --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/1/.hash @@ -0,0 +1 @@ +5f61a54bc37f935e7eb8d1fb624347f68c03c6ca diff --git a/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/Certificate.aidl b/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/Certificate.aidl new file mode 100644 index 0000000000..7e3002d70a --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/Certificate.aidl @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +parcelable Certificate { + byte[] encodedCertificate; +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/CipherSuite.aidl b/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/CipherSuite.aidl new file mode 100644 index 0000000000..447203faa6 --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/CipherSuite.aidl @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@Backing(type="int") @VintfStability +enum CipherSuite { + CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 = 1, +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/HardwareInformation.aidl b/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/HardwareInformation.aidl new file mode 100644 index 0000000000..e1296e05e8 --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/HardwareInformation.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +parcelable HardwareInformation { + @utf8InCpp String credentialStoreName; + @utf8InCpp String credentialStoreAuthorName; + int dataChunkSize; + boolean isDirectAccess; + @utf8InCpp String[] supportedDocTypes; +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/IIdentityCredential.aidl new file mode 100644 index 0000000000..58b90b54be --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/IIdentityCredential.aidl @@ -0,0 +1,30 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +interface IIdentityCredential { + byte[] deleteCredential(); + byte[] createEphemeralKeyPair(); + void setReaderEphemeralPublicKey(in byte[] publicKey); + long createAuthChallenge(); + void startRetrieval(in android.hardware.identity.SecureAccessControlProfile[] accessControlProfiles, in android.hardware.keymaster.HardwareAuthToken authToken, in byte[] itemsRequest, in byte[] signingKeyBlob, in byte[] sessionTranscript, in byte[] readerSignature, in int[] requestCounts); + void startRetrieveEntryValue(in @utf8InCpp String nameSpace, in @utf8InCpp String name, in int entrySize, in int[] accessControlProfileIds); + byte[] retrieveEntryValue(in byte[] encryptedContent); + void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces); + android.hardware.identity.Certificate generateSigningKeyPair(out byte[] signingKeyBlob); +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/IIdentityCredentialStore.aidl b/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/IIdentityCredentialStore.aidl new file mode 100644 index 0000000000..5dafb76d1c --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/IIdentityCredentialStore.aidl @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +interface IIdentityCredentialStore { + android.hardware.identity.HardwareInformation getHardwareInformation(); + android.hardware.identity.IWritableIdentityCredential createCredential(in @utf8InCpp String docType, in boolean testCredential); + android.hardware.identity.IIdentityCredential getCredential(in android.hardware.identity.CipherSuite cipherSuite, in byte[] credentialData); + const int STATUS_OK = 0; + const int STATUS_FAILED = 1; + const int STATUS_CIPHER_SUITE_NOT_SUPPORTED = 2; + const int STATUS_INVALID_DATA = 3; + const int STATUS_INVALID_AUTH_TOKEN = 4; + const int STATUS_INVALID_ITEMS_REQUEST_MESSAGE = 5; + const int STATUS_READER_SIGNATURE_CHECK_FAILED = 6; + const int STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND = 7; + const int STATUS_USER_AUTHENTICATION_FAILED = 8; + const int STATUS_READER_AUTHENTICATION_FAILED = 9; + const int STATUS_NO_ACCESS_CONTROL_PROFILES = 10; + const int STATUS_NOT_IN_REQUEST_MESSAGE = 11; + const int STATUS_SESSION_TRANSCRIPT_MISMATCH = 12; +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/IWritableIdentityCredential.aidl new file mode 100644 index 0000000000..32f283cc18 --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/IWritableIdentityCredential.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +interface IWritableIdentityCredential { + android.hardware.identity.Certificate[] getAttestationCertificate(in byte[] attestationApplicationId, in byte[] attestationChallenge); + void startPersonalization(in int accessControlProfileCount, in int[] entryCounts); + android.hardware.identity.SecureAccessControlProfile addAccessControlProfile(in int id, in android.hardware.identity.Certificate readerCertificate, in boolean userAuthenticationRequired, in long timeoutMillis, in long secureUserId); + void beginAddEntry(in int[] accessControlProfileIds, in @utf8InCpp String nameSpace, in @utf8InCpp String name, in int entrySize); + byte[] addEntryValue(in byte[] content); + void finishAddingEntries(out byte[] credentialData, out byte[] proofOfProvisioningSignature); +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/SecureAccessControlProfile.aidl b/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/SecureAccessControlProfile.aidl new file mode 100644 index 0000000000..dfc1ad0681 --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/1/android/hardware/identity/SecureAccessControlProfile.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +parcelable SecureAccessControlProfile { + int id; + android.hardware.identity.Certificate readerCertificate; + boolean userAuthenticationRequired; + long timeoutMillis; + long secureUserId; + byte[] mac; +} diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp index a2d73ead08..3011da67db 100644 --- a/keymaster/aidl/Android.bp +++ b/keymaster/aidl/Android.bp @@ -15,4 +15,5 @@ aidl_interface { }, }, }, + versions: ["1"], } diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/1/.hash b/keymaster/aidl/aidl_api/android.hardware.keymaster/1/.hash new file mode 100644 index 0000000000..4c441d44a6 --- /dev/null +++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/1/.hash @@ -0,0 +1 @@ +584fcb51e6025741fa62e16227c0158bf26a9195 diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/1/android/hardware/keymaster/HardwareAuthToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/1/android/hardware/keymaster/HardwareAuthToken.aidl new file mode 100644 index 0000000000..db1df2b050 --- /dev/null +++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/1/android/hardware/keymaster/HardwareAuthToken.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymaster; +@VintfStability +parcelable HardwareAuthToken { + long challenge; + long userId; + long authenticatorId; + android.hardware.keymaster.HardwareAuthenticatorType authenticatorType; + android.hardware.keymaster.Timestamp timestamp; + byte[] mac; +} diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/1/android/hardware/keymaster/HardwareAuthenticatorType.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/1/android/hardware/keymaster/HardwareAuthenticatorType.aidl new file mode 100644 index 0000000000..924567f95b --- /dev/null +++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/1/android/hardware/keymaster/HardwareAuthenticatorType.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymaster; +@Backing(type="int") @VintfStability +enum HardwareAuthenticatorType { + NONE = 0, + PASSWORD = 1, + FINGERPRINT = 2, + ANY = -1, +} diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/1/android/hardware/keymaster/Timestamp.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/1/android/hardware/keymaster/Timestamp.aidl new file mode 100644 index 0000000000..45fa1aed13 --- /dev/null +++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/1/android/hardware/keymaster/Timestamp.aidl @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymaster; +@VintfStability +parcelable Timestamp { + long milliSeconds; +} diff --git a/light/aidl/Android.bp b/light/aidl/Android.bp index 916a857b58..91de3e9e0c 100644 --- a/light/aidl/Android.bp +++ b/light/aidl/Android.bp @@ -15,4 +15,5 @@ aidl_interface { }, }, }, + versions: ["1"], } diff --git a/light/aidl/aidl_api/android.hardware.light/1/.hash b/light/aidl/aidl_api/android.hardware.light/1/.hash new file mode 100644 index 0000000000..e8fcb80fae --- /dev/null +++ b/light/aidl/aidl_api/android.hardware.light/1/.hash @@ -0,0 +1 @@ +33fec8401b6e66bddaeff251e1a2a0f4fa0d3bee diff --git a/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/BrightnessMode.aidl b/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/BrightnessMode.aidl new file mode 100644 index 0000000000..c4c6d64786 --- /dev/null +++ b/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/BrightnessMode.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.light; +@VintfStability +enum BrightnessMode { + USER = 0, + SENSOR = 1, + LOW_PERSISTENCE = 2, +} diff --git a/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/FlashMode.aidl b/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/FlashMode.aidl new file mode 100644 index 0000000000..349f9f321c --- /dev/null +++ b/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/FlashMode.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.light; +@VintfStability +enum FlashMode { + NONE = 0, + TIMED = 1, + HARDWARE = 2, +} diff --git a/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/HwLight.aidl b/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/HwLight.aidl new file mode 100644 index 0000000000..c397f91060 --- /dev/null +++ b/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/HwLight.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.light; +@VintfStability +parcelable HwLight { + int id; + int ordinal; + android.hardware.light.LightType type; +} diff --git a/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/HwLightState.aidl b/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/HwLightState.aidl new file mode 100644 index 0000000000..44a088234f --- /dev/null +++ b/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/HwLightState.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.light; +@VintfStability +parcelable HwLightState { + int color; + android.hardware.light.FlashMode flashMode; + int flashOnMs; + int flashOffMs; + android.hardware.light.BrightnessMode brightnessMode; +} diff --git a/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/ILights.aidl b/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/ILights.aidl new file mode 100644 index 0000000000..fc6c6265af --- /dev/null +++ b/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/ILights.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.light; +@VintfStability +interface ILights { + void setLightState(in int id, in android.hardware.light.HwLightState state); + android.hardware.light.HwLight[] getLights(); +} diff --git a/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/LightType.aidl b/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/LightType.aidl new file mode 100644 index 0000000000..77ab98c1cf --- /dev/null +++ b/light/aidl/aidl_api/android.hardware.light/1/android/hardware/light/LightType.aidl @@ -0,0 +1,30 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.light; +@VintfStability +enum LightType { + BACKLIGHT = 0, + KEYBOARD = 1, + BUTTONS = 2, + BATTERY = 3, + NOTIFICATIONS = 4, + ATTENTION = 5, + BLUETOOTH = 6, + WIFI = 7, + MICROPHONE = 8, +} diff --git a/power/aidl/Android.bp b/power/aidl/Android.bp index 2a6cf94977..40086520fa 100644 --- a/power/aidl/Android.bp +++ b/power/aidl/Android.bp @@ -29,4 +29,5 @@ aidl_interface { }, }, }, + versions: ["1"], } diff --git a/power/aidl/aidl_api/android.hardware.power/1/.hash b/power/aidl/aidl_api/android.hardware.power/1/.hash new file mode 100644 index 0000000000..3baf095ea7 --- /dev/null +++ b/power/aidl/aidl_api/android.hardware.power/1/.hash @@ -0,0 +1 @@ +d5bbe80a8c4df49931e8453f3138820e82dc525c diff --git a/power/aidl/aidl_api/android.hardware.power/1/android/hardware/power/Boost.aidl b/power/aidl/aidl_api/android.hardware.power/1/android/hardware/power/Boost.aidl new file mode 100644 index 0000000000..aced215bb9 --- /dev/null +++ b/power/aidl/aidl_api/android.hardware.power/1/android/hardware/power/Boost.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.power; +@Backing(type="int") @VintfStability +enum Boost { + INTERACTION = 0, + DISPLAY_UPDATE_IMMINENT = 1, + ML_ACC = 2, + AUDIO_LAUNCH = 3, + CAMERA_LAUNCH = 4, + CAMERA_SHOT = 5, +} diff --git a/power/aidl/aidl_api/android.hardware.power/1/android/hardware/power/IPower.aidl b/power/aidl/aidl_api/android.hardware.power/1/android/hardware/power/IPower.aidl new file mode 100644 index 0000000000..8a06623fca --- /dev/null +++ b/power/aidl/aidl_api/android.hardware.power/1/android/hardware/power/IPower.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.power; +@VintfStability +interface IPower { + oneway void setMode(in android.hardware.power.Mode type, in boolean enabled); + boolean isModeSupported(in android.hardware.power.Mode type); + oneway void setBoost(in android.hardware.power.Boost type, in int durationMs); + boolean isBoostSupported(in android.hardware.power.Boost type); +} diff --git a/power/aidl/aidl_api/android.hardware.power/1/android/hardware/power/Mode.aidl b/power/aidl/aidl_api/android.hardware.power/1/android/hardware/power/Mode.aidl new file mode 100644 index 0000000000..f7c2552c8d --- /dev/null +++ b/power/aidl/aidl_api/android.hardware.power/1/android/hardware/power/Mode.aidl @@ -0,0 +1,36 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.power; +@Backing(type="int") @VintfStability +enum Mode { + DOUBLE_TAP_TO_WAKE = 0, + LOW_POWER = 1, + SUSTAINED_PERFORMANCE = 2, + FIXED_PERFORMANCE = 3, + VR = 4, + LAUNCH = 5, + EXPENSIVE_RENDERING = 6, + INTERACTIVE = 7, + DEVICE_IDLE = 8, + DISPLAY_INACTIVE = 9, + AUDIO_STREAMING_LOW_LATENCY = 10, + CAMERA_STREAMING_SECURE = 11, + CAMERA_STREAMING_LOW = 12, + CAMERA_STREAMING_MID = 13, + CAMERA_STREAMING_HIGH = 14, +} diff --git a/tests/extension/vibrator/aidl/Android.bp b/tests/extension/vibrator/aidl/Android.bp index b1cda0c9c1..c64779cb4c 100644 --- a/tests/extension/vibrator/aidl/Android.bp +++ b/tests/extension/vibrator/aidl/Android.bp @@ -26,4 +26,5 @@ aidl_interface { enabled: false, }, }, + versions: ["1"], } diff --git a/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/1/.hash b/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/1/.hash new file mode 100644 index 0000000000..7df27909e1 --- /dev/null +++ b/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/1/.hash @@ -0,0 +1 @@ +86dfe4cf135ed1bf501e7e8408bcee3b590e8a53 diff --git a/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/1/android/hardware/tests/extension/vibrator/Directionality.aidl b/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/1/android/hardware/tests/extension/vibrator/Directionality.aidl new file mode 100644 index 0000000000..26eb1b48b4 --- /dev/null +++ b/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/1/android/hardware/tests/extension/vibrator/Directionality.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.tests.extension.vibrator; +@Backing(type="int") @VintfStability +enum Directionality { + NONE = 0, + TRANSVERSE = 1, + LONGITUDINAL = 2, +} diff --git a/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/1/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl b/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/1/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl new file mode 100644 index 0000000000..ed9a3c665e --- /dev/null +++ b/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/1/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.tests.extension.vibrator; +@VintfStability +interface ICustomVibrator { + int getVendorCapabilities(); + void setDirectionality(android.hardware.tests.extension.vibrator.Directionality directionality); + int perform(android.hardware.tests.extension.vibrator.VendorEffect effect, android.hardware.vibrator.IVibratorCallback callback); + const int CAP_VENDOR_DIRECTIONALITY = 1; +} diff --git a/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/1/android/hardware/tests/extension/vibrator/VendorEffect.aidl b/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/1/android/hardware/tests/extension/vibrator/VendorEffect.aidl new file mode 100644 index 0000000000..4d03a0a09c --- /dev/null +++ b/tests/extension/vibrator/aidl/aidl_api/android.hardware.tests.extension.vibrator/1/android/hardware/tests/extension/vibrator/VendorEffect.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.tests.extension.vibrator; +@Backing(type="int") @VintfStability +enum VendorEffect { + CRACKLE = 0, + WIGGLE = 1, +} diff --git a/vibrator/aidl/Android.bp b/vibrator/aidl/Android.bp index ae7f4348ff..97663538fa 100644 --- a/vibrator/aidl/Android.bp +++ b/vibrator/aidl/Android.bp @@ -15,4 +15,5 @@ aidl_interface { }, }, }, + versions: ["1"], } diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/1/.hash b/vibrator/aidl/aidl_api/android.hardware.vibrator/1/.hash new file mode 100644 index 0000000000..06b78577c7 --- /dev/null +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/1/.hash @@ -0,0 +1 @@ +eeab78b6096b029f424ab5ce9c2c4ef1249a5cb0 diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/CompositeEffect.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/CompositeEffect.aidl new file mode 100644 index 0000000000..8cb259ffaa --- /dev/null +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/CompositeEffect.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.vibrator; +@VintfStability +parcelable CompositeEffect { + int delayMs; + android.hardware.vibrator.CompositePrimitive primitive; + float scale; +} diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/CompositePrimitive.aidl new file mode 100644 index 0000000000..6ab7ac5b20 --- /dev/null +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/CompositePrimitive.aidl @@ -0,0 +1,29 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.vibrator; +@Backing(type="int") @VintfStability +enum CompositePrimitive { + NOOP = 0, + CLICK = 1, + THUD = 2, + SPIN = 3, + QUICK_RISE = 4, + SLOW_RISE = 5, + QUICK_FALL = 6, + LIGHT_TICK = 7, +} diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/Effect.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/Effect.aidl new file mode 100644 index 0000000000..5ed4dc5ad6 --- /dev/null +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/Effect.aidl @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.vibrator; +@Backing(type="int") @VintfStability +enum Effect { + CLICK = 0, + DOUBLE_CLICK = 1, + TICK = 2, + THUD = 3, + POP = 4, + HEAVY_CLICK = 5, + RINGTONE_1 = 6, + RINGTONE_2 = 7, + RINGTONE_3 = 8, + RINGTONE_4 = 9, + RINGTONE_5 = 10, + RINGTONE_6 = 11, + RINGTONE_7 = 12, + RINGTONE_8 = 13, + RINGTONE_9 = 14, + RINGTONE_10 = 15, + RINGTONE_11 = 16, + RINGTONE_12 = 17, + RINGTONE_13 = 18, + RINGTONE_14 = 19, + RINGTONE_15 = 20, + TEXTURE_TICK = 21, +} diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/EffectStrength.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/EffectStrength.aidl new file mode 100644 index 0000000000..802d236309 --- /dev/null +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/EffectStrength.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.vibrator; +@Backing(type="byte") @VintfStability +enum EffectStrength { + LIGHT = 0, + MEDIUM = 1, + STRONG = 2, +} diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/IVibrator.aidl new file mode 100644 index 0000000000..2de1d7bde7 --- /dev/null +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/IVibrator.aidl @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.vibrator; +@VintfStability +interface IVibrator { + int getCapabilities(); + void off(); + void on(in int timeoutMs, in android.hardware.vibrator.IVibratorCallback callback); + int perform(in android.hardware.vibrator.Effect effect, in android.hardware.vibrator.EffectStrength strength, in android.hardware.vibrator.IVibratorCallback callback); + android.hardware.vibrator.Effect[] getSupportedEffects(); + void setAmplitude(in float amplitude); + void setExternalControl(in boolean enabled); + int getCompositionDelayMax(); + int getCompositionSizeMax(); + android.hardware.vibrator.CompositePrimitive[] getSupportedPrimitives(); + int getPrimitiveDuration(android.hardware.vibrator.CompositePrimitive primitive); + void compose(in android.hardware.vibrator.CompositeEffect[] composite, in android.hardware.vibrator.IVibratorCallback callback); + android.hardware.vibrator.Effect[] getSupportedAlwaysOnEffects(); + void alwaysOnEnable(in int id, in android.hardware.vibrator.Effect effect, in android.hardware.vibrator.EffectStrength strength); + void alwaysOnDisable(in int id); + const int CAP_ON_CALLBACK = 1; + const int CAP_PERFORM_CALLBACK = 2; + const int CAP_AMPLITUDE_CONTROL = 4; + const int CAP_EXTERNAL_CONTROL = 8; + const int CAP_EXTERNAL_AMPLITUDE_CONTROL = 16; + const int CAP_COMPOSE_EFFECTS = 32; + const int CAP_ALWAYS_ON_CONTROL = 64; +} diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/IVibratorCallback.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/IVibratorCallback.aidl new file mode 100644 index 0000000000..3a1e7d865b --- /dev/null +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/1/android/hardware/vibrator/IVibratorCallback.aidl @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.vibrator; +@VintfStability +interface IVibratorCallback { + oneway void onComplete(); +} From c537f3e2ce3299e92888d7e3dcf945e4e25f0da0 Mon Sep 17 00:00:00 2001 From: Jeongik Cha Date: Thu, 9 Apr 2020 17:01:44 +0900 Subject: [PATCH 0821/1022] Remove redunant aidl api test-android.hardware.vibrator-ext became android.hardware.vibrator-ext accordingly, remove redunant aidl api directory Bug: 153501107 Bug: 152655547 Test: m Change-Id: I3de4196c6fe8ecfae4a6bd5f6bac7920695150c8 Merged-In: I3de4196c6fe8ecfae4a6bd5f6bac7920695150c8 --- .../extension/vibrator/Directionality.aidl | 24 ------------------ .../extension/vibrator/ICustomVibrator.aidl | 25 ------------------- .../extension/vibrator/VendorEffect.aidl | 23 ----------------- 3 files changed, 72 deletions(-) delete mode 100644 tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/Directionality.aidl delete mode 100644 tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl delete mode 100644 tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/VendorEffect.aidl diff --git a/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/Directionality.aidl b/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/Directionality.aidl deleted file mode 100644 index 26eb1b48b4..0000000000 --- a/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/Directionality.aidl +++ /dev/null @@ -1,24 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // -/////////////////////////////////////////////////////////////////////////////// - -// This file is a snapshot of an AIDL interface (or parcelable). Do not try to -// edit this file. It looks like you are doing that because you have modified -// an AIDL interface in a backward-incompatible way, e.g., deleting a function -// from an interface or a field from a parcelable and it broke the build. That -// breakage is intended. -// -// You must not make a backward incompatible changes to the AIDL files built -// with the aidl_interface module type with versions property set. The module -// type is used to build AIDL files in a way that they can be used across -// independently updatable components of the system. If a device is shipped -// with such a backward incompatible change, it has a high risk of breaking -// later when a module using the interface is updated, e.g., Mainline modules. - -package android.hardware.tests.extension.vibrator; -@Backing(type="int") @VintfStability -enum Directionality { - NONE = 0, - TRANSVERSE = 1, - LONGITUDINAL = 2, -} diff --git a/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl b/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl deleted file mode 100644 index ed9a3c665e..0000000000 --- a/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl +++ /dev/null @@ -1,25 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // -/////////////////////////////////////////////////////////////////////////////// - -// This file is a snapshot of an AIDL interface (or parcelable). Do not try to -// edit this file. It looks like you are doing that because you have modified -// an AIDL interface in a backward-incompatible way, e.g., deleting a function -// from an interface or a field from a parcelable and it broke the build. That -// breakage is intended. -// -// You must not make a backward incompatible changes to the AIDL files built -// with the aidl_interface module type with versions property set. The module -// type is used to build AIDL files in a way that they can be used across -// independently updatable components of the system. If a device is shipped -// with such a backward incompatible change, it has a high risk of breaking -// later when a module using the interface is updated, e.g., Mainline modules. - -package android.hardware.tests.extension.vibrator; -@VintfStability -interface ICustomVibrator { - int getVendorCapabilities(); - void setDirectionality(android.hardware.tests.extension.vibrator.Directionality directionality); - int perform(android.hardware.tests.extension.vibrator.VendorEffect effect, android.hardware.vibrator.IVibratorCallback callback); - const int CAP_VENDOR_DIRECTIONALITY = 1; -} diff --git a/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/VendorEffect.aidl b/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/VendorEffect.aidl deleted file mode 100644 index 4d03a0a09c..0000000000 --- a/tests/extension/vibrator/aidl/aidl_api/test-android.hardware.vibrator-ext/current/android/hardware/tests/extension/vibrator/VendorEffect.aidl +++ /dev/null @@ -1,23 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // -/////////////////////////////////////////////////////////////////////////////// - -// This file is a snapshot of an AIDL interface (or parcelable). Do not try to -// edit this file. It looks like you are doing that because you have modified -// an AIDL interface in a backward-incompatible way, e.g., deleting a function -// from an interface or a field from a parcelable and it broke the build. That -// breakage is intended. -// -// You must not make a backward incompatible changes to the AIDL files built -// with the aidl_interface module type with versions property set. The module -// type is used to build AIDL files in a way that they can be used across -// independently updatable components of the system. If a device is shipped -// with such a backward incompatible change, it has a high risk of breaking -// later when a module using the interface is updated, e.g., Mainline modules. - -package android.hardware.tests.extension.vibrator; -@Backing(type="int") @VintfStability -enum VendorEffect { - CRACKLE = 0, - WIGGLE = 1, -} From cd4d9abdcc710462dfb8efa6ce3f5753f1fc7573 Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Thu, 9 Apr 2020 11:05:46 -0400 Subject: [PATCH 0822/1022] Don't modify -1 sensorHandle value A -1 sensorHandle value is used to denote all active sensors should be stopped for a given channel. Make sure the multi-HAL code doesn't modify handles of this value or it'll corrupt them before passing to the direct channel sub-HAL. Bug: 153413565 Test: atest VtsHalSensorsV2_0Target Change-Id: I3fe9cbf4661aa3db4ff534765d5112a193b7bf4a --- sensors/common/default/2.X/multihal/HalProxy.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sensors/common/default/2.X/multihal/HalProxy.cpp b/sensors/common/default/2.X/multihal/HalProxy.cpp index 518e138f6a..869c0330f4 100644 --- a/sensors/common/default/2.X/multihal/HalProxy.cpp +++ b/sensors/common/default/2.X/multihal/HalProxy.cpp @@ -260,9 +260,14 @@ Return HalProxy::configDirectReport(int32_t sensorHandle, int32_t channelH RateLevel rate, configDirectReport_cb _hidl_cb) { if (mDirectChannelSubHal == nullptr) { _hidl_cb(Result::INVALID_OPERATION, -1 /* reportToken */); + } else if (sensorHandle == -1 && rate != RateLevel::STOP) { + _hidl_cb(Result::BAD_VALUE, -1 /* reportToken */); } else { - mDirectChannelSubHal->configDirectReport(clearSubHalIndex(sensorHandle), channelHandle, - rate, _hidl_cb); + // -1 denotes all sensors should be disabled + if (sensorHandle != -1) { + sensorHandle = clearSubHalIndex(sensorHandle); + } + mDirectChannelSubHal->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); } return Return(); } From 050bf7864462aa8db54c93473d75b1829cfd7cd7 Mon Sep 17 00:00:00 2001 From: Amy Zhang Date: Fri, 27 Mar 2020 14:54:48 -0700 Subject: [PATCH 0823/1022] Enhance and refactoring the Tuner VTS on searching frontend by type test Test: atest VtsHalTvTunerV1_0TargetTest on cf and vendor device Bug: 150953857 Change-Id: I9c90e34c6b336d20f5456e7f676ced699f166d54 --- tv/tuner/1.0/default/Frontend.cpp | 24 +- tv/tuner/1.0/default/Frontend.h | 1 + tv/tuner/1.0/default/Tuner.cpp | 78 ++-- .../VtsHalTvTunerV1_0TargetTest.cpp | 349 ++++++------------ 4 files changed, 179 insertions(+), 273 deletions(-) diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp index bb0d8dcaf9..2cff9be459 100644 --- a/tv/tuner/1.0/default/Frontend.cpp +++ b/tv/tuner/1.0/default/Frontend.cpp @@ -41,6 +41,7 @@ Return Frontend::close() { ALOGV("%s", __FUNCTION__); // Reset callback mCallback = nullptr; + mIsLocked = false; return Result::SUCCESS; } @@ -64,6 +65,7 @@ Return Frontend::tune(const FrontendSettings& /* settings */) { } mCallback->onEvent(FrontendEventType::LOCKED); + mIsLocked = false; return Result::SUCCESS; } @@ -71,16 +73,35 @@ Return Frontend::stopTune() { ALOGV("%s", __FUNCTION__); mTunerService->frontendStopTune(mId); + mIsLocked = false; return Result::SUCCESS; } -Return Frontend::scan(const FrontendSettings& /* settings */, FrontendScanType /* type */) { +Return Frontend::scan(const FrontendSettings& settings, FrontendScanType type) { ALOGV("%s", __FUNCTION__); + if (mType != FrontendType::DVBT) { + return Result::UNAVAILABLE; + } + FrontendScanMessage msg; + + if (mIsLocked) { + msg.isEnd(true); + mCallback->onScanMessage(FrontendScanMessageType::END, msg); + return Result::SUCCESS; + } + + uint32_t frequency = settings.dvbt().frequency; + if (type == FrontendScanType::SCAN_BLIND) { + frequency += 100; + } + msg.frequencies({frequency}); + mCallback->onScanMessage(FrontendScanMessageType::FREQUENCY, msg); msg.isLocked(true); mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg); + mIsLocked = true; return Result::SUCCESS; } @@ -88,6 +109,7 @@ Return Frontend::scan(const FrontendSettings& /* settings */, FrontendSc Return Frontend::stopScan() { ALOGV("%s", __FUNCTION__); + mIsLocked = false; return Result::SUCCESS; } diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h index b954639956..8a30b91e87 100644 --- a/tv/tuner/1.0/default/Frontend.h +++ b/tv/tuner/1.0/default/Frontend.h @@ -74,6 +74,7 @@ class Frontend : public IFrontend { sp mTunerService; FrontendType mType = FrontendType::UNDEFINED; FrontendId mId = 0; + bool mIsLocked = false; const string FRONTEND_STREAM_FILE = "/vendor/etc/dumpTs3.ts"; std::ifstream mFrontendData; diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp index 8fb506132a..6f9a5cf016 100644 --- a/tv/tuner/1.0/default/Tuner.cpp +++ b/tv/tuner/1.0/default/Tuner.cpp @@ -106,40 +106,54 @@ Return Tuner::openDescrambler(openDescrambler_cb _hidl_cb) { return Void(); } -Return Tuner::getFrontendInfo(FrontendId /*frontendId*/, getFrontendInfo_cb _hidl_cb) { +Return Tuner::getFrontendInfo(FrontendId frontendId, getFrontendInfo_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); - vector statusCaps = { - FrontendStatusType::DEMOD_LOCK, - FrontendStatusType::SNR, - FrontendStatusType::FEC, - FrontendStatusType::MODULATION, - FrontendStatusType::PLP_ID, - FrontendStatusType::LAYER_ERROR, - FrontendStatusType::ATSC3_PLP_INFO, - }; - FrontendInfo::FrontendCapabilities frontendCaps; - FrontendIsdbtCapabilities isdbtCaps{ - .modeCap = FrontendIsdbtMode::MODE_1 | FrontendIsdbtMode::MODE_2, - .bandwidthCap = (unsigned int)FrontendIsdbtBandwidth::BANDWIDTH_6MHZ, - .modulationCap = (unsigned int)FrontendIsdbtModulation::MOD_16QAM, - // ISDBT shares coderate and guard interval with DVBT - .coderateCap = FrontendDvbtCoderate::CODERATE_4_5 | FrontendDvbtCoderate::CODERATE_6_7, - .guardIntervalCap = (unsigned int)FrontendDvbtGuardInterval::INTERVAL_1_128, - }; - frontendCaps.isdbtCaps(isdbtCaps); - // assign randomly selected values for testing. - FrontendInfo info{ - .type = FrontendType::ISDBT, - .minFrequency = 139, - .maxFrequency = 1139, - .minSymbolRate = 45, - .maxSymbolRate = 1145, - .acquireRange = 30, - .exclusiveGroupId = 57, - .statusCaps = statusCaps, - .frontendCaps = frontendCaps, - }; + FrontendInfo info; + if (frontendId >= mFrontendSize) { + _hidl_cb(Result::INVALID_ARGUMENT, info); + return Void(); + } + + switch (mFrontends[frontendId]->getFrontendType()) { + case FrontendType::DVBT: + info.type = FrontendType::DVBT; + break; + default: + vector statusCaps = { + FrontendStatusType::DEMOD_LOCK, + FrontendStatusType::SNR, + FrontendStatusType::FEC, + FrontendStatusType::MODULATION, + FrontendStatusType::PLP_ID, + FrontendStatusType::LAYER_ERROR, + FrontendStatusType::ATSC3_PLP_INFO, + }; + FrontendInfo::FrontendCapabilities frontendCaps; + FrontendIsdbtCapabilities isdbtCaps{ + .modeCap = FrontendIsdbtMode::MODE_1 | FrontendIsdbtMode::MODE_2, + .bandwidthCap = (unsigned int)FrontendIsdbtBandwidth::BANDWIDTH_6MHZ, + .modulationCap = (unsigned int)FrontendIsdbtModulation::MOD_16QAM, + // ISDBT shares coderate and guard interval with DVBT + .coderateCap = + FrontendDvbtCoderate::CODERATE_4_5 | FrontendDvbtCoderate::CODERATE_6_7, + .guardIntervalCap = (unsigned int)FrontendDvbtGuardInterval::INTERVAL_1_128, + }; + frontendCaps.isdbtCaps(isdbtCaps); + // assign randomly selected values for testing. + info = { + .type = FrontendType::ISDBT, + .minFrequency = 139, + .maxFrequency = 1139, + .minSymbolRate = 45, + .maxSymbolRate = 1145, + .acquireRange = 30, + .exclusiveGroupId = 57, + .statusCaps = statusCaps, + .frontendCaps = frontendCaps, + }; + break; + } _hidl_cb(Result::SUCCESS, info); return Void(); diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 8f83d82afe..5e98367af6 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -47,6 +47,7 @@ #include "VtsHalTvTunerV1_0TestConfigurations.h" #define WAIT_TIMEOUT 3000000000 +#define INVALID_ID -1 using android::Condition; using android::IMemory; @@ -214,7 +215,7 @@ class FrontendCallback : public IFrontendCallback { // Helper methods uint32_t getTargetFrequency(FrontendSettings settings, FrontendType type); - void resetBlindScanStartingFrequency(FrontendConfig config, uint32_t resetingFreq); + void resetBlindScanStartingFrequency(FrontendConfig& config, uint32_t resetingFreq); private: bool mEventReceived = false; @@ -340,7 +341,7 @@ uint32_t FrontendCallback::getTargetFrequency(FrontendSettings settings, Fronten } } -void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig config, +void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig& config, uint32_t resetingFreq) { switch (config.type) { case FrontendType::ANALOG: @@ -856,7 +857,7 @@ class TunerHidlTest : public testing::TestWithParam { AssertionResult getFrontendIds(); AssertionResult getFrontendInfo(uint32_t frontendId); - AssertionResult openFrontend(uint32_t frontendId); + AssertionResult openFrontendById(uint32_t frontendId); AssertionResult setFrontendCallback(); AssertionResult scanFrontend(FrontendConfig config, FrontendScanType type); AssertionResult stopScanFrontend(); @@ -889,7 +890,10 @@ class TunerHidlTest : public testing::TestWithParam { RecordSettings recordSetting, vector goldenOutputFiles); AssertionResult broadcastDataFlowTest(vector goldenOutputFiles); - void broadcastFilterTest(int selectedFilter, int feId); + + void broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf); + void getFrontendIdByType(FrontendType feType, uint32_t& feId); + void scanTest(FrontendConfig frontend, FrontendScanType type); FilterEventType getFilterEventType(DemuxFilterType type); }; @@ -913,7 +917,7 @@ AssertionResult TunerHidlTest::getFrontendInfo(uint32_t frontendId) { return AssertionResult(status == Result::SUCCESS); } -AssertionResult TunerHidlTest::openFrontend(uint32_t frontendId) { +AssertionResult TunerHidlTest::openFrontendById(uint32_t frontendId) { Result status; mService->openFrontendById(frontendId, [&](Result result, const sp& frontend) { mFrontend = frontend; @@ -923,7 +927,7 @@ AssertionResult TunerHidlTest::openFrontend(uint32_t frontendId) { } AssertionResult TunerHidlTest::setFrontendCallback() { - EXPECT_TRUE(mFrontend) << "Test with openFrontend first."; + EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; mFrontendCallback = new FrontendCallback(); auto callbackStatus = mFrontend->setCallback(mFrontendCallback); return AssertionResult(callbackStatus.isOk()); @@ -931,7 +935,7 @@ AssertionResult TunerHidlTest::setFrontendCallback() { AssertionResult TunerHidlTest::scanFrontend(FrontendConfig config, FrontendScanType type) { EXPECT_TRUE(mFrontendCallback) - << "test with openFrontend/setFrontendCallback/getFrontendInfo first."; + << "test with openFrontendById/setFrontendCallback/getFrontendInfo first."; EXPECT_TRUE(mFrontendInfo.type == config.type) << "FrontendConfig does not match the frontend info of the given id."; @@ -941,7 +945,7 @@ AssertionResult TunerHidlTest::scanFrontend(FrontendConfig config, FrontendScanT } AssertionResult TunerHidlTest::stopScanFrontend() { - EXPECT_TRUE(mFrontend) << "Test with openFrontend first."; + EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; Result status; status = mFrontend->stopScan(); return AssertionResult(status == Result::SUCCESS); @@ -949,7 +953,7 @@ AssertionResult TunerHidlTest::stopScanFrontend() { AssertionResult TunerHidlTest::tuneFrontend(FrontendConfig config) { EXPECT_TRUE(mFrontendCallback) - << "test with openFrontend/setFrontendCallback/getFrontendInfo first."; + << "test with openFrontendById/setFrontendCallback/getFrontendInfo first."; EXPECT_TRUE(mFrontendInfo.type == config.type) << "FrontendConfig does not match the frontend info of the given id."; @@ -959,14 +963,14 @@ AssertionResult TunerHidlTest::tuneFrontend(FrontendConfig config) { } AssertionResult TunerHidlTest::stopTuneFrontend() { - EXPECT_TRUE(mFrontend) << "Test with openFrontend first."; + EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; Result status; status = mFrontend->stopTune(); return AssertionResult(status == Result::SUCCESS); } AssertionResult TunerHidlTest::closeFrontend() { - EXPECT_TRUE(mFrontend) << "Test with openFrontend first."; + EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; Result status; status = mFrontend->close(); mFrontend = nullptr; @@ -988,7 +992,7 @@ AssertionResult TunerHidlTest::openDemux() { AssertionResult TunerHidlTest::setDemuxFrontendDataSource(uint32_t frontendId) { EXPECT_TRUE(mDemux) << "Test with openDemux first."; - EXPECT_TRUE(mFrontend) << "Test with openFrontend first."; + EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; auto status = mDemux->setFrontendDataSource(frontendId); return AssertionResult(status.isOk()); } @@ -1184,28 +1188,6 @@ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutp return success(); } -void TunerHidlTest::broadcastFilterTest(int selectedFilter, int feId) { - ASSERT_TRUE(openFrontend(feId)); - ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(openDemux()); - ASSERT_TRUE(setDemuxFrontendDataSource(feId)); - ASSERT_TRUE(openFilterInDemux(filterArray[selectedFilter].type)); - uint32_t filterId; - ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); - ASSERT_TRUE(configFilter(filterArray[selectedFilter].setting, filterId)); - ASSERT_TRUE(getFilterMQDescriptor(filterId)); - ASSERT_TRUE(startFilter(filterId)); - // tune test - ASSERT_TRUE(tuneFrontend(frontendArray[DVBT])); - // broadcast data flow test - ASSERT_TRUE(broadcastDataFlowTest(goldenOutputFiles)); - ASSERT_TRUE(stopTuneFrontend()); - ASSERT_TRUE(stopFilter(filterId)); - ASSERT_TRUE(closeFilter(filterId)); - ASSERT_TRUE(closeDemux()); - ASSERT_TRUE(closeFrontend()); -} - /* * TODO: re-enable the tests after finalizing the test refactoring. */ @@ -1351,6 +1333,64 @@ AssertionResult TunerHidlTest::recordDataFlowTest(vector filterConf, }*/ /*========================= End Data Flow Tests Implementation =========================*/ +/*================================= Start Test Module =================================*/ +void TunerHidlTest::getFrontendIdByType(FrontendType feType, uint32_t& feId) { + ASSERT_TRUE(getFrontendIds()); + ASSERT_TRUE(mFeIds.size() > 0); + for (size_t i = 0; i < mFeIds.size(); i++) { + ASSERT_TRUE(getFrontendInfo(mFeIds[i])); + if (mFrontendInfo.type != feType) { + continue; + } + feId = mFeIds[i]; + return; + } + feId = INVALID_ID; +} + +void TunerHidlTest::broadcastSingleFilterTest(FilterConfig filterConf, + FrontendConfig frontendConf) { + uint32_t feId; + getFrontendIdByType(frontendConf.type, feId); + if (feId == INVALID_ID) { + // TODO broadcast test on Cuttlefish needs licensed ts input, + // these tests are runnable on vendor device with real frontend module + // or with manual ts installing and use DVBT frontend. + return; + } + ASSERT_TRUE(openFrontendById(feId)); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(openDemux()); + ASSERT_TRUE(setDemuxFrontendDataSource(feId)); + ASSERT_TRUE(openFilterInDemux(filterConf.type)); + uint32_t filterId; + ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); + ASSERT_TRUE(configFilter(filterConf.setting, filterId)); + ASSERT_TRUE(getFilterMQDescriptor(filterId)); + ASSERT_TRUE(startFilter(filterId)); + // tune test + ASSERT_TRUE(tuneFrontend(frontendConf)); + // broadcast data flow test + ASSERT_TRUE(broadcastDataFlowTest(goldenOutputFiles)); + ASSERT_TRUE(stopTuneFrontend()); + ASSERT_TRUE(stopFilter(filterId)); + ASSERT_TRUE(closeFilter(filterId)); + ASSERT_TRUE(closeDemux()); + ASSERT_TRUE(closeFrontend()); +} + +void TunerHidlTest::scanTest(FrontendConfig frontendConf, FrontendScanType scanType) { + uint32_t feId; + getFrontendIdByType(frontendConf.type, feId); + ASSERT_TRUE(feId != INVALID_ID); + ASSERT_TRUE(openFrontendById(feId)); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(scanFrontend(frontendConf, scanType)); + ASSERT_TRUE(stopScanFrontend()); + ASSERT_TRUE(closeFrontend()); +} +/*================================== End Test Module ==================================*/ + /*=============================== Start Helper Functions ===============================*/ FilterEventType TunerHidlTest::getFilterEventType(DemuxFilterType type) { FilterEventType eventType = FilterEventType::UNDEFINED; @@ -1403,151 +1443,49 @@ FilterEventType TunerHidlTest::getFilterEventType(DemuxFilterType type) { /******************************** Start Test Entry **********************************/ /*============================== Start Frontend Tests ==============================*/ -TEST_P(TunerHidlTest, getFrontendIds) { - description("Get Frontend ids and verify frontends exist"); - ASSERT_TRUE(getFrontendIds()); - ASSERT_TRUE(mFeIds.size() > 0); -} - -TEST_P(TunerHidlTest, openFrontend) { - description("Open all the existing Frontends and close them"); - ASSERT_TRUE(getFrontendIds()); - ASSERT_TRUE(mFeIds.size() > 0); - - for (size_t i = 0; i < mFeIds.size(); i++) { - ASSERT_TRUE(openFrontend(mFeIds[i])); - ASSERT_TRUE(closeFrontend()); - } -} - TEST_P(TunerHidlTest, TuneFrontend) { description("Tune one Frontend with specific setting and check Lock event"); - ASSERT_TRUE(getFrontendIds()); - ASSERT_TRUE(mFeIds.size() > 0); - for (size_t i = 0; i < mFeIds.size(); i++) { - ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendArray[DVBT].type) { - continue; - } - ASSERT_TRUE(openFrontend(mFeIds[i])); - ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(tuneFrontend(frontendArray[DVBT])); - ASSERT_TRUE(stopTuneFrontend()); - ASSERT_TRUE(closeFrontend()); - break; - } + uint32_t feId; + getFrontendIdByType(frontendArray[DVBT].type, feId); + ASSERT_TRUE(feId != INVALID_ID); + ASSERT_TRUE(openFrontendById(feId)); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(tuneFrontend(frontendArray[DVBT])); + ASSERT_TRUE(stopTuneFrontend()); + ASSERT_TRUE(closeFrontend()); } TEST_P(TunerHidlTest, AutoScanFrontend) { description("Run an auto frontend scan with specific setting and check lock scanMessage"); - ASSERT_TRUE(getFrontendIds()); - ASSERT_TRUE(mFeIds.size() > 0); - - for (size_t i = 0; i < mFeIds.size(); i++) { - ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendScanArray[SCAN_DVBT].type) { - continue; - } - ASSERT_TRUE(openFrontend(mFeIds[i])); - ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(scanFrontend(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_AUTO)); - ASSERT_TRUE(stopScanFrontend()); - ASSERT_TRUE(closeFrontend()); - break; - } + scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_AUTO); } TEST_P(TunerHidlTest, BlindScanFrontend) { description("Run an blind frontend scan with specific setting and check lock scanMessage"); - ASSERT_TRUE(getFrontendIds()); - ASSERT_TRUE(mFeIds.size() > 0); - - for (size_t i = 0; i < mFeIds.size(); i++) { - ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendScanArray[SCAN_DVBT].type) { - continue; - } - ASSERT_TRUE(openFrontend(mFeIds[i])); - ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(scanFrontend(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_BLIND)); - ASSERT_TRUE(stopScanFrontend()); - ASSERT_TRUE(closeFrontend()); - break; - } + scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_BLIND); } /*=============================== End Frontend Tests ===============================*/ /*============================ Start Demux/Filter Tests ============================*/ -TEST_P(TunerHidlTest, OpenDemuxWithFrontendDataSource) { - description("Open Demux with a Frontend as its data source."); - ASSERT_TRUE(getFrontendIds()); - ASSERT_TRUE(mFeIds.size() > 0); - - for (size_t i = 0; i < mFeIds.size(); i++) { - ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendArray[DVBT].type) { - continue; - } - ASSERT_TRUE(openFrontend(mFeIds[i])); - ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(openDemux()); - ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i])); - ASSERT_TRUE(closeDemux()); - ASSERT_TRUE(closeFrontend()); - break; - } -} - -TEST_P(TunerHidlTest, OpenFilterInDemux) { - description("Open a filter in Demux."); - ASSERT_TRUE(getFrontendIds()); - ASSERT_TRUE(mFeIds.size() > 0); - - for (size_t i = 0; i < mFeIds.size(); i++) { - ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendArray[DVBT].type) { - continue; - } - ASSERT_TRUE(openFrontend(mFeIds[i])); - ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(openDemux()); - ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i])); - ASSERT_TRUE(openFilterInDemux(filterArray[TS_VIDEO0].type)); - uint32_t filterId; - ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); - ASSERT_TRUE(closeFilter(filterId)); - ASSERT_TRUE(closeDemux()); - ASSERT_TRUE(closeFrontend()); - break; - } -} - TEST_P(TunerHidlTest, StartFilterInDemux) { description("Open and start a filter in Demux."); - ASSERT_TRUE(getFrontendIds()); - ASSERT_TRUE(mFeIds.size() > 0); - - for (size_t i = 0; i < mFeIds.size(); i++) { - ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendArray[DVBT].type) { - continue; - } - ASSERT_TRUE(openFrontend(mFeIds[i])); - ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(openDemux()); - ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i])); - ASSERT_TRUE(openFilterInDemux(filterArray[TS_VIDEO0].type)); - uint32_t filterId; - ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); - ASSERT_TRUE(configFilter(filterArray[TS_VIDEO0].setting, filterId)); - ASSERT_TRUE(getFilterMQDescriptor(filterId)); - ASSERT_TRUE(startFilter(filterId)); - ASSERT_TRUE(stopFilter(filterId)); - ASSERT_TRUE(closeFilter(filterId)); - ASSERT_TRUE(closeDemux()); - ASSERT_TRUE(closeFrontend()); - break; - } + uint32_t feId; + getFrontendIdByType(frontendArray[DVBT].type, feId); + ASSERT_TRUE(feId != INVALID_ID); + ASSERT_TRUE(openFrontendById(feId)); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(openDemux()); + ASSERT_TRUE(setDemuxFrontendDataSource(feId)); + ASSERT_TRUE(openFilterInDemux(filterArray[TS_VIDEO0].type)); + uint32_t filterId; + ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); + ASSERT_TRUE(configFilter(filterArray[TS_VIDEO0].setting, filterId)); + ASSERT_TRUE(getFilterMQDescriptor(filterId)); + ASSERT_TRUE(startFilter(filterId)); + ASSERT_TRUE(stopFilter(filterId)); + ASSERT_TRUE(closeFilter(filterId)); + ASSERT_TRUE(closeDemux()); + ASSERT_TRUE(closeFrontend()); } /*============================ End Demux/Filter Tests ============================*/ @@ -1569,64 +1507,28 @@ TEST_P(TunerHidlTest, CloseDescrambler) { /*============================== Start Data Flow Tests ==============================*/ TEST_P(TunerHidlTest, BroadcastDataFlowVideoFilterTest) { description("Test Video Filter functionality in Broadcast use case."); - ASSERT_TRUE(getFrontendIds()); - ASSERT_TRUE(mFeIds.size() > 0); - - for (size_t i = 0; i < mFeIds.size(); i++) { - ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendArray[DVBT].type) { - continue; - } - broadcastFilterTest(TS_VIDEO1, mFeIds[i]); - break; - } + broadcastSingleFilterTest(filterArray[TS_VIDEO1], frontendArray[DVBS]); } TEST_P(TunerHidlTest, BroadcastDataFlowAudioFilterTest) { description("Test Audio Filter functionality in Broadcast use case."); - ASSERT_TRUE(getFrontendIds()); - ASSERT_TRUE(mFeIds.size() > 0); - - for (size_t i = 0; i < mFeIds.size(); i++) { - ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendArray[DVBT].type) { - continue; - } - broadcastFilterTest(TS_AUDIO0, mFeIds[i]); - break; - } + broadcastSingleFilterTest(filterArray[TS_AUDIO0], frontendArray[DVBS]); } TEST_P(TunerHidlTest, BroadcastDataFlowTsFilterTest) { description("Test TS Filter functionality in Broadcast use case."); - ASSERT_TRUE(getFrontendIds()); - ASSERT_TRUE(mFeIds.size() > 0); - - for (size_t i = 0; i < mFeIds.size(); i++) { - ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendArray[DVBT].type) { - continue; - } - broadcastFilterTest(TS_TS0, mFeIds[i]); - break; - } + broadcastSingleFilterTest(filterArray[TS_TS0], frontendArray[DVBS]); } TEST_P(TunerHidlTest, BroadcastDataFlowSectionFilterTest) { description("Test Section Filter functionality in Broadcast use case."); - ASSERT_TRUE(getFrontendIds()); - ASSERT_TRUE(mFeIds.size() > 0); - - for (size_t i = 0; i < mFeIds.size(); i++) { - ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendArray[DVBT].type) { - continue; - } - broadcastFilterTest(TS_SECTION0, mFeIds[i]); - break; - } + broadcastSingleFilterTest(filterArray[TS_SECTION0], frontendArray[DVBS]); } +TEST_P(TunerHidlTest, IonBufferTest) { + description("Test the av filter data bufferring."); + broadcastSingleFilterTest(filterArray[TS_VIDEO0], frontendArray[DVBS]); +} /* * TODO: re-enable the tests after finalizing the testing stream. */ @@ -1710,39 +1612,6 @@ TEST_P(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) { ASSERT_TRUE(recordDataFlowTest(filterConf, recordSetting, goldenOutputFiles)); }*/ - -TEST_P(TunerHidlTest, AvBufferTest) { - description("Test the av filter data bufferring."); - - ASSERT_TRUE(getFrontendIds()); - ASSERT_TRUE(mFeIds.size() > 0); - - for (size_t i = 0; i < mFeIds.size(); i++) { - ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != frontendArray[DVBS].type) { - continue; - } - ASSERT_TRUE(openFrontend(mFeIds[i])); - ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(openDemux()); - ASSERT_TRUE(openFilterInDemux(filterArray[TS_VIDEO0].type)); - uint32_t filterId; - ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); - ASSERT_TRUE(configFilter(filterArray[TS_VIDEO0].setting, filterId)); - ASSERT_TRUE(startFilter(filterId)); - ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i])); - // tune test - ASSERT_TRUE(tuneFrontend(frontendArray[DVBS])); - // broadcast data flow test - ASSERT_TRUE(broadcastDataFlowTest(goldenOutputFiles)); - ASSERT_TRUE(stopTuneFrontend()); - ASSERT_TRUE(stopFilter(filterId)); - ASSERT_TRUE(closeFilter(filterId)); - ASSERT_TRUE(closeDemux()); - ASSERT_TRUE(closeFrontend()); - break; - } -} /*============================== End Data Flow Tests ==============================*/ /******************************** End Test Entry **********************************/ } // namespace From 37cd4646ac087f8145fcc666e288400856124d64 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Mon, 6 Apr 2020 16:23:10 -0700 Subject: [PATCH 0824/1022] Move virtualization-specific proto definition to /device/google/trout Test: build Bug: 148816426 Change-Id: I5ea4a078d2733d0b5fc370211389ebc0488898ef --- .../default/impl/vhal_v2_0/proto/Android.bp | 29 ---------- .../impl/vhal_v2_0/proto/VehicleServer.proto | 57 ------------------- 2 files changed, 86 deletions(-) delete mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto 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 9784f751f2..31ba8ab18a 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 @@ -40,29 +40,6 @@ filegroup { ], } -cc_library_static { - name: "android.hardware.automotive.vehicle@2.0-grpc", - vendor: true, - include_dirs: [ - "external/protobuf/src", - ], - generated_headers: [ - "DefaultVehicleHalProtoStub_h", - ], - export_generated_headers: [ - "DefaultVehicleHalProtoStub_h", - ], - generated_sources: [ - "DefaultVehicleHalProtoStub_cc", - ], - shared_libs: [ - "libgrpc++_unsecure", - ], - cflags: [ - "-Wno-unused-parameter", - ], -} - genrule { name: "DefaultVehicleHalProtoStub_h", tools: [ @@ -72,13 +49,10 @@ genrule { cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)", srcs: [ "VehicleHalProto.proto", - "VehicleServer.proto", ], out: [ "VehicleHalProto.pb.h", "VehicleHalProto.grpc.pb.h", - "VehicleServer.pb.h", - "VehicleServer.grpc.pb.h", ], } @@ -91,12 +65,9 @@ genrule { cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)", srcs: [ "VehicleHalProto.proto", - "VehicleServer.proto", ], out: [ "VehicleHalProto.pb.cc", "VehicleHalProto.grpc.pb.cc", - "VehicleServer.pb.cc", - "VehicleServer.grpc.pb.cc", ], } diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto deleted file mode 100644 index 6f71d654a7..0000000000 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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. - */ - -syntax = "proto3"; - -package vhal_proto; - -import "google/protobuf/empty.proto"; -import "VehicleHalProto.proto"; - -// correspond to StatusCode defined in types.hal -enum VehicleHalStatusCode { - OK = 0; - TRY_AGAIN = 1; - INVALID_ARG = 2; - NOT_AVAILABLE = 3; - ACCESS_DENIED = 4; - INTERNAL_ERROR = 5; -} - -message VehicleHalCallStatus { - VehicleHalStatusCode status_code = 1; -} - -message WrappedVehiclePropValue { - VehiclePropValue value = 1; - // An indicator on whether we should update the status of the property - // - true: if the value is generated by (emulated/real) car, or; - // if the value is injected to 'fake' a on car event (for debugging purpose) - // - false: if the value is set by VHal (public interface), since Android - // cannot change status of property on a real car - bool update_status = 2; -} - -service VehicleServer { - rpc GetAllPropertyConfig(google.protobuf.Empty) returns (stream VehiclePropConfig) {} - - // Change the property value of the vehicle - rpc SetProperty(WrappedVehiclePropValue) returns (VehicleHalCallStatus) {} - - // Start a vehicle property value stream - rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream WrappedVehiclePropValue) {} -} - From 6d586607cd5726ea10559379ce6a510159c1fa0c Mon Sep 17 00:00:00 2001 From: Nazanin Date: Thu, 9 Apr 2020 13:26:41 -0700 Subject: [PATCH 0825/1022] Remove requirement for VtsHalRadioV1_3 tests for sim to be present Bug: 153293861 Test: run vts -m VtsHalRadioV1_3Target Change-Id: Idb1067e757d4abadb2142627b88f775a685d0c02 --- radio/1.3/vts/functional/radio_hidl_hal_test.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/radio/1.3/vts/functional/radio_hidl_hal_test.cpp b/radio/1.3/vts/functional/radio_hidl_hal_test.cpp index 4581350e9b..c6e5550995 100644 --- a/radio/1.3/vts/functional/radio_hidl_hal_test.cpp +++ b/radio/1.3/vts/functional/radio_hidl_hal_test.cpp @@ -38,9 +38,6 @@ void RadioHidlTest_v1_3::SetUp() { EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_3->rspInfo.type); EXPECT_EQ(serial, radioRsp_v1_3->rspInfo.serial); EXPECT_EQ(RadioError::NONE, radioRsp_v1_3->rspInfo.error); - - /* Enforce Vts Testing with Sim Status Present only. */ - EXPECT_EQ(CardState::PRESENT, cardStatus.base.cardState); } /* From b642700c7ff54e84864df50f0337c43e99808590 Mon Sep 17 00:00:00 2001 From: Xusong Wang Date: Thu, 9 Apr 2020 14:26:54 -0700 Subject: [PATCH 0826/1022] Remove BLOB AHWB tests from 1.2 VTS. Bug: 153282844 Test: 1.2 VTS Change-Id: I866fe1388a64a36372f90c60fef340d2fe4c8682 --- neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp index 35275b4e61..56f3c0b7e2 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp @@ -350,7 +350,7 @@ void EvaluatePreparedModel(const sp& preparedModel, const TestMo outputTypesList = {OutputType::FULLY_SPECIFIED}; measureTimingList = {MeasureTiming::NO, MeasureTiming::YES}; executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST}; - memoryTypeList = {MemoryType::ASHMEM, MemoryType::BLOB_AHWB}; + memoryTypeList = {MemoryType::ASHMEM}; } for (const OutputType outputType : outputTypesList) { From a6491f8adfe0ee0b2a3e1f4ca3c141fc21b20220 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Wed, 8 Apr 2020 15:37:02 -0700 Subject: [PATCH 0827/1022] health 2.0 VTS: require GTEST_SKIP to be defined This is a hack to support the test in Android P. Now that gtest has been updated, we no longer need this hack. Test: run it Bug: 118852225 Bug: 136717180 Change-Id: I81802b6fae0dc7839aa9fd1dd40cb881ff4eefdb (cherry picked from commit 9fb96fa4b0b85e3b94e7a28abab9c97c3d6123b1) Merged-In: I81802b6fae0dc7839aa9fd1dd40cb881ff4eefdb --- .../functional/VtsHalHealthV2_0TargetTest.cpp | 44 ------------------- 1 file changed, 44 deletions(-) diff --git a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp index 352a990af2..012988387e 100644 --- a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp +++ b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp @@ -35,39 +35,6 @@ using ::testing::AssertionSuccess; DEFINE_bool(force, false, "Force test healthd even when the default instance is present."); -// If GTEST_SKIP is not implemented, use our own skipping mechanism -#ifndef GTEST_SKIP -static std::mutex gSkippedTestsMutex; -static std::set gSkippedTests; -static std::string GetCurrentTestName() { - const auto& info = ::testing::UnitTest::GetInstance()->current_test_info(); -#ifdef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ - std::string test_suite = info->test_suite_name(); -#else - std::string test_suite = info->test_case_name(); -#endif - return test_suite + "." + info->name(); -} - -#define GTEST_SKIP() \ - do { \ - std::unique_lock lock(gSkippedTestsMutex); \ - gSkippedTests.insert(GetCurrentTestName()); \ - return; \ - } while (0) - -#define SKIP_IF_SKIPPED() \ - do { \ - std::unique_lock lock(gSkippedTestsMutex); \ - if (gSkippedTests.find(GetCurrentTestName()) != gSkippedTests.end()) { \ - std::cerr << "[ SKIPPED ] " << GetCurrentTestName() << std::endl; \ - return; \ - } \ - } while (0) -#else -#define SKIP_IF_SKIPPED() -#endif - namespace android { namespace hardware { namespace health { @@ -141,7 +108,6 @@ AssertionResult isAllOk(const Return& r) { * unregisterCallback, and update. */ TEST_P(HealthHidlTest, Callbacks) { - SKIP_IF_SKIPPED(); using namespace std::chrono_literals; sp firstCallback = new Callback(); sp secondCallback = new Callback(); @@ -178,7 +144,6 @@ TEST_P(HealthHidlTest, Callbacks) { } TEST_P(HealthHidlTest, UnregisterNonExistentCallback) { - SKIP_IF_SKIPPED(); sp callback = new Callback(); auto ret = mHealth->unregisterCallback(callback); ASSERT_OK(ret); @@ -263,7 +228,6 @@ bool verifyHealthInfo(const HealthInfo& health_info) { * Tests the values returned by getChargeCounter() from interface IHealth. */ TEST_P(HealthHidlTest, getChargeCounter) { - SKIP_IF_SKIPPED(); EXPECT_OK(mHealth->getChargeCounter([](auto result, auto value) { EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value > 0); })); @@ -273,7 +237,6 @@ TEST_P(HealthHidlTest, getChargeCounter) { * Tests the values returned by getCurrentNow() from interface IHealth. */ TEST_P(HealthHidlTest, getCurrentNow) { - SKIP_IF_SKIPPED(); EXPECT_OK(mHealth->getCurrentNow([](auto result, auto value) { EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT32_MIN); })); @@ -283,7 +246,6 @@ TEST_P(HealthHidlTest, getCurrentNow) { * Tests the values returned by getCurrentAverage() from interface IHealth. */ TEST_P(HealthHidlTest, getCurrentAverage) { - SKIP_IF_SKIPPED(); EXPECT_OK(mHealth->getCurrentAverage([](auto result, auto value) { EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT32_MIN); })); @@ -293,7 +255,6 @@ TEST_P(HealthHidlTest, getCurrentAverage) { * Tests the values returned by getCapacity() from interface IHealth. */ TEST_P(HealthHidlTest, getCapacity) { - SKIP_IF_SKIPPED(); EXPECT_OK(mHealth->getCapacity([](auto result, auto value) { EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), 0 <= value && value <= 100); })); @@ -303,7 +264,6 @@ TEST_P(HealthHidlTest, getCapacity) { * Tests the values returned by getEnergyCounter() from interface IHealth. */ TEST_P(HealthHidlTest, getEnergyCounter) { - SKIP_IF_SKIPPED(); EXPECT_OK(mHealth->getEnergyCounter([](auto result, auto value) { EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT64_MIN); })); @@ -313,7 +273,6 @@ TEST_P(HealthHidlTest, getEnergyCounter) { * Tests the values returned by getChargeStatus() from interface IHealth. */ TEST_P(HealthHidlTest, getChargeStatus) { - SKIP_IF_SKIPPED(); EXPECT_OK(mHealth->getChargeStatus([](auto result, auto value) { EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyEnum(value)); })); @@ -323,7 +282,6 @@ TEST_P(HealthHidlTest, getChargeStatus) { * Tests the values returned by getStorageInfo() from interface IHealth. */ TEST_P(HealthHidlTest, getStorageInfo) { - SKIP_IF_SKIPPED(); EXPECT_OK(mHealth->getStorageInfo([](auto result, auto& value) { EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyStorageInfo(value)); })); @@ -333,7 +291,6 @@ TEST_P(HealthHidlTest, getStorageInfo) { * Tests the values returned by getDiskStats() from interface IHealth. */ TEST_P(HealthHidlTest, getDiskStats) { - SKIP_IF_SKIPPED(); EXPECT_OK(mHealth->getDiskStats([](auto result, auto& value) { EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), true); })); @@ -343,7 +300,6 @@ TEST_P(HealthHidlTest, getDiskStats) { * Tests the values returned by getHealthInfo() from interface IHealth. */ TEST_P(HealthHidlTest, getHealthInfo) { - SKIP_IF_SKIPPED(); EXPECT_OK(mHealth->getHealthInfo([](auto result, auto& value) { EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyHealthInfo(value)); })); From fa81977e1a072a42fcdfd1515eee0a13cdd59f43 Mon Sep 17 00:00:00 2001 From: Hayden Gomes Date: Thu, 2 Apr 2020 13:40:22 -0700 Subject: [PATCH 0828/1022] Adding --request command to default AudioControl HAL Adding a lshal command for requesting focus Bug: 148098383 Test: adb root && adb shell lshal debug android.hardware.automotive.audiocontrol@2.0::IAudioControl/default --request 1 0 1 Change-Id: I51f78ff495d81f03903515a9151c9ddd3350ee96 --- .../audiocontrol/2.0/default/AudioControl.cpp | 74 ++++++++++++++++++- .../audiocontrol/2.0/default/AudioControl.h | 4 + 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/automotive/audiocontrol/2.0/default/AudioControl.cpp b/automotive/audiocontrol/2.0/default/AudioControl.cpp index eac3514960..7a121f5d3f 100644 --- a/automotive/audiocontrol/2.0/default/AudioControl.cpp +++ b/automotive/audiocontrol/2.0/default/AudioControl.cpp @@ -16,12 +16,16 @@ #include "AudioControl.h" -#include -#include -#include - #include +#include +#include +#include + +#include +#include +#include + #include "CloseHandle.h" namespace android::hardware::automotive::audiocontrol::V2_0::implementation { @@ -104,6 +108,8 @@ void AudioControl::cmdDump(int fd, const hidl_vec& options) { std::string option = options[0]; if (EqualsIgnoreCase(option, "--help")) { cmdHelp(fd); + } else if (EqualsIgnoreCase(option, "--request")) { + cmdRequestFocus(fd, options); } else { dprintf(fd, "Invalid option: %s\n", option.c_str()); } @@ -121,6 +127,66 @@ void AudioControl::cmdHelp(int fd) const { dprintf(fd, "Usage: \n\n"); dprintf(fd, "[no args]: dumps focus listener status\n"); dprintf(fd, "--help: shows this help\n"); + dprintf(fd, + "--request : requests audio focus for specified " + "usage (int), audio zone ID (int), and focus gain type (int)\n"); +} + +void AudioControl::cmdRequestFocus(int fd, const hidl_vec& options) { + if (!checkCallerHasWritePermissions(fd) || !checkArgumentsSize(fd, options, 3)) return; + + hidl_bitfield usage; + if (!safelyParseInt(options[1], &usage)) { + dprintf(fd, "Non-integer usage provided with request: %s\n", options[1].c_str()); + return; + } + int zoneId; + if (!safelyParseInt(options[2], &zoneId)) { + dprintf(fd, "Non-integer zoneId provided with request: %s\n", options[2].c_str()); + return; + } + hidl_bitfield focusGain; + if (!safelyParseInt(options[3], &focusGain)) { + dprintf(fd, "Non-integer focusGain provided with request: %s\n", options[3].c_str()); + return; + } + + if (mFocusListener == nullptr) { + dprintf(fd, "Unable to request focus - no focus listener registered\n"); + return; + } + + mFocusListener->requestAudioFocus(usage, zoneId, focusGain); + dprintf(fd, "Requested focus for usage %d, zoneId %d, and focusGain %d\n", usage, zoneId, + focusGain); +} + +bool AudioControl::checkCallerHasWritePermissions(int fd) { + // Double check that's only called by root - it should be be blocked at the HIDL debug() level, + // but it doesn't hurt to make sure... + if (hardware::IPCThreadState::self()->getCallingUid() != AID_ROOT) { + dprintf(fd, "Must be root\n"); + return false; + } + return true; +} + +bool AudioControl::checkArgumentsSize(int fd, const hidl_vec& options, + size_t expectedSize) { + // options includes the command, so reducing size by one + size_t size = options.size() - 1; + if (size == expectedSize) { + return true; + } + dprintf(fd, "Invalid number of arguments: required %zu, got %zu\n", expectedSize, size); + return false; +} + +bool AudioControl::safelyParseInt(std::string s, int* out) { + if (!android::base::ParseInt(s, out)) { + return false; + } + return true; } } // namespace android::hardware::automotive::audiocontrol::V2_0::implementation diff --git a/automotive/audiocontrol/2.0/default/AudioControl.h b/automotive/audiocontrol/2.0/default/AudioControl.h index 6a3f21b55b..1cd7cbc5de 100644 --- a/automotive/audiocontrol/2.0/default/AudioControl.h +++ b/automotive/audiocontrol/2.0/default/AudioControl.h @@ -43,10 +43,14 @@ class AudioControl : public IAudioControl { private: sp mFocusListener; + static bool checkArgumentsSize(int fd, const hidl_vec& options, size_t minSize); + static bool checkCallerHasWritePermissions(int fd); static bool isValidValue(float value); + static bool safelyParseInt(std::string s, int* out); void cmdDump(int fd, const hidl_vec& options); void cmdHelp(int fd) const; + void cmdRequestFocus(int fd, const hidl_vec& options); void dump(int fd); }; From c4199eabf83bacc608c188a30d009b7ff7396360 Mon Sep 17 00:00:00 2001 From: Hayden Gomes Date: Thu, 2 Apr 2020 14:29:00 -0700 Subject: [PATCH 0829/1022] Adding a lshal command for abandoning focus Bug: 148098383 Test: adb shell lshal debug android.hardware.automotive.audiocontrol@2.0::IAudioControl/default --abandon 1 0 Change-Id: I4bec12ec3ae0fc6b73de8b823501f0f478d75d94 --- .../audiocontrol/2.0/default/AudioControl.cpp | 28 +++++++++++++++++++ .../audiocontrol/2.0/default/AudioControl.h | 1 + 2 files changed, 29 insertions(+) diff --git a/automotive/audiocontrol/2.0/default/AudioControl.cpp b/automotive/audiocontrol/2.0/default/AudioControl.cpp index 7a121f5d3f..5bde8396f2 100644 --- a/automotive/audiocontrol/2.0/default/AudioControl.cpp +++ b/automotive/audiocontrol/2.0/default/AudioControl.cpp @@ -110,6 +110,8 @@ void AudioControl::cmdDump(int fd, const hidl_vec& options) { cmdHelp(fd); } else if (EqualsIgnoreCase(option, "--request")) { cmdRequestFocus(fd, options); + } else if (EqualsIgnoreCase(option, "--abandon")) { + cmdAbandonFocus(fd, options); } else { dprintf(fd, "Invalid option: %s\n", option.c_str()); } @@ -130,6 +132,9 @@ void AudioControl::cmdHelp(int fd) const { dprintf(fd, "--request : requests audio focus for specified " "usage (int), audio zone ID (int), and focus gain type (int)\n"); + dprintf(fd, + "--abandon : abandons audio focus for specified usage (int) and " + "audio zone ID (int)\n"); } void AudioControl::cmdRequestFocus(int fd, const hidl_vec& options) { @@ -161,6 +166,29 @@ void AudioControl::cmdRequestFocus(int fd, const hidl_vec& options) focusGain); } +void AudioControl::cmdAbandonFocus(int fd, const hidl_vec& options) { + if (!checkCallerHasWritePermissions(fd) || !checkArgumentsSize(fd, options, 2)) return; + + hidl_bitfield usage; + if (!safelyParseInt(options[1], &usage)) { + dprintf(fd, "Non-integer usage provided with abandon: %s\n", options[1].c_str()); + return; + } + int zoneId; + if (!safelyParseInt(options[2], &zoneId)) { + dprintf(fd, "Non-integer zoneId provided with abandon: %s\n", options[2].c_str()); + return; + } + + if (mFocusListener == nullptr) { + dprintf(fd, "Unable to abandon focus - no focus listener registered\n"); + return; + } + + mFocusListener->abandonAudioFocus(usage, zoneId); + dprintf(fd, "Abandoned focus for usage %d and zoneId %d\n", usage, zoneId); +} + bool AudioControl::checkCallerHasWritePermissions(int fd) { // Double check that's only called by root - it should be be blocked at the HIDL debug() level, // but it doesn't hurt to make sure... diff --git a/automotive/audiocontrol/2.0/default/AudioControl.h b/automotive/audiocontrol/2.0/default/AudioControl.h index 1cd7cbc5de..d66458ec05 100644 --- a/automotive/audiocontrol/2.0/default/AudioControl.h +++ b/automotive/audiocontrol/2.0/default/AudioControl.h @@ -51,6 +51,7 @@ class AudioControl : public IAudioControl { void cmdDump(int fd, const hidl_vec& options); void cmdHelp(int fd) const; void cmdRequestFocus(int fd, const hidl_vec& options); + void cmdAbandonFocus(int fd, const hidl_vec& options); void dump(int fd); }; From 20746053a5a5635bd2d12ed75f81fce7ce3f3427 Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Thu, 9 Apr 2020 23:44:38 +0000 Subject: [PATCH 0830/1022] Add biometrics.fingerprint@2.2 to the compatibility matrix Bug: 153012763 Test: build blueline-userdebug Change-Id: I209db8a74665df98b4923cbfa11b2b2c9d6dabfa --- compatibility_matrices/compatibility_matrix.5.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compatibility_matrices/compatibility_matrix.5.xml b/compatibility_matrices/compatibility_matrix.5.xml index 30c15721c0..783ef8c582 100644 --- a/compatibility_matrices/compatibility_matrix.5.xml +++ b/compatibility_matrices/compatibility_matrix.5.xml @@ -94,7 +94,7 @@ android.hardware.biometrics.fingerprint - 2.1 + 2.1-2 IBiometricsFingerprint default From b0c1bbb3546ba8fa6dd64808381e2712a08e454b Mon Sep 17 00:00:00 2001 From: shubang Date: Mon, 6 Apr 2020 22:41:33 -0700 Subject: [PATCH 0831/1022] Add frontend caps for CTS Bug: 150952758 Test: atest android.media.tv.tuner.cts.TunerTest Change-Id: I5bf1fbf24ef6375b08554617bcd05792e7e9e521 --- tv/tuner/1.0/default/Tuner.cpp | 57 ++++++++++++++++++++++++++-------- tv/tuner/1.0/default/Tuner.h | 1 + 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp index 6f9a5cf016..e39333ce3e 100644 --- a/tv/tuner/1.0/default/Tuner.cpp +++ b/tv/tuner/1.0/default/Tuner.cpp @@ -46,6 +46,48 @@ Tuner::Tuner() { mFrontends[5] = new Frontend(FrontendType::ISDBT, 5, this); mFrontends[6] = new Frontend(FrontendType::ANALOG, 6, this); mFrontends[7] = new Frontend(FrontendType::ATSC, 7, this); + + FrontendInfo::FrontendCapabilities caps; + mFrontendCaps.resize(mFrontendSize); + caps = FrontendInfo::FrontendCapabilities(); + caps.dvbtCaps(FrontendDvbtCapabilities()); + mFrontendCaps[0] = caps; + + caps = FrontendInfo::FrontendCapabilities(); + caps.atscCaps(FrontendAtscCapabilities()); + mFrontendCaps[1] = caps; + + caps = FrontendInfo::FrontendCapabilities(); + caps.dvbcCaps(FrontendDvbcCapabilities()); + mFrontendCaps[2] = caps; + + caps = FrontendInfo::FrontendCapabilities(); + caps.dvbsCaps(FrontendDvbsCapabilities()); + mFrontendCaps[3] = caps; + + caps = FrontendInfo::FrontendCapabilities(); + caps.dvbtCaps(FrontendDvbtCapabilities()); + mFrontendCaps[4] = caps; + + caps = FrontendInfo::FrontendCapabilities(); + FrontendIsdbtCapabilities isdbtCaps{ + .modeCap = FrontendIsdbtMode::MODE_1 | FrontendIsdbtMode::MODE_2, + .bandwidthCap = (unsigned int)FrontendIsdbtBandwidth::BANDWIDTH_6MHZ, + .modulationCap = (unsigned int)FrontendIsdbtModulation::MOD_16QAM, + // ISDBT shares coderate and guard interval with DVBT + .coderateCap = FrontendDvbtCoderate::CODERATE_4_5 | FrontendDvbtCoderate::CODERATE_6_7, + .guardIntervalCap = (unsigned int)FrontendDvbtGuardInterval::INTERVAL_1_128, + }; + caps.isdbtCaps(isdbtCaps); + mFrontendCaps[5] = caps; + + caps = FrontendInfo::FrontendCapabilities(); + caps.analogCaps(FrontendAnalogCapabilities()); + mFrontendCaps[6] = caps; + + caps = FrontendInfo::FrontendCapabilities(); + caps.atscCaps(FrontendAtscCapabilities()); + mFrontendCaps[7] = caps; } Tuner::~Tuner() {} @@ -129,20 +171,9 @@ Return Tuner::getFrontendInfo(FrontendId frontendId, getFrontendInfo_cb _h FrontendStatusType::LAYER_ERROR, FrontendStatusType::ATSC3_PLP_INFO, }; - FrontendInfo::FrontendCapabilities frontendCaps; - FrontendIsdbtCapabilities isdbtCaps{ - .modeCap = FrontendIsdbtMode::MODE_1 | FrontendIsdbtMode::MODE_2, - .bandwidthCap = (unsigned int)FrontendIsdbtBandwidth::BANDWIDTH_6MHZ, - .modulationCap = (unsigned int)FrontendIsdbtModulation::MOD_16QAM, - // ISDBT shares coderate and guard interval with DVBT - .coderateCap = - FrontendDvbtCoderate::CODERATE_4_5 | FrontendDvbtCoderate::CODERATE_6_7, - .guardIntervalCap = (unsigned int)FrontendDvbtGuardInterval::INTERVAL_1_128, - }; - frontendCaps.isdbtCaps(isdbtCaps); // assign randomly selected values for testing. info = { - .type = FrontendType::ISDBT, + .type = mFrontends[frontendId]->getFrontendType(), .minFrequency = 139, .maxFrequency = 1139, .minSymbolRate = 45, @@ -150,7 +181,7 @@ Return Tuner::getFrontendInfo(FrontendId frontendId, getFrontendInfo_cb _h .acquireRange = 30, .exclusiveGroupId = 57, .statusCaps = statusCaps, - .frontendCaps = frontendCaps, + .frontendCaps = mFrontendCaps[frontendId], }; break; } diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h index 7a8a9198ce..d17b5aeb64 100644 --- a/tv/tuner/1.0/default/Tuner.h +++ b/tv/tuner/1.0/default/Tuner.h @@ -68,6 +68,7 @@ class Tuner : public ITuner { virtual ~Tuner(); // Static mFrontends array to maintain local frontends information vector> mFrontends; + vector mFrontendCaps; std::map mFrontendToDemux; std::map> mDemuxes; // To maintain how many Frontends we have From 8261cac9e8e32323b1afa42ff2479de0808fd14a Mon Sep 17 00:00:00 2001 From: Hayden Gomes Date: Thu, 9 Apr 2020 16:15:46 -0700 Subject: [PATCH 0832/1022] Adding android_filesystem_config.h import Addressing outstanding todo in VehicleHalManager Bug: 148098383 Test: m vts and atest android.hardware.automotive.vehicle@2.0-manager-unit-tests Change-Id: I9a222077d0de91f8c7353c80d8a1aeff53cffa61 --- .../vehicle/2.0/default/common/src/VehicleHalManager.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp index 5bebd1e6a4..b09e9bfba0 100644 --- a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp +++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp @@ -27,14 +27,11 @@ #include #include - +#include #include #include "VehicleUtils.h" -// TODO: figure out how to include private/android_filesystem_config.h instead... -#define AID_ROOT 0 /* traditional unix root user */ - namespace android { namespace hardware { namespace automotive { From fe7701e227fc028cd1e69303f9237840d523388f Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Fri, 10 Apr 2020 01:19:32 +0000 Subject: [PATCH 0833/1022] Revert^2 "Modify the name of the SV interface to match VTS" Modify the name of the Surround View interface to match the one in VTS and the one in the default implementation. fc614a63faa49cdd5b00537ce2c78f25c0c51452 Bug: 150412555 Test: m -j Change-Id: Ie274e0501ce807bafe0211b6a8a9ba694e979341 --- compatibility_matrices/compatibility_matrix.5.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compatibility_matrices/compatibility_matrix.5.xml b/compatibility_matrices/compatibility_matrix.5.xml index 30c15721c0..ff4083ff33 100644 --- a/compatibility_matrices/compatibility_matrix.5.xml +++ b/compatibility_matrices/compatibility_matrix.5.xml @@ -72,7 +72,7 @@ android.hardware.automotive.sv 1.0 - ISurroundView + ISurroundViewService default From 059441bdd21edb72f15676be36b8dab736c22a9b Mon Sep 17 00:00:00 2001 From: Yichi Chen Date: Mon, 6 Apr 2020 17:58:12 +0800 Subject: [PATCH 0834/1022] gralloc4-vts: Correct plane layout test of RGBA_8888 and YCbCr_420 The patch enhanced the plane layout tests in verifyRGBA8888 and Lock_YCRCB_420_SP with considerations of sample increment and subsampling. Test: VtsHalGraphicsMapperV4_0 Bug: 150461327 Change-Id: I16fce5f29ec927de110cbaf5767e0b585d3c1919 --- .../VtsHalGraphicsMapperV4_0TargetTest.cpp | 80 +++++++++++++------ 1 file changed, 56 insertions(+), 24 deletions(-) diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 0689919ab5..8247ded1fe 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -107,7 +107,7 @@ class GraphicsMapperHidlTest ASSERT_NO_FATAL_FAILURE(decode(descriptorInfo, vec)); } - void verifyDummyDescriptorInfoPlaneLayouts(const std::vector& planeLayouts) { + void verifyRGBA8888PlaneLayouts(const std::vector& planeLayouts) { ASSERT_EQ(1, planeLayouts.size()); const auto& planeLayout = planeLayouts.front(); @@ -191,7 +191,7 @@ class GraphicsMapperHidlTest } void getAndroidYCbCr(const native_handle_t* bufferHandle, uint8_t* data, - android_ycbcr* outYCbCr) { + android_ycbcr* outYCbCr, int64_t* hSubsampling, int64_t* vSubsampling) { hidl_vec vec; ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec)); @@ -241,6 +241,14 @@ class GraphicsMapperHidlTest ASSERT_EQ(outYCbCr->chroma_step, sampleIncrementInBytes); } + if (*hSubsampling == 0 && *vSubsampling == 0) { + *hSubsampling = planeLayout.horizontalSubsampling; + *vSubsampling = planeLayout.verticalSubsampling; + } else { + ASSERT_EQ(*hSubsampling, planeLayout.horizontalSubsampling); + ASSERT_EQ(*vSubsampling, planeLayout.verticalSubsampling); + } + if (type == PlaneLayoutComponentType::CB) { ASSERT_EQ(nullptr, outYCbCr->cb); outYCbCr->cb = tmpData; @@ -268,8 +276,16 @@ class GraphicsMapperHidlTest } } - void verifyRGBA8888(uint8_t* data, uint32_t height, size_t strideInBytes, size_t widthInBytes, - uint32_t seed = 0) { + void verifyRGBA8888(const native_handle_t* bufferHandle, uint8_t* data, uint32_t height, + size_t strideInBytes, size_t widthInBytes, uint32_t seed = 0) { + 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)); + + verifyRGBA8888PlaneLayouts(planeLayouts); + for (uint32_t y = 0; y < height; y++) { for (size_t i = 0; i < widthInBytes; i++) { EXPECT_EQ(static_cast(y + seed), data[i]); @@ -534,7 +550,9 @@ TEST_P(GraphicsMapperHidlTest, LockUnlockBasic) { // lock again for reading ASSERT_NO_FATAL_FAILURE( data = static_cast(mGralloc->lock(bufferHandle, info.usage, region, fence))); - ASSERT_NO_FATAL_FAILURE(verifyRGBA8888(data, info.height, stride * 4, info.width * 4)); + + ASSERT_NO_FATAL_FAILURE( + verifyRGBA8888(bufferHandle, data, info.height, stride * 4, info.width * 4)); ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); if (fence >= 0) { @@ -542,9 +560,9 @@ TEST_P(GraphicsMapperHidlTest, LockUnlockBasic) { } } -TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_420_888) { +TEST_P(GraphicsMapperHidlTest, Lock_YCRCB_420_SP) { auto info = mDummyDescriptorInfo; - info.format = PixelFormat::YCBCR_420_888; + info.format = PixelFormat::YCRCB_420_SP; const native_handle_t* bufferHandle; uint32_t stride; @@ -560,7 +578,10 @@ TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_420_888) { data = static_cast(mGralloc->lock(bufferHandle, info.usage, region, fence))); android_ycbcr yCbCr; - ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(bufferHandle, data, &yCbCr)); + int64_t hSubsampling = 0; + int64_t vSubsampling = 0; + ASSERT_NO_FATAL_FAILURE( + getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling)); auto yData = static_cast(yCbCr.y); auto cbData = static_cast(yCbCr.cb); @@ -570,6 +591,10 @@ TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_420_888) { auto chromaStep = yCbCr.chroma_step; constexpr uint32_t kCbCrSubSampleFactor = 2; + ASSERT_EQ(crData + 1, cbData); + ASSERT_EQ(2, chromaStep); + ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling); + ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling); for (uint32_t y = 0; y < info.height; y++) { for (uint32_t x = 0; x < info.width; x++) { @@ -577,13 +602,15 @@ TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_420_888) { yData[yStride * y + x] = val; - if (y % kCbCrSubSampleFactor && x % kCbCrSubSampleFactor == 0) { - uint32_t subSampleX = x / kCbCrSubSampleFactor; - uint32_t subSampleY = y / kCbCrSubSampleFactor; - auto subSampleVal = static_cast(info.height * subSampleY + subSampleX); + if (y % vSubsampling == 0 && x % hSubsampling == 0) { + uint32_t subSampleX = x / hSubsampling; + uint32_t subSampleY = y / vSubsampling; + const auto subSampleOffset = cStride * subSampleY + chromaStep * subSampleX; + const auto subSampleVal = + static_cast(info.height * subSampleY + subSampleX); - cbData[cStride * subSampleY + chromaStep * subSampleX] = subSampleVal; - crData[cStride * subSampleY + chromaStep * subSampleX] = subSampleVal; + cbData[subSampleOffset] = subSampleVal; + crData[subSampleOffset] = subSampleVal + 1; } } } @@ -594,24 +621,28 @@ TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_420_888) { ASSERT_NO_FATAL_FAILURE( data = static_cast(mGralloc->lock(bufferHandle, info.usage, region, fence))); - ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(bufferHandle, data, &yCbCr)); + ASSERT_NO_FATAL_FAILURE( + getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling)); yData = static_cast(yCbCr.y); cbData = static_cast(yCbCr.cb); crData = static_cast(yCbCr.cr); + for (uint32_t y = 0; y < info.height; y++) { for (uint32_t x = 0; x < info.width; x++) { auto val = static_cast(info.height * y + x); EXPECT_EQ(val, yData[yStride * y + x]); - if (y % kCbCrSubSampleFactor == 0 && x % kCbCrSubSampleFactor == 0) { - uint32_t subSampleX = x / kCbCrSubSampleFactor; - uint32_t subSampleY = y / kCbCrSubSampleFactor; - auto subSampleVal = static_cast(info.height * subSampleY + subSampleX); + if (y % vSubsampling == 0 && x % hSubsampling == 0) { + uint32_t subSampleX = x / hSubsampling; + uint32_t subSampleY = y / vSubsampling; + const auto subSampleOffset = cStride * subSampleY + chromaStep * subSampleX; + const auto subSampleVal = + static_cast(info.height * subSampleY + subSampleX); - EXPECT_EQ(subSampleVal, cbData[cStride * subSampleY + chromaStep * subSampleX]); - EXPECT_EQ(subSampleVal, crData[cStride * subSampleY + chromaStep * subSampleX]); + EXPECT_EQ(subSampleVal, cbData[subSampleOffset]); + EXPECT_EQ(subSampleVal + 1, crData[subSampleOffset]); } } } @@ -744,7 +775,8 @@ TEST_P(GraphicsMapperHidlTest, FlushRereadBasic) { ASSERT_NO_FATAL_FAILURE(mGralloc->rereadLockedBuffer(readBufferHandle)); - ASSERT_NO_FATAL_FAILURE(verifyRGBA8888(readData, info.height, stride * 4, info.width * 4)); + ASSERT_NO_FATAL_FAILURE( + verifyRGBA8888(readBufferHandle, readData, info.height, stride * 4, info.width * 4)); ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(readBufferHandle)); if (fence >= 0) { @@ -1005,7 +1037,7 @@ TEST_P(GraphicsMapperHidlTest, GetPlaneLayouts) { std::vector planeLayouts; ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts)); - ASSERT_NO_FATAL_FAILURE(verifyDummyDescriptorInfoPlaneLayouts(planeLayouts)); + ASSERT_NO_FATAL_FAILURE(verifyRGBA8888PlaneLayouts(planeLayouts)); } /** @@ -1870,7 +1902,7 @@ TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPlaneLayouts) { if (ret == Error::NONE) { std::vector planeLayouts; ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts)); - ASSERT_NO_FATAL_FAILURE(verifyDummyDescriptorInfoPlaneLayouts(planeLayouts)); + ASSERT_NO_FATAL_FAILURE(verifyRGBA8888PlaneLayouts(planeLayouts)); } else { ASSERT_EQ(Error::UNSUPPORTED, ret); } From ddedfb31ff55bc12dd663f73f95bdb0423426063 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Thu, 9 Apr 2020 12:16:56 -0700 Subject: [PATCH 0835/1022] Add vintf_fragments to android.hardware.confirmationui@1.0-service Bug: 153666825 Test: presubmit Signed-off-by: Roman Kiryanov Merged-In: Ib8ff51a60df30d6d8773d658bdadf3de904c0426 Change-Id: I0d23a4202919054efb04b3114edcb8639fcb3995 --- confirmationui/1.0/default/Android.bp | 3 ++- .../android.hardware.confirmationui@1.0-service.xml | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.xml diff --git a/confirmationui/1.0/default/Android.bp b/confirmationui/1.0/default/Android.bp index ecba064b21..33a1e078a9 100644 --- a/confirmationui/1.0/default/Android.bp +++ b/confirmationui/1.0/default/Android.bp @@ -17,6 +17,7 @@ cc_binary { name: "android.hardware.confirmationui@1.0-service", init_rc: ["android.hardware.confirmationui@1.0-service.rc"], + vintf_fragments: ["android.hardware.confirmationui@1.0-service.xml"], vendor: true, relative_install_path: "hw", cflags: [ @@ -39,4 +40,4 @@ cc_binary { "liblog", "libutils", ], -} \ No newline at end of file +} diff --git a/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.xml b/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.xml new file mode 100644 index 0000000000..9008b872e6 --- /dev/null +++ b/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.xml @@ -0,0 +1,11 @@ + + + android.hardware.confirmationui + hwbinder + 1.0 + + IConfirmationUI + default + + + From 133c495d1a19cd689ec518e8e35344cac196e779 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Tue, 28 Jan 2020 16:11:39 -0800 Subject: [PATCH 0836/1022] health 2.0 vts: add battery current test. Require the following on battery current: - skip health info tests if current is 0 (indicates the value is unavailable) - when charging, positive - when discharging / not charging, negative - when unknown, zero - batteryCurrentAverage should be similar to batteryCurrentNow. All new tests are executed over a period of time to avoid effects of fluctuation in battery current, and ensure battery status is initialized. Requirements are enforced on devices launching with R only. Require the following on battery status: - if not charging / full / charging, must be connected - if discharging, must not be connected. Test: run on coral, tests are skipped Test: run on cuttlefish, test passes Fixes: 136717180 Change-Id: Ic5a714b830ffeca1dcd000c6cad0fbfe8a8710ed (cherry picked from commit 94841c9df15b3c95b4c64973dbd7b70073006539) Merged-In: Ic5a714b830ffeca1dcd000c6cad0fbfe8a8710ed --- .../functional/VtsHalHealthV2_0TargetTest.cpp | 367 +++++++++++++++++- 1 file changed, 366 insertions(+), 1 deletion(-) diff --git a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp index 012988387e..441e2d756f 100644 --- a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp +++ b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp @@ -16,11 +16,15 @@ #define LOG_TAG "health_hidl_hal_test" +#include #include #include #include +#include #include +#include +#include #include #include #include @@ -32,15 +36,25 @@ using ::testing::AssertionFailure; using ::testing::AssertionResult; using ::testing::AssertionSuccess; +using namespace std::chrono_literals; DEFINE_bool(force, false, "Force test healthd even when the default instance is present."); +// Return expr if it is evaluated to false. +#define TEST_AND_RETURN(expr) \ + do { \ + auto res = (expr); \ + if (!res) return res; \ + } while (0) + namespace android { namespace hardware { namespace health { -namespace V2_0 { using V1_0::BatteryStatus; +using V1_0::toString; + +namespace V2_0 { class HealthHidlTest : public ::testing::TestWithParam { public: @@ -309,6 +323,357 @@ INSTANTIATE_TEST_SUITE_P( PerInstance, HealthHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames(IHealth::descriptor)), android::hardware::PrintInstanceNameToString); + +// For battery current tests, value may not be stable if the battery current has fluctuated. +// Retry in a bit more time (with the following timeout) and consider the test successful if it +// has succeed once. +static constexpr auto gBatteryTestTimeout = 1min; +// Tests on battery current signs are only enforced on devices launching with Android 11. +static constexpr int64_t gBatteryTestMinShippingApiLevel = 30; +static constexpr double gCurrentCompareFactor = 0.50; + +// Tuple for all IHealth::get* API return values. +template +struct HalResult { + Result result; + T value; +}; + +// Needs to be called repeatedly within a period of time to ensure values are initialized. +static AssertionResult IsBatteryCurrentSignCorrect(HalResult status, + HalResult current, + bool acceptZeroCurrentAsUnknown) { + // getChargeStatus / getCurrentNow / getCurrentAverage / getHealthInfo already tested above. + // Here, just skip if not ok. + if (status.result != Result::SUCCESS) { + return AssertionSuccess() << "getChargeStatus / getHealthInfo returned " + << toString(status.result) << ", skipping"; + } + + if (current.result != Result::SUCCESS) { + return AssertionSuccess() << "getCurrentNow / getCurrentAverage returned " + << toString(current.result) << ", skipping"; + } + + // For IHealth.getCurrentNow/Average, if current is not available, it is expected that + // current.result == Result::NOT_SUPPORTED, which is checked above. Hence, zero current is + // not treated as unknown values. + // For IHealth.getHealthInfo, if current is not available, health_info.current_* == 0. + // Caller of this function provides current.result == Result::SUCCESS. Hence, just skip the + // check. + if (current.value == 0 && acceptZeroCurrentAsUnknown) { + return AssertionSuccess() + << "current is 0, which indicates the value may not be available. Skipping."; + } + + switch (status.value) { + case BatteryStatus::UNKNOWN: + if (current.value != 0) { + // BatteryStatus may be UNKNOWN initially with a non-zero current value, but + // after it is initialized, it should be known. + return AssertionFailure() + << "BatteryStatus is UNKNOWN but current is not 0. Actual: " + << current.value; + } + break; + case BatteryStatus::CHARGING: + if (current.value <= 0) { + return AssertionFailure() + << "BatteryStatus is CHARGING but current is not positive. Actual: " + << current.value; + } + break; + case BatteryStatus::NOT_CHARGING: + if (current.value > 0) { + return AssertionFailure() << "BatteryStatus is " << toString(status.value) + << " but current is positive. Actual: " << current.value; + } + break; + case BatteryStatus::DISCHARGING: + if (current.value >= 0) { + return AssertionFailure() + << "BatteryStatus is " << toString(status.value) + << " but current is not negative. Actual: " << current.value; + } + break; + case BatteryStatus::FULL: + // Battery current may be positive or negative depending on the load. + break; + default: + return AssertionFailure() << "Unknown BatteryStatus " << toString(status.value); + } + + return AssertionSuccess() << "BatteryStatus is " << toString(status.value) + << " and current has the correct sign: " << current.value; +} + +static AssertionResult IsValueSimilar(int32_t dividend, int32_t divisor, double factor) { + auto difference = abs(dividend - divisor); + if (difference > factor * abs(divisor)) { + return AssertionFailure() << dividend << " and " << divisor << " are not similar."; + } + return AssertionSuccess() << dividend << " and " << divisor << " are similar."; +} + +static AssertionResult IsBatteryCurrentSimilar(HalResult status, + HalResult currentNow, + HalResult currentAverage) { + if (status.result == Result::SUCCESS && status.value == BatteryStatus::FULL) { + // No reason to test on full battery because battery current load fluctuates. + return AssertionSuccess() << "Battery is full, skipping"; + } + + // getCurrentNow / getCurrentAverage / getHealthInfo already tested above. Here, just skip if + // not SUCCESS or value 0. + if (currentNow.result != Result::SUCCESS || currentNow.value == 0) { + return AssertionSuccess() << "getCurrentNow returned " << toString(currentNow.result) + << " with value " << currentNow.value << ", skipping"; + } + + if (currentAverage.result != Result::SUCCESS || currentAverage.value == 0) { + return AssertionSuccess() << "getCurrentAverage returned " + << toString(currentAverage.result) << " with value " + << currentAverage.value << ", skipping"; + } + + // Check that the two values are similar. Note that the two tests uses a different + // divisor to ensure that they are actually pretty similar. For example, + // IsValueSimilar(5,10,0.4) returns true, but IsValueSimlar(10,5,0.4) returns false. + TEST_AND_RETURN(IsValueSimilar(currentNow.value, currentAverage.value, gCurrentCompareFactor) + << " for now vs. average. Check units."); + TEST_AND_RETURN(IsValueSimilar(currentAverage.value, currentNow.value, gCurrentCompareFactor) + << " for average vs. now. Check units."); + return AssertionSuccess() << "currentNow = " << currentNow.value + << " and currentAverage = " << currentAverage.value + << " are considered similar."; +} + +// Test that f() returns AssertionSuccess() once in a given period of time. +template +static AssertionResult SucceedOnce(Duration d, Function f) { + AssertionResult result = AssertionFailure() << "Function never evaluated."; + auto end = std::chrono::system_clock::now() + d; + while (std::chrono::system_clock::now() <= end) { + result = f(); + if (result) { + return result; + } + std::this_thread::sleep_for(2s); + } + return result; +} + +uint64_t GetShippingApiLevel() { + uint64_t api_level = android::base::GetUintProperty("ro.product.first_api_level", 0); + if (api_level != 0) { + return api_level; + } + return android::base::GetUintProperty("ro.build.version.sdk", 0); +} + +class BatteryTest : public HealthHidlTest { + public: + void SetUp() override { + HealthHidlTest::SetUp(); + + auto shippingApiLevel = GetShippingApiLevel(); + if (shippingApiLevel < gBatteryTestMinShippingApiLevel) { + GTEST_SKIP() << "Skipping on devices with first API level " << shippingApiLevel; + } + } +}; + +TEST_P(BatteryTest, InstantCurrentAgainstChargeStatusInHealthInfo) { + auto testOnce = [&]() -> AssertionResult { + HalResult healthInfo; + TEST_AND_RETURN(isOk(mHealth->getHealthInfo([&](auto result, const auto& value) { + healthInfo = {result, value}; + }))); + + return IsBatteryCurrentSignCorrect( + {healthInfo.result, healthInfo.value.legacy.batteryStatus}, + {healthInfo.result, healthInfo.value.legacy.batteryCurrent}, + true /* accept zero current as unknown */); + }; + EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce)) + << "You may want to try again later when current_now becomes stable."; +} + +TEST_P(BatteryTest, AverageCurrentAgainstChargeStatusInHealthInfo) { + auto testOnce = [&]() -> AssertionResult { + HalResult healthInfo; + TEST_AND_RETURN(isOk(mHealth->getHealthInfo([&](auto result, const auto& value) { + healthInfo = {result, value}; + }))); + return IsBatteryCurrentSignCorrect( + {healthInfo.result, healthInfo.value.legacy.batteryStatus}, + {healthInfo.result, healthInfo.value.batteryCurrentAverage}, + true /* accept zero current as unknown */); + }; + + EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce)) + << "You may want to try again later when current_average becomes stable."; +} + +TEST_P(BatteryTest, InstantCurrentAgainstAverageCurrentInHealthInfo) { + auto testOnce = [&]() -> AssertionResult { + HalResult healthInfo; + TEST_AND_RETURN(isOk(mHealth->getHealthInfo([&](auto result, const auto& value) { + healthInfo = {result, value}; + }))); + return IsBatteryCurrentSimilar({healthInfo.result, healthInfo.value.legacy.batteryStatus}, + {healthInfo.result, healthInfo.value.legacy.batteryCurrent}, + {healthInfo.result, healthInfo.value.batteryCurrentAverage}); + }; + + EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce)) + << "You may want to try again later when current_now and current_average becomes " + "stable."; +} + +TEST_P(BatteryTest, InstantCurrentAgainstChargeStatusFromHal) { + auto testOnce = [&]() -> AssertionResult { + HalResult status; + HalResult currentNow; + TEST_AND_RETURN(isOk(mHealth->getChargeStatus([&](auto result, auto value) { + status = {result, value}; + }))); + TEST_AND_RETURN(isOk(mHealth->getCurrentNow([&](auto result, auto value) { + currentNow = {result, value}; + }))); + + return IsBatteryCurrentSignCorrect(status, currentNow, + false /* accept zero current as unknown */); + }; + + EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce)) + << "You may want to try again later when current_now becomes stable."; +} + +TEST_P(BatteryTest, AverageCurrentAgainstChargeStatusFromHal) { + auto testOnce = [&]() -> AssertionResult { + HalResult status; + TEST_AND_RETURN(isOk(mHealth->getChargeStatus([&](auto result, auto value) { + status = {result, value}; + }))); + HalResult currentAverage; + TEST_AND_RETURN(isOk(mHealth->getCurrentAverage([&](auto result, auto value) { + currentAverage = {result, value}; + }))); + return IsBatteryCurrentSignCorrect(status, currentAverage, + false /* accept zero current as unknown */); + }; + + EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce)) + << "You may want to try again later when current_average becomes stable."; +} + +TEST_P(BatteryTest, InstantCurrentAgainstAverageCurrentFromHal) { + auto testOnce = [&]() -> AssertionResult { + HalResult status; + TEST_AND_RETURN(isOk(mHealth->getChargeStatus([&](auto result, auto value) { + status = {result, value}; + }))); + HalResult currentNow; + TEST_AND_RETURN(isOk(mHealth->getCurrentNow([&](auto result, auto value) { + currentNow = {result, value}; + }))); + HalResult currentAverage; + TEST_AND_RETURN(isOk(mHealth->getCurrentAverage([&](auto result, auto value) { + currentAverage = {result, value}; + }))); + return IsBatteryCurrentSimilar(status, currentNow, currentAverage); + }; + + EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce)) + << "You may want to try again later when current_average becomes stable."; +} + +AssertionResult IsBatteryStatusCorrect(HalResult status, + HalResult healthInfo) { + // getChargetStatus / getHealthInfo is already tested above. Here, just skip if not ok. + if (healthInfo.result != Result::SUCCESS) { + return AssertionSuccess() << "getHealthInfo returned " << toString(healthInfo.result) + << ", skipping"; + } + if (status.result != Result::SUCCESS) { + return AssertionSuccess() << "getChargeStatus returned " << toString(status.result) + << ", skipping"; + } + + const auto& batteryInfo = healthInfo.value.legacy; + bool isConnected = batteryInfo.chargerAcOnline || batteryInfo.chargerUsbOnline || + batteryInfo.chargerWirelessOnline; + + std::stringstream message; + message << "BatteryStatus is " << toString(status.value) << " and " + << (isConnected ? "" : "no ") + << "power source is connected: ac=" << batteryInfo.chargerAcOnline + << ", usb=" << batteryInfo.chargerUsbOnline + << ", wireless=" << batteryInfo.chargerWirelessOnline; + + switch (status.value) { + case BatteryStatus::UNKNOWN: { + // Don't enforce anything on isConnected on unknown battery status. + // Battery-less devices must report UNKNOWN battery status, but may report true + // or false on isConnected. + } break; + case BatteryStatus::CHARGING: + case BatteryStatus::NOT_CHARGING: + case BatteryStatus::FULL: { + if (!isConnected) { + return AssertionFailure() << message.str(); + } + } break; + case BatteryStatus::DISCHARGING: { + if (isConnected) { + return AssertionFailure() << message.str(); + } + } break; + default: { + return AssertionFailure() << "Unknown battery status value " << toString(status.value); + } break; + } + + return AssertionSuccess() << message.str(); +} + +TEST_P(BatteryTest, ConnectedAgainstStatusFromHal) { + auto testOnce = [&]() -> AssertionResult { + HalResult status; + TEST_AND_RETURN(isOk(mHealth->getChargeStatus([&](auto result, auto value) { + status = {result, value}; + }))); + HalResult healthInfo; + TEST_AND_RETURN(isOk(mHealth->getHealthInfo([&](auto result, const auto& value) { + healthInfo = {result, value}; + }))); + return IsBatteryStatusCorrect(status, healthInfo); + }; + + EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce)) + << "You may want to try again later when battery_status becomes stable."; +} + +TEST_P(BatteryTest, ConnectedAgainstStatusInHealthInfo) { + auto testOnce = [&]() -> AssertionResult { + HalResult healthInfo; + TEST_AND_RETURN(isOk(mHealth->getHealthInfo([&](auto result, const auto& value) { + healthInfo = {result, value}; + }))); + return IsBatteryStatusCorrect({healthInfo.result, healthInfo.value.legacy.batteryStatus}, + healthInfo); + }; + + EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce)) + << "You may want to try again later when getHealthInfo becomes stable."; +} + +INSTANTIATE_TEST_SUITE_P( + PerInstance, BatteryTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IHealth::descriptor)), + android::hardware::PrintInstanceNameToString); + } // namespace V2_0 } // namespace health } // namespace hardware From 71d6059bbaa0ae48d65c76ccff58fb7556787df2 Mon Sep 17 00:00:00 2001 From: shubang Date: Fri, 10 Apr 2020 18:08:49 -0700 Subject: [PATCH 0837/1022] Return SUCCESS in scan for ATSC This is for a CTS test case Bug: 150952758 Test: atest android.media.tv.tuner.cts.TunerTest Change-Id: I8761fec6af392e4f2d18bc38760effcae2aec273 --- tv/tuner/1.0/default/Frontend.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp index 2cff9be459..6565746c76 100644 --- a/tv/tuner/1.0/default/Frontend.cpp +++ b/tv/tuner/1.0/default/Frontend.cpp @@ -81,6 +81,9 @@ Return Frontend::stopTune() { Return Frontend::scan(const FrontendSettings& settings, FrontendScanType type) { ALOGV("%s", __FUNCTION__); + if (mType == FrontendType::ATSC) { + return Result::SUCCESS; + } if (mType != FrontendType::DVBT) { return Result::UNAVAILABLE; } From b3fb40bd0549d49bd38dcfde365eaa2eabb3e6ba Mon Sep 17 00:00:00 2001 From: Amy Zhang Date: Thu, 2 Apr 2020 13:48:43 -0700 Subject: [PATCH 0838/1022] Make VtsHalTvTunerV1_0FrontendTest an independent test. Note that this refactoring extracts two header files for VtsHalTvTunerV1_0FrontendTest and VtsHalTvTunerV1_0TargetTest. Test: atest VtsHalTvTunerV1_0FrontendTest/VtsHalTvTunerV1_0TargetTest Bug: 150953857 Change-Id: Ie5f0dc4a9180ecc779004cb451a45ae54a6ea47c --- tv/tuner/1.0/vts/functional/Android.bp | 5 +- tv/tuner/1.0/vts/functional/FrontendTests.cpp | 310 ++++++++ tv/tuner/1.0/vts/functional/FrontendTests.h | 127 +++ .../VtsHalTvTunerV1_0TargetTest.cpp | 752 +----------------- .../functional/VtsHalTvTunerV1_0TargetTest.h | 333 ++++++++ 5 files changed, 796 insertions(+), 731 deletions(-) create mode 100644 tv/tuner/1.0/vts/functional/FrontendTests.cpp create mode 100644 tv/tuner/1.0/vts/functional/FrontendTests.h create mode 100644 tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp index 641e16a937..b4dbda7896 100644 --- a/tv/tuner/1.0/vts/functional/Android.bp +++ b/tv/tuner/1.0/vts/functional/Android.bp @@ -17,7 +17,10 @@ cc_test { name: "VtsHalTvTunerV1_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], - srcs: ["VtsHalTvTunerV1_0TargetTest.cpp"], + srcs: [ + "VtsHalTvTunerV1_0TargetTest.cpp", + "FrontendTests.cpp", + ], static_libs: [ "android.hardware.tv.tuner@1.0", "android.hidl.allocator@1.0", diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.cpp b/tv/tuner/1.0/vts/functional/FrontendTests.cpp new file mode 100644 index 0000000000..5bc3705fcd --- /dev/null +++ b/tv/tuner/1.0/vts/functional/FrontendTests.cpp @@ -0,0 +1,310 @@ +/* + * Copyright 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 "FrontendTests.h" + +Return FrontendCallback::onEvent(FrontendEventType frontendEventType) { + android::Mutex::Autolock autoLock(mMsgLock); + ALOGD("[vts] frontend event received. Type: %d", frontendEventType); + mEventReceived = true; + mMsgCondition.signal(); + switch (frontendEventType) { + case FrontendEventType::LOCKED: + mLockMsgReceived = true; + mLockMsgCondition.signal(); + return Void(); + default: + // do nothing + return Void(); + } +} + +Return FrontendCallback::onScanMessage(FrontendScanMessageType type, + const FrontendScanMessage& message) { + android::Mutex::Autolock autoLock(mMsgLock); + while (!mScanMsgProcessed) { + mMsgCondition.wait(mMsgLock); + } + ALOGD("[vts] frontend scan message. Type: %d", type); + mScanMessageReceived = true; + mScanMsgProcessed = false; + mScanMessageType = type; + mScanMessage = message; + mMsgCondition.signal(); + return Void(); +} + +void FrontendCallback::tuneTestOnEventReceive(sp& frontend, FrontendSettings settings) { + Result result = frontend->tune(settings); + EXPECT_TRUE(result == Result::SUCCESS); + + android::Mutex::Autolock autoLock(mMsgLock); + while (!mEventReceived) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "Event not received within timeout"; + mLockMsgReceived = false; + return; + } + } + mEventReceived = false; +} + +void FrontendCallback::tuneTestOnLock(sp& frontend, FrontendSettings settings) { + Result result = frontend->tune(settings); + EXPECT_TRUE(result == Result::SUCCESS); + + android::Mutex::Autolock autoLock(mMsgLock); + while (!mLockMsgReceived) { + if (-ETIMEDOUT == mLockMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "Event LOCKED not received within timeout"; + mLockMsgReceived = false; + return; + } + } + mLockMsgReceived = false; +} + +void FrontendCallback::scanTest(sp& frontend, FrontendConfig config, + FrontendScanType type) { + uint32_t targetFrequency = getTargetFrequency(config.settings, config.type); + if (type == FrontendScanType::SCAN_BLIND) { + // reset the frequency in the scan configuration to test blind scan. The settings param of + // passed in means the real input config on the transponder connected to the DUT. + // We want the blind the test to start from lower frequency than this to check the blind + // scan implementation. + resetBlindScanStartingFrequency(config, targetFrequency - 100); + } + + Result result = frontend->scan(config.settings, type); + EXPECT_TRUE(result == Result::SUCCESS); + + bool scanMsgLockedReceived = false; + bool targetFrequencyReceived = false; + + android::Mutex::Autolock autoLock(mMsgLock); +wait: + while (!mScanMessageReceived) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "Scan message not received within timeout"; + mScanMessageReceived = false; + mScanMsgProcessed = true; + return; + } + } + + if (mScanMessageType != FrontendScanMessageType::END) { + if (mScanMessageType == FrontendScanMessageType::LOCKED) { + scanMsgLockedReceived = true; + Result result = frontend->scan(config.settings, type); + EXPECT_TRUE(result == Result::SUCCESS); + } + + if (mScanMessageType == FrontendScanMessageType::FREQUENCY) { + targetFrequencyReceived = mScanMessage.frequencies().size() > 0 && + mScanMessage.frequencies()[0] == targetFrequency; + } + + if (mScanMessageType == FrontendScanMessageType::PROGRESS_PERCENT) { + ALOGD("[vts] Scan in progress...[%d%%]", mScanMessage.progressPercent()); + } + + mScanMessageReceived = false; + mScanMsgProcessed = true; + mMsgCondition.signal(); + goto wait; + } + + EXPECT_TRUE(scanMsgLockedReceived) << "Scan message LOCKED not received before END"; + EXPECT_TRUE(targetFrequencyReceived) << "frequency not received before LOCKED on blindScan"; + mScanMessageReceived = false; + mScanMsgProcessed = true; +} + +uint32_t FrontendCallback::getTargetFrequency(FrontendSettings settings, FrontendType type) { + switch (type) { + case FrontendType::ANALOG: + return settings.analog().frequency; + case FrontendType::ATSC: + return settings.atsc().frequency; + case FrontendType::ATSC3: + return settings.atsc3().frequency; + case FrontendType::DVBC: + return settings.dvbc().frequency; + case FrontendType::DVBS: + return settings.dvbs().frequency; + case FrontendType::DVBT: + return settings.dvbt().frequency; + case FrontendType::ISDBS: + return settings.isdbs().frequency; + case FrontendType::ISDBS3: + return settings.isdbs3().frequency; + case FrontendType::ISDBT: + return settings.isdbt().frequency; + default: + return 0; + } +} + +void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig& config, + uint32_t resetingFreq) { + switch (config.type) { + case FrontendType::ANALOG: + config.settings.analog().frequency = resetingFreq; + break; + case FrontendType::ATSC: + config.settings.atsc().frequency = resetingFreq; + break; + case FrontendType::ATSC3: + config.settings.atsc3().frequency = resetingFreq; + break; + case FrontendType::DVBC: + config.settings.dvbc().frequency = resetingFreq; + break; + case FrontendType::DVBS: + config.settings.dvbs().frequency = resetingFreq; + break; + case FrontendType::DVBT: + config.settings.dvbt().frequency = resetingFreq; + break; + case FrontendType::ISDBS: + config.settings.isdbs().frequency = resetingFreq; + break; + case FrontendType::ISDBS3: + config.settings.isdbs3().frequency = resetingFreq; + break; + case FrontendType::ISDBT: + config.settings.isdbt().frequency = resetingFreq; + break; + default: + // do nothing + return; + } +} + +AssertionResult FrontendTests::getFrontendIds() { + Result status; + mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { + status = result; + mFeIds = frontendIds; + }); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FrontendTests::getFrontendInfo(uint32_t frontendId) { + Result status; + mService->getFrontendInfo(frontendId, [&](Result result, const FrontendInfo& frontendInfo) { + mFrontendInfo = frontendInfo; + status = result; + }); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FrontendTests::openFrontendById(uint32_t frontendId) { + Result status; + mService->openFrontendById(frontendId, [&](Result result, const sp& frontend) { + mFrontend = frontend; + status = result; + }); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FrontendTests::setFrontendCallback() { + EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; + mFrontendCallback = new FrontendCallback(); + auto callbackStatus = mFrontend->setCallback(mFrontendCallback); + return AssertionResult(callbackStatus.isOk()); +} + +AssertionResult FrontendTests::scanFrontend(FrontendConfig config, FrontendScanType type) { + EXPECT_TRUE(mFrontendCallback) + << "test with openFrontendById/setFrontendCallback/getFrontendInfo first."; + + EXPECT_TRUE(mFrontendInfo.type == config.type) + << "FrontendConfig does not match the frontend info of the given id."; + + mFrontendCallback->scanTest(mFrontend, config, type); + return AssertionResult(true); +} + +AssertionResult FrontendTests::stopScanFrontend() { + EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; + Result status; + status = mFrontend->stopScan(); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FrontendTests::tuneFrontend(FrontendConfig config) { + EXPECT_TRUE(mFrontendCallback) + << "test with openFrontendById/setFrontendCallback/getFrontendInfo first."; + + EXPECT_TRUE(mFrontendInfo.type == config.type) + << "FrontendConfig does not match the frontend info of the given id."; + + mFrontendCallback->tuneTestOnLock(mFrontend, config.settings); + return AssertionResult(true); +} + +AssertionResult FrontendTests::stopTuneFrontend() { + EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; + Result status; + status = mFrontend->stopTune(); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FrontendTests::closeFrontend() { + EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; + Result status; + status = mFrontend->close(); + mFrontend = nullptr; + mFrontendCallback = nullptr; + return AssertionResult(status == Result::SUCCESS); +} + +void FrontendTests::getFrontendIdByType(FrontendType feType, uint32_t& feId) { + ASSERT_TRUE(getFrontendIds()); + ASSERT_TRUE(mFeIds.size() > 0); + for (size_t i = 0; i < mFeIds.size(); i++) { + ASSERT_TRUE(getFrontendInfo(mFeIds[i])); + if (mFrontendInfo.type != feType) { + continue; + } + feId = mFeIds[i]; + return; + } + feId = INVALID_ID; +} + +void FrontendTests::tuneTest(FrontendConfig frontendConf) { + uint32_t feId; + getFrontendIdByType(frontendConf.type, feId); + ASSERT_TRUE(feId != INVALID_ID); + ASSERT_TRUE(openFrontendById(feId)); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(tuneFrontend(frontendConf)); + ASSERT_TRUE(stopTuneFrontend()); + ASSERT_TRUE(closeFrontend()); +} + +void FrontendTests::scanTest(FrontendConfig frontendConf, FrontendScanType scanType) { + uint32_t feId; + getFrontendIdByType(frontendConf.type, feId); + ASSERT_TRUE(feId != INVALID_ID); + ASSERT_TRUE(openFrontendById(feId)); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(scanFrontend(frontendConf, scanType)); + ASSERT_TRUE(stopScanFrontend()); + ASSERT_TRUE(closeFrontend()); +} \ No newline at end of file diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.h b/tv/tuner/1.0/vts/functional/FrontendTests.h new file mode 100644 index 0000000000..5aa6e159f1 --- /dev/null +++ b/tv/tuner/1.0/vts/functional/FrontendTests.h @@ -0,0 +1,127 @@ +/* + * Copyright 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "VtsHalTvTunerV1_0TestConfigurations.h" + +#define WAIT_TIMEOUT 3000000000 +#define INVALID_ID -1 + +using android::Condition; +using android::IMemory; +using android::IMemoryHeap; +using android::MemoryDealer; +using android::Mutex; +using android::sp; +using android::hardware::fromHeap; +using android::hardware::hidl_handle; +using android::hardware::hidl_string; +using android::hardware::hidl_vec; +using android::hardware::HidlMemory; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::tv::tuner::V1_0::FrontendAtscModulation; +using android::hardware::tv::tuner::V1_0::FrontendAtscSettings; +using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings; +using android::hardware::tv::tuner::V1_0::FrontendEventType; +using android::hardware::tv::tuner::V1_0::FrontendId; +using android::hardware::tv::tuner::V1_0::FrontendInfo; +using android::hardware::tv::tuner::V1_0::FrontendInnerFec; +using android::hardware::tv::tuner::V1_0::FrontendScanMessage; +using android::hardware::tv::tuner::V1_0::FrontendScanMessageType; +using android::hardware::tv::tuner::V1_0::FrontendScanType; +using android::hardware::tv::tuner::V1_0::FrontendSettings; +using android::hardware::tv::tuner::V1_0::IFrontend; +using android::hardware::tv::tuner::V1_0::IFrontendCallback; +using android::hardware::tv::tuner::V1_0::ITuner; +using android::hardware::tv::tuner::V1_0::Result; + +using ::testing::AssertionResult; + +#define INVALID_ID -1 +#define WAIT_TIMEOUT 3000000000 + +class FrontendCallback : public IFrontendCallback { + public: + virtual Return onEvent(FrontendEventType frontendEventType) override; + virtual Return onScanMessage(FrontendScanMessageType type, + const FrontendScanMessage& message) override; + + void tuneTestOnEventReceive(sp& frontend, FrontendSettings settings); + void tuneTestOnLock(sp& frontend, FrontendSettings settings); + void scanTest(sp& frontend, FrontendConfig config, FrontendScanType type); + + // Helper methods + uint32_t getTargetFrequency(FrontendSettings settings, FrontendType type); + void resetBlindScanStartingFrequency(FrontendConfig& config, uint32_t resetingFreq); + + private: + bool mEventReceived = false; + bool mScanMessageReceived = false; + bool mLockMsgReceived = false; + bool mScanMsgProcessed = true; + FrontendScanMessageType mScanMessageType; + FrontendScanMessage mScanMessage; + hidl_vec mEventMessage; + android::Mutex mMsgLock; + android::Condition mMsgCondition; + android::Condition mLockMsgCondition; +}; + +class FrontendTests { + public: + sp mService; + + void setService(sp tuner) { mService = tuner; } + + AssertionResult getFrontendIds(); + AssertionResult getFrontendInfo(uint32_t frontendId); + AssertionResult openFrontendById(uint32_t frontendId); + AssertionResult setFrontendCallback(); + AssertionResult scanFrontend(FrontendConfig config, FrontendScanType type); + AssertionResult stopScanFrontend(); + AssertionResult tuneFrontend(FrontendConfig config); + AssertionResult stopTuneFrontend(); + AssertionResult closeFrontend(); + + void getFrontendIdByType(FrontendType feType, uint32_t& feId); + void tuneTest(FrontendConfig frontendConf); + void scanTest(FrontendConfig frontend, FrontendScanType type); + + protected: + sp mFrontend; + FrontendInfo mFrontendInfo; + sp mFrontendCallback; + hidl_vec mFeIds; +}; diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 5e98367af6..59c94793ec 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -14,433 +14,10 @@ * limitations under the License. */ -#define LOG_TAG "Tuner_hidl_hal_test" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "VtsHalTvTunerV1_0TestConfigurations.h" - -#define WAIT_TIMEOUT 3000000000 -#define INVALID_ID -1 - -using android::Condition; -using android::IMemory; -using android::IMemoryHeap; -using android::MemoryDealer; -using android::Mutex; -using android::sp; -using android::hardware::EventFlag; -using android::hardware::fromHeap; -using android::hardware::hidl_handle; -using android::hardware::hidl_string; -using android::hardware::hidl_vec; -using android::hardware::HidlMemory; -using android::hardware::kSynchronizedReadWrite; -using android::hardware::MessageQueue; -using android::hardware::MQDescriptorSync; -using android::hardware::Return; -using android::hardware::Void; -using android::hardware::tv::tuner::V1_0::DataFormat; -using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; -using android::hardware::tv::tuner::V1_0::DemuxFilterMainType; -using android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent; -using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; -using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent; -using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings; -using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent; -using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings; -using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; -using android::hardware::tv::tuner::V1_0::DemuxFilterStatus; -using android::hardware::tv::tuner::V1_0::DemuxFilterType; -using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; -using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings; -using android::hardware::tv::tuner::V1_0::DemuxTsFilterType; -using android::hardware::tv::tuner::V1_0::DvrSettings; -using android::hardware::tv::tuner::V1_0::DvrType; -using android::hardware::tv::tuner::V1_0::FrontendAtscModulation; -using android::hardware::tv::tuner::V1_0::FrontendAtscSettings; -using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings; -using android::hardware::tv::tuner::V1_0::FrontendEventType; -using android::hardware::tv::tuner::V1_0::FrontendId; -using android::hardware::tv::tuner::V1_0::FrontendInfo; -using android::hardware::tv::tuner::V1_0::FrontendInnerFec; -using android::hardware::tv::tuner::V1_0::FrontendScanMessage; -using android::hardware::tv::tuner::V1_0::FrontendScanMessageType; -using android::hardware::tv::tuner::V1_0::FrontendScanType; -using android::hardware::tv::tuner::V1_0::FrontendSettings; -using android::hardware::tv::tuner::V1_0::IDemux; -using android::hardware::tv::tuner::V1_0::IDescrambler; -using android::hardware::tv::tuner::V1_0::IDvr; -using android::hardware::tv::tuner::V1_0::IDvrCallback; -using android::hardware::tv::tuner::V1_0::IFilter; -using android::hardware::tv::tuner::V1_0::IFilterCallback; -using android::hardware::tv::tuner::V1_0::IFrontend; -using android::hardware::tv::tuner::V1_0::IFrontendCallback; -using android::hardware::tv::tuner::V1_0::ITuner; -using android::hardware::tv::tuner::V1_0::PlaybackSettings; -using android::hardware::tv::tuner::V1_0::PlaybackStatus; -using android::hardware::tv::tuner::V1_0::RecordSettings; -using android::hardware::tv::tuner::V1_0::RecordStatus; -using android::hardware::tv::tuner::V1_0::Result; - -using ::testing::AssertionResult; +#include "VtsHalTvTunerV1_0TargetTest.h" namespace { - -using FilterMQ = MessageQueue; -using MQDesc = MQDescriptorSync; - -const std::vector goldenDataOutputBuffer{ - 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb, - 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03, - 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06, - 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, - 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, - 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d, - 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63, - 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, - 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, - 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, - 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20, - 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, - 0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d, - 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65, - 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31, - 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e, - 0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20, - 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, - 0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69, - 0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71, - 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, - 0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d, - 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, - 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, - 0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68, - 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f, - 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, - 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79, - 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, - 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20, - 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68, - 0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30, - 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20, - 0x73, 0x63, 0x65, 0x6e, 0x65, -}; - -// const uint16_t FMQ_SIZE_4K = 0x1000; -const uint32_t FMQ_SIZE_1M = 0x100000; -const uint32_t FMQ_SIZE_16M = 0x1000000; - -enum FilterEventType : uint8_t { - UNDEFINED, - SECTION, - MEDIA, - PES, - RECORD, - MMTPRECORD, - DOWNLOAD, - TEMI, -}; - -struct PlaybackConf { - string inputDataFile; - PlaybackSettings setting; -}; - -/******************************** Start FrontendCallback **********************************/ -class FrontendCallback : public IFrontendCallback { - public: - virtual Return onEvent(FrontendEventType frontendEventType) override { - android::Mutex::Autolock autoLock(mMsgLock); - ALOGD("[vts] frontend event received. Type: %d", frontendEventType); - mEventReceived = true; - mMsgCondition.signal(); - switch (frontendEventType) { - case FrontendEventType::LOCKED: - mLockMsgReceived = true; - mLockMsgCondition.signal(); - return Void(); - default: - // do nothing - return Void(); - } - } - - virtual Return onScanMessage(FrontendScanMessageType type, - const FrontendScanMessage& message) override { - android::Mutex::Autolock autoLock(mMsgLock); - while (!mScanMsgProcessed) { - mMsgCondition.wait(mMsgLock); - } - ALOGD("[vts] frontend scan message. Type: %d", type); - mScanMessageReceived = true; - mScanMsgProcessed = false; - mScanMessageType = type; - mScanMessage = message; - mMsgCondition.signal(); - return Void(); - } - - void tuneTestOnEventReceive(sp& frontend, FrontendSettings settings); - void tuneTestOnLock(sp& frontend, FrontendSettings settings); - void scanTest(sp& frontend, FrontendConfig config, FrontendScanType type); - - // Helper methods - uint32_t getTargetFrequency(FrontendSettings settings, FrontendType type); - void resetBlindScanStartingFrequency(FrontendConfig& config, uint32_t resetingFreq); - - private: - bool mEventReceived = false; - bool mScanMessageReceived = false; - bool mLockMsgReceived = false; - bool mScanMsgProcessed = true; - FrontendScanMessageType mScanMessageType; - FrontendScanMessage mScanMessage; - hidl_vec mEventMessage; - android::Mutex mMsgLock; - android::Condition mMsgCondition; - android::Condition mLockMsgCondition; -}; - -void FrontendCallback::tuneTestOnEventReceive(sp& frontend, FrontendSettings settings) { - Result result = frontend->tune(settings); - EXPECT_TRUE(result == Result::SUCCESS); - - android::Mutex::Autolock autoLock(mMsgLock); - while (!mEventReceived) { - if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { - EXPECT_TRUE(false) << "Event not received within timeout"; - mLockMsgReceived = false; - return; - } - } - mEventReceived = false; -} - -void FrontendCallback::tuneTestOnLock(sp& frontend, FrontendSettings settings) { - Result result = frontend->tune(settings); - EXPECT_TRUE(result == Result::SUCCESS); - - android::Mutex::Autolock autoLock(mMsgLock); - while (!mLockMsgReceived) { - if (-ETIMEDOUT == mLockMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { - EXPECT_TRUE(false) << "Event LOCKED not received within timeout"; - mLockMsgReceived = false; - return; - } - } - mLockMsgReceived = false; -} - -void FrontendCallback::scanTest(sp& frontend, FrontendConfig config, - FrontendScanType type) { - uint32_t targetFrequency = getTargetFrequency(config.settings, config.type); - if (type == FrontendScanType::SCAN_BLIND) { - // reset the frequency in the scan configuration to test blind scan. The settings param of - // passed in means the real input config on the transponder connected to the DUT. - // We want the blind the test to start from lower frequency than this to check the blind - // scan implementation. - resetBlindScanStartingFrequency(config, targetFrequency - 100); - } - - Result result = frontend->scan(config.settings, type); - EXPECT_TRUE(result == Result::SUCCESS); - - bool scanMsgLockedReceived = false; - bool targetFrequencyReceived = false; - - android::Mutex::Autolock autoLock(mMsgLock); -wait: - while (!mScanMessageReceived) { - if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { - EXPECT_TRUE(false) << "Scan message not received within timeout"; - mScanMessageReceived = false; - mScanMsgProcessed = true; - return; - } - } - - if (mScanMessageType != FrontendScanMessageType::END) { - if (mScanMessageType == FrontendScanMessageType::LOCKED) { - scanMsgLockedReceived = true; - Result result = frontend->scan(config.settings, type); - EXPECT_TRUE(result == Result::SUCCESS); - } - - if (mScanMessageType == FrontendScanMessageType::FREQUENCY) { - targetFrequencyReceived = mScanMessage.frequencies().size() > 0 && - mScanMessage.frequencies()[0] == targetFrequency; - } - - if (mScanMessageType == FrontendScanMessageType::PROGRESS_PERCENT) { - ALOGD("[vts] Scan in progress...[%d%%]", mScanMessage.progressPercent()); - } - - mScanMessageReceived = false; - mScanMsgProcessed = true; - mMsgCondition.signal(); - goto wait; - } - - EXPECT_TRUE(scanMsgLockedReceived) << "Scan message LOCKED not received before END"; - EXPECT_TRUE(targetFrequencyReceived) << "frequency not received before LOCKED on blindScan"; - mScanMessageReceived = false; - mScanMsgProcessed = true; -} - -uint32_t FrontendCallback::getTargetFrequency(FrontendSettings settings, FrontendType type) { - switch (type) { - case FrontendType::ANALOG: - return settings.analog().frequency; - case FrontendType::ATSC: - return settings.atsc().frequency; - case FrontendType::ATSC3: - return settings.atsc3().frequency; - case FrontendType::DVBC: - return settings.dvbc().frequency; - case FrontendType::DVBS: - return settings.dvbs().frequency; - case FrontendType::DVBT: - return settings.dvbt().frequency; - case FrontendType::ISDBS: - return settings.isdbs().frequency; - case FrontendType::ISDBS3: - return settings.isdbs3().frequency; - case FrontendType::ISDBT: - return settings.isdbt().frequency; - default: - return 0; - } -} - -void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig& config, - uint32_t resetingFreq) { - switch (config.type) { - case FrontendType::ANALOG: - config.settings.analog().frequency = resetingFreq; - break; - case FrontendType::ATSC: - config.settings.atsc().frequency = resetingFreq; - break; - case FrontendType::ATSC3: - config.settings.atsc3().frequency = resetingFreq; - break; - case FrontendType::DVBC: - config.settings.dvbc().frequency = resetingFreq; - break; - case FrontendType::DVBS: - config.settings.dvbs().frequency = resetingFreq; - break; - case FrontendType::DVBT: - config.settings.dvbt().frequency = resetingFreq; - break; - case FrontendType::ISDBS: - config.settings.isdbs().frequency = resetingFreq; - break; - case FrontendType::ISDBS3: - config.settings.isdbs3().frequency = resetingFreq; - break; - case FrontendType::ISDBT: - config.settings.isdbt().frequency = resetingFreq; - break; - default: - // do nothing - return; - } -} -/******************************** End FrontendCallback **********************************/ - /******************************** Start FilterCallback **********************************/ -class FilterCallback : public IFilterCallback { - public: - virtual Return onFilterEvent(const DemuxFilterEvent& filterEvent) override { - android::Mutex::Autolock autoLock(mMsgLock); - // Temprarily we treat the first coming back filter data on the matching pid a success - // once all of the MQ are cleared, means we got all the expected output - mFilterEvent = filterEvent; - readFilterEventData(); - mPidFilterOutputCount++; - // mFilterIdToMQ.erase(filterEvent.filterId); - - // startFilterEventThread(filterEvent); - mMsgCondition.signal(); - return Void(); - } - - virtual Return onFilterStatus(const DemuxFilterStatus /*status*/) override { - return Void(); - } - - void setFilterId(uint32_t filterId) { mFilterId = filterId; } - void setFilterInterface(sp filter) { mFilter = filter; } - void setFilterEventType(FilterEventType type) { mFilterEventType = type; } - - void testFilterDataOutput(); - - void startFilterEventThread(DemuxFilterEvent event); - static void* __threadLoopFilter(void* threadArgs); - void filterThreadLoop(DemuxFilterEvent& event); - - void updateFilterMQ(MQDesc& filterMQDescriptor); - void updateGoldenOutputMap(string goldenOutputFile); - bool readFilterEventData(); - bool dumpAvData(DemuxFilterMediaEvent event); - - private: - struct FilterThreadArgs { - FilterCallback* user; - DemuxFilterEvent event; - }; - uint16_t mDataLength = 0; - std::vector mDataOutputBuffer; - - string mFilterIdToGoldenOutput; - - uint32_t mFilterId; - sp mFilter; - FilterEventType mFilterEventType; - std::unique_ptr mFilterMQ; - EventFlag* mFilterMQEventFlag; - DemuxFilterEvent mFilterEvent; - - android::Mutex mMsgLock; - android::Mutex mFilterOutputLock; - android::Condition mMsgCondition; - android::Condition mFilterOutputCondition; - - pthread_t mFilterThread; - - int mPidFilterOutputCount = 0; -}; - void FilterCallback::startFilterEventThread(DemuxFilterEvent event) { struct FilterThreadArgs* threadArgs = (struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs)); @@ -555,89 +132,6 @@ bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) { /******************************** End FilterCallback **********************************/ /******************************** Start DvrCallback **********************************/ -class DvrCallback : public IDvrCallback { - public: - virtual Return onRecordStatus(DemuxFilterStatus status) override { - ALOGW("[vts] record status %hhu", status); - switch (status) { - case DemuxFilterStatus::DATA_READY: - break; - case DemuxFilterStatus::LOW_WATER: - break; - case DemuxFilterStatus::HIGH_WATER: - case DemuxFilterStatus::OVERFLOW: - ALOGW("[vts] record overflow. Flushing"); - break; - } - return Void(); - } - - virtual Return onPlaybackStatus(PlaybackStatus status) override { - // android::Mutex::Autolock autoLock(mMsgLock); - ALOGW("[vts] playback status %d", status); - switch (status) { - case PlaybackStatus::SPACE_EMPTY: - case PlaybackStatus::SPACE_ALMOST_EMPTY: - ALOGW("[vts] keep playback inputing %d", status); - mKeepWritingPlaybackFMQ = true; - break; - case PlaybackStatus::SPACE_ALMOST_FULL: - case PlaybackStatus::SPACE_FULL: - ALOGW("[vts] stop playback inputing %d", status); - mKeepWritingPlaybackFMQ = false; - break; - } - return Void(); - } - - void testFilterDataOutput(); - void stopPlaybackThread(); - void testRecordOutput(); - void stopRecordThread(); - - void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor); - void startRecordOutputThread(RecordSettings recordSetting, MQDesc& recordMQDescriptor); - static void* __threadLoopPlayback(void* threadArgs); - static void* __threadLoopRecord(void* threadArgs); - void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ); - void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ); - - bool readRecordFMQ(); - - private: - struct PlaybackThreadArgs { - DvrCallback* user; - PlaybackConf* playbackConf; - bool* keepWritingPlaybackFMQ; - }; - struct RecordThreadArgs { - DvrCallback* user; - RecordSettings* recordSetting; - bool* keepReadingRecordFMQ; - }; - uint16_t mDataLength = 0; - std::vector mDataOutputBuffer; - - std::map> mFilterMQ; - std::unique_ptr mPlaybackMQ; - std::unique_ptr mRecordMQ; - std::map mFilterMQEventFlag; - - android::Mutex mMsgLock; - android::Mutex mPlaybackThreadLock; - android::Mutex mRecordThreadLock; - android::Condition mMsgCondition; - - bool mKeepWritingPlaybackFMQ = true; - bool mKeepReadingRecordFMQ = true; - bool mPlaybackThreadRunning; - bool mRecordThreadRunning; - pthread_t mPlaybackThread; - pthread_t mRecordThread; - - int mPidFilterOutputCount = 0; -}; - void DvrCallback::startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor) { mPlaybackMQ = std::make_unique(playbackMQDescriptor, true /* resetPointers */); @@ -809,176 +303,6 @@ void DvrCallback::stopRecordThread() { } /********************************** End DvrCallback ************************************/ -/***************************** Start Test Implementation ******************************/ -class TunerHidlTest : public testing::TestWithParam { - public: - virtual void SetUp() override { - mService = ITuner::getService(GetParam()); - ASSERT_NE(mService, nullptr); - initFrontendConfig(); - initFrontendScanConfig(); - initFilterConfig(); - } - - sp mService; - - protected: - static AssertionResult failure() { return ::testing::AssertionFailure(); } - - static AssertionResult success() { return ::testing::AssertionSuccess(); } - - static void description(const std::string& description) { - RecordProperty("description", description); - } - - sp mFrontend; - FrontendInfo mFrontendInfo; - sp mFrontendCallback; - sp mDescrambler; - sp mDemux; - sp mDvr; - sp mFilter; - std::map> mFilters; - std::map> mFilterCallbacks; - - sp mFilterCallback; - sp mDvrCallback; - MQDesc mFilterMQDescriptor; - MQDesc mDvrMQDescriptor; - MQDesc mRecordMQDescriptor; - vector mUsedFilterIds; - hidl_vec mFeIds; - - uint32_t mDemuxId; - uint32_t mFilterId = -1; - - pthread_t mPlaybackshread; - bool mPlaybackThreadRunning; - - AssertionResult getFrontendIds(); - AssertionResult getFrontendInfo(uint32_t frontendId); - AssertionResult openFrontendById(uint32_t frontendId); - AssertionResult setFrontendCallback(); - AssertionResult scanFrontend(FrontendConfig config, FrontendScanType type); - AssertionResult stopScanFrontend(); - AssertionResult tuneFrontend(FrontendConfig config); - AssertionResult stopTuneFrontend(); - AssertionResult closeFrontend(); - - AssertionResult openDemux(); - AssertionResult setDemuxFrontendDataSource(uint32_t frontendId); - AssertionResult closeDemux(); - - AssertionResult openDvrInDemux(DvrType type); - AssertionResult configDvr(DvrSettings setting); - AssertionResult getDvrMQDescriptor(); - - AssertionResult openFilterInDemux(DemuxFilterType type); - AssertionResult getNewlyOpenedFilterId(uint32_t& filterId); - AssertionResult configFilter(DemuxFilterSettings setting, uint32_t filterId); - AssertionResult getFilterMQDescriptor(uint32_t filterId); - AssertionResult startFilter(uint32_t filterId); - AssertionResult stopFilter(uint32_t filterId); - AssertionResult closeFilter(uint32_t filterId); - - AssertionResult createDescrambler(); - AssertionResult closeDescrambler(); - - AssertionResult playbackDataFlowTest(vector filterConf, PlaybackConf playbackConf, - vector goldenOutputFiles); - AssertionResult recordDataFlowTest(vector filterConf, - RecordSettings recordSetting, - vector goldenOutputFiles); - AssertionResult broadcastDataFlowTest(vector goldenOutputFiles); - - void broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf); - void getFrontendIdByType(FrontendType feType, uint32_t& feId); - void scanTest(FrontendConfig frontend, FrontendScanType type); - - FilterEventType getFilterEventType(DemuxFilterType type); -}; - -/*========================== Start Frontend APIs Tests Implementation ==========================*/ -AssertionResult TunerHidlTest::getFrontendIds() { - Result status; - mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { - status = result; - mFeIds = frontendIds; - }); - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::getFrontendInfo(uint32_t frontendId) { - Result status; - mService->getFrontendInfo(frontendId, [&](Result result, const FrontendInfo& frontendInfo) { - mFrontendInfo = frontendInfo; - status = result; - }); - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::openFrontendById(uint32_t frontendId) { - Result status; - mService->openFrontendById(frontendId, [&](Result result, const sp& frontend) { - mFrontend = frontend; - status = result; - }); - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::setFrontendCallback() { - EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; - mFrontendCallback = new FrontendCallback(); - auto callbackStatus = mFrontend->setCallback(mFrontendCallback); - return AssertionResult(callbackStatus.isOk()); -} - -AssertionResult TunerHidlTest::scanFrontend(FrontendConfig config, FrontendScanType type) { - EXPECT_TRUE(mFrontendCallback) - << "test with openFrontendById/setFrontendCallback/getFrontendInfo first."; - - EXPECT_TRUE(mFrontendInfo.type == config.type) - << "FrontendConfig does not match the frontend info of the given id."; - - mFrontendCallback->scanTest(mFrontend, config, type); - return AssertionResult(true); -} - -AssertionResult TunerHidlTest::stopScanFrontend() { - EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; - Result status; - status = mFrontend->stopScan(); - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::tuneFrontend(FrontendConfig config) { - EXPECT_TRUE(mFrontendCallback) - << "test with openFrontendById/setFrontendCallback/getFrontendInfo first."; - - EXPECT_TRUE(mFrontendInfo.type == config.type) - << "FrontendConfig does not match the frontend info of the given id."; - - mFrontendCallback->tuneTestOnLock(mFrontend, config.settings); - return AssertionResult(true); -} - -AssertionResult TunerHidlTest::stopTuneFrontend() { - EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; - Result status; - status = mFrontend->stopTune(); - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::closeFrontend() { - EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; - Result status; - status = mFrontend->close(); - mFrontend = nullptr; - mFrontendCallback = nullptr; - return AssertionResult(status == Result::SUCCESS); -} -/*=========================== End Frontend APIs Tests Implementation ===========================*/ - /*============================ Start Demux APIs Tests Implementation ============================*/ AssertionResult TunerHidlTest::openDemux() { Result status; @@ -992,7 +316,6 @@ AssertionResult TunerHidlTest::openDemux() { AssertionResult TunerHidlTest::setDemuxFrontendDataSource(uint32_t frontendId) { EXPECT_TRUE(mDemux) << "Test with openDemux first."; - EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; auto status = mDemux->setFrontendDataSource(frontendId); return AssertionResult(status.isOk()); } @@ -1176,7 +499,6 @@ AssertionResult TunerHidlTest::getDvrMQDescriptor() { /*========================== Start Data Flow Tests Implementation ==========================*/ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutputFiles*/) { - EXPECT_TRUE(mFrontend) << "Test with openFilterInDemux first."; EXPECT_TRUE(mDemux) << "Test with openDemux first."; EXPECT_TRUE(mFilterCallback) << "Test with getFilterMQDescriptor first."; @@ -1334,32 +656,18 @@ AssertionResult TunerHidlTest::recordDataFlowTest(vector filterConf, /*========================= End Data Flow Tests Implementation =========================*/ /*================================= Start Test Module =================================*/ -void TunerHidlTest::getFrontendIdByType(FrontendType feType, uint32_t& feId) { - ASSERT_TRUE(getFrontendIds()); - ASSERT_TRUE(mFeIds.size() > 0); - for (size_t i = 0; i < mFeIds.size(); i++) { - ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != feType) { - continue; - } - feId = mFeIds[i]; - return; - } - feId = INVALID_ID; -} - void TunerHidlTest::broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf) { uint32_t feId; - getFrontendIdByType(frontendConf.type, feId); + mFrontendTests.getFrontendIdByType(frontendConf.type, feId); if (feId == INVALID_ID) { // TODO broadcast test on Cuttlefish needs licensed ts input, // these tests are runnable on vendor device with real frontend module // or with manual ts installing and use DVBT frontend. return; } - ASSERT_TRUE(openFrontendById(feId)); - ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(mFrontendTests.openFrontendById(feId)); + ASSERT_TRUE(mFrontendTests.setFrontendCallback()); ASSERT_TRUE(openDemux()); ASSERT_TRUE(setDemuxFrontendDataSource(feId)); ASSERT_TRUE(openFilterInDemux(filterConf.type)); @@ -1369,25 +677,14 @@ void TunerHidlTest::broadcastSingleFilterTest(FilterConfig filterConf, ASSERT_TRUE(getFilterMQDescriptor(filterId)); ASSERT_TRUE(startFilter(filterId)); // tune test - ASSERT_TRUE(tuneFrontend(frontendConf)); + ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf)); // broadcast data flow test ASSERT_TRUE(broadcastDataFlowTest(goldenOutputFiles)); - ASSERT_TRUE(stopTuneFrontend()); + ASSERT_TRUE(mFrontendTests.stopTuneFrontend()); ASSERT_TRUE(stopFilter(filterId)); ASSERT_TRUE(closeFilter(filterId)); ASSERT_TRUE(closeDemux()); - ASSERT_TRUE(closeFrontend()); -} - -void TunerHidlTest::scanTest(FrontendConfig frontendConf, FrontendScanType scanType) { - uint32_t feId; - getFrontendIdByType(frontendConf.type, feId); - ASSERT_TRUE(feId != INVALID_ID); - ASSERT_TRUE(openFrontendById(feId)); - ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(scanFrontend(frontendConf, scanType)); - ASSERT_TRUE(stopScanFrontend()); - ASSERT_TRUE(closeFrontend()); + ASSERT_TRUE(mFrontendTests.closeFrontend()); } /*================================== End Test Module ==================================*/ @@ -1442,38 +739,29 @@ FilterEventType TunerHidlTest::getFilterEventType(DemuxFilterType type) { /***************************** End Test Implementation *****************************/ /******************************** Start Test Entry **********************************/ -/*============================== Start Frontend Tests ==============================*/ -TEST_P(TunerHidlTest, TuneFrontend) { +TEST_P(TunerFrontendHidlTest, TuneFrontend) { description("Tune one Frontend with specific setting and check Lock event"); - uint32_t feId; - getFrontendIdByType(frontendArray[DVBT].type, feId); - ASSERT_TRUE(feId != INVALID_ID); - ASSERT_TRUE(openFrontendById(feId)); - ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(tuneFrontend(frontendArray[DVBT])); - ASSERT_TRUE(stopTuneFrontend()); - ASSERT_TRUE(closeFrontend()); + mFrontendTests.tuneTest(frontendArray[DVBT]); } -TEST_P(TunerHidlTest, AutoScanFrontend) { +TEST_P(TunerFrontendHidlTest, AutoScanFrontend) { description("Run an auto frontend scan with specific setting and check lock scanMessage"); - scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_AUTO); + mFrontendTests.scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_AUTO); } -TEST_P(TunerHidlTest, BlindScanFrontend) { +TEST_P(TunerFrontendHidlTest, BlindScanFrontend) { description("Run an blind frontend scan with specific setting and check lock scanMessage"); - scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_BLIND); + mFrontendTests.scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_BLIND); } -/*=============================== End Frontend Tests ===============================*/ /*============================ Start Demux/Filter Tests ============================*/ TEST_P(TunerHidlTest, StartFilterInDemux) { description("Open and start a filter in Demux."); uint32_t feId; - getFrontendIdByType(frontendArray[DVBT].type, feId); + mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId); ASSERT_TRUE(feId != INVALID_ID); - ASSERT_TRUE(openFrontendById(feId)); - ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(mFrontendTests.openFrontendById(feId)); + ASSERT_TRUE(mFrontendTests.setFrontendCallback()); ASSERT_TRUE(openDemux()); ASSERT_TRUE(setDemuxFrontendDataSource(feId)); ASSERT_TRUE(openFilterInDemux(filterArray[TS_VIDEO0].type)); @@ -1485,7 +773,7 @@ TEST_P(TunerHidlTest, StartFilterInDemux) { ASSERT_TRUE(stopFilter(filterId)); ASSERT_TRUE(closeFilter(filterId)); ASSERT_TRUE(closeDemux()); - ASSERT_TRUE(closeFrontend()); + ASSERT_TRUE(mFrontendTests.closeFrontend()); } /*============================ End Demux/Filter Tests ============================*/ @@ -1614,9 +902,13 @@ TEST_P(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) { }*/ /*============================== End Data Flow Tests ==============================*/ /******************************** End Test Entry **********************************/ -} // namespace +INSTANTIATE_TEST_SUITE_P( + PerInstance, TunerFrontendHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), + android::hardware::PrintInstanceNameToString); INSTANTIATE_TEST_SUITE_P( PerInstance, TunerHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), android::hardware::PrintInstanceNameToString); +} // namespace diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h new file mode 100644 index 0000000000..4d6715eeb7 --- /dev/null +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h @@ -0,0 +1,333 @@ +/* + * Copyright 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FrontendTests.h" + +using android::hardware::EventFlag; +using android::hardware::kSynchronizedReadWrite; +using android::hardware::MessageQueue; +using android::hardware::MQDescriptorSync; +using android::hardware::tv::tuner::V1_0::DataFormat; +using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterMainType; +using android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterStatus; +using android::hardware::tv::tuner::V1_0::DemuxFilterType; +using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; +using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings; +using android::hardware::tv::tuner::V1_0::DemuxTsFilterType; +using android::hardware::tv::tuner::V1_0::DvrSettings; +using android::hardware::tv::tuner::V1_0::DvrType; +using android::hardware::tv::tuner::V1_0::IDemux; +using android::hardware::tv::tuner::V1_0::IDescrambler; +using android::hardware::tv::tuner::V1_0::IDvr; +using android::hardware::tv::tuner::V1_0::IDvrCallback; +using android::hardware::tv::tuner::V1_0::IFilter; +using android::hardware::tv::tuner::V1_0::IFilterCallback; +using android::hardware::tv::tuner::V1_0::PlaybackSettings; +using android::hardware::tv::tuner::V1_0::PlaybackStatus; +using android::hardware::tv::tuner::V1_0::RecordSettings; +using android::hardware::tv::tuner::V1_0::RecordStatus; + +using FilterMQ = MessageQueue; +using MQDesc = MQDescriptorSync; + +const uint32_t FMQ_SIZE_1M = 0x100000; +const uint32_t FMQ_SIZE_16M = 0x1000000; + +enum FilterEventType : uint8_t { + UNDEFINED, + SECTION, + MEDIA, + PES, + RECORD, + MMTPRECORD, + DOWNLOAD, + TEMI, +}; + +struct PlaybackConf { + string inputDataFile; + PlaybackSettings setting; +}; + +static AssertionResult failure() { + return ::testing::AssertionFailure(); +} + +static AssertionResult success() { + return ::testing::AssertionSuccess(); +} + +namespace { + +class FilterCallback : public IFilterCallback { + public: + virtual Return onFilterEvent(const DemuxFilterEvent& filterEvent) override { + android::Mutex::Autolock autoLock(mMsgLock); + // Temprarily we treat the first coming back filter data on the matching pid a success + // once all of the MQ are cleared, means we got all the expected output + mFilterEvent = filterEvent; + readFilterEventData(); + mPidFilterOutputCount++; + // mFilterIdToMQ.erase(filterEvent.filterId); + + // startFilterEventThread(filterEvent); + mMsgCondition.signal(); + return Void(); + } + + virtual Return onFilterStatus(const DemuxFilterStatus /*status*/) override { + return Void(); + } + + void setFilterId(uint32_t filterId) { mFilterId = filterId; } + void setFilterInterface(sp filter) { mFilter = filter; } + void setFilterEventType(FilterEventType type) { mFilterEventType = type; } + + void testFilterDataOutput(); + + void startFilterEventThread(DemuxFilterEvent event); + static void* __threadLoopFilter(void* threadArgs); + void filterThreadLoop(DemuxFilterEvent& event); + + void updateFilterMQ(MQDesc& filterMQDescriptor); + void updateGoldenOutputMap(string goldenOutputFile); + bool readFilterEventData(); + bool dumpAvData(DemuxFilterMediaEvent event); + + private: + struct FilterThreadArgs { + FilterCallback* user; + DemuxFilterEvent event; + }; + uint16_t mDataLength = 0; + std::vector mDataOutputBuffer; + + string mFilterIdToGoldenOutput; + + uint32_t mFilterId; + sp mFilter; + FilterEventType mFilterEventType; + std::unique_ptr mFilterMQ; + EventFlag* mFilterMQEventFlag; + DemuxFilterEvent mFilterEvent; + + android::Mutex mMsgLock; + android::Mutex mFilterOutputLock; + android::Condition mMsgCondition; + android::Condition mFilterOutputCondition; + + pthread_t mFilterThread; + + int mPidFilterOutputCount = 0; +}; + +class DvrCallback : public IDvrCallback { + public: + virtual Return onRecordStatus(DemuxFilterStatus status) override { + ALOGW("[vts] record status %hhu", status); + switch (status) { + case DemuxFilterStatus::DATA_READY: + break; + case DemuxFilterStatus::LOW_WATER: + break; + case DemuxFilterStatus::HIGH_WATER: + case DemuxFilterStatus::OVERFLOW: + ALOGW("[vts] record overflow. Flushing"); + break; + } + return Void(); + } + + virtual Return onPlaybackStatus(PlaybackStatus status) override { + // android::Mutex::Autolock autoLock(mMsgLock); + ALOGW("[vts] playback status %d", status); + switch (status) { + case PlaybackStatus::SPACE_EMPTY: + case PlaybackStatus::SPACE_ALMOST_EMPTY: + ALOGW("[vts] keep playback inputing %d", status); + mKeepWritingPlaybackFMQ = true; + break; + case PlaybackStatus::SPACE_ALMOST_FULL: + case PlaybackStatus::SPACE_FULL: + ALOGW("[vts] stop playback inputing %d", status); + mKeepWritingPlaybackFMQ = false; + break; + } + return Void(); + } + + void testFilterDataOutput(); + void stopPlaybackThread(); + void testRecordOutput(); + void stopRecordThread(); + + void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor); + void startRecordOutputThread(RecordSettings recordSetting, MQDesc& recordMQDescriptor); + static void* __threadLoopPlayback(void* threadArgs); + static void* __threadLoopRecord(void* threadArgs); + void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ); + void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ); + + bool readRecordFMQ(); + + private: + struct PlaybackThreadArgs { + DvrCallback* user; + PlaybackConf* playbackConf; + bool* keepWritingPlaybackFMQ; + }; + struct RecordThreadArgs { + DvrCallback* user; + RecordSettings* recordSetting; + bool* keepReadingRecordFMQ; + }; + uint16_t mDataLength = 0; + std::vector mDataOutputBuffer; + + std::map> mFilterMQ; + std::unique_ptr mPlaybackMQ; + std::unique_ptr mRecordMQ; + std::map mFilterMQEventFlag; + + android::Mutex mMsgLock; + android::Mutex mPlaybackThreadLock; + android::Mutex mRecordThreadLock; + android::Condition mMsgCondition; + + bool mKeepWritingPlaybackFMQ = true; + bool mKeepReadingRecordFMQ = true; + bool mPlaybackThreadRunning; + bool mRecordThreadRunning; + pthread_t mPlaybackThread; + pthread_t mRecordThread; + + int mPidFilterOutputCount = 0; +}; + +class TunerFrontendHidlTest : public testing::TestWithParam { + public: + sp mService; + FrontendTests mFrontendTests; + + virtual void SetUp() override { + mService = ITuner::getService(GetParam()); + ASSERT_NE(mService, nullptr); + initFrontendConfig(); + initFrontendScanConfig(); + + mFrontendTests.setService(mService); + } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } +}; + +class TunerHidlTest : public testing::TestWithParam { + public: + sp mService; + FrontendTests mFrontendTests; + + virtual void SetUp() override { + mService = ITuner::getService(GetParam()); + ASSERT_NE(mService, nullptr); + initFrontendConfig(); + initFrontendScanConfig(); + initFilterConfig(); + + mFrontendTests.setService(mService); + } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp mDescrambler; + + sp mDemux; + sp mDvr; + sp mFilter; + std::map> mFilters; + std::map> mFilterCallbacks; + + sp mFilterCallback; + sp mDvrCallback; + MQDesc mFilterMQDescriptor; + MQDesc mDvrMQDescriptor; + MQDesc mRecordMQDescriptor; + vector mUsedFilterIds; + hidl_vec mFeIds; + + uint32_t mDemuxId; + uint32_t mFilterId = -1; + + pthread_t mPlaybackshread; + bool mPlaybackThreadRunning; + + AssertionResult openDemux(); + AssertionResult setDemuxFrontendDataSource(uint32_t frontendId); + AssertionResult closeDemux(); + + AssertionResult openDvrInDemux(DvrType type); + AssertionResult configDvr(DvrSettings setting); + AssertionResult getDvrMQDescriptor(); + + AssertionResult openFilterInDemux(DemuxFilterType type); + AssertionResult getNewlyOpenedFilterId(uint32_t& filterId); + AssertionResult configFilter(DemuxFilterSettings setting, uint32_t filterId); + AssertionResult getFilterMQDescriptor(uint32_t filterId); + AssertionResult startFilter(uint32_t filterId); + AssertionResult stopFilter(uint32_t filterId); + AssertionResult closeFilter(uint32_t filterId); + + AssertionResult createDescrambler(); + AssertionResult closeDescrambler(); + + AssertionResult playbackDataFlowTest(vector filterConf, PlaybackConf playbackConf, + vector goldenOutputFiles); + AssertionResult recordDataFlowTest(vector filterConf, + RecordSettings recordSetting, + vector goldenOutputFiles); + AssertionResult broadcastDataFlowTest(vector goldenOutputFiles); + + void broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf); + + FilterEventType getFilterEventType(DemuxFilterType type); +}; +} // namespace \ No newline at end of file From 4f6980571a8430eb0c13c033822c470c0aa66a1b Mon Sep 17 00:00:00 2001 From: Amy Zhang Date: Tue, 7 Apr 2020 13:43:05 -0700 Subject: [PATCH 0839/1022] Separate Demux and Filter fixture classes from the Tuner HAL VTS target test Test: atest VtsHalTvTunerV1_0TargetTest Bug: 150953857 Change-Id: I373c3ba56ab80e02c79d24f865a956dae4b44226 --- tv/tuner/1.0/vts/functional/Android.bp | 2 + tv/tuner/1.0/vts/functional/DemuxTests.cpp | 41 ++ tv/tuner/1.0/vts/functional/DemuxTests.h | 57 +++ tv/tuner/1.0/vts/functional/FilterTests.cpp | 226 +++++++++++ tv/tuner/1.0/vts/functional/FilterTests.h | 226 +++++++++++ tv/tuner/1.0/vts/functional/FrontendTests.cpp | 2 +- tv/tuner/1.0/vts/functional/FrontendTests.h | 3 - .../VtsHalTvTunerV1_0TargetTest.cpp | 363 +++--------------- .../functional/VtsHalTvTunerV1_0TargetTest.h | 199 +++------- 9 files changed, 663 insertions(+), 456 deletions(-) create mode 100644 tv/tuner/1.0/vts/functional/DemuxTests.cpp create mode 100644 tv/tuner/1.0/vts/functional/DemuxTests.h create mode 100644 tv/tuner/1.0/vts/functional/FilterTests.cpp create mode 100644 tv/tuner/1.0/vts/functional/FilterTests.h diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp index b4dbda7896..448575ea7a 100644 --- a/tv/tuner/1.0/vts/functional/Android.bp +++ b/tv/tuner/1.0/vts/functional/Android.bp @@ -20,6 +20,8 @@ cc_test { srcs: [ "VtsHalTvTunerV1_0TargetTest.cpp", "FrontendTests.cpp", + "DemuxTests.cpp", + "FilterTests.cpp", ], static_libs: [ "android.hardware.tv.tuner@1.0", diff --git a/tv/tuner/1.0/vts/functional/DemuxTests.cpp b/tv/tuner/1.0/vts/functional/DemuxTests.cpp new file mode 100644 index 0000000000..b1d8a0a0b2 --- /dev/null +++ b/tv/tuner/1.0/vts/functional/DemuxTests.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 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 "DemuxTests.h" + +AssertionResult DemuxTests::openDemux(sp& demux, uint32_t& demuxId) { + Result status; + mService->openDemux([&](Result result, uint32_t id, const sp& demuxSp) { + mDemux = demuxSp; + demux = demuxSp; + demuxId = id; + status = result; + }); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult DemuxTests::setDemuxFrontendDataSource(uint32_t frontendId) { + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + auto status = mDemux->setFrontendDataSource(frontendId); + return AssertionResult(status.isOk()); +} + +AssertionResult DemuxTests::closeDemux() { + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + auto status = mDemux->close(); + mDemux = nullptr; + return AssertionResult(status.isOk()); +} \ No newline at end of file diff --git a/tv/tuner/1.0/vts/functional/DemuxTests.h b/tv/tuner/1.0/vts/functional/DemuxTests.h new file mode 100644 index 0000000000..f405a79ae8 --- /dev/null +++ b/tv/tuner/1.0/vts/functional/DemuxTests.h @@ -0,0 +1,57 @@ +/* + * Copyright 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using android::sp; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::tv::tuner::V1_0::IDemux; +using android::hardware::tv::tuner::V1_0::ITuner; +using android::hardware::tv::tuner::V1_0::Result; + +using ::testing::AssertionResult; + +class DemuxTests { + public: + sp mService; + + void setService(sp tuner) { mService = tuner; } + + AssertionResult openDemux(sp& demux, uint32_t& demuxId); + AssertionResult setDemuxFrontendDataSource(uint32_t frontendId); + AssertionResult closeDemux(); + + protected: + static AssertionResult failure() { return ::testing::AssertionFailure(); } + + static AssertionResult success() { return ::testing::AssertionSuccess(); } + + sp mDemux; +}; \ No newline at end of file diff --git a/tv/tuner/1.0/vts/functional/FilterTests.cpp b/tv/tuner/1.0/vts/functional/FilterTests.cpp new file mode 100644 index 0000000000..82e955d90e --- /dev/null +++ b/tv/tuner/1.0/vts/functional/FilterTests.cpp @@ -0,0 +1,226 @@ +/* + * Copyright 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 "FilterTests.h" + +void FilterCallback::startFilterEventThread(DemuxFilterEvent event) { + struct FilterThreadArgs* threadArgs = + (struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs)); + threadArgs->user = this; + threadArgs->event = event; + + pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs); + pthread_setname_np(mFilterThread, "test_playback_input_loop"); +} + +void FilterCallback::testFilterDataOutput() { + android::Mutex::Autolock autoLock(mMsgLock); + while (mPidFilterOutputCount < 1) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "filter output matching pid does not output within timeout"; + return; + } + } + mPidFilterOutputCount = 0; + ALOGW("[vts] pass and stop"); +} + +void FilterCallback::updateFilterMQ(MQDesc& filterMQDescriptor) { + mFilterMQ = std::make_unique(filterMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(mFilterMQ); + EXPECT_TRUE(EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag) == + android::OK); +} + +void FilterCallback::updateGoldenOutputMap(string goldenOutputFile) { + mFilterIdToGoldenOutput = goldenOutputFile; +} + +void* FilterCallback::__threadLoopFilter(void* threadArgs) { + FilterCallback* const self = + static_cast(((struct FilterThreadArgs*)threadArgs)->user); + self->filterThreadLoop(((struct FilterThreadArgs*)threadArgs)->event); + return 0; +} + +void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) { + android::Mutex::Autolock autoLock(mFilterOutputLock); + // Read from mFilterMQ[event.filterId] per event and filter type + + // Assemble to filterOutput[filterId] + + // check if filterOutput[filterId] matches goldenOutput[filterId] + + // If match, remove filterId entry from MQ map + + // end thread +} + +bool FilterCallback::readFilterEventData() { + bool result = false; + DemuxFilterEvent filterEvent = mFilterEvent; + ALOGW("[vts] reading from filter FMQ or buffer %d", mFilterId); + // todo separate filter handlers + for (int i = 0; i < filterEvent.events.size(); i++) { + switch (mFilterEventType) { + case FilterEventType::SECTION: + mDataLength = filterEvent.events[i].section().dataLength; + break; + case FilterEventType::PES: + mDataLength = filterEvent.events[i].pes().dataLength; + break; + case FilterEventType::MEDIA: + return dumpAvData(filterEvent.events[i].media()); + case FilterEventType::RECORD: + break; + case FilterEventType::MMTPRECORD: + break; + case FilterEventType::DOWNLOAD: + break; + default: + break; + } + // EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not + // match"; + + mDataOutputBuffer.resize(mDataLength); + result = mFilterMQ->read(mDataOutputBuffer.data(), mDataLength); + EXPECT_TRUE(result) << "can't read from Filter MQ"; + + /*for (int i = 0; i < mDataLength; i++) { + EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match"; + }*/ + } + mFilterMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); + return result; +} + +bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) { + uint32_t length = event.dataLength; + uint64_t dataId = event.avDataId; + // read data from buffer pointed by a handle + hidl_handle handle = event.avMemory; + + int av_fd = handle.getNativeHandle()->data[0]; + uint8_t* buffer = static_cast( + mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0 /*offset*/)); + if (buffer == MAP_FAILED) { + ALOGE("[vts] fail to allocate av buffer, errno=%d", errno); + return false; + } + uint8_t output[length + 1]; + memcpy(output, buffer, length); + // print buffer and check with golden output. + EXPECT_TRUE(mFilter->releaseAvHandle(handle, dataId) == Result::SUCCESS); + return true; +} + +AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type) { + Result status; + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + + // Create demux callback + mFilterCallback = new FilterCallback(); + + // Add filter to the local demux + mDemux->openFilter(type, FMQ_SIZE_16M, mFilterCallback, + [&](Result result, const sp& filter) { + mFilter = filter; + status = result; + }); + + if (status == Result::SUCCESS) { + mFilterCallback->setFilterEventType(getFilterEventType(type)); + } + + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FilterTests::getNewlyOpenedFilterId(uint32_t& filterId) { + Result status; + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + EXPECT_TRUE(mFilter) << "Test with openFilterInDemux first."; + EXPECT_TRUE(mFilterCallback) << "Test with openFilterInDemux first."; + + mFilter->getId([&](Result result, uint32_t filterId) { + mFilterId = filterId; + status = result; + }); + + if (status == Result::SUCCESS) { + mFilterCallback->setFilterId(mFilterId); + mFilterCallback->setFilterInterface(mFilter); + mUsedFilterIds.insert(mUsedFilterIds.end(), mFilterId); + mFilters[mFilterId] = mFilter; + mFilterCallbacks[mFilterId] = mFilterCallback; + filterId = mFilterId; + } + + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FilterTests::configFilter(DemuxFilterSettings setting, uint32_t filterId) { + Result status; + EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; + status = mFilters[filterId]->configure(setting); + + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FilterTests::getFilterMQDescriptor(uint32_t filterId) { + Result status; + EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; + EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first."; + + mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) { + mFilterMQDescriptor = filterMQDesc; + status = result; + }); + + if (status == Result::SUCCESS) { + mFilterCallbacks[filterId]->updateFilterMQ(mFilterMQDescriptor); + } + + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FilterTests::startFilter(uint32_t filterId) { + EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; + Result status = mFilters[filterId]->start(); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FilterTests::stopFilter(uint32_t filterId) { + EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; + Result status = mFilters[filterId]->stop(); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FilterTests::closeFilter(uint32_t filterId) { + EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; + Result status = mFilters[filterId]->close(); + if (status == Result::SUCCESS) { + for (int i = 0; i < mUsedFilterIds.size(); i++) { + if (mUsedFilterIds[i] == filterId) { + mUsedFilterIds.erase(mUsedFilterIds.begin() + i); + break; + } + } + mFilterCallbacks.erase(filterId); + mFilters.erase(filterId); + } + return AssertionResult(status == Result::SUCCESS); +} \ No newline at end of file diff --git a/tv/tuner/1.0/vts/functional/FilterTests.h b/tv/tuner/1.0/vts/functional/FilterTests.h new file mode 100644 index 0000000000..eab963bc34 --- /dev/null +++ b/tv/tuner/1.0/vts/functional/FilterTests.h @@ -0,0 +1,226 @@ +/* + * Copyright 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using android::Condition; +using android::Mutex; +using android::sp; +using android::hardware::EventFlag; +using android::hardware::hidl_handle; +using android::hardware::hidl_string; +using android::hardware::hidl_vec; +using android::hardware::kSynchronizedReadWrite; +using android::hardware::MessageQueue; +using android::hardware::MQDescriptorSync; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterMainType; +using android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterStatus; +using android::hardware::tv::tuner::V1_0::DemuxFilterType; +using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; +using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings; +using android::hardware::tv::tuner::V1_0::DemuxTsFilterType; +using android::hardware::tv::tuner::V1_0::IDemux; +using android::hardware::tv::tuner::V1_0::IFilter; +using android::hardware::tv::tuner::V1_0::IFilterCallback; +using android::hardware::tv::tuner::V1_0::ITuner; +using android::hardware::tv::tuner::V1_0::Result; + +using ::testing::AssertionResult; + +enum FilterEventType : uint8_t { + UNDEFINED, + SECTION, + MEDIA, + PES, + RECORD, + MMTPRECORD, + DOWNLOAD, + TEMI, +}; + +using FilterMQ = MessageQueue; +using MQDesc = MQDescriptorSync; + +const uint32_t FMQ_SIZE_1M = 0x100000; +const uint32_t FMQ_SIZE_16M = 0x1000000; + +#define WAIT_TIMEOUT 3000000000 + +class FilterCallback : public IFilterCallback { + public: + virtual Return onFilterEvent(const DemuxFilterEvent& filterEvent) override { + android::Mutex::Autolock autoLock(mMsgLock); + // Temprarily we treat the first coming back filter data on the matching pid a success + // once all of the MQ are cleared, means we got all the expected output + mFilterEvent = filterEvent; + readFilterEventData(); + mPidFilterOutputCount++; + // mFilterIdToMQ.erase(filterEvent.filterId); + + // startFilterEventThread(filterEvent); + mMsgCondition.signal(); + return Void(); + } + + virtual Return onFilterStatus(const DemuxFilterStatus /*status*/) override { + return Void(); + } + + void setFilterId(uint32_t filterId) { mFilterId = filterId; } + void setFilterInterface(sp filter) { mFilter = filter; } + void setFilterEventType(FilterEventType type) { mFilterEventType = type; } + + void testFilterDataOutput(); + + void startFilterEventThread(DemuxFilterEvent event); + static void* __threadLoopFilter(void* threadArgs); + void filterThreadLoop(DemuxFilterEvent& event); + + void updateFilterMQ(MQDesc& filterMQDescriptor); + void updateGoldenOutputMap(string goldenOutputFile); + bool readFilterEventData(); + bool dumpAvData(DemuxFilterMediaEvent event); + + private: + struct FilterThreadArgs { + FilterCallback* user; + DemuxFilterEvent event; + }; + uint16_t mDataLength = 0; + std::vector mDataOutputBuffer; + + string mFilterIdToGoldenOutput; + + uint32_t mFilterId; + sp mFilter; + FilterEventType mFilterEventType; + std::unique_ptr mFilterMQ; + EventFlag* mFilterMQEventFlag; + DemuxFilterEvent mFilterEvent; + + android::Mutex mMsgLock; + android::Mutex mFilterOutputLock; + android::Condition mMsgCondition; + android::Condition mFilterOutputCondition; + + pthread_t mFilterThread; + + int mPidFilterOutputCount = 0; +}; + +class FilterTests { + public: + void setService(sp tuner) { mService = tuner; } + void setDemux(sp demux) { mDemux = demux; } + + std::map> getFilterCallbacks() { return mFilterCallbacks; } + + AssertionResult openFilterInDemux(DemuxFilterType type); + AssertionResult getNewlyOpenedFilterId(uint32_t& filterId); + AssertionResult configFilter(DemuxFilterSettings setting, uint32_t filterId); + AssertionResult getFilterMQDescriptor(uint32_t filterId); + AssertionResult startFilter(uint32_t filterId); + AssertionResult stopFilter(uint32_t filterId); + AssertionResult closeFilter(uint32_t filterId); + + FilterEventType getFilterEventType(DemuxFilterType type) { + FilterEventType eventType = FilterEventType::UNDEFINED; + switch (type.mainType) { + case DemuxFilterMainType::TS: + switch (type.subType.tsFilterType()) { + case DemuxTsFilterType::UNDEFINED: + break; + case DemuxTsFilterType::SECTION: + eventType = FilterEventType::SECTION; + break; + case DemuxTsFilterType::PES: + eventType = FilterEventType::PES; + break; + case DemuxTsFilterType::TS: + break; + case DemuxTsFilterType::AUDIO: + case DemuxTsFilterType::VIDEO: + eventType = FilterEventType::MEDIA; + break; + case DemuxTsFilterType::PCR: + break; + case DemuxTsFilterType::RECORD: + eventType = FilterEventType::RECORD; + break; + case DemuxTsFilterType::TEMI: + eventType = FilterEventType::TEMI; + break; + } + break; + case DemuxFilterMainType::MMTP: + /*mmtpSettings*/ + break; + case DemuxFilterMainType::IP: + /*ipSettings*/ + break; + case DemuxFilterMainType::TLV: + /*tlvSettings*/ + break; + case DemuxFilterMainType::ALP: + /*alpSettings*/ + break; + default: + break; + } + return eventType; + } + + protected: + static AssertionResult failure() { return ::testing::AssertionFailure(); } + + static AssertionResult success() { return ::testing::AssertionSuccess(); } + + sp mService; + sp mFilter; + sp mDemux; + std::map> mFilters; + std::map> mFilterCallbacks; + + sp mFilterCallback; + MQDesc mFilterMQDescriptor; + vector mUsedFilterIds; + + uint32_t mFilterId = -1; +}; \ No newline at end of file diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.cpp b/tv/tuner/1.0/vts/functional/FrontendTests.cpp index 5bc3705fcd..fc5071ceaa 100644 --- a/tv/tuner/1.0/vts/functional/FrontendTests.cpp +++ b/tv/tuner/1.0/vts/functional/FrontendTests.cpp @@ -307,4 +307,4 @@ void FrontendTests::scanTest(FrontendConfig frontendConf, FrontendScanType scanT ASSERT_TRUE(scanFrontend(frontendConf, scanType)); ASSERT_TRUE(stopScanFrontend()); ASSERT_TRUE(closeFrontend()); -} \ No newline at end of file +} diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.h b/tv/tuner/1.0/vts/functional/FrontendTests.h index 5aa6e159f1..701be826d5 100644 --- a/tv/tuner/1.0/vts/functional/FrontendTests.h +++ b/tv/tuner/1.0/vts/functional/FrontendTests.h @@ -45,10 +45,7 @@ using android::MemoryDealer; using android::Mutex; using android::sp; using android::hardware::fromHeap; -using android::hardware::hidl_handle; -using android::hardware::hidl_string; using android::hardware::hidl_vec; -using android::hardware::HidlMemory; using android::hardware::Return; using android::hardware::Void; using android::hardware::tv::tuner::V1_0::FrontendAtscModulation; diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 59c94793ec..d836c26f9f 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -17,119 +17,6 @@ #include "VtsHalTvTunerV1_0TargetTest.h" namespace { -/******************************** Start FilterCallback **********************************/ -void FilterCallback::startFilterEventThread(DemuxFilterEvent event) { - struct FilterThreadArgs* threadArgs = - (struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs)); - threadArgs->user = this; - threadArgs->event = event; - - pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs); - pthread_setname_np(mFilterThread, "test_playback_input_loop"); -} - -void FilterCallback::testFilterDataOutput() { - android::Mutex::Autolock autoLock(mMsgLock); - while (mPidFilterOutputCount < 1) { - if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { - EXPECT_TRUE(false) << "filter output matching pid does not output within timeout"; - return; - } - } - mPidFilterOutputCount = 0; - ALOGW("[vts] pass and stop"); -} - -void FilterCallback::updateFilterMQ(MQDesc& filterMQDescriptor) { - mFilterMQ = std::make_unique(filterMQDescriptor, true /* resetPointers */); - EXPECT_TRUE(mFilterMQ); - EXPECT_TRUE(EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag) == - android::OK); -} - -void FilterCallback::updateGoldenOutputMap(string goldenOutputFile) { - mFilterIdToGoldenOutput = goldenOutputFile; -} - -void* FilterCallback::__threadLoopFilter(void* threadArgs) { - FilterCallback* const self = - static_cast(((struct FilterThreadArgs*)threadArgs)->user); - self->filterThreadLoop(((struct FilterThreadArgs*)threadArgs)->event); - return 0; -} - -void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) { - android::Mutex::Autolock autoLock(mFilterOutputLock); - // Read from mFilterMQ[event.filterId] per event and filter type - - // Assemble to filterOutput[filterId] - - // check if filterOutput[filterId] matches goldenOutput[filterId] - - // If match, remove filterId entry from MQ map - - // end thread -} - -bool FilterCallback::readFilterEventData() { - bool result = false; - DemuxFilterEvent filterEvent = mFilterEvent; - ALOGW("[vts] reading from filter FMQ or buffer %d", mFilterId); - // todo separate filter handlers - for (int i = 0; i < filterEvent.events.size(); i++) { - switch (mFilterEventType) { - case FilterEventType::SECTION: - mDataLength = filterEvent.events[i].section().dataLength; - break; - case FilterEventType::PES: - mDataLength = filterEvent.events[i].pes().dataLength; - break; - case FilterEventType::MEDIA: - return dumpAvData(filterEvent.events[i].media()); - case FilterEventType::RECORD: - break; - case FilterEventType::MMTPRECORD: - break; - case FilterEventType::DOWNLOAD: - break; - default: - break; - } - // EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not - // match"; - - mDataOutputBuffer.resize(mDataLength); - result = mFilterMQ->read(mDataOutputBuffer.data(), mDataLength); - EXPECT_TRUE(result) << "can't read from Filter MQ"; - - /*for (int i = 0; i < mDataLength; i++) { - EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match"; - }*/ - } - mFilterMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); - return result; -} - -bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) { - uint32_t length = event.dataLength; - uint64_t dataId = event.avDataId; - // read data from buffer pointed by a handle - hidl_handle handle = event.avMemory; - - int av_fd = handle.getNativeHandle()->data[0]; - uint8_t* buffer = static_cast( - mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0 /*offset*/)); - if (buffer == MAP_FAILED) { - ALOGE("[vts] fail to allocate av buffer, errno=%d", errno); - return false; - } - uint8_t output[length + 1]; - memcpy(output, buffer, length); - // print buffer and check with golden output. - EXPECT_TRUE(mFilter->releaseAvHandle(handle, dataId) == Result::SUCCESS); - return true; -} -/******************************** End FilterCallback **********************************/ /******************************** Start DvrCallback **********************************/ void DvrCallback::startPlaybackInputThread(PlaybackConf playbackConf, @@ -303,134 +190,9 @@ void DvrCallback::stopRecordThread() { } /********************************** End DvrCallback ************************************/ -/*============================ Start Demux APIs Tests Implementation ============================*/ -AssertionResult TunerHidlTest::openDemux() { - Result status; - mService->openDemux([&](Result result, uint32_t demuxId, const sp& demux) { - mDemux = demux; - mDemuxId = demuxId; - status = result; - }); - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::setDemuxFrontendDataSource(uint32_t frontendId) { - EXPECT_TRUE(mDemux) << "Test with openDemux first."; - auto status = mDemux->setFrontendDataSource(frontendId); - return AssertionResult(status.isOk()); -} - -AssertionResult TunerHidlTest::closeDemux() { - EXPECT_TRUE(mDemux) << "Test with openDemux first."; - auto status = mDemux->close(); - mDemux = nullptr; - return AssertionResult(status.isOk()); -} - -AssertionResult TunerHidlTest::openFilterInDemux(DemuxFilterType type) { - Result status; - EXPECT_TRUE(mDemux) << "Test with openDemux first."; - - // Create demux callback - mFilterCallback = new FilterCallback(); - - // Add filter to the local demux - mDemux->openFilter(type, FMQ_SIZE_16M, mFilterCallback, - [&](Result result, const sp& filter) { - mFilter = filter; - status = result; - }); - - if (status == Result::SUCCESS) { - mFilterCallback->setFilterEventType(getFilterEventType(type)); - } - - return AssertionResult(status == Result::SUCCESS); -} -/*============================ End Demux APIs Tests Implementation ============================*/ - -/*=========================== Start Filter APIs Tests Implementation ===========================*/ -AssertionResult TunerHidlTest::getNewlyOpenedFilterId(uint32_t& filterId) { - Result status; - EXPECT_TRUE(mDemux) << "Test with openDemux first."; - EXPECT_TRUE(mFilter) << "Test with openFilterInDemux first."; - EXPECT_TRUE(mFilterCallback) << "Test with openFilterInDemux first."; - - mFilter->getId([&](Result result, uint32_t filterId) { - mFilterId = filterId; - status = result; - }); - - if (status == Result::SUCCESS) { - mFilterCallback->setFilterId(mFilterId); - mFilterCallback->setFilterInterface(mFilter); - mUsedFilterIds.insert(mUsedFilterIds.end(), mFilterId); - mFilters[mFilterId] = mFilter; - mFilterCallbacks[mFilterId] = mFilterCallback; - filterId = mFilterId; - } - - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::configFilter(DemuxFilterSettings setting, uint32_t filterId) { - Result status; - EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; - status = mFilters[filterId]->configure(setting); - - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::getFilterMQDescriptor(uint32_t filterId) { - Result status; - EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; - EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first."; - - mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) { - mFilterMQDescriptor = filterMQDesc; - status = result; - }); - - if (status == Result::SUCCESS) { - mFilterCallbacks[filterId]->updateFilterMQ(mFilterMQDescriptor); - } - - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::startFilter(uint32_t filterId) { - EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; - Result status = mFilters[filterId]->start(); - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::stopFilter(uint32_t filterId) { - EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; - Result status = mFilters[filterId]->stop(); - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::closeFilter(uint32_t filterId) { - EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; - Result status = mFilters[filterId]->close(); - if (status == Result::SUCCESS) { - for (int i = 0; i < mUsedFilterIds.size(); i++) { - if (mUsedFilterIds[i] == filterId) { - mUsedFilterIds.erase(mUsedFilterIds.begin() + i); - break; - } - } - mFilterCallbacks.erase(filterId); - mFilters.erase(filterId); - } - return AssertionResult(status == Result::SUCCESS); -} -/*=========================== End Filter APIs Tests Implementation ===========================*/ - /*======================== Start Descrambler APIs Tests Implementation ========================*/ AssertionResult TunerHidlTest::createDescrambler() { Result status; - EXPECT_TRUE(mDemux) << "Test with openDemux first."; mService->openDescrambler([&](Result result, const sp& descrambler) { mDescrambler = descrambler; status = result; @@ -464,7 +226,6 @@ AssertionResult TunerHidlTest::closeDescrambler() { /*============================ Start Dvr APIs Tests Implementation ============================*/ AssertionResult TunerHidlTest::openDvrInDemux(DvrType type) { Result status; - EXPECT_TRUE(mDemux) << "Test with openDemux first."; // Create dvr callback mDvrCallback = new DvrCallback(); @@ -485,7 +246,6 @@ AssertionResult TunerHidlTest::configDvr(DvrSettings setting) { AssertionResult TunerHidlTest::getDvrMQDescriptor() { Result status; - EXPECT_TRUE(mDemux) << "Test with openDemux first."; EXPECT_TRUE(mDvr) << "Test with openDvr first."; mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) { @@ -499,12 +259,10 @@ AssertionResult TunerHidlTest::getDvrMQDescriptor() { /*========================== Start Data Flow Tests Implementation ==========================*/ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutputFiles*/) { - EXPECT_TRUE(mDemux) << "Test with openDemux first."; - EXPECT_TRUE(mFilterCallback) << "Test with getFilterMQDescriptor first."; - // Data Verify Module std::map>::iterator it; - for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) { + std::map> filterCallbacks = mFilterTests.getFilterCallbacks(); + for (it = filterCallbacks.begin(); it != filterCallbacks.end(); it++) { it->second->testFilterDataOutput(); } return success(); @@ -668,74 +426,26 @@ void TunerHidlTest::broadcastSingleFilterTest(FilterConfig filterConf, } ASSERT_TRUE(mFrontendTests.openFrontendById(feId)); ASSERT_TRUE(mFrontendTests.setFrontendCallback()); - ASSERT_TRUE(openDemux()); - ASSERT_TRUE(setDemuxFrontendDataSource(feId)); - ASSERT_TRUE(openFilterInDemux(filterConf.type)); + ASSERT_TRUE(mDemuxTests.openDemux(mDemux, mDemuxId)); + mFilterTests.setDemux(mDemux); + ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); + ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type)); uint32_t filterId; - ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); - ASSERT_TRUE(configFilter(filterConf.setting, filterId)); - ASSERT_TRUE(getFilterMQDescriptor(filterId)); - ASSERT_TRUE(startFilter(filterId)); + ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId)); + ASSERT_TRUE(mFilterTests.configFilter(filterConf.setting, filterId)); + ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId)); + ASSERT_TRUE(mFilterTests.startFilter(filterId)); // tune test ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf)); // broadcast data flow test ASSERT_TRUE(broadcastDataFlowTest(goldenOutputFiles)); ASSERT_TRUE(mFrontendTests.stopTuneFrontend()); - ASSERT_TRUE(stopFilter(filterId)); - ASSERT_TRUE(closeFilter(filterId)); - ASSERT_TRUE(closeDemux()); + ASSERT_TRUE(mFilterTests.stopFilter(filterId)); + ASSERT_TRUE(mFilterTests.closeFilter(filterId)); + ASSERT_TRUE(mDemuxTests.closeDemux()); ASSERT_TRUE(mFrontendTests.closeFrontend()); } /*================================== End Test Module ==================================*/ - -/*=============================== Start Helper Functions ===============================*/ -FilterEventType TunerHidlTest::getFilterEventType(DemuxFilterType type) { - FilterEventType eventType = FilterEventType::UNDEFINED; - switch (type.mainType) { - case DemuxFilterMainType::TS: - switch (type.subType.tsFilterType()) { - case DemuxTsFilterType::UNDEFINED: - break; - case DemuxTsFilterType::SECTION: - eventType = FilterEventType::SECTION; - break; - case DemuxTsFilterType::PES: - eventType = FilterEventType::PES; - break; - case DemuxTsFilterType::TS: - break; - case DemuxTsFilterType::AUDIO: - case DemuxTsFilterType::VIDEO: - eventType = FilterEventType::MEDIA; - break; - case DemuxTsFilterType::PCR: - break; - case DemuxTsFilterType::RECORD: - eventType = FilterEventType::RECORD; - break; - case DemuxTsFilterType::TEMI: - eventType = FilterEventType::TEMI; - break; - } - break; - case DemuxFilterMainType::MMTP: - /*mmtpSettings*/ - break; - case DemuxFilterMainType::IP: - /*ipSettings*/ - break; - case DemuxFilterMainType::TLV: - /*tlvSettings*/ - break; - case DemuxFilterMainType::ALP: - /*alpSettings*/ - break; - default: - break; - } - return eventType; -} -/*============================== End Helper Functions ==============================*/ /***************************** End Test Implementation *****************************/ /******************************** Start Test Entry **********************************/ @@ -754,28 +464,39 @@ TEST_P(TunerFrontendHidlTest, BlindScanFrontend) { mFrontendTests.scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_BLIND); } -/*============================ Start Demux/Filter Tests ============================*/ -TEST_P(TunerHidlTest, StartFilterInDemux) { +TEST_P(TunerDemuxHidlTest, openDemux) { + description("Open and close a Demux."); + uint32_t feId; + mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId); + ASSERT_TRUE(feId != INVALID_ID); + ASSERT_TRUE(mFrontendTests.openFrontendById(feId)); + ASSERT_TRUE(mFrontendTests.setFrontendCallback()); + ASSERT_TRUE(mDemuxTests.openDemux(mDemux, mDemuxId)); + ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); + ASSERT_TRUE(mDemuxTests.closeDemux()); +} + +TEST_P(TunerFilterHidlTest, StartFilterInDemux) { description("Open and start a filter in Demux."); uint32_t feId; mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId); ASSERT_TRUE(feId != INVALID_ID); ASSERT_TRUE(mFrontendTests.openFrontendById(feId)); ASSERT_TRUE(mFrontendTests.setFrontendCallback()); - ASSERT_TRUE(openDemux()); - ASSERT_TRUE(setDemuxFrontendDataSource(feId)); - ASSERT_TRUE(openFilterInDemux(filterArray[TS_VIDEO0].type)); + ASSERT_TRUE(mDemuxTests.openDemux(mDemux, mDemuxId)); + mFilterTests.setDemux(mDemux); + ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); + ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_VIDEO0].type)); uint32_t filterId; - ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); - ASSERT_TRUE(configFilter(filterArray[TS_VIDEO0].setting, filterId)); - ASSERT_TRUE(getFilterMQDescriptor(filterId)); - ASSERT_TRUE(startFilter(filterId)); - ASSERT_TRUE(stopFilter(filterId)); - ASSERT_TRUE(closeFilter(filterId)); - ASSERT_TRUE(closeDemux()); + ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId)); + ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_VIDEO0].setting, filterId)); + ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId)); + ASSERT_TRUE(mFilterTests.startFilter(filterId)); + ASSERT_TRUE(mFilterTests.stopFilter(filterId)); + ASSERT_TRUE(mFilterTests.closeFilter(filterId)); + ASSERT_TRUE(mDemuxTests.closeDemux()); ASSERT_TRUE(mFrontendTests.closeFrontend()); } -/*============================ End Demux/Filter Tests ============================*/ /*============================ Start Descrambler Tests ============================*/ /* @@ -911,4 +632,14 @@ INSTANTIATE_TEST_SUITE_P( PerInstance, TunerHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), android::hardware::PrintInstanceNameToString); + +INSTANTIATE_TEST_SUITE_P( + PerInstance, TunerDemuxHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), + android::hardware::PrintInstanceNameToString); + +INSTANTIATE_TEST_SUITE_P( + PerInstance, TunerFilterHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), + android::hardware::PrintInstanceNameToString); } // namespace diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h index 4d6715eeb7..f17704774c 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h @@ -14,70 +14,27 @@ * limitations under the License. */ -#include #include #include #include -#include -#include -#include -#include -#include #include #include -#include +#include "DemuxTests.h" +#include "FilterTests.h" #include "FrontendTests.h" -using android::hardware::EventFlag; -using android::hardware::kSynchronizedReadWrite; -using android::hardware::MessageQueue; -using android::hardware::MQDescriptorSync; using android::hardware::tv::tuner::V1_0::DataFormat; -using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; -using android::hardware::tv::tuner::V1_0::DemuxFilterMainType; -using android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent; -using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; -using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent; -using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings; -using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent; -using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings; -using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; -using android::hardware::tv::tuner::V1_0::DemuxFilterStatus; -using android::hardware::tv::tuner::V1_0::DemuxFilterType; -using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; -using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings; -using android::hardware::tv::tuner::V1_0::DemuxTsFilterType; using android::hardware::tv::tuner::V1_0::DvrSettings; using android::hardware::tv::tuner::V1_0::DvrType; -using android::hardware::tv::tuner::V1_0::IDemux; using android::hardware::tv::tuner::V1_0::IDescrambler; using android::hardware::tv::tuner::V1_0::IDvr; using android::hardware::tv::tuner::V1_0::IDvrCallback; -using android::hardware::tv::tuner::V1_0::IFilter; -using android::hardware::tv::tuner::V1_0::IFilterCallback; using android::hardware::tv::tuner::V1_0::PlaybackSettings; using android::hardware::tv::tuner::V1_0::PlaybackStatus; using android::hardware::tv::tuner::V1_0::RecordSettings; using android::hardware::tv::tuner::V1_0::RecordStatus; -using FilterMQ = MessageQueue; -using MQDesc = MQDescriptorSync; - -const uint32_t FMQ_SIZE_1M = 0x100000; -const uint32_t FMQ_SIZE_16M = 0x1000000; - -enum FilterEventType : uint8_t { - UNDEFINED, - SECTION, - MEDIA, - PES, - RECORD, - MMTPRECORD, - DOWNLOAD, - TEMI, -}; - struct PlaybackConf { string inputDataFile; PlaybackSettings setting; @@ -93,68 +50,6 @@ static AssertionResult success() { namespace { -class FilterCallback : public IFilterCallback { - public: - virtual Return onFilterEvent(const DemuxFilterEvent& filterEvent) override { - android::Mutex::Autolock autoLock(mMsgLock); - // Temprarily we treat the first coming back filter data on the matching pid a success - // once all of the MQ are cleared, means we got all the expected output - mFilterEvent = filterEvent; - readFilterEventData(); - mPidFilterOutputCount++; - // mFilterIdToMQ.erase(filterEvent.filterId); - - // startFilterEventThread(filterEvent); - mMsgCondition.signal(); - return Void(); - } - - virtual Return onFilterStatus(const DemuxFilterStatus /*status*/) override { - return Void(); - } - - void setFilterId(uint32_t filterId) { mFilterId = filterId; } - void setFilterInterface(sp filter) { mFilter = filter; } - void setFilterEventType(FilterEventType type) { mFilterEventType = type; } - - void testFilterDataOutput(); - - void startFilterEventThread(DemuxFilterEvent event); - static void* __threadLoopFilter(void* threadArgs); - void filterThreadLoop(DemuxFilterEvent& event); - - void updateFilterMQ(MQDesc& filterMQDescriptor); - void updateGoldenOutputMap(string goldenOutputFile); - bool readFilterEventData(); - bool dumpAvData(DemuxFilterMediaEvent event); - - private: - struct FilterThreadArgs { - FilterCallback* user; - DemuxFilterEvent event; - }; - uint16_t mDataLength = 0; - std::vector mDataOutputBuffer; - - string mFilterIdToGoldenOutput; - - uint32_t mFilterId; - sp mFilter; - FilterEventType mFilterEventType; - std::unique_ptr mFilterMQ; - EventFlag* mFilterMQEventFlag; - DemuxFilterEvent mFilterEvent; - - android::Mutex mMsgLock; - android::Mutex mFilterOutputLock; - android::Condition mMsgCondition; - android::Condition mFilterOutputCondition; - - pthread_t mFilterThread; - - int mPidFilterOutputCount = 0; -}; - class DvrCallback : public IDvrCallback { public: virtual Return onRecordStatus(DemuxFilterStatus status) override { @@ -240,9 +135,6 @@ class DvrCallback : public IDvrCallback { class TunerFrontendHidlTest : public testing::TestWithParam { public: - sp mService; - FrontendTests mFrontendTests; - virtual void SetUp() override { mService = ITuner::getService(GetParam()); ASSERT_NE(mService, nullptr); @@ -256,12 +148,69 @@ class TunerFrontendHidlTest : public testing::TestWithParam { static void description(const std::string& description) { RecordProperty("description", description); } + + sp mService; + FrontendTests mFrontendTests; +}; + +class TunerDemuxHidlTest : public testing::TestWithParam { + public: + virtual void SetUp() override { + mService = ITuner::getService(GetParam()); + ASSERT_NE(mService, nullptr); + initFrontendConfig(); + initFrontendScanConfig(); + initFilterConfig(); + + mFrontendTests.setService(mService); + mDemuxTests.setService(mService); + } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp mService; + FrontendTests mFrontendTests; + DemuxTests mDemuxTests; + sp mDemux; + uint32_t mDemuxId; +}; + +class TunerFilterHidlTest : public testing::TestWithParam { + public: + virtual void SetUp() override { + mService = ITuner::getService(GetParam()); + ASSERT_NE(mService, nullptr); + initFrontendConfig(); + initFrontendScanConfig(); + initFilterConfig(); + + mFrontendTests.setService(mService); + mDemuxTests.setService(mService); + mFilterTests.setService(mService); + } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp mService; + FrontendTests mFrontendTests; + DemuxTests mDemuxTests; + FilterTests mFilterTests; + sp mDemux; + uint32_t mDemuxId; }; class TunerHidlTest : public testing::TestWithParam { public: sp mService; FrontendTests mFrontendTests; + DemuxTests mDemuxTests; + FilterTests mFilterTests; virtual void SetUp() override { mService = ITuner::getService(GetParam()); @@ -271,6 +220,8 @@ class TunerHidlTest : public testing::TestWithParam { initFilterConfig(); mFrontendTests.setService(mService); + mDemuxTests.setService(mService); + mFilterTests.setService(mService); } protected: @@ -279,43 +230,21 @@ class TunerHidlTest : public testing::TestWithParam { } sp mDescrambler; - - sp mDemux; sp mDvr; - sp mFilter; - std::map> mFilters; - std::map> mFilterCallbacks; + sp mDemux; + uint32_t mDemuxId; - sp mFilterCallback; sp mDvrCallback; - MQDesc mFilterMQDescriptor; MQDesc mDvrMQDescriptor; MQDesc mRecordMQDescriptor; - vector mUsedFilterIds; - hidl_vec mFeIds; - - uint32_t mDemuxId; - uint32_t mFilterId = -1; pthread_t mPlaybackshread; bool mPlaybackThreadRunning; - AssertionResult openDemux(); - AssertionResult setDemuxFrontendDataSource(uint32_t frontendId); - AssertionResult closeDemux(); - AssertionResult openDvrInDemux(DvrType type); AssertionResult configDvr(DvrSettings setting); AssertionResult getDvrMQDescriptor(); - AssertionResult openFilterInDemux(DemuxFilterType type); - AssertionResult getNewlyOpenedFilterId(uint32_t& filterId); - AssertionResult configFilter(DemuxFilterSettings setting, uint32_t filterId); - AssertionResult getFilterMQDescriptor(uint32_t filterId); - AssertionResult startFilter(uint32_t filterId); - AssertionResult stopFilter(uint32_t filterId); - AssertionResult closeFilter(uint32_t filterId); - AssertionResult createDescrambler(); AssertionResult closeDescrambler(); @@ -327,7 +256,5 @@ class TunerHidlTest : public testing::TestWithParam { AssertionResult broadcastDataFlowTest(vector goldenOutputFiles); void broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf); - - FilterEventType getFilterEventType(DemuxFilterType type); }; } // namespace \ No newline at end of file From 56e5567aaaa5c76f10de06e68903a894ebf9ae23 Mon Sep 17 00:00:00 2001 From: Kai Date: Mon, 13 Apr 2020 18:07:54 -0700 Subject: [PATCH 0840/1022] Duplicate setting when generate fake data If the statusCode is Ok, we generate the fake data twice which will break the test. Bug: 143234180 Test: atest VehicleHALTest Change-Id: I7754649fb4202239f9eca63a12bc8dd5f2a3d916 --- .../vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 84354c15f8..e99de60ca8 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 @@ -147,9 +147,7 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { // here, since we never send the control signal back, the value of 'updateStatus' flag // does not matter here. auto status = mVehicleClient->setProperty(propValue, updateStatus); - if (status != StatusCode::OK) { - return status; - } + return status; } else if (mHvacPowerProps.count(propValue.prop)) { auto hvacPowerOn = mPropStore->readValueOrNull( toInt(VehicleProperty::HVAC_POWER_ON), From 2d7820a6ef2df58f2417f2ea7bfefe01c763e807 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Fri, 10 Apr 2020 13:22:10 -0700 Subject: [PATCH 0841/1022] Add vintf_fragments to android.hardware.usb@1.0-service Bug: 153739768 Test: presubmit Signed-off-by: Roman Kiryanov Merged-In: I324f226496d7cf1085f0a3687af6054c56c9dbf8 Change-Id: I032144a0774eb1580f9f027496f5bdfcd6abf603 --- usb/1.0/default/Android.bp | 1 + usb/1.0/default/android.hardware.usb@1.0-service.xml | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 usb/1.0/default/android.hardware.usb@1.0-service.xml diff --git a/usb/1.0/default/Android.bp b/usb/1.0/default/Android.bp index 96d24c1e93..98d9064474 100644 --- a/usb/1.0/default/Android.bp +++ b/usb/1.0/default/Android.bp @@ -16,6 +16,7 @@ cc_binary { name: "android.hardware.usb@1.0-service", defaults: ["hidl_defaults"], init_rc: ["android.hardware.usb@1.0-service.rc"], + vintf_fragments: ["android.hardware.usb@1.0-service.xml"], relative_install_path: "hw", vendor: true, srcs: [ diff --git a/usb/1.0/default/android.hardware.usb@1.0-service.xml b/usb/1.0/default/android.hardware.usb@1.0-service.xml new file mode 100644 index 0000000000..971c8722c0 --- /dev/null +++ b/usb/1.0/default/android.hardware.usb@1.0-service.xml @@ -0,0 +1,11 @@ + + + android.hardware.usb + hwbinder + 1.0 + + IUsb + default + + + From 761c93e3b993f046aab8a867afdfea0a4a8844db Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Thu, 9 Apr 2020 14:17:54 -0700 Subject: [PATCH 0842/1022] Add vintf_fragments to android.hardware.biometrics.fingerprint@2.1-service Bug: 144386336 Test: boot emulator, lshal | grep fingerprint Signed-off-by: Roman Kiryanov Merged-In: I97ad0451bb3edfe85d33300baaa41c3fbc5c3cc6 Change-Id: I11c8ebea731f5e7b24ee483d20a8cd25fd01be38 --- biometrics/fingerprint/2.1/default/Android.bp | 1 + ...id.hardware.biometrics.fingerprint@2.1-service.xml | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.xml diff --git a/biometrics/fingerprint/2.1/default/Android.bp b/biometrics/fingerprint/2.1/default/Android.bp index 497fa3fe0d..ec4838bd9d 100644 --- a/biometrics/fingerprint/2.1/default/Android.bp +++ b/biometrics/fingerprint/2.1/default/Android.bp @@ -2,6 +2,7 @@ cc_binary { name: "android.hardware.biometrics.fingerprint@2.1-service", defaults: ["hidl_defaults"], init_rc: ["android.hardware.biometrics.fingerprint@2.1-service.rc"], + vintf_fragments: ["android.hardware.biometrics.fingerprint@2.1-service.xml"], vendor: true, relative_install_path: "hw", srcs: [ diff --git a/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.xml b/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.xml new file mode 100644 index 0000000000..115dd7b943 --- /dev/null +++ b/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.xml @@ -0,0 +1,11 @@ + + + android.hardware.biometrics.fingerprint + hwbinder + 2.1 + + IBiometricsFingerprint + default + + + From fdbc494c694240b3d1169d35f6c8c74089d775d5 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Tue, 7 Apr 2020 14:38:56 -0700 Subject: [PATCH 0843/1022] Remove references of VtsHalHidlTargetTestBase Bug: 147894326 Test: build Change-Id: If847cc3aa5bb17682b92266f5460efe9d3fadfab --- Android.bp | 14 +++++++++++++- broadcastradio/common/vts/utils/Android.bp | 3 --- tv/tuner/1.0/vts/functional/DemuxTests.h | 4 +--- tv/tuner/1.0/vts/functional/FilterTests.h | 6 +++--- tv/tuner/1.0/vts/functional/FrontendTests.h | 4 ++-- .../VtsHalTvTunerV1_0TestConfigurations.h | 2 ++ wifi/1.0/vts/functional/wifi_hidl_call_util.h | 3 +-- wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp | 2 -- .../1.0/vts/functional/hostapd_hidl_test_utils.cpp | 3 +-- .../vts/functional/supplicant_hidl_test_utils.cpp | 1 - .../functional/supplicant_hidl_test_utils_1_2.cpp | 1 - .../functional/supplicant_p2p_iface_hidl_test.cpp | 2 -- .../functional/supplicant_hidl_test_utils_1_3.cpp | 1 - 13 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Android.bp b/Android.bp index f64968f7b4..9e1df132a7 100644 --- a/Android.bp +++ b/Android.bp @@ -21,7 +21,7 @@ cc_defaults { // Lists all dependencies that can *not* be expected on the device. static_libs: [ - "VtsHalHidlTargetTestBase", + "VtsHalHidlTestUtils", "libhidl-gen-utils", ], @@ -47,3 +47,15 @@ cc_defaults { require_root: true, } + +// TODO: Remove this after all vts tests under vendor/qcom are converted to +// parameterized gtest. +cc_defaults { + name: "Vts10HalTargetTestDefaults", + defaults: [ + "VtsHalTargetTestDefaults", + ], + static_libs: [ + "VtsHalHidlTargetTestBase", + ], +} diff --git a/broadcastradio/common/vts/utils/Android.bp b/broadcastradio/common/vts/utils/Android.bp index d3edc76678..24fea0bb2d 100644 --- a/broadcastradio/common/vts/utils/Android.bp +++ b/broadcastradio/common/vts/utils/Android.bp @@ -25,8 +25,5 @@ cc_library_static { "-Wextra", "-Werror", ], - static_libs: [ - "VtsHalHidlTargetTestBase", - ], group_static_libs: true, } diff --git a/tv/tuner/1.0/vts/functional/DemuxTests.h b/tv/tuner/1.0/vts/functional/DemuxTests.h index f405a79ae8..a72c09fd0c 100644 --- a/tv/tuner/1.0/vts/functional/DemuxTests.h +++ b/tv/tuner/1.0/vts/functional/DemuxTests.h @@ -14,8 +14,6 @@ * limitations under the License. */ -#include -#include #include #include #include @@ -54,4 +52,4 @@ class DemuxTests { static AssertionResult success() { return ::testing::AssertionSuccess(); } sp mDemux; -}; \ No newline at end of file +}; diff --git a/tv/tuner/1.0/vts/functional/FilterTests.h b/tv/tuner/1.0/vts/functional/FilterTests.h index eab963bc34..3cc06e578d 100644 --- a/tv/tuner/1.0/vts/functional/FilterTests.h +++ b/tv/tuner/1.0/vts/functional/FilterTests.h @@ -14,8 +14,6 @@ * limitations under the License. */ -#include -#include #include #include #include @@ -64,6 +62,8 @@ using android::hardware::tv::tuner::V1_0::Result; using ::testing::AssertionResult; +using namespace std; + enum FilterEventType : uint8_t { UNDEFINED, SECTION, @@ -223,4 +223,4 @@ class FilterTests { vector mUsedFilterIds; uint32_t mFilterId = -1; -}; \ No newline at end of file +}; diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.h b/tv/tuner/1.0/vts/functional/FrontendTests.h index 701be826d5..1a9bec9627 100644 --- a/tv/tuner/1.0/vts/functional/FrontendTests.h +++ b/tv/tuner/1.0/vts/functional/FrontendTests.h @@ -14,8 +14,6 @@ * limitations under the License. */ -#include -#include #include #include #include @@ -66,6 +64,8 @@ using android::hardware::tv::tuner::V1_0::Result; using ::testing::AssertionResult; +using namespace std; + #define INVALID_ID -1 #define WAIT_TIMEOUT 3000000000 diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h index 10c60142ba..538773a209 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h @@ -38,6 +38,8 @@ using android::hardware::tv::tuner::V1_0::FrontendDvbtTransmissionMode; using android::hardware::tv::tuner::V1_0::FrontendSettings; using android::hardware::tv::tuner::V1_0::FrontendType; +using namespace std; + typedef enum { TS_VIDEO0, TS_VIDEO1, diff --git a/wifi/1.0/vts/functional/wifi_hidl_call_util.h b/wifi/1.0/vts/functional/wifi_hidl_call_util.h index f3ca517fe6..3be14c33dd 100644 --- a/wifi/1.0/vts/functional/wifi_hidl_call_util.h +++ b/wifi/1.0/vts/functional/wifi_hidl_call_util.h @@ -16,13 +16,12 @@ #pragma once +#include #include #include #include #include -#include - namespace { namespace detail { template diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp index c1542dcb59..3ff33a564b 100644 --- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp +++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp @@ -16,8 +16,6 @@ #include -#include - #include #include "wifi_hidl_call_util.h" diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp index 6058fd2d5f..d4063fe258 100644 --- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp +++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include @@ -148,4 +147,4 @@ bool is_1_1(const sp& hostapd) { sp<::android::hardware::wifi::hostapd::V1_1::IHostapd> hostapd_1_1 = ::android::hardware::wifi::hostapd::V1_1::IHostapd::castFrom(hostapd); return hostapd_1_1.get() != nullptr; -} \ No newline at end of file +} diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp index 6fe6fc5936..38153238b8 100644 --- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp +++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp index 480929af2b..46d5a61156 100644 --- a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp +++ b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include "supplicant_hidl_test_utils.h" diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp index 2b63ad0ea0..7b96b8714a 100644 --- a/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp +++ b/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp @@ -16,8 +16,6 @@ #include -#include - #include #include #include diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp index dbf2b91fe7..424c107bfd 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include "supplicant_hidl_test_utils.h" From 5ba0a90cac5172b5b406971aaf3280afd06c3c03 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Tue, 14 Apr 2020 11:55:42 -0700 Subject: [PATCH 0844/1022] Use additional interface for the WiFi Aware Discovery operations. NAN operations are currently done on the STA interface.This resulted in the NAN sessions getting terminated in all the instances where the STA interface is restarted (IFF DOWN/UP), due to connected MAC randomization. Hence, remove the dependency of NAN over STA interface. This change expects the driver to create a dedicated interface for the NAN operations. The iface name needs to be set in "wifi.aware.interface" property. Bug: 1636219 Test: HAL unit tests Test: Device boots up and connects to wifi network. Change-Id: I1b6d64eb94334172a8cd621d0b15ed8c8dc87f91 --- wifi/1.4/default/Android.mk | 12 +++++----- wifi/1.4/default/tests/mock_wifi_iface_util.h | 1 + wifi/1.4/default/tests/mock_wifi_legacy_hal.h | 4 ++++ .../default/tests/wifi_chip_unit_tests.cpp | 23 +++++++++++++++++++ .../tests/wifi_nan_iface_unit_tests.cpp | 2 +- wifi/1.4/default/wifi_chip.cpp | 22 +++++++++++++++--- wifi/1.4/default/wifi_iface_util.cpp | 8 +++++++ wifi/1.4/default/wifi_iface_util.h | 1 + wifi/1.4/default/wifi_legacy_hal.h | 6 ++--- wifi/1.4/default/wifi_nan_iface.cpp | 15 +++++++++++- wifi/1.4/default/wifi_nan_iface.h | 3 ++- 11 files changed, 82 insertions(+), 15 deletions(-) diff --git a/wifi/1.4/default/Android.mk b/wifi/1.4/default/Android.mk index ab76ff66e2..8573e8e1f5 100644 --- a/wifi/1.4/default/Android.mk +++ b/wifi/1.4/default/Android.mk @@ -156,6 +156,11 @@ LOCAL_SRC_FILES := \ LOCAL_STATIC_LIBRARIES := \ libgmock \ libgtest \ + android.hardware.wifi@1.0 \ + android.hardware.wifi@1.1 \ + android.hardware.wifi@1.2 \ + android.hardware.wifi@1.3 \ + android.hardware.wifi@1.4 \ android.hardware.wifi@1.0-service-lib LOCAL_SHARED_LIBRARIES := \ libbase \ @@ -165,10 +170,5 @@ LOCAL_SHARED_LIBRARIES := \ libnl \ libutils \ libwifi-hal \ - libwifi-system-iface \ - android.hardware.wifi@1.0 \ - android.hardware.wifi@1.1 \ - android.hardware.wifi@1.2 \ - android.hardware.wifi@1.3 \ - android.hardware.wifi@1.4 + libwifi-system-iface include $(BUILD_NATIVE_TEST) diff --git a/wifi/1.4/default/tests/mock_wifi_iface_util.h b/wifi/1.4/default/tests/mock_wifi_iface_util.h index 6cc81e4083..3b36f13b37 100644 --- a/wifi/1.4/default/tests/mock_wifi_iface_util.h +++ b/wifi/1.4/default/tests/mock_wifi_iface_util.h @@ -40,6 +40,7 @@ class MockWifiIfaceUtil : public WifiIfaceUtil { MOCK_METHOD2(registerIfaceEventHandlers, void(const std::string&, IfaceEventHandlers)); MOCK_METHOD1(unregisterIfaceEventHandlers, void(const std::string&)); + MOCK_METHOD2(setUpState, bool(const std::string&, bool)); }; } // namespace iface_util } // namespace implementation diff --git a/wifi/1.4/default/tests/mock_wifi_legacy_hal.h b/wifi/1.4/default/tests/mock_wifi_legacy_hal.h index 6942c1e4e3..3bb7b54760 100644 --- a/wifi/1.4/default/tests/mock_wifi_legacy_hal.h +++ b/wifi/1.4/default/tests/mock_wifi_legacy_hal.h @@ -57,6 +57,10 @@ class MockWifiLegacyHal : public WifiLegacyHal { MOCK_METHOD3(nanDataInterfaceDelete, wifi_error(const std::string&, transaction_id, const std::string&)); + MOCK_METHOD2(createVirtualInterface, + wifi_error(const std::string& ifname, + wifi_interface_type iftype)); + MOCK_METHOD1(deleteVirtualInterface, wifi_error(const std::string& ifname)); }; } // namespace legacy_hal } // namespace implementation diff --git a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp index d35adbc125..d5b1a50ca6 100644 --- a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp +++ b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp @@ -292,6 +292,7 @@ class WifiChipTest : public Test { // mock). property_set("wifi.interface", "wlan0"); property_set("wifi.concurrent.interface", "wlan1"); + property_set("wifi.aware.interface", nullptr); } }; @@ -773,6 +774,28 @@ TEST_F(WifiChipV2_AwareIfaceCombinationTest, }); } +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNanWithSharedNanIface) { + property_set("wifi.aware.interface", nullptr); + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); + ASSERT_EQ(createIface(IfaceType::NAN), "wlan0"); + removeIface(IfaceType::NAN, "wlan0"); + EXPECT_CALL(*iface_util_, setUpState(testing::_, testing::_)).Times(0); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNanWithDedicatedNanIface) { + property_set("wifi.aware.interface", "aware0"); + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); + EXPECT_CALL(*iface_util_, setUpState("aware0", true)) + .WillOnce(testing::Return(true)); + ASSERT_EQ(createIface(IfaceType::NAN), "aware0"); + + EXPECT_CALL(*iface_util_, setUpState("aware0", false)) + .WillOnce(testing::Return(true)); + removeIface(IfaceType::NAN, "aware0"); +} + ////////// V1 Iface Combinations when AP creation is disabled ////////// class WifiChipV1_AwareDisabledApIfaceCombinationTest : public WifiChipTest { public: diff --git a/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp index 90227925dd..70424db815 100644 --- a/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp +++ b/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp @@ -131,7 +131,7 @@ TEST_F(WifiNanIfaceTest, IfacEventHandlers_OnStateToggleOffOn) { bind(CaptureIfaceEventHandlers, std::placeholders::_1, std::placeholders::_2, &captured_iface_event_handlers))); sp nan_iface = - new WifiNanIface(kIfaceName, legacy_hal_, iface_util_); + new WifiNanIface(kIfaceName, false, legacy_hal_, iface_util_); // Register a mock nan event callback. sp> mock_event_callback{ diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp index 4c9fad17bb..d64dfbfd60 100644 --- a/wifi/1.4/default/wifi_chip.cpp +++ b/wifi/1.4/default/wifi_chip.cpp @@ -107,6 +107,15 @@ std::string getP2pIfaceName() { return buffer.data(); } +// Returns the dedicated iface name if one is defined. +std::string getNanIfaceName() { + std::array buffer; + if (property_get("wifi.aware.interface", buffer.data(), nullptr) == 0) { + return {}; + } + return buffer.data(); +} + void setActiveWlanIfaceNameProperty(const std::string& ifname) { auto res = property_set(kActiveWlanIfaceNameProperty, ifname.data()); if (res != 0) { @@ -864,9 +873,16 @@ std::pair> WifiChip::createNanIfaceInternal() { if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::NAN)) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } - // These are still assumed to be based on wlan0. - std::string ifname = getFirstActiveWlanIfaceName(); - sp iface = new WifiNanIface(ifname, legacy_hal_, iface_util_); + bool is_dedicated_iface = true; + std::string ifname = getNanIfaceName(); + if (ifname.empty()) { + // Use the first shared STA iface (wlan0) if a dedicated aware iface is + // not defined. + ifname = getFirstActiveWlanIfaceName(); + is_dedicated_iface = false; + } + sp iface = + new WifiNanIface(ifname, is_dedicated_iface, legacy_hal_, iface_util_); nan_ifaces_.push_back(iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) { diff --git a/wifi/1.4/default/wifi_iface_util.cpp b/wifi/1.4/default/wifi_iface_util.cpp index 2883b4627b..036c97bcba 100644 --- a/wifi/1.4/default/wifi_iface_util.cpp +++ b/wifi/1.4/default/wifi_iface_util.cpp @@ -110,6 +110,14 @@ std::array WifiIfaceUtil::createRandomMacAddress() { address[0] &= ~kMacAddressMulticastMask; return address; } + +bool WifiIfaceUtil::setUpState(const std::string& iface_name, bool request_up) { + if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), request_up)) { + LOG(ERROR) << "SetUpState to " << request_up << " failed"; + return false; + } + return true; +} } // namespace iface_util } // namespace implementation } // namespace V1_4 diff --git a/wifi/1.4/default/wifi_iface_util.h b/wifi/1.4/default/wifi_iface_util.h index 35edff68bd..f83d717bf6 100644 --- a/wifi/1.4/default/wifi_iface_util.h +++ b/wifi/1.4/default/wifi_iface_util.h @@ -56,6 +56,7 @@ class WifiIfaceUtil { virtual void registerIfaceEventHandlers(const std::string& iface_name, IfaceEventHandlers handlers); virtual void unregisterIfaceEventHandlers(const std::string& iface_name); + virtual bool setUpState(const std::string& iface_name, bool request_up); private: std::array createRandomMacAddress(); diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h index c21563ee92..c697ff9682 100644 --- a/wifi/1.4/default/wifi_legacy_hal.h +++ b/wifi/1.4/default/wifi_legacy_hal.h @@ -373,9 +373,9 @@ class WifiLegacyHal { std::array code); // interface functions. - wifi_error createVirtualInterface(const std::string& ifname, - wifi_interface_type iftype); - wifi_error deleteVirtualInterface(const std::string& ifname); + virtual wifi_error createVirtualInterface(const std::string& ifname, + wifi_interface_type iftype); + virtual wifi_error deleteVirtualInterface(const std::string& ifname); private: // Retrieve interface handles for all the available interfaces. diff --git a/wifi/1.4/default/wifi_nan_iface.cpp b/wifi/1.4/default/wifi_nan_iface.cpp index 073101cbd5..5764d35ec4 100644 --- a/wifi/1.4/default/wifi_nan_iface.cpp +++ b/wifi/1.4/default/wifi_nan_iface.cpp @@ -29,13 +29,22 @@ namespace implementation { using hidl_return_util::validateAndCall; WifiNanIface::WifiNanIface( - const std::string& ifname, + const std::string& ifname, bool is_dedicated_iface, const std::weak_ptr legacy_hal, const std::weak_ptr iface_util) : ifname_(ifname), + is_dedicated_iface_(is_dedicated_iface), legacy_hal_(legacy_hal), iface_util_(iface_util), is_valid_(true) { + if (is_dedicated_iface_) { + // If using a dedicated iface, set the iface up first. + if (!iface_util_.lock()->setUpState(ifname_, true)) { + // Fatal failure, invalidate the iface object. + invalidate(); + return; + } + } // Register all the callbacks here. these should be valid for the lifetime // of the object. Whenever the mode changes legacy HAL will remove // all of these callbacks. @@ -534,6 +543,10 @@ void WifiNanIface::invalidate() { event_cb_handler_.invalidate(); event_cb_handler_1_2_.invalidate(); is_valid_ = false; + if (is_dedicated_iface_) { + // If using a dedicated iface, set the iface down. + iface_util_.lock()->setUpState(ifname_, false); + } } bool WifiNanIface::isValid() { return is_valid_; } diff --git a/wifi/1.4/default/wifi_nan_iface.h b/wifi/1.4/default/wifi_nan_iface.h index c16628bbf6..06edbf2609 100644 --- a/wifi/1.4/default/wifi_nan_iface.h +++ b/wifi/1.4/default/wifi_nan_iface.h @@ -38,7 +38,7 @@ using namespace android::hardware::wifi::V1_2; */ class WifiNanIface : public V1_4::IWifiNanIface { public: - WifiNanIface(const std::string& ifname, + WifiNanIface(const std::string& ifname, bool is_dedicated_iface, const std::weak_ptr legacy_hal, const std::weak_ptr iface_util); // Refer to |WifiChip::invalidate()|. @@ -165,6 +165,7 @@ class WifiNanIface : public V1_4::IWifiNanIface { std::set> getEventCallbacks_1_2(); std::string ifname_; + bool is_dedicated_iface_; std::weak_ptr legacy_hal_; std::weak_ptr iface_util_; bool is_valid_; From 51d789e8dd85870adf5c3838962b5eafa98c1185 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Fri, 10 Apr 2020 16:42:50 -0700 Subject: [PATCH 0845/1022] Check against xsd for building all matrices Test: builds Fixes: 149929588 Change-Id: Id08cfe41af59bb336889f9edeaf35dc484892997 (cherry picked from commit fca5d95ce6864c0b3a2ead9ff8e077ad47e3c8a1) Merged-In: Id08cfe41af59bb336889f9edeaf35dc484892997 --- .../build/vintf_compatibility_matrix.go | 65 ++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/compatibility_matrices/build/vintf_compatibility_matrix.go b/compatibility_matrices/build/vintf_compatibility_matrix.go index e48f9931ea..2772ba36e7 100644 --- a/compatibility_matrices/build/vintf_compatibility_matrix.go +++ b/compatibility_matrices/build/vintf_compatibility_matrix.go @@ -40,7 +40,15 @@ var ( Description: "assemble_vintf -i ${inputs}", }, "inputs") - kernelConfigTag = dependencyTag{name: "kernel-config"} + xmllintXsd = pctx.AndroidStaticRule("xmllint-xsd", blueprint.RuleParams{ + Command: `$XmlLintCmd --schema $xsd $in > /dev/null && touch -a $out`, + CommandDeps: []string{"$XmlLintCmd"}, + Restat: true, + }, "xsd") + + kernelConfigTag = dependencyTag{name: "kernel-config"} + schemaTag = dependencyTag{name: "matrix-schema"} + schemaModuleName = "compatibility_matrix_schema" ) const ( @@ -62,11 +70,13 @@ type vintfCompatibilityMatrixRule struct { android.ModuleBase properties vintfCompatibilityMatrixProperties - genFile android.WritablePath + genFile android.WritablePath + additionalDependencies android.WritablePaths } func init() { pctx.HostBinToolVariable("assembleVintfCmd", "assemble_vintf") + pctx.HostBinToolVariable("XmlLintCmd", "xmllint") android.RegisterModuleType("vintf_compatibility_matrix", vintfCompatibilityMatrixFactory) } @@ -82,6 +92,42 @@ var _ android.AndroidMkDataProvider = (*vintfCompatibilityMatrixRule)(nil) func (g *vintfCompatibilityMatrixRule) DepsMutator(ctx android.BottomUpMutatorContext) { android.ExtractSourcesDeps(ctx, g.properties.Srcs) ctx.AddDependency(ctx.Module(), kernelConfigTag, g.properties.Kernel_configs...) + ctx.AddDependency(ctx.Module(), schemaTag, schemaModuleName) +} + +func (g *vintfCompatibilityMatrixRule) timestampFilePath(ctx android.ModuleContext, path android.Path) android.WritablePath { + return android.GenPathWithExt(ctx, "vintf-xmllint", path, "ts") +} + +func (g *vintfCompatibilityMatrixRule) generateValidateBuildAction(ctx android.ModuleContext, path android.Path, schema android.Path) { + timestamp := g.timestampFilePath(ctx, path) + ctx.Build(pctx, android.BuildParams{ + Rule: xmllintXsd, + Description: "xmllint-xsd", + Input: path, + Output: timestamp, + Implicit: schema, + Args: map[string]string{ + "xsd": schema.String(), + }, + }) + g.additionalDependencies = append(g.additionalDependencies, timestamp) +} + +func (g *vintfCompatibilityMatrixRule) getSchema(ctx android.ModuleContext) android.OptionalPath { + schemaModule := ctx.GetDirectDepWithTag(schemaModuleName, schemaTag) + sfp, ok := schemaModule.(android.SourceFileProducer) + if !ok { + ctx.ModuleErrorf("Implicit dependency %q has no srcs", ctx.OtherModuleName(schemaModule)) + return android.OptionalPath{} + } + + schemaSrcs := sfp.Srcs() + if len(schemaSrcs) != 1 { + ctx.PropertyErrorf(`srcs of implicit dependency %q has length %d != 1`, ctx.OtherModuleName(schemaModule), len(schemaSrcs)) + return android.OptionalPath{} + } + return android.OptionalPathForPath(schemaSrcs[0]) } func (g *vintfCompatibilityMatrixRule) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -91,7 +137,18 @@ func (g *vintfCompatibilityMatrixRule) GenerateAndroidBuildActions(ctx android.M outputFilename = g.Name() } + schema := g.getSchema(ctx) + if !schema.Valid() { + return + } + inputPaths := android.PathsForModuleSrc(ctx, g.properties.Srcs) + for _, srcPath := range inputPaths { + g.generateValidateBuildAction(ctx, srcPath, schema.Path()) + } + + // No need to validate matrices from kernel configs because they are generated by + // assemble_vintf. ctx.VisitDirectDepsWithTag(kernelConfigTag, func(m android.Module) { if k, ok := m.(*configs.KernelConfigRule); ok { inputPaths = append(inputPaths, k.OutputPath()) @@ -112,6 +169,7 @@ func (g *vintfCompatibilityMatrixRule) GenerateAndroidBuildActions(ctx android.M "inputs": strings.Join(inputPaths.Strings(), ":"), }, }) + g.generateValidateBuildAction(ctx, g.genFile, schema.Path()) ctx.InstallFile(android.PathForModuleInstall(ctx, "etc", relpath), outputFilename, g.genFile) } @@ -126,6 +184,9 @@ func (g *vintfCompatibilityMatrixRule) AndroidMk() android.AndroidMkData { if proptools.String(g.properties.Stem) != "" { fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", proptools.String(g.properties.Stem)) } + for _, path := range g.additionalDependencies { + fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", path.String()) + } }, }, } From 08c7e7123641efcef65398bf1d16bd368c5fb14a Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Tue, 14 Apr 2020 21:48:11 -0600 Subject: [PATCH 0846/1022] Fix delivery of earlyBootEnded to KM4.1 Bug: 152932559 Test: Boot and observe that Strongbox gets the message Change-Id: I752b44f5cc20d85bf819188ccaaf0813a5607ba5 --- keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h index 75d9139e83..f4957961b4 100644 --- a/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h +++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h @@ -31,17 +31,11 @@ class Keymaster4 : public Keymaster { // enumerate 4.1. devices. using WrappedIKeymasterDevice = V4_0::IKeymasterDevice; - Keymaster4(sp km4_1_dev, const hidl_string& instanceName) - : Keymaster(V4_1::IKeymasterDevice::descriptor, instanceName), - haveVersion_(false), - km4_0_dev_(km4_1_dev), - km4_1_dev_(km4_1_dev) {} - Keymaster4(sp km4_0_dev, const hidl_string& instanceName) : Keymaster(V4_1::IKeymasterDevice::descriptor, instanceName), haveVersion_(false), km4_0_dev_(km4_0_dev), - km4_1_dev_() {} + km4_1_dev_(V4_1::IKeymasterDevice::castFrom(km4_0_dev)) {} const VersionResult& halVersion() const override { const_cast(this)->getVersionIfNeeded(); From 279a5ae37efd63f247162784076c8920da7a1998 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Wed, 15 Apr 2020 10:34:11 -0700 Subject: [PATCH 0847/1022] Add the missing unregisterCallback call The sensor reading thread continues producing event and refers to the already destroyed callback object which causes a crash in SensorsHidlEnvironmentBase::addEvent. Bug: 153754380 Test: atest VtsHalSensorsV2_0TargetTest Signed-off-by: Roman Kiryanov Change-Id: Id7fb72c42dc67f89ceef93d937241e1584b853e7 --- sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h index 745ab2d0d9..75f2c28eaf 100644 --- a/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h +++ b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h @@ -737,6 +737,8 @@ TEST_P(SensorsHidlTest, NoStaleEvents) { callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay)); activateAllSensors(false); + getEnvironment()->unregisterCallback(); + for (const SensorInfoType& sensor : sensors) { // Skip sensors that did not previously report an event if (lastEventTimestampMap.find(sensor.sensorHandle) == lastEventTimestampMap.end()) { From cedd3f387b49d3060a4c8cbc72c41a134638d19e Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 2 Apr 2020 14:30:52 -0700 Subject: [PATCH 0848/1022] VtsHalAudio*TargetTest in vts. Bug: 139438327 Test: N/A Change-Id: I0fb6c966c70cc51cbfd13fd27d6224c9fd07ec20 --- audio/core/all-versions/vts/functional/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp index db52e6095f..729ee7ab4a 100644 --- a/audio/core/all-versions/vts/functional/Android.bp +++ b/audio/core/all-versions/vts/functional/Android.bp @@ -33,7 +33,7 @@ cc_defaults { ], test_suites: [ "general-tests", - "vts-core", + "vts", ], } From 25b3a6f0a42e9f3c7f793dfd06ad431106e078b7 Mon Sep 17 00:00:00 2001 From: Veerendranath Jakkam Date: Tue, 14 Apr 2020 22:04:39 +0530 Subject: [PATCH 0849/1022] Synchronize on_ring_buffer_data_callback and writeRingbufferFiles on_ring_buffer_data_callback callback is invoked on getting the corresponding driver/firmware ringbuffer logs. This callback further stores the ringbuffer data locally in cur_buffer. While the data is getting updated through this callback, writeRingbufferFilesInternal can get triggered from a different context which accesses the same buffer -cur_buffer. Synchronization is missing between these two contexts while accessing the buffer and this commit attempts the same. Bug: 153970986 Test: Manual - collect the bugreport and check the ring buffer logs. Change-Id: Id99a517f4d72872b84b48c3df75dd29743f3e9b2 --- wifi/1.4/default/wifi_chip.cpp | 57 ++++++++++++++++++++-------------- wifi/1.4/default/wifi_chip.h | 2 ++ 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp index d64dfbfd60..23dd13be66 100644 --- a/wifi/1.4/default/wifi_chip.cpp +++ b/wifi/1.4/default/wifi_chip.cpp @@ -1314,13 +1314,18 @@ WifiStatus WifiChip::registerDebugRingBufferCallback() { LOG(ERROR) << "Error converting ring buffer status"; return; } - const auto& target = shared_ptr_this->ringbuffer_map_.find(name); - if (target != shared_ptr_this->ringbuffer_map_.end()) { - Ringbuffer& cur_buffer = target->second; - cur_buffer.append(data); - } else { - LOG(ERROR) << "Ringname " << name << " not found"; - return; + { + std::unique_lock lk(shared_ptr_this->lock_t); + const auto& target = + shared_ptr_this->ringbuffer_map_.find(name); + if (target != shared_ptr_this->ringbuffer_map_.end()) { + Ringbuffer& cur_buffer = target->second; + cur_buffer.append(data); + } else { + LOG(ERROR) << "Ringname " << name << " not found"; + return; + } + // unlock } }; legacy_hal::wifi_error legacy_status = @@ -1595,25 +1600,29 @@ bool WifiChip::writeRingbufferFilesInternal() { return false; } // write ringbuffers to file - for (const auto& item : ringbuffer_map_) { - const Ringbuffer& cur_buffer = item.second; - if (cur_buffer.getData().empty()) { - continue; - } - const std::string file_path_raw = - kTombstoneFolderPath + item.first + "XXXXXXXXXX"; - const int dump_fd = mkstemp(makeCharVec(file_path_raw).data()); - if (dump_fd == -1) { - PLOG(ERROR) << "create file failed"; - return false; - } - unique_fd file_auto_closer(dump_fd); - for (const auto& cur_block : cur_buffer.getData()) { - if (write(dump_fd, cur_block.data(), - sizeof(cur_block[0]) * cur_block.size()) == -1) { - PLOG(ERROR) << "Error writing to file"; + { + std::unique_lock lk(lock_t); + for (const auto& item : ringbuffer_map_) { + const Ringbuffer& cur_buffer = item.second; + if (cur_buffer.getData().empty()) { + continue; + } + const std::string file_path_raw = + kTombstoneFolderPath + item.first + "XXXXXXXXXX"; + const int dump_fd = mkstemp(makeCharVec(file_path_raw).data()); + if (dump_fd == -1) { + PLOG(ERROR) << "create file failed"; + return false; + } + unique_fd file_auto_closer(dump_fd); + for (const auto& cur_block : cur_buffer.getData()) { + if (write(dump_fd, cur_block.data(), + sizeof(cur_block[0]) * cur_block.size()) == -1) { + PLOG(ERROR) << "Error writing to file"; + } } } + // unlock } return true; } diff --git a/wifi/1.4/default/wifi_chip.h b/wifi/1.4/default/wifi_chip.h index 3323ade681..98e18bba07 100644 --- a/wifi/1.4/default/wifi_chip.h +++ b/wifi/1.4/default/wifi_chip.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -272,6 +273,7 @@ class WifiChip : public V1_4::IWifiChip { bool is_valid_; // Members pertaining to chip configuration. uint32_t current_mode_id_; + std::mutex lock_t; std::vector modes_; // The legacy ring buffer callback API has only a global callback // registration mechanism. Use this to check if we have already From baa4cf02f2733bdb8e680a0e8b08e2f14d1bf9eb Mon Sep 17 00:00:00 2001 From: Slava Shklyaev Date: Thu, 16 Apr 2020 14:58:55 +0100 Subject: [PATCH 0850/1022] Exclude unused operands from removeOperandTest Bug: 148208229 Test: TestGenerated/ValidationTest.Test/nnapi_sample*_while*_unused_output* Change-Id: I39bebefd0e40d370882d614d4beb97ab36c9da8f --- .../1.3/vts/functional/ValidateModel.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 4c0100e219..e590fdad2d 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -535,13 +535,18 @@ static void removeOperand(Model* model, uint32_t index) { removeValueAndDecrementGreaterValues(&model->main.outputIndexes, index); } -static bool removeOperandSkip(size_t operand, const Model& model) { +static bool removeOperandSkip(size_t operandIndex, const Model& model) { + const Operand& operand = model.main.operands[operandIndex]; + if (operand.numberOfConsumers == 0) { + // Removing an unused operand has no effect. + return true; + } for (const Operation& operation : model.main.operations) { // Skip removeOperandTest for the following operations. // - SPLIT's outputs are not checked during prepareModel. if (operation.type == OperationType::SPLIT) { - for (const size_t outOprand : operation.outputs) { - if (operand == outOprand) { + for (const size_t index : operation.outputs) { + if (index == operandIndex) { return true; } } @@ -556,8 +561,8 @@ static bool removeOperandSkip(size_t operand, const Model& model) { operation.type == OperationType::UNIDIRECTIONAL_SEQUENCE_RNN || operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_LSTM || operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_RNN) { - for (const size_t outOprand : operation.outputs) { - if (operand == outOprand) { + for (const size_t index : operation.outputs) { + if (index == operandIndex) { return true; } } From a7f44eb83c3ef4c90c8798edc8c122a67f3a45ae Mon Sep 17 00:00:00 2001 From: Calvin Huang Date: Thu, 16 Apr 2020 15:59:50 -0700 Subject: [PATCH 0851/1022] Add manifest for IVehicle Bug: 153734354 Test: Manual Change-Id: I7e6a65e3fb49bb04108d0fd243df0b7447a93b1e --- automotive/vehicle/2.0/manifest.vehicle.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 automotive/vehicle/2.0/manifest.vehicle.xml diff --git a/automotive/vehicle/2.0/manifest.vehicle.xml b/automotive/vehicle/2.0/manifest.vehicle.xml new file mode 100644 index 0000000000..832b302dfa --- /dev/null +++ b/automotive/vehicle/2.0/manifest.vehicle.xml @@ -0,0 +1,11 @@ + + + android.hardware.automotive.vehicle + hwbinder + 2.0 + + IVehicle + default + + + From 322677a17218bf7be7e92e76679879509504db35 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Thu, 16 Apr 2020 16:18:23 -0700 Subject: [PATCH 0852/1022] wifi_sta_iface: Deprecate setScanningMacOui Bug: 154267383 Test: Device boots up and connects to wifi networks. Change-Id: I70206e2c25d90ebd5ac35938af9ca2ebffefa318 --- wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp | 6 +++--- wifi/1.4/default/wifi_legacy_hal.cpp | 7 ------- wifi/1.4/default/wifi_legacy_hal.h | 2 -- wifi/1.4/default/wifi_sta_iface.cpp | 7 +++---- 4 files changed, 6 insertions(+), 16 deletions(-) diff --git a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp index 7db0526d1c..e311c846e8 100644 --- a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp @@ -260,8 +260,8 @@ TEST_P(WifiStaIfaceHidlTest, EnableNDOffload) { /* * SetScanningMacOui: - * Ensures that calls to set scanning MAC OUI will return a success status - * code. + * Ensures that calls to set scanning MAC OUI will return a NOT_SUPPORTED + * code since it is now deprecated. */ TEST_P(WifiStaIfaceHidlTest, SetScanningMacOui) { if (!isCapabilitySupported( @@ -271,7 +271,7 @@ TEST_P(WifiStaIfaceHidlTest, SetScanningMacOui) { } const android::hardware::hidl_array kOui{ std::array{{0x10, 0x22, 0x33}}}; - EXPECT_EQ(WifiStatusCode::SUCCESS, + EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, HIDL_INVOKE(wifi_sta_iface_, setScanningMacOui, kOui).code); } diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp index f5961954df..29123bfe47 100644 --- a/wifi/1.4/default/wifi_legacy_hal.cpp +++ b/wifi/1.4/default/wifi_legacy_hal.cpp @@ -801,13 +801,6 @@ wifi_error WifiLegacyHal::stopSendingOffloadedPacket( cmd_id, getIfaceHandle(iface_name)); } -wifi_error WifiLegacyHal::setScanningMacOui(const std::string& iface_name, - const std::array& oui) { - std::vector oui_internal(oui.data(), oui.data() + oui.size()); - return global_func_table_.wifi_set_scanning_mac_oui( - getIfaceHandle(iface_name), oui_internal.data()); -} - wifi_error WifiLegacyHal::selectTxPowerScenario(const std::string& iface_name, wifi_power_scenario scenario) { return global_func_table_.wifi_select_tx_power_scenario( diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h index c697ff9682..99644604cc 100644 --- a/wifi/1.4/default/wifi_legacy_hal.h +++ b/wifi/1.4/default/wifi_legacy_hal.h @@ -252,8 +252,6 @@ class WifiLegacyHal { const std::array& dst_address, uint32_t period_in_ms); wifi_error stopSendingOffloadedPacket(const std::string& iface_name, uint32_t cmd_id); - wifi_error setScanningMacOui(const std::string& iface_name, - const std::array& oui); virtual wifi_error selectTxPowerScenario(const std::string& iface_name, wifi_power_scenario scenario); virtual wifi_error resetTxPowerScenario(const std::string& iface_name); diff --git a/wifi/1.4/default/wifi_sta_iface.cpp b/wifi/1.4/default/wifi_sta_iface.cpp index e2ea6e464e..49f383ae2f 100644 --- a/wifi/1.4/default/wifi_sta_iface.cpp +++ b/wifi/1.4/default/wifi_sta_iface.cpp @@ -578,10 +578,9 @@ WifiStatus WifiStaIface::stopSendingKeepAlivePacketsInternal(uint32_t cmd_id) { } WifiStatus WifiStaIface::setScanningMacOuiInternal( - const std::array& oui) { - legacy_hal::wifi_error legacy_status = - legacy_hal_.lock()->setScanningMacOui(ifname_, oui); - return createWifiStatusFromLegacyError(legacy_status); + const std::array& /* oui */) { + // deprecated. + return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED); } WifiStatus WifiStaIface::startDebugPacketFateMonitoringInternal() { From 0dd9a6bacc2f4d7d269c13c7ed8dec7346e80be7 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Tue, 14 Apr 2020 14:53:22 -0700 Subject: [PATCH 0853/1022] audio: Centralize audio configuration paths specification The list of possible paths for the audio configuration files is now retrieved using audio_get_configuration_paths() function. All duplicated lists of known configuration directories have been removed. Bug: 153680356 Test: atest VtsHalAudioV6_0TargetTest \ VtsHalAudioPolicyV1_0TargetTest \ VtsHalAudioEffectV6_0TargetTest Change-Id: I1e40fdf8d6e3a5ac339f7f138f62063bb87bd3da Merged-In: I1e40fdf8d6e3a5ac339f7f138f62063bb87bd3da --- .../utility/include/utility/ValidateXml.h | 27 +++++++++++++++++-- .../test/utility/src/ValidateXml.cpp | 21 +++++++-------- .../vts/functional/AudioPrimaryHidlHalTest.h | 11 ++++---- .../ValidateAudioEffectsConfiguration.cpp | 8 +++--- .../ValidateEngineConfiguration.cpp | 12 ++++++--- 5 files changed, 54 insertions(+), 25 deletions(-) diff --git a/audio/common/all-versions/test/utility/include/utility/ValidateXml.h b/audio/common/all-versions/test/utility/include/utility/ValidateXml.h index ee206f7458..274a10b515 100644 --- a/audio/common/all-versions/test/utility/include/utility/ValidateXml.h +++ b/audio/common/all-versions/test/utility/include/utility/ValidateXml.h @@ -51,8 +51,31 @@ namespace utility { */ template ::testing::AssertionResult validateXmlMultipleLocations( - const char* xmlFileNameExpr, const char* xmlFileLocationsExpr, const char* xsdFilePathExpr, - const char* xmlFileName, std::vector xmlFileLocations, const char* xsdFilePath); + const char* xmlFileNameExpr, const char* xmlFileLocationsExpr, const char* xsdFilePathExpr, + const char* xmlFileName, const std::vector& xmlFileLocations, + const char* xsdFilePath); +template +::testing::AssertionResult validateXmlMultipleLocations( + const char* xmlFileNameExpr, const char* xmlFileLocationsExpr, const char* xsdFilePathExpr, + const char* xmlFileName, std::initializer_list xmlFileLocations, + const char* xsdFilePath) { + return validateXmlMultipleLocations( + xmlFileNameExpr, xmlFileLocationsExpr, xsdFilePathExpr, xmlFileName, + std::vector(xmlFileLocations.begin(), xmlFileLocations.end()), + xsdFilePath); +} +template +::testing::AssertionResult validateXmlMultipleLocations(const char* xmlFileNameExpr, + const char* xmlFileLocationsExpr, + const char* xsdFilePathExpr, + const char* xmlFileName, + std::vector xmlFileLocations, + const char* xsdFilePath) { + return validateXmlMultipleLocations( + xmlFileNameExpr, xmlFileLocationsExpr, xsdFilePathExpr, xmlFileName, + std::vector(xmlFileLocations.begin(), xmlFileLocations.end()), + xsdFilePath); +} /** ASSERT that all found XML are valid according to an xsd. */ #define ASSERT_VALID_XML_MULTIPLE_LOCATIONS(xmlFileName, xmlFileLocations, xsdFilePath) \ diff --git a/audio/common/all-versions/test/utility/src/ValidateXml.cpp b/audio/common/all-versions/test/utility/src/ValidateXml.cpp index bdafa82d6b..a866104b38 100644 --- a/audio/common/all-versions/test/utility/src/ValidateXml.cpp +++ b/audio/common/all-versions/test/utility/src/ValidateXml.cpp @@ -131,14 +131,15 @@ struct Libxml2Global { template ::testing::AssertionResult validateXmlMultipleLocations( - const char* xmlFileNameExpr, const char* xmlFileLocationsExpr, const char* xsdFilePathExpr, - const char* xmlFileName, std::vector xmlFileLocations, const char* xsdFilePath) { + const char* xmlFileNameExpr, const char* xmlFileLocationsExpr, const char* xsdFilePathExpr, + const char* xmlFileName, const std::vector& xmlFileLocations, + const char* xsdFilePath) { using namespace std::string_literals; std::vector errors; std::vector foundFiles; - for (const char* location : xmlFileLocations) { + for (const auto& location : xmlFileLocations) { std::string xmlFilePath = location + "/"s + xmlFileName; if (access(xmlFilePath.c_str(), F_OK) != 0) { // If the file does not exist ignore this location and fallback on the next one @@ -166,14 +167,12 @@ template : "\nWhere no file might exist."); } -template ::testing::AssertionResult validateXmlMultipleLocations(const char*, const char*, - const char*, const char*, - std::vector, - const char*); -template ::testing::AssertionResult validateXmlMultipleLocations(const char*, const char*, - const char*, const char*, - std::vector, - const char*); +template ::testing::AssertionResult validateXmlMultipleLocations( + const char*, const char*, const char*, const char*, const std::vector&, + const char*); +template ::testing::AssertionResult validateXmlMultipleLocations( + const char*, const char*, const char*, const char*, const std::vector&, + const char*); } // namespace utility } // namespace test diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h index 5d82e7bd80..d5af335f6a 100644 --- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -35,6 +35,7 @@ #include #include +#include #include PATH(android/hardware/audio/FILE_VERSION/IDevice.h) #include PATH(android/hardware/audio/FILE_VERSION/IDevicesFactory.h) @@ -135,7 +136,6 @@ class HidlTest : public ::testing::Test { ////////////////////////// Audio policy configuration //////////////////////// ////////////////////////////////////////////////////////////////////////////// -static const std::vector kConfigLocations = {"/odm/etc", "/vendor/etc", "/system/etc"}; static constexpr char kConfigFileName[] = "audio_policy_configuration.xml"; // Stringify the argument. @@ -154,8 +154,8 @@ class PolicyConfig : private PolicyConfigData, public AudioPolicyConfig { PolicyConfig() : AudioPolicyConfig(hwModules, availableOutputDevices, availableInputDevices, defaultOutputDevice) { - for (const char* location : kConfigLocations) { - std::string path = std::string(location) + '/' + kConfigFileName; + for (const auto& location : android::audio_get_configuration_paths()) { + std::string path = location + '/' + kConfigFileName; if (access(path.c_str(), F_OK) == 0) { mFilePath = path; break; @@ -188,7 +188,7 @@ class PolicyConfig : private PolicyConfigData, public AudioPolicyConfig { std::string getError() const { if (mFilePath.empty()) { return std::string{"Could not find "} + kConfigFileName + - " file in: " + testing::PrintToString(kConfigLocations); + " file in: " + testing::PrintToString(android::audio_get_configuration_paths()); } else { return "Invalid config file: " + mFilePath; } @@ -304,7 +304,8 @@ TEST(CheckConfig, audioPolicyConfigurationValidation) { "is valid according to the schema"); const char* xsd = "/data/local/tmp/audio_policy_configuration_" STRINGIFY(CPP_VERSION) ".xsd"; - EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(kConfigFileName, kConfigLocations, xsd); + EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(kConfigFileName, + android::audio_get_configuration_paths(), xsd); } class AudioPolicyConfigTest : public AudioHidlTestWithDeviceParameter { diff --git a/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp b/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp index 9c0135bf93..f2516349d4 100644 --- a/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp +++ b/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp @@ -18,6 +18,7 @@ #include #include +#include // clang-format off #include PATH(android/hardware/audio/effect/FILE_VERSION/IEffectsFactory.h) // clang-format on @@ -41,13 +42,14 @@ TEST(CheckConfig, audioEffectsConfigurationValidation) { GTEST_SKIP() << "No Effects HAL version " STRINGIFY(CPP_VERSION) " on this device"; } - std::vector locations(std::begin(DEFAULT_LOCATIONS), std::end(DEFAULT_LOCATIONS)); const char* xsd = "/data/local/tmp/audio_effects_conf_" STRINGIFY(CPP_VERSION) ".xsd"; #if MAJOR_VERSION == 2 // In V2, audio effect XML is not required. .conf is still allowed though deprecated - EXPECT_VALID_XML_MULTIPLE_LOCATIONS(DEFAULT_NAME, locations, xsd); + EXPECT_VALID_XML_MULTIPLE_LOCATIONS(DEFAULT_NAME, android::audio_get_configuration_paths(), + xsd); #elif MAJOR_VERSION >= 4 // Starting with V4, audio effect XML is required - EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(DEFAULT_NAME, locations, xsd); + EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(DEFAULT_NAME, android::audio_get_configuration_paths(), + xsd); #endif } diff --git a/audio/policy/1.0/vts/functional/ValidateEngineConfiguration.cpp b/audio/policy/1.0/vts/functional/ValidateEngineConfiguration.cpp index a0aaa6e89f..5741fa97cc 100644 --- a/audio/policy/1.0/vts/functional/ValidateEngineConfiguration.cpp +++ b/audio/policy/1.0/vts/functional/ValidateEngineConfiguration.cpp @@ -23,7 +23,8 @@ #include #include "utility/ValidateXml.h" -static const std::vector locations = {"/odm/etc", "/vendor/etc", "/system/etc"}; +#include + static const std::string config = "audio_policy_engine_configuration.xml"; static const std::string schema = std::string(XSD_DIR) + "/audio_policy_engine_configuration_V1_0.xsd"; @@ -42,7 +43,8 @@ TEST(ValidateConfiguration, audioPolicyEngineConfiguration) { RecordProperty("description", "Verify that the audio policy engine configuration file " "is valid according to the schemas"); - EXPECT_VALID_XML_MULTIPLE_LOCATIONS(config.c_str(), locations, schema.c_str()); + EXPECT_VALID_XML_MULTIPLE_LOCATIONS(config.c_str(), android::audio_get_configuration_paths(), + schema.c_str()); } /** @@ -52,9 +54,11 @@ TEST(ValidateConfiguration, audioPolicyEngineConfiguration) { */ static bool deviceUsesConfigurableEngine() { return android::hardware::audio::common::test::utility::validateXmlMultipleLocations( - "", "", "", config.c_str(), locations, schema.c_str()) && + "", "", "", config.c_str(), android::audio_get_configuration_paths(), + schema.c_str()) && android::hardware::audio::common::test::utility::validateXmlMultipleLocations( - "", "", "", configurableConfig.c_str(), locations, configurableSchemas.c_str()); + "", "", "", configurableConfig.c_str(), android::audio_get_configuration_paths(), + configurableSchemas.c_str()); } TEST(ValidateConfiguration, audioPolicyEngineConfigurable) { From 62b79417a44d8cfba8d77042253b12a787c29f76 Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Thu, 16 Apr 2020 15:58:21 -0700 Subject: [PATCH 0854/1022] Update CodeType comment for adding BDS B1C Bug: 154267746 Test: doc update only. Builds Change-Id: I997f1febef4f7b266cc51fe59a645ee1a48fd971 --- current.txt | 1 + gnss/2.0/IGnssMeasurementCallback.hal | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/current.txt b/current.txt index 656f5c7d61..e553999c59 100644 --- a/current.txt +++ b/current.txt @@ -588,6 +588,7 @@ d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardwar cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types a05277065c28ebecd58118bd240fb8c55757361e8648c01f7c4dacdb7f2a95dc android.hardware.camera.metadata@3.3::types 9cb3df2bde2c6cd5fd96b7c41555420cacd7e276a556c684af91b7461c86460f android.hardware.gnss@1.0::IGnssCallback +dd6cd9dba4fde99a1bc3cb1728d82309f509a6e6e1993e5042dfa5ffe4af5442 android.hardware.gnss@2.0::IGnssMeasurementCallback af334f1fc85c62b343f84b74d0495eed6f495f7fecedb53463db10c202310058 android.hardware.gnss.measurement_corrections@1.0::types 33a6b20c43af00fdfb305df891bc5911c06d9a9130b912759649932e5a4a6e6d android.hardware.gnss.visibility_control@1.0::IGnssVisibilityControlCallback bceee81ec1b59324abd05932b5620fda5a6589597c9cb3953ba7f3ea02cccd3e android.hardware.camera.provider@2.4::ICameraProvider diff --git a/gnss/2.0/IGnssMeasurementCallback.hal b/gnss/2.0/IGnssMeasurementCallback.hal index e055f7aa45..76c7943f8d 100644 --- a/gnss/2.0/IGnssMeasurementCallback.hal +++ b/gnss/2.0/IGnssMeasurementCallback.hal @@ -402,6 +402,8 @@ interface IGnssMeasurementCallback extends @1.1::IGnssMeasurementCallback { * Value "C" represents GPS L1 C/A, GPS L2 C/A, GLONASS G1 C/A, GLONASS G2 C/A, GALILEO E1C, * GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, IRNSS L5C. * + * value "D" represents BDS B1C D. + * * Value "I" represents GPS L5 I, GLONASS G3 I, GALILEO E5a I, GALILEO E5b I, GALILEO E5a+b I, * SBAS L5 I, QZSS L5 I, BDS B1 I, BDS B2 I, BDS B3 I. * @@ -411,7 +413,7 @@ interface IGnssMeasurementCallback extends @1.1::IGnssMeasurementCallback { * * Value "N" represents GPS L1 codeless, GPS L2 codeless. * - * Value "P" represents GPS L1P, GPS L2P, GLONASS G1P, GLONASS G2P. + * Value "P" represents GPS L1P, GPS L2P, GLONASS G1P, GLONASS G2P, BDS B1C P. * * Value "Q" represents GPS L5 Q, GLONASS G3 Q, GALILEO E5a Q, GALILEO E5b Q, GALILEO E5a+b Q, * SBAS L5 Q, QZSS L5 Q, BDS B1 Q, BDS B2 Q, BDS B3 Q. @@ -423,7 +425,7 @@ interface IGnssMeasurementCallback extends @1.1::IGnssMeasurementCallback { * Value "X" represents GPS L1C (D+P), GPS L2C (M+L), GPS L5 (I+Q), GLONASS G3 (I+Q), * GALILEO E1 (B+C), GALILEO E5a (I+Q), GALILEO E5b (I+Q), GALILEO E5a+b(I+Q), * GALILEO E6 (B+C), SBAS L5 (I+Q), QZSS L1C (D+P), QZSS L2C (M+L), QZSS L5 (I+Q), - * LEX(6) (S+L), BDS B1 (I+Q), BDS B2 (I+Q), BDS B3 (I+Q), IRNSS L5 (B+C). + * LEX(6) (S+L), BDS B1 (I+Q), BDS B1C (D+P), BDS B2 (I+Q), BDS B3 (I+Q), IRNSS L5 (B+C). * * Value "Y" represents GPS L1Y, GPS L2Y. * From a990ecee798ebd62827531a720b73f1dd0b196d3 Mon Sep 17 00:00:00 2001 From: shubang Date: Fri, 17 Apr 2020 18:25:45 -0700 Subject: [PATCH 0855/1022] Call scan callback for ATSC It's a temp solution for CTS. Bug: 150952758 Test: atest android.media.tv.tuner.cts.TunerTest Change-Id: I31242910af39108dca5920bd0892fa16aa6d29be --- tv/tuner/1.0/default/Frontend.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp index 6565746c76..ae5f587b94 100644 --- a/tv/tuner/1.0/default/Frontend.cpp +++ b/tv/tuner/1.0/default/Frontend.cpp @@ -82,6 +82,10 @@ Return Frontend::scan(const FrontendSettings& settings, FrontendScanType ALOGV("%s", __FUNCTION__); if (mType == FrontendType::ATSC) { + FrontendScanMessage msg; + msg.isLocked(true); + mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg); + mIsLocked = true; return Result::SUCCESS; } if (mType != FrontendType::DVBT) { From c578a913568a5611f396e97b4ee5851930559b97 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Thu, 16 Apr 2020 11:48:14 +0800 Subject: [PATCH 0856/1022] wifi: skip tests if RTT is not supported Bug: 153418156 Test: atest VtsHalWifiApV1_4TargetTest Change-Id: I2aa58c501f44a9b32c1a7ebf48aa8fcbfb08b046 --- wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp index 295c86e1a7..4035fb8f71 100644 --- a/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp +++ b/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp @@ -64,6 +64,14 @@ class WifiRttControllerHidlTest : public ::testing::TestWithParam { wifi_rtt_controller_ = getWifiRttController(); ASSERT_NE(nullptr, wifi_rtt_controller_.get()); + + // Check RTT support before we run the test. + std::pair status_and_caps; + status_and_caps = + HIDL_INVOKE(wifi_rtt_controller_, getCapabilities_1_4); + if (status_and_caps.first.code == WifiStatusCode::ERROR_NOT_SUPPORTED) { + GTEST_SKIP() << "Skipping this test since RTT is not supported."; + } } virtual void TearDown() override { stopWifi(GetInstanceName()); } From 0fe25be00596c588a6c76f1d417c0dcd713456e0 Mon Sep 17 00:00:00 2001 From: Amy Zhang Date: Wed, 8 Apr 2020 17:30:52 -0700 Subject: [PATCH 0857/1022] Make dvr tests a separate module Test: atest VtsHalTvTunerV1_0TargetTest Bug: 150989084 Change-Id: I35d717f357b176d5cbec5d154f4df30fd2c4a18e --- tv/tuner/1.0/default/Demux.cpp | 8 +- tv/tuner/1.0/default/Demux.h | 2 +- tv/tuner/1.0/default/Frontend.cpp | 1 + tv/tuner/1.0/default/Tuner.cpp | 9 + tv/tuner/1.0/default/Tuner.h | 1 + tv/tuner/1.0/vts/functional/Android.bp | 1 + tv/tuner/1.0/vts/functional/DemuxTests.h | 3 +- tv/tuner/1.0/vts/functional/DvrTests.cpp | 267 +++++++++++++ tv/tuner/1.0/vts/functional/DvrTests.h | 187 ++++++++++ tv/tuner/1.0/vts/functional/FilterTests.h | 1 + .../VtsHalTvTunerV1_0TargetTest.cpp | 350 ++++++------------ .../functional/VtsHalTvTunerV1_0TargetTest.h | 167 ++------- .../VtsHalTvTunerV1_0TestConfigurations.h | 69 +++- 13 files changed, 674 insertions(+), 392 deletions(-) create mode 100644 tv/tuner/1.0/vts/functional/DvrTests.cpp create mode 100644 tv/tuner/1.0/vts/functional/DvrTests.h diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp index 43c4e3a086..95b4ebc7a6 100644 --- a/tv/tuner/1.0/default/Demux.cpp +++ b/tv/tuner/1.0/default/Demux.cpp @@ -52,7 +52,7 @@ Return Demux::setFrontendDataSource(uint32_t frontendId) { mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId); - return startFrontendInputLoop(); + return Result::SUCCESS; } Return Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize, @@ -60,7 +60,6 @@ Return Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize, ALOGV("%s", __FUNCTION__); uint32_t filterId; - if (!mUnusedFilterIds.empty()) { filterId = *mUnusedFilterIds.begin(); @@ -83,7 +82,6 @@ Return Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize, _hidl_cb(Result::UNKNOWN_ERROR, filter); return Void(); } - mFilters[filterId] = filter; _hidl_cb(Result::SUCCESS, filter); @@ -234,11 +232,9 @@ uint16_t Demux::getFilterTpid(uint32_t filterId) { return mFilters[filterId]->getTpid(); } -Result Demux::startFrontendInputLoop() { +void Demux::startFrontendInputLoop() { pthread_create(&mFrontendInputThread, NULL, __threadLoopFrontend, this); pthread_setname_np(mFrontendInputThread, "frontend_input_thread"); - - return Result::SUCCESS; } void* Demux::__threadLoopFrontend(void* user) { diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h index 1405d0c2ca..759e348d93 100644 --- a/tv/tuner/1.0/default/Demux.h +++ b/tv/tuner/1.0/default/Demux.h @@ -89,6 +89,7 @@ class Demux : public IDemux { void updateFilterOutput(uint16_t filterId, vector data); uint16_t getFilterTpid(uint32_t filterId); void setIsRecording(bool isRecording); + void startFrontendInputLoop(); private: // Tuner service @@ -104,7 +105,6 @@ class Demux : public IDemux { uint32_t filterId; }; - Result startFrontendInputLoop(); static void* __threadLoopFrontend(void* user); void frontendInputThreadLoop(); diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp index 2cff9be459..7d55739cff 100644 --- a/tv/tuner/1.0/default/Frontend.cpp +++ b/tv/tuner/1.0/default/Frontend.cpp @@ -64,6 +64,7 @@ Return Frontend::tune(const FrontendSettings& /* settings */) { return Result::INVALID_STATE; } + mTunerService->frontendStartTune(mId); mCallback->onEvent(FrontendEventType::LOCKED); mIsLocked = false; return Result::SUCCESS; diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp index e39333ce3e..14a428970a 100644 --- a/tv/tuner/1.0/default/Tuner.cpp +++ b/tv/tuner/1.0/default/Tuner.cpp @@ -236,6 +236,15 @@ void Tuner::frontendStopTune(uint32_t frontendId) { } } +void Tuner::frontendStartTune(uint32_t frontendId) { + map::iterator it = mFrontendToDemux.find(frontendId); + uint32_t demuxId; + if (it != mFrontendToDemux.end()) { + demuxId = it->second; + mDemuxes[demuxId]->startFrontendInputLoop(); + } +} + } // namespace implementation } // namespace V1_0 } // namespace tuner diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h index d17b5aeb64..ada0f81cac 100644 --- a/tv/tuner/1.0/default/Tuner.h +++ b/tv/tuner/1.0/default/Tuner.h @@ -62,6 +62,7 @@ class Tuner : public ITuner { void setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId); + void frontendStartTune(uint32_t frontendId); void frontendStopTune(uint32_t frontendId); private: diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp index 448575ea7a..b152a292cb 100644 --- a/tv/tuner/1.0/vts/functional/Android.bp +++ b/tv/tuner/1.0/vts/functional/Android.bp @@ -22,6 +22,7 @@ cc_test { "FrontendTests.cpp", "DemuxTests.cpp", "FilterTests.cpp", + "DvrTests.cpp", ], static_libs: [ "android.hardware.tv.tuner@1.0", diff --git a/tv/tuner/1.0/vts/functional/DemuxTests.h b/tv/tuner/1.0/vts/functional/DemuxTests.h index f405a79ae8..31b3e7bafc 100644 --- a/tv/tuner/1.0/vts/functional/DemuxTests.h +++ b/tv/tuner/1.0/vts/functional/DemuxTests.h @@ -40,8 +40,6 @@ using ::testing::AssertionResult; class DemuxTests { public: - sp mService; - void setService(sp tuner) { mService = tuner; } AssertionResult openDemux(sp& demux, uint32_t& demuxId); @@ -53,5 +51,6 @@ class DemuxTests { static AssertionResult success() { return ::testing::AssertionSuccess(); } + sp mService; sp mDemux; }; \ No newline at end of file diff --git a/tv/tuner/1.0/vts/functional/DvrTests.cpp b/tv/tuner/1.0/vts/functional/DvrTests.cpp new file mode 100644 index 0000000000..a1ce23d730 --- /dev/null +++ b/tv/tuner/1.0/vts/functional/DvrTests.cpp @@ -0,0 +1,267 @@ +/* + * Copyright 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 "DvrTests.h" + +void DvrCallback::startPlaybackInputThread(PlaybackConf playbackConf, + MQDesc& playbackMQDescriptor) { + mPlaybackMQ = std::make_unique(playbackMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(mPlaybackMQ); + struct PlaybackThreadArgs* threadArgs = + (struct PlaybackThreadArgs*)malloc(sizeof(struct PlaybackThreadArgs)); + threadArgs->user = this; + threadArgs->playbackConf = &playbackConf; + threadArgs->keepWritingPlaybackFMQ = &mKeepWritingPlaybackFMQ; + + pthread_create(&mPlaybackThread, NULL, __threadLoopPlayback, (void*)threadArgs); + pthread_setname_np(mPlaybackThread, "test_playback_input_loop"); +} + +void DvrCallback::stopPlaybackThread() { + mPlaybackThreadRunning = false; + mKeepWritingPlaybackFMQ = false; + + android::Mutex::Autolock autoLock(mPlaybackThreadLock); +} + +void* DvrCallback::__threadLoopPlayback(void* threadArgs) { + DvrCallback* const self = + static_cast(((struct PlaybackThreadArgs*)threadArgs)->user); + self->playbackThreadLoop(((struct PlaybackThreadArgs*)threadArgs)->playbackConf, + ((struct PlaybackThreadArgs*)threadArgs)->keepWritingPlaybackFMQ); + return 0; +} + +void DvrCallback::playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ) { + android::Mutex::Autolock autoLock(mPlaybackThreadLock); + mPlaybackThreadRunning = true; + + // Create the EventFlag that is used to signal the HAL impl that data have been + // written into the Playback FMQ + EventFlag* playbackMQEventFlag; + EXPECT_TRUE(EventFlag::createEventFlag(mPlaybackMQ->getEventFlagWord(), &playbackMQEventFlag) == + android::OK); + + // open the stream and get its length + std::ifstream inputData(playbackConf->inputDataFile, std::ifstream::binary); + int writeSize = playbackConf->setting.packetSize * 6; + char* buffer = new char[writeSize]; + ALOGW("[vts] playback thread loop start %s", playbackConf->inputDataFile.c_str()); + if (!inputData.is_open()) { + mPlaybackThreadRunning = false; + ALOGW("[vts] Error %s", strerror(errno)); + } + + while (mPlaybackThreadRunning) { + // move the stream pointer for packet size * 6 every read until the end + while (*keepWritingPlaybackFMQ) { + inputData.read(buffer, writeSize); + if (!inputData) { + int leftSize = inputData.gcount(); + if (leftSize == 0) { + mPlaybackThreadRunning = false; + break; + } + inputData.clear(); + inputData.read(buffer, leftSize); + // Write the left over of the input data and quit the thread + if (leftSize > 0) { + EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], leftSize)); + playbackMQEventFlag->wake( + static_cast(DemuxQueueNotifyBits::DATA_READY)); + } + mPlaybackThreadRunning = false; + break; + } + // Write input FMQ and notify the Tuner Implementation + EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], writeSize)); + playbackMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); + inputData.seekg(writeSize, inputData.cur); + sleep(1); + } + } + + ALOGW("[vts] Playback thread end."); + + delete[] buffer; + inputData.close(); +} + +void DvrCallback::testRecordOutput() { + android::Mutex::Autolock autoLock(mMsgLock); + while (mDataOutputBuffer.empty()) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "record output matching pid does not output within timeout"; + return; + } + } + stopRecordThread(); + ALOGW("[vts] record pass and stop"); +} + +void DvrCallback::startRecordOutputThread(RecordSettings recordSettings, + MQDesc& recordMQDescriptor) { + mRecordMQ = std::make_unique(recordMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(mRecordMQ); + struct RecordThreadArgs* threadArgs = + (struct RecordThreadArgs*)malloc(sizeof(struct RecordThreadArgs)); + threadArgs->user = this; + threadArgs->recordSettings = &recordSettings; + threadArgs->keepReadingRecordFMQ = &mKeepReadingRecordFMQ; + + pthread_create(&mRecordThread, NULL, __threadLoopRecord, (void*)threadArgs); + pthread_setname_np(mRecordThread, "test_record_input_loop"); +} + +void* DvrCallback::__threadLoopRecord(void* threadArgs) { + DvrCallback* const self = + static_cast(((struct RecordThreadArgs*)threadArgs)->user); + self->recordThreadLoop(((struct RecordThreadArgs*)threadArgs)->recordSettings, + ((struct RecordThreadArgs*)threadArgs)->keepReadingRecordFMQ); + return 0; +} + +void DvrCallback::recordThreadLoop(RecordSettings* /*recordSettings*/, bool* keepReadingRecordFMQ) { + ALOGD("[vts] DvrCallback record threadLoop start."); + android::Mutex::Autolock autoLock(mRecordThreadLock); + mRecordThreadRunning = true; + + // Create the EventFlag that is used to signal the HAL impl that data have been + // read from the Record FMQ + EventFlag* recordMQEventFlag; + EXPECT_TRUE(EventFlag::createEventFlag(mRecordMQ->getEventFlagWord(), &recordMQEventFlag) == + android::OK); + + while (mRecordThreadRunning) { + while (*keepReadingRecordFMQ) { + uint32_t efState = 0; + android::status_t status = recordMQEventFlag->wait( + static_cast(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT, + true /* retry on spurious wake */); + if (status != android::OK) { + ALOGD("[vts] wait for data ready on the record FMQ"); + continue; + } + // Our current implementation filter the data and write it into the filter FMQ + // immediately after the DATA_READY from the VTS/framework + if (!readRecordFMQ()) { + ALOGD("[vts] record data failed to be filtered. Ending thread"); + mRecordThreadRunning = false; + break; + } + } + } + + mRecordThreadRunning = false; + ALOGD("[vts] record thread ended."); +} + +bool DvrCallback::readRecordFMQ() { + android::Mutex::Autolock autoLock(mMsgLock); + bool result = false; + mDataOutputBuffer.clear(); + mDataOutputBuffer.resize(mRecordMQ->availableToRead()); + result = mRecordMQ->read(mDataOutputBuffer.data(), mRecordMQ->availableToRead()); + EXPECT_TRUE(result) << "can't read from Record MQ"; + mMsgCondition.signal(); + return result; +} + +void DvrCallback::stopRecordThread() { + mKeepReadingRecordFMQ = false; + mRecordThreadRunning = false; + android::Mutex::Autolock autoLock(mRecordThreadLock); +} + +AssertionResult DvrTests::openDvrInDemux(DvrType type) { + Result status; + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + + // Create dvr callback + mDvrCallback = new DvrCallback(); + + mDemux->openDvr(type, FMQ_SIZE_1M, mDvrCallback, [&](Result result, const sp& dvr) { + mDvr = dvr; + status = result; + }); + + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult DvrTests::configDvr(DvrSettings setting) { + Result status = mDvr->configure(setting); + + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult DvrTests::getDvrMQDescriptor() { + Result status; + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + EXPECT_TRUE(mDvr) << "Test with openDvr first."; + + mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) { + mDvrMQDescriptor = dvrMQDesc; + status = result; + }); + + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult DvrTests::attachFilterToDvr(sp filter) { + Result status; + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + EXPECT_TRUE(mDvr) << "Test with openDvr first."; + + status = mDvr->attachFilter(filter); + + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult DvrTests::detachFilterToDvr(sp filter) { + Result status; + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + EXPECT_TRUE(mDvr) << "Test with openDvr first."; + + status = mDvr->detachFilter(filter); + + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult DvrTests::startDvr() { + Result status; + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + EXPECT_TRUE(mDvr) << "Test with openDvr first."; + + status = mDvr->start(); + + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult DvrTests::stopDvr() { + Result status; + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + EXPECT_TRUE(mDvr) << "Test with openDvr first."; + + status = mDvr->stop(); + + return AssertionResult(status == Result::SUCCESS); +} + +void DvrTests::closeDvr() { + ASSERT_TRUE(mDemux); + ASSERT_TRUE(mDvr); + ASSERT_TRUE(mDvr->close() == Result::SUCCESS); +} \ No newline at end of file diff --git a/tv/tuner/1.0/vts/functional/DvrTests.h b/tv/tuner/1.0/vts/functional/DvrTests.h new file mode 100644 index 0000000000..74ef58ebf1 --- /dev/null +++ b/tv/tuner/1.0/vts/functional/DvrTests.h @@ -0,0 +1,187 @@ +/* + * Copyright 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FilterTests.h" + +using android::Condition; +using android::Mutex; +using android::sp; +using android::hardware::EventFlag; +using android::hardware::kSynchronizedReadWrite; +using android::hardware::MessageQueue; +using android::hardware::MQDescriptorSync; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::tv::tuner::V1_0::DemuxFilterStatus; +using android::hardware::tv::tuner::V1_0::DvrSettings; +using android::hardware::tv::tuner::V1_0::DvrType; +using android::hardware::tv::tuner::V1_0::IDvr; +using android::hardware::tv::tuner::V1_0::IDvrCallback; +using android::hardware::tv::tuner::V1_0::ITuner; +using android::hardware::tv::tuner::V1_0::PlaybackSettings; +using android::hardware::tv::tuner::V1_0::PlaybackStatus; +using android::hardware::tv::tuner::V1_0::RecordSettings; +using android::hardware::tv::tuner::V1_0::RecordStatus; +using android::hardware::tv::tuner::V1_0::Result; + +#define WAIT_TIMEOUT 3000000000 + +struct PlaybackConf { + string inputDataFile; + PlaybackSettings setting; +}; + +class DvrCallback : public IDvrCallback { + public: + virtual Return onRecordStatus(DemuxFilterStatus status) override { + ALOGW("[vts] record status %hhu", status); + switch (status) { + case DemuxFilterStatus::DATA_READY: + break; + case DemuxFilterStatus::LOW_WATER: + break; + case DemuxFilterStatus::HIGH_WATER: + case DemuxFilterStatus::OVERFLOW: + ALOGW("[vts] record overflow. Flushing"); + break; + } + return Void(); + } + + virtual Return onPlaybackStatus(PlaybackStatus status) override { + // android::Mutex::Autolock autoLock(mMsgLock); + ALOGW("[vts] playback status %d", status); + switch (status) { + case PlaybackStatus::SPACE_EMPTY: + case PlaybackStatus::SPACE_ALMOST_EMPTY: + ALOGW("[vts] keep playback inputing %d", status); + mKeepWritingPlaybackFMQ = true; + break; + case PlaybackStatus::SPACE_ALMOST_FULL: + case PlaybackStatus::SPACE_FULL: + ALOGW("[vts] stop playback inputing %d", status); + mKeepWritingPlaybackFMQ = false; + break; + } + return Void(); + } + + void stopPlaybackThread(); + void testRecordOutput(); + void stopRecordThread(); + + void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor); + void startRecordOutputThread(RecordSettings recordSettings, MQDesc& recordMQDescriptor); + static void* __threadLoopPlayback(void* threadArgs); + static void* __threadLoopRecord(void* threadArgs); + void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ); + void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ); + + bool readRecordFMQ(); + + private: + struct PlaybackThreadArgs { + DvrCallback* user; + PlaybackConf* playbackConf; + bool* keepWritingPlaybackFMQ; + }; + struct RecordThreadArgs { + DvrCallback* user; + RecordSettings* recordSettings; + bool* keepReadingRecordFMQ; + }; + // uint16_t mDataLength = 0; + std::vector mDataOutputBuffer; + + std::map> mFilterMQ; + std::unique_ptr mPlaybackMQ; + std::unique_ptr mRecordMQ; + std::map mFilterMQEventFlag; + + android::Mutex mMsgLock; + android::Mutex mPlaybackThreadLock; + android::Mutex mRecordThreadLock; + android::Condition mMsgCondition; + + bool mKeepWritingPlaybackFMQ = true; + bool mKeepReadingRecordFMQ = true; + bool mPlaybackThreadRunning; + bool mRecordThreadRunning; + pthread_t mPlaybackThread; + pthread_t mRecordThread; + + // int mPidFilterOutputCount = 0; +}; + +class DvrTests { + public: + void setService(sp tuner) { mService = tuner; } + void setDemux(sp demux) { mDemux = demux; } + + void startPlaybackInputThread(string dataInputFile, PlaybackSettings settings) { + PlaybackConf conf{ + .inputDataFile = dataInputFile, + .setting = settings, + }; + mDvrCallback->startPlaybackInputThread(conf, mDvrMQDescriptor); + }; + + void startRecordOutputThread(RecordSettings settings) { + mDvrCallback->startRecordOutputThread(settings, mDvrMQDescriptor); + }; + + void stopPlaybackThread() { mDvrCallback->stopPlaybackThread(); } + void testRecordOutput() { mDvrCallback->testRecordOutput(); } + void stopRecordThread() { mDvrCallback->stopPlaybackThread(); } + + AssertionResult openDvrInDemux(DvrType type); + AssertionResult configDvr(DvrSettings setting); + AssertionResult getDvrMQDescriptor(); + AssertionResult attachFilterToDvr(sp filter); + AssertionResult detachFilterToDvr(sp filter); + AssertionResult stopDvr(); + AssertionResult startDvr(); + void closeDvr(); + + protected: + static AssertionResult failure() { return ::testing::AssertionFailure(); } + + static AssertionResult success() { return ::testing::AssertionSuccess(); } + + sp mService; + sp mDvr; + sp mDemux; + sp mDvrCallback; + MQDesc mDvrMQDescriptor; + + pthread_t mPlaybackshread; + bool mPlaybackThreadRunning; +}; \ No newline at end of file diff --git a/tv/tuner/1.0/vts/functional/FilterTests.h b/tv/tuner/1.0/vts/functional/FilterTests.h index eab963bc34..39462dcbbe 100644 --- a/tv/tuner/1.0/vts/functional/FilterTests.h +++ b/tv/tuner/1.0/vts/functional/FilterTests.h @@ -149,6 +149,7 @@ class FilterTests { public: void setService(sp tuner) { mService = tuner; } void setDemux(sp demux) { mDemux = demux; } + sp getFilterById(uint32_t filterId) { return mFilters[filterId]; } std::map> getFilterCallbacks() { return mFilterCallbacks; } diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index d836c26f9f..f211be2e90 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -17,181 +17,8 @@ #include "VtsHalTvTunerV1_0TargetTest.h" namespace { - -/******************************** Start DvrCallback **********************************/ -void DvrCallback::startPlaybackInputThread(PlaybackConf playbackConf, - MQDesc& playbackMQDescriptor) { - mPlaybackMQ = std::make_unique(playbackMQDescriptor, true /* resetPointers */); - EXPECT_TRUE(mPlaybackMQ); - struct PlaybackThreadArgs* threadArgs = - (struct PlaybackThreadArgs*)malloc(sizeof(struct PlaybackThreadArgs)); - threadArgs->user = this; - threadArgs->playbackConf = &playbackConf; - threadArgs->keepWritingPlaybackFMQ = &mKeepWritingPlaybackFMQ; - - pthread_create(&mPlaybackThread, NULL, __threadLoopPlayback, (void*)threadArgs); - pthread_setname_np(mPlaybackThread, "test_playback_input_loop"); -} - -void DvrCallback::stopPlaybackThread() { - mPlaybackThreadRunning = false; - mKeepWritingPlaybackFMQ = false; - - android::Mutex::Autolock autoLock(mPlaybackThreadLock); -} - -void* DvrCallback::__threadLoopPlayback(void* threadArgs) { - DvrCallback* const self = - static_cast(((struct PlaybackThreadArgs*)threadArgs)->user); - self->playbackThreadLoop(((struct PlaybackThreadArgs*)threadArgs)->playbackConf, - ((struct PlaybackThreadArgs*)threadArgs)->keepWritingPlaybackFMQ); - return 0; -} - -void DvrCallback::playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ) { - android::Mutex::Autolock autoLock(mPlaybackThreadLock); - mPlaybackThreadRunning = true; - - // Create the EventFlag that is used to signal the HAL impl that data have been - // written into the Playback FMQ - EventFlag* playbackMQEventFlag; - EXPECT_TRUE(EventFlag::createEventFlag(mPlaybackMQ->getEventFlagWord(), &playbackMQEventFlag) == - android::OK); - - // open the stream and get its length - std::ifstream inputData(playbackConf->inputDataFile, std::ifstream::binary); - int writeSize = playbackConf->setting.packetSize * 6; - char* buffer = new char[writeSize]; - ALOGW("[vts] playback thread loop start %s", playbackConf->inputDataFile.c_str()); - if (!inputData.is_open()) { - mPlaybackThreadRunning = false; - ALOGW("[vts] Error %s", strerror(errno)); - } - - while (mPlaybackThreadRunning) { - // move the stream pointer for packet size * 6 every read until the end - while (*keepWritingPlaybackFMQ) { - inputData.read(buffer, writeSize); - if (!inputData) { - int leftSize = inputData.gcount(); - if (leftSize == 0) { - mPlaybackThreadRunning = false; - break; - } - inputData.clear(); - inputData.read(buffer, leftSize); - // Write the left over of the input data and quit the thread - if (leftSize > 0) { - EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], leftSize)); - playbackMQEventFlag->wake( - static_cast(DemuxQueueNotifyBits::DATA_READY)); - } - mPlaybackThreadRunning = false; - break; - } - // Write input FMQ and notify the Tuner Implementation - EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], writeSize)); - playbackMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); - inputData.seekg(writeSize, inputData.cur); - sleep(1); - } - } - - ALOGW("[vts] Playback thread end."); - - delete[] buffer; - inputData.close(); -} - -void DvrCallback::testRecordOutput() { - android::Mutex::Autolock autoLock(mMsgLock); - while (mDataOutputBuffer.empty()) { - if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { - EXPECT_TRUE(false) << "record output matching pid does not output within timeout"; - return; - } - } - stopRecordThread(); - ALOGW("[vts] record pass and stop"); -} - -void DvrCallback::startRecordOutputThread(RecordSettings recordSetting, - MQDesc& recordMQDescriptor) { - mRecordMQ = std::make_unique(recordMQDescriptor, true /* resetPointers */); - EXPECT_TRUE(mRecordMQ); - struct RecordThreadArgs* threadArgs = - (struct RecordThreadArgs*)malloc(sizeof(struct RecordThreadArgs)); - threadArgs->user = this; - threadArgs->recordSetting = &recordSetting; - threadArgs->keepReadingRecordFMQ = &mKeepReadingRecordFMQ; - - pthread_create(&mRecordThread, NULL, __threadLoopRecord, (void*)threadArgs); - pthread_setname_np(mRecordThread, "test_record_input_loop"); -} - -void* DvrCallback::__threadLoopRecord(void* threadArgs) { - DvrCallback* const self = - static_cast(((struct RecordThreadArgs*)threadArgs)->user); - self->recordThreadLoop(((struct RecordThreadArgs*)threadArgs)->recordSetting, - ((struct RecordThreadArgs*)threadArgs)->keepReadingRecordFMQ); - return 0; -} - -void DvrCallback::recordThreadLoop(RecordSettings* /*recordSetting*/, bool* keepReadingRecordFMQ) { - ALOGD("[vts] DvrCallback record threadLoop start."); - android::Mutex::Autolock autoLock(mRecordThreadLock); - mRecordThreadRunning = true; - - // Create the EventFlag that is used to signal the HAL impl that data have been - // read from the Record FMQ - EventFlag* recordMQEventFlag; - EXPECT_TRUE(EventFlag::createEventFlag(mRecordMQ->getEventFlagWord(), &recordMQEventFlag) == - android::OK); - - while (mRecordThreadRunning) { - while (*keepReadingRecordFMQ) { - uint32_t efState = 0; - android::status_t status = recordMQEventFlag->wait( - static_cast(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT, - true /* retry on spurious wake */); - if (status != android::OK) { - ALOGD("[vts] wait for data ready on the record FMQ"); - continue; - } - // Our current implementation filter the data and write it into the filter FMQ - // immediately after the DATA_READY from the VTS/framework - if (!readRecordFMQ()) { - ALOGD("[vts] record data failed to be filtered. Ending thread"); - mRecordThreadRunning = false; - break; - } - } - } - - mRecordThreadRunning = false; - ALOGD("[vts] record thread ended."); -} - -bool DvrCallback::readRecordFMQ() { - android::Mutex::Autolock autoLock(mMsgLock); - bool result = false; - mDataOutputBuffer.clear(); - mDataOutputBuffer.resize(mRecordMQ->availableToRead()); - result = mRecordMQ->read(mDataOutputBuffer.data(), mRecordMQ->availableToRead()); - EXPECT_TRUE(result) << "can't read from Record MQ"; - mMsgCondition.signal(); - return result; -} - -void DvrCallback::stopRecordThread() { - mKeepReadingRecordFMQ = false; - mRecordThreadRunning = false; - android::Mutex::Autolock autoLock(mRecordThreadLock); -} -/********************************** End DvrCallback ************************************/ - /*======================== Start Descrambler APIs Tests Implementation ========================*/ -AssertionResult TunerHidlTest::createDescrambler() { +AssertionResult TunerHidlTest::createDescrambler(uint32_t demuxId) { Result status; mService->openDescrambler([&](Result result, const sp& descrambler) { mDescrambler = descrambler; @@ -201,21 +28,19 @@ AssertionResult TunerHidlTest::createDescrambler() { return failure(); } - status = mDescrambler->setDemuxSource(mDemuxId); + status = mDescrambler->setDemuxSource(demuxId); if (status != Result::SUCCESS) { return failure(); } // Test if demux source can be set more than once. - status = mDescrambler->setDemuxSource(mDemuxId); + status = mDescrambler->setDemuxSource(demuxId); return AssertionResult(status == Result::INVALID_STATE); } AssertionResult TunerHidlTest::closeDescrambler() { Result status; - if (!mDescrambler && createDescrambler() == failure()) { - return failure(); - } + EXPECT_TRUE(mDescrambler); status = mDescrambler->close(); mDescrambler = nullptr; @@ -223,40 +48,6 @@ AssertionResult TunerHidlTest::closeDescrambler() { } /*========================= End Descrambler APIs Tests Implementation =========================*/ -/*============================ Start Dvr APIs Tests Implementation ============================*/ -AssertionResult TunerHidlTest::openDvrInDemux(DvrType type) { - Result status; - - // Create dvr callback - mDvrCallback = new DvrCallback(); - - mDemux->openDvr(type, FMQ_SIZE_1M, mDvrCallback, [&](Result result, const sp& dvr) { - mDvr = dvr; - status = result; - }); - - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::configDvr(DvrSettings setting) { - Result status = mDvr->configure(setting); - - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::getDvrMQDescriptor() { - Result status; - EXPECT_TRUE(mDvr) << "Test with openDvr first."; - - mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) { - mDvrMQDescriptor = dvrMQDesc; - status = result; - }); - - return AssertionResult(status == Result::SUCCESS); -} -/*============================ End Dvr APIs Tests Implementation ============================*/ - /*========================== Start Data Flow Tests Implementation ==========================*/ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutputFiles*/) { // Data Verify Module @@ -417,6 +208,10 @@ AssertionResult TunerHidlTest::recordDataFlowTest(vector filterConf, void TunerHidlTest::broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf) { uint32_t feId; + uint32_t demuxId; + sp demux; + uint32_t filterId; + mFrontendTests.getFrontendIdByType(frontendConf.type, feId); if (feId == INVALID_ID) { // TODO broadcast test on Cuttlefish needs licensed ts input, @@ -426,13 +221,12 @@ void TunerHidlTest::broadcastSingleFilterTest(FilterConfig filterConf, } ASSERT_TRUE(mFrontendTests.openFrontendById(feId)); ASSERT_TRUE(mFrontendTests.setFrontendCallback()); - ASSERT_TRUE(mDemuxTests.openDemux(mDemux, mDemuxId)); - mFilterTests.setDemux(mDemux); + ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId)); ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); + mFilterTests.setDemux(demux); ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type)); - uint32_t filterId; ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId)); - ASSERT_TRUE(mFilterTests.configFilter(filterConf.setting, filterId)); + ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId)); ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId)); ASSERT_TRUE(mFilterTests.startFilter(filterId)); // tune test @@ -445,6 +239,67 @@ void TunerHidlTest::broadcastSingleFilterTest(FilterConfig filterConf, ASSERT_TRUE(mDemuxTests.closeDemux()); ASSERT_TRUE(mFrontendTests.closeFrontend()); } + +void TunerDvrHidlTest::attachSingleFilterToDvrTest(FilterConfig filterConf, + FrontendConfig frontendConf, DvrConfig dvrConf) { + description("Open and configure a Dvr in Demux."); + uint32_t feId; + uint32_t demuxId; + sp demux; + uint32_t filterId; + sp filter; + + mFrontendTests.getFrontendIdByType(frontendConf.type, feId); + ASSERT_TRUE(feId != INVALID_ID); + ASSERT_TRUE(mFrontendTests.openFrontendById(feId)); + ASSERT_TRUE(mFrontendTests.setFrontendCallback()); + ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId)); + ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); + mFilterTests.setDemux(demux); + mDvrTests.setDemux(demux); + ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrConf.type)); + ASSERT_TRUE(mDvrTests.configDvr(dvrConf.settings)); + ASSERT_TRUE(mDvrTests.getDvrMQDescriptor()); + ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type)); + ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId)); + ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId)); + ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId)); + ASSERT_TRUE(mFilterTests.startFilter(filterId)); + filter = mFilterTests.getFilterById(filterId); + ASSERT_TRUE(filter != nullptr); + ASSERT_TRUE(mDvrTests.attachFilterToDvr(filter)); + ASSERT_TRUE(mDvrTests.detachFilterToDvr(filter)); + ASSERT_TRUE(mFilterTests.stopFilter(filterId)); + ASSERT_TRUE(mFilterTests.closeFilter(filterId)); + mDvrTests.closeDvr(); + ASSERT_TRUE(mDemuxTests.closeDemux()); + ASSERT_TRUE(mFrontendTests.closeFrontend()); +} + +void TunerFilterHidlTest::configSingleFilterInDemuxTest(FilterConfig filterConf, + FrontendConfig frontendConf) { + uint32_t feId; + uint32_t demuxId; + sp demux; + uint32_t filterId; + + mFrontendTests.getFrontendIdByType(frontendConf.type, feId); + ASSERT_TRUE(feId != INVALID_ID); + ASSERT_TRUE(mFrontendTests.openFrontendById(feId)); + ASSERT_TRUE(mFrontendTests.setFrontendCallback()); + ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId)); + ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); + mFilterTests.setDemux(demux); + ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type)); + ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId)); + ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId)); + ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId)); + ASSERT_TRUE(mFilterTests.startFilter(filterId)); + ASSERT_TRUE(mFilterTests.stopFilter(filterId)); + ASSERT_TRUE(mFilterTests.closeFilter(filterId)); + ASSERT_TRUE(mDemuxTests.closeDemux()); + ASSERT_TRUE(mFrontendTests.closeFrontend()); +} /*================================== End Test Module ==================================*/ /***************************** End Test Implementation *****************************/ @@ -467,50 +322,56 @@ TEST_P(TunerFrontendHidlTest, BlindScanFrontend) { TEST_P(TunerDemuxHidlTest, openDemux) { description("Open and close a Demux."); uint32_t feId; + uint32_t demuxId; + sp demux; mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId); ASSERT_TRUE(feId != INVALID_ID); ASSERT_TRUE(mFrontendTests.openFrontendById(feId)); ASSERT_TRUE(mFrontendTests.setFrontendCallback()); - ASSERT_TRUE(mDemuxTests.openDemux(mDemux, mDemuxId)); + ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId)); ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); ASSERT_TRUE(mDemuxTests.closeDemux()); } TEST_P(TunerFilterHidlTest, StartFilterInDemux) { description("Open and start a filter in Demux."); - uint32_t feId; - mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId); - ASSERT_TRUE(feId != INVALID_ID); - ASSERT_TRUE(mFrontendTests.openFrontendById(feId)); - ASSERT_TRUE(mFrontendTests.setFrontendCallback()); - ASSERT_TRUE(mDemuxTests.openDemux(mDemux, mDemuxId)); - mFilterTests.setDemux(mDemux); - ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); - ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_VIDEO0].type)); - uint32_t filterId; - ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId)); - ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_VIDEO0].setting, filterId)); - ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId)); - ASSERT_TRUE(mFilterTests.startFilter(filterId)); - ASSERT_TRUE(mFilterTests.stopFilter(filterId)); - ASSERT_TRUE(mFilterTests.closeFilter(filterId)); - ASSERT_TRUE(mDemuxTests.closeDemux()); - ASSERT_TRUE(mFrontendTests.closeFrontend()); + // TODO use paramterized tests + configSingleFilterInDemuxTest(filterArray[TS_VIDEO0], frontendArray[DVBT]); +} + +TEST_P(TunerDvrHidlTest, AttachFiltersToRecordTest) { + description("Attach a single filter to the record dvr test."); + // TODO use paramterized tests + attachSingleFilterToDvrTest(filterArray[TS_VIDEO0], frontendArray[DVBT], dvrArray[DVR_RECORD0]); +} + +TEST_P(TunerDvrHidlTest, AttachFiltersToPlaybackTest) { + description("Attach a single filter to the playback dvr test."); + // TODO use paramterized tests + attachSingleFilterToDvrTest(filterArray[TS_VIDEO0], frontendArray[DVBT], + dvrArray[DVR_PLAYBACK0]); } /*============================ Start Descrambler Tests ============================*/ /* * TODO: re-enable the tests after finalizing the test refactoring. */ -/*TEST_P(TunerHidlTest, CreateDescrambler) { +TEST_P(TunerHidlTest, CreateDescrambler) { description("Create Descrambler"); - ASSERT_TRUE(createDescrambler()); + uint32_t feId; + uint32_t demuxId; + sp demux; + mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId); + ASSERT_TRUE(feId != INVALID_ID); + ASSERT_TRUE(mFrontendTests.openFrontendById(feId)); + ASSERT_TRUE(mFrontendTests.setFrontendCallback()); + ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId)); + ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); + ASSERT_TRUE(createDescrambler(demuxId)); + ASSERT_TRUE(mDemuxTests.closeDemux()); + ASSERT_TRUE(closeDescrambler()); } -TEST_P(TunerHidlTest, CloseDescrambler) { - description("Close Descrambler"); - ASSERT_TRUE(closeDescrambler()); -}*/ /*============================== End Descrambler Tests ==============================*/ /*============================== Start Data Flow Tests ==============================*/ @@ -642,4 +503,9 @@ INSTANTIATE_TEST_SUITE_P( PerInstance, TunerFilterHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), android::hardware::PrintInstanceNameToString); + +INSTANTIATE_TEST_SUITE_P( + PerInstance, TunerDvrHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), + android::hardware::PrintInstanceNameToString); } // namespace diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h index f17704774c..37b28660fb 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h @@ -15,30 +15,13 @@ */ #include -#include -#include -#include -#include #include "DemuxTests.h" -#include "FilterTests.h" +#include "DvrTests.h" #include "FrontendTests.h" using android::hardware::tv::tuner::V1_0::DataFormat; -using android::hardware::tv::tuner::V1_0::DvrSettings; -using android::hardware::tv::tuner::V1_0::DvrType; using android::hardware::tv::tuner::V1_0::IDescrambler; -using android::hardware::tv::tuner::V1_0::IDvr; -using android::hardware::tv::tuner::V1_0::IDvrCallback; -using android::hardware::tv::tuner::V1_0::PlaybackSettings; -using android::hardware::tv::tuner::V1_0::PlaybackStatus; -using android::hardware::tv::tuner::V1_0::RecordSettings; -using android::hardware::tv::tuner::V1_0::RecordStatus; - -struct PlaybackConf { - string inputDataFile; - PlaybackSettings setting; -}; static AssertionResult failure() { return ::testing::AssertionFailure(); @@ -50,89 +33,6 @@ static AssertionResult success() { namespace { -class DvrCallback : public IDvrCallback { - public: - virtual Return onRecordStatus(DemuxFilterStatus status) override { - ALOGW("[vts] record status %hhu", status); - switch (status) { - case DemuxFilterStatus::DATA_READY: - break; - case DemuxFilterStatus::LOW_WATER: - break; - case DemuxFilterStatus::HIGH_WATER: - case DemuxFilterStatus::OVERFLOW: - ALOGW("[vts] record overflow. Flushing"); - break; - } - return Void(); - } - - virtual Return onPlaybackStatus(PlaybackStatus status) override { - // android::Mutex::Autolock autoLock(mMsgLock); - ALOGW("[vts] playback status %d", status); - switch (status) { - case PlaybackStatus::SPACE_EMPTY: - case PlaybackStatus::SPACE_ALMOST_EMPTY: - ALOGW("[vts] keep playback inputing %d", status); - mKeepWritingPlaybackFMQ = true; - break; - case PlaybackStatus::SPACE_ALMOST_FULL: - case PlaybackStatus::SPACE_FULL: - ALOGW("[vts] stop playback inputing %d", status); - mKeepWritingPlaybackFMQ = false; - break; - } - return Void(); - } - - void testFilterDataOutput(); - void stopPlaybackThread(); - void testRecordOutput(); - void stopRecordThread(); - - void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor); - void startRecordOutputThread(RecordSettings recordSetting, MQDesc& recordMQDescriptor); - static void* __threadLoopPlayback(void* threadArgs); - static void* __threadLoopRecord(void* threadArgs); - void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ); - void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ); - - bool readRecordFMQ(); - - private: - struct PlaybackThreadArgs { - DvrCallback* user; - PlaybackConf* playbackConf; - bool* keepWritingPlaybackFMQ; - }; - struct RecordThreadArgs { - DvrCallback* user; - RecordSettings* recordSetting; - bool* keepReadingRecordFMQ; - }; - uint16_t mDataLength = 0; - std::vector mDataOutputBuffer; - - std::map> mFilterMQ; - std::unique_ptr mPlaybackMQ; - std::unique_ptr mRecordMQ; - std::map mFilterMQEventFlag; - - android::Mutex mMsgLock; - android::Mutex mPlaybackThreadLock; - android::Mutex mRecordThreadLock; - android::Condition mMsgCondition; - - bool mKeepWritingPlaybackFMQ = true; - bool mKeepReadingRecordFMQ = true; - bool mPlaybackThreadRunning; - bool mRecordThreadRunning; - pthread_t mPlaybackThread; - pthread_t mRecordThread; - - int mPidFilterOutputCount = 0; -}; - class TunerFrontendHidlTest : public testing::TestWithParam { public: virtual void SetUp() override { @@ -174,8 +74,6 @@ class TunerDemuxHidlTest : public testing::TestWithParam { sp mService; FrontendTests mFrontendTests; DemuxTests mDemuxTests; - sp mDemux; - uint32_t mDemuxId; }; class TunerFilterHidlTest : public testing::TestWithParam { @@ -197,21 +95,47 @@ class TunerFilterHidlTest : public testing::TestWithParam { RecordProperty("description", description); } + void configSingleFilterInDemuxTest(FilterConfig filterConf, FrontendConfig frontendConf); + sp mService; FrontendTests mFrontendTests; DemuxTests mDemuxTests; FilterTests mFilterTests; - sp mDemux; - uint32_t mDemuxId; +}; + +class TunerDvrHidlTest : public testing::TestWithParam { + public: + virtual void SetUp() override { + mService = ITuner::getService(GetParam()); + ASSERT_NE(mService, nullptr); + initFrontendConfig(); + initFrontendScanConfig(); + initFilterConfig(); + initDvrConfig(); + + mFrontendTests.setService(mService); + mDemuxTests.setService(mService); + mFilterTests.setService(mService); + mDvrTests.setService(mService); + } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + void attachSingleFilterToDvrTest(FilterConfig filterConf, FrontendConfig frontendConf, + DvrConfig dvrConf); + + sp mService; + FrontendTests mFrontendTests; + DemuxTests mDemuxTests; + FilterTests mFilterTests; + DvrTests mDvrTests; }; class TunerHidlTest : public testing::TestWithParam { public: - sp mService; - FrontendTests mFrontendTests; - DemuxTests mDemuxTests; - FilterTests mFilterTests; - virtual void SetUp() override { mService = ITuner::getService(GetParam()); ASSERT_NE(mService, nullptr); @@ -229,23 +153,14 @@ class TunerHidlTest : public testing::TestWithParam { RecordProperty("description", description); } + sp mService; + FrontendTests mFrontendTests; + DemuxTests mDemuxTests; + FilterTests mFilterTests; + sp mDescrambler; - sp mDvr; - sp mDemux; - uint32_t mDemuxId; - sp mDvrCallback; - MQDesc mDvrMQDescriptor; - MQDesc mRecordMQDescriptor; - - pthread_t mPlaybackshread; - bool mPlaybackThreadRunning; - - AssertionResult openDvrInDemux(DvrType type); - AssertionResult configDvr(DvrSettings setting); - AssertionResult getDvrMQDescriptor(); - - AssertionResult createDescrambler(); + AssertionResult createDescrambler(uint32_t demuxId); AssertionResult closeDescrambler(); AssertionResult playbackDataFlowTest(vector filterConf, PlaybackConf playbackConf, @@ -257,4 +172,4 @@ class TunerHidlTest : public testing::TestWithParam { void broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf); }; -} // namespace \ No newline at end of file +} // namespace diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h index 10c60142ba..1c25c51cf9 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h @@ -21,12 +21,15 @@ #include #include +using android::hardware::tv::tuner::V1_0::DataFormat; using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; using android::hardware::tv::tuner::V1_0::DemuxFilterMainType; using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterType; using android::hardware::tv::tuner::V1_0::DemuxTpid; using android::hardware::tv::tuner::V1_0::DemuxTsFilterType; +using android::hardware::tv::tuner::V1_0::DvrSettings; +using android::hardware::tv::tuner::V1_0::DvrType; using android::hardware::tv::tuner::V1_0::FrontendDvbtBandwidth; using android::hardware::tv::tuner::V1_0::FrontendDvbtCoderate; using android::hardware::tv::tuner::V1_0::FrontendDvbtConstellation; @@ -37,6 +40,8 @@ using android::hardware::tv::tuner::V1_0::FrontendDvbtStandard; using android::hardware::tv::tuner::V1_0::FrontendDvbtTransmissionMode; using android::hardware::tv::tuner::V1_0::FrontendSettings; using android::hardware::tv::tuner::V1_0::FrontendType; +using android::hardware::tv::tuner::V1_0::PlaybackSettings; +using android::hardware::tv::tuner::V1_0::RecordSettings; typedef enum { TS_VIDEO0, @@ -60,9 +65,15 @@ typedef enum { SCAN_MAX, } FrontendScan; +typedef enum { + DVR_RECORD0, + DVR_PLAYBACK0, + DVR_MAX, +} Dvr; + struct FilterConfig { DemuxFilterType type; - DemuxFilterSettings setting; + DemuxFilterSettings settings; }; struct FrontendConfig { @@ -78,10 +89,16 @@ struct ChannelConfig { DemuxTpid audioPid; }; +struct DvrConfig { + DvrType type; + DvrSettings settings; +}; + static FrontendConfig frontendArray[FILTER_MAX]; static FrontendConfig frontendScanArray[SCAN_MAX]; static ChannelConfig channelArray[FRONTEND_MAX]; static FilterConfig filterArray[FILTER_MAX]; +static DvrConfig dvrArray[DVR_MAX]; static vector goldenOutputFiles; /** Configuration array for the frontend tune test */ @@ -124,40 +141,62 @@ inline void initFilterConfig() { // TS VIDEO filter setting for default implementation testing filterArray[TS_VIDEO0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_VIDEO0].type.subType.tsFilterType(DemuxTsFilterType::VIDEO); - filterArray[TS_VIDEO0].setting.ts().tpid = 119; - filterArray[TS_VIDEO0].setting.ts().filterSettings.av({.isPassthrough = false}); + filterArray[TS_VIDEO0].settings.ts().tpid = 119; + filterArray[TS_VIDEO0].settings.ts().filterSettings.av({.isPassthrough = false}); filterArray[TS_VIDEO1].type.mainType = DemuxFilterMainType::TS; filterArray[TS_VIDEO1].type.subType.tsFilterType(DemuxTsFilterType::VIDEO); - filterArray[TS_VIDEO1].setting.ts().tpid = 81; - filterArray[TS_VIDEO1].setting.ts().filterSettings.av({.isPassthrough = false}); + filterArray[TS_VIDEO1].settings.ts().tpid = 81; + filterArray[TS_VIDEO1].settings.ts().filterSettings.av({.isPassthrough = false}); // TS AUDIO filter setting filterArray[TS_AUDIO0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_AUDIO0].type.subType.tsFilterType(DemuxTsFilterType::AUDIO); - filterArray[TS_AUDIO0].setting.ts().tpid = 84; - filterArray[TS_AUDIO0].setting.ts().filterSettings.av({.isPassthrough = false}); + filterArray[TS_AUDIO0].settings.ts().tpid = 84; + filterArray[TS_AUDIO0].settings.ts().filterSettings.av({.isPassthrough = false}); // TS PES filter setting filterArray[TS_PES0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_PES0].type.subType.tsFilterType(DemuxTsFilterType::PES); - filterArray[TS_PES0].setting.ts().tpid = 256; - filterArray[TS_PES0].setting.ts().filterSettings.pesData({ + filterArray[TS_PES0].settings.ts().tpid = 256; + filterArray[TS_PES0].settings.ts().filterSettings.pesData({ .isRaw = false, .streamId = 0xbd, }); // TS PCR filter setting filterArray[TS_PCR0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_PCR0].type.subType.tsFilterType(DemuxTsFilterType::PCR); - filterArray[TS_PCR0].setting.ts().tpid = 81; - filterArray[TS_PCR0].setting.ts().filterSettings.noinit(); + filterArray[TS_PCR0].settings.ts().tpid = 81; + filterArray[TS_PCR0].settings.ts().filterSettings.noinit(); // TS filter setting filterArray[TS_TS0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_TS0].type.subType.tsFilterType(DemuxTsFilterType::TS); - filterArray[TS_TS0].setting.ts().tpid = 48; - filterArray[TS_TS0].setting.ts().filterSettings.noinit(); + filterArray[TS_TS0].settings.ts().tpid = 48; + filterArray[TS_TS0].settings.ts().filterSettings.noinit(); // TS SECTION filter setting filterArray[TS_SECTION0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_SECTION0].type.subType.tsFilterType(DemuxTsFilterType::SECTION); - filterArray[TS_SECTION0].setting.ts().tpid = 48; - filterArray[TS_SECTION0].setting.ts().filterSettings.section({ + filterArray[TS_SECTION0].settings.ts().tpid = 48; + filterArray[TS_SECTION0].settings.ts().filterSettings.section({ .isRaw = false, }); }; + +/** Configuration array for the dvr test */ +inline void initDvrConfig() { + RecordSettings recordSettings{ + .statusMask = 0xf, + .lowThreshold = 0x1000, + .highThreshold = 0x07fff, + .dataFormat = DataFormat::TS, + .packetSize = 188, + }; + dvrArray[DVR_RECORD0].type = DvrType::RECORD; + dvrArray[DVR_RECORD0].settings.record(recordSettings); + PlaybackSettings playbackSettings{ + .statusMask = 0xf, + .lowThreshold = 0x1000, + .highThreshold = 0x07fff, + .dataFormat = DataFormat::TS, + .packetSize = 188, + }; + dvrArray[DVR_PLAYBACK0].type = DvrType::PLAYBACK; + dvrArray[DVR_PLAYBACK0].settings.playback(playbackSettings); +}; \ No newline at end of file From 0d69b72097c3899935d9dd2abf831d5badf90ee5 Mon Sep 17 00:00:00 2001 From: chrisweir Date: Wed, 15 Apr 2020 11:01:20 -0700 Subject: [PATCH 0858/1022] Undo symlinked libc++fs Several features for auto need libc++fs, but the previous solution of symlinking to external/libcxx would cause problems later down the line. Instead, we will compile a separate version of libc++fs with a different namespace, as to not interfere with the canonical std::filesystem. Change summary =============================================================== directory_iterator.cpp: ----------------------- * _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM --> namespace android::hardware::automotive::filesystem { * _LIBCPP_END_NAMESPACE_FILESYSTEM --> } // namespace android::hardware::automotive::filesystem * disable clang-format (to reduce diff size) * "" --> <> for non-local includes filesystem_common.h: -------------------- * FILESYSTEM_COMMON_H --> AUTO_FILESYSTEM_COMMON_H * "" --> <> for non-local includes * filesystem --> automotive/filesystem * don't include apple_availability.h * add using std::error_code * _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM --> namespace android::hardware::automotive::filesystem { * use namespace std::chrono * use std::error_code, std::is_floating_point, std::micro, std::nano, std::ratio * LIBCPP_END_NAMESPACE_FILESYSTEM --> } // namespace android::hardware::automotive::filesystem * disable clang format (to reduce diff size) filesystem: ----------- * _LIBCPP_FILESYSTEM --> _LIBAUTO_FILESYSTEM * std::filesystem --> android::hardware:automotive::filesystem * _VSTD_FS --> android::hardware::automotive::filesystem * _LIBCPP_END_NAMESPACE_FILESYSTEM --> } // namespace android::hardware::automotive::filesystem * Copied _FilesystemClock from chrono * use namespace std and std::chrono * use std::basic_string, std::enable_if, std::error_code, and std::false_type operations.cpp: --------------- * filesystem --> automotive/filesystem * "" --> <> for non-local includes * _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM --> namespace android::hardware::automotive::filesystem { * _VSTD_FS --> android::hardware::automotive::filesystem * _LIBCPP_END_NAMESPACE_FILESYSTEM --> } // namespace android::hardware::automotive::filesystem * disable clang-format (to reduce diff size) * fix "the the" typo (to pass lint) Bug: 152067309 Test: Manual Change-Id: I5551b3e634b85b4d7236e888de68740bfda6aad1 --- automotive/can/1.0/default/CanController.cpp | 25 +- .../can/1.0/default/libc++fs/.clang-format | 13 + .../can/1.0/default/libc++fs/Android.bp | 24 +- automotive/can/1.0/default/libc++fs/include | 1 - .../libc++fs/include/automotive/filesystem | 2699 +++++++++++++++++ automotive/can/1.0/default/libc++fs/src | 1 - .../src/filesystem/directory_iterator.cpp | 397 +++ .../src/filesystem/filesystem_common.h | 441 +++ .../libc++fs/src/filesystem/operations.cpp | 1773 +++++++++++ 9 files changed, 5337 insertions(+), 37 deletions(-) create mode 100644 automotive/can/1.0/default/libc++fs/.clang-format delete mode 120000 automotive/can/1.0/default/libc++fs/include create mode 100644 automotive/can/1.0/default/libc++fs/include/automotive/filesystem delete mode 120000 automotive/can/1.0/default/libc++fs/src create mode 100644 automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp create mode 100644 automotive/can/1.0/default/libc++fs/src/filesystem/filesystem_common.h create mode 100644 automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp index a2643afccf..9c0f2c57a2 100644 --- a/automotive/can/1.0/default/CanController.cpp +++ b/automotive/can/1.0/default/CanController.cpp @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include @@ -31,6 +31,7 @@ namespace android::hardware::automotive::can::V1_0::implementation { using IfId = ICanController::BusConfig::InterfaceId; using IfIdDisc = ICanController::BusConfig::InterfaceId::hidl_discriminator; +namespace fs = android::hardware::automotive::filesystem; namespace fsErrors { static const std::error_code ok; @@ -42,10 +43,10 @@ static const std::error_code eacces(EACCES, std::generic_category()); /* In the /sys/devices tree, there are files called "serial", which contain the serial numbers * for various devices. The exact location inside of this directory is dependent upon the * hardware we are running on, so we have to start from /sys/devices and work our way down. */ -static const std::filesystem::path kDevPath("/sys/devices/"); +static const fs::path kDevPath("/sys/devices/"); static const std::regex kTtyRe("^tty[A-Z]+[0-9]+$"); -static constexpr auto kOpts = ~(std::filesystem::directory_options::follow_directory_symlink | - std::filesystem::directory_options::skip_permission_denied); +static constexpr auto kOpts = ~(fs::directory_options::follow_directory_symlink | + fs::directory_options::skip_permission_denied); /** * A helper object to associate the interface name and type of a USB to CAN adapter. @@ -72,16 +73,16 @@ static bool isValidName(const std::string& name) { * \param serialPath - Absolute path to a "serial" file for a given device in /sys. * \return A populated UsbCanIface. On failure, nullopt is returned. */ -static std::optional getIfaceName(std::filesystem::path serialPath) { +static std::optional getIfaceName(fs::path serialPath) { std::error_code fsStatus; // Since the path is to a file called "serial", we need to search its parent directory. - std::filesystem::recursive_directory_iterator fsItr(serialPath.parent_path(), kOpts, fsStatus); + fs::recursive_directory_iterator fsItr(serialPath.parent_path(), kOpts, fsStatus); if (fsStatus != fsErrors::ok) { LOG(ERROR) << "Failed to open " << serialPath.parent_path(); return std::nullopt; } - for (; fsStatus == fsErrors::ok && fsItr != std::filesystem::recursive_directory_iterator(); + for (; fsStatus == fsErrors::ok && fsItr != fs::recursive_directory_iterator(); fsItr.increment(fsStatus)) { /* We want either a directory called "net" or a directory that looks like tty, so * skip files. */ @@ -95,7 +96,7 @@ static std::optional getIfaceName(std::filesystem::path serialPath) if (currentDir == "net") { /* This device is a SocketCAN device. The iface name is the only directory under * net/. Multiple directories under net/ is an error.*/ - std::filesystem::directory_iterator netItr(fsItr->path(), kOpts, fsStatus); + fs::directory_iterator netItr(fsItr->path(), kOpts, fsStatus); if (fsStatus != fsErrors::ok) { LOG(ERROR) << "Failed to open " << fsItr->path() << " to get net name!"; return std::nullopt; @@ -111,7 +112,7 @@ static std::optional getIfaceName(std::filesystem::path serialPath) LOG(ERROR) << "Failed to verify " << fsItr->path() << " has valid net name!"; return std::nullopt; } - if (netItr != std::filesystem::directory_iterator()) { + if (netItr != fs::directory_iterator()) { // There should never be more than one name under net/ LOG(ERROR) << "Found more than one net name in " << fsItr->path() << "!"; return std::nullopt; @@ -157,13 +158,13 @@ static std::optional readSerialNo(const std::string& serialnoPath) */ static std::optional findUsbDevice(const hidl_vec& configSerialnos) { std::error_code fsStatus; - std::filesystem::recursive_directory_iterator fsItr(kDevPath, kOpts, fsStatus); + fs::recursive_directory_iterator fsItr(kDevPath, kOpts, fsStatus); if (fsStatus != fsErrors::ok) { LOG(ERROR) << "Failed to open " << kDevPath; return std::nullopt; } - for (; fsStatus == fsErrors::ok && fsItr != std::filesystem::recursive_directory_iterator(); + for (; fsStatus == fsErrors::ok && fsItr != fs::recursive_directory_iterator(); fsItr.increment(fsStatus)) { // We want to find a file called "serial", which is in a directory somewhere. Skip files. bool isDir = fsItr->is_directory(fsStatus); @@ -174,7 +175,7 @@ static std::optional findUsbDevice(const hidl_vec& con if (!isDir) continue; auto serialnoPath = fsItr->path() / "serial"; - bool isReg = std::filesystem::is_regular_file(serialnoPath, fsStatus); + bool isReg = fs::is_regular_file(serialnoPath, fsStatus); /* Make sure we have permissions to this directory, ignore enoent, since the file * "serial" may not exist, which is ok. */ diff --git a/automotive/can/1.0/default/libc++fs/.clang-format b/automotive/can/1.0/default/libc++fs/.clang-format new file mode 100644 index 0000000000..dd596813fb --- /dev/null +++ b/automotive/can/1.0/default/libc++fs/.clang-format @@ -0,0 +1,13 @@ +BasedOnStyle: LLVM + +--- +Language: Cpp +Standard: Cpp03 + +AlwaysBreakTemplateDeclarations: true +PointerAlignment: Left + +# Disable formatting options which may break tests. +SortIncludes: false +ReflowComments: false +--- diff --git a/automotive/can/1.0/default/libc++fs/Android.bp b/automotive/can/1.0/default/libc++fs/Android.bp index 1fe324ed0f..7ab1c28b3b 100644 --- a/automotive/can/1.0/default/libc++fs/Android.bp +++ b/automotive/can/1.0/default/libc++fs/Android.bp @@ -19,7 +19,6 @@ cc_defaults { name: "android.hardware.automotive@libc++fsdefaults", - host_supported: true, local_include_dirs: ["include"], export_include_dirs: ["include"], cflags: [ @@ -28,33 +27,12 @@ cc_defaults { "-Wno-unused-parameter", ], cppflags: [ - "-std=c++14", + "-std=c++17", "-fexceptions", "-DLIBCXX_BUILDING_LIBCXXABI", "-D_LIBCPP_BUILDING_LIBRARY", ], rtti: true, - stl: "none", - target: { - linux_bionic: { - enabled: true, - }, - windows: { - enabled: true, - cflags: [ - "-D_LIBCPP_HAS_THREAD_API_WIN32", - "-D_LIBCXXABI_BUILDING_LIBRARY", - "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS", - "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", - "-UWIN32_LEAN_AND_MEAN", - ], - }, - windows_x86: { - cflags: [ - "-fsjlj-exceptions", - ], - }, - }, } cc_library_static { diff --git a/automotive/can/1.0/default/libc++fs/include b/automotive/can/1.0/default/libc++fs/include deleted file mode 120000 index 346e65945a..0000000000 --- a/automotive/can/1.0/default/libc++fs/include +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../external/libcxx/include/ \ No newline at end of file diff --git a/automotive/can/1.0/default/libc++fs/include/automotive/filesystem b/automotive/can/1.0/default/libc++fs/include/automotive/filesystem new file mode 100644 index 0000000000..660ad09745 --- /dev/null +++ b/automotive/can/1.0/default/libc++fs/include/automotive/filesystem @@ -0,0 +1,2699 @@ +// -*- C++ -*- +//===--------------------------- filesystem -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef _LIBAUTO_FILESYSTEM +#define _LIBAUTO_FILESYSTEM +/* + filesystem synopsis + + namespace android::hardware::automotive { namespace filesystem { + + class path; + + void swap(path& lhs, path& rhs) noexcept; + size_t hash_value(const path& p) noexcept; + + bool operator==(const path& lhs, const path& rhs) noexcept; + bool operator!=(const path& lhs, const path& rhs) noexcept; + bool operator< (const path& lhs, const path& rhs) noexcept; + bool operator<=(const path& lhs, const path& rhs) noexcept; + bool operator> (const path& lhs, const path& rhs) noexcept; + bool operator>=(const path& lhs, const path& rhs) noexcept; + + path operator/ (const path& lhs, const path& rhs); + + // fs.path.io operators are friends of path. + template + friend basic_ostream& + operator<<(basic_ostream& os, const path& p); + + template + friend basic_istream& + operator>>(basic_istream& is, path& p); + + template + path u8path(const Source& source); + template + path u8path(InputIterator first, InputIterator last); + + class filesystem_error; + class directory_entry; + + class directory_iterator; + + // enable directory_iterator range-based for statements + directory_iterator begin(directory_iterator iter) noexcept; + directory_iterator end(const directory_iterator&) noexcept; + + class recursive_directory_iterator; + + // enable recursive_directory_iterator range-based for statements + recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept; + recursive_directory_iterator end(const recursive_directory_iterator&) noexcept; + + class file_status; + + struct space_info + { + uintmax_t capacity; + uintmax_t free; + uintmax_t available; + }; + + enum class file_type; + enum class perms; + enum class perm_options; + enum class copy_options; + enum class directory_options; + + typedef chrono::time_point file_time_type; + + // operational functions + + path absolute(const path& p); + path absolute(const path& p, error_code &ec); + + path canonical(const path& p); + path canonical(const path& p, error_code& ec); + + void copy(const path& from, const path& to); + void copy(const path& from, const path& to, error_code& ec); + void copy(const path& from, const path& to, copy_options options); + void copy(const path& from, const path& to, copy_options options, + error_code& ec); + + bool copy_file(const path& from, const path& to); + bool copy_file(const path& from, const path& to, error_code& ec); + bool copy_file(const path& from, const path& to, copy_options option); + bool copy_file(const path& from, const path& to, copy_options option, + error_code& ec); + + void copy_symlink(const path& existing_symlink, const path& new_symlink); + void copy_symlink(const path& existing_symlink, const path& new_symlink, + error_code& ec) noexcept; + + bool create_directories(const path& p); + bool create_directories(const path& p, error_code& ec); + + bool create_directory(const path& p); + bool create_directory(const path& p, error_code& ec) noexcept; + + bool create_directory(const path& p, const path& attributes); + bool create_directory(const path& p, const path& attributes, + error_code& ec) noexcept; + + void create_directory_symlink(const path& to, const path& new_symlink); + void create_directory_symlink(const path& to, const path& new_symlink, + error_code& ec) noexcept; + + void create_hard_link(const path& to, const path& new_hard_link); + void create_hard_link(const path& to, const path& new_hard_link, + error_code& ec) noexcept; + + void create_symlink(const path& to, const path& new_symlink); + void create_symlink(const path& to, const path& new_symlink, + error_code& ec) noexcept; + + path current_path(); + path current_path(error_code& ec); + void current_path(const path& p); + void current_path(const path& p, error_code& ec) noexcept; + + bool exists(file_status s) noexcept; + bool exists(const path& p); + bool exists(const path& p, error_code& ec) noexcept; + + bool equivalent(const path& p1, const path& p2); + bool equivalent(const path& p1, const path& p2, error_code& ec) noexcept; + + uintmax_t file_size(const path& p); + uintmax_t file_size(const path& p, error_code& ec) noexcept; + + uintmax_t hard_link_count(const path& p); + uintmax_t hard_link_count(const path& p, error_code& ec) noexcept; + + bool is_block_file(file_status s) noexcept; + bool is_block_file(const path& p); + bool is_block_file(const path& p, error_code& ec) noexcept; + + bool is_character_file(file_status s) noexcept; + bool is_character_file(const path& p); + bool is_character_file(const path& p, error_code& ec) noexcept; + + bool is_directory(file_status s) noexcept; + bool is_directory(const path& p); + bool is_directory(const path& p, error_code& ec) noexcept; + + bool is_empty(const path& p); + bool is_empty(const path& p, error_code& ec) noexcept; + + bool is_fifo(file_status s) noexcept; + bool is_fifo(const path& p); + bool is_fifo(const path& p, error_code& ec) noexcept; + + bool is_other(file_status s) noexcept; + bool is_other(const path& p); + bool is_other(const path& p, error_code& ec) noexcept; + + bool is_regular_file(file_status s) noexcept; + bool is_regular_file(const path& p); + bool is_regular_file(const path& p, error_code& ec) noexcept; + + bool is_socket(file_status s) noexcept; + bool is_socket(const path& p); + bool is_socket(const path& p, error_code& ec) noexcept; + + bool is_symlink(file_status s) noexcept; + bool is_symlink(const path& p); + bool is_symlink(const path& p, error_code& ec) noexcept; + + file_time_type last_write_time(const path& p); + file_time_type last_write_time(const path& p, error_code& ec) noexcept; + void last_write_time(const path& p, file_time_type new_time); + void last_write_time(const path& p, file_time_type new_time, + error_code& ec) noexcept; + + void permissions(const path& p, perms prms, + perm_options opts=perm_options::replace); + void permissions(const path& p, perms prms, error_code& ec) noexcept; + void permissions(const path& p, perms prms, perm_options opts, + error_code& ec); + + path proximate(const path& p, error_code& ec); + path proximate(const path& p, const path& base = current_path()); + path proximate(const path& p, const path& base, error_code &ec); + + path read_symlink(const path& p); + path read_symlink(const path& p, error_code& ec); + + path relative(const path& p, error_code& ec); + path relative(const path& p, const path& base=current_path()); + path relative(const path& p, const path& base, error_code& ec); + + bool remove(const path& p); + bool remove(const path& p, error_code& ec) noexcept; + + uintmax_t remove_all(const path& p); + uintmax_t remove_all(const path& p, error_code& ec); + + void rename(const path& from, const path& to); + void rename(const path& from, const path& to, error_code& ec) noexcept; + + void resize_file(const path& p, uintmax_t size); + void resize_file(const path& p, uintmax_t size, error_code& ec) noexcept; + + space_info space(const path& p); + space_info space(const path& p, error_code& ec) noexcept; + + file_status status(const path& p); + file_status status(const path& p, error_code& ec) noexcept; + + bool status_known(file_status s) noexcept; + + file_status symlink_status(const path& p); + file_status symlink_status(const path& p, error_code& ec) noexcept; + + path temp_directory_path(); + path temp_directory_path(error_code& ec); + + path weakly_canonical(path const& p); + path weakly_canonical(path const& p, error_code& ec); + + +} } // namespace android::hardware::automotive::filesystem + +*/ + +#include <__config> +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for quoted +#include +#include + +#include <__debug> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#ifndef _LIBCPP_CXX03_LANG + +namespace android::hardware::automotive::filesystem { +using namespace std; +using namespace std::chrono; + +using std::basic_string; +using std::enable_if; +using std::error_code; +using std::false_type; + +#ifndef _VSTD +#define _LIBAUTO_UNDEF_VSTD +#define _VSTD std +#endif + +#ifdef _VSTD_FS +#pragma push_macro("_VSTD_FS") +#else +#define _LIBAUTO_UNDEF_VSTD_FS +#endif +#define _VSTD_FS android::hardware::automotive::filesystem + +/* Begin copy of _FilesystemClock from include/chrono */ +struct _FilesystemClock { +#if !defined(_LIBCPP_HAS_NO_INT128) + typedef __int128_t rep; + typedef nano period; +#else + typedef long long rep; + typedef nano period; +#endif + + typedef chrono::duration duration; + typedef chrono::time_point<_FilesystemClock> time_point; + + static _LIBCPP_CONSTEXPR_AFTER_CXX11 const bool is_steady = false; + + _LIBCPP_FUNC_VIS static time_point now() noexcept; + + _LIBCPP_INLINE_VISIBILITY + static time_t to_time_t(const time_point& __t) noexcept { + typedef chrono::duration __secs; + return time_t( + chrono::duration_cast<__secs>(__t.time_since_epoch()).count()); + } + + _LIBCPP_INLINE_VISIBILITY + static time_point from_time_t(time_t __t) noexcept { + typedef chrono::duration __secs; + return time_point(__secs(__t)); + } +}; +/* End copy of _FilesystemClock from include/chrono */ + +typedef chrono::time_point<_FilesystemClock> file_time_type; + +struct _LIBCPP_TYPE_VIS space_info { + uintmax_t capacity; + uintmax_t free; + uintmax_t available; +}; + +enum class _LIBCPP_ENUM_VIS file_type : signed char { + none = 0, + not_found = -1, + regular = 1, + directory = 2, + symlink = 3, + block = 4, + character = 5, + fifo = 6, + socket = 7, + unknown = 8 +}; + +enum class _LIBCPP_ENUM_VIS perms : unsigned { + none = 0, + + owner_read = 0400, + owner_write = 0200, + owner_exec = 0100, + owner_all = 0700, + + group_read = 040, + group_write = 020, + group_exec = 010, + group_all = 070, + + others_read = 04, + others_write = 02, + others_exec = 01, + others_all = 07, + + all = 0777, + + set_uid = 04000, + set_gid = 02000, + sticky_bit = 01000, + mask = 07777, + unknown = 0xFFFF, +}; + +_LIBCPP_INLINE_VISIBILITY +inline constexpr perms operator&(perms _LHS, perms _RHS) { + return static_cast(static_cast(_LHS) & + static_cast(_RHS)); +} + +_LIBCPP_INLINE_VISIBILITY +inline constexpr perms operator|(perms _LHS, perms _RHS) { + return static_cast(static_cast(_LHS) | + static_cast(_RHS)); +} + +_LIBCPP_INLINE_VISIBILITY +inline constexpr perms operator^(perms _LHS, perms _RHS) { + return static_cast(static_cast(_LHS) ^ + static_cast(_RHS)); +} + +_LIBCPP_INLINE_VISIBILITY +inline constexpr perms operator~(perms _LHS) { + return static_cast(~static_cast(_LHS)); +} + +_LIBCPP_INLINE_VISIBILITY +inline perms& operator&=(perms& _LHS, perms _RHS) { return _LHS = _LHS & _RHS; } + +_LIBCPP_INLINE_VISIBILITY +inline perms& operator|=(perms& _LHS, perms _RHS) { return _LHS = _LHS | _RHS; } + +_LIBCPP_INLINE_VISIBILITY +inline perms& operator^=(perms& _LHS, perms _RHS) { return _LHS = _LHS ^ _RHS; } + +enum class _LIBCPP_ENUM_VIS perm_options : unsigned char { + replace = 1, + add = 2, + remove = 4, + nofollow = 8 +}; + +_LIBCPP_INLINE_VISIBILITY +inline constexpr perm_options operator&(perm_options _LHS, perm_options _RHS) { + return static_cast(static_cast(_LHS) & + static_cast(_RHS)); +} + +_LIBCPP_INLINE_VISIBILITY +inline constexpr perm_options operator|(perm_options _LHS, perm_options _RHS) { + return static_cast(static_cast(_LHS) | + static_cast(_RHS)); +} + +_LIBCPP_INLINE_VISIBILITY +inline constexpr perm_options operator^(perm_options _LHS, perm_options _RHS) { + return static_cast(static_cast(_LHS) ^ + static_cast(_RHS)); +} + +_LIBCPP_INLINE_VISIBILITY +inline constexpr perm_options operator~(perm_options _LHS) { + return static_cast(~static_cast(_LHS)); +} + +_LIBCPP_INLINE_VISIBILITY +inline perm_options& operator&=(perm_options& _LHS, perm_options _RHS) { + return _LHS = _LHS & _RHS; +} + +_LIBCPP_INLINE_VISIBILITY +inline perm_options& operator|=(perm_options& _LHS, perm_options _RHS) { + return _LHS = _LHS | _RHS; +} + +_LIBCPP_INLINE_VISIBILITY +inline perm_options& operator^=(perm_options& _LHS, perm_options _RHS) { + return _LHS = _LHS ^ _RHS; +} + +enum class _LIBCPP_ENUM_VIS copy_options : unsigned short { + none = 0, + skip_existing = 1, + overwrite_existing = 2, + update_existing = 4, + recursive = 8, + copy_symlinks = 16, + skip_symlinks = 32, + directories_only = 64, + create_symlinks = 128, + create_hard_links = 256, + __in_recursive_copy = 512, +}; + +_LIBCPP_INLINE_VISIBILITY +inline constexpr copy_options operator&(copy_options _LHS, copy_options _RHS) { + return static_cast(static_cast(_LHS) & + static_cast(_RHS)); +} + +_LIBCPP_INLINE_VISIBILITY +inline constexpr copy_options operator|(copy_options _LHS, copy_options _RHS) { + return static_cast(static_cast(_LHS) | + static_cast(_RHS)); +} + +_LIBCPP_INLINE_VISIBILITY +inline constexpr copy_options operator^(copy_options _LHS, copy_options _RHS) { + return static_cast(static_cast(_LHS) ^ + static_cast(_RHS)); +} + +_LIBCPP_INLINE_VISIBILITY +inline constexpr copy_options operator~(copy_options _LHS) { + return static_cast(~static_cast(_LHS)); +} + +_LIBCPP_INLINE_VISIBILITY +inline copy_options& operator&=(copy_options& _LHS, copy_options _RHS) { + return _LHS = _LHS & _RHS; +} + +_LIBCPP_INLINE_VISIBILITY +inline copy_options& operator|=(copy_options& _LHS, copy_options _RHS) { + return _LHS = _LHS | _RHS; +} + +_LIBCPP_INLINE_VISIBILITY +inline copy_options& operator^=(copy_options& _LHS, copy_options _RHS) { + return _LHS = _LHS ^ _RHS; +} + +enum class _LIBCPP_ENUM_VIS directory_options : unsigned char { + none = 0, + follow_directory_symlink = 1, + skip_permission_denied = 2 +}; + +_LIBCPP_INLINE_VISIBILITY +inline constexpr directory_options operator&(directory_options _LHS, + directory_options _RHS) { + return static_cast(static_cast(_LHS) & + static_cast(_RHS)); +} + +_LIBCPP_INLINE_VISIBILITY +inline constexpr directory_options operator|(directory_options _LHS, + directory_options _RHS) { + return static_cast(static_cast(_LHS) | + static_cast(_RHS)); +} + +_LIBCPP_INLINE_VISIBILITY +inline constexpr directory_options operator^(directory_options _LHS, + directory_options _RHS) { + return static_cast(static_cast(_LHS) ^ + static_cast(_RHS)); +} + +_LIBCPP_INLINE_VISIBILITY +inline constexpr directory_options operator~(directory_options _LHS) { + return static_cast(~static_cast(_LHS)); +} + +_LIBCPP_INLINE_VISIBILITY +inline directory_options& operator&=(directory_options& _LHS, + directory_options _RHS) { + return _LHS = _LHS & _RHS; +} + +_LIBCPP_INLINE_VISIBILITY +inline directory_options& operator|=(directory_options& _LHS, + directory_options _RHS) { + return _LHS = _LHS | _RHS; +} + +_LIBCPP_INLINE_VISIBILITY +inline directory_options& operator^=(directory_options& _LHS, + directory_options _RHS) { + return _LHS = _LHS ^ _RHS; +} + +class _LIBCPP_TYPE_VIS file_status { +public: + // constructors + _LIBCPP_INLINE_VISIBILITY + file_status() noexcept : file_status(file_type::none) {} + _LIBCPP_INLINE_VISIBILITY + explicit file_status(file_type __ft, perms __prms = perms::unknown) noexcept + : __ft_(__ft), + __prms_(__prms) {} + + file_status(const file_status&) noexcept = default; + file_status(file_status&&) noexcept = default; + + _LIBCPP_INLINE_VISIBILITY + ~file_status() {} + + file_status& operator=(const file_status&) noexcept = default; + file_status& operator=(file_status&&) noexcept = default; + + // observers + _LIBCPP_INLINE_VISIBILITY + file_type type() const noexcept { return __ft_; } + + _LIBCPP_INLINE_VISIBILITY + perms permissions() const noexcept { return __prms_; } + + // modifiers + _LIBCPP_INLINE_VISIBILITY + void type(file_type __ft) noexcept { __ft_ = __ft; } + + _LIBCPP_INLINE_VISIBILITY + void permissions(perms __p) noexcept { __prms_ = __p; } + +private: + file_type __ft_; + perms __prms_; +}; + +class _LIBCPP_TYPE_VIS directory_entry; + +template +struct __can_convert_char { + static const bool value = false; +}; +template +struct __can_convert_char : public __can_convert_char<_Tp> {}; +template <> +struct __can_convert_char { + static const bool value = true; + using __char_type = char; +}; +template <> +struct __can_convert_char { + static const bool value = true; + using __char_type = wchar_t; +}; +template <> +struct __can_convert_char { + static const bool value = true; + using __char_type = char16_t; +}; +template <> +struct __can_convert_char { + static const bool value = true; + using __char_type = char32_t; +}; + +template +typename enable_if<__can_convert_char<_ECharT>::value, bool>::type +__is_separator(_ECharT __e) { + return __e == _ECharT('/'); +} + +struct _NullSentinal {}; + +template +using _Void = void; + +template +struct __is_pathable_string : public false_type {}; + +template +struct __is_pathable_string< + basic_string<_ECharT, _Traits, _Alloc>, + _Void::__char_type> > + : public __can_convert_char<_ECharT> { + using _Str = basic_string<_ECharT, _Traits, _Alloc>; + using _Base = __can_convert_char<_ECharT>; + static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); } + static _ECharT const* __range_end(_Str const& __s) { + return __s.data() + __s.length(); + } + static _ECharT __first_or_null(_Str const& __s) { + return __s.empty() ? _ECharT{} : __s[0]; + } +}; + +template +struct __is_pathable_string< + basic_string_view<_ECharT, _Traits>, + _Void::__char_type> > + : public __can_convert_char<_ECharT> { + using _Str = basic_string_view<_ECharT, _Traits>; + using _Base = __can_convert_char<_ECharT>; + static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); } + static _ECharT const* __range_end(_Str const& __s) { + return __s.data() + __s.length(); + } + static _ECharT __first_or_null(_Str const& __s) { + return __s.empty() ? _ECharT{} : __s[0]; + } +}; + +template ::type, + class _UnqualPtrType = + typename remove_const::type>::type, + bool _IsCharPtr = is_pointer<_DS>::value&& + __can_convert_char<_UnqualPtrType>::value> +struct __is_pathable_char_array : false_type {}; + +template +struct __is_pathable_char_array<_Source, _ECharT*, _UPtr, true> + : __can_convert_char::type> { + using _Base = __can_convert_char::type>; + + static _ECharT const* __range_begin(const _ECharT* __b) { return __b; } + static _ECharT const* __range_end(const _ECharT* __b) { + using _Iter = const _ECharT*; + const _ECharT __sentinal = _ECharT{}; + _Iter __e = __b; + for (; *__e != __sentinal; ++__e) + ; + return __e; + } + + static _ECharT __first_or_null(const _ECharT* __b) { return *__b; } +}; + +template ::value, + class = void> +struct __is_pathable_iter : false_type {}; + +template +struct __is_pathable_iter< + _Iter, true, + _Void::value_type>::__char_type> > + : __can_convert_char::value_type> { + using _ECharT = typename iterator_traits<_Iter>::value_type; + using _Base = __can_convert_char<_ECharT>; + + static _Iter __range_begin(_Iter __b) { return __b; } + static _NullSentinal __range_end(_Iter) { return _NullSentinal{}; } + + static _ECharT __first_or_null(_Iter __b) { return *__b; } +}; + +template ::value, + bool _IsCharIterT = __is_pathable_char_array<_Tp>::value, + bool _IsIterT = !_IsCharIterT && __is_pathable_iter<_Tp>::value> +struct __is_pathable : false_type { + static_assert(!_IsStringT && !_IsCharIterT && !_IsIterT, "Must all be false"); +}; + +template +struct __is_pathable<_Tp, true, false, false> : __is_pathable_string<_Tp> {}; + +template +struct __is_pathable<_Tp, false, true, false> : __is_pathable_char_array<_Tp> { +}; + +template +struct __is_pathable<_Tp, false, false, true> : __is_pathable_iter<_Tp> {}; + +template +struct _PathCVT { + static_assert(__can_convert_char<_ECharT>::value, + "Char type not convertible"); + + typedef __narrow_to_utf8 _Narrower; + + static void __append_range(string& __dest, _ECharT const* __b, + _ECharT const* __e) { + _Narrower()(back_inserter(__dest), __b, __e); + } + + template + static void __append_range(string& __dest, _Iter __b, _Iter __e) { + static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload"); + if (__b == __e) + return; + basic_string<_ECharT> __tmp(__b, __e); + _Narrower()(back_inserter(__dest), __tmp.data(), + __tmp.data() + __tmp.length()); + } + + template + static void __append_range(string& __dest, _Iter __b, _NullSentinal) { + static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload"); + const _ECharT __sentinal = _ECharT{}; + if (*__b == __sentinal) + return; + basic_string<_ECharT> __tmp; + for (; *__b != __sentinal; ++__b) + __tmp.push_back(*__b); + _Narrower()(back_inserter(__dest), __tmp.data(), + __tmp.data() + __tmp.length()); + } + + template + static void __append_source(string& __dest, _Source const& __s) { + using _Traits = __is_pathable<_Source>; + __append_range(__dest, _Traits::__range_begin(__s), + _Traits::__range_end(__s)); + } +}; + +template <> +struct _PathCVT { + + template + static typename enable_if<__is_exactly_input_iterator<_Iter>::value>::type + __append_range(string& __dest, _Iter __b, _Iter __e) { + for (; __b != __e; ++__b) + __dest.push_back(*__b); + } + + template + static typename enable_if<__is_forward_iterator<_Iter>::value>::type + __append_range(string& __dest, _Iter __b, _Iter __e) { + __dest.__append_forward_unsafe(__b, __e); + } + + template + static void __append_range(string& __dest, _Iter __b, _NullSentinal) { + const char __sentinal = char{}; + for (; *__b != __sentinal; ++__b) + __dest.push_back(*__b); + } + + template + static void __append_source(string& __dest, _Source const& __s) { + using _Traits = __is_pathable<_Source>; + __append_range(__dest, _Traits::__range_begin(__s), + _Traits::__range_end(__s)); + } +}; + +class _LIBCPP_TYPE_VIS path { + template + using _EnableIfPathable = + typename enable_if<__is_pathable<_SourceOrIter>::value, _Tp>::type; + + template + using _SourceChar = typename __is_pathable<_Tp>::__char_type; + + template + using _SourceCVT = _PathCVT<_SourceChar<_Tp> >; + +public: + typedef char value_type; + typedef basic_string string_type; + typedef _VSTD::string_view __string_view; + static constexpr value_type preferred_separator = '/'; + + enum class _LIBCPP_ENUM_VIS format : unsigned char { + auto_format, + native_format, + generic_format + }; + + // constructors and destructor + _LIBCPP_INLINE_VISIBILITY path() noexcept {} + _LIBCPP_INLINE_VISIBILITY path(const path& __p) : __pn_(__p.__pn_) {} + _LIBCPP_INLINE_VISIBILITY path(path&& __p) noexcept + : __pn_(_VSTD::move(__p.__pn_)) {} + + _LIBCPP_INLINE_VISIBILITY + path(string_type&& __s, format = format::auto_format) noexcept + : __pn_(_VSTD::move(__s)) {} + + template > + path(const _Source& __src, format = format::auto_format) { + _SourceCVT<_Source>::__append_source(__pn_, __src); + } + + template + path(_InputIt __first, _InputIt __last, format = format::auto_format) { + typedef typename iterator_traits<_InputIt>::value_type _ItVal; + _PathCVT<_ItVal>::__append_range(__pn_, __first, __last); + } + + // TODO Implement locale conversions. + template > + path(const _Source& __src, const locale& __loc, format = format::auto_format); + template + path(_InputIt __first, _InputIt _last, const locale& __loc, + format = format::auto_format); + + _LIBCPP_INLINE_VISIBILITY + ~path() = default; + + // assignments + _LIBCPP_INLINE_VISIBILITY + path& operator=(const path& __p) { + __pn_ = __p.__pn_; + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + path& operator=(path&& __p) noexcept { + __pn_ = _VSTD::move(__p.__pn_); + return *this; + } + + template + _LIBCPP_INLINE_VISIBILITY path& operator=(string_type&& __s) noexcept { + __pn_ = _VSTD::move(__s); + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + path& assign(string_type&& __s) noexcept { + __pn_ = _VSTD::move(__s); + return *this; + } + + template + _LIBCPP_INLINE_VISIBILITY _EnableIfPathable<_Source> + operator=(const _Source& __src) { + return this->assign(__src); + } + + template + _EnableIfPathable<_Source> assign(const _Source& __src) { + __pn_.clear(); + _SourceCVT<_Source>::__append_source(__pn_, __src); + return *this; + } + + template + path& assign(_InputIt __first, _InputIt __last) { + typedef typename iterator_traits<_InputIt>::value_type _ItVal; + __pn_.clear(); + _PathCVT<_ItVal>::__append_range(__pn_, __first, __last); + return *this; + } + +private: + template + static bool __source_is_absolute(_ECharT __first_or_null) { + return __is_separator(__first_or_null); + } + +public: + // appends + path& operator/=(const path& __p) { + if (__p.is_absolute()) { + __pn_ = __p.__pn_; + return *this; + } + if (has_filename()) + __pn_ += preferred_separator; + __pn_ += __p.native(); + return *this; + } + + // FIXME: Use _LIBCPP_DIAGNOSE_WARNING to produce a diagnostic when __src + // is known at compile time to be "/' since the user almost certainly intended + // to append a separator instead of overwriting the path with "/" + template + _LIBCPP_INLINE_VISIBILITY _EnableIfPathable<_Source> + operator/=(const _Source& __src) { + return this->append(__src); + } + + template + _EnableIfPathable<_Source> append(const _Source& __src) { + using _Traits = __is_pathable<_Source>; + using _CVT = _PathCVT<_SourceChar<_Source> >; + if (__source_is_absolute(_Traits::__first_or_null(__src))) + __pn_.clear(); + else if (has_filename()) + __pn_ += preferred_separator; + _CVT::__append_source(__pn_, __src); + return *this; + } + + template + path& append(_InputIt __first, _InputIt __last) { + typedef typename iterator_traits<_InputIt>::value_type _ItVal; + static_assert(__can_convert_char<_ItVal>::value, "Must convertible"); + using _CVT = _PathCVT<_ItVal>; + if (__first != __last && __source_is_absolute(*__first)) + __pn_.clear(); + else if (has_filename()) + __pn_ += preferred_separator; + _CVT::__append_range(__pn_, __first, __last); + return *this; + } + + // concatenation + _LIBCPP_INLINE_VISIBILITY + path& operator+=(const path& __x) { + __pn_ += __x.__pn_; + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + path& operator+=(const string_type& __x) { + __pn_ += __x; + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + path& operator+=(__string_view __x) { + __pn_ += __x; + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + path& operator+=(const value_type* __x) { + __pn_ += __x; + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + path& operator+=(value_type __x) { + __pn_ += __x; + return *this; + } + + template + typename enable_if<__can_convert_char<_ECharT>::value, path&>::type + operator+=(_ECharT __x) { + basic_string<_ECharT> __tmp; + __tmp += __x; + _PathCVT<_ECharT>::__append_source(__pn_, __tmp); + return *this; + } + + template + _EnableIfPathable<_Source> operator+=(const _Source& __x) { + return this->concat(__x); + } + + template + _EnableIfPathable<_Source> concat(const _Source& __x) { + _SourceCVT<_Source>::__append_source(__pn_, __x); + return *this; + } + + template + path& concat(_InputIt __first, _InputIt __last) { + typedef typename iterator_traits<_InputIt>::value_type _ItVal; + _PathCVT<_ItVal>::__append_range(__pn_, __first, __last); + return *this; + } + + // modifiers + _LIBCPP_INLINE_VISIBILITY + void clear() noexcept { __pn_.clear(); } + + path& make_preferred() { return *this; } + + _LIBCPP_INLINE_VISIBILITY + path& remove_filename() { + auto __fname = __filename(); + if (!__fname.empty()) + __pn_.erase(__fname.data() - __pn_.data()); + return *this; + } + + path& replace_filename(const path& __replacement) { + remove_filename(); + return (*this /= __replacement); + } + + path& replace_extension(const path& __replacement = path()); + + _LIBCPP_INLINE_VISIBILITY + void swap(path& __rhs) noexcept { __pn_.swap(__rhs.__pn_); } + + // private helper to allow reserving memory in the path + _LIBCPP_INLINE_VISIBILITY + void __reserve(size_t __s) { __pn_.reserve(__s); } + + // native format observers + _LIBCPP_INLINE_VISIBILITY + const string_type& native() const noexcept { return __pn_; } + + _LIBCPP_INLINE_VISIBILITY + const value_type* c_str() const noexcept { return __pn_.c_str(); } + + _LIBCPP_INLINE_VISIBILITY operator string_type() const { return __pn_; } + + template , + class _Allocator = allocator<_ECharT> > + basic_string<_ECharT, _Traits, _Allocator> + string(const _Allocator& __a = _Allocator()) const { + using _CVT = __widen_from_utf8; + using _Str = basic_string<_ECharT, _Traits, _Allocator>; + _Str __s(__a); + __s.reserve(__pn_.size()); + _CVT()(back_inserter(__s), __pn_.data(), __pn_.data() + __pn_.size()); + return __s; + } + + _LIBCPP_INLINE_VISIBILITY std::string string() const { return __pn_; } + _LIBCPP_INLINE_VISIBILITY std::wstring wstring() const { + return string(); + } + _LIBCPP_INLINE_VISIBILITY std::string u8string() const { return __pn_; } + _LIBCPP_INLINE_VISIBILITY std::u16string u16string() const { + return string(); + } + _LIBCPP_INLINE_VISIBILITY std::u32string u32string() const { + return string(); + } + + // generic format observers + template , + class _Allocator = allocator<_ECharT> > + basic_string<_ECharT, _Traits, _Allocator> + generic_string(const _Allocator& __a = _Allocator()) const { + return string<_ECharT, _Traits, _Allocator>(__a); + } + + std::string generic_string() const { return __pn_; } + std::wstring generic_wstring() const { return string(); } + std::string generic_u8string() const { return __pn_; } + std::u16string generic_u16string() const { return string(); } + std::u32string generic_u32string() const { return string(); } + +private: + int __compare(__string_view) const; + __string_view __root_name() const; + __string_view __root_directory() const; + __string_view __root_path_raw() const; + __string_view __relative_path() const; + __string_view __parent_path() const; + __string_view __filename() const; + __string_view __stem() const; + __string_view __extension() const; + +public: + // compare + _LIBCPP_INLINE_VISIBILITY int compare(const path& __p) const noexcept { + return __compare(__p.__pn_); + } + _LIBCPP_INLINE_VISIBILITY int compare(const string_type& __s) const { + return __compare(__s); + } + _LIBCPP_INLINE_VISIBILITY int compare(__string_view __s) const { + return __compare(__s); + } + _LIBCPP_INLINE_VISIBILITY int compare(const value_type* __s) const { + return __compare(__s); + } + + // decomposition + _LIBCPP_INLINE_VISIBILITY path root_name() const { + return string_type(__root_name()); + } + _LIBCPP_INLINE_VISIBILITY path root_directory() const { + return string_type(__root_directory()); + } + _LIBCPP_INLINE_VISIBILITY path root_path() const { + return root_name().append(string_type(__root_directory())); + } + _LIBCPP_INLINE_VISIBILITY path relative_path() const { + return string_type(__relative_path()); + } + _LIBCPP_INLINE_VISIBILITY path parent_path() const { + return string_type(__parent_path()); + } + _LIBCPP_INLINE_VISIBILITY path filename() const { + return string_type(__filename()); + } + _LIBCPP_INLINE_VISIBILITY path stem() const { return string_type(__stem()); } + _LIBCPP_INLINE_VISIBILITY path extension() const { + return string_type(__extension()); + } + + // query + _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY bool + empty() const noexcept { + return __pn_.empty(); + } + + _LIBCPP_INLINE_VISIBILITY bool has_root_name() const { + return !__root_name().empty(); + } + _LIBCPP_INLINE_VISIBILITY bool has_root_directory() const { + return !__root_directory().empty(); + } + _LIBCPP_INLINE_VISIBILITY bool has_root_path() const { + return !__root_path_raw().empty(); + } + _LIBCPP_INLINE_VISIBILITY bool has_relative_path() const { + return !__relative_path().empty(); + } + _LIBCPP_INLINE_VISIBILITY bool has_parent_path() const { + return !__parent_path().empty(); + } + _LIBCPP_INLINE_VISIBILITY bool has_filename() const { + return !__filename().empty(); + } + _LIBCPP_INLINE_VISIBILITY bool has_stem() const { return !__stem().empty(); } + _LIBCPP_INLINE_VISIBILITY bool has_extension() const { + return !__extension().empty(); + } + + _LIBCPP_INLINE_VISIBILITY bool is_absolute() const { + return has_root_directory(); + } + _LIBCPP_INLINE_VISIBILITY bool is_relative() const { return !is_absolute(); } + + // relative paths + path lexically_normal() const; + path lexically_relative(const path& __base) const; + + _LIBCPP_INLINE_VISIBILITY path lexically_proximate(const path& __base) const { + path __result = this->lexically_relative(__base); + if (__result.native().empty()) + return *this; + return __result; + } + + // iterators + class _LIBCPP_TYPE_VIS iterator; + typedef iterator const_iterator; + + iterator begin() const; + iterator end() const; + + template + _LIBCPP_INLINE_VISIBILITY friend + typename enable_if::value && + is_same<_Traits, char_traits >::value, + basic_ostream<_CharT, _Traits>&>::type + operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) { + __os << std::__quoted(__p.native()); + return __os; + } + + template + _LIBCPP_INLINE_VISIBILITY friend + typename enable_if::value || + !is_same<_Traits, char_traits >::value, + basic_ostream<_CharT, _Traits>&>::type + operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) { + __os << std::__quoted(__p.string<_CharT, _Traits>()); + return __os; + } + + template + _LIBCPP_INLINE_VISIBILITY friend basic_istream<_CharT, _Traits>& + operator>>(basic_istream<_CharT, _Traits>& __is, path& __p) { + basic_string<_CharT, _Traits> __tmp; + __is >> __quoted(__tmp); + __p = __tmp; + return __is; + } + + friend _LIBCPP_INLINE_VISIBILITY bool operator==(const path& __lhs, const path& __rhs) noexcept { + return __lhs.compare(__rhs) == 0; + } + friend _LIBCPP_INLINE_VISIBILITY bool operator!=(const path& __lhs, const path& __rhs) noexcept { + return __lhs.compare(__rhs) != 0; + } + friend _LIBCPP_INLINE_VISIBILITY bool operator<(const path& __lhs, const path& __rhs) noexcept { + return __lhs.compare(__rhs) < 0; + } + friend _LIBCPP_INLINE_VISIBILITY bool operator<=(const path& __lhs, const path& __rhs) noexcept { + return __lhs.compare(__rhs) <= 0; + } + friend _LIBCPP_INLINE_VISIBILITY bool operator>(const path& __lhs, const path& __rhs) noexcept { + return __lhs.compare(__rhs) > 0; + } + friend _LIBCPP_INLINE_VISIBILITY bool operator>=(const path& __lhs, const path& __rhs) noexcept { + return __lhs.compare(__rhs) >= 0; + } + + friend _LIBCPP_INLINE_VISIBILITY path operator/(const path& __lhs, + const path& __rhs) { + path __result(__lhs); + __result /= __rhs; + return __result; + } +private: + inline _LIBCPP_INLINE_VISIBILITY path& + __assign_view(__string_view const& __s) noexcept { + __pn_ = string_type(__s); + return *this; + } + string_type __pn_; +}; + +inline _LIBCPP_INLINE_VISIBILITY void swap(path& __lhs, path& __rhs) noexcept { + __lhs.swap(__rhs); +} + +_LIBCPP_FUNC_VIS +size_t hash_value(const path& __p) noexcept; + +template +_LIBCPP_INLINE_VISIBILITY + typename enable_if<__is_pathable<_Source>::value, path>::type + u8path(const _Source& __s) { + static_assert( + is_same::__char_type, char>::value, + "u8path(Source const&) requires Source have a character type of type " + "'char'"); + return path(__s); +} + +template +_LIBCPP_INLINE_VISIBILITY + typename enable_if<__is_pathable<_InputIt>::value, path>::type + u8path(_InputIt __f, _InputIt __l) { + static_assert( + is_same::__char_type, char>::value, + "u8path(Iter, Iter) requires Iter have a value_type of type 'char'"); + return path(__f, __l); +} + +class _LIBCPP_TYPE_VIS path::iterator { +public: + enum _ParserState : unsigned char { + _Singular, + _BeforeBegin, + _InRootName, + _InRootDir, + _InFilenames, + _InTrailingSep, + _AtEnd + }; + +public: + typedef bidirectional_iterator_tag iterator_category; + + typedef path value_type; + typedef std::ptrdiff_t difference_type; + typedef const path* pointer; + typedef const path& reference; + + typedef void + __stashing_iterator_tag; // See reverse_iterator and __is_stashing_iterator + +public: + _LIBCPP_INLINE_VISIBILITY + iterator() + : __stashed_elem_(), __path_ptr_(nullptr), __entry_(), + __state_(_Singular) {} + + iterator(const iterator&) = default; + ~iterator() = default; + + iterator& operator=(const iterator&) = default; + + _LIBCPP_INLINE_VISIBILITY + reference operator*() const { return __stashed_elem_; } + + _LIBCPP_INLINE_VISIBILITY + pointer operator->() const { return &__stashed_elem_; } + + _LIBCPP_INLINE_VISIBILITY + iterator& operator++() { + _LIBCPP_ASSERT(__state_ != _Singular, + "attempting to increment a singular iterator"); + _LIBCPP_ASSERT(__state_ != _AtEnd, + "attempting to increment the end iterator"); + return __increment(); + } + + _LIBCPP_INLINE_VISIBILITY + iterator operator++(int) { + iterator __it(*this); + this->operator++(); + return __it; + } + + _LIBCPP_INLINE_VISIBILITY + iterator& operator--() { + _LIBCPP_ASSERT(__state_ != _Singular, + "attempting to decrement a singular iterator"); + _LIBCPP_ASSERT(__entry_.data() != __path_ptr_->native().data(), + "attempting to decrement the begin iterator"); + return __decrement(); + } + + _LIBCPP_INLINE_VISIBILITY + iterator operator--(int) { + iterator __it(*this); + this->operator--(); + return __it; + } + +private: + friend class path; + + inline _LIBCPP_INLINE_VISIBILITY friend bool operator==(const iterator&, + const iterator&); + + iterator& __increment(); + iterator& __decrement(); + + path __stashed_elem_; + const path* __path_ptr_; + path::__string_view __entry_; + _ParserState __state_; +}; + +inline _LIBCPP_INLINE_VISIBILITY bool operator==(const path::iterator& __lhs, + const path::iterator& __rhs) { + return __lhs.__path_ptr_ == __rhs.__path_ptr_ && + __lhs.__entry_.data() == __rhs.__entry_.data(); +} + +inline _LIBCPP_INLINE_VISIBILITY bool operator!=(const path::iterator& __lhs, + const path::iterator& __rhs) { + return !(__lhs == __rhs); +} + +class _LIBCPP_EXCEPTION_ABI filesystem_error : public system_error { +public: + _LIBCPP_INLINE_VISIBILITY + filesystem_error(const string& __what, error_code __ec) + : system_error(__ec, __what), + __storage_(make_shared<_Storage>(path(), path())) { + __create_what(0); + } + + _LIBCPP_INLINE_VISIBILITY + filesystem_error(const string& __what, const path& __p1, error_code __ec) + : system_error(__ec, __what), + __storage_(make_shared<_Storage>(__p1, path())) { + __create_what(1); + } + + _LIBCPP_INLINE_VISIBILITY + filesystem_error(const string& __what, const path& __p1, const path& __p2, + error_code __ec) + : system_error(__ec, __what), + __storage_(make_shared<_Storage>(__p1, __p2)) { + __create_what(2); + } + + _LIBCPP_INLINE_VISIBILITY + const path& path1() const noexcept { return __storage_->__p1_; } + + _LIBCPP_INLINE_VISIBILITY + const path& path2() const noexcept { return __storage_->__p2_; } + + ~filesystem_error() override; // key function + + _LIBCPP_INLINE_VISIBILITY + const char* what() const noexcept override { + return __storage_->__what_.c_str(); + } + + _LIBCPP_FUNC_VIS + void __create_what(int __num_paths); + +private: + struct _Storage { + _LIBCPP_INLINE_VISIBILITY + _Storage(const path& __p1, const path& __p2) : __p1_(__p1), __p2_(__p2) {} + + path __p1_; + path __p2_; + string __what_; + }; + shared_ptr<_Storage> __storage_; +}; + +template +_LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY +#ifndef _LIBCPP_NO_EXCEPTIONS + void + __throw_filesystem_error(_Args&&... __args) { + throw filesystem_error(std::forward<_Args>(__args)...); +} +#else + void + __throw_filesystem_error(_Args&&...) { + _VSTD::abort(); +} +#endif + +// operational functions + +_LIBCPP_FUNC_VIS +path __absolute(const path&, error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +path __canonical(const path&, error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +void __copy(const path& __from, const path& __to, copy_options __opt, + error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +bool __copy_file(const path& __from, const path& __to, copy_options __opt, + error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +void __copy_symlink(const path& __existing_symlink, const path& __new_symlink, + error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +bool __create_directories(const path& p, error_code* ec = nullptr); +_LIBCPP_FUNC_VIS +bool __create_directory(const path& p, error_code* ec = nullptr); +_LIBCPP_FUNC_VIS +bool __create_directory(const path& p, const path& attributes, + error_code* ec = nullptr); +_LIBCPP_FUNC_VIS +void __create_directory_symlink(const path& __to, const path& __new_symlink, + error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +void __create_hard_link(const path& __to, const path& __new_hard_link, + error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +void __create_symlink(const path& __to, const path& __new_symlink, + error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +path __current_path(error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +void __current_path(const path&, error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +bool __equivalent(const path&, const path&, error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +uintmax_t __file_size(const path&, error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +uintmax_t __hard_link_count(const path&, error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +bool __fs_is_empty(const path& p, error_code* ec = nullptr); +_LIBCPP_FUNC_VIS +file_time_type __last_write_time(const path& p, error_code* ec = nullptr); +_LIBCPP_FUNC_VIS +void __last_write_time(const path& p, file_time_type new_time, + error_code* ec = nullptr); +_LIBCPP_FUNC_VIS +void __permissions(const path&, perms, perm_options, error_code* = nullptr); +_LIBCPP_FUNC_VIS +path __read_symlink(const path& p, error_code* ec = nullptr); +_LIBCPP_FUNC_VIS +bool __remove(const path& p, error_code* ec = nullptr); +_LIBCPP_FUNC_VIS +uintmax_t __remove_all(const path& p, error_code* ec = nullptr); +_LIBCPP_FUNC_VIS +void __rename(const path& from, const path& to, error_code* ec = nullptr); +_LIBCPP_FUNC_VIS +void __resize_file(const path& p, uintmax_t size, error_code* ec = nullptr); +_LIBCPP_FUNC_VIS +space_info __space(const path&, error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +file_status __status(const path&, error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +file_status __symlink_status(const path&, error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +path __system_complete(const path&, error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +path __temp_directory_path(error_code* __ec = nullptr); +_LIBCPP_FUNC_VIS +path __weakly_canonical(path const& __p, error_code* __ec = nullptr); + +inline _LIBCPP_INLINE_VISIBILITY path current_path() { + return __current_path(); +} + +inline _LIBCPP_INLINE_VISIBILITY path current_path(error_code& __ec) { + return __current_path(&__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY void current_path(const path& __p) { + __current_path(__p); +} + +inline _LIBCPP_INLINE_VISIBILITY void current_path(const path& __p, + error_code& __ec) noexcept { + __current_path(__p, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY path absolute(const path& __p) { + return __absolute(__p); +} + +inline _LIBCPP_INLINE_VISIBILITY path absolute(const path& __p, + error_code& __ec) { + return __absolute(__p, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY path canonical(const path& __p) { + return __canonical(__p); +} + +inline _LIBCPP_INLINE_VISIBILITY path canonical(const path& __p, + error_code& __ec) { + return __canonical(__p, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY void copy(const path& __from, + const path& __to) { + __copy(__from, __to, copy_options::none); +} + +inline _LIBCPP_INLINE_VISIBILITY void copy(const path& __from, const path& __to, + error_code& __ec) { + __copy(__from, __to, copy_options::none, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY void copy(const path& __from, const path& __to, + copy_options __opt) { + __copy(__from, __to, __opt); +} + +inline _LIBCPP_INLINE_VISIBILITY void copy(const path& __from, const path& __to, + copy_options __opt, + error_code& __ec) { + __copy(__from, __to, __opt, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY bool copy_file(const path& __from, + const path& __to) { + return __copy_file(__from, __to, copy_options::none); +} + +inline _LIBCPP_INLINE_VISIBILITY bool +copy_file(const path& __from, const path& __to, error_code& __ec) { + return __copy_file(__from, __to, copy_options::none, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY bool +copy_file(const path& __from, const path& __to, copy_options __opt) { + return __copy_file(__from, __to, __opt); +} + +inline _LIBCPP_INLINE_VISIBILITY bool copy_file(const path& __from, + const path& __to, + copy_options __opt, + error_code& __ec) { + return __copy_file(__from, __to, __opt, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY void copy_symlink(const path& __existing, + const path& __new) { + __copy_symlink(__existing, __new); +} + +inline _LIBCPP_INLINE_VISIBILITY void +copy_symlink(const path& __ext, const path& __new, error_code& __ec) noexcept { + __copy_symlink(__ext, __new, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY bool create_directories(const path& __p) { + return __create_directories(__p); +} + +inline _LIBCPP_INLINE_VISIBILITY bool create_directories(const path& __p, + error_code& __ec) { + return __create_directories(__p, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY bool create_directory(const path& __p) { + return __create_directory(__p); +} + +inline _LIBCPP_INLINE_VISIBILITY bool +create_directory(const path& __p, error_code& __ec) noexcept { + return __create_directory(__p, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY bool create_directory(const path& __p, + const path& __attrs) { + return __create_directory(__p, __attrs); +} + +inline _LIBCPP_INLINE_VISIBILITY bool +create_directory(const path& __p, const path& __attrs, + error_code& __ec) noexcept { + return __create_directory(__p, __attrs, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY void +create_directory_symlink(const path& __to, const path& __new) { + __create_directory_symlink(__to, __new); +} + +inline _LIBCPP_INLINE_VISIBILITY void +create_directory_symlink(const path& __to, const path& __new, + error_code& __ec) noexcept { + __create_directory_symlink(__to, __new, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY void create_hard_link(const path& __to, + const path& __new) { + __create_hard_link(__to, __new); +} + +inline _LIBCPP_INLINE_VISIBILITY void +create_hard_link(const path& __to, const path& __new, + error_code& __ec) noexcept { + __create_hard_link(__to, __new, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY void create_symlink(const path& __to, + const path& __new) { + __create_symlink(__to, __new); +} + +inline _LIBCPP_INLINE_VISIBILITY void +create_symlink(const path& __to, const path& __new, error_code& __ec) noexcept { + return __create_symlink(__to, __new, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY bool status_known(file_status __s) noexcept { + return __s.type() != file_type::none; +} + +inline _LIBCPP_INLINE_VISIBILITY bool exists(file_status __s) noexcept { + return status_known(__s) && __s.type() != file_type::not_found; +} + +inline _LIBCPP_INLINE_VISIBILITY bool exists(const path& __p) { + return exists(__status(__p)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool exists(const path& __p, + error_code& __ec) noexcept { + auto __s = __status(__p, &__ec); + if (status_known(__s)) + __ec.clear(); + return exists(__s); +} + +inline _LIBCPP_INLINE_VISIBILITY bool equivalent(const path& __p1, + const path& __p2) { + return __equivalent(__p1, __p2); +} + +inline _LIBCPP_INLINE_VISIBILITY bool +equivalent(const path& __p1, const path& __p2, error_code& __ec) noexcept { + return __equivalent(__p1, __p2, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY uintmax_t file_size(const path& __p) { + return __file_size(__p); +} + +inline _LIBCPP_INLINE_VISIBILITY uintmax_t +file_size(const path& __p, error_code& __ec) noexcept { + return __file_size(__p, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY uintmax_t hard_link_count(const path& __p) { + return __hard_link_count(__p); +} + +inline _LIBCPP_INLINE_VISIBILITY uintmax_t +hard_link_count(const path& __p, error_code& __ec) noexcept { + return __hard_link_count(__p, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_block_file(file_status __s) noexcept { + return __s.type() == file_type::block; +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_block_file(const path& __p) { + return is_block_file(__status(__p)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_block_file(const path& __p, + error_code& __ec) noexcept { + return is_block_file(__status(__p, &__ec)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool +is_character_file(file_status __s) noexcept { + return __s.type() == file_type::character; +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_character_file(const path& __p) { + return is_character_file(__status(__p)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool +is_character_file(const path& __p, error_code& __ec) noexcept { + return is_character_file(__status(__p, &__ec)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_directory(file_status __s) noexcept { + return __s.type() == file_type::directory; +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_directory(const path& __p) { + return is_directory(__status(__p)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_directory(const path& __p, + error_code& __ec) noexcept { + return is_directory(__status(__p, &__ec)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_empty(const path& __p) { + return __fs_is_empty(__p); +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_empty(const path& __p, + error_code& __ec) { + return __fs_is_empty(__p, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_fifo(file_status __s) noexcept { + return __s.type() == file_type::fifo; +} +inline _LIBCPP_INLINE_VISIBILITY bool is_fifo(const path& __p) { + return is_fifo(__status(__p)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_fifo(const path& __p, + error_code& __ec) noexcept { + return is_fifo(__status(__p, &__ec)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool +is_regular_file(file_status __s) noexcept { + return __s.type() == file_type::regular; +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_regular_file(const path& __p) { + return is_regular_file(__status(__p)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool +is_regular_file(const path& __p, error_code& __ec) noexcept { + return is_regular_file(__status(__p, &__ec)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_socket(file_status __s) noexcept { + return __s.type() == file_type::socket; +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_socket(const path& __p) { + return is_socket(__status(__p)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_socket(const path& __p, + error_code& __ec) noexcept { + return is_socket(__status(__p, &__ec)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_symlink(file_status __s) noexcept { + return __s.type() == file_type::symlink; +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_symlink(const path& __p) { + return is_symlink(__symlink_status(__p)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_symlink(const path& __p, + error_code& __ec) noexcept { + return is_symlink(__symlink_status(__p, &__ec)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_other(file_status __s) noexcept { + return exists(__s) && !is_regular_file(__s) && !is_directory(__s) && + !is_symlink(__s); +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_other(const path& __p) { + return is_other(__status(__p)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool is_other(const path& __p, + error_code& __ec) noexcept { + return is_other(__status(__p, &__ec)); +} + +inline _LIBCPP_INLINE_VISIBILITY file_time_type +last_write_time(const path& __p) { + return __last_write_time(__p); +} + +inline _LIBCPP_INLINE_VISIBILITY file_time_type +last_write_time(const path& __p, error_code& __ec) noexcept { + return __last_write_time(__p, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY void last_write_time(const path& __p, + file_time_type __t) { + __last_write_time(__p, __t); +} + +inline _LIBCPP_INLINE_VISIBILITY void +last_write_time(const path& __p, file_time_type __t, + error_code& __ec) noexcept { + __last_write_time(__p, __t, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY void +permissions(const path& __p, perms __prms, + perm_options __opts = perm_options::replace) { + __permissions(__p, __prms, __opts); +} + +inline _LIBCPP_INLINE_VISIBILITY void permissions(const path& __p, perms __prms, + error_code& __ec) noexcept { + __permissions(__p, __prms, perm_options::replace, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY void permissions(const path& __p, perms __prms, + perm_options __opts, + error_code& __ec) { + __permissions(__p, __prms, __opts, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY path proximate(const path& __p, + const path& __base, + error_code& __ec) { + path __tmp = __weakly_canonical(__p, &__ec); + if (__ec) + return {}; + path __tmp_base = __weakly_canonical(__base, &__ec); + if (__ec) + return {}; + return __tmp.lexically_proximate(__tmp_base); +} + +inline _LIBCPP_INLINE_VISIBILITY path proximate(const path& __p, + error_code& __ec) { + return proximate(__p, current_path(), __ec); +} + +inline _LIBCPP_INLINE_VISIBILITY path +proximate(const path& __p, const path& __base = current_path()) { + return __weakly_canonical(__p).lexically_proximate( + __weakly_canonical(__base)); +} + +inline _LIBCPP_INLINE_VISIBILITY path read_symlink(const path& __p) { + return __read_symlink(__p); +} + +inline _LIBCPP_INLINE_VISIBILITY path read_symlink(const path& __p, + error_code& __ec) { + return __read_symlink(__p, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY path relative(const path& __p, + const path& __base, + error_code& __ec) { + path __tmp = __weakly_canonical(__p, &__ec); + if (__ec) + return path(); + path __tmpbase = __weakly_canonical(__base, &__ec); + if (__ec) + return path(); + return __tmp.lexically_relative(__tmpbase); +} + +inline _LIBCPP_INLINE_VISIBILITY path relative(const path& __p, + error_code& __ec) { + return relative(__p, current_path(), __ec); +} + +inline _LIBCPP_INLINE_VISIBILITY path +relative(const path& __p, const path& __base = current_path()) { + return __weakly_canonical(__p).lexically_relative(__weakly_canonical(__base)); +} + +inline _LIBCPP_INLINE_VISIBILITY bool remove(const path& __p) { + return __remove(__p); +} + +inline _LIBCPP_INLINE_VISIBILITY bool remove(const path& __p, + error_code& __ec) noexcept { + return __remove(__p, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY uintmax_t remove_all(const path& __p) { + return __remove_all(__p); +} + +inline _LIBCPP_INLINE_VISIBILITY uintmax_t remove_all(const path& __p, + error_code& __ec) { + return __remove_all(__p, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY void rename(const path& __from, + const path& __to) { + return __rename(__from, __to); +} + +inline _LIBCPP_INLINE_VISIBILITY void +rename(const path& __from, const path& __to, error_code& __ec) noexcept { + return __rename(__from, __to, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY void resize_file(const path& __p, + uintmax_t __ns) { + return __resize_file(__p, __ns); +} + +inline _LIBCPP_INLINE_VISIBILITY void +resize_file(const path& __p, uintmax_t __ns, error_code& __ec) noexcept { + return __resize_file(__p, __ns, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY space_info space(const path& __p) { + return __space(__p); +} + +inline _LIBCPP_INLINE_VISIBILITY space_info space(const path& __p, + error_code& __ec) noexcept { + return __space(__p, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY file_status status(const path& __p) { + return __status(__p); +} + +inline _LIBCPP_INLINE_VISIBILITY file_status status(const path& __p, + error_code& __ec) noexcept { + return __status(__p, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY file_status symlink_status(const path& __p) { + return __symlink_status(__p); +} + +inline _LIBCPP_INLINE_VISIBILITY file_status +symlink_status(const path& __p, error_code& __ec) noexcept { + return __symlink_status(__p, &__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY path temp_directory_path() { + return __temp_directory_path(); +} + +inline _LIBCPP_INLINE_VISIBILITY path temp_directory_path(error_code& __ec) { + return __temp_directory_path(&__ec); +} + +inline _LIBCPP_INLINE_VISIBILITY path weakly_canonical(path const& __p) { + return __weakly_canonical(__p); +} + +inline _LIBCPP_INLINE_VISIBILITY path weakly_canonical(path const& __p, + error_code& __ec) { + return __weakly_canonical(__p, &__ec); +} + +class directory_iterator; +class recursive_directory_iterator; +class __dir_stream; + +class directory_entry { + typedef _VSTD_FS::path _Path; + +public: + // constructors and destructors + directory_entry() noexcept = default; + directory_entry(directory_entry const&) = default; + directory_entry(directory_entry&&) noexcept = default; + + _LIBCPP_INLINE_VISIBILITY + explicit directory_entry(_Path const& __p) : __p_(__p) { + error_code __ec; + __refresh(&__ec); + } + + _LIBCPP_INLINE_VISIBILITY + directory_entry(_Path const& __p, error_code& __ec) : __p_(__p) { + __refresh(&__ec); + } + + ~directory_entry() {} + + directory_entry& operator=(directory_entry const&) = default; + directory_entry& operator=(directory_entry&&) noexcept = default; + + _LIBCPP_INLINE_VISIBILITY + void assign(_Path const& __p) { + __p_ = __p; + error_code __ec; + __refresh(&__ec); + } + + _LIBCPP_INLINE_VISIBILITY + void assign(_Path const& __p, error_code& __ec) { + __p_ = __p; + __refresh(&__ec); + } + + _LIBCPP_INLINE_VISIBILITY + void replace_filename(_Path const& __p) { + __p_.replace_filename(__p); + error_code __ec; + __refresh(&__ec); + } + + _LIBCPP_INLINE_VISIBILITY + void replace_filename(_Path const& __p, error_code& __ec) { + __p_ = __p_.parent_path() / __p; + __refresh(&__ec); + } + + _LIBCPP_INLINE_VISIBILITY + void refresh() { __refresh(); } + + _LIBCPP_INLINE_VISIBILITY + void refresh(error_code& __ec) noexcept { __refresh(&__ec); } + + _LIBCPP_INLINE_VISIBILITY + _Path const& path() const noexcept { return __p_; } + + _LIBCPP_INLINE_VISIBILITY + operator const _Path&() const noexcept { return __p_; } + + _LIBCPP_INLINE_VISIBILITY + bool exists() const { return _VSTD_FS::exists(file_status{__get_ft()}); } + + _LIBCPP_INLINE_VISIBILITY + bool exists(error_code& __ec) const noexcept { + return _VSTD_FS::exists(file_status{__get_ft(&__ec)}); + } + + _LIBCPP_INLINE_VISIBILITY + bool is_block_file() const { return __get_ft() == file_type::block; } + + _LIBCPP_INLINE_VISIBILITY + bool is_block_file(error_code& __ec) const noexcept { + return __get_ft(&__ec) == file_type::block; + } + + _LIBCPP_INLINE_VISIBILITY + bool is_character_file() const { return __get_ft() == file_type::character; } + + _LIBCPP_INLINE_VISIBILITY + bool is_character_file(error_code& __ec) const noexcept { + return __get_ft(&__ec) == file_type::character; + } + + _LIBCPP_INLINE_VISIBILITY + bool is_directory() const { return __get_ft() == file_type::directory; } + + _LIBCPP_INLINE_VISIBILITY + bool is_directory(error_code& __ec) const noexcept { + return __get_ft(&__ec) == file_type::directory; + } + + _LIBCPP_INLINE_VISIBILITY + bool is_fifo() const { return __get_ft() == file_type::fifo; } + + _LIBCPP_INLINE_VISIBILITY + bool is_fifo(error_code& __ec) const noexcept { + return __get_ft(&__ec) == file_type::fifo; + } + + _LIBCPP_INLINE_VISIBILITY + bool is_other() const { return _VSTD_FS::is_other(file_status{__get_ft()}); } + + _LIBCPP_INLINE_VISIBILITY + bool is_other(error_code& __ec) const noexcept { + return _VSTD_FS::is_other(file_status{__get_ft(&__ec)}); + } + + _LIBCPP_INLINE_VISIBILITY + bool is_regular_file() const { return __get_ft() == file_type::regular; } + + _LIBCPP_INLINE_VISIBILITY + bool is_regular_file(error_code& __ec) const noexcept { + return __get_ft(&__ec) == file_type::regular; + } + + _LIBCPP_INLINE_VISIBILITY + bool is_socket() const { return __get_ft() == file_type::socket; } + + _LIBCPP_INLINE_VISIBILITY + bool is_socket(error_code& __ec) const noexcept { + return __get_ft(&__ec) == file_type::socket; + } + + _LIBCPP_INLINE_VISIBILITY + bool is_symlink() const { return __get_sym_ft() == file_type::symlink; } + + _LIBCPP_INLINE_VISIBILITY + bool is_symlink(error_code& __ec) const noexcept { + return __get_sym_ft(&__ec) == file_type::symlink; + } + _LIBCPP_INLINE_VISIBILITY + uintmax_t file_size() const { return __get_size(); } + + _LIBCPP_INLINE_VISIBILITY + uintmax_t file_size(error_code& __ec) const noexcept { + return __get_size(&__ec); + } + + _LIBCPP_INLINE_VISIBILITY + uintmax_t hard_link_count() const { return __get_nlink(); } + + _LIBCPP_INLINE_VISIBILITY + uintmax_t hard_link_count(error_code& __ec) const noexcept { + return __get_nlink(&__ec); + } + + _LIBCPP_INLINE_VISIBILITY + file_time_type last_write_time() const { return __get_write_time(); } + + _LIBCPP_INLINE_VISIBILITY + file_time_type last_write_time(error_code& __ec) const noexcept { + return __get_write_time(&__ec); + } + + _LIBCPP_INLINE_VISIBILITY + file_status status() const { return __get_status(); } + + _LIBCPP_INLINE_VISIBILITY + file_status status(error_code& __ec) const noexcept { + return __get_status(&__ec); + } + + _LIBCPP_INLINE_VISIBILITY + file_status symlink_status() const { return __get_symlink_status(); } + + _LIBCPP_INLINE_VISIBILITY + file_status symlink_status(error_code& __ec) const noexcept { + return __get_symlink_status(&__ec); + } + + _LIBCPP_INLINE_VISIBILITY + bool operator<(directory_entry const& __rhs) const noexcept { + return __p_ < __rhs.__p_; + } + + _LIBCPP_INLINE_VISIBILITY + bool operator==(directory_entry const& __rhs) const noexcept { + return __p_ == __rhs.__p_; + } + + _LIBCPP_INLINE_VISIBILITY + bool operator!=(directory_entry const& __rhs) const noexcept { + return __p_ != __rhs.__p_; + } + + _LIBCPP_INLINE_VISIBILITY + bool operator<=(directory_entry const& __rhs) const noexcept { + return __p_ <= __rhs.__p_; + } + + _LIBCPP_INLINE_VISIBILITY + bool operator>(directory_entry const& __rhs) const noexcept { + return __p_ > __rhs.__p_; + } + + _LIBCPP_INLINE_VISIBILITY + bool operator>=(directory_entry const& __rhs) const noexcept { + return __p_ >= __rhs.__p_; + } + +private: + friend class directory_iterator; + friend class recursive_directory_iterator; + friend class __dir_stream; + + enum _CacheType : unsigned char { + _Empty, + _IterSymlink, + _IterNonSymlink, + _RefreshSymlink, + _RefreshSymlinkUnresolved, + _RefreshNonSymlink + }; + + struct __cached_data { + uintmax_t __size_; + uintmax_t __nlink_; + file_time_type __write_time_; + perms __sym_perms_; + perms __non_sym_perms_; + file_type __type_; + _CacheType __cache_type_; + + _LIBCPP_INLINE_VISIBILITY + __cached_data() noexcept { __reset(); } + + _LIBCPP_INLINE_VISIBILITY + void __reset() { + __cache_type_ = _Empty; + __type_ = file_type::none; + __sym_perms_ = __non_sym_perms_ = perms::unknown; + __size_ = __nlink_ = uintmax_t(-1); + __write_time_ = file_time_type::min(); + } + }; + + _LIBCPP_INLINE_VISIBILITY + static __cached_data __create_iter_result(file_type __ft) { + __cached_data __data; + __data.__type_ = __ft; + __data.__cache_type_ = [&]() { + switch (__ft) { + case file_type::none: + return _Empty; + case file_type::symlink: + return _IterSymlink; + default: + return _IterNonSymlink; + } + }(); + return __data; + } + + _LIBCPP_INLINE_VISIBILITY + void __assign_iter_entry(_Path&& __p, __cached_data __dt) { + __p_ = std::move(__p); + __data_ = __dt; + } + + _LIBCPP_FUNC_VIS + error_code __do_refresh() noexcept; + + _LIBCPP_INLINE_VISIBILITY + static bool __is_dne_error(error_code const& __ec) { + if (!__ec) + return true; + switch (static_cast(__ec.value())) { + case errc::no_such_file_or_directory: + case errc::not_a_directory: + return true; + default: + return false; + } + } + + _LIBCPP_INLINE_VISIBILITY + void __handle_error(const char* __msg, error_code* __dest_ec, + error_code const& __ec, bool __allow_dne = false) const { + if (__dest_ec) { + *__dest_ec = __ec; + return; + } + if (__ec && (!__allow_dne || !__is_dne_error(__ec))) + __throw_filesystem_error(__msg, __p_, __ec); + } + + _LIBCPP_INLINE_VISIBILITY + void __refresh(error_code* __ec = nullptr) { + __handle_error("in directory_entry::refresh", __ec, __do_refresh(), + /*allow_dne*/ true); + } + + _LIBCPP_INLINE_VISIBILITY + file_type __get_sym_ft(error_code* __ec = nullptr) const { + switch (__data_.__cache_type_) { + case _Empty: + return __symlink_status(__p_, __ec).type(); + case _IterSymlink: + case _RefreshSymlink: + case _RefreshSymlinkUnresolved: + if (__ec) + __ec->clear(); + return file_type::symlink; + case _IterNonSymlink: + case _RefreshNonSymlink: + file_status __st(__data_.__type_); + if (__ec && !_VSTD_FS::exists(__st)) + *__ec = make_error_code(errc::no_such_file_or_directory); + else if (__ec) + __ec->clear(); + return __data_.__type_; + } + _LIBCPP_UNREACHABLE(); + } + + _LIBCPP_INLINE_VISIBILITY + file_type __get_ft(error_code* __ec = nullptr) const { + switch (__data_.__cache_type_) { + case _Empty: + case _IterSymlink: + case _RefreshSymlinkUnresolved: + return __status(__p_, __ec).type(); + case _IterNonSymlink: + case _RefreshNonSymlink: + case _RefreshSymlink: { + file_status __st(__data_.__type_); + if (__ec && !_VSTD_FS::exists(__st)) + *__ec = make_error_code(errc::no_such_file_or_directory); + else if (__ec) + __ec->clear(); + return __data_.__type_; + } + } + _LIBCPP_UNREACHABLE(); + } + + _LIBCPP_INLINE_VISIBILITY + file_status __get_status(error_code* __ec = nullptr) const { + switch (__data_.__cache_type_) { + case _Empty: + case _IterNonSymlink: + case _IterSymlink: + case _RefreshSymlinkUnresolved: + return __status(__p_, __ec); + case _RefreshNonSymlink: + case _RefreshSymlink: + return file_status(__get_ft(__ec), __data_.__non_sym_perms_); + } + _LIBCPP_UNREACHABLE(); + } + + _LIBCPP_INLINE_VISIBILITY + file_status __get_symlink_status(error_code* __ec = nullptr) const { + switch (__data_.__cache_type_) { + case _Empty: + case _IterNonSymlink: + case _IterSymlink: + return __symlink_status(__p_, __ec); + case _RefreshNonSymlink: + return file_status(__get_sym_ft(__ec), __data_.__non_sym_perms_); + case _RefreshSymlink: + case _RefreshSymlinkUnresolved: + return file_status(__get_sym_ft(__ec), __data_.__sym_perms_); + } + _LIBCPP_UNREACHABLE(); + } + + _LIBCPP_INLINE_VISIBILITY + uintmax_t __get_size(error_code* __ec = nullptr) const { + switch (__data_.__cache_type_) { + case _Empty: + case _IterNonSymlink: + case _IterSymlink: + case _RefreshSymlinkUnresolved: + return _VSTD_FS::__file_size(__p_, __ec); + case _RefreshSymlink: + case _RefreshNonSymlink: { + error_code __m_ec; + file_status __st(__get_ft(&__m_ec)); + __handle_error("in directory_entry::file_size", __ec, __m_ec); + if (_VSTD_FS::exists(__st) && !_VSTD_FS::is_regular_file(__st)) { + errc __err_kind = _VSTD_FS::is_directory(__st) ? errc::is_a_directory + : errc::not_supported; + __handle_error("in directory_entry::file_size", __ec, + make_error_code(__err_kind)); + } + return __data_.__size_; + } + } + _LIBCPP_UNREACHABLE(); + } + + _LIBCPP_INLINE_VISIBILITY + uintmax_t __get_nlink(error_code* __ec = nullptr) const { + switch (__data_.__cache_type_) { + case _Empty: + case _IterNonSymlink: + case _IterSymlink: + case _RefreshSymlinkUnresolved: + return _VSTD_FS::__hard_link_count(__p_, __ec); + case _RefreshSymlink: + case _RefreshNonSymlink: { + error_code __m_ec; + (void)__get_ft(&__m_ec); + __handle_error("in directory_entry::hard_link_count", __ec, __m_ec); + return __data_.__nlink_; + } + } + _LIBCPP_UNREACHABLE(); + } + + _LIBCPP_INLINE_VISIBILITY + file_time_type __get_write_time(error_code* __ec = nullptr) const { + switch (__data_.__cache_type_) { + case _Empty: + case _IterNonSymlink: + case _IterSymlink: + case _RefreshSymlinkUnresolved: + return _VSTD_FS::__last_write_time(__p_, __ec); + case _RefreshSymlink: + case _RefreshNonSymlink: { + error_code __m_ec; + file_status __st(__get_ft(&__m_ec)); + __handle_error("in directory_entry::last_write_time", __ec, __m_ec); + if (_VSTD_FS::exists(__st) && + __data_.__write_time_ == file_time_type::min()) + __handle_error("in directory_entry::last_write_time", __ec, + make_error_code(errc::value_too_large)); + return __data_.__write_time_; + } + } + _LIBCPP_UNREACHABLE(); + } + +private: + _Path __p_; + __cached_data __data_; +}; + +class __dir_element_proxy { +public: + inline _LIBCPP_INLINE_VISIBILITY directory_entry operator*() { + return _VSTD::move(__elem_); + } + +private: + friend class directory_iterator; + friend class recursive_directory_iterator; + explicit __dir_element_proxy(directory_entry const& __e) : __elem_(__e) {} + __dir_element_proxy(__dir_element_proxy&& __o) + : __elem_(_VSTD::move(__o.__elem_)) {} + directory_entry __elem_; +}; + +class directory_iterator { +public: + typedef directory_entry value_type; + typedef ptrdiff_t difference_type; + typedef value_type const* pointer; + typedef value_type const& reference; + typedef input_iterator_tag iterator_category; + +public: + //ctor & dtor + directory_iterator() noexcept {} + + explicit directory_iterator(const path& __p) + : directory_iterator(__p, nullptr) {} + + directory_iterator(const path& __p, directory_options __opts) + : directory_iterator(__p, nullptr, __opts) {} + + directory_iterator(const path& __p, error_code& __ec) + : directory_iterator(__p, &__ec) {} + + directory_iterator(const path& __p, directory_options __opts, + error_code& __ec) + : directory_iterator(__p, &__ec, __opts) {} + + directory_iterator(const directory_iterator&) = default; + directory_iterator(directory_iterator&&) = default; + directory_iterator& operator=(const directory_iterator&) = default; + + directory_iterator& operator=(directory_iterator&& __o) noexcept { + // non-default implementation provided to support self-move assign. + if (this != &__o) { + __imp_ = _VSTD::move(__o.__imp_); + } + return *this; + } + + ~directory_iterator() = default; + + const directory_entry& operator*() const { + _LIBCPP_ASSERT(__imp_, "The end iterator cannot be dereferenced"); + return __dereference(); + } + + const directory_entry* operator->() const { return &**this; } + + directory_iterator& operator++() { return __increment(); } + + __dir_element_proxy operator++(int) { + __dir_element_proxy __p(**this); + __increment(); + return __p; + } + + directory_iterator& increment(error_code& __ec) { return __increment(&__ec); } + +private: + inline _LIBCPP_INLINE_VISIBILITY friend bool + operator==(const directory_iterator& __lhs, + const directory_iterator& __rhs) noexcept; + + // construct the dir_stream + _LIBCPP_FUNC_VIS + directory_iterator(const path&, error_code*, + directory_options = directory_options::none); + + _LIBCPP_FUNC_VIS + directory_iterator& __increment(error_code* __ec = nullptr); + + _LIBCPP_FUNC_VIS + const directory_entry& __dereference() const; + +private: + shared_ptr<__dir_stream> __imp_; +}; + +inline _LIBCPP_INLINE_VISIBILITY bool +operator==(const directory_iterator& __lhs, + const directory_iterator& __rhs) noexcept { + return __lhs.__imp_ == __rhs.__imp_; +} + +inline _LIBCPP_INLINE_VISIBILITY bool +operator!=(const directory_iterator& __lhs, + const directory_iterator& __rhs) noexcept { + return !(__lhs == __rhs); +} + +// enable directory_iterator range-based for statements +inline _LIBCPP_INLINE_VISIBILITY directory_iterator +begin(directory_iterator __iter) noexcept { + return __iter; +} + +inline _LIBCPP_INLINE_VISIBILITY directory_iterator +end(const directory_iterator&) noexcept { + return directory_iterator(); +} + +class recursive_directory_iterator { +public: + using value_type = directory_entry; + using difference_type = std::ptrdiff_t; + using pointer = directory_entry const*; + using reference = directory_entry const&; + using iterator_category = std::input_iterator_tag; + +public: + // constructors and destructor + _LIBCPP_INLINE_VISIBILITY + recursive_directory_iterator() noexcept : __rec_(false) {} + + _LIBCPP_INLINE_VISIBILITY + explicit recursive_directory_iterator( + const path& __p, directory_options __xoptions = directory_options::none) + : recursive_directory_iterator(__p, __xoptions, nullptr) {} + + _LIBCPP_INLINE_VISIBILITY + recursive_directory_iterator(const path& __p, directory_options __xoptions, + error_code& __ec) + : recursive_directory_iterator(__p, __xoptions, &__ec) {} + + _LIBCPP_INLINE_VISIBILITY + recursive_directory_iterator(const path& __p, error_code& __ec) + : recursive_directory_iterator(__p, directory_options::none, &__ec) {} + + recursive_directory_iterator(const recursive_directory_iterator&) = default; + recursive_directory_iterator(recursive_directory_iterator&&) = default; + + recursive_directory_iterator& + operator=(const recursive_directory_iterator&) = default; + + _LIBCPP_INLINE_VISIBILITY + recursive_directory_iterator& + operator=(recursive_directory_iterator&& __o) noexcept { + // non-default implementation provided to support self-move assign. + if (this != &__o) { + __imp_ = _VSTD::move(__o.__imp_); + __rec_ = __o.__rec_; + } + return *this; + } + + ~recursive_directory_iterator() = default; + + _LIBCPP_INLINE_VISIBILITY + const directory_entry& operator*() const { return __dereference(); } + + _LIBCPP_INLINE_VISIBILITY + const directory_entry* operator->() const { return &__dereference(); } + + recursive_directory_iterator& operator++() { return __increment(); } + + _LIBCPP_INLINE_VISIBILITY + __dir_element_proxy operator++(int) { + __dir_element_proxy __p(**this); + __increment(); + return __p; + } + + _LIBCPP_INLINE_VISIBILITY + recursive_directory_iterator& increment(error_code& __ec) { + return __increment(&__ec); + } + + _LIBCPP_FUNC_VIS directory_options options() const; + _LIBCPP_FUNC_VIS int depth() const; + + _LIBCPP_INLINE_VISIBILITY + void pop() { __pop(); } + + _LIBCPP_INLINE_VISIBILITY + void pop(error_code& __ec) { __pop(&__ec); } + + _LIBCPP_INLINE_VISIBILITY + bool recursion_pending() const { return __rec_; } + + _LIBCPP_INLINE_VISIBILITY + void disable_recursion_pending() { __rec_ = false; } + +private: + recursive_directory_iterator(const path& __p, directory_options __opt, + error_code* __ec); + + _LIBCPP_FUNC_VIS + const directory_entry& __dereference() const; + + _LIBCPP_FUNC_VIS + bool __try_recursion(error_code* __ec); + + _LIBCPP_FUNC_VIS + void __advance(error_code* __ec = nullptr); + + _LIBCPP_FUNC_VIS + recursive_directory_iterator& __increment(error_code* __ec = nullptr); + + _LIBCPP_FUNC_VIS + void __pop(error_code* __ec = nullptr); + + inline _LIBCPP_INLINE_VISIBILITY friend bool + operator==(const recursive_directory_iterator&, + const recursive_directory_iterator&) noexcept; + + struct __shared_imp; + shared_ptr<__shared_imp> __imp_; + bool __rec_; +}; // class recursive_directory_iterator + +inline _LIBCPP_INLINE_VISIBILITY bool +operator==(const recursive_directory_iterator& __lhs, + const recursive_directory_iterator& __rhs) noexcept { + return __lhs.__imp_ == __rhs.__imp_; +} + +_LIBCPP_INLINE_VISIBILITY +inline bool operator!=(const recursive_directory_iterator& __lhs, + const recursive_directory_iterator& __rhs) noexcept { + return !(__lhs == __rhs); +} +// enable recursive_directory_iterator range-based for statements +inline _LIBCPP_INLINE_VISIBILITY recursive_directory_iterator +begin(recursive_directory_iterator __iter) noexcept { + return __iter; +} + +inline _LIBCPP_INLINE_VISIBILITY recursive_directory_iterator +end(const recursive_directory_iterator&) noexcept { + return recursive_directory_iterator(); +} + +} // namespace android::hardware::automotive::filesystem +#ifdef _LIBAUTO_UNDEF_VSTD +#undef _VSTD +#undef _LIBAUTO_UNDEF_VSTD +#endif + +#ifndef _LIBAUTO_UNDEF_VSTD_FS +#pragma pop_macro("_VSTD_FS") +#else +#undef _VSTD +#undef _LIBAUTO_UNDEF_VSTD_FS +#endif + +#endif // !_LIBCPP_CXX03_LANG + +_LIBCPP_POP_MACROS + +#endif // _LIBAUTO_FILESYSTEM diff --git a/automotive/can/1.0/default/libc++fs/src b/automotive/can/1.0/default/libc++fs/src deleted file mode 120000 index 7abb4ba5f9..0000000000 --- a/automotive/can/1.0/default/libc++fs/src +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../external/libcxx/src/ \ No newline at end of file diff --git a/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp b/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp new file mode 100644 index 0000000000..624538bd77 --- /dev/null +++ b/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp @@ -0,0 +1,397 @@ +//===------------------ directory_iterator.cpp ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/* clang-format off */ +#include "automotive/filesystem" +#include <__config> +#if defined(_LIBCPP_WIN32API) +#define WIN32_LEAN_AND_MEAN +#include +#else +#include +#endif +#include + +#include "filesystem_common.h" + +namespace android::hardware::automotive::filesystem { + +namespace detail { +namespace { + +#if !defined(_LIBCPP_WIN32API) +template +static file_type get_file_type(DirEntT* ent, int) { + switch (ent->d_type) { + case DT_BLK: + return file_type::block; + case DT_CHR: + return file_type::character; + case DT_DIR: + return file_type::directory; + case DT_FIFO: + return file_type::fifo; + case DT_LNK: + return file_type::symlink; + case DT_REG: + return file_type::regular; + case DT_SOCK: + return file_type::socket; + // Unlike in lstat, hitting "unknown" here simply means that the underlying + // filesystem doesn't support d_type. Report is as 'none' so we correctly + // set the cache to empty. + case DT_UNKNOWN: + break; + } + return file_type::none; +} + +template +static file_type get_file_type(DirEntT* ent, long) { + return file_type::none; +} + +static pair posix_readdir(DIR* dir_stream, + error_code& ec) { + struct dirent* dir_entry_ptr = nullptr; + errno = 0; // zero errno in order to detect errors + ec.clear(); + if ((dir_entry_ptr = ::readdir(dir_stream)) == nullptr) { + if (errno) + ec = capture_errno(); + return {}; + } else { + return {dir_entry_ptr->d_name, get_file_type(dir_entry_ptr, 0)}; + } +} +#else + +static file_type get_file_type(const WIN32_FIND_DATA& data) { + //auto attrs = data.dwFileAttributes; + // FIXME(EricWF) + return file_type::unknown; +} +static uintmax_t get_file_size(const WIN32_FIND_DATA& data) { + return (data.nFileSizeHight * (MAXDWORD + 1)) + data.nFileSizeLow; +} +static file_time_type get_write_time(const WIN32_FIND_DATA& data) { + ULARGE_INTEGER tmp; + FILETIME& time = data.ftLastWriteTime; + tmp.u.LowPart = time.dwLowDateTime; + tmp.u.HighPart = time.dwHighDateTime; + return file_time_type(file_time_type::duration(time.QuadPart)); +} + +#endif + +} // namespace +} // namespace detail + +using detail::ErrorHandler; + +#if defined(_LIBCPP_WIN32API) +class __dir_stream { +public: + __dir_stream() = delete; + __dir_stream& operator=(const __dir_stream&) = delete; + + __dir_stream(__dir_stream&& __ds) noexcept : __stream_(__ds.__stream_), + __root_(move(__ds.__root_)), + __entry_(move(__ds.__entry_)) { + __ds.__stream_ = INVALID_HANDLE_VALUE; + } + + __dir_stream(const path& root, directory_options opts, error_code& ec) + : __stream_(INVALID_HANDLE_VALUE), __root_(root) { + __stream_ = ::FindFirstFileEx(root.c_str(), &__data_); + if (__stream_ == INVALID_HANDLE_VALUE) { + ec = error_code(::GetLastError(), generic_category()); + const bool ignore_permission_denied = + bool(opts & directory_options::skip_permission_denied); + if (ignore_permission_denied && ec.value() == ERROR_ACCESS_DENIED) + ec.clear(); + return; + } + } + + ~__dir_stream() noexcept { + if (__stream_ == INVALID_HANDLE_VALUE) + return; + close(); + } + + bool good() const noexcept { return __stream_ != INVALID_HANDLE_VALUE; } + + bool advance(error_code& ec) { + while (::FindNextFile(__stream_, &__data_)) { + if (!strcmp(__data_.cFileName, ".") || strcmp(__data_.cFileName, "..")) + continue; + // FIXME: Cache more of this + //directory_entry::__cached_data cdata; + //cdata.__type_ = get_file_type(__data_); + //cdata.__size_ = get_file_size(__data_); + //cdata.__write_time_ = get_write_time(__data_); + __entry_.__assign_iter_entry( + __root_ / __data_.cFileName, + directory_entry::__create_iter_result(get_file_type(__data))); + return true; + } + ec = error_code(::GetLastError(), generic_category()); + close(); + return false; + } + +private: + error_code close() noexcept { + error_code ec; + if (!::FindClose(__stream_)) + ec = error_code(::GetLastError(), generic_category()); + __stream_ = INVALID_HANDLE_VALUE; + return ec; + } + + HANDLE __stream_{INVALID_HANDLE_VALUE}; + WIN32_FIND_DATA __data_; + +public: + path __root_; + directory_entry __entry_; +}; +#else +class __dir_stream { +public: + __dir_stream() = delete; + __dir_stream& operator=(const __dir_stream&) = delete; + + __dir_stream(__dir_stream&& other) noexcept : __stream_(other.__stream_), + __root_(move(other.__root_)), + __entry_(move(other.__entry_)) { + other.__stream_ = nullptr; + } + + __dir_stream(const path& root, directory_options opts, error_code& ec) + : __stream_(nullptr), __root_(root) { + if ((__stream_ = ::opendir(root.c_str())) == nullptr) { + ec = detail::capture_errno(); + const bool allow_eacess = + bool(opts & directory_options::skip_permission_denied); + if (allow_eacess && ec.value() == EACCES) + ec.clear(); + return; + } + advance(ec); + } + + ~__dir_stream() noexcept { + if (__stream_) + close(); + } + + bool good() const noexcept { return __stream_ != nullptr; } + + bool advance(error_code& ec) { + while (true) { + auto str_type_pair = detail::posix_readdir(__stream_, ec); + auto& str = str_type_pair.first; + if (str == "." || str == "..") { + continue; + } else if (ec || str.empty()) { + close(); + return false; + } else { + __entry_.__assign_iter_entry( + __root_ / str, + directory_entry::__create_iter_result(str_type_pair.second)); + return true; + } + } + } + +private: + error_code close() noexcept { + error_code m_ec; + if (::closedir(__stream_) == -1) + m_ec = detail::capture_errno(); + __stream_ = nullptr; + return m_ec; + } + + DIR* __stream_{nullptr}; + +public: + path __root_; + directory_entry __entry_; +}; +#endif + +// directory_iterator + +directory_iterator::directory_iterator(const path& p, error_code* ec, + directory_options opts) { + ErrorHandler err("directory_iterator::directory_iterator(...)", ec, &p); + + error_code m_ec; + __imp_ = make_shared<__dir_stream>(p, opts, m_ec); + if (ec) + *ec = m_ec; + if (!__imp_->good()) { + __imp_.reset(); + if (m_ec) + err.report(m_ec); + } +} + +directory_iterator& directory_iterator::__increment(error_code* ec) { + _LIBCPP_ASSERT(__imp_, "Attempting to increment an invalid iterator"); + ErrorHandler err("directory_iterator::operator++()", ec); + + error_code m_ec; + if (!__imp_->advance(m_ec)) { + path root = move(__imp_->__root_); + __imp_.reset(); + if (m_ec) + err.report(m_ec, "at root \"%s\"", root); + } + return *this; +} + +directory_entry const& directory_iterator::__dereference() const { + _LIBCPP_ASSERT(__imp_, "Attempting to dereference an invalid iterator"); + return __imp_->__entry_; +} + +// recursive_directory_iterator + +struct recursive_directory_iterator::__shared_imp { + stack<__dir_stream> __stack_; + directory_options __options_; +}; + +recursive_directory_iterator::recursive_directory_iterator( + const path& p, directory_options opt, error_code* ec) + : __imp_(nullptr), __rec_(true) { + ErrorHandler err("recursive_directory_iterator", ec, &p); + + error_code m_ec; + __dir_stream new_s(p, opt, m_ec); + if (m_ec) + err.report(m_ec); + if (m_ec || !new_s.good()) + return; + + __imp_ = make_shared<__shared_imp>(); + __imp_->__options_ = opt; + __imp_->__stack_.push(move(new_s)); +} + +void recursive_directory_iterator::__pop(error_code* ec) { + _LIBCPP_ASSERT(__imp_, "Popping the end iterator"); + if (ec) + ec->clear(); + __imp_->__stack_.pop(); + if (__imp_->__stack_.size() == 0) + __imp_.reset(); + else + __advance(ec); +} + +directory_options recursive_directory_iterator::options() const { + return __imp_->__options_; +} + +int recursive_directory_iterator::depth() const { + return __imp_->__stack_.size() - 1; +} + +const directory_entry& recursive_directory_iterator::__dereference() const { + return __imp_->__stack_.top().__entry_; +} + +recursive_directory_iterator& +recursive_directory_iterator::__increment(error_code* ec) { + if (ec) + ec->clear(); + if (recursion_pending()) { + if (__try_recursion(ec) || (ec && *ec)) + return *this; + } + __rec_ = true; + __advance(ec); + return *this; +} + +void recursive_directory_iterator::__advance(error_code* ec) { + ErrorHandler err("recursive_directory_iterator::operator++()", ec); + + const directory_iterator end_it; + auto& stack = __imp_->__stack_; + error_code m_ec; + while (stack.size() > 0) { + if (stack.top().advance(m_ec)) + return; + if (m_ec) + break; + stack.pop(); + } + + if (m_ec) { + path root = move(stack.top().__root_); + __imp_.reset(); + err.report(m_ec, "at root \"%s\"", root); + } else { + __imp_.reset(); + } +} + +bool recursive_directory_iterator::__try_recursion(error_code* ec) { + ErrorHandler err("recursive_directory_iterator::operator++()", ec); + + bool rec_sym = bool(options() & directory_options::follow_directory_symlink); + + auto& curr_it = __imp_->__stack_.top(); + + bool skip_rec = false; + error_code m_ec; + if (!rec_sym) { + file_status st(curr_it.__entry_.__get_sym_ft(&m_ec)); + if (m_ec && status_known(st)) + m_ec.clear(); + if (m_ec || is_symlink(st) || !is_directory(st)) + skip_rec = true; + } else { + file_status st(curr_it.__entry_.__get_ft(&m_ec)); + if (m_ec && status_known(st)) + m_ec.clear(); + if (m_ec || !is_directory(st)) + skip_rec = true; + } + + if (!skip_rec) { + __dir_stream new_it(curr_it.__entry_.path(), __imp_->__options_, m_ec); + if (new_it.good()) { + __imp_->__stack_.push(move(new_it)); + return true; + } + } + if (m_ec) { + const bool allow_eacess = + bool(__imp_->__options_ & directory_options::skip_permission_denied); + if (m_ec.value() == EACCES && allow_eacess) { + if (ec) + ec->clear(); + } else { + path at_ent = move(curr_it.__entry_.__p_); + __imp_.reset(); + err.report(m_ec, "attempting recursion into \"%s\"", at_ent); + } + } + return false; +} + +} // namespace android::hardware::automotive::filesystem +/* clang-format on */ diff --git a/automotive/can/1.0/default/libc++fs/src/filesystem/filesystem_common.h b/automotive/can/1.0/default/libc++fs/src/filesystem/filesystem_common.h new file mode 100644 index 0000000000..4f4466120a --- /dev/null +++ b/automotive/can/1.0/default/libc++fs/src/filesystem/filesystem_common.h @@ -0,0 +1,441 @@ +//===----------------------------------------------------------------------===//// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===//// +/* clang-format off */ +#ifndef AUTO_FILESYSTEM_COMMON_H +#define AUTO_FILESYSTEM_COMMON_H + +#include "automotive/filesystem" +#include +#include +#include +#include + +#include +#include +#include +#include // for ::utimes as used in __last_write_time +#include /* values for fchmodat */ + +#if !defined(__APPLE__) +// We can use the presence of UTIME_OMIT to detect platforms that provide +// utimensat. +#if defined(UTIME_OMIT) +#define _LIBCPP_USE_UTIMENSAT +#endif +#endif + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +namespace android::hardware::automotive::filesystem { +using namespace std::chrono; + +using std::error_code; +using std::is_floating_point; +using std::micro; +using std::nano; +using std::ratio; + +namespace detail { +namespace { + +static string format_string_imp(const char* msg, ...) { + // we might need a second shot at this, so pre-emptivly make a copy + struct GuardVAList { + va_list& target; + bool active = true; + GuardVAList(va_list& target) : target(target), active(true) {} + void clear() { + if (active) + va_end(target); + active = false; + } + ~GuardVAList() { + if (active) + va_end(target); + } + }; + va_list args; + va_start(args, msg); + GuardVAList args_guard(args); + + va_list args_cp; + va_copy(args_cp, args); + GuardVAList args_copy_guard(args_cp); + + std::string result; + + array local_buff; + size_t size_with_null = local_buff.size(); + auto ret = ::vsnprintf(local_buff.data(), size_with_null, msg, args_cp); + + args_copy_guard.clear(); + + // handle empty expansion + if (ret == 0) + return result; + if (static_cast(ret) < size_with_null) { + result.assign(local_buff.data(), static_cast(ret)); + return result; + } + + // we did not provide a long enough buffer on our first attempt. The + // return value is the number of bytes (excluding the null byte) that are + // needed for formatting. + size_with_null = static_cast(ret) + 1; + result.__resize_default_init(size_with_null - 1); + ret = ::vsnprintf(&result[0], size_with_null, msg, args); + _LIBCPP_ASSERT(static_cast(ret) == (size_with_null - 1), "TODO"); + + return result; +} + +const char* unwrap(string const& s) { return s.c_str(); } +const char* unwrap(path const& p) { return p.native().c_str(); } +template +Arg const& unwrap(Arg const& a) { + static_assert(!is_class::value, "cannot pass class here"); + return a; +} + +template +string format_string(const char* fmt, Args const&... args) { + return format_string_imp(fmt, unwrap(args)...); +} + +error_code capture_errno() { + _LIBCPP_ASSERT(errno, "Expected errno to be non-zero"); + return error_code(errno, generic_category()); +} + +template +T error_value(); +template <> +_LIBCPP_CONSTEXPR_AFTER_CXX11 void error_value() {} +template <> +bool error_value() { + return false; +} +template <> +uintmax_t error_value() { + return uintmax_t(-1); +} +template <> +_LIBCPP_CONSTEXPR_AFTER_CXX11 file_time_type error_value() { + return file_time_type::min(); +} +template <> +path error_value() { + return {}; +} + +template +struct ErrorHandler { + const char* func_name; + error_code* ec = nullptr; + const path* p1 = nullptr; + const path* p2 = nullptr; + + ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr, + const path* p2 = nullptr) + : func_name(fname), ec(ec), p1(p1), p2(p2) { + if (ec) + ec->clear(); + } + + T report(const error_code& m_ec) const { + if (ec) { + *ec = m_ec; + return error_value(); + } + string what = string("in ") + func_name; + switch (bool(p1) + bool(p2)) { + case 0: + __throw_filesystem_error(what, m_ec); + case 1: + __throw_filesystem_error(what, *p1, m_ec); + case 2: + __throw_filesystem_error(what, *p1, *p2, m_ec); + } + _LIBCPP_UNREACHABLE(); + } + + template + T report(const error_code& m_ec, const char* msg, Args const&... args) const { + if (ec) { + *ec = m_ec; + return error_value(); + } + string what = + string("in ") + func_name + ": " + format_string(msg, args...); + switch (bool(p1) + bool(p2)) { + case 0: + __throw_filesystem_error(what, m_ec); + case 1: + __throw_filesystem_error(what, *p1, m_ec); + case 2: + __throw_filesystem_error(what, *p1, *p2, m_ec); + } + _LIBCPP_UNREACHABLE(); + } + + T report(errc const& err) const { return report(make_error_code(err)); } + + template + T report(errc const& err, const char* msg, Args const&... args) const { + return report(make_error_code(err), msg, args...); + } + +private: + ErrorHandler(ErrorHandler const&) = delete; + ErrorHandler& operator=(ErrorHandler const&) = delete; +}; + +using chrono::duration; +using chrono::duration_cast; + +using TimeSpec = struct ::timespec; +using StatT = struct ::stat; + +template ::value> +struct time_util_base { + using rep = typename FileTimeT::rep; + using fs_duration = typename FileTimeT::duration; + using fs_seconds = duration; + using fs_nanoseconds = duration; + using fs_microseconds = duration; + + static constexpr rep max_seconds = + duration_cast(FileTimeT::duration::max()).count(); + + static constexpr rep max_nsec = + duration_cast(FileTimeT::duration::max() - + fs_seconds(max_seconds)) + .count(); + + static constexpr rep min_seconds = + duration_cast(FileTimeT::duration::min()).count(); + + static constexpr rep min_nsec_timespec = + duration_cast( + (FileTimeT::duration::min() - fs_seconds(min_seconds)) + + fs_seconds(1)) + .count(); + +private: +#if _LIBCPP_STD_VER > 11 && !defined(_LIBCPP_HAS_NO_CXX14_CONSTEXPR) + static constexpr fs_duration get_min_nsecs() { + return duration_cast( + fs_nanoseconds(min_nsec_timespec) - + duration_cast(fs_seconds(1))); + } + // Static assert that these values properly round trip. + static_assert(fs_seconds(min_seconds) + get_min_nsecs() == + FileTimeT::duration::min(), + "value doesn't roundtrip"); + + static constexpr bool check_range() { + // This kinda sucks, but it's what happens when we don't have __int128_t. + if (sizeof(TimeT) == sizeof(rep)) { + typedef duration > Years; + return duration_cast(fs_seconds(max_seconds)) > Years(250) && + duration_cast(fs_seconds(min_seconds)) < Years(-250); + } + return max_seconds >= numeric_limits::max() && + min_seconds <= numeric_limits::min(); + } + static_assert(check_range(), "the representable range is unacceptable small"); +#endif +}; + +template +struct time_util_base { + using rep = typename FileTimeT::rep; + using fs_duration = typename FileTimeT::duration; + using fs_seconds = duration; + using fs_nanoseconds = duration; + using fs_microseconds = duration; + + static const rep max_seconds; + static const rep max_nsec; + static const rep min_seconds; + static const rep min_nsec_timespec; +}; + +template +const typename FileTimeT::rep + time_util_base::max_seconds = + duration_cast(FileTimeT::duration::max()).count(); + +template +const typename FileTimeT::rep time_util_base::max_nsec = + duration_cast(FileTimeT::duration::max() - + fs_seconds(max_seconds)) + .count(); + +template +const typename FileTimeT::rep + time_util_base::min_seconds = + duration_cast(FileTimeT::duration::min()).count(); + +template +const typename FileTimeT::rep + time_util_base::min_nsec_timespec = + duration_cast((FileTimeT::duration::min() - + fs_seconds(min_seconds)) + + fs_seconds(1)) + .count(); + +template +struct time_util : time_util_base { + using Base = time_util_base; + using Base::max_nsec; + using Base::max_seconds; + using Base::min_nsec_timespec; + using Base::min_seconds; + + using typename Base::fs_duration; + using typename Base::fs_microseconds; + using typename Base::fs_nanoseconds; + using typename Base::fs_seconds; + +public: + template + static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool checked_set(CType* out, + ChronoType time) { + using Lim = numeric_limits; + if (time > Lim::max() || time < Lim::min()) + return false; + *out = static_cast(time); + return true; + } + + static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(TimeSpecT tm) { + if (tm.tv_sec >= 0) { + return tm.tv_sec < max_seconds || + (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec); + } else if (tm.tv_sec == (min_seconds - 1)) { + return tm.tv_nsec >= min_nsec_timespec; + } else { + return tm.tv_sec >= min_seconds; + } + } + + static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(FileTimeT tm) { + auto secs = duration_cast(tm.time_since_epoch()); + auto nsecs = duration_cast(tm.time_since_epoch() - secs); + if (nsecs.count() < 0) { + secs = secs + fs_seconds(1); + nsecs = nsecs + fs_seconds(1); + } + using TLim = numeric_limits; + if (secs.count() >= 0) + return secs.count() <= TLim::max(); + return secs.count() >= TLim::min(); + } + + static _LIBCPP_CONSTEXPR_AFTER_CXX11 FileTimeT + convert_from_timespec(TimeSpecT tm) { + if (tm.tv_sec >= 0 || tm.tv_nsec == 0) { + return FileTimeT(fs_seconds(tm.tv_sec) + + duration_cast(fs_nanoseconds(tm.tv_nsec))); + } else { // tm.tv_sec < 0 + auto adj_subsec = duration_cast(fs_seconds(1) - + fs_nanoseconds(tm.tv_nsec)); + auto Dur = fs_seconds(tm.tv_sec + 1) - adj_subsec; + return FileTimeT(Dur); + } + } + + template + static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool + set_times_checked(TimeT* sec_out, SubSecT* subsec_out, FileTimeT tp) { + auto dur = tp.time_since_epoch(); + auto sec_dur = duration_cast(dur); + auto subsec_dur = duration_cast(dur - sec_dur); + // The tv_nsec and tv_usec fields must not be negative so adjust accordingly + if (subsec_dur.count() < 0) { + if (sec_dur.count() > min_seconds) { + sec_dur = sec_dur - fs_seconds(1); + subsec_dur = subsec_dur + fs_seconds(1); + } else { + subsec_dur = fs_nanoseconds::zero(); + } + } + return checked_set(sec_out, sec_dur.count()) && + checked_set(subsec_out, subsec_dur.count()); + } + static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool convert_to_timespec(TimeSpecT& dest, + FileTimeT tp) { + if (!is_representable(tp)) + return false; + return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp); + } +}; + +using fs_time = time_util; + +#if defined(__APPLE__) +TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; } +TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; } +#else +TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; } +TimeSpec extract_atime(StatT const& st) { return st.st_atim; } +#endif + +// allow the utimes implementation to compile even it we're not going +// to use it. + +bool posix_utimes(const path& p, std::array const& TS, + error_code& ec) { + using namespace chrono; + auto Convert = [](long nsec) { + using int_type = decltype(std::declval< ::timeval>().tv_usec); + auto dur = duration_cast(nanoseconds(nsec)).count(); + return static_cast(dur); + }; + struct ::timeval ConvertedTS[2] = {{TS[0].tv_sec, Convert(TS[0].tv_nsec)}, + {TS[1].tv_sec, Convert(TS[1].tv_nsec)}}; + if (::utimes(p.c_str(), ConvertedTS) == -1) { + ec = capture_errno(); + return true; + } + return false; +} + +#if defined(_LIBCPP_USE_UTIMENSAT) +bool posix_utimensat(const path& p, std::array const& TS, + error_code& ec) { + if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1) { + ec = capture_errno(); + return true; + } + return false; +} +#endif + +bool set_file_times(const path& p, std::array const& TS, + error_code& ec) { +#if !defined(_LIBCPP_USE_UTIMENSAT) + return posix_utimes(p, TS, ec); +#else + return posix_utimensat(p, TS, ec); +#endif +} + +} // namespace +} // end namespace detail + +} // namespace android::hardware::automotive::filesystem + +#endif // AUTO_FILESYSTEM_COMMON_H +/* clang-format on */ diff --git a/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp b/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp new file mode 100644 index 0000000000..404c0bd4c9 --- /dev/null +++ b/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp @@ -0,0 +1,1773 @@ +//===--------------------- filesystem/ops.cpp -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/* clang-format off */ +#include "automotive/filesystem" +#include +#include +#include +#include /* for unique_path */ +#include +#include +#include +#include +#include + +#include "filesystem_common.h" + +#include +#include +#include +#include +#include /* values for fchmodat */ + +#if defined(__linux__) +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) +#include +#define _LIBCPP_USE_SENDFILE +#endif +#elif defined(__APPLE__) || __has_include() +#include +#define _LIBCPP_USE_COPYFILE +#endif + +#if !defined(__APPLE__) +#define _LIBCPP_USE_CLOCK_GETTIME +#endif + +#if !defined(CLOCK_REALTIME) || !defined(_LIBCPP_USE_CLOCK_GETTIME) +#include // for gettimeofday and timeval +#endif // !defined(CLOCK_REALTIME) + +#if defined(_LIBCPP_COMPILER_GCC) +#if _GNUC_VER < 500 +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif +#endif + +namespace android::hardware::automotive::filesystem { + +#ifdef _VSTD_FS +#pragma push_macro("_VSTD_FS") +#else +#define _LIBAUTO_UNDEF_VSTD_FS +#endif +#define _VSTD_FS android::hardware::automotive::filesystem + +namespace { +namespace parser { + +using string_view_t = path::__string_view; +using string_view_pair = pair; +using PosPtr = path::value_type const*; + +struct PathParser { + enum ParserState : unsigned char { + // Zero is a special sentinel value used by default constructed iterators. + PS_BeforeBegin = path::iterator::_BeforeBegin, + PS_InRootName = path::iterator::_InRootName, + PS_InRootDir = path::iterator::_InRootDir, + PS_InFilenames = path::iterator::_InFilenames, + PS_InTrailingSep = path::iterator::_InTrailingSep, + PS_AtEnd = path::iterator::_AtEnd + }; + + const string_view_t Path; + string_view_t RawEntry; + ParserState State; + +private: + PathParser(string_view_t P, ParserState State) noexcept : Path(P), + State(State) {} + +public: + PathParser(string_view_t P, string_view_t E, unsigned char S) + : Path(P), RawEntry(E), State(static_cast(S)) { + // S cannot be '0' or PS_BeforeBegin. + } + + static PathParser CreateBegin(string_view_t P) noexcept { + PathParser PP(P, PS_BeforeBegin); + PP.increment(); + return PP; + } + + static PathParser CreateEnd(string_view_t P) noexcept { + PathParser PP(P, PS_AtEnd); + return PP; + } + + PosPtr peek() const noexcept { + auto TkEnd = getNextTokenStartPos(); + auto End = getAfterBack(); + return TkEnd == End ? nullptr : TkEnd; + } + + void increment() noexcept { + const PosPtr End = getAfterBack(); + const PosPtr Start = getNextTokenStartPos(); + if (Start == End) + return makeState(PS_AtEnd); + + switch (State) { + case PS_BeforeBegin: { + PosPtr TkEnd = consumeSeparator(Start, End); + if (TkEnd) + return makeState(PS_InRootDir, Start, TkEnd); + else + return makeState(PS_InFilenames, Start, consumeName(Start, End)); + } + case PS_InRootDir: + return makeState(PS_InFilenames, Start, consumeName(Start, End)); + + case PS_InFilenames: { + PosPtr SepEnd = consumeSeparator(Start, End); + if (SepEnd != End) { + PosPtr TkEnd = consumeName(SepEnd, End); + if (TkEnd) + return makeState(PS_InFilenames, SepEnd, TkEnd); + } + return makeState(PS_InTrailingSep, Start, SepEnd); + } + + case PS_InTrailingSep: + return makeState(PS_AtEnd); + + case PS_InRootName: + case PS_AtEnd: + _LIBCPP_UNREACHABLE(); + } + } + + void decrement() noexcept { + const PosPtr REnd = getBeforeFront(); + const PosPtr RStart = getCurrentTokenStartPos() - 1; + if (RStart == REnd) // we're decrementing the begin + return makeState(PS_BeforeBegin); + + switch (State) { + case PS_AtEnd: { + // Try to consume a trailing separator or root directory first. + if (PosPtr SepEnd = consumeSeparator(RStart, REnd)) { + if (SepEnd == REnd) + return makeState(PS_InRootDir, Path.data(), RStart + 1); + return makeState(PS_InTrailingSep, SepEnd + 1, RStart + 1); + } else { + PosPtr TkStart = consumeName(RStart, REnd); + return makeState(PS_InFilenames, TkStart + 1, RStart + 1); + } + } + case PS_InTrailingSep: + return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1, + RStart + 1); + case PS_InFilenames: { + PosPtr SepEnd = consumeSeparator(RStart, REnd); + if (SepEnd == REnd) + return makeState(PS_InRootDir, Path.data(), RStart + 1); + PosPtr TkEnd = consumeName(SepEnd, REnd); + return makeState(PS_InFilenames, TkEnd + 1, SepEnd + 1); + } + case PS_InRootDir: + // return makeState(PS_InRootName, Path.data(), RStart + 1); + case PS_InRootName: + case PS_BeforeBegin: + _LIBCPP_UNREACHABLE(); + } + } + + /// \brief Return a view with the "preferred representation" of the current + /// element. For example trailing separators are represented as a '.' + string_view_t operator*() const noexcept { + switch (State) { + case PS_BeforeBegin: + case PS_AtEnd: + return ""; + case PS_InRootDir: + return "/"; + case PS_InTrailingSep: + return ""; + case PS_InRootName: + case PS_InFilenames: + return RawEntry; + } + _LIBCPP_UNREACHABLE(); + } + + explicit operator bool() const noexcept { + return State != PS_BeforeBegin && State != PS_AtEnd; + } + + PathParser& operator++() noexcept { + increment(); + return *this; + } + + PathParser& operator--() noexcept { + decrement(); + return *this; + } + + bool atEnd() const noexcept { + return State == PS_AtEnd; + } + + bool inRootDir() const noexcept { + return State == PS_InRootDir; + } + + bool inRootName() const noexcept { + return State == PS_InRootName; + } + + bool inRootPath() const noexcept { + return inRootName() || inRootDir(); + } + +private: + void makeState(ParserState NewState, PosPtr Start, PosPtr End) noexcept { + State = NewState; + RawEntry = string_view_t(Start, End - Start); + } + void makeState(ParserState NewState) noexcept { + State = NewState; + RawEntry = {}; + } + + PosPtr getAfterBack() const noexcept { return Path.data() + Path.size(); } + + PosPtr getBeforeFront() const noexcept { return Path.data() - 1; } + + /// \brief Return a pointer to the first character after the currently + /// lexed element. + PosPtr getNextTokenStartPos() const noexcept { + switch (State) { + case PS_BeforeBegin: + return Path.data(); + case PS_InRootName: + case PS_InRootDir: + case PS_InFilenames: + return &RawEntry.back() + 1; + case PS_InTrailingSep: + case PS_AtEnd: + return getAfterBack(); + } + _LIBCPP_UNREACHABLE(); + } + + /// \brief Return a pointer to the first character in the currently lexed + /// element. + PosPtr getCurrentTokenStartPos() const noexcept { + switch (State) { + case PS_BeforeBegin: + case PS_InRootName: + return &Path.front(); + case PS_InRootDir: + case PS_InFilenames: + case PS_InTrailingSep: + return &RawEntry.front(); + case PS_AtEnd: + return &Path.back() + 1; + } + _LIBCPP_UNREACHABLE(); + } + + PosPtr consumeSeparator(PosPtr P, PosPtr End) const noexcept { + if (P == End || *P != '/') + return nullptr; + const int Inc = P < End ? 1 : -1; + P += Inc; + while (P != End && *P == '/') + P += Inc; + return P; + } + + PosPtr consumeName(PosPtr P, PosPtr End) const noexcept { + if (P == End || *P == '/') + return nullptr; + const int Inc = P < End ? 1 : -1; + P += Inc; + while (P != End && *P != '/') + P += Inc; + return P; + } +}; + +string_view_pair separate_filename(string_view_t const& s) { + if (s == "." || s == ".." || s.empty()) + return string_view_pair{s, ""}; + auto pos = s.find_last_of('.'); + if (pos == string_view_t::npos || pos == 0) + return string_view_pair{s, string_view_t{}}; + return string_view_pair{s.substr(0, pos), s.substr(pos)}; +} + +string_view_t createView(PosPtr S, PosPtr E) noexcept { + return {S, static_cast(E - S) + 1}; +} + +} // namespace parser +} // namespace + +// POSIX HELPERS + +namespace detail { +namespace { + +using value_type = path::value_type; +using string_type = path::string_type; + +struct FileDescriptor { + const path& name; + int fd = -1; + StatT m_stat; + file_status m_status; + + template + static FileDescriptor create(const path* p, error_code& ec, Args... args) { + ec.clear(); + int fd; + if ((fd = ::open(p->c_str(), args...)) == -1) { + ec = capture_errno(); + return FileDescriptor{p}; + } + return FileDescriptor(p, fd); + } + + template + static FileDescriptor create_with_status(const path* p, error_code& ec, + Args... args) { + FileDescriptor fd = create(p, ec, args...); + if (!ec) + fd.refresh_status(ec); + + return fd; + } + + file_status get_status() const { return m_status; } + StatT const& get_stat() const { return m_stat; } + + bool status_known() const { return _VSTD_FS::status_known(m_status); } + + file_status refresh_status(error_code& ec); + + void close() noexcept { + if (fd != -1) + ::close(fd); + fd = -1; + } + + FileDescriptor(FileDescriptor&& other) + : name(other.name), fd(other.fd), m_stat(other.m_stat), + m_status(other.m_status) { + other.fd = -1; + other.m_status = file_status{}; + } + + ~FileDescriptor() { close(); } + + FileDescriptor(FileDescriptor const&) = delete; + FileDescriptor& operator=(FileDescriptor const&) = delete; + +private: + explicit FileDescriptor(const path* p, int fd = -1) : name(*p), fd(fd) {} +}; + +perms posix_get_perms(const StatT& st) noexcept { + return static_cast(st.st_mode) & perms::mask; +} + +::mode_t posix_convert_perms(perms prms) { + return static_cast< ::mode_t>(prms & perms::mask); +} + +file_status create_file_status(error_code& m_ec, path const& p, + const StatT& path_stat, error_code* ec) { + if (ec) + *ec = m_ec; + if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) { + return file_status(file_type::not_found); + } else if (m_ec) { + ErrorHandler err("posix_stat", ec, &p); + err.report(m_ec, "failed to determine attributes for the specified path"); + return file_status(file_type::none); + } + // else + + file_status fs_tmp; + auto const mode = path_stat.st_mode; + if (S_ISLNK(mode)) + fs_tmp.type(file_type::symlink); + else if (S_ISREG(mode)) + fs_tmp.type(file_type::regular); + else if (S_ISDIR(mode)) + fs_tmp.type(file_type::directory); + else if (S_ISBLK(mode)) + fs_tmp.type(file_type::block); + else if (S_ISCHR(mode)) + fs_tmp.type(file_type::character); + else if (S_ISFIFO(mode)) + fs_tmp.type(file_type::fifo); + else if (S_ISSOCK(mode)) + fs_tmp.type(file_type::socket); + else + fs_tmp.type(file_type::unknown); + + fs_tmp.permissions(detail::posix_get_perms(path_stat)); + return fs_tmp; +} + +file_status posix_stat(path const& p, StatT& path_stat, error_code* ec) { + error_code m_ec; + if (::stat(p.c_str(), &path_stat) == -1) + m_ec = detail::capture_errno(); + return create_file_status(m_ec, p, path_stat, ec); +} + +file_status posix_stat(path const& p, error_code* ec) { + StatT path_stat; + return posix_stat(p, path_stat, ec); +} + +file_status posix_lstat(path const& p, StatT& path_stat, error_code* ec) { + error_code m_ec; + if (::lstat(p.c_str(), &path_stat) == -1) + m_ec = detail::capture_errno(); + return create_file_status(m_ec, p, path_stat, ec); +} + +file_status posix_lstat(path const& p, error_code* ec) { + StatT path_stat; + return posix_lstat(p, path_stat, ec); +} + +bool posix_ftruncate(const FileDescriptor& fd, size_t to_size, error_code& ec) { + if (::ftruncate(fd.fd, to_size) == -1) { + ec = capture_errno(); + return true; + } + ec.clear(); + return false; +} + +bool posix_fchmod(const FileDescriptor& fd, const StatT& st, error_code& ec) { + if (::fchmod(fd.fd, st.st_mode) == -1) { + ec = capture_errno(); + return true; + } + ec.clear(); + return false; +} + +bool stat_equivalent(const StatT& st1, const StatT& st2) { + return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino); +} + +file_status FileDescriptor::refresh_status(error_code& ec) { + // FD must be open and good. + m_status = file_status{}; + m_stat = {}; + error_code m_ec; + if (::fstat(fd, &m_stat) == -1) + m_ec = capture_errno(); + m_status = create_file_status(m_ec, name, m_stat, &ec); + return m_status; +} +} // namespace +} // end namespace detail + +using detail::capture_errno; +using detail::ErrorHandler; +using detail::StatT; +using detail::TimeSpec; +using parser::createView; +using parser::PathParser; +using parser::string_view_t; + +const bool _FilesystemClock::is_steady; + +_FilesystemClock::time_point _FilesystemClock::now() noexcept { + typedef chrono::duration __secs; +#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME) + typedef chrono::duration __nsecs; + struct timespec tp; + if (0 != clock_gettime(CLOCK_REALTIME, &tp)) + __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed"); + return time_point(__secs(tp.tv_sec) + + chrono::duration_cast(__nsecs(tp.tv_nsec))); +#else + typedef chrono::duration __microsecs; + timeval tv; + gettimeofday(&tv, 0); + return time_point(__secs(tv.tv_sec) + __microsecs(tv.tv_usec)); +#endif // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME +} + +filesystem_error::~filesystem_error() {} + +void filesystem_error::__create_what(int __num_paths) { + const char* derived_what = system_error::what(); + __storage_->__what_ = [&]() -> string { + const char* p1 = path1().native().empty() ? "\"\"" : path1().c_str(); + const char* p2 = path2().native().empty() ? "\"\"" : path2().c_str(); + switch (__num_paths) { + default: + return detail::format_string("filesystem error: %s", derived_what); + case 1: + return detail::format_string("filesystem error: %s [%s]", derived_what, + p1); + case 2: + return detail::format_string("filesystem error: %s [%s] [%s]", + derived_what, p1, p2); + } + }(); +} + +static path __do_absolute(const path& p, path* cwd, error_code* ec) { + if (ec) + ec->clear(); + if (p.is_absolute()) + return p; + *cwd = __current_path(ec); + if (ec && *ec) + return {}; + return (*cwd) / p; +} + +path __absolute(const path& p, error_code* ec) { + path cwd; + return __do_absolute(p, &cwd, ec); +} + +path __canonical(path const& orig_p, error_code* ec) { + path cwd; + ErrorHandler err("canonical", ec, &orig_p, &cwd); + + path p = __do_absolute(orig_p, &cwd, ec); + char buff[PATH_MAX + 1]; + char* ret; + if ((ret = ::realpath(p.c_str(), buff)) == nullptr) + return err.report(capture_errno()); + return {ret}; +} + +void __copy(const path& from, const path& to, copy_options options, + error_code* ec) { + ErrorHandler err("copy", ec, &from, &to); + + const bool sym_status = bool( + options & (copy_options::create_symlinks | copy_options::skip_symlinks)); + + const bool sym_status2 = bool(options & copy_options::copy_symlinks); + + error_code m_ec1; + StatT f_st = {}; + const file_status f = sym_status || sym_status2 + ? detail::posix_lstat(from, f_st, &m_ec1) + : detail::posix_stat(from, f_st, &m_ec1); + if (m_ec1) + return err.report(m_ec1); + + StatT t_st = {}; + const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec1) + : detail::posix_stat(to, t_st, &m_ec1); + + if (not status_known(t)) + return err.report(m_ec1); + + if (!exists(f) || is_other(f) || is_other(t) || + (is_directory(f) && is_regular_file(t)) || + detail::stat_equivalent(f_st, t_st)) { + return err.report(errc::function_not_supported); + } + + if (ec) + ec->clear(); + + if (is_symlink(f)) { + if (bool(copy_options::skip_symlinks & options)) { + // do nothing + } else if (not exists(t)) { + __copy_symlink(from, to, ec); + } else { + return err.report(errc::file_exists); + } + return; + } else if (is_regular_file(f)) { + if (bool(copy_options::directories_only & options)) { + // do nothing + } else if (bool(copy_options::create_symlinks & options)) { + __create_symlink(from, to, ec); + } else if (bool(copy_options::create_hard_links & options)) { + __create_hard_link(from, to, ec); + } else if (is_directory(t)) { + __copy_file(from, to / from.filename(), options, ec); + } else { + __copy_file(from, to, options, ec); + } + return; + } else if (is_directory(f) && bool(copy_options::create_symlinks & options)) { + return err.report(errc::is_a_directory); + } else if (is_directory(f) && (bool(copy_options::recursive & options) || + copy_options::none == options)) { + + if (!exists(t)) { + // create directory to with attributes from 'from'. + __create_directory(to, from, ec); + if (ec && *ec) { + return; + } + } + directory_iterator it = + ec ? directory_iterator(from, *ec) : directory_iterator(from); + if (ec && *ec) { + return; + } + error_code m_ec2; + for (; it != directory_iterator(); it.increment(m_ec2)) { + if (m_ec2) { + return err.report(m_ec2); + } + __copy(it->path(), to / it->path().filename(), + options | copy_options::__in_recursive_copy, ec); + if (ec && *ec) { + return; + } + } + } +} + +namespace detail { +namespace { + +#ifdef _LIBCPP_USE_SENDFILE +bool copy_file_impl_sendfile(FileDescriptor& read_fd, FileDescriptor& write_fd, + error_code& ec) { + + size_t count = read_fd.get_stat().st_size; + do { + ssize_t res; + if ((res = ::sendfile(write_fd.fd, read_fd.fd, nullptr, count)) == -1) { + ec = capture_errno(); + return false; + } + count -= res; + } while (count > 0); + + ec.clear(); + + return true; +} +#elif defined(_LIBCPP_USE_COPYFILE) +bool copy_file_impl_copyfile(FileDescriptor& read_fd, FileDescriptor& write_fd, + error_code& ec) { + struct CopyFileState { + copyfile_state_t state; + CopyFileState() { state = copyfile_state_alloc(); } + ~CopyFileState() { copyfile_state_free(state); } + + private: + CopyFileState(CopyFileState const&) = delete; + CopyFileState& operator=(CopyFileState const&) = delete; + }; + + CopyFileState cfs; + if (fcopyfile(read_fd.fd, write_fd.fd, cfs.state, COPYFILE_DATA) < 0) { + ec = capture_errno(); + return false; + } + + ec.clear(); + return true; +} +#endif + +// Note: This function isn't guarded by ifdef's even though it may be unused +// in order to assure it still compiles. +__attribute__((unused)) bool copy_file_impl_default(FileDescriptor& read_fd, + FileDescriptor& write_fd, + error_code& ec) { + ifstream in; + in.__open(read_fd.fd, ios::binary); + if (!in.is_open()) { + // This assumes that __open didn't reset the error code. + ec = capture_errno(); + return false; + } + ofstream out; + out.__open(write_fd.fd, ios::binary); + if (!out.is_open()) { + ec = capture_errno(); + return false; + } + + if (in.good() && out.good()) { + using InIt = istreambuf_iterator; + using OutIt = ostreambuf_iterator; + InIt bin(in); + InIt ein; + OutIt bout(out); + copy(bin, ein, bout); + } + if (out.fail() || in.fail()) { + ec = make_error_code(errc::io_error); + return false; + } + + ec.clear(); + return true; +} + +bool copy_file_impl(FileDescriptor& from, FileDescriptor& to, error_code& ec) { +#if defined(_LIBCPP_USE_SENDFILE) + return copy_file_impl_sendfile(from, to, ec); +#elif defined(_LIBCPP_USE_COPYFILE) + return copy_file_impl_copyfile(from, to, ec); +#else + return copy_file_impl_default(from, to, ec); +#endif +} + +} // namespace +} // namespace detail + +bool __copy_file(const path& from, const path& to, copy_options options, + error_code* ec) { + using detail::FileDescriptor; + ErrorHandler err("copy_file", ec, &to, &from); + + error_code m_ec; + FileDescriptor from_fd = + FileDescriptor::create_with_status(&from, m_ec, O_RDONLY | O_NONBLOCK); + if (m_ec) + return err.report(m_ec); + + auto from_st = from_fd.get_status(); + StatT const& from_stat = from_fd.get_stat(); + if (!is_regular_file(from_st)) { + if (not m_ec) + m_ec = make_error_code(errc::not_supported); + return err.report(m_ec); + } + + const bool skip_existing = bool(copy_options::skip_existing & options); + const bool update_existing = bool(copy_options::update_existing & options); + const bool overwrite_existing = + bool(copy_options::overwrite_existing & options); + + StatT to_stat_path; + file_status to_st = detail::posix_stat(to, to_stat_path, &m_ec); + if (!status_known(to_st)) + return err.report(m_ec); + + const bool to_exists = exists(to_st); + if (to_exists && !is_regular_file(to_st)) + return err.report(errc::not_supported); + + if (to_exists && detail::stat_equivalent(from_stat, to_stat_path)) + return err.report(errc::file_exists); + + if (to_exists && skip_existing) + return false; + + bool ShouldCopy = [&]() { + if (to_exists && update_existing) { + auto from_time = detail::extract_mtime(from_stat); + auto to_time = detail::extract_mtime(to_stat_path); + if (from_time.tv_sec < to_time.tv_sec) + return false; + if (from_time.tv_sec == to_time.tv_sec && + from_time.tv_nsec <= to_time.tv_nsec) + return false; + return true; + } + if (!to_exists || overwrite_existing) + return true; + return err.report(errc::file_exists); + }(); + if (!ShouldCopy) + return false; + + // Don't truncate right away. We may not be opening the file we originally + // looked at; we'll check this later. + int to_open_flags = O_WRONLY; + if (!to_exists) + to_open_flags |= O_CREAT; + FileDescriptor to_fd = FileDescriptor::create_with_status( + &to, m_ec, to_open_flags, from_stat.st_mode); + if (m_ec) + return err.report(m_ec); + + if (to_exists) { + // Check that the file we initially stat'ed is equivalent to the one + // we opened. + // FIXME: report this better. + if (!detail::stat_equivalent(to_stat_path, to_fd.get_stat())) + return err.report(errc::bad_file_descriptor); + + // Set the permissions and truncate the file we opened. + if (detail::posix_fchmod(to_fd, from_stat, m_ec)) + return err.report(m_ec); + if (detail::posix_ftruncate(to_fd, 0, m_ec)) + return err.report(m_ec); + } + + if (!copy_file_impl(from_fd, to_fd, m_ec)) { + // FIXME: Remove the dest file if we failed, and it didn't exist previously. + return err.report(m_ec); + } + + return true; +} + +void __copy_symlink(const path& existing_symlink, const path& new_symlink, + error_code* ec) { + const path real_path(__read_symlink(existing_symlink, ec)); + if (ec && *ec) { + return; + } + // NOTE: proposal says you should detect if you should call + // create_symlink or create_directory_symlink. I don't think this + // is needed with POSIX + __create_symlink(real_path, new_symlink, ec); +} + +bool __create_directories(const path& p, error_code* ec) { + ErrorHandler err("create_directories", ec, &p); + + error_code m_ec; + auto const st = detail::posix_stat(p, &m_ec); + if (!status_known(st)) + return err.report(m_ec); + else if (is_directory(st)) + return false; + else if (exists(st)) + return err.report(errc::file_exists); + + const path parent = p.parent_path(); + if (!parent.empty()) { + const file_status parent_st = status(parent, m_ec); + if (not status_known(parent_st)) + return err.report(m_ec); + if (not exists(parent_st)) { + __create_directories(parent, ec); + if (ec && *ec) { + return false; + } + } + } + return __create_directory(p, ec); +} + +bool __create_directory(const path& p, error_code* ec) { + ErrorHandler err("create_directory", ec, &p); + + if (::mkdir(p.c_str(), static_cast(perms::all)) == 0) + return true; + if (errno != EEXIST) + err.report(capture_errno()); + return false; +} + +bool __create_directory(path const& p, path const& attributes, error_code* ec) { + ErrorHandler err("create_directory", ec, &p, &attributes); + + StatT attr_stat; + error_code mec; + auto st = detail::posix_stat(attributes, attr_stat, &mec); + if (!status_known(st)) + return err.report(mec); + if (!is_directory(st)) + return err.report(errc::not_a_directory, + "the specified attribute path is invalid"); + + if (::mkdir(p.c_str(), attr_stat.st_mode) == 0) + return true; + if (errno != EEXIST) + err.report(capture_errno()); + return false; +} + +void __create_directory_symlink(path const& from, path const& to, + error_code* ec) { + ErrorHandler err("create_directory_symlink", ec, &from, &to); + if (::symlink(from.c_str(), to.c_str()) != 0) + return err.report(capture_errno()); +} + +void __create_hard_link(const path& from, const path& to, error_code* ec) { + ErrorHandler err("create_hard_link", ec, &from, &to); + if (::link(from.c_str(), to.c_str()) == -1) + return err.report(capture_errno()); +} + +void __create_symlink(path const& from, path const& to, error_code* ec) { + ErrorHandler err("create_symlink", ec, &from, &to); + if (::symlink(from.c_str(), to.c_str()) == -1) + return err.report(capture_errno()); +} + +path __current_path(error_code* ec) { + ErrorHandler err("current_path", ec); + + auto size = ::pathconf(".", _PC_PATH_MAX); + _LIBCPP_ASSERT(size >= 0, "pathconf returned a 0 as max size"); + + auto buff = unique_ptr(new char[size + 1]); + char* ret; + if ((ret = ::getcwd(buff.get(), static_cast(size))) == nullptr) + return err.report(capture_errno(), "call to getcwd failed"); + + return {buff.get()}; +} + +void __current_path(const path& p, error_code* ec) { + ErrorHandler err("current_path", ec, &p); + if (::chdir(p.c_str()) == -1) + err.report(capture_errno()); +} + +bool __equivalent(const path& p1, const path& p2, error_code* ec) { + ErrorHandler err("equivalent", ec, &p1, &p2); + + error_code ec1, ec2; + StatT st1 = {}, st2 = {}; + auto s1 = detail::posix_stat(p1.native(), st1, &ec1); + if (!exists(s1)) + return err.report(errc::not_supported); + auto s2 = detail::posix_stat(p2.native(), st2, &ec2); + if (!exists(s2)) + return err.report(errc::not_supported); + + return detail::stat_equivalent(st1, st2); +} + +uintmax_t __file_size(const path& p, error_code* ec) { + ErrorHandler err("file_size", ec, &p); + + error_code m_ec; + StatT st; + file_status fst = detail::posix_stat(p, st, &m_ec); + if (!exists(fst) || !is_regular_file(fst)) { + errc error_kind = + is_directory(fst) ? errc::is_a_directory : errc::not_supported; + if (!m_ec) + m_ec = make_error_code(error_kind); + return err.report(m_ec); + } + // is_regular_file(p) == true + return static_cast(st.st_size); +} + +uintmax_t __hard_link_count(const path& p, error_code* ec) { + ErrorHandler err("hard_link_count", ec, &p); + + error_code m_ec; + StatT st; + detail::posix_stat(p, st, &m_ec); + if (m_ec) + return err.report(m_ec); + return static_cast(st.st_nlink); +} + +bool __fs_is_empty(const path& p, error_code* ec) { + ErrorHandler err("is_empty", ec, &p); + + error_code m_ec; + StatT pst; + auto st = detail::posix_stat(p, pst, &m_ec); + if (m_ec) + return err.report(m_ec); + else if (!is_directory(st) && !is_regular_file(st)) + return err.report(errc::not_supported); + else if (is_directory(st)) { + auto it = ec ? directory_iterator(p, *ec) : directory_iterator(p); + if (ec && *ec) + return false; + return it == directory_iterator{}; + } else if (is_regular_file(st)) + return static_cast(pst.st_size) == 0; + + _LIBCPP_UNREACHABLE(); +} + +static file_time_type __extract_last_write_time(const path& p, const StatT& st, + error_code* ec) { + using detail::fs_time; + ErrorHandler err("last_write_time", ec, &p); + + auto ts = detail::extract_mtime(st); + if (!fs_time::is_representable(ts)) + return err.report(errc::value_too_large); + + return fs_time::convert_from_timespec(ts); +} + +file_time_type __last_write_time(const path& p, error_code* ec) { + using namespace chrono; + ErrorHandler err("last_write_time", ec, &p); + + error_code m_ec; + StatT st; + detail::posix_stat(p, st, &m_ec); + if (m_ec) + return err.report(m_ec); + return __extract_last_write_time(p, st, ec); +} + +void __last_write_time(const path& p, file_time_type new_time, error_code* ec) { + using detail::fs_time; + ErrorHandler err("last_write_time", ec, &p); + + error_code m_ec; + array tbuf; +#if !defined(_LIBCPP_USE_UTIMENSAT) + // This implementation has a race condition between determining the + // last access time and attempting to set it to the same value using + // ::utimes + StatT st; + file_status fst = detail::posix_stat(p, st, &m_ec); + if (m_ec) + return err.report(m_ec); + tbuf[0] = detail::extract_atime(st); +#else + tbuf[0].tv_sec = 0; + tbuf[0].tv_nsec = UTIME_OMIT; +#endif + if (!fs_time::convert_to_timespec(tbuf[1], new_time)) + return err.report(errc::value_too_large); + + detail::set_file_times(p, tbuf, m_ec); + if (m_ec) + return err.report(m_ec); +} + +void __permissions(const path& p, perms prms, perm_options opts, + error_code* ec) { + ErrorHandler err("permissions", ec, &p); + + auto has_opt = [&](perm_options o) { return bool(o & opts); }; + const bool resolve_symlinks = !has_opt(perm_options::nofollow); + const bool add_perms = has_opt(perm_options::add); + const bool remove_perms = has_opt(perm_options::remove); + _LIBCPP_ASSERT( + (add_perms + remove_perms + has_opt(perm_options::replace)) == 1, + "One and only one of the perm_options constants replace, add, or remove " + "is present in opts"); + + bool set_sym_perms = false; + prms &= perms::mask; + if (!resolve_symlinks || (add_perms || remove_perms)) { + error_code m_ec; + file_status st = resolve_symlinks ? detail::posix_stat(p, &m_ec) + : detail::posix_lstat(p, &m_ec); + set_sym_perms = is_symlink(st); + if (m_ec) + return err.report(m_ec); + _LIBCPP_ASSERT(st.permissions() != perms::unknown, + "Permissions unexpectedly unknown"); + if (add_perms) + prms |= st.permissions(); + else if (remove_perms) + prms = st.permissions() & ~prms; + } + const auto real_perms = detail::posix_convert_perms(prms); + +#if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD) + const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0; + if (::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) { + return err.report(capture_errno()); + } +#else + if (set_sym_perms) + return err.report(errc::operation_not_supported); + if (::chmod(p.c_str(), real_perms) == -1) { + return err.report(capture_errno()); + } +#endif +} + +path __read_symlink(const path& p, error_code* ec) { + ErrorHandler err("read_symlink", ec, &p); + + char buff[PATH_MAX + 1]; + error_code m_ec; + ::ssize_t ret; + if ((ret = ::readlink(p.c_str(), buff, PATH_MAX)) == -1) { + return err.report(capture_errno()); + } + _LIBCPP_ASSERT(ret <= PATH_MAX, "TODO"); + _LIBCPP_ASSERT(ret > 0, "TODO"); + buff[ret] = 0; + return {buff}; +} + +bool __remove(const path& p, error_code* ec) { + ErrorHandler err("remove", ec, &p); + if (::remove(p.c_str()) == -1) { + if (errno != ENOENT) + err.report(capture_errno()); + return false; + } + return true; +} + +namespace { + +uintmax_t remove_all_impl(path const& p, error_code& ec) { + const auto npos = static_cast(-1); + const file_status st = __symlink_status(p, &ec); + if (ec) + return npos; + uintmax_t count = 1; + if (is_directory(st)) { + for (directory_iterator it(p, ec); !ec && it != directory_iterator(); + it.increment(ec)) { + auto other_count = remove_all_impl(it->path(), ec); + if (ec) + return npos; + count += other_count; + } + if (ec) + return npos; + } + if (!__remove(p, &ec)) + return npos; + return count; +} + +} // end namespace + +uintmax_t __remove_all(const path& p, error_code* ec) { + ErrorHandler err("remove_all", ec, &p); + + error_code mec; + auto count = remove_all_impl(p, mec); + if (mec) { + if (mec == errc::no_such_file_or_directory) + return 0; + return err.report(mec); + } + return count; +} + +void __rename(const path& from, const path& to, error_code* ec) { + ErrorHandler err("rename", ec, &from, &to); + if (::rename(from.c_str(), to.c_str()) == -1) + err.report(capture_errno()); +} + +void __resize_file(const path& p, uintmax_t size, error_code* ec) { + ErrorHandler err("resize_file", ec, &p); + if (::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1) + return err.report(capture_errno()); +} + +space_info __space(const path& p, error_code* ec) { + ErrorHandler err("space", ec, &p); + space_info si; + struct statvfs m_svfs = {}; + if (::statvfs(p.c_str(), &m_svfs) == -1) { + err.report(capture_errno()); + si.capacity = si.free = si.available = static_cast(-1); + return si; + } + // Multiply with overflow checking. + auto do_mult = [&](uintmax_t& out, uintmax_t other) { + out = other * m_svfs.f_frsize; + if (other == 0 || out / other != m_svfs.f_frsize) + out = static_cast(-1); + }; + do_mult(si.capacity, m_svfs.f_blocks); + do_mult(si.free, m_svfs.f_bfree); + do_mult(si.available, m_svfs.f_bavail); + return si; +} + +file_status __status(const path& p, error_code* ec) { + return detail::posix_stat(p, ec); +} + +file_status __symlink_status(const path& p, error_code* ec) { + return detail::posix_lstat(p, ec); +} + +path __temp_directory_path(error_code* ec) { + ErrorHandler err("temp_directory_path", ec); + + const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"}; + const char* ret = nullptr; + + for (auto& ep : env_paths) + if ((ret = getenv(ep))) + break; + if (ret == nullptr) + ret = "/tmp"; + + path p(ret); + error_code m_ec; + file_status st = detail::posix_stat(p, &m_ec); + if (!status_known(st)) + return err.report(m_ec, "cannot access path \"%s\"", p); + + if (!exists(st) || !is_directory(st)) + return err.report(errc::not_a_directory, "path \"%s\" is not a directory", + p); + + return p; +} + +path __weakly_canonical(const path& p, error_code* ec) { + ErrorHandler err("weakly_canonical", ec, &p); + + if (p.empty()) + return __canonical("", ec); + + path result; + path tmp; + tmp.__reserve(p.native().size()); + auto PP = PathParser::CreateEnd(p.native()); + --PP; + vector DNEParts; + + while (PP.State != PathParser::PS_BeforeBegin) { + tmp.assign(createView(p.native().data(), &PP.RawEntry.back())); + error_code m_ec; + file_status st = __status(tmp, &m_ec); + if (!status_known(st)) { + return err.report(m_ec); + } else if (exists(st)) { + result = __canonical(tmp, ec); + break; + } + DNEParts.push_back(*PP); + --PP; + } + if (PP.State == PathParser::PS_BeforeBegin) + result = __canonical("", ec); + if (ec) + ec->clear(); + if (DNEParts.empty()) + return result; + for (auto It = DNEParts.rbegin(); It != DNEParts.rend(); ++It) + result /= *It; + return result.lexically_normal(); +} + +/////////////////////////////////////////////////////////////////////////////// +// path definitions +/////////////////////////////////////////////////////////////////////////////// + +constexpr path::value_type path::preferred_separator; + +path& path::replace_extension(path const& replacement) { + path p = extension(); + if (not p.empty()) { + __pn_.erase(__pn_.size() - p.native().size()); + } + if (!replacement.empty()) { + if (replacement.native()[0] != '.') { + __pn_ += "."; + } + __pn_.append(replacement.__pn_); + } + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// +// path.decompose + +string_view_t path::__root_name() const { + auto PP = PathParser::CreateBegin(__pn_); + if (PP.State == PathParser::PS_InRootName) + return *PP; + return {}; +} + +string_view_t path::__root_directory() const { + auto PP = PathParser::CreateBegin(__pn_); + if (PP.State == PathParser::PS_InRootName) + ++PP; + if (PP.State == PathParser::PS_InRootDir) + return *PP; + return {}; +} + +string_view_t path::__root_path_raw() const { + auto PP = PathParser::CreateBegin(__pn_); + if (PP.State == PathParser::PS_InRootName) { + auto NextCh = PP.peek(); + if (NextCh && *NextCh == '/') { + ++PP; + return createView(__pn_.data(), &PP.RawEntry.back()); + } + return PP.RawEntry; + } + if (PP.State == PathParser::PS_InRootDir) + return *PP; + return {}; +} + +static bool ConsumeRootName(PathParser *PP) { + static_assert(PathParser::PS_BeforeBegin == 1 && + PathParser::PS_InRootName == 2, + "Values for enums are incorrect"); + while (PP->State <= PathParser::PS_InRootName) + ++(*PP); + return PP->State == PathParser::PS_AtEnd; +} + +static bool ConsumeRootDir(PathParser* PP) { + static_assert(PathParser::PS_BeforeBegin == 1 && + PathParser::PS_InRootName == 2 && + PathParser::PS_InRootDir == 3, "Values for enums are incorrect"); + while (PP->State <= PathParser::PS_InRootDir) + ++(*PP); + return PP->State == PathParser::PS_AtEnd; +} + +string_view_t path::__relative_path() const { + auto PP = PathParser::CreateBegin(__pn_); + if (ConsumeRootDir(&PP)) + return {}; + return createView(PP.RawEntry.data(), &__pn_.back()); +} + +string_view_t path::__parent_path() const { + if (empty()) + return {}; + // Determine if we have a root path but not a relative path. In that case + // return *this. + { + auto PP = PathParser::CreateBegin(__pn_); + if (ConsumeRootDir(&PP)) + return __pn_; + } + // Otherwise remove a single element from the end of the path, and return + // a string representing that path + { + auto PP = PathParser::CreateEnd(__pn_); + --PP; + if (PP.RawEntry.data() == __pn_.data()) + return {}; + --PP; + return createView(__pn_.data(), &PP.RawEntry.back()); + } +} + +string_view_t path::__filename() const { + if (empty()) + return {}; + { + PathParser PP = PathParser::CreateBegin(__pn_); + if (ConsumeRootDir(&PP)) + return {}; + } + return *(--PathParser::CreateEnd(__pn_)); +} + +string_view_t path::__stem() const { + return parser::separate_filename(__filename()).first; +} + +string_view_t path::__extension() const { + return parser::separate_filename(__filename()).second; +} + +//////////////////////////////////////////////////////////////////////////// +// path.gen + +enum PathPartKind : unsigned char { + PK_None, + PK_RootSep, + PK_Filename, + PK_Dot, + PK_DotDot, + PK_TrailingSep +}; + +static PathPartKind ClassifyPathPart(string_view_t Part) { + if (Part.empty()) + return PK_TrailingSep; + if (Part == ".") + return PK_Dot; + if (Part == "..") + return PK_DotDot; + if (Part == "/") + return PK_RootSep; + return PK_Filename; +} + +path path::lexically_normal() const { + if (__pn_.empty()) + return *this; + + using PartKindPair = pair; + vector Parts; + // Guess as to how many elements the path has to avoid reallocating. + Parts.reserve(32); + + // Track the total size of the parts as we collect them. This allows the + // resulting path to reserve the correct amount of memory. + size_t NewPathSize = 0; + auto AddPart = [&](PathPartKind K, string_view_t P) { + NewPathSize += P.size(); + Parts.emplace_back(P, K); + }; + auto LastPartKind = [&]() { + if (Parts.empty()) + return PK_None; + return Parts.back().second; + }; + + bool MaybeNeedTrailingSep = false; + // Build a stack containing the remaining elements of the path, popping off + // elements which occur before a '..' entry. + for (auto PP = PathParser::CreateBegin(__pn_); PP; ++PP) { + auto Part = *PP; + PathPartKind Kind = ClassifyPathPart(Part); + switch (Kind) { + case PK_Filename: + case PK_RootSep: { + // Add all non-dot and non-dot-dot elements to the stack of elements. + AddPart(Kind, Part); + MaybeNeedTrailingSep = false; + break; + } + case PK_DotDot: { + // Only push a ".." element if there are no elements preceding the "..", + // or if the preceding element is itself "..". + auto LastKind = LastPartKind(); + if (LastKind == PK_Filename) { + NewPathSize -= Parts.back().first.size(); + Parts.pop_back(); + } else if (LastKind != PK_RootSep) + AddPart(PK_DotDot, ".."); + MaybeNeedTrailingSep = LastKind == PK_Filename; + break; + } + case PK_Dot: + case PK_TrailingSep: { + MaybeNeedTrailingSep = true; + break; + } + case PK_None: + _LIBCPP_UNREACHABLE(); + } + } + // [fs.path.generic]p6.8: If the path is empty, add a dot. + if (Parts.empty()) + return "."; + + // [fs.path.generic]p6.7: If the last filename is dot-dot, remove any + // trailing directory-separator. + bool NeedTrailingSep = MaybeNeedTrailingSep && LastPartKind() == PK_Filename; + + path Result; + Result.__pn_.reserve(Parts.size() + NewPathSize + NeedTrailingSep); + for (auto& PK : Parts) + Result /= PK.first; + + if (NeedTrailingSep) + Result /= ""; + + return Result; +} + +static int DetermineLexicalElementCount(PathParser PP) { + int Count = 0; + for (; PP; ++PP) { + auto Elem = *PP; + if (Elem == "..") + --Count; + else if (Elem != "." && Elem != "") + ++Count; + } + return Count; +} + +path path::lexically_relative(const path& base) const { + { // perform root-name/root-directory mismatch checks + auto PP = PathParser::CreateBegin(__pn_); + auto PPBase = PathParser::CreateBegin(base.__pn_); + auto CheckIterMismatchAtBase = [&]() { + return PP.State != PPBase.State && + (PP.inRootPath() || PPBase.inRootPath()); + }; + if (PP.inRootName() && PPBase.inRootName()) { + if (*PP != *PPBase) + return {}; + } else if (CheckIterMismatchAtBase()) + return {}; + + if (PP.inRootPath()) + ++PP; + if (PPBase.inRootPath()) + ++PPBase; + if (CheckIterMismatchAtBase()) + return {}; + } + + // Find the first mismatching element + auto PP = PathParser::CreateBegin(__pn_); + auto PPBase = PathParser::CreateBegin(base.__pn_); + while (PP && PPBase && PP.State == PPBase.State && *PP == *PPBase) { + ++PP; + ++PPBase; + } + + // If there is no mismatch, return ".". + if (!PP && !PPBase) + return "."; + + // Otherwise, determine the number of elements, 'n', which are not dot or + // dot-dot minus the number of dot-dot elements. + int ElemCount = DetermineLexicalElementCount(PPBase); + if (ElemCount < 0) + return {}; + + // if n == 0 and (a == end() || a->empty()), returns path("."); otherwise + if (ElemCount == 0 && (PP.atEnd() || *PP == "")) + return "."; + + // return a path constructed with 'n' dot-dot elements, followed by the + // elements of '*this' after the mismatch. + path Result; + // FIXME: Reserve enough room in Result that it won't have to re-allocate. + while (ElemCount--) + Result /= ".."; + for (; PP; ++PP) + Result /= *PP; + return Result; +} + +//////////////////////////////////////////////////////////////////////////// +// path.comparisons +static int CompareRootName(PathParser *LHS, PathParser *RHS) { + if (!LHS->inRootName() && !RHS->inRootName()) + return 0; + + auto GetRootName = [](PathParser *Parser) -> string_view_t { + return Parser->inRootName() ? **Parser : ""; + }; + int res = GetRootName(LHS).compare(GetRootName(RHS)); + ConsumeRootName(LHS); + ConsumeRootName(RHS); + return res; +} + +static int CompareRootDir(PathParser *LHS, PathParser *RHS) { + if (!LHS->inRootDir() && RHS->inRootDir()) + return -1; + else if (LHS->inRootDir() && !RHS->inRootDir()) + return 1; + else { + ConsumeRootDir(LHS); + ConsumeRootDir(RHS); + return 0; + } +} + +static int CompareRelative(PathParser *LHSPtr, PathParser *RHSPtr) { + auto &LHS = *LHSPtr; + auto &RHS = *RHSPtr; + + int res; + while (LHS && RHS) { + if ((res = (*LHS).compare(*RHS)) != 0) + return res; + ++LHS; + ++RHS; + } + return 0; +} + +static int CompareEndState(PathParser *LHS, PathParser *RHS) { + if (LHS->atEnd() && !RHS->atEnd()) + return -1; + else if (!LHS->atEnd() && RHS->atEnd()) + return 1; + return 0; +} + +int path::__compare(string_view_t __s) const { + auto LHS = PathParser::CreateBegin(__pn_); + auto RHS = PathParser::CreateBegin(__s); + int res; + + if ((res = CompareRootName(&LHS, &RHS)) != 0) + return res; + + if ((res = CompareRootDir(&LHS, &RHS)) != 0) + return res; + + if ((res = CompareRelative(&LHS, &RHS)) != 0) + return res; + + return CompareEndState(&LHS, &RHS); +} + +//////////////////////////////////////////////////////////////////////////// +// path.nonmembers +size_t hash_value(const path& __p) noexcept { + auto PP = PathParser::CreateBegin(__p.native()); + size_t hash_value = 0; + hash hasher; + while (PP) { + hash_value = __hash_combine(hash_value, hasher(*PP)); + ++PP; + } + return hash_value; +} + +//////////////////////////////////////////////////////////////////////////// +// path.itr +path::iterator path::begin() const { + auto PP = PathParser::CreateBegin(__pn_); + iterator it; + it.__path_ptr_ = this; + it.__state_ = static_cast(PP.State); + it.__entry_ = PP.RawEntry; + it.__stashed_elem_.__assign_view(*PP); + return it; +} + +path::iterator path::end() const { + iterator it{}; + it.__state_ = path::iterator::_AtEnd; + it.__path_ptr_ = this; + return it; +} + +path::iterator& path::iterator::__increment() { + PathParser PP(__path_ptr_->native(), __entry_, __state_); + ++PP; + __state_ = static_cast<_ParserState>(PP.State); + __entry_ = PP.RawEntry; + __stashed_elem_.__assign_view(*PP); + return *this; +} + +path::iterator& path::iterator::__decrement() { + PathParser PP(__path_ptr_->native(), __entry_, __state_); + --PP; + __state_ = static_cast<_ParserState>(PP.State); + __entry_ = PP.RawEntry; + __stashed_elem_.__assign_view(*PP); + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// +// directory entry definitions +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _LIBCPP_WIN32API +error_code directory_entry::__do_refresh() noexcept { + __data_.__reset(); + error_code failure_ec; + + StatT full_st; + file_status st = detail::posix_lstat(__p_, full_st, &failure_ec); + if (!status_known(st)) { + __data_.__reset(); + return failure_ec; + } + + if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) { + __data_.__cache_type_ = directory_entry::_RefreshNonSymlink; + __data_.__type_ = st.type(); + __data_.__non_sym_perms_ = st.permissions(); + } else { // we have a symlink + __data_.__sym_perms_ = st.permissions(); + // Get the information about the linked entity. + // Ignore errors from stat, since we don't want errors regarding symlink + // resolution to be reported to the user. + error_code ignored_ec; + st = detail::posix_stat(__p_, full_st, &ignored_ec); + + __data_.__type_ = st.type(); + __data_.__non_sym_perms_ = st.permissions(); + + // If we failed to resolve the link, then only partially populate the + // cache. + if (!status_known(st)) { + __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved; + return error_code{}; + } + // Otherwise, we resolved the link, potentially as not existing. + // That's OK. + __data_.__cache_type_ = directory_entry::_RefreshSymlink; + } + + if (_VSTD_FS::is_regular_file(st)) + __data_.__size_ = static_cast(full_st.st_size); + + if (_VSTD_FS::exists(st)) { + __data_.__nlink_ = static_cast(full_st.st_nlink); + + // Attempt to extract the mtime, and fail if it's not representable using + // file_time_type. For now we ignore the error, as we'll report it when + // the value is actually used. + error_code ignored_ec; + __data_.__write_time_ = + __extract_last_write_time(__p_, full_st, &ignored_ec); + } + + return failure_ec; +} +#else +error_code directory_entry::__do_refresh() noexcept { + __data_.__reset(); + error_code failure_ec; + + file_status st = _VSTD_FS::symlink_status(__p_, failure_ec); + if (!status_known(st)) { + __data_.__reset(); + return failure_ec; + } + + if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) { + __data_.__cache_type_ = directory_entry::_RefreshNonSymlink; + __data_.__type_ = st.type(); + __data_.__non_sym_perms_ = st.permissions(); + } else { // we have a symlink + __data_.__sym_perms_ = st.permissions(); + // Get the information about the linked entity. + // Ignore errors from stat, since we don't want errors regarding symlink + // resolution to be reported to the user. + error_code ignored_ec; + st = _VSTD_FS::status(__p_, ignored_ec); + + __data_.__type_ = st.type(); + __data_.__non_sym_perms_ = st.permissions(); + + // If we failed to resolve the link, then only partially populate the + // cache. + if (!status_known(st)) { + __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved; + return error_code{}; + } + __data_.__cache_type_ = directory_entry::_RefreshSymlink; + } + + // FIXME: This is currently broken, and the implementation only a placeholder. + // We need to cache last_write_time, file_size, and hard_link_count here before + // the implementation actually works. + + return failure_ec; +} +#endif + +#ifndef _LIBAUTO_UNDEF_VSTD_FS +#pragma pop_macro("_VSTD_FS") +#else +#undef _VSTD +#undef _LIBAUTO_UNDEF_VSTD_FS +#endif +} // namespace android::hardware::automotive::filesystem +/* clang-format on */ From a7bdc9559a8c989c4d06025fc557a087562c27fb Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Tue, 3 Mar 2020 10:09:03 -0500 Subject: [PATCH 0859/1022] Update Identity Credential HAL docs. This change contains no actual syntactical or semantic changes, just clarifications on the inputs and outputs. Test: N/A Bug: 151082886 Merged-In: I794b8d0360c1eda37b4dbe757d7a7fadcbdda7bc Change-Id: I5ad596ec0fa4dac7473d8fd435f538dbb5529846 --- .../hardware/identity/CipherSuite.aidl | 14 +++-- .../identity/IIdentityCredential.aidl | 61 ++++++++++++++----- .../identity/IIdentityCredentialStore.aidl | 37 ++++++----- .../identity/IWritableIdentityCredential.aidl | 50 +++++++++++++-- .../identity/SecureAccessControlProfile.aidl | 2 +- 5 files changed, 115 insertions(+), 49 deletions(-) diff --git a/identity/aidl/android/hardware/identity/CipherSuite.aidl b/identity/aidl/android/hardware/identity/CipherSuite.aidl index 20b02a8a08..f38134bc10 100644 --- a/identity/aidl/android/hardware/identity/CipherSuite.aidl +++ b/identity/aidl/android/hardware/identity/CipherSuite.aidl @@ -24,13 +24,15 @@ package android.hardware.identity; enum CipherSuite { /** * Specifies that the cipher suite that will be used to secure communications between the reader - * is: + * and the prover is using the following primitives * - * - ECDHE with HKDF-SHA-256 for key agreement. - * - AES-256 with GCM block mode for authenticated encryption (nonces are incremented by - * one for every message). - * - ECDSA with SHA-256 for signing (used for signing session transcripts to defeat - * man-in-the-middle attacks), signing keys are not ephemeral. + * - ECKA-DH (Elliptic Curve Key Agreement Algorithm - Diffie-Hellman, see BSI TR-03111) + * - HKDF-SHA-256 (see RFC 5869) + * - AES-256-GCM (see NIST SP 800-38D) + * - HMAC-SHA-256 (see RFC 2104) + * + * The exact way these primitives are combined to derive the session key is specified in + * section 9.2.1.4 of ISO/IEC 18013-5 (see description of cipher suite '1'). * * At present this is the only supported cipher suite and it is mandatory for all * implementations to support it. diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl index cc142713cd..7d14f03b1f 100644 --- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl +++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl @@ -48,6 +48,8 @@ interface IIdentityCredential { * with the reader. The reason for generating the key pair in the secure environment is so that * the secure environment knows what public key to expect to find in the session transcript. * + * The generated key must be an EC key using the P-256 curve. + * * This method may only be called once per instance. If called more than once, STATUS_FAILED * will be returned. * @@ -61,7 +63,8 @@ interface IIdentityCredential { * This method may only be called once per instance. If called more than once, STATUS_FAILED * will be returned. * - * @param publicKey contains the reader's ephemeral public key, in uncompressed form. + * @param publicKey contains the reader's ephemeral public key, in uncompressed + * form (e.g. 0x04 || X || Y). */ void setReaderEphemeralPublicKey(in byte[] publicKey); @@ -82,9 +85,9 @@ interface IIdentityCredential { * This method be called after createEphemeralKeyPair(), setReaderEphemeralPublicKey(), * createAuthChallenge() and before startRetrieveEntry(). This method call is followed by * multiple calls of startRetrieveEntryValue(), retrieveEntryValue(), and finally - * finishRetrieval().This whole process is called a "credential presentation". + * finishRetrieval(). * - * It is permissible to perform multiple credential presentations using the same instance (e.g. + * It is permissible to perform data retrievals multiple times using the same instance (e.g. * startRetrieval(), then multiple calls of startRetrieveEntryValue(), retrieveEntryValue(), * then finally finishRetrieval()) but if this is done, the sessionTranscript parameter * must be identical for each startRetrieval() invocation. If this is not the case, this call @@ -148,6 +151,8 @@ interface IIdentityCredential { * EReaderKeyBytes = #6.24(bstr .cbor EReaderKey.Pub) * ItemsRequestBytes = #6.24(bstr .cbor ItemsRequest) * + * EReaderKey.Pub = COSE_Key ; Ephemeral public key provided by reader + * * 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 * in 'draft-ietf-cose-x509-04'). There will be at least one certificate in said element @@ -220,13 +225,11 @@ interface IIdentityCredential { * * It is permissible to keep retrieving values if an access control check fails. * - * @param nameSpace is the namespace of the element, e.g. "org.iso.18013" + * @param nameSpace is the namespace of the element, e.g. "org.iso.18013.5.1" * - * @param name is the name of the element. + * @param name is the name of the element, e.g. "driving_privileges". * - * @param entrySize is the size of the entry value, if it's a text string or a byte string. - * It must be zero if the entry value is an integer or boolean. If this requirement - * is not met the call fails with STATUS_INVALID_DATA. + * @param entrySize is the size of the entry value encoded in CBOR. * * @param accessControlProfileIds specifies the set of access control profiles that can * authorize access to the provisioned element. If an identifier of a profile @@ -260,14 +263,12 @@ 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. - * The key used for the MAC operation is EMacKey and is derived as follows: - * - * KDF(ECDH(SDeviceKey.Priv, EReaderKey.Pub)) - * - * where SDeviceKey.Priv is the key identified by signingKeyBlob. The KDF - * and ECDH functions shall be the same as the ciphersuite selected and - * passed to IIdentityStore.getCredential(). The EMacKey shall be derived - * using a salt of 0x00. + * 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) + * key, then using the MAC function from the ciphersuite to compute a MAC of + * the authenticated data. See section 9.2.3.5 of ISO/IEC 18013-5 for details + * of this operation. * * DeviceAuthentication = [ * "DeviceAuthentication", @@ -308,6 +309,34 @@ interface IIdentityCredential { /** * Generate a key pair to be used for signing session data and retrieved data items. * + * The generated key must be an EC key using the P-256 curve. + * + * This method shall return just a single X.509 certificate which is signed by CredentialKey. + * When combined with the certificate chain returned at provisioning time by + * getAttestationCertificate() on IWritableIdentityCredential (for the credential key), this + * forms a chain all the way from the root of trust to the generated key. + * + * The public part of a signing key is usually included in issuer-signed data and is + * used for anti-cloning purposes or as a mechanism for the issuer to attest to data + * generated on the device. + * + * 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 Authentication Key". + * + * - issuer: shall be set to "credentialStoreName (credentialStoreAuthorName)" using the + * values returned in HardwareInformation. + * + * - validity: should be from current time and one year in the future. + * + * - subjectPublicKeyInfo: must contain attested public key. + * * @param out signingKeyBlob contains an encrypted copy of the newly-generated private * signing key. * diff --git a/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl b/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl index 23cb1b75a2..bd664e86ea 100644 --- a/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl +++ b/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl @@ -55,8 +55,8 @@ import android.hardware.identity.CipherSuite; * * - For each namespase, a set of name/value pairs, each with an associated set of access control * profile IDs. Names are UTF-8 strings of up to 256 bytes in length (most should be much - * shorter). Values stored must be encoed as valid CBOR (https://tools.ietf.org/html/rfc7049) and - * the encoeded size is is limited to at most 512 KiB. + * shorter). Values stored must be encoded as CBOR (https://tools.ietf.org/html/rfc7049) and + * the encoded size is is limited to at most 512 KiB. * * - A set of access control profiles, each with a profile ID and a specification of the * conditions which satisfy the profile's requirements. @@ -108,12 +108,13 @@ import android.hardware.identity.CipherSuite; @VintfStability interface IIdentityCredentialStore { /** - * Success. + * Success. This is never returned but included for completeness and for use by code + * using these statuses for internal use. */ const int STATUS_OK = 0; /** - * The operation failed. This is used as a generic catch-all for errors that don't belong + * The operation failed. This is used as a generic catch-all for errors that don't belong * in other categories, including memory/resource allocation failures and I/O errors. */ const int STATUS_FAILED = 1; @@ -124,7 +125,7 @@ interface IIdentityCredentialStore { const int STATUS_CIPHER_SUITE_NOT_SUPPORTED = 2; /** - * The passed data was invalid. This is a generic catch all for errors that don't belong + * The passed data was invalid. This is a generic catch all for errors that don't belong * in other categories related to parameter validation. */ const int STATUS_INVALID_DATA = 3; @@ -186,16 +187,19 @@ interface IIdentityCredentialStore { HardwareInformation getHardwareInformation(); /** - * createCredential creates a new Credential. When a Credential is created, two cryptographic + * createCredential creates a new credential. When a credential is created, two cryptographic * keys are created: StorageKey, an AES key used to secure the externalized Credential - * contents, and CredentialKeyPair, an EC key pair used to authenticate the store to the IA. In - * addition, all of the Credential data content is imported and a certificate for the - * CredentialKeyPair and a signature produced with the CredentialKeyPair are created. These + * contents, and CredentialKey, an EC key pair used to authenticate the store to the IA. + * + * CredentialKey must be an EC key using the P-256 curve. + * + * In addition, all of the Credential data content is imported and a certificate for the + * CredentialKey and a signature produced with the CredentialKey are created. These * latter values may be checked by an issuing authority to verify that the data was imported * into secure hardware and that it was imported unmodified. * * @param docType is an optional name (may be an empty string) that identifies the type of - * credential being created, e.g. "org.iso.18013-5.2019.mdl" (the doc type of the ISO + * credential being created, e.g. "org.iso.18013.5.1.mDL" (the doc type of the ISO * driving license standard). * * @param testCredential indicates if this is a test store. Test credentials must use an @@ -213,15 +217,8 @@ interface IIdentityCredentialStore { * Credential. * * The cipher suite used to communicate with the remote verifier must also be specified. Currently - * only a single cipher-suite is supported and the details of this are as follow: - * - * - ECDHE with HKDF-SHA-256 for key agreement. - * - AES-256 with GCM block mode for authenticated encryption (nonces are incremented by one - * for every message). - * - ECDSA with SHA-256 for signing (used for signing session transcripts to defeat - * man-in-the-middle attacks), signing keys are not ephemeral. - * - * Support for other cipher suites may be added in a future version of this HAL. + * only a single cipher-suite is supported. Support for other cipher suites may be added in a + * future version of this HAL. * * This method fails with STATUS_INVALID_DATA if the passed in credentialData cannot be * decoded or decrypted. @@ -233,7 +230,7 @@ interface IIdentityCredentialStore { * return argument of the same name in finishAddingEntries(), in * IWritableIdentityCredential. * - * @return an IIdentityCredential HIDL interface that provides operations on the Credential. + * @return an IIdentityCredential interface that provides operations on the Credential. */ IIdentityCredential getCredential(in CipherSuite cipherSuite, in byte[] credentialData); } diff --git a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl index 483b0c7b6b..9673821b82 100644 --- a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl +++ b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl @@ -60,12 +60,50 @@ interface IWritableIdentityCredential { * attestationApplicationId. * * - The teeEnforced field in the attestation extension must include - * Tag::IDENTITY_CREDENTIAL_KEY. This tag indicates that the key is an Identity - * Credential key (which can only sign/MAC very specific messages) and not an Android - * Keystore key (which can be used to sign/MAC anything). + * + * - Tag::IDENTITY_CREDENTIAL_KEY which indicates that the key is an Identity + * Credential key (which can only sign/MAC very specific messages) and not an Android + * Keystore key (which can be used to sign/MAC anything). + * + * - Tag::PURPOSE must be set to SIGN + * + * - Tag::KEY_SIZE must be set to the appropriate key size, in bits (e.g. 256) + * + * - Tag::ALGORITHM must be set to EC + * + * - Tag::NO_AUTH_REQUIRED must be set + * + * - Tag::DIGEST must be set to SHA_2_256 + * + * - Tag::EC_CURVE must be set to P_256 * * Additional authorizations may be needed in the softwareEnforced and teeEnforced - * fields - the above is not an exhaustive list. + * fields - the above is not an exhaustive list. Specifically, authorizations containing + * information about the root of trust, OS version, verified boot state, and so on should + * be included. + * + * Since the chain is required to be generated using Keymaster Attestation, the returned + * certificate chain has the following properties: + * + * - The certificate chain is of at least length three. + * + * - The root of trust is the same as for Keymaster Attestation. This is usually + * a certificate owned by Google but depending on the specific Android device it may + * be another certificate. + * + * As with any user of attestation, the Issuing Authority (as a relying party) wishing + * to issue a credential to a device using these APIs, must carefully examine the + * returned certificate chain for all of the above (and more). In particular, the Issuing + * Authority should check the root of trust, verified boot state, patch level, + * application id, etc. + * + * This all depends on the needs of the Issuing Authority and the kind of credential but + * in general an Issuing Authority should never issue a credential to a device without + * verified boot enabled, to an unrecognized application, or if it appears the device + * hasn't been updated for a long time. + * + * See https://github.com/google/android-key-attestation for an example of how to + * examine attestations generated from Android devices. * * @param attestationApplicationId is the DER encoded value to be stored * in Tag::ATTESTATION_APPLICATION_ID. This schema is described in @@ -105,7 +143,7 @@ interface IWritableIdentityCredential { * be used to reference the profile. If this is not satisfied the call fails with * STATUS_INVALID_DATA. * - * @param readerCertificate if non-empty, specifies a X.509 certificate (or chain of + * @param readerCertificate if non-empty, specifies a single X.509 certificate (not a chain of * certificates) that must be used to authenticate requests (see the readerSignature * parameter in IIdentityCredential.startRetrieval). * @@ -142,7 +180,7 @@ interface IWritableIdentityCredential { * @param accessControlProfileIds specifies the set of access control profiles that can * authorize access to the provisioned element. * - * @param nameSpace is the namespace of the element, e.g. "org.iso.18013" + * @param nameSpace is the namespace of the element, e.g. "org.iso.18013.5.1" * * @param name is the name of the element. * diff --git a/identity/aidl/android/hardware/identity/SecureAccessControlProfile.aidl b/identity/aidl/android/hardware/identity/SecureAccessControlProfile.aidl index 01d312d3e6..13f0c6d431 100644 --- a/identity/aidl/android/hardware/identity/SecureAccessControlProfile.aidl +++ b/identity/aidl/android/hardware/identity/SecureAccessControlProfile.aidl @@ -29,7 +29,7 @@ parcelable SecureAccessControlProfile { /** * readerCertificate, if non-empty, specifies a single X.509 certificate (not a chain * of certificates) that must be used to authenticate requests. For details about how - * this is done, see the readerSignature paremter of IIdentityCredential.startRetrieval. + * this is done, see the readerSignature parameter of IIdentityCredential.startRetrieval. */ Certificate readerCertificate; From a653616f182f203093c7fd0da1d5482cf6c909fc Mon Sep 17 00:00:00 2001 From: Calvin Huang Date: Mon, 20 Apr 2020 12:41:20 -0700 Subject: [PATCH 0860/1022] Add manifest to vintf fragments Bug: 153734354 Test: Manual Change-Id: I5f29cdacced0bdc0bf5a74f92ecda916f10bea06 --- automotive/vehicle/2.0/default/Android.bp | 3 +++ .../android.hardware.automotive.vehicle@2.0-service.xml} | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) rename automotive/vehicle/2.0/{manifest.vehicle.xml => default/android.hardware.automotive.vehicle@2.0-service.xml} (83%) diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp index e529675203..21b410a080 100644 --- a/automotive/vehicle/2.0/default/Android.bp +++ b/automotive/vehicle/2.0/default/Android.bp @@ -125,6 +125,9 @@ cc_test { cc_binary { name: "android.hardware.automotive.vehicle@2.0-service", defaults: ["vhal_v2_0_defaults"], + vintf_fragments: [ + "android.hardware.automotive.vehicle@2.0-service.xml", + ], init_rc: ["android.hardware.automotive.vehicle@2.0-service.rc"], vendor: true, relative_install_path: "hw", diff --git a/automotive/vehicle/2.0/manifest.vehicle.xml b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.xml similarity index 83% rename from automotive/vehicle/2.0/manifest.vehicle.xml rename to automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.xml index 832b302dfa..660b03d9cf 100644 --- a/automotive/vehicle/2.0/manifest.vehicle.xml +++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.xml @@ -1,4 +1,4 @@ - + android.hardware.automotive.vehicle hwbinder From 70cf06e1c634028ae47a7d626864ee9f8d3e2b63 Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Tue, 21 Apr 2020 22:49:19 +0000 Subject: [PATCH 0861/1022] Add biometrics.fingerprint@2.2 to the current matrix This HIDL was added to compatibility_matrix.5 in I209db8a74665df98b4923cbfa11b2b2c9d6dabfa Bug: 153012763 Test: build blueline-userdebug Change-Id: I360c192992b63967c76227d6c47e9a52662aeae7 --- compatibility_matrices/compatibility_matrix.current.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 2b1979322a..41a7d0bb76 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -94,7 +94,7 @@ android.hardware.biometrics.fingerprint - 2.1 + 2.1-2 IBiometricsFingerprint default From c6e69bde302b5c45fe5dd0b8a1e7e9e152d1a0ee Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Tue, 21 Apr 2020 16:23:45 -0700 Subject: [PATCH 0862/1022] Rename vts-core to vts Bug: 151896491 Bug: 139438327 Test: local build Change-Id: Ida36f4e10bbdd72f58039f8ee5ae6f61edac4769 Merged-In: Id542b54ba2da1fca03a9c44bf05d0f68793445cf --- bluetooth/a2dp/1.0/vts/functional/Android.bp | 2 +- media/omx/1.0/vts/functional/audio/Android.bp | 4 ++-- media/omx/1.0/vts/functional/component/Android.bp | 2 +- media/omx/1.0/vts/functional/master/Android.bp | 2 +- media/omx/1.0/vts/functional/video/Android.bp | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bluetooth/a2dp/1.0/vts/functional/Android.bp b/bluetooth/a2dp/1.0/vts/functional/Android.bp index 5b8410adc5..df18fcc7c5 100644 --- a/bluetooth/a2dp/1.0/vts/functional/Android.bp +++ b/bluetooth/a2dp/1.0/vts/functional/Android.bp @@ -23,5 +23,5 @@ cc_test { "android.hardware.bluetooth.a2dp@1.0", "libbluetooth-types", ], - test_suites: ["general-tests", "vts-core"], + test_suites: ["general-tests", "vts"], } diff --git a/media/omx/1.0/vts/functional/audio/Android.bp b/media/omx/1.0/vts/functional/audio/Android.bp index 532521e0fe..ec7357cb3d 100644 --- a/media/omx/1.0/vts/functional/audio/Android.bp +++ b/media/omx/1.0/vts/functional/audio/Android.bp @@ -25,7 +25,7 @@ cc_test { data: [":media_omx_audio_res"], test_config: "VtsHalMediaOmxV1_0TargetAudioEncTest.xml", test_suites: [ - "vts-core", + "vts", ], } @@ -40,6 +40,6 @@ cc_test { data: [":media_omx_audio_res"], test_config: "VtsHalMediaOmxV1_0TargetAudioDecTest.xml", test_suites: [ - "vts-core", + "vts", ], } diff --git a/media/omx/1.0/vts/functional/component/Android.bp b/media/omx/1.0/vts/functional/component/Android.bp index c7be2cc8d9..8fb627ad42 100644 --- a/media/omx/1.0/vts/functional/component/Android.bp +++ b/media/omx/1.0/vts/functional/component/Android.bp @@ -19,6 +19,6 @@ cc_test { defaults: ["VtsHalMediaOmxV1_0Defaults"], srcs: ["VtsHalMediaOmxV1_0TargetComponentTest.cpp"], test_suites: [ - "vts-core", + "vts", ], } diff --git a/media/omx/1.0/vts/functional/master/Android.bp b/media/omx/1.0/vts/functional/master/Android.bp index 0eb2cc998d..8e58821e12 100644 --- a/media/omx/1.0/vts/functional/master/Android.bp +++ b/media/omx/1.0/vts/functional/master/Android.bp @@ -19,6 +19,6 @@ cc_test { defaults: ["VtsHalMediaOmxV1_0Defaults"], srcs: ["VtsHalMediaOmxV1_0TargetMasterTest.cpp"], test_suites: [ - "vts-core", + "vts", ], } diff --git a/media/omx/1.0/vts/functional/video/Android.bp b/media/omx/1.0/vts/functional/video/Android.bp index 7e93faa261..b35c26c0f3 100644 --- a/media/omx/1.0/vts/functional/video/Android.bp +++ b/media/omx/1.0/vts/functional/video/Android.bp @@ -25,7 +25,7 @@ cc_test { data: [":media_omx_video_res"], test_config: "VtsHalMediaOmxV1_0TargetVideoDecTest.xml", test_suites: [ - "vts-core", + "vts", ], } @@ -43,6 +43,6 @@ cc_test { data: [":media_omx_video_res"], test_config: "VtsHalMediaOmxV1_0TargetVideoEncTest.xml", test_suites: [ - "vts-core", + "vts", ], } From 5d531a26c02b8f411ab896b536828580a2f2205a Mon Sep 17 00:00:00 2001 From: nagendra modadugu Date: Tue, 31 Mar 2020 15:55:01 -0700 Subject: [PATCH 0863/1022] Fix StrongBoxOnly test This test is expected to be run on non-StrongBox instances. Bug: 129282228 Test: StrongBoxOnly passes on TZ Change-Id: Ia6b274d097b4c698904d1c51daed821188a50510 --- keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp index 7ea3275851..2af7775dea 100644 --- a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp +++ b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp @@ -155,8 +155,8 @@ void check_attestation_record(AttestationRecord attestation, const HidlBuf& chal using std::string; using DeviceUniqueAttestationTest = Keymaster4_1HidlTest; -TEST_P(DeviceUniqueAttestationTest, StrongBoxOnly) { - if (SecLevel() != SecurityLevel::STRONGBOX) return; +TEST_P(DeviceUniqueAttestationTest, NonStrongBoxOnly) { + if (SecLevel() == SecurityLevel::STRONGBOX) return; ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder() .Authorization(TAG_NO_AUTH_REQUIRED) From eb7f3527de4369d9a3712883f03254e428d0b328 Mon Sep 17 00:00:00 2001 From: nagendra modadugu Date: Wed, 1 Apr 2020 02:40:59 -0700 Subject: [PATCH 0864/1022] Round off attestation tests. This CL needs some polish. Changes herein are somewhat brute-force to make things work, particularly with authorization-list parsing and validation. This CL also copies over support for dumping attestation records. Bug: 129282228 Test: VtsHalKeymasterV4_1TargetTest Change-Id: I4fc0183dc0b8a76e84d14054b38ad7c1540a1897 --- keymaster/4.1/support/attestation_record.cpp | 4 + .../DeviceUniqueAttestationTest.cpp | 97 +++++++++++++------ 2 files changed, 73 insertions(+), 28 deletions(-) diff --git a/keymaster/4.1/support/attestation_record.cpp b/keymaster/4.1/support/attestation_record.cpp index 63bf854f0f..598b6b50c4 100644 --- a/keymaster/4.1/support/attestation_record.cpp +++ b/keymaster/4.1/support/attestation_record.cpp @@ -296,6 +296,10 @@ MAKE_OPENSSL_PTR_TYPE(KM_KEY_DESCRIPTION) std::tuple parse_attestation_record(const hidl_vec& cert) { const uint8_t* p = cert.data(); X509_Ptr x509(d2i_X509(nullptr, &p, cert.size())); + if (!x509.get()) { + LOG(ERROR) << "Error converting DER"; + return {ErrorCode::INVALID_ARGUMENT, {}}; + } ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */)); if (!oid.get()) { diff --git a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp index 2af7775dea..495de0f97d 100644 --- a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp +++ b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +#define LOG_TAG "keymaster_hidl_hal_test" +#include + #include "Keymaster4_1HidlTest.h" #include @@ -23,6 +26,10 @@ #include #include +// Not to dump the attestation by default. Can enable by specify the parameter +// "--dump_attestations" on lunching VTS +static bool dumpAttestations = false; + namespace android::hardware::keymaster::V4_0 { bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) { @@ -57,6 +64,10 @@ string bin2hex(const hidl_vec& data) { return retval; } +inline void dumpContent(string content) { + std::cout << content << std::endl; +} + struct AuthorizationSetDifferences { string aName; string bName; @@ -126,6 +137,23 @@ void check_root_of_trust(const RootOfTrust& root_of_trust) { } } +bool tag_in_list(const KeyParameter& entry) { + // Attestations don't contain everything in key authorization lists, so we need to filter + // the key lists to produce the lists that we expect to match the attestations. + auto tag_list = { + Tag::INCLUDE_UNIQUE_ID, Tag::BLOB_USAGE_REQUIREMENTS, Tag::EC_CURVE, + Tag::HARDWARE_TYPE, Tag::VENDOR_PATCHLEVEL, Tag::BOOT_PATCHLEVEL, + Tag::CREATION_DATETIME, + }; + return std::find(tag_list.begin(), tag_list.end(), (V4_1::Tag)entry.tag) != tag_list.end(); +} + +AuthorizationSet filter_tags(const AuthorizationSet& set) { + AuthorizationSet filtered; + std::remove_copy_if(set.begin(), set.end(), std::back_inserter(filtered), tag_in_list); + return filtered; +} + void check_attestation_record(AttestationRecord attestation, const HidlBuf& challenge, AuthorizationSet expected_sw_enforced, AuthorizationSet expected_hw_enforced, @@ -144,9 +172,9 @@ void check_attestation_record(AttestationRecord attestation, const HidlBuf& chal attestation.software_enforced.Sort(); attestation.hardware_enforced.Sort(); - EXPECT_EQ(expected_sw_enforced, attestation.software_enforced) + EXPECT_EQ(filter_tags(expected_sw_enforced), filter_tags(attestation.software_enforced)) << DIFFERENCE(expected_sw_enforced, attestation.software_enforced); - EXPECT_EQ(expected_hw_enforced, attestation.hardware_enforced) + EXPECT_EQ(filter_tags(expected_hw_enforced), filter_tags(attestation.hardware_enforced)) << DIFFERENCE(expected_hw_enforced, attestation.hardware_enforced); } @@ -193,11 +221,11 @@ TEST_P(DeviceUniqueAttestationTest, Rsa) { if (SecLevel() != SecurityLevel::STRONGBOX) return; ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder() - .Authorization(TAG_NO_AUTH_REQUIRED) - .RsaSigningKey(2048, 65537) - .Digest(Digest::SHA_2_256) - .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN) - .Authorization(TAG_CREATION_DATETIME, 1)))); + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(2048, 65537) + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN) + .Authorization(TAG_INCLUDE_UNIQUE_ID)))); hidl_vec> cert_chain; HidlBuf challenge("challenge"); @@ -209,14 +237,14 @@ TEST_P(DeviceUniqueAttestationTest, Rsa) { .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id), &cert_chain))); - EXPECT_EQ(1U, cert_chain.size()); + EXPECT_EQ(2U, cert_chain.size()); + if (dumpAttestations) dumpContent(bin2hex(cert_chain[0])); auto [err, attestation] = parse_attestation_record(cert_chain[0]); - EXPECT_EQ(ErrorCode::OK, err); + ASSERT_EQ(ErrorCode::OK, err); check_attestation_record(attestation, challenge, /* sw_enforced */ AuthorizationSetBuilder() - .Authorization(TAG_CREATION_DATETIME, 1) .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id), /* hw_enforced */ AuthorizationSetBuilder() @@ -238,7 +266,7 @@ TEST_P(DeviceUniqueAttestationTest, Ecdsa) { .Authorization(TAG_NO_AUTH_REQUIRED) .EcdsaSigningKey(256) .Digest(Digest::SHA_2_256) - .Authorization(TAG_CREATION_DATETIME, 1)))); + .Authorization(TAG_INCLUDE_UNIQUE_ID)))); hidl_vec> cert_chain; HidlBuf challenge("challenge"); @@ -250,29 +278,42 @@ TEST_P(DeviceUniqueAttestationTest, Ecdsa) { .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id), &cert_chain))); - EXPECT_EQ(1U, cert_chain.size()); + EXPECT_EQ(2U, cert_chain.size()); + if (dumpAttestations) dumpContent(bin2hex(cert_chain[0])); auto [err, attestation] = parse_attestation_record(cert_chain[0]); - EXPECT_EQ(ErrorCode::OK, err); + ASSERT_EQ(ErrorCode::OK, err); check_attestation_record(attestation, challenge, - /* sw_enforced */ - AuthorizationSetBuilder() - .Authorization(TAG_CREATION_DATETIME, 1) - .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id), - /* hw_enforced */ - AuthorizationSetBuilder() - .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION) - .Authorization(TAG_NO_AUTH_REQUIRED) - .EcdsaSigningKey(256) - .Digest(Digest::SHA_2_256) - .Authorization(TAG_EC_CURVE, EcCurve::P_256) - .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED) - .Authorization(TAG_OS_VERSION, os_version()) - .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()), - SecLevel()); + /* sw_enforced */ + AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id), + /* hw_enforced */ + AuthorizationSetBuilder() + .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION) + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(256) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_EC_CURVE, EcCurve::P_256) + .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED) + .Authorization(TAG_OS_VERSION, os_version()) + .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()), + SecLevel()); } INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(DeviceUniqueAttestationTest); } // namespace test } // namespace android::hardware::keymaster::V4_1 + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + for (int i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + if (std::string(argv[i]) == "--dump_attestations") { + dumpAttestations = true; + } + } + } + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +} From 7faa170ff1edc3526b92c1caba126bb83b33bb6a Mon Sep 17 00:00:00 2001 From: Jordan Jozwiak Date: Wed, 22 Apr 2020 14:04:32 -0700 Subject: [PATCH 0865/1022] Add config for tire pressure display units Bug: 154751939 Test: aae app vhal apply google // verify property included in dump adb -s c3139966 shell dumpsys activity service com.android.car get-carpropertyconfig | grep TIRE_PRESSURE_DISPLAY_UNITS -A5 Change-Id: Id7a3ad7351db5a4f03ab3a29fa06e9c82321a44e --- .../vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h | 10 ++++++++++ 1 file changed, 10 insertions(+) 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 ea759867f2..bad9ffe9ff 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 @@ -437,6 +437,16 @@ const ConfigDeclaration kVehicleProperties[]{ }, .initialValue = {.floatValues = {200.0f}}}, // units in kPa + {.config = + { + .prop = toInt(VehicleProperty::TIRE_PRESSURE_DISPLAY_UNITS), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {(int)VehicleUnit::KILOPASCAL, (int)VehicleUnit::PSI, + (int)VehicleUnit::BAR}, + }, + .initialValue = {.int32Values = {toInt(VehicleUnit::PSI)}}}, + {.config = { .prop = toInt(VehicleProperty::CURRENT_GEAR), From 957857f19de2a99062b949501b30b48a77e2ac5e Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Tue, 21 Apr 2020 18:09:02 -0700 Subject: [PATCH 0866/1022] power: fix TryDifferentGovernors test Switch to std::string and libbase to simplify the test and avoid string manipulation bugs Bug: 154070740 Bug: 149044096 Test: atest VtsHalPowerV1_0TargetTest Change-Id: Ic80ca462cfeb650edcdc6420bf1b3190aa14dbe4 Signed-off-by: Connor O'Brien --- .../functional/VtsHalPowerV1_0TargetTest.cpp | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp b/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp index ba08ee733f..7e0ae9c37f 100644 --- a/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp +++ b/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp @@ -19,6 +19,8 @@ #include +#include +#include #include #include #include @@ -73,26 +75,16 @@ TEST_P(PowerHidlTest, SetInteractive) { TEST_P(PowerHidlTest, TryDifferentGovernors) { Return ret; - unique_fd fd1(open(CPU_GOVERNOR_PATH, O_RDWR)); - unique_fd fd2(open(AVAILABLE_GOVERNORS_PATH, O_RDONLY)); - if (fd1 < 0 || fd2 < 0) { + std::string old_governor, governors; + if (!android::base::ReadFileToString(CPU_GOVERNOR_PATH, &old_governor) || + !android::base::ReadFileToString(AVAILABLE_GOVERNORS_PATH, &governors)) { // Files don't exist, so skip the rest of the test case SUCCEED(); return; } - - char old_governor[80]; - ASSERT_LE(0, read(fd1, old_governor, 80)); - - char governors[1024]; - unsigned len = read(fd2, governors, 1024); - ASSERT_LE(0u, len); - governors[len] = '\0'; - - char *saveptr; - char *name = strtok_r(governors, " \n", &saveptr); - while (name) { - ASSERT_LE(0, write(fd1, name, strlen(name))); + auto all_governors = android::base::Split(governors, " \n"); + for (const auto &governor : all_governors) { + ASSERT_TRUE(android::base::WriteStringToFile(governor, CPU_GOVERNOR_PATH)); ret = power->setInteractive(true); ASSERT_TRUE(ret.isOk()); @@ -104,11 +96,9 @@ TEST_P(PowerHidlTest, TryDifferentGovernors) { power->powerHint(PowerHint::LAUNCH, 1); power->powerHint(PowerHint::LAUNCH, 0); - - name = strtok_r(NULL, " \n", &saveptr); } - ASSERT_LE(0, write(fd1, old_governor, strlen(old_governor))); + ASSERT_TRUE(android::base::WriteStringToFile(old_governor, CPU_GOVERNOR_PATH)); } // Sanity check Power::powerHint on good and bad inputs. From fd882510f30eda4acf7601db142b559bb07d19b1 Mon Sep 17 00:00:00 2001 From: shubang Date: Wed, 22 Apr 2020 14:59:03 -0700 Subject: [PATCH 0867/1022] Add Lnbs for CTS Bug: 150952758 Test: atest android.media.tv.tuner.cts.TunerTest Change-Id: I0e1954ceaa93c110dabc669759675834f30b9524 --- tv/tuner/1.0/default/Lnb.cpp | 9 ++++++++- tv/tuner/1.0/default/Lnb.h | 6 +++++- tv/tuner/1.0/default/Tuner.cpp | 17 ++++++++++++++--- tv/tuner/1.0/default/Tuner.h | 2 ++ 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/tv/tuner/1.0/default/Lnb.cpp b/tv/tuner/1.0/default/Lnb.cpp index 51931d67fe..6025339ba7 100644 --- a/tv/tuner/1.0/default/Lnb.cpp +++ b/tv/tuner/1.0/default/Lnb.cpp @@ -27,6 +27,9 @@ namespace V1_0 { namespace implementation { Lnb::Lnb() {} +Lnb::Lnb(int id) { + mId = id; +} Lnb::~Lnb() {} @@ -66,9 +69,13 @@ Return Lnb::close() { return Result::SUCCESS; } +int Lnb::getId() { + return mId; +} + } // namespace implementation } // namespace V1_0 } // namespace tuner } // namespace tv } // namespace hardware -} // namespace android \ No newline at end of file +} // namespace android diff --git a/tv/tuner/1.0/default/Lnb.h b/tv/tuner/1.0/default/Lnb.h index f285cb9e65..1e97214430 100644 --- a/tv/tuner/1.0/default/Lnb.h +++ b/tv/tuner/1.0/default/Lnb.h @@ -38,6 +38,7 @@ using ::android::hardware::tv::tuner::V1_0::Result; class Lnb : public ILnb { public: Lnb(); + Lnb(int id); virtual Return setCallback(const sp& callback) override; @@ -51,7 +52,10 @@ class Lnb : public ILnb { virtual Return close() override; + int getId(); + private: + int mId; virtual ~Lnb(); }; @@ -62,4 +66,4 @@ class Lnb : public ILnb { } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_LNB_H_ \ No newline at end of file +#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_LNB_H_ diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp index e39333ce3e..27a67bf6fe 100644 --- a/tv/tuner/1.0/default/Tuner.cpp +++ b/tv/tuner/1.0/default/Tuner.cpp @@ -88,6 +88,10 @@ Tuner::Tuner() { caps = FrontendInfo::FrontendCapabilities(); caps.atscCaps(FrontendAtscCapabilities()); mFrontendCaps[7] = caps; + + mLnbs.resize(2); + mLnbs[0] = new Lnb(0); + mLnbs[1] = new Lnb(1); } Tuner::~Tuner() {} @@ -194,17 +198,24 @@ Return Tuner::getLnbIds(getLnbIds_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); vector lnbIds; + lnbIds.resize(mLnbs.size()); + for (int i = 0; i < lnbIds.size(); i++) { + lnbIds[i] = mLnbs[i]->getId(); + } _hidl_cb(Result::SUCCESS, lnbIds); return Void(); } -Return Tuner::openLnbById(LnbId /* lnbId */, openLnbById_cb _hidl_cb) { +Return Tuner::openLnbById(LnbId lnbId, openLnbById_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); - sp lnb = new Lnb(); + if (lnbId >= mLnbs.size()) { + _hidl_cb(Result::INVALID_ARGUMENT, nullptr); + return Void(); + } - _hidl_cb(Result::SUCCESS, lnb); + _hidl_cb(Result::SUCCESS, mLnbs[lnbId]); return Void(); } diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h index d17b5aeb64..3f2d60d7b4 100644 --- a/tv/tuner/1.0/default/Tuner.h +++ b/tv/tuner/1.0/default/Tuner.h @@ -21,6 +21,7 @@ #include #include "Demux.h" #include "Frontend.h" +#include "Lnb.h" using namespace std; @@ -76,6 +77,7 @@ class Tuner : public ITuner { // The last used demux id. Initial value is -1. // First used id will be 0. int mLastUsedId = -1; + vector> mLnbs; }; } // namespace implementation From edded5fa08d78cc114318801068fa4a5d6a9905a Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 23 Apr 2020 09:49:04 +0800 Subject: [PATCH 0868/1022] Add owner to secure element vts test Bug: 154772240 Test: N/A Exempt-From-Owner-Approval: test owner is not added Change-Id: I87df98366b07ac26b971d80b27f8f600783d74d0 --- secure_element/1.0/vts/OWNERS | 4 ++++ secure_element/1.1/vts/OWNERS | 4 ++++ secure_element/1.2/vts/OWNERS | 4 ++++ 3 files changed, 12 insertions(+) create mode 100644 secure_element/1.0/vts/OWNERS create mode 100644 secure_element/1.1/vts/OWNERS create mode 100644 secure_element/1.2/vts/OWNERS diff --git a/secure_element/1.0/vts/OWNERS b/secure_element/1.0/vts/OWNERS new file mode 100644 index 0000000000..c7963e7fd3 --- /dev/null +++ b/secure_element/1.0/vts/OWNERS @@ -0,0 +1,4 @@ +alisher@google.com +jackcwyu@google.com +georgekgchang@google.com +zachoverflow@google.com diff --git a/secure_element/1.1/vts/OWNERS b/secure_element/1.1/vts/OWNERS new file mode 100644 index 0000000000..c7963e7fd3 --- /dev/null +++ b/secure_element/1.1/vts/OWNERS @@ -0,0 +1,4 @@ +alisher@google.com +jackcwyu@google.com +georgekgchang@google.com +zachoverflow@google.com diff --git a/secure_element/1.2/vts/OWNERS b/secure_element/1.2/vts/OWNERS new file mode 100644 index 0000000000..c7963e7fd3 --- /dev/null +++ b/secure_element/1.2/vts/OWNERS @@ -0,0 +1,4 @@ +alisher@google.com +jackcwyu@google.com +georgekgchang@google.com +zachoverflow@google.com From af249dbc1f84823dde55793937ebb0e7a783a1aa Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 21 Apr 2020 18:03:43 +0800 Subject: [PATCH 0869/1022] Update VtsHalSecureElementV1_2TargetTest When calling se reset, connected state should be reported with false and then true. Bug: 154572079 Test: run vts -m VtsHalSecureElementV1_2TargetTest Change-Id: I907d32a2c44230b581680d1872c9b01e517a5d81 --- .../1.2/vts/functional/VtsHalSecureElementV1_2TargetTest.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/secure_element/1.2/vts/functional/VtsHalSecureElementV1_2TargetTest.cpp b/secure_element/1.2/vts/functional/VtsHalSecureElementV1_2TargetTest.cpp index 98e45021d9..9392f1438e 100644 --- a/secure_element/1.2/vts/functional/VtsHalSecureElementV1_2TargetTest.cpp +++ b/secure_element/1.2/vts/functional/VtsHalSecureElementV1_2TargetTest.cpp @@ -85,6 +85,7 @@ class SecureElementHidlTest : public ::testing::TestWithParam { * Reset: * Calls reset() * Checks status + * Check onStateChange is received with connected state set to false * Check onStateChange is received with connected state set to true */ TEST_P(SecureElementHidlTest, Reset) { @@ -92,6 +93,10 @@ TEST_P(SecureElementHidlTest, Reset) { auto res = se_cb_->WaitForCallback(kCallbackNameOnStateChange); EXPECT_TRUE(res.no_timeout); + EXPECT_FALSE(res.args->state_); + + res = se_cb_->WaitForCallback(kCallbackNameOnStateChange); + EXPECT_TRUE(res.no_timeout); EXPECT_TRUE(res.args->state_); } From 67664dfaccf4b5995d5e368c67f5f2557f3e27ef Mon Sep 17 00:00:00 2001 From: felipeal Date: Thu, 23 Apr 2020 12:53:10 -0700 Subject: [PATCH 0870/1022] Add support to USER_IDENTIFICATION_ASSOCIATION_PROPERTY. Test: adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default --set 299896587 i 1 i 1 i 2 Test: adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default --get 299896587 Bug: 150409351 Change-Id: I5f05c1689abdeeffd1abcd0e85fd01b584501a2e --- .../vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h | 8 ++++++++ 1 file changed, 8 insertions(+) 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 ea759867f2..a4ea7cf771 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 @@ -1028,6 +1028,14 @@ const ConfigDeclaration kVehicleProperties[]{ .changeMode = VehiclePropertyChangeMode::ON_CHANGE, }, }, + { + .config = + { + .prop = toInt(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + }, }; } // impl From 0fd963cad8e723ac9a6555a79f218214bf7deb76 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 22 Apr 2020 09:59:13 -0700 Subject: [PATCH 0871/1022] Minor corrections on USER_SWITCH documentation. Also removed the hash check on Vehicle HAL files, as they're still being worked on. Test: m Bug: 15249991 Change-Id: I214ebc9b5bbd71e5db1a1332296ceb4e426c50cf --- automotive/vehicle/2.0/types.hal | 20 ++++++++++++-------- current.txt | 3 --- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index 23f91356b6..82f938c611 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -2646,9 +2646,9 @@ enum VehicleProperty : int32_t { * If the request succeeded and Android has 3 users (0, 10, 11), the response would be: * * int32[0]: -108 // request id - * int32[1]: 5 // messageType = SwitchUserMessageType::ANDROID_SWITCH + * int32[1]: 5 // messageType = SwitchUserMessageType::ANDROID_POST_SWITCH * int32[2]: 11 // target user id - * int32[3]: 11 // target user id flags (none) + * int32[3]: 0 // target user id flags (none) * int32[4]: 11 // current user * int32[5]: 0 // current user flags (none) * int32[6]: 3 // number of users @@ -2664,17 +2664,21 @@ enum VehicleProperty : int32_t { * * 5.ANDROID_POST_SWITCH * --------------------- - * Called by the Android System after a request to switch a user was made + * Called by the Android System after a request to switch a user was made. * * This property is called after switch requests of any type (i.e., LEGACY_ANDROID_SWITCH, * ANDROID_SWITCH, or VEHICLE_REQUEST) and can be used to determine if the request succeeded or * failed: * - * 1. When it succeeded, it's called when the Android user is in the boot locked state and the - * value of the current and target users ids in the response are different. This would be - * equivalent to receiving an Intent.ACTION_LOCKED_BOOT_COMPLETED in an Android app. + * 1. When it succeeded, it's called when the Android user is in the unlocked state and the + * value of the current and target users ids in the response are the same. This would be + * equivalent to receiving an Intent.ACTION_USER_UNLOCKED in an Android app. * 2. When it failed it's called right away and the value of the current and target users ids - * in the response are the same. + * 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 + * 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 * reply back to the Android System. @@ -2824,7 +2828,7 @@ enum VehicleProperty : int32_t { * int32[0]: 0 (Android user flags) * int32[1]: 1 (number of associations being set) * int32[2]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1) - * int32[3]: 1 (1st value: UserIdentificationAssociationSETValue::ASSOCIATE_CURRENT_USER) + * int32[3]: 1 (1st value: UserIdentificationAssociationSetValue::ASSOCIATE_CURRENT_USER) * * If the request succeeded, the response would be simply: * diff --git a/current.txt b/current.txt index e553999c59..eb2273ee19 100644 --- a/current.txt +++ b/current.txt @@ -656,9 +656,6 @@ b7015428cd52ce8192d13bfcbf2c4455cda3727d57f2aac80d65a1747104f5ac android.hardwar 7d2e77ad86766bbc213fa7377eab739f44cc0866e567e6d33c0e27e7f99e27a8 android.hardware.automotive.sv@1.0::ISurroundViewSession d34769e55df919739bb46f25ae2e125e9c807733afa94daeca20feadd74de79c android.hardware.automotive.sv@1.0::ISurroundViewStream affd9c591f48a69773fcf43dc4a716d292cd4bc5ba2be8649276af0aedea435d android.hardware.automotive.sv@1.0::types -b3caf524c46a47d67e6453a34419e1881942d059e146cda740502670e9a752c3 android.hardware.automotive.vehicle@2.0::IVehicle -7ce8728b27600e840cacf0a832f6942819fe535f9d3797ae052d5eef5065921c android.hardware.automotive.vehicle@2.0::IVehicleCallback -6b2564fce1d364baf9ba15a5cb00a8f08f86a5be5387c0ede795328ca536a2c7 android.hardware.automotive.vehicle@2.0::types 140f8f62100ccf9cd282ae3685a0f4ef0a9f971d77dfbc7350ccb4e04cf295ec android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprint 82cad99f5feb2ea9bcd4579055edf4af8feb9fc602a6e4827ddd727d254d4991 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprintClientCallback ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types From 0c6e08d07a73e4253155973f563f759606c75dcb Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Tue, 24 Mar 2020 15:34:29 -0700 Subject: [PATCH 0872/1022] android.hardware.tests.lazy@1.0::ILazy For testing lazy HALs in HIDL on continuous integration. Bug: 148114689 Test: hidl_lazy_test Change-Id: I710c11c0cb59f04b4f162d627ca0d11135ab1437 (cherry picked from commit 1f9aa386ba7ccc800ede697a381b700f89dc7ee0) Merged-In: I710c11c0cb59f04b4f162d627ca0d11135ab1437 --- current.txt | 4 ++++ tests/lazy/1.0/.hidl_for_test | 0 tests/lazy/1.0/Android.bp | 14 ++++++++++++++ tests/lazy/1.0/ILazy.hal | 19 +++++++++++++++++++ 4 files changed, 37 insertions(+) create mode 100644 tests/lazy/1.0/.hidl_for_test create mode 100644 tests/lazy/1.0/Android.bp create mode 100644 tests/lazy/1.0/ILazy.hal diff --git a/current.txt b/current.txt index e553999c59..955dbbce14 100644 --- a/current.txt +++ b/current.txt @@ -1,6 +1,10 @@ # Do not change this file except to add new interfaces. Changing # pre-existing interfaces will fail VTS and break framework-only OTAs +# Test HALs + +717c17cd380bb48710dff601d1a03351d4ebc28028353d5d60489248f506523c android.hardware.tests.lazy@1.0::ILazy + # HALs released in Android O f219c3b5b8c6cb1d659d4c7328f67246abfe1a8613f469826fd3b9ad090417a2 android.hardware.audio@2.0::IDevice diff --git a/tests/lazy/1.0/.hidl_for_test b/tests/lazy/1.0/.hidl_for_test new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/lazy/1.0/Android.bp b/tests/lazy/1.0/Android.bp new file mode 100644 index 0000000000..d2f81756e3 --- /dev/null +++ b/tests/lazy/1.0/Android.bp @@ -0,0 +1,14 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.tests.lazy@1.0", + root: "android.hardware", + system_ext_specific: true, + srcs: [ + "ILazy.hal", + ], + interfaces: [ + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/tests/lazy/1.0/ILazy.hal b/tests/lazy/1.0/ILazy.hal new file mode 100644 index 0000000000..b0be48ebd1 --- /dev/null +++ b/tests/lazy/1.0/ILazy.hal @@ -0,0 +1,19 @@ +/* + * 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. + */ + +package android.hardware.tests.lazy@1.0; + +interface ILazy {}; From 9c998c0720e4220d174f5377d43213cc389f7d7e Mon Sep 17 00:00:00 2001 From: felipeal Date: Fri, 17 Apr 2020 14:32:53 -0700 Subject: [PATCH 0873/1022] Moved emulated User HAL capabilities into a library. So it can be used by other Vehicle HAL implementations. Test: adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default --user-hal Test: adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default --help Test: m -j android.hardware.automotive.vehicle@2.0-emulated-user-hal-lib Bug: 150167241 Bug: 150409377 Merged-In: I2d0c5039c3b994dfe10d3b411f6d502bebe7cca0 Change-Id: I2d0c5039c3b994dfe10d3b411f6d502bebe7cca0 --- automotive/vehicle/2.0/default/Android.bp | 15 +- .../default/impl/vhal_v2_0/DefaultConfig.h | 2 - .../impl/vhal_v2_0/EmulatedUserHal.cpp | 186 ++++++++++++++++++ .../default/impl/vhal_v2_0/EmulatedUserHal.h | 115 +++++++++++ .../vhal_v2_0/EmulatedVehicleConnector.cpp | 26 +-- .../impl/vhal_v2_0/VehicleHalServer.cpp | 182 ++--------------- .../default/impl/vhal_v2_0/VehicleHalServer.h | 8 +- 7 files changed, 338 insertions(+), 196 deletions(-) create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp index e529675203..86e59d0865 100644 --- a/automotive/vehicle/2.0/default/Android.bp +++ b/automotive/vehicle/2.0/default/Android.bp @@ -75,7 +75,10 @@ cc_library_static { ], local_include_dirs: ["common/include/vhal_v2_0"], export_include_dirs: ["impl"], - whole_static_libs: ["android.hardware.automotive.vehicle@2.0-manager-lib"], + whole_static_libs: [ + "android.hardware.automotive.vehicle@2.0-emulated-user-hal-lib", + "android.hardware.automotive.vehicle@2.0-manager-lib", + ], shared_libs: [ "libbase", "libjsoncpp", @@ -87,6 +90,16 @@ cc_library_static { ], } +// Library used to emulate User HAL behavior through lshal debug requests. +cc_library_static { + name: "android.hardware.automotive.vehicle@2.0-emulated-user-hal-lib", + vendor: true, + defaults: ["vhal_v2_0_defaults"], + srcs: [ + "impl/vhal_v2_0/EmulatedUserHal.cpp", + ], +} + cc_test { name: "android.hardware.automotive.vehicle@2.0-manager-unit-tests", vendor: true, 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 ea759867f2..e50aafbeff 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 @@ -79,8 +79,6 @@ constexpr int WHEEL_FRONT_LEFT = (int)VehicleAreaWheel::LEFT_FRONT; constexpr int WHEEL_FRONT_RIGHT = (int)VehicleAreaWheel::RIGHT_FRONT; constexpr int WHEEL_REAR_LEFT = (int)VehicleAreaWheel::LEFT_REAR; constexpr int WHEEL_REAR_RIGHT = (int)VehicleAreaWheel::RIGHT_REAR; -constexpr int INITIAL_USER_INFO = (int)VehicleProperty::INITIAL_USER_INFO; -constexpr int SWITCH_USER = (int)VehicleProperty::SWITCH_USER; /** * This property is used for test purpose to generate fake events. Here is the test package that 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 new file mode 100644 index 0000000000..c49fadc9eb --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp @@ -0,0 +1,186 @@ +/* + * 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. + */ +#define LOG_TAG "EmulatedUserHal" + +#include +#include + +#include "EmulatedUserHal.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +constexpr int INITIAL_USER_INFO = static_cast(VehicleProperty::INITIAL_USER_INFO); +constexpr int SWITCH_USER = static_cast(VehicleProperty::SWITCH_USER); + +bool EmulatedUserHal::isSupported(int32_t prop) { + switch (prop) { + case INITIAL_USER_INFO: + case SWITCH_USER: + return true; + default: + return false; + } +} + +android::base::Result> EmulatedUserHal::onSetProperty( + const VehiclePropValue& value) { + ALOGV("onSetProperty(): %s", toString(value).c_str()); + + switch (value.prop) { + case INITIAL_USER_INFO: + return onSetInitialUserInfoResponse(value); + case SWITCH_USER: + return onSetSwitchUserResponse(value); + default: + return android::base::Error(static_cast(StatusCode::INVALID_ARG)) + << "Unsupported property: " << toString(value); + } +} + +android::base::Result> +EmulatedUserHal::onSetInitialUserInfoResponse(const VehiclePropValue& value) { + if (value.value.int32Values.size() == 0) { + ALOGE("set(INITIAL_USER_INFO): 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(INITIAL_USER_INFO) called from lshal; storing it: %s", toString(value).c_str()); + mInitialUserResponseFromCmd.reset(new VehiclePropValue(value)); + return {}; + } + + ALOGD("set(INITIAL_USER_INFO) called from Android: %s", toString(value).c_str()); + + int32_t requestId = value.value.int32Values[0]; + if (mInitialUserResponseFromCmd != nullptr) { + ALOGI("replying INITIAL_USER_INFO with lshal value: %s", + toString(*mInitialUserResponseFromCmd).c_str()); + return sendUserHalResponse(std::move(mInitialUserResponseFromCmd), requestId); + } + + // Returns default response + auto updatedValue = std::unique_ptr(new VehiclePropValue); + updatedValue->prop = INITIAL_USER_INFO; + updatedValue->timestamp = elapsedRealtimeNano(); + updatedValue->value.int32Values.resize(2); + updatedValue->value.int32Values[0] = requestId; + updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT; + + ALOGI("no lshal response; replying with InitialUserInfoResponseAction::DEFAULT: %s", + toString(*updatedValue).c_str()); + + return updatedValue; +} + +android::base::Result> EmulatedUserHal::onSetSwitchUserResponse( + const VehiclePropValue& value) { + if (value.value.int32Values.size() == 0) { + ALOGE("set(SWITCH_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(SWITCH_USER) called from lshal; storing it: %s", toString(value).c_str()); + mSwitchUserResponseFromCmd.reset(new VehiclePropValue(value)); + return {}; + } + ALOGD("set(SWITCH_USER) called from Android: %s", toString(value).c_str()); + + int32_t requestId = value.value.int32Values[0]; + if (mSwitchUserResponseFromCmd != nullptr) { + ALOGI("replying SWITCH_USER with lshal value: %s", + toString(*mSwitchUserResponseFromCmd).c_str()); + return sendUserHalResponse(std::move(mSwitchUserResponseFromCmd), requestId); + } + + // Returns default response + auto updatedValue = std::unique_ptr(new VehiclePropValue); + updatedValue->prop = SWITCH_USER; + updatedValue->timestamp = elapsedRealtimeNano(); + updatedValue->value.int32Values.resize(3); + updatedValue->value.int32Values[0] = requestId; + updatedValue->value.int32Values[1] = (int32_t)SwitchUserMessageType::VEHICLE_RESPONSE; + updatedValue->value.int32Values[2] = (int32_t)SwitchUserStatus::SUCCESS; + + ALOGI("no lshal response; replying with VEHICLE_RESPONSE / SUCCESS: %s", + toString(*updatedValue).c_str()); + + return updatedValue; +} + +android::base::Result> EmulatedUserHal::sendUserHalResponse( + std::unique_ptr response, int32_t requestId) { + switch (response->areaId) { + case 1: + ALOGD("returning response with right request id"); + response->value.int32Values[0] = requestId; + break; + case 2: + ALOGD("returning response with wrong request id"); + response->value.int32Values[0] = -requestId; + break; + case 3: + ALOGD("not generating a property change event because of lshal prop: %s", + toString(*response).c_str()); + return android::base::Error(static_cast(StatusCode::NOT_AVAILABLE)) + << "not generating a property change event because of lshal prop: " + << toString(*response); + default: + ALOGE("invalid action on lshal response: %s", toString(*response).c_str()); + return android::base::Error(static_cast(StatusCode::INTERNAL_ERROR)) + << "invalid action on lshal response: " << toString(*response); + } + + ALOGD("updating property to: %s", toString(*response).c_str()); + + return response; +} + +void EmulatedUserHal::showDumpHelp(int fd) { + dprintf(fd, "%s: dumps state used for user management\n", kUserHalDumpOption); +} + +void EmulatedUserHal::dump(int fd, std::string indent) { + if (mInitialUserResponseFromCmd != nullptr) { + dprintf(fd, "%sInitialUserInfo response: %s\n", indent.c_str(), + toString(*mInitialUserResponseFromCmd).c_str()); + } else { + dprintf(fd, "%sNo InitialUserInfo response\n", indent.c_str()); + } + if (mSwitchUserResponseFromCmd != nullptr) { + dprintf(fd, "%sSwitchUser response: %s\n", indent.c_str(), + toString(*mSwitchUserResponseFromCmd).c_str()); + } else { + dprintf(fd, "%sNo SwitchUser response\n", indent.c_str()); + } +} + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android 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 new file mode 100644 index 0000000000..b25efcb4d7 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h @@ -0,0 +1,115 @@ +/* + * 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_automotive_vehicle_V2_0_impl_EmulatedUserHal_H_ +#define android_hardware_automotive_vehicle_V2_0_impl_EmulatedUserHal_H_ + +#include + +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +constexpr char kUserHalDumpOption[] = "--user-hal"; + +/** + * Class used to emulate User HAL behavior through lshal debug requests. + */ +class EmulatedUserHal { + public: + EmulatedUserHal() {} + + ~EmulatedUserHal() = default; + + /** + * Checks if the emulator can handle the property. + */ + bool isSupported(int32_t prop); + + /** + * Lets the emulator handle the property. + * + * @return updated property and StatusCode + */ + android::base::Result> onSetProperty( + const VehiclePropValue& value); + + /** + * Shows the User HAL emulation help. + */ + void showDumpHelp(int fd); + + /** + * Dump its contents. + */ + void dump(int fd, std::string indent); + + private: + /** + * INITIAL_USER_INFO is called by Android when it starts, and it's expecting a property change + * indicating what the initial user should be. + * + * During normal circumstances, the emulator will reply right away, passing a response if + * InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which + * user to boot). + * + * But during development / testing, the behavior can be changed using lshal dump, which must + * use the areaId to indicate what should happen next. + * + * So, the behavior of set(INITIAL_USER_INFO) is: + * + * - if it has an areaId, store the property into mInitialUserResponseFromCmd (as it was called + * by lshal). + * - else if mInitialUserResponseFromCmd is not set, return a response with the same request id + * and InitialUserInfoResponseAction::DEFAULT + * - else the behavior is defined by the areaId on mInitialUserResponseFromCmd: + * - if it's 1, reply with mInitialUserResponseFromCmd and the right request id + * - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can + * test this error scenario) + * - if it's 3, then don't send a property change (so Android can emulate a timeout) + * + */ + android::base::Result> onSetInitialUserInfoResponse( + const VehiclePropValue& value); + + /** + * Used to emulate SWITCH_USER - see onSetInitialUserInfoResponse() for usage. + */ + android::base::Result> onSetSwitchUserResponse( + const VehiclePropValue& value); + + android::base::Result> sendUserHalResponse( + std::unique_ptr response, int32_t requestId); + + std::unique_ptr mInitialUserResponseFromCmd; + std::unique_ptr mSwitchUserResponseFromCmd; +}; + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_0_impl_EmulatedUserHal_H_ diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp index ce7dc65127..7f9362fdf4 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp @@ -38,9 +38,6 @@ namespace impl { class EmulatedPassthroughConnector : public PassthroughConnector { public: bool onDump(const hidl_handle& fd, const hidl_vec& options) override; - - private: - void dumpUserHal(int fd, std::string indent); }; bool EmulatedPassthroughConnector::onDump(const hidl_handle& handle, @@ -50,12 +47,12 @@ bool EmulatedPassthroughConnector::onDump(const hidl_handle& handle, if (options.size() > 0) { if (options[0] == "--help") { dprintf(fd, "Emulator-specific usage:\n"); - dprintf(fd, "--user-hal: dumps state used for user management \n"); + mEmulatedUserHal.showDumpHelp(fd); dprintf(fd, "\n"); // Include caller's help options return true; - } else if (options[0] == "--user-hal") { - dumpUserHal(fd, ""); + } else if (options[0] == kUserHalDumpOption) { + mEmulatedUserHal.dump(fd, ""); return false; } else { @@ -65,27 +62,12 @@ bool EmulatedPassthroughConnector::onDump(const hidl_handle& handle, } dprintf(fd, "Emulator-specific state:\n"); - dumpUserHal(fd, " "); + mEmulatedUserHal.dump(fd, " "); dprintf(fd, "\n"); return true; } -void EmulatedPassthroughConnector::dumpUserHal(int fd, std::string indent) { - if (mInitialUserResponseFromCmd != nullptr) { - dprintf(fd, "%sInitialUserInfo response: %s\n", indent.c_str(), - toString(*mInitialUserResponseFromCmd).c_str()); - } else { - dprintf(fd, "%sNo InitialUserInfo response\n", indent.c_str()); - } - if (mSwitchUserResponseFromCmd != nullptr) { - dprintf(fd, "%sSwitchUser response: %s\n", indent.c_str(), - toString(*mSwitchUserResponseFromCmd).c_str()); - } else { - dprintf(fd, "%sNo SwitchUser response\n", indent.c_str()); - } -} - PassthroughConnectorPtr makeEmulatedPassthroughConnector() { return std::make_unique(); } diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp index 70e39ebdbf..ad5096e58f 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp @@ -181,6 +181,23 @@ VehicleHalServer::VehiclePropValuePtr VehicleHalServer::createHwInputKeyProp( } StatusCode VehicleHalServer::onSetProperty(const VehiclePropValue& value, bool updateStatus) { + if (mEmulatedUserHal.isSupported(value.prop)) { + LOG(INFO) << "onSetProperty(): property " << value.prop << " will be handled by UserHal"; + + const auto& ret = mEmulatedUserHal.onSetProperty(value); + if (!ret.ok()) { + LOG(ERROR) << "onSetProperty(): HAL returned error: " << ret.error().message(); + return StatusCode(ret.error().code()); + } + auto updatedValue = ret.value().get(); + if (updatedValue != nullptr) { + LOG(INFO) << "onSetProperty(): updating property returned by HAL: " + << toString(*updatedValue); + onPropertyValueFromCar(*updatedValue, updateStatus); + } + return StatusCode::OK; + } + // Some properties need to be treated non-trivially switch (value.prop) { case kGenerateFakeDataControllingProperty: @@ -245,10 +262,6 @@ StatusCode VehicleHalServer::onSetProperty(const VehiclePropValue& value, bool u break; } break; - case INITIAL_USER_INFO: - return onSetInitialUserInfoResponse(value, updateStatus); - case SWITCH_USER: - return onSetSwitchUserResponse(value, updateStatus); default: break; } @@ -262,165 +275,4 @@ StatusCode VehicleHalServer::onSetProperty(const VehiclePropValue& value, bool u return StatusCode::OK; } -/** - * INITIAL_USER_INFO is called by Android when it starts, and it's expecting a property change - * indicating what the initial user should be. - * - * During normal circumstances, the emulator will reply right away, passing a response if - * InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which user - * to boot). - * - * But during development / testing, the behavior can be changed using lshal dump, which must use - * the areaId to indicate what should happen next. - * - * So, the behavior of set(INITIAL_USER_INFO) is: - * - * - if it has an areaId, store the property into mInitialUserResponseFromCmd (as it was called by - * lshal). - * - else if mInitialUserResponseFromCmd is not set, return a response with the same request id and - * InitialUserInfoResponseAction::DEFAULT - * - else the behavior is defined by the areaId on mInitialUserResponseFromCmd: - * - if it's 1, reply with mInitialUserResponseFromCmd and the right request id - * - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can test - * this error scenario) - * - if it's 3, then don't send a property change (so Android can emulate a timeout) - * - */ -StatusCode VehicleHalServer::onSetInitialUserInfoResponse(const VehiclePropValue& value, - bool updateStatus) { - // TODO: LOG calls below might be more suited to be DEBUG, but those are not being logged - // (even when explicitly calling setprop log.tag. As this class should be using ALOG instead of - // LOG, it's not worth investigating why... - - if (value.value.int32Values.size() == 0) { - LOG(ERROR) << "set(INITIAL_USER_INFO): no int32values, ignoring it: " << toString(value); - return StatusCode::INVALID_ARG; - } - - if (value.areaId != 0) { - LOG(INFO) << "set(INITIAL_USER_INFO) called from lshal; storing it: " << toString(value); - mInitialUserResponseFromCmd.reset(new VehiclePropValue(value)); - return StatusCode::OK; - } - LOG(INFO) << "set(INITIAL_USER_INFO) called from Android: " << toString(value); - - int32_t requestId = value.value.int32Values[0]; - - // Create the update property and set common values - auto updatedValue = createVehiclePropValue(VehiclePropertyType::MIXED, 0); - updatedValue->prop = INITIAL_USER_INFO; - updatedValue->timestamp = elapsedRealtimeNano(); - - if (mInitialUserResponseFromCmd == nullptr) { - updatedValue->value.int32Values.resize(2); - updatedValue->value.int32Values[0] = requestId; - updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT; - LOG(INFO) << "no lshal response; returning InitialUserInfoResponseAction::DEFAULT: " - << toString(*updatedValue); - onPropertyValueFromCar(*updatedValue, updateStatus); - return StatusCode::OK; - } - - // mInitialUserResponseFromCmd is used for just one request - std::unique_ptr response = std::move(mInitialUserResponseFromCmd); - - // TODO(b/150409377): rather than populate the raw values directly, it should use the - // libraries that convert a InitialUserInfoResponse into a VehiclePropValue) - - switch (response->areaId) { - case 1: - LOG(INFO) << "returning response with right request id"; - *updatedValue = *response; - updatedValue->areaId = 0; - updatedValue->value.int32Values[0] = requestId; - break; - case 2: - LOG(INFO) << "returning response with wrong request id"; - *updatedValue = *response; - updatedValue->areaId = 0; - updatedValue->value.int32Values[0] = -requestId; - break; - case 3: - LOG(INFO) << "not generating a property change event because of lshal prop: " - << toString(*response); - return StatusCode::OK; - default: - LOG(ERROR) << "invalid action on lshal response: " << toString(*response); - return StatusCode::INTERNAL_ERROR; - } - - LOG(INFO) << "updating property to: " << toString(*updatedValue); - onPropertyValueFromCar(*updatedValue, updateStatus); - return StatusCode::OK; -} - -/** - * Used to emulate SWITCH_USER - see onSetInitialUserInfoResponse() for usage. - */ -StatusCode VehicleHalServer::onSetSwitchUserResponse(const VehiclePropValue& value, - bool updateStatus) { - if (value.value.int32Values.size() == 0) { - LOG(ERROR) << "set(SWITCH_USER): no int32values, ignoring it: " << toString(value); - return StatusCode::INVALID_ARG; - } - - if (value.areaId != 0) { - LOG(INFO) << "set(SWITCH_USER) called from lshal; storing it: " << toString(value); - mSwitchUserResponseFromCmd.reset(new VehiclePropValue(value)); - return StatusCode::OK; - } - LOG(INFO) << "set(SWITCH_USER) called from Android: " << toString(value); - - int32_t requestId = value.value.int32Values[0]; - - // Create the update property and set common values - auto updatedValue = createVehiclePropValue(VehiclePropertyType::MIXED, 0); - updatedValue->prop = SWITCH_USER; - updatedValue->timestamp = elapsedRealtimeNano(); - - if (mSwitchUserResponseFromCmd == nullptr) { - updatedValue->value.int32Values.resize(3); - updatedValue->value.int32Values[0] = requestId; - updatedValue->value.int32Values[1] = (int32_t)SwitchUserMessageType::VEHICLE_RESPONSE; - updatedValue->value.int32Values[2] = (int32_t)SwitchUserStatus::SUCCESS; - LOG(INFO) << "no lshal response; returning VEHICLE_RESPONSE / SUCCESS: " - << toString(*updatedValue); - onPropertyValueFromCar(*updatedValue, updateStatus); - return StatusCode::OK; - } - - // mSwitchUserResponseFromCmd is used for just one request - std::unique_ptr response = std::move(mSwitchUserResponseFromCmd); - - // TODO(b/150409377): move code below to a local function like sendUserHalResponse(), - // as it's the same for all (like onSetInitialUserInfoResponse) - - switch (response->areaId) { - case 1: - LOG(INFO) << "returning response with right request id"; - *updatedValue = *response; - updatedValue->areaId = 0; - updatedValue->value.int32Values[0] = requestId; - break; - case 2: - LOG(INFO) << "returning response with wrong request id"; - *updatedValue = *response; - updatedValue->areaId = 0; - updatedValue->value.int32Values[0] = -requestId; - break; - case 3: - LOG(INFO) << "not generating a property change event because of lshal prop: " - << toString(*response); - return StatusCode::OK; - default: - LOG(ERROR) << "invalid action on lshal response: " << toString(*response); - return StatusCode::INTERNAL_ERROR; - } - - LOG(INFO) << "updating property to: " << toString(*updatedValue); - onPropertyValueFromCar(*updatedValue, updateStatus); - - return StatusCode::OK; -} - } // namespace android::hardware::automotive::vehicle::V2_0::impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h index 20e094a00f..2841fbee3c 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h @@ -19,6 +19,7 @@ #include #include +#include "EmulatedUserHal.h" #include "GeneratorHub.h" namespace android::hardware::automotive::vehicle::V2_0::impl { @@ -53,15 +54,10 @@ class VehicleHalServer : public IVehicleServer { VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay); - StatusCode onSetInitialUserInfoResponse(const VehiclePropValue& value, bool updateStatus); - StatusCode onSetSwitchUserResponse(const VehiclePropValue& value, bool updateStatus); - // data members protected: - // TODO(b/146207078): it might be clearer to move members below to an EmulatedUserHal class - std::unique_ptr mInitialUserResponseFromCmd; - std::unique_ptr mSwitchUserResponseFromCmd; + EmulatedUserHal mEmulatedUserHal; private: GeneratorHub mGeneratorHub{ From d39b9fb604dc1592c13ba2db1fa7ac12416b94de Mon Sep 17 00:00:00 2001 From: Selene Huang Date: Wed, 4 Mar 2020 02:24:16 -0800 Subject: [PATCH 0874/1022] Fix IC vts bugs and add tests for IC IWritableIdentityCredential.aidl interface. Fixed following bugs in WritableIdentityCredential.cpp - Do not allow startPersonalization to be called more than once per aidl. - Do not preceed with beginAddEntry if addAccessControlProfile and startPersonalization profile count mismatch. - Verify access control profile ids are unique. - Do not let empty name space to mess up beginAddEntry. - Do not allow beginAddEntry to add entries interleaving namespace groupings. Enforce all entries must be added in namespace "groups" per aidl. - Fix counting error that allowed one entries to be added per name space than startPersonalization limit. - Do not approve finishAddingEntries if there are more profiles or entries to be added than startPersonalization set accounting. - Add testing utilities library for identity credential. - Refactored end to end tests. Bug: 154909726 Test: atest VtsHalIdentityTargetTest Test: atest android.security.identity.cts Merged-In: I51902681776c6230e49589fc75a8145e79d7d1a6 Change-Id: Ib7c108f67c61125edba6177dcac61cfbf58da671 --- .../default/WritableIdentityCredential.cpp | 39 +- .../aidl/default/WritableIdentityCredential.h | 8 + identity/aidl/vts/Android.bp | 6 +- ...est.cpp => VtsHalIdentityEndToEndTest.cpp} | 153 +---- .../VtsIWritableIdentityCredentialTests.cpp | 649 ++++++++++++++++++ identity/aidl/vts/VtsIdentityTestUtils.cpp | 179 +++++ identity/aidl/vts/VtsIdentityTestUtils.h | 118 ++++ .../support/src/IdentityCredentialSupport.cpp | 7 +- 8 files changed, 1036 insertions(+), 123 deletions(-) rename identity/aidl/vts/{VtsHalIdentityTargetTest.cpp => VtsHalIdentityEndToEndTest.cpp} (69%) create mode 100644 identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp create mode 100644 identity/aidl/vts/VtsIdentityTestUtils.cpp create mode 100644 identity/aidl/vts/VtsIdentityTestUtils.h diff --git a/identity/aidl/default/WritableIdentityCredential.cpp b/identity/aidl/default/WritableIdentityCredential.cpp index 89f7f35696..553a3d832b 100644 --- a/identity/aidl/default/WritableIdentityCredential.cpp +++ b/identity/aidl/default/WritableIdentityCredential.cpp @@ -44,6 +44,8 @@ bool WritableIdentityCredential::initialize() { return false; } storageKey_ = random.value(); + startPersonalizationCalled_ = false; + firstEntry_ = true; return true; } @@ -105,6 +107,12 @@ ndk::ScopedAStatus WritableIdentityCredential::getAttestationCertificate( ndk::ScopedAStatus WritableIdentityCredential::startPersonalization( int32_t accessControlProfileCount, const vector& entryCounts) { + if (startPersonalizationCalled_) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + IIdentityCredentialStore::STATUS_FAILED, "startPersonalization called already")); + } + + startPersonalizationCalled_ = true; numAccessControlProfileRemaining_ = accessControlProfileCount; remainingEntryCounts_ = entryCounts; entryNameSpace_ = ""; @@ -128,6 +136,13 @@ ndk::ScopedAStatus WritableIdentityCredential::addAccessControlProfile( "numAccessControlProfileRemaining_ is 0 and expected non-zero")); } + if (accessControlProfileIds_.find(id) != accessControlProfileIds_.end()) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + IIdentityCredentialStore::STATUS_INVALID_DATA, + "Access Control Profile id must be unique")); + } + accessControlProfileIds_.insert(id); + // Spec requires if |userAuthenticationRequired| is false, then |timeoutMillis| must also // be zero. if (!userAuthenticationRequired && timeoutMillis != 0) { @@ -184,12 +199,20 @@ ndk::ScopedAStatus WritableIdentityCredential::beginAddEntry( } // Handle initial beginEntry() call. - if (entryNameSpace_ == "") { + if (firstEntry_) { + firstEntry_ = false; entryNameSpace_ = nameSpace; + allNameSpaces_.insert(nameSpace); } // If the namespace changed... if (nameSpace != entryNameSpace_) { + if (allNameSpaces_.find(nameSpace) != allNameSpaces_.end()) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + IIdentityCredentialStore::STATUS_INVALID_DATA, + "Name space cannot be added in interleaving fashion")); + } + // Then check that all entries in the previous namespace have been added.. if (remainingEntryCounts_[0] != 0) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( @@ -197,6 +220,8 @@ ndk::ScopedAStatus WritableIdentityCredential::beginAddEntry( "New namespace but a non-zero number of entries remain to be added")); } remainingEntryCounts_.erase(remainingEntryCounts_.begin()); + remainingEntryCounts_[0] -= 1; + allNameSpaces_.insert(nameSpace); if (signedDataCurrentNamespace_.size() > 0) { signedDataNamespaces_.add(entryNameSpace_, std::move(signedDataCurrentNamespace_)); @@ -330,6 +355,18 @@ bool generateCredentialData(const vector& hardwareBoundKey, const strin ndk::ScopedAStatus WritableIdentityCredential::finishAddingEntries( vector* outCredentialData, vector* outProofOfProvisioningSignature) { + if (numAccessControlProfileRemaining_ != 0) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + IIdentityCredentialStore::STATUS_INVALID_DATA, + "numAccessControlProfileRemaining_ is not 0 and expected zero")); + } + + if (remainingEntryCounts_.size() > 1 || remainingEntryCounts_[0] != 0) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + IIdentityCredentialStore::STATUS_INVALID_DATA, + "More entry spaces remain than startPersonalization configured")); + } + if (signedDataCurrentNamespace_.size() > 0) { signedDataNamespaces_.add(entryNameSpace_, std::move(signedDataCurrentNamespace_)); } diff --git a/identity/aidl/default/WritableIdentityCredential.h b/identity/aidl/default/WritableIdentityCredential.h index b182862862..cb91f7ba86 100644 --- a/identity/aidl/default/WritableIdentityCredential.h +++ b/identity/aidl/default/WritableIdentityCredential.h @@ -21,9 +21,11 @@ #include #include +#include namespace aidl::android::hardware::identity { +using ::std::set; using ::std::string; using ::std::vector; @@ -66,6 +68,8 @@ class WritableIdentityCredential : public BnWritableIdentityCredential { // This is set in initialize(). vector storageKey_; + bool startPersonalizationCalled_; + bool firstEntry_; // These are set in getAttestationCertificate(). vector credentialPrivKey_; @@ -79,6 +83,9 @@ class WritableIdentityCredential : public BnWritableIdentityCredential { cppbor::Map signedDataNamespaces_; cppbor::Array signedDataCurrentNamespace_; + // This field is initialized in addAccessControlProfile + set accessControlProfileIds_; + // These fields are initialized during beginAddEntry() size_t entryRemainingBytes_; vector entryAdditionalData_; @@ -86,6 +93,7 @@ class WritableIdentityCredential : public BnWritableIdentityCredential { string entryName_; vector entryAccessControlProfileIds_; vector entryBytes_; + set allNameSpaces_; }; } // namespace aidl::android::hardware::identity diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp index ef8beb4cdf..e4780bf89c 100644 --- a/identity/aidl/vts/Android.bp +++ b/identity/aidl/vts/Android.bp @@ -4,7 +4,11 @@ cc_test { "VtsHalTargetTestDefaults", "use_libaidlvintf_gtest_helper_static", ], - srcs: ["VtsHalIdentityTargetTest.cpp"], + srcs: [ + "VtsHalIdentityEndToEndTest.cpp", + "VtsIWritableIdentityCredentialTests.cpp", + "VtsIdentityTestUtils.cpp", + ], shared_libs: [ "libbinder", "libcrypto", diff --git a/identity/aidl/vts/VtsHalIdentityTargetTest.cpp b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp similarity index 69% rename from identity/aidl/vts/VtsHalIdentityTargetTest.cpp rename to identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp index ea37fdc7a5..8a4e8a7fa1 100644 --- a/identity/aidl/vts/VtsHalIdentityTargetTest.cpp +++ b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp @@ -28,8 +28,11 @@ #include #include +#include "VtsIdentityTestUtils.h" + namespace android::hardware::identity { +using std::endl; using std::map; using std::optional; using std::string; @@ -41,51 +44,6 @@ using ::android::binder::Status; using ::android::hardware::keymaster::HardwareAuthToken; -// --------------------------------------------------------------------------- -// Test Data. -// --------------------------------------------------------------------------- - -struct TestEntryData { - TestEntryData(string nameSpace, string name, vector profileIds) - : nameSpace(nameSpace), name(name), profileIds(profileIds) {} - - TestEntryData(string nameSpace, string name, const string& value, vector profileIds) - : TestEntryData(nameSpace, name, profileIds) { - valueCbor = cppbor::Tstr(((const char*)value.data())).encode(); - } - TestEntryData(string nameSpace, string name, const vector& value, - vector profileIds) - : TestEntryData(nameSpace, name, profileIds) { - valueCbor = cppbor::Bstr(value).encode(); - } - TestEntryData(string nameSpace, string name, bool value, vector profileIds) - : TestEntryData(nameSpace, name, profileIds) { - valueCbor = cppbor::Bool(value).encode(); - } - TestEntryData(string nameSpace, string name, int64_t value, vector profileIds) - : TestEntryData(nameSpace, name, profileIds) { - if (value >= 0) { - valueCbor = cppbor::Uint(value).encode(); - } else { - valueCbor = cppbor::Nint(-value).encode(); - } - } - - string nameSpace; - string name; - vector valueCbor; - vector profileIds; -}; - -struct TestProfile { - uint16_t id; - vector readerCertificate; - bool userAuthenticationRequired; - uint64_t timeoutMillis; -}; - -// ---------------------------------------------------------------- - class IdentityAidl : public testing::TestWithParam { public: virtual void SetUp() override { @@ -108,39 +66,26 @@ TEST_P(IdentityAidl, hardwareInformation) { TEST_P(IdentityAidl, createAndRetrieveCredential) { // First, generate a key-pair for the reader since its public key will be // part of the request data. - optional> readerKeyPKCS8 = support::createEcKeyPair(); - ASSERT_TRUE(readerKeyPKCS8); - optional> readerPublicKey = - support::ecKeyPairGetPublicKey(readerKeyPKCS8.value()); - optional> readerKey = support::ecKeyPairGetPrivateKey(readerKeyPKCS8.value()); - string serialDecimal = "1234"; - string issuer = "Android Open Source Project"; - string subject = "Android IdentityCredential VTS Test"; - time_t validityNotBefore = time(nullptr); - time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600; - optional> readerCertificate = support::ecPublicKeyGenerateCertificate( - readerPublicKey.value(), readerKey.value(), serialDecimal, issuer, subject, - validityNotBefore, validityNotAfter); + vector readerKey; + optional> readerCertificate = + test_utils::GenerateReaderCertificate("1234", readerKey); ASSERT_TRUE(readerCertificate); // Make the portrait image really big (just shy of 256 KiB) to ensure that // the chunking code gets exercised. vector portraitImage; - portraitImage.resize(256 * 1024 - 10); - for (size_t n = 0; n < portraitImage.size(); n++) { - portraitImage[n] = (uint8_t)n; - } + test_utils::SetImageData(portraitImage); // Access control profiles: - const vector testProfiles = {// Profile 0 (reader authentication) - {0, readerCertificate.value(), false, 0}, - // Profile 1 (no authentication) - {1, {}, false, 0}}; + const vector testProfiles = {// Profile 0 (reader authentication) + {0, readerCertificate.value(), false, 0}, + // Profile 1 (no authentication) + {1, {}, false, 0}}; HardwareAuthToken authToken; // Here's the actual test data: - const vector testEntries = { + const vector testEntries = { {"PersonalData", "Last name", string("Turing"), vector{0, 1}}, {"PersonalData", "Birth date", string("19120623"), vector{0, 1}}, {"PersonalData", "First name", string("Alan"), vector{0, 1}}, @@ -155,67 +100,33 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { string cborPretty; sp writableCredential; - string docType = "org.iso.18013-5.2019.mdl"; - bool testCredential = true; - ASSERT_TRUE(credentialStore_->createCredential(docType, testCredential, &writableCredential) - .isOk()); - ASSERT_NE(writableCredential, nullptr); + ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); string challenge = "attestationChallenge"; + test_utils::AttestationData attData(writableCredential, challenge, {}); + ASSERT_TRUE(attData.result.isOk()) + << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl; + ASSERT_EQ(binder::Status::EX_NONE, attData.result.exceptionCode()); + ASSERT_EQ(IIdentityCredentialStore::STATUS_OK, attData.result.serviceSpecificErrorCode()); + // TODO: set it to something random and check it's in the cert chain - vector attestationApplicationId = {}; - vector attestationChallenge(challenge.begin(), challenge.end()); - vector attestationCertificates; - ASSERT_TRUE(writableCredential - ->getAttestationCertificate(attestationApplicationId, attestationChallenge, - &attestationCertificates) - .isOk()); - ASSERT_GE(attestationCertificates.size(), 2); + ASSERT_GE(attData.attestationCertificate.size(), 2); ASSERT_TRUE( writableCredential->startPersonalization(testProfiles.size(), testEntriesEntryCounts) .isOk()); - vector returnedSecureProfiles; - for (const auto& testProfile : testProfiles) { - SecureAccessControlProfile profile; - Certificate cert; - cert.encodedCertificate = testProfile.readerCertificate; - ASSERT_TRUE(writableCredential - ->addAccessControlProfile(testProfile.id, cert, - testProfile.userAuthenticationRequired, - testProfile.timeoutMillis, - 0, // secureUserId - &profile) - .isOk()); - ASSERT_EQ(testProfile.id, profile.id); - ASSERT_EQ(testProfile.readerCertificate, profile.readerCertificate.encodedCertificate); - ASSERT_EQ(testProfile.userAuthenticationRequired, profile.userAuthenticationRequired); - ASSERT_EQ(testProfile.timeoutMillis, profile.timeoutMillis); - ASSERT_EQ(support::kAesGcmTagSize + support::kAesGcmIvSize, profile.mac.size()); - returnedSecureProfiles.push_back(profile); - } + optional> secureProfiles = + test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + ASSERT_TRUE(secureProfiles); // Uses TestEntryData* pointer as key and values are the encrypted blobs. This // is a little hacky but it works well enough. - map>> encryptedBlobs; + map>> encryptedBlobs; for (const auto& entry : testEntries) { - vector> chunks = - support::chunkVector(entry.valueCbor, hwInfo.dataChunkSize); - - ASSERT_TRUE(writableCredential - ->beginAddEntry(entry.profileIds, entry.nameSpace, entry.name, - entry.valueCbor.size()) - .isOk()); - - vector> encryptedChunks; - for (const auto& chunk : chunks) { - vector encryptedChunk; - ASSERT_TRUE(writableCredential->addEntryValue(chunk, &encryptedChunk).isOk()); - encryptedChunks.push_back(encryptedChunk); - } - encryptedBlobs[&entry] = encryptedChunks; + ASSERT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize, + encryptedBlobs, true)); } vector credentialData; @@ -276,8 +187,8 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { "]", cborPretty); - optional> credentialPubKey = - support::certificateChainGetTopMostKey(attestationCertificates[0].encodedCertificate); + optional> credentialPubKey = support::certificateChainGetTopMostKey( + attData.attestationCertificate[0].encodedCertificate); ASSERT_TRUE(credentialPubKey); EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfProvisioningSignature, {}, // Additional data @@ -347,8 +258,8 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { .add(cppbor::Semantic(24, itemsRequestBytes)) .encode(); optional> readerSignature = - support::coseSignEcDsa(readerKey.value(), {}, // content - dataToSign, // detached content + support::coseSignEcDsa(readerKey, {}, // content + dataToSign, // detached content readerCertificate.value()); ASSERT_TRUE(readerSignature); @@ -358,7 +269,7 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk()); ASSERT_TRUE(credential - ->startRetrieval(returnedSecureProfiles, authToken, itemsRequestBytes, + ->startRetrieval(secureProfiles.value(), authToken, itemsRequestBytes, signingKeyBlob, sessionTranscriptBytes, readerSignature.value(), testEntriesEntryCounts) .isOk()); @@ -405,6 +316,8 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { cppbor::Array deviceAuthentication; deviceAuthentication.add("DeviceAuthentication"); deviceAuthentication.add(sessionTranscript.clone()); + + string docType = "org.iso.18013-5.2019.mdl"; deviceAuthentication.add(docType); deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes)); vector encodedDeviceAuthentication = deviceAuthentication.encode(); diff --git a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp new file mode 100644 index 0000000000..56b30af9a4 --- /dev/null +++ b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp @@ -0,0 +1,649 @@ +/* + * 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 "VtsIWritableIdentityCredentialTests" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "VtsIdentityTestUtils.h" + +namespace android::hardware::identity { + +using std::endl; +using std::map; +using std::optional; +using std::string; +using std::vector; + +using ::android::sp; +using ::android::String16; +using ::android::binder::Status; + +class IdentityCredentialTests : public testing::TestWithParam { + public: + virtual void SetUp() override { + credentialStore_ = android::waitForDeclaredService( + String16(GetParam().c_str())); + ASSERT_NE(credentialStore_, nullptr); + } + + sp credentialStore_; +}; + +TEST_P(IdentityCredentialTests, verifyAttestationWithEmptyChallenge) { + Status result; + sp writableCredential; + ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + + vector attestationChallenge; + vector attestationCertificate; + vector attestationApplicationId = {}; + result = writableCredential->getAttestationCertificate( + attestationApplicationId, attestationChallenge, &attestationCertificate); + + EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + + EXPECT_TRUE(test_utils::ValidateAttestationCertificate(attestationCertificate)); +} + +TEST_P(IdentityCredentialTests, verifyAttestationSuccessWithChallenge) { + Status result; + sp writableCredential; + ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + + string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1"; + vector attestationChallenge(challenge.begin(), challenge.end()); + vector attestationCertificate; + vector attestationApplicationId = {}; + + result = writableCredential->getAttestationCertificate( + attestationApplicationId, attestationChallenge, &attestationCertificate); + + EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + + EXPECT_TRUE(test_utils::ValidateAttestationCertificate(attestationCertificate)); +} + +TEST_P(IdentityCredentialTests, verifyAttestationDoubleCallFails) { + Status result; + sp writableCredential; + ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + + string challenge = "NotSoRandomChallenge1"; + test_utils::AttestationData attData(writableCredential, challenge, {}); + ASSERT_TRUE(test_utils::ValidateAttestationCertificate(attData.attestationCertificate)); + + string challenge2 = "NotSoRandomChallenge2"; + test_utils::AttestationData attData2(writableCredential, challenge2, {}); + EXPECT_FALSE(attData2.result.isOk()) << attData2.result.exceptionCode() << "; " + << attData2.result.exceptionMessage() << endl; + EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, attData2.result.exceptionCode()); + EXPECT_EQ(IIdentityCredentialStore::STATUS_FAILED, attData2.result.serviceSpecificErrorCode()); +} + +TEST_P(IdentityCredentialTests, verifyStartPersonalization) { + Status result; + sp writableCredential; + ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + + // First call should go through + const vector entryCounts = {2, 4}; + result = writableCredential->startPersonalization(5, entryCounts); + ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + + // Call personalization again to check if repeat call is allowed. + result = writableCredential->startPersonalization(7, entryCounts); + + // Second call to startPersonalization should have failed. + EXPECT_FALSE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode()); + EXPECT_EQ(IIdentityCredentialStore::STATUS_FAILED, result.serviceSpecificErrorCode()); +} + +TEST_P(IdentityCredentialTests, verifyStartPersonalizationMin) { + Status result; + sp writableCredential; + ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + + // 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); + EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; +} + +TEST_P(IdentityCredentialTests, verifyStartPersonalizationOne) { + Status result; + sp writableCredential; + ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + + // Verify minimal number of profile count and entry count + const vector entryCounts = {1}; + writableCredential->startPersonalization(1, entryCounts); + EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; +} + +TEST_P(IdentityCredentialTests, verifyStartPersonalizationLarge) { + Status result; + sp writableCredential; + ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + + // Verify set a large number of profile count and entry count is ok + const vector entryCounts = {3000}; + writableCredential->startPersonalization(3500, entryCounts); + EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; +} + +TEST_P(IdentityCredentialTests, verifyProfileNumberMismatchShouldFail) { + Status result; + sp writableCredential; + ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + + // Enter mismatched entry and profile numbers + const vector entryCounts = {5, 6}; + writableCredential->startPersonalization(5, entryCounts); + ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + + optional> readerCertificate = test_utils::GenerateReaderCertificate("12345"); + ASSERT_TRUE(readerCertificate); + + const vector testProfiles = {// Profile 0 (reader authentication) + {1, readerCertificate.value(), false, 0}, + {2, readerCertificate.value(), true, 1}, + // Profile 4 (no authentication) + {4, {}, false, 0}}; + + optional> secureProfiles = + test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + ASSERT_TRUE(secureProfiles); + + vector credentialData; + vector proofOfProvisioningSignature; + result = + writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature); + + // finishAddingEntries should fail because the number of addAccessControlProfile mismatched with + // startPersonalization, and begintest_utils::AddEntry was not called. + 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, verifyDuplicateProfileId) { + Status result; + sp writableCredential; + ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + + const vector entryCounts = {3, 6}; + writableCredential->startPersonalization(3, entryCounts); + ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + + const vector testProfiles = {// first profile should go though + {1, {}, true, 2}, + // same id, different + // authentication requirement + {1, {}, true, 1}, + // same id, different certificate + {1, {}, false, 0}}; + + bool expectOk = true; + for (const auto& testProfile : testProfiles) { + SecureAccessControlProfile profile; + Certificate cert; + cert.encodedCertificate = testProfile.readerCertificate; + result = writableCredential->addAccessControlProfile( + testProfile.id, cert, testProfile.userAuthenticationRequired, + testProfile.timeoutMillis, 0, &profile); + + if (expectOk) { + expectOk = false; + // for profile should be allowed though as there are no duplications + // yet. + ASSERT_TRUE(result.isOk()) + << result.exceptionCode() << "; " << result.exceptionMessage() + << "test profile id = " << testProfile.id << endl; + + ASSERT_EQ(testProfile.id, profile.id); + ASSERT_EQ(testProfile.readerCertificate, profile.readerCertificate.encodedCertificate); + ASSERT_EQ(testProfile.userAuthenticationRequired, profile.userAuthenticationRequired); + ASSERT_EQ(testProfile.timeoutMillis, profile.timeoutMillis); + ASSERT_EQ(support::kAesGcmTagSize + support::kAesGcmIvSize, profile.mac.size()); + } else { + // should not allow duplicate id profiles. + ASSERT_FALSE(result.isOk()) + << result.exceptionCode() << "; " << result.exceptionMessage() + << ". Test profile id = " << testProfile.id + << ", timeout=" << testProfile.timeoutMillis << endl; + ASSERT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode()); + ASSERT_EQ(IIdentityCredentialStore::STATUS_INVALID_DATA, + result.serviceSpecificErrorCode()); + } + } +} + +TEST_P(IdentityCredentialTests, verifyOneProfileAndEntryPass) { + Status result; + + HardwareInformation hwInfo; + ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); + + sp writableCredential; + ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + + string challenge = "NotSoRandomChallenge1"; + test_utils::AttestationData attData(writableCredential, challenge, {}); + EXPECT_TRUE(attData.result.isOk()) + << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl; + + const vector entryCounts = {1u}; + writableCredential->startPersonalization(1, entryCounts); + ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + + optional> readerCertificate1 = test_utils::GenerateReaderCertificate("123456"); + ASSERT_TRUE(readerCertificate1); + + const vector testProfiles = {{1, readerCertificate1.value(), true, 1}}; + + optional> secureProfiles = + test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + ASSERT_TRUE(secureProfiles); + + const vector testEntries1 = { + {"Name Space", "Last name", string("Turing"), vector{0, 1}}, + }; + + map>> encryptedBlobs; + for (const auto& entry : testEntries1) { + ASSERT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize, + encryptedBlobs, true)); + } + + vector credentialData; + vector proofOfProvisioningSignature; + result = + writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature); + + EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + + optional> proofOfProvisioning = + support::coseSignGetPayload(proofOfProvisioningSignature); + ASSERT_TRUE(proofOfProvisioning); + string cborPretty = + support::cborPrettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"}); + EXPECT_EQ( + "[\n" + " 'ProofOfProvisioning',\n" + " 'org.iso.18013-5.2019.mdl',\n" + " [\n" + " {\n" + " 'id' : 1,\n" + " 'readerCertificate' : ,\n" + " 'userAuthenticationRequired' : true,\n" + " 'timeoutMillis' : 1,\n" + " },\n" + " ],\n" + " {\n" + " 'Name Space' : [\n" + " {\n" + " 'name' : 'Last name',\n" + " 'value' : 'Turing',\n" + " 'accessControlProfiles' : [0, 1, ],\n" + " },\n" + " ],\n" + " },\n" + " true,\n" + "]", + cborPretty); + + optional> credentialPubKey = support::certificateChainGetTopMostKey( + attData.attestationCertificate[0].encodedCertificate); + ASSERT_TRUE(credentialPubKey); + EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfProvisioningSignature, + {}, // Additional data + credentialPubKey.value())); +} + +TEST_P(IdentityCredentialTests, verifyManyProfilesAndEntriesPass) { + Status result; + + HardwareInformation hwInfo; + ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); + + sp writableCredential; + ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + + string challenge = "NotSoRandomChallenge"; + test_utils::AttestationData attData(writableCredential, challenge, {}); + EXPECT_TRUE(attData.result.isOk()) + << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl; + + optional> readerCertificate1 = test_utils::GenerateReaderCertificate("123456"); + ASSERT_TRUE(readerCertificate1); + + optional> readerCertificate2 = test_utils::GenerateReaderCertificate("1256"); + ASSERT_TRUE(readerCertificate2); + + const vector testProfiles = { + {1, readerCertificate1.value(), true, 1}, + {2, readerCertificate2.value(), true, 2}, + }; + const vector entryCounts = {1u, 3u, 1u, 1u, 2u}; + writableCredential->startPersonalization(testProfiles.size(), entryCounts); + ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + + optional> secureProfiles = + test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + ASSERT_TRUE(secureProfiles); + + vector portraitImage1; + test_utils::SetImageData(portraitImage1); + + vector portraitImage2; + test_utils::SetImageData(portraitImage2); + + const vector testEntries1 = { + {"Name Space 1", "Last name", string("Turing"), vector{1, 2}}, + {"Name Space2", "Home address", string("Maida Vale, London, England"), + vector{1}}, + {"Name Space2", "Work address", string("Maida Vale2, London, England"), + vector{2}}, + {"Name Space2", "Trailer address", string("Maida, London, England"), + vector{1}}, + {"Image", "Portrait image", portraitImage1, vector{1}}, + {"Image2", "Work image", portraitImage2, vector{1, 2}}, + {"Name Space3", "xyzw", string("random stuff"), vector{1, 2}}, + {"Name Space3", "Something", string("Some string"), vector{2}}, + }; + + map>> encryptedBlobs; + for (const auto& entry : testEntries1) { + EXPECT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize, + encryptedBlobs, true)); + } + + vector credentialData; + vector proofOfProvisioningSignature; + result = + writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature); + + EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + + optional> proofOfProvisioning = + support::coseSignGetPayload(proofOfProvisioningSignature); + ASSERT_TRUE(proofOfProvisioning); + string cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), + 32, // + {"readerCertificate"}); + EXPECT_EQ( + "[\n" + " 'ProofOfProvisioning',\n" + " 'org.iso.18013-5.2019.mdl',\n" + " [\n" + " {\n" + " 'id' : 1,\n" + " 'readerCertificate' : ,\n" + " 'userAuthenticationRequired' : true,\n" + " 'timeoutMillis' : 1,\n" + " },\n" + " {\n" + " 'id' : 2,\n" + " 'readerCertificate' : ,\n" + " 'userAuthenticationRequired' : true,\n" + " 'timeoutMillis' : 2,\n" + " },\n" + " ],\n" + " {\n" + " 'Name Space 1' : [\n" + " {\n" + " 'name' : 'Last name',\n" + " 'value' : 'Turing',\n" + " 'accessControlProfiles' : [1, 2, ],\n" + " },\n" + " ],\n" + " 'Name Space2' : [\n" + " {\n" + " 'name' : 'Home address',\n" + " 'value' : 'Maida Vale, London, England',\n" + " 'accessControlProfiles' : [1, ],\n" + " },\n" + " {\n" + " 'name' : 'Work address',\n" + " 'value' : 'Maida Vale2, London, England',\n" + " 'accessControlProfiles' : [2, ],\n" + " },\n" + " {\n" + " 'name' : 'Trailer address',\n" + " 'value' : 'Maida, London, England',\n" + " 'accessControlProfiles' : [1, ],\n" + " },\n" + " ],\n" + " 'Image' : [\n" + " {\n" + " 'name' : 'Portrait image',\n" + " 'value' : ,\n" + " 'accessControlProfiles' : [1, ],\n" + " },\n" + " ],\n" + " 'Image2' : [\n" + " {\n" + " 'name' : 'Work image',\n" + " 'value' : ,\n" + " 'accessControlProfiles' : [1, 2, ],\n" + " },\n" + " ],\n" + " 'Name Space3' : [\n" + " {\n" + " 'name' : 'xyzw',\n" + " 'value' : 'random stuff',\n" + " 'accessControlProfiles' : [1, 2, ],\n" + " },\n" + " {\n" + " 'name' : 'Something',\n" + " 'value' : 'Some string',\n" + " 'accessControlProfiles' : [2, ],\n" + " },\n" + " ],\n" + " },\n" + " true,\n" + "]", + cborPretty); + + optional> credentialPubKey = support::certificateChainGetTopMostKey( + attData.attestationCertificate[0].encodedCertificate); + ASSERT_TRUE(credentialPubKey); + EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfProvisioningSignature, + {}, // Additional data + credentialPubKey.value())); +} + +TEST_P(IdentityCredentialTests, verifyEmptyNameSpaceMixedWithNonEmptyWorks) { + Status result; + + HardwareInformation hwInfo; + ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); + + sp writableCredential; + ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + + string challenge = "NotSoRandomChallenge"; + test_utils::AttestationData attData(writableCredential, challenge, {}); + ASSERT_TRUE(attData.result.isOk()) + << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl; + + const vector entryCounts = {2u, 2u}; + writableCredential->startPersonalization(3, entryCounts); + ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + + optional> readerCertificate1 = test_utils::GenerateReaderCertificate("123456"); + ASSERT_TRUE(readerCertificate1); + + optional> readerCertificate2 = + test_utils::GenerateReaderCertificate("123456987987987987987987"); + ASSERT_TRUE(readerCertificate2); + + const vector testProfiles = {{0, readerCertificate1.value(), false, 0}, + {1, readerCertificate2.value(), true, 1}, + {2, {}, false, 0}}; + + optional> secureProfiles = + test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + ASSERT_TRUE(secureProfiles); + + const vector testEntries1 = { + // test empty name space + {"", "t name", string("Turing"), vector{2}}, + {"", "Birth", string("19120623"), vector{2}}, + {"Name Space", "Last name", string("Turing"), vector{0, 1}}, + {"Name Space", "Birth date", string("19120623"), vector{0, 1}}, + }; + + map>> encryptedBlobs; + for (const auto& entry : testEntries1) { + EXPECT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize, + encryptedBlobs, true)); + } + + vector credentialData; + vector proofOfProvisioningSignature; + result = + writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature); + + EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; +} + +TEST_P(IdentityCredentialTests, verifyInterleavingEntryNameSpaceOrderingFails) { + Status result; + + HardwareInformation hwInfo; + ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); + + sp writableCredential; + ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + + string challenge = "NotSoRandomChallenge"; + test_utils::AttestationData attData(writableCredential, challenge, {}); + ASSERT_TRUE(attData.result.isOk()) + << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl; + + // Enter mismatched entry and profile numbers. + // Technically the 2nd name space of "Name Space" occurs intermittently, 2 + // 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); + ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + + optional> readerCertificate1 = test_utils::GenerateReaderCertificate("123456"); + ASSERT_TRUE(readerCertificate1); + + optional> readerCertificate2 = + test_utils::GenerateReaderCertificate("123456987987987987987987"); + ASSERT_TRUE(readerCertificate2); + + const vector testProfiles = {{0, readerCertificate1.value(), false, 0}, + {1, readerCertificate2.value(), true, 1}, + {2, {}, false, 0}}; + + optional> secureProfiles = + test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + ASSERT_TRUE(secureProfiles); + + const vector testEntries1 = { + // test empty name space + {"Name Space", "Last name", string("Turing"), vector{0, 1}}, + {"Name Space", "Birth date", string("19120623"), vector{0, 1}}, + }; + + map>> encryptedBlobs; + for (const auto& entry : testEntries1) { + EXPECT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize, + encryptedBlobs, true)); + } + const test_utils::TestEntryData testEntry2 = {"Image", "Portrait image", string("asdfs"), + vector{0, 1}}; + + EXPECT_TRUE(test_utils::AddEntry(writableCredential, testEntry2, hwInfo.dataChunkSize, + encryptedBlobs, true)); + + // We expect this to fail because the namespace is out of order, all "Name Space" + // should have been called together + const vector testEntries3 = { + {"Name Space", "First name", string("Alan"), vector{0, 1}}, + {"Name Space", "Home address", string("Maida Vale, London, England"), + vector{0}}, + }; + + for (const auto& entry : testEntries3) { + EXPECT_FALSE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize, + encryptedBlobs, false)); + } + + vector credentialData; + vector proofOfProvisioningSignature; + result = + writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature); + + // should fail because test_utils::AddEntry should have failed earlier. + 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()); +} + +INSTANTIATE_TEST_SUITE_P( + Identity, IdentityCredentialTests, + testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)), + android::PrintInstanceNameToString); + +} // namespace android::hardware::identity diff --git a/identity/aidl/vts/VtsIdentityTestUtils.cpp b/identity/aidl/vts/VtsIdentityTestUtils.cpp new file mode 100644 index 0000000000..3aeebc66b6 --- /dev/null +++ b/identity/aidl/vts/VtsIdentityTestUtils.cpp @@ -0,0 +1,179 @@ +/* + * Copyright 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. + */ + +#include "VtsIdentityTestUtils.h" + +#include +#include + +namespace android::hardware::identity::test_utils { + +using std::endl; +using std::map; +using std::optional; +using std::string; +using std::vector; + +using ::android::sp; +using ::android::String16; +using ::android::binder::Status; + +bool SetupWritableCredential(sp& writableCredential, + sp& credentialStore) { + if (credentialStore == nullptr) { + return false; + } + + string docType = "org.iso.18013-5.2019.mdl"; + bool testCredential = true; + Status result = credentialStore->createCredential(docType, testCredential, &writableCredential); + + if (result.isOk() && writableCredential != nullptr) { + return true; + } else { + return false; + } +} + +optional> GenerateReaderCertificate(string serialDecimal) { + vector privKey; + return GenerateReaderCertificate(serialDecimal, privKey); +} + +optional> GenerateReaderCertificate(string serialDecimal, + vector& readerPrivateKey) { + optional> readerKeyPKCS8 = support::createEcKeyPair(); + if (!readerKeyPKCS8) { + return {}; + } + + optional> readerPublicKey = + support::ecKeyPairGetPublicKey(readerKeyPKCS8.value()); + optional> readerKey = support::ecKeyPairGetPrivateKey(readerKeyPKCS8.value()); + if (!readerPublicKey || !readerKey) { + return {}; + } + + readerPrivateKey = readerKey.value(); + + string issuer = "Android Open Source Project"; + string subject = "Android IdentityCredential VTS Test"; + time_t validityNotBefore = time(nullptr); + time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600; + + return support::ecPublicKeyGenerateCertificate(readerPublicKey.value(), readerKey.value(), + serialDecimal, issuer, subject, + validityNotBefore, validityNotAfter); +} + +optional> AddAccessControlProfiles( + sp& writableCredential, + const vector& testProfiles) { + Status result; + + vector secureProfiles; + + for (const auto& testProfile : testProfiles) { + SecureAccessControlProfile profile; + Certificate cert; + cert.encodedCertificate = testProfile.readerCertificate; + result = writableCredential->addAccessControlProfile( + testProfile.id, cert, testProfile.userAuthenticationRequired, + testProfile.timeoutMillis, 0, &profile); + + // Don't use assert so all errors can be outputed. Then return + // instead of exit even on errors so caller can decide. + EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << "test profile id = " << testProfile.id << endl; + EXPECT_EQ(testProfile.id, profile.id); + EXPECT_EQ(testProfile.readerCertificate, profile.readerCertificate.encodedCertificate); + EXPECT_EQ(testProfile.userAuthenticationRequired, profile.userAuthenticationRequired); + EXPECT_EQ(testProfile.timeoutMillis, profile.timeoutMillis); + EXPECT_EQ(support::kAesGcmTagSize + support::kAesGcmIvSize, profile.mac.size()); + + if (!result.isOk() || testProfile.id != profile.id || + testProfile.readerCertificate != profile.readerCertificate.encodedCertificate || + testProfile.userAuthenticationRequired != profile.userAuthenticationRequired || + testProfile.timeoutMillis != profile.timeoutMillis || + support::kAesGcmTagSize + support::kAesGcmIvSize != profile.mac.size()) { + return {}; + } + + secureProfiles.push_back(profile); + } + + return secureProfiles; +} + +// Most test expects this function to pass. So we will print out additional +// value if failed so more debug data can be provided. +bool AddEntry(sp& writableCredential, const TestEntryData& entry, + int dataChunkSize, map>>& encryptedBlobs, + bool expectSuccess) { + Status result; + vector> chunks = support::chunkVector(entry.valueCbor, dataChunkSize); + + result = writableCredential->beginAddEntry(entry.profileIds, entry.nameSpace, entry.name, + entry.valueCbor.size()); + + if (expectSuccess) { + EXPECT_TRUE(result.isOk()) + << result.exceptionCode() << "; " << result.exceptionMessage() << endl + << "entry name = " << entry.name << ", name space=" << entry.nameSpace << endl; + } + + if (!result.isOk()) { + return false; + } + + vector> encryptedChunks; + for (const auto& chunk : chunks) { + vector encryptedContent; + result = writableCredential->addEntryValue(chunk, &encryptedContent); + if (expectSuccess) { + EXPECT_TRUE(result.isOk()) + << result.exceptionCode() << "; " << result.exceptionMessage() << endl + << "entry name = " << entry.name << ", name space = " << entry.nameSpace + << endl; + + EXPECT_GT(encryptedContent.size(), 0u) << "entry name = " << entry.name + << ", name space = " << entry.nameSpace << endl; + } + + if (!result.isOk() || encryptedContent.size() <= 0u) { + return false; + } + + encryptedChunks.push_back(encryptedContent); + } + + encryptedBlobs[&entry] = encryptedChunks; + return true; +} + +bool ValidateAttestationCertificate(vector& inputCertificates) { + return (inputCertificates.size() >= 2); + // TODO: add parsing of the certificate and make sure it is genuine. +} + +void SetImageData(vector& image) { + image.resize(256 * 1024 - 10); + for (size_t n = 0; n < image.size(); n++) { + image[n] = (uint8_t)n; + } +} + +} // namespace android::hardware::identity::test_utils diff --git a/identity/aidl/vts/VtsIdentityTestUtils.h b/identity/aidl/vts/VtsIdentityTestUtils.h new file mode 100644 index 0000000000..043ccd6905 --- /dev/null +++ b/identity/aidl/vts/VtsIdentityTestUtils.h @@ -0,0 +1,118 @@ +/* + * Copyright 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. + */ + +#ifndef VTS_IDENTITY_TEST_UTILS_H +#define VTS_IDENTITY_TEST_UTILS_H + +#include +#include +#include +#include + +namespace android::hardware::identity::test_utils { + +using ::std::map; +using ::std::optional; +using ::std::string; +using ::std::vector; + +using ::android::sp; +using ::android::binder::Status; + +struct AttestationData { + AttestationData(sp& writableCredential, string challenge, + vector applicationId) + : attestationApplicationId(applicationId) { + // ASSERT_NE(writableCredential, nullptr); + + if (!challenge.empty()) { + attestationChallenge.assign(challenge.begin(), challenge.end()); + } + + result = writableCredential->getAttestationCertificate( + attestationApplicationId, attestationChallenge, &attestationCertificate); + } + + AttestationData() {} + + vector attestationChallenge; + vector attestationApplicationId; + vector attestationCertificate; + Status result; +}; + +struct TestEntryData { + TestEntryData(string nameSpace, string name, vector profileIds) + : nameSpace(nameSpace), name(name), profileIds(profileIds) {} + + TestEntryData(string nameSpace, string name, const string& value, vector profileIds) + : TestEntryData(nameSpace, name, profileIds) { + valueCbor = cppbor::Tstr(((const char*)value.data())).encode(); + } + TestEntryData(string nameSpace, string name, const vector& value, + vector profileIds) + : TestEntryData(nameSpace, name, profileIds) { + valueCbor = cppbor::Bstr(value).encode(); + } + TestEntryData(string nameSpace, string name, bool value, vector profileIds) + : TestEntryData(nameSpace, name, profileIds) { + valueCbor = cppbor::Bool(value).encode(); + } + TestEntryData(string nameSpace, string name, int64_t value, vector profileIds) + : TestEntryData(nameSpace, name, profileIds) { + if (value >= 0) { + valueCbor = cppbor::Uint(value).encode(); + } else { + valueCbor = cppbor::Nint(-value).encode(); + } + } + + string nameSpace; + string name; + vector valueCbor; + vector profileIds; +}; + +struct TestProfile { + uint16_t id; + vector readerCertificate; + bool userAuthenticationRequired; + uint64_t timeoutMillis; +}; + +bool SetupWritableCredential(sp& writableCredential, + sp& credentialStore); + +optional> GenerateReaderCertificate(string serialDecimal); + +optional> GenerateReaderCertificate(string serialDecimal, + vector& readerPrivateKey); + +optional> AddAccessControlProfiles( + sp& writableCredential, + const vector& testProfiles); + +bool AddEntry(sp& writableCredential, const TestEntryData& entry, + int dataChunkSize, map>>& encryptedBlobs, + bool expectSuccess); + +bool ValidateAttestationCertificate(vector& inputCertificates); + +void SetImageData(vector& image); + +} // namespace android::hardware::identity::test_utils + +#endif // VTS_IDENTITY_TEST_UTILS_H diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp index bf6a5c3c45..dc49ddc992 100644 --- a/identity/support/src/IdentityCredentialSupport.cpp +++ b/identity/support/src/IdentityCredentialSupport.cpp @@ -958,12 +958,17 @@ optional, vector>>> createEcKeyPairAnd optional> createEcKeyPair() { auto ec_key = EC_KEY_Ptr(EC_KEY_new()); auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new()); - auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); if (ec_key.get() == nullptr || pkey.get() == nullptr) { LOG(ERROR) << "Memory allocation failed"; return {}; } + auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); + if (group.get() == nullptr) { + LOG(ERROR) << "Error creating EC group by curve name"; + return {}; + } + if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 || EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) { LOG(ERROR) << "Error generating key"; From 5db41c8698a5a0d2163adcf5532dc246a805c4cb Mon Sep 17 00:00:00 2001 From: Hall Liu Date: Wed, 8 Apr 2020 18:44:29 -0700 Subject: [PATCH 0875/1022] Allow android.hardware.radio 1.4 for R SOC manufacturers have requested that devices be allowed to ship with R without using the IRadio 1.5 API. Fixes: 153495340 Test: build flame Change-Id: Iba2ac5902e69fc0af0c5f4d7cae4fed77204acd1 --- compatibility_matrices/compatibility_matrix.5.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/compatibility_matrices/compatibility_matrix.5.xml b/compatibility_matrices/compatibility_matrix.5.xml index 1b051f5576..e772b6fe1d 100644 --- a/compatibility_matrices/compatibility_matrix.5.xml +++ b/compatibility_matrices/compatibility_matrix.5.xml @@ -371,6 +371,7 @@ android.hardware.radio + 1.4 1.5 IRadio From 602753593ee0bf881edd9aa4fbad01d23dd16158 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Mon, 27 Apr 2020 15:24:55 -0400 Subject: [PATCH 0876/1022] Identity Credential: Restrict AccessControlProfile identifiers to 32. In order to implement Identity Credential on resource-restricted secure hardware, we need to limit the number of possible AccessControlProfile in a credential. A limit of 32 means that such hardware only need to devote four bytes of RAM for a bitmask with information about which profiles are authorized. Document this, add new VTS test, and update the default implementation. Bug: 155100967 Test: atest android.security.identity.cts Test: atest VtsHalIdentityTargetTest Merged-In: Ia4f2ee0013b330561df744e0595f298a0d156122 Change-Id: I2dd672447bedfa9407bf1044e6261af26fd137f9 --- .../identity/IWritableIdentityCredential.aidl | 3 +- .../default/WritableIdentityCredential.cpp | 6 ++++ .../VtsIWritableIdentityCredentialTests.cpp | 34 +++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl index 9673821b82..07486e6001 100644 --- a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl +++ b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl @@ -140,7 +140,8 @@ interface IWritableIdentityCredential { * with STATUS_INVALID_DATA. * * @param id a numeric identifier that must be unique within the context of a Credential and may - * be used to reference the profile. If this is not satisfied the call fails with + * be used to reference the profile. This id must be non-negative and less than 32 (allowing + * for a total of 32 profiles). If this is not satisfied the call fails with * STATUS_INVALID_DATA. * * @param readerCertificate if non-empty, specifies a single X.509 certificate (not a chain of diff --git a/identity/aidl/default/WritableIdentityCredential.cpp b/identity/aidl/default/WritableIdentityCredential.cpp index 553a3d832b..52cd49600f 100644 --- a/identity/aidl/default/WritableIdentityCredential.cpp +++ b/identity/aidl/default/WritableIdentityCredential.cpp @@ -143,6 +143,12 @@ ndk::ScopedAStatus WritableIdentityCredential::addAccessControlProfile( } accessControlProfileIds_.insert(id); + if (id < 0 || id >= 32) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + IIdentityCredentialStore::STATUS_INVALID_DATA, + "Access Control Profile id must be non-negative and less than 32")); + } + // Spec requires if |userAuthenticationRequired| is false, then |timeoutMillis| must also // be zero. if (!userAuthenticationRequired && timeoutMillis != 0) { diff --git a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp index 56b30af9a4..b68fbb54f1 100644 --- a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp +++ b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp @@ -641,6 +641,40 @@ TEST_P(IdentityCredentialTests, verifyInterleavingEntryNameSpaceOrderingFails) { EXPECT_EQ(IIdentityCredentialStore::STATUS_INVALID_DATA, result.serviceSpecificErrorCode()); } +TEST_P(IdentityCredentialTests, verifyAccessControlProfileIdOutOfRange) { + sp writableCredential; + ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + + const vector entryCounts = {1}; + Status result = writableCredential->startPersonalization(1, entryCounts); + ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + + SecureAccessControlProfile profile; + + // This should fail because the id is >= 32 + result = writableCredential->addAccessControlProfile(32, // id + {}, // readerCertificate + false, // userAuthenticationRequired + 0, // timeoutMillis + 42, // secureUserId + &profile); + ASSERT_FALSE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage(); + ASSERT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode()); + ASSERT_EQ(IIdentityCredentialStore::STATUS_INVALID_DATA, result.serviceSpecificErrorCode()); + + // This should fail because the id is < 0 + result = writableCredential->addAccessControlProfile(-1, // id + {}, // readerCertificate + false, // userAuthenticationRequired + 0, // timeoutMillis + 42, // secureUserId + &profile); + ASSERT_FALSE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage(); + ASSERT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode()); + ASSERT_EQ(IIdentityCredentialStore::STATUS_INVALID_DATA, result.serviceSpecificErrorCode()); +} + INSTANTIATE_TEST_SUITE_P( Identity, IdentityCredentialTests, testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)), From 5bd2a350adf6044310384649a91047f0b44af1c7 Mon Sep 17 00:00:00 2001 From: Devin Moore Date: Wed, 22 Apr 2020 15:49:21 -0700 Subject: [PATCH 0877/1022] Convert Python OMX VTS test to Gtest Moving the extra tests from test/vts-testcase/hal/media/omx/V1_0/host_omxstore/VtsHalMediaOmxStoreV1_0HostTest.py to the OMX Gtest in VtsHalMediaOmxV1_0TargetMasterTest. This is mostly validating the RoleInfo and NodeInfo data obtained from IOmxStore interface. Bug: 152237762 Test: atest VtsHalMediaOmxV1_0TargetMasterTest on cf and pixel devices Change-Id: I8174b8953ee5e484777afb21b2d170cec0159edc --- .../omx/1.0/vts/functional/master/Android.bp | 1 + .../VtsHalMediaOmxV1_0TargetMasterTest.cpp | 343 +++++++++++++++++- 2 files changed, 325 insertions(+), 19 deletions(-) diff --git a/media/omx/1.0/vts/functional/master/Android.bp b/media/omx/1.0/vts/functional/master/Android.bp index 8e58821e12..5953eb5681 100644 --- a/media/omx/1.0/vts/functional/master/Android.bp +++ b/media/omx/1.0/vts/functional/master/Android.bp @@ -19,6 +19,7 @@ cc_test { defaults: ["VtsHalMediaOmxV1_0Defaults"], srcs: ["VtsHalMediaOmxV1_0TargetMasterTest.cpp"], test_suites: [ + "general-tests", "vts", ], } 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 c14f1da8bc..9b4722ec57 100644 --- a/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp +++ b/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp @@ -20,6 +20,7 @@ #endif #include +#include #include #include @@ -33,21 +34,22 @@ #include #include -using ::android::hardware::media::omx::V1_0::IOmx; -using ::android::hardware::media::omx::V1_0::IOmxObserver; -using ::android::hardware::media::omx::V1_0::IOmxNode; -using ::android::hardware::media::omx::V1_0::IOmxStore; -using ::android::hardware::media::omx::V1_0::Message; -using ::android::hardware::media::omx::V1_0::CodecBuffer; -using ::android::hardware::media::omx::V1_0::PortMode; -using ::android::hidl::allocator::V1_0::IAllocator; -using ::android::hidl::memory::V1_0::IMemory; -using ::android::hidl::memory::V1_0::IMapper; +using ::android::sp; +using ::android::base::Join; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using ::android::hardware::media::omx::V1_0::CodecBuffer; +using ::android::hardware::media::omx::V1_0::IOmx; +using ::android::hardware::media::omx::V1_0::IOmxNode; +using ::android::hardware::media::omx::V1_0::IOmxObserver; +using ::android::hardware::media::omx::V1_0::IOmxStore; +using ::android::hardware::media::omx::V1_0::Message; +using ::android::hardware::media::omx::V1_0::PortMode; +using ::android::hidl::allocator::V1_0::IAllocator; +using ::android::hidl::memory::V1_0::IMapper; +using ::android::hidl::memory::V1_0::IMemory; #include #include @@ -70,6 +72,11 @@ class MasterHidlTest : public ::testing::TestWithParam { } }; +struct AttributePattern { + const testing::internal::RE key; + const testing::internal::RE value; +}; + void displayComponentInfo(hidl_vec& nodeList) { for (size_t i = 0; i < nodeList.size(); i++) { printf("%s | ", nodeList[i].mName.c_str()); @@ -80,6 +87,109 @@ 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, + hidl_vec attributes) { + std::set attributeKeys; + for (const auto& attr : attributes) { + // Make sure there are no duplicates + const auto [nodeIter, inserted] = attributeKeys.insert(attr.key); + EXPECT_EQ(inserted, true) << "Attribute \"" << attr.key << "\" has duplicates."; + + // Check the value against the corresponding regular + // expression. + const auto knownPattern = knownPatterns.find(attr.key); + if (knownPattern != knownPatterns.end()) { + EXPECT_EQ(testing::internal::RE::FullMatch(attr.value, knownPattern->second), true) + << "Attribute \"" << attr.key << "\" has invalid value \"" << attr.value << "."; + ; + } else { + // Failed to find exact attribute, check against + // possible patterns. + bool keyFound = false; + for (const auto& unknownPattern : unknownPatterns) { + if (testing::internal::RE::PartialMatch(attr.key, unknownPattern.key)) { + keyFound = true; + EXPECT_EQ(testing::internal::RE::FullMatch(attr.value, unknownPattern.value), + true) + << "Attribute \"" << attr.key << "\" has invalid value \"" << attr.value + << "."; + } + } + if (!keyFound) { + std::cout << "Warning, Unrecognized attribute \"" << attr.key << "\" with value \"" + << attr.value << "\"." << std::endl; + } + } + } +} + // Make sure IOmx and IOmxStore have the same set of instances. TEST(MasterHidlTest, instanceMatchValidation) { auto omxInstances = android::hardware::getAllHalInstanceNames(IOmx::descriptor); @@ -91,7 +201,7 @@ TEST(MasterHidlTest, instanceMatchValidation) { } } -// list service attributes +// list service attributes and verify expected formats TEST_P(MasterHidlTest, ListServiceAttr) { description("list service attributes"); android::hardware::media::omx::V1_0::Status status; @@ -105,7 +215,36 @@ TEST_P(MasterHidlTest, ListServiceAttr) { }) .isOk()); ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); - if (attributes.size() == 0) ALOGV("Warning, Attribute list empty"); + if (attributes.size() == 0) { + std::cout << "Warning, Attribute list empty" << std::endl; + } else { + /* + * knownPatterns is a map whose keys are the known "key" for a service + * attribute pair (see IOmxStore::Attribute), and whose values are the + * corresponding regular expressions that will have to match with the + * "value" of the attribute pair. If listServiceAttributes() returns an + * attribute that has a matching key but an unmatched value, the test + * will fail. + */ + const std::map knownPatterns = { + {"max-video-encoder-input-buffers", "0|[1-9][0-9]*"}, + {"supports-multiple-secure-codecs", "0|1"}, + {"supports-secure-with-non-secure-codec", "0|1"}, + }; + /* + * unknownPatterns is a vector of pairs of regular expressions. + * For each attribute whose key is not known (i.e., does not match any + * of the keys in the "knownPatterns" variable defined above), that key will be + * tried for a match with the first element of each pair of the variable + * "unknownPatterns". If a match occurs, the value of that same attribute will be + * tried for a match with the second element of the pair. If this second + * match fails, the test will fail. + */ + const std::vector unknownPatterns = { + {"supports-[a-z0-9-]*", "0|1"}}; + + validateAttributes(knownPatterns, unknownPatterns, attributes); + } } // get node prefix @@ -114,17 +253,183 @@ TEST_P(MasterHidlTest, getNodePrefix) { hidl_string prefix; omxStore->getNodePrefix( [&prefix](hidl_string const& _nl) { prefix = _nl; }); - if (prefix.empty()) ALOGV("Warning, Node Prefix empty"); + if (prefix.empty()) std::cout << "Warning, Node Prefix empty" << std::endl; } -// list roles +// list roles and validate all RoleInfo objects TEST_P(MasterHidlTest, ListRoles) { description("list roles"); hidl_vec roleList; omxStore->listRoles([&roleList](hidl_vec const& _nl) { roleList = _nl; }); - if (roleList.size() == 0) ALOGV("Warning, RoleInfo list empty"); + if (roleList.size() == 0) { + GTEST_SKIP() << "Warning, RoleInfo list empty"; + return; + } + + // Basic patterns for matching + const std::string toggle = "(0|1)"; + const std::string string = "(.*)"; + const std::string num = "(0|([1-9][0-9]*))"; + const std::string size = "(" + num + "x" + num + ")"; + const std::string ratio = "(" + num + ":" + num + ")"; + const std::string range_num = "((" + num + "-" + num + ")|" + num + ")"; + const std::string range_size = "((" + size + "-" + size + ")|" + size + ")"; + const std::string range_ratio = "((" + ratio + "-" + ratio + ")|" + ratio + ")"; + const std::string list_range_num = "(" + range_num + "(," + range_num + ")*)"; + + // Matching rules for node attributes with fixed keys + const std::map knownPatterns = { + {"alignment", size}, + {"bitrate-range", range_num}, + {"block-aspect-ratio-range", range_ratio}, + {"block-count-range", range_num}, + {"block-size", size}, + {"blocks-per-second-range", range_num}, + {"complexity-default", num}, + {"complexity-range", range_num}, + {"feature-adaptive-playback", toggle}, + {"feature-bitrate-control", "(VBR|CBR|CQ)[,(VBR|CBR|CQ)]*"}, + {"feature-can-swap-width-height", toggle}, + {"feature-intra-refresh", toggle}, + {"feature-partial-frame", toggle}, + {"feature-secure-playback", toggle}, + {"feature-tunneled-playback", toggle}, + {"frame-rate-range", range_num}, + {"max-channel-count", num}, + {"max-concurrent-instances", num}, + {"max-supported-instances", num}, + {"pixel-aspect-ratio-range", range_ratio}, + {"quality-default", num}, + {"quality-range", range_num}, + {"quality-scale", string}, + {"sample-rate-ranges", list_range_num}, + {"size-range", range_size}, + }; + + // Strings for matching rules for node attributes with key patterns + const std::vector unknownPatterns = { + {"measured-frame-rate-" + size + "-range", range_num}, + {"feature-[a-zA-Z0-9_-]+", string}, + }; + + // Matching rules for node names and owners + const testing::internal::RE nodeNamePattern = "[a-zA-Z0-9.-]+"; + const testing::internal::RE nodeOwnerPattern = "[a-zA-Z0-9._-]+"; + + std::set roleKeys; + std::map> nodeToRoles; + std::map> ownerToNodes; + for (const IOmxStore::RoleInfo& role : roleList) { + // Make sure there are no duplicates + const auto [roleIter, inserted] = roleKeys.insert(role.role); + EXPECT_EQ(inserted, true) << "Role \"" << role.role << "\" has duplicates."; + + // Make sure role name follows expected format based on type and + // isEncoder + const std::string role_name = getComponentRole(role.isEncoder, role.type); + EXPECT_EQ(role_name, role.role) << "Role \"" << role.role << "\" does not match " + << (role.isEncoder ? "an encoder " : "a decoder ") + << "for mime type \"" << role.type << "."; + + // Check the nodes for this role + std::set nodeKeys; + for (const IOmxStore::NodeInfo& node : role.nodes) { + // Make sure there are no duplicates + const auto [nodeIter, inserted] = nodeKeys.insert(node.name); + EXPECT_EQ(inserted, true) << "Node \"" << node.name << "\" has duplicates."; + + // Check the format of node name + EXPECT_EQ(testing::internal::RE::FullMatch(node.name, nodeNamePattern), true) + << "Node name \"" << node.name << " is invalid."; + // Check the format of node owner + EXPECT_EQ(testing::internal::RE::FullMatch(node.owner, nodeOwnerPattern), true) + << "Node owner \"" << node.owner << " is invalid."; + + validateAttributes(knownPatterns, unknownPatterns, node.attributes); + + ownerToNodes[node.owner].insert(node.name); + nodeToRoles[node.name].insert(role.role); + } + } + + // Verify the information with IOmx::listNodes(). + // IOmxStore::listRoles() and IOmx::listNodes() should give consistent + // information about nodes and roles. + for (const auto& [owner, nodes] : ownerToNodes) { + // Obtain the IOmx instance for each "owner" + const sp omx = omxStore->getOmx(owner); + EXPECT_NE(nullptr, omx); + + // Invoke IOmx::listNodes() + android::hardware::media::omx::V1_0::Status status; + hidl_vec nodeList; + EXPECT_TRUE( + omx->listNodes([&status, &nodeList](android::hardware::media::omx::V1_0::Status _s, + hidl_vec const& _nl) { + status = _s; + nodeList = _nl; + }).isOk()); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); + + // Verify that roles for each node match with the information from + // IOmxStore::listRoles(). + std::set nodeKeys; + for (IOmx::ComponentInfo node : nodeList) { + // Make sure there are no duplicates + const auto [nodeIter, inserted] = nodeKeys.insert(node.mName); + EXPECT_EQ(inserted, true) + << "IOmx::listNodes() lists duplicate nodes \"" << node.mName << "\"."; + + // Skip "hidden" nodes, i.e. those that are not advertised by + // IOmxStore::listRoles(). + if (nodes.find(node.mName) == nodes.end()) { + std::cout << "Warning, IOmx::listNodes() lists unknown node \"" << node.mName + << "\" for IOmx instance \"" << owner << "\"." << std::endl; + continue; + } + + // All the roles advertised by IOmxStore::listRoles() for this + // node must be included in roleKeys. + std::set difference; + std::set_difference(nodeToRoles[node.mName].begin(), nodeToRoles[node.mName].end(), + roleKeys.begin(), roleKeys.end(), + std::inserter(difference, difference.begin())); + EXPECT_EQ(difference.empty(), true) << "IOmx::listNodes() for IOmx " + "instance \"" + << owner + << "\" does not report some " + "expected nodes: " + << android::base::Join(difference, ", ") << "."; + } + // Check that all nodes obtained from IOmxStore::listRoles() are + // supported by the their corresponding IOmx instances. + std::set difference; + std::set_difference(nodes.begin(), nodes.end(), nodeKeys.begin(), nodeKeys.end(), + std::inserter(difference, difference.begin())); + EXPECT_EQ(difference.empty(), true) << "IOmx::listNodes() for IOmx " + "instance \"" + << owner + << "\" does not report some " + "expected nodes: " + << android::base::Join(difference, ", ") << "."; + } + + if (!nodeToRoles.empty()) { + // Check that the prefix is a sensible string. + hidl_string prefix; + omxStore->getNodePrefix([&prefix](hidl_string const& _nl) { prefix = _nl; }); + EXPECT_EQ(testing::internal::RE::PartialMatch(prefix, nodeNamePattern), true) + << "\"" << prefix << "\" is not a valid prefix for node names."; + + // Check that all node names have the said prefix. + for (const auto& node : nodeToRoles) { + EXPECT_NE(node.first.rfind(prefix, 0), std::string::npos) + << "Node \"" << node.first << "\" does not start with prefix \"" << prefix + << "\"."; + } + } } // list components and roles. @@ -143,7 +448,7 @@ TEST_P(MasterHidlTest, ListNodes) { .isOk()); ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); if (nodeList.size() == 0) - ALOGV("Warning, ComponentInfo list empty"); + std::cout << "Warning, ComponentInfo list empty" << std::endl; else { // displayComponentInfo(nodeList); for (size_t i = 0; i < nodeList.size(); i++) { From 7612f161a7619ff65cc804d34b64902d7ba6cc84 Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Thu, 23 Apr 2020 23:07:09 -0700 Subject: [PATCH 0878/1022] vts camera characteristtics: add tests for system camera restrictions. The system camera kind of physical cameras which are public, should be the same as the system camera kind of the logical cameras they back. The system camera kinds of all logical cameras that share the same hidden physical cameras must be the same. Bug: 152053830 Test: VtsHalCameraProviderV2_4TargetTest --gtest_filter=PerInstance/CameraHidlTest.getCameraCharacter* Test: VtsHalCameraProviderV2_4TargetTest --gtest_filter=PerInstance/CameraHidlTest.systemCamera* Change-Id: Iba07a6aa4a5fb465e9e0c4d0adedf6becaba7d14 Signed-off-by: Jayant Chowdhary --- .../VtsHalCameraProviderV2_4TargetTest.cpp | 183 ++++++++++++++++-- 1 file changed, 166 insertions(+), 17 deletions(-) diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 05b8b47caa..bf5fbfe692 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -18,12 +18,13 @@ #include #include +#include +#include #include #include #include #include #include -#include #include @@ -165,6 +166,26 @@ enum ReprocessType { YUV_REPROCESS, }; +enum SystemCameraKind { + /** + * These camera devices are visible to all apps and system components alike + */ + PUBLIC = 0, + + /** + * These camera devices are visible only to processes having the + * android.permission.SYSTEM_CAMERA permission. They are not exposed to 3P + * apps. + */ + SYSTEM_ONLY_CAMERA, + + /** + * These camera devices are visible only to HAL clients (that try to connect + * on a hwbinder thread). + */ + HIDDEN_SECURE_CAMERA +}; + namespace { // "device@/legacy/" const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)"; @@ -851,6 +872,8 @@ public: static Status isAutoFocusModeAvailable( CameraParameters &cameraParams, const char *mode) ; static Status isMonochromeCamera(const camera_metadata_t *staticMeta); + static Status getSystemCameraKind(const camera_metadata_t* staticMeta, + SystemCameraKind* systemCameraKind); // Used by switchToOffline where a new result queue is created for offline reqs void updateInflightResultQueue(std::shared_ptr resultQueue); @@ -2555,6 +2578,90 @@ TEST_P(CameraHidlTest, getSetParameters) { } } +TEST_P(CameraHidlTest, systemCameraTest) { + hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); + std::map> hiddenPhysicalIdToLogicalMap; + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_6: + case CAMERA_DEVICE_API_VERSION_3_5: + case CAMERA_DEVICE_API_VERSION_3_4: + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { + ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x; + ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str()); + Return ret; + ret = mProvider->getCameraDeviceInterface_V3_x( + name, [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + device3_x = device; + }); + ASSERT_TRUE(ret.isOk()); + + ret = device3_x->getCameraCharacteristics([&](auto status, const auto& chars) { + ASSERT_EQ(status, Status::OK); + const camera_metadata_t* staticMeta = + reinterpret_cast(chars.data()); + ASSERT_NE(staticMeta, nullptr); + Status rc = isLogicalMultiCamera(staticMeta); + ASSERT_TRUE(Status::OK == rc || Status::METHOD_NOT_SUPPORTED == rc); + if (Status::METHOD_NOT_SUPPORTED == rc) { + return; + } + std::unordered_set physicalIds; + ASSERT_EQ(Status::OK, getPhysicalCameraIds(staticMeta, &physicalIds)); + SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC; + rc = getSystemCameraKind(staticMeta, &systemCameraKind); + ASSERT_EQ(rc, Status::OK); + for (auto physicalId : physicalIds) { + bool isPublicId = false; + for (auto& deviceName : cameraDeviceNames) { + std::string publicVersion, publicId; + ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, &publicVersion, + &publicId)); + if (physicalId == publicId) { + isPublicId = true; + break; + } + } + // For hidden physical cameras, collect their associated logical cameras + // and store the system camera kind. + if (!isPublicId) { + auto it = hiddenPhysicalIdToLogicalMap.find(physicalId); + if (it == hiddenPhysicalIdToLogicalMap.end()) { + hiddenPhysicalIdToLogicalMap.insert(std::make_pair( + physicalId, std::list(systemCameraKind))); + } else { + it->second.push_back(systemCameraKind); + } + } + } + }); + ASSERT_TRUE(ret.isOk()); + } break; + case CAMERA_DEVICE_API_VERSION_1_0: { + // Not applicable + } break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } break; + } + } + + // Check that the system camera kind of the logical cameras associated with + // each hidden physical camera is the same. + for (const auto& it : hiddenPhysicalIdToLogicalMap) { + SystemCameraKind neededSystemCameraKind = it.second.front(); + for (auto foundSystemCamera : it.second) { + ASSERT_EQ(neededSystemCameraKind, foundSystemCamera); + } + } +} + // Verify that the static camera characteristics can be retrieved // successfully. TEST_P(CameraHidlTest, getCameraCharacteristics) { @@ -5671,6 +5778,39 @@ Status CameraHidlTest::isZSLModeAvailable(const camera_metadata_t *staticMeta, return ret; } +Status CameraHidlTest::getSystemCameraKind(const camera_metadata_t* staticMeta, + SystemCameraKind* systemCameraKind) { + Status ret = Status::OK; + if (nullptr == staticMeta || nullptr == systemCameraKind) { + return Status::ILLEGAL_ARGUMENT; + } + + camera_metadata_ro_entry entry; + int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, + &entry); + if (0 != rc) { + return Status::ILLEGAL_ARGUMENT; + } + + if (entry.count == 1 && + entry.data.u8[0] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA) { + *systemCameraKind = SystemCameraKind::HIDDEN_SECURE_CAMERA; + return ret; + } + + // Go through the capabilities and check if it has + // ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA + for (size_t i = 0; i < entry.count; ++i) { + uint8_t capability = entry.data.u8[i]; + if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA) { + *systemCameraKind = SystemCameraKind::SYSTEM_ONLY_CAMERA; + return ret; + } + } + *systemCameraKind = SystemCameraKind::PUBLIC; + return ret; +} + // Check whether this is a monochrome camera using the static camera characteristics. Status CameraHidlTest::isMonochromeCamera(const camera_metadata_t *staticMeta) { Status ret = Status::METHOD_NOT_SUPPORTED; @@ -6391,8 +6531,10 @@ void CameraHidlTest::verifyLogicalCameraMetadata(const std::string& cameraName, const hidl_vec& deviceNames) { const camera_metadata_t* metadata = (camera_metadata_t*)chars.data(); ASSERT_NE(nullptr, metadata); - - Status rc = isLogicalMultiCamera(metadata); + SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC; + Status rc = getSystemCameraKind(metadata, &systemCameraKind); + ASSERT_EQ(rc, Status::OK); + rc = isLogicalMultiCamera(metadata); ASSERT_TRUE(Status::OK == rc || Status::METHOD_NOT_SUPPORTED == rc); if (Status::METHOD_NOT_SUPPORTED == rc) { return; @@ -6411,6 +6553,7 @@ void CameraHidlTest::verifyLogicalCameraMetadata(const std::string& cameraName, ASSERT_NE(physicalId, cameraId); bool isPublicId = false; std::string fullPublicId; + SystemCameraKind physSystemCameraKind = SystemCameraKind::PUBLIC; for (auto& deviceName : deviceNames) { std::string publicVersion, publicId; ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId)); @@ -6434,9 +6577,16 @@ void CameraHidlTest::verifyLogicalCameraMetadata(const std::string& cameraName, ret = subDevice->getCameraCharacteristics( [&](auto status, const auto& chars) { ASSERT_EQ(Status::OK, status); - retcode = find_camera_metadata_ro_entry( - (const camera_metadata_t *)chars.data(), - ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry); + const camera_metadata_t* staticMeta = + reinterpret_cast(chars.data()); + rc = getSystemCameraKind(staticMeta, &physSystemCameraKind); + ASSERT_EQ(rc, Status::OK); + // Make sure that the system camera kind of a non-hidden + // physical cameras is the same as the logical camera associated + // with it. + ASSERT_EQ(physSystemCameraKind, systemCameraKind); + retcode = find_camera_metadata_ro_entry(staticMeta, + ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry); bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2); ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange); }); @@ -6452,17 +6602,16 @@ void CameraHidlTest::verifyLogicalCameraMetadata(const std::string& cameraName, ASSERT_NE(device3_5, nullptr); // Check camera characteristics for hidden camera id - Return ret = device3_5->getPhysicalCameraCharacteristics(physicalId, - [&](auto status, const auto& chars) { - verifyCameraCharacteristics(status, chars); - verifyMonochromeCharacteristics(chars, deviceVersion); - - retcode = find_camera_metadata_ro_entry( - (const camera_metadata_t *)chars.data(), - ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry); - bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2); - ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange); - }); + Return ret = device3_5->getPhysicalCameraCharacteristics( + physicalId, [&](auto status, const auto& chars) { + verifyCameraCharacteristics(status, chars); + verifyMonochromeCharacteristics(chars, deviceVersion); + retcode = + find_camera_metadata_ro_entry((const camera_metadata_t*)chars.data(), + ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry); + bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2); + ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange); + }); ASSERT_TRUE(ret.isOk()); // Check calling getCameraDeviceInterface_V3_x() on hidden camera id returns From bc20e5c2a32e3693242259dc7f9eca6a3a368dcb Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Tue, 3 Mar 2020 15:32:39 -0500 Subject: [PATCH 0879/1022] Set up Multi-HAL for Sensors HAL 2.1 Bug: 149758467 Test: Load onto device and verify VTS passes Test: Verify new fake subhals load properly and that unit tests pass that have been updated in this topic Change-Id: Icefae8c1261b29d704beedd51de5b3f53b374cc4 --- sensors/2.0/multihal/Android.bp | 8 +- sensors/2.0/multihal/service.cpp | 4 +- .../common/default/2.X/multihal/Android.bp | 5 + .../common/default/2.X/multihal/HalProxy.cpp | 207 +++++++++------- .../default/2.X/multihal/HalProxyCallback.cpp | 82 +++++++ .../default/2.X/multihal/include/HalProxy.h | 228 +++++++++++------- .../2.X/multihal/include/HalProxyCallback.h | 171 +++++++++++++ .../2.X/multihal/include/SubHalWrapper.h | 188 +++++++++++++++ .../multihal/include/V2_0/ScopedWakelock.h | 2 +- .../default/2.X/multihal/tests/Android.bp | 6 + .../2.X/multihal/tests/HalProxy_test.cpp | 5 +- .../common/utils/EventMessageQueueWrapper.h | 36 +++ .../common/utils/ISensorsCallbackWrapper.h | 96 ++++++++ 13 files changed, 855 insertions(+), 183 deletions(-) create mode 100644 sensors/common/default/2.X/multihal/HalProxyCallback.cpp create mode 100644 sensors/common/default/2.X/multihal/include/HalProxyCallback.h create mode 100644 sensors/common/default/2.X/multihal/include/SubHalWrapper.h create mode 100644 sensors/common/utils/ISensorsCallbackWrapper.h diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp index 3ce33906cc..bf51fcdbbc 100644 --- a/sensors/2.0/multihal/Android.bp +++ b/sensors/2.0/multihal/Android.bp @@ -25,6 +25,9 @@ cc_binary { ], init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"], vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"], + header_libs: [ + "android.hardware.sensors@2.X-shared-utils", + ], shared_libs: [ "android.hardware.sensors@2.0", "android.hardware.sensors@2.0-ScopedWakelock", @@ -37,5 +40,8 @@ cc_binary { "libpower", "libutils", ], - static_libs: ["android.hardware.sensors@2.X-multihal"], + static_libs: [ + "android.hardware.sensors@1.0-convert", + "android.hardware.sensors@2.X-multihal", + ], } diff --git a/sensors/2.0/multihal/service.cpp b/sensors/2.0/multihal/service.cpp index ef77048020..f50ad7e16a 100644 --- a/sensors/2.0/multihal/service.cpp +++ b/sensors/2.0/multihal/service.cpp @@ -23,12 +23,12 @@ using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; using android::hardware::sensors::V2_0::ISensors; -using android::hardware::sensors::V2_0::implementation::HalProxy; +using android::hardware::sensors::V2_1::implementation::HalProxyV2_0; int main(int /* argc */, char** /* argv */) { configureRpcThreadpool(1, true); - android::sp halProxy = new HalProxy(); + android::sp halProxy = new HalProxyV2_0(); if (halProxy->registerAsService() != ::android::OK) { ALOGE("Failed to register Sensors HAL instance"); return -1; diff --git a/sensors/common/default/2.X/multihal/Android.bp b/sensors/common/default/2.X/multihal/Android.bp index 6122323fd8..c80c47a4bf 100644 --- a/sensors/common/default/2.X/multihal/Android.bp +++ b/sensors/common/default/2.X/multihal/Android.bp @@ -17,6 +17,7 @@ cc_defaults { name: "android.hardware.sensors@2.X-multihal-defaults", header_libs: [ "android.hardware.sensors@2.X-multihal.header", + "android.hardware.sensors@2.X-shared-utils", ], shared_libs: [ "android.hardware.sensors@1.0", @@ -30,6 +31,9 @@ cc_defaults { "libpower", "libutils", ], + static_libs: [ + "android.hardware.sensors@1.0-convert", + ], cflags: ["-DLOG_TAG=\"SensorsMultiHal\""], } @@ -62,6 +66,7 @@ cc_library_static { ], srcs: [ "HalProxy.cpp", + "HalProxyCallback.cpp", ], vendor_available: true, export_header_lib_headers: [ diff --git a/sensors/common/default/2.X/multihal/HalProxy.cpp b/sensors/common/default/2.X/multihal/HalProxy.cpp index 869c0330f4..a09e9e938e 100644 --- a/sensors/common/default/2.X/multihal/HalProxy.cpp +++ b/sensors/common/default/2.X/multihal/HalProxy.cpp @@ -32,15 +32,17 @@ namespace android { namespace hardware { namespace sensors { -namespace V2_0 { +namespace V2_1 { namespace implementation { +using ::android::hardware::sensors::V1_0::Result; using ::android::hardware::sensors::V2_0::EventQueueFlagBits; using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; using ::android::hardware::sensors::V2_0::implementation::getTimeNow; using ::android::hardware::sensors::V2_0::implementation::kWakelockTimeoutNs; -typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*); +typedef V2_0::implementation::ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*); +typedef V2_1::implementation::ISensorsSubHal*(SensorsHalGetSubHalV2_1Func)(uint32_t*); static constexpr int32_t kBitsAfterSubHalIndex = 24; @@ -85,7 +87,24 @@ HalProxy::HalProxy() { init(); } -HalProxy::HalProxy(std::vector& subHalList) : mSubHalList(subHalList) { +HalProxy::HalProxy(std::vector& subHalList) { + for (ISensorsSubHalV2_0* subHal : subHalList) { + mSubHalList.push_back(std::make_unique(subHal)); + } + + init(); +} + +HalProxy::HalProxy(std::vector& subHalList, + std::vector& subHalListV2_1) { + for (ISensorsSubHalV2_0* subHal : subHalList) { + mSubHalList.push_back(std::make_unique(subHal)); + } + + for (ISensorsSubHalV2_1* subHal : subHalListV2_1) { + mSubHalList.push_back(std::make_unique(subHal)); + } + init(); } @@ -93,8 +112,8 @@ HalProxy::~HalProxy() { stopThreads(); } -Return HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) { - std::vector sensors; +Return HalProxy::getSensorsList_2_1(ISensorsV2_1::getSensorsList_2_1_cb _hidl_cb) { + std::vector sensors; for (const auto& iter : mSensors) { sensors.push_back(iter.second); } @@ -102,22 +121,31 @@ Return HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) { return Void(); } +Return HalProxy::getSensorsList(ISensorsV2_0::getSensorsList_cb _hidl_cb) { + std::vector sensors; + for (const auto& iter : mSensors) { + sensors.push_back(convertToOldSensorInfo(iter.second)); + } + _hidl_cb(sensors); + return Void(); +} + Return HalProxy::setOperationMode(OperationMode mode) { Result result = Result::OK; size_t subHalIndex; for (subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) { - ISensorsSubHal* subHal = mSubHalList[subHalIndex]; - result = subHal->setOperationMode(mode); + result = mSubHalList[subHalIndex]->setOperationMode(mode); if (result != Result::OK) { - ALOGE("setOperationMode failed for SubHal: %s", subHal->getName().c_str()); + ALOGE("setOperationMode failed for SubHal: %s", + mSubHalList[subHalIndex]->getName().c_str()); break; } } + if (result != Result::OK) { // Reset the subhal operation modes that have been flipped for (size_t i = 0; i < subHalIndex; i++) { - ISensorsSubHal* subHal = mSubHalList[i]; - subHal->setOperationMode(mCurrentOperationMode); + mSubHalList[i]->setOperationMode(mCurrentOperationMode); } } else { mCurrentOperationMode = mode; @@ -133,10 +161,42 @@ Return HalProxy::activate(int32_t sensorHandle, bool enabled) { ->activate(clearSubHalIndex(sensorHandle), enabled); } -Return HalProxy::initialize( - const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, +Return HalProxy::initialize_2_1( + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback) { + const sp& sensorsCallback) { + sp dynamicCallback = + new ISensorsCallbackWrapperV2_1(sensorsCallback); + + // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions. + auto eventQueue = + std::make_unique(eventQueueDescriptor, true /* resetPointers */); + std::unique_ptr queue = + std::make_unique(eventQueue); + + return initializeCommon(queue, wakeLockDescriptor, dynamicCallback); +} + +Return HalProxy::initialize( + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) { + sp dynamicCallback = + new ISensorsCallbackWrapperV2_0(sensorsCallback); + + // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions. + auto eventQueue = + std::make_unique(eventQueueDescriptor, true /* resetPointers */); + std::unique_ptr queue = + std::make_unique(eventQueue); + + return initializeCommon(queue, wakeLockDescriptor, dynamicCallback); +} + +Return HalProxy::initializeCommon( + std::unique_ptr& eventQueue, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) { Result result = Result::OK; stopThreads(); @@ -147,7 +207,7 @@ Return HalProxy::initialize( disableAllSensors(); // Clears the queue if any events were pending write before. - mPendingWriteEventsQueue = std::queue, size_t>>(); + mPendingWriteEventsQueue = std::queue, size_t>>(); mSizePendingWriteEventsQueue = 0; // Clears previously connected dynamic sensors @@ -156,8 +216,7 @@ Return HalProxy::initialize( mDynamicSensorsCallback = sensorsCallback; // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions. - mEventQueue = - std::make_unique(eventQueueDescriptor, true /* resetPointers */); + mEventQueue = std::move(eventQueue); // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP // events have been successfully read and handled by the framework. @@ -186,12 +245,10 @@ Return HalProxy::initialize( mWakelockThread = std::thread(startWakelockThread, this); for (size_t i = 0; i < mSubHalList.size(); i++) { - auto subHal = mSubHalList[i]; - const auto& subHalCallback = mSubHalCallbacks[i]; - Result currRes = subHal->initialize(subHalCallback); + Result currRes = mSubHalList[i]->initialize(this, this, i); if (currRes != Result::OK) { result = currRes; - ALOGE("Subhal '%s' failed to initialize.", subHal->getName().c_str()); + ALOGE("Subhal '%s' failed to initialize.", mSubHalList[i]->getName().c_str()); break; } } @@ -217,7 +274,11 @@ Return HalProxy::flush(int32_t sensorHandle) { return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle)); } -Return HalProxy::injectSensorData(const Event& event) { +Return HalProxy::injectSensorData_2_1(const V2_1::Event& event) { + return injectSensorData(convertToOldEvent(event)); +} + +Return HalProxy::injectSensorData(const V1_0::Event& event) { Result result = Result::OK; if (mCurrentOperationMode == OperationMode::NORMAL && event.sensorType != V1_0::SensorType::ADDITIONAL_INFO) { @@ -226,18 +287,19 @@ Return HalProxy::injectSensorData(const Event& event) { result = Result::BAD_VALUE; } if (result == Result::OK) { - Event subHalEvent = event; + V1_0::Event subHalEvent = event; if (!isSubHalIndexValid(event.sensorHandle)) { return Result::BAD_VALUE; } subHalEvent.sensorHandle = clearSubHalIndex(event.sensorHandle); - result = getSubHalForSensorHandle(event.sensorHandle)->injectSensorData(subHalEvent); + result = getSubHalForSensorHandle(event.sensorHandle) + ->injectSensorData(convertToNewEvent(subHalEvent)); } return result; } Return HalProxy::registerDirectChannel(const SharedMemInfo& mem, - registerDirectChannel_cb _hidl_cb) { + ISensorsV2_0::registerDirectChannel_cb _hidl_cb) { if (mDirectChannelSubHal == nullptr) { _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */); } else { @@ -257,7 +319,8 @@ Return HalProxy::unregisterDirectChannel(int32_t channelHandle) { } Return HalProxy::configDirectReport(int32_t sensorHandle, int32_t channelHandle, - RateLevel rate, configDirectReport_cb _hidl_cb) { + RateLevel rate, + ISensorsV2_0::configDirectReport_cb _hidl_cb) { if (mDirectChannelSubHal == nullptr) { _hidl_cb(Result::INVALID_OPERATION, -1 /* reportToken */); } else if (sensorHandle == -1 && rate != RateLevel::STOP) { @@ -302,7 +365,7 @@ Return HalProxy::debug(const hidl_handle& fd, const hidl_vec& stream << " # of non-dynamic sensors across all subhals: " << mSensors.size() << std::endl; stream << " # of dynamic sensors across all subhals: " << mDynamicSensors.size() << std::endl; stream << "SubHals (" << mSubHalList.size() << "):" << std::endl; - for (ISensorsSubHal* subHal : mSubHalList) { + for (auto& subHal : mSubHalList) { stream << " Name: " << subHal->getName() << std::endl; stream << " Debug dump: " << std::endl; android::base::WriteStringToFd(stream.str(), writeFd); @@ -369,20 +432,37 @@ void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) { } else { SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr = (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal"); - if (sensorsHalGetSubHalPtr == nullptr) { - ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s", - subHalLibraryFile.c_str()); - } else { + if (sensorsHalGetSubHalPtr != nullptr) { std::function sensorsHalGetSubHal = *sensorsHalGetSubHalPtr; uint32_t version; - ISensorsSubHal* subHal = sensorsHalGetSubHal(&version); + ISensorsSubHalV2_0* subHal = sensorsHalGetSubHal(&version); if (version != SUB_HAL_2_0_VERSION) { ALOGE("SubHal version was not 2.0 for library: %s", subHalLibraryFile.c_str()); } else { ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str()); - mSubHalList.push_back(subHal); + mSubHalList.push_back(std::make_unique(subHal)); + } + } else { + SensorsHalGetSubHalV2_1Func* getSubHalV2_1Ptr = + (SensorsHalGetSubHalV2_1Func*)dlsym(handle, "sensorsHalGetSubHal_2_1"); + + if (getSubHalV2_1Ptr == nullptr) { + ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s", + subHalLibraryFile.c_str()); + } else { + std::function sensorsHalGetSubHal_2_1 = + *getSubHalV2_1Ptr; + uint32_t version; + ISensorsSubHalV2_1* subHal = sensorsHalGetSubHal_2_1(&version); + if (version != SUB_HAL_2_1_VERSION) { + ALOGE("SubHal version was not 2.1 for library: %s", + subHalLibraryFile.c_str()); + } else { + ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str()); + mSubHalList.push_back(std::make_unique(subHal)); + } } } } @@ -390,36 +470,28 @@ void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) { } } -void HalProxy::initializeSubHalCallbacks() { - for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) { - sp callback = new HalProxyCallback(this, subHalIndex); - mSubHalCallbacks.push_back(callback); - } -} - void HalProxy::initializeSensorList() { for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) { - ISensorsSubHal* subHal = mSubHalList[subHalIndex]; - auto result = subHal->getSensorsList([&](const auto& list) { + auto result = mSubHalList[subHalIndex]->getSensorsList([&](const auto& list) { for (SensorInfo sensor : list) { if (!subHalIndexIsClear(sensor.sensorHandle)) { ALOGE("SubHal sensorHandle's first byte was not 0"); } else { ALOGV("Loaded sensor: %s", sensor.name.c_str()); sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex); - setDirectChannelFlags(&sensor, subHal); + setDirectChannelFlags(&sensor, mSubHalList[subHalIndex]); mSensors[sensor.sensorHandle] = sensor; } } }); if (!result.isOk()) { - ALOGE("getSensorsList call failed for SubHal: %s", subHal->getName().c_str()); + ALOGE("getSensorsList call failed for SubHal: %s", + mSubHalList[subHalIndex]->getName().c_str()); } } } void HalProxy::init() { - initializeSubHalCallbacks(); initializeSensorList(); } @@ -552,7 +624,7 @@ void HalProxy::resetSharedWakelock() { } void HalProxy::postEventsToMessageQueue(const std::vector& events, size_t numWakeupEvents, - ScopedWakelock wakelock) { + V2_0::implementation::ScopedWakelock wakelock) { size_t numToWrite = 0; std::lock_guard lock(mEventQueueWriteMutex); if (wakelock.isLocked()) { @@ -610,7 +682,8 @@ void HalProxy::decrementRefCountAndMaybeReleaseWakelock(size_t delta, } } -void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal) { +void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, + std::shared_ptr subHal) { bool sensorSupportsDirectChannel = (sensorInfo->flags & (V1_0::SensorFlagBits::MASK_DIRECT_REPORT | V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL)) != 0; @@ -624,7 +697,7 @@ void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* sub } } -ISensorsSubHal* HalProxy::getSubHalForSensorHandle(int32_t sensorHandle) { +std::shared_ptr HalProxy::getSubHalForSensorHandle(int32_t sensorHandle) { return mSubHalList[extractSubHalIndex(sensorHandle)]; } @@ -651,46 +724,8 @@ bool HalProxy::subHalIndexIsClear(int32_t sensorHandle) { return (sensorHandle & kSensorHandleSubHalIndexMask) == 0; } -void HalProxyCallback::postEvents(const std::vector& events, ScopedWakelock wakelock) { - if (events.empty() || !mHalProxy->areThreadsRunning()) return; - size_t numWakeupEvents; - std::vector processedEvents = processEvents(events, &numWakeupEvents); - if (numWakeupEvents > 0) { - ALOG_ASSERT(wakelock.isLocked(), - "Wakeup events posted while wakelock unlocked for subhal" - " w/ index %" PRId32 ".", - mSubHalIndex); - } else { - ALOG_ASSERT(!wakelock.isLocked(), - "No Wakeup events posted but wakelock locked for subhal" - " w/ index %" PRId32 ".", - mSubHalIndex); - } - mHalProxy->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock)); -} - -ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) { - ScopedWakelock wakelock(mHalProxy, lock); - return wakelock; -} - -std::vector HalProxyCallback::processEvents(const std::vector& events, - size_t* numWakeupEvents) const { - *numWakeupEvents = 0; - std::vector eventsOut; - for (Event event : events) { - event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex); - eventsOut.push_back(event); - const SensorInfo& sensor = mHalProxy->getSensorInfo(event.sensorHandle); - if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) { - (*numWakeupEvents)++; - } - } - return eventsOut; -} - } // namespace implementation -} // namespace V2_0 +} // namespace V2_1 } // namespace sensors } // namespace hardware } // namespace android diff --git a/sensors/common/default/2.X/multihal/HalProxyCallback.cpp b/sensors/common/default/2.X/multihal/HalProxyCallback.cpp new file mode 100644 index 0000000000..a0e0c6b751 --- /dev/null +++ b/sensors/common/default/2.X/multihal/HalProxyCallback.cpp @@ -0,0 +1,82 @@ +/* + * 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. + */ + +#include "HalProxyCallback.h" + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace implementation { + +static constexpr int32_t kBitsAfterSubHalIndex = 24; + +/** + * Set the subhal index as first byte of sensor handle and return this modified version. + * + * @param sensorHandle The sensor handle to modify. + * @param subHalIndex The index in the hal proxy of the sub hal this sensor belongs to. + * + * @return The modified sensor handle. + */ +int32_t setSubHalIndex(int32_t sensorHandle, size_t subHalIndex) { + return sensorHandle | (static_cast(subHalIndex) << kBitsAfterSubHalIndex); +} + +void HalProxyCallbackBase::postEvents(const std::vector& events, + ScopedWakelock wakelock) { + if (events.empty() || !mCallback->areThreadsRunning()) return; + size_t numWakeupEvents; + std::vector processedEvents = processEvents(events, &numWakeupEvents); + if (numWakeupEvents > 0) { + ALOG_ASSERT(wakelock.isLocked(), + "Wakeup events posted while wakelock unlocked for subhal" + " w/ index %" PRId32 ".", + mSubHalIndex); + } else { + ALOG_ASSERT(!wakelock.isLocked(), + "No Wakeup events posted but wakelock locked for subhal" + " w/ index %" PRId32 ".", + mSubHalIndex); + } + mCallback->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock)); +} + +ScopedWakelock HalProxyCallbackBase::createScopedWakelock(bool lock) { + ScopedWakelock wakelock(mRefCounter, lock); + return wakelock; +} + +std::vector HalProxyCallbackBase::processEvents(const std::vector& events, + size_t* numWakeupEvents) const { + *numWakeupEvents = 0; + std::vector eventsOut; + for (V2_1::Event event : events) { + event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex); + eventsOut.push_back(event); + const V2_1::SensorInfo& sensor = mCallback->getSensorInfo(event.sensorHandle); + if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) { + (*numWakeupEvents)++; + } + } + return eventsOut; +} + +} // namespace implementation +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android diff --git a/sensors/common/default/2.X/multihal/include/HalProxy.h b/sensors/common/default/2.X/multihal/include/HalProxy.h index d7e8795903..fb0b806bab 100644 --- a/sensors/common/default/2.X/multihal/include/HalProxy.h +++ b/sensors/common/default/2.X/multihal/include/HalProxy.h @@ -16,12 +16,17 @@ #pragma once +#include "EventMessageQueueWrapper.h" +#include "HalProxyCallback.h" +#include "ISensorsCallbackWrapper.h" +#include "SubHalWrapper.h" #include "V2_0/ScopedWakelock.h" #include "V2_0/SubHal.h" #include "V2_1/SubHal.h" +#include "convertV2_1.h" -#include -#include +#include +#include #include #include #include @@ -38,96 +43,97 @@ namespace android { namespace hardware { namespace sensors { -namespace V2_0 { +namespace V2_1 { namespace implementation { -using ::android::sp; -using ::android::hardware::EventFlag; -using ::android::hardware::hidl_string; -using ::android::hardware::hidl_vec; -using ::android::hardware::MessageQueue; -using ::android::hardware::MQDescriptor; -using ::android::hardware::Return; -using ::android::hardware::Void; - -class HalProxy : public ISensors, public IScopedWakelockRefCounter { +/** + * HalProxy is the main interface for Multi-HAL. It is responsible for managing subHALs and + * proxying function calls to/from the subHAL APIs from the sensors framework. It also manages any + * wakelocks allocated through the IHalProxyCallback and manages posting events to the sensors + * framework. + */ +class HalProxy : public V2_0::implementation::IScopedWakelockRefCounter, + public V2_0::implementation::ISubHalCallback { public: - using Event = ::android::hardware::sensors::V1_0::Event; + using Event = ::android::hardware::sensors::V2_1::Event; using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; using Result = ::android::hardware::sensors::V1_0::Result; - using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo; + using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo; using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; - using ISensorsSubHal = ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal; + using IHalProxyCallbackV2_0 = V2_0::implementation::IHalProxyCallback; + using IHalProxyCallbackV2_1 = V2_1::implementation::IHalProxyCallback; + using ISensorsSubHalV2_0 = V2_0::implementation::ISensorsSubHal; + using ISensorsSubHalV2_1 = V2_1::implementation::ISensorsSubHal; + using ISensorsV2_0 = V2_0::ISensors; + using ISensorsV2_1 = V2_1::ISensors; + using HalProxyCallbackBase = V2_0::implementation::HalProxyCallbackBase; explicit HalProxy(); // Test only constructor. - explicit HalProxy(std::vector& subHalList); + explicit HalProxy(std::vector& subHalList); + explicit HalProxy(std::vector& subHalList, + std::vector& subHalListV2_1); ~HalProxy(); + // Methods from ::android::hardware::sensors::V2_1::ISensors follow. + Return getSensorsList_2_1(ISensorsV2_1::getSensorsList_2_1_cb _hidl_cb); + + Return initialize_2_1( + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback); + + Return injectSensorData_2_1(const Event& event); + // Methods from ::android::hardware::sensors::V2_0::ISensors follow. - Return getSensorsList(getSensorsList_cb _hidl_cb) override; + Return getSensorsList(ISensorsV2_0::getSensorsList_cb _hidl_cb); - Return setOperationMode(OperationMode mode) override; + Return setOperationMode(OperationMode mode); - Return activate(int32_t sensorHandle, bool enabled) override; + Return activate(int32_t sensorHandle, bool enabled); Return initialize( - const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback) override; + const sp& sensorsCallback); + + Return initializeCommon( + std::unique_ptr& eventQueue, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback); Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) override; + int64_t maxReportLatencyNs); - Return flush(int32_t sensorHandle) override; + Return flush(int32_t sensorHandle); - Return injectSensorData(const Event& event) override; + Return injectSensorData(const V1_0::Event& event); Return registerDirectChannel(const SharedMemInfo& mem, - registerDirectChannel_cb _hidl_cb) override; + ISensorsV2_0::registerDirectChannel_cb _hidl_cb); - Return unregisterDirectChannel(int32_t channelHandle) override; + Return unregisterDirectChannel(int32_t channelHandle); Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, - configDirectReport_cb _hidl_cb) override; + ISensorsV2_0::configDirectReport_cb _hidl_cb); - Return debug(const hidl_handle& fd, const hidl_vec& args) override; + Return debug(const hidl_handle& fd, const hidl_vec& args); - // Below methods from ::android::hardware::sensors::V2_0::ISensorsCallback with a minor change - // to pass in the sub-HAL index. While the above methods are invoked from the sensors framework - // via the binder, these methods are invoked from a callback provided to sub-HALs inside the - // same process as the HalProxy, but potentially running on different threads. Return onDynamicSensorsConnected(const hidl_vec& dynamicSensorsAdded, - int32_t subHalIndex); + int32_t subHalIndex) override; Return onDynamicSensorsDisconnected(const hidl_vec& dynamicSensorHandlesRemoved, - int32_t subHalIndex); + int32_t subHalIndex) override; - // Below methods are for HalProxyCallback - - /** - * Post events to the event message queue if there is room to write them. Otherwise post the - * remaining events to a background thread for a blocking write with a kPendingWriteTimeoutNs - * timeout. - * - * @param events The list of events to post to the message queue. - * @param numWakeupEvents The number of wakeup events in events. - * @param wakelock The wakelock associated with this post of events. - */ void postEventsToMessageQueue(const std::vector& events, size_t numWakeupEvents, - ScopedWakelock wakelock); + V2_0::implementation::ScopedWakelock wakelock) override; - /** - * Get the sensor info associated with that sensorHandle. - * - * @param sensorHandle The sensor handle. - * - * @return The sensor info object in the mapping. - */ - const SensorInfo& getSensorInfo(int32_t sensorHandle) { return mSensors[sensorHandle]; } + const SensorInfo& getSensorInfo(int32_t sensorHandle) override { + return mSensors[sensorHandle]; + } - bool areThreadsRunning() { return mThreadsRun.load(); } + bool areThreadsRunning() override { return mThreadsRun.load(); } // Below methods are from IScopedWakelockRefCounter interface bool incrementRefCountAndMaybeAcquireWakelock(size_t delta, @@ -136,13 +142,14 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { void decrementRefCountAndMaybeReleaseWakelock(size_t delta, int64_t timeoutStart = -1) override; private: - using EventMessageQueue = MessageQueue; + using EventMessageQueueV2_1 = MessageQueue; + using EventMessageQueueV2_0 = MessageQueue; using WakeLockMessageQueue = MessageQueue; /** * The Event FMQ where sensor events are written */ - std::unique_ptr mEventQueue; + std::unique_ptr mEventQueue; /** * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events @@ -161,15 +168,12 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { /** * Callback to the sensors framework to inform it that new sensors have been added or removed. */ - sp mDynamicSensorsCallback; + sp mDynamicSensorsCallback; /** - * SubHal object pointers that have been saved from vendor dynamic libraries. + * SubHal objects that have been saved from vendor dynamic libraries. */ - std::vector mSubHalList; - - //! The list of subhal callbacks for each subhal where the indices correlate with mSubHalList - std::vector> mSubHalCallbacks; + std::vector> mSubHalList; /** * Map of sensor handles to SensorInfo objects that contains the sensor info from subhals as @@ -187,7 +191,7 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { OperationMode mCurrentOperationMode = OperationMode::NORMAL; //! The single subHal that supports directChannel reporting. - ISensorsSubHal* mDirectChannelSubHal = nullptr; + std::shared_ptr mDirectChannelSubHal; //! The timeout for each pending write on background thread for events. static const int64_t kPendingWriteTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */; @@ -239,9 +243,9 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { //! The refcount of how many ScopedWakelocks and pending wakeup events are active size_t mWakelockRefCount = 0; - int64_t mWakelockTimeoutStartTime = getTimeNow(); + int64_t mWakelockTimeoutStartTime = V2_0::implementation::getTimeNow(); - int64_t mWakelockTimeoutResetTime = getTimeNow(); + int64_t mWakelockTimeoutResetTime = V2_0::implementation::getTimeNow(); const char* kWakelockName = "SensorsHAL_WAKEUP"; @@ -321,7 +325,7 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { * disabled. * @param subHal The subhal pointer that the current sensorInfo object came from. */ - void setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal); + void setDirectChannelFlags(SensorInfo* sensorInfo, std::shared_ptr subHal); /* * Get the subhal pointer which can be found by indexing into the mSubHalList vector @@ -329,7 +333,7 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { * * @param sensorHandle The handle used to identify a sensor in one of the subhals. */ - ISensorsSubHal* getSubHalForSensorHandle(int32_t sensorHandle); + std::shared_ptr getSubHalForSensorHandle(int32_t sensorHandle); /** * Checks that sensorHandle's subhal index byte is within bounds of mSubHalList. @@ -368,39 +372,81 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { }; /** - * Callback class used to provide the HalProxy with the index of which subHal is invoking + * Since a newer HAL can't masquerade as a older HAL, IHalProxy enables the HalProxy to be compiled + * either for HAL 2.0 or HAL 2.1 depending on the build configuration. */ -class HalProxyCallback : public IHalProxyCallback { - using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo; - - public: - HalProxyCallback(HalProxy* halProxy, int32_t subHalIndex) - : mHalProxy(halProxy), mSubHalIndex(subHalIndex) {} - - Return onDynamicSensorsConnected( - const hidl_vec& dynamicSensorsAdded) override { - return mHalProxy->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex); +template +class IHalProxy : public HalProxy, public ISensorsVersion { + Return getSensorsList(ISensorsV2_0::getSensorsList_cb _hidl_cb) override { + return HalProxy::getSensorsList(_hidl_cb); } - Return onDynamicSensorsDisconnected( - const hidl_vec& dynamicSensorHandlesRemoved) override { - return mHalProxy->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex); + Return setOperationMode(OperationMode mode) override { + return HalProxy::setOperationMode(mode); } - void postEvents(const std::vector& events, ScopedWakelock wakelock); + Return activate(int32_t sensorHandle, bool enabled) override { + return HalProxy::activate(sensorHandle, enabled); + } - ScopedWakelock createScopedWakelock(bool lock); + Return initialize( + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) override { + return HalProxy::initialize(eventQueueDescriptor, wakeLockDescriptor, sensorsCallback); + } - private: - HalProxy* mHalProxy; - int32_t mSubHalIndex; + Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) override { + return HalProxy::batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); + } - std::vector processEvents(const std::vector& events, - size_t* numWakeupEvents) const; + Return flush(int32_t sensorHandle) override { return HalProxy::flush(sensorHandle); } + + Return injectSensorData(const V1_0::Event& event) override { + return HalProxy::injectSensorData(event); + } + + Return registerDirectChannel(const SharedMemInfo& mem, + ISensorsV2_0::registerDirectChannel_cb _hidl_cb) override { + return HalProxy::registerDirectChannel(mem, _hidl_cb); + } + + Return unregisterDirectChannel(int32_t channelHandle) override { + return HalProxy::unregisterDirectChannel(channelHandle); + } + + Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + ISensorsV2_0::configDirectReport_cb _hidl_cb) override { + return HalProxy::configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); + } + + Return debug(const hidl_handle& fd, const hidl_vec& args) override { + return HalProxy::debug(fd, args); + } +}; + +class HalProxyV2_0 : public IHalProxy {}; + +class HalProxyV2_1 : public IHalProxy { + Return getSensorsList_2_1(ISensorsV2_1::getSensorsList_2_1_cb _hidl_cb) override { + return HalProxy::getSensorsList_2_1(_hidl_cb); + } + + Return initialize_2_1( + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) override { + return HalProxy::initialize_2_1(eventQueueDescriptor, wakeLockDescriptor, sensorsCallback); + } + + Return injectSensorData_2_1(const Event& event) override { + return HalProxy::injectSensorData_2_1(event); + } }; } // namespace implementation -} // namespace V2_0 +} // namespace V2_1 } // namespace sensors } // namespace hardware } // namespace android diff --git a/sensors/common/default/2.X/multihal/include/HalProxyCallback.h b/sensors/common/default/2.X/multihal/include/HalProxyCallback.h new file mode 100644 index 0000000000..e62b7d1c00 --- /dev/null +++ b/sensors/common/default/2.X/multihal/include/HalProxyCallback.h @@ -0,0 +1,171 @@ +/* + * 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. + */ + +#pragma once + +#include "V2_0/ScopedWakelock.h" +#include "V2_0/SubHal.h" +#include "V2_1/SubHal.h" +#include "convertV2_1.h" + +#include +#include +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace implementation { + +/** + * Interface used to communicate with the HalProxy when subHals interact with their provided + * callback. + */ +class ISubHalCallback { + public: + virtual ~ISubHalCallback() {} + + // Below methods from ::android::hardware::sensors::V2_0::ISensorsCallback with a minor change + // to pass in the sub-HAL index. While the above methods are invoked from the sensors framework + // via the binder, these methods are invoked from a callback provided to sub-HALs inside the + // same process as the HalProxy, but potentially running on different threads. + virtual Return onDynamicSensorsConnected( + const hidl_vec& dynamicSensorsAdded, int32_t subHalIndex) = 0; + + virtual Return onDynamicSensorsDisconnected( + const hidl_vec& dynamicSensorHandlesRemoved, int32_t subHalIndex) = 0; + + /** + * Post events to the event message queue if there is room to write them. Otherwise post the + * remaining events to a background thread for a blocking write with a kPendingWriteTimeoutNs + * timeout. + * + * @param events The list of events to post to the message queue. + * @param numWakeupEvents The number of wakeup events in events. + * @param wakelock The wakelock associated with this post of events. + */ + virtual void postEventsToMessageQueue(const std::vector& events, + size_t numWakeupEvents, + V2_0::implementation::ScopedWakelock wakelock) = 0; + + /** + * Get the sensor info associated with that sensorHandle. + * + * @param sensorHandle The sensor handle. + * + * @return The sensor info object in the mapping. + */ + virtual const V2_1::SensorInfo& getSensorInfo(int32_t sensorHandle) = 0; + + virtual bool areThreadsRunning() = 0; +}; + +/** + * Callback class given to subhals that allows the HalProxy to know which subhal a given invocation + * is coming from. + */ +class HalProxyCallbackBase : public VirtualLightRefBase { + public: + HalProxyCallbackBase(ISubHalCallback* callback, + V2_0::implementation::IScopedWakelockRefCounter* refCounter, + int32_t subHalIndex) + : mCallback(callback), mRefCounter(refCounter), mSubHalIndex(subHalIndex) {} + + void postEvents(const std::vector& events, + V2_0::implementation::ScopedWakelock wakelock); + + V2_0::implementation::ScopedWakelock createScopedWakelock(bool lock); + + protected: + ISubHalCallback* mCallback; + V2_0::implementation::IScopedWakelockRefCounter* mRefCounter; + int32_t mSubHalIndex; + + private: + std::vector processEvents(const std::vector& events, + size_t* numWakeupEvents) const; +}; + +class HalProxyCallbackV2_0 : public HalProxyCallbackBase, + public V2_0::implementation::IHalProxyCallback { + public: + HalProxyCallbackV2_0(ISubHalCallback* callback, + V2_0::implementation::IScopedWakelockRefCounter* refCounter, + int32_t subHalIndex) + : HalProxyCallbackBase(callback, refCounter, subHalIndex) {} + + Return onDynamicSensorsConnected( + const hidl_vec& dynamicSensorsAdded) override { + return mCallback->onDynamicSensorsConnected( + V2_1::implementation::convertToNewSensorInfos(dynamicSensorsAdded), mSubHalIndex); + } + + Return onDynamicSensorsDisconnected( + const hidl_vec& dynamicSensorHandlesRemoved) override { + return mCallback->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex); + } + + void postEvents(const std::vector& events, + V2_0::implementation::ScopedWakelock wakelock) override { + HalProxyCallbackBase::postEvents(V2_1::implementation::convertToNewEvents(events), + std::move(wakelock)); + } + + V2_0::implementation::ScopedWakelock createScopedWakelock(bool lock) override { + return HalProxyCallbackBase::createScopedWakelock(lock); + } +}; + +class HalProxyCallbackV2_1 : public HalProxyCallbackBase, + public V2_1::implementation::IHalProxyCallback { + public: + HalProxyCallbackV2_1(ISubHalCallback* callback, + V2_0::implementation::IScopedWakelockRefCounter* refCounter, + int32_t subHalIndex) + : HalProxyCallbackBase(callback, refCounter, subHalIndex) {} + + Return onDynamicSensorsConnected_2_1( + const hidl_vec& dynamicSensorsAdded) override { + return mCallback->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex); + } + + Return onDynamicSensorsConnected( + const hidl_vec& /* dynamicSensorsAdded */) override { + LOG_ALWAYS_FATAL("Old dynamic sensors method can't be used"); + return Void(); + } + + Return onDynamicSensorsDisconnected( + const hidl_vec& dynamicSensorHandlesRemoved) override { + return mCallback->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex); + } + + void postEvents(const std::vector& events, + V2_0::implementation::ScopedWakelock wakelock) override { + return HalProxyCallbackBase::postEvents(events, std::move(wakelock)); + } + + V2_0::implementation::ScopedWakelock createScopedWakelock(bool lock) override { + return HalProxyCallbackBase::createScopedWakelock(lock); + } +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/sensors/common/default/2.X/multihal/include/SubHalWrapper.h b/sensors/common/default/2.X/multihal/include/SubHalWrapper.h new file mode 100644 index 0000000000..149bb5ea5b --- /dev/null +++ b/sensors/common/default/2.X/multihal/include/SubHalWrapper.h @@ -0,0 +1,188 @@ +/* + * 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. + */ + +#pragma once + +#include "HalProxyCallback.h" +#include "V2_0/SubHal.h" +#include "V2_1/SubHal.h" + +#include "android/hardware/sensors/1.0/ISensors.h" +#include "android/hardware/sensors/1.0/types.h" +#include "android/hardware/sensors/2.0/ISensors.h" +#include "android/hardware/sensors/2.0/ISensorsCallback.h" +#include "android/hardware/sensors/2.1/ISensors.h" +#include "android/hardware/sensors/2.1/ISensorsCallback.h" +#include "android/hardware/sensors/2.1/types.h" + +#include + +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_1 { +namespace implementation { + +/** + * The following subHal wrapper classes abstract away common functionality across V2.0 and V2.1 + * subHal interfaces. Much of the logic is common between the two versions and this allows users of + * the classes to only care about the type used at initialization and then interact with either + * version of the subHal interface without worrying about the type. + */ +class ISubHalWrapperBase { + protected: + using Event = ::android::hardware::sensors::V2_1::Event; + using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; + using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; + using Result = ::android::hardware::sensors::V1_0::Result; + using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo; + using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; + + public: + virtual ~ISubHalWrapperBase() {} + + virtual bool supportsNewEvents() = 0; + + virtual Return initialize(V2_0::implementation::ISubHalCallback* callback, + V2_0::implementation::IScopedWakelockRefCounter* refCounter, + int32_t subHalIndex) = 0; + + virtual Return getSensorsList( + ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) = 0; + + virtual Return setOperationMode(OperationMode mode) = 0; + + virtual Return activate(int32_t sensorHandle, bool enabled) = 0; + + virtual Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) = 0; + + virtual Return flush(int32_t sensorHandle) = 0; + + virtual Return injectSensorData(const Event& event) = 0; + + virtual Return registerDirectChannel(const SharedMemInfo& mem, + ISensors::registerDirectChannel_cb _hidl_cb) = 0; + + virtual Return unregisterDirectChannel(int32_t channelHandle) = 0; + + virtual Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, + RateLevel rate, + ISensors::configDirectReport_cb _hidl_cb) = 0; + + virtual Return debug(const hidl_handle& fd, const hidl_vec& args) = 0; + + virtual const std::string getName() = 0; +}; + +template +class SubHalWrapperBase : public ISubHalWrapperBase { + public: + SubHalWrapperBase(T* subHal) : mSubHal(subHal){}; + + virtual bool supportsNewEvents() override { return false; } + + virtual Return getSensorsList( + ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override { + return mSubHal->getSensorsList( + [&](const auto& list) { _hidl_cb(convertToNewSensorInfos(list)); }); + } + + Return setOperationMode(OperationMode mode) override { + return mSubHal->setOperationMode(mode); + } + + Return activate(int32_t sensorHandle, bool enabled) override { + return mSubHal->activate(sensorHandle, enabled); + } + + Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) override { + return mSubHal->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); + } + + Return flush(int32_t sensorHandle) override { return mSubHal->flush(sensorHandle); } + + virtual Return injectSensorData(const Event& event) override { + return mSubHal->injectSensorData(convertToOldEvent(event)); + } + + Return registerDirectChannel(const SharedMemInfo& mem, + ISensors::registerDirectChannel_cb _hidl_cb) override { + return mSubHal->registerDirectChannel(mem, _hidl_cb); + } + + Return unregisterDirectChannel(int32_t channelHandle) override { + return mSubHal->unregisterDirectChannel(channelHandle); + } + + Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + ISensors::configDirectReport_cb _hidl_cb) override { + return mSubHal->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); + } + + Return debug(const hidl_handle& fd, const hidl_vec& args) override { + return mSubHal->debug(fd, args); + } + + const std::string getName() override { return mSubHal->getName(); } + + protected: + T* mSubHal; +}; + +class SubHalWrapperV2_0 : public SubHalWrapperBase { + public: + SubHalWrapperV2_0(V2_0::implementation::ISensorsSubHal* subHal) : SubHalWrapperBase(subHal){}; + + Return initialize(V2_0::implementation::ISubHalCallback* callback, + V2_0::implementation::IScopedWakelockRefCounter* refCounter, + int32_t subHalIndex) override { + return mSubHal->initialize( + new V2_0::implementation::HalProxyCallbackV2_0(callback, refCounter, subHalIndex)); + } +}; + +class SubHalWrapperV2_1 : public SubHalWrapperBase { + public: + SubHalWrapperV2_1(V2_1::implementation::ISensorsSubHal* subHal) : SubHalWrapperBase(subHal) {} + + bool supportsNewEvents() override { return true; } + + virtual Return getSensorsList( + ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override { + return mSubHal->getSensorsList_2_1([&](const auto& list) { _hidl_cb(list); }); + } + + virtual Return injectSensorData(const Event& event) override { + return mSubHal->injectSensorData_2_1(event); + } + + Return initialize(V2_0::implementation::ISubHalCallback* callback, + V2_0::implementation::IScopedWakelockRefCounter* refCounter, + int32_t subHalIndex) override { + return mSubHal->initialize( + new V2_0::implementation::HalProxyCallbackV2_1(callback, refCounter, subHalIndex)); + } +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace sensors +} // namespace hardware +} // namespace android diff --git a/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h b/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h index aa6d9db3d4..1cc5cd5e9e 100644 --- a/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h +++ b/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h @@ -88,7 +88,7 @@ class ScopedWakelock { bool isLocked() const { return mLocked; } private: - friend class HalProxyCallback; + friend class HalProxyCallbackBase; IScopedWakelockRefCounter* mRefCounter; int64_t mCreatedAtTimeNs; bool mLocked; diff --git a/sensors/common/default/2.X/multihal/tests/Android.bp b/sensors/common/default/2.X/multihal/tests/Android.bp index 7692b51de0..cfd9e78a6f 100644 --- a/sensors/common/default/2.X/multihal/tests/Android.bp +++ b/sensors/common/default/2.X/multihal/tests/Android.bp @@ -20,6 +20,7 @@ cc_defaults { ], header_libs: [ "android.hardware.sensors@2.0-multihal.header", + "android.hardware.sensors@2.X-shared-utils", ], export_include_dirs: ["fake_subhal"], shared_libs: [ @@ -36,6 +37,7 @@ cc_defaults { "libutils", ], static_libs: [ + "android.hardware.sensors@1.0-convert", "android.hardware.sensors@2.X-multihal", ], cflags: [ @@ -78,7 +80,11 @@ cc_test { name: "android.hardware.sensors@2.X-halproxy-unit-tests", srcs: ["HalProxy_test.cpp"], vendor: true, + header_libs: [ + "android.hardware.sensors@2.X-shared-utils", + ], static_libs: [ + "android.hardware.sensors@1.0-convert", "android.hardware.sensors@2.0-ScopedWakelock.testlib", "android.hardware.sensors@2.X-multihal", "android.hardware.sensors@2.X-fakesubhal-unittest", diff --git a/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp index 867c4a149d..ce65c3cd80 100644 --- a/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp +++ b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp @@ -40,8 +40,8 @@ using ::android::hardware::sensors::V1_0::SensorType; using ::android::hardware::sensors::V2_0::EventQueueFlagBits; using ::android::hardware::sensors::V2_0::ISensorsCallback; using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; -using ::android::hardware::sensors::V2_0::implementation::HalProxy; -using ::android::hardware::sensors::V2_0::implementation::HalProxyCallback; +using ::android::hardware::sensors::V2_0::implementation::HalProxyCallbackBase; +using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock; using ::android::hardware::sensors::V2_0::subhal::implementation::AddAndRemoveDynamicSensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation:: @@ -53,6 +53,7 @@ using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensor using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation:: SetOperationModeFailingSensorsSubHal; +using ::android::hardware::sensors::V2_1::implementation::HalProxy; using EventMessageQueue = MessageQueue; using WakeupMessageQueue = MessageQueue; diff --git a/sensors/common/utils/EventMessageQueueWrapper.h b/sensors/common/utils/EventMessageQueueWrapper.h index bf3261ffbc..c4f92c8386 100644 --- a/sensors/common/utils/EventMessageQueueWrapper.h +++ b/sensors/common/utils/EventMessageQueueWrapper.h @@ -39,8 +39,14 @@ class EventMessageQueueWrapperBase : public RefBase { virtual std::atomic* getEventFlagWord() = 0; virtual size_t availableToRead() = 0; + virtual size_t availableToWrite() = 0; virtual bool read(V2_1::Event* events, size_t numToRead) = 0; + virtual bool write(const V2_1::Event* events, size_t numToWrite) = 0; virtual bool write(const std::vector& events) = 0; + virtual bool writeBlocking(const V2_1::Event* events, size_t count, uint32_t readNotification, + uint32_t writeNotification, int64_t timeOutNanos, + android::hardware::EventFlag* evFlag) = 0; + virtual size_t getQuantumCount() = 0; }; class EventMessageQueueWrapperV1_0 : public EventMessageQueueWrapperBase { @@ -60,15 +66,30 @@ class EventMessageQueueWrapperV1_0 : public EventMessageQueueWrapperBase { virtual size_t availableToRead() override { return mQueue->availableToRead(); } + size_t availableToWrite() override { return mQueue->availableToWrite(); } + virtual bool read(V2_1::Event* events, size_t numToRead) override { return mQueue->read(reinterpret_cast(events), numToRead); } + bool write(const V2_1::Event* events, size_t numToWrite) override { + return mQueue->write(reinterpret_cast(events), numToWrite); + } + virtual bool write(const std::vector& events) override { const std::vector& oldEvents = convertToOldEvents(events); return mQueue->write(oldEvents.data(), oldEvents.size()); } + bool writeBlocking(const V2_1::Event* events, size_t count, uint32_t readNotification, + uint32_t writeNotification, int64_t timeOutNanos, + android::hardware::EventFlag* evFlag) override { + return mQueue->writeBlocking(reinterpret_cast(events), count, + readNotification, writeNotification, timeOutNanos, evFlag); + } + + size_t getQuantumCount() override { return mQueue->getQuantumCount(); } + private: std::unique_ptr mQueue; }; @@ -88,14 +109,29 @@ class EventMessageQueueWrapperV2_1 : public EventMessageQueueWrapperBase { virtual size_t availableToRead() override { return mQueue->availableToRead(); } + size_t availableToWrite() override { return mQueue->availableToWrite(); } + virtual bool read(V2_1::Event* events, size_t numToRead) override { return mQueue->read(events, numToRead); } + bool write(const V2_1::Event* events, size_t numToWrite) override { + return mQueue->write(events, numToWrite); + } + bool write(const std::vector& events) override { return mQueue->write(events.data(), events.size()); } + bool writeBlocking(const V2_1::Event* events, size_t count, uint32_t readNotification, + uint32_t writeNotification, int64_t timeOutNanos, + android::hardware::EventFlag* evFlag) override { + return mQueue->writeBlocking(events, count, readNotification, writeNotification, + timeOutNanos, evFlag); + } + + size_t getQuantumCount() override { return mQueue->getQuantumCount(); } + private: std::unique_ptr mQueue; }; diff --git a/sensors/common/utils/ISensorsCallbackWrapper.h b/sensors/common/utils/ISensorsCallbackWrapper.h new file mode 100644 index 0000000000..816b225806 --- /dev/null +++ b/sensors/common/utils/ISensorsCallbackWrapper.h @@ -0,0 +1,96 @@ +/* + * 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_SENSORS_V2_1_ISENSORSCALLBACKWRAPPER_H +#define ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSCALLBACKWRAPPER_H + +#include "convertV2_1.h" + +#include "android/hardware/sensors/1.0/ISensors.h" +#include "android/hardware/sensors/1.0/types.h" +#include "android/hardware/sensors/2.0/ISensors.h" +#include "android/hardware/sensors/2.0/ISensorsCallback.h" +#include "android/hardware/sensors/2.1/ISensors.h" +#include "android/hardware/sensors/2.1/ISensorsCallback.h" +#include "android/hardware/sensors/2.1/types.h" + +#include + +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_1 { +namespace implementation { + +/** + * The ISensorsCallbackWrapper classes below abstract away the common logic between both the V2.0 + * and V2.1 versions of the Sensors HAL interface. This allows users of these classes to only care + * about the HAL version at init time and then interact with either version of the callback without + * worrying about the class type by utilizing the base class. + */ +class ISensorsCallbackWrapperBase : public VirtualLightRefBase { + public: + virtual Return onDynamicSensorsConnected( + const hidl_vec& sensorInfos) = 0; + + virtual Return onDynamicSensorsDisconnected(const hidl_vec& sensorHandles) = 0; +}; + +template +class SensorsCallbackWrapperBase : public ISensorsCallbackWrapperBase { + public: + SensorsCallbackWrapperBase(sp sensorsCallback) : mSensorsCallback(sensorsCallback){}; + + virtual Return onDynamicSensorsConnected( + const hidl_vec& sensorInfos) override { + return mSensorsCallback->onDynamicSensorsConnected(convertToOldSensorInfos(sensorInfos)); + } + + Return onDynamicSensorsDisconnected(const hidl_vec& sensorHandles) { + return mSensorsCallback->onDynamicSensorsDisconnected(sensorHandles); + } + + protected: + sp mSensorsCallback; +}; + +class ISensorsCallbackWrapperV2_0 + : public SensorsCallbackWrapperBase { + public: + ISensorsCallbackWrapperV2_0(sp sensorsCallback) + : SensorsCallbackWrapperBase(sensorsCallback){}; +}; + +class ISensorsCallbackWrapperV2_1 + : public SensorsCallbackWrapperBase { + public: + ISensorsCallbackWrapperV2_1(sp sensorsCallback) + : SensorsCallbackWrapperBase(sensorsCallback) {} + + Return onDynamicSensorsConnected(const hidl_vec& sensorInfos) override { + return mSensorsCallback->onDynamicSensorsConnected_2_1(sensorInfos); + } +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace sensors +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSCALLBACKWRAPPER_H \ No newline at end of file From 82f8d466919c33d754d83b426d8679009a4f6626 Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Tue, 28 Apr 2020 12:03:18 -0400 Subject: [PATCH 0880/1022] Create Multi-HAL 2.1 service Bug: 149758467 Test: Verify that the new unit tests and subhals in this topic load and run on a Pixel device Change-Id: Id5ab7b606f91764a456d8e3a16f7f0f2cf9b4fef --- sensors/2.1/multihal/Android.bp | 47 +++++++++++++++++++ sensors/2.1/multihal/OWNERS | 3 ++ .../android.hardware.sensors@2.1-multihal.xml | 11 +++++ ...d.hardware.sensors@2.1-service-multihal.rc | 7 +++ sensors/2.1/multihal/service.cpp | 39 +++++++++++++++ 5 files changed, 107 insertions(+) create mode 100644 sensors/2.1/multihal/Android.bp create mode 100644 sensors/2.1/multihal/OWNERS create mode 100644 sensors/2.1/multihal/android.hardware.sensors@2.1-multihal.xml create mode 100644 sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc create mode 100644 sensors/2.1/multihal/service.cpp diff --git a/sensors/2.1/multihal/Android.bp b/sensors/2.1/multihal/Android.bp new file mode 100644 index 0000000000..6a7cac9f25 --- /dev/null +++ b/sensors/2.1/multihal/Android.bp @@ -0,0 +1,47 @@ +// +// 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. + +cc_binary { + name: "android.hardware.sensors@2.1-service.multihal", + defaults: [ + "hidl_defaults", + ], + vendor: true, + relative_install_path: "hw", + srcs: [ + "service.cpp", + ], + init_rc: ["android.hardware.sensors@2.1-service-multihal.rc"], + vintf_fragments: ["android.hardware.sensors@2.1-multihal.xml"], + header_libs: [ + "android.hardware.sensors@2.X-shared-utils", + ], + shared_libs: [ + "android.hardware.sensors@2.0", + "android.hardware.sensors@2.0-ScopedWakelock", + "android.hardware.sensors@2.1", + "libbase", + "libcutils", + "libfmq", + "libhidlbase", + "liblog", + "libpower", + "libutils", + ], + static_libs: [ + "android.hardware.sensors@1.0-convert", + "android.hardware.sensors@2.X-multihal", + ], +} diff --git a/sensors/2.1/multihal/OWNERS b/sensors/2.1/multihal/OWNERS new file mode 100644 index 0000000000..e9556700d6 --- /dev/null +++ b/sensors/2.1/multihal/OWNERS @@ -0,0 +1,3 @@ +arthuri@google.com +bduddie@google.com +stange@google.com \ No newline at end of file diff --git a/sensors/2.1/multihal/android.hardware.sensors@2.1-multihal.xml b/sensors/2.1/multihal/android.hardware.sensors@2.1-multihal.xml new file mode 100644 index 0000000000..18bd3ae83b --- /dev/null +++ b/sensors/2.1/multihal/android.hardware.sensors@2.1-multihal.xml @@ -0,0 +1,11 @@ + + + android.hardware.sensors + hwbinder + 2.1 + + ISensors + default + + + diff --git a/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc b/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc new file mode 100644 index 0000000000..fc99ee7a06 --- /dev/null +++ b/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc @@ -0,0 +1,7 @@ +service vendor.sensors-hal-2-1-multihal /vendor/bin/hw/android.hardware.sensors@2.1-service.multihal + class hal + user system + group system wakelock context_hub + writepid /dev/cpuset/system-background/tasks + capabilities BLOCK_SUSPEND + rlimit rtprio 10 10 diff --git a/sensors/2.1/multihal/service.cpp b/sensors/2.1/multihal/service.cpp new file mode 100644 index 0000000000..d68d9a3e73 --- /dev/null +++ b/sensors/2.1/multihal/service.cpp @@ -0,0 +1,39 @@ +/* + * 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 +#include +#include +#include "HalProxy.h" + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::sensors::V2_1::ISensors; +using android::hardware::sensors::V2_1::implementation::HalProxyV2_1; + +int main(int /* argc */, char** /* argv */) { + configureRpcThreadpool(1, true); + + android::sp halProxy = new HalProxyV2_1(); + if (halProxy->registerAsService() != ::android::OK) { + ALOGE("Failed to register Sensors HAL instance"); + return -1; + } + + joinRpcThreadpool(); + return 1; // joinRpcThreadpool shouldn't exit +} From a305c1c58caad9bfa9bc69dec6f2142773753458 Mon Sep 17 00:00:00 2001 From: Amy Zhang Date: Mon, 20 Apr 2020 17:59:26 -0700 Subject: [PATCH 0881/1022] Refactoring the Dvr data flow tests in the Tuner VTS Test: atest VtsHalTvTunerV1_0TargetTest Bug: 150989084 Change-Id: I496dccd9dddcf6043c05faee6fbe1f0418586bc4 --- tv/tuner/1.0/default/Filter.cpp | 16 +- tv/tuner/1.0/default/Filter.h | 1 + tv/tuner/1.0/vts/functional/DvrTests.cpp | 6 +- tv/tuner/1.0/vts/functional/DvrTests.h | 6 +- tv/tuner/1.0/vts/functional/FilterTests.cpp | 6 +- tv/tuner/1.0/vts/functional/FilterTests.h | 5 +- .../VtsHalTvTunerV1_0TargetTest.cpp | 435 ++++++------------ .../functional/VtsHalTvTunerV1_0TargetTest.h | 102 ++-- .../VtsHalTvTunerV1_0TestConfigurations.h | 30 +- 9 files changed, 266 insertions(+), 341 deletions(-) diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp index f610c60743..dab3c177a5 100644 --- a/tv/tuner/1.0/default/Filter.cpp +++ b/tv/tuner/1.0/default/Filter.cpp @@ -73,18 +73,22 @@ Return Filter::configure(const DemuxFilterSettings& settings) { switch (mType.mainType) { case DemuxFilterMainType::TS: mTpid = settings.ts().tpid; + if (mType.subType.tsFilterType() == DemuxTsFilterType::AUDIO || + mType.subType.tsFilterType() == DemuxTsFilterType::VIDEO) { + mIsMediaFilter = true; + } break; case DemuxFilterMainType::MMTP: - /*mmtpSettings*/ + if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO || + mType.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) { + mIsMediaFilter = true; + } break; case DemuxFilterMainType::IP: - /*ipSettings*/ break; case DemuxFilterMainType::TLV: - /*tlvSettings*/ break; case DemuxFilterMainType::ALP: - /*alpSettings*/ break; default: break; @@ -241,9 +245,7 @@ void Filter::filterThreadLoop() { } void Filter::freeAvHandle() { - if (mType.mainType != DemuxFilterMainType::TS || - (mType.subType.tsFilterType() == DemuxTsFilterType::AUDIO && - mType.subType.tsFilterType() == DemuxTsFilterType::VIDEO)) { + if (!mIsMediaFilter) { return; } for (int i = 0; i < mFilterEvent.events.size(); i++) { diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h index afed98eb0a..9b49ad8bd9 100644 --- a/tv/tuner/1.0/default/Filter.h +++ b/tv/tuner/1.0/default/Filter.h @@ -103,6 +103,7 @@ class Filter : public IFilter { uint32_t mFilterId; uint32_t mBufferSize; DemuxFilterType mType; + bool mIsMediaFilter = false; DemuxFilterSettings mFilterSettings; uint16_t mTpid; diff --git a/tv/tuner/1.0/vts/functional/DvrTests.cpp b/tv/tuner/1.0/vts/functional/DvrTests.cpp index a1ce23d730..9b24aa7a08 100644 --- a/tv/tuner/1.0/vts/functional/DvrTests.cpp +++ b/tv/tuner/1.0/vts/functional/DvrTests.cpp @@ -186,14 +186,14 @@ void DvrCallback::stopRecordThread() { android::Mutex::Autolock autoLock(mRecordThreadLock); } -AssertionResult DvrTests::openDvrInDemux(DvrType type) { +AssertionResult DvrTests::openDvrInDemux(DvrType type, uint32_t bufferSize) { Result status; EXPECT_TRUE(mDemux) << "Test with openDemux first."; // Create dvr callback mDvrCallback = new DvrCallback(); - mDemux->openDvr(type, FMQ_SIZE_1M, mDvrCallback, [&](Result result, const sp& dvr) { + mDemux->openDvr(type, bufferSize, mDvrCallback, [&](Result result, const sp& dvr) { mDvr = dvr; status = result; }); @@ -264,4 +264,4 @@ void DvrTests::closeDvr() { ASSERT_TRUE(mDemux); ASSERT_TRUE(mDvr); ASSERT_TRUE(mDvr->close() == Result::SUCCESS); -} \ No newline at end of file +} diff --git a/tv/tuner/1.0/vts/functional/DvrTests.h b/tv/tuner/1.0/vts/functional/DvrTests.h index 74ef58ebf1..d60ce2bd9d 100644 --- a/tv/tuner/1.0/vts/functional/DvrTests.h +++ b/tv/tuner/1.0/vts/functional/DvrTests.h @@ -146,7 +146,7 @@ class DvrTests { void setService(sp tuner) { mService = tuner; } void setDemux(sp demux) { mDemux = demux; } - void startPlaybackInputThread(string dataInputFile, PlaybackSettings settings) { + void startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings) { PlaybackConf conf{ .inputDataFile = dataInputFile, .setting = settings, @@ -162,7 +162,7 @@ class DvrTests { void testRecordOutput() { mDvrCallback->testRecordOutput(); } void stopRecordThread() { mDvrCallback->stopPlaybackThread(); } - AssertionResult openDvrInDemux(DvrType type); + AssertionResult openDvrInDemux(DvrType type, uint32_t bufferSize); AssertionResult configDvr(DvrSettings setting); AssertionResult getDvrMQDescriptor(); AssertionResult attachFilterToDvr(sp filter); @@ -184,4 +184,4 @@ class DvrTests { pthread_t mPlaybackshread; bool mPlaybackThreadRunning; -}; \ No newline at end of file +}; diff --git a/tv/tuner/1.0/vts/functional/FilterTests.cpp b/tv/tuner/1.0/vts/functional/FilterTests.cpp index 82e955d90e..4639e59c62 100644 --- a/tv/tuner/1.0/vts/functional/FilterTests.cpp +++ b/tv/tuner/1.0/vts/functional/FilterTests.cpp @@ -128,7 +128,7 @@ bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) { return true; } -AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type) { +AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type, uint32_t bufferSize) { Result status; EXPECT_TRUE(mDemux) << "Test with openDemux first."; @@ -136,7 +136,7 @@ AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type) { mFilterCallback = new FilterCallback(); // Add filter to the local demux - mDemux->openFilter(type, FMQ_SIZE_16M, mFilterCallback, + mDemux->openFilter(type, bufferSize, mFilterCallback, [&](Result result, const sp& filter) { mFilter = filter; status = result; @@ -223,4 +223,4 @@ AssertionResult FilterTests::closeFilter(uint32_t filterId) { mFilters.erase(filterId); } return AssertionResult(status == Result::SUCCESS); -} \ No newline at end of file +} diff --git a/tv/tuner/1.0/vts/functional/FilterTests.h b/tv/tuner/1.0/vts/functional/FilterTests.h index dc798c9b1e..71efce4e21 100644 --- a/tv/tuner/1.0/vts/functional/FilterTests.h +++ b/tv/tuner/1.0/vts/functional/FilterTests.h @@ -78,9 +78,6 @@ enum FilterEventType : uint8_t { using FilterMQ = MessageQueue; using MQDesc = MQDescriptorSync; -const uint32_t FMQ_SIZE_1M = 0x100000; -const uint32_t FMQ_SIZE_16M = 0x1000000; - #define WAIT_TIMEOUT 3000000000 class FilterCallback : public IFilterCallback { @@ -153,7 +150,7 @@ class FilterTests { std::map> getFilterCallbacks() { return mFilterCallbacks; } - AssertionResult openFilterInDemux(DemuxFilterType type); + AssertionResult openFilterInDemux(DemuxFilterType type, uint32_t bufferSize); AssertionResult getNewlyOpenedFilterId(uint32_t& filterId); AssertionResult configFilter(DemuxFilterSettings setting, uint32_t filterId); AssertionResult getFilterMQDescriptor(uint32_t filterId); diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index f211be2e90..c5b159f4f3 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -17,7 +17,7 @@ #include "VtsHalTvTunerV1_0TargetTest.h" namespace { -/*======================== Start Descrambler APIs Tests Implementation ========================*/ + AssertionResult TunerHidlTest::createDescrambler(uint32_t demuxId) { Result status; mService->openDescrambler([&](Result result, const sp& descrambler) { @@ -46,10 +46,8 @@ AssertionResult TunerHidlTest::closeDescrambler() { mDescrambler = nullptr; return AssertionResult(status == Result::SUCCESS); } -/*========================= End Descrambler APIs Tests Implementation =========================*/ -/*========================== Start Data Flow Tests Implementation ==========================*/ -AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutputFiles*/) { +AssertionResult TunerBroadcastHidlTest::filterDataOutputTest(vector /*goldenOutputFiles*/) { // Data Verify Module std::map>::iterator it; std::map> filterCallbacks = mFilterTests.getFilterCallbacks(); @@ -59,154 +57,43 @@ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutp return success(); } -/* - * TODO: re-enable the tests after finalizing the test refactoring. - */ -/*AssertionResult TunerHidlTest::playbackDataFlowTest( - vector filterConf, PlaybackConf playbackConf, - vector \/\*goldenOutputFiles\*\/) { - Result status; - int filterIdsSize; - // Filter Configuration Module - for (int i = 0; i < filterConf.size(); i++) { - if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) == - failure() || - // TODO use a map to save the FMQs/EvenFlags and pass to callback - getFilterMQDescriptor() == failure()) { - return failure(); - } - filterIdsSize = mUsedFilterIds.size(); - mUsedFilterIds.resize(filterIdsSize + 1); - mUsedFilterIds[filterIdsSize] = mFilterId; - mFilters[mFilterId] = mFilter; - mFilterCallbacks[mFilterId] = mFilterCallback; - mFilterCallback->updateFilterMQ(mFilterMQDescriptor); - // mDemuxCallback->updateGoldenOutputMap(goldenOutputFiles[i]); - status = mFilter->start(); - if (status != Result::SUCCESS) { - return failure(); - } - } - - // Playback Input Module - PlaybackSettings playbackSetting = playbackConf.setting; - if (addPlaybackToDemux(playbackSetting) == failure() || - getPlaybackMQDescriptor() == failure()) { - return failure(); - } - for (int i = 0; i <= filterIdsSize; i++) { - if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) { - return failure(); - } - } - mDvrCallback->startPlaybackInputThread(playbackConf, mPlaybackMQDescriptor); - status = mDvr->start(); - if (status != Result::SUCCESS) { - return failure(); - } - +AssertionResult TunerPlaybackHidlTest::filterDataOutputTest(vector /*goldenOutputFiles*/) { // Data Verify Module std::map>::iterator it; - for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) { + std::map> filterCallbacks = mFilterTests.getFilterCallbacks(); + for (it = filterCallbacks.begin(); it != filterCallbacks.end(); it++) { it->second->testFilterDataOutput(); } - mDvrCallback->stopPlaybackThread(); - - // Clean Up Module - for (int i = 0; i <= filterIdsSize; i++) { - if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) { - return failure(); - } - } - if (mDvr->stop() != Result::SUCCESS) { - return failure(); - } - mUsedFilterIds.clear(); - mFilterCallbacks.clear(); - mFilters.clear(); - return closeDemux(); + return success(); } -AssertionResult TunerHidlTest::recordDataFlowTest(vector filterConf, - RecordSettings recordSetting, - vector goldenOutputFiles) { - Result status; - hidl_vec feIds; +void TunerFilterHidlTest::configSingleFilterInDemuxTest(FilterConfig filterConf, + FrontendConfig frontendConf) { + uint32_t feId; + uint32_t demuxId; + sp demux; + uint32_t filterId; - mService->getFrontendIds([&](Result result, const hidl_vec& frontendIds) { - status = result; - feIds = frontendIds; - }); + mFrontendTests.getFrontendIdByType(frontendConf.type, feId); + ASSERT_TRUE(feId != INVALID_ID); + ASSERT_TRUE(mFrontendTests.openFrontendById(feId)); + ASSERT_TRUE(mFrontendTests.setFrontendCallback()); + ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId)); + ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); + mFilterTests.setDemux(demux); + ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize)); + ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId)); + ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId)); + ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId)); + ASSERT_TRUE(mFilterTests.startFilter(filterId)); + ASSERT_TRUE(mFilterTests.stopFilter(filterId)); + ASSERT_TRUE(mFilterTests.closeFilter(filterId)); + ASSERT_TRUE(mDemuxTests.closeDemux()); + ASSERT_TRUE(mFrontendTests.closeFrontend()); +} - if (feIds.size() == 0) { - ALOGW("[ WARN ] Frontend isn't available"); - return failure(); - } - - FrontendDvbtSettings dvbt{ - .frequency = 1000, - }; - FrontendSettings settings; - settings.dvbt(dvbt); - - int filterIdsSize; - // Filter Configuration Module - for (int i = 0; i < filterConf.size(); i++) { - if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) == - failure() || - // TODO use a map to save the FMQs/EvenFlags and pass to callback - getFilterMQDescriptor() == failure()) { - return failure(); - } - filterIdsSize = mUsedFilterIds.size(); - mUsedFilterIds.resize(filterIdsSize + 1); - mUsedFilterIds[filterIdsSize] = mFilterId; - mFilters[mFilterId] = mFilter; - } - - // Record Config Module - if (addRecordToDemux(recordSetting) == failure() || - getRecordMQDescriptor() == failure()) { - return failure(); - } - for (int i = 0; i <= filterIdsSize; i++) { - if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) { - return failure(); - } - } - - mDvrCallback->startRecordOutputThread(recordSetting, mRecordMQDescriptor); - status = mDvr->start(); - if (status != Result::SUCCESS) { - return failure(); - } - - if (setDemuxFrontendDataSource(feIds[0]) != success()) { - return failure(); - } - - // Data Verify Module - mDvrCallback->testRecordOutput(); - - // Clean Up Module - for (int i = 0; i <= filterIdsSize; i++) { - if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) { - return failure(); - } - } - if (mFrontend->stopTune() != Result::SUCCESS) { - return failure(); - } - mUsedFilterIds.clear(); - mFilterCallbacks.clear(); - mFilters.clear(); - return closeDemux(); -}*/ -/*========================= End Data Flow Tests Implementation =========================*/ - -/*================================= Start Test Module =================================*/ -void TunerHidlTest::broadcastSingleFilterTest(FilterConfig filterConf, - FrontendConfig frontendConf) { +void TunerBroadcastHidlTest::broadcastSingleFilterTest(FilterConfig filterConf, + FrontendConfig frontendConf) { uint32_t feId; uint32_t demuxId; sp demux; @@ -224,15 +111,14 @@ void TunerHidlTest::broadcastSingleFilterTest(FilterConfig filterConf, ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId)); ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); mFilterTests.setDemux(demux); - ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type)); + ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize)); ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId)); ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId)); ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId)); ASSERT_TRUE(mFilterTests.startFilter(filterId)); // tune test ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf)); - // broadcast data flow test - ASSERT_TRUE(broadcastDataFlowTest(goldenOutputFiles)); + ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles)); ASSERT_TRUE(mFrontendTests.stopTuneFrontend()); ASSERT_TRUE(mFilterTests.stopFilter(filterId)); ASSERT_TRUE(mFilterTests.closeFilter(filterId)); @@ -240,9 +126,38 @@ void TunerHidlTest::broadcastSingleFilterTest(FilterConfig filterConf, ASSERT_TRUE(mFrontendTests.closeFrontend()); } -void TunerDvrHidlTest::attachSingleFilterToDvrTest(FilterConfig filterConf, - FrontendConfig frontendConf, DvrConfig dvrConf) { - description("Open and configure a Dvr in Demux."); +void TunerPlaybackHidlTest::playbackSingleFilterTest(FilterConfig filterConf, DvrConfig dvrConf) { + uint32_t demuxId; + sp demux; + uint32_t filterId; + sp filter; + + ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId)); + mFilterTests.setDemux(demux); + mDvrTests.setDemux(demux); + ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrConf.type, dvrConf.bufferSize)); + ASSERT_TRUE(mDvrTests.configDvr(dvrConf.settings)); + ASSERT_TRUE(mDvrTests.getDvrMQDescriptor()); + ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize)); + ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId)); + ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId)); + ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId)); + filter = mFilterTests.getFilterById(filterId); + ASSERT_TRUE(filter != nullptr); + mDvrTests.startPlaybackInputThread(dvrConf.playbackInputFile, dvrConf.settings.playback()); + ASSERT_TRUE(mDvrTests.startDvr()); + ASSERT_TRUE(mFilterTests.startFilter(filterId)); + ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles)); + mDvrTests.stopPlaybackThread(); + ASSERT_TRUE(mFilterTests.stopFilter(filterId)); + ASSERT_TRUE(mDvrTests.stopDvr()); + ASSERT_TRUE(mFilterTests.closeFilter(filterId)); + mDvrTests.closeDvr(); + ASSERT_TRUE(mDemuxTests.closeDemux()); +} + +void TunerRecordHidlTest::recordSingleFilterTest(FilterConfig filterConf, + FrontendConfig frontendConf, DvrConfig dvrConf) { uint32_t feId; uint32_t demuxId; sp demux; @@ -257,31 +172,38 @@ void TunerDvrHidlTest::attachSingleFilterToDvrTest(FilterConfig filterConf, ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); mFilterTests.setDemux(demux); mDvrTests.setDemux(demux); - ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrConf.type)); + ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrConf.type, dvrConf.bufferSize)); ASSERT_TRUE(mDvrTests.configDvr(dvrConf.settings)); ASSERT_TRUE(mDvrTests.getDvrMQDescriptor()); - ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type)); + ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize)); ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId)); ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId)); ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId)); - ASSERT_TRUE(mFilterTests.startFilter(filterId)); filter = mFilterTests.getFilterById(filterId); ASSERT_TRUE(filter != nullptr); ASSERT_TRUE(mDvrTests.attachFilterToDvr(filter)); - ASSERT_TRUE(mDvrTests.detachFilterToDvr(filter)); + mDvrTests.startRecordOutputThread(dvrConf.settings.record()); + ASSERT_TRUE(mDvrTests.startDvr()); + ASSERT_TRUE(mFilterTests.startFilter(filterId)); + mDvrTests.testRecordOutput(); + mDvrTests.stopRecordThread(); ASSERT_TRUE(mFilterTests.stopFilter(filterId)); + ASSERT_TRUE(mDvrTests.stopDvr()); + ASSERT_TRUE(mDvrTests.detachFilterToDvr(filter)); ASSERT_TRUE(mFilterTests.closeFilter(filterId)); mDvrTests.closeDvr(); ASSERT_TRUE(mDemuxTests.closeDemux()); ASSERT_TRUE(mFrontendTests.closeFrontend()); } -void TunerFilterHidlTest::configSingleFilterInDemuxTest(FilterConfig filterConf, - FrontendConfig frontendConf) { +void TunerRecordHidlTest::attachSingleFilterToRecordDvrTest(FilterConfig filterConf, + FrontendConfig frontendConf, + DvrConfig dvrConf) { uint32_t feId; uint32_t demuxId; sp demux; uint32_t filterId; + sp filter; mFrontendTests.getFrontendIdByType(frontendConf.type, feId); ASSERT_TRUE(feId != INVALID_ID); @@ -290,20 +212,28 @@ void TunerFilterHidlTest::configSingleFilterInDemuxTest(FilterConfig filterConf, ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId)); ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); mFilterTests.setDemux(demux); - ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type)); + mDvrTests.setDemux(demux); + ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrConf.type, dvrConf.bufferSize)); + ASSERT_TRUE(mDvrTests.configDvr(dvrConf.settings)); + ASSERT_TRUE(mDvrTests.getDvrMQDescriptor()); + ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize)); ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId)); ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId)); ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId)); + filter = mFilterTests.getFilterById(filterId); + ASSERT_TRUE(filter != nullptr); + ASSERT_TRUE(mDvrTests.attachFilterToDvr(filter)); + ASSERT_TRUE(mDvrTests.startDvr()); ASSERT_TRUE(mFilterTests.startFilter(filterId)); ASSERT_TRUE(mFilterTests.stopFilter(filterId)); + ASSERT_TRUE(mDvrTests.stopDvr()); + ASSERT_TRUE(mDvrTests.detachFilterToDvr(filter)); ASSERT_TRUE(mFilterTests.closeFilter(filterId)); + mDvrTests.closeDvr(); ASSERT_TRUE(mDemuxTests.closeDemux()); ASSERT_TRUE(mFrontendTests.closeFrontend()); } -/*================================== End Test Module ==================================*/ -/***************************** End Test Implementation *****************************/ -/******************************** Start Test Entry **********************************/ TEST_P(TunerFrontendHidlTest, TuneFrontend) { description("Tune one Frontend with specific setting and check Lock event"); mFrontendTests.tuneTest(frontendArray[DVBT]); @@ -331,6 +261,7 @@ TEST_P(TunerDemuxHidlTest, openDemux) { ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId)); ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); ASSERT_TRUE(mDemuxTests.closeDemux()); + ASSERT_TRUE(mFrontendTests.closeFrontend()); } TEST_P(TunerFilterHidlTest, StartFilterInDemux) { @@ -339,23 +270,48 @@ TEST_P(TunerFilterHidlTest, StartFilterInDemux) { configSingleFilterInDemuxTest(filterArray[TS_VIDEO0], frontendArray[DVBT]); } -TEST_P(TunerDvrHidlTest, AttachFiltersToRecordTest) { +TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowVideoFilterTest) { + description("Test Video Filter functionality in Broadcast use case."); + broadcastSingleFilterTest(filterArray[TS_VIDEO1], frontendArray[DVBS]); +} + +TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowAudioFilterTest) { + description("Test Audio Filter functionality in Broadcast use case."); + broadcastSingleFilterTest(filterArray[TS_AUDIO0], frontendArray[DVBS]); +} + +TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowTsFilterTest) { + description("Test TS Filter functionality in Broadcast use case."); + broadcastSingleFilterTest(filterArray[TS_TS0], frontendArray[DVBS]); +} + +TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowSectionFilterTest) { + description("Test Section Filter functionality in Broadcast use case."); + broadcastSingleFilterTest(filterArray[TS_SECTION0], frontendArray[DVBS]); +} + +TEST_P(TunerBroadcastHidlTest, IonBufferTest) { + description("Test the av filter data bufferring."); + broadcastSingleFilterTest(filterArray[TS_VIDEO0], frontendArray[DVBS]); +} + +TEST_P(TunerPlaybackHidlTest, PlaybackDataFlowWithTsRecordFilterTest) { + description("Feed ts data from playback and configure Ts filter to get output"); + playbackSingleFilterTest(filterArray[TS_VIDEO1], dvrArray[DVR_PLAYBACK0]); +} + +TEST_P(TunerRecordHidlTest, AttachFiltersToRecordTest) { description("Attach a single filter to the record dvr test."); // TODO use paramterized tests - attachSingleFilterToDvrTest(filterArray[TS_VIDEO0], frontendArray[DVBT], dvrArray[DVR_RECORD0]); + attachSingleFilterToRecordDvrTest(filterArray[TS_RECORD0], frontendArray[DVBT], + dvrArray[DVR_RECORD0]); } -TEST_P(TunerDvrHidlTest, AttachFiltersToPlaybackTest) { - description("Attach a single filter to the playback dvr test."); - // TODO use paramterized tests - attachSingleFilterToDvrTest(filterArray[TS_VIDEO0], frontendArray[DVBT], - dvrArray[DVR_PLAYBACK0]); +TEST_P(TunerRecordHidlTest, RecordDataFlowWithTsRecordFilterTest) { + description("Feed ts data from frontend to recording and test with ts record filter"); + recordSingleFilterTest(filterArray[TS_RECORD0], frontendArray[DVBT], dvrArray[DVR_RECORD0]); } -/*============================ Start Descrambler Tests ============================*/ -/* - * TODO: re-enable the tests after finalizing the test refactoring. - */ TEST_P(TunerHidlTest, CreateDescrambler) { description("Create Descrambler"); uint32_t feId; @@ -368,132 +324,16 @@ TEST_P(TunerHidlTest, CreateDescrambler) { ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId)); ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); ASSERT_TRUE(createDescrambler(demuxId)); - ASSERT_TRUE(mDemuxTests.closeDemux()); ASSERT_TRUE(closeDescrambler()); + ASSERT_TRUE(mDemuxTests.closeDemux()); + ASSERT_TRUE(mFrontendTests.closeFrontend()); } -/*============================== End Descrambler Tests ==============================*/ - -/*============================== Start Data Flow Tests ==============================*/ -TEST_P(TunerHidlTest, BroadcastDataFlowVideoFilterTest) { - description("Test Video Filter functionality in Broadcast use case."); - broadcastSingleFilterTest(filterArray[TS_VIDEO1], frontendArray[DVBS]); -} - -TEST_P(TunerHidlTest, BroadcastDataFlowAudioFilterTest) { - description("Test Audio Filter functionality in Broadcast use case."); - broadcastSingleFilterTest(filterArray[TS_AUDIO0], frontendArray[DVBS]); -} - -TEST_P(TunerHidlTest, BroadcastDataFlowTsFilterTest) { - description("Test TS Filter functionality in Broadcast use case."); - broadcastSingleFilterTest(filterArray[TS_TS0], frontendArray[DVBS]); -} - -TEST_P(TunerHidlTest, BroadcastDataFlowSectionFilterTest) { - description("Test Section Filter functionality in Broadcast use case."); - broadcastSingleFilterTest(filterArray[TS_SECTION0], frontendArray[DVBS]); -} - -TEST_P(TunerHidlTest, IonBufferTest) { - description("Test the av filter data bufferring."); - broadcastSingleFilterTest(filterArray[TS_VIDEO0], frontendArray[DVBS]); -} -/* - * TODO: re-enable the tests after finalizing the testing stream. - */ -/*TEST_P(TunerHidlTest, PlaybackDataFlowWithSectionFilterTest) { - description("Feed ts data from playback and configure pes filter to get output"); - - // todo modulize the filter conf parser - vector filterConf; - filterConf.resize(1); - - DemuxFilterSettings filterSetting; - DemuxTsFilterSettings tsFilterSetting{ - .tpid = 18, - }; - DemuxFilterSectionSettings sectionFilterSetting; - tsFilterSetting.filterSettings.section(sectionFilterSetting); - filterSetting.ts(tsFilterSetting); - - DemuxFilterType type{ - .mainType = DemuxFilterMainType::TS, - }; - type.subType.tsFilterType(DemuxTsFilterType::SECTION); - FilterConf sectionFilterConf{ - .type = type, - .setting = filterSetting, - }; - filterConf[0] = sectionFilterConf; - - PlaybackSettings playbackSetting{ - .statusMask = 0xf, - .lowThreshold = 0x1000, - .highThreshold = 0x07fff, - .dataFormat = DataFormat::TS, - .packetSize = 188, - }; - - PlaybackConf playbackConf{ - .inputDataFile = "/vendor/etc/test1.ts", - .setting = playbackSetting, - }; - - vector goldenOutputFiles; - - ASSERT_TRUE(playbackDataFlowTest(filterConf, playbackConf, goldenOutputFiles)); -} - -TEST_P(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) { - description("Feed ts data from frontend to recording and test with ts record filter"); - - // todo modulize the filter conf parser - vector filterConf; - filterConf.resize(1); - - DemuxFilterSettings filterSetting; - DemuxTsFilterSettings tsFilterSetting{ - .tpid = 119, - }; - DemuxFilterRecordSettings recordFilterSetting; - tsFilterSetting.filterSettings.record(recordFilterSetting); - filterSetting.ts(tsFilterSetting); - - DemuxFilterType type{ - .mainType = DemuxFilterMainType::TS, - }; - type.subType.tsFilterType(DemuxTsFilterType::RECORD); - FilterConf recordFilterConf{ - .type = type, - .setting = filterSetting, - }; - filterConf[0] = recordFilterConf; - - RecordSettings recordSetting{ - .statusMask = 0xf, - .lowThreshold = 0x1000, - .highThreshold = 0x07fff, - .dataFormat = DataFormat::TS, - .packetSize = 188, - }; - - vector goldenOutputFiles; - - ASSERT_TRUE(recordDataFlowTest(filterConf, recordSetting, goldenOutputFiles)); -}*/ -/*============================== End Data Flow Tests ==============================*/ -/******************************** End Test Entry **********************************/ INSTANTIATE_TEST_SUITE_P( PerInstance, TunerFrontendHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), android::hardware::PrintInstanceNameToString); -INSTANTIATE_TEST_SUITE_P( - PerInstance, TunerHidlTest, - testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), - android::hardware::PrintInstanceNameToString); - INSTANTIATE_TEST_SUITE_P( PerInstance, TunerDemuxHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), @@ -505,7 +345,22 @@ INSTANTIATE_TEST_SUITE_P( android::hardware::PrintInstanceNameToString); INSTANTIATE_TEST_SUITE_P( - PerInstance, TunerDvrHidlTest, + PerInstance, TunerBroadcastHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), + android::hardware::PrintInstanceNameToString); + +INSTANTIATE_TEST_SUITE_P( + PerInstance, TunerPlaybackHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), + android::hardware::PrintInstanceNameToString); + +INSTANTIATE_TEST_SUITE_P( + PerInstance, TunerRecordHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), + android::hardware::PrintInstanceNameToString); + +INSTANTIATE_TEST_SUITE_P( + PerInstance, TunerHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), android::hardware::PrintInstanceNameToString); } // namespace diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h index 37b28660fb..21a98559f9 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h @@ -33,13 +33,19 @@ static AssertionResult success() { namespace { +void initConfiguration() { + initFrontendConfig(); + initFrontendScanConfig(); + initFilterConfig(); + initDvrConfig(); +} + class TunerFrontendHidlTest : public testing::TestWithParam { public: virtual void SetUp() override { mService = ITuner::getService(GetParam()); ASSERT_NE(mService, nullptr); - initFrontendConfig(); - initFrontendScanConfig(); + initConfiguration(); mFrontendTests.setService(mService); } @@ -58,9 +64,7 @@ class TunerDemuxHidlTest : public testing::TestWithParam { virtual void SetUp() override { mService = ITuner::getService(GetParam()); ASSERT_NE(mService, nullptr); - initFrontendConfig(); - initFrontendScanConfig(); - initFilterConfig(); + initConfiguration(); mFrontendTests.setService(mService); mDemuxTests.setService(mService); @@ -81,9 +85,7 @@ class TunerFilterHidlTest : public testing::TestWithParam { virtual void SetUp() override { mService = ITuner::getService(GetParam()); ASSERT_NE(mService, nullptr); - initFrontendConfig(); - initFrontendScanConfig(); - initFilterConfig(); + initConfiguration(); mFrontendTests.setService(mService); mDemuxTests.setService(mService); @@ -103,15 +105,39 @@ class TunerFilterHidlTest : public testing::TestWithParam { FilterTests mFilterTests; }; -class TunerDvrHidlTest : public testing::TestWithParam { +class TunerBroadcastHidlTest : public testing::TestWithParam { public: virtual void SetUp() override { mService = ITuner::getService(GetParam()); ASSERT_NE(mService, nullptr); - initFrontendConfig(); - initFrontendScanConfig(); - initFilterConfig(); - initDvrConfig(); + initConfiguration(); + + mFrontendTests.setService(mService); + mDemuxTests.setService(mService); + mFilterTests.setService(mService); + } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp mService; + FrontendTests mFrontendTests; + DemuxTests mDemuxTests; + FilterTests mFilterTests; + + AssertionResult filterDataOutputTest(vector goldenOutputFiles); + + void broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf); +}; + +class TunerPlaybackHidlTest : public testing::TestWithParam { + public: + virtual void SetUp() override { + mService = ITuner::getService(GetParam()); + ASSERT_NE(mService, nullptr); + initConfiguration(); mFrontendTests.setService(mService); mDemuxTests.setService(mService); @@ -124,8 +150,39 @@ class TunerDvrHidlTest : public testing::TestWithParam { RecordProperty("description", description); } - void attachSingleFilterToDvrTest(FilterConfig filterConf, FrontendConfig frontendConf, - DvrConfig dvrConf); + sp mService; + FrontendTests mFrontendTests; + DemuxTests mDemuxTests; + FilterTests mFilterTests; + DvrTests mDvrTests; + + AssertionResult filterDataOutputTest(vector goldenOutputFiles); + + void playbackSingleFilterTest(FilterConfig filterConf, DvrConfig dvrConf); +}; + +class TunerRecordHidlTest : public testing::TestWithParam { + public: + virtual void SetUp() override { + mService = ITuner::getService(GetParam()); + ASSERT_NE(mService, nullptr); + initConfiguration(); + + mFrontendTests.setService(mService); + mDemuxTests.setService(mService); + mFilterTests.setService(mService); + mDvrTests.setService(mService); + } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + void attachSingleFilterToRecordDvrTest(FilterConfig filterConf, FrontendConfig frontendConf, + DvrConfig dvrConf); + void recordSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf, + DvrConfig dvrConf); sp mService; FrontendTests mFrontendTests; @@ -139,13 +196,10 @@ class TunerHidlTest : public testing::TestWithParam { virtual void SetUp() override { mService = ITuner::getService(GetParam()); ASSERT_NE(mService, nullptr); - initFrontendConfig(); - initFrontendScanConfig(); - initFilterConfig(); + initConfiguration(); mFrontendTests.setService(mService); mDemuxTests.setService(mService); - mFilterTests.setService(mService); } protected: @@ -156,20 +210,10 @@ class TunerHidlTest : public testing::TestWithParam { sp mService; FrontendTests mFrontendTests; DemuxTests mDemuxTests; - FilterTests mFilterTests; sp mDescrambler; AssertionResult createDescrambler(uint32_t demuxId); AssertionResult closeDescrambler(); - - AssertionResult playbackDataFlowTest(vector filterConf, PlaybackConf playbackConf, - vector goldenOutputFiles); - AssertionResult recordDataFlowTest(vector filterConf, - RecordSettings recordSetting, - vector goldenOutputFiles); - AssertionResult broadcastDataFlowTest(vector goldenOutputFiles); - - void broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf); }; } // namespace diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h index a74fa02855..a9f892262c 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h @@ -26,6 +26,7 @@ using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; using android::hardware::tv::tuner::V1_0::DemuxFilterMainType; using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterType; +using android::hardware::tv::tuner::V1_0::DemuxRecordScIndexType; using android::hardware::tv::tuner::V1_0::DemuxTpid; using android::hardware::tv::tuner::V1_0::DemuxTsFilterType; using android::hardware::tv::tuner::V1_0::DvrSettings; @@ -45,6 +46,10 @@ using android::hardware::tv::tuner::V1_0::RecordSettings; using namespace std; +const uint32_t FMQ_SIZE_1M = 0x100000; +const uint32_t FMQ_SIZE_4M = 0x400000; +const uint32_t FMQ_SIZE_16M = 0x1000000; + typedef enum { TS_VIDEO0, TS_VIDEO1, @@ -53,6 +58,7 @@ typedef enum { TS_PCR0, TS_SECTION0, TS_TS0, + TS_RECORD0, FILTER_MAX, } Filter; @@ -74,6 +80,7 @@ typedef enum { } Dvr; struct FilterConfig { + uint32_t bufferSize; DemuxFilterType type; DemuxFilterSettings settings; }; @@ -93,7 +100,9 @@ struct ChannelConfig { struct DvrConfig { DvrType type; + uint32_t bufferSize; DvrSettings settings; + string playbackInputFile; }; static FrontendConfig frontendArray[FILTER_MAX]; @@ -143,20 +152,24 @@ inline void initFilterConfig() { // TS VIDEO filter setting for default implementation testing filterArray[TS_VIDEO0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_VIDEO0].type.subType.tsFilterType(DemuxTsFilterType::VIDEO); + filterArray[TS_VIDEO0].bufferSize = FMQ_SIZE_16M; filterArray[TS_VIDEO0].settings.ts().tpid = 119; filterArray[TS_VIDEO0].settings.ts().filterSettings.av({.isPassthrough = false}); filterArray[TS_VIDEO1].type.mainType = DemuxFilterMainType::TS; filterArray[TS_VIDEO1].type.subType.tsFilterType(DemuxTsFilterType::VIDEO); + filterArray[TS_VIDEO1].bufferSize = FMQ_SIZE_16M; filterArray[TS_VIDEO1].settings.ts().tpid = 81; filterArray[TS_VIDEO1].settings.ts().filterSettings.av({.isPassthrough = false}); // TS AUDIO filter setting filterArray[TS_AUDIO0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_AUDIO0].type.subType.tsFilterType(DemuxTsFilterType::AUDIO); + filterArray[TS_AUDIO0].bufferSize = FMQ_SIZE_16M; filterArray[TS_AUDIO0].settings.ts().tpid = 84; filterArray[TS_AUDIO0].settings.ts().filterSettings.av({.isPassthrough = false}); // TS PES filter setting filterArray[TS_PES0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_PES0].type.subType.tsFilterType(DemuxTsFilterType::PES); + filterArray[TS_PES0].bufferSize = FMQ_SIZE_16M; filterArray[TS_PES0].settings.ts().tpid = 256; filterArray[TS_PES0].settings.ts().filterSettings.pesData({ .isRaw = false, @@ -165,20 +178,30 @@ inline void initFilterConfig() { // TS PCR filter setting filterArray[TS_PCR0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_PCR0].type.subType.tsFilterType(DemuxTsFilterType::PCR); + filterArray[TS_PCR0].bufferSize = FMQ_SIZE_16M; filterArray[TS_PCR0].settings.ts().tpid = 81; filterArray[TS_PCR0].settings.ts().filterSettings.noinit(); // TS filter setting filterArray[TS_TS0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_TS0].type.subType.tsFilterType(DemuxTsFilterType::TS); - filterArray[TS_TS0].settings.ts().tpid = 48; + filterArray[TS_TS0].bufferSize = FMQ_SIZE_16M; + filterArray[TS_TS0].settings.ts().tpid = 18; filterArray[TS_TS0].settings.ts().filterSettings.noinit(); // TS SECTION filter setting filterArray[TS_SECTION0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_SECTION0].type.subType.tsFilterType(DemuxTsFilterType::SECTION); + filterArray[TS_SECTION0].bufferSize = FMQ_SIZE_16M; filterArray[TS_SECTION0].settings.ts().tpid = 48; filterArray[TS_SECTION0].settings.ts().filterSettings.section({ .isRaw = false, }); + // TS RECORD filter setting + filterArray[TS_RECORD0].type.mainType = DemuxFilterMainType::TS; + filterArray[TS_RECORD0].type.subType.tsFilterType(DemuxTsFilterType::RECORD); + filterArray[TS_RECORD0].settings.ts().tpid = 81; + filterArray[TS_RECORD0].settings.ts().filterSettings.record({ + .scIndexType = DemuxRecordScIndexType::NONE, + }); }; /** Configuration array for the dvr test */ @@ -191,6 +214,7 @@ inline void initDvrConfig() { .packetSize = 188, }; dvrArray[DVR_RECORD0].type = DvrType::RECORD; + dvrArray[DVR_RECORD0].bufferSize = FMQ_SIZE_4M; dvrArray[DVR_RECORD0].settings.record(recordSettings); PlaybackSettings playbackSettings{ .statusMask = 0xf, @@ -200,5 +224,7 @@ inline void initDvrConfig() { .packetSize = 188, }; dvrArray[DVR_PLAYBACK0].type = DvrType::PLAYBACK; + dvrArray[DVR_PLAYBACK0].playbackInputFile = "/vendor/etc/test1.ts"; + dvrArray[DVR_PLAYBACK0].bufferSize = FMQ_SIZE_4M; dvrArray[DVR_PLAYBACK0].settings.playback(playbackSettings); -}; \ No newline at end of file +}; From 908a0a2d6b54d5e536fe9a357ab8d456b62e7ec5 Mon Sep 17 00:00:00 2001 From: Hayden Gomes Date: Tue, 28 Apr 2020 15:12:19 -0700 Subject: [PATCH 0882/1022] Fix AudioControl@2.0 fade check Fade now checks isValidValue rather than !isValidValue Bug: 155225937 Test: built ran and adjusted fade Change-Id: I21b0dee8ebd677217b037c38cc744a77cf145709 --- automotive/audiocontrol/2.0/default/AudioControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automotive/audiocontrol/2.0/default/AudioControl.cpp b/automotive/audiocontrol/2.0/default/AudioControl.cpp index 5bde8396f2..b7c11cdf07 100644 --- a/automotive/audiocontrol/2.0/default/AudioControl.cpp +++ b/automotive/audiocontrol/2.0/default/AudioControl.cpp @@ -69,7 +69,7 @@ Return AudioControl::setBalanceTowardRight(float value) { } Return AudioControl::setFadeTowardFront(float value) { - if (!isValidValue(value)) { + if (isValidValue(value)) { // Just log in this default mock implementation LOG(INFO) << "Fader set to " << value; } else { From 99a9a529bae8dee04d2c3d428414936b25b92725 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Tue, 28 Apr 2020 18:18:38 -0700 Subject: [PATCH 0883/1022] Remove non-test ScopedWakelock dependency Unit tests were depending on a non test library unecesarrily and it was causing unit test build failure. Fixes: 155239061 Test: atest android.hardware.sensors@2.0-halproxy-unit-tests Change-Id: I057a432fdbef93680a67558c27ed7adc7fedfbbc --- sensors/common/default/2.X/multihal/tests/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/sensors/common/default/2.X/multihal/tests/Android.bp b/sensors/common/default/2.X/multihal/tests/Android.bp index 7692b51de0..e0b3b8d3d0 100644 --- a/sensors/common/default/2.X/multihal/tests/Android.bp +++ b/sensors/common/default/2.X/multihal/tests/Android.bp @@ -86,7 +86,6 @@ cc_test { shared_libs: [ "android.hardware.sensors@1.0", "android.hardware.sensors@2.0", - "android.hardware.sensors@2.0-ScopedWakelock", "android.hardware.sensors@2.1", "libbase", "libcutils", From 6e8163a241695b19e21fafaaa049498574a2d9fb Mon Sep 17 00:00:00 2001 From: Amy Zhang Date: Fri, 24 Apr 2020 15:41:21 -0700 Subject: [PATCH 0884/1022] Fix issues in Tuner VTS Dvr testing This CL fixes the following issues: 1. Modified some unnecessary or not proper debug msg in the VTS/Default impl 2. Some incorrect VTS testing order 3. Added a flush test on Dvr status 4. Used a ts from Android aosp cts for testing 5. Changed the configuration to run with the new ts on cf 6. Fixed some deadlock and logic issues in the VTS/Default implementation Test: atest VtsHalTvTunerV1_0TargetTest Bug: 150989084 Bug: 153366959 Bug: 153367094 Change-Id: If7eb8534caff4fc11ac4e166ef5391e8f543408d --- tv/tuner/1.0/default/Demux.cpp | 27 +++++++----- tv/tuner/1.0/default/Demux.h | 2 +- tv/tuner/1.0/default/Dvr.cpp | 39 +++++++++++----- tv/tuner/1.0/default/Dvr.h | 2 + tv/tuner/1.0/default/Filter.cpp | 5 +-- tv/tuner/1.0/default/Frontend.h | 2 +- tv/tuner/1.0/vts/functional/DvrTests.cpp | 36 +++++++-------- tv/tuner/1.0/vts/functional/DvrTests.h | 44 +++++++++---------- .../VtsHalTvTunerV1_0TargetTest.cpp | 18 +++----- .../VtsHalTvTunerV1_0TestConfigurations.h | 14 +++--- 10 files changed, 100 insertions(+), 89 deletions(-) diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp index 95b4ebc7a6..4e5ae4b626 100644 --- a/tv/tuner/1.0/default/Demux.cpp +++ b/tv/tuner/1.0/default/Demux.cpp @@ -71,7 +71,7 @@ Return Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize, mUsedFilterIds.insert(filterId); if (cb == nullptr) { - ALOGW("callback can't be null"); + ALOGW("[Demux] callback can't be null"); _hidl_cb(Result::INVALID_ARGUMENT, new Filter()); return Void(); } @@ -82,9 +82,14 @@ Return Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize, _hidl_cb(Result::UNKNOWN_ERROR, filter); return Void(); } - mFilters[filterId] = filter; - _hidl_cb(Result::SUCCESS, filter); + mFilters[filterId] = filter; + bool result = true; + if (mDvr != nullptr && mDvr->getType() == DvrType::PLAYBACK) { + result = mDvr->addPlaybackFilter(filter); + } + + _hidl_cb(result ? Result::SUCCESS : Result::INVALID_ARGUMENT, filter); return Void(); } @@ -130,7 +135,7 @@ Return Demux::openDvr(DvrType type, uint32_t bufferSize, const sp data) { set::iterator it; + uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff)); + if (DEBUG_DEMUX) { + ALOGW("[Demux] start ts filter pid: %d", pid); + } for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { - uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff)); - if (DEBUG_FILTER) { - ALOGW("start ts filter pid: %d", pid); - } if (pid == mFilters[*it]->getTpid()) { mFilters[*it]->updateFilterOutput(data); } @@ -187,10 +192,10 @@ void Demux::startBroadcastTsFilter(vector data) { void Demux::sendFrontendInputToRecord(vector data) { set::iterator it; + if (DEBUG_DEMUX) { + ALOGW("[Demux] update record filter output"); + } for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) { - if (DEBUG_FILTER) { - ALOGW("update record filter output"); - } mFilters[*it]->updateRecordOutput(data); } } diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h index 759e348d93..3c91dafbd1 100644 --- a/tv/tuner/1.0/default/Demux.h +++ b/tv/tuner/1.0/default/Demux.h @@ -188,7 +188,7 @@ class Demux : public IDemux { int mPesSizeLeft = 0; vector mPesOutput; - const bool DEBUG_FILTER = false; + const bool DEBUG_DEMUX = false; }; } // namespace implementation diff --git a/tv/tuner/1.0/default/Dvr.cpp b/tv/tuner/1.0/default/Dvr.cpp index 3088a9d73b..adb263553e 100644 --- a/tv/tuner/1.0/default/Dvr.cpp +++ b/tv/tuner/1.0/default/Dvr.cpp @@ -71,13 +71,10 @@ Return Dvr::attachFilter(const sp& filter) { } // check if the attached filter is a record filter - mFilters[filterId] = filter; - mIsRecordFilterAttached = true; if (!mDemux->attachRecordFilter(filterId)) { return Result::INVALID_ARGUMENT; } - mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached); return Result::SUCCESS; } @@ -110,7 +107,6 @@ Return Dvr::detachFilter(const sp& filter) { // If all the filters are detached, record can't be started if (mFilters.empty()) { mIsRecordFilterAttached = false; - mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached); } return Result::SUCCESS; @@ -132,8 +128,7 @@ Return Dvr::start() { pthread_setname_np(mDvrThread, "playback_waiting_loop"); } else if (mType == DvrType::RECORD) { mRecordStatus = RecordStatus::DATA_READY; - mIsRecordStarted = true; - mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached); + mDemux->setIsRecording(mType == DvrType::RECORD); } // TODO start another thread to send filter status callback to the framework @@ -149,7 +144,7 @@ Return Dvr::stop() { std::lock_guard lock(mDvrThreadLock); mIsRecordStarted = false; - mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached); + mDemux->setIsRecording(false); return Result::SUCCESS; } @@ -175,7 +170,7 @@ bool Dvr::createDvrMQ() { std::unique_ptr tmpDvrMQ = std::unique_ptr(new (std::nothrow) DvrMQ(mBufferSize, true)); if (!tmpDvrMQ->isValid()) { - ALOGW("Failed to create FMQ of DVR"); + ALOGW("[Dvr] Failed to create FMQ of DVR"); return false; } @@ -256,7 +251,6 @@ bool Dvr::readPlaybackFMQ() { int playbackPacketSize = mDvrSettings.playback().packetSize; vector dataOutputBuffer; dataOutputBuffer.resize(playbackPacketSize); - // Dispatch the packet to the PID matching filter output buffer for (int i = 0; i < size / playbackPacketSize; i++) { if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) { @@ -283,7 +277,6 @@ void Dvr::startTpidFilter(vector data) { bool Dvr::startFilterDispatcher() { std::map>::iterator it; - // Handle the output data per filter type for (it = mFilters.begin(); it != mFilters.end(); it++) { if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) { @@ -296,7 +289,10 @@ bool Dvr::startFilterDispatcher() { bool Dvr::writeRecordFMQ(const std::vector& data) { std::lock_guard lock(mWriteLock); - ALOGW("[Dvr] write record FMQ"); + if (mRecordStatus == RecordStatus::OVERFLOW) { + ALOGW("[Dvr] stops writing and wait for the client side flushing."); + return true; + } if (mDvrMQ->write(data.data(), data.size())) { mDvrEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); maySendRecordStatusCallback(); @@ -333,6 +329,27 @@ RecordStatus Dvr::checkRecordStatusChange(uint32_t availableToWrite, uint32_t av return mRecordStatus; } +bool Dvr::addPlaybackFilter(sp filter) { + uint32_t filterId; + Result status; + + filter->getId([&](Result result, uint32_t id) { + filterId = id; + status = result; + }); + + if (status != Result::SUCCESS) { + return false; + } + + mFilters[filterId] = filter; + return true; +} + +DvrType Dvr::getType() { + return mType; +} + } // namespace implementation } // namespace V1_0 } // namespace tuner diff --git a/tv/tuner/1.0/default/Dvr.h b/tv/tuner/1.0/default/Dvr.h index f39d8db152..08afd5dc83 100644 --- a/tv/tuner/1.0/default/Dvr.h +++ b/tv/tuner/1.0/default/Dvr.h @@ -81,6 +81,8 @@ class Dvr : public IDvr { bool createDvrMQ(); void sendBroadcastInputToDvrRecord(vector byteBuffer); bool writeRecordFMQ(const std::vector& data); + DvrType getType(); + bool addPlaybackFilter(sp filter); private: // Demux service diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp index dab3c177a5..fef7a3599c 100644 --- a/tv/tuner/1.0/default/Filter.cpp +++ b/tv/tuner/1.0/default/Filter.cpp @@ -149,7 +149,7 @@ bool Filter::createFilterMQ() { std::unique_ptr tmpFilterMQ = std::unique_ptr(new (std::nothrow) FilterMQ(mBufferSize, true)); if (!tmpFilterMQ->isValid()) { - ALOGW("Failed to create FMQ of filter with id: %d", mFilterId); + ALOGW("[Filter] Failed to create FMQ of filter with id: %d", mFilterId); return false; } @@ -290,13 +290,11 @@ uint16_t Filter::getTpid() { void Filter::updateFilterOutput(vector data) { std::lock_guard lock(mFilterOutputLock); - ALOGD("[Filter] filter output updated"); mFilterOutput.insert(mFilterOutput.end(), data.begin(), data.end()); } void Filter::updateRecordOutput(vector data) { std::lock_guard lock(mRecordFilterOutputLock); - ALOGD("[Filter] record filter output updated"); mRecordFilterOutput.insert(mRecordFilterOutput.end(), data.begin(), data.end()); } @@ -438,7 +436,6 @@ Result Filter::startMediaFilterHandler() { if (mFilterOutput.empty()) { return Result::SUCCESS; } - for (int i = 0; i < mFilterOutput.size(); i += 188) { if (mPesSizeLeft == 0) { uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) | diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h index 8a30b91e87..65537d7a23 100644 --- a/tv/tuner/1.0/default/Frontend.h +++ b/tv/tuner/1.0/default/Frontend.h @@ -76,7 +76,7 @@ class Frontend : public IFrontend { FrontendId mId = 0; bool mIsLocked = false; - const string FRONTEND_STREAM_FILE = "/vendor/etc/dumpTs3.ts"; + const string FRONTEND_STREAM_FILE = "/vendor/etc/segment000000.ts"; std::ifstream mFrontendData; }; diff --git a/tv/tuner/1.0/vts/functional/DvrTests.cpp b/tv/tuner/1.0/vts/functional/DvrTests.cpp index 9b24aa7a08..7e7f8e6da8 100644 --- a/tv/tuner/1.0/vts/functional/DvrTests.cpp +++ b/tv/tuner/1.0/vts/functional/DvrTests.cpp @@ -16,17 +16,13 @@ #include "DvrTests.h" -void DvrCallback::startPlaybackInputThread(PlaybackConf playbackConf, +void DvrCallback::startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings, MQDesc& playbackMQDescriptor) { + mInputDataFile = dataInputFile; + mPlaybackSettings = settings; mPlaybackMQ = std::make_unique(playbackMQDescriptor, true /* resetPointers */); EXPECT_TRUE(mPlaybackMQ); - struct PlaybackThreadArgs* threadArgs = - (struct PlaybackThreadArgs*)malloc(sizeof(struct PlaybackThreadArgs)); - threadArgs->user = this; - threadArgs->playbackConf = &playbackConf; - threadArgs->keepWritingPlaybackFMQ = &mKeepWritingPlaybackFMQ; - - pthread_create(&mPlaybackThread, NULL, __threadLoopPlayback, (void*)threadArgs); + pthread_create(&mPlaybackThread, NULL, __threadLoopPlayback, this); pthread_setname_np(mPlaybackThread, "test_playback_input_loop"); } @@ -37,15 +33,13 @@ void DvrCallback::stopPlaybackThread() { android::Mutex::Autolock autoLock(mPlaybackThreadLock); } -void* DvrCallback::__threadLoopPlayback(void* threadArgs) { - DvrCallback* const self = - static_cast(((struct PlaybackThreadArgs*)threadArgs)->user); - self->playbackThreadLoop(((struct PlaybackThreadArgs*)threadArgs)->playbackConf, - ((struct PlaybackThreadArgs*)threadArgs)->keepWritingPlaybackFMQ); +void* DvrCallback::__threadLoopPlayback(void* user) { + DvrCallback* const self = static_cast(user); + self->playbackThreadLoop(); return 0; } -void DvrCallback::playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ) { +void DvrCallback::playbackThreadLoop() { android::Mutex::Autolock autoLock(mPlaybackThreadLock); mPlaybackThreadRunning = true; @@ -56,10 +50,10 @@ void DvrCallback::playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWriti android::OK); // open the stream and get its length - std::ifstream inputData(playbackConf->inputDataFile, std::ifstream::binary); - int writeSize = playbackConf->setting.packetSize * 6; + std::ifstream inputData(mInputDataFile.c_str(), std::ifstream::binary); + int writeSize = mPlaybackSettings.packetSize * 6; char* buffer = new char[writeSize]; - ALOGW("[vts] playback thread loop start %s", playbackConf->inputDataFile.c_str()); + ALOGW("[vts] playback thread loop start %s!", mInputDataFile.c_str()); if (!inputData.is_open()) { mPlaybackThreadRunning = false; ALOGW("[vts] Error %s", strerror(errno)); @@ -67,7 +61,7 @@ void DvrCallback::playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWriti while (mPlaybackThreadRunning) { // move the stream pointer for packet size * 6 every read until the end - while (*keepWritingPlaybackFMQ) { + while (mKeepWritingPlaybackFMQ) { inputData.read(buffer, writeSize); if (!inputData) { int leftSize = inputData.gcount(); @@ -105,6 +99,7 @@ void DvrCallback::testRecordOutput() { while (mDataOutputBuffer.empty()) { if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { EXPECT_TRUE(false) << "record output matching pid does not output within timeout"; + stopRecordThread(); return; } } @@ -138,6 +133,7 @@ void DvrCallback::recordThreadLoop(RecordSettings* /*recordSettings*/, bool* kee ALOGD("[vts] DvrCallback record threadLoop start."); android::Mutex::Autolock autoLock(mRecordThreadLock); mRecordThreadRunning = true; + mKeepReadingRecordFMQ = true; // Create the EventFlag that is used to signal the HAL impl that data have been // read from the Record FMQ @@ -183,7 +179,6 @@ bool DvrCallback::readRecordFMQ() { void DvrCallback::stopRecordThread() { mKeepReadingRecordFMQ = false; mRecordThreadRunning = false; - android::Mutex::Autolock autoLock(mRecordThreadLock); } AssertionResult DvrTests::openDvrInDemux(DvrType type, uint32_t bufferSize) { @@ -198,6 +193,9 @@ AssertionResult DvrTests::openDvrInDemux(DvrType type, uint32_t bufferSize) { status = result; }); + if (status == Result::SUCCESS) { + mDvrCallback->setDvr(mDvr); + } return AssertionResult(status == Result::SUCCESS); } diff --git a/tv/tuner/1.0/vts/functional/DvrTests.h b/tv/tuner/1.0/vts/functional/DvrTests.h index d60ce2bd9d..dd00c27431 100644 --- a/tv/tuner/1.0/vts/functional/DvrTests.h +++ b/tv/tuner/1.0/vts/functional/DvrTests.h @@ -54,15 +54,10 @@ using android::hardware::tv::tuner::V1_0::Result; #define WAIT_TIMEOUT 3000000000 -struct PlaybackConf { - string inputDataFile; - PlaybackSettings setting; -}; - class DvrCallback : public IDvrCallback { public: virtual Return onRecordStatus(DemuxFilterStatus status) override { - ALOGW("[vts] record status %hhu", status); + ALOGD("[vts] record status %hhu", status); switch (status) { case DemuxFilterStatus::DATA_READY: break; @@ -70,7 +65,12 @@ class DvrCallback : public IDvrCallback { break; case DemuxFilterStatus::HIGH_WATER: case DemuxFilterStatus::OVERFLOW: - ALOGW("[vts] record overflow. Flushing"); + ALOGD("[vts] record overflow. Flushing."); + EXPECT_TRUE(mDvr) << "Dvr callback is not set with an IDvr"; + if (mDvr) { + Result result = mDvr->flush(); + ALOGD("[vts] Flushing result %d.", result); + } break; } return Void(); @@ -78,16 +78,16 @@ class DvrCallback : public IDvrCallback { virtual Return onPlaybackStatus(PlaybackStatus status) override { // android::Mutex::Autolock autoLock(mMsgLock); - ALOGW("[vts] playback status %d", status); + ALOGD("[vts] playback status %d", status); switch (status) { case PlaybackStatus::SPACE_EMPTY: case PlaybackStatus::SPACE_ALMOST_EMPTY: - ALOGW("[vts] keep playback inputing %d", status); + ALOGD("[vts] keep playback inputing %d", status); mKeepWritingPlaybackFMQ = true; break; case PlaybackStatus::SPACE_ALMOST_FULL: case PlaybackStatus::SPACE_FULL: - ALOGW("[vts] stop playback inputing %d", status); + ALOGD("[vts] stop playback inputing %d", status); mKeepWritingPlaybackFMQ = false; break; } @@ -98,21 +98,19 @@ class DvrCallback : public IDvrCallback { void testRecordOutput(); void stopRecordThread(); - void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor); + void startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings, + MQDesc& playbackMQDescriptor); void startRecordOutputThread(RecordSettings recordSettings, MQDesc& recordMQDescriptor); - static void* __threadLoopPlayback(void* threadArgs); + static void* __threadLoopPlayback(void* user); static void* __threadLoopRecord(void* threadArgs); - void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ); + void playbackThreadLoop(); void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ); bool readRecordFMQ(); + void setDvr(sp dvr) { mDvr = dvr; } + private: - struct PlaybackThreadArgs { - DvrCallback* user; - PlaybackConf* playbackConf; - bool* keepWritingPlaybackFMQ; - }; struct RecordThreadArgs { DvrCallback* user; RecordSettings* recordSettings; @@ -137,6 +135,10 @@ class DvrCallback : public IDvrCallback { bool mRecordThreadRunning; pthread_t mPlaybackThread; pthread_t mRecordThread; + string mInputDataFile; + PlaybackSettings mPlaybackSettings; + + sp mDvr = nullptr; // int mPidFilterOutputCount = 0; }; @@ -147,11 +149,7 @@ class DvrTests { void setDemux(sp demux) { mDemux = demux; } void startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings) { - PlaybackConf conf{ - .inputDataFile = dataInputFile, - .setting = settings, - }; - mDvrCallback->startPlaybackInputThread(conf, mDvrMQDescriptor); + mDvrCallback->startPlaybackInputThread(dataInputFile, settings, mDvrMQDescriptor); }; void startRecordOutputThread(RecordSettings settings) { diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index c5b159f4f3..c44f77d1a1 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -130,7 +130,6 @@ void TunerPlaybackHidlTest::playbackSingleFilterTest(FilterConfig filterConf, Dv uint32_t demuxId; sp demux; uint32_t filterId; - sp filter; ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId)); mFilterTests.setDemux(demux); @@ -142,8 +141,6 @@ void TunerPlaybackHidlTest::playbackSingleFilterTest(FilterConfig filterConf, Dv ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId)); ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId)); ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId)); - filter = mFilterTests.getFilterById(filterId); - ASSERT_TRUE(filter != nullptr); mDvrTests.startPlaybackInputThread(dvrConf.playbackInputFile, dvrConf.settings.playback()); ASSERT_TRUE(mDvrTests.startDvr()); ASSERT_TRUE(mFilterTests.startFilter(filterId)); @@ -181,12 +178,14 @@ void TunerRecordHidlTest::recordSingleFilterTest(FilterConfig filterConf, ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId)); filter = mFilterTests.getFilterById(filterId); ASSERT_TRUE(filter != nullptr); - ASSERT_TRUE(mDvrTests.attachFilterToDvr(filter)); mDvrTests.startRecordOutputThread(dvrConf.settings.record()); + ASSERT_TRUE(mDvrTests.attachFilterToDvr(filter)); ASSERT_TRUE(mDvrTests.startDvr()); ASSERT_TRUE(mFilterTests.startFilter(filterId)); + ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf)); mDvrTests.testRecordOutput(); mDvrTests.stopRecordThread(); + ASSERT_TRUE(mFrontendTests.stopTuneFrontend()); ASSERT_TRUE(mFilterTests.stopFilter(filterId)); ASSERT_TRUE(mDvrTests.stopDvr()); ASSERT_TRUE(mDvrTests.detachFilterToDvr(filter)); @@ -280,11 +279,6 @@ TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowAudioFilterTest) { broadcastSingleFilterTest(filterArray[TS_AUDIO0], frontendArray[DVBS]); } -TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowTsFilterTest) { - description("Test TS Filter functionality in Broadcast use case."); - broadcastSingleFilterTest(filterArray[TS_TS0], frontendArray[DVBS]); -} - TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowSectionFilterTest) { description("Test Section Filter functionality in Broadcast use case."); broadcastSingleFilterTest(filterArray[TS_SECTION0], frontendArray[DVBS]); @@ -295,9 +289,9 @@ TEST_P(TunerBroadcastHidlTest, IonBufferTest) { broadcastSingleFilterTest(filterArray[TS_VIDEO0], frontendArray[DVBS]); } -TEST_P(TunerPlaybackHidlTest, PlaybackDataFlowWithTsRecordFilterTest) { - description("Feed ts data from playback and configure Ts filter to get output"); - playbackSingleFilterTest(filterArray[TS_VIDEO1], dvrArray[DVR_PLAYBACK0]); +TEST_P(TunerPlaybackHidlTest, PlaybackDataFlowWithTsSectionFilterTest) { + description("Feed ts data from playback and configure Ts section filter to get output"); + playbackSingleFilterTest(filterArray[TS_SECTION0], dvrArray[DVR_PLAYBACK0]); } TEST_P(TunerRecordHidlTest, AttachFiltersToRecordTest) { diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h index a9f892262c..b84013b665 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h @@ -153,18 +153,18 @@ inline void initFilterConfig() { filterArray[TS_VIDEO0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_VIDEO0].type.subType.tsFilterType(DemuxTsFilterType::VIDEO); filterArray[TS_VIDEO0].bufferSize = FMQ_SIZE_16M; - filterArray[TS_VIDEO0].settings.ts().tpid = 119; + filterArray[TS_VIDEO0].settings.ts().tpid = 256; filterArray[TS_VIDEO0].settings.ts().filterSettings.av({.isPassthrough = false}); filterArray[TS_VIDEO1].type.mainType = DemuxFilterMainType::TS; filterArray[TS_VIDEO1].type.subType.tsFilterType(DemuxTsFilterType::VIDEO); filterArray[TS_VIDEO1].bufferSize = FMQ_SIZE_16M; - filterArray[TS_VIDEO1].settings.ts().tpid = 81; + filterArray[TS_VIDEO1].settings.ts().tpid = 256; filterArray[TS_VIDEO1].settings.ts().filterSettings.av({.isPassthrough = false}); // TS AUDIO filter setting filterArray[TS_AUDIO0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_AUDIO0].type.subType.tsFilterType(DemuxTsFilterType::AUDIO); filterArray[TS_AUDIO0].bufferSize = FMQ_SIZE_16M; - filterArray[TS_AUDIO0].settings.ts().tpid = 84; + filterArray[TS_AUDIO0].settings.ts().tpid = 256; filterArray[TS_AUDIO0].settings.ts().filterSettings.av({.isPassthrough = false}); // TS PES filter setting filterArray[TS_PES0].type.mainType = DemuxFilterMainType::TS; @@ -179,19 +179,19 @@ inline void initFilterConfig() { filterArray[TS_PCR0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_PCR0].type.subType.tsFilterType(DemuxTsFilterType::PCR); filterArray[TS_PCR0].bufferSize = FMQ_SIZE_16M; - filterArray[TS_PCR0].settings.ts().tpid = 81; + filterArray[TS_PCR0].settings.ts().tpid = 256; filterArray[TS_PCR0].settings.ts().filterSettings.noinit(); // TS filter setting filterArray[TS_TS0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_TS0].type.subType.tsFilterType(DemuxTsFilterType::TS); filterArray[TS_TS0].bufferSize = FMQ_SIZE_16M; - filterArray[TS_TS0].settings.ts().tpid = 18; + filterArray[TS_TS0].settings.ts().tpid = 256; filterArray[TS_TS0].settings.ts().filterSettings.noinit(); // TS SECTION filter setting filterArray[TS_SECTION0].type.mainType = DemuxFilterMainType::TS; filterArray[TS_SECTION0].type.subType.tsFilterType(DemuxTsFilterType::SECTION); filterArray[TS_SECTION0].bufferSize = FMQ_SIZE_16M; - filterArray[TS_SECTION0].settings.ts().tpid = 48; + filterArray[TS_SECTION0].settings.ts().tpid = 256; filterArray[TS_SECTION0].settings.ts().filterSettings.section({ .isRaw = false, }); @@ -224,7 +224,7 @@ inline void initDvrConfig() { .packetSize = 188, }; dvrArray[DVR_PLAYBACK0].type = DvrType::PLAYBACK; - dvrArray[DVR_PLAYBACK0].playbackInputFile = "/vendor/etc/test1.ts"; + dvrArray[DVR_PLAYBACK0].playbackInputFile = "/vendor/etc/segment000000.ts"; dvrArray[DVR_PLAYBACK0].bufferSize = FMQ_SIZE_4M; dvrArray[DVR_PLAYBACK0].settings.playback(playbackSettings); }; From 67888489ce9d0a2f3a7cc29e46ef8e6c521537c1 Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Tue, 28 Apr 2020 15:12:41 -0400 Subject: [PATCH 0885/1022] Update tests for multihal to test HAL 2.1 Updates tests and fake subhals to support Multi-HAL 2.1 to make on-device testing feasible. Bug: 149758467 Test: Verify that the new unit tests and subhals in this topic load and run on a Pixel device Change-Id: I2be51568ba8dd99aa0588b8945d3d41bda7d9941 --- .../default/2.X/multihal/tests/Android.bp | 12 + .../2.X/multihal/tests/HalProxy_test.cpp | 331 +++++++++++------- .../fake_subhal/IHalProxyCallbackWrapper.h | 107 ++++++ .../2.X/multihal/tests/fake_subhal/Sensor.cpp | 9 +- .../2.X/multihal/tests/fake_subhal/Sensor.h | 12 +- .../tests/fake_subhal/SensorsSubHal.cpp | 120 ++++--- .../tests/fake_subhal/SensorsSubHal.h | 173 +++++++-- 7 files changed, 531 insertions(+), 233 deletions(-) create mode 100644 sensors/common/default/2.X/multihal/tests/fake_subhal/IHalProxyCallbackWrapper.h diff --git a/sensors/common/default/2.X/multihal/tests/Android.bp b/sensors/common/default/2.X/multihal/tests/Android.bp index cfd9e78a6f..6586b0b470 100644 --- a/sensors/common/default/2.X/multihal/tests/Android.bp +++ b/sensors/common/default/2.X/multihal/tests/Android.bp @@ -50,6 +50,7 @@ cc_library { vendor: true, defaults: ["android.hardware.sensors@2.X-fakesubhal-defaults"], cflags: [ + "-DSUB_HAL_VERSION_2_0", "-DSUPPORT_CONTINUOUS_SENSORS", "-DSUB_HAL_NAME=\"FakeSubHal-Continuous\"", ], @@ -59,6 +60,17 @@ cc_library { name: "android.hardware.sensors@2.X-fakesubhal-config2", vendor: true, defaults: ["android.hardware.sensors@2.X-fakesubhal-defaults"], + cflags: [ + "-DSUB_HAL_VERSION_2_0", + "-DSUPPORT_ON_CHANGE_SENSORS", + "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"", + ], +} + +cc_library { + name: "android.hardware.sensors@2.X-fakesubhal-config3", + vendor: true, + defaults: ["android.hardware.sensors@2.X-fakesubhal-defaults"], cflags: [ "-DSUPPORT_ON_CHANGE_SENSORS", "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"", diff --git a/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp index ce65c3cd80..858786af09 100644 --- a/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp +++ b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp @@ -15,12 +15,15 @@ #include +#include #include +#include #include #include "HalProxy.h" #include "SensorsSubHal.h" #include "V2_0/ScopedWakelock.h" +#include "convertV2_1.h" #include #include @@ -38,28 +41,35 @@ using ::android::hardware::sensors::V1_0::SensorFlagBits; using ::android::hardware::sensors::V1_0::SensorInfo; using ::android::hardware::sensors::V1_0::SensorType; using ::android::hardware::sensors::V2_0::EventQueueFlagBits; -using ::android::hardware::sensors::V2_0::ISensorsCallback; using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; using ::android::hardware::sensors::V2_0::implementation::HalProxyCallbackBase; using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock; -using ::android::hardware::sensors::V2_0::subhal::implementation::AddAndRemoveDynamicSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation:: - AllSupportDirectChannelSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation:: - DoesNotSupportDirectChannelSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation:: - SetOperationModeFailingSensorsSubHal; +using ::android::hardware::sensors::V2_1::implementation::convertToNewEvents; +using ::android::hardware::sensors::V2_1::implementation::convertToNewSensorInfos; using ::android::hardware::sensors::V2_1::implementation::HalProxy; +using ::android::hardware::sensors::V2_1::subhal::implementation::AddAndRemoveDynamicSensorsSubHal; +using ::android::hardware::sensors::V2_1::subhal::implementation::AllSensorsSubHal; +using ::android::hardware::sensors::V2_1::subhal::implementation:: + AllSupportDirectChannelSensorsSubHal; +using ::android::hardware::sensors::V2_1::subhal::implementation::ContinuousSensorsSubHal; +using ::android::hardware::sensors::V2_1::subhal::implementation:: + DoesNotSupportDirectChannelSensorsSubHal; +using ::android::hardware::sensors::V2_1::subhal::implementation::OnChangeSensorsSubHal; +using ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0; +using ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1; +using ::android::hardware::sensors::V2_1::subhal::implementation:: + SetOperationModeFailingSensorsSubHal; -using EventMessageQueue = MessageQueue; +using ISensorsCallbackV2_0 = ::android::hardware::sensors::V2_0::ISensorsCallback; +using ISensorsCallbackV2_1 = ::android::hardware::sensors::V2_1::ISensorsCallback; +using EventV1_0 = ::android::hardware::sensors::V1_0::Event; +using EventV2_1 = ::android::hardware::sensors::V2_1::Event; +using EventMessageQueueV2_1 = MessageQueue; +using EventMessageQueueV2_0 = MessageQueue; using WakeupMessageQueue = MessageQueue; // The barebones sensors callback class passed into halproxy initialize calls -class SensorsCallback : public ISensorsCallback { +class SensorsCallback : public ISensorsCallbackV2_0 { public: Return onDynamicSensorsConnected( const hidl_vec& /*dynamicSensorsAdded*/) override { @@ -74,8 +84,30 @@ class SensorsCallback : public ISensorsCallback { } }; +class SensorsCallbackV2_1 : public ISensorsCallbackV2_1 { + public: + Return onDynamicSensorsConnected_2_1( + const hidl_vec<::android::hardware::sensors::V2_1::SensorInfo>& /*dynamicSensorsAdded*/) + override { + // Nothing yet + return Return(); + } + + Return onDynamicSensorsConnected( + const hidl_vec& /*dynamicSensorsAdded*/) override { + // Nothing yet + return Return(); + } + + Return onDynamicSensorsDisconnected( + const hidl_vec& /*dynamicSensorHandlesRemoved*/) override { + // Nothing yet + return Return(); + } +}; + // The sensors callback that expects a variable list of sensors to be added -class TestSensorsCallback : public ISensorsCallback { +class TestSensorsCallback : public ISensorsCallbackV2_0 { public: Return onDynamicSensorsConnected( const hidl_vec& dynamicSensorsAdded) override { @@ -130,10 +162,10 @@ void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector& wakelockQueue, EventFlag* wakelockQueueFlag); -bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& eventQueue, +bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& eventQueue, EventFlag* eventQueueFlag); -std::unique_ptr makeEventFMQ(size_t size); +std::unique_ptr makeEventFMQ(size_t size); std::unique_ptr makeWakelockFMQ(size_t size); @@ -143,7 +175,7 @@ std::unique_ptr makeWakelockFMQ(size_t size); * * @return A proximity event. */ -Event makeProximityEvent(); +EventV1_0 makeProximityEvent(); /** * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor @@ -151,7 +183,7 @@ Event makeProximityEvent(); * * @return A proximity event. */ -Event makeAccelerometerEvent(); +EventV1_0 makeAccelerometerEvent(); /** * Make a certain number of proximity type events with the sensorHandle field set to @@ -161,7 +193,7 @@ Event makeAccelerometerEvent(); * * @return The created list of events. */ -std::vector makeMultipleProximityEvents(size_t numEvents); +std::vector makeMultipleProximityEvents(size_t numEvents); /** * Make a certain number of accelerometer type events with the sensorHandle field set to @@ -171,7 +203,7 @@ std::vector makeMultipleProximityEvents(size_t numEvents); * * @return The created list of events. */ -std::vector makeMultipleAccelerometerEvents(size_t numEvents); +std::vector makeMultipleAccelerometerEvents(size_t numEvents); /** * Given a SensorInfo vector and a sensor handles vector populate 'sensors' with SensorInfo @@ -189,7 +221,7 @@ void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size, // Tests follow TEST(HalProxyTest, GetSensorsListOneSubHalTest) { - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector fakeSubHals{&subHal}; HalProxy proxy(fakeSubHals); @@ -201,8 +233,8 @@ TEST(HalProxyTest, GetSensorsListOneSubHalTest) { } TEST(HalProxyTest, GetSensorsListTwoSubHalTest) { - ContinuousSensorsSubHal continuousSubHal; - OnChangeSensorsSubHal onChangeSubHal; + ContinuousSensorsSubHal continuousSubHal; + OnChangeSensorsSubHal onChangeSubHal; std::vector fakeSubHals; fakeSubHals.push_back(&continuousSubHal); fakeSubHals.push_back(&onChangeSubHal); @@ -222,8 +254,8 @@ TEST(HalProxyTest, GetSensorsListTwoSubHalTest) { } TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) { - ContinuousSensorsSubHal subHal1; - OnChangeSensorsSubHal subHal2; + ContinuousSensorsSubHal subHal1; + OnChangeSensorsSubHal subHal2; std::vector fakeSubHals{&subHal1, &subHal2}; HalProxy proxy(fakeSubHals); @@ -239,7 +271,7 @@ TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) { } TEST(HalProxyTest, SetOperationModeTwoSubHalFailTest) { - AllSensorsSubHal subHal1; + AllSensorsSubHal subHal1; SetOperationModeFailingSensorsSubHal subHal2; std::vector fakeSubHals{&subHal1, &subHal2}; @@ -280,16 +312,16 @@ TEST(HalProxyTest, InitDirectChannelThreeSubHalsUnitTest) { TEST(HalProxyTest, PostSingleNonWakeupEvent) { constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events{makeAccelerometerEvent()}; - subHal.postEvents(events, false /* wakeup */); + std::vector events{makeAccelerometerEvent()}; + subHal.postEvents(convertToNewEvents(events), false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), 1); } @@ -297,28 +329,28 @@ TEST(HalProxyTest, PostSingleNonWakeupEvent) { TEST(HalProxyTest, PostMultipleNonWakeupEvent) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 3; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal.postEvents(events, false /* wakeup */); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal.postEvents(convertToNewEvents(events), false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); } TEST(HalProxyTest, PostSingleWakeupEvent) { constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); EventFlag* eventQueueFlag; @@ -327,8 +359,8 @@ TEST(HalProxyTest, PostSingleWakeupEvent) { EventFlag* wakelockQueueFlag; EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag); - std::vector events{makeProximityEvent()}; - subHal.postEvents(events, true /* wakeup */); + std::vector events{makeProximityEvent()}; + subHal.postEvents(convertToNewEvents(events), true /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), 1); @@ -339,12 +371,12 @@ TEST(HalProxyTest, PostSingleWakeupEvent) { TEST(HalProxyTest, PostMultipleWakeupEvents) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 3; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); EventFlag* eventQueueFlag; @@ -353,8 +385,8 @@ TEST(HalProxyTest, PostMultipleWakeupEvents) { EventFlag* wakelockQueueFlag; EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag); - std::vector events = makeMultipleProximityEvents(kNumEvents); - subHal.postEvents(events, true /* wakeup */); + std::vector events = makeMultipleProximityEvents(kNumEvents); + subHal.postEvents(convertToNewEvents(events), true /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); @@ -365,20 +397,20 @@ TEST(HalProxyTest, PostMultipleWakeupEvents) { TEST(HalProxyTest, PostEventsMultipleSubhals) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 2; - AllSensorsSubHal subHal1, subHal2; + AllSensorsSubHal subHal1, subHal2; std::vector subHals{&subHal1, &subHal2}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal1.postEvents(events, false /* wakeup */); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal1.postEvents(convertToNewEvents(events), false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); - subHal2.postEvents(events, false /* wakeup */); + subHal2.postEvents(convertToNewEvents(events), false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2); } @@ -386,19 +418,19 @@ TEST(HalProxyTest, PostEventsMultipleSubhals) { TEST(HalProxyTest, PostEventsDelayedWrite) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 6; - AllSensorsSubHal subHal1, subHal2; + AllSensorsSubHal subHal1, subHal2; std::vector subHals{&subHal1, &subHal2}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); EventFlag* eventQueueFlag; EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal1.postEvents(events, false /* wakeup */); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal1.postEvents(convertToNewEvents(events), false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kQueueSize); @@ -414,18 +446,20 @@ TEST(HalProxyTest, PostEventsDelayedWrite) { TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 2; - AllSensorsSubHal subHal1, subHal2; + AllSensorsSubHal subHal1, subHal2; std::vector subHals{&subHal1, &subHal2}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, events, false); - std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, events, false); + std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, + convertToNewEvents(events), false); + std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, + convertToNewEvents(events), false); t1.join(); t2.join(); @@ -436,34 +470,34 @@ TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) { TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThread) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 6; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal.postEvents(events, false /* wakeup */); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal.postEvents(convertToNewEvents(events), false /* wakeup */); // Destructing HalProxy object with events on the background thread } TEST(HalProxyTest, DestructingWithUnackedWakeupEventsPosted) { constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events{makeProximityEvent()}; - subHal.postEvents(events, true /* wakeup */); + std::vector events{makeProximityEvent()}; + subHal.postEvents(convertToNewEvents(events), true /* wakeup */); // Not sending any acks back through wakeLockQueue @@ -473,17 +507,17 @@ TEST(HalProxyTest, DestructingWithUnackedWakeupEventsPosted) { TEST(HalProxyTest, ReinitializeWithEventsPendingOnBackgroundThread) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 10; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal.postEvents(events, false /* wakeup */); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal.postEvents(convertToNewEvents(events), false /* wakeup */); eventQueue = makeEventFMQ(kQueueSize); wakeLockQueue = makeWakelockFMQ(kQueueSize); @@ -493,23 +527,23 @@ TEST(HalProxyTest, ReinitializeWithEventsPendingOnBackgroundThread) { EXPECT_EQ(secondInitResult, Result::OK); // Small sleep so that pending writes thread has a change to hit writeBlocking call. std::this_thread::sleep_for(std::chrono::milliseconds(5)); - Event eventOut; + EventV1_0 eventOut; EXPECT_FALSE(eventQueue->read(&eventOut)); } TEST(HalProxyTest, ReinitializingWithUnackedWakeupEventsPosted) { constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events{makeProximityEvent()}; - subHal.postEvents(events, true /* wakeup */); + std::vector events{makeProximityEvent()}; + subHal.postEvents(convertToNewEvents(events), true /* wakeup */); // Not sending any acks back through wakeLockQueue @@ -524,12 +558,12 @@ TEST(HalProxyTest, ReinitializingWithUnackedWakeupEventsPosted) { TEST(HalProxyTest, InitializeManyTimesInARow) { constexpr size_t kQueueSize = 5; constexpr size_t kNumTimesToInit = 100; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); for (size_t i = 0; i < kNumTimesToInit; i++) { @@ -541,15 +575,15 @@ TEST(HalProxyTest, InitializeManyTimesInARow) { TEST(HalProxyTest, OperationModeResetOnInitialize) { constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.setOperationMode(OperationMode::DATA_INJECTION); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - Event event = makeAccelerometerEvent(); + EventV1_0 event = makeAccelerometerEvent(); // Should not be able to inject a non AdditionInfo type event because operation mode should // have been reset to NORMAL EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE); @@ -560,7 +594,7 @@ TEST(HalProxyTest, DynamicSensorsDiscardedOnInitialize) { constexpr size_t kNumSensors = 5; AddAndRemoveDynamicSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); HalProxy proxy(subHals); @@ -575,9 +609,9 @@ TEST(HalProxyTest, DynamicSensorsDiscardedOnInitialize) { } TestSensorsCallback* callback = new TestSensorsCallback(); - ::android::sp callbackPtr = callback; + ::android::sp callbackPtr = callback; proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); - subHal.addDynamicSensors(sensorsToConnect); + subHal.addDynamicSensors(convertToNewSensorInfos(sensorsToConnect)); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove); @@ -594,7 +628,7 @@ TEST(HalProxyTest, DynamicSensorsConnectedTest) { AddAndRemoveDynamicSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(0); + std::unique_ptr eventQueue = makeEventFMQ(0); std::unique_ptr wakeLockQueue = makeWakelockFMQ(0); std::vector sensorsToConnect; @@ -603,9 +637,9 @@ TEST(HalProxyTest, DynamicSensorsConnectedTest) { sensorHandlesToExpect); TestSensorsCallback* callback = new TestSensorsCallback(); - ::android::sp callbackPtr = callback; + ::android::sp callbackPtr = callback; proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); - subHal.addDynamicSensors(sensorsToConnect); + subHal.addDynamicSensors(convertToNewSensorInfos(sensorsToConnect)); std::vector sensorsSeen = callback->getSensorsConnected(); EXPECT_EQ(kNumSensors, sensorsSeen.size()); @@ -622,7 +656,7 @@ TEST(HalProxyTest, DynamicSensorsDisconnectedTest) { AddAndRemoveDynamicSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(0); + std::unique_ptr eventQueue = makeEventFMQ(0); std::unique_ptr wakeLockQueue = makeWakelockFMQ(0); std::vector sensorsToConnect; @@ -647,9 +681,9 @@ TEST(HalProxyTest, DynamicSensorsDisconnectedTest) { nonDynamicSensorHandles.end()); TestSensorsCallback* callback = new TestSensorsCallback(); - ::android::sp callbackPtr = callback; + ::android::sp callbackPtr = callback; proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); - subHal.addDynamicSensors(sensorsToConnect); + subHal.addDynamicSensors(convertToNewSensorInfos(sensorsToConnect)); subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove); std::vector sensorHandlesSeen = callback->getSensorHandlesDisconnected(); @@ -668,15 +702,15 @@ TEST(HalProxyTest, InvalidSensorHandleSubHalIndexProxyCalls) { constexpr size_t kNumSubHals = 3; constexpr size_t kQueueSize = 5; int32_t kNumSubHalsInt32 = static_cast(kNumSubHals); - std::vector subHalObjs(kNumSubHals); + std::vector> subHalObjs(kNumSubHals); std::vector subHals; for (const auto& subHal : subHalObjs) { subHals.push_back((ISensorsSubHal*)(&subHal)); } - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); // Initialize for the injectSensorData call so callback postEvents is valid proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); @@ -688,7 +722,7 @@ TEST(HalProxyTest, InvalidSensorHandleSubHalIndexProxyCalls) { EXPECT_EQ(proxy.activate(0x00000001 | (kNumSubHalsInt32 << 24), true), Result::BAD_VALUE); EXPECT_EQ(proxy.batch(0x00000001 | (kNumSubHalsInt32 << 24), 0, 0), Result::BAD_VALUE); EXPECT_EQ(proxy.flush(0x00000001 | (kNumSubHalsInt32 << 24)), Result::BAD_VALUE); - Event event; + EventV1_0 event; event.sensorHandle = 0x00000001 | (kNumSubHalsInt32 << 24); EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE); } @@ -697,28 +731,28 @@ TEST(HalProxyTest, PostedEventSensorHandleSubHalIndexValid) { constexpr size_t kQueueSize = 5; constexpr int32_t subhal1Index = 0; constexpr int32_t subhal2Index = 1; - AllSensorsSubHal subhal1; - AllSensorsSubHal subhal2; + AllSensorsSubHal subhal1; + AllSensorsSubHal subhal2; std::vector subHals{&subhal1, &subhal2}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); int32_t sensorHandleToPost = 0x00000001; - Event eventIn = makeAccelerometerEvent(); + EventV1_0 eventIn = makeAccelerometerEvent(); eventIn.sensorHandle = sensorHandleToPost; - std::vector eventsToPost{eventIn}; - subhal1.postEvents(eventsToPost, false); + std::vector eventsToPost{eventIn}; + subhal1.postEvents(convertToNewEvents(eventsToPost), false); - Event eventOut; + EventV1_0 eventOut; EXPECT_TRUE(eventQueue->read(&eventOut)); EXPECT_EQ(eventOut.sensorHandle, (subhal1Index << 24) | sensorHandleToPost); - subhal2.postEvents(eventsToPost, false); + subhal2.postEvents(convertToNewEvents(eventsToPost), false); EXPECT_TRUE(eventQueue->read(&eventOut)); @@ -729,22 +763,22 @@ TEST(HalProxyTest, FillAndDrainPendingQueueTest) { constexpr size_t kQueueSize = 5; // TODO: Make this constant linked to same limit in HalProxy.h constexpr size_t kMaxPendingQueueSize = 100000; - AllSensorsSubHal subhal; + AllSensorsSubHal subhal; std::vector subHals{&subhal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); EventFlag* eventQueueFlag; EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); // Fill pending queue - std::vector events = makeMultipleAccelerometerEvents(kQueueSize); - subhal.postEvents(events, false); + std::vector events = makeMultipleAccelerometerEvents(kQueueSize); + subhal.postEvents(convertToNewEvents(events), false); events = makeMultipleAccelerometerEvents(kMaxPendingQueueSize); - subhal.postEvents(events, false); + subhal.postEvents(convertToNewEvents(events), false); // Drain pending queue for (int i = 0; i < kMaxPendingQueueSize + kQueueSize; i += kQueueSize) { @@ -753,9 +787,9 @@ TEST(HalProxyTest, FillAndDrainPendingQueueTest) { // Put one event on pending queue events = makeMultipleAccelerometerEvents(kQueueSize); - subhal.postEvents(events, false); + subhal.postEvents(convertToNewEvents(events), false); events = {makeAccelerometerEvent()}; - subhal.postEvents(events, false); + subhal.postEvents(convertToNewEvents(events), false); // Read out to make room for one event on pending queue to write to FMQ ASSERT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag)); @@ -764,6 +798,35 @@ TEST(HalProxyTest, FillAndDrainPendingQueueTest) { EXPECT_TRUE(readEventsOutOfQueue(1, eventQueue, eventQueueFlag)); } +TEST(HalProxyTest, PostEventsMultipleSubhalsThreadedV2_1) { + constexpr size_t kQueueSize = 5; + constexpr size_t kNumEvents = 2; + AllSensorsSubHal subHal1; + AllSensorsSubHal subHal2; + std::vector<::android::hardware::sensors::V2_0::implementation::ISensorsSubHal*> subHalsV2_0{ + &subHal1}; + std::vector<::android::hardware::sensors::V2_1::implementation::ISensorsSubHal*> subHalsV2_1{ + &subHal2}; + HalProxy proxy(subHalsV2_0, subHalsV2_1); + std::unique_ptr eventQueue = + std::make_unique(kQueueSize, true); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); + ::android::sp callback = new SensorsCallbackV2_1(); + proxy.initialize_2_1(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + + std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, + convertToNewEvents(events), false); + std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, + convertToNewEvents(events), false); + + t1.join(); + t2.join(); + + EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2); +} + // Helper implementations follow void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, const std::vector& subHalSensorsList) { @@ -802,26 +865,26 @@ void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptrwake(static_cast(WakeLockQueueFlagBits::DATA_WRITTEN)); } -bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& eventQueue, +bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& eventQueue, EventFlag* eventQueueFlag) { constexpr int64_t kReadBlockingTimeout = INT64_C(500000000); - std::vector events(numEvents); + std::vector events(numEvents); return eventQueue->readBlocking(events.data(), numEvents, static_cast(EventQueueFlagBits::EVENTS_READ), static_cast(EventQueueFlagBits::READ_AND_PROCESS), kReadBlockingTimeout, eventQueueFlag); } -std::unique_ptr makeEventFMQ(size_t size) { - return std::make_unique(size, true); +std::unique_ptr makeEventFMQ(size_t size) { + return std::make_unique(size, true); } std::unique_ptr makeWakelockFMQ(size_t size) { return std::make_unique(size, true); } -Event makeProximityEvent() { - Event event; +EventV1_0 makeProximityEvent() { + EventV1_0 event; event.timestamp = 0xFF00FF00; // This is the sensorhandle of proximity, which is wakeup type event.sensorHandle = 0x00000008; @@ -830,8 +893,8 @@ Event makeProximityEvent() { return event; } -Event makeAccelerometerEvent() { - Event event; +EventV1_0 makeAccelerometerEvent() { + EventV1_0 event; event.timestamp = 0xFF00FF00; // This is the sensorhandle of proximity, which is wakeup type event.sensorHandle = 0x00000001; @@ -840,16 +903,16 @@ Event makeAccelerometerEvent() { return event; } -std::vector makeMultipleProximityEvents(size_t numEvents) { - std::vector events; +std::vector makeMultipleProximityEvents(size_t numEvents) { + std::vector events; for (size_t i = 0; i < numEvents; i++) { events.push_back(makeProximityEvent()); } return events; } -std::vector makeMultipleAccelerometerEvents(size_t numEvents) { - std::vector events; +std::vector makeMultipleAccelerometerEvents(size_t numEvents) { + std::vector events; for (size_t i = 0; i < numEvents; i++) { events.push_back(makeAccelerometerEvent()); } diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/IHalProxyCallbackWrapper.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/IHalProxyCallbackWrapper.h new file mode 100644 index 0000000000..4542bfdc2c --- /dev/null +++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/IHalProxyCallbackWrapper.h @@ -0,0 +1,107 @@ +/* + * 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. + */ + +#pragma once + +#include "V2_0/SubHal.h" +#include "V2_1/SubHal.h" +#include "convertV2_1.h" + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_1 { +namespace subhal { +namespace implementation { + +/** + * The following callback wrapper classes abstract away common functionality across V2.0 and V2.1 + * interfaces. Much of the logic is common between the two versions and this allows users of the + * classes to only care about the type used at initialization and then interact with either version + * of the callback interface without worrying about the type. + */ +class IHalProxyCallbackWrapperBase { + protected: + using ScopedWakelock = V2_0::implementation::ScopedWakelock; + + public: + virtual ~IHalProxyCallbackWrapperBase() {} + + virtual Return onDynamicSensorsConnected( + const hidl_vec& sensorInfos) = 0; + + virtual Return onDynamicSensorsDisconnected(const hidl_vec& sensorHandles) = 0; + + virtual void postEvents(const std::vector& events, ScopedWakelock wakelock) = 0; + + virtual ScopedWakelock createScopedWakelock(bool lock) = 0; +}; + +template +class HalProxyCallbackWrapperBase : public IHalProxyCallbackWrapperBase { + public: + HalProxyCallbackWrapperBase(sp callback) : mCallback(callback){}; + + Return onDynamicSensorsDisconnected(const hidl_vec& sensorHandles) override { + return mCallback->onDynamicSensorsDisconnected(sensorHandles); + } + + ScopedWakelock createScopedWakelock(bool lock) override { + return mCallback->createScopedWakelock(lock); + } + + protected: + sp mCallback; +}; + +class HalProxyCallbackWrapperV2_0 + : public HalProxyCallbackWrapperBase { + public: + HalProxyCallbackWrapperV2_0(sp callback) + : HalProxyCallbackWrapperBase(callback){}; + + Return onDynamicSensorsConnected(const hidl_vec& sensorInfos) override { + return mCallback->onDynamicSensorsConnected( + V2_1::implementation::convertToOldSensorInfos(sensorInfos)); + } + + void postEvents(const std::vector& events, ScopedWakelock wakelock) override { + return mCallback->postEvents(V2_1::implementation::convertToOldEvents(events), + std::move(wakelock)); + } +}; + +class HalProxyCallbackWrapperV2_1 + : public HalProxyCallbackWrapperBase { + public: + HalProxyCallbackWrapperV2_1(sp callback) + : HalProxyCallbackWrapperBase(callback){}; + + Return onDynamicSensorsConnected(const hidl_vec& sensorInfos) override { + return mCallback->onDynamicSensorsConnected_2_1(sensorInfos); + } + + void postEvents(const std::vector& events, ScopedWakelock wakelock) { + return mCallback->postEvents(events, std::move(wakelock)); + } +}; + +} // namespace implementation +} // namespace subhal +} // namespace V2_1 +} // namespace sensors +} // namespace hardware +} // namespace android diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp index de89a00ef9..1efd971115 100644 --- a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp +++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp @@ -24,13 +24,18 @@ namespace android { namespace hardware { namespace sensors { -namespace V2_0 { +namespace V2_1 { namespace subhal { namespace implementation { using ::android::hardware::sensors::V1_0::MetaDataEventType; +using ::android::hardware::sensors::V1_0::OperationMode; +using ::android::hardware::sensors::V1_0::Result; using ::android::hardware::sensors::V1_0::SensorFlagBits; using ::android::hardware::sensors::V1_0::SensorStatus; +using ::android::hardware::sensors::V2_1::Event; +using ::android::hardware::sensors::V2_1::SensorInfo; +using ::android::hardware::sensors::V2_1::SensorType; Sensor::Sensor(int32_t sensorHandle, ISensorsEventCallback* callback) : mIsEnabled(false), @@ -343,7 +348,7 @@ RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle, } // namespace implementation } // namespace subhal -} // namespace V2_0 +} // namespace V2_1 } // namespace sensors } // namespace hardware } // namespace android diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h index 60f5d3d40a..5cf9f837cf 100644 --- a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h +++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h @@ -16,7 +16,7 @@ #pragma once -#include +#include #include #include @@ -24,16 +24,16 @@ #include #include -using ::android::hardware::sensors::V1_0::Event; using ::android::hardware::sensors::V1_0::OperationMode; using ::android::hardware::sensors::V1_0::Result; -using ::android::hardware::sensors::V1_0::SensorInfo; -using ::android::hardware::sensors::V1_0::SensorType; +using ::android::hardware::sensors::V2_1::Event; +using ::android::hardware::sensors::V2_1::SensorInfo; +using ::android::hardware::sensors::V2_1::SensorType; namespace android { namespace hardware { namespace sensors { -namespace V2_0 { +namespace V2_1 { namespace subhal { namespace implementation { @@ -151,7 +151,7 @@ class RelativeHumiditySensor : public OnChangeSensor { } // namespace implementation } // namespace subhal -} // namespace V2_0 +} // namespace V2_1 } // namespace sensors } // namespace hardware } // namespace android diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp index ff5ff38541..20a4e9de04 100644 --- a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp +++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp @@ -16,33 +16,66 @@ #include "SensorsSubHal.h" -#include +#include #include -ISensorsSubHal* sensorsHalGetSubHal(uint32_t* version) { +#ifdef SUB_HAL_VERSION_2_0 +::android::hardware::sensors::V2_0::implementation::ISensorsSubHal* sensorsHalGetSubHal( + uint32_t* version) { #if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS - static ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal subHal; + static ::android::hardware::sensors::V2_1::subhal::implementation::AllSensorsSubHal< + ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0> + subHal; #elif defined SUPPORT_CONTINUOUS_SENSORS - static ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal + static ::android::hardware::sensors::V2_1::subhal::implementation::ContinuousSensorsSubHal< + ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0> subHal; #elif defined SUPPORT_ON_CHANGE_SENSORS - static ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal subHal; + static ::android::hardware::sensors::V2_1::subhal::implementation::OnChangeSensorsSubHal< + ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0> + subHal; #else - static ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal subHal; + static ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHal< + ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0> + subHal; #endif // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS *version = SUB_HAL_2_0_VERSION; return &subHal; } +#else // SUB_HAL_VERSION_2_0 + +::android::hardware::sensors::V2_1::implementation::ISensorsSubHal* sensorsHalGetSubHal_2_1( + uint32_t* version) { +#if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS + static ::android::hardware::sensors::V2_1::subhal::implementation::AllSensorsSubHal< + ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1> + subHal; +#elif defined SUPPORT_CONTINUOUS_SENSORS + static ::android::hardware::sensors::V2_1::subhal::implementation::ContinuousSensorsSubHal< + ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1> + subHal; +#elif defined SUPPORT_ON_CHANGE_SENSORS + static ::android::hardware::sensors::V2_1::subhal::implementation::OnChangeSensorsSubHal< + ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1> + subHal; +#else + static ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1 subHal; +#endif // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS + *version = SUB_HAL_2_1_VERSION; + return &subHal; +} + +#endif // SUB_HAL_VERSION_2_0 + namespace android { namespace hardware { namespace sensors { -namespace V2_0 { +namespace V2_1 { namespace subhal { namespace implementation { using ::android::hardware::Void; -using ::android::hardware::sensors::V1_0::Event; using ::android::hardware::sensors::V1_0::OperationMode; using ::android::hardware::sensors::V1_0::RateLevel; using ::android::hardware::sensors::V1_0::Result; @@ -50,11 +83,12 @@ using ::android::hardware::sensors::V1_0::SharedMemInfo; using ::android::hardware::sensors::V2_0::SensorTimeout; using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock; +using ::android::hardware::sensors::V2_1::Event; -SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {} +ISensorsSubHalBase::ISensorsSubHalBase() : mCallback(nullptr), mNextHandle(1) {} // Methods from ::android::hardware::sensors::V2_0::ISensors follow. -Return SensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) { +Return ISensorsSubHalBase::getSensorsList(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) { std::vector sensors; for (const auto& sensor : mSensors) { sensors.push_back(sensor.second->getSensorInfo()); @@ -64,7 +98,7 @@ Return SensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) { return Void(); } -Return SensorsSubHal::setOperationMode(OperationMode mode) { +Return ISensorsSubHalBase::setOperationMode(OperationMode mode) { for (auto sensor : mSensors) { sensor.second->setOperationMode(mode); } @@ -72,7 +106,7 @@ Return SensorsSubHal::setOperationMode(OperationMode mode) { return Result::OK; } -Return SensorsSubHal::activate(int32_t sensorHandle, bool enabled) { +Return ISensorsSubHalBase::activate(int32_t sensorHandle, bool enabled) { auto sensor = mSensors.find(sensorHandle); if (sensor != mSensors.end()) { sensor->second->activate(enabled); @@ -81,8 +115,8 @@ Return SensorsSubHal::activate(int32_t sensorHandle, bool enabled) { return Result::BAD_VALUE; } -Return SensorsSubHal::batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t /* maxReportLatencyNs */) { +Return ISensorsSubHalBase::batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t /* maxReportLatencyNs */) { auto sensor = mSensors.find(sensorHandle); if (sensor != mSensors.end()) { sensor->second->batch(samplingPeriodNs); @@ -91,7 +125,7 @@ Return SensorsSubHal::batch(int32_t sensorHandle, int64_t samplingPeriod return Result::BAD_VALUE; } -Return SensorsSubHal::flush(int32_t sensorHandle) { +Return ISensorsSubHalBase::flush(int32_t sensorHandle) { auto sensor = mSensors.find(sensorHandle); if (sensor != mSensors.end()) { return sensor->second->flush(); @@ -99,7 +133,7 @@ Return SensorsSubHal::flush(int32_t sensorHandle) { return Result::BAD_VALUE; } -Return SensorsSubHal::injectSensorData(const Event& event) { +Return ISensorsSubHalBase::injectSensorData(const Event& event) { auto sensor = mSensors.find(event.sensorHandle); if (sensor != mSensors.end()) { return sensor->second->injectEvent(event); @@ -108,24 +142,24 @@ Return SensorsSubHal::injectSensorData(const Event& event) { return Result::BAD_VALUE; } -Return SensorsSubHal::registerDirectChannel(const SharedMemInfo& /* mem */, - registerDirectChannel_cb _hidl_cb) { +Return ISensorsSubHalBase::registerDirectChannel( + const SharedMemInfo& /* mem */, V2_0::ISensors::registerDirectChannel_cb _hidl_cb) { _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */); return Return(); } -Return SensorsSubHal::unregisterDirectChannel(int32_t /* channelHandle */) { +Return ISensorsSubHalBase::unregisterDirectChannel(int32_t /* channelHandle */) { return Result::INVALID_OPERATION; } -Return SensorsSubHal::configDirectReport(int32_t /* sensorHandle */, - int32_t /* channelHandle */, RateLevel /* rate */, - configDirectReport_cb _hidl_cb) { +Return ISensorsSubHalBase::configDirectReport( + int32_t /* sensorHandle */, int32_t /* channelHandle */, RateLevel /* rate */, + V2_0::ISensors::configDirectReport_cb _hidl_cb) { _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */); return Return(); } -Return SensorsSubHal::debug(const hidl_handle& fd, const hidl_vec& args) { +Return ISensorsSubHalBase::debug(const hidl_handle& fd, const hidl_vec& args) { if (fd.getNativeHandle() == nullptr || fd->numFds < 1) { ALOGE("%s: missing fd for writing", __FUNCTION__); return Void(); @@ -156,44 +190,18 @@ Return SensorsSubHal::debug(const hidl_handle& fd, const hidl_vec(); } -Return SensorsSubHal::initialize(const sp& halProxyCallback) { - mCallback = halProxyCallback; +Return ISensorsSubHalBase::initialize( + std::unique_ptr& halProxyCallback) { + mCallback = std::move(halProxyCallback); setOperationMode(OperationMode::NORMAL); return Result::OK; } -void SensorsSubHal::postEvents(const std::vector& events, bool wakeup) { +void ISensorsSubHalBase::postEvents(const std::vector& events, bool wakeup) { ScopedWakelock wakelock = mCallback->createScopedWakelock(wakeup); mCallback->postEvents(events, std::move(wakelock)); } -ContinuousSensorsSubHal::ContinuousSensorsSubHal() { - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); -} - -OnChangeSensorsSubHal::OnChangeSensorsSubHal() { - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); -} - -AllSensorsSubHal::AllSensorsSubHal() { - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); -} - Return SetOperationModeFailingSensorsSubHal::setOperationMode(OperationMode /*mode*/) { return Result::BAD_VALUE; } @@ -206,7 +214,7 @@ Return AllSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_REPORT; sensors.push_back(sensorInfo); } - _hidl_cb(sensors); + _hidl_cb(V2_1::implementation::convertToOldSensorInfos(sensors)); return Void(); } @@ -218,7 +226,7 @@ Return DoesNotSupportDirectChannelSensorsSubHal::getSensorsList(getSensors sensorInfo.flags &= ~static_cast(V1_0::SensorFlagBits::MASK_DIRECT_REPORT); sensors.push_back(sensorInfo); } - _hidl_cb(sensors); + _hidl_cb(V2_1::implementation::convertToOldSensorInfos(sensors)); return Void(); } @@ -234,7 +242,7 @@ void AddAndRemoveDynamicSensorsSubHal::removeDynamicSensors( } // namespace implementation } // namespace subhal -} // namespace V2_0 +} // namespace V2_1 } // namespace sensors } // namespace hardware } // namespace android diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h index 6da4404c3e..1a78e847c7 100644 --- a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h +++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h @@ -17,7 +17,9 @@ #pragma once #include "V2_0/SubHal.h" +#include "V2_1/SubHal.h" +#include "IHalProxyCallbackWrapper.h" #include "Sensor.h" #include @@ -25,54 +27,54 @@ namespace android { namespace hardware { namespace sensors { -namespace V2_0 { +namespace V2_1 { namespace subhal { namespace implementation { using ::android::hardware::sensors::V1_0::OperationMode; using ::android::hardware::sensors::V1_0::Result; -using ::android::hardware::sensors::V2_0::implementation::IHalProxyCallback; /** * Implementation of a ISensorsSubHal that can be used to test the implementation of multihal 2.0. * See the README file for more details on how this class can be used for testing. */ -class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { - using Event = ::android::hardware::sensors::V1_0::Event; +class ISensorsSubHalBase : public ISensorsEventCallback { + protected: + using Event = ::android::hardware::sensors::V2_1::Event; using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; public: - SensorsSubHal(); + ISensorsSubHalBase(); + + Return getSensorsList(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb); + Return injectSensorData(const Event& event); + Return initialize(std::unique_ptr& halProxyCallback); // Methods from ::android::hardware::sensors::V2_0::ISensors follow. - virtual Return getSensorsList(getSensorsList_cb _hidl_cb) override; - - virtual Return setOperationMode(OperationMode mode) override; + virtual Return setOperationMode(OperationMode mode); OperationMode getOperationMode() const { return mCurrentOperationMode; } - Return activate(int32_t sensorHandle, bool enabled) override; + Return activate(int32_t sensorHandle, bool enabled); Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) override; + int64_t maxReportLatencyNs); - Return flush(int32_t sensorHandle) override; - - Return injectSensorData(const Event& event) override; + Return flush(int32_t sensorHandle); Return registerDirectChannel(const SharedMemInfo& mem, - registerDirectChannel_cb _hidl_cb) override; + V2_0::ISensors::registerDirectChannel_cb _hidl_cb); - Return unregisterDirectChannel(int32_t channelHandle) override; + Return unregisterDirectChannel(int32_t channelHandle); Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, - configDirectReport_cb _hidl_cb) override; + V2_0::ISensors::configDirectReport_cb _hidl_cb); - Return debug(const hidl_handle& fd, const hidl_vec& args) override; + Return debug(const hidl_handle& fd, const hidl_vec& args); // Methods from ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal follow. - const std::string getName() override { + const std::string getName() { #ifdef SUB_HAL_NAME return SUB_HAL_NAME; #else // SUB_HAL_NAME @@ -80,8 +82,6 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { #endif // SUB_HAL_NAME } - Return initialize(const sp& halProxyCallback) override; - // Method from ISensorsEventCallback. void postEvents(const std::vector& events, bool wakeup) override; @@ -103,7 +103,7 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { * disconnected, sensor events need to be sent to the framework, and when a wakelock should be * acquired. */ - sp mCallback; + std::unique_ptr mCallback; private: /** @@ -118,40 +118,143 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { int32_t mNextHandle; }; -// SubHal that has continuous sensors for testing purposes. -class ContinuousSensorsSubHal : public SensorsSubHal { +template +class SensorsSubHalBase : public ISensorsSubHalBase, public SubHalClass { public: - ContinuousSensorsSubHal(); + Return setOperationMode(OperationMode mode) override { + return ISensorsSubHalBase::setOperationMode(mode); + } + + Return activate(int32_t sensorHandle, bool enabled) override { + return ISensorsSubHalBase::activate(sensorHandle, enabled); + } + + Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) override { + return ISensorsSubHalBase::batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); + } + + Return flush(int32_t sensorHandle) override { + return ISensorsSubHalBase::flush(sensorHandle); + } + + Return registerDirectChannel(const SharedMemInfo& mem, + V2_0::ISensors::registerDirectChannel_cb _hidl_cb) override { + return ISensorsSubHalBase::registerDirectChannel(mem, _hidl_cb); + } + + Return unregisterDirectChannel(int32_t channelHandle) override { + return ISensorsSubHalBase::unregisterDirectChannel(channelHandle); + } + + Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + V2_0::ISensors::configDirectReport_cb _hidl_cb) override { + return ISensorsSubHalBase::configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); + } + + Return debug(const hidl_handle& fd, const hidl_vec& args) override { + return ISensorsSubHalBase::debug(fd, args); + } + + const std::string getName() override { return ISensorsSubHalBase::getName(); } +}; + +class SensorsSubHalV2_0 : public SensorsSubHalBase { + public: + virtual Return getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override { + return ISensorsSubHalBase::getSensorsList([&](const auto& list) { + _hidl_cb(V2_1::implementation::convertToOldSensorInfos(list)); + }); + } + + Return injectSensorData(const V1_0::Event& event) override { + return ISensorsSubHalBase::injectSensorData(V2_1::implementation::convertToNewEvent(event)); + } + + Return initialize( + const sp& halProxyCallback) override { + std::unique_ptr wrapper = + std::make_unique(halProxyCallback); + return ISensorsSubHalBase::initialize(wrapper); + } +}; + +class SensorsSubHalV2_1 : public SensorsSubHalBase { + public: + Return getSensorsList_2_1(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override { + return ISensorsSubHalBase::getSensorsList(_hidl_cb); + } + + Return injectSensorData_2_1(const V2_1::Event& event) override { + return ISensorsSubHalBase::injectSensorData(event); + } + + Return initialize( + const sp& halProxyCallback) override { + std::unique_ptr wrapper = + std::make_unique(halProxyCallback); + return ISensorsSubHalBase::initialize(wrapper); + } +}; + +// SubHal that has continuous sensors for testing purposes. +template +class ContinuousSensorsSubHal : public SubHalVersion { + public: + ContinuousSensorsSubHal() { + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + } }; // SubHal that has on-change sensors for testing purposes. -class OnChangeSensorsSubHal : public SensorsSubHal { +template +class OnChangeSensorsSubHal : public SubHalVersion { public: - OnChangeSensorsSubHal(); + OnChangeSensorsSubHal() { + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + } }; // SubHal that has both continuous and on-change sensors for testing purposes. -class AllSensorsSubHal : public SensorsSubHal { +template +class AllSensorsSubHal : public SubHalVersion { public: - AllSensorsSubHal(); + AllSensorsSubHal() { + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + } }; -class SetOperationModeFailingSensorsSubHal : public AllSensorsSubHal { +class SetOperationModeFailingSensorsSubHal : public AllSensorsSubHal { public: Return setOperationMode(OperationMode mode) override; }; -class AllSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { +class AllSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { public: - Return getSensorsList(getSensorsList_cb _hidl_cb) override; + Return getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override; }; -class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { +class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { public: - Return getSensorsList(getSensorsList_cb _hidl_cb) override; + Return getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override; }; -class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal { +class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal { public: void addDynamicSensors(const std::vector& sensorsAdded); void removeDynamicSensors(const std::vector& sensorHandlesAdded); @@ -159,7 +262,7 @@ class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal { } // namespace implementation } // namespace subhal -} // namespace V2_0 +} // namespace V2_1 } // namespace sensors } // namespace hardware } // namespace android From 3dd52813519561483f2c29496e573d5bc43bcd64 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 28 Apr 2020 17:44:32 -0700 Subject: [PATCH 0886/1022] boot: Relax getSnapshotMergeStatus test. The SNAPSHOTTED state is allowed to be NONE if the slot hasn't changed, to avoid needing extra snapshot cancels in the bootloader. Bug: 154449745 Test: vts Change-Id: Ibcb9f18f535cdcb5aae7e2c9c01e03681dbfff13 Merged-In: Ibcb9f18f535cdcb5aae7e2c9c01e03681dbfff13 --- boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp b/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp index 7c58ef3717..30b965ddbb 100644 --- a/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp +++ b/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp @@ -76,7 +76,11 @@ TEST_P(BootHidlTest, SetSnapshotMergeStatus) { for (const auto value : ValidMergeStatusValues()) { EXPECT_TRUE(boot->setSnapshotMergeStatus(value).withDefault(false)); auto status = boot->getSnapshotMergeStatus(); - EXPECT_EQ(status, value); + if (value == MergeStatus::SNAPSHOTTED) { + EXPECT_TRUE(status == MergeStatus::SNAPSHOTTED || status == MergeStatus::NONE); + } else { + EXPECT_EQ(status, value); + } } } From f4b5b40b4a9d723789aae8b144ee5b1792558eb1 Mon Sep 17 00:00:00 2001 From: Nick Chalko Date: Wed, 29 Apr 2020 22:06:31 +0000 Subject: [PATCH 0887/1022] Revert "Update tests for multihal to test HAL 2.1" Revert submission 10501254-multihal_2_1 Reason for revert: Droidcop: Potential culprit for b/155328660 - verifying through Forrest before revert submission. This is part of the standard investigation process, and does not mean your CL will be reverted. Bug: 155328660 Reverted Changes: I2be51568b:Update tests for multihal to test HAL 2.1 Id5ab7b606:Create Multi-HAL 2.1 service Icefae8c12:Set up Multi-HAL for Sensors HAL 2.1 Change-Id: I8b97eb29633cf24f464d742770256791108c27dd --- .../default/2.X/multihal/tests/Android.bp | 12 - .../2.X/multihal/tests/HalProxy_test.cpp | 327 +++++++----------- .../fake_subhal/IHalProxyCallbackWrapper.h | 107 ------ .../2.X/multihal/tests/fake_subhal/Sensor.cpp | 9 +- .../2.X/multihal/tests/fake_subhal/Sensor.h | 12 +- .../tests/fake_subhal/SensorsSubHal.cpp | 120 +++---- .../tests/fake_subhal/SensorsSubHal.h | 171 ++------- 7 files changed, 230 insertions(+), 528 deletions(-) delete mode 100644 sensors/common/default/2.X/multihal/tests/fake_subhal/IHalProxyCallbackWrapper.h diff --git a/sensors/common/default/2.X/multihal/tests/Android.bp b/sensors/common/default/2.X/multihal/tests/Android.bp index 6586b0b470..cfd9e78a6f 100644 --- a/sensors/common/default/2.X/multihal/tests/Android.bp +++ b/sensors/common/default/2.X/multihal/tests/Android.bp @@ -50,7 +50,6 @@ cc_library { vendor: true, defaults: ["android.hardware.sensors@2.X-fakesubhal-defaults"], cflags: [ - "-DSUB_HAL_VERSION_2_0", "-DSUPPORT_CONTINUOUS_SENSORS", "-DSUB_HAL_NAME=\"FakeSubHal-Continuous\"", ], @@ -60,17 +59,6 @@ cc_library { name: "android.hardware.sensors@2.X-fakesubhal-config2", vendor: true, defaults: ["android.hardware.sensors@2.X-fakesubhal-defaults"], - cflags: [ - "-DSUB_HAL_VERSION_2_0", - "-DSUPPORT_ON_CHANGE_SENSORS", - "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"", - ], -} - -cc_library { - name: "android.hardware.sensors@2.X-fakesubhal-config3", - vendor: true, - defaults: ["android.hardware.sensors@2.X-fakesubhal-defaults"], cflags: [ "-DSUPPORT_ON_CHANGE_SENSORS", "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"", diff --git a/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp index 858786af09..ce65c3cd80 100644 --- a/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp +++ b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp @@ -15,15 +15,12 @@ #include -#include #include -#include #include #include "HalProxy.h" #include "SensorsSubHal.h" #include "V2_0/ScopedWakelock.h" -#include "convertV2_1.h" #include #include @@ -41,35 +38,28 @@ using ::android::hardware::sensors::V1_0::SensorFlagBits; using ::android::hardware::sensors::V1_0::SensorInfo; using ::android::hardware::sensors::V1_0::SensorType; using ::android::hardware::sensors::V2_0::EventQueueFlagBits; +using ::android::hardware::sensors::V2_0::ISensorsCallback; using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; using ::android::hardware::sensors::V2_0::implementation::HalProxyCallbackBase; using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock; -using ::android::hardware::sensors::V2_1::implementation::convertToNewEvents; -using ::android::hardware::sensors::V2_1::implementation::convertToNewSensorInfos; -using ::android::hardware::sensors::V2_1::implementation::HalProxy; -using ::android::hardware::sensors::V2_1::subhal::implementation::AddAndRemoveDynamicSensorsSubHal; -using ::android::hardware::sensors::V2_1::subhal::implementation::AllSensorsSubHal; -using ::android::hardware::sensors::V2_1::subhal::implementation:: +using ::android::hardware::sensors::V2_0::subhal::implementation::AddAndRemoveDynamicSensorsSubHal; +using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal; +using ::android::hardware::sensors::V2_0::subhal::implementation:: AllSupportDirectChannelSensorsSubHal; -using ::android::hardware::sensors::V2_1::subhal::implementation::ContinuousSensorsSubHal; -using ::android::hardware::sensors::V2_1::subhal::implementation:: +using ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal; +using ::android::hardware::sensors::V2_0::subhal::implementation:: DoesNotSupportDirectChannelSensorsSubHal; -using ::android::hardware::sensors::V2_1::subhal::implementation::OnChangeSensorsSubHal; -using ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0; -using ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1; -using ::android::hardware::sensors::V2_1::subhal::implementation:: +using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal; +using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal; +using ::android::hardware::sensors::V2_0::subhal::implementation:: SetOperationModeFailingSensorsSubHal; +using ::android::hardware::sensors::V2_1::implementation::HalProxy; -using ISensorsCallbackV2_0 = ::android::hardware::sensors::V2_0::ISensorsCallback; -using ISensorsCallbackV2_1 = ::android::hardware::sensors::V2_1::ISensorsCallback; -using EventV1_0 = ::android::hardware::sensors::V1_0::Event; -using EventV2_1 = ::android::hardware::sensors::V2_1::Event; -using EventMessageQueueV2_1 = MessageQueue; -using EventMessageQueueV2_0 = MessageQueue; +using EventMessageQueue = MessageQueue; using WakeupMessageQueue = MessageQueue; // The barebones sensors callback class passed into halproxy initialize calls -class SensorsCallback : public ISensorsCallbackV2_0 { +class SensorsCallback : public ISensorsCallback { public: Return onDynamicSensorsConnected( const hidl_vec& /*dynamicSensorsAdded*/) override { @@ -84,30 +74,8 @@ class SensorsCallback : public ISensorsCallbackV2_0 { } }; -class SensorsCallbackV2_1 : public ISensorsCallbackV2_1 { - public: - Return onDynamicSensorsConnected_2_1( - const hidl_vec<::android::hardware::sensors::V2_1::SensorInfo>& /*dynamicSensorsAdded*/) - override { - // Nothing yet - return Return(); - } - - Return onDynamicSensorsConnected( - const hidl_vec& /*dynamicSensorsAdded*/) override { - // Nothing yet - return Return(); - } - - Return onDynamicSensorsDisconnected( - const hidl_vec& /*dynamicSensorHandlesRemoved*/) override { - // Nothing yet - return Return(); - } -}; - // The sensors callback that expects a variable list of sensors to be added -class TestSensorsCallback : public ISensorsCallbackV2_0 { +class TestSensorsCallback : public ISensorsCallback { public: Return onDynamicSensorsConnected( const hidl_vec& dynamicSensorsAdded) override { @@ -162,10 +130,10 @@ void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector& wakelockQueue, EventFlag* wakelockQueueFlag); -bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& eventQueue, +bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& eventQueue, EventFlag* eventQueueFlag); -std::unique_ptr makeEventFMQ(size_t size); +std::unique_ptr makeEventFMQ(size_t size); std::unique_ptr makeWakelockFMQ(size_t size); @@ -175,7 +143,7 @@ std::unique_ptr makeWakelockFMQ(size_t size); * * @return A proximity event. */ -EventV1_0 makeProximityEvent(); +Event makeProximityEvent(); /** * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor @@ -183,7 +151,7 @@ EventV1_0 makeProximityEvent(); * * @return A proximity event. */ -EventV1_0 makeAccelerometerEvent(); +Event makeAccelerometerEvent(); /** * Make a certain number of proximity type events with the sensorHandle field set to @@ -193,7 +161,7 @@ EventV1_0 makeAccelerometerEvent(); * * @return The created list of events. */ -std::vector makeMultipleProximityEvents(size_t numEvents); +std::vector makeMultipleProximityEvents(size_t numEvents); /** * Make a certain number of accelerometer type events with the sensorHandle field set to @@ -203,7 +171,7 @@ std::vector makeMultipleProximityEvents(size_t numEvents); * * @return The created list of events. */ -std::vector makeMultipleAccelerometerEvents(size_t numEvents); +std::vector makeMultipleAccelerometerEvents(size_t numEvents); /** * Given a SensorInfo vector and a sensor handles vector populate 'sensors' with SensorInfo @@ -221,7 +189,7 @@ void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size, // Tests follow TEST(HalProxyTest, GetSensorsListOneSubHalTest) { - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector fakeSubHals{&subHal}; HalProxy proxy(fakeSubHals); @@ -233,8 +201,8 @@ TEST(HalProxyTest, GetSensorsListOneSubHalTest) { } TEST(HalProxyTest, GetSensorsListTwoSubHalTest) { - ContinuousSensorsSubHal continuousSubHal; - OnChangeSensorsSubHal onChangeSubHal; + ContinuousSensorsSubHal continuousSubHal; + OnChangeSensorsSubHal onChangeSubHal; std::vector fakeSubHals; fakeSubHals.push_back(&continuousSubHal); fakeSubHals.push_back(&onChangeSubHal); @@ -254,8 +222,8 @@ TEST(HalProxyTest, GetSensorsListTwoSubHalTest) { } TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) { - ContinuousSensorsSubHal subHal1; - OnChangeSensorsSubHal subHal2; + ContinuousSensorsSubHal subHal1; + OnChangeSensorsSubHal subHal2; std::vector fakeSubHals{&subHal1, &subHal2}; HalProxy proxy(fakeSubHals); @@ -271,7 +239,7 @@ TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) { } TEST(HalProxyTest, SetOperationModeTwoSubHalFailTest) { - AllSensorsSubHal subHal1; + AllSensorsSubHal subHal1; SetOperationModeFailingSensorsSubHal subHal2; std::vector fakeSubHals{&subHal1, &subHal2}; @@ -312,16 +280,16 @@ TEST(HalProxyTest, InitDirectChannelThreeSubHalsUnitTest) { TEST(HalProxyTest, PostSingleNonWakeupEvent) { constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events{makeAccelerometerEvent()}; - subHal.postEvents(convertToNewEvents(events), false /* wakeup */); + std::vector events{makeAccelerometerEvent()}; + subHal.postEvents(events, false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), 1); } @@ -329,28 +297,28 @@ TEST(HalProxyTest, PostSingleNonWakeupEvent) { TEST(HalProxyTest, PostMultipleNonWakeupEvent) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 3; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal.postEvents(convertToNewEvents(events), false /* wakeup */); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal.postEvents(events, false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); } TEST(HalProxyTest, PostSingleWakeupEvent) { constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); EventFlag* eventQueueFlag; @@ -359,8 +327,8 @@ TEST(HalProxyTest, PostSingleWakeupEvent) { EventFlag* wakelockQueueFlag; EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag); - std::vector events{makeProximityEvent()}; - subHal.postEvents(convertToNewEvents(events), true /* wakeup */); + std::vector events{makeProximityEvent()}; + subHal.postEvents(events, true /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), 1); @@ -371,12 +339,12 @@ TEST(HalProxyTest, PostSingleWakeupEvent) { TEST(HalProxyTest, PostMultipleWakeupEvents) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 3; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); EventFlag* eventQueueFlag; @@ -385,8 +353,8 @@ TEST(HalProxyTest, PostMultipleWakeupEvents) { EventFlag* wakelockQueueFlag; EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag); - std::vector events = makeMultipleProximityEvents(kNumEvents); - subHal.postEvents(convertToNewEvents(events), true /* wakeup */); + std::vector events = makeMultipleProximityEvents(kNumEvents); + subHal.postEvents(events, true /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); @@ -397,20 +365,20 @@ TEST(HalProxyTest, PostMultipleWakeupEvents) { TEST(HalProxyTest, PostEventsMultipleSubhals) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 2; - AllSensorsSubHal subHal1, subHal2; + AllSensorsSubHal subHal1, subHal2; std::vector subHals{&subHal1, &subHal2}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal1.postEvents(convertToNewEvents(events), false /* wakeup */); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal1.postEvents(events, false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); - subHal2.postEvents(convertToNewEvents(events), false /* wakeup */); + subHal2.postEvents(events, false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2); } @@ -418,19 +386,19 @@ TEST(HalProxyTest, PostEventsMultipleSubhals) { TEST(HalProxyTest, PostEventsDelayedWrite) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 6; - AllSensorsSubHal subHal1, subHal2; + AllSensorsSubHal subHal1, subHal2; std::vector subHals{&subHal1, &subHal2}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); EventFlag* eventQueueFlag; EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal1.postEvents(convertToNewEvents(events), false /* wakeup */); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal1.postEvents(events, false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kQueueSize); @@ -446,20 +414,18 @@ TEST(HalProxyTest, PostEventsDelayedWrite) { TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 2; - AllSensorsSubHal subHal1, subHal2; + AllSensorsSubHal subHal1, subHal2; std::vector subHals{&subHal1, &subHal2}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, - convertToNewEvents(events), false); - std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, - convertToNewEvents(events), false); + std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, events, false); + std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, events, false); t1.join(); t2.join(); @@ -470,34 +436,34 @@ TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) { TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThread) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 6; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal.postEvents(convertToNewEvents(events), false /* wakeup */); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal.postEvents(events, false /* wakeup */); // Destructing HalProxy object with events on the background thread } TEST(HalProxyTest, DestructingWithUnackedWakeupEventsPosted) { constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events{makeProximityEvent()}; - subHal.postEvents(convertToNewEvents(events), true /* wakeup */); + std::vector events{makeProximityEvent()}; + subHal.postEvents(events, true /* wakeup */); // Not sending any acks back through wakeLockQueue @@ -507,17 +473,17 @@ TEST(HalProxyTest, DestructingWithUnackedWakeupEventsPosted) { TEST(HalProxyTest, ReinitializeWithEventsPendingOnBackgroundThread) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 10; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal.postEvents(convertToNewEvents(events), false /* wakeup */); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal.postEvents(events, false /* wakeup */); eventQueue = makeEventFMQ(kQueueSize); wakeLockQueue = makeWakelockFMQ(kQueueSize); @@ -527,23 +493,23 @@ TEST(HalProxyTest, ReinitializeWithEventsPendingOnBackgroundThread) { EXPECT_EQ(secondInitResult, Result::OK); // Small sleep so that pending writes thread has a change to hit writeBlocking call. std::this_thread::sleep_for(std::chrono::milliseconds(5)); - EventV1_0 eventOut; + Event eventOut; EXPECT_FALSE(eventQueue->read(&eventOut)); } TEST(HalProxyTest, ReinitializingWithUnackedWakeupEventsPosted) { constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events{makeProximityEvent()}; - subHal.postEvents(convertToNewEvents(events), true /* wakeup */); + std::vector events{makeProximityEvent()}; + subHal.postEvents(events, true /* wakeup */); // Not sending any acks back through wakeLockQueue @@ -558,12 +524,12 @@ TEST(HalProxyTest, ReinitializingWithUnackedWakeupEventsPosted) { TEST(HalProxyTest, InitializeManyTimesInARow) { constexpr size_t kQueueSize = 5; constexpr size_t kNumTimesToInit = 100; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); for (size_t i = 0; i < kNumTimesToInit; i++) { @@ -575,15 +541,15 @@ TEST(HalProxyTest, InitializeManyTimesInARow) { TEST(HalProxyTest, OperationModeResetOnInitialize) { constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.setOperationMode(OperationMode::DATA_INJECTION); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - EventV1_0 event = makeAccelerometerEvent(); + Event event = makeAccelerometerEvent(); // Should not be able to inject a non AdditionInfo type event because operation mode should // have been reset to NORMAL EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE); @@ -594,7 +560,7 @@ TEST(HalProxyTest, DynamicSensorsDiscardedOnInitialize) { constexpr size_t kNumSensors = 5; AddAndRemoveDynamicSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); HalProxy proxy(subHals); @@ -609,9 +575,9 @@ TEST(HalProxyTest, DynamicSensorsDiscardedOnInitialize) { } TestSensorsCallback* callback = new TestSensorsCallback(); - ::android::sp callbackPtr = callback; + ::android::sp callbackPtr = callback; proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); - subHal.addDynamicSensors(convertToNewSensorInfos(sensorsToConnect)); + subHal.addDynamicSensors(sensorsToConnect); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove); @@ -628,7 +594,7 @@ TEST(HalProxyTest, DynamicSensorsConnectedTest) { AddAndRemoveDynamicSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(0); + std::unique_ptr eventQueue = makeEventFMQ(0); std::unique_ptr wakeLockQueue = makeWakelockFMQ(0); std::vector sensorsToConnect; @@ -637,9 +603,9 @@ TEST(HalProxyTest, DynamicSensorsConnectedTest) { sensorHandlesToExpect); TestSensorsCallback* callback = new TestSensorsCallback(); - ::android::sp callbackPtr = callback; + ::android::sp callbackPtr = callback; proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); - subHal.addDynamicSensors(convertToNewSensorInfos(sensorsToConnect)); + subHal.addDynamicSensors(sensorsToConnect); std::vector sensorsSeen = callback->getSensorsConnected(); EXPECT_EQ(kNumSensors, sensorsSeen.size()); @@ -656,7 +622,7 @@ TEST(HalProxyTest, DynamicSensorsDisconnectedTest) { AddAndRemoveDynamicSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(0); + std::unique_ptr eventQueue = makeEventFMQ(0); std::unique_ptr wakeLockQueue = makeWakelockFMQ(0); std::vector sensorsToConnect; @@ -681,9 +647,9 @@ TEST(HalProxyTest, DynamicSensorsDisconnectedTest) { nonDynamicSensorHandles.end()); TestSensorsCallback* callback = new TestSensorsCallback(); - ::android::sp callbackPtr = callback; + ::android::sp callbackPtr = callback; proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); - subHal.addDynamicSensors(convertToNewSensorInfos(sensorsToConnect)); + subHal.addDynamicSensors(sensorsToConnect); subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove); std::vector sensorHandlesSeen = callback->getSensorHandlesDisconnected(); @@ -702,15 +668,15 @@ TEST(HalProxyTest, InvalidSensorHandleSubHalIndexProxyCalls) { constexpr size_t kNumSubHals = 3; constexpr size_t kQueueSize = 5; int32_t kNumSubHalsInt32 = static_cast(kNumSubHals); - std::vector> subHalObjs(kNumSubHals); + std::vector subHalObjs(kNumSubHals); std::vector subHals; for (const auto& subHal : subHalObjs) { subHals.push_back((ISensorsSubHal*)(&subHal)); } - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); // Initialize for the injectSensorData call so callback postEvents is valid proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); @@ -722,7 +688,7 @@ TEST(HalProxyTest, InvalidSensorHandleSubHalIndexProxyCalls) { EXPECT_EQ(proxy.activate(0x00000001 | (kNumSubHalsInt32 << 24), true), Result::BAD_VALUE); EXPECT_EQ(proxy.batch(0x00000001 | (kNumSubHalsInt32 << 24), 0, 0), Result::BAD_VALUE); EXPECT_EQ(proxy.flush(0x00000001 | (kNumSubHalsInt32 << 24)), Result::BAD_VALUE); - EventV1_0 event; + Event event; event.sensorHandle = 0x00000001 | (kNumSubHalsInt32 << 24); EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE); } @@ -731,28 +697,28 @@ TEST(HalProxyTest, PostedEventSensorHandleSubHalIndexValid) { constexpr size_t kQueueSize = 5; constexpr int32_t subhal1Index = 0; constexpr int32_t subhal2Index = 1; - AllSensorsSubHal subhal1; - AllSensorsSubHal subhal2; + AllSensorsSubHal subhal1; + AllSensorsSubHal subhal2; std::vector subHals{&subhal1, &subhal2}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); int32_t sensorHandleToPost = 0x00000001; - EventV1_0 eventIn = makeAccelerometerEvent(); + Event eventIn = makeAccelerometerEvent(); eventIn.sensorHandle = sensorHandleToPost; - std::vector eventsToPost{eventIn}; - subhal1.postEvents(convertToNewEvents(eventsToPost), false); + std::vector eventsToPost{eventIn}; + subhal1.postEvents(eventsToPost, false); - EventV1_0 eventOut; + Event eventOut; EXPECT_TRUE(eventQueue->read(&eventOut)); EXPECT_EQ(eventOut.sensorHandle, (subhal1Index << 24) | sensorHandleToPost); - subhal2.postEvents(convertToNewEvents(eventsToPost), false); + subhal2.postEvents(eventsToPost, false); EXPECT_TRUE(eventQueue->read(&eventOut)); @@ -763,22 +729,22 @@ TEST(HalProxyTest, FillAndDrainPendingQueueTest) { constexpr size_t kQueueSize = 5; // TODO: Make this constant linked to same limit in HalProxy.h constexpr size_t kMaxPendingQueueSize = 100000; - AllSensorsSubHal subhal; + AllSensorsSubHal subhal; std::vector subHals{&subhal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); EventFlag* eventQueueFlag; EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); // Fill pending queue - std::vector events = makeMultipleAccelerometerEvents(kQueueSize); - subhal.postEvents(convertToNewEvents(events), false); + std::vector events = makeMultipleAccelerometerEvents(kQueueSize); + subhal.postEvents(events, false); events = makeMultipleAccelerometerEvents(kMaxPendingQueueSize); - subhal.postEvents(convertToNewEvents(events), false); + subhal.postEvents(events, false); // Drain pending queue for (int i = 0; i < kMaxPendingQueueSize + kQueueSize; i += kQueueSize) { @@ -787,9 +753,9 @@ TEST(HalProxyTest, FillAndDrainPendingQueueTest) { // Put one event on pending queue events = makeMultipleAccelerometerEvents(kQueueSize); - subhal.postEvents(convertToNewEvents(events), false); + subhal.postEvents(events, false); events = {makeAccelerometerEvent()}; - subhal.postEvents(convertToNewEvents(events), false); + subhal.postEvents(events, false); // Read out to make room for one event on pending queue to write to FMQ ASSERT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag)); @@ -798,35 +764,6 @@ TEST(HalProxyTest, FillAndDrainPendingQueueTest) { EXPECT_TRUE(readEventsOutOfQueue(1, eventQueue, eventQueueFlag)); } -TEST(HalProxyTest, PostEventsMultipleSubhalsThreadedV2_1) { - constexpr size_t kQueueSize = 5; - constexpr size_t kNumEvents = 2; - AllSensorsSubHal subHal1; - AllSensorsSubHal subHal2; - std::vector<::android::hardware::sensors::V2_0::implementation::ISensorsSubHal*> subHalsV2_0{ - &subHal1}; - std::vector<::android::hardware::sensors::V2_1::implementation::ISensorsSubHal*> subHalsV2_1{ - &subHal2}; - HalProxy proxy(subHalsV2_0, subHalsV2_1); - std::unique_ptr eventQueue = - std::make_unique(kQueueSize, true); - std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallbackV2_1(); - proxy.initialize_2_1(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - - std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, - convertToNewEvents(events), false); - std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, - convertToNewEvents(events), false); - - t1.join(); - t2.join(); - - EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2); -} - // Helper implementations follow void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, const std::vector& subHalSensorsList) { @@ -865,26 +802,26 @@ void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptrwake(static_cast(WakeLockQueueFlagBits::DATA_WRITTEN)); } -bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& eventQueue, +bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& eventQueue, EventFlag* eventQueueFlag) { constexpr int64_t kReadBlockingTimeout = INT64_C(500000000); - std::vector events(numEvents); + std::vector events(numEvents); return eventQueue->readBlocking(events.data(), numEvents, static_cast(EventQueueFlagBits::EVENTS_READ), static_cast(EventQueueFlagBits::READ_AND_PROCESS), kReadBlockingTimeout, eventQueueFlag); } -std::unique_ptr makeEventFMQ(size_t size) { - return std::make_unique(size, true); +std::unique_ptr makeEventFMQ(size_t size) { + return std::make_unique(size, true); } std::unique_ptr makeWakelockFMQ(size_t size) { return std::make_unique(size, true); } -EventV1_0 makeProximityEvent() { - EventV1_0 event; +Event makeProximityEvent() { + Event event; event.timestamp = 0xFF00FF00; // This is the sensorhandle of proximity, which is wakeup type event.sensorHandle = 0x00000008; @@ -893,8 +830,8 @@ EventV1_0 makeProximityEvent() { return event; } -EventV1_0 makeAccelerometerEvent() { - EventV1_0 event; +Event makeAccelerometerEvent() { + Event event; event.timestamp = 0xFF00FF00; // This is the sensorhandle of proximity, which is wakeup type event.sensorHandle = 0x00000001; @@ -903,16 +840,16 @@ EventV1_0 makeAccelerometerEvent() { return event; } -std::vector makeMultipleProximityEvents(size_t numEvents) { - std::vector events; +std::vector makeMultipleProximityEvents(size_t numEvents) { + std::vector events; for (size_t i = 0; i < numEvents; i++) { events.push_back(makeProximityEvent()); } return events; } -std::vector makeMultipleAccelerometerEvents(size_t numEvents) { - std::vector events; +std::vector makeMultipleAccelerometerEvents(size_t numEvents) { + std::vector events; for (size_t i = 0; i < numEvents; i++) { events.push_back(makeAccelerometerEvent()); } diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/IHalProxyCallbackWrapper.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/IHalProxyCallbackWrapper.h deleted file mode 100644 index 4542bfdc2c..0000000000 --- a/sensors/common/default/2.X/multihal/tests/fake_subhal/IHalProxyCallbackWrapper.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include "V2_0/SubHal.h" -#include "V2_1/SubHal.h" -#include "convertV2_1.h" - -namespace android { -namespace hardware { -namespace sensors { -namespace V2_1 { -namespace subhal { -namespace implementation { - -/** - * The following callback wrapper classes abstract away common functionality across V2.0 and V2.1 - * interfaces. Much of the logic is common between the two versions and this allows users of the - * classes to only care about the type used at initialization and then interact with either version - * of the callback interface without worrying about the type. - */ -class IHalProxyCallbackWrapperBase { - protected: - using ScopedWakelock = V2_0::implementation::ScopedWakelock; - - public: - virtual ~IHalProxyCallbackWrapperBase() {} - - virtual Return onDynamicSensorsConnected( - const hidl_vec& sensorInfos) = 0; - - virtual Return onDynamicSensorsDisconnected(const hidl_vec& sensorHandles) = 0; - - virtual void postEvents(const std::vector& events, ScopedWakelock wakelock) = 0; - - virtual ScopedWakelock createScopedWakelock(bool lock) = 0; -}; - -template -class HalProxyCallbackWrapperBase : public IHalProxyCallbackWrapperBase { - public: - HalProxyCallbackWrapperBase(sp callback) : mCallback(callback){}; - - Return onDynamicSensorsDisconnected(const hidl_vec& sensorHandles) override { - return mCallback->onDynamicSensorsDisconnected(sensorHandles); - } - - ScopedWakelock createScopedWakelock(bool lock) override { - return mCallback->createScopedWakelock(lock); - } - - protected: - sp mCallback; -}; - -class HalProxyCallbackWrapperV2_0 - : public HalProxyCallbackWrapperBase { - public: - HalProxyCallbackWrapperV2_0(sp callback) - : HalProxyCallbackWrapperBase(callback){}; - - Return onDynamicSensorsConnected(const hidl_vec& sensorInfos) override { - return mCallback->onDynamicSensorsConnected( - V2_1::implementation::convertToOldSensorInfos(sensorInfos)); - } - - void postEvents(const std::vector& events, ScopedWakelock wakelock) override { - return mCallback->postEvents(V2_1::implementation::convertToOldEvents(events), - std::move(wakelock)); - } -}; - -class HalProxyCallbackWrapperV2_1 - : public HalProxyCallbackWrapperBase { - public: - HalProxyCallbackWrapperV2_1(sp callback) - : HalProxyCallbackWrapperBase(callback){}; - - Return onDynamicSensorsConnected(const hidl_vec& sensorInfos) override { - return mCallback->onDynamicSensorsConnected_2_1(sensorInfos); - } - - void postEvents(const std::vector& events, ScopedWakelock wakelock) { - return mCallback->postEvents(events, std::move(wakelock)); - } -}; - -} // namespace implementation -} // namespace subhal -} // namespace V2_1 -} // namespace sensors -} // namespace hardware -} // namespace android diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp index 1efd971115..de89a00ef9 100644 --- a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp +++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp @@ -24,18 +24,13 @@ namespace android { namespace hardware { namespace sensors { -namespace V2_1 { +namespace V2_0 { namespace subhal { namespace implementation { using ::android::hardware::sensors::V1_0::MetaDataEventType; -using ::android::hardware::sensors::V1_0::OperationMode; -using ::android::hardware::sensors::V1_0::Result; using ::android::hardware::sensors::V1_0::SensorFlagBits; using ::android::hardware::sensors::V1_0::SensorStatus; -using ::android::hardware::sensors::V2_1::Event; -using ::android::hardware::sensors::V2_1::SensorInfo; -using ::android::hardware::sensors::V2_1::SensorType; Sensor::Sensor(int32_t sensorHandle, ISensorsEventCallback* callback) : mIsEnabled(false), @@ -348,7 +343,7 @@ RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle, } // namespace implementation } // namespace subhal -} // namespace V2_1 +} // namespace V2_0 } // namespace sensors } // namespace hardware } // namespace android diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h index 5cf9f837cf..60f5d3d40a 100644 --- a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h +++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h @@ -16,7 +16,7 @@ #pragma once -#include +#include #include #include @@ -24,16 +24,16 @@ #include #include +using ::android::hardware::sensors::V1_0::Event; using ::android::hardware::sensors::V1_0::OperationMode; using ::android::hardware::sensors::V1_0::Result; -using ::android::hardware::sensors::V2_1::Event; -using ::android::hardware::sensors::V2_1::SensorInfo; -using ::android::hardware::sensors::V2_1::SensorType; +using ::android::hardware::sensors::V1_0::SensorInfo; +using ::android::hardware::sensors::V1_0::SensorType; namespace android { namespace hardware { namespace sensors { -namespace V2_1 { +namespace V2_0 { namespace subhal { namespace implementation { @@ -151,7 +151,7 @@ class RelativeHumiditySensor : public OnChangeSensor { } // namespace implementation } // namespace subhal -} // namespace V2_1 +} // namespace V2_0 } // namespace sensors } // namespace hardware } // namespace android diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp index 20a4e9de04..ff5ff38541 100644 --- a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp +++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp @@ -16,66 +16,33 @@ #include "SensorsSubHal.h" -#include +#include #include -#ifdef SUB_HAL_VERSION_2_0 -::android::hardware::sensors::V2_0::implementation::ISensorsSubHal* sensorsHalGetSubHal( - uint32_t* version) { +ISensorsSubHal* sensorsHalGetSubHal(uint32_t* version) { #if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS - static ::android::hardware::sensors::V2_1::subhal::implementation::AllSensorsSubHal< - ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0> - subHal; + static ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal subHal; #elif defined SUPPORT_CONTINUOUS_SENSORS - static ::android::hardware::sensors::V2_1::subhal::implementation::ContinuousSensorsSubHal< - ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0> + static ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal subHal; #elif defined SUPPORT_ON_CHANGE_SENSORS - static ::android::hardware::sensors::V2_1::subhal::implementation::OnChangeSensorsSubHal< - ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0> - subHal; + static ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal subHal; #else - static ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHal< - ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0> - subHal; + static ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal subHal; #endif // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS *version = SUB_HAL_2_0_VERSION; return &subHal; } -#else // SUB_HAL_VERSION_2_0 - -::android::hardware::sensors::V2_1::implementation::ISensorsSubHal* sensorsHalGetSubHal_2_1( - uint32_t* version) { -#if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS - static ::android::hardware::sensors::V2_1::subhal::implementation::AllSensorsSubHal< - ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1> - subHal; -#elif defined SUPPORT_CONTINUOUS_SENSORS - static ::android::hardware::sensors::V2_1::subhal::implementation::ContinuousSensorsSubHal< - ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1> - subHal; -#elif defined SUPPORT_ON_CHANGE_SENSORS - static ::android::hardware::sensors::V2_1::subhal::implementation::OnChangeSensorsSubHal< - ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1> - subHal; -#else - static ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1 subHal; -#endif // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS - *version = SUB_HAL_2_1_VERSION; - return &subHal; -} - -#endif // SUB_HAL_VERSION_2_0 - namespace android { namespace hardware { namespace sensors { -namespace V2_1 { +namespace V2_0 { namespace subhal { namespace implementation { using ::android::hardware::Void; +using ::android::hardware::sensors::V1_0::Event; using ::android::hardware::sensors::V1_0::OperationMode; using ::android::hardware::sensors::V1_0::RateLevel; using ::android::hardware::sensors::V1_0::Result; @@ -83,12 +50,11 @@ using ::android::hardware::sensors::V1_0::SharedMemInfo; using ::android::hardware::sensors::V2_0::SensorTimeout; using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock; -using ::android::hardware::sensors::V2_1::Event; -ISensorsSubHalBase::ISensorsSubHalBase() : mCallback(nullptr), mNextHandle(1) {} +SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {} // Methods from ::android::hardware::sensors::V2_0::ISensors follow. -Return ISensorsSubHalBase::getSensorsList(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) { +Return SensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) { std::vector sensors; for (const auto& sensor : mSensors) { sensors.push_back(sensor.second->getSensorInfo()); @@ -98,7 +64,7 @@ Return ISensorsSubHalBase::getSensorsList(V2_1::ISensors::getSensorsList_2 return Void(); } -Return ISensorsSubHalBase::setOperationMode(OperationMode mode) { +Return SensorsSubHal::setOperationMode(OperationMode mode) { for (auto sensor : mSensors) { sensor.second->setOperationMode(mode); } @@ -106,7 +72,7 @@ Return ISensorsSubHalBase::setOperationMode(OperationMode mode) { return Result::OK; } -Return ISensorsSubHalBase::activate(int32_t sensorHandle, bool enabled) { +Return SensorsSubHal::activate(int32_t sensorHandle, bool enabled) { auto sensor = mSensors.find(sensorHandle); if (sensor != mSensors.end()) { sensor->second->activate(enabled); @@ -115,8 +81,8 @@ Return ISensorsSubHalBase::activate(int32_t sensorHandle, bool enabled) return Result::BAD_VALUE; } -Return ISensorsSubHalBase::batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t /* maxReportLatencyNs */) { +Return SensorsSubHal::batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t /* maxReportLatencyNs */) { auto sensor = mSensors.find(sensorHandle); if (sensor != mSensors.end()) { sensor->second->batch(samplingPeriodNs); @@ -125,7 +91,7 @@ Return ISensorsSubHalBase::batch(int32_t sensorHandle, int64_t samplingP return Result::BAD_VALUE; } -Return ISensorsSubHalBase::flush(int32_t sensorHandle) { +Return SensorsSubHal::flush(int32_t sensorHandle) { auto sensor = mSensors.find(sensorHandle); if (sensor != mSensors.end()) { return sensor->second->flush(); @@ -133,7 +99,7 @@ Return ISensorsSubHalBase::flush(int32_t sensorHandle) { return Result::BAD_VALUE; } -Return ISensorsSubHalBase::injectSensorData(const Event& event) { +Return SensorsSubHal::injectSensorData(const Event& event) { auto sensor = mSensors.find(event.sensorHandle); if (sensor != mSensors.end()) { return sensor->second->injectEvent(event); @@ -142,24 +108,24 @@ Return ISensorsSubHalBase::injectSensorData(const Event& event) { return Result::BAD_VALUE; } -Return ISensorsSubHalBase::registerDirectChannel( - const SharedMemInfo& /* mem */, V2_0::ISensors::registerDirectChannel_cb _hidl_cb) { +Return SensorsSubHal::registerDirectChannel(const SharedMemInfo& /* mem */, + registerDirectChannel_cb _hidl_cb) { _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */); return Return(); } -Return ISensorsSubHalBase::unregisterDirectChannel(int32_t /* channelHandle */) { +Return SensorsSubHal::unregisterDirectChannel(int32_t /* channelHandle */) { return Result::INVALID_OPERATION; } -Return ISensorsSubHalBase::configDirectReport( - int32_t /* sensorHandle */, int32_t /* channelHandle */, RateLevel /* rate */, - V2_0::ISensors::configDirectReport_cb _hidl_cb) { +Return SensorsSubHal::configDirectReport(int32_t /* sensorHandle */, + int32_t /* channelHandle */, RateLevel /* rate */, + configDirectReport_cb _hidl_cb) { _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */); return Return(); } -Return ISensorsSubHalBase::debug(const hidl_handle& fd, const hidl_vec& args) { +Return SensorsSubHal::debug(const hidl_handle& fd, const hidl_vec& args) { if (fd.getNativeHandle() == nullptr || fd->numFds < 1) { ALOGE("%s: missing fd for writing", __FUNCTION__); return Void(); @@ -190,18 +156,44 @@ Return ISensorsSubHalBase::debug(const hidl_handle& fd, const hidl_vec(); } -Return ISensorsSubHalBase::initialize( - std::unique_ptr& halProxyCallback) { - mCallback = std::move(halProxyCallback); +Return SensorsSubHal::initialize(const sp& halProxyCallback) { + mCallback = halProxyCallback; setOperationMode(OperationMode::NORMAL); return Result::OK; } -void ISensorsSubHalBase::postEvents(const std::vector& events, bool wakeup) { +void SensorsSubHal::postEvents(const std::vector& events, bool wakeup) { ScopedWakelock wakelock = mCallback->createScopedWakelock(wakeup); mCallback->postEvents(events, std::move(wakelock)); } +ContinuousSensorsSubHal::ContinuousSensorsSubHal() { + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); +} + +OnChangeSensorsSubHal::OnChangeSensorsSubHal() { + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); +} + +AllSensorsSubHal::AllSensorsSubHal() { + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); + AddSensor(); +} + Return SetOperationModeFailingSensorsSubHal::setOperationMode(OperationMode /*mode*/) { return Result::BAD_VALUE; } @@ -214,7 +206,7 @@ Return AllSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_REPORT; sensors.push_back(sensorInfo); } - _hidl_cb(V2_1::implementation::convertToOldSensorInfos(sensors)); + _hidl_cb(sensors); return Void(); } @@ -226,7 +218,7 @@ Return DoesNotSupportDirectChannelSensorsSubHal::getSensorsList(getSensors sensorInfo.flags &= ~static_cast(V1_0::SensorFlagBits::MASK_DIRECT_REPORT); sensors.push_back(sensorInfo); } - _hidl_cb(V2_1::implementation::convertToOldSensorInfos(sensors)); + _hidl_cb(sensors); return Void(); } @@ -242,7 +234,7 @@ void AddAndRemoveDynamicSensorsSubHal::removeDynamicSensors( } // namespace implementation } // namespace subhal -} // namespace V2_1 +} // namespace V2_0 } // namespace sensors } // namespace hardware } // namespace android diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h index 1a78e847c7..6da4404c3e 100644 --- a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h +++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h @@ -17,9 +17,7 @@ #pragma once #include "V2_0/SubHal.h" -#include "V2_1/SubHal.h" -#include "IHalProxyCallbackWrapper.h" #include "Sensor.h" #include @@ -27,54 +25,54 @@ namespace android { namespace hardware { namespace sensors { -namespace V2_1 { +namespace V2_0 { namespace subhal { namespace implementation { using ::android::hardware::sensors::V1_0::OperationMode; using ::android::hardware::sensors::V1_0::Result; +using ::android::hardware::sensors::V2_0::implementation::IHalProxyCallback; /** * Implementation of a ISensorsSubHal that can be used to test the implementation of multihal 2.0. * See the README file for more details on how this class can be used for testing. */ -class ISensorsSubHalBase : public ISensorsEventCallback { - protected: - using Event = ::android::hardware::sensors::V2_1::Event; +class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { + using Event = ::android::hardware::sensors::V1_0::Event; using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; public: - ISensorsSubHalBase(); - - Return getSensorsList(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb); - Return injectSensorData(const Event& event); - Return initialize(std::unique_ptr& halProxyCallback); + SensorsSubHal(); // Methods from ::android::hardware::sensors::V2_0::ISensors follow. - virtual Return setOperationMode(OperationMode mode); + virtual Return getSensorsList(getSensorsList_cb _hidl_cb) override; + + virtual Return setOperationMode(OperationMode mode) override; OperationMode getOperationMode() const { return mCurrentOperationMode; } - Return activate(int32_t sensorHandle, bool enabled); + Return activate(int32_t sensorHandle, bool enabled) override; Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs); + int64_t maxReportLatencyNs) override; - Return flush(int32_t sensorHandle); + Return flush(int32_t sensorHandle) override; + + Return injectSensorData(const Event& event) override; Return registerDirectChannel(const SharedMemInfo& mem, - V2_0::ISensors::registerDirectChannel_cb _hidl_cb); + registerDirectChannel_cb _hidl_cb) override; - Return unregisterDirectChannel(int32_t channelHandle); + Return unregisterDirectChannel(int32_t channelHandle) override; Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, - V2_0::ISensors::configDirectReport_cb _hidl_cb); + configDirectReport_cb _hidl_cb) override; - Return debug(const hidl_handle& fd, const hidl_vec& args); + Return debug(const hidl_handle& fd, const hidl_vec& args) override; // Methods from ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal follow. - const std::string getName() { + const std::string getName() override { #ifdef SUB_HAL_NAME return SUB_HAL_NAME; #else // SUB_HAL_NAME @@ -82,6 +80,8 @@ class ISensorsSubHalBase : public ISensorsEventCallback { #endif // SUB_HAL_NAME } + Return initialize(const sp& halProxyCallback) override; + // Method from ISensorsEventCallback. void postEvents(const std::vector& events, bool wakeup) override; @@ -103,7 +103,7 @@ class ISensorsSubHalBase : public ISensorsEventCallback { * disconnected, sensor events need to be sent to the framework, and when a wakelock should be * acquired. */ - std::unique_ptr mCallback; + sp mCallback; private: /** @@ -118,143 +118,40 @@ class ISensorsSubHalBase : public ISensorsEventCallback { int32_t mNextHandle; }; -template -class SensorsSubHalBase : public ISensorsSubHalBase, public SubHalClass { - public: - Return setOperationMode(OperationMode mode) override { - return ISensorsSubHalBase::setOperationMode(mode); - } - - Return activate(int32_t sensorHandle, bool enabled) override { - return ISensorsSubHalBase::activate(sensorHandle, enabled); - } - - Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) override { - return ISensorsSubHalBase::batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); - } - - Return flush(int32_t sensorHandle) override { - return ISensorsSubHalBase::flush(sensorHandle); - } - - Return registerDirectChannel(const SharedMemInfo& mem, - V2_0::ISensors::registerDirectChannel_cb _hidl_cb) override { - return ISensorsSubHalBase::registerDirectChannel(mem, _hidl_cb); - } - - Return unregisterDirectChannel(int32_t channelHandle) override { - return ISensorsSubHalBase::unregisterDirectChannel(channelHandle); - } - - Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, - V2_0::ISensors::configDirectReport_cb _hidl_cb) override { - return ISensorsSubHalBase::configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); - } - - Return debug(const hidl_handle& fd, const hidl_vec& args) override { - return ISensorsSubHalBase::debug(fd, args); - } - - const std::string getName() override { return ISensorsSubHalBase::getName(); } -}; - -class SensorsSubHalV2_0 : public SensorsSubHalBase { - public: - virtual Return getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override { - return ISensorsSubHalBase::getSensorsList([&](const auto& list) { - _hidl_cb(V2_1::implementation::convertToOldSensorInfos(list)); - }); - } - - Return injectSensorData(const V1_0::Event& event) override { - return ISensorsSubHalBase::injectSensorData(V2_1::implementation::convertToNewEvent(event)); - } - - Return initialize( - const sp& halProxyCallback) override { - std::unique_ptr wrapper = - std::make_unique(halProxyCallback); - return ISensorsSubHalBase::initialize(wrapper); - } -}; - -class SensorsSubHalV2_1 : public SensorsSubHalBase { - public: - Return getSensorsList_2_1(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override { - return ISensorsSubHalBase::getSensorsList(_hidl_cb); - } - - Return injectSensorData_2_1(const V2_1::Event& event) override { - return ISensorsSubHalBase::injectSensorData(event); - } - - Return initialize( - const sp& halProxyCallback) override { - std::unique_ptr wrapper = - std::make_unique(halProxyCallback); - return ISensorsSubHalBase::initialize(wrapper); - } -}; - // SubHal that has continuous sensors for testing purposes. -template -class ContinuousSensorsSubHal : public SubHalVersion { +class ContinuousSensorsSubHal : public SensorsSubHal { public: - ContinuousSensorsSubHal() { - ISensorsSubHalBase::AddSensor(); - ISensorsSubHalBase::AddSensor(); - ISensorsSubHalBase::AddSensor(); - ISensorsSubHalBase::AddSensor(); - ISensorsSubHalBase::AddSensor(); - } + ContinuousSensorsSubHal(); }; // SubHal that has on-change sensors for testing purposes. -template -class OnChangeSensorsSubHal : public SubHalVersion { +class OnChangeSensorsSubHal : public SensorsSubHal { public: - OnChangeSensorsSubHal() { - ISensorsSubHalBase::AddSensor(); - ISensorsSubHalBase::AddSensor(); - ISensorsSubHalBase::AddSensor(); - ISensorsSubHalBase::AddSensor(); - } + OnChangeSensorsSubHal(); }; // SubHal that has both continuous and on-change sensors for testing purposes. -template -class AllSensorsSubHal : public SubHalVersion { +class AllSensorsSubHal : public SensorsSubHal { public: - AllSensorsSubHal() { - ISensorsSubHalBase::AddSensor(); - ISensorsSubHalBase::AddSensor(); - ISensorsSubHalBase::AddSensor(); - ISensorsSubHalBase::AddSensor(); - ISensorsSubHalBase::AddSensor(); - ISensorsSubHalBase::AddSensor(); - ISensorsSubHalBase::AddSensor(); - ISensorsSubHalBase::AddSensor(); - ISensorsSubHalBase::AddSensor(); - } + AllSensorsSubHal(); }; -class SetOperationModeFailingSensorsSubHal : public AllSensorsSubHal { +class SetOperationModeFailingSensorsSubHal : public AllSensorsSubHal { public: Return setOperationMode(OperationMode mode) override; }; -class AllSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { +class AllSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { public: - Return getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override; + Return getSensorsList(getSensorsList_cb _hidl_cb) override; }; -class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { +class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { public: - Return getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override; + Return getSensorsList(getSensorsList_cb _hidl_cb) override; }; -class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal { +class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal { public: void addDynamicSensors(const std::vector& sensorsAdded); void removeDynamicSensors(const std::vector& sensorHandlesAdded); @@ -262,7 +159,7 @@ class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal Date: Wed, 29 Apr 2020 22:06:31 +0000 Subject: [PATCH 0888/1022] Revert "Create Multi-HAL 2.1 service" Revert submission 10501254-multihal_2_1 Reason for revert: Droidcop: Potential culprit for b/155328660 - verifying through Forrest before revert submission. This is part of the standard investigation process, and does not mean your CL will be reverted. Bug: 155328660 Reverted Changes: I2be51568b:Update tests for multihal to test HAL 2.1 Id5ab7b606:Create Multi-HAL 2.1 service Icefae8c12:Set up Multi-HAL for Sensors HAL 2.1 Change-Id: I5e828d1dfd4f9ede5cbd38ff8bc4cc5dc48e4d76 --- sensors/2.1/multihal/Android.bp | 47 ------------------- sensors/2.1/multihal/OWNERS | 3 -- .../android.hardware.sensors@2.1-multihal.xml | 11 ----- ...d.hardware.sensors@2.1-service-multihal.rc | 7 --- sensors/2.1/multihal/service.cpp | 39 --------------- 5 files changed, 107 deletions(-) delete mode 100644 sensors/2.1/multihal/Android.bp delete mode 100644 sensors/2.1/multihal/OWNERS delete mode 100644 sensors/2.1/multihal/android.hardware.sensors@2.1-multihal.xml delete mode 100644 sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc delete mode 100644 sensors/2.1/multihal/service.cpp diff --git a/sensors/2.1/multihal/Android.bp b/sensors/2.1/multihal/Android.bp deleted file mode 100644 index 6a7cac9f25..0000000000 --- a/sensors/2.1/multihal/Android.bp +++ /dev/null @@ -1,47 +0,0 @@ -// -// 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. - -cc_binary { - name: "android.hardware.sensors@2.1-service.multihal", - defaults: [ - "hidl_defaults", - ], - vendor: true, - relative_install_path: "hw", - srcs: [ - "service.cpp", - ], - init_rc: ["android.hardware.sensors@2.1-service-multihal.rc"], - vintf_fragments: ["android.hardware.sensors@2.1-multihal.xml"], - header_libs: [ - "android.hardware.sensors@2.X-shared-utils", - ], - shared_libs: [ - "android.hardware.sensors@2.0", - "android.hardware.sensors@2.0-ScopedWakelock", - "android.hardware.sensors@2.1", - "libbase", - "libcutils", - "libfmq", - "libhidlbase", - "liblog", - "libpower", - "libutils", - ], - static_libs: [ - "android.hardware.sensors@1.0-convert", - "android.hardware.sensors@2.X-multihal", - ], -} diff --git a/sensors/2.1/multihal/OWNERS b/sensors/2.1/multihal/OWNERS deleted file mode 100644 index e9556700d6..0000000000 --- a/sensors/2.1/multihal/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -arthuri@google.com -bduddie@google.com -stange@google.com \ No newline at end of file diff --git a/sensors/2.1/multihal/android.hardware.sensors@2.1-multihal.xml b/sensors/2.1/multihal/android.hardware.sensors@2.1-multihal.xml deleted file mode 100644 index 18bd3ae83b..0000000000 --- a/sensors/2.1/multihal/android.hardware.sensors@2.1-multihal.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - android.hardware.sensors - hwbinder - 2.1 - - ISensors - default - - - diff --git a/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc b/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc deleted file mode 100644 index fc99ee7a06..0000000000 --- a/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc +++ /dev/null @@ -1,7 +0,0 @@ -service vendor.sensors-hal-2-1-multihal /vendor/bin/hw/android.hardware.sensors@2.1-service.multihal - class hal - user system - group system wakelock context_hub - writepid /dev/cpuset/system-background/tasks - capabilities BLOCK_SUSPEND - rlimit rtprio 10 10 diff --git a/sensors/2.1/multihal/service.cpp b/sensors/2.1/multihal/service.cpp deleted file mode 100644 index d68d9a3e73..0000000000 --- a/sensors/2.1/multihal/service.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 -#include -#include -#include "HalProxy.h" - -using android::hardware::configureRpcThreadpool; -using android::hardware::joinRpcThreadpool; -using android::hardware::sensors::V2_1::ISensors; -using android::hardware::sensors::V2_1::implementation::HalProxyV2_1; - -int main(int /* argc */, char** /* argv */) { - configureRpcThreadpool(1, true); - - android::sp halProxy = new HalProxyV2_1(); - if (halProxy->registerAsService() != ::android::OK) { - ALOGE("Failed to register Sensors HAL instance"); - return -1; - } - - joinRpcThreadpool(); - return 1; // joinRpcThreadpool shouldn't exit -} From cd5d437ae974a779dc9318143ce4626d7c4fd1b0 Mon Sep 17 00:00:00 2001 From: Nick Chalko Date: Wed, 29 Apr 2020 22:06:31 +0000 Subject: [PATCH 0889/1022] Revert "Set up Multi-HAL for Sensors HAL 2.1" Revert submission 10501254-multihal_2_1 Reason for revert: Droidcop: Potential culprit for b/155328660 - verifying through Forrest before revert submission. This is part of the standard investigation process, and does not mean your CL will be reverted. Bug: 155328660 Reverted Changes: I2be51568b:Update tests for multihal to test HAL 2.1 Id5ab7b606:Create Multi-HAL 2.1 service Icefae8c12:Set up Multi-HAL for Sensors HAL 2.1 Change-Id: I21176759d45972cde3221cb462934fc1d7bd88c2 --- sensors/2.0/multihal/Android.bp | 8 +- sensors/2.0/multihal/service.cpp | 4 +- .../common/default/2.X/multihal/Android.bp | 5 - .../common/default/2.X/multihal/HalProxy.cpp | 205 +++++++--------- .../default/2.X/multihal/HalProxyCallback.cpp | 82 ------- .../default/2.X/multihal/include/HalProxy.h | 228 +++++++----------- .../2.X/multihal/include/HalProxyCallback.h | 171 ------------- .../2.X/multihal/include/SubHalWrapper.h | 188 --------------- .../multihal/include/V2_0/ScopedWakelock.h | 2 +- .../default/2.X/multihal/tests/Android.bp | 6 - .../2.X/multihal/tests/HalProxy_test.cpp | 5 +- .../common/utils/EventMessageQueueWrapper.h | 36 --- .../common/utils/ISensorsCallbackWrapper.h | 96 -------- 13 files changed, 182 insertions(+), 854 deletions(-) delete mode 100644 sensors/common/default/2.X/multihal/HalProxyCallback.cpp delete mode 100644 sensors/common/default/2.X/multihal/include/HalProxyCallback.h delete mode 100644 sensors/common/default/2.X/multihal/include/SubHalWrapper.h delete mode 100644 sensors/common/utils/ISensorsCallbackWrapper.h diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp index bf51fcdbbc..3ce33906cc 100644 --- a/sensors/2.0/multihal/Android.bp +++ b/sensors/2.0/multihal/Android.bp @@ -25,9 +25,6 @@ cc_binary { ], init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"], vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"], - header_libs: [ - "android.hardware.sensors@2.X-shared-utils", - ], shared_libs: [ "android.hardware.sensors@2.0", "android.hardware.sensors@2.0-ScopedWakelock", @@ -40,8 +37,5 @@ cc_binary { "libpower", "libutils", ], - static_libs: [ - "android.hardware.sensors@1.0-convert", - "android.hardware.sensors@2.X-multihal", - ], + static_libs: ["android.hardware.sensors@2.X-multihal"], } diff --git a/sensors/2.0/multihal/service.cpp b/sensors/2.0/multihal/service.cpp index f50ad7e16a..ef77048020 100644 --- a/sensors/2.0/multihal/service.cpp +++ b/sensors/2.0/multihal/service.cpp @@ -23,12 +23,12 @@ using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; using android::hardware::sensors::V2_0::ISensors; -using android::hardware::sensors::V2_1::implementation::HalProxyV2_0; +using android::hardware::sensors::V2_0::implementation::HalProxy; int main(int /* argc */, char** /* argv */) { configureRpcThreadpool(1, true); - android::sp halProxy = new HalProxyV2_0(); + android::sp halProxy = new HalProxy(); if (halProxy->registerAsService() != ::android::OK) { ALOGE("Failed to register Sensors HAL instance"); return -1; diff --git a/sensors/common/default/2.X/multihal/Android.bp b/sensors/common/default/2.X/multihal/Android.bp index c80c47a4bf..6122323fd8 100644 --- a/sensors/common/default/2.X/multihal/Android.bp +++ b/sensors/common/default/2.X/multihal/Android.bp @@ -17,7 +17,6 @@ cc_defaults { name: "android.hardware.sensors@2.X-multihal-defaults", header_libs: [ "android.hardware.sensors@2.X-multihal.header", - "android.hardware.sensors@2.X-shared-utils", ], shared_libs: [ "android.hardware.sensors@1.0", @@ -31,9 +30,6 @@ cc_defaults { "libpower", "libutils", ], - static_libs: [ - "android.hardware.sensors@1.0-convert", - ], cflags: ["-DLOG_TAG=\"SensorsMultiHal\""], } @@ -66,7 +62,6 @@ cc_library_static { ], srcs: [ "HalProxy.cpp", - "HalProxyCallback.cpp", ], vendor_available: true, export_header_lib_headers: [ diff --git a/sensors/common/default/2.X/multihal/HalProxy.cpp b/sensors/common/default/2.X/multihal/HalProxy.cpp index a09e9e938e..869c0330f4 100644 --- a/sensors/common/default/2.X/multihal/HalProxy.cpp +++ b/sensors/common/default/2.X/multihal/HalProxy.cpp @@ -32,17 +32,15 @@ namespace android { namespace hardware { namespace sensors { -namespace V2_1 { +namespace V2_0 { namespace implementation { -using ::android::hardware::sensors::V1_0::Result; using ::android::hardware::sensors::V2_0::EventQueueFlagBits; using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; using ::android::hardware::sensors::V2_0::implementation::getTimeNow; using ::android::hardware::sensors::V2_0::implementation::kWakelockTimeoutNs; -typedef V2_0::implementation::ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*); -typedef V2_1::implementation::ISensorsSubHal*(SensorsHalGetSubHalV2_1Func)(uint32_t*); +typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*); static constexpr int32_t kBitsAfterSubHalIndex = 24; @@ -87,24 +85,7 @@ HalProxy::HalProxy() { init(); } -HalProxy::HalProxy(std::vector& subHalList) { - for (ISensorsSubHalV2_0* subHal : subHalList) { - mSubHalList.push_back(std::make_unique(subHal)); - } - - init(); -} - -HalProxy::HalProxy(std::vector& subHalList, - std::vector& subHalListV2_1) { - for (ISensorsSubHalV2_0* subHal : subHalList) { - mSubHalList.push_back(std::make_unique(subHal)); - } - - for (ISensorsSubHalV2_1* subHal : subHalListV2_1) { - mSubHalList.push_back(std::make_unique(subHal)); - } - +HalProxy::HalProxy(std::vector& subHalList) : mSubHalList(subHalList) { init(); } @@ -112,8 +93,8 @@ HalProxy::~HalProxy() { stopThreads(); } -Return HalProxy::getSensorsList_2_1(ISensorsV2_1::getSensorsList_2_1_cb _hidl_cb) { - std::vector sensors; +Return HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) { + std::vector sensors; for (const auto& iter : mSensors) { sensors.push_back(iter.second); } @@ -121,31 +102,22 @@ Return HalProxy::getSensorsList_2_1(ISensorsV2_1::getSensorsList_2_1_cb _h return Void(); } -Return HalProxy::getSensorsList(ISensorsV2_0::getSensorsList_cb _hidl_cb) { - std::vector sensors; - for (const auto& iter : mSensors) { - sensors.push_back(convertToOldSensorInfo(iter.second)); - } - _hidl_cb(sensors); - return Void(); -} - Return HalProxy::setOperationMode(OperationMode mode) { Result result = Result::OK; size_t subHalIndex; for (subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) { - result = mSubHalList[subHalIndex]->setOperationMode(mode); + ISensorsSubHal* subHal = mSubHalList[subHalIndex]; + result = subHal->setOperationMode(mode); if (result != Result::OK) { - ALOGE("setOperationMode failed for SubHal: %s", - mSubHalList[subHalIndex]->getName().c_str()); + ALOGE("setOperationMode failed for SubHal: %s", subHal->getName().c_str()); break; } } - if (result != Result::OK) { // Reset the subhal operation modes that have been flipped for (size_t i = 0; i < subHalIndex; i++) { - mSubHalList[i]->setOperationMode(mCurrentOperationMode); + ISensorsSubHal* subHal = mSubHalList[i]; + subHal->setOperationMode(mCurrentOperationMode); } } else { mCurrentOperationMode = mode; @@ -161,42 +133,10 @@ Return HalProxy::activate(int32_t sensorHandle, bool enabled) { ->activate(clearSubHalIndex(sensorHandle), enabled); } -Return HalProxy::initialize_2_1( - const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, - const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback) { - sp dynamicCallback = - new ISensorsCallbackWrapperV2_1(sensorsCallback); - - // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions. - auto eventQueue = - std::make_unique(eventQueueDescriptor, true /* resetPointers */); - std::unique_ptr queue = - std::make_unique(eventQueue); - - return initializeCommon(queue, wakeLockDescriptor, dynamicCallback); -} - Return HalProxy::initialize( - const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback) { - sp dynamicCallback = - new ISensorsCallbackWrapperV2_0(sensorsCallback); - - // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions. - auto eventQueue = - std::make_unique(eventQueueDescriptor, true /* resetPointers */); - std::unique_ptr queue = - std::make_unique(eventQueue); - - return initializeCommon(queue, wakeLockDescriptor, dynamicCallback); -} - -Return HalProxy::initializeCommon( - std::unique_ptr& eventQueue, - const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback) { + const sp& sensorsCallback) { Result result = Result::OK; stopThreads(); @@ -207,7 +147,7 @@ Return HalProxy::initializeCommon( disableAllSensors(); // Clears the queue if any events were pending write before. - mPendingWriteEventsQueue = std::queue, size_t>>(); + mPendingWriteEventsQueue = std::queue, size_t>>(); mSizePendingWriteEventsQueue = 0; // Clears previously connected dynamic sensors @@ -216,7 +156,8 @@ Return HalProxy::initializeCommon( mDynamicSensorsCallback = sensorsCallback; // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions. - mEventQueue = std::move(eventQueue); + mEventQueue = + std::make_unique(eventQueueDescriptor, true /* resetPointers */); // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP // events have been successfully read and handled by the framework. @@ -245,10 +186,12 @@ Return HalProxy::initializeCommon( mWakelockThread = std::thread(startWakelockThread, this); for (size_t i = 0; i < mSubHalList.size(); i++) { - Result currRes = mSubHalList[i]->initialize(this, this, i); + auto subHal = mSubHalList[i]; + const auto& subHalCallback = mSubHalCallbacks[i]; + Result currRes = subHal->initialize(subHalCallback); if (currRes != Result::OK) { result = currRes; - ALOGE("Subhal '%s' failed to initialize.", mSubHalList[i]->getName().c_str()); + ALOGE("Subhal '%s' failed to initialize.", subHal->getName().c_str()); break; } } @@ -274,11 +217,7 @@ Return HalProxy::flush(int32_t sensorHandle) { return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle)); } -Return HalProxy::injectSensorData_2_1(const V2_1::Event& event) { - return injectSensorData(convertToOldEvent(event)); -} - -Return HalProxy::injectSensorData(const V1_0::Event& event) { +Return HalProxy::injectSensorData(const Event& event) { Result result = Result::OK; if (mCurrentOperationMode == OperationMode::NORMAL && event.sensorType != V1_0::SensorType::ADDITIONAL_INFO) { @@ -287,19 +226,18 @@ Return HalProxy::injectSensorData(const V1_0::Event& event) { result = Result::BAD_VALUE; } if (result == Result::OK) { - V1_0::Event subHalEvent = event; + Event subHalEvent = event; if (!isSubHalIndexValid(event.sensorHandle)) { return Result::BAD_VALUE; } subHalEvent.sensorHandle = clearSubHalIndex(event.sensorHandle); - result = getSubHalForSensorHandle(event.sensorHandle) - ->injectSensorData(convertToNewEvent(subHalEvent)); + result = getSubHalForSensorHandle(event.sensorHandle)->injectSensorData(subHalEvent); } return result; } Return HalProxy::registerDirectChannel(const SharedMemInfo& mem, - ISensorsV2_0::registerDirectChannel_cb _hidl_cb) { + registerDirectChannel_cb _hidl_cb) { if (mDirectChannelSubHal == nullptr) { _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */); } else { @@ -319,8 +257,7 @@ Return HalProxy::unregisterDirectChannel(int32_t channelHandle) { } Return HalProxy::configDirectReport(int32_t sensorHandle, int32_t channelHandle, - RateLevel rate, - ISensorsV2_0::configDirectReport_cb _hidl_cb) { + RateLevel rate, configDirectReport_cb _hidl_cb) { if (mDirectChannelSubHal == nullptr) { _hidl_cb(Result::INVALID_OPERATION, -1 /* reportToken */); } else if (sensorHandle == -1 && rate != RateLevel::STOP) { @@ -365,7 +302,7 @@ Return HalProxy::debug(const hidl_handle& fd, const hidl_vec& stream << " # of non-dynamic sensors across all subhals: " << mSensors.size() << std::endl; stream << " # of dynamic sensors across all subhals: " << mDynamicSensors.size() << std::endl; stream << "SubHals (" << mSubHalList.size() << "):" << std::endl; - for (auto& subHal : mSubHalList) { + for (ISensorsSubHal* subHal : mSubHalList) { stream << " Name: " << subHal->getName() << std::endl; stream << " Debug dump: " << std::endl; android::base::WriteStringToFd(stream.str(), writeFd); @@ -432,37 +369,20 @@ void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) { } else { SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr = (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal"); - if (sensorsHalGetSubHalPtr != nullptr) { + if (sensorsHalGetSubHalPtr == nullptr) { + ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s", + subHalLibraryFile.c_str()); + } else { std::function sensorsHalGetSubHal = *sensorsHalGetSubHalPtr; uint32_t version; - ISensorsSubHalV2_0* subHal = sensorsHalGetSubHal(&version); + ISensorsSubHal* subHal = sensorsHalGetSubHal(&version); if (version != SUB_HAL_2_0_VERSION) { ALOGE("SubHal version was not 2.0 for library: %s", subHalLibraryFile.c_str()); } else { ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str()); - mSubHalList.push_back(std::make_unique(subHal)); - } - } else { - SensorsHalGetSubHalV2_1Func* getSubHalV2_1Ptr = - (SensorsHalGetSubHalV2_1Func*)dlsym(handle, "sensorsHalGetSubHal_2_1"); - - if (getSubHalV2_1Ptr == nullptr) { - ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s", - subHalLibraryFile.c_str()); - } else { - std::function sensorsHalGetSubHal_2_1 = - *getSubHalV2_1Ptr; - uint32_t version; - ISensorsSubHalV2_1* subHal = sensorsHalGetSubHal_2_1(&version); - if (version != SUB_HAL_2_1_VERSION) { - ALOGE("SubHal version was not 2.1 for library: %s", - subHalLibraryFile.c_str()); - } else { - ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str()); - mSubHalList.push_back(std::make_unique(subHal)); - } + mSubHalList.push_back(subHal); } } } @@ -470,28 +390,36 @@ void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) { } } +void HalProxy::initializeSubHalCallbacks() { + for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) { + sp callback = new HalProxyCallback(this, subHalIndex); + mSubHalCallbacks.push_back(callback); + } +} + void HalProxy::initializeSensorList() { for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) { - auto result = mSubHalList[subHalIndex]->getSensorsList([&](const auto& list) { + ISensorsSubHal* subHal = mSubHalList[subHalIndex]; + auto result = subHal->getSensorsList([&](const auto& list) { for (SensorInfo sensor : list) { if (!subHalIndexIsClear(sensor.sensorHandle)) { ALOGE("SubHal sensorHandle's first byte was not 0"); } else { ALOGV("Loaded sensor: %s", sensor.name.c_str()); sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex); - setDirectChannelFlags(&sensor, mSubHalList[subHalIndex]); + setDirectChannelFlags(&sensor, subHal); mSensors[sensor.sensorHandle] = sensor; } } }); if (!result.isOk()) { - ALOGE("getSensorsList call failed for SubHal: %s", - mSubHalList[subHalIndex]->getName().c_str()); + ALOGE("getSensorsList call failed for SubHal: %s", subHal->getName().c_str()); } } } void HalProxy::init() { + initializeSubHalCallbacks(); initializeSensorList(); } @@ -624,7 +552,7 @@ void HalProxy::resetSharedWakelock() { } void HalProxy::postEventsToMessageQueue(const std::vector& events, size_t numWakeupEvents, - V2_0::implementation::ScopedWakelock wakelock) { + ScopedWakelock wakelock) { size_t numToWrite = 0; std::lock_guard lock(mEventQueueWriteMutex); if (wakelock.isLocked()) { @@ -682,8 +610,7 @@ void HalProxy::decrementRefCountAndMaybeReleaseWakelock(size_t delta, } } -void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, - std::shared_ptr subHal) { +void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal) { bool sensorSupportsDirectChannel = (sensorInfo->flags & (V1_0::SensorFlagBits::MASK_DIRECT_REPORT | V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL)) != 0; @@ -697,7 +624,7 @@ void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, } } -std::shared_ptr HalProxy::getSubHalForSensorHandle(int32_t sensorHandle) { +ISensorsSubHal* HalProxy::getSubHalForSensorHandle(int32_t sensorHandle) { return mSubHalList[extractSubHalIndex(sensorHandle)]; } @@ -724,8 +651,46 @@ bool HalProxy::subHalIndexIsClear(int32_t sensorHandle) { return (sensorHandle & kSensorHandleSubHalIndexMask) == 0; } +void HalProxyCallback::postEvents(const std::vector& events, ScopedWakelock wakelock) { + if (events.empty() || !mHalProxy->areThreadsRunning()) return; + size_t numWakeupEvents; + std::vector processedEvents = processEvents(events, &numWakeupEvents); + if (numWakeupEvents > 0) { + ALOG_ASSERT(wakelock.isLocked(), + "Wakeup events posted while wakelock unlocked for subhal" + " w/ index %" PRId32 ".", + mSubHalIndex); + } else { + ALOG_ASSERT(!wakelock.isLocked(), + "No Wakeup events posted but wakelock locked for subhal" + " w/ index %" PRId32 ".", + mSubHalIndex); + } + mHalProxy->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock)); +} + +ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) { + ScopedWakelock wakelock(mHalProxy, lock); + return wakelock; +} + +std::vector HalProxyCallback::processEvents(const std::vector& events, + size_t* numWakeupEvents) const { + *numWakeupEvents = 0; + std::vector eventsOut; + for (Event event : events) { + event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex); + eventsOut.push_back(event); + const SensorInfo& sensor = mHalProxy->getSensorInfo(event.sensorHandle); + if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) { + (*numWakeupEvents)++; + } + } + return eventsOut; +} + } // namespace implementation -} // namespace V2_1 +} // namespace V2_0 } // namespace sensors } // namespace hardware } // namespace android diff --git a/sensors/common/default/2.X/multihal/HalProxyCallback.cpp b/sensors/common/default/2.X/multihal/HalProxyCallback.cpp deleted file mode 100644 index a0e0c6b751..0000000000 --- a/sensors/common/default/2.X/multihal/HalProxyCallback.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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. - */ - -#include "HalProxyCallback.h" - -namespace android { -namespace hardware { -namespace sensors { -namespace V2_0 { -namespace implementation { - -static constexpr int32_t kBitsAfterSubHalIndex = 24; - -/** - * Set the subhal index as first byte of sensor handle and return this modified version. - * - * @param sensorHandle The sensor handle to modify. - * @param subHalIndex The index in the hal proxy of the sub hal this sensor belongs to. - * - * @return The modified sensor handle. - */ -int32_t setSubHalIndex(int32_t sensorHandle, size_t subHalIndex) { - return sensorHandle | (static_cast(subHalIndex) << kBitsAfterSubHalIndex); -} - -void HalProxyCallbackBase::postEvents(const std::vector& events, - ScopedWakelock wakelock) { - if (events.empty() || !mCallback->areThreadsRunning()) return; - size_t numWakeupEvents; - std::vector processedEvents = processEvents(events, &numWakeupEvents); - if (numWakeupEvents > 0) { - ALOG_ASSERT(wakelock.isLocked(), - "Wakeup events posted while wakelock unlocked for subhal" - " w/ index %" PRId32 ".", - mSubHalIndex); - } else { - ALOG_ASSERT(!wakelock.isLocked(), - "No Wakeup events posted but wakelock locked for subhal" - " w/ index %" PRId32 ".", - mSubHalIndex); - } - mCallback->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock)); -} - -ScopedWakelock HalProxyCallbackBase::createScopedWakelock(bool lock) { - ScopedWakelock wakelock(mRefCounter, lock); - return wakelock; -} - -std::vector HalProxyCallbackBase::processEvents(const std::vector& events, - size_t* numWakeupEvents) const { - *numWakeupEvents = 0; - std::vector eventsOut; - for (V2_1::Event event : events) { - event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex); - eventsOut.push_back(event); - const V2_1::SensorInfo& sensor = mCallback->getSensorInfo(event.sensorHandle); - if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) { - (*numWakeupEvents)++; - } - } - return eventsOut; -} - -} // namespace implementation -} // namespace V2_0 -} // namespace sensors -} // namespace hardware -} // namespace android diff --git a/sensors/common/default/2.X/multihal/include/HalProxy.h b/sensors/common/default/2.X/multihal/include/HalProxy.h index fb0b806bab..d7e8795903 100644 --- a/sensors/common/default/2.X/multihal/include/HalProxy.h +++ b/sensors/common/default/2.X/multihal/include/HalProxy.h @@ -16,17 +16,12 @@ #pragma once -#include "EventMessageQueueWrapper.h" -#include "HalProxyCallback.h" -#include "ISensorsCallbackWrapper.h" -#include "SubHalWrapper.h" #include "V2_0/ScopedWakelock.h" #include "V2_0/SubHal.h" #include "V2_1/SubHal.h" -#include "convertV2_1.h" -#include -#include +#include +#include #include #include #include @@ -43,97 +38,96 @@ namespace android { namespace hardware { namespace sensors { -namespace V2_1 { +namespace V2_0 { namespace implementation { -/** - * HalProxy is the main interface for Multi-HAL. It is responsible for managing subHALs and - * proxying function calls to/from the subHAL APIs from the sensors framework. It also manages any - * wakelocks allocated through the IHalProxyCallback and manages posting events to the sensors - * framework. - */ -class HalProxy : public V2_0::implementation::IScopedWakelockRefCounter, - public V2_0::implementation::ISubHalCallback { +using ::android::sp; +using ::android::hardware::EventFlag; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::MessageQueue; +using ::android::hardware::MQDescriptor; +using ::android::hardware::Return; +using ::android::hardware::Void; + +class HalProxy : public ISensors, public IScopedWakelockRefCounter { public: - using Event = ::android::hardware::sensors::V2_1::Event; + using Event = ::android::hardware::sensors::V1_0::Event; using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; using Result = ::android::hardware::sensors::V1_0::Result; - using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo; + using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo; using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; - using IHalProxyCallbackV2_0 = V2_0::implementation::IHalProxyCallback; - using IHalProxyCallbackV2_1 = V2_1::implementation::IHalProxyCallback; - using ISensorsSubHalV2_0 = V2_0::implementation::ISensorsSubHal; - using ISensorsSubHalV2_1 = V2_1::implementation::ISensorsSubHal; - using ISensorsV2_0 = V2_0::ISensors; - using ISensorsV2_1 = V2_1::ISensors; - using HalProxyCallbackBase = V2_0::implementation::HalProxyCallbackBase; + using ISensorsSubHal = ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal; explicit HalProxy(); // Test only constructor. - explicit HalProxy(std::vector& subHalList); - explicit HalProxy(std::vector& subHalList, - std::vector& subHalListV2_1); + explicit HalProxy(std::vector& subHalList); ~HalProxy(); - // Methods from ::android::hardware::sensors::V2_1::ISensors follow. - Return getSensorsList_2_1(ISensorsV2_1::getSensorsList_2_1_cb _hidl_cb); - - Return initialize_2_1( - const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, - const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback); - - Return injectSensorData_2_1(const Event& event); - // Methods from ::android::hardware::sensors::V2_0::ISensors follow. - Return getSensorsList(ISensorsV2_0::getSensorsList_cb _hidl_cb); + Return getSensorsList(getSensorsList_cb _hidl_cb) override; - Return setOperationMode(OperationMode mode); + Return setOperationMode(OperationMode mode) override; - Return activate(int32_t sensorHandle, bool enabled); + Return activate(int32_t sensorHandle, bool enabled) override; Return initialize( - const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback); - - Return initializeCommon( - std::unique_ptr& eventQueue, - const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback); + const sp& sensorsCallback) override; Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs); + int64_t maxReportLatencyNs) override; - Return flush(int32_t sensorHandle); + Return flush(int32_t sensorHandle) override; - Return injectSensorData(const V1_0::Event& event); + Return injectSensorData(const Event& event) override; Return registerDirectChannel(const SharedMemInfo& mem, - ISensorsV2_0::registerDirectChannel_cb _hidl_cb); + registerDirectChannel_cb _hidl_cb) override; - Return unregisterDirectChannel(int32_t channelHandle); + Return unregisterDirectChannel(int32_t channelHandle) override; Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, - ISensorsV2_0::configDirectReport_cb _hidl_cb); + configDirectReport_cb _hidl_cb) override; - Return debug(const hidl_handle& fd, const hidl_vec& args); + Return debug(const hidl_handle& fd, const hidl_vec& args) override; + // Below methods from ::android::hardware::sensors::V2_0::ISensorsCallback with a minor change + // to pass in the sub-HAL index. While the above methods are invoked from the sensors framework + // via the binder, these methods are invoked from a callback provided to sub-HALs inside the + // same process as the HalProxy, but potentially running on different threads. Return onDynamicSensorsConnected(const hidl_vec& dynamicSensorsAdded, - int32_t subHalIndex) override; + int32_t subHalIndex); Return onDynamicSensorsDisconnected(const hidl_vec& dynamicSensorHandlesRemoved, - int32_t subHalIndex) override; + int32_t subHalIndex); + // Below methods are for HalProxyCallback + + /** + * Post events to the event message queue if there is room to write them. Otherwise post the + * remaining events to a background thread for a blocking write with a kPendingWriteTimeoutNs + * timeout. + * + * @param events The list of events to post to the message queue. + * @param numWakeupEvents The number of wakeup events in events. + * @param wakelock The wakelock associated with this post of events. + */ void postEventsToMessageQueue(const std::vector& events, size_t numWakeupEvents, - V2_0::implementation::ScopedWakelock wakelock) override; + ScopedWakelock wakelock); - const SensorInfo& getSensorInfo(int32_t sensorHandle) override { - return mSensors[sensorHandle]; - } + /** + * Get the sensor info associated with that sensorHandle. + * + * @param sensorHandle The sensor handle. + * + * @return The sensor info object in the mapping. + */ + const SensorInfo& getSensorInfo(int32_t sensorHandle) { return mSensors[sensorHandle]; } - bool areThreadsRunning() override { return mThreadsRun.load(); } + bool areThreadsRunning() { return mThreadsRun.load(); } // Below methods are from IScopedWakelockRefCounter interface bool incrementRefCountAndMaybeAcquireWakelock(size_t delta, @@ -142,14 +136,13 @@ class HalProxy : public V2_0::implementation::IScopedWakelockRefCounter, void decrementRefCountAndMaybeReleaseWakelock(size_t delta, int64_t timeoutStart = -1) override; private: - using EventMessageQueueV2_1 = MessageQueue; - using EventMessageQueueV2_0 = MessageQueue; + using EventMessageQueue = MessageQueue; using WakeLockMessageQueue = MessageQueue; /** * The Event FMQ where sensor events are written */ - std::unique_ptr mEventQueue; + std::unique_ptr mEventQueue; /** * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events @@ -168,12 +161,15 @@ class HalProxy : public V2_0::implementation::IScopedWakelockRefCounter, /** * Callback to the sensors framework to inform it that new sensors have been added or removed. */ - sp mDynamicSensorsCallback; + sp mDynamicSensorsCallback; /** - * SubHal objects that have been saved from vendor dynamic libraries. + * SubHal object pointers that have been saved from vendor dynamic libraries. */ - std::vector> mSubHalList; + std::vector mSubHalList; + + //! The list of subhal callbacks for each subhal where the indices correlate with mSubHalList + std::vector> mSubHalCallbacks; /** * Map of sensor handles to SensorInfo objects that contains the sensor info from subhals as @@ -191,7 +187,7 @@ class HalProxy : public V2_0::implementation::IScopedWakelockRefCounter, OperationMode mCurrentOperationMode = OperationMode::NORMAL; //! The single subHal that supports directChannel reporting. - std::shared_ptr mDirectChannelSubHal; + ISensorsSubHal* mDirectChannelSubHal = nullptr; //! The timeout for each pending write on background thread for events. static const int64_t kPendingWriteTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */; @@ -243,9 +239,9 @@ class HalProxy : public V2_0::implementation::IScopedWakelockRefCounter, //! The refcount of how many ScopedWakelocks and pending wakeup events are active size_t mWakelockRefCount = 0; - int64_t mWakelockTimeoutStartTime = V2_0::implementation::getTimeNow(); + int64_t mWakelockTimeoutStartTime = getTimeNow(); - int64_t mWakelockTimeoutResetTime = V2_0::implementation::getTimeNow(); + int64_t mWakelockTimeoutResetTime = getTimeNow(); const char* kWakelockName = "SensorsHAL_WAKEUP"; @@ -325,7 +321,7 @@ class HalProxy : public V2_0::implementation::IScopedWakelockRefCounter, * disabled. * @param subHal The subhal pointer that the current sensorInfo object came from. */ - void setDirectChannelFlags(SensorInfo* sensorInfo, std::shared_ptr subHal); + void setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal); /* * Get the subhal pointer which can be found by indexing into the mSubHalList vector @@ -333,7 +329,7 @@ class HalProxy : public V2_0::implementation::IScopedWakelockRefCounter, * * @param sensorHandle The handle used to identify a sensor in one of the subhals. */ - std::shared_ptr getSubHalForSensorHandle(int32_t sensorHandle); + ISensorsSubHal* getSubHalForSensorHandle(int32_t sensorHandle); /** * Checks that sensorHandle's subhal index byte is within bounds of mSubHalList. @@ -372,81 +368,39 @@ class HalProxy : public V2_0::implementation::IScopedWakelockRefCounter, }; /** - * Since a newer HAL can't masquerade as a older HAL, IHalProxy enables the HalProxy to be compiled - * either for HAL 2.0 or HAL 2.1 depending on the build configuration. + * Callback class used to provide the HalProxy with the index of which subHal is invoking */ -template -class IHalProxy : public HalProxy, public ISensorsVersion { - Return getSensorsList(ISensorsV2_0::getSensorsList_cb _hidl_cb) override { - return HalProxy::getSensorsList(_hidl_cb); +class HalProxyCallback : public IHalProxyCallback { + using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo; + + public: + HalProxyCallback(HalProxy* halProxy, int32_t subHalIndex) + : mHalProxy(halProxy), mSubHalIndex(subHalIndex) {} + + Return onDynamicSensorsConnected( + const hidl_vec& dynamicSensorsAdded) override { + return mHalProxy->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex); } - Return setOperationMode(OperationMode mode) override { - return HalProxy::setOperationMode(mode); + Return onDynamicSensorsDisconnected( + const hidl_vec& dynamicSensorHandlesRemoved) override { + return mHalProxy->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex); } - Return activate(int32_t sensorHandle, bool enabled) override { - return HalProxy::activate(sensorHandle, enabled); - } + void postEvents(const std::vector& events, ScopedWakelock wakelock); - Return initialize( - const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, - const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback) override { - return HalProxy::initialize(eventQueueDescriptor, wakeLockDescriptor, sensorsCallback); - } + ScopedWakelock createScopedWakelock(bool lock); - Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) override { - return HalProxy::batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); - } + private: + HalProxy* mHalProxy; + int32_t mSubHalIndex; - Return flush(int32_t sensorHandle) override { return HalProxy::flush(sensorHandle); } - - Return injectSensorData(const V1_0::Event& event) override { - return HalProxy::injectSensorData(event); - } - - Return registerDirectChannel(const SharedMemInfo& mem, - ISensorsV2_0::registerDirectChannel_cb _hidl_cb) override { - return HalProxy::registerDirectChannel(mem, _hidl_cb); - } - - Return unregisterDirectChannel(int32_t channelHandle) override { - return HalProxy::unregisterDirectChannel(channelHandle); - } - - Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, - ISensorsV2_0::configDirectReport_cb _hidl_cb) override { - return HalProxy::configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); - } - - Return debug(const hidl_handle& fd, const hidl_vec& args) override { - return HalProxy::debug(fd, args); - } -}; - -class HalProxyV2_0 : public IHalProxy {}; - -class HalProxyV2_1 : public IHalProxy { - Return getSensorsList_2_1(ISensorsV2_1::getSensorsList_2_1_cb _hidl_cb) override { - return HalProxy::getSensorsList_2_1(_hidl_cb); - } - - Return initialize_2_1( - const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, - const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback) override { - return HalProxy::initialize_2_1(eventQueueDescriptor, wakeLockDescriptor, sensorsCallback); - } - - Return injectSensorData_2_1(const Event& event) override { - return HalProxy::injectSensorData_2_1(event); - } + std::vector processEvents(const std::vector& events, + size_t* numWakeupEvents) const; }; } // namespace implementation -} // namespace V2_1 +} // namespace V2_0 } // namespace sensors } // namespace hardware } // namespace android diff --git a/sensors/common/default/2.X/multihal/include/HalProxyCallback.h b/sensors/common/default/2.X/multihal/include/HalProxyCallback.h deleted file mode 100644 index e62b7d1c00..0000000000 --- a/sensors/common/default/2.X/multihal/include/HalProxyCallback.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include "V2_0/ScopedWakelock.h" -#include "V2_0/SubHal.h" -#include "V2_1/SubHal.h" -#include "convertV2_1.h" - -#include -#include -#include - -namespace android { -namespace hardware { -namespace sensors { -namespace V2_0 { -namespace implementation { - -/** - * Interface used to communicate with the HalProxy when subHals interact with their provided - * callback. - */ -class ISubHalCallback { - public: - virtual ~ISubHalCallback() {} - - // Below methods from ::android::hardware::sensors::V2_0::ISensorsCallback with a minor change - // to pass in the sub-HAL index. While the above methods are invoked from the sensors framework - // via the binder, these methods are invoked from a callback provided to sub-HALs inside the - // same process as the HalProxy, but potentially running on different threads. - virtual Return onDynamicSensorsConnected( - const hidl_vec& dynamicSensorsAdded, int32_t subHalIndex) = 0; - - virtual Return onDynamicSensorsDisconnected( - const hidl_vec& dynamicSensorHandlesRemoved, int32_t subHalIndex) = 0; - - /** - * Post events to the event message queue if there is room to write them. Otherwise post the - * remaining events to a background thread for a blocking write with a kPendingWriteTimeoutNs - * timeout. - * - * @param events The list of events to post to the message queue. - * @param numWakeupEvents The number of wakeup events in events. - * @param wakelock The wakelock associated with this post of events. - */ - virtual void postEventsToMessageQueue(const std::vector& events, - size_t numWakeupEvents, - V2_0::implementation::ScopedWakelock wakelock) = 0; - - /** - * Get the sensor info associated with that sensorHandle. - * - * @param sensorHandle The sensor handle. - * - * @return The sensor info object in the mapping. - */ - virtual const V2_1::SensorInfo& getSensorInfo(int32_t sensorHandle) = 0; - - virtual bool areThreadsRunning() = 0; -}; - -/** - * Callback class given to subhals that allows the HalProxy to know which subhal a given invocation - * is coming from. - */ -class HalProxyCallbackBase : public VirtualLightRefBase { - public: - HalProxyCallbackBase(ISubHalCallback* callback, - V2_0::implementation::IScopedWakelockRefCounter* refCounter, - int32_t subHalIndex) - : mCallback(callback), mRefCounter(refCounter), mSubHalIndex(subHalIndex) {} - - void postEvents(const std::vector& events, - V2_0::implementation::ScopedWakelock wakelock); - - V2_0::implementation::ScopedWakelock createScopedWakelock(bool lock); - - protected: - ISubHalCallback* mCallback; - V2_0::implementation::IScopedWakelockRefCounter* mRefCounter; - int32_t mSubHalIndex; - - private: - std::vector processEvents(const std::vector& events, - size_t* numWakeupEvents) const; -}; - -class HalProxyCallbackV2_0 : public HalProxyCallbackBase, - public V2_0::implementation::IHalProxyCallback { - public: - HalProxyCallbackV2_0(ISubHalCallback* callback, - V2_0::implementation::IScopedWakelockRefCounter* refCounter, - int32_t subHalIndex) - : HalProxyCallbackBase(callback, refCounter, subHalIndex) {} - - Return onDynamicSensorsConnected( - const hidl_vec& dynamicSensorsAdded) override { - return mCallback->onDynamicSensorsConnected( - V2_1::implementation::convertToNewSensorInfos(dynamicSensorsAdded), mSubHalIndex); - } - - Return onDynamicSensorsDisconnected( - const hidl_vec& dynamicSensorHandlesRemoved) override { - return mCallback->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex); - } - - void postEvents(const std::vector& events, - V2_0::implementation::ScopedWakelock wakelock) override { - HalProxyCallbackBase::postEvents(V2_1::implementation::convertToNewEvents(events), - std::move(wakelock)); - } - - V2_0::implementation::ScopedWakelock createScopedWakelock(bool lock) override { - return HalProxyCallbackBase::createScopedWakelock(lock); - } -}; - -class HalProxyCallbackV2_1 : public HalProxyCallbackBase, - public V2_1::implementation::IHalProxyCallback { - public: - HalProxyCallbackV2_1(ISubHalCallback* callback, - V2_0::implementation::IScopedWakelockRefCounter* refCounter, - int32_t subHalIndex) - : HalProxyCallbackBase(callback, refCounter, subHalIndex) {} - - Return onDynamicSensorsConnected_2_1( - const hidl_vec& dynamicSensorsAdded) override { - return mCallback->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex); - } - - Return onDynamicSensorsConnected( - const hidl_vec& /* dynamicSensorsAdded */) override { - LOG_ALWAYS_FATAL("Old dynamic sensors method can't be used"); - return Void(); - } - - Return onDynamicSensorsDisconnected( - const hidl_vec& dynamicSensorHandlesRemoved) override { - return mCallback->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex); - } - - void postEvents(const std::vector& events, - V2_0::implementation::ScopedWakelock wakelock) override { - return HalProxyCallbackBase::postEvents(events, std::move(wakelock)); - } - - V2_0::implementation::ScopedWakelock createScopedWakelock(bool lock) override { - return HalProxyCallbackBase::createScopedWakelock(lock); - } -}; - -} // namespace implementation -} // namespace V2_0 -} // namespace sensors -} // namespace hardware -} // namespace android \ No newline at end of file diff --git a/sensors/common/default/2.X/multihal/include/SubHalWrapper.h b/sensors/common/default/2.X/multihal/include/SubHalWrapper.h deleted file mode 100644 index 149bb5ea5b..0000000000 --- a/sensors/common/default/2.X/multihal/include/SubHalWrapper.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include "HalProxyCallback.h" -#include "V2_0/SubHal.h" -#include "V2_1/SubHal.h" - -#include "android/hardware/sensors/1.0/ISensors.h" -#include "android/hardware/sensors/1.0/types.h" -#include "android/hardware/sensors/2.0/ISensors.h" -#include "android/hardware/sensors/2.0/ISensorsCallback.h" -#include "android/hardware/sensors/2.1/ISensors.h" -#include "android/hardware/sensors/2.1/ISensorsCallback.h" -#include "android/hardware/sensors/2.1/types.h" - -#include - -#include - -namespace android { -namespace hardware { -namespace sensors { -namespace V2_1 { -namespace implementation { - -/** - * The following subHal wrapper classes abstract away common functionality across V2.0 and V2.1 - * subHal interfaces. Much of the logic is common between the two versions and this allows users of - * the classes to only care about the type used at initialization and then interact with either - * version of the subHal interface without worrying about the type. - */ -class ISubHalWrapperBase { - protected: - using Event = ::android::hardware::sensors::V2_1::Event; - using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; - using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; - using Result = ::android::hardware::sensors::V1_0::Result; - using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo; - using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; - - public: - virtual ~ISubHalWrapperBase() {} - - virtual bool supportsNewEvents() = 0; - - virtual Return initialize(V2_0::implementation::ISubHalCallback* callback, - V2_0::implementation::IScopedWakelockRefCounter* refCounter, - int32_t subHalIndex) = 0; - - virtual Return getSensorsList( - ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) = 0; - - virtual Return setOperationMode(OperationMode mode) = 0; - - virtual Return activate(int32_t sensorHandle, bool enabled) = 0; - - virtual Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) = 0; - - virtual Return flush(int32_t sensorHandle) = 0; - - virtual Return injectSensorData(const Event& event) = 0; - - virtual Return registerDirectChannel(const SharedMemInfo& mem, - ISensors::registerDirectChannel_cb _hidl_cb) = 0; - - virtual Return unregisterDirectChannel(int32_t channelHandle) = 0; - - virtual Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, - RateLevel rate, - ISensors::configDirectReport_cb _hidl_cb) = 0; - - virtual Return debug(const hidl_handle& fd, const hidl_vec& args) = 0; - - virtual const std::string getName() = 0; -}; - -template -class SubHalWrapperBase : public ISubHalWrapperBase { - public: - SubHalWrapperBase(T* subHal) : mSubHal(subHal){}; - - virtual bool supportsNewEvents() override { return false; } - - virtual Return getSensorsList( - ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override { - return mSubHal->getSensorsList( - [&](const auto& list) { _hidl_cb(convertToNewSensorInfos(list)); }); - } - - Return setOperationMode(OperationMode mode) override { - return mSubHal->setOperationMode(mode); - } - - Return activate(int32_t sensorHandle, bool enabled) override { - return mSubHal->activate(sensorHandle, enabled); - } - - Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) override { - return mSubHal->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); - } - - Return flush(int32_t sensorHandle) override { return mSubHal->flush(sensorHandle); } - - virtual Return injectSensorData(const Event& event) override { - return mSubHal->injectSensorData(convertToOldEvent(event)); - } - - Return registerDirectChannel(const SharedMemInfo& mem, - ISensors::registerDirectChannel_cb _hidl_cb) override { - return mSubHal->registerDirectChannel(mem, _hidl_cb); - } - - Return unregisterDirectChannel(int32_t channelHandle) override { - return mSubHal->unregisterDirectChannel(channelHandle); - } - - Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, - ISensors::configDirectReport_cb _hidl_cb) override { - return mSubHal->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); - } - - Return debug(const hidl_handle& fd, const hidl_vec& args) override { - return mSubHal->debug(fd, args); - } - - const std::string getName() override { return mSubHal->getName(); } - - protected: - T* mSubHal; -}; - -class SubHalWrapperV2_0 : public SubHalWrapperBase { - public: - SubHalWrapperV2_0(V2_0::implementation::ISensorsSubHal* subHal) : SubHalWrapperBase(subHal){}; - - Return initialize(V2_0::implementation::ISubHalCallback* callback, - V2_0::implementation::IScopedWakelockRefCounter* refCounter, - int32_t subHalIndex) override { - return mSubHal->initialize( - new V2_0::implementation::HalProxyCallbackV2_0(callback, refCounter, subHalIndex)); - } -}; - -class SubHalWrapperV2_1 : public SubHalWrapperBase { - public: - SubHalWrapperV2_1(V2_1::implementation::ISensorsSubHal* subHal) : SubHalWrapperBase(subHal) {} - - bool supportsNewEvents() override { return true; } - - virtual Return getSensorsList( - ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override { - return mSubHal->getSensorsList_2_1([&](const auto& list) { _hidl_cb(list); }); - } - - virtual Return injectSensorData(const Event& event) override { - return mSubHal->injectSensorData_2_1(event); - } - - Return initialize(V2_0::implementation::ISubHalCallback* callback, - V2_0::implementation::IScopedWakelockRefCounter* refCounter, - int32_t subHalIndex) override { - return mSubHal->initialize( - new V2_0::implementation::HalProxyCallbackV2_1(callback, refCounter, subHalIndex)); - } -}; - -} // namespace implementation -} // namespace V2_1 -} // namespace sensors -} // namespace hardware -} // namespace android diff --git a/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h b/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h index 1cc5cd5e9e..aa6d9db3d4 100644 --- a/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h +++ b/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h @@ -88,7 +88,7 @@ class ScopedWakelock { bool isLocked() const { return mLocked; } private: - friend class HalProxyCallbackBase; + friend class HalProxyCallback; IScopedWakelockRefCounter* mRefCounter; int64_t mCreatedAtTimeNs; bool mLocked; diff --git a/sensors/common/default/2.X/multihal/tests/Android.bp b/sensors/common/default/2.X/multihal/tests/Android.bp index cfd9e78a6f..7692b51de0 100644 --- a/sensors/common/default/2.X/multihal/tests/Android.bp +++ b/sensors/common/default/2.X/multihal/tests/Android.bp @@ -20,7 +20,6 @@ cc_defaults { ], header_libs: [ "android.hardware.sensors@2.0-multihal.header", - "android.hardware.sensors@2.X-shared-utils", ], export_include_dirs: ["fake_subhal"], shared_libs: [ @@ -37,7 +36,6 @@ cc_defaults { "libutils", ], static_libs: [ - "android.hardware.sensors@1.0-convert", "android.hardware.sensors@2.X-multihal", ], cflags: [ @@ -80,11 +78,7 @@ cc_test { name: "android.hardware.sensors@2.X-halproxy-unit-tests", srcs: ["HalProxy_test.cpp"], vendor: true, - header_libs: [ - "android.hardware.sensors@2.X-shared-utils", - ], static_libs: [ - "android.hardware.sensors@1.0-convert", "android.hardware.sensors@2.0-ScopedWakelock.testlib", "android.hardware.sensors@2.X-multihal", "android.hardware.sensors@2.X-fakesubhal-unittest", diff --git a/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp index ce65c3cd80..867c4a149d 100644 --- a/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp +++ b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp @@ -40,8 +40,8 @@ using ::android::hardware::sensors::V1_0::SensorType; using ::android::hardware::sensors::V2_0::EventQueueFlagBits; using ::android::hardware::sensors::V2_0::ISensorsCallback; using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; -using ::android::hardware::sensors::V2_0::implementation::HalProxyCallbackBase; -using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock; +using ::android::hardware::sensors::V2_0::implementation::HalProxy; +using ::android::hardware::sensors::V2_0::implementation::HalProxyCallback; using ::android::hardware::sensors::V2_0::subhal::implementation::AddAndRemoveDynamicSensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation:: @@ -53,7 +53,6 @@ using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensor using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation:: SetOperationModeFailingSensorsSubHal; -using ::android::hardware::sensors::V2_1::implementation::HalProxy; using EventMessageQueue = MessageQueue; using WakeupMessageQueue = MessageQueue; diff --git a/sensors/common/utils/EventMessageQueueWrapper.h b/sensors/common/utils/EventMessageQueueWrapper.h index c4f92c8386..bf3261ffbc 100644 --- a/sensors/common/utils/EventMessageQueueWrapper.h +++ b/sensors/common/utils/EventMessageQueueWrapper.h @@ -39,14 +39,8 @@ class EventMessageQueueWrapperBase : public RefBase { virtual std::atomic* getEventFlagWord() = 0; virtual size_t availableToRead() = 0; - virtual size_t availableToWrite() = 0; virtual bool read(V2_1::Event* events, size_t numToRead) = 0; - virtual bool write(const V2_1::Event* events, size_t numToWrite) = 0; virtual bool write(const std::vector& events) = 0; - virtual bool writeBlocking(const V2_1::Event* events, size_t count, uint32_t readNotification, - uint32_t writeNotification, int64_t timeOutNanos, - android::hardware::EventFlag* evFlag) = 0; - virtual size_t getQuantumCount() = 0; }; class EventMessageQueueWrapperV1_0 : public EventMessageQueueWrapperBase { @@ -66,30 +60,15 @@ class EventMessageQueueWrapperV1_0 : public EventMessageQueueWrapperBase { virtual size_t availableToRead() override { return mQueue->availableToRead(); } - size_t availableToWrite() override { return mQueue->availableToWrite(); } - virtual bool read(V2_1::Event* events, size_t numToRead) override { return mQueue->read(reinterpret_cast(events), numToRead); } - bool write(const V2_1::Event* events, size_t numToWrite) override { - return mQueue->write(reinterpret_cast(events), numToWrite); - } - virtual bool write(const std::vector& events) override { const std::vector& oldEvents = convertToOldEvents(events); return mQueue->write(oldEvents.data(), oldEvents.size()); } - bool writeBlocking(const V2_1::Event* events, size_t count, uint32_t readNotification, - uint32_t writeNotification, int64_t timeOutNanos, - android::hardware::EventFlag* evFlag) override { - return mQueue->writeBlocking(reinterpret_cast(events), count, - readNotification, writeNotification, timeOutNanos, evFlag); - } - - size_t getQuantumCount() override { return mQueue->getQuantumCount(); } - private: std::unique_ptr mQueue; }; @@ -109,29 +88,14 @@ class EventMessageQueueWrapperV2_1 : public EventMessageQueueWrapperBase { virtual size_t availableToRead() override { return mQueue->availableToRead(); } - size_t availableToWrite() override { return mQueue->availableToWrite(); } - virtual bool read(V2_1::Event* events, size_t numToRead) override { return mQueue->read(events, numToRead); } - bool write(const V2_1::Event* events, size_t numToWrite) override { - return mQueue->write(events, numToWrite); - } - bool write(const std::vector& events) override { return mQueue->write(events.data(), events.size()); } - bool writeBlocking(const V2_1::Event* events, size_t count, uint32_t readNotification, - uint32_t writeNotification, int64_t timeOutNanos, - android::hardware::EventFlag* evFlag) override { - return mQueue->writeBlocking(events, count, readNotification, writeNotification, - timeOutNanos, evFlag); - } - - size_t getQuantumCount() override { return mQueue->getQuantumCount(); } - private: std::unique_ptr mQueue; }; diff --git a/sensors/common/utils/ISensorsCallbackWrapper.h b/sensors/common/utils/ISensorsCallbackWrapper.h deleted file mode 100644 index 816b225806..0000000000 --- a/sensors/common/utils/ISensorsCallbackWrapper.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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_SENSORS_V2_1_ISENSORSCALLBACKWRAPPER_H -#define ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSCALLBACKWRAPPER_H - -#include "convertV2_1.h" - -#include "android/hardware/sensors/1.0/ISensors.h" -#include "android/hardware/sensors/1.0/types.h" -#include "android/hardware/sensors/2.0/ISensors.h" -#include "android/hardware/sensors/2.0/ISensorsCallback.h" -#include "android/hardware/sensors/2.1/ISensors.h" -#include "android/hardware/sensors/2.1/ISensorsCallback.h" -#include "android/hardware/sensors/2.1/types.h" - -#include - -#include - -namespace android { -namespace hardware { -namespace sensors { -namespace V2_1 { -namespace implementation { - -/** - * The ISensorsCallbackWrapper classes below abstract away the common logic between both the V2.0 - * and V2.1 versions of the Sensors HAL interface. This allows users of these classes to only care - * about the HAL version at init time and then interact with either version of the callback without - * worrying about the class type by utilizing the base class. - */ -class ISensorsCallbackWrapperBase : public VirtualLightRefBase { - public: - virtual Return onDynamicSensorsConnected( - const hidl_vec& sensorInfos) = 0; - - virtual Return onDynamicSensorsDisconnected(const hidl_vec& sensorHandles) = 0; -}; - -template -class SensorsCallbackWrapperBase : public ISensorsCallbackWrapperBase { - public: - SensorsCallbackWrapperBase(sp sensorsCallback) : mSensorsCallback(sensorsCallback){}; - - virtual Return onDynamicSensorsConnected( - const hidl_vec& sensorInfos) override { - return mSensorsCallback->onDynamicSensorsConnected(convertToOldSensorInfos(sensorInfos)); - } - - Return onDynamicSensorsDisconnected(const hidl_vec& sensorHandles) { - return mSensorsCallback->onDynamicSensorsDisconnected(sensorHandles); - } - - protected: - sp mSensorsCallback; -}; - -class ISensorsCallbackWrapperV2_0 - : public SensorsCallbackWrapperBase { - public: - ISensorsCallbackWrapperV2_0(sp sensorsCallback) - : SensorsCallbackWrapperBase(sensorsCallback){}; -}; - -class ISensorsCallbackWrapperV2_1 - : public SensorsCallbackWrapperBase { - public: - ISensorsCallbackWrapperV2_1(sp sensorsCallback) - : SensorsCallbackWrapperBase(sensorsCallback) {} - - Return onDynamicSensorsConnected(const hidl_vec& sensorInfos) override { - return mSensorsCallback->onDynamicSensorsConnected_2_1(sensorInfos); - } -}; - -} // namespace implementation -} // namespace V2_1 -} // namespace sensors -} // namespace hardware -} // namespace android - -#endif // ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSCALLBACKWRAPPER_H \ No newline at end of file From f809faed3c04148f90ddc08cc8d3db668d8299c8 Mon Sep 17 00:00:00 2001 From: shubang Date: Wed, 29 Apr 2020 18:16:39 -0700 Subject: [PATCH 0890/1022] Update FrontendInfo for CTS Bug: 155342902 Test: atest android.media.tv.tuner.cts.TunerFrontendTest Change-Id: Iacc0eb09499a14cbbb6cc605c91fa404361a073c --- tv/tuner/1.0/default/Tuner.cpp | 49 +++++++++++++++------------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp index b1f2490bb6..821d83f87b 100644 --- a/tv/tuner/1.0/default/Tuner.cpp +++ b/tv/tuner/1.0/default/Tuner.cpp @@ -161,34 +161,27 @@ Return Tuner::getFrontendInfo(FrontendId frontendId, getFrontendInfo_cb _h return Void(); } - switch (mFrontends[frontendId]->getFrontendType()) { - case FrontendType::DVBT: - info.type = FrontendType::DVBT; - break; - default: - vector statusCaps = { - FrontendStatusType::DEMOD_LOCK, - FrontendStatusType::SNR, - FrontendStatusType::FEC, - FrontendStatusType::MODULATION, - FrontendStatusType::PLP_ID, - FrontendStatusType::LAYER_ERROR, - FrontendStatusType::ATSC3_PLP_INFO, - }; - // assign randomly selected values for testing. - info = { - .type = mFrontends[frontendId]->getFrontendType(), - .minFrequency = 139, - .maxFrequency = 1139, - .minSymbolRate = 45, - .maxSymbolRate = 1145, - .acquireRange = 30, - .exclusiveGroupId = 57, - .statusCaps = statusCaps, - .frontendCaps = mFrontendCaps[frontendId], - }; - break; - } + vector statusCaps = { + FrontendStatusType::DEMOD_LOCK, + FrontendStatusType::SNR, + FrontendStatusType::FEC, + FrontendStatusType::MODULATION, + FrontendStatusType::PLP_ID, + FrontendStatusType::LAYER_ERROR, + FrontendStatusType::ATSC3_PLP_INFO, + }; + // assign randomly selected values for testing. + info = { + .type = mFrontends[frontendId]->getFrontendType(), + .minFrequency = 139, + .maxFrequency = 1139, + .minSymbolRate = 45, + .maxSymbolRate = 1145, + .acquireRange = 30, + .exclusiveGroupId = 57, + .statusCaps = statusCaps, + .frontendCaps = mFrontendCaps[frontendId], + }; _hidl_cb(Result::SUCCESS, info); return Void(); From c633302a86d4e90f3bdd774e9326d4ed0d429a9e Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Thu, 30 Apr 2020 15:37:29 +0800 Subject: [PATCH 0891/1022] wifi: stop running supplicant before tests The first test would always fail because it tries to use system-initiating supplicant process. Bug: 155257934 Test: atest VtsHalWifiSupplicantV1_3TargetTest Change-Id: I79b69ec04faab5e8f2af0e5e3a9b1cc4c3aa0c36 --- .../1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp | 1 + .../1.3/vts/functional/supplicant_sta_network_hidl_test.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp index 3754520eeb..40202980bc 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp @@ -64,6 +64,7 @@ class SupplicantStaIfaceHidlTest isP2pOn_ = testing::deviceSupportsFeature("android.hardware.wifi.direct"); + stopSupplicant(wifi_v1_0_instance_name_); startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_, supplicant_v1_3_instance_name_); supplicant_ = diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp index 9c40de1cb3..7603c5b914 100644 --- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp +++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp @@ -51,6 +51,8 @@ class SupplicantStaNetworkHidlTest supplicant_v1_3_instance_name_ = std::get<1>(GetParam()); isP2pOn_ = testing::deviceSupportsFeature("android.hardware.wifi.direct"); + + stopSupplicant(wifi_v1_0_instance_name_); startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_, supplicant_v1_3_instance_name_); supplicant_ = From 33acf9fb3aca402105542dc2b3dade8ce18cfbae Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Tue, 3 Mar 2020 15:32:39 -0500 Subject: [PATCH 0892/1022] V2: Set up Multi-HAL for Sensors HAL 2.1 Bug: 149758467 Test: Load onto device and verify VTS passes Test: Verify new fake subhals load properly and that unit tests pass that have been updated in this topic Change-Id: Ie73458b3447dab80f6b692e55832ef562636bfdb --- sensors/2.0/multihal/Android.bp | 8 +- sensors/2.0/multihal/service.cpp | 4 +- .../common/default/2.X/multihal/Android.bp | 5 + .../common/default/2.X/multihal/HalProxy.cpp | 207 +++++++++------- .../default/2.X/multihal/HalProxyCallback.cpp | 84 +++++++ .../default/2.X/multihal/include/HalProxy.h | 228 +++++++++++------- .../2.X/multihal/include/HalProxyCallback.h | 171 +++++++++++++ .../2.X/multihal/include/SubHalWrapper.h | 188 +++++++++++++++ .../multihal/include/V2_0/ScopedWakelock.h | 2 +- .../default/2.X/multihal/tests/Android.bp | 6 + .../2.X/multihal/tests/HalProxy_test.cpp | 5 +- .../common/utils/EventMessageQueueWrapper.h | 36 +++ .../common/utils/ISensorsCallbackWrapper.h | 96 ++++++++ 13 files changed, 857 insertions(+), 183 deletions(-) create mode 100644 sensors/common/default/2.X/multihal/HalProxyCallback.cpp create mode 100644 sensors/common/default/2.X/multihal/include/HalProxyCallback.h create mode 100644 sensors/common/default/2.X/multihal/include/SubHalWrapper.h create mode 100644 sensors/common/utils/ISensorsCallbackWrapper.h diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp index 3ce33906cc..bf51fcdbbc 100644 --- a/sensors/2.0/multihal/Android.bp +++ b/sensors/2.0/multihal/Android.bp @@ -25,6 +25,9 @@ cc_binary { ], init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"], vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"], + header_libs: [ + "android.hardware.sensors@2.X-shared-utils", + ], shared_libs: [ "android.hardware.sensors@2.0", "android.hardware.sensors@2.0-ScopedWakelock", @@ -37,5 +40,8 @@ cc_binary { "libpower", "libutils", ], - static_libs: ["android.hardware.sensors@2.X-multihal"], + static_libs: [ + "android.hardware.sensors@1.0-convert", + "android.hardware.sensors@2.X-multihal", + ], } diff --git a/sensors/2.0/multihal/service.cpp b/sensors/2.0/multihal/service.cpp index ef77048020..f50ad7e16a 100644 --- a/sensors/2.0/multihal/service.cpp +++ b/sensors/2.0/multihal/service.cpp @@ -23,12 +23,12 @@ using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; using android::hardware::sensors::V2_0::ISensors; -using android::hardware::sensors::V2_0::implementation::HalProxy; +using android::hardware::sensors::V2_1::implementation::HalProxyV2_0; int main(int /* argc */, char** /* argv */) { configureRpcThreadpool(1, true); - android::sp halProxy = new HalProxy(); + android::sp halProxy = new HalProxyV2_0(); if (halProxy->registerAsService() != ::android::OK) { ALOGE("Failed to register Sensors HAL instance"); return -1; diff --git a/sensors/common/default/2.X/multihal/Android.bp b/sensors/common/default/2.X/multihal/Android.bp index 6122323fd8..c80c47a4bf 100644 --- a/sensors/common/default/2.X/multihal/Android.bp +++ b/sensors/common/default/2.X/multihal/Android.bp @@ -17,6 +17,7 @@ cc_defaults { name: "android.hardware.sensors@2.X-multihal-defaults", header_libs: [ "android.hardware.sensors@2.X-multihal.header", + "android.hardware.sensors@2.X-shared-utils", ], shared_libs: [ "android.hardware.sensors@1.0", @@ -30,6 +31,9 @@ cc_defaults { "libpower", "libutils", ], + static_libs: [ + "android.hardware.sensors@1.0-convert", + ], cflags: ["-DLOG_TAG=\"SensorsMultiHal\""], } @@ -62,6 +66,7 @@ cc_library_static { ], srcs: [ "HalProxy.cpp", + "HalProxyCallback.cpp", ], vendor_available: true, export_header_lib_headers: [ diff --git a/sensors/common/default/2.X/multihal/HalProxy.cpp b/sensors/common/default/2.X/multihal/HalProxy.cpp index 869c0330f4..a09e9e938e 100644 --- a/sensors/common/default/2.X/multihal/HalProxy.cpp +++ b/sensors/common/default/2.X/multihal/HalProxy.cpp @@ -32,15 +32,17 @@ namespace android { namespace hardware { namespace sensors { -namespace V2_0 { +namespace V2_1 { namespace implementation { +using ::android::hardware::sensors::V1_0::Result; using ::android::hardware::sensors::V2_0::EventQueueFlagBits; using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; using ::android::hardware::sensors::V2_0::implementation::getTimeNow; using ::android::hardware::sensors::V2_0::implementation::kWakelockTimeoutNs; -typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*); +typedef V2_0::implementation::ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*); +typedef V2_1::implementation::ISensorsSubHal*(SensorsHalGetSubHalV2_1Func)(uint32_t*); static constexpr int32_t kBitsAfterSubHalIndex = 24; @@ -85,7 +87,24 @@ HalProxy::HalProxy() { init(); } -HalProxy::HalProxy(std::vector& subHalList) : mSubHalList(subHalList) { +HalProxy::HalProxy(std::vector& subHalList) { + for (ISensorsSubHalV2_0* subHal : subHalList) { + mSubHalList.push_back(std::make_unique(subHal)); + } + + init(); +} + +HalProxy::HalProxy(std::vector& subHalList, + std::vector& subHalListV2_1) { + for (ISensorsSubHalV2_0* subHal : subHalList) { + mSubHalList.push_back(std::make_unique(subHal)); + } + + for (ISensorsSubHalV2_1* subHal : subHalListV2_1) { + mSubHalList.push_back(std::make_unique(subHal)); + } + init(); } @@ -93,8 +112,8 @@ HalProxy::~HalProxy() { stopThreads(); } -Return HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) { - std::vector sensors; +Return HalProxy::getSensorsList_2_1(ISensorsV2_1::getSensorsList_2_1_cb _hidl_cb) { + std::vector sensors; for (const auto& iter : mSensors) { sensors.push_back(iter.second); } @@ -102,22 +121,31 @@ Return HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) { return Void(); } +Return HalProxy::getSensorsList(ISensorsV2_0::getSensorsList_cb _hidl_cb) { + std::vector sensors; + for (const auto& iter : mSensors) { + sensors.push_back(convertToOldSensorInfo(iter.second)); + } + _hidl_cb(sensors); + return Void(); +} + Return HalProxy::setOperationMode(OperationMode mode) { Result result = Result::OK; size_t subHalIndex; for (subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) { - ISensorsSubHal* subHal = mSubHalList[subHalIndex]; - result = subHal->setOperationMode(mode); + result = mSubHalList[subHalIndex]->setOperationMode(mode); if (result != Result::OK) { - ALOGE("setOperationMode failed for SubHal: %s", subHal->getName().c_str()); + ALOGE("setOperationMode failed for SubHal: %s", + mSubHalList[subHalIndex]->getName().c_str()); break; } } + if (result != Result::OK) { // Reset the subhal operation modes that have been flipped for (size_t i = 0; i < subHalIndex; i++) { - ISensorsSubHal* subHal = mSubHalList[i]; - subHal->setOperationMode(mCurrentOperationMode); + mSubHalList[i]->setOperationMode(mCurrentOperationMode); } } else { mCurrentOperationMode = mode; @@ -133,10 +161,42 @@ Return HalProxy::activate(int32_t sensorHandle, bool enabled) { ->activate(clearSubHalIndex(sensorHandle), enabled); } -Return HalProxy::initialize( - const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, +Return HalProxy::initialize_2_1( + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback) { + const sp& sensorsCallback) { + sp dynamicCallback = + new ISensorsCallbackWrapperV2_1(sensorsCallback); + + // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions. + auto eventQueue = + std::make_unique(eventQueueDescriptor, true /* resetPointers */); + std::unique_ptr queue = + std::make_unique(eventQueue); + + return initializeCommon(queue, wakeLockDescriptor, dynamicCallback); +} + +Return HalProxy::initialize( + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) { + sp dynamicCallback = + new ISensorsCallbackWrapperV2_0(sensorsCallback); + + // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions. + auto eventQueue = + std::make_unique(eventQueueDescriptor, true /* resetPointers */); + std::unique_ptr queue = + std::make_unique(eventQueue); + + return initializeCommon(queue, wakeLockDescriptor, dynamicCallback); +} + +Return HalProxy::initializeCommon( + std::unique_ptr& eventQueue, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) { Result result = Result::OK; stopThreads(); @@ -147,7 +207,7 @@ Return HalProxy::initialize( disableAllSensors(); // Clears the queue if any events were pending write before. - mPendingWriteEventsQueue = std::queue, size_t>>(); + mPendingWriteEventsQueue = std::queue, size_t>>(); mSizePendingWriteEventsQueue = 0; // Clears previously connected dynamic sensors @@ -156,8 +216,7 @@ Return HalProxy::initialize( mDynamicSensorsCallback = sensorsCallback; // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions. - mEventQueue = - std::make_unique(eventQueueDescriptor, true /* resetPointers */); + mEventQueue = std::move(eventQueue); // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP // events have been successfully read and handled by the framework. @@ -186,12 +245,10 @@ Return HalProxy::initialize( mWakelockThread = std::thread(startWakelockThread, this); for (size_t i = 0; i < mSubHalList.size(); i++) { - auto subHal = mSubHalList[i]; - const auto& subHalCallback = mSubHalCallbacks[i]; - Result currRes = subHal->initialize(subHalCallback); + Result currRes = mSubHalList[i]->initialize(this, this, i); if (currRes != Result::OK) { result = currRes; - ALOGE("Subhal '%s' failed to initialize.", subHal->getName().c_str()); + ALOGE("Subhal '%s' failed to initialize.", mSubHalList[i]->getName().c_str()); break; } } @@ -217,7 +274,11 @@ Return HalProxy::flush(int32_t sensorHandle) { return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle)); } -Return HalProxy::injectSensorData(const Event& event) { +Return HalProxy::injectSensorData_2_1(const V2_1::Event& event) { + return injectSensorData(convertToOldEvent(event)); +} + +Return HalProxy::injectSensorData(const V1_0::Event& event) { Result result = Result::OK; if (mCurrentOperationMode == OperationMode::NORMAL && event.sensorType != V1_0::SensorType::ADDITIONAL_INFO) { @@ -226,18 +287,19 @@ Return HalProxy::injectSensorData(const Event& event) { result = Result::BAD_VALUE; } if (result == Result::OK) { - Event subHalEvent = event; + V1_0::Event subHalEvent = event; if (!isSubHalIndexValid(event.sensorHandle)) { return Result::BAD_VALUE; } subHalEvent.sensorHandle = clearSubHalIndex(event.sensorHandle); - result = getSubHalForSensorHandle(event.sensorHandle)->injectSensorData(subHalEvent); + result = getSubHalForSensorHandle(event.sensorHandle) + ->injectSensorData(convertToNewEvent(subHalEvent)); } return result; } Return HalProxy::registerDirectChannel(const SharedMemInfo& mem, - registerDirectChannel_cb _hidl_cb) { + ISensorsV2_0::registerDirectChannel_cb _hidl_cb) { if (mDirectChannelSubHal == nullptr) { _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */); } else { @@ -257,7 +319,8 @@ Return HalProxy::unregisterDirectChannel(int32_t channelHandle) { } Return HalProxy::configDirectReport(int32_t sensorHandle, int32_t channelHandle, - RateLevel rate, configDirectReport_cb _hidl_cb) { + RateLevel rate, + ISensorsV2_0::configDirectReport_cb _hidl_cb) { if (mDirectChannelSubHal == nullptr) { _hidl_cb(Result::INVALID_OPERATION, -1 /* reportToken */); } else if (sensorHandle == -1 && rate != RateLevel::STOP) { @@ -302,7 +365,7 @@ Return HalProxy::debug(const hidl_handle& fd, const hidl_vec& stream << " # of non-dynamic sensors across all subhals: " << mSensors.size() << std::endl; stream << " # of dynamic sensors across all subhals: " << mDynamicSensors.size() << std::endl; stream << "SubHals (" << mSubHalList.size() << "):" << std::endl; - for (ISensorsSubHal* subHal : mSubHalList) { + for (auto& subHal : mSubHalList) { stream << " Name: " << subHal->getName() << std::endl; stream << " Debug dump: " << std::endl; android::base::WriteStringToFd(stream.str(), writeFd); @@ -369,20 +432,37 @@ void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) { } else { SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr = (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal"); - if (sensorsHalGetSubHalPtr == nullptr) { - ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s", - subHalLibraryFile.c_str()); - } else { + if (sensorsHalGetSubHalPtr != nullptr) { std::function sensorsHalGetSubHal = *sensorsHalGetSubHalPtr; uint32_t version; - ISensorsSubHal* subHal = sensorsHalGetSubHal(&version); + ISensorsSubHalV2_0* subHal = sensorsHalGetSubHal(&version); if (version != SUB_HAL_2_0_VERSION) { ALOGE("SubHal version was not 2.0 for library: %s", subHalLibraryFile.c_str()); } else { ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str()); - mSubHalList.push_back(subHal); + mSubHalList.push_back(std::make_unique(subHal)); + } + } else { + SensorsHalGetSubHalV2_1Func* getSubHalV2_1Ptr = + (SensorsHalGetSubHalV2_1Func*)dlsym(handle, "sensorsHalGetSubHal_2_1"); + + if (getSubHalV2_1Ptr == nullptr) { + ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s", + subHalLibraryFile.c_str()); + } else { + std::function sensorsHalGetSubHal_2_1 = + *getSubHalV2_1Ptr; + uint32_t version; + ISensorsSubHalV2_1* subHal = sensorsHalGetSubHal_2_1(&version); + if (version != SUB_HAL_2_1_VERSION) { + ALOGE("SubHal version was not 2.1 for library: %s", + subHalLibraryFile.c_str()); + } else { + ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str()); + mSubHalList.push_back(std::make_unique(subHal)); + } } } } @@ -390,36 +470,28 @@ void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) { } } -void HalProxy::initializeSubHalCallbacks() { - for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) { - sp callback = new HalProxyCallback(this, subHalIndex); - mSubHalCallbacks.push_back(callback); - } -} - void HalProxy::initializeSensorList() { for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) { - ISensorsSubHal* subHal = mSubHalList[subHalIndex]; - auto result = subHal->getSensorsList([&](const auto& list) { + auto result = mSubHalList[subHalIndex]->getSensorsList([&](const auto& list) { for (SensorInfo sensor : list) { if (!subHalIndexIsClear(sensor.sensorHandle)) { ALOGE("SubHal sensorHandle's first byte was not 0"); } else { ALOGV("Loaded sensor: %s", sensor.name.c_str()); sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex); - setDirectChannelFlags(&sensor, subHal); + setDirectChannelFlags(&sensor, mSubHalList[subHalIndex]); mSensors[sensor.sensorHandle] = sensor; } } }); if (!result.isOk()) { - ALOGE("getSensorsList call failed for SubHal: %s", subHal->getName().c_str()); + ALOGE("getSensorsList call failed for SubHal: %s", + mSubHalList[subHalIndex]->getName().c_str()); } } } void HalProxy::init() { - initializeSubHalCallbacks(); initializeSensorList(); } @@ -552,7 +624,7 @@ void HalProxy::resetSharedWakelock() { } void HalProxy::postEventsToMessageQueue(const std::vector& events, size_t numWakeupEvents, - ScopedWakelock wakelock) { + V2_0::implementation::ScopedWakelock wakelock) { size_t numToWrite = 0; std::lock_guard lock(mEventQueueWriteMutex); if (wakelock.isLocked()) { @@ -610,7 +682,8 @@ void HalProxy::decrementRefCountAndMaybeReleaseWakelock(size_t delta, } } -void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal) { +void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, + std::shared_ptr subHal) { bool sensorSupportsDirectChannel = (sensorInfo->flags & (V1_0::SensorFlagBits::MASK_DIRECT_REPORT | V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL)) != 0; @@ -624,7 +697,7 @@ void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* sub } } -ISensorsSubHal* HalProxy::getSubHalForSensorHandle(int32_t sensorHandle) { +std::shared_ptr HalProxy::getSubHalForSensorHandle(int32_t sensorHandle) { return mSubHalList[extractSubHalIndex(sensorHandle)]; } @@ -651,46 +724,8 @@ bool HalProxy::subHalIndexIsClear(int32_t sensorHandle) { return (sensorHandle & kSensorHandleSubHalIndexMask) == 0; } -void HalProxyCallback::postEvents(const std::vector& events, ScopedWakelock wakelock) { - if (events.empty() || !mHalProxy->areThreadsRunning()) return; - size_t numWakeupEvents; - std::vector processedEvents = processEvents(events, &numWakeupEvents); - if (numWakeupEvents > 0) { - ALOG_ASSERT(wakelock.isLocked(), - "Wakeup events posted while wakelock unlocked for subhal" - " w/ index %" PRId32 ".", - mSubHalIndex); - } else { - ALOG_ASSERT(!wakelock.isLocked(), - "No Wakeup events posted but wakelock locked for subhal" - " w/ index %" PRId32 ".", - mSubHalIndex); - } - mHalProxy->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock)); -} - -ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) { - ScopedWakelock wakelock(mHalProxy, lock); - return wakelock; -} - -std::vector HalProxyCallback::processEvents(const std::vector& events, - size_t* numWakeupEvents) const { - *numWakeupEvents = 0; - std::vector eventsOut; - for (Event event : events) { - event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex); - eventsOut.push_back(event); - const SensorInfo& sensor = mHalProxy->getSensorInfo(event.sensorHandle); - if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) { - (*numWakeupEvents)++; - } - } - return eventsOut; -} - } // namespace implementation -} // namespace V2_0 +} // namespace V2_1 } // namespace sensors } // namespace hardware } // namespace android diff --git a/sensors/common/default/2.X/multihal/HalProxyCallback.cpp b/sensors/common/default/2.X/multihal/HalProxyCallback.cpp new file mode 100644 index 0000000000..3c1b17c8f0 --- /dev/null +++ b/sensors/common/default/2.X/multihal/HalProxyCallback.cpp @@ -0,0 +1,84 @@ +/* + * 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. + */ + +#include "HalProxyCallback.h" + +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace implementation { + +static constexpr int32_t kBitsAfterSubHalIndex = 24; + +/** + * Set the subhal index as first byte of sensor handle and return this modified version. + * + * @param sensorHandle The sensor handle to modify. + * @param subHalIndex The index in the hal proxy of the sub hal this sensor belongs to. + * + * @return The modified sensor handle. + */ +int32_t setSubHalIndex(int32_t sensorHandle, size_t subHalIndex) { + return sensorHandle | (static_cast(subHalIndex) << kBitsAfterSubHalIndex); +} + +void HalProxyCallbackBase::postEvents(const std::vector& events, + ScopedWakelock wakelock) { + if (events.empty() || !mCallback->areThreadsRunning()) return; + size_t numWakeupEvents; + std::vector processedEvents = processEvents(events, &numWakeupEvents); + if (numWakeupEvents > 0) { + ALOG_ASSERT(wakelock.isLocked(), + "Wakeup events posted while wakelock unlocked for subhal" + " w/ index %" PRId32 ".", + mSubHalIndex); + } else { + ALOG_ASSERT(!wakelock.isLocked(), + "No Wakeup events posted but wakelock locked for subhal" + " w/ index %" PRId32 ".", + mSubHalIndex); + } + mCallback->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock)); +} + +ScopedWakelock HalProxyCallbackBase::createScopedWakelock(bool lock) { + ScopedWakelock wakelock(mRefCounter, lock); + return wakelock; +} + +std::vector HalProxyCallbackBase::processEvents(const std::vector& events, + size_t* numWakeupEvents) const { + *numWakeupEvents = 0; + std::vector eventsOut; + for (V2_1::Event event : events) { + event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex); + eventsOut.push_back(event); + const V2_1::SensorInfo& sensor = mCallback->getSensorInfo(event.sensorHandle); + if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) { + (*numWakeupEvents)++; + } + } + return eventsOut; +} + +} // namespace implementation +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android diff --git a/sensors/common/default/2.X/multihal/include/HalProxy.h b/sensors/common/default/2.X/multihal/include/HalProxy.h index d7e8795903..fb0b806bab 100644 --- a/sensors/common/default/2.X/multihal/include/HalProxy.h +++ b/sensors/common/default/2.X/multihal/include/HalProxy.h @@ -16,12 +16,17 @@ #pragma once +#include "EventMessageQueueWrapper.h" +#include "HalProxyCallback.h" +#include "ISensorsCallbackWrapper.h" +#include "SubHalWrapper.h" #include "V2_0/ScopedWakelock.h" #include "V2_0/SubHal.h" #include "V2_1/SubHal.h" +#include "convertV2_1.h" -#include -#include +#include +#include #include #include #include @@ -38,96 +43,97 @@ namespace android { namespace hardware { namespace sensors { -namespace V2_0 { +namespace V2_1 { namespace implementation { -using ::android::sp; -using ::android::hardware::EventFlag; -using ::android::hardware::hidl_string; -using ::android::hardware::hidl_vec; -using ::android::hardware::MessageQueue; -using ::android::hardware::MQDescriptor; -using ::android::hardware::Return; -using ::android::hardware::Void; - -class HalProxy : public ISensors, public IScopedWakelockRefCounter { +/** + * HalProxy is the main interface for Multi-HAL. It is responsible for managing subHALs and + * proxying function calls to/from the subHAL APIs from the sensors framework. It also manages any + * wakelocks allocated through the IHalProxyCallback and manages posting events to the sensors + * framework. + */ +class HalProxy : public V2_0::implementation::IScopedWakelockRefCounter, + public V2_0::implementation::ISubHalCallback { public: - using Event = ::android::hardware::sensors::V1_0::Event; + using Event = ::android::hardware::sensors::V2_1::Event; using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; using Result = ::android::hardware::sensors::V1_0::Result; - using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo; + using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo; using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; - using ISensorsSubHal = ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal; + using IHalProxyCallbackV2_0 = V2_0::implementation::IHalProxyCallback; + using IHalProxyCallbackV2_1 = V2_1::implementation::IHalProxyCallback; + using ISensorsSubHalV2_0 = V2_0::implementation::ISensorsSubHal; + using ISensorsSubHalV2_1 = V2_1::implementation::ISensorsSubHal; + using ISensorsV2_0 = V2_0::ISensors; + using ISensorsV2_1 = V2_1::ISensors; + using HalProxyCallbackBase = V2_0::implementation::HalProxyCallbackBase; explicit HalProxy(); // Test only constructor. - explicit HalProxy(std::vector& subHalList); + explicit HalProxy(std::vector& subHalList); + explicit HalProxy(std::vector& subHalList, + std::vector& subHalListV2_1); ~HalProxy(); + // Methods from ::android::hardware::sensors::V2_1::ISensors follow. + Return getSensorsList_2_1(ISensorsV2_1::getSensorsList_2_1_cb _hidl_cb); + + Return initialize_2_1( + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback); + + Return injectSensorData_2_1(const Event& event); + // Methods from ::android::hardware::sensors::V2_0::ISensors follow. - Return getSensorsList(getSensorsList_cb _hidl_cb) override; + Return getSensorsList(ISensorsV2_0::getSensorsList_cb _hidl_cb); - Return setOperationMode(OperationMode mode) override; + Return setOperationMode(OperationMode mode); - Return activate(int32_t sensorHandle, bool enabled) override; + Return activate(int32_t sensorHandle, bool enabled); Return initialize( - const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, - const sp& sensorsCallback) override; + const sp& sensorsCallback); + + Return initializeCommon( + std::unique_ptr& eventQueue, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback); Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) override; + int64_t maxReportLatencyNs); - Return flush(int32_t sensorHandle) override; + Return flush(int32_t sensorHandle); - Return injectSensorData(const Event& event) override; + Return injectSensorData(const V1_0::Event& event); Return registerDirectChannel(const SharedMemInfo& mem, - registerDirectChannel_cb _hidl_cb) override; + ISensorsV2_0::registerDirectChannel_cb _hidl_cb); - Return unregisterDirectChannel(int32_t channelHandle) override; + Return unregisterDirectChannel(int32_t channelHandle); Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, - configDirectReport_cb _hidl_cb) override; + ISensorsV2_0::configDirectReport_cb _hidl_cb); - Return debug(const hidl_handle& fd, const hidl_vec& args) override; + Return debug(const hidl_handle& fd, const hidl_vec& args); - // Below methods from ::android::hardware::sensors::V2_0::ISensorsCallback with a minor change - // to pass in the sub-HAL index. While the above methods are invoked from the sensors framework - // via the binder, these methods are invoked from a callback provided to sub-HALs inside the - // same process as the HalProxy, but potentially running on different threads. Return onDynamicSensorsConnected(const hidl_vec& dynamicSensorsAdded, - int32_t subHalIndex); + int32_t subHalIndex) override; Return onDynamicSensorsDisconnected(const hidl_vec& dynamicSensorHandlesRemoved, - int32_t subHalIndex); + int32_t subHalIndex) override; - // Below methods are for HalProxyCallback - - /** - * Post events to the event message queue if there is room to write them. Otherwise post the - * remaining events to a background thread for a blocking write with a kPendingWriteTimeoutNs - * timeout. - * - * @param events The list of events to post to the message queue. - * @param numWakeupEvents The number of wakeup events in events. - * @param wakelock The wakelock associated with this post of events. - */ void postEventsToMessageQueue(const std::vector& events, size_t numWakeupEvents, - ScopedWakelock wakelock); + V2_0::implementation::ScopedWakelock wakelock) override; - /** - * Get the sensor info associated with that sensorHandle. - * - * @param sensorHandle The sensor handle. - * - * @return The sensor info object in the mapping. - */ - const SensorInfo& getSensorInfo(int32_t sensorHandle) { return mSensors[sensorHandle]; } + const SensorInfo& getSensorInfo(int32_t sensorHandle) override { + return mSensors[sensorHandle]; + } - bool areThreadsRunning() { return mThreadsRun.load(); } + bool areThreadsRunning() override { return mThreadsRun.load(); } // Below methods are from IScopedWakelockRefCounter interface bool incrementRefCountAndMaybeAcquireWakelock(size_t delta, @@ -136,13 +142,14 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { void decrementRefCountAndMaybeReleaseWakelock(size_t delta, int64_t timeoutStart = -1) override; private: - using EventMessageQueue = MessageQueue; + using EventMessageQueueV2_1 = MessageQueue; + using EventMessageQueueV2_0 = MessageQueue; using WakeLockMessageQueue = MessageQueue; /** * The Event FMQ where sensor events are written */ - std::unique_ptr mEventQueue; + std::unique_ptr mEventQueue; /** * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events @@ -161,15 +168,12 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { /** * Callback to the sensors framework to inform it that new sensors have been added or removed. */ - sp mDynamicSensorsCallback; + sp mDynamicSensorsCallback; /** - * SubHal object pointers that have been saved from vendor dynamic libraries. + * SubHal objects that have been saved from vendor dynamic libraries. */ - std::vector mSubHalList; - - //! The list of subhal callbacks for each subhal where the indices correlate with mSubHalList - std::vector> mSubHalCallbacks; + std::vector> mSubHalList; /** * Map of sensor handles to SensorInfo objects that contains the sensor info from subhals as @@ -187,7 +191,7 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { OperationMode mCurrentOperationMode = OperationMode::NORMAL; //! The single subHal that supports directChannel reporting. - ISensorsSubHal* mDirectChannelSubHal = nullptr; + std::shared_ptr mDirectChannelSubHal; //! The timeout for each pending write on background thread for events. static const int64_t kPendingWriteTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */; @@ -239,9 +243,9 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { //! The refcount of how many ScopedWakelocks and pending wakeup events are active size_t mWakelockRefCount = 0; - int64_t mWakelockTimeoutStartTime = getTimeNow(); + int64_t mWakelockTimeoutStartTime = V2_0::implementation::getTimeNow(); - int64_t mWakelockTimeoutResetTime = getTimeNow(); + int64_t mWakelockTimeoutResetTime = V2_0::implementation::getTimeNow(); const char* kWakelockName = "SensorsHAL_WAKEUP"; @@ -321,7 +325,7 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { * disabled. * @param subHal The subhal pointer that the current sensorInfo object came from. */ - void setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal); + void setDirectChannelFlags(SensorInfo* sensorInfo, std::shared_ptr subHal); /* * Get the subhal pointer which can be found by indexing into the mSubHalList vector @@ -329,7 +333,7 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { * * @param sensorHandle The handle used to identify a sensor in one of the subhals. */ - ISensorsSubHal* getSubHalForSensorHandle(int32_t sensorHandle); + std::shared_ptr getSubHalForSensorHandle(int32_t sensorHandle); /** * Checks that sensorHandle's subhal index byte is within bounds of mSubHalList. @@ -368,39 +372,81 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { }; /** - * Callback class used to provide the HalProxy with the index of which subHal is invoking + * Since a newer HAL can't masquerade as a older HAL, IHalProxy enables the HalProxy to be compiled + * either for HAL 2.0 or HAL 2.1 depending on the build configuration. */ -class HalProxyCallback : public IHalProxyCallback { - using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo; - - public: - HalProxyCallback(HalProxy* halProxy, int32_t subHalIndex) - : mHalProxy(halProxy), mSubHalIndex(subHalIndex) {} - - Return onDynamicSensorsConnected( - const hidl_vec& dynamicSensorsAdded) override { - return mHalProxy->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex); +template +class IHalProxy : public HalProxy, public ISensorsVersion { + Return getSensorsList(ISensorsV2_0::getSensorsList_cb _hidl_cb) override { + return HalProxy::getSensorsList(_hidl_cb); } - Return onDynamicSensorsDisconnected( - const hidl_vec& dynamicSensorHandlesRemoved) override { - return mHalProxy->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex); + Return setOperationMode(OperationMode mode) override { + return HalProxy::setOperationMode(mode); } - void postEvents(const std::vector& events, ScopedWakelock wakelock); + Return activate(int32_t sensorHandle, bool enabled) override { + return HalProxy::activate(sensorHandle, enabled); + } - ScopedWakelock createScopedWakelock(bool lock); + Return initialize( + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) override { + return HalProxy::initialize(eventQueueDescriptor, wakeLockDescriptor, sensorsCallback); + } - private: - HalProxy* mHalProxy; - int32_t mSubHalIndex; + Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) override { + return HalProxy::batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); + } - std::vector processEvents(const std::vector& events, - size_t* numWakeupEvents) const; + Return flush(int32_t sensorHandle) override { return HalProxy::flush(sensorHandle); } + + Return injectSensorData(const V1_0::Event& event) override { + return HalProxy::injectSensorData(event); + } + + Return registerDirectChannel(const SharedMemInfo& mem, + ISensorsV2_0::registerDirectChannel_cb _hidl_cb) override { + return HalProxy::registerDirectChannel(mem, _hidl_cb); + } + + Return unregisterDirectChannel(int32_t channelHandle) override { + return HalProxy::unregisterDirectChannel(channelHandle); + } + + Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + ISensorsV2_0::configDirectReport_cb _hidl_cb) override { + return HalProxy::configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); + } + + Return debug(const hidl_handle& fd, const hidl_vec& args) override { + return HalProxy::debug(fd, args); + } +}; + +class HalProxyV2_0 : public IHalProxy {}; + +class HalProxyV2_1 : public IHalProxy { + Return getSensorsList_2_1(ISensorsV2_1::getSensorsList_2_1_cb _hidl_cb) override { + return HalProxy::getSensorsList_2_1(_hidl_cb); + } + + Return initialize_2_1( + const ::android::hardware::MQDescriptorSync& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync& wakeLockDescriptor, + const sp& sensorsCallback) override { + return HalProxy::initialize_2_1(eventQueueDescriptor, wakeLockDescriptor, sensorsCallback); + } + + Return injectSensorData_2_1(const Event& event) override { + return HalProxy::injectSensorData_2_1(event); + } }; } // namespace implementation -} // namespace V2_0 +} // namespace V2_1 } // namespace sensors } // namespace hardware } // namespace android diff --git a/sensors/common/default/2.X/multihal/include/HalProxyCallback.h b/sensors/common/default/2.X/multihal/include/HalProxyCallback.h new file mode 100644 index 0000000000..e62b7d1c00 --- /dev/null +++ b/sensors/common/default/2.X/multihal/include/HalProxyCallback.h @@ -0,0 +1,171 @@ +/* + * 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. + */ + +#pragma once + +#include "V2_0/ScopedWakelock.h" +#include "V2_0/SubHal.h" +#include "V2_1/SubHal.h" +#include "convertV2_1.h" + +#include +#include +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace implementation { + +/** + * Interface used to communicate with the HalProxy when subHals interact with their provided + * callback. + */ +class ISubHalCallback { + public: + virtual ~ISubHalCallback() {} + + // Below methods from ::android::hardware::sensors::V2_0::ISensorsCallback with a minor change + // to pass in the sub-HAL index. While the above methods are invoked from the sensors framework + // via the binder, these methods are invoked from a callback provided to sub-HALs inside the + // same process as the HalProxy, but potentially running on different threads. + virtual Return onDynamicSensorsConnected( + const hidl_vec& dynamicSensorsAdded, int32_t subHalIndex) = 0; + + virtual Return onDynamicSensorsDisconnected( + const hidl_vec& dynamicSensorHandlesRemoved, int32_t subHalIndex) = 0; + + /** + * Post events to the event message queue if there is room to write them. Otherwise post the + * remaining events to a background thread for a blocking write with a kPendingWriteTimeoutNs + * timeout. + * + * @param events The list of events to post to the message queue. + * @param numWakeupEvents The number of wakeup events in events. + * @param wakelock The wakelock associated with this post of events. + */ + virtual void postEventsToMessageQueue(const std::vector& events, + size_t numWakeupEvents, + V2_0::implementation::ScopedWakelock wakelock) = 0; + + /** + * Get the sensor info associated with that sensorHandle. + * + * @param sensorHandle The sensor handle. + * + * @return The sensor info object in the mapping. + */ + virtual const V2_1::SensorInfo& getSensorInfo(int32_t sensorHandle) = 0; + + virtual bool areThreadsRunning() = 0; +}; + +/** + * Callback class given to subhals that allows the HalProxy to know which subhal a given invocation + * is coming from. + */ +class HalProxyCallbackBase : public VirtualLightRefBase { + public: + HalProxyCallbackBase(ISubHalCallback* callback, + V2_0::implementation::IScopedWakelockRefCounter* refCounter, + int32_t subHalIndex) + : mCallback(callback), mRefCounter(refCounter), mSubHalIndex(subHalIndex) {} + + void postEvents(const std::vector& events, + V2_0::implementation::ScopedWakelock wakelock); + + V2_0::implementation::ScopedWakelock createScopedWakelock(bool lock); + + protected: + ISubHalCallback* mCallback; + V2_0::implementation::IScopedWakelockRefCounter* mRefCounter; + int32_t mSubHalIndex; + + private: + std::vector processEvents(const std::vector& events, + size_t* numWakeupEvents) const; +}; + +class HalProxyCallbackV2_0 : public HalProxyCallbackBase, + public V2_0::implementation::IHalProxyCallback { + public: + HalProxyCallbackV2_0(ISubHalCallback* callback, + V2_0::implementation::IScopedWakelockRefCounter* refCounter, + int32_t subHalIndex) + : HalProxyCallbackBase(callback, refCounter, subHalIndex) {} + + Return onDynamicSensorsConnected( + const hidl_vec& dynamicSensorsAdded) override { + return mCallback->onDynamicSensorsConnected( + V2_1::implementation::convertToNewSensorInfos(dynamicSensorsAdded), mSubHalIndex); + } + + Return onDynamicSensorsDisconnected( + const hidl_vec& dynamicSensorHandlesRemoved) override { + return mCallback->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex); + } + + void postEvents(const std::vector& events, + V2_0::implementation::ScopedWakelock wakelock) override { + HalProxyCallbackBase::postEvents(V2_1::implementation::convertToNewEvents(events), + std::move(wakelock)); + } + + V2_0::implementation::ScopedWakelock createScopedWakelock(bool lock) override { + return HalProxyCallbackBase::createScopedWakelock(lock); + } +}; + +class HalProxyCallbackV2_1 : public HalProxyCallbackBase, + public V2_1::implementation::IHalProxyCallback { + public: + HalProxyCallbackV2_1(ISubHalCallback* callback, + V2_0::implementation::IScopedWakelockRefCounter* refCounter, + int32_t subHalIndex) + : HalProxyCallbackBase(callback, refCounter, subHalIndex) {} + + Return onDynamicSensorsConnected_2_1( + const hidl_vec& dynamicSensorsAdded) override { + return mCallback->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex); + } + + Return onDynamicSensorsConnected( + const hidl_vec& /* dynamicSensorsAdded */) override { + LOG_ALWAYS_FATAL("Old dynamic sensors method can't be used"); + return Void(); + } + + Return onDynamicSensorsDisconnected( + const hidl_vec& dynamicSensorHandlesRemoved) override { + return mCallback->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex); + } + + void postEvents(const std::vector& events, + V2_0::implementation::ScopedWakelock wakelock) override { + return HalProxyCallbackBase::postEvents(events, std::move(wakelock)); + } + + V2_0::implementation::ScopedWakelock createScopedWakelock(bool lock) override { + return HalProxyCallbackBase::createScopedWakelock(lock); + } +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/sensors/common/default/2.X/multihal/include/SubHalWrapper.h b/sensors/common/default/2.X/multihal/include/SubHalWrapper.h new file mode 100644 index 0000000000..149bb5ea5b --- /dev/null +++ b/sensors/common/default/2.X/multihal/include/SubHalWrapper.h @@ -0,0 +1,188 @@ +/* + * 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. + */ + +#pragma once + +#include "HalProxyCallback.h" +#include "V2_0/SubHal.h" +#include "V2_1/SubHal.h" + +#include "android/hardware/sensors/1.0/ISensors.h" +#include "android/hardware/sensors/1.0/types.h" +#include "android/hardware/sensors/2.0/ISensors.h" +#include "android/hardware/sensors/2.0/ISensorsCallback.h" +#include "android/hardware/sensors/2.1/ISensors.h" +#include "android/hardware/sensors/2.1/ISensorsCallback.h" +#include "android/hardware/sensors/2.1/types.h" + +#include + +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_1 { +namespace implementation { + +/** + * The following subHal wrapper classes abstract away common functionality across V2.0 and V2.1 + * subHal interfaces. Much of the logic is common between the two versions and this allows users of + * the classes to only care about the type used at initialization and then interact with either + * version of the subHal interface without worrying about the type. + */ +class ISubHalWrapperBase { + protected: + using Event = ::android::hardware::sensors::V2_1::Event; + using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; + using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; + using Result = ::android::hardware::sensors::V1_0::Result; + using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo; + using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; + + public: + virtual ~ISubHalWrapperBase() {} + + virtual bool supportsNewEvents() = 0; + + virtual Return initialize(V2_0::implementation::ISubHalCallback* callback, + V2_0::implementation::IScopedWakelockRefCounter* refCounter, + int32_t subHalIndex) = 0; + + virtual Return getSensorsList( + ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) = 0; + + virtual Return setOperationMode(OperationMode mode) = 0; + + virtual Return activate(int32_t sensorHandle, bool enabled) = 0; + + virtual Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) = 0; + + virtual Return flush(int32_t sensorHandle) = 0; + + virtual Return injectSensorData(const Event& event) = 0; + + virtual Return registerDirectChannel(const SharedMemInfo& mem, + ISensors::registerDirectChannel_cb _hidl_cb) = 0; + + virtual Return unregisterDirectChannel(int32_t channelHandle) = 0; + + virtual Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, + RateLevel rate, + ISensors::configDirectReport_cb _hidl_cb) = 0; + + virtual Return debug(const hidl_handle& fd, const hidl_vec& args) = 0; + + virtual const std::string getName() = 0; +}; + +template +class SubHalWrapperBase : public ISubHalWrapperBase { + public: + SubHalWrapperBase(T* subHal) : mSubHal(subHal){}; + + virtual bool supportsNewEvents() override { return false; } + + virtual Return getSensorsList( + ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override { + return mSubHal->getSensorsList( + [&](const auto& list) { _hidl_cb(convertToNewSensorInfos(list)); }); + } + + Return setOperationMode(OperationMode mode) override { + return mSubHal->setOperationMode(mode); + } + + Return activate(int32_t sensorHandle, bool enabled) override { + return mSubHal->activate(sensorHandle, enabled); + } + + Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) override { + return mSubHal->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); + } + + Return flush(int32_t sensorHandle) override { return mSubHal->flush(sensorHandle); } + + virtual Return injectSensorData(const Event& event) override { + return mSubHal->injectSensorData(convertToOldEvent(event)); + } + + Return registerDirectChannel(const SharedMemInfo& mem, + ISensors::registerDirectChannel_cb _hidl_cb) override { + return mSubHal->registerDirectChannel(mem, _hidl_cb); + } + + Return unregisterDirectChannel(int32_t channelHandle) override { + return mSubHal->unregisterDirectChannel(channelHandle); + } + + Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + ISensors::configDirectReport_cb _hidl_cb) override { + return mSubHal->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); + } + + Return debug(const hidl_handle& fd, const hidl_vec& args) override { + return mSubHal->debug(fd, args); + } + + const std::string getName() override { return mSubHal->getName(); } + + protected: + T* mSubHal; +}; + +class SubHalWrapperV2_0 : public SubHalWrapperBase { + public: + SubHalWrapperV2_0(V2_0::implementation::ISensorsSubHal* subHal) : SubHalWrapperBase(subHal){}; + + Return initialize(V2_0::implementation::ISubHalCallback* callback, + V2_0::implementation::IScopedWakelockRefCounter* refCounter, + int32_t subHalIndex) override { + return mSubHal->initialize( + new V2_0::implementation::HalProxyCallbackV2_0(callback, refCounter, subHalIndex)); + } +}; + +class SubHalWrapperV2_1 : public SubHalWrapperBase { + public: + SubHalWrapperV2_1(V2_1::implementation::ISensorsSubHal* subHal) : SubHalWrapperBase(subHal) {} + + bool supportsNewEvents() override { return true; } + + virtual Return getSensorsList( + ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override { + return mSubHal->getSensorsList_2_1([&](const auto& list) { _hidl_cb(list); }); + } + + virtual Return injectSensorData(const Event& event) override { + return mSubHal->injectSensorData_2_1(event); + } + + Return initialize(V2_0::implementation::ISubHalCallback* callback, + V2_0::implementation::IScopedWakelockRefCounter* refCounter, + int32_t subHalIndex) override { + return mSubHal->initialize( + new V2_0::implementation::HalProxyCallbackV2_1(callback, refCounter, subHalIndex)); + } +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace sensors +} // namespace hardware +} // namespace android diff --git a/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h b/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h index aa6d9db3d4..1cc5cd5e9e 100644 --- a/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h +++ b/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h @@ -88,7 +88,7 @@ class ScopedWakelock { bool isLocked() const { return mLocked; } private: - friend class HalProxyCallback; + friend class HalProxyCallbackBase; IScopedWakelockRefCounter* mRefCounter; int64_t mCreatedAtTimeNs; bool mLocked; diff --git a/sensors/common/default/2.X/multihal/tests/Android.bp b/sensors/common/default/2.X/multihal/tests/Android.bp index e0b3b8d3d0..0dfbd498ec 100644 --- a/sensors/common/default/2.X/multihal/tests/Android.bp +++ b/sensors/common/default/2.X/multihal/tests/Android.bp @@ -20,6 +20,7 @@ cc_defaults { ], header_libs: [ "android.hardware.sensors@2.0-multihal.header", + "android.hardware.sensors@2.X-shared-utils", ], export_include_dirs: ["fake_subhal"], shared_libs: [ @@ -36,6 +37,7 @@ cc_defaults { "libutils", ], static_libs: [ + "android.hardware.sensors@1.0-convert", "android.hardware.sensors@2.X-multihal", ], cflags: [ @@ -78,7 +80,11 @@ cc_test { name: "android.hardware.sensors@2.X-halproxy-unit-tests", srcs: ["HalProxy_test.cpp"], vendor: true, + header_libs: [ + "android.hardware.sensors@2.X-shared-utils", + ], static_libs: [ + "android.hardware.sensors@1.0-convert", "android.hardware.sensors@2.0-ScopedWakelock.testlib", "android.hardware.sensors@2.X-multihal", "android.hardware.sensors@2.X-fakesubhal-unittest", diff --git a/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp index 867c4a149d..ce65c3cd80 100644 --- a/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp +++ b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp @@ -40,8 +40,8 @@ using ::android::hardware::sensors::V1_0::SensorType; using ::android::hardware::sensors::V2_0::EventQueueFlagBits; using ::android::hardware::sensors::V2_0::ISensorsCallback; using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; -using ::android::hardware::sensors::V2_0::implementation::HalProxy; -using ::android::hardware::sensors::V2_0::implementation::HalProxyCallback; +using ::android::hardware::sensors::V2_0::implementation::HalProxyCallbackBase; +using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock; using ::android::hardware::sensors::V2_0::subhal::implementation::AddAndRemoveDynamicSensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation:: @@ -53,6 +53,7 @@ using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensor using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal; using ::android::hardware::sensors::V2_0::subhal::implementation:: SetOperationModeFailingSensorsSubHal; +using ::android::hardware::sensors::V2_1::implementation::HalProxy; using EventMessageQueue = MessageQueue; using WakeupMessageQueue = MessageQueue; diff --git a/sensors/common/utils/EventMessageQueueWrapper.h b/sensors/common/utils/EventMessageQueueWrapper.h index bf3261ffbc..c4f92c8386 100644 --- a/sensors/common/utils/EventMessageQueueWrapper.h +++ b/sensors/common/utils/EventMessageQueueWrapper.h @@ -39,8 +39,14 @@ class EventMessageQueueWrapperBase : public RefBase { virtual std::atomic* getEventFlagWord() = 0; virtual size_t availableToRead() = 0; + virtual size_t availableToWrite() = 0; virtual bool read(V2_1::Event* events, size_t numToRead) = 0; + virtual bool write(const V2_1::Event* events, size_t numToWrite) = 0; virtual bool write(const std::vector& events) = 0; + virtual bool writeBlocking(const V2_1::Event* events, size_t count, uint32_t readNotification, + uint32_t writeNotification, int64_t timeOutNanos, + android::hardware::EventFlag* evFlag) = 0; + virtual size_t getQuantumCount() = 0; }; class EventMessageQueueWrapperV1_0 : public EventMessageQueueWrapperBase { @@ -60,15 +66,30 @@ class EventMessageQueueWrapperV1_0 : public EventMessageQueueWrapperBase { virtual size_t availableToRead() override { return mQueue->availableToRead(); } + size_t availableToWrite() override { return mQueue->availableToWrite(); } + virtual bool read(V2_1::Event* events, size_t numToRead) override { return mQueue->read(reinterpret_cast(events), numToRead); } + bool write(const V2_1::Event* events, size_t numToWrite) override { + return mQueue->write(reinterpret_cast(events), numToWrite); + } + virtual bool write(const std::vector& events) override { const std::vector& oldEvents = convertToOldEvents(events); return mQueue->write(oldEvents.data(), oldEvents.size()); } + bool writeBlocking(const V2_1::Event* events, size_t count, uint32_t readNotification, + uint32_t writeNotification, int64_t timeOutNanos, + android::hardware::EventFlag* evFlag) override { + return mQueue->writeBlocking(reinterpret_cast(events), count, + readNotification, writeNotification, timeOutNanos, evFlag); + } + + size_t getQuantumCount() override { return mQueue->getQuantumCount(); } + private: std::unique_ptr mQueue; }; @@ -88,14 +109,29 @@ class EventMessageQueueWrapperV2_1 : public EventMessageQueueWrapperBase { virtual size_t availableToRead() override { return mQueue->availableToRead(); } + size_t availableToWrite() override { return mQueue->availableToWrite(); } + virtual bool read(V2_1::Event* events, size_t numToRead) override { return mQueue->read(events, numToRead); } + bool write(const V2_1::Event* events, size_t numToWrite) override { + return mQueue->write(events, numToWrite); + } + bool write(const std::vector& events) override { return mQueue->write(events.data(), events.size()); } + bool writeBlocking(const V2_1::Event* events, size_t count, uint32_t readNotification, + uint32_t writeNotification, int64_t timeOutNanos, + android::hardware::EventFlag* evFlag) override { + return mQueue->writeBlocking(events, count, readNotification, writeNotification, + timeOutNanos, evFlag); + } + + size_t getQuantumCount() override { return mQueue->getQuantumCount(); } + private: std::unique_ptr mQueue; }; diff --git a/sensors/common/utils/ISensorsCallbackWrapper.h b/sensors/common/utils/ISensorsCallbackWrapper.h new file mode 100644 index 0000000000..816b225806 --- /dev/null +++ b/sensors/common/utils/ISensorsCallbackWrapper.h @@ -0,0 +1,96 @@ +/* + * 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_SENSORS_V2_1_ISENSORSCALLBACKWRAPPER_H +#define ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSCALLBACKWRAPPER_H + +#include "convertV2_1.h" + +#include "android/hardware/sensors/1.0/ISensors.h" +#include "android/hardware/sensors/1.0/types.h" +#include "android/hardware/sensors/2.0/ISensors.h" +#include "android/hardware/sensors/2.0/ISensorsCallback.h" +#include "android/hardware/sensors/2.1/ISensors.h" +#include "android/hardware/sensors/2.1/ISensorsCallback.h" +#include "android/hardware/sensors/2.1/types.h" + +#include + +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_1 { +namespace implementation { + +/** + * The ISensorsCallbackWrapper classes below abstract away the common logic between both the V2.0 + * and V2.1 versions of the Sensors HAL interface. This allows users of these classes to only care + * about the HAL version at init time and then interact with either version of the callback without + * worrying about the class type by utilizing the base class. + */ +class ISensorsCallbackWrapperBase : public VirtualLightRefBase { + public: + virtual Return onDynamicSensorsConnected( + const hidl_vec& sensorInfos) = 0; + + virtual Return onDynamicSensorsDisconnected(const hidl_vec& sensorHandles) = 0; +}; + +template +class SensorsCallbackWrapperBase : public ISensorsCallbackWrapperBase { + public: + SensorsCallbackWrapperBase(sp sensorsCallback) : mSensorsCallback(sensorsCallback){}; + + virtual Return onDynamicSensorsConnected( + const hidl_vec& sensorInfos) override { + return mSensorsCallback->onDynamicSensorsConnected(convertToOldSensorInfos(sensorInfos)); + } + + Return onDynamicSensorsDisconnected(const hidl_vec& sensorHandles) { + return mSensorsCallback->onDynamicSensorsDisconnected(sensorHandles); + } + + protected: + sp mSensorsCallback; +}; + +class ISensorsCallbackWrapperV2_0 + : public SensorsCallbackWrapperBase { + public: + ISensorsCallbackWrapperV2_0(sp sensorsCallback) + : SensorsCallbackWrapperBase(sensorsCallback){}; +}; + +class ISensorsCallbackWrapperV2_1 + : public SensorsCallbackWrapperBase { + public: + ISensorsCallbackWrapperV2_1(sp sensorsCallback) + : SensorsCallbackWrapperBase(sensorsCallback) {} + + Return onDynamicSensorsConnected(const hidl_vec& sensorInfos) override { + return mSensorsCallback->onDynamicSensorsConnected_2_1(sensorInfos); + } +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace sensors +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSCALLBACKWRAPPER_H \ No newline at end of file From 199b5ff96aba15718ee0e1e8f8af9642fc6fff8d Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Tue, 28 Apr 2020 12:03:18 -0400 Subject: [PATCH 0893/1022] V2: Create Multi-HAL 2.1 service Bug: 149758467 Test: Verify that the new unit tests and subhals in this topic load and run on a Pixel device Change-Id: I275274659816b3a00374fb0b7a93f199874afdcd --- sensors/2.1/multihal/Android.bp | 47 +++++++++++++++++++ sensors/2.1/multihal/OWNERS | 3 ++ .../android.hardware.sensors@2.1-multihal.xml | 11 +++++ ...d.hardware.sensors@2.1-service-multihal.rc | 7 +++ sensors/2.1/multihal/service.cpp | 39 +++++++++++++++ 5 files changed, 107 insertions(+) create mode 100644 sensors/2.1/multihal/Android.bp create mode 100644 sensors/2.1/multihal/OWNERS create mode 100644 sensors/2.1/multihal/android.hardware.sensors@2.1-multihal.xml create mode 100644 sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc create mode 100644 sensors/2.1/multihal/service.cpp diff --git a/sensors/2.1/multihal/Android.bp b/sensors/2.1/multihal/Android.bp new file mode 100644 index 0000000000..6a7cac9f25 --- /dev/null +++ b/sensors/2.1/multihal/Android.bp @@ -0,0 +1,47 @@ +// +// 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. + +cc_binary { + name: "android.hardware.sensors@2.1-service.multihal", + defaults: [ + "hidl_defaults", + ], + vendor: true, + relative_install_path: "hw", + srcs: [ + "service.cpp", + ], + init_rc: ["android.hardware.sensors@2.1-service-multihal.rc"], + vintf_fragments: ["android.hardware.sensors@2.1-multihal.xml"], + header_libs: [ + "android.hardware.sensors@2.X-shared-utils", + ], + shared_libs: [ + "android.hardware.sensors@2.0", + "android.hardware.sensors@2.0-ScopedWakelock", + "android.hardware.sensors@2.1", + "libbase", + "libcutils", + "libfmq", + "libhidlbase", + "liblog", + "libpower", + "libutils", + ], + static_libs: [ + "android.hardware.sensors@1.0-convert", + "android.hardware.sensors@2.X-multihal", + ], +} diff --git a/sensors/2.1/multihal/OWNERS b/sensors/2.1/multihal/OWNERS new file mode 100644 index 0000000000..e9556700d6 --- /dev/null +++ b/sensors/2.1/multihal/OWNERS @@ -0,0 +1,3 @@ +arthuri@google.com +bduddie@google.com +stange@google.com \ No newline at end of file diff --git a/sensors/2.1/multihal/android.hardware.sensors@2.1-multihal.xml b/sensors/2.1/multihal/android.hardware.sensors@2.1-multihal.xml new file mode 100644 index 0000000000..18bd3ae83b --- /dev/null +++ b/sensors/2.1/multihal/android.hardware.sensors@2.1-multihal.xml @@ -0,0 +1,11 @@ + + + android.hardware.sensors + hwbinder + 2.1 + + ISensors + default + + + diff --git a/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc b/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc new file mode 100644 index 0000000000..fc99ee7a06 --- /dev/null +++ b/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc @@ -0,0 +1,7 @@ +service vendor.sensors-hal-2-1-multihal /vendor/bin/hw/android.hardware.sensors@2.1-service.multihal + class hal + user system + group system wakelock context_hub + writepid /dev/cpuset/system-background/tasks + capabilities BLOCK_SUSPEND + rlimit rtprio 10 10 diff --git a/sensors/2.1/multihal/service.cpp b/sensors/2.1/multihal/service.cpp new file mode 100644 index 0000000000..d68d9a3e73 --- /dev/null +++ b/sensors/2.1/multihal/service.cpp @@ -0,0 +1,39 @@ +/* + * 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 +#include +#include +#include "HalProxy.h" + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::sensors::V2_1::ISensors; +using android::hardware::sensors::V2_1::implementation::HalProxyV2_1; + +int main(int /* argc */, char** /* argv */) { + configureRpcThreadpool(1, true); + + android::sp halProxy = new HalProxyV2_1(); + if (halProxy->registerAsService() != ::android::OK) { + ALOGE("Failed to register Sensors HAL instance"); + return -1; + } + + joinRpcThreadpool(); + return 1; // joinRpcThreadpool shouldn't exit +} From 7a21c53268b7bee5326f5b8fa70dd6cb714d1426 Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Tue, 28 Apr 2020 15:12:41 -0400 Subject: [PATCH 0894/1022] V2: Update tests for multihal to test HAL 2.1 Updates tests and fake subhals to support Multi-HAL 2.1 to make on-device testing feasible. Bug: 149758467 Test: Verify that the new unit tests and subhals in this topic load and run on a Pixel device Change-Id: I7a9d7c1678826bb1956119e8b76f591c7bc213e1 --- .../default/2.X/multihal/tests/Android.bp | 12 + .../2.X/multihal/tests/HalProxy_test.cpp | 331 +++++++++++------- .../fake_subhal/IHalProxyCallbackWrapper.h | 107 ++++++ .../2.X/multihal/tests/fake_subhal/Sensor.cpp | 9 +- .../2.X/multihal/tests/fake_subhal/Sensor.h | 12 +- .../tests/fake_subhal/SensorsSubHal.cpp | 120 ++++--- .../tests/fake_subhal/SensorsSubHal.h | 173 +++++++-- 7 files changed, 531 insertions(+), 233 deletions(-) create mode 100644 sensors/common/default/2.X/multihal/tests/fake_subhal/IHalProxyCallbackWrapper.h diff --git a/sensors/common/default/2.X/multihal/tests/Android.bp b/sensors/common/default/2.X/multihal/tests/Android.bp index 0dfbd498ec..a15faed1ef 100644 --- a/sensors/common/default/2.X/multihal/tests/Android.bp +++ b/sensors/common/default/2.X/multihal/tests/Android.bp @@ -50,6 +50,7 @@ cc_library { vendor: true, defaults: ["android.hardware.sensors@2.X-fakesubhal-defaults"], cflags: [ + "-DSUB_HAL_VERSION_2_0", "-DSUPPORT_CONTINUOUS_SENSORS", "-DSUB_HAL_NAME=\"FakeSubHal-Continuous\"", ], @@ -59,6 +60,17 @@ cc_library { name: "android.hardware.sensors@2.X-fakesubhal-config2", vendor: true, defaults: ["android.hardware.sensors@2.X-fakesubhal-defaults"], + cflags: [ + "-DSUB_HAL_VERSION_2_0", + "-DSUPPORT_ON_CHANGE_SENSORS", + "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"", + ], +} + +cc_library { + name: "android.hardware.sensors@2.X-fakesubhal-config3", + vendor: true, + defaults: ["android.hardware.sensors@2.X-fakesubhal-defaults"], cflags: [ "-DSUPPORT_ON_CHANGE_SENSORS", "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"", diff --git a/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp index ce65c3cd80..858786af09 100644 --- a/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp +++ b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp @@ -15,12 +15,15 @@ #include +#include #include +#include #include #include "HalProxy.h" #include "SensorsSubHal.h" #include "V2_0/ScopedWakelock.h" +#include "convertV2_1.h" #include #include @@ -38,28 +41,35 @@ using ::android::hardware::sensors::V1_0::SensorFlagBits; using ::android::hardware::sensors::V1_0::SensorInfo; using ::android::hardware::sensors::V1_0::SensorType; using ::android::hardware::sensors::V2_0::EventQueueFlagBits; -using ::android::hardware::sensors::V2_0::ISensorsCallback; using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; using ::android::hardware::sensors::V2_0::implementation::HalProxyCallbackBase; using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock; -using ::android::hardware::sensors::V2_0::subhal::implementation::AddAndRemoveDynamicSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation:: - AllSupportDirectChannelSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation:: - DoesNotSupportDirectChannelSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal; -using ::android::hardware::sensors::V2_0::subhal::implementation:: - SetOperationModeFailingSensorsSubHal; +using ::android::hardware::sensors::V2_1::implementation::convertToNewEvents; +using ::android::hardware::sensors::V2_1::implementation::convertToNewSensorInfos; using ::android::hardware::sensors::V2_1::implementation::HalProxy; +using ::android::hardware::sensors::V2_1::subhal::implementation::AddAndRemoveDynamicSensorsSubHal; +using ::android::hardware::sensors::V2_1::subhal::implementation::AllSensorsSubHal; +using ::android::hardware::sensors::V2_1::subhal::implementation:: + AllSupportDirectChannelSensorsSubHal; +using ::android::hardware::sensors::V2_1::subhal::implementation::ContinuousSensorsSubHal; +using ::android::hardware::sensors::V2_1::subhal::implementation:: + DoesNotSupportDirectChannelSensorsSubHal; +using ::android::hardware::sensors::V2_1::subhal::implementation::OnChangeSensorsSubHal; +using ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0; +using ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1; +using ::android::hardware::sensors::V2_1::subhal::implementation:: + SetOperationModeFailingSensorsSubHal; -using EventMessageQueue = MessageQueue; +using ISensorsCallbackV2_0 = ::android::hardware::sensors::V2_0::ISensorsCallback; +using ISensorsCallbackV2_1 = ::android::hardware::sensors::V2_1::ISensorsCallback; +using EventV1_0 = ::android::hardware::sensors::V1_0::Event; +using EventV2_1 = ::android::hardware::sensors::V2_1::Event; +using EventMessageQueueV2_1 = MessageQueue; +using EventMessageQueueV2_0 = MessageQueue; using WakeupMessageQueue = MessageQueue; // The barebones sensors callback class passed into halproxy initialize calls -class SensorsCallback : public ISensorsCallback { +class SensorsCallback : public ISensorsCallbackV2_0 { public: Return onDynamicSensorsConnected( const hidl_vec& /*dynamicSensorsAdded*/) override { @@ -74,8 +84,30 @@ class SensorsCallback : public ISensorsCallback { } }; +class SensorsCallbackV2_1 : public ISensorsCallbackV2_1 { + public: + Return onDynamicSensorsConnected_2_1( + const hidl_vec<::android::hardware::sensors::V2_1::SensorInfo>& /*dynamicSensorsAdded*/) + override { + // Nothing yet + return Return(); + } + + Return onDynamicSensorsConnected( + const hidl_vec& /*dynamicSensorsAdded*/) override { + // Nothing yet + return Return(); + } + + Return onDynamicSensorsDisconnected( + const hidl_vec& /*dynamicSensorHandlesRemoved*/) override { + // Nothing yet + return Return(); + } +}; + // The sensors callback that expects a variable list of sensors to be added -class TestSensorsCallback : public ISensorsCallback { +class TestSensorsCallback : public ISensorsCallbackV2_0 { public: Return onDynamicSensorsConnected( const hidl_vec& dynamicSensorsAdded) override { @@ -130,10 +162,10 @@ void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector& wakelockQueue, EventFlag* wakelockQueueFlag); -bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& eventQueue, +bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& eventQueue, EventFlag* eventQueueFlag); -std::unique_ptr makeEventFMQ(size_t size); +std::unique_ptr makeEventFMQ(size_t size); std::unique_ptr makeWakelockFMQ(size_t size); @@ -143,7 +175,7 @@ std::unique_ptr makeWakelockFMQ(size_t size); * * @return A proximity event. */ -Event makeProximityEvent(); +EventV1_0 makeProximityEvent(); /** * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor @@ -151,7 +183,7 @@ Event makeProximityEvent(); * * @return A proximity event. */ -Event makeAccelerometerEvent(); +EventV1_0 makeAccelerometerEvent(); /** * Make a certain number of proximity type events with the sensorHandle field set to @@ -161,7 +193,7 @@ Event makeAccelerometerEvent(); * * @return The created list of events. */ -std::vector makeMultipleProximityEvents(size_t numEvents); +std::vector makeMultipleProximityEvents(size_t numEvents); /** * Make a certain number of accelerometer type events with the sensorHandle field set to @@ -171,7 +203,7 @@ std::vector makeMultipleProximityEvents(size_t numEvents); * * @return The created list of events. */ -std::vector makeMultipleAccelerometerEvents(size_t numEvents); +std::vector makeMultipleAccelerometerEvents(size_t numEvents); /** * Given a SensorInfo vector and a sensor handles vector populate 'sensors' with SensorInfo @@ -189,7 +221,7 @@ void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size, // Tests follow TEST(HalProxyTest, GetSensorsListOneSubHalTest) { - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector fakeSubHals{&subHal}; HalProxy proxy(fakeSubHals); @@ -201,8 +233,8 @@ TEST(HalProxyTest, GetSensorsListOneSubHalTest) { } TEST(HalProxyTest, GetSensorsListTwoSubHalTest) { - ContinuousSensorsSubHal continuousSubHal; - OnChangeSensorsSubHal onChangeSubHal; + ContinuousSensorsSubHal continuousSubHal; + OnChangeSensorsSubHal onChangeSubHal; std::vector fakeSubHals; fakeSubHals.push_back(&continuousSubHal); fakeSubHals.push_back(&onChangeSubHal); @@ -222,8 +254,8 @@ TEST(HalProxyTest, GetSensorsListTwoSubHalTest) { } TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) { - ContinuousSensorsSubHal subHal1; - OnChangeSensorsSubHal subHal2; + ContinuousSensorsSubHal subHal1; + OnChangeSensorsSubHal subHal2; std::vector fakeSubHals{&subHal1, &subHal2}; HalProxy proxy(fakeSubHals); @@ -239,7 +271,7 @@ TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) { } TEST(HalProxyTest, SetOperationModeTwoSubHalFailTest) { - AllSensorsSubHal subHal1; + AllSensorsSubHal subHal1; SetOperationModeFailingSensorsSubHal subHal2; std::vector fakeSubHals{&subHal1, &subHal2}; @@ -280,16 +312,16 @@ TEST(HalProxyTest, InitDirectChannelThreeSubHalsUnitTest) { TEST(HalProxyTest, PostSingleNonWakeupEvent) { constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events{makeAccelerometerEvent()}; - subHal.postEvents(events, false /* wakeup */); + std::vector events{makeAccelerometerEvent()}; + subHal.postEvents(convertToNewEvents(events), false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), 1); } @@ -297,28 +329,28 @@ TEST(HalProxyTest, PostSingleNonWakeupEvent) { TEST(HalProxyTest, PostMultipleNonWakeupEvent) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 3; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal.postEvents(events, false /* wakeup */); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal.postEvents(convertToNewEvents(events), false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); } TEST(HalProxyTest, PostSingleWakeupEvent) { constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); EventFlag* eventQueueFlag; @@ -327,8 +359,8 @@ TEST(HalProxyTest, PostSingleWakeupEvent) { EventFlag* wakelockQueueFlag; EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag); - std::vector events{makeProximityEvent()}; - subHal.postEvents(events, true /* wakeup */); + std::vector events{makeProximityEvent()}; + subHal.postEvents(convertToNewEvents(events), true /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), 1); @@ -339,12 +371,12 @@ TEST(HalProxyTest, PostSingleWakeupEvent) { TEST(HalProxyTest, PostMultipleWakeupEvents) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 3; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); EventFlag* eventQueueFlag; @@ -353,8 +385,8 @@ TEST(HalProxyTest, PostMultipleWakeupEvents) { EventFlag* wakelockQueueFlag; EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag); - std::vector events = makeMultipleProximityEvents(kNumEvents); - subHal.postEvents(events, true /* wakeup */); + std::vector events = makeMultipleProximityEvents(kNumEvents); + subHal.postEvents(convertToNewEvents(events), true /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); @@ -365,20 +397,20 @@ TEST(HalProxyTest, PostMultipleWakeupEvents) { TEST(HalProxyTest, PostEventsMultipleSubhals) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 2; - AllSensorsSubHal subHal1, subHal2; + AllSensorsSubHal subHal1, subHal2; std::vector subHals{&subHal1, &subHal2}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal1.postEvents(events, false /* wakeup */); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal1.postEvents(convertToNewEvents(events), false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kNumEvents); - subHal2.postEvents(events, false /* wakeup */); + subHal2.postEvents(convertToNewEvents(events), false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2); } @@ -386,19 +418,19 @@ TEST(HalProxyTest, PostEventsMultipleSubhals) { TEST(HalProxyTest, PostEventsDelayedWrite) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 6; - AllSensorsSubHal subHal1, subHal2; + AllSensorsSubHal subHal1, subHal2; std::vector subHals{&subHal1, &subHal2}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); EventFlag* eventQueueFlag; EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal1.postEvents(events, false /* wakeup */); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal1.postEvents(convertToNewEvents(events), false /* wakeup */); EXPECT_EQ(eventQueue->availableToRead(), kQueueSize); @@ -414,18 +446,20 @@ TEST(HalProxyTest, PostEventsDelayedWrite) { TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 2; - AllSensorsSubHal subHal1, subHal2; + AllSensorsSubHal subHal1, subHal2; std::vector subHals{&subHal1, &subHal2}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, events, false); - std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, events, false); + std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, + convertToNewEvents(events), false); + std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, + convertToNewEvents(events), false); t1.join(); t2.join(); @@ -436,34 +470,34 @@ TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) { TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThread) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 6; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal.postEvents(events, false /* wakeup */); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal.postEvents(convertToNewEvents(events), false /* wakeup */); // Destructing HalProxy object with events on the background thread } TEST(HalProxyTest, DestructingWithUnackedWakeupEventsPosted) { constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events{makeProximityEvent()}; - subHal.postEvents(events, true /* wakeup */); + std::vector events{makeProximityEvent()}; + subHal.postEvents(convertToNewEvents(events), true /* wakeup */); // Not sending any acks back through wakeLockQueue @@ -473,17 +507,17 @@ TEST(HalProxyTest, DestructingWithUnackedWakeupEventsPosted) { TEST(HalProxyTest, ReinitializeWithEventsPendingOnBackgroundThread) { constexpr size_t kQueueSize = 5; constexpr size_t kNumEvents = 10; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events = makeMultipleAccelerometerEvents(kNumEvents); - subHal.postEvents(events, false /* wakeup */); + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + subHal.postEvents(convertToNewEvents(events), false /* wakeup */); eventQueue = makeEventFMQ(kQueueSize); wakeLockQueue = makeWakelockFMQ(kQueueSize); @@ -493,23 +527,23 @@ TEST(HalProxyTest, ReinitializeWithEventsPendingOnBackgroundThread) { EXPECT_EQ(secondInitResult, Result::OK); // Small sleep so that pending writes thread has a change to hit writeBlocking call. std::this_thread::sleep_for(std::chrono::milliseconds(5)); - Event eventOut; + EventV1_0 eventOut; EXPECT_FALSE(eventQueue->read(&eventOut)); } TEST(HalProxyTest, ReinitializingWithUnackedWakeupEventsPosted) { constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - std::vector events{makeProximityEvent()}; - subHal.postEvents(events, true /* wakeup */); + std::vector events{makeProximityEvent()}; + subHal.postEvents(convertToNewEvents(events), true /* wakeup */); // Not sending any acks back through wakeLockQueue @@ -524,12 +558,12 @@ TEST(HalProxyTest, ReinitializingWithUnackedWakeupEventsPosted) { TEST(HalProxyTest, InitializeManyTimesInARow) { constexpr size_t kQueueSize = 5; constexpr size_t kNumTimesToInit = 100; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); for (size_t i = 0; i < kNumTimesToInit; i++) { @@ -541,15 +575,15 @@ TEST(HalProxyTest, InitializeManyTimesInARow) { TEST(HalProxyTest, OperationModeResetOnInitialize) { constexpr size_t kQueueSize = 5; - AllSensorsSubHal subHal; + AllSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.setOperationMode(OperationMode::DATA_INJECTION); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); - Event event = makeAccelerometerEvent(); + EventV1_0 event = makeAccelerometerEvent(); // Should not be able to inject a non AdditionInfo type event because operation mode should // have been reset to NORMAL EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE); @@ -560,7 +594,7 @@ TEST(HalProxyTest, DynamicSensorsDiscardedOnInitialize) { constexpr size_t kNumSensors = 5; AddAndRemoveDynamicSensorsSubHal subHal; std::vector subHals{&subHal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); HalProxy proxy(subHals); @@ -575,9 +609,9 @@ TEST(HalProxyTest, DynamicSensorsDiscardedOnInitialize) { } TestSensorsCallback* callback = new TestSensorsCallback(); - ::android::sp callbackPtr = callback; + ::android::sp callbackPtr = callback; proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); - subHal.addDynamicSensors(sensorsToConnect); + subHal.addDynamicSensors(convertToNewSensorInfos(sensorsToConnect)); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove); @@ -594,7 +628,7 @@ TEST(HalProxyTest, DynamicSensorsConnectedTest) { AddAndRemoveDynamicSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(0); + std::unique_ptr eventQueue = makeEventFMQ(0); std::unique_ptr wakeLockQueue = makeWakelockFMQ(0); std::vector sensorsToConnect; @@ -603,9 +637,9 @@ TEST(HalProxyTest, DynamicSensorsConnectedTest) { sensorHandlesToExpect); TestSensorsCallback* callback = new TestSensorsCallback(); - ::android::sp callbackPtr = callback; + ::android::sp callbackPtr = callback; proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); - subHal.addDynamicSensors(sensorsToConnect); + subHal.addDynamicSensors(convertToNewSensorInfos(sensorsToConnect)); std::vector sensorsSeen = callback->getSensorsConnected(); EXPECT_EQ(kNumSensors, sensorsSeen.size()); @@ -622,7 +656,7 @@ TEST(HalProxyTest, DynamicSensorsDisconnectedTest) { AddAndRemoveDynamicSensorsSubHal subHal; std::vector subHals{&subHal}; HalProxy proxy(subHals); - std::unique_ptr eventQueue = makeEventFMQ(0); + std::unique_ptr eventQueue = makeEventFMQ(0); std::unique_ptr wakeLockQueue = makeWakelockFMQ(0); std::vector sensorsToConnect; @@ -647,9 +681,9 @@ TEST(HalProxyTest, DynamicSensorsDisconnectedTest) { nonDynamicSensorHandles.end()); TestSensorsCallback* callback = new TestSensorsCallback(); - ::android::sp callbackPtr = callback; + ::android::sp callbackPtr = callback; proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); - subHal.addDynamicSensors(sensorsToConnect); + subHal.addDynamicSensors(convertToNewSensorInfos(sensorsToConnect)); subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove); std::vector sensorHandlesSeen = callback->getSensorHandlesDisconnected(); @@ -668,15 +702,15 @@ TEST(HalProxyTest, InvalidSensorHandleSubHalIndexProxyCalls) { constexpr size_t kNumSubHals = 3; constexpr size_t kQueueSize = 5; int32_t kNumSubHalsInt32 = static_cast(kNumSubHals); - std::vector subHalObjs(kNumSubHals); + std::vector> subHalObjs(kNumSubHals); std::vector subHals; for (const auto& subHal : subHalObjs) { subHals.push_back((ISensorsSubHal*)(&subHal)); } - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); // Initialize for the injectSensorData call so callback postEvents is valid proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); @@ -688,7 +722,7 @@ TEST(HalProxyTest, InvalidSensorHandleSubHalIndexProxyCalls) { EXPECT_EQ(proxy.activate(0x00000001 | (kNumSubHalsInt32 << 24), true), Result::BAD_VALUE); EXPECT_EQ(proxy.batch(0x00000001 | (kNumSubHalsInt32 << 24), 0, 0), Result::BAD_VALUE); EXPECT_EQ(proxy.flush(0x00000001 | (kNumSubHalsInt32 << 24)), Result::BAD_VALUE); - Event event; + EventV1_0 event; event.sensorHandle = 0x00000001 | (kNumSubHalsInt32 << 24); EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE); } @@ -697,28 +731,28 @@ TEST(HalProxyTest, PostedEventSensorHandleSubHalIndexValid) { constexpr size_t kQueueSize = 5; constexpr int32_t subhal1Index = 0; constexpr int32_t subhal2Index = 1; - AllSensorsSubHal subhal1; - AllSensorsSubHal subhal2; + AllSensorsSubHal subhal1; + AllSensorsSubHal subhal2; std::vector subHals{&subhal1, &subhal2}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); int32_t sensorHandleToPost = 0x00000001; - Event eventIn = makeAccelerometerEvent(); + EventV1_0 eventIn = makeAccelerometerEvent(); eventIn.sensorHandle = sensorHandleToPost; - std::vector eventsToPost{eventIn}; - subhal1.postEvents(eventsToPost, false); + std::vector eventsToPost{eventIn}; + subhal1.postEvents(convertToNewEvents(eventsToPost), false); - Event eventOut; + EventV1_0 eventOut; EXPECT_TRUE(eventQueue->read(&eventOut)); EXPECT_EQ(eventOut.sensorHandle, (subhal1Index << 24) | sensorHandleToPost); - subhal2.postEvents(eventsToPost, false); + subhal2.postEvents(convertToNewEvents(eventsToPost), false); EXPECT_TRUE(eventQueue->read(&eventOut)); @@ -729,22 +763,22 @@ TEST(HalProxyTest, FillAndDrainPendingQueueTest) { constexpr size_t kQueueSize = 5; // TODO: Make this constant linked to same limit in HalProxy.h constexpr size_t kMaxPendingQueueSize = 100000; - AllSensorsSubHal subhal; + AllSensorsSubHal subhal; std::vector subHals{&subhal}; - std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); + std::unique_ptr eventQueue = makeEventFMQ(kQueueSize); std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); - ::android::sp callback = new SensorsCallback(); + ::android::sp callback = new SensorsCallback(); EventFlag* eventQueueFlag; EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag); HalProxy proxy(subHals); proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); // Fill pending queue - std::vector events = makeMultipleAccelerometerEvents(kQueueSize); - subhal.postEvents(events, false); + std::vector events = makeMultipleAccelerometerEvents(kQueueSize); + subhal.postEvents(convertToNewEvents(events), false); events = makeMultipleAccelerometerEvents(kMaxPendingQueueSize); - subhal.postEvents(events, false); + subhal.postEvents(convertToNewEvents(events), false); // Drain pending queue for (int i = 0; i < kMaxPendingQueueSize + kQueueSize; i += kQueueSize) { @@ -753,9 +787,9 @@ TEST(HalProxyTest, FillAndDrainPendingQueueTest) { // Put one event on pending queue events = makeMultipleAccelerometerEvents(kQueueSize); - subhal.postEvents(events, false); + subhal.postEvents(convertToNewEvents(events), false); events = {makeAccelerometerEvent()}; - subhal.postEvents(events, false); + subhal.postEvents(convertToNewEvents(events), false); // Read out to make room for one event on pending queue to write to FMQ ASSERT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag)); @@ -764,6 +798,35 @@ TEST(HalProxyTest, FillAndDrainPendingQueueTest) { EXPECT_TRUE(readEventsOutOfQueue(1, eventQueue, eventQueueFlag)); } +TEST(HalProxyTest, PostEventsMultipleSubhalsThreadedV2_1) { + constexpr size_t kQueueSize = 5; + constexpr size_t kNumEvents = 2; + AllSensorsSubHal subHal1; + AllSensorsSubHal subHal2; + std::vector<::android::hardware::sensors::V2_0::implementation::ISensorsSubHal*> subHalsV2_0{ + &subHal1}; + std::vector<::android::hardware::sensors::V2_1::implementation::ISensorsSubHal*> subHalsV2_1{ + &subHal2}; + HalProxy proxy(subHalsV2_0, subHalsV2_1); + std::unique_ptr eventQueue = + std::make_unique(kQueueSize, true); + std::unique_ptr wakeLockQueue = makeWakelockFMQ(kQueueSize); + ::android::sp callback = new SensorsCallbackV2_1(); + proxy.initialize_2_1(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback); + + std::vector events = makeMultipleAccelerometerEvents(kNumEvents); + + std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, + convertToNewEvents(events), false); + std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, + convertToNewEvents(events), false); + + t1.join(); + t2.join(); + + EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2); +} + // Helper implementations follow void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, const std::vector& subHalSensorsList) { @@ -802,26 +865,26 @@ void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptrwake(static_cast(WakeLockQueueFlagBits::DATA_WRITTEN)); } -bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& eventQueue, +bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr& eventQueue, EventFlag* eventQueueFlag) { constexpr int64_t kReadBlockingTimeout = INT64_C(500000000); - std::vector events(numEvents); + std::vector events(numEvents); return eventQueue->readBlocking(events.data(), numEvents, static_cast(EventQueueFlagBits::EVENTS_READ), static_cast(EventQueueFlagBits::READ_AND_PROCESS), kReadBlockingTimeout, eventQueueFlag); } -std::unique_ptr makeEventFMQ(size_t size) { - return std::make_unique(size, true); +std::unique_ptr makeEventFMQ(size_t size) { + return std::make_unique(size, true); } std::unique_ptr makeWakelockFMQ(size_t size) { return std::make_unique(size, true); } -Event makeProximityEvent() { - Event event; +EventV1_0 makeProximityEvent() { + EventV1_0 event; event.timestamp = 0xFF00FF00; // This is the sensorhandle of proximity, which is wakeup type event.sensorHandle = 0x00000008; @@ -830,8 +893,8 @@ Event makeProximityEvent() { return event; } -Event makeAccelerometerEvent() { - Event event; +EventV1_0 makeAccelerometerEvent() { + EventV1_0 event; event.timestamp = 0xFF00FF00; // This is the sensorhandle of proximity, which is wakeup type event.sensorHandle = 0x00000001; @@ -840,16 +903,16 @@ Event makeAccelerometerEvent() { return event; } -std::vector makeMultipleProximityEvents(size_t numEvents) { - std::vector events; +std::vector makeMultipleProximityEvents(size_t numEvents) { + std::vector events; for (size_t i = 0; i < numEvents; i++) { events.push_back(makeProximityEvent()); } return events; } -std::vector makeMultipleAccelerometerEvents(size_t numEvents) { - std::vector events; +std::vector makeMultipleAccelerometerEvents(size_t numEvents) { + std::vector events; for (size_t i = 0; i < numEvents; i++) { events.push_back(makeAccelerometerEvent()); } diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/IHalProxyCallbackWrapper.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/IHalProxyCallbackWrapper.h new file mode 100644 index 0000000000..4542bfdc2c --- /dev/null +++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/IHalProxyCallbackWrapper.h @@ -0,0 +1,107 @@ +/* + * 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. + */ + +#pragma once + +#include "V2_0/SubHal.h" +#include "V2_1/SubHal.h" +#include "convertV2_1.h" + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_1 { +namespace subhal { +namespace implementation { + +/** + * The following callback wrapper classes abstract away common functionality across V2.0 and V2.1 + * interfaces. Much of the logic is common between the two versions and this allows users of the + * classes to only care about the type used at initialization and then interact with either version + * of the callback interface without worrying about the type. + */ +class IHalProxyCallbackWrapperBase { + protected: + using ScopedWakelock = V2_0::implementation::ScopedWakelock; + + public: + virtual ~IHalProxyCallbackWrapperBase() {} + + virtual Return onDynamicSensorsConnected( + const hidl_vec& sensorInfos) = 0; + + virtual Return onDynamicSensorsDisconnected(const hidl_vec& sensorHandles) = 0; + + virtual void postEvents(const std::vector& events, ScopedWakelock wakelock) = 0; + + virtual ScopedWakelock createScopedWakelock(bool lock) = 0; +}; + +template +class HalProxyCallbackWrapperBase : public IHalProxyCallbackWrapperBase { + public: + HalProxyCallbackWrapperBase(sp callback) : mCallback(callback){}; + + Return onDynamicSensorsDisconnected(const hidl_vec& sensorHandles) override { + return mCallback->onDynamicSensorsDisconnected(sensorHandles); + } + + ScopedWakelock createScopedWakelock(bool lock) override { + return mCallback->createScopedWakelock(lock); + } + + protected: + sp mCallback; +}; + +class HalProxyCallbackWrapperV2_0 + : public HalProxyCallbackWrapperBase { + public: + HalProxyCallbackWrapperV2_0(sp callback) + : HalProxyCallbackWrapperBase(callback){}; + + Return onDynamicSensorsConnected(const hidl_vec& sensorInfos) override { + return mCallback->onDynamicSensorsConnected( + V2_1::implementation::convertToOldSensorInfos(sensorInfos)); + } + + void postEvents(const std::vector& events, ScopedWakelock wakelock) override { + return mCallback->postEvents(V2_1::implementation::convertToOldEvents(events), + std::move(wakelock)); + } +}; + +class HalProxyCallbackWrapperV2_1 + : public HalProxyCallbackWrapperBase { + public: + HalProxyCallbackWrapperV2_1(sp callback) + : HalProxyCallbackWrapperBase(callback){}; + + Return onDynamicSensorsConnected(const hidl_vec& sensorInfos) override { + return mCallback->onDynamicSensorsConnected_2_1(sensorInfos); + } + + void postEvents(const std::vector& events, ScopedWakelock wakelock) { + return mCallback->postEvents(events, std::move(wakelock)); + } +}; + +} // namespace implementation +} // namespace subhal +} // namespace V2_1 +} // namespace sensors +} // namespace hardware +} // namespace android diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp index de89a00ef9..1efd971115 100644 --- a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp +++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp @@ -24,13 +24,18 @@ namespace android { namespace hardware { namespace sensors { -namespace V2_0 { +namespace V2_1 { namespace subhal { namespace implementation { using ::android::hardware::sensors::V1_0::MetaDataEventType; +using ::android::hardware::sensors::V1_0::OperationMode; +using ::android::hardware::sensors::V1_0::Result; using ::android::hardware::sensors::V1_0::SensorFlagBits; using ::android::hardware::sensors::V1_0::SensorStatus; +using ::android::hardware::sensors::V2_1::Event; +using ::android::hardware::sensors::V2_1::SensorInfo; +using ::android::hardware::sensors::V2_1::SensorType; Sensor::Sensor(int32_t sensorHandle, ISensorsEventCallback* callback) : mIsEnabled(false), @@ -343,7 +348,7 @@ RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle, } // namespace implementation } // namespace subhal -} // namespace V2_0 +} // namespace V2_1 } // namespace sensors } // namespace hardware } // namespace android diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h index 60f5d3d40a..5cf9f837cf 100644 --- a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h +++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h @@ -16,7 +16,7 @@ #pragma once -#include +#include #include #include @@ -24,16 +24,16 @@ #include #include -using ::android::hardware::sensors::V1_0::Event; using ::android::hardware::sensors::V1_0::OperationMode; using ::android::hardware::sensors::V1_0::Result; -using ::android::hardware::sensors::V1_0::SensorInfo; -using ::android::hardware::sensors::V1_0::SensorType; +using ::android::hardware::sensors::V2_1::Event; +using ::android::hardware::sensors::V2_1::SensorInfo; +using ::android::hardware::sensors::V2_1::SensorType; namespace android { namespace hardware { namespace sensors { -namespace V2_0 { +namespace V2_1 { namespace subhal { namespace implementation { @@ -151,7 +151,7 @@ class RelativeHumiditySensor : public OnChangeSensor { } // namespace implementation } // namespace subhal -} // namespace V2_0 +} // namespace V2_1 } // namespace sensors } // namespace hardware } // namespace android diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp index ff5ff38541..20a4e9de04 100644 --- a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp +++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp @@ -16,33 +16,66 @@ #include "SensorsSubHal.h" -#include +#include #include -ISensorsSubHal* sensorsHalGetSubHal(uint32_t* version) { +#ifdef SUB_HAL_VERSION_2_0 +::android::hardware::sensors::V2_0::implementation::ISensorsSubHal* sensorsHalGetSubHal( + uint32_t* version) { #if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS - static ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal subHal; + static ::android::hardware::sensors::V2_1::subhal::implementation::AllSensorsSubHal< + ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0> + subHal; #elif defined SUPPORT_CONTINUOUS_SENSORS - static ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal + static ::android::hardware::sensors::V2_1::subhal::implementation::ContinuousSensorsSubHal< + ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0> subHal; #elif defined SUPPORT_ON_CHANGE_SENSORS - static ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal subHal; + static ::android::hardware::sensors::V2_1::subhal::implementation::OnChangeSensorsSubHal< + ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0> + subHal; #else - static ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal subHal; + static ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHal< + ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0> + subHal; #endif // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS *version = SUB_HAL_2_0_VERSION; return &subHal; } +#else // SUB_HAL_VERSION_2_0 + +::android::hardware::sensors::V2_1::implementation::ISensorsSubHal* sensorsHalGetSubHal_2_1( + uint32_t* version) { +#if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS + static ::android::hardware::sensors::V2_1::subhal::implementation::AllSensorsSubHal< + ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1> + subHal; +#elif defined SUPPORT_CONTINUOUS_SENSORS + static ::android::hardware::sensors::V2_1::subhal::implementation::ContinuousSensorsSubHal< + ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1> + subHal; +#elif defined SUPPORT_ON_CHANGE_SENSORS + static ::android::hardware::sensors::V2_1::subhal::implementation::OnChangeSensorsSubHal< + ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1> + subHal; +#else + static ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1 subHal; +#endif // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS + *version = SUB_HAL_2_1_VERSION; + return &subHal; +} + +#endif // SUB_HAL_VERSION_2_0 + namespace android { namespace hardware { namespace sensors { -namespace V2_0 { +namespace V2_1 { namespace subhal { namespace implementation { using ::android::hardware::Void; -using ::android::hardware::sensors::V1_0::Event; using ::android::hardware::sensors::V1_0::OperationMode; using ::android::hardware::sensors::V1_0::RateLevel; using ::android::hardware::sensors::V1_0::Result; @@ -50,11 +83,12 @@ using ::android::hardware::sensors::V1_0::SharedMemInfo; using ::android::hardware::sensors::V2_0::SensorTimeout; using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock; +using ::android::hardware::sensors::V2_1::Event; -SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {} +ISensorsSubHalBase::ISensorsSubHalBase() : mCallback(nullptr), mNextHandle(1) {} // Methods from ::android::hardware::sensors::V2_0::ISensors follow. -Return SensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) { +Return ISensorsSubHalBase::getSensorsList(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) { std::vector sensors; for (const auto& sensor : mSensors) { sensors.push_back(sensor.second->getSensorInfo()); @@ -64,7 +98,7 @@ Return SensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) { return Void(); } -Return SensorsSubHal::setOperationMode(OperationMode mode) { +Return ISensorsSubHalBase::setOperationMode(OperationMode mode) { for (auto sensor : mSensors) { sensor.second->setOperationMode(mode); } @@ -72,7 +106,7 @@ Return SensorsSubHal::setOperationMode(OperationMode mode) { return Result::OK; } -Return SensorsSubHal::activate(int32_t sensorHandle, bool enabled) { +Return ISensorsSubHalBase::activate(int32_t sensorHandle, bool enabled) { auto sensor = mSensors.find(sensorHandle); if (sensor != mSensors.end()) { sensor->second->activate(enabled); @@ -81,8 +115,8 @@ Return SensorsSubHal::activate(int32_t sensorHandle, bool enabled) { return Result::BAD_VALUE; } -Return SensorsSubHal::batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t /* maxReportLatencyNs */) { +Return ISensorsSubHalBase::batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t /* maxReportLatencyNs */) { auto sensor = mSensors.find(sensorHandle); if (sensor != mSensors.end()) { sensor->second->batch(samplingPeriodNs); @@ -91,7 +125,7 @@ Return SensorsSubHal::batch(int32_t sensorHandle, int64_t samplingPeriod return Result::BAD_VALUE; } -Return SensorsSubHal::flush(int32_t sensorHandle) { +Return ISensorsSubHalBase::flush(int32_t sensorHandle) { auto sensor = mSensors.find(sensorHandle); if (sensor != mSensors.end()) { return sensor->second->flush(); @@ -99,7 +133,7 @@ Return SensorsSubHal::flush(int32_t sensorHandle) { return Result::BAD_VALUE; } -Return SensorsSubHal::injectSensorData(const Event& event) { +Return ISensorsSubHalBase::injectSensorData(const Event& event) { auto sensor = mSensors.find(event.sensorHandle); if (sensor != mSensors.end()) { return sensor->second->injectEvent(event); @@ -108,24 +142,24 @@ Return SensorsSubHal::injectSensorData(const Event& event) { return Result::BAD_VALUE; } -Return SensorsSubHal::registerDirectChannel(const SharedMemInfo& /* mem */, - registerDirectChannel_cb _hidl_cb) { +Return ISensorsSubHalBase::registerDirectChannel( + const SharedMemInfo& /* mem */, V2_0::ISensors::registerDirectChannel_cb _hidl_cb) { _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */); return Return(); } -Return SensorsSubHal::unregisterDirectChannel(int32_t /* channelHandle */) { +Return ISensorsSubHalBase::unregisterDirectChannel(int32_t /* channelHandle */) { return Result::INVALID_OPERATION; } -Return SensorsSubHal::configDirectReport(int32_t /* sensorHandle */, - int32_t /* channelHandle */, RateLevel /* rate */, - configDirectReport_cb _hidl_cb) { +Return ISensorsSubHalBase::configDirectReport( + int32_t /* sensorHandle */, int32_t /* channelHandle */, RateLevel /* rate */, + V2_0::ISensors::configDirectReport_cb _hidl_cb) { _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */); return Return(); } -Return SensorsSubHal::debug(const hidl_handle& fd, const hidl_vec& args) { +Return ISensorsSubHalBase::debug(const hidl_handle& fd, const hidl_vec& args) { if (fd.getNativeHandle() == nullptr || fd->numFds < 1) { ALOGE("%s: missing fd for writing", __FUNCTION__); return Void(); @@ -156,44 +190,18 @@ Return SensorsSubHal::debug(const hidl_handle& fd, const hidl_vec(); } -Return SensorsSubHal::initialize(const sp& halProxyCallback) { - mCallback = halProxyCallback; +Return ISensorsSubHalBase::initialize( + std::unique_ptr& halProxyCallback) { + mCallback = std::move(halProxyCallback); setOperationMode(OperationMode::NORMAL); return Result::OK; } -void SensorsSubHal::postEvents(const std::vector& events, bool wakeup) { +void ISensorsSubHalBase::postEvents(const std::vector& events, bool wakeup) { ScopedWakelock wakelock = mCallback->createScopedWakelock(wakeup); mCallback->postEvents(events, std::move(wakelock)); } -ContinuousSensorsSubHal::ContinuousSensorsSubHal() { - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); -} - -OnChangeSensorsSubHal::OnChangeSensorsSubHal() { - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); -} - -AllSensorsSubHal::AllSensorsSubHal() { - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); - AddSensor(); -} - Return SetOperationModeFailingSensorsSubHal::setOperationMode(OperationMode /*mode*/) { return Result::BAD_VALUE; } @@ -206,7 +214,7 @@ Return AllSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_REPORT; sensors.push_back(sensorInfo); } - _hidl_cb(sensors); + _hidl_cb(V2_1::implementation::convertToOldSensorInfos(sensors)); return Void(); } @@ -218,7 +226,7 @@ Return DoesNotSupportDirectChannelSensorsSubHal::getSensorsList(getSensors sensorInfo.flags &= ~static_cast(V1_0::SensorFlagBits::MASK_DIRECT_REPORT); sensors.push_back(sensorInfo); } - _hidl_cb(sensors); + _hidl_cb(V2_1::implementation::convertToOldSensorInfos(sensors)); return Void(); } @@ -234,7 +242,7 @@ void AddAndRemoveDynamicSensorsSubHal::removeDynamicSensors( } // namespace implementation } // namespace subhal -} // namespace V2_0 +} // namespace V2_1 } // namespace sensors } // namespace hardware } // namespace android diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h index 6da4404c3e..1a78e847c7 100644 --- a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h +++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h @@ -17,7 +17,9 @@ #pragma once #include "V2_0/SubHal.h" +#include "V2_1/SubHal.h" +#include "IHalProxyCallbackWrapper.h" #include "Sensor.h" #include @@ -25,54 +27,54 @@ namespace android { namespace hardware { namespace sensors { -namespace V2_0 { +namespace V2_1 { namespace subhal { namespace implementation { using ::android::hardware::sensors::V1_0::OperationMode; using ::android::hardware::sensors::V1_0::Result; -using ::android::hardware::sensors::V2_0::implementation::IHalProxyCallback; /** * Implementation of a ISensorsSubHal that can be used to test the implementation of multihal 2.0. * See the README file for more details on how this class can be used for testing. */ -class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { - using Event = ::android::hardware::sensors::V1_0::Event; +class ISensorsSubHalBase : public ISensorsEventCallback { + protected: + using Event = ::android::hardware::sensors::V2_1::Event; using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; public: - SensorsSubHal(); + ISensorsSubHalBase(); + + Return getSensorsList(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb); + Return injectSensorData(const Event& event); + Return initialize(std::unique_ptr& halProxyCallback); // Methods from ::android::hardware::sensors::V2_0::ISensors follow. - virtual Return getSensorsList(getSensorsList_cb _hidl_cb) override; - - virtual Return setOperationMode(OperationMode mode) override; + virtual Return setOperationMode(OperationMode mode); OperationMode getOperationMode() const { return mCurrentOperationMode; } - Return activate(int32_t sensorHandle, bool enabled) override; + Return activate(int32_t sensorHandle, bool enabled); Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) override; + int64_t maxReportLatencyNs); - Return flush(int32_t sensorHandle) override; - - Return injectSensorData(const Event& event) override; + Return flush(int32_t sensorHandle); Return registerDirectChannel(const SharedMemInfo& mem, - registerDirectChannel_cb _hidl_cb) override; + V2_0::ISensors::registerDirectChannel_cb _hidl_cb); - Return unregisterDirectChannel(int32_t channelHandle) override; + Return unregisterDirectChannel(int32_t channelHandle); Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, - configDirectReport_cb _hidl_cb) override; + V2_0::ISensors::configDirectReport_cb _hidl_cb); - Return debug(const hidl_handle& fd, const hidl_vec& args) override; + Return debug(const hidl_handle& fd, const hidl_vec& args); // Methods from ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal follow. - const std::string getName() override { + const std::string getName() { #ifdef SUB_HAL_NAME return SUB_HAL_NAME; #else // SUB_HAL_NAME @@ -80,8 +82,6 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { #endif // SUB_HAL_NAME } - Return initialize(const sp& halProxyCallback) override; - // Method from ISensorsEventCallback. void postEvents(const std::vector& events, bool wakeup) override; @@ -103,7 +103,7 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { * disconnected, sensor events need to be sent to the framework, and when a wakelock should be * acquired. */ - sp mCallback; + std::unique_ptr mCallback; private: /** @@ -118,40 +118,143 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { int32_t mNextHandle; }; -// SubHal that has continuous sensors for testing purposes. -class ContinuousSensorsSubHal : public SensorsSubHal { +template +class SensorsSubHalBase : public ISensorsSubHalBase, public SubHalClass { public: - ContinuousSensorsSubHal(); + Return setOperationMode(OperationMode mode) override { + return ISensorsSubHalBase::setOperationMode(mode); + } + + Return activate(int32_t sensorHandle, bool enabled) override { + return ISensorsSubHalBase::activate(sensorHandle, enabled); + } + + Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) override { + return ISensorsSubHalBase::batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); + } + + Return flush(int32_t sensorHandle) override { + return ISensorsSubHalBase::flush(sensorHandle); + } + + Return registerDirectChannel(const SharedMemInfo& mem, + V2_0::ISensors::registerDirectChannel_cb _hidl_cb) override { + return ISensorsSubHalBase::registerDirectChannel(mem, _hidl_cb); + } + + Return unregisterDirectChannel(int32_t channelHandle) override { + return ISensorsSubHalBase::unregisterDirectChannel(channelHandle); + } + + Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + V2_0::ISensors::configDirectReport_cb _hidl_cb) override { + return ISensorsSubHalBase::configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); + } + + Return debug(const hidl_handle& fd, const hidl_vec& args) override { + return ISensorsSubHalBase::debug(fd, args); + } + + const std::string getName() override { return ISensorsSubHalBase::getName(); } +}; + +class SensorsSubHalV2_0 : public SensorsSubHalBase { + public: + virtual Return getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override { + return ISensorsSubHalBase::getSensorsList([&](const auto& list) { + _hidl_cb(V2_1::implementation::convertToOldSensorInfos(list)); + }); + } + + Return injectSensorData(const V1_0::Event& event) override { + return ISensorsSubHalBase::injectSensorData(V2_1::implementation::convertToNewEvent(event)); + } + + Return initialize( + const sp& halProxyCallback) override { + std::unique_ptr wrapper = + std::make_unique(halProxyCallback); + return ISensorsSubHalBase::initialize(wrapper); + } +}; + +class SensorsSubHalV2_1 : public SensorsSubHalBase { + public: + Return getSensorsList_2_1(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override { + return ISensorsSubHalBase::getSensorsList(_hidl_cb); + } + + Return injectSensorData_2_1(const V2_1::Event& event) override { + return ISensorsSubHalBase::injectSensorData(event); + } + + Return initialize( + const sp& halProxyCallback) override { + std::unique_ptr wrapper = + std::make_unique(halProxyCallback); + return ISensorsSubHalBase::initialize(wrapper); + } +}; + +// SubHal that has continuous sensors for testing purposes. +template +class ContinuousSensorsSubHal : public SubHalVersion { + public: + ContinuousSensorsSubHal() { + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + } }; // SubHal that has on-change sensors for testing purposes. -class OnChangeSensorsSubHal : public SensorsSubHal { +template +class OnChangeSensorsSubHal : public SubHalVersion { public: - OnChangeSensorsSubHal(); + OnChangeSensorsSubHal() { + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + } }; // SubHal that has both continuous and on-change sensors for testing purposes. -class AllSensorsSubHal : public SensorsSubHal { +template +class AllSensorsSubHal : public SubHalVersion { public: - AllSensorsSubHal(); + AllSensorsSubHal() { + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + ISensorsSubHalBase::AddSensor(); + } }; -class SetOperationModeFailingSensorsSubHal : public AllSensorsSubHal { +class SetOperationModeFailingSensorsSubHal : public AllSensorsSubHal { public: Return setOperationMode(OperationMode mode) override; }; -class AllSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { +class AllSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { public: - Return getSensorsList(getSensorsList_cb _hidl_cb) override; + Return getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override; }; -class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { +class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { public: - Return getSensorsList(getSensorsList_cb _hidl_cb) override; + Return getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override; }; -class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal { +class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal { public: void addDynamicSensors(const std::vector& sensorsAdded); void removeDynamicSensors(const std::vector& sensorHandlesAdded); @@ -159,7 +262,7 @@ class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal { } // namespace implementation } // namespace subhal -} // namespace V2_0 +} // namespace V2_1 } // namespace sensors } // namespace hardware } // namespace android From 738702f8757b23b7e5bcd583e2d7f9a7c2b62b6f Mon Sep 17 00:00:00 2001 From: Midas Chien Date: Thu, 30 Apr 2020 23:52:17 +0800 Subject: [PATCH 0895/1022] composer: vts: send a frame after call setActiveConfig setActiveConfig will take effect follow by a frame updated. To make sure it takes effect, send a frame after setActiveConfig. Bug: 150831726 Test: VtsHalGraphicsComposerV2_4TargetTest Change-Id: Ib999e808ac1339d1cba9e25e9a57b681b055cc99 --- .../VtsHalGraphicsComposerV2_4TargetTest.cpp | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index 7a00ed23ac..27b633a409 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -204,7 +204,7 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { void Test_setActiveConfigWithConstraints( const IComposerClient::VsyncPeriodChangeConstraints& constraints, bool refreshMiss); - void sendRefreshFrame(const VsyncPeriodChangeTimeline&); + void sendRefreshFrame(const VsyncPeriodChangeTimeline*); void waitForVsyncPeriodChange(Display display, const VsyncPeriodChangeTimeline& timeline, int64_t desiredTimeNanos, int64_t oldPeriodNanos, @@ -294,7 +294,7 @@ TEST_P(GraphicsComposerHidlCommandTest, getDisplayVsyncPeriod) { display, config, constraints, &timeline)); if (timeline.refreshRequired) { - sendRefreshFrame(timeline); + sendRefreshFrame(&timeline); } waitForVsyncPeriodChange(display, timeline, constraints.desiredTimeNanos, 0, expectedVsyncPeriodNanos); @@ -350,7 +350,7 @@ TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_BadConfig) { } } -TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_SeamlessNotAllowed) { +TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_SeamlessNotAllowed) { VsyncPeriodChangeTimeline timeline; IComposerClient::VsyncPeriodChangeConstraints constraints; @@ -365,6 +365,7 @@ TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_SeamlessNotAllow display, config2, IComposerClient::IComposerClient::Attribute::CONFIG_GROUP); if (configGroup1 != configGroup2) { mComposerClient->setActiveConfig(display, config1); + sendRefreshFrame(nullptr); EXPECT_EQ(Error::SEAMLESS_NOT_ALLOWED, mComposerClient->setActiveConfigWithConstraints(display, config2, constraints, &timeline)); @@ -377,11 +378,13 @@ static inline auto toTimePoint(nsecs_t time) { return std::chrono::time_point(std::chrono::nanoseconds(time)); } -void GraphicsComposerHidlCommandTest::sendRefreshFrame(const VsyncPeriodChangeTimeline& timeline) { - // Refresh time should be before newVsyncAppliedTimeNanos - EXPECT_LT(timeline.refreshTimeNanos, timeline.newVsyncAppliedTimeNanos); +void GraphicsComposerHidlCommandTest::sendRefreshFrame(const VsyncPeriodChangeTimeline* timeline) { + if (timeline != nullptr) { + // Refresh time should be before newVsyncAppliedTimeNanos + EXPECT_LT(timeline->refreshTimeNanos, timeline->newVsyncAppliedTimeNanos); - std::this_thread::sleep_until(toTimePoint(timeline.refreshTimeNanos)); + std::this_thread::sleep_until(toTimePoint(timeline->refreshTimeNanos)); + } mWriter->selectDisplay(mPrimaryDisplay); mComposerClient->setPowerMode(mPrimaryDisplay, V2_1::IComposerClient::PowerMode::ON); @@ -453,6 +456,7 @@ void GraphicsComposerHidlCommandTest::Test_setActiveConfigWithConstraints( for (Display display : mComposerCallback->getDisplays()) { forEachTwoConfigs(display, [&](Config config1, Config config2) { mComposerClient->setActiveConfig(display, config1); + sendRefreshFrame(nullptr); int32_t vsyncPeriod1 = mComposerClient->getDisplayAttribute_2_4( display, config1, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD); @@ -478,7 +482,7 @@ void GraphicsComposerHidlCommandTest::Test_setActiveConfigWithConstraints( // callback std::this_thread::sleep_until(toTimePoint(timeline.refreshTimeNanos) + 100ms); } - sendRefreshFrame(timeline); + sendRefreshFrame(&timeline); } waitForVsyncPeriodChange(display, timeline, constraints.desiredTimeNanos, vsyncPeriod1, vsyncPeriod2); @@ -493,7 +497,7 @@ void GraphicsComposerHidlCommandTest::Test_setActiveConfigWithConstraints( if (newTimelime.has_value()) { if (timeline.refreshRequired) { - sendRefreshFrame(newTimelime.value()); + sendRefreshFrame(&newTimelime.value()); } waitForVsyncPeriodChange(display, newTimelime.value(), constraints.desiredTimeNanos, vsyncPeriod1, vsyncPeriod2); From bb780f4875519e5084308e72e3cbd1a49cabcc3e Mon Sep 17 00:00:00 2001 From: Kai Date: Tue, 14 Apr 2020 16:33:33 -0700 Subject: [PATCH 0896/1022] Revise documentation for tire pressure and max_defrost Use the max/min in areaConfig to indicate the recommended tire pressure. Explain areaId for HVAC_MAX_DEFROST Bug: 153906683 Test: make and flash Change-Id: Ie71279dba4e87efdec75934dcac1c86e22fffaa3 --- automotive/vehicle/2.0/types.hal | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index 82f938c611..ee34e420c9 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -606,8 +606,23 @@ enum VehicleProperty : int32_t { /** * Tire pressure * - * min/max value indicates tire pressure sensor range. Each tire will have a separate min/max - * value denoted by its areaConfig.areaId. + * Each tires is identified by its areaConfig.areaId config and their + * minFloatValue/maxFloatValue are used to store OEM recommended pressure + * range. + * The Min value in the areaConfig data represents the lower bound of + * the recommended tire pressure. + * The Max value in the areaConfig data represents the upper bound of + * the recommended tire pressure. + * For example: + * The following areaConfig indicates the recommended tire pressure + * of left_front tire is from 200.0 KILOPASCAL to 240.0 KILOPASCAL. + * .areaConfigs = { + * VehicleAreaConfig { + * .areaId = VehicleAreaWheel::LEFT_FRONT, + * .minFloatValue = 200.0, + * .maxFloatValue = 240.0, + * } + * }, * * @change_mode VehiclePropertyChangeMode:CONTINUOUS * @access VehiclePropertyAccess:READ @@ -786,7 +801,8 @@ enum VehicleProperty : int32_t { /* * HVAC Properties * - * Additional rules for mapping a zoned HVAC property to AreaIDs: + * Additional rules for mapping a zoned HVAC property (except + * HVAC_MAX_DEFROST_ON) to AreaIDs: * - Every seat in VehicleAreaSeat that is available in the car, must be * part of an AreaID in the AreaID array. * @@ -919,6 +935,11 @@ enum VehicleProperty : int32_t { * possible. Any parameters modified as a side effect of turning on/off * the MAX DEFROST parameter shall generate onPropertyEvent() callbacks to * the VHAL. + * The AreaIDs for HVAC_MAX_DEFROST_ON indicate MAX DEFROST can be controlled + * in the area. + * For example: + * areaConfig.areaId = {ROW_1_LEFT | ROW_1_RIGHT} indicates HVAC_MAX_DEFROST_ON + * only can be controlled for the front rows. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE * @access VehiclePropertyAccess:READ_WRITE From 78cb59913a1461f147c8c6b5f17add00a00c06b9 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Thu, 30 Apr 2020 12:39:21 -0700 Subject: [PATCH 0897/1022] Allow tethering name config Test: manual Bug: 155110247 Test: Compiles Test: Verified that SAP is working Change-Id: I6f0fd5b891dd6e6c2f0ceab05f6830b56f6474b1 --- wifi/1.4/default/wifi_chip.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp index 23dd13be66..61912a53e0 100644 --- a/wifi/1.4/default/wifi_chip.cpp +++ b/wifi/1.4/default/wifi_chip.cpp @@ -101,6 +101,16 @@ std::string getWlanIfaceName(unsigned idx) { return "wlan" + std::to_string(idx); } +// Returns the dedicated iface name if one is defined. +std::string getApIfaceName() { + std::array buffer; + if (property_get("ro.vendor.wifi.sap.interface", buffer.data(), nullptr) == + 0) { + return {}; + } + return buffer.data(); +} + std::string getP2pIfaceName() { std::array buffer; property_get("wifi.direct.interface", buffer.data(), "p2p0"); @@ -1582,6 +1592,11 @@ std::string WifiChip::allocateApOrStaIfaceName(uint32_t start_idx) { // AP iface names start with idx 1 for modes supporting // concurrent STA and not dual AP, else start with idx 0. std::string WifiChip::allocateApIfaceName() { + // Check if we have a dedicated iface for AP. + std::string ifname = getApIfaceName(); + if (!ifname.empty()) { + return ifname; + } return allocateApOrStaIfaceName((isStaApConcurrencyAllowedInCurrentMode() && !isDualApAllowedInCurrentMode()) ? 1 From 3ee519be3a3da1d9b341cbeeb400ceeaeb309aae Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Mon, 20 Apr 2020 16:28:49 +0800 Subject: [PATCH 0898/1022] Wifi: Optionally avoid interface down/up when doing setMacAddress Some vendors implementation will reset wifi chip when doing interface down. Accordingly, We need to avoid the interface down/up when doing setMacAddress to avoid loss of sync between framework and firmware. This commit uses a BOARD_WIFI_AVOID_IFACE_RESET_MAC_CHANGE macro to check if it is needed to avoid interface down/up at setMacAddress. Bug: 153771961 Test: VTS Test Test: atest VtsHalWifiV1_2TargetTest Change-Id: I971764f1c272ebfd245959974fa0d1b10ba7c39b --- wifi/1.4/default/Android.mk | 3 +++ wifi/1.4/default/wifi_iface_util.cpp | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/wifi/1.4/default/Android.mk b/wifi/1.4/default/Android.mk index 8573e8e1f5..6be7dad59e 100644 --- a/wifi/1.4/default/Android.mk +++ b/wifi/1.4/default/Android.mk @@ -36,6 +36,9 @@ endif ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION endif +ifdef WIFI_AVOID_IFACE_RESET_MAC_CHANGE +LOCAL_CPPFLAGS += -DWIFI_AVOID_IFACE_RESET_MAC_CHANGE +endif # Allow implicit fallthroughs in wifi_legacy_hal.cpp until they are fixed. LOCAL_CFLAGS += -Wno-error=implicit-fallthrough LOCAL_SRC_FILES := \ diff --git a/wifi/1.4/default/wifi_iface_util.cpp b/wifi/1.4/default/wifi_iface_util.cpp index 036c97bcba..13ba0225d1 100644 --- a/wifi/1.4/default/wifi_iface_util.cpp +++ b/wifi/1.4/default/wifi_iface_util.cpp @@ -52,18 +52,22 @@ std::array WifiIfaceUtil::getFactoryMacAddress( bool WifiIfaceUtil::setMacAddress(const std::string& iface_name, const std::array& mac) { +#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), false)) { LOG(ERROR) << "SetUpState(false) failed."; return false; } +#endif if (!iface_tool_.lock()->SetMacAddress(iface_name.c_str(), mac)) { LOG(ERROR) << "SetMacAddress failed."; return false; } +#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) { LOG(ERROR) << "SetUpState(true) failed."; return false; } +#endif IfaceEventHandlers event_handlers = {}; const auto it = event_handlers_map_.find(iface_name); if (it != event_handlers_map_.end()) { From 75b0f0288c85cba5975b2898e6d37731b116a322 Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Fri, 1 May 2020 11:57:27 -0700 Subject: [PATCH 0899/1022] Camera: move preCorrectionActiveArraySize override to cameraserver This is to handle the case where HAL isn't using the hidl shim. Test: dumpsys on Pixel 2 Bug: 145300768 Change-Id: I74874a025904887cc27ec00518f4261dd24e291a --- camera/common/1.0/default/CameraModule.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp index 467c121a94..86f26e480c 100644 --- a/camera/common/1.0/default/CameraModule.cpp +++ b/camera/common/1.0/default/CameraModule.cpp @@ -194,16 +194,6 @@ void CameraModule::deriveCameraCharacteristicsKeys( } } - // Always add a default for the pre-correction active array if the vendor chooses to omit this - camera_metadata_entry entry = chars.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); - if (entry.count == 0) { - Vector preCorrectionArray; - entry = chars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE); - preCorrectionArray.appendArray(entry.data.i32, entry.count); - chars.update(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, preCorrectionArray); - derivedCharKeys.push(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); - } - // Add those newly added keys to AVAILABLE_CHARACTERISTICS_KEYS // This has to be done at this end of this function. if (derivedCharKeys.size() > 0) { From c786dfc5b170125ac95a442e46a2af445df72f35 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Tue, 28 Apr 2020 17:12:13 -0700 Subject: [PATCH 0900/1022] Search for subhal .so files in additional directories Fixes: 154634207 Test: Load onto flame and confirm that subhal .so android.hardware.sensors@2.X-fakesubhal-config3.so loads when it is living in the /vendor/lib64/hw directory using adb shell lshal debug android.hardware.sensors@2.0::ISensors/default Change-Id: I8a676b97f6f6992e8937ecf31c3b7af06e676ebb --- .../common/default/2.X/multihal/HalProxy.cpp | 21 ++++++++++++++++++- .../default/2.X/multihal/include/HalProxy.h | 10 +++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/sensors/common/default/2.X/multihal/HalProxy.cpp b/sensors/common/default/2.X/multihal/HalProxy.cpp index a09e9e938e..75ffc17a67 100644 --- a/sensors/common/default/2.X/multihal/HalProxy.cpp +++ b/sensors/common/default/2.X/multihal/HalProxy.cpp @@ -426,7 +426,7 @@ void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) { } else { std::string subHalLibraryFile; while (subHalConfigStream >> subHalLibraryFile) { - void* handle = dlopen(subHalLibraryFile.c_str(), RTLD_NOW); + void* handle = getHandleForSubHalSharedObject(subHalLibraryFile); if (handle == nullptr) { ALOGE("dlopen failed for library: %s", subHalLibraryFile.c_str()); } else { @@ -491,6 +491,25 @@ void HalProxy::initializeSensorList() { } } +void* HalProxy::getHandleForSubHalSharedObject(const std::string& filename) { + static const std::string kSubHalShareObjectLocations[] = { + "", // Default locations will be searched +#ifdef __LP64__ + "/vendor/lib64/hw/", "/odm/lib64/hw/" +#else + "/vendor/lib/hw/", "/odm/lib/hw/" +#endif + }; + + for (const std::string& dir : kSubHalShareObjectLocations) { + void* handle = dlopen((dir + filename).c_str(), RTLD_NOW); + if (handle != nullptr) { + return handle; + } + } + return nullptr; +} + void HalProxy::init() { initializeSensorList(); } diff --git a/sensors/common/default/2.X/multihal/include/HalProxy.h b/sensors/common/default/2.X/multihal/include/HalProxy.h index fb0b806bab..35d7c8bae1 100644 --- a/sensors/common/default/2.X/multihal/include/HalProxy.h +++ b/sensors/common/default/2.X/multihal/include/HalProxy.h @@ -266,6 +266,16 @@ class HalProxy : public V2_0::implementation::IScopedWakelockRefCounter, */ void initializeSensorList(); + /** + * Try using the default include directories as well as the directories defined in + * kSubHalShareObjectLocations to get a handle for dlsym for a subhal. + * + * @param filename The file name to search for. + * + * @return The handle or nullptr if search failed. + */ + void* getHandleForSubHalSharedObject(const std::string& filename); + /** * Calls the helper methods that all ctors use. */ From 6ab3f083281a7d9e04a0ea4f472d013d858541b6 Mon Sep 17 00:00:00 2001 From: shubang Date: Fri, 1 May 2020 17:26:08 -0700 Subject: [PATCH 0901/1022] Add more FrontendStatus for CTS Bug: 155342902 Test: atest android.media.tv.tuner.cts.TunerTest Change-Id: I90e08eea2470d223f54179a8fa13eef69e2f5230 --- tv/tuner/1.0/default/Frontend.cpp | 60 +++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp index b509599d40..996b6ef552 100644 --- a/tv/tuner/1.0/default/Frontend.cpp +++ b/tv/tuner/1.0/default/Frontend.cpp @@ -139,6 +139,30 @@ Return Frontend::getStatus(const hidl_vec& statusTypes status.snr(221); break; } + case FrontendStatusType::BER: { + status.ber(1); + break; + } + case FrontendStatusType::PER: { + status.per(2); + break; + } + case FrontendStatusType::PRE_BER: { + status.preBer(3); + break; + } + case FrontendStatusType::SIGNAL_QUALITY: { + status.signalQuality(4); + break; + } + case FrontendStatusType::SIGNAL_STRENGTH: { + status.signalStrength(5); + break; + } + case FrontendStatusType::SYMBOL_RATE: { + status.symbolRate(6); + break; + } case FrontendStatusType::FEC: { status.innerFec(FrontendInnerFec::FEC_2_9); // value = 1 << 7 break; @@ -149,15 +173,51 @@ Return Frontend::getStatus(const hidl_vec& statusTypes status.modulation(modulationStatus); break; } + case FrontendStatusType::SPECTRAL: { + status.inversion(FrontendDvbcSpectralInversion::NORMAL); + break; + } + case FrontendStatusType::LNB_VOLTAGE: { + status.lnbVoltage(LnbVoltage::VOLTAGE_5V); + break; + } case FrontendStatusType::PLP_ID: { status.plpId(101); // type uint8_t break; } + case FrontendStatusType::EWBS: { + status.isEWBS(false); + break; + } + case FrontendStatusType::AGC: { + status.agc(7); + break; + } + case FrontendStatusType::LNA: { + status.isLnaOn(false); + break; + } case FrontendStatusType::LAYER_ERROR: { vector v = {false, true, true}; status.isLayerError(v); break; } + case FrontendStatusType::MER: { + status.mer(8); + break; + } + case FrontendStatusType::FREQ_OFFSET: { + status.freqOffset(9); + break; + } + case FrontendStatusType::HIERARCHY: { + status.hierarchy(FrontendDvbtHierarchy::HIERARCHY_1_NATIVE); + break; + } + case FrontendStatusType::RF_LOCK: { + status.isRfLocked(false); + break; + } case FrontendStatusType::ATSC3_PLP_INFO: { vector v; FrontendStatusAtsc3PlpInfo info1{ From b5b1621fbc6c6ffa908f37089bd412e530d219ec Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Thu, 30 Apr 2020 13:27:38 -0700 Subject: [PATCH 0902/1022] Replace direct pid writes with setting task profiles for bluetooth interfaces For easy transition from SchedTune to UtilClamp, direct access to these cgroups should be abstracted by using task profiles. Replace writepid commands with new task_profiles command. Bug: 155419956 Test: change .rc file and confirm task profile is applied Signed-off-by: Suren Baghdasaryan Change-Id: Ie81da380a9343e098362f5fee5026799c4486e7e Merged-In: Ie81da380a9343e098362f5fee5026799c4486e7e --- bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc | 2 +- bluetooth/1.1/default/android.hardware.bluetooth@1.1-service.rc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc index 9fa128dfc6..def59de566 100644 --- a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc +++ b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc @@ -4,5 +4,5 @@ service vendor.bluetooth-1-0 /vendor/bin/hw/android.hardware.bluetooth@1.0-servi capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE user bluetooth group bluetooth - writepid /dev/stune/foreground/tasks + task_profiles HighPerformance diff --git a/bluetooth/1.1/default/android.hardware.bluetooth@1.1-service.rc b/bluetooth/1.1/default/android.hardware.bluetooth@1.1-service.rc index 49f0be3c10..5c7cbf4b3a 100644 --- a/bluetooth/1.1/default/android.hardware.bluetooth@1.1-service.rc +++ b/bluetooth/1.1/default/android.hardware.bluetooth@1.1-service.rc @@ -5,5 +5,5 @@ service vendor.bluetooth-1-1 /vendor/bin/hw/android.hardware.bluetooth@1.1-servi capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE user bluetooth group bluetooth - writepid /dev/stune/foreground/tasks + task_profiles HighPerformance From b74f6423f5976ded0096042266595ddc38f5d944 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Thu, 30 Apr 2020 13:30:47 -0700 Subject: [PATCH 0903/1022] Replace direct pid writes with setting task profiles for audio interfaces For easy transition from SchedTune to UtilClamp, direct access to these cgroups should be abstracted by using task profiles. Replace writepid commands with new task_profiles command. Bug: 155419956 Test: change .rc file and confirm task profile is applied Signed-off-by: Suren Baghdasaryan Change-Id: Ide373c283359cf4b73af4cb0813d8c0306942595 Merged-In: Ide373c283359cf4b73af4cb0813d8c0306942595 --- .../default/service/android.hardware.audio.service.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/audio/common/all-versions/default/service/android.hardware.audio.service.rc b/audio/common/all-versions/default/service/android.hardware.audio.service.rc index 63d2542498..f7e1e244d5 100644 --- a/audio/common/all-versions/default/service/android.hardware.audio.service.rc +++ b/audio/common/all-versions/default/service/android.hardware.audio.service.rc @@ -5,5 +5,5 @@ service vendor.audio-hal /vendor/bin/hw/android.hardware.audio.service group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock capabilities BLOCK_SUSPEND ioprio rt 4 - writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks + task_profiles ProcessCapacityHigh HighPerformance onrestart restart audioserver From 608059a6bc336cbbf6f5c0c344220917a9047228 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Thu, 30 Apr 2020 13:40:40 -0700 Subject: [PATCH 0904/1022] Replace direct pid writes with setting task profiles for camera interfaces For easy transition from SchedTune to UtilClamp, direct access to these cgroups should be abstracted by using task profiles. Replace writepid commands with new task_profiles command. Bug: 155419956 Test: change .rc file and confirm task profile is applied Signed-off-by: Suren Baghdasaryan Change-Id: I2732f7365351f132dbf0566319e3969c2a25b3e4 Merged-In: I2732f7365351f132dbf0566319e3969c2a25b3e4 --- .../android.hardware.camera.provider@2.4-external-service.rc | 2 +- .../android.hardware.camera.provider@2.4-service-lazy.rc | 2 +- .../android.hardware.camera.provider@2.4-service-lazy_64.rc | 2 +- .../2.4/default/android.hardware.camera.provider@2.4-service.rc | 2 +- .../default/android.hardware.camera.provider@2.4-service_64.rc | 2 +- .../android.hardware.camera.provider@2.5-external-service.rc | 2 +- .../android.hardware.camera.provider@2.5-service-lazy.rc | 2 +- .../android.hardware.camera.provider@2.5-service-lazy_64.rc | 2 +- .../2.5/default/android.hardware.camera.provider@2.5-service.rc | 2 +- .../default/android.hardware.camera.provider@2.5-service_64.rc | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-external-service.rc b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-external-service.rc index 64cf321d83..52ade977b3 100644 --- a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-external-service.rc +++ b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-external-service.rc @@ -5,4 +5,4 @@ service vendor.camera-provider-2-4-ext /vendor/bin/hw/android.hardware.camera.pr group audio camera input drmrpc usb ioprio rt 4 capabilities SYS_NICE - writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks + task_profiles CameraServiceCapacity MaxPerformance diff --git a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service-lazy.rc b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service-lazy.rc index e8549ed82d..63ded900c0 100644 --- a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service-lazy.rc +++ b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service-lazy.rc @@ -7,4 +7,4 @@ service vendor.camera-provider-2-4 /vendor/bin/hw/android.hardware.camera.provid group audio camera input drmrpc ioprio rt 4 capabilities SYS_NICE - writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks + task_profiles CameraServiceCapacity MaxPerformance diff --git a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service-lazy_64.rc b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service-lazy_64.rc index 2dfac764eb..953d1af7e4 100644 --- a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service-lazy_64.rc +++ b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service-lazy_64.rc @@ -7,4 +7,4 @@ service vendor.camera-provider-2-4 /vendor/bin/hw/android.hardware.camera.provid group audio camera input drmrpc ioprio rt 4 capabilities SYS_NICE - writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks + task_profiles CameraServiceCapacity MaxPerformance diff --git a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc index 913561b1fe..f7ac9f83e4 100644 --- a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc +++ b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc @@ -5,4 +5,4 @@ service vendor.camera-provider-2-4 /vendor/bin/hw/android.hardware.camera.provid group audio camera input drmrpc ioprio rt 4 capabilities SYS_NICE - writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks + task_profiles CameraServiceCapacity MaxPerformance diff --git a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service_64.rc b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service_64.rc index fd4826ec2c..a32dd468d3 100644 --- a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service_64.rc +++ b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service_64.rc @@ -5,4 +5,4 @@ service vendor.camera-provider-2-4 /vendor/bin/hw/android.hardware.camera.provid group audio camera input drmrpc ioprio rt 4 capabilities SYS_NICE - writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks + task_profiles CameraServiceCapacity MaxPerformance diff --git a/camera/provider/2.5/default/android.hardware.camera.provider@2.5-external-service.rc b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-external-service.rc index 107097e661..b3b06b2391 100644 --- a/camera/provider/2.5/default/android.hardware.camera.provider@2.5-external-service.rc +++ b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-external-service.rc @@ -6,4 +6,4 @@ service vendor.camera-provider-2-5-ext /vendor/bin/hw/android.hardware.camera.pr group audio camera input drmrpc usb ioprio rt 4 capabilities SYS_NICE - writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks + task_profiles CameraServiceCapacity MaxPerformance diff --git a/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy.rc b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy.rc index b45158a082..7c5e69b070 100644 --- a/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy.rc +++ b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy.rc @@ -8,4 +8,4 @@ service vendor.camera-provider-2-5 /vendor/bin/hw/android.hardware.camera.provid group audio camera input drmrpc ioprio rt 4 capabilities SYS_NICE - writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks + task_profiles CameraServiceCapacity MaxPerformance diff --git a/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy_64.rc b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy_64.rc index 955b28e6b4..49bca8f93c 100644 --- a/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy_64.rc +++ b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy_64.rc @@ -8,4 +8,4 @@ service vendor.camera-provider-2-5 /vendor/bin/hw/android.hardware.camera.provid group audio camera input drmrpc ioprio rt 4 capabilities SYS_NICE - writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks + task_profiles CameraServiceCapacity MaxPerformance diff --git a/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service.rc b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service.rc index c065815fab..4bd1fb4078 100644 --- a/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service.rc +++ b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service.rc @@ -6,4 +6,4 @@ service vendor.camera-provider-2-5 /vendor/bin/hw/android.hardware.camera.provid group audio camera input drmrpc ioprio rt 4 capabilities SYS_NICE - writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks + task_profiles CameraServiceCapacity MaxPerformance diff --git a/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service_64.rc b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service_64.rc index 63dd11d349..b4443256cf 100644 --- a/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service_64.rc +++ b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service_64.rc @@ -6,4 +6,4 @@ service vendor.camera-provider-2-5 /vendor/bin/hw/android.hardware.camera.provid group audio camera input drmrpc ioprio rt 4 capabilities SYS_NICE - writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks + task_profiles CameraServiceCapacity MaxPerformance From 12ab6c57cc6a2b9ac48e0a927a7e4d55330372a2 Mon Sep 17 00:00:00 2001 From: David Gross Date: Mon, 14 May 2018 12:23:04 -0700 Subject: [PATCH 0905/1022] More tests for graph validation. - detect cycle (CycleTest) - detect bad execution order (mutateExecutionOrderTest) - detect lifetime inconsistent with whether operand is written (mutateOperandLifeTimeTest) - detect lifetime inconsistent with Model inputIndexes/outputIndexes (mutateOperandInputOutputTest) - detect incorrect number of consumers (mutateOperandNumberOfConsumersTest) - detect operand written multiple times (mutateOperandAddWriterTest) - detect operand never written (mutateOperationRemoveWriteTest) Bug: 66478689 Test: VtsHalNeuralnetworksV1_*TargetTest Change-Id: Id4ba19660bbd31a16f8a675f7b6437f4d779e8da Merged-In: Id4ba19660bbd31a16f8a675f7b6437f4d779e8da (cherry picked from commit af51663e9980265853750a51fa2f4bb1cd4e48c1) --- .../1.0/vts/functional/BasicTests.cpp | 136 +++++ neuralnetworks/1.0/vts/functional/Utils.cpp | 43 ++ .../1.0/vts/functional/ValidateModel.cpp | 489 +++++++++++++++- .../1.0/vts/functional/include/1.0/Utils.h | 22 + .../1.1/vts/functional/BasicTests.cpp | 139 +++++ .../1.1/vts/functional/ValidateModel.cpp | 482 +++++++++++++++- neuralnetworks/1.2/vts/functional/Android.bp | 5 +- .../1.2/vts/functional/BasicTests.cpp | 139 +++++ neuralnetworks/1.2/vts/functional/Utils.cpp | 85 +++ .../1.2/vts/functional/ValidateModel.cpp | 520 ++++++++++++++++- .../1.2/vts/functional/include/1.2/Utils.h | 42 ++ neuralnetworks/1.3/vts/functional/Android.bp | 2 +- .../1.3/vts/functional/BasicTests.cpp | 142 +++++ neuralnetworks/1.3/vts/functional/Utils.cpp | 71 ++- .../1.3/vts/functional/ValidateModel.cpp | 538 +++++++++++++++++- .../1.3/vts/functional/include/1.3/Utils.h | 12 + 16 files changed, 2838 insertions(+), 29 deletions(-) create mode 100644 neuralnetworks/1.2/vts/functional/Utils.cpp create mode 100644 neuralnetworks/1.2/vts/functional/include/1.2/Utils.h diff --git a/neuralnetworks/1.0/vts/functional/BasicTests.cpp b/neuralnetworks/1.0/vts/functional/BasicTests.cpp index cc44c9efe1..bda43b1986 100644 --- a/neuralnetworks/1.0/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.0/vts/functional/BasicTests.cpp @@ -18,8 +18,12 @@ #include "VtsHalNeuralnetworks.h" +#include "1.0/Callbacks.h" + namespace android::hardware::neuralnetworks::V1_0::vts::functional { +using implementation::PreparedModelCallback; + // create device test TEST_P(NeuralnetworksHidlTest, CreateDevice) {} @@ -43,4 +47,136 @@ TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) { EXPECT_TRUE(ret.isOk()); } +// detect cycle +TEST_P(NeuralnetworksHidlTest, CycleTest) { + // opnd0 = TENSOR_FLOAT32 // model input + // opnd1 = TENSOR_FLOAT32 // model input + // opnd2 = INT32 // model input + // opnd3 = ADD(opnd0, opnd4, opnd2) + // opnd4 = ADD(opnd1, opnd3, opnd2) + // opnd5 = ADD(opnd4, opnd0, opnd2) // model output + // + // +-----+ + // | | + // v | + // 3 = ADD(0, 4, 2) | + // | | + // +----------+ | + // | | + // v | + // 4 = ADD(1, 3, 2) | + // | | + // +----------------+ + // | + // | + // +-------+ + // | + // v + // 5 = ADD(4, 0, 2) + + const std::vector operands = { + { + // operands[0] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 2, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[1] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[2] + .type = OperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 3, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[3] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::TEMPORARY_VARIABLE, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[4] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 2, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::TEMPORARY_VARIABLE, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[5] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 0, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_OUTPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + }; + + const std::vector operations = { + {.type = OperationType::ADD, .inputs = {0, 4, 2}, .outputs = {3}}, + {.type = OperationType::ADD, .inputs = {1, 3, 2}, .outputs = {4}}, + {.type = OperationType::ADD, .inputs = {4, 0, 2}, .outputs = {5}}, + }; + + const Model model = { + .operands = operands, + .operations = operations, + .inputIndexes = {0, 1, 2}, + .outputIndexes = {5}, + .operandValues = {}, + .pools = {}, + }; + + // ensure that getSupportedOperations() checks model validity + ErrorStatus supportedOpsErrorStatus = ErrorStatus::GENERAL_FAILURE; + Return supportedOpsReturn = kDevice->getSupportedOperations( + model, [&model, &supportedOpsErrorStatus](ErrorStatus status, + const hidl_vec& supported) { + supportedOpsErrorStatus = status; + if (status == ErrorStatus::NONE) { + ASSERT_EQ(supported.size(), model.operations.size()); + } + }); + ASSERT_TRUE(supportedOpsReturn.isOk()); + ASSERT_EQ(supportedOpsErrorStatus, ErrorStatus::INVALID_ARGUMENT); + + // ensure that prepareModel() checks model validity + sp preparedModelCallback = new PreparedModelCallback; + Return prepareLaunchReturn = kDevice->prepareModel(model, preparedModelCallback); + ASSERT_TRUE(prepareLaunchReturn.isOk()); + // Note that preparation can fail for reasons other than an + // invalid model (invalid model should result in + // INVALID_ARGUMENT) -- for example, perhaps not all + // operations are supported, or perhaps the device hit some + // kind of capacity limit. + EXPECT_NE(prepareLaunchReturn, ErrorStatus::NONE); + EXPECT_NE(preparedModelCallback->getStatus(), ErrorStatus::NONE); + EXPECT_EQ(preparedModelCallback->getPreparedModel(), nullptr); +} + } // namespace android::hardware::neuralnetworks::V1_0::vts::functional diff --git a/neuralnetworks/1.0/vts/functional/Utils.cpp b/neuralnetworks/1.0/vts/functional/Utils.cpp index 3613e69088..32850b060c 100644 --- a/neuralnetworks/1.0/vts/functional/Utils.cpp +++ b/neuralnetworks/1.0/vts/functional/Utils.cpp @@ -29,7 +29,11 @@ #include #include +#include +#include #include +#include +#include #include namespace android::hardware::neuralnetworks { @@ -172,6 +176,45 @@ std::vector ExecutionContext::getOutputBuffers(const Request& reques return outputBuffers; } +uint32_t sizeOfData(V1_0::OperandType type) { + switch (type) { + case V1_0::OperandType::FLOAT32: + case V1_0::OperandType::INT32: + case V1_0::OperandType::UINT32: + case V1_0::OperandType::TENSOR_FLOAT32: + case V1_0::OperandType::TENSOR_INT32: + return 4; + case V1_0::OperandType::TENSOR_QUANT8_ASYMM: + return 1; + default: + CHECK(false) << "Invalid OperandType " << static_cast(type); + return 0; + } +} + +static bool isTensor(V1_0::OperandType type) { + switch (type) { + case V1_0::OperandType::FLOAT32: + case V1_0::OperandType::INT32: + case V1_0::OperandType::UINT32: + return false; + case V1_0::OperandType::TENSOR_FLOAT32: + case V1_0::OperandType::TENSOR_INT32: + case V1_0::OperandType::TENSOR_QUANT8_ASYMM: + return true; + default: + CHECK(false) << "Invalid OperandType " << static_cast(type); + return false; + } +} + +uint32_t sizeOfData(const V1_0::Operand& operand) { + const uint32_t dataSize = sizeOfData(operand.type); + if (isTensor(operand.type) && operand.dimensions.size() == 0) return 0; + return std::accumulate(operand.dimensions.begin(), operand.dimensions.end(), dataSize, + std::multiplies<>{}); +} + std::string gtestCompliantName(std::string name) { // gtest test names must only contain alphanumeric characters std::replace_if( diff --git a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp index 79d85943b1..5ffbd4328c 100644 --- a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp @@ -17,9 +17,14 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" #include "1.0/Callbacks.h" +#include "1.0/Utils.h" #include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" +#include +#include +#include + namespace android::hardware::neuralnetworks::V1_0::vts::functional { using implementation::PreparedModelCallback; @@ -67,26 +72,6 @@ static void validate(const sp& device, const std::string& message, validatePrepareModel(device, message, model); } -// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation, -// so this is efficiently accomplished by moving the element to the end and -// resizing the hidl_vec to one less. -template -static void hidl_vec_removeAt(hidl_vec* vec, uint32_t index) { - if (vec) { - std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end()); - vec->resize(vec->size() - 1); - } -} - -template -static uint32_t hidl_vec_push_back(hidl_vec* vec, const Type& value) { - // assume vec is valid - const uint32_t index = vec->size(); - vec->resize(index + 1); - (*vec)[index] = value; - return index; -} - static uint32_t addOperand(Model* model) { return hidl_vec_push_back(&model->operands, { @@ -107,6 +92,211 @@ static uint32_t addOperand(Model* model, OperandLifeTime lifetime) { return index; } +// If we introduce a CONSTANT_COPY for an operand of size operandSize, +// how much will this increase the size of the model? This assumes +// that we can (re)use all of model.operandValues for the operand +// value. +static size_t constantCopyExtraSize(const Model& model, size_t operandSize) { + const size_t operandValuesSize = model.operandValues.size(); + return (operandValuesSize < operandSize) ? (operandSize - operandValuesSize) : 0; +} + +// Highly specialized utility routine for converting an operand to +// CONSTANT_COPY lifetime. +// +// Expects that: +// - operand has a known size +// - operand->lifetime has already been set to CONSTANT_COPY +// - operand->location has been zeroed out +// +// Does the following: +// - initializes operand->location to point to the beginning of model->operandValues +// - resizes model->operandValues (if necessary) to be large enough for the operand +// value, padding it with zeroes on the end +// +// Potential problem: +// By changing the operand to CONSTANT_COPY lifetime, this function is effectively initializing the +// operand with unspecified (but deterministic) data. This means that the model may be invalidated +// in two ways: not only is the lifetime of CONSTANT_COPY invalid, but the operand's value in the +// graph may also be invalid (e.g., if the operand is used as an activation code and has an invalid +// value). For now, this should be fine because it just means we're not testing what we think we're +// testing in certain cases; but we can handwave this and assume we're probabilistically likely to +// exercise the validation code over the span of the entire test set and operand space. +// +// Aborts if the specified operand type is an extension type or OEM type. +static void becomeConstantCopy(Model* model, Operand* operand) { + // sizeOfData will abort if the specified type is an extension type or OEM type. + const size_t sizeOfOperand = sizeOfData(*operand); + EXPECT_NE(sizeOfOperand, size_t(0)); + operand->location.poolIndex = 0; + operand->location.offset = 0; + operand->location.length = sizeOfOperand; + if (model->operandValues.size() < sizeOfOperand) { + model->operandValues.resize(sizeOfOperand); + } +} + +// The sizeForBinder() functions estimate the size of the +// representation of a value when sent to binder. It's probably a bit +// of an under-estimate, because we don't know the size of the +// metadata in the binder format (e.g., representation of the size of +// a vector); but at least it adds up "big" things like vector +// contents. However, it doesn't treat inter-field or end-of-struct +// padding in a methodical way -- there's no attempt to be consistent +// in whether or not padding in the native (C++) representation +// contributes to the estimated size for the binder representation; +// and there's no attempt to understand what padding (if any) is +// needed in the binder representation. +// +// This assumes that non-metadata uses a fixed length encoding (e.g., +// a uint32_t is always encoded in sizeof(uint32_t) bytes, rather than +// using an encoding whose length is related to the magnitude of the +// encoded value). + +template +static size_t sizeForBinder(const Type& val) { + static_assert(std::is_trivially_copyable_v>, + "expected a trivially copyable type"); + return sizeof(val); +} + +template +static size_t sizeForBinder(const hidl_vec& vec) { + return std::accumulate(vec.begin(), vec.end(), 0, + [](size_t acc, const Type& x) { return acc + sizeForBinder(x); }); +} + +template <> +size_t sizeForBinder(const Operand& operand) { + size_t size = 0; + + size += sizeForBinder(operand.type); + size += sizeForBinder(operand.dimensions); + size += sizeForBinder(operand.numberOfConsumers); + size += sizeForBinder(operand.scale); + size += sizeForBinder(operand.zeroPoint); + size += sizeForBinder(operand.lifetime); + size += sizeForBinder(operand.location); + + return size; +} + +template <> +size_t sizeForBinder(const Operation& operation) { + size_t size = 0; + + size += sizeForBinder(operation.type); + size += sizeForBinder(operation.inputs); + size += sizeForBinder(operation.outputs); + + return size; +} + +template <> +size_t sizeForBinder(const hidl_string& name) { + return name.size(); +} + +template <> +size_t sizeForBinder(const hidl_memory& memory) { + // This is just a guess. + + size_t size = 0; + + if (const native_handle_t* handle = memory.handle()) { + size += sizeof(*handle); + size += sizeof(handle->data[0] * (handle->numFds + handle->numInts)); + } + size += sizeForBinder(memory.name()); + + return size; +} + +template <> +size_t sizeForBinder(const Model& model) { + size_t size = 0; + + size += sizeForBinder(model.operands); + size += sizeForBinder(model.operations); + size += sizeForBinder(model.inputIndexes); + size += sizeForBinder(model.outputIndexes); + size += sizeForBinder(model.operandValues); + size += sizeForBinder(model.pools); + + return size; +} + +// https://developer.android.com/reference/android/os/TransactionTooLargeException.html +// +// "The Binder transaction buffer has a limited fixed size, +// currently 1Mb, which is shared by all transactions in progress +// for the process." +// +// Will our representation fit under this limit? There are two complications: +// - Our representation size is just approximate (see sizeForBinder()). +// - This object may not be the only occupant of the Binder transaction buffer. +// So we'll be very conservative: We want the representation size to be no +// larger than half the transaction buffer size. +// +// If our representation grows large enough that it still fits within +// the transaction buffer but combined with other transactions may +// exceed the buffer size, then we may see intermittent HAL transport +// errors. +static bool exceedsBinderSizeLimit(size_t representationSize) { + // Instead of using this fixed buffer size, we might instead be able to use + // ProcessState::self()->getMmapSize(). However, this has a potential + // problem: The binder/mmap size of the current process does not necessarily + // indicate the binder/mmap size of the service (i.e., the other process). + // The only way it would be a good indication is if both the current process + // and the service use the default size. + static const size_t kHalfBufferSize = 1024 * 1024 / 2; + + return representationSize > kHalfBufferSize; +} + +///////////////////////// VALIDATE EXECUTION ORDER //////////////////////////// + +static void mutateExecutionOrderTest(const sp& device, const V1_0::Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + const Operation& operationObj = model.operations[operation]; + for (uint32_t input : operationObj.inputs) { + if (model.operands[input].lifetime == OperandLifeTime::TEMPORARY_VARIABLE || + model.operands[input].lifetime == OperandLifeTime::MODEL_OUTPUT) { + // This operation reads an operand written by some + // other operation. Move this operation to the + // beginning of the sequence, ensuring that it reads + // the operand before that operand is written, thereby + // violating execution order rules. + const std::string message = "mutateExecutionOrderTest: operation " + + std::to_string(operation) + " is a reader"; + validate(device, message, model, [operation](Model* model) { + auto& operations = model->operations; + std::rotate(operations.begin(), operations.begin() + operation, + operations.begin() + operation + 1); + }); + break; // only need to do this once per operation + } + } + for (uint32_t output : operationObj.outputs) { + if (model.operands[output].numberOfConsumers > 0) { + // This operation writes an operand read by some other + // operation. Move this operation to the end of the + // sequence, ensuring that it writes the operand after + // that operand is read, thereby violating execution + // order rules. + const std::string message = "mutateExecutionOrderTest: operation " + + std::to_string(operation) + " is a writer"; + validate(device, message, model, [operation](Model* model) { + auto& operations = model->operations; + std::rotate(operations.begin() + operation, operations.begin() + operation + 1, + operations.end()); + }); + break; // only need to do this once per operation + } + } + } +} + ///////////////////////// VALIDATE MODEL OPERAND TYPE ///////////////////////// static const int32_t invalidOperandTypes[] = { @@ -218,9 +408,233 @@ static void mutateOperandZeroPointTest(const sp& device, const Model& m } } +///////////////////////// VALIDATE OPERAND LIFETIME ///////////////////////////////////////////// + +static std::vector getInvalidLifeTimes(const Model& model, size_t modelSize, + const Operand& operand) { + // TODO: Support OperandLifeTime::CONSTANT_REFERENCE as an invalid lifetime + // TODO: Support OperandLifeTime::NO_VALUE as an invalid lifetime + + // Ways to get an invalid lifetime: + // - change whether a lifetime means an operand should have a writer + std::vector ret; + switch (operand.lifetime) { + case OperandLifeTime::MODEL_OUTPUT: + case OperandLifeTime::TEMPORARY_VARIABLE: + ret = { + OperandLifeTime::MODEL_INPUT, + OperandLifeTime::CONSTANT_COPY, + }; + break; + case OperandLifeTime::CONSTANT_COPY: + case OperandLifeTime::CONSTANT_REFERENCE: + case OperandLifeTime::MODEL_INPUT: + ret = { + OperandLifeTime::TEMPORARY_VARIABLE, + OperandLifeTime::MODEL_OUTPUT, + }; + break; + case OperandLifeTime::NO_VALUE: + // Not enough information to know whether + // TEMPORARY_VARIABLE or CONSTANT_COPY would be invalid -- + // is this operand written (then CONSTANT_COPY would be + // invalid) or not (then TEMPORARY_VARIABLE would be + // invalid)? + break; + default: + ADD_FAILURE(); + break; + } + + const size_t operandSize = sizeOfData(operand); // will be zero if shape is unknown + if (!operandSize || + exceedsBinderSizeLimit(modelSize + constantCopyExtraSize(model, operandSize))) { + // Unknown size or too-large size + ret.erase(std::remove(ret.begin(), ret.end(), OperandLifeTime::CONSTANT_COPY), ret.end()); + } + + return ret; +} + +static void mutateOperandLifeTimeTest(const sp& device, const V1_0::Model& model) { + const size_t modelSize = sizeForBinder(model); + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + const std::vector invalidLifeTimes = + getInvalidLifeTimes(model, modelSize, model.operands[operand]); + for (OperandLifeTime invalidLifeTime : invalidLifeTimes) { + const std::string message = "mutateOperandLifetimeTest: operand " + + std::to_string(operand) + " has lifetime " + + toString(invalidLifeTime) + " instead of lifetime " + + toString(model.operands[operand].lifetime); + validate(device, message, model, [operand, invalidLifeTime](Model* model) { + static const DataLocation kZeroDataLocation = {}; + Operand& operandObj = model->operands[operand]; + switch (operandObj.lifetime) { + case OperandLifeTime::MODEL_INPUT: { + hidl_vec_remove(&model->inputIndexes, uint32_t(operand)); + break; + } + case OperandLifeTime::MODEL_OUTPUT: { + hidl_vec_remove(&model->outputIndexes, uint32_t(operand)); + break; + } + default: + break; + } + operandObj.lifetime = invalidLifeTime; + operandObj.location = kZeroDataLocation; + switch (invalidLifeTime) { + case OperandLifeTime::CONSTANT_COPY: { + becomeConstantCopy(model, &operandObj); + break; + } + case OperandLifeTime::MODEL_INPUT: + hidl_vec_push_back(&model->inputIndexes, uint32_t(operand)); + break; + case OperandLifeTime::MODEL_OUTPUT: + hidl_vec_push_back(&model->outputIndexes, uint32_t(operand)); + break; + default: + break; + } + }); + } + } +} + +///////////////////////// VALIDATE OPERAND INPUT-or-OUTPUT ////////////////////////////////////// + +static std::optional getInputOutputLifeTime(const Model& model, size_t modelSize, + const Operand& operand) { + // Ways to get an invalid lifetime (with respect to model inputIndexes and outputIndexes): + // - change whether a lifetime means an operand is a model input, a model output, or neither + // - preserve whether or not a lifetime means an operand should have a writer + switch (operand.lifetime) { + case OperandLifeTime::CONSTANT_COPY: + case OperandLifeTime::CONSTANT_REFERENCE: + return OperandLifeTime::MODEL_INPUT; + case OperandLifeTime::MODEL_INPUT: { + const size_t operandSize = sizeOfData(operand); // will be zero if shape is unknown + if (!operandSize || + exceedsBinderSizeLimit(modelSize + constantCopyExtraSize(model, operandSize))) { + // Unknown size or too-large size + break; + } + return OperandLifeTime::CONSTANT_COPY; + } + case OperandLifeTime::MODEL_OUTPUT: + return OperandLifeTime::TEMPORARY_VARIABLE; + case OperandLifeTime::TEMPORARY_VARIABLE: + return OperandLifeTime::MODEL_OUTPUT; + case OperandLifeTime::NO_VALUE: + // Not enough information to know whether + // TEMPORARY_VARIABLE or CONSTANT_COPY would be an + // appropriate choice -- is this operand written (then + // TEMPORARY_VARIABLE would be appropriate) or not (then + // CONSTANT_COPY would be appropriate)? + break; + default: + ADD_FAILURE(); + break; + } + + return std::nullopt; +} + +static void mutateOperandInputOutputTest(const sp& device, const V1_0::Model& model) { + const size_t modelSize = sizeForBinder(model); + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + const std::optional changedLifeTime = + getInputOutputLifeTime(model, modelSize, model.operands[operand]); + if (changedLifeTime) { + const std::string message = "mutateOperandInputOutputTest: operand " + + std::to_string(operand) + " has lifetime " + + toString(*changedLifeTime) + " instead of lifetime " + + toString(model.operands[operand].lifetime); + validate(device, message, model, [operand, changedLifeTime](Model* model) { + static const DataLocation kZeroDataLocation = {}; + Operand& operandObj = model->operands[operand]; + operandObj.lifetime = *changedLifeTime; + operandObj.location = kZeroDataLocation; + if (*changedLifeTime == OperandLifeTime::CONSTANT_COPY) { + becomeConstantCopy(model, &operandObj); + } + }); + } + } +} + +///////////////////////// VALIDATE OPERAND NUMBER OF CONSUMERS ////////////////////////////////// + +static std::vector getInvalidNumberOfConsumers(uint32_t numberOfConsumers) { + if (numberOfConsumers == 0) { + return {1}; + } else { + return {numberOfConsumers - 1, numberOfConsumers + 1}; + } +} + +static void mutateOperandNumberOfConsumersTest(const sp& device, + const V1_0::Model& model) { + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + const std::vector invalidNumberOfConsumersVec = + getInvalidNumberOfConsumers(model.operands[operand].numberOfConsumers); + for (uint32_t invalidNumberOfConsumers : invalidNumberOfConsumersVec) { + const std::string message = + "mutateOperandNumberOfConsumersTest: operand " + std::to_string(operand) + + " numberOfConsumers = " + std::to_string(invalidNumberOfConsumers); + validate(device, message, model, [operand, invalidNumberOfConsumers](Model* model) { + model->operands[operand].numberOfConsumers = invalidNumberOfConsumers; + }); + } + } +} + +///////////////////////// VALIDATE OPERAND NUMBER OF WRITERS //////////////////////////////////// + +static void mutateOperandAddWriterTest(const sp& device, const V1_0::Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + for (size_t badOutputNum = 0; badOutputNum < model.operations[operation].outputs.size(); + ++badOutputNum) { + const uint32_t outputOperandIndex = model.operations[operation].outputs[badOutputNum]; + const std::string message = "mutateOperandAddWriterTest: operation " + + std::to_string(operation) + " writes to " + + std::to_string(outputOperandIndex); + // We'll insert a copy of the operation, all of whose + // OTHER output operands are newly-created -- i.e., + // there'll only be a duplicate write of ONE of that + // operation's output operands. + validate(device, message, model, [operation, badOutputNum](Model* model) { + Operation newOperation = model->operations[operation]; + for (uint32_t input : newOperation.inputs) { + ++model->operands[input].numberOfConsumers; + } + for (size_t outputNum = 0; outputNum < newOperation.outputs.size(); ++outputNum) { + if (outputNum == badOutputNum) continue; + + Operand operandValue = model->operands[newOperation.outputs[outputNum]]; + operandValue.numberOfConsumers = 0; + if (operandValue.lifetime == OperandLifeTime::MODEL_OUTPUT) { + operandValue.lifetime = OperandLifeTime::TEMPORARY_VARIABLE; + } else { + ASSERT_EQ(operandValue.lifetime, OperandLifeTime::TEMPORARY_VARIABLE); + } + newOperation.outputs[outputNum] = + hidl_vec_push_back(&model->operands, operandValue); + } + // Where do we insert the extra writer (a new + // operation)? It has to be later than all the + // writers of its inputs. The easiest thing to do + // is to insert it at the end of the operation + // sequence. + hidl_vec_push_back(&model->operations, newOperation); + }); + } + } +} + ///////////////////////// VALIDATE EXTRA ??? ///////////////////////// -// TODO: Operand::lifetime // TODO: Operand::location ///////////////////////// VALIDATE OPERATION OPERAND TYPE ///////////////////////// @@ -351,6 +765,33 @@ static void mutateOperationOutputOperandIndexTest(const sp& device, con } } +///////////////////////// VALIDATE MODEL OPERANDS WRITTEN /////////////////////////////////////// + +static void mutateOperationRemoveWriteTest(const sp& device, const V1_0::Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + for (size_t outputNum = 0; outputNum < model.operations[operation].outputs.size(); + ++outputNum) { + const uint32_t outputOperandIndex = model.operations[operation].outputs[outputNum]; + if (model.operands[outputOperandIndex].numberOfConsumers > 0) { + const std::string message = "mutateOperationRemoveWriteTest: operation " + + std::to_string(operation) + " writes to " + + std::to_string(outputOperandIndex); + validate(device, message, model, [operation, outputNum](Model* model) { + uint32_t& outputOperandIndex = model->operations[operation].outputs[outputNum]; + Operand operandValue = model->operands[outputOperandIndex]; + operandValue.numberOfConsumers = 0; + if (operandValue.lifetime == OperandLifeTime::MODEL_OUTPUT) { + operandValue.lifetime = OperandLifeTime::TEMPORARY_VARIABLE; + } else { + ASSERT_EQ(operandValue.lifetime, OperandLifeTime::TEMPORARY_VARIABLE); + } + outputOperandIndex = hidl_vec_push_back(&model->operands, operandValue); + }); + } + } + } +} + ///////////////////////// REMOVE OPERAND FROM EVERYTHING ///////////////////////// static void removeValueAndDecrementGreaterValues(hidl_vec* vec, uint32_t value) { @@ -476,14 +917,20 @@ static void addOperationOutputTest(const sp& device, const Model& model ////////////////////////// ENTRY POINT ////////////////////////////// void validateModel(const sp& device, const Model& model) { + mutateExecutionOrderTest(device, model); mutateOperandTypeTest(device, model); mutateOperandRankTest(device, model); mutateOperandScaleTest(device, model); mutateOperandZeroPointTest(device, model); + mutateOperandLifeTimeTest(device, model); + mutateOperandInputOutputTest(device, model); + mutateOperandNumberOfConsumersTest(device, model); + mutateOperandAddWriterTest(device, model); mutateOperationOperandTypeTest(device, model); mutateOperationTypeTest(device, model); mutateOperationInputOperandIndexTest(device, model); mutateOperationOutputOperandIndexTest(device, model); + mutateOperationRemoveWriteTest(device, model); removeOperandTest(device, model); removeOperationTest(device, model); removeOperationInputTest(device, model); diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h index 3292f79b1a..7bd0460b82 100644 --- a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h +++ b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -108,6 +109,15 @@ inline void hidl_vec_removeAt(hidl_vec* vec, uint32_t index) { vec->resize(vec->size() - 1); } +// Assumes there is exactly one instance of the value in the vector. +template +inline void hidl_vec_remove(hidl_vec* vec, const Type& val) { + CHECK(vec != nullptr); + auto where = std::find(vec->begin(), vec->end(), val); + ASSERT_NE(where, vec->end()); + hidl_vec_removeAt(vec, where - vec->begin()); +} + template inline uint32_t hidl_vec_push_back(hidl_vec* vec, const Type& value) { CHECK(vec != nullptr); @@ -117,6 +127,18 @@ inline uint32_t hidl_vec_push_back(hidl_vec* vec, const Type& value) { return index; } +// Returns the amount of space needed to store a value of the specified type. +// +// Aborts if the specified type is an extension type or OEM type. +uint32_t sizeOfData(V1_0::OperandType type); + +// Returns the amount of space needed to store a value of the dimensions and +// type of this operand. For a non-extension, non-OEM tensor with unspecified +// rank or at least one unspecified dimension, returns zero. +// +// Aborts if the specified type is an extension type or OEM type. +uint32_t sizeOfData(const V1_0::Operand& operand); + template using Named = std::pair; diff --git a/neuralnetworks/1.1/vts/functional/BasicTests.cpp b/neuralnetworks/1.1/vts/functional/BasicTests.cpp index 44836f0c95..baadd1b23b 100644 --- a/neuralnetworks/1.1/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.1/vts/functional/BasicTests.cpp @@ -18,10 +18,16 @@ #include "VtsHalNeuralnetworks.h" +#include "1.0/Callbacks.h" + namespace android::hardware::neuralnetworks::V1_1::vts::functional { using V1_0::DeviceStatus; using V1_0::ErrorStatus; +using V1_0::Operand; +using V1_0::OperandLifeTime; +using V1_0::OperandType; +using V1_0::implementation::PreparedModelCallback; // create device test TEST_P(NeuralnetworksHidlTest, CreateDevice) {} @@ -48,4 +54,137 @@ TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) { EXPECT_TRUE(ret.isOk()); } +// detect cycle +TEST_P(NeuralnetworksHidlTest, CycleTest) { + // opnd0 = TENSOR_FLOAT32 // model input + // opnd1 = TENSOR_FLOAT32 // model input + // opnd2 = INT32 // model input + // opnd3 = ADD(opnd0, opnd4, opnd2) + // opnd4 = ADD(opnd1, opnd3, opnd2) + // opnd5 = ADD(opnd4, opnd0, opnd2) // model output + // + // +-----+ + // | | + // v | + // 3 = ADD(0, 4, 2) | + // | | + // +----------+ | + // | | + // v | + // 4 = ADD(1, 3, 2) | + // | | + // +----------------+ + // | + // | + // +-------+ + // | + // v + // 5 = ADD(4, 0, 2) + + const std::vector operands = { + { + // operands[0] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 2, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[1] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[2] + .type = OperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 3, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[3] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::TEMPORARY_VARIABLE, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[4] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 2, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::TEMPORARY_VARIABLE, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[5] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 0, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_OUTPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + }; + + const std::vector operations = { + {.type = OperationType::ADD, .inputs = {0, 4, 2}, .outputs = {3}}, + {.type = OperationType::ADD, .inputs = {1, 3, 2}, .outputs = {4}}, + {.type = OperationType::ADD, .inputs = {4, 0, 2}, .outputs = {5}}, + }; + + const Model model = { + .operands = operands, + .operations = operations, + .inputIndexes = {0, 1, 2}, + .outputIndexes = {5}, + .operandValues = {}, + .pools = {}, + }; + + // ensure that getSupportedOperations_1_1() checks model validity + ErrorStatus supportedOpsErrorStatus = ErrorStatus::GENERAL_FAILURE; + Return supportedOpsReturn = kDevice->getSupportedOperations_1_1( + model, [&model, &supportedOpsErrorStatus](ErrorStatus status, + const hidl_vec& supported) { + supportedOpsErrorStatus = status; + if (status == ErrorStatus::NONE) { + ASSERT_EQ(supported.size(), model.operations.size()); + } + }); + ASSERT_TRUE(supportedOpsReturn.isOk()); + ASSERT_EQ(supportedOpsErrorStatus, ErrorStatus::INVALID_ARGUMENT); + + // ensure that prepareModel_1_1() checks model validity + sp preparedModelCallback = new PreparedModelCallback; + Return prepareLaunchReturn = kDevice->prepareModel_1_1( + model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback); + ASSERT_TRUE(prepareLaunchReturn.isOk()); + // Note that preparation can fail for reasons other than an + // invalid model (invalid model should result in + // INVALID_ARGUMENT) -- for example, perhaps not all + // operations are supported, or perhaps the device hit some + // kind of capacity limit. + EXPECT_NE(prepareLaunchReturn, ErrorStatus::NONE); + EXPECT_NE(preparedModelCallback->getStatus(), ErrorStatus::NONE); + EXPECT_EQ(preparedModelCallback->getPreparedModel(), nullptr); +} + } // namespace android::hardware::neuralnetworks::V1_1::vts::functional diff --git a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp index 3b6f0f8300..1f4e4eda49 100644 --- a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp @@ -16,13 +16,19 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" +#include #include "1.0/Callbacks.h" #include "1.0/Utils.h" #include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" +#include +#include +#include + namespace android::hardware::neuralnetworks::V1_1::vts::functional { +using V1_0::DataLocation; using V1_0::ErrorStatus; using V1_0::IPreparedModel; using V1_0::Operand; @@ -105,6 +111,212 @@ static uint32_t addOperand(Model* model, OperandLifeTime lifetime) { return index; } +// If we introduce a CONSTANT_COPY for an operand of size operandSize, +// how much will this increase the size of the model? This assumes +// that we can (re)use all of model.operandValues for the operand +// value. +static size_t constantCopyExtraSize(const Model& model, size_t operandSize) { + const size_t operandValuesSize = model.operandValues.size(); + return (operandValuesSize < operandSize) ? (operandSize - operandValuesSize) : 0; +} + +// Highly specialized utility routine for converting an operand to +// CONSTANT_COPY lifetime. +// +// Expects that: +// - operand has a known size +// - operand->lifetime has already been set to CONSTANT_COPY +// - operand->location has been zeroed out +// +// Does the following: +// - initializes operand->location to point to the beginning of model->operandValues +// - resizes model->operandValues (if necessary) to be large enough for the operand +// value, padding it with zeroes on the end +// +// Potential problem: +// By changing the operand to CONSTANT_COPY lifetime, this function is effectively initializing the +// operand with unspecified (but deterministic) data. This means that the model may be invalidated +// in two ways: not only is the lifetime of CONSTANT_COPY invalid, but the operand's value in the +// graph may also be invalid (e.g., if the operand is used as an activation code and has an invalid +// value). For now, this should be fine because it just means we're not testing what we think we're +// testing in certain cases; but we can handwave this and assume we're probabilistically likely to +// exercise the validation code over the span of the entire test set and operand space. +// +// Aborts if the specified operand type is an extension type or OEM type. +static void becomeConstantCopy(Model* model, Operand* operand) { + // sizeOfData will abort if the specified type is an extension type or OEM type. + const size_t sizeOfOperand = sizeOfData(*operand); + EXPECT_NE(sizeOfOperand, size_t(0)); + operand->location.poolIndex = 0; + operand->location.offset = 0; + operand->location.length = sizeOfOperand; + if (model->operandValues.size() < sizeOfOperand) { + model->operandValues.resize(sizeOfOperand); + } +} + +// The sizeForBinder() functions estimate the size of the +// representation of a value when sent to binder. It's probably a bit +// of an under-estimate, because we don't know the size of the +// metadata in the binder format (e.g., representation of the size of +// a vector); but at least it adds up "big" things like vector +// contents. However, it doesn't treat inter-field or end-of-struct +// padding in a methodical way -- there's no attempt to be consistent +// in whether or not padding in the native (C++) representation +// contributes to the estimated size for the binder representation; +// and there's no attempt to understand what padding (if any) is +// needed in the binder representation. +// +// This assumes that non-metadata uses a fixed length encoding (e.g., +// a uint32_t is always encoded in sizeof(uint32_t) bytes, rather than +// using an encoding whose length is related to the magnitude of the +// encoded value). + +template +static size_t sizeForBinder(const Type& val) { + static_assert(std::is_trivially_copyable_v>, + "expected a trivially copyable type"); + return sizeof(val); +} + +template +static size_t sizeForBinder(const hidl_vec& vec) { + return std::accumulate(vec.begin(), vec.end(), 0, + [](size_t acc, const Type& x) { return acc + sizeForBinder(x); }); +} + +template <> +size_t sizeForBinder(const Operand& operand) { + size_t size = 0; + + size += sizeForBinder(operand.type); + size += sizeForBinder(operand.dimensions); + size += sizeForBinder(operand.numberOfConsumers); + size += sizeForBinder(operand.scale); + size += sizeForBinder(operand.zeroPoint); + size += sizeForBinder(operand.lifetime); + size += sizeForBinder(operand.location); + + return size; +} + +template <> +size_t sizeForBinder(const Operation& operation) { + size_t size = 0; + + size += sizeForBinder(operation.type); + size += sizeForBinder(operation.inputs); + size += sizeForBinder(operation.outputs); + + return size; +} + +template <> +size_t sizeForBinder(const hidl_string& name) { + return name.size(); +} + +template <> +size_t sizeForBinder(const hidl_memory& memory) { + // This is just a guess. + + size_t size = 0; + + if (const native_handle_t* handle = memory.handle()) { + size += sizeof(*handle); + size += sizeof(handle->data[0] * (handle->numFds + handle->numInts)); + } + size += sizeForBinder(memory.name()); + + return size; +} + +template <> +size_t sizeForBinder(const Model& model) { + size_t size = 0; + + size += sizeForBinder(model.operands); + size += sizeForBinder(model.operations); + size += sizeForBinder(model.inputIndexes); + size += sizeForBinder(model.outputIndexes); + size += sizeForBinder(model.operandValues); + size += sizeForBinder(model.pools); + size += sizeForBinder(model.relaxComputationFloat32toFloat16); + + return size; +} + +// https://developer.android.com/reference/android/os/TransactionTooLargeException.html +// +// "The Binder transaction buffer has a limited fixed size, +// currently 1Mb, which is shared by all transactions in progress +// for the process." +// +// Will our representation fit under this limit? There are two complications: +// - Our representation size is just approximate (see sizeForBinder()). +// - This object may not be the only occupant of the Binder transaction buffer. +// So we'll be very conservative: We want the representation size to be no +// larger than half the transaction buffer size. +// +// If our representation grows large enough that it still fits within +// the transaction buffer but combined with other transactions may +// exceed the buffer size, then we may see intermittent HAL transport +// errors. +static bool exceedsBinderSizeLimit(size_t representationSize) { + // Instead of using this fixed buffer size, we might instead be able to use + // ProcessState::self()->getMmapSize(). However, this has a potential + // problem: The binder/mmap size of the current process does not necessarily + // indicate the binder/mmap size of the service (i.e., the other process). + // The only way it would be a good indication is if both the current process + // and the service use the default size. + static const size_t kHalfBufferSize = 1024 * 1024 / 2; + + return representationSize > kHalfBufferSize; +} + +///////////////////////// VALIDATE EXECUTION ORDER //////////////////////////// + +static void mutateExecutionOrderTest(const sp& device, const V1_1::Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + const Operation& operationObj = model.operations[operation]; + for (uint32_t input : operationObj.inputs) { + if (model.operands[input].lifetime == OperandLifeTime::TEMPORARY_VARIABLE || + model.operands[input].lifetime == OperandLifeTime::MODEL_OUTPUT) { + // This operation reads an operand written by some + // other operation. Move this operation to the + // beginning of the sequence, ensuring that it reads + // the operand before that operand is written, thereby + // violating execution order rules. + const std::string message = "mutateExecutionOrderTest: operation " + + std::to_string(operation) + " is a reader"; + validate(device, message, model, [operation](Model* model, ExecutionPreference*) { + auto& operations = model->operations; + std::rotate(operations.begin(), operations.begin() + operation, + operations.begin() + operation + 1); + }); + break; // only need to do this once per operation + } + } + for (uint32_t output : operationObj.outputs) { + if (model.operands[output].numberOfConsumers > 0) { + // This operation writes an operand read by some other + // operation. Move this operation to the end of the + // sequence, ensuring that it writes the operand after + // that operand is read, thereby violating execution + // order rules. + const std::string message = "mutateExecutionOrderTest: operation " + + std::to_string(operation) + " is a writer"; + validate(device, message, model, [operation](Model* model, ExecutionPreference*) { + auto& operations = model->operations; + std::rotate(operations.begin() + operation, operations.begin() + operation + 1, + operations.end()); + }); + break; // only need to do this once per operation + } + } + } +} + ///////////////////////// VALIDATE MODEL OPERAND TYPE ///////////////////////// static const int32_t invalidOperandTypes[] = { @@ -221,9 +433,240 @@ static void mutateOperandZeroPointTest(const sp& device, const Model& m } } +///////////////////////// VALIDATE OPERAND LIFETIME ///////////////////////////////////////////// + +static std::vector getInvalidLifeTimes(const Model& model, size_t modelSize, + const Operand& operand) { + // TODO: Support OperandLifeTime::CONSTANT_REFERENCE as an invalid lifetime + // TODO: Support OperandLifeTime::NO_VALUE as an invalid lifetime + + // Ways to get an invalid lifetime: + // - change whether a lifetime means an operand should have a writer + std::vector ret; + switch (operand.lifetime) { + case OperandLifeTime::MODEL_OUTPUT: + case OperandLifeTime::TEMPORARY_VARIABLE: + ret = { + OperandLifeTime::MODEL_INPUT, + OperandLifeTime::CONSTANT_COPY, + }; + break; + case OperandLifeTime::CONSTANT_COPY: + case OperandLifeTime::CONSTANT_REFERENCE: + case OperandLifeTime::MODEL_INPUT: + ret = { + OperandLifeTime::TEMPORARY_VARIABLE, + OperandLifeTime::MODEL_OUTPUT, + }; + break; + case OperandLifeTime::NO_VALUE: + // Not enough information to know whether + // TEMPORARY_VARIABLE or CONSTANT_COPY would be invalid -- + // is this operand written (then CONSTANT_COPY would be + // invalid) or not (then TEMPORARY_VARIABLE would be + // invalid)? + break; + default: + ADD_FAILURE(); + break; + } + + const size_t operandSize = sizeOfData(operand); // will be zero if shape is unknown + if (!operandSize || + exceedsBinderSizeLimit(modelSize + constantCopyExtraSize(model, operandSize))) { + // Unknown size or too-large size + ret.erase(std::remove(ret.begin(), ret.end(), OperandLifeTime::CONSTANT_COPY), ret.end()); + } + + return ret; +} + +static void mutateOperandLifeTimeTest(const sp& device, const V1_1::Model& model) { + const size_t modelSize = sizeForBinder(model); + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + const std::vector invalidLifeTimes = + getInvalidLifeTimes(model, modelSize, model.operands[operand]); + for (OperandLifeTime invalidLifeTime : invalidLifeTimes) { + const std::string message = "mutateOperandLifetimeTest: operand " + + std::to_string(operand) + " has lifetime " + + toString(invalidLifeTime) + " instead of lifetime " + + toString(model.operands[operand].lifetime); + validate(device, message, model, + [operand, invalidLifeTime](Model* model, ExecutionPreference*) { + static const DataLocation kZeroDataLocation = {}; + Operand& operandObj = model->operands[operand]; + switch (operandObj.lifetime) { + case OperandLifeTime::MODEL_INPUT: { + hidl_vec_remove(&model->inputIndexes, uint32_t(operand)); + break; + } + case OperandLifeTime::MODEL_OUTPUT: { + hidl_vec_remove(&model->outputIndexes, uint32_t(operand)); + break; + } + default: + break; + } + operandObj.lifetime = invalidLifeTime; + operandObj.location = kZeroDataLocation; + switch (invalidLifeTime) { + case OperandLifeTime::CONSTANT_COPY: { + becomeConstantCopy(model, &operandObj); + break; + } + case OperandLifeTime::MODEL_INPUT: + hidl_vec_push_back(&model->inputIndexes, uint32_t(operand)); + break; + case OperandLifeTime::MODEL_OUTPUT: + hidl_vec_push_back(&model->outputIndexes, uint32_t(operand)); + break; + default: + break; + } + }); + } + } +} + +///////////////////////// VALIDATE OPERAND INPUT-or-OUTPUT ////////////////////////////////////// + +static std::optional getInputOutputLifeTime(const Model& model, size_t modelSize, + const Operand& operand) { + // Ways to get an invalid lifetime (with respect to model inputIndexes and outputIndexes): + // - change whether a lifetime means an operand is a model input, a model output, or neither + // - preserve whether or not a lifetime means an operand should have a writer + switch (operand.lifetime) { + case OperandLifeTime::CONSTANT_COPY: + case OperandLifeTime::CONSTANT_REFERENCE: + return OperandLifeTime::MODEL_INPUT; + case OperandLifeTime::MODEL_INPUT: { + const size_t operandSize = sizeOfData(operand); // will be zero if shape is unknown + if (!operandSize || + exceedsBinderSizeLimit(modelSize + constantCopyExtraSize(model, operandSize))) { + // Unknown size or too-large size + break; + } + return OperandLifeTime::CONSTANT_COPY; + } + case OperandLifeTime::MODEL_OUTPUT: + return OperandLifeTime::TEMPORARY_VARIABLE; + case OperandLifeTime::TEMPORARY_VARIABLE: + return OperandLifeTime::MODEL_OUTPUT; + case OperandLifeTime::NO_VALUE: + // Not enough information to know whether + // TEMPORARY_VARIABLE or CONSTANT_COPY would be an + // appropriate choice -- is this operand written (then + // TEMPORARY_VARIABLE would be appropriate) or not (then + // CONSTANT_COPY would be appropriate)? + break; + default: + ADD_FAILURE(); + break; + } + + return std::nullopt; +} + +static void mutateOperandInputOutputTest(const sp& device, const V1_1::Model& model) { + const size_t modelSize = sizeForBinder(model); + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + const std::optional changedLifeTime = + getInputOutputLifeTime(model, modelSize, model.operands[operand]); + if (changedLifeTime) { + const std::string message = "mutateOperandInputOutputTest: operand " + + std::to_string(operand) + " has lifetime " + + toString(*changedLifeTime) + " instead of lifetime " + + toString(model.operands[operand].lifetime); + validate(device, message, model, + [operand, changedLifeTime](Model* model, ExecutionPreference*) { + static const DataLocation kZeroDataLocation = {}; + Operand& operandObj = model->operands[operand]; + operandObj.lifetime = *changedLifeTime; + operandObj.location = kZeroDataLocation; + if (*changedLifeTime == OperandLifeTime::CONSTANT_COPY) { + becomeConstantCopy(model, &operandObj); + } + }); + } + } +} + +///////////////////////// VALIDATE OPERAND NUMBER OF CONSUMERS ////////////////////////////////// + +static std::vector getInvalidNumberOfConsumers(uint32_t numberOfConsumers) { + if (numberOfConsumers == 0) { + return {1}; + } else { + return {numberOfConsumers - 1, numberOfConsumers + 1}; + } +} + +static void mutateOperandNumberOfConsumersTest(const sp& device, + const V1_1::Model& model) { + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + const std::vector invalidNumberOfConsumersVec = + getInvalidNumberOfConsumers(model.operands[operand].numberOfConsumers); + for (uint32_t invalidNumberOfConsumers : invalidNumberOfConsumersVec) { + const std::string message = + "mutateOperandNumberOfConsumersTest: operand " + std::to_string(operand) + + " numberOfConsumers = " + std::to_string(invalidNumberOfConsumers); + validate(device, message, model, + [operand, invalidNumberOfConsumers](Model* model, ExecutionPreference*) { + model->operands[operand].numberOfConsumers = invalidNumberOfConsumers; + }); + } + } +} + +///////////////////////// VALIDATE OPERAND NUMBER OF WRITERS //////////////////////////////////// + +static void mutateOperandAddWriterTest(const sp& device, const V1_1::Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + for (size_t badOutputNum = 0; badOutputNum < model.operations[operation].outputs.size(); + ++badOutputNum) { + const uint32_t outputOperandIndex = model.operations[operation].outputs[badOutputNum]; + const std::string message = "mutateOperandAddWriterTest: operation " + + std::to_string(operation) + " writes to " + + std::to_string(outputOperandIndex); + // We'll insert a copy of the operation, all of whose + // OTHER output operands are newly-created -- i.e., + // there'll only be a duplicate write of ONE of that + // operation's output operands. + validate(device, message, model, + [operation, badOutputNum](Model* model, ExecutionPreference*) { + Operation newOperation = model->operations[operation]; + for (uint32_t input : newOperation.inputs) { + ++model->operands[input].numberOfConsumers; + } + for (size_t outputNum = 0; outputNum < newOperation.outputs.size(); + ++outputNum) { + if (outputNum == badOutputNum) continue; + + Operand operandValue = + model->operands[newOperation.outputs[outputNum]]; + operandValue.numberOfConsumers = 0; + if (operandValue.lifetime == OperandLifeTime::MODEL_OUTPUT) { + operandValue.lifetime = OperandLifeTime::TEMPORARY_VARIABLE; + } else { + ASSERT_EQ(operandValue.lifetime, + OperandLifeTime::TEMPORARY_VARIABLE); + } + newOperation.outputs[outputNum] = + hidl_vec_push_back(&model->operands, operandValue); + } + // Where do we insert the extra writer (a new + // operation)? It has to be later than all the + // writers of its inputs. The easiest thing to do + // is to insert it at the end of the operation + // sequence. + hidl_vec_push_back(&model->operations, newOperation); + }); + } + } +} + ///////////////////////// VALIDATE EXTRA ??? ///////////////////////// -// TODO: Operand::lifetime // TODO: Operand::location ///////////////////////// VALIDATE OPERATION OPERAND TYPE ///////////////////////// @@ -358,6 +801,37 @@ static void mutateOperationOutputOperandIndexTest(const sp& device, con } } +///////////////////////// VALIDATE MODEL OPERANDS WRITTEN /////////////////////////////////////// + +static void mutateOperationRemoveWriteTest(const sp& device, const V1_1::Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + for (size_t outputNum = 0; outputNum < model.operations[operation].outputs.size(); + ++outputNum) { + const uint32_t outputOperandIndex = model.operations[operation].outputs[outputNum]; + if (model.operands[outputOperandIndex].numberOfConsumers > 0) { + const std::string message = "mutateOperationRemoveWriteTest: operation " + + std::to_string(operation) + " writes to " + + std::to_string(outputOperandIndex); + validate(device, message, model, + [operation, outputNum](Model* model, ExecutionPreference*) { + uint32_t& outputOperandIndex = + model->operations[operation].outputs[outputNum]; + Operand operandValue = model->operands[outputOperandIndex]; + operandValue.numberOfConsumers = 0; + if (operandValue.lifetime == OperandLifeTime::MODEL_OUTPUT) { + operandValue.lifetime = OperandLifeTime::TEMPORARY_VARIABLE; + } else { + ASSERT_EQ(operandValue.lifetime, + OperandLifeTime::TEMPORARY_VARIABLE); + } + outputOperandIndex = + hidl_vec_push_back(&model->operands, operandValue); + }); + } + } + } +} + ///////////////////////// REMOVE OPERAND FROM EVERYTHING ///////////////////////// static void removeValueAndDecrementGreaterValues(hidl_vec* vec, uint32_t value) { @@ -504,14 +978,20 @@ static void mutateExecutionPreferenceTest(const sp& device, const Model ////////////////////////// ENTRY POINT ////////////////////////////// void validateModel(const sp& device, const Model& model) { + mutateExecutionOrderTest(device, model); mutateOperandTypeTest(device, model); mutateOperandRankTest(device, model); mutateOperandScaleTest(device, model); mutateOperandZeroPointTest(device, model); + mutateOperandLifeTimeTest(device, model); + mutateOperandInputOutputTest(device, model); + mutateOperandNumberOfConsumersTest(device, model); + mutateOperandAddWriterTest(device, model); mutateOperationOperandTypeTest(device, model); mutateOperationTypeTest(device, model); mutateOperationInputOperandIndexTest(device, model); mutateOperationOutputOperandIndexTest(device, model); + mutateOperationRemoveWriteTest(device, model); removeOperandTest(device, model); removeOperationTest(device, model); removeOperationInputTest(device, model); diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index 481eb80258..182f716115 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -15,11 +15,12 @@ // cc_library_static { - name: "VtsHalNeuralNetworksV1_2Callbacks", + name: "VtsHalNeuralNetworksV1_2_utils", defaults: ["neuralnetworks_vts_functional_defaults"], export_include_dirs: ["include"], srcs: [ "Callbacks.cpp", + "Utils.cpp", ], static_libs: [ "android.hardware.neuralnetworks@1.0", @@ -51,7 +52,7 @@ cc_test { ], static_libs: [ "VtsHalNeuralNetworksV1_0_utils", - "VtsHalNeuralNetworksV1_2Callbacks", + "VtsHalNeuralNetworksV1_2_utils", "android.hardware.neuralnetworks@1.0", "android.hardware.neuralnetworks@1.1", "android.hardware.neuralnetworks@1.2", diff --git a/neuralnetworks/1.2/vts/functional/BasicTests.cpp b/neuralnetworks/1.2/vts/functional/BasicTests.cpp index 58d3c4a403..77340e7434 100644 --- a/neuralnetworks/1.2/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.2/vts/functional/BasicTests.cpp @@ -20,9 +20,13 @@ namespace android::hardware::neuralnetworks::V1_2::vts::functional { +using implementation::PreparedModelCallback; using V1_0::DeviceStatus; using V1_0::ErrorStatus; +using V1_0::OperandLifeTime; using V1_0::PerformanceInfo; +using V1_1::ExecutionPreference; +using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; // create device test TEST_P(NeuralnetworksHidlTest, CreateDevice) {} @@ -123,4 +127,139 @@ TEST_P(NeuralnetworksHidlTest, getNumberOfCacheFilesNeeded) { }); EXPECT_TRUE(ret.isOk()); } + +// detect cycle +TEST_P(NeuralnetworksHidlTest, CycleTest) { + // opnd0 = TENSOR_FLOAT32 // model input + // opnd1 = TENSOR_FLOAT32 // model input + // opnd2 = INT32 // model input + // opnd3 = ADD(opnd0, opnd4, opnd2) + // opnd4 = ADD(opnd1, opnd3, opnd2) + // opnd5 = ADD(opnd4, opnd0, opnd2) // model output + // + // +-----+ + // | | + // v | + // 3 = ADD(0, 4, 2) | + // | | + // +----------+ | + // | | + // v | + // 4 = ADD(1, 3, 2) | + // | | + // +----------------+ + // | + // | + // +-------+ + // | + // v + // 5 = ADD(4, 0, 2) + + const std::vector operands = { + { + // operands[0] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 2, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[1] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[2] + .type = OperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 3, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[3] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::TEMPORARY_VARIABLE, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[4] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 2, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::TEMPORARY_VARIABLE, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[5] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 0, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_OUTPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + }; + + const std::vector operations = { + {.type = OperationType::ADD, .inputs = {0, 4, 2}, .outputs = {3}}, + {.type = OperationType::ADD, .inputs = {1, 3, 2}, .outputs = {4}}, + {.type = OperationType::ADD, .inputs = {4, 0, 2}, .outputs = {5}}, + }; + + const Model model = { + .operands = operands, + .operations = operations, + .inputIndexes = {0, 1, 2}, + .outputIndexes = {5}, + .operandValues = {}, + .pools = {}, + }; + + // ensure that getSupportedOperations_1_2() checks model validity + ErrorStatus supportedOpsErrorStatus = ErrorStatus::GENERAL_FAILURE; + Return supportedOpsReturn = kDevice->getSupportedOperations_1_2( + model, [&model, &supportedOpsErrorStatus](ErrorStatus status, + const hidl_vec& supported) { + supportedOpsErrorStatus = status; + if (status == ErrorStatus::NONE) { + ASSERT_EQ(supported.size(), model.operations.size()); + } + }); + ASSERT_TRUE(supportedOpsReturn.isOk()); + ASSERT_EQ(supportedOpsErrorStatus, ErrorStatus::INVALID_ARGUMENT); + + // ensure that prepareModel_1_2() checks model validity + sp preparedModelCallback = new PreparedModelCallback; + Return prepareLaunchReturn = kDevice->prepareModel_1_2( + model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec(), + hidl_vec(), HidlToken(), preparedModelCallback); + ASSERT_TRUE(prepareLaunchReturn.isOk()); + // Note that preparation can fail for reasons other than an + // invalid model (invalid model should result in + // INVALID_ARGUMENT) -- for example, perhaps not all + // operations are supported, or perhaps the device hit some + // kind of capacity limit. + EXPECT_NE(prepareLaunchReturn, ErrorStatus::NONE); + EXPECT_NE(preparedModelCallback->getStatus(), ErrorStatus::NONE); + EXPECT_EQ(preparedModelCallback->getPreparedModel(), nullptr); +} + } // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.2/vts/functional/Utils.cpp b/neuralnetworks/1.2/vts/functional/Utils.cpp new file mode 100644 index 0000000000..cc654f2c57 --- /dev/null +++ b/neuralnetworks/1.2/vts/functional/Utils.cpp @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#include +#include + +#include +#include + +namespace android { +namespace hardware { +namespace neuralnetworks { + +uint32_t sizeOfData(V1_2::OperandType type) { + switch (type) { + case V1_2::OperandType::FLOAT32: + case V1_2::OperandType::INT32: + case V1_2::OperandType::UINT32: + case V1_2::OperandType::TENSOR_FLOAT32: + case V1_2::OperandType::TENSOR_INT32: + return 4; + case V1_2::OperandType::TENSOR_QUANT16_SYMM: + case V1_2::OperandType::TENSOR_FLOAT16: + case V1_2::OperandType::FLOAT16: + case V1_2::OperandType::TENSOR_QUANT16_ASYMM: + return 2; + case V1_2::OperandType::TENSOR_QUANT8_ASYMM: + case V1_2::OperandType::BOOL: + case V1_2::OperandType::TENSOR_BOOL8: + case V1_2::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: + case V1_2::OperandType::TENSOR_QUANT8_SYMM: + return 1; + default: + CHECK(false) << "Invalid OperandType " << static_cast(type); + return 0; + } +} + +static bool isTensor(V1_2::OperandType type) { + switch (type) { + case V1_2::OperandType::FLOAT32: + case V1_2::OperandType::INT32: + case V1_2::OperandType::UINT32: + case V1_2::OperandType::FLOAT16: + case V1_2::OperandType::BOOL: + return false; + case V1_2::OperandType::TENSOR_FLOAT32: + case V1_2::OperandType::TENSOR_INT32: + case V1_2::OperandType::TENSOR_QUANT16_SYMM: + case V1_2::OperandType::TENSOR_FLOAT16: + case V1_2::OperandType::TENSOR_QUANT16_ASYMM: + case V1_2::OperandType::TENSOR_QUANT8_ASYMM: + case V1_2::OperandType::TENSOR_BOOL8: + case V1_2::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: + case V1_2::OperandType::TENSOR_QUANT8_SYMM: + return true; + default: + CHECK(false) << "Invalid OperandType " << static_cast(type); + return false; + } +} + +uint32_t sizeOfData(const V1_2::Operand& operand) { + const uint32_t dataSize = sizeOfData(operand.type); + if (isTensor(operand.type) && operand.dimensions.size() == 0) return 0; + return std::accumulate(operand.dimensions.begin(), operand.dimensions.end(), dataSize, + std::multiplies<>{}); +} + +} // namespace neuralnetworks +} // namespace hardware +} // namespace android diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp index 7451f095bf..3375602d27 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp @@ -16,14 +16,21 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" +#include #include "1.0/Utils.h" #include "1.2/Callbacks.h" +#include "1.2/Utils.h" #include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" +#include +#include +#include + namespace android::hardware::neuralnetworks::V1_2::vts::functional { using implementation::PreparedModelCallback; +using V1_0::DataLocation; using V1_0::ErrorStatus; using V1_0::OperandLifeTime; using V1_1::ExecutionPreference; @@ -105,6 +112,250 @@ static uint32_t addOperand(Model* model, OperandLifeTime lifetime) { return index; } +// If we introduce a CONSTANT_COPY for an operand of size operandSize, +// how much will this increase the size of the model? This assumes +// that we can (re)use all of model.operandValues for the operand +// value. +static size_t constantCopyExtraSize(const Model& model, size_t operandSize) { + const size_t operandValuesSize = model.operandValues.size(); + return (operandValuesSize < operandSize) ? (operandSize - operandValuesSize) : 0; +} + +// Highly specialized utility routine for converting an operand to +// CONSTANT_COPY lifetime. +// +// Expects that: +// - operand has a known size +// - operand->lifetime has already been set to CONSTANT_COPY +// - operand->location has been zeroed out +// +// Does the following: +// - initializes operand->location to point to the beginning of model->operandValues +// - resizes model->operandValues (if necessary) to be large enough for the operand +// value, padding it with zeroes on the end +// +// Potential problem: +// By changing the operand to CONSTANT_COPY lifetime, this function is effectively initializing the +// operand with unspecified (but deterministic) data. This means that the model may be invalidated +// in two ways: not only is the lifetime of CONSTANT_COPY invalid, but the operand's value in the +// graph may also be invalid (e.g., if the operand is used as an activation code and has an invalid +// value). For now, this should be fine because it just means we're not testing what we think we're +// testing in certain cases; but we can handwave this and assume we're probabilistically likely to +// exercise the validation code over the span of the entire test set and operand space. +// +// Aborts if the specified operand type is an extension type or OEM type. +static void becomeConstantCopy(Model* model, Operand* operand) { + // sizeOfData will abort if the specified type is an extension type or OEM type. + const size_t sizeOfOperand = sizeOfData(*operand); + EXPECT_NE(sizeOfOperand, size_t(0)); + operand->location.poolIndex = 0; + operand->location.offset = 0; + operand->location.length = sizeOfOperand; + if (model->operandValues.size() < sizeOfOperand) { + model->operandValues.resize(sizeOfOperand); + } +} + +// The sizeForBinder() functions estimate the size of the +// representation of a value when sent to binder. It's probably a bit +// of an under-estimate, because we don't know the size of the +// metadata in the binder format (e.g., representation of the size of +// a vector); but at least it adds up "big" things like vector +// contents. However, it doesn't treat inter-field or end-of-struct +// padding in a methodical way -- there's no attempt to be consistent +// in whether or not padding in the native (C++) representation +// contributes to the estimated size for the binder representation; +// and there's no attempt to understand what padding (if any) is +// needed in the binder representation. +// +// This assumes that non-metadata uses a fixed length encoding (e.g., +// a uint32_t is always encoded in sizeof(uint32_t) bytes, rather than +// using an encoding whose length is related to the magnitude of the +// encoded value). + +template +static size_t sizeForBinder(const Type& val) { + static_assert(std::is_trivially_copyable_v>, + "expected a trivially copyable type"); + return sizeof(val); +} + +template +static size_t sizeForBinder(const hidl_vec& vec) { + return std::accumulate(vec.begin(), vec.end(), 0, + [](size_t acc, const Type& x) { return acc + sizeForBinder(x); }); +} + +template <> +size_t sizeForBinder(const SymmPerChannelQuantParams& symmPerChannelQuantParams) { + size_t size = 0; + + size += sizeForBinder(symmPerChannelQuantParams.scales); + size += sizeForBinder(symmPerChannelQuantParams.channelDim); + + return size; +} + +template <> +size_t sizeForBinder(const Operand::ExtraParams& extraParams) { + using Discriminator = Operand::ExtraParams::hidl_discriminator; + switch (extraParams.getDiscriminator()) { + case Discriminator::none: + return 0; + case Discriminator::channelQuant: + return sizeForBinder(extraParams.channelQuant()); + case Discriminator::extension: + return sizeForBinder(extraParams.extension()); + } + LOG(FATAL) << "Unrecognized extraParams enum: " + << static_cast(extraParams.getDiscriminator()); + return 0; +} + +template <> +size_t sizeForBinder(const Operand& operand) { + size_t size = 0; + + size += sizeForBinder(operand.type); + size += sizeForBinder(operand.dimensions); + size += sizeForBinder(operand.numberOfConsumers); + size += sizeForBinder(operand.scale); + size += sizeForBinder(operand.zeroPoint); + size += sizeForBinder(operand.lifetime); + size += sizeForBinder(operand.location); + size += sizeForBinder(operand.extraParams); + + return size; +} + +template <> +size_t sizeForBinder(const Operation& operation) { + size_t size = 0; + + size += sizeForBinder(operation.type); + size += sizeForBinder(operation.inputs); + size += sizeForBinder(operation.outputs); + + return size; +} + +template <> +size_t sizeForBinder(const hidl_string& name) { + return name.size(); +} + +template <> +size_t sizeForBinder(const hidl_memory& memory) { + // This is just a guess. + + size_t size = 0; + + if (const native_handle_t* handle = memory.handle()) { + size += sizeof(*handle); + size += sizeof(handle->data[0] * (handle->numFds + handle->numInts)); + } + size += sizeForBinder(memory.name()); + + return size; +} + +template <> +size_t sizeForBinder(const Model::ExtensionNameAndPrefix& extensionNameToPrefix) { + size_t size = 0; + + size += sizeForBinder(extensionNameToPrefix.name); + size += sizeForBinder(extensionNameToPrefix.prefix); + + return size; +} + +template <> +size_t sizeForBinder(const Model& model) { + size_t size = 0; + + size += sizeForBinder(model.operands); + size += sizeForBinder(model.operations); + size += sizeForBinder(model.inputIndexes); + size += sizeForBinder(model.outputIndexes); + size += sizeForBinder(model.operandValues); + size += sizeForBinder(model.pools); + size += sizeForBinder(model.relaxComputationFloat32toFloat16); + size += sizeForBinder(model.extensionNameToPrefix); + + return size; +} + +// https://developer.android.com/reference/android/os/TransactionTooLargeException.html +// +// "The Binder transaction buffer has a limited fixed size, +// currently 1Mb, which is shared by all transactions in progress +// for the process." +// +// Will our representation fit under this limit? There are two complications: +// - Our representation size is just approximate (see sizeForBinder()). +// - This object may not be the only occupant of the Binder transaction buffer. +// So we'll be very conservative: We want the representation size to be no +// larger than half the transaction buffer size. +// +// If our representation grows large enough that it still fits within +// the transaction buffer but combined with other transactions may +// exceed the buffer size, then we may see intermittent HAL transport +// errors. +static bool exceedsBinderSizeLimit(size_t representationSize) { + // Instead of using this fixed buffer size, we might instead be able to use + // ProcessState::self()->getMmapSize(). However, this has a potential + // problem: The binder/mmap size of the current process does not necessarily + // indicate the binder/mmap size of the service (i.e., the other process). + // The only way it would be a good indication is if both the current process + // and the service use the default size. + static const size_t kHalfBufferSize = 1024 * 1024 / 2; + + return representationSize > kHalfBufferSize; +} + +///////////////////////// VALIDATE EXECUTION ORDER //////////////////////////// + +static void mutateExecutionOrderTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + const Operation& operationObj = model.operations[operation]; + for (uint32_t input : operationObj.inputs) { + if (model.operands[input].lifetime == OperandLifeTime::TEMPORARY_VARIABLE || + model.operands[input].lifetime == OperandLifeTime::MODEL_OUTPUT) { + // This operation reads an operand written by some + // other operation. Move this operation to the + // beginning of the sequence, ensuring that it reads + // the operand before that operand is written, thereby + // violating execution order rules. + const std::string message = "mutateExecutionOrderTest: operation " + + std::to_string(operation) + " is a reader"; + validate(device, message, model, [operation](Model* model, ExecutionPreference*) { + auto& operations = model->operations; + std::rotate(operations.begin(), operations.begin() + operation, + operations.begin() + operation + 1); + }); + break; // only need to do this once per operation + } + } + for (uint32_t output : operationObj.outputs) { + if (model.operands[output].numberOfConsumers > 0) { + // This operation writes an operand read by some other + // operation. Move this operation to the end of the + // sequence, ensuring that it writes the operand after + // that operand is read, thereby violating execution + // order rules. + const std::string message = "mutateExecutionOrderTest: operation " + + std::to_string(operation) + " is a writer"; + validate(device, message, model, [operation](Model* model, ExecutionPreference*) { + auto& operations = model->operations; + std::rotate(operations.begin() + operation, operations.begin() + operation + 1, + operations.end()); + }); + break; // only need to do this once per operation + } + } + } +} + ///////////////////////// VALIDATE MODEL OPERAND TYPE ///////////////////////// static const uint32_t invalidOperandTypes[] = { @@ -251,9 +502,239 @@ static void mutateOperandZeroPointTest(const sp& device, const Model& m } } +///////////////////////// VALIDATE OPERAND LIFETIME ///////////////////////////////////////////// + +static std::vector getInvalidLifeTimes(const Model& model, size_t modelSize, + const Operand& operand) { + // TODO: Support OperandLifeTime::CONSTANT_REFERENCE as an invalid lifetime + // TODO: Support OperandLifeTime::NO_VALUE as an invalid lifetime + + // Ways to get an invalid lifetime: + // - change whether a lifetime means an operand should have a writer + std::vector ret; + switch (operand.lifetime) { + case OperandLifeTime::MODEL_OUTPUT: + case OperandLifeTime::TEMPORARY_VARIABLE: + ret = { + OperandLifeTime::MODEL_INPUT, + OperandLifeTime::CONSTANT_COPY, + }; + break; + case OperandLifeTime::CONSTANT_COPY: + case OperandLifeTime::CONSTANT_REFERENCE: + case OperandLifeTime::MODEL_INPUT: + ret = { + OperandLifeTime::TEMPORARY_VARIABLE, + OperandLifeTime::MODEL_OUTPUT, + }; + break; + case OperandLifeTime::NO_VALUE: + // Not enough information to know whether + // TEMPORARY_VARIABLE or CONSTANT_COPY would be invalid -- + // is this operand written (then CONSTANT_COPY would be + // invalid) or not (then TEMPORARY_VARIABLE would be + // invalid)? + break; + default: + ADD_FAILURE(); + break; + } + + const size_t operandSize = sizeOfData(operand); // will be zero if shape is unknown + if (!operandSize || + exceedsBinderSizeLimit(modelSize + constantCopyExtraSize(model, operandSize))) { + // Unknown size or too-large size + ret.erase(std::remove(ret.begin(), ret.end(), OperandLifeTime::CONSTANT_COPY), ret.end()); + } + + return ret; +} + +static void mutateOperandLifeTimeTest(const sp& device, const Model& model) { + const size_t modelSize = sizeForBinder(model); + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + const std::vector invalidLifeTimes = + getInvalidLifeTimes(model, modelSize, model.operands[operand]); + for (OperandLifeTime invalidLifeTime : invalidLifeTimes) { + const std::string message = "mutateOperandLifetimeTest: operand " + + std::to_string(operand) + " has lifetime " + + toString(invalidLifeTime) + " instead of lifetime " + + toString(model.operands[operand].lifetime); + validate(device, message, model, + [operand, invalidLifeTime](Model* model, ExecutionPreference*) { + static const DataLocation kZeroDataLocation = {}; + Operand& operandObj = model->operands[operand]; + switch (operandObj.lifetime) { + case OperandLifeTime::MODEL_INPUT: { + hidl_vec_remove(&model->inputIndexes, uint32_t(operand)); + break; + } + case OperandLifeTime::MODEL_OUTPUT: { + hidl_vec_remove(&model->outputIndexes, uint32_t(operand)); + break; + } + default: + break; + } + operandObj.lifetime = invalidLifeTime; + operandObj.location = kZeroDataLocation; + switch (invalidLifeTime) { + case OperandLifeTime::CONSTANT_COPY: { + becomeConstantCopy(model, &operandObj); + break; + } + case OperandLifeTime::MODEL_INPUT: + hidl_vec_push_back(&model->inputIndexes, uint32_t(operand)); + break; + case OperandLifeTime::MODEL_OUTPUT: + hidl_vec_push_back(&model->outputIndexes, uint32_t(operand)); + break; + default: + break; + } + }); + } + } +} + +///////////////////////// VALIDATE OPERAND INPUT-or-OUTPUT ////////////////////////////////////// + +static std::optional getInputOutputLifeTime(const Model& model, size_t modelSize, + const Operand& operand) { + // Ways to get an invalid lifetime (with respect to model inputIndexes and outputIndexes): + // - change whether a lifetime means an operand is a model input, a model output, or neither + // - preserve whether or not a lifetime means an operand should have a writer + switch (operand.lifetime) { + case OperandLifeTime::CONSTANT_COPY: + case OperandLifeTime::CONSTANT_REFERENCE: + return OperandLifeTime::MODEL_INPUT; + case OperandLifeTime::MODEL_INPUT: { + const size_t operandSize = sizeOfData(operand); // will be zero if shape is unknown + if (!operandSize || + exceedsBinderSizeLimit(modelSize + constantCopyExtraSize(model, operandSize))) { + // Unknown size or too-large size + break; + } + return OperandLifeTime::CONSTANT_COPY; + } + case OperandLifeTime::MODEL_OUTPUT: + return OperandLifeTime::TEMPORARY_VARIABLE; + case OperandLifeTime::TEMPORARY_VARIABLE: + return OperandLifeTime::MODEL_OUTPUT; + case OperandLifeTime::NO_VALUE: + // Not enough information to know whether + // TEMPORARY_VARIABLE or CONSTANT_COPY would be an + // appropriate choice -- is this operand written (then + // TEMPORARY_VARIABLE would be appropriate) or not (then + // CONSTANT_COPY would be appropriate)? + break; + default: + ADD_FAILURE(); + break; + } + + return std::nullopt; +} + +static void mutateOperandInputOutputTest(const sp& device, const Model& model) { + const size_t modelSize = sizeForBinder(model); + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + const std::optional changedLifeTime = + getInputOutputLifeTime(model, modelSize, model.operands[operand]); + if (changedLifeTime) { + const std::string message = "mutateOperandInputOutputTest: operand " + + std::to_string(operand) + " has lifetime " + + toString(*changedLifeTime) + " instead of lifetime " + + toString(model.operands[operand].lifetime); + validate(device, message, model, + [operand, changedLifeTime](Model* model, ExecutionPreference*) { + static const DataLocation kZeroDataLocation = {}; + Operand& operandObj = model->operands[operand]; + operandObj.lifetime = *changedLifeTime; + operandObj.location = kZeroDataLocation; + if (*changedLifeTime == OperandLifeTime::CONSTANT_COPY) { + becomeConstantCopy(model, &operandObj); + } + }); + } + } +} + +///////////////////////// VALIDATE OPERAND NUMBER OF CONSUMERS ////////////////////////////////// + +static std::vector getInvalidNumberOfConsumers(uint32_t numberOfConsumers) { + if (numberOfConsumers == 0) { + return {1}; + } else { + return {numberOfConsumers - 1, numberOfConsumers + 1}; + } +} + +static void mutateOperandNumberOfConsumersTest(const sp& device, const Model& model) { + for (size_t operand = 0; operand < model.operands.size(); ++operand) { + const std::vector invalidNumberOfConsumersVec = + getInvalidNumberOfConsumers(model.operands[operand].numberOfConsumers); + for (uint32_t invalidNumberOfConsumers : invalidNumberOfConsumersVec) { + const std::string message = + "mutateOperandNumberOfConsumersTest: operand " + std::to_string(operand) + + " numberOfConsumers = " + std::to_string(invalidNumberOfConsumers); + validate(device, message, model, + [operand, invalidNumberOfConsumers](Model* model, ExecutionPreference*) { + model->operands[operand].numberOfConsumers = invalidNumberOfConsumers; + }); + } + } +} + +///////////////////////// VALIDATE OPERAND NUMBER OF WRITERS //////////////////////////////////// + +static void mutateOperandAddWriterTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + for (size_t badOutputNum = 0; badOutputNum < model.operations[operation].outputs.size(); + ++badOutputNum) { + const uint32_t outputOperandIndex = model.operations[operation].outputs[badOutputNum]; + const std::string message = "mutateOperandAddWriterTest: operation " + + std::to_string(operation) + " writes to " + + std::to_string(outputOperandIndex); + // We'll insert a copy of the operation, all of whose + // OTHER output operands are newly-created -- i.e., + // there'll only be a duplicate write of ONE of that + // operation's output operands. + validate(device, message, model, + [operation, badOutputNum](Model* model, ExecutionPreference*) { + Operation newOperation = model->operations[operation]; + for (uint32_t input : newOperation.inputs) { + ++model->operands[input].numberOfConsumers; + } + for (size_t outputNum = 0; outputNum < newOperation.outputs.size(); + ++outputNum) { + if (outputNum == badOutputNum) continue; + + Operand operandValue = + model->operands[newOperation.outputs[outputNum]]; + operandValue.numberOfConsumers = 0; + if (operandValue.lifetime == OperandLifeTime::MODEL_OUTPUT) { + operandValue.lifetime = OperandLifeTime::TEMPORARY_VARIABLE; + } else { + ASSERT_EQ(operandValue.lifetime, + OperandLifeTime::TEMPORARY_VARIABLE); + } + newOperation.outputs[outputNum] = + hidl_vec_push_back(&model->operands, operandValue); + } + // Where do we insert the extra writer (a new + // operation)? It has to be later than all the + // writers of its inputs. The easiest thing to do + // is to insert it at the end of the operation + // sequence. + hidl_vec_push_back(&model->operations, newOperation); + }); + } + } +} + ///////////////////////// VALIDATE EXTRA ??? ///////////////////////// -// TODO: Operand::lifetime // TODO: Operand::location ///////////////////////// VALIDATE OPERATION OPERAND TYPE ///////////////////////// @@ -461,6 +942,37 @@ static void mutateOperationOutputOperandIndexTest(const sp& device, con } } +///////////////////////// VALIDATE MODEL OPERANDS WRITTEN /////////////////////////////////////// + +static void mutateOperationRemoveWriteTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.operations.size(); ++operation) { + for (size_t outputNum = 0; outputNum < model.operations[operation].outputs.size(); + ++outputNum) { + const uint32_t outputOperandIndex = model.operations[operation].outputs[outputNum]; + if (model.operands[outputOperandIndex].numberOfConsumers > 0) { + const std::string message = "mutateOperationRemoveWriteTest: operation " + + std::to_string(operation) + " writes to " + + std::to_string(outputOperandIndex); + validate(device, message, model, + [operation, outputNum](Model* model, ExecutionPreference*) { + uint32_t& outputOperandIndex = + model->operations[operation].outputs[outputNum]; + Operand operandValue = model->operands[outputOperandIndex]; + operandValue.numberOfConsumers = 0; + if (operandValue.lifetime == OperandLifeTime::MODEL_OUTPUT) { + operandValue.lifetime = OperandLifeTime::TEMPORARY_VARIABLE; + } else { + ASSERT_EQ(operandValue.lifetime, + OperandLifeTime::TEMPORARY_VARIABLE); + } + outputOperandIndex = + hidl_vec_push_back(&model->operands, operandValue); + }); + } + } + } +} + ///////////////////////// REMOVE OPERAND FROM EVERYTHING ///////////////////////// static void removeValueAndDecrementGreaterValues(hidl_vec* vec, uint32_t value) { @@ -711,14 +1223,20 @@ static void mutateExecutionPreferenceTest(const sp& device, const Model ////////////////////////// ENTRY POINT ////////////////////////////// void validateModel(const sp& device, const Model& model) { + mutateExecutionOrderTest(device, model); mutateOperandTypeTest(device, model); mutateOperandRankTest(device, model); mutateOperandScaleTest(device, model); mutateOperandZeroPointTest(device, model); + mutateOperandLifeTimeTest(device, model); + mutateOperandInputOutputTest(device, model); + mutateOperandNumberOfConsumersTest(device, model); + mutateOperandAddWriterTest(device, model); mutateOperationOperandTypeTest(device, model); mutateOperationTypeTest(device, model); mutateOperationInputOperandIndexTest(device, model); mutateOperationOutputOperandIndexTest(device, model); + mutateOperationRemoveWriteTest(device, model); removeOperandTest(device, model); removeOperationTest(device, model); removeOperationInputTest(device, model); diff --git a/neuralnetworks/1.2/vts/functional/include/1.2/Utils.h b/neuralnetworks/1.2/vts/functional/include/1.2/Utils.h new file mode 100644 index 0000000000..61a8d7485a --- /dev/null +++ b/neuralnetworks/1.2/vts/functional/include/1.2/Utils.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_UTILS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_UTILS_H + +#include + +namespace android { +namespace hardware { +namespace neuralnetworks { + +// Returns the amount of space needed to store a value of the specified type. +// +// Aborts if the specified type is an extension type or OEM type. +uint32_t sizeOfData(V1_2::OperandType type); + +// Returns the amount of space needed to store a value of the dimensions and +// type of this operand. For a non-extension, non-OEM tensor with unspecified +// rank or at least one unspecified dimension, returns zero. +// +// Aborts if the specified type is an extension type or OEM type. +uint32_t sizeOfData(const V1_2::Operand& operand); + +} // namespace neuralnetworks +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_UTILS_H diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp index 2c1be0b008..771fc54e0d 100644 --- a/neuralnetworks/1.3/vts/functional/Android.bp +++ b/neuralnetworks/1.3/vts/functional/Android.bp @@ -54,7 +54,7 @@ cc_test { ], static_libs: [ "VtsHalNeuralNetworksV1_0_utils", - "VtsHalNeuralNetworksV1_2Callbacks", + "VtsHalNeuralNetworksV1_2_utils", "VtsHalNeuralNetworksV1_3_utils", "android.hardware.neuralnetworks@1.0", "android.hardware.neuralnetworks@1.1", diff --git a/neuralnetworks/1.3/vts/functional/BasicTests.cpp b/neuralnetworks/1.3/vts/functional/BasicTests.cpp index 1c2536983e..6fcfc3482d 100644 --- a/neuralnetworks/1.3/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.3/vts/functional/BasicTests.cpp @@ -20,11 +20,14 @@ namespace android::hardware::neuralnetworks::V1_3::vts::functional { +using implementation::PreparedModelCallback; using V1_0::DeviceStatus; using V1_0::PerformanceInfo; +using V1_1::ExecutionPreference; using V1_2::Constant; using V1_2::DeviceType; using V1_2::Extension; +using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; // create device test TEST_P(NeuralnetworksHidlTest, CreateDevice) {} @@ -65,4 +68,143 @@ TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) { }); EXPECT_TRUE(ret.isOk()); } + +// detect cycle +TEST_P(NeuralnetworksHidlTest, CycleTest) { + // opnd0 = TENSOR_FLOAT32 // model input + // opnd1 = TENSOR_FLOAT32 // model input + // opnd2 = INT32 // model input + // opnd3 = ADD(opnd0, opnd4, opnd2) + // opnd4 = ADD(opnd1, opnd3, opnd2) + // opnd5 = ADD(opnd4, opnd0, opnd2) // model output + // + // +-----+ + // | | + // v | + // 3 = ADD(0, 4, 2) | + // | | + // +----------+ | + // | | + // v | + // 4 = ADD(1, 3, 2) | + // | | + // +----------------+ + // | + // | + // +-------+ + // | + // v + // 5 = ADD(4, 0, 2) + + const std::vector operands = { + { + // operands[0] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 2, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::SUBGRAPH_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[1] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::SUBGRAPH_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[2] + .type = OperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 3, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::SUBGRAPH_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[3] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::TEMPORARY_VARIABLE, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[4] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 2, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::TEMPORARY_VARIABLE, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + // operands[5] + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1}, + .numberOfConsumers = 0, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::SUBGRAPH_OUTPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + }; + + const std::vector operations = { + {.type = OperationType::ADD, .inputs = {0, 4, 2}, .outputs = {3}}, + {.type = OperationType::ADD, .inputs = {1, 3, 2}, .outputs = {4}}, + {.type = OperationType::ADD, .inputs = {4, 0, 2}, .outputs = {5}}, + }; + + Subgraph subgraph = { + .operands = operands, + .operations = operations, + .inputIndexes = {0, 1, 2}, + .outputIndexes = {5}, + }; + const Model model = { + .main = std::move(subgraph), + .referenced = {}, + .operandValues = {}, + .pools = {}, + }; + + // ensure that getSupportedOperations_1_2() checks model validity + ErrorStatus supportedOpsErrorStatus = ErrorStatus::GENERAL_FAILURE; + Return supportedOpsReturn = kDevice->getSupportedOperations_1_3( + model, [&model, &supportedOpsErrorStatus](ErrorStatus status, + const hidl_vec& supported) { + supportedOpsErrorStatus = status; + if (status == ErrorStatus::NONE) { + ASSERT_EQ(supported.size(), model.main.operations.size()); + } + }); + ASSERT_TRUE(supportedOpsReturn.isOk()); + ASSERT_EQ(supportedOpsErrorStatus, ErrorStatus::INVALID_ARGUMENT); + + // ensure that prepareModel_1_3() checks model validity + sp preparedModelCallback = new PreparedModelCallback; + Return prepareLaunchReturn = kDevice->prepareModel_1_3( + model, ExecutionPreference::FAST_SINGLE_ANSWER, Priority::MEDIUM, {}, + hidl_vec(), hidl_vec(), HidlToken(), preparedModelCallback); + ASSERT_TRUE(prepareLaunchReturn.isOk()); + // Note that preparation can fail for reasons other than an + // invalid model (invalid model should result in + // INVALID_ARGUMENT) -- for example, perhaps not all + // operations are supported, or perhaps the device hit some + // kind of capacity limit. + EXPECT_NE(prepareLaunchReturn, ErrorStatus::NONE); + EXPECT_NE(preparedModelCallback->getStatus(), ErrorStatus::NONE); + EXPECT_EQ(preparedModelCallback->getPreparedModel(), nullptr); +} + } // namespace android::hardware::neuralnetworks::V1_3::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/Utils.cpp b/neuralnetworks/1.3/vts/functional/Utils.cpp index 23e2af823e..c460e1127b 100644 --- a/neuralnetworks/1.3/vts/functional/Utils.cpp +++ b/neuralnetworks/1.3/vts/functional/Utils.cpp @@ -17,11 +17,78 @@ #include "1.3/Utils.h" #include +#include +#include "android-base/logging.h" +#include "android/hardware/neuralnetworks/1.3/types.h" -namespace android::hardware::neuralnetworks::V1_3 { +namespace android::hardware::neuralnetworks { + +uint32_t sizeOfData(V1_3::OperandType type) { + switch (type) { + case V1_3::OperandType::FLOAT32: + case V1_3::OperandType::INT32: + case V1_3::OperandType::UINT32: + case V1_3::OperandType::TENSOR_FLOAT32: + case V1_3::OperandType::TENSOR_INT32: + return 4; + case V1_3::OperandType::TENSOR_QUANT16_SYMM: + case V1_3::OperandType::TENSOR_FLOAT16: + case V1_3::OperandType::FLOAT16: + case V1_3::OperandType::TENSOR_QUANT16_ASYMM: + return 2; + case V1_3::OperandType::TENSOR_QUANT8_ASYMM: + case V1_3::OperandType::BOOL: + case V1_3::OperandType::TENSOR_BOOL8: + case V1_3::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: + case V1_3::OperandType::TENSOR_QUANT8_SYMM: + case V1_3::OperandType::TENSOR_QUANT8_ASYMM_SIGNED: + return 1; + case V1_3::OperandType::SUBGRAPH: + return 0; + default: + CHECK(false) << "Invalid OperandType " << static_cast(type); + return 0; + } +} + +static bool isTensor(V1_3::OperandType type) { + switch (type) { + case V1_3::OperandType::FLOAT32: + case V1_3::OperandType::INT32: + case V1_3::OperandType::UINT32: + case V1_3::OperandType::FLOAT16: + case V1_3::OperandType::BOOL: + case V1_3::OperandType::SUBGRAPH: + return false; + case V1_3::OperandType::TENSOR_FLOAT32: + case V1_3::OperandType::TENSOR_INT32: + case V1_3::OperandType::TENSOR_QUANT16_SYMM: + case V1_3::OperandType::TENSOR_FLOAT16: + case V1_3::OperandType::TENSOR_QUANT16_ASYMM: + case V1_3::OperandType::TENSOR_QUANT8_ASYMM: + case V1_3::OperandType::TENSOR_BOOL8: + case V1_3::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: + case V1_3::OperandType::TENSOR_QUANT8_SYMM: + case V1_3::OperandType::TENSOR_QUANT8_ASYMM_SIGNED: + return true; + default: + CHECK(false) << "Invalid OperandType " << static_cast(type); + return false; + } +} + +uint32_t sizeOfData(const V1_3::Operand& operand) { + const uint32_t dataSize = sizeOfData(operand.type); + if (isTensor(operand.type) && operand.dimensions.size() == 0) return 0; + return std::accumulate(operand.dimensions.begin(), operand.dimensions.end(), dataSize, + std::multiplies<>{}); +} + +namespace V1_3 { ::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus) { return os << toString(errorStatus); } -} // namespace android::hardware::neuralnetworks::V1_3 +} // namespace V1_3 +} // namespace android::hardware::neuralnetworks diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index e590fdad2d..849ef7bf50 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -16,15 +16,22 @@ #define LOG_TAG "neuralnetworks_hidl_hal_test" +#include +#include #include "1.0/Utils.h" #include "1.3/Callbacks.h" #include "1.3/Utils.h" #include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" +#include +#include +#include + namespace android::hardware::neuralnetworks::V1_3::vts::functional { using implementation::PreparedModelCallback; +using V1_0::DataLocation; using V1_1::ExecutionPreference; using V1_2::SymmPerChannelQuantParams; using HidlToken = @@ -112,6 +119,262 @@ static uint32_t addOperand(Model* model, OperandLifeTime lifetime) { return index; } +// If we introduce a CONSTANT_COPY for an operand of size operandSize, +// how much will this increase the size of the model? This assumes +// that we can (re)use all of model.operandValues for the operand +// value. +static size_t constantCopyExtraSize(const Model& model, size_t operandSize) { + const size_t operandValuesSize = model.operandValues.size(); + return (operandValuesSize < operandSize) ? (operandSize - operandValuesSize) : 0; +} + +// Highly specialized utility routine for converting an operand to +// CONSTANT_COPY lifetime. +// +// Expects that: +// - operand has a known size +// - operand->lifetime has already been set to CONSTANT_COPY +// - operand->location has been zeroed out +// +// Does the following: +// - initializes operand->location to point to the beginning of model->operandValues +// - resizes model->operandValues (if necessary) to be large enough for the operand +// value, padding it with zeroes on the end +// +// Potential problem: +// By changing the operand to CONSTANT_COPY lifetime, this function is effectively initializing the +// operand with unspecified (but deterministic) data. This means that the model may be invalidated +// in two ways: not only is the lifetime of CONSTANT_COPY invalid, but the operand's value in the +// graph may also be invalid (e.g., if the operand is used as an activation code and has an invalid +// value). For now, this should be fine because it just means we're not testing what we think we're +// testing in certain cases; but we can handwave this and assume we're probabilistically likely to +// exercise the validation code over the span of the entire test set and operand space. +// +// Aborts if the specified operand type is an extension type or OEM type. +static void becomeConstantCopy(Model* model, Operand* operand) { + // sizeOfData will abort if the specified type is an extension type or OEM type. + const size_t sizeOfOperand = sizeOfData(*operand); + EXPECT_NE(sizeOfOperand, size_t(0)); + operand->location.poolIndex = 0; + operand->location.offset = 0; + operand->location.length = sizeOfOperand; + if (model->operandValues.size() < sizeOfOperand) { + model->operandValues.resize(sizeOfOperand); + } +} + +// The sizeForBinder() functions estimate the size of the +// representation of a value when sent to binder. It's probably a bit +// of an under-estimate, because we don't know the size of the +// metadata in the binder format (e.g., representation of the size of +// a vector); but at least it adds up "big" things like vector +// contents. However, it doesn't treat inter-field or end-of-struct +// padding in a methodical way -- there's no attempt to be consistent +// in whether or not padding in the native (C++) representation +// contributes to the estimated size for the binder representation; +// and there's no attempt to understand what padding (if any) is +// needed in the binder representation. +// +// This assumes that non-metadata uses a fixed length encoding (e.g., +// a uint32_t is always encoded in sizeof(uint32_t) bytes, rather than +// using an encoding whose length is related to the magnitude of the +// encoded value). + +template +static size_t sizeForBinder(const Type& val) { + static_assert(std::is_trivially_copyable_v>, + "expected a trivially copyable type"); + return sizeof(val); +} + +template +static size_t sizeForBinder(const hidl_vec& vec) { + return std::accumulate(vec.begin(), vec.end(), 0, + [](size_t acc, const Type& x) { return acc + sizeForBinder(x); }); +} + +template <> +size_t sizeForBinder(const SymmPerChannelQuantParams& symmPerChannelQuantParams) { + size_t size = 0; + + size += sizeForBinder(symmPerChannelQuantParams.scales); + size += sizeForBinder(symmPerChannelQuantParams.channelDim); + + return size; +} + +template <> +size_t sizeForBinder(const V1_2::Operand::ExtraParams& extraParams) { + using Discriminator = V1_2::Operand::ExtraParams::hidl_discriminator; + switch (extraParams.getDiscriminator()) { + case Discriminator::none: + return 0; + case Discriminator::channelQuant: + return sizeForBinder(extraParams.channelQuant()); + case Discriminator::extension: + return sizeForBinder(extraParams.extension()); + } + LOG(FATAL) << "Unrecognized extraParams enum: " + << static_cast(extraParams.getDiscriminator()); + return 0; +} + +template <> +size_t sizeForBinder(const Operand& operand) { + size_t size = 0; + + size += sizeForBinder(operand.type); + size += sizeForBinder(operand.dimensions); + size += sizeForBinder(operand.numberOfConsumers); + size += sizeForBinder(operand.scale); + size += sizeForBinder(operand.zeroPoint); + size += sizeForBinder(operand.lifetime); + size += sizeForBinder(operand.location); + size += sizeForBinder(operand.extraParams); + + return size; +} + +template <> +size_t sizeForBinder(const Operation& operation) { + size_t size = 0; + + size += sizeForBinder(operation.type); + size += sizeForBinder(operation.inputs); + size += sizeForBinder(operation.outputs); + + return size; +} + +template <> +size_t sizeForBinder(const hidl_string& name) { + return name.size(); +} + +template <> +size_t sizeForBinder(const hidl_memory& memory) { + // This is just a guess. + + size_t size = 0; + + if (const native_handle_t* handle = memory.handle()) { + size += sizeof(*handle); + size += sizeof(handle->data[0] * (handle->numFds + handle->numInts)); + } + size += sizeForBinder(memory.name()); + + return size; +} + +template <> +size_t sizeForBinder(const Subgraph& subgraph) { + size_t size = 0; + + size += sizeForBinder(subgraph.operands); + size += sizeForBinder(subgraph.operations); + size += sizeForBinder(subgraph.inputIndexes); + size += sizeForBinder(subgraph.outputIndexes); + + return size; +} + +template <> +size_t sizeForBinder(const V1_2::Model::ExtensionNameAndPrefix& extensionNameToPrefix) { + size_t size = 0; + + size += sizeForBinder(extensionNameToPrefix.name); + size += sizeForBinder(extensionNameToPrefix.prefix); + + return size; +} + +template <> +size_t sizeForBinder(const Model& model) { + size_t size = 0; + + size += sizeForBinder(model.main); + size += sizeForBinder(model.referenced); + size += sizeForBinder(model.operandValues); + size += sizeForBinder(model.pools); + size += sizeForBinder(model.relaxComputationFloat32toFloat16); + size += sizeForBinder(model.extensionNameToPrefix); + + return size; +} + +// https://developer.android.com/reference/android/os/TransactionTooLargeException.html +// +// "The Binder transaction buffer has a limited fixed size, +// currently 1Mb, which is shared by all transactions in progress +// for the process." +// +// Will our representation fit under this limit? There are two complications: +// - Our representation size is just approximate (see sizeForBinder()). +// - This object may not be the only occupant of the Binder transaction buffer. +// So we'll be very conservative: We want the representation size to be no +// larger than half the transaction buffer size. +// +// If our representation grows large enough that it still fits within +// the transaction buffer but combined with other transactions may +// exceed the buffer size, then we may see intermittent HAL transport +// errors. +static bool exceedsBinderSizeLimit(size_t representationSize) { + // Instead of using this fixed buffer size, we might instead be able to use + // ProcessState::self()->getMmapSize(). However, this has a potential + // problem: The binder/mmap size of the current process does not necessarily + // indicate the binder/mmap size of the service (i.e., the other process). + // The only way it would be a good indication is if both the current process + // and the service use the default size. + static const size_t kHalfBufferSize = 1024 * 1024 / 2; + + return representationSize > kHalfBufferSize; +} + +///////////////////////// VALIDATE EXECUTION ORDER //////////////////////////// + +static void mutateExecutionOrderTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.main.operations.size(); ++operation) { + const Operation& operationObj = model.main.operations[operation]; + for (uint32_t input : operationObj.inputs) { + if (model.main.operands[input].lifetime == OperandLifeTime::TEMPORARY_VARIABLE || + model.main.operands[input].lifetime == OperandLifeTime::SUBGRAPH_OUTPUT) { + // This operation reads an operand written by some + // other operation. Move this operation to the + // beginning of the sequence, ensuring that it reads + // the operand before that operand is written, thereby + // violating execution order rules. + const std::string message = "mutateExecutionOrderTest: operation " + + std::to_string(operation) + " is a reader"; + validate(device, message, model, + [operation](Model* model, ExecutionPreference*, Priority*) { + auto& operations = model->main.operations; + std::rotate(operations.begin(), operations.begin() + operation, + operations.begin() + operation + 1); + }); + break; // only need to do this once per operation + } + } + for (uint32_t output : operationObj.outputs) { + if (model.main.operands[output].numberOfConsumers > 0) { + // This operation writes an operand read by some other + // operation. Move this operation to the end of the + // sequence, ensuring that it writes the operand after + // that operand is read, thereby violating execution + // order rules. + const std::string message = "mutateExecutionOrderTest: operation " + + std::to_string(operation) + " is a writer"; + validate(device, message, model, + [operation](Model* model, ExecutionPreference*, Priority*) { + auto& operations = model->main.operations; + std::rotate(operations.begin() + operation, + operations.begin() + operation + 1, operations.end()); + }); + break; // only need to do this once per operation + } + } + } +} + ///////////////////////// VALIDATE MODEL OPERAND TYPE ///////////////////////// static const uint32_t invalidOperandTypes[] = { @@ -261,9 +524,245 @@ static void mutateOperandZeroPointTest(const sp& device, const Model& m } } +///////////////////////// VALIDATE OPERAND LIFETIME ///////////////////////////////////////////// + +static std::vector getInvalidLifeTimes(const Model& model, size_t modelSize, + const Operand& operand) { + // TODO: Support OperandLifeTime::CONSTANT_REFERENCE as an invalid lifetime + // TODO: Support OperandLifeTime::NO_VALUE as an invalid lifetime + + // Ways to get an invalid lifetime: + // - change whether a lifetime means an operand should have a writer + std::vector ret; + switch (operand.lifetime) { + case OperandLifeTime::SUBGRAPH_OUTPUT: + case OperandLifeTime::TEMPORARY_VARIABLE: + ret = { + OperandLifeTime::SUBGRAPH_INPUT, + OperandLifeTime::CONSTANT_COPY, + }; + break; + case OperandLifeTime::CONSTANT_COPY: + case OperandLifeTime::CONSTANT_REFERENCE: + case OperandLifeTime::SUBGRAPH_INPUT: + ret = { + OperandLifeTime::TEMPORARY_VARIABLE, + OperandLifeTime::SUBGRAPH_OUTPUT, + }; + break; + case OperandLifeTime::NO_VALUE: + // Not enough information to know whether + // TEMPORARY_VARIABLE or CONSTANT_COPY would be invalid -- + // is this operand written (then CONSTANT_COPY would be + // invalid) or not (then TEMPORARY_VARIABLE would be + // invalid)? + break; + case OperandLifeTime::SUBGRAPH: + break; + default: + ADD_FAILURE(); + break; + } + + const size_t operandSize = sizeOfData(operand); // will be zero if shape is unknown + if (!operandSize || + exceedsBinderSizeLimit(modelSize + constantCopyExtraSize(model, operandSize))) { + // Unknown size or too-large size + ret.erase(std::remove(ret.begin(), ret.end(), OperandLifeTime::CONSTANT_COPY), ret.end()); + } + + return ret; +} + +static void mutateOperandLifeTimeTest(const sp& device, const Model& model) { + const size_t modelSize = sizeForBinder(model); + for (size_t operand = 0; operand < model.main.operands.size(); ++operand) { + const std::vector invalidLifeTimes = + getInvalidLifeTimes(model, modelSize, model.main.operands[operand]); + for (OperandLifeTime invalidLifeTime : invalidLifeTimes) { + const std::string message = "mutateOperandLifetimeTest: operand " + + std::to_string(operand) + " has lifetime " + + toString(invalidLifeTime) + " instead of lifetime " + + toString(model.main.operands[operand].lifetime); + validate(device, message, model, + [operand, invalidLifeTime](Model* model, ExecutionPreference*, Priority*) { + static const DataLocation kZeroDataLocation = {}; + Operand& operandObj = model->main.operands[operand]; + switch (operandObj.lifetime) { + case OperandLifeTime::SUBGRAPH_INPUT: { + hidl_vec_remove(&model->main.inputIndexes, uint32_t(operand)); + break; + } + case OperandLifeTime::SUBGRAPH_OUTPUT: { + hidl_vec_remove(&model->main.outputIndexes, uint32_t(operand)); + break; + } + default: + break; + } + operandObj.lifetime = invalidLifeTime; + operandObj.location = kZeroDataLocation; + switch (invalidLifeTime) { + case OperandLifeTime::CONSTANT_COPY: { + becomeConstantCopy(model, &operandObj); + break; + } + case OperandLifeTime::SUBGRAPH_INPUT: + hidl_vec_push_back(&model->main.inputIndexes, uint32_t(operand)); + break; + case OperandLifeTime::SUBGRAPH_OUTPUT: + hidl_vec_push_back(&model->main.outputIndexes, uint32_t(operand)); + break; + default: + break; + } + }); + } + } +} + +///////////////////////// VALIDATE OPERAND INPUT-or-OUTPUT ////////////////////////////////////// + +static std::optional getInputOutputLifeTime(const Model& model, size_t modelSize, + const Operand& operand) { + // Ways to get an invalid lifetime (with respect to model inputIndexes and outputIndexes): + // - change whether a lifetime means an operand is a model input, a model output, or neither + // - preserve whether or not a lifetime means an operand should have a writer + switch (operand.lifetime) { + case OperandLifeTime::CONSTANT_COPY: + case OperandLifeTime::CONSTANT_REFERENCE: + return OperandLifeTime::SUBGRAPH_INPUT; + case OperandLifeTime::SUBGRAPH_INPUT: { + const size_t operandSize = sizeOfData(operand); // will be zero if shape is unknown + if (!operandSize || + exceedsBinderSizeLimit(modelSize + constantCopyExtraSize(model, operandSize))) { + // Unknown size or too-large size + break; + } + return OperandLifeTime::CONSTANT_COPY; + } + case OperandLifeTime::SUBGRAPH_OUTPUT: + return OperandLifeTime::TEMPORARY_VARIABLE; + case OperandLifeTime::TEMPORARY_VARIABLE: + return OperandLifeTime::SUBGRAPH_OUTPUT; + case OperandLifeTime::NO_VALUE: + // Not enough information to know whether + // TEMPORARY_VARIABLE or CONSTANT_COPY would be an + // appropriate choice -- is this operand written (then + // TEMPORARY_VARIABLE would be appropriate) or not (then + // CONSTANT_COPY would be appropriate)? + break; + case OperandLifeTime::SUBGRAPH: + break; + default: + ADD_FAILURE(); + break; + } + + return std::nullopt; +} + +static void mutateOperandInputOutputTest(const sp& device, const Model& model) { + const size_t modelSize = sizeForBinder(model); + for (size_t operand = 0; operand < model.main.operands.size(); ++operand) { + const std::optional changedLifeTime = + getInputOutputLifeTime(model, modelSize, model.main.operands[operand]); + if (changedLifeTime) { + const std::string message = "mutateOperandInputOutputTest: operand " + + std::to_string(operand) + " has lifetime " + + toString(*changedLifeTime) + " instead of lifetime " + + toString(model.main.operands[operand].lifetime); + validate(device, message, model, + [operand, changedLifeTime](Model* model, ExecutionPreference*, Priority*) { + static const DataLocation kZeroDataLocation = {}; + Operand& operandObj = model->main.operands[operand]; + operandObj.lifetime = *changedLifeTime; + operandObj.location = kZeroDataLocation; + if (*changedLifeTime == OperandLifeTime::CONSTANT_COPY) { + becomeConstantCopy(model, &operandObj); + } + }); + } + } +} + +///////////////////////// VALIDATE OPERAND NUMBER OF CONSUMERS ////////////////////////////////// + +static std::vector getInvalidNumberOfConsumers(uint32_t numberOfConsumers) { + if (numberOfConsumers == 0) { + return {1}; + } else { + return {numberOfConsumers - 1, numberOfConsumers + 1}; + } +} + +static void mutateOperandNumberOfConsumersTest(const sp& device, const Model& model) { + for (size_t operand = 0; operand < model.main.operands.size(); ++operand) { + const std::vector invalidNumberOfConsumersVec = + getInvalidNumberOfConsumers(model.main.operands[operand].numberOfConsumers); + for (uint32_t invalidNumberOfConsumers : invalidNumberOfConsumersVec) { + const std::string message = + "mutateOperandNumberOfConsumersTest: operand " + std::to_string(operand) + + " numberOfConsumers = " + std::to_string(invalidNumberOfConsumers); + validate(device, message, model, + [operand, invalidNumberOfConsumers](Model* model, ExecutionPreference*, + Priority*) { + model->main.operands[operand].numberOfConsumers = invalidNumberOfConsumers; + }); + } + } +} + +///////////////////////// VALIDATE OPERAND NUMBER OF WRITERS //////////////////////////////////// + +static void mutateOperandAddWriterTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.main.operations.size(); ++operation) { + for (size_t badOutputNum = 0; + badOutputNum < model.main.operations[operation].outputs.size(); ++badOutputNum) { + const uint32_t outputOperandIndex = + model.main.operations[operation].outputs[badOutputNum]; + const std::string message = "mutateOperandAddWriterTest: operation " + + std::to_string(operation) + " writes to " + + std::to_string(outputOperandIndex); + // We'll insert a copy of the operation, all of whose + // OTHER output operands are newly-created -- i.e., + // there'll only be a duplicate write of ONE of that + // operation's output operands. + validate(device, message, model, + [operation, badOutputNum](Model* model, ExecutionPreference*, Priority*) { + Operation newOperation = model->main.operations[operation]; + for (uint32_t input : newOperation.inputs) { + ++model->main.operands[input].numberOfConsumers; + } + for (size_t outputNum = 0; outputNum < newOperation.outputs.size(); + ++outputNum) { + if (outputNum == badOutputNum) continue; + + Operand operandValue = + model->main.operands[newOperation.outputs[outputNum]]; + operandValue.numberOfConsumers = 0; + if (operandValue.lifetime == OperandLifeTime::SUBGRAPH_OUTPUT) { + operandValue.lifetime = OperandLifeTime::TEMPORARY_VARIABLE; + } else { + ASSERT_EQ(operandValue.lifetime, + OperandLifeTime::TEMPORARY_VARIABLE); + } + newOperation.outputs[outputNum] = + hidl_vec_push_back(&model->main.operands, operandValue); + } + // Where do we insert the extra writer (a new + // operation)? It has to be later than all the + // writers of its inputs. The easiest thing to do + // is to insert it at the end of the operation + // sequence. + hidl_vec_push_back(&model->main.operations, newOperation); + }); + } + } +} + ///////////////////////// VALIDATE EXTRA ??? ///////////////////////// -// TODO: Operand::lifetime // TODO: Operand::location ///////////////////////// VALIDATE OPERATION OPERAND TYPE ///////////////////////// @@ -511,6 +1010,37 @@ static void mutateOperationOutputOperandIndexTest(const sp& device, con } } +///////////////////////// VALIDATE MODEL OPERANDS WRITTEN /////////////////////////////////////// + +static void mutateOperationRemoveWriteTest(const sp& device, const Model& model) { + for (size_t operation = 0; operation < model.main.operations.size(); ++operation) { + for (size_t outputNum = 0; outputNum < model.main.operations[operation].outputs.size(); + ++outputNum) { + const uint32_t outputOperandIndex = model.main.operations[operation].outputs[outputNum]; + if (model.main.operands[outputOperandIndex].numberOfConsumers > 0) { + const std::string message = "mutateOperationRemoveWriteTest: operation " + + std::to_string(operation) + " writes to " + + std::to_string(outputOperandIndex); + validate(device, message, model, + [operation, outputNum](Model* model, ExecutionPreference*, Priority*) { + uint32_t& outputOperandIndex = + model->main.operations[operation].outputs[outputNum]; + Operand operandValue = model->main.operands[outputOperandIndex]; + operandValue.numberOfConsumers = 0; + if (operandValue.lifetime == OperandLifeTime::SUBGRAPH_OUTPUT) { + operandValue.lifetime = OperandLifeTime::TEMPORARY_VARIABLE; + } else { + ASSERT_EQ(operandValue.lifetime, + OperandLifeTime::TEMPORARY_VARIABLE); + } + outputOperandIndex = + hidl_vec_push_back(&model->main.operands, operandValue); + }); + } + } + } +} + ///////////////////////// REMOVE OPERAND FROM EVERYTHING ///////////////////////// static void removeValueAndDecrementGreaterValues(hidl_vec* vec, uint32_t value) { @@ -804,14 +1334,20 @@ static void mutateExecutionPriorityTest(const sp& device, const Model& ////////////////////////// ENTRY POINT ////////////////////////////// void validateModel(const sp& device, const Model& model) { + mutateExecutionOrderTest(device, model); mutateOperandTypeTest(device, model); mutateOperandRankTest(device, model); mutateOperandScaleTest(device, model); mutateOperandZeroPointTest(device, model); + mutateOperandLifeTimeTest(device, model); + mutateOperandInputOutputTest(device, model); + mutateOperandNumberOfConsumersTest(device, model); + mutateOperandAddWriterTest(device, model); mutateOperationOperandTypeTest(device, model); mutateOperationTypeTest(device, model); mutateOperationInputOperandIndexTest(device, model); mutateOperationOutputOperandIndexTest(device, model); + mutateOperationRemoveWriteTest(device, model); removeOperandTest(device, model); removeOperationTest(device, model); removeOperationInputTest(device, model); diff --git a/neuralnetworks/1.3/vts/functional/include/1.3/Utils.h b/neuralnetworks/1.3/vts/functional/include/1.3/Utils.h index 3661b66445..e07e73bde8 100644 --- a/neuralnetworks/1.3/vts/functional/include/1.3/Utils.h +++ b/neuralnetworks/1.3/vts/functional/include/1.3/Utils.h @@ -24,6 +24,18 @@ namespace android::hardware::neuralnetworks { inline constexpr V1_3::Priority kDefaultPriority = V1_3::Priority::MEDIUM; +// Returns the amount of space needed to store a value of the specified type. +// +// Aborts if the specified type is an extension type or OEM type. +uint32_t sizeOfData(V1_3::OperandType type); + +// Returns the amount of space needed to store a value of the dimensions and +// type of this operand. For a non-extension, non-OEM tensor with unspecified +// rank or at least one unspecified dimension, returns zero. +// +// Aborts if the specified type is an extension type or OEM type. +uint32_t sizeOfData(const V1_3::Operand& operand); + } // namespace android::hardware::neuralnetworks namespace android::hardware::neuralnetworks::V1_3 { From 908e4479dd97482e839763eaf874a25c03f9fd08 Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Mon, 4 May 2020 13:46:07 -0400 Subject: [PATCH 0906/1022] Fix Sensors VTS asserts for sensor type strings Private sensors are the only sensor types that must define a type string. For public sensors, a type string can be left empty as it will be overridden by the sensors frameork. Bug: 155514483 Test: atest VtsHalSensorsV2_0Target Change-Id: Ib5f8fd513313670e88c2b973c1ff724658914eb2 --- sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h index 75f2c28eaf..1db667f2a9 100644 --- a/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h +++ b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h @@ -367,11 +367,13 @@ TEST_P(SensorsHidlTest, SensorListValid) { << s.sensorHandle << std::dec << " type=" << static_cast(s.type) << " name=" << s.name); - // Test non-empty type string - EXPECT_FALSE(s.typeAsString.empty()); - - // Test defined type matches defined string type - EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString)); + // Test type string non-empty only for private sensor types. + if (s.type >= SensorTypeVersion::DEVICE_PRIVATE_BASE) { + EXPECT_FALSE(s.typeAsString.empty()); + } else if (!s.typeAsString.empty()) { + // Test type string matches framework string if specified for non-private types. + EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString)); + } // Test if all sensor has name and vendor EXPECT_FALSE(s.name.empty()); From f7c55d5f9bafa3ba6ddcd5a749a05b8f71bf3077 Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Mon, 4 May 2020 17:18:00 -0700 Subject: [PATCH 0907/1022] Add AndroidTest.xml for NNAPI 1.2 VTS and blacklist failing tests - Also adds TEST_MAPPING filters here to make sure sample driver tests are still being filtered out. Bug: 155674368 Test: mm Test: atest VtsHalNeuralnetworksV1_2TargetTest Change-Id: I5f5d272742d4cdd6a8cc87ec035b5e2508eaa98f --- .../1.2/vts/functional/AndroidTest.xml | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 neuralnetworks/1.2/vts/functional/AndroidTest.xml diff --git a/neuralnetworks/1.2/vts/functional/AndroidTest.xml b/neuralnetworks/1.2/vts/functional/AndroidTest.xml new file mode 100644 index 0000000000..d9a09ab9ae --- /dev/null +++ b/neuralnetworks/1.2/vts/functional/AndroidTest.xml @@ -0,0 +1,36 @@ + + + + From 8ebe2a04c551f14cd49de8eda7880ddf63273c85 Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Tue, 5 May 2020 15:28:57 -0700 Subject: [PATCH 0908/1022] Add AndroidTest.xml for NNAPI 1.0 VTS and blacklist failing tests - Also adds TEST_MAPPING filters here to make sure sample driver tests are still being filtered out. Bug: 155577050 Test: mm Test: atest VtsHalNeuralnetworksV1_0TargetTest Change-Id: Ic8f556a957e6af340d500e2c4696b41b2a6e8516 --- .../1.0/vts/functional/AndroidTest.xml | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 neuralnetworks/1.0/vts/functional/AndroidTest.xml diff --git a/neuralnetworks/1.0/vts/functional/AndroidTest.xml b/neuralnetworks/1.0/vts/functional/AndroidTest.xml new file mode 100644 index 0000000000..54e6e91da4 --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/AndroidTest.xml @@ -0,0 +1,36 @@ + + + + From 4dda37e0d08240d245bfe284c0ddf13e6c69273a Mon Sep 17 00:00:00 2001 From: felipeal Date: Wed, 6 May 2020 09:41:01 -0700 Subject: [PATCH 0909/1022] Fixed USER_IDENTIFICATION_ASSOCIATION structs and documentation. Bug: 150409351 Test: m Test: atest UserHalServiceTest UserHalHelperTest Change-Id: I121b47f1cc0889259210de96007c3c0f82985e8c --- automotive/vehicle/2.0/types.hal | 72 ++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index ee34e420c9..733e7dc945 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -2813,7 +2813,7 @@ enum VehicleProperty : int32_t { * * To query the association, the Android system gets the property, passing a VehiclePropValue * containing the types of associations are being queried, as defined by - * UserIdentificationGetRequest. The HAL must return right away, updating the VehiclePropValue + * UserIdentificationGetRequest. The HAL must return right away, returning a VehiclePropValue * with a UserIdentificationResponse. Notice that user identification should have already * happened while system is booting up and the VHAL implementation should only return the * already identified association (like the key FOB used to unlock the car), instead of starting @@ -2828,45 +2828,50 @@ enum VehicleProperty : int32_t { * For example, to query if the current user (10) is associated with the FOB that unlocked the * car and a custom mechanism provided by the OEM, the request would be: * - * int32[0]: 10 (Android user id) - * int32[1]: 0 (Android user flags) - * int32[2]: 2 (number of types queried) - * int32[3]: 1 (1st type queried, UserIdentificationAssociationType::KEY_FOB) - * int32[4]: 101 (2nd type queried, UserIdentificationAssociationType::CUSTOM_1) + * int32[0]: 42 // request id + * int32[1]: 10 (Android user id) + * int32[2]: 0 (Android user flags) + * int32[3]: 2 (number of types queried) + * int32[4]: 1 (1st type queried, UserIdentificationAssociationType::KEY_FOB) + * int32[5]: 101 (2nd type queried, UserIdentificationAssociationType::CUSTOM_1) * * If the user is associated with the FOB but not with the custom mechanism, the response would * be: * - * int32[9]: 2 (number of associations in the response) - * int32[1]: 1 (1st type: UserIdentificationAssociationType::KEY_FOB) - * int32[2]: 2 (1st value: UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER) - * int32[3]: 101 (2st type: UserIdentificationAssociationType::CUSTOM_1) - * int32[4]: 4 (2nd value: UserIdentificationAssociationValue::NOT_ASSOCIATED_ANY_USER) + * int32[0]: 42 // request id + * int32[1]: 2 (number of associations in the response) + * int32[2]: 1 (1st type: UserIdentificationAssociationType::KEY_FOB) + * int32[3]: 2 (1st value: UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER) + * int32[4]: 101 (2st type: UserIdentificationAssociationType::CUSTOM_1) + * int32[5]: 4 (2nd value: UserIdentificationAssociationValue::NOT_ASSOCIATED_ANY_USER) * * Then to associate the user with the custom mechanism, a set request would be made: * - * int32[0]: 10 (Android user id) - * int32[0]: 0 (Android user flags) - * int32[1]: 1 (number of associations being set) - * int32[2]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1) - * int32[3]: 1 (1st value: UserIdentificationAssociationSetValue::ASSOCIATE_CURRENT_USER) + * int32[0]: 42 // request id + * int32[1]: 10 (Android user id) + * int32[2]: 0 (Android user flags) + * int32[3]: 1 (number of associations being set) + * int32[4]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1) + * int32[5]: 1 (1st value: UserIdentificationAssociationSetValue::ASSOCIATE_CURRENT_USER) * * If the request succeeded, the response would be simply: * - * int32[0]: 2 (number of associations in the response) - * int32[1]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1) - * int32[2]: 1 (1st value: UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER) + * int32[0]: 42 // request id + * int32[1]: 1 (number of associations in the response) + * int32[2]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1) + * int32[3]: 1 (1st value: UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER) * * Notice that the set request adds associations, but doesn't remove the existing ones. In the * example above, the end state would be 2 associations (FOB and CUSTOM_1). If we wanted to * associate the user with just CUSTOM_1 but not FOB, then the request should have been: * - * int32[0]: 10 (Android user id) - * int32[1]: 2 (number of types set) - * int32[2]: 1 (1st type: UserIdentificationAssociationType::KEY_FOB) - * int32[3]: 2 (1st value: UserIdentificationAssociationValue::DISASSOCIATE_CURRENT_USER) - * int32[3]: 101 (2nd type: UserIdentificationAssociationType::CUSTOM_1) - * int32[5]: 1 (2nd value: UserIdentificationAssociationValue::ASSOCIATE_CURRENT_USER) + * int32[0]: 42 // request id + * int32[1]: 10 (Android user id) + * int32[2]: 2 (number of types set) + * int32[3]: 1 (1st type: UserIdentificationAssociationType::KEY_FOB) + * int32[4]: 2 (1st value: UserIdentificationAssociationValue::DISASSOCIATE_CURRENT_USER) + * int32[5]: 101 (2nd type: UserIdentificationAssociationType::CUSTOM_1) + * int32[6]: 1 (2nd value: UserIdentificationAssociationValue::ASSOCIATE_CURRENT_USER) * * @change_mode VehiclePropertyChangeMode:ON_CHANGE * @access VehiclePropertyAccess:READ_WRITE @@ -4638,6 +4643,11 @@ enum UserIdentificationAssociationSetValue : int32_t { * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation. */ struct UserIdentificationGetRequest { + /** + * Id of the request being responded. + */ + UserRequestId requestId; + /** * Information about the current foreground Android user. */ @@ -4661,6 +4671,11 @@ struct UserIdentificationGetRequest { * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation. */ struct UserIdentificationSetRequest { + /** + * Id of the request being responded. + */ + UserRequestId requestId; + /** * Information about the current foreground Android user. */ @@ -4674,7 +4689,7 @@ struct UserIdentificationSetRequest { /** * Associations being set. */ - vec associations; + vec associations; }; /** @@ -4684,6 +4699,11 @@ struct UserIdentificationSetRequest { * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation. */ struct UserIdentificationResponse { + /** + * Id of the request being responded. + */ + UserRequestId requestId; + /** * Number of associations being returned. */ From 0b4b27183c849e3496f0dbf49c29113833ba34f1 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 6 May 2020 13:50:21 -0700 Subject: [PATCH 0910/1022] Radio tests: root before multi-sim preparation. These tests assumed that they were rooted before running, and due to a combination of b/152655658 and b/154638140, these appeared to work when a device already happened to be rooted and the test failures showed up as problems with the test rather than as problems with the target preparer. This is the same workaround being used elsewhere. Fixes: 154445273 # specifically about VtsHalSapV1_0TargetTest Test: atest VtsHalSapV1_0TargetTest # passes 100% The following tests, I confirm MultiSimTargetPreparer works, although my test device has no SIM so I cannot get fully useful results. Test: atest VtsHalRadioV1_0TargetTest # slot2 cases can now pass Test: atest VtsHalRadioV1_1TargetTest # slot2 cases can now pass Test: atest VtsHalRadioV1_2TargetTest # slot2 cases can now pass Test: atest VtsHalRadioV1_3TargetTest # fully passes Test: atest VtsHalRadioV1_4TargetTest # fully passes Change-Id: Id62cb2e1b7a95552b560ab1d4ff2f63c0a7569a3 --- radio/1.0/vts/functional/vts_hal_radio_target_test.xml | 5 +++-- radio/1.0/vts/functional/vts_hal_sap_target_test.xml | 5 +++-- radio/1.1/vts/functional/AndroidTest.xml | 5 +++-- radio/1.2/vts/functional/AndroidTest.xml | 5 +++-- radio/1.3/vts/functional/AndroidTest.xml | 5 +++-- radio/1.4/vts/functional/AndroidTest.xml | 5 +++-- 6 files changed, 18 insertions(+), 12 deletions(-) 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 5e4a1cd7a1..b91119d40a 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 @@ -17,9 +17,10 @@

      Duration between the start of first row exposure - * and the start of last row exposure.

      + *

      Duration between the start of exposure for the first row of the image sensor, + * and the start of exposure for one past the last row of the image sensor.

      */ ANDROID_SENSOR_ROLLING_SHUTTER_SKEW, diff --git a/current.txt b/current.txt index d2b720693c..e9c69441b7 100644 --- a/current.txt +++ b/current.txt @@ -590,6 +590,7 @@ f5bc6aa840db933cb9fd36668b06d3e2021cf5384bb70e459f22e2f2f921fba5 android.hardwar d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardware.automotive.evs@1.0::types 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 a05277065c28ebecd58118bd240fb8c55757361e8648c01f7c4dacdb7f2a95dc android.hardware.camera.metadata@3.3::types 9cb3df2bde2c6cd5fd96b7c41555420cacd7e276a556c684af91b7461c86460f android.hardware.gnss@1.0::IGnssCallback dd6cd9dba4fde99a1bc3cb1728d82309f509a6e6e1993e5042dfa5ffe4af5442 android.hardware.gnss@2.0::IGnssMeasurementCallback From 15bbf8424013c640687e33efe1f675d436d4b0cc Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Thu, 14 May 2020 23:01:13 -0700 Subject: [PATCH 0937/1022] Add WifiPreparer to drm tests to confirm wifi connection The tests require wifi connectivity. Bug: 156266690 Test: none Change-Id: Ib5116d62265241938f9292956b3c4829da7b425e --- drm/1.1/vts/functional/AndroidTest.xml | 4 ++++ drm/1.2/vts/functional/AndroidTest.xml | 4 ++++ drm/1.3/vts/functional/AndroidTest.xml | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/drm/1.1/vts/functional/AndroidTest.xml b/drm/1.1/vts/functional/AndroidTest.xml index 65c45accee..24eeb72fd2 100644 --- a/drm/1.1/vts/functional/AndroidTest.xml +++ b/drm/1.1/vts/functional/AndroidTest.xml @@ -19,6 +19,10 @@ + + +